1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.findExecutables = exports.which = exports.fork = exports.spawn = exports.Subprocess = exports.SubprocessError = exports.convertPATH = exports.expandTildePath = exports.TILDE_PATH_REGEX = exports.ERROR_SIGNAL_EXIT = exports.ERROR_NON_ZERO_EXIT = exports.ERROR_COMMAND_NOT_FOUND = void 0;
|
4 | const utils_array_1 = require("@ionic/utils-array");
|
5 | const utils_fs_1 = require("@ionic/utils-fs");
|
6 | const utils_process_1 = require("@ionic/utils-process");
|
7 | const utils_stream_1 = require("@ionic/utils-stream");
|
8 | const utils_terminal_1 = require("@ionic/utils-terminal");
|
9 | const child_process_1 = require("child_process");
|
10 | const crossSpawn = require("cross-spawn");
|
11 | const os = require("os");
|
12 | const pathlib = require("path");
|
13 | exports.ERROR_COMMAND_NOT_FOUND = 'ERR_SUBPROCESS_COMMAND_NOT_FOUND';
|
14 | exports.ERROR_NON_ZERO_EXIT = 'ERR_SUBPROCESS_NON_ZERO_EXIT';
|
15 | exports.ERROR_SIGNAL_EXIT = 'ERR_SUBPROCESS_SIGNAL_EXIT';
|
16 | exports.TILDE_PATH_REGEX = /^~($|\/|\\)/;
|
17 | function expandTildePath(p) {
|
18 | const h = os.homedir();
|
19 | return p.replace(exports.TILDE_PATH_REGEX, `${h}$1`);
|
20 | }
|
21 | exports.expandTildePath = expandTildePath;
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 | function convertPATH(path = process.env.PATH || '') {
|
33 | return path.split(pathlib.delimiter).map(expandTildePath).join(pathlib.delimiter);
|
34 | }
|
35 | exports.convertPATH = convertPATH;
|
36 | class SubprocessError extends Error {
|
37 | constructor(message) {
|
38 | super(message);
|
39 | this.name = 'SubprocessError';
|
40 | this.message = message;
|
41 | this.stack = (new Error()).stack || '';
|
42 | }
|
43 | }
|
44 | exports.SubprocessError = SubprocessError;
|
45 | class Subprocess {
|
46 | constructor(name, args, options = {}) {
|
47 | this.name = name;
|
48 | this.args = args;
|
49 | const masked = this.maskArg(name);
|
50 | if (masked !== name) {
|
51 | this.name = masked;
|
52 | this.path = name;
|
53 | }
|
54 | this._options = options;
|
55 | }
|
56 | get options() {
|
57 | const opts = this._options;
|
58 | if (!opts.env) {
|
59 | opts.env = process.env;
|
60 | }
|
61 | const env = utils_process_1.createProcessEnv(opts.env || {}, {
|
62 | PATH: convertPATH(typeof opts.env.PATH === 'string' ? opts.env.PATH : process.env.PATH),
|
63 | });
|
64 | return { ...opts, env };
|
65 | }
|
66 | async output() {
|
67 | this._options.stdio = 'pipe';
|
68 | const promise = this.run();
|
69 | const stdoutBuf = new utils_stream_1.WritableStreamBuffer();
|
70 | const stderrBuf = new utils_stream_1.WritableStreamBuffer();
|
71 | const combinedBuf = new utils_stream_1.WritableStreamBuffer();
|
72 | promise.p.stdout.pipe(stdoutBuf);
|
73 | promise.p.stdout.pipe(combinedBuf);
|
74 | promise.p.stderr.pipe(stderrBuf);
|
75 | promise.p.stderr.pipe(combinedBuf);
|
76 | try {
|
77 | await promise;
|
78 | }
|
79 | catch (e) {
|
80 | stdoutBuf.end();
|
81 | stderrBuf.end();
|
82 | e.output = combinedBuf.consume().toString();
|
83 | throw e;
|
84 | }
|
85 | stderrBuf.end();
|
86 | combinedBuf.end();
|
87 | return stdoutBuf.consume().toString();
|
88 | }
|
89 | async combinedOutput() {
|
90 | this._options.stdio = 'pipe';
|
91 | const promise = this.run();
|
92 | const buf = new utils_stream_1.WritableStreamBuffer();
|
93 | promise.p.stdout.pipe(buf);
|
94 | promise.p.stderr.pipe(buf);
|
95 | try {
|
96 | await promise;
|
97 | }
|
98 | catch (e) {
|
99 | e.output = buf.consume().toString();
|
100 | throw e;
|
101 | }
|
102 | return buf.consume().toString();
|
103 | }
|
104 | run() {
|
105 | const p = this.spawn();
|
106 | const promise = new Promise((resolve, reject) => {
|
107 | p.on('error', (error) => {
|
108 | let err;
|
109 | if (error.code === 'ENOENT') {
|
110 | err = new SubprocessError('Command not found.');
|
111 | err.code = exports.ERROR_COMMAND_NOT_FOUND;
|
112 | }
|
113 | else {
|
114 | err = new SubprocessError('Command error.');
|
115 | }
|
116 | err.error = error;
|
117 | reject(err);
|
118 | });
|
119 | p.on('close', (code, signal) => {
|
120 | let err;
|
121 | if (code === 0) {
|
122 | return resolve();
|
123 | }
|
124 | if (signal) {
|
125 | err = new SubprocessError('Signal exit from subprocess.');
|
126 | err.code = exports.ERROR_SIGNAL_EXIT;
|
127 | err.signal = signal;
|
128 | }
|
129 | else {
|
130 | err = new SubprocessError('Non-zero exit from subprocess.');
|
131 | err.code = exports.ERROR_NON_ZERO_EXIT;
|
132 | err.exitCode = code;
|
133 | }
|
134 | reject(err);
|
135 | });
|
136 | });
|
137 | Object.defineProperties(promise, {
|
138 | p: { value: p },
|
139 | });
|
140 | return promise;
|
141 | }
|
142 | spawn() {
|
143 | return spawn(this.path ? this.path : this.name, this.args, this.options);
|
144 | }
|
145 | bashify({ maskArgv0 = true, maskArgv1 = false, shiftArgv0 = false } = {}) {
|
146 | const args = [this.path ? this.path : this.name, ...this.args];
|
147 | if (shiftArgv0) {
|
148 | args.shift();
|
149 | }
|
150 | if (args[0] && maskArgv0) {
|
151 | args[0] = this.maskArg(args[0]);
|
152 | }
|
153 | if (args[1] && maskArgv1) {
|
154 | args[1] = this.maskArg(args[1]);
|
155 | }
|
156 | return args.length > 0
|
157 | ? args.map(arg => this.bashifyArg(arg)).join(' ')
|
158 | : '';
|
159 | }
|
160 | bashifyArg(arg) {
|
161 | return arg.includes(' ') ? `"${arg.replace(/\"/g, '\\"')}"` : arg;
|
162 | }
|
163 | maskArg(arg) {
|
164 | const i = arg.lastIndexOf(pathlib.sep);
|
165 | return i >= 0 ? arg.substring(i + 1) : arg;
|
166 | }
|
167 | }
|
168 | exports.Subprocess = Subprocess;
|
169 | function spawn(command, args = [], options) {
|
170 | return crossSpawn(command, [...args], options);
|
171 | }
|
172 | exports.spawn = spawn;
|
173 | function fork(modulePath, args = [], options = {}) {
|
174 | return child_process_1.fork(modulePath, [...args], options);
|
175 | }
|
176 | exports.fork = fork;
|
177 | const DEFAULT_PATHEXT = utils_terminal_1.TERMINAL_INFO.windows ? '.COM;.EXE;.BAT;.CMD' : undefined;
|
178 |
|
179 |
|
180 |
|
181 |
|
182 |
|
183 |
|
184 |
|
185 | async function which(program, { PATH = process.env.PATH, PATHEXT = process.env.PATHEXT || DEFAULT_PATHEXT } = {}) {
|
186 | if (program.includes(pathlib.sep)) {
|
187 | return program;
|
188 | }
|
189 | const results = await _findExecutables(program, { PATH });
|
190 | if (!results.length) {
|
191 | const err = new Error(`${program} cannot be found within PATH`);
|
192 | err.code = 'ENOENT';
|
193 | throw err;
|
194 | }
|
195 | return results[0];
|
196 | }
|
197 | exports.which = which;
|
198 |
|
199 |
|
200 |
|
201 |
|
202 |
|
203 |
|
204 |
|
205 |
|
206 | async function findExecutables(program, { PATH = process.env.PATH, PATHEXT = process.env.PATHEXT || DEFAULT_PATHEXT } = {}) {
|
207 | if (program.includes(pathlib.sep)) {
|
208 | return [program];
|
209 | }
|
210 | return _findExecutables(program, { PATH });
|
211 | }
|
212 | exports.findExecutables = findExecutables;
|
213 | async function _findExecutables(program, { PATH = process.env.PATH, PATHEXT = process.env.PATHEXT || DEFAULT_PATHEXT } = {}) {
|
214 | const pathParts = utils_process_1.getPathParts(PATH);
|
215 | let programNames;
|
216 |
|
217 |
|
218 | if (utils_terminal_1.TERMINAL_INFO.windows) {
|
219 | const exts = utils_process_1.getPathParts(PATHEXT).map(ext => ext.toLowerCase());
|
220 |
|
221 | programNames = exts.includes(pathlib.extname(program).toLowerCase()) ? [program] : exts.map(ext => program + ext);
|
222 | }
|
223 | else {
|
224 | programNames = [program];
|
225 | }
|
226 | return [].concat(...await utils_array_1.map(programNames, async (programName) => utils_array_1.concurrentFilter(pathParts.map(p => pathlib.join(p, programName)), async (p) => utils_fs_1.isExecutableFile(p))));
|
227 | }
|