Repositorio del curso CCOM4030 el semestre B91 del proyecto Artesanías con el Instituto de Cultura

superspawn.js 5.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. /**
  2. Licensed to the Apache Software Foundation (ASF) under one
  3. or more contributor license agreements. See the NOTICE file
  4. distributed with this work for additional information
  5. regarding copyright ownership. The ASF licenses this file
  6. to you under the Apache License, Version 2.0 (the
  7. "License"); you may not use this file except in compliance
  8. with the License. You may obtain a copy of the License at
  9. http://www.apache.org/licenses/LICENSE-2.0
  10. Unless required by applicable law or agreed to in writing,
  11. software distributed under the License is distributed on an
  12. "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  13. KIND, either express or implied. See the License for the
  14. specific language governing permissions and limitations
  15. under the License.
  16. */
  17. var crossSpawn = require('cross-spawn');
  18. var fs = require('fs-extra');
  19. var _ = require('underscore');
  20. var Q = require('q');
  21. var events = require('./events');
  22. var iswin32 = process.platform === 'win32';
  23. /**
  24. * A special implementation for child_process.spawn that handles
  25. * Windows-specific issues with batch files and spaces in paths. Returns a
  26. * promise that succeeds only for return code 0. It is also possible to
  27. * subscribe on spawned process' stdout and stderr streams using progress
  28. * handler for resultant promise.
  29. *
  30. * @example spawn('mycommand', [], {stdio: 'pipe'}) .progress(function (stdio){
  31. * if (stdio.stderr) { console.error(stdio.stderr); } })
  32. * .then(function(result){ // do other stuff })
  33. *
  34. * @param {String} cmd A command to spawn
  35. * @param {String[]} [args=[]] An array of arguments, passed to spawned
  36. * process
  37. * @param {Object} [opts={}] A configuration object
  38. * @param {String|String[]|Object} opts.stdio Property that configures how
  39. * spawned process' stdio will behave. Has the same meaning and possible
  40. * values as 'stdio' options for child_process.spawn method
  41. * (https://nodejs.org/api/child_process.html#child_process_options_stdio).
  42. * @param {Object} [env={}] A map of extra environment variables
  43. * @param {String} [cwd=process.cwd()] Working directory for the command
  44. * @param {Boolean} [chmod=false] If truthy, will attempt to set the execute
  45. * bit before executing on non-Windows platforms
  46. *
  47. * @return {Promise} A promise that is either fulfilled if the spawned
  48. * process is exited with zero error code or rejected otherwise. If the
  49. * 'stdio' option set to 'default' or 'pipe', the promise also emits progress
  50. * messages with the following contents:
  51. * {
  52. * 'stdout': ...,
  53. * 'stderr': ...
  54. * }
  55. */
  56. exports.spawn = function (cmd, args, opts) {
  57. args = args || [];
  58. opts = opts || {};
  59. var spawnOpts = {};
  60. var d = Q.defer();
  61. if (opts.stdio !== 'default') {
  62. // Ignore 'default' value for stdio because it corresponds to child_process's default 'pipe' option
  63. spawnOpts.stdio = opts.stdio;
  64. }
  65. if (opts.cwd) {
  66. spawnOpts.cwd = opts.cwd;
  67. }
  68. if (opts.env) {
  69. spawnOpts.env = _.extend(_.extend({}, process.env), opts.env);
  70. }
  71. if (opts.chmod && !iswin32) {
  72. try {
  73. // This fails when module is installed in a system directory (e.g. via sudo npm install)
  74. fs.chmodSync(cmd, '755');
  75. } catch (e) {
  76. // If the perms weren't set right, then this will come as an error upon execution.
  77. }
  78. }
  79. events.emit(opts.printCommand ? 'log' : 'verbose', 'Running command: ' + cmd + ' ' + args.join(' '));
  80. // At least until Node.js 8, child_process.spawn will throw exceptions
  81. // instead of emitting error events in certain cases (like EACCES), Thus we
  82. // have to wrap the execution in try/catch to convert them into rejections.
  83. try {
  84. var child = crossSpawn.spawn(cmd, args, spawnOpts);
  85. } catch (e) {
  86. whenDone(e);
  87. return d.promise;
  88. }
  89. var capturedOut = '';
  90. var capturedErr = '';
  91. if (child.stdout) {
  92. child.stdout.setEncoding('utf8');
  93. child.stdout.on('data', function (data) {
  94. capturedOut += data;
  95. d.notify({ 'stdout': data });
  96. });
  97. }
  98. if (child.stderr) {
  99. child.stderr.setEncoding('utf8');
  100. child.stderr.on('data', function (data) {
  101. capturedErr += data;
  102. d.notify({ 'stderr': data });
  103. });
  104. }
  105. child.on('close', whenDone);
  106. child.on('error', whenDone);
  107. function whenDone (arg) {
  108. if (child) {
  109. child.removeListener('close', whenDone);
  110. child.removeListener('error', whenDone);
  111. }
  112. var code = typeof arg === 'number' ? arg : arg && arg.code;
  113. events.emit('verbose', 'Command finished with error code ' + code + ': ' + cmd + ' ' + args);
  114. if (code === 0) {
  115. d.resolve(capturedOut.trim());
  116. } else {
  117. var errMsg = cmd + ': Command failed with exit code ' + code;
  118. if (capturedErr) {
  119. errMsg += ' Error output:\n' + capturedErr.trim();
  120. }
  121. var err = new Error(errMsg);
  122. if (capturedErr) {
  123. err.stderr = capturedErr;
  124. }
  125. if (capturedOut) {
  126. err.stdout = capturedOut;
  127. }
  128. err.code = code;
  129. d.reject(err);
  130. }
  131. }
  132. return d.promise;
  133. };
  134. exports.maybeSpawn = function (cmd, args, opts) {
  135. if (fs.existsSync(cmd)) {
  136. return exports.spawn(cmd, args, opts);
  137. }
  138. return Q(null);
  139. };