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

Unified Diff: runtime/bin/builtin.dart

Issue 1232593003: - Implement .packages specification. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Address review comments. Created 5 years, 5 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | runtime/bin/dartutils.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/bin/builtin.dart
diff --git a/runtime/bin/builtin.dart b/runtime/bin/builtin.dart
index 940556a1acd647494ef13ced93019689835a8d72..42a5e1e9c4122cbe110a0cd9a559f3852b247efc 100644
--- a/runtime/bin/builtin.dart
+++ b/runtime/bin/builtin.dart
@@ -78,15 +78,32 @@ Uri _workingDirectory;
// package imports can be resolved relative to it. The root script is the basis
// for the root library in the VM.
Uri _rootScript;
+
+// Packages are either resolved looking up in a map or resolved from within a
+// package root.
+bool _packagesReady() => (_packageRoot != null) || (_packageMap != null);
// The directory to look in to resolve "package:" scheme URIs. By detault it is
// the 'packages' directory right next to the script.
-Uri _packageRoot = _rootScript.resolve('packages/');
+Uri _packageRoot = null; // Used to be _rootScript.resolve('packages/');
+// The map describing how certain package names are mapped to Uris.
+Map<String, Uri> _packageMap = null;
+// A list of pending packags which have been requested while resolving the
+// location of the package root or the contents of the package map.
+List<_LoadRequest> _pendingPackageLoads = [];
+
+// If we have outstanding loads or pending package loads waiting for resolution,
+// then we do have pending loads.
+bool _pendingLoads() => !_reqMap.isEmpty || !_pendingPackageLoads.isEmpty;
// Special handling for Windows paths so that they are compatible with URI
// handling.
// Embedder sets this to true if we are running on Windows.
bool _isWindows = false;
+// Logging from builtin.dart is prefixed with a '*'.
+_log(msg) {
+ _print("* $msg");
+}
// A class wrapping the load error message in an Error object.
class _LoadError extends Error {
@@ -103,8 +120,15 @@ class _LoadRequest {
final int _tag;
final String _uri;
final String _libraryUri;
+ final Uri _resourceUri;
- _LoadRequest(this._id, this._tag, this._uri, this._libraryUri);
+ _LoadRequest(this._id,
+ this._tag,
+ this._uri,
+ this._libraryUri,
+ this._resourceUri);
+
+ toString() => "LoadRequest($_id, $_tag, $_uri, $_libraryUri, $_resourceUri)";
}
@@ -172,11 +196,11 @@ _enforceTrailingSlash(uri) {
// The embedder calls this method with the current working directory.
void _setWorkingDirectory(cwd) {
if (_traceLoading) {
- _print('# Setting working directory: $cwd');
+ _log('Setting working directory: $cwd');
}
_workingDirectory = new Uri.directory(cwd);
if (_traceLoading) {
- _print('# Working directory URI: $_workingDirectory');
+ _log('Working directory URI: $_workingDirectory');
}
}
@@ -185,7 +209,7 @@ void _setWorkingDirectory(cwd) {
// The embedder calls this method with a custom package root.
_setPackageRoot(String packageRoot) {
if (_traceLoading) {
- _print('# Setting package root: $packageRoot');
+ _log('Setting package root: $packageRoot');
}
packageRoot = _enforceTrailingSlash(packageRoot);
if (packageRoot.startsWith('file:') ||
@@ -198,7 +222,7 @@ _setPackageRoot(String packageRoot) {
_packageRoot = _workingDirectory.resolveUri(new Uri.file(packageRoot));
}
if (_traceLoading) {
- _print('# Package root URI: $_packageRoot');
+ _log('Package root URI: $_packageRoot');
}
}
@@ -216,16 +240,36 @@ Uri _resolvePackageUri(Uri uri) {
}
if (_traceLoading) {
- _print('# Package root: $_packageRoot');
- _print('# uri path: ${uri.path}');
+ _log('Resolving package with uri path: ${uri.path}');
+ }
+ var resolvedUri;
+ if (_packageRoot != null) {
+ resolvedUri = _packageRoot.resolve(uri.path);
+ } else {
+ var packageName = uri.pathSegments[0];
+ var mapping = _packageMap[packageName];
+ if (_traceLoading) {
+ _log("Mapped '$packageName' package to '$mapping'");
+ }
+ if (mapping == null) {
+ throw "No mapping for '$packageName' package when resolving '$uri'.";
+ }
+ var path = uri.path.substring(packageName.length + 1);
+ resolvedUri = mapping.resolve(path);
+ }
+ if (_traceLoading) {
+ _log("Resolved '$uri' to '$resolvedUri'.");
}
- return _packageRoot.resolve(uri.path);
+ return resolvedUri;
}
// Resolves the script uri in the current working directory iff the given uri
// did not specify a scheme (e.g. a path to a script file on the command line).
Uri _resolveScriptUri(String scriptName) {
+ if (_traceLoading) {
+ _log("Resolving script: $scriptName");
+ }
if (_workingDirectory == null) {
throw 'No current working directory set.';
}
@@ -243,7 +287,7 @@ Uri _resolveScriptUri(String scriptName) {
_rootScript = scriptUri;
if (_traceLoading) {
- _print('# Resolved entry point to: $_rootScript');
+ _log('Resolved entry point to: $_rootScript');
}
return scriptUri;
}
@@ -254,13 +298,14 @@ void _finishLoadRequest(_LoadRequest req) {
var tmp = _reqMap.remove(req._id);
assert(tmp == req);
if (_traceLoading) {
- _print("Loading of ${req._uri} finished, "
- "${_reqMap.length} requests remaining");
+ _log("Loading of ${req._uri} finished: "
+ "${_reqMap.length} requests remaining, "
+ "${_pendingPackageLoads.length} packages pending.");
}
- if (_reqMap.isEmpty) {
+ if (!_pendingLoads()) {
if (_traceLoading) {
- _print("Closing loading port.");
+ _log("Closing loading port.");
}
_receivePort.close();
_receivePort = null;
@@ -298,9 +343,9 @@ void _startLoadRequest(int tag,
String uri,
String libraryUri,
Uri resourceUri) {
- if (_reqMap.isEmpty) {
+ if (_receivePort == null) {
if (_traceLoading) {
- _print("Initializing load port.");
+ _log("Initializing load port.");
}
assert(_receivePort == null);
assert(_sendPort == null);
@@ -311,17 +356,136 @@ void _startLoadRequest(int tag,
var curId = _reqId++;
assert(_reqMap[curId] == null);
- _reqMap[curId] = new _LoadRequest(curId, tag, uri, libraryUri);
+ _reqMap[curId] = new _LoadRequest(curId, tag, uri, libraryUri, resourceUri);
+
+ assert(_receivePort != null);
+ assert(_sendPort != null);
- var msg = new List(3);
+ var msg = new List(4);
msg[0] = _sendPort;
- msg[1] = curId;
- msg[2] = resourceUri.toString();
+ msg[1] = _traceLoading;
+ msg[2] = curId;
+ msg[3] = resourceUri.toString();
_loadPort.send(msg);
if (_traceLoading) {
- _print("Loading of $resourceUri for $uri started with id: $curId, "
- "${_reqMap.length} requests outstanding");
+ _log("Loading of $resourceUri for $uri started with id: $curId, "
+ "${_reqMap.length} requests outstanding");
+ }
+}
+
+
+RawReceivePort _packagesPort;
+
+void _handlePackagesReply(msg) {
+ // Make sure to close the _packagePort before any other action.
+ _packagesPort.close();
+
+ if (_traceLoading) {
+ _log("Got packages reply: $msg");
+ }
+ if (msg is String) {
+ if (_traceLoading) {
+ _log("Got failure response on package port: '$msg'");
+ }
+ throw msg;
+ }
+ if (msg.length == 1) {
+ if (_traceLoading) {
+ _log("Received package root: '${msg[0]}'");
+ }
+ _packageRoot = Uri.parse(msg[0]);
+ } else {
+ assert((msg.length % 2) == 0);
+ _packageMap = new Map<String, Uri>();
+ for (var i = 0; i < msg.length; i+=2) {
+ // TODO(iposva): Complain about duplicate entries.
+ _packageMap[msg[i]] = Uri.parse(msg[i+1]);
+ }
+ if (_traceLoading) {
+ _log("Setup package map: $_packageMap");
+ }
+ }
+
+ // Resolve all pending package loads now that we know how to resolve them.
+ for (var i = 0; i < _pendingPackageLoads.length; i++) {
+ var req = _pendingPackageLoads[i];
+ if (req != null) {
+ if (_traceLoading) {
+ _log("Handling deferred load request: $req");
+ }
+ _loadPackage(req._tag, req._uri, req._libraryUri, req._resourceUri);
+ }
+ }
+ // Reset the pending package loads to empty. So that we eventually can
+ // finish loading.
+ _pendingPackageLoads = [];
+}
+
+
+void _requestPackagesMap() {
+ assert(_packagesPort == null);
+ assert(_rootScript != null);
+ // Create a port to receive the packages map on.
+ _packagesPort = new RawReceivePort(_handlePackagesReply);
+ var sp = _packagesPort.sendPort;
+
+ var msg = new List(4);
+ msg[0] = sp;
+ msg[1] = _traceLoading;
+ msg[2] = -1;
+ msg[3] = _rootScript.toString();
+ _loadPort.send(msg);
+
+ if (_traceLoading) {
+ _log("Requested packages map for '$_rootScript'.");
+ }
+}
+
+
+// Embedder Entrypoint:
+// Request the load of a particular packages map.
+void _loadPackagesMap(String packagesParam) {
+ // First convert the packages parameter from the command line to a URI which
+ // can be handled by the loader code.
+ // TODO(iposva): Consider refactoring the common code below which is almost
+ // shared with resolution of the root script.
+ if (_traceLoading) {
+ _log("Resolving packages map: $packagesParam");
+ }
+ if (_workingDirectory == null) {
+ throw 'No current working directory set.';
+ }
+ var packagesName = _sanitizeWindowsPath(packagesParam);
+ var packagesUri = Uri.parse(packagesName);
+ if (packagesUri.scheme == '') {
+ // Script does not have a scheme, assume that it is a path,
+ // resolve it against the working directory.
+ packagesUri = _workingDirectory.resolveUri(packagesUri);
+ }
+ if (_traceLoading) {
+ _log('Resolved packages map to: $packagesUri');
+ }
+
+ // Request the loading and parsing of the packages map at the specified URI.
+ // Create a port to receive the packages map on.
+ assert(_packagesPort == null);
+ _packagesPort = new RawReceivePort(_handlePackagesReply);
+ var sp = _packagesPort.sendPort;
+
+ var msg = new List(4);
+ msg[0] = sp;
+ msg[1] = _traceLoading;
+ msg[2] = -2;
+ msg[3] = packagesUri.toString();
+ _loadPort.send(msg);
+
+ // Signal that the resolution of the packages map has started. But in this
+ // case it is not tied to a particular request.
+ _pendingPackageLoads.add(null);
+
+ if (_traceLoading) {
+ _log("Requested packages map at '$packagesUri'.");
}
}
@@ -337,7 +501,7 @@ void _loadScript(_LoadRequest req, Uint8List data) {
void _asyncLoadError(_LoadRequest req, _LoadError error) {
if (_traceLoading) {
- _print("_asyncLoadError(${req._uri}), error: $error");
+ _log("_asyncLoadError(${req._uri}), error: $error");
}
var libraryUri = req._libraryUri;
if (req._tag == Dart_kImportTag) {
@@ -358,7 +522,7 @@ _loadDataFromLoadPort(int tag,
_startLoadRequest(tag, uri, libraryUri, resourceUri);
} catch (e) {
if (_traceLoading) {
- _print("Exception when communicating with service isolate: $e");
+ _log("Exception when communicating with service isolate: $e");
}
// Wrap inside a _LoadError unless we are already propagating a previously
// seen _LoadError.
@@ -368,6 +532,40 @@ _loadDataFromLoadPort(int tag,
}
+// Loading a package URI needs to first map the package name to a loadable
+// URI.
+_loadPackage(int tag, String uri, String libraryUri, Uri resourceUri) {
+ if (_packagesReady()) {
+ _loadData(tag, uri, libraryUri, _resolvePackageUri(resourceUri));
+ } else {
+ if (_pendingPackageLoads.isEmpty) {
+ // Package resolution has not been setup yet, and this is the first
+ // request for package resolution & loading.
+ _requestPackagesMap();
+ }
+ var req = new _LoadRequest(-1, tag, uri, libraryUri, resourceUri);
+ _pendingPackageLoads.add(req);
+ if (_traceLoading) {
+ _log("Pending package load of '$uri': "
+ "${_pendingPackageLoads.length} pending");
+ }
+ }
+}
+
+
+// Load the data associated with the resourceUri.
+_loadData(int tag, String uri, String libraryUri, Uri resourceUri) {
+ if (resourceUri.scheme == 'package') {
+ // package based uris need to be resolved to the correct loadable location.
+ // The logic of which is handled seperately, and then _loadData is called
+ // recursively.
+ _loadPackage(tag, uri, libraryUri, resourceUri);
+ } else {
+ _loadDataFromLoadPort(tag, uri, libraryUri, resourceUri);
+ }
+}
+
+
// Embedder Entrypoint:
// Asynchronously loads script data through a http[s] or file uri.
_loadDataAsync(int tag, String uri, String libraryUri) {
@@ -378,13 +576,7 @@ _loadDataAsync(int tag, String uri, String libraryUri) {
} else {
resourceUri = Uri.parse(uri);
}
-
- // package based uris need to be resolved to the correct loadable location.
- if (resourceUri.scheme == 'package') {
- resourceUri = _resolvePackageUri(resourceUri);
- }
-
- _loadDataFromLoadPort(tag, uri, libraryUri, resourceUri);
+ _loadData(tag, uri, libraryUri, resourceUri);
}
@@ -393,7 +585,7 @@ _loadDataAsync(int tag, String uri, String libraryUri) {
// Dart_kCanonicalizeUrl from the tag handler.
String _resolveUri(String base, String userString) {
if (_traceLoading) {
- _print('# Resolving: $userString from $base');
+ _log('Resolving: $userString from $base');
}
var baseUri = Uri.parse(base);
var result;
@@ -404,7 +596,7 @@ String _resolveUri(String base, String userString) {
result = baseUri.resolve(userString).toString();
}
if (_traceLoading) {
- _print('Resolved $userString in $base to $result');
+ _log('Resolved $userString in $base to $result');
}
return result;
}
@@ -425,7 +617,7 @@ String _resolveInWorkingDirectory(String fileName) {
uri = _workingDirectory.resolveUri(uri);
if (_traceLoading) {
- _print('# Resolved in working directory: $fileName -> $uri');
+ _log('Resolved in working directory: $fileName -> $uri');
}
return uri.toString();
}
@@ -453,7 +645,7 @@ String _platformExtensionFileName(String name) {
String _filePathFromUri(String userUri) {
var uri = Uri.parse(userUri);
if (_traceLoading) {
- _print('# Getting file path from: $uri');
+ _log('Getting file path from: $uri');
}
var path;
@@ -471,7 +663,7 @@ String _filePathFromUri(String userUri) {
// Only handling file, http, and package URIs
// in standalone binary.
if (_traceLoading) {
- _print('# Unknown scheme (${uri.scheme}) in $uri.');
+ _log('Unknown scheme (${uri.scheme}) in $uri.');
}
throw 'Not a known scheme: $uri';
}
« no previous file with comments | « no previous file | runtime/bin/dartutils.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698