diff --git a/nvm.sh b/nvm.sh index c2d869ab..204c396b 100755 --- a/nvm.sh +++ b/nvm.sh @@ -1117,6 +1117,19 @@ nvm_change_path() { fi } +nvm_hash_reset() { + # under `set +h` there is no cache to clear, and `hash -r` errors + if [ -n "${BASH_VERSION-}" ] && [ "${-#*h}" = "$-" ]; then + return 0 + fi + # `ksh93`'s `hash` takes no `-r` and its usage error is fatal; probing in a + # subshell contains it, and spares the `ksh` variants that do accept `-r` + if [ -n "${KSH_VERSION-}" ] && ! ( \hash -r ) >/dev/null 2>&1; then + return 0 + fi + \hash -r +} + nvm_binary_available() { # binaries started with node 0.8.6 nvm_version_greater_than_or_equal_to "$(nvm_strip_iojs_prefix "${1-}")" v0.8.6 @@ -4228,7 +4241,7 @@ nvm() { fi else export PATH="${NEWPATH}" - \hash -r + nvm_hash_reset if [ "${NVM_SILENT:-0}" -ne 1 ]; then nvm_echo "${NVM_DIR}/*/bin removed from \${PATH}" fi @@ -4373,7 +4386,7 @@ nvm() { export MANPATH fi export PATH - \hash -r + nvm_hash_reset export NVM_BIN="${NVM_VERSION_DIR}/bin" export NVM_INC="${NVM_VERSION_DIR}/include/node" if [ "${NVM_SYMLINK_CURRENT-}" = true ]; then @@ -4980,7 +4993,7 @@ nvm() { nvm_echo_with_colors nvm_err_with_colors \ nvm_get_artifact_compression nvm_install_binary_extract nvm_extract_tarball \ nvm_process_nvmrc nvm_process_nvmrc_content nvm_nvmrc_invalid_msg \ - nvm_write_nvmrc \ + nvm_write_nvmrc nvm_hash_reset \ >/dev/null 2>&1 unset NVM_NODEJS_ORG_MIRROR NVM_IOJS_ORG_MIRROR NVM_DIR \ NVM_CD_FLAGS NVM_BIN NVM_INC NVM_MAKE_JOBS NVM_INSTALL_LOCK \ diff --git a/test/fast/Running 'nvm use' and 'nvm deactivate' with hashing disabled b/test/fast/Running 'nvm use' and 'nvm deactivate' with hashing disabled new file mode 100755 index 00000000..990ce6e6 --- /dev/null +++ b/test/fast/Running 'nvm use' and 'nvm deactivate' with hashing disabled @@ -0,0 +1,45 @@ +#!/bin/bash + +# the `bash` shebang is deliberate: only bash can exhibit the bug, so pinning +# it keeps this meaningful in every job of the shell matrix + +die () { echo "$@" ; cleanup ; exit 1; } +cleanup () { + set -h + rm -f "${OUTPUT_FILE-}" +} + +export NVM_DIR="$(cd ../.. && pwd)" + +: nvm.sh +\. ../../nvm.sh +\. ../common.sh + +make_fake_node v0.2.3 || die 'unable to make fake node' + +OUTPUT_FILE="$(mktemp)" + +set +h + +# not in a command substitution, so the `PATH` it sets survives to `nvm deactivate` +nvm use --delete-prefix v0.2.3 > "${OUTPUT_FILE}" 2>&1 +OUTPUT="$(cat "${OUTPUT_FILE}")" +case "${OUTPUT}" in + *'hash: '*) die "nvm use complained about hashing: ${OUTPUT}" ;; +esac +case "${OUTPUT}" in + *'Now using node v0.2.3'*) ;; + *) die "nvm use did not activate v0.2.3: ${OUTPUT}" ;; +esac + +nvm deactivate > "${OUTPUT_FILE}" 2>&1 +OUTPUT="$(cat "${OUTPUT_FILE}")" +case "${OUTPUT}" in + *'hash: '*) die "nvm deactivate complained about hashing: ${OUTPUT}" ;; +esac +case "${OUTPUT}" in + *'removed from ${PATH}'*) ;; + *) die "nvm deactivate did not strip the nvm bin dir: ${OUTPUT}" ;; +esac + +cleanup diff --git a/test/fast/Running 'nvm use' does not leave a stale hashed node b/test/fast/Running 'nvm use' does not leave a stale hashed node new file mode 100755 index 00000000..4629dc50 --- /dev/null +++ b/test/fast/Running 'nvm use' does not leave a stale hashed node @@ -0,0 +1,29 @@ +#!/bin/sh + +die () { echo "$@" ; exit 1; } + +export NVM_DIR="$(cd ../.. && pwd)" + +: nvm.sh +\. ../../nvm.sh +\. ../common.sh + +make_fake_node v0.2.3 || die 'unable to make fake node v0.2.3' +make_fake_node v0.10.1 || die 'unable to make fake node v0.10.1' + +nvm use --delete-prefix v0.2.3 >/dev/null 2>&1 || die 'failed to activate v0.2.3' + +# run `node` from this shell, so that the shell caches where it found it +node >/dev/null 2>&1 || die 'fake node v0.2.3 is not runnable' + +nvm use --delete-prefix v0.10.1 >/dev/null 2>&1 || die 'failed to activate v0.10.1' + +ACTUAL="$(node)" +[ "${ACTUAL}" = 'v0.10.1' ] || die "expected node v0.10.1 after switching versions, got '${ACTUAL}'" + +nvm deactivate >/dev/null 2>&1 || die 'failed to deactivate' + +RESOLVED="$(command -v node || true)" +case "${RESOLVED}" in + "${NVM_DIR}"/*) die "after deactivating, node still resolves inside \${NVM_DIR}: ${RESOLVED}" ;; +esac diff --git a/test/fast/Unit tests/nvm_hash_reset b/test/fast/Unit tests/nvm_hash_reset new file mode 100755 index 00000000..4520eff7 --- /dev/null +++ b/test/fast/Unit tests/nvm_hash_reset @@ -0,0 +1,27 @@ +#!/bin/sh + +die () { echo "$@" ; exit 1; } + +: nvm.sh +\. ../../../nvm.sh + +# also covers #3247, where `command hash -r` found a `hash` binary, not the builtin +OUTPUT="$(nvm_hash_reset 2>&1)" +RC=$? +[ ${RC} -eq 0 ] || die "nvm_hash_reset returned ${RC}: ${OUTPUT}" +[ -z "${OUTPUT}" ] || die "nvm_hash_reset was not silent: ${OUTPUT}" + +# bash is the only supported shell that can turn hashing off +if [ -n "${BASH_VERSION-}" ]; then + set +h + OUTPUT="$(nvm_hash_reset 2>&1)" + RC=$? + set -h + [ ${RC} -eq 0 ] || die "with hashing disabled, nvm_hash_reset returned ${RC}: ${OUTPUT}" + [ -z "${OUTPUT}" ] || die "with hashing disabled, nvm_hash_reset was not silent: ${OUTPUT}" + + ls >/dev/null 2>&1 + hash -t ls >/dev/null 2>&1 || die 'expected `ls` to be hashed' + nvm_hash_reset || die 'with hashing enabled, nvm_hash_reset failed' + ! hash -t ls >/dev/null 2>&1 || die 'nvm_hash_reset did not clear the hash table' +fi