diff --git a/src/cargo/ops/vendor.rs b/src/cargo/ops/vendor.rs index c09a936d03f0..c6fb5ffb51f1 100644 --- a/src/cargo/ops/vendor.rs +++ b/src/cargo/ops/vendor.rs @@ -1,5 +1,5 @@ use crate::core::shell::Verbosity; -use crate::core::{GitReference, Workspace}; +use crate::core::{GitReference, Package, Workspace}; use crate::ops; use crate::sources::path::PathSource; use crate::sources::CRATES_IO_REGISTRY; @@ -9,6 +9,7 @@ use cargo_util::{paths, Sha256}; use serde::Serialize; use std::collections::HashSet; use std::collections::{BTreeMap, BTreeSet, HashMap}; +use std::ffi::OsStr; use std::fs::{self, File, OpenOptions}; use std::io::{Read, Write}; use std::path::{Path, PathBuf}; @@ -225,7 +226,7 @@ fn sync( let pathsource = PathSource::new(src, id.source_id(), config); let paths = pathsource.list_files(pkg)?; let mut map = BTreeMap::new(); - cp_sources(src, &paths, &dst, &mut map, &mut tmp_buf) + cp_sources(pkg, src, &paths, &dst, &mut map, &mut tmp_buf) .with_context(|| format!("failed to copy over vendored sources for: {}", id))?; // Finally, emit the metadata about this package @@ -313,6 +314,7 @@ fn sync( } fn cp_sources( + pkg: &Package, src: &Path, paths: &[PathBuf], dst: &Path, @@ -352,25 +354,42 @@ fn cp_sources( .fold(dst.to_owned(), |acc, component| acc.join(&component)); paths::create_dir_all(dst.parent().unwrap())?; + let mut dst_opts = OpenOptions::new(); + dst_opts.write(true).create(true).truncate(true); + let cksum = if dst.file_name() == Some(OsStr::new("Cargo.toml")) { + let contents = toml::to_string_pretty(pkg.manifest().original())?; + copy_and_checksum( + &dst, + &mut dst_opts, + &mut contents.as_bytes(), + "Generated Cargo.toml", + tmp_buf, + )? + } else { + let mut src = File::open(&p).with_context(|| format!("failed to open {:?}", &p))?; + #[cfg(unix)] + { + use std::os::unix::fs::{MetadataExt, OpenOptionsExt}; + let src_metadata = src + .metadata() + .with_context(|| format!("failed to stat {:?}", p))?; + dst_opts.mode(src_metadata.mode()); + } + copy_and_checksum(&dst, &mut dst_opts, &mut src, p.to_str().unwrap(), tmp_buf)? + }; - let cksum = copy_and_checksum(p, &dst, tmp_buf)?; cksums.insert(relative.to_str().unwrap().replace("\\", "/"), cksum); } Ok(()) } -fn copy_and_checksum(src_path: &Path, dst_path: &Path, buf: &mut [u8]) -> CargoResult { - let mut src = File::open(src_path).with_context(|| format!("failed to open {:?}", src_path))?; - let mut dst_opts = OpenOptions::new(); - dst_opts.write(true).create(true).truncate(true); - #[cfg(unix)] - { - use std::os::unix::fs::{MetadataExt, OpenOptionsExt}; - let src_metadata = src - .metadata() - .with_context(|| format!("failed to stat {:?}", src_path))?; - dst_opts.mode(src_metadata.mode()); - } +fn copy_and_checksum( + dst_path: &Path, + dst_opts: &mut OpenOptions, + contents: &mut T, + contents_path: &str, + buf: &mut [u8], +) -> CargoResult { let mut dst = dst_opts .open(dst_path) .with_context(|| format!("failed to create {:?}", dst_path))?; @@ -378,9 +397,9 @@ fn copy_and_checksum(src_path: &Path, dst_path: &Path, buf: &mut [u8]) -> CargoR // shouldn't be any under normal conditions. let mut cksum = Sha256::new(); loop { - let n = src + let n = contents .read(buf) - .with_context(|| format!("failed to read from {:?}", src_path))?; + .with_context(|| format!("failed to read from {:?}", contents_path))?; if n == 0 { break Ok(cksum.finish_hex()); } diff --git a/tests/testsuite/vendor.rs b/tests/testsuite/vendor.rs index 8e985e265a3d..d8c96a4f6cbc 100644 --- a/tests/testsuite/vendor.rs +++ b/tests/testsuite/vendor.rs @@ -926,3 +926,64 @@ fn no_remote_dependency_no_vendor() { .run(); assert!(!p.root().join("vendor").exists()); } + +#[cargo_test] +fn vendor_crate_with_ws_inherit() { + let git = git::new("ws", |p| { + p.file( + "Cargo.toml", + r#" + [workspace] + members = ["bar"] + [workspace.package] + version = "0.1.0" + "#, + ) + .file( + "bar/Cargo.toml", + r#" + [package] + name = "bar" + version.workspace = true + "#, + ) + .file("bar/src/lib.rs", "") + }); + + let p = project() + .file( + "Cargo.toml", + &format!( + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = {{ git = '{}' }} + "#, + git.url() + ), + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("vendor --respect-source-config").run(); + p.change_file( + ".cargo/config", + &format!( + r#" + [source."{}"] + git = "{}" + replace-with = "vendor" + + [source.vendor] + directory = "vendor" + "#, + git.url(), + git.url() + ), + ); + + p.cargo("check").run() +}