winbrew_engines\windows\exe/
remove.rs1use anyhow::{Context, Result, bail};
2use std::path::Path;
3use std::process::Command;
4use tracing::warn;
5
6use crate::core::fs::cleanup_path;
7use crate::models::install::installed::InstalledPackage;
8
9use super::NATIVE_EXE_SUCCESS_EXIT_CODES;
10use super::switches::split_switches;
11use super::validation::{validate_install_dir, validate_package_name};
12
13pub(crate) fn remove(package: &InstalledPackage) -> Result<()> {
20 validate_package_name(&package.name)?;
21 validate_install_dir(Path::new(&package.install_dir))?;
22
23 let uninstall_command = package
24 .engine_metadata
25 .as_ref()
26 .and_then(|metadata| metadata.native_exe_uninstall_command());
27
28 if let Some(command) = uninstall_command {
29 if let Err(err) = run_uninstall_command(command, &package.name) {
30 warn!(
31 package = package.name.as_str(),
32 error = %err,
33 "native executable uninstall command failed; falling back to directory cleanup"
34 );
35 }
36 } else {
37 warn!(
38 package = package.name.as_str(),
39 install_dir = %package.install_dir,
40 "native executable uninstall metadata was not available; falling back to directory cleanup"
41 );
42 }
43
44 cleanup_path(Path::new(&package.install_dir))
45 .with_context(|| format!("failed to remove {}", package.install_dir))?;
46
47 Ok(())
48}
49
50fn run_uninstall_command(command: &str, package_name: &str) -> Result<()> {
51 let mut command_parts = split_switches(command)?;
52
53 if command_parts.is_empty() {
54 bail!("native executable uninstall command is empty for '{package_name}'");
55 }
56
57 let program = command_parts.remove(0);
58 let status = Command::new(program)
59 .args(command_parts)
60 .status()
61 .with_context(|| {
62 format!("failed to launch native executable uninstaller for {package_name}")
63 })?;
64
65 let exit_code = status.code().ok_or_else(|| {
66 anyhow::anyhow!("native executable uninstaller terminated without an exit code")
67 })?;
68
69 if !NATIVE_EXE_SUCCESS_EXIT_CODES.contains(&exit_code) {
70 bail!(
71 "native executable uninstaller for {} failed with exit code {}",
72 package_name,
73 exit_code
74 );
75 }
76
77 Ok(())
78}