| 3 | |
| 4 | |
| 5 | function exec2(file, args /*, options, callback */) { |
| 6 | var options = { encoding: 'utf8' |
| 7 | , timeout: 0 |
| 8 | , maxBuffer: 500*1024 |
| 9 | , killSignal: 'SIGKILL' |
| 10 | , output: null |
| 11 | }; |
| 12 | |
| 13 | var callback = arguments[arguments.length-1]; |
| 14 | if ('function' != typeof callback) callback = null; |
| 15 | |
| 16 | if (typeof arguments[2] == 'object') { |
| 17 | var keys = Object.keys(options); |
| 18 | for (var i = 0; i < keys.length; i++) { |
| 19 | var k = keys[i]; |
| 20 | if (arguments[2][k] !== undefined) options[k] = arguments[2][k]; |
| 21 | } |
| 22 | } |
| 23 | |
| 24 | var child = childproc.spawn(file, args); |
| 25 | var killed = false; |
| 26 | var timedOut = false; |
| 27 | |
| 28 | var Wrapper = function(proc) { |
| 29 | this.proc = proc; |
| 30 | this.stderr = new Accumulator(); |
| 31 | proc.emitter = new EventEmitter(); |
| 32 | proc.on = proc.emitter.on.bind(proc.emitter); |
| 33 | this.out = proc.emitter.emit.bind(proc.emitter, 'data'); |
| 34 | this.err = this.stderr.out.bind(this.stderr); |
| 35 | this.errCurrent = this.stderr.current.bind(this.stderr); |
| 36 | }; |
| 37 | Wrapper.prototype.finish = function(err) { |
| 38 | this.proc.emitter.emit('end', err, this.errCurrent()); |
| 39 | }; |
| 40 | |
| 41 | var Accumulator = function(cb) { |
| 42 | this.stdout = {contents: ""}; |
| 43 | this.stderr = {contents: ""}; |
| 44 | this.callback = cb; |
| 45 | |
| 46 | var limitedWrite = function(stream) { |
| 47 | return function(chunk) { |
| 48 | stream.contents += chunk; |
| 49 | if (!killed && stream.contents.length > options.maxBuffer) { |
| 50 | child.kill(options.killSignal); |
| 51 | killed = true; |
| 52 | } |
| 53 | }; |
| 54 | }; |
| 55 | this.out = limitedWrite(this.stdout); |
| 56 | this.err = limitedWrite(this.stderr); |
| 57 | }; |
| 58 | Accumulator.prototype.current = function() { return this.stdout.contents; }; |
| 59 | Accumulator.prototype.errCurrent = function() { return this.stderr.contents; }; |
| 60 | Accumulator.prototype.finish = function(err) { this.callback(err, this.stdout.contents, this.stderr.contents); }; |
| 61 | |
| 62 | var std = callback ? new Accumulator(callback) : new Wrapper(child); |