| 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 |