-
Notifications
You must be signed in to change notification settings - Fork 9
Open
Labels
enhancementNew feature or requestNew feature or requestgood-first-issueGood for newcomersGood for newcomers
Description
The Viper IDE took its spawn function from this repository. In the process, they did some nice changes, among with a check of the exist code of the spawned process: viperproject/viper-ide#357. We should port the same check to this repository.
Relevant code:
Lines 95 to 188 in 694dc6c
| export function spawn( | |
| cmd: string, | |
| args?: string[] | undefined, | |
| { options, onStdout, onStderr }: { | |
| options?: childProcess.SpawnOptionsWithoutStdio; | |
| onStdout?: ((data: string) => void); | |
| onStderr?: ((data: string) => void); | |
| } = {}, | |
| destructors?: Set<KillFunction>, | |
| ): Promise<Output> { | |
| const description = `${cmd} ${args?.join(" ") ?? ""}`; | |
| log(`Run command '${description}'`); | |
| let stdout = ""; | |
| let stderr = ""; | |
| const start = process.hrtime(); | |
| const proc = childProcess.spawn(cmd, args, options); | |
| const status: { killed: boolean } = { killed: false }; | |
| log(`Spawned PID: ${proc.pid}`); | |
| // Register destructor | |
| function killProc() { | |
| if (!status.killed) { | |
| status.killed = true; | |
| // TODO: Try with SIGTERM before. | |
| treeKill(proc.pid, "SIGKILL", (err) => { | |
| if (err) { | |
| log(`Failed to kill process tree of ${proc.pid}: ${err}`); | |
| const succeeded = proc.kill("SIGKILL"); | |
| if (!succeeded) { | |
| log(`Failed to kill process ${proc}.`); | |
| } | |
| } else { | |
| log(`Process ${proc.pid} has been killed successfully.`); | |
| } | |
| }); | |
| } else { | |
| log(`Process ${proc.pid} has already been killed.`); | |
| } | |
| } | |
| if (destructors) { | |
| destructors.add(killProc); | |
| } | |
| proc.stdout.on("data", (data) => { | |
| stdout += data; | |
| try { | |
| onStdout?.(data); | |
| } catch (e) { | |
| log(`error in stdout handler for '${description}': ${e}`); | |
| } | |
| }); | |
| proc.stderr.on("data", (data) => { | |
| stderr += data; | |
| try { | |
| onStderr?.(data); | |
| } catch (e) { | |
| log(`error in stderr handler for '${description}': ${e}`); | |
| } | |
| }); | |
| function printOutput(duration: Duration, code: number | null, signal: NodeJS.Signals | null) { | |
| const durationSecMsg = (duration[0] + duration[1] / 1e9).toFixed(1); | |
| log(`Output from '${description}' (${durationSecMsg}s):`); | |
| log("┌──── Begin stdout ────┐"); | |
| log(stdout); | |
| log("└──── End stdout ──────┘"); | |
| log("┌──── Begin stderr ────┐"); | |
| log(stderr); | |
| log("└──── End stderr ──────┘"); | |
| log(`Exit code ${code}, signal ${signal}.`); | |
| } | |
| return new Promise((resolve, reject) => { | |
| proc.on("close", (code, signal) => { | |
| const duration = process.hrtime(start); | |
| printOutput(duration, code, signal); | |
| if (destructors) { | |
| destructors.delete(killProc); | |
| } | |
| resolve({ stdout, stderr, code, signal, duration }); | |
| }); | |
| proc.on("error", (err) => { | |
| const duration = process.hrtime(start); | |
| printOutput(duration, null, null); | |
| log(`Error: ${err}`); | |
| if (destructors) { | |
| destructors.delete(killProc); | |
| } | |
| reject(err); | |
| }); | |
| }); | |
| } |
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or requestgood-first-issueGood for newcomersGood for newcomers