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

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

Powered by Google App Engine
This is Rietveld 408576698