| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 | 'use strict';const os = require('os');const onExit = require('signal-exit');const DEFAULT_FORCE_KILL_TIMEOUT = 1000 * 5;// Monkey-patches `childProcess.kill()` to add `forceKillAfterTimeout` behaviorconst spawnedKill = (kill, signal = 'SIGTERM', options = {}) => {	const killResult = kill(signal);	setKillTimeout(kill, signal, options, killResult);	return killResult;};const setKillTimeout = (kill, signal, options, killResult) => {	if (!shouldForceKill(signal, options, killResult)) {		return;	}	const timeout = getForceKillAfterTimeout(options);	const t = setTimeout(() => {		kill('SIGKILL');	}, timeout);	// Guarded because there's no `.unref()` when `execa` is used in the renderer	// process in Electron. This cannot be tested since we don't run tests in	// Electron.	// istanbul ignore else	if (t.unref) {		t.unref();	}};const shouldForceKill = (signal, {forceKillAfterTimeout}, killResult) => {	return isSigterm(signal) && forceKillAfterTimeout !== false && killResult;};const isSigterm = signal => {	return signal === os.constants.signals.SIGTERM ||		(typeof signal === 'string' && signal.toUpperCase() === 'SIGTERM');};const getForceKillAfterTimeout = ({forceKillAfterTimeout = true}) => {	if (forceKillAfterTimeout === true) {		return DEFAULT_FORCE_KILL_TIMEOUT;	}	if (!Number.isFinite(forceKillAfterTimeout) || forceKillAfterTimeout < 0) {		throw new TypeError(`Expected the \`forceKillAfterTimeout\` option to be a non-negative integer, got \`${forceKillAfterTimeout}\` (${typeof forceKillAfterTimeout})`);	}	return forceKillAfterTimeout;};// `childProcess.cancel()`const spawnedCancel = (spawned, context) => {	const killResult = spawned.kill();	if (killResult) {		context.isCanceled = true;	}};const timeoutKill = (spawned, signal, reject) => {	spawned.kill(signal);	reject(Object.assign(new Error('Timed out'), {timedOut: true, signal}));};// `timeout` option handlingconst setupTimeout = (spawned, {timeout, killSignal = 'SIGTERM'}, spawnedPromise) => {	if (timeout === 0 || timeout === undefined) {		return spawnedPromise;	}	let timeoutId;	const timeoutPromise = new Promise((resolve, reject) => {		timeoutId = setTimeout(() => {			timeoutKill(spawned, killSignal, reject);		}, timeout);	});	const safeSpawnedPromise = spawnedPromise.finally(() => {		clearTimeout(timeoutId);	});	return Promise.race([timeoutPromise, safeSpawnedPromise]);};const validateTimeout = ({timeout}) => {	if (timeout !== undefined && (!Number.isFinite(timeout) || timeout < 0)) {		throw new TypeError(`Expected the \`timeout\` option to be a non-negative integer, got \`${timeout}\` (${typeof timeout})`);	}};// `cleanup` option handlingconst setExitHandler = async (spawned, {cleanup, detached}, timedPromise) => {	if (!cleanup || detached) {		return timedPromise;	}	const removeExitHandler = onExit(() => {		spawned.kill();	});	return timedPromise.finally(() => {		removeExitHandler();	});};module.exports = {	spawnedKill,	spawnedCancel,	setupTimeout,	validateTimeout,	setExitHandler};
 |