Compare commits

...

11 Commits

Author SHA1 Message Date
Jordan Harband 39d9a42c35
[Fix] `install.sh`: error out if the install instructions are not followed 2022-02-08 10:40:11 -08:00
Kai 2c0c34f10e
[Docs] HTTP => HTTPS 2022-01-16 14:25:11 +01:00
Jordan Harband c2f740ab38
[patch] HTTP -> HTTPS 2022-01-18 12:49:57 -08:00
Jordan Harband 6cfaede5a0
[Fix] `install`: better error message when xcode command line tools are needed
Fixes #2697. Fixes #2663.
2021-11-27 22:16:14 -08:00
Luke Arms 1875fe8b40
[Fix] avoid OpenBSD `nvm install` error when /sbin/init doesn't exist
`nvm install` fails with "Binary download failed, trying source" when
- running on Bash;
- errtrace (`set -E`) is enabled;
- an ERR trap uses `exit` to return a non-zero status; and
- /sbin/init doesn't exist.

Resolved by moving `ls -dl /sbin/init` to the following `if` statement.
In this context, returning non-zero isn't an error and the ERR trap
isn't executed.
2021-12-26 15:31:53 +11:00
Luke Arms 81f0f3ec19
[Fix] `set -E`: Add test for `node install` on Bash with an ERR trap and `set -E` 2021-12-27 16:02:25 +11:00
lsfxz fb4538b360
[Fix] add missing `local` (handle nonexisting /sbin/init a bit more cleanly) 2021-11-17 16:59:53 +01:00
Luke LaFountaine d004c6b064
[readme] clarify instructions for running Node on M1 Mac 2021-12-03 16:52:18 -05:00
Bob Bregant II 79ad72d116
[Fix] Update `nvm_extract_tarball` to support OpenBSD
Fixes #2660.
2021-12-19 02:58:18 +00:00
Bob Bregant II ccd442d833
[Refactor] add `nvm_extract_tarball` to consolidate extraction logic 2021-12-19 02:58:18 +00:00
Jordan Harband 9600617c52
v0.39.1 2021-12-17 14:55:52 -08:00
8 changed files with 212 additions and 95 deletions

121
README.md
View File

@ -1,4 +1,4 @@
# Node Version Manager [![Build Status](https://travis-ci.org/nvm-sh/nvm.svg?branch=master)][3] [![nvm version](https://img.shields.io/badge/version-v0.39.0-yellow.svg)][4] [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/684/badge)](https://bestpractices.coreinfrastructure.org/projects/684)
# Node Version Manager [![Build Status](https://travis-ci.org/nvm-sh/nvm.svg?branch=master)][3] [![nvm version](https://img.shields.io/badge/version-v0.39.1-yellow.svg)][4] [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/684/badge)](https://bestpractices.coreinfrastructure.org/projects/684)
<!-- To update this table of contents, ensure you have run `npm install` then `npm run doctoc` -->
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
@ -90,10 +90,10 @@ nvm is a version manager for [node.js](https://nodejs.org/en/), designed to be i
To **install** or **update** nvm, you should run the [install script][2]. To do that, you may either download and run the script manually, or use the following cURL or Wget command:
```sh
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
```
```sh
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
```
Running either of the above commands downloads a script and runs it. The script clones the nvm repository to `~/.nvm`, and attempts to add the source lines from the snippet below to the correct profile file (`~/.bash_profile`, `~/.zshrc`, `~/.profile`, or `~/.bashrc`).
@ -161,7 +161,7 @@ You can use a task:
```yaml
- name: nvm
shell: >
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
args:
creates: "{{ ansible_env.HOME }}/.nvm/nvm.sh"
```
@ -203,7 +203,7 @@ If you're running a system without prepackaged binary available, which means you
**Note:** On OS X, if you do not have Xcode installed and you do not wish to download the ~4.3GB file, you can install the `Command Line Tools`. You can check out this blog post on how to just that:
- [How to Install Command Line Tools in OS X Mavericks & Yosemite (Without Xcode)](http://osxdaily.com/2014/02/12/install-command-line-tools-mac-os-x/)
- [How to Install Command Line Tools in OS X Mavericks & Yosemite (Without Xcode)](https://osxdaily.com/2014/02/12/install-command-line-tools-mac-os-x/)
**Note:** On OS X, if you have/had a "system" node installed and want to install modules globally, keep in mind that:
@ -223,7 +223,7 @@ If you have `git` installed (requires git v1.7.10+):
1. clone this repo in the root of your user profile
- `cd ~/` from anywhere then `git clone https://github.com/nvm-sh/nvm.git .nvm`
1. `cd ~/.nvm` and check out the latest version with `git checkout v0.39.0`
1. `cd ~/.nvm` and check out the latest version with `git checkout v0.39.1`
1. activate `nvm` by sourcing it from your shell: `. ./nvm.sh`
Now add these lines to your `~/.bashrc`, `~/.profile`, or `~/.zshrc` file to have it automatically sourced upon login:
@ -789,7 +789,7 @@ If installing nvm on Alpine Linux *is* still what you want or need to do, you sh
```sh
apk add -U curl bash ca-certificates openssl ncurses coreutils python2 make gcc g++ libgcc linux-headers grep util-linux binutils findutils
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
```
The Node project has some desire but no concrete plans (due to the overheads of building, testing and support) to offer Alpine-compatible binaries.
@ -886,11 +886,11 @@ You have to make sure that the user directory name in `$HOME` and the user direc
To change the user directory and/or account name follow the instructions [here](https://support.apple.com/en-us/HT201548)
[1]: https://github.com/nvm-sh/nvm.git
[2]: https://github.com/nvm-sh/nvm/blob/v0.39.0/install.sh
[2]: https://github.com/nvm-sh/nvm/blob/v0.39.1/install.sh
[3]: https://travis-ci.org/nvm-sh/nvm
[4]: https://github.com/nvm-sh/nvm/releases/tag/v0.39.0
[4]: https://github.com/nvm-sh/nvm/releases/tag/v0.39.1
[Urchin]: https://github.com/scraperwiki/urchin
[Fish]: http://fishshell.com
[Fish]: https://fishshell.com
**Homebrew makes zsh directories unsecure**
@ -903,57 +903,70 @@ Homebrew causes insecure directories like `/usr/local/share/zsh/site-functions`
**Macs with M1 chip**
_January 2021:_ there are no pre-compiled NodeJS binaries for versions prior to 15.x for Apple's new M1 chip (arm64 architecture).
Experimental support for the M1 architecture was added in node.js v15.3 and full support was added in v16.0.
Because of this, if you try to install older versions of node as usual, you will probably experience either compilation errors when installing node or out-of-memory errors while running your code.
Some issues you may encounter:
So, if you want to run a version prior to v16.0 on an M1 Mac, it may be best to compile node targeting the x86_64 Intel architecture so that Rosetta 2 can translate the x86_64 processor instructions to ARM-based Apple Silicon instructions.
Here's what you will need to do:
- Install Rosetta, if you haven't already done so
- using `nvm` to install, say, `v14.15.4`:
- the C code compiles successfully
- but crashes with an out of memory error when used
- increasing the memory available to node still produces the out of memory errors:
```sh
$ NODE_OPTIONS="--max-old-space-size=4096" ./node_modules/.bin/your_node_package
$ softwareupdate --install-rosetta
```
- when using `nvm` to install some versions, the compilation fails
- after `nvm` successfully compiles some versions, `yarn` or `npm` may later fail to install packages with an `incorrect data check` error.
One solution to this issue is to change the architecture of your shell from arm64 to x86.
You might wonder, "how will my M1 Mac know to use Rosetta for a version of node compiled for an Intel chip?".
If an executable contains only Intel instructions, macOS will automatically use Rosetta to translate the instructions.
Let's assume that:
- you already have versions `12.20.1` and `14.15.4` installed using `nvm`
- the current version in use is `14.15.4`
- you are using the `zsh` shell
- you have Rosetta 2 installed (macOS prompts you to install Rosetta 2 the first time you open a Intel-only non-command-line application, or you may install Rosetta 2 from the command line with `softwareupdate --install-rosetta`)
- Open a shell that's running using Rosetta
```sh
# Check what version you're running:
$ node --version
v14.15.4
# Check architecture of the `node` binary:
$ node -p process.arch
arm64
# This confirms that the arch is for the M1 chip, which is causing the problems.
# So we need to uninstall it.
# We can't uninstall the version we are currently using, so switch to another version:
$ nvm install v12.20.1
# Now uninstall the version we want to replace:
$ nvm uninstall v14.15.4
# Launch a new zsh process under the 64-bit X86 architecture:
$ arch -x86_64 zsh
# Install node using nvm. This should download the precompiled x64 binary:
$ nvm install v14.15.4
# Now check that the architecture is correct:
$ node -p process.arch
x64
# It is now safe to return to the arm64 zsh process:
$ exit
# We're back to a native shell:
$ arch
arm64
# And the new version is now available to use:
$ nvm use v14.15.4
Now using node v14.15.4 (npm v6.14.10)
```
```sh
$ arch -x86_64 zsh
```
Note: This same thing can also be accomplished by finding the Terminal or iTerm App in Finder, right clicking, selecting "Get Info", and then checking the box labeled "Open using Rosetta".
Note: This terminal session is now running in `zsh`.
If `zsh` is not the shell you typically use, `nvm` may not be `source`'d automatically like it probably is for your usual shell through your dotfiles.
If that's the case, make sure to source `nvm`.
```sh
$ source "${NVM_DIR}/.nvm/nvm.sh"
```
- Install whatever older version of node you are interested in. Let's use 12.22.1 as an example.
This will fetch the node source code and compile it, which will take several minutes.
```sh
$ nvm install v12.22.1 --shared-zlib
```
Note: You're probably curious why `--shared-zlib` is included.
There's a bug in recent versions of Apple's system `clang` compiler.
If one of these broken versions is installed on your system, the above step will likely still succeed even if you didn't include the `--shared-zlib` flag.
However, later, when you attempt to `npm install` something using your old version of node.js, you will see `incorrect data check` errors.
If you want to avoid the possible hassle of dealing with this, include that flag.
For more details, see [this issue](https://github.com/nodejs/node/issues/39313) and [this comment](https://github.com/nodejs/node/issues/39313#issuecomment-902395576)
- Exit back to your native shell.
```sh
$ exit
$ arch
arm64
```
Note: If you selected the box labeled "Open using Rosetta" rather than running the CLI command in the second step, you will see `i386` here.
Unless you have another reason to have that box selected, you can deselect it now.
- Check to make sure the architecture is correct. `x64` is the abbreviation for x86_64, which is what you want to see.
```sh
$ node -p process.arch
x64
```
Now you should be able to use node as usual.
## Maintainers

View File

@ -10,6 +10,12 @@ nvm_echo() {
command printf %s\\n "$*" 2>/dev/null
}
if [ -z "${BASH_VERSION}" ] || [ -n "${ZSH_VERSION}" ]; then
# shellcheck disable=SC2016
nvm_echo >&2 'Error: the install instructions explicitly say to pipe the install script to `bash`; please follow them'
exit 1
fi
nvm_grep() {
GREP_OPTIONS='' command grep "$@"
}
@ -27,7 +33,7 @@ nvm_install_dir() {
}
nvm_latest_version() {
nvm_echo "v0.39.0"
nvm_echo "v0.39.1"
}
nvm_profile_is_bash_or_zsh() {
@ -356,6 +362,12 @@ nvm_do_install() {
exit 1
fi
fi
if nvm_has xcode-select && [ "$(xcode-select -p >/dev/null 2>/dev/null ; echo $?)" = '2' ] && [ "$(which git)" = '/usr/bin/git' ] && [ "$(which curl)" = '/usr/bin/curl' ]; then
nvm_echo >&2 'You may be on a Mac, and need to install the Xcode Command Line Developer Tools.'
# shellcheck disable=SC2016
nvm_echo >&2 'If so, run `xcode-select --install` and try again. If not, please report this!'
exit 1
fi
if [ -z "${METHOD}" ]; then
# Autodetect install method
if nvm_has git; then

98
nvm.sh
View File

@ -101,15 +101,15 @@ nvm_get_latest() {
if nvm_curl_use_compression; then
CURL_COMPRESSED_FLAG="--compressed"
fi
NVM_LATEST_URL="$(curl ${CURL_COMPRESSED_FLAG:-} -q -w "%{url_effective}\\n" -L -s -S http://latest.nvm.sh -o /dev/null)"
NVM_LATEST_URL="$(curl ${CURL_COMPRESSED_FLAG:-} -q -w "%{url_effective}\\n" -L -s -S https://latest.nvm.sh -o /dev/null)"
elif nvm_has "wget"; then
NVM_LATEST_URL="$(wget -q http://latest.nvm.sh --server-response -O /dev/null 2>&1 | command awk '/^ Location: /{DEST=$2} END{ print DEST }')"
NVM_LATEST_URL="$(wget -q https://latest.nvm.sh --server-response -O /dev/null 2>&1 | command awk '/^ Location: /{DEST=$2} END{ print DEST }')"
else
nvm_err 'nvm needs curl or wget to proceed.'
return 1
fi
if [ -z "${NVM_LATEST_URL}" ]; then
nvm_err "http://latest.nvm.sh did not redirect to the latest release on GitHub"
nvm_err "https://latest.nvm.sh did not redirect to the latest release on GitHub"
return 2
fi
nvm_echo "${NVM_LATEST_URL##*/}"
@ -1870,9 +1870,12 @@ nvm_get_arch() {
*) NVM_ARCH="${HOST_ARCH}" ;;
esac
# If running a 64bit ARM kernel but a 32bit ARM userland, change ARCH to 32bit ARM (armv7l)
L=$(ls -dl /sbin/init 2>/dev/null) # if /sbin/init is 32bit executable
if [ "$(uname)" = "Linux" ] && [ "${NVM_ARCH}" = arm64 ] && [ "$(od -An -t x1 -j 4 -N 1 "${L#*-> }")" = ' 01' ]; then
# If running a 64bit ARM kernel but a 32bit ARM userland,
# change ARCH to 32bit ARM (armv7l) if /sbin/init is 32bit executable
local L
if [ "$(uname)" = "Linux" ] && [ "${NVM_ARCH}" = arm64 ] &&
L="$(ls -dl /sbin/init 2>/dev/null)" &&
[ "$(od -An -t x1 -j 4 -N 1 "${L#*-> }")" = ' 01' ]; then
NVM_ARCH=armv7l
HOST_ARCH=armv7l
fi
@ -1971,19 +1974,7 @@ nvm_install_binary_extract() {
command unzip -q "${TARBALL}" -d "${TMPDIR}" || return 1
# For non Windows system (including WSL running on Windows)
else
local tar_compression_flag
tar_compression_flag='z'
if nvm_supports_xz "${VERSION}"; then
tar_compression_flag='J'
fi
local tar
if [ "${NVM_OS}" = 'aix' ]; then
tar='gtar'
else
tar='tar'
fi
command "${tar}" -x${tar_compression_flag}f "${TARBALL}" -C "${TMPDIR}" --strip-components 1 || return 1
nvm_extract_tarball "${NVM_OS}" "${VERSION}" "${TARBALL}" "${TMPDIR}"
fi
command mkdir -p "${VERSION_PATH}" || return 1
@ -2251,6 +2242,48 @@ nvm_download_artifact() {
nvm_echo "${TARBALL}"
}
# args: nvm_os, version, tarball, tmpdir
nvm_extract_tarball() {
if [ "$#" -ne 4 ]; then
nvm_err 'nvm_extract_tarball requires exactly 4 arguments'
return 5
fi
local NVM_OS
NVM_OS="${1-}"
local VERSION
VERSION="${2-}"
local TARBALL
TARBALL="${3-}"
local TMPDIR
TMPDIR="${4-}"
local tar_compression_flag
tar_compression_flag='z'
if nvm_supports_xz "${VERSION}"; then
tar_compression_flag='J'
fi
local tar
tar='tar'
if [ "${NVM_OS}" = 'aix' ]; then
tar='gtar'
fi
if [ "${NVM_OS}" = 'openbsd' ]; then
if [ "${tar_compression_flag}" = 'J' ]; then
command xzcat "${TARBALL}" | "${tar}" -xf - -C "${TMPDIR}" -s '/[^\/]*\///' || return 1
else
command "${tar}" -x${tar_compression_flag}f "${TARBALL}" -C "${TMPDIR}" -s '/[^\/]*\///' || return 1
fi
else
command "${tar}" -x${tar_compression_flag}f "${TARBALL}" -C "${TMPDIR}" --strip-components 1 || return 1
fi
}
nvm_get_make_jobs() {
if nvm_is_natural_num "${1-}"; then
NVM_MAKE_JOBS="$1"
@ -2362,18 +2395,6 @@ nvm_install_source() {
fi
fi
local tar_compression_flag
tar_compression_flag='z'
if nvm_supports_xz "${VERSION}"; then
tar_compression_flag='J'
fi
local tar
tar='tar'
if [ "${NVM_OS}" = 'aix' ]; then
tar='gtar'
fi
local TARBALL
local TMPDIR
local VERSION_PATH
@ -2393,7 +2414,7 @@ nvm_install_source() {
if ! (
# shellcheck disable=SC2086
command mkdir -p "${TMPDIR}" && \
command "${tar}" -x${tar_compression_flag}f "${TARBALL}" -C "${TMPDIR}" --strip-components 1 && \
nvm_extract_tarball "${NVM_OS}" "${VERSION}" "${TARBALL}" "${TMPDIR}" && \
VERSION_PATH="$(nvm_version_path "${PREFIXED_VERSION}")" && \
nvm_cd "${TMPDIR}" && \
nvm_echo '$>'./configure --prefix="${VERSION_PATH}" $ADDITIONAL_PARAMETERS'<' && \
@ -2723,6 +2744,15 @@ nvm() {
EXIT_CODE="$?"
set -a
return "$EXIT_CODE"
elif [ -n "${BASH-}" ] && [ "${-#*E}" != "$-" ]; then
# shellcheck disable=SC3041
set +E
local EXIT_CODE
IFS="${DEFAULT_IFS}" nvm "$@"
EXIT_CODE="$?"
# shellcheck disable=SC3041
set -E
return "$EXIT_CODE"
elif [ "${IFS}" != "${DEFAULT_IFS}" ]; then
IFS="${DEFAULT_IFS}" nvm "$@"
return "$?"
@ -4107,7 +4137,7 @@ nvm() {
NVM_VERSION_ONLY=true NVM_LTS="${NVM_LTS-}" nvm_remote_version "${PATTERN:-node}"
;;
"--version" | "-v")
nvm_echo '0.39.0'
nvm_echo '0.39.1'
;;
"unload")
nvm deactivate >/dev/null 2>&1
@ -4151,7 +4181,7 @@ nvm() {
nvm_npmrc_bad_news_bears \
nvm_get_colors nvm_set_colors nvm_print_color_code nvm_format_help_message_colors \
nvm_echo_with_colors nvm_err_with_colors \
nvm_get_artifact_compression nvm_install_binary_extract \
nvm_get_artifact_compression nvm_install_binary_extract nvm_extract_tarball \
>/dev/null 2>&1
unset NVM_RC_VERSION NVM_NODEJS_ORG_MIRROR NVM_IOJS_ORG_MIRROR NVM_DIR \
NVM_CD_FLAGS NVM_BIN NVM_INC NVM_MAKE_JOBS \

View File

@ -1,6 +1,6 @@
{
"name": "nvm",
"version": "0.39.0",
"version": "0.39.1",
"description": "Node Version Manager - Simple bash script to manage multiple active node.js versions",
"directories": {
"test": "test"

View File

@ -0,0 +1,12 @@
#!/bin/sh
die () { echo "$@" ; exit 1; }
\. ../../../nvm.sh
[ "$(nvm_extract_tarball 2>&1)" = "nvm_extract_tarball requires exactly 4 arguments" ] || die 'incorrect error message with no args'
[ "$(nvm_extract_tarball > /dev/null 2>&1 ; echo $?)" = "5" ] || die 'incorrect error code with no args'
[ "$(nvm_extract_tarball one two three 2>&1)" = "nvm_extract_tarball requires exactly 4 arguments" ] || die 'incorrect error message with three args'
[ "$(nvm_extract_tarball one two three > /dev/null 2>&1 ; echo $?)" = "5" ] || die 'incorrect error code with three args'
[ "$(nvm_extract_tarball one two three four five 2>&1)" = "nvm_extract_tarball requires exactly 4 arguments" ] || die 'incorrect error message with five args'
[ "$(nvm_extract_tarball one two three four five > /dev/null 2>&1 ; echo $?)" = "5" ] || die 'incorrect error code with five args'

View File

@ -0,0 +1,50 @@
#!/bin/sh
set -e
cleanup() {
nvm cache clear
nvm deactivate
rm -rf "${NVM_DIR}"/v*
nvm unalias default
}
die() {
echo "$@"
cleanup || true
exit 1
}
\. ../../nvm.sh
if [ -z "${BASH-}" ]; then
echo "This test only applies to Bash; skipping"
exit
fi
cleanup || true
trap 'echo "==> EXIT signal received (status: $?)"; cleanup' EXIT
# shellcheck disable=SC3047
trap 'echo "==> ERR signal received"; exit 1' ERR
# shellcheck disable=SC3041
set -E
# shellcheck disable=SC3045,SC3047
ERR_TRAP_EXPECTED="$(trap -p ERR)"
# Adding ` || die 'install failed'` implicitly disables error handling and
# prevents ERR trap execution, so for the purposes of this test, `nvm install`
# can't be part of another command or statement
nvm install node
case "$-" in
*E*)
# shellcheck disable=SC3045,SC3047
[ "$(trap -p ERR)" = "$ERR_TRAP_EXPECTED" ] ||
die "ERR trap not restored after \"nvm install $VERSION\""
;;
*)
die "errtrace not restored after \"nvm install $VERSION\""
;;
esac

View File

@ -10,8 +10,8 @@ cleanup() {
EXPECTED_VERSION="v12.3.456"
URL="https://github.com/nvm-sh/nvm/releases/tag/$EXPECTED_VERSION"
EXPECTED_CURL_ARGS="--compressed -q -w %{url_effective}\n -L -s -S http://latest.nvm.sh -o /dev/null"
EXPECTED_WGET_ARGS="-q http://latest.nvm.sh --server-response -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"
curl() {
if [ $# -eq 1 ] && [ "$1" = "-V" ]; then

View File

@ -17,7 +17,7 @@ wget() {
OUTPUT="$(nvm_get_latest 2>&1)"
EXIT_CODE="$(nvm_get_latest >/dev/null 2>&1 ; echo $?)"
[ "_$OUTPUT" = "_http://latest.nvm.sh did not redirect to the latest release on GitHub" ] \
[ "_$OUTPUT" = "_https://latest.nvm.sh did not redirect to the latest release on GitHub" ] \
|| die "failed redirect did not report correct error message, got '$OUTPUT'"
[ "_$EXIT_CODE" = "_2" ] \
|| die "failed redirect did not exit with code 2, got $EXIT_CODE"