winbrew_cli\commands/
remove.rs1use anyhow::Result;
5
6use crate::commands::error::reported_with_hint;
7use crate::{CommandContext, app::remove};
8use winbrew_ui::Ui;
9
10pub fn run(ctx: &CommandContext, name: &[String], yes: bool, force: bool) -> Result<()> {
11 let mut ui = ctx.ui();
12 ui.page_title("Remove Package");
13
14 let name_text = name.join(" ").trim().to_owned();
15 if name_text.is_empty() {
16 return Err(anyhow::anyhow!("package name cannot be empty"));
17 }
18
19 ui.info(format!("Assessing impact for {name_text}..."));
20 let plan = remove::plan_removal(&name_text)?;
21
22 if !plan.dependents.is_empty() {
23 ui.warn(format!(
24 "Caution: {} is required by: {}",
25 plan.package.name,
26 plan.dependents.join(", ")
27 ));
28 }
29
30 if !should_proceed(&mut ui, &plan, yes, force)? {
31 ui.notice("Removal aborted.");
32 return Ok(());
33 }
34
35 let removal_result = ui.spinner(format!("Removing {}...", plan.package.name), || {
36 remove::execute_removal(&plan, force)
37 });
38
39 if let Err(err) = removal_result {
40 match err {
41 remove::RemovalError::DependentPackagesBlocked { name, dependents } => {
42 ui.warn(format!(
43 "Removal of {name} was blocked because it is required by: {}",
44 dependents
45 ));
46 let message = format!(
47 "cannot remove '{name}' because it is required by: {}",
48 dependents
49 );
50 ui.notice("Hint: re-run with --force if you intend to remove the package anyway.");
51 return Err(reported_with_hint(
52 message,
53 "Re-run with --force if you intend to remove the package anyway.",
54 ));
55 }
56 remove::RemovalError::UnsupportedPackageType { kind } => {
57 ui.error(format!("unsupported package type: {kind}"));
58 let message = format!("unsupported package type: {kind}");
59 ui.notice("Hint: check the package metadata or choose a supported installer type.");
60 return Err(reported_with_hint(
61 message,
62 "Check the package metadata or choose a supported installer type.",
63 ));
64 }
65 remove::RemovalError::Unexpected(err) => return Err(err),
66 }
67 }
68
69 ui.success(format!("Successfully removed {}.", plan.package.name));
70
71 Ok(())
72}
73
74fn should_proceed<W: std::io::Write>(
75 ui: &mut Ui<W>,
76 plan: &remove::RemovalPlan,
77 yes: bool,
78 force: bool,
79) -> Result<bool> {
80 if force || yes {
81 return Ok(true);
82 }
83
84 let prompt = if plan.dependents.is_empty() {
85 format!("Are you sure you want to remove {}?", plan.package.name)
86 } else {
87 format!(
88 "Removal of {} may break other packages. Proceed anyway?",
89 plan.package.name
90 )
91 };
92
93 ui.confirm(&prompt, false)
94}