Chromium Code Reviews| Index: pkg/barback/lib/src/phase_input.dart |
| diff --git a/pkg/barback/lib/src/phase_input.dart b/pkg/barback/lib/src/phase_input.dart |
| index 3506560da0ef4cc5898357ca8323c5eac93591f9..adf212eddb3b2a590cdc69eeef457e3799db2c3f 100644 |
| --- a/pkg/barback/lib/src/phase_input.dart |
| +++ b/pkg/barback/lib/src/phase_input.dart |
| @@ -10,6 +10,7 @@ import 'dart:collection'; |
| import 'asset.dart'; |
| import 'asset_forwarder.dart'; |
| import 'asset_node.dart'; |
| +import 'asset_node_set.dart'; |
| import 'errors.dart'; |
| import 'log.dart'; |
| import 'phase.dart'; |
| @@ -45,18 +46,20 @@ class PhaseInput { |
| /// The asset node for this input. |
| AssetNode get input => _inputForwarder.node; |
| - /// The controller that's used for the output node if [input] isn't consumed |
| - /// by any transformers. |
| + /// The controller that's used for the output node if [input] isn't |
| + /// overwritten by any transformers. |
| /// |
| /// This needs an intervening controller to ensure that the output can be |
| - /// marked dirty when determining whether transforms apply, and removed if |
| - /// they do. It's null if the asset is not being passed through. |
| + /// marked dirty when determining whether transforms will overwrite it, and |
| + /// 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.
|
| AssetNodeController _passThroughController; |
| /// Whether [_passThroughController] has been newly created since [process] |
| /// last completed. |
| bool _newPassThrough = false; |
| + final _outputs = new AssetNodeSet(); |
| + |
| /// A Future that will complete once the transformers that consume [input] are |
| /// determined. |
| Future _adjustTransformersFuture; |
| @@ -137,12 +140,6 @@ class PhaseInput { |
| }); |
| } |
| - if (_transforms.isEmpty && _adjustTransformersFuture == null && |
| - _passThroughController == null) { |
| - _passThroughController = new AssetNodeController.from(input); |
| - _newPassThrough = true; |
| - } |
| - |
| var brandNewTransformers = newTransformers.difference(oldTransformers); |
| if (brandNewTransformers.isEmpty) return; |
| @@ -170,8 +167,8 @@ class PhaseInput { |
| // kick off a build, even if that build does nothing. |
| _onDirtyController.add(null); |
| - // If there's a pass-through for this input, mark it dirty while we figure |
| - // out whether we need to add any transforms for it. |
| + // If there's a pass-through for this input, mark it dirty until we figure |
| + // out if a transformer will emit an asset with that id. |
| if (_passThroughController != null) _passThroughController.setDirty(); |
| // Once the input is available, hook up transformers for it. If it changes |
| @@ -243,34 +240,15 @@ class PhaseInput { |
| var transform = new TransformNode( |
| _phase, transformer, input, _location); |
| _transforms.add(transform); |
| + transform.onDirty.listen((_) { |
| + if (_passThroughController != null) _passThroughController.setDirty(); |
| + }); |
| _onDirtyPool.add(transform.onDirty); |
| _onLogPool.add(transform.onLog); |
| }); |
| })); |
| } |
| - /// Adjust whether [input] is passed through the phase unmodified, based on |
| - /// whether it's consumed by other transforms in this phase. |
| - /// |
| - /// If [input] was already passed-through, this will update the passed-through |
| - /// value. |
| - void _adjustPassThrough() { |
| - assert(input.state.isAvailable); |
| - |
| - if (_transforms.isEmpty) { |
| - if (_passThroughController != null) { |
| - _passThroughController.setAvailable(input.asset); |
| - } else { |
| - _passThroughController = new AssetNodeController.from(input); |
| - _newPassThrough = true; |
| - } |
| - } else if (_passThroughController != null) { |
| - _passThroughController.setRemoved(); |
| - _passThroughController = null; |
| - _newPassThrough = false; |
| - } |
| - } |
| - |
| /// Like [AssetNode.tryUntilStable], but also re-runs [callback] if this |
| /// phase's transformers are modified. |
| Future _tryUntilStable( |
| @@ -291,8 +269,27 @@ class PhaseInput { |
| /// for this input. The assets returned this way are guaranteed not to be |
| /// [AssetState.REMOVED]. |
| Future<Set<AssetNode>> process() { |
| - return _waitForTransformers(() => _processTransforms()).then((outputs) { |
| + return _waitForTransformers(() { |
| + if (input.state.isRemoved) return new Future.value(new Set()); |
| + |
| + return Future.wait(_transforms.map((transform) { |
| + if (!transform.isDirty) return new Future.value(new Set()); |
| + return transform.apply(); |
| + })).then((outputs) => unionAll(outputs)); |
| + }).then((outputs) { |
| if (input.state.isRemoved) return new Set(); |
| + |
| + for (var output in outputs) { |
| + assert(!output.state.isRemoved); |
| + _outputs.add(output); |
| + output.whenRemoved(_adjustPassThrough); |
| + } |
| + |
| + _adjustPassThrough(); |
| + if (_newPassThrough) { |
| + outputs.add(_passThroughController.node); |
| + _newPassThrough = false; |
| + } |
| return outputs; |
| }); |
| } |
| @@ -309,21 +306,30 @@ class PhaseInput { |
| (_) => _waitForTransformers(callback)); |
| } |
| - /// Applies all currently wired up and dirty transforms. |
| - Future<Set<AssetNode>> _processTransforms() { |
| - if (input.state.isRemoved) return new Future.value(new Set()); |
| + /// Adjust whether [input] is passed through the phase unmodified, based on |
| + /// whether it's overwritten by other transforms in this phase. |
| + /// |
| + /// If [input] was already passed-through, this will update the passed-through |
| + /// value. |
| + void _adjustPassThrough() { |
| + if (!input.state.isAvailable) return; |
| - if (_passThroughController != null) { |
| - if (!_newPassThrough) return new Future.value(new Set()); |
| - _newPassThrough = false; |
| - return new Future.value( |
| - new Set<AssetNode>.from([_passThroughController.node])); |
| + // If there's an output with the same id as the primary input, that |
| + // overwrites the input so it doesn't get passed through. Otherwise, |
| + // create a pass-through controller if none exists, or set the existing |
| + // one available. |
| + if (_outputs.any((output) => output.id == input.id)) { |
| + if (_passThroughController != null) { |
| + _passThroughController.setRemoved(); |
| + _passThroughController = null; |
| + _newPassThrough = false; |
| + } |
| + } else if (_passThroughController == null) { |
| + _passThroughController = new AssetNodeController.from(input); |
| + _newPassThrough = true; |
| + } else if (_passThroughController.node.state.isDirty) { |
| + _passThroughController.setAvailable(input.asset); |
| } |
| - |
| - return Future.wait(_transforms.map((transform) { |
| - if (!transform.isDirty) return new Future.value(new Set()); |
| - return transform.apply(); |
| - })).then((outputs) => unionAll(outputs)); |
| } |
| String toString() => "phase input in $_location for $input"; |