cargo/ops/
cargo_remove.rs1use crate::CargoResult;
4use crate::GlobalContext;
5use crate::core::Package;
6use crate::util::toml_mut::manifest::DepTable;
7use crate::util::toml_mut::manifest::LocalManifest;
8use crate::util::toml_mut::manifest::MissingDependencyError;
9
10#[derive(Debug)]
12pub struct RemoveOptions<'a> {
13 pub gctx: &'a GlobalContext,
15 pub spec: &'a Package,
17 pub dependencies: Vec<String>,
19 pub section: DepTable,
21 pub dry_run: bool,
23}
24
25pub fn remove(options: &RemoveOptions<'_>) -> CargoResult<()> {
27 let dep_table = options
28 .section
29 .to_table()
30 .into_iter()
31 .map(String::from)
32 .collect::<Vec<_>>();
33
34 let manifest_path = options.spec.manifest_path().to_path_buf();
35 let mut manifest = LocalManifest::try_new(&manifest_path)?;
36
37 for dep in &options.dependencies {
38 let section = if dep_table.len() >= 3 {
39 format!("{} for target `{}`", &dep_table[2], &dep_table[1])
40 } else {
41 dep_table[0].clone()
42 };
43 options
44 .gctx
45 .shell()
46 .status("Removing", format!("{dep} from {section}"))?;
47
48 manifest.remove_from_table(&dep_table, dep).map_err(
49 |MissingDependencyError {
50 expected_name,
51 expected_path,
52 alt_name,
53 alt_path,
54 }| {
55 use std::fmt::Write as _;
56
57 let mut error = String::new();
58 let path = expected_path.join(".");
59 let _ = write!(
60 &mut error,
61 "the dependency `{expected_name}` could not be found in `{path}`"
62 );
63 if let Some(alt_path) = alt_path {
64 let mut flags = Vec::new();
65 match (
66 expected_path.last().unwrap().as_str(),
67 alt_path.last().unwrap().as_str(),
68 ) {
69 ("build-dependencies", "build-dependencies") => {}
70 ("dev-dependencies", "dev-dependencies") => {}
71 ("dependencies", "dependencies") => {}
72 (_, "build-dependencies") => flags.push("--build"),
73 (_, "dev-dependencies") => flags.push("--dev"),
74 (_, _) => {}
75 }
76 if expected_path[0] != "target" && alt_path[0] == "target" {
77 flags.push(&"--target");
78 flags.push(&alt_path[1]);
79 }
80 let alt_path = alt_path.join(".");
81 if !flags.is_empty() {
82 let flags = flags.join(" ");
83 let _ = write!(
84 &mut error,
85 "\n\nhelp: pass `{flags}` to remove `{expected_name}` from `{alt_path}`"
86 );
87 } else {
88 let _ = write!(
89 &mut error,
90 "\n\nhelp: a dependency with the same name exists in `{alt_path}`"
91 );
92 }
93 } else if let Some(alt_name) = alt_name {
94 let _ = write!(
95 &mut error,
96 "\n\nhelp: a dependency with a similar name exists: `{alt_name}`"
97 );
98 }
99 anyhow::format_err!("{error}")
100 },
101 )?;
102
103 manifest.gc_dep(dep);
107 }
108
109 if options.dry_run {
110 options
111 .gctx
112 .shell()
113 .warn("aborting remove due to dry run")?;
114 } else {
115 manifest.write()?;
116 }
117
118 Ok(())
119}