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 /// A library for compiling Dart code and manipulating analyzer parse trees. | 5 /// A library for compiling Dart code and manipulating analyzer parse trees. |
6 library pub.dart; | 6 library pub.dart; |
7 | 7 |
8 import 'dart:async'; | 8 import 'dart:async'; |
9 import 'dart:io'; | 9 import 'dart:io'; |
10 import 'dart:isolate'; | 10 import 'dart:isolate'; |
11 | 11 |
12 import 'package:analyzer/analyzer.dart'; | 12 import 'package:analyzer/analyzer.dart'; |
13 import 'package:compiler_unsupported/compiler.dart' as compiler; | 13 import 'package:compiler_unsupported/compiler.dart' as compiler; |
14 import 'package:compiler_unsupported/src/filenames.dart' | 14 import 'package:compiler_unsupported/src/filenames.dart' |
15 show appendSlash; | 15 show appendSlash; |
16 import 'package:path/path.dart' as path; | 16 import 'package:path/path.dart' as p; |
17 | 17 |
18 import 'asset/dart/serialize.dart'; | 18 import 'asset/dart/serialize.dart'; |
19 import 'io.dart'; | 19 import 'io.dart'; |
20 import 'log.dart' as log; | 20 import 'log.dart' as log; |
21 | 21 |
22 /// Interface to communicate with dart2js. | 22 /// Interface to communicate with dart2js. |
23 /// | 23 /// |
24 /// This is basically an amalgamation of dart2js's | 24 /// This is basically an amalgamation of dart2js's |
25 /// [compiler.CompilerInputProvider], [compiler.CompilerOutputProvider], and | 25 /// [compiler.CompilerInputProvider], [compiler.CompilerOutputProvider], and |
26 /// [compiler.DiagnosticHandler] function types so that we can provide them | 26 /// [compiler.DiagnosticHandler] function types so that we can provide them |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
63 bool verbose: false, | 63 bool verbose: false, |
64 Map<String, String> environment, | 64 Map<String, String> environment, |
65 String packageRoot, | 65 String packageRoot, |
66 bool analyzeAll: false, | 66 bool analyzeAll: false, |
67 bool preserveUris: false, | 67 bool preserveUris: false, |
68 bool suppressWarnings: false, | 68 bool suppressWarnings: false, |
69 bool suppressHints: false, | 69 bool suppressHints: false, |
70 bool suppressPackageWarnings: true, | 70 bool suppressPackageWarnings: true, |
71 bool terse: false, | 71 bool terse: false, |
72 bool includeSourceMapUrls: false, | 72 bool includeSourceMapUrls: false, |
73 bool toDart: false}) { | 73 bool toDart: false}) async { |
74 return new Future.sync(() { | 74 // dart2js chokes on relative paths. Including "/./" can also confuse it, so |
Bob Nystrom
2015/07/09 22:47:19
File bugs for these?
nweiz
2015/07/09 23:42:44
They seem to be closely tied to the specific way w
| |
75 var options = <String>['--categories=Client,Server']; | 75 // we normalize as well. |
76 if (checked) options.add('--enable-checked-mode'); | 76 entrypoint = p.normalize(p.absolute(entrypoint)); |
77 if (csp) options.add('--csp'); | |
78 if (minify) options.add('--minify'); | |
79 if (verbose) options.add('--verbose'); | |
80 if (analyzeAll) options.add('--analyze-all'); | |
81 if (preserveUris) options.add('--preserve-uris'); | |
82 if (suppressWarnings) options.add('--suppress-warnings'); | |
83 if (suppressHints) options.add('--suppress-hints'); | |
84 if (!suppressPackageWarnings) options.add('--show-package-warnings'); | |
85 if (terse) options.add('--terse'); | |
86 if (toDart) options.add('--output-type=dart'); | |
87 | 77 |
88 var sourceUrl = path.toUri(entrypoint); | 78 var options = <String>['--categories=Client,Server']; |
89 options.add("--out=$sourceUrl.js"); | 79 if (checked) options.add('--enable-checked-mode'); |
80 if (csp) options.add('--csp'); | |
81 if (minify) options.add('--minify'); | |
82 if (verbose) options.add('--verbose'); | |
83 if (analyzeAll) options.add('--analyze-all'); | |
84 if (preserveUris) options.add('--preserve-uris'); | |
85 if (suppressWarnings) options.add('--suppress-warnings'); | |
86 if (suppressHints) options.add('--suppress-hints'); | |
87 if (!suppressPackageWarnings) options.add('--show-package-warnings'); | |
88 if (terse) options.add('--terse'); | |
89 if (toDart) options.add('--output-type=dart'); | |
90 | 90 |
91 // Add the source map URLs. | 91 var sourceUrl = p.toUri(entrypoint); |
92 if (includeSourceMapUrls) { | 92 options.add("--out=$sourceUrl.js"); |
93 options.add("--source-map=$sourceUrl.js.map"); | |
94 } | |
95 | 93 |
96 if (environment == null) environment = {}; | 94 // Add the source map URLs. |
97 if (commandLineOptions != null) options.addAll(commandLineOptions); | 95 if (includeSourceMapUrls) { |
96 options.add("--source-map=$sourceUrl.js.map"); | |
97 } | |
98 | 98 |
99 if (packageRoot == null) { | 99 if (environment == null) environment = {}; |
100 packageRoot = path.join(path.dirname(entrypoint), 'packages'); | 100 if (commandLineOptions != null) options.addAll(commandLineOptions); |
101 } | |
102 | 101 |
103 return compiler.compile( | 102 if (packageRoot == null) { |
104 path.toUri(path.absolute(entrypoint)), | 103 packageRoot = p.join(p.dirname(entrypoint), 'packages'); |
105 provider.libraryRoot, | 104 } else { |
106 path.toUri(appendSlash(path.absolute(packageRoot))), | 105 packageRoot = p.normalize(p.absolute(packageRoot)); |
107 provider.provideInput, | 106 } |
108 provider.handleDiagnostic, | 107 |
109 options, | 108 await compiler.compile( |
110 provider.provideOutput, | 109 p.toUri(entrypoint), |
111 environment); | 110 provider.libraryRoot, |
112 }); | 111 p.toUri(appendSlash(packageRoot)), |
112 provider.provideInput, | |
113 provider.handleDiagnostic, | |
114 options, | |
115 provider.provideOutput, | |
116 environment); | |
113 } | 117 } |
114 | 118 |
115 /// Returns whether [dart] looks like an entrypoint file. | 119 /// Returns whether [dart] looks like an entrypoint file. |
116 bool isEntrypoint(CompilationUnit dart) { | 120 bool isEntrypoint(CompilationUnit dart) { |
117 // Allow two or fewer arguments so that entrypoints intended for use with | 121 // Allow two or fewer arguments so that entrypoints intended for use with |
118 // [spawnUri] get counted. | 122 // [spawnUri] get counted. |
119 // | 123 // |
120 // TODO(nweiz): this misses the case where a Dart file doesn't contain main(), | 124 // TODO(nweiz): this misses the case where a Dart file doesn't contain main(), |
121 // but it parts in another file that does. | 125 // but it parts in another file that does. |
122 return dart.declarations.any((node) { | 126 return dart.declarations.any((node) { |
(...skipping 30 matching lines...) Expand all Loading... | |
153 /// | 157 /// |
154 /// If [snapshot] is passed, the isolate will be loaded from that path if it | 158 /// If [snapshot] is passed, the isolate will be loaded from that path if it |
155 /// exists. Otherwise, a snapshot of the isolate's code will be saved to that | 159 /// exists. Otherwise, a snapshot of the isolate's code will be saved to that |
156 /// path once the isolate is loaded. | 160 /// path once the isolate is loaded. |
157 Future runInIsolate(String code, message, {packageRoot, String snapshot}) | 161 Future runInIsolate(String code, message, {packageRoot, String snapshot}) |
158 async { | 162 async { |
159 if (snapshot != null && fileExists(snapshot)) { | 163 if (snapshot != null && fileExists(snapshot)) { |
160 log.fine("Spawning isolate from $snapshot."); | 164 log.fine("Spawning isolate from $snapshot."); |
161 if (packageRoot != null) packageRoot = Uri.parse(packageRoot.toString()); | 165 if (packageRoot != null) packageRoot = Uri.parse(packageRoot.toString()); |
162 try { | 166 try { |
163 await Isolate.spawnUri(path.toUri(snapshot), [], message, | 167 await Isolate.spawnUri(p.toUri(snapshot), [], message, |
164 packageRoot: packageRoot); | 168 packageRoot: packageRoot); |
165 return; | 169 return; |
166 } on IsolateSpawnException catch (error) { | 170 } on IsolateSpawnException catch (error) { |
167 log.fine("Couldn't load existing snapshot $snapshot:\n$error"); | 171 log.fine("Couldn't load existing snapshot $snapshot:\n$error"); |
168 // Do nothing, we will regenerate the snapshot below. | 172 // Do nothing, we will regenerate the snapshot below. |
169 } | 173 } |
170 } | 174 } |
171 | 175 |
172 await withTempDir((dir) async { | 176 await withTempDir((dir) async { |
173 var dartPath = path.join(dir, 'runInIsolate.dart'); | 177 var dartPath = p.join(dir, 'runInIsolate.dart'); |
174 writeTextFile(dartPath, code, dontLogContents: true); | 178 writeTextFile(dartPath, code, dontLogContents: true); |
175 var port = new ReceivePort(); | 179 var port = new ReceivePort(); |
176 await Isolate.spawn(_isolateBuffer, { | 180 await Isolate.spawn(_isolateBuffer, { |
177 'replyTo': port.sendPort, | 181 'replyTo': port.sendPort, |
178 'uri': path.toUri(dartPath).toString(), | 182 'uri': p.toUri(dartPath).toString(), |
179 'packageRoot': packageRoot == null ? null : packageRoot.toString(), | 183 'packageRoot': packageRoot == null ? null : packageRoot.toString(), |
180 'message': message | 184 'message': message |
181 }); | 185 }); |
182 | 186 |
183 var response = await port.first; | 187 var response = await port.first; |
184 if (response['type'] == 'error') { | 188 if (response['type'] == 'error') { |
185 throw new CrossIsolateException.deserialize(response['error']); | 189 throw new CrossIsolateException.deserialize(response['error']); |
186 } | 190 } |
187 | 191 |
188 if (snapshot == null) return; | 192 if (snapshot == null) return; |
189 | 193 |
190 ensureDir(path.dirname(snapshot)); | 194 ensureDir(p.dirname(snapshot)); |
191 var snapshotArgs = []; | 195 var snapshotArgs = []; |
192 if (packageRoot != null) snapshotArgs.add('--package-root=$packageRoot'); | 196 if (packageRoot != null) snapshotArgs.add('--package-root=$packageRoot'); |
193 snapshotArgs.addAll(['--snapshot=$snapshot', dartPath]); | 197 snapshotArgs.addAll(['--snapshot=$snapshot', dartPath]); |
194 var result = await runProcess(Platform.executable, snapshotArgs); | 198 var result = await runProcess(Platform.executable, snapshotArgs); |
195 | 199 |
196 if (result.success) return; | 200 if (result.success) return; |
197 | 201 |
198 // Don't emit a fatal error here, since we don't want to crash the | 202 // Don't emit a fatal error here, since we don't want to crash the |
199 // otherwise successful isolate load. | 203 // otherwise successful isolate load. |
200 log.warning("Failed to compile a snapshot to " | 204 log.warning("Failed to compile a snapshot to " |
201 "${path.relative(snapshot)}:\n" + result.stderr.join("\n")); | 205 "${p.relative(snapshot)}:\n" + result.stderr.join("\n")); |
202 }); | 206 }); |
203 } | 207 } |
204 | 208 |
205 // TODO(nweiz): remove this when issue 12617 is fixed. | 209 // TODO(nweiz): remove this when issue 12617 is fixed. |
206 /// A function used as a buffer between the host isolate and [spawnUri]. | 210 /// A function used as a buffer between the host isolate and [spawnUri]. |
207 /// | 211 /// |
208 /// [spawnUri] synchronously loads the file and its imports, which can deadlock | 212 /// [spawnUri] synchronously loads the file and its imports, which can deadlock |
209 /// the host isolate if there's an HTTP import pointing at a server in the host. | 213 /// the host isolate if there's an HTTP import pointing at a server in the host. |
210 /// Adding an additional isolate in the middle works around this. | 214 /// Adding an additional isolate in the middle works around this. |
211 void _isolateBuffer(message) { | 215 void _isolateBuffer(message) { |
212 var replyTo = message['replyTo']; | 216 var replyTo = message['replyTo']; |
213 var packageRoot = message['packageRoot']; | 217 var packageRoot = message['packageRoot']; |
214 if (packageRoot != null) packageRoot = Uri.parse(packageRoot); | 218 if (packageRoot != null) packageRoot = Uri.parse(packageRoot); |
215 Isolate.spawnUri(Uri.parse(message['uri']), [], message['message'], | 219 Isolate.spawnUri(Uri.parse(message['uri']), [], message['message'], |
216 packageRoot: packageRoot) | 220 packageRoot: packageRoot) |
217 .then((_) => replyTo.send({'type': 'success'})) | 221 .then((_) => replyTo.send({'type': 'success'})) |
218 .catchError((e, stack) { | 222 .catchError((e, stack) { |
219 replyTo.send({ | 223 replyTo.send({ |
220 'type': 'error', | 224 'type': 'error', |
221 'error': CrossIsolateException.serialize(e, stack) | 225 'error': CrossIsolateException.serialize(e, stack) |
222 }); | 226 }); |
223 }); | 227 }); |
224 } | 228 } |
OLD | NEW |