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

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

Issue 180473003: Barback transforms now pass through the primary input by default. (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.phase_input; 5 library barback.phase_input;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:collection'; 8 import 'dart:collection';
9 9
10 import 'asset.dart'; 10 import 'asset.dart';
11 import 'asset_forwarder.dart'; 11 import 'asset_forwarder.dart';
12 import 'asset_node.dart'; 12 import 'asset_node.dart';
13 import 'asset_node_set.dart';
13 import 'errors.dart'; 14 import 'errors.dart';
14 import 'log.dart'; 15 import 'log.dart';
15 import 'phase.dart'; 16 import 'phase.dart';
16 import 'stream_pool.dart'; 17 import 'stream_pool.dart';
17 import 'transform_node.dart'; 18 import 'transform_node.dart';
18 import 'transformer.dart'; 19 import 'transformer.dart';
19 import 'utils.dart'; 20 import 'utils.dart';
20 21
21 /// A class for watching a single [AssetNode] and running any transforms that 22 /// A class for watching a single [AssetNode] and running any transforms that
22 /// take that node as a primary input. 23 /// take that node as a primary input.
(...skipping 15 matching lines...) Expand all
38 final _transforms = new Set<TransformNode>(); 39 final _transforms = new Set<TransformNode>();
39 40
40 /// A forwarder for the input [AssetNode] for this phase. 41 /// A forwarder for the input [AssetNode] for this phase.
41 /// 42 ///
42 /// This is used to mark the node as removed should the input ever be removed. 43 /// This is used to mark the node as removed should the input ever be removed.
43 final AssetForwarder _inputForwarder; 44 final AssetForwarder _inputForwarder;
44 45
45 /// The asset node for this input. 46 /// The asset node for this input.
46 AssetNode get input => _inputForwarder.node; 47 AssetNode get input => _inputForwarder.node;
47 48
48 /// The controller that's used for the output node if [input] isn't consumed 49 /// The controller that's used for the output node if [input] isn't
49 /// by any transformers. 50 /// overwritten by any transformers.
50 /// 51 ///
51 /// This needs an intervening controller to ensure that the output can be 52 /// This needs an intervening controller to ensure that the output can be
52 /// marked dirty when determining whether transforms apply, and removed if 53 /// marked dirty when determining whether transforms will overwrite it, and
53 /// they do. It's null if the asset is not being passed through. 54 /// removed if they do. It's null if the asset is not being passed through.
Bob Nystrom 2014/02/26 01:09:15 do -> will
nweiz 2014/02/26 19:37:14 I don't think that's right -- we don't emit the pa
Bob Nystrom 2014/02/26 20:28:50 Oh, now I get it. That sentence is hairy. "removed
nweiz 2014/02/27 21:04:20 Done.
54 AssetNodeController _passThroughController; 55 AssetNodeController _passThroughController;
55 56
56 /// Whether [_passThroughController] has been newly created since [process] 57 /// Whether [_passThroughController] has been newly created since [process]
57 /// last completed. 58 /// last completed.
58 bool _newPassThrough = false; 59 bool _newPassThrough = false;
59 60
61 final _outputs = new AssetNodeSet();
62
60 /// A Future that will complete once the transformers that consume [input] are 63 /// A Future that will complete once the transformers that consume [input] are
61 /// determined. 64 /// determined.
62 Future _adjustTransformersFuture; 65 Future _adjustTransformersFuture;
63 66
64 /// A stream that emits an event whenever this input becomes dirty and needs 67 /// A stream that emits an event whenever this input becomes dirty and needs
65 /// [process] to be called. 68 /// [process] to be called.
66 /// 69 ///
67 /// This may emit events when the input was already dirty or while processing 70 /// This may emit events when the input was already dirty or while processing
68 /// transforms. Events are emitted synchronously to ensure that the dirty 71 /// transforms. Events are emitted synchronously to ensure that the dirty
69 /// state is thoroughly propagated as soon as any assets are changed. 72 /// state is thoroughly propagated as soon as any assets are changed.
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
130 // automatically pick up on [removedTransformer] being gone. 133 // automatically pick up on [removedTransformer] being gone.
131 if (_adjustTransformersFuture != null) continue; 134 if (_adjustTransformersFuture != null) continue;
132 135
133 _transforms.removeWhere((transform) { 136 _transforms.removeWhere((transform) {
134 if (transform.transformer != removedTransformer) return false; 137 if (transform.transformer != removedTransformer) return false;
135 transform.remove(); 138 transform.remove();
136 return true; 139 return true;
137 }); 140 });
138 } 141 }
139 142
140 if (_transforms.isEmpty && _adjustTransformersFuture == null &&
141 _passThroughController == null) {
142 _passThroughController = new AssetNodeController.from(input);
143 _newPassThrough = true;
144 }
145
146 var brandNewTransformers = newTransformers.difference(oldTransformers); 143 var brandNewTransformers = newTransformers.difference(oldTransformers);
147 if (brandNewTransformers.isEmpty) return; 144 if (brandNewTransformers.isEmpty) return;
148 145
149 brandNewTransformers.forEach(_transformers.add); 146 brandNewTransformers.forEach(_transformers.add);
150 if (_adjustTransformersFuture == null) _adjustTransformers(); 147 if (_adjustTransformersFuture == null) _adjustTransformers();
151 } 148 }
152 149
153 /// Force all [LazyTransformer]s' transforms in this input to begin producing 150 /// Force all [LazyTransformer]s' transforms in this input to begin producing
154 /// concrete assets. 151 /// concrete assets.
155 void forceAllTransforms() { 152 void forceAllTransforms() {
156 for (var transform in _transforms) { 153 for (var transform in _transforms) {
157 transform.force(); 154 transform.force();
158 } 155 }
159 } 156 }
160 157
161 /// Asynchronously determines which transformers can consume [input] as a 158 /// Asynchronously determines which transformers can consume [input] as a
162 /// primary input and creates transforms for them. 159 /// primary input and creates transforms for them.
163 /// 160 ///
164 /// This ensures that if [input] is modified or removed during or after the 161 /// This ensures that if [input] is modified or removed during or after the
165 /// time it takes to adjust its transformers, they're appropriately 162 /// time it takes to adjust its transformers, they're appropriately
166 /// re-adjusted. Its progress can be tracked in [_adjustTransformersFuture]. 163 /// re-adjusted. Its progress can be tracked in [_adjustTransformersFuture].
167 void _adjustTransformers() { 164 void _adjustTransformers() {
168 // Mark the input as dirty. This may not actually end up creating any new 165 // Mark the input as dirty. This may not actually end up creating any new
169 // transforms, but we want adding or removing a source asset to consistently 166 // transforms, but we want adding or removing a source asset to consistently
170 // kick off a build, even if that build does nothing. 167 // kick off a build, even if that build does nothing.
171 _onDirtyController.add(null); 168 _onDirtyController.add(null);
172 169
173 // If there's a pass-through for this input, mark it dirty while we figure 170 // If there's a pass-through for this input, mark it dirty until we figure
174 // out whether we need to add any transforms for it. 171 // out if a transformer will emit an asset with that id.
175 if (_passThroughController != null) _passThroughController.setDirty(); 172 if (_passThroughController != null) _passThroughController.setDirty();
176 173
177 // Once the input is available, hook up transformers for it. If it changes 174 // Once the input is available, hook up transformers for it. If it changes
178 // while that's happening, try again. 175 // while that's happening, try again.
179 _adjustTransformersFuture = _tryUntilStable((asset, transformers) { 176 _adjustTransformersFuture = _tryUntilStable((asset, transformers) {
180 var oldTransformers = 177 var oldTransformers =
181 _transforms.map((transform) => transform.transformer).toSet(); 178 _transforms.map((transform) => transform.transformer).toSet();
182 179
183 return _removeStaleTransforms(asset, transformers).then((_) => 180 return _removeStaleTransforms(asset, transformers).then((_) =>
184 _addFreshTransforms(transformers, oldTransformers)); 181 _addFreshTransforms(transformers, oldTransformers));
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
236 // We can safely access [input.asset] here even though it might have 233 // We can safely access [input.asset] here even though it might have
237 // changed since (as above) if it has, [_adjustTransformers] will just be 234 // changed since (as above) if it has, [_adjustTransformers] will just be
238 // re-run. 235 // re-run.
239 // TODO(rnystrom): Catch all errors from isPrimary() and redirect to 236 // TODO(rnystrom): Catch all errors from isPrimary() and redirect to
240 // results. 237 // results.
241 return transformer.isPrimary(input.asset).then((isPrimary) { 238 return transformer.isPrimary(input.asset).then((isPrimary) {
242 if (!isPrimary) return; 239 if (!isPrimary) return;
243 var transform = new TransformNode( 240 var transform = new TransformNode(
244 _phase, transformer, input, _location); 241 _phase, transformer, input, _location);
245 _transforms.add(transform); 242 _transforms.add(transform);
243 transform.onDirty.listen((_) {
244 if (_passThroughController != null) _passThroughController.setDirty();
245 });
246 _onDirtyPool.add(transform.onDirty); 246 _onDirtyPool.add(transform.onDirty);
247 _onLogPool.add(transform.onLog); 247 _onLogPool.add(transform.onLog);
248 }); 248 });
249 })); 249 }));
250 } 250 }
251 251
252 /// Adjust whether [input] is passed through the phase unmodified, based on
253 /// whether it's consumed by other transforms in this phase.
254 ///
255 /// If [input] was already passed-through, this will update the passed-through
256 /// value.
257 void _adjustPassThrough() {
258 assert(input.state.isAvailable);
259
260 if (_transforms.isEmpty) {
261 if (_passThroughController != null) {
262 _passThroughController.setAvailable(input.asset);
263 } else {
264 _passThroughController = new AssetNodeController.from(input);
265 _newPassThrough = true;
266 }
267 } else if (_passThroughController != null) {
268 _passThroughController.setRemoved();
269 _passThroughController = null;
270 _newPassThrough = false;
271 }
272 }
273
274 /// Like [AssetNode.tryUntilStable], but also re-runs [callback] if this 252 /// Like [AssetNode.tryUntilStable], but also re-runs [callback] if this
275 /// phase's transformers are modified. 253 /// phase's transformers are modified.
276 Future _tryUntilStable( 254 Future _tryUntilStable(
277 Future callback(Asset asset, Set<Transformer> transformers)) { 255 Future callback(Asset asset, Set<Transformer> transformers)) {
278 var oldTransformers; 256 var oldTransformers;
279 return input.tryUntilStable((asset) { 257 return input.tryUntilStable((asset) {
280 oldTransformers = _transformers.toSet(); 258 oldTransformers = _transformers.toSet();
281 return callback(asset, _transformers); 259 return callback(asset, _transformers);
282 }).then((result) { 260 }).then((result) {
283 if (setEquals(oldTransformers, _transformers)) return result; 261 if (setEquals(oldTransformers, _transformers)) return result;
284 return _tryUntilStable(callback); 262 return _tryUntilStable(callback);
285 }); 263 });
286 } 264 }
287 265
288 /// Processes the transforms for this input. 266 /// Processes the transforms for this input.
289 /// 267 ///
290 /// Returns the set of newly-created asset nodes that transforms have emitted 268 /// Returns the set of newly-created asset nodes that transforms have emitted
291 /// for this input. The assets returned this way are guaranteed not to be 269 /// for this input. The assets returned this way are guaranteed not to be
292 /// [AssetState.REMOVED]. 270 /// [AssetState.REMOVED].
293 Future<Set<AssetNode>> process() { 271 Future<Set<AssetNode>> process() {
294 return _waitForTransformers(() => _processTransforms()).then((outputs) { 272 return _waitForTransformers(() {
273 if (input.state.isRemoved) return new Future.value(new Set());
274
275 return Future.wait(_transforms.map((transform) {
276 if (!transform.isDirty) return new Future.value(new Set());
277 return transform.apply();
278 })).then((outputs) => unionAll(outputs));
279 }).then((outputs) {
295 if (input.state.isRemoved) return new Set(); 280 if (input.state.isRemoved) return new Set();
281
282 for (var output in outputs) {
283 assert(!output.state.isRemoved);
284 _outputs.add(output);
285 output.whenRemoved(_adjustPassThrough);
286 }
287
288 _adjustPassThrough();
289 if (_newPassThrough) {
290 outputs.add(_passThroughController.node);
291 _newPassThrough = false;
292 }
296 return outputs; 293 return outputs;
297 }); 294 });
298 } 295 }
299 296
300 /// Runs [callback] once all the transformers are adjusted correctly and the 297 /// Runs [callback] once all the transformers are adjusted correctly and the
301 /// input is ready to be processed. 298 /// input is ready to be processed.
302 /// 299 ///
303 /// If the transformers are already properly adjusted, [callback] is called 300 /// If the transformers are already properly adjusted, [callback] is called
304 /// synchronously to ensure that [_adjustTransformers] isn't called before the 301 /// synchronously to ensure that [_adjustTransformers] isn't called before the
305 /// callback. 302 /// callback.
306 Future _waitForTransformers(callback()) { 303 Future _waitForTransformers(callback()) {
307 if (_adjustTransformersFuture == null) return syncFuture(callback); 304 if (_adjustTransformersFuture == null) return syncFuture(callback);
308 return _adjustTransformersFuture.then( 305 return _adjustTransformersFuture.then(
309 (_) => _waitForTransformers(callback)); 306 (_) => _waitForTransformers(callback));
310 } 307 }
311 308
312 /// Applies all currently wired up and dirty transforms. 309 /// Adjust whether [input] is passed through the phase unmodified, based on
313 Future<Set<AssetNode>> _processTransforms() { 310 /// whether it's overwritten by other transforms in this phase.
314 if (input.state.isRemoved) return new Future.value(new Set()); 311 ///
312 /// If [input] was already passed-through, this will update the passed-through
313 /// value.
314 void _adjustPassThrough() {
315 if (!input.state.isAvailable) return;
315 316
316 if (_passThroughController != null) { 317 // If there's an output with the same id as the primary input, that
317 if (!_newPassThrough) return new Future.value(new Set()); 318 // overwrites the input so it doesn't get passed through. Otherwise,
318 _newPassThrough = false; 319 // create a pass-through controller if none exists, or set the existing
319 return new Future.value( 320 // one available.
320 new Set<AssetNode>.from([_passThroughController.node])); 321 if (_outputs.any((output) => output.id == input.id)) {
322 if (_passThroughController != null) {
323 _passThroughController.setRemoved();
324 _passThroughController = null;
325 _newPassThrough = false;
326 }
327 } else if (_passThroughController == null) {
328 _passThroughController = new AssetNodeController.from(input);
329 _newPassThrough = true;
330 } else if (_passThroughController.node.state.isDirty) {
331 _passThroughController.setAvailable(input.asset);
321 } 332 }
322
323 return Future.wait(_transforms.map((transform) {
324 if (!transform.isDirty) return new Future.value(new Set());
325 return transform.apply();
326 })).then((outputs) => unionAll(outputs));
327 } 333 }
328 334
329 String toString() => "phase input in $_location for $input"; 335 String toString() => "phase input in $_location for $input";
330 } 336 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698