@@ -15,6 +15,8 @@ const NodeVersion = require('./version');
1515let nvsDownload = null ; // Delay-load
1616let nvsExtract = null ; // Delay-load
1717
18+ const isWindows = process . platform === 'win32' ;
19+
1820/**
1921 * Downloads and extracts a version of node.
2022 *
@@ -163,6 +165,8 @@ function downloadAndExtractAsync(version) {
163165 }
164166 } ) ;
165167 }
168+
169+ return fixNpmCmdShimsAsync ( targetDir ) ;
166170 } ) . catch ( e => {
167171 removeDirectoryIfEmpty ( targetDir ) ;
168172 removeDirectoryIfEmpty ( path . dirname ( targetDir ) ) ;
@@ -272,6 +276,53 @@ function removeDirectoryIfEmpty(dir) {
272276 }
273277}
274278
279+ /**
280+ * Fix Windows .cmd shims for npm executables, which are installed incorrectly
281+ * by Node.js and may block global npm package updates.
282+ *
283+ * @param {string } targetDir Directory where a node version was extracted.
284+ */
285+ async function fixNpmCmdShimsAsync ( targetDir ) {
286+ if ( ! isWindows ) return ;
287+
288+ try {
289+ // This assumes the npm version carried with the node installation
290+ // includes a `cmd-shim` module. Currently true for at least npm >= 3.
291+ const cmdShimPath = path . join (
292+ targetDir , 'node_modules' , 'npm' , 'node_modules' , 'cmd-shim' ) ;
293+ const cmdShim = require ( cmdShimPath ) ;
294+
295+ // Enumerate .cmd files in the target directory and fix if they are shims.
296+ for ( let childName of fs . readdirSync ( targetDir ) ) {
297+ if ( path . extname ( childName ) . toLowerCase ( ) !== '.cmd' ) {
298+ continue ;
299+ }
300+
301+ const cmdName = path . basename ( childName , '.cmd' ) ;
302+ const shimPath = path . join ( targetDir , cmdName ) ;
303+ const jsCliPath = path . join (
304+ targetDir , 'node_modules' , 'npm' , 'bin' , `${ cmdName } -cli.js` ) ;
305+ if ( ! fs . existsSync ( jsCliPath ) ) {
306+ // A corresponding JS CLI file does not exist in the npm bin dir.
307+ // Probably this is some other .cmd file that isn't an npm shim.
308+ continue ;
309+ }
310+
311+ // Found an npm shim. Call the cmd-shim module to fix it.
312+ await new Promise ( ( resolve , reject ) => {
313+ cmdShim ( jsCliPath , shimPath , ( e ) => {
314+ if ( e ) reject ( e ) ;
315+ else resolve ( ) ;
316+ } ) ;
317+ } ) ;
318+ }
319+ } catch ( e ) {
320+ // Not a fatal error. Most things still work if the shims are not fixed.
321+ // The only problem may be that the global npm package cannot be upgraded.
322+ console . warn ( 'Warning: Failed to fix npm cmd shims: ' + e . message ) ;
323+ }
324+ }
325+
275326module . exports = {
276327 addAsync,
277328 remove,
0 commit comments