diff options
author | Rebecca Turner <me@re-becca.org> | 2015-08-14 09:49:54 +0300 |
---|---|---|
committer | Rebecca Turner <me@re-becca.org> | 2015-08-21 22:30:51 +0300 |
commit | d395a6b8767853eede6ad4502266ac99504f51a8 (patch) | |
tree | fb8342416ab11abb720750fcada1b57104da4d26 /lib | |
parent | d119ea67804e4bd2ea00025bd1d779cf7ec8ca18 (diff) |
diff-trees: Make install order more consistent for directly dependencies
The install order is determined by:
1) The location of the thing to be installed relative to the root module.
2) Dependency order, such that a -> b -> c will install modules as: c, b, a
1 is deterministic, regardless of what's being installed.
But 2 can change the order of things higher in the dep tree. Eg, b, or a
might get sorted earlier if c requires them. This mostly doesn't matter,
but it does mean that if you have two modules with conflicting bins, they
_can_ get installed in different orders. This changes sorts all of the top
level modules to be LAST, in location order (1), and then sorts all the rest
per (2). This ensures that top level modules have a deterministic install
order. (Non top level modules can't have bin conflicts as that's treated
the same as a version conflict and the conflicting module would be hoisted.)
PR-URL: https://github.com/npm/npm/pull/9274
Fixes: #8995
Diffstat (limited to 'lib')
-rw-r--r-- | lib/install/diff-trees.js | 32 |
1 files changed, 26 insertions, 6 deletions
diff --git a/lib/install/diff-trees.js b/lib/install/diff-trees.js index e52d950bf..768bcde55 100644 --- a/lib/install/diff-trees.js +++ b/lib/install/diff-trees.js @@ -59,6 +59,12 @@ function requiredByAllLinked (node) { return node.requiredBy.filter(isLink).length === node.requiredBy.length } +function isNotReqByTop (req) { + return req !== '/' && // '/' is the top level itself + req !== '#USER' && // #USER + req !== '#EXTRANEOUS' +} + var sortActions = module.exports.sortActions = function (differences) { var actions = {} differences.forEach(function (action) { @@ -68,22 +74,36 @@ var sortActions = module.exports.sortActions = function (differences) { var sorted = [] var added = {} - Object.keys(actions).sort(sortByLocation).forEach(function (location) { + + var sortedlocs = Object.keys(actions).sort(sortByLocation) + + // Do top level deps first, this stops the sorting by required order from + // unsorting these deps. + var toplocs = sortedlocs.filter(function (location) { + var mod = actions[location][1] + if (!mod.package._requiredBy) return true + // If the module is required by ANY non-top level package + // then we don't want to include this. + return !mod.package._requiredBy.some(isNotReqByTop) + }) + + toplocs.concat(sortedlocs).forEach(function (location) { sortByDeps(actions[location]) }) function sortByLocation (aa, bb) { - return aa.length - bb.length || bb.localeCompare(aa) + return bb.localeCompare(aa) } function sortByDeps (action) { - var cmd = action[1] - if (added[cmd.package._location]) return - added[cmd.package._location] = action - cmd.package._requiredBy.forEach(function (location) { + var mod = action[1] + if (added[mod.package._location]) return + added[mod.package._location] = action + mod.package._requiredBy.sort().forEach(function (location) { if (actions[location]) sortByDeps(actions[location]) }) sorted.unshift(action) } + return sorted } |