-
Notifications
You must be signed in to change notification settings - Fork 618
/
Copy pathStdioSummarizer.ts
134 lines (118 loc) · 4.28 KB
/
StdioSummarizer.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.
import { type ITerminalChunk, TerminalChunkKind } from './ITerminalChunk';
import { type ITerminalWritableOptions, TerminalWritable } from './TerminalWritable';
/**
* Constructor options for {@link StdioSummarizer}.
* @beta
*/
export interface IStdioSummarizerOptions extends ITerminalWritableOptions {
/**
* Specifies the maximum number of leading lines to include in the summary.
* @defaultValue `10`
*/
leadingLines?: number;
/**
* Specifies the maximum number of trailing lines to include in the summary.
* @defaultValue `10`
*/
trailingLines?: number;
}
/**
* Summarizes the results of a failed build task by returning a subset of `stderr` output not to exceed
* a specified maximum number of lines.
*
* @remarks
* IMPORTANT: This transform assumes that its input was prepared by {@link StderrLineTransform}, so that each
* {@link ITerminalChunk.text} item is a single line terminated by a `"\n"` character.
*
* The {@link IStdioSummarizerOptions.leadingLines} and {@link IStdioSummarizerOptions.trailingLines}
* counts specify the maximum number of lines to be returned. Any additional lines will be omitted.
* For example, if `leadingLines` and `trailingLines` were set to `3`, then the summary of 16 `stderr` lines might
* look like this:
*
* ```
* Line 1
* Line 2
* Line 3
* ...10 lines omitted...
* Line 14
* Line 15
* Line 16
* ```
*
* If the `stderr` output is completely empty, then the `stdout` output will be summarized instead.
*
* @beta
*/
export class StdioSummarizer extends TerminalWritable {
// Capture up to this many leading lines
private _leadingLines: number;
// Capture up to this many trailing lines
private _trailingLines: number;
private readonly _abridgedLeading: string[];
private readonly _abridgedTrailing: string[];
private _abridgedOmittedLines: number = 0;
private _abridgedStderr: boolean;
public constructor(options?: IStdioSummarizerOptions) {
super(options);
if (!options) {
options = {};
}
this._leadingLines = options.leadingLines !== undefined ? options.leadingLines : 10;
this._trailingLines = options.trailingLines !== undefined ? options.trailingLines : 10;
this._abridgedLeading = [];
this._abridgedTrailing = [];
this._abridgedStderr = false;
}
/**
* Returns the summary report.
*
* @remarks
* The `close()` method must be called before `getReport()` can be used.
*/
public getReport(): string {
if (this.isOpen) {
throw new Error('The summary cannot be prepared until after close() is called.');
}
const report: string[] = [...this._abridgedLeading];
if (this._abridgedOmittedLines === 1) {
report.push(` ...${this._abridgedOmittedLines} line omitted...\n`);
}
if (this._abridgedOmittedLines > 1) {
report.push(` ...${this._abridgedOmittedLines} lines omitted...\n`);
}
report.push(...this._abridgedTrailing);
return report.join('');
}
public onWriteChunk(chunk: ITerminalChunk): void {
if (chunk.text.length === 0 || chunk.text[chunk.text.length - 1] !== '\n') {
throw new Error(
'StdioSummarizer expects chunks that were separated parsed into lines by StderrLineTransform\n' +
' Invalid input: ' +
JSON.stringify(chunk.text)
);
}
if (chunk.kind === TerminalChunkKind.Stderr && !this._abridgedStderr) {
// The first time we see stderr, switch to capturing stderr
this._abridgedStderr = true;
this._abridgedLeading.length = 0;
this._abridgedTrailing.length = 0;
this._abridgedOmittedLines = 0;
} else if (this._abridgedStderr && chunk.kind !== TerminalChunkKind.Stderr) {
// If we're capturing stderr, then ignore non-stderr input
return;
}
// Did we capture enough leading lines?
if (this._abridgedLeading.length < this._leadingLines) {
this._abridgedLeading.push(chunk.text);
return;
}
this._abridgedTrailing.push(chunk.text);
// If we captured to many trailing lines, omit the extras
while (this._abridgedTrailing.length > this._trailingLines) {
this._abridgedTrailing.shift();
++this._abridgedOmittedLines;
}
}
}