diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..86696d9 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +.gitattributes text eol=lf +README.md text eol=lf +.github/workflows/*.yml text eol=lf +node-reinstall.bat text eol=crlf +test/*.bat text eol=crlf diff --git a/.github/workflows/windows-test.yml b/.github/workflows/windows-test.yml new file mode 100644 index 0000000..1987d78 --- /dev/null +++ b/.github/workflows/windows-test.yml @@ -0,0 +1,19 @@ +name: Windows test + +on: + pull_request: + push: + +jobs: + batch-smoke: + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Run Windows smoke checks + shell: cmd + run: call test\windows-smoke.bat diff --git a/README.md b/README.md index 93ebe77..b6c6097 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,56 @@ This script assumes you are comfortable enough with UNIX to perform these action ![](img/pay-attention.gif) +## Windows + +Windows support is provided by `node-reinstall.bat`. It is intentionally narrower +than the OSX/Linux script: it removes the user-level npm paths that commonly hold +global npm shims, modules, caches, and native build artifacts, then reinstalls +Node.js through nvm-windows when `nvm` is available on `PATH`. + +The Windows script may delete: + +``` +%APPDATA%\npm\npm +%APPDATA%\npm\npm.cmd +%APPDATA%\npm\npx +%APPDATA%\npm\npx.cmd +%APPDATA%\npm\node_modules +%APPDATA%\npm-cache +%USERPROFILE%\.npm +%USERPROFILE%\.npm-cache +%USERPROFILE%\.node-gyp +``` + +Preview the cleanup before deleting anything: + +``` +node-reinstall.bat --dry-run +``` + +Run the non-destructive Windows smoke checks: + +``` +test\windows-smoke.bat +``` + +Run the Windows re-installer: + +``` +node-reinstall.bat +``` + +Or specify a Node.js version for nvm-windows: + +``` +node-reinstall.bat 20.11.1 +``` + +If nvm-windows is not installed, the script still performs the npm cleanup and +prints the next manual install step instead of downloading or running an +installer for you. The repository pins `node-reinstall.bat` to CRLF line endings +so Windows `cmd.exe` can resolve its internal labels reliably. + ## Summary This is a complete (and very destructive) tool for re-installing Node.js on OSX and Linux. See the [SO article](http://stackoverflow.com/a/11178106/2083544) for reference and the related [gist that spawned this repo](https://gist.github.com/brock/5b1b70590e1171c4ab54). This deletes ~~everything, yes everything,~~ **a lot of stuff you might want** and completely removes Node.js and NPM and replaces it with the Node Version Manager called [NVM](https://github.com/creationix/nvm). It will attempt to re-install any global NPM modules already installed, and you can opt for Nave instead of NVM if you prefer. diff --git a/node-reinstall.bat b/node-reinstall.bat new file mode 100644 index 0000000..257334f --- /dev/null +++ b/node-reinstall.bat @@ -0,0 +1,209 @@ +@echo off +setlocal EnableExtensions EnableDelayedExpansion + +set "VERSION=0.0.17" +set "DEFAULT_NODE_VERSION=5" +set "FORCE=0" +set "DRY_RUN=0" +set "DESIRED_NODE_VERSION=" +set "GLOBAL_MODULES_FILE=%TEMP%\node-reinstall-global-modules-%RANDOM%.txt" + +:parse_args +if "%~1"=="" goto after_args +set "ARG=%~1" +if /I "%ARG%"=="--help" goto usage +if /I "%ARG%"=="-h" goto usage +if /I "%ARG%"=="--version" goto version +if /I "%ARG%"=="-v" goto version +if /I "%ARG%"=="--force" ( + set "FORCE=1" + shift + goto parse_args +) +if /I "%ARG%"=="-f" ( + set "FORCE=1" + shift + goto parse_args +) +if /I "%ARG%"=="--dry-run" ( + set "DRY_RUN=1" + shift + goto parse_args +) +if "%ARG:~0,1%"=="-" ( + echo error: Unknown option `%ARG%` 1>&2 + call :usage_text 1>&2 + exit /b 1 +) +if defined DESIRED_NODE_VERSION ( + echo error: Only one NODE_VERSION argument is supported. 1>&2 + call :usage_text 1>&2 + exit /b 1 +) +set "DESIRED_NODE_VERSION=%ARG%" +shift +goto parse_args + +:after_args +call :detect_node_version + +if defined DESIRED_NODE_VERSION ( + set "NODE_VERSION=%DESIRED_NODE_VERSION%" +) else if defined INSTALLED_NODE_VERSION ( + set "NODE_VERSION=%INSTALLED_NODE_VERSION%" +) else ( + set "NODE_VERSION=%DEFAULT_NODE_VERSION%" +) + +if /I "%NODE_VERSION:~0,1%"=="v" set "NODE_VERSION=%NODE_VERSION:~1%" + +echo node-reinstall.bat will delete user-level Windows Node/npm paths. +echo Read this script before continuing. The deleted files cannot be recovered. +echo. + +if defined INSTALLED_NODE_VERSION ( + echo Found Node.js version %INSTALLED_NODE_VERSION% already installed. + echo If you continue now, this script will clean npm paths and reinstall Node.js version %NODE_VERSION% when nvm-windows is available. + call :confirm || exit /b 1 +) + +call :collect_global_modules + +if exist "%GLOBAL_MODULES_FILE%" ( + echo Will reinstall these global npm modules after Node is available: + for /f "usebackq delims=" %%M in ("%GLOBAL_MODULES_FILE%") do echo %%M +) else ( + echo No global npm modules were detected before cleanup. +) + +call :confirm || exit /b 1 + +call :remove_file "%APPDATA%\npm\npm" +call :remove_file "%APPDATA%\npm\npm.cmd" +call :remove_file "%APPDATA%\npm\npx" +call :remove_file "%APPDATA%\npm\npx.cmd" +call :remove_dir "%APPDATA%\npm\node_modules" +call :remove_dir "%APPDATA%\npm-cache" +call :remove_dir "%USERPROFILE%\.npm" +call :remove_dir "%USERPROFILE%\.npm-cache" +call :remove_dir "%USERPROFILE%\.node-gyp" + +call :reinstall_with_nvm +call :reinstall_global_modules + +if exist "%GLOBAL_MODULES_FILE%" del /f /q "%GLOBAL_MODULES_FILE%" >nul 2>nul + +echo node-reinstall.bat is done. +echo You must restart your terminal for changes to take effect. +exit /b 0 + +:usage +call :usage_text +exit /b 0 + +:usage_text +echo node-reinstall.bat +echo completely cleans Windows Node/npm user paths and reinstalls with nvm-windows when available. +echo. +echo Usage: node-reinstall.bat [-h^|--help] [-v^|--version] [-f^|--force] [--dry-run] [NODE_VERSION] +echo. +echo Commands: +echo node-reinstall.bat clean npm paths and reinstall current/default Node version with nvm-windows +echo node-reinstall.bat --dry-run show what would be deleted or run without changing anything +echo node-reinstall.bat -f skip confirmation prompts +echo node-reinstall.bat 20.11.1 reinstall a specific Node.js version with nvm-windows +exit /b 0 + +:version +echo %VERSION% +exit /b 0 + +:confirm +if "%FORCE%"=="1" exit /b 0 +choice /C YN /N /M "Continue? [Y/N] " +if errorlevel 2 exit /b 1 +exit /b 0 + +:detect_node_version +set "INSTALLED_NODE_VERSION=" +for /f "usebackq delims=" %%V in (`node --version 2^>nul`) do ( + set "INSTALLED_NODE_VERSION=%%V" +) +exit /b 0 + +:collect_global_modules +if exist "%GLOBAL_MODULES_FILE%" del /f /q "%GLOBAL_MODULES_FILE%" >nul 2>nul +where npm >nul 2>nul +if errorlevel 1 exit /b 0 + +for /f "usebackq delims=" %%G in (`npm -g list --depth 0 --parseable 2^>nul`) do ( + for %%M in ("%%G") do set "MODULE_NAME=%%~nxM" + if /I not "!MODULE_NAME!"=="node_modules" if /I not "!MODULE_NAME!"=="npm" if not "!MODULE_NAME!"=="" ( + echo !MODULE_NAME!>>"%GLOBAL_MODULES_FILE%" + ) +) + +for %%F in ("%GLOBAL_MODULES_FILE%") do if %%~zF EQU 0 del /f /q "%GLOBAL_MODULES_FILE%" >nul 2>nul +exit /b 0 + +:remove_file +set "TARGET=%~1" +if not exist "%TARGET%" exit /b 0 +if "%DRY_RUN%"=="1" ( + echo Would delete file: "%TARGET%" + exit /b 0 +) +echo Deleting file: "%TARGET%" +del /f /q "%TARGET%" +exit /b %ERRORLEVEL% + +:remove_dir +set "TARGET=%~1" +if not exist "%TARGET%\" exit /b 0 +if "%DRY_RUN%"=="1" ( + echo Would delete directory: "%TARGET%" + exit /b 0 +) +echo Deleting directory: "%TARGET%" +rmdir /s /q "%TARGET%" +exit /b %ERRORLEVEL% + +:reinstall_with_nvm +where nvm >nul 2>nul +if errorlevel 1 ( + echo nvm-windows was not found on PATH. + echo Install Node manually from https://nodejs.org/ or install nvm-windows, then rerun this script. + exit /b 0 +) + +if "%DRY_RUN%"=="1" ( + echo Would run: nvm install %NODE_VERSION% + echo Would run: nvm use %NODE_VERSION% + exit /b 0 +) + +echo Installing Node.js %NODE_VERSION% with nvm-windows. +nvm install %NODE_VERSION% +if errorlevel 1 exit /b %ERRORLEVEL% +nvm use %NODE_VERSION% +exit /b %ERRORLEVEL% + +:reinstall_global_modules +if not exist "%GLOBAL_MODULES_FILE%" exit /b 0 +where npm >nul 2>nul +if errorlevel 1 ( + echo npm was not found after cleanup, so global modules were not reinstalled. + exit /b 0 +) + +if "%DRY_RUN%"=="1" ( + for /f "usebackq delims=" %%M in ("%GLOBAL_MODULES_FILE%") do echo Would run: npm install --global %%M + exit /b 0 +) + +for /f "usebackq delims=" %%M in ("%GLOBAL_MODULES_FILE%") do ( + echo Reinstalling global module: %%M + npm install --global %%M + if errorlevel 1 exit /b %ERRORLEVEL% +) +exit /b 0 diff --git a/test/windows-smoke.bat b/test/windows-smoke.bat new file mode 100644 index 0000000..1347da0 --- /dev/null +++ b/test/windows-smoke.bat @@ -0,0 +1,22 @@ +@echo off +setlocal EnableExtensions + +set "SCRIPT=%~dp0..\node-reinstall.bat" + +call "%SCRIPT%" --help +if errorlevel 1 exit /b %ERRORLEVEL% + +call "%SCRIPT%" --version +if errorlevel 1 exit /b %ERRORLEVEL% + +call "%SCRIPT%" --dry-run --force 20.11.1 +if errorlevel 1 exit /b %ERRORLEVEL% + +call "%SCRIPT%" --not-a-real-option +if not errorlevel 1 ( + echo Expected unknown option to fail. + exit /b 1 +) + +echo Windows smoke checks passed. +exit /b 0