Skip to main content

zoi_uninstall/
autoremove.rs

1//! Automatic removal of unused dependencies.
2
3use anyhow::Result;
4use colored::Colorize;
5use zoi_core::types::InstallReason;
6use zoi_core::utils as core_utils;
7use zoi_resolver::local;
8
9/// Runs the autoremove operation, identifying and removing packages that were
10/// installed as dependencies but are no longer required by any other package.
11/// # Errors
12///
13/// Returns an error if the package list cannot be retrieved or uninstallation
14/// fails.
15pub fn run(yes: bool, dry_run: bool) -> Result<()> {
16    println!("Checking for unused dependencies...");
17    let all_installed = local::get_installed_packages()?;
18    let mut packages_to_remove: Vec<String> = Vec::new();
19
20    for package in &all_installed {
21        if !matches!(package.reason, InstallReason::Dependency { .. }) {
22            continue;
23        }
24
25        let package_dir = local::get_package_dir(
26            package.scope,
27            &package.registry_handle,
28            &package.repo,
29            &package.name
30        )?;
31        let dependents = local::get_dependents(&package_dir)?;
32
33        if dependents.is_empty() {
34            packages_to_remove.push(local::installed_manifest_source(package));
35        }
36    }
37
38    if packages_to_remove.is_empty() {
39        println!("{}", "No unused dependencies to remove.".green());
40        return Ok(());
41    }
42
43    if dry_run {
44        println!("\nThe following packages WOULD BE REMOVED (Dry-run):");
45        for pkg_name in &packages_to_remove {
46            println!("    - {}", pkg_name.yellow());
47        }
48        return Ok(());
49    }
50
51    println!("\nThe following packages will be REMOVED:");
52    for pkg_name in &packages_to_remove {
53        println!("    - {}", pkg_name.yellow());
54    }
55
56    if !core_utils::ask_for_confirmation("\nDo you want to continue?", yes) {
57        println!("Operation aborted.");
58        return Ok(());
59    }
60
61    for pkg_name in &packages_to_remove {
62        println!("\n{} Removing {}...", "::".bold().blue(), pkg_name.bold());
63        if let Err(e) = crate::run(pkg_name, None, yes, false, false) {
64            eprintln!(
65                "{} Failed to remove {}: {}",
66                "Error:".red(),
67                pkg_name,
68                e
69            );
70        }
71    }
72
73    Ok(())
74}