[sdk] Provide Isolate.resolvePackageUriSync

TEST=augmented few existing tests

Bug: https://github.com/dart-lang/sdk/issues/52121
CoreLibraryReviewExempt: VM-only change, other platforms don't support this API.
Change-Id: I95decae6cf1a5c6ad694747313aa0dbe0a13025d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/312981
Reviewed-by: Lasse Nielsen <lrn@google.com>
Commit-Queue: Slava Egorov <vegorov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
Vyacheslav Egorov 2023-07-11 12:59:33 +00:00 committed by Commit Queue
parent 0d47ba6890
commit 4fddaf9486
22 changed files with 185 additions and 2103 deletions

View file

@ -36,6 +36,10 @@
[#51486]: https://github.com/dart-lang/sdk/issues/51486
[#52027]: https://github.com/dart-lang/sdk/issues/52027
#### `dart:isolate`
- Added `Isolate.packageConfigSync` and `Isolate.resolvePackageUriSync` APIs.
#### `dart:js_interop`
- **Object literal constructors**:

View file

@ -22,9 +22,15 @@ class Isolate {
@patch
static Future<Uri?> get packageConfig => _unsupported();
@patch
static Uri? get packageConfigSync => _unsupported();
@patch
static Future<Uri?> resolvePackageUri(Uri packageUri) => _unsupported();
@patch
static Uri? resolvePackageUriSync(Uri packageUri) => _unsupported();
@patch
static Future<Isolate> spawn<T>(void entryPoint(T message), T message,
{bool paused = false,

View file

@ -26,11 +26,21 @@ class Isolate {
throw new UnsupportedError("Isolate.packageConfig");
}
@patch
static Uri? get packageConfigSync {
throw new UnsupportedError("Isolate.packageConfigSync");
}
@patch
static Future<Uri?> resolvePackageUri(Uri packageUri) {
throw new UnsupportedError("Isolate.resolvePackageUri");
}
@patch
static Uri? resolvePackageUriSync(Uri packageUri) {
throw new UnsupportedError("Isolate.resolvePackageUriSync");
}
@patch
static Future<Isolate> spawn<T>(void entryPoint(T message), T message,
{bool paused = false,

View file

@ -589,11 +589,11 @@ String _resolveScriptUri(String scriptName) {
@pragma("vm:entry-point")
_setupHooks() {
_setupCompleted = true;
VMLibraryHooks.packageConfigUriFuture = _getPackageConfigFuture;
VMLibraryHooks.resolvePackageUriFuture = _resolvePackageUriFuture;
VMLibraryHooks.packageConfigUriSync = _getPackageConfigSync;
VMLibraryHooks.resolvePackageUriSync = _resolvePackageUriSync;
}
Future<Uri?> _getPackageConfigFuture() {
Uri? _getPackageConfigSync() {
if (_traceLoading) {
_log("Request for package config from user code.");
}
@ -601,10 +601,10 @@ Future<Uri?> _getPackageConfigFuture() {
_requestPackagesMap(_packagesConfigUri);
}
// Respond with the packages config (if any) after package resolution.
return Future.value(_packageConfig);
return _packageConfig;
}
Future<Uri?> _resolvePackageUriFuture(Uri packageUri) {
Uri? _resolvePackageUriSync(Uri packageUri) {
if (_traceLoading) {
_log("Request for package Uri resolution from user code: $packageUri");
}
@ -613,7 +613,7 @@ Future<Uri?> _resolvePackageUriFuture(Uri packageUri) {
_log("Non-package Uri, returning unmodified: $packageUri");
}
// Return the incoming parameter if not passed a package: URI.
return Future.value(packageUri);
return packageUri;
}
if (!_packagesReady) {
_requestPackagesMap(_packagesConfigUri);
@ -630,5 +630,5 @@ Future<Uri?> _resolvePackageUriFuture(Uri packageUri) {
if (_traceLoading) {
_log("Resolved '$packageUri' to '$resolvedUri'");
}
return Future.value(resolvedUri);
return resolvedUri;
}

View file

@ -86,8 +86,8 @@ class VMLibraryHooks {
// Implementation of package root/map provision.
static String? packageRootString;
static String? packageConfigString;
static Future<Uri?> Function()? packageConfigUriFuture;
static Future<Uri?> Function(Uri)? resolvePackageUriFuture;
static Uri? Function()? packageConfigUriSync;
static Uri? Function(Uri)? resolvePackageUriSync;
static Uri Function()? _computeScriptUri;
static Uri? _cachedScript;

View file

@ -2,11 +2,6 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/// Note: the VM concatenates all patch files into a single patch file. This
/// file is the first patch in "dart:isolate" which contains all the imports
/// used by patches of that library. We plan to change this when we have a
/// shared front end and simply use parts.
import "dart:_internal" show ClassID, VMLibraryHooks, patch;
import "dart:async"
@ -315,7 +310,12 @@ final class Isolate {
@patch
static Future<Uri?> get packageConfig {
var hook = VMLibraryHooks.packageConfigUriFuture;
return Future.value(packageConfigSync);
}
@patch
static Uri? get packageConfigSync {
var hook = VMLibraryHooks.packageConfigUriSync;
if (hook == null) {
throw new UnsupportedError("Isolate.packageConfig");
}
@ -324,16 +324,21 @@ final class Isolate {
@patch
static Future<Uri?> resolvePackageUri(Uri packageUri) {
var hook = VMLibraryHooks.resolvePackageUriFuture;
return Future.value(resolvePackageUriSync(packageUri));
}
@patch
static Uri? resolvePackageUriSync(Uri packageUri) {
var hook = VMLibraryHooks.resolvePackageUriSync;
if (hook == null) {
throw new UnsupportedError("Isolate.resolvePackageUri");
throw new UnsupportedError("Isolate.resolvePackageUriSync");
}
return hook(packageUri);
}
static bool _packageSupported() =>
(VMLibraryHooks.packageConfigUriFuture != null) &&
(VMLibraryHooks.resolvePackageUriFuture != null);
(VMLibraryHooks.packageConfigUriSync != null) &&
(VMLibraryHooks.resolvePackageUriSync != null);
@patch
static Future<Isolate> spawn<T>(void entryPoint(T message), T message,
@ -357,7 +362,7 @@ final class Isolate {
if (Isolate._packageSupported()) {
// resolving script uri is not really necessary, but can be useful
// for better failed-to-lookup-function-in-a-script spawn errors.
script = await Isolate.resolvePackageUri(script);
script = Isolate.resolvePackageUriSync(script);
}
}
@ -426,7 +431,7 @@ final class Isolate {
// Inherit this isolate's package resolution setup if not overridden.
if (!automaticPackageResolution && packageConfig == null) {
if (Isolate._packageSupported()) {
packageConfig = await Isolate.packageConfig;
packageConfig = Isolate.packageConfigSync;
}
}
@ -435,7 +440,7 @@ final class Isolate {
// Avoid calling resolvePackageUri if not strictly necessary in case
// the API is not supported.
if (packageConfig.isScheme("package")) {
packageConfig = await Isolate.resolvePackageUri(packageConfig);
packageConfig = Isolate.resolvePackageUriSync(packageConfig);
}
}

View file

@ -25,11 +25,21 @@ class Isolate {
throw UnsupportedError("Isolate.packageConfig");
}
@patch
static Uri? get packageConfigSync {
throw UnsupportedError("Isolate.packageConfigSync");
}
@patch
static Future<Uri?> resolvePackageUri(Uri packageUri) {
throw UnsupportedError("Isolate.resolvePackageUri");
}
@patch
static Uri? resolvePackageUriSync(Uri packageUri) {
throw UnsupportedError("Isolate.resolvePackageUriSync");
}
@patch
static Future<Isolate> spawn<T>(void entryPoint(T message), T message,
{bool paused = false,

View file

@ -318,20 +318,84 @@ final class Isolate {
/// is a sure way to hang your program.
external static Isolate get current;
/// The location of the package configuration of the current isolate, if any.
/// The location of the package configuration file of the current isolate.
///
/// If the isolate has not been setup for package resolution,
/// this location is `null`,
/// otherwise it is a URI referencing the package config file.
/// If the isolate was spawned without specifying its package configuration
/// file then the returned value is `null`.
///
/// Otherwise, the returned value is an absolute URI specifying the location
/// of isolate's package configuration file.
///
/// The package configuration file is usually named `package_config.json`,
/// and you can use [`package:package_config`](https://pub.dev/documentation/package_config/latest/)
/// to read and parse it.
external static Future<Uri?> get packageConfig;
/// Maps a `package:` URI to a non-package Uri.
/// The location of the package configuration file of the current isolate.
///
/// If there is no valid mapping from the `package:` URI in the current
/// isolate, then this call returns `null`. Non-`package:` URIs are
/// returned unmodified.
/// If the isolate was spawned without specifying its package configuration
/// file then the returned value is `null`.
///
/// Otherwise, the returned value is an absolute URI specifying the location
/// of isolate's package configuration file.
///
/// The package configuration file is usually named `package_config.json`,
/// and you can use [`package:package_config`](https://pub.dev/documentation/package_config/latest/)
/// to read and parse it.
@Since('3.1')
external static Uri? get packageConfigSync;
/// Resolves a `package:` URI to its actual location.
///
/// Returns the actual location of the file or directory specified by the
/// [packageUri] `package:` URI.
///
/// If the [packageUri] is not a `package:` URI, it's returned as-is.
///
/// Returns `null` if [packageUri] is a `package:` URI, but either
/// the current package configuration does not have a configuration
/// for the package name of the URI, or
/// the URI is not valid (doesn't start with `package:valid_package_name/`),
///
/// A `package:` URI is resolved to its actual location based on
/// a package resolution configuration (see [packageConfig])
/// which specifies how to find the actual location of the file or directory
/// that the `package:` URI points to.
///
/// The actual location corresponding to a `package:` URI is always a
/// non-`package:` URI, typically a `file:` or possibly `http:` URI.
///
/// A program may be run in a way where source files are not available,
/// and if so, the returned URI may not correspond to the actual file or
/// directory or be `null`.
external static Future<Uri?> resolvePackageUri(Uri packageUri);
/// Resolves a `package:` URI to its actual location.
///
/// Returns the actual location of the file or directory specified by the
/// [packageUri] `package:` URI.
///
/// If the [packageUri] is not a `package:` URI, it's returned as-is.
///
/// Returns `null` if [packageUri] is a `package:` URI, but either
/// the current package configuration does not have a configuration
/// for the package name of the URI, or
/// the URI is not valid (doesn't start with `package:valid_package_name/`),
///
/// A `package:` URI is resolved to its actual location based on
/// a package resolution configuration (see [packageConfig])
/// which specifies how to find the actual location of the file or directory
/// that the `package:` URI points to.
///
/// The actual location corresponding to a `package:` URI is always a
/// non-`package:` URI, typically a `file:` or possibly `http:` URI.
///
/// A program may be run in a way where source files are not available,
/// and if so, the returned URI may not correspond to the actual file or
/// directory or be `null`.
@Since('3.1')
external static Uri? resolvePackageUriSync(Uri packageUri);
/// Creates and spawns an isolate that shares the same code as the current
/// isolate.
///
@ -464,9 +528,7 @@ final class Isolate {
/// Returns a future that will complete with an [Isolate] instance if the
/// spawning succeeded. It will complete with an error otherwise.
external static Future<Isolate> spawnUri(
Uri uri,
List<String> args,
var message,
Uri uri, List<String> args, var message,
{bool paused = false,
SendPort? onExit,
SendPort? onError,
@ -474,11 +536,10 @@ final class Isolate {
bool? checked,
Map<String, String>? environment,
@Deprecated('The packages/ dir is not supported in Dart 2')
Uri? packageRoot,
Uri? packageRoot,
Uri? packageConfig,
bool automaticPackageResolution = false,
@Since("2.3")
String? debugName});
@Since("2.3") String? debugName});
/// Requests the isolate to pause.
///

View file

@ -5,7 +5,7 @@
import 'dart:io';
import 'dart:isolate';
final packageUriToResolve = "package:foo/bar.dart";
final packageUriToResolve = Uri.parse("package:foo/bar.dart");
final packageResolvedUri = "file:///no/such/directory/lib/bar.dart";
final packageConfigJson = """
@ -54,8 +54,13 @@ testPackageResolution(port) async {
try {
var packageConfigStr = Platform.packageConfig;
var packageConfig = await Isolate.packageConfig;
var resolvedPkg =
await Isolate.resolvePackageUri(Uri.parse(packageUriToResolve));
if (packageConfig != Isolate.packageConfigSync) {
throw "Isolate.packageConfig != Isolate.packageConfigSync";
}
var resolvedPkg = await Isolate.resolvePackageUri(packageUriToResolve);
if (resolvedPkg != Isolate.resolvePackageUriSync(packageUriToResolve)) {
throw "Isolate.resolvePackageUri != Isolate.resolvePackageUriSync";
}
print("Spawned isolate's package config flag: $packageConfigStr");
print("Spawned isolate's loaded package config: $packageConfig");
print("Spawned isolate's resolved package path: $resolvedPkg");

View file

@ -1,13 +0,0 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// Regression test for faulty encoding of `Isolate.resolvePackageUri` by
// dart2js.
import 'dart:isolate';
main() {
var uri = Isolate.resolvePackageUri(Uri.parse('memory:main.dart'));
print(uri);
}

View file

@ -5,8 +5,8 @@
import 'dart:io';
import 'dart:isolate';
final PACKAGE_URI = "package:foo/bar.dart";
final PACKAGE_PATH = "file:///no/such/directory/bar.dart";
final packageUriToResolve = Uri.parse("package:foo/bar.dart");
final packagePath = "file:///no/such/directory/bar.dart";
main([args, port]) async {
if (port != null) {
@ -27,7 +27,7 @@ main([args, port]) async {
throw "Bad package config in child isolate: ${msg[0]}\n"
"Expected: $child_pkg_config";
}
if (msg[1] != PACKAGE_PATH) {
if (msg[1] != packagePath) {
throw "Package path not matching: ${msg[1]}";
}
print("SUCCESS");
@ -38,7 +38,13 @@ testPackageResolution(port) async {
try {
var packageConfigStr = Platform.packageConfig;
var packageConfig = await Isolate.packageConfig;
var resolvedPkg = await Isolate.resolvePackageUri(Uri.parse(PACKAGE_URI));
if (packageConfig != Isolate.packageConfigSync) {
throw "Isolate.packageConfig != Isolate.packageConfigSync";
}
var resolvedPkg = await Isolate.resolvePackageUri(packageUriToResolve);
if (resolvedPkg != Isolate.resolvePackageUriSync(packageUriToResolve)) {
throw "Isolate.resolvePackageUri != Isolate.resolvePackageUriSync";
}
print("Spawned isolate's package config flag: $packageConfigStr");
print("Spawned isolate's loaded package config: $packageConfig");
print("Spawned isolate's resolved package path: $resolvedPkg");

View file

@ -7,9 +7,11 @@
import 'dart:io';
import 'dart:isolate';
final packageUriToResolve = Uri.parse("package:asdf/qwerty.dart");
main([args, port]) async {
if (port != null) {
testBadResolvePackage(port);
testPackageResolution(port);
return;
}
var p = new RawReceivePort();
@ -21,7 +23,7 @@ main([args, port]) async {
throw "Failure return from spawned isolate:\n\n$msg";
}
// Expecting a null resolution for inexistent package mapping.
if (msg[0] != null) {
if (msg[1] != null) {
throw "Bad package config in child isolate: ${msg[0]}\n"
"Expected: 'Foo'";
}
@ -29,16 +31,21 @@ main([args, port]) async {
};
}
testBadResolvePackage(port) async {
testPackageResolution(port) async {
try {
var packageConfigStr = Platform.packageConfig;
var packageConfig = await Isolate.packageConfig;
var badPackageUri = Uri.parse("package:asdf/qwerty.dart");
var resolvedPkg = await Isolate.resolvePackageUri(badPackageUri);
if (packageConfig != Isolate.packageConfigSync) {
throw "Isolate.packageConfig != Isolate.packageConfigSync";
}
var resolvedPkg = await Isolate.resolvePackageUri(packageUriToResolve);
if (resolvedPkg != Isolate.resolvePackageUriSync(packageUriToResolve)) {
throw "Isolate.resolvePackageUri != Isolate.resolvePackageUriSync";
}
print("Spawned isolate's package config flag: $packageConfigStr");
print("Spawned isolate's loaded package config: $packageConfig");
print("Spawned isolate's resolved package path: $resolvedPkg");
port.send([resolvedPkg?.toString()]);
port.send([packageConfig?.toString(), resolvedPkg?.toString()]);
} catch (e, s) {
port.send("$e\n$s\n");
}

View file

@ -115,7 +115,6 @@ isolate/int32_length_overflow_test: SkipSlow
[ $compiler != dartk || $runtime != vm ]
isolate/package_config_test: SkipByDesign # Uses Isolate.packageConfig
isolate/package_resolve_test: SkipByDesign # Uses Isolate.resolvePackageUri
isolate/package_root_test: SkipByDesign # Uses Isolate.packageRoot
isolate/scenarios/*: SkipByDesign # Use automatic package resolution, spawnFunction and .dart URIs.
isolate/spawn_uri_fail_test: SkipByDesign # Uses dart:io.

View file

@ -56,8 +56,14 @@ testPackageResolution(port) async {
try {
var packageConfigStr = Platform.packageConfig;
var packageConfig = await Isolate.packageConfig;
if (packageConfig != Isolate.packageConfigSync) {
throw "Isolate.packageConfig != Isolate.packageConfigSync";
}
var resolvedPkg =
await Isolate.resolvePackageUri(Uri.parse(packageUriToResolve));
if (resolvedPkg != Isolate.resolvePackageUriSync(packageUriToResolve)) {
throw "Isolate.resolvePackageUri != Isolate.resolvePackageUriSync";
}
print("Spawned isolate's package config flag: $packageConfigStr");
print("Spawned isolate's loaded package config: $packageConfig");
print("Spawned isolate's resolved package path: $resolvedPkg");

View file

@ -1,15 +0,0 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// @dart = 2.9
// Regression test for faulty encoding of `Isolate.resolvePackageUri` by
// dart2js.
import 'dart:isolate';
main() {
Future<Uri> uri = Isolate.resolvePackageUri(Uri.parse('memory:main.dart'));
print(uri);
}

View file

@ -7,8 +7,8 @@
import 'dart:io';
import 'dart:isolate';
final PACKAGE_URI = "package:foo/bar.dart";
final PACKAGE_PATH = "file:///no/such/directory/bar.dart";
final packageUriToResolve = Uri.parse("package:foo/bar.dart");
final packagePath = "file:///no/such/directory/bar.dart";
main([args, port]) async {
if (port != null) {
@ -29,7 +29,7 @@ main([args, port]) async {
throw "Bad package config in child isolate: ${msg[0]}\n"
"Expected: $child_pkg_config";
}
if (msg[1] != PACKAGE_PATH) {
if (msg[1] != packagePath) {
throw "Package path not matching: ${msg[1]}";
}
print("SUCCESS");
@ -40,7 +40,13 @@ testPackageResolution(port) async {
try {
var packageConfigStr = Platform.packageConfig;
var packageConfig = await Isolate.packageConfig;
var resolvedPkg = await Isolate.resolvePackageUri(Uri.parse(PACKAGE_URI));
if (packageConfig != Isolate.packageConfigSync) {
throw "Isolate.packageConfig != Isolate.packageConfigSync";
}
var resolvedPkg = await Isolate.resolvePackageUri(packageUriToResolve);
if (resolvedPkg != Isolate.resolvePackageUriSync(packageUriToResolve)) {
throw "Isolate.resolvePackageUri != Isolate.resolvePackageUriSync";
}
print("Spawned isolate's package config flag: $packageConfigStr");
print("Spawned isolate's loaded package config: $packageConfig");
print("Spawned isolate's resolved package path: $resolvedPkg");

View file

@ -36,7 +36,13 @@ testBadResolvePackage(port) async {
var packageConfigStr = Platform.packageConfig;
var packageConfig = await Isolate.packageConfig;
var badPackageUri = Uri.parse("package:asdf/qwerty.dart");
if (packageConfig != Isolate.packageConfigSync) {
throw "Isolate.packageConfig != Isolate.packageConfigSync";
}
var resolvedPkg = await Isolate.resolvePackageUri(badPackageUri);
if (resolvedPkg != Isolate.resolvePackageUriSync(badPackageUri)) {
throw "Isolate.resolvePackageUri != Isolate.resolvePackageUriSync";
}
print("Spawned isolate's package config flag: $packageConfigStr");
print("Spawned isolate's loaded package config: $packageConfig");
print("Spawned isolate's resolved package path: $resolvedPkg");

View file

@ -93,7 +93,6 @@ isolate/int32_length_overflow_test: SkipSlow
[ $compiler != dartk || $runtime != vm ]
isolate/package_config_test: SkipByDesign # Uses Isolate.packageConfig
isolate/package_resolve_test: SkipByDesign # Uses Isolate.resolvePackageUri
isolate/package_root_test: SkipByDesign # Uses Isolate.packageRoot
isolate/scenarios/*: SkipByDesign # Use automatic package resolution, spawnFunction and .dart URIs.
isolate/spawn_uri_fail_test: SkipByDesign # Uses dart:io.

File diff suppressed because it is too large Load diff

View file

@ -11,8 +11,6 @@ io/large_file_read_small_file_test: Slow, Pass # Test reads small file 1M times
io/non_utf8_directory_test: Skip # Issue 33519. Temp files causing bots to go purple.
io/non_utf8_file_test: Skip # Issue 33519. Temp files causing bots to go purple.
io/non_utf8_link_test: Skip # Issue 33519. Temp files causing bots to go purple.
packages_file_test: Skip # Issue 26715
packages_file_test/none: Skip # contains no tests.
[ $builder_tag == dwarf ]
io/socket_connect_stacktrace_test: SkipByDesign # Assumes stacktrace can be inspected directly, without decoding

File diff suppressed because it is too large Load diff

View file

@ -11,8 +11,6 @@ io/large_file_read_small_file_test: Slow, Pass # Test reads small file 1M times
io/non_utf8_directory_test: Skip # Issue 33519. Temp files causing bots to go purple.
io/non_utf8_file_test: Skip # Issue 33519. Temp files causing bots to go purple.
io/non_utf8_link_test: Skip # Issue 33519. Temp files causing bots to go purple.
packages_file_test: Skip # Issue 26715
packages_file_test/none: Skip # contains no tests.
[ $builder_tag == dwarf ]
io/socket_connect_stacktrace_test: SkipByDesign # Assumes stacktrace can be inspected directly, without decoding