You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

154 lines
4.9 KiB
JavaScript

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.foregroundChild = exports.normalizeFgArgs = void 0;
const child_process_1 = require("child_process");
const cross_spawn_1 = __importDefault(require("cross-spawn"));
const signal_exit_1 = require("signal-exit");
const all_signals_js_1 = require("./all-signals.js");
const watchdog_js_1 = require("./watchdog.js");
/* c8 ignore start */
const spawn = process?.platform === 'win32' ? cross_spawn_1.default : child_process_1.spawn;
/**
* Normalizes the arguments passed to `foregroundChild`.
*
* Exposed for testing.
*
* @internal
*/
const normalizeFgArgs = (fgArgs) => {
let [program, args = [], spawnOpts = {}, cleanup = () => { }] = fgArgs;
if (typeof args === 'function') {
cleanup = args;
spawnOpts = {};
args = [];
}
else if (!!args && typeof args === 'object' && !Array.isArray(args)) {
if (typeof spawnOpts === 'function')
cleanup = spawnOpts;
spawnOpts = args;
args = [];
}
else if (typeof spawnOpts === 'function') {
cleanup = spawnOpts;
spawnOpts = {};
}
if (Array.isArray(program)) {
const [pp, ...pa] = program;
program = pp;
args = pa;
}
return [program, args, { ...spawnOpts }, cleanup];
};
exports.normalizeFgArgs = normalizeFgArgs;
function foregroundChild(...fgArgs) {
const [program, args, spawnOpts, cleanup] = (0, exports.normalizeFgArgs)(fgArgs);
spawnOpts.stdio = [0, 1, 2];
if (process.send) {
spawnOpts.stdio.push('ipc');
}
const child = spawn(program, args, spawnOpts);
const unproxySignals = proxySignals(child);
const childHangup = () => {
try {
child.kill('SIGHUP');
/* c8 ignore start */
}
catch (_) {
// SIGHUP is weird on windows
child.kill('SIGTERM');
}
/* c8 ignore stop */
};
const removeOnExit = (0, signal_exit_1.onExit)(childHangup);
const dog = (0, watchdog_js_1.watchdog)(child);
let done = false;
child.on('close', async (code, signal) => {
dog.kill('SIGKILL');
/* c8 ignore start */
if (done) {
return;
}
/* c8 ignore stop */
done = true;
const result = cleanup(code, signal);
const res = isPromise(result) ? await result : result;
removeOnExit();
unproxySignals();
if (res === false)
return;
else if (typeof res === 'string') {
signal = res;
code = null;
}
else if (typeof res === 'number') {
code = res;
signal = null;
}
if (signal) {
// If there is nothing else keeping the event loop alive,
// then there's a race between a graceful exit and getting
// the signal to this process. Put this timeout here to
// make sure we're still alive to get the signal, and thus
// exit with the intended signal code.
/* istanbul ignore next */
setTimeout(() => { }, 2000);
try {
process.kill(process.pid, signal);
/* c8 ignore start */
}
catch (_) {
process.kill(process.pid, 'SIGTERM');
}
/* c8 ignore stop */
}
else {
process.exit(code || 0);
}
});
if (process.send) {
process.removeAllListeners('message');
child.on('message', (message, sendHandle) => {
process.send?.(message, sendHandle);
});
process.on('message', (message, sendHandle) => {
child.send(message, sendHandle);
});
}
return child;
}
exports.foregroundChild = foregroundChild;
/**
* Starts forwarding signals to `child` through `parent`.
*/
const proxySignals = (child) => {
const listeners = new Map();
for (const sig of all_signals_js_1.allSignals) {
const listener = () => {
// some signals can only be received, not sent
try {
child.kill(sig);
/* c8 ignore start */
}
catch (_) { }
/* c8 ignore stop */
};
try {
// if it's a signal this system doesn't recognize, skip it
process.on(sig, listener);
listeners.set(sig, listener);
/* c8 ignore start */
}
catch (_) { }
/* c8 ignore stop */
}
return () => {
for (const [sig, listener] of listeners) {
process.removeListener(sig, listener);
}
};
};
const isPromise = (o) => !!o && typeof o === 'object' && typeof o.then === 'function';
//# sourceMappingURL=index.js.map