use super::{EditionFixMode, FixOptions};
use crate::ops;
use crate::workspace::editor::manifest::LocalManifest;
use crate::workspace::features::{Edition, FixEdition};
use crate::workspace::{Package, Workspace};
use crate::{CargoResult, GlobalContext};
use toml_edit::{Formatted, Item, Value};
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) => {
if skip_if_not_edition(*edition)? {
return Ok(());
}
ops::compile(&original_ws, &opts.compile_opts)?;
}
FixEdition::End { initial, next } => {
if skip_if_not_edition(*initial)? {
return Ok(());
}
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)?;
replace_edition(&packages, *next)?;
gctx.shell()
.status("Updated", &format!("edition to {next}"))?;
let ws = original_ws.reload(gctx)?;
*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(())
}
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();
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 !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(())
}