1 | 'use strict';
|
2 |
|
3 | var childProcess = require('child_process');
|
4 | var pathlib = require('path');
|
5 | var stream = require('stream');
|
6 | var util = require('util');
|
7 |
|
8 | var _ = require('lodash');
|
9 | var Vinyl = require('vinyl');
|
10 | var gutil = require('gulp-util');
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 | module.exports = function Command(commandTemplate, opts) {
|
18 |
|
19 |
|
20 | var isWindows = (process.platform.lastIndexOf('win') === 0);
|
21 |
|
22 |
|
23 | opts = _.defaults(opts||{}, {
|
24 | cwd: process.cwd(),
|
25 | env: process.env,
|
26 | silent: false,
|
27 | verbosity: (opts && opts.silent) ? 1 : 2
|
28 | });
|
29 |
|
30 |
|
31 | var oldPath = opts.env.PATH;
|
32 | opts.env.PATH = pathlib.join(__dirname, '..', '..', '.bin');
|
33 | opts.env.PATH += pathlib.delimiter;
|
34 | opts.env.PATH += oldPath;
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 | this.exec = function exec(stdin, callback) {
|
43 |
|
44 |
|
45 | if (typeof arguments[0] === 'function') {
|
46 | callback = arguments[0];
|
47 | stdin = undefined;
|
48 | } else if (typeof callback !== 'function') {
|
49 | callback = function(){};
|
50 | }
|
51 | if (!(stdin instanceof Vinyl)) {
|
52 | var defaultName = commandTemplate.split(' ')[0];
|
53 | if (typeof stdin === 'string') {
|
54 | stdin = new Vinyl({
|
55 | path: defaultName,
|
56 | contents: new Buffer(stdin)
|
57 | });
|
58 | } else if (stdin instanceof Buffer || stdin instanceof stream.Readable) {
|
59 | stdin = new Vinyl({
|
60 | path: defaultName,
|
61 | contents: stdin
|
62 | });
|
63 | } else {
|
64 | stdin = new Vinyl(stdin);
|
65 | if (stdin.path === null) stdin.path = defaultName;
|
66 | }
|
67 | }
|
68 |
|
69 |
|
70 |
|
71 | var command = _.template(commandTemplate, {file:stdin});
|
72 | var subshell;
|
73 | if (isWindows) {
|
74 | subshell = childProcess.spawn('cmd.exe', ['/c', command], {env:opts.env, cwd:opts.cwd});
|
75 | } else {
|
76 | subshell = childProcess.spawn('sh', ['-c', command], {env:opts.env, cwd:opts.cwd});
|
77 | }
|
78 |
|
79 |
|
80 |
|
81 | var logStream = new stream.PassThrough();
|
82 | if (opts.verbosity >= 2) {
|
83 | subshell.stdout.pipe(logStream);
|
84 | }
|
85 | subshell.stderr.pipe(logStream);
|
86 |
|
87 |
|
88 | subshell.once('close', function (code) {
|
89 |
|
90 |
|
91 |
|
92 | if (opts.verbosity >= 1) {
|
93 | var logTitle = util.format(
|
94 | '$ %s %s',
|
95 | gutil.colors.blue(command),
|
96 | (opts.verbosity < 2) ? gutil.colors.grey('# Silenced') : ''
|
97 | );
|
98 | gutil.log(logTitle);
|
99 | var logContents = logStream.read();
|
100 | if (logContents !== null) process.stdout.write(logContents);
|
101 | }
|
102 |
|
103 |
|
104 | if (code !== 0) {
|
105 | var errmsg = util.format('Command `%s` exited with code %s', command, code);
|
106 | var err = new Error(errmsg);
|
107 | err.status = code;
|
108 | return callback(err);
|
109 | }
|
110 |
|
111 | callback(null);
|
112 | });
|
113 |
|
114 |
|
115 |
|
116 | var stdout = new Vinyl(stdin);
|
117 | stdout.contents = subshell.stdout.pipe(new stream.PassThrough());
|
118 | stdin.pipe(subshell.stdin);
|
119 | return stdout;
|
120 | };
|
121 |
|
122 |
|
123 |
|
124 |
|
125 |
|
126 |
|
127 | this.toString = function toString() {
|
128 | return commandTemplate;
|
129 | };
|
130 |
|
131 | };
|