Skip to content

Commit

Permalink
fix(vendor): Strip excluded build targets
Browse files Browse the repository at this point in the history
This is a **very** hacky solution, duplicating the minimum of what
`prepare_for_publish` does to fix this one issue and in the least
intrusive way to the vendor code.

The intention is to keep this low risk for backporting to beta and
stable.
We need to revisit this, refactoring the `cargo package` code so that we
can call into that for each vendored dependency.

Fixes #14348
  • Loading branch information
epage committed Aug 7, 2024
1 parent 33862df commit 1ae77f5
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 70 deletions.
123 changes: 121 additions & 2 deletions src/cargo/ops/vendor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -317,6 +317,7 @@ fn cp_sources(
dst: &Path,
cksums: &mut BTreeMap<String, String>,
tmp_buf: &mut [u8],
gctx: &GlobalContext,
) -> CargoResult<()> {
for p in paths {
let relative = p.strip_prefix(&src).unwrap();
Expand Down Expand Up @@ -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::<Vec<_>>();
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,
Expand Down Expand Up @@ -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<Package> {
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<cargo_util_schemas::manifest::TomlManifest> {
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<T: Read>(
dst_path: &Path,
dst_opts: &mut OpenOptions,
Expand Down
8 changes: 4 additions & 4 deletions src/cargo/util/toml/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<String>,
original_toml: manifest::TomlManifest,
Expand Down Expand Up @@ -2889,7 +2889,7 @@ fn prepare_toml_for_publish(
}
}

fn prepare_targets_for_publish(
pub fn prepare_targets_for_publish(
targets: Option<&Vec<manifest::TomlTarget>>,
packaged_files: Option<&[PathBuf]>,
context: &str,
Expand All @@ -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,
Expand Down Expand Up @@ -2950,7 +2950,7 @@ fn normalize_path_sep(path: PathBuf, context: &str) -> CargoResult<PathBuf> {
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 {
Expand Down
68 changes: 4 additions & 64 deletions tests/testsuite/vendor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand All @@ -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]
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand All @@ -592,27 +565,14 @@ documentation = "docs.rs/foo"
readme = false
license = "MIT"
[lib]
name = "dep"
path = "src/lib.rs"
[[bin]]
name = "dep"
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]
Expand Down Expand Up @@ -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"
"##]],
);

Expand Down Expand Up @@ -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"
Expand All @@ -1598,7 +1538,7 @@ license = "MIT"
[lib]
name = "git_dep"
path = [..]
path = "src/lib.rs"
[[example]]
name = "a"
Expand Down

0 comments on commit 1ae77f5

Please sign in to comment.