diff --git a/src/cargo/ops/vendor.rs b/src/cargo/ops/vendor.rs index a060b3cd6db..6cd27b28899 100644 --- a/src/cargo/ops/vendor.rs +++ b/src/cargo/ops/vendor.rs @@ -221,7 +221,7 @@ fn sync( let pathsource = PathSource::new(src, id.source_id(), gctx); let paths = pathsource.list_files(pkg)?; let mut map = BTreeMap::new(); - cp_sources(pkg, src, &paths, &dst, &mut map, &mut tmp_buf) + cp_sources(pkg, src, &paths, &dst, &mut map, &mut tmp_buf, gctx) .with_context(|| format!("failed to copy over vendored sources for: {}", id))?; // Finally, emit the metadata about this package @@ -317,6 +317,7 @@ fn cp_sources( dst: &Path, cksums: &mut BTreeMap, tmp_buf: &mut [u8], + gctx: &GlobalContext, ) -> CargoResult<()> { for p in paths { let relative = p.strip_prefix(&src).unwrap(); @@ -360,7 +361,12 @@ fn cp_sources( let cksum = if dst.file_name() == Some(OsStr::new("Cargo.toml")) && pkg.package_id().source_id().is_git() { - let contents = pkg.manifest().to_normalized_contents()?; + let packaged_files = paths + .iter() + .map(|p| p.strip_prefix(src).unwrap().to_owned()) + .collect::>(); + let vendored_pkg = prepare_for_vendor(pkg, &packaged_files, gctx)?; + let contents = vendored_pkg.manifest().to_normalized_contents()?; copy_and_checksum( &dst, &mut dst_opts, @@ -392,6 +398,119 @@ fn cp_sources( Ok(()) } +/// HACK: Perform the bare minimum of `prepare_for_publish` needed for #14348. +/// +/// There are parts of `prepare_for_publish` that could be directly useful (e.g. stripping +/// `[workspace]`) while other parts that require other filesystem operations (moving the README +/// file) and ideally we'd reuse `cargo package` code to take care of all of this for us. +fn prepare_for_vendor( + me: &Package, + packaged_files: &[PathBuf], + gctx: &GlobalContext, +) -> CargoResult { + let contents = me.manifest().contents(); + let document = me.manifest().document(); + let original_toml = prepare_toml_for_vendor( + me.manifest().normalized_toml().clone(), + packaged_files, + gctx, + )?; + let normalized_toml = original_toml.clone(); + let features = me.manifest().unstable_features().clone(); + let workspace_config = me.manifest().workspace_config().clone(); + let source_id = me.package_id().source_id(); + let mut warnings = Default::default(); + let mut errors = Default::default(); + let manifest = crate::util::toml::to_real_manifest( + contents.to_owned(), + document.clone(), + original_toml, + normalized_toml, + features, + workspace_config, + source_id, + me.manifest_path(), + gctx, + &mut warnings, + &mut errors, + )?; + let new_pkg = Package::new(manifest, me.manifest_path()); + Ok(new_pkg) +} + +fn prepare_toml_for_vendor( + mut me: cargo_util_schemas::manifest::TomlManifest, + packaged_files: &[PathBuf], + gctx: &GlobalContext, +) -> CargoResult { + let package = me + .package + .as_mut() + .expect("venedored manifests must have packages"); + if let Some(cargo_util_schemas::manifest::StringOrBool::String(path)) = &package.build { + let path = paths::normalize_path(Path::new(path)); + let included = packaged_files.contains(&path); + let build = if included { + let path = path + .into_os_string() + .into_string() + .map_err(|_err| anyhow::format_err!("non-UTF8 `package.build`"))?; + let path = crate::util::toml::normalize_path_string_sep(path); + cargo_util_schemas::manifest::StringOrBool::String(path) + } else { + gctx.shell().warn(format!( + "ignoring `package.build` as `{}` is not included in the published package", + path.display() + ))?; + cargo_util_schemas::manifest::StringOrBool::Bool(false) + }; + package.build = Some(build); + } + + let lib = if let Some(target) = &me.lib { + crate::util::toml::prepare_target_for_publish( + target, + Some(packaged_files), + "library", + gctx, + )? + } else { + None + }; + let bin = crate::util::toml::prepare_targets_for_publish( + me.bin.as_ref(), + Some(packaged_files), + "binary", + gctx, + )?; + let example = crate::util::toml::prepare_targets_for_publish( + me.example.as_ref(), + Some(packaged_files), + "example", + gctx, + )?; + let test = crate::util::toml::prepare_targets_for_publish( + me.test.as_ref(), + Some(packaged_files), + "test", + gctx, + )?; + let bench = crate::util::toml::prepare_targets_for_publish( + me.bench.as_ref(), + Some(packaged_files), + "benchmark", + gctx, + )?; + + me.lib = lib; + me.bin = bin; + me.example = example; + me.test = test; + me.bench = bench; + + Ok(me) +} + fn copy_and_checksum( dst_path: &Path, dst_opts: &mut OpenOptions, diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 35318991789..172a4a736a5 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -1086,7 +1086,7 @@ fn deprecated_ws_default_features( } #[tracing::instrument(skip_all)] -fn to_real_manifest( +pub fn to_real_manifest( contents: String, document: toml_edit::ImDocument, original_toml: manifest::TomlManifest, @@ -2889,7 +2889,7 @@ fn prepare_toml_for_publish( } } -fn prepare_targets_for_publish( +pub fn prepare_targets_for_publish( targets: Option<&Vec>, packaged_files: Option<&[PathBuf]>, context: &str, @@ -2915,7 +2915,7 @@ fn prepare_targets_for_publish( } } -fn prepare_target_for_publish( +pub fn prepare_target_for_publish( target: &manifest::TomlTarget, packaged_files: Option<&[PathBuf]>, context: &str, @@ -2950,7 +2950,7 @@ fn normalize_path_sep(path: PathBuf, context: &str) -> CargoResult { Ok(path.into()) } -fn normalize_path_string_sep(path: String) -> String { +pub fn normalize_path_string_sep(path: String) -> String { if std::path::MAIN_SEPARATOR != '/' { path.replace(std::path::MAIN_SEPARATOR, "/") } else { diff --git a/tests/testsuite/vendor.rs b/tests/testsuite/vendor.rs index 1a2b783fe8f..0f3a7f7b4ef 100644 --- a/tests/testsuite/vendor.rs +++ b/tests/testsuite/vendor.rs @@ -284,11 +284,6 @@ fn discovery_inferred_build_rs_included() { # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. -bin = [] -example = [] -test = [] -bench = [] - [package] edition = "2015" name = "dep" @@ -377,17 +372,12 @@ fn discovery_inferred_build_rs_excluded() { # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. -bin = [] -example = [] -test = [] -bench = [] - [package] edition = "2015" name = "dep" version = "0.0.1" authors = [] -build = "build.rs" +build = false include = ["src/lib.rs"] autobins = false autoexamples = false @@ -405,16 +395,7 @@ path = "src/lib.rs" "##]], ); - p.cargo("check") - .with_status(101) - .with_stderr_data(str![[r#" -[COMPILING] dep v0.0.1 ([ROOTURL]/dep#[..]) -[ERROR] couldn't read [ROOT]/foo/vendor/dep/build.rs: [NOT_FOUND] - -[ERROR] could not compile `dep` (build script) due to 1 previous error - -"#]]) - .run(); + p.cargo("check").run(); } #[cargo_test] @@ -476,10 +457,6 @@ fn discovery_inferred_lib_included() { # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. -example = [] -test = [] -bench = [] - [package] edition = "2015" name = "dep" @@ -572,10 +549,6 @@ fn discovery_inferred_lib_excluded() { # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. -example = [] -test = [] -bench = [] - [package] edition = "2015" name = "dep" @@ -592,10 +565,6 @@ documentation = "docs.rs/foo" readme = false license = "MIT" -[lib] -name = "dep" -path = "src/lib.rs" - [[bin]] name = "dep" path = "src/main.rs" @@ -603,16 +572,7 @@ path = "src/main.rs" "##]], ); - p.cargo("check") - .with_status(101) - .with_stderr_data(str![[r#" -[CHECKING] dep v0.0.1 ([ROOTURL]/dep#[..]) -[ERROR] couldn't read [ROOT]/foo/vendor/dep/src/lib.rs: [NOT_FOUND] - -[ERROR] could not compile `dep` (lib) due to 1 previous error - -"#]]) - .run(); + p.cargo("check").run(); } #[cargo_test] @@ -807,22 +767,6 @@ license = "MIT" name = "dep" path = "src/lib.rs" -[[bin]] -name = "foo" -path = "src/bin/foo/main.rs" - -[[example]] -name = "example_foo" -path = "examples/example_foo.rs" - -[[test]] -name = "test_foo" -path = "tests/test_foo.rs" - -[[bench]] -name = "bench_foo" -path = "benches/bench_foo.rs" - "##]], ); @@ -1577,10 +1521,6 @@ fn git_deterministic() { # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. -bin = [] -test = [] -bench = [] - [package] edition = "2021" name = "git_dep" @@ -1598,7 +1538,7 @@ license = "MIT" [lib] name = "git_dep" -path = [..] +path = "src/lib.rs" [[example]] name = "a"