concurrently 7.5.0 → 7.6.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 +13 -13
- package/dist/bin/concurrently.js +3 -2
- package/dist/src/command-parser/expand-arguments.d.ts +3 -3
- package/dist/src/command-parser/expand-npm-wildcard.js +9 -7
- package/dist/src/command-parser/strip-quotes.d.ts +3 -3
- package/dist/src/command.d.ts +15 -5
- package/dist/src/command.js +16 -7
- package/dist/src/completion-listener.d.ts +2 -1
- package/dist/src/completion-listener.js +5 -2
- package/dist/src/concurrently.d.ts +7 -4
- package/dist/src/concurrently.js +7 -8
- package/dist/src/flow-control/input-handler.d.ts +2 -2
- package/dist/src/flow-control/input-handler.js +5 -4
- package/dist/src/flow-control/kill-others.d.ts +2 -2
- package/dist/src/flow-control/kill-others.js +3 -2
- package/dist/src/flow-control/log-timings.js +10 -7
- package/dist/src/get-spawn-opts.d.ts +5 -5
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +3 -3
- package/dist/src/logger.js +2 -1
- package/dist/src/prefix-color-selector.js +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://github.com/open-cli-tools/concurrently/releases)
|
|
4
4
|
[](https://github.com/open-cli-tools/concurrently/blob/main/LICENSE)
|
|
5
5
|
[](https://www.npmjs.com/package/concurrently)
|
|
6
|
-
[](https://github.com/open-cli-tools/concurrently/actions/workflows/test.yml)
|
|
7
7
|
[](https://coveralls.io/github/open-cli-tools/concurrently?branch=main)
|
|
8
8
|
|
|
9
9
|
Run multiple commands concurrently.
|
|
@@ -15,7 +15,7 @@ Like `npm run watch-js & npm run watch-less` but better.
|
|
|
15
15
|
|
|
16
16
|
- [concurrently](#concurrently)
|
|
17
17
|
- [Why](#why)
|
|
18
|
-
- [
|
|
18
|
+
- [Installation](#installation)
|
|
19
19
|
- [Usage](#usage)
|
|
20
20
|
- [API](#api)
|
|
21
21
|
- [`concurrently(commands[, options])`](#concurrentlycommands-options)
|
|
@@ -41,25 +41,24 @@ tired of opening terminals and made **concurrently**.
|
|
|
41
41
|
- With `--kill-others` switch, all commands are killed if one dies
|
|
42
42
|
- Spawns commands with [spawn-command](https://github.com/mmalecki/spawn-command)
|
|
43
43
|
|
|
44
|
-
##
|
|
44
|
+
## Installation
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
```bash
|
|
49
|
-
npm install -g concurrently
|
|
50
|
-
```
|
|
46
|
+
**concurrently** can be installed in the global scope (if you'd like to have it available and use it on the whole system) or locally for a specific package (for example if you'd like to use it in the `scripts` section of your package):
|
|
51
47
|
|
|
52
|
-
|
|
48
|
+
| | npm | Yarn | pnpm |
|
|
49
|
+
| ----------- | ----------------------- | ------------------------------ | -------------------------- |
|
|
50
|
+
| **Global** | `npm i -g concurrently` | `yarn global add concurrently` | `pnpm add -g concurrently` |
|
|
51
|
+
| **Local**\* | `npm i concurrently -D` | `yarn add concurrently -D` | `pnpm add -D concurrently` |
|
|
53
52
|
|
|
54
|
-
|
|
55
|
-
npm install concurrently --save
|
|
56
|
-
```
|
|
53
|
+
<sub>\* It's recommended to add **concurrently** as `devDependencies` as it's usually used for developing purposes. Please change this flag if this doesn't apply in your case.</sub>
|
|
57
54
|
|
|
58
55
|
## Usage
|
|
59
56
|
|
|
60
57
|
> **Note**
|
|
61
58
|
> The `concurrently` command is now also available under the shorthand alias `conc`.
|
|
62
59
|
|
|
60
|
+
The tool is written in Node.js, but you can use it to run **any** commands.
|
|
61
|
+
|
|
63
62
|
Remember to surround separate commands with quotes:
|
|
64
63
|
|
|
65
64
|
```bash
|
|
@@ -146,8 +145,9 @@ concurrently [options] <command ...>
|
|
|
146
145
|
|
|
147
146
|
General
|
|
148
147
|
-m, --max-processes How many processes should run at once.
|
|
148
|
+
Exact number or a percent of CPUs available (for example "50%").
|
|
149
149
|
New processes only spawn after all restart tries
|
|
150
|
-
of a process. [
|
|
150
|
+
of a process. [string]
|
|
151
151
|
-n, --names List of custom names to be used in prefix
|
|
152
152
|
template.
|
|
153
153
|
Example names: "main,browser,server" [string]
|
package/dist/bin/concurrently.js
CHANGED
|
@@ -54,8 +54,9 @@ const args = (0, yargs_1.default)(argsBeforeSep)
|
|
|
54
54
|
'max-processes': {
|
|
55
55
|
alias: 'm',
|
|
56
56
|
describe: 'How many processes should run at once.\n' +
|
|
57
|
-
'New processes only spawn after all restart tries of a process
|
|
58
|
-
|
|
57
|
+
'New processes only spawn after all restart tries of a process.\n' +
|
|
58
|
+
'Exact number or a percent of CPUs available (for example "50%")',
|
|
59
|
+
type: 'string',
|
|
59
60
|
},
|
|
60
61
|
names: {
|
|
61
62
|
alias: 'n',
|
|
@@ -9,8 +9,8 @@ export declare class ExpandArguments implements CommandParser {
|
|
|
9
9
|
parse(commandInfo: CommandInfo): {
|
|
10
10
|
command: string;
|
|
11
11
|
name: string;
|
|
12
|
-
env?: Record<string, unknown
|
|
13
|
-
cwd?: string;
|
|
14
|
-
prefixColor?: string;
|
|
12
|
+
env?: Record<string, unknown> | undefined;
|
|
13
|
+
cwd?: string | undefined;
|
|
14
|
+
prefixColor?: string | undefined;
|
|
15
15
|
};
|
|
16
16
|
}
|
|
@@ -12,9 +12,6 @@ const OMISSION = /\(!([^)]+)\)/;
|
|
|
12
12
|
* `package.json` file of the current directory.
|
|
13
13
|
*/
|
|
14
14
|
class ExpandNpmWildcard {
|
|
15
|
-
constructor(readPackage = ExpandNpmWildcard.readPackage) {
|
|
16
|
-
this.readPackage = readPackage;
|
|
17
|
-
}
|
|
18
15
|
static readPackage() {
|
|
19
16
|
try {
|
|
20
17
|
const json = fs_1.default.readFileSync('package.json', { encoding: 'utf-8' });
|
|
@@ -24,6 +21,9 @@ class ExpandNpmWildcard {
|
|
|
24
21
|
return {};
|
|
25
22
|
}
|
|
26
23
|
}
|
|
24
|
+
constructor(readPackage = ExpandNpmWildcard.readPackage) {
|
|
25
|
+
this.readPackage = readPackage;
|
|
26
|
+
}
|
|
27
27
|
parse(commandInfo) {
|
|
28
28
|
const [, npmCmd, cmdName, args] = commandInfo.command.match(/(npm|yarn|pnpm) run (\S+)([^&]*)/) || [];
|
|
29
29
|
const wildcardPosition = (cmdName || '').indexOf('*');
|
|
@@ -40,7 +40,9 @@ class ExpandNpmWildcard {
|
|
|
40
40
|
const preWildcard = lodash_1.default.escapeRegExp(cmdNameSansOmission.slice(0, wildcardPosition));
|
|
41
41
|
const postWildcard = lodash_1.default.escapeRegExp(cmdNameSansOmission.slice(wildcardPosition + 1));
|
|
42
42
|
const wildcardRegex = new RegExp(`^${preWildcard}(.*?)${postWildcard}$`);
|
|
43
|
-
|
|
43
|
+
// If 'commandInfo.name' doesn't match 'cmdName', this means a custom name
|
|
44
|
+
// has been specified and thus becomes the prefix (as described in the README).
|
|
45
|
+
const prefix = commandInfo.name !== cmdName ? commandInfo.name : '';
|
|
44
46
|
return this.scripts
|
|
45
47
|
.map((script) => {
|
|
46
48
|
const match = script.match(wildcardRegex);
|
|
@@ -54,9 +56,9 @@ class ExpandNpmWildcard {
|
|
|
54
56
|
return {
|
|
55
57
|
...commandInfo,
|
|
56
58
|
command: `${npmCmd} run ${script}${args}`,
|
|
57
|
-
// Will use an empty command name if
|
|
58
|
-
// e.g. if `npm:watch-*` matches `npm run watch-`.
|
|
59
|
-
name:
|
|
59
|
+
// Will use an empty command name if no prefix has been specified and
|
|
60
|
+
// the wildcard match is empty, e.g. if `npm:watch-*` matches `npm run watch-`.
|
|
61
|
+
name: prefix + match[1],
|
|
60
62
|
};
|
|
61
63
|
}
|
|
62
64
|
})
|
|
@@ -7,8 +7,8 @@ export declare class StripQuotes implements CommandParser {
|
|
|
7
7
|
parse(commandInfo: CommandInfo): {
|
|
8
8
|
command: string;
|
|
9
9
|
name: string;
|
|
10
|
-
env?: Record<string, unknown
|
|
11
|
-
cwd?: string;
|
|
12
|
-
prefixColor?: string;
|
|
10
|
+
env?: Record<string, unknown> | undefined;
|
|
11
|
+
cwd?: string | undefined;
|
|
12
|
+
prefixColor?: string | undefined;
|
|
13
13
|
};
|
|
14
14
|
}
|
package/dist/src/command.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { EventEmitter, Writable } from 'stream';
|
|
|
8
8
|
/**
|
|
9
9
|
* Identifier for a command; if string, it's the command's name, if number, it's the index.
|
|
10
10
|
*/
|
|
11
|
-
export
|
|
11
|
+
export type CommandIdentifier = string | number;
|
|
12
12
|
export interface CommandInfo {
|
|
13
13
|
/**
|
|
14
14
|
* Command's name.
|
|
@@ -58,15 +58,15 @@ export interface TimerEvent {
|
|
|
58
58
|
/**
|
|
59
59
|
* Subtype of NodeJS's child_process including only what's actually needed for a command to work.
|
|
60
60
|
*/
|
|
61
|
-
export
|
|
61
|
+
export type ChildProcess = EventEmitter & Pick<BaseChildProcess, 'pid' | 'stdin' | 'stdout' | 'stderr'>;
|
|
62
62
|
/**
|
|
63
63
|
* Interface for a function that must kill the process with `pid`, optionally sending `signal` to it.
|
|
64
64
|
*/
|
|
65
|
-
export
|
|
65
|
+
export type KillProcess = (pid: number, signal?: string) => void;
|
|
66
66
|
/**
|
|
67
67
|
* Interface for a function that spawns a command and returns its child process instance.
|
|
68
68
|
*/
|
|
69
|
-
export
|
|
69
|
+
export type SpawnCommand = (command: string, options: SpawnOptions) => ChildProcess;
|
|
70
70
|
export declare class Command implements CommandInfo {
|
|
71
71
|
private readonly killProcess;
|
|
72
72
|
private readonly spawn;
|
|
@@ -77,7 +77,7 @@ export declare class Command implements CommandInfo {
|
|
|
77
77
|
/** @inheritdoc */
|
|
78
78
|
readonly command: string;
|
|
79
79
|
/** @inheritdoc */
|
|
80
|
-
readonly prefixColor
|
|
80
|
+
readonly prefixColor?: string;
|
|
81
81
|
/** @inheritdoc */
|
|
82
82
|
readonly env: Record<string, unknown>;
|
|
83
83
|
/** @inheritdoc */
|
|
@@ -92,6 +92,7 @@ export declare class Command implements CommandInfo {
|
|
|
92
92
|
pid?: number;
|
|
93
93
|
killed: boolean;
|
|
94
94
|
exited: boolean;
|
|
95
|
+
/** @deprecated */
|
|
95
96
|
get killable(): boolean;
|
|
96
97
|
constructor({ index, name, command, prefixColor, env, cwd }: CommandInfo & {
|
|
97
98
|
index: number;
|
|
@@ -104,4 +105,13 @@ export declare class Command implements CommandInfo {
|
|
|
104
105
|
* Kills this command, optionally specifying a signal to send to it.
|
|
105
106
|
*/
|
|
106
107
|
kill(code?: string): void;
|
|
108
|
+
/**
|
|
109
|
+
* Detects whether a command can be killed.
|
|
110
|
+
*
|
|
111
|
+
* Also works as a type guard on the input `command`.
|
|
112
|
+
*/
|
|
113
|
+
static canKill(command: Command): command is Command & {
|
|
114
|
+
pid: number;
|
|
115
|
+
process: ChildProcess;
|
|
116
|
+
};
|
|
107
117
|
}
|
package/dist/src/command.js
CHANGED
|
@@ -26,6 +26,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
26
26
|
exports.Command = void 0;
|
|
27
27
|
const Rx = __importStar(require("rxjs"));
|
|
28
28
|
class Command {
|
|
29
|
+
/** @deprecated */
|
|
30
|
+
get killable() {
|
|
31
|
+
return Command.canKill(this);
|
|
32
|
+
}
|
|
29
33
|
constructor({ index, name, command, prefixColor, env, cwd }, spawnOpts, spawn, killProcess) {
|
|
30
34
|
this.close = new Rx.Subject();
|
|
31
35
|
this.error = new Rx.Subject();
|
|
@@ -38,15 +42,12 @@ class Command {
|
|
|
38
42
|
this.name = name;
|
|
39
43
|
this.command = command;
|
|
40
44
|
this.prefixColor = prefixColor;
|
|
41
|
-
this.env = env;
|
|
45
|
+
this.env = env || {};
|
|
42
46
|
this.cwd = cwd;
|
|
43
47
|
this.killProcess = killProcess;
|
|
44
48
|
this.spawn = spawn;
|
|
45
49
|
this.spawnOpts = spawnOpts;
|
|
46
50
|
}
|
|
47
|
-
get killable() {
|
|
48
|
-
return !!this.process;
|
|
49
|
-
}
|
|
50
51
|
/**
|
|
51
52
|
* Starts this command, piping output, error and close events onto the corresponding observables.
|
|
52
53
|
*/
|
|
@@ -72,7 +73,7 @@ class Command {
|
|
|
72
73
|
this.close.next({
|
|
73
74
|
command: this,
|
|
74
75
|
index: this.index,
|
|
75
|
-
exitCode: exitCode
|
|
76
|
+
exitCode: exitCode !== null && exitCode !== void 0 ? exitCode : String(signal),
|
|
76
77
|
killed: this.killed,
|
|
77
78
|
timings: {
|
|
78
79
|
startDate,
|
|
@@ -83,17 +84,25 @@ class Command {
|
|
|
83
84
|
});
|
|
84
85
|
child.stdout && pipeTo(Rx.fromEvent(child.stdout, 'data'), this.stdout);
|
|
85
86
|
child.stderr && pipeTo(Rx.fromEvent(child.stderr, 'data'), this.stderr);
|
|
86
|
-
this.stdin = child.stdin;
|
|
87
|
+
this.stdin = child.stdin || undefined;
|
|
87
88
|
}
|
|
88
89
|
/**
|
|
89
90
|
* Kills this command, optionally specifying a signal to send to it.
|
|
90
91
|
*/
|
|
91
92
|
kill(code) {
|
|
92
|
-
if (this
|
|
93
|
+
if (Command.canKill(this)) {
|
|
93
94
|
this.killed = true;
|
|
94
95
|
this.killProcess(this.pid, code);
|
|
95
96
|
}
|
|
96
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* Detects whether a command can be killed.
|
|
100
|
+
*
|
|
101
|
+
* Also works as a type guard on the input `command`.
|
|
102
|
+
*/
|
|
103
|
+
static canKill(command) {
|
|
104
|
+
return !!command.pid && !!command.process;
|
|
105
|
+
}
|
|
97
106
|
}
|
|
98
107
|
exports.Command = Command;
|
|
99
108
|
/**
|
|
@@ -9,7 +9,7 @@ import { CloseEvent, Command } from './command';
|
|
|
9
9
|
* - `command-{name|index}`: only the commands with the specified names or index.
|
|
10
10
|
* - `!command-{name|index}`: all commands but the ones with the specified names or index.
|
|
11
11
|
*/
|
|
12
|
-
export
|
|
12
|
+
export type SuccessCondition = 'first' | 'last' | 'all' | `command-${string | number}` | `!command-${string | number}`;
|
|
13
13
|
/**
|
|
14
14
|
* Provides logic to determine whether lists of commands ran successfully.
|
|
15
15
|
*/
|
|
@@ -36,4 +36,5 @@ export declare class CompletionListener {
|
|
|
36
36
|
* @returns A Promise that resolves if the success condition is met, or rejects otherwise.
|
|
37
37
|
*/
|
|
38
38
|
listen(commands: Command[]): Promise<CloseEvent[]>;
|
|
39
|
+
private emitWithScheduler;
|
|
39
40
|
}
|
|
@@ -67,8 +67,11 @@ class CompletionListener {
|
|
|
67
67
|
listen(commands) {
|
|
68
68
|
const closeStreams = commands.map((command) => command.close);
|
|
69
69
|
return Rx.lastValueFrom(Rx.merge(...closeStreams).pipe((0, operators_1.bufferCount)(closeStreams.length), (0, operators_1.switchMap)((exitInfos) => this.isSuccess(exitInfos)
|
|
70
|
-
? Rx.of(exitInfos
|
|
71
|
-
: Rx.throwError(exitInfos
|
|
70
|
+
? this.emitWithScheduler(Rx.of(exitInfos))
|
|
71
|
+
: this.emitWithScheduler(Rx.throwError(exitInfos))), (0, operators_1.take)(1)));
|
|
72
|
+
}
|
|
73
|
+
emitWithScheduler(input) {
|
|
74
|
+
return this.scheduler ? input.pipe(Rx.observeOn(this.scheduler)) : input;
|
|
72
75
|
}
|
|
73
76
|
}
|
|
74
77
|
exports.CompletionListener = CompletionListener;
|
|
@@ -9,8 +9,10 @@ import { Logger } from './logger';
|
|
|
9
9
|
* If value is a string, then that's the command's command line.
|
|
10
10
|
* Fine grained options can be defined by using the object format.
|
|
11
11
|
*/
|
|
12
|
-
export
|
|
13
|
-
|
|
12
|
+
export type ConcurrentlyCommandInput = string | ({
|
|
13
|
+
command: string;
|
|
14
|
+
} & Partial<CommandInfo>);
|
|
15
|
+
export type ConcurrentlyResult = {
|
|
14
16
|
/**
|
|
15
17
|
* All commands created and ran by concurrently.
|
|
16
18
|
*/
|
|
@@ -23,7 +25,7 @@ export declare type ConcurrentlyResult = {
|
|
|
23
25
|
*/
|
|
24
26
|
result: Promise<CloseEvent[]>;
|
|
25
27
|
};
|
|
26
|
-
export
|
|
28
|
+
export type ConcurrentlyOptions = {
|
|
27
29
|
logger?: Logger;
|
|
28
30
|
/**
|
|
29
31
|
* Which stream should the commands output be written to.
|
|
@@ -39,11 +41,12 @@ export declare type ConcurrentlyOptions = {
|
|
|
39
41
|
prefixColors?: string[];
|
|
40
42
|
/**
|
|
41
43
|
* Maximum number of commands to run at once.
|
|
44
|
+
* Exact number or a percent of CPUs available (for example "50%").
|
|
42
45
|
*
|
|
43
46
|
* If undefined, then all processes will start in parallel.
|
|
44
47
|
* Setting this value to 1 will achieve sequential running.
|
|
45
48
|
*/
|
|
46
|
-
maxProcesses?: number;
|
|
49
|
+
maxProcesses?: number | string;
|
|
47
50
|
/**
|
|
48
51
|
* Whether commands should be spawned in raw mode.
|
|
49
52
|
* Defaults to false.
|
package/dist/src/concurrently.js
CHANGED
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.concurrently = void 0;
|
|
7
7
|
const assert_1 = __importDefault(require("assert"));
|
|
8
8
|
const lodash_1 = __importDefault(require("lodash"));
|
|
9
|
+
const os_1 = require("os");
|
|
9
10
|
const spawn_command_1 = __importDefault(require("spawn-command"));
|
|
10
11
|
const tree_kill_1 = __importDefault(require("tree-kill"));
|
|
11
12
|
const command_1 = require("./command");
|
|
@@ -69,13 +70,15 @@ function concurrently(baseCommands, baseOptions) {
|
|
|
69
70
|
if (options.logger && options.outputStream) {
|
|
70
71
|
const outputWriter = new output_writer_1.OutputWriter({
|
|
71
72
|
outputStream: options.outputStream,
|
|
72
|
-
group: options.group,
|
|
73
|
+
group: !!options.group,
|
|
73
74
|
commands,
|
|
74
75
|
});
|
|
75
76
|
options.logger.output.subscribe(({ command, text }) => outputWriter.write(command, text));
|
|
76
77
|
}
|
|
77
78
|
const commandsLeft = commands.slice();
|
|
78
|
-
const maxProcesses = Math.max(1,
|
|
79
|
+
const maxProcesses = Math.max(1, (typeof options.maxProcesses === 'string' && options.maxProcesses.endsWith('%')
|
|
80
|
+
? Math.round(((0, os_1.cpus)().length * Number(options.maxProcesses.slice(0, -1))) / 100)
|
|
81
|
+
: Number(options.maxProcesses)) || commandsLeft.length);
|
|
79
82
|
for (let i = 0; i < maxProcesses; i++) {
|
|
80
83
|
maybeRunMore(commandsLeft);
|
|
81
84
|
}
|
|
@@ -92,13 +95,9 @@ function concurrently(baseCommands, baseOptions) {
|
|
|
92
95
|
exports.concurrently = concurrently;
|
|
93
96
|
function mapToCommandInfo(command) {
|
|
94
97
|
if (typeof command === 'string') {
|
|
95
|
-
return {
|
|
96
|
-
command,
|
|
97
|
-
name: '',
|
|
98
|
-
env: {},
|
|
99
|
-
cwd: '',
|
|
100
|
-
};
|
|
98
|
+
return mapToCommandInfo({ command });
|
|
101
99
|
}
|
|
100
|
+
assert_1.default.ok(command.command, '[concurrently] command cannot be empty');
|
|
102
101
|
return {
|
|
103
102
|
command: command.command,
|
|
104
103
|
name: command.name || '',
|
|
@@ -15,10 +15,10 @@ import { FlowController } from './flow-controller';
|
|
|
15
15
|
export declare class InputHandler implements FlowController {
|
|
16
16
|
private readonly logger;
|
|
17
17
|
private readonly defaultInputTarget;
|
|
18
|
-
private readonly inputStream
|
|
18
|
+
private readonly inputStream?;
|
|
19
19
|
private readonly pauseInputStreamOnFinish;
|
|
20
20
|
constructor({ defaultInputTarget, inputStream, pauseInputStreamOnFinish, logger, }: {
|
|
21
|
-
inputStream
|
|
21
|
+
inputStream?: Readable;
|
|
22
22
|
logger: Logger;
|
|
23
23
|
defaultInputTarget?: CommandIdentifier;
|
|
24
24
|
pauseInputStreamOnFinish?: boolean;
|
|
@@ -44,11 +44,12 @@ class InputHandler {
|
|
|
44
44
|
this.pauseInputStreamOnFinish = pauseInputStreamOnFinish !== false;
|
|
45
45
|
}
|
|
46
46
|
handle(commands) {
|
|
47
|
-
|
|
47
|
+
const { inputStream } = this;
|
|
48
|
+
if (!inputStream) {
|
|
48
49
|
return { commands };
|
|
49
50
|
}
|
|
50
|
-
Rx.fromEvent(
|
|
51
|
-
.pipe((0, operators_1.map)((data) => data
|
|
51
|
+
Rx.fromEvent(inputStream, 'data')
|
|
52
|
+
.pipe((0, operators_1.map)((data) => String(data)))
|
|
52
53
|
.subscribe((data) => {
|
|
53
54
|
const dataParts = data.split(/:(.+)/);
|
|
54
55
|
const targetId = dataParts.length > 1 ? dataParts[0] : this.defaultInputTarget;
|
|
@@ -67,7 +68,7 @@ class InputHandler {
|
|
|
67
68
|
onFinish: () => {
|
|
68
69
|
if (this.pauseInputStreamOnFinish) {
|
|
69
70
|
// https://github.com/kimmobrunfeldt/concurrently/issues/252
|
|
70
|
-
|
|
71
|
+
inputStream.pause();
|
|
71
72
|
}
|
|
72
73
|
},
|
|
73
74
|
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Command } from '../command';
|
|
2
2
|
import { Logger } from '../logger';
|
|
3
3
|
import { FlowController } from './flow-controller';
|
|
4
|
-
export
|
|
4
|
+
export type ProcessCloseCondition = 'failure' | 'success';
|
|
5
5
|
/**
|
|
6
|
-
* Sends a SIGTERM signal to all commands when one of the exits with a matching condition.
|
|
6
|
+
* Sends a SIGTERM signal to all commands when one of the commands exits with a matching condition.
|
|
7
7
|
*/
|
|
8
8
|
export declare class KillOthers implements FlowController {
|
|
9
9
|
private readonly logger;
|
|
@@ -6,8 +6,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.KillOthers = void 0;
|
|
7
7
|
const lodash_1 = __importDefault(require("lodash"));
|
|
8
8
|
const operators_1 = require("rxjs/operators");
|
|
9
|
+
const command_1 = require("../command");
|
|
9
10
|
/**
|
|
10
|
-
* Sends a SIGTERM signal to all commands when one of the exits with a matching condition.
|
|
11
|
+
* Sends a SIGTERM signal to all commands when one of the commands exits with a matching condition.
|
|
11
12
|
*/
|
|
12
13
|
class KillOthers {
|
|
13
14
|
constructor({ logger, conditions, }) {
|
|
@@ -21,7 +22,7 @@ class KillOthers {
|
|
|
21
22
|
}
|
|
22
23
|
const closeStates = commands.map((command) => command.close.pipe((0, operators_1.map)(({ exitCode }) => exitCode === 0 ? 'success' : 'failure'), (0, operators_1.filter)((state) => conditions.includes(state))));
|
|
23
24
|
closeStates.forEach((closeState) => closeState.subscribe(() => {
|
|
24
|
-
const killableCommands = commands.filter((command) => command
|
|
25
|
+
const killableCommands = commands.filter((command) => command_1.Command.canKill(command));
|
|
25
26
|
if (killableCommands.length) {
|
|
26
27
|
this.logger.logGlobalEvent('Sending SIGTERM to other processes..');
|
|
27
28
|
killableCommands.forEach((command) => command.kill());
|
|
@@ -27,6 +27,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
exports.LogTimings = void 0;
|
|
30
|
+
const assert = __importStar(require("assert"));
|
|
30
31
|
const format_1 = __importDefault(require("date-fns/format"));
|
|
31
32
|
const lodash_1 = __importDefault(require("lodash"));
|
|
32
33
|
const Rx = __importStar(require("rxjs"));
|
|
@@ -36,10 +37,6 @@ const defaults = __importStar(require("../defaults"));
|
|
|
36
37
|
* Logs timing information about commands as they start/stop and then a summary when all commands finish.
|
|
37
38
|
*/
|
|
38
39
|
class LogTimings {
|
|
39
|
-
constructor({ logger, timestampFormat = defaults.timestampFormat, }) {
|
|
40
|
-
this.logger = logger;
|
|
41
|
-
this.timestampFormat = timestampFormat;
|
|
42
|
-
}
|
|
43
40
|
static mapCloseEventToTimingInfo({ command, timings, killed, exitCode, }) {
|
|
44
41
|
const readableDurationMs = (timings.endDate.getTime() - timings.startDate.getTime()).toLocaleString();
|
|
45
42
|
return {
|
|
@@ -50,7 +47,12 @@ class LogTimings {
|
|
|
50
47
|
command: command.command,
|
|
51
48
|
};
|
|
52
49
|
}
|
|
50
|
+
constructor({ logger, timestampFormat = defaults.timestampFormat, }) {
|
|
51
|
+
this.logger = logger;
|
|
52
|
+
this.timestampFormat = timestampFormat;
|
|
53
|
+
}
|
|
53
54
|
printExitInfoTimingTable(exitInfos) {
|
|
55
|
+
assert.ok(this.logger);
|
|
54
56
|
const exitInfoTable = (0, lodash_1.default)(exitInfos)
|
|
55
57
|
.sortBy(({ timings }) => timings.durationSeconds)
|
|
56
58
|
.reverse()
|
|
@@ -61,7 +63,8 @@ class LogTimings {
|
|
|
61
63
|
return exitInfos;
|
|
62
64
|
}
|
|
63
65
|
handle(commands) {
|
|
64
|
-
|
|
66
|
+
const { logger } = this;
|
|
67
|
+
if (!logger) {
|
|
65
68
|
return { commands };
|
|
66
69
|
}
|
|
67
70
|
// individual process timings
|
|
@@ -69,12 +72,12 @@ class LogTimings {
|
|
|
69
72
|
command.timer.subscribe(({ startDate, endDate }) => {
|
|
70
73
|
if (!endDate) {
|
|
71
74
|
const formattedStartDate = (0, format_1.default)(startDate, this.timestampFormat);
|
|
72
|
-
|
|
75
|
+
logger.logCommandEvent(`${command.command} started at ${formattedStartDate}`, command);
|
|
73
76
|
}
|
|
74
77
|
else {
|
|
75
78
|
const durationMs = endDate.getTime() - startDate.getTime();
|
|
76
79
|
const formattedEndDate = (0, format_1.default)(endDate, this.timestampFormat);
|
|
77
|
-
|
|
80
|
+
logger.logCommandEvent(`${command.command} stopped at ${formattedEndDate} after ${durationMs.toLocaleString()}ms`, command);
|
|
78
81
|
}
|
|
79
82
|
});
|
|
80
83
|
});
|
|
@@ -11,23 +11,23 @@ export declare const getSpawnOpts: ({ colorSupport, cwd, process, raw, env, }: {
|
|
|
11
11
|
*
|
|
12
12
|
* Defaults to whatever the terminal's stdout support is.
|
|
13
13
|
*/
|
|
14
|
-
colorSupport?: Pick<supportsColor.supportsColor.Level,
|
|
14
|
+
colorSupport?: false | Pick<supportsColor.supportsColor.Level, "level"> | undefined;
|
|
15
15
|
/**
|
|
16
16
|
* The NodeJS process.
|
|
17
17
|
*/
|
|
18
|
-
process?: Pick<NodeJS.Process,
|
|
18
|
+
process?: Pick<NodeJS.Process, "cwd" | "env" | "platform"> | undefined;
|
|
19
19
|
/**
|
|
20
20
|
* A custom working directory to spawn processes in.
|
|
21
21
|
* Defaults to `process.cwd()`.
|
|
22
22
|
*/
|
|
23
|
-
cwd?: string;
|
|
23
|
+
cwd?: string | undefined;
|
|
24
24
|
/**
|
|
25
25
|
* Whether to customize the options for spawning processes in raw mode.
|
|
26
26
|
* Defaults to false.
|
|
27
27
|
*/
|
|
28
|
-
raw?: boolean;
|
|
28
|
+
raw?: boolean | undefined;
|
|
29
29
|
/**
|
|
30
30
|
* Map of custom environment variables to include in the spawn options.
|
|
31
31
|
*/
|
|
32
|
-
env?: Record<string, unknown
|
|
32
|
+
env?: Record<string, unknown> | undefined;
|
|
33
33
|
}) => SpawnOptions;
|
package/dist/src/index.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ import { LogOutput } from './flow-control/log-output';
|
|
|
12
12
|
import { LogTimings } from './flow-control/log-timings';
|
|
13
13
|
import { RestartProcess } from './flow-control/restart-process';
|
|
14
14
|
import { Logger } from './logger';
|
|
15
|
-
export
|
|
15
|
+
export type ConcurrentlyOptions = BaseConcurrentlyOptions & {
|
|
16
16
|
/**
|
|
17
17
|
* Which command(s) should have their output hidden.
|
|
18
18
|
*/
|
package/dist/src/index.js
CHANGED
|
@@ -46,7 +46,7 @@ exports.default = (commands, options = {}) => {
|
|
|
46
46
|
new input_handler_1.InputHandler({
|
|
47
47
|
logger,
|
|
48
48
|
defaultInputTarget: options.defaultInputTarget,
|
|
49
|
-
inputStream: options.inputStream || (options.handleInput
|
|
49
|
+
inputStream: options.inputStream || (options.handleInput ? process.stdin : undefined),
|
|
50
50
|
pauseInputStreamOnFinish: options.pauseInputStreamOnFinish,
|
|
51
51
|
}),
|
|
52
52
|
new kill_on_signal_1.KillOnSignal({ process }),
|
|
@@ -57,10 +57,10 @@ exports.default = (commands, options = {}) => {
|
|
|
57
57
|
}),
|
|
58
58
|
new kill_others_1.KillOthers({
|
|
59
59
|
logger,
|
|
60
|
-
conditions: options.killOthers,
|
|
60
|
+
conditions: options.killOthers || [],
|
|
61
61
|
}),
|
|
62
62
|
new log_timings_1.LogTimings({
|
|
63
|
-
logger: options.timings ? logger :
|
|
63
|
+
logger: options.timings ? logger : undefined,
|
|
64
64
|
timestampFormat: options.timestampFormat,
|
|
65
65
|
}),
|
|
66
66
|
],
|
package/dist/src/logger.js
CHANGED
|
@@ -86,13 +86,14 @@ class Logger {
|
|
|
86
86
|
}, prefix);
|
|
87
87
|
}
|
|
88
88
|
colorText(command, text) {
|
|
89
|
+
var _a;
|
|
89
90
|
let color;
|
|
90
91
|
if (command.prefixColor && command.prefixColor.startsWith('#')) {
|
|
91
92
|
color = chalk_1.default.hex(command.prefixColor);
|
|
92
93
|
}
|
|
93
94
|
else {
|
|
94
95
|
const defaultColor = lodash_1.default.get(chalk_1.default, defaults.prefixColors, chalk_1.default.reset);
|
|
95
|
-
color = lodash_1.default.get(chalk_1.default, command.prefixColor, defaultColor);
|
|
96
|
+
color = lodash_1.default.get(chalk_1.default, (_a = command.prefixColor) !== null && _a !== void 0 ? _a : '', defaultColor);
|
|
96
97
|
}
|
|
97
98
|
return color(text);
|
|
98
99
|
}
|
|
@@ -25,7 +25,7 @@ function* createColorGenerator(customColors) {
|
|
|
25
25
|
// There could be more "auto" values than auto colors so this needs to be able to refill
|
|
26
26
|
nextAutoColors.push(...PrefixColorSelector.ACCEPTABLE_CONSOLE_COLORS);
|
|
27
27
|
}
|
|
28
|
-
currentColor = nextAutoColors.shift();
|
|
28
|
+
currentColor = String(nextAutoColors.shift());
|
|
29
29
|
}
|
|
30
30
|
yield currentColor; // Auto color
|
|
31
31
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "concurrently",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.6.0",
|
|
4
4
|
"description": "Run commands concurrently",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "dist/src/index.d.ts",
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
"build": "tsc --build",
|
|
26
26
|
"postbuild": "chmod +x dist/bin/concurrently.js",
|
|
27
27
|
"clean": "tsc --build --clean",
|
|
28
|
-
"format": "prettier --
|
|
28
|
+
"format": "prettier --check '**/*.{json,y?(a)ml,md}'",
|
|
29
29
|
"format:fix": "npm run format -- --write",
|
|
30
|
-
"lint": "eslint . --ext mjs,js,ts
|
|
30
|
+
"lint": "eslint --ignore-path .gitignore --ext mjs,js,ts .",
|
|
31
31
|
"lint:fix": "npm run lint -- --fix",
|
|
32
32
|
"prepublishOnly": "npm run build",
|
|
33
33
|
"report-coverage": "cat coverage/lcov.info | coveralls",
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
"prettier": "^2.6.2",
|
|
87
87
|
"simple-git-hooks": "^2.7.0",
|
|
88
88
|
"string-argv": "^0.3.1",
|
|
89
|
-
"typescript": "~4.
|
|
89
|
+
"typescript": "~4.9.3"
|
|
90
90
|
},
|
|
91
91
|
"files": [
|
|
92
92
|
"dist",
|
|
@@ -101,6 +101,6 @@
|
|
|
101
101
|
},
|
|
102
102
|
"lint-staged": {
|
|
103
103
|
"*.m?{js,ts}": "eslint --fix",
|
|
104
|
-
"{
|
|
104
|
+
"*.{json,y?(a)ml,md}": "prettier --write"
|
|
105
105
|
}
|
|
106
106
|
}
|