190 lines
5.3 KiB
JavaScript
190 lines
5.3 KiB
JavaScript
|
#! /usr/bin/env node
|
||
|
|
||
|
// This is a build scripts, so some logging is desireable as it allows
|
||
|
// us to follow the code path that triggered the error.
|
||
|
/* eslint-disable no-console */
|
||
|
const fs = require('fs');
|
||
|
|
||
|
let SOURCE_DIR, PLATFORM, ARCH, STDLIB, NODE, HELP;
|
||
|
|
||
|
for (let i = 0; i < process.argv.length; i++) {
|
||
|
const arg = process.argv[i];
|
||
|
if (arg.startsWith('--target_dir_path=')) {
|
||
|
SOURCE_DIR = arg.split('=')[1];
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (arg.startsWith('--target_platform=')) {
|
||
|
PLATFORM = arg.split('=')[1];
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (arg.startsWith('--target_arch=')) {
|
||
|
ARCH = arg.split('=')[1];
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (arg.startsWith('--target_stdlib=')) {
|
||
|
STDLIB = arg.split('=')[1];
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (arg.startsWith('--target_node=')) {
|
||
|
NODE = arg.split('=')[1];
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (arg === '--help' || arg === '-h') {
|
||
|
HELP = true;
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (HELP) {
|
||
|
console.log(
|
||
|
`\nSentry: Prune profiler binaries\n
|
||
|
Usage: sentry-prune-profiler-binaries --target_dir_path=... --target_platform=... --target_arch=... --target_stdlib=...\n
|
||
|
Arguments:\n
|
||
|
--target_dir_path: Path to the directory containing the final bundled code. If you are using webpack, this would be the equivalent of output.path option.\n
|
||
|
--target_node: The major node version the code will be running on. Example: 16, 18, 20...\n
|
||
|
--target_platform: The platform the code will be running on. Example: linux, darwin, win32\n
|
||
|
--target_arch: The architecture the code will be running on. Example: x64, arm64\n
|
||
|
--target_stdlib: The standard library the code will be running on. Example: glibc, musl\n
|
||
|
--dry-run: Do not delete any files, just print the files that would be deleted.\n
|
||
|
--help: Print this help message.\n`,
|
||
|
);
|
||
|
process.exit(0);
|
||
|
}
|
||
|
|
||
|
const ARGV_ERRORS = [];
|
||
|
|
||
|
const NODE_TO_ABI = {
|
||
|
16: '93',
|
||
|
18: '108',
|
||
|
20: '115',
|
||
|
};
|
||
|
|
||
|
if (NODE) {
|
||
|
if (NODE_TO_ABI[NODE]) {
|
||
|
NODE = NODE_TO_ABI[NODE];
|
||
|
} else if (NODE.startsWith('16')) {
|
||
|
NODE = NODE_TO_ABI['16'];
|
||
|
} else if (NODE.startsWith('18')) {
|
||
|
NODE = NODE_TO_ABI['18'];
|
||
|
} else if (NODE.startsWith('20')) {
|
||
|
NODE = NODE_TO_ABI['20'];
|
||
|
} else {
|
||
|
ARGV_ERRORS.push(
|
||
|
'❌ Sentry: Invalid node version passed as argument, please make sure --target_node is a valid major node version. Supported versions are 16, 18 and 20.',
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!SOURCE_DIR) {
|
||
|
ARGV_ERRORS.push(
|
||
|
'❌ Sentry: Missing target_dir_path argument. target_dir_path should point to the directory containing the final bundled code. If you are using webpack, this would be the equivalent of output.path option.',
|
||
|
);
|
||
|
}
|
||
|
|
||
|
if (!PLATFORM && !ARCH && !STDLIB) {
|
||
|
ARGV_ERRORS.push(
|
||
|
`❌ Sentry: Missing argument values, pruning requires either --target_platform, --target_arch or --targer_stdlib to be passed as argument values.\n Example: sentry-prune-profiler-binaries --target_platform=linux --target_arch=x64 --target_stdlib=glibc\n
|
||
|
If you are unsure about the execution environment, you can opt to skip some values, but at least one value must be passed.`,
|
||
|
);
|
||
|
}
|
||
|
|
||
|
if (ARGV_ERRORS.length > 0) {
|
||
|
console.log(ARGV_ERRORS.join('\n'));
|
||
|
process.exit(1);
|
||
|
}
|
||
|
|
||
|
const SENTRY__PROFILER_BIN_REGEXP = /sentry_cpu_profiler-.*\.node$/;
|
||
|
|
||
|
async function findSentryProfilerBinaries(source_dir) {
|
||
|
const binaries = new Set();
|
||
|
const queue = [source_dir];
|
||
|
|
||
|
while (queue.length > 0) {
|
||
|
const dir = queue.pop();
|
||
|
|
||
|
for (const file of fs.readdirSync(dir)) {
|
||
|
if (SENTRY__PROFILER_BIN_REGEXP.test(file)) {
|
||
|
binaries.add(`${dir}/${file}`);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (fs.statSync(`${dir}/${file}`).isDirectory()) {
|
||
|
if (file === 'node_modules') {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
queue.push(`${dir}/${file}`);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return binaries;
|
||
|
}
|
||
|
|
||
|
function bytesToHumanReadable(bytes) {
|
||
|
if (bytes < 1024) {
|
||
|
return `${bytes} Bytes`;
|
||
|
} else if (bytes < 1048576) {
|
||
|
return `${(bytes / 1024).toFixed(2)} KiB`;
|
||
|
} else {
|
||
|
return `${(bytes / 1048576).toFixed(2)} MiB`;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async function prune(binaries) {
|
||
|
let bytesSaved = 0;
|
||
|
let removedBinariesCount = 0;
|
||
|
|
||
|
const conditions = [PLATFORM, ARCH, STDLIB, NODE].filter(n => !!n);
|
||
|
|
||
|
for (const binary of binaries) {
|
||
|
if (conditions.every(condition => binary.includes(condition))) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
const stats = fs.statSync(binary);
|
||
|
bytesSaved += stats.size;
|
||
|
removedBinariesCount++;
|
||
|
|
||
|
if (process.argv.includes('--dry-run')) {
|
||
|
console.log(`Sentry: would have pruned ${binary} (${bytesToHumanReadable(stats.size)})`);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
console.log(`Sentry: pruned ${binary} (${bytesToHumanReadable(stats.size)})`);
|
||
|
fs.unlinkSync(binary);
|
||
|
}
|
||
|
|
||
|
if (removedBinariesCount === 0) {
|
||
|
console.log(
|
||
|
'❌ Sentry: no binaries pruned, please make sure target argument values are valid or use --help for more information.',
|
||
|
);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (process.argv.includes('--dry-run')) {
|
||
|
console.log(
|
||
|
`✅ Sentry: would have pruned ${removedBinariesCount} ${
|
||
|
removedBinariesCount === 1 ? 'binary' : 'binaries'
|
||
|
} and saved ${bytesToHumanReadable(bytesSaved)}.`,
|
||
|
);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
console.log(
|
||
|
`✅ Sentry: pruned ${removedBinariesCount} ${
|
||
|
removedBinariesCount === 1 ? 'binary' : 'binaries'
|
||
|
}, saved ${bytesToHumanReadable(bytesSaved)} in total.`,
|
||
|
);
|
||
|
}
|
||
|
|
||
|
(async () => {
|
||
|
const binaries = await findSentryProfilerBinaries(SOURCE_DIR);
|
||
|
await prune(binaries);
|
||
|
})();
|