Skip to content
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
82 changes: 82 additions & 0 deletions e2e/cli/test_tool_stub_preserves_caller_path_slow
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#!/usr/bin/env bash
Comment thread
tmkx marked this conversation as resolved.
# shellcheck disable=SC2103
#
# tool-stub non-cached exec must:
# 1. Keep project _.path dirs so sibling stubs remain LookPath-able
# 2. Prefer the stub-selected tool version over an outer task's tool bins

export MISE_GPG_VERIFY=false

mkdir -p tool_stub_preserves_caller_path/bin
cd tool_stub_preserves_caller_path

# --- _.path sibling stubs remain visible ------------------------------------

cat >mise.toml <<'EOF'
[env]
_.path = ["./bin"]

[tasks.check]
run = "dummy"
EOF

cat >bin/dummy <<'EOF'
#!/usr/bin/env -S mise tool-stub
tool = "dummy"
version = "1.0.0"
EOF
chmod +x bin/dummy

cat >bin/sibling <<'EOF'
#!/usr/bin/env bash
echo sibling-found
EOF
chmod +x bin/sibling

# Install via stub (also writes tool-stub bin-path cache)
assert_contains "mise run check" "This is Dummy"

# Replace the installed binary with a PATH probe. Keep the tool installed so the
# next stub run skips install but still hits execute_with_tool_request after the
# bin-path cache is cleared (not the inherit-PATH short-circuit).
DUMMY_BIN="$MISE_DATA_DIR/installs/dummy/1.0.0/bin/dummy"
cat >"$DUMMY_BIN" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
command -v sibling
EOF
chmod +x "$DUMMY_BIN"

rm -rf "$MISE_CACHE_DIR/tool-stubs"

assert_contains "mise run check" "sibling"

# --- stub-selected version wins over outer toolset --------------------------

mkdir -p ../tool_stub_no_shadow/bin
cd ../tool_stub_no_shadow

cat >mise.toml <<'EOF'
[tools]
dummy = "1.0.0"

[env]
_.path = ["./bin"]

[tasks.check]
run = "dummy"
EOF

cat >bin/dummy <<'EOF'
#!/usr/bin/env -S mise tool-stub
tool = "dummy"
version = "2.0.0"
EOF
chmod +x bin/dummy

mise install dummy@1.0.0 dummy@2.0.0
rm -rf "$MISE_CACHE_DIR/tool-stubs"

# Outer task activates dummy@1.0.0; stub selects 2.0.0 — must not resolve 1.0.0
assert_contains "mise run check" "This is Dummy 2.0.0"
assert_not_contains "mise run check" "This is Dummy 1.0.0"
25 changes: 14 additions & 11 deletions src/cli/tool_stub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -566,25 +566,28 @@ async fn execute_with_tool_request(
// Find the binary path using cache
match find_cached_or_resolve_bin_path(&toolset, &*config, stub, stub_path).await? {
Ok(bin_path) => {
// Get the environment with proper PATH from toolset
// env_with_path already has _.path and filters outer install dirs.
// Prepend backend dependency bins (e.g. node for npm); see #7777.
let mut env = toolset.env_with_path(config).await?;
let mut path_env = crate::path_env::PathEnv::from_iter(crate::env::PATH.clone());
for p in toolset.list_paths(config).await {
path_env.add(p);
}

if let Some((backend, _tv)) = toolset.list_current_installed_versions(config).first() {
let btp = backend
let dep_paths = backend
.dependency_toolset(config)
.await?
.list_paths(config)
.await;
for p in btp {
path_env.add(p);
if !dep_paths.is_empty() {
let path = env
.get(crate::env::PATH_KEY.as_str())
.cloned()
.unwrap_or_default();
let mut paths = dep_paths;
paths.extend(std::env::split_paths(&path));
env.insert(
crate::env::PATH_KEY.to_string(),
std::env::join_paths(paths)?.to_string_lossy().to_string(),
);
}
}
env.insert(crate::env::PATH_KEY.to_string(), path_env.to_string());

crate::cli::exec::exec_program(bin_path, args, env, &Default::default(), false).await
}
Err(e) => match e {
Expand Down
Loading