| 44 | } |
| 45 | |
| 46 | export function runProcess(logger: Logger, binPath: string, args: string[], workingDirectory: string | undefined, env: Record<string, string | undefined> | undefined, spawn: SpawnFunction, cancellationToken?: CancellationToken): Promise<RunProcessResult> { |
| 47 | return new Promise((resolve, reject) => { |
| 48 | logger.info(`Spawning ${binPath} with args ${JSON.stringify(args)} in ${workingDirectory} with env ${JSON.stringify(env)}`); |
| 49 | const proc = spawn(workingDirectory, binPath, args, env); |
| 50 | cancellationToken?.onCancellationRequested(() => proc.kill()); |
| 51 | logProcess(logger, LogCategory.CommandProcesses, proc); |
| 52 | |
| 53 | const out: string[] = []; |
| 54 | const err: string[] = []; |
| 55 | proc.stdout.on("data", (data: Buffer) => out.push(data.toString())); |
| 56 | proc.stderr.on("data", (data: Buffer) => err.push(data.toString())); |
| 57 | proc.on("exit", (code) => { |
| 58 | resolve(new RunProcessResult( |
| 59 | nullToUndefined(code) ?? 1 // null means terminated by signal |
| 60 | , out.join(""), |
| 61 | err.join(""), |
| 62 | )); |
| 63 | }); |
| 64 | // Handle things like ENOENT which are async and come via error, but mean exit will never fire. |
| 65 | proc.on("error", (e) => reject(e)); |
| 66 | }); |
| 67 | } |
| 68 | |
| 69 | type SpawnFunction = (workingDirectory: string | undefined, binPath: string, args: string[], env: Record<string, string | undefined> | undefined) => SpawnedProcess; |
| 70 | |