-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Preserve builtin conf when installing npm globally
When a file named 'npmrc' is in the root of the npm module that is currently running, it adds config values that override the defaults (but not the global or user configs). This is a way for a system package installer to tell the npm that it installs to put its globals somewhere other than the default. In order to keep these configs around when users self-update npm with `npm i -g npm`, these config values must be "sticky", and ride along into the newly globally installed npm. This commit restores this behavior, fixing self-updating npm for Windows users, and any other systems that may make use of this functionality. Fixes: #2002 PR-URL: #2184 Credit: @isaacs Close: #2184 Reviewed-by: @ruyadorno
- Loading branch information
Showing
12 changed files
with
173 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
const reifyOutput = require('./reify-output.js') | ||
const npm = require('../npm.js') | ||
const ini = require('ini') | ||
const {writeFile} = require('fs').promises | ||
const {resolve} = require('path') | ||
|
||
const reifyFinish = async arb => { | ||
await saveBuiltinConfig(arb) | ||
reifyOutput(arb) | ||
} | ||
|
||
const saveBuiltinConfig = async arb => { | ||
const { options: { global }, actualTree } = arb | ||
if (!global) | ||
return | ||
|
||
// if we are using a builtin config, and just installed npm as | ||
// a top-level global package, we have to preserve that config. | ||
const npmNode = actualTree.inventory.get('node_modules/npm') | ||
if (!npmNode) | ||
return | ||
|
||
const builtinConf = npm.config.data.get('builtin') | ||
if (builtinConf.loadError) | ||
return | ||
|
||
const content = ini.stringify(builtinConf.raw).trim() + '\n' | ||
await writeFile(resolve(npmNode.path, 'npmrc'), content) | ||
} | ||
|
||
module.exports = reifyFinish |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
/* IMPORTANT | ||
* This snapshot file is auto-generated, but designed for humans. | ||
* It should be checked into source control and tracked carefully. | ||
* Re-generate by setting TAP_SNAPSHOT=1 and running tests. | ||
* Make sure to inspect the output below. Do not ignore changes! | ||
*/ | ||
'use strict' | ||
exports[`test/lib/utils/reify-finish.js TAP should write if everything above passes > written config 1`] = ` | ||
hasBuiltinConfig=true | ||
x=y | ||
[nested] | ||
foo=bar | ||
` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
const t = require('tap') | ||
const requireInject = require('require-inject') | ||
|
||
const npm = { | ||
config: { | ||
data: { | ||
get: () => builtinConfMock, | ||
}, | ||
}, | ||
} | ||
|
||
const builtinConfMock = { | ||
loadError: new Error('no builtin config'), | ||
raw: { hasBuiltinConfig: true, x: 'y', nested: { foo: 'bar' }}, | ||
} | ||
|
||
const reifyOutput = () => {} | ||
|
||
let expectWrite = false | ||
const realFs = require('fs') | ||
const fs = { | ||
...realFs, | ||
promises: { | ||
...realFs.promises, | ||
writeFile: async (path, data) => { | ||
if (!expectWrite) | ||
throw new Error('did not expect to write builtin config file') | ||
return realFs.promises.writeFile(path, data) | ||
}, | ||
}, | ||
} | ||
|
||
const reifyFinish = requireInject('../../../lib/utils/reify-finish.js', { | ||
fs, | ||
'../../../lib/npm.js': npm, | ||
'../../../lib/utils/reify-output.js': reifyOutput, | ||
}) | ||
|
||
t.test('should not write if not global', async t => { | ||
expectWrite = false | ||
await reifyFinish({ | ||
options: { global: false }, | ||
actualTree: {}, | ||
}) | ||
}) | ||
|
||
t.test('should not write if no global npm module', async t => { | ||
expectWrite = false | ||
await reifyFinish({ | ||
options: { global: true }, | ||
actualTree: { | ||
inventory: new Map(), | ||
}, | ||
}) | ||
}) | ||
|
||
t.test('should not write if builtin conf had load error', async t => { | ||
expectWrite = false | ||
await reifyFinish({ | ||
options: { global: true }, | ||
actualTree: { | ||
inventory: new Map([['node_modules/npm', {}]]), | ||
}, | ||
}) | ||
}) | ||
|
||
t.test('should write if everything above passes', async t => { | ||
expectWrite = true | ||
delete builtinConfMock.loadError | ||
const path = t.testdir() | ||
await reifyFinish({ | ||
options: { global: true }, | ||
actualTree: { | ||
inventory: new Map([['node_modules/npm', {path}]]), | ||
}, | ||
}) | ||
t.matchSnapshot(fs.readFileSync(`${path}/npmrc`, 'utf8'), 'written config') | ||
}) |