Skip to content

Commit 61da2b2

Browse files
committed
Add EditionFixMode
This adds the `EditionFixMode` enum to control the behavior of `cargo fix --edition`. The main intent is to provide a way to force `cargo fix` to migrate to a specific edition, instead of just going to the "next". This will be needed for `-Zfix-edition` in order to force it to use the "future" edition, which is never the "next" edition. This requires being able to serialize and deserialize this setting as it is conveyed through an environment variable to the recursive cargo invocation.
1 parent acab7e0 commit 61da2b2

File tree

3 files changed

+60
-14
lines changed

3 files changed

+60
-14
lines changed

src/bin/cargo/commands/fix.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,9 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
9595
gctx,
9696
&ws,
9797
&mut ops::FixOptions {
98-
edition: args.flag("edition"),
98+
edition: args
99+
.flag("edition")
100+
.then_some(ops::EditionFixMode::NextRelative),
99101
idioms: args.flag("edition-idioms"),
100102
compile_opts: opts,
101103
allow_dirty,

src/cargo/ops/fix.rs

Lines changed: 56 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ const IDIOMS_ENV_INTERNAL: &str = "__CARGO_FIX_IDIOMS";
9090
const SYSROOT_INTERNAL: &str = "__CARGO_FIX_RUST_SRC";
9191

9292
pub struct FixOptions {
93-
pub edition: bool,
93+
pub edition: Option<EditionFixMode>,
9494
pub idioms: bool,
9595
pub compile_opts: CompileOptions,
9696
pub allow_dirty: bool,
@@ -100,6 +100,46 @@ pub struct FixOptions {
100100
pub requested_lockfile_path: Option<PathBuf>,
101101
}
102102

103+
/// The behavior of `--edition` migration.
104+
#[derive(Clone, Copy)]
105+
pub enum EditionFixMode {
106+
/// Migrates the package from the current edition to the next.
107+
///
108+
/// This is the normal (stable) behavior of `--edition`.
109+
NextRelative,
110+
/// Migrates to a specific edition.
111+
///
112+
/// This is used by `-Zfix-edition` to force a specific edition like
113+
/// `future`, which does not have a relative value.
114+
OverrideSpecific(Edition),
115+
}
116+
117+
impl EditionFixMode {
118+
/// Returns the edition to use for the given current edition.
119+
pub fn next_edition(&self, current_edition: Edition) -> Edition {
120+
match self {
121+
EditionFixMode::NextRelative => current_edition.saturating_next(),
122+
EditionFixMode::OverrideSpecific(edition) => *edition,
123+
}
124+
}
125+
126+
/// Serializes to a string.
127+
fn to_string(&self) -> String {
128+
match self {
129+
EditionFixMode::NextRelative => "1".to_string(),
130+
EditionFixMode::OverrideSpecific(edition) => edition.to_string(),
131+
}
132+
}
133+
134+
/// Deserializes from the given string.
135+
fn from_str(s: &str) -> EditionFixMode {
136+
match s {
137+
"1" => EditionFixMode::NextRelative,
138+
edition => EditionFixMode::OverrideSpecific(edition.parse().unwrap()),
139+
}
140+
}
141+
}
142+
103143
pub fn fix(
104144
gctx: &GlobalContext,
105145
original_ws: &Workspace<'_>,
@@ -109,13 +149,13 @@ pub fn fix(
109149

110150
let mut target_data =
111151
RustcTargetData::new(original_ws, &opts.compile_opts.build_config.requested_kinds)?;
112-
if opts.edition {
152+
if let Some(edition_mode) = opts.edition {
113153
let specs = opts.compile_opts.spec.to_package_id_specs(&original_ws)?;
114154
let members: Vec<&Package> = original_ws
115155
.members()
116156
.filter(|m| specs.iter().any(|spec| spec.matches(m.package_id())))
117157
.collect();
118-
migrate_manifests(original_ws, &members)?;
158+
migrate_manifests(original_ws, &members, edition_mode)?;
119159

120160
check_resolver_change(&original_ws, &mut target_data, opts)?;
121161
}
@@ -133,8 +173,8 @@ pub fn fix(
133173
wrapper.env(BROKEN_CODE_ENV_INTERNAL, "1");
134174
}
135175

136-
if opts.edition {
137-
wrapper.env(EDITION_ENV_INTERNAL, "1");
176+
if let Some(mode) = &opts.edition {
177+
wrapper.env(EDITION_ENV_INTERNAL, mode.to_string());
138178
}
139179
if opts.idioms {
140180
wrapper.env(IDIOMS_ENV_INTERNAL, "1");
@@ -248,7 +288,11 @@ fn check_version_control(gctx: &GlobalContext, opts: &FixOptions) -> CargoResult
248288
);
249289
}
250290

251-
fn migrate_manifests(ws: &Workspace<'_>, pkgs: &[&Package]) -> CargoResult<()> {
291+
fn migrate_manifests(
292+
ws: &Workspace<'_>,
293+
pkgs: &[&Package],
294+
edition_mode: EditionFixMode,
295+
) -> CargoResult<()> {
252296
// HACK: Duplicate workspace migration logic between virtual manifests and real manifests to
253297
// reduce multiple Migrating messages being reported for the same file to the user
254298
if matches!(ws.root_maybe(), MaybePackage::Virtual(_)) {
@@ -259,7 +303,7 @@ fn migrate_manifests(ws: &Workspace<'_>, pkgs: &[&Package]) -> CargoResult<()> {
259303
.map(|p| p.manifest().edition())
260304
.max()
261305
.unwrap_or_default();
262-
let prepare_for_edition = highest_edition.saturating_next();
306+
let prepare_for_edition = edition_mode.next_edition(highest_edition);
263307
if highest_edition == prepare_for_edition
264308
|| (!prepare_for_edition.is_stable() && !ws.gctx().nightly_features_allowed)
265309
{
@@ -304,7 +348,7 @@ fn migrate_manifests(ws: &Workspace<'_>, pkgs: &[&Package]) -> CargoResult<()> {
304348

305349
for pkg in pkgs {
306350
let existing_edition = pkg.manifest().edition();
307-
let prepare_for_edition = existing_edition.saturating_next();
351+
let prepare_for_edition = edition_mode.next_edition(existing_edition);
308352
if existing_edition == prepare_for_edition
309353
|| (!prepare_for_edition.is_stable() && !ws.gctx().nightly_features_allowed)
310354
{
@@ -1191,10 +1235,10 @@ impl FixArgs {
11911235
// ALLOWED: For the internal mechanism of `cargo fix` only.
11921236
// Shouldn't be set directly by anyone.
11931237
#[allow(clippy::disallowed_methods)]
1194-
let prepare_for_edition = env::var(EDITION_ENV_INTERNAL).ok().map(|_| {
1195-
enabled_edition
1196-
.unwrap_or(Edition::Edition2015)
1197-
.saturating_next()
1238+
let prepare_for_edition = env::var(EDITION_ENV_INTERNAL).ok().map(|v| {
1239+
let enabled_edition = enabled_edition.unwrap_or(Edition::Edition2015);
1240+
let mode = EditionFixMode::from_str(&v);
1241+
mode.next_edition(enabled_edition)
11981242
});
11991243

12001244
// ALLOWED: For the internal mechanism of `cargo fix` only.

src/cargo/ops/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ pub use self::cargo_update::upgrade_manifests;
2626
pub use self::cargo_update::write_manifest_upgrades;
2727
pub use self::cargo_update::UpdateOptions;
2828
pub use self::common_for_install_and_uninstall::{resolve_root, InstallTracker};
29-
pub use self::fix::{fix, fix_exec_rustc, fix_get_proxy_lock_addr, FixOptions};
29+
pub use self::fix::{fix, fix_exec_rustc, fix_get_proxy_lock_addr, EditionFixMode, FixOptions};
3030
pub use self::lockfile::{load_pkg_lockfile, resolve_to_string, write_pkg_lockfile};
3131
pub use self::registry::info;
3232
pub use self::registry::modify_owners;

0 commit comments

Comments
 (0)