Skip to content

Commit c6773a8

Browse files
committed
fix(vendor): dont use PathSource heuristic when copying files
`PathSource::list_files` has some heurstic rules for listing files. Those rules are mainly designed `cargo package`. Previously, cargo-vendor relies on those rules to understand what files to vendor. However, it shouldn't use those rules because * Package extracted from a `.crate` tarball isn't Git-controlled, some rules may apply differently. * The extracted package already went through `PathSource::list_files` when packaging. It is clean enough. * Should keep crate sources from registry sources in a pristine state, which is exactly what vendoring is meant for. Since cargo-vendor already removes and re-extracts crates of registry sources, we can assume they are not modified, and copy them directly into the vendor directory. That is this fix.
1 parent 056f5f4 commit c6773a8

File tree

2 files changed

+33
-10
lines changed

2 files changed

+33
-10
lines changed

src/cargo/ops/vendor.rs

+27-5
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,16 @@ use crate::core::SourceId;
33
use crate::core::{GitReference, Package, Workspace};
44
use crate::ops;
55
use crate::sources::path::PathSource;
6-
use crate::sources::PathEntry;
76
use crate::sources::SourceConfigMap;
87
use crate::sources::CRATES_IO_REGISTRY;
98
use crate::util::cache_lock::CacheLockMode;
109
use crate::util::{try_canonicalize, CargoResult, GlobalContext};
10+
1111
use anyhow::{bail, Context as _};
1212
use cargo_util::{paths, Sha256};
1313
use serde::Serialize;
14+
use walkdir::WalkDir;
15+
1416
use std::collections::HashSet;
1517
use std::collections::{BTreeMap, BTreeSet, HashMap};
1618
use std::ffi::OsStr;
@@ -263,8 +265,29 @@ fn sync(
263265
)?;
264266

265267
let _ = fs::remove_dir_all(&dst);
266-
let pathsource = PathSource::new(src, id.source_id(), gctx);
267-
let paths = pathsource.list_files(pkg)?;
268+
269+
let paths: Vec<_> = if id.source_id().is_registry() {
270+
// To avoid exclude rules in PathSource mess up files from registry source,
271+
// just copy whatever we extracted from .crate tarballs.
272+
WalkDir::new(src)
273+
.into_iter()
274+
// It is safe to skip erros,
275+
// since we'll hit them during fs::copy later anyway.
276+
.filter_map(|e| e.ok())
277+
// There should be no symlink in tarballs on crates.io,
278+
// but be wrong for local registries.
279+
// Hence be conservative and include symlinks.
280+
.filter(|e| e.file_type().is_file() || e.file_type().is_symlink())
281+
.map(|e| e.into_path())
282+
.collect()
283+
} else {
284+
PathSource::new(src, id.source_id(), gctx)
285+
.list_files(pkg)?
286+
.into_iter()
287+
.map(|p| p.into_path_buf())
288+
.collect()
289+
};
290+
268291
let mut map = BTreeMap::new();
269292
cp_sources(pkg, src, &paths, &dst, &mut map, &mut tmp_buf, gctx)
270293
.with_context(|| format!("failed to copy over vendored sources for: {}", id))?;
@@ -358,14 +381,13 @@ fn sync(
358381
fn cp_sources(
359382
pkg: &Package,
360383
src: &Path,
361-
paths: &[PathEntry],
384+
paths: &[PathBuf],
362385
dst: &Path,
363386
cksums: &mut BTreeMap<String, String>,
364387
tmp_buf: &mut [u8],
365388
gctx: &GlobalContext,
366389
) -> CargoResult<()> {
367390
for p in paths {
368-
let p = p.as_ref();
369391
let relative = p.strip_prefix(&src).unwrap();
370392

371393
match relative.to_str() {

tests/testsuite/vendor.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -213,12 +213,13 @@ fn package_exclude() {
213213

214214
p.cargo("vendor --respect-source-config").run();
215215
let csum = p.read_file("vendor/bar/.cargo-checksum.json");
216+
// Everything is included because `cargo-vendor`
217+
// copies whatever in the tarball.
218+
// (Some are excluded like `.git` or `.cargo-ok` though.)
216219
assert!(csum.contains(".include"));
217-
assert!(!csum.contains(".exclude"));
218-
assert!(!csum.contains(".dotdir/exclude"));
219-
// Gitignore doesn't re-include a file in an excluded parent directory,
220-
// even if negating it explicitly.
221-
assert!(!csum.contains(".dotdir/include"));
220+
assert!(csum.contains(".exclude"));
221+
assert!(csum.contains(".dotdir/exclude"));
222+
assert!(csum.contains(".dotdir/include"));
222223
}
223224

224225
#[cargo_test]

0 commit comments

Comments
 (0)