139 lines
2.9 KiB
JavaScript
139 lines
2.9 KiB
JavaScript
|
|
var EventEmitter = require('events').EventEmitter;
|
||
|
|
var inherits = require('util').inherits;
|
||
|
|
var spawn = require('child_process').spawn;
|
||
|
|
var path = require('path');
|
||
|
|
var Promise = require('native-or-bluebird');
|
||
|
|
var platform = require('os').platform();
|
||
|
|
|
||
|
|
function Exeq(commands) {
|
||
|
|
EventEmitter.call(this);
|
||
|
|
this.commands = commands || [];
|
||
|
|
this.cwd = '';
|
||
|
|
this.results = [];
|
||
|
|
|
||
|
|
var instance = new Promise(this.run.bind(this));
|
||
|
|
instance.q = this;
|
||
|
|
|
||
|
|
return instance;
|
||
|
|
}
|
||
|
|
|
||
|
|
inherits(Exeq, EventEmitter);
|
||
|
|
|
||
|
|
Exeq.prototype.run = function(resolve, reject) {
|
||
|
|
|
||
|
|
var that = this;
|
||
|
|
|
||
|
|
var stdout = new Buffer('');
|
||
|
|
var stderr = new Buffer('');
|
||
|
|
|
||
|
|
// done!
|
||
|
|
if (this.commands.length === 0) {
|
||
|
|
this.emit('done', this.results);
|
||
|
|
resolve(this.results);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
var cmdString = this.commands.shift();
|
||
|
|
var parsed = parseCommand(cmdString);
|
||
|
|
var s = this.proc = spawn(parsed.cmd, parsed.args, {
|
||
|
|
cwd: this.cwd
|
||
|
|
});
|
||
|
|
|
||
|
|
s.stdout.pipe(process.stdout);
|
||
|
|
s.stdout.on('data', function(data) {
|
||
|
|
that.emit('stdout', data);
|
||
|
|
stdout += data.toString();
|
||
|
|
});
|
||
|
|
|
||
|
|
s.stderr.pipe(process.stderr);
|
||
|
|
s.stderr.on('data', function(data) {
|
||
|
|
that.emit('stderr', data);
|
||
|
|
stderr += data.toString();
|
||
|
|
});
|
||
|
|
|
||
|
|
s.on('close', function(code, signal) {
|
||
|
|
var reason;
|
||
|
|
if (code) {
|
||
|
|
reason = {
|
||
|
|
code: code,
|
||
|
|
stdout: stdout.toString(),
|
||
|
|
stderr: stderr.toString()
|
||
|
|
};
|
||
|
|
|
||
|
|
that.emit('failed', reason);
|
||
|
|
return reject(reason);
|
||
|
|
}
|
||
|
|
|
||
|
|
that.results.push({
|
||
|
|
cmd: cmdString,
|
||
|
|
stdout: stdout.toString(),
|
||
|
|
stderr: stderr.toString()
|
||
|
|
});
|
||
|
|
|
||
|
|
if (that.killed) {
|
||
|
|
reason = {
|
||
|
|
code: code,
|
||
|
|
stderr: that.results.map(function(result) {
|
||
|
|
return result.stdout.toString();
|
||
|
|
}).join('') + 'Process has been killed.'
|
||
|
|
};
|
||
|
|
|
||
|
|
if (signal) {
|
||
|
|
reason.errno = signal;
|
||
|
|
}
|
||
|
|
|
||
|
|
that.emit('killed', reason);
|
||
|
|
return reject(reason);
|
||
|
|
}
|
||
|
|
|
||
|
|
// cd /path/to
|
||
|
|
// change cwd to /path/to
|
||
|
|
if (parsed.changeCwd) {
|
||
|
|
that.cwd = path.resolve(that.cwd, parsed.changeCwd);
|
||
|
|
}
|
||
|
|
that.run(resolve, reject);
|
||
|
|
});
|
||
|
|
};
|
||
|
|
|
||
|
|
Exeq.prototype.kill = function() {
|
||
|
|
if (this.proc) {
|
||
|
|
try {
|
||
|
|
this.proc.kill('SIGTERM');
|
||
|
|
this.killed = true;
|
||
|
|
} catch (e) {
|
||
|
|
if (e.errno != 'ESRCH') {
|
||
|
|
throw (e);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
module.exports = function() {
|
||
|
|
var cmds = [], args = Array.prototype.slice.call(arguments);
|
||
|
|
args.forEach(function(arg) {
|
||
|
|
if (Array.isArray(arg)) {
|
||
|
|
cmds = cmds.concat(arg);
|
||
|
|
} else {
|
||
|
|
cmds.push(arg);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
return new Exeq(cmds);
|
||
|
|
};
|
||
|
|
|
||
|
|
function parseCommand(cmd) {
|
||
|
|
cmd = cmd.trim();
|
||
|
|
var command = (platform === 'win32' ? 'cmd.exe' : 'sh');
|
||
|
|
var args = (platform === 'win32' ? ['/s', '/c'] : ['-c']);
|
||
|
|
var changeCwd;
|
||
|
|
// change cwd for "cd /path/to"
|
||
|
|
if (/^cd\s+/.test(cmd)) {
|
||
|
|
changeCwd = cmd.replace(/^cd\s+/, '');
|
||
|
|
}
|
||
|
|
return {
|
||
|
|
cmd: command,
|
||
|
|
args: args.concat([cmd]),
|
||
|
|
changeCwd: changeCwd
|
||
|
|
};
|
||
|
|
}
|