Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: use undici #658

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 117 additions & 43 deletions lib/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@ const versioning = require('./util/versioning.js');
const napi = require('./util/napi.js');
const makeDir = require('make-dir');
// for fetching binaries
const fetch = require('node-fetch');
const { request } = require('undici');
const tar = require('tar');

let npgVersion = 'unknown';
try {
// Read own package.json to get the current node-pre-pyp version.
const ownPackageJSON = fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8');
const ownPackageJSON = fs.readFileSync(
path.join(__dirname, '..', 'package.json'),
'utf8'
);
npgVersion = JSON.parse(ownPackageJSON).version;
} catch (e) {
// do nothing
Expand All @@ -28,14 +31,15 @@ function place_binary(uri, targetDir, opts, callback) {
log.http('GET', uri);

// Try getting version info from the currently running npm.
const envVersionInfo = process.env.npm_config_user_agent ||
'node ' + process.version;
const envVersionInfo =
process.env.npm_config_user_agent || 'node ' + process.version;

const sanitized = uri.replace('+', '%2B');
const requestOpts = {
uri: sanitized,
headers: {
'User-Agent': 'node-pre-gyp (v' + npgVersion + ', ' + envVersionInfo + ')'
'User-Agent':
'node-pre-gyp (v' + npgVersion + ', ' + envVersionInfo + ')'
},
follow_max: 10
};
Expand All @@ -50,21 +54,26 @@ function place_binary(uri, targetDir, opts, callback) {
requestOpts.ca = opts.ca;
}

const proxyUrl = opts.proxy ||
process.env.http_proxy ||
process.env.HTTP_PROXY ||
process.env.npm_config_proxy;
let agent;
const proxyUrl =
opts.proxy ||
process.env.http_proxy ||
process.env.HTTP_PROXY ||
process.env.npm_config_proxy;
let dispatcher;
if (proxyUrl) {
const ProxyAgent = require('https-proxy-agent');
agent = new ProxyAgent(proxyUrl);
const { ProxyAgent } = require('undici');
dispatcher = new ProxyAgent(proxyUrl);
log.http('download', 'proxy agent configured using: "%s"', proxyUrl);
}

fetch(sanitized, { agent })
request(sanitized, {
dispatcher
})
.then((res) => {
if (!res.ok) {
throw new Error(`response status ${res.status} ${res.statusText} on ${sanitized}`);
if (res.statusCode !== 200) {
throw new Error(
`response status ${res.status} ${res.statusText} on ${sanitized}`
);
}
const dataStream = res.body;

Expand All @@ -75,7 +84,8 @@ function place_binary(uri, targetDir, opts, callback) {
log.info('install', 'unpacking %s', entry.path);
};

dataStream.pipe(extract(targetDir, countExtractions))
dataStream
.pipe(extract(targetDir, countExtractions))
.on('error', (e) => {
reject(e);
});
Expand Down Expand Up @@ -120,13 +130,16 @@ function extract_from_local(from, targetDir, callback) {
function afterExtract(err) {
if (err) return callback(err);
if (extractCount === 0) {
return callback(new Error('There was a fatal problem while extracting the tarball'));
return callback(
new Error('There was a fatal problem while extracting the tarball')
);
}
log.info('tarball', 'done parsing tarball');
callback();
}

fs.createReadStream(from).pipe(extract(targetDir, countExtractions))
fs.createReadStream(from)
.pipe(extract(targetDir, countExtractions))
.on('close', afterExtract)
.on('error', afterExtract);
}
Expand All @@ -144,17 +157,45 @@ function print_fallback_error(err, opts, package_json) {
// If we got a network response it but failed to download
// it means remote binaries are not available, so let's try to help
// the user/developer with the info to debug why
full_message = 'Pre-built binaries not found for ' + package_json.name + '@' + package_json.version;
full_message += ' and ' + opts.runtime + '@' + (opts.target || process.versions.node) + ' (' + opts.node_abi + ' ABI, ' + opts.libc + ')';
full_message =
'Pre-built binaries not found for ' +
package_json.name +
'@' +
package_json.version;
full_message +=
' and ' +
opts.runtime +
'@' +
(opts.target || process.versions.node) +
' (' +
opts.node_abi +
' ABI, ' +
opts.libc +
')';
full_message += fallback_message;
log.warn('Tried to download(' + err.statusCode + '): ' + opts.hosted_tarball);
log.warn(
'Tried to download(' + err.statusCode + '): ' + opts.hosted_tarball
);
log.warn(full_message);
log.http(err.message);
} else {
// If we do not have a statusCode that means an unexpected error
// happened and prevented an http response, so we output the exact error
full_message = 'Pre-built binaries not installable for ' + package_json.name + '@' + package_json.version;
full_message += ' and ' + opts.runtime + '@' + (opts.target || process.versions.node) + ' (' + opts.node_abi + ' ABI, ' + opts.libc + ')';
full_message =
'Pre-built binaries not installable for ' +
package_json.name +
'@' +
package_json.version;
full_message +=
' and ' +
opts.runtime +
'@' +
(opts.target || process.versions.node) +
' (' +
opts.node_abi +
' ABI, ' +
opts.libc +
')';
full_message += fallback_message;
log.warn(full_message);
log.warn('Hit error ' + err.message);
Expand All @@ -166,23 +207,39 @@ function print_fallback_error(err, opts, package_json) {
//
function install(gyp, argv, callback) {
const package_json = gyp.package_json;
const napi_build_version = napi.get_napi_build_version_from_command_args(argv);
const source_build = gyp.opts['build-from-source'] || gyp.opts.build_from_source;
const napi_build_version =
napi.get_napi_build_version_from_command_args(argv);
const source_build =
gyp.opts['build-from-source'] || gyp.opts.build_from_source;
const update_binary = gyp.opts['update-binary'] || gyp.opts.update_binary;
const should_do_source_build = source_build === package_json.name || (source_build === true || source_build === 'true');
const should_do_source_build =
source_build === package_json.name ||
source_build === true ||
source_build === 'true';
if (should_do_source_build) {
log.info('build', 'requesting source compile');
return do_build(gyp, argv, callback);
} else {
const fallback_to_build = gyp.opts['fallback-to-build'] || gyp.opts.fallback_to_build;
let should_do_fallback_build = fallback_to_build === package_json.name || (fallback_to_build === true || fallback_to_build === 'true');
const fallback_to_build =
gyp.opts['fallback-to-build'] || gyp.opts.fallback_to_build;
let should_do_fallback_build =
fallback_to_build === package_json.name ||
fallback_to_build === true ||
fallback_to_build === 'true';
// but allow override from npm
if (process.env.npm_config_argv) {
const cooked = JSON.parse(process.env.npm_config_argv).cooked;
const match = cooked.indexOf('--fallback-to-build');
if (match > -1 && cooked.length > match && cooked[match + 1] === 'false') {
if (
match > -1 &&
cooked.length > match &&
cooked[match + 1] === 'false'
) {
should_do_fallback_build = false;
log.info('install', 'Build fallback disabled via npm flag: --fallback-to-build=false');
log.info(
'install',
'Build fallback disabled via npm flag: --fallback-to-build=false'
);
}
}
let opts;
Expand All @@ -201,23 +258,34 @@ function install(gyp, argv, callback) {
existsAsync(binary_module, (found) => {
if (!update_binary) {
if (found) {
console.log('[' + package_json.name + '] Success: "' + binary_module + '" already installed');
console.log('Pass --update-binary to reinstall or --build-from-source to recompile');
console.log(
'[' +
package_json.name +
'] Success: "' +
binary_module +
'" already installed'
);
console.log(
'Pass --update-binary to reinstall or --build-from-source to recompile'
);
return callback();
}
log.info('check', 'checked for "' + binary_module + '" (not found)');
}

makeDir(to).then(() => {
const fileName = from.startsWith('file://') && from.slice('file://'.length);
if (fileName) {
extract_from_local(fileName, to, after_place);
} else {
place_binary(from, to, opts, after_place);
}
}).catch((err) => {
after_place(err);
});
makeDir(to)
.then(() => {
const fileName =
from.startsWith('file://') && from.slice('file://'.length);
if (fileName) {
extract_from_local(fileName, to, after_place);
} else {
place_binary(from, to, opts, after_place);
}
})
.catch((err) => {
after_place(err);
});

function after_place(err) {
if (err && should_do_fallback_build) {
Expand All @@ -226,7 +294,13 @@ function install(gyp, argv, callback) {
} else if (err) {
return callback(err);
} else {
console.log('[' + package_json.name + '] Success: "' + binary_module + '" is installed via remote');
console.log(
'[' +
package_json.name +
'] Success: "' +
binary_module +
'" is installed via remote'
);
return callback();
}
}
Expand Down
Loading