parcoursup/node_modules/foreground-child/index.js

134 lines
3.3 KiB
JavaScript
Raw Normal View History

2023-03-05 13:23:23 +01:00
const signalExit = require('signal-exit')
/* istanbul ignore next */
const spawn = process.platform === 'win32' ? require('cross-spawn') : require('child_process').spawn
/**
* Normalizes the arguments passed to `foregroundChild`.
*
* See the signature of `foregroundChild` for the supported arguments.
*
* @param fgArgs Array of arguments passed to `foregroundChild`.
* @return Normalized arguments
* @internal
*/
function normalizeFgArgs(fgArgs) {
let program, args, cb;
let processArgsEnd = fgArgs.length;
const lastFgArg = fgArgs[fgArgs.length - 1];
if (typeof lastFgArg === "function") {
cb = lastFgArg;
processArgsEnd -= 1;
} else {
cb = (done) => done();
}
if (Array.isArray(fgArgs[0])) {
[program, ...args] = fgArgs[0];
} else {
program = fgArgs[0];
args = Array.isArray(fgArgs[1]) ? fgArgs[1] : fgArgs.slice(1, processArgsEnd);
}
return {program, args, cb};
}
/**
*
* Signatures:
* ```
* (program: string | string[], cb?: CloseHandler);
* (program: string, args: string[], cb?: CloseHandler);
* (program: string, ...args: string[], cb?: CloseHandler);
* ```
*/
function foregroundChild (...fgArgs) {
const {program, args, cb} = normalizeFgArgs(fgArgs);
const spawnOpts = { stdio: [0, 1, 2] }
if (process.send) {
spawnOpts.stdio.push('ipc')
}
const child = spawn(program, args, spawnOpts)
const unproxySignals = proxySignals(process, child)
process.on('exit', childHangup)
function childHangup () {
child.kill('SIGHUP')
}
child.on('close', (code, signal) => {
// Allow the callback to inspect the childs exit code and/or modify it.
process.exitCode = signal ? 128 + signal : code
let done = false;
const doneCB = () => {
if (done) {
return
}
done = true
unproxySignals()
process.removeListener('exit', childHangup)
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(function () {}, 200)
process.kill(process.pid, signal)
} else {
process.exit(process.exitCode)
}
};
const result = cb(doneCB);
if (result && result.then) {
result.then(doneCB);
}
})
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
}
/**
* Starts forwarding signals to `child` through `parent`.
*
* @param parent Parent process.
* @param child Child Process.
* @return `unproxy` function to stop the forwarding.
* @internal
*/
function proxySignals (parent, child) {
const listeners = new Map()
for (const sig of signalExit.signals()) {
const listener = () => child.kill(sig)
listeners.set(sig, listener)
parent.on(sig, listener)
}
return function unproxySignals () {
for (const [sig, listener] of listeners) {
parent.removeListener(sig, listener)
}
}
}
module.exports = foregroundChild