| Index: pkg/barback/lib/src/phase.dart
|
| diff --git a/pkg/barback/lib/src/phase.dart b/pkg/barback/lib/src/phase.dart
|
| index 3c9f3f9d2b94818b06860c424ccb2995386d2414..263741de931d6c3c3d0997b3b39b8a1d43c0a9e0 100644
|
| --- a/pkg/barback/lib/src/phase.dart
|
| +++ b/pkg/barback/lib/src/phase.dart
|
| @@ -36,7 +36,7 @@ class Phase {
|
| /// The transformers that can access [inputs].
|
| ///
|
| /// Their outputs will be available to the next phase.
|
| - final List<Transformer> _transformers;
|
| + final Set<Transformer> _transformers;
|
|
|
| /// The inputs that are available for transforms in this phase to consume.
|
| ///
|
| @@ -102,7 +102,8 @@ class Phase {
|
| /// The phase after this one.
|
| ///
|
| /// Outputs from this phase will be passed to it.
|
| - final Phase _next;
|
| + Phase get next => _next;
|
| + Phase _next;
|
|
|
| /// Returns all currently-available output assets for this phase.
|
| AssetSet get availableOutputs {
|
| @@ -112,7 +113,8 @@ class Phase {
|
| .map((node) => node.asset));
|
| }
|
|
|
| - Phase(this.cascade, this._transformers, this._next) {
|
| + Phase(this.cascade, Iterable<Transformer> transformers)
|
| + : _transformers = transformers.toSet() {
|
| _onDirtyPool.add(_onDirtyController.stream);
|
| }
|
|
|
| @@ -195,6 +197,60 @@ class Phase {
|
| });
|
| }
|
|
|
| + /// Set this phase's transformers to [transformers].
|
| + void updateTransformers(Iterable<Transformer> transformers) {
|
| + _onDirtyController.add(null);
|
| +
|
| + var newTransformers = transformers.toSet();
|
| + var oldTransformers = _transformers.toSet();
|
| + for (var removedTransformer in
|
| + oldTransformers.difference(newTransformers)) {
|
| + _transformers.remove(removedTransformer);
|
| +
|
| + // Remove old transforms for which [removedTransformer] was a transformer.
|
| + for (var id in _inputs.keys) {
|
| + // If the transformers are being adjusted for [id], it will
|
| + // automatically pick up on [removedTransformer] being gone.
|
| + if (_adjustTransformersFutures.containsKey(id)) continue;
|
| +
|
| + _transforms[id].removeWhere((transform) {
|
| + if (transform.transformer != removedTransformer) return false;
|
| + transform.remove();
|
| + return true;
|
| + });
|
| +
|
| + if (!_transforms[id].isEmpty) continue;
|
| + _passThroughControllers.putIfAbsent(id, () {
|
| + return new AssetNodeController.available(
|
| + _inputs[id].asset, _inputs[id].transform);
|
| + });
|
| + }
|
| + }
|
| +
|
| + var brandNewTransformers = newTransformers.difference(oldTransformers);
|
| + if (brandNewTransformers.isEmpty) return;
|
| + brandNewTransformers.forEach(_transformers.add);
|
| +
|
| + // If there are any new transformers, start re-adjusting the transforms for
|
| + // all inputs so we pick up which inputs the new transformers apply to.
|
| + _inputs.forEach((id, node) {
|
| + if (_adjustTransformersFutures.containsKey(id)) return;
|
| + _adjustTransformers(node);
|
| + });
|
| + }
|
| +
|
| + /// Add a new phase after this one with [transformers].
|
| + ///
|
| + /// This may only be called on a phase with no phase following it.
|
| + Phase addPhase(Iterable<Transformer> transformers) {
|
| + assert(_next == null);
|
| + _next = new Phase(cascade, transformers);
|
| + for (var outputs in _outputs.values) {
|
| + _next.addInput(outputs.first);
|
| + }
|
| + return _next;
|
| + }
|
| +
|
| /// Asynchronously determines which transformers can consume [node] as a
|
| /// primary input and creates transforms for them.
|
| ///
|
| @@ -214,12 +270,13 @@ class Phase {
|
|
|
| // Once the input is available, hook up transformers for it. If it changes
|
| // while that's happening, try again.
|
| - _adjustTransformersFutures[node.id] = node.tryUntilStable((asset) {
|
| + _adjustTransformersFutures[node.id] = _tryUntilStable(node,
|
| + (asset, transformers) {
|
| var oldTransformers = _transforms[node.id]
|
| .map((transform) => transform.transformer).toSet();
|
|
|
| - return _removeStaleTransforms(asset)
|
| - .then((_) => _addFreshTransforms(node, oldTransformers));
|
| + return _removeStaleTransforms(asset, transformers).then((_) =>
|
| + _addFreshTransforms(node, transformers, oldTransformers));
|
| }).then((_) {
|
| _adjustPassThrough(node);
|
|
|
| @@ -258,11 +315,15 @@ class Phase {
|
|
|
| // Remove any old transforms that used to have [asset] as a primary asset but
|
| // no longer apply to its new contents.
|
| - Future _removeStaleTransforms(Asset asset) {
|
| + Future _removeStaleTransforms(Asset asset, Set<Transformer> transformers) {
|
| return Future.wait(_transforms[asset.id].map((transform) {
|
| - // TODO(rnystrom): Catch all errors from isPrimary() and redirect to
|
| - // results.
|
| - return transform.transformer.isPrimary(asset).then((isPrimary) {
|
| + return newFuture(() {
|
| + if (!transformers.contains(transform.transformer)) return false;
|
| +
|
| + // TODO(rnystrom): Catch all errors from isPrimary() and redirect to
|
| + // results.
|
| + return transform.transformer.isPrimary(asset);
|
| + }).then((isPrimary) {
|
| if (isPrimary) return;
|
| _transforms[asset.id].remove(transform);
|
| _onDirtyPool.remove(transform.onDirty);
|
| @@ -274,11 +335,13 @@ class Phase {
|
| // Add new transforms for transformers that consider [node]'s asset to be a
|
| // primary input.
|
| //
|
| - // [oldTransformers] is the set of transformers that had [node] as a primary
|
| - // input prior to this. They don't need to be checked, since they were removed
|
| - // or preserved in [_removeStaleTransforms].
|
| - Future _addFreshTransforms(AssetNode node, Set<Transformer> oldTransformers) {
|
| - return Future.wait(_transformers.map((transformer) {
|
| + // [oldTransformers] is the set of transformers for which there were
|
| + // transforms that had [node] as a primary input prior to this. They don't
|
| + // need to be checked, since their transforms were removed or preserved in
|
| + // [_removeStaleTransforms].
|
| + Future _addFreshTransforms(AssetNode node, Set<Transformer> transformers,
|
| + Set<Transformer> oldTransformers) {
|
| + return Future.wait(transformers.map((transformer) {
|
| if (oldTransformers.contains(transformer)) return new Future.value();
|
|
|
| // If the asset is unavailable, the results of this [_adjustTransformers]
|
| @@ -321,6 +384,20 @@ class Phase {
|
| }
|
| }
|
|
|
| + /// Like [AssetNode.tryUntilStable], but also re-runs [callback] if this
|
| + /// phase's transformers are modified.
|
| + Future _tryUntilStable(AssetNode node,
|
| + Future callback(Asset asset, Set<Transformer> transformers)) {
|
| + var oldTransformers;
|
| + return node.tryUntilStable((asset) {
|
| + oldTransformers = _transformers.toSet();
|
| + return callback(asset, _transformers);
|
| + }).then((result) {
|
| + if (setEquals(oldTransformers, _transformers)) return result;
|
| + return _tryUntilStable(node, callback);
|
| + });
|
| + }
|
| +
|
| /// Processes this phase.
|
| ///
|
| /// Returns a future that completes when processing is done. If there is
|
|
|