Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make it work on Windows with WSL, MSYS, Cygwin #2391

Merged
merged 2 commits into from
Apr 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 106 additions & 0 deletions .github/workflows/windows-npm.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
name: 'Tests on Windows: `nvm install`'

on: [pull_request, push]

env:
NVM_INSTALL_GITHUB_REPO: ${{ github.repository }}
NVM_INSTALL_VERSION: ${{ github.sha }}

jobs:
node_fail_install:
# Default installation does not work due to npm_config_prefix set to C:\npm\prefix
name: 'MSYS fail prefix nvm install'
runs-on: windows-latest
steps:
- name: Retrieve nvm
shell: bash
run: |
curl -fsSLo- "https://raw.githubusercontent.com/${NVM_INSTALL_GITHUB_REPO}/${NVM_INSTALL_VERSION}/install.sh" | METHOD=script bash
. "$HOME/.nvm/nvm.sh"
! nvm install --lts
ljharb marked this conversation as resolved.
Show resolved Hide resolved
nodes:
name: 'MSYS nvm install'
runs-on: windows-latest
strategy:
matrix:
npm-node-version:
- '--lts'
- '--default 12'
- '--no-progress 10'
steps:
- name: Retrieve nvm
shell: bash
run: |
unset npm_config_prefix
ljharb marked this conversation as resolved.
Show resolved Hide resolved
if [ "${{ matrix.npm-node-version }}" = "--lts" ]; then
curl -fsSLo- "https://raw.githubusercontent.com/${NVM_INSTALL_GITHUB_REPO}/${NVM_INSTALL_VERSION}/install.sh" | bash
else
curl -fsSLo- "https://raw.githubusercontent.com/${NVM_INSTALL_GITHUB_REPO}/${NVM_INSTALL_VERSION}/install.sh" | METHOD=script bash
fi
. "$HOME/.nvm/nvm.sh"
nvm install ${{ matrix.npm-node-version }}
node_cygwin:
name: 'Cygwin nvm install'
runs-on: windows-latest
steps:
- name: Install Cygwin
shell: bash
run: |
export SITE='https://mirror.clarkson.edu/cygwin/'
export LOCALDIR="$(pwd)"
export ROOTDIR="$USERPROFILE\\cygwin"
export PACKAGES='bash,git,curl'

curl -fsSLo setup-x86_64.exe 'https://cygwin.com/setup-x86_64.exe'
./setup-x86_64.exe --disable-buggy-antivirus -q -s "$SITE" -l "$LOCALDIR" -R "$ROOTDIR" -P "$PACKAGES"

cat >~/setup.sh <<EOM
unset npm_config_prefix
export NVM_INSTALL_GITHUB_REPO="$NVM_INSTALL_GITHUB_REPO"
export NVM_INSTALL_VERSION="$NVM_INSTALL_VERSION"

curl -fsSLo- "https://raw.githubusercontent.com/${NVM_INSTALL_GITHUB_REPO}/${NVM_INSTALL_VERSION}/install.sh" | bash
. "$HOME/.nvm/nvm.sh"
nvm install --lts

nvm deactivate
rm -rf "$HOME/.nvm/nvm.sh"

curl -fsSLo- "https://raw.githubusercontent.com/${NVM_INSTALL_GITHUB_REPO}/${NVM_INSTALL_VERSION}/install.sh" | METHOD=script bash
. "$HOME/.nvm/nvm.sh"
nvm install 9
EOM
- name: Retrieve nvm
shell: cmd
run: |
cd %USERPROFILE%\cygwin\bin
bash.exe "%USERPROFILE%\setup.sh"
wsl_nodes:
name: 'WSL nvm install'
runs-on: windows-latest
env:
WSLENV: NVM_INSTALL_GITHUB_REPO:NVM_INSTALL_VERSION:/p
strategy:
matrix:
wsl-distrib:
- Debian
- Alpine
- Ubuntu-18.04
npm-node-version:
- '--lts'
- '11'
steps:
- uses: Vampire/setup-wsl@v1
with:
distribution: ${{ matrix.wsl-distrib }}
additional-packages: bash git curl ca-certificates
- name: Retrieve nvm on WSL
shell: wsl-bash {0}
run: |
if [ "${{ matrix.wsl-distrib }}" = "Ubuntu-18.04" ] && [ "${{ matrix.npm-node-version }}" = "--lts" ]; then
curl -fsSLo- "https://raw.githubusercontent.com/${NVM_INSTALL_GITHUB_REPO}/${NVM_INSTALL_VERSION}/install.sh" | bash
else
curl -fsSLo- "https://raw.githubusercontent.com/${NVM_INSTALL_GITHUB_REPO}/${NVM_INSTALL_VERSION}/install.sh" | METHOD=script bash
fi
. "$HOME/.nvm/nvm.sh"
nvm install ${{ matrix.npm-node-version }}
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ which should output `nvm` if the installation was successful. Please note that `

If you're running a system without prepackaged binary available, which means you're going to install nodejs or io.js from its source code, you need to make sure your system has a C++ compiler. For OS X, Xcode will work, for Debian/Ubuntu based GNU/Linux, the `build-essential` and `libssl-dev` packages work.

**Note:** `nvm` does not support Windows (see [#284](https://github.com/nvm-sh/nvm/issues/284)), but may work in WSL (Windows Subsystem for Linux) depending on the version of WSL. For Windows, a few alternatives exist, which are neither supported nor developed by us:
**Note:** `nvm` also support Windows in some cases. It should work through WSL (Windows Subsystem for Linux) depending on the version of WSL. It should also work with [GitBash](https://gitforwindows.org/) (MSYS) or [Cygwin](https://cygwin.com). Otherwise, for Windows, afew alternatives exist, which are neither supported nor developed by us:

- [nvm-windows](https://github.com/coreybutler/nvm-windows)
- [nodist](https://github.com/marcelklehr/nodist)
Expand Down
81 changes: 62 additions & 19 deletions nvm.sh
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,18 @@ nvm_has_system_iojs() {
}

nvm_is_version_installed() {
[ -n "${1-}" ] && [ -x "$(nvm_version_path "$1" 2>/dev/null)"/bin/node ]
if [ -z "${1-}" ]; then
return 1
fi
local NVM_NODE_BINARY
NVM_NODE_BINARY='node'
if [ "_$(nvm_get_os)" = '_win' ]; then
NVM_NODE_BINARY='node.exe'
fi
if [ -x "$(nvm_version_path "$1" 2>/dev/null)/bin/${NVM_NODE_BINARY}" ]; then
return 0
fi
return 1
}
nmarghetti marked this conversation as resolved.
Show resolved Hide resolved

nvm_print_npm_version() {
Expand Down Expand Up @@ -326,10 +337,14 @@ nvm_tree_contains_path() {
return 2
fi

local previous_pathdir
previous_pathdir="${node_path}"
local pathdir
pathdir=$(dirname "${node_path}")
while [ "${pathdir}" != "" ] && [ "${pathdir}" != "." ] && [ "${pathdir}" != "/" ] && [ "${pathdir}" != "${tree}" ]; do
pathdir=$(dirname "${pathdir}")
pathdir=$(dirname "${previous_pathdir}")
while [ "${pathdir}" != '' ] && [ "${pathdir}" != '.' ] && [ "${pathdir}" != '/' ] &&
[ "${pathdir}" != "${tree}" ] && [ "${pathdir}" != "${previous_pathdir}" ]; do
nmarghetti marked this conversation as resolved.
Show resolved Hide resolved
previous_pathdir="${pathdir}"
pathdir=$(dirname "${previous_pathdir}")
done
[ "${pathdir}" = "${tree}" ]
}
Expand Down Expand Up @@ -1763,6 +1778,7 @@ nvm_get_os() {
FreeBSD\ *) NVM_OS=freebsd ;;
OpenBSD\ *) NVM_OS=openbsd ;;
AIX\ *) NVM_OS=aix ;;
CYGWIN* | MSYS* | MINGW*) NVM_OS=win ;;
esac
nvm_echo "${NVM_OS-}"
}
Expand Down Expand Up @@ -1892,23 +1908,37 @@ nvm_install_binary_extract() {
command mkdir -p "${TMPDIR}" && \
VERSION_PATH="$(nvm_version_path "${PREFIXED_VERSION}")" || return 1

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'
# For Windows system (GitBash with MSYS, Cygwin)
if [ "${NVM_OS}" = 'win' ]; then
VERSION_PATH="${VERSION_PATH}/bin"
command unzip -q "${TARBALL}" -d "${TMPDIR}" || return 1
ljharb marked this conversation as resolved.
Show resolved Hide resolved
# For non Windows system (including WSL running on Windows)
else
tar='tar'
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
fi
command "${tar}" -x${tar_compression_flag}f "${TARBALL}" -C "${TMPDIR}" --strip-components 1 || return 1

command mkdir -p "${VERSION_PATH}" || return 1

command mv "${TMPDIR}/"* "${VERSION_PATH}" || return 1
if [ "${NVM_OS}" = 'win' ]; then
command mv "${TMPDIR}/"*/* "${VERSION_PATH}" || return 1
command chmod +x "${VERSION_PATH}"/node.exe || return 1
command chmod +x "${VERSION_PATH}"/npm || return 1
command chmod +x "${VERSION_PATH}"/npx 2>/dev/null
else
command mv "${TMPDIR}/"* "${VERSION_PATH}" || return 1
fi

command rm -rf "${TMPDIR}"

Expand Down Expand Up @@ -2042,7 +2072,9 @@ nvm_get_artifact_compression() {

local COMPRESSION
COMPRESSION='tar.gz'
if nvm_supports_xz "${VERSION}"; then
if [ "_${NVM_OS}" = '_win' ]; then
COMPRESSION='zip'
elif nvm_supports_xz "${VERSION}"; then
COMPRESSION='tar.xz'
fi

Expand Down Expand Up @@ -2409,6 +2441,9 @@ nvm_die_on_prefix() {
return 3
fi

local NVM_OS
NVM_OS="$(nvm_get_os)"

# npm normalizes NPM_CONFIG_-prefixed env vars
# https://github.com/npm/npmconf/blob/22827e4038d6eebaafeb5c13ed2b92cf97b8fb82/npmconf.js#L331-L348
# https://github.com/npm/npm/blob/5e426a78ca02d0044f8dd26e0c5f881217081cbd/lib/config/core.js#L343-L359
Expand All @@ -2420,6 +2455,9 @@ nvm_die_on_prefix() {
if [ -n "${NVM_NPM_CONFIG_PREFIX_ENV-}" ]; then
local NVM_CONFIG_VALUE
eval "NVM_CONFIG_VALUE=\"\$${NVM_NPM_CONFIG_PREFIX_ENV}\""
if [ -n "${NVM_CONFIG_VALUE-}" ] && [ "_${NVM_OS}" = "_win" ]; then
NVM_CONFIG_VALUE="$(cd "$NVM_CONFIG_VALUE" 2>/dev/null && pwd)"
fi
if [ -n "${NVM_CONFIG_VALUE-}" ] && ! nvm_tree_contains_path "${NVM_DIR}" "${NVM_CONFIG_VALUE}"; then
nvm deactivate >/dev/null 2>&1
nvm_err "nvm is not compatible with the \"${NVM_NPM_CONFIG_PREFIX_ENV}\" environment variable: currently set to \"${NVM_CONFIG_VALUE}\""
Expand Down Expand Up @@ -3209,8 +3247,13 @@ nvm() {
nvm_get_make_jobs
fi

NVM_NO_PROGRESS="${NVM_NO_PROGRESS:-${noprogress}}" nvm_install_source "${FLAVOR}" std "${VERSION}" "${NVM_MAKE_JOBS}" "${ADDITIONAL_PARAMETERS}"
EXIT_CODE=$?
if [ "_${NVM_OS}" = "_win" ]; then
nvm_err 'Installing from source on non-WSL Windows is not supported'
EXIT_CODE=87
else
NVM_NO_PROGRESS="${NVM_NO_PROGRESS:-${noprogress}}" nvm_install_source "${FLAVOR}" std "${VERSION}" "${NVM_MAKE_JOBS}" "${ADDITIONAL_PARAMETERS}"
EXIT_CODE=$?
fi
fi

fi
Expand Down
6 changes: 6 additions & 0 deletions test/fast/Unit tests/nvm_get_artifact_compression
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,10 @@ die () { echo "$@" ; cleanup ; exit 1; }
# nvm_get_artifact_compression with xz
[ "$(nvm_get_artifact_compression "14.0.0")" = 'tar.xz' ] || die 'nvm_get_artifact_compression should return "tar.xz" for this version'

# nvm_get_artifact_compression with zip on Windows
nvm_get_os() {
nvm_echo 'win'
}
[ "$(nvm_get_artifact_compression)" = 'zip' ] || die 'nvm_get_artifact_compression should return "zip" for Windows'

cleanup
3 changes: 3 additions & 0 deletions test/fast/Unit tests/nvm_install_binary_extract
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ if [ -z "$NVM_DIR" ] || [ -z "$tmp_dir" ]; then
die 'Unable to create temporary folder'
fi

# Test windows zip
test_archi 'win' 'v15.6.0' 'x64' 'node' 'zip' 'zip' '-qr'

# Test linux tar.xz
test_archi 'linux' 'v14.15.4' 'x64' 'bin/node' 'tar.xz' 'tar' '-cJf'

Expand Down
54 changes: 54 additions & 0 deletions test/fast/Unit tests/nvm_is_version_installed
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/bin/sh

cleanup () {
rm -rf "$NVM_DIR"
unset -f die cleanup nvm_get_os check_version
unset NVM_DIR NODE_PATH
}
die () { echo "$@" ; cleanup ; exit 1; }

\. ../../../nvm.sh

set -ex

NVM_DIR=$(mktemp -d)
NODE_PATH="$NVM_DIR/versions/node"
mkdir -p "$NODE_PATH"
if [ -z "$NODE_PATH" ]; then
die 'Unable to create temporary folder'
fi

check_version() {
local VERSION
local BINARY
VERSION=$1
BINARY=$2

# nvm_is_version_installed fails with non existing version
! nvm_is_version_installed "$VERSION" || die "nvm_is_version_installed $VERSION should fail with non existing version"

# nvm_is_version_installed fails with non executable existing version
mkdir -p "$NODE_PATH/$VERSION/bin" && cd "$NODE_PATH/$VERSION/bin" && touch "$NODE_PATH/$VERSION/bin/$BINARY"
! nvm_is_version_installed "$VERSION" || die "nvm_is_version_installed $VERSION should fail with non executable existing version"

# nvm_is_version_installed whould work
chmod +x "$NODE_PATH/$VERSION/bin/$BINARY"
nvm_is_version_installed "$VERSION" || die "nvm_is_version_installed $VERSION should work"
}

# nvm_is_version_installed is available
type nvm_is_version_installed > /dev/null 2>&1 || die 'nvm_is_version_installed is not available'

# nvm_is_version_installed with no parameter fails
! nvm_is_version_installed || die 'nvm_is_version_installed without parameter should fail'

check_version '12.0.0' 'node'

# Checking for Windows
nvm_get_os() {
echo "win"
}
check_version '13.0.0' 'node.exe'


cleanup