Add functions to help with --packages/--package-root command line parameters.
R=pquitslund@google.com, sgjesse@google.com
Review URL: https://codereview.chromium.org//1166443005.
diff --git a/pkgs/package_config/lib/discovery.dart b/pkgs/package_config/lib/discovery.dart
index 0dd7f55..35c3ece 100644
--- a/pkgs/package_config/lib/discovery.dart
+++ b/pkgs/package_config/lib/discovery.dart
@@ -15,6 +15,55 @@
import "src/packages_impl.dart";
import "src/packages_io_impl.dart";
+/// Reads a package resolution file and creates a [Packages] object from it.
+///
+/// The [packagesFile] must exist and be loadable.
+/// Currently that means the URI must have a `file`, `http` or `https` scheme,
+/// and that the file can be loaded and its contents parsed correctly.
+///
+/// If the [loader] is provided, it is used to fetch non-`file` URIs, and
+/// it can support other schemes or set up more complex HTTP requests.
+///
+/// This function can be used to load an explicitly configured package
+/// resolution file, for example one specified using a `--packages`
+/// command-line parameter.
+Future<Packages> loadPackagesFile(Uri packagesFile,
+ {Future<List<int>> loader(Uri uri)}) {
+ Packages parseBytes(List<int> bytes) {
+ Map<String, Uri> packageMap = pkgfile.parse(bytes, packagesFile);
+ return new MapPackages(packageMap);
+ }
+ if (packagesFile.scheme == "file") {
+ File file = new File.fromUri(packagesFile);
+ return file.readAsBytes().then(parseBytes);
+ }
+ if (loader == null) {
+ return http.readBytes(packagesFile).then(parseBytes);
+ }
+ return loader(packagesFile).then(parseBytes);
+}
+
+
+/// Create a [Packages] object for a package directory.
+///
+/// The [packagesDir] URI should refer to a directory.
+/// Package names are resolved as relative to sub-directories of the
+/// package directory.
+///
+/// This function can be used for explicitly configured package directories,
+/// for example one specified using a `--package-root` comand-line parameter.
+Packages getPackagesDirectory(Uri packagesDir) {
+ if (packagesDir.scheme == "file") {
+ Directory directory = new Directory.fromUri(packagesDir);
+ return new FilePackagesDirectoryPackages(directory);
+ }
+ if (!packagesDir.path.endsWith('/')) {
+ packagesDir = packagesDir.replace(path: packagesDir.path + '/');
+ }
+ return new NonFilePackagesDirectoryPackages(packagesDir);
+}
+
+
/// Discover the package configuration for a Dart script.
///
/// The [baseUri] points to either the Dart script or its directory.
@@ -36,19 +85,21 @@
/// It needs to be able to load a `.packages` file from the URI, so only
/// recognized schemes are accepted.
///
-/// To support other schemes, an optional [loader] function can be supplied.
-/// It's called to load the `.packages` file for any unsupported scheme.
-/// It must return the *contents* of the file identified by the URI it's given,
-/// which should be a UTF-8 encoded `.packages` file, and must return an
+/// To support other schemes, or more complex HTTP requests,
+/// an optional [loader] function can be supplied.
+/// It's called to load the `.packages` file for a non-`file` scheme.
+/// The loader function returns the *contents* of the file
+/// identified by the URI it's given.
+/// The content should be a UTF-8 encoded `.packages` file, and must return an
/// error future if loading fails for any reason.
Future<Packages> findPackages(Uri baseUri,
- {Future<List<int>> loader(Uri unsupportedUri)}) {
+ {Future<List<int>> loader(Uri unsupportedUri)}) {
if (baseUri.scheme == "file") {
return new Future<Packages>.sync(() => findPackagesFromFile(baseUri));
- } else if (baseUri.scheme == "http" || baseUri.scheme == "https") {
- return findPackagesFromNonFile(baseUri, loader: _httpGet);
} else if (loader != null) {
return findPackagesFromNonFile(baseUri, loader: loader);
+ } else if (baseUri.scheme == "http" || baseUri.scheme == "https") {
+ return findPackagesFromNonFile(baseUri, loader: http.readBytes);
} else {
return new Future<Packages>.value(Packages.noPackages);
}
@@ -140,8 +191,8 @@
/// of the requested `.packages` file as bytes, which will be assumed to be
/// UTF-8 encoded.
Future<Packages> findPackagesFromNonFile(Uri nonFileUri,
- {Future<List<int>> loader(Uri name)}) {
- if (loader == null) loader = _httpGet;
+ {Future<List<int>> loader(Uri name)}) {
+ if (loader == null) loader = http.readBytes;
Uri packagesFileUri = nonFileUri.resolve(".packages");
return loader(packagesFileUri).then((List<int> fileBytes) {
Map<String, Uri> map = pkgfile.parse(fileBytes, packagesFileUri);
@@ -152,30 +203,3 @@
return new NonFilePackagesDirectoryPackages(packagesDirectoryUri);
});
}
-
-/// Fetches a file over http.
-Future<List<int>> _httpGet(Uri uri) {
- HttpClient client = new HttpClient();
- return client
- .getUrl(uri)
- .then((HttpClientRequest request) => request.close())
- .then((HttpClientResponse response) {
- if (response.statusCode != HttpStatus.OK) {
- String msg = 'Failure getting $uri: '
- '${response.statusCode} ${response.reasonPhrase}';
- throw msg;
- }
- return response.toList();
- }).then((List<List<int>> splitContent) {
- int totalLength = splitContent.fold(0, (int old, List list) {
- return old + list.length;
- });
- Uint8List result = new Uint8List(totalLength);
- int offset = 0;
- for (List<int> contentPart in splitContent) {
- result.setRange(offset, offset + contentPart.length, contentPart);
- offset += contentPart.length;
- }
- return result;
- });
-}
diff --git a/pkgs/package_config/test/discovery_test.dart b/pkgs/package_config/test/discovery_test.dart
index 16544e4..d89cc2f 100644
--- a/pkgs/package_config/test/discovery_test.dart
+++ b/pkgs/package_config/test/discovery_test.dart
@@ -205,6 +205,52 @@
loader:loader);
validatePackagesDir(resolver, location);
});
+
+ generalTest("loadPackagesFile",
+ {".packages": packagesFile},
+ (Uri directory) async {
+ Uri file = directory.resolve(".packages");
+ Packages resolver = await loadPackagesFile(file);
+ validatePackagesFile(resolver, file);
+ });
+
+ generalTest("loadPackagesFile non-default name",
+ {"pheldagriff": packagesFile},
+ (Uri directory) async {
+ Uri file = directory.resolve("pheldagriff");
+ Packages resolver = await loadPackagesFile(file);
+ validatePackagesFile(resolver, file);
+ });
+
+ test("loadPackagesFile w/ loader", () async {
+ loader(Uri uri) async => packagesFile.codeUnits;
+ Uri file = Uri.parse("krutz://example.com/.packages");
+ Packages resolver = await loadPackagesFile(file, loader: loader);
+ validatePackagesFile(resolver, file);
+ });
+
+ generalTest("loadPackagesFile not found",
+ {},
+ (Uri directory) async {
+ Uri file = directory.resolve(".packages");
+ expect(loadPackagesFile(file), throws);
+ });
+
+ generalTest("loadPackagesFile syntax error",
+ {".packages": "syntax error"},
+ (Uri directory) async {
+ Uri file = directory.resolve(".packages");
+ expect(loadPackagesFile(file), throws);
+ });
+
+ generalTest("getPackagesDir",
+ {"packages": {"foo": {}, "bar": {}, "baz": {}}},
+ (Uri directory) async {
+ Uri packages = directory.resolve("packages/");
+ Packages resolver = getPackagesDirectory(packages);
+ Uri resolved = resolver.resolve(pkg("foo","flip/flop"));
+ expect(resolved, packages.resolve("foo/flip/flop"));
+ });
}
/// Create a directory structure from [description] and run [fileTest].
@@ -285,5 +331,3 @@
}
});
}
-
-