cargo/ops/
cargo_remove.rs

1//! Core of cargo-remove command
2
3use crate::core::Package;
4use crate::util::toml_mut::manifest::DepTable;
5use crate::util::toml_mut::manifest::LocalManifest;
6use crate::CargoResult;
7use crate::GlobalContext;
8
9/// Remove a dependency from a Cargo.toml manifest file.
10#[derive(Debug)]
11pub struct RemoveOptions<'a> {
12    /// Configuration information for Cargo operations
13    pub gctx: &'a GlobalContext,
14    /// Package to remove dependencies from
15    pub spec: &'a Package,
16    /// Dependencies to remove
17    pub dependencies: Vec<String>,
18    /// Which dependency section to remove these from
19    pub section: DepTable,
20    /// Whether or not to actually write the manifest
21    pub dry_run: bool,
22}
23
24/// Remove dependencies from a manifest
25pub fn remove(options: &RemoveOptions<'_>) -> CargoResult<()> {
26    let dep_table = options
27        .section
28        .to_table()
29        .into_iter()
30        .map(String::from)
31        .collect::<Vec<_>>();
32
33    let manifest_path = options.spec.manifest_path().to_path_buf();
34    let mut manifest = LocalManifest::try_new(&manifest_path)?;
35
36    for dep in &options.dependencies {
37        let section = if dep_table.len() >= 3 {
38            format!("{} for target `{}`", &dep_table[2], &dep_table[1])
39        } else {
40            dep_table[0].clone()
41        };
42        options
43            .gctx
44            .shell()
45            .status("Removing", format!("{dep} from {section}"))?;
46
47        manifest.remove_from_table(&dep_table, dep)?;
48
49        // Now that we have removed the crate, if that was the last reference to that
50        // crate, then we need to drop any explicitly activated features on
51        // that crate.
52        manifest.gc_dep(dep);
53    }
54
55    if options.dry_run {
56        options
57            .gctx
58            .shell()
59            .warn("aborting remove due to dry run")?;
60    } else {
61        manifest.write()?;
62    }
63
64    Ok(())
65}