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