@naturalcycles/nodejs-lib 13.33.1 → 13.34.1

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.
@@ -140,6 +140,16 @@ export interface SpawnOptions {
140
140
  name?: string;
141
141
  cwd?: string;
142
142
  env?: AnyObject;
143
+ /**
144
+ * Defaults to false for security reasons.
145
+ * Set to true to pass `process.env` to the spawned process.
146
+ */
147
+ passProcessEnv?: boolean;
148
+ /**
149
+ * Defaults to "auto detect colors".
150
+ * Set to false or true to override.
151
+ */
152
+ forceColor?: boolean;
143
153
  }
144
154
  export interface ExecOptions {
145
155
  /**
@@ -163,5 +173,10 @@ export interface ExecOptions {
163
173
  cwd?: string;
164
174
  timeout?: NumberOfMilliseconds;
165
175
  env?: AnyObject;
176
+ /**
177
+ * Defaults to false for security reasons.
178
+ * Set to true to pass `process.env` to the spawned process.
179
+ */
180
+ passProcessEnv?: boolean;
166
181
  }
167
182
  export {};
@@ -50,15 +50,20 @@ class Exec2 {
50
50
  async spawnAsync(cmd, opt = {}) {
51
51
  const started = Date.now();
52
52
  this.logStart(cmd, opt);
53
- const { shell = true, printWhileRunning = true, collectOutputWhileRunning = true, throwOnNonZeroCode = true, cwd, env, } = opt;
53
+ const { shell = true, printWhileRunning = true, collectOutputWhileRunning = true, throwOnNonZeroCode = true, cwd, env, forceColor = colors_1.hasColors, } = opt;
54
54
  let stdout = '';
55
55
  let stderr = '';
56
+ if (printWhileRunning)
57
+ console.log(''); // 1-line padding before the output
56
58
  return await new Promise((resolve, reject) => {
57
59
  const p = node_child_process_1.default.spawn(cmd, opt.args || [], {
58
60
  shell,
59
61
  cwd,
60
- env,
61
- // ...process.env, // not passing by default for security reasons
62
+ env: {
63
+ ...env,
64
+ ...(opt.passProcessEnv ? process.env : {}),
65
+ ...(forceColor ? { FORCE_COLOR: '1' } : {}),
66
+ },
62
67
  });
63
68
  p.stdout.on('data', data => {
64
69
  if (collectOutputWhileRunning) {
@@ -79,7 +84,10 @@ class Exec2 {
79
84
  }
80
85
  });
81
86
  p.on('close', code => {
82
- this.logFinish(cmd, opt, started);
87
+ if (printWhileRunning)
88
+ console.log(''); // 1-line padding after the output
89
+ const isSuccessful = !code;
90
+ this.logFinish(cmd, opt, started, isSuccessful);
83
91
  const exitCode = code || 0;
84
92
  const o = {
85
93
  exitCode,
@@ -109,16 +117,22 @@ class Exec2 {
109
117
  spawn(cmd, opt = {}) {
110
118
  const started = Date.now();
111
119
  this.logStart(cmd, opt);
112
- const { shell = true, cwd, env } = opt;
120
+ const { shell = true, cwd, env, forceColor = colors_1.hasColors } = opt;
121
+ console.log(''); // 1-line padding before the output
113
122
  const r = node_child_process_1.default.spawnSync(cmd, opt.args, {
114
123
  encoding: 'utf8',
115
124
  stdio: 'inherit',
116
125
  shell,
117
126
  cwd,
118
- env,
119
- // ...process.env, // not passing by default for security reasons
127
+ env: {
128
+ ...env,
129
+ ...(opt.passProcessEnv ? process.env : {}),
130
+ ...(forceColor ? { FORCE_COLOR: '1' } : {}),
131
+ },
120
132
  });
121
- this.logFinish(cmd, opt, started);
133
+ console.log(''); // 1-line padding after the output
134
+ const isSuccessful = !r.error && !r.status;
135
+ this.logFinish(cmd, opt, started, isSuccessful);
122
136
  if (r.error) {
123
137
  throw r.error;
124
138
  }
@@ -145,7 +159,7 @@ class Exec2 {
145
159
  this.logStart(cmd, opt);
146
160
  const { cwd, env, timeout } = opt;
147
161
  try {
148
- return node_child_process_1.default
162
+ const s = node_child_process_1.default
149
163
  .execSync(cmd, {
150
164
  encoding: 'utf8',
151
165
  // stdio: 'inherit', // no, otherwise we don't get the output returned
@@ -153,10 +167,14 @@ class Exec2 {
153
167
  // shell: undefined,
154
168
  cwd,
155
169
  timeout,
156
- env,
157
- // ...process.env, // not passing by default for security reasons
170
+ env: {
171
+ ...env,
172
+ ...(opt.passProcessEnv ? process.env : {}),
173
+ },
158
174
  })
159
175
  .trim();
176
+ this.logFinish(cmd, opt, started, true);
177
+ return s;
160
178
  }
161
179
  catch (err) {
162
180
  // Not logging stderr, as it's printed by execSync by default (somehow)
@@ -167,11 +185,9 @@ class Exec2 {
167
185
  if (err.stdout) {
168
186
  process.stdout.write(err.stdout);
169
187
  }
188
+ this.logFinish(cmd, opt, started, false);
170
189
  throw new Error(`exec exited with code ${err.status}: ${cmd}`);
171
190
  }
172
- finally {
173
- this.logFinish(cmd, opt, started);
174
- }
175
191
  }
176
192
  throwOnNonZeroExitCode(o) {
177
193
  if (o.exitCode) {
@@ -189,10 +205,17 @@ class Exec2 {
189
205
  .filter(Boolean)
190
206
  .join(' '));
191
207
  }
192
- logFinish(cmd, opt, started) {
193
- if (!opt.logFinish && !opt.log)
208
+ logFinish(cmd, opt, started, isSuccessful) {
209
+ if (isSuccessful && !opt.logFinish && !opt.log)
194
210
  return;
195
- console.log([(0, colors_1.white)(opt.name || cmd), (0, colors_1.dimGrey)('took ' + (0, js_lib_1._since)(started))].join(' '));
211
+ console.log([
212
+ (0, colors_1.white)(opt.name || cmd),
213
+ ...((!opt.name && opt.args) || []),
214
+ (0, colors_1.dimGrey)('took ' + (0, js_lib_1._since)(started)),
215
+ !isSuccessful && (0, colors_1.dimGrey)('and ') + (0, colors_1.dimRed)('failed'),
216
+ ]
217
+ .filter(Boolean)
218
+ .join(' '));
196
219
  }
197
220
  }
198
221
  exports.exec2 = new Exec2();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naturalcycles/nodejs-lib",
3
- "version": "13.33.1",
3
+ "version": "13.34.1",
4
4
  "scripts": {
5
5
  "prepare": "husky",
6
6
  "build": "dev-lib build",
package/src/util/exec2.ts CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  NumberOfMilliseconds,
7
7
  UnixTimestampMillisNumber,
8
8
  } from '@naturalcycles/js-lib'
9
- import { dimGrey, white } from '../colors/colors'
9
+ import { dimGrey, dimRed, hasColors, white } from '../colors/colors'
10
10
 
11
11
  /**
12
12
  * Set of utility functions to work with Spawn / Exec.
@@ -60,16 +60,22 @@ class Exec2 {
60
60
  throwOnNonZeroCode = true,
61
61
  cwd,
62
62
  env,
63
+ forceColor = hasColors,
63
64
  } = opt
64
65
  let stdout = ''
65
66
  let stderr = ''
66
67
 
68
+ if (printWhileRunning) console.log('') // 1-line padding before the output
69
+
67
70
  return await new Promise<SpawnOutput>((resolve, reject) => {
68
71
  const p = cp.spawn(cmd, opt.args || [], {
69
72
  shell,
70
73
  cwd,
71
- env,
72
- // ...process.env, // not passing by default for security reasons
74
+ env: {
75
+ ...env,
76
+ ...(opt.passProcessEnv ? process.env : {}),
77
+ ...(forceColor ? { FORCE_COLOR: '1' } : {}),
78
+ },
73
79
  })
74
80
 
75
81
  p.stdout.on('data', data => {
@@ -92,7 +98,9 @@ class Exec2 {
92
98
  })
93
99
 
94
100
  p.on('close', code => {
95
- this.logFinish(cmd, opt, started)
101
+ if (printWhileRunning) console.log('') // 1-line padding after the output
102
+ const isSuccessful = !code
103
+ this.logFinish(cmd, opt, started, isSuccessful)
96
104
  const exitCode = code || 0
97
105
  const o: SpawnOutput = {
98
106
  exitCode,
@@ -123,18 +131,24 @@ class Exec2 {
123
131
  spawn(cmd: string, opt: SpawnOptions = {}): void {
124
132
  const started = Date.now()
125
133
  this.logStart(cmd, opt)
126
- const { shell = true, cwd, env } = opt
134
+ const { shell = true, cwd, env, forceColor = hasColors } = opt
135
+ console.log('') // 1-line padding before the output
127
136
 
128
137
  const r = cp.spawnSync(cmd, opt.args, {
129
138
  encoding: 'utf8',
130
139
  stdio: 'inherit',
131
140
  shell,
132
141
  cwd,
133
- env,
134
- // ...process.env, // not passing by default for security reasons
142
+ env: {
143
+ ...env,
144
+ ...(opt.passProcessEnv ? process.env : {}),
145
+ ...(forceColor ? { FORCE_COLOR: '1' } : {}),
146
+ },
135
147
  })
136
148
 
137
- this.logFinish(cmd, opt, started)
149
+ console.log('') // 1-line padding after the output
150
+ const isSuccessful = !r.error && !r.status
151
+ this.logFinish(cmd, opt, started, isSuccessful)
138
152
 
139
153
  if (r.error) {
140
154
  throw r.error
@@ -164,7 +178,7 @@ class Exec2 {
164
178
  const { cwd, env, timeout } = opt
165
179
 
166
180
  try {
167
- return cp
181
+ const s = cp
168
182
  .execSync(cmd, {
169
183
  encoding: 'utf8',
170
184
  // stdio: 'inherit', // no, otherwise we don't get the output returned
@@ -172,10 +186,15 @@ class Exec2 {
172
186
  // shell: undefined,
173
187
  cwd,
174
188
  timeout,
175
- env,
176
- // ...process.env, // not passing by default for security reasons
189
+ env: {
190
+ ...env,
191
+ ...(opt.passProcessEnv ? process.env : {}),
192
+ },
177
193
  })
178
194
  .trim()
195
+
196
+ this.logFinish(cmd, opt, started, true)
197
+ return s
179
198
  } catch (err) {
180
199
  // Not logging stderr, as it's printed by execSync by default (somehow)
181
200
  // stdout is not printed by execSync though, therefor we print it here
@@ -185,9 +204,8 @@ class Exec2 {
185
204
  if ((err as any).stdout) {
186
205
  process.stdout.write((err as any).stdout)
187
206
  }
207
+ this.logFinish(cmd, opt, started, false)
188
208
  throw new Error(`exec exited with code ${(err as any).status}: ${cmd}`)
189
- } finally {
190
- this.logFinish(cmd, opt, started)
191
209
  }
192
210
  }
193
211
 
@@ -215,10 +233,20 @@ class Exec2 {
215
233
  cmd: string,
216
234
  opt: SpawnOptions | ExecOptions,
217
235
  started: UnixTimestampMillisNumber,
236
+ isSuccessful: boolean,
218
237
  ): void {
219
- if (!opt.logFinish && !opt.log) return
238
+ if (isSuccessful && !opt.logFinish && !opt.log) return
220
239
 
221
- console.log([white(opt.name || cmd), dimGrey('took ' + _since(started))].join(' '))
240
+ console.log(
241
+ [
242
+ white(opt.name || cmd),
243
+ ...((!opt.name && (opt as SpawnOptions).args) || []),
244
+ dimGrey('took ' + _since(started)),
245
+ !isSuccessful && dimGrey('and ') + dimRed('failed'),
246
+ ]
247
+ .filter(Boolean)
248
+ .join(' '),
249
+ )
222
250
  }
223
251
  }
224
252
 
@@ -297,6 +325,16 @@ export interface SpawnOptions {
297
325
  cwd?: string
298
326
 
299
327
  env?: AnyObject
328
+ /**
329
+ * Defaults to false for security reasons.
330
+ * Set to true to pass `process.env` to the spawned process.
331
+ */
332
+ passProcessEnv?: boolean
333
+ /**
334
+ * Defaults to "auto detect colors".
335
+ * Set to false or true to override.
336
+ */
337
+ forceColor?: boolean
300
338
  }
301
339
 
302
340
  export interface ExecOptions {
@@ -323,4 +361,9 @@ export interface ExecOptions {
323
361
  timeout?: NumberOfMilliseconds
324
362
 
325
363
  env?: AnyObject
364
+ /**
365
+ * Defaults to false for security reasons.
366
+ * Set to true to pass `process.env` to the spawned process.
367
+ */
368
+ passProcessEnv?: boolean
326
369
  }