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

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

Issue 255483002: Expand barback's notion of dirtiness to understand declaredness. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: code review Created 6 years, 7 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
« no previous file with comments | « pkg/barback/lib/src/package_graph.dart ('k') | pkg/barback/lib/src/phase_input.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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.phase; 5 library barback.phase;
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_id.dart'; 10 import 'asset_id.dart';
11 import 'asset_node.dart'; 11 import 'asset_node.dart';
12 import 'errors.dart'; 12 import 'errors.dart';
13 import 'group_runner.dart'; 13 import 'group_runner.dart';
14 import 'log.dart'; 14 import 'log.dart';
15 import 'multiset.dart'; 15 import 'multiset.dart';
16 import 'node_status.dart';
16 import 'node_streams.dart'; 17 import 'node_streams.dart';
17 import 'phase_forwarder.dart'; 18 import 'phase_forwarder.dart';
18 import 'phase_input.dart'; 19 import 'phase_input.dart';
19 import 'phase_output.dart'; 20 import 'phase_output.dart';
20 import 'transformer.dart'; 21 import 'transformer.dart';
21 import 'transformer_group.dart'; 22 import 'transformer_group.dart';
22 import 'utils.dart'; 23 import 'utils.dart';
23 24
24 /// One phase in the ordered series of transformations in an [AssetCascade]. 25 /// One phase in the ordered series of transformations in an [AssetCascade].
25 /// 26 ///
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
73 /// group, and so shouldn't be forwarded through the phase as a whole. 74 /// group, and so shouldn't be forwarded through the phase as a whole.
74 /// 75 ///
75 /// In order to detect whether an output has been forwarded through a group or 76 /// In order to detect whether an output has been forwarded through a group or
76 /// a PhaseInput, we must be able to distinguish it from other outputs with 77 /// a PhaseInput, we must be able to distinguish it from other outputs with
77 /// the same id. To do so, we check if its origin is in [_inputOrigins]. If 78 /// the same id. To do so, we check if its origin is in [_inputOrigins]. If
78 /// so, it's been forwarded unmodified. 79 /// so, it's been forwarded unmodified.
79 final _inputOrigins = new Multiset<AssetNode>(); 80 final _inputOrigins = new Multiset<AssetNode>();
80 81
81 /// The streams exposed by this phase. 82 /// The streams exposed by this phase.
82 final _streams = new NodeStreams(); 83 final _streams = new NodeStreams();
83 Stream get onDone => _streams.onDone; 84 Stream<NodeStatus> get onStatusChange => _streams.onStatusChange;
84 Stream<AssetNode> get onAsset => _streams.onAsset; 85 Stream<AssetNode> get onAsset => _streams.onAsset;
85 Stream<LogEntry> get onLog => _streams.onLog; 86 Stream<LogEntry> get onLog => _streams.onLog;
86 87
87 /// Whether [this] is dirty and still has more processing to do. 88 /// How far along [this] is in processing its assets.
88 /// 89 NodeStatus get status {
89 /// A phase is considered dirty if any of the previous phases in the same 90 var inputStatus = NodeStatus.dirtiest(
90 /// cascade are dirty, since those phases could emit an asset that this phase 91 _inputs.values.map((input) => input.status));
91 /// will then need to process. 92 var groupStatus = NodeStatus.dirtiest(
92 bool get isDirty => (previous != null && previous.isDirty) || 93 _groups.values.map((group) => group.status));
93 _inputs.values.any((input) => input.isDirty) || 94 return (previous == null ? NodeStatus.IDLE : previous.status)
94 _groups.values.any((group) => group.isDirty); 95 .dirtier(inputStatus)
96 .dirtier(groupStatus);
97 }
95 98
96 /// The previous phase in the cascade, or null if this is the first phase. 99 /// The previous phase in the cascade, or null if this is the first phase.
97 final Phase previous; 100 final Phase previous;
98 101
99 /// The subscription to [previous]'s [onDone] stream. 102 /// The subscription to [previous]'s [onStatusChange] stream.
100 StreamSubscription _previousOnDoneSubscription; 103 StreamSubscription _previousStatusSubscription;
101 104
102 /// The subscription to [previous]'s [onAsset] stream. 105 /// The subscription to [previous]'s [onAsset] stream.
103 StreamSubscription<AssetNode> _previousOnAssetSubscription; 106 StreamSubscription<AssetNode> _previousOnAssetSubscription;
104 107
105 /// A map of asset ids to completers for [getInput] requests. 108 /// A map of asset ids to completers for [getInput] requests.
106 /// 109 ///
107 /// If an asset node is requested before it's available, we put a completer in 110 /// If an asset node is requested before it's available, we put a completer in
108 /// this map to wait for the asset to be generated. If it's not generated, the 111 /// this map to wait for the asset to be generated. If it's not generated, the
109 /// completer should complete to `null`. 112 /// completer should complete to `null`.
110 final _pendingOutputRequests = new Map<AssetId, Completer<AssetNode>>(); 113 final _pendingOutputRequests = new Map<AssetId, Completer<AssetNode>>();
111 114
112 /// Returns all currently-available output assets for this phase. 115 /// Returns all currently-available output assets for this phase.
113 Set<AssetNode> get availableOutputs { 116 Set<AssetNode> get availableOutputs {
114 return _outputs.values 117 return _outputs.values
115 .map((output) => output.output) 118 .map((output) => output.output)
116 .where((node) => node.state.isAvailable) 119 .where((node) => node.state.isAvailable)
117 .toSet(); 120 .toSet();
118 } 121 }
119 122
120 // TODO(nweiz): Rather than passing the cascade and the phase everywhere, 123 // TODO(nweiz): Rather than passing the cascade and the phase everywhere,
121 // create an interface that just exposes [getInput]. Emit errors via 124 // create an interface that just exposes [getInput]. Emit errors via
122 // [AssetNode]s. 125 // [AssetNode]s.
123 Phase(AssetCascade cascade, String location) 126 Phase(AssetCascade cascade, String location)
124 : this._(cascade, location, 0); 127 : this._(cascade, location, 0);
125 128
126 Phase._(this.cascade, this._location, this._index, [this.previous]) { 129 Phase._(this.cascade, this._location, this._index, [this.previous]) {
127 if (previous != null) { 130 if (previous != null) {
128 _previousOnAssetSubscription = previous.onAsset.listen(addInput); 131 _previousOnAssetSubscription = previous.onAsset.listen(addInput);
129 _previousOnDoneSubscription = previous.onDone.listen((_) { 132 _previousStatusSubscription = previous.onStatusChange
130 if (!isDirty) _streams.onDoneController.add(null); 133 .listen((_) => _streams.changeStatus(status));
131 });
132 } 134 }
133 135
134 onDone.listen((_) { 136 onStatusChange.listen((status) {
135 // All the previous phases have finished building. If anyone's still 137 if (status == NodeStatus.RUNNING) return;
136 // waiting for outputs, cut off the wait; we won't be generating them, 138
137 // at least until a source asset changes. 139 // All the previous phases have finished declaring or producing their
140 // outputs. If anyone's still waiting for outputs, cut off the wait; we
141 // won't be generating them, at least until a source asset changes.
138 for (var completer in _pendingOutputRequests.values) { 142 for (var completer in _pendingOutputRequests.values) {
139 completer.complete(null); 143 completer.complete(null);
140 } 144 }
141 _pendingOutputRequests.clear(); 145 _pendingOutputRequests.clear();
142 }); 146 });
143 } 147 }
144 148
145 /// Adds a new asset as an input for this phase. 149 /// Adds a new asset as an input for this phase.
146 /// 150 ///
147 /// [node] doesn't have to be [AssetState.AVAILABLE]. Once it is, the phase 151 /// [node] doesn't have to be [AssetState.AVAILABLE]. Once it is, the phase
(...skipping 17 matching lines...) Expand all
165 _handleOutputWithoutForwarder(forwarder.output); 169 _handleOutputWithoutForwarder(forwarder.output);
166 } 170 }
167 171
168 _inputOrigins.add(node.origin); 172 _inputOrigins.add(node.origin);
169 var input = new PhaseInput(this, node, "$_location.$_index"); 173 var input = new PhaseInput(this, node, "$_location.$_index");
170 _inputs[node.id] = input; 174 _inputs[node.id] = input;
171 input.input.whenRemoved(() { 175 input.input.whenRemoved(() {
172 _inputOrigins.remove(node.origin); 176 _inputOrigins.remove(node.origin);
173 _inputs.remove(node.id); 177 _inputs.remove(node.id);
174 _forwarders.remove(node.id).remove(); 178 _forwarders.remove(node.id).remove();
175 if (!isDirty) _streams.onDoneController.add(null); 179 _streams.changeStatus(status);
176 }); 180 });
177 input.onAsset.listen(_handleOutput); 181 input.onAsset.listen(_handleOutput);
178 _streams.onLogPool.add(input.onLog); 182 _streams.onLogPool.add(input.onLog);
179 input.onDone.listen((_) { 183 input.onStatusChange.listen((_) => _streams.changeStatus(status));
180 if (!isDirty) _streams.onDoneController.add(null);
181 });
182 184
183 input.updateTransformers(_transformers); 185 input.updateTransformers(_transformers);
184 186
185 for (var group in _groups.values) { 187 for (var group in _groups.values) {
186 group.addInput(node); 188 group.addInput(node);
187 } 189 }
188 } 190 }
189 191
190 // TODO(nweiz): If the output is available when this is called, it's 192 // TODO(nweiz): If the output is available when this is called, it's
191 // theoretically possible for it to become unavailable between the call and 193 // theoretically possible for it to become unavailable between the call and
(...skipping 20 matching lines...) Expand all
212 // try again, since it could be generated again. 214 // try again, since it could be generated again.
213 output.force(); 215 output.force();
214 return output.whenAvailable((_) { 216 return output.whenAvailable((_) {
215 return output; 217 return output;
216 }).catchError((error) { 218 }).catchError((error) {
217 if (error is! AssetNotFoundException) throw error; 219 if (error is! AssetNotFoundException) throw error;
218 return getOutput(id); 220 return getOutput(id);
219 }); 221 });
220 } 222 }
221 223
222 // If neither this phase nor the previous phases are dirty, the requested 224 // If this phase and the previous phases are fully declared or done, the
223 // output won't be generated and we can safely return null. 225 // requested output won't be generated and we can safely return null.
224 if (!isDirty) return null; 226 if (status != NodeStatus.RUNNING) return null;
225 227
226 // Otherwise, store a completer for the asset node. If it's generated in 228 // Otherwise, store a completer for the asset node. If it's generated in
227 // the future, we'll complete this completer. 229 // the future, we'll complete this completer.
228 var completer = _pendingOutputRequests.putIfAbsent(id, 230 var completer = _pendingOutputRequests.putIfAbsent(id,
229 () => new Completer.sync()); 231 () => new Completer.sync());
230 return completer.future; 232 return completer.future;
231 }); 233 });
232 } 234 }
233 235
234 /// Set this phase's transformers to [transformers]. 236 /// Set this phase's transformers to [transformers].
(...skipping 10 matching lines...) Expand all
245 var oldGroups = _groups.keys.toSet(); 247 var oldGroups = _groups.keys.toSet();
246 for (var removed in oldGroups.difference(newGroups)) { 248 for (var removed in oldGroups.difference(newGroups)) {
247 _groups.remove(removed).remove(); 249 _groups.remove(removed).remove();
248 } 250 }
249 251
250 for (var added in newGroups.difference(oldGroups)) { 252 for (var added in newGroups.difference(oldGroups)) {
251 var runner = new GroupRunner(cascade, added, "$_location.$_index"); 253 var runner = new GroupRunner(cascade, added, "$_location.$_index");
252 _groups[added] = runner; 254 _groups[added] = runner;
253 runner.onAsset.listen(_handleOutput); 255 runner.onAsset.listen(_handleOutput);
254 _streams.onLogPool.add(runner.onLog); 256 _streams.onLogPool.add(runner.onLog);
255 runner.onDone.listen((_) { 257 runner.onStatusChange.listen((_) => _streams.changeStatus(status));
256 if (!isDirty) _streams.onDoneController.add(null);
257 });
258 for (var input in _inputs.values) { 258 for (var input in _inputs.values) {
259 runner.addInput(input.input); 259 runner.addInput(input.input);
260 } 260 }
261 } 261 }
262 262
263 for (var forwarder in _forwarders.values) { 263 for (var forwarder in _forwarders.values) {
264 forwarder.updateTransformers(_transformers.length, _groups.length); 264 forwarder.updateTransformers(_transformers.length, _groups.length);
265 } 265 }
266 } 266 }
267 267
(...skipping 27 matching lines...) Expand all
295 /// 295 ///
296 /// This will remove all the phase's outputs. 296 /// This will remove all the phase's outputs.
297 void remove() { 297 void remove() {
298 for (var input in _inputs.values.toList()) { 298 for (var input in _inputs.values.toList()) {
299 input.remove(); 299 input.remove();
300 } 300 }
301 for (var group in _groups.values) { 301 for (var group in _groups.values) {
302 group.remove(); 302 group.remove();
303 } 303 }
304 _streams.close(); 304 _streams.close();
305 if (_previousOnDoneSubscription != null) { 305 if (_previousStatusSubscription != null) {
306 _previousOnDoneSubscription.cancel(); 306 _previousStatusSubscription.cancel();
307 } 307 }
308 if (_previousOnAssetSubscription != null) { 308 if (_previousOnAssetSubscription != null) {
309 _previousOnAssetSubscription.cancel(); 309 _previousOnAssetSubscription.cancel();
310 } 310 }
311 } 311 }
312 312
313 /// Add [asset] as an output of this phase. 313 /// Add [asset] as an output of this phase.
314 void _handleOutput(AssetNode asset) { 314 void _handleOutput(AssetNode asset) {
315 if (_inputOrigins.contains(asset.origin)) { 315 if (_inputOrigins.contains(asset.origin)) {
316 _forwarders[asset.id].addIntermediateAsset(asset); 316 _forwarders[asset.id].addIntermediateAsset(asset);
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
360 assert(asset.state.isDirty); 360 assert(asset.state.isDirty);
361 asset.force(); 361 asset.force();
362 asset.whenStateChanges().then((state) { 362 asset.whenStateChanges().then((state) {
363 if (state.isRemoved) return getOutput(asset.id); 363 if (state.isRemoved) return getOutput(asset.id);
364 return asset; 364 return asset;
365 }).then(request.complete).catchError(request.completeError); 365 }).then(request.complete).catchError(request.completeError);
366 } 366 }
367 367
368 String toString() => "phase $_location.$_index"; 368 String toString() => "phase $_location.$_index";
369 } 369 }
OLDNEW
« no previous file with comments | « pkg/barback/lib/src/package_graph.dart ('k') | pkg/barback/lib/src/phase_input.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698