diff options
author | Rebecca Turner <me@re-becca.org> | 2016-06-24 13:43:51 -0700 |
---|---|---|
committer | Jeremiah Senkpiel <fishrock123@rocketmail.com> | 2016-06-27 11:46:15 +0200 |
commit | d538811fc8b920f3f36d5f21a4c23e270367ceb0 (patch) | |
tree | 11cee6c00aa843f16a71819039396f80bf6abe22 /deps/npm/lib | |
parent | 1db31a34948eee311abd9881bbf5d906d0cd678b (diff) | |
download | node-new-d538811fc8b920f3f36d5f21a4c23e270367ceb0.tar.gz |
deps: upgrade npm to 3.10.2
Contains the following npm releases:
- https://github.com/npm/npm/releases/tag/v3.9.6
- https://github.com/npm/npm/releases/tag/v3.10.0
- https://github.com/npm/npm/releases/tag/v3.10.1
- https://github.com/npm/npm/releases/tag/v3.10.2
PR-URL: https://github.com/nodejs/node/pull/7410
Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
Diffstat (limited to 'deps/npm/lib')
56 files changed, 567 insertions, 305 deletions
diff --git a/deps/npm/lib/access.js b/deps/npm/lib/access.js index 69527c2aa4..ad7a1f54bd 100644 --- a/deps/npm/lib/access.js +++ b/deps/npm/lib/access.js @@ -5,6 +5,7 @@ var resolve = require('path').resolve var readPackageJson = require('read-package-json') var mapToRegistry = require('./utils/map-to-registry.js') var npm = require('./npm.js') +var output = require('./utils/output.js') var whoami = require('./whoami') @@ -62,7 +63,9 @@ function access (args, cb) { params.auth = auth try { return npm.registry.access(cmd, uri, params, function (err, data) { - !err && data && console.log(JSON.stringify(data, undefined, 2)) + if (!err && data) { + output(JSON.stringify(data, undefined, 2)) + } cb(err, data) }) } catch (e) { diff --git a/deps/npm/lib/adduser.js b/deps/npm/lib/adduser.js index 3a7425d471..e04af0556b 100644 --- a/deps/npm/lib/adduser.js +++ b/deps/npm/lib/adduser.js @@ -4,7 +4,9 @@ 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 { @@ -30,15 +32,14 @@ function adduser (args, cb) { e: creds.email || '' } var u = {} - var fns = [readUsername, readPassword, readEmail, save] - loop() - function loop (er) { - if (er) return cb(er) - var fn = fns.shift() - if (fn) return fn(c, u, loop) - cb() - } + log.disableProgress() + chain([ + [readUsername, c, u], + [readPassword, c, u], + [readEmail, c, u], + [save, c, u] + ], cb) } function readUsername (c, u, cb) { @@ -173,7 +174,7 @@ function save (c, u, cb) { log.info('adduser', 'Authorized user %s', u.u) var scopeMessage = scope ? ' to scope ' + scope : '' - console.log('Logged in as %s%s on %s.', u.u, scopeMessage, uri) + output('Logged in as %s%s on %s.', u.u, scopeMessage, uri) npm.config.save('user', cb) }) } diff --git a/deps/npm/lib/bin.js b/deps/npm/lib/bin.js index 2e02617d35..7258893b9c 100644 --- a/deps/npm/lib/bin.js +++ b/deps/npm/lib/bin.js @@ -2,6 +2,7 @@ module.exports = bin var npm = require('./npm.js') var osenv = require('osenv') +var output = require('./utils/output.js') bin.usage = 'npm bin [--global]' @@ -13,7 +14,7 @@ function bin (args, silent, cb) { var b = npm.bin var PATH = osenv.path() - if (!silent) console.log(b) + if (!silent) output(b) process.nextTick(cb.bind(this, null, b)) if (npm.config.get('global') && PATH.indexOf(b) === -1) { diff --git a/deps/npm/lib/build.js b/deps/npm/lib/build.js index e9da59a23d..fbe78c746d 100644 --- a/deps/npm/lib/build.js +++ b/deps/npm/lib/build.js @@ -22,6 +22,7 @@ var asyncMap = require('slide').asyncMap var ini = require('ini') var writeFile = require('write-file-atomic') var packageId = require('./utils/package-id.js') +var output = require('./utils/output.js') module.exports = build build.usage = 'npm build [<folder>]' @@ -211,9 +212,7 @@ function linkBins (pkg, folder, parent, gtop, cb) { var out = npm.config.get('parseable') ? dest + '::' + src + ':BINFILE' : dest + ' -> ' + src - log.clearProgress() - console.log(out) - log.showProgress() + output(out) cb() }) } diff --git a/deps/npm/lib/cache.js b/deps/npm/lib/cache.js index 757ba6e79d..5ad07dfdcd 100644 --- a/deps/npm/lib/cache.js +++ b/deps/npm/lib/cache.js @@ -82,6 +82,7 @@ var npa = require('npm-package-arg') var getStat = require('./cache/get-stat.js') var cachedPackageRoot = require('./cache/cached-package-root.js') var mapToRegistry = require('./utils/map-to-registry.js') +var output = require('./utils/output.js') cache.usage = 'npm cache add <tarball file>' + '\nnpm cache add <folder>' + @@ -182,7 +183,7 @@ function ls (args, cb) { prefix = '~' + prefix.substr(process.env.HOME.length) } ls_(normalize(args), npm.config.get('depth'), function (er, files) { - console.log(files.map(function (f) { + output(files.map(function (f) { return path.join(prefix, f) }).join('\n').trim()) cb(er, files) diff --git a/deps/npm/lib/completion.js b/deps/npm/lib/completion.js index 6f6cfd810b..3157255bfb 100644 --- a/deps/npm/lib/completion.js +++ b/deps/npm/lib/completion.js @@ -14,6 +14,7 @@ var shorthandNames = Object.keys(shorthands) var allConfs = configNames.concat(shorthandNames) var once = require('once') var isWindowsShell = require('./utils/is-windows-shell.js') +var output = require('./utils/output.js') completion.completion = function (opts, cb) { if (opts.w > 3) return cb() @@ -203,7 +204,7 @@ function wrapCb (cb, opts) { console.error([er && er.stack, compls, opts.partialWord]) if (er || compls.length === 0) return cb(er) - console.log(compls.join('\n')) + output(compls.join('\n')) cb() } } diff --git a/deps/npm/lib/config.js b/deps/npm/lib/config.js index 80958ec5fc..7112e88c5f 100644 --- a/deps/npm/lib/config.js +++ b/deps/npm/lib/config.js @@ -11,6 +11,7 @@ var editor = require('editor') var os = require('os') var umask = require('./utils/umask') var usage = require('./utils/usage') +var output = require('./utils/output') config.usage = usage( 'config', @@ -148,7 +149,7 @@ function get (key, cb) { } var val = npm.config.get(key) if (key.match(/umask/)) val = umask.toString(val) - console.log(val) + output(val) cb() } @@ -278,7 +279,7 @@ function list (cb) { '; HOME = ' + process.env.HOME + '\n' + '; "npm config ls -l" to show all defaults.\n' - console.log(msg) + output(msg) return cb() } @@ -294,7 +295,7 @@ function list (cb) { }) msg += '\n' - console.log(msg) + output(msg) return cb() } diff --git a/deps/npm/lib/dist-tag.js b/deps/npm/lib/dist-tag.js index 0e9d914d39..7c20ea9901 100644 --- a/deps/npm/lib/dist-tag.js +++ b/deps/npm/lib/dist-tag.js @@ -8,6 +8,7 @@ var npm = require('./npm.js') var mapToRegistry = require('./utils/map-to-registry.js') var readLocalPkg = require('./utils/read-local-package.js') var usage = require('./utils/usage') +var output = require('./utils/output.js') distTag.usage = usage( 'dist-tag', @@ -77,7 +78,7 @@ function add (spec, tag, cb) { npm.registry.distTags.add(base, params, function (er) { if (er) return cb(er) - console.log('+' + t + ': ' + pkg + '@' + version) + output('+' + t + ': ' + pkg + '@' + version) cb() }) }) @@ -108,7 +109,7 @@ function remove (tag, pkg, cb) { npm.registry.distTags.rm(base, params, function (er) { if (er) return cb(er) - console.log('-' + tag + ': ' + pkg + '@' + version) + output('-' + tag + ': ' + pkg + '@' + version) cb() }) }) @@ -132,7 +133,7 @@ function list (pkg, cb) { var msg = Object.keys(tags).map(function (k) { return k + ': ' + tags[k] }).sort().join('\n') - console.log(msg) + output(msg) cb(er, tags) }) } diff --git a/deps/npm/lib/explore.js b/deps/npm/lib/explore.js index 05b5220d5f..5640d5f157 100644 --- a/deps/npm/lib/explore.js +++ b/deps/npm/lib/explore.js @@ -12,6 +12,7 @@ var fs = require('graceful-fs') var isWindowsShell = require('./utils/is-windows-shell.js') var escapeExecPath = require('./utils/escape-exec-path.js') var escapeArg = require('./utils/escape-arg.js') +var output = require('./utils/output.js') function explore (args, cb) { if (args.length < 1 || !args[0]) return cb(explore.usage) @@ -42,7 +43,7 @@ function explore (args, cb) { } if (!shellArgs.length) { - console.log( + output( '\nExploring ' + cwd + '\n' + "Type 'exit' or ^D when finished\n" ) diff --git a/deps/npm/lib/help-search.js b/deps/npm/lib/help-search.js index 8a138feebe..ffbe554b7b 100644 --- a/deps/npm/lib/help-search.js +++ b/deps/npm/lib/help-search.js @@ -7,6 +7,7 @@ var asyncMap = require('slide').asyncMap var npm = require('./npm.js') var glob = require('glob') var color = require('ansicolors') +var output = require('./utils/output.js') helpSearch.usage = 'npm help-search <text>' @@ -135,7 +136,7 @@ function searchFiles (args, files, cb) { } if (results.length === 0) { - console.log('No results for ' + args.map(JSON.stringify).join(' ')) + output('No results for ' + args.map(JSON.stringify).join(' ')) return cb() } @@ -206,6 +207,6 @@ function formatResults (args, results, cb) { '(run with -l or --long to see more context)' } - console.log(out.trim()) + output(out.trim()) cb(null, results) } diff --git a/deps/npm/lib/help.js b/deps/npm/lib/help.js index cecc6e02b0..cfac917999 100644 --- a/deps/npm/lib/help.js +++ b/deps/npm/lib/help.js @@ -15,6 +15,7 @@ var glob = require('glob') var cmdList = require('./config/cmd-list').cmdList var shorthands = require('./config/cmd-list').shorthands var commands = cmdList.concat(Object.keys(shorthands)) +var output = require('./utils/output.js') function help (args, cb) { var argv = npm.config.get('argv').cooked @@ -43,7 +44,7 @@ function help (args, cb) { npm.commands[section].usage) { npm.config.set('loglevel', 'silent') log.level = 'silent' - console.log(npm.commands[section].usage) + output(npm.commands[section].usage) return cb() } @@ -161,7 +162,7 @@ function htmlMan (man) { function npmUsage (valid, cb) { npm.config.set('loglevel', 'silent') log.level = 'silent' - console.log([ + output([ '\nUsage: npm <command>', '', 'where <command> is one of:', diff --git a/deps/npm/lib/init.js b/deps/npm/lib/init.js index e3eb3d40dd..a5d102c1f3 100644 --- a/deps/npm/lib/init.js +++ b/deps/npm/lib/init.js @@ -5,15 +5,17 @@ module.exports = init var log = require('npmlog') var npm = require('./npm.js') var initJson = require('init-package-json') +var output = require('./utils/output.js') init.usage = 'npm init [--force|-f|--yes|-y]' function init (args, cb) { var dir = process.cwd() log.pause() + log.disableProgress() var initFile = npm.config.get('init-module') if (!initJson.yes(npm.config)) { - console.log([ + output([ 'This utility will walk you through creating a package.json file.', 'It only covers the most common items, and tries to guess sensible defaults.', '', diff --git a/deps/npm/lib/install.js b/deps/npm/lib/install.js index 53153e1463..1fb5a4f4e6 100644 --- a/deps/npm/lib/install.js +++ b/deps/npm/lib/install.js @@ -113,6 +113,7 @@ var lock = locker.lock var unlock = locker.unlock var ls = require('./ls.js') var parseJSON = require('./utils/parse-json.js') +var output = require('./utils/output.js') // install specific libraries var copyTree = require('./install/copy-tree.js') @@ -123,7 +124,6 @@ var loadDevDeps = require('./install/deps.js').loadDevDeps var getAllMetadata = require('./install/deps.js').getAllMetadata var loadRequestedDeps = require('./install/deps.js').loadRequestedDeps var loadExtraneous = require('./install/deps.js').loadExtraneous -var pruneTree = require('./install/prune-tree.js') var diffTrees = require('./install/diff-trees.js') var checkPermissions = require('./install/check-permissions.js') var decomposeActions = require('./install/decompose-actions.js') @@ -136,9 +136,11 @@ var doSerialActions = require('./install/actions.js').doSerial var doReverseSerialActions = require('./install/actions.js').doReverseSerial var doParallelActions = require('./install/actions.js').doParallel var doOneAction = require('./install/actions.js').doOne +var removeObsoleteDep = require('./install/deps.js').removeObsoleteDep var packageId = require('./utils/package-id.js') var moduleName = require('./utils/module-name.js') var errorMessage = require('./utils/error-message.js') +var andIgnoreErrors = require('./install/and-ignore-errors.js') function unlockCB (lockPath, name, cb) { validate('SSF', arguments) @@ -363,9 +365,8 @@ Installer.prototype.loadIdealTree = function (cb) { [this, this.loadAllDepsIntoIdealTree], [this, this.finishTracker, 'loadAllDepsIntoIdealTree'], - [this, function (next) { recalculateMetadata(this.idealTree, log, next) }], - [this, this.debugTree, 'idealTree:prePrune', 'idealTree'], - [this, function (next) { next(pruneTree(this.idealTree)) }] + // TODO: Remove this (should no longer be necessary, instead counter productive) + [this, function (next) { recalculateMetadata(this.idealTree, log, next) }] ], cb) } @@ -419,21 +420,18 @@ Installer.prototype.computeLinked = function (cb) { var cmd = action[0] var pkg = action[1] if (cmd !== 'add' && cmd !== 'update') return next() - var isReqByTop = pkg.package._requiredBy.filter(function (name) { return name === '/' }).length - var isReqByUser = pkg.package._requiredBy.filter(function (name) { return name === '#USER' }).length - var isExtraneous = pkg.package._requiredBy.length === 0 + var isReqByTop = pkg.requiredBy.filter(function (mod) { return mod.isTop }).length + var isReqByUser = pkg.userRequired + var isExtraneous = pkg.requiredBy.length === 0 if (!isReqByTop && !isReqByUser && !isExtraneous) return next() isLinkable(pkg, function (install, link) { if (install) linkTodoList.push(['global-install', pkg]) if (link) linkTodoList.push(['global-link', pkg]) - if (install || link) { - pkg.parent.children = pkg.parent.children.filter(function (child) { return child !== pkg }) - } + if (install || link) removeObsoleteDep(pkg) next() }) }, function () { if (linkTodoList.length === 0) return cb() - pruneTree(self.idealTree) self.differences.length = 0 Array.prototype.push.apply(self.differences, linkTodoList) diffTrees(self.currentTree, self.idealTree, self.differences, log.newGroup('d2'), cb) @@ -633,8 +631,8 @@ Installer.prototype.normalizeTree = function (log, cb) { log.silly('install', 'normalizeTree') recalculateMetadata(this.currentTree, log, iferr(cb, function (tree) { tree.children.forEach(function (child) { - if (child.package._requiredBy.length === 0) { - child.package._requiredBy.push('#EXISTING') + if (child.requiredBy.length === 0) { + child.existing = true } }) cb(null, tree) @@ -655,17 +653,16 @@ Installer.prototype.printInstalled = function (cb) { validate('F', arguments) log.silly('install', 'printInstalled') var self = this - log.clearProgress() this.differences.forEach(function (action) { var mutation = action[0] var child = action[1] var name = packageId(child) var where = path.relative(self.where, child.path) if (mutation === 'remove') { - console.log('- ' + name + ' ' + where) + output('- ' + name + ' ' + where) } else if (mutation === 'move') { var oldWhere = path.relative(self.where, child.fromPath) - console.log(name + ' ' + oldWhere + ' -> ' + where) + output(name + ' ' + oldWhere + ' -> ' + where) } }) var addedOrMoved = this.differences.filter(function (action) { @@ -676,10 +673,9 @@ Installer.prototype.printInstalled = function (cb) { var child = action[1] return child.path }) - log.showProgress() if (!addedOrMoved.length) return cb() + // TODO: remove the recalculateMetadata, should not be needed recalculateMetadata(this.idealTree, log, iferr(cb, function (tree) { - log.clearProgress() // These options control both how installs happen AND how `ls` shows output. // Something like `npm install --production` only installs production deps. // By contrast `npm install --production foo` installs `foo` and the @@ -691,10 +687,7 @@ Installer.prototype.printInstalled = function (cb) { npm.config.set('dev', false) npm.config.set('only', '') npm.config.set('also', '') - ls.fromTree(self.where, tree, addedOrMoved, false, function () { - log.showProgress() - cb() - }) + ls.fromTree(self.where, tree, addedOrMoved, false, andIgnoreErrors(cb)) })) } diff --git a/deps/npm/lib/install/actions.js b/deps/npm/lib/install/actions.js index 5d162f86d0..1c7462030c 100644 --- a/deps/npm/lib/install/actions.js +++ b/deps/npm/lib/install/actions.js @@ -63,7 +63,7 @@ function andHandleOptionalDepErrors (pkg, next) { return function (er) { if (!er) return next.apply(null, arguments) markAsFailed(pkg) - var anyFatal = pkg.userRequired || !pkg.parent + var anyFatal = pkg.userRequired || pkg.isTop for (var ii = 0; ii < pkg.requiredBy.length; ++ii) { var parent = pkg.requiredBy[ii] var isFatal = failedDependency(parent, pkg) diff --git a/deps/npm/lib/install/deps.js b/deps/npm/lib/install/deps.js index edc317f846..886e841913 100644 --- a/deps/npm/lib/install/deps.js +++ b/deps/npm/lib/install/deps.js @@ -10,6 +10,7 @@ var iferr = require('iferr') var npa = require('npm-package-arg') var validate = require('aproba') var realizePackageSpecifier = require('realize-package-specifier') +var asap = require('asap') var dezalgo = require('dezalgo') var fetchPackageMetadata = require('../fetch-package-metadata.js') var andAddParentToErrors = require('./and-add-parent-to-errors.js') @@ -78,15 +79,17 @@ function doesChildVersionMatch (child, requested, requestor) { return semver.satisfies(child.package.version, requested.spec) } +// TODO: Rename to maybe computeMetadata or computeRelationships exports.recalculateMetadata = function (tree, log, next) { recalculateMetadata(tree, log, {}, next) } +exports._childDependencySpecifier = childDependencySpecifier function childDependencySpecifier (tree, name, spec, cb) { if (!tree.resolved) tree.resolved = {} if (!tree.resolved[name]) tree.resolved[name] = {} if (tree.resolved[name][spec]) { - return process.nextTick(function () { + return asap(function () { cb(null, tree.resolved[name][spec]) }) } @@ -101,19 +104,24 @@ function recalculateMetadata (tree, log, seen, next) { validate('OOOF', arguments) if (seen[tree.path]) return next() seen[tree.path] = true - if (tree.parent == null) resetMetadata(tree) - function markDeps (spec, done) { - validate('SF', arguments) - var matched = spec.match(/^(@?[^@]+)@(.*)$/) - childDependencySpecifier(tree, matched[1], matched[2], function (er, req) { + if (tree.parent == null) { + resetMetadata(tree) + tree.isTop = true + } + + function markDeps (toMark, done) { + var name = toMark.name + var spec = toMark.spec + var kind = toMark.kind + childDependencySpecifier(tree, name, spec, function (er, req) { if (er || !req.name) return done() var child = findRequirement(tree, req.name, req) if (child) { resolveWithExistingModule(child, tree, log, andIgnoreErrors(done)) - } else if (tree.package.dependencies[req.name] != null) { + } else if (kind === 'dep') { tree.missingDeps[req.name] = req.rawSpec done() - } else if (tree.package.devDependencies[req.name] != null) { + } else if (kind === 'dev') { tree.missingDevDeps[req.name] = req.rawSpec done() } else { @@ -121,15 +129,16 @@ function recalculateMetadata (tree, log, seen, next) { } }) } - function specs (deps) { - return Object.keys(deps).map(function (depname) { return depname + '@' + deps[depname] }) + + function makeMarkable (deps, kind) { + if (!deps) return [] + return Object.keys(deps).map(function (depname) { return { name: depname, spec: deps[depname], kind: kind } }) } // Ensure dependencies and dev dependencies are marked as required - var tomark = specs(tree.package.dependencies) - if (!tree.parent && (npm.config.get('dev') || !npm.config.get('production'))) { - tomark = union(tomark, specs(tree.package.devDependencies)) - } + var tomark = makeMarkable(tree.package.dependencies, 'dep') + if (tree.isTop) tomark = union(tomark, makeMarkable(tree.package.devDependencies, 'dev')) + // Ensure any children ONLY from a shrinkwrap are also included var childrenOnlyInShrinkwrap = tree.children.filter(function (child) { return child.fromShrinkwrap && @@ -137,7 +146,13 @@ function recalculateMetadata (tree, log, seen, next) { !tree.package.devDependencies[child.package.name] }) var tomarkOnlyInShrinkwrap = childrenOnlyInShrinkwrap.map(function (child) { - return child.package._spec + var name = child.package.name + var matched = child.package._spec.match(/^@?[^@]+@(.*)$/) + var spec = matched ? matched[1] : child.package._spec + var kind = tree.package.dependencies[name] ? 'dep' + : tree.package.devDependencies[name] ? 'dev' + : 'dep' + return { name: name, spec: spec, kind: kind } }) tomark = union(tomark, tomarkOnlyInShrinkwrap) @@ -148,9 +163,7 @@ function recalculateMetadata (tree, log, seen, next) { [asyncMap, tomark, markDeps], [asyncMap, tree.children, function (child, done) { recalculateMetadata(child, log, seen, done) }] ], function () { - tree.userRequired = tree.package._requiredBy.some(function (req) { return req === '#USER' }) - tree.existing = tree.package._requiredBy.some(function (req) { return req === '#EXISTING' }) - tree.package._location = flatNameFromTree(tree) + tree.location = flatNameFromTree(tree) next(null, tree) }) } @@ -158,18 +171,23 @@ function recalculateMetadata (tree, log, seen, next) { function addRequiredDep (tree, child, cb) { isDep(tree, child, function (childIsDep, childIsProdDep, childIsDevDep) { if (!childIsDep) return cb(false) - var name = childIsProdDep ? flatNameFromTree(tree) : '#DEV:' + flatNameFromTree(tree) - replaceModuleName(child.package, '_requiredBy', name) - replaceModule(child, 'requiredBy', tree) - replaceModule(tree, 'requires', child) + replaceModuleByPath(child, 'requiredBy', tree) + replaceModuleByName(tree, 'requires', child) + if (childIsProdDep && tree.missingDeps) delete tree.missingDeps[moduleName(child)] + if (childIsDevDep && tree.missingDevDeps) delete tree.missingDevDeps[moduleName(child)] cb(true) }) } -exports._removeObsoleteDep = removeObsoleteDep +exports.removeObsoleteDep = removeObsoleteDep function removeObsoleteDep (child) { if (child.removed) return child.removed = true + // remove from physical tree + if (child.parent) { + child.parent.children = child.parent.children.filter(function (pchild) { return pchild !== child }) + } + // remove from logical tree var requires = child.requires || [] requires.forEach(function (requirement) { requirement.requiredBy = requirement.requiredBy.filter(function (reqBy) { return reqBy !== child }) @@ -243,9 +261,7 @@ exports.loadRequestedDeps = function (args, tree, saveToDependencies, log, next) // won't be when we're done), flag it as "depending" on the user // themselves, so we don't remove it as a dep that no longer exists addRequiredDep(tree, child, function (childIsDep) { - if (!childIsDep) { - replaceModuleName(child.package, '_requiredBy', '#USER') - } + if (!childIsDep) child.userRequired = true depLoaded(null, child, tracker) }) })) @@ -266,13 +282,13 @@ exports.removeDeps = function (args, tree, saveToDependencies, log, next) { validate('AOOF', [args, tree, log, next]) args.forEach(function (pkg) { var pkgName = moduleName(pkg) + var toRemove = tree.children.filter(moduleNameMatches(pkgName)) + var pkgToRemove = toRemove[0] || createChild({package: {name: pkgName}}) if (saveToDependencies) { - var toRemove = tree.children.filter(moduleNameMatches(pkgName)) - var pkgToRemove = toRemove[0] || createChild({package: {name: pkgName}}) - replaceModule(tree, 'removed', pkgToRemove) + replaceModuleByPath(tree, 'removed', pkgToRemove) pkgToRemove.save = saveToDependencies } - tree.children = tree.children.filter(noModuleNameMatches(pkgName)) + removeObsoleteDep(pkgToRemove) }) log.finish() next() @@ -313,7 +329,6 @@ var failedDependency = exports.failedDependency = function (tree, name_pkg) { pkg = name_pkg name = moduleName(pkg) } - tree.children = tree.children.filter(noModuleNameMatches(name)) if (isDepOptional(tree, name)) { @@ -322,10 +337,14 @@ var failedDependency = exports.failedDependency = function (tree, name_pkg) { tree.failed = true - if (!tree.parent) return true + if (tree.isTop) return true if (tree.userRequired) return true + removeObsoleteDep(tree) + + if (!tree.requiredBy) return false + for (var ii = 0; ii < tree.requiredBy.length; ++ii) { var requireParent = tree.requiredBy[ii] if (failedDependency(requireParent, tree.package)) { @@ -367,7 +386,7 @@ function andHandleOptionalErrors (log, tree, name, done) { exports.loadDeps = loadDeps function loadDeps (tree, log, next) { validate('OOF', arguments) - if (tree.loaded || (tree.parent && tree.parent.failed)) return andFinishTracker.now(log, next) + if (tree.loaded || (tree.parent && tree.parent.failed) || tree.removed) return andFinishTracker.now(log, next) if (tree.parent) tree.loaded = true if (!tree.package.dependencies) tree.package.dependencies = {} asyncMap(Object.keys(tree.package.dependencies), function (dep, done) { @@ -446,38 +465,44 @@ function resolveWithExistingModule (child, tree, log, next) { var updatePhantomChildren = exports.updatePhantomChildren = function (current, child) { validate('OO', arguments) while (current && current !== child.parent) { - // FIXME: phantomChildren doesn't actually belong in the package.json - if (!current.package._phantomChildren) current.package._phantomChildren = {} - current.package._phantomChildren[moduleName(child)] = child.package.version + if (!current.phantomChildren) current.phantomChildren = {} + current.phantomChildren[moduleName(child)] = child current = current.parent } } function flatNameFromTree (tree) { validate('O', arguments) - if (!tree.parent) return '/' + if (tree.isTop) return '/' var path = flatNameFromTree(tree.parent) if (path !== '/') path += '/' return flatName(path, tree) } -exports._replaceModuleName = replaceModuleName -function replaceModuleName (obj, key, name) { - validate('OSS', arguments) - obj[key] = union(obj[key] || [], [name]) +exports._replaceModuleByPath = replaceModuleByPath +function replaceModuleByPath (obj, key, child) { + return replaceModule(obj, key, child, function (replacing, child) { + return replacing.path === child.path + }) +} + +exports._replaceModuleByName = replaceModuleByName +function replaceModuleByName (obj, key, child) { + var childName = moduleName(child) + return replaceModule(obj, key, child, function (replacing, child) { + return moduleName(replacing) === childName + }) } -exports._replaceModule = replaceModule -function replaceModule (obj, key, child) { - validate('OSO', arguments) +function replaceModule (obj, key, child, matchBy) { + validate('OSOF', arguments) if (!obj[key]) obj[key] = [] // we replace children with a new array object instead of mutating it // because mutating it results in weird failure states. // I would very much like to know _why_ this is. =/ var children = [].concat(obj[key]) - var childName = moduleName(child) for (var replaceAt = 0; replaceAt < children.length; ++replaceAt) { - if (moduleName(children[replaceAt]) === childName) break + if (matchBy(children[replaceAt], child)) break } var replacing = children.splice(replaceAt, 1, child) obj[key] = children @@ -514,15 +539,17 @@ function resolveWithNewModule (pkg, tree, log, next) { children: pkg._bundled || [], isLink: tree.isLink }) + delete pkg._bundled + var hasBundled = child.children.length - var replaced = replaceModule(parent, 'children', child) + var replaced = replaceModuleByName(parent, 'children', child) if (replaced) removeObsoleteDep(replaced) addRequiredDep(tree, child, function () { - pkg._location = flatNameFromTree(child) + child.location = flatNameFromTree(child) if (tree.parent && parent !== tree) updatePhantomChildren(tree.parent, child) - if (pkg._bundled) { + if (hasBundled) { inflateBundled(child, child.children) } @@ -584,7 +611,7 @@ var findRequirement = exports.findRequirement = function (tree, name, requested, if (matches.length) return matches[0] return null } - if (!tree.parent) return null + if (tree.isTop) return null return findRequirement(tree.parent, name, requested, requestor) } @@ -618,13 +645,12 @@ var earliestInstallable = exports.earliestInstallable = function (requiredBy, tr return null } - // FIXME: phantomChildren doesn't actually belong in the package.json - if (tree.package._phantomChildren && tree.package._phantomChildren[pkg.name]) return null + if (tree.phantomChildren && tree.phantomChildren[pkg.name]) return null - if (!tree.parent) return tree + if (tree.isTop) return tree if (tree.isGlobal) return tree - if (npm.config.get('global-style') && !tree.parent.parent) return tree + if (npm.config.get('global-style') && tree.parent.isTop) return tree if (npm.config.get('legacy-bundling')) return tree return (earliestInstallable(requiredBy, tree.parent, pkg) || tree) diff --git a/deps/npm/lib/install/diff-trees.js b/deps/npm/lib/install/diff-trees.js index 8000124604..578cda90ce 100644 --- a/deps/npm/lib/install/diff-trees.js +++ b/deps/npm/lib/install/diff-trees.js @@ -59,17 +59,15 @@ function requiredByAllLinked (node) { return node.requiredBy.filter(isLink).length === node.requiredBy.length } -function isNotReqByTop (req) { - return req !== '/' && // '/' is the top level itself - req !== '#USER' && // #USER - req !== '#EXTRANEOUS' +function isNotTopOrExtraneous (node) { + return !node.isTop && !node.userRequired && !node.existing } var sortActions = module.exports.sortActions = function (differences) { var actions = {} differences.forEach(function (action) { var child = action[1] - actions[child.package._location] = action + actions[child.location] = action }) var sorted = [] @@ -77,14 +75,18 @@ var sortActions = module.exports.sortActions = function (differences) { var sortedlocs = Object.keys(actions).sort(sortByLocation) - // Do top level deps first, this stops the sorting by required order from - // unsorting these deps. + // We're going to sort the actions taken on top level dependencies first, before + // considering the order of transitive deps. Because we're building our list + // from the bottom up, this means we will return a list with top level deps LAST. + // This is important in terms of keeping installations as consistent as possible + // as folks add new dependencies. var toplocs = sortedlocs.filter(function (location) { var mod = actions[location][1] - if (!mod.package._requiredBy) return true - // If the module is required by ANY non-top level package - // then we don't want to include this. - return !mod.package._requiredBy.some(isNotReqByTop) + if (!mod.requiredBy) return true + // If this module is required by any non-top level module + // or by any extraneous module, eg user requested or existing + // then we don't want to give this priority sorting. + return !mod.requiredBy.some(isNotTopOrExtraneous) }) toplocs.concat(sortedlocs).forEach(function (location) { @@ -94,12 +96,16 @@ var sortActions = module.exports.sortActions = function (differences) { function sortByLocation (aa, bb) { return bb.localeCompare(aa) } + function sortModuleByLocation (aa, bb) { + return sortByLocation(aa && aa.location, bb && bb.location) + } function sortByDeps (action) { var mod = action[1] - if (added[mod.package._location]) return - added[mod.package._location] = action - mod.package._requiredBy.sort().forEach(function (location) { - if (actions[location]) sortByDeps(actions[location]) + if (added[mod.location]) return + added[mod.location] = action + if (!mod.requiredBy) mod.requiredBy = [] + mod.requiredBy.sort(sortModuleByLocation).forEach(function (mod) { + if (actions[mod.location]) sortByDeps(actions[mod.location]) }) sorted.unshift(action) } diff --git a/deps/npm/lib/install/inflate-shrinkwrap.js b/deps/npm/lib/install/inflate-shrinkwrap.js index b38181b9f1..1853f2c068 100644 --- a/deps/npm/lib/install/inflate-shrinkwrap.js +++ b/deps/npm/lib/install/inflate-shrinkwrap.js @@ -55,6 +55,7 @@ var inflateShrinkwrap = module.exports = function (tree, swdeps, finishInflating }) tree.children.push(child) if (pkg._bundled) { + delete pkg._bundled inflateBundled(child, child.children) } inflateShrinkwrap(child, sw.dependencies || {}, next) diff --git a/deps/npm/lib/install/is-dev.js b/deps/npm/lib/install/is-dev.js index b1f2c4b661..e0fae4eb82 100644 --- a/deps/npm/lib/install/is-dev.js +++ b/deps/npm/lib/install/is-dev.js @@ -1,7 +1,26 @@ 'use strict' -var isDev = exports.isDev = function (node) { - return node.package._requiredBy.some(function (req) { return req === '#DEV:/' }) +var moduleName = require('../utils/module-name.js') + +function andIsDev (name) { + return function (req) { + return req.package && + req.package.devDependencies && + req.package.devDependencies[name] + } } + +exports.isDev = function (node) { + return node.requiredBy.some(andIsDev(moduleName(node))) +} + +function andIsOnlyDev (name) { + var isThisDev = andIsDev(name) + return function (req) { + return isThisDev(req) && + (!req.package.dependencies || !req.package.dependencies[name]) + } +} + exports.isOnlyDev = function (node) { - return node.package._requiredBy.length === 1 && isDev(node) + return node.requiredBy.every(andIsOnlyDev(moduleName(node))) } diff --git a/deps/npm/lib/install/is-extraneous.js b/deps/npm/lib/install/is-extraneous.js index cd4d954668..f0d599965f 100644 --- a/deps/npm/lib/install/is-extraneous.js +++ b/deps/npm/lib/install/is-extraneous.js @@ -1,14 +1,37 @@ 'use strict' -var path = require('path') -var isDev = require('./is-dev.js').isDev -var npm = require('../npm.js') - -module.exports = function (tree) { - var pkg = tree.package - var requiredBy = pkg._requiredBy.filter(function (req) { return req[0] !== '#' }) - var isTopLevel = tree.parent == null - var isChildOfTop = !isTopLevel && tree.parent.parent == null - var isTopGlobal = isChildOfTop && tree.parent.path === path.resolve(npm.globalDir, '..') - var topHasNoPackageJson = isChildOfTop && tree.parent.error - return !isTopLevel && (!isChildOfTop || !topHasNoPackageJson) && !isTopGlobal && requiredBy.length === 0 && !isDev(tree) +module.exports = isExtraneous + +function isExtraneous (tree) { + var result = !isNotExtraneous(tree) + return result +} + +function isNotRequired (tree) { + return tree.requiredBy && tree.requiredBy.length === 0 +} + +function parentHasNoPjson (tree) { + return tree.parent && tree.parent.isTop && tree.parent.error +} + +function topHasNoPjson (tree) { + var top = tree + while (!top.isTop) top = top.parent + return top.error +} + +function isNotExtraneous (tree, isCycle) { + if (!isCycle) isCycle = {} + if (tree.isTop || tree.userRequired) { + return true + } else if (isNotRequired(tree) && parentHasNoPjson(tree)) { + return true + } else if (isCycle[tree.path]) { + return topHasNoPjson(tree) + } else { + isCycle[tree.path] = true + return tree.requiredBy && tree.requiredBy.some(function (node) { + return isNotExtraneous(node, Object.create(isCycle)) + }) + } } diff --git a/deps/npm/lib/install/mutate-into-logical-tree.js b/deps/npm/lib/install/mutate-into-logical-tree.js index 833aa94c94..b2059da906 100644 --- a/deps/npm/lib/install/mutate-into-logical-tree.js +++ b/deps/npm/lib/install/mutate-into-logical-tree.js @@ -8,6 +8,24 @@ var validateAllPeerDeps = require('./deps.js').validateAllPeerDeps var packageId = require('../utils/package-id.js') var moduleName = require('../utils/module-name.js') +// Return true if tree is a part of a cycle that: +// A) Never connects to the top of the tree +// B) Has not not had a point in the cycle arbitraryly declared its top +// yet. +function isDisconnectedCycle (tree, seen) { + if (!seen) seen = {} + if (tree.isTop || tree.cycleTop || tree.requiredBy.length === 0) { + return false + } else if (seen[tree.path]) { + return true + } else { + seen[tree.path] = true + return tree.requiredBy.every(function (node) { + return isDisconnectedCycle(node, Object.create(seen)) + }) + } +} + var mutateIntoLogicalTree = module.exports = function (tree) { validate('O', arguments) @@ -18,35 +36,29 @@ var mutateIntoLogicalTree = module.exports = function (tree) { var flat = flattenTree(tree) - function getNode (flatname) { - return flatname.substr(0, 5) === '#DEV:' - ? flat[flatname.substr(5)] - : flat[flatname] - } - Object.keys(flat).sort().forEach(function (flatname) { var node = flat[flatname] - var requiredBy = node.package._requiredBy || [] - var requiredByNames = requiredBy.filter(function (parentFlatname) { - var parentNode = getNode(parentFlatname) - if (!parentNode) return false - return parentNode.package.dependencies[moduleName(node)] || - (parentNode.package.devDependencies && parentNode.package.devDependencies[moduleName(node)]) - }) - requiredBy = requiredByNames.map(getNode) - - node.requiredBy = requiredBy - - if (!requiredBy.length) return + if (!node.requiredBy.length) return - if (node.parent) node.parent.children = without(node.parent.children, node) + if (node.parent) { + // If a node is a cycle that never reaches the root of the logical + // tree then we'll leave it attached to the root, or else it + // would go missing. Further we'll note that this is the node in the + // cycle that we picked arbitrarily to be the one attached to the root. + // others will fall + if (isDisconnectedCycle(node)) { + node.cycleTop = true + // Nor do we want to disconnect non-cyclical extraneous modules from the tree. + } else if (node.requiredBy.length) { + // regular deps though, we do, as we're moving them into the capable + // hands of the modules that require them. + node.parent.children = without(node.parent.children, node) + } + } - requiredBy.forEach(function (parentNode) { + node.requiredBy.forEach(function (parentNode) { parentNode.children = union(parentNode.children, [node]) }) - if (node.package._requiredBy.some(function (nodename) { return nodename[0] === '#' })) { - tree.children = union(tree.children, [node]) - } }) return tree } @@ -70,18 +82,27 @@ function translateTree_ (tree, seen) { tree.children.forEach(function (child) { pkg.dependencies[moduleName(child)] = translateTree_(child, seen) }) - Object.keys(tree.missingDeps).forEach(function (name) { + + function markMissing (name, requiredBy) { if (pkg.dependencies[name]) { + if (pkg.dependencies[name].missing) return pkg.dependencies[name].invalid = true pkg.dependencies[name].realName = name pkg.dependencies[name].extraneous = false } else { pkg.dependencies[name] = { - requiredBy: tree.missingDeps[name], + requiredBy: requiredBy, missing: true, optional: !!pkg.optionalDependencies[name] } } + } + + Object.keys(tree.missingDeps).forEach(function (name) { + markMissing(name, tree.missingDeps[name]) + }) + Object.keys(tree.missingDevDeps).forEach(function (name) { + markMissing(name, tree.missingDevDeps[name]) }) var checkForMissingPeers = (tree.parent ? [] : [tree]).concat(tree.children) checkForMissingPeers.filter(function (child) { diff --git a/deps/npm/lib/install/node.js b/deps/npm/lib/install/node.js index c76dc765ba..a5b766b054 100644 --- a/deps/npm/lib/install/node.js +++ b/deps/npm/lib/install/node.js @@ -2,11 +2,10 @@ var defaultTemplate = { package: { + version: '', dependencies: {}, devDependencies: {}, - optionalDependencies: {}, - _requiredBy: [], - _phantomChildren: {} + optionalDependencies: {} }, loaded: false, children: [], @@ -14,10 +13,13 @@ var defaultTemplate = { requires: [], missingDeps: {}, missingDevDeps: {}, + phantomChildren: {}, path: null, realpath: null, + location: null, userRequired: false, - existing: false + existing: false, + isTop: false } function isLink (node) { @@ -34,7 +36,7 @@ var create = exports.create = function (node, template) { if (node[key] != null) return node[key] = template[key] }) - if (isLink(node) || isLink(node.parent)) { + if (isLink(node.parent)) { node.isLink = true } return node @@ -48,14 +50,17 @@ function reset (node, seen) { if (seen[node.path]) return seen[node.path] = true var child = create(node) - child.package._requiredBy = child.package._requiredBy.filter(function (req) { - return req[0] === '#' - }) - child.requiredBy = [] - child.package._phantomChildren = {} + // FIXME: cleaning up after read-package-json's mess =( if (child.package._id === '@') delete child.package._id + + child.isTop = false + child.requiredBy = [] + child.requires = [] child.missingDeps = {} + child.missingDevDeps = {} + child.phantomChildren = {} + child.location = null + child.children.forEach(function (child) { reset(child, seen) }) - if (!child.package.version) child.package.version = '' } diff --git a/deps/npm/lib/install/prune-tree.js b/deps/npm/lib/install/prune-tree.js deleted file mode 100644 index eb3edf4f75..0000000000 --- a/deps/npm/lib/install/prune-tree.js +++ /dev/null @@ -1,36 +0,0 @@ -'use strict' -var validate = require('aproba') -var flattenTree = require('./flatten-tree.js') - -function isNotPackage (mod) { - return function (parentMod) { return mod !== parentMod } -} - -module.exports = function pruneTree (tree) { - validate('O', arguments) - var flat = flattenTree(tree) - // we just do this repeatedly until there are no more orphaned packages - // which isn't as effecient as it could be on a REALLY big tree - // but we'll face that if it proves to be an issue - var removedPackage - do { - removedPackage = false - Object.keys(flat).forEach(function (flatname) { - var child = flat[flatname] - if (!child.parent) return - child.package._requiredBy = (child.package._requiredBy || []).filter(function (req) { - var isDev = req.substr(0, 4) === '#DEV' - if (req[0] === '#' && !isDev) return true - if (flat[req]) return true - if (!isDev) return false - var reqChildAsDevDep = flat[req.substr(5)] - return reqChildAsDevDep && !reqChildAsDevDep.parent - }) - if (!child.package._requiredBy.length) { - removedPackage = true - delete flat[flatname] - child.parent.children = child.parent.children.filter(isNotPackage(child)) - } - }) - } while (removedPackage) -} diff --git a/deps/npm/lib/install/save.js b/deps/npm/lib/install/save.js index acbe8c5bb3..708da61c8a 100644 --- a/deps/npm/lib/install/save.js +++ b/deps/npm/lib/install/save.js @@ -12,6 +12,7 @@ var npm = require('../npm.js') var deepSortObject = require('../utils/deep-sort-object.js') var parseJSON = require('../utils/parse-json.js') var moduleName = require('../utils/module-name.js') +var isOnlyDev = require('./is-dev.js').isOnlyDev // if the -S|--save option is specified, then write installed packages // as dependencies to a package.json file. @@ -49,8 +50,7 @@ function saveShrinkwrap (tree, next) { var shrinkwrap = tree.package._shrinkwrap || {dependencies: {}} var hasDevOnlyDeps = tree.requires.filter(function (dep) { - var devReqs = dep.package._requiredBy.filter(function (name) { return name.substr(0, 4) === '#DEV' }) - return devReqs.length === dep.package._requiredBy.length + return isOnlyDev(dep) }).some(function (dep) { return shrinkwrap.dependencies[dep.package.name] != null }) diff --git a/deps/npm/lib/install/update-package-json.js b/deps/npm/lib/install/update-package-json.js index 97b2f05bb0..eee530c3cd 100644 --- a/deps/npm/lib/install/update-package-json.js +++ b/deps/npm/lib/install/update-package-json.js @@ -1,18 +1,46 @@ 'use strict' var path = require('path') var writeFileAtomic = require('write-file-atomic') +var moduleName = require('../utils/module-name.js') var deepSortObject = require('../utils/deep-sort-object.js') +var sortedObject = require('sorted-object') + +var sortKeys = [ + 'dependencies', 'devDependencies', 'bundleDependencies', + 'optionalDependencies', 'keywords', 'engines', 'scripts', + 'files' +] + +module.exports = function (mod, buildpath, next) { + var pkg = sortedObject(mod.package) + var name = moduleName(mod) + // Add our diagnostic keys to the package.json. + // Note that there are folks relying on these, for ex, the Visual Studio + // Node.js addon. + pkg._requiredBy = + mod.requiredBy + .map(function (req) { + if (req.package.devDependencies[name] && !req.package.dependencies[name]) { + return '#DEV:' + req.location + } else { + return req.location + } + }) + .concat(mod.userRequired ? ['#USER'] : []) + .concat(mod.existing ? ['#EXISTING'] : []) + .sort() + pkg._location = mod.location + pkg._phantomChildren = {} + Object.keys(mod.phantomChildren).sort().forEach(function (name) { + pkg._phantomChildren[name] = mod.phantomChildren[name].package.version + }) + + // sort keys that are known safe to sort to produce more consistent output + sortKeys.forEach(function (key) { + if (pkg[key] != null) pkg[key] = deepSortObject(pkg[key]) + }) + + var data = JSON.stringify(sortedObject(pkg), null, 2) + '\n' -module.exports = function (pkg, buildpath, next) { - // FIXME: This bundled dance is because we're sticking a big tree of bundled - // deps into the parsed package.json– it probably doesn't belong there =/ - // But the real reason we don't just dump it out is that it's the result - // of npm-read-tree, which produces circular data structures, due to the - // parent and children keys. - var bundled = pkg.package._bundled - delete pkg.package._bundled // FIXME - var packagejson = deepSortObject(pkg.package) - var data = JSON.stringify(packagejson, null, 2) + '\n' - pkg.package._bundled = bundled writeFileAtomic(path.resolve(buildpath, 'package.json'), data, next) } diff --git a/deps/npm/lib/link.js b/deps/npm/lib/link.js index 3624a16c98..54b8dcac7a 100644 --- a/deps/npm/lib/link.js +++ b/deps/npm/lib/link.js @@ -11,6 +11,7 @@ var path = require('path') var build = require('./build.js') var npa = require('npm-package-arg') var usage = require('./utils/usage') +var output = require('./utils/output.js') module.exports = link @@ -179,9 +180,7 @@ function resultPrinter (pkg, src, dest, rp, cb) { return parseableOutput(dest, rp || src, cb) } if (rp === src) rp = null - log.clearProgress() - console.log(where + ' -> ' + src + (rp ? ' -> ' + rp : '')) - log.showProgress() + output(where + ' -> ' + src + (rp ? ' -> ' + rp : '')) cb() } @@ -193,8 +192,6 @@ function parseableOutput (dest, rp, cb) { // *just* print the target folder. // However, we don't actually ever read the version number, so // the second field is always blank. - log.clearProgress() - console.log(dest + '::' + rp) - log.showProgress() + output(dest + '::' + rp) cb() } diff --git a/deps/npm/lib/ls.js b/deps/npm/lib/ls.js index d2fe14fb2f..ba5ab16e51 100644 --- a/deps/npm/lib/ls.js +++ b/deps/npm/lib/ls.js @@ -20,6 +20,7 @@ var mutateIntoLogicalTree = require('./install/mutate-into-logical-tree.js') var recalculateMetadata = require('./install/deps.js').recalculateMetadata var packageId = require('./utils/package-id.js') var usage = require('./utils/usage') +var output = require('./utils/output.js') ls.usage = usage( 'ls', @@ -99,7 +100,7 @@ var lsFromTree = ls.fromTree = function (dir, physicalTree, args, silent, cb) { } else if (data) { out = makeArchy(bfs, long, dir) } - console.log(out) + output(out) if (args.length && !data._found) process.exitCode = 1 diff --git a/deps/npm/lib/npm.js b/deps/npm/lib/npm.js index 9d6cda386a..4f81015251 100644 --- a/deps/npm/lib/npm.js +++ b/deps/npm/lib/npm.js @@ -22,6 +22,7 @@ var npmconf = require('./config/core.js') var log = require('npmlog') + var tty = require('tty') var path = require('path') var abbrev = require('abbrev') var which = require('which') @@ -30,6 +31,7 @@ var aliases = require('./config/cmd-list').aliases var cmdList = require('./config/cmd-list').cmdList var plumbing = require('./config/cmd-list').plumbing + var output = require('./utils/output.js') npm.config = { loaded: false, @@ -140,7 +142,7 @@ function defaultCb (er, data) { log.disableProgress() if (er) console.error(er.stack || er.message) - else console.log(data) + else output(data) } npm.deref = function (c) { @@ -261,7 +263,6 @@ npm.color = false break default: - var tty = require('tty') if (process.stdout.isTTY) npm.color = true else if (!tty.isatty) npm.color = true else if (tty.isatty(1)) npm.color = true @@ -269,19 +270,19 @@ break } - log.resume() + if (config.get('unicode')) { + log.enableUnicode() + } else { + log.disableUnicode() + } - if (config.get('progress')) { + if (config.get('progress') && (process.stderr.isTTY || (tty.isatty && tty.isatty(2)))) { log.enableProgress() } else { log.disableProgress() } - if (config.get('unicode')) { - log.enableUnicode() - } else { - log.disableUnicode() - } + log.resume() // at this point the configs are all set. // go ahead and spin up the registry client. diff --git a/deps/npm/lib/outdated.js b/deps/npm/lib/outdated.js index 50bdb363d1..dd59798365 100644 --- a/deps/npm/lib/outdated.js +++ b/deps/npm/lib/outdated.js @@ -40,6 +40,7 @@ var mapToRegistry = require('./utils/map-to-registry.js') var isExtraneous = require('./install/is-extraneous.js') var recalculateMetadata = require('./install/deps.js').recalculateMetadata var moduleName = require('./utils/module-name.js') +var output = require('./utils/output.js') function uniqName (item) { return item[0].path + '|' + item[1] + '|' + item[7] @@ -75,6 +76,7 @@ function outdated (args, silent, cb) { if (npm.config.get('depth') === Infinity) npm.config.set('depth', 0) readPackageTree(dir, andRecalculateMetadata(function (er, tree) { + if (!tree) return cb(er) mutateIntoLogicalTree(tree) outdated_(args, '', tree, {}, 0, function (er, list) { list = uniq(list || []).sort(function (aa, bb) { @@ -82,11 +84,10 @@ function outdated (args, silent, cb) { aa[1].localeCompare(bb[1]) }) if (er || silent || list.length === 0) return cb(er, list) - log.disableProgress() if (npm.config.get('json')) { - console.log(makeJSON(list)) + output(makeJSON(list)) } else if (npm.config.get('parseable')) { - console.log(makeParseable(list)) + output(makeParseable(list)) } else { var outList = list.map(makePretty) var outHead = [ 'Package', @@ -108,7 +109,7 @@ function outdated (args, silent, cb) { align: ['l', 'r', 'r', 'r', 'l'], stringLength: function (s) { return ansiTrim(s).length } } - console.log(table(outTable, tableOpts)) + output(table(outTable, tableOpts)) } cb(null, list.map(function (item) { return [item[0].parent.path].concat(item.slice(1, 7)) })) }) @@ -142,8 +143,6 @@ function makePretty (p) { columns[0] = color[has === want || want === 'linked' ? 'yellow' : 'red'](columns[0]) // dep columns[2] = color.green(columns[2]) // want columns[3] = color.magenta(columns[3]) // latest - columns[4] = color.brightBlack(columns[4]) // dir - if (long) columns[5] = color.brightBlack(columns[5]) // type } return columns @@ -333,7 +332,7 @@ function shouldUpdate (args, tree, dep, has, req, depth, pkgpath, cb, type) { if (args.length && args.indexOf(dep) === -1) return skip() var parsed = npa(dep + '@' + req) - if (tree.isLink && (tree.parent !== null && tree.parent.parent === null)) { + if (tree.isLink && tree.parent && tree.parent.isTop) { return doIt('linked', 'linked') } if (parsed.type === 'git' || parsed.type === 'hosted') { diff --git a/deps/npm/lib/owner.js b/deps/npm/lib/owner.js index 2cc3eef3b9..64d086af78 100644 --- a/deps/npm/lib/owner.js +++ b/deps/npm/lib/owner.js @@ -5,6 +5,7 @@ var log = require('npmlog') var mapToRegistry = require('./utils/map-to-registry.js') var readLocalPkg = require('./utils/read-local-package.js') var usage = require('./utils/usage') +var output = require('./utils/output.js') owner.usage = usage( 'owner', @@ -127,7 +128,7 @@ function ls (pkg, cb) { return o.name + ' <' + o.email + '>' }).join('\n') } - console.log(msg) + output(msg) cb(er, owners) }) }) @@ -258,9 +259,9 @@ function mutate (pkg, user, mutation, cb) { if (er) { log.error('owner mutate', 'Failed to update package metadata') } else if (m.length > beforeMutation) { - console.log('+ %s (%s)', user, pkg) + output('+ %s (%s)', user, pkg) } else if (m.length < beforeMutation) { - console.log('- %s (%s)', user, pkg) + output('- %s (%s)', user, pkg) } cb(er, data) diff --git a/deps/npm/lib/pack.js b/deps/npm/lib/pack.js index c98f5f2020..ede59dd12c 100644 --- a/deps/npm/lib/pack.js +++ b/deps/npm/lib/pack.js @@ -12,6 +12,7 @@ var path = require('path') var cwd = process.cwd() var writeStreamAtomic = require('fs-write-stream-atomic') var cachedPackageRoot = require('./cache/cached-package-root.js') +var output = require('./utils/output.js') pack.usage = 'npm pack [[<@scope>/]<pkg>...]' @@ -39,7 +40,7 @@ function printFiles (files, cb) { files = files.map(function (file) { return path.relative(cwd, file) }) - console.log(files.join('\n')) + output(files.join('\n')) cb() } diff --git a/deps/npm/lib/ping.js b/deps/npm/lib/ping.js index 23b18bfba0..a86150508d 100644 --- a/deps/npm/lib/ping.js +++ b/deps/npm/lib/ping.js @@ -1,4 +1,5 @@ var npm = require('./npm.js') +var output = require('./utils/output.js') module.exports = ping @@ -14,7 +15,7 @@ function ping (args, silent, cb) { var auth = npm.config.getCredentialsByURI(registry) npm.registry.ping(registry, {auth: auth}, function (er, pong) { - if (!silent) console.log(JSON.stringify(pong)) + if (!silent) output(JSON.stringify(pong)) cb(er, er ? null : pong) }) } diff --git a/deps/npm/lib/prefix.js b/deps/npm/lib/prefix.js index 42f61103f6..fb20389c45 100644 --- a/deps/npm/lib/prefix.js +++ b/deps/npm/lib/prefix.js @@ -1,6 +1,7 @@ module.exports = prefix var npm = require('./npm.js') +var output = require('./utils/output.js') prefix.usage = 'npm prefix [-g]' @@ -9,6 +10,6 @@ function prefix (args, silent, cb) { cb = silent silent = false } - if (!silent) console.log(npm.prefix) + if (!silent) output(npm.prefix) process.nextTick(cb.bind(this, null, npm.prefix)) } diff --git a/deps/npm/lib/publish.js b/deps/npm/lib/publish.js index 45de4f24b4..e1826df9d4 100644 --- a/deps/npm/lib/publish.js +++ b/deps/npm/lib/publish.js @@ -13,6 +13,7 @@ var createReadStream = require('graceful-fs').createReadStream var npa = require('npm-package-arg') var semver = require('semver') var getPublishConfig = require('./utils/get-publish-config.js') +var output = require('./utils/output.js') publish.usage = 'npm publish [<tarball>|<folder>] [--tag <tag>] [--access <public|restricted>]' + "\n\nPublishes '.' if no argument supplied" + @@ -147,8 +148,7 @@ function publish_ (arg, data, isRetry, cachedir, cb) { // report the unpublish error if this was a retry and unpublish failed if (er && isRetry && isRetry !== true) return cb(isRetry) if (er) return cb(er) - log.clearProgress() - console.log('+ ' + data._id) + output('+ ' + data._id) cb() }) }) diff --git a/deps/npm/lib/rebuild.js b/deps/npm/lib/rebuild.js index 29492c27f2..2673b1cfea 100644 --- a/deps/npm/lib/rebuild.js +++ b/deps/npm/lib/rebuild.js @@ -7,6 +7,7 @@ var log = require('npmlog') var npm = require('./npm.js') var npa = require('npm-package-arg') var usage = require('./utils/usage') +var output = require('./utils/output.js') rebuild.usage = usage( 'rebuild', @@ -33,11 +34,9 @@ function rebuild (args, cb) { function cleanBuild (folders, set, cb) { npm.commands.build(folders, function (er) { if (er) return cb(er) - log.clearProgress() - console.log(folders.map(function (f) { + output(folders.map(function (f) { return set[f] + ' ' + f }).join('\n')) - log.showProgress() cb() }) } diff --git a/deps/npm/lib/root.js b/deps/npm/lib/root.js index 958361d351..82a804aff5 100644 --- a/deps/npm/lib/root.js +++ b/deps/npm/lib/root.js @@ -1,6 +1,7 @@ module.exports = root var npm = require('./npm.js') +var output = require('./utils/output.js') root.usage = 'npm root [-g]' @@ -9,6 +10,6 @@ function root (args, silent, cb) { cb = silent silent = false } - if (!silent) console.log(npm.dir) + if (!silent) output(npm.dir) process.nextTick(cb.bind(this, null, npm.dir)) } diff --git a/deps/npm/lib/run-script.js b/deps/npm/lib/run-script.js index f9c6872aa9..05bc1fe98b 100644 --- a/deps/npm/lib/run-script.js +++ b/deps/npm/lib/run-script.js @@ -7,6 +7,7 @@ var readJson = require('read-package-json') var log = require('npmlog') var chain = require('slide').chain var usage = require('./utils/usage') +var output = require('./utils/output.js') runScript.usage = usage( 'run-script', @@ -91,13 +92,13 @@ function list (cb) { } if (npm.config.get('json')) { - console.log(JSON.stringify(d.scripts || {}, null, 2)) + output(JSON.stringify(d.scripts || {}, null, 2)) return cb(null, allScripts) } if (npm.config.get('parseable')) { allScripts.forEach(function (script) { - console.log(script + ':' + d.scripts[script]) + output(script + ':' + d.scripts[script]) }) return cb(null, allScripts) } @@ -105,18 +106,18 @@ function list (cb) { var s = '\n ' var prefix = ' ' if (scripts.length) { - console.log('Lifecycle scripts included in %s:', d.name) + output('Lifecycle scripts included in %s:', d.name) } scripts.forEach(function (script) { - console.log(prefix + script + s + d.scripts[script]) + output(prefix + script + s + d.scripts[script]) }) if (!scripts.length && runScripts.length) { - console.log('Scripts available in %s via `npm run-script`:', d.name) + output('Scripts available in %s via `npm run-script`:', d.name) } else if (runScripts.length) { - console.log('\navailable via `npm run-script`:') + output('\navailable via `npm run-script`:') } runScripts.forEach(function (script) { - console.log(prefix + script + s + d.scripts[script]) + output(prefix + script + s + d.scripts[script]) }) return cb(null, allScripts) }) diff --git a/deps/npm/lib/search.js b/deps/npm/lib/search.js index d71102ac3e..cd6d5ed8ea 100644 --- a/deps/npm/lib/search.js +++ b/deps/npm/lib/search.js @@ -5,6 +5,7 @@ var npm = require('./npm.js') var columnify = require('columnify') var updateIndex = require('./cache/update-index.js') var usage = require('./utils/usage') +var output = require('./utils/output.js') search.usage = usage( 'search', @@ -70,7 +71,7 @@ function search (args, silent, staleness, cb) { // prettify and print it, and then provide the raw // data to the cb. if (er || silent) return cb(er, data) - console.log(prettify(data, args)) + output(prettify(data, args)) cb(null, data) }) } diff --git a/deps/npm/lib/shrinkwrap.js b/deps/npm/lib/shrinkwrap.js index 9a6d8e76bd..c6a41842fc 100644 --- a/deps/npm/lib/shrinkwrap.js +++ b/deps/npm/lib/shrinkwrap.js @@ -7,8 +7,10 @@ var path = require('path') var log = require('npmlog') var writeFileAtomic = require('write-file-atomic') var iferr = require('iferr') +var readPackageJson = require('read-package-json') var readPackageTree = require('read-package-tree') var validate = require('aproba') +var chain = require('slide').chain var npm = require('./npm.js') var recalculateMetadata = require('./install/deps.js').recalculateMetadata var validatePeerDeps = require('./install/deps.js').validatePeerDeps @@ -16,6 +18,8 @@ var isExtraneous = require('./install/is-extraneous.js') var isOnlyDev = require('./install/is-dev.js').isOnlyDev var packageId = require('./utils/package-id.js') var moduleName = require('./utils/module-name.js') +var output = require('./utils/output.js') +var lifecycle = require('./utils/lifecycle.js') shrinkwrap.usage = 'npm shrinkwrap' @@ -30,11 +34,24 @@ function shrinkwrap (args, silent, cb) { } var dir = path.resolve(npm.dir, '..') + var packagePath = path.join(npm.localPrefix, 'package.json') npm.config.set('production', true) - readPackageTree(dir, andRecalculateMetadata(iferr(cb, function (tree) { - var pkginfo = treeToShrinkwrap(tree, !!npm.config.get('dev') || /^dev(elopment)?$/.test(npm.config.get('also'))) - shrinkwrap_(pkginfo, silent, cb) - }))) + + readPackageJson(packagePath, iferr(cb, function (data) { + lifecycle(data, 'preshrinkwrap', function () { + readPackageTree(dir, andRecalculateMetadata(iferr(cb, function (tree) { + var pkginfo = treeToShrinkwrap(tree, !!npm.config.get('dev') || /^dev(elopment)?$/.test(npm.config.get('also'))) + + chain([ + [lifecycle, tree.package, 'shrinkwrap'], + [shrinkwrap_, pkginfo, silent], + [lifecycle, tree.package, 'postshrinkwrap'] + ], iferr(cb, function (data) { + cb(null, data[0]) + })) + }))) + }) + })) } function andRecalculateMetadata (next) { @@ -122,9 +139,7 @@ function save (pkginfo, silent, cb) { writeFileAtomic(file, swdata, function (er) { if (er) return cb(er) if (silent) return cb(null, pkginfo) - log.clearProgress() - console.log('wrote npm-shrinkwrap.json') - log.showProgress() + output('wrote npm-shrinkwrap.json') cb(null, pkginfo) }) } diff --git a/deps/npm/lib/star.js b/deps/npm/lib/star.js index ce141688b9..f19cb4b07b 100644 --- a/deps/npm/lib/star.js +++ b/deps/npm/lib/star.js @@ -5,6 +5,7 @@ var log = require('npmlog') var asyncMap = require('slide').asyncMap var mapToRegistry = require('./utils/map-to-registry.js') var usage = require('./utils/usage') +var output = require('./utils/output.js') star.usage = usage( 'star', @@ -34,7 +35,7 @@ function star (args, cb) { } npm.registry.star(uri, params, function (er, data, raw, req) { if (!er) { - console.log(s + ' ' + pkg) + output(s + ' ' + pkg) log.verbose('star', data) } cb(er, data, raw, req) diff --git a/deps/npm/lib/stars.js b/deps/npm/lib/stars.js index 4ad8f02e59..4771079356 100644 --- a/deps/npm/lib/stars.js +++ b/deps/npm/lib/stars.js @@ -5,6 +5,7 @@ stars.usage = 'npm stars [<user>]' var npm = require('./npm.js') var log = require('npmlog') var mapToRegistry = require('./utils/map-to-registry.js') +var output = require('./utils/output.js') function stars (args, cb) { npm.commands.whoami([], true, function (er, username) { @@ -38,7 +39,7 @@ function stars (args, cb) { log.warn('stars', 'user has not starred any packages.') } else { data.rows.forEach(function (a) { - console.log(a.value) + output(a.value) }) } cb() diff --git a/deps/npm/lib/substack.js b/deps/npm/lib/substack.js index c39a5dcc48..428e0a5898 100644 --- a/deps/npm/lib/substack.js +++ b/deps/npm/lib/substack.js @@ -1,5 +1,6 @@ module.exports = substack var npm = require('./npm.js') +var output = require('./utils/output.js') var isms = [ '\u001b[32mbeep \u001b[35mboop\u001b[m', @@ -14,7 +15,7 @@ var isms = [ function substack (args, cb) { var i = Math.floor(Math.random() * isms.length) - console.log(isms[i]) + output(isms[i]) var c = args.shift() if (c) npm.commands[c](args, cb) else cb() diff --git a/deps/npm/lib/team.js b/deps/npm/lib/team.js index 324d8df5e2..f99063b278 100644 --- a/deps/npm/lib/team.js +++ b/deps/npm/lib/team.js @@ -1,5 +1,6 @@ var mapToRegistry = require('./utils/map-to-registry.js') var npm = require('./npm') +var output = require('./utils/output.js') module.exports = team @@ -44,7 +45,7 @@ function team (args, cb) { team: entity[1], user: args.shift() }, function (err, data) { - !err && data && console.log(JSON.stringify(data, undefined, 2)) + !err && data && output(JSON.stringify(data, undefined, 2)) cb(err, data) }) } catch (e) { diff --git a/deps/npm/lib/unbuild.js b/deps/npm/lib/unbuild.js index f5efb1ee6d..9ba5972d8a 100644 --- a/deps/npm/lib/unbuild.js +++ b/deps/npm/lib/unbuild.js @@ -12,6 +12,7 @@ var asyncMap = require('slide').asyncMap var chain = require('slide').chain var log = require('npmlog') var build = require('./build.js') +var output = require('./utils/output.js') // args is a list of folders. // remove any bins/etc, and then delete the folder. @@ -40,9 +41,7 @@ function unbuild_ (silent) { [lifecycle, pkg, 'preuninstall', folder, false, true], [lifecycle, pkg, 'uninstall', folder, false, true], !silent && function (cb) { - log.clearProgress() - console.log('unbuild ' + pkg._id) - log.showProgress() + output('unbuild ' + pkg._id) cb() }, [rmStuff, pkg, folder], diff --git a/deps/npm/lib/unpublish.js b/deps/npm/lib/unpublish.js index 63f87b8207..ee050c2846 100644 --- a/deps/npm/lib/unpublish.js +++ b/deps/npm/lib/unpublish.js @@ -8,6 +8,7 @@ var path = require('path') var mapToRegistry = require('./utils/map-to-registry.js') var npa = require('npm-package-arg') var getPublishConfig = require('./utils/get-publish-config.js') +var output = require('./utils/output.js') unpublish.usage = 'npm unpublish [<@scope>/]<pkg>[@<version>]' @@ -89,7 +90,7 @@ function gotProject (project, version, publishConfig, cb_) { function cb (er) { if (er) return cb_(er) - console.log('- ' + project + (version ? '@' + version : '')) + output('- ' + project + (version ? '@' + version : '')) cb_() } diff --git a/deps/npm/lib/utils/git.js b/deps/npm/lib/utils/git.js index dc021300ea..4d05c75b86 100644 --- a/deps/npm/lib/utils/git.js +++ b/deps/npm/lib/utils/git.js @@ -11,6 +11,7 @@ var which = require('which') var git = npm.config.get('git') var assert = require('assert') var log = require('npmlog') +var noProgressTillDone = require('./no-progress-while-running.js').tillDone function prefixGitArgs () { return process.platform === 'win32' ? ['-c', 'core.longpaths=true'] : [] @@ -19,7 +20,7 @@ function prefixGitArgs () { function execGit (args, options, cb) { log.info('git', args) var fullArgs = prefixGitArgs().concat(args || []) - return exec(git, fullArgs, options, cb) + return exec(git, fullArgs, options, noProgressTillDone(cb)) } function spawnGit (args, options) { diff --git a/deps/npm/lib/utils/lifecycle.js b/deps/npm/lib/utils/lifecycle.js index fd1a59b74c..6a862366f2 100644 --- a/deps/npm/lib/utils/lifecycle.js +++ b/deps/npm/lib/utils/lifecycle.js @@ -14,6 +14,7 @@ var PATH = 'PATH' var uidNumber = require('uid-number') var umask = require('./umask') var usage = require('./usage') +var output = require('./output.js') // windows calls it's path 'Path' usually, but this is not guaranteed. if (process.platform === 'win32') { @@ -182,9 +183,7 @@ function runCmd (note, cmd, pkg, env, stage, wd, unsafe, cb) { var group = unsafe ? null : npm.config.get('group') if (log.level !== 'silent') { - log.clearProgress() - console.log(note) - log.showProgress() + output(note) } log.verbose('lifecycle', logid(pkg, stage), 'unsafe-perm in lifecycle', unsafe) @@ -232,8 +231,6 @@ function runCmd_ (cmd, pkg, env, wd, stage, unsafe, uid, gid, cb_) { log.verbose('lifecycle', logid(pkg, stage), 'CWD:', wd) log.silly('lifecycle', logid(pkg, stage), 'Args:', [shFlag, cmd]) - var progressEnabled = log.progressEnabled - if (progressEnabled) log.disableProgress() var proc = spawn(sh, [shFlag, cmd], conf) proc.on('error', procError) @@ -249,7 +246,6 @@ function runCmd_ (cmd, pkg, env, wd, stage, unsafe, uid, gid, cb_) { process.once('SIGTERM', procKill) function procError (er) { - if (progressEnabled) log.enableProgress() if (er) { log.info('lifecycle', logid(pkg, stage), 'Failed to exec ' + stage + ' script') er.message = pkg._id + ' ' + stage + ': `' + cmd + '`\n' + diff --git a/deps/npm/lib/utils/no-progress-while-running.js b/deps/npm/lib/utils/no-progress-while-running.js new file mode 100644 index 0000000000..961fa8b555 --- /dev/null +++ b/deps/npm/lib/utils/no-progress-while-running.js @@ -0,0 +1,23 @@ +'use strict' +var log = require('npmlog') +var progressEnabled +var running = 0 + +var startRunning = exports.startRunning = function () { + if (progressEnabled == null) progressEnabled = log.progressEnabled + if (progressEnabled) log.disableProgress() + ++running +} + +var stopRunning = exports.stopRunning = function () { + --running + if (progressEnabled && running === 0) log.enableProgress() +} + +exports.tillDone = function noProgressTillDone (cb) { + startRunning() + return function () { + stopRunning() + cb.apply(this, arguments) + } +} diff --git a/deps/npm/lib/utils/output.js b/deps/npm/lib/utils/output.js new file mode 100644 index 0000000000..3dd66cbdd2 --- /dev/null +++ b/deps/npm/lib/utils/output.js @@ -0,0 +1,8 @@ +'use strict' +var log = require('npmlog') +// output to stdout in a progress bar compatible way +module.exports = function () { + log.clearProgress() + console.log.apply(console, arguments) + log.showProgress() +} diff --git a/deps/npm/lib/utils/pulse-till-done.js b/deps/npm/lib/utils/pulse-till-done.js index fc6450e003..2669241306 100644 --- a/deps/npm/lib/utils/pulse-till-done.js +++ b/deps/npm/lib/utils/pulse-till-done.js @@ -7,9 +7,10 @@ var pulse module.exports = function (prefix, cb) { validate('SF', [prefix, cb]) + if (!prefix) prefix = 'network' if (!pulsers++) { pulse = setInterval(function () { - log.gauge.pulse('network') + log.gauge.pulse(prefix) }, 250) } return function () { diff --git a/deps/npm/lib/utils/spawn.js b/deps/npm/lib/utils/spawn.js index e389d83e02..b164a6acba 100644 --- a/deps/npm/lib/utils/spawn.js +++ b/deps/npm/lib/utils/spawn.js @@ -2,15 +2,31 @@ module.exports = spawn var _spawn = require('child_process').spawn var EventEmitter = require('events').EventEmitter +var npwr = require('./no-progress-while-running.js') + +function willCmdOutput (stdio) { + if (stdio === 'inherit') return true + if (!Array.isArray(stdio)) return false + for (var fh = 1; fh <= 2; ++fh) { + if (stdio[fh] === 'inherit') return true + if (stdio[fh] === 1 || stdio[fh] === 2) return true + } + return false +} function spawn (cmd, args, options) { + var cmdWillOutput = willCmdOutput(options && options.stdio) + + if (cmdWillOutput) npwr.startRunning() var raw = _spawn(cmd, args, options) var cooked = new EventEmitter() raw.on('error', function (er) { + if (cmdWillOutput) npwr.stopRunning() er.file = cmd cooked.emit('error', er) }).on('close', function (code, signal) { + if (cmdWillOutput) npwr.stopRunning() // Create ENOENT error because Node.js v0.8 will not emit // an `error` event if the command could not be found. if (code === 127) { diff --git a/deps/npm/lib/utils/tar.js b/deps/npm/lib/utils/tar.js index 98f6e4ff64..1e00040dbb 100644 --- a/deps/npm/lib/utils/tar.js +++ b/deps/npm/lib/utils/tar.js @@ -20,9 +20,9 @@ var myUid = process.getuid && process.getuid() var myGid = process.getgid && process.getgid() var readPackageTree = require('read-package-tree') var union = require('lodash.union') -var flattenTree = require('../install/flatten-tree.js') var moduleName = require('./module-name.js') var packageId = require('./package-id.js') +var pulseTillDone = require('../utils/pulse-till-done.js') if (process.env.SUDO_UID && myUid === 0) { if (!isNaN(process.env.SUDO_UID)) myUid = +process.env.SUDO_UID @@ -40,18 +40,20 @@ function pack (tarball, folder, pkg, cb) { readJson(path.join(folder, 'package.json'), function (er, pkg) { if (er || !pkg.bundleDependencies) { - pack_(tarball, folder, null, null, pkg, cb) + pack_(tarball, folder, null, pkg, cb) } else { // we require this at runtime due to load-order issues, because recursive // requires fail if you replace the exports object, and we do, not in deps, but // in a dep of it. var recalculateMetadata = require('../install/deps.js').recalculateMetadata - readPackageTree(folder, iferr(cb, function (tree) { - recalculateMetadata(tree, log.newGroup('pack:' + packageId(pkg)), iferr(cb, function () { - pack_(tarball, folder, tree, flattenTree(tree), pkg, cb) + readPackageTree(folder, pulseTillDone('pack:readTree:' + packageId(pkg), iferr(cb, function (tree) { + var recalcGroup = log.newGroup('pack:recalc:' + packageId(pkg)) + recalculateMetadata(tree, recalcGroup, iferr(cb, function () { + recalcGroup.finish() + pack_(tarball, folder, tree, pkg, pulseTillDone('pack:' + packageId(pkg), cb)) })) - })) + }))) } }) } @@ -61,9 +63,96 @@ function BundledPacker (props) { } inherits(BundledPacker, Packer) +BundledPacker.prototype.applyIgnores = function (entry, partial, entryObj) { + if (!entryObj || entryObj.type !== 'Directory') { + // package.json files can never be ignored. + if (entry === 'package.json') return true + + // readme files should never be ignored. + if (entry.match(/^readme(\.[^\.]*)$/i)) return true + + // license files should never be ignored. + if (entry.match(/^(license|licence)(\.[^\.]*)?$/i)) return true + + // copyright notice files should never be ignored. + if (entry.match(/^(notice)(\.[^\.]*)?$/i)) return true + + // changelogs should never be ignored. + if (entry.match(/^(changes|changelog|history)(\.[^\.]*)?$/i)) return true + } + + // special rules. see below. + if (entry === 'node_modules' && this.packageRoot) return true + + // package.json main file should never be ignored. + var mainFile = this.package && this.package.main + if (mainFile && path.resolve(this.path, entry) === path.resolve(this.path, mainFile)) return true + + // some files are *never* allowed under any circumstances + // (VCS folders, native build cruft, npm cruft, regular cruft) + if (entry === '.git' || + entry === 'CVS' || + entry === '.svn' || + entry === '.hg' || + entry === '.lock-wscript' || + entry.match(/^\.wafpickle-[0-9]+$/) || + (this.parent && this.parent.packageRoot && this.basename === 'build' && + entry === 'config.gypi') || + entry === 'npm-debug.log' || + entry === '.npmrc' || + entry.match(/^\..*\.swp$/) || + entry === '.DS_Store' || + entry.match(/^\._/) + ) { + return false + } + + // in a node_modules folder, we only include bundled dependencies + // also, prevent packages in node_modules from being affected + // by rules set in the containing package, so that + // bundles don't get busted. + // Also, once in a bundle, everything is installed as-is + // To prevent infinite cycles in the case of cyclic deps that are + // linked with npm link, even in a bundle, deps are only bundled + // if they're not already present at a higher level. + if (this.bundleMagic) { + // bubbling up. stop here and allow anything the bundled pkg allows + if (entry.indexOf('/') !== -1) return true + + // never include the .bin. It's typically full of platform-specific + // stuff like symlinks and .cmd files anyway. + if (entry === '.bin') return false + + // the package root. + var p = this.parent + // the package before this one. + var pp = p && p.parent + + // if this entry has already been bundled, and is a symlink, + // and it is the *same* symlink as this one, then exclude it. + if (pp && pp.bundleLinks && this.bundleLinks && + pp.bundleLinks[entry] && + pp.bundleLinks[entry] === this.bundleLinks[entry]) { + return false + } + + // since it's *not* a symbolic link, if we're *already* in a bundle, + // then we should include everything. + if (pp && pp.package && pp.basename === 'node_modules') { + return true + } + + // only include it at this point if it's a bundleDependency + return this.isBundled(entry) + } + // if (this.bundled) return true + + return Packer.prototype.applyIgnores.call(this, entry, partial, entryObj) +} + function nameMatch (name) { return function (other) { return name === moduleName(other) } } -function pack_ (tarball, folder, tree, flatTree, pkg, cb) { +function pack_ (tarball, folder, tree, pkg, cb) { function InstancePacker (props) { BundledPacker.call(this, props) } @@ -81,18 +170,17 @@ function pack_ (tarball, folder, tree, flatTree, pkg, cb) { if (bd.indexOf(name) !== -1) return true var pkg = tree.children.filter(nameMatch(name))[0] if (!pkg) return false - var requiredBy = union([], pkg.package._requiredBy) + var requiredBy = [].concat(pkg.requiredBy) var seen = {} while (requiredBy.length) { - var req = requiredBy.shift() - if (seen[req]) continue - seen[req] = true - var reqPkg = flatTree[req] + var reqPkg = requiredBy.shift() + if (seen[reqPkg.path]) continue + seen[reqPkg.path] = true if (!reqPkg) continue if (reqPkg.parent === tree && bd.indexOf(moduleName(reqPkg)) !== -1) { return true } - requiredBy = union(requiredBy, reqPkg.package._requiredBy) + requiredBy = union(requiredBy, reqPkg.requiredBy) } return false } diff --git a/deps/npm/lib/utils/usage.js b/deps/npm/lib/utils/usage.js index 261d84ee8e..ba069e645e 100644 --- a/deps/npm/lib/utils/usage.js +++ b/deps/npm/lib/utils/usage.js @@ -11,7 +11,7 @@ module.exports = function usage (cmd, txt, opt) { if (opt || post.length > 0) txt += '\n\n' if (post.length === 1) { - txt += 'aliase: ' + txt += 'alias: ' txt += post.join(', ') } else if (post.length > 1) { txt += 'aliases: ' diff --git a/deps/npm/lib/version.js b/deps/npm/lib/version.js index 448c7713ce..e69560fa9a 100644 --- a/deps/npm/lib/version.js +++ b/deps/npm/lib/version.js @@ -13,6 +13,7 @@ var git = require('./utils/git.js') var assert = require('assert') var lifecycle = require('./utils/lifecycle.js') var parseJSON = require('./utils/parse-json.js') +var output = require('./utils/output.js') version.usage = 'npm version [<newversion> | major | minor | patch | premajor | preminor | prepatch | prerelease | from-git]' + '\n(run in package dir)\n' + @@ -121,7 +122,7 @@ function readPackage (cb) { function updatePackage (newVersion, silent, cb_) { function cb (er) { - if (!er && !silent) console.log('v' + newVersion) + if (!er && !silent) output('v' + newVersion) cb_(er) } @@ -174,7 +175,7 @@ function dump (data, cb) { if (npm.config.get('json')) v = JSON.stringify(v, null, 2) - console.log(v) + output(v) cb() } diff --git a/deps/npm/lib/view.js b/deps/npm/lib/view.js index 79c440426b..5bf1cbf248 100644 --- a/deps/npm/lib/view.js +++ b/deps/npm/lib/view.js @@ -288,6 +288,10 @@ function printData (data, name, cb) { // there's one at the beginning if (/^\s*\n/.test(msg)) msg += '\n' + // disable the progress bar entirely, as we can't meaningfully update it if + // we may have partial lines printed. + log.disableProgress() + // print directly to stdout to not unnecessarily add blank lines process.stdout.write(msg) diff --git a/deps/npm/lib/visnup.js b/deps/npm/lib/visnup.js index b0352fd6d0..a61bacb73b 100644 --- a/deps/npm/lib/visnup.js +++ b/deps/npm/lib/visnup.js @@ -1,5 +1,6 @@ module.exports = visnup var npm = require('./npm.js') +var output = require('./utils/output.js') var handsomeFace = [ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 237, 236, 236, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], @@ -31,7 +32,7 @@ var handsomeFace = [ function visnup (args, cb) { handsomeFace.forEach(function (line) { - console.log(line.map(function (ch) { + output(line.map(function (ch) { return '\u001b[' + (ch ? '48;5;' + ch : ch) + 'm' }).join(' ')) }) diff --git a/deps/npm/lib/whoami.js b/deps/npm/lib/whoami.js index feb6fab95a..e8af6595d1 100644 --- a/deps/npm/lib/whoami.js +++ b/deps/npm/lib/whoami.js @@ -1,4 +1,5 @@ var npm = require('./npm.js') +var output = require('./utils/output.js') module.exports = whoami @@ -17,7 +18,7 @@ function whoami (args, silent, cb) { var auth = npm.config.getCredentialsByURI(registry) if (auth) { if (auth.username) { - if (!silent) console.log(auth.username) + if (!silent) output(auth.username) return process.nextTick(cb.bind(this, null, auth.username)) } else if (auth.token) { return npm.registry.whoami(registry, { auth: auth }, function (er, username) { @@ -30,7 +31,7 @@ function whoami (args, silent, cb) { return cb(needNewSession) } - if (!silent) console.log(username) + if (!silent) output(username) cb(null, username) }) } |