* Helper to run a shell command via /bin/sh -c and collect stdout/stderr/exitCode. * Since the new Kaos.exec(...args) doesn't take options, timeout is implemented * by killing the process after the given duration.
(
kaos: Kaos,
command: string,
options?: { timeout?: number; stdinData?: string },
)
| 14 | * by killing the process after the given duration. |
| 15 | */ |
| 16 | async function runSh( |
| 17 | kaos: Kaos, |
| 18 | command: string, |
| 19 | options?: { timeout?: number; stdinData?: string }, |
| 20 | ): Promise<{ stdout: string; stderr: string; exitCode: number }> { |
| 21 | const proc: KaosProcess = await kaos.exec('/bin/sh', '-c', command); |
| 22 | |
| 23 | // Set up timeout if requested |
| 24 | let timedOut = false; |
| 25 | let timer: ReturnType<typeof setTimeout> | undefined; |
| 26 | if (options?.timeout !== undefined) { |
| 27 | timer = setTimeout(() => { |
| 28 | timedOut = true; |
| 29 | void proc.kill('SIGKILL'); |
| 30 | }, options.timeout); |
| 31 | } |
| 32 | |
| 33 | // If stdinData is provided, write it and close stdin |
| 34 | if (options?.stdinData !== undefined) { |
| 35 | proc.stdin.write(options.stdinData); |
| 36 | proc.stdin.end(); |
| 37 | } else { |
| 38 | proc.stdin.end(); |
| 39 | } |
| 40 | |
| 41 | // Collect stdout and stderr concurrently with waiting for process exit |
| 42 | const stdoutChunks: Buffer[] = []; |
| 43 | const stderrChunks: Buffer[] = []; |
| 44 | |
| 45 | const stdoutDone = new Promise<void>((resolve) => { |
| 46 | proc.stdout.on('data', (chunk: Buffer) => { |
| 47 | stdoutChunks.push(chunk); |
| 48 | }); |
| 49 | proc.stdout.on('end', () => { |
| 50 | resolve(); |
| 51 | }); |
| 52 | }); |
| 53 | |
| 54 | const stderrDone = new Promise<void>((resolve) => { |
| 55 | proc.stderr.on('data', (chunk: Buffer) => { |
| 56 | stderrChunks.push(chunk); |
| 57 | }); |
| 58 | proc.stderr.on('end', () => { |
| 59 | resolve(); |
| 60 | }); |
| 61 | }); |
| 62 | |
| 63 | const exitCode = await proc.wait(); |
| 64 | await stdoutDone; |
| 65 | await stderrDone; |
| 66 | |
| 67 | if (timer !== undefined) { |
| 68 | clearTimeout(timer); |
| 69 | } |
| 70 | |
| 71 | return { |
| 72 | stdout: Buffer.concat(stdoutChunks).toString('utf-8'), |
| 73 | stderr: Buffer.concat(stderrChunks).toString('utf-8'), |