download.js 3.6 KB

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