diff --git a/src/main.rs b/src/main.rs index ab458dd2..7ded2c23 100644 --- a/src/main.rs +++ b/src/main.rs @@ -360,8 +360,10 @@ fn sync(workspaces: &[Workspace], &format!("{} ({}) to {}", id, src.to_string_lossy(), dst.display()))?; let _ = fs::remove_dir_all(&dst); + let pathsource = cargo::sources::path::PathSource::new(&src, id.source_id(), config); + let paths = pathsource.list_files(&pkg)?; let mut map = BTreeMap::new(); - cp_r(&src, &dst, &dst, &mut map).chain_err(|| { + cp_sources(&src, &paths, &dst, &mut map).chain_err(|| { format!("failed to copy over vendored sources for: {}", id) })?; @@ -476,15 +478,18 @@ fn sync(workspaces: &[Workspace], Ok(VendorConfig { source: config }) } -fn cp_r(src: &Path, - dst: &Path, - root: &Path, - cksums: &mut BTreeMap) -> io::Result<()> { +fn cp_sources(src: &Path, + paths: &Vec, + dst: &Path, + cksums: &mut BTreeMap) -> io::Result<()> { + let mut created_directories = BTreeSet::new(); fs::create_dir(dst)?; - for entry in src.read_dir()? { - let entry = entry?; + created_directories.insert(dst.to_owned()); - match entry.file_name().to_str() { + for p in paths { + let relative = p.strip_prefix(&src).unwrap(); + + match relative.to_str() { // Skip git config files as they're not relevant to builds most of // the time and if we respect them (e.g. in git) then it'll // probably mess with the checksums when a vendor dir is checked @@ -505,17 +510,33 @@ fn cp_r(src: &Path, } } _ => () + }; + + let dst = dst.join(&relative); + + // Create any necessary directories for the given file. We may need + // to create multiple directories, so loop until we find a directory + // we've already created. + let mut to_create = Vec::new(); + { + let mut parent = dst.to_owned(); + loop { + parent = parent.parent().unwrap().to_owned(); + if created_directories.insert(parent.to_owned()) { + to_create.push(parent.to_owned()); + } else { + break; + } + } } - let src = entry.path(); - let dst = dst.join(entry.file_name()); - if entry.file_type()?.is_dir() { - cp_r(&src, &dst, root, cksums)?; - } else { - fs::copy(&src, &dst)?; - let rel = dst.strip_prefix(root).unwrap().to_str().unwrap(); - cksums.insert(rel.replace("\\", "/"), sha256(&dst)?); + to_create.reverse(); + for p in to_create.iter() { + fs::create_dir(&p)?; } + + fs::copy(&p, &dst)?; + cksums.insert(relative.to_str().unwrap().replace("\\", "/"), sha256(&dst)?); } Ok(()) } diff --git a/tests/vendor.rs b/tests/vendor.rs index 60d1e973..f3e36e58 100644 --- a/tests/vendor.rs +++ b/tests/vendor.rs @@ -304,6 +304,27 @@ fn ignore_files() { assert!(!csum.contains("\"Cargo.toml.orig\"")); } +#[test] +fn included_files_only() { + let (dir, _lock) = dir(); + // Use a fixed commit so we know what files are excluded. + file(&dir, "Cargo.toml", r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies.libc] + git = "https://github.com/rust-lang/libc" + rev = "b95fa265332df919e53eb66de5e6bd37fcd94041" + "#); + file(&dir, "src/lib.rs", ""); + + run(&mut vendor(&dir)); + let csum = read(&dir.join("vendor/libc/.cargo-checksum.json")); + assert!(!csum.contains("\"ci/README.md\"")); + assert!(!csum.contains("\"ci/docker/aarch64-linux-android\"")); +} + #[test] fn git_simple() { let (dir, _lock) = dir();