Spaces:
Sleeping
Sleeping
File size: 9,355 Bytes
a23aa7d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 | #!/usr/bin/env node
import process from 'node:process';
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import * as defaults from '../lib/defaults.js';
import { concurrently } from '../lib/index.js';
import { castArray, splitOutsideParens } from '../lib/utils.js';
import { normalizeCliCommand } from './normalize-cli-command.js';
import { readPackageJson } from './read-package-json.js';
const version = String(readPackageJson().version);
const epilogue = `For documentation and more examples, visit:\nhttps://github.com/open-cli-tools/concurrently/tree/v${version}/docs`;
// Clean-up arguments (yargs expects only the arguments after the program name)
const program = yargs(hideBin(process.argv))
.parserConfiguration({
// Avoids options that can be specified multiple times from requiring a `--` to pass commands
'greedy-arrays': false,
// Makes sure that --passthrough-arguments works correctly
'populate--': true,
})
.usage('$0 [options] <command ...>')
.help('h')
.alias('h', 'help')
.version(version)
.alias('version', 'v')
.alias('version', 'V')
// TODO: Add some tests for this.
.env('CONCURRENTLY')
.options({
// General
'max-processes': {
alias: 'm',
describe: 'How many processes should run at once.\n' +
'New processes only spawn after all restart tries of a process.\n' +
'Exact number or a percent of CPUs available (for example "50%")',
type: 'string',
},
names: {
alias: 'n',
describe: 'List of custom names to be used in prefix template.\n' +
'Example names: "main,browser,server"',
type: 'string',
},
success: {
alias: 's',
describe: 'Which command(s) must exit with code 0 in order for concurrently exit with ' +
'code 0 too. Options are:\n' +
'- "first" for the first command to exit;\n' +
'- "last" for the last command to exit;\n' +
'- "all" for all commands;\n' +
// Note: not a typo. Multiple commands can have the same name.
'- "command-{name}"/"command-{index}" for the commands with that name or index;\n' +
'- "!command-{name}"/"!command-{index}" for all commands but the ones with that ' +
'name or index.\n',
default: defaults.success,
},
raw: {
alias: 'r',
describe: 'Output only raw output of processes, disables prettifying ' +
'and concurrently coloring.',
type: 'boolean',
},
// This one is provided for free. Chalk reads this itself and removes colors.
// https://www.npmjs.com/package/chalk#supportscolor
'no-color': {
describe: 'Disables colors from logging',
type: 'boolean',
},
hide: {
describe: 'Comma-separated list of processes to hide the output.\n' +
'The processes can be identified by their name or index.',
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',
default: defaults.timings,
},
shell: {
describe: 'Shell to run commands with. Defaults to cmd.exe on Windows and /bin/sh elsewhere.',
type: 'string',
},
'passthrough-arguments': {
alias: 'P',
describe: 'Passthrough additional arguments to commands (accessible via placeholders) ' +
'instead of treating them as commands.',
type: 'boolean',
default: defaults.passthroughArguments,
},
teardown: {
describe: 'Clean up command(s) to execute before exiting concurrently. Might be specified multiple times.\n' +
"These aren't prefixed and they don't affect concurrently's exit code.",
type: 'string',
array: true,
},
// Kill others
'kill-others': {
alias: 'k',
describe: 'Kill other processes once the first exits.',
type: 'boolean',
},
'kill-others-on-fail': {
describe: 'Kill other processes if one exits with non zero status code.',
type: 'boolean',
},
'kill-signal': {
alias: 'ks',
describe: 'Signal to send to other processes if one exits or dies. (SIGTERM/SIGKILL, defaults to SIGTERM)',
type: 'string',
default: defaults.killSignal,
},
'kill-timeout': {
describe: 'How many milliseconds to wait before forcing process terminating.',
type: 'number',
},
// Prefix
prefix: {
alias: 'p',
describe: 'Prefix used in logging for each process.\n' +
'Possible values: index, pid, time, command, name, none, or a template. ' +
'Example template: "{time}-{pid}"',
defaultDescription: 'index or name (when --names is set)',
type: 'string',
},
'prefix-colors': {
alias: 'c',
describe: 'Comma-separated list of Chalk colors to use on prefixes. ' +
'If there are more commands than colors, the last color will be repeated.\n' +
'- Available modifiers: reset, bold, dim, italic, underline, inverse, hidden, strikethrough\n' +
'- Available colors: black, red, green, yellow, blue, magenta, cyan, white, gray, \n' +
'any hex values for colors (e.g. #23de43) or auto for an automatically picked color\n' +
'- Available background colors: bgBlack, bgRed, bgGreen, bgYellow, bgBlue, bgMagenta, bgCyan, bgWhite\n' +
'See https://www.npmjs.com/package/chalk for more information.',
default: defaults.prefixColors,
type: 'string',
},
'prefix-length': {
alias: 'l',
describe: 'Limit how many characters of the command is displayed in prefix. ' +
'The option can be used to shorten the prefix when it is set to "command"',
default: defaults.prefixLength,
type: 'number',
},
'pad-prefix': {
describe: 'Pads short prefixes with spaces so that the length of all prefixes match',
type: 'boolean',
},
'timestamp-format': {
alias: 't',
describe: 'Specify the timestamp in Unicode format:\n' +
'https://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table',
default: defaults.timestampFormat,
type: 'string',
},
// Restarting
'restart-tries': {
describe: 'How many times a process that died should restart.\n' +
'Negative numbers will make the process restart forever.',
default: defaults.restartTries,
type: 'number',
},
'restart-after': {
describe: 'Delay before restarting the process, in milliseconds, or "exponential".',
default: defaults.restartDelay,
type: 'string',
},
// Input
'handle-input': {
alias: 'i',
describe: 'Whether input should be forwarded to the child processes. ' +
'See examples for more information.',
type: 'boolean',
},
'default-input-target': {
default: defaults.defaultInputTarget,
describe: 'Identifier for child process to which input on stdin ' +
'should be sent if not specified at start of input.\n' +
'Can be either the index or the name of the process.',
},
})
.group(['m', 'n', 's', 'r', 'no-color', 'hide', 'g', 'timings', 'shell', 'P', 'teardown'], 'General')
.group(['p', 'c', 'l', 't', 'pad-prefix'], 'Prefix styling')
.group(['i', 'default-input-target'], 'Input handling')
.group(['k', 'kill-others-on-fail', 'kill-signal', 'kill-timeout'], 'Killing other processes')
.group(['restart-tries', 'restart-after'], 'Restarting')
.epilogue(epilogue);
const args = program.parseSync();
const names = (args.names || '').split(',');
const additionalArguments = castArray(args['--'] ?? []).map(String);
const commands = args.passthroughArguments ? args._ : args._.concat(additionalArguments);
if (!commands.length) {
program.showHelp();
process.exit();
}
concurrently(commands.map((command, index) => ({
command: normalizeCliCommand(String(command)),
name: names[index],
})), {
handleInput: args.handleInput,
defaultInputTarget: args.defaultInputTarget,
killOthersOn: args.killOthers
? ['success', 'failure']
: args.killOthersOnFail
? ['failure']
: [],
killSignal: args.killSignal,
killTimeout: args.killTimeout,
maxProcesses: args.maxProcesses,
raw: args.raw,
hide: args.hide.split(','),
group: args.group,
prefix: args.prefix,
prefixColors: splitOutsideParens(args.prefixColors, ','),
prefixLength: args.prefixLength,
padPrefix: args.padPrefix,
restartDelay: args.restartAfter === 'exponential' ? 'exponential' : Number(args.restartAfter),
restartTries: args.restartTries,
successCondition: args.success,
timestampFormat: args.timestampFormat,
timings: args.timings,
shell: args.shell,
teardown: args.teardown,
additionalArguments: args.passthroughArguments ? additionalArguments : undefined,
}).result.then(() => process.exit(0), () => process.exit(1));
|