diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-08-07 16:19:51 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-08-09 02:56:28 +0800 |
| commit | 8c88a6c170b3429c90efa96c5f3dcb0a3e9988ae (patch) | |
| tree | 323441a4da274bae111f7563e60516d875a7db10 /mingling_cli/src/pkg_mgr/cmd_internal_loadpkgs.rs | |
| parent | 25ece73e61cd5a9076c63fe884c84a86b35b5b42 (diff) | |
feat(pkg-mgr): implement pkg-show command
Add `pkg-show` to display installed packages and their versions,
removing its NOT_IMPL marker from help. Include internal commands
to load enabled package paths and completion scripts.
Diffstat (limited to 'mingling_cli/src/pkg_mgr/cmd_internal_loadpkgs.rs')
| -rw-r--r-- | mingling_cli/src/pkg_mgr/cmd_internal_loadpkgs.rs | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/mingling_cli/src/pkg_mgr/cmd_internal_loadpkgs.rs b/mingling_cli/src/pkg_mgr/cmd_internal_loadpkgs.rs new file mode 100644 index 0000000..b4928ce --- /dev/null +++ b/mingling_cli/src/pkg_mgr/cmd_internal_loadpkgs.rs @@ -0,0 +1,104 @@ +use std::{ + fs, io, + path::{Path, PathBuf}, +}; + +use mingling::{ + Routable, + macros::{buffer, command, pack, r_println, renderer, routeify}, +}; + +use crate::{ + Next, + pkg_mgr::{ErrorNoDataDirectory, ResPackagesDir}, +}; + +// Version directory paths of every enabled package. +pack!(ResultLoadPkgsPaths = Vec<PathBuf>); + +// Completion script paths of every enabled package. +pack!(ResultLoadPkgsComps = Vec<PathBuf>); + +#[command(node = "__loadpkgs_path", routeify)] +pub fn load_packages_paths(packages_dir: &ResPackagesDir) -> Next { + let packages_dir = &packages_dir.path; + if packages_dir.as_os_str().is_empty() { + return ErrorNoDataDirectory::default().to_chain(); + } + let paths = enabled_version_dirs(packages_dir).map_err(|e| { + io::Error::new( + e.kind(), + format!("failed to read {}: {e}", packages_dir.display()), + ) + })?; + ResultLoadPkgsPaths::new(paths).to_chain() +} + +#[command(node = "__loadpkgs_comp_scripts", routeify)] +pub fn load_packages_comp_scripts(packages_dir: &ResPackagesDir) -> Next { + let packages_dir = &packages_dir.path; + if packages_dir.as_os_str().is_empty() { + return ErrorNoDataDirectory::default().to_chain(); + } + let scripts = comp_scripts(packages_dir).map_err(|e| { + io::Error::new( + e.kind(), + format!("failed to read {}: {e}", packages_dir.display()), + ) + })?; + ResultLoadPkgsComps::new(scripts).to_chain() +} + +#[renderer(buffer)] +pub fn render_result_load_pkgs_paths(r: ResultLoadPkgsPaths) { + for path in r.inner { + r_println!("{}", path.display()); + } +} + +#[renderer(buffer)] +pub fn render_result_load_pkgs_comps(r: ResultLoadPkgsComps) { + for path in r.inner { + r_println!("{}", path.display()); + } +} + +/// Version directories of every enabled package. +/// +/// An enable file is a `name` file (no `@`) whose content is the enabled version. +fn enabled_version_dirs(packages_dir: &Path) -> Result<Vec<PathBuf>, io::Error> { + let mut dirs = Vec::new(); + for entry in fs::read_dir(packages_dir)? { + let entry = entry?; + if !entry.file_type().is_ok_and(|t| t.is_file()) { + continue; + } + let name = entry.file_name().to_string_lossy().into_owned(); + if name.contains('@') { + continue; + } + let version = fs::read_to_string(entry.path())?; + dirs.push(packages_dir.join(format!("{name}@{}", version.trim()))); + } + dirs.sort(); + Ok(dirs) +} + +/// Completion scripts inside every enabled version directory. +fn comp_scripts(packages_dir: &Path) -> Result<Vec<PathBuf>, io::Error> { + let mut scripts = Vec::new(); + for dir in enabled_version_dirs(packages_dir)? { + if !dir.is_dir() { + continue; + } + for entry in fs::read_dir(&dir)? { + let entry = entry?; + let name = entry.file_name().to_string_lossy().into_owned(); + if name.contains("_comp") { + scripts.push(entry.path()); + } + } + } + scripts.sort(); + Ok(scripts) +} |
