summaryrefslogtreecommitdiff
path: root/deps/npm/lib/install
diff options
context:
space:
mode:
Diffstat (limited to 'deps/npm/lib/install')
-rw-r--r--deps/npm/lib/install/action/extract-worker.js4
-rw-r--r--deps/npm/lib/install/action/extract.js32
-rw-r--r--deps/npm/lib/install/actions.js2
-rw-r--r--deps/npm/lib/install/copy-tree.js17
-rw-r--r--deps/npm/lib/install/deps.js75
-rw-r--r--deps/npm/lib/install/diff-trees.js3
-rw-r--r--deps/npm/lib/install/has-modern-meta.js19
-rw-r--r--deps/npm/lib/install/inflate-shrinkwrap.js29
-rw-r--r--deps/npm/lib/install/read-shrinkwrap.js66
-rw-r--r--deps/npm/lib/install/save.js7
10 files changed, 175 insertions, 79 deletions
diff --git a/deps/npm/lib/install/action/extract-worker.js b/deps/npm/lib/install/action/extract-worker.js
index 24508c7804..2b082b4a57 100644
--- a/deps/npm/lib/install/action/extract-worker.js
+++ b/deps/npm/lib/install/action/extract-worker.js
@@ -10,9 +10,9 @@ module.exports = (args, cb) => {
const spec = parsed[0]
const extractTo = parsed[1]
const opts = parsed[2]
- if (!opts.log && opts.loglevel) {
+ if (!opts.log) {
opts.log = npmlog
- opts.log.level = opts.loglevel
}
+ opts.log.level = opts.loglevel || opts.log.level
BB.resolve(extract(spec, extractTo, opts)).nodeify(cb)
}
diff --git a/deps/npm/lib/install/action/extract.js b/deps/npm/lib/install/action/extract.js
index 6b827f36ea..e8d7a6c4f6 100644
--- a/deps/npm/lib/install/action/extract.js
+++ b/deps/npm/lib/install/action/extract.js
@@ -4,9 +4,7 @@ const BB = require('bluebird')
const stat = BB.promisify(require('graceful-fs').stat)
const gentlyRm = BB.promisify(require('../../utils/gently-rm.js'))
-const log = require('npmlog')
const mkdirp = BB.promisify(require('mkdirp'))
-const moduleName = require('../../utils/module-name.js')
const moduleStagingPath = require('../module-staging-path.js')
const move = require('../../utils/move.js')
const npa = require('npm-package-arg')
@@ -59,12 +57,11 @@ function extract (staging, pkg, log) {
pacoteOpts = require('../../config/pacote')
}
const opts = pacoteOpts({
- integrity: pkg.package._integrity
+ integrity: pkg.package._integrity,
+ resolved: pkg.package._resolved
})
const args = [
- pkg.package._resolved
- ? npa.resolve(pkg.package.name, pkg.package._resolved)
- : pkg.package._requested,
+ pkg.package._requested,
extractTo,
opts
]
@@ -112,18 +109,6 @@ function readBundled (pkg, staging, extractTo) {
}, {concurrency: 10})
}
-function getTree (pkg) {
- while (pkg.parent) pkg = pkg.parent
- return pkg
-}
-
-function warn (pkg, code, msg) {
- const tree = getTree(pkg)
- const err = new Error(msg)
- err.code = code
- tree.warnings.push(err)
-}
-
function stageBundledModule (bundler, child, staging, parentPath) {
const stageFrom = path.join(parentPath, 'node_modules', child.package.name)
const stageTo = moduleStagingPath(staging, child)
@@ -146,15 +131,6 @@ function finishModule (bundler, child, stageTo, stageFrom) {
return move(stageFrom, stageTo)
})
} else {
- return stat(stageFrom).then(() => {
- const bundlerId = packageId(bundler)
- if (!getTree(bundler).warnings.some((w) => {
- return w.code === 'EBUNDLEOVERRIDE'
- })) {
- warn(bundler, 'EBUNDLEOVERRIDE', `${bundlerId} had bundled packages that do not match the required version(s). They have been replaced with non-bundled versions.`)
- }
- log.verbose('bundle', `EBUNDLEOVERRIDE: Replacing ${bundlerId}'s bundled version of ${moduleName(child)} with ${packageId(child)}.`)
- return gentlyRm(stageFrom)
- }, () => {})
+ return stat(stageFrom).then(() => gentlyRm(stageFrom), () => {})
}
}
diff --git a/deps/npm/lib/install/actions.js b/deps/npm/lib/install/actions.js
index 9608a943a5..a34d03ffe2 100644
--- a/deps/npm/lib/install/actions.js
+++ b/deps/npm/lib/install/actions.js
@@ -118,7 +118,7 @@ function doParallel (type, staging, actionsToRun, log, next) {
}
return acc
}, [])
- log.silly('doParallel', type + ' ' + actionsToRun.length)
+ log.silly('doParallel', type + ' ' + acts.length)
time(log)
if (!acts.length) { return next() }
return withInit(actions[type], () => {
diff --git a/deps/npm/lib/install/copy-tree.js b/deps/npm/lib/install/copy-tree.js
index a5b558cf59..2bf7064f33 100644
--- a/deps/npm/lib/install/copy-tree.js
+++ b/deps/npm/lib/install/copy-tree.js
@@ -1,27 +1,26 @@
'use strict'
var createNode = require('./node.js').create
-module.exports = function (tree, filter) {
- return copyTree(tree, {}, filter)
+module.exports = function (tree) {
+ return copyTree(tree, {})
}
-function copyTree (tree, cache, filter) {
- if (filter && !filter(tree)) { return null }
+function copyTree (tree, cache) {
if (cache[tree.path]) { return cache[tree.path] }
var newTree = cache[tree.path] = createNode(Object.assign({}, tree))
- copyModuleList(newTree, 'children', cache, filter)
+ copyModuleList(newTree, 'children', cache)
newTree.children.forEach(function (child) {
child.parent = newTree
})
- copyModuleList(newTree, 'requires', cache, filter)
- copyModuleList(newTree, 'requiredBy', cache, filter)
+ copyModuleList(newTree, 'requires', cache)
+ copyModuleList(newTree, 'requiredBy', cache)
return newTree
}
-function copyModuleList (tree, key, cache, filter) {
+function copyModuleList (tree, key, cache) {
var newList = []
if (tree[key]) {
tree[key].forEach(function (child) {
- const copy = copyTree(child, cache, filter)
+ const copy = copyTree(child, cache)
if (copy) {
newList.push(copy)
}
diff --git a/deps/npm/lib/install/deps.js b/deps/npm/lib/install/deps.js
index 93c4adffd7..54cc5258fa 100644
--- a/deps/npm/lib/install/deps.js
+++ b/deps/npm/lib/install/deps.js
@@ -33,6 +33,7 @@ var getSaveType = require('./save.js').getSaveType
var unixFormatPath = require('../utils/unix-format-path.js')
var isExtraneous = require('./is-extraneous.js')
var isRegistry = require('../utils/is-registry.js')
+var hasModernMeta = require('./has-modern-meta.js')
// The export functions in this module mutate a dependency tree, adding
// items to them.
@@ -111,7 +112,7 @@ function computeMetadata (tree, seen) {
const reqs = tree.swRequires || {}
for (let name of Object.keys(deps)) {
if (findChild(name, deps[name])) continue
- if (findChild(name, reqs[name])) continue
+ if (name in reqs && findChild(name, reqs[name])) continue
tree.missingDeps[name] = deps[name]
}
if (tree.isTop) {
@@ -332,9 +333,21 @@ exports.removeDeps = function (args, tree, saveToDependencies, next) {
parent.requires = parent.requires.filter((child) => child !== pkgToRemove)
}
pkgToRemove.requiredBy = pkgToRemove.requiredBy.filter((parent) => parent !== tree)
+ flagAsRemoving(pkgToRemove)
}
next()
}
+
+function flagAsRemoving (toRemove, seen) {
+ if (!seen) seen = new Set()
+ if (seen.has(toRemove)) return
+ seen.add(toRemove)
+ toRemove.removing = true
+ toRemove.requires.forEach((required) => {
+ flagAsRemoving(required, seen)
+ })
+}
+
exports.removeExtraneous = function (args, tree, next) {
for (let pkg of args) {
var pkgName = moduleName(pkg)
@@ -526,7 +539,7 @@ function addDependency (name, versionSpec, tree, log, done) {
}
var child = findRequirement(tree, name, req)
if (!child && swReq) child = findRequirement(tree, name, swReq)
- if (child) {
+ if (hasModernMeta(child)) {
resolveWithExistingModule(child, tree)
if (child.package._shrinkwrap === undefined) {
readShrinkwrap.andInflate(child, function (er) { next(er, child, log) })
@@ -534,12 +547,42 @@ function addDependency (name, versionSpec, tree, log, done) {
next(null, child, log)
}
} else {
+ if (child) {
+ if (req.registry) {
+ req = childDependencySpecifier(tree, name, child.package.version)
+ }
+ if (child.fromBundle) reportBundleOverride(child, log)
+ removeObsoleteDep(child, log)
+ }
fetchPackageMetadata(req, packageRelativePath(tree), {tracker: log.newItem('fetchMetadata')}, iferr(next, function (pkg) {
resolveWithNewModule(pkg, tree, log, next)
}))
}
}
+function getTop (pkg) {
+ const seen = new Set()
+ while (pkg.parent && !seen.has(pkg.parent)) {
+ pkg = pkg.parent
+ seen.add(pkg)
+ }
+ return pkg
+}
+
+function reportBundleOverride (child, log) {
+ const code = 'EBUNDLEOVERRIDE'
+ const top = getTop(child.fromBundle)
+ const bundlerId = packageId(child.fromBundle)
+ if (!top.warnings.some((w) => {
+ return w.code === code
+ })) {
+ const err = new Error(`${bundlerId} had bundled packages that do not match the required version(s). They have been replaced with non-bundled versions.`)
+ err.code = code
+ top.warnings.push(err)
+ }
+ if (log) log.verbose('bundle', `${code}: Replacing ${bundlerId}'s bundled version of ${moduleName(child)} with ${packageId(child)}.`)
+}
+
function resolveWithExistingModule (child, tree) {
validate('OO', arguments)
addRequiredDep(tree, child)
@@ -592,7 +635,7 @@ function resolveWithNewModule (pkg, tree, log, next) {
return isInstallable(pkg, (err) => {
let installable = !err
addBundled(pkg, (bundleErr) => {
- var parent = earliestInstallable(tree, tree, pkg) || tree
+ var parent = earliestInstallable(tree, tree, pkg, log) || tree
var isLink = pkg._requested.type === 'directory'
var child = createChild({
package: pkg,
@@ -609,7 +652,10 @@ function resolveWithNewModule (pkg, tree, log, next) {
var hasBundled = child.children.length
var replaced = replaceModuleByName(parent, 'children', child)
- if (replaced) removeObsoleteDep(replaced)
+ if (replaced) {
+ if (replaced.fromBundle) reportBundleOverride(replaced, log)
+ removeObsoleteDep(replaced)
+ }
addRequiredDep(tree, child)
child.location = flatNameFromTree(child)
@@ -694,12 +740,25 @@ function preserveSymlinks () {
// Find the highest level in the tree that we can install this module in.
// If the module isn't installed above us yet, that'd be the very top.
// If it is, then it's the level below where its installed.
-var earliestInstallable = exports.earliestInstallable = function (requiredBy, tree, pkg) {
- validate('OOO', arguments)
+var earliestInstallable = exports.earliestInstallable = function (requiredBy, tree, pkg, log) {
+ validate('OOOO', arguments)
+
function undeletedModuleMatches (child) {
return !child.removed && moduleName(child) === pkg.name
}
- if (tree.children.some(undeletedModuleMatches)) return null
+ const undeletedMatches = tree.children.filter(undeletedModuleMatches)
+ if (undeletedMatches.length) {
+ // if there's a conflict with another child AT THE SAME level then we're replacing it, so
+ // mark it as removed and continue with resolution normally.
+ if (tree === requiredBy) {
+ undeletedMatches.forEach((pkg) => {
+ if (pkg.fromBundle) reportBundleOverride(pkg, log)
+ removeObsoleteDep(pkg, log)
+ })
+ } else {
+ return null
+ }
+ }
// If any of the children of this tree have conflicting
// binaries then we need to decline to install this package here.
@@ -738,5 +797,5 @@ var earliestInstallable = exports.earliestInstallable = function (requiredBy, tr
if (!preserveSymlinks() && /^[.][.][\\/]/.test(path.relative(tree.parent.realpath, tree.realpath))) return tree
- return (earliestInstallable(requiredBy, tree.parent, pkg) || tree)
+ return (earliestInstallable(requiredBy, tree.parent, pkg, log) || tree)
}
diff --git a/deps/npm/lib/install/diff-trees.js b/deps/npm/lib/install/diff-trees.js
index 4316f351cc..06e6b77a91 100644
--- a/deps/npm/lib/install/diff-trees.js
+++ b/deps/npm/lib/install/diff-trees.js
@@ -70,6 +70,9 @@ function sriMatch (aa, bb) {
function pkgAreEquiv (aa, bb) {
// coming in we know they share a path…
+ // if one is inside a link and the other is not, then they are not equivalent
+ // this happens when we're replacing a linked dep with a non-linked version
+ if (aa.isInLink !== bb.isInLink) return false
// if they share package metadata _identity_, they're the same thing
if (aa.package === bb.package) return true
// if they share integrity information, they're the same thing
diff --git a/deps/npm/lib/install/has-modern-meta.js b/deps/npm/lib/install/has-modern-meta.js
new file mode 100644
index 0000000000..382e74c70c
--- /dev/null
+++ b/deps/npm/lib/install/has-modern-meta.js
@@ -0,0 +1,19 @@
+'use strict'
+module.exports = hasModernMeta
+
+const npa = require('npm-package-arg')
+const moduleName = require('../utils/module-name.js')
+
+function isLink (child) {
+ return child.isLink || (child.parent && isLink(child.parent))
+}
+
+function hasModernMeta (child) {
+ if (!child) return false
+ const resolved = child.package._resolved && npa.resolve(moduleName(child), child.package._resolved)
+ return child.isTop || isLink(child) || (
+ child.package &&
+ resolved &&
+ (child.package._integrity || child.package._shasum || resolved.type === 'git')
+ )
+}
diff --git a/deps/npm/lib/install/inflate-shrinkwrap.js b/deps/npm/lib/install/inflate-shrinkwrap.js
index 43ac9136f0..e596ca94ab 100644
--- a/deps/npm/lib/install/inflate-shrinkwrap.js
+++ b/deps/npm/lib/install/inflate-shrinkwrap.js
@@ -14,6 +14,8 @@ const realizeShrinkwrapSpecifier = require('./realize-shrinkwrap-specifier.js')
const validate = require('aproba')
const path = require('path')
const isRegistry = require('../utils/is-registry.js')
+const hasModernMeta = require('./has-modern-meta.js')
+const ssri = require('ssri')
module.exports = function (tree, sw, opts, finishInflating) {
if (!fetchPackageMetadata) {
@@ -68,7 +70,7 @@ function normalizePackageDataNoErrors (pkg) {
function inflatableChild (onDiskChild, name, topPath, tree, sw, requested, opts) {
validate('OSSOOOO|ZSSOOOO', arguments)
- if (onDiskChild && childIsEquivalent(sw, requested, onDiskChild)) {
+ if (hasModernMeta(onDiskChild) && childIsEquivalent(sw, requested, onDiskChild)) {
// The version on disk matches the shrinkwrap entry.
if (!onDiskChild.fromShrinkwrap) onDiskChild.fromShrinkwrap = true
onDiskChild.package._requested = requested
@@ -106,7 +108,7 @@ function makeFakeChild (name, topPath, tree, sw, requested) {
name: name,
version: sw.version,
_id: name + '@' + sw.version,
- _resolved: adaptResolved(requested, sw.resolved),
+ _resolved: sw.resolved,
_requested: requested,
_optional: sw.optional,
_development: sw.dev,
@@ -144,23 +146,6 @@ function makeFakeChild (name, topPath, tree, sw, requested) {
return child
}
-function adaptResolved (requested, resolved) {
- const registry = requested.scope
- ? npm.config.get(`${requested.scope}:registry`) || npm.config.get('registry')
- : npm.config.get('registry')
- if (!isRegistry(requested) || (resolved && resolved.indexOf(registry) === 0)) {
- // Nothing to worry about here. Pass it through.
- return resolved
- } else {
- // We could fast-path for registry.npmjs.org here, but if we do, it
- // would end up getting written back to the `resolved` field. By always
- // returning `null` for other registries, `pacote.extract()` will take
- // care of any required metadata fetches internally, without altering
- // the tree we're going to write out to shrinkwrap/lockfile.
- return null
- }
-}
-
function fetchChild (topPath, tree, sw, requested) {
return fetchPackageMetadata(requested, topPath).then((pkg) => {
pkg._from = sw.from || requested.raw
@@ -196,7 +181,11 @@ function fetchChild (topPath, tree, sw, requested) {
function childIsEquivalent (sw, requested, child) {
if (!child) return false
if (child.fromShrinkwrap) return true
- if (sw.integrity && child.package._integrity === sw.integrity) return true
+ if (
+ sw.integrity &&
+ child.package._integrity &&
+ ssri.parse(sw.integrity).match(child.package._integrity)
+ ) return true
if (child.isLink && requested.type === 'directory') return path.relative(child.realpath, requested.fetchSpec) === ''
if (sw.resolved) return child.package._resolved === sw.resolved
diff --git a/deps/npm/lib/install/read-shrinkwrap.js b/deps/npm/lib/install/read-shrinkwrap.js
index 45e883caa2..a48a4aea00 100644
--- a/deps/npm/lib/install/read-shrinkwrap.js
+++ b/deps/npm/lib/install/read-shrinkwrap.js
@@ -25,14 +25,7 @@ function readShrinkwrap (child, next) {
log.warn('read-shrinkwrap', 'Ignoring package-lock.json because there is already an npm-shrinkwrap.json. Please use only one of the two.')
}
const name = shrinkwrap ? 'npm-shrinkwrap.json' : 'package-lock.json'
- let parsed = null
- if (shrinkwrap || lockfile) {
- try {
- parsed = parseJSON(shrinkwrap || lockfile)
- } catch (ex) {
- throw ex
- }
- }
+ const parsed = parsePkgLock(shrinkwrap || lockfile, name)
if (parsed && parsed.lockfileVersion !== PKGLOCK_VERSION) {
log.warn('read-shrinkwrap', `This version of npm is compatible with lockfileVersion@${PKGLOCK_VERSION}, but ${name} was generated for lockfileVersion@${parsed.lockfileVersion || 0}. I'll try to do my best with it!`)
}
@@ -43,7 +36,8 @@ function readShrinkwrap (child, next) {
function maybeReadFile (name, child) {
return readFileAsync(
- path.join(child.path, name)
+ path.join(child.path, name),
+ 'utf8'
).catch({code: 'ENOENT'}, () => null)
}
@@ -56,3 +50,57 @@ module.exports.andInflate = function (child, next) {
}
}))
}
+
+const PARENT_RE = /\|{7,}/g
+const OURS_RE = /\<{7,}/g
+const THEIRS_RE = /\={7,}/g
+const END_RE = /\>{7,}/g
+
+module.exports._isDiff = isDiff
+function isDiff (str) {
+ return str.match(OURS_RE) && str.match(THEIRS_RE) && str.match(END_RE)
+}
+
+module.exports._parsePkgLock = parsePkgLock
+function parsePkgLock (str, filename) {
+ if (!str) { return null }
+ try {
+ return parseJSON(str)
+ } catch (e) {
+ if (isDiff(str)) {
+ log.warn('conflict', `A git conflict was detected in ${filename}. Attempting to auto-resolve.`)
+ const pieces = str.split(/[\n\r]+/g).reduce((acc, line) => {
+ if (line.match(PARENT_RE)) acc.state = 'parent'
+ else if (line.match(OURS_RE)) acc.state = 'ours'
+ else if (line.match(THEIRS_RE)) acc.state = 'theirs'
+ else if (line.match(END_RE)) acc.state = 'top'
+ else {
+ if (acc.state === 'top' || acc.state === 'ours') acc.ours += line
+ if (acc.state === 'top' || acc.state === 'theirs') acc.theirs += line
+ if (acc.state === 'top' || acc.state === 'parent') acc.parent += line
+ }
+ return acc
+ }, {
+ state: 'top',
+ ours: '',
+ theirs: '',
+ parent: ''
+ })
+ try {
+ const ours = parseJSON(pieces.ours)
+ const theirs = parseJSON(pieces.theirs)
+ return reconcileLockfiles(ours, theirs)
+ } catch (_e) {
+ log.error('conflict', `Automatic conflict resolution failed. Please manually resolve conflicts in ${filename} and try again.`)
+ log.silly('conflict', `Error during resolution: ${_e}`)
+ throw e
+ }
+ } else {
+ throw e
+ }
+ }
+}
+
+function reconcileLockfiles (parent, ours, theirs) {
+ return Object.assign({}, ours, theirs)
+}
diff --git a/deps/npm/lib/install/save.js b/deps/npm/lib/install/save.js
index f0c61f555d..3f62643b80 100644
--- a/deps/npm/lib/install/save.js
+++ b/deps/npm/lib/install/save.js
@@ -3,6 +3,7 @@
const createShrinkwrap = require('../shrinkwrap.js').createShrinkwrap
const deepSortObject = require('../utils/deep-sort-object.js')
const detectIndent = require('detect-indent')
+const detectNewline = require('detect-newline')
const fs = require('graceful-fs')
const iferr = require('iferr')
const log = require('npmlog')
@@ -10,6 +11,7 @@ const moduleName = require('../utils/module-name.js')
const npm = require('../npm.js')
const parseJSON = require('../utils/parse-json.js')
const path = require('path')
+const stringifyPackage = require('../utils/stringify-package')
const validate = require('aproba')
const without = require('lodash.without')
const writeFileAtomic = require('write-file-atomic')
@@ -60,7 +62,8 @@ function savePackageJson (tree, next) {
// don't use readJson, because we don't want to do all the other
// tricky npm-specific stuff that's in there.
fs.readFile(saveTarget, 'utf8', iferr(next, function (packagejson) {
- const indent = detectIndent(packagejson).indent || ' '
+ const indent = detectIndent(packagejson).indent
+ const newline = detectNewline(packagejson)
try {
tree.package = parseJSON(packagejson)
} catch (ex) {
@@ -122,7 +125,7 @@ function savePackageJson (tree, next) {
tree.package.bundleDependencies = deepSortObject(bundle)
}
- var json = JSON.stringify(tree.package, null, indent) + '\n'
+ var json = stringifyPackage(tree.package, indent, newline)
if (json === packagejson) {
log.verbose('shrinkwrap', 'skipping write for package.json because there were no changes.')
next()