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

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

Issue 255283003: Don't assume that a transform node is consistently deferred or not. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 7 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
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';
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
45 /// The subscription to [phase]'s [Phase.onAsset] stream. 45 /// The subscription to [phase]'s [Phase.onAsset] stream.
46 StreamSubscription<AssetNode> _phaseSubscription; 46 StreamSubscription<AssetNode> _phaseSubscription;
47 47
48 /// How far along [this] is in processing its assets. 48 /// How far along [this] is in processing its assets.
49 NodeStatus get status { 49 NodeStatus get status {
50 if (_state == _State.NOT_PRIMARY || _state == _State.APPLIED || 50 if (_state == _State.NOT_PRIMARY || _state == _State.APPLIED ||
51 _state == _State.DECLARED) { 51 _state == _State.DECLARED) {
52 return NodeStatus.IDLE; 52 return NodeStatus.IDLE;
53 } 53 }
54 54
55 if (transformer is DeclaringTransformer && _state != _State.DECLARING) { 55 if (_declaring && _state != _State.DECLARING) {
56 return NodeStatus.MATERIALIZING; 56 return NodeStatus.MATERIALIZING;
57 } else { 57 } else {
58 return NodeStatus.RUNNING; 58 return NodeStatus.RUNNING;
59 } 59 }
60 } 60 }
61 61
62 /// Whether this transform is deferred. 62 /// Whether this is a declaring transform.
63 /// 63 ///
64 /// A transform is deferred if either its transformer is lazy or if its 64 /// This is usually identical to `transformer is DeclaringTransformer`, but if
65 /// transformer is declaring and its primary input comes from a deferred 65 /// a declaring and non-lazy transformer emits an error during
66 /// transformer. 66 /// `declareOutputs` it's treated as though it wasn't declaring.
67 final bool deferred; 67 bool get _declaring => transformer is DeclaringTransformer &&
68 (_state == _State.DECLARING || _declaredOutputs != null);
68 69
69 /// Whether this transform has been forced since it last finished applying. 70 /// Whether this transform has been forced since it last finished applying.
70 /// 71 ///
71 /// A transform being forced means it should run until it generates outputs 72 /// A transform being forced means it should run until it generates outputs
72 /// and is no longer dirty. This is always true for non-[deferred] 73 /// and is no longer dirty. This is always true for non-declaring
73 /// transformers, since they always need to eagerly generate outputs. 74 /// transformers, since they always need to eagerly generate outputs.
74 bool _forced; 75 bool _forced;
75 76
76 /// The subscriptions to each input's [AssetNode.onStateChange] stream. 77 /// The subscriptions to each input's [AssetNode.onStateChange] stream.
77 final _inputSubscriptions = new Map<AssetId, StreamSubscription>(); 78 final _inputSubscriptions = new Map<AssetId, StreamSubscription>();
78 79
79 /// The controllers for the asset nodes emitted by this node. 80 /// The controllers for the asset nodes emitted by this node.
80 final _outputControllers = new Map<AssetId, AssetNodeController>(); 81 final _outputControllers = new Map<AssetId, AssetNodeController>();
81 82
82 /// The ids of inputs the transformer tried and failed to read last time it 83 /// The ids of inputs the transformer tried and failed to read last time it
(...skipping 14 matching lines...) Expand all
97 Stream<NodeStatus> get onStatusChange => _streams.onStatusChange; 98 Stream<NodeStatus> get onStatusChange => _streams.onStatusChange;
98 Stream<AssetNode> get onAsset => _streams.onAsset; 99 Stream<AssetNode> get onAsset => _streams.onAsset;
99 Stream<LogEntry> get onLog => _streams.onLog; 100 Stream<LogEntry> get onLog => _streams.onLog;
100 101
101 /// The current state of [this]. 102 /// The current state of [this].
102 var _state = _State.DECLARING; 103 var _state = _State.DECLARING;
103 104
104 /// Whether [this] has been marked as removed. 105 /// Whether [this] has been marked as removed.
105 bool get _isRemoved => _streams.onAssetController.isClosed; 106 bool get _isRemoved => _streams.onAssetController.isClosed;
106 107
108 // If [transformer] is declaring but not lazy and [primary] is available, we
109 // can run [apply] even if [force] hasn't been called, since [transformer]
110 // should run eagerly if possible.
111 bool get _canRunDeclaringEagerly =>
112 _declaring && transformer is! LazyTransformer &&
113 primary.state.isAvailable;
114
107 /// Whether the most recent run of this transform has declared that it 115 /// Whether the most recent run of this transform has declared that it
108 /// consumes the primary input. 116 /// consumes the primary input.
109 /// 117 ///
110 /// Defaults to `false`. This is not meaningful unless [_state] is 118 /// Defaults to `false`. This is not meaningful unless [_state] is
111 /// [_State.APPLIED] or [_State.DECLARED]. 119 /// [_State.APPLIED] or [_State.DECLARED].
112 bool _consumePrimary = false; 120 bool _consumePrimary = false;
113 121
114 /// The set of output ids that [transformer] declared it would emit. 122 /// The set of output ids that [transformer] declared it would emit.
115 /// 123 ///
116 /// This is only non-null if [transformer] is a [DeclaringTransformer] and its 124 /// This is only non-null if [transformer] is a [DeclaringTransformer] and its
117 /// [declareOutputs] has been run successfully. 125 /// [declareOutputs] has been run successfully.
118 Set<AssetId> _declaredOutputs; 126 Set<AssetId> _declaredOutputs;
119 127
120 TransformNode(this.phase, Transformer transformer, AssetNode primary, 128 TransformNode(this.phase, Transformer transformer, AssetNode primary,
121 this._location) 129 this._location)
122 : transformer = transformer, 130 : transformer = transformer,
123 primary = primary, 131 primary = primary {
124 deferred = transformer is LazyTransformer || 132 _forced = transformer is! DeclaringTransformer;
125 (transformer is DeclaringTransformer && primary.deferred) {
126 _forced = !deferred;
127 133
128 _primarySubscription = primary.onStateChange.listen((state) { 134 _primarySubscription = primary.onStateChange.listen((state) {
129 if (state.isRemoved) { 135 if (state.isRemoved) {
130 remove(); 136 remove();
131 } else { 137 } else {
132 if (state.isDirty && !deferred) primary.force(); 138 if (_forced) primary.force();
133 // If this is deferred but applying, that means it must have been
134 // forced, so we should ensure its input remains forced as well.
135 if (deferred && _forced && _state == _State.APPLYING) primary.force();
136 _dirty(); 139 _dirty();
137 } 140 }
138 }); 141 });
139 142
140 _phaseSubscription = phase.previous.onAsset.listen((node) { 143 _phaseSubscription = phase.previous.onAsset.listen((node) {
141 if (!_missingInputs.contains(node.id)) return; 144 if (!_missingInputs.contains(node.id)) return;
142 if (!deferred) node.force(); 145 if (_forced) node.force();
143 _dirty(); 146 _dirty();
144 }); 147 });
145 148
146 _isPrimary(); 149 _isPrimary();
147 } 150 }
148 151
149 /// The [TransformInfo] describing this node. 152 /// The [TransformInfo] describing this node.
150 /// 153 ///
151 /// [TransformInfo] is the publicly-visible representation of a transform 154 /// [TransformInfo] is the publicly-visible representation of a transform
152 /// node. 155 /// node.
(...skipping 16 matching lines...) Expand all
169 _passThroughController = null; 172 _passThroughController = null;
170 } 173 }
171 } 174 }
172 175
173 /// If [this] is deferred, ensures that its concrete outputs will be 176 /// If [this] is deferred, ensures that its concrete outputs will be
174 /// generated. 177 /// generated.
175 void force() { 178 void force() {
176 if (_forced || _state == _State.APPLIED) return; 179 if (_forced || _state == _State.APPLIED) return;
177 primary.force(); 180 primary.force();
178 _forced = true; 181 _forced = true;
179 _dirty(); 182 if (_state == _State.DECLARED) _dirty();
180 } 183 }
181 184
182 /// Marks this transform as dirty. 185 /// Marks this transform as dirty.
183 /// 186 ///
184 /// This causes all of the transform's outputs to be marked as dirty as well. 187 /// This causes all of the transform's outputs to be marked as dirty as well.
185 void _dirty() { 188 void _dirty() {
186 if (_state == _State.NOT_PRIMARY) { 189 if (_state == _State.NOT_PRIMARY) {
187 _emitPassThrough(); 190 _emitPassThrough();
188 return; 191 return;
189 } 192 }
190 193
191 // If we're in the process of running [isPrimary] or [declareOutputs], we 194 // If we're in the process of running [isPrimary] or [declareOutputs], we
192 // already know that [apply] needs to be run so there's nothing we need to 195 // already know that [apply] needs to be run so there's nothing we need to
193 // mark as dirty. 196 // mark as dirty.
194 if (_state == _State.DECLARING) return; 197 if (_state == _State.DECLARING) return;
195 198
196 // If [transformer] is declaring but not lazy and [primary] is available, we 199 if (!_forced && !_canRunDeclaringEagerly) {
197 // do want to start running [apply] even if [force] hasn't been called, 200 // [forced] should only ever be false for a declaring transformer.
198 // since [transformer] should run eagerly if possible. 201 assert(_declaring);
199 var canRunDeclaringEagerly =
200 transformer is! LazyTransformer && primary.state.isAvailable;
201 if (!_forced && !canRunDeclaringEagerly) {
202 // [forced] should only ever be false for a deferred transform.
203 assert(deferred);
204 202
205 // If we've finished applying, transition to MATERIALIZING, indicating 203 // If we've finished applying, transition to MATERIALIZING, indicating
206 // that we know what outputs [apply] will emit but we're waiting to emit 204 // that we know what outputs [apply] will emit but we're waiting to emit
207 // them concretely until [force] is called. If we're still applying, we'll 205 // them concretely until [force] is called. If we're still applying, we'll
208 // transition to MATERIALIZING once we finish. 206 // transition to MATERIALIZING once we finish.
209 if (_state == _State.APPLIED) _state = _State.DECLARED; 207 if (_state == _State.APPLIED) _state = _State.DECLARED;
210 for (var controller in _outputControllers.values) { 208 for (var controller in _outputControllers.values) {
211 controller.setLazy(force); 209 controller.setLazy(force);
212 } 210 }
213 _emitDeclaredOutputs(); 211 _emitDeclaredOutputs();
(...skipping 25 matching lines...) Expand all
239 if (_isRemoved) return false; 237 if (_isRemoved) return false;
240 238
241 // 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
242 // 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.
243 phase.cascade.reportError(_wrapException(error, stackTrace)); 241 phase.cascade.reportError(_wrapException(error, stackTrace));
244 242
245 return false; 243 return false;
246 }).then((isPrimary) { 244 }).then((isPrimary) {
247 if (_isRemoved) return null; 245 if (_isRemoved) return null;
248 if (isPrimary) { 246 if (isPrimary) {
249 if (!deferred) primary.force(); 247 if (_forced) primary.force();
250 return _declareOutputs().then((_) { 248 return _declareOutputs().then((_) {
251 if (_isRemoved) return; 249 if (_isRemoved) return;
252 if (_forced) { 250 if (_forced || _canRunDeclaringEagerly) {
253 _apply(); 251 _apply();
254 } else { 252 } else {
255 _state = _State.DECLARED; 253 _state = _State.DECLARED;
256 _streams.changeStatus(NodeStatus.IDLE); 254 _streams.changeStatus(NodeStatus.IDLE);
257 } 255 }
258 }); 256 });
259 } 257 }
260 258
261 _emitPassThrough(); 259 _emitPassThrough();
262 _state = _State.NOT_PRIMARY; 260 _state = _State.NOT_PRIMARY;
(...skipping 21 matching lines...) Expand all
284 for (var id in invalidIds) { 282 for (var id in invalidIds) {
285 _declaredOutputs.remove(id); 283 _declaredOutputs.remove(id);
286 // TODO(nweiz): report this as a warning rather than a failing error. 284 // TODO(nweiz): report this as a warning rather than a failing error.
287 phase.cascade.reportError(new InvalidOutputException(info, id)); 285 phase.cascade.reportError(new InvalidOutputException(info, id));
288 } 286 }
289 287
290 if (!_declaredOutputs.contains(primary.id)) _emitPassThrough(); 288 if (!_declaredOutputs.contains(primary.id)) _emitPassThrough();
291 _emitDeclaredOutputs(); 289 _emitDeclaredOutputs();
292 }).catchError((error, stackTrace) { 290 }).catchError((error, stackTrace) {
293 if (_isRemoved) return; 291 if (_isRemoved) return;
292 if (transformer is! LazyTransformer) _forced = true;
294 phase.cascade.reportError(_wrapException(error, stackTrace)); 293 phase.cascade.reportError(_wrapException(error, stackTrace));
295 }); 294 });
296 } 295 }
297 296
298 /// Emits a dirty asset node for all outputs that were declared by the 297 /// Emits a dirty asset node for all outputs that were declared by the
299 /// transformer. 298 /// transformer.
300 /// 299 ///
301 /// This won't emit any outputs for which there already exist output 300 /// This won't emit any outputs for which there already exist output
302 /// controllers. It should only be called for transforms that have declared 301 /// controllers. It should only be called for transforms that have declared
303 /// their outputs. 302 /// their outputs.
(...skipping 21 matching lines...) Expand all
325 _runApply().then((hadError) { 324 _runApply().then((hadError) {
326 if (_isRemoved) return; 325 if (_isRemoved) return;
327 326
328 if (_state == _State.DECLARED) return; 327 if (_state == _State.DECLARED) return;
329 328
330 if (_state == _State.NEEDS_APPLY) { 329 if (_state == _State.NEEDS_APPLY) {
331 _apply(); 330 _apply();
332 return; 331 return;
333 } 332 }
334 333
335 if (deferred) _forced = false; 334 if (_declaring) _forced = false;
336 335
337 assert(_state == _State.APPLYING); 336 assert(_state == _State.APPLYING);
338 if (hadError) { 337 if (hadError) {
339 _clearOutputs(); 338 _clearOutputs();
340 // If the transformer threw an error, we don't want to emit the 339 // If the transformer threw an error, we don't want to emit the
341 // pass-through asset in case it will be overwritten by the transformer. 340 // pass-through asset in case it will be overwritten by the transformer.
342 // However, if the transformer declared that it wouldn't overwrite or 341 // However, if the transformer declared that it wouldn't overwrite or
343 // consume the pass-through asset, we can safely emit it. 342 // consume the pass-through asset, we can safely emit it.
344 if (_declaredOutputs != null && !_consumePrimary && 343 if (_declaredOutputs != null && !_consumePrimary &&
345 !_declaredOutputs.contains(primary.id)) { 344 !_declaredOutputs.contains(primary.id)) {
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
380 /// Returns whether or not an error occurred while running the transformer. 379 /// Returns whether or not an error occurred while running the transformer.
381 Future<bool> _runApply() { 380 Future<bool> _runApply() {
382 var transformController = new TransformController(this); 381 var transformController = new TransformController(this);
383 _streams.onLogPool.add(transformController.onLog); 382 _streams.onLogPool.add(transformController.onLog);
384 383
385 return primary.whenAvailable((_) { 384 return primary.whenAvailable((_) {
386 if (_isRemoved) return null; 385 if (_isRemoved) return null;
387 _state = _State.APPLYING; 386 _state = _State.APPLYING;
388 return syncFuture(() => transformer.apply(transformController.transform)); 387 return syncFuture(() => transformer.apply(transformController.transform));
389 }).then((_) { 388 }).then((_) {
390 if (deferred && !_forced && !primary.state.isAvailable) { 389 if (!_forced && !primary.state.isAvailable) {
391 _state = _State.DECLARED; 390 _state = _State.DECLARED;
392 _streams.changeStatus(NodeStatus.IDLE); 391 _streams.changeStatus(NodeStatus.IDLE);
393 return false; 392 return false;
394 } 393 }
395 394
396 if (_isRemoved) return false; 395 if (_isRemoved) return false;
397 if (_state == _State.NEEDS_APPLY) return false; 396 if (_state == _State.NEEDS_APPLY) return false;
398 if (_state == _State.DECLARING) return false; 397 if (_state == _State.DECLARING) return false;
399 if (transformController.loggedError) return true; 398 if (transformController.loggedError) return true;
400 _handleApplyResults(transformController); 399 _handleApplyResults(transformController);
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
505 } 504 }
506 } 505 }
507 506
508 /// Emit a warning about the transformer on [id]. 507 /// Emit a warning about the transformer on [id].
509 void _warn(String message) { 508 void _warn(String message) {
510 _streams.onLogController.add( 509 _streams.onLogController.add(
511 new LogEntry(info, primary.id, LogLevel.WARNING, message, null)); 510 new LogEntry(info, primary.id, LogLevel.WARNING, message, null));
512 } 511 }
513 512
514 String toString() => 513 String toString() =>
515 "transform node in $_location for $transformer on $primary"; 514 "transform node in $_location for $transformer on $primary ($_state, "
515 "$status, ${_forced ? '' : 'un'}forced)";
516 } 516 }
517 517
518 /// The enum of states that [TransformNode] can be in. 518 /// The enum of states that [TransformNode] can be in.
519 class _State { 519 class _State {
520 /// The transform is running [Transformer.isPrimary] followed by 520 /// The transform is running [Transformer.isPrimary] followed by
521 /// [DeclaringTransformer.declareOutputs] (for a [DeclaringTransformer]). 521 /// [DeclaringTransformer.declareOutputs] (for a [DeclaringTransformer]).
522 /// 522 ///
523 /// This is the initial state of the transformer, and it will only occur once 523 /// This is the initial state of the transformer, and it will only occur once
524 /// since [Transformer.isPrimary] and [DeclaringTransformer.declareOutputs] 524 /// since [Transformer.isPrimary] and [DeclaringTransformer.declareOutputs]
525 /// are independent of the contents of the primary input. Once the two methods 525 /// are independent of the contents of the primary input. Once the two methods
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
565 /// 565 ///
566 /// This will never transition to another state. 566 /// This will never transition to another state.
567 static final NOT_PRIMARY = const _State._("not primary"); 567 static final NOT_PRIMARY = const _State._("not primary");
568 568
569 final String name; 569 final String name;
570 570
571 const _State._(this.name); 571 const _State._(this.name);
572 572
573 String toString() => name; 573 String toString() => name;
574 } 574 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698