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

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

Issue 249183005: Move common streams in barback to their own class. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « pkg/barback/lib/src/phase_input.dart ('k') | no next file » | 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 'declaring_transform.dart'; 12 import 'declaring_transform.dart';
13 import 'declaring_transformer.dart'; 13 import 'declaring_transformer.dart';
14 import 'errors.dart'; 14 import 'errors.dart';
15 import 'lazy_transformer.dart'; 15 import 'lazy_transformer.dart';
16 import 'log.dart'; 16 import 'log.dart';
17 import 'node_streams.dart';
17 import 'phase.dart'; 18 import 'phase.dart';
18 import 'stream_pool.dart';
19 import 'transform.dart'; 19 import 'transform.dart';
20 import 'transformer.dart'; 20 import 'transformer.dart';
21 import 'utils.dart'; 21 import 'utils.dart';
22 22
23 /// Describes a transform on a set of assets and its relationship to the build 23 /// Describes a transform on a set of assets and its relationship to the build
24 /// dependency graph. 24 /// dependency graph.
25 /// 25 ///
26 /// Keeps track of whether it's dirty and needs to be run and which assets it 26 /// Keeps track of whether it's dirty and needs to be run and which assets it
27 /// depends on. 27 /// depends on.
28 class TransformNode { 28 class TransformNode {
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
74 74
75 /// The controller that's used to pass [primary] through [this] if it's not 75 /// The controller that's used to pass [primary] through [this] if it's not
76 /// consumed or overwritten. 76 /// consumed or overwritten.
77 /// 77 ///
78 /// This needs an intervening controller to ensure that the output can be 78 /// This needs an intervening controller to ensure that the output can be
79 /// marked dirty when determining whether [this] will consume or overwrite it, 79 /// marked dirty when determining whether [this] will consume or overwrite it,
80 /// and be marked removed if it does. [_passThroughController] will be null 80 /// and be marked removed if it does. [_passThroughController] will be null
81 /// if the asset is not being passed through. 81 /// if the asset is not being passed through.
82 AssetNodeController _passThroughController; 82 AssetNodeController _passThroughController;
83 83
84 /// A stream that emits an event whenever [this] is no longer dirty. 84 /// The asset node for this transform.
85 /// 85 final _streams = new NodeStreams();
86 /// This is synchronous in order to guarantee that it will emit an event as 86 Stream get onDone => _streams.onDone;
87 /// soon as [isDirty] flips from `true` to `false`. 87 Stream<AssetNode> get onAsset => _streams.onAsset;
88 Stream get onDone => _onDoneController.stream; 88 Stream<LogEntry> get onLog => _streams.onLog;
89 final _onDoneController = new StreamController.broadcast(sync: true);
90
91 /// A stream that emits any new assets emitted by [this].
92 ///
93 /// Assets are emitted synchronously to ensure that any changes are thoroughly
94 /// propagated as soon as they occur.
95 Stream<AssetNode> get onAsset => _onAssetController.stream;
96 final _onAssetController =
97 new StreamController<AssetNode>.broadcast(sync: true);
98
99 /// A stream that emits an event whenever this transform logs an entry.
100 ///
101 /// This is synchronous because error logs can cause the transform to fail, so
102 /// we need to ensure that their processing isn't delayed until after the
103 /// transform or build has finished.
104 Stream<LogEntry> get onLog => _onLogPool.stream;
105 final _onLogPool = new StreamPool<LogEntry>.broadcast();
106
107 /// A controller for log entries emitted by this node.
108 final _onLogController = new StreamController<LogEntry>.broadcast(sync: true);
109 89
110 /// The current state of [this]. 90 /// The current state of [this].
111 var _state = _State.DECLARING; 91 var _state = _State.DECLARING;
112 92
113 /// Whether [this] has been marked as removed. 93 /// Whether [this] has been marked as removed.
114 bool get _isRemoved => _onAssetController.isClosed; 94 bool get _isRemoved => _streams.onAssetController.isClosed;
115 95
116 /// Whether the most recent run of this transform has declared that it 96 /// Whether the most recent run of this transform has declared that it
117 /// consumes the primary input. 97 /// consumes the primary input.
118 /// 98 ///
119 /// Defaults to `false`. This is not meaningful unless [_state] is 99 /// Defaults to `false`. This is not meaningful unless [_state] is
120 /// [_State.APPLIED] or [_State.DECLARED]. 100 /// [_State.APPLIED] or [_State.DECLARED].
121 bool _consumePrimary = false; 101 bool _consumePrimary = false;
122 102
123 /// The set of output ids that [transformer] declared it would emit. 103 /// The set of output ids that [transformer] declared it would emit.
124 /// 104 ///
125 /// This is only non-null if [transformer] is a [DeclaringTransformer] and its 105 /// This is only non-null if [transformer] is a [DeclaringTransformer] and its
126 /// [declareOutputs] has been run successfully. 106 /// [declareOutputs] has been run successfully.
127 Set<AssetId> _declaredOutputs; 107 Set<AssetId> _declaredOutputs;
128 108
129 TransformNode(this.phase, Transformer transformer, AssetNode primary, 109 TransformNode(this.phase, Transformer transformer, AssetNode primary,
130 this._location) 110 this._location)
131 : transformer = transformer, 111 : transformer = transformer,
132 primary = primary, 112 primary = primary,
133 deferred = transformer is LazyTransformer || 113 deferred = transformer is LazyTransformer ||
134 (transformer is DeclaringTransformer && primary.deferred) { 114 (transformer is DeclaringTransformer && primary.deferred) {
135 _forced = !deferred; 115 _forced = !deferred;
136 116
137 _onLogPool.add(_onLogController.stream);
138
139 _primarySubscription = primary.onStateChange.listen((state) { 117 _primarySubscription = primary.onStateChange.listen((state) {
140 if (state.isRemoved) { 118 if (state.isRemoved) {
141 remove(); 119 remove();
142 } else { 120 } else {
143 if (state.isDirty && !deferred) primary.force(); 121 if (state.isDirty && !deferred) primary.force();
144 // If this is deferred but applying, that means it must have been 122 // If this is deferred but applying, that means it must have been
145 // forced, so we should ensure its input remains forced as well. 123 // forced, so we should ensure its input remains forced as well.
146 if (deferred && _forced && _state == _State.APPLYING) primary.force(); 124 if (deferred && _forced && _state == _State.APPLYING) primary.force();
147 _dirty(); 125 _dirty();
148 } 126 }
(...skipping 14 matching lines...) Expand all
163 /// node. 141 /// node.
164 TransformInfo get info => new TransformInfo(transformer, primary.id); 142 TransformInfo get info => new TransformInfo(transformer, primary.id);
165 143
166 /// Marks this transform as removed. 144 /// Marks this transform as removed.
167 /// 145 ///
168 /// This causes all of the transform's outputs to be marked as removed as 146 /// This causes all of the transform's outputs to be marked as removed as
169 /// well. Normally this will be automatically done internally based on events 147 /// well. Normally this will be automatically done internally based on events
170 /// from the primary input, but it's possible for a transform to no longer be 148 /// from the primary input, but it's possible for a transform to no longer be
171 /// valid even if its primary input still exists. 149 /// valid even if its primary input still exists.
172 void remove() { 150 void remove() {
173 _onLogController.close(); 151 _streams.close();
174 _onAssetController.close();
175 _onDoneController.close();
176 _primarySubscription.cancel(); 152 _primarySubscription.cancel();
177 _phaseSubscription.cancel(); 153 _phaseSubscription.cancel();
178 _clearInputSubscriptions(); 154 _clearInputSubscriptions();
179 _clearOutputs(); 155 _clearOutputs();
180 if (_passThroughController != null) { 156 if (_passThroughController != null) {
181 _passThroughController.setRemoved(); 157 _passThroughController.setRemoved();
182 _passThroughController = null; 158 _passThroughController = null;
183 } 159 }
184 } 160 }
185 161
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
255 }).then((isPrimary) { 231 }).then((isPrimary) {
256 if (_isRemoved) return null; 232 if (_isRemoved) return null;
257 if (isPrimary) { 233 if (isPrimary) {
258 if (!deferred) primary.force(); 234 if (!deferred) primary.force();
259 return _declareOutputs().then((_) { 235 return _declareOutputs().then((_) {
260 if (_isRemoved) return; 236 if (_isRemoved) return;
261 if (_forced) { 237 if (_forced) {
262 _apply(); 238 _apply();
263 } else { 239 } else {
264 _state = _State.DECLARED; 240 _state = _State.DECLARED;
265 _onDoneController.add(null); 241 _streams.onDoneController.add(null);
266 } 242 }
267 }); 243 });
268 } 244 }
269 245
270 _emitPassThrough(); 246 _emitPassThrough();
271 _state = _State.NOT_PRIMARY; 247 _state = _State.NOT_PRIMARY;
272 _onDoneController.add(null); 248 _streams.onDoneController.add(null);
273 }); 249 });
274 } 250 }
275 251
276 /// Runs [transform.declareOutputs] and emits the resulting assets as dirty 252 /// Runs [transform.declareOutputs] and emits the resulting assets as dirty
277 /// assets. 253 /// assets.
278 Future _declareOutputs() { 254 Future _declareOutputs() {
279 if (transformer is! DeclaringTransformer) return new Future.value(); 255 if (transformer is! DeclaringTransformer) return new Future.value();
280 256
281 var controller = new DeclaringTransformController(this); 257 var controller = new DeclaringTransformController(this);
282 return syncFuture(() { 258 return syncFuture(() {
(...skipping 13 matching lines...) Expand all
296 phase.cascade.reportError(new InvalidOutputException(info, id)); 272 phase.cascade.reportError(new InvalidOutputException(info, id));
297 } 273 }
298 274
299 if (!_declaredOutputs.contains(primary.id)) _emitPassThrough(); 275 if (!_declaredOutputs.contains(primary.id)) _emitPassThrough();
300 276
301 for (var id in _declaredOutputs) { 277 for (var id in _declaredOutputs) {
302 var controller = _forced 278 var controller = _forced
303 ? new AssetNodeController(id, this) 279 ? new AssetNodeController(id, this)
304 : new AssetNodeController.lazy(id, force, this); 280 : new AssetNodeController.lazy(id, force, this);
305 _outputControllers[id] = controller; 281 _outputControllers[id] = controller;
306 _onAssetController.add(controller.node); 282 _streams.onAssetController.add(controller.node);
307 } 283 }
308 }).catchError((error, stackTrace) { 284 }).catchError((error, stackTrace) {
309 if (_isRemoved) return; 285 if (_isRemoved) return;
310 phase.cascade.reportError(_wrapException(error, stackTrace)); 286 phase.cascade.reportError(_wrapException(error, stackTrace));
311 }); 287 });
312 } 288 }
313 289
314 /// Applies this transform. 290 /// Applies this transform.
315 void _apply() { 291 void _apply() {
316 assert(!_isRemoved); 292 assert(!_isRemoved);
(...skipping 23 matching lines...) Expand all
340 // consume the pass-through asset, we can safely emit it. 316 // consume the pass-through asset, we can safely emit it.
341 if (_declaredOutputs != null && !_consumePrimary && 317 if (_declaredOutputs != null && !_consumePrimary &&
342 !_declaredOutputs.contains(primary.id)) { 318 !_declaredOutputs.contains(primary.id)) {
343 _emitPassThrough(); 319 _emitPassThrough();
344 } else { 320 } else {
345 _dontEmitPassThrough(); 321 _dontEmitPassThrough();
346 } 322 }
347 } 323 }
348 324
349 _state = _State.APPLIED; 325 _state = _State.APPLIED;
350 _onDoneController.add(null); 326 _streams.onDoneController.add(null);
351 }); 327 });
352 } 328 }
353 329
354 /// Gets the asset for an input [id]. 330 /// Gets the asset for an input [id].
355 /// 331 ///
356 /// If an input with [id] cannot be found, throws an [AssetNotFoundException]. 332 /// If an input with [id] cannot be found, throws an [AssetNotFoundException].
357 Future<Asset> getInput(AssetId id) { 333 Future<Asset> getInput(AssetId id) {
358 return phase.previous.getOutput(id).then((node) { 334 return phase.previous.getOutput(id).then((node) {
359 // Throw if the input isn't found. This ensures the transformer's apply 335 // Throw if the input isn't found. This ensures the transformer's apply
360 // is exited. We'll then catch this and report it through the proper 336 // is exited. We'll then catch this and report it through the proper
361 // results stream. 337 // results stream.
362 if (node == null) { 338 if (node == null) {
363 _missingInputs.add(id); 339 _missingInputs.add(id);
364 throw new AssetNotFoundException(id); 340 throw new AssetNotFoundException(id);
365 } 341 }
366 342
367 _inputSubscriptions.putIfAbsent(node.id, () { 343 _inputSubscriptions.putIfAbsent(node.id, () {
368 return node.onStateChange.listen((state) => _dirty()); 344 return node.onStateChange.listen((state) => _dirty());
369 }); 345 });
370 346
371 return node.asset; 347 return node.asset;
372 }); 348 });
373 } 349 }
374 350
375 /// Run [Transformer.apply] as soon as [primary] is available. 351 /// Run [Transformer.apply] as soon as [primary] is available.
376 /// 352 ///
377 /// Returns whether or not an error occurred while running the transformer. 353 /// Returns whether or not an error occurred while running the transformer.
378 Future<bool> _runApply() { 354 Future<bool> _runApply() {
379 var transformController = new TransformController(this); 355 var transformController = new TransformController(this);
380 _onLogPool.add(transformController.onLog); 356 _streams.onLogPool.add(transformController.onLog);
381 357
382 return primary.whenAvailable((_) { 358 return primary.whenAvailable((_) {
383 if (_isRemoved) return null; 359 if (_isRemoved) return null;
384 _state = _State.APPLYING; 360 _state = _State.APPLYING;
385 return syncFuture(() => transformer.apply(transformController.transform)); 361 return syncFuture(() => transformer.apply(transformController.transform));
386 }).then((_) { 362 }).then((_) {
387 if (deferred && !_forced && !primary.state.isAvailable) { 363 if (deferred && !_forced && !primary.state.isAvailable) {
388 _state = _State.DECLARED; 364 _state = _State.DECLARED;
389 _onDoneController.add(null); 365 _streams.onDoneController.add(null);
390 return false; 366 return false;
391 } 367 }
392 368
393 if (_isRemoved) return false; 369 if (_isRemoved) return false;
394 if (_state == _State.NEEDS_APPLY) return false; 370 if (_state == _State.NEEDS_APPLY) return false;
395 if (_state == _State.DECLARING) return false; 371 if (_state == _State.DECLARING) return false;
396 if (transformController.loggedError) return true; 372 if (transformController.loggedError) return true;
397 _handleApplyResults(transformController); 373 _handleApplyResults(transformController);
398 return false; 374 return false;
399 }).catchError((error, stackTrace) { 375 }).catchError((error, stackTrace) {
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
442 } 418 }
443 419
444 // Store any new outputs or new contents for existing outputs. 420 // Store any new outputs or new contents for existing outputs.
445 for (var asset in newOutputs) { 421 for (var asset in newOutputs) {
446 var controller = _outputControllers[asset.id]; 422 var controller = _outputControllers[asset.id];
447 if (controller != null) { 423 if (controller != null) {
448 controller.setAvailable(asset); 424 controller.setAvailable(asset);
449 } else { 425 } else {
450 var controller = new AssetNodeController.available(asset, this); 426 var controller = new AssetNodeController.available(asset, this);
451 _outputControllers[asset.id] = controller; 427 _outputControllers[asset.id] = controller;
452 _onAssetController.add(controller.node); 428 _streams.onAssetController.add(controller.node);
453 } 429 }
454 } 430 }
455 } 431 }
456 432
457 /// Cancels all subscriptions to secondary input nodes. 433 /// Cancels all subscriptions to secondary input nodes.
458 void _clearInputSubscriptions() { 434 void _clearInputSubscriptions() {
459 _missingInputs.clear(); 435 _missingInputs.clear();
460 for (var subscription in _inputSubscriptions.values) { 436 for (var subscription in _inputSubscriptions.values) {
461 subscription.cancel(); 437 subscription.cancel();
462 } 438 }
463 _inputSubscriptions.clear(); 439 _inputSubscriptions.clear();
464 } 440 }
465 441
466 /// Removes all output assets. 442 /// Removes all output assets.
467 void _clearOutputs() { 443 void _clearOutputs() {
468 // Remove all the previously-emitted assets. 444 // Remove all the previously-emitted assets.
469 for (var controller in _outputControllers.values) { 445 for (var controller in _outputControllers.values) {
470 controller.setRemoved(); 446 controller.setRemoved();
471 } 447 }
472 _outputControllers.clear(); 448 _outputControllers.clear();
473 } 449 }
474 450
475 /// Emit the pass-through asset if it's not being emitted already. 451 /// Emit the pass-through asset if it's not being emitted already.
476 void _emitPassThrough() { 452 void _emitPassThrough() {
477 assert(!_outputControllers.containsKey(primary.id)); 453 assert(!_outputControllers.containsKey(primary.id));
478 454
479 if (_consumePrimary) return; 455 if (_consumePrimary) return;
480 if (_passThroughController == null) { 456 if (_passThroughController == null) {
481 _passThroughController = new AssetNodeController.from(primary); 457 _passThroughController = new AssetNodeController.from(primary);
482 _onAssetController.add(_passThroughController.node); 458 _streams.onAssetController.add(_passThroughController.node);
483 } else if (primary.state.isDirty) { 459 } else if (primary.state.isDirty) {
484 _passThroughController.setDirty(); 460 _passThroughController.setDirty();
485 } else if (!_passThroughController.node.state.isAvailable) { 461 } else if (!_passThroughController.node.state.isAvailable) {
486 _passThroughController.setAvailable(primary.asset); 462 _passThroughController.setAvailable(primary.asset);
487 } 463 }
488 } 464 }
489 465
490 /// Stop emitting the pass-through asset if it's being emitted already. 466 /// Stop emitting the pass-through asset if it's being emitted already.
491 void _dontEmitPassThrough() { 467 void _dontEmitPassThrough() {
492 if (_passThroughController == null) return; 468 if (_passThroughController == null) return;
493 _passThroughController.setRemoved(); 469 _passThroughController.setRemoved();
494 _passThroughController = null; 470 _passThroughController = null;
495 } 471 }
496 472
497 BarbackException _wrapException(error, StackTrace stackTrace) { 473 BarbackException _wrapException(error, StackTrace stackTrace) {
498 if (error is! AssetNotFoundException) { 474 if (error is! AssetNotFoundException) {
499 return new TransformerException(info, error, stackTrace); 475 return new TransformerException(info, error, stackTrace);
500 } else { 476 } else {
501 return new MissingInputException(info, error.id); 477 return new MissingInputException(info, error.id);
502 } 478 }
503 } 479 }
504 480
505 /// Emit a warning about the transformer on [id]. 481 /// Emit a warning about the transformer on [id].
506 void _warn(String message) { 482 void _warn(String message) {
507 _onLogController.add( 483 _streams.onLogController.add(
508 new LogEntry(info, primary.id, LogLevel.WARNING, message, null)); 484 new LogEntry(info, primary.id, LogLevel.WARNING, message, null));
509 } 485 }
510 486
511 String toString() => 487 String toString() =>
512 "transform node in $_location for $transformer on $primary"; 488 "transform node in $_location for $transformer on $primary";
513 } 489 }
514 490
515 /// The enum of states that [TransformNode] can be in. 491 /// The enum of states that [TransformNode] can be in.
516 class _State { 492 class _State {
517 /// The transform is running [Transformer.isPrimary] followed by 493 /// The transform is running [Transformer.isPrimary] followed by
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
562 /// 538 ///
563 /// This will never transition to another state. 539 /// This will never transition to another state.
564 static final NOT_PRIMARY = const _State._("not primary"); 540 static final NOT_PRIMARY = const _State._("not primary");
565 541
566 final String name; 542 final String name;
567 543
568 const _State._(this.name); 544 const _State._(this.name);
569 545
570 String toString() => name; 546 String toString() => name;
571 } 547 }
OLDNEW
« no previous file with comments | « pkg/barback/lib/src/phase_input.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698