Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
35 changes: 35 additions & 0 deletions e2e/cli/test_exec_venv_path_order
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#!/usr/bin/env bash

# Regression test: `mise x -- tool` should respect PATH order when a
# virtualenv (or similar) directory is prepended to PATH by mise config.
# Previously, `which_bin` pre-resolution bypassed PATH entirely for
# mise-managed tools, so a venv binary would be ignored even though
# mise itself added it to PATH.
# See: https://github.com/jdx/mise/discussions/8340

# Create a fake "venv" with a dummy override that prints a distinct marker
venvdir="$HOME/fake_venv/bin"
mkdir -p "$venvdir"
cat >"$venvdir/dummy" <<'SCRIPT'
#!/bin/sh
echo VENV_DUMMY
SCRIPT
chmod +x "$venvdir/dummy"

# Configure mise with the dummy tool and prepend the venv dir to PATH
# (this simulates what _.python.venv does)
cat >mise.toml <<EOF
[tools]
dummy = "latest"

[env]
_.path = ["$venvdir"]
EOF

mise i

# mise x -- which dummy should find the venv binary first
assert "mise x -- which dummy" "$venvdir/dummy"

# mise x -- dummy should actually execute the venv binary, not the mise-managed one
assert "mise x -- dummy" "VENV_DUMMY"
19 changes: 0 additions & 19 deletions src/cli/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,25 +126,6 @@ impl Exec {

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

// On Unix, resolve the program to its full mise-installed path if it is
Comment thread
cursor[bot] marked this conversation as resolved.
// provided by a mise-managed tool. This prevents infinite recursion when
// a wrapper script (e.g., .devcontainer/bin/tool) calls `mise x -- tool`:
// without this, execvp would find the wrapper again (since it precedes
// the mise install path in PATH) and loop until E2BIG.
// On Windows, exec_program uses which::which_in with PATHEXT to resolve
// the correct executable (.cmd/.exe), so we skip this to avoid passing
// a pre-resolved path that bypasses Windows-specific extension handling.
#[cfg(unix)]
let program = if !program.contains('/') {
if let Some(bin) = ts.which_bin(&config, &program).await {
bin.to_string_lossy().to_string()
} else {
program
}
} else {
program
};

let mut env = measure!("env_with_path", { ts.env_with_path(&config).await? });

// Run auto-enabled prepare steps (unless --no-prepare)
Expand Down
Loading