UNPKG

5.11 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.execvp = exports.pipevp = exports.EndStrategy = void 0;
4const tslib_1 = require("tslib");
5const fslib_1 = require("@yarnpkg/fslib");
6const cross_spawn_1 = tslib_1.__importDefault(require("cross-spawn"));
7var EndStrategy;
8(function (EndStrategy) {
9 EndStrategy[EndStrategy["Never"] = 0] = "Never";
10 EndStrategy[EndStrategy["ErrorCode"] = 1] = "ErrorCode";
11 EndStrategy[EndStrategy["Always"] = 2] = "Always";
12})(EndStrategy = exports.EndStrategy || (exports.EndStrategy = {}));
13function hasFd(stream) {
14 // @ts-expect-error: Not sure how to typecheck this field
15 return stream !== null && typeof stream.fd === `number`;
16}
17function sigintHandler() {
18 // We don't want SIGINT to kill our process; we want it to kill the
19 // innermost process, whose end will cause our own to exit.
20}
21// Rather than attaching one SIGINT handler for each process, we
22// attach a single one and use a refcount to detect once it's no
23// longer needed.
24let sigintRefCount = 0;
25async function pipevp(fileName, args, { cwd, env = process.env, strict = false, stdin = null, stdout, stderr, end = EndStrategy.Always }) {
26 const stdio = [`pipe`, `pipe`, `pipe`];
27 if (stdin === null)
28 stdio[0] = `ignore`;
29 else if (hasFd(stdin))
30 stdio[0] = stdin;
31 if (hasFd(stdout))
32 stdio[1] = stdout;
33 if (hasFd(stderr))
34 stdio[2] = stderr;
35 if (sigintRefCount++ === 0)
36 process.on(`SIGINT`, sigintHandler);
37 const child = cross_spawn_1.default(fileName, args, {
38 cwd: fslib_1.npath.fromPortablePath(cwd),
39 env: {
40 ...env,
41 PWD: fslib_1.npath.fromPortablePath(cwd),
42 },
43 stdio,
44 });
45 if (!hasFd(stdin) && stdin !== null)
46 stdin.pipe(child.stdin);
47 if (!hasFd(stdout))
48 child.stdout.pipe(stdout, { end: false });
49 if (!hasFd(stderr))
50 child.stderr.pipe(stderr, { end: false });
51 const closeStreams = () => {
52 for (const stream of new Set([stdout, stderr])) {
53 if (!hasFd(stream)) {
54 stream.end();
55 }
56 }
57 };
58 return new Promise((resolve, reject) => {
59 child.on(`error`, error => {
60 if (--sigintRefCount === 0)
61 process.off(`SIGINT`, sigintHandler);
62 if (end === EndStrategy.Always || end === EndStrategy.ErrorCode)
63 closeStreams();
64 reject(error);
65 });
66 child.on(`close`, (code, sig) => {
67 if (--sigintRefCount === 0)
68 process.off(`SIGINT`, sigintHandler);
69 if (end === EndStrategy.Always || (end === EndStrategy.ErrorCode && code > 0))
70 closeStreams();
71 if (code === 0 || !strict) {
72 resolve({ code: getExitCode(code, sig) });
73 }
74 else if (code !== null) {
75 reject(new Error(`Child "${fileName}" exited with exit code ${code}`));
76 }
77 else {
78 reject(new Error(`Child "${fileName}" exited with signal ${sig}`));
79 }
80 });
81 });
82}
83exports.pipevp = pipevp;
84async function execvp(fileName, args, { cwd, env = process.env, encoding = `utf8`, strict = false }) {
85 const stdio = [`ignore`, `pipe`, `pipe`];
86 const stdoutChunks = [];
87 const stderrChunks = [];
88 const nativeCwd = fslib_1.npath.fromPortablePath(cwd);
89 if (typeof env.PWD !== `undefined`)
90 env = { ...env, PWD: nativeCwd };
91 const subprocess = cross_spawn_1.default(fileName, args, {
92 cwd: nativeCwd,
93 env,
94 stdio,
95 });
96 subprocess.stdout.on(`data`, (chunk) => {
97 stdoutChunks.push(chunk);
98 });
99 subprocess.stderr.on(`data`, (chunk) => {
100 stderrChunks.push(chunk);
101 });
102 return await new Promise((resolve, reject) => {
103 subprocess.on(`error`, reject);
104 subprocess.on(`close`, (code, signal) => {
105 const stdout = encoding === `buffer`
106 ? Buffer.concat(stdoutChunks)
107 : Buffer.concat(stdoutChunks).toString(encoding);
108 const stderr = encoding === `buffer`
109 ? Buffer.concat(stderrChunks)
110 : Buffer.concat(stderrChunks).toString(encoding);
111 if (code === 0 || !strict) {
112 resolve({
113 code: getExitCode(code, signal), stdout, stderr,
114 });
115 }
116 else {
117 reject(Object.assign(new Error(`Child "${fileName}" exited with exit code ${code}\n\n${stderr}`), {
118 code: getExitCode(code, signal), stdout, stderr,
119 }));
120 }
121 });
122 });
123}
124exports.execvp = execvp;
125const signalToCodeMap = new Map([
126 [`SIGINT`, 2],
127 [`SIGQUIT`, 3],
128 [`SIGKILL`, 9],
129 [`SIGTERM`, 15],
130]);
131function getExitCode(code, signal) {
132 const signalCode = signalToCodeMap.get(signal);
133 if (typeof signalCode !== `undefined`) {
134 return 128 + signalCode;
135 }
136 else {
137 return code !== null && code !== void 0 ? code : 1;
138 }
139}