]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.maps.server/node/node-v4.8.0-win-x64/node_modules/npm/lib/install.js
Adding integrated tile server
[simantics/district.git] / org.simantics.maps.server / node / node-v4.8.0-win-x64 / node_modules / npm / lib / install.js
1 // npm install <pkg> <pkg> <pkg>
2 //
3 // See doc/cli/npm-install.md for more description
4 //
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.
13
14 module.exports = install
15
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."
30
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
37     return cb(null, [])
38   }
39
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
44     // complete.
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 = "/"
49
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
54       }
55       fs.readdir(fullPath, function (err, contents) {
56         if (err) return cb(null, { isPackage: false })
57
58         cb(
59           null,
60           {
61             fullPath: fullPath,
62             isPackage: contents.indexOf("package.json") !== -1
63           }
64         )
65       })
66     }
67
68     return fs.readdir(partialPath, function (err, siblings) {
69       if (err) return cb(null, []) // invalid dir: no matching
70
71       asyncMap(siblings, annotatePackageDirMatch, function (err, matches) {
72         if (err) return cb(err)
73
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, [])
77
78         // Success - only one match and it is a package dir
79         return cb(null, [cleaned[0].fullPath])
80       })
81     })
82   }
83
84   // FIXME: there used to be registry completion here, but it stopped making
85   // sense somewhere around 50,000 packages on the registry
86   cb()
87 }
88
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")
110   , lock = locker.lock
111   , unlock = locker.unlock
112   , warnStrict = require("./utils/warn-deprecated.js")("engineStrict")
113   , warnPeers = require("./utils/warn-deprecated.js")("peerDependencies")
114
115 function install (args, cb_) {
116   var hasArguments = !!args.length
117
118   function cb (er, installed) {
119     if (er) return cb_(er)
120
121     validateInstall(where, function (er, problem) {
122       if (er) return cb_(er)
123
124       if (problem) {
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)
132       }
133
134       var tree = treeify(installed || [])
135         , pretty = prettify(tree, installed).trim()
136
137       if (pretty) console.log(pretty)
138       save(where, installed, tree, pretty, hasArguments, cb_)
139     })
140   }
141
142   // the /path/to/node_modules/..
143   var where = path.resolve(npm.dir, "..")
144
145   // internal api: install(where, what, cb)
146   if (arguments.length === 3) {
147     where = args
148     args = [].concat(cb_) // pass in [] to do default dep-install
149     cb_ = arguments[2]
150     log.verbose("install", "where, what", [where, args])
151   }
152
153   if (!npm.config.get("global")) {
154     args = args.filter(function (a) {
155       return path.resolve(a) !== where
156     })
157   }
158
159   mkdir(where, function (er) {
160     if (er) return cb(er)
161     // install dependencies locally by default,
162     // or install current folder globally
163     if (!args.length) {
164       var opt = { dev: npm.config.get("dev") || !npm.config.get("production") }
165
166       if (npm.config.get("global")) args = ["."]
167       else return readDependencies(null, where, opt, function (er, data) {
168         if (er) {
169           log.error("install", "Couldn't read dependencies")
170           return cb(er)
171         }
172         var deps = Object.keys(data.dependencies || {})
173         log.verbose("install", "where, deps", [where, deps])
174
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.
178         var peers = []
179         Object.keys(data.peerDependencies || {}).forEach(function (dep) {
180           if (!data.dependencies[dep]) {
181             log.verbose(
182               "install",
183               "peerDependency", dep, "wasn't going to be installed; adding"
184             )
185             warnPeers([
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)
190             peers.push(dep)
191           }
192         })
193         log.verbose("install", "where, peers", [where, peers])
194
195         var context = { family: {}
196                       , ancestors: {}
197                       , explicit: false
198                       , parent: data
199                       , root: true
200                       , wrap: null }
201
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
208         }
209
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)
220           })
221         })
222       })
223     }
224
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) {
230       if (er
231           && er.code !== "ENOENT"
232           && er.code !== "ENOTDIR") return cb(er)
233       if (er) data = null
234       var context = { family: {}
235                     , ancestors: {}
236                     , explicit: true
237                     , parent: data
238                     , root: true
239                     , wrap: null }
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
243       }
244       var fn = npm.config.get("global") ? installMany : installManyTop
245       fn(args, where, context, cb)
246     })
247   })
248 }
249
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) {
254     if (er
255         && er.code !== 'ENOENT'
256         && er.code !== 'ENOTDIR') return cb(er)
257
258     if (data && data.engineStrict) {
259       warnStrict([
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."
262       ], data.name)
263     }
264
265     readInstalled(where, { log: log.warn, dev: true }, function (er, data) {
266       if (er) return cb(er)
267
268       cb(null, findPeerInvalid_(data.dependencies, []))
269     })
270   })
271 }
272
273 function findPeerInvalid_ (packageMap, fpiList) {
274   if (fpiList.indexOf(packageMap) !== -1)
275     return undefined
276
277   fpiList.push(packageMap)
278
279   for (var packageName in packageMap) {
280     var pkg = packageMap[packageName]
281
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]
289         }
290       }
291       return { name: pkg.name, peersDepending: peersDepending, version: pkg.version, _id: pkg._id }
292     }
293
294     if (pkg.dependencies) {
295       var invalid = findPeerInvalid_(pkg.dependencies, fpiList)
296       if (invalid)
297         return invalid
298     }
299   }
300
301   return null
302 }
303
304 // reads dependencies for the package at "where". There are several cases,
305 // depending on our current state and the package's configuration:
306 //
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
310 //    read from there.
311 // 3. Otherwise, dependencies come from package.json.
312 //
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
320
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)
326
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])
334         } else {
335           data.dependencies[k] = data.devDependencies[k]
336         }
337       })
338     }
339
340     if (!npm.config.get("optional") && data.optionalDependencies) {
341       Object.keys(data.optionalDependencies).forEach(function (d) {
342         delete data.dependencies[d]
343       })
344     }
345
346     // User has opted out of shrinkwraps entirely
347     if (npm.config.get("shrinkwrap") === false)
348       return cb(null, data, null)
349
350     if (wrap) {
351       log.verbose("readDependencies: using existing wrap", [where, wrap])
352       var rv = {}
353       Object.keys(data).forEach(function (key) {
354         rv[key] = data[key]
355       })
356       rv.dependencies = {}
357       Object.keys(wrap).forEach(function (key) {
358         log.verbose("from wrap", [key, wrap[key]])
359         rv.dependencies[key] = readWrap(wrap[key])
360       })
361       log.verbose("readDependencies returned deps", rv.dependencies)
362       return cb(null, rv, wrap)
363     }
364
365     var wrapfile = path.resolve(where, "npm-shrinkwrap.json")
366
367     fs.readFile(wrapfile, "utf8", function (er, wrapjson) {
368       if (er) return cb(null, data, null)
369
370       log.verbose("readDependencies", "npm-shrinkwrap.json is overriding dependencies")
371       var newwrap
372       try {
373         newwrap = JSON.parse(wrapjson)
374       } catch (ex) {
375         return cb(ex)
376       }
377
378       log.info("shrinkwrap", "file %j", wrapfile)
379       var rv = {}
380       Object.keys(data).forEach(function (key) {
381         rv[key] = data[key]
382       })
383       rv.dependencies = {}
384       Object.keys(newwrap.dependencies || {}).forEach(function (key) {
385         rv.dependencies[key] = readWrap(newwrap.dependencies[key])
386       })
387
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]
392         })
393       }
394
395       log.verbose("readDependencies returned deps", rv.dependencies)
396       return cb(null, rv, newwrap.dependencies)
397     })
398   })
399 }
400
401 function readWrap (w) {
402   return (w.resolved) ? w.resolved
403        : (w.from && url.parse(w.from).protocol) ? w.from
404        : w.version
405 }
406
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) {
410   if (!hasArguments ||
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)
416   }
417
418   var saveBundle = npm.config.get("save-bundle")
419   var savePrefix = npm.config.get("save-prefix")
420
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")
425
426   asyncMap(Object.keys(tree), function (k, cb) {
427     // if "from" is remote, git, or hosted, then save that instead.
428     var t = tree[k]
429       , f = npa(t.from)
430       , a = npa(t.what)
431       , w = [a.name, a.spec]
432
433
434     fs.stat(t.from, function (er){
435       if (!er) {
436         w[1] = "file:" + t.from
437       } else if (['hosted', 'git', 'remote'].indexOf(f.type) !== -1) {
438         w[1] = t.from
439       }
440       cb(null, [w])
441     })
442   }
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")
448                             ? savePrefix : ""
449         set[k[0]] = rangeDescriptor + k[1]
450         return set
451       }, {})
452
453
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.
458       try {
459         data = JSON.parse(data.toString("utf8"))
460       } catch (ex) {
461         er = ex
462       }
463
464       if (er) {
465         return cb(null, installed, tree, pretty)
466       }
467
468       var deps = npm.config.get("save-optional") ? "optionalDependencies"
469                : npm.config.get("save-dev") ? "devDependencies"
470                : "dependencies"
471
472       if (saveBundle) {
473         var bundle = data.bundleDependencies || data.bundledDependencies
474         delete data.bundledDependencies
475         if (!Array.isArray(bundle)) bundle = []
476         data.bundleDependencies = bundle.sort()
477       }
478
479       log.verbose("save", "saving", things)
480       data[deps] = data[deps] || {}
481       Object.keys(things).forEach(function (t) {
482         data[deps][t] = things[t]
483         if (saveBundle) {
484           var i = bundle.indexOf(t)
485           if (i === -1) bundle.push(t)
486           data.bundleDependencies = bundle.sort()
487         }
488       })
489
490       data[deps] = sortedObject(data[deps])
491
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)
496       })
497     })
498   })
499 }
500
501
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) {
508     set[kv[0]] = kv[1]
509     return set
510   }
511
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)
516         , name = what.name
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)
521            , name = what.name
522            , version = what.spec
523            , o = { version: version, from: dep.from }
524          o.dependencies = dep.children.map(P).reduce(red, {})
525          return [name, o]
526        }).reduce(red, {})
527        return o
528     })
529
530     return JSON.stringify(tree, null, 2)
531   }
532   if (npm.config.get("parseable")) return parseable(installed)
533
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) }
539                      }
540                      var g = c.children.map(function (g) {
541                        return g.what
542                      }).join(", ")
543                      if (g) g = " (" + g + ")"
544                      return c.what + g
545                    })
546                  }, "", { unicode: npm.config.get("unicode") })
547   }).join("\n")
548 }
549
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] : "" )
556   }).join("\n")
557 }
558
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) {
565     var parentDir = r[3]
566       , parent = r[2]
567       , where = r[1]
568       , what = r[0]
569       , from = r[4]
570     l[where] = { parentDir: parentDir
571                , parent: parent
572                , children: []
573                , where: where
574                , what: what
575                , from: from }
576     return l
577   }, {})
578
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])
583     if (!ww.parent) {
584       l[r] = ww
585     } else {
586       var p = whatWhere[ww.parentDir]
587       if (p) p.children.push(ww)
588       else l[r] = ww
589     }
590     return l
591   }, {})
592 }
593
594
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) {
603       return cb_(er, d)
604     })
605   }
606
607   if (context.explicit) return next()
608
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)
614   })
615
616   function next (er) {
617     if (er) return cb(er)
618     installManyTop_(what, where, context, cb)
619   }
620 }
621
622 function installManyTop_ (what, where, context, cb) {
623   var nm = path.resolve(where, "node_modules")
624
625   fs.readdir(nm, function (er, pkgs) {
626     if (er) return installMany(what, where, context, cb)
627
628     var scopes = [], unscoped = []
629     pkgs.filter(function (p) {
630       return !p.match(/^[\._-]/)
631     }).forEach(function (p) {
632       // @names deserve deeper investigation
633       if (p[0] === "@") {
634         scopes.push(p)
635       }
636       else {
637         unscoped.push(p)
638       }
639     })
640
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]])
652         })
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]
660         })
661         installMany(what, where, context, cb)
662       })
663     })
664   })
665 }
666
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)
674       })
675       cb(null, paths)
676     })
677   }, cb)
678 }
679
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) {
687     if (er) data = {}
688
689     var parent = data
690
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
697
698     var deps = data.dependencies || {}
699     var devDeps = data.devDependencies || {}
700
701     // what is a list of things.
702     // resolve each one.
703     asyncMap( what
704             , targetResolver(where, context, deps, devDeps)
705             , function (er, targets) {
706
707       if (er) return cb(er)
708
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)
714       } else {
715         andBuildResolvedTree()
716       }
717
718       function andBuildResolvedTree (er, current) {
719         if (er) return cb(er)
720
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)
725
726         if (!context.root) {
727           newAnc[data.name] = data.version
728         }
729         bundled.forEach(function (bundle) {
730           var bundleData = current.dependencies[bundle]
731           if ((!bundleData || !bundleData.version) && current.devDependencies) {
732             log.verbose(
733               'installMany', bundle, 'was bundled with',
734               data.name + '@' + data.version +
735                 ", but wasn't found in dependencies. Trying devDependencies"
736             )
737             bundleData = current.devDependencies[bundle]
738           }
739
740           if (!bundleData || !bundleData.version) {
741             log.warn(
742               'installMany', bundle, 'was bundled with',
743               data.name + '@' + data.version +
744                 ", but bundled package wasn't found in unpacked tree"
745             )
746           } else {
747             log.verbose(
748               'installMany', bundle + '@' + bundleData.version,
749               'was bundled with', data.name + '@' + data.version
750             )
751             newPrev[bundle] = bundleData.version
752           }
753         })
754         targets.forEach(function (t) {
755           newPrev[t.name] = t.version
756         })
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)
760         })
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 || {}
766                       : null
767           var newContext = { family: newPrev
768                            , ancestors: newAnc
769                            , parent: parent
770                            , explicit: false
771                            , wrap: newWrap }
772           installOne(target, where, newContext, cb)
773         }, cb)
774       }
775     })
776   })
777 }
778
779 function targetResolver (where, context, deps, devDeps) {
780   var alreadyInstalledManually = []
781     , resolveLeft = 0
782     , nm = path.resolve(where, "node_modules")
783     , parent = context.parent
784     , wrap = context.wrap
785
786   if (!context.explicit) readdir(nm)
787
788   function readdir(name) {
789     resolveLeft++
790     fs.readdir(name, function (er, inst) {
791       if (er) return resolveLeft--
792
793       // don't even mess with non-package looking things
794       inst = inst.filter(function (p) {
795         if (!p.match(/^[@\._-]/)) return true
796         // scoped packages
797         readdir(path.join(name, p))
798       })
799
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, [])
807
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)
816           }
817
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)
823             }
824
825             // something is there, but it's not satisfactory.  Clobber it.
826             return cb(null, [])
827           })
828         })
829       }, function (er, inst) {
830         // this is the list of things that are valid and should be ignored.
831         alreadyInstalledManually = alreadyInstalledManually.concat(inst)
832         resolveLeft--
833       })
834     })
835   }
836
837   var to = 0
838   return function resolver (what, cb) {
839     if (resolveLeft) return setTimeout(function () {
840       resolver(what, cb)
841     }, to++)
842
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)
847       return cb(null, [])
848     }
849
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)
856         return cb(null, [])
857       }
858     }
859
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"
865               , what)
866       return cb(null, [])
867     }
868
869     if (wrap) {
870       var name = npa(what).name
871       if (wrap[name]) {
872         var wrapTarget = readWrap(wrap[name])
873         what = name + "@" + wrapTarget
874       } else {
875         log.verbose("shrinkwrap", "skipping %s (not in shrinkwrap)", what)
876       }
877     } else if (deps[what]) {
878       what = what + "@" + deps[what]
879     }
880
881     // This is where we actually fetch the package, if it's not already
882     // in the cache.
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])
893         return cb(null, [])
894       }
895
896       var type = npa(what).type
897       var isGit = type === "git" || type === "hosted"
898
899       if (!er &&
900           data &&
901           !context.explicit &&
902           context.family[data.name] === data.version &&
903           !npm.config.get("force") &&
904           !isGit) {
905         log.info("already installed", data.name + "@" + data.version)
906         return cb(null, [])
907       }
908
909
910       if (data && !data._from) data._from = what
911       if (er && parent && parent.name) er.parent = parent.name
912       return cb(er, data || [])
913     })
914   }
915 }
916
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
921   // the top level.
922   var isGit = false
923   var type = npa(target._from).type
924   if (target && target._from) isGit = type === 'git' || type === 'hosted'
925
926   if (where === npm.prefix && npm.config.get("link")
927       && !npm.config.get("global") && !isGit) {
928     return localLink(target, where, context, cb)
929   }
930   installOne_(target, where, context, function (er, installedWhat) {
931
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])
937       er = null
938     }
939
940     cb(er, installedWhat)
941   })
942
943 }
944
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
949
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)])
956       })
957     }
958
959     if (er && er.code !== "ENOENT" && er.code !== "ENOTDIR") return cb(er)
960     if (er || data._id === target._id) {
961       if (er) {
962         install( path.resolve(npm.globalDir, "..")
963                , target._id
964                , function (er) {
965           if (er) return cb(er, [])
966           thenLink()
967         })
968       } else thenLink()
969     } else {
970       log.verbose("localLink", "install locally (no link)", target._id)
971       installOne_(target, where, context, cb)
972     }
973   })
974 }
975
976 function resultList (target, where, parentId) {
977   var nm = path.resolve(where, "node_modules")
978     , targetFolder = path.resolve(nm, target.name)
979     , prettyWhere = where
980
981   if (!npm.config.get("global")) {
982     prettyWhere = path.relative(process.cwd(), where)
983   }
984
985   if (prettyWhere === ".") prettyWhere = null
986
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)
990   }
991
992   return [ target._id
993          , targetFolder
994          , prettyWhere && parentId
995          , parentId && prettyWhere
996          , target._from ]
997 }
998
999 var installed = Object.create(null)
1000
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
1006
1007   if (prettyWhere === ".") prettyWhere = null
1008
1009   cb_ = inflight(target.name + ":" + where, cb_)
1010   if (!cb_) {
1011     return log.verbose("installOne", "of", target.name, "to", where, "already in flight; waiting")
1012   }
1013   else {
1014     log.verbose("installOne", "of", target.name, "to", where, "not in flight; installing")
1015   }
1016
1017   function cb(er, data) {
1018     unlock(nm, target.name, function () { cb_(er, data) })
1019   }
1020
1021   lock(nm, target.name, function (er) {
1022     if (er) return cb(er)
1023
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)
1028     }
1029     else {
1030       installed[targetFolder] = [target.version]
1031     }
1032
1033     var force = npm.config.get("force")
1034       , nodeVersion = npm.config.get("node-version")
1035       , strict = npm.config.get("engine-strict")
1036       , c = npmInstallChecks
1037
1038     chain(
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)
1046
1047           d.push(resultList(target, where, parent && parent._id))
1048           cb(er, d)
1049         }
1050       )
1051   })
1052 }
1053
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
1059
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)
1064
1065     if (npm.config.get("rollback") === false) return cb_(er)
1066     npm.rollbacks.push(targetFolder)
1067     cb_(er, data)
1068   }
1069
1070   var bundled = []
1071
1072   log.silly("install write", "writing", target.name, target.version, "to", targetFolder)
1073   chain(
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)
1079       },
1080       [ lifecycle, target, "preinstall", targetFolder ],
1081       function collectBundled (cb) {
1082         if (!target.bundleDependencies) return cb()
1083
1084         var bd = path.resolve(targetFolder, "node_modules")
1085         fs.readdir(bd, function (er, b) {
1086           // nothing bundled, maybe
1087           if (er) return cb()
1088           bundled = b || []
1089           cb()
1090         })
1091       } ]
1092
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.
1095     , function X (er) {
1096       if (er) return cb(er)
1097
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,
1103             family)
1104         var depsTargetFolder = targetFolder
1105         var depsContext = { family: family
1106                           , ancestors: context.ancestors
1107                           , parent: target
1108                           , explicit: false
1109                           , wrap: wrap }
1110
1111         var actions =
1112           [ [ installManyAndBuild, deps, depsTargetFolder, depsContext ] ]
1113
1114         // FIXME: This is an accident waiting to happen!
1115         //
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.
1123         //
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,
1129             wrap, family)
1130         peerDeps.forEach(function (pd) {
1131             warnPeers([
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)
1136         })
1137
1138         // Package scopes cause an addditional tree level which needs to be
1139         // considered when resolving a peerDependency's target folder.
1140         var pdTargetFolder
1141         if (npa(target.name).scope) {
1142           pdTargetFolder = path.resolve(targetFolder, '../../..')
1143         } else {
1144           pdTargetFolder = path.resolve(targetFolder, '../..')
1145         }
1146
1147         var pdContext = context
1148         if (peerDeps.length > 0) {
1149           actions.push(
1150             [ installMany, peerDeps, pdTargetFolder, pdContext ]
1151           )
1152         }
1153
1154         chain(actions, cb)
1155       })
1156     })
1157 }
1158
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")
1165                       , true
1166                       , function (er) { return cb(er, d) })
1167   })
1168 }
1169
1170 function prepareForInstallMany (packageData, depsKey, bundled, wrap, family) {
1171   var deps = Object.keys(packageData[depsKey] || {})
1172
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
1178     })
1179   }
1180
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)
1188     }
1189     return true
1190   }).map(function (d) {
1191     var v = packageData[depsKey][d]
1192     var t = d + "@" + v
1193     log.silly("prepareForInstallMany", "adding", t, "from", packageData.name, depsKey)
1194     return t
1195   })
1196 }