Chromium Code Reviews| 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 |