| 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.phase; | 5 library barback.phase; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 | 8 |
| 9 import 'asset_cascade.dart'; | 9 import 'asset_cascade.dart'; |
| 10 import 'asset_id.dart'; | 10 import 'asset_id.dart'; |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 92 /// emit assets. | 92 /// emit assets. |
| 93 Stream<AssetNode> get onAsset => _onAssetController.stream; | 93 Stream<AssetNode> get onAsset => _onAssetController.stream; |
| 94 final _onAssetController = | 94 final _onAssetController = |
| 95 new StreamController<AssetNode>.broadcast(sync: true); | 95 new StreamController<AssetNode>.broadcast(sync: true); |
| 96 | 96 |
| 97 /// Whether [this] is dirty and still has more processing to do. | 97 /// Whether [this] is dirty and still has more processing to do. |
| 98 /// | 98 /// |
| 99 /// A phase is considered dirty if any of the previous phases in the same | 99 /// A phase is considered dirty if any of the previous phases in the same |
| 100 /// cascade are dirty, since those phases could emit an asset that this phase | 100 /// cascade are dirty, since those phases could emit an asset that this phase |
| 101 /// will then need to process. | 101 /// will then need to process. |
| 102 bool get isDirty => (_previous != null && _previous.isDirty) || | 102 bool get isDirty => (previous != null && previous.isDirty) || |
| 103 _inputs.values.any((input) => input.isDirty) || | 103 _inputs.values.any((input) => input.isDirty) || |
| 104 _groups.values.any((group) => group.isDirty); | 104 _groups.values.any((group) => group.isDirty); |
| 105 | 105 |
| 106 /// A stream that emits an event whenever any transforms in this phase logs | 106 /// A stream that emits an event whenever any transforms in this phase logs |
| 107 /// an entry. | 107 /// an entry. |
| 108 Stream<LogEntry> get onLog => _onLogPool.stream; | 108 Stream<LogEntry> get onLog => _onLogPool.stream; |
| 109 final _onLogPool = new StreamPool<LogEntry>.broadcast(); | 109 final _onLogPool = new StreamPool<LogEntry>.broadcast(); |
| 110 | 110 |
| 111 /// The previous phase in the cascade, or null if this is the first phase. | 111 /// The previous phase in the cascade, or null if this is the first phase. |
| 112 final Phase _previous; | 112 final Phase previous; |
| 113 | 113 |
| 114 /// The subscription to [_previous]'s [onDone] stream. | 114 /// The subscription to [previous]'s [onDone] stream. |
| 115 StreamSubscription _previousOnDoneSubscription; | 115 StreamSubscription _previousOnDoneSubscription; |
| 116 | 116 |
| 117 /// The subscription to [_previous]'s [onAsset] stream. | 117 /// The subscription to [previous]'s [onAsset] stream. |
| 118 StreamSubscription<AssetNode> _previousOnAssetSubscription; | 118 StreamSubscription<AssetNode> _previousOnAssetSubscription; |
| 119 | 119 |
| 120 /// A map of asset ids to completers for [getInput] requests. | 120 /// A map of asset ids to completers for [getInput] requests. |
| 121 /// | 121 /// |
| 122 /// If an asset node is requested before it's available, we put a completer in | 122 /// If an asset node is requested before it's available, we put a completer in |
| 123 /// this map to wait for the asset to be generated. If it's not generated, the | 123 /// this map to wait for the asset to be generated. If it's not generated, the |
| 124 /// completer should complete to `null`. | 124 /// completer should complete to `null`. |
| 125 final _pendingOutputRequests = new Map<AssetId, Completer<AssetNode>>(); | 125 final _pendingOutputRequests = new Map<AssetId, Completer<AssetNode>>(); |
| 126 | 126 |
| 127 /// Returns all currently-available output assets for this phase. | 127 /// Returns all currently-available output assets for this phase. |
| 128 Set<AssetNode> get availableOutputs { | 128 Set<AssetNode> get availableOutputs { |
| 129 return _outputs.values | 129 return _outputs.values |
| 130 .map((output) => output.output) | 130 .map((output) => output.output) |
| 131 .where((node) => node.state.isAvailable) | 131 .where((node) => node.state.isAvailable) |
| 132 .toSet(); | 132 .toSet(); |
| 133 } | 133 } |
| 134 | 134 |
| 135 // TODO(nweiz): Rather than passing the cascade and the phase everywhere, | 135 // TODO(nweiz): Rather than passing the cascade and the phase everywhere, |
| 136 // create an interface that just exposes [getInput]. Emit errors via | 136 // create an interface that just exposes [getInput]. Emit errors via |
| 137 // [AssetNode]s. | 137 // [AssetNode]s. |
| 138 Phase(AssetCascade cascade, String location) | 138 Phase(AssetCascade cascade, String location) |
| 139 : this._(cascade, location, 0); | 139 : this._(cascade, location, 0); |
| 140 | 140 |
| 141 Phase._(this.cascade, this._location, this._index, [this._previous]) { | 141 Phase._(this.cascade, this._location, this._index, [this.previous]) { |
| 142 if (_previous != null) { | 142 if (previous != null) { |
| 143 _previousOnAssetSubscription = _previous.onAsset.listen(addInput); | 143 _previousOnAssetSubscription = previous.onAsset.listen(addInput); |
| 144 _previousOnDoneSubscription = _previous.onDone.listen((_) { | 144 _previousOnDoneSubscription = previous.onDone.listen((_) { |
| 145 if (!isDirty) _onDoneController.add(null); | 145 if (!isDirty) _onDoneController.add(null); |
| 146 }); | 146 }); |
| 147 } | 147 } |
| 148 | 148 |
| 149 onDone.listen((_) { | 149 onDone.listen((_) { |
| 150 // All the previous phases have finished building. If anyone's still | 150 // All the previous phases have finished building. If anyone's still |
| 151 // waiting for outputs, cut off the wait; we won't be generating them, | 151 // waiting for outputs, cut off the wait; we won't be generating them, |
| 152 // at least until a source asset changes. | 152 // at least until a source asset changes. |
| 153 for (var completer in _pendingOutputRequests.values) { | 153 for (var completer in _pendingOutputRequests.values) { |
| 154 completer.complete(null); | 154 completer.complete(null); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 197 if (!isDirty) _onDoneController.add(null); | 197 if (!isDirty) _onDoneController.add(null); |
| 198 }); | 198 }); |
| 199 | 199 |
| 200 input.updateTransformers(_transformers); | 200 input.updateTransformers(_transformers); |
| 201 | 201 |
| 202 for (var group in _groups.values) { | 202 for (var group in _groups.values) { |
| 203 group.addInput(node); | 203 group.addInput(node); |
| 204 } | 204 } |
| 205 } | 205 } |
| 206 | 206 |
| 207 // TODO(nweiz): If the input is available when this is called, it's | 207 // TODO(nweiz): If the output is available when this is called, it's |
| 208 // theoretically possible for it to become unavailable between the call and | 208 // theoretically possible for it to become unavailable between the call and |
| 209 // the return. If it does so, it won't trigger the rebuilding process. To | 209 // the return. If it does so, it won't trigger the rebuilding process. To |
| 210 // avoid this, we should have this and the methods it calls take explicit | 210 // avoid this, we should have this and the methods it calls take explicit |
| 211 // callbacks, as in [AssetNode.whenAvailable]. | 211 // callbacks, as in [AssetNode.whenAvailable]. |
| 212 /// Gets the asset node for an input [id]. | |
| 213 /// | |
| 214 /// If [id] is for a generated or transformed asset, this will wait until it | |
| 215 /// has been created and return it. This means that the returned asset will | |
| 216 /// always be [AssetState.AVAILABLE]. | |
| 217 /// | |
| 218 /// If the input cannot be found, returns null. | |
| 219 Future<AssetNode> getInput(AssetId id) { | |
| 220 return syncFuture(() { | |
| 221 if (id.package != cascade.package) return cascade.graph.getAssetNode(id); | |
| 222 if (_previous != null) return _previous.getOutput(id); | |
| 223 if (!_inputs.containsKey(id)) return null; | |
| 224 | |
| 225 var input = _inputs[id].input; | |
| 226 return input.whenAvailable((_) => input).catchError((error) { | |
| 227 if (error is! AssetNotFoundException || error.id != id) throw error; | |
| 228 // Retry in case the input was replaced. | |
| 229 return getInput(id); | |
| 230 }); | |
| 231 }); | |
| 232 } | |
| 233 | |
| 234 /// Gets the asset node for an output [id]. | 212 /// Gets the asset node for an output [id]. |
| 235 /// | 213 /// |
| 236 /// If [id] is for a generated or transformed asset, this will wait until it | 214 /// If [id] is for a generated or transformed asset, this will wait until it |
| 237 /// has been created and return it. This means that the returned asset will | 215 /// has been created and return it. This means that the returned asset will |
| 238 /// always be [AssetState.AVAILABLE]. | 216 /// always be [AssetState.AVAILABLE]. |
| 239 /// | 217 /// |
| 240 /// If the output cannot be found, returns null. | 218 /// If the output cannot be found, returns null. |
| 241 Future<AssetNode> getOutput(AssetId id) { | 219 Future<AssetNode> getOutput(AssetId id) { |
| 242 return syncFuture(() { | 220 return syncFuture(() { |
| 243 if (id.package != cascade.package) return cascade.graph.getAssetNode(id); | 221 if (id.package != cascade.package) return cascade.graph.getAssetNode(id); |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 400 assert(asset.state.isDirty); | 378 assert(asset.state.isDirty); |
| 401 asset.force(); | 379 asset.force(); |
| 402 asset.whenStateChanges().then((state) { | 380 asset.whenStateChanges().then((state) { |
| 403 if (state.isRemoved) return getOutput(asset.id); | 381 if (state.isRemoved) return getOutput(asset.id); |
| 404 return asset; | 382 return asset; |
| 405 }).then(request.complete).catchError(request.completeError); | 383 }).then(request.complete).catchError(request.completeError); |
| 406 } | 384 } |
| 407 | 385 |
| 408 String toString() => "phase $_location.$_index"; | 386 String toString() => "phase $_location.$_index"; |
| 409 } | 387 } |
| OLD | NEW |