@laurence79/wireit 0.14.13-shared-cache.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +1062 -0
- package/bin/wireit.js +9 -0
- package/lib/analyzer.js +1600 -0
- package/lib/caching/cache.js +7 -0
- package/lib/caching/github-actions-cache.js +832 -0
- package/lib/caching/local-cache.js +78 -0
- package/lib/caching/shared-cache.js +256 -0
- package/lib/cli-options.js +495 -0
- package/lib/cli.js +177 -0
- package/lib/config.js +18 -0
- package/lib/error.js +160 -0
- package/lib/event.js +7 -0
- package/lib/execution/base.js +108 -0
- package/lib/execution/no-command.js +32 -0
- package/lib/execution/service.js +1017 -0
- package/lib/execution/standard.js +683 -0
- package/lib/executor.js +249 -0
- package/lib/fingerprint.js +164 -0
- package/lib/ide.js +583 -0
- package/lib/language-server.js +135 -0
- package/lib/logging/combination-logger.js +41 -0
- package/lib/logging/debug-logger.js +43 -0
- package/lib/logging/logger.js +38 -0
- package/lib/logging/metrics-logger.js +108 -0
- package/lib/logging/quiet/run-tracker.js +597 -0
- package/lib/logging/quiet/stack-map.js +41 -0
- package/lib/logging/quiet/writeover-line.js +197 -0
- package/lib/logging/quiet-logger.js +78 -0
- package/lib/logging/simple-logger.js +296 -0
- package/lib/logging/watch-logger.js +81 -0
- package/lib/script-child-process.js +270 -0
- package/lib/util/ast.js +71 -0
- package/lib/util/async-cache.js +24 -0
- package/lib/util/copy.js +120 -0
- package/lib/util/deferred.js +35 -0
- package/lib/util/delete.js +120 -0
- package/lib/util/dispose.js +16 -0
- package/lib/util/fs.js +258 -0
- package/lib/util/glob.js +255 -0
- package/lib/util/line-monitor.js +69 -0
- package/lib/util/manifest.js +31 -0
- package/lib/util/optimize-mkdirs.js +55 -0
- package/lib/util/package-json-reader.js +61 -0
- package/lib/util/package-json.js +179 -0
- package/lib/util/script-data-dir.js +19 -0
- package/lib/util/shuffle.js +16 -0
- package/lib/util/unreachable.js +12 -0
- package/lib/util/windows.js +87 -0
- package/lib/util/worker-pool.js +61 -0
- package/lib/watcher.js +396 -0
- package/package.json +470 -0
- package/schema.json +132 -0
- package/wireit.svg +1 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2023 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { DEBUG } from '../logger.js';
|
|
7
|
+
import '../../util/dispose.js';
|
|
8
|
+
// To prevent using the global console accidentally, we shadow it with
|
|
9
|
+
// undefined
|
|
10
|
+
const console = undefined;
|
|
11
|
+
function markAsUsed(_) { }
|
|
12
|
+
markAsUsed(console);
|
|
13
|
+
class BaseWriteoverLine {
|
|
14
|
+
#updateInterval;
|
|
15
|
+
#disposed;
|
|
16
|
+
constructor(console) {
|
|
17
|
+
this._line = '';
|
|
18
|
+
this._targetFps = 60;
|
|
19
|
+
/**
|
|
20
|
+
* If true, we write over the previous line with a \r carriage return,
|
|
21
|
+
* otherwise we write a new line.
|
|
22
|
+
*/
|
|
23
|
+
this._writeOver = !DEBUG;
|
|
24
|
+
this.#disposed = false;
|
|
25
|
+
this.#previousLineLength = 0;
|
|
26
|
+
this.console = console;
|
|
27
|
+
}
|
|
28
|
+
clearAndStopRendering() {
|
|
29
|
+
// Writeover the previous line and cancel the spinner interval.
|
|
30
|
+
if (this.#updateInterval !== undefined) {
|
|
31
|
+
clearInterval(this.#updateInterval);
|
|
32
|
+
this.#updateInterval = undefined;
|
|
33
|
+
}
|
|
34
|
+
if (this._line !== '') {
|
|
35
|
+
this._line = '';
|
|
36
|
+
this._writeLine('');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
#previousLineLength;
|
|
40
|
+
_writeLine(line) {
|
|
41
|
+
if (!this._writeOver) {
|
|
42
|
+
if (line === '') {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
this.console.stderr.write(line);
|
|
46
|
+
this.console.stderr.write('\n');
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
this.console.stderr.write(line);
|
|
50
|
+
const overflow = this.#previousLineLength - line.length;
|
|
51
|
+
if (overflow > 0) {
|
|
52
|
+
this.console.stderr.write(' '.repeat(overflow));
|
|
53
|
+
}
|
|
54
|
+
this.console.stderr.write('\r');
|
|
55
|
+
this.#previousLineLength = line.length;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Clears the line and stops the spinner, and returns a Disposable that, once
|
|
59
|
+
* disposed, will restore the line and restart the spinner (if the spinner
|
|
60
|
+
* was going when clearUntilDisposed() was called).
|
|
61
|
+
*
|
|
62
|
+
* Note that we don't expect writeoverLine.writeLine to be called while the
|
|
63
|
+
* Disposable is active, so we don't handle that case. We could, it just
|
|
64
|
+
* hasn't come up yet. We'd need to have an instance variable to count how
|
|
65
|
+
* many active Disposables there are, and only restore the line and restart
|
|
66
|
+
* the spinner when the last one is disposed. We'd also need to short circuit
|
|
67
|
+
* the logic in writeLine, and set aside the latest line to be written.
|
|
68
|
+
*
|
|
69
|
+
* Use like:
|
|
70
|
+
*
|
|
71
|
+
* {
|
|
72
|
+
* using _pause = writeoverLine.clearUntilDisposed();
|
|
73
|
+
* // console.log, write to stdout and stderr, etc
|
|
74
|
+
* }
|
|
75
|
+
* // once the block ends, the writeoverLine is restored
|
|
76
|
+
*/
|
|
77
|
+
clearUntilDisposed() {
|
|
78
|
+
// already cleared, nothing to do
|
|
79
|
+
if (this.#updateInterval === undefined) {
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
const line = this._line;
|
|
83
|
+
this.clearAndStopRendering();
|
|
84
|
+
return {
|
|
85
|
+
[Symbol.dispose]: () => {
|
|
86
|
+
this.updateStatusLine(line);
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
updateStatusLine(line) {
|
|
91
|
+
if (this.#disposed) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (DEBUG) {
|
|
95
|
+
if (this._line !== line) {
|
|
96
|
+
// Ensure that every line is written immediately in debug mode
|
|
97
|
+
this.console.stderr.write(` ${line}\n`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
this._line = line;
|
|
101
|
+
if (line === '') {
|
|
102
|
+
// Writeover the previous line and cancel the spinner interval.
|
|
103
|
+
if (this.#updateInterval !== undefined) {
|
|
104
|
+
clearInterval(this.#updateInterval);
|
|
105
|
+
this.#updateInterval = undefined;
|
|
106
|
+
}
|
|
107
|
+
this._writeLine('');
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
if (this.#updateInterval !== undefined) {
|
|
111
|
+
// will render on next frame
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
// render now, and then schedule future renders.
|
|
115
|
+
if (!DEBUG) {
|
|
116
|
+
this._update();
|
|
117
|
+
}
|
|
118
|
+
// schedule future renders so the spinner stays going
|
|
119
|
+
this.#updateInterval = setInterval(() => {
|
|
120
|
+
if (DEBUG) {
|
|
121
|
+
// We want to schedule an interval even in debug mode, so that tests
|
|
122
|
+
// will still fail if we don't clean it up properly, but we don't want
|
|
123
|
+
// to actually render anything here, since we render any new line
|
|
124
|
+
// the moment it comes in.
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
this._update();
|
|
128
|
+
}, 1000 / this._targetFps);
|
|
129
|
+
}
|
|
130
|
+
[Symbol.dispose]() {
|
|
131
|
+
this.#disposed = true;
|
|
132
|
+
this.clearAndStopRendering();
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Handles displaying a single line of status text, overwriting the previously
|
|
137
|
+
* written line, and displaying a spinner to indicate liveness.
|
|
138
|
+
*/
|
|
139
|
+
export class WriteoverLine extends BaseWriteoverLine {
|
|
140
|
+
#spinner = new Spinner();
|
|
141
|
+
#previouslyWrittenLine = undefined;
|
|
142
|
+
_update() {
|
|
143
|
+
if (this._line === this.#previouslyWrittenLine) {
|
|
144
|
+
// just write over the spinner
|
|
145
|
+
this.console.stderr.write(this.#spinner.nextFrame);
|
|
146
|
+
this.console.stderr.write('\r');
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
this.#previouslyWrittenLine = this._line;
|
|
150
|
+
this._writeLine(`${this.#spinner.nextFrame} ${this._line}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Like WriteoverLine, but it updates much less frequently, just prints lines
|
|
155
|
+
* rather doing fancy writeover, doesn't draw a spinner, and stays silent
|
|
156
|
+
* if the status line line hasn't changed.
|
|
157
|
+
*/
|
|
158
|
+
export class CiWriter extends BaseWriteoverLine {
|
|
159
|
+
constructor(console) {
|
|
160
|
+
super(console);
|
|
161
|
+
this.previousLine = '';
|
|
162
|
+
// Don't write too much, no need to flood the CI logs.
|
|
163
|
+
this._targetFps = 1;
|
|
164
|
+
// GitHub seems to handle \r carraige returns the same as \n, but
|
|
165
|
+
// we don't want to rely on that. Just print status lines on new lines.
|
|
166
|
+
this._writeOver = false;
|
|
167
|
+
}
|
|
168
|
+
_update() {
|
|
169
|
+
if (this._line === this.previousLine) {
|
|
170
|
+
// nothing new to log
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
this.previousLine = this._line;
|
|
174
|
+
this._writeLine(this._line);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const spinnerFrames = [
|
|
178
|
+
'⠋',
|
|
179
|
+
'⠙',
|
|
180
|
+
'⠹',
|
|
181
|
+
'⠸',
|
|
182
|
+
'⠼',
|
|
183
|
+
'⠴',
|
|
184
|
+
'⠦',
|
|
185
|
+
'⠧',
|
|
186
|
+
'⠇',
|
|
187
|
+
'⠏',
|
|
188
|
+
];
|
|
189
|
+
class Spinner {
|
|
190
|
+
#frame = 0;
|
|
191
|
+
get nextFrame() {
|
|
192
|
+
const frame = spinnerFrames[this.#frame];
|
|
193
|
+
this.#frame = (this.#frame + 1) % spinnerFrames.length;
|
|
194
|
+
return frame;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=writeover-line.js.map
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2023 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { CiWriter, WriteoverLine, } from './quiet/writeover-line.js';
|
|
7
|
+
import { QuietRunLogger, noChange, nothing } from './quiet/run-tracker.js';
|
|
8
|
+
// To prevent using the global console accidentally, we shadow it with
|
|
9
|
+
// undefined
|
|
10
|
+
const console = undefined;
|
|
11
|
+
function markAsUsed(_) { }
|
|
12
|
+
markAsUsed(console);
|
|
13
|
+
/**
|
|
14
|
+
* A {@link Logger} that prints less to the console.
|
|
15
|
+
*
|
|
16
|
+
* While running, it prints a single line of status text with information about
|
|
17
|
+
* how the run is progressing, as well as emitting errors as they happen,
|
|
18
|
+
* and any output from services or the root script.
|
|
19
|
+
*
|
|
20
|
+
* When the run is complete, it prints a one line summary of the results.
|
|
21
|
+
*/
|
|
22
|
+
export class QuietLogger {
|
|
23
|
+
#runTracker;
|
|
24
|
+
#rootPackage;
|
|
25
|
+
#statusLineWriter;
|
|
26
|
+
constructor(rootPackage, ourConsole, statusLineWriter) {
|
|
27
|
+
this.#rootPackage = rootPackage;
|
|
28
|
+
this.#statusLineWriter = statusLineWriter ?? new WriteoverLine(ourConsole);
|
|
29
|
+
this.#runTracker = new QuietRunLogger(this.#rootPackage, this.#statusLineWriter, ourConsole);
|
|
30
|
+
this.console = ourConsole;
|
|
31
|
+
}
|
|
32
|
+
printMetrics() {
|
|
33
|
+
this.#statusLineWriter.clearAndStopRendering();
|
|
34
|
+
this.#runTracker.printSummary();
|
|
35
|
+
}
|
|
36
|
+
log(event) {
|
|
37
|
+
if (event.type === 'info' && event.detail === 'watch-run-start') {
|
|
38
|
+
this.#runTracker = this.#runTracker.makeInstanceForNextWatchRun();
|
|
39
|
+
}
|
|
40
|
+
const line = this.#runTracker.getUpdatedMessageAfterEvent(event);
|
|
41
|
+
if (line === noChange) {
|
|
42
|
+
// nothing to do
|
|
43
|
+
}
|
|
44
|
+
else if (line === nothing) {
|
|
45
|
+
this.#statusLineWriter.clearAndStopRendering();
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
this.#statusLineWriter.updateStatusLine(line);
|
|
49
|
+
}
|
|
50
|
+
if (event.type === 'info' && event.detail === 'watch-run-end') {
|
|
51
|
+
this.printMetrics();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
getWatchLogger() {
|
|
55
|
+
// QuietLogger doesn't need the screen-clearning behavior of the watch
|
|
56
|
+
// logger, since in successful cases it only prints one line of output,
|
|
57
|
+
// and in failure cases it can be nice to keep the old output around.
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
[Symbol.dispose]() {
|
|
61
|
+
this.#statusLineWriter[Symbol.dispose]();
|
|
62
|
+
this.#runTracker[Symbol.dispose]();
|
|
63
|
+
this.console[Symbol.dispose]();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* A QuietLogger that is intended to be used in CI environments and other
|
|
68
|
+
* non-interactive environments.
|
|
69
|
+
*
|
|
70
|
+
* Doesn't use a spinner, updates less often, and doesn't use '/r' to writeover
|
|
71
|
+
* the previous line.
|
|
72
|
+
*/
|
|
73
|
+
export class QuietCiLogger extends QuietLogger {
|
|
74
|
+
constructor(rootPackage, ourConsole) {
|
|
75
|
+
super(rootPackage, ourConsole, new CiWriter(ourConsole));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=quiet-logger.js.map
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import * as pathlib from 'path';
|
|
7
|
+
import { unreachable } from '../util/unreachable.js';
|
|
8
|
+
import { DiagnosticPrinter } from '../error.js';
|
|
9
|
+
import { createRequire } from 'module';
|
|
10
|
+
import { WatchLogger } from './watch-logger.js';
|
|
11
|
+
const getWireitVersion = (() => {
|
|
12
|
+
let version;
|
|
13
|
+
return () => {
|
|
14
|
+
if (version === undefined) {
|
|
15
|
+
version = createRequire(import.meta.url)('../../package.json').version;
|
|
16
|
+
}
|
|
17
|
+
return version;
|
|
18
|
+
};
|
|
19
|
+
})();
|
|
20
|
+
// To prevent using the global console accidentally, we shadow it with
|
|
21
|
+
// undefined
|
|
22
|
+
const console = undefined;
|
|
23
|
+
function markAsUsed(_) { }
|
|
24
|
+
markAsUsed(console);
|
|
25
|
+
/**
|
|
26
|
+
* Simple {@link Logger} which logs to stdout and stderr.
|
|
27
|
+
*/
|
|
28
|
+
export class SimpleLogger {
|
|
29
|
+
#rootPackageDir;
|
|
30
|
+
#diagnosticPrinter;
|
|
31
|
+
/**
|
|
32
|
+
* @param rootPackage The npm package directory that the root script being
|
|
33
|
+
* executed belongs to.
|
|
34
|
+
*/
|
|
35
|
+
constructor(rootPackage, ourConsole) {
|
|
36
|
+
this.#rootPackageDir = rootPackage;
|
|
37
|
+
this.#diagnosticPrinter = new DiagnosticPrinter(this.#rootPackageDir);
|
|
38
|
+
this.console = ourConsole;
|
|
39
|
+
}
|
|
40
|
+
log(event) {
|
|
41
|
+
const type = event.type;
|
|
42
|
+
const label = labelForScript(this.#rootPackageDir, event.script);
|
|
43
|
+
const prefix = label !== '' ? ` [${label}]` : '';
|
|
44
|
+
switch (type) {
|
|
45
|
+
default: {
|
|
46
|
+
throw new Error(`Unknown event type: ${unreachable(type)}`);
|
|
47
|
+
}
|
|
48
|
+
case 'success': {
|
|
49
|
+
const reason = event.reason;
|
|
50
|
+
switch (reason) {
|
|
51
|
+
default: {
|
|
52
|
+
throw new Error(`Unknown success reason: ${unreachable(reason)}`);
|
|
53
|
+
}
|
|
54
|
+
case 'exit-zero': {
|
|
55
|
+
this.console.log(`✅${prefix} Executed successfully`);
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
case 'no-command': {
|
|
59
|
+
this.console.log(`✅${prefix} No command to execute`);
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
case 'fresh': {
|
|
63
|
+
this.console.log(`✅${prefix} Already fresh`);
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
case 'cached': {
|
|
67
|
+
this.console.log(`✅${prefix} Restored from cache`);
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
case 'failure': {
|
|
74
|
+
if (event.logged) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
event.logged = true;
|
|
78
|
+
const reason = event.reason;
|
|
79
|
+
switch (reason) {
|
|
80
|
+
default: {
|
|
81
|
+
throw new Error(`Unknown failure reason: ${unreachable(reason)}`);
|
|
82
|
+
}
|
|
83
|
+
case 'launched-incorrectly': {
|
|
84
|
+
this.console.error(`❌${prefix} wireit must be launched with "npm run" or a compatible command.`);
|
|
85
|
+
this.console.error(` More info: ${event.detail}`);
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
case 'missing-package-json': {
|
|
89
|
+
this.console.error(`❌${prefix} No package.json was found in ${event.script.packageDir}`);
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
case 'invalid-json-syntax': {
|
|
93
|
+
for (const diagnostic of event.diagnostics) {
|
|
94
|
+
this.console.error(this.#diagnosticPrinter.print(diagnostic));
|
|
95
|
+
}
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
case 'no-scripts-in-package-json': {
|
|
99
|
+
this.console.error(`❌${prefix} No "scripts" section defined in package.json in ${event.script.packageDir}`);
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
case 'script-not-found':
|
|
103
|
+
case 'wireit-config-but-no-script':
|
|
104
|
+
case 'duplicate-dependency':
|
|
105
|
+
case 'script-not-wireit':
|
|
106
|
+
case 'invalid-config-syntax':
|
|
107
|
+
case 'cycle':
|
|
108
|
+
case 'dependency-on-missing-package-json':
|
|
109
|
+
case 'dependency-on-missing-script': {
|
|
110
|
+
this.console.error(this.#diagnosticPrinter.print(event.diagnostic));
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
case 'invalid-usage': {
|
|
114
|
+
this.console.error(`❌${prefix} Invalid usage: ${event.message}`);
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
case 'exit-non-zero': {
|
|
118
|
+
this.console.error(`❌${prefix} Failed with exit status ${event.status}`);
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
case 'signal': {
|
|
122
|
+
this.console.error(`❌${prefix} Failed with signal ${event.signal}`);
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
case 'spawn-error': {
|
|
126
|
+
this.console.error(`❌${prefix} Process spawn error: ${event.message}`);
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
case 'start-cancelled': {
|
|
130
|
+
// The script never started. We don't really need to log this, it's
|
|
131
|
+
// fairly noisy. Maybe in a verbose mode.
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
case 'failed-previous-watch-iteration': {
|
|
135
|
+
this.console.error(`❌${prefix} Failed on previous watch iteration`);
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
case 'killed': {
|
|
139
|
+
this.console.error(`💀${prefix} Killed`);
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
case 'unknown-error-thrown': {
|
|
143
|
+
this.console.error(`❌${prefix} Internal error! Please file a bug at https://github.com/google/wireit/issues/new, mention this message, that you encountered it in wireit version ${getWireitVersion()}, and give information about your package.json files.\n Unknown error thrown: ${String(event.error)}`);
|
|
144
|
+
const maybeError = event.error;
|
|
145
|
+
if (maybeError?.stack) {
|
|
146
|
+
this.console.error(maybeError.stack);
|
|
147
|
+
}
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
case 'dependency-invalid': {
|
|
151
|
+
this.console.error(`❌${prefix} Depended, perhaps indirectly, on ${labelForScript(this.#rootPackageDir, event.dependency)} which could not be validated. Please file a bug at https://github.com/google/wireit/issues/new, mention this message, that you encountered it in wireit version ${getWireitVersion()}, and give information about your package.json files.`);
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
case 'service-exited-unexpectedly': {
|
|
155
|
+
this.console.error(`❌${prefix} Service exited unexpectedly`);
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
case 'input-file-deleted-unexpectedly': {
|
|
159
|
+
for (const filePath of event.filePaths) {
|
|
160
|
+
this.console.error(`❌${prefix} Input file "${filePath}" was deleted unexpectedly. Is another process writing to the same location?`);
|
|
161
|
+
}
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
case 'output-file-deleted-unexpectedly': {
|
|
165
|
+
for (const filePath of event.filePaths) {
|
|
166
|
+
this.console.error(`❌${prefix} Output file "${filePath}" was deleted unexpectedly. Is another process writing to the same location?`);
|
|
167
|
+
}
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
case 'aborted':
|
|
171
|
+
case 'dependency-service-exited-unexpectedly': {
|
|
172
|
+
// These event isn't very useful to log, because they are downstream
|
|
173
|
+
// of failures that already get reported elsewhere.
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
case 'output': {
|
|
180
|
+
const stream = event.stream;
|
|
181
|
+
switch (stream) {
|
|
182
|
+
default: {
|
|
183
|
+
throw new Error(`Unknown output stream: ${unreachable(stream)}`);
|
|
184
|
+
}
|
|
185
|
+
// TODO(aomarks) More advanced handling of output streams so that
|
|
186
|
+
// output isn't simply interweaved.
|
|
187
|
+
case 'stdout': {
|
|
188
|
+
this.console.stdout.write(event.data);
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
case 'stderr': {
|
|
192
|
+
this.console.stderr.write(event.data);
|
|
193
|
+
break;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
break;
|
|
197
|
+
}
|
|
198
|
+
case 'info': {
|
|
199
|
+
const detail = event.detail;
|
|
200
|
+
switch (detail) {
|
|
201
|
+
default: {
|
|
202
|
+
throw new Error(`Unknown info event detail: ${unreachable(detail)}`);
|
|
203
|
+
}
|
|
204
|
+
case 'running': {
|
|
205
|
+
this.console.log(`🏃${prefix} Running command "${event.script.command?.value ?? ''}"`);
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
case 'locked': {
|
|
209
|
+
this.console.log(`💤${prefix} Waiting for another process which is already running this script.`);
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
case 'output-modified': {
|
|
213
|
+
this.console.log(`ℹ️${prefix} Output files were modified since the previous run.`);
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
case 'watch-run-start': {
|
|
217
|
+
if (process.stdout.isTTY) {
|
|
218
|
+
// If we are in an interactive terminal (TTY), reset it before
|
|
219
|
+
// each run. This is helpful because it means only the output for
|
|
220
|
+
// the current build is visible. This is exactly the same as what
|
|
221
|
+
// "tsc --watch" does.
|
|
222
|
+
//
|
|
223
|
+
// This string is the ESC character (ASCII \x1B) followed by "c",
|
|
224
|
+
// which is the VT100 reset sequence, supported by most terminals:
|
|
225
|
+
// https://www2.ccs.neu.edu/research/gpc/VonaUtils/vona/terminal/vtansi.htm#:~:text=Reset%20Device
|
|
226
|
+
this.console.log('\x1Bc');
|
|
227
|
+
}
|
|
228
|
+
break;
|
|
229
|
+
}
|
|
230
|
+
case 'watch-run-end': {
|
|
231
|
+
this.console.log(`👀${prefix} Watching for file changes`);
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
case 'cache-info': {
|
|
235
|
+
this.console.log(`ℹ️${prefix} ${event.message}`);
|
|
236
|
+
break;
|
|
237
|
+
}
|
|
238
|
+
case 'service-process-started': {
|
|
239
|
+
this.console.log(`⬆️${prefix} Service starting...`);
|
|
240
|
+
break;
|
|
241
|
+
}
|
|
242
|
+
case 'service-ready': {
|
|
243
|
+
this.console.log(`⬆️${prefix} Service ready`);
|
|
244
|
+
break;
|
|
245
|
+
}
|
|
246
|
+
case 'service-stopped': {
|
|
247
|
+
this.console.log(`⬇️${prefix} Service stopped`);
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
250
|
+
case 'analysis-started':
|
|
251
|
+
case 'analysis-completed': {
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
printMetrics() {
|
|
259
|
+
// printMetrics() not used in default-logger.
|
|
260
|
+
}
|
|
261
|
+
getWatchLogger() {
|
|
262
|
+
return new WatchLogger(this);
|
|
263
|
+
}
|
|
264
|
+
[Symbol.dispose]() {
|
|
265
|
+
this.console[Symbol.dispose]();
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Make a concise label for a script, or for just a package if we don't know
|
|
270
|
+
* the script name. If the package is different to the root package, it is
|
|
271
|
+
* disambiguated with a relative path.
|
|
272
|
+
*/
|
|
273
|
+
export function labelForScript(rootPackageDir, script) {
|
|
274
|
+
const packageDir = script.packageDir;
|
|
275
|
+
const scriptName = 'name' in script ? script.name : undefined;
|
|
276
|
+
if (packageDir !== rootPackageDir) {
|
|
277
|
+
const relativePackageDir = pathlib
|
|
278
|
+
.relative(rootPackageDir, script.packageDir)
|
|
279
|
+
// Normalize to posix-style forward-slashes as the path separator, even
|
|
280
|
+
// on Windows which usually uses back-slashes. This way labels match the
|
|
281
|
+
// syntax used in the package.json dependency specifiers (which are
|
|
282
|
+
// already posix style).
|
|
283
|
+
.replace(pathlib.sep, pathlib.posix.sep);
|
|
284
|
+
if (scriptName !== undefined) {
|
|
285
|
+
return `${relativePackageDir}:${scriptName}`;
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
return relativePackageDir;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
else if (scriptName !== undefined) {
|
|
292
|
+
return scriptName;
|
|
293
|
+
}
|
|
294
|
+
return '';
|
|
295
|
+
}
|
|
296
|
+
//# sourceMappingURL=simple-logger.js.map
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2023 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
// To prevent using the global console accidentally, we shadow it with
|
|
7
|
+
// undefined
|
|
8
|
+
const console = undefined;
|
|
9
|
+
function markAsUsed(_) { }
|
|
10
|
+
markAsUsed(console);
|
|
11
|
+
/**
|
|
12
|
+
* A logger for watch mode that avoids useless output.
|
|
13
|
+
*/
|
|
14
|
+
export class WatchLogger {
|
|
15
|
+
#actualLogger;
|
|
16
|
+
#iterationBuffer = [];
|
|
17
|
+
#iterationIsInteresting = /* The first iteration is always interesting. */ true;
|
|
18
|
+
constructor(actualLogger) {
|
|
19
|
+
this.#actualLogger = actualLogger;
|
|
20
|
+
this.console = actualLogger.console;
|
|
21
|
+
}
|
|
22
|
+
log(event) {
|
|
23
|
+
if (this.#iterationIsInteresting) {
|
|
24
|
+
// This iteration previously had an interesting event (or it's the very
|
|
25
|
+
// first one, which we always show).
|
|
26
|
+
this.#actualLogger.log(event);
|
|
27
|
+
this.#actualLogger.printMetrics();
|
|
28
|
+
if (this.#isWatchRunEnd(event)) {
|
|
29
|
+
this.#iterationIsInteresting = false;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
else if (this.#isWatchRunEnd(event)) {
|
|
33
|
+
// We finished a watch iteration and nothing interesting ever happened.
|
|
34
|
+
// Discard the buffer.
|
|
35
|
+
this.#iterationBuffer.length = 0;
|
|
36
|
+
}
|
|
37
|
+
else if (this.#isInteresting(event)) {
|
|
38
|
+
// The first interesting event of the iteration. Flush the buffer and log
|
|
39
|
+
// everything from now until the next iteration.
|
|
40
|
+
while (this.#iterationBuffer.length > 0) {
|
|
41
|
+
this.#actualLogger.log(this.#iterationBuffer.shift());
|
|
42
|
+
}
|
|
43
|
+
this.#actualLogger.log(event);
|
|
44
|
+
this.#iterationIsInteresting = true;
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
// An uninteresting event in a thus far uninteresting iteration.
|
|
48
|
+
this.#iterationBuffer.push(event);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
printMetrics() {
|
|
52
|
+
// printMetrics() not used in watch-logger.
|
|
53
|
+
}
|
|
54
|
+
#isInteresting(event) {
|
|
55
|
+
const code = event.type === 'output'
|
|
56
|
+
? event.stream
|
|
57
|
+
: event.type === 'info'
|
|
58
|
+
? event.detail
|
|
59
|
+
: event.reason;
|
|
60
|
+
switch (code) {
|
|
61
|
+
case 'fresh':
|
|
62
|
+
case 'no-command':
|
|
63
|
+
case 'failed-previous-watch-iteration':
|
|
64
|
+
case 'watch-run-start':
|
|
65
|
+
case 'start-cancelled':
|
|
66
|
+
case 'locked':
|
|
67
|
+
case 'analysis-completed': {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
#isWatchRunEnd(event) {
|
|
74
|
+
return event.type === 'info' && event.detail === 'watch-run-end';
|
|
75
|
+
}
|
|
76
|
+
[Symbol.dispose]() {
|
|
77
|
+
this.#actualLogger[Symbol.dispose]();
|
|
78
|
+
this.console[Symbol.dispose]();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=watch-logger.js.map
|