use std::{env::current_dir, fs::read_to_string, path::Path, str::FromStr};
use anyhow::{Context, Result};
use cargo::{core::Workspace, util::toml_mut::manifest::LocalManifest};
use crate::{
cli::{self, Args},
edit,
plan::{RemoveCrate, RemoveDep, RemoveFeature},
};
#[derive(serde::Serialize, serde::Deserialize, Default)]
pub struct Crate {
pub name: String,
#[serde(skip_serializing_if = "Vec::is_empty")]
#[serde(default)]
pub remove_feature: Vec<RemoveFeature>,
#[serde(skip_serializing_if = "Vec::is_empty")]
#[serde(default)]
pub remove_dep: Vec<RemoveDep>,
}
#[derive(serde::Serialize, serde::Deserialize, Default)]
pub struct Config {
#[serde(skip_serializing_if = "Vec::is_empty")]
#[serde(default)]
#[serde(rename = "crate")]
pub crates: Vec<Crate>,
#[serde(skip_serializing_if = "Vec::is_empty")]
#[serde(default)]
#[serde(rename = "remove_crate")]
pub remove_crates: Vec<RemoveCrate>,
}
pub fn handle_config(_args: Args, cli: cli::Config) -> Result<()> {
let path = current_dir()?;
let config = read_config(&path)?;
let cargo_config = cargo::GlobalContext::default()?;
cargo_config
.shell()
.set_verbosity(cargo::core::Verbosity::Quiet);
let workspace = Workspace::new(&path.join("Cargo.toml"), &cargo_config)?;
if cli.apply {
apply_config(&workspace, &config)?;
}
Ok(())
}
pub fn apply_config(workspace: &Workspace, config: &Config) -> Result<()> {
for pkg in &config.remove_crates {
edit::remove_crate(&workspace, pkg)?;
}
let root_manifest = std::fs::read_to_string(workspace.root_manifest())?;
let mut root_manifest = toml_edit::DocumentMut::from_str(&root_manifest)?;
for pkg in &config.crates {
let c = workspace
.members()
.find(|c| c.name().as_str() == pkg.name)
.context("can't find crate")?;
let path = c.root();
let mut manifest = LocalManifest::try_new(&path.join(path).join("Cargo.toml"))?;
for remove_feature in &pkg.remove_feature {
edit::remove_feature(&mut manifest, remove_feature)?;
}
for remove_dep in &pkg.remove_dep {
edit::remove_dep(&workspace, &mut root_manifest, &mut manifest, remove_dep)?;
}
manifest.write()?;
std::fs::write(workspace.root_manifest(), &root_manifest.to_string())?;
}
Ok(())
}
pub fn read_config(path: &Path) -> Result<Config> {
let path = path.join("Plan.config");
if !path.exists() {
return Ok(Default::default());
}
let config = read_to_string(path).context("failed to read Plan.config")?;
let config = toml::from_str(&config)?;
Ok(config)
}