|
|
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;
|