| 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 import 'transformer_classifier.dart'; |
| 25 | 25 |
| 26 /// Every `_applyLogDuration`, we will issue a fine log entry letting the user |
| 27 /// know that the transform is still executing. |
| 28 const _applyLogDuration = const Duration(seconds: 10); |
| 29 |
| 26 /// Describes a transform on a set of assets and its relationship to the build | 30 /// Describes a transform on a set of assets and its relationship to the build |
| 27 /// dependency graph. | 31 /// dependency graph. |
| 28 /// | 32 /// |
| 29 /// Keeps track of whether it's dirty and needs to be run and which assets it | 33 /// Keeps track of whether it's dirty and needs to be run and which assets it |
| 30 /// depends on. | 34 /// depends on. |
| 31 class TransformNode { | 35 class TransformNode { |
| 32 /// The aggregate key for this node. | 36 /// The aggregate key for this node. |
| 33 final String key; | 37 final String key; |
| 34 | 38 |
| 35 /// The [TransformerClassifier] that [this] belongs to. | 39 /// The [TransformerClassifier] that [this] belongs to. |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 164 | 168 |
| 165 /// The controller for the currently-running [AggregateTransformer.apply] | 169 /// The controller for the currently-running [AggregateTransformer.apply] |
| 166 /// call's [AggregateTransform]. | 170 /// call's [AggregateTransform]. |
| 167 /// | 171 /// |
| 168 /// This will be non-`null` when [AggregateTransform.apply] is running, which | 172 /// This will be non-`null` when [AggregateTransform.apply] is running, which |
| 169 /// means that it's always non-`null` when [_state] is [_State.APPLYING] or | 173 /// means that it's always non-`null` when [_state] is [_State.APPLYING] or |
| 170 /// [_State.NEEDS_APPLY], sometimes non-`null` when it's | 174 /// [_State.NEEDS_APPLY], sometimes non-`null` when it's |
| 171 /// [_State.NEEDS_DECLARE], and always `null` otherwise. | 175 /// [_State.NEEDS_DECLARE], and always `null` otherwise. |
| 172 AggregateTransformController _applyController; | 176 AggregateTransformController _applyController; |
| 173 | 177 |
| 174 /// The number of secondary inputs that have been requested but not yet | 178 /// Map to track pending requests for secondary inputs. |
| 175 /// produced. | 179 /// |
| 176 int _pendingSecondaryInputs = 0; | 180 /// Keys are the secondary inputs that have been requested but not yet |
| 181 /// produced. Values are the number of requests for that input. |
| 182 final _pendingSecondaryInputs = <AssetId, int>{}; |
| 177 | 183 |
| 178 /// A stopwatch that tracks the total time spent in a transformer's `apply` | 184 /// A stopwatch that tracks the total time spent in a transformer's `apply` |
| 179 /// function. | 185 /// function. |
| 180 final _timeInTransformer = new Stopwatch(); | 186 final _timeInTransformer = new Stopwatch(); |
| 181 | 187 |
| 182 /// A stopwatch that tracks the time in a transformer's `apply` function spent | 188 /// A stopwatch that tracks the time in a transformer's `apply` function spent |
| 183 /// waiting for [getInput] calls to complete. | 189 /// waiting for [getInput] calls to complete. |
| 184 final _timeAwaitingInputs = new Stopwatch(); | 190 final _timeAwaitingInputs = new Stopwatch(); |
| 185 | 191 |
| 186 TransformNode(this.classifier, this.transformer, this.key, this._location) { | 192 TransformNode(this.classifier, this.transformer, this.key, this._location) { |
| (...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 570 _state = _State.APPLIED; | 576 _state = _State.APPLIED; |
| 571 _streams.changeStatus(NodeStatus.IDLE); | 577 _streams.changeStatus(NodeStatus.IDLE); |
| 572 }); | 578 }); |
| 573 } | 579 } |
| 574 | 580 |
| 575 /// Gets the asset for an input [id]. | 581 /// Gets the asset for an input [id]. |
| 576 /// | 582 /// |
| 577 /// If an input with [id] cannot be found, throws an [AssetNotFoundException]. | 583 /// If an input with [id] cannot be found, throws an [AssetNotFoundException]. |
| 578 Future<Asset> getInput(AssetId id) { | 584 Future<Asset> getInput(AssetId id) { |
| 579 _timeAwaitingInputs.start(); | 585 _timeAwaitingInputs.start(); |
| 580 _pendingSecondaryInputs++; | 586 _pendingSecondaryInputs[id] = _pendingSecondaryInputs.containsKey(id) |
| 587 ? _pendingSecondaryInputs[id] + 1 |
| 588 : 1; |
| 581 return phase.previous.getOutput(id).then((node) { | 589 return phase.previous.getOutput(id).then((node) { |
| 582 // Throw if the input isn't found. This ensures the transformer's apply | 590 // Throw if the input isn't found. This ensures the transformer's apply |
| 583 // is exited. We'll then catch this and report it through the proper | 591 // is exited. We'll then catch this and report it through the proper |
| 584 // results stream. | 592 // results stream. |
| 585 if (node == null) { | 593 if (node == null) { |
| 586 _missingInputs.add(id); | 594 _missingInputs.add(id); |
| 587 | 595 |
| 588 // If this id is for an asset in another package, subscribe to that | 596 // If this id is for an asset in another package, subscribe to that |
| 589 // package's asset cascade so when it starts emitting the id we know to | 597 // package's asset cascade so when it starts emitting the id we know to |
| 590 // re-run the transformer. | 598 // re-run the transformer. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 603 | 611 |
| 604 throw new AssetNotFoundException(id); | 612 throw new AssetNotFoundException(id); |
| 605 } | 613 } |
| 606 | 614 |
| 607 _secondarySubscriptions.putIfAbsent(node.id, () { | 615 _secondarySubscriptions.putIfAbsent(node.id, () { |
| 608 return node.onStateChange.listen((_) => _dirty()); | 616 return node.onStateChange.listen((_) => _dirty()); |
| 609 }); | 617 }); |
| 610 | 618 |
| 611 return node.asset; | 619 return node.asset; |
| 612 }).whenComplete(() { | 620 }).whenComplete(() { |
| 613 _pendingSecondaryInputs--; | 621 assert(_pendingSecondaryInputs.containsKey(id)); |
| 614 if (_pendingSecondaryInputs != 0) _timeAwaitingInputs.stop(); | 622 if (_pendingSecondaryInputs[id] == 1) { |
| 623 _pendingSecondaryInputs.remove(id); |
| 624 } else { |
| 625 _pendingSecondaryInputs[id]--; |
| 626 } |
| 627 if (_pendingSecondaryInputs.isEmpty) _timeAwaitingInputs.stop(); |
| 615 }); | 628 }); |
| 616 } | 629 } |
| 617 | 630 |
| 618 /// Run [AggregateTransformer.apply]. | 631 /// Run [AggregateTransformer.apply]. |
| 619 /// | 632 /// |
| 620 /// Returns whether or not an error occurred while running the transformer. | 633 /// Returns whether or not an error occurred while running the transformer. |
| 621 Future<bool> _runApply() { | 634 Future<bool> _runApply() { |
| 622 var controller = new AggregateTransformController(this); | 635 var controller = new AggregateTransformController(this); |
| 623 _applyController = controller; | 636 _applyController = controller; |
| 624 _streams.onLogPool.add(controller.onLog); | 637 _streams.onLogPool.add(controller.onLog); |
| 625 for (var primary in _primaries) { | 638 for (var primary in _primaries) { |
| 626 if (!primary.state.isAvailable) continue; | 639 if (!primary.state.isAvailable) continue; |
| 627 controller.addInput(primary.asset); | 640 controller.addInput(primary.asset); |
| 628 } | 641 } |
| 629 _maybeFinishApplyController(); | 642 _maybeFinishApplyController(); |
| 630 | 643 |
| 644 var transformCounterTimer; |
| 645 |
| 631 return syncFuture(() { | 646 return syncFuture(() { |
| 632 _timeInTransformer.reset(); | 647 _timeInTransformer.reset(); |
| 633 _timeAwaitingInputs.reset(); | 648 _timeAwaitingInputs.reset(); |
| 634 _timeInTransformer.start(); | 649 _timeInTransformer.start(); |
| 650 |
| 651 transformCounterTimer = new Timer.periodic(_applyLogDuration, (_) { |
| 652 if (_streams.onLogController.isClosed || |
| 653 !_timeInTransformer.isRunning) { |
| 654 return; |
| 655 } |
| 656 |
| 657 var message = new StringBuffer("Not yet complete after " |
| 658 "${niceDuration(_timeInTransformer.elapsed)}"); |
| 659 if (_pendingSecondaryInputs.isNotEmpty) { |
| 660 message.write(", waiting on input(s) " |
| 661 "${_pendingSecondaryInputs.keys.join(", ")}"); |
| 662 } |
| 663 _streams.onLogController.add(new LogEntry( |
| 664 info, |
| 665 info.primaryId, |
| 666 LogLevel.FINE, |
| 667 message.toString(), |
| 668 null)); |
| 669 }); |
| 670 |
| 635 return transformer.apply(controller.transform); | 671 return transformer.apply(controller.transform); |
| 636 }).whenComplete(() { | 672 }).whenComplete(() { |
| 673 transformCounterTimer.cancel(); |
| 637 _timeInTransformer.stop(); | 674 _timeInTransformer.stop(); |
| 638 _timeAwaitingInputs.stop(); | 675 _timeAwaitingInputs.stop(); |
| 639 | 676 |
| 640 // Cancel the controller here even if `apply` wasn't interrupted. Since | 677 // Cancel the controller here even if `apply` wasn't interrupted. Since |
| 641 // the apply is finished, we want to close out the controller's streams. | 678 // the apply is finished, we want to close out the controller's streams. |
| 642 controller.cancel(); | 679 controller.cancel(); |
| 643 _applyController = null; | 680 _applyController = null; |
| 644 }).then((_) { | 681 }).then((_) { |
| 645 assert(_state != _State.DECLARED); | 682 assert(_state != _State.DECLARED); |
| 646 assert(_state != _State.DECLARING); | 683 assert(_state != _State.DECLARING); |
| (...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 877 /// declaring and [APPLYING] otherwise. If a primary input is added or | 914 /// declaring and [APPLYING] otherwise. If a primary input is added or |
| 878 /// removed, this will transition to [DECLARING]. | 915 /// removed, this will transition to [DECLARING]. |
| 879 static const APPLIED = const _State._("applied"); | 916 static const APPLIED = const _State._("applied"); |
| 880 | 917 |
| 881 final String name; | 918 final String name; |
| 882 | 919 |
| 883 const _State._(this.name); | 920 const _State._(this.name); |
| 884 | 921 |
| 885 String toString() => name; | 922 String toString() => name; |
| 886 } | 923 } |
| OLD | NEW |