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

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

Issue 23363002: Factor out an input-handling class from Phase in barback. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Code review changes. 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/package_provider.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 import 'dart:collection'; 8 import 'dart:collection';
9 9
10 import 'asset.dart';
11 import 'asset_cascade.dart'; 10 import 'asset_cascade.dart';
12 import 'asset_id.dart'; 11 import 'asset_id.dart';
13 import 'asset_node.dart'; 12 import 'asset_node.dart';
14 import 'asset_set.dart'; 13 import 'asset_set.dart';
15 import 'errors.dart'; 14 import 'errors.dart';
15 import 'phase_input.dart';
16 import 'stream_pool.dart'; 16 import 'stream_pool.dart';
17 import 'transform_node.dart';
18 import 'transformer.dart'; 17 import 'transformer.dart';
19 import 'utils.dart'; 18 import 'utils.dart';
20 19
21 /// One phase in the ordered series of transformations in an [AssetCascade]. 20 /// One phase in the ordered series of transformations in an [AssetCascade].
22 /// 21 ///
23 /// 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
24 /// outputs to later phases. Phases are processed strictly serially. All 23 /// outputs to later phases. Phases are processed strictly serially. All
25 /// 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.
26 /// Within a single phase, all transforms will be run in parallel. 25 /// Within a single phase, all transforms will be run in parallel.
27 /// 26 ///
28 /// Building can be interrupted between phases. For example, a source is added 27 /// Building can be interrupted between phases. For example, a source is added
29 /// which starts the background process. Sometime during, say, phase 2 (which 28 /// which starts the background process. Sometime during, say, phase 2 (which
30 /// is running asynchronously) that source is modified. When the process queue 29 /// is running asynchronously) that source is modified. When the process queue
31 /// goes to advance to phase 3, it will see that modification and start the 30 /// goes to advance to phase 3, it will see that modification and start the
32 /// waterfall from the beginning again. 31 /// waterfall from the beginning again.
33 class Phase { 32 class Phase {
34 /// The cascade that owns this phase. 33 /// The cascade that owns this phase.
35 final AssetCascade cascade; 34 final AssetCascade cascade;
36 35
37 /// The transformers that can access [inputs]. 36 /// The transformers that can access [inputs].
38 /// 37 ///
39 /// Their outputs will be available to the next phase. 38 /// Their outputs will be available to the next phase.
40 final Set<Transformer> _transformers; 39 final Set<Transformer> _transformers;
41 40
42 /// The inputs that are available for transforms in this phase to consume. 41 /// The inputs for this phase.
43 /// 42 ///
44 /// For the first phase, these will be the source assets. For all other 43 /// For the first phase, these will be the source assets. For all other
45 /// phases, they will be the outputs from the previous phase. 44 /// phases, they will be the outputs from the previous phase.
46 final _inputs = new Map<AssetId, AssetNode>(); 45 final _inputs = new Map<AssetId, PhaseInput>();
47
48 /// The transforms currently applicable to assets in [inputs], indexed by
49 /// the ids of their primary inputs.
50 ///
51 /// These are the transforms that have been "wired up": they represent a
52 /// repeatable transformation of a single concrete set of inputs. "dart2js"
53 /// is a transformer. "dart2js on web/main.dart" is a transform.
54 final _transforms = new Map<AssetId, Set<TransformNode>>();
55
56 /// Controllers for assets that aren't consumed by transforms in this phase.
57 ///
58 /// These assets are passed to the next phase unmodified. They need
59 /// intervening controllers to ensure that the outputs can be marked dirty
60 /// when determining whether transforms apply, and removed if they do.
61 final _passThroughControllers = new Map<AssetId, AssetNodeController>();
62
63 /// Futures that will complete once the transformers that can consume a given
64 /// asset are determined.
65 ///
66 /// Whenever an asset is added or modified, we need to asynchronously
67 /// determine which transformers can use it as their primary input. We can't
68 /// start processing until we know which transformers to run, and this allows
69 /// us to wait until we do.
70 var _adjustTransformersFutures = new Map<AssetId, Future>();
71
72 /// New asset nodes that were added while [_adjustTransformers] was still
73 /// being run on an old version of that asset.
74 var _pendingNewInputs = new Map<AssetId, AssetNode>();
75 46
76 /// A map of output ids to the asset node outputs for those ids and the 47 /// A map of output ids to the asset node outputs for those ids and the
77 /// transforms that produced those asset nodes. 48 /// transforms that produced those asset nodes.
78 /// 49 ///
79 /// Usually there's only one node for a given output id. However, it's 50 /// Usually there's only one node for a given output id. However, it's
80 /// possible for multiple transformers to output an asset with the same id. In 51 /// possible for multiple transformers to output an asset with the same id. In
81 /// that case, the chronologically first output emitted is passed forward. We 52 /// that case, the chronologically first output emitted is passed forward. We
82 /// keep track of the other nodes so that if that output is removed, we know 53 /// keep track of the other nodes so that if that output is removed, we know
83 /// which asset to replace it with. 54 /// which asset to replace it with.
84 final _outputs = new Map<AssetId, Queue<AssetNode>>(); 55 final _outputs = new Map<AssetId, Queue<AssetNode>>();
85 56
86 /// A stream that emits an event whenever this phase becomes dirty and needs 57 /// A stream that emits an event whenever this phase becomes dirty and needs
87 /// to be run. 58 /// to be run.
88 /// 59 ///
89 /// This may emit events when the phase was already dirty or while processing 60 /// This may emit events when the phase was already dirty or while processing
90 /// transforms. Events are emitted synchronously to ensure that the dirty 61 /// transforms. Events are emitted synchronously to ensure that the dirty
91 /// state is thoroughly propagated as soon as any assets are changed. 62 /// state is thoroughly propagated as soon as any assets are changed.
92 Stream get onDirty => _onDirtyPool.stream; 63 Stream get onDirty => _onDirtyPool.stream;
93 final _onDirtyPool = new StreamPool.broadcast(); 64 final _onDirtyPool = new StreamPool.broadcast();
94 65
95 /// A controller whose stream feeds into [_onDirtyPool]. 66 /// A controller whose stream feeds into [_onDirtyPool].
96 /// 67 ///
97 /// This is used whenever an input is added, changed, or removed. It's 68 /// This is used whenever an input is added or transforms are changed.
98 /// sometimes redundant with the events collected from [_transforms], but this
99 /// stream is necessary for new and removed inputs, and the transform stream
100 /// is necessary for modified secondary inputs.
101 final _onDirtyController = new StreamController.broadcast(sync: true); 69 final _onDirtyController = new StreamController.broadcast(sync: true);
102 70
103 /// The phase after this one. 71 /// The phase after this one.
104 /// 72 ///
105 /// Outputs from this phase will be passed to it. 73 /// Outputs from this phase will be passed to it.
106 Phase get next => _next; 74 Phase get next => _next;
107 Phase _next; 75 Phase _next;
108 76
109 /// Returns all currently-available output assets for this phase. 77 /// Returns all currently-available output assets for this phase.
110 AssetSet get availableOutputs { 78 AssetSet get availableOutputs {
(...skipping 12 matching lines...) Expand all
123 /// 91 ///
124 /// [node] doesn't have to be [AssetState.AVAILABLE]. Once it is, the phase 92 /// [node] doesn't have to be [AssetState.AVAILABLE]. Once it is, the phase
125 /// will automatically begin determining which transforms can consume it as a 93 /// will automatically begin determining which transforms can consume it as a
126 /// primary input. The transforms themselves won't be applied until [process] 94 /// primary input. The transforms themselves won't be applied until [process]
127 /// is called, however. 95 /// is called, however.
128 /// 96 ///
129 /// This should only be used for brand-new assets or assets that have been 97 /// This should only be used for brand-new assets or assets that have been
130 /// removed and re-created. The phase will automatically handle updated assets 98 /// removed and re-created. The phase will automatically handle updated assets
131 /// using the [AssetNode.onStateChange] stream. 99 /// using the [AssetNode.onStateChange] stream.
132 void addInput(AssetNode node) { 100 void addInput(AssetNode node) {
133 // We remove [node.id] from [inputs] as soon as the node is removed rather 101 if (_inputs.containsKey(node.id)) _inputs[node.id].remove();
134 // than at the same time [node.id] is removed from [_transforms] so we don't
135 // have to wait on [_adjustTransformers]. It's important that [inputs] is
136 // always up-to-date so that the [AssetCascade] can look there for available
137 // assets.
138 _inputs[node.id] = node;
139 node.whenRemoved.then((_) => _inputs.remove(node.id));
140 102
141 if (!_adjustTransformersFutures.containsKey(node.id)) { 103 var input = new PhaseInput(this, node, _transformers);
142 _transforms[node.id] = new Set<TransformNode>(); 104 _inputs[node.id] = input;
143 _adjustTransformers(node); 105 input.input.whenRemoved.then((_) => _inputs.remove(node.id));
144 return; 106 _onDirtyPool.add(input.onDirty);
145 } 107 _onDirtyController.add(null);
146
147 // If an input is added while the same input is still being processed,
148 // that means that the asset was removed and recreated while
149 // [_adjustTransformers] was being run on the old value. We have to wait
150 // until that finishes, then run it again on whatever the newest version
151 // of that asset is.
152
153 // We may already be waiting for the existing [_adjustTransformers] call to
154 // finish. If so, all we need to do is change the node that will be loaded
155 // after it completes.
156 var containedKey = _pendingNewInputs.containsKey(node.id);
157 _pendingNewInputs[node.id] = node;
158 if (containedKey) return;
159
160 // If we aren't already waiting, start doing so.
161 _adjustTransformersFutures[node.id].then((_) {
162 assert(!_adjustTransformersFutures.containsKey(node.id));
163 assert(_pendingNewInputs.containsKey(node.id));
164 _transforms[node.id] = new Set<TransformNode>();
165 _adjustTransformers(_pendingNewInputs.remove(node.id));
166 }, onError: (_) {
167 // If there was a programmatic error while processing the old input,
168 // we don't want to just ignore it; it may have left the system in an
169 // inconsistent state. We also don't want to top-level it, so we
170 // ignore it here but don't start processing the new input. That way
171 // when [process] is called, the error will be piped through its
172 // return value.
173 }).catchError((e) {
174 // If our code above has a programmatic error, ensure it will be piped
175 // through [process] by putting it into [_adjustTransformersFutures].
176 _adjustTransformersFutures[node.id] = new Future.error(e);
177 });
178 } 108 }
179 109
180 /// Gets the asset node for an input [id]. 110 /// Gets the asset node for an input [id].
181 /// 111 ///
182 /// If an input with that ID cannot be found, returns null. 112 /// If an input with that ID cannot be found, returns null.
183 Future<AssetNode> getInput(AssetId id) { 113 Future<AssetNode> getInput(AssetId id) {
184 return newFuture(() { 114 return newFuture(() {
185 if (id.package == cascade.package) return _inputs[id]; 115 if (id.package != cascade.package) return cascade.graph.getAssetNode(id);
186 return cascade.graph.getAssetNode(id); 116 if (_inputs.containsKey(id)) return _inputs[id].input;
117 return null;
187 }); 118 });
188 } 119 }
189 120
190 /// Gets the asset node for an output [id]. 121 /// Gets the asset node for an output [id].
191 /// 122 ///
192 /// If an output with that ID cannot be found, returns null. 123 /// If an output with that ID cannot be found, returns null.
193 Future<AssetNode> getOutput(AssetId id) { 124 Future<AssetNode> getOutput(AssetId id) {
194 return newFuture(() { 125 return newFuture(() {
195 if (id.package != cascade.package) return cascade.graph.getAssetNode(id); 126 if (id.package != cascade.package) return cascade.graph.getAssetNode(id);
196 if (!_outputs.containsKey(id)) return null; 127 if (!_outputs.containsKey(id)) return null;
197 return _outputs[id].first; 128 return _outputs[id].first;
198 }); 129 });
199 } 130 }
200 131
201 /// Set this phase's transformers to [transformers]. 132 /// Set this phase's transformers to [transformers].
202 void updateTransformers(Iterable<Transformer> transformers) { 133 void updateTransformers(Iterable<Transformer> transformers) {
203 _onDirtyController.add(null); 134 _onDirtyController.add(null);
204 135 _transformers.clear();
205 var newTransformers = transformers.toSet(); 136 _transformers.addAll(transformers);
206 var oldTransformers = _transformers.toSet(); 137 for (var input in _inputs.values) {
207 for (var removedTransformer in 138 input.updateTransformers(_transformers);
208 oldTransformers.difference(newTransformers)) {
209 _transformers.remove(removedTransformer);
210
211 // Remove old transforms for which [removedTransformer] was a transformer.
212 for (var id in _inputs.keys) {
213 // If the transformers are being adjusted for [id], it will
214 // automatically pick up on [removedTransformer] being gone.
215 if (_adjustTransformersFutures.containsKey(id)) continue;
216
217 _transforms[id].removeWhere((transform) {
218 if (transform.transformer != removedTransformer) return false;
219 transform.remove();
220 return true;
221 });
222
223 if (!_transforms[id].isEmpty) continue;
224 _passThroughControllers.putIfAbsent(id, () {
225 return new AssetNodeController.available(
226 _inputs[id].asset, _inputs[id].transform);
227 });
228 }
229 } 139 }
230
231 var brandNewTransformers = newTransformers.difference(oldTransformers);
232 if (brandNewTransformers.isEmpty) return;
233 brandNewTransformers.forEach(_transformers.add);
234
235 // If there are any new transformers, start re-adjusting the transforms for
236 // all inputs so we pick up which inputs the new transformers apply to.
237 _inputs.forEach((id, node) {
238 if (_adjustTransformersFutures.containsKey(id)) return;
239 _adjustTransformers(node);
240 });
241 } 140 }
242 141
243 /// Add a new phase after this one with [transformers]. 142 /// Add a new phase after this one with [transformers].
244 /// 143 ///
245 /// This may only be called on a phase with no phase following it. 144 /// This may only be called on a phase with no phase following it.
246 Phase addPhase(Iterable<Transformer> transformers) { 145 Phase addPhase(Iterable<Transformer> transformers) {
247 assert(_next == null); 146 assert(_next == null);
248 _next = new Phase(cascade, transformers); 147 _next = new Phase(cascade, transformers);
249 for (var outputs in _outputs.values) { 148 for (var outputs in _outputs.values) {
250 _next.addInput(outputs.first); 149 _next.addInput(outputs.first);
251 } 150 }
252 return _next; 151 return _next;
253 } 152 }
254 153
255 /// Asynchronously determines which transformers can consume [node] as a
256 /// primary input and creates transforms for them.
257 ///
258 /// This ensures that if [node] is modified or removed during or after the
259 /// time it takes to adjust its transformers, they're appropriately
260 /// re-adjusted. Its progress can be tracked in [_adjustTransformersFutures].
261 void _adjustTransformers(AssetNode node) {
262 // Mark the phase as dirty. This may not actually end up creating any new
263 // transforms, but we want adding or removing a source asset to consistently
264 // kick off a build, even if that build does nothing.
265 _onDirtyController.add(null);
266
267 // If there's a pass-through for this node, mark it dirty while we figure
268 // out whether we need to add any transforms for it.
269 var controller = _passThroughControllers[node.id];
270 if (controller != null) controller.setDirty();
271
272 // Once the input is available, hook up transformers for it. If it changes
273 // while that's happening, try again.
274 _adjustTransformersFutures[node.id] = _tryUntilStable(node,
275 (asset, transformers) {
276 var oldTransformers = _transforms[node.id]
277 .map((transform) => transform.transformer).toSet();
278
279 return _removeStaleTransforms(asset, transformers).then((_) =>
280 _addFreshTransforms(node, transformers, oldTransformers));
281 }).then((_) {
282 _adjustPassThrough(node);
283
284 // Now all the transforms are set up correctly and the asset is available
285 // for the time being. Set up handlers for when the asset changes in the
286 // future.
287 node.onStateChange.first.then((state) {
288 if (state.isRemoved) {
289 _onDirtyController.add(null);
290 _transforms.remove(node.id);
291 var passThrough = _passThroughControllers.remove(node.id);
292 if (passThrough != null) passThrough.setRemoved();
293 } else {
294 _adjustTransformers(node);
295 }
296 }).catchError((e) {
297 _adjustTransformersFutures[node.id] = new Future.error(e);
298 });
299 }).catchError((error) {
300 if (error is! AssetNotFoundException || error.id != node.id) throw error;
301
302 // If the asset is removed, [tryUntilStable] will throw an
303 // [AssetNotFoundException]. In that case, just remove all transforms for
304 // the node, and its pass-through.
305 _transforms.remove(node.id);
306 var passThrough = _passThroughControllers.remove(node.id);
307 if (passThrough != null) passThrough.setRemoved();
308 }).whenComplete(() {
309 _adjustTransformersFutures.remove(node.id);
310 });
311
312 // Don't top-level errors coming from the input processing. Any errors will
313 // eventually be piped through [process]'s returned Future.
314 _adjustTransformersFutures[node.id].catchError((_) {});
315 }
316
317 // Remove any old transforms that used to have [asset] as a primary asset but
318 // no longer apply to its new contents.
319 Future _removeStaleTransforms(Asset asset, Set<Transformer> transformers) {
320 return Future.wait(_transforms[asset.id].map((transform) {
321 return newFuture(() {
322 if (!transformers.contains(transform.transformer)) return false;
323
324 // TODO(rnystrom): Catch all errors from isPrimary() and redirect to
325 // results.
326 return transform.transformer.isPrimary(asset);
327 }).then((isPrimary) {
328 if (isPrimary) return;
329 _transforms[asset.id].remove(transform);
330 _onDirtyPool.remove(transform.onDirty);
331 transform.remove();
332 });
333 }));
334 }
335
336 // Add new transforms for transformers that consider [node]'s asset to be a
337 // primary input.
338 //
339 // [oldTransformers] is the set of transformers for which there were
340 // transforms that had [node] as a primary input prior to this. They don't
341 // need to be checked, since their transforms were removed or preserved in
342 // [_removeStaleTransforms].
343 Future _addFreshTransforms(AssetNode node, Set<Transformer> transformers,
344 Set<Transformer> oldTransformers) {
345 return Future.wait(transformers.map((transformer) {
346 if (oldTransformers.contains(transformer)) return new Future.value();
347
348 // If the asset is unavailable, the results of this [_adjustTransformers]
349 // run will be discarded, so we can just short-circuit.
350 if (node.asset == null) return new Future.value();
351
352 // We can safely access [node.asset] here even though it might have
353 // changed since (as above) if it has, [_adjustTransformers] will just be
354 // re-run.
355 // TODO(rnystrom): Catch all errors from isPrimary() and redirect to
356 // results.
357 return transformer.isPrimary(node.asset).then((isPrimary) {
358 if (!isPrimary) return;
359 var transform = new TransformNode(this, transformer, node);
360 _transforms[node.id].add(transform);
361 _onDirtyPool.add(transform.onDirty);
362 });
363 }));
364 }
365
366 /// Adjust whether [node] is passed through the phase unmodified, based on
367 /// whether it's consumed by other transforms in this phase.
368 ///
369 /// If [node] was already passed-through, this will update the passed-through
370 /// value.
371 void _adjustPassThrough(AssetNode node) {
372 assert(node.state.isAvailable);
373
374 if (_transforms[node.id].isEmpty) {
375 var controller = _passThroughControllers[node.id];
376 if (controller != null) {
377 controller.setAvailable(node.asset);
378 } else {
379 _passThroughControllers[node.id] =
380 new AssetNodeController.available(node.asset, node.transform);
381 }
382 } else {
383 var controller = _passThroughControllers.remove(node.id);
384 if (controller != null) controller.setRemoved();
385 }
386 }
387
388 /// Like [AssetNode.tryUntilStable], but also re-runs [callback] if this
389 /// phase's transformers are modified.
390 Future _tryUntilStable(AssetNode node,
391 Future callback(Asset asset, Set<Transformer> transformers)) {
392 var oldTransformers;
393 return node.tryUntilStable((asset) {
394 oldTransformers = _transformers.toSet();
395 return callback(asset, _transformers);
396 }).then((result) {
397 if (setEquals(oldTransformers, _transformers)) return result;
398 return _tryUntilStable(node, callback);
399 });
400 }
401
402 /// Processes this phase. 154 /// Processes this phase.
403 /// 155 ///
404 /// Returns a future that completes when processing is done. If there is 156 /// Returns a future that completes when processing is done. If there is
405 /// nothing to process, returns `null`. 157 /// nothing to process, returns `null`.
406 Future process() { 158 Future process() {
407 if (_adjustTransformersFutures.isEmpty) return _processTransforms(); 159 if (!_inputs.values.any((input) => input.isDirty)) return null;
408 return _waitForInputs().then((_) => _processTransforms());
409 }
410 160
411 Future _waitForInputs() { 161 return Future.wait(_inputs.values.map((input) {
412 if (_adjustTransformersFutures.isEmpty) return new Future.value(); 162 if (!input.isDirty) return new Future.value(new Set());
413 return Future.wait(_adjustTransformersFutures.values) 163 return input.process().then((outputs) {
414 .then((_) => _waitForInputs()); 164 return outputs.where(_addOutput).map((output) => output.id).toSet();
415 }
416
417 /// Applies all currently wired up and dirty transforms.
418 Future _processTransforms() {
419 var newPassThroughs = _passThroughControllers.values
420 .map((controller) => controller.node)
421 .where((output) {
422 return !_outputs.containsKey(output.id) ||
423 !_outputs[output.id].contains(output);
424 }).toSet();
425
426 // Convert this to a list so we can safely modify _transforms while
427 // iterating over it.
428 var dirtyTransforms =
429 flatten(_transforms.values.map((transforms) => transforms.toList()))
430 .where((transform) => transform.isDirty).toList();
431
432 if (dirtyTransforms.isEmpty && newPassThroughs.isEmpty) return null;
433
434 var collisions = new Set<AssetId>();
435 for (var output in newPassThroughs) {
436 if (_addOutput(output)) collisions.add(output.id);
437 }
438
439 return Future.wait(dirtyTransforms.map((transform) {
440 return transform.apply().then((outputs) {
441 for (var output in outputs) {
442 if (_addOutput(output)) collisions.add(output.id);
443 }
444 }); 165 });
445 })).then((_) { 166 })).then((collisionsList) {
446 // Report collisions in a deterministic order. 167 // Report collisions in a deterministic order.
447 collisions = collisions.toList(); 168 var collisions = unionAll(collisionsList).toList();
448 collisions.sort((a, b) => a.compareTo(b)); 169 collisions.sort((a, b) => a.compareTo(b));
449 for (var collision in collisions) { 170 for (var collision in collisions) {
450 // Ensure that there's still a collision. It's possible it was resolved 171 // Ensure that there's still a collision. It's possible it was resolved
451 // while another transform was running. 172 // while another transform was running.
452 if (_outputs[collision].length <= 1) continue; 173 if (_outputs[collision].length <= 1) continue;
453 cascade.reportError(new AssetCollisionException( 174 cascade.reportError(new AssetCollisionException(
454 _outputs[collision].where((asset) => asset.transform != null) 175 _outputs[collision].where((asset) => asset.transform != null)
455 .map((asset) => asset.transform.info), 176 .map((asset) => asset.transform.info),
456 collision)); 177 collision));
457 } 178 }
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
504 // Pump the event queue to ensure that the removal of the input triggers 225 // Pump the event queue to ensure that the removal of the input triggers
505 // a new build to which we can attach the error. 226 // a new build to which we can attach the error.
506 newFuture(() => cascade.reportError(new AssetCollisionException( 227 newFuture(() => cascade.reportError(new AssetCollisionException(
507 assets.where((asset) => asset.transform != null) 228 assets.where((asset) => asset.transform != null)
508 .map((asset) => asset.transform.info), 229 .map((asset) => asset.transform.info),
509 output.id))); 230 output.id)));
510 } 231 }
511 }); 232 });
512 } 233 }
513 } 234 }
OLDNEW
« no previous file with comments | « pkg/barback/lib/src/package_provider.dart ('k') | pkg/barback/lib/src/phase_input.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698