diff options
Diffstat (limited to 'deps/npm/lib/install.js')
-rw-r--r-- | deps/npm/lib/install.js | 103 |
1 files changed, 78 insertions, 25 deletions
diff --git a/deps/npm/lib/install.js b/deps/npm/lib/install.js index 029f806f83..42906f2394 100644 --- a/deps/npm/lib/install.js +++ b/deps/npm/lib/install.js @@ -106,6 +106,8 @@ var mkdirp = require('mkdirp') var rimraf = require('rimraf') var iferr = require('iferr') var validate = require('aproba') +var uniq = require('lodash.uniq') +var Bluebird = require('bluebird') // npm internal utils var npm = require('./npm.js') @@ -132,6 +134,7 @@ var decomposeActions = require('./install/decompose-actions.js') var validateTree = require('./install/validate-tree.js') var validateArgs = require('./install/validate-args.js') var saveRequested = require('./install/save.js').saveRequested +var saveShrinkwrap = require('./install/save.js').saveShrinkwrap var getSaveType = require('./install/save.js').getSaveType var doSerialActions = require('./install/actions.js').doSerial var doReverseSerialActions = require('./install/actions.js').doReverseSerial @@ -199,8 +202,9 @@ function install (where, args, cb) { new Installer(where, dryrun, args).run(cb) } -function Installer (where, dryrun, args) { - validate('SBA', arguments) +function Installer (where, dryrun, args, opts) { + validate('SBA|SBAO', arguments) + if (!opts) opts = {} this.where = where this.dryrun = dryrun this.args = args @@ -215,23 +219,40 @@ function Installer (where, dryrun, args) { this.progress = {} this.noPackageJsonOk = !!args.length this.topLevelLifecycles = !args.length - this.dev = npm.config.get('dev') || (!/^prod(uction)?$/.test(npm.config.get('only')) && !npm.config.get('production')) || /^dev(elopment)?$/.test(npm.config.get('only')) - this.prod = !/^dev(elopment)?$/.test(npm.config.get('only')) - this.rollback = npm.config.get('rollback') - this.link = npm.config.get('link') - this.global = this.where === path.resolve(npm.globalDir, '..') + + const dev = npm.config.get('dev') + const only = npm.config.get('only') + const onlyProd = /^prod(uction)?$/.test(only) + const onlyDev = /^dev(elopment)?$/.test(only) + const prod = npm.config.get('production') + this.dev = opts.dev != null ? opts.dev : dev || (!onlyProd && !prod) || onlyDev + this.prod = opts.prod != null ? opts.prod : !onlyDev + + this.packageLockOnly = opts.packageLockOnly != null + ? opts.packageLockOnly : npm.config.get('package-lock-only') + this.rollback = opts.rollback != null ? opts.rollback : npm.config.get('rollback') + this.link = opts.link != null ? opts.link : npm.config.get('link') + this.saveOnlyLock = opts.saveOnlyLock + this.global = opts.global != null ? opts.global : this.where === path.resolve(npm.globalDir, '..') this.started = Date.now() } Installer.prototype = {} Installer.prototype.run = function (_cb) { - validate('F', arguments) - - var cb = function (err) { - saveMetrics(!err) - return _cb.apply(this, arguments) + validate('F|', arguments) + + var result + var cb + if (_cb) { + cb = function (err) { + saveMetrics(!err) + return _cb.apply(this, arguments) + } + } else { + result = new Promise((resolve, reject) => { + cb = (err, value) => err ? reject(err) : resolve(value) + }) } - // FIXME: This is bad and I should feel bad. // lib/install needs to have some way of sharing _limited_ // state with the things it calls. Passing the object is too @@ -274,7 +295,11 @@ Installer.prototype.run = function (_cb) { [this, this.debugActions, 'diffTrees', 'differences'], [this, this.debugActions, 'decomposeActions', 'todo']) - if (!this.dryrun) { + + if (this.packageLockOnly) { + postInstallSteps.push( + [this, this.saveToDependencies]) + } else if (!this.dryrun) { installSteps.push( [this.newTracker(log, 'executeActions', 8)], [this, this.executeActions], @@ -296,6 +321,7 @@ Installer.prototype.run = function (_cb) { // until after we extract them [this, (next) => { computeMetadata(this.idealTree); next() }], [this, this.pruneIdealTree], + [this, this.debugLogicalTree, 'saveTree', 'idealTree'], [this, this.saveToDependencies]) } } @@ -319,6 +345,7 @@ Installer.prototype.run = function (_cb) { cb(installEr || postInstallEr, self.getInstalledModules(), self.idealTree) }) }) + return result } Installer.prototype.loadArgMetadata = function (next) { @@ -544,17 +571,15 @@ Installer.prototype.executeActions = function (cb) { Installer.prototype.rollbackFailedOptional = function (staging, actionsToRun, cb) { if (!this.rollback) return cb() - var failed = actionsToRun.map(function (action) { + var failed = uniq(actionsToRun.map(function (action) { return action[1] }).filter(function (pkg) { return pkg.failed && pkg.rollback - }) + })) var top = this.currentTree && this.currentTree.path - asyncMap(failed, function (pkg, next) { - asyncMap(pkg.rollback, function (rollback, done) { - rollback(top, staging, pkg, done) - }, next) - }, cb) + Bluebird.map(failed, (pkg) => { + return Bluebird.map(pkg.rollback, (rollback) => rollback(top, staging, pkg)) + }).asCallback(cb) } Installer.prototype.commit = function (staging, actionsToRun, cb) { @@ -609,7 +634,11 @@ Installer.prototype.saveToDependencies = function (cb) { validate('F', arguments) if (this.failing) return cb() log.silly('install', 'saveToDependencies') - saveRequested(this.idealTree, cb) + if (this.saveOnlyLock) { + saveShrinkwrap(this.idealTree, cb) + } else { + saveRequested(this.idealTree, cb) + } } Installer.prototype.readGlobalPackageData = function (cb) { @@ -747,6 +776,8 @@ Installer.prototype.printInstalledForHuman = function (diffs, cb) { var moved = 0 diffs.forEach(function (action) { var mutation = action[0] + var pkg = action[1] + if (pkg.failed) return if (mutation === 'remove') { ++removed } else if (mutation === 'move') { @@ -885,11 +916,33 @@ Installer.prototype.debugActions = function (name, actionListName, cb) { // to define the arguments for use by chain before the property exists yet. Installer.prototype.debugTree = function (name, treeName, cb) { validate('SSF', arguments) - log.silly(name, this.prettify(this[treeName]).trim()) + log.silly(name, this.archyDebugTree(this[treeName]).trim()) + cb() +} + +Installer.prototype.archyDebugTree = function (tree) { + validate('O', arguments) + var seen = new Set() + function byName (aa, bb) { + return packageId(aa).localeCompare(packageId(bb)) + } + function expandTree (tree) { + seen.add(tree) + return { + label: packageId(tree), + nodes: tree.children.filter((tree) => { return !seen.has(tree) && !tree.removed }).sort(byName).map(expandTree) + } + } + return archy(expandTree(tree), '', { unicode: npm.config.get('unicode') }) +} + +Installer.prototype.debugLogicalTree = function (name, treeName, cb) { + validate('SSF', arguments) + this[treeName] && log.silly(name, this.archyDebugLogicalTree(this[treeName]).trim()) cb() } -Installer.prototype.prettify = function (tree) { +Installer.prototype.archyDebugLogicalTree = function (tree) { validate('O', arguments) var seen = new Set() function byName (aa, bb) { @@ -899,7 +952,7 @@ Installer.prototype.prettify = function (tree) { seen.add(tree) return { label: packageId(tree), - nodes: tree.children.filter((tree) => { return !seen.has(tree) && !tree.removed && !tree.failed }).sort(byName).map(expandTree) + nodes: tree.requires.filter((tree) => { return !seen.has(tree) && !tree.removed }).sort(byName).map(expandTree) } } return archy(expandTree(tree), '', { unicode: npm.config.get('unicode') }) |