LocalCommandRunner.js 2.6 KB

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