| Index: runtime/bin/builtin.dart
|
| diff --git a/runtime/bin/builtin.dart b/runtime/bin/builtin.dart
|
| index 940556a1acd647494ef13ced93019689835a8d72..96f1bdae2b9bd50fbcaea9057867c6d661a390fd 100644
|
| --- a/runtime/bin/builtin.dart
|
| +++ b/runtime/bin/builtin.dart
|
| @@ -48,6 +48,10 @@ _getUriBaseClosure() => _uriBase;
|
| // Asynchronous loading of resources.
|
| // The embedder forwards most loading requests to this library.
|
|
|
| +_log(msg) {
|
| + _print("* $msg");
|
| +}
|
| +
|
| // See Dart_LibraryTag in dart_api.h
|
| const Dart_kScriptTag = null;
|
| const Dart_kImportTag = 0;
|
| @@ -78,9 +82,22 @@ 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.
|
| @@ -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,
|
| + this._resourceUri);
|
|
|
| - _LoadRequest(this._id, this._tag, this._uri, this._libraryUri);
|
| + 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}');
|
| }
|
| - return _packageRoot.resolve(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 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,135 @@ 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);
|
|
|
| - var msg = new List(3);
|
| + assert(_receivePort != null);
|
| + assert(_sendPort != null);
|
| +
|
| + 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) {
|
| + _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) {
|
| + _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) {
|
| - _print("Loading of $resourceUri for $uri started with id: $curId, "
|
| - "${_reqMap.length} requests outstanding");
|
| + _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 +500,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 +521,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 +531,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 +575,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 +584,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 +595,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 +616,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 +644,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 +662,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';
|
| }
|
|
|