diff --git a/src/cargo/ops/fix/mod.rs b/src/cargo/ops/fix/mod.rs index 6bd0199a494..e7632e43e76 100644 --- a/src/cargo/ops/fix/mod.rs +++ b/src/cargo/ops/fix/mod.rs @@ -151,16 +151,18 @@ pub fn fix( let mut target_data = RustcTargetData::new(original_ws, &opts.compile_opts.build_config.requested_kinds)?; + + let specs = opts.compile_opts.spec.to_package_id_specs(&original_ws)?; + let members: Vec<&Package> = original_ws + .members() + .filter(|m| specs.iter().any(|spec| spec.matches(m.package_id()))) + .collect(); if let Some(edition_mode) = opts.edition { - let specs = opts.compile_opts.spec.to_package_id_specs(&original_ws)?; - let members: Vec<&Package> = original_ws - .members() - .filter(|m| specs.iter().any(|spec| spec.matches(m.package_id()))) - .collect(); migrate_manifests(original_ws, &members, edition_mode)?; check_resolver_change(&original_ws, &mut target_data, opts)?; } + fix_manifests(original_ws, &members)?; let ws = original_ws.reload(gctx)?; // Spin up our lock server, which our subprocesses will use to synchronize fixes. @@ -290,6 +292,50 @@ fn check_version_control(gctx: &GlobalContext, opts: &FixOptions) -> CargoResult ); } +fn fix_manifests(ws: &Workspace<'_>, pkgs: &[&Package]) -> CargoResult<()> { + for pkg in pkgs { + if !pkg.manifest().is_embedded() + || pkg + .manifest() + .original_toml() + .and_then(|m| m.package()) + .map(|pkg| pkg.edition.is_some()) + .unwrap_or(false) + { + continue; + } + let file = pkg.manifest_path(); + let file = file.strip_prefix(ws.root()).unwrap_or(file); + let file = file.display(); + + let mut manifest_mut = LocalManifest::try_new(pkg.manifest_path())?; + let document = &mut manifest_mut.data; + let mut fixes = 0; + + let root = document.as_table_mut(); + + fixes += 1; + root.entry("package").or_insert_with(|| { + let mut t = toml_edit::Table::new(); + t.set_position(Some(-1)); + t.into() + }); + root["package"]["edition"] = crate::core::features::Edition::LATEST_STABLE + .to_string() + .into(); + + if 0 < fixes { + let verb = if fixes == 1 { "fix" } else { "fixes" }; + let msg = format!("{file} ({fixes} {verb})"); + ws.gctx().shell().status("Fixed", msg)?; + + manifest_mut.write()?; + } + } + + Ok(()) +} + fn migrate_manifests( ws: &Workspace<'_>, pkgs: &[&Package], diff --git a/tests/testsuite/fix.rs b/tests/testsuite/fix.rs index b4d411f781c..1fafbbfa163 100644 --- a/tests/testsuite/fix.rs +++ b/tests/testsuite/fix.rs @@ -3066,3 +3066,186 @@ edition = "future" "#]], ); } + +#[cargo_test(nightly, reason = "-Zscript is unstable")] +fn script_without_frontmatter() { + let p = cargo_test_support::project() + .file("echo.rs", "fn main() {}") + .build(); + + p.cargo("fix -Zscript --allow-no-vcs --manifest-path echo.rs") + .masquerade_as_nightly_cargo(&["script"]) + .with_stdout_data(str![""]) + .with_stderr_data(str![[r#" +[WARNING] `package.edition` is unspecified, defaulting to the latest edition (currently `[..]`) +[FIXED] echo.rs (1 fix) +[CHECKING] echo v0.0.0 ([ROOT]/foo/echo.rs) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s + +"#]]) + .run(); + + assert_e2e().eq( + p.read_file("echo.rs"), + str![[r#" +--- +[package] +edition = "2024" +--- + +fn main() {} +"#]], + ); +} + +#[cargo_test(nightly, reason = "-Zscript is unstable")] +fn script_with_frontmatter() { + let p = cargo_test_support::project() + .file( + "echo.rs", + "#!/usr/bin/env cargo +--- +[dependencies] +--- +fn main() {}", + ) + .build(); + + p.cargo("fix -Zscript --allow-no-vcs --manifest-path echo.rs") + .masquerade_as_nightly_cargo(&["script"]) + .with_stdout_data(str![""]) + .with_stderr_data(str![[r#" +[WARNING] `package.edition` is unspecified, defaulting to the latest edition (currently `[..]`) +[FIXED] echo.rs (1 fix) +[CHECKING] echo v0.0.0 ([ROOT]/foo/echo.rs) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s + +"#]]) + .run(); + + assert_e2e().eq( + p.read_file("echo.rs"), + str![[r##" +#!/usr/bin/env cargo +--- +[package] +edition = "2024" +[dependencies] +--- +fn main() {} +"##]], + ); +} + +#[cargo_test(nightly, reason = "-Zscript is unstable")] +fn script_with_package_table() { + let p = cargo_test_support::project() + .file( + "echo.rs", + r#"#!/usr/bin/env cargo +--- +[package] +name = "foo" +--- +fn main() {}"#, + ) + .build(); + + p.cargo("fix -Zscript --allow-no-vcs --manifest-path echo.rs") + .masquerade_as_nightly_cargo(&["script"]) + .with_stdout_data(str![""]) + .with_stderr_data(str![[r#" +[WARNING] `package.edition` is unspecified, defaulting to the latest edition (currently `[..]`) +[FIXED] echo.rs (1 fix) +[CHECKING] foo v0.0.0 ([ROOT]/foo/echo.rs) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s + +"#]]) + .run(); + + assert_e2e().eq( + p.read_file("echo.rs"), + str![[r##" +#!/usr/bin/env cargo +--- +[package] +name = "foo" +edition = "2024" +--- +fn main() {} +"##]], + ); +} + +#[cargo_test(nightly, reason = "-Zscript is unstable")] +fn script_with_package_dotted() { + let p = cargo_test_support::project() + .file( + "echo.rs", + r#"#!/usr/bin/env cargo +--- +package.name = "foo" +--- +fn main() {}"#, + ) + .build(); + + p.cargo("fix -Zscript --allow-no-vcs --manifest-path echo.rs") + .masquerade_as_nightly_cargo(&["script"]) + .with_stdout_data(str![""]) + .with_stderr_data(str![[r#" +[WARNING] `package.edition` is unspecified, defaulting to the latest edition (currently `[..]`) +[FIXED] echo.rs (1 fix) +[CHECKING] foo v0.0.0 ([ROOT]/foo/echo.rs) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s + +"#]]) + .run(); + + assert_e2e().eq( + p.read_file("echo.rs"), + str![[r##" +#!/usr/bin/env cargo +--- +package.name = "foo" +package.edition = "2024" +--- +fn main() {} +"##]], + ); +} + +#[cargo_test(nightly, reason = "-Zscript is unstable")] +fn script_with_edition() { + let p = cargo_test_support::project() + .file( + "echo.rs", + r#"#!/usr/bin/env cargo +--- +package.edition = "2015" +--- +fn main() {}"#, + ) + .build(); + + p.cargo("fix -Zscript --allow-no-vcs --manifest-path echo.rs") + .masquerade_as_nightly_cargo(&["script"]) + .with_stdout_data(str![""]) + .with_stderr_data(str![[r#" +[CHECKING] echo v0.0.0 ([ROOT]/foo/echo.rs) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s + +"#]]) + .run(); + + assert_e2e().eq( + p.read_file("echo.rs"), + str![[r##" +#!/usr/bin/env cargo +--- +package.edition = "2015" +--- +fn main() {} +"##]], + ); +}