function GulpRunner(template, options) { if (!(this instanceof GulpRunner)) { return new GulpRunner(template, options); } this.command = new Command(template, options || {}); Transform.call(this, { objectMode: true }); }
n/a
function Command(command, options) { var previousPath; this.command = command; // We're on Windows if `process.platform` starts with "win", i.e. "win32". this.isWindows = (process.platform.lastIndexOf('win') === 0); // the cwd and environment of the command are the same as the main node // process by default. this.options = defaults(options || {}, { cwd: process.cwd(), env: process.env, verbosity: (options && options.silent) ? 1 : 2, usePowerShell: false }); // include node_modules/.bin on the path when we execute the command. previousPath = this.options.env.PATH; this.options.env.PATH = path.join(this.options.cwd, 'node_modules', '.bin'); this.options.env.PATH += path.delimiter; this.options.env.PATH += previousPath; }
...
.src('path/to/input/*') // get input files.
.pipe(run('awk "NR % 2 == 0"')) // use awk to extract the even lines.
.pipe(gulp.dest('path/to/output')) // profit.
;
});
// use gulp-run without gulp
var cmd = new run.Command('cat'); // create a command object for `cat`.
cmd.exec('hello world'); // call `cat` with 'hello world' on stdin.
```
## API
### `run(template, [options])`
Creates a Vinyl (gulp) stream that transforms its input by piping it to a shell command.
...
function Transform(options) { if (!(this instanceof Transform)) return new Transform(options); Duplex.call(this, options); this._transformState = new TransformState(this); var stream = this; // start out asking for a readable event once data is transformed. this._readableState.needReadable = true; // we have implemented the _read method, and done the other things // that Readable wants before the first _read call, so unset the // sync guard flag. this._readableState.sync = false; if (options) { if (typeof options.transform === 'function') this._transform = options.transform; if (typeof options.flush === 'function') this._flush = options.flush; } // When the writable side finishes, then flush out anything remaining. this.once('prefinish', function() { if (typeof this._flush === 'function') this._flush(function(er) { done(stream, er); }); else done(stream); }); }
n/a
function Command(command, options) { var previousPath; this.command = command; // We're on Windows if `process.platform` starts with "win", i.e. "win32". this.isWindows = (process.platform.lastIndexOf('win') === 0); // the cwd and environment of the command are the same as the main node // process by default. this.options = defaults(options || {}, { cwd: process.cwd(), env: process.env, verbosity: (options && options.silent) ? 1 : 2, usePowerShell: false }); // include node_modules/.bin on the path when we execute the command. previousPath = this.options.env.PATH; this.options.env.PATH = path.join(this.options.cwd, 'node_modules', '.bin'); this.options.env.PATH += path.delimiter; this.options.env.PATH += previousPath; }
...
.src('path/to/input/*') // get input files.
.pipe(run('awk "NR % 2 == 0"')) // use awk to extract the even lines.
.pipe(gulp.dest('path/to/output')) // profit.
;
});
// use gulp-run without gulp
var cmd = new run.Command('cat'); // create a command object for `cat`.
cmd.exec('hello world'); // call `cat` with 'hello world' on stdin.
```
## API
### `run(template, [options])`
Creates a Vinyl (gulp) stream that transforms its input by piping it to a shell command.
...
function exec(stdin, callback) { var self = this; var command; var fileName; var directory; var subShell; var log; var err; var stdout; // parse the arguments, both are optional. // after parsing, stdin is a vinyl file to use as standard input to // the command (possibly empty), and callback is a function. if (typeof stdin === 'function') { callback = stdin; stdin = undefined; } else if (typeof callback !== 'function') { callback = function noop() {}; } if (!(stdin instanceof Vinyl)) { fileName = this.command.split(' ')[0]; directory = path.join(this.options.cwd, fileName); if (typeof stdin === 'string') { stdin = new Vinyl({ path: directory, contents: new Buffer(stdin) }); } else if (stdin instanceof Buffer || stdin instanceof stream.Readable) { stdin = new Vinyl({ path: directory, contents: stdin }); } else { stdin = new Vinyl(stdin); if (!stdin.path) { stdin.path = directory; } } } // execute the command. // we spawn the command in a subshell, so things like i/o redirection // just work. e.g. `echo hello world >> ./hello.txt` works as expected. command = applyTemplate(this.command)({ file: stdin }); if (this.isWindows && this.options.usePowerShell) { // windows powershell subShell = cp.spawn('powershell.exe', ['-NonInteractive', '-NoLogo', '-Command', command], { env: this.options.env, cwd: this.options.cwd }); } else if (this.isWindows) { // windows cmd.exe subShell = cp.spawn('cmd.exe', ['/c', command], { env: this.options.env, cwd: this.options.cwd }); } else { // POSIX shell subShell = cp.spawn('sh', ['-c', command], { env: this.options.env, cwd: this.options.cwd }); } // setup the output // // - if verbosity equals to 3, the command prints directly to the terminal. // - if verbosity equals to 2, the command's stdout and stderr are buffered // and printed to the user's terminal after the command exits (this // prevents overlaping output of multiple commands) // - if verbosity equals to 1, the command's stderr is buffered as in 2, but // the stdout is silenced. log = new stream.PassThrough(); function sendLog(context) { var title = util.format( '$ %s%s', gutil.colors.blue(command), (self.options.verbosity < 2) ? gutil.colors.grey(' # Silenced\n') : '\n' ); context.write(title); } switch (this.options.verbosity) { case 3: sendLog(process.stdout); subShell.stdout.pipe(process.stdout); subShell.stderr.pipe(process.stderr); break; case 2: subShell.stdout.pipe(log); // fallthrough case 1: subShell.stderr.pipe(log); sendLog(log); break; } // setup the cleanup proceedure for when the command finishes. subShell.once('close', function handleSubShellClose() { // write the buffered output to stdout var content = log.read(); if (content !== null) { process.stdout.write(content); } }); subShell.once('exit', function handleSubShellExit(code) { // report an error if the command exited with a non-zero exit code. if (code !== 0) { err = new Error(util.format('Command `%s` exited with code %s', command, code)); err.status = code; return callback(err); } callback(null); }); // the file wrapping stdout is as the one wrapping stdin (same metadata) // with different contents. stdout = stdin.clone(); stdout.contents = subShell.stdout.pipe(new stream.PassThrough()); // finally, write the input to the process's stdin. stdin.pipe(subShell.stdin); return stdout; }
...
/**
* @param {string} file
* @param {string} encoding
* @param {function} callback
* @return {void}
*/
GulpRunner.prototype._transform = function _transform(file, encoding, callback) {
var newfile = this.command.exec(file, callback);
this.push(newfile);
};
/**
* Writes `stdin` to itself and returns itself.
*
* Whenever an object is written into the GulpRunner, a new process is
...
function toString() { return this.command; }
...
* @param {string|RegExp} match
* @return {Stream}
*/
module.exports.compare = function compare(match) {
var stream;
if (!(match instanceof RegExp)) {
match = new RegExp('^' + match.toString() + '$');
}
stream = new Stream.Transform({
objectMode: true
});
stream._transform = function _transform(file, encoding, callback) {
...