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

Commit

Permalink
feat(config): allow injection of npm configs (#35)
Browse files Browse the repository at this point in the history
  • Loading branch information
zkat authored Jan 7, 2018
1 parent 856f772 commit 1f5694b
Show file tree
Hide file tree
Showing 11 changed files with 244 additions and 250 deletions.
18 changes: 12 additions & 6 deletions bin/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

'use strict'

const config = require('../lib/config/npm-config.js')
const yargs = require('yargs')
const Installer = require('../index.js')

Expand All @@ -12,13 +13,18 @@ if (require.main === module) {
}

function cliMain () {
return new Installer(parseArgs()).run().then(details => {
console.error(`added ${details.pkgCount} packages in ${
parseArgs()
return config.fromNpm(process.argv)
.then(c => new Installer({
config: c,
log: require('npmlog')
}).run())
.then(
details => console.error(`added ${details.pkgCount} packages in ${
details.runTime / 1000
}s`)
}, err => {
console.error(`Error!\n${err.message}\n${err.stack}`)
})
}s`),
err => console.error(`cipm failed:\n${err.message}\n${err.stack}`)
)
}

function parseArgs () {
Expand Down
81 changes: 45 additions & 36 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,59 +3,60 @@
const BB = require('bluebird')

const binLink = require('bin-links')
const config = require('./lib/config.js')
const extract = require('./lib/extract.js')
const fs = require('graceful-fs')
const getPrefix = require('find-npm-prefix')
const lifecycle = require('npm-lifecycle')
const lockVerify = require('lock-verify')
const logi = require('npm-logical-tree')
const npmlog = require('npmlog')
const path = require('path')
const readPkgJson = BB.promisify(require('read-package-json'))
const rimraf = BB.promisify(require('rimraf'))

const readFileAsync = BB.promisify(fs.readFile)
const statAsync = BB.promisify(fs.stat)

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

// Stats
this.startTime = Date.now()
this.runTime = 0
this.pkgCount = 0

// Misc
this.log = npmlog
this.log = this.opts.log || require('npmlog')
this.pkg = null
this.tree = null
this.failedDeps = new Set()
}

run () {
const prefix = this.config.get('prefix')
return this.prepare()
.then(() => this.extractTree(this.tree))
.then(() => this.buildTree(this.tree))
.then(() => this.garbageCollect(this.tree))
.then(() => this.runScript('prepublish', this.pkg, this.prefix))
.then(() => this.runScript('prepare', this.pkg, this.prefix))
.then(() => {
extract.stopWorkers()
this.runTime = Date.now() - this.startTime
return this
}, e => {
extract.stopWorkers()
throw e
})
.then(() => this.runScript('prepublish', this.pkg, prefix))
.then(() => this.runScript('prepare', this.pkg, prefix))
.then(() => this.teardown())
.then(() => { this.runTime = Date.now() - this.startTime })
.catch(err => { this.teardown(); throw err })
.then(() => this)
}

prepare () {
extract.startWorkers()

return (
this.opts.prefix
? BB.resolve(this.opts.prefix)
this.config.get('prefix') && this.config.get('global')
? BB.resolve(this.config.get('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(/--prefix/i))
? this.config.get('prefix')
: getPrefix(process.cwd())
)
.then(prefix => {
Expand All @@ -70,22 +71,27 @@ class Installer {
}
)
})
.then(() => config(this.prefix, process.argv, this.pkg))
.then(conf => {
this.config = conf
.then(() => statAsync(
path.join(this.config.get('prefix'), 'node_modules')
).catch(err => { if (err.code !== 'ENOENT') { throw err } }))
.then(stat => {
return BB.join(
this.checkLock(),
rimraf(path.join(this.prefix, 'node_modules'))
stat && rimraf(path.join(this.config.get('prefix'), 'node_modules'))
)
}).then(() => {
// This needs to happen -after- we've done checkLock()
this.tree = logi(this.pkg, this.pkg._shrinkwrap)
})
}

teardown () {
return extract.stopWorkers()
}

checkLock () {
const pkg = this.pkg
const prefix = this.prefix
const prefix = this.config.get('prefix')
if (!pkg._shrinkwrap || !pkg._shrinkwrap.lockfileVersion) {
return BB.reject(
new Error(`cipm can only install packages with an existing package-lock.json or npm-shrinkwrap.json with lockfileVersion >= 1. Run an install with npm@5 or later to generate it, then try again.`)
Expand All @@ -108,40 +114,39 @@ class Installer {

extractTree (tree) {
return tree.forEachAsync((dep, next) => {
if (dep.dev && this.config.config.production) { return }
const depPath = dep.path(this.prefix)
if (dep.dev && this.config.get('production')) { return }
const depPath = dep.path(this.config.get('prefix'))
// Process children first, then extract this child
return BB.join(
!dep.isRoot && extract.child(dep.name, dep, depPath, this.config),
!dep.isRoot &&
extract.child(dep.name, dep, depPath, this.config, this.opts),
next()
).then(() => { !dep.isRoot && this.pkgCount++ })
}, {concurrency: 50, Promise: BB})
}

buildTree (tree) {
return tree.forEachAsync((dep, next) => {
if (dep.dev && this.config.config.production) { return }
const depPath = dep.path(this.prefix)
if (dep.dev && this.config.get('production')) { return }
const depPath = dep.path(this.config.get('prefix'))
return readPkgJson(path.join(depPath, 'package.json'))
.then(pkg => {
return this.runScript('preinstall', pkg, depPath)
.then(next) // build children between preinstall and binLink
// Don't link root bins
.then(() => !dep.isRoot && binLink(pkg, depPath, false, {
force: this.config.config.force,
ignoreScripts: this.config.lifecycleOpts.ignoreScripts,
force: this.config.get('force'),
ignoreScripts: this.config.get('ignore-scripts'),
log: this.log,
name: pkg.name,
pkgId: pkg.name + '@' + pkg.version,
prefix: this.prefix,
prefixes: [this.prefix],
umask: this.config.config.umask
prefix: this.config.get('prefix'),
prefixes: [this.config.get('prefix')],
umask: this.config.get('umask')
}), e => {})
.then(() => this.runScript('install', pkg, depPath))
.then(() => this.runScript('postinstall', pkg, depPath))
.then(() => {
return this
})
.then(() => this)
.catch(e => {
if (dep.optional) {
this.failedDeps.add(dep)
Expand All @@ -158,7 +163,7 @@ class Installer {
if (!this.failedDeps.size) { return }
return sweep(
tree,
this.prefix,
this.config.get('prefix'),
mark(tree, this.failedDeps)
)
.then(purged => {
Expand All @@ -168,15 +173,19 @@ class Installer {
}

runScript (stage, pkg, pkgPath) {
if (!this.config.lifecycleOpts.ignoreScripts && pkg.scripts && pkg.scripts[stage]) {
if (
!this.config.get('ignore-scripts') && pkg.scripts && pkg.scripts[stage]
) {
// TODO(mikesherov): remove pkg._id when npm-lifecycle no longer relies on it
pkg._id = pkg.name + '@' + pkg.version
return lifecycle(pkg, stage, pkgPath, this.config.lifecycleOpts)
const opts = this.config.toLifecycle()
return lifecycle(pkg, stage, pkgPath, opts)
}
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
87 changes: 0 additions & 87 deletions lib/config.js

This file was deleted.

29 changes: 29 additions & 0 deletions lib/config/lifecycle-opts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
'use strict'

const log = require('npmlog')

module.exports = lifecycleOpts
function lifecycleOpts (opts) {
const objConfig = {}
for (const key of opts.keys()) {
const val = opts.get(key)
if (val != null) {
objConfig[key] = val
}
}
return {
config: objConfig,
scriptShell: opts.get('script-shell'),
force: opts.get('force'),
user: opts.get('user'),
group: opts.get('group'),
ignoreScripts: opts.get('ignore-scripts'),
ignorePrepublish: opts.get('ignore-prepublish'),
scriptsPrependNodePath: opts.get('scripts-prepend-node-path'),
unsafePerm: opts.get('unsafe-perm'),
log,
dir: opts.get('prefix'),
failOk: false,
production: opts.get('production')
}
}
Loading

0 comments on commit 1f5694b

Please sign in to comment.