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
44 changes: 44 additions & 0 deletions e2e/cli/test_reshim_with_shims_on_path
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/usr/bin/env bash

# Regression test: when shims are on PATH and a "mise" shim exists (e.g. because
# core:rust is managed and ~/.cargo/bin contains the mise binary),
# `mise reshim` should still create shims pointing to the real mise binary,
# not to the mise shim itself (which would create a circular symlink).
# Similarly, `mise doctor` should not report shims as missing.

shimdir="$MISE_DATA_DIR/shims"
mise_bin="$(which mise)"

# Install a tool so there are shims to create
mise i dummy@latest

# Reshim without shims on PATH — baseline
mise reshim

# Verify shim was created and points to the real binary
assert "readlink $shimdir/dummy" "$mise_bin"

# Simulate what happens when core:rust is in the toolset: the mise binary
# itself ends up with a shim because ~/.cargo/bin (containing mise) is scanned
# as a tool bin directory. Create a mise shim pointing to the real binary.
ln -sf "$mise_bin" "$shimdir/mise"

# Now put shims on PATH (as mise activate --shims does in non-interactive shells)
export PATH="$shimdir:$PATH"

# Reshim WITH shims on PATH and a mise shim present.
# Previously this caused file::which("mise") to find the shim, leading to
# circular symlinks (shim pointing to itself) and broken doctor output.
mise reshim

# Shim should still point to the real mise binary, not to the shim directory
assert "readlink $shimdir/dummy" "$mise_bin"
assert_not_contains "readlink $shimdir/dummy" "$shimdir"

# The mise shim itself must not be circular
if [ -L "$shimdir/mise" ]; then
assert_not_contains "readlink $shimdir/mise" "$shimdir"
fi

# Doctor should not report missing shims
assert_not_contains "mise doctor" "shims are missing"
2 changes: 1 addition & 1 deletion src/cli/doctor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ impl Doctor {
}

async fn analyze_shims(&mut self, config: &Arc<Config>, toolset: &Toolset) {
let mise_bin = file::which("mise").unwrap_or(env::MISE_BIN.clone());
let mise_bin = file::which_no_shims("mise").unwrap_or(env::MISE_BIN.clone());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For consistency with the reshim implementation in src/shims.rs, this path should ideally be absolutized.

In src/shims.rs, mise_bin is explicitly absolutized (line 128) before being used to create shims. If doctor uses a different path representation (e.g., a relative path if which_no_shims finds one in PATH), the comparison in shims::get_actual_shims (line 436 in src/shims.rs) might fail when checking if a shim's target matches mise_bin, potentially leading to false "missing shim" reports in the doctor output.

Note that since analyze_shims does not return a Result, you would need to handle the potential error from an .absolutize() call manually or ensure the path is absolute via other means.


if let Ok((missing, extra)) = shims::get_shim_diffs(config, mise_bin, toolset).await {
let cmd = style::nyellow("mise reshim");
Expand Down
2 changes: 1 addition & 1 deletion src/shims.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ pub async fn reshim(config: &Arc<Config>, ts: &Toolset, force: bool) -> Result<(
})
.lock();

let mise_bin = file::which("mise").unwrap_or(env::MISE_BIN.clone());
let mise_bin = file::which_no_shims("mise").unwrap_or(env::MISE_BIN.clone());
let mise_bin = mise_bin.absolutize()?; // relative paths don't work as shims

#[cfg(windows)]
Expand Down
Loading