1 | import {
|
2 | ChildProcess,
|
3 | spawn as cpSpawn,
|
4 | SpawnOptions as cpSpawnOptions,
|
5 | } from 'child_process';
|
6 |
|
7 | import invariant from 'invariant';
|
8 |
|
9 |
|
10 |
|
11 |
|
12 | export function spawn(
|
13 | cmd: string,
|
14 | args: string[] = [],
|
15 | options?: spawn.Options,
|
16 | ): Promise<void> {
|
17 | return new Promise((resolve, reject) => {
|
18 | invariant(cmd, '"cmd" is required');
|
19 | invariant(Array.isArray(args), '"args" is required and must be an Array');
|
20 |
|
21 | const opts = {
|
22 | detached: false,
|
23 | stdio: 'inherit',
|
24 | ...options,
|
25 | };
|
26 | const child = cpSpawn(cmd, args, opts);
|
27 |
|
28 | let data = '';
|
29 | if (child.stderr) {
|
30 | child.stderr.on('data', d => {
|
31 | data += d;
|
32 | });
|
33 | }
|
34 |
|
35 | child.on('close', code => {
|
36 | if (code) {
|
37 | const e = new spawn.ExitError(`${cmd} exited with code "${code}"`);
|
38 | e.code = code;
|
39 | e.data = data;
|
40 |
|
41 | return reject(e);
|
42 | }
|
43 |
|
44 | return resolve();
|
45 | });
|
46 |
|
47 | if (options && options.detached) {
|
48 | child.unref();
|
49 |
|
50 | options.child = child;
|
51 | }
|
52 | });
|
53 | }
|
54 |
|
55 | export namespace spawn {
|
56 | |
57 |
|
58 |
|
59 | export interface Options extends cpSpawnOptions {
|
60 | |
61 |
|
62 |
|
63 | detached?: boolean;
|
64 | |
65 |
|
66 |
|
67 |
|
68 | child?: ChildProcess;
|
69 | }
|
70 |
|
71 | |
72 |
|
73 |
|
74 | export class ExitError extends Error {
|
75 | |
76 |
|
77 |
|
78 | code: number = 0;
|
79 |
|
80 | |
81 |
|
82 |
|
83 | data: string = '';
|
84 | }
|
85 | }
|