extract.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. 'use strict'
  2. const BB = require('bluebird')
  3. const figgyPudding = require('figgy-pudding')
  4. const stat = BB.promisify(require('graceful-fs').stat)
  5. const gentlyRm = BB.promisify(require('../../utils/gently-rm.js'))
  6. const mkdirp = BB.promisify(require('gentle-fs').mkdir)
  7. const moduleName = require('../../utils/module-name.js')
  8. const moduleStagingPath = require('../module-staging-path.js')
  9. const move = require('../../utils/move.js')
  10. const npa = require('npm-package-arg')
  11. const npm = require('../../npm.js')
  12. let npmConfig
  13. const packageId = require('../../utils/package-id.js')
  14. const path = require('path')
  15. const localWorker = require('./extract-worker.js')
  16. const workerFarm = require('worker-farm')
  17. const isRegistry = require('../../utils/is-registry.js')
  18. const WORKER_PATH = require.resolve('./extract-worker.js')
  19. let workers
  20. const ExtractOpts = figgyPudding({
  21. log: {}
  22. }, { other () { return true } })
  23. // Disabled for now. Re-enable someday. Just not today.
  24. const ENABLE_WORKERS = false
  25. extract.init = () => {
  26. if (ENABLE_WORKERS) {
  27. workers = workerFarm({
  28. maxConcurrentCallsPerWorker: npm.limit.fetch,
  29. maxRetries: 1
  30. }, WORKER_PATH)
  31. }
  32. return BB.resolve()
  33. }
  34. extract.teardown = () => {
  35. if (ENABLE_WORKERS) {
  36. workerFarm.end(workers)
  37. workers = null
  38. }
  39. return BB.resolve()
  40. }
  41. module.exports = extract
  42. function extract (staging, pkg, log) {
  43. log.silly('extract', packageId(pkg))
  44. const extractTo = moduleStagingPath(staging, pkg)
  45. if (!npmConfig) {
  46. npmConfig = require('../../config/figgy-config.js')
  47. }
  48. let opts = ExtractOpts(npmConfig()).concat({
  49. integrity: pkg.package._integrity,
  50. resolved: pkg.package._resolved
  51. })
  52. const args = [
  53. pkg.package._requested,
  54. extractTo,
  55. opts
  56. ]
  57. return BB.fromNode((cb) => {
  58. let launcher = localWorker
  59. let msg = args
  60. const spec = typeof args[0] === 'string' ? npa(args[0]) : args[0]
  61. args[0] = spec.raw
  62. if (ENABLE_WORKERS && (isRegistry(spec) || spec.type === 'remote')) {
  63. // We can't serialize these options
  64. opts = opts.concat({
  65. loglevel: opts.log.level,
  66. log: null,
  67. dirPacker: null,
  68. Promise: null,
  69. _events: null,
  70. _eventsCount: null,
  71. list: null,
  72. sources: null,
  73. _maxListeners: null,
  74. root: null
  75. })
  76. // workers will run things in parallel!
  77. launcher = workers
  78. try {
  79. msg = JSON.stringify(msg)
  80. } catch (e) {
  81. return cb(e)
  82. }
  83. }
  84. launcher(msg, cb)
  85. }).then(() => {
  86. if (pkg.package.bundleDependencies || anyBundled(pkg)) {
  87. return readBundled(pkg, staging, extractTo)
  88. }
  89. }).then(() => {
  90. return gentlyRm(path.join(extractTo, 'node_modules'))
  91. })
  92. }
  93. function anyBundled (top, pkg) {
  94. if (!pkg) pkg = top
  95. return pkg.children.some((child) => child.fromBundle === top || anyBundled(top, child))
  96. }
  97. function readBundled (pkg, staging, extractTo) {
  98. return BB.map(pkg.children, (child) => {
  99. if (!child.fromBundle) return
  100. if (child.error) {
  101. throw child.error
  102. } else {
  103. return stageBundledModule(pkg, child, staging, extractTo)
  104. }
  105. }, {concurrency: 10})
  106. }
  107. function stageBundledModule (bundler, child, staging, parentPath) {
  108. const stageFrom = path.join(parentPath, 'node_modules', moduleName(child))
  109. const stageTo = moduleStagingPath(staging, child)
  110. return BB.map(child.children, (child) => {
  111. if (child.error) {
  112. throw child.error
  113. } else {
  114. return stageBundledModule(bundler, child, staging, stageFrom)
  115. }
  116. }).then(() => {
  117. return finishModule(bundler, child, stageTo, stageFrom)
  118. })
  119. }
  120. function finishModule (bundler, child, stageTo, stageFrom) {
  121. // If we were the one's who bundled this module…
  122. if (child.fromBundle === bundler) {
  123. return mkdirp(path.dirname(stageTo)).then(() => {
  124. return move(stageFrom, stageTo)
  125. })
  126. } else {
  127. return stat(stageFrom).then(() => gentlyRm(stageFrom), () => {})
  128. }
  129. }