Index: pkg/compiler/lib/src/apiimpl.dart |
diff --git a/pkg/compiler/lib/src/apiimpl.dart b/pkg/compiler/lib/src/apiimpl.dart |
index 76765e1f562d9d5a66996f642e474902d26a3cc7..a36ee9ab9ba9beb8328e606bbd9292d64c67769c 100644 |
--- a/pkg/compiler/lib/src/apiimpl.dart |
+++ b/pkg/compiler/lib/src/apiimpl.dart |
@@ -5,6 +5,7 @@ |
library leg_apiimpl; |
import 'dart:async'; |
+import 'dart:convert'; |
import '../compiler.dart' as api; |
import 'dart2jslib.dart' as leg; |
@@ -13,6 +14,11 @@ import 'elements/elements.dart' as elements; |
import 'package:_internal/libraries.dart' hide LIBRARIES; |
import 'package:_internal/libraries.dart' as library_info show LIBRARIES; |
import 'io/source_file.dart'; |
+import 'package:package_config/packages.dart'; |
+import 'package:package_config/packages_file.dart' as pkgs; |
+import 'package:package_config/src/packages_impl.dart' |
+ show NonFilePackagesDirectoryPackages, MapPackages; |
+import 'package:package_config/src/util.dart' show checkValidPackageUri; |
const bool forceIncrementalSupport = |
const bool.fromEnvironment('DART2JS_EXPERIMENTAL_INCREMENTAL_SUPPORT'); |
@@ -21,7 +27,10 @@ class Compiler extends leg.Compiler { |
api.CompilerInputProvider provider; |
api.DiagnosticHandler handler; |
final Uri libraryRoot; |
+ final Uri packageConfig; |
final Uri packageRoot; |
+ final api.PackagesDiscoveryProvider packagesDiscoveryProvider; |
+ Packages packages; |
List<String> options; |
Map<String, dynamic> environment; |
bool mockableLibraryUsed = false; |
@@ -29,6 +38,7 @@ class Compiler extends leg.Compiler { |
leg.GenericTask userHandlerTask; |
leg.GenericTask userProviderTask; |
+ leg.GenericTask userPackagesDiscoveryTask; |
Compiler(this.provider, |
api.CompilerOutputProvider outputProvider, |
@@ -36,7 +46,9 @@ class Compiler extends leg.Compiler { |
this.libraryRoot, |
this.packageRoot, |
List<String> options, |
- this.environment) |
+ this.environment, |
+ [this.packageConfig, |
+ this.packagesDiscoveryProvider]) |
: this.options = options, |
this.allowedLibraryCategories = getAllowedLibraryCategories(options), |
super( |
@@ -96,6 +108,8 @@ class Compiler extends leg.Compiler { |
tasks.addAll([ |
userHandlerTask = new leg.GenericTask('Diagnostic handler', this), |
userProviderTask = new leg.GenericTask('Input provider', this), |
+ userPackagesDiscoveryTask = |
+ new leg.GenericTask('Package discovery', this), |
]); |
if (libraryRoot == null) { |
throw new ArgumentError("[libraryRoot] is null."); |
@@ -103,10 +117,11 @@ class Compiler extends leg.Compiler { |
if (!libraryRoot.path.endsWith("/")) { |
throw new ArgumentError("[libraryRoot] must end with a /."); |
} |
- if (packageRoot == null) { |
- throw new ArgumentError("[packageRoot] is null."); |
+ if (packageRoot != null && packageConfig != null) { |
+ throw new ArgumentError("Only one of [packageRoot] or [packageConfig] " |
+ "may be given."); |
} |
- if (!packageRoot.path.endsWith("/")) { |
+ if (packageRoot != null && !packageRoot.path.endsWith("/")) { |
throw new ArgumentError("[packageRoot] must end with a /."); |
} |
if (!analyzeOnly) { |
@@ -160,8 +175,7 @@ class Compiler extends leg.Compiler { |
// TODO(johnniwinther): Merge better with [translateDartUri] when |
// [scanBuiltinLibrary] is removed. |
- String lookupLibraryPath(String dartLibraryName) { |
- LibraryInfo info = lookupLibraryInfo(dartLibraryName); |
+ String lookupLibraryPath(LibraryInfo info) { |
if (info == null) return null; |
if (!info.isDart2jsLibrary) return null; |
if (!allowedLibraryCategories.contains(info.category)) return null; |
@@ -225,6 +239,7 @@ class Compiler extends leg.Compiler { |
} |
Uri resourceUri = translateUri(node, readableUri); |
+ if (resourceUri == null) return synthesizeScript(node, readableUri); |
if (resourceUri.scheme == 'dart-ext') { |
if (!allowNativeExtensions) { |
withCurrentElement(element, () { |
@@ -260,12 +275,11 @@ class Compiler extends leg.Compiler { |
} |
Future<leg.Script> synthesizeScript(leg.Spannable node, Uri readableUri) { |
- Uri resourceUri = translateUri(node, readableUri); |
return new Future.value( |
new leg.Script( |
- readableUri, resourceUri, |
+ readableUri, readableUri, |
new StringSourceFile.fromUri( |
- resourceUri, |
+ readableUri, |
"// Synthetic source file generated for '$readableUri'."), |
isSynthesized: true)); |
} |
@@ -285,7 +299,7 @@ class Compiler extends leg.Compiler { |
Uri translateDartUri(elements.LibraryElement importingLibrary, |
Uri resolvedUri, tree.Node node) { |
LibraryInfo libraryInfo = lookupLibraryInfo(resolvedUri.path); |
- String path = lookupLibraryPath(resolvedUri.path); |
+ String path = lookupLibraryPath(libraryInfo); |
if (libraryInfo != null && |
libraryInfo.category == "Internal") { |
bool allowInternalLibraryAccess = false; |
@@ -333,25 +347,66 @@ class Compiler extends leg.Compiler { |
} |
Uri translatePackageUri(leg.Spannable node, Uri uri) { |
- return packageRoot.resolve(uri.path); |
+ try { |
+ checkValidPackageUri(uri); |
+ } on ArgumentError catch (e) { |
+ reportError( |
+ node, |
+ leg.MessageKind.INVALID_PACKAGE_URI, |
+ {'uri': uri, 'exception': e.message}); |
+ return null; |
+ } |
+ return packages.resolve(uri, |
+ notFound: (Uri notFound) { |
+ reportError( |
+ node, |
+ leg.MessageKind.LIBRARY_NOT_FOUND, |
+ {'resolvedUri': uri} |
+ ); |
+ return null; |
+ }); |
+ } |
+ |
+ Future setupPackages(Uri uri) async { |
+ if (packageRoot != null) { |
+ // Use "non-file" packages because the file version requires a [Directory] |
+ // and we can't depend on 'dart:io' classes. |
+ packages = new NonFilePackagesDirectoryPackages(packageRoot); |
+ } else if (packageConfig != null) { |
+ var packageConfigContents = await provider(packageConfig); |
+ if (packageConfigContents is String) { |
+ packageConfigContents = UTF8.encode(packageConfigContents); |
+ } |
+ packages = |
+ new MapPackages(pkgs.parse(packageConfigContents, packageConfig)); |
+ } else { |
+ if (packagesDiscoveryProvider == null) { |
+ packages = Packages.noPackages; |
+ } else { |
+ packages = await callUserPackagesDiscovery(uri); |
+ } |
+ } |
} |
- Future<bool> run(Uri uri) { |
+ Future<bool> run(Uri uri) async { |
log('Allowed library categories: $allowedLibraryCategories'); |
- return super.run(uri).then((bool success) { |
- int cumulated = 0; |
- for (final task in tasks) { |
- int elapsed = task.timing; |
- if (elapsed != 0) { |
- cumulated += elapsed; |
- log('${task.name} took ${elapsed}msec'); |
- } |
+ |
+ await setupPackages(uri); |
+ assert(packages != null); |
+ |
+ bool success = await super.run(uri); |
+ int cumulated = 0; |
+ for (final task in tasks) { |
+ int elapsed = task.timing; |
+ if (elapsed != 0) { |
+ cumulated += elapsed; |
+ log('${task.name} took ${elapsed}msec'); |
} |
- int total = totalCompileTime.elapsedMilliseconds; |
- log('Total compile-time ${total}msec;' |
- ' unaccounted ${total - cumulated}msec'); |
- return success; |
- }); |
+ } |
+ int total = totalCompileTime.elapsedMilliseconds; |
+ log('Total compile-time ${total}msec;' |
+ ' unaccounted ${total - cumulated}msec'); |
+ return success; |
} |
void reportDiagnostic(leg.Spannable node, |
@@ -368,8 +423,7 @@ class Compiler extends leg.Compiler { |
if (span == null || span.uri == null) { |
callUserHandler(null, null, null, '$message', kind); |
} else { |
- callUserHandler( |
- translateUri(null, span.uri), span.begin, span.end, '$message', kind); |
+ callUserHandler(span.uri, span.begin, span.end, '$message', kind); |
} |
} |
@@ -400,6 +454,16 @@ class Compiler extends leg.Compiler { |
} |
} |
+ Future<Packages> callUserPackagesDiscovery(Uri uri) { |
+ try { |
+ return userPackagesDiscoveryTask.measure( |
+ () => packagesDiscoveryProvider(uri)); |
+ } catch (ex, s) { |
+ diagnoseCrashInUserCode('Uncaught exception in package discovery', ex, s); |
+ rethrow; |
+ } |
+ } |
+ |
void diagnoseCrashInUserCode(String message, exception, stackTrace) { |
hasCrashed = true; |
print('$message: ${tryToString(exception)}'); |