zoi/cmd/
why.rs

1use crate::pkg::{local, resolve, types};
2use anyhow::{Result, anyhow};
3use colored::*;
4
5pub fn run(package_name: &str) -> Result<()> {
6    let request = resolve::parse_source_string(package_name)?;
7    let (pkg_meta, _, _, _, _) = resolve::resolve_package_and_version(package_name, false)?;
8
9    let user_manifest = local::is_package_installed(
10        &pkg_meta.name,
11        request.sub_package.as_deref(),
12        types::Scope::User,
13    )?;
14    let system_manifest = local::is_package_installed(
15        &pkg_meta.name,
16        request.sub_package.as_deref(),
17        types::Scope::System,
18    )?;
19    let _project_manifest = local::is_package_installed(
20        &pkg_meta.name,
21        request.sub_package.as_deref(),
22        types::Scope::Project,
23    )?;
24
25    let manifest = match (user_manifest, system_manifest) {
26        (Some(m), None) => m,
27        (None, Some(m)) => m,
28        (Some(_), Some(_)) => {
29            return Err(anyhow!(
30                "Package '{}' is installed in both user and system scopes. This is an ambiguous state.",
31                package_name
32            ));
33        }
34        (None, None) => {
35            return Err(anyhow!("Package '{}' is not installed.", package_name));
36        }
37    };
38
39    let pkg_dir = local::get_package_dir(
40        manifest.scope,
41        &manifest.registry_handle,
42        &manifest.repo,
43        &manifest.name,
44    )?;
45    let mut reasons = Vec::new();
46
47    if manifest.reason == types::InstallReason::Direct {
48        reasons.push("it was installed directly by the user".to_string());
49    }
50
51    let mut dependents = local::get_dependents(&pkg_dir)?;
52
53    if !dependents.is_empty() {
54        dependents.sort();
55        reasons.push(format!(
56            "it is a dependency for: {}",
57            dependents.join(", ").cyan()
58        ));
59    }
60
61    if reasons.is_empty() {
62        if matches!(manifest.reason, types::InstallReason::Dependency { .. }) {
63            println!(
64                "Package '{}' is installed as a dependency, but no packages list it as a requirement. It may be an orphan.",
65                package_name.bold()
66            );
67        } else {
68            println!(
69                "Package '{}' is installed, but its installation reason is unclear.",
70                package_name.bold()
71            );
72        }
73    } else {
74        println!(
75            "Package '{}' is installed because {}.",
76            package_name.bold(),
77            reasons.join(" and ")
78        );
79    }
80
81    Ok(())
82}