mirror of
https://github.com/nvm-sh/nvm.git
synced 2026-09-17 00:00:07 +08:00
[Robustness] nvm_install_binary_extract: replace a broken version dir atomically
A version directory left without a working `bin/node` - e.g. a partial or interrupted earlier install - wedged reinstallation: `nvm install` saw the version as not installed and re-extracted, but the per-entry `mv` refused to overwrite the leftover non-empty `bin/`, `lib/`, … subdirectories and left a half-updated tree behind (and, without `-b`, fell back to a from-source compile) Remove any pre-existing version directory and move the freshly extracted tree into place with a single rename, so a version is either fully installed or not present at all. The removal is safe: it runs only after the tarball has downloaded and extracted successfully into the cache. Fall back to the previous per-entry move when a single rename cannot cross filesystems.
This commit is contained in:
@@ -2377,22 +2377,39 @@ nvm_install_binary_extract() {
|
||||
if [ "${NVM_OS}" = 'win' ]; then
|
||||
VERSION_PATH="${VERSION_PATH}/bin"
|
||||
command unzip -q "${TARBALL}" -d "${TMPDIR}" || return 1
|
||||
# For non Windows system (including WSL running on Windows)
|
||||
else
|
||||
nvm_extract_tarball "${NVM_OS}" "${VERSION}" "${TARBALL}" "${TMPDIR}"
|
||||
fi
|
||||
|
||||
command mkdir -p "${VERSION_PATH}" || return 1
|
||||
|
||||
if [ "${NVM_OS}" = 'win' ]; then
|
||||
# Replace any pre-existing (possibly broken or partial) install so the
|
||||
# move below cannot collide with leftover files. Safe here: the archive
|
||||
# has already downloaded and unzipped successfully into TMPDIR.
|
||||
command rm -rf "${VERSION_PATH}"
|
||||
command mkdir -p "${VERSION_PATH}" || return 1
|
||||
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
|
||||
command rm -rf "${TMPDIR}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# For non-Windows systems (including WSL running on Windows)
|
||||
nvm_extract_tarball "${NVM_OS}" "${VERSION}" "${TARBALL}" "${TMPDIR}" || return 1
|
||||
|
||||
# Install atomically: replace any pre-existing version directory with a
|
||||
# single rename, so a partial or broken tree is never observed as installed.
|
||||
# A leftover directory without a working bin/node otherwise wedges the
|
||||
# install - the per-entry `mv` refuses to overwrite the non-empty bin/, lib/,
|
||||
# ... subdirectories and leaves a half-updated tree behind. Removing it first
|
||||
# is safe: the tarball has already downloaded and extracted into TMPDIR.
|
||||
command rm -rf "${VERSION_PATH}" || return 1
|
||||
command mkdir -p "$(dirname "${VERSION_PATH}")" || return 1
|
||||
if command mv "${TMPDIR}" "${VERSION_PATH}" 2>/dev/null; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Fall back to a per-entry move when a single rename is not possible (e.g.
|
||||
# TMPDIR and the versions directory are on different filesystems).
|
||||
command rm -rf "${VERSION_PATH}"
|
||||
command mkdir -p "${VERSION_PATH}" || return 1
|
||||
command mv "${TMPDIR}/"* "${VERSION_PATH}" || return 1
|
||||
command rm -rf "${TMPDIR}"
|
||||
|
||||
return 0
|
||||
|
||||
Reference in New Issue
Block a user