Initial project import
This commit is contained in:
13
node_modules/concurrently/dist/lib/flow-control/flow-controller.d.ts
generated
vendored
Normal file
13
node_modules/concurrently/dist/lib/flow-control/flow-controller.d.ts
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
import type { Command } from '../command.js';
|
||||
/**
|
||||
* Interface for a class that controls and/or watches the behavior of commands.
|
||||
*
|
||||
* This may include logging their output, creating interactions between them, or changing when they
|
||||
* actually finish.
|
||||
*/
|
||||
export interface FlowController {
|
||||
handle(commands: Command[]): {
|
||||
commands: Command[];
|
||||
onFinish?: () => void | Promise<void>;
|
||||
};
|
||||
}
|
||||
1
node_modules/concurrently/dist/lib/flow-control/flow-controller.js
generated
vendored
Normal file
1
node_modules/concurrently/dist/lib/flow-control/flow-controller.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export {};
|
||||
29
node_modules/concurrently/dist/lib/flow-control/input-handler.d.ts
generated
vendored
Normal file
29
node_modules/concurrently/dist/lib/flow-control/input-handler.d.ts
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
import { Readable } from 'node:stream';
|
||||
import { Command, CommandIdentifier } from '../command.js';
|
||||
import { Logger } from '../logger.js';
|
||||
import { FlowController } from './flow-controller.js';
|
||||
/**
|
||||
* Sends input from concurrently through to commands.
|
||||
*
|
||||
* Input can start with a command identifier, in which case it will be sent to that specific command.
|
||||
* For instance, `0:bla` will send `bla` to command at index `0`, and `server:stop` will send `stop`
|
||||
* to command with name `server`.
|
||||
*
|
||||
* If the input doesn't start with a command identifier, it is then always sent to the default target.
|
||||
*/
|
||||
export declare class InputHandler implements FlowController {
|
||||
private readonly logger;
|
||||
private readonly defaultInputTarget;
|
||||
private readonly inputStream?;
|
||||
private readonly pauseInputStreamOnFinish;
|
||||
constructor({ defaultInputTarget, inputStream, pauseInputStreamOnFinish, logger, }: {
|
||||
inputStream?: Readable;
|
||||
logger: Logger;
|
||||
defaultInputTarget?: CommandIdentifier;
|
||||
pauseInputStreamOnFinish?: boolean;
|
||||
});
|
||||
handle(commands: Command[]): {
|
||||
commands: Command[];
|
||||
onFinish?: () => void | undefined;
|
||||
};
|
||||
}
|
||||
68
node_modules/concurrently/dist/lib/flow-control/input-handler.js
generated
vendored
Normal file
68
node_modules/concurrently/dist/lib/flow-control/input-handler.js
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
import Rx from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import * as defaults from '../defaults.js';
|
||||
/**
|
||||
* Sends input from concurrently through to commands.
|
||||
*
|
||||
* Input can start with a command identifier, in which case it will be sent to that specific command.
|
||||
* For instance, `0:bla` will send `bla` to command at index `0`, and `server:stop` will send `stop`
|
||||
* to command with name `server`.
|
||||
*
|
||||
* If the input doesn't start with a command identifier, it is then always sent to the default target.
|
||||
*/
|
||||
export class InputHandler {
|
||||
logger;
|
||||
defaultInputTarget;
|
||||
inputStream;
|
||||
pauseInputStreamOnFinish;
|
||||
constructor({ defaultInputTarget, inputStream, pauseInputStreamOnFinish, logger, }) {
|
||||
this.logger = logger;
|
||||
this.defaultInputTarget = defaultInputTarget || defaults.defaultInputTarget;
|
||||
this.inputStream = inputStream;
|
||||
this.pauseInputStreamOnFinish = pauseInputStreamOnFinish !== false;
|
||||
}
|
||||
handle(commands) {
|
||||
const { inputStream } = this;
|
||||
if (!inputStream) {
|
||||
return { commands };
|
||||
}
|
||||
const commandsMap = new Map();
|
||||
for (const command of commands) {
|
||||
commandsMap.set(command.index.toString(), command);
|
||||
commandsMap.set(command.name, command);
|
||||
}
|
||||
Rx.fromEvent(inputStream, 'data')
|
||||
.pipe(map((data) => String(data)))
|
||||
.subscribe((data) => {
|
||||
const dataParts = data.split(/:(.+)/s);
|
||||
let target = dataParts[0];
|
||||
let command = commandsMap.get(target);
|
||||
let input;
|
||||
if (dataParts.length > 1 && command) {
|
||||
input = dataParts[1];
|
||||
}
|
||||
else {
|
||||
// If `target` does not match a registered command,
|
||||
// fallback to `defaultInputTarget` and forward the whole input data
|
||||
target = this.defaultInputTarget.toString();
|
||||
command = commandsMap.get(target);
|
||||
input = data;
|
||||
}
|
||||
if (command?.stdin) {
|
||||
command.stdin.write(input);
|
||||
}
|
||||
else {
|
||||
this.logger.logGlobalEvent(`Unable to find command "${target}", or it has no stdin open\n`);
|
||||
}
|
||||
});
|
||||
return {
|
||||
commands,
|
||||
onFinish: () => {
|
||||
if (this.pauseInputStreamOnFinish) {
|
||||
// https://github.com/kimmobrunfeldt/concurrently/issues/252
|
||||
inputStream.pause();
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
19
node_modules/concurrently/dist/lib/flow-control/kill-on-signal.d.ts
generated
vendored
Normal file
19
node_modules/concurrently/dist/lib/flow-control/kill-on-signal.d.ts
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
import EventEmitter from 'node:events';
|
||||
import { Command } from '../command.js';
|
||||
import { FlowController } from './flow-controller.js';
|
||||
/**
|
||||
* Watches the main concurrently process for signals and sends the same signal down to each spawned
|
||||
* command.
|
||||
*/
|
||||
export declare class KillOnSignal implements FlowController {
|
||||
private readonly process;
|
||||
private readonly abortController?;
|
||||
constructor({ process, abortController, }: {
|
||||
process: EventEmitter;
|
||||
abortController?: AbortController;
|
||||
});
|
||||
handle(commands: Command[]): {
|
||||
commands: Command[];
|
||||
onFinish: () => void;
|
||||
};
|
||||
}
|
||||
43
node_modules/concurrently/dist/lib/flow-control/kill-on-signal.js
generated
vendored
Normal file
43
node_modules/concurrently/dist/lib/flow-control/kill-on-signal.js
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
import { map } from 'rxjs/operators';
|
||||
const SIGNALS = ['SIGINT', 'SIGTERM', 'SIGHUP'];
|
||||
/**
|
||||
* Watches the main concurrently process for signals and sends the same signal down to each spawned
|
||||
* command.
|
||||
*/
|
||||
export class KillOnSignal {
|
||||
process;
|
||||
abortController;
|
||||
constructor({ process, abortController, }) {
|
||||
this.process = process;
|
||||
this.abortController = abortController;
|
||||
}
|
||||
handle(commands) {
|
||||
let caughtSignal;
|
||||
const signalListener = (signal) => {
|
||||
caughtSignal = signal;
|
||||
this.abortController?.abort();
|
||||
commands.forEach((command) => command.kill(signal));
|
||||
};
|
||||
SIGNALS.forEach((signal) => this.process.on(signal, signalListener));
|
||||
return {
|
||||
commands: commands.map((command) => {
|
||||
const closeStream = command.close.pipe(map((exitInfo) => {
|
||||
const exitCode = caughtSignal === 'SIGINT' ? 0 : exitInfo.exitCode;
|
||||
return { ...exitInfo, exitCode };
|
||||
}));
|
||||
// Return a proxy so that mutations happen on the original Command object.
|
||||
// If either `Object.assign()` or `Object.create()` were used, it'd be hard to
|
||||
// reflect the mutations on Command objects referenced by previous flow controllers.
|
||||
return new Proxy(command, {
|
||||
get(target, prop) {
|
||||
return prop === 'close' ? closeStream : target[prop];
|
||||
},
|
||||
});
|
||||
}),
|
||||
onFinish: () => {
|
||||
// Avoids MaxListenersExceededWarning when running programmatically
|
||||
SIGNALS.forEach((signal) => this.process.off(signal, signalListener));
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
25
node_modules/concurrently/dist/lib/flow-control/kill-others.d.ts
generated
vendored
Normal file
25
node_modules/concurrently/dist/lib/flow-control/kill-others.d.ts
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
import { Command } from '../command.js';
|
||||
import { Logger } from '../logger.js';
|
||||
import { FlowController } from './flow-controller.js';
|
||||
export type ProcessCloseCondition = 'failure' | 'success';
|
||||
/**
|
||||
* Sends a SIGTERM signal to all commands when one of the commands exits with a matching condition.
|
||||
*/
|
||||
export declare class KillOthers implements FlowController {
|
||||
private readonly logger;
|
||||
private readonly abortController?;
|
||||
private readonly conditions;
|
||||
private readonly killSignal;
|
||||
private readonly timeoutMs?;
|
||||
constructor({ logger, abortController, conditions, killSignal, timeoutMs, }: {
|
||||
logger: Logger;
|
||||
abortController?: AbortController;
|
||||
conditions: ProcessCloseCondition | ProcessCloseCondition[];
|
||||
killSignal: string | undefined;
|
||||
timeoutMs?: number;
|
||||
});
|
||||
handle(commands: Command[]): {
|
||||
commands: Command[];
|
||||
};
|
||||
private maybeForceKill;
|
||||
}
|
||||
50
node_modules/concurrently/dist/lib/flow-control/kill-others.js
generated
vendored
Normal file
50
node_modules/concurrently/dist/lib/flow-control/kill-others.js
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
import { filter, map } from 'rxjs/operators';
|
||||
import { Command } from '../command.js';
|
||||
import { castArray } from '../utils.js';
|
||||
/**
|
||||
* Sends a SIGTERM signal to all commands when one of the commands exits with a matching condition.
|
||||
*/
|
||||
export class KillOthers {
|
||||
logger;
|
||||
abortController;
|
||||
conditions;
|
||||
killSignal;
|
||||
timeoutMs;
|
||||
constructor({ logger, abortController, conditions, killSignal, timeoutMs, }) {
|
||||
this.logger = logger;
|
||||
this.abortController = abortController;
|
||||
this.conditions = castArray(conditions);
|
||||
this.killSignal = killSignal;
|
||||
this.timeoutMs = timeoutMs;
|
||||
}
|
||||
handle(commands) {
|
||||
const conditions = this.conditions.filter((condition) => condition === 'failure' || condition === 'success');
|
||||
if (!conditions.length) {
|
||||
return { commands };
|
||||
}
|
||||
const closeStates = commands.map((command) => command.close.pipe(map(({ exitCode }) => exitCode === 0 ? 'success' : 'failure'), filter((state) => conditions.includes(state))));
|
||||
closeStates.forEach((closeState) => closeState.subscribe(() => {
|
||||
this.abortController?.abort();
|
||||
const killableCommands = commands.filter((command) => Command.canKill(command));
|
||||
if (killableCommands.length) {
|
||||
this.logger.logGlobalEvent(`Sending ${this.killSignal || 'SIGTERM'} to other processes..`);
|
||||
killableCommands.forEach((command) => command.kill(this.killSignal));
|
||||
this.maybeForceKill(killableCommands);
|
||||
}
|
||||
}));
|
||||
return { commands };
|
||||
}
|
||||
maybeForceKill(commands) {
|
||||
// No need to force kill when the signal already is SIGKILL.
|
||||
if (!this.timeoutMs || this.killSignal === 'SIGKILL') {
|
||||
return;
|
||||
}
|
||||
setTimeout(() => {
|
||||
const killableCommands = commands.filter((command) => Command.canKill(command));
|
||||
if (killableCommands) {
|
||||
this.logger.logGlobalEvent(`Sending SIGKILL to ${killableCommands.length} processes..`);
|
||||
killableCommands.forEach((command) => command.kill('SIGKILL'));
|
||||
}
|
||||
}, this.timeoutMs);
|
||||
}
|
||||
}
|
||||
15
node_modules/concurrently/dist/lib/flow-control/log-error.d.ts
generated
vendored
Normal file
15
node_modules/concurrently/dist/lib/flow-control/log-error.d.ts
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Command } from '../command.js';
|
||||
import { Logger } from '../logger.js';
|
||||
import { FlowController } from './flow-controller.js';
|
||||
/**
|
||||
* Logs when commands failed executing, e.g. due to the executable not existing in the system.
|
||||
*/
|
||||
export declare class LogError implements FlowController {
|
||||
private readonly logger;
|
||||
constructor({ logger }: {
|
||||
logger: Logger;
|
||||
});
|
||||
handle(commands: Command[]): {
|
||||
commands: Command[];
|
||||
};
|
||||
}
|
||||
17
node_modules/concurrently/dist/lib/flow-control/log-error.js
generated
vendored
Normal file
17
node_modules/concurrently/dist/lib/flow-control/log-error.js
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Logs when commands failed executing, e.g. due to the executable not existing in the system.
|
||||
*/
|
||||
export class LogError {
|
||||
logger;
|
||||
constructor({ logger }) {
|
||||
this.logger = logger;
|
||||
}
|
||||
handle(commands) {
|
||||
commands.forEach((command) => command.error.subscribe((event) => {
|
||||
this.logger.logCommandEvent(`Error occurred when executing command: ${command.command}`, command);
|
||||
const errorText = String(event instanceof Error ? event.stack || event : event);
|
||||
this.logger.logCommandEvent(errorText, command);
|
||||
}));
|
||||
return { commands };
|
||||
}
|
||||
}
|
||||
15
node_modules/concurrently/dist/lib/flow-control/log-exit.d.ts
generated
vendored
Normal file
15
node_modules/concurrently/dist/lib/flow-control/log-exit.d.ts
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Command } from '../command.js';
|
||||
import { Logger } from '../logger.js';
|
||||
import { FlowController } from './flow-controller.js';
|
||||
/**
|
||||
* Logs the exit code/signal of commands.
|
||||
*/
|
||||
export declare class LogExit implements FlowController {
|
||||
private readonly logger;
|
||||
constructor({ logger }: {
|
||||
logger: Logger;
|
||||
});
|
||||
handle(commands: Command[]): {
|
||||
commands: Command[];
|
||||
};
|
||||
}
|
||||
15
node_modules/concurrently/dist/lib/flow-control/log-exit.js
generated
vendored
Normal file
15
node_modules/concurrently/dist/lib/flow-control/log-exit.js
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Logs the exit code/signal of commands.
|
||||
*/
|
||||
export class LogExit {
|
||||
logger;
|
||||
constructor({ logger }) {
|
||||
this.logger = logger;
|
||||
}
|
||||
handle(commands) {
|
||||
commands.forEach((command) => command.close.subscribe(({ exitCode }) => {
|
||||
this.logger.logCommandEvent(`${command.command} exited with code ${exitCode}`, command);
|
||||
}));
|
||||
return { commands };
|
||||
}
|
||||
}
|
||||
15
node_modules/concurrently/dist/lib/flow-control/log-output.d.ts
generated
vendored
Normal file
15
node_modules/concurrently/dist/lib/flow-control/log-output.d.ts
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Command } from '../command.js';
|
||||
import { Logger } from '../logger.js';
|
||||
import { FlowController } from './flow-controller.js';
|
||||
/**
|
||||
* Logs the stdout and stderr output of commands.
|
||||
*/
|
||||
export declare class LogOutput implements FlowController {
|
||||
private readonly logger;
|
||||
constructor({ logger }: {
|
||||
logger: Logger;
|
||||
});
|
||||
handle(commands: Command[]): {
|
||||
commands: Command[];
|
||||
};
|
||||
}
|
||||
16
node_modules/concurrently/dist/lib/flow-control/log-output.js
generated
vendored
Normal file
16
node_modules/concurrently/dist/lib/flow-control/log-output.js
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Logs the stdout and stderr output of commands.
|
||||
*/
|
||||
export class LogOutput {
|
||||
logger;
|
||||
constructor({ logger }) {
|
||||
this.logger = logger;
|
||||
}
|
||||
handle(commands) {
|
||||
commands.forEach((command) => {
|
||||
command.stdout.subscribe((text) => this.logger.logCommandText(text.toString(), command));
|
||||
command.stderr.subscribe((text) => this.logger.logCommandText(text.toString(), command));
|
||||
});
|
||||
return { commands };
|
||||
}
|
||||
}
|
||||
31
node_modules/concurrently/dist/lib/flow-control/log-timings.d.ts
generated
vendored
Normal file
31
node_modules/concurrently/dist/lib/flow-control/log-timings.d.ts
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
import { CloseEvent, Command } from '../command.js';
|
||||
import { Logger } from '../logger.js';
|
||||
import { FlowController } from './flow-controller.js';
|
||||
type TimingInfo = {
|
||||
name: string;
|
||||
duration: string;
|
||||
'exit code': string | number;
|
||||
killed: boolean;
|
||||
command: string;
|
||||
};
|
||||
/**
|
||||
* Logs timing information about commands as they start/stop and then a summary when all commands finish.
|
||||
*/
|
||||
export declare class LogTimings implements FlowController {
|
||||
static mapCloseEventToTimingInfo({ command, timings, killed, exitCode, }: CloseEvent): TimingInfo;
|
||||
private readonly logger?;
|
||||
private readonly dateFormatter;
|
||||
constructor({ logger, timestampFormat, }: {
|
||||
logger?: Logger;
|
||||
timestampFormat?: string;
|
||||
});
|
||||
private printExitInfoTimingTable;
|
||||
handle(commands: Command[]): {
|
||||
commands: Command[];
|
||||
onFinish?: undefined;
|
||||
} | {
|
||||
commands: Command[];
|
||||
onFinish: () => void;
|
||||
};
|
||||
}
|
||||
export {};
|
||||
61
node_modules/concurrently/dist/lib/flow-control/log-timings.js
generated
vendored
Normal file
61
node_modules/concurrently/dist/lib/flow-control/log-timings.js
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
import assert from 'node:assert';
|
||||
import Rx from 'rxjs';
|
||||
import { bufferCount, combineLatestWith, take } from 'rxjs/operators';
|
||||
import { DateFormatter } from '../date-format.js';
|
||||
import * as defaults from '../defaults.js';
|
||||
/**
|
||||
* Logs timing information about commands as they start/stop and then a summary when all commands finish.
|
||||
*/
|
||||
export class LogTimings {
|
||||
static mapCloseEventToTimingInfo({ command, timings, killed, exitCode, }) {
|
||||
const readableDurationMs = (timings.endDate.getTime() - timings.startDate.getTime()).toLocaleString();
|
||||
return {
|
||||
name: command.name,
|
||||
duration: readableDurationMs,
|
||||
'exit code': exitCode,
|
||||
killed,
|
||||
command: command.command,
|
||||
};
|
||||
}
|
||||
logger;
|
||||
dateFormatter;
|
||||
constructor({ logger, timestampFormat = defaults.timestampFormat, }) {
|
||||
this.logger = logger;
|
||||
this.dateFormatter = new DateFormatter(timestampFormat);
|
||||
}
|
||||
printExitInfoTimingTable(exitInfos) {
|
||||
assert.ok(this.logger);
|
||||
const exitInfoTable = exitInfos
|
||||
.sort((a, b) => b.timings.durationSeconds - a.timings.durationSeconds)
|
||||
.map(LogTimings.mapCloseEventToTimingInfo);
|
||||
this.logger.logGlobalEvent('Timings:');
|
||||
this.logger.logTable(exitInfoTable);
|
||||
return exitInfos;
|
||||
}
|
||||
handle(commands) {
|
||||
const { logger } = this;
|
||||
if (!logger) {
|
||||
return { commands };
|
||||
}
|
||||
// individual process timings
|
||||
commands.forEach((command) => {
|
||||
command.timer.subscribe(({ startDate, endDate }) => {
|
||||
if (!endDate) {
|
||||
const formattedStartDate = this.dateFormatter.format(startDate);
|
||||
logger.logCommandEvent(`${command.command} started at ${formattedStartDate}`, command);
|
||||
}
|
||||
else {
|
||||
const durationMs = endDate.getTime() - startDate.getTime();
|
||||
const formattedEndDate = this.dateFormatter.format(endDate);
|
||||
logger.logCommandEvent(`${command.command} stopped at ${formattedEndDate} after ${durationMs.toLocaleString()}ms`, command);
|
||||
}
|
||||
});
|
||||
});
|
||||
// overall summary timings
|
||||
const closeStreams = commands.map((command) => command.close);
|
||||
const finished = new Rx.Subject();
|
||||
const allProcessesClosed = Rx.merge(...closeStreams).pipe(bufferCount(closeStreams.length), take(1), combineLatestWith(finished));
|
||||
allProcessesClosed.subscribe(([exitInfos]) => this.printExitInfoTimingTable(exitInfos));
|
||||
return { commands, onFinish: () => finished.next() };
|
||||
}
|
||||
}
|
||||
13
node_modules/concurrently/dist/lib/flow-control/logger-padding.d.ts
generated
vendored
Normal file
13
node_modules/concurrently/dist/lib/flow-control/logger-padding.d.ts
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
import { Command } from '../command.js';
|
||||
import { Logger } from '../logger.js';
|
||||
import { FlowController } from './flow-controller.js';
|
||||
export declare class LoggerPadding implements FlowController {
|
||||
private readonly logger;
|
||||
constructor({ logger }: {
|
||||
logger: Logger;
|
||||
});
|
||||
handle(commands: Command[]): {
|
||||
commands: Command[];
|
||||
onFinish: () => void;
|
||||
};
|
||||
}
|
||||
35
node_modules/concurrently/dist/lib/flow-control/logger-padding.js
generated
vendored
Normal file
35
node_modules/concurrently/dist/lib/flow-control/logger-padding.js
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
import { COLOR_MARKER_RE } from '../logger.js';
|
||||
function visibleLength(value) {
|
||||
return value ? value.replace(COLOR_MARKER_RE, '').length : 0;
|
||||
}
|
||||
export class LoggerPadding {
|
||||
logger;
|
||||
constructor({ logger }) {
|
||||
this.logger = logger;
|
||||
}
|
||||
handle(commands) {
|
||||
// Sometimes there's limited concurrency, so not all commands will spawn straight away.
|
||||
// Compute the prefix length now, which works for all styles but those with a PID.
|
||||
let length = commands.reduce((length, command) => {
|
||||
const content = this.logger.getPrefixContent(command);
|
||||
return Math.max(length, visibleLength(content?.value));
|
||||
}, 0);
|
||||
this.logger.setPrefixLength(length);
|
||||
// The length of prefixes is somewhat stable, except for PIDs, which might change when a
|
||||
// process spawns (e.g. PIDs might look like 1, 10 or 100), therefore listen to command starts
|
||||
// and update the prefix length when this happens.
|
||||
const subs = commands.map((command) => command.timer.subscribe((event) => {
|
||||
if (!event.endDate) {
|
||||
const content = this.logger.getPrefixContent(command);
|
||||
length = Math.max(length, visibleLength(content?.value));
|
||||
this.logger.setPrefixLength(length);
|
||||
}
|
||||
}));
|
||||
return {
|
||||
commands,
|
||||
onFinish() {
|
||||
subs.forEach((sub) => sub.unsubscribe());
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
18
node_modules/concurrently/dist/lib/flow-control/output-error-handler.d.ts
generated
vendored
Normal file
18
node_modules/concurrently/dist/lib/flow-control/output-error-handler.d.ts
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Writable } from 'node:stream';
|
||||
import { Command } from '../command.js';
|
||||
import { FlowController } from './flow-controller.js';
|
||||
/**
|
||||
* Kills processes and aborts further command spawning on output stream error (namely, SIGPIPE).
|
||||
*/
|
||||
export declare class OutputErrorHandler implements FlowController {
|
||||
private readonly outputStream;
|
||||
private readonly abortController;
|
||||
constructor({ abortController, outputStream, }: {
|
||||
abortController: AbortController;
|
||||
outputStream: Writable;
|
||||
});
|
||||
handle(commands: Command[]): {
|
||||
commands: Command[];
|
||||
onFinish: () => void;
|
||||
};
|
||||
}
|
||||
23
node_modules/concurrently/dist/lib/flow-control/output-error-handler.js
generated
vendored
Normal file
23
node_modules/concurrently/dist/lib/flow-control/output-error-handler.js
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
import { fromSharedEvent } from '../observables.js';
|
||||
/**
|
||||
* Kills processes and aborts further command spawning on output stream error (namely, SIGPIPE).
|
||||
*/
|
||||
export class OutputErrorHandler {
|
||||
outputStream;
|
||||
abortController;
|
||||
constructor({ abortController, outputStream, }) {
|
||||
this.abortController = abortController;
|
||||
this.outputStream = outputStream;
|
||||
}
|
||||
handle(commands) {
|
||||
const subscription = fromSharedEvent(this.outputStream, 'error').subscribe(() => {
|
||||
commands.forEach((command) => command.kill());
|
||||
// Avoid further commands from spawning, e.g. if `RestartProcess` is used.
|
||||
this.abortController.abort();
|
||||
});
|
||||
return {
|
||||
commands,
|
||||
onFinish: () => subscription.unsubscribe(),
|
||||
};
|
||||
}
|
||||
}
|
||||
23
node_modules/concurrently/dist/lib/flow-control/restart-process.d.ts
generated
vendored
Normal file
23
node_modules/concurrently/dist/lib/flow-control/restart-process.d.ts
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
import Rx from 'rxjs';
|
||||
import { Command } from '../command.js';
|
||||
import { Logger } from '../logger.js';
|
||||
import { FlowController } from './flow-controller.js';
|
||||
export type RestartDelay = number | 'exponential';
|
||||
/**
|
||||
* Restarts commands that fail up to a defined number of times.
|
||||
*/
|
||||
export declare class RestartProcess implements FlowController {
|
||||
private readonly logger;
|
||||
private readonly scheduler?;
|
||||
private readonly delay;
|
||||
readonly tries: number;
|
||||
constructor({ delay, tries, logger, scheduler, }: {
|
||||
delay?: RestartDelay;
|
||||
tries?: number;
|
||||
logger: Logger;
|
||||
scheduler?: Rx.SchedulerLike;
|
||||
});
|
||||
handle(commands: Command[]): {
|
||||
commands: Command[];
|
||||
};
|
||||
}
|
||||
61
node_modules/concurrently/dist/lib/flow-control/restart-process.js
generated
vendored
Normal file
61
node_modules/concurrently/dist/lib/flow-control/restart-process.js
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
import Rx from 'rxjs';
|
||||
import { defaultIfEmpty, delayWhen, filter, map, skip, take, takeWhile } from 'rxjs/operators';
|
||||
import * as defaults from '../defaults.js';
|
||||
/**
|
||||
* Restarts commands that fail up to a defined number of times.
|
||||
*/
|
||||
export class RestartProcess {
|
||||
logger;
|
||||
scheduler;
|
||||
delay;
|
||||
tries;
|
||||
constructor({ delay, tries, logger, scheduler, }) {
|
||||
this.logger = logger;
|
||||
this.delay = delay ?? 0;
|
||||
this.tries = tries != null ? +tries : defaults.restartTries;
|
||||
this.tries = this.tries < 0 ? Infinity : this.tries;
|
||||
this.scheduler = scheduler;
|
||||
}
|
||||
handle(commands) {
|
||||
if (this.tries === 0) {
|
||||
return { commands };
|
||||
}
|
||||
const delayOperator = delayWhen((_, index) => {
|
||||
const { delay } = this;
|
||||
const value = delay === 'exponential' ? 2 ** index * 1000 : delay;
|
||||
return Rx.timer(value, this.scheduler);
|
||||
});
|
||||
commands
|
||||
.map((command) => command.close.pipe(take(this.tries), takeWhile(({ exitCode }) => exitCode !== 0)))
|
||||
.forEach((failure, index) => Rx.merge(
|
||||
// Delay the emission (so that the restarts happen on time),
|
||||
// explicitly telling the subscriber that a restart is needed
|
||||
failure.pipe(delayOperator, map(() => true)),
|
||||
// Skip the first N emissions (as these would be duplicates of the above),
|
||||
// meaning it will be empty because of success, or failed all N times,
|
||||
// and no more restarts should be attempted.
|
||||
failure.pipe(skip(this.tries), map(() => false), defaultIfEmpty(false))).subscribe((restart) => {
|
||||
const command = commands[index];
|
||||
if (restart) {
|
||||
this.logger.logCommandEvent(`${command.command} restarted`, command);
|
||||
command.start();
|
||||
}
|
||||
}));
|
||||
return {
|
||||
commands: commands.map((command) => {
|
||||
const closeStream = command.close.pipe(filter(({ exitCode }, emission) => {
|
||||
// We let all success codes pass, and failures only after restarting won't happen again
|
||||
return exitCode === 0 || emission >= this.tries;
|
||||
}));
|
||||
// Return a proxy so that mutations happen on the original Command object.
|
||||
// If either `Object.assign()` or `Object.create()` were used, it'd be hard to
|
||||
// reflect the mutations on Command objects referenced by previous flow controllers.
|
||||
return new Proxy(command, {
|
||||
get(target, prop) {
|
||||
return prop === 'close' ? closeStream : target[prop];
|
||||
},
|
||||
});
|
||||
}),
|
||||
};
|
||||
}
|
||||
}
|
||||
20
node_modules/concurrently/dist/lib/flow-control/teardown.d.ts
generated
vendored
Normal file
20
node_modules/concurrently/dist/lib/flow-control/teardown.d.ts
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Command, SpawnCommand } from '../command.js';
|
||||
import { Logger } from '../logger.js';
|
||||
import { FlowController } from './flow-controller.js';
|
||||
export declare class Teardown implements FlowController {
|
||||
private readonly logger;
|
||||
private readonly spawn;
|
||||
private readonly teardown;
|
||||
constructor({ logger, spawn, commands, }: {
|
||||
logger: Logger;
|
||||
/**
|
||||
* Which function to use to spawn commands.
|
||||
*/
|
||||
spawn: SpawnCommand;
|
||||
commands: readonly string[];
|
||||
});
|
||||
handle(commands: Command[]): {
|
||||
commands: Command[];
|
||||
onFinish: () => Promise<void>;
|
||||
};
|
||||
}
|
||||
45
node_modules/concurrently/dist/lib/flow-control/teardown.js
generated
vendored
Normal file
45
node_modules/concurrently/dist/lib/flow-control/teardown.js
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
import Rx from 'rxjs';
|
||||
import { getSpawnOpts } from '../spawn.js';
|
||||
export class Teardown {
|
||||
logger;
|
||||
spawn;
|
||||
teardown;
|
||||
constructor({ logger, spawn, commands, }) {
|
||||
this.logger = logger;
|
||||
this.spawn = spawn;
|
||||
this.teardown = commands;
|
||||
}
|
||||
handle(commands) {
|
||||
const { logger, teardown, spawn } = this;
|
||||
const onFinish = async () => {
|
||||
if (!teardown.length) {
|
||||
return;
|
||||
}
|
||||
for (const command of teardown) {
|
||||
logger.logGlobalEvent(`Running teardown command "${command}"`);
|
||||
const child = spawn(command, getSpawnOpts({ stdio: 'raw' }));
|
||||
const error = Rx.fromEvent(child, 'error');
|
||||
const close = Rx.fromEvent(child, 'close');
|
||||
try {
|
||||
const [exitCode, signal] = await Promise.race([
|
||||
Rx.firstValueFrom(error).then((event) => {
|
||||
throw event;
|
||||
}),
|
||||
Rx.firstValueFrom(close).then((event) => event),
|
||||
]);
|
||||
logger.logGlobalEvent(`Teardown command "${command}" exited with code ${exitCode ?? signal}`);
|
||||
if (signal === 'SIGINT') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
const errorText = String(error instanceof Error ? error.stack || error : error);
|
||||
logger.logGlobalEvent(`Teardown command "${command}" errored:`);
|
||||
logger.logGlobalEvent(errorText);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}
|
||||
};
|
||||
return { commands, onFinish };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user