117 lines
3.2 KiB
JavaScript
117 lines
3.2 KiB
JavaScript
import {setImmediate} from 'node:timers/promises';
|
|
import getStream, {getStreamAsArrayBuffer, getStreamAsArray} from 'get-stream';
|
|
import {isArrayBuffer} from '../utils/uint-array.js';
|
|
import {shouldLogOutput, logLines} from '../verbose/output.js';
|
|
import {iterateForResult} from './iterate.js';
|
|
import {handleMaxBuffer} from './max-buffer.js';
|
|
import {getStripFinalNewline} from './strip-newline.js';
|
|
|
|
// Retrieve `result.stdout|stderr|all|stdio[*]`
|
|
export const getStreamOutput = async ({stream, onStreamEnd, fdNumber, encoding, buffer, maxBuffer, lines, allMixed, stripFinalNewline, verboseInfo, streamInfo}) => {
|
|
const logPromise = logOutputAsync({
|
|
stream,
|
|
onStreamEnd,
|
|
fdNumber,
|
|
encoding,
|
|
allMixed,
|
|
verboseInfo,
|
|
streamInfo,
|
|
});
|
|
|
|
if (!buffer) {
|
|
await Promise.all([resumeStream(stream), logPromise]);
|
|
return;
|
|
}
|
|
|
|
const stripFinalNewlineValue = getStripFinalNewline(stripFinalNewline, fdNumber);
|
|
const iterable = iterateForResult({
|
|
stream,
|
|
onStreamEnd,
|
|
lines,
|
|
encoding,
|
|
stripFinalNewline: stripFinalNewlineValue,
|
|
allMixed,
|
|
});
|
|
const [output] = await Promise.all([
|
|
getStreamContents({
|
|
stream,
|
|
iterable,
|
|
fdNumber,
|
|
encoding,
|
|
maxBuffer,
|
|
lines,
|
|
}),
|
|
logPromise,
|
|
]);
|
|
return output;
|
|
};
|
|
|
|
const logOutputAsync = async ({stream, onStreamEnd, fdNumber, encoding, allMixed, verboseInfo, streamInfo: {fileDescriptors}}) => {
|
|
if (!shouldLogOutput({
|
|
stdioItems: fileDescriptors[fdNumber]?.stdioItems,
|
|
encoding,
|
|
verboseInfo,
|
|
fdNumber,
|
|
})) {
|
|
return;
|
|
}
|
|
|
|
const linesIterable = iterateForResult({
|
|
stream,
|
|
onStreamEnd,
|
|
lines: true,
|
|
encoding,
|
|
stripFinalNewline: true,
|
|
allMixed,
|
|
});
|
|
await logLines(linesIterable, stream, fdNumber, verboseInfo);
|
|
};
|
|
|
|
// When using `buffer: false`, users need to read `subprocess.stdout|stderr|all` right away
|
|
// See https://github.com/sindresorhus/execa/issues/730 and https://github.com/sindresorhus/execa/pull/729#discussion_r1465496310
|
|
const resumeStream = async stream => {
|
|
await setImmediate();
|
|
if (stream.readableFlowing === null) {
|
|
stream.resume();
|
|
}
|
|
};
|
|
|
|
const getStreamContents = async ({stream, stream: {readableObjectMode}, iterable, fdNumber, encoding, maxBuffer, lines}) => {
|
|
try {
|
|
if (readableObjectMode || lines) {
|
|
return await getStreamAsArray(iterable, {maxBuffer});
|
|
}
|
|
|
|
if (encoding === 'buffer') {
|
|
return new Uint8Array(await getStreamAsArrayBuffer(iterable, {maxBuffer}));
|
|
}
|
|
|
|
return await getStream(iterable, {maxBuffer});
|
|
} catch (error) {
|
|
return handleBufferedData(handleMaxBuffer({
|
|
error,
|
|
stream,
|
|
readableObjectMode,
|
|
lines,
|
|
encoding,
|
|
fdNumber,
|
|
}));
|
|
}
|
|
};
|
|
|
|
// On failure, `result.stdout|stderr|all` should contain the currently buffered stream
|
|
// They are automatically closed and flushed by Node.js when the subprocess exits
|
|
// When `buffer` is `false`, `streamPromise` is `undefined` and there is no buffered data to retrieve
|
|
export const getBufferedData = async streamPromise => {
|
|
try {
|
|
return await streamPromise;
|
|
} catch (error) {
|
|
return handleBufferedData(error);
|
|
}
|
|
};
|
|
|
|
// Ensure we are returning Uint8Arrays when using `encoding: 'buffer'`
|
|
const handleBufferedData = ({bufferedData}) => isArrayBuffer(bufferedData)
|
|
? new Uint8Array(bufferedData)
|
|
: bufferedData;
|