diff options
Diffstat (limited to 'deps/npm/lib')
-rw-r--r-- | deps/npm/lib/cache/add-named.js | 7 | ||||
-rw-r--r-- | deps/npm/lib/cache/add-remote-git.js | 532 | ||||
-rw-r--r-- | deps/npm/lib/cache/add-remote-tarball.js | 2 | ||||
-rw-r--r-- | deps/npm/lib/config/defaults.js | 15 | ||||
-rw-r--r-- | deps/npm/lib/dedupe.js | 27 | ||||
-rw-r--r-- | deps/npm/lib/install.js | 29 | ||||
-rw-r--r-- | deps/npm/lib/npm.js | 1 | ||||
-rw-r--r-- | deps/npm/lib/publish.js | 13 | ||||
-rw-r--r-- | deps/npm/lib/stars.js | 11 | ||||
-rw-r--r-- | deps/npm/lib/update.js | 20 | ||||
-rw-r--r-- | deps/npm/lib/utils/error-handler.js | 3 | ||||
-rw-r--r-- | deps/npm/lib/whoami.js | 24 |
12 files changed, 410 insertions, 274 deletions
diff --git a/deps/npm/lib/cache/add-named.js b/deps/npm/lib/cache/add-named.js index d81b7b0da6..cb5a3fa8a6 100644 --- a/deps/npm/lib/cache/add-named.js +++ b/deps/npm/lib/cache/add-named.js @@ -12,7 +12,6 @@ var path = require("path") , addRemoteTarball = require("./add-remote-tarball.js") , cachedPackageRoot = require("./cached-package-root.js") , mapToRegistry = require("../utils/map-to-registry.js") - , warnStrict = require("../utils/warn-deprecated.js")("engineStrict") module.exports = addNamed @@ -92,12 +91,6 @@ function engineFilter (data) { Object.keys(data.versions || {}).forEach(function (v) { var eng = data.versions[v].engines if (!eng) return - if (data.versions[v].engineStrict) { - warnStrict([ - "Per-package engineStrict (found in package.json for "+data.name+")", - "won't be used in npm 3+. Use the config setting `engine-strict` instead." - ], data.name) - } if (!strict && !data.versions[v].engineStrict) return if (eng.node && !semver.satisfies(nodev, eng.node, true) || eng.npm && !semver.satisfies(npmv, eng.npm, true)) { diff --git a/deps/npm/lib/cache/add-remote-git.js b/deps/npm/lib/cache/add-remote-git.js index 974c158f9c..9eaf6b18a5 100644 --- a/deps/npm/lib/cache/add-remote-git.js +++ b/deps/npm/lib/cache/add-remote-git.js @@ -1,269 +1,330 @@ -var mkdir = require("mkdirp") - , assert = require("assert") - , git = require("../utils/git.js") - , fs = require("graceful-fs") - , log = require("npmlog") - , path = require("path") - , url = require("url") - , chownr = require("chownr") - , crypto = require("crypto") - , npm = require("../npm.js") - , rm = require("../utils/gently-rm.js") - , inflight = require("inflight") - , getCacheStat = require("./get-stat.js") - , addLocal = require("./add-local.js") - , realizePackageSpecifier = require("realize-package-specifier") - , normalizeGitUrl = require("normalize-git-url") - , randomBytes = require("crypto").pseudoRandomBytes // only need uniqueness - -var remotes = path.resolve(npm.config.get("cache"), "_git-remotes") -var templates = path.join(remotes, "_templates") +var mkdir = require('mkdirp') +var assert = require('assert') +var git = require('../utils/git.js') +var fs = require('graceful-fs') +var log = require('npmlog') +var path = require('path') +var url = require('url') +var chownr = require('chownr') +var crypto = require('crypto') +var npm = require('../npm.js') +var rm = require('../utils/gently-rm.js') +var inflight = require('inflight') +var getCacheStat = require('./get-stat.js') +var addLocal = require('./add-local.js') +var realizePackageSpecifier = require('realize-package-specifier') +var normalizeGitUrl = require('normalize-git-url') +var randomBytes = require('crypto').pseudoRandomBytes // only need uniqueness + +var remotes = path.resolve(npm.config.get('cache'), '_git-remotes') +var templates = path.join(remotes, '_templates') var VALID_VARIABLES = [ - "GIT_SSH", - "GIT_SSL_NO_VERIFY", - "GIT_PROXY_COMMAND", - "GIT_SSL_CAINFO" + 'GIT_SSH', + 'GIT_SSL_NO_VERIFY', + 'GIT_PROXY_COMMAND', + 'GIT_SSL_CAINFO' ] -// 1. cacheDir = path.join(cache,'_git-remotes',sha1(u)) -// 2. checkGitDir(cacheDir) ? 4. : 3. (rm cacheDir if necessary) -// 3. git clone --mirror u cacheDir -// 4. cd cacheDir && git fetch -a origin -// 5. git archive /tmp/random.tgz -// 6. addLocalTarball(/tmp/random.tgz) <gitref> --format=tar --prefix=package/ -// silent flag is used if this should error quietly -module.exports = function addRemoteGit (u, silent, cb) { - assert(typeof u === "string", "must have git URL") - assert(typeof cb === "function", "must have callback") - - log.verbose("addRemoteGit", "u=%j silent=%j", u, silent) - var normalized = normalizeGitUrl(u) - log.silly("addRemoteGit", "normalized", normalized) - - var v = crypto.createHash("sha1").update(normalized.url).digest("hex").slice(0, 8) - v = normalized.url.replace(/[^a-zA-Z0-9]+/g, "-")+"-"+v - log.silly("addRemoteGit", "v", v) - - var p = path.join(remotes, v) - cb = inflight(p, cb) - if (!cb) return log.verbose("addRemoteGit", p, "already in flight; waiting") - log.verbose("addRemoteGit", p, "not in flight; cloning") +module.exports = function addRemoteGit (uri, silent, cb) { + assert(typeof uri === 'string', 'must have git URL') + assert(typeof cb === 'function', 'must have callback') + + // reconstruct the URL as it was passed in – realizePackageSpecifier + // strips off `git+` and `maybeGithub` doesn't include it. + var originalURL + if (!/^git[+:]/.test(uri)) { + originalURL = 'git+' + uri + } else { + originalURL = uri + } - getGitDir(function (er) { - if (er) return cb(er) - checkGitDir(p, normalized.url, normalized.branch, u, silent, function (er, data) { - if (er) return cb(er, data) + // break apart the origin URL and the branch / tag / commitish + var normalized = normalizeGitUrl(uri) + var gitURL = normalized.url + var treeish = normalized.branch - addModeRecursive(p, npm.modes.file, function (er) { - return cb(er, data) - }) - }) - }) -} + // ensure that similarly-named remotes don't collide + var repoID = gitURL.replace(/[^a-zA-Z0-9]+/g, '-') + '-' + + crypto.createHash('sha1').update(gitURL).digest('hex').slice(0, 8) + var cachedRemote = path.join(remotes, repoID) -function getGitDir (cb) { - getCacheStat(function (er, st) { - if (er) return cb(er) + // set later, as the callback flow proceeds + var resolvedURL + var resolvedTreeish + var tmpdir - // We don't need global templates when cloning. Use an empty directory for - // the templates, creating it (and setting its permissions) if necessary. - mkdir(templates, function (er) { - if (er) return cb(er) + cb = inflight(repoID, cb) + if (!cb) { + return log.verbose('addRemoteGit', repoID, 'already in flight; waiting') + } + log.verbose('addRemoteGit', repoID, 'not in flight; caching') - // Ensure that both the template and remotes directories have the correct - // permissions. - fs.chown(templates, st.uid, st.gid, function (er) { - if (er) return cb(er) + // initialize the remotes cache with the correct perms + getGitDir(function (er) { + if (er) return cb(er) + fs.stat(cachedRemote, function (er, s) { + if (er) return mirrorRemote(finish) + if (!s.isDirectory()) return resetRemote(finish) - fs.chown(remotes, st.uid, st.gid, function (er) { - cb(er, st) - }) - }) + validateExistingRemote(finish) }) + + // always set permissions on the cached remote + function finish (er, data) { + if (er) return cb(er, data) + addModeRecursive(cachedRemote, npm.modes.file, function (er) { + return cb(er, data) + }) + } }) -} -function checkGitDir (p, u, co, origUrl, silent, cb) { - fs.stat(p, function (er, s) { - if (er) return cloneGitRemote(p, u, co, origUrl, silent, cb) - if (!s.isDirectory()) return rm(p, function (er) { + // don't try too hard to hold on to a remote + function resetRemote (cb) { + log.info('addRemoteGit', 'resetting', cachedRemote) + rm(cachedRemote, function (er) { if (er) return cb(er) - cloneGitRemote(p, u, co, origUrl, silent, cb) + mirrorRemote(cb) }) + } + // reuse a cached remote when possible, but nuke it if it's in an + // inconsistent state + function validateExistingRemote (cb) { git.whichAndExec( - [ "config", "--get", "remote.origin.url" ], - { cwd : p, env : gitEnv }, + ['config', '--get', 'remote.origin.url'], + { cwd: cachedRemote, env: gitEnv() }, function (er, stdout, stderr) { - var stdoutTrimmed = (stdout + "\n" + stderr).trim() - if (er || u !== stdout.trim()) { - log.warn( "`git config --get remote.origin.url` returned " - + "wrong result ("+u+")", stdoutTrimmed ) - return rm(p, function (er){ - if (er) return cb(er) - cloneGitRemote(p, u, co, origUrl, silent, cb) - }) + var originURL = stdout.trim() + stderr = stderr.trim() + log.verbose('addRemoteGit', 'remote.origin.url:', originURL) + + if (stderr || er) { + log.warn('addRemoteGit', 'resetting remote', cachedRemote, 'because of error:', stderr || er) + return resetRemote(cb) + } else if (gitURL !== originURL) { + log.warn( + 'addRemoteGit', + 'pre-existing cached repo', cachedRemote, 'points to', originURL, 'and not', gitURL + ) + return resetRemote(cb) } - log.verbose("git remote.origin.url", stdoutTrimmed) - fetchRemote(p, u, co, origUrl, cb) + + log.verbose('addRemoteGit', 'updating existing cached remote', cachedRemote) + updateRemote(cb) } ) - }) -} + } -function cloneGitRemote (p, u, co, origUrl, silent, cb) { - mkdir(p, function (er) { - if (er) return cb(er) + // make a complete bare mirror of the remote repo + // NOTE: npm uses a blank template directory to prevent weird inconsistencies + // https://github.com/npm/npm/issues/5867 + function mirrorRemote (cb) { + mkdir(cachedRemote, function (er) { + if (er) return cb(er) - git.whichAndExec( - [ "clone", "--template=" + templates, "--mirror", u, p ], - { cwd : p, env : gitEnv() }, - function (er, stdout, stderr) { - stdout = (stdout + "\n" + stderr).trim() - if (er) { - if (silent) { - log.verbose("git clone " + u, stdout) - } else { - log.error("git clone " + u, stdout) + var args = [ + 'clone', + '--template=' + templates, + '--mirror', + gitURL, cachedRemote + ] + git.whichAndExec( + ['clone', '--template=' + templates, '--mirror', gitURL, cachedRemote], + { cwd: cachedRemote, env: gitEnv() }, + function (er, stdout, stderr) { + if (er) { + var combined = (stdout + '\n' + stderr).trim() + var command = 'git ' + args.join(' ') + ':' + if (silent) { + log.verbose(command, combined) + } else { + log.error(command, combined) + } + return cb(er) } - return cb(er) + log.verbose('addRemoteGit', 'git clone ' + gitURL, stdout.trim()) + setPermissions(cb) } - log.verbose("git clone " + u, stdout) - fetchRemote(p, u, co, origUrl, cb) - } - ) - }) -} + ) + }) + } -function fetchRemote (p, u, co, origUrl, cb) { - git.whichAndExec( - [ "fetch", "-a", "origin" ], - { cwd : p, env : gitEnv() }, - function (er, stdout, stderr) { - stdout = (stdout + "\n" + stderr).trim() - if (er) { - log.error("git fetch -a origin ("+u+")", stdout) - return cb(er) - } - log.verbose("git fetch -a origin ("+u+")", stdout) + function setPermissions (cb) { + if (process.platform === 'win32') { + log.verbose('addRemoteGit', 'skipping chownr on Windows') + resolveHead(cb) + } else { + getGitDir(function (er, cs) { + if (er) { + log.error('addRemoteGit', 'could not get cache stat') + return cb(er) + } - if (process.platform === "win32") { - log.silly("verifyOwnership", "skipping for windows") - resolveHead(p, u, co, origUrl, cb) - } - else { - getGitDir(function (er, cs) { + chownr(cachedRemote, cs.uid, cs.gid, function (er) { if (er) { - log.error("Could not get cache stat") + log.error( + 'addRemoteGit', + 'Failed to change folder ownership under npm cache for', + cachedRemote + ) return cb(er) } - chownr(p, cs.uid, cs.gid, function (er) { - if (er) { - log.error("Failed to change folder ownership under npm cache for %s", p) - return cb(er) - } - - resolveHead(p, u, co, origUrl, cb) - }) + log.verbose('addRemoteGit', 'set permissions on', cachedRemote) + resolveHead(cb) }) - } + }) } - ) -} - -function resolveHead (p, u, co, origUrl, cb) { - git.whichAndExec( - [ "rev-list", "-n1", co ], - { cwd : p, env : gitEnv() }, - function (er, stdout, stderr) { - stdout = (stdout + "\n" + stderr).trim() - if (er) { - log.error("Failed resolving git HEAD (" + u + ")", stderr) - return cb(er) - } - log.verbose("git rev-list -n1 " + co, stdout) - var parsed = url.parse(origUrl) - parsed.hash = stdout - var resolved = url.format(parsed) + } - if (!/^git[+:]/.test(parsed.protocol)) { - resolved = "git+" + resolved - } + // always fetch the origin, even right after mirroring, because this way + // permissions will get set correctly + function updateRemote (cb) { + git.whichAndExec( + ['fetch', '-a', 'origin'], + { cwd: cachedRemote, env: gitEnv() }, + function (er, stdout, stderr) { + if (er) { + var combined = (stdout + '\n' + stderr).trim() + log.error('git fetch -a origin (' + gitURL + ')', combined) + return cb(er) + } + log.verbose('addRemoteGit', 'git fetch -a origin (' + gitURL + ')', stdout.trim()) - // https://github.com/npm/npm/issues/3224 - // node incorrectly sticks a / at the start of the path We know that the - // host won't change, so split and detect this - var spo = origUrl.split(parsed.host) - var spr = resolved.split(parsed.host) - if (spo[1].charAt(0) === ":" && spr[1].charAt(0) === "/") { - spr[1] = spr[1].slice(1) + setPermissions(cb) } - resolved = spr.join(parsed.host) + ) + } - log.verbose("resolved git url", resolved) - cache(p, u, stdout, resolved, cb) - } - ) -} + // branches and tags are both symbolic labels that can be attached to different + // commits, so resolve the commitish to the current actual treeish the label + // corresponds to + // + // important for shrinkwrap + function resolveHead (cb) { + log.verbose('addRemoteGit', 'original treeish:', treeish) + var args = ['rev-list', '-n1', treeish] + git.whichAndExec( + args, + { cwd: cachedRemote, env: gitEnv() }, + function (er, stdout, stderr) { + if (er) { + log.error('git ' + args.join(' ') + ':', stderr) + return cb(er) + } -/** - * Make an actual clone from the bare (mirrored) cache. There is no safe way to - * do a one-step clone to a treeish that isn't guaranteed to be a branch, so - * this has to be two steps. - */ -function cache (p, u, treeish, resolved, cb) { - // generate a unique filename - randomBytes(6, function (er, random) { - if (er) return cb(er) + resolvedTreeish = stdout.trim() + log.silly('addRemoteGit', 'resolved treeish:', resolvedTreeish) - var tmp = path.join( - npm.tmp, - "git-cache-"+random.toString("hex"), - treeish - ) + resolvedURL = getResolved(originalURL, resolvedTreeish) + log.verbose('addRemoteGit', 'resolved Git URL:', resolvedURL) - mkdir(tmp, function (er) { - if (er) return cb(er) + // generate a unique filename + tmpdir = path.join( + npm.tmp, + 'git-cache-' + randomBytes(6).toString('hex'), + resolvedTreeish + ) + log.silly('addRemoteGit', 'Git working directory:', tmpdir) - git.whichAndExec(["clone", p, tmp], { cwd : p, env : gitEnv() }, clone) - }) + mkdir(tmpdir, function (er) { + if (er) return cb(er) - function clone (er, stdout, stderr) { - stdout = (stdout + "\n" + stderr).trim() - if (er) { - log.error("Failed to clone "+resolved+" from "+u, stderr) - return cb(er) + cloneResolved(cb) + }) } - log.verbose("git clone", "from", p) - log.verbose("git clone", stdout) + ) + } - git.whichAndExec(["checkout", treeish], { cwd : tmp, env : gitEnv() }, checkout) - } + // make a clone from the mirrored cache so we have a temporary directory in + // which we can check out the resolved treeish + function cloneResolved (cb) { + var args = ['clone', cachedRemote, tmpdir] + git.whichAndExec( + args, + { cwd: cachedRemote, env: gitEnv() }, + function (er, stdout, stderr) { + stdout = (stdout + '\n' + stderr).trim() + if (er) { + log.error('git ' + args.join(' ') + ':', stderr) + return cb(er) + } + log.verbose('addRemoteGit', 'clone', stdout) - function checkout (er, stdout, stderr) { - stdout = (stdout + "\n" + stderr).trim() - if (er) { - log.error("Failed to check out "+treeish, stderr) - return cb(er) + checkoutTreeish(cb) } - log.verbose("git checkout", stdout) + ) + } - realizePackageSpecifier(tmp, function (er, spec) { + // there is no safe way to do a one-step clone to a treeish that isn't + // guaranteed to be a branch, so explicitly check out the treeish once it's + // cloned + function checkoutTreeish (cb) { + var args = ['checkout', resolvedTreeish] + git.whichAndExec( + args, + { cwd: tmpdir, env: gitEnv() }, + function (er, stdout, stderr) { + stdout = (stdout + '\n' + stderr).trim() if (er) { - log.error("Failed to map", tmp, "to a package specifier") + log.error('git ' + args.join(' ') + ':', stderr) return cb(er) } + log.verbose('addRemoteGit', 'checkout', stdout) - // https://github.com/npm/npm/issues/6400 - // ensure pack logic is applied - addLocal(spec, null, function (er, data) { - if (data) data._resolved = resolved - cb(er, data) + // convince addLocal that the checkout is a local dependency + realizePackageSpecifier(tmpdir, function (er, spec) { + if (er) { + log.error('addRemoteGit', 'Failed to map', tmpdir, 'to a package specifier') + return cb(er) + } + + // ensure pack logic is applied + // https://github.com/npm/npm/issues/6400 + addLocal(spec, null, function (er, data) { + if (data) { + log.verbose('addRemoteGit', 'data._resolved:', resolvedURL) + data._resolved = resolvedURL + + // the spec passed to addLocal is not what the user originally requested, + // so remap + // https://github.com/npm/npm/issues/7121 + if (!data._fromGitHub) { + log.silly('addRemoteGit', 'data._from:', originalURL) + data._from = originalURL + } else { + log.silly('addRemoteGit', 'data._from:', data._from, '(GitHub)') + } + } + + cb(er, data) + }) + }) + } + ) + } +} + +function getGitDir (cb) { + getCacheStat(function (er, stats) { + if (er) return cb(er) + + // We don't need global templates when cloning. Use an empty directory for + // the templates, creating it (and setting its permissions) if necessary. + mkdir(templates, function (er) { + if (er) return cb(er) + + // Ensure that both the template and remotes directories have the correct + // permissions. + fs.chown(templates, stats.uid, stats.gid, function (er) { + if (er) return cb(er) + + fs.chown(remotes, stats.uid, stats.gid, function (er) { + cb(er, stats) }) }) - } + }) }) } @@ -280,41 +341,60 @@ function gitEnv () { return gitEnv_ } +function getResolved (uri, treeish) { + var parsed = url.parse(uri) + parsed.hash = treeish + if (!/^git[+:]/.test(parsed.protocol)) { + parsed.protocol = 'git+' + parsed.protocol + } + var resolved = url.format(parsed) + + // node incorrectly sticks a / at the start of the path We know that the host + // won't change, so split and detect this + // https://github.com/npm/npm/issues/3224 + var spo = uri.split(parsed.host) + var spr = resolved.split(parsed.host) + if (spo[1].charAt(0) === ':' && spr[1].charAt(0) === '/') { + spr[1] = spr[1].slice(1) + } + return spr.join(parsed.host) +} + // similar to chmodr except it add permissions rather than overwriting them // adapted from https://github.com/isaacs/chmodr/blob/master/chmodr.js -function addModeRecursive(p, mode, cb) { - fs.readdir(p, function (er, children) { +function addModeRecursive (cachedRemote, mode, cb) { + fs.readdir(cachedRemote, function (er, children) { // Any error other than ENOTDIR means it's not readable, or doesn't exist. // Give up. - if (er && er.code !== "ENOTDIR") return cb(er) - if (er || !children.length) return addMode(p, mode, cb) + if (er && er.code !== 'ENOTDIR') return cb(er) + if (er || !children.length) return addMode(cachedRemote, mode, cb) var len = children.length var errState = null children.forEach(function (child) { - addModeRecursive(path.resolve(p, child), mode, then) + addModeRecursive(path.resolve(cachedRemote, child), mode, then) }) function then (er) { if (errState) return undefined if (er) return cb(errState = er) - if (--len === 0) return addMode(p, dirMode(mode), cb) + if (--len === 0) return addMode(cachedRemote, dirMode(mode), cb) } }) } -function addMode(p, mode, cb) { - fs.stat(p, function (er, stats) { +function addMode (cachedRemote, mode, cb) { + fs.stat(cachedRemote, function (er, stats) { if (er) return cb(er) mode = stats.mode | mode - fs.chmod(p, mode, cb) + fs.chmod(cachedRemote, mode, cb) }) } // taken from https://github.com/isaacs/chmodr/blob/master/chmodr.js -function dirMode(mode) { - if (mode & parseInt("0400", 8)) mode |= parseInt("0100", 8) - if (mode & parseInt( "040", 8)) mode |= parseInt( "010", 8) - if (mode & parseInt( "04", 8)) mode |= parseInt( "01", 8) +function dirMode (mode) { + if (mode & parseInt('0400', 8)) mode |= parseInt('0100', 8) + if (mode & parseInt('040', 8)) mode |= parseInt('010', 8) + if (mode & parseInt('04', 8)) mode |= parseInt('01', 8) return mode } diff --git a/deps/npm/lib/cache/add-remote-tarball.js b/deps/npm/lib/cache/add-remote-tarball.js index e87ac54bb1..66d2200966 100644 --- a/deps/npm/lib/cache/add-remote-tarball.js +++ b/deps/npm/lib/cache/add-remote-tarball.js @@ -19,8 +19,8 @@ function addRemoteTarball (u, pkgData, shasum, auth, cb_) { function cb (er, data) { if (data) { data._from = u - data._shasum = data._shasum || shasum data._resolved = u + data._shasum = data._shasum || shasum } cb_(er, data) } diff --git a/deps/npm/lib/config/defaults.js b/deps/npm/lib/config/defaults.js index e49ce210b3..e5744772ed 100644 --- a/deps/npm/lib/config/defaults.js +++ b/deps/npm/lib/config/defaults.js @@ -32,12 +32,6 @@ function validateSemver (data, k, val) { data[k] = semver.valid(val) } -function validateTag (data, k, val) { - val = ("" + val).trim() - if (!val || semver.validRange(val)) return false - data[k] = val -} - function validateStream (data, k, val) { if (!(val instanceof Stream)) return false data[k] = val @@ -47,10 +41,6 @@ nopt.typeDefs.semver = { type: semver, validate: validateSemver } nopt.typeDefs.Stream = { type: Stream, validate: validateStream } nopt.typeDefs.Umask = { type: Umask, validate: validateUmask } -// Don't let --tag=1.2.3 ever be a thing -var tag = {} -nopt.typeDefs.tag = { type: tag, validate: validateTag } - nopt.invalidHandler = function (k, val, type) { log.warn("invalid config", k + "=" + JSON.stringify(val)) @@ -60,9 +50,6 @@ nopt.invalidHandler = function (k, val, type) { } switch (type) { - case tag: - log.warn("invalid config", "Tag must not be a SemVer range") - break case Umask: log.warn("invalid config", "Must be umask, octal number in range 0000..0777") break @@ -312,7 +299,7 @@ exports.types = , "sign-git-tag": Boolean , spin: ["always", Boolean] , "strict-ssl": Boolean - , tag : tag + , tag : String , tmp : path , unicode : Boolean , "unsafe-perm" : Boolean diff --git a/deps/npm/lib/dedupe.js b/deps/npm/lib/dedupe.js index 6a4abd7307..c63705e18d 100644 --- a/deps/npm/lib/dedupe.js +++ b/deps/npm/lib/dedupe.js @@ -314,11 +314,28 @@ function readInstalled (dir, counter, parent, cb) { }) fs.readdir(path.resolve(dir, "node_modules"), function (er, c) { - children = c || [] // error is ok, just means no children. - children = children.filter(function (p) { - return !p.match(/^[\._-]/) - }) - next() + children = children || [] // error is ok, just means no children. + // check if there are scoped packages. + asyncMap(c || [], function (child, cb) { + if (child.indexOf('@') === 0) { + fs.readdir(path.resolve(dir, "node_modules", child), function (er, scopedChildren) { + // error is ok, just means no children. + (scopedChildren || []).forEach(function (sc) { + children.push(path.join(child, sc)) + }) + cb() + }) + } else { + children.push(child) + cb() + } + }, function (er) { + if (er) return cb(er) + children = children.filter(function (p) { + return !p.match(/^[\._-]/) + }) + next(); + }); }) function next () { diff --git a/deps/npm/lib/install.js b/deps/npm/lib/install.js index 73580e5afa..1a235793df 100644 --- a/deps/npm/lib/install.js +++ b/deps/npm/lib/install.js @@ -109,6 +109,7 @@ var npm = require("./npm.js") , locker = require("./utils/locker.js") , lock = locker.lock , unlock = locker.unlock + , warnStrict = require("./utils/warn-deprecated.js")("engineStrict") , warnPeers = require("./utils/warn-deprecated.js")("peerDependencies") function install (args, cb_) { @@ -117,7 +118,7 @@ function install (args, cb_) { function cb (er, installed) { if (er) return cb_(er) - findPeerInvalid(where, function (er, problem) { + validateInstall(where, function (er, problem) { if (er) return cb_(er) if (problem) { @@ -244,11 +245,24 @@ function install (args, cb_) { }) } -function findPeerInvalid (where, cb) { - readInstalled(where, { log: log.warn, dev: true }, function (er, data) { - if (er) return cb(er) +function validateInstall (where, cb) { + readJson(path.resolve(where, 'package.json'), log.warn, function (er, data) { + if (er + && er.code !== 'ENOENT' + && er.code !== 'ENOTDIR') return cb(er) + + if (data && data.engineStrict) { + warnStrict([ + "Per-package engineStrict (found in this package's package.json) ", + "won't be used in npm 3+. Use the config setting `engine-strict` instead." + ], data.name) + } + + readInstalled(where, { log: log.warn, dev: true }, function (er, data) { + if (er) return cb(er) - cb(null, findPeerInvalid_(data.dependencies, [])) + cb(null, findPeerInvalid_(data.dependencies, [])) + }) }) } @@ -854,8 +868,11 @@ function targetResolver (where, context, deps) { function installOne (target, where, context, cb) { // the --link flag makes this a "link" command if it's at the // the top level. + var isGit = false + if (target && target._from) isGit = npa(target._from).type === 'git' + if (where === npm.prefix && npm.config.get("link") - && !npm.config.get("global")) { + && !npm.config.get("global") && !isGit) { return localLink(target, where, context, cb) } installOne_(target, where, context, function (er, installedWhat) { diff --git a/deps/npm/lib/npm.js b/deps/npm/lib/npm.js index 3cd21cac1d..459a3c3245 100644 --- a/deps/npm/lib/npm.js +++ b/deps/npm/lib/npm.js @@ -66,6 +66,7 @@ var commandCache = {} , "i" : "install" , "isntall" : "install" , "up" : "update" + , "upgrade" : "update" , "c" : "config" , "dist-tags" : "dist-tag" , "info" : "view" diff --git a/deps/npm/lib/publish.js b/deps/npm/lib/publish.js index 06a3404af9..92a9a9b671 100644 --- a/deps/npm/lib/publish.js +++ b/deps/npm/lib/publish.js @@ -13,10 +13,12 @@ var npm = require("./npm.js") , cachedPackageRoot = require("./cache/cached-package-root.js") , createReadStream = require("graceful-fs").createReadStream , npa = require("npm-package-arg") + , semver = require('semver') -publish.usage = "npm publish <tarball>" - + "\nnpm publish <folder>" +publish.usage = "npm publish <tarball> [--tag <tagname>]" + + "\nnpm publish <folder> [--tag <tagname>]" + "\n\nPublishes '.' if no argument supplied" + + "\n\nSets tag `latest` if no --tag specified" publish.completion = function (opts, cb) { // publish can complete to a folder with a package.json @@ -34,6 +36,13 @@ function publish (args, isRetry, cb) { if (args.length !== 1) return cb(publish.usage) log.verbose("publish", args) + + var t = npm.config.get('tag').trim() + if (semver.validRange(t)) { + var er = new Error("Tag name must not be a valid SemVer range: " + t) + return cb(er) + } + var arg = args[0] // if it's a local folder, then run the prepublish there, first. readJson(path.resolve(arg, "package.json"), function (er, data) { diff --git a/deps/npm/lib/stars.js b/deps/npm/lib/stars.js index 087e8d9bf2..01ec76e42c 100644 --- a/deps/npm/lib/stars.js +++ b/deps/npm/lib/stars.js @@ -9,6 +9,17 @@ var npm = require("./npm.js") function stars (args, cb) { npm.commands.whoami([], true, function (er, username) { var name = args.length === 1 ? args[0] : username + + if (er) { + if (er.code === 'ENEEDAUTH' && !name) { + var needAuth = new Error("'npm stars' on your own user account requires auth") + needAuth.code = 'ENEEDAUTH' + return cb(needAuth) + } + + if (er.code !== 'ENEEDAUTH') return cb(er) + } + mapToRegistry("", npm.config, function (er, uri, auth) { if (er) return cb(er) diff --git a/deps/npm/lib/update.js b/deps/npm/lib/update.js index 06d199cc09..3e9438e923 100644 --- a/deps/npm/lib/update.js +++ b/deps/npm/lib/update.js @@ -22,10 +22,26 @@ update.completion = npm.commands.outdated.completion function update (args, cb) { npm.commands.outdated(args, true, function (er, outdated) { - log.info("outdated", "updating", outdated) if (er) return cb(er) - asyncMap(outdated, function (ww, cb) { + var wanted = outdated.filter(function (ww) { + var dep = ww[1] + var current = ww[2] + var wanted = ww[3] + var latest = ww[4] + if (current === wanted && wanted !== latest) { + log.verbose( + 'outdated', + 'not updating', dep, + "because it's currently at the maximum version that matches its specified semver range" + ) + } + return current !== wanted + }) + if (wanted.length === 0) return cb() + + log.info('outdated', 'updating', wanted) + asyncMap(wanted, function (ww, cb) { // [[ dir, dep, has, want, req ]] var where = ww[0] , dep = ww[1] diff --git a/deps/npm/lib/utils/error-handler.js b/deps/npm/lib/utils/error-handler.js index de12c63632..1c80ab590f 100644 --- a/deps/npm/lib/utils/error-handler.js +++ b/deps/npm/lib/utils/error-handler.js @@ -287,6 +287,7 @@ function errorHandler (er) { case "ECONNRESET": case "ENOTFOUND": case "ETIMEDOUT": + case "EAI_FAIL": log.error("network", [er.message ,"This is most likely not a problem with npm itself" ,"and is related to network connectivity." @@ -354,7 +355,7 @@ function errorHandler (er) { default: log.error("", er.message || er) log.error("", ["", "If you need help, you may report this error at:" - ," <http://github.com/npm/npm/issues>" + ," <https://github.com/npm/npm/issues>" ].join("\n")) break } diff --git a/deps/npm/lib/whoami.js b/deps/npm/lib/whoami.js index 42cede1b82..d92a6574a1 100644 --- a/deps/npm/lib/whoami.js +++ b/deps/npm/lib/whoami.js @@ -14,14 +14,6 @@ function whoami (args, silent, cb) { var registry = npm.config.get("registry") if (!registry) return cb(new Error("no default registry set")) - function noUser () { - // At this point, if they have a credentials object, it doesn't have a - // token or auth in it. Probably just the default registry. - var msg = "Not authed. Run 'npm adduser'" - if (!silent) console.log(msg) - cb(null, msg) - } - var auth = npm.config.getCredentialsByURI(registry) if (auth) { if (auth.username) { @@ -31,7 +23,13 @@ function whoami (args, silent, cb) { else if (auth.token) { return npm.registry.whoami(registry, { auth : auth }, function (er, username) { if (er) return cb(er) - if (!username) return noUser() + if (!username) { + var needNewSession = new Error( + "Your auth token is no longer valid. Please log in again." + ) + needNewSession.code = 'ENEEDAUTH' + return cb(needNewSession) + } if (!silent) console.log(username) cb(null, username) @@ -39,5 +37,11 @@ function whoami (args, silent, cb) { } } - process.nextTick(noUser) + // At this point, if they have a credentials object, it doesn't have a token + // or auth in it. Probably just the default registry. + var needAuth = new Error( + "'npm whoami' requires you to be logged in." + ) + needAuth.code = 'ENEEDAUTH' + process.nextTick(cb.bind(this, needAuth)) } |