OLD | NEW |
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 pub.dart2js_transformer; | 5 library pub.dart2js_transformer; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 import 'dart:convert'; | 8 import 'dart:convert'; |
9 import 'dart:io'; | 9 import 'dart:io'; |
10 | 10 |
11 import 'package:analyzer/analyzer.dart'; | 11 import 'package:analyzer/analyzer.dart'; |
12 import 'package:barback/barback.dart'; | 12 import 'package:barback/barback.dart'; |
13 import 'package:path/path.dart' as path; | 13 import 'package:path/path.dart' as path; |
14 import 'package:stack_trace/stack_trace.dart'; | 14 import 'package:stack_trace/stack_trace.dart'; |
15 | 15 |
16 import '../../../../compiler/compiler.dart' as compiler; | 16 import '../../../../compiler/compiler.dart' as compiler; |
17 import '../../../../compiler/implementation/dart2js.dart' | 17 import '../../../../compiler/implementation/dart2js.dart' |
18 show AbortLeg; | 18 show AbortLeg; |
19 import '../../../../compiler/implementation/source_file.dart'; | 19 import '../../../../compiler/implementation/source_file.dart'; |
20 import '../barback.dart'; | 20 import '../barback.dart'; |
21 import '../dart.dart' as dart; | 21 import '../dart.dart' as dart; |
22 import '../io.dart'; | 22 import '../io.dart'; |
23 import '../package.dart'; | 23 import '../package.dart'; |
24 import '../package_graph.dart'; | 24 import '../package_graph.dart'; |
25 import '../utils.dart'; | 25 import '../utils.dart'; |
| 26 import 'build_environment.dart'; |
26 | 27 |
27 /// The set of all valid configuration options for this transformer. | 28 /// The set of all valid configuration options for this transformer. |
28 final _validOptions = new Set<String>.from([ | 29 final _validOptions = new Set<String>.from([ |
29 'commandLineOptions', 'checked', 'minify', 'verbose', 'environment', | 30 'commandLineOptions', 'checked', 'minify', 'verbose', 'environment', |
30 'analyzeAll', 'suppressWarnings', 'suppressHints', 'terse' | 31 'analyzeAll', 'suppressWarnings', 'suppressHints', 'terse' |
31 ]); | 32 ]); |
32 | 33 |
33 /// A [Transformer] that uses dart2js's library API to transform Dart | 34 /// A [Transformer] that uses dart2js's library API to transform Dart |
34 /// entrypoints in "web" to JavaScript. | 35 /// entrypoints in "web" to JavaScript. |
35 class Dart2JSTransformer extends Transformer { | 36 class Dart2JSTransformer extends Transformer { |
36 final PackageGraph _graph; | 37 final BuildEnvironment _environment; |
37 final BarbackSettings _settings; | 38 final BarbackSettings _settings; |
38 | 39 |
39 /// The [AssetId]s the transformer has discovered so far. Used by pub build | |
40 /// to determine where to copy the JS bootstrap files. | |
41 // TODO(rnystrom): Do something cleaner for this, or eliminate those files. | |
42 final entrypoints = new Set<AssetId>(); | |
43 | |
44 /// If this is non-null, then the transformer is currently being applied, so | 40 /// If this is non-null, then the transformer is currently being applied, so |
45 /// subsequent calls to [apply] will wait for this to finish before | 41 /// subsequent calls to [apply] will wait for this to finish before |
46 /// proceeding. | 42 /// proceeding. |
47 /// | 43 /// |
48 /// Dart2js uses lots of memory, so if we try to actually run compiles in | 44 /// Dart2js uses lots of memory, so if we try to actually run compiles in |
49 /// parallel, it takes down the VM. Instead, the transformer will force | 45 /// parallel, it takes down the VM. Instead, the transformer will force |
50 /// all applies to be sequential. The tracking bug to do something better | 46 /// all applies to be sequential. The tracking bug to do something better |
51 /// is here: https://code.google.com/p/dart/issues/detail?id=14730. | 47 /// is here: https://code.google.com/p/dart/issues/detail?id=14730. |
52 Future _running; | 48 Future _running; |
53 | 49 |
54 Dart2JSTransformer.withSettings(this._graph, this._settings) { | 50 Dart2JSTransformer.withSettings(this._environment, this._settings) { |
55 var invalidOptions = _settings.configuration.keys.toSet() | 51 var invalidOptions = _settings.configuration.keys.toSet() |
56 .difference(_validOptions); | 52 .difference(_validOptions); |
57 if (invalidOptions.isEmpty) return; | 53 if (invalidOptions.isEmpty) return; |
58 | 54 |
59 throw new FormatException("Unrecognized dart2js " | 55 throw new FormatException("Unrecognized dart2js " |
60 "${pluralize('option', invalidOptions.length)} " | 56 "${pluralize('option', invalidOptions.length)} " |
61 "${toSentence(invalidOptions.map((option) => '"$option"'))}."); | 57 "${toSentence(invalidOptions.map((option) => '"$option"'))}."); |
62 } | 58 } |
63 | 59 |
64 Dart2JSTransformer(PackageGraph graph, BarbackMode mode) | 60 Dart2JSTransformer(BuildEnvironment environment, BarbackMode mode) |
65 : this.withSettings(graph, new BarbackSettings({}, mode)); | 61 : this.withSettings(environment, new BarbackSettings({}, mode)); |
66 | 62 |
67 /// Only ".dart" files within "web/" are processed. | 63 /// Only ".dart" files within a buildable directory are processed. |
68 Future<bool> isPrimary(Asset asset) { | 64 Future<bool> isPrimary(Asset asset) { |
69 return new Future.value( | 65 if (asset.id.extension != ".dart") return new Future.value(false); |
70 asset.id.extension == ".dart" && | 66 |
71 asset.id.path.startsWith("web/")); | 67 for (var dir in ["benchmark", "example", "test", "web"]) { |
| 68 if (asset.id.path.startsWith("$dir/")) return new Future.value(true); |
| 69 } |
| 70 |
| 71 return new Future.value(false); |
72 } | 72 } |
73 | 73 |
74 Future apply(Transform transform) { | 74 Future apply(Transform transform) { |
75 // Wait for any ongoing apply to finish first. | 75 // Wait for any ongoing apply to finish first. |
76 // TODO(rnystrom): If there are multiple simultaneous compiles, this will | 76 // TODO(rnystrom): If there are multiple simultaneous compiles, this will |
77 // resume and pause them repeatedly. It still serializes them correctly, | 77 // resume and pause them repeatedly. It still serializes them correctly, |
78 // but it might be cleaner to use a real queue. | 78 // but it might be cleaner to use a real queue. |
79 // TODO(rnystrom): Add a test that this is functionality is helpful. | 79 // TODO(rnystrom): Add a test that this is functionality is helpful. |
80 if (_running != null) { | 80 if (_running != null) { |
81 return _running.then((_) => apply(transform)); | 81 return _running.then((_) => apply(transform)); |
82 } | 82 } |
83 | 83 |
84 var completer = new Completer(); | 84 var completer = new Completer(); |
85 _running = completer.future; | 85 _running = completer.future; |
86 | 86 |
87 var stopwatch = new Stopwatch(); | 87 var stopwatch = new Stopwatch(); |
88 stopwatch.start(); | 88 stopwatch.start(); |
89 | 89 |
90 return transform.primaryInput.readAsString().then((code) { | 90 return transform.primaryInput.readAsString().then((code) { |
91 try { | 91 try { |
92 var id = transform.primaryInput.id; | 92 var id = transform.primaryInput.id; |
93 var name = id.path; | 93 var name = id.path; |
94 if (id.package != _graph.entrypoint.root.name) { | 94 if (id.package != _environment.rootPackage.name) { |
95 name += " in ${id.package}"; | 95 name += " in ${id.package}"; |
96 } | 96 } |
97 | 97 |
98 var parsed = parseCompilationUnit(code, name: name); | 98 var parsed = parseCompilationUnit(code, name: name); |
99 if (!dart.isEntrypoint(parsed)) return null; | 99 if (!dart.isEntrypoint(parsed)) return null; |
100 } on AnalyzerErrorGroup catch (e) { | 100 } on AnalyzerErrorGroup catch (e) { |
101 transform.logger.error(e.message); | 101 transform.logger.error(e.message); |
102 return null; | 102 return null; |
103 } | 103 } |
104 | 104 |
105 var provider = new _BarbackCompilerProvider(_graph, transform); | 105 var provider = new _BarbackCompilerProvider(_environment, transform); |
106 | 106 |
107 // Create a "path" to the entrypoint script. The entrypoint may not | 107 // Create a "path" to the entrypoint script. The entrypoint may not |
108 // actually be on disk, but this gives dart2js a root to resolve | 108 // actually be on disk, but this gives dart2js a root to resolve |
109 // relative paths against. | 109 // relative paths against. |
110 var id = transform.primaryInput.id; | 110 var id = transform.primaryInput.id; |
111 | 111 |
112 entrypoints.add(id); | 112 var entrypoint = path.join(_environment.graph.packages[id.package].dir, |
113 | 113 id.path); |
114 var entrypoint = path.join(_graph.packages[id.package].dir, id.path); | |
115 | 114 |
116 // TODO(rnystrom): Should have more sophisticated error-handling here. | 115 // TODO(rnystrom): Should have more sophisticated error-handling here. |
117 // Need to report compile errors to the user in an easily visible way. | 116 // Need to report compile errors to the user in an easily visible way. |
118 // Need to make sure paths in errors are mapped to the original source | 117 // Need to make sure paths in errors are mapped to the original source |
119 // path so they can understand them. | 118 // path so they can understand them. |
120 return Chain.track(dart.compile( | 119 return Chain.track(dart.compile( |
121 entrypoint, provider, | 120 entrypoint, provider, |
122 commandLineOptions: _configCommandLineOptions, | 121 commandLineOptions: _configCommandLineOptions, |
123 checked: _configBool('checked'), | 122 checked: _configBool('checked'), |
124 minify: _configBool( | 123 minify: _configBool( |
125 'minify', defaultsTo: _settings.mode == BarbackMode.RELEASE), | 124 'minify', defaultsTo: _settings.mode == BarbackMode.RELEASE), |
126 verbose: _configBool('verbose'), | 125 verbose: _configBool('verbose'), |
127 environment: _configEnvironment, | 126 environment: _configEnvironment, |
128 packageRoot: path.join(_graph.entrypoint.root.dir, "packages"), | 127 packageRoot: path.join(_environment.rootPackage.dir, |
| 128 "packages"), |
129 analyzeAll: _configBool('analyzeAll'), | 129 analyzeAll: _configBool('analyzeAll'), |
130 suppressWarnings: _configBool('suppressWarnings'), | 130 suppressWarnings: _configBool('suppressWarnings'), |
131 suppressHints: _configBool('suppressHints'), | 131 suppressHints: _configBool('suppressHints'), |
132 terse: _configBool('terse'))).then((_) { | 132 terse: _configBool('terse'))).then((_) { |
133 stopwatch.stop(); | 133 stopwatch.stop(); |
134 transform.logger.info("Took ${stopwatch.elapsed} to compile $id."); | 134 transform.logger.info("Took ${stopwatch.elapsed} to compile $id."); |
135 }); | 135 }); |
136 }).whenComplete(() { | 136 }).whenComplete(() { |
137 completer.complete(); | 137 completer.complete(); |
138 _running = null; | 138 _running = null; |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
180 } | 180 } |
181 } | 181 } |
182 | 182 |
183 /// Defines an interface for dart2js to communicate with barback and pub. | 183 /// Defines an interface for dart2js to communicate with barback and pub. |
184 /// | 184 /// |
185 /// Note that most of the implementation of diagnostic handling here was | 185 /// Note that most of the implementation of diagnostic handling here was |
186 /// copied from [FormattingDiagnosticHandler] in dart2js. The primary | 186 /// copied from [FormattingDiagnosticHandler] in dart2js. The primary |
187 /// difference is that it uses barback's logging code and, more importantly, it | 187 /// difference is that it uses barback's logging code and, more importantly, it |
188 /// handles missing source files more gracefully. | 188 /// handles missing source files more gracefully. |
189 class _BarbackCompilerProvider implements dart.CompilerProvider { | 189 class _BarbackCompilerProvider implements dart.CompilerProvider { |
190 final PackageGraph _graph; | 190 final BuildEnvironment _environment; |
191 final Transform _transform; | 191 final Transform _transform; |
192 | 192 |
193 /// The map of previously loaded files. | 193 /// The map of previously loaded files. |
194 /// | 194 /// |
195 /// Used to show where an error occurred in a source file. | 195 /// Used to show where an error occurred in a source file. |
196 final _sourceFiles = new Map<String, SourceFile>(); | 196 final _sourceFiles = new Map<String, SourceFile>(); |
197 | 197 |
198 // TODO(rnystrom): Make these configurable. | 198 // TODO(rnystrom): Make these configurable. |
199 /// Whether or not warnings should be logged. | 199 /// Whether or not warnings should be logged. |
200 var _showWarnings = true; | 200 var _showWarnings = true; |
(...skipping 13 matching lines...) Expand all Loading... |
214 | 214 |
215 compiler.Diagnostic _lastKind = null; | 215 compiler.Diagnostic _lastKind = null; |
216 | 216 |
217 static final int _FATAL = | 217 static final int _FATAL = |
218 compiler.Diagnostic.CRASH.ordinal | | 218 compiler.Diagnostic.CRASH.ordinal | |
219 compiler.Diagnostic.ERROR.ordinal; | 219 compiler.Diagnostic.ERROR.ordinal; |
220 static final int _INFO = | 220 static final int _INFO = |
221 compiler.Diagnostic.INFO.ordinal | | 221 compiler.Diagnostic.INFO.ordinal | |
222 compiler.Diagnostic.VERBOSE_INFO.ordinal; | 222 compiler.Diagnostic.VERBOSE_INFO.ordinal; |
223 | 223 |
224 _BarbackCompilerProvider(this._graph, this._transform); | 224 _BarbackCompilerProvider(this._environment, this._transform); |
225 | 225 |
226 /// A [CompilerInputProvider] for dart2js. | 226 /// A [CompilerInputProvider] for dart2js. |
227 Future<String> provideInput(Uri resourceUri) { | 227 Future<String> provideInput(Uri resourceUri) { |
228 // We only expect to get absolute "file:" URLs from dart2js. | 228 // We only expect to get absolute "file:" URLs from dart2js. |
229 assert(resourceUri.isAbsolute); | 229 assert(resourceUri.isAbsolute); |
230 assert(resourceUri.scheme == "file"); | 230 assert(resourceUri.scheme == "file"); |
231 | 231 |
232 var sourcePath = path.fromUri(resourceUri); | 232 var sourcePath = path.fromUri(resourceUri); |
233 return _readResource(resourceUri).then((source) { | 233 return _readResource(resourceUri).then((source) { |
234 _sourceFiles[resourceUri.toString()] = | 234 _sourceFiles[resourceUri.toString()] = |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
337 } | 337 } |
338 | 338 |
339 AssetId _sourceUrlToId(Uri url) { | 339 AssetId _sourceUrlToId(Uri url) { |
340 // See if it's a special path with "packages" or "assets" in it. | 340 // See if it's a special path with "packages" or "assets" in it. |
341 var id = specialUrlToId(url); | 341 var id = specialUrlToId(url); |
342 if (id != null) return id; | 342 if (id != null) return id; |
343 | 343 |
344 // See if it's a path to a "public" asset within the root package. All | 344 // See if it's a path to a "public" asset within the root package. All |
345 // other files in the root package are not visible to transformers, so | 345 // other files in the root package are not visible to transformers, so |
346 // should be loaded directly from disk. | 346 // should be loaded directly from disk. |
347 var rootDir = _graph.entrypoint.root.dir; | 347 var rootDir = _environment.rootPackage.dir; |
348 var sourcePath = path.fromUri(url); | 348 var sourcePath = path.fromUri(url); |
349 if (isBeneath(sourcePath, path.join(rootDir, "lib")) || | 349 if (isBeneath(sourcePath, path.join(rootDir, "lib")) || |
350 isBeneath(sourcePath, path.join(rootDir, "asset")) || | 350 isBeneath(sourcePath, path.join(rootDir, "asset")) || |
351 isBeneath(sourcePath, path.join(rootDir, "web"))) { | 351 isBeneath(sourcePath, path.join(rootDir, "web"))) { |
352 var relative = path.relative(sourcePath, from: rootDir); | 352 var relative = path.relative(sourcePath, from: rootDir); |
353 | 353 |
354 return new AssetId(_graph.entrypoint.root.name, relative); | 354 return new AssetId(_environment.rootPackage.name, relative); |
355 } | 355 } |
356 | 356 |
357 return null; | 357 return null; |
358 } | 358 } |
359 } | 359 } |
OLD | NEW |