concurrently.js 11 KB

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