Skip to content

Commit f258227

Browse files
nmarghettiljharb
authored andcommitted
[New] maybe support Windows with WSL, MSYS, Cygwin
1 parent d118be8 commit f258227

File tree

6 files changed

+186
-21
lines changed

6 files changed

+186
-21
lines changed

.github/workflows/windows-npm.yml

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
name: 'Tests on Windows: `nvm install`'
2+
3+
on: [pull_request, push]
4+
5+
env:
6+
NVM_INSTALL_GITHUB_REPO: ${{ github.repository }}
7+
NVM_INSTALL_VERSION: ${{ github.sha }}
8+
9+
jobs:
10+
node_fail_install:
11+
# Default installation does not work due to npm_config_prefix set to C:\npm\prefix
12+
name: 'MSYS fail prefix nvm install'
13+
runs-on: windows-latest
14+
steps:
15+
- name: Retrieve nvm
16+
shell: bash
17+
run: |
18+
curl -fsSLo- "https://raw.githubusercontent.com/${NVM_INSTALL_GITHUB_REPO}/${NVM_INSTALL_VERSION}/install.sh" | METHOD=script bash
19+
. "$HOME/.nvm/nvm.sh"
20+
! nvm install --lts
21+
nodes:
22+
name: 'MSYS nvm install'
23+
runs-on: windows-latest
24+
strategy:
25+
matrix:
26+
npm-node-version:
27+
- '--lts'
28+
- '--default 12'
29+
- '--no-progress 10'
30+
steps:
31+
- name: Retrieve nvm
32+
shell: bash
33+
run: |
34+
unset npm_config_prefix
35+
if [ "${{ matrix.npm-node-version }}" = "--lts" ]; then
36+
curl -fsSLo- "https://raw.githubusercontent.com/${NVM_INSTALL_GITHUB_REPO}/${NVM_INSTALL_VERSION}/install.sh" | bash
37+
else
38+
curl -fsSLo- "https://raw.githubusercontent.com/${NVM_INSTALL_GITHUB_REPO}/${NVM_INSTALL_VERSION}/install.sh" | METHOD=script bash
39+
fi
40+
. "$HOME/.nvm/nvm.sh"
41+
nvm install ${{ matrix.npm-node-version }}
42+
node_cygwin:
43+
name: 'Cygwin nvm install'
44+
runs-on: windows-latest
45+
steps:
46+
- name: Install Cygwin
47+
shell: bash
48+
run: |
49+
export SITE='https://mirror.clarkson.edu/cygwin/'
50+
export LOCALDIR="$(pwd)"
51+
export ROOTDIR="$USERPROFILE\\cygwin"
52+
export PACKAGES='bash,git,curl'
53+
54+
curl -fsSLo setup-x86_64.exe 'https://cygwin.com/setup-x86_64.exe'
55+
./setup-x86_64.exe --disable-buggy-antivirus -q -s "$SITE" -l "$LOCALDIR" -R "$ROOTDIR" -P "$PACKAGES"
56+
57+
cat >~/setup.sh <<EOM
58+
unset npm_config_prefix
59+
export NVM_INSTALL_GITHUB_REPO="$NVM_INSTALL_GITHUB_REPO"
60+
export NVM_INSTALL_VERSION="$NVM_INSTALL_VERSION"
61+
62+
curl -fsSLo- "https://raw.githubusercontent.com/${NVM_INSTALL_GITHUB_REPO}/${NVM_INSTALL_VERSION}/install.sh" | bash
63+
. "$HOME/.nvm/nvm.sh"
64+
nvm install --lts
65+
66+
nvm deactivate
67+
rm -rf "$HOME/.nvm/nvm.sh"
68+
69+
curl -fsSLo- "https://raw.githubusercontent.com/${NVM_INSTALL_GITHUB_REPO}/${NVM_INSTALL_VERSION}/install.sh" | METHOD=script bash
70+
. "$HOME/.nvm/nvm.sh"
71+
nvm install 9
72+
EOM
73+
- name: Retrieve nvm
74+
shell: cmd
75+
run: |
76+
cd %USERPROFILE%\cygwin\bin
77+
bash.exe "%USERPROFILE%\setup.sh"
78+
wsl_nodes:
79+
name: 'WSL nvm install'
80+
runs-on: windows-latest
81+
env:
82+
WSLENV: NVM_INSTALL_GITHUB_REPO:NVM_INSTALL_VERSION:/p
83+
strategy:
84+
matrix:
85+
wsl-distrib:
86+
- Debian
87+
- Alpine
88+
- Ubuntu-18.04
89+
npm-node-version:
90+
- '--lts'
91+
- '11'
92+
steps:
93+
- uses: Vampire/setup-wsl@v1
94+
with:
95+
distribution: ${{ matrix.wsl-distrib }}
96+
additional-packages: bash git curl ca-certificates
97+
- name: Retrieve nvm on WSL
98+
shell: wsl-bash {0}
99+
run: |
100+
if [ "${{ matrix.wsl-distrib }}" = "Ubuntu-18.04" ] && [ "${{ matrix.npm-node-version }}" = "--lts" ]; then
101+
curl -fsSLo- "https://raw.githubusercontent.com/${NVM_INSTALL_GITHUB_REPO}/${NVM_INSTALL_VERSION}/install.sh" | bash
102+
else
103+
curl -fsSLo- "https://raw.githubusercontent.com/${NVM_INSTALL_GITHUB_REPO}/${NVM_INSTALL_VERSION}/install.sh" | METHOD=script bash
104+
fi
105+
. "$HOME/.nvm/nvm.sh"
106+
nvm install ${{ matrix.npm-node-version }}

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ which should output `nvm` if the installation was successful. Please note that `
152152

153153
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.
154154

155-
**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:
155+
**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:
156156

157157
- [nvm-windows](https://github.com/coreybutler/nvm-windows)
158158
- [nodist](https://github.com/marcelklehr/nodist)

nvm.sh

+62-19
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,18 @@ nvm_has_system_iojs() {
146146
}
147147

148148
nvm_is_version_installed() {
149-
[ -n "${1-}" ] && [ -x "$(nvm_version_path "$1" 2>/dev/null)"/bin/node ]
149+
if [ -z "${1-}" ]; then
150+
return 1
151+
fi
152+
local NVM_NODE_BINARY
153+
NVM_NODE_BINARY='node'
154+
if [ "_$(nvm_get_os)" = '_win' ]; then
155+
NVM_NODE_BINARY='node.exe'
156+
fi
157+
if [ -x "$(nvm_version_path "$1" 2>/dev/null)/bin/${NVM_NODE_BINARY}" ]; then
158+
return 0
159+
fi
160+
return 1
150161
}
151162

152163
nvm_print_npm_version() {
@@ -326,10 +337,14 @@ nvm_tree_contains_path() {
326337
return 2
327338
fi
328339

340+
local previous_pathdir
341+
previous_pathdir="${node_path}"
329342
local pathdir
330-
pathdir=$(dirname "${node_path}")
331-
while [ "${pathdir}" != "" ] && [ "${pathdir}" != "." ] && [ "${pathdir}" != "/" ] && [ "${pathdir}" != "${tree}" ]; do
332-
pathdir=$(dirname "${pathdir}")
343+
pathdir=$(dirname "${previous_pathdir}")
344+
while [ "${pathdir}" != '' ] && [ "${pathdir}" != '.' ] && [ "${pathdir}" != '/' ] &&
345+
[ "${pathdir}" != "${tree}" ] && [ "${pathdir}" != "${previous_pathdir}" ]; do
346+
previous_pathdir="${pathdir}"
347+
pathdir=$(dirname "${previous_pathdir}")
333348
done
334349
[ "${pathdir}" = "${tree}" ]
335350
}
@@ -1763,6 +1778,7 @@ nvm_get_os() {
17631778
FreeBSD\ *) NVM_OS=freebsd ;;
17641779
OpenBSD\ *) NVM_OS=openbsd ;;
17651780
AIX\ *) NVM_OS=aix ;;
1781+
CYGWIN* | MSYS* | MINGW*) NVM_OS=win ;;
17661782
esac
17671783
nvm_echo "${NVM_OS-}"
17681784
}
@@ -1892,23 +1908,37 @@ nvm_install_binary_extract() {
18921908
command mkdir -p "${TMPDIR}" && \
18931909
VERSION_PATH="$(nvm_version_path "${PREFIXED_VERSION}")" || return 1
18941910

1895-
local tar_compression_flag
1896-
tar_compression_flag='z'
1897-
if nvm_supports_xz "${VERSION}"; then
1898-
tar_compression_flag='J'
1899-
fi
1900-
1901-
local tar
1902-
if [ "${NVM_OS}" = 'aix' ]; then
1903-
tar='gtar'
1911+
# For Windows system (GitBash with MSYS, Cygwin)
1912+
if [ "${NVM_OS}" = 'win' ]; then
1913+
VERSION_PATH="${VERSION_PATH}/bin"
1914+
command unzip -q "${TARBALL}" -d "${TMPDIR}" || return 1
1915+
# For non Windows system (including WSL running on Windows)
19041916
else
1905-
tar='tar'
1917+
local tar_compression_flag
1918+
tar_compression_flag='z'
1919+
if nvm_supports_xz "${VERSION}"; then
1920+
tar_compression_flag='J'
1921+
fi
1922+
1923+
local tar
1924+
if [ "${NVM_OS}" = 'aix' ]; then
1925+
tar='gtar'
1926+
else
1927+
tar='tar'
1928+
fi
1929+
command "${tar}" -x${tar_compression_flag}f "${TARBALL}" -C "${TMPDIR}" --strip-components 1 || return 1
19061930
fi
1907-
command "${tar}" -x${tar_compression_flag}f "${TARBALL}" -C "${TMPDIR}" --strip-components 1 || return 1
19081931

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

1911-
command mv "${TMPDIR}/"* "${VERSION_PATH}" || return 1
1934+
if [ "${NVM_OS}" = 'win' ]; then
1935+
command mv "${TMPDIR}/"*/* "${VERSION_PATH}" || return 1
1936+
command chmod +x "${VERSION_PATH}"/node.exe || return 1
1937+
command chmod +x "${VERSION_PATH}"/npm || return 1
1938+
command chmod +x "${VERSION_PATH}"/npx 2>/dev/null
1939+
else
1940+
command mv "${TMPDIR}/"* "${VERSION_PATH}" || return 1
1941+
fi
19121942

19131943
command rm -rf "${TMPDIR}"
19141944

@@ -2042,7 +2072,9 @@ nvm_get_artifact_compression() {
20422072

20432073
local COMPRESSION
20442074
COMPRESSION='tar.gz'
2045-
if nvm_supports_xz "${VERSION}"; then
2075+
if [ "_${NVM_OS}" = '_win' ]; then
2076+
COMPRESSION='zip'
2077+
elif nvm_supports_xz "${VERSION}"; then
20462078
COMPRESSION='tar.xz'
20472079
fi
20482080

@@ -2409,6 +2441,9 @@ nvm_die_on_prefix() {
24092441
return 3
24102442
fi
24112443

2444+
local NVM_OS
2445+
NVM_OS="$(nvm_get_os)"
2446+
24122447
# npm normalizes NPM_CONFIG_-prefixed env vars
24132448
# https://github.com/npm/npmconf/blob/22827e4038d6eebaafeb5c13ed2b92cf97b8fb82/npmconf.js#L331-L348
24142449
# https://github.com/npm/npm/blob/5e426a78ca02d0044f8dd26e0c5f881217081cbd/lib/config/core.js#L343-L359
@@ -2420,6 +2455,9 @@ nvm_die_on_prefix() {
24202455
if [ -n "${NVM_NPM_CONFIG_PREFIX_ENV-}" ]; then
24212456
local NVM_CONFIG_VALUE
24222457
eval "NVM_CONFIG_VALUE=\"\$${NVM_NPM_CONFIG_PREFIX_ENV}\""
2458+
if [ -n "${NVM_CONFIG_VALUE-}" ] && [ "_${NVM_OS}" = "_win" ]; then
2459+
NVM_CONFIG_VALUE="$(cd "$NVM_CONFIG_VALUE" 2>/dev/null && pwd)"
2460+
fi
24232461
if [ -n "${NVM_CONFIG_VALUE-}" ] && ! nvm_tree_contains_path "${NVM_DIR}" "${NVM_CONFIG_VALUE}"; then
24242462
nvm deactivate >/dev/null 2>&1
24252463
nvm_err "nvm is not compatible with the \"${NVM_NPM_CONFIG_PREFIX_ENV}\" environment variable: currently set to \"${NVM_CONFIG_VALUE}\""
@@ -3209,8 +3247,13 @@ nvm() {
32093247
nvm_get_make_jobs
32103248
fi
32113249

3212-
NVM_NO_PROGRESS="${NVM_NO_PROGRESS:-${noprogress}}" nvm_install_source "${FLAVOR}" std "${VERSION}" "${NVM_MAKE_JOBS}" "${ADDITIONAL_PARAMETERS}"
3213-
EXIT_CODE=$?
3250+
if [ "_${NVM_OS}" = "_win" ]; then
3251+
nvm_err 'Installing from source on non-WSL Windows is not supported'
3252+
EXIT_CODE=87
3253+
else
3254+
NVM_NO_PROGRESS="${NVM_NO_PROGRESS:-${noprogress}}" nvm_install_source "${FLAVOR}" std "${VERSION}" "${NVM_MAKE_JOBS}" "${ADDITIONAL_PARAMETERS}"
3255+
EXIT_CODE=$?
3256+
fi
32143257
fi
32153258

32163259
fi

test/fast/Unit tests/nvm_get_artifact_compression

+6
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,10 @@ die () { echo "$@" ; cleanup ; exit 1; }
1313
# nvm_get_artifact_compression with xz
1414
[ "$(nvm_get_artifact_compression "14.0.0")" = 'tar.xz' ] || die 'nvm_get_artifact_compression should return "tar.xz" for this version'
1515

16+
# nvm_get_artifact_compression with zip on Windows
17+
nvm_get_os() {
18+
nvm_echo 'win'
19+
}
20+
[ "$(nvm_get_artifact_compression)" = 'zip' ] || die 'nvm_get_artifact_compression should return "zip" for Windows'
21+
1622
cleanup

test/fast/Unit tests/nvm_install_binary_extract

+3
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ if [ -z "$NVM_DIR" ] || [ -z "$tmp_dir" ]; then
4343
die 'Unable to create temporary folder'
4444
fi
4545

46+
# Test windows zip
47+
test_archi 'win' 'v15.6.0' 'x64' 'node' 'zip' 'zip' '-qr'
48+
4649
# Test linux tar.xz
4750
test_archi 'linux' 'v14.15.4' 'x64' 'bin/node' 'tar.xz' 'tar' '-cJf'
4851

test/fast/Unit tests/nvm_is_version_installed

+8-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
cleanup () {
44
rm -rf "$NVM_DIR"
5-
unset -f die cleanup check_version
5+
unset -f die cleanup nvm_get_os check_version
66
unset NVM_DIR NODE_PATH
77
}
88
die () { echo "$@" ; cleanup ; exit 1; }
@@ -44,4 +44,11 @@ type nvm_is_version_installed > /dev/null 2>&1 || die 'nvm_is_version_installed
4444

4545
check_version '12.0.0' 'node'
4646

47+
# Checking for Windows
48+
nvm_get_os() {
49+
echo "win"
50+
}
51+
check_version '13.0.0' 'node.exe'
52+
53+
4754
cleanup

0 commit comments

Comments
 (0)