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

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

Issue 20625005: Support an additional edge case in barback. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: 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/transform.dart ('k') | pkg/barback/test/package_graph/transform_test.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.transform_node; 5 library barback.transform_node;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 8
9 import 'asset.dart'; 9 import 'asset.dart';
10 import 'asset_id.dart'; 10 import 'asset_id.dart';
11 import 'asset_node.dart'; 11 import 'asset_node.dart';
12 import 'asset_set.dart'; 12 import 'asset_set.dart';
13 import 'errors.dart'; 13 import 'errors.dart';
14 import 'phase.dart'; 14 import 'phase.dart';
15 import 'transform.dart'; 15 import 'transform.dart';
16 import 'transformer.dart'; 16 import 'transformer.dart';
17 import 'utils.dart';
17 18
18 /// Describes a transform on a set of assets and its relationship to the build 19 /// Describes a transform on a set of assets and its relationship to the build
19 /// dependency graph. 20 /// dependency graph.
20 /// 21 ///
21 /// Keeps track of whether it's dirty and needs to be run and which assets it 22 /// Keeps track of whether it's dirty and needs to be run and which assets it
22 /// depends on. 23 /// depends on.
23 class TransformNode { 24 class TransformNode {
24 /// The [Phase] that this transform runs in. 25 /// The [Phase] that this transform runs in.
25 final Phase phase; 26 final Phase phase;
26 27
27 /// The [Transformer] to apply to this node's inputs. 28 /// The [Transformer] to apply to this node's inputs.
28 final Transformer transformer; 29 final Transformer transformer;
29 30
30 /// The node for the primary asset this transform depends on. 31 /// The node for the primary asset this transform depends on.
31 final AssetNode primary; 32 final AssetNode primary;
32 33
33 /// The subscription to [primary]'s [AssetNode.onStateChange] stream. 34 /// The subscription to [primary]'s [AssetNode.onStateChange] stream.
34 StreamSubscription _primarySubscription; 35 StreamSubscription _primarySubscription;
35 36
36 /// True if an input has been modified since the last time this transform 37 /// True if an input has been modified since the last time this transform
37 /// began running. 38 /// began running.
38 bool get isDirty => _isDirty; 39 bool get isDirty => _isDirty;
39 var _isDirty = true; 40 var _isDirty = true;
40 41
41 /// The inputs read by this transform the last time it was run.
42 ///
43 /// Used to tell if an input was added or removed in a later run.
44 var _inputs = new Set<AssetNode>();
45
46 /// The subscriptions to each input's [AssetNode.onStateChange] stream. 42 /// The subscriptions to each input's [AssetNode.onStateChange] stream.
47 var _inputSubscriptions = new Map<AssetId, StreamSubscription>(); 43 var _inputSubscriptions = new Map<AssetId, StreamSubscription>();
48 44
49 /// The controllers for the asset nodes emitted by this node. 45 /// The controllers for the asset nodes emitted by this node.
50 var _outputControllers = new Map<AssetId, AssetNodeController>(); 46 var _outputControllers = new Map<AssetId, AssetNodeController>();
51 47
52 TransformNode(this.phase, this.transformer, this.primary) { 48 TransformNode(this.phase, this.transformer, this.primary) {
53 _primarySubscription = primary.onStateChange.listen((state) { 49 _primarySubscription = primary.onStateChange.listen((state) {
54 if (state.isRemoved) { 50 if (state.isRemoved) {
55 remove(); 51 remove();
(...skipping 28 matching lines...) Expand all
84 for (var controller in _outputControllers.values) { 80 for (var controller in _outputControllers.values) {
85 controller.setDirty(); 81 controller.setDirty();
86 } 82 }
87 } 83 }
88 84
89 /// Applies this transform. 85 /// Applies this transform.
90 /// 86 ///
91 /// Returns a set of asset nodes representing the outputs from this transform 87 /// Returns a set of asset nodes representing the outputs from this transform
92 /// that weren't emitted last time it was run. 88 /// that weren't emitted last time it was run.
93 Future<Set<AssetNode>> apply() { 89 Future<Set<AssetNode>> apply() {
94 var newInputs = new Set<AssetNode>();
95 var newOutputs = new AssetSet(); 90 var newOutputs = new AssetSet();
96 var transform = createTransform(this, newInputs, newOutputs); 91 var transform = createTransform(this, newOutputs);
92
93 // Clear all the old input subscriptions. If an input is re-used, we'll
94 // re-subscribe.
95 for (var subscription in _inputSubscriptions.values) {
96 subscription.cancel();
97 }
98 _inputSubscriptions.clear();
99
97 _isDirty = false; 100 _isDirty = false;
98 return transformer.apply(transform).catchError((error) { 101 return transformer.apply(transform).catchError((error) {
99 // If the transform became dirty while processing, ignore any errors from 102 // If the transform became dirty while processing, ignore any errors from
100 // it. 103 // it.
101 if (_isDirty) return; 104 if (_isDirty) return;
102 105
103 // Catch all transformer errors and pipe them to the results stream. 106 // Catch all transformer errors and pipe them to the results stream.
104 // This is so a broken transformer doesn't take down the whole graph. 107 // This is so a broken transformer doesn't take down the whole graph.
105 phase.cascade.reportError(error); 108 phase.cascade.reportError(error);
106 109
107 // Don't allow partial results from a failed transform. 110 // Don't allow partial results from a failed transform.
108 newOutputs.clear(); 111 newOutputs.clear();
109 }).then((_) { 112 }).then((_) {
110 if (_isDirty) return []; 113 if (_isDirty) return [];
111 114
112 _adjustInputs(newInputs);
113 return _adjustOutputs(newOutputs); 115 return _adjustOutputs(newOutputs);
114 }); 116 });
115 } 117 }
116 118
117 /// Adjusts the inputs of the transform to reflect the inputs consumed on its 119 Future<Asset> getInput(AssetId id) {
118 /// most recent run. 120 return newFuture(() {
119 void _adjustInputs(Set<AssetNode> newInputs) { 121 var node = phase.inputs[id];
120 // Stop watching any inputs that were removed. 122 // TODO(rnystrom): Need to handle passthrough where an asset from a
121 for (var oldInput in _inputs.difference(newInputs)) { 123 // previous phase can be found.
122 _inputSubscriptions.remove(oldInput.id).cancel();
123 }
124 124
125 // Watch any new inputs so this transform will be re-processed when an 125 // Throw if the input isn't found. This ensures the transformer's apply
126 // input is modified. 126 // is exited. We'll then catch this and report it through the proper
127 for (var newInput in newInputs.difference(_inputs)) { 127 // results stream.
128 if (newInput.id == primary.id) continue; 128 if (node == null) throw new MissingInputException(id);
129 // TODO(nweiz): support the case where a new secondary input changes
130 // after it's been loaded by the transform but before the transform has
131 // finished running.
132 _inputSubscriptions[newInput.id] = newInput.onStateChange
133 .listen((_) => _dirty());
134 }
135 129
136 _inputs = newInputs; 130 // If the asset node is found, wait until its contents are actually
131 // available before we return them.
132 return node.whenAvailable.then((asset) {
133 _inputSubscriptions.putIfAbsent(node.id,
134 () => node.onStateChange.listen((_) => _dirty()));
135
136 return asset;
137 }).catchError((error) {
138 if (error is! AssetNotFoundException || error.id != id) throw error;
139 // If the node was removed before it could be loaded, treat it as though
140 // it never existed and throw a MissingInputException.
141 throw new MissingInputException(id);
142 });
143 });
137 } 144 }
138 145
139 /// Adjusts the outputs of the transform to reflect the outputs emitted on its 146 /// Adjusts the outputs of the transform to reflect the outputs emitted on its
140 /// most recent run. 147 /// most recent run.
141 Set<AssetNode> _adjustOutputs(AssetSet newOutputs) { 148 Set<AssetNode> _adjustOutputs(AssetSet newOutputs) {
142 // Any ids that are for a different package are invalid. 149 // Any ids that are for a different package are invalid.
143 var invalidIds = newOutputs 150 var invalidIds = newOutputs
144 .map((asset) => asset.id) 151 .map((asset) => asset.id)
145 .where((id) => id.package != phase.cascade.package) 152 .where((id) => id.package != phase.cascade.package)
146 .toSet(); 153 .toSet();
(...skipping 19 matching lines...) Expand all
166 } else { 173 } else {
167 var controller = new AssetNodeController.available(asset); 174 var controller = new AssetNodeController.available(asset);
168 _outputControllers[asset.id] = controller; 175 _outputControllers[asset.id] = controller;
169 brandNewOutputs.add(controller.node); 176 brandNewOutputs.add(controller.node);
170 } 177 }
171 } 178 }
172 179
173 return brandNewOutputs; 180 return brandNewOutputs;
174 } 181 }
175 } 182 }
OLDNEW
« no previous file with comments | « pkg/barback/lib/src/transform.dart ('k') | pkg/barback/test/package_graph/transform_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698