mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-11-01 03:12:37 +08:00
88 lines
3.4 KiB
JavaScript
88 lines
3.4 KiB
JavaScript
#!/usr/bin/env node
|
|
'use strict';
|
|
|
|
const fs = require('node:fs');
|
|
const path = require('node:path');
|
|
const { spawn } = require('node:child_process');
|
|
const platforms = require('./platforms.json');
|
|
const { name: launcherPackage, version } = require('../package.json');
|
|
|
|
function main() {
|
|
const target = `${process.platform}-${process.arch}`;
|
|
const platform = platforms[target];
|
|
if (!platform) {
|
|
throw new Error(`No crossdesk-cli build for ${target}. Supported targets: ${Object.keys(platforms).join(', ')}.`);
|
|
}
|
|
if (process.platform === 'linux' && !process.report.getReport().header.glibcVersionRuntime) {
|
|
throw new Error('This release requires glibc Linux. Alpine/musl needs a separate native build.');
|
|
}
|
|
const packageName = platform.packageName;
|
|
let manifestPath;
|
|
try {
|
|
manifestPath = require.resolve(`${packageName}/package.json`);
|
|
} catch {
|
|
throw new Error(`Missing ${packageName}@${version}. Install with optional dependencies enabled; this platform's package must be published before ${launcherPackage}.`);
|
|
}
|
|
if (require(manifestPath).version !== version) {
|
|
throw new Error(`Expected ${packageName}@${version}; reinstall matching package versions.`);
|
|
}
|
|
const binary = path.join(path.dirname(manifestPath), 'bin', process.platform === 'win32' ? 'crossdesk-cli.exe' : 'crossdesk-cli');
|
|
fs.accessSync(binary, process.platform === 'win32' ? fs.constants.F_OK : fs.constants.X_OK);
|
|
const args = process.argv.slice(2);
|
|
// Hosts such as Pi should spawn the native path directly, retaining descriptor
|
|
// inheritance and control of the process lifetime without an npm intermediary.
|
|
if (args.length === 1 && args[0] === '--print-binary-path') {
|
|
process.stdout.write(`${binary}\n`);
|
|
return;
|
|
}
|
|
const stdio = ['inherit', 'inherit', 'inherit'];
|
|
if (args[0] === 'bridge') {
|
|
const index = args.lastIndexOf('--password-fd');
|
|
const fd = index === -1 ? 3 : Number(args[index + 1]);
|
|
if (Number.isInteger(fd) && fd >= 3 && fd <= 1024) {
|
|
try {
|
|
const stat = fs.fstatSync(fd);
|
|
if (stat.isFIFO() || stat.isSocket() || stat.isFile()) {
|
|
while (stdio.length <= fd) stdio.push('ignore');
|
|
stdio[fd] = fd;
|
|
}
|
|
} catch { /* The native bridge reports a missing credential descriptor. */ }
|
|
}
|
|
}
|
|
const child = spawn(binary, args, { stdio, shell: false });
|
|
const handlers = new Map();
|
|
if (process.platform !== 'win32') {
|
|
for (const signal of ['SIGINT', 'SIGTERM', 'SIGHUP']) {
|
|
const handler = () => { if (child.exitCode === null) child.kill(signal); };
|
|
handlers.set(signal, handler);
|
|
process.on(signal, handler);
|
|
}
|
|
} else {
|
|
// Console Ctrl+C is delivered to both processes. Do not terminate the native
|
|
// child before it has restored console modes.
|
|
const handler = () => {};
|
|
handlers.set('SIGINT', handler);
|
|
process.on('SIGINT', handler);
|
|
}
|
|
const cleanup = () => {
|
|
for (const [signal, handler] of handlers) process.removeListener(signal, handler);
|
|
};
|
|
child.once('error', (error) => {
|
|
cleanup();
|
|
process.stderr.write(`crossdesk-cli: cannot start native program (${error.code || 'unknown error'}).\n`);
|
|
process.exitCode = 1;
|
|
});
|
|
child.once('exit', (code, signal) => {
|
|
cleanup();
|
|
if (signal && process.platform !== 'win32') process.kill(process.pid, signal);
|
|
else process.exitCode = code ?? 1;
|
|
});
|
|
}
|
|
|
|
try {
|
|
main();
|
|
} catch (error) {
|
|
process.stderr.write(`crossdesk-cli: ${error.message}\n`);
|
|
process.exitCode = 1;
|
|
}
|