[New] nvm ls-remote: annotate versions with the node alias and local aliases
Tests: installation_node / installation_node (bash) (push) Canceled after 0s
Tests: installation_node / installation_node (bash, without curl) (push) Canceled after 0s
Tests: installation_node / installation_node (dash) (push) Canceled after 0s
Tests: installation_node / installation_node (dash, without curl) (push) Canceled after 0s
Tests: installation_node / installation_node (sh) (push) Canceled after 0s
Tests: installation_node / installation_node (sh, without curl) (push) Canceled after 0s
Tests: installation_node / installation_node (zsh, without curl) (push) Canceled after 0s
Tests: xenial / xenial (bash) (push) Canceled after 0s
Tests: xenial / xenial (dash) (push) Canceled after 0s
Tests: xenial / xenial (sh) (push) Canceled after 0s
Tests: xenial / xenial (zsh) (push) Canceled after 0s
Tests: linting / dockerfile_lint (push) Canceled after 0s
Tests: linting / doctoc (push) Canceled after 0s
Tests: linting / test_naming (push) Canceled after 0s
Tests: linting / check_exec (push) Canceled after 0s
Tests on Windows: `nvm install` / MSYS fail prefix nvm install (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3, zsh) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3, bash) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3, dash) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3, sh) (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3.15, dash) (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3.15, sh) (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3.15, zsh) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3.15, bash) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3.15, dash) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3.15, sh) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3.15, zsh) (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3.19, bash) (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3.19, dash) (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3.19, zsh) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3.19, bash) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3.19, dash) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3.19, sh) (push) Canceled after 0s
Tests: installation_node / installation_node (zsh) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3, zsh) (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3.15, bash) (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3.19, sh) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 12, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 16, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 16, Ubuntu-18.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 16, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 16, Ubuntu-24.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Debian-13) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3.19, zsh) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 12, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 12, Ubuntu-18.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 12, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 12, Ubuntu-24.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 14, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 14, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 14, Ubuntu-18.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 14, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 14, Ubuntu-24.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 16, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 18, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 18, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 18, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 18, Ubuntu-24.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 21, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 21, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 21, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 21, Ubuntu-24.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Ubuntu-18.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Ubuntu-24.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Ubuntu-18.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Ubuntu-24.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Ubuntu-18.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Ubuntu-24.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Ubuntu-18.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Ubuntu-24.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, --lts, Alpine-3.17) (push) Canceled after 0s
Code scanning - action / CodeQL-Build (push) Canceled after 0s
Tests: `nvm install-latest-npm` / matrix (push) Canceled after 0s
Tests: linting / eclint (push) Canceled after 0s
Tests: nvm install with set -e / matrix (push) Canceled after 0s
Tests: release process / release (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3, bash) (push) Canceled after 0s
Tests: shellcheck / shellcheck_matrix (nvm.sh, dash) (push) Canceled after 0s
Tests: shellcheck / shellcheck_matrix (nvm.sh, ksh) (push) Canceled after 0s
Tests: alpine / musl-binary arm64 (alpine 3, node v22.21.1) (push) Canceled after 0s
Tests: alpine / musl-binary arm64 (alpine 3, node v24.9.0) (push) Canceled after 0s
Tests: alpine / musl-binary x64 (alpine 3, node v22.12.0) (push) Canceled after 0s
Tests: alpine / musl-binary x64 (alpine 3.10, node v10.24.1) (push) Canceled after 0s
Tests: alpine / musl-binary x64 (alpine 3.10, node v8.17.0) (push) Canceled after 0s
Tests: alpine / musl-binary x64 (alpine 3.12, node v12.22.12) (push) Canceled after 0s
Tests: alpine / musl-binary x64 (alpine 3.16, node v16.20.2) (push) Canceled after 0s
Tests: alpine / musl-binary x64 (alpine 3.18, node v18.20.4) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Ubuntu-24.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Ubuntu-24.04) (push) Canceled after 0s
Tests: shellcheck / shellcheck_matrix (bash_completion, bash) (push) Canceled after 0s
Tests: shellcheck / shellcheck_matrix (install.sh, bash) (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3, dash) (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3, sh) (push) Canceled after 0s
Tests: shellcheck / shellcheck_matrix (nvm-exec, bash) (push) Canceled after 0s
Tests: shellcheck / shellcheck_matrix (nvm.sh, bash) (push) Canceled after 0s
Tests: shellcheck / shellcheck_matrix (nvm.sh, sh) (push) Canceled after 0s
Tests: alpine / musl-binary x64 (alpine 3.15, node v14.21.3) (push) Canceled after 0s
Tests: fast / fast (bash, gawk) (push) Canceled after 0s
Tests: fast / fast (sh, gawk) (push) Canceled after 0s
Tests: fast / fast (zsh, gawk) (push) Canceled after 0s
Tests: fast / fast (bash, mawk) (push) Canceled after 0s
Tests: fast / fast (dash, mawk) (push) Canceled after 0s
Tests: fast / fast (sh, mawk) (push) Canceled after 0s
Tests: fast / fast (zsh, mawk) (push) Canceled after 0s
Tests: installation_iojs / installation_iojs without curl (bash) (push) Canceled after 0s
Tests: installation_iojs / installation_iojs without curl (dash) (push) Canceled after 0s
Tests: installation_iojs / installation_iojs without curl (sh) (push) Canceled after 0s
Tests: alpine / musl-binary arm64 (alpine 3.20, node v20.20.1) (push) Canceled after 0s
Tests: alpine / musl-binary x64 (alpine 3.20, node v20.18.1) (push) Canceled after 0s
Tests: installation_iojs / actually compile io.js from source (gcc 4.9 container) (push) Canceled after 0s
Tests: fast / fast (dash, gawk) (push) Canceled after 0s
urchin tests / tests (dash, installation_iojs) (push) Canceled after 0s
urchin tests / tests (dash, slow) (push) Canceled after 0s
urchin tests / tests (dash, sourcing) (push) Canceled after 0s
urchin tests / tests (sh, installation_iojs) (push) Canceled after 0s
urchin tests / tests (sh, slow) (push) Canceled after 0s
urchin tests / tests (sh, sourcing) (push) Canceled after 0s
urchin tests / tests (zsh, installation_iojs) (push) Canceled after 0s
urchin tests / tests (zsh, slow) (push) Canceled after 0s
urchin tests / tests (zsh, sourcing) (push) Canceled after 0s
update readme TOC / update readme TOC (push) Canceled after 0s
Tests on Windows: `nvm install` / MSYS nvm install (--default 12) (push) Canceled after 0s
Tests on Windows: `nvm install` / MSYS nvm install (--lts) (push) Canceled after 0s
Tests on Windows: `nvm install` / MSYS nvm install (--no-progress 10) (push) Canceled after 0s
Tests on Windows: `nvm install` / Cygwin nvm install (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 10, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 10, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 10, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 10, Ubuntu-24.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, --lts, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 10, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 10, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 11, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 11, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 12, Alpine-3.17) (push) Canceled after 0s
Tests: installation_iojs / installation_iojs without curl (zsh) (push) Canceled after 0s
urchin tests / tests (bash, install_script) (push) Canceled after 0s
urchin tests / tests (bash, installation_iojs) (push) Canceled after 0s
urchin tests / tests (bash, slow) (push) Canceled after 0s
urchin tests / tests (bash, sourcing) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 10, Ubuntu-18.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, --lts, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 11, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 11, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Alpine-3.23) (push) Canceled after 0s
Tests: fast / all fast tests (push) Canceled after 0s
latest-npm.yml / nvm install-latest-npm (${{ fromJson(needs.matrix.outputs.latest) }}) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (21) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (9.0) (push) Canceled after 0s
nvm-install-test.yml / test (nvmrc, ${{ fromJson(needs.matrix.outputs.matrix) }}, 2 shlvls) (push) Canceled after 0s
Tests: nvm install with set -e / finisher (push) Canceled after 0s
Tests: shellcheck / shellcheck (push) Canceled after 0s
Tests: alpine / all alpine tests (push) Canceled after 0s
urchin tests / all test suites, all shells (push) Canceled after 0s
Tests on Windows: `nvm install` / tests, on windows (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 12, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 14, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 14, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 16, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 16, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 18, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 18, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 21, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 21, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, --lts, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Alpine-3.23) (push) Canceled after 0s
Tests: installation_iojs / all installation_iojs tests (push) Canceled after 0s
Tests: installation_node / all installation_node tests (push) Canceled after 0s
Tests: xenial / all xenial tests (push) Canceled after 0s
Tests: linting / all linting (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (0.10) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (0.12) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (14.16) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (14.17) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (20.4) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (20.5) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (4.4) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (4.5) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (4.6) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (5.9) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (6.1) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (9.1) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (9.2) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (push) Canceled after 0s
nvm-install-test.yml / test (no nvmrc, ${{ fromJson(needs.matrix.outputs.matrix) }}, 1 shlvl) (push) Canceled after 0s
nvm-install-test.yml / test (no nvmrc, ${{ fromJson(needs.matrix.outputs.matrix) }}, 2 shlvls) (push) Canceled after 0s
nvm-install-test.yml / test (nvmrc, ${{ fromJson(needs.matrix.outputs.matrix) }}, 1 shlvl) (push) Canceled after 0s

Fixes #2786.

Ben Younes added the alias annotations to bare `nvm ls-remote`, with their regression tests;
Jordan Harband moved `(Latest: node)` onto the newest node release, gave each kind of annotation a fixed column so the output can be sliced with `cut`, matched aliases to versions in one pass, and kept local aliases out of the mocks and tests.

Co-authored-by: Ben Younes <2910651+ousamabenyounes@users.noreply.github.com>
Co-authored-by: Jordan Harband <ljharb@gmail.com>
This commit is contained in:
Ben Younes
2026-09-23 21:35:43 +00:00
committed by Jordan Harband
co-authored by Jordan Harband
parent 04fbd9570c
commit a8bb497400
6 changed files with 326 additions and 14 deletions
+9
View File
@@ -401,6 +401,15 @@ You can list available versions using `ls-remote`:
nvm ls-remote
```
When no version or `--lts` filter is given, the list also marks the version the `node` alias would install, and every version that one of your own aliases would resolve to. Each kind of annotation always starts in the same column, so the output can be sliced with `cut -c` or similar tools:
```
v20.9.0 (Latest LTS: Iron) (Aliases: work)
v21.0.0
v21.1.0
v21.2.0 (Latest: node) (Aliases: default)
```
And then in any new shell just use the installed version:
```sh
+176 -12
View File
@@ -2161,10 +2161,53 @@ nvm_get_checksum() {
nvm_download -L -s "${SHASUMS_URL}" -o - | command awk -v tarball="${4}.${5}" '{ if (tarball == $2) print $1 }'
}
nvm_get_remote_aliases() {
local NVM_ALIAS_DIR
NVM_ALIAS_DIR="$(nvm_alias_path)"
if [ ! -d "${NVM_ALIAS_DIR}" ]; then
return 0
fi
local NVM_NODE_PREFIX
NVM_NODE_PREFIX="$(nvm_node_prefix)"
local NVM_IOJS_PREFIX
NVM_IOJS_PREFIX="$(nvm_iojs_prefix)"
local NVM_ALIAS_PATH
local NVM_ALIAS_NAME
local NVM_ALIAS_TARGET
nvm_is_zsh && setopt local_options nonomatch
# the same glob as `nvm_list_aliases`, so this never shows an alias that `nvm alias` omits
for NVM_ALIAS_PATH in "${NVM_ALIAS_DIR}/"*; do
if [ ! -f "${NVM_ALIAS_PATH}" ]; then
continue
fi
NVM_ALIAS_NAME="${NVM_ALIAS_PATH##*/}"
case "${NVM_ALIAS_NAME}" in
"${NVM_NODE_PREFIX}" | "${NVM_IOJS_PREFIX}" | stable | unstable) continue ;;
# control characters would corrupt the terminal, or the tab-separated output
*[[:cntrl:]]*) continue ;;
esac
NVM_ALIAS_TARGET="$(nvm_resolve_alias "${NVM_ALIAS_NAME}" 2>/dev/null)" || continue
case "${NVM_ALIAS_TARGET}" in
'' | *[[:cntrl:]]*) continue ;;
esac
command printf '%s\t%s\n' "${NVM_ALIAS_TARGET}" "${NVM_ALIAS_NAME}"
done
}
nvm_print_versions() {
local NVM_CURRENT
NVM_CURRENT=$(nvm_ls_current)
local NVM_LATEST_ALIAS
NVM_LATEST_ALIAS="${2-}"
local NVM_NAMED_ALIASES
NVM_NAMED_ALIASES="${3-}"
local INSTALLED_COLOR
local SYSTEM_COLOR
local CURRENT_COLOR
@@ -2185,20 +2228,36 @@ nvm_print_versions() {
NVM_HAS_COLORS=1
fi
local NVM_HAS_ITALICS
NVM_HAS_ITALICS=0
if [ "${NVM_HAS_COLORS}" = 1 ] && [ -n "${NVM_LATEST_ALIAS}${NVM_NAMED_ALIASES}" ] && nvm_has_italics; then
NVM_HAS_ITALICS=1
fi
NVM_NAMED_ALIASES="${NVM_NAMED_ALIASES}" \
command awk \
-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 | 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" '
-v old_lts_color="$DEFAULT_COLOR" -v has_colors="$NVM_HAS_COLORS" \
-v has_italics="$NVM_HAS_ITALICS" '
function alen(arr, i, len) { len=0; for(i in arr) len++; return len; }
function paint(color, text) { return (has_colors && color) ? ("\033[" color text "\033[0m") : text; }
function spaces(count, result) { result = ""; while (count-- > 0) result = result " "; return result; }
function italicize(text) { return has_italics ? ("\033[3m" text "\033[23m") : text; }
BEGIN {
named_alias_list = ENVIRON["NVM_NAMED_ALIASES"];
fmt_installed = has_colors ? (installed_color ? "\033[" installed_color "%15s\033[0m" : "%15s") : "%15s *";
fmt_system = has_colors ? (system_color ? "\033[" system_color "%15s\033[0m" : "%15s") : "%15s *";
fmt_current = has_colors ? (current_color ? "\033[" current_color "->%13s\033[0m" : "%15s") : "->%13s *";
latest_lts_color = current_color;
sub(/0;/, "1;", latest_lts_color);
alias_color = current_color;
sub(/^1;/, "0;", alias_color);
fmt_latest_lts = has_colors && latest_lts_color ? ("\033[" latest_lts_color " (Latest LTS: %s)\033[0m") : " (Latest LTS: %s)";
fmt_old_lts = has_colors && old_lts_color ? ("\033[" old_lts_color " (LTS: %s)\033[0m") : " (LTS: %s)";
@@ -2208,6 +2267,57 @@ BEGIN {
split(installed_versions, installed, "|");
rows = alen(lines);
for (n = 1; n <= rows; n++) {
split(lines[n], fields, "[[:blank:]]+");
if (index(fields[1], iojs_prefix "-") == 1) {
latest_iojs = fields[1];
} else if (fields[1] ~ /^v0\.[0-9]*[13579]\./) {
latest_unstable = fields[1];
} else if (fields[1] ~ /^v[0-9]/) {
latest_stable = fields[1];
}
}
named_alias_rows = split(named_alias_list, named_alias_lines, "\n");
for (a = 1; a <= named_alias_rows; a++) {
tab_position = index(named_alias_lines[a], "\t");
if (tab_position < 2) {
continue;
}
alias_target = substr(named_alias_lines[a], 1, tab_position - 1);
alias_name = substr(named_alias_lines[a], tab_position + 1);
if (alias_name == "") {
continue;
}
alias_version = "";
if (alias_target == node_prefix || alias_target == "stable") {
alias_version = latest_stable;
} else if (alias_target == "unstable") {
alias_version = latest_unstable;
} else if (alias_target == iojs_prefix || alias_target == (iojs_prefix "-")) {
alias_version = latest_iojs;
} else {
for (n = 1; n <= rows; n++) {
split(lines[n], fields, "[[:blank:]]+");
if (fields[1] == alias_target || index(fields[1], alias_target ".") == 1) {
alias_version = fields[1];
}
}
}
if (alias_version != "") {
# mawk creates the assigned element before evaluating the right side, so `in` must be checked first
if (alias_version in named_aliases) {
named_aliases[alias_version] = named_aliases[alias_version] ", " alias_name;
italic_aliases[alias_version] = italic_aliases[alias_version] ", " italicize(alias_name);
} else {
named_aliases[alias_version] = alias_name;
italic_aliases[alias_version] = italicize(alias_name);
}
}
}
for (n = 1; n <= rows; n++) {
split(lines[n], fields, "[[:blank:]]+");
cols = alen(fields);
@@ -2230,23 +2340,69 @@ BEGIN {
fmt_version = fmt_installed;
}
padding = (!has_colors && is_installed) ? "" : " ";
padding[n] = (!has_colors && is_installed) ? "" : " ";
if (cols == 1) {
formatted = sprintf(fmt_version, version);
} else if (version == "system" && cols >= 2) {
formatted = sprintf((fmt_version fmt_system_target), version, fields[2]);
output[n] = sprintf(fmt_version, version);
version_width[n] = output[n] padding[n];
gsub(/\033\[[0-9;]*m/, "", version_width[n]);
version_width[n] = length(version_width[n]);
if (version_width[n] > max_version_width) {
max_version_width = version_width[n];
}
for (c = 1; c <= 3; c++) {
text[n, c] = "";
cell[n, c] = "";
}
if (version == "system" && cols >= 2) {
output[n] = output[n] sprintf(fmt_system_target, fields[2]);
} else if (cols == 2) {
formatted = sprintf((fmt_version padding fmt_old_lts), version, fields[2]);
text[n, 1] = sprintf(" (LTS: %s)", fields[2]);
cell[n, 1] = sprintf(fmt_old_lts, fields[2]);
} else if (cols == 3 && fields[3] == "*") {
formatted = sprintf((fmt_version padding fmt_latest_lts), version, fields[2]);
text[n, 1] = sprintf(" (Latest LTS: %s)", fields[2]);
cell[n, 1] = sprintf(fmt_latest_lts, fields[2]);
}
output[n] = formatted;
if (latest_alias != "" && version == latest_stable) {
text[n, 2] = " (Latest: " latest_alias ")";
cell[n, 2] = paint(alias_color, " (Latest: " italicize(latest_alias) ")");
}
if (version in named_aliases) {
text[n, 3] = " (Aliases: " named_aliases[version] ")";
cell[n, 3] = paint(alias_color, " (Aliases: " italic_aliases[version] ")");
}
for (c = 1; c <= 3; c++) {
if (length(text[n, c]) > width[c]) {
width[c] = length(text[n, c]);
}
}
}
# each kind of annotation starts in the same column on every row, so the output stays `cut`-able
for (n = 1; n <= rows; n++) {
print output[n]
last = 0;
for (c = 1; c <= 3; c++) {
if (text[n, c] != "") {
last = c;
}
}
formatted = output[n];
if (last) {
formatted = formatted padding[n];
if (width[2] || width[3]) {
formatted = formatted spaces(max_version_width - version_width[n]);
}
gap = "";
for (c = 1; c <= last; c++) {
if (width[c]) {
formatted = formatted gap cell[n, c];
gap = spaces(width[c] - length(text[n, c])) " ";
}
}
}
print formatted
}
exit
@@ -4751,7 +4907,15 @@ nvm() {
NVM_OUTPUT="$(NVM_LTS="${NVM_LTS-}" nvm_remote_versions "${PATTERN-}" &&:)"
EXIT_CODE=$?
if [ -n "${NVM_OUTPUT}" ]; then
NVM_NO_COLORS="${NVM_NO_COLORS-}" nvm_print_versions "${NVM_OUTPUT}"
local NVM_REMOTE_LATEST_ALIAS
NVM_REMOTE_LATEST_ALIAS=''
local NVM_REMOTE_NAMED_ALIASES
NVM_REMOTE_NAMED_ALIASES=''
if [ "${EXIT_CODE}" -eq 0 ] && [ -z "${NVM_LTS-}" ] && [ -z "${PATTERN-}" ]; then
NVM_REMOTE_LATEST_ALIAS="$(nvm_node_prefix)"
NVM_REMOTE_NAMED_ALIASES="$(nvm_get_remote_aliases)"
fi
NVM_NO_COLORS="${NVM_NO_COLORS-}" nvm_print_versions "${NVM_OUTPUT}" "${NVM_REMOTE_LATEST_ALIAS}" "${NVM_REMOTE_NAMED_ALIASES}"
return $EXIT_CODE
fi
NVM_NO_COLORS="${NVM_NO_COLORS-}" nvm_print_versions "N/A"
@@ -5035,7 +5199,7 @@ nvm() {
nvm_iojs_prefix nvm_node_prefix \
nvm_add_iojs_prefix nvm_strip_iojs_prefix \
nvm_is_iojs_version nvm_is_alias nvm_has_non_aliased \
nvm_ls_remote nvm_ls_remote_iojs nvm_ls_remote_index_tab \
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_install_binary nvm_install_source nvm_clang_version \
nvm_get_mirror nvm_get_download_slug nvm_download_artifact \
+1 -1
View File
@@ -797,4 +797,4 @@
v22.10.0
v22.11.0  (Latest LTS: Jod)
v23.0.0
v23.1.0
v23.1.0  (Latest: node)
+4 -1
View File
@@ -3,7 +3,7 @@
die () { echo "$@" ; cleanup ; exit 1; }
cleanup() {
unset -f nvm_download nvm_ls_remote nvm_ls_remote_iojs
unset -f nvm_download nvm_ls_remote nvm_ls_remote_iojs nvm_get_remote_aliases nvm_has_italics
if [ -n "${TEMP_NVM_COLORS-}" ]; then
export NVM_COLORS=TEMP_NVM_COLORS
fi
@@ -87,6 +87,9 @@ REMOTE_IOJS="${PWD}/mocks/nvm_ls_remote_iojs.txt"
nvm_ls_remote_iojs() {
cat "${REMOTE_IOJS}"
}
# the mock must not depend on whatever local aliases exist in $NVM_DIR
nvm_get_remote_aliases() { :; }
nvm_has_italics() { return 0; }
EXPECTED_OUTPUT_PATH="${MOCKS_DIR}/nvm ls-remote.txt"
OUTPUT="$(nvm ls-remote | sed 's/[ \t]*$//')"
+126
View File
@@ -0,0 +1,126 @@
#!/bin/sh
WORK="${PWD}/nvm-ls-remote-aliases-work.$$"
export HOME="${WORK}/home"
export NVM_DIR="${HOME}/.nvm"
cleanup() {
command rm -rf "${WORK}"
unset -f cleanup die nvm_has_colors nvm_has_italics nvm_remote_versions expected_row
}
die () { echo "$@" ; cleanup ; exit 1; }
command mkdir -p "${NVM_DIR}/alias/lts" "${NVM_DIR}/versions/node/v1.5.0"
: nvm.sh
\. ../../../nvm.sh
nvm_has_colors() { return 1; }
nvm_remote_versions() {
if [ -n "${NVM_LTS-}" ] || [ -n "${1-}" ]; then
command printf '%s\n' 'v2.0.0'
else
# io.js sorts last here, so the latest node release is not the last row
command printf '%s\n' 'v0.11.16' 'v0.12.18' 'v1.0.0 Argon' 'v1.5.0' 'v2.0.0 Iron *' 'iojs-v3.3.1'
fi
return "${NVM_REMOTE_STATUS-0}"
}
nvm_make_alias 'project' '1' >/dev/null
nvm_make_alias 'argon-project' '1.0' >/dev/null
nvm_make_alias 'lts/iron' 'v2.0.0' >/dev/null
nvm_make_alias 'iron-project' 'lts/iron' >/dev/null
nvm_make_alias 'latest-project' 'node' >/dev/null
nvm_make_alias 'stable-project' 'stable' >/dev/null
nvm_make_alias 'unstable-project' 'unstable' >/dev/null
nvm_make_alias 'io-project' 'iojs' >/dev/null
nvm_make_alias '.hidden-project' '1' >/dev/null
command printf '%s\n' '[' > "${NVM_DIR}/alias/invalid-pattern"
command printf '%s\n' '1' > "${NVM_DIR}/alias/$(command printf 'control\rname')"
# the version cell is 17 wide (`%15s` plus the ` *` installed marker or two spaces), then LTS, Latest, and Aliases columns
expected_row() {
command printf '%-17s%-19s %-15s %s\n' "$1" "$2" "$3" "$4" | command sed 's/[[:space:]]*$//'
}
EXPECTED_OUTPUT="$(
expected_row ' v0.11.16' '' '' ' (Aliases: unstable-project)'
expected_row ' v0.12.18'
expected_row ' v1.0.0' ' (LTS: Argon)' '' ' (Aliases: argon-project)'
expected_row ' v1.5.0 *' '' '' ' (Aliases: project)'
expected_row ' v2.0.0' ' (Latest LTS: Iron)' ' (Latest: node)' ' (Aliases: iron-project, latest-project, stable-project)'
expected_row ' iojs-v3.3.1' '' '' ' (Aliases: io-project)'
)"
REMOTE_ERROR="${WORK}/remote-error"
OUTPUT="$(NVM_REMOTE_LATEST_ALIAS='injected' NVM_REMOTE_NAMED_ALIASES="$(command printf 'v0.12.18\tinjected')" nvm ls-remote --no-colors 2>"${REMOTE_ERROR}")"
[ ! -s "${REMOTE_ERROR}" ] \
|| die "bare nvm ls-remote emitted an error; got >$(command cat "${REMOTE_ERROR}")<"
[ "_${OUTPUT}" = "_${EXPECTED_OUTPUT}" ] \
|| die "bare nvm ls-remote did not annotate aliases in stable columns; got >${OUTPUT}< expected >${EXPECTED_OUTPUT}<"
ALIASES_COLUMN="$(command printf '%s\n' "${OUTPUT}" | command cut -c56-65 | command sort -u)"
[ "_${ALIASES_COLUMN}" = "_$(command printf '\n (Aliases:')" ] \
|| die "bare nvm ls-remote did not start every Aliases annotation in the same column; got >${ALIASES_COLUMN}<"
case "${OUTPUT}" in
*'node, stable'* | *unstable,* | *hidden* | *invalid* | *control* | *injected*)
die "bare nvm ls-remote showed an alias it should omit; got >${OUTPUT}<"
;;
esac
EXPECTED_FILTERED_OUTPUT='v2.0.0'
OUTPUT="$(nvm ls-remote 2 --no-colors | command sed 's/^[[:space:]]*//')"
[ "_${OUTPUT}" = "_${EXPECTED_FILTERED_OUTPUT}" ] \
|| die "filtered nvm ls-remote annotated aliases; got >${OUTPUT}< expected >${EXPECTED_FILTERED_OUTPUT}<"
OUTPUT="$(nvm ls-remote --lts --no-colors | command sed 's/^[[:space:]]*//')"
[ "_${OUTPUT}" = "_${EXPECTED_FILTERED_OUTPUT}" ] \
|| die "LTS nvm ls-remote annotated aliases; got >${OUTPUT}< expected >${EXPECTED_FILTERED_OUTPUT}<"
NVM_REMOTE_STATUS=1
OUTPUT="$(nvm ls-remote --no-colors 2>/dev/null)"
COMMAND_STATUS=$?
NVM_REMOTE_STATUS=0
[ "${COMMAND_STATUS}" -eq 1 ] \
|| die "failed nvm ls-remote returned ${COMMAND_STATUS}; expected 1"
case "${OUTPUT}" in
*Latest:* | *Aliases:*) die "failed nvm ls-remote annotated aliases; got >${OUTPUT}<" ;;
esac
nvm_has_colors() { return 0; }
nvm_has_italics() { return 0; }
ESC="$(command printf '\033')"
OUTPUT="$(nvm ls-remote)"
EXPECTED_LATEST_ROW="$(command printf ' v2.0.0 \033[1;32m (Latest LTS: Iron)\033[0m \033[0;32m (Latest: \033[3mnode\033[23m)\033[0m \033[0;32m (Aliases: \033[3miron-project\033[23m, \033[3mlatest-project\033[23m, \033[3mstable-project\033[23m)\033[0m')"
case "${OUTPUT}" in
*"${EXPECTED_LATEST_ROW}"*) ;;
*) die "colored nvm ls-remote did not use an unbolded color and italic names for aliases; got >${OUTPUT}<" ;;
esac
nvm_has_italics() { return 1; }
NO_ITALICS_OUTPUT="$(nvm ls-remote)"
nvm_has_italics() { return 0; }
EXPECTED_LATEST_ROW="$(command printf ' v2.0.0 \033[1;32m (Latest LTS: Iron)\033[0m \033[0;32m (Latest: node)\033[0m \033[0;32m (Aliases: iron-project, latest-project, stable-project)\033[0m')"
case "${NO_ITALICS_OUTPUT}" in
*"${EXPECTED_LATEST_ROW}"*) ;;
*) die "colored nvm ls-remote used italics on a terminal without italics support; got >${NO_ITALICS_OUTPUT}<" ;;
esac
OUTPUT="$(command printf '%s\n' "${OUTPUT}" | command sed "s/${ESC}\[[0-9;]*m//g")"
EXPECTED_OUTPUT="$(command printf '%s\n' "${EXPECTED_OUTPUT}" | command sed 's/^\( v1\.5\.0\) \*/\1 /')"
[ "_${OUTPUT}" = "_${EXPECTED_OUTPUT}" ] \
|| die "colored nvm ls-remote did not keep annotation columns aligned; got >${OUTPUT}< expected >${EXPECTED_OUTPUT}<"
nvm_has_colors() { return 1; }
nvm_remote_versions() {
command printf '%s\n' 'v2.0.0-nightly20240101abcdef0123 Iron *' 'v3.0.0-nightly2024020201234567890abc'
}
nvm_make_alias 'nightly-project' 'v2.0.0-nightly20240101abcdef0123' >/dev/null
OUTPUT="$(nvm ls-remote --no-colors)"
ALIASES_COLUMNS="$(command printf '%s\n' "${OUTPUT}" | command awk 'index($0, "(Aliases:") { print index($0, "(Aliases:") }' | command sort -u)"
[ "$(command printf '%s\n' "${ALIASES_COLUMNS}" | command wc -l | command tr -d ' ')" = 1 ] \
|| die "versions wider than the version column did not keep Aliases annotations in one column; got >${OUTPUT}<"
cleanup
+10
View File
@@ -20,6 +20,16 @@ nvm_make_alias() {
return 0
}
nvm_get_remote_aliases() {
# prevent local aliases from leaking into `nvm ls-remote` mocks
return 0
}
nvm_has_italics() {
# keep mocks independent of the local terminal's italics support
return 0
}
nvm_ls_remote > "$MOCKS_DIR/nvm_ls_remote.txt"
nvm_ls_remote_iojs > "$MOCKS_DIR/nvm_ls_remote_iojs.txt"
NVM_LTS=* nvm_ls_remote > "$MOCKS_DIR/nvm_ls_remote LTS.txt"