Skip to content

Commit dcaeaad

Browse files
committed
fix(vendor): Make vendor work similar to package since it resolves manifest correctly
1 parent ba607b2 commit dcaeaad

File tree

3 files changed

+139
-43
lines changed

3 files changed

+139
-43
lines changed

src/cargo/ops/cargo_package.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,24 +40,24 @@ pub struct PackageOpts<'cfg> {
4040
const ORIGINAL_MANIFEST_FILE: &str = "Cargo.toml.orig";
4141
const VCS_INFO_FILE: &str = ".cargo_vcs_info.json";
4242

43-
struct ArchiveFile {
43+
pub struct ArchiveFile {
4444
/// The relative path in the archive (not including the top-level package
4545
/// name directory).
46-
rel_path: PathBuf,
46+
pub rel_path: PathBuf,
4747
/// String variant of `rel_path`, for convenience.
48-
rel_str: String,
48+
pub rel_str: String,
4949
/// The contents to add to the archive.
50-
contents: FileContents,
50+
pub contents: FileContents,
5151
}
5252

53-
enum FileContents {
53+
pub enum FileContents {
5454
/// Absolute path to the file on disk to add to the archive.
5555
OnDisk(PathBuf),
5656
/// Generates a file.
5757
Generated(GeneratedFile),
5858
}
5959

60-
enum GeneratedFile {
60+
pub enum GeneratedFile {
6161
/// Generates `Cargo.toml` by rewriting the original.
6262
Manifest,
6363
/// Generates `Cargo.lock` in some cases (like if there is a binary).
@@ -67,14 +67,14 @@ enum GeneratedFile {
6767
}
6868

6969
#[derive(Serialize)]
70-
struct VcsInfo {
70+
pub struct VcsInfo {
7171
git: GitVcsInfo,
7272
/// Path to the package within repo (empty string if root). / not \
7373
path_in_vcs: String,
7474
}
7575

7676
#[derive(Serialize)]
77-
struct GitVcsInfo {
77+
pub struct GitVcsInfo {
7878
sha1: String,
7979
}
8080

@@ -219,7 +219,7 @@ pub fn package(ws: &Workspace<'_>, opts: &PackageOpts<'_>) -> CargoResult<Option
219219
}
220220

221221
/// Builds list of files to archive.
222-
fn build_ar_list(
222+
pub fn build_ar_list(
223223
ws: &Workspace<'_>,
224224
pkg: &Package,
225225
src_files: Vec<PathBuf>,
@@ -369,7 +369,7 @@ fn check_for_file_and_add(
369369
}
370370

371371
/// Construct `Cargo.lock` for the package to be published.
372-
fn build_lock(ws: &Workspace<'_>, orig_pkg: &Package) -> CargoResult<String> {
372+
pub fn build_lock(ws: &Workspace<'_>, orig_pkg: &Package) -> CargoResult<String> {
373373
let config = ws.config();
374374
let orig_resolve = ops::load_pkg_lockfile(ws)?;
375375

src/cargo/ops/vendor.rs

Lines changed: 68 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::core::shell::Verbosity;
2-
use crate::core::{GitReference, Workspace};
2+
use crate::core::{GitReference, Package, Workspace};
33
use crate::ops;
4+
use crate::ops::cargo_package::{build_ar_list, build_lock, FileContents, GeneratedFile};
45
use crate::sources::path::PathSource;
56
use crate::sources::CRATES_IO_REGISTRY;
67
use crate::util::{CargoResult, Config};
@@ -160,10 +161,13 @@ fn sync(
160161
}
161162
ids.insert(
162163
pkg,
163-
packages
164-
.get_one(pkg)
165-
.with_context(|| "failed to fetch package")?
166-
.clone(),
164+
(
165+
ws,
166+
packages
167+
.get_one(pkg)
168+
.with_context(|| "failed to fetch package")?
169+
.clone(),
170+
),
167171
);
168172

169173
checksums.insert(pkg, resolve.checksums().get(&pkg).cloned());
@@ -191,7 +195,7 @@ fn sync(
191195

192196
let mut sources = BTreeSet::new();
193197
let mut tmp_buf = [0; 64 * 1024];
194-
for (id, pkg) in ids.iter() {
198+
for (id, (ws, pkg)) in ids.iter() {
195199
// Next up, copy it to the vendor directory
196200
let src = pkg
197201
.manifest_path()
@@ -225,7 +229,7 @@ fn sync(
225229
let pathsource = PathSource::new(src, id.source_id(), config);
226230
let paths = pathsource.list_files(pkg)?;
227231
let mut map = BTreeMap::new();
228-
cp_sources(src, &paths, &dst, &mut map, &mut tmp_buf)
232+
cp_sources(ws, pkg, &paths, &dst, &mut map, &mut tmp_buf)
229233
.with_context(|| format!("failed to copy over vendored sources for: {}", id))?;
230234

231235
// Finally, emit the metadata about this package
@@ -313,74 +317,105 @@ fn sync(
313317
}
314318

315319
fn cp_sources(
316-
src: &Path,
320+
ws: &Workspace<'_>,
321+
pkg: &Package,
317322
paths: &[PathBuf],
318323
dst: &Path,
319324
cksums: &mut BTreeMap<String, String>,
320325
tmp_buf: &mut [u8],
321326
) -> CargoResult<()> {
322-
for p in paths {
323-
let relative = p.strip_prefix(&src).unwrap();
324-
325-
match relative.to_str() {
327+
let ar_files = build_ar_list(ws, pkg, paths.to_vec(), None)?;
328+
for file in ar_files {
329+
match file.rel_str.as_str() {
326330
// Skip git config files as they're not relevant to builds most of
327331
// the time and if we respect them (e.g. in git) then it'll
328332
// probably mess with the checksums when a vendor dir is checked
329333
// into someone else's source control
330-
Some(".gitattributes") | Some(".gitignore") | Some(".git") => continue,
334+
".gitattributes" | ".gitignore" | ".git" => continue,
331335

332336
// Temporary Cargo files
333-
Some(".cargo-ok") => continue,
337+
".cargo-ok" => continue,
334338

335339
// Skip patch-style orig/rej files. Published crates on crates.io
336340
// have `Cargo.toml.orig` which we don't want to use here and
337341
// otherwise these are rarely used as part of the build process.
338-
Some(filename) => {
342+
filename => {
339343
if filename.ends_with(".orig") || filename.ends_with(".rej") {
340344
continue;
341345
}
342346
}
343-
_ => {}
344347
};
345348

346349
// Join pathname components individually to make sure that the joined
347350
// path uses the correct directory separators everywhere, since
348351
// `relative` may use Unix-style and `dst` may require Windows-style
349352
// backslashes.
350-
let dst = relative
353+
let dst = file
354+
.rel_path
351355
.iter()
352356
.fold(dst.to_owned(), |acc, component| acc.join(&component));
353357

354358
paths::create_dir_all(dst.parent().unwrap())?;
355359

356-
let cksum = copy_and_checksum(p, &dst, tmp_buf)?;
357-
cksums.insert(relative.to_str().unwrap().replace("\\", "/"), cksum);
360+
let mut dst_opts = OpenOptions::new();
361+
dst_opts.write(true).create(true).truncate(true);
362+
let cksum = match file.contents {
363+
FileContents::OnDisk(disk_path) => {
364+
let mut src = File::open(&disk_path)
365+
.with_context(|| format!("failed to open {:?}", &disk_path))?;
366+
#[cfg(unix)]
367+
{
368+
use std::os::unix::fs::{MetadataExt, OpenOptionsExt};
369+
let src_metadata = src
370+
.metadata()
371+
.with_context(|| format!("failed to stat {:?}", disk_path))?;
372+
dst_opts.mode(src_metadata.mode());
373+
}
374+
copy_and_checksum(
375+
&dst,
376+
&mut dst_opts,
377+
&mut src,
378+
disk_path.to_str().unwrap(),
379+
tmp_buf,
380+
)?
381+
}
382+
FileContents::Generated(generated_kind) => {
383+
let contents = match generated_kind {
384+
GeneratedFile::Manifest => pkg.to_registry_toml(ws)?,
385+
GeneratedFile::Lockfile => build_lock(ws, pkg)?,
386+
GeneratedFile::VcsInfo(ref s) => serde_json::to_string_pretty(s)?,
387+
};
388+
copy_and_checksum(
389+
&dst,
390+
&mut dst_opts,
391+
&mut contents.as_bytes(),
392+
"Generated File",
393+
tmp_buf,
394+
)?
395+
}
396+
};
397+
cksums.insert(file.rel_str.replace("\\", "/"), cksum);
358398
}
359399
Ok(())
360400
}
361401

362-
fn copy_and_checksum(src_path: &Path, dst_path: &Path, buf: &mut [u8]) -> CargoResult<String> {
363-
let mut src = File::open(src_path).with_context(|| format!("failed to open {:?}", src_path))?;
364-
let mut dst_opts = OpenOptions::new();
365-
dst_opts.write(true).create(true).truncate(true);
366-
#[cfg(unix)]
367-
{
368-
use std::os::unix::fs::{MetadataExt, OpenOptionsExt};
369-
let src_metadata = src
370-
.metadata()
371-
.with_context(|| format!("failed to stat {:?}", src_path))?;
372-
dst_opts.mode(src_metadata.mode());
373-
}
402+
fn copy_and_checksum<T: Read>(
403+
dst_path: &Path,
404+
dst_opts: &mut OpenOptions,
405+
contents: &mut T,
406+
contents_path: &str,
407+
buf: &mut [u8],
408+
) -> CargoResult<String> {
374409
let mut dst = dst_opts
375410
.open(dst_path)
376411
.with_context(|| format!("failed to create {:?}", dst_path))?;
377412
// Not going to bother setting mode on pre-existing files, since there
378413
// shouldn't be any under normal conditions.
379414
let mut cksum = Sha256::new();
380415
loop {
381-
let n = src
416+
let n = contents
382417
.read(buf)
383-
.with_context(|| format!("failed to read from {:?}", src_path))?;
418+
.with_context(|| format!("failed to read from {:?}", contents_path))?;
384419
if n == 0 {
385420
break Ok(cksum.finish_hex());
386421
}

tests/testsuite/vendor.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -926,3 +926,64 @@ fn no_remote_dependency_no_vendor() {
926926
.run();
927927
assert!(!p.root().join("vendor").exists());
928928
}
929+
930+
#[cargo_test]
931+
fn vendor_crate_with_ws_inherit() {
932+
let git = git::new("ws", |p| {
933+
p.file(
934+
"Cargo.toml",
935+
r#"
936+
[workspace]
937+
members = ["bar"]
938+
[workspace.package]
939+
version = "0.1.0"
940+
"#,
941+
)
942+
.file(
943+
"bar/Cargo.toml",
944+
r#"
945+
[package]
946+
name = "bar"
947+
version.workspace = true
948+
"#,
949+
)
950+
.file("bar/src/lib.rs", "")
951+
});
952+
953+
let p = project()
954+
.file(
955+
"Cargo.toml",
956+
&format!(
957+
r#"
958+
[package]
959+
name = "foo"
960+
version = "0.1.0"
961+
962+
[dependencies]
963+
bar = {{ git = '{}' }}
964+
"#,
965+
git.url()
966+
),
967+
)
968+
.file("src/lib.rs", "")
969+
.build();
970+
971+
p.cargo("vendor --respect-source-config").run();
972+
p.change_file(
973+
".cargo/config",
974+
&format!(
975+
r#"
976+
[source."{}"]
977+
git = "{}"
978+
replace-with = "vendor"
979+
980+
[source.vendor]
981+
directory = "vendor"
982+
"#,
983+
git.url(),
984+
git.url()
985+
),
986+
);
987+
988+
p.cargo("build").run()
989+
}

0 commit comments

Comments
 (0)