mirror of
https://github.com/rust-lang/cargo.git
synced 2025-09-25 11:14:46 +00:00
Implement -Zfix-edition
This adds the implementation for the behavior of `cargo fix -Zfix-edition`.
This commit is contained in:
parent
331dcec02d
commit
21629670f4
@ -91,10 +91,7 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
|
||||
|
||||
let allow_dirty = args.flag("allow-dirty");
|
||||
|
||||
ops::fix(
|
||||
gctx,
|
||||
&ws,
|
||||
&mut ops::FixOptions {
|
||||
let mut opts = ops::FixOptions {
|
||||
edition: args
|
||||
.flag("edition")
|
||||
.then_some(ops::EditionFixMode::NextRelative),
|
||||
@ -105,7 +102,13 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
|
||||
allow_no_vcs: args.flag("allow-no-vcs"),
|
||||
broken_code: args.flag("broken-code"),
|
||||
requested_lockfile_path: lockfile_path,
|
||||
},
|
||||
)?;
|
||||
};
|
||||
|
||||
if let Some(fe) = &gctx.cli_unstable().fix_edition {
|
||||
ops::fix_edition(gctx, &ws, &mut opts, fe)?;
|
||||
} else {
|
||||
ops::fix(gctx, &ws, &mut opts)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
108
src/cargo/ops/fix/fix_edition.rs
Normal file
108
src/cargo/ops/fix/fix_edition.rs
Normal file
@ -0,0 +1,108 @@
|
||||
//! Support for the permanently unstable `-Zfix-edition` flag.
|
||||
|
||||
use super::{EditionFixMode, FixOptions};
|
||||
use crate::core::features::{Edition, FixEdition};
|
||||
use crate::core::{Package, Workspace};
|
||||
use crate::ops;
|
||||
use crate::util::toml_mut::manifest::LocalManifest;
|
||||
use crate::{CargoResult, GlobalContext};
|
||||
use toml_edit::{Formatted, Item, Value};
|
||||
|
||||
/// Performs the actions for the `-Zfix-edition` flag.
|
||||
pub fn fix_edition(
|
||||
gctx: &GlobalContext,
|
||||
original_ws: &Workspace<'_>,
|
||||
opts: &mut FixOptions,
|
||||
fix_edition: &FixEdition,
|
||||
) -> CargoResult<()> {
|
||||
let packages = opts.compile_opts.spec.get_packages(original_ws)?;
|
||||
let skip_if_not_edition = |edition| -> CargoResult<bool> {
|
||||
if !packages.iter().all(|p| p.manifest().edition() == edition) {
|
||||
gctx.shell().status(
|
||||
"Skipping",
|
||||
&format!("not all packages are at edition {edition}"),
|
||||
)?;
|
||||
Ok(true)
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
};
|
||||
|
||||
match fix_edition {
|
||||
FixEdition::Start(edition) => {
|
||||
// The start point just runs `cargo check` if the edition is the
|
||||
// starting edition. This is so that crater can set a baseline of
|
||||
// whether or not the package builds at all. For other editions,
|
||||
// we skip entirely since they are not of interest since we can't
|
||||
// migrate them.
|
||||
if skip_if_not_edition(*edition)? {
|
||||
return Ok(());
|
||||
}
|
||||
ops::compile(&original_ws, &opts.compile_opts)?;
|
||||
}
|
||||
FixEdition::End { initial, next } => {
|
||||
// Skip packages that are not the starting edition, since we can
|
||||
// only migrate from one edition to the next.
|
||||
if skip_if_not_edition(*initial)? {
|
||||
return Ok(());
|
||||
}
|
||||
// Do the edition fix.
|
||||
opts.edition = Some(EditionFixMode::OverrideSpecific(*next));
|
||||
opts.allow_dirty = true;
|
||||
opts.allow_no_vcs = true;
|
||||
opts.allow_staged = true;
|
||||
ops::fix(gctx, original_ws, opts)?;
|
||||
// Do `cargo check` with the new edition so that we can verify
|
||||
// that it also works on the next edition.
|
||||
replace_edition(&packages, *next)?;
|
||||
gctx.shell()
|
||||
.status("Updated", &format!("edition to {next}"))?;
|
||||
let ws = original_ws.reload(gctx)?;
|
||||
// Unset these since we just want to do a normal `cargo check`.
|
||||
*opts
|
||||
.compile_opts
|
||||
.build_config
|
||||
.rustfix_diagnostic_server
|
||||
.borrow_mut() = None;
|
||||
opts.compile_opts.build_config.primary_unit_rustc = None;
|
||||
|
||||
ops::compile(&ws, &opts.compile_opts)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Modifies the `edition` value of the given packages to the new edition.
|
||||
fn replace_edition(packages: &[&Package], to_edition: Edition) -> CargoResult<()> {
|
||||
for package in packages {
|
||||
let mut manifest_mut = LocalManifest::try_new(package.manifest_path())?;
|
||||
let document = &mut manifest_mut.data;
|
||||
let root = document.as_table_mut();
|
||||
// Update edition to the new value.
|
||||
if let Some(package) = root.get_mut("package").and_then(|t| t.as_table_like_mut()) {
|
||||
package.insert(
|
||||
"edition",
|
||||
Item::Value(Value::String(Formatted::new(to_edition.to_string()))),
|
||||
);
|
||||
}
|
||||
// If the edition is unstable, add it to cargo-features.
|
||||
if !to_edition.is_stable() {
|
||||
let feature = "unstable-editions";
|
||||
|
||||
if let Some(features) = root
|
||||
.entry("cargo-features")
|
||||
.or_insert_with(|| Item::Value(Value::Array(toml_edit::Array::new())))
|
||||
.as_array_mut()
|
||||
{
|
||||
if !features
|
||||
.iter()
|
||||
.any(|f| f.as_str().map_or(false, |f| f == feature))
|
||||
{
|
||||
features.push(feature);
|
||||
}
|
||||
}
|
||||
}
|
||||
manifest_mut.write()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
@ -51,6 +51,7 @@ use rustfix::CodeFix;
|
||||
use semver::Version;
|
||||
use tracing::{debug, trace, warn};
|
||||
|
||||
pub use self::fix_edition::fix_edition;
|
||||
use crate::core::compiler::CompileKind;
|
||||
use crate::core::compiler::RustcTargetData;
|
||||
use crate::core::resolver::features::{DiffMap, FeatureOpts, FeatureResolver, FeaturesFor};
|
||||
@ -66,6 +67,8 @@ use crate::util::GlobalContext;
|
||||
use crate::util::{existing_vcs_repo, LockServer, LockServerClient};
|
||||
use crate::{drop_eprint, drop_eprintln};
|
||||
|
||||
mod fix_edition;
|
||||
|
||||
/// **Internal only.**
|
||||
/// Indicates Cargo is in fix-proxy-mode if presents.
|
||||
/// The value of it is the socket address of the [`LockServer`] being used.
|
@ -26,7 +26,9 @@ pub use self::cargo_update::upgrade_manifests;
|
||||
pub use self::cargo_update::write_manifest_upgrades;
|
||||
pub use self::cargo_update::UpdateOptions;
|
||||
pub use self::common_for_install_and_uninstall::{resolve_root, InstallTracker};
|
||||
pub use self::fix::{fix, fix_exec_rustc, fix_get_proxy_lock_addr, EditionFixMode, FixOptions};
|
||||
pub use self::fix::{
|
||||
fix, fix_edition, fix_exec_rustc, fix_get_proxy_lock_addr, EditionFixMode, FixOptions,
|
||||
};
|
||||
pub use self::lockfile::{load_pkg_lockfile, resolve_to_string, write_pkg_lockfile};
|
||||
pub use self::registry::info;
|
||||
pub use self::registry::modify_owners;
|
||||
|
@ -2963,3 +2963,103 @@ dep_df_false = { workspace = true, default-features = false }
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn fix_edition_skips_old_editions() {
|
||||
// Checks that -Zfix-edition will skip things that are not 2024.
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
r#"[workspace]
|
||||
members = ["e2021", "e2024"]
|
||||
resolver = "3"
|
||||
"#,
|
||||
)
|
||||
.file(
|
||||
"e2021/Cargo.toml",
|
||||
r#"
|
||||
[package]
|
||||
name = "e2021"
|
||||
edition = "2021"
|
||||
"#,
|
||||
)
|
||||
.file("e2021/src/lib.rs", "")
|
||||
.file(
|
||||
"e2024/Cargo.toml",
|
||||
r#"
|
||||
[package]
|
||||
name = "e2024"
|
||||
edition = "2024"
|
||||
"#,
|
||||
)
|
||||
.file("e2024/src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
// Doing the whole workspace should skip since there is a 2021 in the mix.
|
||||
p.cargo("fix -Zfix-edition=start=2024 -v")
|
||||
.masquerade_as_nightly_cargo(&["fix-edition"])
|
||||
.with_stderr_data(str![[r#"
|
||||
[SKIPPING] not all packages are at edition 2024
|
||||
|
||||
"#]])
|
||||
.run();
|
||||
|
||||
// Same with `end`.
|
||||
p.cargo("fix -Zfix-edition=end=2024,future -v")
|
||||
.masquerade_as_nightly_cargo(&["fix-edition"])
|
||||
.with_stderr_data(str![[r#"
|
||||
[SKIPPING] not all packages are at edition 2024
|
||||
|
||||
"#]])
|
||||
.run();
|
||||
|
||||
// Doing an individual package at the correct edition should check it.
|
||||
p.cargo("fix -Zfix-edition=start=2024 -p e2024")
|
||||
.masquerade_as_nightly_cargo(&["fix-edition"])
|
||||
.with_stderr_data(str![[r#"
|
||||
[CHECKING] e2024 v0.0.0 ([ROOT]/foo/e2024)
|
||||
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
|
||||
|
||||
"#]])
|
||||
.run();
|
||||
}
|
||||
|
||||
#[cargo_test(nightly, reason = "future edition is always unstable")]
|
||||
fn fix_edition_future() {
|
||||
// Checks that the -Zfix-edition can work for the future.
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
r#"
|
||||
[package]
|
||||
name = "foo"
|
||||
edition = "2024""#,
|
||||
)
|
||||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
p.cargo("fix -Zfix-edition=end=2024,future")
|
||||
.masquerade_as_nightly_cargo(&["fix-edition"])
|
||||
.with_stderr_data(str![[r#"
|
||||
[MIGRATING] Cargo.toml from 2024 edition to future
|
||||
[CHECKING] foo v0.0.0 ([ROOT]/foo)
|
||||
[MIGRATING] src/lib.rs from 2024 edition to future
|
||||
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
|
||||
Updated edition to future
|
||||
[CHECKING] foo v0.0.0 ([ROOT]/foo)
|
||||
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
|
||||
|
||||
"#]])
|
||||
.run();
|
||||
assert_e2e().eq(
|
||||
p.read_file("Cargo.toml"),
|
||||
str![[r#"
|
||||
cargo-features = ["unstable-editions"]
|
||||
|
||||
[package]
|
||||
name = "foo"
|
||||
edition = "future"
|
||||
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -279,7 +279,7 @@ trigger_files = ["src/bin/cargo/commands/fetch.rs", "src/cargo/ops/cargo_fetch.r
|
||||
trigger_files = [
|
||||
"crates/rustfix/",
|
||||
"src/bin/cargo/commands/fix.rs",
|
||||
"src/cargo/ops/fix.rs",
|
||||
"src/cargo/ops/fix/",
|
||||
"src/cargo/util/diagnostic_server.rs",
|
||||
"src/cargo/util/lockserver.rs",
|
||||
]
|
||||
|
Loading…
x
Reference in New Issue
Block a user