concurrently 6.5.1 → 7.2.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 +133 -43
- package/dist/bin/concurrently.d.ts +2 -0
- package/dist/bin/concurrently.js +218 -0
- package/dist/bin/epilogue.d.ts +1 -0
- package/dist/bin/epilogue.js +81 -0
- package/dist/src/command-parser/command-parser.d.ts +19 -0
- package/dist/src/command-parser/command-parser.js +2 -0
- package/dist/src/command-parser/expand-arguments.d.ts +12 -0
- package/dist/src/command-parser/expand-arguments.js +40 -0
- package/dist/src/command-parser/expand-npm-shortcut.d.ts +8 -0
- package/dist/src/command-parser/expand-npm-shortcut.js +20 -0
- package/dist/src/command-parser/expand-npm-wildcard.d.ts +13 -0
- package/dist/src/command-parser/expand-npm-wildcard.js +82 -0
- package/dist/src/command-parser/strip-quotes.d.ts +10 -0
- package/dist/src/command-parser/strip-quotes.js +18 -0
- package/dist/src/command.d.ts +104 -0
- package/{src → dist/src}/command.js +54 -30
- package/dist/src/completion-listener.d.ts +39 -0
- package/dist/src/completion-listener.js +74 -0
- package/dist/src/concurrently.d.ts +90 -0
- package/dist/src/concurrently.js +124 -0
- package/dist/src/defaults.d.ts +62 -0
- package/dist/src/defaults.js +67 -0
- package/dist/src/flow-control/flow-controller.d.ts +13 -0
- package/dist/src/flow-control/flow-controller.js +2 -0
- package/dist/src/flow-control/input-handler.d.ts +33 -0
- package/dist/src/flow-control/input-handler.js +73 -0
- package/dist/src/flow-control/kill-on-signal.d.ts +17 -0
- package/{src → dist/src}/flow-control/kill-on-signal.js +15 -13
- package/dist/src/flow-control/kill-others.d.ts +18 -0
- package/dist/src/flow-control/kill-others.js +35 -0
- package/dist/src/flow-control/log-error.d.ts +15 -0
- package/dist/src/flow-control/log-error.js +21 -0
- package/dist/src/flow-control/log-exit.d.ts +15 -0
- package/dist/src/flow-control/log-exit.js +19 -0
- package/dist/src/flow-control/log-output.d.ts +15 -0
- package/{src → dist/src}/flow-control/log-output.js +13 -5
- package/dist/src/flow-control/log-timings.d.ts +27 -0
- package/dist/src/flow-control/log-timings.js +88 -0
- package/dist/src/flow-control/restart-process.d.ts +22 -0
- package/dist/src/flow-control/restart-process.js +71 -0
- package/dist/src/get-spawn-opts.d.ts +30 -0
- package/dist/src/get-spawn-opts.js +11 -0
- package/dist/src/index.d.ts +74 -0
- package/dist/src/index.js +70 -0
- package/dist/src/logger.d.ts +72 -0
- package/{src → dist/src}/logger.js +77 -58
- package/dist/src/output-writer.d.ts +19 -0
- package/dist/src/output-writer.js +69 -0
- package/index.js +6 -68
- package/index.mjs +9 -0
- package/package.json +42 -12
- package/bin/concurrently.js +0 -186
- package/bin/concurrently.spec.js +0 -428
- package/bin/epilogue.txt +0 -46
- package/src/command-parser/expand-npm-shortcut.js +0 -13
- package/src/command-parser/expand-npm-shortcut.spec.js +0 -36
- package/src/command-parser/expand-npm-wildcard.js +0 -52
- package/src/command-parser/expand-npm-wildcard.spec.js +0 -104
- package/src/command-parser/strip-quotes.js +0 -12
- package/src/command-parser/strip-quotes.spec.js +0 -20
- package/src/command.spec.js +0 -275
- package/src/completion-listener.js +0 -39
- package/src/completion-listener.spec.js +0 -89
- package/src/concurrently.js +0 -116
- package/src/concurrently.spec.js +0 -199
- package/src/defaults.js +0 -35
- package/src/flow-control/base-handler.js +0 -16
- package/src/flow-control/base-handler.spec.js +0 -22
- package/src/flow-control/input-handler.js +0 -50
- package/src/flow-control/input-handler.spec.js +0 -113
- package/src/flow-control/kill-on-signal.spec.js +0 -79
- package/src/flow-control/kill-others.js +0 -38
- package/src/flow-control/kill-others.spec.js +0 -66
- package/src/flow-control/log-error.js +0 -18
- package/src/flow-control/log-error.spec.js +0 -40
- package/src/flow-control/log-exit.js +0 -11
- package/src/flow-control/log-exit.spec.js +0 -36
- package/src/flow-control/log-output.spec.js +0 -41
- package/src/flow-control/log-timings.js +0 -64
- package/src/flow-control/log-timings.spec.js +0 -137
- package/src/flow-control/restart-process.js +0 -56
- package/src/flow-control/restart-process.spec.js +0 -139
- package/src/get-spawn-opts.js +0 -16
- package/src/get-spawn-opts.spec.js +0 -30
- package/src/logger.spec.js +0 -318
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ExpandNpmShortcut = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Expands commands prefixed with `npm:`, `yarn:` or `pnpm:` into the full version `npm run <command>` and so on.
|
|
6
|
+
*/
|
|
7
|
+
class ExpandNpmShortcut {
|
|
8
|
+
parse(commandInfo) {
|
|
9
|
+
const [, npmCmd, cmdName, args] = commandInfo.command.match(/^(npm|yarn|pnpm):(\S+)(.*)/) || [];
|
|
10
|
+
if (!cmdName) {
|
|
11
|
+
return commandInfo;
|
|
12
|
+
}
|
|
13
|
+
return Object.assign({}, commandInfo, {
|
|
14
|
+
name: commandInfo.name || cmdName,
|
|
15
|
+
command: `${npmCmd} run ${cmdName}${args}`,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.ExpandNpmShortcut = ExpandNpmShortcut;
|
|
20
|
+
;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { CommandInfo } from '../command';
|
|
2
|
+
import { CommandParser } from './command-parser';
|
|
3
|
+
/**
|
|
4
|
+
* Finds wildcards in npm/yarn/pnpm run commands and replaces them with all matching scripts in the
|
|
5
|
+
* `package.json` file of the current directory.
|
|
6
|
+
*/
|
|
7
|
+
export declare class ExpandNpmWildcard implements CommandParser {
|
|
8
|
+
private readonly readPackage;
|
|
9
|
+
static readPackage(): any;
|
|
10
|
+
private scripts?;
|
|
11
|
+
constructor(readPackage?: typeof ExpandNpmWildcard.readPackage);
|
|
12
|
+
parse(commandInfo: CommandInfo): CommandInfo | CommandInfo[];
|
|
13
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
+
}) : (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
o[k2] = m[k];
|
|
8
|
+
}));
|
|
9
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
10
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
11
|
+
}) : function(o, v) {
|
|
12
|
+
o["default"] = v;
|
|
13
|
+
});
|
|
14
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
15
|
+
if (mod && mod.__esModule) return mod;
|
|
16
|
+
var result = {};
|
|
17
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
18
|
+
__setModuleDefault(result, mod);
|
|
19
|
+
return result;
|
|
20
|
+
};
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.ExpandNpmWildcard = void 0;
|
|
23
|
+
const fs = __importStar(require("fs"));
|
|
24
|
+
const _ = __importStar(require("lodash"));
|
|
25
|
+
const OMISSION = /\(!([^\)]+)\)/;
|
|
26
|
+
/**
|
|
27
|
+
* Finds wildcards in npm/yarn/pnpm run commands and replaces them with all matching scripts in the
|
|
28
|
+
* `package.json` file of the current directory.
|
|
29
|
+
*/
|
|
30
|
+
class ExpandNpmWildcard {
|
|
31
|
+
constructor(readPackage = ExpandNpmWildcard.readPackage) {
|
|
32
|
+
this.readPackage = readPackage;
|
|
33
|
+
}
|
|
34
|
+
static readPackage() {
|
|
35
|
+
try {
|
|
36
|
+
const json = fs.readFileSync('package.json', { encoding: 'utf-8' });
|
|
37
|
+
return JSON.parse(json);
|
|
38
|
+
}
|
|
39
|
+
catch (e) {
|
|
40
|
+
return {};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
parse(commandInfo) {
|
|
44
|
+
const [, npmCmd, cmdName, args] = commandInfo.command.match(/(npm|yarn|pnpm) run (\S+)([^&]*)/) || [];
|
|
45
|
+
const wildcardPosition = (cmdName || '').indexOf('*');
|
|
46
|
+
// If the regex didn't match an npm script, or it has no wildcard,
|
|
47
|
+
// then we have nothing to do here
|
|
48
|
+
if (!cmdName || wildcardPosition === -1) {
|
|
49
|
+
return commandInfo;
|
|
50
|
+
}
|
|
51
|
+
if (!this.scripts) {
|
|
52
|
+
this.scripts = Object.keys(this.readPackage().scripts || {});
|
|
53
|
+
}
|
|
54
|
+
const omissionRegex = cmdName.match(OMISSION);
|
|
55
|
+
const cmdNameSansOmission = cmdName.replace(OMISSION, '');
|
|
56
|
+
const preWildcard = _.escapeRegExp(cmdNameSansOmission.substr(0, wildcardPosition));
|
|
57
|
+
const postWildcard = _.escapeRegExp(cmdNameSansOmission.substr(wildcardPosition + 1));
|
|
58
|
+
const wildcardRegex = new RegExp(`^${preWildcard}(.*?)${postWildcard}$`);
|
|
59
|
+
const currentName = commandInfo.name || '';
|
|
60
|
+
return this.scripts
|
|
61
|
+
.map(script => {
|
|
62
|
+
const match = script.match(wildcardRegex);
|
|
63
|
+
if (omissionRegex) {
|
|
64
|
+
const toOmit = script.match(new RegExp(omissionRegex[1]));
|
|
65
|
+
if (toOmit) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (match) {
|
|
70
|
+
return Object.assign({}, commandInfo, {
|
|
71
|
+
command: `${npmCmd} run ${script}${args}`,
|
|
72
|
+
// Will use an empty command name if command has no name and the wildcard match is empty,
|
|
73
|
+
// e.g. if `npm:watch-*` matches `npm run watch-`.
|
|
74
|
+
name: currentName + match[1],
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
.filter((commandInfo) => !!commandInfo);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
exports.ExpandNpmWildcard = ExpandNpmWildcard;
|
|
82
|
+
;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { CommandInfo } from '../command';
|
|
2
|
+
import { CommandParser } from './command-parser';
|
|
3
|
+
/**
|
|
4
|
+
* Strips quotes around commands so that they can run on the current shell.
|
|
5
|
+
*/
|
|
6
|
+
export declare class StripQuotes implements CommandParser {
|
|
7
|
+
parse(commandInfo: CommandInfo): CommandInfo & {
|
|
8
|
+
command: string;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StripQuotes = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Strips quotes around commands so that they can run on the current shell.
|
|
6
|
+
*/
|
|
7
|
+
class StripQuotes {
|
|
8
|
+
parse(commandInfo) {
|
|
9
|
+
let { command } = commandInfo;
|
|
10
|
+
// Removes the quotes surrounding a command.
|
|
11
|
+
if (/^"(.+?)"$/.test(command) || /^'(.+?)'$/.test(command)) {
|
|
12
|
+
command = command.substring(1, command.length - 1);
|
|
13
|
+
}
|
|
14
|
+
return Object.assign({}, commandInfo, { command });
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.StripQuotes = StripQuotes;
|
|
18
|
+
;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { ChildProcess as BaseChildProcess, SpawnOptions } from 'child_process';
|
|
3
|
+
import * as Rx from 'rxjs';
|
|
4
|
+
import { EventEmitter, Writable } from 'stream';
|
|
5
|
+
/**
|
|
6
|
+
* Identifier for a command; if string, it's the command's name, if number, it's the index.
|
|
7
|
+
*/
|
|
8
|
+
export declare type CommandIdentifier = string | number;
|
|
9
|
+
export interface CommandInfo {
|
|
10
|
+
/**
|
|
11
|
+
* Command's name.
|
|
12
|
+
*/
|
|
13
|
+
name: string;
|
|
14
|
+
/**
|
|
15
|
+
* Which command line the command has.
|
|
16
|
+
*/
|
|
17
|
+
command: string;
|
|
18
|
+
/**
|
|
19
|
+
* Which environment variables should the spawned process have.
|
|
20
|
+
*/
|
|
21
|
+
env?: Record<string, any>;
|
|
22
|
+
/**
|
|
23
|
+
* The current working directory of the process when spawned.
|
|
24
|
+
*/
|
|
25
|
+
cwd?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Color to use on prefix of command.
|
|
28
|
+
*/
|
|
29
|
+
prefixColor?: string;
|
|
30
|
+
}
|
|
31
|
+
export interface CloseEvent {
|
|
32
|
+
command: CommandInfo;
|
|
33
|
+
/**
|
|
34
|
+
* The command's index among all commands ran.
|
|
35
|
+
*/
|
|
36
|
+
index: number;
|
|
37
|
+
/**
|
|
38
|
+
* Whether the command exited because it was killed.
|
|
39
|
+
*/
|
|
40
|
+
killed: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* The exit code or signal for the command.
|
|
43
|
+
*/
|
|
44
|
+
exitCode: string | number;
|
|
45
|
+
timings: {
|
|
46
|
+
startDate: Date;
|
|
47
|
+
endDate: Date;
|
|
48
|
+
durationSeconds: number;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export interface TimerEvent {
|
|
52
|
+
startDate: Date;
|
|
53
|
+
endDate?: Date;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Subtype of NodeJS's child_process including only what's actually needed for a command to work.
|
|
57
|
+
*/
|
|
58
|
+
export declare type ChildProcess = EventEmitter & Pick<BaseChildProcess, 'pid' | 'stdin' | 'stdout' | 'stderr'>;
|
|
59
|
+
/**
|
|
60
|
+
* Interface for a function that must kill the process with `pid`, optionally sending `signal` to it.
|
|
61
|
+
*/
|
|
62
|
+
export declare type KillProcess = (pid: number, signal?: string) => void;
|
|
63
|
+
/**
|
|
64
|
+
* Interface for a function that spawns a command and returns its child process instance.
|
|
65
|
+
*/
|
|
66
|
+
export declare type SpawnCommand = (command: string, options: SpawnOptions) => ChildProcess;
|
|
67
|
+
export declare class Command implements CommandInfo {
|
|
68
|
+
private readonly killProcess;
|
|
69
|
+
private readonly spawn;
|
|
70
|
+
private readonly spawnOpts;
|
|
71
|
+
readonly index: number;
|
|
72
|
+
/** @inheritdoc */
|
|
73
|
+
readonly name: string;
|
|
74
|
+
/** @inheritdoc */
|
|
75
|
+
readonly command: string;
|
|
76
|
+
/** @inheritdoc */
|
|
77
|
+
readonly prefixColor: string;
|
|
78
|
+
/** @inheritdoc */
|
|
79
|
+
readonly env: Record<string, any>;
|
|
80
|
+
/** @inheritdoc */
|
|
81
|
+
readonly cwd?: string;
|
|
82
|
+
readonly close: Rx.Subject<CloseEvent>;
|
|
83
|
+
readonly error: Rx.Subject<unknown>;
|
|
84
|
+
readonly stdout: Rx.Subject<Buffer>;
|
|
85
|
+
readonly stderr: Rx.Subject<Buffer>;
|
|
86
|
+
readonly timer: Rx.Subject<TimerEvent>;
|
|
87
|
+
process?: ChildProcess;
|
|
88
|
+
stdin?: Writable;
|
|
89
|
+
pid?: number;
|
|
90
|
+
killed: boolean;
|
|
91
|
+
exited: boolean;
|
|
92
|
+
get killable(): boolean;
|
|
93
|
+
constructor({ index, name, command, prefixColor, env, cwd }: CommandInfo & {
|
|
94
|
+
index: number;
|
|
95
|
+
}, spawnOpts: SpawnOptions, spawn: SpawnCommand, killProcess: KillProcess);
|
|
96
|
+
/**
|
|
97
|
+
* Starts this command, piping output, error and close events onto the corresponding observables.
|
|
98
|
+
*/
|
|
99
|
+
start(): void;
|
|
100
|
+
/**
|
|
101
|
+
* Kills this command, optionally specifying a signal to send to it.
|
|
102
|
+
*/
|
|
103
|
+
kill(code?: string): void;
|
|
104
|
+
}
|
|
@@ -1,54 +1,72 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
get
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
+
}) : (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
o[k2] = m[k];
|
|
8
|
+
}));
|
|
9
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
10
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
11
|
+
}) : function(o, v) {
|
|
12
|
+
o["default"] = v;
|
|
13
|
+
});
|
|
14
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
15
|
+
if (mod && mod.__esModule) return mod;
|
|
16
|
+
var result = {};
|
|
17
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
18
|
+
__setModuleDefault(result, mod);
|
|
19
|
+
return result;
|
|
20
|
+
};
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.Command = void 0;
|
|
23
|
+
const Rx = __importStar(require("rxjs"));
|
|
24
|
+
class Command {
|
|
25
|
+
constructor({ index, name, command, prefixColor, env, cwd }, spawnOpts, spawn, killProcess) {
|
|
26
|
+
this.close = new Rx.Subject();
|
|
27
|
+
this.error = new Rx.Subject();
|
|
28
|
+
this.stdout = new Rx.Subject();
|
|
29
|
+
this.stderr = new Rx.Subject();
|
|
30
|
+
this.timer = new Rx.Subject();
|
|
31
|
+
this.killed = false;
|
|
32
|
+
this.exited = false;
|
|
9
33
|
this.index = index;
|
|
10
34
|
this.name = name;
|
|
11
35
|
this.command = command;
|
|
12
36
|
this.prefixColor = prefixColor;
|
|
13
37
|
this.env = env;
|
|
38
|
+
this.cwd = cwd;
|
|
14
39
|
this.killProcess = killProcess;
|
|
15
40
|
this.spawn = spawn;
|
|
16
41
|
this.spawnOpts = spawnOpts;
|
|
17
|
-
this.killed = false;
|
|
18
|
-
|
|
19
|
-
this.error = new Rx.Subject();
|
|
20
|
-
this.timer = new Rx.Subject();
|
|
21
|
-
this.close = new Rx.Subject();
|
|
22
|
-
this.stdout = new Rx.Subject();
|
|
23
|
-
this.stderr = new Rx.Subject();
|
|
24
42
|
}
|
|
25
|
-
|
|
43
|
+
get killable() {
|
|
44
|
+
return !!this.process;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Starts this command, piping output, error and close events onto the corresponding observables.
|
|
48
|
+
*/
|
|
26
49
|
start() {
|
|
27
50
|
const child = this.spawn(this.command, this.spawnOpts);
|
|
28
51
|
this.process = child;
|
|
29
52
|
this.pid = child.pid;
|
|
30
53
|
const startDate = new Date(Date.now());
|
|
31
54
|
const highResStartTime = process.hrtime();
|
|
32
|
-
this.timer.next({startDate});
|
|
33
|
-
|
|
55
|
+
this.timer.next({ startDate });
|
|
34
56
|
Rx.fromEvent(child, 'error').subscribe(event => {
|
|
35
57
|
this.process = undefined;
|
|
36
58
|
const endDate = new Date(Date.now());
|
|
37
|
-
this.timer.next({startDate, endDate});
|
|
59
|
+
this.timer.next({ startDate, endDate });
|
|
38
60
|
this.error.next(event);
|
|
39
61
|
});
|
|
40
62
|
Rx.fromEvent(child, 'close').subscribe(([exitCode, signal]) => {
|
|
41
63
|
this.process = undefined;
|
|
64
|
+
this.exited = true;
|
|
42
65
|
const endDate = new Date(Date.now());
|
|
43
|
-
this.timer.next({startDate, endDate});
|
|
66
|
+
this.timer.next({ startDate, endDate });
|
|
44
67
|
const [durationSeconds, durationNanoSeconds] = process.hrtime(highResStartTime);
|
|
45
68
|
this.close.next({
|
|
46
|
-
command:
|
|
47
|
-
command: this.command,
|
|
48
|
-
name: this.name,
|
|
49
|
-
prefixColor: this.prefixColor,
|
|
50
|
-
env: this.env,
|
|
51
|
-
},
|
|
69
|
+
command: this,
|
|
52
70
|
index: this.index,
|
|
53
71
|
exitCode: exitCode === null ? signal : exitCode,
|
|
54
72
|
killed: this.killed,
|
|
@@ -56,22 +74,28 @@ module.exports = class Command {
|
|
|
56
74
|
startDate,
|
|
57
75
|
endDate,
|
|
58
76
|
durationSeconds: durationSeconds + (durationNanoSeconds / 1e9),
|
|
59
|
-
}
|
|
77
|
+
},
|
|
60
78
|
});
|
|
61
79
|
});
|
|
62
80
|
child.stdout && pipeTo(Rx.fromEvent(child.stdout, 'data'), this.stdout);
|
|
63
81
|
child.stderr && pipeTo(Rx.fromEvent(child.stderr, 'data'), this.stderr);
|
|
64
82
|
this.stdin = child.stdin;
|
|
65
83
|
}
|
|
66
|
-
|
|
84
|
+
/**
|
|
85
|
+
* Kills this command, optionally specifying a signal to send to it.
|
|
86
|
+
*/
|
|
67
87
|
kill(code) {
|
|
68
88
|
if (this.killable) {
|
|
69
89
|
this.killed = true;
|
|
70
90
|
this.killProcess(this.pid, code);
|
|
71
91
|
}
|
|
72
92
|
}
|
|
73
|
-
}
|
|
74
|
-
|
|
93
|
+
}
|
|
94
|
+
exports.Command = Command;
|
|
95
|
+
;
|
|
96
|
+
/**
|
|
97
|
+
* Pipes all events emitted by `stream` into `subject`.
|
|
98
|
+
*/
|
|
75
99
|
function pipeTo(stream, subject) {
|
|
76
100
|
stream.subscribe(event => subject.next(event));
|
|
77
101
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as Rx from 'rxjs';
|
|
2
|
+
import { CloseEvent, Command } from './command';
|
|
3
|
+
/**
|
|
4
|
+
* Defines which command(s) in a list must exit successfully (with an exit code of `0`):
|
|
5
|
+
*
|
|
6
|
+
* - `first`: only the first specified command;
|
|
7
|
+
* - `last`: only the last specified command;
|
|
8
|
+
* - `all`: all commands.
|
|
9
|
+
* - `command-{name|index}`: only the commands with the specified names or index.
|
|
10
|
+
* - `!command-{name|index}`: all commands but the ones with the specified names or index.
|
|
11
|
+
*/
|
|
12
|
+
export declare type SuccessCondition = 'first' | 'last' | 'all' | `command-${string | number}` | `!command-${string | number}`;
|
|
13
|
+
/**
|
|
14
|
+
* Provides logic to determine whether lists of commands ran successfully.
|
|
15
|
+
*/
|
|
16
|
+
export declare class CompletionListener {
|
|
17
|
+
private readonly successCondition;
|
|
18
|
+
private readonly scheduler?;
|
|
19
|
+
constructor({ successCondition, scheduler }: {
|
|
20
|
+
/**
|
|
21
|
+
* How this instance will define that a list of commands ran successfully.
|
|
22
|
+
* Defaults to `all`.
|
|
23
|
+
*
|
|
24
|
+
* @see {SuccessCondition}
|
|
25
|
+
*/
|
|
26
|
+
successCondition?: SuccessCondition;
|
|
27
|
+
/**
|
|
28
|
+
* For testing only.
|
|
29
|
+
*/
|
|
30
|
+
scheduler?: Rx.SchedulerLike;
|
|
31
|
+
});
|
|
32
|
+
private isSuccess;
|
|
33
|
+
/**
|
|
34
|
+
* Given a list of commands, wait for all of them to exit and then evaluate their exit codes.
|
|
35
|
+
*
|
|
36
|
+
* @returns A Promise that resolves if the success condition is met, or rejects otherwise.
|
|
37
|
+
*/
|
|
38
|
+
listen(commands: Command[]): Promise<CloseEvent[]>;
|
|
39
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
+
}) : (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
o[k2] = m[k];
|
|
8
|
+
}));
|
|
9
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
10
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
11
|
+
}) : function(o, v) {
|
|
12
|
+
o["default"] = v;
|
|
13
|
+
});
|
|
14
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
15
|
+
if (mod && mod.__esModule) return mod;
|
|
16
|
+
var result = {};
|
|
17
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
18
|
+
__setModuleDefault(result, mod);
|
|
19
|
+
return result;
|
|
20
|
+
};
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.CompletionListener = void 0;
|
|
23
|
+
const Rx = __importStar(require("rxjs"));
|
|
24
|
+
const operators_1 = require("rxjs/operators");
|
|
25
|
+
/**
|
|
26
|
+
* Provides logic to determine whether lists of commands ran successfully.
|
|
27
|
+
*/
|
|
28
|
+
class CompletionListener {
|
|
29
|
+
constructor({ successCondition = 'all', scheduler }) {
|
|
30
|
+
this.successCondition = successCondition;
|
|
31
|
+
this.scheduler = scheduler;
|
|
32
|
+
}
|
|
33
|
+
isSuccess(events) {
|
|
34
|
+
if (this.successCondition === 'first') {
|
|
35
|
+
return events[0].exitCode === 0;
|
|
36
|
+
}
|
|
37
|
+
else if (this.successCondition === 'last') {
|
|
38
|
+
return events[events.length - 1].exitCode === 0;
|
|
39
|
+
}
|
|
40
|
+
else if (!/^!?command-.+$/.test(this.successCondition)) {
|
|
41
|
+
// If not a `command-` syntax, then it's an 'all' condition or it's treated as such.
|
|
42
|
+
return events.every(({ exitCode }) => exitCode === 0);
|
|
43
|
+
}
|
|
44
|
+
// Check `command-` syntax condition.
|
|
45
|
+
// Note that a command's `name` is not necessarily unique,
|
|
46
|
+
// in which case all of them must meet the success condition.
|
|
47
|
+
const [, nameOrIndex] = this.successCondition.split('-');
|
|
48
|
+
const targetCommandsEvents = events.filter(({ command, index }) => (command.name === nameOrIndex
|
|
49
|
+
|| index === Number(nameOrIndex)));
|
|
50
|
+
if (this.successCondition.startsWith('!')) {
|
|
51
|
+
// All commands except the specified ones must exit succesfully
|
|
52
|
+
return events.every((event) => (targetCommandsEvents.includes(event)
|
|
53
|
+
|| event.exitCode === 0));
|
|
54
|
+
}
|
|
55
|
+
// Only the specified commands must exit succesfully
|
|
56
|
+
return targetCommandsEvents.length > 0
|
|
57
|
+
&& targetCommandsEvents.every(event => event.exitCode === 0);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Given a list of commands, wait for all of them to exit and then evaluate their exit codes.
|
|
61
|
+
*
|
|
62
|
+
* @returns A Promise that resolves if the success condition is met, or rejects otherwise.
|
|
63
|
+
*/
|
|
64
|
+
listen(commands) {
|
|
65
|
+
const closeStreams = commands.map(command => command.close);
|
|
66
|
+
return Rx.merge(...closeStreams)
|
|
67
|
+
.pipe((0, operators_1.bufferCount)(closeStreams.length), (0, operators_1.switchMap)(exitInfos => this.isSuccess(exitInfos)
|
|
68
|
+
? Rx.of(exitInfos, this.scheduler)
|
|
69
|
+
: Rx.throwError(exitInfos, this.scheduler)), (0, operators_1.take)(1))
|
|
70
|
+
.toPromise();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
exports.CompletionListener = CompletionListener;
|
|
74
|
+
;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { Writable } from 'stream';
|
|
3
|
+
import { CloseEvent, Command, CommandInfo, KillProcess, SpawnCommand } from './command';
|
|
4
|
+
import { SuccessCondition } from './completion-listener';
|
|
5
|
+
import { FlowController } from './flow-control/flow-controller';
|
|
6
|
+
import { Logger } from './logger';
|
|
7
|
+
/**
|
|
8
|
+
* A command that is to be passed into `concurrently()`.
|
|
9
|
+
* If value is a string, then that's the command's command line.
|
|
10
|
+
* Fine grained options can be defined by using the object format.
|
|
11
|
+
*/
|
|
12
|
+
export declare type ConcurrentlyCommandInput = string | Partial<CommandInfo>;
|
|
13
|
+
export declare type ConcurrentlyResult = {
|
|
14
|
+
/**
|
|
15
|
+
* All commands created and ran by concurrently.
|
|
16
|
+
*/
|
|
17
|
+
commands: Command[];
|
|
18
|
+
/**
|
|
19
|
+
* A promise that resolves when concurrently ran successfully according to the specified
|
|
20
|
+
* success condition, or reject otherwise.
|
|
21
|
+
*
|
|
22
|
+
* Both the resolved and rejected value is the list of all command's close events.
|
|
23
|
+
*/
|
|
24
|
+
result: Promise<CloseEvent[]>;
|
|
25
|
+
};
|
|
26
|
+
export declare type ConcurrentlyOptions = {
|
|
27
|
+
logger?: Logger;
|
|
28
|
+
/**
|
|
29
|
+
* Which stream should the commands output be written to.
|
|
30
|
+
*/
|
|
31
|
+
outputStream?: Writable;
|
|
32
|
+
/**
|
|
33
|
+
* Whether the output should be ordered as if the commands were run sequentially.
|
|
34
|
+
*/
|
|
35
|
+
group?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Comma-separated list of chalk colors to use on prefixes.
|
|
38
|
+
*/
|
|
39
|
+
prefixColors?: string[];
|
|
40
|
+
/**
|
|
41
|
+
* Maximum number of commands to run at once.
|
|
42
|
+
*
|
|
43
|
+
* If undefined, then all processes will start in parallel.
|
|
44
|
+
* Setting this value to 1 will achieve sequential running.
|
|
45
|
+
*/
|
|
46
|
+
maxProcesses?: number;
|
|
47
|
+
/**
|
|
48
|
+
* Whether commands should be spawned in raw mode.
|
|
49
|
+
* Defaults to false.
|
|
50
|
+
*/
|
|
51
|
+
raw?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* The current working directory of commands which didn't specify one.
|
|
54
|
+
* Defaults to `process.cwd()`.
|
|
55
|
+
*/
|
|
56
|
+
cwd?: string;
|
|
57
|
+
/**
|
|
58
|
+
* @see CompletionListener
|
|
59
|
+
*/
|
|
60
|
+
successCondition?: SuccessCondition;
|
|
61
|
+
/**
|
|
62
|
+
* Which flow controllers should be applied on commands spawned by concurrently.
|
|
63
|
+
* Defaults to an empty array.
|
|
64
|
+
*/
|
|
65
|
+
controllers: FlowController[];
|
|
66
|
+
/**
|
|
67
|
+
* A function that will spawn commands.
|
|
68
|
+
* Defaults to the `spawn-command` module.
|
|
69
|
+
*/
|
|
70
|
+
spawn: SpawnCommand;
|
|
71
|
+
/**
|
|
72
|
+
* A function that will kill processes.
|
|
73
|
+
* Defaults to the `tree-kill` module.
|
|
74
|
+
*/
|
|
75
|
+
kill: KillProcess;
|
|
76
|
+
/**
|
|
77
|
+
* List of additional arguments passed that will get replaced in each command.
|
|
78
|
+
* If not defined, no argument replacing will happen.
|
|
79
|
+
*
|
|
80
|
+
* @see ExpandArguments
|
|
81
|
+
*/
|
|
82
|
+
additionalArguments?: string[];
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Core concurrently functionality -- spawns the given commands concurrently and
|
|
86
|
+
* returns the commands themselves + the result according to the specified success condition.
|
|
87
|
+
*
|
|
88
|
+
* @see CompletionListener
|
|
89
|
+
*/
|
|
90
|
+
export declare function concurrently(baseCommands: ConcurrentlyCommandInput[], baseOptions?: Partial<ConcurrentlyOptions>): ConcurrentlyResult;
|