From 1f48eab757c627b80d79d6ac6e6088bc434f09ae Mon Sep 17 00:00:00 2001
From: heisen-li
Date: Thu, 16 May 2024 20:03:26 +0800
Subject: [PATCH 01/53] fix(toml): remove lib.plugin key
---
crates/cargo-util-schemas/src/manifest/mod.rs | 1 -
src/cargo/core/manifest.rs | 2 +-
src/cargo/util/toml/targets.rs | 41 ++++---------------
3 files changed, 9 insertions(+), 35 deletions(-)
diff --git a/crates/cargo-util-schemas/src/manifest/mod.rs b/crates/cargo-util-schemas/src/manifest/mod.rs
index 375d0de451ac..14659b81cf54 100644
--- a/crates/cargo-util-schemas/src/manifest/mod.rs
+++ b/crates/cargo-util-schemas/src/manifest/mod.rs
@@ -1223,7 +1223,6 @@ pub struct TomlTarget {
pub doctest: Option,
pub bench: Option,
pub doc: Option,
- pub plugin: Option,
pub doc_scrape_examples: Option,
pub proc_macro: Option,
#[serde(rename = "proc_macro")]
diff --git a/src/cargo/core/manifest.rs b/src/cargo/core/manifest.rs
index 14245c410e82..a45a26a765ff 100644
--- a/src/cargo/core/manifest.rs
+++ b/src/cargo/core/manifest.rs
@@ -905,7 +905,7 @@ impl Target {
pub fn documented(&self) -> bool {
self.inner.doc
}
- // A plugin, proc-macro, or build-script.
+ // A proc-macro or build-script.
pub fn for_host(&self) -> bool {
self.inner.for_host
}
diff --git a/src/cargo/util/toml/targets.rs b/src/cargo/util/toml/targets.rs
index 261ff67b3200..5a4c4df83037 100644
--- a/src/cargo/util/toml/targets.rs
+++ b/src/cargo/util/toml/targets.rs
@@ -188,17 +188,6 @@ fn to_lib_target(
let path = lib.path.as_ref().expect("previously resolved");
let path = package_root.join(&path.0);
- if lib.plugin == Some(true) {
- warnings.push(format!(
- "support for rustc plugins has been removed from rustc. \
- library `{}` should not specify `plugin = true`",
- name_or_panic(lib)
- ));
- warnings.push(format!(
- "support for `plugin = true` will be removed from cargo in the future"
- ));
- }
-
// Per the Macros 1.1 RFC:
//
// > Initially if a crate is compiled with the `proc-macro` crate type
@@ -208,8 +197,8 @@ fn to_lib_target(
//
// A plugin requires exporting plugin_registrar so a crate cannot be
// both at once.
- let crate_types = match (lib.crate_types(), lib.plugin, lib.proc_macro()) {
- (Some(kinds), _, _)
+ let crate_types = match (lib.crate_types(), lib.proc_macro()) {
+ (Some(kinds), _)
if kinds.contains(&CrateType::Dylib.as_str().to_owned())
&& kinds.contains(&CrateType::Cdylib.as_str().to_owned()) =>
{
@@ -218,14 +207,7 @@ fn to_lib_target(
name_or_panic(lib)
));
}
- (Some(kinds), _, _) if kinds.contains(&"proc-macro".to_string()) => {
- if let Some(true) = lib.plugin {
- // This is a warning to retain backwards compatibility.
- warnings.push(format!(
- "proc-macro library `{}` should not specify `plugin = true`",
- name_or_panic(lib)
- ));
- }
+ (Some(kinds), _) if kinds.contains(&"proc-macro".to_string()) => {
warnings.push(format!(
"library `{}` should only specify `proc-macro = true` instead of setting `crate-type`",
name_or_panic(lib)
@@ -235,13 +217,9 @@ fn to_lib_target(
}
vec![CrateType::ProcMacro]
}
- (_, Some(true), Some(true)) => {
- anyhow::bail!("`lib.plugin` and `lib.proc-macro` cannot both be `true`")
- }
- (Some(kinds), _, _) => kinds.iter().map(|s| s.into()).collect(),
- (None, Some(true), _) => vec![CrateType::Dylib],
- (None, _, Some(true)) => vec![CrateType::ProcMacro],
- (None, _, _) => vec![CrateType::Lib],
+ (Some(kinds), _) => kinds.iter().map(|s| s.into()).collect(),
+ (None, Some(true)) => vec![CrateType::ProcMacro],
+ (None, _) => vec![CrateType::Lib],
};
let mut target = Target::lib_target(name_or_panic(lib), crate_types, path, edition);
@@ -863,11 +841,8 @@ fn configure(toml: &TomlTarget, target: &mut Target) -> CargoResult<()> {
Some(false) => RustdocScrapeExamples::Disabled,
Some(true) => RustdocScrapeExamples::Enabled,
})
- .set_for_host(match (toml.plugin, toml.proc_macro()) {
- (None, None) => t2.for_host(),
- (Some(true), _) | (_, Some(true)) => true,
- (Some(false), _) | (_, Some(false)) => false,
- });
+ .set_for_host(toml.proc_macro().unwrap_or_else(|| t2.for_host()));
+
if let Some(edition) = toml.edition.clone() {
target.set_edition(
edition
From 8056001e8a6e764d2dbf4ad2f4c75e7a812efea8 Mon Sep 17 00:00:00 2001
From: heisen-li
Date: Thu, 16 May 2024 20:18:54 +0800
Subject: [PATCH 02/53] remove or change lib.plugin related test
---
tests/testsuite/build_script.rs | 55 ------
tests/testsuite/cross_compile.rs | 41 ----
tests/testsuite/proc_macro.rs | 36 ++--
tests/testsuite/rustflags.rs | 322 +------------------------------
4 files changed, 26 insertions(+), 428 deletions(-)
diff --git a/tests/testsuite/build_script.rs b/tests/testsuite/build_script.rs
index ef76309233b6..65a004ee66b8 100644
--- a/tests/testsuite/build_script.rs
+++ b/tests/testsuite/build_script.rs
@@ -2177,61 +2177,6 @@ fn shared_dep_with_a_build_script() {
p.cargo("build -v").run();
}
-#[cargo_test]
-fn transitive_dep_host() {
- let p = project()
- .file(
- "Cargo.toml",
- r#"
- [package]
- name = "foo"
- version = "0.5.0"
- edition = "2015"
- authors = []
- build = "build.rs"
-
- [build-dependencies.b]
- path = "b"
- "#,
- )
- .file("src/lib.rs", "")
- .file("build.rs", "fn main() {}")
- .file(
- "a/Cargo.toml",
- r#"
- [package]
- name = "a"
- version = "0.5.0"
- edition = "2015"
- authors = []
- links = "foo"
- build = "build.rs"
- "#,
- )
- .file("a/build.rs", "fn main() {}")
- .file("a/src/lib.rs", "")
- .file(
- "b/Cargo.toml",
- r#"
- [package]
- name = "b"
- version = "0.5.0"
- edition = "2015"
- authors = []
-
- [lib]
- name = "b"
- plugin = true
-
- [dependencies.a]
- path = "../a"
- "#,
- )
- .file("b/src/lib.rs", "")
- .build();
- p.cargo("build").run();
-}
-
#[cargo_test]
fn test_a_lib_with_a_build_command() {
let p = project()
diff --git a/tests/testsuite/cross_compile.rs b/tests/testsuite/cross_compile.rs
index bcb0a4190179..85cc7174ced1 100644
--- a/tests/testsuite/cross_compile.rs
+++ b/tests/testsuite/cross_compile.rs
@@ -883,47 +883,6 @@ fn build_script_only_host() {
p.cargo("build -v --target").arg(&target).run();
}
-#[cargo_test]
-fn plugin_build_script_right_arch() {
- if cross_compile::disabled() {
- return;
- }
- let p = project()
- .file(
- "Cargo.toml",
- r#"
- [package]
- name = "foo"
- version = "0.0.1"
- edition = "2015"
- authors = []
- build = "build.rs"
-
- [lib]
- name = "foo"
- plugin = true
- "#,
- )
- .file("build.rs", "fn main() {}")
- .file("src/lib.rs", "")
- .build();
-
- p.cargo("build -v --target")
- .arg(cross_compile::alternate())
- .with_stderr(
- "\
-[WARNING] support for rustc plugins has been removed from rustc. library `foo` should not specify `plugin = true`
-[WARNING] support for `plugin = true` will be removed from cargo in the future
-[COMPILING] foo v0.0.1 ([..])
-[RUNNING] `rustc [..] build.rs [..]`
-[RUNNING] `[..]/build-script-build`
-[RUNNING] `rustc [..] src/lib.rs [..]`
-[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [..]
-",
- )
- .run();
-}
-
#[cargo_test]
fn build_script_with_platform_specific_dependencies() {
if cross_compile::disabled() {
diff --git a/tests/testsuite/proc_macro.rs b/tests/testsuite/proc_macro.rs
index 86bfe086c995..0d793f10c50e 100644
--- a/tests/testsuite/proc_macro.rs
+++ b/tests/testsuite/proc_macro.rs
@@ -346,7 +346,7 @@ fn proc_macro_crate_type_warning() {
}
#[cargo_test]
-fn proc_macro_crate_type_warning_plugin() {
+fn lib_plugin_unused_key_warning() {
let foo = project()
.file(
"Cargo.toml",
@@ -356,7 +356,6 @@ fn proc_macro_crate_type_warning_plugin() {
version = "0.1.0"
edition = "2015"
[lib]
- crate-type = ["proc-macro"]
plugin = true
"#,
)
@@ -364,18 +363,33 @@ fn proc_macro_crate_type_warning_plugin() {
.build();
foo.cargo("check")
- .with_stderr_contains(
- "[WARNING] support for rustc plugins has been removed from rustc. \
- library `foo` should not specify `plugin = true`")
- .with_stderr_contains(
- "[WARNING] support for `plugin = true` will be removed from cargo in the future")
- .with_stderr_contains(
- "[WARNING] proc-macro library `foo` should not specify `plugin = true`")
- .with_stderr_contains(
- "[WARNING] library `foo` should only specify `proc-macro = true` instead of setting `crate-type`")
+ .with_stderr_contains("[WARNING] unused manifest key: lib.plugin")
.run();
}
+#[cargo_test]
+fn proc_macro_crate_type_warning_plugin() {
+ let foo = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.1.0"
+ edition = "2015"
+ [lib]
+ crate-type = ["proc-macro"]
+ "#,
+ )
+ .file("src/lib.rs", "")
+ .build();
+
+ foo.cargo("check")
+ .with_stderr_contains(
+ "[WARNING] library `foo` should only specify `proc-macro = true` instead of setting `crate-type`")
+ .run();
+}
+
#[cargo_test]
fn proc_macro_crate_type_multiple() {
let foo = project()
diff --git a/tests/testsuite/rustflags.rs b/tests/testsuite/rustflags.rs
index 1f7ca1bd7eaf..564f70c33a34 100644
--- a/tests/testsuite/rustflags.rs
+++ b/tests/testsuite/rustflags.rs
@@ -1,9 +1,7 @@
//! Tests for setting custom rustc flags.
use cargo_test_support::registry::Package;
-use cargo_test_support::{
- basic_lib_manifest, basic_manifest, paths, project, project_in_home, rustc_host,
-};
+use cargo_test_support::{basic_manifest, paths, project, project_in_home, rustc_host};
use std::fs;
#[cargo_test]
@@ -114,76 +112,6 @@ fn env_rustflags_build_script_dep() {
foo.cargo("check").env("RUSTFLAGS", "--cfg foo").run();
}
-#[cargo_test]
-fn env_rustflags_plugin() {
- // RUSTFLAGS should be passed to rustc for plugins
- // when --target is not specified.
- // In this test if --cfg foo is not passed the build will fail.
- let p = project()
- .file(
- "Cargo.toml",
- r#"
- [package]
- name = "foo"
- version = "0.0.1"
-
- [lib]
- name = "foo"
- plugin = true
- "#,
- )
- .file(
- "src/lib.rs",
- r#"
- fn main() { }
- #[cfg(not(foo))]
- fn main() { }
- "#,
- )
- .build();
-
- p.cargo("check").env("RUSTFLAGS", "--cfg foo").run();
-}
-
-#[cargo_test]
-fn env_rustflags_plugin_dep() {
- // RUSTFLAGS should be passed to rustc for plugins
- // when --target is not specified.
- // In this test if --cfg foo is not passed the build will fail.
- let foo = project()
- .file(
- "Cargo.toml",
- r#"
- [package]
- name = "foo"
- version = "0.0.1"
-
- [lib]
- name = "foo"
- plugin = true
-
- [dependencies.bar]
- path = "../bar"
- "#,
- )
- .file("src/lib.rs", "fn foo() {}")
- .build();
- let _bar = project()
- .at("bar")
- .file("Cargo.toml", &basic_lib_manifest("bar"))
- .file(
- "src/lib.rs",
- r#"
- fn bar() { }
- #[cfg(not(foo))]
- fn bar() { }
- "#,
- )
- .build();
-
- foo.cargo("check").env("RUSTFLAGS", "--cfg foo").run();
-}
-
#[cargo_test]
fn env_rustflags_normal_source_with_target() {
let p = project()
@@ -345,84 +273,6 @@ fn env_rustflags_build_script_dep_with_target() {
.run();
}
-#[cargo_test]
-fn env_rustflags_plugin_with_target() {
- // RUSTFLAGS should not be passed to rustc for plugins
- // when --target is specified.
- // In this test if --cfg foo is passed the build will fail.
- let p = project()
- .file(
- "Cargo.toml",
- r#"
- [package]
- name = "foo"
- version = "0.0.1"
-
- [lib]
- name = "foo"
- plugin = true
- "#,
- )
- .file(
- "src/lib.rs",
- r#"
- fn main() { }
- #[cfg(foo)]
- fn main() { }
- "#,
- )
- .build();
-
- let host = rustc_host();
- p.cargo("check --target")
- .arg(host)
- .env("RUSTFLAGS", "--cfg foo")
- .run();
-}
-
-#[cargo_test]
-fn env_rustflags_plugin_dep_with_target() {
- // RUSTFLAGS should not be passed to rustc for plugins
- // when --target is specified.
- // In this test if --cfg foo is passed the build will fail.
- let foo = project()
- .file(
- "Cargo.toml",
- r#"
- [package]
- name = "foo"
- version = "0.0.1"
-
- [lib]
- name = "foo"
- plugin = true
-
- [dependencies.bar]
- path = "../bar"
- "#,
- )
- .file("src/lib.rs", "fn foo() {}")
- .build();
- let _bar = project()
- .at("bar")
- .file("Cargo.toml", &basic_lib_manifest("bar"))
- .file(
- "src/lib.rs",
- r#"
- fn bar() { }
- #[cfg(foo)]
- fn bar() { }
- "#,
- )
- .build();
-
- let host = rustc_host();
- foo.cargo("check --target")
- .arg(host)
- .env("RUSTFLAGS", "--cfg foo")
- .run();
-}
-
#[cargo_test]
fn env_rustflags_recompile() {
let p = project().file("src/lib.rs", "").build();
@@ -583,90 +433,6 @@ fn build_rustflags_build_script_dep() {
foo.cargo("check").run();
}
-#[cargo_test]
-fn build_rustflags_plugin() {
- // RUSTFLAGS should be passed to rustc for plugins
- // when --target is not specified.
- // In this test if --cfg foo is not passed the build will fail.
- let p = project()
- .file(
- "Cargo.toml",
- r#"
- [package]
- name = "foo"
- version = "0.0.1"
-
- [lib]
- name = "foo"
- plugin = true
- "#,
- )
- .file(
- "src/lib.rs",
- r#"
- fn main() { }
- #[cfg(not(foo))]
- fn main() { }
- "#,
- )
- .file(
- ".cargo/config.toml",
- r#"
- [build]
- rustflags = ["--cfg", "foo"]
- "#,
- )
- .build();
-
- p.cargo("check").run();
-}
-
-#[cargo_test]
-fn build_rustflags_plugin_dep() {
- // RUSTFLAGS should be passed to rustc for plugins
- // when --target is not specified.
- // In this test if --cfg foo is not passed the build will fail.
- let foo = project()
- .file(
- "Cargo.toml",
- r#"
- [package]
- name = "foo"
- version = "0.0.1"
-
- [lib]
- name = "foo"
- plugin = true
-
- [dependencies.bar]
- path = "../bar"
- "#,
- )
- .file("src/lib.rs", "fn foo() {}")
- .file(
- ".cargo/config.toml",
- r#"
- [build]
- rustflags = ["--cfg", "foo"]
- "#,
- )
- .build();
- let _bar = project()
- .at("bar")
- .file("Cargo.toml", &basic_lib_manifest("bar"))
- .file(
- "src/lib.rs",
- r#"
- fn bar() { }
- #[cfg(not(foo))]
- fn bar() { }
- "#,
- )
- .build();
-
- foo.cargo("check").run();
-}
-
#[cargo_test]
fn build_rustflags_normal_source_with_target() {
let p = project()
@@ -800,92 +566,6 @@ fn build_rustflags_build_script_dep_with_target() {
foo.cargo("check --target").arg(host).run();
}
-#[cargo_test]
-fn build_rustflags_plugin_with_target() {
- // RUSTFLAGS should not be passed to rustc for plugins
- // when --target is specified.
- // In this test if --cfg foo is passed the build will fail.
- let p = project()
- .file(
- "Cargo.toml",
- r#"
- [package]
- name = "foo"
- version = "0.0.1"
-
- [lib]
- name = "foo"
- plugin = true
- "#,
- )
- .file(
- "src/lib.rs",
- r#"
- fn main() { }
- #[cfg(foo)]
- fn main() { }
- "#,
- )
- .file(
- ".cargo/config.toml",
- r#"
- [build]
- rustflags = ["--cfg", "foo"]
- "#,
- )
- .build();
-
- let host = rustc_host();
- p.cargo("check --target").arg(host).run();
-}
-
-#[cargo_test]
-fn build_rustflags_plugin_dep_with_target() {
- // RUSTFLAGS should not be passed to rustc for plugins
- // when --target is specified.
- // In this test if --cfg foo is passed the build will fail.
- let foo = project()
- .file(
- "Cargo.toml",
- r#"
- [package]
- name = "foo"
- version = "0.0.1"
-
- [lib]
- name = "foo"
- plugin = true
-
- [dependencies.bar]
- path = "../bar"
- "#,
- )
- .file("src/lib.rs", "fn foo() {}")
- .file(
- ".cargo/config.toml",
- r#"
- [build]
- rustflags = ["--cfg", "foo"]
- "#,
- )
- .build();
- let _bar = project()
- .at("bar")
- .file("Cargo.toml", &basic_lib_manifest("bar"))
- .file(
- "src/lib.rs",
- r#"
- fn bar() { }
- #[cfg(foo)]
- fn bar() { }
- "#,
- )
- .build();
-
- let host = rustc_host();
- foo.cargo("check --target").arg(host).run();
-}
-
#[cargo_test]
fn build_rustflags_recompile() {
let p = project().file("src/lib.rs", "").build();
From a969971632a16625f72b320845213d03fe99898b Mon Sep 17 00:00:00 2001
From: heisen-li
Date: Thu, 16 May 2024 20:24:07 +0800
Subject: [PATCH 03/53] After deleting the key lib.plugin, modify the
corresponding document.
---
src/doc/src/reference/cargo-targets.md | 3 +--
src/doc/src/reference/environment-variables.md | 2 +-
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/src/doc/src/reference/cargo-targets.md b/src/doc/src/reference/cargo-targets.md
index 9129310399c6..38a6f4be31fd 100644
--- a/src/doc/src/reference/cargo-targets.md
+++ b/src/doc/src/reference/cargo-targets.md
@@ -184,7 +184,6 @@ test = true # Is tested by default.
doctest = true # Documentation examples are tested by default.
bench = true # Is benchmarked by default.
doc = true # Is documented by default.
-plugin = false # Used as a compiler plugin (deprecated).
proc-macro = false # Set to `true` for a proc-macro library.
harness = true # Use libtest harness.
edition = "2015" # The edition of the target.
@@ -247,7 +246,7 @@ libraries and binaries.
### The `plugin` field
-This field is used for `rustc` plugins, which are being deprecated.
+This option is deprecated and unused.
### The `proc-macro` field
diff --git a/src/doc/src/reference/environment-variables.md b/src/doc/src/reference/environment-variables.md
index 45de5329b28f..9904b66268a1 100644
--- a/src/doc/src/reference/environment-variables.md
+++ b/src/doc/src/reference/environment-variables.md
@@ -299,7 +299,7 @@ Cargo includes the following paths:
Cargo to properly set the environment if additional libraries on the system
are needed in the search path.
* The base output directory, such as `target/debug`, and the "deps" directory.
- This is mostly for legacy support of `rustc` compiler plugins.
+ This is mostly for support of proc-macros.
* The rustc sysroot library path. This generally is not important to most
users.
From 09a8ece8eefbf7d3054a83631d1a0afe00d862f1 Mon Sep 17 00:00:00 2001
From: heisen-li
Date: Fri, 31 May 2024 15:02:09 +0800
Subject: [PATCH 04/53] fix:Using --release/debug and --profile together
becomes an error
---
src/bin/cargo/commands/bench.rs | 2 +-
src/bin/cargo/commands/clean.rs | 2 +-
src/bin/cargo/commands/install.rs | 2 +-
src/bin/cargo/commands/test.rs | 2 +-
src/cargo/util/command_prelude.rs | 37 +++++++------------
tests/testsuite/check.rs | 13 +++++++
tests/testsuite/profile_custom.rs | 61 ++++++++++++-------------------
7 files changed, 54 insertions(+), 65 deletions(-)
diff --git a/src/bin/cargo/commands/bench.rs b/src/bin/cargo/commands/bench.rs
index f6d8766570d6..c79d7cb350d0 100644
--- a/src/bin/cargo/commands/bench.rs
+++ b/src/bin/cargo/commands/bench.rs
@@ -63,7 +63,7 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
args.compile_options(gctx, CompileMode::Bench, Some(&ws), ProfileChecking::Custom)?;
compile_opts.build_config.requested_profile =
- args.get_profile_name(gctx, "bench", ProfileChecking::Custom)?;
+ args.get_profile_name("bench", ProfileChecking::Custom)?;
let ops = TestOptions {
no_run: args.flag("no-run"),
diff --git a/src/bin/cargo/commands/clean.rs b/src/bin/cargo/commands/clean.rs
index e358b9671509..1764c0bca1c9 100644
--- a/src/bin/cargo/commands/clean.rs
+++ b/src/bin/cargo/commands/clean.rs
@@ -146,7 +146,7 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
gctx,
spec: values(args, "package"),
targets: args.targets()?,
- requested_profile: args.get_profile_name(gctx, "dev", ProfileChecking::Custom)?,
+ requested_profile: args.get_profile_name("dev", ProfileChecking::Custom)?,
profile_specified: args.contains_id("profile") || args.flag("release"),
doc: args.flag("doc"),
dry_run: args.dry_run(),
diff --git a/src/bin/cargo/commands/install.rs b/src/bin/cargo/commands/install.rs
index e188d6a0d677..79e39c163f79 100644
--- a/src/bin/cargo/commands/install.rs
+++ b/src/bin/cargo/commands/install.rs
@@ -196,7 +196,7 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
)?;
compile_opts.build_config.requested_profile =
- args.get_profile_name(gctx, "release", ProfileChecking::Custom)?;
+ args.get_profile_name("release", ProfileChecking::Custom)?;
if args.flag("list") {
ops::install_list(root, gctx)?;
diff --git a/src/bin/cargo/commands/test.rs b/src/bin/cargo/commands/test.rs
index 1815ee62f9f7..c2657a78f054 100644
--- a/src/bin/cargo/commands/test.rs
+++ b/src/bin/cargo/commands/test.rs
@@ -74,7 +74,7 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
args.compile_options(gctx, CompileMode::Test, Some(&ws), ProfileChecking::Custom)?;
compile_opts.build_config.requested_profile =
- args.get_profile_name(gctx, "test", ProfileChecking::Custom)?;
+ args.get_profile_name("test", ProfileChecking::Custom)?;
// `TESTNAME` is actually an argument of the test binary, but it's
// important, so we explicitly mention it and reconfigure.
diff --git a/src/cargo/util/command_prelude.rs b/src/cargo/util/command_prelude.rs
index 63435b50eaaf..11164b8409c4 100644
--- a/src/cargo/util/command_prelude.rs
+++ b/src/cargo/util/command_prelude.rs
@@ -558,12 +558,19 @@ Run `{cmd}` to see possible targets."
fn get_profile_name(
&self,
- gctx: &GlobalContext,
default: &str,
profile_checking: ProfileChecking,
) -> CargoResult {
let specified_profile = self._value_of("profile");
+ let err_message = |flag: &str| {
+ format!(
+ "\
+the `--{flag}` flag can not be specified with the `--profile` flag
+Please remove one of the flags."
+ )
+ };
+
// Check for allowed legacy names.
// This is an early exit, since it allows combination with `--release`.
match (specified_profile, profile_checking) {
@@ -572,39 +579,23 @@ Run `{cmd}` to see possible targets."
// `cargo fix` and `cargo check` has legacy handling of this profile name
| (Some(name @ "test"), ProfileChecking::LegacyTestOnly) => {
if self.maybe_flag("release") {
- gctx.shell().warn(
- "the `--release` flag should not be specified with the `--profile` flag\n\
- The `--release` flag will be ignored.\n\
- This was historically accepted, but will become an error \
- in a future release."
- )?;
+ bail!(err_message("release"));
}
return Ok(InternedString::new(name));
}
_ => {}
}
- let conflict = |flag: &str, equiv: &str, specified: &str| -> anyhow::Error {
- anyhow::format_err!(
- "conflicting usage of --profile={} and --{flag}\n\
- The `--{flag}` flag is the same as `--profile={equiv}`.\n\
- Remove one flag or the other to continue.",
- specified,
- flag = flag,
- equiv = equiv
- )
- };
-
let name = match (
self.maybe_flag("release"),
self.maybe_flag("debug"),
specified_profile,
) {
(false, false, None) => default,
- (true, _, None | Some("release")) => "release",
- (true, _, Some(name)) => return Err(conflict("release", "release", name)),
- (_, true, None | Some("dev")) => "dev",
- (_, true, Some(name)) => return Err(conflict("debug", "dev", name)),
+ (true, _, None) => "release",
+ (true, _, Some(_)) => bail!(err_message("release")),
+ (_, true, None) => "dev",
+ (_, true, Some(_)) => bail!(err_message("debug")),
// `doc` is separate from all the other reservations because
// [profile.doc] was historically allowed, but is deprecated and
// has no effect. To avoid potentially breaking projects, it is a
@@ -710,7 +701,7 @@ Run `{cmd}` to see possible targets."
mode,
)?;
build_config.message_format = message_format.unwrap_or(MessageFormat::Human);
- build_config.requested_profile = self.get_profile_name(gctx, "dev", profile_checking)?;
+ build_config.requested_profile = self.get_profile_name("dev", profile_checking)?;
build_config.build_plan = self.flag("build-plan");
build_config.unit_graph = self.flag("unit-graph");
build_config.future_incompat_report = self.flag("future-incompat-report");
diff --git a/tests/testsuite/check.rs b/tests/testsuite/check.rs
index da8239fd748e..ab135c7cb21f 100644
--- a/tests/testsuite/check.rs
+++ b/tests/testsuite/check.rs
@@ -289,8 +289,21 @@ fn rustc_check() {
// Verify compatible usage of --profile with --release, issue #7488
foo.cargo("rustc --profile check --release -- --emit=metadata")
+ .with_status(101)
+ .with_stderr(
+ "\
+error: the `--release` flag can not be specified with the `--profile` flag
+Please remove one of the flags.",
+ )
.run();
+
foo.cargo("rustc --profile test --release -- --emit=metadata")
+ .with_status(101)
+ .with_stderr(
+ "\
+error: the `--release` flag can not be specified with the `--profile` flag
+Please remove one of the flags.",
+ )
.run();
}
diff --git a/tests/testsuite/profile_custom.rs b/tests/testsuite/profile_custom.rs
index e906d11ccf37..22481fabdeb5 100644
--- a/tests/testsuite/profile_custom.rs
+++ b/tests/testsuite/profile_custom.rs
@@ -383,10 +383,8 @@ fn conflicting_usage() {
.with_status(101)
.with_stderr(
"\
-error: conflicting usage of --profile=dev and --release
-The `--release` flag is the same as `--profile=release`.
-Remove one flag or the other to continue.
-",
+error: the `--release` flag can not be specified with the `--profile` flag
+Please remove one of the flags.",
)
.run();
@@ -394,21 +392,17 @@ Remove one flag or the other to continue.
.with_status(101)
.with_stderr(
"\
-error: conflicting usage of --profile=release and --debug
-The `--debug` flag is the same as `--profile=dev`.
-Remove one flag or the other to continue.
-",
+error: the `--debug` flag can not be specified with the `--profile` flag
+Please remove one of the flags.",
)
.run();
p.cargo("rustc --profile=dev --release")
+ .with_status(101)
.with_stderr(
"\
-warning: the `--release` flag should not be specified with the `--profile` flag
-The `--release` flag will be ignored.
-This was historically accepted, but will become an error in a future release.
-[COMPILING] foo [..]
-[FINISHED] `dev` profile [..]
+error: the `--release` flag can not be specified with the `--profile` flag
+Please remove one of the flags.
",
)
.run();
@@ -417,52 +411,45 @@ This was historically accepted, but will become an error in a future release.
.with_status(101)
.with_stderr(
"\
-error: conflicting usage of --profile=dev and --release
-The `--release` flag is the same as `--profile=release`.
-Remove one flag or the other to continue.
-",
+error: the `--release` flag can not be specified with the `--profile` flag
+Please remove one of the flags.",
)
.run();
p.cargo("check --profile=test --release")
+ .with_status(101)
.with_stderr(
"\
-warning: the `--release` flag should not be specified with the `--profile` flag
-The `--release` flag will be ignored.
-This was historically accepted, but will become an error in a future release.
-[CHECKING] foo [..]
-[FINISHED] `test` profile [..]
-",
+error: the `--release` flag can not be specified with the `--profile` flag
+Please remove one of the flags.",
)
.run();
// This is OK since the two are the same.
p.cargo("rustc --profile=release --release")
+ .with_status(101)
.with_stderr(
"\
-[COMPILING] foo [..]
-[FINISHED] `release` profile [..]
-",
+error: the `--release` flag can not be specified with the `--profile` flag
+Please remove one of the flags.",
)
.run();
p.cargo("build --profile=release --release")
+ .with_status(101)
.with_stderr(
"\
-[FINISHED] `release` profile [..]
-",
+error: the `--release` flag can not be specified with the `--profile` flag
+Please remove one of the flags.",
)
.run();
p.cargo("install --path . --profile=dev --debug")
+ .with_status(101)
.with_stderr(
"\
-[INSTALLING] foo [..]
-[FINISHED] `dev` profile [..]
-[INSTALLING] [..]
-[INSTALLED] [..]
-[WARNING] be sure to add [..]
-",
+error: the `--debug` flag can not be specified with the `--profile` flag
+Please remove one of the flags.",
)
.run();
@@ -470,10 +457,8 @@ This was historically accepted, but will become an error in a future release.
.with_status(101)
.with_stderr(
"\
-error: conflicting usage of --profile=release and --debug
-The `--debug` flag is the same as `--profile=dev`.
-Remove one flag or the other to continue.
-",
+error: the `--debug` flag can not be specified with the `--profile` flag
+Please remove one of the flags.",
)
.run();
}
From 193319c66c92d20ffbedc304425f92c13889f0e2 Mon Sep 17 00:00:00 2001
From: heisen-li
Date: Tue, 4 Jun 2024 12:32:18 +0800
Subject: [PATCH 05/53] fix(toml): Convert warnings that license and readme
files do not exist into errors
---
src/cargo/ops/cargo_package.rs | 31 ++++++++++++------
tests/testsuite/package.rs | 57 +++++++++++++---------------------
tests/testsuite/publish.rs | 50 +----------------------------
tests/testsuite/registry.rs | 2 +-
4 files changed, 45 insertions(+), 95 deletions(-)
diff --git a/src/cargo/ops/cargo_package.rs b/src/cargo/ops/cargo_package.rs
index 533852551c20..b0168aebf863 100644
--- a/src/cargo/ops/cargo_package.rs
+++ b/src/cargo/ops/cargo_package.rs
@@ -310,6 +310,8 @@ fn build_ar_list(
});
}
+ let mut invalid_manifest_field: Vec = vec![];
+
let mut result = result.into_values().flatten().collect();
if let Some(license_file) = &pkg.manifest().metadata().license_file {
let license_path = Path::new(license_file);
@@ -324,7 +326,12 @@ fn build_ar_list(
ws,
)?;
} else {
- warn_on_nonexistent_file(&pkg, &license_path, "license-file", &ws)?;
+ error_on_nonexistent_file(
+ &pkg,
+ &license_path,
+ "license-file",
+ &mut invalid_manifest_field,
+ );
}
}
if let Some(readme) = &pkg.manifest().metadata().readme {
@@ -333,10 +340,14 @@ fn build_ar_list(
if abs_file_path.is_file() {
check_for_file_and_add("readme", readme_path, abs_file_path, pkg, &mut result, ws)?;
} else {
- warn_on_nonexistent_file(&pkg, &readme_path, "readme", &ws)?;
+ error_on_nonexistent_file(&pkg, &readme_path, "readme", &mut invalid_manifest_field);
}
}
+ if !invalid_manifest_field.is_empty() {
+ return Err(anyhow::anyhow!(invalid_manifest_field.join("\n")));
+ }
+
for t in pkg
.manifest()
.targets()
@@ -406,25 +417,27 @@ fn check_for_file_and_add(
Ok(())
}
-fn warn_on_nonexistent_file(
+fn error_on_nonexistent_file(
pkg: &Package,
path: &Path,
manifest_key_name: &'static str,
- ws: &Workspace<'_>,
-) -> CargoResult<()> {
+ invalid: &mut Vec,
+) {
let rel_msg = if path.is_absolute() {
"".to_string()
} else {
format!(" (relative to `{}`)", pkg.root().display())
};
- ws.gctx().shell().warn(&format!(
+
+ let msg = format!(
"{manifest_key_name} `{}` does not appear to exist{}.\n\
- Please update the {manifest_key_name} setting in the manifest at `{}`\n\
- This may become a hard error in the future.",
+ Please update the {manifest_key_name} setting in the manifest at `{}`.",
path.display(),
rel_msg,
pkg.manifest_path().display()
- ))
+ );
+
+ invalid.push(msg);
}
fn error_custom_build_file_not_in_package(
diff --git a/tests/testsuite/package.rs b/tests/testsuite/package.rs
index 850fe9c50b9b..68a21663a4e5 100644
--- a/tests/testsuite/package.rs
+++ b/tests/testsuite/package.rs
@@ -1943,8 +1943,7 @@ fn exclude_dot_files_and_directories_by_default() {
#[cargo_test]
fn empty_readme_path() {
- // Warn but don't fail if `readme` is empty.
- // Issue #11522.
+ // fail if `readme` is empty.
let p = project()
.file(
"Cargo.toml",
@@ -1963,13 +1962,11 @@ fn empty_readme_path() {
.build();
p.cargo("package --no-verify")
+ .with_status(101)
.with_stderr(
"\
-[WARNING] readme `` does not appear to exist (relative to `[..]/foo`).
-Please update the readme setting in the manifest at `[..]/foo/Cargo.toml`
-This may become a hard error in the future.
-[PACKAGING] foo v1.0.0 ([..]/foo)
-[PACKAGED] [..] files, [..] ([..] compressed)
+[ERROR] readme `` does not appear to exist (relative to `[..]/foo`).
+Please update the readme setting in the manifest at `[..]/foo/Cargo.toml`.
",
)
.run();
@@ -1977,8 +1974,7 @@ This may become a hard error in the future.
#[cargo_test]
fn invalid_readme_path() {
- // Warn but don't fail if `readme` path is invalid.
- // Issue #11522.
+ // fail if `readme` path is invalid.
let p = project()
.file(
"Cargo.toml",
@@ -1997,13 +1993,11 @@ fn invalid_readme_path() {
.build();
p.cargo("package --no-verify")
+ .with_status(101)
.with_stderr(
"\
-[WARNING] readme `DOES-NOT-EXIST` does not appear to exist (relative to `[..]/foo`).
-Please update the readme setting in the manifest at `[..]/foo/Cargo.toml`
-This may become a hard error in the future.
-[PACKAGING] foo v1.0.0 ([..]/foo)
-[PACKAGED] [..] files, [..] ([..] compressed)
+[ERROR] readme `DOES-NOT-EXIST` does not appear to exist (relative to `[..]/foo`).
+Please update the readme setting in the manifest at `[..]/foo/Cargo.toml`.
",
)
.run();
@@ -2011,8 +2005,7 @@ This may become a hard error in the future.
#[cargo_test]
fn readme_or_license_file_is_dir() {
- // Test warning when `readme` or `license-file` is a directory, not a file.
- // Issue #11522.
+ // Test error when `readme` or `license-file` is a directory, not a file.
let p = project()
.file(
"Cargo.toml",
@@ -2031,16 +2024,13 @@ fn readme_or_license_file_is_dir() {
.build();
p.cargo("package --no-verify")
+ .with_status(101)
.with_stderr(
"\
-[WARNING] license-file `./src` does not appear to exist (relative to `[..]/foo`).
-Please update the license-file setting in the manifest at `[..]/foo/Cargo.toml`
-This may become a hard error in the future.
-[WARNING] readme `./src` does not appear to exist (relative to `[..]/foo`).
-Please update the readme setting in the manifest at `[..]/foo/Cargo.toml`
-This may become a hard error in the future.
-[PACKAGING] foo v1.0.0 ([..]/foo)
-[PACKAGED] [..] files, [..] ([..] compressed)
+[ERROR] license-file `./src` does not appear to exist (relative to `[..]/foo`).
+Please update the license-file setting in the manifest at `[..]/foo/Cargo.toml`.
+readme `./src` does not appear to exist (relative to `[..]/foo`).
+Please update the readme setting in the manifest at `[..]/foo/Cargo.toml`.
",
)
.run();
@@ -2048,8 +2038,7 @@ This may become a hard error in the future.
#[cargo_test]
fn empty_license_file_path() {
- // Warn but don't fail if license-file is empty.
- // Issue #11522.
+ // fail if license-file is empty.
let p = project()
.file(
"Cargo.toml",
@@ -2067,15 +2056,13 @@ fn empty_license_file_path() {
.build();
p.cargo("package --no-verify")
+ .with_status(101)
.with_stderr(
"\
[WARNING] manifest has no license or license-file.
See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info.
-[WARNING] license-file `` does not appear to exist (relative to `[..]/foo`).
-Please update the license-file setting in the manifest at `[..]/foo/Cargo.toml`
-This may become a hard error in the future.
-[PACKAGING] foo v1.0.0 ([..]/foo)
-[PACKAGED] [..] files, [..] ([..] compressed)
+[ERROR] license-file `` does not appear to exist (relative to `[..]/foo`).
+Please update the license-file setting in the manifest at `[..]/foo/Cargo.toml`.
",
)
.run();
@@ -2101,13 +2088,11 @@ fn invalid_license_file_path() {
.build();
p.cargo("package --no-verify")
+ .with_status(101)
.with_stderr(
"\
-[WARNING] license-file `does-not-exist` does not appear to exist (relative to `[..]/foo`).
-Please update the license-file setting in the manifest at `[..]/foo/Cargo.toml`
-This may become a hard error in the future.
-[PACKAGING] foo v1.0.0 ([..]/foo)
-[PACKAGED] [..] files, [..] ([..] compressed)
+[ERROR] license-file `does-not-exist` does not appear to exist (relative to `[..]/foo`).
+Please update the license-file setting in the manifest at `[..]/foo/Cargo.toml`.
",
)
.run();
diff --git a/tests/testsuite/publish.rs b/tests/testsuite/publish.rs
index 38577bbcfdde..c182b5087491 100644
--- a/tests/testsuite/publish.rs
+++ b/tests/testsuite/publish.rs
@@ -3,7 +3,7 @@
use cargo_test_support::git::{self, repo};
use cargo_test_support::paths;
use cargo_test_support::registry::{self, Package, RegistryBuilder, Response};
-use cargo_test_support::{basic_manifest, no_such_file_err_msg, project, publish};
+use cargo_test_support::{basic_manifest, project, publish};
use std::fs;
use std::sync::{Arc, Mutex};
@@ -2137,54 +2137,6 @@ include `--registry dummy-registry` or `--registry crates-io`
.run();
}
-#[cargo_test]
-fn publish_with_missing_readme() {
- // Use local registry for faster test times since no publish will occur
- let registry = registry::init();
-
- let p = project()
- .file(
- "Cargo.toml",
- r#"
- [package]
- name = "foo"
- version = "0.1.0"
- edition = "2015"
- authors = []
- license = "MIT"
- description = "foo"
- homepage = "https://example.com/"
- readme = "foo.md"
- "#,
- )
- .file("src/lib.rs", "")
- .build();
-
- p.cargo("publish --no-verify")
- .replace_crates_io(registry.index_url())
- .with_status(101)
- .with_stderr(&format!(
- "\
-[UPDATING] [..]
-[WARNING] readme `foo.md` does not appear to exist (relative to `[..]/foo`).
-Please update the readme setting in the manifest at `[..]/foo/Cargo.toml`
-This may become a hard error in the future.
-[PACKAGING] foo v0.1.0 [..]
-[PACKAGED] [..] files, [..] ([..] compressed)
-[UPLOADING] foo v0.1.0 [..]
-[ERROR] failed to read `readme` file for package `foo v0.1.0 ([ROOT]/foo)`
-
-Caused by:
- failed to read `[ROOT]/foo/foo.md`
-
-Caused by:
- {}
-",
- no_such_file_err_msg()
- ))
- .run();
-}
-
// Registry returns an API error.
#[cargo_test]
fn api_error_json() {
diff --git a/tests/testsuite/registry.rs b/tests/testsuite/registry.rs
index 24c253c55040..0475e8f6d7f1 100644
--- a/tests/testsuite/registry.rs
+++ b/tests/testsuite/registry.rs
@@ -1146,7 +1146,7 @@ fn bad_license_file(registry: &TestRegistry) {
p.cargo("publish -v")
.replace_crates_io(registry.index_url())
.with_status(101)
- .with_stderr_contains("[ERROR] the license file `foo` does not exist")
+ .with_stderr_contains("[ERROR] license-file `foo` does not appear to exist ([..]).")
.run();
}
From 5d8022c9e82490347a732834809106bdf8777616 Mon Sep 17 00:00:00 2001
From: heisen-li
Date: Wed, 5 Jun 2024 15:36:06 +0800
Subject: [PATCH 06/53] Use clap's conflict support and keep some command tests
---
src/bin/cargo/commands/install.rs | 11 +++--
src/cargo/util/command_prelude.rs | 21 +++------
tests/testsuite/check.rs | 18 +++++---
tests/testsuite/profile_custom.rs | 75 ++++++-------------------------
4 files changed, 40 insertions(+), 85 deletions(-)
diff --git a/src/bin/cargo/commands/install.rs b/src/bin/cargo/commands/install.rs
index 79e39c163f79..8aaaeb87b0e4 100644
--- a/src/bin/cargo/commands/install.rs
+++ b/src/bin/cargo/commands/install.rs
@@ -85,10 +85,13 @@ pub fn cli() -> Command {
)
.arg_features()
.arg_parallel()
- .arg(flag(
- "debug",
- "Build in debug mode (with the 'dev' profile) instead of release mode",
- ))
+ .arg(
+ flag(
+ "debug",
+ "Build in debug mode (with the 'dev' profile) instead of release mode",
+ )
+ .conflicts_with("profile"),
+ )
.arg_redundant_default_mode("release", "install", "debug")
.arg_profile("Install artifacts with the specified profile")
.arg_target_triple("Build for the target triple")
diff --git a/src/cargo/util/command_prelude.rs b/src/cargo/util/command_prelude.rs
index 11164b8409c4..f40dc85ac671 100644
--- a/src/cargo/util/command_prelude.rs
+++ b/src/cargo/util/command_prelude.rs
@@ -131,7 +131,12 @@ pub trait CommandExt: Sized {
) -> Self {
let msg = format!("`--{default_mode}` is the default for `cargo {command}`; instead `--{supported_mode}` is supported");
let value_parser = UnknownArgumentValueParser::suggest(msg);
- self._arg(flag(default_mode, "").value_parser(value_parser).hide(true))
+ self._arg(
+ flag(default_mode, "")
+ .conflicts_with("profile")
+ .value_parser(value_parser)
+ .hide(true),
+ )
}
fn arg_targets_all(
@@ -226,6 +231,7 @@ pub trait CommandExt: Sized {
self._arg(
flag("release", release)
.short('r')
+ .conflicts_with("profile")
.help_heading(heading::COMPILATION_OPTIONS),
)
}
@@ -563,14 +569,6 @@ Run `{cmd}` to see possible targets."
) -> CargoResult {
let specified_profile = self._value_of("profile");
- let err_message = |flag: &str| {
- format!(
- "\
-the `--{flag}` flag can not be specified with the `--profile` flag
-Please remove one of the flags."
- )
- };
-
// Check for allowed legacy names.
// This is an early exit, since it allows combination with `--release`.
match (specified_profile, profile_checking) {
@@ -578,9 +576,6 @@ Please remove one of the flags."
(Some(name @ ("dev" | "test" | "bench" | "check")), ProfileChecking::LegacyRustc)
// `cargo fix` and `cargo check` has legacy handling of this profile name
| (Some(name @ "test"), ProfileChecking::LegacyTestOnly) => {
- if self.maybe_flag("release") {
- bail!(err_message("release"));
- }
return Ok(InternedString::new(name));
}
_ => {}
@@ -593,9 +588,7 @@ Please remove one of the flags."
) {
(false, false, None) => default,
(true, _, None) => "release",
- (true, _, Some(_)) => bail!(err_message("release")),
(_, true, None) => "dev",
- (_, true, Some(_)) => bail!(err_message("debug")),
// `doc` is separate from all the other reservations because
// [profile.doc] was historically allowed, but is deprecated and
// has no effect. To avoid potentially breaking projects, it is a
diff --git a/tests/testsuite/check.rs b/tests/testsuite/check.rs
index ab135c7cb21f..54e11f5d74e9 100644
--- a/tests/testsuite/check.rs
+++ b/tests/testsuite/check.rs
@@ -289,20 +289,26 @@ fn rustc_check() {
// Verify compatible usage of --profile with --release, issue #7488
foo.cargo("rustc --profile check --release -- --emit=metadata")
- .with_status(101)
+ .with_status(1)
.with_stderr(
"\
-error: the `--release` flag can not be specified with the `--profile` flag
-Please remove one of the flags.",
+[ERROR] the argument '--profile ' cannot be used with '--release'
+
+Usage: cargo[EXE] rustc --profile [ARGS]...
+
+For more information, try '--help'.",
)
.run();
foo.cargo("rustc --profile test --release -- --emit=metadata")
- .with_status(101)
+ .with_status(1)
.with_stderr(
"\
-error: the `--release` flag can not be specified with the `--profile` flag
-Please remove one of the flags.",
+[ERROR] the argument '--profile ' cannot be used with '--release'
+
+Usage: cargo[EXE] rustc --profile [ARGS]...
+
+For more information, try '--help'.",
)
.run();
}
diff --git a/tests/testsuite/profile_custom.rs b/tests/testsuite/profile_custom.rs
index 22481fabdeb5..d879507d0ca8 100644
--- a/tests/testsuite/profile_custom.rs
+++ b/tests/testsuite/profile_custom.rs
@@ -380,85 +380,38 @@ fn conflicting_usage() {
.build();
p.cargo("build --profile=dev --release")
- .with_status(101)
+ .with_status(1)
.with_stderr(
"\
-error: the `--release` flag can not be specified with the `--profile` flag
-Please remove one of the flags.",
- )
- .run();
+[ERROR] the argument '--profile ' cannot be used with '--release'
- p.cargo("install --profile=release --debug")
- .with_status(101)
- .with_stderr(
- "\
-error: the `--debug` flag can not be specified with the `--profile` flag
-Please remove one of the flags.",
- )
- .run();
+Usage: cargo[EXE] build --profile
- p.cargo("rustc --profile=dev --release")
- .with_status(101)
- .with_stderr(
- "\
-error: the `--release` flag can not be specified with the `--profile` flag
-Please remove one of the flags.
-",
+For more information, try '--help'.",
)
.run();
- p.cargo("check --profile=dev --release")
- .with_status(101)
+ p.cargo("install --profile=release --debug")
+ .with_status(1)
.with_stderr(
"\
-error: the `--release` flag can not be specified with the `--profile` flag
-Please remove one of the flags.",
- )
- .run();
+[ERROR] the argument '--profile ' cannot be used with '--debug'
- p.cargo("check --profile=test --release")
- .with_status(101)
- .with_stderr(
- "\
-error: the `--release` flag can not be specified with the `--profile` flag
-Please remove one of the flags.",
- )
- .run();
+Usage: cargo[EXE] install --profile [CRATE[@]]...
- // This is OK since the two are the same.
- p.cargo("rustc --profile=release --release")
- .with_status(101)
- .with_stderr(
- "\
-error: the `--release` flag can not be specified with the `--profile` flag
-Please remove one of the flags.",
+For more information, try '--help'.",
)
.run();
- p.cargo("build --profile=release --release")
- .with_status(101)
+ p.cargo("check --profile=dev --release")
+ .with_status(1)
.with_stderr(
"\
-error: the `--release` flag can not be specified with the `--profile` flag
-Please remove one of the flags.",
- )
- .run();
+[ERROR] the argument '--profile ' cannot be used with '--release'
- p.cargo("install --path . --profile=dev --debug")
- .with_status(101)
- .with_stderr(
- "\
-error: the `--debug` flag can not be specified with the `--profile` flag
-Please remove one of the flags.",
- )
- .run();
+Usage: cargo[EXE] check --profile
- p.cargo("install --path . --profile=release --debug")
- .with_status(101)
- .with_stderr(
- "\
-error: the `--debug` flag can not be specified with the `--profile` flag
-Please remove one of the flags.",
+For more information, try '--help'.",
)
.run();
}
From b95fb6e2bfc425f9d7d8e505446f3f80d7fdb0b2 Mon Sep 17 00:00:00 2001
From: Tor Hovland <55164+torhovland@users.noreply.github.com>
Date: Fri, 31 May 2024 09:28:31 +0200
Subject: [PATCH 07/53] refactor: cargo_generate_lockfile -> cargo_update.
---
.../{cargo_generate_lockfile.rs => cargo_update.rs} | 0
src/cargo/ops/mod.rs | 10 +++++-----
triagebot.toml | 4 ++--
3 files changed, 7 insertions(+), 7 deletions(-)
rename src/cargo/ops/{cargo_generate_lockfile.rs => cargo_update.rs} (100%)
diff --git a/src/cargo/ops/cargo_generate_lockfile.rs b/src/cargo/ops/cargo_update.rs
similarity index 100%
rename from src/cargo/ops/cargo_generate_lockfile.rs
rename to src/cargo/ops/cargo_update.rs
diff --git a/src/cargo/ops/mod.rs b/src/cargo/ops/mod.rs
index 3b4c74c89224..88b422e5b301 100644
--- a/src/cargo/ops/mod.rs
+++ b/src/cargo/ops/mod.rs
@@ -7,10 +7,6 @@ pub use self::cargo_compile::{
pub use self::cargo_compile::{CompileFilter, FilterRule, LibRule, Packages};
pub use self::cargo_doc::{doc, DocOptions, OutputFormat};
pub use self::cargo_fetch::{fetch, FetchOptions};
-pub use self::cargo_generate_lockfile::generate_lockfile;
-pub use self::cargo_generate_lockfile::print_lockfile_changes;
-pub use self::cargo_generate_lockfile::update_lockfile;
-pub use self::cargo_generate_lockfile::UpdateOptions;
pub use self::cargo_install::{install, install_list};
pub use self::cargo_new::{init, new, NewOptions, NewProjectKind, VersionControl};
pub use self::cargo_output_metadata::{output_metadata, ExportInfo, OutputMetadataOptions};
@@ -20,6 +16,10 @@ pub use self::cargo_read_manifest::{read_package, read_packages};
pub use self::cargo_run::run;
pub use self::cargo_test::{run_benches, run_tests, TestOptions};
pub use self::cargo_uninstall::uninstall;
+pub use self::cargo_update::generate_lockfile;
+pub use self::cargo_update::print_lockfile_changes;
+pub use self::cargo_update::update_lockfile;
+pub use self::cargo_update::UpdateOptions;
pub use self::fix::{fix, fix_exec_rustc, fix_get_proxy_lock_addr, FixOptions};
pub use self::lockfile::{load_pkg_lockfile, resolve_to_string, write_pkg_lockfile};
pub use self::registry::modify_owners;
@@ -44,7 +44,6 @@ pub(crate) mod cargo_compile;
pub mod cargo_config;
mod cargo_doc;
mod cargo_fetch;
-mod cargo_generate_lockfile;
mod cargo_install;
mod cargo_new;
mod cargo_output_metadata;
@@ -55,6 +54,7 @@ pub mod cargo_remove;
mod cargo_run;
mod cargo_test;
mod cargo_uninstall;
+mod cargo_update;
mod common_for_install_and_uninstall;
mod fix;
pub(crate) mod lockfile;
diff --git a/triagebot.toml b/triagebot.toml
index b659dee749de..609d76830812 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -265,7 +265,7 @@ trigger_files = [
]
[autolabel."Command-generate-lockfile"]
-trigger_files = ["src/bin/cargo/commands/generate_lockfile.rs", "src/cargo/ops/cargo_generate_lockfile.rs"]
+trigger_files = ["src/bin/cargo/commands/generate_lockfile.rs"]
[autolabel."Command-git-checkout"]
trigger_files = ["src/bin/cargo/commands/git_checkout.rs"]
@@ -334,7 +334,7 @@ trigger_files = ["src/bin/cargo/commands/tree.rs", "src/cargo/ops/tree/"]
trigger_files = ["src/bin/cargo/commands/uninstall.rs", "src/cargo/ops/cargo_uninstall.rs"]
[autolabel."Command-update"]
-trigger_files = ["src/bin/cargo/commands/update.rs"]
+trigger_files = ["src/bin/cargo/commands/update.rs", "src/cargo/ops/cargo_update.rs"]
[autolabel."Command-vendor"]
trigger_files = ["src/bin/cargo/commands/vendor.rs", "src/cargo/ops/vendor.rs"]
From b902398b020054c87529ca4222a0a88b62d5efd4 Mon Sep 17 00:00:00 2001
From: Tor Hovland <55164+torhovland@users.noreply.github.com>
Date: Wed, 5 Jun 2024 17:58:08 +0200
Subject: [PATCH 08/53] Add a dry_run argument to resolve_ws().
---
benches/benchsuite/benches/resolve.rs | 4 ++++
src/bin/cargo/commands/add.rs | 8 +++-----
src/bin/cargo/commands/remove.rs | 4 ++--
src/cargo/core/compiler/standard_lib.rs | 2 ++
src/cargo/ops/cargo_clean.rs | 12 ++++++++++--
src/cargo/ops/cargo_compile/mod.rs | 2 ++
src/cargo/ops/cargo_fetch.rs | 3 ++-
src/cargo/ops/cargo_install.rs | 3 ++-
src/cargo/ops/cargo_output_metadata.rs | 2 ++
src/cargo/ops/cargo_package.rs | 3 ++-
src/cargo/ops/fix.rs | 2 ++
src/cargo/ops/resolve.rs | 14 ++++++++++----
src/cargo/ops/tree/mod.rs | 2 ++
src/cargo/ops/vendor.rs | 5 +++--
14 files changed, 48 insertions(+), 18 deletions(-)
diff --git a/benches/benchsuite/benches/resolve.rs b/benches/benchsuite/benches/resolve.rs
index 89d0212e378c..d798dd6d62bb 100644
--- a/benches/benchsuite/benches/resolve.rs
+++ b/benches/benchsuite/benches/resolve.rs
@@ -33,6 +33,7 @@ fn do_resolve<'gctx>(gctx: &'gctx GlobalContext, ws_root: &Path) -> ResolveInfo<
let force_all_targets = ForceAllTargets::No;
// Do an initial run to download anything necessary so that it does
// not confuse criterion's warmup.
+ let dry_run = false;
let ws_resolve = cargo::ops::resolve_ws_with_opts(
&ws,
&mut target_data,
@@ -41,6 +42,7 @@ fn do_resolve<'gctx>(gctx: &'gctx GlobalContext, ws_root: &Path) -> ResolveInfo<
&specs,
has_dev_units,
force_all_targets,
+ dry_run,
)
.unwrap();
ResolveInfo {
@@ -71,6 +73,7 @@ fn resolve_ws(c: &mut Criterion) {
// iterator once, and we don't want to call `do_resolve` in every
// "step", since that would just be some useless work.
let mut lazy_info = None;
+ let dry_run = false;
group.bench_function(&ws_name, |b| {
let ResolveInfo {
ws,
@@ -91,6 +94,7 @@ fn resolve_ws(c: &mut Criterion) {
specs,
*has_dev_units,
*force_all_targets,
+ dry_run,
)
.unwrap();
})
diff --git a/src/bin/cargo/commands/add.rs b/src/bin/cargo/commands/add.rs
index 9c67eb8343cb..30956b00479f 100644
--- a/src/bin/cargo/commands/add.rs
+++ b/src/bin/cargo/commands/add.rs
@@ -214,11 +214,9 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
};
add(&ws, &options)?;
- if !dry_run {
- // Reload the workspace since we've changed dependencies
- let ws = args.workspace(gctx)?;
- resolve_ws(&ws)?;
- }
+ // Reload the workspace since we've changed dependencies
+ let ws = args.workspace(gctx)?;
+ resolve_ws(&ws, dry_run)?;
Ok(())
}
diff --git a/src/bin/cargo/commands/remove.rs b/src/bin/cargo/commands/remove.rs
index 25179487c934..b5695e59937f 100644
--- a/src/bin/cargo/commands/remove.rs
+++ b/src/bin/cargo/commands/remove.rs
@@ -121,7 +121,7 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
ws.gctx()
.shell()
.set_verbosity(cargo::core::Verbosity::Quiet);
- let resolve = resolve_ws(&ws);
+ let resolve = resolve_ws(&ws, dry_run);
ws.gctx().shell().set_verbosity(verbosity);
resolve?.1
};
@@ -129,7 +129,7 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
// Attempt to gc unused patches and re-resolve if anything is removed
if gc_unused_patches(&workspace, &resolve)? {
let ws = args.workspace(gctx)?;
- resolve_ws(&ws)?;
+ resolve_ws(&ws, dry_run)?;
}
}
Ok(())
diff --git a/src/cargo/core/compiler/standard_lib.rs b/src/cargo/core/compiler/standard_lib.rs
index 684e4426c04a..3e387bdddccf 100644
--- a/src/cargo/core/compiler/standard_lib.rs
+++ b/src/cargo/core/compiler/standard_lib.rs
@@ -149,6 +149,7 @@ pub fn resolve_std<'gctx>(
let cli_features = CliFeatures::from_command_line(
&features, /*all_features*/ false, /*uses_default_features*/ false,
)?;
+ let dry_run = false;
let resolve = ops::resolve_ws_with_opts(
&std_ws,
target_data,
@@ -157,6 +158,7 @@ pub fn resolve_std<'gctx>(
&specs,
HasDevUnits::No,
crate::core::resolver::features::ForceAllTargets::No,
+ dry_run,
)?;
Ok((
resolve.pkg_set,
diff --git a/src/cargo/ops/cargo_clean.rs b/src/cargo/ops/cargo_clean.rs
index 5969bf287eb9..5297430b175a 100644
--- a/src/cargo/ops/cargo_clean.rs
+++ b/src/cargo/ops/cargo_clean.rs
@@ -77,7 +77,14 @@ pub fn clean(ws: &Workspace<'_>, opts: &CleanOptions<'_>) -> CargoResult<()> {
if opts.spec.is_empty() {
clean_ctx.remove_paths(&[target_dir.into_path_unlocked()])?;
} else {
- clean_specs(&mut clean_ctx, &ws, &profiles, &opts.targets, &opts.spec)?;
+ clean_specs(
+ &mut clean_ctx,
+ &ws,
+ &profiles,
+ &opts.targets,
+ &opts.spec,
+ opts.dry_run,
+ )?;
}
}
@@ -91,11 +98,12 @@ fn clean_specs(
profiles: &Profiles,
targets: &[String],
spec: &[String],
+ dry_run: bool,
) -> CargoResult<()> {
// Clean specific packages.
let requested_kinds = CompileKind::from_requested_targets(clean_ctx.gctx, targets)?;
let target_data = RustcTargetData::new(ws, &requested_kinds)?;
- let (pkg_set, resolve) = ops::resolve_ws(ws)?;
+ let (pkg_set, resolve) = ops::resolve_ws(ws, dry_run)?;
let prof_dir_name = profiles.get_dir_name();
let host_layout = Layout::new(ws, None, &prof_dir_name)?;
// Convert requested kinds to a Vec of layouts.
diff --git a/src/cargo/ops/cargo_compile/mod.rs b/src/cargo/ops/cargo_compile/mod.rs
index 68f1df76ba6f..0553e5e2d5de 100644
--- a/src/cargo/ops/cargo_compile/mod.rs
+++ b/src/cargo/ops/cargo_compile/mod.rs
@@ -264,6 +264,7 @@ pub fn create_bcx<'a, 'gctx>(
HasDevUnits::No
}
};
+ let dry_run = false;
let resolve = ops::resolve_ws_with_opts(
ws,
&mut target_data,
@@ -272,6 +273,7 @@ pub fn create_bcx<'a, 'gctx>(
&specs,
has_dev_units,
crate::core::resolver::features::ForceAllTargets::No,
+ dry_run,
)?;
let WorkspaceResolve {
mut pkg_set,
diff --git a/src/cargo/ops/cargo_fetch.rs b/src/cargo/ops/cargo_fetch.rs
index 761f171f1f69..37b56438cd60 100644
--- a/src/cargo/ops/cargo_fetch.rs
+++ b/src/cargo/ops/cargo_fetch.rs
@@ -19,7 +19,8 @@ pub fn fetch<'a>(
options: &FetchOptions<'a>,
) -> CargoResult<(Resolve, PackageSet<'a>)> {
ws.emit_warnings()?;
- let (mut packages, resolve) = ops::resolve_ws(ws)?;
+ let dry_run = false;
+ let (mut packages, resolve) = ops::resolve_ws(ws, dry_run)?;
let jobs = Some(JobsConfig::Integer(1));
let keep_going = false;
diff --git a/src/cargo/ops/cargo_install.rs b/src/cargo/ops/cargo_install.rs
index a662e891f387..e4304d74829c 100644
--- a/src/cargo/ops/cargo_install.rs
+++ b/src/cargo/ops/cargo_install.rs
@@ -561,7 +561,8 @@ impl<'gctx> InstallablePackage<'gctx> {
// It would be best if `source` could be passed in here to avoid a
// duplicate "Updating", but since `source` is taken by value, then it
// wouldn't be available for `compile_ws`.
- let (pkg_set, resolve) = ops::resolve_ws(&self.ws)?;
+ let dry_run = false;
+ let (pkg_set, resolve) = ops::resolve_ws(&self.ws, dry_run)?;
ops::check_yanked(
self.ws.gctx(),
&pkg_set,
diff --git a/src/cargo/ops/cargo_output_metadata.rs b/src/cargo/ops/cargo_output_metadata.rs
index 408be75faf38..1aadc05d77a3 100644
--- a/src/cargo/ops/cargo_output_metadata.rs
+++ b/src/cargo/ops/cargo_output_metadata.rs
@@ -142,6 +142,7 @@ fn build_resolve_graph(
// Note that even with --filter-platform we end up downloading host dependencies as well,
// as that is the behavior of download_accessible.
+ let dry_run = false;
let ws_resolve = ops::resolve_ws_with_opts(
ws,
&mut target_data,
@@ -150,6 +151,7 @@ fn build_resolve_graph(
&specs,
HasDevUnits::Yes,
force_all,
+ dry_run,
)?;
let package_map: BTreeMap = ws_resolve
diff --git a/src/cargo/ops/cargo_package.rs b/src/cargo/ops/cargo_package.rs
index 533852551c20..e105d7012d4c 100644
--- a/src/cargo/ops/cargo_package.rs
+++ b/src/cargo/ops/cargo_package.rs
@@ -190,7 +190,8 @@ pub fn package(ws: &Workspace<'_>, opts: &PackageOpts<'_>) -> CargoResult
This option is unstable and available only on the
nightly channel
diff --git a/src/doc/src/reference/unstable.md b/src/doc/src/reference/unstable.md
index fce26e146c54..5e871aca5ae5 100644
--- a/src/doc/src/reference/unstable.md
+++ b/src/doc/src/reference/unstable.md
@@ -28,9 +28,9 @@ how the feature works:
* 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:
+ `--artifact-dir` option is only available on nightly:
- ```cargo +nightly build --out-dir=out -Z unstable-options```
+ ```cargo +nightly build --artifact-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
@@ -74,7 +74,7 @@ For the latest nightly, see the [nightly version] of this page.
* [msrv-policy](#msrv-policy) --- MSRV-aware resolver and version selection
* [precise-pre-release](#precise-pre-release) --- Allows pre-release versions to be selected with `update --precise`
* Output behavior
- * [out-dir](#out-dir) --- Adds a directory where artifacts are copied to.
+ * [artifact-dir](#artifact-dir) --- Adds a directory where artifacts are copied to.
* [Different binary name](#different-binary-name) --- Assign a name to the built binary that is separate from the crate name.
* Compile behavior
* [mtime-on-use](#mtime-on-use) --- Updates the last-modified timestamp on every dependency every time it is used, to provide a mechanism to delete unused artifacts.
@@ -206,27 +206,27 @@ minimum versions that you are actually using. That is, if Cargo.toml says
Indirect dependencies are resolved as normal so as not to be blocked on their
minimal version validation.
-## out-dir
+## artifact-dir
* Original Issue: [#4875](https://github.com/rust-lang/cargo/issues/4875)
* Tracking Issue: [#6790](https://github.com/rust-lang/cargo/issues/6790)
-This feature allows you to specify the directory where artifacts will be
-copied to after they are built. Typically artifacts are only written to the
-`target/release` or `target/debug` directories. However, determining the
-exact filename can be tricky since you need to parse JSON output. The
-`--out-dir` flag makes it easier to predictably access the artifacts. Note
-that the artifacts are copied, so the originals are still in the `target`
-directory. Example:
+This feature allows you to specify the directory where artifacts will be copied
+to after they are built. Typically artifacts are only written to the
+`target/release` or `target/debug` directories. However, determining the exact
+filename can be tricky since you need to parse JSON output. The `--artifact-dir`
+flag makes it easier to predictably access the artifacts. Note that the
+artifacts are copied, so the originals are still in the `target` directory.
+Example:
```sh
-cargo +nightly build --out-dir=out -Z unstable-options
+cargo +nightly build --artifact-dir=out -Z unstable-options
```
This can also be specified in `.cargo/config.toml` files.
```toml
[build]
-out-dir = "out"
+artifact-dir = "out"
```
## doctest-xcompile
diff --git a/src/etc/man/cargo-build.1 b/src/etc/man/cargo-build.1
index 9b7a08e4ed1e..23e49a15e16a 100644
--- a/src/etc/man/cargo-build.1
+++ b/src/etc/man/cargo-build.1
@@ -222,7 +222,7 @@ specified with the \fBCARGO_TARGET_DIR\fR environment variable, or the
Defaults to \fBtarget\fR in the root of the workspace.
.RE
.sp
-\fB\-\-out\-dir\fR \fIdirectory\fR
+\fB\-\-artifact\-dir\fR \fIdirectory\fR
.RS 4
Copy final artifacts to this directory.
.sp
diff --git a/tests/testsuite/out_dir.rs b/tests/testsuite/artifact_dir.rs
similarity index 83%
rename from tests/testsuite/out_dir.rs
rename to tests/testsuite/artifact_dir.rs
index 1b3d4a64ad10..47ef7bfc34ed 100644
--- a/tests/testsuite/out_dir.rs
+++ b/tests/testsuite/artifact_dir.rs
@@ -1,4 +1,4 @@
-//! Tests for --out-dir flag.
+//! Tests for --artifact-dir flag.
use cargo_test_support::sleep_ms;
use cargo_test_support::{basic_manifest, project};
@@ -12,8 +12,8 @@ fn binary_with_debug() {
.file("src/main.rs", r#"fn main() { println!("Hello, World!") }"#)
.build();
- p.cargo("build -Z unstable-options --out-dir out")
- .masquerade_as_nightly_cargo(&["out-dir"])
+ p.cargo("build -Z unstable-options --artifact-dir out")
+ .masquerade_as_nightly_cargo(&["artifact-dir"])
.enable_mac_dsym()
.run();
check_dir_contents(
@@ -49,8 +49,8 @@ fn static_library_with_debug() {
)
.build();
- p.cargo("build -Z unstable-options --out-dir out")
- .masquerade_as_nightly_cargo(&["out-dir"])
+ p.cargo("build -Z unstable-options --artifact-dir out")
+ .masquerade_as_nightly_cargo(&["artifact-dir"])
.run();
check_dir_contents(
&p.root().join("out"),
@@ -85,8 +85,8 @@ fn dynamic_library_with_debug() {
)
.build();
- p.cargo("build -Z unstable-options --out-dir out")
- .masquerade_as_nightly_cargo(&["out-dir"])
+ p.cargo("build -Z unstable-options --artifact-dir out")
+ .masquerade_as_nightly_cargo(&["artifact-dir"])
.enable_mac_dsym()
.run();
check_dir_contents(
@@ -121,8 +121,8 @@ fn rlib_with_debug() {
)
.build();
- p.cargo("build -Z unstable-options --out-dir out")
- .masquerade_as_nightly_cargo(&["out-dir"])
+ p.cargo("build -Z unstable-options --artifact-dir out")
+ .masquerade_as_nightly_cargo(&["artifact-dir"])
.run();
check_dir_contents(
&p.root().join("out"),
@@ -165,8 +165,8 @@ fn include_only_the_binary_from_the_current_package() {
.file("utils/src/lib.rs", "")
.build();
- p.cargo("build -Z unstable-options --bin foo --out-dir out")
- .masquerade_as_nightly_cargo(&["out-dir"])
+ p.cargo("build -Z unstable-options --bin foo --artifact-dir out")
+ .masquerade_as_nightly_cargo(&["artifact-dir"])
.enable_mac_dsym()
.run();
check_dir_contents(
@@ -179,14 +179,14 @@ fn include_only_the_binary_from_the_current_package() {
}
#[cargo_test]
-fn out_dir_is_a_file() {
+fn artifact_dir_is_a_file() {
let p = project()
.file("src/main.rs", r#"fn main() { println!("Hello, World!") }"#)
.file("out", "")
.build();
- p.cargo("build -Z unstable-options --out-dir out")
- .masquerade_as_nightly_cargo(&["out-dir"])
+ p.cargo("build -Z unstable-options --artifact-dir out")
+ .masquerade_as_nightly_cargo(&["artifact-dir"])
.with_status(101)
.with_stderr_contains("[ERROR] failed to create directory [..]")
.run();
@@ -198,8 +198,8 @@ fn replaces_artifacts() {
.file("src/main.rs", r#"fn main() { println!("foo") }"#)
.build();
- p.cargo("build -Z unstable-options --out-dir out")
- .masquerade_as_nightly_cargo(&["out-dir"])
+ p.cargo("build -Z unstable-options --artifact-dir out")
+ .masquerade_as_nightly_cargo(&["artifact-dir"])
.run();
p.process(
&p.root()
@@ -211,8 +211,8 @@ fn replaces_artifacts() {
sleep_ms(1000);
p.change_file("src/main.rs", r#"fn main() { println!("bar") }"#);
- p.cargo("build -Z unstable-options --out-dir out")
- .masquerade_as_nightly_cargo(&["out-dir"])
+ p.cargo("build -Z unstable-options --artifact-dir out")
+ .masquerade_as_nightly_cargo(&["artifact-dir"])
.run();
p.process(
&p.root()
@@ -240,8 +240,8 @@ fn avoid_build_scripts() {
.file("b/build.rs", r#"fn main() { println!("hello-build-b"); }"#)
.build();
- p.cargo("build -Z unstable-options --out-dir out -vv")
- .masquerade_as_nightly_cargo(&["out-dir"])
+ p.cargo("build -Z unstable-options --artifact-dir out -vv")
+ .masquerade_as_nightly_cargo(&["artifact-dir"])
.enable_mac_dsym()
.with_stdout_contains("[a 0.0.1] hello-build-a")
.with_stdout_contains("[b 0.0.1] hello-build-b")
@@ -256,20 +256,20 @@ fn avoid_build_scripts() {
}
#[cargo_test]
-fn cargo_build_out_dir() {
+fn cargo_build_artifact_dir() {
let p = project()
.file("src/main.rs", r#"fn main() { println!("Hello, World!") }"#)
.file(
".cargo/config.toml",
r#"
[build]
- out-dir = "out"
+ artifact-dir = "out"
"#,
)
.build();
p.cargo("build -Z unstable-options")
- .masquerade_as_nightly_cargo(&["out-dir"])
+ .masquerade_as_nightly_cargo(&["artifact-dir"])
.enable_mac_dsym()
.run();
check_dir_contents(
@@ -282,18 +282,18 @@ fn cargo_build_out_dir() {
}
#[cargo_test]
-fn unsupported_short_out_dir_flag() {
+fn unsupported_short_artifact_dir_flag() {
let p = project()
.file("src/main.rs", r#"fn main() { println!("Hello, World!") }"#)
.build();
p.cargo("build -Z unstable-options -O")
- .masquerade_as_nightly_cargo(&["out-dir"])
+ .masquerade_as_nightly_cargo(&["artifact-dir"])
.with_stderr(
"\
error: unexpected argument '-O' found
- tip: a similar argument exists: '--out-dir'
+ tip: a similar argument exists: '--artifact-dir'
Usage: cargo[EXE] build [OPTIONS]
@@ -305,7 +305,7 @@ For more information, try '--help'.
}
fn check_dir_contents(
- out_dir: &Path,
+ artifact_dir: &Path,
expected_linux: &[&str],
expected_mac: &[&str],
expected_win_msvc: &[&str],
@@ -323,7 +323,7 @@ fn check_dir_contents(
expected_linux
};
- let actual = list_dir(out_dir);
+ let actual = list_dir(artifact_dir);
let mut expected = expected.iter().map(|s| s.to_string()).collect::>();
expected.sort_unstable();
assert_eq!(actual, expected);
diff --git a/tests/testsuite/cargo_build/help/stdout.term.svg b/tests/testsuite/cargo_build/help/stdout.term.svg
index 6b297f59393a..e426262f9c56 100644
--- a/tests/testsuite/cargo_build/help/stdout.term.svg
+++ b/tests/testsuite/cargo_build/help/stdout.term.svg
@@ -109,7 +109,7 @@
--target-dir<DIRECTORY> Directory for all generated artifacts
- --out-dir<PATH> Copy final artifacts to this directory (unstable)
+ --artifact-dir<PATH> Copy final artifacts to this directory (unstable)--build-plan Output the build plan in JSON (unstable)
diff --git a/tests/testsuite/collisions.rs b/tests/testsuite/collisions.rs
index b615f713e957..0f1cdf20051b 100644
--- a/tests/testsuite/collisions.rs
+++ b/tests/testsuite/collisions.rs
@@ -96,10 +96,10 @@ This may become a hard error in the future; see
Date: Fri, 7 Jun 2024 03:01:40 -0400
Subject: [PATCH 12/53] Add tests for out-dir option deprecation
Ensure that the old options still work and provide the proper
deprecation warning.
---
tests/testsuite/artifact_dir.rs | 49 +++++++++++++++++++++++++++++++++
1 file changed, 49 insertions(+)
diff --git a/tests/testsuite/artifact_dir.rs b/tests/testsuite/artifact_dir.rs
index 47ef7bfc34ed..ff83a720913a 100644
--- a/tests/testsuite/artifact_dir.rs
+++ b/tests/testsuite/artifact_dir.rs
@@ -304,6 +304,55 @@ For more information, try '--help'.
.run();
}
+#[cargo_test]
+fn deprecated_out_dir() {
+ let p = project()
+ .file("src/main.rs", r#"fn main() { println!("Hello, World!") }"#)
+ .build();
+
+ p.cargo("build -Z unstable-options --out-dir out")
+ .masquerade_as_nightly_cargo(&["out-dir"])
+ .enable_mac_dsym()
+ .with_stderr_contains("[WARNING] the --out-dir flag has been changed to --artifact-dir")
+ .run();
+ check_dir_contents(
+ &p.root().join("out"),
+ &["foo"],
+ &["foo", "foo.dSYM"],
+ &["foo.exe", "foo.pdb"],
+ &["foo.exe"],
+ );
+}
+
+#[cargo_test]
+fn cargo_build_deprecated_out_dir() {
+ let p = project()
+ .file("src/main.rs", r#"fn main() { println!("Hello, World!") }"#)
+ .file(
+ ".cargo/config.toml",
+ r#"
+ [build]
+ out-dir = "out"
+ "#,
+ )
+ .build();
+
+ p.cargo("build -Z unstable-options")
+ .masquerade_as_nightly_cargo(&["out-dir"])
+ .enable_mac_dsym()
+ .with_stderr_contains(
+ "[WARNING] the out-dir config option has been changed to artifact-dir",
+ )
+ .run();
+ check_dir_contents(
+ &p.root().join("out"),
+ &["foo"],
+ &["foo", "foo.dSYM"],
+ &["foo.exe", "foo.pdb"],
+ &["foo.exe"],
+ );
+}
+
fn check_dir_contents(
artifact_dir: &Path,
expected_linux: &[&str],
From c694ff0b44c8510878cc83137fb8a0f40531ec67 Mon Sep 17 00:00:00 2001
From: Tor Hovland <55164+torhovland@users.noreply.github.com>
Date: Fri, 31 May 2024 11:09:15 +0200
Subject: [PATCH 13/53] test: For the upcoming `cargo update --breaking`
feature.
---
tests/testsuite/update.rs | 429 +++++++++++++++++++++++++++++++++++++-
1 file changed, 427 insertions(+), 2 deletions(-)
diff --git a/tests/testsuite/update.rs b/tests/testsuite/update.rs
index 2e6d8daf6c8e..609fc59736f4 100644
--- a/tests/testsuite/update.rs
+++ b/tests/testsuite/update.rs
@@ -1,7 +1,9 @@
//! Tests for the `cargo update` command.
-use cargo_test_support::registry::Package;
-use cargo_test_support::{basic_lib_manifest, basic_manifest, git, project};
+use cargo_test_support::compare::assert_e2e;
+use cargo_test_support::registry::{self};
+use cargo_test_support::registry::{Dependency, Package};
+use cargo_test_support::{basic_lib_manifest, basic_manifest, git, project, str};
#[cargo_test]
fn minor_update_two_places() {
@@ -1637,3 +1639,426 @@ fn update_with_missing_feature() {
)
.run();
}
+
+#[cargo_test]
+fn update_breaking_unstable() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ edition = "2015"
+ authors = []
+ "#,
+ )
+ .file("src/lib.rs", "")
+ .build();
+
+ p.cargo("update --breaking")
+ .masquerade_as_nightly_cargo(&["update-breaking"])
+ .with_status(1)
+ .with_stderr_contains("[ERROR] unexpected argument '--breaking' found")
+ .run();
+}
+
+#[cargo_test]
+fn update_breaking_dry_run() {
+ Package::new("incompatible", "1.0.0").publish();
+ Package::new("ws", "1.0.0").publish();
+
+ let root_manifest = r#"
+ # Check if formatting is preserved. Nothing here should change, due to dry-run.
+
+ [workspace]
+ members = ["foo"]
+
+ [workspace.dependencies]
+ ws = "1.0" # Preserve formatting
+ "#;
+
+ let crate_manifest = r#"
+ # Check if formatting is preserved. Nothing here should change, due to dry-run.
+
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ edition = "2015"
+ authors = []
+
+ [dependencies]
+ incompatible = "1.0" # Preserve formatting
+ ws.workspace = true # Preserve formatting
+ "#;
+
+ let p = project()
+ .file("Cargo.toml", root_manifest)
+ .file("foo/Cargo.toml", crate_manifest)
+ .file("foo/src/lib.rs", "")
+ .build();
+
+ p.cargo("generate-lockfile").run();
+ let lock_file = p.read_file("Cargo.lock");
+
+ Package::new("incompatible", "1.0.1").publish();
+ Package::new("ws", "1.0.1").publish();
+
+ Package::new("incompatible", "2.0.0").publish();
+ Package::new("ws", "2.0.0").publish();
+
+ p.cargo("update --dry-run --breaking")
+ .with_status(1)
+ .with_stderr_contains("[ERROR] unexpected argument '--breaking' found")
+ .run();
+
+ let root_manifest_after = p.read_file("Cargo.toml");
+ assert_e2e().eq(&root_manifest_after, root_manifest);
+
+ let crate_manifest_after = p.read_file("foo/Cargo.toml");
+ assert_e2e().eq(&crate_manifest_after, crate_manifest);
+
+ let lock_file_after = p.read_file("Cargo.lock");
+ assert_e2e().eq(&lock_file_after, lock_file);
+}
+
+#[cargo_test]
+fn update_breaking() {
+ registry::alt_init();
+ Package::new("compatible", "1.0.0").publish();
+ Package::new("incompatible", "1.0.0").publish();
+ Package::new("pinned", "1.0.0").publish();
+ Package::new("less-than", "1.0.0").publish();
+ Package::new("renamed-from", "1.0.0").publish();
+ Package::new("pre-release", "1.0.0").publish();
+ Package::new("yanked", "1.0.0").publish();
+ Package::new("ws", "1.0.0").publish();
+ Package::new("shared", "1.0.0").publish();
+ Package::new("multiple-versions", "1.0.0").publish();
+ Package::new("multiple-versions", "2.0.0").publish();
+ Package::new("alternative-1", "1.0.0")
+ .alternative(true)
+ .publish();
+ Package::new("alternative-2", "1.0.0")
+ .alternative(true)
+ .publish();
+ Package::new("bar", "1.0.0").alternative(true).publish();
+ Package::new("multiple-registries", "1.0.0").publish();
+ Package::new("multiple-registries", "2.0.0")
+ .alternative(true)
+ .publish();
+ Package::new("multiple-source-types", "1.0.0").publish();
+
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ # Check if formatting is preserved
+
+ [workspace]
+ members = ["foo", "bar"]
+
+ [workspace.dependencies]
+ ws = "1.0" # This line gets partially rewritten
+ "#,
+ )
+ .file(
+ "foo/Cargo.toml",
+ r#"
+ # Check if formatting is preserved
+
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ edition = "2015"
+ authors = []
+
+ [dependencies]
+ compatible = "1.0" # Comment
+ incompatible = "1.0" # Comment
+ pinned = "=1.0" # Comment
+ less-than = "<99.0" # Comment
+ renamed-to = { package = "renamed-from", version = "1.0" } # Comment
+ pre-release = "1.0" # Comment
+ yanked = "1.0" # Comment
+ ws.workspace = true # Comment
+ shared = "1.0" # Comment
+ multiple-versions = "1.0" # Comment
+ alternative-1 = { registry = "alternative", version = "1.0" } # Comment
+ multiple-registries = "1.0" # Comment
+ bar = { path = "../bar", registry = "alternative", version = "1.0.0" } # Comment
+ multiple-source-types = { path = "../multiple-source-types", version = "1.0.0" } # Comment
+
+ [dependencies.alternative-2] # Comment
+ version = "1.0" # Comment
+ registry = "alternative" # Comment
+ "#,
+ )
+ .file("foo/src/lib.rs", "")
+ .file(
+ "bar/Cargo.toml",
+ r#"
+ [package]
+ name = "bar"
+ version = "1.0.0"
+ edition = "2015"
+ authors = []
+
+ [dependencies]
+ shared = "1.0"
+ multiple-versions = "2.0"
+ multiple-registries = { registry = "alternative", version = "2.0" } # Comment
+ multiple-source-types = "1.0" # Comment
+ "#,
+ )
+ .file("bar/src/lib.rs", "")
+ .file(
+ "multiple-source-types/Cargo.toml",
+ r#"
+ [package]
+ name = "multiple-source-types"
+ version = "1.0.0"
+ edition = "2015"
+ authors = []
+ "#,
+ )
+ .file("multiple-source-types/src/lib.rs", "")
+ .build();
+
+ p.cargo("generate-lockfile").run();
+
+ Package::new("compatible", "1.0.1").publish();
+ Package::new("incompatible", "1.0.1").publish();
+ Package::new("pinned", "1.0.1").publish();
+ Package::new("less-than", "1.0.1").publish();
+ Package::new("renamed-from", "1.0.1").publish();
+ Package::new("ws", "1.0.1").publish();
+ Package::new("multiple-versions", "1.0.1").publish();
+ Package::new("multiple-versions", "2.0.1").publish();
+ Package::new("alternative-1", "1.0.1")
+ .alternative(true)
+ .publish();
+ Package::new("alternative-2", "1.0.1")
+ .alternative(true)
+ .publish();
+
+ Package::new("incompatible", "2.0.0").publish();
+ Package::new("pinned", "2.0.0").publish();
+ Package::new("less-than", "2.0.0").publish();
+ Package::new("renamed-from", "2.0.0").publish();
+ Package::new("pre-release", "2.0.0-alpha").publish();
+ Package::new("yanked", "2.0.0").yanked(true).publish();
+ Package::new("ws", "2.0.0").publish();
+ Package::new("shared", "2.0.0").publish();
+ Package::new("multiple-versions", "3.0.0").publish();
+ Package::new("alternative-1", "2.0.0")
+ .alternative(true)
+ .publish();
+ Package::new("alternative-2", "2.0.0")
+ .alternative(true)
+ .publish();
+ Package::new("bar", "2.0.0").alternative(true).publish();
+ Package::new("multiple-registries", "2.0.0").publish();
+ Package::new("multiple-registries", "3.0.0")
+ .alternative(true)
+ .publish();
+ Package::new("multiple-source-types", "2.0.0").publish();
+
+ p.cargo("update --breaking")
+ .with_status(1)
+ .with_stderr_contains("[ERROR] unexpected argument '--breaking' found")
+ .run();
+
+ let root_manifest = p.read_file("Cargo.toml");
+ assert_e2e().eq(
+ &root_manifest,
+ str![[r#"
+
+ # Check if formatting is preserved
+
+ [workspace]
+ members = ["foo", "bar"]
+
+ [workspace.dependencies]
+ ws = "1.0" # This line gets partially rewritten
+ "#]],
+ );
+
+ let foo_manifest = p.read_file("foo/Cargo.toml");
+
+ assert_e2e().eq(
+ &foo_manifest,
+ str![[r#"
+
+ # Check if formatting is preserved
+
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ edition = "2015"
+ authors = []
+
+ [dependencies]
+ compatible = "1.0" # Comment
+ incompatible = "1.0" # Comment
+ pinned = "=1.0" # Comment
+ less-than = "<99.0" # Comment
+ renamed-to = { package = "renamed-from", version = "1.0" } # Comment
+ pre-release = "1.0" # Comment
+ yanked = "1.0" # Comment
+ ws.workspace = true # Comment
+ shared = "1.0" # Comment
+ multiple-versions = "1.0" # Comment
+ alternative-1 = { registry = "alternative", version = "1.0" } # Comment
+ multiple-registries = "1.0" # Comment
+ bar = { path = "../bar", registry = "alternative", version = "1.0.0" } # Comment
+ multiple-source-types = { path = "../multiple-source-types", version = "1.0.0" } # Comment
+
+ [dependencies.alternative-2] # Comment
+ version = "1.0" # Comment
+ registry = "alternative" # Comment
+ "#]],
+ );
+
+ let bar_manifest = p.read_file("bar/Cargo.toml");
+
+ assert_e2e().eq(
+ &bar_manifest,
+ str![[r#"
+
+ [package]
+ name = "bar"
+ version = "1.0.0"
+ edition = "2015"
+ authors = []
+
+ [dependencies]
+ shared = "1.0"
+ multiple-versions = "2.0"
+ multiple-registries = { registry = "alternative", version = "2.0" } # Comment
+ multiple-source-types = "1.0" # Comment
+ "#]],
+ );
+
+ p.cargo("update")
+ .with_stderr(
+ "\
+[UPDATING] `alternative` index
+[UPDATING] `dummy-registry` index
+[LOCKING] 10 packages to latest compatible versions
+[UPDATING] alternative-1 v1.0.0 (registry `alternative`) -> v1.0.1 (latest: v2.0.0)
+[UPDATING] alternative-2 v1.0.0 (registry `alternative`) -> v1.0.1 (latest: v2.0.0)
+[UPDATING] compatible v1.0.0 -> v1.0.1
+[UPDATING] incompatible v1.0.0 -> v1.0.1 (latest: v2.0.0)
+[UPDATING] less-than v1.0.0 -> v2.0.0
+[REMOVING] multiple-versions v1.0.0
+[REMOVING] multiple-versions v2.0.0
+[ADDING] multiple-versions v1.0.1 (latest: v3.0.0)
+[ADDING] multiple-versions v2.0.1 (latest: v3.0.0)
+[UPDATING] pinned v1.0.0 -> v1.0.1 (latest: v2.0.0)
+[UPDATING] renamed-from v1.0.0 -> v1.0.1 (latest: v2.0.0)
+[UPDATING] ws v1.0.0 -> v1.0.1 (latest: v2.0.0)
+[NOTE] pass `--verbose` to see 4 unchanged dependencies behind latest
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn update_breaking_specific_packages() {
+ Package::new("just-foo", "1.0.0")
+ .add_dep(Dependency::new("transitive-compatible", "1.0.0").build())
+ .add_dep(Dependency::new("transitive-incompatible", "1.0.0").build())
+ .publish();
+ Package::new("just-bar", "1.0.0").publish();
+ Package::new("shared", "1.0.0").publish();
+ Package::new("ws", "1.0.0").publish();
+ Package::new("transitive-compatible", "1.0.0").publish();
+ Package::new("transitive-incompatible", "1.0.0").publish();
+
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [workspace]
+ members = ["foo", "bar"]
+
+ [workspace.dependencies]
+ ws = "1.0"
+ "#,
+ )
+ .file(
+ "foo/Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ edition = "2015"
+ authors = []
+
+ [dependencies]
+ just-foo = "1.0"
+ shared = "1.0"
+ ws.workspace = true
+ "#,
+ )
+ .file("foo/src/lib.rs", "")
+ .file(
+ "bar/Cargo.toml",
+ r#"
+ [package]
+ name = "bar"
+ version = "0.0.1"
+ edition = "2015"
+ authors = []
+
+ [dependencies]
+ just-bar = "1.0"
+ shared = "1.0"
+ ws.workspace = true
+ "#,
+ )
+ .file("bar/src/lib.rs", "")
+ .build();
+
+ p.cargo("generate-lockfile").run();
+
+ Package::new("just-foo", "1.0.1")
+ .add_dep(Dependency::new("transitive-compatible", "1.0.0").build())
+ .add_dep(Dependency::new("transitive-incompatible", "1.0.0").build())
+ .publish();
+ Package::new("just-bar", "1.0.1").publish();
+ Package::new("shared", "1.0.1").publish();
+ Package::new("ws", "1.0.1").publish();
+ Package::new("transitive-compatible", "1.0.1").publish();
+ Package::new("transitive-incompatible", "1.0.1").publish();
+
+ Package::new("just-foo", "2.0.0")
+ // Upgrading just-foo implies accepting an update of transitive-compatible.
+ .add_dep(Dependency::new("transitive-compatible", "1.0.1").build())
+ // Upgrading just-foo implies accepting a major update of transitive-incompatible.
+ .add_dep(Dependency::new("transitive-incompatible", "2.0.0").build())
+ .publish();
+ Package::new("just-bar", "2.0.0").publish();
+ Package::new("shared", "2.0.0").publish();
+ Package::new("ws", "2.0.0").publish();
+ Package::new("transitive-incompatible", "2.0.0").publish();
+
+ p.cargo("update --breaking just-foo shared ws")
+ .with_status(1)
+ .with_stderr_contains("[ERROR] unexpected argument '--breaking' found")
+ .run();
+
+ p.cargo("update just-foo shared ws")
+ .with_stderr(
+ "\
+[UPDATING] `[..]` index
+[LOCKING] 3 packages to latest compatible versions
+[UPDATING] just-foo v1.0.0 -> v1.0.1 (latest: v2.0.0)
+[UPDATING] shared v1.0.0 -> v1.0.1 (latest: v2.0.0)
+[UPDATING] ws v1.0.0 -> v1.0.1 (latest: v2.0.0)
+[NOTE] pass `--verbose` to see 3 unchanged dependencies behind latest
+",
+ )
+ .run();
+}
From 031b410181ed3e20152bbe8b9b3b771995474111 Mon Sep 17 00:00:00 2001
From: Tor Hovland <55164+torhovland@users.noreply.github.com>
Date: Mon, 27 May 2024 12:08:32 +0200
Subject: [PATCH 14/53] feat: Implement `cargo update --breaking`.
---
crates/cargo-test-support/src/compare.rs | 1 +
src/bin/cargo/commands/update.rs | 30 +-
src/cargo/core/summary.rs | 16 +-
src/cargo/ops/cargo_update.rs | 261 +++++++++++++++++-
src/cargo/ops/mod.rs | 2 +
src/cargo/util/toml_mut/manifest.rs | 66 +++--
src/cargo/util/toml_mut/mod.rs | 1 +
src/cargo/util/toml_mut/upgrade.rs | 219 +++++++++++++++
src/doc/src/reference/unstable.md | 20 ++
.../cargo_update/help/stdout.term.svg | 44 +--
tests/testsuite/update.rs | 114 +++++---
11 files changed, 686 insertions(+), 88 deletions(-)
create mode 100644 src/cargo/util/toml_mut/upgrade.rs
diff --git a/crates/cargo-test-support/src/compare.rs b/crates/cargo-test-support/src/compare.rs
index 53b752621de8..a6a9d30e7af9 100644
--- a/crates/cargo-test-support/src/compare.rs
+++ b/crates/cargo-test-support/src/compare.rs
@@ -176,6 +176,7 @@ static E2E_LITERAL_REDACTIONS: &[(&str, &str)] = &[
("[DIRTY]", " Dirty"),
("[LOCKING]", " Locking"),
("[UPDATING]", " Updating"),
+ ("[UPGRADING]", " Upgrading"),
("[ADDING]", " Adding"),
("[REMOVING]", " Removing"),
("[REMOVED]", " Removed"),
diff --git a/src/bin/cargo/commands/update.rs b/src/bin/cargo/commands/update.rs
index fb394e4aa336..3369763d6764 100644
--- a/src/bin/cargo/commands/update.rs
+++ b/src/bin/cargo/commands/update.rs
@@ -35,6 +35,13 @@ pub fn cli() -> Command {
.value_name("PRECISE")
.requires("package-group"),
)
+ .arg(
+ flag(
+ "breaking",
+ "Upgrade [SPEC] to latest breaking versions, unless pinned (unstable)",
+ )
+ .short('b'),
+ )
.arg_silent_suggestion()
.arg(
flag("workspace", "Only update the workspace packages")
@@ -59,7 +66,8 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
gctx.cli_unstable().msrv_policy,
)?;
}
- let ws = args.workspace(gctx)?;
+
+ let mut ws = args.workspace(gctx)?;
if args.is_present_with_zero_values("package") {
print_available_packages(&ws)?;
@@ -89,6 +97,24 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
workspace: args.flag("workspace"),
gctx,
};
- ops::update_lockfile(&ws, &update_opts)?;
+
+ if args.flag("breaking") {
+ gctx.cli_unstable()
+ .fail_if_stable_opt("--breaking", 12425)?;
+
+ let upgrades = ops::upgrade_manifests(&mut ws, &update_opts.to_update)?;
+ ops::resolve_ws(&ws, update_opts.dry_run)?;
+ ops::write_manifest_upgrades(&ws, &upgrades, update_opts.dry_run)?;
+
+ if update_opts.dry_run {
+ update_opts
+ .gctx
+ .shell()
+ .warn("aborting update due to dry run")?;
+ }
+ } else {
+ ops::update_lockfile(&ws, &update_opts)?;
+ }
+
Ok(())
}
diff --git a/src/cargo/core/summary.rs b/src/cargo/core/summary.rs
index ec0197cf40d0..d7744e24ef73 100644
--- a/src/cargo/core/summary.rs
+++ b/src/cargo/core/summary.rs
@@ -103,15 +103,25 @@ impl Summary {
Rc::make_mut(&mut self.inner).checksum = Some(cksum);
}
- pub fn map_dependencies(mut self, f: F) -> Summary
+ pub fn map_dependencies(self, mut f: F) -> Summary
where
F: FnMut(Dependency) -> Dependency,
+ {
+ self.try_map_dependencies(|dep| Ok(f(dep))).unwrap()
+ }
+
+ pub fn try_map_dependencies(mut self, f: F) -> CargoResult
+ where
+ F: FnMut(Dependency) -> CargoResult,
{
{
let slot = &mut Rc::make_mut(&mut self.inner).dependencies;
- *slot = mem::take(slot).into_iter().map(f).collect();
+ *slot = mem::take(slot)
+ .into_iter()
+ .map(f)
+ .collect::>()?;
}
- self
+ Ok(self)
}
pub fn map_source(self, to_replace: SourceId, replace_with: SourceId) -> Summary {
diff --git a/src/cargo/ops/cargo_update.rs b/src/cargo/ops/cargo_update.rs
index fc22608e8f23..35902aaad55e 100644
--- a/src/cargo/ops/cargo_update.rs
+++ b/src/cargo/ops/cargo_update.rs
@@ -1,3 +1,4 @@
+use crate::core::dependency::Dependency;
use crate::core::registry::PackageRegistry;
use crate::core::resolver::features::{CliFeatures, HasDevUnits};
use crate::core::shell::Verbosity;
@@ -8,11 +9,18 @@ use crate::ops;
use crate::sources::source::QueryKind;
use crate::util::cache_lock::CacheLockMode;
use crate::util::context::GlobalContext;
-use crate::util::style;
-use crate::util::CargoResult;
+use crate::util::toml_mut::dependency::{MaybeWorkspace, Source};
+use crate::util::toml_mut::manifest::LocalManifest;
+use crate::util::toml_mut::upgrade::upgrade_requirement;
+use crate::util::{style, OptVersionReq};
+use crate::util::{CargoResult, VersionExt};
+use itertools::Itertools;
+use semver::{Op, Version, VersionReq};
use std::cmp::Ordering;
-use std::collections::{BTreeMap, HashSet};
-use tracing::debug;
+use std::collections::{BTreeMap, HashMap, HashSet};
+use tracing::{debug, trace};
+
+pub type UpgradeMap = HashMap<(String, SourceId), Version>;
pub struct UpdateOptions<'a> {
pub gctx: &'a GlobalContext,
@@ -206,6 +214,251 @@ pub fn print_lockfile_changes(
print_lockfile_generation(ws, resolve, registry)
}
}
+pub fn upgrade_manifests(
+ ws: &mut Workspace<'_>,
+ to_update: &Vec,
+) -> CargoResult {
+ let gctx = ws.gctx();
+ let mut upgrades = HashMap::new();
+ let mut upgrade_messages = HashSet::new();
+
+ // Updates often require a lot of modifications to the registry, so ensure
+ // that we're synchronized against other Cargos.
+ let _lock = gctx.acquire_package_cache_lock(CacheLockMode::DownloadExclusive)?;
+
+ let mut registry = PackageRegistry::new(gctx)?;
+ registry.lock_patches();
+
+ for member in ws.members_mut().sorted() {
+ debug!("upgrading manifest for `{}`", member.name());
+
+ *member.manifest_mut().summary_mut() = member
+ .manifest()
+ .summary()
+ .clone()
+ .try_map_dependencies(|d| {
+ upgrade_dependency(
+ &gctx,
+ to_update,
+ &mut registry,
+ &mut upgrades,
+ &mut upgrade_messages,
+ d,
+ )
+ })?;
+ }
+
+ Ok(upgrades)
+}
+
+fn upgrade_dependency(
+ gctx: &GlobalContext,
+ to_update: &Vec,
+ registry: &mut PackageRegistry<'_>,
+ upgrades: &mut UpgradeMap,
+ upgrade_messages: &mut HashSet,
+ dependency: Dependency,
+) -> CargoResult {
+ let name = dependency.package_name();
+ let renamed_to = dependency.name_in_toml();
+
+ if name != renamed_to {
+ trace!(
+ "skipping dependency renamed from `{}` to `{}`",
+ name,
+ renamed_to
+ );
+ return Ok(dependency);
+ }
+
+ if !to_update.is_empty() && !to_update.contains(&name.to_string()) {
+ trace!("skipping dependency `{}` not selected for upgrading", name);
+ return Ok(dependency);
+ }
+
+ if !dependency.source_id().is_registry() {
+ trace!("skipping non-registry dependency: {}", name);
+ return Ok(dependency);
+ }
+
+ let version_req = dependency.version_req();
+
+ let OptVersionReq::Req(current) = version_req else {
+ trace!(
+ "skipping dependency `{}` without a simple version requirement: {}",
+ name,
+ version_req
+ );
+ return Ok(dependency);
+ };
+
+ let [comparator] = ¤t.comparators[..] else {
+ trace!(
+ "skipping dependency `{}` with multiple version comparators: {:?}",
+ name,
+ ¤t.comparators
+ );
+ return Ok(dependency);
+ };
+
+ if comparator.op != Op::Caret {
+ trace!("skipping non-caret dependency `{}`: {}", name, comparator);
+ return Ok(dependency);
+ }
+
+ let query =
+ crate::core::dependency::Dependency::parse(name, None, dependency.source_id().clone())?;
+
+ let possibilities = {
+ loop {
+ match registry.query_vec(&query, QueryKind::Exact) {
+ std::task::Poll::Ready(res) => {
+ break res?;
+ }
+ std::task::Poll::Pending => registry.block_until_ready()?,
+ }
+ }
+ };
+
+ let latest = if !possibilities.is_empty() {
+ possibilities
+ .iter()
+ .map(|s| s.as_summary())
+ .map(|s| s.version())
+ .filter(|v| !v.is_prerelease())
+ .max()
+ } else {
+ None
+ };
+
+ let Some(latest) = latest else {
+ trace!(
+ "skipping dependency `{}` without any published versions",
+ name
+ );
+ return Ok(dependency);
+ };
+
+ if current.matches(&latest) {
+ trace!(
+ "skipping dependency `{}` without a breaking update available",
+ name
+ );
+ return Ok(dependency);
+ }
+
+ let Some(new_req_string) = upgrade_requirement(¤t.to_string(), latest)? else {
+ trace!(
+ "skipping dependency `{}` because the version requirement didn't change",
+ name
+ );
+ return Ok(dependency);
+ };
+
+ let upgrade_message = format!("{} {} -> {}", name, current, new_req_string);
+ trace!(upgrade_message);
+
+ if upgrade_messages.insert(upgrade_message.clone()) {
+ gctx.shell()
+ .status_with_color("Upgrading", &upgrade_message, &style::GOOD)?;
+ }
+
+ upgrades.insert((name.to_string(), dependency.source_id()), latest.clone());
+
+ let req = OptVersionReq::Req(VersionReq::parse(&latest.to_string())?);
+ let mut dep = dependency.clone();
+ dep.set_version_req(req);
+ Ok(dep)
+}
+
+/// Update manifests with upgraded versions, and write to disk. Based on cargo-edit.
+/// Returns true if any file has changed.
+pub fn write_manifest_upgrades(
+ ws: &Workspace<'_>,
+ upgrades: &UpgradeMap,
+ dry_run: bool,
+) -> CargoResult {
+ if upgrades.is_empty() {
+ return Ok(false);
+ }
+
+ let mut any_file_has_changed = false;
+
+ let manifest_paths = std::iter::once(ws.root_manifest())
+ .chain(ws.members().map(|member| member.manifest_path()))
+ .collect::>();
+
+ for manifest_path in manifest_paths {
+ trace!(
+ "updating TOML manifest at `{:?}` with upgraded dependencies",
+ manifest_path
+ );
+
+ let crate_root = manifest_path
+ .parent()
+ .expect("manifest path is absolute")
+ .to_owned();
+
+ let mut local_manifest = LocalManifest::try_new(&manifest_path)?;
+ let mut manifest_has_changed = false;
+
+ for dep_table in local_manifest.get_dependency_tables_mut() {
+ for (mut dep_key, dep_item) in dep_table.iter_mut() {
+ let dep_key_str = dep_key.get();
+ let dependency = crate::util::toml_mut::dependency::Dependency::from_toml(
+ &manifest_path,
+ dep_key_str,
+ dep_item,
+ )?;
+
+ let Some(current) = dependency.version() else {
+ trace!("skipping dependency without a version: {}", dependency.name);
+ continue;
+ };
+
+ let (MaybeWorkspace::Other(source_id), Some(Source::Registry(source))) =
+ (dependency.source_id(ws.gctx())?, dependency.source())
+ else {
+ trace!("skipping non-registry dependency: {}", dependency.name);
+ continue;
+ };
+
+ let Some(latest) = upgrades.get(&(dependency.name.to_owned(), source_id)) else {
+ trace!(
+ "skipping dependency without an upgrade: {}",
+ dependency.name
+ );
+ continue;
+ };
+
+ let Some(new_req_string) = upgrade_requirement(current, latest)? else {
+ trace!(
+ "skipping dependency `{}` because the version requirement didn't change",
+ dependency.name
+ );
+ continue;
+ };
+
+ let mut dep = dependency.clone();
+ let mut source = source.clone();
+ source.version = new_req_string;
+ dep.source = Some(Source::Registry(source));
+
+ trace!("upgrading dependency {}", dependency.name);
+ dep.update_toml(&crate_root, &mut dep_key, dep_item);
+ manifest_has_changed = true;
+ any_file_has_changed = true;
+ }
+ }
+
+ if manifest_has_changed && !dry_run {
+ debug!("writing upgraded manifest to {}", manifest_path.display());
+ local_manifest.write()?;
+ }
+ }
+
+ Ok(any_file_has_changed)
+}
fn print_lockfile_generation(
ws: &Workspace<'_>,
diff --git a/src/cargo/ops/mod.rs b/src/cargo/ops/mod.rs
index 88b422e5b301..49dfaf53fc87 100644
--- a/src/cargo/ops/mod.rs
+++ b/src/cargo/ops/mod.rs
@@ -19,6 +19,8 @@ pub use self::cargo_uninstall::uninstall;
pub use self::cargo_update::generate_lockfile;
pub use self::cargo_update::print_lockfile_changes;
pub use self::cargo_update::update_lockfile;
+pub use self::cargo_update::upgrade_manifests;
+pub use self::cargo_update::write_manifest_upgrades;
pub use self::cargo_update::UpdateOptions;
pub use self::fix::{fix, fix_exec_rustc, fix_get_proxy_lock_addr, FixOptions};
pub use self::lockfile::{load_pkg_lockfile, resolve_to_string, write_pkg_lockfile};
diff --git a/src/cargo/util/toml_mut/manifest.rs b/src/cargo/util/toml_mut/manifest.rs
index 1fbfb9deccab..d7ed18440d29 100644
--- a/src/cargo/util/toml_mut/manifest.rs
+++ b/src/cargo/util/toml_mut/manifest.rs
@@ -276,23 +276,6 @@ impl LocalManifest {
/// Write changes back to the file.
pub fn write(&self) -> CargoResult<()> {
- if !self.manifest.data.contains_key("package")
- && !self.manifest.data.contains_key("project")
- {
- if self.manifest.data.contains_key("workspace") {
- anyhow::bail!(
- "found virtual manifest at {}, but this command requires running against an \
- actual package in this workspace.",
- self.path.display()
- );
- } else {
- anyhow::bail!(
- "missing expected `package` or `project` fields in {}",
- self.path.display()
- );
- }
- }
-
let s = self.manifest.data.to_string();
let new_contents_bytes = s.as_bytes();
@@ -397,6 +380,55 @@ impl LocalManifest {
Ok(())
}
+ /// Allow mutating depedencies, wherever they live.
+ /// Copied from cargo-edit.
+ pub fn get_dependency_tables_mut(
+ &mut self,
+ ) -> impl Iterator + '_ {
+ let root = self.data.as_table_mut();
+ root.iter_mut().flat_map(|(k, v)| {
+ if DepTable::KINDS
+ .iter()
+ .any(|dt| dt.kind.kind_table() == k.get())
+ {
+ v.as_table_like_mut().into_iter().collect::>()
+ } else if k == "workspace" {
+ v.as_table_like_mut()
+ .unwrap()
+ .iter_mut()
+ .filter_map(|(k, v)| {
+ if k.get() == "dependencies" {
+ v.as_table_like_mut()
+ } else {
+ None
+ }
+ })
+ .collect::>()
+ } else if k == "target" {
+ v.as_table_like_mut()
+ .unwrap()
+ .iter_mut()
+ .flat_map(|(_, v)| {
+ v.as_table_like_mut().into_iter().flat_map(|v| {
+ v.iter_mut().filter_map(|(k, v)| {
+ if DepTable::KINDS
+ .iter()
+ .any(|dt| dt.kind.kind_table() == k.get())
+ {
+ v.as_table_like_mut()
+ } else {
+ None
+ }
+ })
+ })
+ })
+ .collect::>()
+ } else {
+ Vec::new()
+ }
+ })
+ }
+
/// Remove references to `dep_key` if its no longer present.
pub fn gc_dep(&mut self, dep_key: &str) {
let explicit_dep_activation = self.is_explicit_dep_activation(dep_key);
diff --git a/src/cargo/util/toml_mut/mod.rs b/src/cargo/util/toml_mut/mod.rs
index cb5d3aaf2920..1da707ea192d 100644
--- a/src/cargo/util/toml_mut/mod.rs
+++ b/src/cargo/util/toml_mut/mod.rs
@@ -11,6 +11,7 @@
pub mod dependency;
pub mod manifest;
+pub mod upgrade;
// Based on Iterator::is_sorted from nightly std; remove in favor of that when stabilized.
pub fn is_sorted(mut it: impl Iterator) -> bool {
diff --git a/src/cargo/util/toml_mut/upgrade.rs b/src/cargo/util/toml_mut/upgrade.rs
new file mode 100644
index 000000000000..5bf7dacee4bd
--- /dev/null
+++ b/src/cargo/util/toml_mut/upgrade.rs
@@ -0,0 +1,219 @@
+use std::fmt::Display;
+
+use crate::CargoResult;
+
+/// Upgrade an existing requirement to a new version.
+/// Copied from cargo-edit.
+pub(crate) fn upgrade_requirement(
+ req: &str,
+ version: &semver::Version,
+) -> CargoResult