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

Unified Diff: pkg/barback/lib/src/transform_node.dart

Issue 261823008: Reorganize barback's source files. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: re-add barback/lib/src/internal_asset.dart Created 6 years, 8 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/barback/lib/src/transform_logger.dart ('k') | pkg/barback/lib/src/transformer.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/barback/lib/src/transform_node.dart
diff --git a/pkg/barback/lib/src/transform_node.dart b/pkg/barback/lib/src/transform_node.dart
deleted file mode 100644
index 95847a7808737d4fc6a90083df1f540b0cf58d90..0000000000000000000000000000000000000000
--- a/pkg/barback/lib/src/transform_node.dart
+++ /dev/null
@@ -1,535 +0,0 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library barback.transform_node;
-
-import 'dart:async';
-
-import 'asset.dart';
-import 'asset_id.dart';
-import 'asset_node.dart';
-import 'declaring_transform.dart';
-import 'declaring_transformer.dart';
-import 'errors.dart';
-import 'lazy_transformer.dart';
-import 'log.dart';
-import 'node_status.dart';
-import 'node_streams.dart';
-import 'phase.dart';
-import 'transform.dart';
-import 'transformer.dart';
-import 'utils.dart';
-
-/// Describes a transform on a set of assets and its relationship to the build
-/// dependency graph.
-///
-/// Keeps track of whether it's dirty and needs to be run and which assets it
-/// depends on.
-class TransformNode {
- /// The [Phase] that this transform runs in.
- final Phase phase;
-
- /// The [Transformer] to apply to this node's inputs.
- final Transformer transformer;
-
- /// The node for the primary asset this transform depends on.
- final AssetNode primary;
-
- /// A string describing the location of [this] in the transformer graph.
- final String _location;
-
- /// The subscription to [primary]'s [AssetNode.onStateChange] stream.
- StreamSubscription _primarySubscription;
-
- /// The subscription to [phase]'s [Phase.onAsset] stream.
- StreamSubscription<AssetNode> _phaseSubscription;
-
- /// How far along [this] is in processing its assets.
- NodeStatus get status {
- if (_state == _State.APPLIED || _state == _State.DECLARED) {
- return NodeStatus.IDLE;
- }
-
- if (_declaring && _state != _State.DECLARING) {
- return NodeStatus.MATERIALIZING;
- } else {
- return NodeStatus.RUNNING;
- }
- }
-
- /// Whether this is a declaring transform.
- ///
- /// This is usually identical to `transformer is DeclaringTransformer`, but if
- /// a declaring and non-lazy transformer emits an error during
- /// `declareOutputs` it's treated as though it wasn't declaring.
- bool get _declaring => transformer is DeclaringTransformer &&
- (_state == _State.DECLARING || _declaredOutputs != null);
-
- /// Whether this transform has been forced since it last finished applying.
- ///
- /// A transform being forced means it should run until it generates outputs
- /// and is no longer dirty. This is always true for non-declaring
- /// transformers, since they always need to eagerly generate outputs.
- bool _forced;
-
- /// The subscriptions to each input's [AssetNode.onStateChange] stream.
- final _inputSubscriptions = new Map<AssetId, StreamSubscription>();
-
- /// The controllers for the asset nodes emitted by this node.
- final _outputControllers = new Map<AssetId, AssetNodeController>();
-
- /// The ids of inputs the transformer tried and failed to read last time it
- /// ran.
- final _missingInputs = new Set<AssetId>();
-
- /// The controller that's used to pass [primary] through [this] if it's not
- /// consumed or overwritten.
- ///
- /// This needs an intervening controller to ensure that the output can be
- /// marked dirty when determining whether [this] will consume or overwrite it,
- /// and be marked removed if it does. [_passThroughController] will be null
- /// if the asset is not being passed through.
- AssetNodeController _passThroughController;
-
- /// The asset node for this transform.
- final _streams = new NodeStreams();
- Stream<NodeStatus> get onStatusChange => _streams.onStatusChange;
- Stream<AssetNode> get onAsset => _streams.onAsset;
- Stream<LogEntry> get onLog => _streams.onLog;
-
- /// The current state of [this].
- var _state = _State.DECLARING;
-
- /// Whether [this] has been marked as removed.
- bool get _isRemoved => _streams.onAssetController.isClosed;
-
- // If [transformer] is declaring but not lazy and [primary] is available, we
- // can run [apply] even if [force] hasn't been called, since [transformer]
- // should run eagerly if possible.
- bool get _canRunDeclaringEagerly =>
- _declaring && transformer is! LazyTransformer &&
- primary.state.isAvailable;
-
- /// Whether the most recent run of this transform has declared that it
- /// consumes the primary input.
- ///
- /// Defaults to `false`. This is not meaningful unless [_state] is
- /// [_State.APPLIED] or [_State.DECLARED].
- bool _consumePrimary = false;
-
- /// The set of output ids that [transformer] declared it would emit.
- ///
- /// This is only non-null if [transformer] is a [DeclaringTransformer] and its
- /// [declareOutputs] has been run successfully.
- Set<AssetId> _declaredOutputs;
-
- TransformNode(this.phase, Transformer transformer, AssetNode primary,
- this._location)
- : transformer = transformer,
- primary = primary {
- _forced = transformer is! DeclaringTransformer;
- if (_forced) primary.force();
-
- _primarySubscription = primary.onStateChange.listen((state) {
- if (state.isRemoved) {
- remove();
- } else {
- if (_forced) primary.force();
- _dirty();
- }
- });
-
- _phaseSubscription = phase.previous.onAsset.listen((node) {
- if (!_missingInputs.contains(node.id)) return;
- if (_forced) node.force();
- _dirty();
- });
-
- _declareOutputs().then((_) {
- if (_forced || _canRunDeclaringEagerly) {
- _apply();
- } else {
- _state = _State.DECLARED;
- _streams.changeStatus(NodeStatus.IDLE);
- }
- });
- }
-
- /// The [TransformInfo] describing this node.
- ///
- /// [TransformInfo] is the publicly-visible representation of a transform
- /// node.
- TransformInfo get info => new TransformInfo(transformer, primary.id);
-
- /// Marks this transform as removed.
- ///
- /// This causes all of the transform's outputs to be marked as removed as
- /// well. Normally this will be automatically done internally based on events
- /// from the primary input, but it's possible for a transform to no longer be
- /// valid even if its primary input still exists.
- void remove() {
- _streams.close();
- _primarySubscription.cancel();
- _phaseSubscription.cancel();
- _clearInputSubscriptions();
- _clearOutputs();
- if (_passThroughController != null) {
- _passThroughController.setRemoved();
- _passThroughController = null;
- }
- }
-
- /// If [this] is deferred, ensures that its concrete outputs will be
- /// generated.
- void force() {
- if (_forced || _state == _State.APPLIED) return;
- primary.force();
- _forced = true;
- if (_state == _State.DECLARED) _dirty();
- }
-
- /// Marks this transform as dirty.
- ///
- /// This causes all of the transform's outputs to be marked as dirty as well.
- void _dirty() {
- // If we're in the process of running [declareOutputs], we already know that
- // [apply] needs to be run so there's nothing we need to mark as dirty.
- if (_state == _State.DECLARING) return;
-
- if (!_forced && !_canRunDeclaringEagerly) {
- // [forced] should only ever be false for a declaring transformer.
- assert(_declaring);
-
- // If we've finished applying, transition to MATERIALIZING, indicating
- // that we know what outputs [apply] will emit but we're waiting to emit
- // them concretely until [force] is called. If we're still applying, we'll
- // transition to MATERIALIZING once we finish.
- if (_state == _State.APPLIED) _state = _State.DECLARED;
- for (var controller in _outputControllers.values) {
- controller.setLazy(force);
- }
- _emitDeclaredOutputs();
- return;
- }
-
- if (_passThroughController != null) _passThroughController.setDirty();
- for (var controller in _outputControllers.values) {
- controller.setDirty();
- }
-
- if (_state == _State.APPLIED) {
- if (_declaredOutputs != null) _emitDeclaredOutputs();
- _apply();
- } else if (_state == _State.DECLARED) {
- _apply();
- } else {
- _state = _State.NEEDS_APPLY;
- }
- }
-
- /// Runs [transform.declareOutputs] and emits the resulting assets as dirty
- /// assets.
- Future _declareOutputs() {
- if (transformer is! DeclaringTransformer) return new Future.value();
-
- var controller = new DeclaringTransformController(this);
- return syncFuture(() {
- return (transformer as DeclaringTransformer)
- .declareOutputs(controller.transform);
- }).then((_) {
- if (_isRemoved) return;
- if (controller.loggedError) return;
-
- _consumePrimary = controller.consumePrimary;
- _declaredOutputs = controller.outputIds;
- var invalidIds = _declaredOutputs
- .where((id) => id.package != phase.cascade.package).toSet();
- for (var id in invalidIds) {
- _declaredOutputs.remove(id);
- // TODO(nweiz): report this as a warning rather than a failing error.
- phase.cascade.reportError(new InvalidOutputException(info, id));
- }
-
- if (!_declaredOutputs.contains(primary.id)) _emitPassThrough();
- _emitDeclaredOutputs();
- }).catchError((error, stackTrace) {
- if (_isRemoved) return;
- if (transformer is! LazyTransformer) _forced = true;
- phase.cascade.reportError(_wrapException(error, stackTrace));
- });
- }
-
- /// Emits a dirty asset node for all outputs that were declared by the
- /// transformer.
- ///
- /// This won't emit any outputs for which there already exist output
- /// controllers. It should only be called for transforms that have declared
- /// their outputs.
- void _emitDeclaredOutputs() {
- assert(_declaredOutputs != null);
- for (var id in _declaredOutputs) {
- if (_outputControllers.containsKey(id)) continue;
- var controller = _forced
- ? new AssetNodeController(id, this)
- : new AssetNodeController.lazy(id, force, this);
- _outputControllers[id] = controller;
- _streams.onAssetController.add(controller.node);
- }
- }
-
- /// Applies this transform.
- void _apply() {
- assert(!_isRemoved);
-
- // Clear input subscriptions here as well as in [_process] because [_apply]
- // may be restarted independently if only a secondary input changes.
- _clearInputSubscriptions();
- _state = _State.APPLYING;
- _streams.changeStatus(status);
- _runApply().then((hadError) {
- if (_isRemoved) return;
-
- if (_state == _State.DECLARED) return;
-
- if (_state == _State.NEEDS_APPLY) {
- _apply();
- return;
- }
-
- if (_declaring) _forced = false;
-
- assert(_state == _State.APPLYING);
- if (hadError) {
- _clearOutputs();
- // If the transformer threw an error, we don't want to emit the
- // pass-through asset in case it will be overwritten by the transformer.
- // However, if the transformer declared that it wouldn't overwrite or
- // consume the pass-through asset, we can safely emit it.
- if (_declaredOutputs != null && !_consumePrimary &&
- !_declaredOutputs.contains(primary.id)) {
- _emitPassThrough();
- } else {
- _dontEmitPassThrough();
- }
- }
-
- _state = _State.APPLIED;
- _streams.changeStatus(NodeStatus.IDLE);
- });
- }
-
- /// Gets the asset for an input [id].
- ///
- /// If an input with [id] cannot be found, throws an [AssetNotFoundException].
- Future<Asset> getInput(AssetId id) {
- return phase.previous.getOutput(id).then((node) {
- // Throw if the input isn't found. This ensures the transformer's apply
- // is exited. We'll then catch this and report it through the proper
- // results stream.
- if (node == null) {
- _missingInputs.add(id);
- throw new AssetNotFoundException(id);
- }
-
- _inputSubscriptions.putIfAbsent(node.id, () {
- return node.onStateChange.listen((state) => _dirty());
- });
-
- return node.asset;
- });
- }
-
- /// Run [Transformer.apply] as soon as [primary] is available.
- ///
- /// Returns whether or not an error occurred while running the transformer.
- Future<bool> _runApply() {
- var transformController = new TransformController(this);
- _streams.onLogPool.add(transformController.onLog);
-
- return primary.whenAvailable((_) {
- if (_isRemoved) return null;
- _state = _State.APPLYING;
- return syncFuture(() => transformer.apply(transformController.transform));
- }).then((_) {
- if (!_forced && !primary.state.isAvailable) {
- _state = _State.DECLARED;
- _streams.changeStatus(NodeStatus.IDLE);
- return false;
- }
-
- if (_isRemoved) return false;
- if (_state == _State.NEEDS_APPLY) return false;
- if (_state == _State.DECLARING) return false;
- if (transformController.loggedError) return true;
- _handleApplyResults(transformController);
- return false;
- }).catchError((error, stackTrace) {
- // If the transform became dirty while processing, ignore any errors from
- // it.
- if (_state == _State.NEEDS_APPLY || _isRemoved) return false;
-
- // Catch all transformer errors and pipe them to the results stream. This
- // is so a broken transformer doesn't take down the whole graph.
- phase.cascade.reportError(_wrapException(error, stackTrace));
- return true;
- });
- }
-
- /// Handle the results of running [Transformer.apply].
- ///
- /// [transformController] should be the controller for the [Transform] passed
- /// to [Transformer.apply].
- void _handleApplyResults(TransformController transformController) {
- _consumePrimary = transformController.consumePrimary;
-
- var newOutputs = transformController.outputs;
- // Any ids that are for a different package are invalid.
- var invalidIds = newOutputs
- .map((asset) => asset.id)
- .where((id) => id.package != phase.cascade.package)
- .toSet();
- for (var id in invalidIds) {
- newOutputs.removeId(id);
- // TODO(nweiz): report this as a warning rather than a failing error.
- phase.cascade.reportError(new InvalidOutputException(info, id));
- }
-
- // Remove outputs that used to exist but don't anymore.
- for (var id in _outputControllers.keys.toList()) {
- if (newOutputs.containsId(id)) continue;
- _outputControllers.remove(id).setRemoved();
- }
-
- // Emit or stop emitting the pass-through asset between removing and
- // adding outputs to ensure there are no collisions.
- if (!_consumePrimary && !newOutputs.containsId(primary.id)) {
- _emitPassThrough();
- } else {
- _dontEmitPassThrough();
- }
-
- // Store any new outputs or new contents for existing outputs.
- for (var asset in newOutputs) {
- var controller = _outputControllers[asset.id];
- if (controller != null) {
- controller.setAvailable(asset);
- } else {
- var controller = new AssetNodeController.available(asset, this);
- _outputControllers[asset.id] = controller;
- _streams.onAssetController.add(controller.node);
- }
- }
- }
-
- /// Cancels all subscriptions to secondary input nodes.
- void _clearInputSubscriptions() {
- _missingInputs.clear();
- for (var subscription in _inputSubscriptions.values) {
- subscription.cancel();
- }
- _inputSubscriptions.clear();
- }
-
- /// Removes all output assets.
- void _clearOutputs() {
- // Remove all the previously-emitted assets.
- for (var controller in _outputControllers.values) {
- controller.setRemoved();
- }
- _outputControllers.clear();
- }
-
- /// Emit the pass-through asset if it's not being emitted already.
- void _emitPassThrough() {
- assert(!_outputControllers.containsKey(primary.id));
-
- if (_consumePrimary) return;
- if (_passThroughController == null) {
- _passThroughController = new AssetNodeController.from(primary);
- _streams.onAssetController.add(_passThroughController.node);
- } else if (primary.state.isDirty) {
- _passThroughController.setDirty();
- } else if (!_passThroughController.node.state.isAvailable) {
- _passThroughController.setAvailable(primary.asset);
- }
- }
-
- /// Stop emitting the pass-through asset if it's being emitted already.
- void _dontEmitPassThrough() {
- if (_passThroughController == null) return;
- _passThroughController.setRemoved();
- _passThroughController = null;
- }
-
- BarbackException _wrapException(error, StackTrace stackTrace) {
- if (error is! AssetNotFoundException) {
- return new TransformerException(info, error, stackTrace);
- } else {
- return new MissingInputException(info, error.id);
- }
- }
-
- /// Emit a warning about the transformer on [id].
- void _warn(String message) {
- _streams.onLogController.add(
- new LogEntry(info, primary.id, LogLevel.WARNING, message, null));
- }
-
- String toString() =>
- "transform node in $_location for $transformer on $primary ($_state, "
- "$status, ${_forced ? '' : 'un'}forced)";
-}
-
-/// The enum of states that [TransformNode] can be in.
-class _State {
- /// The transform is running [DeclaringTransformer.declareOutputs].
- ///
- /// This is the initial state of the transformer, and it will only occur once
- /// since [DeclaringTransformer.declareOutputs] is independent of the contents
- /// of the primary input. Once the method finishes running, this will
- /// transition to [APPLYING] if the transform is non-lazy and the input is
- /// available, and [DECLARED] otherwise.
- ///
- /// Non-declaring transformers will transition out of this state and into
- /// [APPLYING] immediately.
- static final DECLARING = const _State._("declaring outputs");
-
- /// The transform is deferred and has run
- /// [DeclaringTransformer.declareOutputs] but hasn't yet been forced.
- ///
- /// This will transition to [APPLYING] when one of the outputs has been
- /// forced.
- static final DECLARED = const _State._("declared");
-
- /// The transform is running [Transformer.apply].
- ///
- /// If an input changes while in this state, it will transition to
- /// [NEEDS_APPLY]. If the [TransformNode] is still in this state when
- /// [Transformer.apply] finishes running, it will transition to [APPLIED].
- static final APPLYING = const _State._("applying");
-
- /// The transform is running [Transformer.apply], but an input changed after
- /// it started, so it will need to re-run [Transformer.apply].
- ///
- /// This will transition to [APPLYING] once [Transformer.apply] finishes
- /// running.
- static final NEEDS_APPLY = const _State._("needs apply");
-
- /// The transform has finished running [Transformer.apply], whether or not it
- /// emitted an error.
- ///
- /// If the transformer is deferred, the [TransformNode] can also be in this
- /// state when [Transformer.declareOutputs] has been run but
- /// [Transformer.apply] has not.
- ///
- /// If an input changes, this will transition to [DECLARED] if the transform
- /// is deferred and [APPLYING] otherwise.
- static final APPLIED = const _State._("applied");
-
- final String name;
-
- const _State._(this.name);
-
- String toString() => name;
-}
« no previous file with comments | « pkg/barback/lib/src/transform_logger.dart ('k') | pkg/barback/lib/src/transformer.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698