From 1db6945064e12aee243b2725aa4998f95a7c4c7f Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sat, 11 Jan 2025 16:21:54 -0600 Subject: [PATCH] feat: added `mise ls --prunable` flag (#4062) --- docs/cli/ls.md | 4 ++++ docs/cli/prune.md | 2 ++ e2e/cli/test_ls | 3 +++ mise.usage.kdl | 3 ++- src/cli/ls.rs | 18 +++++++++++++++++- src/cli/prune.rs | 11 +++++++++-- xtasks/fig/src/mise.ts | 5 +++++ 7 files changed, 42 insertions(+), 4 deletions(-) diff --git a/docs/cli/ls.md b/docs/cli/ls.md index 6befafea7d..d5b8d9351e 100644 --- a/docs/cli/ls.md +++ b/docs/cli/ls.md @@ -52,6 +52,10 @@ Display missing tool versions Display versions matching this prefix +### `--prunable` + +List only tools that can be pruned with `mise prune` + ### `--no-header` Don't display headers diff --git a/docs/cli/prune.md b/docs/cli/prune.md index 48c37a4531..140fce103b 100644 --- a/docs/cli/prune.md +++ b/docs/cli/prune.md @@ -10,6 +10,8 @@ Versions which are no longer the latest specified in any of those configs are de Versions installed only with environment variables `MISE__VERSION` will be deleted, as will versions only referenced on the command line `mise exec @`. +You can list prunable tools with `mise ls --prunable` + ## Arguments ### `[INSTALLED_TOOL]...` diff --git a/e2e/cli/test_ls b/e2e/cli/test_ls index fa840148e0..9e9823cef8 100644 --- a/e2e/cli/test_ls +++ b/e2e/cli/test_ls @@ -34,3 +34,6 @@ mise use cargo-binstall mise i cargo:usage-cli assert_contains "mise ls" "cargo:usage-cli" assert_not_contains "mise ls" "cargo-usage-cli" # if the backend meta file isn't working right these will be displayed + +assert "mise ls --prunable" "cargo:usage-cli 2.0.3 +tiny 2.0.0" diff --git a/mise.usage.kdl b/mise.usage.kdl index a45a118f61..4a26cc9124 100644 --- a/mise.usage.kdl +++ b/mise.usage.kdl @@ -458,6 +458,7 @@ cmd ls help="List installed and active tool versions" { flag --prefix help="Display versions matching this prefix" { arg } + flag --prunable help="List only tools that can be pruned with `mise prune`" flag --no-header help="Don't display headers" arg "[INSTALLED_TOOL]..." help="Only show tool versions from [TOOL]" required=#false var=#true } @@ -544,7 +545,7 @@ cmd plugins help="Manage plugins" { } } cmd prune help="Delete unused versions of tools" { - long_help "Delete unused versions of tools\n\nmise tracks which config files have been used in ~/.local/state/mise/tracked-configs\nVersions which are no longer the latest specified in any of those configs are deleted.\nVersions installed only with environment variables `MISE__VERSION` will be deleted,\nas will versions only referenced on the command line `mise exec @`." + long_help "Delete unused versions of tools\n\nmise tracks which config files have been used in ~/.local/state/mise/tracked-configs\nVersions which are no longer the latest specified in any of those configs are deleted.\nVersions installed only with environment variables `MISE__VERSION` will be deleted,\nas will versions only referenced on the command line `mise exec @`.\n\nYou can list prunable tools with `mise ls --prunable`" after_long_help "Examples:\n\n $ mise prune --dry-run\n rm -rf ~/.local/share/mise/versions/node/20.0.0\n rm -rf ~/.local/share/mise/versions/node/20.0.1\n" flag "-n --dry-run" help="Do not actually delete anything" flag --configs help="Prune only tracked and trusted configuration links that point to non-existent configurations" diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 4646d5fb64..563250c55b 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -10,6 +10,7 @@ use versions::Versioning; use crate::backend::Backend; use crate::cli::args::BackendArg; +use crate::cli::prune; use crate::config; use crate::config::Config; use crate::toolset::{ToolSource, ToolVersion, Toolset}; @@ -65,6 +66,10 @@ pub struct Ls { #[clap(long, requires = "installed_tool")] prefix: Option, + /// List only tools that can be pruned with `mise prune` + #[clap(long)] + prunable: bool, + /// Don't display headers #[clap(long, alias = "no-headers", verbatim_doc_comment, conflicts_with_all = &["json"])] no_header: bool, @@ -78,7 +83,11 @@ impl Ls { .or_else(|| self.tool_flag.clone().map(|p| vec![p])); self.verify_plugin()?; - let mut runtimes = self.get_runtime_list(&config)?; + let mut runtimes = if self.prunable { + self.get_prunable_runtime_list()? + } else { + self.get_runtime_list(&config)? + }; if self.current || self.global { // TODO: global is a little weird: it will show global versions as the active ones even if // they're overridden locally @@ -165,6 +174,13 @@ impl Ls { table.truncate(true).print() } + fn get_prunable_runtime_list(&self) -> Result> { + let installed_tool = self.installed_tool.clone().unwrap_or_default(); + Ok(prune::prunable_tools(installed_tool.iter().collect())? + .into_iter() + .map(|(p, tv)| (self, p, tv, ToolSource::Unknown)) + .collect()) + } fn get_runtime_list(&self, config: &Config) -> Result> { let mut trs = config.get_tool_request_set()?.clone(); if self.global { diff --git a/src/cli/prune.rs b/src/cli/prune.rs index 029fb7a3ae..1a58d94742 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -19,6 +19,8 @@ use super::trust::Trust; /// Versions which are no longer the latest specified in any of those configs are deleted. /// Versions installed only with environment variables `MISE__VERSION` will be deleted, /// as will versions only referenced on the command line `mise exec @`. +/// +/// You can list prunable tools with `mise ls --prunable` #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Prune { @@ -66,7 +68,7 @@ impl Prune { } } -pub fn prune(tools: Vec<&BackendArg>, dry_run: bool) -> Result<()> { +pub fn prunable_tools(tools: Vec<&BackendArg>) -> Result, ToolVersion)>> { let config = Config::try_get()?; let ts = ToolsetBuilder::new().build(&config)?; let mut to_delete = ts @@ -87,7 +89,12 @@ pub fn prune(tools: Vec<&BackendArg>, dry_run: bool) -> Result<()> { } } - delete(dry_run, to_delete.into_values().collect()) + Ok(to_delete.into_values().collect()) +} + +pub fn prune(tools: Vec<&BackendArg>, dry_run: bool) -> Result<()> { + let to_delete = prunable_tools(tools)?; + delete(dry_run, to_delete) } fn delete(dry_run: bool, to_delete: Vec<(Arc, ToolVersion)>) -> Result<()> { diff --git a/xtasks/fig/src/mise.ts b/xtasks/fig/src/mise.ts index f1ad71a673..b9b6831bca 100644 --- a/xtasks/fig/src/mise.ts +++ b/xtasks/fig/src/mise.ts @@ -1361,6 +1361,11 @@ const completionSpec: Fig.Spec = { debounce: true, }, }, + { + name: "--prunable", + description: "List only tools that can be pruned with `mise prune`", + isRepeatable: false, + }, { name: "--no-header", description: "Don't display headers",