@naturalcycles/nodejs-lib 13.34.4 → 13.34.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -49,7 +49,7 @@ function transformThrottle(opt) {
49
49
  // console.log('pausing now after', {item, count})
50
50
  paused = (0, js_lib_1.pDefer)();
51
51
  if (debug) {
52
- console.log(`${js_lib_1.localTime.now().toPretty()} transformThrottle activated: ${count} items passed in ${(0, js_lib_1._ms)(interval * 1000)}, will pause for ${(0, js_lib_1._ms)(interval * 1000 - (Date.now() - start))}`);
52
+ console.log(`${js_lib_1.localTime.now().toPretty()} transformThrottle activated: ${count} items passed in ${(0, js_lib_1._since)(start)}, will pause for ${(0, js_lib_1._ms)(interval * 1000 - (Date.now() - start))}`);
53
53
  }
54
54
  }
55
55
  cb(null, item); // pass the item through
@@ -60,15 +60,20 @@ function transformThrottle(opt) {
60
60
  },
61
61
  });
62
62
  function onInterval(transform) {
63
- if (!paused)
64
- return;
65
- if (debug) {
66
- console.log(`${js_lib_1.localTime.now().toPretty()} transformThrottle resumed`);
63
+ if (paused) {
64
+ if (debug) {
65
+ console.log(`${js_lib_1.localTime.now().toPretty()} transformThrottle resumed`);
66
+ }
67
+ paused.resolve();
68
+ paused = undefined;
69
+ }
70
+ else {
71
+ if (debug) {
72
+ console.log(`${js_lib_1.localTime.now().toPretty()} transformThrottle passed ${count} (of max ${throughput}) items in ${(0, js_lib_1._since)(start)}`);
73
+ }
67
74
  }
68
75
  count = 0;
69
76
  start = Date.now();
70
77
  timeout = setTimeout(() => onInterval(transform), interval * 1000);
71
- paused.resolve();
72
- paused = undefined;
73
78
  }
74
79
  }
@@ -8,7 +8,7 @@ import { AnyObject, AppError, NumberOfMilliseconds } from '@naturalcycles/js-lib
8
8
  *
9
9
  * Short-running job, no need to print the output, might want to return the output - use Exec.
10
10
  *
11
- * Need to both print and return the output - use SpawnAsync.
11
+ * Need to both print and return the output - use SpawnAsyncAndReturn.
12
12
  *
13
13
  * ***
14
14
  *
@@ -22,33 +22,13 @@ import { AnyObject, AppError, NumberOfMilliseconds } from '@naturalcycles/js-lib
22
22
  * Exec always uses the shell (there's no option to disable it).
23
23
  */
24
24
  declare class Exec2 {
25
- /**
26
- * Advanced/async version of Spawn.
27
- * Consider simpler `spawn` or `exec` first, which are also sync.
28
- *
29
- * spawnAsync features:
30
- *
31
- * 1. Async
32
- * 2. Allows to collect the output AND print it while running.
33
- * 3. Returns SpawnOutput with stdout, stderr and exitCode.
34
- * 4. Allows to not throw on error, but just return SpawnOutput for further inspection.
35
- *
36
- * Defaults:
37
- *
38
- * shell: true
39
- * printWhileRunning: true
40
- * collectOutputWhileRunning: true
41
- * throwOnNonZeroCode: true
42
- * log: true
43
- */
44
- spawnAsync(cmd: string, opt?: SpawnAsyncOptions): Promise<SpawnOutput>;
45
25
  /**
46
26
  * Reasons to use it:
47
27
  * - Sync
48
28
  * - Need to print output while running
49
29
  *
50
30
  * Limitations:
51
- * - Cannot return stdout/stderr (use exec or spawnAsync for that)
31
+ * - Cannot return stdout/stderr (use exec, execAsync or spawnAsyncAndReturn for that)
52
32
  *
53
33
  * Defaults:
54
34
  *
@@ -71,7 +51,40 @@ declare class Exec2 {
71
51
  * log: false
72
52
  */
73
53
  exec(cmd: string, opt?: ExecOptions): string;
74
- throwOnNonZeroExitCode(o: SpawnOutput): void;
54
+ /**
55
+ * Reasons to use it:
56
+ * - Async
57
+ * - Need to print output while running
58
+ *
59
+ * Limitations:
60
+ * - Cannot return stdout/stderr (use execAsync or spawnAsyncAndReturn for that)
61
+ *
62
+ * Defaults:
63
+ *
64
+ * shell: true
65
+ * log: true
66
+ */
67
+ spawnAsync(cmd: string, opt?: SpawnOptions): Promise<void>;
68
+ /**
69
+ * Advanced/async version of Spawn.
70
+ * Consider simpler `spawn` or `exec` first, which are also sync.
71
+ *
72
+ * spawnAsyncAndReturn features:
73
+ *
74
+ * 1. Async
75
+ * 2. Allows to collect the output AND print it while running.
76
+ * 3. Returns SpawnOutput with stdout, stderr and exitCode.
77
+ * 4. Allows to not throw on error, but just return SpawnOutput for further inspection.
78
+ *
79
+ * Defaults:
80
+ *
81
+ * shell: true
82
+ * printWhileRunning: true
83
+ * collectOutputWhileRunning: true
84
+ * throwOnNonZeroCode: true
85
+ * log: true
86
+ */
87
+ spawnAsyncAndReturn(cmd: string, opt?: SpawnAsyncOptions): Promise<SpawnOutput>;
75
88
  private logStart;
76
89
  private logFinish;
77
90
  }
@@ -14,7 +14,7 @@ const colors_1 = require("../colors/colors");
14
14
  *
15
15
  * Short-running job, no need to print the output, might want to return the output - use Exec.
16
16
  *
17
- * Need to both print and return the output - use SpawnAsync.
17
+ * Need to both print and return the output - use SpawnAsyncAndReturn.
18
18
  *
19
19
  * ***
20
20
  *
@@ -28,87 +28,13 @@ const colors_1 = require("../colors/colors");
28
28
  * Exec always uses the shell (there's no option to disable it).
29
29
  */
30
30
  class Exec2 {
31
- /**
32
- * Advanced/async version of Spawn.
33
- * Consider simpler `spawn` or `exec` first, which are also sync.
34
- *
35
- * spawnAsync features:
36
- *
37
- * 1. Async
38
- * 2. Allows to collect the output AND print it while running.
39
- * 3. Returns SpawnOutput with stdout, stderr and exitCode.
40
- * 4. Allows to not throw on error, but just return SpawnOutput for further inspection.
41
- *
42
- * Defaults:
43
- *
44
- * shell: true
45
- * printWhileRunning: true
46
- * collectOutputWhileRunning: true
47
- * throwOnNonZeroCode: true
48
- * log: true
49
- */
50
- async spawnAsync(cmd, opt = {}) {
51
- const { shell = true, printWhileRunning = true, collectOutputWhileRunning = true, throwOnNonZeroCode = true, cwd, env, passProcessEnv = true, forceColor = colors_1.hasColors, } = opt;
52
- opt.log ??= printWhileRunning; // by default log should be true, as we are printing the output
53
- opt.logStart ??= opt.log;
54
- opt.logFinish ??= opt.log;
55
- const started = Date.now();
56
- this.logStart(cmd, opt);
57
- let stdout = '';
58
- let stderr = '';
59
- // if (printWhileRunning) console.log('') // 1-line padding before the output
60
- return await new Promise((resolve, reject) => {
61
- const p = node_child_process_1.default.spawn(cmd, opt.args || [], {
62
- shell,
63
- cwd,
64
- env: {
65
- ...(passProcessEnv ? process.env : {}),
66
- ...(forceColor ? { FORCE_COLOR: '1' } : {}),
67
- ...env,
68
- },
69
- });
70
- p.stdout.on('data', data => {
71
- if (collectOutputWhileRunning) {
72
- stdout += data.toString();
73
- // console.log('stdout:', data.toString())
74
- }
75
- if (printWhileRunning) {
76
- process.stdout.write(data);
77
- // console.log('stderr:', data.toString())
78
- }
79
- });
80
- p.stderr.on('data', data => {
81
- if (collectOutputWhileRunning) {
82
- stderr += data.toString();
83
- }
84
- if (printWhileRunning) {
85
- process.stderr.write(data);
86
- }
87
- });
88
- p.on('close', code => {
89
- // if (printWhileRunning) console.log('') // 1-line padding after the output
90
- const isSuccessful = !code;
91
- this.logFinish(cmd, opt, started, isSuccessful);
92
- const exitCode = code || 0;
93
- const o = {
94
- exitCode,
95
- stdout: stdout.trim(),
96
- stderr: stderr.trim(),
97
- };
98
- if (throwOnNonZeroCode && code) {
99
- return reject(new SpawnError(`spawnAsync exited with code ${code}: ${cmd}`, o));
100
- }
101
- resolve(o);
102
- });
103
- });
104
- }
105
31
  /**
106
32
  * Reasons to use it:
107
33
  * - Sync
108
34
  * - Need to print output while running
109
35
  *
110
36
  * Limitations:
111
- * - Cannot return stdout/stderr (use exec or spawnAsync for that)
37
+ * - Cannot return stdout/stderr (use exec, execAsync or spawnAsyncAndReturn for that)
112
38
  *
113
39
  * Defaults:
114
40
  *
@@ -122,7 +48,6 @@ class Exec2 {
122
48
  opt.logFinish ??= opt.log;
123
49
  const started = Date.now();
124
50
  this.logStart(cmd, opt);
125
- // console.log('') // 1-line padding before the output
126
51
  const r = node_child_process_1.default.spawnSync(cmd, opt.args, {
127
52
  encoding: 'utf8',
128
53
  stdio: 'inherit',
@@ -134,7 +59,6 @@ class Exec2 {
134
59
  ...env,
135
60
  },
136
61
  });
137
- // console.log('') // 1-line padding after the output
138
62
  const isSuccessful = !r.error && !r.status;
139
63
  this.logFinish(cmd, opt, started, isSuccessful);
140
64
  if (r.error) {
@@ -195,10 +119,118 @@ class Exec2 {
195
119
  throw new Error(`exec exited with code ${err.status}: ${cmd}`);
196
120
  }
197
121
  }
198
- throwOnNonZeroExitCode(o) {
199
- if (o.exitCode) {
200
- throw new SpawnError(`spawn exited with code ${o.exitCode}`, o);
201
- }
122
+ /**
123
+ * Reasons to use it:
124
+ * - Async
125
+ * - Need to print output while running
126
+ *
127
+ * Limitations:
128
+ * - Cannot return stdout/stderr (use execAsync or spawnAsyncAndReturn for that)
129
+ *
130
+ * Defaults:
131
+ *
132
+ * shell: true
133
+ * log: true
134
+ */
135
+ async spawnAsync(cmd, opt = {}) {
136
+ const { shell = true, cwd, env, passProcessEnv = true, forceColor = colors_1.hasColors } = opt;
137
+ opt.log ??= true; // by default log should be true, as we are printing the output
138
+ opt.logStart ??= opt.log;
139
+ opt.logFinish ??= opt.log;
140
+ const started = Date.now();
141
+ this.logStart(cmd, opt);
142
+ await new Promise((resolve, reject) => {
143
+ const p = node_child_process_1.default.spawn(cmd, opt.args || [], {
144
+ shell,
145
+ cwd,
146
+ stdio: 'inherit',
147
+ env: {
148
+ ...(passProcessEnv ? process.env : {}),
149
+ ...(forceColor ? { FORCE_COLOR: '1' } : {}),
150
+ ...env,
151
+ },
152
+ });
153
+ p.on('close', code => {
154
+ const isSuccessful = !code;
155
+ this.logFinish(cmd, opt, started, isSuccessful);
156
+ if (code) {
157
+ return reject(new Error(`spawnAsync exited with code ${code}: ${cmd}`));
158
+ }
159
+ resolve();
160
+ });
161
+ });
162
+ }
163
+ /**
164
+ * Advanced/async version of Spawn.
165
+ * Consider simpler `spawn` or `exec` first, which are also sync.
166
+ *
167
+ * spawnAsyncAndReturn features:
168
+ *
169
+ * 1. Async
170
+ * 2. Allows to collect the output AND print it while running.
171
+ * 3. Returns SpawnOutput with stdout, stderr and exitCode.
172
+ * 4. Allows to not throw on error, but just return SpawnOutput for further inspection.
173
+ *
174
+ * Defaults:
175
+ *
176
+ * shell: true
177
+ * printWhileRunning: true
178
+ * collectOutputWhileRunning: true
179
+ * throwOnNonZeroCode: true
180
+ * log: true
181
+ */
182
+ async spawnAsyncAndReturn(cmd, opt = {}) {
183
+ const { shell = true, printWhileRunning = true, collectOutputWhileRunning = true, throwOnNonZeroCode = true, cwd, env, passProcessEnv = true, forceColor = colors_1.hasColors, } = opt;
184
+ opt.log ??= printWhileRunning; // by default log should be true, as we are printing the output
185
+ opt.logStart ??= opt.log;
186
+ opt.logFinish ??= opt.log;
187
+ const started = Date.now();
188
+ this.logStart(cmd, opt);
189
+ let stdout = '';
190
+ let stderr = '';
191
+ return await new Promise((resolve, reject) => {
192
+ const p = node_child_process_1.default.spawn(cmd, opt.args || [], {
193
+ shell,
194
+ cwd,
195
+ env: {
196
+ ...(passProcessEnv ? process.env : {}),
197
+ ...(forceColor ? { FORCE_COLOR: '1' } : {}),
198
+ ...env,
199
+ },
200
+ });
201
+ p.stdout.on('data', data => {
202
+ if (collectOutputWhileRunning) {
203
+ stdout += data.toString();
204
+ // console.log('stdout:', data.toString())
205
+ }
206
+ if (printWhileRunning) {
207
+ process.stdout.write(data);
208
+ // console.log('stderr:', data.toString())
209
+ }
210
+ });
211
+ p.stderr.on('data', data => {
212
+ if (collectOutputWhileRunning) {
213
+ stderr += data.toString();
214
+ }
215
+ if (printWhileRunning) {
216
+ process.stderr.write(data);
217
+ }
218
+ });
219
+ p.on('close', code => {
220
+ const isSuccessful = !code;
221
+ this.logFinish(cmd, opt, started, isSuccessful);
222
+ const exitCode = code || 0;
223
+ const o = {
224
+ exitCode,
225
+ stdout: stdout.trim(),
226
+ stderr: stderr.trim(),
227
+ };
228
+ if (throwOnNonZeroCode && code) {
229
+ return reject(new SpawnError(`spawnAsyncAndReturn exited with code ${code}: ${cmd}`, o));
230
+ }
231
+ resolve(o);
232
+ });
233
+ });
202
234
  }
203
235
  logStart(cmd, opt) {
204
236
  if (!opt.logStart)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naturalcycles/nodejs-lib",
3
- "version": "13.34.4",
3
+ "version": "13.34.6",
4
4
  "scripts": {
5
5
  "prepare": "husky",
6
6
  "build": "dev-lib build",
@@ -1,6 +1,7 @@
1
1
  import { Transform } from 'node:stream'
2
2
  import {
3
3
  _ms,
4
+ _since,
4
5
  DeferredPromise,
5
6
  localTime,
6
7
  NumberOfMilliseconds,
@@ -75,7 +76,7 @@ export function transformThrottle<T>(opt: TransformThrottleOptions): TransformTy
75
76
  paused = pDefer()
76
77
  if (debug) {
77
78
  console.log(
78
- `${localTime.now().toPretty()} transformThrottle activated: ${count} items passed in ${_ms(interval * 1000)}, will pause for ${_ms(interval * 1000 - (Date.now() - start))}`,
79
+ `${localTime.now().toPretty()} transformThrottle activated: ${count} items passed in ${_since(start)}, will pause for ${_ms(interval * 1000 - (Date.now() - start))}`,
79
80
  )
80
81
  }
81
82
  }
@@ -89,16 +90,23 @@ export function transformThrottle<T>(opt: TransformThrottleOptions): TransformTy
89
90
  })
90
91
 
91
92
  function onInterval(transform: Transform): void {
92
- if (!paused) return
93
+ if (paused) {
94
+ if (debug) {
95
+ console.log(`${localTime.now().toPretty()} transformThrottle resumed`)
96
+ }
93
97
 
94
- if (debug) {
95
- console.log(`${localTime.now().toPretty()} transformThrottle resumed`)
98
+ paused.resolve()
99
+ paused = undefined
100
+ } else {
101
+ if (debug) {
102
+ console.log(
103
+ `${localTime.now().toPretty()} transformThrottle passed ${count} (of max ${throughput}) items in ${_since(start)}`,
104
+ )
105
+ }
96
106
  }
97
107
 
98
108
  count = 0
99
109
  start = Date.now()
100
110
  timeout = setTimeout(() => onInterval(transform), interval * 1000)
101
- paused.resolve()
102
- paused = undefined
103
111
  }
104
112
  }
package/src/util/exec2.ts CHANGED
@@ -17,7 +17,7 @@ import { dimGrey, dimRed, hasColors, white } from '../colors/colors'
17
17
  *
18
18
  * Short-running job, no need to print the output, might want to return the output - use Exec.
19
19
  *
20
- * Need to both print and return the output - use SpawnAsync.
20
+ * Need to both print and return the output - use SpawnAsyncAndReturn.
21
21
  *
22
22
  * ***
23
23
  *
@@ -31,101 +31,13 @@ import { dimGrey, dimRed, hasColors, white } from '../colors/colors'
31
31
  * Exec always uses the shell (there's no option to disable it).
32
32
  */
33
33
  class 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
-
122
34
  /**
123
35
  * Reasons to use it:
124
36
  * - Sync
125
37
  * - Need to print output while running
126
38
  *
127
39
  * Limitations:
128
- * - Cannot return stdout/stderr (use exec or spawnAsync for that)
40
+ * - Cannot return stdout/stderr (use exec, execAsync or spawnAsyncAndReturn for that)
129
41
  *
130
42
  * Defaults:
131
43
  *
@@ -139,7 +51,6 @@ class Exec2 {
139
51
  opt.logFinish ??= opt.log
140
52
  const started = Date.now()
141
53
  this.logStart(cmd, opt)
142
- // console.log('') // 1-line padding before the output
143
54
 
144
55
  const r = cp.spawnSync(cmd, opt.args, {
145
56
  encoding: 'utf8',
@@ -153,7 +64,6 @@ class Exec2 {
153
64
  },
154
65
  })
155
66
 
156
- // console.log('') // 1-line padding after the output
157
67
  const isSuccessful = !r.error && !r.status
158
68
  this.logFinish(cmd, opt, started, isSuccessful)
159
69
 
@@ -218,10 +128,133 @@ class Exec2 {
218
128
  }
219
129
  }
220
130
 
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
+ })
225
258
  }
226
259
 
227
260
  private logStart(cmd: string, opt: SpawnOptions | ExecOptions): void {