33// found in the LICENSE file.
44
55import '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
118import 'package:logging/logging.dart' as log;
129import 'package:meta/meta.dart' ;
@@ -29,7 +26,9 @@ import 'package:meta/meta.dart';
2926/// which can be inspected by unit tetss.
3027class 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.
250272class 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+ }
0 commit comments