Skip to content

Commit f9f1199

Browse files
authored
Refactor verbose logic (#1126)
1 parent cbe805c commit f9f1199

18 files changed

Lines changed: 246 additions & 157 deletions

lib/arguments/command.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@ import {joinCommand} from './escape.js';
55
import {normalizeFdSpecificOption} from './specific.js';
66

77
// Compute `result.command`, `result.escapedCommand` and `verbose`-related information
8-
export const handleCommand = (filePath, rawArguments, rawOptions) => {
8+
export const handleCommand = (filePath, rawArguments, {piped, ...rawOptions}) => {
99
const startTime = getStartTime();
1010
const {command, escapedCommand} = joinCommand(filePath, rawArguments);
11-
const verboseInfo = getVerboseInfo(normalizeFdSpecificOption(rawOptions, 'verbose'));
12-
logCommand(escapedCommand, verboseInfo, rawOptions);
11+
const verbose = normalizeFdSpecificOption(rawOptions, 'verbose');
12+
const verboseInfo = getVerboseInfo(verbose, escapedCommand, {...rawOptions});
13+
logCommand(escapedCommand, verboseInfo, piped);
1314
return {
1415
command,
1516
escapedCommand,

lib/arguments/specific.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
import {debuglog} from 'node:util';
12
import isPlainObject from 'is-plain-obj';
23
import {STANDARD_STREAMS_ALIASES} from '../utils/standard-stream.js';
3-
import {verboseDefault} from '../verbose/info.js';
44

55
// Some options can have different values for `stdout`/`stderr`/`fd3`.
66
// This normalizes those to array of values.
@@ -91,6 +91,9 @@ const addDefaultValue = (optionArray, optionName) => optionArray.map(optionValue
9191
? DEFAULT_OPTIONS[optionName]
9292
: optionValue);
9393

94+
// Default value for the `verbose` option
95+
const verboseDefault = debuglog('execa').enabled ? 'full' : 'none';
96+
9497
const DEFAULT_OPTIONS = {
9598
lines: false,
9699
buffer: true,
@@ -101,3 +104,8 @@ const DEFAULT_OPTIONS = {
101104

102105
// List of options which can have different values for `stdout`/`stderr`
103106
export const FD_SPECIFIC_OPTIONS = ['lines', 'buffer', 'maxBuffer', 'verbose', 'stripFinalNewline'];
107+
108+
// Retrieve fd-specific option
109+
export const getFdSpecificValue = (optionArray, fdNumber) => fdNumber === 'ipc'
110+
? optionArray.at(-1)
111+
: optionArray[fdNumber];

lib/io/contents.js

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,19 @@ import {handleMaxBuffer} from './max-buffer.js';
77
import {getStripFinalNewline} from './strip-newline.js';
88

99
// Retrieve `result.stdout|stderr|all|stdio[*]`
10-
export const getStreamOutput = async ({stream, onStreamEnd, fdNumber, encoding, buffer, maxBuffer, lines, allMixed, stripFinalNewline, verboseInfo, streamInfo: {fileDescriptors}}) => {
11-
if (shouldLogOutput({
12-
stdioItems: fileDescriptors[fdNumber]?.stdioItems,
10+
export const getStreamOutput = async ({stream, onStreamEnd, fdNumber, encoding, buffer, maxBuffer, lines, allMixed, stripFinalNewline, verboseInfo, streamInfo}) => {
11+
const logPromise = logOutputAsync({
12+
stream,
13+
onStreamEnd,
14+
fdNumber,
1315
encoding,
16+
allMixed,
1417
verboseInfo,
15-
fdNumber,
16-
})) {
17-
const linesIterable = iterateForResult({
18-
stream,
19-
onStreamEnd,
20-
lines: true,
21-
encoding,
22-
stripFinalNewline: true,
23-
allMixed,
24-
});
25-
logLines(linesIterable, stream, verboseInfo);
26-
}
18+
streamInfo,
19+
});
2720

2821
if (!buffer) {
29-
await resumeStream(stream);
22+
await Promise.all([resumeStream(stream), logPromise]);
3023
return;
3124
}
3225

@@ -39,14 +32,39 @@ export const getStreamOutput = async ({stream, onStreamEnd, fdNumber, encoding,
3932
stripFinalNewline: stripFinalNewlineValue,
4033
allMixed,
4134
});
42-
return getStreamContents({
43-
stream,
44-
iterable,
35+
const [output] = await Promise.all([
36+
getStreamContents({
37+
stream,
38+
iterable,
39+
fdNumber,
40+
encoding,
41+
maxBuffer,
42+
lines,
43+
}),
44+
logPromise,
45+
]);
46+
return output;
47+
};
48+
49+
const logOutputAsync = async ({stream, onStreamEnd, fdNumber, encoding, allMixed, verboseInfo, streamInfo: {fileDescriptors}}) => {
50+
if (!shouldLogOutput({
51+
stdioItems: fileDescriptors[fdNumber]?.stdioItems,
52+
encoding,
53+
verboseInfo,
4554
fdNumber,
55+
})) {
56+
return;
57+
}
58+
59+
const linesIterable = iterateForResult({
60+
stream,
61+
onStreamEnd,
62+
lines: true,
4663
encoding,
47-
maxBuffer,
48-
lines,
64+
stripFinalNewline: true,
65+
allMixed,
4966
});
67+
await logLines(linesIterable, stream, verboseInfo);
5068
};
5169

5270
// When using `buffer: false`, users need to read `subprocess.stdout|stderr|all` right away

lib/io/max-buffer.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {MaxBufferError} from 'get-stream';
22
import {getStreamName} from '../utils/standard-stream.js';
3+
import {getFdSpecificValue} from '../arguments/specific.js';
34

45
// When the `maxBuffer` option is hit, a MaxBufferError is thrown.
56
// The stream is aborted, then specific information is kept for the error message.
@@ -59,11 +60,12 @@ const getMaxBufferInfo = (error, maxBuffer) => {
5960
const {maxBufferInfo: {fdNumber, unit}} = error;
6061
delete error.maxBufferInfo;
6162

63+
const threshold = getFdSpecificValue(maxBuffer, fdNumber);
6264
if (fdNumber === 'ipc') {
63-
return {streamName: 'IPC output', threshold: maxBuffer.at(-1), unit: 'messages'};
65+
return {streamName: 'IPC output', threshold, unit: 'messages'};
6466
}
6567

66-
return {streamName: getStreamName(fdNumber), threshold: maxBuffer[fdNumber], unit};
68+
return {streamName: getStreamName(fdNumber), threshold, unit};
6769
};
6870

6971
// The only way to apply `maxBuffer` with `spawnSync()` is to use the native `maxBuffer` option Node.js provides.

lib/io/output-sync.js

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,14 @@ const transformOutputResultSync = (
4848
fdNumber,
4949
});
5050

51-
if (shouldLogOutput({
52-
stdioItems,
53-
encoding,
54-
verboseInfo,
51+
logOutputSync({
52+
serializedResult,
5553
fdNumber,
56-
})) {
57-
const linesArray = splitLinesSync(serializedResult, false, objectMode);
58-
logLinesSync(linesArray, verboseInfo);
59-
}
54+
verboseInfo,
55+
encoding,
56+
stdioItems,
57+
objectMode,
58+
});
6059

6160
const returnedResult = buffer[fdNumber] ? finalResult : undefined;
6261

@@ -102,6 +101,20 @@ const serializeChunks = ({chunks, objectMode, encoding, lines, stripFinalNewline
102101
return {serializedResult};
103102
};
104103

104+
const logOutputSync = ({serializedResult, fdNumber, verboseInfo, encoding, stdioItems, objectMode}) => {
105+
if (!shouldLogOutput({
106+
stdioItems,
107+
encoding,
108+
verboseInfo,
109+
fdNumber,
110+
})) {
111+
return;
112+
}
113+
114+
const linesArray = splitLinesSync(serializedResult, false, objectMode);
115+
logLinesSync(linesArray, verboseInfo);
116+
};
117+
105118
// When the `std*` target is a file path/URL or a file descriptor
106119
const writeToFiles = (serializedResult, stdioItems, outputFiles) => {
107120
for (const {path} of stdioItems.filter(({type}) => FILE_TYPES.has(type))) {

lib/ipc/buffer-messages.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {checkIpcMaxBuffer} from '../io/max-buffer.js';
22
import {shouldLogIpc, logIpcOutput} from '../verbose/ipc.js';
3+
import {getFdSpecificValue} from '../arguments/specific.js';
34
import {loopOnMessages} from './get-each.js';
45

56
// Iterate through IPC messages sent by the subprocess
@@ -16,8 +17,8 @@ export const waitForIpcOutput = async ({
1617
}
1718

1819
const isVerbose = shouldLogIpc(verboseInfo);
19-
const buffer = bufferArray.at(-1);
20-
const maxBuffer = maxBufferArray.at(-1);
20+
const buffer = getFdSpecificValue(bufferArray, 'ipc');
21+
const maxBuffer = getFdSpecificValue(maxBufferArray, 'ipc');
2122

2223
for await (const message of loopOnMessages({
2324
anyProcess: subprocess,

lib/ipc/outgoing.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {createDeferred} from '../utils/deferred.js';
2+
import {getFdSpecificValue} from '../arguments/specific.js';
23
import {SUBPROCESS_OPTIONS} from '../arguments/fd-options.js';
34
import {validateStrictDeadlock} from './strict.js';
45

@@ -41,6 +42,6 @@ export const hasMessageListeners = (anyProcess, ipcEmitter) => ipcEmitter.listen
4142
// When `buffer` is `false`, we set up a `message` listener that should be ignored.
4243
// That listener is only meant to intercept `strict` acknowledgement responses.
4344
const getMinListenerCount = anyProcess => SUBPROCESS_OPTIONS.has(anyProcess)
44-
&& !SUBPROCESS_OPTIONS.get(anyProcess).options.buffer.at(-1)
45+
&& !getFdSpecificValue(SUBPROCESS_OPTIONS.get(anyProcess).options.buffer, 'ipc')
4546
? 1
4647
: 0;

lib/return/reject.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {logFinalResult} from '../verbose/complete.js';
33
// Applies the `reject` option.
44
// Also print the final log line with `verbose`.
55
export const handleResult = (result, verboseInfo, {reject}) => {
6-
logFinalResult(result, reject, verboseInfo);
6+
logFinalResult(result, verboseInfo);
77

88
if (result.failed && reject) {
99
throw result;

lib/stdio/handle.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {filterDuplicates, getDuplicateStream} from './duplicate.js';
1717
// They are converted into an array of `fileDescriptors`.
1818
// Each `fileDescriptor` is normalized, validated and contains all information necessary for further handling.
1919
export const handleStdio = (addProperties, options, verboseInfo, isSync) => {
20-
const stdio = normalizeStdioOption(options, isSync);
20+
const stdio = normalizeStdioOption(options, verboseInfo, isSync);
2121
const initialFileDescriptors = stdio.map((stdioOption, fdNumber) => getFileDescriptor({
2222
stdioOption,
2323
fdNumber,

lib/stdio/stdio-option.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import {STANDARD_STREAMS_ALIASES} from '../utils/standard-stream.js';
22
import {normalizeIpcStdioArray} from '../ipc/array.js';
3+
import {isFullVerbose} from '../verbose/info.js';
34

45
// Add support for `stdin`/`stdout`/`stderr` as an alias for `stdio`.
56
// Also normalize the `stdio` option.
6-
export const normalizeStdioOption = ({stdio, ipc, buffer, verbose, ...options}, isSync) => {
7+
export const normalizeStdioOption = ({stdio, ipc, buffer, ...options}, verboseInfo, isSync) => {
78
const stdioArray = getStdioArray(stdio, options).map((stdioOption, fdNumber) => addDefaultValue(stdioOption, fdNumber));
89
return isSync
9-
? normalizeStdioSync(stdioArray, buffer, verbose)
10+
? normalizeStdioSync(stdioArray, buffer, verboseInfo)
1011
: normalizeIpcStdioArray(stdioArray, ipc);
1112
};
1213

@@ -47,10 +48,10 @@ const addDefaultValue = (stdioOption, fdNumber) => {
4748

4849
// Using `buffer: false` with synchronous methods implies `stdout`/`stderr`: `ignore`.
4950
// Unless the output is needed, e.g. due to `verbose: 'full'` or to redirecting to a file.
50-
const normalizeStdioSync = (stdioArray, buffer, verbose) => stdioArray.map((stdioOption, fdNumber) =>
51+
const normalizeStdioSync = (stdioArray, buffer, verboseInfo) => stdioArray.map((stdioOption, fdNumber) =>
5152
!buffer[fdNumber]
5253
&& fdNumber !== 0
53-
&& verbose[fdNumber] !== 'full'
54+
&& !isFullVerbose(verboseInfo, fdNumber)
5455
&& isOutputPipeOnly(stdioOption)
5556
? 'ignore'
5657
: stdioOption);

0 commit comments

Comments
 (0)