2025-04-02 06:50:39 -04:00

154 lines
4.2 KiB
JavaScript

const path = require('path');
const fs = require('fs');
const get = require('simple-get');
const pump = require('pump');
const tfs = require('tar-fs');
const zlib = require('zlib');
const util = require('./util');
const error = require('./error');
const proxy = require('./proxy');
const mkdirp = require('mkdirp-classic');
function downloadPrebuild(downloadUrl, opts, cb) {
let cachedPrebuild = util.cachedPrebuild(downloadUrl);
const localPrebuild = util.localPrebuild(downloadUrl, opts);
const tempFile = util.tempFile(cachedPrebuild);
const log = opts.log || util.noopLogger;
if (opts.nolocal) return download();
log.info('looking for local prebuild @', localPrebuild);
fs.access(localPrebuild, fs.R_OK | fs.W_OK, function (err) {
if (err && err.code === 'ENOENT') {
return download();
}
log.info('found local prebuild');
cachedPrebuild = localPrebuild;
unpack();
});
function download() {
ensureNpmCacheDir(function (err) {
if (err) return onerror(err);
log.info('looking for cached prebuild @', cachedPrebuild);
fs.access(cachedPrebuild, fs.R_OK | fs.W_OK, function (err) {
if (!(err && err.code === 'ENOENT')) {
log.info('found cached prebuild');
return unpack();
}
log.http('request', 'GET ' + downloadUrl);
const reqOpts = proxy({ url: downloadUrl }, opts);
if (opts.token) {
reqOpts.headers = {
'User-Agent': 'simple-get',
Accept: 'application/octet-stream',
Authorization: 'token ' + opts.token,
};
}
const req = get(reqOpts, function (err, res) {
if (err) return onerror(err);
log.http(res.statusCode, downloadUrl);
if (res.statusCode !== 200) return onerror();
mkdirp(util.prebuildCache(), function () {
log.info('downloading to @', tempFile);
pump(res, fs.createWriteStream(tempFile), function (err) {
if (err) return onerror(err);
fs.rename(tempFile, cachedPrebuild, function (err) {
if (err) return cb(err);
log.info('renaming to @', cachedPrebuild);
unpack();
});
});
});
});
req.setTimeout(30 * 1000, function () {
req.abort();
});
});
function onerror(err) {
fs.unlink(tempFile, function () {
cb(err || error.noPrebuilts(opts));
});
}
});
}
function unpack() {
let binaryName;
const updateName =
opts.updateName ||
function (entry) {
if (/\.node$/i.test(entry.name)) binaryName = entry.name;
};
log.info('unpacking @', cachedPrebuild);
const options = {
readable: true,
writable: true,
hardlinkAsFilesFallback: true,
};
const extract = tfs.extract(opts.path, options).on('entry', updateName);
pump(
fs.createReadStream(cachedPrebuild),
zlib.createGunzip(),
extract,
function (err) {
if (err) return cb(err);
let resolved;
if (binaryName) {
try {
resolved = path.resolve(opts.path || '.', binaryName);
} catch (err) {
return cb(err);
}
log.info('unpack', 'resolved to ' + resolved);
if (
opts.runtime === 'node' &&
opts.platform === process.platform &&
opts.abi === process.versions.modules &&
opts.arch === process.arch
) {
try {
require(resolved);
} catch (err) {
return cb(err);
}
log.info('unpack', 'required ' + resolved + ' successfully');
}
}
cb(null, resolved);
}
);
}
function ensureNpmCacheDir(cb) {
const cacheFolder = util.npmCache();
fs.access(cacheFolder, fs.R_OK | fs.W_OK, function (err) {
if (err && err.code === 'ENOENT') {
return makeNpmCacheDir();
}
cb(err);
});
function makeNpmCacheDir() {
log.info('npm cache directory missing, creating it...');
mkdirp(cacheFolder, cb);
}
}
}
module.exports = downloadPrebuild;