@@ -17,7 +17,7 @@ import { dimGrey, dimRed, hasColors, white } from '../colors/colors'
1717 *
1818 * Short-running job, no need to print the output, might want to return the output - use Exec.
1919 *
20- * Need to both print and return the output - use SpawnAsync .
20+ * Need to both print and return the output - use SpawnAsyncAndReturn .
2121 *
2222 * ***
2323 *
@@ -31,101 +31,13 @@ import { dimGrey, dimRed, hasColors, white } from '../colors/colors'
3131 * Exec always uses the shell (there's no option to disable it).
3232 */
3333class Exec2 {
34- /**
35- * Advanced/async version of Spawn.
36- * Consider simpler `spawn` or `exec` first, which are also sync.
37- *
38- * spawnAsync features:
39- *
40- * 1. Async
41- * 2. Allows to collect the output AND print it while running.
42- * 3. Returns SpawnOutput with stdout, stderr and exitCode.
43- * 4. Allows to not throw on error, but just return SpawnOutput for further inspection.
44- *
45- * Defaults:
46- *
47- * shell: true
48- * printWhileRunning: true
49- * collectOutputWhileRunning: true
50- * throwOnNonZeroCode: true
51- * log: true
52- */
53- async spawnAsync ( cmd : string , opt : SpawnAsyncOptions = { } ) : Promise < SpawnOutput > {
54- const {
55- shell = true ,
56- printWhileRunning = true ,
57- collectOutputWhileRunning = true ,
58- throwOnNonZeroCode = true ,
59- cwd,
60- env,
61- passProcessEnv = true ,
62- forceColor = hasColors ,
63- } = opt
64- opt . log ??= printWhileRunning // by default log should be true, as we are printing the output
65- opt . logStart ??= opt . log
66- opt . logFinish ??= opt . log
67- const started = Date . now ( )
68- this . logStart ( cmd , opt )
69- let stdout = ''
70- let stderr = ''
71-
72- // if (printWhileRunning) console.log('') // 1-line padding before the output
73-
74- return await new Promise < SpawnOutput > ( ( resolve , reject ) => {
75- const p = cp . spawn ( cmd , opt . args || [ ] , {
76- shell,
77- cwd,
78- env : {
79- ...( passProcessEnv ? process . env : { } ) ,
80- ...( forceColor ? { FORCE_COLOR : '1' } : { } ) ,
81- ...env ,
82- } ,
83- } )
84-
85- p . stdout . on ( 'data' , data => {
86- if ( collectOutputWhileRunning ) {
87- stdout += data . toString ( )
88- // console.log('stdout:', data.toString())
89- }
90- if ( printWhileRunning ) {
91- process . stdout . write ( data )
92- // console.log('stderr:', data.toString())
93- }
94- } )
95- p . stderr . on ( 'data' , data => {
96- if ( collectOutputWhileRunning ) {
97- stderr += data . toString ( )
98- }
99- if ( printWhileRunning ) {
100- process . stderr . write ( data )
101- }
102- } )
103-
104- p . on ( 'close' , code => {
105- // if (printWhileRunning) console.log('') // 1-line padding after the output
106- const isSuccessful = ! code
107- this . logFinish ( cmd , opt , started , isSuccessful )
108- const exitCode = code || 0
109- const o : SpawnOutput = {
110- exitCode,
111- stdout : stdout . trim ( ) ,
112- stderr : stderr . trim ( ) ,
113- }
114- if ( throwOnNonZeroCode && code ) {
115- return reject ( new SpawnError ( `spawnAsync exited with code ${ code } : ${ cmd } ` , o ) )
116- }
117- resolve ( o )
118- } )
119- } )
120- }
121-
12234 /**
12335 * Reasons to use it:
12436 * - Sync
12537 * - Need to print output while running
12638 *
12739 * Limitations:
128- * - Cannot return stdout/stderr (use exec or spawnAsync for that)
40+ * - Cannot return stdout/stderr (use exec, execAsync or spawnAsyncAndReturn for that)
12941 *
13042 * Defaults:
13143 *
@@ -139,7 +51,6 @@ class Exec2 {
13951 opt . logFinish ??= opt . log
14052 const started = Date . now ( )
14153 this . logStart ( cmd , opt )
142- // console.log('') // 1-line padding before the output
14354
14455 const r = cp . spawnSync ( cmd , opt . args , {
14556 encoding : 'utf8' ,
@@ -153,7 +64,6 @@ class Exec2 {
15364 } ,
15465 } )
15566
156- // console.log('') // 1-line padding after the output
15767 const isSuccessful = ! r . error && ! r . status
15868 this . logFinish ( cmd , opt , started , isSuccessful )
15969
@@ -218,10 +128,133 @@ class Exec2 {
218128 }
219129 }
220130
221- throwOnNonZeroExitCode ( o : SpawnOutput ) : void {
222- if ( o . exitCode ) {
223- throw new SpawnError ( `spawn exited with code ${ o . exitCode } ` , o )
224- }
131+ /**
132+ * Reasons to use it:
133+ * - Async
134+ * - Need to print output while running
135+ *
136+ * Limitations:
137+ * - Cannot return stdout/stderr (use execAsync or spawnAsyncAndReturn for that)
138+ *
139+ * Defaults:
140+ *
141+ * shell: true
142+ * log: true
143+ */
144+ async spawnAsync ( cmd : string , opt : SpawnOptions = { } ) : Promise < void > {
145+ const { shell = true , cwd, env, passProcessEnv = true , forceColor = hasColors } = opt
146+ opt . log ??= true // by default log should be true, as we are printing the output
147+ opt . logStart ??= opt . log
148+ opt . logFinish ??= opt . log
149+ const started = Date . now ( )
150+ this . logStart ( cmd , opt )
151+
152+ await new Promise < void > ( ( resolve , reject ) => {
153+ const p = cp . spawn ( cmd , opt . args || [ ] , {
154+ shell,
155+ cwd,
156+ stdio : 'inherit' ,
157+ env : {
158+ ...( passProcessEnv ? process . env : { } ) ,
159+ ...( forceColor ? { FORCE_COLOR : '1' } : { } ) ,
160+ ...env ,
161+ } ,
162+ } )
163+
164+ p . on ( 'close' , code => {
165+ const isSuccessful = ! code
166+ this . logFinish ( cmd , opt , started , isSuccessful )
167+ if ( code ) {
168+ return reject ( new Error ( `spawnAsync exited with code ${ code } : ${ cmd } ` ) )
169+ }
170+ resolve ( )
171+ } )
172+ } )
173+ }
174+
175+ /**
176+ * Advanced/async version of Spawn.
177+ * Consider simpler `spawn` or `exec` first, which are also sync.
178+ *
179+ * spawnAsyncAndReturn features:
180+ *
181+ * 1. Async
182+ * 2. Allows to collect the output AND print it while running.
183+ * 3. Returns SpawnOutput with stdout, stderr and exitCode.
184+ * 4. Allows to not throw on error, but just return SpawnOutput for further inspection.
185+ *
186+ * Defaults:
187+ *
188+ * shell: true
189+ * printWhileRunning: true
190+ * collectOutputWhileRunning: true
191+ * throwOnNonZeroCode: true
192+ * log: true
193+ */
194+ async spawnAsyncAndReturn ( cmd : string , opt : SpawnAsyncOptions = { } ) : Promise < SpawnOutput > {
195+ const {
196+ shell = true ,
197+ printWhileRunning = true ,
198+ collectOutputWhileRunning = true ,
199+ throwOnNonZeroCode = true ,
200+ cwd,
201+ env,
202+ passProcessEnv = true ,
203+ forceColor = hasColors ,
204+ } = opt
205+ opt . log ??= printWhileRunning // by default log should be true, as we are printing the output
206+ opt . logStart ??= opt . log
207+ opt . logFinish ??= opt . log
208+ const started = Date . now ( )
209+ this . logStart ( cmd , opt )
210+ let stdout = ''
211+ let stderr = ''
212+
213+ return await new Promise < SpawnOutput > ( ( resolve , reject ) => {
214+ const p = cp . spawn ( cmd , opt . args || [ ] , {
215+ shell,
216+ cwd,
217+ env : {
218+ ...( passProcessEnv ? process . env : { } ) ,
219+ ...( forceColor ? { FORCE_COLOR : '1' } : { } ) ,
220+ ...env ,
221+ } ,
222+ } )
223+
224+ p . stdout . on ( 'data' , data => {
225+ if ( collectOutputWhileRunning ) {
226+ stdout += data . toString ( )
227+ // console.log('stdout:', data.toString())
228+ }
229+ if ( printWhileRunning ) {
230+ process . stdout . write ( data )
231+ // console.log('stderr:', data.toString())
232+ }
233+ } )
234+ p . stderr . on ( 'data' , data => {
235+ if ( collectOutputWhileRunning ) {
236+ stderr += data . toString ( )
237+ }
238+ if ( printWhileRunning ) {
239+ process . stderr . write ( data )
240+ }
241+ } )
242+
243+ p . on ( 'close' , code => {
244+ const isSuccessful = ! code
245+ this . logFinish ( cmd , opt , started , isSuccessful )
246+ const exitCode = code || 0
247+ const o : SpawnOutput = {
248+ exitCode,
249+ stdout : stdout . trim ( ) ,
250+ stderr : stderr . trim ( ) ,
251+ }
252+ if ( throwOnNonZeroCode && code ) {
253+ return reject ( new SpawnError ( `spawnAsyncAndReturn exited with code ${ code } : ${ cmd } ` , o ) )
254+ }
255+ resolve ( o )
256+ } )
257+ } )
225258 }
226259
227260 private logStart ( cmd : string , opt : SpawnOptions | ExecOptions ) : void {
0 commit comments