From b6e66e263f0285e2a4266a8ad3b391dce03a7e12 Mon Sep 17 00:00:00 2001 From: Lin Yihai Date: Mon, 19 Feb 2024 08:59:48 +0800 Subject: [PATCH] feat: Add "-Zpublic-dependency" for public-dependency feature --- src/cargo/core/compiler/mod.rs | 7 +- src/cargo/core/features.rs | 2 + src/cargo/ops/cargo_package.rs | 1 + src/cargo/util/toml/mod.rs | 24 +++- tests/build-std/main.rs | 2 +- tests/testsuite/cargo/z_help/stdout.log | 1 + tests/testsuite/pub_priv.rs | 159 ++++++++++++++++++++++-- 7 files changed, 178 insertions(+), 18 deletions(-) diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 19a77173e922..6adb20122969 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -1449,15 +1449,14 @@ pub fn extern_args( |dep: &UnitDep, extern_crate_name: InternedString, noprelude: bool| -> CargoResult<()> { let mut value = OsString::new(); let mut opts = Vec::new(); - if unit + let is_public_dependency_enabled = unit .pkg .manifest() .unstable_features() .require(Feature::public_dependency()) .is_ok() - && !dep.public - && unit.target.is_lib() - { + || cx.bcx.config.cli_unstable().public_dependency; + if !dep.public && unit.target.is_lib() && is_public_dependency_enabled { opts.push("priv"); *unstable_opts = true; } diff --git a/src/cargo/core/features.rs b/src/cargo/core/features.rs index dd82833a38b8..066dd0cabf30 100644 --- a/src/cargo/core/features.rs +++ b/src/cargo/core/features.rs @@ -764,6 +764,7 @@ unstable_cli_options!( panic_abort_tests: bool = ("Enable support to run tests with -Cpanic=abort"), precise_pre_release: bool = ("Enable pre-release versions to be selected with `update --precise`"), profile_rustflags: bool = ("Enable the `rustflags` option in profiles in .cargo/config.toml file"), + public_dependency: bool = ("Respect a dependency's `public` field in Cargo.toml to control public/private dependencies"), publish_timeout: bool = ("Enable the `publish.timeout` key in .cargo/config.toml file"), rustdoc_map: bool = ("Allow passing external documentation mappings to rustdoc"), rustdoc_scrape_examples: bool = ("Allows Rustdoc to scrape code examples from reverse-dependencies"), @@ -1140,6 +1141,7 @@ impl CliUnstable { "mtime-on-use" => self.mtime_on_use = parse_empty(k, v)?, "no-index-update" => self.no_index_update = parse_empty(k, v)?, "panic-abort-tests" => self.panic_abort_tests = parse_empty(k, v)?, + "public-dependency" => self.public_dependency = parse_empty(k, v)?, "profile-rustflags" => self.profile_rustflags = parse_empty(k, v)?, "precise-pre-release" => self.precise_pre_release = parse_empty(k, v)?, "trim-paths" => self.trim_paths = parse_empty(k, v)?, diff --git a/src/cargo/ops/cargo_package.rs b/src/cargo/ops/cargo_package.rs index b3d0cc495d22..7594dabd812c 100644 --- a/src/cargo/ops/cargo_package.rs +++ b/src/cargo/ops/cargo_package.rs @@ -916,6 +916,7 @@ fn run_verify( .unstable_features() .require(Feature::public_dependency()) .is_ok() + || ws.config().cli_unstable().public_dependency { // FIXME: Turn this on at some point in the future //Some(vec!["-D exported_private_dependencies".to_string()]) diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index f4c3b9034c7f..54e36860af4b 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -717,6 +717,16 @@ pub fn to_real_manifest( }; unused_dep_keys(name_in_toml, &table_in_toml, v.unused_keys(), cx.warnings); cx.deps.push(dep); + + let mut resolved = resolved; + if !cx.config.cli_unstable().public_dependency && cx.config.nightly_features_allowed { + if let manifest::TomlDependency::Detailed(ref mut d) = resolved { + if d.public.is_some() { + d.public = None; + } + } + } + deps.insert( n.clone(), manifest::InheritableDependency::Value(resolved.clone()), @@ -1944,12 +1954,24 @@ fn detailed_dep_to_dependency( } if let Some(p) = orig.public { - cx.features.require(Feature::public_dependency())?; + let public_feature = cx.features.require(Feature::public_dependency()); + let enable_public = public_feature.is_ok(); + if !enable_public + && (!cx.config.cli_unstable().public_dependency && !cx.config.nightly_features_allowed) + { + public_feature?; + } if dep.kind() != DepKind::Normal { bail!("'public' specifier can only be used on regular dependencies, not {:?} dependencies", dep.kind()); } + if !enable_public && !cx.config.cli_unstable().public_dependency { + cx.warnings.push(format!( + "Ignoring `public` on dependency {name}. Pass `-Zpublic-dependency` to enable support for it", name = dep.name_in_toml() + )) + } + dep.set_public(p); } diff --git a/tests/build-std/main.rs b/tests/build-std/main.rs index 39c23196266c..849157908511 100644 --- a/tests/build-std/main.rs +++ b/tests/build-std/main.rs @@ -33,7 +33,7 @@ fn enable_build_std(e: &mut Execs, arg: Option<&str>) { Some(s) => format!("-Zbuild-std={}", s), None => "-Zbuild-std".to_string(), }; - e.arg(arg); + e.arg(arg).arg("-Zpublic-dependency"); e.masquerade_as_nightly_cargo(&["build-std"]); } diff --git a/tests/testsuite/cargo/z_help/stdout.log b/tests/testsuite/cargo/z_help/stdout.log index 2a4703cc11f2..abdd93b00e76 100644 --- a/tests/testsuite/cargo/z_help/stdout.log +++ b/tests/testsuite/cargo/z_help/stdout.log @@ -25,6 +25,7 @@ Available unstable (nightly-only) flags: -Z panic-abort-tests Enable support to run tests with -Cpanic=abort -Z precise-pre-release Enable pre-release versions to be selected with `update --precise` -Z profile-rustflags Enable the `rustflags` option in profiles in .cargo/config.toml file + -Z public-dependency Respect a dependency's `public` field in Cargo.toml to control public/private dependencies -Z publish-timeout Enable the `publish.timeout` key in .cargo/config.toml file -Z rustdoc-map Allow passing external documentation mappings to rustdoc -Z rustdoc-scrape-examples Allows Rustdoc to scrape code examples from reverse-dependencies diff --git a/tests/testsuite/pub_priv.rs b/tests/testsuite/pub_priv.rs index ebed8e6e7282..80768eba59a3 100644 --- a/tests/testsuite/pub_priv.rs +++ b/tests/testsuite/pub_priv.rs @@ -136,20 +136,15 @@ fn requires_feature() { p.cargo("check --message-format=short") .masquerade_as_nightly_cargo(&["public-dependency"]) - .with_status(101) .with_stderr( "\ -error: failed to parse manifest at `[..]` - -Caused by: - feature `public-dependency` is required - - The package requires the Cargo feature called `public-dependency`, \ - but that feature is not stabilized in this version of Cargo (1.[..]). - Consider adding `cargo-features = [\"public-dependency\"]` to the top of Cargo.toml \ - (above the [package] table) to tell Cargo you are opting in to use this unstable feature. - See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#public-dependency \ - for more information about the status of this feature. +[WARNING] Ignoring `public` on dependency pub_dep. Pass `-Zpublic-dependency` to enable support for it +[UPDATING] `[..]` index +[DOWNLOADING] crates ... +[DOWNLOADED] pub_dep v0.1.0 ([..]) +[CHECKING] pub_dep v0.1.0 +[CHECKING] foo v0.0.1 ([CWD]) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [..] ", ) .run() @@ -198,6 +193,47 @@ Caused by: .run() } +#[cargo_test] +fn pub_dev_dependency_without_feature() { + Package::new("pub_dep", "0.1.0") + .file("src/lib.rs", "pub struct FromPub;") + .publish(); + + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + + [dev-dependencies] + pub_dep = {version = "0.1.0", public = true} + "#, + ) + .file( + "src/lib.rs", + " + extern crate pub_dep; + pub fn use_pub(_: pub_dep::FromPub) {} + ", + ) + .build(); + + p.cargo("check --message-format=short") + .masquerade_as_nightly_cargo(&["public-dependency"]) + .with_status(101) + .with_stderr( + "\ +[ERROR] failed to parse manifest at `[..]` + +Caused by: + 'public' specifier can only be used on regular dependencies, not Development dependencies +", + ) + .run() +} + #[cargo_test(nightly, reason = "exported_private_dependencies lint is unstable")] fn workspace_pub_disallowed() { Package::new("foo1", "0.1.0") @@ -534,3 +570,102 @@ fn publish_package_with_public_dependency() { ) .run() } + +#[cargo_test(nightly, reason = "exported_private_dependencies lint is unstable")] +fn verify_mix_cargo_feature_z() { + Package::new("dep", "0.1.0") + .file("src/lib.rs", "pub struct FromDep;") + .publish(); + Package::new("priv_dep", "0.1.0") + .file("src/lib.rs", "pub struct FromPriv;") + .publish(); + Package::new("pub_dep", "0.1.0") + .file("src/lib.rs", "pub struct FromPub;") + .publish(); + let p = project() + .file( + "Cargo.toml", + r#" + cargo-features = ["public-dependency"] + [package] + name = "foo" + version = "0.0.1" + + [dependencies] + dep = "0.1.0" + priv_dep = {version = "0.1.0", public = false} + pub_dep = {version = "0.1.0", public = true} + "#, + ) + .file( + "src/lib.rs", + " + extern crate dep; + extern crate priv_dep; + extern crate pub_dep; + pub fn use_dep(_: dep::FromDep) {} + pub fn use_priv(_: priv_dep::FromPriv) {} + pub fn use_pub(_: pub_dep::FromPub) {} + ", + ) + .build(); + + p.cargo("check -Zpublic-dependency --message-format=short") + .masquerade_as_nightly_cargo(&["public-dependency"]) + .with_stderr_contains( + "\ +src/lib.rs:5:13: warning: type `FromDep` from private dependency 'dep' in public interface +src/lib.rs:6:13: warning: type `FromPriv` from private dependency 'priv_dep' in public interface +", + ) + .run(); +} + +#[cargo_test(nightly, reason = "exported_private_dependencies lint is unstable")] +fn verify_z_public_dependency() { + Package::new("dep", "0.1.0") + .file("src/lib.rs", "pub struct FromDep;") + .publish(); + Package::new("priv_dep", "0.1.0") + .file("src/lib.rs", "pub struct FromPriv;") + .publish(); + Package::new("pub_dep", "0.1.0") + .file("src/lib.rs", "pub struct FromPub;") + .publish(); + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + + [dependencies] + dep = "0.1.0" + priv_dep = {version = "0.1.0", public = false} + pub_dep = {version = "0.1.0", public = true} + "#, + ) + .file( + "src/lib.rs", + " + extern crate dep; + extern crate priv_dep; + extern crate pub_dep; + pub fn use_dep(_: dep::FromDep) {} + pub fn use_priv(_: priv_dep::FromPriv) {} + pub fn use_pub(_: pub_dep::FromPub) {} + ", + ) + .build(); + + p.cargo("check -Zpublic-dependency --message-format=short") + .masquerade_as_nightly_cargo(&["public-dependency"]) + .with_stderr_contains( + "\ +src/lib.rs:5:13: warning: type `FromDep` from private dependency 'dep' in public interface +src/lib.rs:6:13: warning: type `FromPriv` from private dependency 'priv_dep' in public interface +", + ) + .run(); +}