download.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  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 = require('noop-logger')
  7. var zlib = require('zlib')
  8. var util = require('./util')
  9. var error = require('./error')
  10. var url = require('url')
  11. var tunnel = require('tunnel-agent')
  12. var mkdirp = require('mkdirp')
  13. function downloadPrebuild (opts, cb) {
  14. var downloadUrl = util.getDownloadUrl(opts)
  15. var cachedPrebuild = util.cachedPrebuild(downloadUrl)
  16. var localPrebuild = util.localPrebuild(downloadUrl)
  17. var tempFile = util.tempFile(cachedPrebuild)
  18. var log = opts.log || noop
  19. if (opts.nolocal) return download()
  20. log.info('looking for local prebuild @', localPrebuild)
  21. fs.exists(localPrebuild, function (exists) {
  22. if (exists) {
  23. log.info('found local prebuild')
  24. cachedPrebuild = localPrebuild
  25. return unpack()
  26. }
  27. download()
  28. })
  29. function download () {
  30. ensureNpmCacheDir(function (err) {
  31. if (err) return onerror(err)
  32. log.info('looking for cached prebuild @', cachedPrebuild)
  33. fs.exists(cachedPrebuild, function (exists) {
  34. if (exists) {
  35. log.info('found cached prebuild')
  36. return unpack()
  37. }
  38. log.http('request', 'GET ' + downloadUrl)
  39. var reqOpts = { url: downloadUrl }
  40. var proxy = opts['https-proxy'] || opts.proxy
  41. if (proxy) {
  42. var parsedDownloadUrl = url.parse(downloadUrl)
  43. var parsedProxy = url.parse(proxy)
  44. var uriProtocol = (parsedDownloadUrl.protocol === 'https:' ? 'https' : 'http')
  45. var proxyProtocol = (parsedProxy.protocol === 'https:' ? 'Https' : 'Http')
  46. var tunnelFnName = [uriProtocol, proxyProtocol].join('Over')
  47. reqOpts.agent = tunnel[tunnelFnName]({
  48. proxy: {
  49. host: parsedProxy.hostname,
  50. port: +parsedProxy.port,
  51. proxyAuth: parsedProxy.auth
  52. }
  53. })
  54. }
  55. var req = get(reqOpts, function (err, res) {
  56. if (err) return onerror(err)
  57. log.http(res.statusCode, downloadUrl)
  58. if (res.statusCode !== 200) return onerror()
  59. mkdirp(util.prebuildCache(), function () {
  60. log.info('downloading to @', tempFile)
  61. pump(res, fs.createWriteStream(tempFile), function (err) {
  62. if (err) return onerror(err)
  63. fs.rename(tempFile, cachedPrebuild, function (err) {
  64. if (err) return cb(err)
  65. log.info('renaming to @', cachedPrebuild)
  66. unpack()
  67. })
  68. })
  69. })
  70. })
  71. req.setTimeout(30 * 1000, function () {
  72. req.abort()
  73. })
  74. })
  75. function onerror (err) {
  76. fs.unlink(tempFile, function () {
  77. cb(err || error.noPrebuilts(opts))
  78. })
  79. }
  80. })
  81. }
  82. function unpack () {
  83. var binaryName
  84. var updateName = opts.updateName || function (entry) {
  85. if (/\.node$/i.test(entry.name)) binaryName = entry.name
  86. }
  87. log.info('unpacking @', cachedPrebuild)
  88. var options = {
  89. readable: true,
  90. writable: true,
  91. hardlinkAsFilesFallback: true
  92. }
  93. var extract = tfs.extract(opts.path, options).on('entry', updateName)
  94. pump(fs.createReadStream(cachedPrebuild), zlib.createGunzip(), extract,
  95. function (err) {
  96. if (err) return cb(err)
  97. var resolved
  98. if (binaryName) {
  99. try {
  100. resolved = path.resolve(opts.path || '.', binaryName)
  101. } catch (err) {
  102. return cb(err)
  103. }
  104. log.info('unpack', 'resolved to ' + resolved)
  105. if (opts.platform === process.platform && opts.abi === process.versions.modules) {
  106. try {
  107. require(resolved)
  108. } catch (err) {
  109. return cb(err)
  110. }
  111. log.info('unpack', 'required ' + resolved + ' successfully')
  112. }
  113. }
  114. cb(null, resolved)
  115. })
  116. }
  117. function ensureNpmCacheDir (cb) {
  118. var cacheFolder = util.npmCache()
  119. if (fs.access) {
  120. fs.access(cacheFolder, fs.R_OK | fs.W_OK, function (err) {
  121. if (err && err.code === 'ENOENT') {
  122. return makeNpmCacheDir()
  123. }
  124. cb(err)
  125. })
  126. } else {
  127. fs.exists(cacheFolder, function (exists) {
  128. if (!exists) return makeNpmCacheDir()
  129. cb()
  130. })
  131. }
  132. function makeNpmCacheDir () {
  133. log.info('npm cache directory missing, creating it...')
  134. mkdirp(cacheFolder, cb)
  135. }
  136. }
  137. }
  138. module.exports = downloadPrebuild