mirror of
https://github.com/cypress-io/cypress.git
synced 2026-03-20 19:32:16 -05:00
95 lines
2.0 KiB
TypeScript
95 lines
2.0 KiB
TypeScript
import type { ChildProcess } from 'child_process'
|
|
import pDefer from 'p-defer'
|
|
import treeKill from 'tree-kill'
|
|
import gulp from 'gulp'
|
|
|
|
const childProcesses = new Set<ChildProcess>()
|
|
const exitedPids = new Set<number>()
|
|
|
|
let hasExited = false
|
|
|
|
export function addChildProcess (child: ChildProcess) {
|
|
if (hasExited) {
|
|
treeKill(child.pid)
|
|
|
|
return
|
|
}
|
|
|
|
childProcesses.add(child)
|
|
child.on('exit', () => {
|
|
if (!hasExited) {
|
|
exitAndRemoveProcess(child)
|
|
}
|
|
})
|
|
}
|
|
|
|
export async function exitAndRemoveProcess (child: ChildProcess) {
|
|
if (exitedPids.has(child.pid)) {
|
|
return
|
|
}
|
|
|
|
if (!childProcesses.has(child)) {
|
|
throw new Error(`Cannot remove child process ${child.pid}, it was never registered`)
|
|
}
|
|
|
|
childProcesses.delete(child)
|
|
|
|
const dfd = pDefer()
|
|
|
|
exitedPids.add(child.pid)
|
|
treeKill(child.pid, (err) => {
|
|
if (err) {
|
|
console.error(err)
|
|
}
|
|
|
|
dfd.resolve()
|
|
})
|
|
|
|
return dfd.promise
|
|
}
|
|
|
|
export async function exitAllProcesses () {
|
|
await Promise.all(Array.from(childProcesses).map(exitAndRemoveProcess))
|
|
}
|
|
|
|
process.stdin.resume() //so the program will not close instantly
|
|
|
|
const _task = gulp.task
|
|
|
|
// So that we auto-exit on single tasks
|
|
// @ts-expect-error
|
|
gulp.task = function () {
|
|
if (arguments.length === 1 && typeof arguments[0] === 'function') {
|
|
process.stdin.pause()
|
|
}
|
|
|
|
// @ts-ignore
|
|
return _task.apply(this, arguments)
|
|
}
|
|
|
|
export async function exitAfterAll () {
|
|
process.stdin.pause()
|
|
}
|
|
|
|
function exitHandler (msg: string) {
|
|
return async function _exitHandler (exitCode: number) {
|
|
hasExited = true
|
|
console.log(`Exiting due to ${msg} => code ${exitCode}`)
|
|
await exitAllProcesses()
|
|
process.exit(exitCode)
|
|
}
|
|
}
|
|
|
|
// do something when app is closing
|
|
process.on('exit', exitHandler('exit'))
|
|
|
|
// catches ctrl+c event
|
|
process.on('SIGINT', exitHandler('SIGINT'))
|
|
|
|
// catches "kill pid" (for example: nodemon restart)
|
|
process.on('SIGUSR1', exitHandler('SIGUSR1'))
|
|
process.on('SIGUSR2', exitHandler('SIGUSR2'))
|
|
|
|
// catches uncaught exceptions
|
|
process.on('uncaughtException', exitHandler('uncaughtException'))
|