1 | "use strict";
|
2 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
3 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
4 | };
|
5 | Object.defineProperty(exports, "__esModule", { value: true });
|
6 | const cross_spawn_1 = __importDefault(require("cross-spawn"));
|
7 | const stream_1 = require("stream");
|
8 | var Pipe;
|
9 | (function (Pipe) {
|
10 | Pipe[Pipe["STDOUT"] = 1] = "STDOUT";
|
11 | Pipe[Pipe["STDERR"] = 2] = "STDERR";
|
12 | })(Pipe || (Pipe = {}));
|
13 | function sigintHandler() {
|
14 |
|
15 |
|
16 | }
|
17 |
|
18 |
|
19 |
|
20 | let sigintRefCount = 0;
|
21 | function makeProcess(name, args, opts, spawnOpts) {
|
22 | return (stdio) => {
|
23 | const stdin = stdio[0] instanceof stream_1.Transform
|
24 | ? `pipe`
|
25 | : stdio[0];
|
26 | const stdout = stdio[1] instanceof stream_1.Transform
|
27 | ? `pipe`
|
28 | : stdio[1];
|
29 | const stderr = stdio[2] instanceof stream_1.Transform
|
30 | ? `pipe`
|
31 | : stdio[2];
|
32 | const child = cross_spawn_1.default(name, args, { ...spawnOpts, stdio: [
|
33 | stdin,
|
34 | stdout,
|
35 | stderr,
|
36 | ] });
|
37 | if (sigintRefCount++ === 0)
|
38 | process.on(`SIGINT`, sigintHandler);
|
39 | if (stdio[0] instanceof stream_1.Transform)
|
40 | stdio[0].pipe(child.stdin);
|
41 | if (stdio[1] instanceof stream_1.Transform)
|
42 | child.stdout.pipe(stdio[1], { end: false });
|
43 | if (stdio[2] instanceof stream_1.Transform)
|
44 | child.stderr.pipe(stdio[2], { end: false });
|
45 | return {
|
46 | stdin: child.stdin,
|
47 | promise: new Promise(resolve => {
|
48 | child.on(`error`, error => {
|
49 | if (--sigintRefCount === 0)
|
50 | process.off(`SIGINT`, sigintHandler);
|
51 |
|
52 | switch (error.code) {
|
53 | case `ENOENT`:
|
54 | {
|
55 | stdio[2].write(`command not found: ${name}\n`);
|
56 | resolve(127);
|
57 | }
|
58 | break;
|
59 | case `EACCESS`:
|
60 | {
|
61 | stdio[2].write(`permission denied: ${name}\n`);
|
62 | resolve(128);
|
63 | }
|
64 | break;
|
65 | default:
|
66 | {
|
67 | stdio[2].write(`uncaught error: ${error.message}\n`);
|
68 | resolve(1);
|
69 | }
|
70 | break;
|
71 | }
|
72 | });
|
73 | child.on(`exit`, code => {
|
74 | if (--sigintRefCount === 0)
|
75 | process.off(`SIGINT`, sigintHandler);
|
76 | if (code !== null) {
|
77 | resolve(code);
|
78 | }
|
79 | else {
|
80 | resolve(129);
|
81 | }
|
82 | });
|
83 | }),
|
84 | };
|
85 | };
|
86 | }
|
87 | exports.makeProcess = makeProcess;
|
88 | function makeBuiltin(builtin) {
|
89 | return (stdio) => {
|
90 | const stdin = stdio[0] === `pipe`
|
91 | ? new stream_1.PassThrough()
|
92 | : stdio[0];
|
93 | return {
|
94 | stdin,
|
95 | promise: Promise.resolve().then(() => builtin({
|
96 | stdin,
|
97 | stdout: stdio[1],
|
98 | stderr: stdio[2],
|
99 | })),
|
100 | };
|
101 | };
|
102 | }
|
103 | exports.makeBuiltin = makeBuiltin;
|
104 | class ProtectedStream {
|
105 | constructor(stream) {
|
106 | this.stream = stream;
|
107 | }
|
108 | close() {
|
109 |
|
110 | }
|
111 | get() {
|
112 | return this.stream;
|
113 | }
|
114 | }
|
115 | exports.ProtectedStream = ProtectedStream;
|
116 | class PipeStream {
|
117 | constructor() {
|
118 | this.stream = null;
|
119 | }
|
120 | close() {
|
121 | if (this.stream === null) {
|
122 | throw new Error(`Assertion failed: No stream attached`);
|
123 | }
|
124 | else {
|
125 | this.stream.end();
|
126 | }
|
127 | }
|
128 | attach(stream) {
|
129 | this.stream = stream;
|
130 | }
|
131 | get() {
|
132 | if (this.stream === null) {
|
133 | throw new Error(`Assertion failed: No stream attached`);
|
134 | }
|
135 | else {
|
136 | return this.stream;
|
137 | }
|
138 | }
|
139 | }
|
140 | class Handle {
|
141 | constructor(ancestor, implementation) {
|
142 | this.stdin = null;
|
143 | this.stdout = null;
|
144 | this.stderr = null;
|
145 | this.pipe = null;
|
146 | this.ancestor = ancestor;
|
147 | this.implementation = implementation;
|
148 | }
|
149 | static start(implementation, { stdin, stdout, stderr }) {
|
150 | const chain = new Handle(null, implementation);
|
151 | chain.stdin = stdin;
|
152 | chain.stdout = stdout;
|
153 | chain.stderr = stderr;
|
154 | return chain;
|
155 | }
|
156 | pipeTo(implementation, source = Pipe.STDOUT) {
|
157 | const next = new Handle(this, implementation);
|
158 | const pipe = new PipeStream();
|
159 | next.pipe = pipe;
|
160 | next.stdout = this.stdout;
|
161 | next.stderr = this.stderr;
|
162 | if ((source & Pipe.STDOUT) === Pipe.STDOUT)
|
163 | this.stdout = pipe;
|
164 | else if (this.ancestor !== null)
|
165 | this.stderr = this.ancestor.stdout;
|
166 | if ((source & Pipe.STDERR) === Pipe.STDERR)
|
167 | this.stderr = pipe;
|
168 | else if (this.ancestor !== null)
|
169 | this.stderr = this.ancestor.stderr;
|
170 | return next;
|
171 | }
|
172 | async exec() {
|
173 | const stdio = [
|
174 | `ignore`,
|
175 | `ignore`,
|
176 | `ignore`,
|
177 | ];
|
178 | if (this.pipe) {
|
179 | stdio[0] = `pipe`;
|
180 | }
|
181 | else {
|
182 | if (this.stdin === null) {
|
183 | throw new Error(`Assertion failed: No input stream registered`);
|
184 | }
|
185 | else {
|
186 | stdio[0] = this.stdin.get();
|
187 | }
|
188 | }
|
189 | let stdoutLock;
|
190 | if (this.stdout === null) {
|
191 | throw new Error(`Assertion failed: No output stream registered`);
|
192 | }
|
193 | else {
|
194 | stdoutLock = this.stdout;
|
195 | stdio[1] = stdoutLock.get();
|
196 | }
|
197 | let stderrLock;
|
198 | if (this.stderr === null) {
|
199 | throw new Error(`Assertion failed: No error stream registered`);
|
200 | }
|
201 | else {
|
202 | stderrLock = this.stderr;
|
203 | stdio[2] = stderrLock.get();
|
204 | }
|
205 | const child = this.implementation(stdio);
|
206 | if (this.pipe)
|
207 | this.pipe.attach(child.stdin);
|
208 | return await child.promise.then(code => {
|
209 | stdoutLock.close();
|
210 | stderrLock.close();
|
211 | return code;
|
212 | });
|
213 | }
|
214 | async run() {
|
215 | const promises = [];
|
216 | for (let handle = this; handle; handle = handle.ancestor)
|
217 | promises.push(handle.exec());
|
218 | const exitCodes = await Promise.all(promises);
|
219 | return exitCodes[0];
|
220 | }
|
221 | }
|
222 | exports.Handle = Handle;
|
223 | function start(p, opts) {
|
224 | return Handle.start(p, opts);
|
225 | }
|
226 | exports.start = start;
|