Skip to content
This repository has been archived by the owner on Aug 17, 2019. It is now read-only.

Commit

Permalink
feat(config): switch to modern, figgy-pudding configuration
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
zkat committed Aug 31, 2018
1 parent 2fd8651 commit 617a39d
Show file tree
Hide file tree
Showing 10 changed files with 199 additions and 394 deletions.
7 changes: 2 additions & 5 deletions bin/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,8 @@ function cliMain () {
const log = require('npmlog')
return fromNpm(process.argv)
.then(c => {
log.level = c.get('loglevel')
return new Installer({
config: c,
log
})
log.level = c.loglevel
return new Installer(c.concat({log}))
})
.then(cipm => cipm.run())
.then(
Expand Down
78 changes: 58 additions & 20 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const BB = require('bluebird')
const binLink = require('bin-links')
const buildLogicalTree = require('npm-logical-tree')
const extract = require('./lib/extract.js')
const figgyPudding = require('figgy-pudding')
const fs = require('graceful-fs')
const getPrefix = require('find-npm-prefix')
const lifecycle = require('npm-lifecycle')
Expand All @@ -20,10 +21,44 @@ const statAsync = BB.promisify(fs.stat)
const symlinkAsync = BB.promisify(fs.symlink)
const writeFileAsync = BB.promisify(fs.writeFile)

const CipmOpts = figgyPudding({
also: {},
dev: 'development',
development: {},
force: {},
global: {},
ignoreScripts: 'ignore-scripts',
'ignore-scripts': {},
log: {},
loglevel: {},
only: {},
prefix: {},
prod: 'production',
production: {},
Promise: { default: () => BB },
umask: {}
})

const LifecycleOpts = figgyPudding({
config: {},
'script-shell': {},
scriptShell: 'script-shell',
'ignore-scripts': {},
ignoreScripts: 'ignore-scripts',
'ignore-prepublish': {},
ignorePrepublish: 'ignore-prepublish',
'scripts-prepend-node-path': {},
scriptsPrependNodePath: 'scripts-prepend-node-path',
'unsafe-perm': {},
unsafePerm: 'unsafe-perm',
prefix: {},
dir: 'prefix',
failOk: { default: false }
}, { other () { return true } })

class Installer {
constructor (opts) {
this.opts = opts
this.config = opts.config
this.opts = CipmOpts(opts)

// Stats
this.startTime = Date.now()
Expand Down Expand Up @@ -80,17 +115,17 @@ class Installer {

prepare () {
this.log.info('prepare', 'initializing installer')
this.log.level = this.config.get('loglevel')
this.log.level = this.opts.loglevel
this.log.verbose('prepare', 'starting workers')
extract.startWorkers()

return (
this.config.get('prefix') && this.config.get('global')
? BB.resolve(this.config.get('prefix'))
this.opts.prefix && this.opts.global
? BB.resolve(this.opts.prefix)
// There's some Special™ logic around the `--prefix` config when it
// comes from a config file or env vs when it comes from the CLI
: process.argv.some(arg => arg.match(/^\s*--prefix\s*/i))
? BB.resolve(this.config.get('prefix'))
? BB.resolve(this.opts.prefix)
: getPrefix(process.cwd())
)
.then(prefix => {
Expand Down Expand Up @@ -218,15 +253,15 @@ class Installer {
checkDepEnv (dep) {
const includeDev = (
// Covers --dev and --development (from npm config itself)
this.config.get('dev') ||
this.opts.dev ||
(
!/^prod(uction)?$/.test(this.config.get('only')) &&
!this.config.get('production')
!/^prod(uction)?$/.test(this.opts.only) &&
!this.opts.production
) ||
/^dev(elopment)?$/.test(this.config.get('only')) ||
/^dev(elopment)?$/.test(this.config.get('also'))
/^dev(elopment)?$/.test(this.opts.only) ||
/^dev(elopment)?$/.test(this.opts.also)
)
const includeProd = !/^dev(elopment)?$/.test(this.config.get('only'))
const includeProd = !/^dev(elopment)?$/.test(this.opts.only)
return (dep.dev && includeDev) || (!dep.dev && includeProd)
}

Expand Down Expand Up @@ -274,14 +309,14 @@ class Installer {
}
return readPkgJson(path.join(depPath, 'package.json'))
.then(pkg => binLink(pkg, depPath, false, {
force: this.config.get('force'),
ignoreScripts: this.config.get('ignore-scripts'),
force: this.opts.force,
ignoreScripts: this.opts['ignore-scripts'],
log: Object.assign({}, this.log, { info: () => {} }),
name: pkg.name,
pkgId: pkg.name + '@' + pkg.version,
prefix: this.prefix,
prefixes: [this.prefix],
umask: this.config.get('umask')
umask: this.opts.umask
}), e => {
this.log.verbose('buildTree', `error linking ${spec}: ${e.message} ${e.stack}`)
})
Expand Down Expand Up @@ -346,18 +381,21 @@ class Installer {

runScript (stage, pkg, pkgPath) {
const start = Date.now()
if (!this.config.get('ignore-scripts')) {
if (!this.opts['ignore-scripts']) {
// TODO(mikesherov): remove pkg._id when npm-lifecycle no longer relies on it
pkg._id = pkg.name + '@' + pkg.version
const opts = this.config.toLifecycle()
return BB.resolve(lifecycle(pkg, stage, pkgPath, opts))
.tap(() => { this.timings.scripts += Date.now() - start })
return BB.resolve(lifecycle(
pkg, stage, pkgPath, LifecycleOpts(this.opts).concat({
// TODO: can be removed once npm-lifecycle is updated to modern
// config practices.
config: this.opts
}))
).tap(() => { this.timings.scripts += Date.now() - start })
}
return BB.resolve()
}
}
module.exports = Installer
module.exports.CipmConfig = require('./lib/config/npm-config.js').CipmConfig

function mark (tree, failed) {
const liveDeps = new Set()
Expand Down
29 changes: 0 additions & 29 deletions lib/config/lifecycle-opts.js

This file was deleted.

72 changes: 42 additions & 30 deletions lib/config/npm-config.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,22 @@
'use strict'

const BB = require('bluebird')
const lifecycleOpts = require('./lifecycle-opts.js')
const pacoteOpts = require('./pacote-opts.js')
const protoduck = require('protoduck')
const spawn = require('child_process').spawn

class NpmConfig extends Map {}
const fs = require('fs')
const figgyPudding = require('figgy-pudding')
const ini = require('ini')
const path = require('path')
const spawn = require('child_process').spawn

const CipmConfig = protoduck.define({
get: [],
set: [],
toPacote: [],
toLifecycle: []
}, {
name: 'CipmConfig'
})
module.exports.CipmConfig = CipmConfig
const readFileAsync = BB.promisify(fs.readFile)

CipmConfig.impl(NpmConfig, {
get: Map.prototype.get,
set: Map.prototype.set,
toPacote (opts) {
return pacoteOpts(this, opts)
},
toLifecycle () {
return lifecycleOpts(this)
}
const NpmConfig = figgyPudding({
cache: { default: '' },
then: {},
userconfig: {}
})

module.exports.fromObject = fromObj
function fromObj (obj) {
const map = new NpmConfig()
Object.keys(obj).forEach(k => map.set(k, obj[k]))
return map
}
module.exports = NpmConfig

module.exports.fromNpm = getNpmConfig
function getNpmConfig (argv) {
Expand Down Expand Up @@ -62,11 +44,41 @@ function getNpmConfig (argv) {
reject(new Error('`npm` command not found. Please ensure you have npm@5.4.0 or later installed.'))
} else {
try {
resolve(fromObj(JSON.parse(stdout)))
resolve(JSON.parse(stdout))
} catch (e) {
reject(new Error('`npm config ls --json` failed to output json. Please ensure you have npm@5.4.0 or later installed.'))
}
}
})
}).then(opts => {
return BB.all(
process.cwd().split(path.sep).reduce((acc, next) => {
acc.path = path.join(acc.path, next)
acc.promises.push(maybeReadIni(path.join(acc.path, '.npmrc')))
acc.promises.push(maybeReadIni(path.join(acc.path, 'npmrc')))
return acc
}, {
path: '',
promises: []
}).promises.concat(
opts.userconfig ? maybeReadIni(opts.userconfig) : {}
)
).then(configs => NpmConfig(...configs, opts))
}).then(opts => {
if (opts.cache) {
return opts.concat({ cache: path.join(opts.cache, '_cacache') })
} else {
return opts
}
})
}

function maybeReadIni (f) {
return readFileAsync(f, 'utf8').catch(err => {
if (err.code === 'ENOENT') {
return ''
} else {
throw err
}
}).then(ini.parse)
}

0 comments on commit 617a39d

Please sign in to comment.