1
1
import * as ansiColors from 'ansi-colors' ;
2
- import { SpawnOptions } from " child_process" ;
2
+ import { SpawnOptions } from ' child_process' ;
3
3
import * as child_process from 'child_process' ;
4
- import { concat , defer , EMPTY , from } from 'rxjs' ;
5
- import { repeat , takeLast } from 'rxjs/operators' ;
6
- import { getGlobalVariable } from './env' ;
7
- import { catchError } from 'rxjs/operators' ;
4
+ import { concat , defer , EMPTY , from } from 'rxjs' ;
5
+ import { repeat , takeLast } from 'rxjs/operators' ;
6
+ import { getGlobalVariable } from './env' ;
7
+ import { catchError } from 'rxjs/operators' ;
8
8
const treeKill = require ( 'tree-kill' ) ;
9
9
10
-
11
10
interface ExecOptions {
12
11
silent ?: boolean ;
13
12
waitForMatch ?: RegExp ;
14
13
env ?: { [ varname : string ] : string } ;
15
14
}
16
15
17
-
18
16
let _processes : child_process . ChildProcess [ ] = [ ] ;
19
17
20
18
export type ProcessOutput = {
21
19
stdout : string ;
22
20
stderr : string ;
23
21
} ;
24
22
25
-
26
- function _exec ( options : ExecOptions , cmd : string , args : string [ ] ) : Promise < ProcessOutput > {
23
+ function _exec ( options : ExecOptions , cmd : string , args : string [ ] ) : Promise < ProcessOutput > {
27
24
// Create a separate instance to prevent unintended global changes to the color configuration
28
25
// Create function is not defined in the typings. See: https://github.com/doowb/ansi-colors/pull/44
29
26
const colors = ( ansiColors as typeof ansiColors & { create : ( ) => typeof ansiColors } ) . create ( ) ;
@@ -33,24 +30,24 @@ function _exec(options: ExecOptions, cmd: string, args: string[]): Promise<Proc
33
30
const cwd = process . cwd ( ) ;
34
31
const env = options . env ;
35
32
console . log (
36
- `==========================================================================================`
33
+ `==========================================================================================` ,
37
34
) ;
38
35
39
- args = args . filter ( x => x !== undefined ) ;
36
+ args = args . filter ( ( x ) => x !== undefined ) ;
40
37
const flags = [
41
38
options . silent && 'silent' ,
42
- options . waitForMatch && `matching(${ options . waitForMatch } )`
39
+ options . waitForMatch && `matching(${ options . waitForMatch } )` ,
43
40
]
44
- . filter ( x => ! ! x ) // Remove false and undefined.
41
+ . filter ( ( x ) => ! ! x ) // Remove false and undefined.
45
42
. join ( ', ' )
46
- . replace ( / ^ ( .+ ) $ / , ' [$1]' ) ; // Proper formatting.
43
+ . replace ( / ^ ( .+ ) $ / , ' [$1]' ) ; // Proper formatting.
47
44
48
- console . log ( colors . blue ( `Running \`${ cmd } ${ args . map ( x => `"${ x } "` ) . join ( ' ' ) } \`${ flags } ...` ) ) ;
45
+ console . log ( colors . blue ( `Running \`${ cmd } ${ args . map ( ( x ) => `"${ x } "` ) . join ( ' ' ) } \`${ flags } ...` ) ) ;
49
46
console . log ( colors . blue ( `CWD: ${ cwd } ` ) ) ;
50
47
console . log ( colors . blue ( `ENV: ${ JSON . stringify ( env ) } ` ) ) ;
51
48
const spawnOptions : SpawnOptions = {
52
49
cwd,
53
- ...env ? { env } : { } ,
50
+ ...( env ? { env } : { } ) ,
54
51
} ;
55
52
56
53
if ( process . platform . startsWith ( 'win' ) ) {
@@ -65,56 +62,74 @@ function _exec(options: ExecOptions, cmd: string, args: string[]): Promise<Proc
65
62
if ( options . silent ) {
66
63
return ;
67
64
}
68
- data . toString ( 'utf-8' )
65
+ data
66
+ . toString ( 'utf-8' )
69
67
. split ( / [ \n \r ] + / )
70
- . filter ( line => line !== '' )
71
- . forEach ( line => console . log ( ' ' + line ) ) ;
68
+ . filter ( ( line ) => line !== '' )
69
+ . forEach ( ( line ) => console . log ( ' ' + line ) ) ;
72
70
} ) ;
73
71
childProcess . stderr . on ( 'data' , ( data : Buffer ) => {
74
72
stderr += data . toString ( 'utf-8' ) ;
75
73
if ( options . silent ) {
76
74
return ;
77
75
}
78
- data . toString ( 'utf-8' )
76
+ data
77
+ . toString ( 'utf-8' )
79
78
. split ( / [ \n \r ] + / )
80
- . filter ( line => line !== '' )
81
- . forEach ( line => console . error ( colors . yellow ( ' ' + line ) ) ) ;
79
+ . filter ( ( line ) => line !== '' )
80
+ . forEach ( ( line ) => console . error ( colors . yellow ( ' ' + line ) ) ) ;
82
81
} ) ;
83
82
84
83
_processes . push ( childProcess ) ;
85
84
86
85
// Create the error here so the stack shows who called this function.
87
- const err = new Error ( `Running " ${ cmd } ${ args . join ( ' ' ) } " returned error code ` ) ;
86
+
88
87
return new Promise ( ( resolve , reject ) => {
88
+ let matched = false ;
89
+
89
90
childProcess . on ( 'exit' , ( error : any ) => {
90
- _processes = _processes . filter ( p => p !== childProcess ) ;
91
+ _processes = _processes . filter ( ( p ) => p !== childProcess ) ;
92
+
93
+ if ( options . waitForMatch && ! matched ) {
94
+ error = `Output didn't match '${ options . waitForMatch } '.` ;
95
+ }
91
96
92
97
if ( ! error ) {
93
98
resolve ( { stdout, stderr } ) ;
94
- } else {
95
- err . message += `${ error } ...\n\nSTDOUT:\n${ stdout } \n\nSTDERR:\n${ stderr } \n` ;
96
- reject ( err ) ;
99
+ return ;
97
100
}
101
+
102
+ reject (
103
+ new Error (
104
+ `Running "${ cmd } ${ args . join (
105
+ ' ' ,
106
+ ) } " returned error. ${ error } ...\n\nSTDOUT:\n${ stdout } \n\nSTDERR:\n${ stderr } \n`,
107
+ ) ,
108
+ ) ;
98
109
} ) ;
99
110
100
111
if ( options . waitForMatch ) {
101
112
const match = options . waitForMatch ;
102
113
childProcess . stdout . on ( 'data' , ( data : Buffer ) => {
103
114
if ( data . toString ( ) . match ( match ) ) {
104
115
resolve ( { stdout, stderr } ) ;
116
+ matched = true ;
105
117
}
106
118
} ) ;
107
119
childProcess . stderr . on ( 'data' , ( data : Buffer ) => {
108
120
if ( data . toString ( ) . match ( match ) ) {
109
121
resolve ( { stdout, stderr } ) ;
122
+ matched = true ;
110
123
}
111
124
} ) ;
112
125
}
113
126
} ) ;
114
127
}
115
128
116
- export function waitForAnyProcessOutputToMatch ( match : RegExp ,
117
- timeout = 30000 ) : Promise < ProcessOutput > {
129
+ export function waitForAnyProcessOutputToMatch (
130
+ match : RegExp ,
131
+ timeout = 30000 ,
132
+ ) : Promise < ProcessOutput > {
118
133
// Race between _all_ processes, and the timeout. First one to resolve/reject wins.
119
134
const timeoutPromise : Promise < ProcessOutput > = new Promise ( ( _resolve , reject ) => {
120
135
// Wait for 30 seconds and timeout.
@@ -124,28 +139,30 @@ export function waitForAnyProcessOutputToMatch(match: RegExp,
124
139
} ) ;
125
140
126
141
const matchPromises : Promise < ProcessOutput > [ ] = _processes . map (
127
- childProcess => new Promise ( resolve => {
128
- let stdout = '' ;
129
- let stderr = '' ;
130
- childProcess . stdout . on ( 'data' , ( data : Buffer ) => {
131
- stdout += data . toString ( ) ;
132
- if ( data . toString ( ) . match ( match ) ) {
133
- resolve ( { stdout, stderr } ) ;
134
- }
135
- } ) ;
136
- childProcess . stderr . on ( 'data' , ( data : Buffer ) => {
137
- stderr += data . toString ( ) ;
138
- if ( data . toString ( ) . match ( match ) ) {
139
- resolve ( { stdout, stderr } ) ;
140
- }
141
- } ) ;
142
- } ) ) ;
142
+ ( childProcess ) =>
143
+ new Promise ( ( resolve ) => {
144
+ let stdout = '' ;
145
+ let stderr = '' ;
146
+ childProcess . stdout . on ( 'data' , ( data : Buffer ) => {
147
+ stdout += data . toString ( ) ;
148
+ if ( data . toString ( ) . match ( match ) ) {
149
+ resolve ( { stdout, stderr } ) ;
150
+ }
151
+ } ) ;
152
+ childProcess . stderr . on ( 'data' , ( data : Buffer ) => {
153
+ stderr += data . toString ( ) ;
154
+ if ( data . toString ( ) . match ( match ) ) {
155
+ resolve ( { stdout, stderr } ) ;
156
+ }
157
+ } ) ;
158
+ } ) ,
159
+ ) ;
143
160
144
161
return Promise . race ( matchPromises . concat ( [ timeoutPromise ] ) ) ;
145
162
}
146
163
147
164
export function killAllProcesses ( signal = 'SIGTERM' ) {
148
- _processes . forEach ( process => treeKill ( process . pid , signal ) ) ;
165
+ _processes . forEach ( ( process ) => treeKill ( process . pid , signal ) ) ;
149
166
_processes = [ ] ;
150
167
}
151
168
@@ -169,16 +186,14 @@ export function execAndWaitForOutputToMatch(cmd: string, args: string[], match:
169
186
// This seems to be due to host file system differences, see
170
187
// https://nodejs.org/docs/latest/api/fs.html#fs_caveats
171
188
return concat (
172
- from (
173
- _exec ( { waitForMatch : match } , cmd , args )
174
- ) ,
189
+ from ( _exec ( { waitForMatch : match } , cmd , args ) ) ,
175
190
defer ( ( ) => waitForAnyProcessOutputToMatch ( match , 2500 ) ) . pipe (
176
191
repeat ( 20 ) ,
177
192
catchError ( ( ) => EMPTY ) ,
178
193
) ,
179
- ) . pipe (
180
- takeLast ( 1 ) ,
181
- ) . toPromise ( ) ;
194
+ )
195
+ . pipe ( takeLast ( 1 ) )
196
+ . toPromise ( ) ;
182
197
} else {
183
198
return _exec ( { waitForMatch : match } , cmd , args ) ;
184
199
}
@@ -190,8 +205,7 @@ export function ng(...args: string[]) {
190
205
if ( [ 'build' , 'serve' , 'test' , 'e2e' , 'extract-i18n' ] . indexOf ( args [ 0 ] ) != - 1 ) {
191
206
if ( args [ 0 ] == 'e2e' ) {
192
207
// Wait 1 second before running any end-to-end test.
193
- return new Promise ( resolve => setTimeout ( resolve , 1000 ) )
194
- . then ( ( ) => maybeSilentNg ( ...args ) ) ;
208
+ return new Promise ( ( resolve ) => setTimeout ( resolve , 1000 ) ) . then ( ( ) => maybeSilentNg ( ...args ) ) ;
195
209
}
196
210
197
211
return maybeSilentNg ( ...args ) ;
@@ -205,15 +219,15 @@ export function noSilentNg(...args: string[]) {
205
219
}
206
220
207
221
export function silentNg ( ...args : string [ ] ) {
208
- return _exec ( { silent : true } , 'ng' , args ) ;
222
+ return _exec ( { silent : true } , 'ng' , args ) ;
209
223
}
210
224
211
225
export function silentNpm ( ...args : string [ ] ) {
212
- return _exec ( { silent : true } , 'npm' , args ) ;
226
+ return _exec ( { silent : true } , 'npm' , args ) ;
213
227
}
214
228
215
229
export function silentYarn ( ...args : string [ ] ) {
216
- return _exec ( { silent : true } , 'yarn' , args ) ;
230
+ return _exec ( { silent : true } , 'yarn' , args ) ;
217
231
}
218
232
219
233
export function npm ( ...args : string [ ] ) {
@@ -229,5 +243,5 @@ export function git(...args: string[]) {
229
243
}
230
244
231
245
export function silentGit ( ...args : string [ ] ) {
232
- return _exec ( { silent : true } , 'git' , args ) ;
246
+ return _exec ( { silent : true } , 'git' , args ) ;
233
247
}
0 commit comments