1 // npm install <pkg> <pkg> <pkg>
3 // See doc/cli/npm-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 if (/^https?:\/\//.test(opts.partialWord)) {
36 // do not complete to URLs
40 if (/\//.test(opts.partialWord)) {
41 // Complete fully to folder if there is exactly one match and it
42 // is a folder containing a package.json file. If that is not the
43 // case we return 0 matches, which will trigger the default bash
45 var lastSlashIdx = opts.partialWord.lastIndexOf("/")
46 var partialName = opts.partialWord.slice(lastSlashIdx + 1)
47 var partialPath = opts.partialWord.slice(0, lastSlashIdx)
48 if (partialPath === "") partialPath = "/"
50 function annotatePackageDirMatch (sibling, cb) {
51 var fullPath = path.join(partialPath, sibling)
52 if (sibling.slice(0, partialName.length) !== partialName) {
53 return cb(null, null) // not name match
55 fs.readdir(fullPath, function (err, contents) {
56 if (err) return cb(null, { isPackage: false })
62 isPackage: contents.indexOf("package.json") !== -1
68 return fs.readdir(partialPath, function (err, siblings) {
69 if (err) return cb(null, []) // invalid dir: no matching
71 asyncMap(siblings, annotatePackageDirMatch, function (err, matches) {
72 if (err) return cb(err)
74 var cleaned = matches.filter(function (x) { return x !== null })
75 if (cleaned.length !== 1) return cb(null, [])
76 if (!cleaned[0].isPackage) return cb(null, [])
78 // Success - only one match and it is a package dir
79 return cb(null, [cleaned[0].fullPath])
84 // FIXME: there used to be registry completion here, but it stopped making
85 // sense somewhere around 50,000 packages on the registry
89 var npm = require("./npm.js")
90 , semver = require("semver")
91 , readJson = require("read-package-json")
92 , readInstalled = require("read-installed")
93 , log = require("npmlog")
94 , path = require("path")
95 , fs = require("graceful-fs")
96 , writeFileAtomic = require("write-file-atomic")
97 , cache = require("./cache.js")
98 , asyncMap = require("slide").asyncMap
99 , chain = require("slide").chain
100 , url = require("url")
101 , mkdir = require("mkdirp")
102 , lifecycle = require("./utils/lifecycle.js")
103 , archy = require("archy")
104 , npmInstallChecks = require("npm-install-checks")
105 , sortedObject = require("sorted-object")
106 , mapToRegistry = require("./utils/map-to-registry.js")
107 , npa = require("npm-package-arg")
108 , inflight = require("inflight")
109 , locker = require("./utils/locker.js")
111 , unlock = locker.unlock
112 , warnStrict = require("./utils/warn-deprecated.js")("engineStrict")
113 , warnPeers = require("./utils/warn-deprecated.js")("peerDependencies")
115 function install (args, cb_) {
116 var hasArguments = !!args.length
118 function cb (er, installed) {
119 if (er) return cb_(er)
121 validateInstall(where, function (er, problem) {
122 if (er) return cb_(er)
125 var peerInvalidError = new Error("The package " + problem._id +
126 " does not satisfy its siblings' peerDependencies requirements!")
127 peerInvalidError.code = "EPEERINVALID"
128 peerInvalidError.packageName = problem.name
129 peerInvalidError.packageVersion = problem.version
130 peerInvalidError.peersDepending = problem.peersDepending
131 return cb(peerInvalidError)
134 var tree = treeify(installed || [])
135 , pretty = prettify(tree, installed).trim()
137 if (pretty) console.log(pretty)
138 save(where, installed, tree, pretty, hasArguments, cb_)
142 // the /path/to/node_modules/..
143 var where = path.resolve(npm.dir, "..")
145 // internal api: install(where, what, cb)
146 if (arguments.length === 3) {
148 args = [].concat(cb_) // pass in [] to do default dep-install
150 log.verbose("install", "where, what", [where, args])
153 if (!npm.config.get("global")) {
154 args = args.filter(function (a) {
155 return path.resolve(a) !== where
159 mkdir(where, function (er) {
160 if (er) return cb(er)
161 // install dependencies locally by default,
162 // or install current folder globally
164 var opt = { dev: npm.config.get("dev") || !npm.config.get("production") }
166 if (npm.config.get("global")) args = ["."]
167 else return readDependencies(null, where, opt, function (er, data) {
169 log.error("install", "Couldn't read dependencies")
172 var deps = Object.keys(data.dependencies || {})
173 log.verbose("install", "where, deps", [where, deps])
175 // FIXME: Install peerDependencies as direct dependencies, but only at
176 // the top level. Should only last until peerDependencies are nerfed to
177 // no longer implicitly install themselves.
179 Object.keys(data.peerDependencies || {}).forEach(function (dep) {
180 if (!data.dependencies[dep]) {
183 "peerDependency", dep, "wasn't going to be installed; adding"
186 "The peer dependency "+dep+" included from "+data.name+" will no",
187 "longer be automatically installed to fulfill the peerDependency ",
188 "in npm 3+. Your application will need to depend on it explicitly."
189 ], dep+","+data.name)
193 log.verbose("install", "where, peers", [where, peers])
195 var context = { family: {}
202 if (data.name === path.basename(where) &&
203 path.basename(path.dirname(where)) === "node_modules") {
204 // Only include in ancestry if it can actually be required.
205 // Otherwise, it does not count.
206 context.family[data.name] =
207 context.ancestors[data.name] = data.version
210 installManyTop(deps.map(function (dep) {
211 var target = data.dependencies[dep]
212 return dep + "@" + target
213 }).concat(peers.map(function (dep) {
214 var target = data.peerDependencies[dep]
215 return dep + "@" + target
216 })), where, context, function(er, results) {
217 if (er || npm.config.get("production")) return cb(er, results)
218 lifecycle(data, "prepublish", where, function(er) {
219 return cb(er, results)
225 // initial "family" is the name:version of the root, if it's got
226 // a package.json file.
227 var jsonPath = path.resolve(where, "package.json")
228 log.verbose('install', 'initial load of', jsonPath)
229 readJson(jsonPath, log.warn, function (er, data) {
231 && er.code !== "ENOENT"
232 && er.code !== "ENOTDIR") return cb(er)
234 var context = { family: {}
240 if (data && data.name === path.basename(where) &&
241 path.basename(path.dirname(where)) === "node_modules") {
242 context.family[data.name] = context.ancestors[data.name] = data.version
244 var fn = npm.config.get("global") ? installMany : installManyTop
245 fn(args, where, context, cb)
250 function validateInstall (where, cb) {
251 var jsonPath = path.resolve(where, 'package.json')
252 log.verbose('validateInstall', 'loading', jsonPath, 'for validation')
253 readJson(jsonPath, log.warn, function (er, data) {
255 && er.code !== 'ENOENT'
256 && er.code !== 'ENOTDIR') return cb(er)
258 if (data && data.engineStrict) {
260 "Per-package engineStrict (found in this package's package.json) ",
261 "won't be used in npm 3+. Use the config setting `engine-strict` instead."
265 readInstalled(where, { log: log.warn, dev: true }, function (er, data) {
266 if (er) return cb(er)
268 cb(null, findPeerInvalid_(data.dependencies, []))
273 function findPeerInvalid_ (packageMap, fpiList) {
274 if (fpiList.indexOf(packageMap) !== -1)
277 fpiList.push(packageMap)
279 for (var packageName in packageMap) {
280 var pkg = packageMap[packageName]
282 if (pkg.peerInvalid) {
283 var peersDepending = {}
284 for (var peerName in packageMap) {
285 var peer = packageMap[peerName]
286 if (peer.peerDependencies && peer.peerDependencies[packageName]) {
287 peersDepending[peer.name + "@" + peer.version] =
288 peer.peerDependencies[packageName]
291 return { name: pkg.name, peersDepending: peersDepending, version: pkg.version, _id: pkg._id }
294 if (pkg.dependencies) {
295 var invalid = findPeerInvalid_(pkg.dependencies, fpiList)
304 // reads dependencies for the package at "where". There are several cases,
305 // depending on our current state and the package's configuration:
307 // 1. If "context" is specified, then we examine the context to see if there's a
308 // shrinkwrap there. In that case, dependencies are read from the shrinkwrap.
309 // 2. Otherwise, if an npm-shrinkwrap.json file is present, dependencies are
311 // 3. Otherwise, dependencies come from package.json.
313 // Regardless of which case we fall into, "cb" is invoked with a first argument
314 // describing the full package (as though readJson had been used) but with
315 // "dependencies" read as described above. The second argument to "cb" is the
316 // shrinkwrap to use in processing this package's dependencies, which may be
317 // "wrap" (in case 1) or a new shrinkwrap (in case 2).
318 function readDependencies (context, where, opts, cb) {
319 var wrap = context ? context.wrap : null
321 var jsonPath = path.resolve(where, 'package.json')
322 log.verbose('readDependencies', 'loading dependencies from', jsonPath)
323 readJson(jsonPath, log.warn, function (er, data) {
324 if (er && er.code === "ENOENT") er.code = "ENOPACKAGEJSON"
325 if (er) return cb(er)
327 if (opts && opts.dev) {
328 if (!data.dependencies) data.dependencies = {}
329 Object.keys(data.devDependencies || {}).forEach(function (k) {
330 if (data.dependencies[k]) {
331 log.warn("package.json", "Dependency '%s' exists in both dependencies " +
332 "and devDependencies, using '%s@%s' from dependencies",
333 k, k, data.dependencies[k])
335 data.dependencies[k] = data.devDependencies[k]
340 if (!npm.config.get("optional") && data.optionalDependencies) {
341 Object.keys(data.optionalDependencies).forEach(function (d) {
342 delete data.dependencies[d]
346 // User has opted out of shrinkwraps entirely
347 if (npm.config.get("shrinkwrap") === false)
348 return cb(null, data, null)
351 log.verbose("readDependencies: using existing wrap", [where, wrap])
353 Object.keys(data).forEach(function (key) {
357 Object.keys(wrap).forEach(function (key) {
358 log.verbose("from wrap", [key, wrap[key]])
359 rv.dependencies[key] = readWrap(wrap[key])
361 log.verbose("readDependencies returned deps", rv.dependencies)
362 return cb(null, rv, wrap)
365 var wrapfile = path.resolve(where, "npm-shrinkwrap.json")
367 fs.readFile(wrapfile, "utf8", function (er, wrapjson) {
368 if (er) return cb(null, data, null)
370 log.verbose("readDependencies", "npm-shrinkwrap.json is overriding dependencies")
373 newwrap = JSON.parse(wrapjson)
378 log.info("shrinkwrap", "file %j", wrapfile)
380 Object.keys(data).forEach(function (key) {
384 Object.keys(newwrap.dependencies || {}).forEach(function (key) {
385 rv.dependencies[key] = readWrap(newwrap.dependencies[key])
388 // fold in devDependencies if not already present, at top level
389 if (opts && opts.dev) {
390 Object.keys(data.devDependencies || {}).forEach(function (k) {
391 rv.dependencies[k] = rv.dependencies[k] || data.devDependencies[k]
395 log.verbose("readDependencies returned deps", rv.dependencies)
396 return cb(null, rv, newwrap.dependencies)
401 function readWrap (w) {
402 return (w.resolved) ? w.resolved
403 : (w.from && url.parse(w.from).protocol) ? w.from
407 // if the -S|--save option is specified, then write installed packages
408 // as dependencies to a package.json file.
409 function save (where, installed, tree, pretty, hasArguments, cb) {
411 !npm.config.get("save") &&
412 !npm.config.get("save-dev") &&
413 !npm.config.get("save-optional") ||
414 npm.config.get("global")) {
415 return cb(null, installed, tree, pretty)
418 var saveBundle = npm.config.get("save-bundle")
419 var savePrefix = npm.config.get("save-prefix")
421 // each item in the tree is a top-level thing that should be saved
422 // to the package.json file.
423 // The relevant tree shape is { <folder>: {what:<pkg>} }
424 var saveTarget = path.resolve(where, "package.json")
426 asyncMap(Object.keys(tree), function (k, cb) {
427 // if "from" is remote, git, or hosted, then save that instead.
431 , w = [a.name, a.spec]
434 fs.stat(t.from, function (er){
436 w[1] = "file:" + t.from
437 } else if (['hosted', 'git', 'remote'].indexOf(f.type) !== -1) {
443 , function (er, arr) {
444 var things = arr.reduce(function (set, k) {
445 var rangeDescriptor = semver.valid(k[1], true) &&
446 semver.gte(k[1], "0.1.0", true) &&
447 !npm.config.get("save-exact")
449 set[k[0]] = rangeDescriptor + k[1]
454 // don't use readJson, because we don't want to do all the other
455 // tricky npm-specific stuff that's in there.
456 fs.readFile(saveTarget, function (er, data) {
457 // ignore errors here, just don't save it.
459 data = JSON.parse(data.toString("utf8"))
465 return cb(null, installed, tree, pretty)
468 var deps = npm.config.get("save-optional") ? "optionalDependencies"
469 : npm.config.get("save-dev") ? "devDependencies"
473 var bundle = data.bundleDependencies || data.bundledDependencies
474 delete data.bundledDependencies
475 if (!Array.isArray(bundle)) bundle = []
476 data.bundleDependencies = bundle.sort()
479 log.verbose("save", "saving", things)
480 data[deps] = data[deps] || {}
481 Object.keys(things).forEach(function (t) {
482 data[deps][t] = things[t]
484 var i = bundle.indexOf(t)
485 if (i === -1) bundle.push(t)
486 data.bundleDependencies = bundle.sort()
490 data[deps] = sortedObject(data[deps])
492 log.silly("save", "writing", saveTarget)
493 data = JSON.stringify(data, null, 2) + "\n"
494 writeFileAtomic(saveTarget, data, function (er) {
495 cb(er, installed, tree, pretty)
502 // Outputting *all* the installed modules is a bit confusing,
503 // because the length of the path does not make it clear
504 // that the submodules are not immediately require()able.
505 // TODO: Show the complete tree, ls-style, but only if --long is provided
506 function prettify (tree, installed) {
507 function red (set, kv) {
512 if (npm.config.get("json")) {
513 tree = Object.keys(tree).map(function (p) {
514 if (!tree[p]) return null
515 var what = npa(tree[p].what)
517 , version = what.spec
518 , o = { name: name, version: version, from: tree[p].from }
519 o.dependencies = tree[p].children.map(function P (dep) {
520 var what = npa(dep.what)
522 , version = what.spec
523 , o = { version: version, from: dep.from }
524 o.dependencies = dep.children.map(P).reduce(red, {})
530 return JSON.stringify(tree, null, 2)
532 if (npm.config.get("parseable")) return parseable(installed)
534 return Object.keys(tree).map(function (p) {
535 return archy({ label: tree[p].what + " " + p
536 , nodes: (tree[p].children || []).map(function P (c) {
537 if (npm.config.get("long")) {
538 return { label: c.what, nodes: c.children.map(P) }
540 var g = c.children.map(function (g) {
543 if (g) g = " (" + g + ")"
546 }, "", { unicode: npm.config.get("unicode") })
550 function parseable (installed) {
551 var long = npm.config.get("long")
552 , cwd = process.cwd()
553 return installed.map(function (item) {
554 return path.resolve(cwd, item[1]) +
555 ( long ? ":" + item[0] : "" )
559 function treeify (installed) {
560 // each item is [what, where, parent, parentDir]
561 // If no parent, then report it.
562 // otherwise, tack it into the parent's children list.
563 // If the parent isn't a top-level then ignore it.
564 var whatWhere = installed.reduce(function (l, r) {
570 l[where] = { parentDir: parentDir
579 // log.warn("install", whatWhere, "whatWhere")
580 return Object.keys(whatWhere).reduce(function (l, r) {
581 var ww = whatWhere[r]
582 //log.warn("r, ww", [r, ww])
586 var p = whatWhere[ww.parentDir]
587 if (p) p.children.push(ww)
595 // just like installMany, but also add the existing packages in
596 // where/node_modules to the family object.
597 function installManyTop (what, where, context, cb_) {
598 function cb (er, d) {
599 if (context.explicit || er) return cb_(er, d)
600 // since this wasn't an explicit install, let's build the top
601 // folder, so that `npm install` also runs the lifecycle scripts.
602 npm.commands.build([where], false, true, function (er) {
607 if (context.explicit) return next()
609 var jsonPath = path.join(where, 'package.json')
610 log.verbose('installManyTop', 'reading for lifecycle', jsonPath)
611 readJson(jsonPath, log.warn, function (er, data) {
612 if (er) return next(er)
613 lifecycle(data, "preinstall", where, next)
617 if (er) return cb(er)
618 installManyTop_(what, where, context, cb)
622 function installManyTop_ (what, where, context, cb) {
623 var nm = path.resolve(where, "node_modules")
625 fs.readdir(nm, function (er, pkgs) {
626 if (er) return installMany(what, where, context, cb)
628 var scopes = [], unscoped = []
629 pkgs.filter(function (p) {
630 return !p.match(/^[\._-]/)
631 }).forEach(function (p) {
632 // @names deserve deeper investigation
641 maybeScoped(scopes, nm, function (er, scoped) {
642 if (er && er.code !== "ENOENT" && er.code !== "ENOTDIR") return cb(er)
643 // recombine unscoped with @scope/package packages
644 asyncMap(unscoped.concat(scoped).map(function (p) {
645 return path.resolve(nm, p, "package.json")
646 }), function (jsonPath, cb) {
647 log.verbose('installManyTop', 'reading scoped package data from', jsonPath)
648 readJson(jsonPath, log.info, function (er, data) {
649 if (er && er.code !== "ENOENT" && er.code !== "ENOTDIR") return cb(er)
650 if (er) return cb(null, [])
651 cb(null, [[data.name, data.version]])
653 }, function (er, packages) {
654 // if there's nothing in node_modules, then don't freak out.
655 if (er) packages = []
656 // add all the existing packages to the family list.
657 // however, do not add to the ancestors list.
658 packages.forEach(function (p) {
659 context.family[p[0]] = p[1]
661 installMany(what, where, context, cb)
667 function maybeScoped (scopes, where, cb) {
668 // find packages in scopes
669 asyncMap(scopes, function (scope, cb) {
670 fs.readdir(path.resolve(where, scope), function (er, scoped) {
671 if (er) return cb(er)
672 var paths = scoped.map(function (p) {
673 return path.join(scope, p)
680 function installMany (what, where, context, cb) {
681 // readDependencies takes care of figuring out whether the list of
682 // dependencies we'll iterate below comes from an existing shrinkwrap from a
683 // parent level, a new shrinkwrap at this level, or package.json at this
684 // level, as well as which shrinkwrap (if any) our dependencies should use.
685 var opt = { dev: npm.config.get("dev") }
686 readDependencies(context, where, opt, function (er, data, wrap) {
691 // if we're explicitly installing "what" into "where", then the shrinkwrap
692 // for "where" doesn't apply. This would be the case if someone were adding
693 // a new package to a shrinkwrapped package. (data.dependencies will not be
694 // used here except to indicate what packages are already present, so
695 // there's no harm in using that.)
696 if (context.explicit) wrap = null
698 var deps = data.dependencies || {}
699 var devDeps = data.devDependencies || {}
701 // what is a list of things.
704 , targetResolver(where, context, deps, devDeps)
705 , function (er, targets) {
707 if (er) return cb(er)
709 var bundled = data.bundleDependencies || data.bundledDependencies || []
710 // only take the hit for readInstalled if there are probably bundled
711 // dependencies to read
712 if (bundled.length) {
713 readInstalled(where, { dev: true }, andBuildResolvedTree)
715 andBuildResolvedTree()
718 function andBuildResolvedTree (er, current) {
719 if (er) return cb(er)
721 // each target will be a data object corresponding
722 // to a package, folder, or whatever that is in the cache now.
723 var newPrev = Object.create(context.family)
724 , newAnc = Object.create(context.ancestors)
727 newAnc[data.name] = data.version
729 bundled.forEach(function (bundle) {
730 var bundleData = current.dependencies[bundle]
731 if ((!bundleData || !bundleData.version) && current.devDependencies) {
733 'installMany', bundle, 'was bundled with',
734 data.name + '@' + data.version +
735 ", but wasn't found in dependencies. Trying devDependencies"
737 bundleData = current.devDependencies[bundle]
740 if (!bundleData || !bundleData.version) {
742 'installMany', bundle, 'was bundled with',
743 data.name + '@' + data.version +
744 ", but bundled package wasn't found in unpacked tree"
748 'installMany', bundle + '@' + bundleData.version,
749 'was bundled with', data.name + '@' + data.version
751 newPrev[bundle] = bundleData.version
754 targets.forEach(function (t) {
755 newPrev[t.name] = t.version
757 log.silly("install resolved", targets)
758 targets.filter(function (t) { return t }).forEach(function (t) {
759 log.info("install", "%s into %s", t._id, where)
761 asyncMap(targets, function (target, cb) {
762 log.info("installOne", target._id)
763 var wrapData = wrap ? wrap[target.name] : null
764 var newWrap = wrapData && wrapData.dependencies
765 ? wrap[target.name].dependencies || {}
767 var newContext = { family: newPrev
772 installOne(target, where, newContext, cb)
779 function targetResolver (where, context, deps, devDeps) {
780 var alreadyInstalledManually = []
782 , nm = path.resolve(where, "node_modules")
783 , parent = context.parent
784 , wrap = context.wrap
786 if (!context.explicit) readdir(nm)
788 function readdir(name) {
790 fs.readdir(name, function (er, inst) {
791 if (er) return resolveLeft--
793 // don't even mess with non-package looking things
794 inst = inst.filter(function (p) {
795 if (!p.match(/^[@\._-]/)) return true
797 readdir(path.join(name, p))
800 asyncMap(inst, function (pkg, cb) {
801 var jsonPath = path.resolve(name, pkg, 'package.json')
802 log.verbose('targetResolver', 'reading package data from', jsonPath)
803 readJson(jsonPath, log.info, function (er, d) {
804 if (er && er.code !== "ENOENT" && er.code !== "ENOTDIR") return cb(er)
805 // error means it's not a package, most likely.
806 if (er) return cb(null, [])
808 // if it's a bundled dep, then assume that anything there is valid.
809 // otherwise, make sure that it's a semver match with what we want.
810 var bd = parent.bundleDependencies
811 var isBundled = bd && bd.indexOf(d.name) !== -1
812 var expectedVersion = deps[d.name] || (devDeps && devDeps[d.name]) || "*"
813 var currentIsSatisfactory = semver.satisfies(d.version, expectedVersion, true)
814 if (isBundled || currentIsSatisfactory || deps[d.name] === d._resolved) {
815 return cb(null, d.name)
818 // see if the package had been previously linked
819 fs.lstat(path.resolve(nm, pkg), function(err, s) {
820 if (err) return cb(null, [])
821 if (s.isSymbolicLink()) {
822 return cb(null, d.name)
825 // something is there, but it's not satisfactory. Clobber it.
829 }, function (er, inst) {
830 // this is the list of things that are valid and should be ignored.
831 alreadyInstalledManually = alreadyInstalledManually.concat(inst)
838 return function resolver (what, cb) {
839 if (resolveLeft) return setTimeout(function () {
843 // now we know what's been installed here manually,
844 // or tampered with in some way that npm doesn't want to overwrite.
845 if (alreadyInstalledManually.indexOf(npa(what).name) !== -1) {
846 log.verbose("already installed", "skipping %s %s", what, where)
850 // check for a version installed higher in the tree.
851 // If installing from a shrinkwrap, it must match exactly.
852 if (context.family[what]) {
853 log.verbose('install', what, 'is installed as', context.family[what])
854 if (wrap && wrap[what].version === context.family[what]) {
855 log.verbose("shrinkwrap", "use existing", what)
860 // if it's identical to its parent, then it's probably someone
861 // doing `npm install foo` inside of the foo project. Print
862 // a warning, and skip it.
863 if (parent && parent.name === what && !npm.config.get("force")) {
864 log.warn("install", "Refusing to install %s as a dependency of itself"
870 var name = npa(what).name
872 var wrapTarget = readWrap(wrap[name])
873 what = name + "@" + wrapTarget
875 log.verbose("shrinkwrap", "skipping %s (not in shrinkwrap)", what)
877 } else if (deps[what]) {
878 what = what + "@" + deps[what]
881 // This is where we actually fetch the package, if it's not already
883 // If it's a git repo, then we want to install it, even if the parent
884 // already has a matching copy.
885 // If it's not a git repo, and the parent already has that pkg, then
886 // we can skip installing it again.
887 var pkgroot = path.resolve(npm.prefix, (parent && parent._from) || "")
888 cache.add(what, null, pkgroot, false, function (er, data) {
889 if (er && parent && parent.optionalDependencies &&
890 parent.optionalDependencies.hasOwnProperty(npa(what).name)) {
891 log.warn("optional dep failed, continuing", what)
892 log.verbose("optional dep failed, continuing", [what, er])
896 var type = npa(what).type
897 var isGit = type === "git" || type === "hosted"
902 context.family[data.name] === data.version &&
903 !npm.config.get("force") &&
905 log.info("already installed", data.name + "@" + data.version)
910 if (data && !data._from) data._from = what
911 if (er && parent && parent.name) er.parent = parent.name
912 return cb(er, data || [])
917 // we've already decided to install this. if anything's in the way,
918 // then uninstall it first.
919 function installOne (target, where, context, cb) {
920 // the --link flag makes this a "link" command if it's at the
923 var type = npa(target._from).type
924 if (target && target._from) isGit = type === 'git' || type === 'hosted'
926 if (where === npm.prefix && npm.config.get("link")
927 && !npm.config.get("global") && !isGit) {
928 return localLink(target, where, context, cb)
930 installOne_(target, where, context, function (er, installedWhat) {
932 // check if this one is optional to its parent.
933 if (er && context.parent && context.parent.optionalDependencies &&
934 context.parent.optionalDependencies.hasOwnProperty(target.name)) {
935 log.warn("optional dep failed, continuing", target._id)
936 log.verbose("optional dep failed, continuing", [target._id, er])
940 cb(er, installedWhat)
945 function localLink (target, where, context, cb) {
946 log.verbose("localLink", target._id)
947 var jsonPath = path.resolve(npm.globalDir, target.name , 'package.json')
948 var parent = context.parent
950 log.verbose('localLink', 'reading data to link', target.name, 'from', jsonPath)
951 readJson(jsonPath, log.warn, function (er, data) {
952 function thenLink () {
953 npm.commands.link([target.name], function (er, d) {
954 log.silly("localLink", "back from link", [er, d])
955 cb(er, [resultList(target, where, parent && parent._id)])
959 if (er && er.code !== "ENOENT" && er.code !== "ENOTDIR") return cb(er)
960 if (er || data._id === target._id) {
962 install( path.resolve(npm.globalDir, "..")
965 if (er) return cb(er, [])
970 log.verbose("localLink", "install locally (no link)", target._id)
971 installOne_(target, where, context, cb)
976 function resultList (target, where, parentId) {
977 var nm = path.resolve(where, "node_modules")
978 , targetFolder = path.resolve(nm, target.name)
979 , prettyWhere = where
981 if (!npm.config.get("global")) {
982 prettyWhere = path.relative(process.cwd(), where)
985 if (prettyWhere === ".") prettyWhere = null
987 if (!npm.config.get("global")) {
988 // print out the folder relative to where we are right now.
989 targetFolder = path.relative(process.cwd(), targetFolder)
994 , prettyWhere && parentId
995 , parentId && prettyWhere
999 var installed = Object.create(null)
1001 function installOne_ (target, where, context, cb_) {
1002 var nm = path.resolve(where, "node_modules")
1003 , targetFolder = path.resolve(nm, target.name)
1004 , prettyWhere = path.relative(process.cwd(), where)
1005 , parent = context.parent
1007 if (prettyWhere === ".") prettyWhere = null
1009 cb_ = inflight(target.name + ":" + where, cb_)
1011 return log.verbose("installOne", "of", target.name, "to", where, "already in flight; waiting")
1014 log.verbose("installOne", "of", target.name, "to", where, "not in flight; installing")
1017 function cb(er, data) {
1018 unlock(nm, target.name, function () { cb_(er, data) })
1021 lock(nm, target.name, function (er) {
1022 if (er) return cb(er)
1024 if (targetFolder in installed) {
1025 log.error("install", "trying to install", target.version, "to", targetFolder)
1026 log.error("install", "but already installed versions", installed[targetFolder])
1027 installed[targetFolder].push(target.version)
1030 installed[targetFolder] = [target.version]
1033 var force = npm.config.get("force")
1034 , nodeVersion = npm.config.get("node-version")
1035 , strict = npm.config.get("engine-strict")
1036 , c = npmInstallChecks
1039 [ [c.checkEngine, target, npm.version, nodeVersion, force, strict]
1040 , [c.checkPlatform, target, force]
1041 , [c.checkCycle, target, context.ancestors]
1042 , [c.checkGit, targetFolder]
1043 , [write, target, targetFolder, context] ]
1044 , function (er, d) {
1045 if (er) return cb(er)
1047 d.push(resultList(target, where, parent && parent._id))
1054 function write (target, targetFolder, context, cb_) {
1055 var up = npm.config.get("unsafe-perm")
1056 , user = up ? null : npm.config.get("user")
1057 , group = up ? null : npm.config.get("group")
1058 , family = context.family
1060 function cb (er, data) {
1061 // cache.unpack returns the data object, and all we care about
1062 // is the list of installed packages from that last thing.
1063 if (!er) return cb_(er, data)
1065 if (npm.config.get("rollback") === false) return cb_(er)
1066 npm.rollbacks.push(targetFolder)
1072 log.silly("install write", "writing", target.name, target.version, "to", targetFolder)
1074 [ [ cache.unpack, target.name, target.version, targetFolder, null, null, user, group ],
1075 function writePackageJSON (cb) {
1076 var jsonPath = path.resolve(targetFolder, 'package.json')
1077 log.verbose('write', 'writing to', jsonPath)
1078 writeFileAtomic(jsonPath, JSON.stringify(target, null, 2) + '\n', cb)
1080 [ lifecycle, target, "preinstall", targetFolder ],
1081 function collectBundled (cb) {
1082 if (!target.bundleDependencies) return cb()
1084 var bd = path.resolve(targetFolder, "node_modules")
1085 fs.readdir(bd, function (er, b) {
1086 // nothing bundled, maybe
1093 // nest the chain so that we can throw away the results returned
1094 // up until this point, since we really don't care about it.
1096 if (er) return cb(er)
1098 // before continuing to installing dependencies, check for a shrinkwrap.
1099 var opt = { dev: npm.config.get("dev") }
1100 readDependencies(context, targetFolder, opt, function (er, data, wrap) {
1101 if (er) return cb(er);
1102 var deps = prepareForInstallMany(data, "dependencies", bundled, wrap,
1104 var depsTargetFolder = targetFolder
1105 var depsContext = { family: family
1106 , ancestors: context.ancestors
1112 [ [ installManyAndBuild, deps, depsTargetFolder, depsContext ] ]
1114 // FIXME: This is an accident waiting to happen!
1116 // 1. If multiple children at the same level of the tree share a
1117 // peerDependency that's not in the parent's dependencies, because
1118 // the peerDeps don't get added to the family, they will keep
1119 // getting reinstalled (worked around by inflighting installOne).
1120 // 2. The installer can't safely build at the parent level because
1121 // that's already being done by the parent's installAndBuild. This
1122 // runs the risk of the peerDependency never getting built.
1124 // The fix: Don't install peerDependencies; require them to be
1125 // included as explicit dependencies / devDependencies, and warn
1126 // or error when they're missing. See #5080 for more arguments in
1127 // favor of killing implicit peerDependency installs with fire.
1128 var peerDeps = prepareForInstallMany(data, "peerDependencies", bundled,
1130 peerDeps.forEach(function (pd) {
1132 "The peer dependency "+pd+" included from "+data.name+" will no",
1133 "longer be automatically installed to fulfill the peerDependency ",
1134 "in npm 3+. Your application will need to depend on it explicitly."
1135 ], pd+","+data.name)
1138 // Package scopes cause an addditional tree level which needs to be
1139 // considered when resolving a peerDependency's target folder.
1141 if (npa(target.name).scope) {
1142 pdTargetFolder = path.resolve(targetFolder, '../../..')
1144 pdTargetFolder = path.resolve(targetFolder, '../..')
1147 var pdContext = context
1148 if (peerDeps.length > 0) {
1150 [ installMany, peerDeps, pdTargetFolder, pdContext ]
1159 function installManyAndBuild (deps, targetFolder, context, cb) {
1160 installMany(deps, targetFolder, context, function (er, d) {
1161 log.verbose("about to build", targetFolder)
1162 if (er) return cb(er)
1163 npm.commands.build( [targetFolder]
1164 , npm.config.get("global")
1166 , function (er) { return cb(er, d) })
1170 function prepareForInstallMany (packageData, depsKey, bundled, wrap, family) {
1171 var deps = Object.keys(packageData[depsKey] || {})
1173 // don't install bundleDependencies, unless they're missing.
1174 if (packageData.bundleDependencies) {
1175 deps = deps.filter(function (d) {
1176 return packageData.bundleDependencies.indexOf(d) === -1 ||
1177 bundled.indexOf(d) === -1
1181 return deps.filter(function (d) {
1182 // prefer to not install things that are satisfied by
1183 // something in the "family" list, unless we're installing
1184 // from a shrinkwrap.
1185 if (depsKey !== "peerDependencies" && wrap) return true
1186 if (semver.validRange(family[d], true)) {
1187 return !semver.satisfies(family[d], packageData[depsKey][d], true)
1190 }).map(function (d) {
1191 var v = packageData[depsKey][d]
1193 log.silly("prepareForInstallMany", "adding", t, "from", packageData.name, depsKey)