spawn-rx 2.0.12 → 4.0.0-beta.1
Sign up to get free protection for your applications and to get access to all the features.
- package/.prettierrc +4 -0
- package/CODE_OF_CONDUCT.md +50 -50
- package/COPYING +7 -7
- package/README.md +187 -187
- package/build.cmd +1 -1
- package/build.sh +2 -2
- package/esdoc.json +26 -26
- package/eslint.config.mjs +88 -0
- package/lib/src/index.d.ts +84 -88
- package/lib/src/index.js +336 -316
- package/lib/src/index.js.map +1 -1
- package/package.json +28 -21
- package/src/ambient.d.ts +1 -1
- package/src/index.ts +405 -341
- package/test/asserttest.ts +16 -15
- package/test/spawn.ts +139 -102
- package/test/support.ts +15 -14
- package/tsconfig.json +25 -29
- package/.npmignore +0 -3
- package/.travis.yml +0 -24
- package/appveyor.yml +0 -21
- package/lib/index.js +0 -352
- package/tslint.json +0 -38
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
|
-
}
|
package/tslint.json
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
{
|
2
|
-
"rules": {
|
3
|
-
"curly": true,
|
4
|
-
"eofline": false,
|
5
|
-
"align": [true, "parameters"],
|
6
|
-
"class-name": true,
|
7
|
-
"indent": [true, "spaces"],
|
8
|
-
"max-line-length": [true, 150],
|
9
|
-
"no-consecutive-blank-lines": [true],
|
10
|
-
"no-trailing-whitespace": true,
|
11
|
-
"no-duplicate-variable": true,
|
12
|
-
"no-var-keyword": true,
|
13
|
-
"no-empty": true,
|
14
|
-
"no-unused-expression": true,
|
15
|
-
"no-use-before-declare": true,
|
16
|
-
"no-var-requires": true,
|
17
|
-
"one-line": [true,
|
18
|
-
"check-else",
|
19
|
-
"check-whitespace",
|
20
|
-
"check-open-brace"],
|
21
|
-
"quotemark": [true,
|
22
|
-
"single",
|
23
|
-
"avoid-escape"],
|
24
|
-
"semicolon": [true, "always"],
|
25
|
-
"typedef-whitespace": [true, {
|
26
|
-
"call-signature": "nospace",
|
27
|
-
"index-signature": "nospace",
|
28
|
-
"parameter": "nospace",
|
29
|
-
"property-declaration": "nospace",
|
30
|
-
"variable-declaration": "nospace"
|
31
|
-
}],
|
32
|
-
"whitespace": [true,
|
33
|
-
"check-branch",
|
34
|
-
"check-decl",
|
35
|
-
"check-operator",
|
36
|
-
"check-type"]
|
37
|
-
}
|
38
|
-
}
|