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