| 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.transform_node; | 5 library barback.graph.transform_node; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 | 8 |
| 9 import '../asset/asset.dart'; | 9 import '../asset/asset.dart'; |
| 10 import '../asset/asset_id.dart'; | 10 import '../asset/asset_id.dart'; |
| 11 import '../asset/asset_node.dart'; | 11 import '../asset/asset_node.dart'; |
| 12 import '../asset/asset_node_set.dart'; | 12 import '../asset/asset_node_set.dart'; |
| 13 import '../errors.dart'; | 13 import '../errors.dart'; |
| 14 import '../log.dart'; | 14 import '../log.dart'; |
| 15 import '../transformer/aggregate_transform.dart'; | 15 import '../transformer/aggregate_transform.dart'; |
| 16 import '../transformer/aggregate_transformer.dart'; | 16 import '../transformer/aggregate_transformer.dart'; |
| 17 import '../transformer/declaring_aggregate_transform.dart'; | 17 import '../transformer/declaring_aggregate_transform.dart'; |
| 18 import '../transformer/declaring_aggregate_transformer.dart'; | 18 import '../transformer/declaring_aggregate_transformer.dart'; |
| 19 import '../transformer/lazy_aggregate_transformer.dart'; | 19 import '../transformer/lazy_aggregate_transformer.dart'; |
| 20 import '../utils.dart'; | 20 import '../utils.dart'; |
| 21 import 'node_status.dart'; | 21 import 'node_status.dart'; |
| 22 import 'node_streams.dart'; | 22 import 'node_streams.dart'; |
| 23 import 'phase.dart'; | 23 import 'phase.dart'; |
| 24 import 'transformer_classifier.dart'; |
| 24 | 25 |
| 25 /// Describes a transform on a set of assets and its relationship to the build | 26 /// Describes a transform on a set of assets and its relationship to the build |
| 26 /// dependency graph. | 27 /// dependency graph. |
| 27 /// | 28 /// |
| 28 /// Keeps track of whether it's dirty and needs to be run and which assets it | 29 /// Keeps track of whether it's dirty and needs to be run and which assets it |
| 29 /// depends on. | 30 /// depends on. |
| 30 class TransformNode { | 31 class TransformNode { |
| 31 /// The aggregate key for this node. | 32 /// The aggregate key for this node. |
| 32 final String key; | 33 final String key; |
| 33 | 34 |
| 35 /// The [TransformerClassifier] that [this] belongs to. |
| 36 final TransformerClassifier classifier; |
| 37 |
| 34 /// The [Phase] that this transform runs in. | 38 /// The [Phase] that this transform runs in. |
| 35 final Phase phase; | 39 Phase get phase => classifier.phase; |
| 36 | 40 |
| 37 /// The [AggregateTransformer] to apply to this node's inputs. | 41 /// The [AggregateTransformer] to apply to this node's inputs. |
| 38 final AggregateTransformer transformer; | 42 final AggregateTransformer transformer; |
| 39 | 43 |
| 40 /// The primary asset nodes this transform runs on. | 44 /// The primary asset nodes this transform runs on. |
| 41 final _primaries = new AssetNodeSet(); | 45 final _primaries = new AssetNodeSet(); |
| 42 | 46 |
| 43 /// A string describing the location of [this] in the transformer graph. | 47 /// A string describing the location of [this] in the transformer graph. |
| 44 final String _location; | 48 final String _location; |
| 45 | 49 |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 155 | 159 |
| 156 /// The controller for the currently-running [AggregateTransformer.apply] | 160 /// The controller for the currently-running [AggregateTransformer.apply] |
| 157 /// call's [AggregateTransform]. | 161 /// call's [AggregateTransform]. |
| 158 /// | 162 /// |
| 159 /// This will be non-`null` when [AggregateTransform.apply] is running, which | 163 /// This will be non-`null` when [AggregateTransform.apply] is running, which |
| 160 /// means that it's always non-`null` when [_state] is [_State.APPLYING] or | 164 /// means that it's always non-`null` when [_state] is [_State.APPLYING] or |
| 161 /// [_State.NEEDS_APPLY], sometimes non-`null` when it's | 165 /// [_State.NEEDS_APPLY], sometimes non-`null` when it's |
| 162 /// [_State.NEEDS_DECLARE], and always `null` otherwise. | 166 /// [_State.NEEDS_DECLARE], and always `null` otherwise. |
| 163 AggregateTransformController _applyController; | 167 AggregateTransformController _applyController; |
| 164 | 168 |
| 165 TransformNode(this.phase, this.transformer, this.key, this._location) { | 169 TransformNode(this.classifier, this.transformer, this.key, this._location) { |
| 166 _forced = transformer is! DeclaringAggregateTransformer; | 170 _forced = transformer is! DeclaringAggregateTransformer; |
| 167 | 171 |
| 168 _phaseAssetSubscription = phase.previous.onAsset.listen((node) { | 172 _phaseAssetSubscription = phase.previous.onAsset.listen((node) { |
| 169 if (!_missingInputs.contains(node.id)) return; | 173 if (!_missingInputs.contains(node.id)) return; |
| 170 if (_forced) node.force(); | 174 if (_forced) node.force(); |
| 171 _dirty(); | 175 _dirty(); |
| 172 }); | 176 }); |
| 173 | 177 |
| 174 _phaseStatusSubscription = phase.previous.onStatusChange.listen((status) { | 178 _phaseStatusSubscription = phase.previous.onStatusChange.listen((status) { |
| 175 if (status == NodeStatus.RUNNING) return; | 179 if (status == NodeStatus.RUNNING) return; |
| 176 | 180 |
| 177 _maybeFinishDeclareController(); | 181 _maybeFinishDeclareController(); |
| 178 _maybeFinishApplyController(); | 182 _maybeFinishApplyController(); |
| 179 }); | 183 }); |
| 180 | 184 |
| 185 classifier.onDoneClassifying.listen((_) { |
| 186 _maybeFinishDeclareController(); |
| 187 _maybeFinishApplyController(); |
| 188 }); |
| 189 |
| 181 _run(); | 190 _run(); |
| 182 } | 191 } |
| 183 | 192 |
| 184 /// Adds [input] as a primary input for this node. | 193 /// Adds [input] as a primary input for this node. |
| 185 void addPrimary(AssetNode input) { | 194 void addPrimary(AssetNode input) { |
| 186 _primaries.add(input); | 195 _primaries.add(input); |
| 187 if (_forced) input.force(); | 196 if (_forced) input.force(); |
| 188 | 197 |
| 189 _primarySubscriptions[input.id] = input.onStateChange | 198 _primarySubscriptions[input.id] = input.onStateChange |
| 190 .listen((_) => _onPrimaryStateChange(input)); | 199 .listen((_) => _onPrimaryStateChange(input)); |
| 191 | 200 |
| 192 if (_state == _State.DECLARING && !_declareController.isDone) { | 201 if (_state == _State.DECLARING && !_declareController.isDone) { |
| 193 // If we're running `declareOutputs` and its id stream isn't closed yet, | 202 // If we're running `declareOutputs` and its id stream isn't closed yet, |
| 194 // pass this in as another id. | 203 // pass this in as another id. |
| 195 _declareController.addId(input.id); | 204 _declareController.addId(input.id); |
| 196 _maybeFinishDeclareController(); | 205 _maybeFinishDeclareController(); |
| 197 } else if (_state == _State.APPLYING) { | 206 } else if (_state == _State.APPLYING) { |
| 198 // If we're running `apply`, we need to wait until [input] is available | 207 // If we're running `apply`, we need to wait until [input] is available |
| 199 // before we pass it into the stream. If it's available now, great; if | 208 // before we pass it into the stream. If it's available now, great; if |
| 200 // not, [_onPrimaryStateChange] will handle it. | 209 // not, [_onPrimaryStateChange] will handle it. |
| 201 if (!input.state.isAvailable) return; | 210 if (!input.state.isAvailable) { |
| 211 // If we started running eagerly without being forced, abort that run if |
| 212 // a new unavailable asset comes in. |
| 213 if (input.isLazy && !_forced) _restartRun(); |
| 214 return; |
| 215 } |
| 216 |
| 202 _onPrimaryStateChange(input); | 217 _onPrimaryStateChange(input); |
| 203 _maybeFinishApplyController(); | 218 _maybeFinishApplyController(); |
| 204 } else { | 219 } else { |
| 205 // Otherwise, a new input means we'll need to re-run `declareOutputs`. | 220 // Otherwise, a new input means we'll need to re-run `declareOutputs`. |
| 206 _restartRun(); | 221 _restartRun(); |
| 207 } | 222 } |
| 208 } | 223 } |
| 209 | 224 |
| 210 /// Marks this transform as removed. | 225 /// Marks this transform as removed. |
| 211 /// | 226 /// |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 319 // re-run declare and then apply. | 334 // re-run declare and then apply. |
| 320 _restartRun(); | 335 _restartRun(); |
| 321 } else { | 336 } else { |
| 322 // If the new asset comes before the asset stream is done, we can just | 337 // If the new asset comes before the asset stream is done, we can just |
| 323 // pass it to the stream. | 338 // pass it to the stream. |
| 324 _applyController.addInput(input.asset); | 339 _applyController.addInput(input.asset); |
| 325 _maybeFinishApplyController(); | 340 _maybeFinishApplyController(); |
| 326 } | 341 } |
| 327 } else { | 342 } else { |
| 328 if (_forced) input.force(); | 343 if (_forced) input.force(); |
| 329 if (_state == _State.APPLYING && !_applyController.addedId(input.id)) { | 344 if (_state == _State.APPLYING && !_applyController.addedId(input.id) && |
| 345 (_forced || !input.isLazy)) { |
| 330 // If the input hasn't yet been added to the transform's input stream, | 346 // If the input hasn't yet been added to the transform's input stream, |
| 331 // there's no need to consider the transformation dirty. | 347 // there's no need to consider the transformation dirty. However, if the |
| 348 // input is lazy and we're running eagerly, we need to restart the |
| 349 // transformation. |
| 332 return; | 350 return; |
| 333 } | 351 } |
| 334 _dirty(); | 352 _dirty(); |
| 335 } | 353 } |
| 336 } | 354 } |
| 337 | 355 |
| 338 /// Run the entire transformation, including both `declareOutputs` (if | 356 /// Run the entire transformation, including both `declareOutputs` (if |
| 339 /// applicable) and `apply`. | 357 /// applicable) and `apply`. |
| 340 void _run() { | 358 void _run() { |
| 341 assert(_state != _State.DECLARING); | 359 assert(_state != _State.DECLARING); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 382 return; | 400 return; |
| 383 } | 401 } |
| 384 | 402 |
| 385 _state = _State.DECLARING; | 403 _state = _State.DECLARING; |
| 386 var controller = new DeclaringAggregateTransformController(this); | 404 var controller = new DeclaringAggregateTransformController(this); |
| 387 _declareController = controller; | 405 _declareController = controller; |
| 388 _streams.onLogPool.add(controller.onLog); | 406 _streams.onLogPool.add(controller.onLog); |
| 389 for (var primary in _primaries) { | 407 for (var primary in _primaries) { |
| 390 controller.addId(primary.id); | 408 controller.addId(primary.id); |
| 391 } | 409 } |
| 410 _maybeFinishDeclareController(); |
| 392 | 411 |
| 393 syncFuture(() { | 412 syncFuture(() { |
| 394 return (transformer as DeclaringAggregateTransformer) | 413 return (transformer as DeclaringAggregateTransformer) |
| 395 .declareOutputs(controller.transform); | 414 .declareOutputs(controller.transform); |
| 396 }).whenComplete(() { | 415 }).whenComplete(() { |
| 397 // Cancel the controller here even if `declareOutputs` wasn't interrupted. | 416 // Cancel the controller here even if `declareOutputs` wasn't interrupted. |
| 398 // Since the declaration is finished, we want to close out the | 417 // Since the declaration is finished, we want to close out the |
| 399 // controller's streams. | 418 // controller's streams. |
| 400 controller.cancel(); | 419 controller.cancel(); |
| 401 _declareController = null; | 420 _declareController = null; |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 550 /// | 569 /// |
| 551 /// Returns whether or not an error occurred while running the transformer. | 570 /// Returns whether or not an error occurred while running the transformer. |
| 552 Future<bool> _runApply() { | 571 Future<bool> _runApply() { |
| 553 var controller = new AggregateTransformController(this); | 572 var controller = new AggregateTransformController(this); |
| 554 _applyController = controller; | 573 _applyController = controller; |
| 555 _streams.onLogPool.add(controller.onLog); | 574 _streams.onLogPool.add(controller.onLog); |
| 556 for (var primary in _primaries) { | 575 for (var primary in _primaries) { |
| 557 if (!primary.state.isAvailable) continue; | 576 if (!primary.state.isAvailable) continue; |
| 558 controller.addInput(primary.asset); | 577 controller.addInput(primary.asset); |
| 559 } | 578 } |
| 579 _maybeFinishApplyController(); |
| 560 | 580 |
| 561 return syncFuture(() { | 581 return syncFuture(() { |
| 562 return transformer.apply(controller.transform); | 582 return transformer.apply(controller.transform); |
| 563 }).whenComplete(() { | 583 }).whenComplete(() { |
| 564 // Cancel the controller here even if `apply` wasn't interrupted. Since | 584 // Cancel the controller here even if `apply` wasn't interrupted. Since |
| 565 // the apply is finished, we want to close out the controller's streams. | 585 // the apply is finished, we want to close out the controller's streams. |
| 566 controller.cancel(); | 586 controller.cancel(); |
| 567 _applyController = null; | 587 _applyController = null; |
| 568 }).then((_) { | 588 }).then((_) { |
| 569 assert(_state != _State.DECLARED); | 589 assert(_state != _State.DECLARED); |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 684 void _consumePrimary(AssetId id) { | 704 void _consumePrimary(AssetId id) { |
| 685 var controller = _passThroughControllers.remove(id); | 705 var controller = _passThroughControllers.remove(id); |
| 686 if (controller == null) return; | 706 if (controller == null) return; |
| 687 controller.setRemoved(); | 707 controller.setRemoved(); |
| 688 } | 708 } |
| 689 | 709 |
| 690 /// If `declareOutputs` is running and all previous phases have declared their | 710 /// If `declareOutputs` is running and all previous phases have declared their |
| 691 /// outputs, mark [_declareController] as done. | 711 /// outputs, mark [_declareController] as done. |
| 692 void _maybeFinishDeclareController() { | 712 void _maybeFinishDeclareController() { |
| 693 if (_declareController == null) return; | 713 if (_declareController == null) return; |
| 714 if (classifier.isClassifying) return; |
| 694 if (phase.previous.status == NodeStatus.RUNNING) return; | 715 if (phase.previous.status == NodeStatus.RUNNING) return; |
| 695 _declareController.done(); | 716 _declareController.done(); |
| 696 } | 717 } |
| 697 | 718 |
| 698 /// If `apply` is running, all previous phases have declared their outputs, | 719 /// If `apply` is running, all previous phases have declared their outputs, |
| 699 /// and all primary inputs are available and thus have been passed to the | 720 /// and all primary inputs are available and thus have been passed to the |
| 700 /// transformer, mark [_applyController] as done. | 721 /// transformer, mark [_applyController] as done. |
| 701 void _maybeFinishApplyController() { | 722 void _maybeFinishApplyController() { |
| 702 if (_applyController == null) return; | 723 if (_applyController == null) return; |
| 724 if (classifier.isClassifying) return; |
| 703 if (_primaries.any((input) => !input.state.isAvailable)) return; | 725 if (_primaries.any((input) => !input.state.isAvailable)) return; |
| 704 if (phase.previous.status == NodeStatus.RUNNING) return; | 726 if (phase.previous.status == NodeStatus.RUNNING) return; |
| 705 _applyController.done(); | 727 _applyController.done(); |
| 706 } | 728 } |
| 707 | 729 |
| 708 BarbackException _wrapException(error, StackTrace stackTrace) { | 730 BarbackException _wrapException(error, StackTrace stackTrace) { |
| 709 if (error is! AssetNotFoundException) { | 731 if (error is! AssetNotFoundException) { |
| 710 return new TransformerException(info, error, stackTrace); | 732 return new TransformerException(info, error, stackTrace); |
| 711 } else { | 733 } else { |
| 712 return new MissingInputException(info, error.id); | 734 return new MissingInputException(info, error.id); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 774 /// declaring and [APPLYING] otherwise. If a primary input is added or | 796 /// declaring and [APPLYING] otherwise. If a primary input is added or |
| 775 /// removed, this will transition to [DECLARING]. | 797 /// removed, this will transition to [DECLARING]. |
| 776 static const APPLIED = const _State._("applied"); | 798 static const APPLIED = const _State._("applied"); |
| 777 | 799 |
| 778 final String name; | 800 final String name; |
| 779 | 801 |
| 780 const _State._(this.name); | 802 const _State._(this.name); |
| 781 | 803 |
| 782 String toString() => name; | 804 String toString() => name; |
| 783 } | 805 } |
| OLD | NEW |