[Fix] nvm_download, nvm_get_latest, install: only select a downloader that exists as an executable

`nvm_has` matches shell functions and aliases,
but downloads now run via `command`, which skips them
- a `curl` shell function with no curl binary on the PATH would select the curl path and fail with exit 127,
instead of falling back to an available wget executable.
The new `nvm_has_executable` helper resolves names the same way `command` does, so downloader selection and execution agree.
This commit is contained in:
Jordan Harband
2026-07-08 13:03:16 -07:00
parent 04fef13bdc
commit 9142a92cdc
6 changed files with 59 additions and 15 deletions
+2 -1
View File
@@ -30,9 +30,10 @@ nvm_echo "$CAPTURED_STDERR" | nvm_grep -q "${EXPECTED_ERR}" \
# --offline should not require curl or wget
nvm_has() { return 1; }
nvm_has_executable() { return 1; }
try_err nvm install --offline 999.999.999
# Should fail with "not found" not "nvm needs curl or wget"
nvm_echo "$CAPTURED_STDERR" | nvm_grep -q "curl or wget" \
&& die "nvm install --offline should not require curl or wget"
alias nvm_has='\nvm_has'
unset -f nvm_has
unset -f nvm_has nvm_has_executable
@@ -45,4 +45,22 @@ nvm_curl_libz_support || die 'nvm_curl_libz_support used the shadowing curl func
nvm_download -s 'http://example.com/' -o /dev/null || die 'nvm_download used the shadowing curl function and failed'
grep -Fxq 'http://example.com/' "$ARGV_LOG" || die "nvm_download did not invoke the curl executable; got: $(cat "$ARGV_LOG")"
# when no curl executable exists, a shadowing curl shell function must not fool
# downloader selection: nvm_download must fall back to the wget executable
WGET_ONLY_BIN="$WORK/wget-only-bin"
mkdir -p "$WGET_ONLY_BIN"
{
echo '#!/bin/sh'
echo ': > "$ARGV_LOG"'
echo 'for a in "$@"; do printf "%s\n" "$a" >> "$ARGV_LOG"; done'
} > "$WGET_ONLY_BIN/wget"
chmod +x "$WGET_ONLY_BIN/wget"
(
PATH="$WGET_ONLY_BIN"
export PATH
nvm_download -s 'http://wget-fallback.example.com/' -o /dev/null
) || die 'nvm_download did not fall back to wget when curl is only a shell function'
grep -Fxq 'http://wget-fallback.example.com/' "$ARGV_LOG" || die "nvm_download did not invoke the wget executable; got: $(cat "$ARGV_LOG")"
cleanup
@@ -6,7 +6,7 @@ TEST_BIN="$WORK/bin"
ARGV_LOG="$WORK/argv.log"
cleanup() {
unset -f die cleanup nvm_has
unset -f die cleanup nvm_has_executable
rm -rf "$WORK"
export PATH="$OLDPATH"
}
@@ -30,7 +30,7 @@ chmod +x "$TEST_BIN/wget"
export ARGV_LOG
export PATH="$TEST_BIN:$OLDPATH"
# force the wget path while keeping system tools (sed) available for sanitization
nvm_has() { [ "$1" != curl ] && command -v "$1" >/dev/null 2>&1; }
nvm_has_executable() { [ "$1" != curl ] && command -v "$1" >/dev/null 2>&1; }
# given an Authorization credential in NVM_AUTH_HEADER
# when nvm_download uses the wget path
@@ -3,7 +3,7 @@
die () { echo "$@" ; cleanup ; exit 1; }
cleanup() {
unset -f nvm_has
unset -f nvm_has nvm_has_executable
}
: nvm.sh
@@ -12,6 +12,7 @@ cleanup() {
\. ../../common.sh
nvm_has() { return 1 ; }
nvm_has_executable() { return 1 ; }
try_err nvm_get_latest
[ "_$CAPTURED_STDERR" = "_nvm needs curl or wget to proceed." ] \