install: warn when a stale binary shadows what we just installed
A binary earlier on PATH permanently masks the one the installer writes, and the failure is SILENT in the worst way: the install reports success, the user runs the old copy forever, and re-running the installer never fixes it because it writes to a DIFFERENT directory. Found live: ~/.local/bin/hanzo held a retired Go build (it reports version 'dev') while the canonical Rust CLI installs to ~/.cargo/bin. uv also installs tools into ~/.local/bin, so a Python `hanzo` shadows the same way. Someone in that state debugs a CLI they are not running. check_shadowing compares `command -v <bin>` against where we actually put it, for hanzo/mcp/dev/hanzod, and prints the exact mv to fix it. It does NOT delete anything — the user's files are theirs — but staying quiet is what makes this cost hours. Verified all three cases with a harness against the real function: stale first on PATH -> warns, naming both paths canonical first -> silent (no false positive) canonical not present-> silent (nothing to shadow) (My first harness run passed for the wrong reason — I had created `cargo/bin` instead of `.cargo/bin`, so the check correctly found nothing. Fixed the harness, then it caught the case.)
This commit is contained in:
@@ -426,6 +426,36 @@ summary() {
|
||||
fi
|
||||
}
|
||||
|
||||
check_shadowing() {
|
||||
# A stale binary earlier on PATH permanently masks what we just installed,
|
||||
# and the failure is silent: the install reports success, `hanzo --version`
|
||||
# prints whatever the old copy says, and re-running the installer never
|
||||
# fixes it because it writes to a DIFFERENT directory.
|
||||
#
|
||||
# Real case: ~/.local/bin/hanzo held a retired Go build while the canonical
|
||||
# Rust CLI installs to ~/.cargo/bin. uv also installs tools into
|
||||
# ~/.local/bin, so a Python `hanzo` shadows it the same way. We do NOT
|
||||
# delete anything — the user's files are theirs — but staying quiet about it
|
||||
# is how someone ends up debugging a CLI they are not running.
|
||||
local resolved expected
|
||||
for bin in hanzo mcp dev hanzod; do
|
||||
has_cmd "$bin" || continue
|
||||
resolved="$(command -v "$bin" 2>/dev/null)"
|
||||
|
||||
expected=""
|
||||
[[ -x "$HOME/.cargo/bin/$bin" ]] && expected="$HOME/.cargo/bin/$bin"
|
||||
[[ -z "$expected" && -x "$HANZO_DIR/$bin" ]] && expected="$HANZO_DIR/$bin"
|
||||
[[ -z "$expected" ]] && continue
|
||||
|
||||
if [[ "$resolved" != "$expected" ]]; then
|
||||
warn "$bin resolves to $resolved, shadowing $expected"
|
||||
echo -e " ${DM}the copy on your PATH is not the one just installed.${N}"
|
||||
echo -e " ${DM}remove or rename it, or put its directory later on PATH:${N}"
|
||||
echo " mv $resolved $resolved.old"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
finish() {
|
||||
echo ""
|
||||
|
||||
@@ -450,6 +480,8 @@ finish() {
|
||||
echo ""
|
||||
fi
|
||||
|
||||
check_shadowing
|
||||
|
||||
if [[ ":$PATH:" != *":$HANZO_DIR:"* ]] && [[ ${#INSTALLED[@]} -gt 0 ]]; then
|
||||
echo -e " ${Y}add to path:${N}"
|
||||
echo " export PATH=\"$HANZO_DIR:\$PATH\""
|
||||
|
||||
Reference in New Issue
Block a user