diff options
Diffstat (limited to 'deps/npm/lib/install/inflate-shrinkwrap.js')
-rw-r--r-- | deps/npm/lib/install/inflate-shrinkwrap.js | 244 |
1 files changed, 166 insertions, 78 deletions
diff --git a/deps/npm/lib/install/inflate-shrinkwrap.js b/deps/npm/lib/install/inflate-shrinkwrap.js index aca4204930..9878b0f19a 100644 --- a/deps/npm/lib/install/inflate-shrinkwrap.js +++ b/deps/npm/lib/install/inflate-shrinkwrap.js @@ -1,105 +1,193 @@ 'use strict' -var asyncMap = require('slide').asyncMap -var validate = require('aproba') -var iferr = require('iferr') -var realizeShrinkwrapSpecifier = require('./realize-shrinkwrap-specifier.js') -var isRegistrySpecifier = require('./is-registry-specifier.js') -var fetchPackageMetadata = require('../fetch-package-metadata.js') -var annotateMetadata = require('../fetch-package-metadata.js').annotateMetadata -var addShrinkwrap = require('../fetch-package-metadata.js').addShrinkwrap -var addBundled = require('../fetch-package-metadata.js').addBundled -var inflateBundled = require('./inflate-bundled.js') -var npm = require('../npm.js') -var createChild = require('./node.js').create -var moduleName = require('../utils/module-name.js') -var childPath = require('../utils/child-path.js') + +const BB = require('bluebird') + +const addBundled = BB.promisify(require('../fetch-package-metadata.js').addBundled) +const childPath = require('../utils/child-path.js') +const createChild = require('./node.js').create +const fetchPackageMetadata = BB.promisify(require('../fetch-package-metadata.js')) +const inflateBundled = require('./inflate-bundled.js') +const moduleName = require('../utils/module-name.js') +const normalizePackageData = require('normalize-package-data') +const npm = require('../npm.js') +const realizeShrinkwrapSpecifier = require('./realize-shrinkwrap-specifier.js') +const validate = require('aproba') +const path = require('path') module.exports = function (tree, swdeps, finishInflating) { if (!npm.config.get('shrinkwrap')) return finishInflating() tree.loaded = true - return inflateShrinkwrap(tree.path, tree, swdeps, finishInflating) + return inflateShrinkwrap(tree.path, tree, swdeps).then( + () => finishInflating(), + finishInflating + ) } -function inflateShrinkwrap (topPath, tree, swdeps, finishInflating) { - validate('SOOF', arguments) - var onDisk = {} - tree.children.forEach(function (child) { onDisk[moduleName(child)] = child }) - var dev = npm.config.get('dev') || (!/^prod(uction)?$/.test(npm.config.get('only')) && !npm.config.get('production')) || /^dev(elopment)?$/.test(npm.config.get('only')) - var prod = !/^dev(elopment)?$/.test(npm.config.get('only')) - - // If the shrinkwrap has no dev dependencies in it then we'll leave the one's - // already on disk. If it DOES have dev dependencies then ONLY those in the - // shrinkwrap will be included. - var swHasDev = Object.keys(swdeps).some(function (name) { return swdeps[name].dev }) - tree.children = swHasDev ? [] : tree.children.filter(function (child) { - return tree.package.devDependencies[moduleName(child)] +function inflateShrinkwrap (topPath, tree, swdeps) { + validate('SOO', arguments) + const onDisk = {} + tree.children.forEach((child) => { + onDisk[moduleName(child)] = child }) + const dev = npm.config.get('dev') || (!/^prod(uction)?$/.test(npm.config.get('only')) && !npm.config.get('production')) || /^dev(elopment)?$/.test(npm.config.get('only')) + const prod = !/^dev(elopment)?$/.test(npm.config.get('only')) - return asyncMap(Object.keys(swdeps), doRealizeAndInflate, finishInflating) + tree.children = [] - function doRealizeAndInflate (name, next) { - return realizeShrinkwrapSpecifier(name, swdeps[name], topPath, iferr(next, andInflate(name, next))) - } + return BB.each(Object.keys(swdeps), (name) => { + const sw = swdeps[name] + if ( + (!prod && !sw.dev) || + (!dev && sw.dev) + ) { return null } + const dependencies = sw.dependencies || {} + const requested = realizeShrinkwrapSpecifier(name, sw, topPath) + return inflatableChild( + onDisk[name], name, topPath, tree, sw, requested + ).then((child) => { + return inflateShrinkwrap(topPath, child, dependencies) + }) + }) +} - function andInflate (name, next) { - return function (requested) { - var sw = swdeps[name] - var dependencies = sw.dependencies || {} - if ((!prod && !sw.dev) || (!dev && sw.dev)) return next() - var child = onDisk[name] - if (childIsEquivalent(sw, requested, child)) { - if (!child.fromShrinkwrap) child.fromShrinkwrap = requested.raw - if (sw.dev) child.shrinkwrapDev = true - tree.children.push(child) - annotateMetadata(child.package, requested, requested.raw, topPath) - return inflateShrinkwrap(topPath, child, dependencies || {}, next) - } else { - var from = sw.from || requested.raw - var optional = sw.optional - return fetchPackageMetadata(requested, topPath, iferr(next, andAddShrinkwrap(from, optional, dependencies, next))) - } - } +function normalizePackageDataNoErrors (pkg) { + try { + normalizePackageData(pkg) + } catch (ex) { + // don't care } +} - function andAddShrinkwrap (from, optional, dependencies, next) { - return function (pkg) { - pkg._from = from - pkg._optional = optional - addShrinkwrap(pkg, iferr(next, andAddBundled(pkg, dependencies, next))) - } +function inflatableChild (onDiskChild, name, topPath, tree, sw, requested) { + validate('OSSOOO|ZSSOOO', arguments) + if (onDiskChild && childIsEquivalent(sw, requested, onDiskChild)) { + // The version on disk matches the shrinkwrap entry. + if (!onDiskChild.fromShrinkwrap) onDiskChild.fromShrinkwrap = true + if (sw.dev) onDiskChild.shrinkwrapDev = true + onDiskChild.package._requested = requested + onDiskChild.package._spec = requested.rawSpec + onDiskChild.package._where = topPath + onDiskChild.fromBundle = sw.bundled ? tree.fromBundle || tree : null + if (!onDiskChild.package._args) onDiskChild.package._args = [] + onDiskChild.package._args.push([String(requested), topPath]) + // non-npm registries can and will return unnormalized data, plus + // even the npm registry may have package data normalized with older + // normalization rules. This ensures we get package data in a consistent, + // stable format. + normalizePackageDataNoErrors(onDiskChild.package) + tree.children.push(onDiskChild) + return BB.resolve(onDiskChild) + } else if (sw.version && sw.integrity) { + // The shrinkwrap entry has an integrity field. We can fake a pkg to get + // the installer to do a content-address fetch from the cache, if possible. + return BB.resolve(makeFakeChild(name, topPath, tree, sw, requested)) + } else { + // It's not on disk, and we can't just look it up by address -- do a full + // fpm/inflate bundle pass. For registry deps, this will go straight to the + // tarball URL, as if it were a remote tarball dep. + return fetchChild(topPath, tree, sw, requested) } +} - function andAddBundled (pkg, dependencies, next) { - return function () { - return addBundled(pkg, iferr(next, andAddChild(pkg, dependencies, next))) +function makeFakeChild (name, topPath, tree, sw, requested) { + const from = sw.from || requested.raw + const pkg = { + name: name, + version: sw.version, + _resolved: adaptResolved(requested, sw.resolved), + _requested: requested, + _optional: sw.optional, + _integrity: sw.integrity, + _from: from, + _spec: requested.rawSpec, + _where: topPath, + _args: [[requested.toString(), topPath]], + _injectedFromShrinkwrap: sw + } + let bundleAdded = BB.resolve() + if (Object.keys(sw.dependencies || {}).some((d) => { + return sw.dependencies[d].bundled + })) { + pkg.bundleDependencies = [] + bundleAdded = addBundled(pkg) + } + return bundleAdded.then(() => { + const child = createChild({ + package: pkg, + loaded: true, + parent: tree, + children: pkg._bundled || [], + fromShrinkwrap: true, + fromBundle: sw.bundled ? tree.fromBundle || tree : null, + path: childPath(tree.path, pkg), + realpath: childPath(tree.realpath, pkg), + location: tree.location + '/' + pkg.name, + isInLink: tree.isLink + }) + tree.children.push(child) + if (pkg._bundled) { + delete pkg._bundled + inflateBundled(child, child, child.children) } + 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 (!requested.registry || (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 andAddChild (pkg, dependencies, next) { - return function () { - var child = createChild({ - package: pkg, - loaded: true, - parent: tree, - fromShrinkwrap: pkg._from, - path: childPath(tree.path, pkg), - realpath: childPath(tree.realpath, pkg), - children: pkg._bundled || [] - }) - tree.children.push(child) - if (pkg._bundled) { - delete pkg._bundled - inflateBundled(child, child, child.children) - } - inflateShrinkwrap(topPath, child, dependencies || {}, next) +function fetchChild (topPath, tree, sw, requested) { + const from = sw.from || requested.raw + const optional = sw.optional + return fetchPackageMetadata(requested, topPath).then((pkg) => { + pkg._from = from + pkg._optional = optional + return addBundled(pkg).then(() => pkg) + }).then((pkg) => { + var isLink = pkg._requested.type === 'directory' + const child = createChild({ + package: pkg, + loaded: true, + parent: tree, + fromShrinkwrap: requested, + path: childPath(tree.path, pkg), + realpath: isLink ? requested.fetchSpec : childPath(tree.realpath, pkg), + children: pkg._bundled || [], + location: tree.location + '/' + pkg.name, + isLink: isLink, + isInLink: tree.isLink + }) + tree.children.push(child) + if (pkg._bundled) { + delete pkg._bundled + inflateBundled(child, child, child.children) } - } + return child + }) } 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 (child.isLink && requested.type === 'directory') return path.relative(child.realpath, requested.fetchSpec) === '' + if (sw.resolved) return child.package._resolved === sw.resolved - if (!isRegistrySpecifier(requested) && sw.from) return child.package._from === sw.from + if (!requested.registry && sw.from) return child.package._from === sw.from + if (!requested.registry && child.package._resolved) return sw.version === child.package._resolved return child.package.version === sw.version } |