From 3fda4d55427c4027ae128edf9bda4cf79f239301 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Wed, 21 Oct 2026 14:09:18 -0700 Subject: [PATCH] [New] select versions by category: `alpha`, `lts`, `non-lts`, `iojs`; exclude alphas by default Node 27 and later publish Alpha prereleases, like `v27.0.0-alpha.1.0.0`, in the main `index.tab`, so `nvm install node` or `nvm install 27` would otherwise pick one. Every version is in exactly one category: `alpha` and `lts` or `non-lts` (by index.tab's LTS column) on the node mirror, and `iojs` on the io.js mirror. Commands select from every category but `alpha`, unless `$NVM_ONLY` lists others, and every command that selects or lists versions takes `--only=` to override both; an exact alpha needs `alpha` selected, like any other. An LTS selection, like `--lts` or an `lts/` version, can't combine with an `--only=` that excludes `lts`. Telling installed `lts` and `non-lts` versions apart uses the recorded LTS status, and fails rather than guess without it. `nvm alias` also stores `--only=`, so `nvm alias default --only=alpha node` makes the latest installed alpha the default, including in a new shell. --- README.md | 26 + nvm-exec | 2 + nvm.sh | 668 ++++++++++++++++-- test/fast/Aliases/an alias can store --only | 75 ++ ...se and nvm which explain an excluded alpha | 63 ++ .../Unit tests/nvm_filter_installed_versions | 78 ++ test/fast/Unit tests/nvm_is_alpha_version | 16 + test/fast/Unit tests/nvm_ls alpha | 56 ++ test/fast/Unit tests/nvm_ls_cached alpha | 43 ++ test/fast/Unit tests/nvm_ls_remote alpha | 92 +++ test/fast/Unit tests/nvm_normalize_only | 23 + test/fast/Unit tests/nvm_resolve_only | 66 ++ test/fast/Unit tests/nvm_sort_versions | 56 ++ 13 files changed, 1213 insertions(+), 51 deletions(-) create mode 100755 test/fast/Aliases/an alias can store --only create mode 100755 test/fast/Unit tests/nvm use and nvm which explain an excluded alpha create mode 100755 test/fast/Unit tests/nvm_filter_installed_versions create mode 100755 test/fast/Unit tests/nvm_is_alpha_version create mode 100755 test/fast/Unit tests/nvm_ls alpha create mode 100755 test/fast/Unit tests/nvm_ls_cached alpha create mode 100755 test/fast/Unit tests/nvm_ls_remote alpha create mode 100755 test/fast/Unit tests/nvm_normalize_only create mode 100755 test/fast/Unit tests/nvm_resolve_only create mode 100755 test/fast/Unit tests/nvm_sort_versions diff --git a/README.md b/README.md index 448bcd36..0593147c 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ - [Manual Upgrade](#manual-upgrade) - [Usage](#usage) - [Long-term Support](#long-term-support) + - [Version Categories](#version-categories) - [Migrating Global Packages While Installing](#migrating-global-packages-while-installing) - [Migrating Global Packages Between Installed Versions](#migrating-global-packages-between-installed-versions) - [Offline Install](#offline-install) @@ -462,6 +463,29 @@ To get the latest LTS version of node and migrate your existing installed packag nvm install --reinstall-packages-from=current 'lts/*' ``` +### Version Categories + +Every version of node belongs to exactly one of these categories: + + - `alpha`: an Alpha prerelease, like `v27.0.0-alpha.1.0.0`, which precedes a major's first release + - `lts`: a version marked as LTS in the mirror's `index.tab` + - `non-lts`: any other version of node + - `iojs`: any version of io.js, from the io.js mirror + +By default, `nvm` selects versions from every category except `alpha`, so `nvm install node`, `nvm install 27`, and `nvm ls-remote` never pick or show an Alpha. Every command that selects or lists versions accepts `--only=` with a comma-separated list of categories to select from instead; Alphas, even an exact version, are only selected when `alpha` is included: + +```sh +nvm ls-remote --only=alpha +nvm install --only=alpha 27 +nvm use --only=alpha,lts,non-lts 27.0.0-alpha.1.0.0 +``` + +To change the default, set `NVM_ONLY` to the same kind of list, for example in your shell profile; `--only=` overrides it. An LTS selection (`--lts`, `--lts=`, or an `lts/` version) picks versions through the matching `lts/` alias, so it only picks LTS versions, and it can't be combined with an `--only=` that excludes `lts`. + +An alias can store `--only=` too, so `nvm alias default --only=alpha node` makes the latest installed version of node, including Alphas, the default. + +Telling `lts` and `non-lts` installed versions apart uses the LTS status that `nvm` records each time it downloads the list of available versions; if it has never done so, the first command that needs it downloads that list once. + ### Migrating Global Packages While Installing If you want to install a new version of Node.js and migrate npm packages from a previous version: @@ -925,6 +949,8 @@ nvm exposes the following environment variables: Additionally, nvm modifies `PATH` when changing versions, along with `MANPATH` wherever a `manpath` command exists, and `NODE_PATH`, if present. +`NVM_ONLY` can be set to a comma-separated list of the [version categories](#version-categories) that commands select from by default. + 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`. diff --git a/nvm-exec b/nvm-exec index 4c5d0cd8..3298610f 100755 --- a/nvm-exec +++ b/nvm-exec @@ -19,4 +19,6 @@ else fi fi +unset NVM_ONLY_SELECTED + exec "$@" diff --git a/nvm.sh b/nvm.sh index 5de201aa..352c7af7 100755 --- a/nvm.sh +++ b/nvm.sh @@ -380,7 +380,7 @@ nvm_is_installed_exact_version() { if [ -e "$(nvm_alias_path)/${1}" ]; then return 1 fi - nvm_is_version_installed "${1}" + nvm_is_version_installed "${1}" && nvm_is_version_selected "${1}" } nvm_is_version_installed() { @@ -1111,6 +1111,9 @@ nvm_ensure_version_installed() { EXIT_CODE="$?" local NVM_VERSION_DIR if [ "${EXIT_CODE}" != "0" ] || ! nvm_is_version_installed "${LOCAL_VERSION}"; then + if nvm_explain_excluded_version "${PROVIDED_VERSION}"; then + return 1 + fi if VERSION="$(nvm_resolve_alias "${PROVIDED_VERSION}")"; then nvm_err "N/A: version \"${PROVIDED_VERSION} -> ${VERSION}\" is not yet installed." else @@ -1130,6 +1133,22 @@ nvm_ensure_version_installed() { fi } +# args: version +# Explains, and succeeds, when the version only matches installed versions outside the selected categories. +nvm_explain_excluded_version() { + local NVM_EXCLUDED_VERSION + NVM_EXCLUDED_VERSION="$(NVM_ONLY_SELECTED='alpha,lts,non-lts,iojs' nvm_version "${1-}" 2>/dev/null)" ||: + if [ "_${NVM_EXCLUDED_VERSION:-N/A}" = '_N/A' ] || ! nvm_is_version_installed "${NVM_EXCLUDED_VERSION}"; then + return 1 + fi + if [ "_${NVM_EXCLUDED_VERSION}" != "_$(nvm_ensure_version_prefix "${1-}")" ]; then + NVM_EXCLUDED_VERSION="${1-} -> ${NVM_EXCLUDED_VERSION}" + fi + nvm_err "N/A: version \"${NVM_EXCLUDED_VERSION}\" is installed, but excluded by the selected version categories (${NVM_ONLY_SELECTED:-${NVM_ONLY:-lts,non-lts,iojs}})." + nvm_err '' + nvm_err 'Include its category with `--only=`, or in `$NVM_ONLY`.' +} + # Expand a version using the version cache nvm_version() { local PATTERN @@ -1148,11 +1167,20 @@ nvm_version() { # flags stored in an alias, like `--lts`, precede the version they apply to local NVM_LTS_FILTER NVM_LTS_FILTER='' + local NVM_ONLY_ALIAS + NVM_ONLY_ALIAS='' while :; do case "${PATTERN}" in '--lts '*) NVM_LTS_FILTER='*' ;; + --only=*' '*) + NVM_ONLY_ALIAS="${PATTERN%% *}" + if ! NVM_ONLY_ALIAS="$(nvm_normalize_only "${NVM_ONLY_ALIAS#--only=}" "an alias's \`--only\`")"; then + nvm_echo 'N/A' + return 3 + fi + ;; --lts=*' '*) NVM_LTS_FILTER="${PATTERN%% *}" NVM_LTS_FILTER="${NVM_LTS_FILTER#--lts=}" @@ -1166,7 +1194,7 @@ nvm_version() { PATTERN="${PATTERN#* }" done # like `nvm_resolve_alias`, these flags replace those of an alias they precede - if [ -n "${NVM_LTS_FILTER}" ]; then + if [ -n "${NVM_LTS_FILTER}${NVM_ONLY_ALIAS}" ]; then local NVM_FLAGGED_TARGET if NVM_FLAGGED_TARGET="$(nvm_resolve_alias "${PATTERN}" 2>/dev/null)" && [ "_${NVM_FLAGGED_TARGET}" != '_∞' ]; then while :; do @@ -1190,8 +1218,25 @@ nvm_version() { PATTERN="stable" fi ;; + _lts/*) + # `lts/` aliases are written from index.tab's LTS rows, so their targets are LTS + case ",${NVM_ONLY_ALIAS:-${NVM_ONLY_SELECTED:-${NVM_ONLY:-lts,non-lts,iojs}}}," in + *,non-lts,*) ;; + *,lts,*) NVM_ONLY_ALIAS="${NVM_ONLY_ALIAS:-${NVM_ONLY_SELECTED:-${NVM_ONLY-}}},non-lts" ;; + esac + ;; esac + if [ -n "${NVM_ONLY_ALIAS}" ]; then + if nvm_needs_lts_status "${NVM_ONLY_ALIAS}" && ! nvm_ensure_lts_status; then + nvm_err 'The LTS status of installed versions is not recorded yet; run `nvm ls-remote` to record it.' + nvm_echo 'N/A' + return 3 + fi + local NVM_ONLY_SELECTED + NVM_ONLY_SELECTED="${NVM_ONLY_ALIAS}" + fi + # Fast path: an exact, fully-qualified version that is installed resolves to # itself, unless an alias of the same name takes precedence. Short-circuiting # it here avoids the `nvm_ls` subprocess pipeline on shell startup; every @@ -1297,7 +1342,11 @@ nvm_remote_versions() { NVM_LS_REMOTE_PRE_MERGED_OUTPUT='' local NVM_LS_REMOTE_POST_MERGED_OUTPUT NVM_LS_REMOTE_POST_MERGED_OUTPUT='' - if [ -z "${NVM_FLAVOR-}" ] || [ "${NVM_FLAVOR-}" = "${NVM_NODE_PREFIX}" ]; then + if { + [ -z "${NVM_FLAVOR-}" ] || [ "${NVM_FLAVOR-}" = "${NVM_NODE_PREFIX}" ]; + } && { + nvm_only_includes alpha || nvm_only_includes lts || nvm_only_includes non-lts; + }; then local NVM_LS_REMOTE_OUTPUT # extra space is needed here to avoid weird behavior when `nvm_ls_remote` ends in a `*` NVM_LS_REMOTE_OUTPUT="$(NVM_LTS="${NVM_LTS-}" nvm_ls_remote "${PATTERN-}") " &&: @@ -1316,7 +1365,7 @@ v[1-9]*}" ;; NVM_LS_REMOTE_IOJS_EXIT_CODE=0 local NVM_LS_REMOTE_IOJS_OUTPUT NVM_LS_REMOTE_IOJS_OUTPUT='' - if [ -z "${NVM_LTS-}" ] && { + if [ -z "${NVM_LTS-}" ] && nvm_only_includes iojs && { [ -z "${NVM_FLAVOR-}" ] || [ "${NVM_FLAVOR-}" = "${NVM_IOJS_PREFIX}" ]; }; then NVM_LS_REMOTE_IOJS_OUTPUT=$(nvm_ls_remote_iojs "${PATTERN-}") &&: @@ -2055,11 +2104,194 @@ nvm_strip_iojs_prefix() { esac } +# vN.0.0-alpha.X.Y.Z +nvm_is_alpha_version() { + local NVM_ALPHA_VERSION + NVM_ALPHA_VERSION="${1#v}" + case "${NVM_ALPHA_VERSION}" in + *-alpha.*) ;; + *) return 1 ;; + esac + local NVM_ALPHA_PART + for NVM_ALPHA_PART in "${NVM_ALPHA_VERSION%%-alpha.*}" "${NVM_ALPHA_VERSION#*-alpha.}"; do + case "${NVM_ALPHA_PART}" in + *[!0-9.]* | .* | *. | *..* | *.*.*.*) return 1 ;; + *.*.*) ;; + *) return 1 ;; + esac + done +} + +# args: comma-separated version categories, where they came from (for errors) +nvm_normalize_only() { + local NVM_ONLY_VALUE + NVM_ONLY_VALUE="${1-}" + local NVM_ONLY_SOURCE + NVM_ONLY_SOURCE="${2-}" + local NVM_ONLY_REST + NVM_ONLY_REST=",${NVM_ONLY_VALUE}," + local NVM_ONLY_RESULT + NVM_ONLY_RESULT='' + local NVM_ONLY_CATEGORY + case "${NVM_ONLY_VALUE}" in + '' | ,* | *, | *,,*) NVM_ONLY_REST='' ;; + esac + for NVM_ONLY_CATEGORY in alpha lts non-lts iojs; do + case "${NVM_ONLY_REST}" in + *",${NVM_ONLY_CATEGORY},"*) NVM_ONLY_RESULT="${NVM_ONLY_RESULT:+${NVM_ONLY_RESULT},}${NVM_ONLY_CATEGORY}" ;; + esac + while :; do + case "${NVM_ONLY_REST}" in + *",${NVM_ONLY_CATEGORY},"*) NVM_ONLY_REST="${NVM_ONLY_REST%%,"${NVM_ONLY_CATEGORY}",*},${NVM_ONLY_REST#*,"${NVM_ONLY_CATEGORY}",}" ;; + *) break ;; + esac + done + done + if [ "${NVM_ONLY_REST}" != ',' ]; then + nvm_err "Invalid ${NVM_ONLY_SOURCE} value \"${NVM_ONLY_VALUE}\": it must be a comma-separated list of any of: alpha, lts, non-lts, iojs" + return 55 + fi + nvm_echo "${NVM_ONLY_RESULT}" +} + +# args: how many times `--only=` was provided, its value, the LTS selection in effect (if any) +# Prints the version categories to select from: the `--only=` value if provided, else +# those of an enclosing `nvm` command, else `$NVM_ONLY`, else every category but alpha. +# An LTS selection, like `--lts`, picks versions through `lts/` aliases, whose targets +# are LTS, so it needs no recorded LTS status; it can't combine with an `--only=` that +# excludes LTS versions. +nvm_resolve_only() { + local NVM_ONLY_RESOLVED + if [ "${1:-0}" -gt 1 ]; then + nvm_err '`--only` may only be provided once.' + return 55 + elif [ "${1-}" = 1 ]; then + NVM_ONLY_RESOLVED="$(nvm_normalize_only "${2-}" '`--only`')" || return + elif [ -n "${NVM_ONLY_SELECTED-}" ]; then + # the enclosing command has already resolved, and recorded LTS status if needed + nvm_echo "${NVM_ONLY_SELECTED}" + return + elif [ -n "${NVM_ONLY-}" ]; then + NVM_ONLY_RESOLVED="$(nvm_normalize_only "${NVM_ONLY}" '`$NVM_ONLY`')" || return + else + NVM_ONLY_RESOLVED='lts,non-lts,iojs' + fi + if [ -n "${3-}" ]; then + case ",${NVM_ONLY_RESOLVED}," in + *,lts,*) ;; + *) + if [ "${1-}" = 1 ]; then + nvm_err "\`--only=${2-}\` excludes LTS versions, so it cannot be combined with an LTS selection like \`--lts\`." + return 55 + fi + ;; + esac + NVM_ONLY_RESOLVED='lts,non-lts' + fi + # commands that download index.tab themselves record LTS status as they do + if [ -z "${NVM_NO_LTS_STATUS-}" ] && nvm_needs_lts_status "${NVM_ONLY_RESOLVED}" && ! nvm_ensure_lts_status; then + nvm_err 'The LTS status of installed versions is not recorded yet; run `nvm ls-remote` to record it.' + return 3 + fi + nvm_echo "${NVM_ONLY_RESOLVED}" +} + +# args: a version read from .nvmrc +# An `lts/` version is an LTS selection, like `--lts`; this updates the enclosing +# `nvm` command's NVM_LTS_REQUEST and NVM_ONLY_SELECTED to match. +nvm_select_lts_from_nvmrc() { + case "${1-}" in + lts/*) ;; + *) return 0 ;; + esac + local NVM_ONLY_LTS + NVM_ONLY_LTS="$(NVM_ONLY_SELECTED='' nvm_resolve_only "${NVM_ONLY_FLAG_COUNT-}" "${NVM_ONLY_FLAG-}" '*')" || return + NVM_ONLY_SELECTED="${NVM_ONLY_LTS}" + NVM_LTS_REQUEST='*' +} + +# assumes the categories have been normalized by `nvm_resolve_only` +nvm_only_includes() { + case ",${NVM_ONLY_SELECTED:-${NVM_ONLY:-lts,non-lts,iojs}}," in + *",${1-},"*) return 0 ;; + esac + return 1 +} + +# args: categories +# Telling LTS from non-LTS versions apart needs their recorded LTS status. +nvm_needs_lts_status() { + case ",${1-}," in + *,lts,*) + case ",${1-}," in + *,non-lts,*) return 1 ;; + esac + ;; + *,non-lts,*) ;; + *) return 1 ;; + esac +} + +# Filters `nvm_ls`-style version lines on stdin down to the selected categories. +nvm_filter_installed_versions() { + local NVM_NEEDS_LTS_STATUS + NVM_NEEDS_LTS_STATUS=0 + if nvm_needs_lts_status "${NVM_ONLY_SELECTED:-${NVM_ONLY:-lts,non-lts,iojs}}"; then + NVM_NEEDS_LTS_STATUS=1 + if [ ! -f "$(nvm_lts_status_path)" ]; then + nvm_err 'The LTS status of installed versions is not recorded yet; run `nvm ls-remote` to record it.' + return 3 + fi + fi + command awk \ + -v only=",${NVM_ONLY_SELECTED:-${NVM_ONLY:-lts,non-lts,iojs}}," \ + -v needs_lts_status="${NVM_NEEDS_LTS_STATUS}" \ + -v record="$(nvm_lts_status_path)" ' + BEGIN { + if (needs_lts_status) { + while ((getline line < record) > 0) { + split(line, fields, " "); + lts[fields[1]] = fields[2]; + } + } + } + { + if ($1 == "system" || $1 == "N/A") { print; next } + if ($1 ~ /^iojs-/) { category = "iojs" } + else if ($1 ~ /^v[0-9]+\.[0-9]+\.[0-9]+-alpha\.[0-9]+\.[0-9]+\.[0-9]+$/) { category = "alpha" } + else if (!needs_lts_status) { category = index(only, ",lts,") ? "lts" : "non-lts" } + else { category = (($1 in lts) && lts[$1] != "-") ? "lts" : "non-lts" } + if (index(only, "," category ",")) { print } + }' +} + +# args: version +nvm_is_version_selected() { + case "${1-}" in + system) return 0 ;; + iojs-*) + nvm_only_includes iojs + return + ;; + esac + if nvm_is_alpha_version "${1-}"; then + nvm_only_includes alpha + return + fi + if ! nvm_needs_lts_status "${NVM_ONLY_SELECTED:-${NVM_ONLY:-lts,non-lts,iojs}}"; then + nvm_only_includes lts + return + fi + [ -n "$(nvm_echo "${1-}" | nvm_filter_installed_versions)" ] +} + # Sorts version lines, keyed on their first field, which may end in `.node` or `.iojs`, # by semver precedence: prereleases come before their release, and their numeric # identifiers compare as numbers, so `v24.0.0-rc.2` comes before `v24.0.0-rc.10`. +# With an argument of `1`, prereleases other than alphas, like nightlies, collapse +# into one line per release. nvm_sort_versions() { - command awk '{ + command awk -v collapse="${1-}" '{ version = $1; sub(/\.(node|iojs)$/, "", version); sub(/^(iojs-)?v/, "", version); @@ -2079,11 +2311,16 @@ nvm_sort_versions() { } prerelease = prerelease identifier "!"; } + if (collapse && version !~ /^[0-9]+\.[0-9]+\.[0-9]+-alpha\.[0-9]+\.[0-9]+\.[0-9]+$/) { prerelease = "0" } version = substr(version, 1, dash - 1); } split(version, parts, "."); printf "%d %d %d %s\t%s\n", parts[1], parts[2], parts[3], prerelease, $0; - }' | LC_ALL=C command sort -k 1,1n -k 2,2n -k 3,3n -k 4,4 | command cut -f 2- | command uniq + }' | if [ "${1-}" = 1 ]; then + LC_ALL=C command sort -u -k 1,1n -k 2,2n -k 3,3n -k 4,4 | command cut -f 2- + else + LC_ALL=C command sort -k 1,1n -k 2,2n -k 3,3n -k 4,4 | command cut -f 2- | command uniq + fi } nvm_ls() { @@ -2258,6 +2495,22 @@ nvm_ls() { fi fi + # filtering is only needed when a selected category leaves out some of these versions + local NVM_FILTER_VERSIONS + NVM_FILTER_VERSIONS=true + if nvm_only_includes lts && nvm_only_includes non-lts; then + NVM_FILTER_VERSIONS=false + case "${VERSIONS}" in + *-alpha.*) nvm_only_includes alpha || NVM_FILTER_VERSIONS=true ;; + esac + case "${VERSIONS}" in + *iojs-*) nvm_only_includes iojs || NVM_FILTER_VERSIONS=true ;; + esac + fi + if [ -n "${VERSIONS}" ] && [ "${NVM_FILTER_VERSIONS}" = true ]; then + VERSIONS="$(nvm_echo "${VERSIONS}" | nvm_filter_installed_versions)" + fi + if [ "${NVM_ADD_SYSTEM-}" = true ]; then local SYSTEM_VERSION SYSTEM_VERSION="$(nvm deactivate >/dev/null 2>&1 && node -v 2>/dev/null)" @@ -2417,7 +2670,7 @@ nvm_ls_remote_index_tab() { local SORT_COMMAND SORT_COMMAND='command sort' case "${FLAVOR}" in - node) SORT_COMMAND='command sort -t. -u -k 1.2,1n -k 2,2n -k 3,3n' ;; + node) SORT_COMMAND='nvm_sort_versions 1' ;; esac local PATTERN @@ -2484,8 +2737,17 @@ EOF LTS="${LTS#lts/}" fi - VERSIONS="$( { command awk -v lts="${LTS-}" '{ + VERSIONS="$( { command awk -v lts="${LTS-}" -v flavor="${FLAVOR}" -v only=",${NVM_ONLY_SELECTED:-${NVM_ONLY:-lts,non-lts,iojs}}," -v pattern="${PATTERN-}" '{ if (!$1) { next } + if (flavor == "iojs") { category = "iojs" } + else if ($1 ~ /^v[0-9]+\.[0-9]+\.[0-9]+-alpha\.[0-9]+\.[0-9]+\.[0-9]+$/) { + # a release, like v27.0.0, is not one of its alphas + if (pattern ~ /^v[0-9]+\.[0-9]+\.[0-9]+$/ && index($1, pattern "-") == 1) { next } + category = "alpha" + } + else if ($10 ~ /^\-?$/) { category = "non-lts" } + else { category = "lts" } + if (!index(only, "," category ",")) { next } if (lts && $10 ~ /^\-?$/) { next } if (lts && lts != "*" && tolower($10) !~ tolower(lts)) { next } if ($10 !~ /^\-?$/) { @@ -2728,7 +2990,7 @@ nvm_print_versions() { -v remote_versions="$(printf '%s' "${1-}" | tr '\n' '|')" \ -v latest_alias="${NVM_LATEST_ALIAS}" \ -v node_prefix="$(nvm_node_prefix)" -v iojs_prefix="$(nvm_iojs_prefix)" \ - -v installed_versions="$(nvm_ls | nvm_grep -v '^N/A$' | tr '\n' '|')" -v current="$NVM_CURRENT" \ + -v installed_versions="$(nvm_ls 2>/dev/null | nvm_grep -v '^N/A$' | tr '\n' '|')" -v current="$NVM_CURRENT" \ -v installed_color="$INSTALLED_COLOR" -v system_color="$SYSTEM_COLOR" \ -v current_color="$CURRENT_COLOR" -v default_color="$DEFAULT_COLOR" \ -v old_lts_color="$DEFAULT_COLOR" -v has_colors="$NVM_HAS_COLORS" \ @@ -4220,22 +4482,33 @@ nvm_ls_cached() { NVM_ARCH="$(nvm_get_arch)" local SUFFIX SUFFIX="${NVM_OS}-${NVM_ARCH}" + local NVM_CACHED_PATTERN + NVM_CACHED_PATTERN="$(nvm_ensure_version_prefix "${PATTERN:-.*}")" + # a release, like v27.0.0, is not one of its alphas + local NVM_CACHED_RELEASE + NVM_CACHED_RELEASE='v-' + case "${NVM_CACHED_PATTERN}" in + *-*) ;; + v[0-9]*.[0-9]*.[0-9]*) NVM_CACHED_RELEASE="${NVM_CACHED_PATTERN}" ;; + esac { if [ -d "${NVM_CACHE_DIR}/bin" ]; then # shellcheck disable=SC2010 command ls -1 "${NVM_CACHE_DIR}/bin" \ - | nvm_grep "^\\(node\\|iojs\\)-v[0-9][0-9.]*-${SUFFIX}\$" \ + | nvm_grep "^\\(node\\|iojs\\)-v[0-9][0-9.]*\\(-alpha\\.[0-9][0-9.]*\\)\\{0,1\\}-${SUFFIX}\$" \ | command sed "s/-${SUFFIX}\$//" fi if [ -d "${NVM_CACHE_DIR}/src" ]; then # shellcheck disable=SC2010 command ls -1 "${NVM_CACHE_DIR}/src" \ - | nvm_grep "^\\(node\\|iojs\\)-v[0-9][0-9.]*\$" + | nvm_grep "^\\(node\\|iojs\\)-v[0-9][0-9.]*\\(-alpha\\.[0-9][0-9.]*\\)\\{0,1\\}\$" fi } \ | command sed 's/^node-//' \ - | nvm_grep -w "$(nvm_ensure_version_prefix "${PATTERN:-.*}")" \ - | command sort -t. -u -k 1.2,1n -k 2,2n -k 3,3n + | nvm_grep -w "${NVM_CACHED_PATTERN}" \ + | nvm_grep -v "^${NVM_CACHED_RELEASE}-" \ + | nvm_filter_installed_versions \ + | nvm_sort_versions } # args: pattern @@ -4338,6 +4611,10 @@ nvm() { nvm_echo nvm_echo ' Any options that produce colorized output should respect the `--no-colors` option.' nvm_echo + nvm_echo ' Every version belongs to one category: alpha, lts, non-lts, or iojs. Commands that select or list versions' + nvm_echo ' accept `--only=`, a comma-separated list of the categories to select from. It defaults to' + nvm_echo ' `$NVM_ONLY` when set, and otherwise to every category except alpha: `lts,non-lts,iojs`.' + nvm_echo nvm_echo 'Usage:' nvm_echo ' nvm --help Show this message' nvm_echo ' --no-colors Suppress colored output' @@ -4350,6 +4627,7 @@ nvm() { 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' + nvm_echo ' --only= Only select from these version categories (see above)' nvm_echo ' --skip-default-packages When installing, skip the default-packages file if it exists' nvm_echo ' --latest-npm After installing, attempt to upgrade to the latest working npm on the given node version' nvm_echo ' --no-progress Disable the progress bar on any downloads' @@ -4360,34 +4638,42 @@ nvm() { nvm_echo ' nvm uninstall Uninstall a version' nvm_echo ' nvm uninstall --lts Uninstall using automatic LTS (long-term support) alias `lts/*`, if available.' nvm_echo ' nvm uninstall --lts= Uninstall using automatic alias for provided LTS line, if available.' + nvm_echo ' --only= Only select from these version categories (see above)' nvm_echo ' nvm use [current | ] Modify PATH to use . Uses .nvmrc if version is omitted; otherwise errors.' nvm_echo ' The following optional arguments, if provided, must appear directly after `nvm use`:' nvm_echo ' --silent Silences stdout/stderr output' nvm_echo ' --lts Uses automatic LTS (long-term support) alias `lts/*`, if available.' nvm_echo ' --lts= Uses automatic alias for provided LTS line, if available.' + nvm_echo ' --only= Only select from these version categories (see above)' nvm_echo ' --save Writes the specified version to .nvmrc.' nvm_echo ' nvm exec [current | ] [] Run on . Uses .nvmrc if version is omitted; otherwise errors.' nvm_echo ' The following optional arguments, if provided, must appear directly after `nvm exec`:' nvm_echo ' --silent Silences stdout/stderr output' nvm_echo ' --lts Uses automatic LTS (long-term support) alias `lts/*`, if available.' nvm_echo ' --lts= Uses automatic alias for provided LTS line, if available.' + nvm_echo ' --only= Only select from these version categories (see above)' nvm_echo ' nvm run [current | ] [] Run `node` on with as arguments. Uses .nvmrc if version is omitted; otherwise errors.' nvm_echo ' The following optional arguments, if provided, must appear directly after `nvm run`:' nvm_echo ' --silent Silences stdout/stderr output' nvm_echo ' --lts Uses automatic LTS (long-term support) alias `lts/*`, if available.' nvm_echo ' --lts= Uses automatic alias for provided LTS line, if available.' + nvm_echo ' --only= Only select from these version categories (see above)' nvm_echo ' nvm current Display the active node version (resolved via $PATH; not affected by .nvmrc).' nvm_echo ' nvm ls [] List installed versions, matching a given if provided' nvm_echo ' --no-colors Suppress colored output' nvm_echo ' --no-alias Suppress `nvm alias` output' + nvm_echo ' --only= Only select from these version categories (see above)' nvm_echo ' nvm ls-remote [] List remote versions available for install, matching a given if provided' nvm_echo ' --lts When listing, only show LTS (long-term support) versions' nvm_echo ' --lts= When listing, only show versions for a specific LTS line' + nvm_echo ' --only= Only select from these version categories (see above)' nvm_echo ' --no-colors Suppress colored output' nvm_echo ' nvm version Resolve the given description to a single local version' + nvm_echo ' --only= Only select from these version categories (see above)' nvm_echo ' nvm version-remote Resolve the given description to a single remote version' nvm_echo ' --lts When listing, only select from LTS (long-term support) versions' nvm_echo ' --lts= When listing, only select from versions for a specific LTS line' + nvm_echo ' --only= Only select from these version categories (see above)' nvm_echo ' nvm deactivate Undo effects of `nvm` on current shell' nvm_echo ' --silent Silences stdout/stderr output' nvm_echo ' nvm alias [] Show all aliases beginning with ' @@ -4395,12 +4681,15 @@ nvm() { nvm_echo ' nvm alias Set an alias named pointing to ' nvm_echo ' --lts Only resolve to installed LTS (long-term support) versions' nvm_echo ' --lts= Only resolve to installed versions of a specific LTS line' + nvm_echo ' --only= Only resolve to installed versions in these categories (see above)' nvm_echo ' nvm unalias Deletes the alias named ' nvm_echo ' nvm install-latest-npm Attempt to upgrade to the latest working `npm` on the current node version' nvm_echo ' nvm reinstall-packages Reinstall global `npm` packages contained in to current version' + nvm_echo ' --only= Only select from these version categories (see above)' nvm_echo ' nvm unload Unload `nvm` from shell' nvm_echo ' nvm which [current | ] Display path to installed node version. Uses .nvmrc if version is omitted; otherwise errors.' nvm_echo ' --silent Silences stdout/stderr output when a version is omitted' + nvm_echo ' --only= Only select from these version categories (see above)' nvm_echo ' nvm cache dir Display path to the cache directory for nvm' nvm_echo ' nvm cache clear Empty cache directory for nvm' nvm_echo ' nvm set-colors [] Set five text colors using format "yMeBg". Available when supported.' @@ -4416,6 +4705,7 @@ nvm() { nvm_echo ' nvm install node Install the latest available version' nvm_echo ' nvm use node Use the latest version' nvm_echo ' nvm install --lts Install the latest LTS version' + nvm_echo ' nvm install --only=alpha 27 Install the latest alpha version of node 27' nvm_echo ' nvm use --lts Use the latest LTS version' nvm_echo nvm_echo ' nvm set-colors cgYmW Set text colors to cyan, green, bold yellow, magenta, and white' @@ -4437,6 +4727,11 @@ nvm() { VERSION='' local ADDITIONAL_PARAMETERS ADDITIONAL_PARAMETERS='' + # the number of `--only=` arguments, and the last one's value + local NVM_ONLY_FLAG_COUNT + NVM_ONLY_FLAG_COUNT=0 + local NVM_ONLY_FLAG + local NVM_ONLY_RESOLVED case $COMMAND in "cache") @@ -4633,6 +4928,11 @@ nvm() { LTS="${1##--lts=}" shift ;; + --only=*) + NVM_ONLY_FLAG="${1#--only=}" + NVM_ONLY_FLAG_COUNT=$((NVM_ONLY_FLAG_COUNT + 1)) + shift + ;; --latest-npm) NVM_UPGRADE_NPM=1 shift @@ -4663,7 +4963,6 @@ nvm() { nvm_err 'If --reinstall-packages-from is provided, it must point to an installed version of node.' return 6 fi - REINSTALL_PACKAGES_FROM="$(nvm_version "${PROVIDED_REINSTALL_PACKAGES_FROM}")" ||: shift ;; --copy-packages-from=*) @@ -4676,7 +4975,6 @@ nvm() { nvm_err 'If --copy-packages-from is provided, it must point to an installed version of node.' return 6 fi - REINSTALL_PACKAGES_FROM="$(nvm_version "${PROVIDED_REINSTALL_PACKAGES_FROM}")" ||: shift ;; --reinstall-packages-from | --copy-packages-from) @@ -4701,6 +4999,20 @@ nvm() { esac done + # like `--reinstall-packages-from`, `--only` may also follow the version, but is needed to resolve it + local NVM_INSTALL_ARG + for NVM_INSTALL_ARG in "$@"; do + case "${NVM_INSTALL_ARG}" in + --only=*) + NVM_ONLY_FLAG="${NVM_INSTALL_ARG#--only=}" + NVM_ONLY_FLAG_COUNT=$((NVM_ONLY_FLAG_COUNT + 1)) + ;; + esac + done + + # validate early; it's resolved again once `lts/*` versions have set LTS + NVM_ONLY_RESOLVED="$(NVM_NO_LTS_STATUS=1 nvm_resolve_only "${NVM_ONLY_FLAG_COUNT}" "${NVM_ONLY_FLAG-}" "${LTS-}")" || return $? + # 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. @@ -4755,6 +5067,19 @@ nvm() { ;; esac + # the version to reinstall packages from is already installed, so an LTS filter doesn't apply to it + # finding the version to install downloads index.tab, which records LTS status + local NVM_INSTALL_NO_LTS_STATUS + NVM_INSTALL_NO_LTS_STATUS=1 + if [ "${NVM_OFFLINE}" = 1 ]; then + NVM_INSTALL_NO_LTS_STATUS='' + fi + local NVM_ONLY_INSTALLED + NVM_ONLY_INSTALLED="$(NVM_NO_LTS_STATUS="${NVM_INSTALL_NO_LTS_STATUS}" nvm_resolve_only "${NVM_ONLY_FLAG_COUNT}" "${NVM_ONLY_FLAG-}" '')" || return $? + NVM_ONLY_RESOLVED="$(NVM_NO_LTS_STATUS="${NVM_INSTALL_NO_LTS_STATUS}" nvm_resolve_only "${NVM_ONLY_FLAG_COUNT}" "${NVM_ONLY_FLAG-}" "${LTS-}")" || return $? + local NVM_ONLY_SELECTED + NVM_ONLY_SELECTED="${NVM_ONLY_RESOLVED}" + local EXIT_CODE if [ "${NVM_OFFLINE}" = 1 ]; then @@ -4804,6 +5129,39 @@ nvm() { else nvm_err "Version '${provided_version}' ${LTS_MSG-}not found - try \`${REMOTE_CMD}\` to browse available versions." fi + # look again in only the categories that weren't selected + local NVM_EXCLUDED_CATEGORIES + NVM_EXCLUDED_CATEGORIES='' + local NVM_EXCLUDED_CATEGORY + for NVM_EXCLUDED_CATEGORY in alpha lts non-lts iojs; do + nvm_only_includes "${NVM_EXCLUDED_CATEGORY}" || NVM_EXCLUDED_CATEGORIES="${NVM_EXCLUDED_CATEGORIES:+${NVM_EXCLUDED_CATEGORIES},}${NVM_EXCLUDED_CATEGORY}" + done + # every alpha is a vN.0.0, so other versions can't match one + if [ "${NVM_EXCLUDED_CATEGORIES}" = 'alpha' ]; then + case "${provided_version#v}" in + *[!0-9.]*) ;; + *.*.*) + case "${provided_version#v}" in + *.0.0) ;; + *) NVM_EXCLUDED_CATEGORIES='' ;; + esac + ;; + *.*) + case "${provided_version#v}" in + *.0) ;; + *) NVM_EXCLUDED_CATEGORIES='' ;; + esac + ;; + esac + fi + if [ "${NVM_OFFLINE}" != 1 ] && [ -z "${LTS-}" ] && [ -n "${NVM_EXCLUDED_CATEGORIES}" ]; then + local NVM_EXCLUDED_VERSION + NVM_EXCLUDED_VERSION="$(NVM_ONLY_SELECTED="${NVM_EXCLUDED_CATEGORIES}" NVM_VERSION_ONLY=true nvm_remote_version "${provided_version}" 2>/dev/null)" ||: + if [ "_${NVM_EXCLUDED_VERSION:-N/A}" != '_N/A' ]; then + nvm_err "It matches ${NVM_EXCLUDED_VERSION}, which is excluded by the selected version categories (${NVM_ONLY_SELECTED})." + nvm_err 'Include its category with `--only=`, or in `$NVM_ONLY`.' + fi + fi return 3 fi @@ -4821,7 +5179,6 @@ nvm() { nvm_err 'If --reinstall-packages-from is provided, it must point to an installed version of node.' return 6 fi - REINSTALL_PACKAGES_FROM="$(nvm_version "${PROVIDED_REINSTALL_PACKAGES_FROM}")" ||: ;; --copy-packages-from=*) if [ -n "${PROVIDED_REINSTALL_PACKAGES_FROM-}" ]; then @@ -4833,7 +5190,6 @@ nvm() { nvm_err 'If --copy-packages-from is provided, it must point to an installed version of node.' return 6 fi - REINSTALL_PACKAGES_FROM="$(nvm_version "${PROVIDED_REINSTALL_PACKAGES_FROM}")" ||: ;; --reinstall-packages-from | --copy-packages-from) nvm_err "If ${1} is provided, it must point to an installed version of node using \`=\`." @@ -4842,6 +5198,7 @@ nvm() { --skip-default-packages) SKIP_DEFAULT_PACKAGES=true ;; + --only=*) ;; *) ADDITIONAL_PARAMETERS="${ADDITIONAL_PARAMETERS} $1" ;; @@ -4849,10 +5206,17 @@ nvm() { shift done + if [ -n "${PROVIDED_REINSTALL_PACKAGES_FROM-}" ]; then + REINSTALL_PACKAGES_FROM="$(NVM_ONLY_SELECTED="${NVM_ONLY_INSTALLED}" nvm_version "${PROVIDED_REINSTALL_PACKAGES_FROM}")" ||: + fi + if [ -n "${PROVIDED_REINSTALL_PACKAGES_FROM-}" ] && [ "$(nvm_ensure_version_prefix "${PROVIDED_REINSTALL_PACKAGES_FROM}")" = "${VERSION}" ]; then nvm_err "You can't reinstall global packages from the same version of node you're installing." return 4 elif [ "${REINSTALL_PACKAGES_FROM-}" = 'N/A' ]; then + if NVM_ONLY_SELECTED="${NVM_ONLY_INSTALLED}" nvm_explain_excluded_version "${PROVIDED_REINSTALL_PACKAGES_FROM}"; then + return 5 + fi nvm_err "If --reinstall-packages-from is provided, it must point to an installed version of node." return 5 fi @@ -4879,7 +5243,7 @@ nvm() { nvm_install_default_packages fi if [ $EXIT_CODE -eq 0 ] && [ -n "${REINSTALL_PACKAGES_FROM-}" ] && [ "_${REINSTALL_PACKAGES_FROM}" != "_N/A" ]; then - nvm reinstall-packages "${REINSTALL_PACKAGES_FROM}" + nvm reinstall-packages "--only=${NVM_ONLY_INSTALLED}" "${REINSTALL_PACKAGES_FROM}" EXIT_CODE=$? fi fi @@ -4996,7 +5360,7 @@ nvm() { nvm_install_default_packages fi if [ $EXIT_CODE -eq 0 ] && [ -n "${REINSTALL_PACKAGES_FROM-}" ] && [ "_${REINSTALL_PACKAGES_FROM}" != "_N/A" ]; then - nvm reinstall-packages "${REINSTALL_PACKAGES_FROM}" + nvm reinstall-packages "--only=${NVM_ONLY_INSTALLED}" "${REINSTALL_PACKAGES_FROM}" EXIT_CODE=$? fi else @@ -5007,7 +5371,23 @@ nvm() { return $EXIT_CODE ;; "uninstall") - if [ $# -ne 1 ]; then + local PATTERN + local NVM_UNINSTALL_ARGS + NVM_UNINSTALL_ARGS=0 + while [ $# -ne 0 ]; do + case "${1}" in + --only=*) + NVM_ONLY_FLAG="${1#--only=}" + NVM_ONLY_FLAG_COUNT=$((NVM_ONLY_FLAG_COUNT + 1)) + ;; + *) + PATTERN="${1}" + NVM_UNINSTALL_ARGS=$((NVM_UNINSTALL_ARGS + 1)) + ;; + esac + shift + done + if [ "${NVM_UNINSTALL_ARGS}" -ne 1 ]; then nvm_err 'Usage: nvm uninstall ' nvm_err ' nvm uninstall --lts' nvm_err ' nvm uninstall --lts=' @@ -5015,8 +5395,17 @@ nvm() { return 127 fi - local PATTERN - PATTERN="${1-}" + case "${PATTERN}" in + --lts | --lts=* | lts/*) + NVM_ONLY_RESOLVED="$(nvm_resolve_only "${NVM_ONLY_FLAG_COUNT}" "${NVM_ONLY_FLAG-}" '*')" || return $? + ;; + *) + NVM_ONLY_RESOLVED="$(nvm_resolve_only "${NVM_ONLY_FLAG_COUNT}" "${NVM_ONLY_FLAG-}" '')" || return $? + ;; + esac + local NVM_ONLY_SELECTED + NVM_ONLY_SELECTED="${NVM_ONLY_RESOLVED}" + case "${PATTERN-}" in --) ;; --lts | 'lts/*') @@ -5043,6 +5432,9 @@ nvm() { fi if ! nvm_is_version_installed "${VERSION}"; then + if nvm_explain_excluded_version "${PATTERN}"; then + return 1 + fi local REQUESTED_VERSION REQUESTED_VERSION="${PATTERN}" if [ "_${VERSION}" != "_N/A" ] && [ "_${VERSION}" != "_${PATTERN}" ]; then @@ -5198,6 +5590,10 @@ nvm() { ;; --lts) NVM_LTS='*' ;; --lts=*) NVM_LTS="${1##--lts=}" ;; + --only=*) + NVM_ONLY_FLAG="${1#--only=}" + NVM_ONLY_FLAG_COUNT=$((NVM_ONLY_FLAG_COUNT + 1)) + ;; --save | -w) if [ $NVM_WRITE_TO_NVMRC -eq 1 ]; then nvm_err '--save and -w may only be provided once' @@ -5215,12 +5611,23 @@ nvm() { shift done + # an `lts/` version is an LTS selection, like `--lts` + local NVM_LTS_REQUEST + NVM_LTS_REQUEST='' + case "${PROVIDED_VERSION-}" in + lts/*) NVM_LTS_REQUEST='*' ;; + esac + NVM_ONLY_RESOLVED="$(nvm_resolve_only "${NVM_ONLY_FLAG_COUNT}" "${NVM_ONLY_FLAG-}" "${NVM_LTS:-${NVM_LTS_REQUEST}}")" || return $? + local NVM_ONLY_SELECTED + NVM_ONLY_SELECTED="${NVM_ONLY_RESOLVED}" + if [ -n "${NVM_LTS-}" ]; then VERSION="$(nvm_match_version "lts/${NVM_LTS:-*}")" elif [ -z "${PROVIDED_VERSION-}" ]; then { PROVIDED_VERSION="$(NVM_SILENT="${NVM_SILENT:-0}" nvm_rc_version 3>&1 1>&4)"; } 4>&1 if [ -n "${PROVIDED_VERSION}" ]; then IS_VERSION_FROM_NVMRC=1 + nvm_select_lts_from_nvmrc "${PROVIDED_VERSION}" || return $? VERSION="$(nvm_version "${PROVIDED_VERSION}")" fi if [ -z "${VERSION}" ]; then @@ -5234,6 +5641,11 @@ nvm() { VERSION="$(nvm_match_version "${PROVIDED_VERSION}")" fi + # a version that resolved, maybe through an alias with its own flags, to an installed one is used as is + if nvm_is_version_installed "${VERSION}"; then + NVM_USE_EXACT_INSTALLED=1 + fi + if [ -z "${VERSION}" ]; then nvm_err 'Usage: nvm use []' nvm_err ' Provide a , or run from a directory containing an .nvmrc file.' @@ -5243,6 +5655,10 @@ nvm() { if [ $NVM_WRITE_TO_NVMRC -eq 1 ]; then nvm_write_nvmrc "${VERSION}" + # .nvmrc can't store the categories that selected this version + if ! NVM_ONLY_SELECTED='' nvm_is_version_selected "${VERSION}" 2>/dev/null; then + nvm_err "Warning: ${VERSION} is not in the default version categories (${NVM_ONLY:-lts,non-lts,iojs}), so using .nvmrc needs \`--only=\`, or \`\$NVM_ONLY\`, to include it." + fi fi if [ "_${VERSION}" = '_system' ]; then @@ -5348,6 +5764,11 @@ nvm() { ;; --lts) NVM_LTS='*' ; shift ;; --lts=*) NVM_LTS="${1##--lts=}" ; shift ;; + --only=*) + NVM_ONLY_FLAG="${1#--only=}" + NVM_ONLY_FLAG_COUNT=$((NVM_ONLY_FLAG_COUNT + 1)) + shift + ;; *) if [ -n "$1" ]; then break @@ -5358,14 +5779,28 @@ nvm() { esac done + # an `lts/` version is an LTS selection, like `--lts` + local NVM_LTS_REQUEST + NVM_LTS_REQUEST='' + case "${1-}" in + lts/*) NVM_LTS_REQUEST='*' ;; + esac + NVM_ONLY_RESOLVED="$(nvm_resolve_only "${NVM_ONLY_FLAG_COUNT}" "${NVM_ONLY_FLAG-}" "${NVM_LTS:-${NVM_LTS_REQUEST}}")" || return $? + local NVM_ONLY_SELECTED + NVM_ONLY_SELECTED="${NVM_ONLY_RESOLVED}" + if [ $# -lt 1 ] && [ -z "${NVM_LTS-}" ]; then local NVM_RC_VERSION NVM_RC_VERSION='' { NVM_RC_VERSION="$(NVM_SILENT="${NVM_SILENT:-0}" nvm_rc_version 3>&1 1>&4)"; } 4>&1 && has_checked_nvmrc=1 if [ -n "${NVM_RC_VERSION}" ]; then + nvm_select_lts_from_nvmrc "${NVM_RC_VERSION}" || return $? VERSION="$(nvm_version "${NVM_RC_VERSION}")" ||: fi if [ "${VERSION:-N/A}" = 'N/A' ]; then + if [ -n "${NVM_RC_VERSION}" ] && nvm_explain_excluded_version "${NVM_RC_VERSION}"; then + return 127 + fi nvm_err 'Usage: nvm run [] []' nvm_err ' Provide a , or run from a directory containing an .nvmrc file.' nvm_err ' Run `nvm --help` for full help.' @@ -5392,6 +5827,7 @@ nvm() { fi provided_version="${NVM_RC_VERSION}" IS_VERSION_FROM_NVMRC=1 + nvm_select_lts_from_nvmrc "${NVM_RC_VERSION}" || return $? VERSION="$(nvm_version "${NVM_RC_VERSION}")" ||: else shift @@ -5414,6 +5850,10 @@ nvm() { LTS_ARG="--lts=${NVM_LTS-}" VERSION='' fi + if [ -n "${VERSION}" ] && [ "_${VERSION}" != '_N/A' ]; then + # the version is selected, maybe by an alias's own flags, so using it needs no other check + NVM_ONLY_SELECTED='alpha,lts,non-lts,iojs' + fi if [ "_${VERSION}" = "_N/A" ]; then nvm_ensure_version_installed "${provided_version}" "${IS_VERSION_FROM_NVMRC}" elif [ "${NVM_IOJS}" = true ]; then @@ -5434,6 +5874,11 @@ nvm() { --silent) NVM_SILENT=1 ; shift ;; --lts) NVM_LTS='*' ; shift ;; --lts=*) NVM_LTS="${1##--lts=}" ; shift ;; + --only=*) + NVM_ONLY_FLAG="${1#--only=}" + NVM_ONLY_FLAG_COUNT=$((NVM_ONLY_FLAG_COUNT + 1)) + shift + ;; --) break ;; --*) nvm_err "Unsupported option \"$1\"." @@ -5449,6 +5894,16 @@ nvm() { esac done + # an `lts/` version is an LTS selection, like `--lts` + local NVM_LTS_REQUEST + NVM_LTS_REQUEST='' + case "${1-}" in + lts/*) NVM_LTS_REQUEST='*' ;; + esac + NVM_ONLY_RESOLVED="$(nvm_resolve_only "${NVM_ONLY_FLAG_COUNT}" "${NVM_ONLY_FLAG-}" "${NVM_LTS:-${NVM_LTS_REQUEST}}")" || return $? + local NVM_ONLY_SELECTED + NVM_ONLY_SELECTED="${NVM_ONLY_RESOLVED}" + local provided_version provided_version="$1" local VERSION_SOURCE @@ -5461,6 +5916,7 @@ nvm() { VERSION="$(nvm_version "${provided_version}")" ||: if [ "_${VERSION}" = '_N/A' ] && ! nvm_is_valid_version "${provided_version}"; then { provided_version="$(NVM_SILENT="${NVM_SILENT:-0}" nvm_rc_version 3>&1 1>&4)"; } 4>&1 && has_checked_nvmrc=1 + nvm_select_lts_from_nvmrc "${provided_version}" || return $? VERSION="$(nvm_version "${provided_version}")" ||: if [ -n "${provided_version}" ]; then VERSION_SOURCE='nvmrc' @@ -5487,6 +5943,8 @@ nvm() { # shellcheck disable=SC2086 return $EXIT_CODE fi + # the version is selected, maybe by an alias's own flags, so using it needs no other check + NVM_ONLY_SELECTED='alpha,lts,non-lts,iojs' if [ "${NVM_SILENT:-0}" -ne 1 ]; then if [ "${NVM_LTS-}" = '*' ]; then @@ -5499,7 +5957,7 @@ nvm() { nvm_echo "Running node ${VERSION}$(nvm use --silent "${VERSION}" && nvm_print_npm_version)" fi fi - NODE_VERSION="${VERSION}" "${NVM_DIR}/nvm-exec" "$@" + NVM_ONLY_SELECTED="${NVM_ONLY_SELECTED}" NODE_VERSION="${VERSION}" "${NVM_DIR}/nvm-exec" "$@" ;; "ls" | "list") local PATTERN @@ -5514,6 +5972,10 @@ nvm() { --) ;; --no-colors) NVM_NO_COLORS="${1}" ;; --no-alias) NVM_NO_ALIAS="${1}" ;; + --only=*) + NVM_ONLY_FLAG="${1#--only=}" + NVM_ONLY_FLAG_COUNT=$((NVM_ONLY_FLAG_COUNT + 1)) + ;; --*) nvm_err "Unsupported option \"${1}\"." return 55 @@ -5528,6 +5990,9 @@ nvm() { nvm_err '`--no-alias` is not supported when a pattern is provided.' return 55 fi + NVM_ONLY_RESOLVED="$(nvm_resolve_only "${NVM_ONLY_FLAG_COUNT}" "${NVM_ONLY_FLAG-}" "")" || return $? + local NVM_ONLY_SELECTED + NVM_ONLY_SELECTED="${NVM_ONLY_RESOLVED}" local NVM_LS_OUTPUT local NVM_LS_EXIT_CODE NVM_LS_OUTPUT=$(nvm_ls "${PATTERN-}") @@ -5559,6 +6024,10 @@ nvm() { --lts=*) NVM_LTS="${1##--lts=}" ;; + --only=*) + NVM_ONLY_FLAG="${1#--only=}" + NVM_ONLY_FLAG_COUNT=$((NVM_ONLY_FLAG_COUNT + 1)) + ;; --no-colors) NVM_NO_COLORS="${1}" ;; --*) nvm_err "Unsupported option \"${1}\"." @@ -5585,6 +6054,10 @@ nvm() { shift done + NVM_ONLY_RESOLVED="$(NVM_NO_LTS_STATUS=1 nvm_resolve_only "${NVM_ONLY_FLAG_COUNT}" "${NVM_ONLY_FLAG-}" "${NVM_LTS-}")" || return $? + local NVM_ONLY_SELECTED + NVM_ONLY_SELECTED="${NVM_ONLY_RESOLVED}" + local NVM_OUTPUT local EXIT_CODE NVM_OUTPUT="$(NVM_LTS="${NVM_LTS-}" nvm_remote_versions "${PATTERN-}" &&:)" @@ -5616,13 +6089,27 @@ nvm() { case "${1}" in --silent) NVM_SILENT=1 ;; --) ;; + --only=*) + NVM_ONLY_FLAG="${1#--only=}" + NVM_ONLY_FLAG_COUNT=$((NVM_ONLY_FLAG_COUNT + 1)) + ;; *) provided_version="${1-}" ;; esac shift done + # an `lts/` version is an LTS selection, like `--lts` + local NVM_LTS_REQUEST + NVM_LTS_REQUEST='' + case "${provided_version-}" in + lts/*) NVM_LTS_REQUEST='*' ;; + esac + NVM_ONLY_RESOLVED="$(nvm_resolve_only "${NVM_ONLY_FLAG_COUNT}" "${NVM_ONLY_FLAG-}" "${NVM_LTS_REQUEST}")" || return $? + local NVM_ONLY_SELECTED + NVM_ONLY_SELECTED="${NVM_ONLY_RESOLVED}" if [ -z "${provided_version-}" ]; then { provided_version="$(NVM_SILENT="${NVM_SILENT:-0}" nvm_rc_version 3>&1 1>&4)"; } 4>&1 if [ -n "${provided_version}" ]; then + nvm_select_lts_from_nvmrc "${provided_version}" || return $? VERSION=$(nvm_version "${provided_version}") ||: fi elif [ "${provided_version}" != 'system' ]; then @@ -5702,6 +6189,10 @@ nvm() { esac NVM_ALIAS_FLAGS="${1}" ;; + --only=*) + NVM_ONLY_FLAG="${1#--only=}" + NVM_ONLY_FLAG_COUNT=$((NVM_ONLY_FLAG_COUNT + 1)) + ;; --*) nvm_err "Unsupported option \"${1}\"." return 55 @@ -5716,6 +6207,10 @@ nvm() { esac shift done + # resolving the alias's target checks for recorded LTS status, if it needs it + NVM_ONLY_RESOLVED="$(NVM_NO_LTS_STATUS=1 nvm_resolve_only "${NVM_ONLY_FLAG_COUNT}" "${NVM_ONLY_FLAG-}" "${NVM_ALIAS_FLAGS}")" || return $? + local NVM_ONLY_SELECTED + NVM_ONLY_SELECTED="${NVM_ONLY_RESOLVED}" if [ -z "${TARGET}" ]; then # for some reason the empty string was explicitly passed as the target @@ -5731,9 +6226,12 @@ nvm() { nvm_err 'Aliases in subdirectories are not supported.' return 1 fi + if [ "${NVM_ONLY_FLAG_COUNT}" -gt 0 ]; then + NVM_ALIAS_FLAGS="--only=$(nvm_normalize_only "${NVM_ONLY_FLAG}" '`--only`')${NVM_ALIAS_FLAGS:+ ${NVM_ALIAS_FLAGS}}" + fi TARGET="${NVM_ALIAS_FLAGS:+${NVM_ALIAS_FLAGS} }${TARGET}" VERSION="$(nvm_version "${TARGET}")" ||: - if [ "${VERSION}" = 'N/A' ]; then + if [ "${VERSION}" = 'N/A' ] && ! nvm_explain_excluded_version "${TARGET}"; then nvm_err "! WARNING: Version '${TARGET}' does not exist." fi nvm_make_alias "${ALIAS}" "${TARGET}" @@ -5812,14 +6310,30 @@ nvm() { nvm_install_latest_npm ;; "reinstall-packages" | "copy-packages") - if [ $# -ne 1 ]; then + local PROVIDED_VERSION + local NVM_REINSTALL_ARGS + NVM_REINSTALL_ARGS=0 + while [ $# -ne 0 ]; do + case "${1}" in + --only=*) + NVM_ONLY_FLAG="${1#--only=}" + NVM_ONLY_FLAG_COUNT=$((NVM_ONLY_FLAG_COUNT + 1)) + ;; + *) + PROVIDED_VERSION="${1}" + NVM_REINSTALL_ARGS=$((NVM_REINSTALL_ARGS + 1)) + ;; + esac + shift + done + if [ "${NVM_REINSTALL_ARGS}" -ne 1 ]; then nvm_err "Usage: nvm ${COMMAND} " nvm_err ' Run `nvm --help` for full help.' return 127 fi - - local PROVIDED_VERSION - PROVIDED_VERSION="${1-}" + NVM_ONLY_RESOLVED="$(nvm_resolve_only "${NVM_ONLY_FLAG_COUNT}" "${NVM_ONLY_FLAG-}" "")" || return $? + local NVM_ONLY_SELECTED + NVM_ONLY_SELECTED="${NVM_ONLY_RESOLVED}" if [ "${PROVIDED_VERSION}" = "$(nvm_ls_current)" ] || [ "$(nvm_version "${PROVIDED_VERSION}" ||:)" = "$(nvm_ls_current)" ]; then nvm_err 'Can not reinstall packages from the current version of node.' @@ -5834,6 +6348,9 @@ nvm() { VERSION="system" else VERSION="$(nvm_version "${PROVIDED_VERSION}")" ||: + if [ "_${VERSION}" = '_N/A' ] && nvm_explain_excluded_version "${PROVIDED_VERSION}"; then + return 3 + fi fi local NPMLIST @@ -5874,7 +6391,22 @@ nvm() { nvm_echo 'nvm cache cleared.' ;; "version") - nvm_version "${1}" + local PATTERN + PATTERN='' + while [ $# -gt 0 ]; do + case "${1}" in + --only=*) + NVM_ONLY_FLAG="${1#--only=}" + NVM_ONLY_FLAG_COUNT=$((NVM_ONLY_FLAG_COUNT + 1)) + ;; + *) PATTERN="${PATTERN:-${1}}" ;; + esac + shift + done + NVM_ONLY_RESOLVED="$(nvm_resolve_only "${NVM_ONLY_FLAG_COUNT}" "${NVM_ONLY_FLAG-}" "")" || return $? + local NVM_ONLY_SELECTED + NVM_ONLY_SELECTED="${NVM_ONLY_RESOLVED}" + nvm_version "${PATTERN-}" ;; "version-remote") local NVM_LTS @@ -5890,6 +6422,10 @@ nvm() { --lts=*) NVM_LTS="${1##--lts=}" ;; + --only=*) + NVM_ONLY_FLAG="${1#--only=}" + NVM_ONLY_FLAG_COUNT=$((NVM_ONLY_FLAG_COUNT + 1)) + ;; --*) nvm_err "Unsupported option \"${1}\"." return 55 @@ -5910,6 +6446,9 @@ nvm() { unset PATTERN ;; esac + NVM_ONLY_RESOLVED="$(NVM_NO_LTS_STATUS=1 nvm_resolve_only "${NVM_ONLY_FLAG_COUNT}" "${NVM_ONLY_FLAG-}" "${NVM_LTS-}")" || return $? + local NVM_ONLY_SELECTED + NVM_ONLY_SELECTED="${NVM_ONLY_RESOLVED}" NVM_VERSION_ONLY=true NVM_LTS="${NVM_LTS-}" nvm_remote_version "${PATTERN:-node}" ;; "--version" | "-v") @@ -5924,6 +6463,8 @@ nvm() { nvm_ls_remote nvm_ls_remote_iojs nvm_ls_remote_index_tab nvm_get_remote_aliases \ nvm_ls nvm_remote_version nvm_remote_versions nvm_sort_versions \ nvm_lts_status_path nvm_record_lts_status nvm_ensure_lts_status nvm_filter_lts_versions \ + nvm_is_alpha_version nvm_normalize_only nvm_resolve_only nvm_only_includes nvm_explain_excluded_version nvm_select_lts_from_nvmrc \ + nvm_needs_lts_status nvm_filter_installed_versions nvm_is_version_selected \ nvm_install_binary nvm_install_source nvm_clang_version \ nvm_get_mirror nvm_get_download_slug nvm_download_artifact nvm_is_cached_artifact \ nvm_install_npm_if_needed nvm_use_if_needed nvm_check_file_permissions \ @@ -6089,6 +6630,13 @@ nvm_auto() { # don't download anything while a shell starts up local NVM_INDEX_NO_FETCH NVM_INDEX_NO_FETCH=1 + if [ -n "${NVM_ONLY-}" ] && ! nvm_normalize_only "${NVM_ONLY}" '`$NVM_ONLY`' >/dev/null; then + return 55 + fi + if nvm_needs_lts_status "${NVM_ONLY-}" && [ ! -f "$(nvm_lts_status_path)" ]; then + nvm_err 'The LTS status of installed versions is not recorded yet; run `nvm ls-remote` to record it.' + return 3 + fi local VERSION local NVM_CURRENT NVM_CURRENT="$(nvm_ls_current)" @@ -6096,41 +6644,59 @@ nvm_auto() { VERSION="$(nvm_resolve_local_alias default 2>/dev/null || nvm_echo)" if [ -n "${VERSION}" ]; then if [ "_${VERSION}" != '_N/A' ] && nvm_is_valid_version "${VERSION}"; then - nvm use --silent "${VERSION}" >/dev/null + # the default alias, and any flags it stores, have already selected this version + nvm use --silent --only=alpha,lts,non-lts,iojs "${VERSION}" >/dev/null else - case "$(nvm_resolve_alias default 2>/dev/null)" in - '--lts '* | --lts=*' '*) - if [ ! -f "$(nvm_lts_status_path)" ]; then - nvm_err 'The default alias needs the LTS status of installed versions, which is not recorded yet; run `nvm ls-remote` to record it.' - fi - ;; - esac + # a default alias whose flags need recorded LTS status can't get it while a shell starts up + local NVM_DEFAULT_TARGET + NVM_DEFAULT_TARGET="$(nvm_resolve_alias default 2>/dev/null ||:)" + local NVM_DEFAULT_NEEDS_LTS_STATUS + NVM_DEFAULT_NEEDS_LTS_STATUS=0 + local NVM_DEFAULT_ONLY + while :; do + case "${NVM_DEFAULT_TARGET}" in + '--lts '* | --lts=*' '*) NVM_DEFAULT_NEEDS_LTS_STATUS=1 ;; + --only=*' '*) + NVM_DEFAULT_ONLY="${NVM_DEFAULT_TARGET%% *}" + if nvm_needs_lts_status "${NVM_DEFAULT_ONLY#--only=}"; then + NVM_DEFAULT_NEEDS_LTS_STATUS=1 + fi + ;; + *) break ;; + esac + NVM_DEFAULT_TARGET="${NVM_DEFAULT_TARGET#* }" + done + # zsh 5.1's `set -e` exits on a failing `cmd || :` in an `else`, but not on a failing condition + if [ "${NVM_DEFAULT_NEEDS_LTS_STATUS}" = 1 ] && [ ! -f "$(nvm_lts_status_path)" ]; then + nvm_err 'The default alias needs the LTS status of installed versions, which is not recorded yet; run `nvm ls-remote` to record it.' + elif nvm_explain_excluded_version default; then + : + fi return 0 fi elif nvm_rc_version 3>/dev/null >/dev/null 2>&1; then nvm use --silent >/dev/null fi else - nvm use --silent "${NVM_CURRENT}" >/dev/null + nvm use --silent --only=alpha,lts,non-lts,iojs "${NVM_CURRENT}" >/dev/null fi ;; install) local VERSION VERSION="$(nvm_alias default 2>/dev/null || nvm_echo)" - local NVM_DEFAULT_LTS - NVM_DEFAULT_LTS='' - case "${VERSION}" in - '--lts '* | --lts=*' '*) - NVM_DEFAULT_LTS="${VERSION%% *}" - VERSION="${VERSION#* }" - ;; - esac + # flags stored in the alias, like `--lts`, are arguments to `nvm install` + set -- + while :; do + case "${VERSION}" in + --*' '*) + set -- "$@" "${VERSION%% *}" + VERSION="${VERSION#* }" + ;; + *) break ;; + esac + done if [ -n "${VERSION}" ] && [ "_${VERSION}" != '_N/A' ] && nvm_is_valid_version "${VERSION}"; then - if [ -n "${NVM_DEFAULT_LTS}" ]; then - nvm install "${NVM_DEFAULT_LTS}" "${VERSION}" >/dev/null - else - nvm install "${VERSION}" >/dev/null - fi + nvm install "$@" "${VERSION}" >/dev/null elif nvm_rc_version 3>/dev/null >/dev/null 2>&1; then nvm install >/dev/null else diff --git a/test/fast/Aliases/an alias can store --only b/test/fast/Aliases/an alias can store --only new file mode 100755 index 00000000..cc9baa4a --- /dev/null +++ b/test/fast/Aliases/an alias can store --only @@ -0,0 +1,75 @@ +#!/bin/sh + +ORIG_NVM_DIR="${NVM_DIR}" +TMP_DIR='' + +cleanup () { + case "${TMP_DIR}" in + /*) rm -rf "${TMP_DIR}" ;; + esac + NVM_DIR="${ORIG_NVM_DIR}" + export NVM_DIR +} + +die () { echo "$@" ; cleanup ; exit 1; } + +: nvm.sh +\. ../../../nvm.sh + +\. ../../common.sh + +TMP_DIR="$(mktemp -d)" +NVM_DIR="${TMP_DIR}/nvm" +export NVM_DIR +mkdir -p "${NVM_DIR}/alias" || die 'could not create alias dir' +unset NVM_ONLY + +for VERSION in v24.11.0 v26.12.1 v27.0.0-alpha.1.2.0 v27.0.0-alpha.1.10.2; do + mkdir -p "${NVM_DIR}/versions/node/${VERSION}/bin" || die "fake node ${VERSION} could not be made" + make_echo "${NVM_DIR}/versions/node/${VERSION}/bin/node" "${VERSION}" +done +printf 'v26.12.1\t2026-10-21\tsrc\t-\t-\t-\t-\t-\t-\t-\t-\nv24.11.0\t2025-10-28\tsrc\t-\t-\t-\t-\t-\t-\tKrypton\t-\n' | nvm_record_lts_status || die 'could not record LTS status' + +nvm alias default --only=alpha node >/dev/null 2>&1 || die 'nvm alias default --only=alpha node failed' +[ "_$(cat "$(nvm_alias_path)/default")" = '_--only=alpha node' ] || die "the alias file should store >--only=alpha node<; got >$(cat "$(nvm_alias_path)/default")<" +[ "_$(nvm version default)" = '_v27.0.0-alpha.1.10.2' ] || die "default should be the latest installed alpha; got >$(nvm version default)<" +[ "_$(nvm version node)" = '_v26.12.1' ] || die "node itself should still exclude alphas; got >$(nvm version node)<" + +nvm use --silent default || die 'nvm use default should use the alpha that default selects' +[ "_$(nvm current)" = '_v27.0.0-alpha.1.10.2' ] || die "nvm current should be the alpha; got >$(nvm current)<" +nvm deactivate >/dev/null 2>&1 + +nvm_auto use || die 'nvm_auto use should use the alpha that default selects' +[ "_$(nvm current)" = '_v27.0.0-alpha.1.10.2' ] || die "a new shell should start with the alpha; got >$(nvm current)<" +nvm_auto use || die 'nvm_auto use should keep using the current alpha' +nvm deactivate >/dev/null 2>&1 + +NVM_ONLY='lts,non-lts' +nvm use --silent --only=alpha v27.0.0-alpha.1.2.0 || die 'nvm use --only=alpha should use an alpha' +[ "_${NVM_ONLY}" = '_lts,non-lts' ] || die "--only should not change NVM_ONLY; got >${NVM_ONLY}<" +[ -z "${NVM_ONLY_SELECTED-}" ] || die "a command's selection should not outlive it; got >${NVM_ONLY_SELECTED}<" +unset NVM_ONLY +nvm deactivate >/dev/null 2>&1 + +nvm alias both --only=lts,alpha --lts node >/dev/null 2>&1 || die 'nvm alias both --only=lts,alpha --lts node failed' +[ "_$(cat "$(nvm_alias_path)/both")" = '_--only=alpha,lts --lts node' ] || die "the alias file should store the normalized flags; got >$(cat "$(nvm_alias_path)/both")<" +[ "_$(nvm version both)" = '_v24.11.0' ] || die "both should be the latest installed LTS version; got >$(nvm version both)<" + +try_err nvm alias bad --only=alpha --lts node +[ "_${CAPTURED_EXIT_CODE}" = '_55' ] || die "--lts with an --only that excludes LTS should exit 55; got ${CAPTURED_EXIT_CODE}" +[ ! -e "$(nvm_alias_path)/bad" ] || die 'a conflicting alias should not be written' + +# a new shell survives `set -e` with a default that resolves to nothing +nvm_make_alias default v99.0.0 || die 'could not alias default' +(set -e; nvm_auto use 2>/dev/null; true) || die 'nvm_auto use should not fail with a default that resolves to nothing' + +# and explains a default whose flags need LTS status that isn't recorded yet +rm -f "$(nvm_lts_status_path)" +nvm_make_alias default '--only=lts node' || die 'could not alias default' +try_err nvm_auto use +[ "_${CAPTURED_STDERR}" = '_The default alias needs the LTS status of installed versions, which is not recorded yet; run `nvm ls-remote` to record it.' ] || die "nvm_auto use should explain the missing LTS status; got >${CAPTURED_STDERR}<" + +echo '--only=beta node' > "$(nvm_alias_path)/invalid" +[ "_$(nvm version invalid 2>/dev/null)" = '_N/A' ] || die "an alias with an invalid --only should not resolve; got >$(nvm version invalid 2>/dev/null)<" + +cleanup diff --git a/test/fast/Unit tests/nvm use and nvm which explain an excluded alpha b/test/fast/Unit tests/nvm use and nvm which explain an excluded alpha new file mode 100755 index 00000000..8c6ff682 --- /dev/null +++ b/test/fast/Unit tests/nvm use and nvm which explain an excluded alpha @@ -0,0 +1,63 @@ +#!/bin/sh + +ORIG_NVM_DIR="${NVM_DIR}" +TMP_DIR='' + +cleanup () { + case "${TMP_DIR}" in + /*) rm -rf "${TMP_DIR}" ;; + esac + NVM_DIR="${ORIG_NVM_DIR}" + export NVM_DIR +} + +die () { echo "$@" ; cleanup ; exit 1; } + +: nvm.sh +\. ../../../nvm.sh + +\. ../../common.sh + +TMP_DIR="$(mktemp -d)" +NVM_DIR="${TMP_DIR}/nvm" +export NVM_DIR +mkdir -p "${NVM_DIR}" || die 'could not create NVM_DIR' +unset NVM_ONLY + +ALPHA='v27.0.0-alpha.1.0.0' +ALPHA_BIN="${NVM_DIR}/versions/node/${ALPHA}/bin" +mkdir -p "${ALPHA_BIN}" || die 'fake alpha could not be made' +make_echo "${ALPHA_BIN}/node" "${ALPHA}" +make_fake_node v20.1.1 || die 'fake node v20.1.1 could not be made' +printf 'v20.1.1\t2023-01-01\tsrc\t-\t-\t-\t-\t-\t-\tIron\t-\n' | nvm_record_lts_status || die 'could not record LTS status' + +HINT='Include its category with `--only=`, or in `$NVM_ONLY`.' +for COMMAND in use which; do + for PAIR in "${ALPHA}:${ALPHA}" "27:27 -> ${ALPHA}"; do + try_err nvm "${COMMAND}" "${PAIR%%:*}" + [ "_${CAPTURED_EXIT_CODE}" != '_0' ] || die "nvm ${COMMAND} ${PAIR%%:*} should fail when alphas are excluded" + EXPECTED="N/A: version \"${PAIR#*:}\" is installed, but excluded by the selected version categories (lts,non-lts,iojs)." + [ "_$(echo "${CAPTURED_STDERR}" | strip_colors | head -1)" = "_${EXPECTED}" ] || die "nvm ${COMMAND} ${PAIR%%:*} printed >${CAPTURED_STDERR}<, expected >${EXPECTED}<" + case "${CAPTURED_STDERR}" in + *"${HINT}"*) ;; + *) die "nvm ${COMMAND} ${PAIR%%:*} did not print >${HINT}<; got >${CAPTURED_STDERR}<" ;; + esac + done +done + +try_err nvm which --only=lts "${ALPHA}" +EXPECTED="N/A: version \"${ALPHA}\" is installed, but excluded by the selected version categories (lts)." +[ "_$(echo "${CAPTURED_STDERR}" | strip_colors | head -1)" = "_${EXPECTED}" ] || die "nvm which --only=lts ${ALPHA} printed >${CAPTURED_STDERR}<, expected >${EXPECTED}<" + +[ "_$(nvm which --only=alpha "${ALPHA}")" = "_${ALPHA_BIN}/node" ] || die "nvm which --only=alpha ${ALPHA} should print its node path" +[ "_$(NVM_ONLY=alpha nvm which 27)" = "_${ALPHA_BIN}/node" ] || die 'NVM_ONLY=alpha nvm which 27 should print the alpha node path' + +nvm use --silent --only=alpha "${ALPHA}" || die "nvm use --only=alpha ${ALPHA} failed" +case ":${PATH}:" in + *":${ALPHA_BIN}:"*) ;; + *) die "nvm use --only=alpha did not put ${ALPHA_BIN} on PATH; got ${PATH}" ;; +esac +[ "_$(nvm current)" = "_${ALPHA}" ] || die "nvm current should be ${ALPHA}; got $(nvm current)" +nvm deactivate >/dev/null 2>&1 + +cleanup diff --git a/test/fast/Unit tests/nvm_filter_installed_versions b/test/fast/Unit tests/nvm_filter_installed_versions new file mode 100755 index 00000000..c9058e96 --- /dev/null +++ b/test/fast/Unit tests/nvm_filter_installed_versions @@ -0,0 +1,78 @@ +#!/bin/sh + +ORIG_NVM_DIR="${NVM_DIR}" +TMP_DIR='' + +cleanup () { + case "${TMP_DIR}" in + /*) rm -rf "${TMP_DIR}" ;; + esac + NVM_DIR="${ORIG_NVM_DIR}" + export NVM_DIR + unset NVM_ONLY + unset -f nvm_download +} + +die () { echo "$@" ; cleanup ; exit 1; } + +: nvm.sh +\. ../../../nvm.sh + +\. ../../common.sh + +TMP_DIR="$(mktemp -d)" +NVM_DIR="${TMP_DIR}/nvm" +export NVM_DIR +mkdir -p "${NVM_DIR}" || die 'could not create NVM_DIR' +unset NVM_ONLY + +DOWNLOADS="${TMP_DIR}/downloads" +nvm_download () { + echo "$*" >> "${DOWNLOADS}" + return 1 +} +downloads () { + if [ -f "${DOWNLOADS}" ]; then + wc -l < "${DOWNLOADS}" | tr -d ' ' + else + echo 0 + fi +} + +for VERSION in v21.0.0 v22.11.0 v27.0.0-alpha.1.0.0; do + mkdir -p "${NVM_DIR}/versions/node/${VERSION}/bin" || die "fake node ${VERSION} could not be made" + make_echo "${NVM_DIR}/versions/node/${VERSION}/bin/node" "${VERSION}" +done +make_fake_iojs v3.3.1 || die 'fake iojs could not be made' + +# without recorded LTS status, selecting only one of lts and non-lts fails rather than guess +try_err nvm ls --no-colors --only=lts +[ "_${CAPTURED_EXIT_CODE}" = '_3' ] || die "nvm ls --only=lts without recorded LTS status should exit 3; got ${CAPTURED_EXIT_CODE}" +[ "_${CAPTURED_STDERR}" = '_The LTS status of installed versions is not recorded yet; run `nvm ls-remote` to record it.' ] || die "got >${CAPTURED_STDERR}<" +[ "_$(downloads)" = '_1' ] || die "missing LTS status should be downloaded once; got $(downloads)" + +# so do internal lookups, rather than treat every version as non-LTS +OUTPUT="$(printf 'v21.0.0\nv22.11.0\n' | NVM_ONLY=non-lts nvm_filter_installed_versions 2>/dev/null)" +[ -z "${OUTPUT}" ] || die "nvm_filter_installed_versions without recorded LTS status should print nothing; got >${OUTPUT}<" +[ "_$(NVM_ONLY=non-lts nvm_version 21 2>/dev/null)" = '_N/A' ] || die 'NVM_ONLY=non-lts nvm_version 21 without recorded LTS status should be N/A' + +# selecting both, or neither, needs no LTS status +[ "_$(nvm ls --no-colors --no-alias --only=lts,non-lts | nvm_grep -v system | tr -d ' *' | tr '\n' ' ')" = '_v21.0.0 v22.11.0 ' ] || die 'nvm ls --only=lts,non-lts should list both' +[ "_$(nvm ls --no-colors --no-alias --only=alpha,iojs | nvm_grep -v system | tr -d ' *' | tr '\n' ' ')" = '_iojs-v3.3.1 v27.0.0-alpha.1.0.0 ' ] || die 'nvm ls --only=alpha,iojs should list the alpha and io.js' +[ "_$(downloads)" = '_1' ] || die "selecting both or neither of lts and non-lts should not download; got $(downloads)" + +printf 'v22.11.0\t2024-10-29\tsrc\t-\t-\t-\t-\t-\t-\tJod\t-\nv21.0.0\t2023-10-17\tsrc\t-\t-\t-\t-\t-\t-\t-\t-\n' | nvm_record_lts_status || die 'could not record LTS status' + +INPUT="$(printf 'system\nv21.0.0\nv22.11.0\nv23.0.0\nv27.0.0-alpha.1.0.0\niojs-v3.3.1\nN/A')" +for PAIR in 'lts:system v22.11.0 N/A ' 'non-lts:system v21.0.0 v23.0.0 N/A ' 'alpha:system v27.0.0-alpha.1.0.0 N/A ' 'iojs:system iojs-v3.3.1 N/A ' \ + 'lts,non-lts:system v21.0.0 v22.11.0 v23.0.0 N/A ' 'alpha,lts,non-lts,iojs:system v21.0.0 v22.11.0 v23.0.0 v27.0.0-alpha.1.0.0 iojs-v3.3.1 N/A '; do + OUTPUT="$(echo "${INPUT}" | NVM_ONLY="${PAIR%%:*}" nvm_filter_installed_versions | tr '\n' ' ')" + [ "_${OUTPUT}" = "_${PAIR#*:}" ] || die "NVM_ONLY=${PAIR%%:*} nvm_filter_installed_versions printed >${OUTPUT}<, expected >${PAIR#*:}<" +done + +[ "_$(nvm ls --no-colors --no-alias --only=lts | nvm_grep -v system | tr -d ' *')" = '_v22.11.0' ] || die 'nvm ls --only=lts should list the recorded LTS version' +[ "_$(nvm version --only=non-lts 21)" = '_v21.0.0' ] || die 'nvm version --only=non-lts 21 should be v21.0.0' +[ "_$(nvm version --only=lts 21)" = '_N/A' ] || die 'nvm version --only=lts 21 should be N/A' +[ "_$(downloads)" = '_1' ] || die "recorded LTS status should not be downloaded again; got $(downloads)" + +cleanup diff --git a/test/fast/Unit tests/nvm_is_alpha_version b/test/fast/Unit tests/nvm_is_alpha_version new file mode 100755 index 00000000..b9781a4e --- /dev/null +++ b/test/fast/Unit tests/nvm_is_alpha_version @@ -0,0 +1,16 @@ +#!/bin/sh + +die () { echo "$@" ; exit 1; } + +: nvm.sh +\. ../../../nvm.sh + +for VERSION in 'v27.0.0-alpha.0.0.0' 'v27.0.0-alpha.1.10.2' '27.0.0-alpha.1.2.0' 'v28.1.2-alpha.10.20.30'; do + nvm_is_alpha_version "${VERSION}" || die "${VERSION} should be an alpha version" +done + +for VERSION in '' 'v27.0.0' 'v27.0.0-alpha.1.0' 'v27.0.0-alpha.1' 'v27.0.0-alpha.1.0.0.0' 'v27.0.0-alpha.1..0' 'v27.0.0-alpha.1.0.0-' \ + 'v27.0-alpha.1.0.0' 'v27.0.0-alpha.' 'v27.0.0-alpha.a.b.c' 'v27.0.0-beta.1.0.0' 'iojs-v3.0.0' 'iojs-v27.0.0-alpha.1.0.0' \ + 'v11.0.0-nightly201810011be804d625' 'v24.0.0-rc.1' 'node' 'lts/*' 'system'; do + ! nvm_is_alpha_version "${VERSION}" || die "${VERSION} should not be an alpha version" +done diff --git a/test/fast/Unit tests/nvm_ls alpha b/test/fast/Unit tests/nvm_ls alpha new file mode 100755 index 00000000..3a9d2a09 --- /dev/null +++ b/test/fast/Unit tests/nvm_ls alpha @@ -0,0 +1,56 @@ +#!/bin/sh + +ORIG_NVM_DIR="${NVM_DIR}" +TMP_DIR='' + +cleanup () { + case "${TMP_DIR}" in + /*) rm -rf "${TMP_DIR}" ;; + esac + NVM_DIR="${ORIG_NVM_DIR}" + export NVM_DIR +} + +die () { echo "$@" ; cleanup ; exit 1; } + +: nvm.sh +\. ../../../nvm.sh + +\. ../../common.sh + +TMP_DIR="$(mktemp -d)" +NVM_DIR="${TMP_DIR}/nvm" +export NVM_DIR +mkdir -p "${NVM_DIR}" || die 'could not create NVM_DIR' +unset NVM_ONLY + +for VERSION in v26.12.1 v27.0.0 v27.0.0-alpha.1.1.1 v27.0.0-alpha.1.1.10 v27.0.0-alpha.1.2.0 v27.0.0-alpha.10.0.0 v27.0.0-alpha.20.0.10; do + mkdir -p "${NVM_DIR}/versions/node/${VERSION}/bin" || die "fake node ${VERSION} could not be made" + make_echo "${NVM_DIR}/versions/node/${VERSION}/bin/node" "${VERSION}" + nvm_is_version_installed "${VERSION}" || die "fake node ${VERSION} is not installed" +done + +check () { + EXPECTED="$1" + shift + OUTPUT="$(nvm_ls "$@" | nvm_grep -v '^system' | tr '\n' ' ')" + [ "_${OUTPUT}" = "_${EXPECTED}" ] || die "nvm_ls $* (NVM_ONLY=${NVM_ONLY-}) printed >${OUTPUT}<, expected >${EXPECTED}<" +} + +check 'v26.12.1 v27.0.0 ' +check 'v27.0.0 ' 27 +check 'N/A ' v27.0.0-alpha.1.1.1 + +NVM_ONLY=alpha +check 'v27.0.0-alpha.1.1.1 v27.0.0-alpha.1.1.10 v27.0.0-alpha.1.2.0 v27.0.0-alpha.10.0.0 v27.0.0-alpha.20.0.10 ' +check 'v27.0.0-alpha.1.1.1 ' v27.0.0-alpha.1.1.1 +check 'v27.0.0-alpha.1.1.1 v27.0.0-alpha.1.1.10 ' v27.0.0-alpha.1.1 +check 'v27.0.0-alpha.1.1.1 v27.0.0-alpha.1.1.10 v27.0.0-alpha.1.2.0 ' v27.0.0-alpha.1 +check 'v27.0.0-alpha.10.0.0 ' v27.0.0-alpha.10 +check 'N/A ' v27.0.0-alpha.20.0.1 + +NVM_ONLY='alpha,lts,non-lts,iojs' +check 'v26.12.1 v27.0.0-alpha.1.1.1 v27.0.0-alpha.1.1.10 v27.0.0-alpha.1.2.0 v27.0.0-alpha.10.0.0 v27.0.0-alpha.20.0.10 v27.0.0 ' +unset NVM_ONLY + +cleanup diff --git a/test/fast/Unit tests/nvm_ls_cached alpha b/test/fast/Unit tests/nvm_ls_cached alpha new file mode 100755 index 00000000..e094a9e9 --- /dev/null +++ b/test/fast/Unit tests/nvm_ls_cached alpha @@ -0,0 +1,43 @@ +#!/bin/sh + +ORIG_NVM_DIR="${NVM_DIR}" +TMP_DIR='' + +cleanup () { + case "${TMP_DIR}" in + /*) rm -rf "${TMP_DIR}" ;; + esac + NVM_DIR="${ORIG_NVM_DIR}" + export NVM_DIR + unset NVM_ONLY +} + +die () { echo "$@" ; cleanup ; exit 1; } + +: nvm.sh +\. ../../../nvm.sh + +TMP_DIR="$(mktemp -d)" +NVM_DIR="${TMP_DIR}/nvm" +export NVM_DIR +unset NVM_ONLY + +CACHE_DIR="$(nvm_cache_dir)" +SUFFIX="$(nvm_get_os)-$(nvm_get_arch)" +mkdir -p "${CACHE_DIR}/bin/node-v27.0.0-alpha.1.2.0-${SUFFIX}" "${CACHE_DIR}/src/node-v27.0.0-alpha.1.10.0" "${CACHE_DIR}/bin/node-v26.12.1-${SUFFIX}" \ + || die 'could not create cached artifacts' + +OUTPUT="$(nvm_ls_cached | tr '\n' ' ')" +[ "_${OUTPUT}" = '_v26.12.1 ' ] || die "cached alphas should be excluded by default; got >${OUTPUT}<" + +NVM_ONLY=alpha +OUTPUT="$(nvm_ls_cached | tr '\n' ' ')" +[ "_${OUTPUT}" = '_v27.0.0-alpha.1.2.0 v27.0.0-alpha.1.10.0 ' ] || die "NVM_ONLY=alpha should list cached alphas, in order; got >${OUTPUT}<" +OUTPUT="$(nvm_ls_cached 27.0.0-alpha.1.2 | tr '\n' ' ')" +[ "_${OUTPUT}" = '_v27.0.0-alpha.1.2.0 ' ] || die "a partial alpha should match only at a dot; got >${OUTPUT}<" + +NVM_ONLY='alpha,lts,non-lts,iojs' +OUTPUT="$(nvm_ls_cached v27.0.0)" +[ -z "${OUTPUT}" ] || die "v27.0.0 is not one of its alphas; got >${OUTPUT}<" + +cleanup diff --git a/test/fast/Unit tests/nvm_ls_remote alpha b/test/fast/Unit tests/nvm_ls_remote alpha new file mode 100755 index 00000000..9e86c84c --- /dev/null +++ b/test/fast/Unit tests/nvm_ls_remote alpha @@ -0,0 +1,92 @@ +#!/bin/sh + +ORIG_NVM_DIR="${NVM_DIR}" +TMP_DIR='' + +cleanup () { + case "${TMP_DIR}" in + /*) rm -rf "${TMP_DIR}" ;; + esac + NVM_DIR="${ORIG_NVM_DIR}" + export NVM_DIR + unset -f nvm_download index_row +} + +die () { echo "$@" ; cleanup ; exit 1; } + +: nvm.sh +\. ../../../nvm.sh + +\. ../../common.sh + +TMP_DIR="$(mktemp -d)" +NVM_DIR="${TMP_DIR}/nvm" +export NVM_DIR +mkdir -p "${NVM_DIR}" || die 'could not create NVM_DIR' +unset NVM_ONLY NVM_LTS + +index_row () { + printf '%s\t2026-01-01\tsrc\t-\t-\t-\t-\t-\t-\t%s\t-\n' "$1" "${2:--}" +} + +nvm_download () { + case "$*" in + *iojs*index.tab*) + printf 'version\tdate\tfiles\tnpm\tv8\tuv\tzlib\topenssl\tmodules\n' + printf 'v3.3.1\t2015-09-15\tsrc\t2.14.3\t4.4.63.30\t1.7.4\t1.2.8\t1.0.2d\t45\n' + printf 'v1.0.0\t2015-01-14\tsrc\t1.1.0\t3.31.74.1\t1.2.0\t1.2.8\t1.0.1k\t42\n' + ;; + *index.tab*) + printf 'version\tdate\tfiles\tnpm\tv8\tuv\tzlib\topenssl\tmodules\tlts\tsecurity\n' + index_row v27.0.0-alpha.1.10.2 + index_row v27.0.0-alpha.1.2.0 + index_row v27.0.0-alpha.0.0.0 + index_row v26.12.10 + index_row v26.12.2 + index_row v24.11.0 Krypton + index_row v22.11.0 Jod + index_row v21.0.0 + ;; + *) return 1 ;; + esac +} + +OUTPUT="$(nvm_ls_remote | awk '{ print $1 }')" +EXPECTED='v21.0.0 +v22.11.0 +v24.11.0 +v26.12.2 +v26.12.10' +[ "_${OUTPUT}" = "_${EXPECTED}" ] || die "nvm_ls_remote should exclude alphas by default; got >${OUTPUT}<" + +for PAIR in 'node:v26.12.10' '27:N/A' 'v27.0.0-alpha.1.2.0:N/A'; do + OUTPUT="$(nvm_remote_version "${PAIR%%:*}")" + [ "_${OUTPUT}" = "_${PAIR#*:}" ] || die "nvm_remote_version ${PAIR%%:*} printed >${OUTPUT}<, expected >${PAIR#*:}<" +done + +OUTPUT="$(NVM_ONLY=alpha nvm_ls_remote | awk '{ print $1 }')" +EXPECTED='v27.0.0-alpha.0.0.0 +v27.0.0-alpha.1.2.0 +v27.0.0-alpha.1.10.2' +[ "_${OUTPUT}" = "_${EXPECTED}" ] || die "NVM_ONLY=alpha nvm_ls_remote should list only alphas, in order; got >${OUTPUT}<" + +for PAIR in '27:v27.0.0-alpha.1.10.2' 'v27.0.0-alpha.1.2.0:v27.0.0-alpha.1.2.0' 'node:v27.0.0-alpha.1.10.2'; do + OUTPUT="$(NVM_ONLY=alpha nvm_remote_version "${PAIR%%:*}")" + [ "_${OUTPUT}" = "_${PAIR#*:}" ] || die "NVM_ONLY=alpha nvm_remote_version ${PAIR%%:*} printed >${OUTPUT}<, expected >${PAIR#*:}<" +done + +ALL="$(NVM_ONLY='alpha,lts,non-lts,iojs' nvm_remote_versions | awk '{ print $1 }' | sort)" +[ "_$(echo "${ALL}" | wc -l | tr -d ' ')" = '_10' ] || die "every category should list all 10 versions; got >${ALL}<" +UNION='' +for CATEGORY in alpha lts non-lts iojs; do + LIST="$(NVM_ONLY="${CATEGORY}" nvm_remote_versions | awk '{ print $1 }')" + [ -n "${LIST}" ] || die "category ${CATEGORY} listed nothing" + UNION="${UNION:+${UNION} +}${LIST}" +done +[ "_$(echo "${UNION}" | sort)" = "_${ALL}" ] || die "categories should partition the versions; got >${UNION}<, expected >${ALL}<" + +[ "_$(NVM_ONLY=lts nvm_remote_versions | awk '{ print $1 }' | tr '\n' ' ')" = '_v22.11.0 v24.11.0 ' ] || die 'NVM_ONLY=lts listed the wrong versions' +[ "_$(NVM_ONLY=iojs nvm_remote_versions | awk '{ print $1 }' | tr '\n' ' ')" = '_iojs-v1.0.0 iojs-v3.3.1 ' ] || die 'NVM_ONLY=iojs listed the wrong versions' + +cleanup diff --git a/test/fast/Unit tests/nvm_normalize_only b/test/fast/Unit tests/nvm_normalize_only new file mode 100755 index 00000000..e5e021c5 --- /dev/null +++ b/test/fast/Unit tests/nvm_normalize_only @@ -0,0 +1,23 @@ +#!/bin/sh + +die () { echo "$@" ; exit 1; } + +: nvm.sh +\. ../../../nvm.sh + +\. ../../common.sh + +for PAIR in 'alpha:alpha' 'iojs,lts:lts,iojs' 'non-lts,alpha,iojs,lts:alpha,lts,non-lts,iojs' 'lts,lts,non-lts,lts:lts,non-lts'; do + try nvm_normalize_only "${PAIR%%:*}" 'SOURCE' + [ "_${CAPTURED_EXIT_CODE}" = '_0' ] || die "nvm_normalize_only ${PAIR%%:*} exited ${CAPTURED_EXIT_CODE}" + [ "_${CAPTURED_STDOUT}" = "_${PAIR#*:}" ] || die "nvm_normalize_only ${PAIR%%:*} printed >${CAPTURED_STDOUT}<, expected >${PAIR#*:}<" +done + +for VALUE in '' 'beta' 'lts,beta' ',lts' 'lts,' 'lts,,iojs' 'LTS' 'lts non-lts' 'nonlts' 'all'; do + try_err nvm_normalize_only "${VALUE}" 'SOURCE' + [ "_${CAPTURED_EXIT_CODE}" = '_55' ] || die "nvm_normalize_only >${VALUE}< exited ${CAPTURED_EXIT_CODE}, expected 55" + EXPECTED="Invalid SOURCE value \"${VALUE}\": it must be a comma-separated list of any of: alpha, lts, non-lts, iojs" + [ "_${CAPTURED_STDERR}" = "_${EXPECTED}" ] || die "nvm_normalize_only >${VALUE}< printed >${CAPTURED_STDERR}<, expected >${EXPECTED}<" + try nvm_normalize_only "${VALUE}" 'SOURCE' + [ -z "${CAPTURED_STDOUT}" ] || die "nvm_normalize_only >${VALUE}< printed >${CAPTURED_STDOUT}< to stdout" +done diff --git a/test/fast/Unit tests/nvm_resolve_only b/test/fast/Unit tests/nvm_resolve_only new file mode 100755 index 00000000..a8354e67 --- /dev/null +++ b/test/fast/Unit tests/nvm_resolve_only @@ -0,0 +1,66 @@ +#!/bin/sh + +die () { echo "$@" ; exit 1; } + +: nvm.sh +\. ../../../nvm.sh + +\. ../../common.sh + +unset NVM_ONLY NVM_ONLY_SELECTED +NVM_NO_LTS_STATUS=1 +export NVM_NO_LTS_STATUS + +check () { + EXPECTED="$1" + shift + try nvm_resolve_only "$@" + [ "_${CAPTURED_EXIT_CODE}" = '_0' ] || die "nvm_resolve_only $* (NVM_ONLY=${NVM_ONLY-}) exited ${CAPTURED_EXIT_CODE}" + [ "_${CAPTURED_STDOUT}" = "_${EXPECTED}" ] || die "nvm_resolve_only $* (NVM_ONLY=${NVM_ONLY-}) printed >${CAPTURED_STDOUT}<, expected >${EXPECTED}<" +} + +check_err () { + EXPECTED="$1" + shift + try_err nvm_resolve_only "$@" + [ "_${CAPTURED_EXIT_CODE}" = "_${EXPECTED_CODE:-55}" ] || die "nvm_resolve_only $* (NVM_ONLY=${NVM_ONLY-}) exited ${CAPTURED_EXIT_CODE}, expected ${EXPECTED_CODE:-55}" + [ "_${CAPTURED_STDERR}" = "_${EXPECTED}" ] || die "nvm_resolve_only $* (NVM_ONLY=${NVM_ONLY-}) printed >${CAPTURED_STDERR}<, expected >${EXPECTED}<" +} + +check 'lts,non-lts,iojs' 0 '' '' +check 'alpha,iojs' 1 'iojs,alpha' '' +check 'lts,non-lts' 0 '' '*' +check 'lts,non-lts' 1 'alpha,lts' 'argon' +check_err '`--only=alpha,iojs` excludes LTS versions, so it cannot be combined with an LTS selection like `--lts`.' 1 'alpha,iojs' '*' +check_err '`--only` may only be provided once.' 2 'alpha' '' +check_err 'Invalid `--only` value "": it must be a comma-separated list of any of: alpha, lts, non-lts, iojs' 1 '' '' +check_err 'Invalid `--only` value ",alpha": it must be a comma-separated list of any of: alpha, lts, non-lts, iojs' 1 ',alpha' '' + +NVM_ONLY='iojs,alpha' +check 'alpha,iojs' 0 '' '' +check 'non-lts' 1 'non-lts' '' +check 'lts,non-lts' 0 '' '*' +NVM_ONLY='alpha,bogus' +check_err 'Invalid `$NVM_ONLY` value "alpha,bogus": it must be a comma-separated list of any of: alpha, lts, non-lts, iojs' 0 '' '' +check 'lts' 1 'lts' '' + +NVM_ONLY='lts' +NVM_ONLY_SELECTED='alpha' +check 'alpha' 0 '' '' +check 'non-lts' 1 'non-lts' '' +unset NVM_ONLY NVM_ONLY_SELECTED NVM_NO_LTS_STATUS + +# selecting only one of lts and non-lts needs recorded LTS status; an LTS selection does not +NVM_INDEX_NO_FETCH=1 +export NVM_INDEX_NO_FETCH +nvm_download() { return 1; } +TMP_DIR="$(mktemp -d)" +ORIG_NVM_DIR="${NVM_DIR}" +NVM_DIR="${TMP_DIR}" +EXPECTED_CODE=3 +check_err 'The LTS status of installed versions is not recorded yet; run `nvm ls-remote` to record it.' 1 'lts' '' +unset EXPECTED_CODE +check 'lts,non-lts' 0 '' '*' +NVM_DIR="${ORIG_NVM_DIR}" +rm -rf "${TMP_DIR}" +unset NVM_INDEX_NO_FETCH diff --git a/test/fast/Unit tests/nvm_sort_versions b/test/fast/Unit tests/nvm_sort_versions new file mode 100755 index 00000000..d337973c --- /dev/null +++ b/test/fast/Unit tests/nvm_sort_versions @@ -0,0 +1,56 @@ +#!/bin/sh + +die () { echo "$@" ; exit 1; } + +: nvm.sh +\. ../../../nvm.sh + +INPUT='v27.0.0 +v27.0.0-alpha.1.10.2 +v26.12.10 +v27.0.0-alpha.1.2.0 +v26.12.2 +v27.0.0-alpha.0.0.0 +v26.12.2 +v4.0.0' +EXPECTED='v4.0.0 +v26.12.2 +v26.12.10 +v27.0.0-alpha.0.0.0 +v27.0.0-alpha.1.2.0 +v27.0.0-alpha.1.10.2 +v27.0.0' +OUTPUT="$(echo "${INPUT}" | nvm_sort_versions)" +[ "_${OUTPUT}" = "_${EXPECTED}" ] || die "nvm_sort_versions printed >${OUTPUT}<, expected >${EXPECTED}<" +OUTPUT="$(echo "${INPUT}" | nvm_sort_versions 1)" +[ "_${OUTPUT}" = "_${EXPECTED}" ] || die "nvm_sort_versions 1 printed >${OUTPUT}<, expected >${EXPECTED}<" + +INPUT='v3.3.1.iojs +v10.0.0.node +v27.0.0-alpha.1.0.0.node +v1.0.0.iojs +v2.0.0.node' +EXPECTED='v1.0.0.iojs +v2.0.0.node +v3.3.1.iojs +v10.0.0.node +v27.0.0-alpha.1.0.0.node' +OUTPUT="$(echo "${INPUT}" | nvm_sort_versions)" +[ "_${OUTPUT}" = "_${EXPECTED}" ] || die "nvm_sort_versions with suffixes printed >${OUTPUT}<, expected >${EXPECTED}<" + +INPUT='v11.1.0-nightly20181101af6d26281f +v11.0.0-nightly201810011be804d625 +v11.0.0-nightly20181002aaaaaaaaaa' +OUTPUT="$(echo "${INPUT}" | nvm_sort_versions 1)" +[ "_$(echo "${OUTPUT}" | grep -c 'v11\.0\.0-nightly')" = '_1' ] || die "nvm_sort_versions 1 should collapse same-release nightlies; got >${OUTPUT}<" +[ "_$(echo "${OUTPUT}" | sed -n '2p')" = '_v11.1.0-nightly20181101af6d26281f' ] || die "nvm_sort_versions 1 should keep other nightlies; got >${OUTPUT}<" +[ "_$(echo "${OUTPUT}" | wc -l | tr -d ' ')" = '_2' ] || die "nvm_sort_versions 1 printed the wrong number of lines; got >${OUTPUT}<" +OUTPUT="$(echo "${INPUT}" | nvm_sort_versions)" +[ "_$(echo "${OUTPUT}" | wc -l | tr -d ' ')" = '_3' ] || die "nvm_sort_versions should keep every distinct line; got >${OUTPUT}<" + +INPUT='v24.11.0 Krypton * +v22.11.0 Jod' +EXPECTED='v22.11.0 Jod +v24.11.0 Krypton *' +OUTPUT="$(echo "${INPUT}" | nvm_sort_versions 1)" +[ "_${OUTPUT}" = "_${EXPECTED}" ] || die "nvm_sort_versions 1 should keep trailing fields; got >${OUTPUT}<"