Security update to Drupal 8.4.6
[yaffs-website] / node_modules / execa / index.js
1 'use strict';
2 const childProcess = require('child_process');
3 const util = require('util');
4 const crossSpawn = require('cross-spawn');
5 const stripEof = require('strip-eof');
6 const npmRunPath = require('npm-run-path');
7 const isStream = require('is-stream');
8 const _getStream = require('get-stream');
9 const pFinally = require('p-finally');
10 const onExit = require('signal-exit');
11 const errname = require('./lib/errname');
12
13 const TEN_MEGABYTES = 1000 * 1000 * 10;
14
15 function handleArgs(cmd, args, opts) {
16         let parsed;
17
18         if (opts && opts.__winShell === true) {
19                 delete opts.__winShell;
20                 parsed = {
21                         command: cmd,
22                         args,
23                         options: opts,
24                         file: cmd,
25                         original: cmd
26                 };
27         } else {
28                 parsed = crossSpawn._parse(cmd, args, opts);
29         }
30
31         opts = Object.assign({
32                 maxBuffer: TEN_MEGABYTES,
33                 stripEof: true,
34                 preferLocal: true,
35                 encoding: 'utf8',
36                 reject: true,
37                 cleanup: true
38         }, parsed.options);
39
40         if (opts.preferLocal) {
41                 opts.env = npmRunPath.env(opts);
42         }
43
44         return {
45                 cmd: parsed.command,
46                 args: parsed.args,
47                 opts
48         };
49 }
50
51 function handleInput(spawned, opts) {
52         const input = opts.input;
53
54         if (input === null || input === undefined) {
55                 return;
56         }
57
58         if (isStream(input)) {
59                 input.pipe(spawned.stdin);
60         } else {
61                 spawned.stdin.end(input);
62         }
63 }
64
65 function handleOutput(opts, val) {
66         if (val && opts.stripEof) {
67                 val = stripEof(val);
68         }
69
70         return val;
71 }
72
73 function handleShell(fn, cmd, opts) {
74         let file = '/bin/sh';
75         let args = ['-c', cmd];
76
77         opts = Object.assign({}, opts);
78
79         if (process.platform === 'win32') {
80                 opts.__winShell = true;
81                 file = process.env.comspec || 'cmd.exe';
82                 args = ['/s', '/c', `"${cmd}"`];
83                 opts.windowsVerbatimArguments = true;
84         }
85
86         if (opts.shell) {
87                 file = opts.shell;
88                 delete opts.shell;
89         }
90
91         return fn(file, args, opts);
92 }
93
94 function getStream(process, stream, encoding, maxBuffer) {
95         if (!process[stream]) {
96                 return null;
97         }
98
99         let ret;
100
101         if (encoding) {
102                 ret = _getStream(process[stream], {
103                         encoding,
104                         maxBuffer
105                 });
106         } else {
107                 ret = _getStream.buffer(process[stream], {maxBuffer});
108         }
109
110         return ret.catch(err => {
111                 err.stream = stream;
112                 err.message = `${stream} ${err.message}`;
113                 throw err;
114         });
115 }
116
117 module.exports = (cmd, args, opts) => {
118         let joinedCmd = cmd;
119
120         if (Array.isArray(args) && args.length > 0) {
121                 joinedCmd += ' ' + args.join(' ');
122         }
123
124         const parsed = handleArgs(cmd, args, opts);
125         const encoding = parsed.opts.encoding;
126         const maxBuffer = parsed.opts.maxBuffer;
127
128         let spawned;
129         try {
130                 spawned = childProcess.spawn(parsed.cmd, parsed.args, parsed.opts);
131         } catch (err) {
132                 return Promise.reject(err);
133         }
134
135         let removeExitHandler;
136         if (parsed.opts.cleanup) {
137                 removeExitHandler = onExit(() => {
138                         spawned.kill();
139                 });
140         }
141
142         let timeoutId = null;
143         let timedOut = false;
144
145         const cleanupTimeout = () => {
146                 if (timeoutId) {
147                         clearTimeout(timeoutId);
148                         timeoutId = null;
149                 }
150         };
151
152         if (parsed.opts.timeout > 0) {
153                 timeoutId = setTimeout(() => {
154                         timeoutId = null;
155                         timedOut = true;
156                         spawned.kill(parsed.killSignal);
157                 }, parsed.opts.timeout);
158         }
159
160         const processDone = new Promise(resolve => {
161                 spawned.on('exit', (code, signal) => {
162                         cleanupTimeout();
163                         resolve({code, signal});
164                 });
165
166                 spawned.on('error', err => {
167                         cleanupTimeout();
168                         resolve({err});
169                 });
170         });
171
172         function destroy() {
173                 if (spawned.stdout) {
174                         spawned.stdout.destroy();
175                 }
176
177                 if (spawned.stderr) {
178                         spawned.stderr.destroy();
179                 }
180         }
181
182         const promise = pFinally(Promise.all([
183                 processDone,
184                 getStream(spawned, 'stdout', encoding, maxBuffer),
185                 getStream(spawned, 'stderr', encoding, maxBuffer)
186         ]).then(arr => {
187                 const result = arr[0];
188                 const stdout = arr[1];
189                 const stderr = arr[2];
190
191                 let err = result.err;
192                 const code = result.code;
193                 const signal = result.signal;
194
195                 if (removeExitHandler) {
196                         removeExitHandler();
197                 }
198
199                 if (err || code !== 0 || signal !== null) {
200                         if (!err) {
201                                 err = new Error(`Command failed: ${joinedCmd}\n${stderr}${stdout}`);
202                                 err.code = code < 0 ? errname(code) : code;
203                         }
204
205                         // TODO: missing some timeout logic for killed
206                         // https://github.com/nodejs/node/blob/master/lib/child_process.js#L203
207                         // err.killed = spawned.killed || killed;
208                         err.killed = err.killed || spawned.killed;
209
210                         err.stdout = stdout;
211                         err.stderr = stderr;
212                         err.failed = true;
213                         err.signal = signal || null;
214                         err.cmd = joinedCmd;
215                         err.timedOut = timedOut;
216
217                         if (!parsed.opts.reject) {
218                                 return err;
219                         }
220
221                         throw err;
222                 }
223
224                 return {
225                         stdout: handleOutput(parsed.opts, stdout),
226                         stderr: handleOutput(parsed.opts, stderr),
227                         code: 0,
228                         failed: false,
229                         killed: false,
230                         signal: null,
231                         cmd: joinedCmd,
232                         timedOut: false
233                 };
234         }), destroy);
235
236         crossSpawn._enoent.hookChildProcess(spawned, parsed);
237
238         handleInput(spawned, parsed.opts);
239
240         spawned.then = promise.then.bind(promise);
241         spawned.catch = promise.catch.bind(promise);
242
243         return spawned;
244 };
245
246 module.exports.stdout = function () {
247         // TODO: set `stderr: 'ignore'` when that option is implemented
248         return module.exports.apply(null, arguments).then(x => x.stdout);
249 };
250
251 module.exports.stderr = function () {
252         // TODO: set `stdout: 'ignore'` when that option is implemented
253         return module.exports.apply(null, arguments).then(x => x.stderr);
254 };
255
256 module.exports.shell = (cmd, opts) => handleShell(module.exports, cmd, opts);
257
258 module.exports.sync = (cmd, args, opts) => {
259         const parsed = handleArgs(cmd, args, opts);
260
261         if (isStream(parsed.opts.input)) {
262                 throw new TypeError('The `input` option cannot be a stream in sync mode');
263         }
264
265         const result = childProcess.spawnSync(parsed.cmd, parsed.args, parsed.opts);
266
267         result.stdout = handleOutput(parsed.opts, result.stdout);
268         result.stderr = handleOutput(parsed.opts, result.stderr);
269
270         return result;
271 };
272
273 module.exports.shellSync = (cmd, opts) => handleShell(module.exports.sync, cmd, opts);
274
275 module.exports.spawn = util.deprecate(module.exports, 'execa.spawn() is deprecated. Use execa() instead.');