Skip to main content

oxi/cli/commands/
pkg.rs

1//! Package subcommand handler.
2
3use crate::cli::PkgCommands;
4use crate::storage::packages::PackageManager;
5use anyhow::Result;
6
7/// Handle `oxi pkg …` subcommands.
8pub fn handle_pkg(action: &PkgCommands) -> Result<()> {
9    let mut mgr = PackageManager::new()?;
10
11    match action {
12        PkgCommands::Install { source } => {
13            if source.starts_with("npm:") {
14                let name = source
15                    .strip_prefix("npm:")
16                    .ok_or_else(|| anyhow::anyhow!("Invalid npm source format: {}", source))?;
17                let manifest = mgr.install_npm(name)?;
18                let counts = mgr.resource_counts(&manifest.name).unwrap_or_default();
19                println!(
20                    "Installed {} v{} ({})",
21                    manifest.name, manifest.version, counts
22                );
23            } else {
24                let manifest = mgr.install(source)?;
25                let counts = mgr.resource_counts(&manifest.name).unwrap_or_default();
26                println!(
27                    "Installed {} v{} ({})",
28                    manifest.name, manifest.version, counts
29                );
30            }
31        }
32        PkgCommands::List => {
33            let packages = mgr.list();
34            if packages.is_empty() {
35                println!("No packages installed.");
36            } else {
37                println!(
38                    "{:<30} {:<10} {:<15} INSTALL DIR",
39                    "NAME", "VERSION", "RESOURCES"
40                );
41                println!("{:-<30} {:-<10} {:-<15} {:-<40}", "", "", "", "");
42                for pkg in packages {
43                    let counts = mgr.resource_counts(&pkg.name).unwrap_or_default();
44                    let install_dir = mgr
45                        .get_install_dir(&pkg.name)
46                        .map(|d| d.display().to_string())
47                        .unwrap_or_else(|| "-".to_string());
48                    println!(
49                        "{:<30} {:<10} {:<15} {}",
50                        pkg.name, pkg.version, counts, install_dir
51                    );
52
53                    // Show discovered resources
54                    if let Ok(resources) = mgr.discover_resources(&pkg.name) {
55                        for r in &resources {
56                            println!("    {} {}", r.kind, r.relative_path);
57                        }
58                    }
59                }
60            }
61        }
62        PkgCommands::Uninstall { name } => {
63            mgr.uninstall(name)?;
64            println!("Uninstalled {}", name);
65        }
66        PkgCommands::Update { name } => match name {
67            Some(pkg_name) => {
68                let manifest = mgr.update(pkg_name)?;
69                println!("Updated {} to v{}", manifest.name, manifest.version);
70            }
71            None => {
72                let packages: Vec<String> = mgr.list().iter().map(|p| p.name.clone()).collect();
73                if packages.is_empty() {
74                    println!("No packages to update.");
75                } else {
76                    for pkg_name in &packages {
77                        match mgr.update(pkg_name) {
78                            Ok(manifest) => {
79                                println!("Updated {} to v{}", manifest.name, manifest.version);
80                            }
81                            Err(e) => {
82                                eprintln!(
83                                    "{}",
84                                    crate::print_mode::format_error(&format!(
85                                        "Failed to update {}: {}",
86                                        pkg_name, e
87                                    ))
88                                );
89                            }
90                        }
91                    }
92                }
93            }
94        },
95    }
96
97    Ok(())
98}