in node/toolrunner.ts [883:988]
public exec(options?: IExecOptions): Q.Promise<number> {
if (this.pipeOutputToTool) {
return this.execWithPiping(this.pipeOutputToTool, options);
}
var defer = Q.defer<number>();
this._debug('exec tool: ' + this.toolPath);
this._debug('arguments:');
this.args.forEach((arg) => {
this._debug(' ' + arg);
});
const optionsNonNull = this._cloneExecOptions(options);
if (!optionsNonNull.silent) {
optionsNonNull.outStream!.write(this._getCommandString(optionsNonNull) + os.EOL);
}
let state = new ExecState(optionsNonNull, this.toolPath);
state.on('debug', (message: string) => {
this._debug(message);
});
let cp = child.spawn(this._getSpawnFileName(options), this._getSpawnArgs(optionsNonNull), this._getSpawnOptions(options));
this.childProcess = cp;
// it is possible for the child process to end its last line without a new line.
// because stdout is buffered, this causes the last line to not get sent to the parent
// stream. Adding this event forces a flush before the child streams are closed.
cp.stdout?.on('finish', () => {
if (!optionsNonNull.silent) {
optionsNonNull.outStream!.write(os.EOL);
}
});
var stdbuffer: string = '';
cp.stdout?.on('data', (data: Buffer) => {
this.emit('stdout', data);
if (!optionsNonNull.silent) {
optionsNonNull.outStream!.write(data);
}
this._processLineBuffer(data, stdbuffer, (line: string) => {
this.emit('stdline', line);
});
});
var errbuffer: string = '';
cp.stderr?.on('data', (data: Buffer) => {
state.processStderr = true;
this.emit('stderr', data);
if (!optionsNonNull.silent) {
var s = optionsNonNull.failOnStdErr ? optionsNonNull.errStream! : optionsNonNull.outStream!;
s.write(data);
}
this._processLineBuffer(data, errbuffer, (line: string) => {
this.emit('errline', line);
});
});
cp.on('error', (err: Error) => {
state.processError = err.message;
state.processExited = true;
state.processClosed = true;
state.CheckComplete();
});
cp.on('exit', (code: number, signal: any) => {
state.processExitCode = code;
state.processExited = true;
this._debug(`Exit code ${code} received from tool '${this.toolPath}'`);
state.CheckComplete()
});
cp.on('close', (code: number, signal: any) => {
state.processExitCode = code;
state.processExited = true;
state.processClosed = true;
this._debug(`STDIO streams have closed for tool '${this.toolPath}'`)
state.CheckComplete();
});
state.on('done', (error: Error, exitCode: number) => {
if (stdbuffer.length > 0) {
this.emit('stdline', stdbuffer);
}
if (errbuffer.length > 0) {
this.emit('errline', errbuffer);
}
cp.removeAllListeners();
if (error) {
defer.reject(error);
}
else {
defer.resolve(exitCode);
}
});
return defer.promise;
}