OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library code_transformers.messages.messages_logger; | 5 library code_transformers.messages.messages_logger; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 import 'dart:convert' show JSON; | 8 import 'dart:convert' show JSON; |
9 | 9 |
10 import 'package:barback/barback.dart'; | 10 import 'package:barback/barback.dart'; |
11 import 'package:source_span/source_span.dart'; | 11 import 'package:source_span/source_span.dart'; |
12 | 12 |
13 import 'messages.dart' show Message, MessageId, BuildLogEntry, LogEntryTable; | 13 import 'messages.dart' show Message, BuildLogEntry, LogEntryTable; |
14 | 14 |
15 /// A [TransformLogger] used to track error and warning messages produced during | 15 /// A [TransformLogger] used to track error and warning messages produced during |
16 /// a build. | 16 /// a build. |
17 /// | 17 /// |
18 /// This logger records all messages that were logged and then forwards | 18 /// This logger records all messages that were logged and then forwards |
19 /// the calls to an underlying [TransformLogger]. The internal records support | 19 /// the calls to an underlying [TransformLogger]. The internal records support |
20 /// serializing the errors and emiting them to an asset (so they can be | 20 /// serializing the errors and emiting them to an asset (so they can be |
21 /// presented to the user in a web-based client), clustering similar messages | 21 /// presented to the user in a web-based client), clustering similar messages |
22 /// together, sorting messages in order of importance, etc. | 22 /// together, sorting messages in order of importance, etc. |
23 /// | 23 /// |
(...skipping 28 matching lines...) Expand all Loading... |
52 /// If transform is a [Transform] then [primaryId] will default to the | 52 /// If transform is a [Transform] then [primaryId] will default to the |
53 /// primaryInput.id, if it is an [AggregateTransform] then you must pass in | 53 /// primaryInput.id, if it is an [AggregateTransform] then you must pass in |
54 /// a [primaryId] to be used, otherwise you will get a runtime error. | 54 /// a [primaryId] to be used, otherwise you will get a runtime error. |
55 BuildLogger(transform, | 55 BuildLogger(transform, |
56 {this.convertErrorsToWarnings: false, AssetId primaryId, this.detailsUri}) | 56 {this.convertErrorsToWarnings: false, AssetId primaryId, this.detailsUri}) |
57 : _transform = transform, | 57 : _transform = transform, |
58 _primaryId = primaryId != null ? primaryId : transform.primaryInput.id; | 58 _primaryId = primaryId != null ? primaryId : transform.primaryInput.id; |
59 | 59 |
60 /// Records a message at the fine level. If [msg] is a [Message] it is | 60 /// Records a message at the fine level. If [msg] is a [Message] it is |
61 /// recorded directly, otherwise it is first converted to a [String]. | 61 /// recorded directly, otherwise it is first converted to a [String]. |
62 void fine(msg, {AssetId asset, SourceSpan span}) { | 62 void fine(Object msg, {AssetId asset, SourceSpan span}) { |
63 msg = msg is Message ? msg : new Message.unknown('$msg'); | 63 msg = msg is Message ? msg : new Message.unknown('$msg'); |
64 _transform.logger.fine(_snippet(msg), asset: asset, span: span); | 64 _transform.logger.fine(_snippet(msg), asset: asset, span: span); |
65 _logs.add(new BuildLogEntry(msg, span, LogLevel.FINE.name)); | 65 _logs.add(new BuildLogEntry(msg, span, LogLevel.FINE.name)); |
66 } | 66 } |
67 | 67 |
68 /// Records a message at the info level. If [msg] is a [Message] it is | 68 /// Records a message at the info level. If [msg] is a [Message] it is |
69 /// recorded directly, otherwise it is first converted to a [String]. | 69 /// recorded directly, otherwise it is first converted to a [String]. |
70 void info(msg, {AssetId asset, SourceSpan span}) { | 70 void info(Object msg, {AssetId asset, SourceSpan span}) { |
71 msg = msg is Message ? msg : new Message.unknown('$msg'); | 71 msg = msg is Message ? msg : new Message.unknown('$msg'); |
72 _transform.logger.info(_snippet(msg), asset: asset, span: span); | 72 _transform.logger.info(_snippet(msg), asset: asset, span: span); |
73 _logs.add(new BuildLogEntry(msg, span, LogLevel.INFO.name)); | 73 _logs.add(new BuildLogEntry(msg, span, LogLevel.INFO.name)); |
74 } | 74 } |
75 | 75 |
76 /// Records a warning message. If [msg] is a [Message] it is recorded | 76 /// Records a warning message. If [msg] is a [Message] it is recorded |
77 /// directly, otherwise it is first converted to a [String]. | 77 /// directly, otherwise it is first converted to a [String]. |
78 void warning(msg, {AssetId asset, SourceSpan span}) { | 78 void warning(Object msg, {AssetId asset, SourceSpan span}) { |
79 msg = msg is Message ? msg : new Message.unknown('$msg'); | 79 msg = msg is Message ? msg : new Message.unknown('$msg'); |
80 _transform.logger.warning(_snippet(msg), asset: asset, span: span); | 80 _transform.logger.warning(_snippet(msg), asset: asset, span: span); |
81 _logs.add(new BuildLogEntry(msg, span, LogLevel.WARNING.name)); | 81 _logs.add(new BuildLogEntry(msg, span, LogLevel.WARNING.name)); |
82 } | 82 } |
83 | 83 |
84 /// Records an error message. If [msg] is a [Message] it is recorded | 84 /// Records an error message. If [msg] is a [Message] it is recorded |
85 /// directly, otherwise it is first converted to a [String]. | 85 /// directly, otherwise it is first converted to a [String]. |
86 void error(msg, {AssetId asset, SourceSpan span}) { | 86 void error(Object msg, {AssetId asset, SourceSpan span}) { |
87 msg = msg is Message ? msg : new Message.unknown('$msg'); | 87 msg = msg is Message ? msg : new Message.unknown('$msg'); |
88 if (convertErrorsToWarnings) { | 88 if (convertErrorsToWarnings) { |
89 _transform.logger.warning(_snippet(msg), asset: asset, span: span); | 89 _transform.logger.warning(_snippet(msg), asset: asset, span: span); |
90 } else { | 90 } else { |
91 _transform.logger.error(_snippet(msg), asset: asset, span: span); | 91 _transform.logger.error(_snippet(msg), asset: asset, span: span); |
92 } | 92 } |
93 _logs.add(new BuildLogEntry(msg, span, LogLevel.ERROR.name)); | 93 _logs.add(new BuildLogEntry(msg, span, LogLevel.ERROR.name)); |
94 } | 94 } |
95 | 95 |
96 String _snippet(Message msg) { | 96 String _snippet(Message msg) { |
97 var s = msg.snippet; | 97 var s = msg.snippet; |
98 if (detailsUri == null) return s; | 98 if (detailsUri == null) return s; |
99 var dot = s.endsWith('.') || s.endsWith('!') || s.endsWith('?') ? '' : '.'; | 99 var dot = s.endsWith('.') || s.endsWith('!') || s.endsWith('?') ? '' : '.'; |
100 var hashTag = '${msg.id.package}_${msg.id.id}'; | 100 var hashTag = '${msg.id.package}_${msg.id.id}'; |
101 return '$s$dot See $detailsUri#$hashTag for details.'; | 101 return '$s$dot See $detailsUri#$hashTag for details.'; |
102 } | 102 } |
103 | 103 |
104 /// Outputs the log data to a JSON serialized file. | 104 /// Outputs the log data to a JSON serialized file. |
105 Future writeOutput() { | 105 Future writeOutput() { |
106 return _getNextLogAssetId().then((id) { | 106 return _getNextLogAssetId().then((id) { |
107 _transform.addOutput(new Asset.fromString(id, JSON.encode(_logs))); | 107 _transform.addOutput(new Asset.fromString(id, JSON.encode(_logs))); |
108 }); | 108 }); |
109 } | 109 } |
110 | 110 |
111 // Each phase outputs a new log file with an incrementing # appended, this | 111 // Each phase outputs a new log file with an incrementing # appended, this |
112 // figures out the next # to use. | 112 // figures out the next # to use. |
113 Future<AssetId> _getNextLogAssetId([int nextNumber = 1]) { | 113 Future<AssetId> _getNextLogAssetId([int nextNumber = 1]) async { |
114 var nextAssetPath = _primaryId.addExtension('${LOG_EXTENSION}.$nextNumber'); | 114 var nextAssetPath = _primaryId.addExtension('${LOG_EXTENSION}.$nextNumber'); |
115 return _transform.hasInput(nextAssetPath).then((exists) { | 115 bool exists = await _transform.hasInput(nextAssetPath); |
116 if (!exists) return nextAssetPath; | 116 if (!exists) return nextAssetPath; |
117 return _getNextLogAssetId(++nextNumber); | 117 return _getNextLogAssetId(++nextNumber); |
118 }); | |
119 } | 118 } |
120 | 119 |
121 // Reads all log files for an Asset into [logs]. | 120 // Reads all log files for an Asset into [logs]. |
122 static Future _readLogFilesForAsset( | 121 static Future _readLogFilesForAsset( |
123 AssetId id, Transform transform, LogEntryTable entries, | 122 AssetId id, Transform transform, LogEntryTable entries, |
124 [nextNumber = 1]) { | 123 [nextNumber = 1]) { |
125 var nextAssetPath = id.addExtension('${LOG_EXTENSION}.$nextNumber'); | 124 var nextAssetPath = id.addExtension('${LOG_EXTENSION}.$nextNumber'); |
126 return transform.hasInput(nextAssetPath).then((exists) { | 125 return transform.hasInput(nextAssetPath).then((exists) { |
127 if (!exists) return null; | 126 if (!exists) return null; |
128 return transform.readInputAsString(nextAssetPath).then((data) { | 127 return transform.readInputAsString(nextAssetPath).then((data) { |
129 entries.addAll(new LogEntryTable.fromJson(JSON.decode(data))); | 128 entries.addAll(new LogEntryTable.fromJson( |
| 129 JSON.decode(data) as Map<String, Iterable>)); |
130 return _readLogFilesForAsset(id, transform, entries, ++nextNumber); | 130 return _readLogFilesForAsset(id, transform, entries, ++nextNumber); |
131 }); | 131 }); |
132 }); | 132 }); |
133 } | 133 } |
134 | 134 |
135 /// Combines all existing ._buildLogs.* files into a single ._buildLogs file. | 135 /// Combines all existing ._buildLogs.* files into a single ._buildLogs file. |
136 /// [transform] may be a [Transform] or [AggregateTransform]. If an | 136 /// [transform] may be a [Transform] or [AggregateTransform]. If an |
137 /// [AggregateTransform] is passed then [primaryId] must also be passed. | 137 /// [AggregateTransform] is passed then [primaryId] must also be passed. |
138 static Future combineLogFiles(transform, [AssetId primaryId]) { | 138 static Future combineLogFiles(transform, [AssetId primaryId]) { |
139 if (primaryId == null) primaryId = transform.primaryInput.id; | 139 if (primaryId == null) primaryId = transform.primaryInput.id; |
140 var entries = new LogEntryTable(); | 140 var entries = new LogEntryTable(); |
141 return _readLogFilesForAsset(primaryId, transform, entries).then((_) { | 141 return _readLogFilesForAsset(primaryId, transform, entries).then((_) { |
142 return transform.addOutput(new Asset.fromString( | 142 return transform.addOutput(new Asset.fromString( |
143 primaryId.addExtension(LOG_EXTENSION), | 143 primaryId.addExtension(LOG_EXTENSION), |
144 JSON.encode(entries.toJson()))); | 144 JSON.encode(entries.toJson()))); |
145 }); | 145 }); |
146 } | 146 } |
147 | 147 |
148 // Reads all logs for an asset and adds them to this loggers log output. | 148 // Reads all logs for an asset and adds them to this loggers log output. |
149 Future addLogFilesFromAsset(AssetId id, [int nextNumber = 1]) { | 149 Future addLogFilesFromAsset(AssetId id, [int nextNumber = 1]) { |
150 return _readLogFilesForAsset(id, _transform, _logs); | 150 return _readLogFilesForAsset(id, _transform, _logs); |
151 } | 151 } |
152 } | 152 } |
153 | 153 |
154 /// Extension used for assets that contained serialized logs. | 154 /// Extension used for assets that contained serialized logs. |
155 const String LOG_EXTENSION = '._buildLogs'; | 155 const String LOG_EXTENSION = '._buildLogs'; |
OLD | NEW |