Skip to content

Commit

Permalink
Add --group option (#272)
Browse files Browse the repository at this point in the history
  • Loading branch information
cdrini committed Dec 28, 2021
1 parent ba384de commit 219e5df
Show file tree
Hide file tree
Showing 9 changed files with 283 additions and 66 deletions.
15 changes: 15 additions & 0 deletions bin/concurrently.spec.ts
Expand Up @@ -184,6 +184,21 @@ describe('--hide', () => {
});
});

describe('--group', () => {
it('groups output per process', done => {
const child = run('--group "echo foo && sleep 1 && echo bar" "echo baz"');
child.log.pipe(buffer(child.close)).subscribe(lines => {
expect(lines.slice(0, 4)).toEqual([
expect.stringContaining('foo'),
expect.stringContaining('bar'),
expect.any(String),
expect.stringContaining('baz'),
]);
done();
}, done);
});
});

describe('--names', () => {
it('is aliased to -n', done => {
const child = run('-n foo,bar "echo foo" "echo bar"');
Expand Down
8 changes: 7 additions & 1 deletion bin/concurrently.ts
Expand Up @@ -65,6 +65,11 @@ const args = yargs
default: defaults.hide,
type: 'string'
},
'group': {
alias: 'g',
describe: 'Order the output as if the commands were run sequentially.',
type: 'boolean'
},
'timings': {
describe: 'Show timing information for all processes',
type: 'boolean',
Expand Down Expand Up @@ -150,7 +155,7 @@ const args = yargs
'Can be either the index or the name of the process.'
}
})
.group(['m', 'n', 'name-separator', 'raw', 's', 'no-color', 'hide', 'timings'], 'General')
.group(['m', 'n', 'name-separator', 'raw', 's', 'no-color', 'hide', 'group', 'timings'], 'General')
.group(['p', 'c', 'l', 't'], 'Prefix styling')
.group(['i', 'default-input-target'], 'Input handling')
.group(['k', 'kill-others-on-fail'], 'Killing other processes')
Expand All @@ -172,6 +177,7 @@ concurrently(args._.map((command, index) => ({
maxProcesses: args.maxProcesses,
raw: args.raw,
hide: args.hide.split(','),
group: args.group,
prefix: args.prefix,
prefixColors: args['prefix-colors'].split(','),
prefixLength: args.prefixLength,
Expand Down
4 changes: 3 additions & 1 deletion index.js
Expand Up @@ -13,7 +13,6 @@ const LogTimings = require( './src/flow-control/log-timings' );
module.exports = exports = (commands, options = {}) => {
const logger = new Logger({
hide: options.hide,
outputStream: options.outputStream || process.stdout,
prefixFormat: options.prefix,
prefixLength: options.prefixLength,
raw: options.raw,
Expand All @@ -25,6 +24,9 @@ module.exports = exports = (commands, options = {}) => {
raw: options.raw,
successCondition: options.successCondition,
cwd: options.cwd,
logger,
outputStream: options.outputStream || process.stdout,
group: options.group,
controllers: [
new LogError({ logger }),
new LogOutput({ logger }),
Expand Down
3 changes: 3 additions & 0 deletions src/command.ts
Expand Up @@ -59,6 +59,7 @@ export class Command implements CommandInfo {
stdin?: Writable;
pid?: number;
killed = false;
exited = false;

get killable() {
return !!this.process;
Expand Down Expand Up @@ -96,6 +97,8 @@ export class Command implements CommandInfo {
});
Rx.fromEvent<[number | null, NodeJS.Signals | null]>(child, 'close').subscribe(([exitCode, signal]) => {
this.process = undefined;
this.exited = true;

const endDate = new Date(Date.now());
this.timer.next({ startDate, endDate });
const [durationSeconds, durationNanoSeconds] = process.hrtime(highResStartTime);
Expand Down
11 changes: 11 additions & 0 deletions src/concurrently.js
Expand Up @@ -11,6 +11,7 @@ const CompletionListener = require('./completion-listener');

const { getSpawnOpts } = require('./get-spawn-opts');
const { Command } = require('./command');
const { OutputWriter } = require('./output-writer');

const defaults = {
spawn,
Expand Down Expand Up @@ -63,6 +64,16 @@ module.exports = (commands, options) => {
);
commands = handleResult.commands;


if (options.logger) {
const outputWriter = new OutputWriter({
outputStream: options.outputStream,
group: options.group,
commands,
});
options.logger.output.subscribe(({command, text}) => outputWriter.write(command, text));
}

const commandsLeft = commands.slice();
const maxProcesses = Math.max(1, Number(options.maxProcesses) || commandsLeft.length);
for (let i = 0; i < maxProcesses; i++) {
Expand Down
21 changes: 13 additions & 8 deletions src/logger.js
@@ -1,20 +1,21 @@
const chalk = require('chalk');
const _ = require('lodash');
const formatDate = require('date-fns/format');
const Rx = require('rxjs');

const defaults = require('./defaults');

module.exports = class Logger {
constructor({ hide, outputStream, prefixFormat, prefixLength, raw, timestampFormat }) {
constructor({ hide, prefixFormat, prefixLength, raw, timestampFormat }) {
// To avoid empty strings from hiding the output of commands that don't have a name,
// keep in the list of commands to hide only strings with some length.
// This might happen through the CLI when no `--hide` argument is specified, for example.
this.hide = _.castArray(hide).filter(name => name || name === 0).map(String);
this.raw = raw;
this.outputStream = outputStream;
this.prefixFormat = prefixFormat;
this.prefixLength = prefixLength || defaults.prefixLength;
this.timestampFormat = timestampFormat || defaults.timestampFormat;
this.output = new Rx.Subject();
}

shortenText(text) {
Expand Down Expand Up @@ -85,15 +86,15 @@ module.exports = class Logger {
}

const prefix = this.colorText(command, this.getPrefix(command));
return this.log(prefix + (prefix ? ' ' : ''), text);
return this.log(prefix + (prefix ? ' ' : ''), text, command);
}

logGlobalEvent(text) {
if (this.raw) {
return;
}

this.log(chalk.reset('-->') + ' ', chalk.reset(text) + '\n');
this.log(chalk.reset('-->') + ' ', chalk.reset(text) + '\n', null);
}

logTable(tableContents) {
Expand Down Expand Up @@ -153,9 +154,9 @@ module.exports = class Logger {
this.logGlobalEvent(`└─${borderRowFormatted.join('─┴─')}─┘`);
}

log(prefix, text) {
log(prefix, text, command) {
if (this.raw) {
return this.outputStream.write(text);
return this.emit(command, text);
}

// #70 - replace some ANSI code that would impact clearing lines
Expand All @@ -171,10 +172,14 @@ module.exports = class Logger {
});

if (!this.lastChar || this.lastChar === '\n') {
this.outputStream.write(prefix);
this.emit(command, prefix);
}

this.lastChar = text[text.length - 1];
this.outputStream.write(lines.join('\n'));
this.emit(command, lines.join('\n'));
}

emit(command, text) {
this.output.next({ command, text });
}
};

0 comments on commit 219e5df

Please sign in to comment.