mirror of
https://github.com/nvm-sh/nvm.git
synced 2026-10-11 00:00:13 +08:00
[Perf] nvm use: skip re-resolving an exact, installed version
When `nvm use` is given an exact `vX.Y.Z` that is already installed, and no alias with that exact name exists, use it directly instead of re-resolving it through `nvm_match_version` and `nvm_ensure_version_installed`, both of which call `nvm_version`. `nvm_auto` takes this path on every shell startup with an already-resolved version, so this removes ~95ms from each new shell (~330ms -> ~235ms in a clean environment on macOS/zsh). Fixes #3930
This commit is contained in:
@@ -212,6 +212,23 @@ nvm_has_system_iojs() {
|
|||||||
[ "$(nvm deactivate >/dev/null 2>&1 && command -v 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() {
|
nvm_is_version_installed() {
|
||||||
if [ -z "${1-}" ]; then
|
if [ -z "${1-}" ]; then
|
||||||
return 1
|
return 1
|
||||||
@@ -4536,6 +4553,8 @@ nvm() {
|
|||||||
IS_VERSION_FROM_NVMRC=0
|
IS_VERSION_FROM_NVMRC=0
|
||||||
local NVM_WRITE_TO_NVMRC
|
local NVM_WRITE_TO_NVMRC
|
||||||
NVM_WRITE_TO_NVMRC=0
|
NVM_WRITE_TO_NVMRC=0
|
||||||
|
local NVM_USE_EXACT_INSTALLED
|
||||||
|
NVM_USE_EXACT_INSTALLED=0
|
||||||
|
|
||||||
while [ $# -ne 0 ]; do
|
while [ $# -ne 0 ]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
@@ -4576,6 +4595,9 @@ nvm() {
|
|||||||
nvm_err 'Please see `nvm --help` or https://github.com/nvm-sh/nvm#nvmrc for more information.'
|
nvm_err 'Please see `nvm --help` or https://github.com/nvm-sh/nvm#nvmrc for more information.'
|
||||||
return 127
|
return 127
|
||||||
fi
|
fi
|
||||||
|
elif nvm_is_installed_exact_version "${PROVIDED_VERSION}"; then
|
||||||
|
VERSION="${PROVIDED_VERSION}"
|
||||||
|
NVM_USE_EXACT_INSTALLED=1
|
||||||
else
|
else
|
||||||
VERSION="$(nvm_match_version "${PROVIDED_VERSION}")"
|
VERSION="$(nvm_match_version "${PROVIDED_VERSION}")"
|
||||||
fi
|
fi
|
||||||
@@ -4617,9 +4639,8 @@ nvm() {
|
|||||||
nvm_ensure_version_installed "${PROVIDED_VERSION}" "${IS_VERSION_FROM_NVMRC}"
|
nvm_ensure_version_installed "${PROVIDED_VERSION}" "${IS_VERSION_FROM_NVMRC}"
|
||||||
fi
|
fi
|
||||||
return 3
|
return 3
|
||||||
# This nvm_ensure_version_installed call can be a performance bottleneck
|
# an exact, already-installed version needs no further resolution or checks
|
||||||
# on shell startup. Perhaps we can optimize it away or make it faster.
|
elif [ "${NVM_USE_EXACT_INSTALLED}" -ne 1 ] && ! nvm_ensure_version_installed "${VERSION}" "${IS_VERSION_FROM_NVMRC}"; then
|
||||||
elif ! nvm_ensure_version_installed "${VERSION}" "${IS_VERSION_FROM_NVMRC}"; then
|
|
||||||
return $?
|
return $?
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -5241,7 +5262,7 @@ nvm() {
|
|||||||
nvm_echo nvm_err nvm_grep nvm_cd \
|
nvm_echo nvm_err nvm_grep nvm_cd \
|
||||||
nvm_die_on_prefix nvm_get_make_jobs nvm_get_minor_version \
|
nvm_die_on_prefix nvm_get_make_jobs nvm_get_minor_version \
|
||||||
nvm_has_solaris_binary nvm_is_merged_node_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_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_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 \
|
nvm_print_default_alias nvm_print_formatted_alias nvm_resolve_local_alias \
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
Reference in New Issue
Block a user