From cf920df38bfe5ac84c1270c25fd3689598f35db5 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 20 Jan 2021 19:16:54 -0800 Subject: [PATCH 1/9] Unhide nightly-only flags. I changed my mind on how these should work. I think it is useful to "advertise" the existence of these options on stable. The error message if you try to use it should help guide on what to do. --- src/bin/cargo/cli.rs | 9 ++++++--- src/cargo/util/command_prelude.rs | 13 +++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/bin/cargo/cli.rs b/src/bin/cargo/cli.rs index ec3ff0fbe96..ed826be5804 100644 --- a/src/bin/cargo/cli.rs +++ b/src/bin/cargo/cli.rs @@ -327,9 +327,12 @@ See 'cargo help ' for more information on a specific command.\n", .arg(opt("locked", "Require Cargo.lock is up to date").global(true)) .arg(opt("offline", "Run without accessing the network").global(true)) .arg( - multi_opt("config", "KEY=VALUE", "Override a configuration value") - .global(true) - .hidden(true), + multi_opt( + "config", + "KEY=VALUE", + "Override a configuration value (unstable)", + ) + .global(true), ) .arg( Arg::with_name("unstable-features") diff --git a/src/cargo/util/command_prelude.rs b/src/cargo/util/command_prelude.rs index 27c6e54e74f..4f56ab242f4 100644 --- a/src/cargo/util/command_prelude.rs +++ b/src/cargo/util/command_prelude.rs @@ -169,7 +169,7 @@ pub trait AppExt: Sized { } fn arg_unit_graph(self) -> Self { - self._arg(opt("unit-graph", "Output build graph in JSON (unstable)").hidden(true)) + self._arg(opt("unit-graph", "Output build graph in JSON (unstable)")) } fn arg_new_opts(self) -> Self { @@ -214,13 +214,10 @@ pub trait AppExt: Sized { } fn arg_ignore_rust_version(self) -> Self { - self._arg( - opt( - "ignore-rust-version", - "Ignore `rust-version` specification in packages", - ) - .hidden(true), // nightly only (`rust-version` feature) - ) + self._arg(opt( + "ignore-rust-version", + "Ignore `rust-version` specification in packages (unstable)", + )) } } From 73b98edc3411f627c96c9b37b48103b5102a3adf Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 20 Jan 2021 19:18:59 -0800 Subject: [PATCH 2/9] Add some comments why some options are hidden. --- src/bin/cargo/commands/login.rs | 1 + src/bin/cargo/commands/tree.rs | 5 +++++ src/bin/cargo/commands/vendor.rs | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/src/bin/cargo/commands/login.rs b/src/bin/cargo/commands/login.rs index 0f67e0c0800..db254948285 100644 --- a/src/bin/cargo/commands/login.rs +++ b/src/bin/cargo/commands/login.rs @@ -10,6 +10,7 @@ pub fn cli() -> App { ) .arg(opt("quiet", "No output printed to stdout").short("q")) .arg(Arg::with_name("token")) + // --host is deprecated (use --registry instead) .arg( opt("host", "Host to set the token for") .value_name("HOST") diff --git a/src/bin/cargo/commands/tree.rs b/src/bin/cargo/commands/tree.rs index 10e89cd5ebd..d14c6887478 100644 --- a/src/bin/cargo/commands/tree.rs +++ b/src/bin/cargo/commands/tree.rs @@ -19,7 +19,9 @@ pub fn cli() -> App { "Display the tree for all packages in the workspace", "Exclude specific workspace members", ) + // Deprecated, use --no-dedupe instead. .arg(Arg::with_name("all").long("all").short("a").hidden(true)) + // Deprecated, use --target=all instead. .arg( Arg::with_name("all-targets") .long("all-targets") @@ -30,6 +32,7 @@ pub fn cli() -> App { "Filter dependencies matching the given target-triple (default host platform). \ Pass `all` to include all targets.", ) + // Deprecated, use -e=no-dev instead. .arg( Arg::with_name("no-dev-dependencies") .long("no-dev-dependencies") @@ -52,7 +55,9 @@ pub fn cli() -> App { ) .short("i"), ) + // Deprecated, use --prefix=none instead. .arg(Arg::with_name("no-indent").long("no-indent").hidden(true)) + // Deprecated, use --prefix=depth instead. .arg( Arg::with_name("prefix-depth") .long("prefix-depth") diff --git a/src/bin/cargo/commands/vendor.rs b/src/bin/cargo/commands/vendor.rs index e0f5dc14ca6..b3705a52665 100644 --- a/src/bin/cargo/commands/vendor.rs +++ b/src/bin/cargo/commands/vendor.rs @@ -32,21 +32,25 @@ pub fn cli() -> App { .long("versioned-dirs") .help("Always include version in subdir name"), ) + // Not supported. .arg( Arg::with_name("no-merge-sources") .long("no-merge-sources") .hidden(true), ) + // Not supported. .arg( Arg::with_name("relative-path") .long("relative-path") .hidden(true), ) + // Not supported. .arg( Arg::with_name("only-git-deps") .long("only-git-deps") .hidden(true), ) + // Not supported. .arg( Arg::with_name("disallow-duplicates") .long("disallow-duplicates") From d89a78ee19cc82471d7a95375a43d2a979e0279c Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 20 Jan 2021 19:22:51 -0800 Subject: [PATCH 3/9] Add error message for wrong cargo-features placement. This is intended to help if the user puts cargo-features in the wrong place in Cargo.toml. --- src/cargo/util/toml/mod.rs | 11 +++++++++++ tests/testsuite/cargo_features.rs | 29 +++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 44dd7140df6..404d07b3428 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -69,6 +69,17 @@ fn do_read_manifest( parse(contents, pretty_filename, config)? }; + // Provide a helpful error message for a common user error. + if let Some(package) = toml.get("package").or_else(|| toml.get("project")) { + if let Some(feats) = package.get("cargo-features") { + bail!( + "cargo-features = {} was found in the wrong location, it \ + should be set at the top of Cargo.toml before any tables", + toml::to_string(feats).unwrap() + ); + } + } + let mut unused = BTreeSet::new(); let manifest: TomlManifest = serde_ignored::deserialize(toml, |path| { let mut key = String::new(); diff --git a/tests/testsuite/cargo_features.rs b/tests/testsuite/cargo_features.rs index 02a41c4fde6..2b638df22f8 100644 --- a/tests/testsuite/cargo_features.rs +++ b/tests/testsuite/cargo_features.rs @@ -327,3 +327,32 @@ fn publish_allowed() { .masquerade_as_nightly_cargo() .run(); } + +#[cargo_test] +fn wrong_position() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + cargo-features = ["test-dummy-unstable"] + "#, + ) + .file("src/lib.rs", "") + .build(); + p.cargo("check") + .masquerade_as_nightly_cargo() + .with_status(101) + .with_stderr( + "\ +error: failed to parse manifest at [..] + +Caused by: + cargo-features = [\"test-dummy-unstable\"] was found in the wrong location, it \ + should be set at the top of Cargo.toml before any tables +", + ) + .run(); +} From ff349f0205e52083393acfca9b61ee82dfc18b31 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 20 Jan 2021 19:31:57 -0800 Subject: [PATCH 4/9] Remove publish-lockfile key from manifest. The feature was stabilized without the key in #7026 about 1.5 years ago. (Will follow up with an error message in a subsequent commit.) --- src/cargo/core/manifest.rs | 3 --- src/cargo/util/toml/mod.rs | 15 --------------- tests/testsuite/publish_lockfile.rs | 2 -- 3 files changed, 20 deletions(-) diff --git a/src/cargo/core/manifest.rs b/src/cargo/core/manifest.rs index 4608adcbe3f..330e07f0627 100644 --- a/src/cargo/core/manifest.rs +++ b/src/cargo/core/manifest.rs @@ -39,7 +39,6 @@ pub struct Manifest { custom_metadata: Option, profiles: Option, publish: Option>, - publish_lockfile: bool, replace: Vec<(PackageIdSpec, Dependency)>, patch: HashMap>, workspace: WorkspaceConfig, @@ -374,7 +373,6 @@ impl Manifest { custom_metadata: Option, profiles: Option, publish: Option>, - publish_lockfile: bool, replace: Vec<(PackageIdSpec, Dependency)>, patch: HashMap>, workspace: WorkspaceConfig, @@ -407,7 +405,6 @@ impl Manifest { original, im_a_teapot, default_run, - publish_lockfile, metabuild, resolve_behavior, } diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 404d07b3428..24f362ce75f 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -825,7 +825,6 @@ pub struct TomlProject { exclude: Option>, include: Option>, publish: Option, - publish_lockfile: Option, workspace: Option, im_a_teapot: Option, autobins: Option, @@ -1304,19 +1303,6 @@ impl TomlManifest { None | Some(VecStringOrBool::Bool(true)) => None, }; - let publish_lockfile = match project.publish_lockfile { - Some(b) => { - features.require(Feature::publish_lockfile())?; - warnings.push( - "The `publish-lockfile` feature is deprecated and currently \ - has no effect. It may be removed in a future version." - .to_string(), - ); - b - } - None => features.is_enabled(Feature::publish_lockfile()), - }; - if summary.features().contains_key("default-features") { warnings.push( "`default-features = [\"..\"]` was found in [features]. \ @@ -1348,7 +1334,6 @@ impl TomlManifest { custom_metadata, profiles, publish, - publish_lockfile, replace, patch, workspace_config, diff --git a/tests/testsuite/publish_lockfile.rs b/tests/testsuite/publish_lockfile.rs index a858444ceef..9355de07b1d 100644 --- a/tests/testsuite/publish_lockfile.rs +++ b/tests/testsuite/publish_lockfile.rs @@ -52,8 +52,6 @@ fn deprecated() { "\ [PACKAGING] foo v0.1.0 ([..]) [VERIFYING] foo v0.1.0 ([..]) -[WARNING] The `publish-lockfile` feature is deprecated and currently has no effect. \ - It may be removed in a future version. [COMPILING] foo v0.1.0 ([..]) [FINISHED] dev [..] ", From 00615fc51a5d47b96adba18d1e5616671680e314 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 20 Jan 2021 19:46:50 -0800 Subject: [PATCH 5/9] Add more helpful message with stabilized -Z flags. Previously, when something was stabilized, Cargo would spit out a very unhelpful error message about an unknown -Z flag. This changes it so that it displays a helpful warning (or error). --- src/cargo/core/features.rs | 93 ++++++++++++++++++++++++++-- src/cargo/lib.rs | 14 ++--- src/cargo/util/config/mod.rs | 4 +- src/cargo/util/mod.rs | 12 ++++ tests/testsuite/cargo_features.rs | 31 ++++++++++ tests/testsuite/weak_dep_features.rs | 5 +- 6 files changed, 143 insertions(+), 16 deletions(-) diff --git a/src/cargo/core/features.rs b/src/cargo/core/features.rs index 45df0d247fe..0a4ce2a2831 100644 --- a/src/cargo/core/features.rs +++ b/src/cargo/core/features.rs @@ -54,6 +54,7 @@ use anyhow::{bail, Error}; use serde::{Deserialize, Serialize}; use crate::util::errors::CargoResult; +use crate::util::indented_lines; pub const SEE_CHANNELS: &str = "See https://doc.rust-lang.org/book/appendix-07-nightly-rust.html for more information \ @@ -380,6 +381,40 @@ pub struct CliUnstable { pub credential_process: bool, } +const STABILIZED_COMPILE_PROGRESS: &str = "The progress bar is now always \ + enabled when used on an interactive console.\n\ + See https://doc.rust-lang.org/cargo/reference/config.html#termprogresswhen \ + for information on controlling the progress bar."; + +const STABILIZED_OFFLINE: &str = "Offline mode is now available via the \ + --offline CLI option"; + +const STABILIZED_CACHE_MESSAGES: &str = "Message caching is now always enabled."; + +const STABILIZED_INSTALL_UPGRADE: &str = "Packages are now always upgraded if \ + they appear out of date.\n\ + See https://doc.rust-lang.org/cargo/commands/cargo-install.html for more \ + information on how upgrading works."; + +const STABILIZED_CONFIG_PROFILE: &str = "See \ + https://doc.rust-lang.org/cargo/reference/config.html#profile for more \ + information about specifying profiles in config."; + +const STABILIZED_CRATE_VERSIONS: &str = "The crate version is now \ + automatically added to the documentation."; + +const STABILIZED_PACKAGE_FEATURES: &str = "Enhanced feature flag behavior is now \ + available in virtual workspaces, and `member/feature-name` syntax is also \ + always available. Other extensions require setting `resolver = \"2\"` in \ + Cargo.toml.\n\ + See https://doc.rust-lang.org/nightly/cargo/reference/features.html#resolver-version-2-command-line-flags \ + for more information."; + +const STABILIZED_FEATURES: &str = "The new feature resolver is now available \ + by specifying `resolver = \"2\"` in Cargo.toml.\n\ + See https://doc.rust-lang.org/nightly/cargo/reference/features.html#feature-resolver-version-2 \ + for more information."; + fn deserialize_build_std<'de, D>(deserializer: D) -> Result>, D::Error> where D: serde::Deserializer<'de>, @@ -395,7 +430,7 @@ where } impl CliUnstable { - pub fn parse(&mut self, flags: &[String]) -> CargoResult<()> { + pub fn parse(&mut self, flags: &[String]) -> CargoResult> { if !flags.is_empty() && !nightly_features_allowed() { bail!( "the `-Z` flag is only accepted on the nightly channel of Cargo, \ @@ -405,13 +440,14 @@ impl CliUnstable { SEE_CHANNELS ); } + let mut warnings = Vec::new(); for flag in flags { - self.add(flag)?; + self.add(flag, &mut warnings)?; } - Ok(()) + Ok(warnings) } - fn add(&mut self, flag: &str) -> CargoResult<()> { + fn add(&mut self, flag: &str, warnings: &mut Vec) -> CargoResult<()> { let mut parts = flag.splitn(2, '='); let k = parts.next().unwrap(); let v = parts.next(); @@ -456,6 +492,26 @@ impl CliUnstable { }) } + let mut stabilized_warn = |key: &str, version: &str, message: &str| { + warnings.push(format!( + "flag `-Z {}` has been stabilized in the {} release, \ + and is no longer necessary\n{}", + key, + version, + indented_lines(message) + )); + }; + + // Use this if the behavior now requires another mechanism to enable. + let stabilized_err = |key: &str, version: &str, message: &str| { + Err(anyhow::format_err!( + "flag `-Z {}` has been stabilized in the {} release\n{}", + key, + version, + indented_lines(message) + )) + }; + match k { "print-im-a-teapot" => self.print_im_a_teapot = parse_bool(k, v)?, "unstable-options" => self.unstable_options = parse_empty(k, v)?, @@ -477,7 +533,27 @@ impl CliUnstable { "doctest-xcompile" => self.doctest_xcompile = parse_empty(k, v)?, "panic-abort-tests" => self.panic_abort_tests = parse_empty(k, v)?, "jobserver-per-rustc" => self.jobserver_per_rustc = parse_empty(k, v)?, - "features" => self.features = Some(parse_features(v)), + "features" => { + // For now this is still allowed (there are still some + // unstable options like "compare"). This should be removed at + // some point, and migrate to a new -Z flag for any future + // things. + let feats = parse_features(v); + let stab: Vec<_> = feats + .iter() + .filter(|feat| { + matches!( + feat.as_str(), + "build_dep" | "host_dep" | "dev_dep" | "itarget" | "all" + ) + }) + .collect(); + if !stab.is_empty() || feats.is_empty() { + // Make this stabilized_err once -Zfeature support is removed. + stabilized_warn(k, "1.51", STABILIZED_FEATURES); + } + self.features = Some(feats); + } "separate-nightlies" => self.separate_nightlies = parse_empty(k, v)?, "multitarget" => self.multitarget = parse_empty(k, v)?, "rustdoc-map" => self.rustdoc_map = parse_empty(k, v)?, @@ -486,6 +562,13 @@ impl CliUnstable { "weak-dep-features" => self.weak_dep_features = parse_empty(k, v)?, "extra-link-arg" => self.extra_link_arg = parse_empty(k, v)?, "credential-process" => self.credential_process = parse_empty(k, v)?, + "compile-progress" => stabilized_warn(k, "1.30", STABILIZED_COMPILE_PROGRESS), + "offline" => stabilized_err(k, "1.36", STABILIZED_OFFLINE)?, + "cache-messages" => stabilized_warn(k, "1.40", STABILIZED_CACHE_MESSAGES), + "install-upgrade" => stabilized_warn(k, "1.41", STABILIZED_INSTALL_UPGRADE), + "config-profile" => stabilized_warn(k, "1.43", STABILIZED_CONFIG_PROFILE), + "crate-versions" => stabilized_warn(k, "1.47", STABILIZED_CRATE_VERSIONS), + "package-features" => stabilized_warn(k, "1.51", STABILIZED_PACKAGE_FEATURES), _ => bail!("unknown `-Z` flag specified: {}", k), } diff --git a/src/cargo/lib.rs b/src/cargo/lib.rs index bccb41121eb..1f8ceb691c0 100644 --- a/src/cargo/lib.rs +++ b/src/cargo/lib.rs @@ -37,7 +37,7 @@ use log::debug; use std::fmt; pub use crate::util::errors::{InternalError, VerboseError}; -pub use crate::util::{CargoResult, CliError, CliResult, Config}; +pub use crate::util::{indented_lines, CargoResult, CliError, CliResult, Config}; pub const CARGO_ENV: &str = "CARGO"; @@ -163,13 +163,11 @@ fn _display_error(err: &Error, shell: &mut Shell, as_err: bool) -> bool { return true; } drop(writeln!(shell.err(), "\nCaused by:")); - for line in cause.to_string().lines() { - if line.is_empty() { - drop(writeln!(shell.err())); - } else { - drop(writeln!(shell.err(), " {}", line)); - } - } + drop(write!( + shell.err(), + "{}", + indented_lines(&cause.to_string()) + )); } false } diff --git a/src/cargo/util/config/mod.rs b/src/cargo/util/config/mod.rs index 5cd6bd85232..b492e94ed81 100644 --- a/src/cargo/util/config/mod.rs +++ b/src/cargo/util/config/mod.rs @@ -704,7 +704,9 @@ impl Config { unstable_flags: &[String], cli_config: &[String], ) -> CargoResult<()> { - self.unstable_flags.parse(unstable_flags)?; + for warning in self.unstable_flags.parse(unstable_flags)? { + self.shell().warn(warning)?; + } if !unstable_flags.is_empty() { // store a copy of the cli flags separately for `load_unstable_flags_from_config` // (we might also need it again for `reload_rooted_at`) diff --git a/src/cargo/util/mod.rs b/src/cargo/util/mod.rs index 11ac2bae679..b9ca5797fa2 100644 --- a/src/cargo/util/mod.rs +++ b/src/cargo/util/mod.rs @@ -79,3 +79,15 @@ pub fn elapsed(duration: Duration) -> String { pub fn is_ci() -> bool { std::env::var("CI").is_ok() || std::env::var("TF_BUILD").is_ok() } + +pub fn indented_lines(text: &str) -> String { + text.lines() + .map(|line| { + if line.is_empty() { + String::from("\n") + } else { + format!(" {}\n", line) + } + }) + .collect() +} diff --git a/tests/testsuite/cargo_features.rs b/tests/testsuite/cargo_features.rs index 2b638df22f8..0d8aa242ae1 100644 --- a/tests/testsuite/cargo_features.rs +++ b/tests/testsuite/cargo_features.rs @@ -356,3 +356,34 @@ Caused by: ) .run(); } + +#[cargo_test] +fn z_stabilized() { + let p = project().file("src/lib.rs", "").build(); + + p.cargo("check -Z cache-messages") + .masquerade_as_nightly_cargo() + .with_stderr( + "\ +warning: flag `-Z cache-messages` has been stabilized in the 1.40 release, \ + and is no longer necessary + Message caching is now always enabled. + +[CHECKING] foo [..] +[FINISHED] [..] +", + ) + .run(); + + p.cargo("check -Z offline") + .masquerade_as_nightly_cargo() + .with_status(101) + .with_stderr( + "\ +error: flag `-Z offline` has been stabilized in the 1.36 release + Offline mode is now available via the --offline CLI option + +", + ) + .run(); +} diff --git a/tests/testsuite/weak_dep_features.rs b/tests/testsuite/weak_dep_features.rs index 6b8ed355add..255e5628e24 100644 --- a/tests/testsuite/weak_dep_features.rs +++ b/tests/testsuite/weak_dep_features.rs @@ -336,7 +336,7 @@ optional dependency with `?` is not allowed in required-features #[cargo_test] fn weak_with_host_decouple() { - // -Z weak-opt-features with -Z features=host + // -Z weak-opt-features with new resolver // // foo v0.1.0 // └── common v1.0.0 @@ -390,6 +390,7 @@ fn weak_with_host_decouple() { [package] name = "foo" version = "0.1.0" + resolver = "2" [dependencies] common = { version = "1.0", features = ["feat"] } @@ -416,7 +417,7 @@ fn weak_with_host_decouple() { ) .build(); - p.cargo("run -Z weak-dep-features -Z features=host_dep") + p.cargo("run -Z weak-dep-features") .masquerade_as_nightly_cargo() .with_stderr( "\ From 7bbef3defe941e46e29c8c1f4ab526d51c48766c Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 20 Jan 2021 20:08:52 -0800 Subject: [PATCH 6/9] Rework cargo-features a little. * Add `removed` support. * Include the version where it is stabilized. * Include a links to the documentation in the error/warning messages. --- src/cargo/core/features.rs | 140 ++++++++++++++++++---------- tests/testsuite/cargo_features.rs | 11 ++- tests/testsuite/pub_priv.rs | 1 + tests/testsuite/publish_lockfile.rs | 12 ++- 4 files changed, 107 insertions(+), 57 deletions(-) diff --git a/src/cargo/core/features.rs b/src/cargo/core/features.rs index 0a4ce2a2831..70b3fd43259 100644 --- a/src/cargo/core/features.rs +++ b/src/cargo/core/features.rs @@ -116,13 +116,12 @@ impl FromStr for Edition { enum Status { Stable, Unstable, + Removed, } macro_rules! features { ( - pub struct Features { - $([$stab:ident] $feature:ident: bool,)* - } + $(($stab:ident, $feature:ident, $version:expr, $docs:expr),)* ) => ( #[derive(Default, Clone, Debug)] pub struct Features { @@ -138,6 +137,9 @@ macro_rules! features { } static FEAT: Feature = Feature { name: stringify!($feature), + stability: stab!($stab), + version: $version, + docs: $docs, get, }; &FEAT @@ -150,14 +152,14 @@ macro_rules! features { } impl Features { - fn status(&mut self, feature: &str) -> Option<(&mut bool, Status)> { + fn status(&mut self, feature: &str) -> Option<(&mut bool, &'static Feature)> { if feature.contains("_") { return None } let feature = feature.replace("-", "_"); $( if feature == stringify!($feature) { - return Some((&mut self.$feature, stab!($stab))) + return Some((&mut self.$feature, Feature::$feature())) } )* None @@ -173,6 +175,9 @@ macro_rules! stab { (unstable) => { Status::Unstable }; + (removed) => { + Status::Removed + }; } // A listing of all features in Cargo. @@ -187,57 +192,64 @@ macro_rules! stab { // character is translated to `-` when specified in the `cargo-features` // manifest entry in `Cargo.toml`. features! { - pub struct Features { - - // A dummy feature that doesn't actually gate anything, but it's used in - // testing to ensure that we can enable stable features. - [stable] test_dummy_stable: bool, + // A dummy feature that doesn't actually gate anything, but it's used in + // testing to ensure that we can enable stable features. + (stable, test_dummy_stable, "1.0", ""), - // A dummy feature that gates the usage of the `im-a-teapot` manifest - // entry. This is basically just intended for tests. - [unstable] test_dummy_unstable: bool, + // A dummy feature that gates the usage of the `im-a-teapot` manifest + // entry. This is basically just intended for tests. + (unstable, test_dummy_unstable, "", "reference/unstable.html"), - // Downloading packages from alternative registry indexes. - [stable] alternative_registries: bool, + // Downloading packages from alternative registry indexes. + (stable, alternative_registries, "1.34", "reference/registries.html"), - // Using editions - [stable] edition: bool, + // Using editions + (stable, edition, "1.31", "reference/manifest.html#the-edition-field"), - // Renaming a package in the manifest via the `package` key - [stable] rename_dependency: bool, + // Renaming a package in the manifest via the `package` key + (stable, rename_dependency, "1.31", "reference/specifying-dependencies.html#renaming-dependencies-in-cargotoml"), - // Whether a lock file is published with this crate - // This is deprecated, and will likely be removed in a future version. - [unstable] publish_lockfile: bool, + // Whether a lock file is published with this crate + (removed, publish_lockfile, "", PUBLISH_LOCKFILE_REMOVED), - // Overriding profiles for dependencies. - [stable] profile_overrides: bool, + // Overriding profiles for dependencies. + (stable, profile_overrides, "1.41", "reference/profiles.html#overrides"), - // "default-run" manifest option, - [stable] default_run: bool, + // "default-run" manifest option, + (stable, default_run, "1.37", "reference/manifest.html#the-default-run-field"), - // Declarative build scripts. - [unstable] metabuild: bool, + // Declarative build scripts. + (unstable, metabuild, "", "reference/unstable.html#metabuild"), - // Specifying the 'public' attribute on dependencies - [unstable] public_dependency: bool, + // Specifying the 'public' attribute on dependencies + (unstable, public_dependency, "", "reference/unstable.html#public-dependency"), - // Allow to specify profiles other than 'dev', 'release', 'test', etc. - [unstable] named_profiles: bool, + // Allow to specify profiles other than 'dev', 'release', 'test', etc. + (unstable, named_profiles, "", "reference/unstable.html#custom-named-profiles"), - // Opt-in new-resolver behavior. - [stable] resolver: bool, + // Opt-in new-resolver behavior. + (stable, resolver, "1.51", "reference/resolver.html#resolver-versions"), - // Allow to specify whether binaries should be stripped. - [unstable] strip: bool, + // Allow to specify whether binaries should be stripped. + (unstable, strip, "", "reference/unstable.html#profile-strip-option"), - // Specifying a minimal 'rust-version' attribute for crates - [unstable] rust_version: bool, - } + // Specifying a minimal 'rust-version' attribute for crates + (unstable, rust_version, "", "reference/unstable.html#rust-version"), } +const PUBLISH_LOCKFILE_REMOVED: &str = "The publish-lockfile key in Cargo.toml \ + has been removed. The Cargo.lock file is always included when a package is \ + published if the package contains a binary target. `cargo install` requires \ + the `--locked` flag to use the Cargo.lock file.\n\ + See https://doc.rust-lang.org/cargo/commands/cargo-package.html and \ + https://doc.rust-lang.org/cargo/commands/cargo-install.html for more \ + information."; + pub struct Feature { name: &'static str, + stability: Status, + version: &'static str, + docs: &'static str, get: fn(&Features) -> bool, } @@ -251,35 +263,61 @@ impl Features { Ok(ret) } - fn add(&mut self, feature: &str, warnings: &mut Vec) -> CargoResult<()> { - let (slot, status) = match self.status(feature) { + fn add(&mut self, feature_name: &str, warnings: &mut Vec) -> CargoResult<()> { + let (slot, feature) = match self.status(feature_name) { Some(p) => p, - None => bail!("unknown cargo feature `{}`", feature), + None => bail!("unknown cargo feature `{}`", feature_name), }; if *slot { - bail!("the cargo feature `{}` has already been activated", feature); + bail!( + "the cargo feature `{}` has already been activated", + feature_name + ); } - match status { + let see_docs = || { + let url_channel = match channel().as_str() { + "dev" | "nightly" => "nightly/", + "beta" => "beta/", + _ => "", + }; + format!( + "See https://doc.rust-lang.org/{}cargo/{} for more information \ + about using this feature.", + url_channel, feature.docs + ) + }; + + match feature.stability { Status::Stable => { let warning = format!( - "the cargo feature `{}` is now stable \ - and is no longer necessary to be listed \ - in the manifest", - feature + "the cargo feature `{}` has been stabilized in the {} \ + release and is no longer necessary to be listed in the \ + manifest\n {}", + feature_name, + feature.version, + see_docs() ); warnings.push(warning); } Status::Unstable if !nightly_features_allowed() => bail!( "the cargo feature `{}` requires a nightly version of \ Cargo, but this is the `{}` channel\n\ - {}", - feature, + {}\n{}", + feature_name, channel(), - SEE_CHANNELS + SEE_CHANNELS, + see_docs() ), Status::Unstable => {} + Status::Removed => bail!( + "the cargo feature `{}` has been removed\n\ + Remove the feature from Cargo.toml to remove this error.\n\ + {}", + feature_name, + feature.docs + ), } *slot = true; diff --git a/tests/testsuite/cargo_features.rs b/tests/testsuite/cargo_features.rs index 0d8aa242ae1..806fc4195c9 100644 --- a/tests/testsuite/cargo_features.rs +++ b/tests/testsuite/cargo_features.rs @@ -103,8 +103,9 @@ fn stable_feature_warns() { p.cargo("build") .with_stderr( "\ -warning: the cargo feature `test-dummy-stable` is now stable and is no longer \ -necessary to be listed in the manifest +warning: the cargo feature `test-dummy-stable` has been stabilized in the 1.0 \ +release and is no longer necessary to be listed in the manifest + See https://doc.rust-lang.org/[..]cargo/ for more information about using this feature. [COMPILING] a [..] [FINISHED] [..] ", @@ -149,6 +150,8 @@ Caused by: the cargo feature `test-dummy-unstable` requires a nightly version of Cargo, \ but this is the `stable` channel See [..] + See https://doc.rust-lang.org/[..]cargo/reference/unstable.html for more \ + information about using this feature. ", ) .run(); @@ -214,6 +217,8 @@ Caused by: the cargo feature `test-dummy-unstable` requires a nightly version of Cargo, \ but this is the `stable` channel See [..] + See https://doc.rust-lang.org/[..]cargo/reference/unstable.html for more \ + information about using this feature. ", ) .run(); @@ -256,6 +261,8 @@ Caused by: the cargo feature `test-dummy-unstable` requires a nightly version of Cargo, \ but this is the `stable` channel See [..] + See https://doc.rust-lang.org/[..]cargo/reference/unstable.html for more \ + information about using this feature. ", ) .run(); diff --git a/tests/testsuite/pub_priv.rs b/tests/testsuite/pub_priv.rs index a10cb1ef0ef..ba77e7f4a68 100644 --- a/tests/testsuite/pub_priv.rs +++ b/tests/testsuite/pub_priv.rs @@ -115,6 +115,7 @@ error: failed to parse manifest at `[..]` Caused by: the cargo feature `public-dependency` requires a nightly version of Cargo, but this is the `stable` channel See https://doc.rust-lang.org/book/appendix-07-nightly-rust.html for more information about Rust release channels. + See https://doc.rust-lang.org/[..]cargo/reference/unstable.html#public-dependency for more information about using this feature. " ) .run() diff --git a/tests/testsuite/publish_lockfile.rs b/tests/testsuite/publish_lockfile.rs index 9355de07b1d..7be995545f8 100644 --- a/tests/testsuite/publish_lockfile.rs +++ b/tests/testsuite/publish_lockfile.rs @@ -48,12 +48,16 @@ fn deprecated() { .build(); p.cargo("package") .masquerade_as_nightly_cargo() + .with_status(101) .with_stderr( "\ -[PACKAGING] foo v0.1.0 ([..]) -[VERIFYING] foo v0.1.0 ([..]) -[COMPILING] foo v0.1.0 ([..]) -[FINISHED] dev [..] +[ERROR] failed to parse manifest at [..] + +Caused by: + the cargo feature `publish-lockfile` has been removed + Remove the feature from Cargo.toml to remove this error. + The publish-lockfile key [..] + See [..] ", ) .run(); From 778b5357beee8df0939c49f908c0d53ea54ebb15 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 20 Jan 2021 20:11:08 -0800 Subject: [PATCH 7/9] Update the internal documentation on unstable features. Attempts to make it clearer on how the different kinds of unstable support works, and clarify the steps for adding new features and stabilizing. --- src/cargo/core/features.rs | 127 ++++++++++++++++++++++--------------- 1 file changed, 77 insertions(+), 50 deletions(-) diff --git a/src/cargo/core/features.rs b/src/cargo/core/features.rs index 70b3fd43259..494e3399300 100644 --- a/src/cargo/core/features.rs +++ b/src/cargo/core/features.rs @@ -6,44 +6,91 @@ //! unstable features are tracked in this file. //! //! If you're reading this then you're likely interested in adding a feature to -//! Cargo, and the good news is that it shouldn't be too hard! To do this you'll -//! want to follow these steps: +//! Cargo, and the good news is that it shouldn't be too hard! First determine +//! how the feature should be gated: //! -//! 1. Add your feature. Do this by searching for "look here" in this file and -//! expanding the macro invocation that lists all features with your new -//! feature. +//! * New syntax in Cargo.toml should use `cargo-features`. +//! * New CLI options should use `-Z unstable-options`. +//! * New functionality that may not have an interface, or the interface has +//! not yet been designed, or for more complex features that affect multiple +//! parts of Cargo should use a new `-Z` flag. +//! +//! See below for more details. +//! +//! When adding new tests for your feature, usually the tests should go into a +//! new module of the testsuite. See +//! for more information on +//! writing tests. Particularly, check out the "Testing Nightly Features" +//! section for testing unstable features. +//! +//! After you have added your feature, be sure to update the unstable +//! documentation at `src/doc/src/reference/unstable.md` to include a short +//! description of how to use your new feature. +//! +//! And hopefully that's it! +//! +//! ## New Cargo.toml syntax +//! +//! The steps for adding new Cargo.toml syntax are: +//! +//! 1. Add the cargo-features unstable gate. Search below for "look here" to +//! find the `features!` macro and add your feature to the list. +//! +//! 2. Update the Cargo.toml parsing code to handle your new feature. +//! +//! 3. Wherever you added the new parsing code, call +//! `features.require(Feature::my_feature_name())?` if the new syntax is +//! used. This will return an error if the user hasn't listed the feature +//! in `cargo-features` or this is not the nightly channel. +//! +//! ## `-Z unstable-options` //! -//! 2. Find the appropriate place to place the feature gate in Cargo itself. If -//! you're extending the manifest format you'll likely just want to modify -//! the `Manifest::feature_gate` function, but otherwise you may wish to -//! place the feature gate elsewhere in Cargo. +//! `-Z unstable-options` is intended to force the user to opt-in to new CLI +//! flags, options, and new subcommands. //! -//! 3. To actually perform the feature gate, you'll want to have code that looks -//! like: +//! The steps to add a new command-line option are: //! -//! ```rust,compile_fail -//! use core::{Feature, Features}; +//! 1. Add the option to the CLI parsing code. In the help text, be sure to +//! include `(unstable)` to note that this is an unstable option. +//! 2. Where the CLI option is loaded, be sure to call +//! [`CliUnstable::fail_if_stable_opt`]. This will return an error if `-Z +//! unstable options` was not passed. //! -//! let feature = Feature::launch_into_space(); -//! package.manifest().unstable_features().require(feature).chain_err(|| { -//! "launching Cargo into space right now is unstable and may result in \ -//! unintended damage to your codebase, use with caution" -//! })?; -//! ``` +//! ## `-Z` options //! -//! Notably you'll notice the `require` function called with your `Feature`, and -//! then you use `chain_err` to tack on more context for why the feature was -//! required when the feature isn't activated. +//! The steps to add a new `-Z` option are: //! -//! 4. Update the unstable documentation at -//! `src/doc/src/reference/unstable.md` to include a short description of -//! how to use your new feature. When the feature is stabilized, be sure -//! that the Cargo Guide or Reference is updated to fully document the -//! feature and remove the entry from the Unstable section. +//! 1. Add the option to the [`CliUnstable`] struct below. Flags can take an +//! optional value if you want. +//! 2. Update the [`CliUnstable::add`] function to parse the flag. +//! 3. Wherever the new functionality is implemented, call +//! [`Config::cli_unstable`][crate::util::config::Config::cli_unstable] to +//! get an instance of `CliUnstable` and check if the option has been +//! enabled on the `CliUnstable` instance. Nightly gating is already +//! handled, so no need to worry about that. +//! 4. Update the `-Z help` documentation in the `main` function. //! -//! And hopefully that's it! Bear with us though that this is, at the time of -//! this writing, a very new feature in Cargo. If the process differs from this -//! we'll be sure to update this documentation! +//! ## Stabilization +//! +//! For the stabilization process, see +//! . +//! +//! The steps for stabilizing are roughly: +//! +//! 1. Update the feature to be stable, based on the kind of feature: +//! 1. `cargo-features`: Change the feature to `stable` in the `features!` +//! macro below. +//! 2. `-Z unstable-options`: Find the call to `fail_if_stable_opt` and +//! remove it. Be sure to update the man pages if necessary. +//! 3. `-Z` flag: Change the parsing code in [`CliUnstable::add`] to call +//! `stabilized_warn` or `stabilized_err`. Remove it from the `-Z help` +//! docs in the `main` function. Remove the `(unstable)` note in the +//! clap help text if necessary. +//! 2. Remove `masquerade_as_nightly_cargo` from any tests, and remove +//! `cargo-features` from `Cargo.toml` test files if any. +//! 3. Remove the docs from unstable.md and update the redirect at the bottom +//! of that page. Update the rest of the documentation to add the new +//! feature. use std::cell::Cell; use std::env; @@ -367,26 +414,6 @@ impl Features { /// Cargo, like `rustc`, accepts a suite of `-Z` flags which are intended for /// gating unstable functionality to Cargo. These flags are only available on /// the nightly channel of Cargo. -/// -/// This struct doesn't have quite the same convenience macro that the features -/// have above, but the procedure should still be relatively stable for adding a -/// new unstable flag: -/// -/// 1. First, add a field to this `CliUnstable` structure. All flags are allowed -/// to have a value as the `-Z` flags are either of the form `-Z foo` or -/// `-Z foo=bar`, and it's up to you how to parse `bar`. -/// -/// 2. Add an arm to the match statement in `CliUnstable::add` below to match on -/// your new flag. The key (`k`) is what you're matching on and the value is -/// in `v`. -/// -/// 3. (optional) Add a new parsing function to parse your datatype. As of now -/// there's an example for `bool`, but more can be added! -/// -/// 4. In Cargo use `config.cli_unstable()` to get a reference to this structure -/// and then test for your flag or your value and act accordingly. -/// -/// If you have any trouble with this, please let us know! #[derive(Default, Debug, Deserialize)] #[serde(default, rename_all = "kebab-case")] pub struct CliUnstable { From 13b0b70da9863769658830a97b5fa4a180797360 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 20 Jan 2021 20:13:06 -0800 Subject: [PATCH 8/9] Update the user documentation on unstable features. This attempts to make it clearer on the different ways unstable features can be activated. --- src/doc/src/reference/unstable.md | 68 ++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 15 deletions(-) diff --git a/src/doc/src/reference/unstable.md b/src/doc/src/reference/unstable.md index 2e60e6a6bd5..86d50cde6e1 100644 --- a/src/doc/src/reference/unstable.md +++ b/src/doc/src/reference/unstable.md @@ -1,24 +1,62 @@ ## Unstable Features -Experimental Cargo features are only available on the nightly channel. You -typically use one of the `-Z` flags to enable them. Run `cargo -Z help` to -see a list of flags available. +Experimental Cargo features are only available on the [nightly channel]. You +are encouraged to experiment with these features to see if they meet your +needs, and if there are any issues or problems. Check the linked tracking +issues listed below for more information on the feature, and click the GitHub +subscribe button if you want future updates. -`-Z unstable-options` is a generic flag for enabling other unstable -command-line flags. Options requiring this will be called out below. +After some period of time, if the feature does not have any major concerns, it +can be [stabilized], which will make it available on stable once the current +nightly release reaches the stable channel (anywhere from 6 to 12 weeks). -Anything which can be configured with a Z flag can also be set in the cargo -config file (`.cargo/config.toml`) in the `unstable` table. For example: +There are three different ways that unstable features can be enabled based on +how the feature works: -```toml -[unstable] -mtime-on-use = true -multitarget = true -timings = ["html"] -``` +* New syntax in `Cargo.toml` requires a `cargo-features` key at the top of + `Cargo.toml`, before any tables. For example: + + ```toml + # This specifies which new Cargo.toml features are enabled. + cargo-features = ["test-dummy-unstable"] + + [package] + name = "my-package" + version = "0.1.0" + im-a-teapot = true # This is a new option enabled by test-dummy-unstable. + ``` + +* New command-line flags, options, and subcommands require the `-Z + unstable-options` CLI option to also be included. For example, the new + `--out-dir` option is only available on nightly: + + ```cargo +nightly build --out-dir=out -Z unstable-options``` + +* `-Z` command-line flags are used to enable new functionality that may not + have an interface, or the interface has not yet been designed, or for more + complex features that affect multiple parts of Cargo. For example, the + [timings](#timings) feature can be enabled with: -Some unstable features will require you to specify the `cargo-features` key in -`Cargo.toml`. + ```cargo +nightly build -Z timings``` + + Run `cargo -Z help` to see a list of flags available. + + Anything which can be configured with a `-Z` flag can also be set in the + cargo [config file] (`.cargo/config.toml`) in the `unstable` table. For + example: + + ```toml + [unstable] + mtime-on-use = true + multitarget = true + timings = ["html"] + ``` + +Each new feature described below should explain how to use it. + +[config file]: config.md +[nightly channel]: ../../book/appendix-07-nightly-rust.html +[stabilized]: https://doc.crates.io/contrib/process/unstable.html#stabilization ### extra-link-arg * Original Pull Request: [#7811](https://github.com/rust-lang/cargo/pull/7811) From a58e7ffdbc96e06f46232237d8086b469a3e6dcf Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 20 Jan 2021 20:14:25 -0800 Subject: [PATCH 9/9] Add redirects on the unstable docs. This adds some redirects so if there are any links to old documentation, they will get redirect to new documentation. --- src/doc/src/reference/unstable.md | 32 +++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/doc/src/reference/unstable.md b/src/doc/src/reference/unstable.md index 86d50cde6e1..52e3459a389 100644 --- a/src/doc/src/reference/unstable.md +++ b/src/doc/src/reference/unstable.md @@ -1060,3 +1060,35 @@ name = "mypackage" version = "0.0.1" rust-version = "1.42" ``` + +