diff options
author | Rebecca Turner <me@re-becca.org> | 2017-04-12 21:47:49 -0700 |
---|---|---|
committer | Jeremiah Senkpiel <fishrock123@rocketmail.com> | 2017-04-25 10:52:01 -0400 |
commit | 00842604483e4c2e622dfdb3a97440e07646158f (patch) | |
tree | f3346902636a44b6037652523767636bf7e4f2c9 /deps/npm/lib | |
parent | 061c5da010e0d249379618382a499840d38247b8 (diff) | |
download | android-node-v8-00842604483e4c2e622dfdb3a97440e07646158f.tar.gz android-node-v8-00842604483e4c2e622dfdb3a97440e07646158f.tar.bz2 android-node-v8-00842604483e4c2e622dfdb3a97440e07646158f.zip |
deps: upgrade npm to 4.5.0
PR-URL: https://github.com/nodejs/node/pull/12480
Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
Diffstat (limited to 'deps/npm/lib')
35 files changed, 546 insertions, 351 deletions
diff --git a/deps/npm/lib/adduser.js b/deps/npm/lib/adduser.js index 7f3975175a..0aac6b7fbb 100644 --- a/deps/npm/lib/adduser.js +++ b/deps/npm/lib/adduser.js @@ -2,11 +2,7 @@ module.exports = adduser var log = require('npmlog') var npm = require('./npm.js') -var read = require('read') -var userValidate = require('npm-user-validate') -var output = require('./utils/output') var usage = require('./utils/usage') -var chain = require('slide').chain var crypto try { @@ -15,7 +11,7 @@ try { adduser.usage = usage( 'adduser', - 'npm adduser [--registry=url] [--scope=@orgname] [--always-auth]' + 'npm adduser [--registry=url] [--scope=@orgname] [--auth-type=legacy] [--always-auth]' ) function adduser (args, cb) { @@ -25,154 +21,29 @@ function adduser (args, cb) { )) } - var creds = npm.config.getCredentialsByURI(npm.config.get('registry')) - var c = { - u: creds.username || '', - p: creds.password || '', - e: creds.email || '' - } - var u = {} - - log.disableProgress() - chain([ - [readUsername, c, u], - [readPassword, c, u], - [readEmail, c, u], - [save, c, u] - ], cb) -} - -function readUsername (c, u, cb) { - var v = userValidate.username - read({prompt: 'Username: ', default: c.u || ''}, function (er, un) { - if (er) { - return cb(er.message === 'cancelled' ? er.message : er) - } - - // make sure it's valid. we have to do this here, because - // couchdb will only ever say "bad password" with a 401 when - // you try to PUT a _users record that the validate_doc_update - // rejects for *any* reason. - - if (!un) { - return readUsername(c, u, cb) - } - - var error = v(un) - if (error) { - log.warn(error.message) - return readUsername(c, u, cb) - } - - c.changed = c.u !== un - u.u = un - cb(er) - }) -} - -function readPassword (c, u, cb) { - var v = userValidate.pw - - var prompt - if (c.p && !c.changed) { - prompt = 'Password: (or leave unchanged) ' - } else { - prompt = 'Password: ' - } - - read({prompt: prompt, silent: true}, function (er, pw) { - if (er) { - return cb(er.message === 'cancelled' ? er.message : er) - } - - if (!c.changed && pw === '') { - // when the username was not changed, - // empty response means "use the old value" - pw = c.p - } - - if (!pw) { - return readPassword(c, u, cb) - } - - var error = v(pw) - if (error) { - log.warn(error.message) - return readPassword(c, u, cb) - } - - c.changed = c.changed || c.p !== pw - u.p = pw - cb(er) - }) -} - -function readEmail (c, u, cb) { - var v = userValidate.email - var r = { prompt: 'Email: (this IS public) ', default: c.e || '' } - read(r, function (er, em) { - if (er) { - return cb(er.message === 'cancelled' ? er.message : er) - } - - if (!em) { - return readEmail(c, u, cb) - } - - var error = v(em) - if (error) { - log.warn(error.message) - return readEmail(c, u, cb) - } - - u.e = em - cb(er) - }) -} - -function save (c, u, cb) { - // save existing configs, but yank off for this PUT - var uri = npm.config.get('registry') + var registry = npm.config.get('registry') var scope = npm.config.get('scope') + var creds = npm.config.getCredentialsByURI(npm.config.get('registry')) - // there may be a saved scope and no --registry (for login) if (scope) { var scopedRegistry = npm.config.get(scope + ':registry') var cliRegistry = npm.config.get('registry', 'cli') - if (scopedRegistry && !cliRegistry) uri = scopedRegistry - } - - var params = { - auth: { - username: u.u, - password: u.p, - email: u.e - } + if (scopedRegistry && !cliRegistry) registry = scopedRegistry } - npm.registry.adduser(uri, params, function (er, doc) { - if (er) return cb(er) - - // don't want this polluting the configuration - npm.config.del('_token', 'user') - if (scope) npm.config.set(scope + ':registry', uri, 'user') + log.disableProgress() - if (doc && doc.token) { - npm.config.setCredentialsByURI(uri, { - token: doc.token - }) - } else { - npm.config.setCredentialsByURI(uri, { - username: u.u, - password: u.p, - email: u.e, - alwaysAuth: npm.config.get('always-auth') - }) - } + try { + var auth = require('./auth/' + npm.config.get('auth-type')) + } catch (e) { + return cb(new Error('no such auth module')) + } + auth.login(creds, registry, scope, function (err, newCreds) { + if (err) return cb(err) - log.info('adduser', 'Authorized user %s', u.u) - var scopeMessage = scope ? ' to scope ' + scope : '' - output('Logged in as %s%s on %s.', u.u, scopeMessage, uri) + npm.config.del('_token', 'user') // prevent legacy pollution + if (scope) npm.config.set(scope + ':registry', registry, 'user') + npm.config.setCredentialsByURI(registry, newCreds) npm.config.save('user', cb) }) } diff --git a/deps/npm/lib/auth/legacy.js b/deps/npm/lib/auth/legacy.js new file mode 100644 index 0000000000..2fa4a26e35 --- /dev/null +++ b/deps/npm/lib/auth/legacy.js @@ -0,0 +1,142 @@ +var log = require('npmlog') +var npm = require('../npm.js') +var read = require('read') +var userValidate = require('npm-user-validate') +var output = require('../utils/output') +var chain = require('slide').chain + +module.exports.login = function login (creds, registry, scope, cb) { + var c = { + u: creds.username || '', + p: creds.password || '', + e: creds.email || '' + } + var u = {} + + chain([ + [readUsername, c, u], + [readPassword, c, u], + [readEmail, c, u], + [save, c, u, registry, scope] + ], function (err, res) { + cb(err, res && res[res.length - 1]) + }) +} + +function readUsername (c, u, cb) { + var v = userValidate.username + read({prompt: 'Username: ', default: c.u || ''}, function (er, un) { + if (er) { + return cb(er.message === 'cancelled' ? er.message : er) + } + + // make sure it's valid. we have to do this here, because + // couchdb will only ever say "bad password" with a 401 when + // you try to PUT a _users record that the validate_doc_update + // rejects for *any* reason. + + if (!un) { + return readUsername(c, u, cb) + } + + var error = v(un) + if (error) { + log.warn(error.message) + return readUsername(c, u, cb) + } + + c.changed = c.u !== un + u.u = un + cb(er) + }) +} + +function readPassword (c, u, cb) { + var v = userValidate.pw + + var prompt + if (c.p && !c.changed) { + prompt = 'Password: (or leave unchanged) ' + } else { + prompt = 'Password: ' + } + + read({prompt: prompt, silent: true}, function (er, pw) { + if (er) { + return cb(er.message === 'cancelled' ? er.message : er) + } + + if (!c.changed && pw === '') { + // when the username was not changed, + // empty response means "use the old value" + pw = c.p + } + + if (!pw) { + return readPassword(c, u, cb) + } + + var error = v(pw) + if (error) { + log.warn(error.message) + return readPassword(c, u, cb) + } + + c.changed = c.changed || c.p !== pw + u.p = pw + cb(er) + }) +} + +function readEmail (c, u, cb) { + var v = userValidate.email + var r = { prompt: 'Email: (this IS public) ', default: c.e || '' } + read(r, function (er, em) { + if (er) { + return cb(er.message === 'cancelled' ? er.message : er) + } + + if (!em) { + return readEmail(c, u, cb) + } + + var error = v(em) + if (error) { + log.warn(error.message) + return readEmail(c, u, cb) + } + + u.e = em + cb(er) + }) +} + +function save (c, u, registry, scope, cb) { + var params = { + auth: { + username: u.u, + password: u.p, + email: u.e + } + } + npm.registry.adduser(registry, params, function (er, doc) { + if (er) return cb(er) + + var newCreds = (doc && doc.token) + ? { + token: doc.token + } + : { + username: u.u, + password: u.p, + email: u.e, + alwaysAuth: npm.config.get('always-auth') + } + + log.info('adduser', 'Authorized user %s', u.u) + var scopeMessage = scope ? ' to scope ' + scope : '' + output('Logged in as %s%s on %s.', u.u, scopeMessage, registry) + + cb(null, newCreds) + }) +} diff --git a/deps/npm/lib/auth/oauth.js b/deps/npm/lib/auth/oauth.js new file mode 100644 index 0000000000..1cb3ffec6f --- /dev/null +++ b/deps/npm/lib/auth/oauth.js @@ -0,0 +1,7 @@ +var ssoAuth = require('./sso') +var npm = require('../npm') + +module.exports.login = function login () { + npm.config.set('sso-type', 'oauth') + ssoAuth.login.apply(this, arguments) +} diff --git a/deps/npm/lib/auth/saml.js b/deps/npm/lib/auth/saml.js new file mode 100644 index 0000000000..ae92ea5bbf --- /dev/null +++ b/deps/npm/lib/auth/saml.js @@ -0,0 +1,7 @@ +var ssoAuth = require('./sso') +var npm = require('../npm') + +module.exports.login = function login () { + npm.config.set('sso-type', 'saml') + ssoAuth.login.apply(this, arguments) +} diff --git a/deps/npm/lib/auth/sso.js b/deps/npm/lib/auth/sso.js new file mode 100644 index 0000000000..faffe2fa59 --- /dev/null +++ b/deps/npm/lib/auth/sso.js @@ -0,0 +1,59 @@ +var log = require('npmlog') +var npm = require('../npm.js') +var output = require('../utils/output') +var opener = require('opener') + +module.exports.login = function login (creds, registry, scope, cb) { + var ssoType = npm.config.get('sso-type') + if (!ssoType) { return cb(new Error('Missing option: sso-type')) } + + var params = { + // We're reusing the legacy login endpoint, so we need some dummy + // stuff here to pass validation. They're never used. + auth: { + username: 'npm_' + ssoType + '_auth_dummy_user', + password: 'placeholder', + email: 'support@npmjs.com', + authType: ssoType + } + } + npm.registry.adduser(registry, params, function (er, doc) { + if (er) return cb(er) + if (!doc || !doc.token) return cb(new Error('no SSO token returned')) + if (!doc.sso) return cb(new Error('no SSO URL returned by services')) + + output('If your browser doesn\'t open, visit ' + + doc.sso + + ' to complete authentication') + opener(doc.sso, { command: npm.config.get('browser') }, function () { + pollForSession(registry, doc.token, function (err, username) { + if (err) return cb(err) + + log.info('adduser', 'Authorized user %s', username) + var scopeMessage = scope ? ' to scope ' + scope : '' + output('Logged in as %s%s on %s.', username, scopeMessage, registry) + + cb(null, { token: doc.token }) + }) + }) + }) +} + +function pollForSession (registry, token, cb) { + log.info('adduser', 'Polling for validated SSO session') + npm.registry.whoami(registry, { + auth: { + token: token + } + }, function (er, username) { + if (er && er.statusCode !== 401) { + cb(er) + } else if (!username) { + setTimeout(function () { + pollForSession(registry, token, cb) + }, npm.config.get('sso-poll-frequency')) + } else { + cb(null, username) + } + }) +} diff --git a/deps/npm/lib/bugs.js b/deps/npm/lib/bugs.js index 003ce7f8cb..5f166c33f6 100644 --- a/deps/npm/lib/bugs.js +++ b/deps/npm/lib/bugs.js @@ -19,7 +19,7 @@ bugs.completion = function (opts, cb) { function bugs (args, cb) { var n = args.length ? args[0] : '.' - fetchPackageMetadata(n, '.', function (er, d) { + fetchPackageMetadata(n, '.', {fullMetadata: true}, function (er, d) { if (er) return cb(er) var url = d.bugs && ((typeof d.bugs === 'string') ? d.bugs : d.bugs.url) diff --git a/deps/npm/lib/config/core.js b/deps/npm/lib/config/core.js index b833b75409..15a1674b3d 100644 --- a/deps/npm/lib/config/core.js +++ b/deps/npm/lib/config/core.js @@ -208,7 +208,7 @@ inherits(Conf, CC) function Conf (base) { if (!(this instanceof Conf)) return new Conf(base) - CC.apply(this) + CC.call(this) if (base) { if (base instanceof Conf) { diff --git a/deps/npm/lib/config/defaults.js b/deps/npm/lib/config/defaults.js index a79c8a0fa0..96499d1718 100644 --- a/deps/npm/lib/config/defaults.js +++ b/deps/npm/lib/config/defaults.js @@ -108,6 +108,7 @@ Object.defineProperty(exports, 'defaults', {get: function () { access: null, 'always-auth': false, also: null, + 'auth-type': 'legacy', 'bin-links': true, browser: null, @@ -148,6 +149,7 @@ Object.defineProperty(exports, 'defaults', {get: function () { 'global-style': false, group: process.platform === 'win32' ? 0 : process.env.SUDO_GID || (process.getgid && process.getgid()), + 'ham-it-up': false, heading: 'npm', 'if-present': false, 'ignore-scripts': false, @@ -168,7 +170,7 @@ Object.defineProperty(exports, 'defaults', {get: function () { long: false, maxsockets: 50, message: '%s', - 'metrics-registry': 'https://registry.npmjs.org/', + 'metrics-registry': null, 'node-version': process.version, 'onload-script': false, only: null, @@ -203,6 +205,8 @@ Object.defineProperty(exports, 'defaults', {get: function () { shell: osenv.shell(), shrinkwrap: true, 'sign-git-tag': false, + 'sso-poll-frequency': 500, + 'sso-type': 'oauth', 'strict-ssl': true, tag: 'latest', 'tag-version-prefix': 'v', @@ -231,6 +235,7 @@ exports.types = { access: [null, 'restricted', 'public'], 'always-auth': Boolean, also: [null, 'dev', 'development'], + 'auth-type': ['legacy', 'sso', 'saml', 'oauth'], 'bin-links': Boolean, browser: [null, String], ca: [null, String, Array], @@ -262,6 +267,7 @@ exports.types = { group: [Number, String], 'https-proxy': [null, url], 'user-agent': String, + 'ham-it-up': Boolean, 'heading': String, 'if-present': Boolean, 'ignore-scripts': Boolean, @@ -284,7 +290,7 @@ exports.types = { long: Boolean, maxsockets: Number, message: String, - 'metrics-registry': String, + 'metrics-registry': [null, String], 'node-version': [null, semver], 'onload-script': [null, String], only: [null, 'dev', 'development', 'prod', 'production'], @@ -314,6 +320,8 @@ exports.types = { shell: String, shrinkwrap: Boolean, 'sign-git-tag': Boolean, + 'sso-poll-frequency': Number, + 'sso-type': [null, 'oauth', 'saml'], 'strict-ssl': Boolean, tag: String, tmp: path, diff --git a/deps/npm/lib/docs.js b/deps/npm/lib/docs.js index 19dcce163c..2248702a46 100644 --- a/deps/npm/lib/docs.js +++ b/deps/npm/lib/docs.js @@ -33,7 +33,7 @@ function docs (args, cb) { function getDoc (project, cb) { log.silly('getDoc', project) - fetchPackageMetadata(project, '.', function (er, d) { + fetchPackageMetadata(project, '.', {fullMetadata: true}, function (er, d) { if (er) return cb(er) var url = d.homepage if (!url) url = 'https://www.npmjs.org/package/' + d.name diff --git a/deps/npm/lib/doctor/check-files-permission.js b/deps/npm/lib/doctor/check-files-permission.js index ac3bb40bc6..74393596f6 100644 --- a/deps/npm/lib/doctor/check-files-permission.js +++ b/deps/npm/lib/doctor/check-files-permission.js @@ -34,7 +34,7 @@ function checkFilesPermission (root, mask, cb) { function checkFile (f, next) { var file = path.join(root, f) tracker.silly('checkFilePermissions', f) - fs.stat(file, function (e, stat) { + fs.lstat(file, function (e, stat) { tracker.completeWork(1) if (e) return next(e) if (!stat.isFile()) return next() diff --git a/deps/npm/lib/doctor/get-latest-npm-version.js b/deps/npm/lib/doctor/get-latest-npm-version.js index 4df0fee0fa..aba9b773cd 100644 --- a/deps/npm/lib/doctor/get-latest-npm-version.js +++ b/deps/npm/lib/doctor/get-latest-npm-version.js @@ -4,7 +4,7 @@ var fetchPackageMetadata = require('../fetch-package-metadata') function getLatestNpmVersion (cb) { var tracker = log.newItem('getLatestNpmVersion', 1) tracker.info('getLatestNpmVersion', 'Getting npm package information') - fetchPackageMetadata('npm@latest', '.', function (e, d) { + fetchPackageMetadata('npm@latest', '.', {fullMetadata: true}, function (e, d) { tracker.finish() cb(e, d.version) }) diff --git a/deps/npm/lib/fetch-package-metadata.js b/deps/npm/lib/fetch-package-metadata.js index bd6e47e17c..ae22004e5b 100644 --- a/deps/npm/lib/fetch-package-metadata.js +++ b/deps/npm/lib/fetch-package-metadata.js @@ -16,6 +16,7 @@ var clone = require('lodash.clonedeep') var validate = require('aproba') var unpipe = require('unpipe') var normalizePackageData = require('normalize-package-data') +var limit = require('call-limit') var npm = require('./npm.js') var mapToRegistry = require('./utils/map-to-registry.js') @@ -39,12 +40,16 @@ function andLogAndFinish (spec, tracker, done) { } } -module.exports = function fetchPackageMetadata (spec, where, tracker, done) { +module.exports = limit(fetchPackageMetadata, npm.limit.fetch) + +function fetchPackageMetadata (spec, where, opts, done) { + validate('SSOF|SSFZ|OSOF|OSFZ', [spec, where, opts, done]) + if (!done) { - done = tracker || where - tracker = null - if (done === where) where = null + done = opts + opts = {} } + var tracker = opts.tracker if (typeof spec === 'object') { var dep = spec spec = dep.raw @@ -53,11 +58,11 @@ module.exports = function fetchPackageMetadata (spec, where, tracker, done) { if (!dep) { log.silly('fetchPackageMetaData', spec) return realizePackageSpecifier(spec, where, iferr(logAndFinish, function (dep) { - fetchPackageMetadata(dep, where, tracker, done) + fetchPackageMetadata(dep, where, {tracker: tracker}, done) })) } if (dep.type === 'version' || dep.type === 'range' || dep.type === 'tag') { - fetchNamedPackageData(dep, addRequestedAndFinish) + fetchNamedPackageData(dep, opts, addRequestedAndFinish) } else if (dep.type === 'directory') { fetchDirectoryPackageData(dep, where, addRequestedAndFinish) } else { @@ -105,14 +110,15 @@ function fetchDirectoryPackageData (dep, where, next) { var regCache = {} -function fetchNamedPackageData (dep, next) { - validate('OF', arguments) +function fetchNamedPackageData (dep, opts, next) { + validate('OOF', arguments) log.silly('fetchNamedPackageData', dep.name || dep.rawSpec) mapToRegistry(dep.name || dep.rawSpec, npm.config, iferr(next, function (url, auth) { if (regCache[url]) { pickVersionFromRegistryDocument(clone(regCache[url])) } else { - npm.registry.get(url, {auth: auth}, pulseTillDone('fetchMetadata', iferr(next, pickVersionFromRegistryDocument))) + var fullMetadata = opts.fullMetadata == null ? true : opts.fullMetadata + npm.registry.get(url, {auth: auth, fullMetadata: fullMetadata}, pulseTillDone('fetchMetadata', iferr(next, pickVersionFromRegistryDocument))) } function thenAddMetadata (pkg) { pkg._from = dep.raw @@ -180,6 +186,10 @@ function retryWithCached (pkg, asserter, next) { module.exports.addShrinkwrap = function addShrinkwrap (pkg, next) { validate('OF', arguments) if (pkg._shrinkwrap !== undefined) return next(null, pkg) + if (pkg._hasShrinkwrap === false) { + pkg._shrinkwrap = null + return next(null, pkg) + } if (retryWithCached(pkg, addShrinkwrap, next)) return pkg._shrinkwrap = null // FIXME: cache the shrinkwrap directly diff --git a/deps/npm/lib/install.js b/deps/npm/lib/install.js index 1b0601d9f4..43ba436630 100644 --- a/deps/npm/lib/install.js +++ b/deps/npm/lib/install.js @@ -508,7 +508,7 @@ Installer.prototype.rollbackFailedOptional = function (staging, actionsToRun, cb }).filter(function (pkg) { return pkg.failed && pkg.rollback }) - var top = this.currentTree.path + var top = this.currentTree && this.currentTree.path asyncMap(failed, function (pkg, next) { asyncMap(pkg.rollback, function (rollback, done) { rollback(top, staging, pkg, done) diff --git a/deps/npm/lib/install/action/extract.js b/deps/npm/lib/install/action/extract.js index 2c8a995af6..fd9562c184 100644 --- a/deps/npm/lib/install/action/extract.js +++ b/deps/npm/lib/install/action/extract.js @@ -3,7 +3,8 @@ var path = require('path') var iferr = require('iferr') var asyncMap = require('slide').asyncMap var fs = require('graceful-fs') -var rename = require('../../utils/rename.js') +var mkdirp = require('mkdirp') +var move = require('../../utils/move.js') var gentlyRm = require('../../utils/gently-rm.js') var updatePackageJson = require('../update-package-json') var npm = require('../../npm.js') @@ -11,6 +12,7 @@ var moduleName = require('../../utils/module-name.js') var packageId = require('../../utils/package-id.js') var cache = require('../../cache.js') var moduleStagingPath = require('../module-staging-path.js') +var readPackageJson = require('read-package-json') module.exports = function (staging, pkg, log, next) { log.silly('extract', packageId(pkg)) @@ -19,31 +21,45 @@ module.exports = function (staging, pkg, log, next) { var group = up ? null : npm.config.get('group') var extractTo = moduleStagingPath(staging, pkg) cache.unpack(pkg.package.name, pkg.package.version, extractTo, null, null, user, group, - andUpdatePackageJson(pkg, staging, extractTo, andStageBundledChildren(pkg, staging, extractTo, log, next))) + andUpdatePackageJson(pkg, staging, extractTo, + andStageBundledChildren(pkg, staging, extractTo, log, + andRemoveExtraneousBundles(extractTo, next)))) } function andUpdatePackageJson (pkg, staging, extractTo, next) { return iferr(next, function () { - updatePackageJson(pkg, extractTo, next) + readPackageJson(path.join(extractTo, 'package.json'), false, function (err, metadata) { + if (!err) { + // Copy _ keys (internal to npm) and any missing keys from the possibly incomplete + // registry metadata over to the full package metadata read off of disk. + Object.keys(pkg.package).forEach(function (key) { + if (key[0] === '_' || !(key in metadata)) metadata[key] = pkg.package[key] + }) + metadata.name = pkg.package.name // things go wrong if these don't match + pkg.package = metadata + } + updatePackageJson(pkg, extractTo, next) + }) }) } function andStageBundledChildren (pkg, staging, extractTo, log, next) { return iferr(next, function () { - for (var i = 0; i < pkg.children.length; ++i) { - var c = pkg.children[i] - if (!c.package.name) return next(c.error) - } + if (!pkg.package.bundleDependencies) return next() - asyncMap(pkg.children, andStageBundledModule(pkg, staging, extractTo), cleanupBundled) + asyncMap(pkg.children, andStageBundledModule(pkg, staging, extractTo), next) }) - function cleanupBundled () { +} + +function andRemoveExtraneousBundles (extractTo, next) { + return iferr(next, function () { gentlyRm(path.join(extractTo, 'node_modules'), next) - } + }) } function andStageBundledModule (bundler, staging, parentPath) { return function (child, next) { + if (child.error) return next(child.error) stageBundledModule(bundler, child, staging, parentPath, next) } } @@ -64,25 +80,36 @@ function stageBundledModule (bundler, child, staging, parentPath, next) { var stageFrom = path.join(parentPath, 'node_modules', child.package.name) var stageTo = moduleStagingPath(staging, child) - asyncMap(child.children, andStageBundledModule(bundler, staging, stageFrom), iferr(next, moveModule)) + return asyncMap(child.children, andStageBundledModule(bundler, staging, stageFrom), iferr(next, finishModule)) - function moveModule () { - if (child.fromBundle) { - return rename(stageFrom, stageTo, iferr(next, updateMovedPackageJson)) + function finishModule () { + // If we were the one's who bundled this moduleā¦ + if (child.fromBundle === bundler) { + return moveModule() } else { - return fs.stat(stageFrom, function (notExists, exists) { - if (exists) { - warn(bundler, 'EBUNDLEOVERRIDE', 'In ' + packageId(bundler) + - ' replacing bundled version of ' + moduleName(child) + - ' with ' + packageId(child)) - return gentlyRm(stageFrom, next) - } else { - return next() - } - }) + return checkForReplacement() } } + function moveModule () { + return mkdirp(path.dirname(stageTo), iferr(next, function () { + return move(stageFrom, stageTo, iferr(next, updateMovedPackageJson)) + })) + } + + function checkForReplacement () { + return fs.stat(stageFrom, function (notExists, exists) { + if (exists) { + warn(bundler, 'EBUNDLEOVERRIDE', 'In ' + packageId(bundler) + + ' replacing bundled version of ' + moduleName(child) + + ' with ' + packageId(child)) + return gentlyRm(stageFrom, next) + } else { + return next() + } + }) + } + function updateMovedPackageJson () { updatePackageJson(child, stageTo, next) } diff --git a/deps/npm/lib/install/action/finalize.js b/deps/npm/lib/install/action/finalize.js index acc11cc4a7..03a71f4cc0 100644 --- a/deps/npm/lib/install/action/finalize.js +++ b/deps/npm/lib/install/action/finalize.js @@ -4,7 +4,7 @@ var rimraf = require('rimraf') var fs = require('graceful-fs') var mkdirp = require('mkdirp') var asyncMap = require('slide').asyncMap -var rename = require('../../utils/rename.js') +var move = require('../../utils/move.js') var gentlyRm = require('../../utils/gently-rm') var moduleStagingPath = require('../module-staging-path.js') @@ -26,31 +26,31 @@ module.exports = function (staging, pkg, log, next) { function destStatted (doesNotExist) { if (doesNotExist) { - rename(extractedTo, pkg.path, whenMoved) + move(extractedTo, pkg.path, whenMoved) } else { moveAway() } } - function whenMoved (renameEr) { - if (!renameEr) return next() - if (renameEr.code !== 'ENOTEMPTY') return next(renameEr) + function whenMoved (moveEr) { + if (!moveEr) return next() + if (moveEr.code !== 'ENOTEMPTY' && moveEr.code !== 'EEXIST') return next(moveEr) moveAway() } function moveAway () { - rename(pkg.path, delpath, whenOldMovedAway) + move(pkg.path, delpath, whenOldMovedAway) } - function whenOldMovedAway (renameEr) { - if (renameEr) return next(renameEr) - rename(extractedTo, pkg.path, whenConflictMoved) + function whenOldMovedAway (moveEr) { + if (moveEr) return next(moveEr) + move(extractedTo, pkg.path, whenConflictMoved) } - function whenConflictMoved (renameEr) { + function whenConflictMoved (moveEr) { // if we got an error we'll try to put back the original module back, // succeed or fail though we want the original error that caused this - if (renameEr) return rename(delpath, pkg.path, function () { next(renameEr) }) + if (moveEr) return move(delpath, pkg.path, function () { next(moveEr) }) fs.readdir(path.join(delpath, 'node_modules'), makeTarget) } @@ -65,7 +65,7 @@ module.exports = function (staging, pkg, log, next) { asyncMap(files, function (file, done) { var from = path.join(delpath, 'node_modules', file) var to = path.join(pkg.path, 'node_modules', file) - rename(from, to, done) + move(from, to, done) }, cleanup) } diff --git a/deps/npm/lib/install/action/move.js b/deps/npm/lib/install/action/move.js index 3f29379f2b..07649c3556 100644 --- a/deps/npm/lib/install/action/move.js +++ b/deps/npm/lib/install/action/move.js @@ -8,7 +8,7 @@ var mkdirp = require('mkdirp') var rmStuff = require('../../unbuild.js').rmStuff var lifecycle = require('../../utils/lifecycle.js') var updatePackageJson = require('../update-package-json.js') -var rename = require('../../utils/rename.js') +var move = require('../../utils/move.js') /* Move a module from one point in the node_modules tree to another. @@ -46,7 +46,7 @@ function moveModuleOnly (from, to, log, done) { log.silly('move', 'move existing destination node_modules away', toModules) - rename(toModules, tempToModules, removeDestination(done)) + move(toModules, tempToModules, removeDestination(done)) function removeDestination (next) { return function (er) { @@ -62,7 +62,7 @@ function moveModuleOnly (from, to, log, done) { function moveToModulesBack (next) { return function () { log.silly('move', 'move existing destination node_modules back', toModules) - rename(tempToModules, toModules, iferr(done, next)) + move(tempToModules, toModules, iferr(done, next)) } } @@ -76,14 +76,14 @@ function moveModuleOnly (from, to, log, done) { function moveNodeModules (next) { return function () { log.silly('move', 'move source node_modules away', fromModules) - rename(fromModules, tempFromModules, iferr(doMove(next), doMove(moveNodeModulesBack(next)))) + move(fromModules, tempFromModules, iferr(doMove(next), doMove(moveNodeModulesBack(next)))) } } function doMove (next) { return function () { log.silly('move', 'move module dir to final dest', from, to) - rename(from, to, iferr(done, next)) + move(from, to, iferr(done, next)) } } @@ -91,7 +91,7 @@ function moveModuleOnly (from, to, log, done) { return function () { mkdirp(from, iferr(done, function () { log.silly('move', 'put source node_modules back', fromModules) - rename(tempFromModules, fromModules, iferr(done, next)) + move(tempFromModules, fromModules, iferr(done, next)) })) } } diff --git a/deps/npm/lib/install/action/remove.js b/deps/npm/lib/install/action/remove.js index 47d5b766f7..9fe77c35e0 100644 --- a/deps/npm/lib/install/action/remove.js +++ b/deps/npm/lib/install/action/remove.js @@ -6,7 +6,7 @@ var asyncMap = require('slide').asyncMap var mkdirp = require('mkdirp') var npm = require('../../npm.js') var andIgnoreErrors = require('../and-ignore-errors.js') -var rename = require('../../utils/rename.js') +var move = require('../../utils/move.js') // This is weird because we want to remove the module but not it's node_modules folder // allowing for this allows us to not worry about the order of operations @@ -26,11 +26,11 @@ function removeLink (pkg, next) { function removeDir (pkg, log, next) { var modpath = path.join(path.dirname(pkg.path), '.' + path.basename(pkg.path) + '.MODULES') - rename(path.join(pkg.path, 'node_modules'), modpath, unbuildPackage) + move(path.join(pkg.path, 'node_modules'), modpath, unbuildPackage) - function unbuildPackage (renameEr) { + function unbuildPackage (moveEr) { npm.commands.unbuild(pkg.path, true, function () { - rimraf(pkg.path, renameEr ? andRemoveEmptyParents(pkg.path) : moveModulesBack) + rimraf(pkg.path, moveEr ? andRemoveEmptyParents(pkg.path) : moveModulesBack) }) } @@ -58,7 +58,7 @@ function removeDir (pkg, log, next) { var to = path.join(pkg.path, 'node_modules', file) // we ignore errors here, because they can legitimately happen, for instance, // bundled modules will be in both node_modules folders - rename(from, to, andIgnoreErrors(done)) + move(from, to, andIgnoreErrors(done)) }, cleanup) } diff --git a/deps/npm/lib/install/action/test.js b/deps/npm/lib/install/action/test.js deleted file mode 100644 index 29f26f3ecf..0000000000 --- a/deps/npm/lib/install/action/test.js +++ /dev/null @@ -1,8 +0,0 @@ -'use strict' -var lifecycle = require('../../utils/lifecycle.js') -var packageId = require('../../utils/package-id.js') - -module.exports = function (staging, pkg, log, next) { - log.silly('test', packageId(pkg)) - lifecycle(pkg.package, 'test', pkg.path, false, false, next) -} diff --git a/deps/npm/lib/install/actions.js b/deps/npm/lib/install/actions.js index 6e9c1a0b65..cb41217c02 100644 --- a/deps/npm/lib/install/actions.js +++ b/deps/npm/lib/install/actions.js @@ -2,7 +2,9 @@ var validate = require('aproba') var chain = require('slide').chain var asyncMap = require('slide').asyncMap +var limit = require('call-limit') var iferr = require('iferr') +var npm = require('../npm.js') var andFinishTracker = require('./and-finish-tracker.js') var andAddParentToErrors = require('./and-add-parent-to-errors.js') var failedDependency = require('./deps.js').failedDependency @@ -15,7 +17,6 @@ var actions = {} actions.fetch = require('./action/fetch.js') actions.extract = require('./action/extract.js') actions.build = require('./action/build.js') -actions.test = require('./action/test.js') actions.preinstall = require('./action/preinstall.js') actions.install = require('./action/install.js') actions.postinstall = require('./action/postinstall.js') @@ -32,7 +33,7 @@ actions['global-link'] = require('./action/global-link.js') Object.keys(actions).forEach(function (actionName) { var action = actions[actionName] - actions[actionName] = function (staging, pkg, log, next) { + actions[actionName] = limit(function (staging, pkg, log, next) { // top, buildpath, pkg, log validate('SOOF', arguments) // refuse to run actions for failed packages @@ -62,7 +63,7 @@ Object.keys(actions).forEach(function (actionName) { function andDone (cb) { return andFinishTracker(log, andAddParentToErrors(pkg.parent, andHandleOptionalDepErrors(pkg, cb))) } - } + }, npm.limit.action) }) function markAsFailed (pkg) { diff --git a/deps/npm/lib/install/deps.js b/deps/npm/lib/install/deps.js index a31976a50d..d1feb6cd4b 100644 --- a/deps/npm/lib/install/deps.js +++ b/deps/npm/lib/install/deps.js @@ -462,7 +462,7 @@ function addDependency (name, versionSpec, tree, log, done) { } })) } else { - fetchPackageMetadata(req, packageRelativePath(tree), log.newItem('fetchMetadata'), iferr(next, function (pkg) { + fetchPackageMetadata(req, packageRelativePath(tree), {tracker: log.newItem('fetchMetadata')}, iferr(next, function (pkg) { resolveWithNewModule(pkg, tree, log, next) })) } @@ -547,7 +547,7 @@ function resolveWithNewModule (pkg, tree, log, next) { if (tree.parent && parent !== tree) updatePhantomChildren(tree.parent, child) if (hasBundled) { - inflateBundled(child, child.children) + inflateBundled(child, child, child.children) } if (pkg._shrinkwrap && pkg._shrinkwrap.dependencies) { diff --git a/deps/npm/lib/install/inflate-bundled.js b/deps/npm/lib/install/inflate-bundled.js index f91e9112b9..5694841290 100644 --- a/deps/npm/lib/install/inflate-bundled.js +++ b/deps/npm/lib/install/inflate-bundled.js @@ -3,15 +3,15 @@ var validate = require('aproba') var childPath = require('../utils/child-path.js') var reset = require('./node.js').reset -module.exports = function inflateBundled (parent, children) { - validate('OA', arguments) +module.exports = function inflateBundled (bundler, parent, children) { + validate('OOA', arguments) children.forEach(function (child) { reset(child) - child.fromBundle = true + child.fromBundle = bundler child.parent = parent child.path = childPath(parent.path, child) child.realpath = childPath(parent.path, child) child.isLink = child.isLink || parent.isLink || parent.target - inflateBundled(child, child.children) + inflateBundled(bundler, child, child.children) }) } diff --git a/deps/npm/lib/install/inflate-shrinkwrap.js b/deps/npm/lib/install/inflate-shrinkwrap.js index 497bbe3348..aca4204930 100644 --- a/deps/npm/lib/install/inflate-shrinkwrap.js +++ b/deps/npm/lib/install/inflate-shrinkwrap.js @@ -89,7 +89,7 @@ function inflateShrinkwrap (topPath, tree, swdeps, finishInflating) { tree.children.push(child) if (pkg._bundled) { delete pkg._bundled - inflateBundled(child, child.children) + inflateBundled(child, child, child.children) } inflateShrinkwrap(topPath, child, dependencies || {}, next) } diff --git a/deps/npm/lib/install/validate-tree.js b/deps/npm/lib/install/validate-tree.js index e89cd6fdd2..ccd4e2e310 100644 --- a/deps/npm/lib/install/validate-tree.js +++ b/deps/npm/lib/install/validate-tree.js @@ -26,7 +26,8 @@ module.exports = function (idealTree, log, next) { ], done) }], [thenValidateAllPeerDeps, idealTree], - [thenCheckTop, idealTree] + [thenCheckTop, idealTree], + [thenCheckDuplicateDeps, idealTree] ], andFinishTracker(log, next)) } @@ -73,5 +74,22 @@ function thenCheckTop (idealTree, next) { warnObj.code = 'ENODEPRE' idealTree.warnings.push(warnObj) } + + next() +} + +// check for deps duplciated between devdeps and regular deps +function thenCheckDuplicateDeps (idealTree, next) { + var deps = idealTree.package.dependencies || {} + var devDeps = idealTree.package.devDependencies || {} + + for (var pkg in devDeps) { + if (pkg in deps) { + var warnObj = new Error('The package ' + pkg + ' is included as both a dev and production dependency.') + warnObj.code = 'EDUPLICATEDEP' + idealTree.warnings.push(warnObj) + } + } + next() } diff --git a/deps/npm/lib/ls.js b/deps/npm/lib/ls.js index ba5ab16e51..3c0e4384dd 100644 --- a/deps/npm/lib/ls.js +++ b/deps/npm/lib/ls.js @@ -15,6 +15,8 @@ var semver = require('semver') var color = require('ansicolors') var npa = require('npm-package-arg') var iferr = require('iferr') +var sortedObject = require('sorted-object') +var extend = Object.assign || require('util')._extend var npm = require('./npm.js') var mutateIntoLogicalTree = require('./install/mutate-into-logical-tree.js') var recalculateMetadata = require('./install/deps.js').recalculateMetadata @@ -76,8 +78,8 @@ var lsFromTree = ls.fromTree = function (dir, physicalTree, args, silent, cb) { pruneNestedExtraneous(data) filterByEnv(data) - var bfs = filterFound(bfsify(data), args) - var lite = getLite(bfs) + var unlooped = filterFound(unloop(data), args) + var lite = getLite(unlooped) if (silent) return cb(null, data, lite) @@ -86,7 +88,7 @@ var lsFromTree = ls.fromTree = function (dir, physicalTree, args, silent, cb) { var out if (json) { var seen = [] - var d = long ? bfs : lite + var d = long ? unlooped : lite // the raw data can be circular out = JSON.stringify(d, function (k, o) { if (typeof o === 'object') { @@ -96,9 +98,9 @@ var lsFromTree = ls.fromTree = function (dir, physicalTree, args, silent, cb) { return o }, 2) } else if (npm.config.get('parseable')) { - out = makeParseable(bfs, long, dir) + out = makeParseable(unlooped, long, dir) } else if (data) { - out = makeArchy(bfs, long, dir) + out = makeArchy(unlooped, long, dir) } output(out) @@ -247,18 +249,10 @@ function getLite (data, noname, depth) { return lite } -function bfsify (root) { - // walk over the data, and turn it from this: - // +-- a - // | `-- b - // | `-- a (truncated) - // `--b (truncated) - // into this: - // +-- a - // `-- b - // which looks nicer +function unloop (root) { var queue = [root] - var seen = [root] + var seen = {} + seen[root.path] = true while (queue.length) { var current = queue.shift() @@ -266,17 +260,14 @@ function bfsify (root) { Object.keys(deps).forEach(function (d) { var dep = deps[d] if (dep.missing) return - if (inList(seen, dep)) { - if (npm.config.get('parseable') || !npm.config.get('long')) { - delete deps[d] - return - } else { - dep = deps[d] = Object.create(dep) - dep.dependencies = {} - } + if (dep.path && seen[dep.path]) { + dep = deps[d] = extend({}, dep) + dep.dependencies = {} + dep._deduped = path.relative(root.path, dep.path).replace(/node_modules\//g, '') + return } + seen[dep.path] = true queue.push(dep) - seen.push(dep) }) } @@ -285,18 +276,23 @@ function bfsify (root) { function filterFound (root, args) { if (!args.length) return root - var deps = root.dependencies - if (deps) { - Object.keys(deps).forEach(function (depName) { - var dep = filterFound(deps[depName], args) + if (!root.dependencies) return root + + // Mark all deps + var toMark = [root] + while (toMark.length) { + var markPkg = toMark.shift() + var markDeps = markPkg.dependencies + if (!markDeps) continue + Object.keys(markDeps).forEach(function (depName) { + var dep = markDeps[depName] if (dep.peerMissing) return - - // see if this one itself matches - var found = false - for (var ii = 0; !found && ii < args.length; ii++) { + dep._parent = markPkg + for (var ii = 0; ii < args.length; ii++) { var argName = args[ii][0] var argVersion = args[ii][1] var argRaw = args[ii][2] + var found if (depName === argName && argVersion) { found = semver.satisfies(dep.version, argVersion, true) } else if (depName === argName) { @@ -305,16 +301,33 @@ function filterFound (root, args) { } else if (dep.path === argRaw) { found = true } + if (found) { + dep._found = 'explicit' + var parent = dep._parent + while (parent && !parent._found && !parent._deduped) { + parent._found = 'implicit' + parent = parent._parent + } + break + } } - // included explicitly - if (found) dep._found = true - // included because a child was included - if (dep._found && !root._found) root._found = 1 - // not included - if (!dep._found) delete deps[depName] + toMark.push(dep) + }) + } + var toTrim = [root] + while (toTrim.length) { + var trimPkg = toTrim.shift() + var trimDeps = trimPkg.dependencies + if (!trimDeps) continue + trimPkg.dependencies = {} + Object.keys(trimDeps).forEach(function (name) { + var dep = trimDeps[name] + if (!dep._found) return + if (dep._found === 'implicit' && dep._deduped) return + trimPkg.dependencies[name] = dep + toTrim.push(dep) }) } - if (!root._found) root._found = false return root } @@ -345,7 +358,7 @@ function makeArchy_ (data, long, dir, depth, parent, d) { var out = {} // the top level is a bit special. out.label = data._id || '' - if (data._found === true && data._id) { + if (data._found === 'explicit' && data._id) { if (npm.color) { out.label = color.bgBlack(color.yellow(out.label.trim())) + ' ' } else { @@ -354,6 +367,14 @@ function makeArchy_ (data, long, dir, depth, parent, d) { } if (data.link) out.label += ' -> ' + data.link + if (data._deduped) { + if (npm.color) { + out.label += ' ' + color.brightBlack('deduped') + } else { + out.label += ' deduped' + } + } + if (data.invalid) { if (data.realName !== data.name) out.label += ' (' + data.realName + ')' var invalid = 'invalid' @@ -369,6 +390,7 @@ function makeArchy_ (data, long, dir, depth, parent, d) { if (data.peerMissing) { var peerMissing = 'UNMET PEER DEPENDENCY' + if (npm.color) peerMissing = color.bgBlack(color.red(peerMissing)) out.label = peerMissing + ' ' + out.label } @@ -415,7 +437,7 @@ function makeArchy_ (data, long, dir, depth, parent, d) { .sort(alphasort).filter(function (d) { return !isCruft(data.dependencies[d]) }).map(function (d) { - return makeArchy_(data.dependencies[d], long, dir, depth + 1, data, d) + return makeArchy_(sortedObject(data.dependencies[d]), long, dir, depth + 1, data, d) }) } @@ -444,19 +466,20 @@ function getExtras (data) { } function makeParseable (data, long, dir, depth, parent, d) { + if (data._deduped) return [] depth = depth || 0 if (depth > npm.config.get('depth')) return [ makeParseable_(data, long, dir, depth, parent, d) ] return [ makeParseable_(data, long, dir, depth, parent, d) ] - .concat(Object.keys(data.dependencies || {}) - .sort(alphasort).map(function (d) { - return makeParseable(data.dependencies[d], long, dir, depth + 1, data, d) - })) - .filter(function (x) { return x }) - .join('\n') + .concat(Object.keys(data.dependencies || {}) + .sort(alphasort).map(function (d) { + return makeParseable(data.dependencies[d], long, dir, depth + 1, data, d) + })) + .filter(function (x) { return x }) + .join('\n') } function makeParseable_ (data, long, dir, depth, parent, d) { - if (data.hasOwnProperty('_found') && data._found !== true) return '' + if (data.hasOwnProperty('_found') && data._found !== 'explicit') return '' if (data.missing) { if (depth < npm.config.get('depth')) { diff --git a/deps/npm/lib/npm.js b/deps/npm/lib/npm.js index 890c369cc6..f852886433 100644 --- a/deps/npm/lib/npm.js +++ b/deps/npm/lib/npm.js @@ -31,7 +31,7 @@ var which = require('which') var glob = require('glob') var rimraf = require('rimraf') - var CachingRegClient = require('./cache/caching-client.js') + var lazyProperty = require('lazy-property') var parseJSON = require('./utils/parse-json.js') var aliases = require('./config/cmd-list').aliases var cmdList = require('./config/cmd-list').cmdList @@ -51,6 +51,13 @@ npm.commands = {} + // TUNING + npm.limit = { + fetch: 10, + action: 10 + } + // *** + npm.rollbacks = [] try { @@ -79,6 +86,9 @@ return littleGuys.indexOf(c) === -1 }) + var registryRefer + var registryLoaded + Object.keys(abbrevs).concat(plumbing).forEach(function addCommand (c) { Object.defineProperty(npm.commands, c, { get: function () { if (!loaded) { @@ -112,9 +122,8 @@ } }) - npm.registry.version = npm.version - if (!npm.registry.refer) { - npm.registry.refer = [a].concat(args[0]).map(function (arg) { + if (!registryRefer) { + registryRefer = [a].concat(args[0]).map(function (arg) { // exclude anything that might be a URL, path, or private module // Those things will always have a slash in them somewhere if (arg && arg.match && arg.match(/\/|\\/)) { @@ -125,6 +134,7 @@ }).filter(function (arg) { return arg && arg.match }).join(' ') + if (registryLoaded) npm.registry.refer = registryRefer } cmd.apply(npm, args) @@ -253,6 +263,10 @@ ua = ua.replace(/\{arch\}/gi, process.arch) config.set('user-agent', ua) + if (config.get('metrics-registry') == null) { + config.set('metrics-registry', config.get('registry')) + } + var color = config.get('color') log.level = config.get('loglevel') @@ -299,10 +313,6 @@ log.resume() - // at this point the configs are all set. - // go ahead and spin up the registry client. - npm.registry = new CachingRegClient(npm.config) - var umask = npm.config.get('umask') npm.modes = { exec: parseInt('0777', 8) & (~umask), @@ -322,7 +332,14 @@ // at this point the configs are all set. // go ahead and spin up the registry client. - npm.registry = new CachingRegClient(npm.config) + lazyProperty(npm, 'registry', function () { + registryLoaded = true + var CachingRegClient = require('./cache/caching-client.js') + var registry = new CachingRegClient(npm.config) + registry.version = npm.version + registry.refer = registryRefer + return registry + }) startMetrics() diff --git a/deps/npm/lib/outdated.js b/deps/npm/lib/outdated.js index a4a0d15abb..546d14b134 100644 --- a/deps/npm/lib/outdated.js +++ b/deps/npm/lib/outdated.js @@ -357,7 +357,7 @@ function shouldUpdate (args, tree, dep, has, req, depth, pkgpath, cb, type) { } } - if (curr.version !== wanted) { + if (!curr || curr.version !== wanted) { doIt(wanted, latest) } else { skip() diff --git a/deps/npm/lib/repo.js b/deps/npm/lib/repo.js index caaf422cfe..d7e79d76ab 100644 --- a/deps/npm/lib/repo.js +++ b/deps/npm/lib/repo.js @@ -16,7 +16,7 @@ repo.completion = function (opts, cb) { function repo (args, cb) { var n = args.length ? args[0] : '.' - fetchPackageMetadata(n, '.', function (er, d) { + fetchPackageMetadata(n, '.', {fullMetadata: true}, function (er, d) { if (er) return cb(er) getUrlAndOpen(d, cb) }) diff --git a/deps/npm/lib/search/format-package-stream.js b/deps/npm/lib/search/format-package-stream.js index caa46cb898..a312e3f483 100644 --- a/deps/npm/lib/search/format-package-stream.js +++ b/deps/npm/lib/search/format-package-stream.js @@ -161,7 +161,7 @@ function normalizePackage (data, opts) { : typeof data.keywords === 'string' ? data.keywords.replace(/[,\s]+/, ' ') : '', - version: Object.keys(data.versions || {})[0] || [], + version: data.version, date: data.date && (data.date.toISOString() // remove time .split('T').join(' ') diff --git a/deps/npm/lib/utils/completion.sh b/deps/npm/lib/utils/completion.sh index 25bef2c17b..c549b31c96 100755 --- a/deps/npm/lib/utils/completion.sh +++ b/deps/npm/lib/utils/completion.sh @@ -11,7 +11,7 @@ if type complete &>/dev/null; then _npm_completion () { local words cword if type _get_comp_words_by_ref &>/dev/null; then - _get_comp_words_by_ref -n = -n @ -w words -i cword + _get_comp_words_by_ref -n = -n @ -n : -w words -i cword else cword="$COMP_CWORD" words=("${COMP_WORDS[@]}") @@ -24,6 +24,9 @@ if type complete &>/dev/null; then npm completion -- "${words[@]}" \ 2>/dev/null)) || return $? IFS="$si" + if type __ltrim_colon_completions &>/dev/null; then + __ltrim_colon_completions "${words[cword]}" + fi } complete -o default -F _npm_completion npm elif type compdef &>/dev/null; then diff --git a/deps/npm/lib/utils/error-handler.js b/deps/npm/lib/utils/error-handler.js index a2911a101a..1213902886 100644 --- a/deps/npm/lib/utils/error-handler.js +++ b/deps/npm/lib/utils/error-handler.js @@ -4,17 +4,16 @@ module.exports = errorHandler var cbCalled = false var log = require('npmlog') var npm = require('../npm.js') -var rm = require('rimraf') var itWorked = false var path = require('path') var wroteLogFile = false var exitCode = 0 var rollbacks = npm.rollbacks var chain = require('slide').chain -var writeStreamAtomic = require('fs-write-stream-atomic') +var writeFileAtomic = require('write-file-atomic') var errorMessage = require('./error-message.js') var stopMetrics = require('./metrics.js').stop -var mkdir = require('mkdirp') +var mkdirp = require('mkdirp') var logFileName function getLogFile () { @@ -32,10 +31,15 @@ process.on('exit', function (code) { stopMetrics() if (code) itWorked = false - if (itWorked) log.info('ok') - else { + if (itWorked) { + log.info('ok') + } else { if (!cbCalled) { log.error('', 'cb() never called!') + console.error('') + log.error('', 'This is an error with npm itself. Please report this error at:') + log.error('', ' <https://github.com/npm/npm/issues>') + writeLogFile() } if (wroteLogFile) { @@ -45,7 +49,7 @@ process.on('exit', function (code) { log.error( '', [ - 'Please include the following file with any support request:', + 'A complete log of this run can be found in:', ' ' + getLogFile() ].join('\n') ) @@ -83,19 +87,22 @@ function exit (code, noLog) { }), function (er) { if (er) { log.error('error rolling back', er) - if (!code) errorHandler(er) - else if (noLog) rm('npm-debug.log', reallyExit.bind(null, er)) - else writeLogFile(reallyExit.bind(this, er)) + if (!code) { + errorHandler(er) + } else { + if (!noLog) writeLogFile() + reallyExit(er) + } } else { - if (!noLog && code) writeLogFile(reallyExit) - else rm(getLogFile(), reallyExit) + if (!noLog && code) writeLogFile() + reallyExit() } }) rollbacks.length = 0 } else if (code && !noLog) { writeLogFile(reallyExit) } else { - rm('npm-debug.log', reallyExit) + reallyExit() } function reallyExit (er) { @@ -115,7 +122,6 @@ function exit (code, noLog) { function errorHandler (er) { log.disableProgress() - // console.error('errorHandler', er) if (!npm.config || !npm.config.loaded) { // logging won't work unless we pretend that it's ready er = er || new Error('Exit prior to config file resolving.') @@ -163,14 +169,10 @@ function errorHandler (er) { log.verbose('cwd', process.cwd()) var os = require('os') - // log.error('System', os.type() + ' ' + os.release()) - // log.error('command', process.argv.map(JSON.stringify).join(' ')) - // log.error('node -v', process.version) - // log.error('npm -v', npm.version) - log.error('', os.type() + ' ' + os.release()) - log.error('argv', process.argv.map(JSON.stringify).join(' ')) - log.error('node', process.version) - log.error('npm ', 'v' + npm.version) + log.verbose('', os.type() + ' ' + os.release()) + log.verbose('argv', process.argv.map(JSON.stringify).join(' ')) + log.verbose('node', process.version) + log.verbose('npm ', 'v' + npm.version) ;[ 'file', @@ -183,9 +185,6 @@ function errorHandler (er) { if (v) log.error(k, v) }) - // just a line break - if (log.levels[log.level] <= log.levels.error) console.error('') - var msg = errorMessage(er) msg.summary.concat(msg.detail).forEach(function (errline) { log.error.apply(log, errline) @@ -194,20 +193,15 @@ function errorHandler (er) { exit(typeof er.errno === 'number' ? er.errno : 1) } -var writingLogFile = false -function writeLogFile (cb) { - if (writingLogFile) return cb() - writingLogFile = true +function writeLogFile () { + if (wroteLogFile) return wroteLogFile = true var os = require('os') - mkdir(path.resolve(npm.config.get('cache'), '_logs'), function (er) { - if (er) { - cb(er) - return - } - var fstr = writeStreamAtomic(getLogFile()) + try { + mkdirp.sync(path.resolve(npm.config.get('cache'), '_logs')) + var logOutput = '' log.record.forEach(function (m) { var pref = [m.id, m.level] if (m.prefix) pref.push(m.prefix) @@ -216,10 +210,11 @@ function writeLogFile (cb) { m.message.trim().split(/\r?\n/).map(function (line) { return (pref + ' ' + line).trim() }).forEach(function (line) { - fstr.write(line + os.EOL) + logOutput += line + os.EOL }) }) - fstr.end() - fstr.on('close', cb) - }) + writeFileAtomic.sync(getLogFile(), logOutput) + } catch (ex) { + return + } } diff --git a/deps/npm/lib/utils/error-message.js b/deps/npm/lib/utils/error-message.js index 5c7ce15bf1..f19d0bf6d3 100644 --- a/deps/npm/lib/utils/error-message.js +++ b/deps/npm/lib/utils/error-message.js @@ -268,7 +268,6 @@ function errorMessage (er) { detail.push([ 'enoent', [ - er.message, 'This is most likely not a problem with npm itself', 'and is related to npm not being able to find a file.', er.file ? "\nCheck if the file '" + er.file + "' is present." : '' @@ -304,14 +303,6 @@ function errorMessage (er) { default: short.push(['', er.message || er]) - detail.push([ - '', - [ - '', - 'If you need help, you may report this error at:', - ' <https://github.com/npm/npm/issues>' - ].join('\n') - ]) break } if (er.optional) { diff --git a/deps/npm/lib/utils/lifecycle.js b/deps/npm/lib/utils/lifecycle.js index f48d5e2a3b..4ab5e0979a 100644 --- a/deps/npm/lib/utils/lifecycle.js +++ b/deps/npm/lib/utils/lifecycle.js @@ -282,6 +282,7 @@ function runCmd_ (cmd, pkg, env, wd, stage, unsafe, uid, gid, cb_) { procError(er) }) process.once('SIGTERM', procKill) + process.once('SIGINT', procInterupt) function procError (er) { if (er) { @@ -302,11 +303,20 @@ function runCmd_ (cmd, pkg, env, wd, stage, unsafe, uid, gid, cb_) { er.pkgname = pkg.name } process.removeListener('SIGTERM', procKill) + process.removeListener('SIGTERM', procInterupt) + process.removeListener('SIGINT', procKill) return cb(er) } function procKill () { proc.kill() } + function procInterupt () { + proc.kill('SIGINT') + proc.on('exit', function () { + process.exit() + }) + process.once('SIGINT', procKill) + } } function runHookLifecycle (pkg, env, wd, unsafe, cb) { diff --git a/deps/npm/lib/utils/move.js b/deps/npm/lib/utils/move.js new file mode 100644 index 0000000000..242e87d37f --- /dev/null +++ b/deps/npm/lib/utils/move.js @@ -0,0 +1,19 @@ +'use strict' +module.exports = wrappedMove + +var fs = require('graceful-fs') +var move = require('move-concurrently') +var Bluebird = require('bluebird') + +function wrappedMove (from, to, cb) { + var movePromise = move(from, to, {fs: fs, Promise: Bluebird, maxConcurrency: 4}) + if (cb) { + return movePromise.then(function (value) { + cb(value) + }, function (err) { + cb(err) + }) + } else { + return movePromise + } +} diff --git a/deps/npm/lib/utils/rename.js b/deps/npm/lib/utils/rename.js index 8a44428984..43a2f7e104 100644 --- a/deps/npm/lib/utils/rename.js +++ b/deps/npm/lib/utils/rename.js @@ -1,16 +1,9 @@ -'use strict' -var fs = require('graceful-fs') -var SaveStack = require('./save-stack.js') +/* -module.exports = rename +This is a stub file to ensure that the following hack doesn't break. This can be removed w/ npm@5. -function rename (from, to, cb) { - var saved = new SaveStack(rename) - fs.rename(from, to, function (er) { - if (er) { - return cb(saved.completeWith(er)) - } else { - return cb() - } - }) -} +# Fix bug https://github.com/npm/npm/issues/9863 +RUN cd $(npm root -g)/npm \ + && npm install fs-extra \ + && sed -i -e s/graceful-fs/fs-extra/ -e s/fs\.rename/fs.move/ ./lib/utils/rename.js +*/ diff --git a/deps/npm/lib/utils/tar.js b/deps/npm/lib/utils/tar.js index f580c8e05d..88cfc6b805 100644 --- a/deps/npm/lib/utils/tar.js +++ b/deps/npm/lib/utils/tar.js @@ -136,8 +136,10 @@ BundledPacker.prototype.applyIgnores = function (entry, partial, entryObj) { // the package root. var p = this.parent - // the package before this one. + // the directory before this one. var pp = p && p.parent + // the directory before that (if this is scoped) + if (pp && pp.basename[0] === '@') pp = pp && pp.parent // if this entry has already been bundled, and is a symlink, // and it is the *same* symlink as this one, then exclude it. |