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

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

Issue 189263002: Make Phase.getInput in barback play nicely with the push model. (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 | « no previous file | pkg/barback/lib/src/phase.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.asset_cascade; 5 library barback.asset_cascade;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:collection';
9 8
10 import 'asset.dart'; 9 import 'asset.dart';
11 import 'asset_id.dart'; 10 import 'asset_id.dart';
12 import 'asset_node.dart'; 11 import 'asset_node.dart';
13 import 'asset_set.dart'; 12 import 'asset_set.dart';
14 import 'log.dart'; 13 import 'log.dart';
15 import 'cancelable_future.dart'; 14 import 'cancelable_future.dart';
16 import 'errors.dart'; 15 import 'errors.dart';
17 import 'package_graph.dart'; 16 import 'package_graph.dart';
18 import 'phase.dart'; 17 import 'phase.dart';
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
71 /// 70 ///
72 /// This is synchronous in order to guarantee that it will emit an event as 71 /// This is synchronous in order to guarantee that it will emit an event as
73 /// soon as [isDirty] flips from `true` to `false`. 72 /// soon as [isDirty] flips from `true` to `false`.
74 Stream get onDone => _onDoneController.stream; 73 Stream get onDone => _onDoneController.stream;
75 final _onDoneController = new StreamController.broadcast(sync: true); 74 final _onDoneController = new StreamController.broadcast(sync: true);
76 75
77 /// Returns all currently-available output assets from this cascade. 76 /// Returns all currently-available output assets from this cascade.
78 AssetSet get availableOutputs => 77 AssetSet get availableOutputs =>
79 new AssetSet.from(_phases.last.availableOutputs.map((node) => node.asset)); 78 new AssetSet.from(_phases.last.availableOutputs.map((node) => node.asset));
80 79
81 /// A map of asset ids to completers for [getAssetNode] requests.
82 ///
83 /// If an asset node is requested before it's available, we put a completer in
84 /// this map to wait for the asset to be generated. If it's not generated, the
85 /// completer should complete to `null`.
86 final _pendingAssetRequests = new Map<AssetId, Completer<AssetNode>>();
87
88 /// Creates a new [AssetCascade]. 80 /// Creates a new [AssetCascade].
89 /// 81 ///
90 /// It loads source assets within [package] using [provider]. 82 /// It loads source assets within [package] using [provider].
91 AssetCascade(this.graph, this.package) { 83 AssetCascade(this.graph, this.package) {
92 _addPhase(new Phase(this, package)); 84 _addPhase(new Phase(this, package));
93 } 85 }
94 86
95 /// Gets the asset identified by [id]. 87 /// Gets the asset identified by [id].
96 /// 88 ///
97 /// If [id] is for a generated or transformed asset, this will wait until it 89 /// If [id] is for a generated or transformed asset, this will wait until it
98 /// has been created and return it. This means that the returned asset will 90 /// has been created and return it. This means that the returned asset will
99 /// always be [AssetState.AVAILABLE]. 91 /// always be [AssetState.AVAILABLE].
100 /// 92 ///
101 /// If the asset cannot be found, returns null. 93 /// If the asset cannot be found, returns null.
102 Future<AssetNode> getAssetNode(AssetId id) { 94 Future<AssetNode> getAssetNode(AssetId id) {
103 assert(id.package == package); 95 assert(id.package == package);
104 96
97 var oldLastPhase = _phases.last;
105 // TODO(rnystrom): Waiting for the entire build to complete is unnecessary 98 // TODO(rnystrom): Waiting for the entire build to complete is unnecessary
106 // in some cases. Should optimize: 99 // in some cases. Should optimize:
107 // * [id] may be generated before the compilation is finished. We should 100 // * [id] may be generated before the compilation is finished. We should
108 // be able to quickly check whether there are any more in-place 101 // be able to quickly check whether there are any more in-place
109 // transformations that can be run on it. If not, we can return it early. 102 // transformations that can be run on it. If not, we can return it early.
110 // * If [id] has never been generated and all active transformers provide 103 // * If [id] has never been generated and all active transformers provide
111 // metadata about the file names of assets it can emit, we can prove that 104 // metadata about the file names of assets it can emit, we can prove that
112 // none of them can emit [id] and fail early. 105 // none of them can emit [id] and fail early.
113 return _phases.last.getOutput(id).then((node) { 106 return oldLastPhase.getOutput(id).then((node) {
114 if (node != null) { 107 // The last phase may have changed if [updateSources] was called after
115 // If the requested asset is available, we can just return it. 108 // requesting the output. In that case, we want the output from the new
116 if (node.state.isAvailable) return node; 109 // last phase.
117 110 if (_phases.last == oldLastPhase) return node;
118 // If the requested asset exists but isn't yet available, wait to see if 111 return getAssetNode(id);
119 // it becomes available. If it's removed before becoming available, try
120 // again, since it could be generated again.
121 node.force();
122 return node.whenAvailable((_) => node).catchError((error) {
123 if (error is! AssetNotFoundException) throw error;
124 return getAssetNode(id);
125 });
126 }
127
128 // If the cascade isn't dirty, the phase won't generate the requested
129 // asset in the future.
130 if (!isDirty) return null;
131
132 // If the cascade is dirty, store a completer for the asset node. If it's
133 // generated in the future, we'll complete this completer.
134 var completer = _pendingAssetRequests.putIfAbsent(id,
135 () => new Completer.sync());
136 return completer.future;
137 }); 112 });
138 } 113 }
139 114
140 /// Adds [sources] to the graph's known set of source assets. 115 /// Adds [sources] to the graph's known set of source assets.
141 /// 116 ///
142 /// Begins applying any transforms that can consume any of the sources. If a 117 /// Begins applying any transforms that can consume any of the sources. If a
143 /// given source is already known, it is considered modified and all 118 /// given source is already known, it is considered modified and all
144 /// transforms that use it will be re-applied. 119 /// transforms that use it will be re-applied.
145 void updateSources(Iterable<AssetId> sources) { 120 void updateSources(Iterable<AssetId> sources) {
146 for (var id in sources) { 121 for (var id in sources) {
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
217 } 192 }
218 } 193 }
219 194
220 void reportError(BarbackException error) { 195 void reportError(BarbackException error) {
221 _errorsController.add(error); 196 _errorsController.add(error);
222 } 197 }
223 198
224 /// Add [phase] to the end of [_phases] and watch its streams. 199 /// Add [phase] to the end of [_phases] and watch its streams.
225 void _addPhase(Phase phase) { 200 void _addPhase(Phase phase) {
226 _onLogPool.add(phase.onLog); 201 _onLogPool.add(phase.onLog);
227 phase.onAsset.listen(_providePendingAsset);
228
229 phase.onDone.listen((_) { 202 phase.onDone.listen((_) {
230 if (isDirty) return; 203 if (!isDirty) _onDoneController.add(null);
231
232 // This cascade has finished building. If anyone's still waiting for
233 // assets, cut off the wait; we won't be generating them, at least until a
234 // source asset changes.
235 for (var completer in _pendingAssetRequests.values) {
236 completer.complete(null);
237 }
238 _pendingAssetRequests.clear();
239 _onDoneController.add(null);
240 }); 204 });
241 205
242 _phases.add(phase); 206 _phases.add(phase);
243 } 207 }
244 208
245 /// Provide an asset to a pending [getAssetNode] call.
246 void _providePendingAsset(AssetNode asset) {
247 // If anyone's waiting for this asset, provide it to them.
248 var request = _pendingAssetRequests.remove(asset.id);
249 if (request == null) return;
250
251 if (asset.state.isAvailable) {
252 request.complete(asset);
253 return;
254 }
255
256 // A lazy asset may be emitted while still dirty. If so, we wait until
257 // it's either available or removed before trying again to access it. We
258 // retry the entire [getAsset] process because the state of the graph may
259 // have changed dramatically by the time it's available.
260 assert(asset.state.isDirty);
261 asset.force();
262 asset.whenStateChanges()
263 .then((_) => getAssetNode(asset.id))
264 .then(request.complete)
265 .catchError(request.completeError);
266 }
267
268 String toString() => "cascade for $package"; 209 String toString() => "cascade for $package";
269 } 210 }
OLDNEW
« no previous file with comments | « no previous file | pkg/barback/lib/src/phase.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698