Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: added "en" command #1697

Merged
merged 3 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/.vitepress/cli_commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ export const commands: { [key: string]: Command } = {
doctor: {
hide: false,
},
en: {
hide: false,
},
env: {
hide: false,
},
Expand Down
38 changes: 38 additions & 0 deletions docs/cli/en.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# `mise en`

- **Usage**: `mise en [-s --shell <SHELL>] [DIR]`
- **Source code**: [`src/cli/en.rs`](https://github.com/jdx/mise/blob/main/src/cli/en.rs)

[experimental] starts a new shell with the mise environment built from the current configuration

This is an alternative to `mise activate` that allows you to explicitly start a mise session.
It will have the tools and environment variables in the configs loaded.
Note that changing directories will not update the mise environment.

## Arguments

### `[DIR]`

Directory to start the shell in

**Default:** `.`

## Flags

### `-s --shell <SHELL>`

Shell to start

Defaults to $SHELL

Examples:

$ mise en .
$ node -v
v20.0.0

Skip loading bashrc:
$ mise en -s "bash --norc"

Skip loading zshrc:
$ mise en -s "zsh -f"
1 change: 1 addition & 0 deletions docs/cli/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ Answer yes to all confirmation prompts
- [`mise direnv <SUBCOMMAND>`](/cli/direnv.md)
- [`mise direnv activate`](/cli/direnv/activate.md)
- [`mise doctor`](/cli/doctor.md)
- [`mise en [-s --shell <SHELL>] [DIR]`](/cli/en.md)
- [`mise env [FLAGS] [TOOL@VERSION]...`](/cli/env.md)
- [`mise exec [FLAGS] [TOOL@VERSION]... [COMMAND]...`](/cli/exec.md)
- [`mise generate <SUBCOMMAND>`](/cli/generate.md)
Expand Down
8 changes: 8 additions & 0 deletions docs/cli/run.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ Print directly to stdout/stderr instead of by line
Defaults to true if --jobs == 1
Configure with `task_output` config or `MISE_TASK_OUTPUT` env var

### `-s --shell <SHELL>`

Shell to use to run toml tasks

Defaults to `sh -c -o errexit -o pipefail` on unix, and `cmd /c` on Windows
Can also be set with the setting `MISE_UNIX_DEFAULT_INLINE_SHELL_ARGS` or `MISE_WINDOWS_DEFAULT_INLINE_SHELL_ARGS`
Or it can be overridden with the `shell` property on a task.

### `-t --tool... <TOOL@VERSION>`

Tool(s) to run in addition to what is in mise.toml files e.g.: node@20 python@3.10
Expand Down
8 changes: 8 additions & 0 deletions docs/cli/tasks/run.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,14 @@ Print directly to stdout/stderr instead of by line
Defaults to true if --jobs == 1
Configure with `task_output` config or `MISE_TASK_OUTPUT` env var

### `-s --shell <SHELL>`

Shell to use to run toml tasks

Defaults to `sh -c -o errexit -o pipefail` on unix, and `cmd /c` on Windows
Can also be set with the setting `MISE_UNIX_DEFAULT_INLINE_SHELL_ARGS` or `MISE_WINDOWS_DEFAULT_INLINE_SHELL_ARGS`
Or it can be overridden with the `shell` property on a task.

### `-t --tool... <TOOL@VERSION>`

Tool(s) to run in addition to what is in mise.toml files e.g.: node@20 python@3.10
Expand Down
3 changes: 3 additions & 0 deletions man/man1/mise.1
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ Output direnv function to use mise inside direnv
mise\-doctor(1)
Check mise installation for possible problems
.TP
mise\-en(1)
[experimental] starts a new shell with the mise environment built from the current configuration
.TP
mise\-env(1)
Exports env vars to activate mise a single time
.TP
Expand Down
35 changes: 35 additions & 0 deletions mise.usage.kdl
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ flag "-p --prefix" hide=true
flag "-P --profile" help="Set the profile (environment)" hide=true global=true {
arg "<PROFILE>"
}
flag "-s --shell" hide=true {
arg "<SHELL>"
}
flag "-t --tool" help="Tool(s) to run in addition to what is in mise.toml files e.g.: node@20 python@3.10" var=true hide=true {
arg "<TOOL@VERSION>"
}
Expand Down Expand Up @@ -343,6 +346,30 @@ cmd "doctor" help="Check mise installation for possible problems" {
[WARN] plugin node is not installed
"
}
cmd "en" help="[experimental] starts a new shell with the mise environment built from the current configuration" {
long_help r"[experimental] starts a new shell with the mise environment built from the current configuration

This is an alternative to `mise activate` that allows you to explicitly start a mise session.
It will have the tools and environment variables in the configs loaded.
Note that changing directories will not update the mise environment."
after_long_help r#"Examples:

$ mise en .
$ node -v
v20.0.0

Skip loading bashrc:
$ mise en -s "bash --norc"

Skip loading zshrc:
$ mise en -s "zsh -f"
"#
flag "-s --shell" help="Shell to start" {
long_help "Shell to start\n\nDefaults to $SHELL"
arg "<SHELL>"
}
arg "[DIR]" help="Directory to start the shell in" default="."
}
cmd "env" help="Exports env vars to activate mise a single time" {
alias "e"
long_help r"Exports env vars to activate mise a single time
Expand Down Expand Up @@ -958,6 +985,10 @@ The name of the script will be the name of the tasks.
flag "-f --force" help="Force the tasks to run even if outputs are up to date"
flag "-p --prefix" help="Print stdout/stderr by line, prefixed with the tasks's label\nDefaults to true if --jobs > 1\nConfigure with `task_output` config or `MISE_TASK_OUTPUT` env var"
flag "-i --interleave" help="Print directly to stdout/stderr instead of by line\nDefaults to true if --jobs == 1\nConfigure with `task_output` config or `MISE_TASK_OUTPUT` env var"
flag "-s --shell" help="Shell to use to run toml tasks" {
long_help "Shell to use to run toml tasks\n\nDefaults to `sh -c -o errexit -o pipefail` on unix, and `cmd /c` on Windows\nCan also be set with the setting `MISE_UNIX_DEFAULT_INLINE_SHELL_ARGS` or `MISE_WINDOWS_DEFAULT_INLINE_SHELL_ARGS`\nOr it can be overridden with the `shell` property on a task."
arg "<SHELL>"
}
flag "-t --tool" help="Tool(s) to run in addition to what is in mise.toml files e.g.: node@20 python@3.10" var=true {
arg "<TOOL@VERSION>"
}
Expand Down Expand Up @@ -1321,6 +1352,10 @@ The name of the script will be the name of the tasks.
flag "-f --force" help="Force the tasks to run even if outputs are up to date"
flag "-p --prefix" help="Print stdout/stderr by line, prefixed with the tasks's label\nDefaults to true if --jobs > 1\nConfigure with `task_output` config or `MISE_TASK_OUTPUT` env var"
flag "-i --interleave" help="Print directly to stdout/stderr instead of by line\nDefaults to true if --jobs == 1\nConfigure with `task_output` config or `MISE_TASK_OUTPUT` env var"
flag "-s --shell" help="Shell to use to run toml tasks" {
long_help "Shell to use to run toml tasks\n\nDefaults to `sh -c -o errexit -o pipefail` on unix, and `cmd /c` on Windows\nCan also be set with the setting `MISE_UNIX_DEFAULT_INLINE_SHELL_ARGS` or `MISE_WINDOWS_DEFAULT_INLINE_SHELL_ARGS`\nOr it can be overridden with the `shell` property on a task."
arg "<SHELL>"
}
flag "-t --tool" help="Tool(s) to run in addition to what is in mise.toml files e.g.: node@20 python@3.10" var=true {
arg "<TOOL@VERSION>"
}
Expand Down
2 changes: 1 addition & 1 deletion schema/mise.json
Original file line number Diff line number Diff line change
Expand Up @@ -664,7 +664,7 @@
}
},
"unix_default_inline_shell_args": {
"default": ["sh", "-c"],
"default": ["sh", "-c", "-o", "errexit"],
"description": "List of default shell arguments for unix to be used with inline commands. For example, `sh`, `-c` for sh.",
"type": "array",
"items": {
Expand Down
2 changes: 1 addition & 1 deletion settings.toml
Original file line number Diff line number Diff line change
Expand Up @@ -885,7 +885,7 @@ description = "List of default shell arguments for unix to be used with `file`.
env = "MISE_UNIX_DEFAULT_INLINE_SHELL_ARGS"
type = "ListString"
rust_type = "Vec<String>"
default = ["sh", "-c"]
default = ["sh", "-c", "-o", "errexit"]
parse_env = "list_by_comma"
description = "List of default shell arguments for unix to be used with inline commands. For example, `sh`, `-c` for sh."

Expand Down
59 changes: 59 additions & 0 deletions src/cli/en.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use crate::cli::exec::Exec;
use crate::config::Settings;
use std::path::PathBuf;

use crate::env;

/// [experimental] starts a new shell with the mise environment built from the current configuration
///
/// This is an alternative to `mise activate` that allows you to explicitly start a mise session.
/// It will have the tools and environment variables in the configs loaded.
/// Note that changing directories will not update the mise environment.
#[derive(Debug, clap::Args)]
#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]
pub struct En {
/// Directory to start the shell in
#[clap(default_value = ".", verbatim_doc_comment, value_hint = clap::ValueHint::DirPath)]
pub dir: PathBuf,

/// Shell to start
///
/// Defaults to $SHELL
#[clap(verbatim_doc_comment, long, short = 's', env = "MISE_SHELL")]
pub shell: Option<String>,
}

impl En {
pub fn run(self) -> eyre::Result<()> {
let settings = Settings::get();
settings.ensure_experimental("en")?;

env::set_current_dir(&self.dir)?;
let shell = self.shell.unwrap_or((*env::SHELL).clone());
let command = shell_words::split(&shell).map_err(|e| eyre::eyre!(e))?;

Exec {
tool: vec![],
raw: false,
jobs: None,
c: None,
command: Some(command),
}
.run()
}
}

static AFTER_LONG_HELP: &str = color_print::cstr!(
r#"<bold><underline>Examples:</underline></bold>

$ <bold>mise en .</bold>
$ <bold>node -v</bold>
v20.0.0

Skip loading bashrc:
$ <bold>mise en -s "bash --norc"</bold>

Skip loading zshrc:
$ <bold>mise en -s "zsh -f"</bold>
"#
);
31 changes: 25 additions & 6 deletions src/cli/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ pub struct Exec {

/// Command string to execute (same as --command)
#[clap(conflicts_with = "c", required_unless_present = "c", last = true)]
pub command: Option<Vec<OsString>>,
pub command: Option<Vec<String>>,

/// Command string to execute
#[clap(short, long = "command", value_hint = ValueHint::CommandString, conflicts_with = "command")]
pub c: Option<OsString>,
pub c: Option<String>,

/// Number of jobs to run in parallel
/// [default: 4]
Expand Down Expand Up @@ -74,9 +74,28 @@ impl Exec {
ts.notify_if_versions_missing()
});

let (program, args) = parse_command(&env::SHELL, &self.command, &self.c);
let (program, mut args) = parse_command(&env::SHELL, &self.command, &self.c);
let env = measure!("env_with_path", { ts.env_with_path(&CONFIG)? });

if program.rsplit('/').next() == Some("fish") {
let mut cmd = vec![];
for (k, v) in env.iter().filter(|(k, _)| *k != "PATH") {
cmd.push(format!(
"set -gx {} {}",
shell_escape::escape(k.into()),
shell_escape::escape(v.into())
));
}
for p in ts.list_final_paths()? {
cmd.push(format!(
"fish_add_path -gm {}",
shell_escape::escape(p.to_string_lossy())
));
}
args.insert(0, cmd.join("\n"));
args.insert(0, "-C".into());
}

time!("exec");
self.exec(program, args, env)
}
Expand Down Expand Up @@ -142,9 +161,9 @@ impl Exec {

fn parse_command(
shell: &str,
command: &Option<Vec<OsString>>,
c: &Option<OsString>,
) -> (OsString, Vec<OsString>) {
command: &Option<Vec<String>>,
c: &Option<String>,
) -> (String, Vec<String>) {
match (&command, &c) {
(Some(command), _) => {
let (program, args) = command.split_first().unwrap();
Expand Down
6 changes: 6 additions & 0 deletions src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ mod current;
mod deactivate;
mod direnv;
mod doctor;
mod en;
mod env;
pub mod exec;
mod external;
Expand Down Expand Up @@ -112,6 +113,8 @@ pub struct Cli {
/// Set the profile (environment)
#[clap(short = 'P', long, global = true, hide = true)]
pub profile: Option<String>,
#[clap(long, short, hide = true)]
pub shell: Option<String>,
/// Tool(s) to run in addition to what is in mise.toml files
/// e.g.: node@20 python@3.10
#[clap(short, long, hide = true, value_name = "TOOL@VERSION")]
Expand Down Expand Up @@ -159,6 +162,7 @@ pub enum Commands {
Deactivate(deactivate::Deactivate),
Direnv(direnv::Direnv),
Doctor(doctor::Doctor),
En(en::En),
Env(env::Env),
Exec(exec::Exec),
Generate(generate::Generate),
Expand Down Expand Up @@ -219,6 +223,7 @@ impl Commands {
Self::Deactivate(cmd) => cmd.run(),
Self::Direnv(cmd) => cmd.run(),
Self::Doctor(cmd) => cmd.run(),
Self::En(cmd) => cmd.run(),
Self::Env(cmd) => cmd.run(),
Self::Exec(cmd) => cmd.run(),
Self::Generate(cmd) => cmd.run(),
Expand Down Expand Up @@ -325,6 +330,7 @@ impl Cli {
no_timings: self.no_timings,
output: run::TaskOutput::Prefix,
prefix: self.prefix,
shell: self.shell,
quiet: self.quiet,
raw: self.raw,
timings: self.timings,
Expand Down
Loading