spawn-rx 2.0.9 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
package/lib/index.js DELETED
@@ -1,352 +0,0 @@
1
- 'use strict';
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.findActualExecutable = findActualExecutable;
7
- exports.spawnDetached = spawnDetached;
8
- exports.spawn = spawn;
9
- exports.spawnDetachedPromise = spawnDetachedPromise;
10
- exports.spawnPromise = spawnPromise;
11
-
12
- var _path = require('path');
13
-
14
- var _path2 = _interopRequireDefault(_path);
15
-
16
- var _net = require('net');
17
-
18
- var _net2 = _interopRequireDefault(_net);
19
-
20
- var _fs = require('fs');
21
-
22
- var _fs2 = _interopRequireDefault(_fs);
23
-
24
- require('rxjs/add/observable/of');
25
-
26
- require('rxjs/add/observable/merge');
27
-
28
- require('rxjs/add/operator/pluck');
29
-
30
- require('rxjs/add/operator/reduce');
31
-
32
- var _Observable = require('rxjs/Observable');
33
-
34
- var _Subscription = require('rxjs/Subscription');
35
-
36
- var _AsyncSubject = require('rxjs/AsyncSubject');
37
-
38
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
39
-
40
- const spawnOg = require('child_process').spawn;
41
- const isWindows = process.platform === 'win32';
42
-
43
- const d = require('debug')('spawn-rx');
44
-
45
- /**
46
- * stat a file but don't throw if it doesn't exist
47
- *
48
- * @param {string} file The path to a file
49
- * @return {Stats} The stats structure
50
- *
51
- * @private
52
- */
53
- function statSyncNoException(file) {
54
- try {
55
- return _fs2.default.statSync(file);
56
- } catch (e) {
57
- return null;
58
- }
59
- }
60
-
61
- /**
62
- * Search PATH to see if a file exists in any of the path folders.
63
- *
64
- * @param {string} exe The file to search for
65
- * @return {string} A fully qualified path, or the original path if nothing
66
- * is found
67
- *
68
- * @private
69
- */
70
- function runDownPath(exe) {
71
- // NB: Windows won't search PATH looking for executables in spawn like
72
- // Posix does
73
-
74
- // Files with any directory path don't get this applied
75
- if (exe.match(/[\\\/]/)) {
76
- d('Path has slash in directory, bailing');
77
- return exe;
78
- }
79
-
80
- let target = _path2.default.join('.', exe);
81
- if (statSyncNoException(target)) {
82
- d(`Found executable in currect directory: ${ target }`);
83
- return target;
84
- }
85
-
86
- let haystack = process.env.PATH.split(isWindows ? ';' : ':');
87
- for (let p of haystack) {
88
- let needle = _path2.default.join(p, exe);
89
- if (statSyncNoException(needle)) return needle;
90
- }
91
-
92
- d('Failed to find executable anywhere in path');
93
- return exe;
94
- }
95
-
96
- /**
97
- * Finds the actual executable and parameters to run on Windows. This method
98
- * mimics the POSIX behavior of being able to run scripts as executables by
99
- * replacing the passed-in executable with the script runner, for PowerShell,
100
- * CMD, and node scripts.
101
- *
102
- * This method also does the work of running down PATH, which spawn on Windows
103
- * also doesn't do, unlike on POSIX.
104
- *
105
- * @param {string} exe The executable to run
106
- * @param {Array<string>} args The arguments to run
107
- *
108
- * @return {Object} The cmd and args to run
109
- * @property {string} cmd The command to pass to spawn
110
- * @property {Array<string>} args The arguments to pass to spawn
111
- */
112
- function findActualExecutable(exe, args) {
113
- // POSIX can just execute scripts directly, no need for silly goosery
114
- if (process.platform !== 'win32') return { cmd: runDownPath(exe), args: args };
115
-
116
- if (!_fs2.default.existsSync(exe)) {
117
- // NB: When you write something like `surf-client ... -- surf-build` on Windows,
118
- // a shell would normally convert that to surf-build.cmd, but since it's passed
119
- // in as an argument, it doesn't happen
120
- const possibleExts = ['.exe', '.bat', '.cmd', '.ps1'];
121
- for (let ext of possibleExts) {
122
- let possibleFullPath = runDownPath(`${ exe }${ ext }`);
123
-
124
- if (_fs2.default.existsSync(possibleFullPath)) {
125
- return findActualExecutable(possibleFullPath, args);
126
- }
127
- }
128
- }
129
-
130
- if (exe.match(/\.ps1$/i)) {
131
- let cmd = _path2.default.join(process.env.SYSTEMROOT, 'System32', 'WindowsPowerShell', 'v1.0', 'PowerShell.exe');
132
- let psargs = ['-ExecutionPolicy', 'Unrestricted', '-NoLogo', '-NonInteractive', '-File', exe];
133
-
134
- return { cmd: cmd, args: psargs.concat(args) };
135
- }
136
-
137
- if (exe.match(/\.(bat|cmd)$/i)) {
138
- let cmd = _path2.default.join(process.env.SYSTEMROOT, 'System32', 'cmd.exe');
139
- let cmdArgs = ['/C', `${ exe } ${ args.join(' ') }`];
140
-
141
- return { cmd: cmd, args: cmdArgs };
142
- }
143
-
144
- if (exe.match(/\.(js)$/i)) {
145
- let cmd = process.execPath;
146
- let nodeArgs = [exe];
147
-
148
- return { cmd: cmd, args: nodeArgs.concat(args) };
149
- }
150
-
151
- // Dunno lol
152
- return { cmd: exe, args: args };
153
- }
154
-
155
- /**
156
- * Spawns a process but detached from the current process. The process is put
157
- * into its own Process Group that can be killed by unsubscribing from the
158
- * return Observable.
159
- *
160
- * @param {string} exe The executable to run
161
- * @param {Array<string>} params The parameters to pass to the child
162
- * @param {Object} opts Options to pass to spawn.
163
- *
164
- * @return {Observable<string>} Returns an Observable that when subscribed
165
- * to, will create a detached process. The
166
- * process output will be streamed to this
167
- * Observable, and if unsubscribed from, the
168
- * process will be terminated early. If the
169
- * process terminates with a non-zero value,
170
- * the Observable will terminate with onError.
171
- */
172
- function spawnDetached(exe, params) {
173
- let opts = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
174
-
175
- var _findActualExecutable = findActualExecutable(exe, params);
176
-
177
- let cmd = _findActualExecutable.cmd,
178
- args = _findActualExecutable.args;
179
-
180
-
181
- if (!isWindows) return spawn(cmd, args, Object.assign({}, opts || {}, { detached: true }));
182
- const newParams = [cmd].concat(args);
183
-
184
- let target = _path2.default.join(__dirname, '..', 'vendor', 'jobber', 'jobber.exe');
185
- let options = Object.assign({}, opts || {}, { detached: true, jobber: true });
186
-
187
- d(`spawnDetached: ${ target }, ${ newParams }`);
188
- return spawn(target, newParams, options);
189
- }
190
-
191
- /**
192
- * Spawns a process attached as a child of the current process.
193
- *
194
- * @param {string} exe The executable to run
195
- * @param {Array<string>} params The parameters to pass to the child
196
- * @param {Object} opts Options to pass to spawn.
197
- *
198
- * @return {Observable<string>} Returns an Observable that when subscribed
199
- * to, will create a child process. The
200
- * process output will be streamed to this
201
- * Observable, and if unsubscribed from, the
202
- * process will be terminated early. If the
203
- * process terminates with a non-zero value,
204
- * the Observable will terminate with onError.
205
- */
206
- function spawn(exe) {
207
- let params = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
208
- let opts = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
209
-
210
- opts = opts || {};
211
- let spawnObs = _Observable.Observable.create(subj => {
212
- let proc = null;
213
-
214
- var _findActualExecutable2 = findActualExecutable(exe, params);
215
-
216
- let cmd = _findActualExecutable2.cmd,
217
- args = _findActualExecutable2.args;
218
-
219
- d(`spawning process: ${ cmd } ${ args.join() }, ${ JSON.stringify(opts) }`);
220
- let origOpts = Object.assign({}, opts);
221
- if ('jobber' in origOpts) delete origOpts.jobber;
222
- if ('split' in origOpts) delete origOpts.split;
223
-
224
- proc = spawnOg(cmd, args, origOpts);
225
-
226
- let bufHandler = source => b => {
227
- if (b.length < 1) return;
228
- let chunk = "<< String sent back was too long >>";
229
- try {
230
- chunk = b.toString();
231
- } catch (e) {
232
- chunk = `<< Lost chunk of process output for ${ exe } - length was ${ b.length }>>`;
233
- }
234
-
235
- subj.next({ source: source, text: chunk });
236
- };
237
-
238
- let ret = new _Subscription.Subscription();
239
-
240
- if (opts.stdin) {
241
- if (proc.stdin) {
242
- ret.add(opts.stdin.subscribe(x => proc.stdin.write(x), subj.error, () => proc.stdin.end()));
243
- } else {
244
- subj.error(new Error(`opts.stdio conflicts with provided spawn opts.stdin observable, 'pipe' is required`));
245
- }
246
- }
247
-
248
- let stderrCompleted = null;
249
- let stdoutCompleted = null;
250
- let noClose = false;
251
-
252
- if (proc.stdout) {
253
- stdoutCompleted = new _AsyncSubject.AsyncSubject();
254
- proc.stdout.on('data', bufHandler('stdout'));
255
- proc.stdout.on('close', () => {
256
- stdoutCompleted.next(true);stdoutCompleted.complete();
257
- });
258
- } else {
259
- stdoutCompleted = _Observable.Observable.of(true);
260
- }
261
-
262
- if (proc.stderr) {
263
- stderrCompleted = new _AsyncSubject.AsyncSubject();
264
- proc.stderr.on('data', bufHandler('stderr'));
265
- proc.stderr.on('close', () => {
266
- stderrCompleted.next(true);stderrCompleted.complete();
267
- });
268
- } else {
269
- stderrCompleted = _Observable.Observable.of(true);
270
- }
271
-
272
- proc.on('error', e => {
273
- noClose = true;
274
- subj.error(e);
275
- });
276
-
277
- proc.on('close', code => {
278
- noClose = true;
279
- let pipesClosed = _Observable.Observable.merge(stdoutCompleted, stderrCompleted).reduce(acc => acc, true);
280
-
281
- if (code === 0) {
282
- pipesClosed.subscribe(() => subj.complete());
283
- } else {
284
- pipesClosed.subscribe(() => subj.error(new Error(`Failed with exit code: ${ code }`)));
285
- }
286
- });
287
-
288
- ret.add(new _Subscription.Subscription(() => {
289
- if (noClose) return;
290
-
291
- d(`Killing process: ${ cmd } ${ args.join() }`);
292
- if (opts.jobber) {
293
- // NB: Connecting to Jobber's named pipe will kill it
294
- _net2.default.connect(`\\\\.\\pipe\\jobber-${ proc.pid }`);
295
- setTimeout(() => proc.kill(), 5 * 1000);
296
- } else {
297
- proc.kill();
298
- }
299
- }));
300
-
301
- return ret;
302
- });
303
-
304
- return opts.split ? spawnObs : spawnObs.pluck('text');
305
- }
306
-
307
- function wrapObservableInPromise(obs) {
308
- return new Promise((res, rej) => {
309
- let out = '';
310
-
311
- obs.subscribe(x => out += x, e => rej(new Error(`${ out }\n${ e.message }`)), () => res(out));
312
- });
313
- }
314
-
315
- /**
316
- * Spawns a process but detached from the current process. The process is put
317
- * into its own Process Group.
318
- *
319
- * @param {string} exe The executable to run
320
- * @param {Array<string>} params The parameters to pass to the child
321
- * @param {Object} opts Options to pass to spawn.
322
- *
323
- * @return {Promise<string>} Returns an Promise that represents a detached
324
- * process. The value returned is the process
325
- * output. If the process terminates with a
326
- * non-zero value, the Promise will resolve with
327
- * an Error.
328
- */
329
- function spawnDetachedPromise(exe, params) {
330
- let opts = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
331
-
332
- return wrapObservableInPromise(spawnDetached(exe, params, opts));
333
- }
334
-
335
- /**
336
- * Spawns a process as a child process.
337
- *
338
- * @param {string} exe The executable to run
339
- * @param {Array<string>} params The parameters to pass to the child
340
- * @param {Object} opts Options to pass to spawn.
341
- *
342
- * @return {Promise<string>} Returns an Promise that represents a child
343
- * process. The value returned is the process
344
- * output. If the process terminates with a
345
- * non-zero value, the Promise will resolve with
346
- * an Error.
347
- */
348
- function spawnPromise(exe, params) {
349
- let opts = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
350
-
351
- return wrapObservableInPromise(spawn(exe, params, opts));
352
- }