(
cmd: string,
args: string[],
opts: { cwd?: string; input?: string; quiet?: boolean } = {}
)
| 131 | * Run a command, streaming its output to stderr while capturing it for parsing. |
| 132 | */ |
| 133 | export function run( |
| 134 | cmd: string, |
| 135 | args: string[], |
| 136 | opts: { cwd?: string; input?: string; quiet?: boolean } = {} |
| 137 | ): Promise<RunResult> { |
| 138 | return new Promise((resolve, reject) => { |
| 139 | const child = spawn(cmd, args, { |
| 140 | cwd: opts.cwd, |
| 141 | stdio: [opts.input !== undefined ? 'pipe' : 'ignore', 'pipe', 'pipe'], |
| 142 | }); |
| 143 | |
| 144 | let stdout = ''; |
| 145 | let stderr = ''; |
| 146 | |
| 147 | child.stdout?.on('data', (chunk: Buffer) => { |
| 148 | const text = chunk.toString(); |
| 149 | stdout += text; |
| 150 | if (!opts.quiet) { |
| 151 | process.stderr.write(text); |
| 152 | } |
| 153 | }); |
| 154 | child.stderr?.on('data', (chunk: Buffer) => { |
| 155 | const text = chunk.toString(); |
| 156 | stderr += text; |
| 157 | if (!opts.quiet) { |
| 158 | process.stderr.write(text); |
| 159 | } |
| 160 | }); |
| 161 | |
| 162 | child.on('error', (err: NodeJS.ErrnoException) => { |
| 163 | if (err.code === 'ENOENT') { |
| 164 | reject( |
| 165 | new Error( |
| 166 | `Command not found: \`${cmd}\`. Ensure \`${cmd}\` is installed and on your PATH.` |
| 167 | ) |
| 168 | ); |
| 169 | return; |
| 170 | } |
| 171 | reject(err); |
| 172 | }); |
| 173 | child.on('close', code => { |
| 174 | if (code === 0) { |
| 175 | resolve({ stdout, stderr }); |
| 176 | } else { |
| 177 | const detail = stderr.trim().split('\n').slice(-5).join('\n'); |
| 178 | reject( |
| 179 | new Error( |
| 180 | `\`${cmd} ${args.join(' ')}\` exited with code ${code}` + |
| 181 | (detail ? `\n${detail}` : '') |
| 182 | ) |
| 183 | ); |
| 184 | } |
| 185 | }); |
| 186 | |
| 187 | if (opts.input !== undefined) { |
| 188 | child.stdin?.end(opts.input); |
| 189 | } |
| 190 | }); |
no test coverage detected