exec.js 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. var spawn = require('child_process').spawn;
  2. module.exports = exec;
  3. /**
  4. * Spawn a child with the ease of exec, but safety of spawn
  5. *
  6. * @param args array ex. [ 'ls', '-lha' ]
  7. * @param opts object [optional] to pass to spawn
  8. * @param callback function(err, out, code)
  9. *
  10. * @return spawn object
  11. */
  12. function exec(args, opts, callback) {
  13. if (arguments.length < 2)
  14. throw new Error('invalid arguments');
  15. if (typeof opts === 'function') {
  16. callback = opts;
  17. opts = {};
  18. }
  19. if (typeof args === 'string') {
  20. args = ['/bin/sh', '-c', args];
  21. }
  22. opts.env = opts.env || process.env;
  23. opts.encoding = opts.encoding || 'utf-8';
  24. opts.killSignal = opts.killSignal || 'SIGTERM';
  25. var out;
  26. var err;
  27. var encoding;
  28. var timeout;
  29. var done = false;
  30. // check encoding
  31. if (opts.encoding !== 'buffer' && Buffer.isEncoding(opts.encoding)) {
  32. // string
  33. encoding = opts.encoding;
  34. out = '';
  35. err = '';
  36. } else {
  37. // buffer
  38. encoding = null;
  39. out = [];
  40. err = [];
  41. }
  42. var child = spawn(args[0], args.slice(1), opts);
  43. if (encoding) {
  44. if (child.stdout) {
  45. child.stdout.setEncoding(encoding);
  46. }
  47. if (child.stderr) {
  48. child.stderr.setEncoding(encoding);
  49. }
  50. }
  51. if (child.stdout) {
  52. child.stdout.on('data', function(data) {
  53. if (encoding)
  54. out += data;
  55. else
  56. out.push(data);
  57. });
  58. }
  59. if (child.strerr) {
  60. child.stderr.on('data', function(data) {
  61. if (encoding)
  62. err += data;
  63. else
  64. err.push(data);
  65. });
  66. }
  67. child.on('close', function(code) {
  68. if (done)
  69. return;
  70. done = true;
  71. if (timeout)
  72. clearTimeout(timeout);
  73. if (!encoding) {
  74. out = Buffer.concat(out);
  75. err = Buffer.concat(err);
  76. }
  77. callback(err, out, code);
  78. });
  79. child.on('error', function(e) {
  80. if (done)
  81. return;
  82. done = true;
  83. callback(e);
  84. });
  85. if (opts.timeout) {
  86. timeout = setTimeout(function() {
  87. child.stdout.destroy();
  88. child.stderr.destroy();
  89. try {
  90. child.kill(opts.killSignal);
  91. } catch(e) {}
  92. timeout = null;
  93. }, opts.timeout);
  94. }
  95. return child;
  96. }