Index: pkg/code_transformers/lib/messages/build_logger.dart |
diff --git a/pkg/code_transformers/lib/messages/build_logger.dart b/pkg/code_transformers/lib/messages/build_logger.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..e1d7e78a58a2b8c53f206b497a180ef23b0fbad0 |
--- /dev/null |
+++ b/pkg/code_transformers/lib/messages/build_logger.dart |
@@ -0,0 +1,131 @@ |
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+library code_transformers.messages.messages_logger; |
+ |
+import 'dart:async'; |
+import 'dart:convert' show JSON; |
+ |
+import 'package:barback/barback.dart'; |
+import 'package:source_span/source_span.dart'; |
+ |
+import 'messages.dart' show Message, MessageId, BuildLogEntry, LogEntryTable; |
+ |
+/// A [TransformLogger] used to track error and warning messages produced during |
+/// a build. |
+/// |
+/// This logger records all messages that were logged and then forwards |
+/// the calls to an underlying [TransformLogger]. The internal records support |
+/// serializing the errors and emiting them to an asset (so they can be |
+/// presented to the user in a web-based client), clustering similar messages |
+/// together, sorting messages in order of importance, etc. |
+/// |
+/// The logger also supports reporting error messages as warnings. Barback makes |
+/// error messages stop the transformation process, which sometimes can surprise |
+/// users. Turning errors into warnings is especially useful when used within |
+/// `pub serve`, where we would like the transformation to continue as far as it |
+/// can. When this flag is turned on, the level is still recorded as an error, |
+/// so a web client UI can still highlight their importance. |
+// TODO(sigmund): also cluster messages when they are reported on the |
+// command-line. |
+class BuildLogger implements TransformLogger { |
+ /// Underling transform that is currently active. |
+ final Transform _transform; |
+ |
+ /// Logs created during the current transform. |
+ final LogEntryTable _logs = new LogEntryTable(); |
+ |
+ /// Whether to use `warning` or `error` when forwarding error messages to the |
+ /// underlying logger in `_transform.logger`. |
+ final bool convertErrorsToWarnings; |
+ |
+ BuildLogger(this._transform, {this.convertErrorsToWarnings: false}); |
+ |
+ /// Records a message at the fine level. If [msg] is a [Message] it is |
+ /// recorded directly, otherwise it is first converted to a [String]. |
+ void fine(msg, {AssetId asset, SourceSpan span}) { |
+ msg = msg is Message ? msg : new Message.unknown('$msg'); |
+ _transform.logger.fine(msg.snippet, asset: asset, span: span); |
+ _logs.add(new BuildLogEntry(msg, span, LogLevel.FINE.name)); |
+ } |
+ |
+ /// Records a message at the info level. If [msg] is a [Message] it is |
+ /// recorded directly, otherwise it is first converted to a [String]. |
+ void info(msg, {AssetId asset, SourceSpan span}) { |
+ msg = msg is Message ? msg : new Message.unknown('$msg'); |
+ _transform.logger.info(msg.snippet, asset: asset, span: span); |
+ _logs.add(new BuildLogEntry(msg, span, LogLevel.INFO.name)); |
+ } |
+ |
+ /// Records a warning message. If [msg] is a [Message] it is recorded |
+ /// directly, otherwise it is first converted to a [String]. |
+ void warning(msg, {AssetId asset, SourceSpan span}) { |
+ msg = msg is Message ? msg : new Message.unknown('$msg'); |
+ _transform.logger.warning(msg.snippet, asset: asset, span: span); |
+ _logs.add(new BuildLogEntry(msg, span, LogLevel.WARNING.name)); |
+ } |
+ |
+ /// Records an error message. If [msg] is a [Message] it is recorded |
+ /// directly, otherwise it is first converted to a [String]. |
+ void error(msg, {AssetId asset, SourceSpan span}) { |
+ msg = msg is Message ? msg : new Message.unknown('$msg'); |
+ if (convertErrorsToWarnings) { |
+ _transform.logger.warning(msg.snippet, asset: asset, span: span); |
+ } else { |
+ _transform.logger.error(msg.snippet, asset: asset, span: span); |
+ } |
+ _logs.add(new BuildLogEntry(msg, span, LogLevel.ERROR.name)); |
+ } |
+ |
+ /// Outputs the log data to a JSON serialized file. |
+ Future writeOutput() { |
+ return _getNextLogAssetPath().then((path) { |
+ _transform.addOutput(new Asset.fromString(path, |
+ JSON.encode(_logs))); |
+ }); |
+ } |
+ |
+ // Each phase outputs a new log file with an incrementing # appended, this |
+ // figures out the next # to use. |
+ Future<String> _getNextLogAssetPath([int nextNumber = 1]) { |
+ var nextAssetPath = _transform.primaryInput.id.addExtension( |
+ '${LOG_EXTENSION}.$nextNumber'); |
+ return _transform.hasInput(nextAssetPath).then((exists) { |
+ if (!exists) return nextAssetPath; |
+ return _getNextLogAssetPath(++nextNumber); |
+ }); |
+ } |
+ |
+ // Reads all log files for an Asset into [logs]. |
+ static Future _readLogFilesForAsset(AssetId id, Transform transform, |
+ LogEntryTable entries, [nextNumber = 1]) { |
+ var nextAssetPath = id.addExtension('${LOG_EXTENSION}.$nextNumber'); |
+ return transform.hasInput(nextAssetPath).then((exists) { |
+ if (!exists) return null; |
+ return transform.readInputAsString(nextAssetPath).then((data) { |
+ entries.addAll(new LogEntryTable.fromJson(JSON.decode(data))); |
+ return _readLogFilesForAsset(id, transform, entries, ++nextNumber); |
+ }); |
+ }); |
+ } |
+ |
+ // Combines all existing ._buildLogs.* files into a single ._buildLogs file. |
+ static Future combineLogFiles(Transform transform) { |
+ var entries = new LogEntryTable(); |
+ var id = transform.primaryInput.id; |
+ return _readLogFilesForAsset(id, transform, entries).then((_) { |
+ return transform.addOutput(new Asset.fromString( |
+ id.addExtension(LOG_EXTENSION), |
+ JSON.encode(entries.toJson()))); |
+ }); |
+ } |
+ |
+ // Reads all logs for an asset and adds them to this loggers log output. |
+ Future addLogFilesFromAsset(AssetId id, [int nextNumber = 1]) { |
+ return _readLogFilesForAsset(id, _transform, _logs); |
+ } |
+} |
+ |
+/// Extension used for assets that contained serialized logs. |
+const String LOG_EXTENSION = '._buildLogs'; |