From f0d372b01b975cca18e237a8cc34b7127bbaa456 Mon Sep 17 00:00:00 2001 From: NUAAwqy <146524024+NUAAwqy@users.noreply.github.com> Date: Tue, 20 Oct 2026 19:31:46 +0800 Subject: [PATCH] [Fix] `install.sh`: `nvm_check_global_modules`: don't run a Windows npm under WSL Under WSL, `PATH` can include a Windows Node install, so `command -v npm` can find its `npm` shell shim, which then failed against Windows paths. That npm is not a system node that nvm would shadow, so under WSL, skip an npm that has an `npm.cmd` beside it: both the Node installer and npm's own shims put one there. Outside WSL (eg, Git Bash or Cygwin), a Windows npm is the system node, so the warning is kept. Fixes #3700. Signed-off-by: NUAAwqy <146524024+NUAAwqy@users.noreply.github.com> Co-Authored-By: Codex --- install.sh | 17 ++++++++- test/install_script/nvm_check_global_modules | 24 +++++++++++- test/install_script/nvm_is_wsl | 40 ++++++++++++++++++++ 3 files changed, 79 insertions(+), 2 deletions(-) create mode 100755 test/install_script/nvm_is_wsl diff --git a/install.sh b/install.sh index 9e66a31a..518123da 100755 --- a/install.sh +++ b/install.sh @@ -374,6 +374,16 @@ nvm_detect_profile() { fi } +nvm_is_wsl() { + if [ -e /proc/sys/fs/binfmt_misc/WSLInterop ] || [ -e /proc/sys/fs/binfmt_misc/WSLInterop-late ]; then + return 0 + fi + case "$(command uname -r 2>/dev/null)" in + *[Mm]icrosoft*) return 0 ;; + esac + return 1 +} + # # Check whether the user has any globally-installed npm modules in their system # Node, and warn them if so. @@ -383,6 +393,11 @@ nvm_check_global_modules() { NPM_COMMAND="$(command -v npm 2>/dev/null)" || return 0 [ -n "${NVM_DIR}" ] && [ -z "${NPM_COMMAND%%"$NVM_DIR"/*}" ] && return 0 + # under WSL, a Windows npm (with its `npm.cmd` beside it) is not a system node that nvm would shadow + case "${NPM_COMMAND}" in + */*) nvm_is_wsl && [ -f "${NPM_COMMAND%/*}/npm.cmd" ] && return 0 ;; + esac + local NPM_VERSION NPM_VERSION="$(npm --version)" NPM_VERSION="${NPM_VERSION:--1}" @@ -552,7 +567,7 @@ nvm_do_install() { nvm_reset() { 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 \ - 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_is_wsl nvm_check_global_modules \ nvm_do_install nvm_reset nvm_default_install_dir nvm_grep } diff --git a/test/install_script/nvm_check_global_modules b/test/install_script/nvm_check_global_modules index 8c3072f9..3a63cbe2 100755 --- a/test/install_script/nvm_check_global_modules +++ b/test/install_script/nvm_check_global_modules @@ -5,11 +5,12 @@ cleanup () { unset npm_config_prefix rm -f npm + [ -z "${WINDOWS_NPM_DIR-}" ] || rm -rf "${WINDOWS_NPM_DIR}" PATH="$ORIGINAL_PATH" NVM_DIR="$ORIGINAL_NVM_DIR" unset -f setup cleanup die - unset message ORIGINAL_PATH ORIGINAL_NVM_DIR + unset message ORIGINAL_PATH ORIGINAL_NVM_DIR WINDOWS_NPM_DIR } die () { echo "$@" ; cleanup ; exit 1; } @@ -61,5 +62,26 @@ chmod +x npm message=$(nvm_check_global_modules) [ -z "$message" ] || die "nvm_check_global_modules should have not printed a notice when npm was unavailable; got:\n${message}" +# Faking a Windows Node's npm, with a global module installed +WINDOWS_NPM_DIR="$(mktemp -d)" +cat <<'SH' >"${WINDOWS_NPM_DIR}/npm" +#!/bin/sh +case "$1" in + --version) echo '10.0.0' ;; + list) printf '%s\n' 'npm@10.0.0' '└── windows-global@1.0.0' ;; +esac +SH +touch "${WINDOWS_NPM_DIR}/npm.cmd" +chmod +x "${WINDOWS_NPM_DIR}/npm" +PATH="${WINDOWS_NPM_DIR}:${ORIGINAL_PATH}" + +nvm_is_wsl() { return 0; } +message=$(nvm_check_global_modules) +[ -z "$message" ] || die "nvm_check_global_modules should not run a Windows npm under WSL; got:\n${message}" + +nvm_is_wsl() { return 1; } +message=$(nvm_check_global_modules) +[ -n "$message" ] || die 'nvm_check_global_modules should still warn about a Windows npm outside WSL, where it is the system node' + cleanup diff --git a/test/install_script/nvm_is_wsl b/test/install_script/nvm_is_wsl new file mode 100755 index 00000000..15a5f14d --- /dev/null +++ b/test/install_script/nvm_is_wsl @@ -0,0 +1,40 @@ +#!/bin/sh + +cleanup () { + rm -rf "${FAKE_BIN_DIR}" + PATH="$ORIGINAL_PATH" + unset -f cleanup die fake_uname + unset ORIGINAL_PATH FAKE_BIN_DIR +} +die () { echo "$@" ; cleanup ; exit 1; } + +NVM_ENV=testing \. ../../install.sh + +ORIGINAL_PATH="$PATH" +FAKE_BIN_DIR="$(mktemp -d)" +PATH="${FAKE_BIN_DIR}:${PATH}" + +fake_uname() { + printf '#!/bin/sh\necho %s\n' "$1" > "${FAKE_BIN_DIR}/uname" + chmod +x "${FAKE_BIN_DIR}/uname" +} + +type nvm_is_wsl > /dev/null 2>&1 || die 'nvm_is_wsl is not available' + +fake_uname '6.6.87.2-microsoft-standard-WSL2' +nvm_is_wsl || die 'a WSL2 kernel release should be detected as WSL' + +fake_uname '4.4.0-19041-Microsoft' +nvm_is_wsl || die 'a WSL1 kernel release should be detected as WSL' + +if [ -e /proc/sys/fs/binfmt_misc/WSLInterop ] || [ -e /proc/sys/fs/binfmt_misc/WSLInterop-late ]; then + echo 'skipping the non-WSL checks: this machine has a WSL interop entry' +else + fake_uname '6.8.0-45-generic' + ! nvm_is_wsl || die 'a non-WSL kernel release should not be detected as WSL' + + fake_uname '24.5.0' + ! nvm_is_wsl || die 'a macOS kernel release should not be detected as WSL' +fi + +cleanup