DCFronted/node_modules/execa/lib/resolve/wait-subprocess.js
zyb 0c0b5d869c 加入了node_modules
添加了新的功能项
2025-05-13 21:23:41 +08:00

147 lines
4.2 KiB
JavaScript

import {once} from 'node:events';
import {isStream as isNodeStream} from 'is-stream';
import {throwOnTimeout} from '../terminate/timeout.js';
import {throwOnCancel} from '../terminate/cancel.js';
import {throwOnGracefulCancel} from '../terminate/graceful.js';
import {isStandardStream} from '../utils/standard-stream.js';
import {TRANSFORM_TYPES} from '../stdio/type.js';
import {getBufferedData} from '../io/contents.js';
import {waitForIpcOutput, getBufferedIpcOutput} from '../ipc/buffer-messages.js';
import {sendIpcInput} from '../ipc/ipc-input.js';
import {waitForAllStream} from './all-async.js';
import {waitForStdioStreams} from './stdio.js';
import {waitForExit, waitForSuccessfulExit} from './exit-async.js';
import {waitForStream} from './wait-stream.js';
// Retrieve result of subprocess: exit code, signal, error, streams (stdout/stderr/all)
export const waitForSubprocessResult = async ({
subprocess,
options: {
encoding,
buffer,
maxBuffer,
lines,
timeoutDuration: timeout,
cancelSignal,
gracefulCancel,
forceKillAfterDelay,
stripFinalNewline,
ipc,
ipcInput,
},
context,
verboseInfo,
fileDescriptors,
originalStreams,
onInternalError,
controller,
}) => {
const exitPromise = waitForExit(subprocess, context);
const streamInfo = {
originalStreams,
fileDescriptors,
subprocess,
exitPromise,
propagating: false,
};
const stdioPromises = waitForStdioStreams({
subprocess,
encoding,
buffer,
maxBuffer,
lines,
stripFinalNewline,
verboseInfo,
streamInfo,
});
const allPromise = waitForAllStream({
subprocess,
encoding,
buffer,
maxBuffer,
lines,
stripFinalNewline,
verboseInfo,
streamInfo,
});
const ipcOutput = [];
const ipcOutputPromise = waitForIpcOutput({
subprocess,
buffer,
maxBuffer,
ipc,
ipcOutput,
verboseInfo,
});
const originalPromises = waitForOriginalStreams(originalStreams, subprocess, streamInfo);
const customStreamsEndPromises = waitForCustomStreamsEnd(fileDescriptors, streamInfo);
try {
return await Promise.race([
Promise.all([
{},
waitForSuccessfulExit(exitPromise),
Promise.all(stdioPromises),
allPromise,
ipcOutputPromise,
sendIpcInput(subprocess, ipcInput),
...originalPromises,
...customStreamsEndPromises,
]),
onInternalError,
throwOnSubprocessError(subprocess, controller),
...throwOnTimeout(subprocess, timeout, context, controller),
...throwOnCancel({
subprocess,
cancelSignal,
gracefulCancel,
context,
controller,
}),
...throwOnGracefulCancel({
subprocess,
cancelSignal,
gracefulCancel,
forceKillAfterDelay,
context,
controller,
}),
]);
} catch (error) {
context.terminationReason ??= 'other';
return Promise.all([
{error},
exitPromise,
Promise.all(stdioPromises.map(stdioPromise => getBufferedData(stdioPromise))),
getBufferedData(allPromise),
getBufferedIpcOutput(ipcOutputPromise, ipcOutput),
Promise.allSettled(originalPromises),
Promise.allSettled(customStreamsEndPromises),
]);
}
};
// Transforms replace `subprocess.std*`, which means they are not exposed to users.
// However, we still want to wait for their completion.
const waitForOriginalStreams = (originalStreams, subprocess, streamInfo) =>
originalStreams.map((stream, fdNumber) => stream === subprocess.stdio[fdNumber]
? undefined
: waitForStream(stream, fdNumber, streamInfo));
// Some `stdin`/`stdout`/`stderr` options create a stream, e.g. when passing a file path.
// The `.pipe()` method automatically ends that stream when `subprocess` ends.
// This makes sure we wait for the completion of those streams, in order to catch any error.
const waitForCustomStreamsEnd = (fileDescriptors, streamInfo) => fileDescriptors.flatMap(({stdioItems}, fdNumber) => stdioItems
.filter(({value, stream = value}) => isNodeStream(stream, {checkOpen: false}) && !isStandardStream(stream))
.map(({type, value, stream = value}) => waitForStream(stream, fdNumber, streamInfo, {
isSameDirection: TRANSFORM_TYPES.has(type),
stopOnExit: type === 'native',
})));
// Fails when the subprocess emits an `error` event
const throwOnSubprocessError = async (subprocess, {signal}) => {
const [error] = await once(subprocess, 'error', {signal});
throw error;
};