azure-pipelines-task-lib 5.0.1-preview.0 → 5.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/toolrunner.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  /// <reference types="node" />
2
+ /// <reference types="node" />
3
+ /// <reference types="node" />
2
4
  import Q = require('q');
3
5
  import events = require('events');
4
6
  /**
@@ -94,6 +96,7 @@ export declare class ToolRunner extends events.EventEmitter {
94
96
  private _cloneExecOptions;
95
97
  private _getSpawnOptions;
96
98
  private _getSpawnSyncOptions;
99
+ private execWithPipingAsync;
97
100
  private execWithPiping;
98
101
  /**
99
102
  * Add argument
@@ -139,6 +142,17 @@ export declare class ToolRunner extends events.EventEmitter {
139
142
  * @param options optional exec options. See IExecOptions
140
143
  * @returns number
141
144
  */
145
+ execAsync(options?: IExecOptions): Promise<number>;
146
+ /**
147
+ * Exec a tool.
148
+ * Output will be streamed to the live console.
149
+ * Returns promise with return code
150
+ *
151
+ * @deprecated Use the `execAsync` method that returns a native Javascript promise instead
152
+ * @param tool path to tool to exec
153
+ * @param options optional exec options. See IExecOptions
154
+ * @returns number
155
+ */
142
156
  exec(options?: IExecOptions): Q.Promise<number>;
143
157
  /**
144
158
  * Exec a tool synchronously.
@@ -155,5 +169,5 @@ export declare class ToolRunner extends events.EventEmitter {
155
169
  * Used to close child process by sending SIGNINT signal.
156
170
  * It allows executed script to have some additional logic on SIGINT, before exiting.
157
171
  */
158
- killChildProcess(): void;
172
+ killChildProcess(signal?: number | NodeJS.Signals): void;
159
173
  }
package/toolrunner.js CHANGED
@@ -7,6 +7,8 @@ var __extends = (this && this.__extends) || (function () {
7
7
  return extendStatics(d, b);
8
8
  };
9
9
  return function (d, b) {
10
+ if (typeof b !== "function" && b !== null)
11
+ throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
10
12
  extendStatics(d, b);
11
13
  function __() { this.constructor = d; }
12
14
  d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
@@ -107,7 +109,7 @@ var ToolRunner = /** @class */ (function (_super) {
107
109
  }
108
110
  // Windows + verbatim
109
111
  else if (options.windowsVerbatimArguments) {
110
- commandParts.push("\"" + toolPath + "\"");
112
+ commandParts.push("\"".concat(toolPath, "\""));
111
113
  commandParts = commandParts.concat(args);
112
114
  }
113
115
  else if (options.shell) {
@@ -134,23 +136,23 @@ var ToolRunner = /** @class */ (function (_super) {
134
136
  }
135
137
  return cmd;
136
138
  };
137
- ToolRunner.prototype._processLineBuffer = function (data, strBuffer, onLine) {
139
+ ToolRunner.prototype._processLineBuffer = function (data, buffer, onLine) {
140
+ var newBuffer = buffer + data.toString();
138
141
  try {
139
- var s = strBuffer + data.toString();
140
- var n = s.indexOf(os.EOL);
141
- while (n > -1) {
142
- var line = s.substring(0, n);
142
+ var eolIndex = newBuffer.indexOf(os.EOL);
143
+ while (eolIndex > -1) {
144
+ var line = newBuffer.substring(0, eolIndex);
143
145
  onLine(line);
144
146
  // the rest of the string ...
145
- s = s.substring(n + os.EOL.length);
146
- n = s.indexOf(os.EOL);
147
+ newBuffer = newBuffer.substring(eolIndex + os.EOL.length);
148
+ eolIndex = newBuffer.indexOf(os.EOL);
147
149
  }
148
- strBuffer = s;
149
150
  }
150
151
  catch (err) {
151
152
  // streaming lines to console is best effort. Don't fail a build.
152
153
  this._debug('error processing line');
153
154
  }
155
+ return newBuffer;
154
156
  };
155
157
  /**
156
158
  * Wraps an arg string with specified char if it's not already wrapped
@@ -160,7 +162,7 @@ var ToolRunner = /** @class */ (function (_super) {
160
162
  */
161
163
  ToolRunner.prototype._wrapArg = function (arg, wrapChar) {
162
164
  if (!this._isWrapped(arg, wrapChar)) {
163
- return "" + wrapChar + arg + wrapChar;
165
+ return "".concat(wrapChar).concat(arg).concat(wrapChar);
164
166
  }
165
167
  return arg;
166
168
  };
@@ -171,7 +173,7 @@ var ToolRunner = /** @class */ (function (_super) {
171
173
  */
172
174
  ToolRunner.prototype._unwrapArg = function (arg, wrapChar) {
173
175
  if (this._isWrapped(arg, wrapChar)) {
174
- var pattern = new RegExp("(^\\\\?" + wrapChar + ")|(\\\\?" + wrapChar + "$)", 'g');
176
+ var pattern = new RegExp("(^\\\\?".concat(wrapChar, ")|(\\\\?").concat(wrapChar, "$)"), 'g');
175
177
  return arg.trim().replace(pattern, '');
176
178
  }
177
179
  return arg;
@@ -181,7 +183,7 @@ var ToolRunner = /** @class */ (function (_super) {
181
183
  * @param arg Input arg string
182
184
  */
183
185
  ToolRunner.prototype._isWrapped = function (arg, wrapChar) {
184
- var pattern = new RegExp("^\\\\?" + wrapChar + ".+\\\\?" + wrapChar + "$");
186
+ var pattern = new RegExp("^\\\\?".concat(wrapChar, ".+\\\\?").concat(wrapChar, "$"));
185
187
  return pattern.test(arg.trim());
186
188
  };
187
189
  ToolRunner.prototype._getSpawnFileName = function (options) {
@@ -199,7 +201,7 @@ var ToolRunner = /** @class */ (function (_super) {
199
201
  var _this = this;
200
202
  if (process.platform == 'win32') {
201
203
  if (this._isCmdFile()) {
202
- var argline = "/D /S /C \"" + this._windowsQuoteCmdArg(this.toolPath);
204
+ var argline = "/D /S /C \"".concat(this._windowsQuoteCmdArg(this.toolPath));
203
205
  for (var i = 0; i < this.args.length; i++) {
204
206
  argline += ' ';
205
207
  argline += options.windowsVerbatimArguments ? this.args[i] : this._windowsQuoteCmdArg(this.args[i]);
@@ -243,7 +245,7 @@ var ToolRunner = /** @class */ (function (_super) {
243
245
  if (arguments.length != 1) {
244
246
  throw new Error('Unexpected arguments passed to args.unshift when windowsVerbatimArguments flag is set.');
245
247
  }
246
- return Array.prototype.unshift.call(args_1, "\"" + arguments[0] + "\""); // quote the file name
248
+ return Array.prototype.unshift.call(args_1, "\"".concat(arguments[0], "\"")); // quote the file name
247
249
  };
248
250
  return args_1;
249
251
  }
@@ -447,7 +449,7 @@ var ToolRunner = /** @class */ (function (_super) {
447
449
  if (arg.indexOf('"') < 0 && arg.indexOf('\\') < 0) {
448
450
  // No embedded double quotes or backslashes, so I can just wrap
449
451
  // quote marks around the whole thing.
450
- return "\"" + arg + "\"";
452
+ return "\"".concat(arg, "\"");
451
453
  }
452
454
  // Expected input/output:
453
455
  // input : hello"world
@@ -516,6 +518,186 @@ var ToolRunner = /** @class */ (function (_super) {
516
518
  result['windowsVerbatimArguments'] = options.windowsVerbatimArguments || this._isCmdFile();
517
519
  return result;
518
520
  };
521
+ ToolRunner.prototype.execWithPipingAsync = function (pipeOutputToTool, options) {
522
+ var _this = this;
523
+ this._debug('exec tool: ' + this.toolPath);
524
+ this._debug('arguments:');
525
+ this.args.forEach(function (arg) {
526
+ _this._debug(' ' + arg);
527
+ });
528
+ var success = true;
529
+ var optionsNonNull = this._cloneExecOptions(options);
530
+ if (!optionsNonNull.silent) {
531
+ optionsNonNull.outStream.write(this._getCommandString(optionsNonNull) + os.EOL);
532
+ }
533
+ var cp;
534
+ var toolPath = pipeOutputToTool.toolPath;
535
+ var toolPathFirst;
536
+ var successFirst = true;
537
+ var returnCodeFirst;
538
+ var fileStream;
539
+ var waitingEvents = 0; // number of process or stream events we are waiting on to complete
540
+ var returnCode = 0;
541
+ var error;
542
+ toolPathFirst = this.toolPath;
543
+ // Following node documentation example from this link on how to pipe output of one process to another
544
+ // https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options
545
+ //start the child process for both tools
546
+ waitingEvents++;
547
+ var cpFirst = child.spawn(this._getSpawnFileName(optionsNonNull), this._getSpawnArgs(optionsNonNull), this._getSpawnOptions(optionsNonNull));
548
+ waitingEvents++;
549
+ cp = child.spawn(pipeOutputToTool._getSpawnFileName(optionsNonNull), pipeOutputToTool._getSpawnArgs(optionsNonNull), pipeOutputToTool._getSpawnOptions(optionsNonNull));
550
+ fileStream = this.pipeOutputToFile ? fs.createWriteStream(this.pipeOutputToFile) : null;
551
+ return new Promise(function (resolve, reject) {
552
+ var _a, _b, _c, _d;
553
+ if (fileStream) {
554
+ waitingEvents++;
555
+ fileStream.on('finish', function () {
556
+ waitingEvents--; //file write is complete
557
+ fileStream = null;
558
+ if (waitingEvents == 0) {
559
+ if (error) {
560
+ reject(error);
561
+ }
562
+ else {
563
+ resolve(returnCode);
564
+ }
565
+ }
566
+ });
567
+ fileStream.on('error', function (err) {
568
+ waitingEvents--; //there were errors writing to the file, write is done
569
+ _this._debug("Failed to pipe output of ".concat(toolPathFirst, " to file ").concat(_this.pipeOutputToFile, ". Error = ").concat(err));
570
+ fileStream = null;
571
+ if (waitingEvents == 0) {
572
+ if (error) {
573
+ reject(error);
574
+ }
575
+ else {
576
+ resolve(returnCode);
577
+ }
578
+ }
579
+ });
580
+ }
581
+ //pipe stdout of first tool to stdin of second tool
582
+ (_a = cpFirst.stdout) === null || _a === void 0 ? void 0 : _a.on('data', function (data) {
583
+ var _a, _b;
584
+ try {
585
+ if (fileStream) {
586
+ fileStream.write(data);
587
+ }
588
+ if (!((_a = cp.stdin) === null || _a === void 0 ? void 0 : _a.destroyed)) {
589
+ (_b = cp.stdin) === null || _b === void 0 ? void 0 : _b.write(data);
590
+ }
591
+ }
592
+ catch (err) {
593
+ _this._debug('Failed to pipe output of ' + toolPathFirst + ' to ' + toolPath);
594
+ _this._debug(toolPath + ' might have exited due to errors prematurely. Verify the arguments passed are valid.');
595
+ }
596
+ });
597
+ (_b = cpFirst.stderr) === null || _b === void 0 ? void 0 : _b.on('data', function (data) {
598
+ if (fileStream) {
599
+ fileStream.write(data);
600
+ }
601
+ successFirst = !optionsNonNull.failOnStdErr;
602
+ if (!optionsNonNull.silent) {
603
+ var s = optionsNonNull.failOnStdErr ? optionsNonNull.errStream : optionsNonNull.outStream;
604
+ s.write(data);
605
+ }
606
+ });
607
+ cpFirst.on('error', function (err) {
608
+ var _a;
609
+ waitingEvents--; //first process is complete with errors
610
+ if (fileStream) {
611
+ fileStream.end();
612
+ }
613
+ (_a = cp.stdin) === null || _a === void 0 ? void 0 : _a.end();
614
+ error = new Error(toolPathFirst + ' failed. ' + err.message);
615
+ if (waitingEvents == 0) {
616
+ reject(error);
617
+ }
618
+ });
619
+ cpFirst.on('close', function (code, signal) {
620
+ var _a;
621
+ waitingEvents--; //first process is complete
622
+ if (code != 0 && !optionsNonNull.ignoreReturnCode) {
623
+ successFirst = false;
624
+ returnCodeFirst = code;
625
+ returnCode = returnCodeFirst;
626
+ }
627
+ _this._debug('success of first tool:' + successFirst);
628
+ if (fileStream) {
629
+ fileStream.end();
630
+ }
631
+ (_a = cp.stdin) === null || _a === void 0 ? void 0 : _a.end();
632
+ if (waitingEvents == 0) {
633
+ if (error) {
634
+ reject(error);
635
+ }
636
+ else {
637
+ resolve(returnCode);
638
+ }
639
+ }
640
+ });
641
+ var stdLineBuffer = '';
642
+ (_c = cp.stdout) === null || _c === void 0 ? void 0 : _c.on('data', function (data) {
643
+ _this.emit('stdout', data);
644
+ if (!optionsNonNull.silent) {
645
+ optionsNonNull.outStream.write(data);
646
+ }
647
+ stdLineBuffer = _this._processLineBuffer(data, stdLineBuffer, function (line) {
648
+ _this.emit('stdline', line);
649
+ });
650
+ });
651
+ var errLineBuffer = '';
652
+ (_d = cp.stderr) === null || _d === void 0 ? void 0 : _d.on('data', function (data) {
653
+ _this.emit('stderr', data);
654
+ success = !optionsNonNull.failOnStdErr;
655
+ if (!optionsNonNull.silent) {
656
+ var s = optionsNonNull.failOnStdErr ? optionsNonNull.errStream : optionsNonNull.outStream;
657
+ s.write(data);
658
+ }
659
+ errLineBuffer = _this._processLineBuffer(data, errLineBuffer, function (line) {
660
+ _this.emit('errline', line);
661
+ });
662
+ });
663
+ cp.on('error', function (err) {
664
+ waitingEvents--; //process is done with errors
665
+ error = new Error(toolPath + ' failed. ' + err.message);
666
+ if (waitingEvents == 0) {
667
+ reject(error);
668
+ }
669
+ });
670
+ cp.on('close', function (code, signal) {
671
+ waitingEvents--; //process is complete
672
+ _this._debug('rc:' + code);
673
+ returnCode = code;
674
+ if (stdLineBuffer.length > 0) {
675
+ _this.emit('stdline', stdLineBuffer);
676
+ }
677
+ if (errLineBuffer.length > 0) {
678
+ _this.emit('errline', errLineBuffer);
679
+ }
680
+ if (code != 0 && !optionsNonNull.ignoreReturnCode) {
681
+ success = false;
682
+ }
683
+ _this._debug('success:' + success);
684
+ if (!successFirst) { //in the case output is piped to another tool, check exit code of both tools
685
+ error = new Error(toolPathFirst + ' failed with return code: ' + returnCodeFirst);
686
+ }
687
+ else if (!success) {
688
+ error = new Error(toolPath + ' failed with return code: ' + code);
689
+ }
690
+ if (waitingEvents == 0) {
691
+ if (error) {
692
+ reject(error);
693
+ }
694
+ else {
695
+ resolve(returnCode);
696
+ }
697
+ }
698
+ });
699
+ });
700
+ };
519
701
  ToolRunner.prototype.execWithPiping = function (pipeOutputToTool, options) {
520
702
  var _this = this;
521
703
  var _a, _b, _c, _d;
@@ -564,7 +746,7 @@ var ToolRunner = /** @class */ (function (_super) {
564
746
  });
565
747
  fileStream.on('error', function (err) {
566
748
  waitingEvents--; //there were errors writing to the file, write is done
567
- _this._debug("Failed to pipe output of " + toolPathFirst + " to file " + _this.pipeOutputToFile + ". Error = " + err);
749
+ _this._debug("Failed to pipe output of ".concat(toolPathFirst, " to file ").concat(_this.pipeOutputToFile, ". Error = ").concat(err));
568
750
  fileStream = null;
569
751
  if (waitingEvents == 0) {
570
752
  if (error) {
@@ -634,17 +816,17 @@ var ToolRunner = /** @class */ (function (_super) {
634
816
  }
635
817
  }
636
818
  });
637
- var stdbuffer = '';
819
+ var stdLineBuffer = '';
638
820
  (_c = cp.stdout) === null || _c === void 0 ? void 0 : _c.on('data', function (data) {
639
821
  _this.emit('stdout', data);
640
822
  if (!optionsNonNull.silent) {
641
823
  optionsNonNull.outStream.write(data);
642
824
  }
643
- _this._processLineBuffer(data, stdbuffer, function (line) {
825
+ stdLineBuffer = _this._processLineBuffer(data, stdLineBuffer, function (line) {
644
826
  _this.emit('stdline', line);
645
827
  });
646
828
  });
647
- var errbuffer = '';
829
+ var errLineBuffer = '';
648
830
  (_d = cp.stderr) === null || _d === void 0 ? void 0 : _d.on('data', function (data) {
649
831
  _this.emit('stderr', data);
650
832
  success = !optionsNonNull.failOnStdErr;
@@ -652,7 +834,7 @@ var ToolRunner = /** @class */ (function (_super) {
652
834
  var s = optionsNonNull.failOnStdErr ? optionsNonNull.errStream : optionsNonNull.outStream;
653
835
  s.write(data);
654
836
  }
655
- _this._processLineBuffer(data, errbuffer, function (line) {
837
+ errLineBuffer = _this._processLineBuffer(data, errLineBuffer, function (line) {
656
838
  _this.emit('errline', line);
657
839
  });
658
840
  });
@@ -667,11 +849,11 @@ var ToolRunner = /** @class */ (function (_super) {
667
849
  waitingEvents--; //process is complete
668
850
  _this._debug('rc:' + code);
669
851
  returnCode = code;
670
- if (stdbuffer.length > 0) {
671
- _this.emit('stdline', stdbuffer);
852
+ if (stdLineBuffer.length > 0) {
853
+ _this.emit('stdline', stdLineBuffer);
672
854
  }
673
- if (errbuffer.length > 0) {
674
- _this.emit('errline', errbuffer);
855
+ if (errLineBuffer.length > 0) {
856
+ _this.emit('errline', errLineBuffer);
675
857
  }
676
858
  if (code != 0 && !optionsNonNull.ignoreReturnCode) {
677
859
  success = false;
@@ -767,13 +949,12 @@ var ToolRunner = /** @class */ (function (_super) {
767
949
  * @param options optional exec options. See IExecOptions
768
950
  * @returns number
769
951
  */
770
- ToolRunner.prototype.exec = function (options) {
952
+ ToolRunner.prototype.execAsync = function (options) {
771
953
  var _this = this;
772
954
  var _a, _b, _c;
773
955
  if (this.pipeOutputToTool) {
774
- return this.execWithPiping(this.pipeOutputToTool, options);
956
+ return this.execWithPipingAsync(this.pipeOutputToTool, options);
775
957
  }
776
- var defer = Q.defer();
777
958
  this._debug('exec tool: ' + this.toolPath);
778
959
  this._debug('arguments:');
779
960
  this.args.forEach(function (arg) {
@@ -787,7 +968,41 @@ var ToolRunner = /** @class */ (function (_super) {
787
968
  state.on('debug', function (message) {
788
969
  _this._debug(message);
789
970
  });
790
- var cp = child.spawn(this._getSpawnFileName(options), this._getSpawnArgs(optionsNonNull), this._getSpawnOptions(options));
971
+ var stdLineBuffer = '';
972
+ var errLineBuffer = '';
973
+ var emitDoneEvent = function (resolve, reject) {
974
+ state.on('done', function (error, exitCode) {
975
+ if (stdLineBuffer.length > 0) {
976
+ _this.emit('stdline', stdLineBuffer);
977
+ }
978
+ if (errLineBuffer.length > 0) {
979
+ _this.emit('errline', errLineBuffer);
980
+ }
981
+ if (cp) {
982
+ cp.removeAllListeners();
983
+ }
984
+ if (error) {
985
+ reject(error);
986
+ }
987
+ else {
988
+ resolve(exitCode);
989
+ }
990
+ });
991
+ };
992
+ // Edge case when the node itself cant's spawn and emit event
993
+ var cp;
994
+ try {
995
+ cp = child.spawn(this._getSpawnFileName(options), this._getSpawnArgs(optionsNonNull), this._getSpawnOptions(options));
996
+ }
997
+ catch (error) {
998
+ return new Promise(function (resolve, reject) {
999
+ emitDoneEvent(resolve, reject);
1000
+ state.processError = error.message;
1001
+ state.processExited = true;
1002
+ state.processClosed = true;
1003
+ state.CheckComplete();
1004
+ });
1005
+ }
791
1006
  this.childProcess = cp;
792
1007
  // it is possible for the child process to end its last line without a new line.
793
1008
  // because stdout is buffered, this causes the last line to not get sent to the parent
@@ -797,17 +1012,15 @@ var ToolRunner = /** @class */ (function (_super) {
797
1012
  optionsNonNull.outStream.write(os.EOL);
798
1013
  }
799
1014
  });
800
- var stdbuffer = '';
801
1015
  (_b = cp.stdout) === null || _b === void 0 ? void 0 : _b.on('data', function (data) {
802
1016
  _this.emit('stdout', data);
803
1017
  if (!optionsNonNull.silent) {
804
1018
  optionsNonNull.outStream.write(data);
805
1019
  }
806
- _this._processLineBuffer(data, stdbuffer, function (line) {
1020
+ stdLineBuffer = _this._processLineBuffer(data, stdLineBuffer, function (line) {
807
1021
  _this.emit('stdline', line);
808
1022
  });
809
1023
  });
810
- var errbuffer = '';
811
1024
  (_c = cp.stderr) === null || _c === void 0 ? void 0 : _c.on('data', function (data) {
812
1025
  state.processStderr = true;
813
1026
  _this.emit('stderr', data);
@@ -815,7 +1028,7 @@ var ToolRunner = /** @class */ (function (_super) {
815
1028
  var s = optionsNonNull.failOnStdErr ? optionsNonNull.errStream : optionsNonNull.outStream;
816
1029
  s.write(data);
817
1030
  }
818
- _this._processLineBuffer(data, errbuffer, function (line) {
1031
+ errLineBuffer = _this._processLineBuffer(data, errLineBuffer, function (line) {
819
1032
  _this.emit('errline', line);
820
1033
  });
821
1034
  });
@@ -825,27 +1038,64 @@ var ToolRunner = /** @class */ (function (_super) {
825
1038
  state.processClosed = true;
826
1039
  state.CheckComplete();
827
1040
  });
1041
+ // Do not write debug logs here. Sometimes stdio not closed yet and you can damage user output commands.
828
1042
  cp.on('exit', function (code, signal) {
829
1043
  state.processExitCode = code;
1044
+ state.processExitSignal = signal;
830
1045
  state.processExited = true;
831
- _this._debug("Exit code " + code + " received from tool '" + _this.toolPath + "'");
832
1046
  state.CheckComplete();
833
1047
  });
834
1048
  cp.on('close', function (code, signal) {
835
- state.processExitCode = code;
836
- state.processExited = true;
1049
+ state.processCloseCode = code;
1050
+ state.processCloseSignal = signal;
837
1051
  state.processClosed = true;
838
- _this._debug("STDIO streams have closed for tool '" + _this.toolPath + "'");
1052
+ state.processExited = true;
839
1053
  state.CheckComplete();
840
1054
  });
1055
+ return new Promise(emitDoneEvent);
1056
+ };
1057
+ /**
1058
+ * Exec a tool.
1059
+ * Output will be streamed to the live console.
1060
+ * Returns promise with return code
1061
+ *
1062
+ * @deprecated Use the `execAsync` method that returns a native Javascript promise instead
1063
+ * @param tool path to tool to exec
1064
+ * @param options optional exec options. See IExecOptions
1065
+ * @returns number
1066
+ */
1067
+ ToolRunner.prototype.exec = function (options) {
1068
+ var _this = this;
1069
+ var _a, _b, _c;
1070
+ if (this.pipeOutputToTool) {
1071
+ return this.execWithPiping(this.pipeOutputToTool, options);
1072
+ }
1073
+ var defer = Q.defer();
1074
+ this._debug('exec tool: ' + this.toolPath);
1075
+ this._debug('arguments:');
1076
+ this.args.forEach(function (arg) {
1077
+ _this._debug(' ' + arg);
1078
+ });
1079
+ var optionsNonNull = this._cloneExecOptions(options);
1080
+ if (!optionsNonNull.silent) {
1081
+ optionsNonNull.outStream.write(this._getCommandString(optionsNonNull) + os.EOL);
1082
+ }
1083
+ var state = new ExecState(optionsNonNull, this.toolPath);
1084
+ state.on('debug', function (message) {
1085
+ _this._debug(message);
1086
+ });
1087
+ var stdLineBuffer = '';
1088
+ var errLineBuffer = '';
841
1089
  state.on('done', function (error, exitCode) {
842
- if (stdbuffer.length > 0) {
843
- _this.emit('stdline', stdbuffer);
1090
+ if (stdLineBuffer.length > 0) {
1091
+ _this.emit('stdline', stdLineBuffer);
844
1092
  }
845
- if (errbuffer.length > 0) {
846
- _this.emit('errline', errbuffer);
1093
+ if (errLineBuffer.length > 0) {
1094
+ _this.emit('errline', errLineBuffer);
1095
+ }
1096
+ if (cp) {
1097
+ cp.removeAllListeners();
847
1098
  }
848
- cp.removeAllListeners();
849
1099
  if (error) {
850
1100
  defer.reject(error);
851
1101
  }
@@ -853,6 +1103,67 @@ var ToolRunner = /** @class */ (function (_super) {
853
1103
  defer.resolve(exitCode);
854
1104
  }
855
1105
  });
1106
+ // Edge case when the node itself cant's spawn and emit event
1107
+ var cp;
1108
+ try {
1109
+ cp = child.spawn(this._getSpawnFileName(options), this._getSpawnArgs(optionsNonNull), this._getSpawnOptions(options));
1110
+ }
1111
+ catch (error) {
1112
+ state.processError = error.message;
1113
+ state.processExited = true;
1114
+ state.processClosed = true;
1115
+ state.CheckComplete();
1116
+ return defer.promise;
1117
+ }
1118
+ this.childProcess = cp;
1119
+ // it is possible for the child process to end its last line without a new line.
1120
+ // because stdout is buffered, this causes the last line to not get sent to the parent
1121
+ // stream. Adding this event forces a flush before the child streams are closed.
1122
+ (_a = cp.stdout) === null || _a === void 0 ? void 0 : _a.on('finish', function () {
1123
+ if (!optionsNonNull.silent) {
1124
+ optionsNonNull.outStream.write(os.EOL);
1125
+ }
1126
+ });
1127
+ (_b = cp.stdout) === null || _b === void 0 ? void 0 : _b.on('data', function (data) {
1128
+ _this.emit('stdout', data);
1129
+ if (!optionsNonNull.silent) {
1130
+ optionsNonNull.outStream.write(data);
1131
+ }
1132
+ stdLineBuffer = _this._processLineBuffer(data, stdLineBuffer, function (line) {
1133
+ _this.emit('stdline', line);
1134
+ });
1135
+ });
1136
+ (_c = cp.stderr) === null || _c === void 0 ? void 0 : _c.on('data', function (data) {
1137
+ state.processStderr = true;
1138
+ _this.emit('stderr', data);
1139
+ if (!optionsNonNull.silent) {
1140
+ var s = optionsNonNull.failOnStdErr ? optionsNonNull.errStream : optionsNonNull.outStream;
1141
+ s.write(data);
1142
+ }
1143
+ errLineBuffer = _this._processLineBuffer(data, errLineBuffer, function (line) {
1144
+ _this.emit('errline', line);
1145
+ });
1146
+ });
1147
+ cp.on('error', function (err) {
1148
+ state.processError = err.message;
1149
+ state.processExited = true;
1150
+ state.processClosed = true;
1151
+ state.CheckComplete();
1152
+ });
1153
+ // Do not write debug logs here. Sometimes stdio not closed yet and you can damage user output commands.
1154
+ cp.on('exit', function (code, signal) {
1155
+ state.processExitCode = code;
1156
+ state.processExitSignal = signal;
1157
+ state.processExited = true;
1158
+ state.CheckComplete();
1159
+ });
1160
+ cp.on('close', function (code, signal) {
1161
+ state.processCloseCode = code;
1162
+ state.processCloseSignal = signal;
1163
+ state.processClosed = true;
1164
+ state.processExited = true;
1165
+ state.CheckComplete();
1166
+ });
856
1167
  return defer.promise;
857
1168
  };
858
1169
  /**
@@ -893,9 +1204,11 @@ var ToolRunner = /** @class */ (function (_super) {
893
1204
  * Used to close child process by sending SIGNINT signal.
894
1205
  * It allows executed script to have some additional logic on SIGINT, before exiting.
895
1206
  */
896
- ToolRunner.prototype.killChildProcess = function () {
1207
+ ToolRunner.prototype.killChildProcess = function (signal) {
1208
+ if (signal === void 0) { signal = "SIGTERM"; }
897
1209
  if (this.childProcess) {
898
- this.childProcess.kill();
1210
+ this._debug("[killChildProcess] Signal ".concat(signal, " received"));
1211
+ this.childProcess.kill(signal);
899
1212
  }
900
1213
  };
901
1214
  return ToolRunner;
@@ -936,6 +1249,7 @@ var ExecState = /** @class */ (function (_super) {
936
1249
  // determine whether there is an error
937
1250
  var error;
938
1251
  if (this.processExited) {
1252
+ this._debug("Process exited with code ".concat(this.processExitCode, " and signal ").concat(this.processExitSignal, " for tool '").concat(this.toolPath, "'"));
939
1253
  if (this.processError) {
940
1254
  error = new Error(im._loc('LIB_ProcessError', this.toolPath, this.processError));
941
1255
  }
@@ -946,6 +1260,9 @@ var ExecState = /** @class */ (function (_super) {
946
1260
  error = new Error(im._loc('LIB_ProcessStderr', this.toolPath));
947
1261
  }
948
1262
  }
1263
+ if (this.processClosed) {
1264
+ this._debug("STDIO streams have closed and received exit code ".concat(this.processCloseCode, " and signal ").concat(this.processCloseSignal, " for tool '").concat(this.toolPath, "'"));
1265
+ }
949
1266
  // clear the timeout
950
1267
  if (this.timeout) {
951
1268
  clearTimeout(this.timeout);