diff --git a/README.md b/README.md index 33e8eb01..f548cae7 100644 --- a/README.md +++ b/README.md @@ -872,6 +872,10 @@ nvm exposes the following environment variables: Additionally, nvm modifies `PATH`, and, if present, `MANPATH` and `NODE_PATH` when changing versions. +The following environment variables can be set to configure `nvm install`: + +- `NVM_NO_SOURCE_FALLBACK` - when `1`, a failed binary download aborts instead of silently falling back to a (much slower) from-source compile; the persistent equivalent of the `-b` flag, and mutually exclusive with `-s`. + ## Bash Completion diff --git a/nvm.sh b/nvm.sh index d2e7f680..eaaa2897 100755 --- a/nvm.sh +++ b/nvm.sh @@ -3362,6 +3362,7 @@ nvm() { nvm_echo ' The following optional arguments, if provided, must appear directly after `nvm install`:' nvm_echo ' -s Skip binary download, install from source only.' nvm_echo ' -b Skip source download, install from binary only.' + nvm_echo ' (set NVM_NO_SOURCE_FALLBACK=1 to make this the default for every install)' nvm_echo ' --reinstall-packages-from= When installing, reinstall packages installed in ' nvm_echo ' --lts When installing, only select from LTS (long-term support) versions' nvm_echo ' --lts= When installing, only select from versions for a specific LTS line' @@ -3710,6 +3711,17 @@ nvm() { esac done + # NVM_NO_SOURCE_FALLBACK=1 makes `nvm install` behave as if `-b` were always passed: + # a failed binary download aborts instead of silently falling back to a from-source compile. + # It is a persistent policy so callers need not thread `-b` through every invocation. + if [ "${NVM_NO_SOURCE_FALLBACK-}" = '1' ] && [ $nosource -ne 1 ]; then + if [ $nobinary -eq 1 ]; then + nvm_err '-s cannot be combined with NVM_NO_SOURCE_FALLBACK=1 since that would skip install from both binary and source' + return 6 + fi + nosource=1 + fi + if [ "${NVM_OFFLINE}" != 1 ] && ! nvm_has_executable "curl" && ! nvm_has_executable "wget"; then nvm_err 'nvm needs curl or wget to proceed.' return 1 diff --git a/test/fast/Unit tests/nvm install NVM_NO_SOURCE_FALLBACK b/test/fast/Unit tests/nvm install NVM_NO_SOURCE_FALLBACK new file mode 100755 index 00000000..eb826aac --- /dev/null +++ b/test/fast/Unit tests/nvm install NVM_NO_SOURCE_FALLBACK @@ -0,0 +1,50 @@ +#!/bin/sh + +cleanup() { + [ -n "${NVM_DIR}" ] && [ -d "${NVM_DIR}" ] && rm -rf "${NVM_DIR}" + unset -f die cleanup nvm_remote_version nvm_has_executable nvm_binary_available \ + nvm_install_binary nvm_install_source nvm_get_make_jobs + unset NVM_DIR version SOURCE_MARKER OUTPUT EXIT_CODE +} + +die() { echo "$@" ; cleanup ; exit 1; } + +: nvm.sh +\. ../../../nvm.sh + +unset npm_config_prefix NPM_CONFIG_PREFIX + +NVM_DIR="$(mktemp -d)" +[ -n "${NVM_DIR}" ] || die 'unable to create temp NVM_DIR' +version='v20.0.0' +SOURCE_MARKER="${NVM_DIR}/source-was-attempted" + +# Stay offline; make the binary download always fail and record any attempt to +# compile from source. +nvm_remote_version() { nvm_echo "${version}"; } +nvm_has_executable() { return 0; } +nvm_binary_available() { return 0; } +nvm_get_make_jobs() { NVM_MAKE_JOBS=1; } +nvm_install_binary() { return 1; } +nvm_install_source() { command touch "${SOURCE_MARKER}"; return 1; } + +# Default: a failed binary download falls back to a source compile. +rm -f "${SOURCE_MARKER}" +nvm install "${version}" > /dev/null 2>&1 +[ -f "${SOURCE_MARKER}" ] || die 'default behaviour should fall back to source when the binary fails' + +# NVM_NO_SOURCE_FALLBACK=1: a failed binary download must NOT compile from source. +rm -f "${SOURCE_MARKER}" +NVM_NO_SOURCE_FALLBACK=1 nvm install "${version}" > /dev/null 2>&1; EXIT_CODE=$? +[ ! -f "${SOURCE_MARKER}" ] || die 'NVM_NO_SOURCE_FALLBACK=1 should not fall back to source' +[ "${EXIT_CODE}" != "0" ] || die 'a failed binary install with NVM_NO_SOURCE_FALLBACK=1 should be non-zero' + +# NVM_NO_SOURCE_FALLBACK=1 combined with -s would skip both methods: a conflict. +OUTPUT="$(NVM_NO_SOURCE_FALLBACK=1 nvm install -s "${version}" 2>&1)"; EXIT_CODE=$? +[ "${EXIT_CODE}" = "6" ] || die "expected exit code 6 for -s with NVM_NO_SOURCE_FALLBACK=1, got ${EXIT_CODE}" +case "${OUTPUT}" in + *'skip install from both binary and source'*) ;; + *) die "expected a conflict message, got >${OUTPUT}<" ;; +esac + +cleanup