From 778ff6885ac9538a73d8c6ecf692917dc2f09759 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 24 May 2025 14:37:37 -0700 Subject: [PATCH 1/4] Factor out workspace reloading This factors out the code to reload a workspace since I will be needing to reuse this elsewhere. There is some risk with this method not getting updated correctly in the future as new fields are added to Workspace (and it may be missing some things now), but that is an issue with the existing code. --- src/bin/cargo/commands/fix.rs | 1 - src/cargo/core/workspace.rs | 12 ++++++++++++ src/cargo/ops/fix.rs | 6 +----- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/bin/cargo/commands/fix.rs b/src/bin/cargo/commands/fix.rs index 8850c8b018f..181a4edec1d 100644 --- a/src/bin/cargo/commands/fix.rs +++ b/src/bin/cargo/commands/fix.rs @@ -94,7 +94,6 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { ops::fix( gctx, &ws, - &root_manifest, &mut ops::FixOptions { edition: args.flag("edition"), idioms: args.flag("edition-idioms"), diff --git a/src/cargo/core/workspace.rs b/src/cargo/core/workspace.rs index 50b1de570e8..4f28a4efb14 100644 --- a/src/cargo/core/workspace.rs +++ b/src/cargo/core/workspace.rs @@ -301,6 +301,18 @@ impl<'gctx> Workspace<'gctx> { Ok(ws) } + /// Reloads the workspace. + /// + /// This is useful if the workspace has been updated, such as with `cargo + /// fix` modifying the `Cargo.toml` file. + pub fn reload(&self, gctx: &'gctx GlobalContext) -> CargoResult> { + let mut ws = Workspace::new(self.root_manifest(), gctx)?; + ws.set_resolve_honors_rust_version(Some(self.resolve_honors_rust_version)); + ws.set_resolve_feature_unification(self.resolve_feature_unification); + ws.set_requested_lockfile_path(self.requested_lockfile_path.clone()); + Ok(ws) + } + fn set_resolve_behavior(&mut self) -> CargoResult<()> { // - If resolver is specified in the workspace definition, use that. // - If the root package specifies the resolver, use that. diff --git a/src/cargo/ops/fix.rs b/src/cargo/ops/fix.rs index bd810defccd..62b293f19e0 100644 --- a/src/cargo/ops/fix.rs +++ b/src/cargo/ops/fix.rs @@ -103,7 +103,6 @@ pub struct FixOptions { pub fn fix( gctx: &GlobalContext, original_ws: &Workspace<'_>, - root_manifest: &Path, opts: &mut FixOptions, ) -> CargoResult<()> { check_version_control(gctx, opts)?; @@ -120,10 +119,7 @@ pub fn fix( check_resolver_change(&original_ws, &mut target_data, opts)?; } - let mut ws = Workspace::new(&root_manifest, gctx)?; - ws.set_resolve_honors_rust_version(Some(original_ws.resolve_honors_rust_version())); - ws.set_resolve_feature_unification(original_ws.resolve_feature_unification()); - ws.set_requested_lockfile_path(opts.requested_lockfile_path.clone()); + let ws = original_ws.reload(gctx)?; // Spin up our lock server, which our subprocesses will use to synchronize fixes. let lock_server = LockServer::new()?; From 9d93b42c4ce4064d2fcc4a6323a169e7d01ef794 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 24 May 2025 14:41:40 -0700 Subject: [PATCH 2/4] Add the `-Zfix-edition` flag This adds support for parsing the `-Zfix-edition` flag. --- src/cargo/core/features.rs | 46 +++++++++++++++ src/doc/src/reference/unstable.md | 14 +++++ tests/testsuite/cargo/z_help/stdout.term.svg | 62 ++++++++++---------- 3 files changed, 92 insertions(+), 30 deletions(-) diff --git a/src/cargo/core/features.rs b/src/cargo/core/features.rs index cdf5c94eb0d..320a0b7cec7 100644 --- a/src/cargo/core/features.rs +++ b/src/cargo/core/features.rs @@ -362,6 +362,45 @@ impl FromStr for Edition { } } +/// The value for `-Zfix-edition`. +#[derive(Debug, Deserialize)] +pub enum FixEdition { + /// `-Zfix-edition=start=$INITIAL` + /// + /// This mode for `cargo fix` will just run `cargo check` if the current + /// edition is equal to this edition. If it is a different edition, then + /// it just exits with success. This is used for crater integration which + /// needs to set a baseline for the "before" toolchain. + Start(Edition), + /// `-Zfix-edition=end=$INITIAL,$NEXT` + /// + /// This mode for `cargo fix` will migrate to the `next` edition if the + /// current edition is `initial`. After migration, it will update + /// `Cargo.toml` and verify that that it works on the new edition. If the + /// current edition is not `initial`, then it immediately exits with + /// success since we just want to ignore those packages. + End { initial: Edition, next: Edition }, +} + +impl FromStr for FixEdition { + type Err = anyhow::Error; + fn from_str(s: &str) -> Result::Err> { + if let Some(start) = s.strip_prefix("start=") { + Ok(FixEdition::Start(start.parse()?)) + } else if let Some(end) = s.strip_prefix("end=") { + let (initial, next) = end + .split_once(',') + .ok_or_else(|| anyhow::format_err!("expected `initial,next`"))?; + Ok(FixEdition::End { + initial: initial.parse()?, + next: next.parse()?, + }) + } else { + bail!("invalid `-Zfix-edition, expected start= or end=, got `{s}`"); + } + } +} + #[derive(Debug, PartialEq)] enum Status { Stable, @@ -791,6 +830,7 @@ unstable_cli_options!( dual_proc_macros: bool = ("Build proc-macros for both the host and the target"), feature_unification: bool = ("Enable new feature unification modes in workspaces"), features: Option>, + fix_edition: Option = ("Permanently unstable edition migration helper"), gc: bool = ("Track cache usage and \"garbage collect\" unused files"), #[serde(deserialize_with = "deserialize_git_features")] git: Option = ("Enable support for shallow git fetch operations"), @@ -1298,6 +1338,12 @@ impl CliUnstable { "doctest-xcompile" => stabilized_warn(k, "1.89", STABILIZED_DOCTEST_XCOMPILE), "dual-proc-macros" => self.dual_proc_macros = parse_empty(k, v)?, "feature-unification" => self.feature_unification = parse_empty(k, v)?, + "fix-edition" => { + let fe = v + .ok_or_else(|| anyhow::anyhow!("-Zfix-edition expected a value"))? + .parse()?; + self.fix_edition = Some(fe); + } "gc" => self.gc = parse_empty(k, v)?, "git" => { self.git = diff --git a/src/doc/src/reference/unstable.md b/src/doc/src/reference/unstable.md index f16ecf25a33..76ecb860f49 100644 --- a/src/doc/src/reference/unstable.md +++ b/src/doc/src/reference/unstable.md @@ -126,6 +126,7 @@ Each new feature described below should explain how to use it. * [native-completions](#native-completions) --- Move cargo shell completions to native completions. * [warnings](#warnings) --- controls warning behavior; options for allowing or denying warnings. * [Package message format](#package-message-format) --- Message format for `cargo package`. + * [`fix-edition`](#fix-edition) --- A permanently unstable edition migration helper. ## allow-features @@ -1915,6 +1916,19 @@ When new editions are introduced, the `unstable-editions` feature is required un The special "future" edition is a home for new features that are under development, and is permanently unstable. The "future" edition also has no new behavior by itself. Each change in the future edition requires an opt-in such as a `#![feature(...)]` attribute. +## `fix-edition` + +`-Zfix-edition` is a permanently unstable flag to assist with testing edition migrations, particularly with the use of crater. It only works with the `cargo fix` subcommand. It takes two different forms: + +- `-Zfix-edition=start=$INITIAL` --- This form checks if the current edition is equal to the given number. If not, it exits with success (because we want to ignore older editions). If it is, then it runs the equivalent of `cargo check`. This is intended to be used with crater's "start" toolchain to set a baseline for the "before" toolchain. +- `-Zfix-edition=end=$INITIAL,$NEXT` --- This form checks if the current edition is equal to the given `$INITIAL` value. If not, it exits with success. If it is, then it performs an edition migration to the edition specified in `$NEXT`. Afterwards, it will modify `Cargo.toml` to add the appropriate `cargo-features = ["unstable-edition"]`, update the `edition` field, and run the equivalent of `cargo check` to verify that the migration works on the new edition. + +For example: + +```console +cargo +nightly fix -Zfix-edition=end=2024,future +``` + # Stabilized and removed features ## Compile progress diff --git a/tests/testsuite/cargo/z_help/stdout.term.svg b/tests/testsuite/cargo/z_help/stdout.term.svg index 0468eb61bc2..b10ddce370d 100644 --- a/tests/testsuite/cargo/z_help/stdout.term.svg +++ b/tests/testsuite/cargo/z_help/stdout.term.svg @@ -1,4 +1,4 @@ - +