diff --git a/.github/workflows/windows-npm.yml b/.github/workflows/windows-npm.yml new file mode 100755 index 00000000000..9640a4594f0 --- /dev/null +++ b/.github/workflows/windows-npm.yml @@ -0,0 +1,64 @@ +name: 'Tests on Windows: `nvm install`' + +on: [pull_request, push] + +jobs: + node: + name: 'MSYS fail prefix nvm install' + runs-on: windows-latest + steps: + - name: Retrieve nvm + shell: bash + run: | + mkdir vp "$HOME/.nvm" + curl -sSLo "$HOME/.nvm/nvm.sh" "https://raw.githubusercontent.com/${GITHUB_REPOSITORY}/${GITHUB_SHA}/nvm.sh" + source "$HOME/.nvm/nvm.sh" + ! nvm install --lts + + 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: | + mkdir vp "$HOME/.nvm" + curl -sSLo "$HOME/.nvm/nvm.sh" "https://raw.githubusercontent.com/${GITHUB_REPOSITORY}/${GITHUB_SHA}/nvm.sh" + source "$HOME/.nvm/nvm.sh" + unset npm_config_prefix + nvm install ${{ matrix.npm-node-version }} + + wsl_nodes: + name: 'WSL nvm install' + runs-on: windows-latest + 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 curl ca-certificates + - name: Retrieve nvm on WSL + shell: wsl-bash {0} + env: + GITHUB_REPOSITORY: ${{ github.repository }} + GITHUB_SHA: github.sha + run: | + mkdir -p "$HOME/.nvm" + curl -sSLo "$HOME/.nvm/nvm.sh" "https://raw.githubusercontent.com/${{ github.repository }}/${{ github.sha }}/nvm.sh" + source "$HOME/.nvm/nvm.sh" + nvm install ${{ matrix.npm-node-version }} diff --git a/README.md b/README.md index c05612a6dc6..08be06f2028 100644 --- a/README.md +++ b/README.md @@ -136,11 +136,17 @@ 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, two alternatives exist, which are neither supported nor developed by us: +**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. It may work also with GitBash or Cygwin. For Windows, two alternatives exist, which are neither supported nor developed by us: - [nvm-windows](https://github.com/coreybutler/nvm-windows) - [nodist](https://github.com/marcelklehr/nodist) +**Note:** `nvm` may work with [GitBash](https://gitforwindows.org/) if installed with script method (the git repository contains filenames with characters not supported on Windows): + +```sh +curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh | METHOD=script bash +``` + **Note:** `nvm` does not support [Fish] either (see [#303](https://github.com/nvm-sh/nvm/issues/303)). Alternatives exist, which are neither supported nor developed by us: - [bass](https://github.com/edc/bass) allows you to use utilities written for Bash in fish shell diff --git a/nvm.sh b/nvm.sh index 2f59708464a..c7655f2d901 100644 --- a/nvm.sh +++ b/nvm.sh @@ -146,7 +146,12 @@ nvm_has_system_iojs() { } nvm_is_version_installed() { - [ -n "${1-}" ] && [ -x "$(nvm_version_path "$1" 2>/dev/null)"/bin/node ] + local NVM_OS + NVM_OS="$(nvm_get_os)" + local NODE + NODE='node' + [ "_${NVM_OS}" = "_win" ] && NODE='node.exe' + [ -n "${1-}" ] && [ -x "$(nvm_version_path "$1" 2>/dev/null)"/bin/"${NODE}" ] } nvm_print_npm_version() { @@ -326,10 +331,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 + previous_pathdir="${pathdir}" + pathdir=$(dirname "${previous_pathdir}") done [ "${pathdir}" = "${tree}" ] } @@ -1559,7 +1568,7 @@ nvm_get_checksum() { SHASUMS_URL="${MIRROR}/${3}/SHASUMS.txt" fi - nvm_download -L -s "${SHASUMS_URL}" -o - | command awk "{ if (\"${4}.tar.${5}\" == \$2) print \$1}" + nvm_download -L -s "${SHASUMS_URL}" -o - | command awk "{ if (\"${4}.${5}\" == \$2) print \$1}" } nvm_print_versions() { @@ -1761,6 +1770,7 @@ nvm_get_os() { SunOS\ *) NVM_OS=sunos ;; FreeBSD\ *) NVM_OS=freebsd ;; AIX\ *) NVM_OS=aix ;; + CYGWIN* | MSYS* | MINGW*) NVM_OS=win ;; esac nvm_echo "${NVM_OS-}" } @@ -1882,14 +1892,11 @@ nvm_install_binary() { local VERSION VERSION="$(nvm_strip_iojs_prefix "${PREFIXED_VERSION}")" - if [ -z "$(nvm_get_os)" ]; then - return 2 - fi + local NVM_OS + NVM_OS="$(nvm_get_os)" - local tar_compression_flag - tar_compression_flag='z' - if nvm_supports_xz "${VERSION}"; then - tar_compression_flag='J' + if [ -z "${NVM_OS}" ]; then + return 2 fi local TARBALL @@ -1914,21 +1921,52 @@ nvm_install_binary() { if [ -f "${TARBALL}" ]; then TMPDIR="$(dirname "${TARBALL}")/files" fi - local tar - tar='tar' - if [ "${NVM_OS}" = 'aix' ]; then - tar='gtar' + + local EXTRACT_SUCCESS + EXTRACT_SUCCESS=0 + + # For Windows system (GitBash with MSYS, Cygwin) + if [ "${NVM_OS}" = 'win' ]; then + if ( + [ -n "${TMPDIR-}" ] && \ + command mkdir -p "${TMPDIR}" && \ + command unzip -q "${TARBALL}" -d "${TMPDIR}" && \ + VERSION_PATH="$(nvm_version_path "${PREFIXED_VERSION}")/bin" && \ + command mkdir -p "${VERSION_PATH}" && \ + command mv "${TMPDIR}/"*/* "${VERSION_PATH}" && \ + command rm -rf "${TMPDIR}" + ); then + EXTRACT_SUCCESS=1 + fi + # 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 + + if ( + [ -n "${TMPDIR-}" ] && \ + command mkdir -p "${TMPDIR}" && \ + command "${tar}" -x${tar_compression_flag}f "${TARBALL}" -C "${TMPDIR}" --strip-components 1 && \ + VERSION_PATH="$(nvm_version_path "${PREFIXED_VERSION}")" && \ + command mkdir -p "${VERSION_PATH}" && \ + command mv "${TMPDIR}/"* "${VERSION_PATH}" && \ + command rm -rf "${TMPDIR}" + ); then + EXTRACT_SUCCESS=1 + fi fi - if ( - [ -n "${TMPDIR-}" ] && \ - command mkdir -p "${TMPDIR}" && \ - command "${tar}" -x${tar_compression_flag}f "${TARBALL}" -C "${TMPDIR}" --strip-components 1 && \ - VERSION_PATH="$(nvm_version_path "${PREFIXED_VERSION}")" && \ - command mkdir -p "${VERSION_PATH}" && \ - command mv "${TMPDIR}/"* "${VERSION_PATH}" && \ - command rm -rf "${TMPDIR}" - ); then + if [ "$EXTRACT_SUCCESS" -eq 1 ]; then if [ -n "${ALIAS-}" ]; then nvm alias "${ALIAS}" "${provided_version}" fi @@ -2028,10 +2066,15 @@ nvm_download_artifact() { local SLUG SLUG="$(nvm_get_download_slug "${FLAVOR}" "${KIND}" "${VERSION}")" + local NVM_OS + NVM_OS="$(nvm_get_os)" + local COMPRESSION - COMPRESSION='gz' - if nvm_supports_xz "${VERSION}"; then - COMPRESSION='xz' + COMPRESSION='tar.gz' + if [ "${NVM_OS}" = "win" ]; then + COMPRESSION='zip' + elif nvm_supports_xz "${VERSION}"; then + COMPRESSION='tar.xz' fi local CHECKSUM @@ -2049,13 +2092,13 @@ nvm_download_artifact() { ) local TARBALL - TARBALL="${tmpdir}/${SLUG}.tar.${COMPRESSION}" + TARBALL="${tmpdir}/${SLUG}.${COMPRESSION}" local TARBALL_URL if nvm_version_greater_than_or_equal_to "${VERSION}" 0.1.14; then - TARBALL_URL="${MIRROR}/${VERSION}/${SLUG}.tar.${COMPRESSION}" + TARBALL_URL="${MIRROR}/${VERSION}/${SLUG}.${COMPRESSION}" else # node <= 0.1.13 does not have a directory - TARBALL_URL="${MIRROR}/${SLUG}.tar.${COMPRESSION}" + TARBALL_URL="${MIRROR}/${SLUG}.${COMPRESSION}" fi if [ -r "${TARBALL}" ]; then @@ -2317,6 +2360,36 @@ nvm_npmrc_bad_news_bears() { return 1 } +# args: path to check and transform if needed +nvm_ensure_posix_path() { + [ -z "$1" ] && nvm_err "Need the location as first parameter" && return 1 + local location + location="$1" + + # If already posix path, just return it + [ "$(printf '%s' "$location" | command cut -b 1)" = "/" ] && nvm_echo "$location" && return 0 + + local letter + letter=$(printf '%s' "$location" | command cut -b 1 | command tr '[:upper:]' '[:lower:]') + local letter_upper + letter_upper=$(printf '%s' "$letter" | command tr '[:lower:]' '[:upper:]') + local letter_prefix + [ -d '/mnt/' ] && letter_prefix='/mnt' + # prefix like /mnt/c or /c + if [ -d "$letter_prefix/$letter" ]; then + letter_prefix="$letter_prefix/$letter" + # prefix like /mnt/C or /C + elif [ -d "$letter_prefix/$letter_upper" ]; then + letter_prefix="$letter_prefix/$letter_upper" + else + nvm_err "Unable to convert the path to posix" + return 1 + fi + # Remove Windows prefix (eg. C:) and replace \ by / + location=$(printf '%s' "$location" | command cut -b 3- | command sed 's#\\#/#g') + nvm_echo "${letter_prefix}${location}" +} + nvm_die_on_prefix() { local NVM_DELETE_PREFIX NVM_DELETE_PREFIX="${1-}" @@ -2346,6 +2419,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 @@ -2357,6 +2433,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="$(nvm_ensure_posix_path "$NVM_CONFIG_VALUE")" + 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}\"" @@ -3130,8 +3209,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 "Unable to install from source for Windows" + EXIT_CODE=1 + else + NVM_NO_PROGRESS="${NVM_NO_PROGRESS:-${noprogress}}" nvm_install_source "${FLAVOR}" std "${VERSION}" "${NVM_MAKE_JOBS}" "${ADDITIONAL_PARAMETERS}" + EXIT_CODE=$? + fi fi fi @@ -3944,6 +4028,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_ensure_posix_path \ >/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 \ diff --git a/test/fast/Unit tests/nvm_get_checksum b/test/fast/Unit tests/nvm_get_checksum index 53e6839b11c..975a3e6972d 100755 --- a/test/fast/Unit tests/nvm_get_checksum +++ b/test/fast/Unit tests/nvm_get_checksum @@ -31,14 +31,14 @@ nvm_download() { nvm_get_checksum_alg() { echo 'sha-256' } -OUTPUT="$(nvm_get_checksum node std foo bar baz)" +OUTPUT="$(nvm_get_checksum node std foo bar tar.baz)" EXPECTED_OUTPUT="mirror-node-std/foo/SHASUMS256.txt" [ "${OUTPUT}" = "${EXPECTED_OUTPUT}" ] || die "expected >${EXPECTED_OUTPUT}<, got >${OUTPUT}<" nvm_get_checksum_alg() { echo 'sha-1' } -OUTPUT="$(nvm_get_checksum iojs std foo bar baz)" +OUTPUT="$(nvm_get_checksum iojs std foo bar tar.baz)" EXPECTED_OUTPUT="mirror-iojs-std/foo/SHASUMS.txt" [ "${OUTPUT}" = "${EXPECTED_OUTPUT}" ] || die "expected >${EXPECTED_OUTPUT}<, got >${OUTPUT}<"