mirror of
https://github.com/nvm-sh/nvm.git
synced 2026-10-11 00:00:13 +08:00
[Perf] nvm_version_greater, nvm_version_greater_than_or_equal_to: avoid awk where possible
This commit is contained in:
@@ -796,33 +796,81 @@ nvm_curl_version() {
|
|||||||
command curl -V | command awk '{ if ($1 == "curl") print $2 }' | command sed 's/-.*$//g'
|
command curl -V | command awk '{ if ($1 == "curl") print $2 }' | command sed 's/-.*$//g'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Try to do some shell magic to do semver greater-than maths.
|
||||||
|
# Fall through to the expensive test by calling `awk` if we can't be sure.
|
||||||
nvm_version_greater() {
|
nvm_version_greater() {
|
||||||
command awk 'BEGIN {
|
local NVM_LEFT
|
||||||
|
NVM_LEFT="${1#v}"
|
||||||
|
local NVM_RIGHT
|
||||||
|
NVM_RIGHT="${2#v}"
|
||||||
|
local NVM_PLAIN
|
||||||
|
# a third, more complex, argument of `1` (a flag) compares equal versions as true; `0` or
|
||||||
|
# no argument compares them as false.
|
||||||
|
local NVM_OR_EQUAL
|
||||||
|
NVM_OR_EQUAL="${3:-0}"
|
||||||
|
NVM_PLAIN='true'
|
||||||
|
|
||||||
|
# `x.y.z` operands are compared in shell arithmetic, which avoids a fork,
|
||||||
|
# except when a group is long enough to overflow it; anything else - partial
|
||||||
|
# versions, prereleases, and malformed operands - keeps the comparison this
|
||||||
|
# function has always made
|
||||||
|
case "${NVM_LEFT}" in
|
||||||
|
'' | *[!0-9.]* | *..* | .* | *. | *.*.*.*) NVM_PLAIN='false' ;;
|
||||||
|
*.*.*) ;;
|
||||||
|
*) NVM_PLAIN='false' ;;
|
||||||
|
esac
|
||||||
|
case "${NVM_RIGHT}" in
|
||||||
|
'' | *[!0-9.]* | *..* | .* | *. | *.*.*.*) NVM_PLAIN='false' ;;
|
||||||
|
*.*.*) ;;
|
||||||
|
*) NVM_PLAIN='false' ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ "${NVM_PLAIN}" = 'true' ] && [ "${#NVM_LEFT}" -lt 19 ] && [ "${#NVM_RIGHT}" -lt 19 ]; then
|
||||||
|
local NVM_GROUP
|
||||||
|
local NVM_LEFT_GROUP
|
||||||
|
local NVM_RIGHT_GROUP
|
||||||
|
NVM_GROUP=1
|
||||||
|
while [ "${NVM_GROUP}" -le 3 ]; do
|
||||||
|
NVM_LEFT_GROUP="${NVM_LEFT%%.*}"
|
||||||
|
NVM_LEFT="${NVM_LEFT#*.}"
|
||||||
|
NVM_RIGHT_GROUP="${NVM_RIGHT%%.*}"
|
||||||
|
NVM_RIGHT="${NVM_RIGHT#*.}"
|
||||||
|
if [ "${NVM_LEFT_GROUP}" -lt "${NVM_RIGHT_GROUP}" ]; then
|
||||||
|
return 1
|
||||||
|
elif [ "${NVM_LEFT_GROUP}" -gt "${NVM_RIGHT_GROUP}" ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
NVM_GROUP=$((NVM_GROUP + 1))
|
||||||
|
done
|
||||||
|
if [ "${NVM_OR_EQUAL}" = 1 ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
command awk -v or_equal="${NVM_OR_EQUAL}" 'BEGIN {
|
||||||
if (ARGV[1] == "" || ARGV[2] == "") exit(1)
|
if (ARGV[1] == "" || ARGV[2] == "") exit(1)
|
||||||
split(ARGV[1], a, /\./);
|
split(ARGV[1], a, /\./);
|
||||||
split(ARGV[2], b, /\./);
|
split(ARGV[2], b, /\./);
|
||||||
for (i=1; i<=3; i++) {
|
for (i=1; i<=3; i++) {
|
||||||
if (a[i] && a[i] !~ /^[0-9]+$/) exit(2);
|
if (a[i] && a[i] !~ /^[0-9]+$/) exit(2);
|
||||||
if (b[i] && b[i] !~ /^[0-9]+$/) { exit(0); }
|
if (b[i] && b[i] !~ /^[0-9]+$/) {
|
||||||
|
# a non-numeric right-hand group (a prerelease): the left is greater,
|
||||||
|
# unless equality counts, in which case the comparison below decides
|
||||||
|
if (or_equal != 1) { exit(0); }
|
||||||
|
}
|
||||||
if (a[i] < b[i]) exit(3);
|
if (a[i] < b[i]) exit(3);
|
||||||
else if (a[i] > b[i]) exit(0);
|
else if (a[i] > b[i]) exit(0);
|
||||||
}
|
}
|
||||||
|
if (or_equal == 1) { exit(0); }
|
||||||
exit(4)
|
exit(4)
|
||||||
}' "${1#v}" "${2#v}"
|
}' "${NVM_LEFT}" "${NVM_RIGHT}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Try to do some shell magic to do semver greater-than or equal-to maths.
|
||||||
|
# Fall through to the expensive test by calling `awk` if we can't be sure.
|
||||||
|
# see `nvm_version_greater`
|
||||||
nvm_version_greater_than_or_equal_to() {
|
nvm_version_greater_than_or_equal_to() {
|
||||||
command awk 'BEGIN {
|
nvm_version_greater "${1-}" "${2-}" 1
|
||||||
if (ARGV[1] == "" || ARGV[2] == "") exit(1)
|
|
||||||
split(ARGV[1], a, /\./);
|
|
||||||
split(ARGV[2], b, /\./);
|
|
||||||
for (i=1; i<=3; i++) {
|
|
||||||
if (a[i] && a[i] !~ /^[0-9]+$/) exit(2);
|
|
||||||
if (a[i] < b[i]) exit(3);
|
|
||||||
else if (a[i] > b[i]) exit(0);
|
|
||||||
}
|
|
||||||
exit(0)
|
|
||||||
}' "${1#v}" "${2#v}"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nvm_version_dir() {
|
nvm_version_dir() {
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ die () { echo "$@" ; exit 1; }
|
|||||||
\. ../../../nvm.sh
|
\. ../../../nvm.sh
|
||||||
|
|
||||||
nvm_version_greater 0.10.0 0.2.12 || die '"nvm_version_greater 0.10.0 0.2.12" did not return true'
|
nvm_version_greater 0.10.0 0.2.12 || die '"nvm_version_greater 0.10.0 0.2.12" did not return true'
|
||||||
|
nvm_version_greater 0.20.12 0.10.0 || die '"nvm_version_greater 0.20.12 0.10.0" did not return true'
|
||||||
|
nvm_version_greater v18.20.0 v18.19.9 || die '"nvm_version_greater v18.20.0 v18.19.9" did not return true'
|
||||||
|
|
||||||
if nvm_version_greater 0.10.0 0.20.12; then
|
if nvm_version_greater 0.10.0 0.20.12; then
|
||||||
die '"nvm_version_greater 0.10.0 0.20.12" returned true'
|
die '"nvm_version_greater 0.10.0 0.20.12" returned true'
|
||||||
@@ -14,3 +16,40 @@ fi
|
|||||||
if nvm_version_greater 0.10.0 0.10.0; then
|
if nvm_version_greater 0.10.0 0.10.0; then
|
||||||
die '"nvm_version_greater" returned false for the same two versions'
|
die '"nvm_version_greater" returned false for the same two versions'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if nvm_version_greater v18.20.0 v18.20.0; then
|
||||||
|
die '"nvm_version_greater v18.20.0 v18.20.0" returned true for the same two versions'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if nvm_version_greater v18.19.9 v18.20.0; then
|
||||||
|
die '"nvm_version_greater v18.19.9 v18.20.0" returned true'
|
||||||
|
fi
|
||||||
|
|
||||||
|
# a partial version is not a plain `x.y.z`, so it keeps the awk comparison
|
||||||
|
nvm_version_greater 0.10 0.2.12 || die '"nvm_version_greater 0.10 0.2.12" did not return true'
|
||||||
|
|
||||||
|
# the comparison must not write anything to stdout (zsh's `typeset` prints a
|
||||||
|
# local variable when it is redeclared)
|
||||||
|
OUTPUT="$(nvm_version_greater 0.10.0 0.2.12 2>&1)"
|
||||||
|
[ -z "${OUTPUT}" ] || die "nvm_version_greater 0.10.0 0.2.12 wrote output: '${OUTPUT}'"
|
||||||
|
|
||||||
|
# `nvm_version_greater` must not fork a command for a plain `x.y.z` pair:
|
||||||
|
# mock `awk`, which the comparison used, and fail if it runs
|
||||||
|
TEST_DIR="$(pwd)/nvm_version_greater_tmp"
|
||||||
|
[ ! -e "${TEST_DIR}" ] && mkdir "${TEST_DIR}"
|
||||||
|
MOCK_BIN="${TEST_DIR}/bin"
|
||||||
|
mkdir -p "${MOCK_BIN}"
|
||||||
|
{
|
||||||
|
echo '#!/bin/sh'
|
||||||
|
echo 'echo "awk was called" >&2'
|
||||||
|
echo 'exit 1'
|
||||||
|
} > "${MOCK_BIN}/awk"
|
||||||
|
chmod +x "${MOCK_BIN}/awk"
|
||||||
|
|
||||||
|
PATH="${MOCK_BIN}:${PATH}" nvm_version_greater 0.10.0 0.2.12 \
|
||||||
|
|| die 'nvm_version_greater 0.10.0 0.2.12 forked a command'
|
||||||
|
|
||||||
|
PATH="${MOCK_BIN}:${PATH}" nvm_version_greater v18.20.0 v18.19.9 \
|
||||||
|
|| die 'nvm_version_greater v18.20.0 v18.19.9 forked a command'
|
||||||
|
|
||||||
|
rm -rf "${TEST_DIR}"
|
||||||
|
|||||||
Reference in New Issue
Block a user