concurrently 3.4.0 → 3.5.0

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.
package/README.md CHANGED
@@ -59,9 +59,10 @@ Options:
59
59
  -h, --help output usage information
60
60
  -V, --version output the version number
61
61
  -k, --kill-others kill other processes if one exits or dies
62
+ --kill-others-on-fail kill other processes if one exits with non zero status code
62
63
  --no-color disable colors from logging
63
64
  -p, --prefix <prefix> prefix used in logging for each process.
64
- Possible values: index, pid, time, command, name, none, or a template. Default: index. Example template: "{time}-{pid}"
65
+ Possible values: index, pid, time, command, name, none, or a template. Default: index or name (when --names is set). Example template: "{time}-{pid}"
65
66
 
66
67
  -n, --names <names> List of custom names to be used in prefix template.
67
68
  Example names: "main,browser,server"
@@ -85,12 +86,21 @@ Options:
85
86
  The option can be used to shorten long commands.
86
87
  Works only if prefix is set to "command". Default: 10
87
88
 
89
+ --allow-restart Restart a process which died. Default: false
90
+
91
+ --restart-after <miliseconds> delay time to respawn the process. Default: 0
92
+
93
+ --restart-tries <times> limit the number of respawn tries. Default: 1
88
94
 
89
95
  Examples:
90
96
 
91
97
  - Kill other processes if one exits or dies
92
98
 
93
99
  $ concurrently --kill-others "grunt watch" "http-server"
100
+
101
+ - Kill other processes if one exits with non zero status code
102
+
103
+ $ concurrently --kill-others-on-fail "npm run build:client" "npm run build:server"
94
104
 
95
105
  - Output nothing more than stdout+stderr of child processes
96
106
 
@@ -106,7 +116,7 @@ Examples:
106
116
 
107
117
  - Custom names and colored prefixes
108
118
 
109
- $ concurrently --prefix "[{name}]" --names "HTTP,WATCH" -c "bgBlue.bold,bgMagenta.bold" "npm run watch" "http-server"
119
+ $ concurrently --names "HTTP,WATCH" -c "bgBlue.bold,bgMagenta.bold" "http-server" "npm run watch"
110
120
 
111
121
  For more details, visit https://github.com/kimmobrunfeldt/concurrently
112
122
  ```
@@ -137,17 +147,3 @@ and you won't even notice the difference.
137
147
 
138
148
  Another option would be to just run all commands in separate terminals. I got
139
149
  tired of opening terminals and made **concurrently**.
140
-
141
- ### NPM Issue
142
-
143
- Previously I thought this could fix some problems I had with watching scripts and this readme said:
144
-
145
- > When running watch or serve tasks, I'd recommend to use `--kill-others` option:
146
- >
147
- > ```bash
148
- > concurrently --kill-others "npm run watch-js" "npm run watch-less"
149
- > ```
150
- >
151
- > That way, if for some reason e.g. your `watch-less` died, you would notice it easier.
152
-
153
- However NPM didn't work as I hoped it would. See [this issue](https://github.com/kimmobrunfeldt/concurrently/issues/4).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "concurrently",
3
- "version": "3.4.0",
3
+ "version": "3.5.0",
4
4
  "description": "Run commands concurrently",
5
5
  "main": "src/main.js",
6
6
  "bin": {
package/src/main.js CHANGED
@@ -24,7 +24,7 @@ var config = {
24
24
 
25
25
  // Prefix logging with pid
26
26
  // Possible values: 'pid', 'none', 'time', 'command', 'index', 'name'
27
- prefix: 'index',
27
+ prefix: '',
28
28
 
29
29
  // List of custom names to be used in prefix template
30
30
  names: '',
@@ -46,7 +46,16 @@ var config = {
46
46
  color: true,
47
47
 
48
48
  // If true, the output will only be raw output of processes, nothing more
49
- raw: false
49
+ raw: false,
50
+
51
+ // If true, the process restart when it exited with status code non-zero
52
+ allowRestart: false,
53
+
54
+ // By default, restart instantly
55
+ restartAfter: 0,
56
+
57
+ // By default, restart once
58
+ restartTries: 1
50
59
  };
51
60
 
52
61
  function main() {
@@ -58,6 +67,8 @@ function main() {
58
67
 
59
68
  parseArgs();
60
69
  config = mergeDefaultsWithArgs(config);
70
+ applyDynamicDefaults(config)
71
+
61
72
  run(program.args);
62
73
  }
63
74
 
@@ -81,7 +92,7 @@ function parseArgs() {
81
92
  '-p, --prefix <prefix>',
82
93
  'prefix used in logging for each process.\n' +
83
94
  'Possible values: index, pid, time, command, name, none, or a template. Default: ' +
84
- config.prefix + '. Example template: "{time}-{pid}"\n'
95
+ 'index or name (when --names is set). Example template: "{time}-{pid}"\n'
85
96
  )
86
97
  .option(
87
98
  '-n, --names <names>',
@@ -126,6 +137,21 @@ function parseArgs() {
126
137
  'The option can be used to shorten long commands.\n' +
127
138
  'Works only if prefix is set to "command". Default: ' +
128
139
  config.prefixLength + '\n'
140
+ )
141
+ .option(
142
+ '--allow-restart',
143
+ 'Restart a process which died. Default: ' +
144
+ config.allowRestart + '\n'
145
+ )
146
+ .option(
147
+ '--restart-after <miliseconds>',
148
+ 'delay time to respawn the process. Default: ' +
149
+ config.restartAfter + '\n'
150
+ )
151
+ .option(
152
+ '--restart-tries <times>',
153
+ 'limit the number of respawn tries. Default: ' +
154
+ config.restartTries + '\n'
129
155
  );
130
156
 
131
157
  program.on('--help', function() {
@@ -154,7 +180,7 @@ function parseArgs() {
154
180
  '',
155
181
  ' - Custom names and colored prefixes',
156
182
  '',
157
- ' $ concurrently --prefix "[{name}]" --names "HTTP,WATCH" -c "bgBlue.bold,bgMagenta.bold" "npm run watch" "http-server"',
183
+ ' $ concurrently --names "HTTP,WATCH" -c "bgBlue.bold,bgMagenta.bold" "http-server" "npm run watch"',
158
184
  ''
159
185
  ];
160
186
  console.log(help.join('\n'));
@@ -172,6 +198,12 @@ function mergeDefaultsWithArgs(config) {
172
198
  return _.merge(config, program);
173
199
  }
174
200
 
201
+ function applyDynamicDefaults(config) {
202
+ if (!config.prefix) {
203
+ config.prefix = config.names ? 'name' : 'index';
204
+ }
205
+ }
206
+
175
207
  function stripCmdQuotes(cmd) {
176
208
  // Removes the quotes surrounding a command.
177
209
  if (cmd[0] === '"' || cmd[0] === '\'') {
@@ -198,14 +230,7 @@ function run(commands) {
198
230
  spawnOpts.env = Object.assign({FORCE_COLOR: supportsColor.level}, process.env)
199
231
  }
200
232
 
201
- var child;
202
- try {
203
- child = spawn(cmd, spawnOpts);
204
- } catch (e) {
205
- logError('', chalk.gray.dim, 'Error occured when executing command: ' + cmd);
206
- logError('', chalk.gray.dim, e.stack);
207
- process.exit(1);
208
- }
233
+ var child = spawnChild(cmd, spawnOpts);
209
234
 
210
235
  if (index < prefixColors.length) {
211
236
  var prefixColorPath = prefixColors[index];
@@ -217,13 +242,41 @@ function run(commands) {
217
242
  command: cmd,
218
243
  index: index,
219
244
  name: name,
245
+ options: spawnOpts,
246
+ restartTries: config.restartTries,
220
247
  prefixColor: lastPrefixColor
221
248
  };
222
249
  return child;
223
250
  });
224
251
 
252
+ var streams = toStreams(children);
253
+
254
+ handleChildEvents(streams, children, childrenInfo);
255
+
256
+ ['SIGINT', 'SIGTERM'].forEach(function(signal) {
257
+ process.on(signal, function() {
258
+ children.forEach(function(child) {
259
+ treeKill(child.pid, signal);
260
+ });
261
+ });
262
+ });
263
+ }
264
+
265
+ function spawnChild(cmd, options) {
266
+ var child;
267
+ try {
268
+ child = spawn(cmd, options);
269
+ } catch (e) {
270
+ logError('', chalk.gray.dim, 'Error occured when executing command: ' + cmd);
271
+ logError('', chalk.gray.dim, e.stack);
272
+ process.exit(1);
273
+ }
274
+ return child;
275
+ }
276
+
277
+ function toStreams(children) {
225
278
  // Transform all process events to rx streams
226
- var streams = _.map(children, function(child) {
279
+ return _.map(children, function(child) {
227
280
  var childStreams = {
228
281
  error: Rx.Node.fromEvent(child, 'error'),
229
282
  close: Rx.Node.fromEvent(child, 'close')
@@ -241,21 +294,15 @@ function run(commands) {
241
294
  return memo;
242
295
  }, {});
243
296
  });
297
+ }
244
298
 
299
+ function handleChildEvents(streams, children, childrenInfo) {
245
300
  handleClose(streams, children, childrenInfo);
246
301
  handleError(streams, childrenInfo);
247
302
  if (!config.raw) {
248
303
  handleOutput(streams, childrenInfo, 'stdout');
249
304
  handleOutput(streams, childrenInfo, 'stderr');
250
305
  }
251
-
252
- ['SIGINT', 'SIGTERM'].forEach(function(signal) {
253
- process.on(signal, function() {
254
- children.forEach(function(child) {
255
- treeKill(child.pid, signal);
256
- });
257
- });
258
- });
259
306
  }
260
307
 
261
308
  function handleOutput(streams, childrenInfo, source) {
@@ -283,14 +330,20 @@ function handleClose(streams, children, childrenInfo) {
283
330
  exitCodes.push(exitCode);
284
331
 
285
332
  var prefix = getPrefix(childrenInfo, event.child);
286
- var prefixColor = childrenInfo[event.child.pid].prefixColor;
287
- var command = childrenInfo[event.child.pid].command;
333
+ var childInfo = childrenInfo[event.child.pid];
334
+ var prefixColor = childInfo.prefixColor;
335
+ var command = childInfo.command;
288
336
  logEvent(prefix, prefixColor, command + ' exited with code ' + exitCode);
289
337
 
290
338
  aliveChildren = _.filter(aliveChildren, function(child) {
291
339
  return child.pid !== event.child.pid;
292
340
  });
293
341
 
342
+ if (nonSuccess && config.allowRestart && childInfo.restartTries--) {
343
+ respawnChild(event, childrenInfo);
344
+ return;
345
+ }
346
+
294
347
  if (aliveChildren.length === 0) {
295
348
  exit(exitCodes);
296
349
  }
@@ -306,6 +359,23 @@ function handleClose(streams, children, childrenInfo) {
306
359
  });
307
360
  }
308
361
 
362
+ function respawnChild(event, childrenInfo) {
363
+ setTimeout(function() {
364
+ var childInfo = childrenInfo[event.child.pid];
365
+ var prefix = getPrefix(childrenInfo, event.child);
366
+ var prefixColor = childInfo.prefixColor;
367
+ logEvent(prefix, prefixColor, childInfo.command + ' restarted');
368
+ var newChild = spawnChild(childInfo.command, childInfo.options);
369
+
370
+ childrenInfo[newChild.pid] = childrenInfo[event.child.pid];
371
+ delete childrenInfo[event.child.pid];
372
+
373
+ var children = [newChild];
374
+ var streams = toStreams(children);
375
+ handleChildEvents(streams, children, childrenInfo);
376
+ }, config.restartAfter);
377
+ }
378
+
309
379
  function killOtherProcesses(processes) {
310
380
  logEvent('--> ', chalk.gray.dim, 'Sending SIGTERM to other processes..');
311
381
 
@@ -5,8 +5,8 @@ var assert = require('assert');
5
5
  var run = require('./utils').run;
6
6
  var IS_WINDOWS = /^win/.test(process.platform);
7
7
 
8
- // If true, output of commands are shown
9
- var DEBUG_TESTS = process.env.DEBUG_TESTS === 'true';
8
+ // Note: Set the DEBUG_TESTS environment variable to `true` to see output of test commands.
9
+
10
10
  var TEST_DIR = 'dir/';
11
11
 
12
12
  // Abs path to test directory
@@ -17,7 +17,7 @@ describe('concurrently', function() {
17
17
  this.timeout(5000);
18
18
 
19
19
  it('help should be successful', () => {
20
- return run('node ./src/main.js --help', {pipe: DEBUG_TESTS})
20
+ return run('node ./src/main.js --help')
21
21
  .then(function(exitCode) {
22
22
  // exit code 0 means success
23
23
  assert.strictEqual(exitCode, 0);
@@ -25,35 +25,35 @@ describe('concurrently', function() {
25
25
  });
26
26
 
27
27
  it('version should be successful', () => {
28
- return run('node ./src/main.js -V', {pipe: DEBUG_TESTS})
28
+ return run('node ./src/main.js -V')
29
29
  .then(function(exitCode) {
30
30
  assert.strictEqual(exitCode, 0);
31
31
  });
32
32
  });
33
33
 
34
34
  it('two successful commands should exit 0', () => {
35
- return run('node ./src/main.js "echo test" "echo test"', {pipe: DEBUG_TESTS})
35
+ return run('node ./src/main.js "echo test" "echo test"')
36
36
  .then(function(exitCode) {
37
37
  assert.strictEqual(exitCode, 0);
38
38
  });
39
39
  });
40
40
 
41
41
  it('at least one unsuccessful commands should exit non-zero', () => {
42
- return run('node ./src/main.js "echo test" "nosuchcmd" "echo test"', {pipe: DEBUG_TESTS})
42
+ return run('node ./src/main.js "echo test" "nosuchcmd" "echo test"')
43
43
  .then(function(exitCode) {
44
44
  assert.notStrictEqual(exitCode, 0);
45
45
  });
46
46
  });
47
47
 
48
48
  it('--kill-others should kill other commands if one dies', () => {
49
- return run('node ./src/main.js --kill-others "sleep 1" "echo test" "sleep 0.1 && nosuchcmd"', {pipe: DEBUG_TESTS})
49
+ return run('node ./src/main.js --kill-others "sleep 1" "echo test" "sleep 0.1 && nosuchcmd"')
50
50
  .then(function(exitCode) {
51
51
  assert.notStrictEqual(exitCode, 0);
52
52
  });
53
53
  });
54
54
 
55
55
  it('--kill-others-on-fail should kill other commands if one exits with non-zero status code', () => {
56
- return run('node ./src/main.js --kill-others-on-fail "sleep 1" "exit 1" "sleep 1"', {pipe: DEBUG_TESTS})
56
+ return run('node ./src/main.js --kill-others-on-fail "sleep 1" "exit 1" "sleep 1"')
57
57
  .then(function(exitCode) {
58
58
  assert.notStrictEqual(exitCode, 0);
59
59
  });
@@ -65,27 +65,15 @@ describe('concurrently', function() {
65
65
  var sigtermInOutput = false;
66
66
 
67
67
  run('node ./src/main.js --kill-others-on-fail "echo killTest1" "echo killTest2" "echo killTest3"', {
68
- pipe: false,
69
- callback: function(child) {
70
- var rl = readline.createInterface({
71
- input: child.stdout,
72
- output: null
73
- });
74
-
75
- rl.on('line', function(line) {
76
- if (DEBUG_TESTS) {
77
- console.log(line);
78
- }
79
-
80
- if (/SIGTERM/.test(line)) {
81
- sigtermInOutput = true;
82
- }
83
-
84
- // waiting for exits
85
- if (/killTest\d$/.test(line)) {
86
- exits++;
87
- }
88
- });
68
+ onOutputLine: function(line) {
69
+ if (/SIGTERM/.test(line)) {
70
+ sigtermInOutput = true;
71
+ }
72
+
73
+ // waiting for exits
74
+ if (/killTest\d$/.test(line)) {
75
+ exits++;
76
+ }
89
77
  }
90
78
  }).then(function() {
91
79
  if(sigtermInOutput) {
@@ -99,7 +87,7 @@ describe('concurrently', function() {
99
87
  });
100
88
 
101
89
  it('--success=first should return first exit code', () => {
102
- return run('node ./src/main.js -k --success first "echo test" "sleep 0.1 && nosuchcmd"', {pipe: DEBUG_TESTS})
90
+ return run('node ./src/main.js -k --success first "echo test" "sleep 0.1 && nosuchcmd"')
103
91
  // When killed, sleep returns null exit code
104
92
  .then(function(exitCode) {
105
93
  assert.strictEqual(exitCode, 0);
@@ -108,26 +96,138 @@ describe('concurrently', function() {
108
96
 
109
97
  it('--success=last should return last exit code', () => {
110
98
  // When killed, sleep returns null exit code
111
- return run('node ./src/main.js -k --success last "echo test" "sleep 0.1 && nosuchcmd"', {pipe: DEBUG_TESTS})
99
+ return run('node ./src/main.js -k --success last "echo test" "sleep 0.1 && nosuchcmd"')
112
100
  .then(function(exitCode) {
113
101
  assert.notStrictEqual(exitCode, 0);
114
102
  });
115
103
  });
116
104
 
117
105
  it('&& nosuchcmd should return non-zero exit code', () => {
118
- return run('node ./src/main.js "echo 1 && nosuchcmd" "echo 1 && nosuchcmd" ', {pipe: DEBUG_TESTS})
106
+ return run('node ./src/main.js "echo 1 && nosuchcmd" "echo 1 && nosuchcmd" ')
119
107
  .then(function(exitCode) {
120
108
  assert.strictEqual(exitCode, 1);
121
109
  });
122
110
  });
123
111
 
124
112
  it('--prefix-colors should handle non-existent colors without failing', () => {
125
- return run('node ./src/main.js -c "not.a.color" "echo colors"', {pipe: DEBUG_TESTS})
113
+ return run('node ./src/main.js -c "not.a.color" "echo colors"')
126
114
  .then(function(exitCode) {
127
115
  assert.strictEqual(exitCode, 0);
128
116
  });
129
117
  });
130
118
 
119
+ it('--prefix should default to "index"', () => {
120
+ var collectedLines = []
121
+
122
+ return run('node ./src/main.js "echo one" "echo two"', {
123
+ onOutputLine: (line) => {
124
+ if (/(one|two)$/.exec(line)) {
125
+ collectedLines.push(line)
126
+ }
127
+ }
128
+ })
129
+ .then(function(exitCode) {
130
+ assert.strictEqual(exitCode, 0);
131
+
132
+ collectedLines.sort()
133
+ assert.deepEqual(collectedLines, [
134
+ '[0] one',
135
+ '[1] two'
136
+ ])
137
+ });
138
+ });
139
+
140
+ it('--names should set a different default prefix', () => {
141
+ var collectedLines = []
142
+
143
+ return run('node ./src/main.js -n aa,bb "echo one" "echo two"', {
144
+ onOutputLine: (line) => {
145
+ if (/(one|two)$/.exec(line)) {
146
+ collectedLines.push(line)
147
+ }
148
+ }
149
+ })
150
+ .then(function(exitCode) {
151
+ assert.strictEqual(exitCode, 0);
152
+
153
+ collectedLines.sort()
154
+ assert.deepEqual(collectedLines, [
155
+ '[aa] one',
156
+ '[bb] two'
157
+ ])
158
+ });
159
+ });
160
+
161
+ it('--allow-restart should restart a proccess with non-zero exit code', (done) => {
162
+ var readline = require('readline');
163
+ var exitedWithOne = false;
164
+ var restarted = false;
165
+
166
+ run('node ./src/main.js --allow-restart "sleep 0.1 && exit 1" "sleep 1"', {
167
+ pipe: false,
168
+ onOutputLine: (line) => {
169
+ var re = /exited with code (.+)/.exec(line);
170
+ if (re && re[1] === '1') {
171
+ exitedWithOne = true
172
+ }
173
+
174
+ if (/restarted/.test(line)) {
175
+ restarted = true;
176
+ }
177
+ }
178
+ }).then(function() {
179
+ if (exitedWithOne && restarted) {
180
+ done();
181
+ } else {
182
+ done(new Error('No restarted process exited with code 1'));
183
+ }
184
+ });
185
+ });
186
+
187
+ it('--restart-after=n should restart a proccess after n miliseconds', (done) => {
188
+ var readline = require('readline');
189
+ var start, end;
190
+
191
+ run('node ./src/main.js --allow-restart --restart-after 300 "exit 1" "sleep 1"', {
192
+ pipe: false,
193
+ onOutputLine: (line) => {
194
+ if (!start && /exited with code (.+)/.test(line)) {
195
+ start = new Date().getTime();
196
+ }
197
+
198
+ if (!end && /restarted/.test(line)) {
199
+ end = new Date().getTime();
200
+ }
201
+ }
202
+ }).then(function() {
203
+ // we accept 100 miliseconds of error
204
+ if (end - start >= 300 && end - start < 400) {
205
+ done();
206
+ } else {
207
+ done(new Error('No restarted process after 300 miliseconds'));
208
+ }
209
+ });
210
+ });
211
+ it('--restart-tries=n should restart a proccess at most n times', (done) => {
212
+ var readline = require('readline');
213
+ var restartedTimes = 0;
214
+
215
+ run('node ./src/main.js --allow-restart --restart-tries 2 "exit 1" "sleep 1"', {
216
+ pipe: false,
217
+ onOutputLine: (line) => {
218
+ if (/restarted/.test(line)) {
219
+ restartedTimes++;
220
+ }
221
+ }
222
+ }).then(function() {
223
+ if (restartedTimes == 2) {
224
+ done();
225
+ } else {
226
+ done(new Error('No restarted process twice'));
227
+ }
228
+ });
229
+ });
230
+
131
231
  ['SIGINT', 'SIGTERM'].forEach((signal) => {
132
232
  if (IS_WINDOWS) {
133
233
  console.log('IS_WINDOWS=true');
@@ -149,32 +249,20 @@ describe('concurrently', function() {
149
249
  }
150
250
 
151
251
  run('node ./src/main.js "node ./test/support/signal.js" "node ./test/support/signal.js"', {
152
- pipe: false,
153
- callback: function(child) {
154
- var rl = readline.createInterface({
155
- input: child.stdout,
156
- output: null
157
- });
252
+ onOutputLine: function(line, child) {
253
+ // waiting for startup
254
+ if (/STARTED/.test(line)) {
255
+ waitingStart--;
256
+ }
257
+ if (!waitingStart) {
258
+ // both processes are started
259
+ child.kill(signal);
260
+ }
158
261
 
159
- rl.on('line', function(line) {
160
- if (DEBUG_TESTS) {
161
- console.log(line);
162
- }
163
-
164
- // waiting for startup
165
- if (/STARTED/.test(line)) {
166
- waitingStart--;
167
- }
168
- if (!waitingStart) {
169
- // both processes are started
170
- child.kill(signal);
171
- }
172
-
173
- // waiting for signal
174
- if (new RegExp(signal).test(line)) {
175
- waitingSignal--;
176
- }
177
- });
262
+ // waiting for signal
263
+ if (new RegExp(signal).test(line)) {
264
+ waitingSignal--;
265
+ }
178
266
  }
179
267
  }).then(function() {
180
268
  waitForSignal(done);
package/test/utils.js CHANGED
@@ -1,31 +1,31 @@
1
1
  var childProcess = require('child_process');
2
2
  var _ = require('lodash');
3
+ var readline = require('readline')
3
4
  var shellQuote = require('shell-quote');
4
5
 
6
+ // If true, output of commands are shown
7
+ var DEBUG_TESTS = process.env.DEBUG_TESTS === 'true';
8
+
5
9
  function run(cmd, opts) {
6
10
  opts = _.merge({
7
- pipe: true,
8
- cwd: undefined,
9
- callback: function(child) {
10
- // Since we return promise, we need to provide
11
- // this callback if one wants to access the child
12
- // process reference
13
- // Called immediately after successful child process
14
- // spawn
15
- }
11
+ // If set to a function, it will be called for each line
12
+ // written to the child process's stdout as (line, child)
13
+ onOutputLine: undefined,
16
14
  }, opts);
17
15
 
18
16
  var child;
19
17
  var parts = shellQuote.parse(cmd);
20
18
  try {
21
19
  child = childProcess.spawn(_.head(parts), _.tail(parts), {
22
- cwd: opts.cwd,
23
- stdio: opts.pipe ? "inherit" : null
20
+ stdio: DEBUG_TESTS && !opts.onOutputLine ? 'inherit': null,
24
21
  });
25
22
  } catch (e) {
26
23
  return Promise.reject(e);
27
24
  }
28
- opts.callback(child);
25
+
26
+ if (opts.onOutputLine) {
27
+ readLines(child, opts.onOutputLine);
28
+ }
29
29
 
30
30
  return new Promise(function(resolve, reject) {
31
31
  child.on('error', function(err) {
@@ -38,6 +38,21 @@ function run(cmd, opts) {
38
38
  });
39
39
  }
40
40
 
41
+ function readLines(child, callback) {
42
+ var rl = readline.createInterface({
43
+ input: child.stdout,
44
+ output: null
45
+ });
46
+
47
+ rl.on('line', function(line) {
48
+ if (DEBUG_TESTS) {
49
+ console.log(line);
50
+ }
51
+
52
+ callback(line, child)
53
+ });
54
+ }
55
+
41
56
  module.exports = {
42
57
  run: run
43
58
  };
package/.eslintrc DELETED
@@ -1,31 +0,0 @@
1
- {
2
- "env": {
3
- "browser": true,
4
- "node": true
5
- },
6
- "globals": {},
7
- "rules": {
8
- "no-bitwise": 2,
9
- "camelcase": 2,
10
- "curly": 2,
11
- "eqeqeq": 2,
12
- "wrap-iife": [
13
- 2,
14
- "any"
15
- ],
16
- "indent": [
17
- 2,
18
- 4,
19
- {
20
- "SwitchCase": 1
21
- }
22
- ],
23
- "no-use-before-define": 0,
24
- "new-cap": 2,
25
- "no-caller": 2,
26
- "quotes": [
27
- 2,
28
- "single"
29
- ]
30
- }
31
- }
package/tst.js DELETED
@@ -1 +0,0 @@
1
- setTimeout(() =>console.log("i win!"), 3000);