download.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. const path = require('path')
  2. const fs = require('fs')
  3. const get = require('simple-get')
  4. const pump = require('pump')
  5. const tfs = require('tar-fs')
  6. const zlib = require('zlib')
  7. const util = require('./util')
  8. const error = require('./error')
  9. const proxy = require('./proxy')
  10. const mkdirp = require('mkdirp-classic')
  11. function downloadPrebuild (downloadUrl, opts, cb) {
  12. let cachedPrebuild = util.cachedPrebuild(downloadUrl)
  13. const localPrebuild = util.localPrebuild(downloadUrl, opts)
  14. const tempFile = util.tempFile(cachedPrebuild)
  15. const log = opts.log || util.noopLogger
  16. if (opts.nolocal) return download()
  17. log.info('looking for local prebuild @', localPrebuild)
  18. fs.access(localPrebuild, fs.R_OK | fs.W_OK, function (err) {
  19. if (err && err.code === 'ENOENT') {
  20. return download()
  21. }
  22. log.info('found local prebuild')
  23. cachedPrebuild = localPrebuild
  24. unpack()
  25. })
  26. function download () {
  27. ensureNpmCacheDir(function (err) {
  28. if (err) return onerror(err)
  29. log.info('looking for cached prebuild @', cachedPrebuild)
  30. fs.access(cachedPrebuild, fs.R_OK | fs.W_OK, function (err) {
  31. if (!(err && err.code === 'ENOENT')) {
  32. log.info('found cached prebuild')
  33. return unpack()
  34. }
  35. log.http('request', 'GET ' + downloadUrl)
  36. const reqOpts = proxy({ url: downloadUrl }, opts)
  37. if (opts.token) {
  38. reqOpts.headers = {
  39. 'User-Agent': 'simple-get',
  40. Accept: 'application/octet-stream',
  41. Authorization: 'token ' + opts.token
  42. }
  43. }
  44. const req = get(reqOpts, function (err, res) {
  45. if (err) return onerror(err)
  46. log.http(res.statusCode, downloadUrl)
  47. if (res.statusCode !== 200) return onerror()
  48. mkdirp(util.prebuildCache(), function () {
  49. log.info('downloading to @', tempFile)
  50. pump(res, fs.createWriteStream(tempFile), function (err) {
  51. if (err) return onerror(err)
  52. fs.rename(tempFile, cachedPrebuild, function (err) {
  53. if (err) return cb(err)
  54. log.info('renaming to @', cachedPrebuild)
  55. unpack()
  56. })
  57. })
  58. })
  59. })
  60. req.setTimeout(30 * 1000, function () {
  61. req.abort()
  62. })
  63. })
  64. function onerror (err) {
  65. fs.unlink(tempFile, function () {
  66. cb(err || error.noPrebuilts(opts))
  67. })
  68. }
  69. })
  70. }
  71. function unpack () {
  72. let binaryName
  73. const updateName = opts.updateName || function (entry) {
  74. if (/\.node$/i.test(entry.name)) binaryName = entry.name
  75. }
  76. log.info('unpacking @', cachedPrebuild)
  77. const options = {
  78. readable: true,
  79. writable: true,
  80. hardlinkAsFilesFallback: true
  81. }
  82. const extract = tfs.extract(opts.path, options).on('entry', updateName)
  83. pump(fs.createReadStream(cachedPrebuild), zlib.createGunzip(), extract,
  84. function (err) {
  85. if (err) return cb(err)
  86. let resolved
  87. if (binaryName) {
  88. try {
  89. resolved = path.resolve(opts.path || '.', binaryName)
  90. } catch (err) {
  91. return cb(err)
  92. }
  93. log.info('unpack', 'resolved to ' + resolved)
  94. if (opts.runtime === 'node' && opts.platform === process.platform && opts.abi === process.versions.modules && opts.arch === process.arch) {
  95. try {
  96. require(resolved)
  97. } catch (err) {
  98. return cb(err)
  99. }
  100. log.info('unpack', 'required ' + resolved + ' successfully')
  101. }
  102. }
  103. cb(null, resolved)
  104. })
  105. }
  106. function ensureNpmCacheDir (cb) {
  107. const cacheFolder = util.npmCache()
  108. fs.access(cacheFolder, fs.R_OK | fs.W_OK, function (err) {
  109. if (err && err.code === 'ENOENT') {
  110. return makeNpmCacheDir()
  111. }
  112. cb(err)
  113. })
  114. function makeNpmCacheDir () {
  115. log.info('npm cache directory missing, creating it...')
  116. mkdirp(cacheFolder, cb)
  117. }
  118. }
  119. }
  120. module.exports = downloadPrebuild