use cargo_edit::shell_status;
use cargo_edit::shell_warn;
use cargo_edit::CargoResult;
use cargo_edit::{manifest_from_pkgid, LocalManifest};
use clap::Args;
use std::borrow::Cow;
use std::path::PathBuf;
#[derive(Debug, Args)]
#[command(version)]
pub struct RmArgs {
#[arg(value_name = "DEP_ID", required = true)]
crates: Vec<String>,
#[arg(long, short = 'D', conflicts_with = "build", help_heading = "Section")]
dev: bool,
#[arg(long, short = 'B', conflicts_with = "dev", help_heading = "Section")]
build: bool,
#[arg(long, value_parser = clap::builder::NonEmptyStringValueParser::new(), help_heading = "Section")]
target: Option<String>,
#[arg(long, value_name = "PATH")]
manifest_path: Option<PathBuf>,
#[arg(long = "package", short = 'p', value_name = "PKGID")]
pkgid: Option<String>,
#[arg(short = 'Z', value_name = "FLAG", global = true, value_enum)]
unstable_features: Vec<UnstableOptions>,
#[arg(long)]
dry_run: bool,
#[arg(long, short)]
quiet: bool,
}
impl RmArgs {
pub fn exec(&self) -> CargoResult<()> {
exec(self)
}
pub fn get_section(&self) -> Vec<String> {
let section_name = if self.dev {
"dev-dependencies"
} else if self.build {
"build-dependencies"
} else {
"dependencies"
};
if let Some(ref target) = self.target {
assert!(!target.is_empty(), "Target specification may not be empty");
vec!["target".to_owned(), target.clone(), section_name.to_owned()]
} else {
vec![section_name.to_owned()]
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
enum UnstableOptions {}
fn exec(args: &RmArgs) -> CargoResult<()> {
let manifest_path = if let Some(ref pkgid) = args.pkgid {
let pkg = manifest_from_pkgid(args.manifest_path.as_deref(), pkgid)?;
Cow::Owned(Some(pkg.manifest_path.into_std_path_buf()))
} else {
Cow::Borrowed(&args.manifest_path)
};
let mut manifest = LocalManifest::find(manifest_path.as_deref())?;
let deps = &args.crates;
deps.iter()
.map(|dep| {
if !args.quiet {
let section = args.get_section();
let section = if section.len() >= 3 {
format!("{} for target `{}`", §ion[2], §ion[1])
} else {
section[0].clone()
};
shell_status("Removing", &format!("{dep} from {section}",))?;
}
let result = manifest
.remove_from_table(&args.get_section(), dep)
.map_err(Into::into);
manifest.gc_dep(dep);
result
})
.collect::<CargoResult<Vec<_>>>()?;
if args.dry_run {
shell_warn("aborting rm due to dry run")?;
} else {
manifest.write()?;
}
Ok(())
}