Files
Firelink/scripts/tauri-command.js
T
NimBold 1d629873b5 fix(deps): refresh packages and harden engine staging
- update npm, Cargo, Deno, and FFmpeg lockfiles
- refresh verified cross-platform engine payload metadata
- serialize staging, verification, and Tauri packaging across concurrent runs
- recover interrupted lock records and cover crash and ownership races
2026-08-30 10:22:38 +03:30

107 lines
3.3 KiB
JavaScript

#!/usr/bin/env node
import path from 'node:path';
import { spawn } from 'node:child_process';
import { fileURLToPath } from 'node:url';
import {
acquireExclusiveFileLock,
readExclusiveFileLockOwner,
} from './engine-staging-lock.js';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const repoRoot = path.resolve(__dirname, '..');
const tauriCli = path.join(repoRoot, 'node_modules', '@tauri-apps', 'cli', 'tauri.js');
const stagingLockPath = path.join(repoRoot, 'src-tauri', 'engine-dist.lock');
const ENGINE_TREE_COMMANDS = new Set(['dev', 'build', 'bundle']);
export function commandUsesEngineTree(args) {
return args.some(argument => ENGINE_TREE_COMMANDS.has(argument));
}
function signalExitCode(signal) {
return {
SIGHUP: 129,
SIGINT: 130,
SIGTERM: 143,
}[signal] ?? 1;
}
const args = process.argv.slice(2);
const holdsEngineLock = commandUsesEngineTree(args);
let releaseEngineLock;
let child;
function handleSignal(signal) {
if (child && child.exitCode === null && child.signalCode === null) {
try {
child.kill(signal);
} catch (error) {
if (error?.code !== 'ESRCH') {
console.error(`[WARN] Could not terminate Tauri: ${error.message}`);
}
}
return;
}
// No child has started yet, so there is no packaging work to preserve. If
// lock acquisition was interrupted after ownership was granted, release it
// before exiting; otherwise exit promptly instead of waiting out the lock.
try {
releaseEngineLock?.();
} catch (error) {
console.error(`[WARN] Could not release the engine staging lock: ${error.message}`);
}
process.exit(signalExitCode(signal));
}
async function run() {
const handlers = new Map(['SIGHUP', 'SIGINT', 'SIGTERM'].map(signal => [
signal,
() => handleSignal(signal),
]));
for (const [signal, handler] of handlers) process.once(signal, handler);
try {
const env = { ...process.env };
if (holdsEngineLock) {
releaseEngineLock = await acquireExclusiveFileLock(stagingLockPath);
const owner = readExclusiveFileLockOwner(stagingLockPath);
// beforeBuildCommand and beforeDevCommand run as child processes. The
// wrapper keeps the lock until Tauri has finished consuming resources;
// nested staging/verifying must therefore use this held lease instead
// of trying to acquire the same path again.
env.FIRELINK_ENGINE_STAGING_LOCK_PID = String(owner.pid);
env.FIRELINK_ENGINE_STAGING_LOCK_TOKEN = owner.token;
}
child = spawn(process.execPath, [tauriCli, ...args], {
cwd: repoRoot,
env,
stdio: 'inherit',
windowsHide: true,
});
const result = await new Promise((resolve, reject) => {
child.once('error', reject);
child.once('close', (code, signal) => resolve({ code, signal }));
});
if (result.signal) {
process.exitCode = signalExitCode(result.signal);
} else {
process.exitCode = result.code ?? 1;
}
} finally {
for (const [signal, handler] of handlers) process.removeListener(signal, handler);
releaseEngineLock?.();
}
}
const isMain = process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url);
if (isMain) {
run().catch(error => {
console.error(`[FAIL] Tauri command failed: ${error.message}`);
process.exitCode = 1;
});
}