concurrently.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. #!/usr/bin/env node
  2. const fs = require('fs');
  3. const yargs = require('yargs');
  4. const defaults = require('../src/defaults');
  5. const concurrently = require('../index');
  6. const args = yargs
  7. .usage('$0 [options] <command ...>')
  8. .help('h')
  9. .alias('h', 'help')
  10. .version('v', require('../package.json').version)
  11. .alias('v', 'V')
  12. .alias('v', 'version')
  13. // TODO: Add some tests for this.
  14. .env('CONCURRENTLY')
  15. .options({
  16. // General
  17. 'm': {
  18. alias: 'max-processes',
  19. describe:
  20. 'How many processes should run at once.\n' +
  21. 'New processes only spawn after all restart tries of a process.',
  22. type: 'number'
  23. },
  24. 'n': {
  25. alias: 'names',
  26. describe:
  27. 'List of custom names to be used in prefix template.\n' +
  28. 'Example names: "main,browser,server"',
  29. type: 'string'
  30. },
  31. 'name-separator': {
  32. describe:
  33. 'The character to split <names> on. Example usage:\n' +
  34. 'concurrently -n "styles|scripts|server" --name-separator "|"',
  35. default: defaults.nameSeparator,
  36. },
  37. 's': {
  38. alias: 'success',
  39. describe:
  40. 'Return exit code of zero or one based on the success or failure ' +
  41. 'of the "first" child to terminate, the "last child", or succeed ' +
  42. 'only if "all" child processes succeed.',
  43. choices: ['first', 'last', 'all'],
  44. default: defaults.success
  45. },
  46. 'r': {
  47. alias: 'raw',
  48. describe:
  49. 'Output only raw output of processes, disables prettifying ' +
  50. 'and concurrently coloring.',
  51. type: 'boolean'
  52. },
  53. // This one is provided for free. Chalk reads this itself and removes colours.
  54. // https://www.npmjs.com/package/chalk#chalksupportscolor
  55. 'no-color': {
  56. describe: 'Disables colors from logging',
  57. type: 'boolean'
  58. },
  59. 'hide': {
  60. describe:
  61. 'Comma-separated list of processes to hide the output.\n' +
  62. 'The processes can be identified by their name or index.',
  63. default: defaults.hide,
  64. type: 'string'
  65. },
  66. 'timings': {
  67. describe: 'Show timing information for all processes',
  68. type: 'boolean',
  69. default: defaults.timings
  70. },
  71. // Kill others
  72. 'k': {
  73. alias: 'kill-others',
  74. describe: 'kill other processes if one exits or dies',
  75. type: 'boolean'
  76. },
  77. 'kill-others-on-fail': {
  78. describe: 'kill other processes if one exits with non zero status code',
  79. type: 'boolean'
  80. },
  81. // Prefix
  82. 'p': {
  83. alias: 'prefix',
  84. describe:
  85. 'Prefix used in logging for each process.\n' +
  86. 'Possible values: index, pid, time, command, name, none, or a template. ' +
  87. 'Example template: "{time}-{pid}"',
  88. defaultDescription: 'index or name (when --names is set)',
  89. type: 'string'
  90. },
  91. 'c': {
  92. alias: 'prefix-colors',
  93. describe:
  94. 'Comma-separated list of chalk colors to use on prefixes. ' +
  95. 'If there are more commands than colors, the last color will be repeated.\n' +
  96. '- Available modifiers: reset, bold, dim, italic, underline, inverse, hidden, strikethrough\n' +
  97. '- Available colors: black, red, green, yellow, blue, magenta, cyan, white, gray \n' +
  98. 'or any hex values for colors, eg #23de43\n' +
  99. '- Available background colors: bgBlack, bgRed, bgGreen, bgYellow, bgBlue, bgMagenta, bgCyan, bgWhite\n' +
  100. 'See https://www.npmjs.com/package/chalk for more information.',
  101. default: defaults.prefixColors,
  102. type: 'string'
  103. },
  104. 'l': {
  105. alias: 'prefix-length',
  106. describe:
  107. 'Limit how many characters of the command is displayed in prefix. ' +
  108. 'The option can be used to shorten the prefix when it is set to "command"',
  109. default: defaults.prefixLength,
  110. type: 'number'
  111. },
  112. 't': {
  113. alias: 'timestamp-format',
  114. describe: 'Specify the timestamp in moment/date-fns format.',
  115. default: defaults.timestampFormat,
  116. type: 'string'
  117. },
  118. // Restarting
  119. 'restart-tries': {
  120. describe:
  121. 'How many times a process that died should restart.\n' +
  122. 'Negative numbers will make the process restart forever.',
  123. default: defaults.restartTries,
  124. type: 'number'
  125. },
  126. 'restart-after': {
  127. describe: 'Delay time to respawn the process, in milliseconds.',
  128. default: defaults.restartDelay,
  129. type: 'number'
  130. },
  131. // Input
  132. 'i': {
  133. alias: 'handle-input',
  134. describe:
  135. 'Whether input should be forwarded to the child processes. ' +
  136. 'See examples for more information.',
  137. type: 'boolean'
  138. },
  139. 'default-input-target': {
  140. default: defaults.defaultInputTarget,
  141. describe:
  142. 'Identifier for child process to which input on stdin ' +
  143. 'should be sent if not specified at start of input.\n' +
  144. 'Can be either the index or the name of the process.'
  145. }
  146. })
  147. .group(['m', 'n', 'name-separator', 'raw', 's', 'no-color', 'hide', 'timings'], 'General')
  148. .group(['p', 'c', 'l', 't'], 'Prefix styling')
  149. .group(['i', 'default-input-target'], 'Input handling')
  150. .group(['k', 'kill-others-on-fail'], 'Killing other processes')
  151. .group(['restart-tries', 'restart-after'], 'Restarting')
  152. // Too much text to write as JS strings, .txt file is better
  153. .epilogue(fs.readFileSync(__dirname + '/epilogue.txt', { encoding: 'utf8' }))
  154. .argv;
  155. const names = (args.names || '').split(args.nameSeparator);
  156. concurrently(args._.map((command, index) => ({
  157. command,
  158. name: names[index]
  159. })), {
  160. handleInput: args.handleInput,
  161. defaultInputTarget: args.defaultInputTarget,
  162. killOthers: args.killOthers
  163. ? ['success', 'failure']
  164. : (args.killOthersOnFail ? ['failure'] : []),
  165. maxProcesses: args.maxProcesses,
  166. raw: args.raw,
  167. hide: args.hide.split(','),
  168. prefix: args.prefix,
  169. prefixColors: args.prefixColors.split(','),
  170. prefixLength: args.prefixLength,
  171. restartDelay: args.restartAfter,
  172. restartTries: args.restartTries,
  173. successCondition: args.success,
  174. timestampFormat: args.timestampFormat,
  175. timings: args.timings
  176. }).then(
  177. () => process.exit(0),
  178. () => process.exit(1)
  179. );