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 from PATH when executing shims #2736

Merged
merged 1 commit into from
Oct 12, 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: 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
Loading