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

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

Issue 22265002: Support cross-package transforms in barback. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Code review changes. 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/barback.dart ('k') | pkg/barback/lib/src/barback.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'; 8 import 'dart:collection';
9 9
10 import 'package:stack_trace/stack_trace.dart';
11
12 import 'asset.dart'; 10 import 'asset.dart';
13 import 'asset_id.dart'; 11 import 'asset_id.dart';
14 import 'asset_node.dart'; 12 import 'asset_node.dart';
13 import 'build_result.dart';
15 import 'cancelable_future.dart'; 14 import 'cancelable_future.dart';
16 import 'errors.dart'; 15 import 'errors.dart';
17 import 'change_batch.dart'; 16 import 'change_batch.dart';
18 import 'package_graph.dart'; 17 import 'package_graph.dart';
19 import 'phase.dart'; 18 import 'phase.dart';
20 import 'transformer.dart'; 19 import 'transformer.dart';
21 import 'utils.dart'; 20 import 'utils.dart';
22 21
23 /// The asset cascade for an individual package. 22 /// The asset cascade for an individual package.
24 /// 23 ///
25 /// This keeps track of which [Transformer]s are applied to which assets, and 24 /// This keeps track of which [Transformer]s are applied to which assets, and
26 /// re-runs those transformers when their dependencies change. The transformed 25 /// re-runs those transformers when their dependencies change. The transformed
27 /// assets are accessible via [getAssetById]. 26 /// asset nodes are accessible via [getAssetNode].
28 /// 27 ///
29 /// A cascade consists of one or more [Phases], each of which has one or more 28 /// A cascade consists of one or more [Phases], each of which has one or more
30 /// [Transformer]s that run in parallel, potentially on the same inputs. The 29 /// [Transformer]s that run in parallel, potentially on the same inputs. The
31 /// inputs of the first phase are the source assets for this cascade's package. 30 /// inputs of the first phase are the source assets for this cascade's package.
32 /// The inputs of each successive phase are the outputs of the previous phase, 31 /// The inputs of each successive phase are the outputs of the previous phase,
33 /// as well as any assets that haven't yet been transformed. 32 /// as well as any assets that haven't yet been transformed.
34 class AssetCascade { 33 class AssetCascade {
35 /// The name of the package whose assets are managed. 34 /// The name of the package whose assets are managed.
36 final String package; 35 final String package;
37 36
38 /// The [PackageGraph] that tracks all [AssetCascade]s for all dependencies of 37 /// The [PackageGraph] that tracks all [AssetCascade]s for all dependencies of
39 /// the current app. 38 /// the current app.
40 final PackageGraph _graph; 39 final PackageGraph graph;
41 40
42 /// The controllers for the [AssetNode]s that provide information about this 41 /// The controllers for the [AssetNode]s that provide information about this
43 /// cascade's package's source assets. 42 /// cascade's package's source assets.
44 final _sourceControllerMap = new Map<AssetId, AssetNodeController>(); 43 final _sourceControllerMap = new Map<AssetId, AssetNodeController>();
45 44
46 /// Futures for source assets that are currently being loaded. 45 /// Futures for source assets that are currently being loaded.
47 /// 46 ///
48 /// These futures are cancelable so that if an asset is updated after a load 47 /// These futures are cancelable so that if an asset is updated after a load
49 /// has been kicked off, the previous load can be ignored in favor of a new 48 /// has been kicked off, the previous load can be ignored in favor of a new
50 /// one. 49 /// one.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
82 81
83 /// Whether any source assets have been updated or removed since processing 82 /// Whether any source assets have been updated or removed since processing
84 /// last began. 83 /// last began.
85 var _newChanges = false; 84 var _newChanges = false;
86 85
87 /// Creates a new [AssetCascade]. 86 /// Creates a new [AssetCascade].
88 /// 87 ///
89 /// It loads source assets within [package] using [provider] and then uses 88 /// It loads source assets within [package] using [provider] and then uses
90 /// [transformerPhases] to generate output files from them. 89 /// [transformerPhases] to generate output files from them.
91 //TODO(rnystrom): Better way of specifying transformers and their ordering. 90 //TODO(rnystrom): Better way of specifying transformers and their ordering.
92 AssetCascade(this._graph, this.package, 91 AssetCascade(this.graph, this.package,
93 Iterable<Iterable<Transformer>> transformerPhases) { 92 Iterable<Iterable<Transformer>> transformerPhases) {
94 // Flatten the phases to a list so we can traverse backwards to wire up 93 // Flatten the phases to a list so we can traverse backwards to wire up
95 // each phase to its next. 94 // each phase to its next.
96 var phases = transformerPhases.toList(); 95 var phases = transformerPhases.toList();
97 96
98 // Each phase writes its outputs as inputs to the next phase after it. 97 // Each phase writes its outputs as inputs to the next phase after it.
99 // Add a phase at the end for the final outputs of the last phase. 98 // Add a phase at the end for the final outputs of the last phase.
100 phases.add([]); 99 phases.add([]);
101 100
102 Phase nextPhase = null; 101 Phase nextPhase = null;
103 for (var transformers in phases.reversed) { 102 for (var transformers in phases.reversed) {
104 nextPhase = new Phase(this, _phases.length, transformers.toList(), 103 nextPhase = new Phase(this, _phases.length, transformers.toList(),
105 nextPhase); 104 nextPhase);
106 nextPhase.onDirty.listen((_) { 105 nextPhase.onDirty.listen((_) {
107 _newChanges = true; 106 _newChanges = true;
108 _waitForProcess(); 107 _waitForProcess();
109 }); 108 });
110 _phases.insert(0, nextPhase); 109 _phases.insert(0, nextPhase);
111 } 110 }
112 } 111 }
113 112
114 /// Gets the asset identified by [id]. 113 /// Gets the asset identified by [id].
115 /// 114 ///
116 /// If [id] is for a generated or transformed asset, this will wait until 115 /// If [id] is for a generated or transformed asset, this will wait until it
117 /// it has been created and return it. If the asset cannot be found, throws 116 /// has been created and return it. If the asset cannot be found, returns
118 /// [AssetNotFoundException]. 117 /// null.
119 Future<Asset> getAssetById(AssetId id) { 118 Future<AssetNode> getAssetNode(AssetId id) {
120 assert(id.package == package); 119 assert(id.package == package);
121 120
122 // TODO(rnystrom): Waiting for the entire build to complete is unnecessary 121 // TODO(rnystrom): Waiting for the entire build to complete is unnecessary
123 // in some cases. Should optimize: 122 // in some cases. Should optimize:
124 // * [id] may be generated before the compilation is finished. We should 123 // * [id] may be generated before the compilation is finished. We should
125 // be able to quickly check whether there are any more in-place 124 // be able to quickly check whether there are any more in-place
126 // transformations that can be run on it. If not, we can return it early. 125 // transformations that can be run on it. If not, we can return it early.
127 // * If [id] has never been generated and all active transformers provide 126 // * If [id] has never been generated and all active transformers provide
128 // metadata about the file names of assets it can emit, we can prove that 127 // metadata about the file names of assets it can emit, we can prove that
129 // none of them can emit [id] and fail early. 128 // none of them can emit [id] and fail early.
130 return newFuture(() { 129 return newFuture(() {
131 var node = _getAssetNode(id); 130 var node = _getAssetNode(id);
132 131
133 // If the requested asset is available, we can just return it. 132 // If the requested asset is available, we can just return it.
134 if (node != null) return node.asset; 133 if (node != null) return node;
135 134
136 // If there's a build running, that build might generate the asset, so we 135 // If there's a build running, that build might generate the asset, so we
137 // wait for it to complete and then try again. 136 // wait for it to complete and then try again.
138 if (_processDone != null) { 137 if (_processDone != null) {
139 return _processDone.then((_) => getAssetById(id)); 138 return _processDone.then((_) => getAssetNode(id));
140 } 139 }
141 140
142 // If the asset hasn't been built and nothing is building now, the asset 141 // If the asset hasn't been built and nothing is building now, the asset
143 // won't be generated, so we throw an error. 142 // won't be generated, so we return null.
144 throw new AssetNotFoundException(id); 143 return null;
145 }); 144 });
146 } 145 }
147 146
148 // Returns the post-transformation asset node for [id], if one is available. 147 // Returns the post-transformation asset node for [id], if one is available.
149 // 148 //
150 // This will only return a node that has an asset available, and only if that 149 // This will only return a node that has an asset available, and only if that
151 // node is guaranteed not to be consumed by any transforms. If the phase is 150 // node is guaranteed not to be consumed by any transforms. If the phase is
152 // still working to figure out if a node will be consumed by a transformer, 151 // still working to figure out if a node will be consumed by a transformer,
153 // that node won't be returned. 152 // that node won't be returned.
154 AssetNode _getAssetNode(AssetId id) { 153 AssetNode _getAssetNode(AssetId id) {
(...skipping 21 matching lines...) Expand all
176 } else { 175 } else {
177 _sourceControllerMap[id] = new AssetNodeController(id); 176 _sourceControllerMap[id] = new AssetNodeController(id);
178 _phases.first.addInput(_sourceControllerMap[id].node); 177 _phases.first.addInput(_sourceControllerMap[id].node);
179 } 178 }
180 179
181 // If this source was already loading, cancel the old load, since it may 180 // If this source was already loading, cancel the old load, since it may
182 // return out-of-date contents for the asset. 181 // return out-of-date contents for the asset.
183 if (_loadingSources.containsKey(id)) _loadingSources[id].cancel(); 182 if (_loadingSources.containsKey(id)) _loadingSources[id].cancel();
184 183
185 _loadingSources[id] = 184 _loadingSources[id] =
186 new CancelableFuture<Asset>(_graph.provider.getAsset(id)); 185 new CancelableFuture<Asset>(graph.provider.getAsset(id));
187 _loadingSources[id].whenComplete(() { 186 _loadingSources[id].whenComplete(() {
188 _loadingSources.remove(id); 187 _loadingSources.remove(id);
189 }).then((asset) { 188 }).then((asset) {
190 var controller = _sourceControllerMap[id].setAvailable(asset); 189 var controller = _sourceControllerMap[id].setAvailable(asset);
191 }).catchError((error) { 190 }).catchError((error) {
192 reportError(error); 191 reportError(error);
193 192
194 // TODO(nweiz): propagate error information through asset nodes. 193 // TODO(nweiz): propagate error information through asset nodes.
195 _sourceControllerMap.remove(id).setRemoved(); 194 _sourceControllerMap.remove(id).setRemoved();
196 }); 195 });
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
265 264
266 // Otherwise, everything is done. 265 // Otherwise, everything is done.
267 return; 266 return;
268 } 267 }
269 268
270 // Process that phase and then loop onto the next. 269 // Process that phase and then loop onto the next.
271 return future.then((_) => _process()); 270 return future.then((_) => _process());
272 }); 271 });
273 } 272 }
274 } 273 }
275
276 /// An event indicating that the cascade has finished building all assets.
277 ///
278 /// A build can end either in success or failure. If there were no errors during
279 /// the build, it's considered to be a success; any errors render it a failure,
280 /// although individual assets may still have built successfully.
281 class BuildResult {
282 /// All errors that occurred during the build.
283 final List errors;
284
285 /// `true` if the build succeeded.
286 bool get succeeded => errors.isEmpty;
287
288 BuildResult(Iterable errors)
289 : errors = errors.toList();
290
291 /// Creates a build result indicating a successful build.
292 ///
293 /// This equivalent to a build result with no errors.
294 BuildResult.success()
295 : this([]);
296
297 String toString() {
298 if (succeeded) return "success";
299
300 return "errors:\n" + errors.map((error) {
301 var stackTrace = getAttachedStackTrace(error);
302 if (stackTrace != null) stackTrace = new Trace.from(stackTrace);
303
304 var msg = new StringBuffer();
305 msg.write(prefixLines(error.toString()));
306 if (stackTrace != null) {
307 msg.write("\n\n");
308 msg.write("Stack trace:\n");
309 msg.write(prefixLines(stackTrace.toString()));
310 }
311 return msg.toString();
312 }).join("\n\n");
313 }
314 }
OLDNEW
« no previous file with comments | « pkg/barback/lib/barback.dart ('k') | pkg/barback/lib/src/barback.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698