Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit d65c7e4

Browse files
Small improvements to et lint command (#51372)
- Default to dumping out lint logs (can be disabled with `--quiet` flag). - Add Logger.fatal which logs an error and throws a FatalError which is caught in main. - Simplify `findDartBinDirectory` implementation. - Make JSON serialized process artifacts more human readable.
1 parent 3d89dfa commit d65c7e4

13 files changed

+117
-81
lines changed

tools/engine_tool/lib/main.dart

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,13 @@ void main(List<String> args) async {
6565
configs: configs,
6666
);
6767

68-
io.exitCode = await runner.run(args);
68+
try {
69+
io.exitCode = await runner.run(args);
70+
} on FatalError catch (e, st) {
71+
environment.logger.error('FatalError caught in main. Please file a bug\n'
72+
'error: $e\n'
73+
'stack: $st');
74+
io.exitCode = 1;
75+
}
6976
return;
7077
}

tools/engine_tool/lib/src/commands/lint_command.dart

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ final class LintCommand extends CommandBase {
6363
Linter.python,
6464
environment.engine.flutterDir,
6565
<String>[p.join(engineFlutterPath, 'ci', 'pylint.sh')]);
66+
argParser.addFlag(
67+
quietFlag,
68+
abbr: 'q',
69+
help: 'Prints minimal output',
70+
);
6671
}
6772

6873
final Map<Linter, _LinterDescription> _linters =
@@ -79,7 +84,7 @@ final class LintCommand extends CommandBase {
7984
// TODO(loic-sharma): Relax this restriction.
8085
if (environment.platform.isWindows) {
8186
environment.logger
82-
.error('lint command is not supported on Windows (for now).');
87+
.fatal('lint command is not supported on Windows (for now).');
8388
return 1;
8489
}
8590
final WorkerPool wp =
@@ -92,16 +97,17 @@ final class LintCommand extends CommandBase {
9297
}
9398
final bool r = await wp.run(tasks);
9499

95-
final bool verbose = globalResults![verboseFlag] as bool;
96-
if (verbose) {
100+
final bool quiet = argResults![quietFlag] as bool;
101+
if (!quiet) {
97102
environment.logger.status('\nDumping failure logs\n');
98103
for (final ProcessTask pt in tasks) {
99104
final ProcessArtifacts pa = pt.processArtifacts;
100105
if (pa.exitCode == 0) {
101106
continue;
102107
}
103-
environment.logger.status(pa.stdout);
104-
environment.logger.status(pa.stderr);
108+
environment.logger.status('Linter ${pt.name} found issues:');
109+
environment.logger.status('${pa.stdout}\n');
110+
environment.logger.status('${pa.stderr}\n');
105111
}
106112
}
107113
return r ? 0 : 1;

tools/engine_tool/lib/src/dart_utils.dart

Lines changed: 1 addition & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,52 +2,12 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
import 'dart:ffi' as ffi show Abi;
6-
75
import 'package:path/path.dart' as p;
86
import 'environment.dart';
97

10-
String _getAbiSubdirectory(ffi.Abi abi) {
11-
switch (abi) {
12-
case ffi.Abi.macosArm64:
13-
return 'macos-arm64';
14-
case ffi.Abi.macosX64:
15-
return 'macos-x64';
16-
case ffi.Abi.windowsArm64:
17-
return 'windows-arm64';
18-
case ffi.Abi.windowsX64:
19-
return 'windows-x64';
20-
case ffi.Abi.linuxArm:
21-
return 'linux-arm';
22-
case ffi.Abi.linuxArm64:
23-
return 'linux-arm64';
24-
case ffi.Abi.linuxIA32:
25-
return 'linux-x86';
26-
case ffi.Abi.linuxX64:
27-
return 'linux-x64';
28-
case ffi.Abi.androidArm:
29-
case ffi.Abi.androidArm64:
30-
case ffi.Abi.androidIA32:
31-
case ffi.Abi.androidX64:
32-
case ffi.Abi.androidRiscv64:
33-
case ffi.Abi.fuchsiaArm64:
34-
case ffi.Abi.fuchsiaX64:
35-
case ffi.Abi.fuchsiaRiscv64:
36-
case ffi.Abi.iosArm:
37-
case ffi.Abi.iosArm64:
38-
case ffi.Abi.iosX64:
39-
case ffi.Abi.linuxRiscv32:
40-
case ffi.Abi.linuxRiscv64:
41-
case ffi.Abi.windowsIA32:
42-
default:
43-
throw UnsupportedError('Unsupported Abi $abi');
44-
}
45-
}
46-
478
/// Returns a dart-sdk/bin directory path that is compatible with the host.
489
String findDartBinDirectory(Environment env) {
49-
return p.join(env.engine.flutterDir.path, 'prebuilts',
50-
_getAbiSubdirectory(env.abi), 'dart-sdk', 'bin');
10+
return p.dirname(env.platform.resolvedExecutable);
5111
}
5212

5313
/// Returns a dart-sdk/bin/dart file pthat that is executable on the host.

tools/engine_tool/lib/src/json_utils.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
import 'dart:convert';
6+
57
void _appendTypeError(
68
Map<String, Object?> map,
79
String field,
@@ -77,3 +79,8 @@ int? intOfJson(
7779
}
7880
return map[field]! as int;
7981
}
82+
83+
const JsonEncoder _jsonEncoder = JsonEncoder.withIndent(' ');
84+
85+
/// Same as [jsonEncode] but is formatted to be human readable.
86+
String jsonEncodePretty(Object? object) => _jsonEncoder.convert(object);

tools/engine_tool/lib/src/logger.dart

Lines changed: 53 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@
33
// found in the LICENSE file.
44

55
import 'dart:async' show Timer, runZoned;
6-
import 'dart:io' as io show
7-
IOSink,
8-
stderr,
9-
stdout;
6+
import 'dart:io' as io show IOSink, stderr, stdout;
107

118
import 'package:logging/logging.dart' as log;
129
import 'package:meta/meta.dart';
@@ -29,7 +26,9 @@ import 'package:meta/meta.dart';
2926
/// which can be inspected by unit tetss.
3027
class Logger {
3128
/// Constructs a logger for use in the tool.
32-
Logger() : _logger = log.Logger.detached('et'), _test = false {
29+
Logger()
30+
: _logger = log.Logger.detached('et'),
31+
_test = false {
3332
_logger.level = statusLevel;
3433
_logger.onRecord.listen(_handler);
3534
_setupIoSink(io.stderr);
@@ -38,7 +37,9 @@ class Logger {
3837

3938
/// A logger for tests.
4039
@visibleForTesting
41-
Logger.test() : _logger = log.Logger.detached('et'), _test = true {
40+
Logger.test()
41+
: _logger = log.Logger.detached('et'),
42+
_test = true {
4243
_logger.level = statusLevel;
4344
_logger.onRecord.listen((log.LogRecord r) => _testLogs.add(r));
4445
}
@@ -57,9 +58,8 @@ class Logger {
5758

5859
static void _handler(log.LogRecord r) {
5960
final io.IOSink sink = r.level >= warningLevel ? io.stderr : io.stdout;
60-
final String prefix = r.level >= warningLevel
61-
? '[${r.time}] ${r.level}: '
62-
: '';
61+
final String prefix =
62+
r.level >= warningLevel ? '[${r.time}] ${r.level}: ' : '';
6363
_ioSinkWrite(sink, '$prefix${r.message}');
6464
}
6565

@@ -77,7 +77,7 @@ class Logger {
7777
runZoned<void>(() {
7878
try {
7979
sink.write(message);
80-
} catch (_) { // ignore: avoid_catches_without_on_clauses
80+
} catch (_) {
8181
_stdioDone = true;
8282
}
8383
}, onError: (Object e, StackTrace s) {
@@ -87,8 +87,12 @@ class Logger {
8787

8888
static void _setupIoSink(io.IOSink sink) {
8989
sink.done.then(
90-
(void _) { _stdioDone = true; },
91-
onError: (Object err, StackTrace st) { _stdioDone = true; },
90+
(void _) {
91+
_stdioDone = true;
92+
},
93+
onError: (Object err, StackTrace st) {
94+
_stdioDone = true;
95+
},
9296
);
9397
}
9498

@@ -106,6 +110,19 @@ class Logger {
106110
_logger.level = l;
107111
}
108112

113+
/// Record a log message level [Logger.error] and throw a FatalError.
114+
/// This should only be called when the program has entered an impossible
115+
/// to recover from state or when something isn't implemented yet.
116+
void fatal(
117+
Object? message, {
118+
int indent = 0,
119+
bool newline = true,
120+
bool fit = false,
121+
}) {
122+
_emitLog(errorLevel, message, indent, newline, fit);
123+
throw FatalError(_formatMessage(message, indent, newline, fit));
124+
}
125+
109126
/// Record a log message at level [Logger.error].
110127
void error(
111128
Object? message, {
@@ -165,9 +182,10 @@ class Logger {
165182
onFinish?.call();
166183
_status = null;
167184
}
185+
168186
_status = io.stdout.hasTerminal && !_test
169-
? FlutterSpinner(onFinish: finishCallback)
170-
: Spinner(onFinish: finishCallback);
187+
? FlutterSpinner(onFinish: finishCallback)
188+
: Spinner(onFinish: finishCallback);
171189
_status!.start();
172190
return _status!;
173191
}
@@ -184,17 +202,22 @@ class Logger {
184202
_ioSinkWrite(io.stdout, '$backspaces$spaces$backspaces');
185203
}
186204

205+
String _formatMessage(Object? message, int indent, bool newline, bool fit) {
206+
String m = '${' ' * indent}$message${newline ? '\n' : ''}';
207+
if (fit && io.stdout.hasTerminal) {
208+
m = fitToWidth(m, io.stdout.terminalColumns);
209+
}
210+
return m;
211+
}
212+
187213
void _emitLog(
188214
log.Level level,
189215
Object? message,
190216
int indent,
191217
bool newline,
192218
bool fit,
193219
) {
194-
String m = '${' ' * indent}$message${newline ? '\n' : ''}';
195-
if (fit && io.stdout.hasTerminal) {
196-
m = fitToWidth(m, io.stdout.terminalColumns);
197-
}
220+
final String m = _formatMessage(message, indent, newline, fit);
198221
_status?.pause();
199222
_logger.log(level, m);
200223
_status?.resume();
@@ -244,7 +267,6 @@ class Logger {
244267
List<log.LogRecord> get testLogs => _testLogs;
245268
}
246269

247-
248270
/// A base class for progress spinners, and a no-op implementation that prints
249271
/// nothing.
250272
class Spinner {
@@ -280,12 +302,10 @@ class FlutterSpinner extends Spinner {
280302
super.onFinish,
281303
});
282304

283-
@visibleForTesting
284305
/// The frames of the animation.
285306
static const String frames = '⢸⡯⠭⠅⢸⣇⣀⡀⢸⣇⣸⡇⠈⢹⡏⠁⠈⢹⡏⠁⢸⣯⣭⡅⢸⡯⢕⡂⠀⠀';
286307

287-
static final List<String> _flutterAnimation = frames
288-
.runes
308+
static final List<String> _flutterAnimation = frames.runes
289309
.map<String>((int scalar) => String.fromCharCode(scalar))
290310
.toList();
291311

@@ -338,3 +358,14 @@ class FlutterSpinner extends Spinner {
338358
}
339359
}
340360
}
361+
362+
/// FatalErrors are thrown when a fatal error has occurred.
363+
class FatalError extends Error {
364+
/// Constructs a FatalError with a message.
365+
FatalError(this._message);
366+
367+
final String _message;
368+
369+
@override
370+
String toString() => _message;
371+
}

tools/engine_tool/lib/src/proc_utils.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ final class ProcessArtifacts {
5050
data['stderr'] = stderr;
5151
data['cwd'] = cwd.absolute.path;
5252
data['commandLine'] = commandLine;
53-
file.writeAsStringSync(jsonEncode(data));
53+
file.writeAsStringSync(jsonEncodePretty(data));
5454
}
5555

5656
/// Creates a temporary file and saves the artifacts into it.

tools/engine_tool/test/build_command_test.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,9 @@ void main() {
6060
Environment(
6161
abi: ffi.Abi.linuxX64,
6262
engine: engine,
63-
platform: FakePlatform(operatingSystem: Platform.linux),
63+
platform: FakePlatform(
64+
operatingSystem: Platform.linux,
65+
resolvedExecutable: io.Platform.resolvedExecutable),
6466
processRunner: ProcessRunner(
6567
processManager: FakeProcessManager(onStart: (List<String> command) {
6668
runHistory.add(command);

tools/engine_tool/test/fetch_command_test.dart

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ void main() {
3131
Environment(
3232
abi: ffi.Abi.linuxX64,
3333
engine: engine,
34-
platform: FakePlatform(operatingSystem: Platform.linux),
34+
platform: FakePlatform(
35+
operatingSystem: Platform.linux,
36+
resolvedExecutable: io.Platform.resolvedExecutable),
3537
processRunner: ProcessRunner(
3638
processManager: FakeProcessManager(onStart: (List<String> command) {
3739
runHistory.add(command);
@@ -54,8 +56,7 @@ void main() {
5456
environment: env,
5557
configs: configs,
5658
);
57-
final int result =
58-
await runner.run(<String>['fetch']);
59+
final int result = await runner.run(<String>['fetch']);
5960
expect(result, equals(0));
6061
expect(runHistory.length, greaterThanOrEqualTo(1));
6162
expect(
@@ -71,8 +72,7 @@ void main() {
7172
environment: env,
7273
configs: configs,
7374
);
74-
final int result =
75-
await runner.run(<String>['sync']);
75+
final int result = await runner.run(<String>['sync']);
7676
expect(result, equals(0));
7777
expect(runHistory.length, greaterThanOrEqualTo(1));
7878
expect(

tools/engine_tool/test/lint_command_test.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ void main() {
5858
Environment(
5959
abi: ffi.Abi.macosArm64,
6060
engine: engine,
61-
platform: FakePlatform(operatingSystem: Platform.macOS),
61+
platform: FakePlatform(
62+
operatingSystem: Platform.macOS,
63+
resolvedExecutable: io.Platform.resolvedExecutable),
6264
processRunner: ProcessRunner(
6365
processManager: FakeProcessManager(onStart: (List<String> command) {
6466
runHistory.add(command);

tools/engine_tool/test/logger_test.dart

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,19 @@ void main() {
7979
expect(stringsFromLogs(logger.testLogs), equals(<String>['info']));
8080
});
8181

82+
test('fatal throws exception', () {
83+
final Logger logger = Logger.test();
84+
logger.level = Logger.infoLevel;
85+
bool caught = false;
86+
try {
87+
logger.fatal('test', newline: false);
88+
} on FatalError catch (_) {
89+
caught = true;
90+
}
91+
expect(caught, equals(true));
92+
expect(stringsFromLogs(logger.testLogs), equals(<String>['test']));
93+
});
94+
8295
test('fitToWidth', () {
8396
expect(Logger.fitToWidth('hello', 0), equals(''));
8497
expect(Logger.fitToWidth('hello', 1), equals('.'));
@@ -117,7 +130,9 @@ void main() {
117130
final Logger logger = Logger.test();
118131
bool called = false;
119132
final Spinner spinner = logger.startSpinner(
120-
onFinish: () { called = true; },
133+
onFinish: () {
134+
called = true;
135+
},
121136
);
122137
spinner.finish();
123138
expect(called, isTrue);

0 commit comments

Comments
 (0)