cargo/ops/fix/
fix_edition.rs1use super::{EditionFixMode, FixOptions};
4use crate::core::features::{Edition, FixEdition};
5use crate::core::{Package, Workspace};
6use crate::ops;
7use crate::util::toml_mut::manifest::LocalManifest;
8use crate::{CargoResult, GlobalContext};
9use toml_edit::{Formatted, Item, Value};
10
11pub fn fix_edition(
13 gctx: &GlobalContext,
14 original_ws: &Workspace<'_>,
15 opts: &mut FixOptions,
16 fix_edition: &FixEdition,
17) -> CargoResult<()> {
18 let packages = opts.compile_opts.spec.get_packages(original_ws)?;
19 let skip_if_not_edition = |edition| -> CargoResult<bool> {
20 if !packages.iter().all(|p| p.manifest().edition() == edition) {
21 gctx.shell().status(
22 "Skipping",
23 &format!("not all packages are at edition {edition}"),
24 )?;
25 Ok(true)
26 } else {
27 Ok(false)
28 }
29 };
30
31 match fix_edition {
32 FixEdition::Start(edition) => {
33 if skip_if_not_edition(*edition)? {
39 return Ok(());
40 }
41 ops::compile(&original_ws, &opts.compile_opts)?;
42 }
43 FixEdition::End { initial, next } => {
44 if skip_if_not_edition(*initial)? {
47 return Ok(());
48 }
49 opts.edition = Some(EditionFixMode::OverrideSpecific(*next));
51 opts.allow_dirty = true;
52 opts.allow_no_vcs = true;
53 opts.allow_staged = true;
54 ops::fix(gctx, original_ws, opts)?;
55 replace_edition(&packages, *next)?;
58 gctx.shell()
59 .status("Updated", &format!("edition to {next}"))?;
60 let ws = original_ws.reload(gctx)?;
61 *opts
63 .compile_opts
64 .build_config
65 .rustfix_diagnostic_server
66 .borrow_mut() = None;
67 opts.compile_opts.build_config.primary_unit_rustc = None;
68
69 ops::compile(&ws, &opts.compile_opts)?;
70 }
71 }
72 Ok(())
73}
74
75fn replace_edition(packages: &[&Package], to_edition: Edition) -> CargoResult<()> {
77 for package in packages {
78 let mut manifest_mut = LocalManifest::try_new(package.manifest_path())?;
79 let document = &mut manifest_mut.data;
80 let root = document.as_table_mut();
81 if let Some(package) = root.get_mut("package").and_then(|t| t.as_table_like_mut()) {
83 package.insert(
84 "edition",
85 Item::Value(Value::String(Formatted::new(to_edition.to_string()))),
86 );
87 }
88 if !to_edition.is_stable() {
90 let feature = "unstable-editions";
91
92 if let Some(features) = root
93 .entry("cargo-features")
94 .or_insert_with(|| Item::Value(Value::Array(toml_edit::Array::new())))
95 .as_array_mut()
96 {
97 if !features
98 .iter()
99 .any(|f| f.as_str().map_or(false, |f| f == feature))
100 {
101 features.push(feature);
102 }
103 }
104 }
105 manifest_mut.write()?;
106 }
107 Ok(())
108}