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

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

Issue 21446002: Add events in barback to bubble up the dirty bit. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Close TransformNode.onDirty. Created 7 years, 4 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/asset_cascade.dart ('k') | pkg/barback/lib/src/stream_pool.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.dart'; 9 import 'asset.dart';
10 import 'asset_cascade.dart'; 10 import 'asset_cascade.dart';
11 import 'asset_id.dart'; 11 import 'asset_id.dart';
12 import 'asset_node.dart'; 12 import 'asset_node.dart';
13 import 'asset_set.dart'; 13 import 'asset_set.dart';
14 import 'errors.dart'; 14 import 'errors.dart';
15 import 'stream_pool.dart';
15 import 'transform_node.dart'; 16 import 'transform_node.dart';
16 import 'transformer.dart'; 17 import 'transformer.dart';
17 import 'utils.dart'; 18 import 'utils.dart';
18 19
19 /// One phase in the ordered series of transformations in an [AssetCascade]. 20 /// One phase in the ordered series of transformations in an [AssetCascade].
20 /// 21 ///
21 /// Each phase can access outputs from previous phases and can in turn pass 22 /// Each phase can access outputs from previous phases and can in turn pass
22 /// outputs to later phases. Phases are processed strictly serially. All 23 /// outputs to later phases. Phases are processed strictly serially. All
23 /// transforms in a phase will be complete before moving on to the next phase. 24 /// transforms in a phase will be complete before moving on to the next phase.
24 /// Within a single phase, all transforms will be run in parallel. 25 /// Within a single phase, all transforms will be run in parallel.
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
66 /// New asset nodes that were added while [_adjustTransformers] was still 67 /// New asset nodes that were added while [_adjustTransformers] was still
67 /// being run on an old version of that asset. 68 /// being run on an old version of that asset.
68 var _pendingNewInputs = new Map<AssetId, AssetNode>(); 69 var _pendingNewInputs = new Map<AssetId, AssetNode>();
69 70
70 /// The ids of assets that are emitted by transforms in this phase. 71 /// The ids of assets that are emitted by transforms in this phase.
71 /// 72 ///
72 /// This is used to detect collisions where multiple transforms emit the same 73 /// This is used to detect collisions where multiple transforms emit the same
73 /// output. 74 /// output.
74 final _outputs = new Set<AssetId>(); 75 final _outputs = new Set<AssetId>();
75 76
77 /// A stream that emits an event whenever this phase becomes dirty and needs
78 /// to be run.
79 ///
80 /// This may emit events when the phase was already dirty or while processing
81 /// transforms. Events are emitted synchronously to ensure that the dirty
82 /// state is thoroughly propagated as soon as any assets are changed.
83 Stream get onDirty => _onDirtyPool.stream;
84 final _onDirtyPool = new StreamPool.broadcast();
85
86 /// A controller whose stream feeds into [_onDirtyPool].
87 ///
88 /// This is used whenever an input is added, changed, or removed. It's
89 /// sometimes redundant with the events collected from [_transforms], but this
90 /// stream is necessary for new and removed inputs, and the transform stream
91 /// is necessary for modified secondary inputs.
92 final _onDirtyController = new StreamController.broadcast(sync: true);
93
76 /// The phase after this one. 94 /// The phase after this one.
77 /// 95 ///
78 /// Outputs from this phase will be passed to it. 96 /// Outputs from this phase will be passed to it.
79 final Phase _next; 97 final Phase _next;
80 98
81 Phase(this.cascade, this._index, this._transformers, this._next); 99 Phase(this.cascade, this._index, this._transformers, this._next) {
100 _onDirtyPool.add(_onDirtyController.stream);
101 }
82 102
83 /// Adds a new asset as an input for this phase. 103 /// Adds a new asset as an input for this phase.
84 /// 104 ///
85 /// [node] doesn't have to be [AssetState.AVAILABLE]. Once it is, the phase 105 /// [node] doesn't have to be [AssetState.AVAILABLE]. Once it is, the phase
86 /// will automatically begin determining which transforms can consume it as a 106 /// will automatically begin determining which transforms can consume it as a
87 /// primary input. The transforms themselves won't be applied until [process] 107 /// primary input. The transforms themselves won't be applied until [process]
88 /// is called, however. 108 /// is called, however.
89 /// 109 ///
90 /// This should only be used for brand-new assets or assets that have been 110 /// This should only be used for brand-new assets or assets that have been
91 /// removed and re-created. The phase will automatically handle updated assets 111 /// removed and re-created. The phase will automatically handle updated assets
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
161 return inputs[id]; 181 return inputs[id];
162 } 182 }
163 183
164 /// Asynchronously determines which transformers can consume [node] as a 184 /// Asynchronously determines which transformers can consume [node] as a
165 /// primary input and creates transforms for them. 185 /// primary input and creates transforms for them.
166 /// 186 ///
167 /// This ensures that if [node] is modified or removed during or after the 187 /// This ensures that if [node] is modified or removed during or after the
168 /// time it takes to adjust its transformers, they're appropriately 188 /// time it takes to adjust its transformers, they're appropriately
169 /// re-adjusted. Its progress can be tracked in [_adjustTransformersFutures]. 189 /// re-adjusted. Its progress can be tracked in [_adjustTransformersFutures].
170 void _adjustTransformers(AssetNode node) { 190 void _adjustTransformers(AssetNode node) {
191 // Mark the phase as dirty. This may not actually end up creating any new
192 // transforms, but we want adding or removing a source asset to consistently
193 // kick off a build, even if that build does nothing.
194 _onDirtyController.add(null);
195
171 // Once the input is available, hook up transformers for it. If it changes 196 // Once the input is available, hook up transformers for it. If it changes
172 // while that's happening, try again. 197 // while that's happening, try again.
173 _adjustTransformersFutures[node.id] = node.tryUntilStable((asset) { 198 _adjustTransformersFutures[node.id] = node.tryUntilStable((asset) {
174 var oldTransformers = _transforms[node.id] 199 var oldTransformers = _transforms[node.id]
175 .map((transform) => transform.transformer).toSet(); 200 .map((transform) => transform.transformer).toSet();
176 201
177 return _removeStaleTransforms(asset) 202 return _removeStaleTransforms(asset)
178 .then((_) => _addFreshTransforms(node, oldTransformers)); 203 .then((_) => _addFreshTransforms(node, oldTransformers));
179 }).then((_) { 204 }).then((_) {
180 // Now all the transforms are set up correctly and the asset is available 205 // Now all the transforms are set up correctly and the asset is available
181 // for the time being. Set up handlers for when the asset changes in the 206 // for the time being. Set up handlers for when the asset changes in the
182 // future. 207 // future.
183 node.onStateChange.first.then((state) { 208 node.onStateChange.first.then((state) {
184 if (state.isRemoved) { 209 if (state.isRemoved) {
210 _onDirtyController.add(null);
185 _transforms.remove(node.id); 211 _transforms.remove(node.id);
186 } else { 212 } else {
187 _adjustTransformers(node); 213 _adjustTransformers(node);
188 } 214 }
189 }).catchError((e) { 215 }).catchError((e) {
190 _adjustTransformersFutures[node.id] = new Future.error(e); 216 _adjustTransformersFutures[node.id] = new Future.error(e);
191 }); 217 });
192 }).catchError((error) { 218 }).catchError((error) {
193 if (error is! AssetNotFoundException || error.id != node.id) throw error; 219 if (error is! AssetNotFoundException || error.id != node.id) throw error;
194 220
(...skipping 12 matching lines...) Expand all
207 233
208 // Remove any old transforms that used to have [asset] as a primary asset but 234 // Remove any old transforms that used to have [asset] as a primary asset but
209 // no longer apply to its new contents. 235 // no longer apply to its new contents.
210 Future _removeStaleTransforms(Asset asset) { 236 Future _removeStaleTransforms(Asset asset) {
211 return Future.wait(_transforms[asset.id].map((transform) { 237 return Future.wait(_transforms[asset.id].map((transform) {
212 // TODO(rnystrom): Catch all errors from isPrimary() and redirect to 238 // TODO(rnystrom): Catch all errors from isPrimary() and redirect to
213 // results. 239 // results.
214 return transform.transformer.isPrimary(asset).then((isPrimary) { 240 return transform.transformer.isPrimary(asset).then((isPrimary) {
215 if (isPrimary) return; 241 if (isPrimary) return;
216 _transforms[asset.id].remove(transform); 242 _transforms[asset.id].remove(transform);
243 _onDirtyPool.remove(transform.onDirty);
217 transform.remove(); 244 transform.remove();
218 }); 245 });
219 })); 246 }));
220 } 247 }
221 248
222 // Add new transforms for transformers that consider [node]'s asset to be a 249 // Add new transforms for transformers that consider [node]'s asset to be a
223 // primary input. 250 // primary input.
224 // 251 //
225 // [oldTransformers] is the set of transformers that had [node] as a primary 252 // [oldTransformers] is the set of transformers that had [node] as a primary
226 // input prior to this. They don't need to be checked, since they were removed 253 // input prior to this. They don't need to be checked, since they were removed
227 // or preserved in [_removeStaleTransforms]. 254 // or preserved in [_removeStaleTransforms].
228 Future _addFreshTransforms(AssetNode node, Set<Transformer> oldTransformers) { 255 Future _addFreshTransforms(AssetNode node, Set<Transformer> oldTransformers) {
229 return Future.wait(_transformers.map((transformer) { 256 return Future.wait(_transformers.map((transformer) {
230 if (oldTransformers.contains(transformer)) return new Future.value(); 257 if (oldTransformers.contains(transformer)) return new Future.value();
231 258
232 // If the asset is unavailable, the results of this [_adjustTransformers] 259 // If the asset is unavailable, the results of this [_adjustTransformers]
233 // run will be discarded, so we can just short-circuit. 260 // run will be discarded, so we can just short-circuit.
234 if (node.asset == null) return new Future.value(); 261 if (node.asset == null) return new Future.value();
235 262
236 // We can safely access [node.asset] here even though it might have 263 // We can safely access [node.asset] here even though it might have
237 // changed since (as above) if it has, [_adjustTransformers] will just be 264 // changed since (as above) if it has, [_adjustTransformers] will just be
238 // re-run. 265 // re-run.
239 // TODO(rnystrom): Catch all errors from isPrimary() and redirect to 266 // TODO(rnystrom): Catch all errors from isPrimary() and redirect to
240 // results. 267 // results.
241 return transformer.isPrimary(node.asset).then((isPrimary) { 268 return transformer.isPrimary(node.asset).then((isPrimary) {
242 if (!isPrimary) return; 269 if (!isPrimary) return;
243 _transforms[node.id].add(new TransformNode(this, transformer, node)); 270 var transform = new TransformNode(this, transformer, node);
271 _transforms[node.id].add(transform);
272 _onDirtyPool.add(transform.onDirty);
244 }); 273 });
245 })); 274 }));
246 } 275 }
247 276
248 /// Processes this phase. 277 /// Processes this phase.
249 /// 278 ///
250 /// Returns a future that completes when processing is done. If there is 279 /// Returns a future that completes when processing is done. If there is
251 /// nothing to process, returns `null`. 280 /// nothing to process, returns `null`.
252 Future process() { 281 Future process() {
253 if (_adjustTransformersFutures.isEmpty) return _processTransforms(); 282 if (_adjustTransformersFutures.isEmpty) return _processTransforms();
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
287 // Report collisions in a deterministic order. 316 // Report collisions in a deterministic order.
288 collisions = collisions.toList(); 317 collisions = collisions.toList();
289 collisions.sort((a, b) => a.toString().compareTo(b.toString())); 318 collisions.sort((a, b) => a.toString().compareTo(b.toString()));
290 for (var collision in collisions) { 319 for (var collision in collisions) {
291 cascade.reportError(new AssetCollisionException(collision)); 320 cascade.reportError(new AssetCollisionException(collision));
292 // TODO(rnystrom): Define what happens after a collision occurs. 321 // TODO(rnystrom): Define what happens after a collision occurs.
293 } 322 }
294 }); 323 });
295 } 324 }
296 } 325 }
OLDNEW
« no previous file with comments | « pkg/barback/lib/src/asset_cascade.dart ('k') | pkg/barback/lib/src/stream_pool.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698