Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 35 additions & 7 deletions nvm.sh
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,23 @@ nvm_has_system_iojs() {
[ "$(nvm deactivate >/dev/null 2>&1 && command -v iojs)" != '' ]
}

nvm_is_installed_exact_version() {
case "${1-}" in
v*) ;;
*) return 1 ;;
esac
case "${1#v}" in
*[!0-9.]* | .* | *. | *..* | *.*.*.*) return 1 ;;
*.*.*) ;;
*) return 1 ;;
esac
# an alias with this exact name takes precedence, as it does in `nvm_version`
if [ -e "$(nvm_alias_path)/${1}" ]; then
return 1
fi
nvm_is_version_installed "${1}"
}

nvm_is_version_installed() {
if [ -z "${1-}" ]; then
return 1
Expand Down Expand Up @@ -1656,11 +1673,18 @@ nvm_resolve_local_alias() {
if [ -z "${VERSION}" ]; then
return $EXIT_CODE
fi
if [ "_${VERSION}" != '_∞' ]; then
nvm_version "${VERSION}"
else
if [ "_${VERSION}" = '_∞' ]; then
nvm_echo "${VERSION}"
return
fi

# Fast path: an exact, installed vX.Y.Z needs no further resolution.
if nvm_is_installed_exact_version "${VERSION}"; then
nvm_echo "${VERSION}"
return
fi

nvm_version "${VERSION}"
}

nvm_iojs_prefix() {
Expand Down Expand Up @@ -4536,6 +4560,8 @@ nvm() {
IS_VERSION_FROM_NVMRC=0
local NVM_WRITE_TO_NVMRC
NVM_WRITE_TO_NVMRC=0
local NVM_USE_EXACT_INSTALLED
NVM_USE_EXACT_INSTALLED=0

while [ $# -ne 0 ]; do
case "$1" in
Expand Down Expand Up @@ -4576,6 +4602,9 @@ nvm() {
nvm_err 'Please see `nvm --help` or https://github.com/nvm-sh/nvm#nvmrc for more information.'
return 127
fi
elif nvm_is_installed_exact_version "${PROVIDED_VERSION}"; then
VERSION="${PROVIDED_VERSION}"
NVM_USE_EXACT_INSTALLED=1
else
VERSION="$(nvm_match_version "${PROVIDED_VERSION}")"
fi
Expand Down Expand Up @@ -4617,9 +4646,8 @@ nvm() {
nvm_ensure_version_installed "${PROVIDED_VERSION}" "${IS_VERSION_FROM_NVMRC}"
fi
return 3
# This nvm_ensure_version_installed call can be a performance bottleneck
# on shell startup. Perhaps we can optimize it away or make it faster.
elif ! nvm_ensure_version_installed "${VERSION}" "${IS_VERSION_FROM_NVMRC}"; then
# an exact, already-installed version needs no further resolution or checks
elif [ "${NVM_USE_EXACT_INSTALLED}" -ne 1 ] && ! nvm_ensure_version_installed "${VERSION}" "${IS_VERSION_FROM_NVMRC}"; then
return $?
fi

Expand Down Expand Up @@ -5241,7 +5269,7 @@ nvm() {
nvm_echo nvm_err nvm_grep nvm_cd \
nvm_die_on_prefix nvm_get_make_jobs nvm_get_minor_version \
nvm_has_solaris_binary nvm_is_merged_node_version \
nvm_is_natural_num nvm_is_version_installed nvm_validate_install \
nvm_is_natural_num nvm_is_installed_exact_version nvm_is_version_installed nvm_validate_install \
nvm_install_lock_name nvm_acquire_install_lock nvm_release_install_lock \
nvm_list_aliases nvm_make_alias nvm_print_alias_file nvm_print_alias_path \
nvm_print_default_alias nvm_print_formatted_alias nvm_resolve_local_alias \
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/bin/sh

die () { echo "$@" ; exit 1; }

: nvm.sh
\. ../../../nvm.sh

nvm_version() {
echo 'nvm_version was called' >&2
return 42
}

EXACT="$(nvm_resolve_local_alias test-stable-1)"
[ "_$EXACT" = "_v0.0.1" ] || die "'nvm_resolve_local_alias test-stable-1' was not v0.0.1; got $EXACT"

echo v0.0.99 > ../../../alias/test-not-installed
NOT_INSTALLED="$(nvm_resolve_local_alias test-not-installed 2>/dev/null)"
EXIT_CODE=$?
rm -f ../../../alias/test-not-installed
[ "_$EXIT_CODE" = "_42" ] || die "an exact version that is not installed should still go through nvm_version; got exit code $EXIT_CODE"
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/bin/sh

cleanup () {
rm -rf "$NVM_DIR"
unset -f die cleanup nvm_version
}
die () { echo "$@" ; cleanup ; exit 1; }

: nvm.sh
\. ../../../nvm.sh

NVM_DIR="$(mktemp -d)"
NODE_BIN="$NVM_DIR/versions/node/v12.0.0/bin"
mkdir -p "$NODE_BIN"
printf '#!/bin/sh\necho v12.0.0\n' > "$NODE_BIN/node"
chmod +x "$NODE_BIN/node"

# the slow path resolves through nvm_version; make it fail so only the fast path can succeed
nvm_version() {
return 42
}

nvm use --silent v12.0.0 || die 'nvm use with an exact, installed version should not need nvm_version'
case ":${PATH}:" in
*":${NODE_BIN}:"*) ;;
*) die "nvm use did not put ${NODE_BIN} on PATH; got ${PATH}" ;;
esac

! nvm use --silent v12 2>/dev/null || die 'nvm use with a partial version should still resolve it through nvm_version'

cleanup
58 changes: 58 additions & 0 deletions test/fast/Unit tests/nvm_is_installed_exact_version
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#!/bin/sh

cleanup () {
rm -rf "$NVM_DIR"
unset -f die cleanup
unset NVM_DIR NODE_PATH VERSION
}
die () { echo "$@" ; cleanup ; exit 1; }

: nvm.sh
\. ../../../nvm.sh

set -ex

NVM_DIR=$(mktemp -d)
NODE_PATH="$NVM_DIR/versions/node"
mkdir -p "$NODE_PATH"
if [ -z "$NODE_PATH" ]; then
die 'Unable to create temporary folder'
fi

# nvm_is_installed_exact_version is available
type nvm_is_installed_exact_version > /dev/null 2>&1 || die 'nvm_is_installed_exact_version is not available'

# nvm_is_installed_exact_version with no parameter fails
! nvm_is_installed_exact_version || die 'nvm_is_installed_exact_version without parameter should fail'

# an exact version that is not installed fails
! nvm_is_installed_exact_version 'v12.0.0' || die 'v12.0.0 is not installed and should fail'

# an exact version whose node binary is not executable fails
mkdir -p "$NODE_PATH/v12.0.0/bin"
touch "$NODE_PATH/v12.0.0/bin/node"
! nvm_is_installed_exact_version 'v12.0.0' || die 'v12.0.0 with a non-executable node should fail'

# an exact, installed version succeeds
chmod +x "$NODE_PATH/v12.0.0/bin/node"
nvm_is_installed_exact_version 'v12.0.0' || die 'v12.0.0 is installed and should succeed'

# something shaped almost like vX.Y.Z fails, even when a directory by that name is installed
for VERSION in 'v12.0.0.0' 'v12.0.0.' 'v12..0' 'v.12.0' 'v12.0'; do
mkdir -p "$NODE_PATH/$VERSION/bin"
touch "$NODE_PATH/$VERSION/bin/node"
chmod +x "$NODE_PATH/$VERSION/bin/node"
! nvm_is_installed_exact_version "$VERSION" || die "$VERSION is not an exact version and should fail, even when installed"
done

# anything that is not an exact vX.Y.Z fails, even if it would resolve to an installed version
for VERSION in '12.0.0' '12' 'v12' 'v12.0' 'v12.0.0-rc.1' 'node' 'stable' 'lts/*' 'iojs-v1.0.0' 'system' 'default'; do
! nvm_is_installed_exact_version "$VERSION" || die "$VERSION is not an exact version and should fail"
done

# an alias with the exact same name takes precedence, so the fast path must not apply
mkdir -p "$(nvm_alias_path)"
echo 'v12.0.0' > "$(nvm_alias_path)/v12.0.0"
! nvm_is_installed_exact_version 'v12.0.0' || die 'an alias named v12.0.0 should take precedence'

cleanup
Loading