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

fix: remove shims directory in mise activate #3232

Merged
merged 3 commits into from
Nov 27, 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
17 changes: 12 additions & 5 deletions docs/dev-tools/shims.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,26 +46,33 @@ If you prefer to use shims, you can run the following to use mise without activa

You can use `.bashrc`/`.zshrc` instead of `.bash_profile`/`.zprofile` if you prefer to only use
mise in interactive sessions (`.bash_profile`/`.zprofile` will work in non-interactive places
like scripts or IDEs).
like scripts or IDEs). Note that `mise activate` will remove the shims directory so it's fine
to call `mise activate --shims` in the profile file then later call `mise activate` in an interactive
session.

::: code-group

```sh [bash]
# note that bash will read from ~/.profile or ~/.bash_profile if the latter exists
# ergo, you may want to check to see which is defined on your system and only append to the existing file
echo 'export PATH="$HOME/.local/share/mise/shims:$PATH"' >> ~/.bash_profile
echo 'eval "$(mise activate bash --shims)"' >> ~/.bash_profile # this sets up non-interactive sessions
echo 'eval "$(mise activate bash)"' >> ~/.bashrc # this sets up interactive sessions
```

```sh [zsh]
echo 'export PATH="$HOME/.local/share/mise/shims:$PATH"' >> ~/.zprofile
echo 'eval "$(mise activate zsh --shims)"' >> ~/.zprofile # this sets up non-interactive sessions
echo 'eval "$(mise activate zsh)"' >> ~/.zshrc # this sets up interactive sessions
```

```sh [fish]
fish_add_path ~/.local/share/mise/shims
echo 'mise activate fish --shims | source' >> ~/.config/fish/config.fish
echo 'mise activate fish | source' >> ~/.config/fish/fish.config
```

:::tip
You can also run `mise activate --shims` which will do the above for you.
You can also run `export PATH="$HOME/.local/share/mise/shims:$PATH"` which is what `mise activate --shims` does.
This can be helpful is mise may not be available at that point in time. It's also a tiny bit faster,
but since this is only run once per shell session it's not a big deal.
:::

## Shims vs PATH
Expand Down
23 changes: 21 additions & 2 deletions src/cli/activate.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use std::path::{Path, PathBuf};

use eyre::Result;

use crate::env::PATH_KEY;
use crate::file::touch_dir;
use crate::path_env::PathEnv;
use crate::shell::{get_shell, Shell, ShellType};
use crate::{dirs, env};
use eyre::Result;
use itertools::Itertools;

/// Initializes mise in the current shell session
///
Expand Down Expand Up @@ -94,6 +95,7 @@ impl Activate {
}
miseprint!("{}", self.prepend_path(shell, exe_dir))?;
miseprint!("{}", shell.activate(mise_bin, flags.join("")))?;
remove_shims(shell)?;
Ok(())
}

Expand All @@ -106,6 +108,23 @@ impl Activate {
}
}

fn remove_shims(shell: &dyn Shell) -> std::io::Result<()> {
let shims = dirs::SHIMS
.canonicalize()
.unwrap_or(dirs::SHIMS.to_path_buf());
if env::PATH
.iter()
.filter_map(|p| p.canonicalize().ok())
.contains(&shims)
{
let path_env = PathEnv::from_iter(env::PATH.clone());
// PathEnv automatically removes the shims directory
let cmd = shell.set_env(&PATH_KEY, path_env.join().to_string_lossy().as_ref());
miseprintln!("{cmd}");
}
Ok(())
}

fn is_dir_in_path(dir: &Path) -> bool {
let dir = dir.canonicalize().unwrap_or(dir.to_path_buf());
env::PATH
Expand Down
2 changes: 1 addition & 1 deletion src/shims.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ fn make_shim(target: &Path, shim: &Path) -> Result<()> {

fn err_no_version_set(ts: Toolset, bin_name: &str, tvs: Vec<ToolVersion>) -> Result<PathBuf> {
if tvs.is_empty() {
bail!("{} is not a valid shim", bin_name);
bail!("{bin_name} is not a valid shim. This likely means you uninstalled a tool and the shim does not point to anything. Run `mise use <TOOL>` to reinstall the tool.");
}
let missing_plugins = tvs.iter().map(|tv| tv.ba()).collect::<HashSet<_>>();
let mut missing_tools = ts
Expand Down