Skip to content

Commit

Permalink
fix: remove shims directory from PATH when executing shims (#2736)
Browse files Browse the repository at this point in the history
A follow-up to #2735 which was missing some cases
  • Loading branch information
jdx authored Oct 12, 2024
1 parent bb42307 commit a908a90
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 34 deletions.
3 changes: 1 addition & 2 deletions docs/dev-tools/backends/vfox.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
[Vfox](https://github.com/version-fox/vfox) plugins may be used in mise as an alternative for asdf
plugins. On Windows, only vfox plugins are supported since asdf plugins require POSIX compatibility.

The code for this is inside of the mise repository at [
`./src/backend/vfox.rs`](https://github.com/jdx/mise/blob/main/src/backend/vfox.rs).
The code for this is inside of the mise repository at [`./src/backend/vfox.rs`](https://github.com/jdx/mise/blob/main/src/backend/vfox.rs).

## Dependencies

Expand Down
29 changes: 2 additions & 27 deletions src/cli/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ use crate::cli::args::ToolArg;
#[cfg(any(test, windows))]
use crate::cmd;
use crate::config::Config;
use crate::env;
use crate::toolset::{InstallOptions, ToolsetBuilder};
use crate::{dirs, env};

/// Execute a command with tool(s) set
///
Expand Down Expand Up @@ -68,11 +68,7 @@ impl Exec {
ts.notify_if_versions_missing();

let (program, args) = parse_command(&env::SHELL, &self.command, &self.c);
let mut env = ts.env_with_path(&config)?;

if let Some(path) = self.remove_shims_from_path(env.get(&*env::PATH_KEY)) {
env.insert(env::PATH_KEY.to_string(), path);
}
let env = ts.env_with_path(&config)?;

self.exec(program, args, env)
}
Expand Down Expand Up @@ -134,27 +130,6 @@ impl Exec {
None => Err(eyre!("command failed: terminated by signal")),
}
}

// remove the shims dir when using `mise x` since the tools will already be on PATH and shims won't
// be needed. This is to avoid shims from being called in a loop.
fn remove_shims_from_path(&self, path: Option<&String>) -> Option<String> {
if let Some(path) = path {
let paths = env::split_paths(path).filter(|p| {
p != *dirs::SHIMS
&& !p
.canonicalize()
.is_ok_and(|p| p == dirs::SHIMS.canonicalize().unwrap_or_default())
});
Some(
env::join_paths(paths)
.unwrap()
.to_string_lossy()
.to_string(),
)
} else {
None
}
}
}

fn parse_command(
Expand Down
26 changes: 21 additions & 5 deletions src/shims.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ use rayon::prelude::*;

use crate::backend::Backend;
use crate::cli::exec::Exec;
use crate::config::{Config, Settings};
use crate::config::settings::SETTINGS;
use crate::config::CONFIG;
use crate::file::display_path;
use crate::lock_file::LockFile;
use crate::toolset::{ToolVersion, Toolset, ToolsetBuilder};
Expand All @@ -30,6 +31,7 @@ pub fn handle_shim() -> Result<()> {
let args = env::ARGS.read().unwrap();
trace!("shim[{bin_name}] args: {}", args.join(" "));
let mut args: Vec<OsString> = args.iter().map(OsString::from).collect();
remove_shim_dir_from_path();
args[0] = which_shim(&env::MISE_BIN_NAME)?.into();
env::set_var("__MISE_SHIM", "1");
let exec = Exec {
Expand All @@ -44,8 +46,7 @@ pub fn handle_shim() -> Result<()> {
}

fn which_shim(bin_name: &str) -> Result<PathBuf> {
let config = Config::try_get()?;
let mut ts = ToolsetBuilder::new().build(&config)?;
let mut ts = ToolsetBuilder::new().build(&CONFIG)?;
if let Some((p, tv)) = ts.which(bin_name) {
if let Some(bin) = p.which(&tv, bin_name)? {
trace!(
Expand All @@ -55,8 +56,7 @@ fn which_shim(bin_name: &str) -> Result<PathBuf> {
return Ok(bin);
}
}
let settings = Settings::try_get()?;
if settings.not_found_auto_install {
if SETTINGS.not_found_auto_install {
for tv in ts.install_missing_bin(bin_name)?.unwrap_or_default() {
let p = tv.get_backend();
if let Some(bin) = p.which(&tv, bin_name)? {
Expand Down Expand Up @@ -280,6 +280,22 @@ fn make_shim(target: &Path, shim: &Path) -> Result<()> {
Ok(())
}

/// prevent shims from being called in a loop
fn remove_shim_dir_from_path() {
let path = env::var_os(&*env::PATH_KEY).unwrap_or_default();
let paths = env::split_paths(&path).filter(|p| {
p != *dirs::SHIMS
&& !p
.canonicalize()
.is_ok_and(|p| p == dirs::SHIMS.canonicalize().unwrap_or_default())
});
let path = env::join_paths(paths)
.unwrap()
.to_string_lossy()
.to_string();
env::set_var(&*env::PATH_KEY, &path);
}

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);
Expand Down

0 comments on commit a908a90

Please sign in to comment.