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 barback.graph.package_graph; | 5 library barback.package_graph; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 import 'dart:collection'; | 8 import 'dart:collection'; |
9 | 9 |
10 import '../asset/asset_id.dart'; | |
11 import '../asset/asset_node.dart'; | |
12 import '../asset/asset_set.dart'; | |
13 import '../build_result.dart'; | |
14 import '../errors.dart'; | |
15 import '../log.dart'; | |
16 import '../package_provider.dart'; | |
17 import '../transformer/transformer.dart'; | |
18 import '../utils.dart'; | |
19 import 'asset_cascade.dart'; | 10 import 'asset_cascade.dart'; |
20 import 'node_status.dart'; | 11 import 'asset_id.dart'; |
| 12 import 'asset_node.dart'; |
| 13 import 'asset_set.dart'; |
| 14 import 'build_result.dart'; |
| 15 import 'errors.dart'; |
| 16 import 'log.dart'; |
| 17 import 'package_provider.dart'; |
| 18 import 'transformer.dart'; |
| 19 import 'utils.dart'; |
21 | 20 |
22 /// The collection of [AssetCascade]s for an entire application. | 21 /// The collection of [AssetCascade]s for an entire application. |
23 /// | 22 /// |
24 /// This tracks each package's [AssetCascade] and routes asset requests between | 23 /// This tracks each package's [AssetCascade] and routes asset requests between |
25 /// them. | 24 /// them. |
26 class PackageGraph { | 25 class PackageGraph { |
27 /// The provider that exposes asset and package information. | 26 /// The provider that exposes asset and package information. |
28 final PackageProvider provider; | 27 final PackageProvider provider; |
29 | 28 |
30 /// The [AssetCascade] for each package. | 29 /// The [AssetCascade] for each package. |
(...skipping 18 matching lines...) Expand all Loading... |
49 /// | 48 /// |
50 /// This will not emit programming errors from barback itself. Those will be | 49 /// This will not emit programming errors from barback itself. Those will be |
51 /// emitted through the [results] stream's error channel. | 50 /// emitted through the [results] stream's error channel. |
52 Stream<BarbackException> get errors => _errors; | 51 Stream<BarbackException> get errors => _errors; |
53 Stream<BarbackException> _errors; | 52 Stream<BarbackException> _errors; |
54 | 53 |
55 /// The stream of [LogEntry] objects used to report transformer log entries. | 54 /// The stream of [LogEntry] objects used to report transformer log entries. |
56 Stream<LogEntry> get log => _logController.stream; | 55 Stream<LogEntry> get log => _logController.stream; |
57 final _logController = new StreamController<LogEntry>.broadcast(sync: true); | 56 final _logController = new StreamController<LogEntry>.broadcast(sync: true); |
58 | 57 |
59 /// How far along [this] is in processing its assets. | 58 /// Whether [this] is dirty and still has more processing to do. |
60 NodeStatus get _status => NodeStatus.dirtiest( | 59 bool get _isDirty => _cascades.values.any((cascade) => cascade.isDirty); |
61 _cascades.values.map((cascade) => cascade.status)); | |
62 | 60 |
63 /// Whether a [BuildResult] is scheduled to be emitted on [results] (see | 61 /// Whether a [BuildResult] is scheduled to be emitted on [results] (see |
64 /// [_tryScheduleResult]). | 62 /// [_tryScheduleResult]). |
65 bool _resultScheduled = false; | 63 bool _resultScheduled = false; |
66 | 64 |
67 /// The most recent [BuildResult] emitted on [results]. | 65 /// The most recent [BuildResult] emitted on [results]. |
68 BuildResult _lastResult; | 66 BuildResult _lastResult; |
69 | 67 |
70 // TODO(nweiz): This can have bogus errors if an error is created and resolved | 68 // TODO(nweiz): This can have bogus errors if an error is created and resolved |
71 // in the space of one build. | 69 // in the space of one build. |
(...skipping 12 matching lines...) Expand all Loading... |
84 StackTrace _lastUnexpectedErrorTrace; | 82 StackTrace _lastUnexpectedErrorTrace; |
85 | 83 |
86 /// Creates a new [PackageGraph] that will transform assets in all packages | 84 /// Creates a new [PackageGraph] that will transform assets in all packages |
87 /// made available by [provider]. | 85 /// made available by [provider]. |
88 PackageGraph(this.provider) { | 86 PackageGraph(this.provider) { |
89 _inErrorZone(() { | 87 _inErrorZone(() { |
90 for (var package in provider.packages) { | 88 for (var package in provider.packages) { |
91 var cascade = new AssetCascade(this, package); | 89 var cascade = new AssetCascade(this, package); |
92 _cascades[package] = cascade; | 90 _cascades[package] = cascade; |
93 cascade.onLog.listen(_onLog); | 91 cascade.onLog.listen(_onLog); |
94 cascade.onStatusChange.listen((status) { | 92 cascade.onDone.listen((_) => _tryScheduleResult()); |
95 if (status == NodeStatus.IDLE) _tryScheduleResult(); | |
96 }); | |
97 } | 93 } |
98 | 94 |
99 _errors = mergeStreams(_cascades.values.map((cascade) => cascade.errors), | 95 _errors = mergeStreams(_cascades.values.map((cascade) => cascade.errors), |
100 broadcast: true); | 96 broadcast: true); |
101 _errors.listen(_accumulatedErrors.add); | 97 _errors.listen(_accumulatedErrors.add); |
102 }); | 98 }); |
103 } | 99 } |
104 | 100 |
105 /// Gets the asset node identified by [id]. | 101 /// Gets the asset node identified by [id]. |
106 /// | 102 /// |
(...skipping 16 matching lines...) Expand all Loading... |
123 /// returned future will complete with an error if the build is not | 119 /// returned future will complete with an error if the build is not |
124 /// successful. | 120 /// successful. |
125 /// | 121 /// |
126 /// Any transforms using [LazyTransformer]s will be forced to generate | 122 /// Any transforms using [LazyTransformer]s will be forced to generate |
127 /// concrete outputs, and those outputs will be returned. | 123 /// concrete outputs, and those outputs will be returned. |
128 Future<AssetSet> getAllAssets() { | 124 Future<AssetSet> getAllAssets() { |
129 for (var cascade in _cascades.values) { | 125 for (var cascade in _cascades.values) { |
130 _inErrorZone(() => cascade.forceAllTransforms()); | 126 _inErrorZone(() => cascade.forceAllTransforms()); |
131 } | 127 } |
132 | 128 |
133 if (_status != NodeStatus.IDLE) { | 129 if (_isDirty) { |
134 // A build is still ongoing, so wait for it to complete and try again. | 130 // A build is still ongoing, so wait for it to complete and try again. |
135 return results.first.then((_) => getAllAssets()); | 131 return results.first.then((_) => getAllAssets()); |
136 } | 132 } |
137 | 133 |
138 // If an unexpected error occurred, complete with that. | 134 // If an unexpected error occurred, complete with that. |
139 if (_lastUnexpectedError != null) { | 135 if (_lastUnexpectedError != null) { |
140 var error = _lastUnexpectedError; | 136 var error = _lastUnexpectedError; |
141 _lastUnexpectedError = null; | 137 _lastUnexpectedError = null; |
142 return new Future.error(error, _lastUnexpectedErrorTrace); | 138 return new Future.error(error, _lastUnexpectedErrorTrace); |
143 } | 139 } |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
219 } | 215 } |
220 } | 216 } |
221 | 217 |
222 /// If [this] is done processing, schedule a [BuildResult] to be emitted on | 218 /// If [this] is done processing, schedule a [BuildResult] to be emitted on |
223 /// [results]. | 219 /// [results]. |
224 /// | 220 /// |
225 /// This schedules the result (as opposed to just emitting one directly on | 221 /// This schedules the result (as opposed to just emitting one directly on |
226 /// [BuildResult]) to ensure that calling multiple functions synchronously | 222 /// [BuildResult]) to ensure that calling multiple functions synchronously |
227 /// produces only a single [BuildResult]. | 223 /// produces only a single [BuildResult]. |
228 void _tryScheduleResult() { | 224 void _tryScheduleResult() { |
229 if (_status != NodeStatus.IDLE) return; | 225 if (_isDirty) return; |
230 if (_resultScheduled) return; | 226 if (_resultScheduled) return; |
231 | 227 |
232 _resultScheduled = true; | 228 _resultScheduled = true; |
233 newFuture(() { | 229 newFuture(() { |
234 _resultScheduled = false; | 230 _resultScheduled = false; |
235 if (_status != NodeStatus.IDLE) return; | 231 if (_isDirty) return; |
236 | 232 |
237 _lastResult = new BuildResult(_accumulatedErrors); | 233 _lastResult = new BuildResult(_accumulatedErrors); |
238 _accumulatedErrors.clear(); | 234 _accumulatedErrors.clear(); |
239 _resultsController.add(_lastResult); | 235 _resultsController.add(_lastResult); |
240 }); | 236 }); |
241 } | 237 } |
242 | 238 |
243 /// Run [body] in an error-handling [Zone] and pipe any unexpected errors to | 239 /// Run [body] in an error-handling [Zone] and pipe any unexpected errors to |
244 /// the error channel of [results]. | 240 /// the error channel of [results]. |
245 /// | 241 /// |
246 /// [body] can return a value or a [Future] that will be piped to the returned | 242 /// [body] can return a value or a [Future] that will be piped to the returned |
247 /// [Future]. If it throws a [BarbackException], that exception will be piped | 243 /// [Future]. If it throws a [BarbackException], that exception will be piped |
248 /// to the returned [Future] as well. Any other exceptions will be piped to | 244 /// to the returned [Future] as well. Any other exceptions will be piped to |
249 /// [results]. | 245 /// [results]. |
250 Future _inErrorZone(body()) { | 246 Future _inErrorZone(body()) { |
251 var completer = new Completer.sync(); | 247 var completer = new Completer.sync(); |
252 runZoned(() { | 248 runZoned(() { |
253 syncFuture(body).then(completer.complete).catchError((error, stackTrace) { | 249 syncFuture(body).then(completer.complete).catchError((error, stackTrace) { |
254 if (error is! BarbackException) throw error; | 250 if (error is! BarbackException) throw error; |
255 completer.completeError(error, stackTrace); | 251 completer.completeError(error, stackTrace); |
256 }); | 252 }); |
257 }, onError: (error, stackTrace) { | 253 }, onError: (error, stackTrace) { |
258 _lastUnexpectedError = error; | 254 _lastUnexpectedError = error; |
259 _lastUnexpectedErrorTrace = stackTrace; | 255 _lastUnexpectedErrorTrace = stackTrace; |
260 _resultsController.addError(error, stackTrace); | 256 _resultsController.addError(error, stackTrace); |
261 }); | 257 }); |
262 return completer.future; | 258 return completer.future; |
263 } | 259 } |
264 } | 260 } |
OLD | NEW |