mirror of
https://github.com/nvm-sh/nvm.git
synced 2026-08-25 00:00:22 +08:00
Compare commits
16
Commits
e2e612e722
...
3a8b51c46c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3a8b51c46c | ||
|
|
ebada63259 | ||
|
|
0a9dead76d | ||
|
|
304a22ad59 | ||
|
|
d22bf7f538 | ||
|
|
dd61ae4bc8 | ||
|
|
59cf9a4ef6 | ||
|
|
21d33ef04a | ||
|
|
82315e2b18 | ||
|
|
ab77712867 | ||
|
|
0c1243a7ea | ||
|
|
9142a92cdc | ||
|
|
04fef13bdc | ||
|
|
cb0e0ba8ed | ||
|
|
b16fb6ece9 | ||
|
|
190cb9458b |
@@ -49,7 +49,6 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
needs: [matrix]
|
needs: [matrix]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
continue-on-error: ${{ matrix.ref == 'v0.40.0' }} # https://github.com/nvm-sh/nvm/issues/3405
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
@@ -81,12 +80,19 @@ jobs:
|
|||||||
set -e
|
set -e
|
||||||
export NVM_INSTALL_VERSION="${ref}"
|
export NVM_INSTALL_VERSION="${ref}"
|
||||||
curl -o- "https://raw.githubusercontent.com/nvm-sh/nvm/${ref}/install.sh" | bash
|
curl -o- "https://raw.githubusercontent.com/nvm-sh/nvm/${ref}/install.sh" | bash
|
||||||
|
# v0.40.0 with an .nvmrc present is expected to fail (https://github.com/nvm-sh/nvm/issues/3405):
|
||||||
|
# the steps below tolerate failure for that combination, and the final step
|
||||||
|
# turns the job red only if the expected failure did NOT happen.
|
||||||
- name: nvm --version
|
- name: nvm --version
|
||||||
|
id: nvm-version
|
||||||
|
continue-on-error: ${{ matrix.ref == 'v0.40.0' && matrix.has-nvmrc == 'nvmrc' }}
|
||||||
run: |
|
run: |
|
||||||
set +e
|
set +e
|
||||||
. $NVM_DIR/nvm.sh && nvm --version
|
. $NVM_DIR/nvm.sh && nvm --version
|
||||||
- name: nvm install in 1 shell level, ${{ matrix.has-nvmrc }}
|
- name: nvm install in 1 shell level, ${{ matrix.has-nvmrc }}
|
||||||
|
id: install-1
|
||||||
if: ${{ matrix.shell-level == '1 shlvl' }}
|
if: ${{ matrix.shell-level == '1 shlvl' }}
|
||||||
|
continue-on-error: ${{ matrix.ref == 'v0.40.0' && matrix.has-nvmrc == 'nvmrc' }}
|
||||||
run: |
|
run: |
|
||||||
set -ex
|
set -ex
|
||||||
. $NVM_DIR/nvm.sh
|
. $NVM_DIR/nvm.sh
|
||||||
@@ -96,13 +102,29 @@ jobs:
|
|||||||
nvm install
|
nvm install
|
||||||
fi
|
fi
|
||||||
- name: nvm install in 2 shell levels, ${{ matrix.has-nvmrc }}
|
- name: nvm install in 2 shell levels, ${{ matrix.has-nvmrc }}
|
||||||
|
id: install-2
|
||||||
if: ${{ matrix.shell-level == '2 shlvls' }}
|
if: ${{ matrix.shell-level == '2 shlvls' }}
|
||||||
|
continue-on-error: ${{ matrix.ref == 'v0.40.0' && matrix.has-nvmrc == 'nvmrc' }}
|
||||||
run: |
|
run: |
|
||||||
if [ '${{ matrix.has-nvmrc }}' == 'nvmrc' ]; then
|
if [ '${{ matrix.has-nvmrc }}' == 'nvmrc' ]; then
|
||||||
bash -c "set -ex && . $NVM_DIR/nvm.sh && echo nvm.sh sourced && nvm --version && nvm install"
|
bash -c "set -ex && . $NVM_DIR/nvm.sh && echo nvm.sh sourced && nvm --version && nvm install"
|
||||||
else
|
else
|
||||||
bash -c "set -ex && . $NVM_DIR/nvm.sh && echo nvm.sh sourced && nvm --version"
|
bash -c "set -ex && . $NVM_DIR/nvm.sh && echo nvm.sh sourced && nvm --version"
|
||||||
fi
|
fi
|
||||||
|
- name: 'confirm the expected failure happened (v0.40.0 + nvmrc)'
|
||||||
|
if: ${{ matrix.ref == 'v0.40.0' && matrix.has-nvmrc == 'nvmrc' }}
|
||||||
|
env:
|
||||||
|
SOURCE_OUTCOME: ${{ steps.nvm-version.outcome }}
|
||||||
|
INSTALL_1_OUTCOME: ${{ steps.install-1.outcome }}
|
||||||
|
INSTALL_2_OUTCOME: ${{ steps.install-2.outcome }}
|
||||||
|
run: |
|
||||||
|
echo "nvm --version: ${SOURCE_OUTCOME}; install (1 shlvl): ${INSTALL_1_OUTCOME}; install (2 shlvls): ${INSTALL_2_OUTCOME}"
|
||||||
|
if [ "${SOURCE_OUTCOME}" = 'failure' ] || [ "${INSTALL_1_OUTCOME}" = 'failure' ] || [ "${INSTALL_2_OUTCOME}" = 'failure' ]; then
|
||||||
|
echo 'v0.40.0 failed as expected: https://github.com/nvm-sh/nvm/issues/3405'
|
||||||
|
else
|
||||||
|
echo '::error::v0.40.0 with an .nvmrc was expected to fail (https://github.com/nvm-sh/nvm/issues/3405), but every step succeeded. If v0.40.0 somehow works now, remove the expected-failure handling from this workflow.'
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
finisher:
|
finisher:
|
||||||
permissions:
|
permissions:
|
||||||
|
|||||||
@@ -998,13 +998,13 @@ export NVM_DIR="$HOME/.nvm"
|
|||||||
|
|
||||||
## Docker For Development Environment
|
## Docker For Development Environment
|
||||||
|
|
||||||
To make the development and testing work easier, we have a Dockerfile for development usage, which is based on Ubuntu 18.04 base image, prepared with essential and useful tools for `nvm` development, to build the docker image of the environment, run the docker command at the root of `nvm` repository:
|
To make development and testing work easier we supply a Dockerfile for development usage. It's based on an Ubuntu base image prepared with essential and useful tools for `nvm` development. To build the docker image of the environment, do a Docker build at the root of `nvm` repository:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
$ docker build -t nvm-dev .
|
$ docker build -t nvm-dev .
|
||||||
```
|
```
|
||||||
|
|
||||||
This will package your current nvm repository with our pre-defined development environment into a docker image named `nvm-dev`, once it's built with success, validate your image via `docker images`:
|
This will package your current nvm working copy with our pre-defined development environment into a Docker image named `nvm-dev`. After the build you should see it appear in the list of images:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
$ docker images
|
$ docker images
|
||||||
@@ -1013,7 +1013,7 @@ REPOSITORY TAG IMAGE ID CREATED S
|
|||||||
nvm-dev latest 9ca4c57a97d8 7 days ago 650 MB
|
nvm-dev latest 9ca4c57a97d8 7 days ago 650 MB
|
||||||
```
|
```
|
||||||
|
|
||||||
If you got no error message, now you can easily involve in:
|
To start and enter a container based on this image:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
$ docker run -h nvm-dev -it nvm-dev
|
$ docker run -h nvm-dev -it nvm-dev
|
||||||
@@ -1021,12 +1021,9 @@ $ docker run -h nvm-dev -it nvm-dev
|
|||||||
nvm@nvm-dev:~/.nvm$
|
nvm@nvm-dev:~/.nvm$
|
||||||
```
|
```
|
||||||
|
|
||||||
Please note that it'll take about 8 minutes to build the image and the image size would be about 650MB, so it's not suitable for production usage.
|
It takes several minutes to build the image and the image size is about 650MB, so it's not suitable for production usage.
|
||||||
|
|
||||||
For more information and documentation about docker, please refer to its official website:
|
For more information and documentation about Docker, please refer to its [official website][docker-www] and [documentation][docker-docs]:
|
||||||
|
|
||||||
- https://www.docker.com/
|
|
||||||
- https://docs.docker.com/
|
|
||||||
|
|
||||||
## Problems
|
## Problems
|
||||||
|
|
||||||
@@ -1205,3 +1202,7 @@ See [LICENSE.md](./LICENSE.md).
|
|||||||
|
|
||||||
Copyright [OpenJS Foundation](https://openjsf.org) and `nvm` contributors. All rights reserved. The [OpenJS Foundation](https://openjsf.org) has registered trademarks and uses trademarks. For a list of trademarks of the [OpenJS Foundation](https://openjsf.org), please see our [Trademark Policy](https://trademark-policy.openjsf.org/) and [Trademark List](https://trademark-list.openjsf.org/). Trademarks and logos not indicated on the [list of OpenJS Foundation trademarks](https://trademark-list.openjsf.org) are trademarks™ or registered® trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.
|
Copyright [OpenJS Foundation](https://openjsf.org) and `nvm` contributors. All rights reserved. The [OpenJS Foundation](https://openjsf.org) has registered trademarks and uses trademarks. For a list of trademarks of the [OpenJS Foundation](https://openjsf.org), please see our [Trademark Policy](https://trademark-policy.openjsf.org/) and [Trademark List](https://trademark-list.openjsf.org/). Trademarks and logos not indicated on the [list of OpenJS Foundation trademarks](https://trademark-list.openjsf.org) are trademarks™ or registered® trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.
|
||||||
[The OpenJS Foundation](https://openjsf.org/) | [Terms of Use](https://terms-of-use.openjsf.org/) | [Privacy Policy](https://privacy-policy.openjsf.org/) | [Bylaws](https://bylaws.openjsf.org/) | [Code of Conduct](https://code-of-conduct.openjsf.org) | [Trademark Policy](https://trademark-policy.openjsf.org/) | [Trademark List](https://trademark-list.openjsf.org/) | [Cookie Policy](https://www.linuxfoundation.org/cookies/)
|
[The OpenJS Foundation](https://openjsf.org/) | [Terms of Use](https://terms-of-use.openjsf.org/) | [Privacy Policy](https://privacy-policy.openjsf.org/) | [Bylaws](https://bylaws.openjsf.org/) | [Code of Conduct](https://code-of-conduct.openjsf.org) | [Trademark Policy](https://trademark-policy.openjsf.org/) | [Trademark List](https://trademark-list.openjsf.org/) | [Cookie Policy](https://www.linuxfoundation.org/cookies/)
|
||||||
|
|
||||||
|
<!-------------------------------------------------------------------->
|
||||||
|
[docker-docs]: https://docs.docker.com/
|
||||||
|
[docker-www]: https://www.docker.com/
|
||||||
|
|||||||
+19
-7
@@ -6,6 +6,18 @@ nvm_has() {
|
|||||||
type "$1" > /dev/null 2>&1
|
type "$1" > /dev/null 2>&1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# resolves like `command "${1}"` does: only executables on the PATH,
|
||||||
|
# ignoring shell functions and aliases
|
||||||
|
nvm_has_executable() {
|
||||||
|
(
|
||||||
|
# `|| true` so that shells with errexit-style options (eg, zsh's ERR_RETURN)
|
||||||
|
# do not abort the subshell when the name is not an alias or a function
|
||||||
|
unalias "${1-}" 2>/dev/null || true
|
||||||
|
unset -f "${1-}" 2>/dev/null || true
|
||||||
|
command -v "${1-}" > /dev/null 2>&1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
nvm_echo() {
|
nvm_echo() {
|
||||||
command printf %s\\n "$*" 2>/dev/null
|
command printf %s\\n "$*" 2>/dev/null
|
||||||
}
|
}
|
||||||
@@ -105,9 +117,9 @@ nvm_node_version() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nvm_download() {
|
nvm_download() {
|
||||||
if nvm_has "curl"; then
|
if nvm_has_executable "curl"; then
|
||||||
curl --fail --compressed -q "$@"
|
command curl --fail --compressed -q "$@"
|
||||||
elif nvm_has "wget"; then
|
elif nvm_has_executable "wget"; then
|
||||||
# Emulate curl with wget
|
# Emulate curl with wget
|
||||||
ARGS=$(nvm_echo "$@" | command sed -e 's/--progress-bar /--progress=bar /' \
|
ARGS=$(nvm_echo "$@" | command sed -e 's/--progress-bar /--progress=bar /' \
|
||||||
-e 's/--compressed //' \
|
-e 's/--compressed //' \
|
||||||
@@ -119,7 +131,7 @@ nvm_download() {
|
|||||||
-e 's/-o /-O /' \
|
-e 's/-o /-O /' \
|
||||||
-e 's/-C - /-c /')
|
-e 's/-C - /-c /')
|
||||||
# shellcheck disable=SC2086
|
# shellcheck disable=SC2086
|
||||||
eval wget $ARGS
|
eval command wget $ARGS
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -401,7 +413,7 @@ nvm_do_install() {
|
|||||||
# Autodetect install method
|
# Autodetect install method
|
||||||
if nvm_has git; then
|
if nvm_has git; then
|
||||||
install_nvm_from_git
|
install_nvm_from_git
|
||||||
elif nvm_has curl || nvm_has wget; then
|
elif nvm_has_executable curl || nvm_has_executable wget; then
|
||||||
install_nvm_as_script
|
install_nvm_as_script
|
||||||
else
|
else
|
||||||
nvm_echo >&2 'You need git, curl, or wget to install nvm'
|
nvm_echo >&2 'You need git, curl, or wget to install nvm'
|
||||||
@@ -414,7 +426,7 @@ nvm_do_install() {
|
|||||||
fi
|
fi
|
||||||
install_nvm_from_git
|
install_nvm_from_git
|
||||||
elif [ "${METHOD}" = 'script' ]; then
|
elif [ "${METHOD}" = 'script' ]; then
|
||||||
if ! nvm_has curl && ! nvm_has wget; then
|
if ! nvm_has_executable curl && ! nvm_has_executable wget; then
|
||||||
nvm_echo >&2 "You need curl or wget to install nvm"
|
nvm_echo >&2 "You need curl or wget to install nvm"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@@ -496,7 +508,7 @@ nvm_do_install() {
|
|||||||
# during the execution of the install script
|
# during the execution of the install script
|
||||||
#
|
#
|
||||||
nvm_reset() {
|
nvm_reset() {
|
||||||
unset -f nvm_has nvm_install_dir nvm_latest_version nvm_profile_is_bash_or_zsh \
|
unset -f nvm_has nvm_has_executable nvm_install_dir nvm_latest_version nvm_profile_is_bash_or_zsh \
|
||||||
nvm_source nvm_node_version nvm_download install_nvm_from_git nvm_install_node \
|
nvm_source nvm_node_version nvm_download install_nvm_from_git nvm_install_node \
|
||||||
install_nvm_as_script nvm_try_profile nvm_detect_profile nvm_check_global_modules \
|
install_nvm_as_script nvm_try_profile nvm_detect_profile nvm_check_global_modules \
|
||||||
nvm_do_install nvm_reset nvm_default_install_dir nvm_grep
|
nvm_do_install nvm_reset nvm_default_install_dir nvm_grep
|
||||||
|
|||||||
@@ -49,6 +49,18 @@ nvm_has() {
|
|||||||
type "${1-}" >/dev/null 2>&1
|
type "${1-}" >/dev/null 2>&1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# resolves like `command "${1}"` does: only executables on the PATH,
|
||||||
|
# ignoring shell functions and aliases
|
||||||
|
nvm_has_executable() {
|
||||||
|
(
|
||||||
|
# `|| true` so that shells with errexit-style options (eg, zsh's ERR_RETURN)
|
||||||
|
# do not abort the subshell when the name is not an alias or a function
|
||||||
|
unalias "${1-}" 2>/dev/null || true
|
||||||
|
unset -f "${1-}" 2>/dev/null || true
|
||||||
|
command -v "${1-}" >/dev/null 2>&1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
nvm_has_non_aliased() {
|
nvm_has_non_aliased() {
|
||||||
nvm_has "${1-}" && ! nvm_is_alias "${1-}"
|
nvm_has "${1-}" && ! nvm_is_alias "${1-}"
|
||||||
}
|
}
|
||||||
@@ -87,7 +99,7 @@ nvm_has_colors() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nvm_curl_libz_support() {
|
nvm_curl_libz_support() {
|
||||||
curl -V 2>/dev/null | nvm_grep "^Features:" | nvm_grep -q "libz"
|
command curl -V 2>/dev/null | nvm_grep "^Features:" | nvm_grep -q "libz"
|
||||||
}
|
}
|
||||||
|
|
||||||
nvm_curl_use_compression() {
|
nvm_curl_use_compression() {
|
||||||
@@ -97,13 +109,13 @@ nvm_curl_use_compression() {
|
|||||||
nvm_get_latest() {
|
nvm_get_latest() {
|
||||||
local NVM_LATEST_URL
|
local NVM_LATEST_URL
|
||||||
local CURL_COMPRESSED_FLAG
|
local CURL_COMPRESSED_FLAG
|
||||||
if nvm_has "curl"; then
|
if nvm_has_executable "curl"; then
|
||||||
if nvm_curl_use_compression; then
|
if nvm_curl_use_compression; then
|
||||||
CURL_COMPRESSED_FLAG="--compressed"
|
CURL_COMPRESSED_FLAG="--compressed"
|
||||||
fi
|
fi
|
||||||
NVM_LATEST_URL="$(curl ${CURL_COMPRESSED_FLAG:-} -q -w "%{url_effective}\\n" -L -s -S https://latest.nvm.sh -o /dev/null)"
|
NVM_LATEST_URL="$(command curl ${CURL_COMPRESSED_FLAG:-} -q -w "%{url_effective}\\n" -L -s -S https://latest.nvm.sh -o /dev/null)"
|
||||||
elif nvm_has "wget"; then
|
elif nvm_has_executable "wget"; then
|
||||||
NVM_LATEST_URL="$(wget -q https://latest.nvm.sh --server-response -O /dev/null 2>&1 | command awk '/^ Location: /{DEST=$2} END{ print DEST }')"
|
NVM_LATEST_URL="$(command wget -q https://latest.nvm.sh --server-response -O /dev/null 2>&1 | command awk '/^ Location: /{DEST=$2} END{ print DEST }')"
|
||||||
else
|
else
|
||||||
nvm_err 'nvm needs curl or wget to proceed.'
|
nvm_err 'nvm needs curl or wget to proceed.'
|
||||||
return 1
|
return 1
|
||||||
@@ -127,13 +139,13 @@ nvm_download() {
|
|||||||
|
|
||||||
local NVM_DOWNLOADER
|
local NVM_DOWNLOADER
|
||||||
NVM_DOWNLOADER=''
|
NVM_DOWNLOADER=''
|
||||||
if nvm_has "curl"; then
|
if nvm_has_executable "curl"; then
|
||||||
NVM_DOWNLOADER='curl'
|
NVM_DOWNLOADER='curl'
|
||||||
set -- -q --fail "$@"
|
set -- -q --fail "$@"
|
||||||
if nvm_curl_use_compression; then
|
if nvm_curl_use_compression; then
|
||||||
set -- --compressed "$@"
|
set -- --compressed "$@"
|
||||||
fi
|
fi
|
||||||
elif nvm_has "wget"; then
|
elif nvm_has_executable "wget"; then
|
||||||
NVM_DOWNLOADER='wget'
|
NVM_DOWNLOADER='wget'
|
||||||
# Emulate curl with wget
|
# Emulate curl with wget
|
||||||
local NVM_DOWNLOAD_WGET_COUNT
|
local NVM_DOWNLOAD_WGET_COUNT
|
||||||
@@ -170,12 +182,17 @@ nvm_download() {
|
|||||||
set -- "$@" --header "Authorization: ${sanitized_header}"
|
set -- "$@" --header "Authorization: ${sanitized_header}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
"${NVM_DOWNLOADER}" "$@"
|
command "${NVM_DOWNLOADER}" "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
nvm_sanitize_auth_header() {
|
nvm_sanitize_auth_header() {
|
||||||
# Remove potentially dangerous characters
|
# Remove potentially dangerous characters; allow the full base64 (A-Za-z0-9+/=)
|
||||||
nvm_echo "$1" | command sed 's/[^a-zA-Z0-9:;_. -]//g'
|
# and base64url (A-Za-z0-9-_=) charsets, plus the space, colon, dot, and
|
||||||
|
# underscore the previous allowlist already permitted, so that values like
|
||||||
|
# `Basic <base64>` and `Bearer <token>` survive intact.
|
||||||
|
# token68's '~' is still stripped.
|
||||||
|
# Note: '-' must be at the end of the bracket expression to be treated as a literal.
|
||||||
|
nvm_echo "$1" | command sed 's/[^a-zA-Z0-9 :_.+/=-]//g'
|
||||||
}
|
}
|
||||||
|
|
||||||
nvm_has_system_node() {
|
nvm_has_system_node() {
|
||||||
@@ -548,12 +565,12 @@ ${1}"
|
|||||||
$(nvm_wrap_with_color_code 'y' "${warn_text}")"
|
$(nvm_wrap_with_color_code 'y' "${warn_text}")"
|
||||||
}
|
}
|
||||||
|
|
||||||
nvm_process_nvmrc() {
|
nvm_process_nvmrc_content() {
|
||||||
local NVMRC_PATH
|
local NVMRC_CONTENT
|
||||||
NVMRC_PATH="$1"
|
NVMRC_CONTENT="${1-}"
|
||||||
local lines
|
local lines
|
||||||
|
|
||||||
lines=$(command sed 's/#.*//' "$NVMRC_PATH" | command sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | nvm_grep -v '^$')
|
lines=$(nvm_echo "${NVMRC_CONTENT}" | command sed 's/#.*//' | command sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | nvm_grep -v '^$')
|
||||||
|
|
||||||
if [ -z "$lines" ]; then
|
if [ -z "$lines" ]; then
|
||||||
nvm_nvmrc_invalid_msg "${lines}"
|
nvm_nvmrc_invalid_msg "${lines}"
|
||||||
@@ -617,6 +634,13 @@ EOF
|
|||||||
nvm_echo "${unpaired_line}"
|
nvm_echo "${unpaired_line}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nvm_process_nvmrc() {
|
||||||
|
local NVMRC_PATH
|
||||||
|
NVMRC_PATH="$1"
|
||||||
|
|
||||||
|
nvm_process_nvmrc_content "$(command cat "${NVMRC_PATH}")"
|
||||||
|
}
|
||||||
|
|
||||||
nvm_rc_version() {
|
nvm_rc_version() {
|
||||||
local NVMRC_PATH
|
local NVMRC_PATH
|
||||||
NVMRC_PATH="$(nvm_find_nvmrc)"
|
NVMRC_PATH="$(nvm_find_nvmrc)"
|
||||||
@@ -649,7 +673,7 @@ nvm_clang_version() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nvm_curl_version() {
|
nvm_curl_version() {
|
||||||
curl -V | command awk '{ if ($1 == "curl") print $2 }' | command sed 's/-.*$//g'
|
command curl -V | command awk '{ if ($1 == "curl") print $2 }' | command sed 's/-.*$//g'
|
||||||
}
|
}
|
||||||
|
|
||||||
nvm_version_greater() {
|
nvm_version_greater() {
|
||||||
@@ -1343,7 +1367,24 @@ nvm_alias() {
|
|||||||
return 2
|
return 2
|
||||||
fi
|
fi
|
||||||
|
|
||||||
command sed 's/#.*//; s/[[:space:]]*$//' "${NVM_ALIAS_PATH}" | command awk 'NF'
|
if [ ! -r "${NVM_ALIAS_PATH}" ]; then
|
||||||
|
# an existing-but-unreadable alias file yields empty output with a success
|
||||||
|
# status - a nonzero status here would make `nvm_ensure_default_set`
|
||||||
|
# overwrite an existing default alias it merely could not read
|
||||||
|
nvm_err "Alias file is not readable: ${NVM_ALIAS_PATH}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local NVM_ALIAS_LINE
|
||||||
|
while IFS= read -r NVM_ALIAS_LINE || [ -n "${NVM_ALIAS_LINE}" ]; do
|
||||||
|
NVM_ALIAS_LINE="${NVM_ALIAS_LINE%%#*}"
|
||||||
|
case "${NVM_ALIAS_LINE}" in
|
||||||
|
*[![:space:]]*) ;;
|
||||||
|
*) continue ;;
|
||||||
|
esac
|
||||||
|
NVM_ALIAS_LINE="${NVM_ALIAS_LINE%"${NVM_ALIAS_LINE##*[![:space:]]}"}"
|
||||||
|
nvm_echo "${NVM_ALIAS_LINE}"
|
||||||
|
done < "${NVM_ALIAS_PATH}"
|
||||||
}
|
}
|
||||||
|
|
||||||
nvm_ls_current() {
|
nvm_ls_current() {
|
||||||
@@ -1376,24 +1417,32 @@ nvm_resolve_alias() {
|
|||||||
local ALIAS
|
local ALIAS
|
||||||
ALIAS="${PATTERN}"
|
ALIAS="${PATTERN}"
|
||||||
local ALIAS_TEMP
|
local ALIAS_TEMP
|
||||||
|
local ALIAS_OUTPUT
|
||||||
|
|
||||||
local SEEN_ALIASES
|
local SEEN_ALIASES
|
||||||
SEEN_ALIASES="${ALIAS}"
|
SEEN_ALIASES="
|
||||||
local NVM_ALIAS_INDEX
|
${ALIAS}
|
||||||
NVM_ALIAS_INDEX=1
|
"
|
||||||
while true; do
|
while true; do
|
||||||
ALIAS_TEMP="$( (nvm_alias "${ALIAS}" 2>/dev/null | command head -n "${NVM_ALIAS_INDEX}" | command tail -n 1) || nvm_echo)"
|
ALIAS_OUTPUT="$(nvm_alias "${ALIAS}" 2>/dev/null)" || ALIAS_OUTPUT=''
|
||||||
|
ALIAS_TEMP="${ALIAS_OUTPUT%%
|
||||||
|
*}"
|
||||||
|
|
||||||
if [ -z "${ALIAS_TEMP}" ]; then
|
if [ -z "${ALIAS_TEMP}" ]; then
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if command printf '%b' "${SEEN_ALIASES}" | nvm_grep -q -e "^${ALIAS_TEMP}$"; then
|
case "${SEEN_ALIASES}" in
|
||||||
|
*"
|
||||||
|
${ALIAS_TEMP}
|
||||||
|
"*)
|
||||||
ALIAS="∞"
|
ALIAS="∞"
|
||||||
break
|
break
|
||||||
fi
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
SEEN_ALIASES="${SEEN_ALIASES}\\n${ALIAS_TEMP}"
|
SEEN_ALIASES="${SEEN_ALIASES}${ALIAS_TEMP}
|
||||||
|
"
|
||||||
ALIAS="${ALIAS_TEMP}"
|
ALIAS="${ALIAS_TEMP}"
|
||||||
done
|
done
|
||||||
|
|
||||||
@@ -1474,6 +1523,17 @@ nvm_strip_iojs_prefix() {
|
|||||||
nvm_ls() {
|
nvm_ls() {
|
||||||
local PATTERN
|
local PATTERN
|
||||||
PATTERN="${1-}"
|
PATTERN="${1-}"
|
||||||
|
case "${PATTERN}" in
|
||||||
|
*'#'* | *'
|
||||||
|
'*)
|
||||||
|
local NVMRC_PATTERN
|
||||||
|
if ! NVMRC_PATTERN="$(nvm_process_nvmrc_content "${PATTERN}" 2>/dev/null)"; then
|
||||||
|
nvm_echo 'N/A'
|
||||||
|
return 3
|
||||||
|
fi
|
||||||
|
PATTERN="${NVMRC_PATTERN}"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
local VERSIONS
|
local VERSIONS
|
||||||
VERSIONS=''
|
VERSIONS=''
|
||||||
if [ "${PATTERN}" = 'current' ]; then
|
if [ "${PATTERN}" = 'current' ]; then
|
||||||
@@ -2171,6 +2231,7 @@ nvm_get_arch() {
|
|||||||
x86_64 | amd64) NVM_ARCH="x64" ;;
|
x86_64 | amd64) NVM_ARCH="x64" ;;
|
||||||
i*86) NVM_ARCH="x86" ;;
|
i*86) NVM_ARCH="x86" ;;
|
||||||
aarch64 | armv8l) NVM_ARCH="arm64" ;;
|
aarch64 | armv8l) NVM_ARCH="arm64" ;;
|
||||||
|
loongarch64) NVM_ARCH="loong64" ;;
|
||||||
*) NVM_ARCH="${HOST_ARCH}" ;;
|
*) NVM_ARCH="${HOST_ARCH}" ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
@@ -2438,16 +2499,11 @@ nvm_get_download_slug() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# If running MAC M1 :: Node v14.17.0 was the first version to offer official experimental support:
|
# If running MAC M1 :: ARM64 binaries are not available for Node < 16.0.0
|
||||||
# https://github.com/nodejs/node/issues/40126 (although binary distributions aren't available until v16)
|
# https://github.com/nodejs/node/issues/40126 (binary distributions aren't available until v16)
|
||||||
if \
|
if nvm_version_greater '16.0.0' "${VERSION}" && [ "_${NVM_OS}" = '_darwin' ] && [ "${NVM_ARCH}" = 'arm64' ]; then
|
||||||
nvm_version_greater '14.17.0' "${VERSION}" \
|
|
||||||
|| (nvm_version_greater_than_or_equal_to "${VERSION}" '15.0.0' && nvm_version_greater '16.0.0' "${VERSION}") \
|
|
||||||
; then
|
|
||||||
if [ "_${NVM_OS}" = '_darwin' ] && [ "${NVM_ARCH}" = 'arm64' ]; then
|
|
||||||
NVM_ARCH=x64
|
NVM_ARCH=x64
|
||||||
fi
|
fi
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "${KIND}" = 'binary' ]; then
|
if [ "${KIND}" = 'binary' ]; then
|
||||||
nvm_echo "${FLAVOR}-${VERSION}-${NVM_OS}-${NVM_ARCH}"
|
nvm_echo "${FLAVOR}-${VERSION}-${NVM_OS}-${NVM_ARCH}"
|
||||||
@@ -3574,7 +3630,7 @@ nvm() {
|
|||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ "${NVM_OFFLINE}" != 1 ] && ! nvm_has "curl" && ! nvm_has "wget"; then
|
if [ "${NVM_OFFLINE}" != 1 ] && ! nvm_has_executable "curl" && ! nvm_has_executable "wget"; then
|
||||||
nvm_err 'nvm needs curl or wget to proceed.'
|
nvm_err 'nvm needs curl or wget to proceed.'
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
@@ -4693,7 +4749,7 @@ nvm() {
|
|||||||
nvm_version_greater nvm_version_greater_than_or_equal_to \
|
nvm_version_greater nvm_version_greater_than_or_equal_to \
|
||||||
nvm_print_npm_version nvm_install_latest_npm nvm_npm_global_modules \
|
nvm_print_npm_version nvm_install_latest_npm nvm_npm_global_modules \
|
||||||
nvm_has_system_node nvm_has_system_iojs \
|
nvm_has_system_node nvm_has_system_iojs \
|
||||||
nvm_download nvm_get_latest nvm_has nvm_install_default_packages nvm_get_default_packages \
|
nvm_download nvm_get_latest nvm_has nvm_has_executable nvm_install_default_packages nvm_get_default_packages \
|
||||||
nvm_curl_use_compression nvm_curl_version \
|
nvm_curl_use_compression nvm_curl_version \
|
||||||
nvm_auto nvm_supports_xz \
|
nvm_auto nvm_supports_xz \
|
||||||
nvm_echo nvm_err nvm_grep nvm_cd \
|
nvm_echo nvm_err nvm_grep nvm_cd \
|
||||||
@@ -4709,7 +4765,7 @@ nvm() {
|
|||||||
nvm_get_colors nvm_set_colors nvm_print_color_code nvm_wrap_with_color_code nvm_format_help_message_colors \
|
nvm_get_colors nvm_set_colors nvm_print_color_code nvm_wrap_with_color_code nvm_format_help_message_colors \
|
||||||
nvm_echo_with_colors nvm_err_with_colors \
|
nvm_echo_with_colors nvm_err_with_colors \
|
||||||
nvm_get_artifact_compression nvm_install_binary_extract nvm_extract_tarball \
|
nvm_get_artifact_compression nvm_install_binary_extract nvm_extract_tarball \
|
||||||
nvm_process_nvmrc nvm_nvmrc_invalid_msg \
|
nvm_process_nvmrc nvm_process_nvmrc_content nvm_nvmrc_invalid_msg \
|
||||||
nvm_write_nvmrc \
|
nvm_write_nvmrc \
|
||||||
>/dev/null 2>&1
|
>/dev/null 2>&1
|
||||||
unset NVM_NODEJS_ORG_MIRROR NVM_IOJS_ORG_MIRROR NVM_DIR \
|
unset NVM_NODEJS_ORG_MIRROR NVM_IOJS_ORG_MIRROR NVM_DIR \
|
||||||
|
|||||||
@@ -50,6 +50,39 @@ make_echo() {
|
|||||||
chmod a+x "$1"
|
chmod a+x "$1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# `command curl` bypasses shell functions and aliases, so tests that mock curl
|
||||||
|
# must provide an actual executable on the PATH: this creates one in the given
|
||||||
|
# directory. Invoked as `curl -V`, it prints ${VERSION_MESSAGE} (exported here
|
||||||
|
# on the mock's behalf); any other invocation runs the body given as the
|
||||||
|
# second argument, or fails.
|
||||||
|
make_fake_curl() {
|
||||||
|
local FAKE_BIN_DIR
|
||||||
|
FAKE_BIN_DIR="${1-}"
|
||||||
|
[ -n "${FAKE_BIN_DIR}" ] || return 1
|
||||||
|
|
||||||
|
local FAKE_CURL_BODY
|
||||||
|
FAKE_CURL_BODY="${2-}"
|
||||||
|
if [ -z "${FAKE_CURL_BODY}" ]; then
|
||||||
|
FAKE_CURL_BODY='echo >&2 "This fake curl only takes one parameter, -V"
|
||||||
|
exit 1'
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "${FAKE_BIN_DIR}" || return 2
|
||||||
|
|
||||||
|
{
|
||||||
|
echo '#!/bin/sh'
|
||||||
|
echo 'if [ "$#" -eq 1 ] && [ "$1" = "-V" ]; then'
|
||||||
|
echo ' echo "${VERSION_MESSAGE}"'
|
||||||
|
echo ' exit 0'
|
||||||
|
echo 'fi'
|
||||||
|
printf '%s\n' "${FAKE_CURL_BODY}"
|
||||||
|
} > "${FAKE_BIN_DIR}/curl"
|
||||||
|
chmod +x "${FAKE_BIN_DIR}/curl"
|
||||||
|
|
||||||
|
# the fake curl reads VERSION_MESSAGE from the environment
|
||||||
|
export VERSION_MESSAGE
|
||||||
|
}
|
||||||
|
|
||||||
make_fake_node() {
|
make_fake_node() {
|
||||||
local VERSION
|
local VERSION
|
||||||
VERSION="${1-}"
|
VERSION="${1-}"
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
die () { echo "$@" ; exit 1; }
|
||||||
|
|
||||||
|
export NVM_DIR="$(cd ../../.. && pwd)"
|
||||||
|
|
||||||
|
: nvm.sh
|
||||||
|
\. "${NVM_DIR}/nvm.sh"
|
||||||
|
|
||||||
|
# Create an alias file whose name contains spaces
|
||||||
|
mkdir -p ../../../alias
|
||||||
|
printf 'v22.1.0\n' > "../../../alias/test edge spaces"
|
||||||
|
ACTUAL="$(nvm_alias "test edge spaces")"
|
||||||
|
EXPECTED='v22.1.0'
|
||||||
|
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}<, got >${ACTUAL}<"
|
||||||
|
|
||||||
|
rm -f "../../../alias/test edge spaces"
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
die () { echo "$@" ; exit 1; }
|
||||||
|
|
||||||
|
export NVM_DIR="$(cd ../../.. && pwd)"
|
||||||
|
|
||||||
|
: nvm.sh
|
||||||
|
\. "${NVM_DIR}/nvm.sh"
|
||||||
|
|
||||||
|
# Create an alias file where the first line has a valid version
|
||||||
|
# followed by a second line of binary-like data
|
||||||
|
printf 'v22.1.0\n' > ../../../alias/test-edge-binary
|
||||||
|
printf '\001\002\003\377\n' >> ../../../alias/test-edge-binary
|
||||||
|
ACTUAL="$(nvm_alias test-edge-binary)"
|
||||||
|
# nvm_alias emits every non-blank, non-comment line — first line should be the version
|
||||||
|
FIRST_LINE="$(nvm_echo "${ACTUAL}" | command head -n 1)"
|
||||||
|
EXPECTED='v22.1.0'
|
||||||
|
[ "${FIRST_LINE}" = "${EXPECTED}" ] || die "expected first line >${EXPECTED}<, got >${FIRST_LINE}<"
|
||||||
|
|
||||||
|
rm -f ../../../alias/test-edge-binary
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
die () { echo "$@" ; exit 1; }
|
||||||
|
|
||||||
|
export NVM_DIR="$(cd ../../.. && pwd)"
|
||||||
|
|
||||||
|
: nvm.sh
|
||||||
|
\. "${NVM_DIR}/nvm.sh"
|
||||||
|
|
||||||
|
# Create an alias file with Windows-style line endings (CRLF)
|
||||||
|
printf 'v22.1.0\r\n' > ../../../alias/test-edge-cr
|
||||||
|
ACTUAL="$(nvm_alias test-edge-cr)"
|
||||||
|
EXPECTED='v22.1.0'
|
||||||
|
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}<, got >${ACTUAL}<"
|
||||||
|
|
||||||
|
# Create an alias file with bare carriage return (no newline)
|
||||||
|
printf 'v22.2.0\r' > ../../../alias/test-edge-cr-bare
|
||||||
|
ACTUAL="$(nvm_alias test-edge-cr-bare)"
|
||||||
|
EXPECTED='v22.2.0'
|
||||||
|
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}< for bare CR, got >${ACTUAL}<"
|
||||||
|
|
||||||
|
rm -f ../../../alias/test-edge-cr ../../../alias/test-edge-cr-bare
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
die () { echo "$@" ; exit 1; }
|
||||||
|
|
||||||
|
export NVM_DIR="$(cd ../../.. && pwd)"
|
||||||
|
|
||||||
|
: nvm.sh
|
||||||
|
\. "${NVM_DIR}/nvm.sh"
|
||||||
|
|
||||||
|
# Create an alias file containing only comments
|
||||||
|
printf '# this is a comment\n# another comment\n' > ../../../alias/test-edge-comments
|
||||||
|
ACTUAL="$(nvm_alias test-edge-comments 2>/dev/null)"
|
||||||
|
EXIT_CODE="$(nvm_alias test-edge-comments 2>/dev/null; echo $?)"
|
||||||
|
[ -z "${ACTUAL}" ] || die "expected empty output for comment-only alias file, got >${ACTUAL}<"
|
||||||
|
[ "${EXIT_CODE}" = '0' ] || die "expected exit code 0, got ${EXIT_CODE}"
|
||||||
|
|
||||||
|
rm -f ../../../alias/test-edge-comments
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
die () { echo "$@" ; exit 1; }
|
||||||
|
|
||||||
|
export NVM_DIR="$(cd ../../.. && pwd)"
|
||||||
|
|
||||||
|
: nvm.sh
|
||||||
|
\. "${NVM_DIR}/nvm.sh"
|
||||||
|
|
||||||
|
# Create an alias file with an embedded NUL byte after the version.
|
||||||
|
# NUL handling varies by shell: some stop at NUL, others read through it.
|
||||||
|
# The function must not crash, and must emit output starting with the version.
|
||||||
|
printf 'v22.1.0\000garbage\n' > ../../../alias/test-edge-nul
|
||||||
|
ACTUAL="$(nvm_alias test-edge-nul)"
|
||||||
|
EXIT_CODE=$?
|
||||||
|
[ "${EXIT_CODE}" = '0' ] || die "expected exit code 0, got ${EXIT_CODE}"
|
||||||
|
case "${ACTUAL}" in
|
||||||
|
v22.1.0*) ;; # OK — starts with the version regardless of NUL handling
|
||||||
|
*) die "expected output starting with >v22.1.0<, got >${ACTUAL}<" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
rm -f ../../../alias/test-edge-nul
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
die () { echo "$@" ; exit 1; }
|
||||||
|
|
||||||
|
export NVM_DIR="$(cd ../../.. && pwd)"
|
||||||
|
|
||||||
|
: nvm.sh
|
||||||
|
\. "${NVM_DIR}/nvm.sh"
|
||||||
|
|
||||||
|
# Create an empty alias file
|
||||||
|
printf '' > ../../../alias/test-edge-empty
|
||||||
|
ACTUAL="$(nvm_alias test-edge-empty 2>/dev/null)"
|
||||||
|
EXIT_CODE="$(nvm_alias test-edge-empty 2>/dev/null; echo $?)"
|
||||||
|
[ -z "${ACTUAL}" ] || die "expected empty output for empty alias file, got >${ACTUAL}<"
|
||||||
|
[ "${EXIT_CODE}" = '0' ] || die "expected exit code 0, got ${EXIT_CODE}"
|
||||||
|
|
||||||
|
rm -f ../../../alias/test-edge-empty
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
die () { echo "$@" ; exit 1; }
|
||||||
|
|
||||||
|
export NVM_DIR="$(cd ../../.. && pwd)"
|
||||||
|
|
||||||
|
: nvm.sh
|
||||||
|
\. "${NVM_DIR}/nvm.sh"
|
||||||
|
|
||||||
|
# Create an alias file with trailing form feed
|
||||||
|
printf 'v22.1.0\f\n' > ../../../alias/test-edge-ff
|
||||||
|
ACTUAL="$(nvm_alias test-edge-ff)"
|
||||||
|
EXPECTED='v22.1.0'
|
||||||
|
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}< for form feed, got >${ACTUAL}<"
|
||||||
|
|
||||||
|
# Create an alias file with trailing vertical tab
|
||||||
|
printf 'v22.2.0\v\n' > ../../../alias/test-edge-vt
|
||||||
|
ACTUAL="$(nvm_alias test-edge-vt)"
|
||||||
|
EXPECTED='v22.2.0'
|
||||||
|
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}< for vertical tab, got >${ACTUAL}<"
|
||||||
|
|
||||||
|
rm -f ../../../alias/test-edge-ff ../../../alias/test-edge-vt
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
die () { echo "$@" ; exit 1; }
|
||||||
|
|
||||||
|
export NVM_DIR="$(cd ../../.. && pwd)"
|
||||||
|
|
||||||
|
: nvm.sh
|
||||||
|
\. "${NVM_DIR}/nvm.sh"
|
||||||
|
|
||||||
|
# Create an alias file with no trailing newline
|
||||||
|
printf 'v22.1.0' > ../../../alias/test-edge-no-newline
|
||||||
|
ACTUAL="$(nvm_alias test-edge-no-newline)"
|
||||||
|
EXPECTED='v22.1.0'
|
||||||
|
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}<, got >${ACTUAL}<"
|
||||||
|
|
||||||
|
rm -f ../../../alias/test-edge-no-newline
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
die () { echo "$@" ; cleanup ; exit 1; }
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
chmod 644 ../../../alias/test-edge-unreadable 2>/dev/null
|
||||||
|
rm -f ../../../alias/test-edge-unreadable
|
||||||
|
}
|
||||||
|
|
||||||
|
export NVM_DIR="$(cd ../../.. && pwd)"
|
||||||
|
|
||||||
|
: nvm.sh
|
||||||
|
\. "${NVM_DIR}/nvm.sh"
|
||||||
|
|
||||||
|
# Create an alias file that exists but can not be read
|
||||||
|
echo 'v0.0.1' > ../../../alias/test-edge-unreadable
|
||||||
|
chmod 000 ../../../alias/test-edge-unreadable
|
||||||
|
|
||||||
|
# root (and some containers) can read mode-000 files; nothing to assert there
|
||||||
|
if [ -r ../../../alias/test-edge-unreadable ]; then
|
||||||
|
cleanup
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# like the sed/awk pipeline this replaced: empty output, success status, so
|
||||||
|
# that `nvm_ensure_default_set` does not overwrite an unreadable default alias
|
||||||
|
OUTPUT="$(nvm_alias test-edge-unreadable 2>/dev/null)"
|
||||||
|
EXIT_CODE=$?
|
||||||
|
[ "${EXIT_CODE}" = '0' ] || die "expected exit code 0 for unreadable alias file, got ${EXIT_CODE}"
|
||||||
|
[ -z "${OUTPUT}" ] || die "expected empty output for unreadable alias file, got >${OUTPUT}<"
|
||||||
|
|
||||||
|
STDERR="$(nvm_alias test-edge-unreadable 2>&1 >/dev/null)"
|
||||||
|
case "${STDERR}" in
|
||||||
|
*'not readable'*) ;;
|
||||||
|
*) die "expected a not-readable warning on stderr, got >${STDERR}<" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
cleanup
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
die () { echo "$@" ; exit 1; }
|
||||||
|
|
||||||
|
export NVM_DIR="$(cd ../../.. && pwd)"
|
||||||
|
|
||||||
|
: nvm.sh
|
||||||
|
\. "${NVM_DIR}/nvm.sh"
|
||||||
|
|
||||||
|
# Create an alias file with a very long line (version followed by a long comment)
|
||||||
|
LONG_COMMENT="$(printf '%0*d' 10000 0 | command tr '0' 'x')"
|
||||||
|
printf 'v22.1.0 #%s\n' "${LONG_COMMENT}" > ../../../alias/test-edge-long
|
||||||
|
ACTUAL="$(nvm_alias test-edge-long)"
|
||||||
|
EXPECTED='v22.1.0'
|
||||||
|
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}<, got >${ACTUAL}<"
|
||||||
|
|
||||||
|
rm -f ../../../alias/test-edge-long
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
die () { echo "$@" ; exit 1; }
|
||||||
|
|
||||||
|
export NVM_DIR="$(cd ../../.. && pwd)"
|
||||||
|
|
||||||
|
: nvm.sh
|
||||||
|
\. "${NVM_DIR}/nvm.sh"
|
||||||
|
|
||||||
|
# Create an alias file with trailing spaces and tabs
|
||||||
|
printf '22.1.0 \t \n' > ../../../alias/test-edge-trailing-ws
|
||||||
|
ACTUAL="$(nvm_alias test-edge-trailing-ws)"
|
||||||
|
EXPECTED='22.1.0'
|
||||||
|
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}<, got >${ACTUAL}<"
|
||||||
|
|
||||||
|
rm -f ../../../alias/test-edge-trailing-ws
|
||||||
+74
@@ -0,0 +1,74 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
die () { echo "$@" ; exit 1; }
|
||||||
|
|
||||||
|
export NVM_DIR="$(cd ../../.. && pwd)"
|
||||||
|
|
||||||
|
: nvm.sh
|
||||||
|
\. "${NVM_DIR}/nvm.sh"
|
||||||
|
|
||||||
|
# 1-hop self-reference: alias points to itself
|
||||||
|
echo 'self' > '../../../alias/self'
|
||||||
|
|
||||||
|
ACTUAL="$(nvm_resolve_alias self)"
|
||||||
|
EXPECTED='∞'
|
||||||
|
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}< for self-reference, got >${ACTUAL}<"
|
||||||
|
|
||||||
|
rm -f '../../../alias/self'
|
||||||
|
|
||||||
|
# Multi-hop loop: link1 -> link2 -> link3 -> link1
|
||||||
|
echo 'link2' > '../../../alias/link1'
|
||||||
|
echo 'link3' > '../../../alias/link2'
|
||||||
|
echo 'link1' > '../../../alias/link3'
|
||||||
|
|
||||||
|
ACTUAL="$(nvm_resolve_alias link1)"
|
||||||
|
EXPECTED='∞'
|
||||||
|
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}< for 3-hop cycle, got >${ACTUAL}<"
|
||||||
|
|
||||||
|
rm -f '../../../alias/link1' '../../../alias/link2' '../../../alias/link3'
|
||||||
|
|
||||||
|
# Cycle through an alias name containing a space
|
||||||
|
echo 'midway' > '../../../alias/foo bar'
|
||||||
|
echo 'foo bar' > '../../../alias/midway'
|
||||||
|
|
||||||
|
ACTUAL="$(nvm_resolve_alias 'foo bar')"
|
||||||
|
EXPECTED='∞'
|
||||||
|
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}< for space-name cycle, got >${ACTUAL}<"
|
||||||
|
|
||||||
|
rm -f '../../../alias/foo bar' '../../../alias/midway'
|
||||||
|
|
||||||
|
# Non-cycle through an alias name containing a space.
|
||||||
|
# Guards the newline-delimited SEEN_ALIASES storage: with space- or
|
||||||
|
# token-delimited storage, seen name 'foo bar' would falsely match 'bar'.
|
||||||
|
# Resolves: 'foo bar' -> 'midway' -> 'bar' -> 0.0.99
|
||||||
|
echo 'midway' > '../../../alias/foo bar'
|
||||||
|
echo 'bar' > '../../../alias/midway'
|
||||||
|
echo '0.0.99' > '../../../alias/bar'
|
||||||
|
|
||||||
|
ACTUAL="$(nvm_resolve_alias 'foo bar')"
|
||||||
|
EXPECTED='v0.0.99'
|
||||||
|
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}< for space-name chain, got >${ACTUAL}<"
|
||||||
|
|
||||||
|
rm -f '../../../alias/foo bar' '../../../alias/midway' '../../../alias/bar'
|
||||||
|
|
||||||
|
# Non-cycle through an alias name containing a regex metacharacter.
|
||||||
|
# Guards the literal `case` matching: the previous grep-based detection
|
||||||
|
# interpolated the resolved name into an anchored regex, so resolving 'axb'
|
||||||
|
# matched the seen name 'axb' against the pattern 'a.b' and falsely
|
||||||
|
# reported a cycle.
|
||||||
|
# Resolves: 'axb' -> 'a.b' -> 0.0.99
|
||||||
|
echo 'a.b' > '../../../alias/axb'
|
||||||
|
echo '0.0.99' > '../../../alias/a.b'
|
||||||
|
|
||||||
|
ACTUAL="$(nvm_resolve_alias axb)"
|
||||||
|
EXPECTED='v0.0.99'
|
||||||
|
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}< for metachar-name chain, got >${ACTUAL}<"
|
||||||
|
|
||||||
|
# ... while a genuine cycle through a metachar name is still detected
|
||||||
|
echo 'axb' > '../../../alias/a.b'
|
||||||
|
|
||||||
|
ACTUAL="$(nvm_resolve_alias axb)"
|
||||||
|
EXPECTED='∞'
|
||||||
|
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}< for metachar-name cycle, got >${ACTUAL}<"
|
||||||
|
|
||||||
|
rm -f '../../../alias/axb' '../../../alias/a.b'
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
die () { echo "$@" ; exit 1; }
|
||||||
|
|
||||||
|
export NVM_DIR="$(cd ../../.. && pwd)"
|
||||||
|
|
||||||
|
: nvm.sh
|
||||||
|
\. "${NVM_DIR}/nvm.sh"
|
||||||
|
|
||||||
|
# Create a 4-deep alias chain: hop1 -> hop2 -> hop3 -> hop4 -> 0.0.99
|
||||||
|
echo 'hop2' > ../../../alias/hop1
|
||||||
|
echo 'hop3' > ../../../alias/hop2
|
||||||
|
echo 'hop4' > ../../../alias/hop3
|
||||||
|
echo '0.0.99' > ../../../alias/hop4
|
||||||
|
|
||||||
|
ACTUAL="$(nvm_resolve_alias hop1)"
|
||||||
|
EXPECTED='v0.0.99'
|
||||||
|
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}< for 4-deep chain, got >${ACTUAL}<"
|
||||||
|
|
||||||
|
rm -f ../../../alias/hop1 ../../../alias/hop2 ../../../alias/hop3 ../../../alias/hop4
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
die () { echo "$@" ; exit 1; }
|
||||||
|
|
||||||
|
export NVM_DIR="$(cd ../../.. && pwd)"
|
||||||
|
|
||||||
|
: nvm.sh
|
||||||
|
\. "${NVM_DIR}/nvm.sh"
|
||||||
|
|
||||||
|
# Create an alias pointing to a version that does not exist as an alias
|
||||||
|
echo '99.99.99' > ../../../alias/test-edge-noexist
|
||||||
|
|
||||||
|
ACTUAL="$(nvm_resolve_alias test-edge-noexist)"
|
||||||
|
EXPECTED='v99.99.99'
|
||||||
|
EXIT_CODE="$(nvm_resolve_alias test-edge-noexist >/dev/null 2>&1; echo $?)"
|
||||||
|
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}<, got >${ACTUAL}<"
|
||||||
|
[ "${EXIT_CODE}" = '0' ] || die "expected exit code 0, got ${EXIT_CODE}"
|
||||||
|
|
||||||
|
rm -f ../../../alias/test-edge-noexist
|
||||||
@@ -17,3 +17,8 @@ rm -f "../../../alias/iojs"
|
|||||||
rm -f "../../../alias/default"
|
rm -f "../../../alias/default"
|
||||||
rm -f "../../../alias/test-blank-lines"
|
rm -f "../../../alias/test-blank-lines"
|
||||||
rm -f "../../../alias/test-multi-lines"
|
rm -f "../../../alias/test-multi-lines"
|
||||||
|
rm -f "../../../alias/test-edge-"* "../../../alias/test edge spaces"
|
||||||
|
rm -f "../../../alias/self" "../../../alias/link1" "../../../alias/link2" "../../../alias/link3"
|
||||||
|
rm -f "../../../alias/foo bar" "../../../alias/midway" "../../../alias/bar"
|
||||||
|
rm -f "../../../alias/hop1" "../../../alias/hop2" "../../../alias/hop3" "../../../alias/hop4"
|
||||||
|
rm -f "../../../alias/axb" "../../../alias/a.b"
|
||||||
|
|||||||
@@ -30,9 +30,10 @@ nvm_echo "$CAPTURED_STDERR" | nvm_grep -q "${EXPECTED_ERR}" \
|
|||||||
|
|
||||||
# --offline should not require curl or wget
|
# --offline should not require curl or wget
|
||||||
nvm_has() { return 1; }
|
nvm_has() { return 1; }
|
||||||
|
nvm_has_executable() { return 1; }
|
||||||
try_err nvm install --offline 999.999.999
|
try_err nvm install --offline 999.999.999
|
||||||
# Should fail with "not found" not "nvm needs curl or wget"
|
# Should fail with "not found" not "nvm needs curl or wget"
|
||||||
nvm_echo "$CAPTURED_STDERR" | nvm_grep -q "curl or wget" \
|
nvm_echo "$CAPTURED_STDERR" | nvm_grep -q "curl or wget" \
|
||||||
&& die "nvm install --offline should not require curl or wget"
|
&& die "nvm install --offline should not require curl or wget"
|
||||||
alias nvm_has='\nvm_has'
|
alias nvm_has='\nvm_has'
|
||||||
unset -f nvm_has
|
unset -f nvm_has nvm_has_executable
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
|
WORK="$PWD/nvm_curl_libz_support-work.$$"
|
||||||
|
TEST_BIN="$WORK/bin"
|
||||||
|
|
||||||
cleanup() {
|
cleanup() {
|
||||||
unset -f curl
|
rm -rf "$WORK"
|
||||||
|
export PATH="$OLDPATH"
|
||||||
}
|
}
|
||||||
|
|
||||||
die() { cleanup; echo "$@" ; exit 1; }
|
die() { cleanup; echo "$@" ; exit 1; }
|
||||||
@@ -9,32 +13,28 @@ die() { cleanup; echo "$@" ; exit 1; }
|
|||||||
: nvm.sh
|
: nvm.sh
|
||||||
\. ../../../nvm.sh
|
\. ../../../nvm.sh
|
||||||
|
|
||||||
curl() {
|
\. ../../common.sh
|
||||||
|
|
||||||
|
OLDPATH="$PATH"
|
||||||
|
|
||||||
|
make_fake_curl "$TEST_BIN"
|
||||||
|
|
||||||
|
export PATH="$TEST_BIN:$OLDPATH"
|
||||||
|
|
||||||
# curl with libz feature
|
# curl with libz feature
|
||||||
if [ $# -ne 1 ] || [ "$1" != "-V" ]; then
|
VERSION_MESSAGE="
|
||||||
die "This fake curl only takes one parameter -V"
|
|
||||||
fi
|
|
||||||
echo "
|
|
||||||
curl 7.47.0 (x86_64-pc-linux-gnu) libcurl/7.47.0 GnuTLS/3.4.10 zlib/1.2.8 libidn/1.32 librtmp/2.3
|
curl 7.47.0 (x86_64-pc-linux-gnu) libcurl/7.47.0 GnuTLS/3.4.10 zlib/1.2.8 libidn/1.32 librtmp/2.3
|
||||||
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp smb smbs smtp smtps telnet tftp
|
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp smb smbs smtp smtps telnet tftp
|
||||||
Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz TLS-SRP UnixSockets"
|
Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz TLS-SRP UnixSockets"
|
||||||
}
|
|
||||||
|
|
||||||
nvm_curl_libz_support || die "nvm_curl_libz_support should return 0"
|
nvm_curl_libz_support || die "nvm_curl_libz_support should return 0"
|
||||||
|
|
||||||
unset -f curl
|
|
||||||
|
|
||||||
curl() {
|
|
||||||
# curl without libz feature
|
# curl without libz feature
|
||||||
if [ "$#" -ne 1 ] || [ "$1" != "-V" ]; then
|
VERSION_MESSAGE="
|
||||||
die "This fake curl only takes one parameter -V"
|
|
||||||
fi
|
|
||||||
echo "
|
|
||||||
curl 7.47.0 (x86_64-pc-linux-gnu) libcurl/7.47.0 GnuTLS/3.4.10 zlib/1.2.8 libidn/1.32 librtmp/2.32
|
curl 7.47.0 (x86_64-pc-linux-gnu) libcurl/7.47.0 GnuTLS/3.4.10 zlib/1.2.8 libidn/1.32 librtmp/2.32
|
||||||
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp smb smbs smtp smtps telnet tftp
|
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp smb smbs smtp smtps telnet tftp
|
||||||
Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL TLS-SRP UnixSockets"
|
Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL TLS-SRP UnixSockets"
|
||||||
}
|
|
||||||
|
|
||||||
! nvm_curl_libz_support || die "nvm_curl_libz_support should return 1"
|
! nvm_curl_libz_support || die "nvm_curl_libz_support should return 1"
|
||||||
|
|
||||||
unset -f curl
|
cleanup
|
||||||
|
|||||||
@@ -1,18 +1,25 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
|
WORK="$PWD/nvm_curl_use_compression-work.$$"
|
||||||
|
TEST_BIN="$WORK/bin"
|
||||||
|
|
||||||
cleanup () {
|
cleanup () {
|
||||||
unset -f die
|
unset -f die
|
||||||
|
rm -rf "$WORK"
|
||||||
|
export PATH="$OLDPATH"
|
||||||
}
|
}
|
||||||
|
|
||||||
die () { echo -e "$@" ; cleanup ; exit 1; }
|
die () { echo -e "$@" ; cleanup ; exit 1; }
|
||||||
|
|
||||||
NVM_ENV=testing \. ../../../nvm.sh
|
NVM_ENV=testing \. ../../../nvm.sh
|
||||||
|
|
||||||
curl() {
|
\. ../../common.sh
|
||||||
if [ "$1" = "-V" ]; then
|
|
||||||
echo "${VERSION_MESSAGE}"
|
OLDPATH="$PATH"
|
||||||
fi
|
|
||||||
}
|
make_fake_curl "$TEST_BIN"
|
||||||
|
|
||||||
|
export PATH="$TEST_BIN:$OLDPATH"
|
||||||
|
|
||||||
CURL_VERSION_ON_ARCHLINUX_WITH_LIBZ="curl 7.54.0 (x86_64-pc-linux-gnu) libcurl/7.54.0 OpenSSL/1.1.0f zlib/1.2.11 libpsl/0.17.0 (+libicu/59.1) libssh2/1.8.0 nghttp2/1.22.0
|
CURL_VERSION_ON_ARCHLINUX_WITH_LIBZ="curl 7.54.0 (x86_64-pc-linux-gnu) libcurl/7.54.0 OpenSSL/1.1.0f zlib/1.2.11 libpsl/0.17.0 (+libicu/59.1) libssh2/1.8.0 nghttp2/1.22.0
|
||||||
Protocols: dict file ftp ftps gopher http https imap imaps pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp
|
Protocols: dict file ftp ftps gopher http https imap imaps pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp
|
||||||
|
|||||||
@@ -1,19 +1,25 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
|
WORK="$PWD/nvm_curl_version-work.$$"
|
||||||
|
TEST_BIN="$WORK/bin"
|
||||||
|
|
||||||
cleanup () {
|
cleanup () {
|
||||||
unset -f die
|
unset -f die cleanup assert_version_is
|
||||||
unset -f curl
|
rm -rf "$WORK"
|
||||||
|
export PATH="$OLDPATH"
|
||||||
}
|
}
|
||||||
|
|
||||||
die () { echo -e "$@" ; cleanup ; exit 1; }
|
die () { echo -e "$@" ; cleanup ; exit 1; }
|
||||||
|
|
||||||
NVM_ENV=testing \. ../../../nvm.sh
|
NVM_ENV=testing \. ../../../nvm.sh
|
||||||
|
|
||||||
curl() {
|
\. ../../common.sh
|
||||||
if [ "$1" = "-V" ]; then
|
|
||||||
echo "${VERSION_MESSAGE}"
|
OLDPATH="$PATH"
|
||||||
fi
|
|
||||||
}
|
make_fake_curl "$TEST_BIN"
|
||||||
|
|
||||||
|
export PATH="$TEST_BIN:$OLDPATH"
|
||||||
|
|
||||||
assert_version_is() {
|
assert_version_is() {
|
||||||
if [ "${1}" != "${2}" ]; then
|
if [ "${1}" != "${2}" ]; then
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
WORK="$PWD/shadowed-curl-work.$$"
|
||||||
|
TEST_BIN="$WORK/bin"
|
||||||
|
ARGV_LOG="$WORK/argv.log"
|
||||||
|
|
||||||
|
cleanup () {
|
||||||
|
unset -f die cleanup curl wget
|
||||||
|
rm -rf "$WORK"
|
||||||
|
export PATH="$OLDPATH"
|
||||||
|
}
|
||||||
|
|
||||||
|
die () { echo "$@" ; cleanup ; exit 1; }
|
||||||
|
|
||||||
|
NVM_ENV=testing \. ../../../nvm.sh
|
||||||
|
|
||||||
|
\. ../../common.sh
|
||||||
|
|
||||||
|
OLDPATH="$PATH"
|
||||||
|
|
||||||
|
# real-looking curl on PATH; calling the shadowing shell function below instead is a failure
|
||||||
|
make_fake_curl "$TEST_BIN" ': > "$ARGV_LOG"
|
||||||
|
for a in "$@"; do printf "%s\n" "$a" >> "$ARGV_LOG"; done'
|
||||||
|
|
||||||
|
VERSION_MESSAGE="curl 7.99.0 (fake)
|
||||||
|
Features: libz"
|
||||||
|
|
||||||
|
export ARGV_LOG
|
||||||
|
export PATH="$TEST_BIN:$OLDPATH"
|
||||||
|
|
||||||
|
# shadowing shell functions, like aliases baked into a user's shell, must be
|
||||||
|
# bypassed in favor of the executables on PATH (https://github.com/nvm-sh/nvm/issues/2923)
|
||||||
|
curl() {
|
||||||
|
echo 'curl 0.0.0-shadowed'
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
wget() {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
[ "$(nvm_curl_version)" = '7.99.0' ] || die "nvm_curl_version used the shadowing curl function; got $(nvm_curl_version)"
|
||||||
|
|
||||||
|
nvm_curl_libz_support || die 'nvm_curl_libz_support used the shadowing curl function'
|
||||||
|
|
||||||
|
nvm_download -s 'http://example.com/' -o /dev/null || die 'nvm_download used the shadowing curl function and failed'
|
||||||
|
grep -Fxq 'http://example.com/' "$ARGV_LOG" || die "nvm_download did not invoke the curl executable; got: $(cat "$ARGV_LOG")"
|
||||||
|
|
||||||
|
# when no curl executable exists, a shadowing curl shell function must not fool
|
||||||
|
# downloader selection: nvm_download must fall back to the wget executable
|
||||||
|
WGET_ONLY_BIN="$WORK/wget-only-bin"
|
||||||
|
mkdir -p "$WGET_ONLY_BIN"
|
||||||
|
{
|
||||||
|
echo '#!/bin/sh'
|
||||||
|
echo ': > "$ARGV_LOG"'
|
||||||
|
echo 'for a in "$@"; do printf "%s\n" "$a" >> "$ARGV_LOG"; done'
|
||||||
|
} > "$WGET_ONLY_BIN/wget"
|
||||||
|
chmod +x "$WGET_ONLY_BIN/wget"
|
||||||
|
|
||||||
|
(
|
||||||
|
PATH="$WGET_ONLY_BIN"
|
||||||
|
export PATH
|
||||||
|
nvm_download -s 'http://wget-fallback.example.com/' -o /dev/null
|
||||||
|
) || die 'nvm_download did not fall back to wget when curl is only a shell function'
|
||||||
|
grep -Fxq 'http://wget-fallback.example.com/' "$ARGV_LOG" || die "nvm_download did not invoke the wget executable; got: $(cat "$ARGV_LOG")"
|
||||||
|
|
||||||
|
cleanup
|
||||||
@@ -6,7 +6,7 @@ TEST_BIN="$WORK/bin"
|
|||||||
ARGV_LOG="$WORK/argv.log"
|
ARGV_LOG="$WORK/argv.log"
|
||||||
|
|
||||||
cleanup() {
|
cleanup() {
|
||||||
unset -f die cleanup nvm_has
|
unset -f die cleanup nvm_has_executable
|
||||||
rm -rf "$WORK"
|
rm -rf "$WORK"
|
||||||
export PATH="$OLDPATH"
|
export PATH="$OLDPATH"
|
||||||
}
|
}
|
||||||
@@ -30,7 +30,7 @@ chmod +x "$TEST_BIN/wget"
|
|||||||
export ARGV_LOG
|
export ARGV_LOG
|
||||||
export PATH="$TEST_BIN:$OLDPATH"
|
export PATH="$TEST_BIN:$OLDPATH"
|
||||||
# force the wget path while keeping system tools (sed) available for sanitization
|
# force the wget path while keeping system tools (sed) available for sanitization
|
||||||
nvm_has() { [ "$1" != curl ] && command -v "$1" >/dev/null 2>&1; }
|
nvm_has_executable() { [ "$1" != curl ] && command -v "$1" >/dev/null 2>&1; }
|
||||||
|
|
||||||
# given an Authorization credential in NVM_AUTH_HEADER
|
# given an Authorization credential in NVM_AUTH_HEADER
|
||||||
# when nvm_download uses the wget path
|
# when nvm_download uses the wget path
|
||||||
|
|||||||
@@ -93,4 +93,6 @@ run_test amd64 osx x64
|
|||||||
run_test arm64 smartos x64
|
run_test arm64 smartos x64
|
||||||
run_test armv8l smartos x64
|
run_test armv8l smartos x64
|
||||||
|
|
||||||
|
run_test loongarch64 linux loong64
|
||||||
|
|
||||||
cleanup
|
cleanup
|
||||||
|
|||||||
@@ -110,3 +110,26 @@ ACTUAL="$(nvm_get_download_slug iojs source 15.99.99)"
|
|||||||
EXPECTED="iojs-15.99.99"
|
EXPECTED="iojs-15.99.99"
|
||||||
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}<, got >${ACTUAL}<"
|
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}<, got >${ACTUAL}<"
|
||||||
|
|
||||||
|
|
||||||
|
REAL_OS="$(command uname -s 2>/dev/null || echo '')"
|
||||||
|
REAL_ARCH="$(command uname -m 2>/dev/null || echo '')"
|
||||||
|
if [ "${REAL_OS}" = "Darwin" ] && [ "${REAL_ARCH}" = "arm64" ]; then
|
||||||
|
# Node < 16 uses x64 on darwin-arm64
|
||||||
|
ACTUAL="$(nvm_get_download_slug node binary 14.21.3)"
|
||||||
|
EXPECTED='node-14.21.3-darwin-x64'
|
||||||
|
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}<, got >${ACTUAL}<"
|
||||||
|
ACTUAL="$(nvm_get_download_slug node binary 15.99.99)"
|
||||||
|
EXPECTED='node-15.99.99-darwin-x64'
|
||||||
|
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}<, got >${ACTUAL}<"
|
||||||
|
ACTUAL="$(nvm_get_download_slug iojs binary 15.99.99)"
|
||||||
|
EXPECTED='iojs-15.99.99-darwin-x64'
|
||||||
|
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}<, got >${ACTUAL}<"
|
||||||
|
|
||||||
|
# Test Node >= 16 uses arm64 on darwin-arm64
|
||||||
|
ACTUAL="$(nvm_get_download_slug node binary 16.0.0)"
|
||||||
|
EXPECTED='node-16.0.0-darwin-arm64'
|
||||||
|
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}<, got >${ACTUAL}<"
|
||||||
|
ACTUAL="$(nvm_get_download_slug node binary 18.0.0)"
|
||||||
|
EXPECTED='node-18.0.0-darwin-arm64'
|
||||||
|
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}<, got >${ACTUAL}<"
|
||||||
|
fi
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
die () { echo "$@" ; cleanup ; exit 1; }
|
die () { echo "$@" ; cleanup ; exit 1; }
|
||||||
|
|
||||||
cleanup() {
|
cleanup() {
|
||||||
unset -f nvm_has
|
unset -f nvm_has nvm_has_executable
|
||||||
}
|
}
|
||||||
|
|
||||||
: nvm.sh
|
: nvm.sh
|
||||||
@@ -12,6 +12,7 @@ cleanup() {
|
|||||||
\. ../../common.sh
|
\. ../../common.sh
|
||||||
|
|
||||||
nvm_has() { return 1 ; }
|
nvm_has() { return 1 ; }
|
||||||
|
nvm_has_executable() { return 1 ; }
|
||||||
|
|
||||||
try_err nvm_get_latest
|
try_err nvm_get_latest
|
||||||
[ "_$CAPTURED_STDERR" = "_nvm needs curl or wget to proceed." ] \
|
[ "_$CAPTURED_STDERR" = "_nvm needs curl or wget to proceed." ] \
|
||||||
|
|||||||
@@ -1,10 +1,24 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
die () { echo "$@" ; exit 1; }
|
die () { echo "$@" ; cleanup ; exit 1; }
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
rm -rf "${TEST_DIR-}"
|
||||||
|
unset NVMRC_CONTENT OUTPUT EXIT_CODE TEST_DIR NVM_DIR
|
||||||
|
}
|
||||||
|
|
||||||
: nvm.sh
|
: nvm.sh
|
||||||
\. ../../../nvm.sh
|
\. ../../../nvm.sh
|
||||||
|
|
||||||
|
\. ../../common.sh
|
||||||
|
|
||||||
|
# an isolated NVM_DIR with a single known version, so that ambient versions
|
||||||
|
# and aliases can not affect any assertions
|
||||||
|
TEST_DIR="${PWD}/nvm_ls_hash_pattern_tmp"
|
||||||
|
mkdir -p "${TEST_DIR}/versions/node/v24.13.0/bin" || die 'failed to create test version dir'
|
||||||
|
make_echo "${TEST_DIR}/versions/node/v24.13.0/bin/node" 'v24.13.0' || die 'failed to create test node binary'
|
||||||
|
NVM_DIR="${TEST_DIR}"
|
||||||
|
|
||||||
# Test: nvm_ls with pattern containing # should not cause sed error
|
# Test: nvm_ls with pattern containing # should not cause sed error
|
||||||
# This is a regression test for https://github.com/nvm-sh/nvm/issues/3761
|
# This is a regression test for https://github.com/nvm-sh/nvm/issues/3761
|
||||||
|
|
||||||
@@ -22,3 +36,33 @@ echo "$OUTPUT" | grep -q "invalid command code" && \
|
|||||||
# Should return N/A with exit code 3 (not found)
|
# Should return N/A with exit code 3 (not found)
|
||||||
[ "$EXIT_CODE" = "3" ] || die "nvm_ls 'foo#bar' should exit with code 3, got $EXIT_CODE"
|
[ "$EXIT_CODE" = "3" ] || die "nvm_ls 'foo#bar' should exit with code 3, got $EXIT_CODE"
|
||||||
echo "$OUTPUT" | grep -q "N/A" || die "nvm_ls 'foo#bar' should output N/A, got: $OUTPUT"
|
echo "$OUTPUT" | grep -q "N/A" || die "nvm_ls 'foo#bar' should output N/A, got: $OUTPUT"
|
||||||
|
|
||||||
|
NVMRC_CONTENT='v24.13.0
|
||||||
|
# krypton is the codename for Node.js v24.x'
|
||||||
|
|
||||||
|
OUTPUT="$(nvm_ls "${NVMRC_CONTENT}" 2>&1)"
|
||||||
|
EXIT_CODE=$?
|
||||||
|
|
||||||
|
[ "$EXIT_CODE" = "0" ] || die "nvm_ls with .nvmrc comments should exit with code 0, got $EXIT_CODE"
|
||||||
|
[ "$OUTPUT" = "v24.13.0" ] || die "nvm_ls with .nvmrc comments should output v24.13.0, got: $OUTPUT"
|
||||||
|
|
||||||
|
OUTPUT="$(nvm_version "${NVMRC_CONTENT}" 2>&1)"
|
||||||
|
[ "$OUTPUT" = "v24.13.0" ] || die "nvm_version with .nvmrc comments should output v24.13.0, got: $OUTPUT"
|
||||||
|
|
||||||
|
# a partial version reaches nvm_ls's find/sed pipeline, which is where multiline
|
||||||
|
# patterns used to break sed ("unterminated regular expression" on BSD sed,
|
||||||
|
# "unterminated address regex" on GNU sed); a full x.y.z version takes the
|
||||||
|
# explicit-version fast path and never reaches it
|
||||||
|
NVMRC_CONTENT='24
|
||||||
|
# krypton is the codename for Node.js v24.x'
|
||||||
|
|
||||||
|
OUTPUT="$(nvm_ls "${NVMRC_CONTENT}" 2>&1)"
|
||||||
|
EXIT_CODE=$?
|
||||||
|
|
||||||
|
echo "$OUTPUT" | grep -q "unterminated" && \
|
||||||
|
die "nvm_ls with partial version + comments caused a sed error: $OUTPUT"
|
||||||
|
|
||||||
|
[ "$EXIT_CODE" = "0" ] || die "nvm_ls with partial version + comments should exit with code 0, got $EXIT_CODE"
|
||||||
|
[ "$OUTPUT" = "v24.13.0" ] || die "nvm_ls with partial version + comments should output v24.13.0, got: $OUTPUT"
|
||||||
|
|
||||||
|
cleanup
|
||||||
|
|||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
die () { echo "$@" ; exit 1; }
|
||||||
|
|
||||||
|
\. ../../../nvm.sh
|
||||||
|
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
# Test 1: all standard base64 characters (RFC 4648) are preserved
|
||||||
|
STANDARD_B64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
|
||||||
|
RESULT=$(nvm_sanitize_auth_header "${STANDARD_B64}")
|
||||||
|
[ "${RESULT}" = "${STANDARD_B64}" ] || die "FAIL: standard base64 chars were stripped. Got: '${RESULT}'"
|
||||||
|
|
||||||
|
# Test 2: all base64url characters (RFC 4648 §5) are preserved
|
||||||
|
B64URL="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_="
|
||||||
|
RESULT=$(nvm_sanitize_auth_header "${B64URL}")
|
||||||
|
[ "${RESULT}" = "${B64URL}" ] || die "FAIL: base64url chars were stripped. Got: '${RESULT}'"
|
||||||
|
|
||||||
|
# Test 3: a real JWT Bearer token (base64url-encoded header.payload.signature) is preserved
|
||||||
|
JWT_TOKEN="Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
|
||||||
|
RESULT=$(nvm_sanitize_auth_header "${JWT_TOKEN}")
|
||||||
|
[ "${RESULT}" = "${JWT_TOKEN}" ] || die "FAIL: JWT Bearer token chars were stripped. Got: '${RESULT}'"
|
||||||
|
|
||||||
|
# Test 4: Basic auth (base64-encoded user:pass) is preserved
|
||||||
|
BASIC_TOKEN="Basic dXNlcm5hbWU6cGFzc3dvcmQ="
|
||||||
|
RESULT=$(nvm_sanitize_auth_header "${BASIC_TOKEN}")
|
||||||
|
[ "${RESULT}" = "${BASIC_TOKEN}" ] || die "FAIL: Basic auth base64 token chars were stripped. Got: '${RESULT}'"
|
||||||
|
|
||||||
|
# Test 5: dangerous shell metacharacters are removed
|
||||||
|
DANGEROUS="Bearer token;\`evil\`-cmd \$(inject)"
|
||||||
|
RESULT=$(nvm_sanitize_auth_header "${DANGEROUS}")
|
||||||
|
case "${RESULT}" in
|
||||||
|
*";"*|*"\`"*|*'$'*|*"("*|*")"*)
|
||||||
|
die "FAIL: dangerous shell metacharacters survived sanitization. Got: '${RESULT}'"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo "All nvm_sanitize_auth_header tests passed"
|
||||||
Regular → Executable
+2
-2
@@ -32,9 +32,9 @@ fi
|
|||||||
# Test 2: Verify that sanitized header still works for legitimate requests
|
# Test 2: Verify that sanitized header still works for legitimate requests
|
||||||
# The sanitized header should only contain safe characters
|
# The sanitized header should only contain safe characters
|
||||||
SANITIZED=$(nvm_sanitize_auth_header "${MALICIOUS_HEADER}")
|
SANITIZED=$(nvm_sanitize_auth_header "${MALICIOUS_HEADER}")
|
||||||
# Verify that dangerous characters were removed
|
# Verify that dangerous shell metacharacters were removed
|
||||||
case "${SANITIZED}" in
|
case "${SANITIZED}" in
|
||||||
*";"*|*"touch"*|*"/tmp"*)
|
*";"*|*'$'*|*"\`"*)
|
||||||
die "SECURITY FAILURE: Sanitization did not remove dangerous characters properly"
|
die "SECURITY FAILURE: Sanitization did not remove dangerous characters properly"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|||||||
Executable
+5
@@ -0,0 +1,5 @@
|
|||||||
|
if [ "_$1" = "_-m" ]; then
|
||||||
|
echo "loongarch64"
|
||||||
|
else
|
||||||
|
echo "Linux foo 6.12.54-16k #0 SMP PREEMPT_DYNAMIC Fri Dec 5 12:35:43 UTC loongarch64 GNU/Linux"
|
||||||
|
fi
|
||||||
@@ -2,37 +2,46 @@
|
|||||||
|
|
||||||
die () { echo "$@" ; cleanup ; exit 1; }
|
die () { echo "$@" ; cleanup ; exit 1; }
|
||||||
|
|
||||||
|
WORK="$PWD/nvm_get_latest-work.$$"
|
||||||
|
TEST_BIN="$WORK/bin"
|
||||||
|
|
||||||
cleanup() {
|
cleanup() {
|
||||||
unset -f curl wget nvm_has
|
unset -f curl wget
|
||||||
|
rm -rf "$WORK"
|
||||||
|
export PATH="$OLDPATH"
|
||||||
}
|
}
|
||||||
|
|
||||||
\. ../../../nvm.sh
|
\. ../../../nvm.sh
|
||||||
|
|
||||||
|
\. ../../common.sh
|
||||||
|
|
||||||
|
OLDPATH="$PATH"
|
||||||
|
|
||||||
EXPECTED_VERSION="v12.3.456"
|
EXPECTED_VERSION="v12.3.456"
|
||||||
URL="https://github.com/nvm-sh/nvm/releases/tag/$EXPECTED_VERSION"
|
URL="https://github.com/nvm-sh/nvm/releases/tag/$EXPECTED_VERSION"
|
||||||
EXPECTED_CURL_ARGS="--compressed -q -w %{url_effective}\n -L -s -S https://latest.nvm.sh -o /dev/null"
|
EXPECTED_CURL_ARGS="--compressed -q -w %{url_effective}\n -L -s -S https://latest.nvm.sh -o /dev/null"
|
||||||
EXPECTED_WGET_ARGS="-q https://latest.nvm.sh --server-response -O /dev/null"
|
EXPECTED_WGET_ARGS="-q https://latest.nvm.sh --server-response -O /dev/null"
|
||||||
|
export URL EXPECTED_CURL_ARGS EXPECTED_WGET_ARGS
|
||||||
|
|
||||||
curl() {
|
VERSION_MESSAGE="
|
||||||
if [ $# -eq 1 ] && [ "$1" = "-V" ]; then
|
|
||||||
echo "
|
|
||||||
curl 7.47.0 (x86_64-pc-linux-gnu) libcurl/7.47.0 GnuTLS/3.4.10 zlib/1.2.8 libidn/1.32 librtmp/2.3
|
curl 7.47.0 (x86_64-pc-linux-gnu) libcurl/7.47.0 GnuTLS/3.4.10 zlib/1.2.8 libidn/1.32 librtmp/2.3
|
||||||
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp smb smbs smtp smtps telnet tftp
|
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp smb smbs smtp smtps telnet tftp
|
||||||
Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz TLS-SRP UnixSockets"
|
Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz TLS-SRP UnixSockets"
|
||||||
elif [ "_$*" != "_$EXPECTED_CURL_ARGS" ]; then
|
|
||||||
|
# fake curl/wget: `command curl` bypasses shell functions, so the mocks must be executables on PATH
|
||||||
|
make_fake_curl "$TEST_BIN" 'if [ "_$*" != "_$EXPECTED_CURL_ARGS" ]; then
|
||||||
echo >&2 "expected args ($EXPECTED_CURL_ARGS), got ($*)"
|
echo >&2 "expected args ($EXPECTED_CURL_ARGS), got ($*)"
|
||||||
return 1
|
exit 1
|
||||||
else
|
|
||||||
echo $URL
|
|
||||||
fi
|
fi
|
||||||
}
|
echo "$URL"'
|
||||||
wget() {
|
|
||||||
|
cat > "$TEST_BIN/wget" <<'OUTER'
|
||||||
|
#!/bin/sh
|
||||||
if [ "_$*" != "_$EXPECTED_WGET_ARGS" ]; then
|
if [ "_$*" != "_$EXPECTED_WGET_ARGS" ]; then
|
||||||
echo >&2 "expected args ($EXPECTED_WGET_ARGS), got ($*)"
|
echo >&2 "expected args ($EXPECTED_WGET_ARGS), got ($*)"
|
||||||
return 1
|
exit 1
|
||||||
else
|
fi
|
||||||
local WGET_CONTENTS
|
cat >&2 <<CONTENTS
|
||||||
WGET_CONTENTS="
|
|
||||||
HTTP/1.1 301 Moved Permanently
|
HTTP/1.1 301 Moved Permanently
|
||||||
Location: https://github.com/nvm-sh/nvm/releases/latest
|
Location: https://github.com/nvm-sh/nvm/releases/latest
|
||||||
Content-Type: text/html; charset=utf-8
|
Content-Type: text/html; charset=utf-8
|
||||||
@@ -82,15 +91,22 @@ wget() {
|
|||||||
X-Content-Type-Options: nosniff
|
X-Content-Type-Options: nosniff
|
||||||
Vary: Accept-Encoding
|
Vary: Accept-Encoding
|
||||||
X-Served-By: 926b734ea1992f8ee1f88ab967a93dac
|
X-Served-By: 926b734ea1992f8ee1f88ab967a93dac
|
||||||
"
|
CONTENTS
|
||||||
"$WGET_CONTENTS" | while read line
|
OUTER
|
||||||
do
|
chmod +x "$TEST_BIN/wget"
|
||||||
>&2 echo "$line"
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
\. ../../common.sh
|
export PATH="$TEST_BIN:$OLDPATH"
|
||||||
|
|
||||||
|
# shadowing shell functions, like aliases baked into a user's shell, must be
|
||||||
|
# bypassed in favor of the executables on PATH (https://github.com/nvm-sh/nvm/issues/2923)
|
||||||
|
curl() {
|
||||||
|
echo >&2 'the shadowing curl function was called'
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
wget() {
|
||||||
|
echo >&2 'the shadowing wget function was called'
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
try nvm_get_latest
|
try nvm_get_latest
|
||||||
[ "_$CAPTURED_STDOUT" = "_$EXPECTED_VERSION" ] \
|
[ "_$CAPTURED_STDOUT" = "_$EXPECTED_VERSION" ] \
|
||||||
|
|||||||
@@ -2,20 +2,26 @@
|
|||||||
|
|
||||||
die () { echo "$@" ; cleanup ; exit 1; }
|
die () { echo "$@" ; cleanup ; exit 1; }
|
||||||
|
|
||||||
|
WORK="$PWD/nvm_get_latest_failed_redirect-work.$$"
|
||||||
|
TEST_BIN="$WORK/bin"
|
||||||
|
|
||||||
cleanup() {
|
cleanup() {
|
||||||
unset -f curl wget
|
rm -rf "$WORK"
|
||||||
|
export PATH="$OLDPATH"
|
||||||
}
|
}
|
||||||
|
|
||||||
\. ../../../nvm.sh
|
\. ../../../nvm.sh
|
||||||
|
|
||||||
\. ../../common.sh
|
\. ../../common.sh
|
||||||
|
|
||||||
curl() {
|
OLDPATH="$PATH"
|
||||||
return 1
|
|
||||||
}
|
# fake curl/wget: `command curl` bypasses shell functions, so the mocks must be executables on PATH
|
||||||
wget() {
|
make_fake_curl "$TEST_BIN" 'exit 1'
|
||||||
return 1
|
printf '#!/bin/sh\nexit 1\n' > "$TEST_BIN/wget"
|
||||||
}
|
chmod +x "$TEST_BIN/wget"
|
||||||
|
|
||||||
|
export PATH="$TEST_BIN:$OLDPATH"
|
||||||
|
|
||||||
try_err nvm_get_latest
|
try_err nvm_get_latest
|
||||||
[ "_$CAPTURED_STDERR" = "_https://latest.nvm.sh did not redirect to the latest release on GitHub" ] \
|
[ "_$CAPTURED_STDERR" = "_https://latest.nvm.sh did not redirect to the latest release on GitHub" ] \
|
||||||
|
|||||||
Reference in New Issue
Block a user