mirror of
https://github.com/nvm-sh/nvm.git
synced 2026-07-18 12:58:21 +08:00
[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:
+17
-5
@@ -6,6 +6,18 @@ nvm_has() {
|
|||||||
type "$1" > /dev/null 2>&1
|
type "$1" > /dev/null 2>&1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# resolves like `command "${1}"` does: only executables on the PATH,
|
||||||
|
# ignoring shell functions and aliases
|
||||||
|
nvm_has_executable() {
|
||||||
|
(
|
||||||
|
# `|| true` so that shells with errexit-style options (eg, zsh's ERR_RETURN)
|
||||||
|
# do not abort the subshell when the name is not an alias or a function
|
||||||
|
unalias "${1-}" 2>/dev/null || true
|
||||||
|
unset -f "${1-}" 2>/dev/null || true
|
||||||
|
command -v "${1-}" > /dev/null 2>&1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
nvm_echo() {
|
nvm_echo() {
|
||||||
command printf %s\\n "$*" 2>/dev/null
|
command printf %s\\n "$*" 2>/dev/null
|
||||||
}
|
}
|
||||||
@@ -105,9 +117,9 @@ nvm_node_version() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nvm_download() {
|
nvm_download() {
|
||||||
if nvm_has "curl"; then
|
if nvm_has_executable "curl"; then
|
||||||
curl --fail --compressed -q "$@"
|
curl --fail --compressed -q "$@"
|
||||||
elif nvm_has "wget"; then
|
elif nvm_has_executable "wget"; then
|
||||||
# Emulate curl with wget
|
# Emulate curl with wget
|
||||||
ARGS=$(nvm_echo "$@" | command sed -e 's/--progress-bar /--progress=bar /' \
|
ARGS=$(nvm_echo "$@" | command sed -e 's/--progress-bar /--progress=bar /' \
|
||||||
-e 's/--compressed //' \
|
-e 's/--compressed //' \
|
||||||
@@ -401,7 +413,7 @@ nvm_do_install() {
|
|||||||
# Autodetect install method
|
# Autodetect install method
|
||||||
if nvm_has git; then
|
if nvm_has git; then
|
||||||
install_nvm_from_git
|
install_nvm_from_git
|
||||||
elif nvm_has curl || nvm_has wget; then
|
elif nvm_has_executable curl || nvm_has_executable wget; then
|
||||||
install_nvm_as_script
|
install_nvm_as_script
|
||||||
else
|
else
|
||||||
nvm_echo >&2 'You need git, curl, or wget to install nvm'
|
nvm_echo >&2 'You need git, curl, or wget to install nvm'
|
||||||
@@ -414,7 +426,7 @@ nvm_do_install() {
|
|||||||
fi
|
fi
|
||||||
install_nvm_from_git
|
install_nvm_from_git
|
||||||
elif [ "${METHOD}" = 'script' ]; then
|
elif [ "${METHOD}" = 'script' ]; then
|
||||||
if ! nvm_has curl && ! nvm_has wget; then
|
if ! nvm_has_executable curl && ! nvm_has_executable wget; then
|
||||||
nvm_echo >&2 "You need curl or wget to install nvm"
|
nvm_echo >&2 "You need curl or wget to install nvm"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@@ -496,7 +508,7 @@ nvm_do_install() {
|
|||||||
# during the execution of the install script
|
# during the execution of the install script
|
||||||
#
|
#
|
||||||
nvm_reset() {
|
nvm_reset() {
|
||||||
unset -f nvm_has nvm_install_dir nvm_latest_version nvm_profile_is_bash_or_zsh \
|
unset -f nvm_has nvm_has_executable nvm_install_dir nvm_latest_version nvm_profile_is_bash_or_zsh \
|
||||||
nvm_source nvm_node_version nvm_download install_nvm_from_git nvm_install_node \
|
nvm_source nvm_node_version nvm_download install_nvm_from_git nvm_install_node \
|
||||||
install_nvm_as_script nvm_try_profile nvm_detect_profile nvm_check_global_modules \
|
install_nvm_as_script nvm_try_profile nvm_detect_profile nvm_check_global_modules \
|
||||||
nvm_do_install nvm_reset nvm_default_install_dir nvm_grep
|
nvm_do_install nvm_reset nvm_default_install_dir nvm_grep
|
||||||
|
|||||||
@@ -49,6 +49,18 @@ nvm_has() {
|
|||||||
type "${1-}" >/dev/null 2>&1
|
type "${1-}" >/dev/null 2>&1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# resolves like `command "${1}"` does: only executables on the PATH,
|
||||||
|
# ignoring shell functions and aliases
|
||||||
|
nvm_has_executable() {
|
||||||
|
(
|
||||||
|
# `|| true` so that shells with errexit-style options (eg, zsh's ERR_RETURN)
|
||||||
|
# do not abort the subshell when the name is not an alias or a function
|
||||||
|
unalias "${1-}" 2>/dev/null || true
|
||||||
|
unset -f "${1-}" 2>/dev/null || true
|
||||||
|
command -v "${1-}" >/dev/null 2>&1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
nvm_has_non_aliased() {
|
nvm_has_non_aliased() {
|
||||||
nvm_has "${1-}" && ! nvm_is_alias "${1-}"
|
nvm_has "${1-}" && ! nvm_is_alias "${1-}"
|
||||||
}
|
}
|
||||||
@@ -97,12 +109,12 @@ nvm_curl_use_compression() {
|
|||||||
nvm_get_latest() {
|
nvm_get_latest() {
|
||||||
local NVM_LATEST_URL
|
local NVM_LATEST_URL
|
||||||
local CURL_COMPRESSED_FLAG
|
local CURL_COMPRESSED_FLAG
|
||||||
if nvm_has "curl"; then
|
if nvm_has_executable "curl"; then
|
||||||
if nvm_curl_use_compression; then
|
if nvm_curl_use_compression; then
|
||||||
CURL_COMPRESSED_FLAG="--compressed"
|
CURL_COMPRESSED_FLAG="--compressed"
|
||||||
fi
|
fi
|
||||||
NVM_LATEST_URL="$(curl ${CURL_COMPRESSED_FLAG:-} -q -w "%{url_effective}\\n" -L -s -S https://latest.nvm.sh -o /dev/null)"
|
NVM_LATEST_URL="$(curl ${CURL_COMPRESSED_FLAG:-} -q -w "%{url_effective}\\n" -L -s -S https://latest.nvm.sh -o /dev/null)"
|
||||||
elif nvm_has "wget"; then
|
elif nvm_has_executable "wget"; then
|
||||||
NVM_LATEST_URL="$(command wget -q https://latest.nvm.sh --server-response -O /dev/null 2>&1 | command awk '/^ Location: /{DEST=$2} END{ print DEST }')"
|
NVM_LATEST_URL="$(command wget -q https://latest.nvm.sh --server-response -O /dev/null 2>&1 | command awk '/^ Location: /{DEST=$2} END{ print DEST }')"
|
||||||
else
|
else
|
||||||
nvm_err 'nvm needs curl or wget to proceed.'
|
nvm_err 'nvm needs curl or wget to proceed.'
|
||||||
@@ -127,13 +139,13 @@ nvm_download() {
|
|||||||
|
|
||||||
local NVM_DOWNLOADER
|
local NVM_DOWNLOADER
|
||||||
NVM_DOWNLOADER=''
|
NVM_DOWNLOADER=''
|
||||||
if nvm_has "curl"; then
|
if nvm_has_executable "curl"; then
|
||||||
NVM_DOWNLOADER='curl'
|
NVM_DOWNLOADER='curl'
|
||||||
set -- -q --fail "$@"
|
set -- -q --fail "$@"
|
||||||
if nvm_curl_use_compression; then
|
if nvm_curl_use_compression; then
|
||||||
set -- --compressed "$@"
|
set -- --compressed "$@"
|
||||||
fi
|
fi
|
||||||
elif nvm_has "wget"; then
|
elif nvm_has_executable "wget"; then
|
||||||
NVM_DOWNLOADER='wget'
|
NVM_DOWNLOADER='wget'
|
||||||
# Emulate curl with wget
|
# Emulate curl with wget
|
||||||
local NVM_DOWNLOAD_WGET_COUNT
|
local NVM_DOWNLOAD_WGET_COUNT
|
||||||
@@ -3569,7 +3581,7 @@ nvm() {
|
|||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ "${NVM_OFFLINE}" != 1 ] && ! nvm_has "curl" && ! nvm_has "wget"; then
|
if [ "${NVM_OFFLINE}" != 1 ] && ! nvm_has_executable "curl" && ! nvm_has_executable "wget"; then
|
||||||
nvm_err 'nvm needs curl or wget to proceed.'
|
nvm_err 'nvm needs curl or wget to proceed.'
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
@@ -4688,7 +4700,7 @@ nvm() {
|
|||||||
nvm_version_greater nvm_version_greater_than_or_equal_to \
|
nvm_version_greater nvm_version_greater_than_or_equal_to \
|
||||||
nvm_print_npm_version nvm_install_latest_npm nvm_npm_global_modules \
|
nvm_print_npm_version nvm_install_latest_npm nvm_npm_global_modules \
|
||||||
nvm_has_system_node nvm_has_system_iojs \
|
nvm_has_system_node nvm_has_system_iojs \
|
||||||
nvm_download nvm_get_latest nvm_has nvm_install_default_packages nvm_get_default_packages \
|
nvm_download nvm_get_latest nvm_has nvm_has_executable nvm_install_default_packages nvm_get_default_packages \
|
||||||
nvm_curl_use_compression nvm_curl_version \
|
nvm_curl_use_compression nvm_curl_version \
|
||||||
nvm_auto nvm_supports_xz \
|
nvm_auto nvm_supports_xz \
|
||||||
nvm_echo nvm_err nvm_grep nvm_cd \
|
nvm_echo nvm_err nvm_grep nvm_cd \
|
||||||
|
|||||||
@@ -30,9 +30,10 @@ nvm_echo "$CAPTURED_STDERR" | nvm_grep -q "${EXPECTED_ERR}" \
|
|||||||
|
|
||||||
# --offline should not require curl or wget
|
# --offline should not require curl or wget
|
||||||
nvm_has() { return 1; }
|
nvm_has() { return 1; }
|
||||||
|
nvm_has_executable() { return 1; }
|
||||||
try_err nvm install --offline 999.999.999
|
try_err nvm install --offline 999.999.999
|
||||||
# Should fail with "not found" not "nvm needs curl or wget"
|
# Should fail with "not found" not "nvm needs curl or wget"
|
||||||
nvm_echo "$CAPTURED_STDERR" | nvm_grep -q "curl or wget" \
|
nvm_echo "$CAPTURED_STDERR" | nvm_grep -q "curl or wget" \
|
||||||
&& die "nvm install --offline should not require curl or wget"
|
&& die "nvm install --offline should not require curl or wget"
|
||||||
alias nvm_has='\nvm_has'
|
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'
|
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")"
|
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
|
cleanup
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ TEST_BIN="$WORK/bin"
|
|||||||
ARGV_LOG="$WORK/argv.log"
|
ARGV_LOG="$WORK/argv.log"
|
||||||
|
|
||||||
cleanup() {
|
cleanup() {
|
||||||
unset -f die cleanup nvm_has
|
unset -f die cleanup nvm_has_executable
|
||||||
rm -rf "$WORK"
|
rm -rf "$WORK"
|
||||||
export PATH="$OLDPATH"
|
export PATH="$OLDPATH"
|
||||||
}
|
}
|
||||||
@@ -30,7 +30,7 @@ chmod +x "$TEST_BIN/wget"
|
|||||||
export ARGV_LOG
|
export ARGV_LOG
|
||||||
export PATH="$TEST_BIN:$OLDPATH"
|
export PATH="$TEST_BIN:$OLDPATH"
|
||||||
# force the wget path while keeping system tools (sed) available for sanitization
|
# 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
|
# given an Authorization credential in NVM_AUTH_HEADER
|
||||||
# when nvm_download uses the wget path
|
# when nvm_download uses the wget path
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
die () { echo "$@" ; cleanup ; exit 1; }
|
die () { echo "$@" ; cleanup ; exit 1; }
|
||||||
|
|
||||||
cleanup() {
|
cleanup() {
|
||||||
unset -f nvm_has
|
unset -f nvm_has nvm_has_executable
|
||||||
}
|
}
|
||||||
|
|
||||||
: nvm.sh
|
: nvm.sh
|
||||||
@@ -12,6 +12,7 @@ cleanup() {
|
|||||||
\. ../../common.sh
|
\. ../../common.sh
|
||||||
|
|
||||||
nvm_has() { return 1 ; }
|
nvm_has() { return 1 ; }
|
||||||
|
nvm_has_executable() { return 1 ; }
|
||||||
|
|
||||||
try_err nvm_get_latest
|
try_err nvm_get_latest
|
||||||
[ "_$CAPTURED_STDERR" = "_nvm needs curl or wget to proceed." ] \
|
[ "_$CAPTURED_STDERR" = "_nvm needs curl or wget to proceed." ] \
|
||||||
|
|||||||
Reference in New Issue
Block a user