| OLD | NEW |
| (Empty) | |
| 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 |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 library barback.group_runner; |
| 6 |
| 7 import 'dart:async'; |
| 8 |
| 9 import 'asset_cascade.dart'; |
| 10 import 'asset_node.dart'; |
| 11 import 'phase.dart'; |
| 12 import 'stream_pool.dart'; |
| 13 import 'transformer_group.dart'; |
| 14 |
| 15 /// A class that process all of the phases in a single transformer group. |
| 16 /// |
| 17 /// A group takes many inputs, processes them, and emits many outputs. |
| 18 class GroupRunner { |
| 19 /// The phases defined by this group. |
| 20 final _phases = new List<Phase>(); |
| 21 |
| 22 /// A stream that emits an event whenever this group becomes dirty and needs |
| 23 /// to be run. |
| 24 /// |
| 25 /// This may emit events when the group was already dirty or while processing |
| 26 /// transforms. Events are emitted synchronously to ensure that the dirty |
| 27 /// state is thoroughly propagated as soon as any assets are changed. |
| 28 Stream get onDirty => _onDirtyPool.stream; |
| 29 final _onDirtyPool = new StreamPool.broadcast(); |
| 30 |
| 31 /// Whether this group is dirty and needs to be run. |
| 32 bool get isDirty => _phases.any((phase) => phase.isDirty); |
| 33 |
| 34 // TODO(nweiz): move to a more push-based way of propagating outputs and get |
| 35 // rid of this. Once that's done, see if we can unify GroupRunner and |
| 36 // AssetCascade. |
| 37 /// The set of outputs that has been returned by [process]. |
| 38 /// |
| 39 /// [process] is expected to only return new outputs, so this is used to |
| 40 /// ensure that it does so. |
| 41 final _alreadyEmittedOutputs = new Set<AssetNode>(); |
| 42 |
| 43 GroupRunner(AssetCascade cascade, TransformerGroup group) { |
| 44 var lastPhase = new Phase(cascade, group.phases.first); |
| 45 _phases.add(lastPhase); |
| 46 for (var phase in group.phases.skip(1)) { |
| 47 lastPhase = lastPhase.addPhase(phase); |
| 48 _phases.add(lastPhase); |
| 49 } |
| 50 |
| 51 for (var phase in _phases) { |
| 52 _onDirtyPool.add(phase.onDirty); |
| 53 } |
| 54 } |
| 55 |
| 56 /// Adds a new asset as an input for this group. |
| 57 void addInput(AssetNode node) { |
| 58 _phases.first.addInput(node); |
| 59 } |
| 60 |
| 61 /// Removes this group and all sub-phases within it. |
| 62 void remove() { |
| 63 _phases.first.remove(); |
| 64 } |
| 65 |
| 66 /// Processes this group. |
| 67 /// |
| 68 /// Returns a future that completes with any new outputs produced by the |
| 69 /// group. |
| 70 Future<Set<AssetNode>> process() { |
| 71 // Process the first phase that needs to do work. |
| 72 for (var phase in _phases) { |
| 73 var future = phase.process(); |
| 74 if (future != null) return future.then((_) => process()); |
| 75 } |
| 76 |
| 77 // If we get here, all phases are done processing. |
| 78 var newOutputs = _phases.last.availableOutputs |
| 79 .difference(_alreadyEmittedOutputs); |
| 80 for (var output in newOutputs) { |
| 81 output.whenRemoved.then((_) => _alreadyEmittedOutputs.remove(output)); |
| 82 } |
| 83 _alreadyEmittedOutputs.addAll(newOutputs); |
| 84 |
| 85 return new Future.value(newOutputs); |
| 86 } |
| 87 } |
| OLD | NEW |