LocalCommandRunner.js 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. /* eslint-disable
  2. camelcase,
  3. no-return-assign,
  4. no-unused-vars,
  5. */
  6. // TODO: This file was created by bulk-decaffeinate.
  7. // Fix any style issues and re-enable lint.
  8. /*
  9. * decaffeinate suggestions:
  10. * DS101: Remove unnecessary use of Array.from
  11. * DS102: Remove unnecessary code created because of implicit returns
  12. * DS207: Consider shorter variations of null checks
  13. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  14. */
  15. let CommandRunner
  16. const { spawn } = require('child_process')
  17. const _ = require('lodash')
  18. const logger = require('logger-sharelatex')
  19. logger.info('using standard command runner')
  20. module.exports = CommandRunner = {
  21. run(
  22. project_id,
  23. command,
  24. directory,
  25. image,
  26. timeout,
  27. environment,
  28. compileGroup,
  29. callback
  30. ) {
  31. let key, value
  32. callback = _.once(callback)
  33. command = Array.from(command).map(arg =>
  34. arg.toString().replace('$COMPILE_DIR', directory)
  35. )
  36. logger.log({ project_id, command, directory }, 'running command')
  37. logger.warn('timeouts and sandboxing are not enabled with CommandRunner')
  38. // merge environment settings
  39. const env = {}
  40. for (key in process.env) {
  41. value = process.env[key]
  42. env[key] = value
  43. }
  44. for (key in environment) {
  45. value = environment[key]
  46. env[key] = value
  47. }
  48. // run command as detached process so it has its own process group (which can be killed if needed)
  49. const proc = spawn(command[0], command.slice(1), { cwd: directory, env })
  50. let stdout = ''
  51. proc.stdout.setEncoding('utf8').on('data', data => (stdout += data))
  52. proc.on('error', function (err) {
  53. logger.err(
  54. { err, project_id, command, directory },
  55. 'error running command'
  56. )
  57. return callback(err)
  58. })
  59. proc.on('close', function (code, signal) {
  60. let err
  61. logger.info({ code, signal, project_id }, 'command exited')
  62. if (signal === 'SIGTERM') {
  63. // signal from kill method below
  64. err = new Error('terminated')
  65. err.terminated = true
  66. return callback(err)
  67. } else if (code === 1) {
  68. // exit status from chktex
  69. err = new Error('exited')
  70. err.code = code
  71. return callback(err)
  72. } else {
  73. return callback(null, { stdout: stdout })
  74. }
  75. })
  76. return proc.pid
  77. }, // return process id to allow job to be killed if necessary
  78. kill(pid, callback) {
  79. if (callback == null) {
  80. callback = function () {}
  81. }
  82. try {
  83. process.kill(-pid) // kill all processes in group
  84. } catch (err) {
  85. return callback(err)
  86. }
  87. return callback()
  88. },
  89. }