Skip to content

Commit

Permalink
feat: mise install-into (#3711)
Browse files Browse the repository at this point in the history
Fixes #1039
  • Loading branch information
jdx authored Dec 19, 2024
1 parent 211d3d3 commit ccac508
Show file tree
Hide file tree
Showing 11 changed files with 144 additions and 1 deletion.
3 changes: 3 additions & 0 deletions docs/.vitepress/cli_commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ export const commands: { [key: string]: Command } = {
install: {
hide: false,
},
"install-into": {
hide: false,
},
latest: {
hide: false,
},
Expand Down
1 change: 1 addition & 0 deletions docs/cli/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ Can also use `MISE_NO_CONFIG=1`
- [`mise generate task-docs [FLAGS]`](/cli/generate/task-docs.md)
- [`mise implode [--config] [-n --dry-run]`](/cli/implode.md)
- [`mise install [FLAGS] [TOOL@VERSION]...`](/cli/install.md)
- [`mise install-into <TOOL@VERSION> <PATH>`](/cli/install-into.md)
- [`mise latest [-i --installed] <TOOL@VERSION>`](/cli/latest.md)
- [`mise link [-f --force] <TOOL@VERSION> <PATH>`](/cli/link.md)
- [`mise ls [FLAGS] [PLUGIN]...`](/cli/ls.md)
Expand Down
26 changes: 26 additions & 0 deletions docs/cli/install-into.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# `mise install-into`

- **Usage**: `mise install-into <TOOL@VERSION> <PATH>`
- **Source code**: [`src/cli/install-into.rs`](https://github.com/jdx/mise/blob/main/src/cli/install-into.rs)

Install a tool version to a specific path

Used for building a tool to a directory for use outside of mise

## Arguments

### `<TOOL@VERSION>`

Tool to install e.g.: node@20

### `<PATH>`

Path to install the tool into

Examples:

```
# install node@20.0.0 into ./mynode
$ mise install-into node@20.0.0 ./mynode && ./mynode/bin/node -v
20.0.0
```
4 changes: 4 additions & 0 deletions e2e/cli/test_install_into
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env bash

assert "mise install-into node@22.0.0 ./mynode"
assert "./mynode/bin/node -v" "v22.0.0"
3 changes: 3 additions & 0 deletions man/man1/mise.1
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ Removes mise CLI and all related data
mise\-install(1)
Install a tool version
.TP
mise\-install\-into(1)
Install a tool version to a specific path
.TP
mise\-latest(1)
Gets the latest available version for a plugin
.TP
Expand Down
13 changes: 13 additions & 0 deletions mise.usage.kdl
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,19 @@ Tools will be installed in parallel. To disable, set `--jobs=1` or `MISE_JOBS=1`
}
arg "[TOOL@VERSION]..." help="Tool(s) to install e.g.: node@20" required=false var=true
}
cmd "install-into" help="Install a tool version to a specific path" {
long_help r"Install a tool version to a specific path

Used for building a tool to a directory for use outside of mise"
after_long_help r"Examples:

# install node@20.0.0 into ./mynode
$ mise install-into node@20.0.0 ./mynode && ./mynode/bin/node -v
20.0.0
"
arg "<TOOL@VERSION>" help="Tool to install e.g.: node@20"
arg "<PATH>" help="Path to install the tool into"
}
cmd "latest" help="Gets the latest available version for a plugin" {
long_help r"Gets the latest available version for a plugin

Expand Down
5 changes: 4 additions & 1 deletion src/backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,10 @@ pub trait Backend: Debug + Send + Sync {
}
};

install_state::write_backend_meta(self.ba())?;
if tv.install_path().starts_with(*dirs::INSTALLS) {
// this will be false only for `install-into`
install_state::write_backend_meta(self.ba())?;
}

self.cleanup_install_dirs(&tv);
// attempt to touch all the .tool-version files to trigger updates in hook-env
Expand Down
60 changes: 60 additions & 0 deletions src/cli/install_into.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use crate::cli::args::ToolArg;
use crate::config::Config;
use crate::install_context::InstallContext;
use crate::toolset::ToolsetBuilder;
use crate::ui::multi_progress_report::MultiProgressReport;
use clap::ValueHint;
use eyre::{eyre, Result};
use std::path::PathBuf;

/// Install a tool version to a specific path
///
/// Used for building a tool to a directory for use outside of mise
#[derive(Debug, clap::Args)]
#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]
pub struct InstallInto {
/// Tool to install
/// e.g.: node@20
#[clap(value_name = "TOOL@VERSION")]
tool: ToolArg,

/// Path to install the tool into
#[clap(value_hint = ValueHint::DirPath)]
path: PathBuf,
}

impl InstallInto {
pub fn run(self) -> Result<()> {
let config = Config::get();
let ts = ToolsetBuilder::new()
.with_args(&[self.tool.clone()])
.build(&config)?;
let mut tv = ts
.versions
.get(&self.tool.ba)
.ok_or_else(|| eyre!("Tool not found"))?
.versions
.first()
.unwrap()
.clone();
let backend = tv.backend()?;
let mpr = MultiProgressReport::get();
let install_ctx = InstallContext {
ts: &ts,
pr: mpr.add(&tv.style()),
force: true,
};
tv.install_path = Some(self.path.clone());
backend.install_version(install_ctx, tv)?;
Ok(())
}
}

static AFTER_LONG_HELP: &str = color_print::cstr!(
r#"<bold><underline>Examples:</underline></bold>
# install node@20.0.0 into ./mynode
$ <bold>mise install-into node@20.0.0 ./mynode && ./mynode/bin/node -v</bold>
20.0.0
"#
);
3 changes: 3 additions & 0 deletions src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ mod hook_env;
mod hook_not_found;
mod implode;
mod install;
mod install_into;
mod latest;
mod link;
mod local;
Expand Down Expand Up @@ -204,6 +205,7 @@ pub enum Commands {
HookNotFound(hook_not_found::HookNotFound),
Implode(implode::Implode),
Install(install::Install),
InstallInto(install_into::InstallInto),
Latest(latest::Latest),
Link(link::Link),
Local(local::Local),
Expand Down Expand Up @@ -267,6 +269,7 @@ impl Commands {
Self::HookNotFound(cmd) => cmd.run(),
Self::Implode(cmd) => cmd.run(),
Self::Install(cmd) => cmd.run(),
Self::InstallInto(cmd) => cmd.run(),
Self::Latest(cmd) => cmd.run(),
Self::Link(cmd) => cmd.run(),
Self::Local(cmd) => cmd.run(),
Expand Down
5 changes: 5 additions & 0 deletions src/toolset/tool_version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub struct ToolVersion {
pub request: ToolRequest,
pub version: String,
pub checksums: BTreeMap<String, String>,
pub install_path: Option<PathBuf>,
}

impl ToolVersion {
Expand All @@ -31,6 +32,7 @@ impl ToolVersion {
request,
version,
checksums: Default::default(),
install_path: None,
}
}

Expand Down Expand Up @@ -77,6 +79,9 @@ impl ToolVersion {
}

pub fn install_path(&self) -> PathBuf {
if let Some(p) = &self.install_path {
return p.clone();
}
let pathname = match &self.request {
ToolRequest::Path { path: p, .. } => p.to_string_lossy().to_string(),
_ => self.tv_pathname(),
Expand Down
22 changes: 22 additions & 0 deletions xtasks/fig/src/mise.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1324,6 +1324,28 @@ const completionSpec: Fig.Spec = {
}
]
},
{
"name": [
"install-into"
],
"description": "Install a tool version to a specific path",
"args": [
{
"name": "tool@version",
"description": "Tool to install e.g.: node@20",
"isOptional": false,
"isVariadic": false,
"generators": toolVersionGenerator
},
{
"name": "path",
"description": "Path to install the tool into",
"isOptional": false,
"isVariadic": false,
"template": "filepaths"
}
]
},
{
"name": [
"latest"
Expand Down

0 comments on commit ccac508

Please sign in to comment.