Skip to content
This repository was archived by the owner on May 10, 2021. It is now read-only.

Commit 161f6b2

Browse files
authoredAug 31, 2018
feat(config): switch to modern, figgy-pudding configuration (#57)
* updates to pacote@9 * switches to figgy-pudding for config handling * removes config/pacote-opts and config/lifecycle-opts * all config is in opts itself. `opts.config` is no longer used * adds support for auth config reading to npmConfig() utility BREAKING CHANGE: this updates cipm to use pacote@9, which consumes npm-style config objects, not pacoteOpts()-style objects.
1 parent 2fd8651 commit 161f6b2

10 files changed

+199
-394
lines changed
 

‎bin/cli.js

+2-5
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,8 @@ function cliMain () {
1717
const log = require('npmlog')
1818
return fromNpm(process.argv)
1919
.then(c => {
20-
log.level = c.get('loglevel')
21-
return new Installer({
22-
config: c,
23-
log
24-
})
20+
log.level = c.loglevel
21+
return new Installer(c.concat({log}))
2522
})
2623
.then(cipm => cipm.run())
2724
.then(

‎index.js

+58-20
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const BB = require('bluebird')
55
const binLink = require('bin-links')
66
const buildLogicalTree = require('npm-logical-tree')
77
const extract = require('./lib/extract.js')
8+
const figgyPudding = require('figgy-pudding')
89
const fs = require('graceful-fs')
910
const getPrefix = require('find-npm-prefix')
1011
const lifecycle = require('npm-lifecycle')
@@ -20,10 +21,44 @@ const statAsync = BB.promisify(fs.stat)
2021
const symlinkAsync = BB.promisify(fs.symlink)
2122
const writeFileAsync = BB.promisify(fs.writeFile)
2223

24+
const CipmOpts = figgyPudding({
25+
also: {},
26+
dev: 'development',
27+
development: {},
28+
force: {},
29+
global: {},
30+
ignoreScripts: 'ignore-scripts',
31+
'ignore-scripts': {},
32+
log: {},
33+
loglevel: {},
34+
only: {},
35+
prefix: {},
36+
prod: 'production',
37+
production: {},
38+
Promise: { default: () => BB },
39+
umask: {}
40+
})
41+
42+
const LifecycleOpts = figgyPudding({
43+
config: {},
44+
'script-shell': {},
45+
scriptShell: 'script-shell',
46+
'ignore-scripts': {},
47+
ignoreScripts: 'ignore-scripts',
48+
'ignore-prepublish': {},
49+
ignorePrepublish: 'ignore-prepublish',
50+
'scripts-prepend-node-path': {},
51+
scriptsPrependNodePath: 'scripts-prepend-node-path',
52+
'unsafe-perm': {},
53+
unsafePerm: 'unsafe-perm',
54+
prefix: {},
55+
dir: 'prefix',
56+
failOk: { default: false }
57+
}, { other () { return true } })
58+
2359
class Installer {
2460
constructor (opts) {
25-
this.opts = opts
26-
this.config = opts.config
61+
this.opts = CipmOpts(opts)
2762

2863
// Stats
2964
this.startTime = Date.now()
@@ -80,17 +115,17 @@ class Installer {
80115

81116
prepare () {
82117
this.log.info('prepare', 'initializing installer')
83-
this.log.level = this.config.get('loglevel')
118+
this.log.level = this.opts.loglevel
84119
this.log.verbose('prepare', 'starting workers')
85120
extract.startWorkers()
86121

87122
return (
88-
this.config.get('prefix') && this.config.get('global')
89-
? BB.resolve(this.config.get('prefix'))
123+
this.opts.prefix && this.opts.global
124+
? BB.resolve(this.opts.prefix)
90125
// There's some Special™ logic around the `--prefix` config when it
91126
// comes from a config file or env vs when it comes from the CLI
92127
: process.argv.some(arg => arg.match(/^\s*--prefix\s*/i))
93-
? BB.resolve(this.config.get('prefix'))
128+
? BB.resolve(this.opts.prefix)
94129
: getPrefix(process.cwd())
95130
)
96131
.then(prefix => {
@@ -218,15 +253,15 @@ class Installer {
218253
checkDepEnv (dep) {
219254
const includeDev = (
220255
// Covers --dev and --development (from npm config itself)
221-
this.config.get('dev') ||
256+
this.opts.dev ||
222257
(
223-
!/^prod(uction)?$/.test(this.config.get('only')) &&
224-
!this.config.get('production')
258+
!/^prod(uction)?$/.test(this.opts.only) &&
259+
!this.opts.production
225260
) ||
226-
/^dev(elopment)?$/.test(this.config.get('only')) ||
227-
/^dev(elopment)?$/.test(this.config.get('also'))
261+
/^dev(elopment)?$/.test(this.opts.only) ||
262+
/^dev(elopment)?$/.test(this.opts.also)
228263
)
229-
const includeProd = !/^dev(elopment)?$/.test(this.config.get('only'))
264+
const includeProd = !/^dev(elopment)?$/.test(this.opts.only)
230265
return (dep.dev && includeDev) || (!dep.dev && includeProd)
231266
}
232267

@@ -274,14 +309,14 @@ class Installer {
274309
}
275310
return readPkgJson(path.join(depPath, 'package.json'))
276311
.then(pkg => binLink(pkg, depPath, false, {
277-
force: this.config.get('force'),
278-
ignoreScripts: this.config.get('ignore-scripts'),
312+
force: this.opts.force,
313+
ignoreScripts: this.opts['ignore-scripts'],
279314
log: Object.assign({}, this.log, { info: () => {} }),
280315
name: pkg.name,
281316
pkgId: pkg.name + '@' + pkg.version,
282317
prefix: this.prefix,
283318
prefixes: [this.prefix],
284-
umask: this.config.get('umask')
319+
umask: this.opts.umask
285320
}), e => {
286321
this.log.verbose('buildTree', `error linking ${spec}: ${e.message} ${e.stack}`)
287322
})
@@ -346,18 +381,21 @@ class Installer {
346381

347382
runScript (stage, pkg, pkgPath) {
348383
const start = Date.now()
349-
if (!this.config.get('ignore-scripts')) {
384+
if (!this.opts['ignore-scripts']) {
350385
// TODO(mikesherov): remove pkg._id when npm-lifecycle no longer relies on it
351386
pkg._id = pkg.name + '@' + pkg.version
352-
const opts = this.config.toLifecycle()
353-
return BB.resolve(lifecycle(pkg, stage, pkgPath, opts))
354-
.tap(() => { this.timings.scripts += Date.now() - start })
387+
return BB.resolve(lifecycle(
388+
pkg, stage, pkgPath, LifecycleOpts(this.opts).concat({
389+
// TODO: can be removed once npm-lifecycle is updated to modern
390+
// config practices.
391+
config: this.opts
392+
}))
393+
).tap(() => { this.timings.scripts += Date.now() - start })
355394
}
356395
return BB.resolve()
357396
}
358397
}
359398
module.exports = Installer
360-
module.exports.CipmConfig = require('./lib/config/npm-config.js').CipmConfig
361399

362400
function mark (tree, failed) {
363401
const liveDeps = new Set()

‎lib/config/lifecycle-opts.js

-29
This file was deleted.

‎lib/config/npm-config.js

+42-30
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,22 @@
11
'use strict'
22

33
const BB = require('bluebird')
4-
const lifecycleOpts = require('./lifecycle-opts.js')
5-
const pacoteOpts = require('./pacote-opts.js')
6-
const protoduck = require('protoduck')
7-
const spawn = require('child_process').spawn
84

9-
class NpmConfig extends Map {}
5+
const fs = require('fs')
6+
const figgyPudding = require('figgy-pudding')
7+
const ini = require('ini')
8+
const path = require('path')
9+
const spawn = require('child_process').spawn
1010

11-
const CipmConfig = protoduck.define({
12-
get: [],
13-
set: [],
14-
toPacote: [],
15-
toLifecycle: []
16-
}, {
17-
name: 'CipmConfig'
18-
})
19-
module.exports.CipmConfig = CipmConfig
11+
const readFileAsync = BB.promisify(fs.readFile)
2012

21-
CipmConfig.impl(NpmConfig, {
22-
get: Map.prototype.get,
23-
set: Map.prototype.set,
24-
toPacote (opts) {
25-
return pacoteOpts(this, opts)
26-
},
27-
toLifecycle () {
28-
return lifecycleOpts(this)
29-
}
13+
const NpmConfig = figgyPudding({
14+
cache: { default: '' },
15+
then: {},
16+
userconfig: {}
3017
})
3118

32-
module.exports.fromObject = fromObj
33-
function fromObj (obj) {
34-
const map = new NpmConfig()
35-
Object.keys(obj).forEach(k => map.set(k, obj[k]))
36-
return map
37-
}
19+
module.exports = NpmConfig
3820

3921
module.exports.fromNpm = getNpmConfig
4022
function getNpmConfig (argv) {
@@ -62,11 +44,41 @@ function getNpmConfig (argv) {
6244
reject(new Error('`npm` command not found. Please ensure you have npm@5.4.0 or later installed.'))
6345
} else {
6446
try {
65-
resolve(fromObj(JSON.parse(stdout)))
47+
resolve(JSON.parse(stdout))
6648
} catch (e) {
6749
reject(new Error('`npm config ls --json` failed to output json. Please ensure you have npm@5.4.0 or later installed.'))
6850
}
6951
}
7052
})
53+
}).then(opts => {
54+
return BB.all(
55+
process.cwd().split(path.sep).reduce((acc, next) => {
56+
acc.path = path.join(acc.path, next)
57+
acc.promises.push(maybeReadIni(path.join(acc.path, '.npmrc')))
58+
acc.promises.push(maybeReadIni(path.join(acc.path, 'npmrc')))
59+
return acc
60+
}, {
61+
path: '',
62+
promises: []
63+
}).promises.concat(
64+
opts.userconfig ? maybeReadIni(opts.userconfig) : {}
65+
)
66+
).then(configs => NpmConfig(...configs, opts))
67+
}).then(opts => {
68+
if (opts.cache) {
69+
return opts.concat({ cache: path.join(opts.cache, '_cacache') })
70+
} else {
71+
return opts
72+
}
7173
})
7274
}
75+
76+
function maybeReadIni (f) {
77+
return readFileAsync(f, 'utf8').catch(err => {
78+
if (err.code === 'ENOENT') {
79+
return ''
80+
} else {
81+
throw err
82+
}
83+
}).then(ini.parse)
84+
}

‎lib/config/pacote-opts.js

-135
This file was deleted.

‎package-lock.json

+83-117
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,16 @@
3232
"dependencies": {
3333
"bin-links": "^1.1.2",
3434
"bluebird": "^3.5.1",
35+
"figgy-pudding": "^3.5.1",
3536
"find-npm-prefix": "^1.0.2",
3637
"graceful-fs": "^4.1.11",
38+
"ini": "^1.3.5",
3739
"lock-verify": "^2.0.2",
3840
"mkdirp": "^0.5.1",
3941
"npm-lifecycle": "^2.0.3",
4042
"npm-logical-tree": "^1.2.1",
4143
"npm-package-arg": "^6.1.0",
42-
"pacote": "^8.1.6",
43-
"protoduck": "^5.0.0",
44+
"pacote": "^9.1.0",
4445
"read-package-json": "^2.0.13",
4546
"rimraf": "^2.6.2",
4647
"worker-farm": "^1.6.0"

‎test/specs/index.js

+6-9
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
const BB = require('bluebird')
44

5-
const npmConfig = require('../../lib/config/npm-config.js')
65
const npmlog = require('npmlog')
76
const fixtureHelper = require('../lib/fixtureHelper.js')
87
const fs = BB.promisifyAll(require('fs'))
@@ -37,15 +36,13 @@ const Installer = requireInject('../../index.js', {
3736
})
3837

3938
function run (moreOpts) {
40-
return new Installer({
39+
return new Installer(Object.assign({
4140
log: npmlog,
42-
config: npmConfig.fromObject(Object.assign({}, {
43-
global: true,
44-
prefix,
45-
'unsafe-perm': true, // this is the default when running non-root
46-
loglevel: process.env.LOGLEVEL || 'error'
47-
}, moreOpts || {}))
48-
}).run()
41+
global: true,
42+
prefix,
43+
'unsafe-perm': true, // this is the default when running non-root
44+
loglevel: process.env.LOGLEVEL || 'error'
45+
}, moreOpts || {})).run()
4946
}
5047

5148
test('throws error when no package.json is found', t => {

‎test/specs/lib/config.js

+5-12
Original file line numberDiff line numberDiff line change
@@ -56,19 +56,12 @@ test('config: errors if npm errors for any reason', t => {
5656
test('config: parses configs from npm', t => {
5757
cleanup()
5858

59-
const expectedConfig = { a: 1, b: 2 }
60-
61-
config().then(config => {
62-
const objConf = {}
63-
for (const k of config.keys()) {
64-
objConf[k] = config.get(k)
65-
}
66-
t.deepEqual(objConf, expectedConfig, 'configs match')
67-
t.end()
68-
})
69-
70-
child.stdout.emit('data', JSON.stringify(expectedConfig))
59+
const c = config()
60+
child.stdout.emit('data', JSON.stringify({cache: 'foo'}))
7161
child.emit('close', 0)
62+
return c.then(config => {
63+
t.match(config.cache, /^foo[/\\]_cacache$/, 'configs match')
64+
})
7265
})
7366

7467
test('config: cleanup', t => {

‎test/specs/lib/pacote-opts.js

-35
This file was deleted.

0 commit comments

Comments
 (0)
This repository has been archived.