Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(55)

Side by Side Diff: pkg/barback/lib/src/group_runner.dart

Issue 187263003: Move Barback to a more thoroughly push-based model. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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.group_runner; 5 library barback.group_runner;
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_node.dart'; 10 import 'asset_node.dart';
11 import 'log.dart'; 11 import 'log.dart';
12 import 'phase.dart'; 12 import 'phase.dart';
13 import 'stream_pool.dart'; 13 import 'stream_pool.dart';
14 import 'transformer_group.dart'; 14 import 'transformer_group.dart';
15 15
16 /// A class that processes all of the phases in a single transformer group. 16 /// A class that processes all of the phases in a single transformer group.
17 /// 17 ///
18 /// A group takes many inputs, processes them, and emits many outputs. 18 /// A group takes many inputs, processes them, and emits many outputs.
19 class GroupRunner { 19 class GroupRunner {
20 /// The group this runner runs. 20 /// The group this runner runs.
21 final TransformerGroup _group; 21 final TransformerGroup _group;
22 22
23 /// A string describing the location of [this] in the transformer graph. 23 /// A string describing the location of [this] in the transformer graph.
24 final String _location; 24 final String _location;
25 25
26 /// The phases defined by this group. 26 /// The phases defined by this group.
27 final _phases = new List<Phase>(); 27 final _phases = new List<Phase>();
28 28
29 /// A stream that emits an event whenever this group becomes dirty and needs 29 /// Whether [this] is dirty and still has more processing to do.
30 /// to be run. 30 bool get isDirty => _phases.any((phase) => phase.isDirty);
31
32 /// A stream that emits an event whenever [this] is no longer dirty.
31 /// 33 ///
32 /// This may emit events when the group was already dirty or while processing 34 /// This is synchronous in order to guarantee that it will emit an event as
33 /// transforms. Events are emitted synchronously to ensure that the dirty 35 /// soon as [isDirty] flips from `true` to `false`.
34 /// state is thoroughly propagated as soon as any assets are changed. 36 Stream get onDone => _onDoneController.stream;
35 Stream get onDirty => _onDirtyPool.stream; 37 final _onDoneController = new StreamController.broadcast(sync: true);
36 final _onDirtyPool = new StreamPool.broadcast();
37 38
38 /// Whether this group is dirty and needs to be run. 39 /// A stream that emits any new assets emitted by [this].
39 bool get isDirty => _phases.any((phase) => phase.isDirty); 40 ///
41 /// Assets are emitted synchronously to ensure that any changes are thoroughly
42 /// propagated as soon as they occur.
43 Stream<AssetNode> get onAsset => _onAssetPool.stream;
44 final _onAssetPool = new StreamPool<AssetNode>();
40 45
41 /// A stream that emits an event whenever any transforms in this group logs 46 /// A stream that emits an event whenever any transforms in this group logs
42 /// an entry. 47 /// an entry.
43 Stream<LogEntry> get onLog => _onLogPool.stream; 48 Stream<LogEntry> get onLog => _onLogPool.stream;
44 final _onLogPool = new StreamPool<LogEntry>.broadcast(); 49 final _onLogPool = new StreamPool<LogEntry>.broadcast();
45 50
46 // TODO(nweiz): move to a more push-based way of propagating outputs and get
47 // rid of this. Once that's done, see if we can unify GroupRunner and
48 // AssetCascade.
49 /// The set of outputs that has been returned by [process].
50 ///
51 /// [process] is expected to only return new outputs, so this is used to
52 /// ensure that it does so.
53 final _alreadyEmittedOutputs = new Set<AssetNode>();
54
55 GroupRunner(AssetCascade cascade, this._group, this._location) { 51 GroupRunner(AssetCascade cascade, this._group, this._location) {
56 var lastPhase = new Phase(cascade, _group.phases.first, _location); 52 _addPhase(new Phase(cascade, _location), _group.phases.first);
57 _phases.add(lastPhase);
58 for (var phase in _group.phases.skip(1)) { 53 for (var phase in _group.phases.skip(1)) {
59 lastPhase = lastPhase.addPhase(phase); 54 _addPhase(_phases.last.addPhase(), phase);
60 _phases.add(lastPhase);
61 }
62
63 for (var phase in _phases) {
64 _onDirtyPool.add(phase.onDirty);
65 _onLogPool.add(phase.onLog);
66 } 55 }
67 } 56 }
68 57
58 /// Add a phase with [contents] to [this]'s list of phases.
59 ///
60 /// [contents] should be an inner [Iterable] from a [TransformGroup.phases]
61 /// value.
62 void _addPhase(Phase phase, Iterable contents) {
63 _phases.add(phase);
64 _onAssetPool.add(phase.onAsset);
65 _onLogPool.add(phase.onLog);
66 phase.onDone.listen((_) {
Bob Nystrom 2014/03/05 22:13:25 Do we need to listen to this on all phases, or jus
nweiz 2014/03/06 00:29:08 It's possible for a middle phase to go dirty and t
67 if (!isDirty) _onDoneController.add(null);
68 });
69 phase.updateTransformers(contents);
70 }
71
69 /// Force all [LazyTransformer]s' transforms in this group to begin producing 72 /// Force all [LazyTransformer]s' transforms in this group to begin producing
70 /// concrete assets. 73 /// concrete assets.
71 void forceAllTransforms() { 74 void forceAllTransforms() {
72 for (var phase in _phases) { 75 for (var phase in _phases) {
73 phase.forceAllTransforms(); 76 phase.forceAllTransforms();
74 } 77 }
75 } 78 }
76 79
77 /// Adds a new asset as an input for this group. 80 /// Adds a new asset as an input for this group.
78 void addInput(AssetNode node) { 81 void addInput(AssetNode node) {
79 _phases.first.addInput(node); 82 _phases.first.addInput(node);
80 } 83 }
81 84
82 /// Removes this group and all sub-phases within it. 85 /// Removes this group and all sub-phases within it.
83 void remove() { 86 void remove() {
84 _phases.first.remove(); 87 _phases.first.remove();
85 } 88 }
86 89
87 /// Processes this group.
88 ///
89 /// Returns a future that completes with any new outputs produced by the
90 /// group.
91 Future<Set<AssetNode>> process() {
92 // Process the first phase that needs to do work.
93 for (var phase in _phases) {
94 var future = phase.process();
95 if (future != null) return future.then((_) => process());
96 }
97
98 // If we get here, all phases are done processing.
99 var newOutputs = _phases.last.availableOutputs
100 .difference(_alreadyEmittedOutputs);
101 for (var output in newOutputs) {
102 output.whenRemoved(() => _alreadyEmittedOutputs.remove(output));
103 }
104 _alreadyEmittedOutputs.addAll(newOutputs);
105
106 return new Future.value(newOutputs);
107 }
108
109 String toString() => "group in phase $_location for $_group"; 90 String toString() => "group in phase $_location for $_group";
110 } 91 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698