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 'package:async/async.dart'; | 9 import 'package:async/async.dart'; |
10 | 10 |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
61 | 61 |
62 /// The subscription to [phase]'s [Phase.onStatusChange] stream. | 62 /// The subscription to [phase]'s [Phase.onStatusChange] stream. |
63 StreamSubscription<NodeStatus> _phaseStatusSubscription; | 63 StreamSubscription<NodeStatus> _phaseStatusSubscription; |
64 | 64 |
65 /// How far along [this] is in processing its assets. | 65 /// How far along [this] is in processing its assets. |
66 NodeStatus get status { | 66 NodeStatus get status { |
67 if (_state == _State.APPLIED || _state == _State.DECLARED) { | 67 if (_state == _State.APPLIED || _state == _State.DECLARED) { |
68 return NodeStatus.IDLE; | 68 return NodeStatus.IDLE; |
69 } | 69 } |
70 | 70 |
71 if (_declaring && _state != _State.DECLARING && | 71 if (_declaring && |
| 72 _state != _State.DECLARING && |
72 _state != _State.NEEDS_DECLARE) { | 73 _state != _State.NEEDS_DECLARE) { |
73 return NodeStatus.MATERIALIZING; | 74 return NodeStatus.MATERIALIZING; |
74 } else { | 75 } else { |
75 return NodeStatus.RUNNING; | 76 return NodeStatus.RUNNING; |
76 } | 77 } |
77 } | 78 } |
78 | 79 |
79 /// The [TransformInfo] describing this node. | 80 /// The [TransformInfo] describing this node. |
80 /// | 81 /// |
81 /// [TransformInfo] is the publicly-visible representation of a transform | 82 /// [TransformInfo] is the publicly-visible representation of a transform |
82 /// node. | 83 /// node. |
83 TransformInfo get info => new TransformInfo(transformer, | 84 TransformInfo get info => |
84 new AssetId(phase.cascade.package, key)); | 85 new TransformInfo(transformer, new AssetId(phase.cascade.package, key)); |
85 | 86 |
86 /// Whether this is a declaring transform. | 87 /// Whether this is a declaring transform. |
87 /// | 88 /// |
88 /// This is usually identical to `transformer is | 89 /// This is usually identical to `transformer is |
89 /// DeclaringAggregateTransformer`, but if a declaring and non-lazy | 90 /// DeclaringAggregateTransformer`, but if a declaring and non-lazy |
90 /// transformer emits an error during `declareOutputs` it's treated as though | 91 /// transformer emits an error during `declareOutputs` it's treated as though |
91 /// it wasn't declaring. | 92 /// it wasn't declaring. |
92 bool get _declaring => transformer is DeclaringAggregateTransformer && | 93 bool get _declaring => |
| 94 transformer is DeclaringAggregateTransformer && |
93 (_state == _State.DECLARING || _declaredOutputs != null); | 95 (_state == _State.DECLARING || _declaredOutputs != null); |
94 | 96 |
95 /// Whether this transform has been forced since it last finished applying. | 97 /// Whether this transform has been forced since it last finished applying. |
96 /// | 98 /// |
97 /// A transform being forced means it should run until it generates outputs | 99 /// A transform being forced means it should run until it generates outputs |
98 /// and is no longer dirty. This is always true for non-declaring | 100 /// and is no longer dirty. This is always true for non-declaring |
99 /// transformers, since they always need to eagerly generate outputs. | 101 /// transformers, since they always need to eagerly generate outputs. |
100 bool _forced; | 102 bool _forced; |
101 | 103 |
102 /// The subscriptions to each secondary input's [AssetNode.onStateChange] | 104 /// The subscriptions to each secondary input's [AssetNode.onStateChange] |
(...skipping 30 matching lines...) Expand all Loading... |
133 /// The current state of [this]. | 135 /// The current state of [this]. |
134 var _state = _State.DECLARED; | 136 var _state = _State.DECLARED; |
135 | 137 |
136 /// Whether [this] has been marked as removed. | 138 /// Whether [this] has been marked as removed. |
137 bool get _isRemoved => _streams.onAssetController.isClosed; | 139 bool get _isRemoved => _streams.onAssetController.isClosed; |
138 | 140 |
139 // If [transformer] is declaring but not lazy and [primary] is available, we | 141 // If [transformer] is declaring but not lazy and [primary] is available, we |
140 // can run [apply] even if [force] hasn't been called, since [transformer] | 142 // can run [apply] even if [force] hasn't been called, since [transformer] |
141 // should run eagerly if possible. | 143 // should run eagerly if possible. |
142 bool get _canRunDeclaringEagerly => | 144 bool get _canRunDeclaringEagerly => |
143 _declaring && transformer is! LazyAggregateTransformer && | 145 _declaring && |
| 146 transformer is! LazyAggregateTransformer && |
144 _primaries.every((input) => input.state.isAvailable); | 147 _primaries.every((input) => input.state.isAvailable); |
145 | 148 |
146 /// Which primary inputs the most recent run of this transform has declared | 149 /// Which primary inputs the most recent run of this transform has declared |
147 /// that it consumes. | 150 /// that it consumes. |
148 /// | 151 /// |
149 /// This starts out `null`, indicating that the transform hasn't declared | 152 /// This starts out `null`, indicating that the transform hasn't declared |
150 /// anything yet. This is not meaningful unless [_state] is [_State.APPLIED] | 153 /// anything yet. This is not meaningful unless [_state] is [_State.APPLIED] |
151 /// or [_State.DECLARED]. | 154 /// or [_State.DECLARED]. |
152 Set<AssetId> _consumedPrimaries; | 155 Set<AssetId> _consumedPrimaries; |
153 | 156 |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
213 }); | 216 }); |
214 | 217 |
215 _run(); | 218 _run(); |
216 } | 219 } |
217 | 220 |
218 /// Adds [input] as a primary input for this node. | 221 /// Adds [input] as a primary input for this node. |
219 void addPrimary(AssetNode input) { | 222 void addPrimary(AssetNode input) { |
220 _primaries.add(input); | 223 _primaries.add(input); |
221 if (_forced) input.force(); | 224 if (_forced) input.force(); |
222 | 225 |
223 _primarySubscriptions[input.id] = input.onStateChange | 226 _primarySubscriptions[input.id] = |
224 .listen((_) => _onPrimaryStateChange(input)); | 227 input.onStateChange.listen((_) => _onPrimaryStateChange(input)); |
225 | 228 |
226 if (_state == _State.DECLARING && !_declareController.isDone) { | 229 if (_state == _State.DECLARING && !_declareController.isDone) { |
227 // If we're running `declareOutputs` and its id stream isn't closed yet, | 230 // If we're running `declareOutputs` and its id stream isn't closed yet, |
228 // pass this in as another id. | 231 // pass this in as another id. |
229 _declareController.addId(input.id); | 232 _declareController.addId(input.id); |
230 _maybeFinishDeclareController(); | 233 _maybeFinishDeclareController(); |
231 } else if (_state == _State.APPLYING) { | 234 } else if (_state == _State.APPLYING) { |
232 // If we're running `apply`, we need to wait until [input] is available | 235 // If we're running `apply`, we need to wait until [input] is available |
233 // before we pass it into the stream. If it's available now, great; if | 236 // before we pass it into the stream. If it's available now, great; if |
234 // not, [_onPrimaryStateChange] will handle it. | 237 // not, [_onPrimaryStateChange] will handle it. |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
285 if (_state == _State.DECLARED) _apply(); | 288 if (_state == _State.DECLARED) _apply(); |
286 } | 289 } |
287 | 290 |
288 /// Marks this transform as dirty. | 291 /// Marks this transform as dirty. |
289 /// | 292 /// |
290 /// Specifically, this should be called when one of the transform's inputs' | 293 /// Specifically, this should be called when one of the transform's inputs' |
291 /// contents change, or when a secondary input is removed. Primary inputs | 294 /// contents change, or when a secondary input is removed. Primary inputs |
292 /// being added or removed are handled by [addInput] and | 295 /// being added or removed are handled by [addInput] and |
293 /// [_onPrimaryStateChange]. | 296 /// [_onPrimaryStateChange]. |
294 void _dirty() { | 297 void _dirty() { |
295 if (_state == _State.DECLARING || _state == _State.NEEDS_DECLARE || | 298 if (_state == _State.DECLARING || |
| 299 _state == _State.NEEDS_DECLARE || |
296 _state == _State.NEEDS_APPLY) { | 300 _state == _State.NEEDS_APPLY) { |
297 // If we already know that [_apply] needs to be run, there's nothing to do | 301 // If we already know that [_apply] needs to be run, there's nothing to do |
298 // here. | 302 // here. |
299 return; | 303 return; |
300 } | 304 } |
301 | 305 |
302 if (!_forced && !_canRunDeclaringEagerly) { | 306 if (!_forced && !_canRunDeclaringEagerly) { |
303 // [forced] should only ever be false for a declaring transformer. | 307 // [forced] should only ever be false for a declaring transformer. |
304 assert(_declaring); | 308 assert(_declaring); |
305 | 309 |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
370 // pass it to the stream. | 374 // pass it to the stream. |
371 _applyController.addInput(input.asset); | 375 _applyController.addInput(input.asset); |
372 _maybeFinishApplyController(); | 376 _maybeFinishApplyController(); |
373 } | 377 } |
374 } else { | 378 } else { |
375 if (_forced) input.force(); | 379 if (_forced) input.force(); |
376 | 380 |
377 var controller = _passThroughControllers[input.id]; | 381 var controller = _passThroughControllers[input.id]; |
378 if (controller != null) controller.setDirty(); | 382 if (controller != null) controller.setDirty(); |
379 | 383 |
380 if (_state == _State.APPLYING && !_applyController.addedId(input.id) && | 384 if (_state == _State.APPLYING && |
| 385 !_applyController.addedId(input.id) && |
381 (_forced || !input.isLazy)) { | 386 (_forced || !input.isLazy)) { |
382 // If the input hasn't yet been added to the transform's input stream, | 387 // If the input hasn't yet been added to the transform's input stream, |
383 // there's no need to consider the transformation dirty. However, if the | 388 // there's no need to consider the transformation dirty. However, if the |
384 // input is lazy and we're running eagerly, we need to restart the | 389 // input is lazy and we're running eagerly, we need to restart the |
385 // transformation. | 390 // transformation. |
386 return; | 391 return; |
387 } | 392 } |
388 _dirty(); | 393 _dirty(); |
389 } | 394 } |
390 } | 395 } |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
465 // If `declareOutputs` fails, fall back to treating a declaring | 470 // If `declareOutputs` fails, fall back to treating a declaring |
466 // transformer as though it were eager. | 471 // transformer as though it were eager. |
467 if (transformer is! LazyAggregateTransformer) _forced = true; | 472 if (transformer is! LazyAggregateTransformer) _forced = true; |
468 callback(); | 473 callback(); |
469 return; | 474 return; |
470 } | 475 } |
471 | 476 |
472 _consumedPrimaries = controller.consumedPrimaries; | 477 _consumedPrimaries = controller.consumedPrimaries; |
473 _declaredOutputs = controller.outputIds; | 478 _declaredOutputs = controller.outputIds; |
474 var invalidIds = _declaredOutputs | 479 var invalidIds = _declaredOutputs |
475 .where((id) => id.package != phase.cascade.package).toSet(); | 480 .where((id) => id.package != phase.cascade.package) |
| 481 .toSet(); |
476 for (var id in invalidIds) { | 482 for (var id in invalidIds) { |
477 _declaredOutputs.remove(id); | 483 _declaredOutputs.remove(id); |
478 // TODO(nweiz): report this as a warning rather than a failing error. | 484 // TODO(nweiz): report this as a warning rather than a failing error. |
479 phase.cascade.reportError(new InvalidOutputException(info, id)); | 485 phase.cascade.reportError(new InvalidOutputException(info, id)); |
480 } | 486 } |
481 | 487 |
482 for (var primary in _primaries) { | 488 for (var primary in _primaries) { |
483 if (_declaredOutputs.contains(primary.id)) continue; | 489 if (_declaredOutputs.contains(primary.id)) continue; |
484 _passThrough(primary.id); | 490 _passThrough(primary.id); |
485 } | 491 } |
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
656 return; | 662 return; |
657 } | 663 } |
658 | 664 |
659 var message = new StringBuffer("Not yet complete after " | 665 var message = new StringBuffer("Not yet complete after " |
660 "${niceDuration(_timeInTransformer.elapsed)}"); | 666 "${niceDuration(_timeInTransformer.elapsed)}"); |
661 if (_pendingSecondaryInputs.isNotEmpty) { | 667 if (_pendingSecondaryInputs.isNotEmpty) { |
662 message.write(", waiting on input(s) " | 668 message.write(", waiting on input(s) " |
663 "${_pendingSecondaryInputs.keys.join(", ")}"); | 669 "${_pendingSecondaryInputs.keys.join(", ")}"); |
664 } | 670 } |
665 _streams.onLogController.add(new LogEntry( | 671 _streams.onLogController.add(new LogEntry( |
666 info, | 672 info, info.primaryId, LogLevel.FINE, message.toString(), null)); |
667 info.primaryId, | |
668 LogLevel.FINE, | |
669 message.toString(), | |
670 null)); | |
671 }); | 673 }); |
672 | 674 |
673 return transformer.apply(controller.transform); | 675 return transformer.apply(controller.transform); |
674 }).whenComplete(() { | 676 }).whenComplete(() { |
675 transformCounterTimer.cancel(); | 677 transformCounterTimer.cancel(); |
676 _timeInTransformer.stop(); | 678 _timeInTransformer.stop(); |
677 _timeAwaitingInputs.stop(); | 679 _timeAwaitingInputs.stop(); |
678 | 680 |
679 // Cancel the controller here even if `apply` wasn't interrupted. Since | 681 // Cancel the controller here even if `apply` wasn't interrupted. Since |
680 // the apply is finished, we want to close out the controller's streams. | 682 // the apply is finished, we want to close out the controller's streams. |
(...skipping 14 matching lines...) Expand all Loading... |
695 if (_state == _State.NEEDS_APPLY) return false; | 697 if (_state == _State.NEEDS_APPLY) return false; |
696 if (_state == _State.NEEDS_DECLARE) return false; | 698 if (_state == _State.NEEDS_DECLARE) return false; |
697 if (controller.loggedError) return true; | 699 if (controller.loggedError) return true; |
698 | 700 |
699 // If the transformer took long enough, log its duration in fine output. | 701 // If the transformer took long enough, log its duration in fine output. |
700 // That way it's not always visible, but users running with "pub serve | 702 // That way it's not always visible, but users running with "pub serve |
701 // --verbose" can see it. | 703 // --verbose" can see it. |
702 var ranLong = _timeInTransformer.elapsed > new Duration(seconds: 1); | 704 var ranLong = _timeInTransformer.elapsed > new Duration(seconds: 1); |
703 var ranLongLocally = | 705 var ranLongLocally = |
704 _timeInTransformer.elapsed - _timeAwaitingInputs.elapsed > | 706 _timeInTransformer.elapsed - _timeAwaitingInputs.elapsed > |
705 new Duration(milliseconds: 200); | 707 new Duration(milliseconds: 200); |
706 | 708 |
707 // Report the transformer's timing information if it spent more than 0.2s | 709 // Report the transformer's timing information if it spent more than 0.2s |
708 // doing things other than waiting for its secondary inputs or if it spent | 710 // doing things other than waiting for its secondary inputs or if it spent |
709 // more than 1s in total. | 711 // more than 1s in total. |
710 if (ranLongLocally || ranLong) { | 712 if (ranLongLocally || ranLong) { |
711 _streams.onLogController.add(new LogEntry( | 713 _streams.onLogController.add(new LogEntry( |
712 info, info.primaryId, LogLevel.FINE, | 714 info, |
| 715 info.primaryId, |
| 716 LogLevel.FINE, |
713 "Took ${niceDuration(_timeInTransformer.elapsed)} " | 717 "Took ${niceDuration(_timeInTransformer.elapsed)} " |
714 "(${niceDuration(_timeAwaitingInputs.elapsed)} awaiting " | 718 "(${niceDuration(_timeAwaitingInputs.elapsed)} awaiting " |
715 "secondary inputs).", | 719 "secondary inputs).", |
716 null)); | 720 null)); |
717 } | 721 } |
718 | 722 |
719 _handleApplyResults(controller); | 723 _handleApplyResults(controller); |
720 return false; | 724 return false; |
721 }).catchError((error, stackTrace) { | 725 }).catchError((error, stackTrace) { |
722 // If the transform became dirty while processing, ignore any errors from | 726 // If the transform became dirty while processing, ignore any errors from |
723 // it. | 727 // it. |
724 if (_state == _State.NEEDS_APPLY || _isRemoved) return false; | 728 if (_state == _State.NEEDS_APPLY || _isRemoved) return false; |
725 | 729 |
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
916 /// declaring and [APPLYING] otherwise. If a primary input is added or | 920 /// declaring and [APPLYING] otherwise. If a primary input is added or |
917 /// removed, this will transition to [DECLARING]. | 921 /// removed, this will transition to [DECLARING]. |
918 static const APPLIED = const _State._("applied"); | 922 static const APPLIED = const _State._("applied"); |
919 | 923 |
920 final String name; | 924 final String name; |
921 | 925 |
922 const _State._(this.name); | 926 const _State._(this.name); |
923 | 927 |
924 String toString() => name; | 928 String toString() => name; |
925 } | 929 } |
OLD | NEW |