Skip to content

Commit

Permalink
feat: mise rm
Browse files Browse the repository at this point in the history
Fixes #1465
  • Loading branch information
jdx committed Dec 18, 2024
1 parent 1670ae4 commit 26f703d
Show file tree
Hide file tree
Showing 19 changed files with 264 additions and 64 deletions.
3 changes: 3 additions & 0 deletions docs/.vitepress/cli_commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,9 @@ export const commands: { [key: string]: Command } = {
unset: {
hide: false,
},
unuse: {
hide: false,
},
upgrade: {
hide: false,
},
Expand Down
3 changes: 2 additions & 1 deletion docs/cli/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ Can also use `MISE_NO_CONFIG=1`
- [`mise plugins ls-remote [-u --urls] [--only-names]`](/cli/plugins/ls-remote.md)
- [`mise plugins uninstall [-p --purge] [-a --all] [PLUGIN]...`](/cli/plugins/uninstall.md)
- [`mise plugins update [-j --jobs <JOBS>] [PLUGIN]...`](/cli/plugins/update.md)
- [`mise prune [FLAGS] [PLUGIN]...`](/cli/prune.md)
- [`mise prune [FLAGS] [INSTALLED_TOOL]...`](/cli/prune.md)
- [`mise registry [-b --backend <BACKEND>] [--hide-aliased] [NAME]`](/cli/registry.md)
- [`mise reshim [-f --force]`](/cli/reshim.md)
- [`mise run [FLAGS]`](/cli/run.md)
Expand Down Expand Up @@ -129,6 +129,7 @@ Can also use `MISE_NO_CONFIG=1`
- [`mise trust [FLAGS] [CONFIG_FILE]`](/cli/trust.md)
- [`mise uninstall [-a --all] [-n --dry-run] [INSTALLED_TOOL@VERSION]...`](/cli/uninstall.md)
- [`mise unset [-f --file <FILE>] [-g --global] [KEYS]...`](/cli/unset.md)
- [`mise unuse [--no-prune] [--global] <INSTALLED_TOOL@VERSION>...`](/cli/unuse.md)
- [`mise upgrade [FLAGS] [TOOL@VERSION]...`](/cli/upgrade.md)
- [`mise use [FLAGS] [TOOL@VERSION]...`](/cli/use.md)
- [`mise version`](/cli/version.md)
Expand Down
6 changes: 3 additions & 3 deletions docs/cli/prune.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# `mise prune`

- **Usage**: `mise prune [FLAGS] [PLUGIN]...`
- **Usage**: `mise prune [FLAGS] [INSTALLED_TOOL]...`
- **Source code**: [`src/cli/prune.rs`](https://github.com/jdx/mise/blob/main/src/cli/prune.rs)

Delete unused versions of tools
Expand All @@ -12,9 +12,9 @@ as will versions only referenced on the command line `mise exec <PLUGIN>@<VERSIO

## Arguments

### `[PLUGIN]...`
### `[INSTALLED_TOOL]...`

Prune only versions from this plugin(s)
Prune only these tools

## Flags

Expand Down
1 change: 0 additions & 1 deletion docs/cli/uninstall.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# `mise uninstall`

- **Usage**: `mise uninstall [-a --all] [-n --dry-run] [INSTALLED_TOOL@VERSION]...`
- **Aliases**: `remove`, `rm`
- **Source code**: [`src/cli/uninstall.rs`](https://github.com/jdx/mise/blob/main/src/cli/uninstall.rs)

Removes installed tool versions
Expand Down
32 changes: 32 additions & 0 deletions docs/cli/unuse.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# `mise unuse`

- **Usage**: `mise unuse [--no-prune] [--global] <INSTALLED_TOOL@VERSION>...`
- **Aliases**: `rm`, `remove`
- **Source code**: [`src/cli/unuse.rs`](https://github.com/jdx/mise/blob/main/src/cli/unuse.rs)

Removes installed tool versions from mise.toml

Will also prune the installed version if no other configurations are using it.

## Arguments

### `<INSTALLED_TOOL@VERSION>...`

Tool(s) to remove

## Flags

### `--no-prune`

Do not also prune the installed version

### `--global`

Remove tool from global config

Examples:

```
# will uninstall specific version
$ mise remove node@18.0.0
```
22 changes: 22 additions & 0 deletions e2e/cli/test_unuse
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env bash

assert "mise use dummy@1.0.0"
assert_contains "mise ls dummy" "1.0.0"
assert "mise unuse dummy"
assert_empty "mise ls dummy"

assert "mise use dummy@1.0.0"
mkdir subdir
cd subdir || exit 1
assert "mise use -p mise.toml dummy@1.0.0"
assert "mise ls dummy" "dummy 1.0.0 ~/workdir/subdir/mise.toml 1.0.0"
assert "mise unuse dummy"
# version is not pruned because it's in ~/workdir/mise.toml
assert "mise ls dummy" "dummy 1.0.0 ~/workdir/mise.toml 1.0.0"
assert "mise unuse dummy"
assert_empty "mise ls dummy"

assert "mise use -g dummy@1.0.0"
assert "mise ls dummy" "dummy 1.0.0 ~/.config/mise/config.toml 1.0.0"
assert "mise unuse dummy"
assert_empty "mise ls dummy"
3 changes: 3 additions & 0 deletions man/man1/mise.1
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,9 @@ Removes installed tool versions
mise\-unset(1)
Remove environment variable(s) from the config file.
.TP
mise\-unuse(1)
Removes installed tool versions from mise.toml
.TP
mise\-upgrade(1)
Upgrades outdated tools
.TP
Expand Down
17 changes: 15 additions & 2 deletions mise.usage.kdl
Original file line number Diff line number Diff line change
Expand Up @@ -922,7 +922,7 @@ as will versions only referenced on the command line `mise exec <PLUGIN>@<VERSIO
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"
flag "--tools" help="Prune only unused versions of tools"
arg "[PLUGIN]..." help="Prune only versions from this plugin(s)" required=false var=true
arg "[INSTALLED_TOOL]..." help="Prune only these tools" required=false var=true
}
cmd "registry" help="List available tools to install" {
long_help r"List available tools to install
Expand Down Expand Up @@ -1554,7 +1554,6 @@ This includes:
arg "[CONFIG_FILE]" help="The config file to trust" required=false
}
cmd "uninstall" help="Removes installed tool versions" {
alias "remove" "rm"
long_help r"Removes installed tool versions

This only removes the installed version, it does not modify mise.toml."
Expand Down Expand Up @@ -1591,6 +1590,20 @@ By default, this command modifies `mise.toml` in the current directory."
flag "-g --global" help="Use the global config file"
arg "[KEYS]..." help="Environment variable(s) to remove\ne.g.: NODE_ENV" required=false var=true
}
cmd "unuse" help="Removes installed tool versions from mise.toml" {
alias "rm" "remove"
long_help r"Removes installed tool versions from mise.toml

Will also prune the installed version if no other configurations are using it."
after_long_help r"Examples:

# will uninstall specific version
$ mise remove node@18.0.0
"
flag "--no-prune" help="Do not also prune the installed version"
flag "--global" help="Remove tool from global config"
arg "<INSTALLED_TOOL@VERSION>..." help="Tool(s) to remove" var=true
}
cmd "upgrade" help="Upgrades outdated tools" {
alias "up"
long_help r"Upgrades outdated tools
Expand Down
2 changes: 1 addition & 1 deletion src/cli/local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ pub fn local(

if let Some(plugins) = &remove {
for plugin in plugins {
cf.remove_plugin(plugin)?;
cf.remove_tool(plugin)?;
}
let tools = plugins
.iter()
Expand Down
3 changes: 3 additions & 0 deletions src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ mod tool;
mod trust;
mod uninstall;
mod unset;
mod unuse;
mod upgrade;
mod usage;
mod r#use;
Expand Down Expand Up @@ -222,6 +223,7 @@ pub enum Commands {
Trust(trust::Trust),
Uninstall(uninstall::Uninstall),
Unset(unset::Unset),
Unuse(unuse::Unuse),
Upgrade(upgrade::Upgrade),
Usage(usage::Usage),
Use(r#use::Use),
Expand Down Expand Up @@ -284,6 +286,7 @@ impl Commands {
Self::Trust(cmd) => cmd.run(),
Self::Uninstall(cmd) => cmd.run(),
Self::Unset(cmd) => cmd.run(),
Self::Unuse(cmd) => cmd.run(),
Self::Upgrade(cmd) => cmd.run(),
Self::Usage(cmd) => cmd.run(),
Self::Use(cmd) => cmd.run(),
Expand Down
79 changes: 40 additions & 39 deletions src/cli/prune.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::collections::BTreeMap;
use std::sync::Arc;

use crate::backend::Backend;
use crate::cli::args::BackendArg;
use crate::cli::args::{BackendArg, ToolArg};
use crate::config::tracking::Tracker;
use crate::config::{Config, SETTINGS};
use crate::toolset::{ToolVersion, Toolset, ToolsetBuilder};
Expand All @@ -22,9 +22,9 @@ use super::trust::Trust;
#[derive(Debug, clap::Args)]
#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]
pub struct Prune {
/// Prune only versions from this plugin(s)
/// Prune only these tools
#[clap()]
pub plugin: Option<Vec<BackendArg>>,
pub installed_tool: Option<Vec<ToolArg>>,

/// Do not actually delete anything
#[clap(long, short = 'n')]
Expand All @@ -45,7 +45,11 @@ impl Prune {
self.prune_configs()?;
}
if self.tools || !self.configs {
self.prune_tools()?;
let backends = self
.installed_tool
.as_ref()
.map(|it| it.iter().map(|ta| &ta.ba).collect());
prune(backends.unwrap_or_default(), self.dry_run)?;
}
Ok(())
}
Expand All @@ -60,49 +64,46 @@ impl Prune {
}
Ok(())
}
}

fn prune_tools(&self) -> Result<()> {
let config = Config::try_get()?;
let ts = ToolsetBuilder::new().build(&config)?;
let mut to_delete = ts
.list_installed_versions()?
.into_iter()
.map(|(p, tv)| ((tv.ba().short.to_string(), tv.tv_pathname()), (p, tv)))
.collect::<BTreeMap<(String, String), (Arc<dyn Backend>, ToolVersion)>>();
pub fn prune(tools: Vec<&BackendArg>, dry_run: bool) -> Result<()> {
let config = Config::try_get()?;
let ts = ToolsetBuilder::new().build(&config)?;
let mut to_delete = ts
.list_installed_versions()?
.into_iter()
.map(|(p, tv)| ((tv.ba().short.to_string(), tv.tv_pathname()), (p, tv)))
.collect::<BTreeMap<(String, String), (Arc<dyn Backend>, ToolVersion)>>();

if let Some(backends) = &self.plugin {
to_delete.retain(|_, (_, tv)| backends.contains(tv.ba()));
}
if !tools.is_empty() {
to_delete.retain(|_, (_, tv)| tools.contains(&tv.ba()));
}

for cf in config.get_tracked_config_files()?.values() {
let mut ts = Toolset::from(cf.to_tool_request_set()?);
ts.resolve()?;
for (_, tv) in ts.list_current_versions() {
to_delete.remove(&(tv.ba().short.to_string(), tv.tv_pathname()));
}
for cf in config.get_tracked_config_files()?.values() {
let mut ts = Toolset::from(cf.to_tool_request_set()?);
ts.resolve()?;
for (_, tv) in ts.list_current_versions() {
to_delete.remove(&(tv.ba().short.to_string(), tv.tv_pathname()));
}

self.delete(to_delete.into_values().collect())
}

fn delete(&self, to_delete: Vec<(Arc<dyn Backend>, ToolVersion)>) -> Result<()> {
let mpr = MultiProgressReport::get();
for (p, tv) in to_delete {
let mut prefix = tv.style();
if self.dry_run {
prefix = format!("{} {} ", prefix, style("[dryrun]").bold());
}
let pr = mpr.add(&prefix);
if self.dry_run
|| SETTINGS.yes
|| prompt::confirm_with_all(format!("remove {} ?", &tv))?
{
p.uninstall_version(&tv, pr.as_ref(), self.dry_run)?;
pr.finish();
}
delete(dry_run, to_delete.into_values().collect())
}

fn delete(dry_run: bool, to_delete: Vec<(Arc<dyn Backend>, ToolVersion)>) -> Result<()> {
let mpr = MultiProgressReport::get();
for (p, tv) in to_delete {
let mut prefix = tv.style();
if dry_run {
prefix = format!("{} {} ", prefix, style("[dryrun]").bold());
}
let pr = mpr.add(&prefix);
if dry_run || SETTINGS.yes || prompt::confirm_with_all(format!("remove {} ?", &tv))? {
p.uninstall_version(&tv, pr.as_ref(), dry_run)?;
pr.finish();
}
Ok(())
}
Ok(())
}

static AFTER_LONG_HELP: &str = color_print::cstr!(
Expand Down
2 changes: 1 addition & 1 deletion src/cli/uninstall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::{config, dirs, file};
///
/// This only removes the installed version, it does not modify mise.toml.
#[derive(Debug, clap::Args)]
#[clap(verbatim_doc_comment, visible_aliases = ["remove", "rm"], after_long_help = AFTER_LONG_HELP)]
#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]
pub struct Uninstall {
/// Tool(s) to remove
#[clap(value_name = "INSTALLED_TOOL@VERSION", required_unless_present = "all")]
Expand Down
Loading

0 comments on commit 26f703d

Please sign in to comment.