zoi-uninstall 1.24.0

Advanced Package Manager & Environment Orchestrator
Documentation
use anyhow::Result;
use colored::*;
use zoi_core::{types::InstallReason, utils as core_utils};
use zoi_resolver::local;

pub fn run(yes: bool, dry_run: bool) -> Result<()> {
    println!("Checking for unused dependencies...");
    let all_installed = local::get_installed_packages()?;
    let mut packages_to_remove: Vec<String> = Vec::new();

    for package in &all_installed {
        if !matches!(package.reason, InstallReason::Dependency { .. }) {
            continue;
        }

        let package_dir = local::get_package_dir(
            package.scope,
            &package.registry_handle,
            &package.repo,
            &package.name,
        )?;
        let dependents = local::get_dependents(&package_dir)?;

        if dependents.is_empty() {
            packages_to_remove.push(local::installed_manifest_source(package));
        }
    }

    if packages_to_remove.is_empty() {
        println!("{}", "No unused dependencies to remove.".green());
        return Ok(());
    }

    if dry_run {
        println!("\nThe following packages WOULD BE REMOVED (Dry-run):");
        for pkg_name in &packages_to_remove {
            println!("    - {}", pkg_name.yellow());
        }
        return Ok(());
    }

    println!("\nThe following packages will be REMOVED:");
    for pkg_name in &packages_to_remove {
        println!("    - {}", pkg_name.yellow());
    }

    if !core_utils::ask_for_confirmation("\nDo you want to continue?", yes) {
        println!("Operation aborted.");
        return Ok(());
    }

    for pkg_name in &packages_to_remove {
        println!("\n{} Removing {}...", "::".bold().blue(), pkg_name.bold());
        if let Err(e) = crate::run(pkg_name, None, yes, false, false) {
            eprintln!("{} Failed to remove {}: {}", "Error:".red(), pkg_name, e);
        }
    }

    Ok(())
}