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

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

Issue 196273003: Move isPrimary computation from PhaseInput into TransformNode. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: code review Created 6 years, 9 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/phase_input.dart ('k') | pkg/barback/test/package_graph/errors_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';
13 import 'declaring_transform.dart'; 12 import 'declaring_transform.dart';
14 import 'errors.dart'; 13 import 'errors.dart';
15 import 'lazy_transformer.dart'; 14 import 'lazy_transformer.dart';
16 import 'log.dart'; 15 import 'log.dart';
17 import 'phase.dart'; 16 import 'phase.dart';
18 import 'stream_pool.dart'; 17 import 'stream_pool.dart';
19 import 'transform.dart'; 18 import 'transform.dart';
20 import 'transformer.dart'; 19 import 'transformer.dart';
21 import 'utils.dart'; 20 import 'utils.dart';
22 21
(...skipping 11 matching lines...) Expand all
34 33
35 /// The node for the primary asset this transform depends on. 34 /// The node for the primary asset this transform depends on.
36 final AssetNode primary; 35 final AssetNode primary;
37 36
38 /// A string describing the location of [this] in the transformer graph. 37 /// A string describing the location of [this] in the transformer graph.
39 final String _location; 38 final String _location;
40 39
41 /// The subscription to [primary]'s [AssetNode.onStateChange] stream. 40 /// The subscription to [primary]'s [AssetNode.onStateChange] stream.
42 StreamSubscription _primarySubscription; 41 StreamSubscription _primarySubscription;
43 42
44 // TODO(nweiz): Remove this and move isPrimary computation into TransformNode.
45 /// Whether the parent [PhaseInput] is currently computing whether its input
46 /// is primary for [this].
47 bool _pendingIsPrimary = false;
48
49 /// Whether [this] is dirty and still has more processing to do. 43 /// Whether [this] is dirty and still has more processing to do.
50 bool get isDirty => _pendingIsPrimary || _isApplying; 44 bool get isDirty => !_state.isDone;
51
52 /// Whether any input has become dirty since [_apply] last started running.
53 var _hasBecomeDirty = false;
54
55 /// Whether [_apply] is currently running.
56 var _isApplying = false;
57
58 /// Whether the most recent run of this transform has declared that it
59 /// consumes the primary input.
60 ///
61 /// Defaults to `false`.
62 bool get consumePrimary => _consumePrimary;
63 bool _consumePrimary = false;
64 45
65 /// Whether [transformer] is lazy and this transform has yet to be forced. 46 /// Whether [transformer] is lazy and this transform has yet to be forced.
66 bool _isLazy; 47 bool _isLazy;
67 48
68 /// The subscriptions to each input's [AssetNode.onStateChange] stream. 49 /// The subscriptions to each input's [AssetNode.onStateChange] stream.
69 var _inputSubscriptions = new Map<AssetId, StreamSubscription>(); 50 var _inputSubscriptions = new Map<AssetId, StreamSubscription>();
70 51
71 /// The controllers for the asset nodes emitted by this node. 52 /// The controllers for the asset nodes emitted by this node.
72 var _outputControllers = new Map<AssetId, AssetNodeController>(); 53 var _outputControllers = new Map<AssetId, AssetNodeController>();
73 54
74 // TODO(nweiz): It's weird that this is different than the [onDone] stream the 55 /// The controller that's used to pass [primary] through [this] if it's not
75 // other nodes emit. See if we can make that more consistent. 56 /// consumed or overwritten.
76 /// A stream that emits an event whenever [onDirty] changes its value. 57 ///
58 /// This needs an intervening controller to ensure that the output can be
59 /// marked dirty when determining whether [this] will consume or overwrite it,
60 /// and be marked removed if it does. [_passThroughController] will be null
61 /// if the asset is not being passed through.
62 AssetNodeController _passThroughController;
63
64 /// A stream that emits an event whenever [this] is no longer dirty.
77 /// 65 ///
78 /// This is synchronous in order to guarantee that it will emit an event as 66 /// This is synchronous in order to guarantee that it will emit an event as
79 /// soon as [isDirty] changes. It's possible for this to emit multiple events 67 /// soon as [isDirty] flips from `true` to `false`.
80 /// while [isDirty] is `true`. However, it will only emit a single event each 68 Stream get onDone => _onDoneController.stream;
81 /// time [isDirty] becomes `false`. 69 final _onDoneController = new StreamController.broadcast(sync: true);
82 Stream get onStateChange => _onStateChangeController.stream;
83 final _onStateChangeController = new StreamController.broadcast(sync: true);
84 70
85 /// A stream that emits any new assets emitted by [this]. 71 /// A stream that emits any new assets emitted by [this].
86 /// 72 ///
87 /// Assets are emitted synchronously to ensure that any changes are thoroughly 73 /// Assets are emitted synchronously to ensure that any changes are thoroughly
88 /// propagated as soon as they occur. 74 /// propagated as soon as they occur.
89 Stream<AssetNode> get onAsset => _onAssetController.stream; 75 Stream<AssetNode> get onAsset => _onAssetController.stream;
90 final _onAssetController = new StreamController<AssetNode>(sync: true); 76 final _onAssetController = new StreamController<AssetNode>(sync: true);
91 77
92 /// A stream that emits an event whenever this transform logs an entry. 78 /// A stream that emits an event whenever this transform logs an entry.
93 /// 79 ///
94 /// This is synchronous because error logs can cause the transform to fail, so 80 /// This is synchronous because error logs can cause the transform to fail, so
95 /// we need to ensure that their processing isn't delayed until after the 81 /// we need to ensure that their processing isn't delayed until after the
96 /// transform or build has finished. 82 /// transform or build has finished.
97 Stream<LogEntry> get onLog => _onLogPool.stream; 83 Stream<LogEntry> get onLog => _onLogPool.stream;
98 final _onLogPool = new StreamPool<LogEntry>.broadcast(); 84 final _onLogPool = new StreamPool<LogEntry>.broadcast();
99 85
86 /// The current state of [this].
87 var _state = _TransformNodeState.PROCESSING;
88
89 /// Whether [this] has been marked as removed.
90 bool get _isRemoved => _onAssetController.isClosed;
91
92 /// Whether the most recent run of this transform has declared that it
93 /// consumes the primary input.
94 ///
95 /// Defaults to `false`. This is not meaningful unless [_state] is
96 /// [_TransformNodeState.APPLIED].
97 bool _consumePrimary = false;
98
100 TransformNode(this.phase, Transformer transformer, this.primary, 99 TransformNode(this.phase, Transformer transformer, this.primary,
101 this._location) 100 this._location)
102 : transformer = transformer, 101 : transformer = transformer,
103 _isLazy = transformer is LazyTransformer { 102 _isLazy = transformer is LazyTransformer {
104 _primarySubscription = primary.onStateChange.listen((state) { 103 _primarySubscription = primary.onStateChange.listen((state) {
105 if (state.isRemoved) { 104 if (state.isRemoved) {
106 remove(); 105 remove();
107 } else { 106 } else {
108 if (state.isDirty) _pendingIsPrimary = true; 107 _dirty(primaryChanged: true);
109 _dirty();
110 } 108 }
111 }); 109 });
112 110
113 _apply(); 111 _process();
114 } 112 }
115 113
116 /// The [TransformInfo] describing this node. 114 /// The [TransformInfo] describing this node.
117 /// 115 ///
118 /// [TransformInfo] is the publicly-visible representation of a transform 116 /// [TransformInfo] is the publicly-visible representation of a transform
119 /// node. 117 /// node.
120 TransformInfo get info => new TransformInfo(transformer, primary.id); 118 TransformInfo get info => new TransformInfo(transformer, primary.id);
121 119
122 /// Marks this transform as removed. 120 /// Marks this transform as removed.
123 /// 121 ///
124 /// This causes all of the transform's outputs to be marked as removed as 122 /// This causes all of the transform's outputs to be marked as removed as
125 /// well. Normally this will be automatically done internally based on events 123 /// well. Normally this will be automatically done internally based on events
126 /// from the primary input, but it's possible for a transform to no longer be 124 /// from the primary input, but it's possible for a transform to no longer be
127 /// valid even if its primary input still exists. 125 /// valid even if its primary input still exists.
128 void remove() { 126 void remove() {
129 _hasBecomeDirty = false;
130 _onAssetController.close(); 127 _onAssetController.close();
131 _onStateChangeController.close(); 128 _onDoneController.close();
132 _primarySubscription.cancel(); 129 _primarySubscription.cancel();
133 for (var subscription in _inputSubscriptions.values) { 130 _clearInputSubscriptions();
134 subscription.cancel();
135 }
136 for (var controller in _outputControllers.values) { 131 for (var controller in _outputControllers.values) {
137 controller.setRemoved(); 132 controller.setRemoved();
138 } 133 }
134 if (_passThroughController != null) {
135 _passThroughController.setRemoved();
136 _passThroughController = null;
137 }
139 } 138 }
140 139
141 /// If [transformer] is lazy, ensures that its concrete outputs will be 140 /// If [transformer] is lazy, ensures that its concrete outputs will be
142 /// generated. 141 /// generated.
143 void force() { 142 void force() {
144 // TODO(nweiz): we might want to have a timeout after which, if the 143 // TODO(nweiz): we might want to have a timeout after which, if the
145 // transform's outputs have gone unused, we switch it back to lazy mode. 144 // transform's outputs have gone unused, we switch it back to lazy mode.
146 if (!_isLazy) return; 145 if (!_isLazy) return;
147 _isLazy = false; 146 _isLazy = false;
148 _dirty(); 147 _dirty(primaryChanged: false);
149 }
150
151 // TODO(nweiz): remove this and move isPrimary computation into TransformNode.
152 /// Mark that the parent [PhaseInput] has determined that its input is indeed
153 /// primary for [this].
154 void markPrimary() {
155 if (!_pendingIsPrimary) return;
156 _pendingIsPrimary = false;
157 if (!_isApplying) _apply();
158 } 148 }
159 149
160 /// Marks this transform as dirty. 150 /// Marks this transform as dirty.
161 /// 151 ///
162 /// This causes all of the transform's outputs to be marked as dirty as well. 152 /// This causes all of the transform's outputs to be marked as dirty as well.
163 void _dirty() { 153 /// [primaryChanged] should be true if and only if [this] was set dirty
154 /// because [primary] changed.
155 void _dirty({bool primaryChanged: false}) {
156 if (!primaryChanged && _state.isNotPrimary) return;
157
158 if (_passThroughController != null) _passThroughController.setDirty();
164 for (var controller in _outputControllers.values) { 159 for (var controller in _outputControllers.values) {
165 controller.setDirty(); 160 controller.setDirty();
166 } 161 }
167 162
168 _hasBecomeDirty = true; 163 if (_state.isDone) {
169 _onStateChangeController.add(null); 164 if (primaryChanged) {
170 if (!_isApplying && !_pendingIsPrimary) _apply(); 165 _process();
166 } else {
167 _apply();
168 }
169 } else if (primaryChanged) {
170 _state = _TransformNodeState.NEEDS_IS_PRIMARY;
171 } else if (!_state.needsIsPrimary) {
172 _state = _TransformNodeState.NEEDS_APPLY;
173 }
174 }
175
176 /// Determines whether [primary] is primary for [transformer], and if so runs
177 /// [transformer.apply].
178 void _process() {
179 // Clear all the old input subscriptions. If an input is re-used, we'll
180 // re-subscribe.
181 _clearInputSubscriptions();
182 _state = _TransformNodeState.PROCESSING;
183 primary.whenAvailable((_) {
184 _state = _TransformNodeState.PROCESSING;
185 return transformer.isPrimary(primary.asset);
186 }).catchError((error, stackTrace) {
187 // If the transform became dirty while processing, ignore any errors from
188 // it.
189 if (_state.needsIsPrimary || _isRemoved) return false;
190
191 if (error is! MissingInputException) {
192 error = new TransformerException(info, error, stackTrace);
193 }
194
195 // Catch all transformer errors and pipe them to the results stream. This
196 // is so a broken transformer doesn't take down the whole graph.
197 phase.cascade.reportError(error);
198
199 return false;
200 }).then((isPrimary) {
201 if (_isRemoved) return;
202 if (_state.needsIsPrimary) {
203 _process();
204 } else if (isPrimary) {
205 _apply();
206 } else {
207 _doesNotApply();
208 _state = _TransformNodeState.NOT_PRIMARY;
209 _onDoneController.add(null);
210 }
211 });
171 } 212 }
172 213
173 /// Applies this transform. 214 /// Applies this transform.
174 void _apply() { 215 void _apply() {
175 assert(!_onAssetController.isClosed); 216 assert(!_onAssetController.isClosed);
176 217
177 // Clear all the old input subscriptions. If an input is re-used, we'll 218 // Clear input subscriptions here as well as in [_process] because [_apply]
178 // re-subscribe. 219 // may be restarted independently if only a secondary input changes.
179 for (var subscription in _inputSubscriptions.values) { 220 _clearInputSubscriptions();
180 subscription.cancel(); 221 _state = _TransformNodeState.PROCESSING;
181 }
182 _inputSubscriptions.clear();
183
184 _isApplying = true;
185 _onStateChangeController.add(null);
186 primary.whenAvailable((_) { 222 primary.whenAvailable((_) {
187 _hasBecomeDirty = false; 223 if (_state.needsIsPrimary) return;
188 224 _state = _TransformNodeState.PROCESSING;
189 // TODO(nweiz): If [transformer] is a [DeclaringTransformer] but not a 225 // TODO(nweiz): If [transformer] is a [DeclaringTransformer] but not a
190 // [LazyTransformer], we can get some mileage out of doing a declarative 226 // [LazyTransformer], we can get some mileage out of doing a declarative
191 // first so we know how to hook up the assets. 227 // first so we know how to hook up the assets.
192 if (_isLazy) return _declareLazy(); 228 if (_isLazy) return _declareLazy();
193 return _applyImmediate(); 229 return _applyImmediate();
194 }).catchError((error, stackTrace) { 230 }).catchError((error, stackTrace) {
195 // If the transform became dirty while processing, ignore any errors from 231 // If the transform became dirty while processing, ignore any errors from
196 // it. 232 // it.
197 if (_hasBecomeDirty || _onAssetController.isClosed) return; 233 if (!_state.isProcessing || _isRemoved) return;
198 234
199 if (error is! MissingInputException) { 235 if (error is! MissingInputException) {
200 error = new TransformerException(info, error, stackTrace); 236 error = new TransformerException(info, error, stackTrace);
201 } 237 }
202 238
203 // Catch all transformer errors and pipe them to the results stream. This 239 // Catch all transformer errors and pipe them to the results stream. This
204 // is so a broken transformer doesn't take down the whole graph. 240 // is so a broken transformer doesn't take down the whole graph.
205 phase.cascade.reportError(error); 241 phase.cascade.reportError(error);
206 242
207 // Remove all the previously-emitted assets. 243 _doesNotApply();
208 for (var controller in _outputControllers.values) {
209 controller.setRemoved();
210 }
211 _outputControllers.clear();
212 }).then((_) { 244 }).then((_) {
213 if (_onAssetController.isClosed) return; 245 if (_isRemoved) return;
214 246
215 _isApplying = false; 247 if (_state.needsIsPrimary) {
216 if (_hasBecomeDirty) { 248 _process();
217 // Re-apply the transform if it became dirty while applying. 249 } else if (_state.needsApply) {
218 if (!_pendingIsPrimary) _apply(); 250 _apply();
219 } else { 251 } else {
220 assert(!isDirty); 252 assert(_state.isProcessing);
221 // Otherwise, notify the parent nodes that it's no longer dirty. 253 _state = _TransformNodeState.APPLIED;
222 _onStateChangeController.add(null); 254 _onDoneController.add(null);
223 } 255 }
224 }); 256 });
225 } 257 }
226 258
227 /// Gets the asset for an input [id]. 259 /// Gets the asset for an input [id].
228 /// 260 ///
229 /// If an input with that ID cannot be found, throws an 261 /// If an input with that ID cannot be found, throws an
230 /// [AssetNotFoundException]. 262 /// [AssetNotFoundException].
231 Future<Asset> getInput(AssetId id) { 263 Future<Asset> getInput(AssetId id) {
232 return phase.getInput(id).then((node) { 264 return phase.getInput(id).then((node) {
233 // Throw if the input isn't found. This ensures the transformer's apply 265 // Throw if the input isn't found. This ensures the transformer's apply
234 // is exited. We'll then catch this and report it through the proper 266 // is exited. We'll then catch this and report it through the proper
235 // results stream. 267 // results stream.
236 if (node == null) throw new MissingInputException(info, id); 268 if (node == null) throw new MissingInputException(info, id);
237 269
238 _inputSubscriptions.putIfAbsent(node.id, 270 _inputSubscriptions.putIfAbsent(node.id, () {
239 () => node.onStateChange.listen((_) => _dirty())); 271 return node.onStateChange.listen((_) => _dirty(primaryChanged: false));
272 });
240 273
241 return node.asset; 274 return node.asset;
242 }); 275 });
243 } 276 }
244 277
245 /// Applies the transform so that it produces concrete (as opposed to lazy) 278 /// Applies the transform so that it produces concrete (as opposed to lazy)
246 /// outputs. 279 /// outputs.
247 Future _applyImmediate() { 280 Future _applyImmediate() {
248 var transformController = new TransformController(this); 281 var transformController = new TransformController(this);
249 _onLogPool.add(transformController.onLog); 282 _onLogPool.add(transformController.onLog);
250 283
251 return syncFuture(() { 284 return syncFuture(() {
252 return transformer.apply(transformController.transform); 285 return transformer.apply(transformController.transform);
253 }).then((_) { 286 }).then((_) {
254 if (_hasBecomeDirty || _onAssetController.isClosed) return; 287 if (!_state.isProcessing || _onAssetController.isClosed) return;
255 288
256 _consumePrimary = transformController.consumePrimary; 289 _consumePrimary = transformController.consumePrimary;
257 290
258 var newOutputs = transformController.outputs; 291 var newOutputs = transformController.outputs;
259 // Any ids that are for a different package are invalid. 292 // Any ids that are for a different package are invalid.
260 var invalidIds = newOutputs 293 var invalidIds = newOutputs
261 .map((asset) => asset.id) 294 .map((asset) => asset.id)
262 .where((id) => id.package != phase.cascade.package) 295 .where((id) => id.package != phase.cascade.package)
263 .toSet(); 296 .toSet();
264 for (var id in invalidIds) { 297 for (var id in invalidIds) {
265 newOutputs.removeId(id); 298 newOutputs.removeId(id);
266 // TODO(nweiz): report this as a warning rather than a failing error. 299 // TODO(nweiz): report this as a warning rather than a failing error.
267 phase.cascade.reportError(new InvalidOutputException(info, id)); 300 phase.cascade.reportError(new InvalidOutputException(info, id));
268 } 301 }
269 302
270 // Remove outputs that used to exist but don't anymore. 303 // Remove outputs that used to exist but don't anymore.
271 for (var id in _outputControllers.keys.toList()) { 304 for (var id in _outputControllers.keys.toList()) {
272 if (newOutputs.containsId(id)) continue; 305 if (newOutputs.containsId(id)) continue;
273 _outputControllers.remove(id).setRemoved(); 306 _outputControllers.remove(id).setRemoved();
274 } 307 }
275 308
309 // Emit or stop emitting the pass-through asset between removing and
310 // adding outputs to ensure there are no collisions.
311 if (!newOutputs.containsId(primary.id)) {
312 _emitPassThrough();
313 } else {
314 _dontEmitPassThrough();
315 }
316
276 // Store any new outputs or new contents for existing outputs. 317 // Store any new outputs or new contents for existing outputs.
277 for (var asset in newOutputs) { 318 for (var asset in newOutputs) {
278 var controller = _outputControllers[asset.id]; 319 var controller = _outputControllers[asset.id];
279 if (controller != null) { 320 if (controller != null) {
280 controller.setAvailable(asset); 321 controller.setAvailable(asset);
281 } else { 322 } else {
282 var controller = new AssetNodeController.available(asset, this); 323 var controller = new AssetNodeController.available(asset, this);
283 _outputControllers[asset.id] = controller; 324 _outputControllers[asset.id] = controller;
284 _onAssetController.add(controller.node); 325 _onAssetController.add(controller.node);
285 } 326 }
286 } 327 }
287 }); 328 });
288 } 329 }
289 330
290 /// Applies the transform in declarative mode so that it produces lazy 331 /// Applies the transform in declarative mode so that it produces lazy
291 /// outputs. 332 /// outputs.
292 Future _declareLazy() { 333 Future _declareLazy() {
293 var transformController = new DeclaringTransformController(this); 334 var transformController = new DeclaringTransformController(this);
294 335
295 return syncFuture(() { 336 return syncFuture(() {
296 return (transformer as LazyTransformer) 337 return (transformer as LazyTransformer)
297 .declareOutputs(transformController.transform); 338 .declareOutputs(transformController.transform);
298 }).then((_) { 339 }).then((_) {
299 if (_hasBecomeDirty || _onAssetController.isClosed) return; 340 if (!_state.isProcessing || _onAssetController.isClosed) return;
300 341
301 _consumePrimary = transformController.consumePrimary; 342 _consumePrimary = transformController.consumePrimary;
302 343
303 var newIds = transformController.outputIds; 344 var newIds = transformController.outputIds;
304 var invalidIds = 345 var invalidIds =
305 newIds.where((id) => id.package != phase.cascade.package).toSet(); 346 newIds.where((id) => id.package != phase.cascade.package).toSet();
306 for (var id in invalidIds) { 347 for (var id in invalidIds) {
307 newIds.remove(id); 348 newIds.remove(id);
308 // TODO(nweiz): report this as a warning rather than a failing error. 349 // TODO(nweiz): report this as a warning rather than a failing error.
309 phase.cascade.reportError(new InvalidOutputException(info, id)); 350 phase.cascade.reportError(new InvalidOutputException(info, id));
310 } 351 }
311 352
312 // Remove outputs that used to exist but don't anymore. 353 // Remove outputs that used to exist but don't anymore.
313 for (var id in _outputControllers.keys.toList()) { 354 for (var id in _outputControllers.keys.toList()) {
314 if (newIds.contains(id)) continue; 355 if (newIds.contains(id)) continue;
315 _outputControllers.remove(id).setRemoved(); 356 _outputControllers.remove(id).setRemoved();
316 } 357 }
317 358
359 // Emit or stop emitting the pass-through asset between removing and
360 // adding outputs to ensure there are no collisions.
361 if (!newIds.contains(primary.id)) {
362 _emitPassThrough();
363 } else {
364 _dontEmitPassThrough();
365 }
366
318 for (var id in newIds) { 367 for (var id in newIds) {
319 var controller = _outputControllers[id]; 368 var controller = _outputControllers[id];
320 if (controller != null) { 369 if (controller != null) {
321 controller.setLazy(force); 370 controller.setLazy(force);
322 } else { 371 } else {
323 var controller = new AssetNodeController.lazy(id, force, this); 372 var controller = new AssetNodeController.lazy(id, force, this);
324 _outputControllers[id] = controller; 373 _outputControllers[id] = controller;
325 _onAssetController.add(controller.node); 374 _onAssetController.add(controller.node);
326 } 375 }
327 } 376 }
328 }); 377 });
329 } 378 }
330 379
380 /// Cancels all subscriptions to secondary input nodes.
381 void _clearInputSubscriptions() {
382 for (var subscription in _inputSubscriptions.values) {
383 subscription.cancel();
384 }
385 _inputSubscriptions.clear();
386 }
387
388 /// Marks this transformer as not applying to [primary].
389 ///
390 /// This might be because [primary] isn't primary for [transformer], or
391 /// because [transformer] threw an error during [transformer.apply].
392 void _doesNotApply() {
393 // Remove all the previously-emitted assets.
394 for (var controller in _outputControllers.values) {
395 controller.setRemoved();
396 }
397 _outputControllers.clear();
398 _emitPassThrough();
399 }
400
401 /// Emit the pass-through asset if it's not being emitted already.
402 void _emitPassThrough() {
403 assert(!_outputControllers.containsKey(primary.id));
404
405 if (_consumePrimary) return;
406 if (_passThroughController == null) {
407 _passThroughController = new AssetNodeController.from(primary);
408 _onAssetController.add(_passThroughController.node);
409 } else {
410 _passThroughController.setAvailable(primary.asset);
411 }
412 }
413
414 /// Stop emitting the pass-through asset if it's being emitted already.
415 void _dontEmitPassThrough() {
416 if (_passThroughController == null) return;
417 _passThroughController.setRemoved();
418 _passThroughController = null;
419 }
420
331 String toString() => 421 String toString() =>
332 "transform node in $_location for $transformer on $primary"; 422 "transform node in $_location for $transformer on $primary";
333 } 423 }
424
425 /// The enum of states that [TransformNode] can be in.
426 class _TransformNodeState {
427 /// The transform node is running [Transformer.isPrimary] or
428 /// [Transformer.apply] and doesn't need to re-run them.
429 ///
430 /// If there are no external changes by the time the processing finishes, this
431 /// will transition to [APPLIED] or [NOT_PRIMARY] depending on the result of
432 /// [Transformer.isPrimary]. If the primary input changes, this will
433 /// transition to [NEEDS_IS_PRIMARY]. If a secondary input changes, this will
434 /// transition to [NEEDS_APPLY].
435 static final PROCESSING = const _TransformNodeState._("processing");
436
437 /// The transform is running [Transformer.isPrimary] or [Transformer.apply],
438 /// but since it started the primary input changed, so it will need to re-run
439 /// [Transformer.isPrimary].
440 ///
441 /// This will always transition to [Transformer.PROCESSING].
442 static final NEEDS_IS_PRIMARY =
443 const _TransformNodeState._("needs isPrimary");
444
445 /// The transform is running [Transformer.apply], but since it started a
446 /// secondary input changed, so it will need to re-run [Transformer.apply].
447 ///
448 /// If there are no external changes by the time [Transformer.apply] finishes,
449 /// this will transition to [PROCESSING]. If the primary input changes, this
450 /// will transition to [NEEDS_IS_PRIMARY].
451 static final NEEDS_APPLY = const _TransformNodeState._("needs apply");
452
453 /// The transform has finished running [Transformer.apply], whether or not it
454 /// emitted an error.
455 ///
456 /// If the primary input or a secondary input changes, this will transition to
457 /// [PROCESSING].
458 static final APPLIED = const _TransformNodeState._("applied");
459
460 /// The transform has finished running [Transformer.isPrimary], which returned
461 /// `false`.
462 ///
463 /// If the primary input changes, this will transition to [PROCESSING].
464 static final NOT_PRIMARY = const _TransformNodeState._("not primary");
465
466 /// Whether [this] is [PROCESSING].
467 bool get isProcessing => this == _TransformNodeState.PROCESSING;
468
469 /// Whether [this] is [NEEDS_IS_PRIMARY].
470 bool get needsIsPrimary => this == _TransformNodeState.NEEDS_IS_PRIMARY;
471
472 /// Whether [this] is [NEEDS_APPLY].
473 bool get needsApply => this == _TransformNodeState.NEEDS_APPLY;
474
475 /// Whether [this] is [APPLIED].
476 bool get isApplied => this == _TransformNodeState.APPLIED;
477
478 /// Whether [this] is [NOT_PRIMARY].
479 bool get isNotPrimary => this == _TransformNodeState.NOT_PRIMARY;
480
481 /// Whether the transform has finished running [Transformer.isPrimary] and
482 /// [Transformer.apply].
483 ///
484 /// Specifically, whether [this] is [APPLIED] or [NOT_PRIMARY].
485 bool get isDone => isApplied || isNotPrimary;
486
487 final String name;
488
489 const _TransformNodeState._(this.name);
490
491 String toString() => name;
492 }
OLDNEW
« no previous file with comments | « pkg/barback/lib/src/phase_input.dart ('k') | pkg/barback/test/package_graph/errors_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698