fetch-package-metadata.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. 'use strict'
  2. const deprCheck = require('./utils/depr-check')
  3. const path = require('path')
  4. const log = require('npmlog')
  5. const pacote = require('pacote')
  6. const readPackageTree = require('read-package-tree')
  7. const rimraf = require('rimraf')
  8. const validate = require('aproba')
  9. const npa = require('npm-package-arg')
  10. const npm = require('./npm')
  11. let npmConfig
  12. const npmlog = require('npmlog')
  13. const limit = require('call-limit')
  14. const tempFilename = require('./utils/temp-filename.js')
  15. const replaceInfo = require('./utils/replace-info.js')
  16. const isWindows = require('./utils/is-windows.js')
  17. function andLogAndFinish (spec, tracker, done) {
  18. validate('SOF|SZF|OOF|OZF', [spec, tracker, done])
  19. return (er, pkg) => {
  20. if (er) {
  21. er.message = replaceInfo(er.message)
  22. var spc = replaceInfo(String(spec))
  23. log.silly('fetchPackageMetaData', 'error for ' + spc, er.message)
  24. if (tracker) tracker.finish()
  25. }
  26. return done(er, pkg)
  27. }
  28. }
  29. const LRUCache = require('lru-cache')
  30. const CACHE = new LRUCache({
  31. max: 300 * 1024 * 1024,
  32. length: (p) => p._contentLength
  33. })
  34. module.exports = limit(fetchPackageMetadata, npm.limit.fetch)
  35. function fetchPackageMetadata (spec, where, opts, done) {
  36. validate('SSOF|SSFZ|OSOF|OSFZ', [spec, where, opts, done])
  37. if (!done) {
  38. done = opts
  39. opts = {}
  40. }
  41. var tracker = opts.tracker
  42. const logAndFinish = andLogAndFinish(spec, tracker, done)
  43. if (typeof spec === 'object') {
  44. var dep = spec
  45. } else {
  46. dep = npa(spec)
  47. }
  48. if (!isWindows && dep.type === 'directory' && /^[a-zA-Z]:/.test(dep.fetchSpec)) {
  49. var err = new Error(`Can't install from windows path on a non-windows system: ${dep.fetchSpec.replace(/[/]/g, '\\')}`)
  50. err.code = 'EWINDOWSPATH'
  51. return logAndFinish(err)
  52. }
  53. if (!npmConfig) {
  54. npmConfig = require('./config/figgy-config.js')
  55. }
  56. pacote.manifest(dep, npmConfig({
  57. annotate: true,
  58. fullMetadata: opts.fullMetadata,
  59. log: tracker || npmlog,
  60. memoize: CACHE,
  61. where: where
  62. })).then(
  63. (pkg) => logAndFinish(null, deprCheck(pkg)),
  64. (err) => {
  65. if (dep.type !== 'directory') return logAndFinish(err)
  66. if (err.code === 'ENOTDIR') {
  67. var enolocal = new Error(`Could not install "${path.relative(process.cwd(), dep.fetchSpec)}" as it is not a directory and is not a file with a name ending in .tgz, .tar.gz or .tar`)
  68. enolocal.code = 'ENOLOCAL'
  69. if (err.stack) enolocal.stack = err.stack
  70. return logAndFinish(enolocal)
  71. } else if (err.code === 'ENOPACKAGEJSON') {
  72. var enopackage = new Error(`Could not install from "${path.relative(process.cwd(), dep.fetchSpec)}" as it does not contain a package.json file.`)
  73. enopackage.code = 'ENOLOCAL'
  74. if (err.stack) enopackage.stack = err.stack
  75. return logAndFinish(enopackage)
  76. } else {
  77. return logAndFinish(err)
  78. }
  79. }
  80. )
  81. }
  82. module.exports.addBundled = addBundled
  83. function addBundled (pkg, next) {
  84. validate('OF', arguments)
  85. if (pkg._bundled !== undefined) return next(null, pkg)
  86. if (!pkg.bundleDependencies && pkg._requested.type !== 'directory') return next(null, pkg)
  87. const requested = pkg._requested || npa(pkg._from)
  88. if (requested.type === 'directory') {
  89. pkg._bundled = null
  90. return readPackageTree(pkg._requested.fetchSpec, function (er, tree) {
  91. if (tree) pkg._bundled = tree.children
  92. return next(null, pkg)
  93. })
  94. }
  95. pkg._bundled = null
  96. const target = tempFilename('unpack')
  97. if (!npmConfig) {
  98. npmConfig = require('./config/figgy-config.js')
  99. }
  100. const opts = npmConfig({integrity: pkg._integrity})
  101. pacote.extract(pkg._resolved || pkg._requested || npa.resolve(pkg.name, pkg.version), target, opts).then(() => {
  102. log.silly('addBundled', 'read tarball')
  103. readPackageTree(target, (err, tree) => {
  104. if (err) { return next(err) }
  105. log.silly('cleanup', 'remove extracted module')
  106. rimraf(target, function () {
  107. if (tree) {
  108. pkg._bundled = tree.children
  109. }
  110. next(null, pkg)
  111. })
  112. })
  113. }, next)
  114. }