1 // npm install <pkg> <pkg> <pkg>
3 // See doc/install.md for more description
5 // Managing contexts...
6 // there's a lot of state associated with an "install" operation, including
7 // packages that are already installed, parent packages, current shrinkwrap, and
8 // so on. We maintain this state in a "context" object that gets passed around.
9 // every time we dive into a deeper node_modules folder, the "family" list that
10 // gets passed along uses the previous "family" list as its __proto__. Any
11 // "resolved precise dependency" things that aren't already on this object get
12 // added, and then that's passed to the next generation of installation.
14 module.exports = install
16 install.usage = "npm install"
17 + "\nnpm install <pkg>"
18 + "\nnpm install <pkg>@<tag>"
19 + "\nnpm install <pkg>@<version>"
20 + "\nnpm install <pkg>@<version range>"
21 + "\nnpm install <folder>"
22 + "\nnpm install <tarball file>"
23 + "\nnpm install <tarball url>"
24 + "\nnpm install <git:// url>"
25 + "\nnpm install <github username>/<github project>"
26 + "\n\nCan specify one or more: npm install ./foo.tgz bar@stable /some/folder"
27 + "\nIf no argument is supplied and ./npm-shrinkwrap.json is "
28 + "\npresent, installs dependencies specified in the shrinkwrap."
29 + "\nOtherwise, installs dependencies from ./package.json."
31 install.completion = function (opts, cb) {
32 // install can complete to a folder with a package.json, or any package.
33 // if it has a slash, then it's gotta be a folder
34 // if it starts with https?://, then just give up, because it's a url
35 // for now, not yet implemented.
36 var registry = npm.registry
37 registry.get("/-/short", function (er, pkgs) {
39 if (!opts.partialWord) return cb(null, pkgs)
41 var name = opts.partialWord.split("@").shift()
42 pkgs = pkgs.filter(function (p) {
43 return p.indexOf(name) === 0
46 if (pkgs.length !== 1 && opts.partialWord === name) {
50 registry.get(pkgs[0], function (er, d) {
52 return cb(null, Object.keys(d["dist-tags"] || {})
53 .concat(Object.keys(d.versions || {}))
55 return pkgs[0] + "@" + t
61 var npm = require("./npm.js")
62 , semver = require("semver")
63 , readJson = require("read-package-json")
64 , readInstalled = require("read-installed")
65 , log = require("npmlog")
66 , path = require("path")
67 , fs = require("graceful-fs")
68 , cache = require("./cache.js")
69 , asyncMap = require("slide").asyncMap
70 , chain = require("slide").chain
71 , url = require("url")
72 , mkdir = require("mkdirp")
73 , lifecycle = require("./utils/lifecycle.js")
74 , archy = require("archy")
75 , isGitUrl = require("./utils/is-git-url.js")
77 function install (args, cb_) {
78 var hasArguments = !!args.length
80 function cb (er, installed) {
81 if (er) return cb_(er)
83 findPeerInvalid(where, function (er, problem) {
84 if (er) return cb_(er)
87 var peerInvalidError = new Error("The package " + problem.name +
88 " does not satisfy its siblings' peerDependencies requirements!")
89 peerInvalidError.code = "EPEERINVALID"
90 peerInvalidError.packageName = problem.name
91 peerInvalidError.peersDepending = problem.peersDepending
92 return cb(peerInvalidError)
95 var tree = treeify(installed || [])
96 , pretty = prettify(tree, installed).trim()
98 if (pretty) console.log(pretty)
99 save(where, installed, tree, pretty, hasArguments, cb_)
103 // the /path/to/node_modules/..
104 var where = path.resolve(npm.dir, "..")
106 // internal api: install(where, what, cb)
107 if (arguments.length === 3) {
109 args = [].concat(cb_) // pass in [] to do default dep-install
111 log.verbose("install", "where,what", [where, args])
114 if (!npm.config.get("global")) {
115 args = args.filter(function (a) {
116 return path.resolve(a) !== where
120 mkdir(where, function (er, made) {
121 if (er) return cb(er)
122 // install dependencies locally by default,
123 // or install current folder globally
125 var opt = { dev: npm.config.get("dev") || !npm.config.get("production") }
127 if (npm.config.get("global")) args = ["."]
128 else return readDependencies(null, where, opt, function (er, data) {
130 log.error("install", "Couldn't read dependencies")
133 var deps = Object.keys(data.dependencies || {})
134 log.verbose("install", "where, deps", [where, deps])
135 var context = { family: {}
142 if (data.name === path.basename(where) &&
143 path.basename(path.dirname(where)) === "node_modules") {
144 // Only include in ancestry if it can actually be required.
145 // Otherwise, it does not count.
146 context.family[data.name] =
147 context.ancestors[data.name] = data.version
150 installManyTop(deps.map(function (dep) {
151 var target = data.dependencies[dep]
152 , parsed = url.parse(target.replace(/^git\+/, "git"))
153 target = dep + "@" + target
155 }), where, context, function(er, results) {
156 if (er) return cb(er, results)
157 lifecycle(data, "prepublish", where, function(er) {
158 return cb(er, results)
164 // initial "family" is the name:version of the root, if it's got
165 // a package.json file.
166 var jsonFile = path.resolve(where, "package.json")
167 readJson(jsonFile, log.warn, function (er, data) {
169 && er.code !== "ENOENT"
170 && er.code !== "ENOTDIR") return cb(er)
172 var context = { family: {}
179 context.family[data.name] = context.ancestors[data.name] = data.version
181 var fn = npm.config.get("global") ? installMany : installManyTop
182 fn(args, where, context, cb)
187 function findPeerInvalid (where, cb) {
188 readInstalled(where, log.warn, function (er, data) {
189 if (er) return cb(er)
191 cb(null, findPeerInvalid_(data.dependencies, []))
195 function findPeerInvalid_ (packageMap, fpiList) {
196 if (fpiList.indexOf(packageMap) !== -1)
199 fpiList.push(packageMap)
201 for (var packageName in packageMap) {
202 var pkg = packageMap[packageName]
204 if (pkg.peerInvalid) {
205 var peersDepending = {};
206 for (peerName in packageMap) {
207 var peer = packageMap[peerName]
208 if (peer.peerDependencies && peer.peerDependencies[packageName]) {
209 peersDepending[peer.name + "@" + peer.version] =
210 peer.peerDependencies[packageName]
213 return { name: pkg.name, peersDepending: peersDepending }
216 if (pkg.dependencies) {
217 var invalid = findPeerInvalid_(pkg.dependencies, fpiList)
226 // reads dependencies for the package at "where". There are several cases,
227 // depending on our current state and the package's configuration:
229 // 1. If "context" is specified, then we examine the context to see if there's a
230 // shrinkwrap there. In that case, dependencies are read from the shrinkwrap.
231 // 2. Otherwise, if an npm-shrinkwrap.json file is present, dependencies are
233 // 3. Otherwise, dependencies come from package.json.
235 // Regardless of which case we fall into, "cb" is invoked with a first argument
236 // describing the full package (as though readJson had been used) but with
237 // "dependencies" read as described above. The second argument to "cb" is the
238 // shrinkwrap to use in processing this package's dependencies, which may be
239 // "wrap" (in case 1) or a new shrinkwrap (in case 2).
240 function readDependencies (context, where, opts, cb) {
241 var wrap = context ? context.wrap : null
243 readJson( path.resolve(where, "package.json")
245 , function (er, data) {
246 if (er && er.code === "ENOENT") er.code = "ENOPACKAGEJSON"
247 if (er) return cb(er)
249 if (opts && opts.dev) {
250 if (!data.dependencies) data.dependencies = {}
251 Object.keys(data.devDependencies || {}).forEach(function (k) {
252 data.dependencies[k] = data.devDependencies[k]
256 if (!npm.config.get("optional") && data.optionalDependencies) {
257 Object.keys(data.optionalDependencies).forEach(function (d) {
258 delete data.dependencies[d]
262 // User has opted out of shrinkwraps entirely
263 if (npm.config.get("shrinkwrap") === false)
264 return cb(null, data, null)
267 log.verbose("readDependencies: using existing wrap", [where, wrap])
269 Object.keys(data).forEach(function (key) {
273 Object.keys(wrap).forEach(function (key) {
274 log.verbose("from wrap", [key, wrap[key]])
275 rv.dependencies[key] = readWrap(wrap[key])
277 log.verbose("readDependencies returned deps", rv.dependencies)
278 return cb(null, rv, wrap)
281 var wrapfile = path.resolve(where, "npm-shrinkwrap.json")
283 fs.readFile(wrapfile, "utf8", function (er, wrapjson) {
285 log.verbose("readDependencies", "using package.json deps")
286 return cb(null, data, null)
290 var newwrap = JSON.parse(wrapjson)
295 log.info("shrinkwrap", "file %j", wrapfile)
297 Object.keys(data).forEach(function (key) {
301 Object.keys(newwrap.dependencies || {}).forEach(function (key) {
302 rv.dependencies[key] = readWrap(newwrap.dependencies[key])
305 // fold in devDependencies if not already present, at top level
306 if (opts && opts.dev) {
307 Object.keys(data.devDependencies || {}).forEach(function (k) {
308 rv.dependencies[k] = rv.dependencies[k] || data.devDependencies[k]
312 log.verbose("readDependencies returned deps", rv.dependencies)
313 return cb(null, rv, newwrap.dependencies)
318 function readWrap (w) {
319 return (w.resolved) ? w.resolved
320 : (w.from && url.parse(w.from).protocol) ? w.from
324 // if the -S|--save option is specified, then write installed packages
325 // as dependencies to a package.json file.
326 // This is experimental.
327 function save (where, installed, tree, pretty, hasArguments, cb) {
329 !npm.config.get("save") &&
330 !npm.config.get("save-dev") &&
331 !npm.config.get("save-optional") ||
332 npm.config.get("global")) {
333 return cb(null, installed, tree, pretty)
336 var saveBundle = npm.config.get('save-bundle')
338 // each item in the tree is a top-level thing that should be saved
339 // to the package.json file.
340 // The relevant tree shape is { <folder>: {what:<pkg>} }
341 var saveTarget = path.resolve(where, "package.json")
342 , things = Object.keys(tree).map(function (k) {
343 // if "what" was a url, then save that instead.
345 , u = url.parse(t.from)
346 , w = t.what.split("@")
347 if (u && u.protocol) w[1] = t.from
349 }).reduce(function (set, k) {
350 var rangeDescriptor = semver.valid(k[1], true) &&
351 semver.gte(k[1], "0.1.0", true)
353 set[k[0]] = rangeDescriptor + k[1]
357 // don't use readJson, because we don't want to do all the other
358 // tricky npm-specific stuff that's in there.
359 fs.readFile(saveTarget, function (er, data) {
360 // ignore errors here, just don't save it.
362 data = JSON.parse(data.toString("utf8"))
368 return cb(null, installed, tree, pretty)
371 var deps = npm.config.get("save-optional") ? "optionalDependencies"
372 : npm.config.get("save-dev") ? "devDependencies"
376 var bundle = data.bundleDependencies || data.bundledDependencies
377 delete data.bundledDependencies
378 if (!Array.isArray(bundle)) bundle = []
379 data.bundleDependencies = bundle
382 log.verbose('saving', things)
383 data[deps] = data[deps] || {}
384 Object.keys(things).forEach(function (t) {
385 data[deps][t] = things[t]
387 var i = bundle.indexOf(t)
388 if (i === -1) bundle.push(t)
392 data = JSON.stringify(data, null, 2) + "\n"
393 fs.writeFile(saveTarget, data, function (er) {
394 cb(er, installed, tree, pretty)
400 // Outputting *all* the installed modules is a bit confusing,
401 // because the length of the path does not make it clear
402 // that the submodules are not immediately require()able.
403 // TODO: Show the complete tree, ls-style, but only if --long is provided
404 function prettify (tree, installed) {
405 if (npm.config.get("json")) {
406 function red (set, kv) {
411 tree = Object.keys(tree).map(function (p) {
412 if (!tree[p]) return null
413 var what = tree[p].what.split("@")
414 , name = what.shift()
415 , version = what.join("@")
416 , o = { name: name, version: version, from: tree[p].from }
417 o.dependencies = tree[p].children.map(function P (dep) {
418 var what = dep.what.split("@")
419 , name = what.shift()
420 , version = what.join("@")
421 , o = { version: version, from: dep.from }
422 o.dependencies = dep.children.map(P).reduce(red, {})
428 return JSON.stringify(tree, null, 2)
430 if (npm.config.get("parseable")) return parseable(installed)
432 return Object.keys(tree).map(function (p) {
433 return archy({ label: tree[p].what + " " + p
434 , nodes: (tree[p].children || []).map(function P (c) {
435 if (npm.config.get("long")) {
436 return { label: c.what, nodes: c.children.map(P) }
438 var g = c.children.map(function (g) {
441 if (g) g = " (" + g + ")"
448 function parseable (installed) {
449 var long = npm.config.get("long")
450 , cwd = process.cwd()
451 return installed.map(function (item) {
452 return path.resolve(cwd, item[1]) +
453 ( long ? ":" + item[0] : "" )
457 function treeify (installed) {
458 // each item is [what, where, parent, parentDir]
459 // If no parent, then report it.
460 // otherwise, tack it into the parent's children list.
461 // If the parent isn't a top-level then ignore it.
462 var whatWhere = installed.reduce(function (l, r) {
468 l[where] = { parentDir: parentDir
477 // log.warn("install", whatWhere, "whatWhere")
478 return Object.keys(whatWhere).reduce(function (l, r) {
479 var ww = whatWhere[r]
480 //log.warn("r, ww", [r, ww])
484 var p = whatWhere[ww.parentDir]
485 if (p) p.children.push(ww)
493 // just like installMany, but also add the existing packages in
494 // where/node_modules to the family object.
495 function installManyTop (what, where, context, cb_) {
496 function cb (er, d) {
497 if (context.explicit || er) return cb_(er, d)
498 // since this wasn't an explicit install, let's build the top
499 // folder, so that `npm install` also runs the lifecycle scripts.
500 npm.commands.build([where], false, true, function (er) {
505 if (context.explicit) return next()
507 readJson(path.join(where, "package.json"), log.warn, function (er, data) {
508 if (er) return next(er)
509 lifecycle(data, "preinstall", where, next)
513 if (er) return cb(er)
514 installManyTop_(what, where, context, cb)
518 function installManyTop_ (what, where, context, cb) {
519 var nm = path.resolve(where, "node_modules")
520 , names = context.explicit
521 ? what.map(function (w) { return w.split(/@/).shift() })
524 fs.readdir(nm, function (er, pkgs) {
525 if (er) return installMany(what, where, context, cb)
526 pkgs = pkgs.filter(function (p) {
527 return !p.match(/^[\._-]/)
529 asyncMap(pkgs.map(function (p) {
530 return path.resolve(nm, p, "package.json")
531 }), function (jsonfile, cb) {
532 readJson(jsonfile, log.warn, function (er, data) {
533 if (er && er.code !== "ENOENT" && er.code !== "ENOTDIR") return cb(er)
534 if (er) return cb(null, [])
535 return cb(null, [[data.name, data.version]])
537 }, function (er, packages) {
538 // if there's nothing in node_modules, then don't freak out.
539 if (er) packages = []
540 // add all the existing packages to the family list.
541 // however, do not add to the ancestors list.
542 packages.forEach(function (p) {
543 context.family[p[0]] = p[1]
545 return installMany(what, where, context, cb)
550 function installMany (what, where, context, cb) {
551 // readDependencies takes care of figuring out whether the list of
552 // dependencies we'll iterate below comes from an existing shrinkwrap from a
553 // parent level, a new shrinkwrap at this level, or package.json at this
554 // level, as well as which shrinkwrap (if any) our dependencies should use.
555 var opt = { dev: npm.config.get("dev") }
556 readDependencies(context, where, opt, function (er, data, wrap) {
561 var d = data.dependencies || {}
563 // if we're explicitly installing "what" into "where", then the shrinkwrap
564 // for "where" doesn't apply. This would be the case if someone were adding
565 // a new package to a shrinkwrapped package. (data.dependencies will not be
566 // used here except to indicate what packages are already present, so
567 // there's no harm in using that.)
568 if (context.explicit) wrap = null
570 // what is a list of things.
573 , targetResolver(where, context, d)
574 , function (er, targets) {
576 if (er) return cb(er)
578 // each target will be a data object corresponding
579 // to a package, folder, or whatever that is in the cache now.
580 var newPrev = Object.create(context.family)
581 , newAnc = Object.create(context.ancestors)
584 newAnc[data.name] = data.version
586 targets.forEach(function (t) {
587 newPrev[t.name] = t.version
589 log.silly("resolved", targets)
590 targets.filter(function (t) { return t }).forEach(function (t) {
591 log.info("install", "%s into %s", t._id, where)
593 asyncMap(targets, function (target, cb) {
594 log.info("installOne", target._id)
595 var wrapData = wrap ? wrap[target.name] : null
596 var newWrap = wrapData && wrapData.dependencies
597 ? wrap[target.name].dependencies || {}
599 var newContext = { family: newPrev
604 installOne(target, where, newContext, cb)
610 function targetResolver (where, context, deps) {
611 var alreadyInstalledManually = context.explicit ? [] : null
612 , nm = path.resolve(where, "node_modules")
613 , parent = context.parent
614 , wrap = context.wrap
616 if (!context.explicit) fs.readdir(nm, function (er, inst) {
617 if (er) return alreadyInstalledManually = []
619 // don't even mess with non-package looking things
620 inst = inst.filter(function (p) {
621 return !p.match(/^[\._-]/)
624 asyncMap(inst, function (pkg, cb) {
625 readJson(path.resolve(nm, pkg, "package.json"), log.warn, function (er, d) {
626 if (er && er.code !== "ENOENT" && er.code !== "ENOTDIR") return cb(er)
627 // error means it's not a package, most likely.
628 if (er) return cb(null, [])
630 // if it's a bundled dep, then assume that anything there is valid.
631 // otherwise, make sure that it's a semver match with what we want.
632 var bd = parent.bundleDependencies
633 if (bd && bd.indexOf(d.name) !== -1 ||
634 semver.satisfies(d.version, deps[d.name] || "*", true) ||
635 deps[d.name] === d._resolved) {
636 return cb(null, d.name)
639 // something is there, but it's not satisfactory. Clobber it.
642 }, function (er, inst) {
643 // this is the list of things that are valid and should be ignored.
644 alreadyInstalledManually = inst
649 return function resolver (what, cb) {
650 if (!alreadyInstalledManually) return setTimeout(function () {
654 // now we know what's been installed here manually,
655 // or tampered with in some way that npm doesn't want to overwrite.
656 if (alreadyInstalledManually.indexOf(what.split("@").shift()) !== -1) {
657 log.verbose("already installed", "skipping %s %s", what, where)
661 // check for a version installed higher in the tree.
662 // If installing from a shrinkwrap, it must match exactly.
663 if (context.family[what]) {
664 if (wrap && wrap[what].version === context.family[what]) {
665 log.verbose("shrinkwrap", "use existing", what)
670 // if it's identical to its parent, then it's probably someone
671 // doing `npm install foo` inside of the foo project. Print
672 // a warning, and skip it.
673 if (parent && parent.name === what && !npm.config.get("force")) {
674 log.warn("install", "Refusing to install %s as a dependency of itself"
680 var name = what.split(/@/).shift()
682 var wrapTarget = readWrap(wrap[name])
683 what = name + "@" + wrapTarget
685 log.verbose("shrinkwrap", "skipping %s (not in shrinkwrap)", what)
687 } else if (deps[what]) {
688 what = what + "@" + deps[what]
691 cache.add(what, function (er, data) {
692 if (er && parent && parent.optionalDependencies &&
693 parent.optionalDependencies.hasOwnProperty(what.split("@")[0])) {
694 log.warn("optional dep failed, continuing", what)
695 log.verbose("optional dep failed, continuing", [what, er])
699 // if the target is a git repository, we always want to fetch it
701 , maybeGit = what.split("@").pop()
704 isGit = isGitUrl(url.parse(maybeGit))
709 context.family[data.name] === data.version &&
710 !npm.config.get("force") &&
712 log.info("already installed", data.name + "@" + data.version)
716 if (data && !data._from) data._from = what
718 return cb(er, data || [])
723 // we've already decided to install this. if anything's in the way,
724 // then uninstall it first.
725 function installOne (target, where, context, cb) {
726 // the --link flag makes this a "link" command if it's at the
728 if (where === npm.prefix && npm.config.get("link")
729 && !npm.config.get("global")) {
730 return localLink(target, where, context, cb)
732 installOne_(target, where, context, function (er, installedWhat) {
734 // check if this one is optional to its parent.
735 if (er && context.parent && context.parent.optionalDependencies &&
736 context.parent.optionalDependencies.hasOwnProperty(target.name)) {
737 log.warn("optional dep failed, continuing", target._id)
738 log.verbose("optional dep failed, continuing", [target._id, er])
742 cb(er, installedWhat)
747 function localLink (target, where, context, cb) {
748 log.verbose("localLink", target._id)
749 var jsonFile = path.resolve( npm.globalDir, target.name
751 , parent = context.parent
753 readJson(jsonFile, log.warn, function (er, data) {
754 if (er && er.code !== "ENOENT" && er.code !== "ENOTDIR") return cb(er)
755 if (er || data._id === target._id) {
757 install( path.resolve(npm.globalDir, "..")
760 if (er) return cb(er, [])
765 function thenLink () {
766 npm.commands.link([target.name], function (er, d) {
767 log.silly("localLink", "back from link", [er, d])
768 cb(er, [resultList(target, where, parent && parent._id)])
773 log.verbose("localLink", "install locally (no link)", target._id)
774 installOne_(target, where, context, cb)
779 function resultList (target, where, parentId) {
780 var nm = path.resolve(where, "node_modules")
781 , targetFolder = path.resolve(nm, target.name)
782 , prettyWhere = where
784 if (!npm.config.get("global")) {
785 prettyWhere = path.relative(process.cwd(), where)
788 if (prettyWhere === ".") prettyWhere = null
790 if (!npm.config.get("global")) {
791 // print out the folder relative to where we are right now.
792 targetFolder = path.relative(process.cwd(), targetFolder)
797 , prettyWhere && parentId
798 , parentId && prettyWhere
802 // name => install locations
803 var installOnesInProgress = Object.create(null)
805 function isIncompatibleInstallOneInProgress(target, where) {
806 return target.name in installOnesInProgress &&
807 installOnesInProgress[target.name].indexOf(where) !== -1
810 function installOne_ (target, where, context, cb) {
811 var nm = path.resolve(where, "node_modules")
812 , targetFolder = path.resolve(nm, target.name)
813 , prettyWhere = path.relative(process.cwd(), where)
814 , parent = context.parent
816 if (prettyWhere === ".") prettyWhere = null
818 if (isIncompatibleInstallOneInProgress(target, where)) {
819 var prettyTarget = path.relative(process.cwd(), targetFolder)
821 // just call back, with no error. the error will be detected in the
822 // final check for peer-invalid dependencies
826 if (!(target.name in installOnesInProgress)) {
827 installOnesInProgress[target.name] = []
829 installOnesInProgress[target.name].push(where)
830 var indexOfIOIP = installOnesInProgress[target.name].length - 1
833 ( [ [checkEngine, target]
834 , [checkPlatform, target]
835 , [checkCycle, target, context.ancestors]
836 , [checkGit, targetFolder]
837 , [write, target, targetFolder, context] ]
839 installOnesInProgress[target.name].splice(indexOfIOIP, 1)
841 if (er) return cb(er)
843 d.push(resultList(target, where, parent && parent._id))
849 function checkEngine (target, cb) {
850 var npmv = npm.version
851 , force = npm.config.get("force")
852 , nodev = force ? null : npm.config.get("node-version")
853 , strict = npm.config.get("engine-strict") || target.engineStrict
854 , eng = target.engines
855 if (!eng) return cb()
856 if (nodev && eng.node && !semver.satisfies(nodev, eng.node)
857 || eng.npm && !semver.satisfies(npmv, eng.npm)) {
859 var er = new Error("Unsupported")
862 er.pkgid = target._id
865 log.warn( "engine", "%s: wanted: %j (current: %j)"
866 , target._id, eng, {node: nodev, npm: npm.version} )
872 function checkPlatform (target, cb) {
873 var platform = process.platform
874 , arch = process.arch
877 , force = npm.config.get("force")
884 osOk = checkList(platform, target.os)
887 cpuOk = checkList(arch, target.cpu)
889 if (!osOk || !cpuOk) {
890 var er = new Error("Unsupported")
891 er.code = "EBADPLATFORM"
892 er.os = target.os || ['any']
893 er.cpu = target.cpu || ['any']
894 er.pkgid = target._id
900 function checkList (value, list) {
904 if (typeof list === "string") {
907 if (list.length === 1 && list[0] === "any") {
910 for (var i = 0; i < list.length; ++i) {
912 if (tmp[0] === '!') {
919 match = match || tmp === value
922 return match || blc === list.length
925 function checkCycle (target, ancestors, cb) {
926 // there are some very rare and pathological edge-cases where
927 // a cycle can cause npm to try to install a never-ending tree
931 // A -> B -> A' -> B' -> A -> B -> A' -> B' -> A -> ...
933 // Solution: Simply flat-out refuse to install any name@version
934 // that is already in the prototype tree of the ancestors object.
935 // A more correct, but more complex, solution would be to symlink
936 // the deeper thing into the new location.
937 // Will do that if anyone whines about this irl.
939 // Note: `npm install foo` inside of the `foo` package will abort
940 // earlier if `--force` is not set. However, if it IS set, then
941 // we need to still fail here, but just skip the first level. Of
942 // course, it'll still fail eventually if it's a true cycle, and
943 // leave things in an undefined state, but that's what is to be
944 // expected when `--force` is used. That is why getPrototypeOf
945 // is used *twice* here: to skip the first level of repetition.
947 var p = Object.getPrototypeOf(Object.getPrototypeOf(ancestors))
949 , version = target.version
950 while (p && p !== Object.prototype && p[name] !== version) {
951 p = Object.getPrototypeOf(p)
953 if (p[name] !== version) return cb()
955 var er = new Error("Unresolvable cycle detected")
956 var tree = [target._id, JSON.parse(JSON.stringify(ancestors))]
957 , t = Object.getPrototypeOf(ancestors)
958 while (t && t !== Object.prototype) {
959 if (t === p) t.THIS_IS_P = true
960 tree.push(JSON.parse(JSON.stringify(t)))
961 t = Object.getPrototypeOf(t)
963 log.verbose("unresolvable dependency tree", tree)
964 er.pkgid = target._id
969 function checkGit (folder, cb) {
970 // if it's a git repo then don't touch it!
971 fs.lstat(folder, function (er, s) {
972 if (er || !s.isDirectory()) return cb()
973 else checkGit_(folder, cb)
977 function checkGit_ (folder, cb) {
978 fs.stat(path.resolve(folder, ".git"), function (er, s) {
979 if (!er && s.isDirectory()) {
980 var e = new Error("Appears to be a git repo or submodule.")
989 function write (target, targetFolder, context, cb_) {
990 var up = npm.config.get("unsafe-perm")
991 , user = up ? null : npm.config.get("user")
992 , group = up ? null : npm.config.get("group")
993 , family = context.family
995 function cb (er, data) {
996 // cache.unpack returns the data object, and all we care about
997 // is the list of installed packages from that last thing.
998 if (!er) return cb_(er, data)
1000 if (false === npm.config.get("rollback")) return cb_(er)
1001 npm.commands.unbuild([targetFolder], true, function (er2) {
1002 if (er2) log.error("error rolling back", target._id, er2)
1003 return cb_(er, data)
1010 ( [ [ cache.unpack, target.name, target.version, targetFolder
1011 , null, null, user, group ]
1013 , path.resolve(targetFolder, "package.json")
1014 , JSON.stringify(target, null, 2) + "\n" ]
1015 , [ lifecycle, target, "preinstall", targetFolder ]
1017 if (!target.bundleDependencies) return cb()
1019 var bd = path.resolve(targetFolder, "node_modules")
1020 fs.readdir(bd, function (er, b) {
1021 // nothing bundled, maybe
1028 // nest the chain so that we can throw away the results returned
1029 // up until this point, since we really don't care about it.
1031 if (er) return cb(er)
1033 // before continuing to installing dependencies, check for a shrinkwrap.
1034 var opt = { dev: npm.config.get("dev") }
1035 readDependencies(context, targetFolder, opt, function (er, data, wrap) {
1036 var deps = prepareForInstallMany(data, "dependencies", bundled, wrap,
1038 var depsTargetFolder = targetFolder
1039 var depsContext = { family: family
1040 , ancestors: context.ancestors
1045 var peerDeps = prepareForInstallMany(data, "peerDependencies", bundled,
1047 var pdTargetFolder = path.resolve(targetFolder, "..", "..")
1048 var pdContext = context
1051 [ [ installManyAndBuild, deps, depsTargetFolder, depsContext ] ]
1053 if (peerDeps.length > 0) {
1055 [ installMany, peerDeps, pdTargetFolder, pdContext ]
1064 function installManyAndBuild (deps, targetFolder, context, cb) {
1065 installMany(deps, targetFolder, context, function (er, d) {
1066 log.verbose("about to build", targetFolder)
1067 if (er) return cb(er)
1068 npm.commands.build( [targetFolder]
1069 , npm.config.get("global")
1071 , function (er) { return cb(er, d) })
1075 function prepareForInstallMany (packageData, depsKey, bundled, wrap, family) {
1076 var deps = Object.keys(packageData[depsKey] || {})
1078 // don't install bundleDependencies, unless they're missing.
1079 if (packageData.bundleDependencies) {
1080 deps = deps.filter(function (d) {
1081 return packageData.bundleDependencies.indexOf(d) === -1 ||
1082 bundled.indexOf(d) === -1
1086 return deps.filter(function (d) {
1087 // prefer to not install things that are satisfied by
1088 // something in the "family" list, unless we're installing
1089 // from a shrinkwrap.
1090 if (wrap) return wrap
1091 if (semver.validRange(family[d], true))
1092 return !semver.satisfies(family[d], packageData[depsKey][d], true)
1094 }).map(function (d) {
1095 var t = packageData[depsKey][d]
1096 , parsed = url.parse(t.replace(/^git\+/, "git"))