cx-protofetch
Version:
A source dependency management tool for Protobuf.
98 lines (80 loc) • 3.12 kB
JavaScript
import { mkdirSync, chmodSync, existsSync, readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
import { pipeline } from 'node:stream/promises';
import * as tar from 'tar';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
function isPlatform(platform, arch) {
return process.platform === platform && process.arch === arch;
}
function getPlatform() {
if (isPlatform('win32', 'x64')) return 'x86_64-pc-windows-msvc';
if (isPlatform('linux', 'x64')) return 'x86_64-unknown-linux-musl';
if (isPlatform('linux', 'arm64')) return 'aarch64-unknown-linux-musl';
if (isPlatform('darwin', 'x64')) return 'x86_64-apple-darwin';
if (isPlatform('darwin', 'arm64')) return 'aarch64-apple-darwin';
throw new Error(`Unsupported platform: ${process.platform} ${process.arch}. Please create an issue at https://github.com/coralogix/protofetch/issues`);
}
function getVersion() {
const packageJsonPath = join(__dirname, 'package.json');
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
return packageJson.version;
}
async function downloadBinary(options = {}) {
const platform = getPlatform();
const version = getVersion();
// Support custom URL for testing (not exposed via postinstall, only via direct script call)
const url = options.url || `https://github.com/coralogix/protofetch/releases/download/v${version}/protofetch_${platform}.tar.gz`;
const binDir = join(__dirname, 'bin');
const isWindows = process.platform === 'win32';
const binaryName = isWindows ? 'protofetch.exe' : 'protofetch';
const binaryPath = join(binDir, binaryName);
if (!existsSync(binDir)) {
mkdirSync(binDir, { recursive: true });
}
console.log(`Downloading protofetch binary from ${url}...`);
let lastError;
for (let attempt = 1; attempt <= 3; attempt++) {
try {
const response = await fetch(url, {
redirect: 'follow'
});
if (!response.ok) {
throw new Error(`Failed to download binary (HTTP ${response.status}): ${response.statusText}`);
}
await pipeline(
response.body,
tar.extract({
cwd: binDir,
strip: 1,
strict: true,
preservePaths: false,
preserveOwner: false,
filter: (path, entry) => {
const allowedFiles = ['protofetch', 'protofetch.exe'];
const fileName = path.split('/').pop();
return entry.type === 'File' && allowedFiles.includes(fileName);
}
})
);
if (!isWindows && existsSync(binaryPath)) {
chmodSync(binaryPath, 0o755);
}
if (existsSync(binaryPath)) {
console.log('protofetch binary installed successfully');
return;
} else {
throw new Error(`Binary extraction failed - ${binaryName} not found after extraction`);
}
} catch (error) {
lastError = error;
if (attempt < 3) {
console.log(`Download attempt ${attempt} failed, retrying...`);
await new Promise(resolve => setTimeout(resolve, attempt * 1000));
}
}
}
throw new Error(`Failed to download protofetch after 3 attempts: ${lastError.message}`);
}
export { downloadBinary };