From fa368609ce721202319196d28e3b8c3d3b6daa3a Mon Sep 17 00:00:00 2001 From: pquitslund Date: Wed, 13 May 2015 13:38:29 -0700 Subject: [PATCH 001/170] Initial template commit. --- pkgs/package_config/.gitignore | 7 +++ pkgs/package_config/.travis.yml | 3 ++ pkgs/package_config/AUTHORS | 6 +++ pkgs/package_config/CHANGELOG.md | 5 ++ pkgs/package_config/CONTRIBUTING.md | 33 ++++++++++++ pkgs/package_config/LICENSE | 26 +++++++++ pkgs/package_config/README.md | 11 ++++ pkgs/package_config/pubspec.lock | 83 +++++++++++++++++++++++++++++ pkgs/package_config/pubspec.yaml | 11 ++++ pkgs/package_config/test/all.dart | 9 ++++ pkgs/package_config/tool/travis.sh | 16 ++++++ 11 files changed, 210 insertions(+) create mode 100644 pkgs/package_config/.gitignore create mode 100644 pkgs/package_config/.travis.yml create mode 100644 pkgs/package_config/AUTHORS create mode 100644 pkgs/package_config/CHANGELOG.md create mode 100644 pkgs/package_config/CONTRIBUTING.md create mode 100644 pkgs/package_config/LICENSE create mode 100644 pkgs/package_config/README.md create mode 100644 pkgs/package_config/pubspec.lock create mode 100644 pkgs/package_config/pubspec.yaml create mode 100644 pkgs/package_config/test/all.dart create mode 100755 pkgs/package_config/tool/travis.sh diff --git a/pkgs/package_config/.gitignore b/pkgs/package_config/.gitignore new file mode 100644 index 000000000..f48e3c9a8 --- /dev/null +++ b/pkgs/package_config/.gitignore @@ -0,0 +1,7 @@ +.idea +.pub +packages +build +.project +.settings +pubspec.lock \ No newline at end of file diff --git a/pkgs/package_config/.travis.yml b/pkgs/package_config/.travis.yml new file mode 100644 index 000000000..b1279b7e4 --- /dev/null +++ b/pkgs/package_config/.travis.yml @@ -0,0 +1,3 @@ +language: dart +script: ./tool/travis.sh +sudo: false diff --git a/pkgs/package_config/AUTHORS b/pkgs/package_config/AUTHORS new file mode 100644 index 000000000..e8063a8cd --- /dev/null +++ b/pkgs/package_config/AUTHORS @@ -0,0 +1,6 @@ +# Below is a list of people and organizations that have contributed +# to the project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md new file mode 100644 index 000000000..2a2d63cf8 --- /dev/null +++ b/pkgs/package_config/CHANGELOG.md @@ -0,0 +1,5 @@ +# Changelog + +## 0.0.1 + +- Initial version diff --git a/pkgs/package_config/CONTRIBUTING.md b/pkgs/package_config/CONTRIBUTING.md new file mode 100644 index 000000000..6f5e0ea67 --- /dev/null +++ b/pkgs/package_config/CONTRIBUTING.md @@ -0,0 +1,33 @@ +Want to contribute? Great! First, read this page (including the small print at +the end). + +### Before you contribute +Before we can use your code, you must sign the +[Google Individual Contributor License Agreement](https://cla.developers.google.com/about/google-individual) +(CLA), which you can do online. The CLA is necessary mainly because you own the +copyright to your changes, even after your contribution becomes part of our +codebase, so we need your permission to use and distribute your code. We also +need to be sure of various other things—for instance that you'll tell us if you +know that your code infringes on other people's patents. You don't have to sign +the CLA until after you've submitted your code for review and a member has +approved it, but you must do it before we can put your code into our codebase. + +Before you start working on a larger contribution, you should get in touch with +us first through the issue tracker with your idea so that we can help out and +possibly guide you. Coordinating up front makes it much easier to avoid +frustration later on. + +### Code reviews +All submissions, including submissions by project members, require review. + +### File headers +All files in the project must start with the following header. + + // Copyright (c) 2015, 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. + +### The small print +Contributions made by corporations are covered by a different agreement than the +one above, the +[Software Grant and Corporate Contributor License Agreement](https://developers.google.com/open-source/cla/corporate). diff --git a/pkgs/package_config/LICENSE b/pkgs/package_config/LICENSE new file mode 100644 index 000000000..de31e1a0a --- /dev/null +++ b/pkgs/package_config/LICENSE @@ -0,0 +1,26 @@ +Copyright 2015, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/pkgs/package_config/README.md b/pkgs/package_config/README.md new file mode 100644 index 000000000..17d199b4a --- /dev/null +++ b/pkgs/package_config/README.md @@ -0,0 +1,11 @@ +# package_config + +Support for working with **Package Resolution Configuration** files as described +in this [DEP](https://github.com/lrhn/dep-pkgspec/blob/master/DEP-pkgspec.md), +under review [here] (https://github.com/dart-lang/dart_enhancement_proposals/issues/5). + +## Features and bugs + +Please file feature requests and bugs at the [issue tracker][tracker]. + +[tracker]: https://github.com/dart-lang/package_config/issues diff --git a/pkgs/package_config/pubspec.lock b/pkgs/package_config/pubspec.lock new file mode 100644 index 000000000..197d32ed6 --- /dev/null +++ b/pkgs/package_config/pubspec.lock @@ -0,0 +1,83 @@ +# Generated by pub +# See http://pub.dartlang.org/doc/glossary.html#lockfile +packages: + analyzer: + description: analyzer + source: hosted + version: "0.25.0+1" + args: + description: args + source: hosted + version: "0.13.0" + barback: + description: barback + source: hosted + version: "0.15.2+4" + collection: + description: collection + source: hosted + version: "1.1.1" + crypto: + description: crypto + source: hosted + version: "0.9.0" + http_parser: + description: http_parser + source: hosted + version: "0.0.2+6" + matcher: + description: matcher + source: hosted + version: "0.12.0" + mime: + description: mime + source: hosted + version: "0.9.3" + path: + description: path + source: hosted + version: "1.3.5" + pool: + description: pool + source: hosted + version: "1.0.1" + pub_semver: + description: pub_semver + source: hosted + version: "1.2.0" + shelf: + description: shelf + source: hosted + version: "0.6.1+2" + shelf_static: + description: shelf_static + source: hosted + version: "0.2.2" + shelf_web_socket: + description: shelf_web_socket + source: hosted + version: "0.0.1+2" + source_span: + description: source_span + source: hosted + version: "1.1.2" + stack_trace: + description: stack_trace + source: hosted + version: "1.3.2" + string_scanner: + description: string_scanner + source: hosted + version: "0.1.3+1" + test: + description: test + source: hosted + version: "0.12.1" + watcher: + description: watcher + source: hosted + version: "0.9.5" + yaml: + description: yaml + source: hosted + version: "2.1.2" diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml new file mode 100644 index 000000000..b0f2d8fec --- /dev/null +++ b/pkgs/package_config/pubspec.yaml @@ -0,0 +1,11 @@ +name: package_config +version: 0.0.1 +description: Support for working with Package Resolution config files. +author: Dart Team +homepage: https://github.com/dart-lang/package_config + +environment: + sdk: '>=1.0.0 <2.0.0' + +dev_dependencies: + test: '>=0.12.0 <0.13.0' diff --git a/pkgs/package_config/test/all.dart b/pkgs/package_config/test/all.dart new file mode 100644 index 000000000..76284af2b --- /dev/null +++ b/pkgs/package_config/test/all.dart @@ -0,0 +1,9 @@ +// Copyright (c) 2015, 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. + +import 'package:test/test.dart'; + +main() { + // TODO: add tests! +} diff --git a/pkgs/package_config/tool/travis.sh b/pkgs/package_config/tool/travis.sh new file mode 100755 index 000000000..8fdabfdf6 --- /dev/null +++ b/pkgs/package_config/tool/travis.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# Copyright (c) 2015, 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. + +# Fast fail the script on failures. +set -e + +# Verify that the libraries are error free. +dartanalyzer --fatal-warnings \ + test/all.dart + +# Run the tests. +dart test/all.dart + From 0ede819f2cd3d377b77cb6c0671398a474cc4a9e Mon Sep 17 00:00:00 2001 From: Phil Quitslund Date: Wed, 13 May 2015 14:05:08 -0700 Subject: [PATCH 002/170] Update README.md Added build badge. --- pkgs/package_config/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkgs/package_config/README.md b/pkgs/package_config/README.md index 17d199b4a..140c3c4f9 100644 --- a/pkgs/package_config/README.md +++ b/pkgs/package_config/README.md @@ -4,6 +4,9 @@ Support for working with **Package Resolution Configuration** files as described in this [DEP](https://github.com/lrhn/dep-pkgspec/blob/master/DEP-pkgspec.md), under review [here] (https://github.com/dart-lang/dart_enhancement_proposals/issues/5). +[![Build Status](https://travis-ci.org/dart-lang/package_config.svg)](https://travis-ci.org/dart-lang/linter) + + ## Features and bugs Please file feature requests and bugs at the [issue tracker][tracker]. From 8aac6f18fd215ae16a164536bf74c50fecf63f81 Mon Sep 17 00:00:00 2001 From: pquitslund Date: Wed, 13 May 2015 14:25:23 -0700 Subject: [PATCH 003/170] Initial parser port. --- pkgs/package_config/lib/packagemap.dart | 227 ++++++++++++++++++ pkgs/package_config/test/all.dart | 4 +- pkgs/package_config/test/test_packagemap.dart | 149 ++++++++++++ pkgs/package_config/tool/travis.sh | 1 + 4 files changed, 379 insertions(+), 2 deletions(-) create mode 100644 pkgs/package_config/lib/packagemap.dart create mode 100644 pkgs/package_config/test/test_packagemap.dart diff --git a/pkgs/package_config/lib/packagemap.dart b/pkgs/package_config/lib/packagemap.dart new file mode 100644 index 000000000..046aa5221 --- /dev/null +++ b/pkgs/package_config/lib/packagemap.dart @@ -0,0 +1,227 @@ +// Copyright (c) 2015, 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. + +library package_config.packagemap; + +class Packages { + static const int _EQUALS = 0x3d; + static const int _CR = 0x0d; + static const int _NL = 0x0a; + static const int _NUMBER_SIGN = 0x23; + + final Map packageMapping; + + Packages(this.packageMapping); + + /// Resolves a URI to a non-package URI. + /// + /// If [uri] is a `package:` URI, the location is resolved wrt. the + /// [packageMapping]. + /// Otherwise the original URI is returned. + Uri resolve(Uri uri) { + if (uri.scheme.toLowerCase() != "package") { + return uri; + } + if (uri.hasAuthority) { + throw new ArgumentError.value(uri, "uri", "Must not have authority"); + } + if (uri.path.startsWith("/")) { + throw new ArgumentError.value(uri, "uri", + "Path must not start with '/'."); + } + // Normalizes the path by removing '.' and '..' segments. + uri = uri.normalizePath(); + String path = uri.path; + var slashIndex = path.indexOf('/'); + String packageName; + String rest; + if (slashIndex < 0) { + packageName = path; + rest = ""; + } else { + packageName = path.substring(0, slashIndex); + rest = path.substring(slashIndex + 1); + } + Uri packageLocation = packageMapping[packageName]; + if (packageLocation == null) { + throw new ArgumentError.value(uri, "uri", + "Unknown package name: $packageName"); + } + return packageLocation.resolveUri(new Uri(path: rest)); + } + + /// Parses a `packages.cfg` file into a `Packages` object. + /// + /// The [baseLocation] is used as a base URI to resolve all relative + /// URI references against. + /// + /// The `Packages` object allows resolving package: URIs and writing + /// the mapping back to a file or string. + /// The [packageMapping] will contain a simple mapping from package name + /// to package location. + static Packages parse(String source, Uri baseLocation) { + int index = 0; + Map result = {}; + while (index < source.length) { + bool isComment = false; + int start = index; + int eqIndex = -1; + int end = source.length; + int char = source.codeUnitAt(index++); + if (char == _CR || char == _NL) { + continue; + } + if (char == _EQUALS) { + throw new FormatException("Missing package name", source, index - 1); + } + isComment = char == _NUMBER_SIGN; + while (index < source.length) { + char = source.codeUnitAt(index++); + if (char == _EQUALS && eqIndex < 0) { + eqIndex = index - 1; + } else if (char == _NL || char == _CR) { + end = index - 1; + break; + } + } + if (isComment) continue; + if (eqIndex < 0) { + throw new FormatException("No '=' on line", source, index - 1); + } + _checkIdentifier(source, start, eqIndex); + var packageName = source.substring(start, eqIndex); + + var packageLocation = Uri.parse(source, eqIndex + 1, end); + if (!packageLocation.path.endsWith('/')) { + packageLocation = packageLocation.replace( + path: packageLocation.path + "/"); + } + packageLocation = baseLocation.resolveUri(packageLocation); + if (result.containsKey(packageName)) { + throw new FormatException("Same package name occured twice.", + source, start); + } + result[packageName] = packageLocation; + } + return new Packages(result); + } + + /** + * Writes the mapping to a [StringSink]. + * + * If [comment] is provided, the output will contain this comment + * with `#` in front of each line. + * + * If [baseUri] is provided, package locations will be made relative + * to the base URI, if possible, before writing. + */ + void write(StringSink output, {Uri baseUri, String comment}) { + if (baseUri != null && !baseUri.isAbsolute) { + throw new ArgumentError.value(baseUri, "baseUri", "Must be absolute"); + } + + if (comment != null) { + for (var commentLine in comment.split('\n')) { + output.write('#'); + output.writeln(commentLine); + } + } else { + output.write("# generated by package:packagecfg at "); + output.write(new DateTime.now()); + output.writeln(); + } + + packageMapping.forEach((String packageName, Uri uri) { + // Validate packageName. + _checkIdentifier(packageName, 0, packageName.length); + output.write(packageName); + + output.write('='); + + // If baseUri provided, make uri relative. + if (baseUri != null) { + uri = _relativizeUri(uri, baseUri); + } + output.write(uri); + if (!uri.path.endsWith('/')) { + output.write('/'); + } + output.writeln(); + }); + } + + String toString() { + StringBuffer buffer = new StringBuffer(); + write(buffer); + return buffer.toString(); + } + + static Uri relativize(Uri uri, + Uri baseUri) { + if (uri.hasQuery || uri.hasFragment) { + uri = new Uri(scheme: uri.scheme, + userInfo: uri.hasAuthority ? uri.userInfo : null, + host: uri.hasAuthority ? uri.host : null, + port: uri.hasAuthority ? uri.port : null, + path: uri.path); + } + if (!baseUri.isAbsolute) { + throw new ArgumentError("Base uri '$baseUri' must be absolute."); + } + // Already relative. + if (!uri.isAbsolute) return uri; + + if (baseUri.scheme.toLowerCase() != uri.scheme.toLowerCase()) { + return uri; + } + // If authority differs, we could remove the scheme, but it's not worth it. + if (uri.hasAuthority != baseUri.hasAuthority) return uri; + if (uri.hasAuthority) { + if (uri.userInfo != baseUri.userInfo || + uri.host.toLowerCase() != baseUri.host.toLowerCase() || + uri.port != baseUri.port) { + return uri; + } + } + + List base = baseUri.pathSegments.toList(); + base = base.normalizePath(); + if (base.isNotEmpty) { + base = new List.from(base)..removeLast(); + } + List target = uri.pathSegments.toList(); + target = target.normalizePath(); + int index = 0; + while (index < base.length && index < target.length) { + if (base[index] != target[index]) { + break; + } + index++; + } + if (index == base.length) { + return new Uri(path: target.skip(index).join('/')); + } else if (index > 0) { + return new Uri( + path: '../' * (base.length - index) + target.skip(index).join('/')); + } else { + return uri; + } + } + + static void _checkIdentifier(String string, int start, int end) { + const int a = 0x61; + const int z = 0x7a; + const int _ = 0x5f; + const int $ = 0x24; + if (start == end) return false; + for (int i = start; i < end; i++) { + var char = string.codeUnitAt(i); + if (char == _ || char == $) continue; + if ((char ^ 0x30) <= 9 && i > 0) continue; + char |= 0x20; // Lower-case letters. + if (char >= a && char <= z) continue; + throw new FormatException("Not an identifier", string, i); + } + } +} \ No newline at end of file diff --git a/pkgs/package_config/test/all.dart b/pkgs/package_config/test/all.dart index 76284af2b..795289cdf 100644 --- a/pkgs/package_config/test/all.dart +++ b/pkgs/package_config/test/all.dart @@ -2,8 +2,8 @@ // 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. -import 'package:test/test.dart'; +import 'test_packagemap.dart' as packagemap; main() { - // TODO: add tests! + packagemap.main(); } diff --git a/pkgs/package_config/test/test_packagemap.dart b/pkgs/package_config/test/test_packagemap.dart new file mode 100644 index 000000000..bce20d4b8 --- /dev/null +++ b/pkgs/package_config/test/test_packagemap.dart @@ -0,0 +1,149 @@ +// Copyright (c) 2015, 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. + +library test_all; + +import "package:package_config/packagemap.dart"; +import "package:test/test.dart"; + +main() { + var base = Uri.parse("file:///one/two/three/packages.map"); + test("empty", () { + var packages = Packages.parse(emptySample, base); + expect(packages.packageMapping, isEmpty); + }); + test("comment only", () { + var packages = Packages.parse(commentOnlySample, base); + expect(packages.packageMapping, isEmpty); + }); + test("empty lines only", () { + var packages = Packages.parse(emptyLinesSample, base); + expect(packages.packageMapping, isEmpty); + }); + + test("empty lines only", () { + var packages = Packages.parse(emptyLinesSample, base); + expect(packages.packageMapping, isEmpty); + }); + + test("single", () { + var packages = Packages.parse(singleRelativeSample, base); + expect(packages.packageMapping.keys.toList(), equals(["foo"])); + expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), + equals(base.resolve("../test/").resolve("bar/baz.dart"))); + }); + + test("single no slash", () { + var packages = Packages.parse(singleRelativeSampleNoSlash, base); + expect(packages.packageMapping.keys.toList(), equals(["foo"])); + expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), + equals(base.resolve("../test/").resolve("bar/baz.dart"))); + }); + + test("single no newline", () { + var packages = Packages.parse(singleRelativeSampleNoNewline, base); + expect(packages.packageMapping.keys.toList(), equals(["foo"])); + expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), + equals(base.resolve("../test/").resolve("bar/baz.dart"))); + }); + + test("single absolute", () { + var packages = Packages.parse(singleAbsoluteSample, base); + expect(packages.packageMapping.keys.toList(), equals(["foo"])); + expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), + equals(Uri.parse("http://example.com/some/where/bar/baz.dart"))); + }); + + test("multiple", () { + var packages = Packages.parse(multiRelativeSample, base); + expect( + packages.packageMapping.keys.toList()..sort(), equals(["bar", "foo"])); + expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), + equals(base.resolve("../test/").resolve("bar/baz.dart"))); + expect(packages.resolve(Uri.parse("package:bar/foo/baz.dart")), + equals(base.resolve("../test2/").resolve("foo/baz.dart"))); + }); + + test("dot-dot 1", () { + var packages = Packages.parse(singleRelativeSample, base); + expect(packages.packageMapping.keys.toList(), equals(["foo"])); + expect(packages.resolve(Uri.parse("package:foo/qux/../bar/baz.dart")), + equals(base.resolve("../test/").resolve("bar/baz.dart"))); + }); + + test("dot-dot 2", () { + var packages = Packages.parse(singleRelativeSample, base); + expect(packages.packageMapping.keys.toList(), equals(["foo"])); + expect(packages.resolve(Uri.parse("package:qux/../foo/bar/baz.dart")), + equals(base.resolve("../test/").resolve("bar/baz.dart"))); + }); + + test("all valid chars", () { + var packages = Packages.parse(allValidCharsSample, base); + expect(packages.packageMapping.keys.toList(), equals([allValidChars])); + expect(packages.resolve(Uri.parse("package:$allValidChars/bar/baz.dart")), + equals(base.resolve("../test/").resolve("bar/baz.dart"))); + }); + + test("no escapes", () { + expect(() => Packages.parse("x%41x=x", base), throws); + }); + + test("not identifiers", () { + expect(() => Packages.parse("1x=x", base), throws); + expect(() => Packages.parse(" x=x", base), throws); + expect(() => Packages.parse("\\x41x=x", base), throws); + expect(() => Packages.parse("x@x=x", base), throws); + expect(() => Packages.parse("x[x=x", base), throws); + expect(() => Packages.parse("x`x=x", base), throws); + expect(() => Packages.parse("x{x=x", base), throws); + expect(() => Packages.parse("x/x=x", base), throws); + expect(() => Packages.parse("x:x=x", base), throws); + }); + + test("same name twice", () { + expect(() => Packages.parse(singleRelativeSample * 2, base), throws); + }); + + for (String invalidSample in invalid) { + test("invalid '$invalidSample'", () { + var result; + try { + result = Packages.parse(invalidSample, base); + } on FormatException { + // expected + return; + } + fail("Resolved to $result"); + }); + } +} + +// Valid samples. +var emptySample = ""; +var commentOnlySample = "# comment only\n"; +var emptyLinesSample = "\n\n\r\n"; +var singleRelativeSample = "foo=../test/\n"; +var singleRelativeSampleNoSlash = "foo=../test\n"; +var singleRelativeSampleNoNewline = "foo=../test/"; +var singleAbsoluteSample = "foo=http://example.com/some/where/\n"; +var multiRelativeSample = "foo=../test/\nbar=../test2/\n"; +// All valid path segment characters in an URI. +var allValidChars = + r"$0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"; +var allValidCharsSample = "${allValidChars.replaceAll('=', '%3D')}=../test/\n"; +var allUnreservedChars = + "-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~"; + +// Invalid samples. +var invalid = [ + "foobar:baz.dart", // no equals + ".=../test/", // dot segment + "..=../test/", // dot-dot segment + "foo/bar=../test/", // + "/foo=../test/", // var multiSegmentSample + "?=../test/", // invalid characters in path segment. + "[=../test/", // invalid characters in path segment. + "x#=../test/", // invalid characters in path segment. +]; diff --git a/pkgs/package_config/tool/travis.sh b/pkgs/package_config/tool/travis.sh index 8fdabfdf6..82423816b 100755 --- a/pkgs/package_config/tool/travis.sh +++ b/pkgs/package_config/tool/travis.sh @@ -9,6 +9,7 @@ set -e # Verify that the libraries are error free. dartanalyzer --fatal-warnings \ + lib/packagemap.dart \ test/all.dart # Run the tests. From a1a4f439bd93755fa76df9eb558ba3a37099b3d8 Mon Sep 17 00:00:00 2001 From: pquitslund Date: Wed, 13 May 2015 14:44:16 -0700 Subject: [PATCH 004/170] Parser fixes. --- pkgs/package_config/lib/packagemap.dart | 47 +++++++++++++------------ 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/pkgs/package_config/lib/packagemap.dart b/pkgs/package_config/lib/packagemap.dart index 046aa5221..25f27b9a2 100644 --- a/pkgs/package_config/lib/packagemap.dart +++ b/pkgs/package_config/lib/packagemap.dart @@ -27,8 +27,8 @@ class Packages { throw new ArgumentError.value(uri, "uri", "Must not have authority"); } if (uri.path.startsWith("/")) { - throw new ArgumentError.value(uri, "uri", - "Path must not start with '/'."); + throw new ArgumentError.value( + uri, "uri", "Path must not start with '/'."); } // Normalizes the path by removing '.' and '..' segments. uri = uri.normalizePath(); @@ -45,8 +45,8 @@ class Packages { } Uri packageLocation = packageMapping[packageName]; if (packageLocation == null) { - throw new ArgumentError.value(uri, "uri", - "Unknown package name: $packageName"); + throw new ArgumentError.value( + uri, "uri", "Unknown package name: $packageName"); } return packageLocation.resolveUri(new Uri(path: rest)); } @@ -94,13 +94,13 @@ class Packages { var packageLocation = Uri.parse(source, eqIndex + 1, end); if (!packageLocation.path.endsWith('/')) { - packageLocation = packageLocation.replace( - path: packageLocation.path + "/"); + packageLocation = + packageLocation.replace(path: packageLocation.path + "/"); } packageLocation = baseLocation.resolveUri(packageLocation); if (result.containsKey(packageName)) { - throw new FormatException("Same package name occured twice.", - source, start); + throw new FormatException( + "Same package name occured twice.", source, start); } result[packageName] = packageLocation; } @@ -141,7 +141,7 @@ class Packages { // If baseUri provided, make uri relative. if (baseUri != null) { - uri = _relativizeUri(uri, baseUri); + uri = relativize(uri, baseUri); } output.write(uri); if (!uri.path.endsWith('/')) { @@ -157,14 +157,14 @@ class Packages { return buffer.toString(); } - static Uri relativize(Uri uri, - Uri baseUri) { + static Uri relativize(Uri uri, Uri baseUri) { if (uri.hasQuery || uri.hasFragment) { - uri = new Uri(scheme: uri.scheme, - userInfo: uri.hasAuthority ? uri.userInfo : null, - host: uri.hasAuthority ? uri.host : null, - port: uri.hasAuthority ? uri.port : null, - path: uri.path); + uri = new Uri( + scheme: uri.scheme, + userInfo: uri.hasAuthority ? uri.userInfo : null, + host: uri.hasAuthority ? uri.host : null, + port: uri.hasAuthority ? uri.port : null, + path: uri.path); } if (!baseUri.isAbsolute) { throw new ArgumentError("Base uri '$baseUri' must be absolute."); @@ -179,19 +179,19 @@ class Packages { if (uri.hasAuthority != baseUri.hasAuthority) return uri; if (uri.hasAuthority) { if (uri.userInfo != baseUri.userInfo || - uri.host.toLowerCase() != baseUri.host.toLowerCase() || - uri.port != baseUri.port) { + uri.host.toLowerCase() != baseUri.host.toLowerCase() || + uri.port != baseUri.port) { return uri; } } + baseUri = baseUri.normalizePath(); List base = baseUri.pathSegments.toList(); - base = base.normalizePath(); if (base.isNotEmpty) { base = new List.from(base)..removeLast(); } + uri = uri.normalizePath(); List target = uri.pathSegments.toList(); - target = target.normalizePath(); int index = 0; while (index < base.length && index < target.length) { if (base[index] != target[index]) { @@ -209,7 +209,7 @@ class Packages { } } - static void _checkIdentifier(String string, int start, int end) { + static bool _checkIdentifier(String string, int start, int end) { const int a = 0x61; const int z = 0x7a; const int _ = 0x5f; @@ -219,9 +219,10 @@ class Packages { var char = string.codeUnitAt(i); if (char == _ || char == $) continue; if ((char ^ 0x30) <= 9 && i > 0) continue; - char |= 0x20; // Lower-case letters. + char |= 0x20; // Lower-case letters. if (char >= a && char <= z) continue; throw new FormatException("Not an identifier", string, i); } + return true; } -} \ No newline at end of file +} From 8dc4c7c292f4a81a312427700b0f429ae5f82ed8 Mon Sep 17 00:00:00 2001 From: pquitslund Date: Wed, 13 May 2015 14:57:34 -0700 Subject: [PATCH 005/170] Backed out path normalization. --- pkgs/package_config/lib/packagemap.dart | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pkgs/package_config/lib/packagemap.dart b/pkgs/package_config/lib/packagemap.dart index 25f27b9a2..e05c14d15 100644 --- a/pkgs/package_config/lib/packagemap.dart +++ b/pkgs/package_config/lib/packagemap.dart @@ -30,8 +30,9 @@ class Packages { throw new ArgumentError.value( uri, "uri", "Path must not start with '/'."); } + //TODO: re-enable // Normalizes the path by removing '.' and '..' segments. - uri = uri.normalizePath(); + // uri = uri.normalizePath(); String path = uri.path; var slashIndex = path.indexOf('/'); String packageName; @@ -185,12 +186,14 @@ class Packages { } } - baseUri = baseUri.normalizePath(); + //TODO: normalize path + // baseUri = baseUri.normalizePath(); List base = baseUri.pathSegments.toList(); if (base.isNotEmpty) { base = new List.from(base)..removeLast(); } - uri = uri.normalizePath(); + //TODO: normalize path + //uri = uri.normalizePath(); List target = uri.pathSegments.toList(); int index = 0; while (index < base.length && index < target.length) { From 4223760f55245869171c4b469ed1f1ce147b8c9f Mon Sep 17 00:00:00 2001 From: pquitslund Date: Wed, 13 May 2015 14:59:02 -0700 Subject: [PATCH 006/170] Backed out path normalization. --- pkgs/package_config/test/test_packagemap.dart | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/pkgs/package_config/test/test_packagemap.dart b/pkgs/package_config/test/test_packagemap.dart index bce20d4b8..2c03dba8b 100644 --- a/pkgs/package_config/test/test_packagemap.dart +++ b/pkgs/package_config/test/test_packagemap.dart @@ -72,12 +72,14 @@ main() { equals(base.resolve("../test/").resolve("bar/baz.dart"))); }); - test("dot-dot 2", () { - var packages = Packages.parse(singleRelativeSample, base); - expect(packages.packageMapping.keys.toList(), equals(["foo"])); - expect(packages.resolve(Uri.parse("package:qux/../foo/bar/baz.dart")), - equals(base.resolve("../test/").resolve("bar/baz.dart"))); - }); + +// TODO: re-enable when path normalization is in +// test("dot-dot 2", () { +// var packages = Packages.parse(singleRelativeSample, base); +// expect(packages.packageMapping.keys.toList(), equals(["foo"])); +// expect(packages.resolve(Uri.parse("package:qux/../foo/bar/baz.dart")), +// equals(base.resolve("../test/").resolve("bar/baz.dart"))); +// }); test("all valid chars", () { var packages = Packages.parse(allValidCharsSample, base); From 9abb76046d9e8143e2268ea0b82764c82fb743ba Mon Sep 17 00:00:00 2001 From: pquitslund Date: Thu, 14 May 2015 10:26:42 -0700 Subject: [PATCH 007/170] Fixed path normalization. --- pkgs/package_config/lib/packagemap.dart | 13 +++++++------ pkgs/package_config/test/test_packagemap.dart | 14 ++++++-------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/pkgs/package_config/lib/packagemap.dart b/pkgs/package_config/lib/packagemap.dart index e05c14d15..46a17970f 100644 --- a/pkgs/package_config/lib/packagemap.dart +++ b/pkgs/package_config/lib/packagemap.dart @@ -30,9 +30,8 @@ class Packages { throw new ArgumentError.value( uri, "uri", "Path must not start with '/'."); } - //TODO: re-enable // Normalizes the path by removing '.' and '..' segments. - // uri = uri.normalizePath(); + uri = _normalizePath(uri); String path = uri.path; var slashIndex = path.indexOf('/'); String packageName; @@ -52,6 +51,10 @@ class Packages { return packageLocation.resolveUri(new Uri(path: rest)); } + /// A stand in for uri.normalizePath(), coming in 1.11 + static Uri _normalizePath(Uri existingUri) => + new Uri().resolveUri(existingUri); + /// Parses a `packages.cfg` file into a `Packages` object. /// /// The [baseLocation] is used as a base URI to resolve all relative @@ -186,14 +189,12 @@ class Packages { } } - //TODO: normalize path - // baseUri = baseUri.normalizePath(); + baseUri = _normalizePath(baseUri); List base = baseUri.pathSegments.toList(); if (base.isNotEmpty) { base = new List.from(base)..removeLast(); } - //TODO: normalize path - //uri = uri.normalizePath(); + uri = _normalizePath(uri); List target = uri.pathSegments.toList(); int index = 0; while (index < base.length && index < target.length) { diff --git a/pkgs/package_config/test/test_packagemap.dart b/pkgs/package_config/test/test_packagemap.dart index 2c03dba8b..bce20d4b8 100644 --- a/pkgs/package_config/test/test_packagemap.dart +++ b/pkgs/package_config/test/test_packagemap.dart @@ -72,14 +72,12 @@ main() { equals(base.resolve("../test/").resolve("bar/baz.dart"))); }); - -// TODO: re-enable when path normalization is in -// test("dot-dot 2", () { -// var packages = Packages.parse(singleRelativeSample, base); -// expect(packages.packageMapping.keys.toList(), equals(["foo"])); -// expect(packages.resolve(Uri.parse("package:qux/../foo/bar/baz.dart")), -// equals(base.resolve("../test/").resolve("bar/baz.dart"))); -// }); + test("dot-dot 2", () { + var packages = Packages.parse(singleRelativeSample, base); + expect(packages.packageMapping.keys.toList(), equals(["foo"])); + expect(packages.resolve(Uri.parse("package:qux/../foo/bar/baz.dart")), + equals(base.resolve("../test/").resolve("bar/baz.dart"))); + }); test("all valid chars", () { var packages = Packages.parse(allValidCharsSample, base); From fd35e58cd6133de83a64803a1300e1d4d20431a1 Mon Sep 17 00:00:00 2001 From: pquitslund Date: Thu, 14 May 2015 11:06:35 -0700 Subject: [PATCH 008/170] Fixed path normalization. --- pkgs/package_config/.travis.yml | 1 + pkgs/package_config/lib/packagemap.dart | 10 +++------- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/pkgs/package_config/.travis.yml b/pkgs/package_config/.travis.yml index b1279b7e4..7a20d25b2 100644 --- a/pkgs/package_config/.travis.yml +++ b/pkgs/package_config/.travis.yml @@ -1,3 +1,4 @@ language: dart +dart: dev script: ./tool/travis.sh sudo: false diff --git a/pkgs/package_config/lib/packagemap.dart b/pkgs/package_config/lib/packagemap.dart index 46a17970f..25f27b9a2 100644 --- a/pkgs/package_config/lib/packagemap.dart +++ b/pkgs/package_config/lib/packagemap.dart @@ -31,7 +31,7 @@ class Packages { uri, "uri", "Path must not start with '/'."); } // Normalizes the path by removing '.' and '..' segments. - uri = _normalizePath(uri); + uri = uri.normalizePath(); String path = uri.path; var slashIndex = path.indexOf('/'); String packageName; @@ -51,10 +51,6 @@ class Packages { return packageLocation.resolveUri(new Uri(path: rest)); } - /// A stand in for uri.normalizePath(), coming in 1.11 - static Uri _normalizePath(Uri existingUri) => - new Uri().resolveUri(existingUri); - /// Parses a `packages.cfg` file into a `Packages` object. /// /// The [baseLocation] is used as a base URI to resolve all relative @@ -189,12 +185,12 @@ class Packages { } } - baseUri = _normalizePath(baseUri); + baseUri = baseUri.normalizePath(); List base = baseUri.pathSegments.toList(); if (base.isNotEmpty) { base = new List.from(base)..removeLast(); } - uri = _normalizePath(uri); + uri = uri.normalizePath(); List target = uri.pathSegments.toList(); int index = 0; while (index < base.length && index < target.length) { From a13bf81ef7eff8a3ad9c754e3592a09a856485fc Mon Sep 17 00:00:00 2001 From: pquitslund Date: Thu, 14 May 2015 15:26:07 -0700 Subject: [PATCH 009/170] SDK constraint bump to pickup Uri.normalizePath(). --- pkgs/package_config/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index b0f2d8fec..7494fddb9 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -5,7 +5,7 @@ author: Dart Team homepage: https://github.com/dart-lang/package_config environment: - sdk: '>=1.0.0 <2.0.0' + sdk: '>=1.11.0-dev.0.0 <2.0.0' dev_dependencies: test: '>=0.12.0 <0.13.0' From 1f27fad214f9e664b1438b3b1f555667a02edb8e Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Fri, 22 May 2015 12:43:32 +0200 Subject: [PATCH 010/170] Added .packages, packages/ discovery. Complete restructure of repository, splitting into several files. R=pquitslund@google.com Review URL: https://codereview.chromium.org//1142363005 --- pkgs/package_config/lib/discovery.dart | 160 ++++++++++++ pkgs/package_config/lib/packagemap.dart | 228 ------------------ pkgs/package_config/lib/packages.dart | 97 ++++++++ pkgs/package_config/lib/packages_file.dart | 172 +++++++++++++ .../package_config/lib/src/packages_impl.dart | 118 +++++++++ pkgs/package_config/lib/src/util.dart | 69 ++++++ pkgs/package_config/pubspec.lock | 8 + pkgs/package_config/pubspec.yaml | 5 + pkgs/package_config/test/all.dart | 4 +- .../{test_packagemap.dart => parse_test.dart} | 80 +++--- 10 files changed, 674 insertions(+), 267 deletions(-) create mode 100644 pkgs/package_config/lib/discovery.dart delete mode 100644 pkgs/package_config/lib/packagemap.dart create mode 100644 pkgs/package_config/lib/packages.dart create mode 100644 pkgs/package_config/lib/packages_file.dart create mode 100644 pkgs/package_config/lib/src/packages_impl.dart create mode 100644 pkgs/package_config/lib/src/util.dart rename pkgs/package_config/test/{test_packagemap.dart => parse_test.dart} (60%) diff --git a/pkgs/package_config/lib/discovery.dart b/pkgs/package_config/lib/discovery.dart new file mode 100644 index 000000000..78254eeba --- /dev/null +++ b/pkgs/package_config/lib/discovery.dart @@ -0,0 +1,160 @@ +// Copyright (c) 2015, 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. + +library package_config.discovery; + +import "dart:async"; +import "dart:io" show Directory, File, FileSystemEntity; +import "package:path/path.dart" as path; +import "package:http/http.dart" as http; +import "packages.dart"; +import "packages_file.dart" as pkgfile show parse; +import "src/packages_impl.dart"; + +/// Discover the package configuration for a Dart script. +/// +/// The [baseUri] points to either the Dart script or its directory. +/// A package resolution strategy is found by going through the following steps, +/// and stopping when something is found. +/// +/// * Check if a `.packages` file exists in the same directory. +/// * If `baseUri`'s scheme is not `file`, then assume a `packages` directory +/// in the same directory, and resolve packages relative to that. +/// * If `baseUri`'s scheme *is* `file`: +/// * Check if a `packages` directory exists. +/// * Otherwise check each successive parent directory of `baseUri` for a +/// `.packages` file. +/// +/// If any of these tests succeed, a `Packages` class is returned. +/// Returns the constant [noPackages] if no resolution strategy is found. +/// +/// This function currently only supports `file`, `http` and `https` URIs. +/// 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 +/// error future if loading fails for any reason. +Future findPackages( + Uri baseUri, + {Future> loader(Uri unsupportedUri)}) { + if (baseUri.scheme == "file") { + return new Future.sync(() => findPackagesFromFile(baseUri)); + } else if (baseUri.scheme == "http" || baseUri.scheme == "https") { + return findPackagesFromNonFile(baseUri, _httpGet); + } else if (loader != null) { + return findPackagesFromNonFile(baseUri, loader); + } else { + return new Future.value(Packages.noPackages); + } +} + +/// Find the location of the package resolution file/directory for a Dart file. +/// +/// Checks for a `.packages` file in the [workingDirectory]. +/// If not found, checks for a `packages` directory in the same directory. +/// If still not found, starts checking parent directories for +/// `.packages` until reaching the root directory. +/// +/// Returns a [File] object of a `.packages` file if one is found, or a +/// [Directory] object for the `packages/` directory if that is found. +FileSystemEntity _findPackagesFile(String workingDirectory) { + var dir = new Directory(workingDirectory); + if (!dir.isAbsolute) dir = dir.absolute; + if (!dir.existsSync()) { + throw new ArgumentError.value( + workingDirectory, "workingDirectory", "Directory does not exist."); + } + File checkForConfigFile(Directory directory) { + assert(directory.isAbsolute); + var file = new File(path.join(directory.path, ".packages")); + if (file.existsSync()) return file; + return null; + } + // Check for $cwd/.packages + var packagesCfgFile = checkForConfigFile(dir); + if (packagesCfgFile != null) return packagesCfgFile; + // Check for $cwd/packages/ + var packagesDir = new Directory(path.join(dir.path, "packages")); + if (packagesDir.existsSync()) return packagesDir; + // Check for cwd(/..)+/.packages + var parentDir = dir.parent; + while (parentDir.path != dir.path) { + packagesCfgFile = checkForConfigFile(parentDir); + if (packagesCfgFile != null) break; + dir = parentDir; + parentDir = dir.parent; + } + return packagesCfgFile; +} + +/// Finds a package resolution strategy for a local Dart script. +/// +/// The [fileBaseUri] points to either a Dart script or the directory of the +/// script. The `fileBaseUri` must be a `file:` URI. +/// +/// This function first tries to locate a `.packages` file in the `fileBaseUri` +/// directory. If that is not found, it instead checks for the presence of +/// a `packages/` directory in the same place. +/// If that also fails, it starts checking parent directories for a `.packages` +/// file, and stops if it finds it. +/// Otherwise it gives up and returns [Pacakges.noPackages]. +Packages findPackagesFromFile(Uri fileBaseUri) { + Uri baseDirectoryUri = fileBaseUri; + if (!fileBaseUri.path.endsWith('/')) { + baseDirectoryUri = baseDirectoryUri.resolve("."); + } + String baseDirectoryPath = baseDirectoryUri.toFilePath(); + FileSystemEntity location = _findPackagesFile(baseDirectoryPath); + if (location == null) return Packages.noPackages; + if (location is File) { + List fileBytes = location.readAsBytesSync(); + Map map = pkgfile.parse(fileBytes, + new Uri.file(location.path)); + return new MapPackages(map); + } + assert(location is Directory); + return new FilePackagesDirectoryPackages(location); +} + +/// Finds a package resolution strategy for a Dart script. +/// +/// The [nonFileUri] points to either a Dart script or the directory of the +/// script. +/// The [nonFileUri] should not be a `file:` URI since the algorithm for +/// finding a package resolution strategy is more elaborate for `file:` URIs. +/// In that case, use [findPackagesFile]. +/// +/// This function first tries to locate a `.packages` file in the [nonFileUri] +/// directory. If that is not found, it instead assumes a `packages/` directory +/// in the same place. +/// +/// By default, this function only works for `http:` and `https:` URIs. +/// To support other schemes, a loader must be provided, which is used to +/// try to load the `.packages` file. The loader should return the contents +/// of the requestsed `.packages` file as bytes, which will be assumed to be +/// UTF-8 encoded. +Future findPackagesFromNonFile(Uri nonFileUri, + [Future> loader(Uri name)]) { + if (loader == null) loader = _httpGet; + Uri packagesFileUri = nonFileUri.resolve(".packages"); + return loader(packagesFileUri).then((List fileBytes) { + Map map = pkgfile.parse(fileBytes, packagesFileUri); + return new MapPackages(map); + }, onError: (_) { + // Didn't manage to load ".packages". Assume a "packages/" directory. + Uri packagesDirectoryUri = nonFileUri.resolve("packages/"); + return new NonFilePackagesDirectoryPackages(packagesDirectoryUri); + }); +} + +/// Fetches a file using the http library. +Future> _httpGet(Uri uri) { + return http.get(uri).then((http.Response response) { + if (response.statusCode == 200) return response.bodyBytes; + throw 0; // The error message isn't being used for anything. + }); +} diff --git a/pkgs/package_config/lib/packagemap.dart b/pkgs/package_config/lib/packagemap.dart deleted file mode 100644 index 25f27b9a2..000000000 --- a/pkgs/package_config/lib/packagemap.dart +++ /dev/null @@ -1,228 +0,0 @@ -// Copyright (c) 2015, 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. - -library package_config.packagemap; - -class Packages { - static const int _EQUALS = 0x3d; - static const int _CR = 0x0d; - static const int _NL = 0x0a; - static const int _NUMBER_SIGN = 0x23; - - final Map packageMapping; - - Packages(this.packageMapping); - - /// Resolves a URI to a non-package URI. - /// - /// If [uri] is a `package:` URI, the location is resolved wrt. the - /// [packageMapping]. - /// Otherwise the original URI is returned. - Uri resolve(Uri uri) { - if (uri.scheme.toLowerCase() != "package") { - return uri; - } - if (uri.hasAuthority) { - throw new ArgumentError.value(uri, "uri", "Must not have authority"); - } - if (uri.path.startsWith("/")) { - throw new ArgumentError.value( - uri, "uri", "Path must not start with '/'."); - } - // Normalizes the path by removing '.' and '..' segments. - uri = uri.normalizePath(); - String path = uri.path; - var slashIndex = path.indexOf('/'); - String packageName; - String rest; - if (slashIndex < 0) { - packageName = path; - rest = ""; - } else { - packageName = path.substring(0, slashIndex); - rest = path.substring(slashIndex + 1); - } - Uri packageLocation = packageMapping[packageName]; - if (packageLocation == null) { - throw new ArgumentError.value( - uri, "uri", "Unknown package name: $packageName"); - } - return packageLocation.resolveUri(new Uri(path: rest)); - } - - /// Parses a `packages.cfg` file into a `Packages` object. - /// - /// The [baseLocation] is used as a base URI to resolve all relative - /// URI references against. - /// - /// The `Packages` object allows resolving package: URIs and writing - /// the mapping back to a file or string. - /// The [packageMapping] will contain a simple mapping from package name - /// to package location. - static Packages parse(String source, Uri baseLocation) { - int index = 0; - Map result = {}; - while (index < source.length) { - bool isComment = false; - int start = index; - int eqIndex = -1; - int end = source.length; - int char = source.codeUnitAt(index++); - if (char == _CR || char == _NL) { - continue; - } - if (char == _EQUALS) { - throw new FormatException("Missing package name", source, index - 1); - } - isComment = char == _NUMBER_SIGN; - while (index < source.length) { - char = source.codeUnitAt(index++); - if (char == _EQUALS && eqIndex < 0) { - eqIndex = index - 1; - } else if (char == _NL || char == _CR) { - end = index - 1; - break; - } - } - if (isComment) continue; - if (eqIndex < 0) { - throw new FormatException("No '=' on line", source, index - 1); - } - _checkIdentifier(source, start, eqIndex); - var packageName = source.substring(start, eqIndex); - - var packageLocation = Uri.parse(source, eqIndex + 1, end); - if (!packageLocation.path.endsWith('/')) { - packageLocation = - packageLocation.replace(path: packageLocation.path + "/"); - } - packageLocation = baseLocation.resolveUri(packageLocation); - if (result.containsKey(packageName)) { - throw new FormatException( - "Same package name occured twice.", source, start); - } - result[packageName] = packageLocation; - } - return new Packages(result); - } - - /** - * Writes the mapping to a [StringSink]. - * - * If [comment] is provided, the output will contain this comment - * with `#` in front of each line. - * - * If [baseUri] is provided, package locations will be made relative - * to the base URI, if possible, before writing. - */ - void write(StringSink output, {Uri baseUri, String comment}) { - if (baseUri != null && !baseUri.isAbsolute) { - throw new ArgumentError.value(baseUri, "baseUri", "Must be absolute"); - } - - if (comment != null) { - for (var commentLine in comment.split('\n')) { - output.write('#'); - output.writeln(commentLine); - } - } else { - output.write("# generated by package:packagecfg at "); - output.write(new DateTime.now()); - output.writeln(); - } - - packageMapping.forEach((String packageName, Uri uri) { - // Validate packageName. - _checkIdentifier(packageName, 0, packageName.length); - output.write(packageName); - - output.write('='); - - // If baseUri provided, make uri relative. - if (baseUri != null) { - uri = relativize(uri, baseUri); - } - output.write(uri); - if (!uri.path.endsWith('/')) { - output.write('/'); - } - output.writeln(); - }); - } - - String toString() { - StringBuffer buffer = new StringBuffer(); - write(buffer); - return buffer.toString(); - } - - static Uri relativize(Uri uri, Uri baseUri) { - if (uri.hasQuery || uri.hasFragment) { - uri = new Uri( - scheme: uri.scheme, - userInfo: uri.hasAuthority ? uri.userInfo : null, - host: uri.hasAuthority ? uri.host : null, - port: uri.hasAuthority ? uri.port : null, - path: uri.path); - } - if (!baseUri.isAbsolute) { - throw new ArgumentError("Base uri '$baseUri' must be absolute."); - } - // Already relative. - if (!uri.isAbsolute) return uri; - - if (baseUri.scheme.toLowerCase() != uri.scheme.toLowerCase()) { - return uri; - } - // If authority differs, we could remove the scheme, but it's not worth it. - if (uri.hasAuthority != baseUri.hasAuthority) return uri; - if (uri.hasAuthority) { - if (uri.userInfo != baseUri.userInfo || - uri.host.toLowerCase() != baseUri.host.toLowerCase() || - uri.port != baseUri.port) { - return uri; - } - } - - baseUri = baseUri.normalizePath(); - List base = baseUri.pathSegments.toList(); - if (base.isNotEmpty) { - base = new List.from(base)..removeLast(); - } - uri = uri.normalizePath(); - List target = uri.pathSegments.toList(); - int index = 0; - while (index < base.length && index < target.length) { - if (base[index] != target[index]) { - break; - } - index++; - } - if (index == base.length) { - return new Uri(path: target.skip(index).join('/')); - } else if (index > 0) { - return new Uri( - path: '../' * (base.length - index) + target.skip(index).join('/')); - } else { - return uri; - } - } - - static bool _checkIdentifier(String string, int start, int end) { - const int a = 0x61; - const int z = 0x7a; - const int _ = 0x5f; - const int $ = 0x24; - if (start == end) return false; - for (int i = start; i < end; i++) { - var char = string.codeUnitAt(i); - if (char == _ || char == $) continue; - if ((char ^ 0x30) <= 9 && i > 0) continue; - char |= 0x20; // Lower-case letters. - if (char >= a && char <= z) continue; - throw new FormatException("Not an identifier", string, i); - } - return true; - } -} diff --git a/pkgs/package_config/lib/packages.dart b/pkgs/package_config/lib/packages.dart new file mode 100644 index 000000000..8523ecc28 --- /dev/null +++ b/pkgs/package_config/lib/packages.dart @@ -0,0 +1,97 @@ +// Copyright (c) 2015, 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. + +library package_config.packages; + +import "dart:async" show Future; +import "discovery.dart" show findPackages; +import "src/packages_impl.dart"; + +/// A package resolution strategy. +/// +/// Allows converting a `package:` URI to a different kind of URI. +/// +/// May also allow listing the available packages and converting +/// to a `Map` that gives the base location of each available +/// package. In some cases there is no way to find the available packages, +/// in which case [packages] and [asMap] will throw if used. +/// One such case is if the packages are resolved relative to a +/// `packages/` directory available over HTTP. +abstract class Packages { + + /// A [Packages] resolver containing no packages. + /// + /// This constant object is returned by [find] above if no + /// package resolution strategy is found. + static const Packages noPackages = const NoPackages(); + + /// Create a `Packages` object based on a map from package name to base URI. + /// + /// The resulting `Packages` object will resolve package URIs by using this + /// map. + /// There is no validation of the map containing only valid package names, + factory Packages(Map packageMapping) => + new MapPackages(packageMapping); + + /// Attempts to find a package resolution strategy for a Dart script. + /// + /// The [baseLocation] should point to a Dart script or to its directory. + /// The function goes through the following steps in order to search for + /// a packages resolution strategy: + /// + /// * First check if a `.packages` file in the script's directory. + /// If a file is found, its content is loaded and interpreted as a map + /// from package names to package location URIs. + /// If loading or parsing of the file fails, so does this function. + /// * Then if `baseLocation` is not a `file:` URI, + /// assume that a `packages/` directory exists in the script's directory, + /// and return a `Packages` object that resolves package URIs as + /// paths into that directory. + /// * If `baseLocation` is a `file:` URI, instead *check* whether + /// a `packages/` directory exists in the script directory. + /// If it does, return a `Packages` object that resolves package URIs + /// as paths into that directory. This `Packages` object is able to + /// read the directory and see which packages are available. + /// * Otherwise, check each directory in the parent path of `baseLocation` + /// for the existence of a `.packages` file. If one is found, it is loaded + /// just as in the first step. + /// * If no file is found before reaching the file system root, + /// the constant [noPacakages] is returned. It's a `Packages` object + /// with no available packages. + /// + static Future find(Uri baseLocation) => findPackages(baseLocation); + + /// Resolve a package URI into a non-package URI. + /// + /// Translates a `package:` URI, according to the package resolution + /// strategy, into a URI that can be loaded. + /// By default, only `file`, `http` and `https` URIs are returned. + /// Custom `Packages` objects may return other URIs. + /// + /// If resolution fails because a package with the requested package name + /// is not available, the [notFound] function is called. + /// If no `notFound` function is provided, it defaults to throwing an error. + /// + /// The [packageUri] must be a valid package URI. + Uri resolve(Uri packageUri, {Uri notFound(Uri packageUri)}); + + /// Return the names of the available packages. + /// + /// Returns an iterable that allows iterating the names of available packages. + /// + /// Some `Packages` objects are unable to find the package names, + /// and getting `packages` from such a `Packages` object will throw. + Iterable get packages; + + /// Return the names-to-base-URI mapping of the available packages. + /// + /// Returns a map from package name to a base URI. + /// The [resolve] method will resolve a package URI with a specific package + /// name to a path extending the base URI that this map gives for that + /// package name. + /// + /// Some `Packages` objects are unable to find the package names, + /// and calling `asMap` on such a `Packages` object will throw. + Map asMap(); +} diff --git a/pkgs/package_config/lib/packages_file.dart b/pkgs/package_config/lib/packages_file.dart new file mode 100644 index 000000000..48c2334e0 --- /dev/null +++ b/pkgs/package_config/lib/packages_file.dart @@ -0,0 +1,172 @@ +// Copyright (c) 2015, 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. + +library package_config.packages_file; + +import "package:charcode/ascii.dart"; +import "src/util.dart" show isIdentifier; + +/// Parses a `.packages` file into a map from package name to base URI. +/// +/// The [source] is the byte content of a `.packages` file, assumed to be +/// UTF-8 encoded. In practice, all sinficant parts of the file must be ASCII, +/// so Latin-1 or Windows-1252 encoding will also work fine. +/// +/// If the file content is available as a string, its [String.codeUnits] can +/// be used as the `source` argument of this function. +/// +/// The [baseLocation] is used as a base URI to resolve all relative +/// URI references against. +/// If the content was read from a file, `baseLocation` should be the +/// location of that file. +/// +/// Returns a simple mapping from package name to package location. +Map parse(List source, Uri baseLocation) { + int index = 0; + Map result = {}; + while (index < source.length) { + bool isComment = false; + int start = index; + int eqIndex = -1; + int end = source.length; + int char = source[index++]; + if (char == $cr || char == $lf) { + continue; + } + if (char == $equal) { + throw new FormatException("Missing package name", source, index - 1); + } + isComment = char == $hash; + while (index < source.length) { + char = source[index++]; + if (char == $equal && eqIndex < 0) { + eqIndex = index - 1; + } else if (char == $cr || char == $lf) { + end = index - 1; + break; + } + } + if (isComment) continue; + if (eqIndex < 0) { + throw new FormatException("No '=' on line", source, index - 1); + } + var packageName = new String.fromCharCodes(source, start, eqIndex); + if (!isIdentifier(packageName)) { + throw new FormatException("Not a valid package name", packageName, 0); + } + var packageUri = new String.fromCharCodes(source, eqIndex + 1, end); + var packageLocation = Uri.parse(packageUri); + if (!packageLocation.path.endsWith('/')) { + packageLocation = + packageLocation.replace(path: packageLocation.path + "/"); + } + packageLocation = baseLocation.resolveUri(packageLocation); + if (result.containsKey(packageName)) { + throw new FormatException( + "Same package name occured twice.", source, start); + } + result[packageName] = packageLocation; + } + return result; +} + +/// Writes the mapping to a [StringSink]. +/// +/// If [comment] is provided, the output will contain this comment +/// with `#` in front of each line. +/// +/// If [baseUri] is provided, package locations will be made relative +/// to the base URI, if possible, before writing. +void write(StringSink output, Map packageMapping, + {Uri baseUri, String comment}) { + if (baseUri != null && !baseUri.isAbsolute) { + throw new ArgumentError.value(baseUri, "baseUri", "Must be absolute"); + } + + if (comment != null) { + for (var commentLine in comment.split('\n')) { + output.write('#'); + output.writeln(commentLine); + } + } else { + output.write("# generated by package:package_config at "); + output.write(new DateTime.now()); + output.writeln(); + } + + packageMapping.forEach((String packageName, Uri uri) { + // Validate packageName. + if (!isIdentifier(packageName)) { + throw new ArgumentError('"$packageName" is not a valid package name'); + } + output.write(packageName); + output.write('='); + // If baseUri provided, make uri relative. + if (baseUri != null) { + uri = _relativize(uri, baseUri); + } + output.write(uri); + if (!uri.path.endsWith('/')) { + output.write('/'); + } + output.writeln(); + }); +} + +/// Attempts to return a relative URI for [uri]. +/// +/// The result URI satisfies `baseUri.resolveUri(result) == uri`, +/// but may be relative. +/// The `baseUri` must be absolute. +Uri _relativize(Uri uri, Uri baseUri) { + assert(!baseUri.isAbsolute); + if (uri.hasQuery || uri.hasFragment) { + uri = new Uri( + scheme: uri.scheme, + userInfo: uri.hasAuthority ? uri.userInfo : null, + host: uri.hasAuthority ? uri.host : null, + port: uri.hasAuthority ? uri.port : null, + path: uri.path); + } + + // Already relative. We assume the caller knows what they are doing. + if (!uri.isAbsolute) return uri; + + if (baseUri.scheme != uri.scheme) { + return uri; + } + + // If authority differs, we could remove the scheme, but it's not worth it. + if (uri.hasAuthority != baseUri.hasAuthority) return uri; + if (uri.hasAuthority) { + if (uri.userInfo != baseUri.userInfo || + uri.host.toLowerCase() != baseUri.host.toLowerCase() || + uri.port != baseUri.port) { + return uri; + } + } + + baseUri = baseUri.normalizePath(); + List base = baseUri.pathSegments.toList(); + if (base.isNotEmpty) { + base = new List.from(base)..removeLast(); + } + uri = uri.normalizePath(); + List target = uri.pathSegments.toList(); + int index = 0; + while (index < base.length && index < target.length) { + if (base[index] != target[index]) { + break; + } + index++; + } + if (index == base.length) { + return new Uri(path: target.skip(index).join('/')); + } else if (index > 0) { + return new Uri( + path: '../' * (base.length - index) + target.skip(index).join('/')); + } else { + return uri; + } +} diff --git a/pkgs/package_config/lib/src/packages_impl.dart b/pkgs/package_config/lib/src/packages_impl.dart new file mode 100644 index 000000000..612dc347d --- /dev/null +++ b/pkgs/package_config/lib/src/packages_impl.dart @@ -0,0 +1,118 @@ +// Copyright (c) 2015, 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. + +library package_config.packages_impl; + +import "dart:collection" show UnmodifiableMapView; +import "dart:io" show Directory; +import "package:path/path.dart" as path; +import "../packages.dart"; +import "util.dart" show checkValidPackageUri; + +/// A [Packages] null-object. +class NoPackages implements Packages { + const NoPackages(); + + Uri resolve(Uri packageUri, {Uri notFound(Uri packageUri)}) { + String packageName = checkValidPackageUri(packageUri); + if (notFound != null) return notFound(packageUri); + throw new ArgumentError.value(packageUri, "packageUri", + 'No package named "$packageName"'); + } + + Iterable get packages => new Iterable.empty(); + + Map asMap() => const{}; +} + + +/// Base class for [Packages] implementations. +/// +/// This class implements the [resolve] method in terms of a private +/// member +abstract class _PackagesBase implements Packages { + Uri resolve(Uri packageUri, {Uri notFound(Uri packageUri)}) { + packageUri = packageUri.normalizePath(); + String packageName = checkValidPackageUri(packageUri); + Uri packageBase = _getBase(packageName); + if (packageBase == null) { + if (notFound != null) return notFound(packageUri); + throw new ArgumentError.value(packageUri, "packageUri", + 'No package named "$packageName"'); + } + String packagePath = packageUri.path.substring(packageName.length + 1); + return packageBase.resolve(packagePath); + } + + /// Find a base location for a package name. + /// + /// Returns `null` if no package exists with that name, and that can be + /// determined. + Uri _getBase(String packageName); +} + +/// A [Packages] implementation based on an existing map. +class MapPackages extends _PackagesBase { + final Map _mapping; + MapPackages(this._mapping); + + Uri _getBase(String packageName) => _mapping[packageName]; + + Iterable get packages => _mapping.keys; + + Map asMap() => new UnmodifiableMapView(_mapping); +} + +/// A [Packages] implementation based on a local directory. +class FilePackagesDirectoryPackages extends _PackagesBase { + final Directory _packageDir; + FilePackagesDirectoryPackages(this._packageDir); + + Uri _getBase(String packageName) => + new Uri.directory(path.join(packageName,'')); + + Iterable _listPackageNames() { + return _packageDir.listSync() + .where((e) => e is Directory) + .map((e) => path.basename(e.path)); + } + + Iterable get packages { + return _listPackageNames(); + } + + Map asMap() { + var result = {}; + for (var packageName in _listPackageNames()) { + result[packageName] = _getBase(packageName); + } + return new UnmodifiableMapView(result); + } +} + +/// A [Packages] implementation based on a remote (e.g., HTTP) directory. +/// +/// There is no way to detect which packages exist short of trying to use +/// them. You can't necessarily check whether a directory exists, +/// except by checking for a know file in the directory. +class NonFilePackagesDirectoryPackages extends _PackagesBase { + final Uri _packageBase; + NonFilePackagesDirectoryPackages(this._packageBase); + + Uri _getBase(String packageName) => _packageBase.resolve("$packageName/"); + + Error _failListingPackages() { + return new UnsupportedError( + "Cannot list packages for a ${_packageBase.scheme}: " + "based package root"); + } + + Iterable get packages { + throw _failListingPackages(); + } + + Map asMap() { + throw _failListingPackages(); + } +} diff --git a/pkgs/package_config/lib/src/util.dart b/pkgs/package_config/lib/src/util.dart new file mode 100644 index 000000000..76bd1d6e5 --- /dev/null +++ b/pkgs/package_config/lib/src/util.dart @@ -0,0 +1,69 @@ +// Copyright (c) 2015, 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. + +/// Utility methods used by more than one library in the package. +library package_config.util; + +import "package:charcode/ascii.dart"; + +/// Tests whether something is a valid Dart identifier/package name. +bool isIdentifier(String string) { + if (string.isEmpty) return false; + int firstChar = string.codeUnitAt(0); + int firstCharLower = firstChar |= 0x20; + if (firstCharLower < $a || firstCharLower > $z) { + if (firstChar != $_ && firstChar != $$) return false; + } + for (int i = 1; i < string.length; i++) { + int char = string.codeUnitAt(i); + int charLower = char | 0x20; + if (charLower < $a || charLower > $z) { // Letters. + if ((char ^ 0x30) <= 9) continue; // Digits. + if (char == $_ || char == $$) continue; // $ and _ + if (firstChar != $_ && firstChar != $$) return false; + } + } + return true; +} + + +/// Validate that a Uri is a valid package:URI. +String checkValidPackageUri(Uri packageUri) { + if (packageUri.scheme != "package") { + throw new ArgumentError.value(packageUri, "packageUri", + "Not a package: URI"); + } + if (packageUri.hasAuthority) { + throw new ArgumentError.value(packageUri, "packageUri", + "Package URIs must not have a host part"); + } + if (packageUri.hasQuery) { + // A query makes no sense if resolved to a file: URI. + throw new ArgumentError.value(packageUri, "packageUri", + "Package URIs must not have a query part"); + } + if (packageUri.hasFragment) { + // We could leave the fragment after the URL when resolving, + // but it would be odd if "package:foo/foo.dart#1" and + // "package:foo/foo.dart#2" were considered different libraries. + // Keep the syntax open in case we ever get multiple libraries in one file. + throw new ArgumentError.value(packageUri, "packageUri", + "Package URIs must not have a fragment part"); + } + if (packageUri.path.startsWith('/')) { + throw new ArgumentError.value(packageUri, "packageUri", + "Package URIs must not start with a '/'"); + } + int firstSlash = packageUri.path.indexOf('/'); + if (firstSlash == -1) { + throw new ArgumentError.value(packageUri, "packageUri", + "Package URIs must start with the package name followed by a '/'"); + } + String packageName = packageUri.path.substring(0, firstSlash); + if (!isIdentifier(packageName)) { + throw new ArgumentError.value(packageUri, "packageUri", + "Package names must be valid identifiers"); + } + return packageName; +} diff --git a/pkgs/package_config/pubspec.lock b/pkgs/package_config/pubspec.lock index 197d32ed6..708d89157 100644 --- a/pkgs/package_config/pubspec.lock +++ b/pkgs/package_config/pubspec.lock @@ -13,6 +13,10 @@ packages: description: barback source: hosted version: "0.15.2+4" + charcode: + description: charcode + source: hosted + version: "1.1.0" collection: description: collection source: hosted @@ -21,6 +25,10 @@ packages: description: crypto source: hosted version: "0.9.0" + http: + description: http + source: hosted + version: "0.11.2" http_parser: description: http_parser source: hosted diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 7494fddb9..27af78ecd 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -7,5 +7,10 @@ homepage: https://github.com/dart-lang/package_config environment: sdk: '>=1.11.0-dev.0.0 <2.0.0' +dependencies: + charcode: '^1.1.0' + path: "any" + http: "any" + dev_dependencies: test: '>=0.12.0 <0.13.0' diff --git a/pkgs/package_config/test/all.dart b/pkgs/package_config/test/all.dart index 795289cdf..310e1ee43 100644 --- a/pkgs/package_config/test/all.dart +++ b/pkgs/package_config/test/all.dart @@ -2,8 +2,8 @@ // 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. -import 'test_packagemap.dart' as packagemap; +import 'parse_test.dart' as parse; main() { - packagemap.main(); + parse.main(); } diff --git a/pkgs/package_config/test/test_packagemap.dart b/pkgs/package_config/test/parse_test.dart similarity index 60% rename from pkgs/package_config/test/test_packagemap.dart rename to pkgs/package_config/test/parse_test.dart index bce20d4b8..f7f68f10d 100644 --- a/pkgs/package_config/test/test_packagemap.dart +++ b/pkgs/package_config/test/parse_test.dart @@ -4,61 +4,62 @@ library test_all; -import "package:package_config/packagemap.dart"; +import "package:package_config/packages.dart"; +import "package:package_config/packages_file.dart" show parse; import "package:test/test.dart"; main() { var base = Uri.parse("file:///one/two/three/packages.map"); test("empty", () { - var packages = Packages.parse(emptySample, base); - expect(packages.packageMapping, isEmpty); + var packages = doParse(emptySample, base); + expect(packages.asMap(), isEmpty); }); test("comment only", () { - var packages = Packages.parse(commentOnlySample, base); - expect(packages.packageMapping, isEmpty); + var packages = doParse(commentOnlySample, base); + expect(packages.asMap(), isEmpty); }); test("empty lines only", () { - var packages = Packages.parse(emptyLinesSample, base); - expect(packages.packageMapping, isEmpty); + var packages = doParse(emptyLinesSample, base); + expect(packages.asMap(), isEmpty); }); test("empty lines only", () { - var packages = Packages.parse(emptyLinesSample, base); - expect(packages.packageMapping, isEmpty); + var packages = doParse(emptyLinesSample, base); + expect(packages.asMap(), isEmpty); }); test("single", () { - var packages = Packages.parse(singleRelativeSample, base); - expect(packages.packageMapping.keys.toList(), equals(["foo"])); + var packages = doParse(singleRelativeSample, base); + expect(packages.packages.toList(), equals(["foo"])); expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), equals(base.resolve("../test/").resolve("bar/baz.dart"))); }); test("single no slash", () { - var packages = Packages.parse(singleRelativeSampleNoSlash, base); - expect(packages.packageMapping.keys.toList(), equals(["foo"])); + var packages = doParse(singleRelativeSampleNoSlash, base); + expect(packages.packages.toList(), equals(["foo"])); expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), equals(base.resolve("../test/").resolve("bar/baz.dart"))); }); test("single no newline", () { - var packages = Packages.parse(singleRelativeSampleNoNewline, base); - expect(packages.packageMapping.keys.toList(), equals(["foo"])); + var packages = doParse(singleRelativeSampleNoNewline, base); + expect(packages.packages.toList(), equals(["foo"])); expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), equals(base.resolve("../test/").resolve("bar/baz.dart"))); }); test("single absolute", () { - var packages = Packages.parse(singleAbsoluteSample, base); - expect(packages.packageMapping.keys.toList(), equals(["foo"])); + var packages = doParse(singleAbsoluteSample, base); + expect(packages.packages.toList(), equals(["foo"])); expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), equals(Uri.parse("http://example.com/some/where/bar/baz.dart"))); }); test("multiple", () { - var packages = Packages.parse(multiRelativeSample, base); + var packages = doParse(multiRelativeSample, base); expect( - packages.packageMapping.keys.toList()..sort(), equals(["bar", "foo"])); + packages.packages.toList()..sort(), equals(["bar", "foo"])); expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), equals(base.resolve("../test/").resolve("bar/baz.dart"))); expect(packages.resolve(Uri.parse("package:bar/foo/baz.dart")), @@ -66,51 +67,51 @@ main() { }); test("dot-dot 1", () { - var packages = Packages.parse(singleRelativeSample, base); - expect(packages.packageMapping.keys.toList(), equals(["foo"])); + var packages = doParse(singleRelativeSample, base); + expect(packages.packages.toList(), equals(["foo"])); expect(packages.resolve(Uri.parse("package:foo/qux/../bar/baz.dart")), equals(base.resolve("../test/").resolve("bar/baz.dart"))); }); test("dot-dot 2", () { - var packages = Packages.parse(singleRelativeSample, base); - expect(packages.packageMapping.keys.toList(), equals(["foo"])); + var packages = doParse(singleRelativeSample, base); + expect(packages.packages.toList(), equals(["foo"])); expect(packages.resolve(Uri.parse("package:qux/../foo/bar/baz.dart")), equals(base.resolve("../test/").resolve("bar/baz.dart"))); }); test("all valid chars", () { - var packages = Packages.parse(allValidCharsSample, base); - expect(packages.packageMapping.keys.toList(), equals([allValidChars])); + var packages = doParse(allValidCharsSample, base); + expect(packages.packages.toList(), equals([allValidChars])); expect(packages.resolve(Uri.parse("package:$allValidChars/bar/baz.dart")), equals(base.resolve("../test/").resolve("bar/baz.dart"))); }); test("no escapes", () { - expect(() => Packages.parse("x%41x=x", base), throws); + expect(() => doParse("x%41x=x", base), throws); }); test("not identifiers", () { - expect(() => Packages.parse("1x=x", base), throws); - expect(() => Packages.parse(" x=x", base), throws); - expect(() => Packages.parse("\\x41x=x", base), throws); - expect(() => Packages.parse("x@x=x", base), throws); - expect(() => Packages.parse("x[x=x", base), throws); - expect(() => Packages.parse("x`x=x", base), throws); - expect(() => Packages.parse("x{x=x", base), throws); - expect(() => Packages.parse("x/x=x", base), throws); - expect(() => Packages.parse("x:x=x", base), throws); + expect(() => doParse("1x=x", base), throws); + expect(() => doParse(" x=x", base), throws); + expect(() => doParse("\\x41x=x", base), throws); + expect(() => doParse("x@x=x", base), throws); + expect(() => doParse("x[x=x", base), throws); + expect(() => doParse("x`x=x", base), throws); + expect(() => doParse("x{x=x", base), throws); + expect(() => doParse("x/x=x", base), throws); + expect(() => doParse("x:x=x", base), throws); }); test("same name twice", () { - expect(() => Packages.parse(singleRelativeSample * 2, base), throws); + expect(() => doParse(singleRelativeSample * 2, base), throws); }); for (String invalidSample in invalid) { test("invalid '$invalidSample'", () { var result; try { - result = Packages.parse(invalidSample, base); + result = doParse(invalidSample, base); } on FormatException { // expected return; @@ -120,6 +121,11 @@ main() { } } +Packages doParse(String sample, Uri baseUri) { + Map map = parse(sample.codeUnits, baseUri); + return new Packages(map); +} + // Valid samples. var emptySample = ""; var commentOnlySample = "# comment only\n"; From 2cb76b9e3c719b789acfdff9cefcea6b63425855 Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Tue, 26 May 2015 11:26:32 +0200 Subject: [PATCH 011/170] Add more tests Review URL: https://codereview.chromium.org//1152173005 --- pkgs/package_config/lib/discovery.dart | 6 +- .../package_config/lib/src/packages_impl.dart | 2 +- pkgs/package_config/test/all.dart | 4 +- pkgs/package_config/test/discovery_test.dart | 281 ++++++++++++++++++ 4 files changed, 288 insertions(+), 5 deletions(-) create mode 100644 pkgs/package_config/test/discovery_test.dart diff --git a/pkgs/package_config/lib/discovery.dart b/pkgs/package_config/lib/discovery.dart index 78254eeba..52f208d81 100644 --- a/pkgs/package_config/lib/discovery.dart +++ b/pkgs/package_config/lib/discovery.dart @@ -44,9 +44,9 @@ Future findPackages( if (baseUri.scheme == "file") { return new Future.sync(() => findPackagesFromFile(baseUri)); } else if (baseUri.scheme == "http" || baseUri.scheme == "https") { - return findPackagesFromNonFile(baseUri, _httpGet); + return findPackagesFromNonFile(baseUri, loader: _httpGet); } else if (loader != null) { - return findPackagesFromNonFile(baseUri, loader); + return findPackagesFromNonFile(baseUri, loader: loader); } else { return new Future.value(Packages.noPackages); } @@ -138,7 +138,7 @@ Packages findPackagesFromFile(Uri fileBaseUri) { /// of the requestsed `.packages` file as bytes, which will be assumed to be /// UTF-8 encoded. Future findPackagesFromNonFile(Uri nonFileUri, - [Future> loader(Uri name)]) { + {Future> loader(Uri name)}) { if (loader == null) loader = _httpGet; Uri packagesFileUri = nonFileUri.resolve(".packages"); return loader(packagesFileUri).then((List fileBytes) { diff --git a/pkgs/package_config/lib/src/packages_impl.dart b/pkgs/package_config/lib/src/packages_impl.dart index 612dc347d..956376275 100644 --- a/pkgs/package_config/lib/src/packages_impl.dart +++ b/pkgs/package_config/lib/src/packages_impl.dart @@ -70,7 +70,7 @@ class FilePackagesDirectoryPackages extends _PackagesBase { FilePackagesDirectoryPackages(this._packageDir); Uri _getBase(String packageName) => - new Uri.directory(path.join(packageName,'')); + new Uri.directory(path.join(_packageDir.path, packageName, '')); Iterable _listPackageNames() { return _packageDir.listSync() diff --git a/pkgs/package_config/test/all.dart b/pkgs/package_config/test/all.dart index 310e1ee43..79f5b3574 100644 --- a/pkgs/package_config/test/all.dart +++ b/pkgs/package_config/test/all.dart @@ -2,8 +2,10 @@ // 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. -import 'parse_test.dart' as parse; +import "discovery_test.dart" as discovery; +import "parse_test.dart" as parse; main() { parse.main(); + discovery.main(); } diff --git a/pkgs/package_config/test/discovery_test.dart b/pkgs/package_config/test/discovery_test.dart new file mode 100644 index 000000000..4a88928e2 --- /dev/null +++ b/pkgs/package_config/test/discovery_test.dart @@ -0,0 +1,281 @@ +// Copyright (c) 2015, 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. + +import "dart:async"; +import "dart:io"; +import "package:test/test.dart"; +import "package:package_config/packages.dart"; +import "package:package_config/discovery.dart"; +import "package:path/path.dart" as path; + +const packagesFile = """ +# A comment +foo=file:///dart/packages/foo/ +bar=http://example.com/dart/packages/bar/ +baz=packages/baz/ +"""; + +void validatePackagesFile(Packages resolver, Uri location) { + expect(resolver, isNotNull); + expect(resolver.resolve(pkg("foo", "bar/baz")), + equals(Uri.parse("file:///dart/packages/foo/bar/baz"))); + expect(resolver.resolve(pkg("bar", "baz/qux")), + equals(Uri.parse("http://example.com/dart/packages/bar/baz/qux"))); + expect(resolver.resolve(pkg("baz", "qux/foo")), + equals(location.resolve("packages/baz/qux/foo"))); + expect(resolver.packages, unorderedEquals(["foo", "bar", "baz"])); +} + +void validatePackagesDir(Packages resolver, Uri location) { + // Expect three packages: foo, bar and baz + expect(resolver, isNotNull); + expect(resolver.resolve(pkg("foo", "bar/baz")), + equals(location.resolve("packages/foo/bar/baz"))); + expect(resolver.resolve(pkg("bar", "baz/qux")), + equals(location.resolve("packages/bar/baz/qux"))); + expect(resolver.resolve(pkg("baz", "qux/foo")), + equals(location.resolve("packages/baz/qux/foo"))); + if (location.scheme == "file") { + expect(resolver.packages, unorderedEquals(["foo", "bar", "baz"])); + } else { + expect(() => resolver.packages, throws); + } +} + + +Uri pkg(String packageName, String packagePath) { + var path; + if (packagePath.startsWith('/')) { + path = "$packageName$packagePath"; + } else { + path = "$packageName/$packagePath"; + } + return new Uri(scheme: "package", path: path); +} + +main() { + generalTest(".packages", + {".packages": packagesFile, + "script.dart": "main(){}", + "packages": {"shouldNotBeFound": {}}}, + (Uri location) async { + Packages resolver; + resolver = await findPackages(location); + validatePackagesFile(resolver, location); + resolver = await findPackages(location.resolve("script.dart")); + validatePackagesFile(resolver, location); + var specificDiscovery = (location.scheme == "file") + ? findPackagesFromFile + : findPackagesFromNonFile; + resolver = await specificDiscovery(location); + validatePackagesFile(resolver, location); + resolver = await specificDiscovery(location.resolve("script.dart")); + validatePackagesFile(resolver, location); + }); + + generalTest("packages/", + {"packages": { "foo": {}, "bar": {}, "baz": {}}, + "script.dart": "main(){}"}, + (Uri location) async { + Packages resolver; + bool isFile = (location.scheme == "file"); + resolver = await findPackages(location); + validatePackagesDir(resolver, location); + resolver = await findPackages(location.resolve("script.dart")); + validatePackagesDir(resolver, location); + var specificDiscovery = isFile + ? findPackagesFromFile + : findPackagesFromNonFile; + resolver = await specificDiscovery(location); + validatePackagesDir(resolver, location); + resolver = await specificDiscovery(location.resolve("script.dart")); + validatePackagesDir(resolver, location); + }); + + fileTest(".packages recursive", + {".packages": packagesFile, "subdir": {"script.dart": "main(){}"}}, + (Uri location) async { + Packages resolver; + resolver = await findPackages(location.resolve("subdir/")); + validatePackagesFile(resolver, location); + resolver = await findPackages(location.resolve("subdir/script.dart")); + validatePackagesFile(resolver, location); + resolver = await findPackagesFromFile(location.resolve("subdir/")); + validatePackagesFile(resolver, location); + resolver = + await findPackagesFromFile(location.resolve("subdir/script.dart")); + validatePackagesFile(resolver, location); + }); + + httpTest(".packages not recursive", + {".packages": packagesFile, "subdir": {"script.dart": "main(){}"}}, + (Uri location) async { + Packages resolver; + var subdir = location.resolve("subdir/"); + resolver = await findPackages(subdir); + validatePackagesDir(resolver, subdir); + resolver = await findPackages(subdir.resolve("script.dart")); + validatePackagesDir(resolver, subdir); + resolver = await findPackagesFromNonFile(subdir); + validatePackagesDir(resolver, subdir); + resolver = await findPackagesFromNonFile(subdir.resolve("script.dart")); + validatePackagesDir(resolver, subdir); + }); + + fileTest("no packages", + {"script.dart": "main(){}"}, + (Uri location) async { + // A file: location with no .packages or packages returns + // Packages.noPackages. + Packages resolver; + resolver = await findPackages(location); + expect(resolver, same(Packages.noPackages)); + resolver = await findPackages(location.resolve("script.dart")); + expect(resolver, same(Packages.noPackages)); + resolver = findPackagesFromFile(location); + expect(resolver, same(Packages.noPackages)); + resolver = findPackagesFromFile(location.resolve("script.dart")); + expect(resolver, same(Packages.noPackages)); + }); + + httpTest("no packages", + {"script.dart": "main(){}"}, + (Uri location) async { + // A non-file: location with no .packages or packages/: + // Assumes a packages dir exists, and resolves relative to that. + Packages resolver; + resolver = await findPackages(location); + validatePackagesDir(resolver, location); + resolver = await findPackages(location.resolve("script.dart")); + validatePackagesDir(resolver, location); + resolver = await findPackagesFromNonFile(location); + validatePackagesDir(resolver, location); + resolver = await findPackagesFromNonFile(location.resolve("script.dart")); + validatePackagesDir(resolver, location); + }); + + test(".packages w/ loader", () async { + Uri location = Uri.parse("krutch://example.com/path/"); + Future loader(Uri file) async { + if (file.path.endsWith(".packages")) { + return packagesFile.codeUnits; + } + throw "not found"; + } + // A non-file: location with no .packages or packages/: + // Assumes a packages dir exists, and resolves relative to that. + Packages resolver; + resolver = await findPackages(location, loader: loader); + validatePackagesFile(resolver, location); + resolver = await findPackages(location.resolve("script.dart"), + loader: loader); + validatePackagesFile(resolver, location); + resolver = await findPackagesFromNonFile(location, loader: loader); + validatePackagesFile(resolver, location); + resolver = await findPackagesFromNonFile(location.resolve("script.dart"), + loader: loader); + validatePackagesFile(resolver, location); + }); + + test("no packages w/ loader", () async { + Uri location = Uri.parse("krutch://example.com/path/"); + Future loader(Uri file) async { + throw "not found"; + } + // A non-file: location with no .packages or packages/: + // Assumes a packages dir exists, and resolves relative to that. + Packages resolver; + resolver = await findPackages(location, loader: loader); + validatePackagesDir(resolver, location); + resolver = await findPackages(location.resolve("script.dart"), + loader: loader); + validatePackagesDir(resolver, location); + resolver = await findPackagesFromNonFile(location, loader: loader); + validatePackagesDir(resolver, location); + resolver = await findPackagesFromNonFile(location.resolve("script.dart"), + loader:loader); + validatePackagesDir(resolver, location); + }); +} + +/// Create a directory structure from [description] and run [fileTest]. +/// +/// Description is a map, each key is a file entry. If the value is a map, +/// it's a sub-dir, otherwise it's a file and the value is the content +/// as a string. +void fileTest(String name, + Map description, + Future fileTest(Uri directory)) { + group("file-test", () { + Directory tempDir = Directory.systemTemp.createTempSync("file-test"); + setUp(() { + _createFiles(tempDir, description); + }); + tearDown(() { + tempDir.deleteSync(recursive: true); + }); + test(name, () => fileTest(new Uri.directory(tempDir.path))); + }); +} + +/// HTTP-server the directory structure from [description] and run [htpTest]. +/// +/// Description is a map, each key is a file entry. If the value is a map, +/// it's a sub-dir, otherwise it's a file and the value is the content +/// as a string. +void httpTest(String name, Map description, Future httpTest(Uri directory)) { + group("http-test", () { + var serverSub; + var uri; + setUp(() { + return HttpServer + .bind(InternetAddress.LOOPBACK_IP_V4, 0) + .then((server) { + uri = new Uri(scheme: "http", + host: "127.0.0.1", + port: server.port, + path: "/"); + serverSub = server.listen((HttpRequest request) { + // No error handling. + var path = request.uri.path; + if (path.startsWith('/')) path = path.substring(1); + if (path.endsWith('/')) path = path.substring(0, path.length - 1); + var parts = path.split('/'); + var fileOrDir = description; + for (int i = 0; i < parts.length; i++) { + fileOrDir = fileOrDir[parts[i]]; + if (fileOrDir == null) { + request.response.statusCode = 404; + request.response.close(); + } + } + request.response.write(fileOrDir); + request.response.close(); + }); + }); + }); + tearDown(() => serverSub.cancel()); + test(name, () => httpTest(uri)); + }); +} + +void generalTest(String name, Map description, Future action(Uri location)) { + fileTest(name, description, action); + httpTest(name, description, action); +} + +void _createFiles(Directory target, Map description) { + description.forEach((name, content) { + if (content is Map) { + Directory subDir = new Directory(path.join(target.path, name)); + subDir.createSync(); + _createFiles(subDir, content); + } else { + File file = new File(path.join(target.path, name)); + file.writeAsStringSync(content, flush: true); + } + }); +} + + From f3bbc021c17b6b70a2d772d5976c9a76e1be7438 Mon Sep 17 00:00:00 2001 From: Phil Quitslund Date: Tue, 26 May 2015 12:48:53 -0700 Subject: [PATCH 012/170] Badge update. (Fix dart-lang/package_config#7.) --- pkgs/package_config/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/package_config/README.md b/pkgs/package_config/README.md index 140c3c4f9..1437e31c1 100644 --- a/pkgs/package_config/README.md +++ b/pkgs/package_config/README.md @@ -4,7 +4,7 @@ Support for working with **Package Resolution Configuration** files as described in this [DEP](https://github.com/lrhn/dep-pkgspec/blob/master/DEP-pkgspec.md), under review [here] (https://github.com/dart-lang/dart_enhancement_proposals/issues/5). -[![Build Status](https://travis-ci.org/dart-lang/package_config.svg)](https://travis-ci.org/dart-lang/linter) +[![Build Status](https://travis-ci.org/dart-lang/package_config.svg)](https://travis-ci.org/dart-lang/package_config) ## Features and bugs From 45aa4d5882b64c3b5b2602c50fd17eda39f25e9b Mon Sep 17 00:00:00 2001 From: Phil Quitslund Date: Tue, 26 May 2015 12:50:09 -0700 Subject: [PATCH 013/170] Travis badge teak (point to master). --- pkgs/package_config/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkgs/package_config/README.md b/pkgs/package_config/README.md index 1437e31c1..42ae1e99b 100644 --- a/pkgs/package_config/README.md +++ b/pkgs/package_config/README.md @@ -4,8 +4,7 @@ Support for working with **Package Resolution Configuration** files as described in this [DEP](https://github.com/lrhn/dep-pkgspec/blob/master/DEP-pkgspec.md), under review [here] (https://github.com/dart-lang/dart_enhancement_proposals/issues/5). -[![Build Status](https://travis-ci.org/dart-lang/package_config.svg)](https://travis-ci.org/dart-lang/package_config) - +[![Build Status](https://travis-ci.org/dart-lang/package_config.svg?branch=master)](https://travis-ci.org/dart-lang/package_config) ## Features and bugs From 3c2c5f5434f021d98c0524eaaa2c435ba8693700 Mon Sep 17 00:00:00 2001 From: Phil Quitslund Date: Wed, 27 May 2015 12:46:11 -0700 Subject: [PATCH 014/170] Update travis.sh --- pkgs/package_config/tool/travis.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/package_config/tool/travis.sh b/pkgs/package_config/tool/travis.sh index 82423816b..6d8cfe375 100755 --- a/pkgs/package_config/tool/travis.sh +++ b/pkgs/package_config/tool/travis.sh @@ -9,7 +9,7 @@ set -e # Verify that the libraries are error free. dartanalyzer --fatal-warnings \ - lib/packagemap.dart \ + lib/packages.dart \ test/all.dart # Run the tests. From 385d634284979e23f127b376c190fc5463cce761 Mon Sep 17 00:00:00 2001 From: Phil Quitslund Date: Wed, 27 May 2015 13:01:50 -0700 Subject: [PATCH 015/170] Build fix. [TBR] (Fix dart-lang/package_config#9) --- pkgs/package_config/lib/src/packages_impl.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/package_config/lib/src/packages_impl.dart b/pkgs/package_config/lib/src/packages_impl.dart index 956376275..6d88a65a0 100644 --- a/pkgs/package_config/lib/src/packages_impl.dart +++ b/pkgs/package_config/lib/src/packages_impl.dart @@ -21,7 +21,7 @@ class NoPackages implements Packages { 'No package named "$packageName"'); } - Iterable get packages => new Iterable.empty(); + Iterable get packages => new Iterable.generate(0); Map asMap() => const{}; } From fd1d37d5ba2e444804436148025fe814824f124c Mon Sep 17 00:00:00 2001 From: Phil Quitslund Date: Thu, 28 May 2015 10:00:52 -0700 Subject: [PATCH 016/170] Version bump. Bump to tag package discovery logic. --- pkgs/package_config/pubspec.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 27af78ecd..36daf6f84 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 0.0.1 +version: 0.0.2 description: Support for working with Package Resolution config files. author: Dart Team homepage: https://github.com/dart-lang/package_config @@ -9,8 +9,8 @@ environment: dependencies: charcode: '^1.1.0' - path: "any" - http: "any" + path: 'any' + http: 'any' dev_dependencies: test: '>=0.12.0 <0.13.0' From 860fa65be9122e4c2e73f11437ef21968726a26a Mon Sep 17 00:00:00 2001 From: Phil Quitslund Date: Thu, 28 May 2015 10:09:50 -0700 Subject: [PATCH 017/170] Constraint cleanup. --- pkgs/package_config/pubspec.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 36daf6f84..0efb23f22 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -9,8 +9,8 @@ environment: dependencies: charcode: '^1.1.0' - path: 'any' - http: 'any' + http: '^0.11.2' + path: '>=1.0.0 <2.0.0' dev_dependencies: test: '>=0.12.0 <0.13.0' From 2e49f23243aba94882c4ecce75ca6aaadfe4daa8 Mon Sep 17 00:00:00 2001 From: Phil Quitslund Date: Thu, 28 May 2015 10:55:08 -0700 Subject: [PATCH 018/170] Package badge. --- pkgs/package_config/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/package_config/README.md b/pkgs/package_config/README.md index 42ae1e99b..9a0995d6b 100644 --- a/pkgs/package_config/README.md +++ b/pkgs/package_config/README.md @@ -4,7 +4,7 @@ Support for working with **Package Resolution Configuration** files as described in this [DEP](https://github.com/lrhn/dep-pkgspec/blob/master/DEP-pkgspec.md), under review [here] (https://github.com/dart-lang/dart_enhancement_proposals/issues/5). -[![Build Status](https://travis-ci.org/dart-lang/package_config.svg?branch=master)](https://travis-ci.org/dart-lang/package_config) +[![Build Status](https://travis-ci.org/dart-lang/package_config.svg?branch=master)](https://travis-ci.org/dart-lang/package_config) [![pub package](http://img.shields.io/pub/v/package_config.svg)](https://pub.dartlang.org/packages/package_config) ## Features and bugs From 58cc2fe7943ad73cd61d323b02e3198715dfe994 Mon Sep 17 00:00:00 2001 From: Phil Quitslund Date: Thu, 28 May 2015 13:06:55 -0700 Subject: [PATCH 019/170] Widen http version constraint. (Required for constraint solving in the SDK build.) --- pkgs/package_config/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 0efb23f22..4a3123e6d 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -9,7 +9,7 @@ environment: dependencies: charcode: '^1.1.0' - http: '^0.11.2' + http: '^0.11.0' path: '>=1.0.0 <2.0.0' dev_dependencies: From f04393798e722151745e8cf2f3126e20531f8bd4 Mon Sep 17 00:00:00 2001 From: Phil Quitslund Date: Thu, 28 May 2015 13:08:20 -0700 Subject: [PATCH 020/170] Update pubspec.yaml --- pkgs/package_config/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 4a3123e6d..5bda6ffae 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 0.0.2 +version: 0.0.2+1 description: Support for working with Package Resolution config files. author: Dart Team homepage: https://github.com/dart-lang/package_config From ffabb77477e3f6cf27c8e0af354a01a7f6a3b7e0 Mon Sep 17 00:00:00 2001 From: pq Date: Thu, 28 May 2015 13:36:25 -0700 Subject: [PATCH 021/170] Inline normalizePath to make observatory happy. --- pkgs/package_config/lib/packages_file.dart | 7 +++++-- pkgs/package_config/lib/src/packages_impl.dart | 5 ++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/pkgs/package_config/lib/packages_file.dart b/pkgs/package_config/lib/packages_file.dart index 48c2334e0..03b37b649 100644 --- a/pkgs/package_config/lib/packages_file.dart +++ b/pkgs/package_config/lib/packages_file.dart @@ -147,12 +147,12 @@ Uri _relativize(Uri uri, Uri baseUri) { } } - baseUri = baseUri.normalizePath(); + baseUri = _normalizePath(baseUri); List base = baseUri.pathSegments.toList(); if (base.isNotEmpty) { base = new List.from(base)..removeLast(); } - uri = uri.normalizePath(); + uri = _normalizePath(uri); List target = uri.pathSegments.toList(); int index = 0; while (index < base.length && index < target.length) { @@ -170,3 +170,6 @@ Uri _relativize(Uri uri, Uri baseUri) { return uri; } } + +// TODO: inline to uri.normalizePath() when we move to 1.11 +Uri _normalizePath(Uri uri) => new Uri().resolveUri(uri); diff --git a/pkgs/package_config/lib/src/packages_impl.dart b/pkgs/package_config/lib/src/packages_impl.dart index 6d88a65a0..880b9db1f 100644 --- a/pkgs/package_config/lib/src/packages_impl.dart +++ b/pkgs/package_config/lib/src/packages_impl.dart @@ -33,7 +33,7 @@ class NoPackages implements Packages { /// member abstract class _PackagesBase implements Packages { Uri resolve(Uri packageUri, {Uri notFound(Uri packageUri)}) { - packageUri = packageUri.normalizePath(); + packageUri = _normalizePath(packageUri); String packageName = checkValidPackageUri(packageUri); Uri packageBase = _getBase(packageName); if (packageBase == null) { @@ -50,6 +50,9 @@ abstract class _PackagesBase implements Packages { /// Returns `null` if no package exists with that name, and that can be /// determined. Uri _getBase(String packageName); + + // TODO: inline to uri.normalizePath() when we move to 1.11 + static Uri _normalizePath(Uri uri) => new Uri().resolveUri(uri); } /// A [Packages] implementation based on an existing map. From a7722c1554c8208f6896feb4046340e98d109061 Mon Sep 17 00:00:00 2001 From: pq Date: Thu, 28 May 2015 13:38:18 -0700 Subject: [PATCH 022/170] Version bump. --- pkgs/package_config/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 5bda6ffae..20494b9f6 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 0.0.2+1 +version: 0.0.2+2 description: Support for working with Package Resolution config files. author: Dart Team homepage: https://github.com/dart-lang/package_config From de64d3dd23f9ff40b4d165d9c984ddb45dfd6ab0 Mon Sep 17 00:00:00 2001 From: Harry Terkelsen Date: Thu, 28 May 2015 15:58:43 -0700 Subject: [PATCH 023/170] Don't use Uri.directory --- pkgs/package_config/lib/discovery.dart | 4 ++-- pkgs/package_config/lib/packages.dart | 2 +- pkgs/package_config/lib/packages_file.dart | 2 +- pkgs/package_config/lib/src/packages_impl.dart | 6 +++--- pkgs/package_config/pubspec.yaml | 2 +- pkgs/package_config/test/discovery_test.dart | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pkgs/package_config/lib/discovery.dart b/pkgs/package_config/lib/discovery.dart index 52f208d81..f298a0afe 100644 --- a/pkgs/package_config/lib/discovery.dart +++ b/pkgs/package_config/lib/discovery.dart @@ -101,7 +101,7 @@ FileSystemEntity _findPackagesFile(String workingDirectory) { /// a `packages/` directory in the same place. /// If that also fails, it starts checking parent directories for a `.packages` /// file, and stops if it finds it. -/// Otherwise it gives up and returns [Pacakges.noPackages]. +/// Otherwise it gives up and returns [Packages.noPackages]. Packages findPackagesFromFile(Uri fileBaseUri) { Uri baseDirectoryUri = fileBaseUri; if (!fileBaseUri.path.endsWith('/')) { @@ -135,7 +135,7 @@ Packages findPackagesFromFile(Uri fileBaseUri) { /// By default, this function only works for `http:` and `https:` URIs. /// To support other schemes, a loader must be provided, which is used to /// try to load the `.packages` file. The loader should return the contents -/// of the requestsed `.packages` file as bytes, which will be assumed to be +/// of the requested `.packages` file as bytes, which will be assumed to be /// UTF-8 encoded. Future findPackagesFromNonFile(Uri nonFileUri, {Future> loader(Uri name)}) { diff --git a/pkgs/package_config/lib/packages.dart b/pkgs/package_config/lib/packages.dart index 8523ecc28..3fba062f5 100644 --- a/pkgs/package_config/lib/packages.dart +++ b/pkgs/package_config/lib/packages.dart @@ -57,7 +57,7 @@ abstract class Packages { /// for the existence of a `.packages` file. If one is found, it is loaded /// just as in the first step. /// * If no file is found before reaching the file system root, - /// the constant [noPacakages] is returned. It's a `Packages` object + /// the constant [noPackages] is returned. It's a `Packages` object /// with no available packages. /// static Future find(Uri baseLocation) => findPackages(baseLocation); diff --git a/pkgs/package_config/lib/packages_file.dart b/pkgs/package_config/lib/packages_file.dart index 03b37b649..2228cb3f0 100644 --- a/pkgs/package_config/lib/packages_file.dart +++ b/pkgs/package_config/lib/packages_file.dart @@ -10,7 +10,7 @@ import "src/util.dart" show isIdentifier; /// Parses a `.packages` file into a map from package name to base URI. /// /// The [source] is the byte content of a `.packages` file, assumed to be -/// UTF-8 encoded. In practice, all sinficant parts of the file must be ASCII, +/// UTF-8 encoded. In practice, all significant parts of the file must be ASCII, /// so Latin-1 or Windows-1252 encoding will also work fine. /// /// If the file content is available as a string, its [String.codeUnits] can diff --git a/pkgs/package_config/lib/src/packages_impl.dart b/pkgs/package_config/lib/src/packages_impl.dart index 880b9db1f..645d76525 100644 --- a/pkgs/package_config/lib/src/packages_impl.dart +++ b/pkgs/package_config/lib/src/packages_impl.dart @@ -50,9 +50,9 @@ abstract class _PackagesBase implements Packages { /// Returns `null` if no package exists with that name, and that can be /// determined. Uri _getBase(String packageName); - + // TODO: inline to uri.normalizePath() when we move to 1.11 - static Uri _normalizePath(Uri uri) => new Uri().resolveUri(uri); + static Uri _normalizePath(Uri uri) => new Uri().resolveUri(uri); } /// A [Packages] implementation based on an existing map. @@ -73,7 +73,7 @@ class FilePackagesDirectoryPackages extends _PackagesBase { FilePackagesDirectoryPackages(this._packageDir); Uri _getBase(String packageName) => - new Uri.directory(path.join(_packageDir.path, packageName, '')); + new Uri.file(path.join(_packageDir.path, packageName, '.')); Iterable _listPackageNames() { return _packageDir.listSync() diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 20494b9f6..2a84d20c4 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 0.0.2+2 +version: 0.0.2+3 description: Support for working with Package Resolution config files. author: Dart Team homepage: https://github.com/dart-lang/package_config diff --git a/pkgs/package_config/test/discovery_test.dart b/pkgs/package_config/test/discovery_test.dart index 4a88928e2..16bdd267b 100644 --- a/pkgs/package_config/test/discovery_test.dart +++ b/pkgs/package_config/test/discovery_test.dart @@ -215,7 +215,7 @@ void fileTest(String name, tearDown(() { tempDir.deleteSync(recursive: true); }); - test(name, () => fileTest(new Uri.directory(tempDir.path))); + test(name, () => fileTest(new Uri.file(path.join(tempDir.path, ".")))); }); } From 95ebf31911fe8621cddbd3d504535f7c77c04eb3 Mon Sep 17 00:00:00 2001 From: Harry Terkelsen Date: Thu, 28 May 2015 18:04:07 -0700 Subject: [PATCH 024/170] Allow "_" as the first char in a package name --- pkgs/package_config/lib/src/util.dart | 2 +- pkgs/package_config/test/discovery_test.dart | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/pkgs/package_config/lib/src/util.dart b/pkgs/package_config/lib/src/util.dart index 76bd1d6e5..abf1d52f0 100644 --- a/pkgs/package_config/lib/src/util.dart +++ b/pkgs/package_config/lib/src/util.dart @@ -11,7 +11,7 @@ import "package:charcode/ascii.dart"; bool isIdentifier(String string) { if (string.isEmpty) return false; int firstChar = string.codeUnitAt(0); - int firstCharLower = firstChar |= 0x20; + int firstCharLower = firstChar | 0x20; if (firstCharLower < $a || firstCharLower > $z) { if (firstChar != $_ && firstChar != $$) return false; } diff --git a/pkgs/package_config/test/discovery_test.dart b/pkgs/package_config/test/discovery_test.dart index 16bdd267b..16544e43d 100644 --- a/pkgs/package_config/test/discovery_test.dart +++ b/pkgs/package_config/test/discovery_test.dart @@ -93,6 +93,14 @@ main() { validatePackagesDir(resolver, location); }); + generalTest("underscore packages", + {"packages": {"_foo": {}}}, + (Uri location) async { + Packages resolver = await findPackages(location); + expect(resolver.resolve(pkg("_foo", "foo.dart")), + equals(location.resolve("packages/_foo/foo.dart"))); + }); + fileTest(".packages recursive", {".packages": packagesFile, "subdir": {"script.dart": "main(){}"}}, (Uri location) async { From 8fee1b417ab070010ca15dd619cc462a01443f53 Mon Sep 17 00:00:00 2001 From: Harry Terkelsen Date: Fri, 29 May 2015 09:58:04 -0700 Subject: [PATCH 025/170] Bump version to 0.0.2+4 --- pkgs/package_config/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 2a84d20c4..aca9c836c 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 0.0.2+3 +version: 0.0.2+4 description: Support for working with Package Resolution config files. author: Dart Team homepage: https://github.com/dart-lang/package_config From 8de7c1064f9f124d520479f2a8be6b64507d399b Mon Sep 17 00:00:00 2001 From: Harry Terkelsen Date: Fri, 29 May 2015 09:58:04 -0700 Subject: [PATCH 026/170] Separate out VM dependencies. The Packages interface class should not depend on a platform specific library (dart:io). This removed the dependency, and also splits the implementation classes into those that are generally applicable and those that requite dart:io to operate (the "local packages directory" which allows iterating the package names by scanning the directory). Bump version to 0.0.2+4 --- pkgs/package_config/lib/discovery.dart | 1 + pkgs/package_config/lib/packages.dart | 38 --------------- .../package_config/lib/src/packages_impl.dart | 47 ++++--------------- .../lib/src/packages_io_impl.dart | 37 +++++++++++++++ pkgs/package_config/pubspec.yaml | 2 +- pkgs/package_config/test/parse_test.dart | 3 +- 6 files changed, 51 insertions(+), 77 deletions(-) create mode 100644 pkgs/package_config/lib/src/packages_io_impl.dart diff --git a/pkgs/package_config/lib/discovery.dart b/pkgs/package_config/lib/discovery.dart index f298a0afe..f8e45d491 100644 --- a/pkgs/package_config/lib/discovery.dart +++ b/pkgs/package_config/lib/discovery.dart @@ -11,6 +11,7 @@ import "package:http/http.dart" as http; import "packages.dart"; import "packages_file.dart" as pkgfile show parse; import "src/packages_impl.dart"; +import "src/packages_io_impl.dart"; /// Discover the package configuration for a Dart script. /// diff --git a/pkgs/package_config/lib/packages.dart b/pkgs/package_config/lib/packages.dart index 3fba062f5..dbaa06dfd 100644 --- a/pkgs/package_config/lib/packages.dart +++ b/pkgs/package_config/lib/packages.dart @@ -4,8 +4,6 @@ library package_config.packages; -import "dart:async" show Future; -import "discovery.dart" show findPackages; import "src/packages_impl.dart"; /// A package resolution strategy. @@ -26,42 +24,6 @@ abstract class Packages { /// package resolution strategy is found. static const Packages noPackages = const NoPackages(); - /// Create a `Packages` object based on a map from package name to base URI. - /// - /// The resulting `Packages` object will resolve package URIs by using this - /// map. - /// There is no validation of the map containing only valid package names, - factory Packages(Map packageMapping) => - new MapPackages(packageMapping); - - /// Attempts to find a package resolution strategy for a Dart script. - /// - /// The [baseLocation] should point to a Dart script or to its directory. - /// The function goes through the following steps in order to search for - /// a packages resolution strategy: - /// - /// * First check if a `.packages` file in the script's directory. - /// If a file is found, its content is loaded and interpreted as a map - /// from package names to package location URIs. - /// If loading or parsing of the file fails, so does this function. - /// * Then if `baseLocation` is not a `file:` URI, - /// assume that a `packages/` directory exists in the script's directory, - /// and return a `Packages` object that resolves package URIs as - /// paths into that directory. - /// * If `baseLocation` is a `file:` URI, instead *check* whether - /// a `packages/` directory exists in the script directory. - /// If it does, return a `Packages` object that resolves package URIs - /// as paths into that directory. This `Packages` object is able to - /// read the directory and see which packages are available. - /// * Otherwise, check each directory in the parent path of `baseLocation` - /// for the existence of a `.packages` file. If one is found, it is loaded - /// just as in the first step. - /// * If no file is found before reaching the file system root, - /// the constant [noPackages] is returned. It's a `Packages` object - /// with no available packages. - /// - static Future find(Uri baseLocation) => findPackages(baseLocation); - /// Resolve a package URI into a non-package URI. /// /// Translates a `package:` URI, according to the package resolution diff --git a/pkgs/package_config/lib/src/packages_impl.dart b/pkgs/package_config/lib/src/packages_impl.dart index 645d76525..e85f75581 100644 --- a/pkgs/package_config/lib/src/packages_impl.dart +++ b/pkgs/package_config/lib/src/packages_impl.dart @@ -2,11 +2,12 @@ // 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. +/// Implementations of [Packages] that may be used in either server or browser +/// based applications. For implementations that can only run in the browser, +/// see [package_config.packages_io_impl]. library package_config.packages_impl; import "dart:collection" show UnmodifiableMapView; -import "dart:io" show Directory; -import "package:path/path.dart" as path; import "../packages.dart"; import "util.dart" show checkValidPackageUri; @@ -26,16 +27,15 @@ class NoPackages implements Packages { Map asMap() => const{}; } - /// Base class for [Packages] implementations. /// /// This class implements the [resolve] method in terms of a private /// member -abstract class _PackagesBase implements Packages { +abstract class PackagesBase implements Packages { Uri resolve(Uri packageUri, {Uri notFound(Uri packageUri)}) { packageUri = _normalizePath(packageUri); String packageName = checkValidPackageUri(packageUri); - Uri packageBase = _getBase(packageName); + Uri packageBase = getBase(packageName); if (packageBase == null) { if (notFound != null) return notFound(packageUri); throw new ArgumentError.value(packageUri, "packageUri", @@ -49,61 +49,34 @@ abstract class _PackagesBase implements Packages { /// /// Returns `null` if no package exists with that name, and that can be /// determined. - Uri _getBase(String packageName); + Uri getBase(String packageName); // TODO: inline to uri.normalizePath() when we move to 1.11 static Uri _normalizePath(Uri uri) => new Uri().resolveUri(uri); } /// A [Packages] implementation based on an existing map. -class MapPackages extends _PackagesBase { +class MapPackages extends PackagesBase { final Map _mapping; MapPackages(this._mapping); - Uri _getBase(String packageName) => _mapping[packageName]; + Uri getBase(String packageName) => _mapping[packageName]; Iterable get packages => _mapping.keys; Map asMap() => new UnmodifiableMapView(_mapping); } -/// A [Packages] implementation based on a local directory. -class FilePackagesDirectoryPackages extends _PackagesBase { - final Directory _packageDir; - FilePackagesDirectoryPackages(this._packageDir); - - Uri _getBase(String packageName) => - new Uri.file(path.join(_packageDir.path, packageName, '.')); - - Iterable _listPackageNames() { - return _packageDir.listSync() - .where((e) => e is Directory) - .map((e) => path.basename(e.path)); - } - - Iterable get packages { - return _listPackageNames(); - } - - Map asMap() { - var result = {}; - for (var packageName in _listPackageNames()) { - result[packageName] = _getBase(packageName); - } - return new UnmodifiableMapView(result); - } -} - /// A [Packages] implementation based on a remote (e.g., HTTP) directory. /// /// There is no way to detect which packages exist short of trying to use /// them. You can't necessarily check whether a directory exists, /// except by checking for a know file in the directory. -class NonFilePackagesDirectoryPackages extends _PackagesBase { +class NonFilePackagesDirectoryPackages extends PackagesBase { final Uri _packageBase; NonFilePackagesDirectoryPackages(this._packageBase); - Uri _getBase(String packageName) => _packageBase.resolve("$packageName/"); + Uri getBase(String packageName) => _packageBase.resolve("$packageName/"); Error _failListingPackages() { return new UnsupportedError( diff --git a/pkgs/package_config/lib/src/packages_io_impl.dart b/pkgs/package_config/lib/src/packages_io_impl.dart new file mode 100644 index 000000000..21b61fdab --- /dev/null +++ b/pkgs/package_config/lib/src/packages_io_impl.dart @@ -0,0 +1,37 @@ +// Copyright (c) 2015, 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. + +/// Implementations of [Packages] that can only be used in server based +/// applications. +library package_config.packages_io_impl; + +import "dart:collection" show UnmodifiableMapView; +import "dart:io" show Directory; +import "package:path/path.dart" as path; +import "packages_impl.dart"; + +/// A [Packages] implementation based on a local directory. +class FilePackagesDirectoryPackages extends PackagesBase { + final Directory _packageDir; + FilePackagesDirectoryPackages(this._packageDir); + + Uri getBase(String packageName) => + new Uri.file(path.join(_packageDir.path, packageName, '.')); + + Iterable _listPackageNames() { + return _packageDir.listSync() + .where((e) => e is Directory) + .map((e) => path.basename(e.path)); + } + + Iterable get packages => _listPackageNames(); + + Map asMap() { + var result = {}; + for (var packageName in _listPackageNames()) { + result[packageName] = getBase(packageName); + } + return new UnmodifiableMapView(result); + } +} diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index aca9c836c..338aab5bf 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 0.0.2+4 +version: 0.0.3 description: Support for working with Package Resolution config files. author: Dart Team homepage: https://github.com/dart-lang/package_config diff --git a/pkgs/package_config/test/parse_test.dart b/pkgs/package_config/test/parse_test.dart index f7f68f10d..ddd8ff6ca 100644 --- a/pkgs/package_config/test/parse_test.dart +++ b/pkgs/package_config/test/parse_test.dart @@ -6,6 +6,7 @@ library test_all; import "package:package_config/packages.dart"; import "package:package_config/packages_file.dart" show parse; +import "package:package_config/src/packages_impl.dart"; import "package:test/test.dart"; main() { @@ -123,7 +124,7 @@ main() { Packages doParse(String sample, Uri baseUri) { Map map = parse(sample.codeUnits, baseUri); - return new Packages(map); + return new MapPackages(map); } // Valid samples. From b3a31b68e0b61e0546f2448ec34f2118305b91d8 Mon Sep 17 00:00:00 2001 From: Harry Terkelsen Date: Thu, 4 Jun 2015 13:50:22 -0700 Subject: [PATCH 027/170] Remove dependency on http package BUG= Review URL: https://codereview.appspot.com/243950044 --- pkgs/package_config/lib/discovery.dart | 42 +++++++++++++++++++------- pkgs/package_config/pubspec.lock | 4 --- pkgs/package_config/pubspec.yaml | 3 +- 3 files changed, 32 insertions(+), 17 deletions(-) diff --git a/pkgs/package_config/lib/discovery.dart b/pkgs/package_config/lib/discovery.dart index f8e45d491..0dd7f5508 100644 --- a/pkgs/package_config/lib/discovery.dart +++ b/pkgs/package_config/lib/discovery.dart @@ -5,9 +5,11 @@ library package_config.discovery; import "dart:async"; -import "dart:io" show Directory, File, FileSystemEntity; +import "dart:io"; +import "dart:typed_data" show Uint8List; + import "package:path/path.dart" as path; -import "package:http/http.dart" as http; + import "packages.dart"; import "packages_file.dart" as pkgfile show parse; import "src/packages_impl.dart"; @@ -39,8 +41,7 @@ import "src/packages_io_impl.dart"; /// 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 /// error future if loading fails for any reason. -Future findPackages( - Uri baseUri, +Future findPackages(Uri baseUri, {Future> loader(Uri unsupportedUri)}) { if (baseUri.scheme == "file") { return new Future.sync(() => findPackagesFromFile(baseUri)); @@ -113,8 +114,8 @@ Packages findPackagesFromFile(Uri fileBaseUri) { if (location == null) return Packages.noPackages; if (location is File) { List fileBytes = location.readAsBytesSync(); - Map map = pkgfile.parse(fileBytes, - new Uri.file(location.path)); + Map map = + pkgfile.parse(fileBytes, new Uri.file(location.path)); return new MapPackages(map); } assert(location is Directory); @@ -139,7 +140,7 @@ Packages findPackagesFromFile(Uri fileBaseUri) { /// of the requested `.packages` file as bytes, which will be assumed to be /// UTF-8 encoded. Future findPackagesFromNonFile(Uri nonFileUri, - {Future> loader(Uri name)}) { + {Future> loader(Uri name)}) { if (loader == null) loader = _httpGet; Uri packagesFileUri = nonFileUri.resolve(".packages"); return loader(packagesFileUri).then((List fileBytes) { @@ -152,10 +153,29 @@ Future findPackagesFromNonFile(Uri nonFileUri, }); } -/// Fetches a file using the http library. +/// Fetches a file over http. Future> _httpGet(Uri uri) { - return http.get(uri).then((http.Response response) { - if (response.statusCode == 200) return response.bodyBytes; - throw 0; // The error message isn't being used for anything. + 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> splitContent) { + int totalLength = splitContent.fold(0, (int old, List list) { + return old + list.length; + }); + Uint8List result = new Uint8List(totalLength); + int offset = 0; + for (List contentPart in splitContent) { + result.setRange(offset, offset + contentPart.length, contentPart); + offset += contentPart.length; + } + return result; }); } diff --git a/pkgs/package_config/pubspec.lock b/pkgs/package_config/pubspec.lock index 708d89157..5cae00509 100644 --- a/pkgs/package_config/pubspec.lock +++ b/pkgs/package_config/pubspec.lock @@ -25,10 +25,6 @@ packages: description: crypto source: hosted version: "0.9.0" - http: - description: http - source: hosted - version: "0.11.2" http_parser: description: http_parser source: hosted diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 338aab5bf..5eca33065 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 0.0.3 +version: 0.0.3+1 description: Support for working with Package Resolution config files. author: Dart Team homepage: https://github.com/dart-lang/package_config @@ -9,7 +9,6 @@ environment: dependencies: charcode: '^1.1.0' - http: '^0.11.0' path: '>=1.0.0 <2.0.0' dev_dependencies: From 53cf751c437cf72d51211e1a5b7a3643e86c66b2 Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Wed, 10 Jun 2015 09:27:28 +0200 Subject: [PATCH 028/170] Initial approach to discovering package resolution for directory tree. R=brianwilkerson@google.com, pquitslund@google.com Review URL: https://codereview.chromium.org//1169513002. --- .../lib/discovery_analysis.dart | 167 ++++++++++++++++++ pkgs/package_config/pubspec.yaml | 2 +- .../test/discovery_analysis_test.dart | 122 +++++++++++++ 3 files changed, 290 insertions(+), 1 deletion(-) create mode 100644 pkgs/package_config/lib/discovery_analysis.dart create mode 100644 pkgs/package_config/test/discovery_analysis_test.dart diff --git a/pkgs/package_config/lib/discovery_analysis.dart b/pkgs/package_config/lib/discovery_analysis.dart new file mode 100644 index 000000000..f3bcac68e --- /dev/null +++ b/pkgs/package_config/lib/discovery_analysis.dart @@ -0,0 +1,167 @@ +// Copyright (c) 2015, 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. + +/// Analyse a directory structure and find packages resolvers for each +/// sub-directory. +/// +/// The resolvers are generally the same that would be found by using +/// the `discovery.dart` library on each sub-directory in turn, +/// but more efficiently and with some heuristics for directories that +/// wouldn't otherwise have a package resolution strategy, or that are +/// determined to be "package directories" themselves. +library package_config.discovery_analysis; + +import "dart:io" show File, Directory; +import "dart:collection" show HashMap; + +import "package:path/path.dart" as path; + +import "packages.dart"; +import "discovery.dart"; +import "packages_file.dart" as pkgfile; +import "src/packages_impl.dart"; +import "src/packages_io_impl.dart"; + +/// Associates a [Packages] package resolution strategy with a directory. +/// +/// The package resolution applies to the directory and any sub-directory +/// that doesn't have its own overriding child [PackageContext]. +abstract class PackageContext { + /// The directory that introduced the [packages] resolver. + Directory get directory; + + /// A [Packages] resolver that applies to the directory. + /// + /// Introduced either by a `.packages` file or a `packages/` directory. + Packages get packages; + + /// Child contexts that apply to sub-directories of [directory]. + List get children; + + /// Look up the [PackageContext] that applies to a specific directory. + /// + /// The directory must be inside [directory]. + PackageContext operator[](Directory directory); + + /// A map from directory to package resolver. + /// + /// Has an entry for this package context and for each child context + /// contained in this one. + Map asMap(); + + /// Analyze [directory] and sub-directories for package resolution strategies. + /// + /// Returns a mapping from sub-directories to [Packages] objects. + /// + /// The analysis assumes that there are no `.packages` files in a parent + /// directory of `directory`. If there is, its corresponding `Packages` object + /// should be provided as `root`. + static PackageContext findAll(Directory directory, + {Packages root: Packages.noPackages}) { + if (!directory.existsSync()) { + throw new ArgumentError("Directory not found: $directory"); + } + List contexts = []; + void findRoots(Directory directory) { + Packages packages; + List oldContexts; + File packagesFile = new File(path.join(directory.path, ".packages")); + if (packagesFile.existsSync()) { + packages = _loadPackagesFile(packagesFile); + oldContexts = contexts; + contexts = []; + } else { + Directory packagesDir = + new Directory(path.join(directory.path, "packages")); + if (packagesDir.existsSync()) { + packages = new FilePackagesDirectoryPackages(packagesDir); + oldContexts = contexts; + contexts = []; + } + } + for (var entry in directory.listSync()) { + if (entry is Directory) { + if (packages == null || !entry.path.endsWith("/packages")) { + findRoots(entry); + } + } + } + if (packages != null) { + oldContexts.add(new _PackageContext(directory, packages, contexts)); + contexts = oldContexts; + } + } + findRoots(directory); + // If the root is not itself context root, add a the wrapper context. + if (contexts.length == 1 && + contexts[0].directory == directory) { + return contexts[0]; + } + return new _PackageContext(directory, root, contexts); + } +} + +class _PackageContext implements PackageContext { + final Directory directory; + final Packages packages; + final List children; + _PackageContext(this.directory, this.packages, List children) + : children = new List.unmodifiable(children); + + Map asMap() { + var result = new HashMap(); + recurse(_PackageContext current) { + result[current.directory] = current.packages; + for (var child in current.children) { + recurse(child); + } + } + recurse(this); + return result; + } + + PackageContext operator[](Directory directory) { + String path = directory.path; + if (!path.startsWith(this.directory.path)) { + throw new ArgumentError("Not inside $path: $directory"); + } + _PackageContext current = this; + // The current path is know to agree with directory until deltaIndex. + int deltaIndex = current.directory.path.length; + List children = current.children; + int i = 0; + while (i < children.length) { + // TODO(lrn): Sort children and use binary search. + _PackageContext child = children[i]; + String childPath = child.directory.path; + if (_stringsAgree(path, childPath, deltaIndex, childPath.length)) { + deltaIndex = childPath.length; + if (deltaIndex == path.length) { + return child; + } + current = child; + children = current.children; + i = 0; + continue; + } + i++; + } + return current; + } + + static bool _stringsAgree(String a, String b, int start, int end) { + if (a.length < end || b.length < end) return false; + for (int i = start; i < end; i++) { + if (a.codeUnitAt(i) != b.codeUnitAt(i)) return false; + } + return true; + } +} + +Packages _loadPackagesFile(File file) { + var uri = new Uri.file(file.path); + var bytes = file.readAsBytesSync(); + var map = pkgfile.parse(bytes, uri); + return new MapPackages(map); +} diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 5eca33065..0f2735b53 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 0.0.3+1 +version: 0.0.4 description: Support for working with Package Resolution config files. author: Dart Team homepage: https://github.com/dart-lang/package_config diff --git a/pkgs/package_config/test/discovery_analysis_test.dart b/pkgs/package_config/test/discovery_analysis_test.dart new file mode 100644 index 000000000..ad007c073 --- /dev/null +++ b/pkgs/package_config/test/discovery_analysis_test.dart @@ -0,0 +1,122 @@ +// Copyright (c) 2015, 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. + +import "dart:async"; +import "dart:io"; + +import "package:package_config/discovery_analysis.dart"; +import "package:package_config/packages.dart"; +import "package:path/path.dart" as path; +import "package:test/test.dart"; + +main() { + fileTest("basic", + {".packages": packagesFile, + "foo": {".packages": packagesFile}, + "bar": {"packages": {"foo": {}, "bar":{}, "baz": {}}}, + "baz": {}}, + (Directory directory) { + var dirUri = new Uri.directory(directory.path); + PackageContext ctx = PackageContext.findAll(directory); + PackagesContext root = ctx[directory]; + expect(root, same(ctx)); + validatePackagesFile(root.packages, dirUri); + var fooDir = sub(directory, "foo"); + PackagesContext foo = ctx[fooDir]; + expect(identical(root, foo), isFalse); + validatePackagesFile(foo.packages, dirUri.resolve("foo/")); + var barDir = sub(directory, "bar"); + PackagesContext bar = ctx[sub(directory, "bar")]; + validatePackagesDir(bar.packages, dirUri.resolve("bar/")); + PackagesContext barbar = ctx[sub(barDir, "bar")]; + expect(barbar, same(bar)); // inherited. + PackagesContext baz = ctx[sub(directory, "baz")]; + expect(baz, same(root)); // inherited. + + var map = ctx.asMap(); + expect(map.keys.map((dir) => dir.path), + unorderedEquals([directory.path, fooDir.path, barDir.path])); + }); +} + +Directory sub(Directory parent, String dirName) { + return new Directory(path.join(parent.path, dirName)); +} + +const packagesFile = """ +# A comment +foo=file:///dart/packages/foo/ +bar=http://example.com/dart/packages/bar/ +baz=packages/baz/ +"""; + +void validatePackagesFile(Packages resolver, Uri location) { + expect(resolver, isNotNull); + expect(resolver.resolve(pkg("foo", "bar/baz")), + equals(Uri.parse("file:///dart/packages/foo/bar/baz"))); + expect(resolver.resolve(pkg("bar", "baz/qux")), + equals(Uri.parse("http://example.com/dart/packages/bar/baz/qux"))); + expect(resolver.resolve(pkg("baz", "qux/foo")), + equals(location.resolve("packages/baz/qux/foo"))); + expect(resolver.packages, unorderedEquals(["foo", "bar", "baz"])); +} + +void validatePackagesDir(Packages resolver, Uri location) { + // Expect three packages: foo, bar and baz + expect(resolver, isNotNull); + expect(resolver.resolve(pkg("foo", "bar/baz")), + equals(location.resolve("packages/foo/bar/baz"))); + expect(resolver.resolve(pkg("bar", "baz/qux")), + equals(location.resolve("packages/bar/baz/qux"))); + expect(resolver.resolve(pkg("baz", "qux/foo")), + equals(location.resolve("packages/baz/qux/foo"))); + if (location.scheme == "file") { + expect(resolver.packages, unorderedEquals(["foo", "bar", "baz"])); + } else { + expect(() => resolver.packages, throws); + } +} + +Uri pkg(String packageName, String packagePath) { + var path; + if (packagePath.startsWith('/')) { + path = "$packageName$packagePath"; + } else { + path = "$packageName/$packagePath"; + } + return new Uri(scheme: "package", path: path); +} + +/// Create a directory structure from [description] and run [fileTest]. +/// +/// Description is a map, each key is a file entry. If the value is a map, +/// it's a sub-dir, otherwise it's a file and the value is the content +/// as a string. +void fileTest(String name, + Map description, + Future fileTest(Uri directory)) { + group("file-test", () { + Directory tempDir = Directory.systemTemp.createTempSync("file-test"); + setUp(() { + _createFiles(tempDir, description); + }); + tearDown(() { + tempDir.deleteSync(recursive: true); + }); + test(name, () => fileTest(tempDir)); + }); +} + +void _createFiles(Directory target, Map description) { + description.forEach((name, content) { + if (content is Map) { + Directory subDir = new Directory(path.join(target.path, name)); + subDir.createSync(); + _createFiles(subDir, content); + } else { + File file = new File(path.join(target.path, name)); + file.writeAsStringSync(content, flush: true); + } + }); +} From 3fcadf72678f524f6d632c80b643519e5d90cd07 Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Wed, 10 Jun 2015 09:43:56 +0200 Subject: [PATCH 029/170] 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. --- pkgs/package_config/lib/discovery.dart | 96 ++++++++++++-------- pkgs/package_config/test/discovery_test.dart | 48 +++++++++- 2 files changed, 106 insertions(+), 38 deletions(-) diff --git a/pkgs/package_config/lib/discovery.dart b/pkgs/package_config/lib/discovery.dart index 0dd7f5508..35c3ece7f 100644 --- a/pkgs/package_config/lib/discovery.dart +++ b/pkgs/package_config/lib/discovery.dart @@ -15,6 +15,55 @@ import "packages_file.dart" as pkgfile show parse; 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 loadPackagesFile(Uri packagesFile, + {Future> loader(Uri uri)}) { + Packages parseBytes(List bytes) { + Map 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 @@ import "src/packages_io_impl.dart"; /// 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 findPackages(Uri baseUri, - {Future> loader(Uri unsupportedUri)}) { + {Future> loader(Uri unsupportedUri)}) { if (baseUri.scheme == "file") { return new Future.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.value(Packages.noPackages); } @@ -140,8 +191,8 @@ Packages findPackagesFromFile(Uri fileBaseUri) { /// of the requested `.packages` file as bytes, which will be assumed to be /// UTF-8 encoded. Future findPackagesFromNonFile(Uri nonFileUri, - {Future> loader(Uri name)}) { - if (loader == null) loader = _httpGet; + {Future> loader(Uri name)}) { + if (loader == null) loader = http.readBytes; Uri packagesFileUri = nonFileUri.resolve(".packages"); return loader(packagesFileUri).then((List fileBytes) { Map map = pkgfile.parse(fileBytes, packagesFileUri); @@ -152,30 +203,3 @@ Future findPackagesFromNonFile(Uri nonFileUri, return new NonFilePackagesDirectoryPackages(packagesDirectoryUri); }); } - -/// Fetches a file over http. -Future> _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> splitContent) { - int totalLength = splitContent.fold(0, (int old, List list) { - return old + list.length; - }); - Uint8List result = new Uint8List(totalLength); - int offset = 0; - for (List 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 16544e43d..d89cc2fa9 100644 --- a/pkgs/package_config/test/discovery_test.dart +++ b/pkgs/package_config/test/discovery_test.dart @@ -205,6 +205,52 @@ main() { 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 @@ void _createFiles(Directory target, Map description) { } }); } - - From 4eace8962445c84f69383010495a3a7b33ff37bd Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Wed, 10 Jun 2015 14:03:44 +0200 Subject: [PATCH 030/170] Tweak comments added by `write` function on packages_file.dart. Now adds "# " in front, not just "#", and doesn't treat the empty string after a final "\n" as an extra line. R=sgjesse@google.com Review URL: https://codereview.chromium.org//1167223004. --- pkgs/package_config/lib/packages_file.dart | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/pkgs/package_config/lib/packages_file.dart b/pkgs/package_config/lib/packages_file.dart index 2228cb3f0..a736ca0b5 100644 --- a/pkgs/package_config/lib/packages_file.dart +++ b/pkgs/package_config/lib/packages_file.dart @@ -74,7 +74,9 @@ Map parse(List source, Uri baseLocation) { /// Writes the mapping to a [StringSink]. /// /// If [comment] is provided, the output will contain this comment -/// with `#` in front of each line. +/// with `# ` in front of each line. +/// Lines are defined as ending in line feed (`'\n'`). If the final +/// line of the comment doesn't end in a line feed, one will be added. /// /// If [baseUri] is provided, package locations will be made relative /// to the base URI, if possible, before writing. @@ -85,8 +87,10 @@ void write(StringSink output, Map packageMapping, } if (comment != null) { - for (var commentLine in comment.split('\n')) { - output.write('#'); + var lines = comment.split('\n'); + if (lines.last.isEmpty) lines.removeLast(); + for (var commentLine in lines) { + output.write('# '); output.writeln(commentLine); } } else { @@ -172,4 +176,4 @@ Uri _relativize(Uri uri, Uri baseUri) { } // TODO: inline to uri.normalizePath() when we move to 1.11 -Uri _normalizePath(Uri uri) => new Uri().resolveUri(uri); +Uri _normalizePath(Uri uri) => new Uri().resolveUri(uri); From 3f171c5fee0b34fa64af46d4ab473c06821a314f Mon Sep 17 00:00:00 2001 From: Sigmund Cherem Date: Tue, 16 Jun 2015 09:42:56 -0700 Subject: [PATCH 031/170] Make tests pass R=het@google.com, lrn@google.com Review URL: https://codereview.chromium.org//1178673002. --- pkgs/package_config/lib/discovery.dart | 29 +++++++++++++++++-- pkgs/package_config/pubspec.yaml | 4 +-- .../test/discovery_analysis_test.dart | 12 ++++---- 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/pkgs/package_config/lib/discovery.dart b/pkgs/package_config/lib/discovery.dart index 35c3ece7f..a399395cb 100644 --- a/pkgs/package_config/lib/discovery.dart +++ b/pkgs/package_config/lib/discovery.dart @@ -38,7 +38,7 @@ Future loadPackagesFile(Uri packagesFile, return file.readAsBytes().then(parseBytes); } if (loader == null) { - return http.readBytes(packagesFile).then(parseBytes); + return _httpGet(packagesFile).then(parseBytes); } return loader(packagesFile).then(parseBytes); } @@ -99,7 +99,7 @@ Future findPackages(Uri baseUri, } else if (loader != null) { return findPackagesFromNonFile(baseUri, loader: loader); } else if (baseUri.scheme == "http" || baseUri.scheme == "https") { - return findPackagesFromNonFile(baseUri, loader: http.readBytes); + return findPackagesFromNonFile(baseUri, loader: _httpGet); } else { return new Future.value(Packages.noPackages); } @@ -192,7 +192,7 @@ Packages findPackagesFromFile(Uri fileBaseUri) { /// UTF-8 encoded. Future findPackagesFromNonFile(Uri nonFileUri, {Future> loader(Uri name)}) { - if (loader == null) loader = http.readBytes; + if (loader == null) loader = _httpGet; Uri packagesFileUri = nonFileUri.resolve(".packages"); return loader(packagesFileUri).then((List fileBytes) { Map map = pkgfile.parse(fileBytes, packagesFileUri); @@ -203,3 +203,26 @@ Future findPackagesFromNonFile(Uri nonFileUri, return new NonFilePackagesDirectoryPackages(packagesDirectoryUri); }); } + +/// Fetches a file over http. +Future> _httpGet(Uri uri) async { + HttpClient client = new HttpClient(); + HttpClientRequest request = await client.getUrl(uri); + HttpClientResponse response = await request.close(); + if (response.statusCode != HttpStatus.OK) { + throw 'Failure getting $uri: ' + '${response.statusCode} ${response.reasonPhrase}'; + } + List> splitContent = await response.toList(); + int totalLength = 0; + for (var list in splitContent) { + totalLength += list.length; + } + Uint8List result = new Uint8List(totalLength); + int offset = 0; + for (List contentPart in splitContent) { + result.setRange(offset, offset + contentPart.length, contentPart); + offset += contentPart.length; + } + return result; +} diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 0f2735b53..0b780d9d7 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -8,8 +8,8 @@ environment: sdk: '>=1.11.0-dev.0.0 <2.0.0' dependencies: - charcode: '^1.1.0' - path: '>=1.0.0 <2.0.0' + charcode: ^1.1.0 + path: ^1.0.0 dev_dependencies: test: '>=0.12.0 <0.13.0' diff --git a/pkgs/package_config/test/discovery_analysis_test.dart b/pkgs/package_config/test/discovery_analysis_test.dart index ad007c073..38599f895 100644 --- a/pkgs/package_config/test/discovery_analysis_test.dart +++ b/pkgs/package_config/test/discovery_analysis_test.dart @@ -19,19 +19,19 @@ main() { (Directory directory) { var dirUri = new Uri.directory(directory.path); PackageContext ctx = PackageContext.findAll(directory); - PackagesContext root = ctx[directory]; + PackageContext root = ctx[directory]; expect(root, same(ctx)); validatePackagesFile(root.packages, dirUri); var fooDir = sub(directory, "foo"); - PackagesContext foo = ctx[fooDir]; + PackageContext foo = ctx[fooDir]; expect(identical(root, foo), isFalse); validatePackagesFile(foo.packages, dirUri.resolve("foo/")); var barDir = sub(directory, "bar"); - PackagesContext bar = ctx[sub(directory, "bar")]; + PackageContext bar = ctx[sub(directory, "bar")]; validatePackagesDir(bar.packages, dirUri.resolve("bar/")); - PackagesContext barbar = ctx[sub(barDir, "bar")]; + PackageContext barbar = ctx[sub(barDir, "bar")]; expect(barbar, same(bar)); // inherited. - PackagesContext baz = ctx[sub(directory, "baz")]; + PackageContext baz = ctx[sub(directory, "baz")]; expect(baz, same(root)); // inherited. var map = ctx.asMap(); @@ -95,7 +95,7 @@ Uri pkg(String packageName, String packagePath) { /// as a string. void fileTest(String name, Map description, - Future fileTest(Uri directory)) { + Future fileTest(Directory directory)) { group("file-test", () { Directory tempDir = Directory.systemTemp.createTempSync("file-test"); setUp(() { From ca0681f4325686bf9350e5a80e289b71f44f1b88 Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Wed, 24 Jun 2015 08:00:52 +0200 Subject: [PATCH 032/170] Update to new syntax. R=het@google.com, pquitslund@google.com Review URL: https://codereview.chromium.org//1178213004. --- .../lib/discovery_analysis.dart | 1 - pkgs/package_config/lib/packages_file.dart | 30 ++++--- pkgs/package_config/lib/src/util.dart | 66 ++++++++++----- pkgs/package_config/pubspec.yaml | 2 +- pkgs/package_config/test/all.dart | 10 ++- .../test/discovery_analysis_test.dart | 8 +- pkgs/package_config/test/discovery_test.dart | 8 +- pkgs/package_config/test/parse_test.dart | 64 +++++++------- .../package_config/test/parse_write_test.dart | 84 +++++++++++++++++++ 9 files changed, 200 insertions(+), 73 deletions(-) create mode 100644 pkgs/package_config/test/parse_write_test.dart diff --git a/pkgs/package_config/lib/discovery_analysis.dart b/pkgs/package_config/lib/discovery_analysis.dart index f3bcac68e..af4df070a 100644 --- a/pkgs/package_config/lib/discovery_analysis.dart +++ b/pkgs/package_config/lib/discovery_analysis.dart @@ -18,7 +18,6 @@ import "dart:collection" show HashMap; import "package:path/path.dart" as path; import "packages.dart"; -import "discovery.dart"; import "packages_file.dart" as pkgfile; import "src/packages_impl.dart"; import "src/packages_io_impl.dart"; diff --git a/pkgs/package_config/lib/packages_file.dart b/pkgs/package_config/lib/packages_file.dart index a736ca0b5..73e6061c9 100644 --- a/pkgs/package_config/lib/packages_file.dart +++ b/pkgs/package_config/lib/packages_file.dart @@ -5,7 +5,7 @@ library package_config.packages_file; import "package:charcode/ascii.dart"; -import "src/util.dart" show isIdentifier; +import "src/util.dart" show isValidPackageName; /// Parses a `.packages` file into a map from package name to base URI. /// @@ -28,34 +28,34 @@ Map parse(List source, Uri baseLocation) { while (index < source.length) { bool isComment = false; int start = index; - int eqIndex = -1; + int separatorIndex = -1; int end = source.length; int char = source[index++]; if (char == $cr || char == $lf) { continue; } - if (char == $equal) { + if (char == $colon) { throw new FormatException("Missing package name", source, index - 1); } isComment = char == $hash; while (index < source.length) { char = source[index++]; - if (char == $equal && eqIndex < 0) { - eqIndex = index - 1; + if (char == $colon && separatorIndex < 0) { + separatorIndex = index - 1; } else if (char == $cr || char == $lf) { end = index - 1; break; } } if (isComment) continue; - if (eqIndex < 0) { - throw new FormatException("No '=' on line", source, index - 1); + if (separatorIndex < 0) { + throw new FormatException("No ':' on line", source, index - 1); } - var packageName = new String.fromCharCodes(source, start, eqIndex); - if (!isIdentifier(packageName)) { + var packageName = new String.fromCharCodes(source, start, separatorIndex); + if (!isValidPackageName(packageName)) { throw new FormatException("Not a valid package name", packageName, 0); } - var packageUri = new String.fromCharCodes(source, eqIndex + 1, end); + var packageUri = new String.fromCharCodes(source, separatorIndex + 1, end); var packageLocation = Uri.parse(packageUri); if (!packageLocation.path.endsWith('/')) { packageLocation = @@ -101,11 +101,11 @@ void write(StringSink output, Map packageMapping, packageMapping.forEach((String packageName, Uri uri) { // Validate packageName. - if (!isIdentifier(packageName)) { + if (!isValidPackageName(packageName)) { throw new ArgumentError('"$packageName" is not a valid package name'); } output.write(packageName); - output.write('='); + output.write(':'); // If baseUri provided, make uri relative. if (baseUri != null) { uri = _relativize(uri, baseUri); @@ -124,7 +124,7 @@ void write(StringSink output, Map packageMapping, /// but may be relative. /// The `baseUri` must be absolute. Uri _relativize(Uri uri, Uri baseUri) { - assert(!baseUri.isAbsolute); + assert(baseUri.isAbsolute); if (uri.hasQuery || uri.hasFragment) { uri = new Uri( scheme: uri.scheme, @@ -158,6 +158,7 @@ Uri _relativize(Uri uri, Uri baseUri) { } uri = _normalizePath(uri); List target = uri.pathSegments.toList(); + if (target.isNotEmpty && target.last.isEmpty) target.removeLast(); int index = 0; while (index < base.length && index < target.length) { if (base[index] != target[index]) { @@ -166,6 +167,9 @@ Uri _relativize(Uri uri, Uri baseUri) { index++; } if (index == base.length) { + if (index == target.length) { + return new Uri(path: "./"); + } return new Uri(path: target.skip(index).join('/')); } else if (index > 0) { return new Uri( diff --git a/pkgs/package_config/lib/src/util.dart b/pkgs/package_config/lib/src/util.dart index abf1d52f0..badf64086 100644 --- a/pkgs/package_config/lib/src/util.dart +++ b/pkgs/package_config/lib/src/util.dart @@ -7,27 +7,39 @@ library package_config.util; import "package:charcode/ascii.dart"; -/// Tests whether something is a valid Dart identifier/package name. -bool isIdentifier(String string) { - if (string.isEmpty) return false; - int firstChar = string.codeUnitAt(0); - int firstCharLower = firstChar | 0x20; - if (firstCharLower < $a || firstCharLower > $z) { - if (firstChar != $_ && firstChar != $$) return false; - } - for (int i = 1; i < string.length; i++) { - int char = string.codeUnitAt(i); - int charLower = char | 0x20; - if (charLower < $a || charLower > $z) { // Letters. - if ((char ^ 0x30) <= 9) continue; // Digits. - if (char == $_ || char == $$) continue; // $ and _ - if (firstChar != $_ && firstChar != $$) return false; +// All ASCII characters that are valid in a package name, with space +// for all the invalid ones (including space). +const String _validPackageNameCharacters = + r" ! $ &'()*+,-. 0123456789 ; = " + r"@ABCDEFGHIJKLMNOPQRSTUVWXYZ _ abcdefghijklmnopqrstuvwxyz ~ "; + +/// Tests whether something is a valid Dart package name. +bool isValidPackageName(String string) { + return _findInvalidCharacter(string) < 0; +} + +/// Check if a string is a valid package name. +/// +/// Valid package names contain only characters in [_validPackageNameCharacters] +/// and must contain at least one non-'.' character. +/// +/// Returns `-1` if the string is valid. +/// Otherwise returns the index of the first invalid character, +/// or `string.length` if the string contains no non-'.' character. +int _findInvalidCharacter(String string) { + // Becomes non-zero if any non-'.' character is encountered. + int nonDot = 0; + for (int i = 0; i < string.length; i++) { + var c = string.codeUnitAt(i); + if (c > 0x7f || _validPackageNameCharacters.codeUnitAt(c) <= $space) { + return i; } + nonDot += c ^ $dot; } - return true; + if (nonDot == 0) return string.length; + return -1; } - /// Validate that a Uri is a valid package:URI. String checkValidPackageUri(Uri packageUri) { if (packageUri.scheme != "package") { @@ -61,9 +73,25 @@ String checkValidPackageUri(Uri packageUri) { "Package URIs must start with the package name followed by a '/'"); } String packageName = packageUri.path.substring(0, firstSlash); - if (!isIdentifier(packageName)) { + int badIndex = _findInvalidCharacter(packageName); + if (badIndex >= 0) { + if (packageName.isEmpty) { + throw new ArgumentError.value(packageUri, "packageUri", + "Package names mus be non-empty"); + } + if (badIndex == packageName.length) { + throw new ArgumentError.value(packageUri, "packageUri", + "Package names must contain at least one non-'.' character"); + } + assert(badIndex < packageName.length); + int badCharCode = packageName.codeUnitAt(badIndex); + var badChar = "U+" + badCharCode.toRadixString(16).padLeft(4, '0'); + if (badCharCode >= 0x20 && badCharCode <= 0x7e) { + // Printable character. + badChar = "'${packageName[badIndex]}' ($badChar)"; + } throw new ArgumentError.value(packageUri, "packageUri", - "Package names must be valid identifiers"); + "Package names must not contain $badChar"); } return packageName; } diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 0b780d9d7..2d96c9035 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 0.0.4 +version: 0.1.0 description: Support for working with Package Resolution config files. author: Dart Team homepage: https://github.com/dart-lang/package_config diff --git a/pkgs/package_config/test/all.dart b/pkgs/package_config/test/all.dart index 79f5b3574..78e6cffd1 100644 --- a/pkgs/package_config/test/all.dart +++ b/pkgs/package_config/test/all.dart @@ -2,10 +2,16 @@ // 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. +import "package:test/test.dart"; + +import "discovery_analysis_test.dart" as discovery_analysis; import "discovery_test.dart" as discovery; import "parse_test.dart" as parse; +import "parse_write_test.dart" as parse_write; main() { - parse.main(); - discovery.main(); + group("parse:", parse.main); + group("discovery:", discovery.main); + group("discovery-analysis:", discovery_analysis.main); + group("parse/write:", parse_write.main); } diff --git a/pkgs/package_config/test/discovery_analysis_test.dart b/pkgs/package_config/test/discovery_analysis_test.dart index 38599f895..f33a4a8c6 100644 --- a/pkgs/package_config/test/discovery_analysis_test.dart +++ b/pkgs/package_config/test/discovery_analysis_test.dart @@ -2,6 +2,8 @@ // 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. +library package_config.discovery_analysis_test; + import "dart:async"; import "dart:io"; @@ -46,9 +48,9 @@ Directory sub(Directory parent, String dirName) { const packagesFile = """ # A comment -foo=file:///dart/packages/foo/ -bar=http://example.com/dart/packages/bar/ -baz=packages/baz/ +foo:file:///dart/packages/foo/ +bar:http://example.com/dart/packages/bar/ +baz:packages/baz/ """; void validatePackagesFile(Packages resolver, Uri location) { diff --git a/pkgs/package_config/test/discovery_test.dart b/pkgs/package_config/test/discovery_test.dart index d89cc2fa9..4f780c2ad 100644 --- a/pkgs/package_config/test/discovery_test.dart +++ b/pkgs/package_config/test/discovery_test.dart @@ -2,6 +2,8 @@ // 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. +library package_config.discovery_test; + import "dart:async"; import "dart:io"; import "package:test/test.dart"; @@ -11,9 +13,9 @@ import "package:path/path.dart" as path; const packagesFile = """ # A comment -foo=file:///dart/packages/foo/ -bar=http://example.com/dart/packages/bar/ -baz=packages/baz/ +foo:file:///dart/packages/foo/ +bar:http://example.com/dart/packages/bar/ +baz:packages/baz/ """; void validatePackagesFile(Packages resolver, Uri location) { diff --git a/pkgs/package_config/test/parse_test.dart b/pkgs/package_config/test/parse_test.dart index ddd8ff6ca..902d8cea8 100644 --- a/pkgs/package_config/test/parse_test.dart +++ b/pkgs/package_config/test/parse_test.dart @@ -2,7 +2,7 @@ // 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. -library test_all; +library package_config.parse_test; import "package:package_config/packages.dart"; import "package:package_config/packages_file.dart" show parse; @@ -81,27 +81,27 @@ main() { equals(base.resolve("../test/").resolve("bar/baz.dart"))); }); - test("all valid chars", () { + test("all valid chars can be used in URI segment", () { var packages = doParse(allValidCharsSample, base); expect(packages.packages.toList(), equals([allValidChars])); expect(packages.resolve(Uri.parse("package:$allValidChars/bar/baz.dart")), equals(base.resolve("../test/").resolve("bar/baz.dart"))); }); - test("no escapes", () { - expect(() => doParse("x%41x=x", base), throws); + test("no invalid chars accepted", () { + var map = {}; + for (int i = 0; i < allValidChars.length; i++) { + map[allValidChars.codeUnitAt(i)] = true; + } + for (int i = 0; i <= 255; i++) { + if (map[i] == true) continue; + var char = new String.fromCharCode(i); + expect(() => doParse("x${char}x:x"), throws); + } }); - test("not identifiers", () { - expect(() => doParse("1x=x", base), throws); - expect(() => doParse(" x=x", base), throws); - expect(() => doParse("\\x41x=x", base), throws); - expect(() => doParse("x@x=x", base), throws); - expect(() => doParse("x[x=x", base), throws); - expect(() => doParse("x`x=x", base), throws); - expect(() => doParse("x{x=x", base), throws); - expect(() => doParse("x/x=x", base), throws); - expect(() => doParse("x:x=x", base), throws); + test("no escapes", () { + expect(() => doParse("x%41x:x", base), throws); }); test("same name twice", () { @@ -131,26 +131,28 @@ Packages doParse(String sample, Uri baseUri) { var emptySample = ""; var commentOnlySample = "# comment only\n"; var emptyLinesSample = "\n\n\r\n"; -var singleRelativeSample = "foo=../test/\n"; -var singleRelativeSampleNoSlash = "foo=../test\n"; -var singleRelativeSampleNoNewline = "foo=../test/"; -var singleAbsoluteSample = "foo=http://example.com/some/where/\n"; -var multiRelativeSample = "foo=../test/\nbar=../test2/\n"; +var singleRelativeSample = "foo:../test/\n"; +var singleRelativeSampleNoSlash = "foo:../test\n"; +var singleRelativeSampleNoNewline = "foo:../test/"; +var singleAbsoluteSample = "foo:http://example.com/some/where/\n"; +var multiRelativeSample = "foo:../test/\nbar:../test2/\n"; // All valid path segment characters in an URI. var allValidChars = - r"$0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"; -var allValidCharsSample = "${allValidChars.replaceAll('=', '%3D')}=../test/\n"; -var allUnreservedChars = - "-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~"; + r"!$&'()*+,-.0123456789;=" + r"@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~"; + +var allValidCharsSample = "${allValidChars}:../test/\n"; // Invalid samples. var invalid = [ - "foobar:baz.dart", // no equals - ".=../test/", // dot segment - "..=../test/", // dot-dot segment - "foo/bar=../test/", // - "/foo=../test/", // var multiSegmentSample - "?=../test/", // invalid characters in path segment. - "[=../test/", // invalid characters in path segment. - "x#=../test/", // invalid characters in path segment. + ":baz.dart", // empty. + "foobar=baz.dart", // no colon (but an equals, which is not the same) + ".:../test/", // dot segment + "..:../test/", // dot-dot segment + "...:../test/", // dot-dot-dot segment + "foo/bar:../test/", // slash in name + "/foo:../test/", // slash at start of name + "?:../test/", // invalid characters. + "[:../test/", // invalid characters. + "x#:../test/", // invalid characters. ]; diff --git a/pkgs/package_config/test/parse_write_test.dart b/pkgs/package_config/test/parse_write_test.dart new file mode 100644 index 000000000..fde9616ea --- /dev/null +++ b/pkgs/package_config/test/parse_write_test.dart @@ -0,0 +1,84 @@ +// Copyright (c) 2015, 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. + +library package_config.parse_write_test; + +import "package:package_config/packages.dart"; +import "package:package_config/packages_file.dart"; +import "package:test/test.dart"; + +main() { + testBase(baseDirString) { + var baseDir = Uri.parse(baseDirString); + group("${baseDir.scheme} base", () { + Uri packagesFile = baseDir.resolve(".packages"); + + roundTripTest(String name, Map map) { + group(name, () { + test("write with no baseUri", () { + var content = writeToString(map).codeUnits; + var resultMap = parse(content, packagesFile); + expect(resultMap, map); + }); + + test("write with base directory", () { + var content = writeToString(map, baseUri: baseDir).codeUnits; + var resultMap = parse(content, packagesFile); + expect(resultMap, map); + }); + + test("write with base .packages file", () { + var content = writeToString(map, baseUri: packagesFile).codeUnits; + var resultMap = parse(content, packagesFile); + expect(resultMap, map); + }); + }); + } + var lowerDir = baseDir.resolve("path3/path4/"); + var higherDir = baseDir.resolve("../"); + var parallelDir = baseDir.resolve("../path3/"); + var rootDir = baseDir.resolve("/"); + var fileDir = Uri.parse("file:///path1/part2/"); + var httpDir = Uri.parse("http://example.com/path1/path2/"); + var otherDir = Uri.parse("other:/path1/path2/"); + + roundTripTest("empty", {}); + roundTripTest("lower directory", {"foo": lowerDir}); + roundTripTest("higher directory", {"foo": higherDir}); + roundTripTest("parallel directory", {"foo": parallelDir}); + roundTripTest("same directory", {"foo": baseDir}); + roundTripTest("root directory", {"foo": rootDir}); + roundTripTest("file directory", {"foo": fileDir}); + roundTripTest("http directory", {"foo": httpDir}); + roundTripTest("other scheme directory", {"foo": otherDir}); + roundTripTest("multiple same-type directories", + {"foo": lowerDir, "bar": higherDir, "baz": parallelDir}); + roundTripTest("multiple scheme directories", + {"foo": fileDir, "bar": httpDir, "baz": otherDir}); + roundTripTest("multiple scheme directories and mutliple same type", + {"foo": fileDir, "bar": httpDir, "baz": otherDir, + "qux": lowerDir, "hip": higherDir, "dep": parallelDir}); + }); + } + + testBase("file:///base1/base2/"); + testBase("http://example.com/base1/base2/"); + testBase("other:/base1/base2/"); + + // Check that writing adds the comment. + test("write preserves comment", () { + var comment = "comment line 1\ncomment line 2\ncomment line 3"; + var result = writeToString({}, comment: comment); + // Comment with "# " before each line and "\n" after last. + var expectedComment = + "# comment line 1\n# comment line 2\n# comment line 3\n"; + expect(result, startsWith(expectedComment)); + }); +} + +String writeToString(Map map, {Uri baseUri, String comment}) { + var buffer = new StringBuffer(); + write(buffer, map, baseUri: baseUri, comment: comment); + return buffer.toString(); +} From 3b11c03435f18fab1943e94ff3d680a098a0d961 Mon Sep 17 00:00:00 2001 From: pq Date: Wed, 24 Jun 2015 09:06:02 -0700 Subject: [PATCH 033/170] Build fixes [TBR]. --- pkgs/package_config/test/parse_test.dart | 2 +- pkgs/package_config/test/parse_write_test.dart | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/pkgs/package_config/test/parse_test.dart b/pkgs/package_config/test/parse_test.dart index 902d8cea8..3c02c84b6 100644 --- a/pkgs/package_config/test/parse_test.dart +++ b/pkgs/package_config/test/parse_test.dart @@ -96,7 +96,7 @@ main() { for (int i = 0; i <= 255; i++) { if (map[i] == true) continue; var char = new String.fromCharCode(i); - expect(() => doParse("x${char}x:x"), throws); + expect(() => doParse("x${char}x:x", null), throws); } }); diff --git a/pkgs/package_config/test/parse_write_test.dart b/pkgs/package_config/test/parse_write_test.dart index fde9616ea..6a185db20 100644 --- a/pkgs/package_config/test/parse_write_test.dart +++ b/pkgs/package_config/test/parse_write_test.dart @@ -4,7 +4,6 @@ library package_config.parse_write_test; -import "package:package_config/packages.dart"; import "package:package_config/packages_file.dart"; import "package:test/test.dart"; From 8110c7a4a8e0119a0625d5e2caa3110a9e236de5 Mon Sep 17 00:00:00 2001 From: pq Date: Wed, 24 Jun 2015 09:13:40 -0700 Subject: [PATCH 034/170] Version bump. --- pkgs/package_config/CHANGELOG.md | 11 +++++++++-- pkgs/package_config/pubspec.yaml | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index 2a2d63cf8..625f48625 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog -## 0.0.1 +## 0.1.1 + +- Syntax updates. + + +## 0.1.0 + +- Initial implementation. + -- Initial version diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 2d96c9035..72406801e 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 0.1.0 +version: 0.1.1 description: Support for working with Package Resolution config files. author: Dart Team homepage: https://github.com/dart-lang/package_config From 3351876c810771f337a05cf2950dce94ce594cde Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Mon, 13 Jul 2015 09:19:24 +0200 Subject: [PATCH 035/170] Don't allow package:-URIs as package locations when creating .packages file. R=pquitslund@google.com Review URL: https://codereview.chromium.org//1227283002 . --- pkgs/package_config/lib/discovery.dart | 2 +- pkgs/package_config/lib/packages_file.dart | 7 +++++++ pkgs/package_config/pubspec.yaml | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/pkgs/package_config/lib/discovery.dart b/pkgs/package_config/lib/discovery.dart index a399395cb..8e42af79d 100644 --- a/pkgs/package_config/lib/discovery.dart +++ b/pkgs/package_config/lib/discovery.dart @@ -179,7 +179,7 @@ Packages findPackagesFromFile(Uri fileBaseUri) { /// script. /// The [nonFileUri] should not be a `file:` URI since the algorithm for /// finding a package resolution strategy is more elaborate for `file:` URIs. -/// In that case, use [findPackagesFile]. +/// In that case, use [findPackagesFromFile]. /// /// This function first tries to locate a `.packages` file in the [nonFileUri] /// directory. If that is not found, it instead assumes a `packages/` directory diff --git a/pkgs/package_config/lib/packages_file.dart b/pkgs/package_config/lib/packages_file.dart index 73e6061c9..25d2d6883 100644 --- a/pkgs/package_config/lib/packages_file.dart +++ b/pkgs/package_config/lib/packages_file.dart @@ -80,6 +80,9 @@ Map parse(List source, Uri baseLocation) { /// /// If [baseUri] is provided, package locations will be made relative /// to the base URI, if possible, before writing. +/// +/// All the keys of [packageMapping] must be valid package names, +/// and the values must be URIs that do not have the `package:` scheme. void write(StringSink output, Map packageMapping, {Uri baseUri, String comment}) { if (baseUri != null && !baseUri.isAbsolute) { @@ -104,6 +107,10 @@ void write(StringSink output, Map packageMapping, if (!isValidPackageName(packageName)) { throw new ArgumentError('"$packageName" is not a valid package name'); } + if (uri.scheme == "package") { + throw new ArgumentError.value( + "Package location must not be a package: URI", uri); + } output.write(packageName); output.write(':'); // If baseUri provided, make uri relative. diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 72406801e..d3acb9064 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 0.1.1 +version: 0.1.2 description: Support for working with Package Resolution config files. author: Dart Team homepage: https://github.com/dart-lang/package_config From 5bd94be91cae69f085ee77f0143262b01500f081 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Fri, 14 Aug 2015 16:47:02 -0700 Subject: [PATCH 036/170] remove checked-in pubspec.lock and ignore .packages --- pkgs/package_config/.gitignore | 3 +- pkgs/package_config/pubspec.lock | 87 -------------------------------- 2 files changed, 2 insertions(+), 88 deletions(-) delete mode 100644 pkgs/package_config/pubspec.lock diff --git a/pkgs/package_config/.gitignore b/pkgs/package_config/.gitignore index f48e3c9a8..b46f3df8e 100644 --- a/pkgs/package_config/.gitignore +++ b/pkgs/package_config/.gitignore @@ -4,4 +4,5 @@ packages build .project .settings -pubspec.lock \ No newline at end of file +pubspec.lock +.packages diff --git a/pkgs/package_config/pubspec.lock b/pkgs/package_config/pubspec.lock deleted file mode 100644 index 5cae00509..000000000 --- a/pkgs/package_config/pubspec.lock +++ /dev/null @@ -1,87 +0,0 @@ -# Generated by pub -# See http://pub.dartlang.org/doc/glossary.html#lockfile -packages: - analyzer: - description: analyzer - source: hosted - version: "0.25.0+1" - args: - description: args - source: hosted - version: "0.13.0" - barback: - description: barback - source: hosted - version: "0.15.2+4" - charcode: - description: charcode - source: hosted - version: "1.1.0" - collection: - description: collection - source: hosted - version: "1.1.1" - crypto: - description: crypto - source: hosted - version: "0.9.0" - http_parser: - description: http_parser - source: hosted - version: "0.0.2+6" - matcher: - description: matcher - source: hosted - version: "0.12.0" - mime: - description: mime - source: hosted - version: "0.9.3" - path: - description: path - source: hosted - version: "1.3.5" - pool: - description: pool - source: hosted - version: "1.0.1" - pub_semver: - description: pub_semver - source: hosted - version: "1.2.0" - shelf: - description: shelf - source: hosted - version: "0.6.1+2" - shelf_static: - description: shelf_static - source: hosted - version: "0.2.2" - shelf_web_socket: - description: shelf_web_socket - source: hosted - version: "0.0.1+2" - source_span: - description: source_span - source: hosted - version: "1.1.2" - stack_trace: - description: stack_trace - source: hosted - version: "1.3.2" - string_scanner: - description: string_scanner - source: hosted - version: "0.1.3+1" - test: - description: test - source: hosted - version: "0.12.1" - watcher: - description: watcher - source: hosted - version: "0.9.5" - yaml: - description: yaml - source: hosted - version: "2.1.2" From 56cefdeb98f127f03e80bc29eb4caf5905f12fce Mon Sep 17 00:00:00 2001 From: pq Date: Tue, 18 Aug 2015 08:53:55 -0700 Subject: [PATCH 037/170] Invalid test cleanup (parse_test). --- pkgs/package_config/CHANGELOG.md | 4 ++++ pkgs/package_config/pubspec.yaml | 2 +- pkgs/package_config/test/parse_test.dart | 7 ------- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index 625f48625..f4e355e2c 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 0.1.3-dev + +- Invalid test cleanup (to keepup with changes in `Uri`). + ## 0.1.1 - Syntax updates. diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index d3acb9064..4cc000616 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 0.1.2 +version: 0.1.3-dev description: Support for working with Package Resolution config files. author: Dart Team homepage: https://github.com/dart-lang/package_config diff --git a/pkgs/package_config/test/parse_test.dart b/pkgs/package_config/test/parse_test.dart index 3c02c84b6..6f830a103 100644 --- a/pkgs/package_config/test/parse_test.dart +++ b/pkgs/package_config/test/parse_test.dart @@ -74,13 +74,6 @@ main() { equals(base.resolve("../test/").resolve("bar/baz.dart"))); }); - test("dot-dot 2", () { - var packages = doParse(singleRelativeSample, base); - expect(packages.packages.toList(), equals(["foo"])); - expect(packages.resolve(Uri.parse("package:qux/../foo/bar/baz.dart")), - equals(base.resolve("../test/").resolve("bar/baz.dart"))); - }); - test("all valid chars can be used in URI segment", () { var packages = doParse(allValidCharsSample, base); expect(packages.packages.toList(), equals([allValidChars])); From c73974c3c5c918b9ccbde699e7c6ff81b8818e79 Mon Sep 17 00:00:00 2001 From: pq Date: Tue, 18 Aug 2015 09:45:31 -0700 Subject: [PATCH 038/170] Static warning fix. --- pkgs/package_config/lib/packages_file.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/package_config/lib/packages_file.dart b/pkgs/package_config/lib/packages_file.dart index 25d2d6883..3f432aa70 100644 --- a/pkgs/package_config/lib/packages_file.dart +++ b/pkgs/package_config/lib/packages_file.dart @@ -109,7 +109,7 @@ void write(StringSink output, Map packageMapping, } if (uri.scheme == "package") { throw new ArgumentError.value( - "Package location must not be a package: URI", uri); + "Package location must not be a package: URI", uri.toString()); } output.write(packageName); output.write(':'); From 57e55d1ba4e85bb0f73b536d72174211f98d4f6a Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Thu, 20 Aug 2015 11:17:58 +0200 Subject: [PATCH 039/170] Add slash to package dir URI after resolving reference against base. Used to add slash to reference before resolving it. It only makes a difference for the empty URI reference which never makes sense anyway - this just ensures the error is the same as on the VM. It is, arguably, what the specification requires. R=sgjesse@google.com Review URL: https://codereview.chromium.org//1297923004. --- pkgs/package_config/lib/packages_file.dart | 2 +- pkgs/package_config/test/parse_test.dart | 32 ++++++++++++++++------ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/pkgs/package_config/lib/packages_file.dart b/pkgs/package_config/lib/packages_file.dart index 3f432aa70..f30781dc3 100644 --- a/pkgs/package_config/lib/packages_file.dart +++ b/pkgs/package_config/lib/packages_file.dart @@ -57,11 +57,11 @@ Map parse(List source, Uri baseLocation) { } var packageUri = new String.fromCharCodes(source, separatorIndex + 1, end); var packageLocation = Uri.parse(packageUri); + packageLocation = baseLocation.resolveUri(packageLocation); if (!packageLocation.path.endsWith('/')) { packageLocation = packageLocation.replace(path: packageLocation.path + "/"); } - packageLocation = baseLocation.resolveUri(packageLocation); if (result.containsKey(packageName)) { throw new FormatException( "Same package name occured twice.", source, start); diff --git a/pkgs/package_config/test/parse_test.dart b/pkgs/package_config/test/parse_test.dart index 6f830a103..8ed5c2eb7 100644 --- a/pkgs/package_config/test/parse_test.dart +++ b/pkgs/package_config/test/parse_test.dart @@ -50,13 +50,27 @@ main() { equals(base.resolve("../test/").resolve("bar/baz.dart"))); }); - test("single absolute", () { + test("single absolute authority", () { var packages = doParse(singleAbsoluteSample, base); expect(packages.packages.toList(), equals(["foo"])); expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), equals(Uri.parse("http://example.com/some/where/bar/baz.dart"))); }); + test("single empty path", () { + var packages = doParse(singleEmptyPathSample, base); + expect(packages.packages.toList(), equals(["foo"])); + expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), + equals(base.replace(path: "${base.path}/bar/baz.dart"))); + }); + + test("single absolute path", () { + var packages = doParse(singleAbsolutePathSample, base); + expect(packages.packages.toList(), equals(["foo"])); + expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), + equals(base.replace(path: "/test/bar/baz.dart"))); + }); + test("multiple", () { var packages = doParse(multiRelativeSample, base); expect( @@ -121,14 +135,16 @@ Packages doParse(String sample, Uri baseUri) { } // Valid samples. -var emptySample = ""; -var commentOnlySample = "# comment only\n"; -var emptyLinesSample = "\n\n\r\n"; -var singleRelativeSample = "foo:../test/\n"; -var singleRelativeSampleNoSlash = "foo:../test\n"; +var emptySample = ""; +var commentOnlySample = "# comment only\n"; +var emptyLinesSample = "\n\n\r\n"; +var singleRelativeSample = "foo:../test/\n"; +var singleRelativeSampleNoSlash = "foo:../test\n"; var singleRelativeSampleNoNewline = "foo:../test/"; -var singleAbsoluteSample = "foo:http://example.com/some/where/\n"; -var multiRelativeSample = "foo:../test/\nbar:../test2/\n"; +var singleAbsoluteSample = "foo:http://example.com/some/where/\n"; +var singleEmptyPathSample = "foo:\n"; +var singleAbsolutePathSample = "foo:/test/\n"; +var multiRelativeSample = "foo:../test/\nbar:../test2/\n"; // All valid path segment characters in an URI. var allValidChars = r"!$&'()*+,-.0123456789;=" From 24e3e0c664fc0a667b825f722244956bdfb7a15c Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Thu, 20 Aug 2015 12:46:36 +0200 Subject: [PATCH 040/170] Update version number before publishing. BUG= Review URL: https://codereview.chromium.org/1301443005 . --- pkgs/package_config/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 4cc000616..f2c4e06cc 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 0.1.3-dev +version: 0.1.3 description: Support for working with Package Resolution config files. author: Dart Team homepage: https://github.com/dart-lang/package_config From ba56d6613604908223abf6dd484daf66ac531f88 Mon Sep 17 00:00:00 2001 From: Seth Ladd Date: Wed, 16 Sep 2015 10:00:40 -0700 Subject: [PATCH 041/170] Go SSL --- pkgs/package_config/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/package_config/README.md b/pkgs/package_config/README.md index 9a0995d6b..0463719b3 100644 --- a/pkgs/package_config/README.md +++ b/pkgs/package_config/README.md @@ -4,7 +4,7 @@ Support for working with **Package Resolution Configuration** files as described in this [DEP](https://github.com/lrhn/dep-pkgspec/blob/master/DEP-pkgspec.md), under review [here] (https://github.com/dart-lang/dart_enhancement_proposals/issues/5). -[![Build Status](https://travis-ci.org/dart-lang/package_config.svg?branch=master)](https://travis-ci.org/dart-lang/package_config) [![pub package](http://img.shields.io/pub/v/package_config.svg)](https://pub.dartlang.org/packages/package_config) +[![Build Status](https://travis-ci.org/dart-lang/package_config.svg?branch=master)](https://travis-ci.org/dart-lang/package_config) [![pub package](https://img.shields.io/pub/v/package_config.svg)](https://pub.dartlang.org/packages/package_config) ## Features and bugs From 469c2234b1281836646e658a225cf56d8aa2ebb1 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Wed, 4 May 2016 11:27:29 -0700 Subject: [PATCH 042/170] dartfmt --- pkgs/package_config/lib/discovery.dart | 8 +- .../lib/discovery_analysis.dart | 9 +- pkgs/package_config/lib/packages.dart | 1 - pkgs/package_config/lib/packages_file.dart | 2 +- .../package_config/lib/src/packages_impl.dart | 10 +- .../lib/src/packages_io_impl.dart | 9 +- pkgs/package_config/lib/src/util.dart | 28 ++-- .../test/discovery_analysis_test.dart | 37 ++--- pkgs/package_config/test/discovery_test.dart | 152 ++++++++---------- pkgs/package_config/test/parse_test.dart | 44 +++-- .../package_config/test/parse_write_test.dart | 15 +- 11 files changed, 151 insertions(+), 164 deletions(-) diff --git a/pkgs/package_config/lib/discovery.dart b/pkgs/package_config/lib/discovery.dart index 8e42af79d..10dbb8ef4 100644 --- a/pkgs/package_config/lib/discovery.dart +++ b/pkgs/package_config/lib/discovery.dart @@ -28,7 +28,7 @@ import "src/packages_io_impl.dart"; /// resolution file, for example one specified using a `--packages` /// command-line parameter. Future loadPackagesFile(Uri packagesFile, - {Future> loader(Uri uri)}) { + {Future> loader(Uri uri)}) { Packages parseBytes(List bytes) { Map packageMap = pkgfile.parse(bytes, packagesFile); return new MapPackages(packageMap); @@ -43,7 +43,6 @@ Future loadPackagesFile(Uri packagesFile, return loader(packagesFile).then(parseBytes); } - /// Create a [Packages] object for a package directory. /// /// The [packagesDir] URI should refer to a directory. @@ -63,7 +62,6 @@ Packages getPackagesDirectory(Uri packagesDir) { return new NonFilePackagesDirectoryPackages(packagesDir); } - /// Discover the package configuration for a Dart script. /// /// The [baseUri] points to either the Dart script or its directory. @@ -93,7 +91,7 @@ Packages getPackagesDirectory(Uri packagesDir) { /// The content should be a UTF-8 encoded `.packages` file, and must return an /// error future if loading fails for any reason. Future findPackages(Uri baseUri, - {Future> loader(Uri unsupportedUri)}) { + {Future> loader(Uri unsupportedUri)}) { if (baseUri.scheme == "file") { return new Future.sync(() => findPackagesFromFile(baseUri)); } else if (loader != null) { @@ -191,7 +189,7 @@ Packages findPackagesFromFile(Uri fileBaseUri) { /// of the requested `.packages` file as bytes, which will be assumed to be /// UTF-8 encoded. Future findPackagesFromNonFile(Uri nonFileUri, - {Future> loader(Uri name)}) { + {Future> loader(Uri name)}) { if (loader == null) loader = _httpGet; Uri packagesFileUri = nonFileUri.resolve(".packages"); return loader(packagesFileUri).then((List fileBytes) { diff --git a/pkgs/package_config/lib/discovery_analysis.dart b/pkgs/package_config/lib/discovery_analysis.dart index af4df070a..6d4b9edd7 100644 --- a/pkgs/package_config/lib/discovery_analysis.dart +++ b/pkgs/package_config/lib/discovery_analysis.dart @@ -41,7 +41,7 @@ abstract class PackageContext { /// Look up the [PackageContext] that applies to a specific directory. /// /// The directory must be inside [directory]. - PackageContext operator[](Directory directory); + PackageContext operator [](Directory directory); /// A map from directory to package resolver. /// @@ -57,7 +57,7 @@ abstract class PackageContext { /// directory of `directory`. If there is, its corresponding `Packages` object /// should be provided as `root`. static PackageContext findAll(Directory directory, - {Packages root: Packages.noPackages}) { + {Packages root: Packages.noPackages}) { if (!directory.existsSync()) { throw new ArgumentError("Directory not found: $directory"); } @@ -93,8 +93,7 @@ abstract class PackageContext { } findRoots(directory); // If the root is not itself context root, add a the wrapper context. - if (contexts.length == 1 && - contexts[0].directory == directory) { + if (contexts.length == 1 && contexts[0].directory == directory) { return contexts[0]; } return new _PackageContext(directory, root, contexts); @@ -120,7 +119,7 @@ class _PackageContext implements PackageContext { return result; } - PackageContext operator[](Directory directory) { + PackageContext operator [](Directory directory) { String path = directory.path; if (!path.startsWith(this.directory.path)) { throw new ArgumentError("Not inside $path: $directory"); diff --git a/pkgs/package_config/lib/packages.dart b/pkgs/package_config/lib/packages.dart index dbaa06dfd..890f4485c 100644 --- a/pkgs/package_config/lib/packages.dart +++ b/pkgs/package_config/lib/packages.dart @@ -17,7 +17,6 @@ import "src/packages_impl.dart"; /// One such case is if the packages are resolved relative to a /// `packages/` directory available over HTTP. abstract class Packages { - /// A [Packages] resolver containing no packages. /// /// This constant object is returned by [find] above if no diff --git a/pkgs/package_config/lib/packages_file.dart b/pkgs/package_config/lib/packages_file.dart index f30781dc3..93ccd3c18 100644 --- a/pkgs/package_config/lib/packages_file.dart +++ b/pkgs/package_config/lib/packages_file.dart @@ -84,7 +84,7 @@ Map parse(List source, Uri baseLocation) { /// All the keys of [packageMapping] must be valid package names, /// and the values must be URIs that do not have the `package:` scheme. void write(StringSink output, Map packageMapping, - {Uri baseUri, String comment}) { + {Uri baseUri, String comment}) { if (baseUri != null && !baseUri.isAbsolute) { throw new ArgumentError.value(baseUri, "baseUri", "Must be absolute"); } diff --git a/pkgs/package_config/lib/src/packages_impl.dart b/pkgs/package_config/lib/src/packages_impl.dart index e85f75581..fa9115fc6 100644 --- a/pkgs/package_config/lib/src/packages_impl.dart +++ b/pkgs/package_config/lib/src/packages_impl.dart @@ -18,13 +18,13 @@ class NoPackages implements Packages { Uri resolve(Uri packageUri, {Uri notFound(Uri packageUri)}) { String packageName = checkValidPackageUri(packageUri); if (notFound != null) return notFound(packageUri); - throw new ArgumentError.value(packageUri, "packageUri", - 'No package named "$packageName"'); + throw new ArgumentError.value( + packageUri, "packageUri", 'No package named "$packageName"'); } Iterable get packages => new Iterable.generate(0); - Map asMap() => const{}; + Map asMap() => const {}; } /// Base class for [Packages] implementations. @@ -38,8 +38,8 @@ abstract class PackagesBase implements Packages { Uri packageBase = getBase(packageName); if (packageBase == null) { if (notFound != null) return notFound(packageUri); - throw new ArgumentError.value(packageUri, "packageUri", - 'No package named "$packageName"'); + throw new ArgumentError.value( + packageUri, "packageUri", 'No package named "$packageName"'); } String packagePath = packageUri.path.substring(packageName.length + 1); return packageBase.resolve(packagePath); diff --git a/pkgs/package_config/lib/src/packages_io_impl.dart b/pkgs/package_config/lib/src/packages_io_impl.dart index 21b61fdab..db39bdb58 100644 --- a/pkgs/package_config/lib/src/packages_io_impl.dart +++ b/pkgs/package_config/lib/src/packages_io_impl.dart @@ -17,12 +17,13 @@ class FilePackagesDirectoryPackages extends PackagesBase { FilePackagesDirectoryPackages(this._packageDir); Uri getBase(String packageName) => - new Uri.file(path.join(_packageDir.path, packageName, '.')); + new Uri.file(path.join(_packageDir.path, packageName, '.')); Iterable _listPackageNames() { - return _packageDir.listSync() - .where((e) => e is Directory) - .map((e) => path.basename(e.path)); + return _packageDir + .listSync() + .where((e) => e is Directory) + .map((e) => path.basename(e.path)); } Iterable get packages => _listPackageNames(); diff --git a/pkgs/package_config/lib/src/util.dart b/pkgs/package_config/lib/src/util.dart index badf64086..f1e1afd0a 100644 --- a/pkgs/package_config/lib/src/util.dart +++ b/pkgs/package_config/lib/src/util.dart @@ -43,29 +43,29 @@ int _findInvalidCharacter(String string) { /// Validate that a Uri is a valid package:URI. String checkValidPackageUri(Uri packageUri) { if (packageUri.scheme != "package") { - throw new ArgumentError.value(packageUri, "packageUri", - "Not a package: URI"); + throw new ArgumentError.value( + packageUri, "packageUri", "Not a package: URI"); } if (packageUri.hasAuthority) { - throw new ArgumentError.value(packageUri, "packageUri", - "Package URIs must not have a host part"); + throw new ArgumentError.value( + packageUri, "packageUri", "Package URIs must not have a host part"); } if (packageUri.hasQuery) { // A query makes no sense if resolved to a file: URI. - throw new ArgumentError.value(packageUri, "packageUri", - "Package URIs must not have a query part"); + throw new ArgumentError.value( + packageUri, "packageUri", "Package URIs must not have a query part"); } if (packageUri.hasFragment) { // We could leave the fragment after the URL when resolving, // but it would be odd if "package:foo/foo.dart#1" and // "package:foo/foo.dart#2" were considered different libraries. // Keep the syntax open in case we ever get multiple libraries in one file. - throw new ArgumentError.value(packageUri, "packageUri", - "Package URIs must not have a fragment part"); + throw new ArgumentError.value( + packageUri, "packageUri", "Package URIs must not have a fragment part"); } if (packageUri.path.startsWith('/')) { - throw new ArgumentError.value(packageUri, "packageUri", - "Package URIs must not start with a '/'"); + throw new ArgumentError.value( + packageUri, "packageUri", "Package URIs must not start with a '/'"); } int firstSlash = packageUri.path.indexOf('/'); if (firstSlash == -1) { @@ -76,8 +76,8 @@ String checkValidPackageUri(Uri packageUri) { int badIndex = _findInvalidCharacter(packageName); if (badIndex >= 0) { if (packageName.isEmpty) { - throw new ArgumentError.value(packageUri, "packageUri", - "Package names mus be non-empty"); + throw new ArgumentError.value( + packageUri, "packageUri", "Package names mus be non-empty"); } if (badIndex == packageName.length) { throw new ArgumentError.value(packageUri, "packageUri", @@ -90,8 +90,8 @@ String checkValidPackageUri(Uri packageUri) { // Printable character. badChar = "'${packageName[badIndex]}' ($badChar)"; } - throw new ArgumentError.value(packageUri, "packageUri", - "Package names must not contain $badChar"); + throw new ArgumentError.value( + packageUri, "packageUri", "Package names must not contain $badChar"); } return packageName; } diff --git a/pkgs/package_config/test/discovery_analysis_test.dart b/pkgs/package_config/test/discovery_analysis_test.dart index f33a4a8c6..0a2876726 100644 --- a/pkgs/package_config/test/discovery_analysis_test.dart +++ b/pkgs/package_config/test/discovery_analysis_test.dart @@ -13,12 +13,14 @@ import "package:path/path.dart" as path; import "package:test/test.dart"; main() { - fileTest("basic", - {".packages": packagesFile, - "foo": {".packages": packagesFile}, - "bar": {"packages": {"foo": {}, "bar":{}, "baz": {}}}, - "baz": {}}, - (Directory directory) { + fileTest("basic", { + ".packages": packagesFile, + "foo": {".packages": packagesFile}, + "bar": { + "packages": {"foo": {}, "bar": {}, "baz": {}} + }, + "baz": {} + }, (Directory directory) { var dirUri = new Uri.directory(directory.path); PackageContext ctx = PackageContext.findAll(directory); PackageContext root = ctx[directory]; @@ -32,13 +34,13 @@ main() { PackageContext bar = ctx[sub(directory, "bar")]; validatePackagesDir(bar.packages, dirUri.resolve("bar/")); PackageContext barbar = ctx[sub(barDir, "bar")]; - expect(barbar, same(bar)); // inherited. + expect(barbar, same(bar)); // inherited. PackageContext baz = ctx[sub(directory, "baz")]; - expect(baz, same(root)); // inherited. + expect(baz, same(root)); // inherited. var map = ctx.asMap(); expect(map.keys.map((dir) => dir.path), - unorderedEquals([directory.path, fooDir.path, barDir.path])); + unorderedEquals([directory.path, fooDir.path, barDir.path])); }); } @@ -56,11 +58,11 @@ baz:packages/baz/ void validatePackagesFile(Packages resolver, Uri location) { expect(resolver, isNotNull); expect(resolver.resolve(pkg("foo", "bar/baz")), - equals(Uri.parse("file:///dart/packages/foo/bar/baz"))); + equals(Uri.parse("file:///dart/packages/foo/bar/baz"))); expect(resolver.resolve(pkg("bar", "baz/qux")), - equals(Uri.parse("http://example.com/dart/packages/bar/baz/qux"))); + equals(Uri.parse("http://example.com/dart/packages/bar/baz/qux"))); expect(resolver.resolve(pkg("baz", "qux/foo")), - equals(location.resolve("packages/baz/qux/foo"))); + equals(location.resolve("packages/baz/qux/foo"))); expect(resolver.packages, unorderedEquals(["foo", "bar", "baz"])); } @@ -68,11 +70,11 @@ void validatePackagesDir(Packages resolver, Uri location) { // Expect three packages: foo, bar and baz expect(resolver, isNotNull); expect(resolver.resolve(pkg("foo", "bar/baz")), - equals(location.resolve("packages/foo/bar/baz"))); + equals(location.resolve("packages/foo/bar/baz"))); expect(resolver.resolve(pkg("bar", "baz/qux")), - equals(location.resolve("packages/bar/baz/qux"))); + equals(location.resolve("packages/bar/baz/qux"))); expect(resolver.resolve(pkg("baz", "qux/foo")), - equals(location.resolve("packages/baz/qux/foo"))); + equals(location.resolve("packages/baz/qux/foo"))); if (location.scheme == "file") { expect(resolver.packages, unorderedEquals(["foo", "bar", "baz"])); } else { @@ -95,9 +97,8 @@ Uri pkg(String packageName, String packagePath) { /// Description is a map, each key is a file entry. If the value is a map, /// it's a sub-dir, otherwise it's a file and the value is the content /// as a string. -void fileTest(String name, - Map description, - Future fileTest(Directory directory)) { +void fileTest( + String name, Map description, Future fileTest(Directory directory)) { group("file-test", () { Directory tempDir = Directory.systemTemp.createTempSync("file-test"); setUp(() { diff --git a/pkgs/package_config/test/discovery_test.dart b/pkgs/package_config/test/discovery_test.dart index 4f780c2ad..97b7bbf91 100644 --- a/pkgs/package_config/test/discovery_test.dart +++ b/pkgs/package_config/test/discovery_test.dart @@ -21,11 +21,11 @@ baz:packages/baz/ void validatePackagesFile(Packages resolver, Uri location) { expect(resolver, isNotNull); expect(resolver.resolve(pkg("foo", "bar/baz")), - equals(Uri.parse("file:///dart/packages/foo/bar/baz"))); + equals(Uri.parse("file:///dart/packages/foo/bar/baz"))); expect(resolver.resolve(pkg("bar", "baz/qux")), - equals(Uri.parse("http://example.com/dart/packages/bar/baz/qux"))); + equals(Uri.parse("http://example.com/dart/packages/bar/baz/qux"))); expect(resolver.resolve(pkg("baz", "qux/foo")), - equals(location.resolve("packages/baz/qux/foo"))); + equals(location.resolve("packages/baz/qux/foo"))); expect(resolver.packages, unorderedEquals(["foo", "bar", "baz"])); } @@ -33,11 +33,11 @@ void validatePackagesDir(Packages resolver, Uri location) { // Expect three packages: foo, bar and baz expect(resolver, isNotNull); expect(resolver.resolve(pkg("foo", "bar/baz")), - equals(location.resolve("packages/foo/bar/baz"))); + equals(location.resolve("packages/foo/bar/baz"))); expect(resolver.resolve(pkg("bar", "baz/qux")), - equals(location.resolve("packages/bar/baz/qux"))); + equals(location.resolve("packages/bar/baz/qux"))); expect(resolver.resolve(pkg("baz", "qux/foo")), - equals(location.resolve("packages/baz/qux/foo"))); + equals(location.resolve("packages/baz/qux/foo"))); if (location.scheme == "file") { expect(resolver.packages, unorderedEquals(["foo", "bar", "baz"])); } else { @@ -45,7 +45,6 @@ void validatePackagesDir(Packages resolver, Uri location) { } } - Uri pkg(String packageName, String packagePath) { var path; if (packagePath.startsWith('/')) { @@ -57,11 +56,11 @@ Uri pkg(String packageName, String packagePath) { } main() { - generalTest(".packages", - {".packages": packagesFile, - "script.dart": "main(){}", - "packages": {"shouldNotBeFound": {}}}, - (Uri location) async { + generalTest(".packages", { + ".packages": packagesFile, + "script.dart": "main(){}", + "packages": {"shouldNotBeFound": {}} + }, (Uri location) async { Packages resolver; resolver = await findPackages(location); validatePackagesFile(resolver, location); @@ -76,36 +75,36 @@ main() { validatePackagesFile(resolver, location); }); - generalTest("packages/", - {"packages": { "foo": {}, "bar": {}, "baz": {}}, - "script.dart": "main(){}"}, - (Uri location) async { + generalTest("packages/", { + "packages": {"foo": {}, "bar": {}, "baz": {}}, + "script.dart": "main(){}" + }, (Uri location) async { Packages resolver; bool isFile = (location.scheme == "file"); resolver = await findPackages(location); validatePackagesDir(resolver, location); resolver = await findPackages(location.resolve("script.dart")); validatePackagesDir(resolver, location); - var specificDiscovery = isFile - ? findPackagesFromFile - : findPackagesFromNonFile; + var specificDiscovery = + isFile ? findPackagesFromFile : findPackagesFromNonFile; resolver = await specificDiscovery(location); validatePackagesDir(resolver, location); resolver = await specificDiscovery(location.resolve("script.dart")); validatePackagesDir(resolver, location); }); - generalTest("underscore packages", - {"packages": {"_foo": {}}}, - (Uri location) async { + generalTest("underscore packages", { + "packages": {"_foo": {}} + }, (Uri location) async { Packages resolver = await findPackages(location); expect(resolver.resolve(pkg("_foo", "foo.dart")), - equals(location.resolve("packages/_foo/foo.dart"))); + equals(location.resolve("packages/_foo/foo.dart"))); }); - fileTest(".packages recursive", - {".packages": packagesFile, "subdir": {"script.dart": "main(){}"}}, - (Uri location) async { + fileTest(".packages recursive", { + ".packages": packagesFile, + "subdir": {"script.dart": "main(){}"} + }, (Uri location) async { Packages resolver; resolver = await findPackages(location.resolve("subdir/")); validatePackagesFile(resolver, location); @@ -118,9 +117,10 @@ main() { validatePackagesFile(resolver, location); }); - httpTest(".packages not recursive", - {".packages": packagesFile, "subdir": {"script.dart": "main(){}"}}, - (Uri location) async { + httpTest(".packages not recursive", { + ".packages": packagesFile, + "subdir": {"script.dart": "main(){}"} + }, (Uri location) async { Packages resolver; var subdir = location.resolve("subdir/"); resolver = await findPackages(subdir); @@ -133,9 +133,7 @@ main() { validatePackagesDir(resolver, subdir); }); - fileTest("no packages", - {"script.dart": "main(){}"}, - (Uri location) async { + fileTest("no packages", {"script.dart": "main(){}"}, (Uri location) async { // A file: location with no .packages or packages returns // Packages.noPackages. Packages resolver; @@ -149,9 +147,7 @@ main() { expect(resolver, same(Packages.noPackages)); }); - httpTest("no packages", - {"script.dart": "main(){}"}, - (Uri location) async { + httpTest("no packages", {"script.dart": "main(){}"}, (Uri location) async { // A non-file: location with no .packages or packages/: // Assumes a packages dir exists, and resolves relative to that. Packages resolver; @@ -178,13 +174,13 @@ main() { Packages resolver; resolver = await findPackages(location, loader: loader); validatePackagesFile(resolver, location); - resolver = await findPackages(location.resolve("script.dart"), - loader: loader); + resolver = + await findPackages(location.resolve("script.dart"), loader: loader); validatePackagesFile(resolver, location); resolver = await findPackagesFromNonFile(location, loader: loader); validatePackagesFile(resolver, location); resolver = await findPackagesFromNonFile(location.resolve("script.dart"), - loader: loader); + loader: loader); validatePackagesFile(resolver, location); }); @@ -198,27 +194,26 @@ main() { Packages resolver; resolver = await findPackages(location, loader: loader); validatePackagesDir(resolver, location); - resolver = await findPackages(location.resolve("script.dart"), - loader: loader); + resolver = + await findPackages(location.resolve("script.dart"), loader: loader); validatePackagesDir(resolver, location); resolver = await findPackagesFromNonFile(location, loader: loader); validatePackagesDir(resolver, location); resolver = await findPackagesFromNonFile(location.resolve("script.dart"), - loader:loader); + loader: loader); validatePackagesDir(resolver, location); }); - generalTest("loadPackagesFile", - {".packages": packagesFile}, - (Uri directory) async { + 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 { + generalTest( + "loadPackagesFile non-default name", {"pheldagriff": packagesFile}, + (Uri directory) async { Uri file = directory.resolve("pheldagriff"); Packages resolver = await loadPackagesFile(file); validatePackagesFile(resolver, file); @@ -231,26 +226,23 @@ main() { validatePackagesFile(resolver, file); }); - generalTest("loadPackagesFile not found", - {}, - (Uri directory) async { + 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 { + 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 { + 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")); + Uri resolved = resolver.resolve(pkg("foo", "flip/flop")); expect(resolved, packages.resolve("foo/flip/flop")); }); } @@ -260,9 +252,7 @@ main() { /// Description is a map, each key is a file entry. If the value is a map, /// it's a sub-dir, otherwise it's a file and the value is the content /// as a string. -void fileTest(String name, - Map description, - Future fileTest(Uri directory)) { +void fileTest(String name, Map description, Future fileTest(Uri directory)) { group("file-test", () { Directory tempDir = Directory.systemTemp.createTempSync("file-test"); setUp(() { @@ -285,31 +275,27 @@ void httpTest(String name, Map description, Future httpTest(Uri directory)) { var serverSub; var uri; setUp(() { - return HttpServer - .bind(InternetAddress.LOOPBACK_IP_V4, 0) - .then((server) { - uri = new Uri(scheme: "http", - host: "127.0.0.1", - port: server.port, - path: "/"); - serverSub = server.listen((HttpRequest request) { - // No error handling. - var path = request.uri.path; - if (path.startsWith('/')) path = path.substring(1); - if (path.endsWith('/')) path = path.substring(0, path.length - 1); - var parts = path.split('/'); - var fileOrDir = description; - for (int i = 0; i < parts.length; i++) { - fileOrDir = fileOrDir[parts[i]]; - if (fileOrDir == null) { - request.response.statusCode = 404; - request.response.close(); - } + return HttpServer.bind(InternetAddress.LOOPBACK_IP_V4, 0).then((server) { + uri = new Uri( + scheme: "http", host: "127.0.0.1", port: server.port, path: "/"); + serverSub = server.listen((HttpRequest request) { + // No error handling. + var path = request.uri.path; + if (path.startsWith('/')) path = path.substring(1); + if (path.endsWith('/')) path = path.substring(0, path.length - 1); + var parts = path.split('/'); + var fileOrDir = description; + for (int i = 0; i < parts.length; i++) { + fileOrDir = fileOrDir[parts[i]]; + if (fileOrDir == null) { + request.response.statusCode = 404; + request.response.close(); } - request.response.write(fileOrDir); - request.response.close(); - }); + } + request.response.write(fileOrDir); + request.response.close(); }); + }); }); tearDown(() => serverSub.cancel()); test(name, () => httpTest(uri)); diff --git a/pkgs/package_config/test/parse_test.dart b/pkgs/package_config/test/parse_test.dart index 8ed5c2eb7..7a2fce7e2 100644 --- a/pkgs/package_config/test/parse_test.dart +++ b/pkgs/package_config/test/parse_test.dart @@ -73,8 +73,7 @@ main() { test("multiple", () { var packages = doParse(multiRelativeSample, base); - expect( - packages.packages.toList()..sort(), equals(["bar", "foo"])); + expect(packages.packages.toList()..sort(), equals(["bar", "foo"])); expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), equals(base.resolve("../test/").resolve("bar/baz.dart"))); expect(packages.resolve(Uri.parse("package:bar/foo/baz.dart")), @@ -135,33 +134,32 @@ Packages doParse(String sample, Uri baseUri) { } // Valid samples. -var emptySample = ""; -var commentOnlySample = "# comment only\n"; -var emptyLinesSample = "\n\n\r\n"; -var singleRelativeSample = "foo:../test/\n"; -var singleRelativeSampleNoSlash = "foo:../test\n"; +var emptySample = ""; +var commentOnlySample = "# comment only\n"; +var emptyLinesSample = "\n\n\r\n"; +var singleRelativeSample = "foo:../test/\n"; +var singleRelativeSampleNoSlash = "foo:../test\n"; var singleRelativeSampleNoNewline = "foo:../test/"; -var singleAbsoluteSample = "foo:http://example.com/some/where/\n"; -var singleEmptyPathSample = "foo:\n"; -var singleAbsolutePathSample = "foo:/test/\n"; -var multiRelativeSample = "foo:../test/\nbar:../test2/\n"; +var singleAbsoluteSample = "foo:http://example.com/some/where/\n"; +var singleEmptyPathSample = "foo:\n"; +var singleAbsolutePathSample = "foo:/test/\n"; +var multiRelativeSample = "foo:../test/\nbar:../test2/\n"; // All valid path segment characters in an URI. -var allValidChars = - r"!$&'()*+,-.0123456789;=" +var allValidChars = r"!$&'()*+,-.0123456789;=" r"@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~"; var allValidCharsSample = "${allValidChars}:../test/\n"; // Invalid samples. var invalid = [ - ":baz.dart", // empty. - "foobar=baz.dart", // no colon (but an equals, which is not the same) - ".:../test/", // dot segment - "..:../test/", // dot-dot segment - "...:../test/", // dot-dot-dot segment - "foo/bar:../test/", // slash in name - "/foo:../test/", // slash at start of name - "?:../test/", // invalid characters. - "[:../test/", // invalid characters. - "x#:../test/", // invalid characters. + ":baz.dart", // empty. + "foobar=baz.dart", // no colon (but an equals, which is not the same) + ".:../test/", // dot segment + "..:../test/", // dot-dot segment + "...:../test/", // dot-dot-dot segment + "foo/bar:../test/", // slash in name + "/foo:../test/", // slash at start of name + "?:../test/", // invalid characters. + "[:../test/", // invalid characters. + "x#:../test/", // invalid characters. ]; diff --git a/pkgs/package_config/test/parse_write_test.dart b/pkgs/package_config/test/parse_write_test.dart index 6a185db20..29c2224a5 100644 --- a/pkgs/package_config/test/parse_write_test.dart +++ b/pkgs/package_config/test/parse_write_test.dart @@ -52,12 +52,17 @@ main() { roundTripTest("http directory", {"foo": httpDir}); roundTripTest("other scheme directory", {"foo": otherDir}); roundTripTest("multiple same-type directories", - {"foo": lowerDir, "bar": higherDir, "baz": parallelDir}); + {"foo": lowerDir, "bar": higherDir, "baz": parallelDir}); roundTripTest("multiple scheme directories", - {"foo": fileDir, "bar": httpDir, "baz": otherDir}); - roundTripTest("multiple scheme directories and mutliple same type", - {"foo": fileDir, "bar": httpDir, "baz": otherDir, - "qux": lowerDir, "hip": higherDir, "dep": parallelDir}); + {"foo": fileDir, "bar": httpDir, "baz": otherDir}); + roundTripTest("multiple scheme directories and mutliple same type", { + "foo": fileDir, + "bar": httpDir, + "baz": otherDir, + "qux": lowerDir, + "hip": higherDir, + "dep": parallelDir + }); }); } From 4cd7dfb3f6c0f528a5cb4baff7779a818d3a850b Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Wed, 4 May 2016 11:31:07 -0700 Subject: [PATCH 043/170] strong-mode clean --- pkgs/package_config/.analysis_options | 2 ++ pkgs/package_config/lib/discovery_analysis.dart | 4 ++-- pkgs/package_config/test/discovery_test.dart | 6 +++--- pkgs/package_config/test/parse_write_test.dart | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) create mode 100644 pkgs/package_config/.analysis_options diff --git a/pkgs/package_config/.analysis_options b/pkgs/package_config/.analysis_options new file mode 100644 index 000000000..a10d4c5a0 --- /dev/null +++ b/pkgs/package_config/.analysis_options @@ -0,0 +1,2 @@ +analyzer: + strong-mode: true diff --git a/pkgs/package_config/lib/discovery_analysis.dart b/pkgs/package_config/lib/discovery_analysis.dart index 6d4b9edd7..058330b19 100644 --- a/pkgs/package_config/lib/discovery_analysis.dart +++ b/pkgs/package_config/lib/discovery_analysis.dart @@ -61,10 +61,10 @@ abstract class PackageContext { if (!directory.existsSync()) { throw new ArgumentError("Directory not found: $directory"); } - List contexts = []; + var contexts = []; void findRoots(Directory directory) { Packages packages; - List oldContexts; + List oldContexts; File packagesFile = new File(path.join(directory.path, ".packages")); if (packagesFile.existsSync()) { packages = _loadPackagesFile(packagesFile); diff --git a/pkgs/package_config/test/discovery_test.dart b/pkgs/package_config/test/discovery_test.dart index 97b7bbf91..8807ac497 100644 --- a/pkgs/package_config/test/discovery_test.dart +++ b/pkgs/package_config/test/discovery_test.dart @@ -163,7 +163,7 @@ main() { test(".packages w/ loader", () async { Uri location = Uri.parse("krutch://example.com/path/"); - Future loader(Uri file) async { + Future> loader(Uri file) async { if (file.path.endsWith(".packages")) { return packagesFile.codeUnits; } @@ -186,7 +186,7 @@ main() { test("no packages w/ loader", () async { Uri location = Uri.parse("krutch://example.com/path/"); - Future loader(Uri file) async { + Future> loader(Uri file) async { throw "not found"; } // A non-file: location with no .packages or packages/: @@ -220,7 +220,7 @@ main() { }); test("loadPackagesFile w/ loader", () async { - loader(Uri uri) async => packagesFile.codeUnits; + Future> loader(Uri uri) async => packagesFile.codeUnits; Uri file = Uri.parse("krutz://example.com/.packages"); Packages resolver = await loadPackagesFile(file, loader: loader); validatePackagesFile(resolver, file); diff --git a/pkgs/package_config/test/parse_write_test.dart b/pkgs/package_config/test/parse_write_test.dart index 29c2224a5..430218791 100644 --- a/pkgs/package_config/test/parse_write_test.dart +++ b/pkgs/package_config/test/parse_write_test.dart @@ -81,7 +81,7 @@ main() { }); } -String writeToString(Map map, {Uri baseUri, String comment}) { +String writeToString(Map map, {Uri baseUri, String comment}) { var buffer = new StringBuffer(); write(buffer, map, baseUri: baseUri, comment: comment); return buffer.toString(); From 019debf0c1f45c5d572329bdf399a0fe4f4719b3 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Wed, 4 May 2016 11:32:13 -0700 Subject: [PATCH 044/170] cleanup gitignore --- pkgs/package_config/.gitignore | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pkgs/package_config/.gitignore b/pkgs/package_config/.gitignore index b46f3df8e..aac1f4fe8 100644 --- a/pkgs/package_config/.gitignore +++ b/pkgs/package_config/.gitignore @@ -1,8 +1,4 @@ -.idea +.packages .pub packages -build -.project -.settings pubspec.lock -.packages From 52f15c0fdbf5a791749335b1807d4dcdee4e0bae Mon Sep 17 00:00:00 2001 From: pq Date: Wed, 4 May 2016 16:05:42 -0700 Subject: [PATCH 045/170] More strong-mode fixes --- pkgs/package_config/CHANGELOG.md | 11 +++++------ pkgs/package_config/lib/discovery.dart | 18 ++++++++++-------- pkgs/package_config/pubspec.yaml | 2 +- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index f4e355e2c..6ac42ec58 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -1,16 +1,15 @@ -# Changelog +## 0.1.4 -## 0.1.3-dev +- Strong mode fixes. -- Invalid test cleanup (to keepup with changes in `Uri`). +## 0.1.3 + +- Invalid test cleanup (to keep up with changes in `Uri`). ## 0.1.1 - Syntax updates. - ## 0.1.0 - Initial implementation. - - diff --git a/pkgs/package_config/lib/discovery.dart b/pkgs/package_config/lib/discovery.dart index 10dbb8ef4..4c09eecfb 100644 --- a/pkgs/package_config/lib/discovery.dart +++ b/pkgs/package_config/lib/discovery.dart @@ -28,19 +28,19 @@ import "src/packages_io_impl.dart"; /// resolution file, for example one specified using a `--packages` /// command-line parameter. Future loadPackagesFile(Uri packagesFile, - {Future> loader(Uri uri)}) { + {Future> loader(Uri uri)}) async { Packages parseBytes(List bytes) { Map packageMap = pkgfile.parse(bytes, packagesFile); return new MapPackages(packageMap); } if (packagesFile.scheme == "file") { File file = new File.fromUri(packagesFile); - return file.readAsBytes().then(parseBytes); + return parseBytes(await file.readAsBytes()); } if (loader == null) { - return _httpGet(packagesFile).then(parseBytes); + return parseBytes(await _httpGet(packagesFile)); } - return loader(packagesFile).then(parseBytes); + return parseBytes(await loader(packagesFile)); } /// Create a [Packages] object for a package directory. @@ -189,17 +189,19 @@ Packages findPackagesFromFile(Uri fileBaseUri) { /// of the requested `.packages` file as bytes, which will be assumed to be /// UTF-8 encoded. Future findPackagesFromNonFile(Uri nonFileUri, - {Future> loader(Uri name)}) { + {Future> loader(Uri name)}) async { if (loader == null) loader = _httpGet; Uri packagesFileUri = nonFileUri.resolve(".packages"); - return loader(packagesFileUri).then((List fileBytes) { + + try { + List fileBytes = await loader(packagesFileUri); Map map = pkgfile.parse(fileBytes, packagesFileUri); return new MapPackages(map); - }, onError: (_) { + } catch (_) { // Didn't manage to load ".packages". Assume a "packages/" directory. Uri packagesDirectoryUri = nonFileUri.resolve("packages/"); return new NonFilePackagesDirectoryPackages(packagesDirectoryUri); - }); + } } /// Fetches a file over http. diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index f2c4e06cc..80aea6dd1 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 0.1.3 +version: 0.1.4 description: Support for working with Package Resolution config files. author: Dart Team homepage: https://github.com/dart-lang/package_config From 0e70668b1de4b464ab429a9453c50fd41837efd8 Mon Sep 17 00:00:00 2001 From: Konstantin Shcheglov Date: Tue, 7 Jun 2016 18:49:55 -0700 Subject: [PATCH 046/170] Cache packageName to base Uri mapping. This makes analysis with using incremental analysis cache 30% faster. Without this change getBase() takes 40% (!) of total analysis time. With this change - just 0.79% of total time. Although the remaining 17% of PackagesBase.resolve() make my cry. Why URI manipulations are SO SLOW?! R=brianwilkerson@google.com, pquitslund@google.com, kevmoo@google.com BUG= Review URL: https://codereview.chromium.org/2041103005 . --- pkgs/package_config/lib/src/packages_io_impl.dart | 9 +++++++-- pkgs/package_config/pubspec.yaml | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/pkgs/package_config/lib/src/packages_io_impl.dart b/pkgs/package_config/lib/src/packages_io_impl.dart index db39bdb58..0e9474639 100644 --- a/pkgs/package_config/lib/src/packages_io_impl.dart +++ b/pkgs/package_config/lib/src/packages_io_impl.dart @@ -14,10 +14,15 @@ import "packages_impl.dart"; /// A [Packages] implementation based on a local directory. class FilePackagesDirectoryPackages extends PackagesBase { final Directory _packageDir; + final Map _packageToBaseUriMap = {}; + FilePackagesDirectoryPackages(this._packageDir); - Uri getBase(String packageName) => - new Uri.file(path.join(_packageDir.path, packageName, '.')); + Uri getBase(String packageName) { + return _packageToBaseUriMap.putIfAbsent(packageName, () { + return new Uri.file(path.join(_packageDir.path, packageName, '.')); + }); + } Iterable _listPackageNames() { return _packageDir diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 80aea6dd1..3d9bd45f9 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 0.1.4 +version: 0.1.5 description: Support for working with Package Resolution config files. author: Dart Team homepage: https://github.com/dart-lang/package_config From 65b68c2597dd2325a113316698276b12ef2053a2 Mon Sep 17 00:00:00 2001 From: pq Date: Thu, 9 Jun 2016 09:00:57 -0700 Subject: [PATCH 047/170] `0.1.5` CHANGELOG update pre-publish. Adds: * FilePackagesDirectoryPackages.getBase(..)` performance improvements. BUG= R=scheglov@google.com Review URL: https://codereview.chromium.org//2051143002 . --- pkgs/package_config/CHANGELOG.md | 4 ++++ pkgs/package_config/codereview.settings | 3 +++ 2 files changed, 7 insertions(+) create mode 100644 pkgs/package_config/codereview.settings diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index 6ac42ec58..b7b441e9e 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.5 + +- `FilePackagesDirectoryPackages.getBase(..)` performance improvements. + ## 0.1.4 - Strong mode fixes. diff --git a/pkgs/package_config/codereview.settings b/pkgs/package_config/codereview.settings new file mode 100644 index 000000000..1099f0594 --- /dev/null +++ b/pkgs/package_config/codereview.settings @@ -0,0 +1,3 @@ +CODE_REVIEW_SERVER: https://codereview.chromium.org/ +VIEW_VC: https://github.com/dart-lang/package_config/commit/ +CC_LIST: reviews@dartlang.org From 08cc6269bab6827b78d8b554582d16d925ceb000 Mon Sep 17 00:00:00 2001 From: pq Date: Tue, 14 Jun 2016 09:37:11 -0700 Subject: [PATCH 048/170] Bump `package_config` to 1.0.0. BUG= R=lrn@google.com Review URL: https://codereview.chromium.org//2061863002 . --- pkgs/package_config/CHANGELOG.md | 4 ++++ pkgs/package_config/pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index b7b441e9e..18a42ce71 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.0 + +- Public API marked stable. + ## 0.1.5 - `FilePackagesDirectoryPackages.getBase(..)` performance improvements. diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 3d9bd45f9..e1afec23c 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 0.1.5 +version: 1.0.0 description: Support for working with Package Resolution config files. author: Dart Team homepage: https://github.com/dart-lang/package_config From afcf0d0f0309ae7b42e5ca2acee24c3b41f722d2 Mon Sep 17 00:00:00 2001 From: Danny Tuppeny Date: Tue, 16 Aug 2016 17:53:12 +0100 Subject: [PATCH 049/170] Remove space that causes link not to render on pub.dartlang.org. The link doesn't render correctly here because of the space: https://pub.dartlang.org/packages/package_config --- pkgs/package_config/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/package_config/README.md b/pkgs/package_config/README.md index 0463719b3..942822002 100644 --- a/pkgs/package_config/README.md +++ b/pkgs/package_config/README.md @@ -2,7 +2,7 @@ Support for working with **Package Resolution Configuration** files as described in this [DEP](https://github.com/lrhn/dep-pkgspec/blob/master/DEP-pkgspec.md), -under review [here] (https://github.com/dart-lang/dart_enhancement_proposals/issues/5). +under review [here](https://github.com/dart-lang/dart_enhancement_proposals/issues/5). [![Build Status](https://travis-ci.org/dart-lang/package_config.svg?branch=master)](https://travis-ci.org/dart-lang/package_config) [![pub package](https://img.shields.io/pub/v/package_config.svg)](https://pub.dartlang.org/packages/package_config) From fe0d59a2a6353f8aa2d961327f91e91847919ab4 Mon Sep 17 00:00:00 2001 From: Devon Carew Date: Fri, 2 Sep 2016 07:04:05 -0700 Subject: [PATCH 050/170] Some minor changes: - organize imports - add the generated doc directory to the gitignore file BUG= R=pquitslund@google.com Review URL: https://codereview.chromium.org//2298063005 . --- pkgs/package_config/.gitignore | 1 + pkgs/package_config/lib/discovery_analysis.dart | 2 +- pkgs/package_config/lib/packages_file.dart | 1 + pkgs/package_config/lib/src/packages_impl.dart | 1 + pkgs/package_config/lib/src/packages_io_impl.dart | 2 ++ 5 files changed, 6 insertions(+), 1 deletion(-) diff --git a/pkgs/package_config/.gitignore b/pkgs/package_config/.gitignore index aac1f4fe8..a8b93ef38 100644 --- a/pkgs/package_config/.gitignore +++ b/pkgs/package_config/.gitignore @@ -2,3 +2,4 @@ .pub packages pubspec.lock +doc/api/ diff --git a/pkgs/package_config/lib/discovery_analysis.dart b/pkgs/package_config/lib/discovery_analysis.dart index 058330b19..ce7e98a1a 100644 --- a/pkgs/package_config/lib/discovery_analysis.dart +++ b/pkgs/package_config/lib/discovery_analysis.dart @@ -12,8 +12,8 @@ /// determined to be "package directories" themselves. library package_config.discovery_analysis; -import "dart:io" show File, Directory; import "dart:collection" show HashMap; +import "dart:io" show File, Directory; import "package:path/path.dart" as path; diff --git a/pkgs/package_config/lib/packages_file.dart b/pkgs/package_config/lib/packages_file.dart index 93ccd3c18..0f1a6e635 100644 --- a/pkgs/package_config/lib/packages_file.dart +++ b/pkgs/package_config/lib/packages_file.dart @@ -5,6 +5,7 @@ library package_config.packages_file; import "package:charcode/ascii.dart"; + import "src/util.dart" show isValidPackageName; /// Parses a `.packages` file into a map from package name to base URI. diff --git a/pkgs/package_config/lib/src/packages_impl.dart b/pkgs/package_config/lib/src/packages_impl.dart index fa9115fc6..df89e4623 100644 --- a/pkgs/package_config/lib/src/packages_impl.dart +++ b/pkgs/package_config/lib/src/packages_impl.dart @@ -8,6 +8,7 @@ library package_config.packages_impl; import "dart:collection" show UnmodifiableMapView; + import "../packages.dart"; import "util.dart" show checkValidPackageUri; diff --git a/pkgs/package_config/lib/src/packages_io_impl.dart b/pkgs/package_config/lib/src/packages_io_impl.dart index 0e9474639..9eba9ce44 100644 --- a/pkgs/package_config/lib/src/packages_io_impl.dart +++ b/pkgs/package_config/lib/src/packages_io_impl.dart @@ -8,7 +8,9 @@ library package_config.packages_io_impl; import "dart:collection" show UnmodifiableMapView; import "dart:io" show Directory; + import "package:path/path.dart" as path; + import "packages_impl.dart"; /// A [Packages] implementation based on a local directory. From 520ade132d7397f7f180a171d387f796b4718af6 Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Thu, 4 May 2017 16:13:41 +0200 Subject: [PATCH 051/170] Fix write to sink after close in test code. R=floitsch@google.com Review-Url: https://codereview.chromium.org//2857383002 . --- pkgs/package_config/CHANGELOG.md | 4 ++++ pkgs/package_config/pubspec.yaml | 2 +- pkgs/package_config/test/discovery_test.dart | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index 18a42ce71..c03367853 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.1 + +- Fix test to not write to sink after it's closed. + ## 1.0.0 - Public API marked stable. diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index e1afec23c..eaef83e3a 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 1.0.0 +version: 1.0.1 description: Support for working with Package Resolution config files. author: Dart Team homepage: https://github.com/dart-lang/package_config diff --git a/pkgs/package_config/test/discovery_test.dart b/pkgs/package_config/test/discovery_test.dart index 8807ac497..897063f52 100644 --- a/pkgs/package_config/test/discovery_test.dart +++ b/pkgs/package_config/test/discovery_test.dart @@ -290,6 +290,7 @@ void httpTest(String name, Map description, Future httpTest(Uri directory)) { if (fileOrDir == null) { request.response.statusCode = 404; request.response.close(); + return; } } request.response.write(fileOrDir); From e7805eaf4c4b21af38c2c9d72e78e092d1242761 Mon Sep 17 00:00:00 2001 From: Phil Quitslund Date: Wed, 19 Jul 2017 12:08:29 -0700 Subject: [PATCH 052/170] Update SDK constraint to be 2.0.0 dev friendly. --- pkgs/package_config/pubspec.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index eaef83e3a..a629eafef 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,15 +1,15 @@ name: package_config -version: 1.0.1 +version: 1.0.2 description: Support for working with Package Resolution config files. author: Dart Team homepage: https://github.com/dart-lang/package_config environment: - sdk: '>=1.11.0-dev.0.0 <2.0.0' + sdk: '>=1.11.0 <2.0.0-dev.infinity' dependencies: charcode: ^1.1.0 path: ^1.0.0 dev_dependencies: - test: '>=0.12.0 <0.13.0' + test: ^0.12.0 From 4160a04201c62ea197f4df9ab0b4007dfc255237 Mon Sep 17 00:00:00 2001 From: Phil Quitslund Date: Wed, 19 Jul 2017 12:10:16 -0700 Subject: [PATCH 053/170] Update CHANGELOG.md --- pkgs/package_config/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index c03367853..c17c67498 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.2 + +- Update SDK constraint to be 2.0.0 dev friendly. + ## 1.0.1 - Fix test to not write to sink after it's closed. From 9d1c4cc5a4ba9740ef46bbebeee73fe882e22f8a Mon Sep 17 00:00:00 2001 From: Phil Quitslund Date: Wed, 19 Jul 2017 12:19:59 -0700 Subject: [PATCH 054/170] Rename .analysis_options to analysis_options.yaml --- pkgs/package_config/{.analysis_options => analysis_options.yaml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename pkgs/package_config/{.analysis_options => analysis_options.yaml} (100%) diff --git a/pkgs/package_config/.analysis_options b/pkgs/package_config/analysis_options.yaml similarity index 100% rename from pkgs/package_config/.analysis_options rename to pkgs/package_config/analysis_options.yaml From 5312c5efd70ea519f5356b83cdfab355e2729d1b Mon Sep 17 00:00:00 2001 From: pq Date: Thu, 3 Aug 2017 15:48:10 -0700 Subject: [PATCH 055/170] Make trusty default distro explicit. --- pkgs/package_config/.travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/pkgs/package_config/.travis.yml b/pkgs/package_config/.travis.yml index 7a20d25b2..d7febddd1 100644 --- a/pkgs/package_config/.travis.yml +++ b/pkgs/package_config/.travis.yml @@ -1,4 +1,5 @@ language: dart dart: dev script: ./tool/travis.sh +dist: trusty sudo: false From ac2c0728aac408b177fd997ef170df830f881ba2 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Fri, 22 Sep 2017 12:05:30 -0700 Subject: [PATCH 056/170] Stop using deprecated pkg/test APIs - throw an HttpException ...instead of a String --- pkgs/package_config/lib/discovery.dart | 4 ++-- pkgs/package_config/pubspec.yaml | 2 +- pkgs/package_config/test/discovery_analysis_test.dart | 2 +- pkgs/package_config/test/discovery_test.dart | 9 ++++++--- pkgs/package_config/test/parse_test.dart | 8 +++++--- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/pkgs/package_config/lib/discovery.dart b/pkgs/package_config/lib/discovery.dart index 4c09eecfb..2abf443fb 100644 --- a/pkgs/package_config/lib/discovery.dart +++ b/pkgs/package_config/lib/discovery.dart @@ -210,8 +210,8 @@ Future> _httpGet(Uri uri) async { HttpClientRequest request = await client.getUrl(uri); HttpClientResponse response = await request.close(); if (response.statusCode != HttpStatus.OK) { - throw 'Failure getting $uri: ' - '${response.statusCode} ${response.reasonPhrase}'; + throw new HttpException('${response.statusCode} ${response.reasonPhrase}', + uri: uri); } List> splitContent = await response.toList(); int totalLength = 0; diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index a629eafef..89b1855a9 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 1.0.2 +version: 1.0.3-dev description: Support for working with Package Resolution config files. author: Dart Team homepage: https://github.com/dart-lang/package_config diff --git a/pkgs/package_config/test/discovery_analysis_test.dart b/pkgs/package_config/test/discovery_analysis_test.dart index 0a2876726..c819a9074 100644 --- a/pkgs/package_config/test/discovery_analysis_test.dart +++ b/pkgs/package_config/test/discovery_analysis_test.dart @@ -78,7 +78,7 @@ void validatePackagesDir(Packages resolver, Uri location) { if (location.scheme == "file") { expect(resolver.packages, unorderedEquals(["foo", "bar", "baz"])); } else { - expect(() => resolver.packages, throws); + expect(() => resolver.packages, throwsUnsupportedError); } } diff --git a/pkgs/package_config/test/discovery_test.dart b/pkgs/package_config/test/discovery_test.dart index 897063f52..cbbca9a5d 100644 --- a/pkgs/package_config/test/discovery_test.dart +++ b/pkgs/package_config/test/discovery_test.dart @@ -41,7 +41,7 @@ void validatePackagesDir(Packages resolver, Uri location) { if (location.scheme == "file") { expect(resolver.packages, unorderedEquals(["foo", "bar", "baz"])); } else { - expect(() => resolver.packages, throws); + expect(() => resolver.packages, throwsUnsupportedError); } } @@ -228,13 +228,16 @@ main() { generalTest("loadPackagesFile not found", {}, (Uri directory) async { Uri file = directory.resolve(".packages"); - expect(loadPackagesFile(file), throws); + expect( + loadPackagesFile(file), + throwsA(anyOf(new isInstanceOf(), + new isInstanceOf()))); }); generalTest("loadPackagesFile syntax error", {".packages": "syntax error"}, (Uri directory) async { Uri file = directory.resolve(".packages"); - expect(loadPackagesFile(file), throws); + expect(loadPackagesFile(file), throwsFormatException); }); generalTest("getPackagesDir", { diff --git a/pkgs/package_config/test/parse_test.dart b/pkgs/package_config/test/parse_test.dart index 7a2fce7e2..fb3a6fab4 100644 --- a/pkgs/package_config/test/parse_test.dart +++ b/pkgs/package_config/test/parse_test.dart @@ -102,16 +102,18 @@ main() { for (int i = 0; i <= 255; i++) { if (map[i] == true) continue; var char = new String.fromCharCode(i); - expect(() => doParse("x${char}x:x", null), throws); + expect(() => doParse("x${char}x:x", null), + anyOf(throwsNoSuchMethodError, throwsFormatException)); } }); test("no escapes", () { - expect(() => doParse("x%41x:x", base), throws); + expect(() => doParse("x%41x:x", base), throwsFormatException); }); test("same name twice", () { - expect(() => doParse(singleRelativeSample * 2, base), throws); + expect( + () => doParse(singleRelativeSample * 2, base), throwsFormatException); }); for (String invalidSample in invalid) { From f0823a14d4f9cf4e9418dec716b2251087216de3 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Fri, 22 Sep 2017 12:06:22 -0700 Subject: [PATCH 057/170] Use travis tasks --- pkgs/package_config/.travis.yml | 18 +++++++++++++++--- pkgs/package_config/tool/travis.sh | 17 ----------------- 2 files changed, 15 insertions(+), 20 deletions(-) delete mode 100755 pkgs/package_config/tool/travis.sh diff --git a/pkgs/package_config/.travis.yml b/pkgs/package_config/.travis.yml index d7febddd1..24d56a3aa 100644 --- a/pkgs/package_config/.travis.yml +++ b/pkgs/package_config/.travis.yml @@ -1,5 +1,17 @@ language: dart -dart: dev -script: ./tool/travis.sh -dist: trusty sudo: false +dart: + - dev + - stable +dart_task: + - test + - dartfmt + - dartanalyzer: --fatal-warnings . + +# Only building master means that we don't run two builds for each pull request. +branches: + only: [master] + +cache: + directories: + - $HOME/.pub-cache diff --git a/pkgs/package_config/tool/travis.sh b/pkgs/package_config/tool/travis.sh deleted file mode 100755 index 6d8cfe375..000000000 --- a/pkgs/package_config/tool/travis.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -# Copyright (c) 2015, 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. - -# Fast fail the script on failures. -set -e - -# Verify that the libraries are error free. -dartanalyzer --fatal-warnings \ - lib/packages.dart \ - test/all.dart - -# Run the tests. -dart test/all.dart - From 25cf81831c5baf6c616c73bbca5325fbcb20cc4c Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Fri, 22 Sep 2017 12:06:38 -0700 Subject: [PATCH 058/170] Remove unneeded SDK constraint --- pkgs/package_config/CHANGELOG.md | 4 ++++ pkgs/package_config/pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index c17c67498..a9ac0ec03 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.3 + +- Removed unneeded dependency constraint on SDK. + ## 1.0.2 - Update SDK constraint to be 2.0.0 dev friendly. diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 89b1855a9..3d81eb2a4 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -5,7 +5,7 @@ author: Dart Team homepage: https://github.com/dart-lang/package_config environment: - sdk: '>=1.11.0 <2.0.0-dev.infinity' + sdk: '>=1.11.0 <2.0.0' dependencies: charcode: ^1.1.0 From f37ecac7ba3642c72f55bc0d8da7283ddb2874f9 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Fri, 22 Sep 2017 12:06:44 -0700 Subject: [PATCH 059/170] dartfmt --- pkgs/package_config/lib/discovery.dart | 2 ++ pkgs/package_config/lib/discovery_analysis.dart | 2 ++ pkgs/package_config/test/discovery_test.dart | 2 ++ pkgs/package_config/test/parse_write_test.dart | 1 + 4 files changed, 7 insertions(+) diff --git a/pkgs/package_config/lib/discovery.dart b/pkgs/package_config/lib/discovery.dart index 2abf443fb..020d99a80 100644 --- a/pkgs/package_config/lib/discovery.dart +++ b/pkgs/package_config/lib/discovery.dart @@ -33,6 +33,7 @@ Future loadPackagesFile(Uri packagesFile, Map packageMap = pkgfile.parse(bytes, packagesFile); return new MapPackages(packageMap); } + if (packagesFile.scheme == "file") { File file = new File.fromUri(packagesFile); return parseBytes(await file.readAsBytes()); @@ -125,6 +126,7 @@ FileSystemEntity _findPackagesFile(String workingDirectory) { if (file.existsSync()) return file; return null; } + // Check for $cwd/.packages var packagesCfgFile = checkForConfigFile(dir); if (packagesCfgFile != null) return packagesCfgFile; diff --git a/pkgs/package_config/lib/discovery_analysis.dart b/pkgs/package_config/lib/discovery_analysis.dart index ce7e98a1a..67798e129 100644 --- a/pkgs/package_config/lib/discovery_analysis.dart +++ b/pkgs/package_config/lib/discovery_analysis.dart @@ -91,6 +91,7 @@ abstract class PackageContext { contexts = oldContexts; } } + findRoots(directory); // If the root is not itself context root, add a the wrapper context. if (contexts.length == 1 && contexts[0].directory == directory) { @@ -115,6 +116,7 @@ class _PackageContext implements PackageContext { recurse(child); } } + recurse(this); return result; } diff --git a/pkgs/package_config/test/discovery_test.dart b/pkgs/package_config/test/discovery_test.dart index cbbca9a5d..6a5bcdee9 100644 --- a/pkgs/package_config/test/discovery_test.dart +++ b/pkgs/package_config/test/discovery_test.dart @@ -169,6 +169,7 @@ main() { } throw "not found"; } + // A non-file: location with no .packages or packages/: // Assumes a packages dir exists, and resolves relative to that. Packages resolver; @@ -189,6 +190,7 @@ main() { Future> loader(Uri file) async { throw "not found"; } + // A non-file: location with no .packages or packages/: // Assumes a packages dir exists, and resolves relative to that. Packages resolver; diff --git a/pkgs/package_config/test/parse_write_test.dart b/pkgs/package_config/test/parse_write_test.dart index 430218791..b963eb5b5 100644 --- a/pkgs/package_config/test/parse_write_test.dart +++ b/pkgs/package_config/test/parse_write_test.dart @@ -34,6 +34,7 @@ main() { }); }); } + var lowerDir = baseDir.resolve("path3/path4/"); var higherDir = baseDir.resolve("../"); var parallelDir = baseDir.resolve("../path3/"); From cae7ab5e1cb56408a2b7cbd66fbcd7da266dd27b Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Fri, 22 Sep 2017 12:28:07 -0700 Subject: [PATCH 060/170] Prepare for release --- pkgs/package_config/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 3d81eb2a4..bd2c6abaf 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 1.0.3-dev +version: 1.0.3 description: Support for working with Package Resolution config files. author: Dart Team homepage: https://github.com/dart-lang/package_config From 0480257ce840ae9b9f64b5d6f4eb7484a8c690d3 Mon Sep 17 00:00:00 2001 From: pq Date: Sat, 10 Mar 2018 14:43:00 -0800 Subject: [PATCH 061/170] Update .gitignore to new `dart_tool` pub cache See: https://github.com/dart-lang/sdk/issues/32030 --- pkgs/package_config/.gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/package_config/.gitignore b/pkgs/package_config/.gitignore index a8b93ef38..4b1d87897 100644 --- a/pkgs/package_config/.gitignore +++ b/pkgs/package_config/.gitignore @@ -1,5 +1,5 @@ .packages -.pub +.dart_tool packages pubspec.lock doc/api/ From 589e7f23facd09b896b9b67bb63459dd8d79f705 Mon Sep 17 00:00:00 2001 From: Phil Quitslund Date: Sat, 10 Mar 2018 17:31:14 -0800 Subject: [PATCH 062/170] Update .gitignore --- pkgs/package_config/.gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/package_config/.gitignore b/pkgs/package_config/.gitignore index 4b1d87897..3b32e387c 100644 --- a/pkgs/package_config/.gitignore +++ b/pkgs/package_config/.gitignore @@ -1,5 +1,5 @@ .packages -.dart_tool +.dart_tool/ packages pubspec.lock doc/api/ From 7666429f5fa4adf5ca7cd9460b5ae25f256fcd2d Mon Sep 17 00:00:00 2001 From: Phil Quitslund Date: Mon, 12 Mar 2018 09:30:31 -0700 Subject: [PATCH 063/170] Update .gitignore --- pkgs/package_config/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/pkgs/package_config/.gitignore b/pkgs/package_config/.gitignore index 3b32e387c..e41fc1916 100644 --- a/pkgs/package_config/.gitignore +++ b/pkgs/package_config/.gitignore @@ -1,4 +1,5 @@ .packages +.pub .dart_tool/ packages pubspec.lock From c15609e86734c64496bee259b55510bb214c3648 Mon Sep 17 00:00:00 2001 From: pq Date: Thu, 21 Jun 2018 10:50:26 -0700 Subject: [PATCH 064/170] core api use migrations --- pkgs/package_config/lib/packages_file.dart | 7 ++----- pkgs/package_config/lib/src/packages_impl.dart | 7 ++----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/pkgs/package_config/lib/packages_file.dart b/pkgs/package_config/lib/packages_file.dart index 0f1a6e635..85de1942d 100644 --- a/pkgs/package_config/lib/packages_file.dart +++ b/pkgs/package_config/lib/packages_file.dart @@ -159,12 +159,12 @@ Uri _relativize(Uri uri, Uri baseUri) { } } - baseUri = _normalizePath(baseUri); + baseUri = baseUri.normalizePath(); List base = baseUri.pathSegments.toList(); if (base.isNotEmpty) { base = new List.from(base)..removeLast(); } - uri = _normalizePath(uri); + uri = uri.normalizePath(); List target = uri.pathSegments.toList(); if (target.isNotEmpty && target.last.isEmpty) target.removeLast(); int index = 0; @@ -186,6 +186,3 @@ Uri _relativize(Uri uri, Uri baseUri) { return uri; } } - -// TODO: inline to uri.normalizePath() when we move to 1.11 -Uri _normalizePath(Uri uri) => new Uri().resolveUri(uri); diff --git a/pkgs/package_config/lib/src/packages_impl.dart b/pkgs/package_config/lib/src/packages_impl.dart index df89e4623..e89d94d22 100644 --- a/pkgs/package_config/lib/src/packages_impl.dart +++ b/pkgs/package_config/lib/src/packages_impl.dart @@ -23,7 +23,7 @@ class NoPackages implements Packages { packageUri, "packageUri", 'No package named "$packageName"'); } - Iterable get packages => new Iterable.generate(0); + Iterable get packages => new Iterable.empty(); Map asMap() => const {}; } @@ -34,7 +34,7 @@ class NoPackages implements Packages { /// member abstract class PackagesBase implements Packages { Uri resolve(Uri packageUri, {Uri notFound(Uri packageUri)}) { - packageUri = _normalizePath(packageUri); + packageUri = packageUri.normalizePath(); String packageName = checkValidPackageUri(packageUri); Uri packageBase = getBase(packageName); if (packageBase == null) { @@ -51,9 +51,6 @@ abstract class PackagesBase implements Packages { /// Returns `null` if no package exists with that name, and that can be /// determined. Uri getBase(String packageName); - - // TODO: inline to uri.normalizePath() when we move to 1.11 - static Uri _normalizePath(Uri uri) => new Uri().resolveUri(uri); } /// A [Packages] implementation based on an existing map. From 0ef6277d76402930b87be453b9b2bb7db2d6dd12 Mon Sep 17 00:00:00 2001 From: pq Date: Thu, 21 Jun 2018 14:01:44 -0700 Subject: [PATCH 065/170] dart2 --- pkgs/package_config/pubspec.yaml | 4 ++-- pkgs/package_config/test/discovery_test.dart | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index bd2c6abaf..56d44f5ff 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -5,11 +5,11 @@ author: Dart Team homepage: https://github.com/dart-lang/package_config environment: - sdk: '>=1.11.0 <2.0.0' + sdk: '>=2.0.0-dev <2.0.0' dependencies: charcode: ^1.1.0 path: ^1.0.0 dev_dependencies: - test: ^0.12.0 + test: ^1.0.0 diff --git a/pkgs/package_config/test/discovery_test.dart b/pkgs/package_config/test/discovery_test.dart index 6a5bcdee9..2c60db389 100644 --- a/pkgs/package_config/test/discovery_test.dart +++ b/pkgs/package_config/test/discovery_test.dart @@ -289,7 +289,7 @@ void httpTest(String name, Map description, Future httpTest(Uri directory)) { if (path.startsWith('/')) path = path.substring(1); if (path.endsWith('/')) path = path.substring(0, path.length - 1); var parts = path.split('/'); - var fileOrDir = description; + dynamic fileOrDir = description; for (int i = 0; i < parts.length; i++) { fileOrDir = fileOrDir[parts[i]]; if (fileOrDir == null) { From 8785d418144ccd4efa2525375f91286c9acf0300 Mon Sep 17 00:00:00 2001 From: Phil Quitslund Date: Thu, 21 Jun 2018 14:05:58 -0700 Subject: [PATCH 066/170] Update .travis.yml --- pkgs/package_config/.travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/pkgs/package_config/.travis.yml b/pkgs/package_config/.travis.yml index 24d56a3aa..655bf3dc1 100644 --- a/pkgs/package_config/.travis.yml +++ b/pkgs/package_config/.travis.yml @@ -2,7 +2,6 @@ language: dart sudo: false dart: - dev - - stable dart_task: - test - dartfmt From ae24ecbe7ee7ca69bd52af8f519c371a63631585 Mon Sep 17 00:00:00 2001 From: pq Date: Mon, 2 Jul 2018 16:27:38 -0700 Subject: [PATCH 067/170] Remove `strong`. --- pkgs/package_config/analysis_options.yaml | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 pkgs/package_config/analysis_options.yaml diff --git a/pkgs/package_config/analysis_options.yaml b/pkgs/package_config/analysis_options.yaml deleted file mode 100644 index a10d4c5a0..000000000 --- a/pkgs/package_config/analysis_options.yaml +++ /dev/null @@ -1,2 +0,0 @@ -analyzer: - strong-mode: true From 5e14a449fa4fabf99960ad7f3df0aab91a0a5b23 Mon Sep 17 00:00:00 2001 From: pq Date: Sat, 14 Jul 2018 08:16:37 -0700 Subject: [PATCH 068/170] bump sdk constraint to 3.0.0 --- pkgs/package_config/CHANGELOG.md | 4 ++++ pkgs/package_config/pubspec.yaml | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index a9ac0ec03..8c179c708 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.4 + +- Set max SDK version to <3.0.0. + ## 1.0.3 - Removed unneeded dependency constraint on SDK. diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 56d44f5ff..c58468167 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,11 +1,11 @@ name: package_config -version: 1.0.3 +version: 1.0.4 description: Support for working with Package Resolution config files. author: Dart Team homepage: https://github.com/dart-lang/package_config environment: - sdk: '>=2.0.0-dev <2.0.0' + sdk: '>=2.0.0-dev <3.0.0' dependencies: charcode: ^1.1.0 From cb0b2b16c733abc7e6c1d472da0f1ad18b9f326c Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Wed, 18 Jul 2018 13:38:22 -0700 Subject: [PATCH 069/170] misc: fix usage of deprecated SDK constants (dart-lang/package_config#50) Also fixed usage of deprecated matcher classes --- pkgs/package_config/CHANGELOG.md | 4 ++++ pkgs/package_config/lib/discovery.dart | 2 +- pkgs/package_config/pubspec.yaml | 4 ++-- pkgs/package_config/test/discovery_test.dart | 6 +++--- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index 8c179c708..e802d7deb 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.5 + +- Fix usage of SDK constants. + ## 1.0.4 - Set max SDK version to <3.0.0. diff --git a/pkgs/package_config/lib/discovery.dart b/pkgs/package_config/lib/discovery.dart index 020d99a80..57584b682 100644 --- a/pkgs/package_config/lib/discovery.dart +++ b/pkgs/package_config/lib/discovery.dart @@ -211,7 +211,7 @@ Future> _httpGet(Uri uri) async { HttpClient client = new HttpClient(); HttpClientRequest request = await client.getUrl(uri); HttpClientResponse response = await request.close(); - if (response.statusCode != HttpStatus.OK) { + if (response.statusCode != HttpStatus.ok) { throw new HttpException('${response.statusCode} ${response.reasonPhrase}', uri: uri); } diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index c58468167..4bad1cf52 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 1.0.4 +version: 1.0.5 description: Support for working with Package Resolution config files. author: Dart Team homepage: https://github.com/dart-lang/package_config @@ -12,4 +12,4 @@ dependencies: path: ^1.0.0 dev_dependencies: - test: ^1.0.0 + test: ^1.3.0 diff --git a/pkgs/package_config/test/discovery_test.dart b/pkgs/package_config/test/discovery_test.dart index 2c60db389..282427289 100644 --- a/pkgs/package_config/test/discovery_test.dart +++ b/pkgs/package_config/test/discovery_test.dart @@ -232,8 +232,8 @@ main() { Uri file = directory.resolve(".packages"); expect( loadPackagesFile(file), - throwsA(anyOf(new isInstanceOf(), - new isInstanceOf()))); + throwsA(anyOf(new TypeMatcher(), + new TypeMatcher()))); }); generalTest("loadPackagesFile syntax error", {".packages": "syntax error"}, @@ -280,7 +280,7 @@ void httpTest(String name, Map description, Future httpTest(Uri directory)) { var serverSub; var uri; setUp(() { - return HttpServer.bind(InternetAddress.LOOPBACK_IP_V4, 0).then((server) { + return HttpServer.bind(InternetAddress.loopbackIPv4, 0).then((server) { uri = new Uri( scheme: "http", host: "127.0.0.1", port: server.port, path: "/"); serverSub = server.listen((HttpRequest request) { From 2c3ab9e81f1964ae27329b8a0ff4563c23b48208 Mon Sep 17 00:00:00 2001 From: Sam Rawlins Date: Thu, 23 May 2019 11:16:58 -0700 Subject: [PATCH 070/170] Fix missing_return violation newly enforced in Dart ~2.3.2-dev.0.1 --- pkgs/package_config/test/discovery_analysis_test.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/pkgs/package_config/test/discovery_analysis_test.dart b/pkgs/package_config/test/discovery_analysis_test.dart index c819a9074..e43245468 100644 --- a/pkgs/package_config/test/discovery_analysis_test.dart +++ b/pkgs/package_config/test/discovery_analysis_test.dart @@ -41,6 +41,7 @@ main() { var map = ctx.asMap(); expect(map.keys.map((dir) => dir.path), unorderedEquals([directory.path, fooDir.path, barDir.path])); + return null; }); } From 393f6d532ba89ba6e23efef9772f26903cc56dde Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Wed, 31 Jul 2019 21:06:27 -0700 Subject: [PATCH 071/170] Delete codereview.settings --- pkgs/package_config/codereview.settings | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 pkgs/package_config/codereview.settings diff --git a/pkgs/package_config/codereview.settings b/pkgs/package_config/codereview.settings deleted file mode 100644 index 1099f0594..000000000 --- a/pkgs/package_config/codereview.settings +++ /dev/null @@ -1,3 +0,0 @@ -CODE_REVIEW_SERVER: https://codereview.chromium.org/ -VIEW_VC: https://github.com/dart-lang/package_config/commit/ -CC_LIST: reviews@dartlang.org From 62c12f20026177ebdf7f6fa12040501ff867dbb9 Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Fri, 16 Aug 2019 15:04:35 +0200 Subject: [PATCH 072/170] Add support for default package and metadata. (dart-lang/package_config#53) --- pkgs/package_config/CHANGELOG.md | 7 ++ .../lib/discovery_analysis.dart | 22 ++--- pkgs/package_config/lib/packages.dart | 36 ++++++++ pkgs/package_config/lib/packages_file.dart | 50 ++++++++--- .../package_config/lib/src/packages_impl.dart | 37 ++++++++- pkgs/package_config/pubspec.yaml | 2 +- pkgs/package_config/test/parse_test.dart | 82 ++++++++++++++++++- 7 files changed, 208 insertions(+), 28 deletions(-) diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index e802d7deb..db4bb00d6 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -1,3 +1,10 @@ +## 1.1.0 + +- Allow parsing files with default-package entries and metadata. + A default-package entry has an empty key and a valid package name + as value. + Metadata is attached as fragments to base URIs. + ## 1.0.5 - Fix usage of SDK constants. diff --git a/pkgs/package_config/lib/discovery_analysis.dart b/pkgs/package_config/lib/discovery_analysis.dart index 67798e129..d623303c8 100644 --- a/pkgs/package_config/lib/discovery_analysis.dart +++ b/pkgs/package_config/lib/discovery_analysis.dart @@ -59,22 +59,22 @@ abstract class PackageContext { static PackageContext findAll(Directory directory, {Packages root: Packages.noPackages}) { if (!directory.existsSync()) { - throw new ArgumentError("Directory not found: $directory"); + throw ArgumentError("Directory not found: $directory"); } var contexts = []; void findRoots(Directory directory) { Packages packages; List oldContexts; - File packagesFile = new File(path.join(directory.path, ".packages")); + File packagesFile = File(path.join(directory.path, ".packages")); if (packagesFile.existsSync()) { packages = _loadPackagesFile(packagesFile); oldContexts = contexts; contexts = []; } else { Directory packagesDir = - new Directory(path.join(directory.path, "packages")); + Directory(path.join(directory.path, "packages")); if (packagesDir.existsSync()) { - packages = new FilePackagesDirectoryPackages(packagesDir); + packages = FilePackagesDirectoryPackages(packagesDir); oldContexts = contexts; contexts = []; } @@ -87,7 +87,7 @@ abstract class PackageContext { } } if (packages != null) { - oldContexts.add(new _PackageContext(directory, packages, contexts)); + oldContexts.add(_PackageContext(directory, packages, contexts)); contexts = oldContexts; } } @@ -97,7 +97,7 @@ abstract class PackageContext { if (contexts.length == 1 && contexts[0].directory == directory) { return contexts[0]; } - return new _PackageContext(directory, root, contexts); + return _PackageContext(directory, root, contexts); } } @@ -106,10 +106,10 @@ class _PackageContext implements PackageContext { final Packages packages; final List children; _PackageContext(this.directory, this.packages, List children) - : children = new List.unmodifiable(children); + : children = List.unmodifiable(children); Map asMap() { - var result = new HashMap(); + var result = HashMap(); recurse(_PackageContext current) { result[current.directory] = current.packages; for (var child in current.children) { @@ -124,7 +124,7 @@ class _PackageContext implements PackageContext { PackageContext operator [](Directory directory) { String path = directory.path; if (!path.startsWith(this.directory.path)) { - throw new ArgumentError("Not inside $path: $directory"); + throw ArgumentError("Not inside $path: $directory"); } _PackageContext current = this; // The current path is know to agree with directory until deltaIndex. @@ -160,8 +160,8 @@ class _PackageContext implements PackageContext { } Packages _loadPackagesFile(File file) { - var uri = new Uri.file(file.path); + var uri = Uri.file(file.path); var bytes = file.readAsBytesSync(); var map = pkgfile.parse(bytes, uri); - return new MapPackages(map); + return MapPackages(map); } diff --git a/pkgs/package_config/lib/packages.dart b/pkgs/package_config/lib/packages.dart index 890f4485c..886fbc83c 100644 --- a/pkgs/package_config/lib/packages.dart +++ b/pkgs/package_config/lib/packages.dart @@ -45,6 +45,32 @@ abstract class Packages { /// and getting `packages` from such a `Packages` object will throw. Iterable get packages; + /// Retrieve metadata associated with a package. + /// + /// Metadata have string keys and values, and are looked up by key. + /// + /// Returns `null` if the argument is not a valid package name, + /// or if the package is not one of the packages configured by + /// this packages object, or if the package does not have associated + /// metadata with the provided [key]. + /// + /// Not all `Packages` objects can support metadata. + /// Those will always return `null`. + String packageMetadata(String packageName, String key); + + /// Retrieve metadata associated with a library. + /// + /// If [libraryUri] is a `package:` URI, the returned value + /// is the same that would be returned by [packageMetadata] with + /// the package's name and the same key. + /// + /// If [libraryUri] is not a `package:` URI, and this [Packages] + /// object has a [defaultPackageName], then the [key] is looked + /// up on the default package instead. + /// + /// Otherwise the result is `null`. + String libraryMetadata(Uri libraryUri, String key); + /// Return the names-to-base-URI mapping of the available packages. /// /// Returns a map from package name to a base URI. @@ -55,4 +81,14 @@ abstract class Packages { /// Some `Packages` objects are unable to find the package names, /// and calling `asMap` on such a `Packages` object will throw. Map asMap(); + + /// The name of the "default package". + /// + /// A default package is a package that *non-package* libraries + /// may be considered part of for some purposes. + /// + /// The value is `null` if there is no default package. + /// Not all implementations of [Packages] supports a default package, + /// and will always have a `null` value for those. + String get defaultPackageName; } diff --git a/pkgs/package_config/lib/packages_file.dart b/pkgs/package_config/lib/packages_file.dart index 85de1942d..284d8e90a 100644 --- a/pkgs/package_config/lib/packages_file.dart +++ b/pkgs/package_config/lib/packages_file.dart @@ -22,8 +22,15 @@ import "src/util.dart" show isValidPackageName; /// If the content was read from a file, `baseLocation` should be the /// location of that file. /// +/// If [allowDefaultPackage] is set to true, an entry with an empty package name +/// is accepted. This entry does not correspond to a package, but instead +/// represents a *default package* which non-package libraries may be considered +/// part of in some cases. The value of that entry must be a valid package name. +/// /// Returns a simple mapping from package name to package location. -Map parse(List source, Uri baseLocation) { +/// If default package is allowed, the map maps the empty string to the default package's name. +Map parse(List source, Uri baseLocation, + {bool allowDefaultPackage = false}) { int index = 0; Map result = {}; while (index < source.length) { @@ -36,7 +43,10 @@ Map parse(List source, Uri baseLocation) { continue; } if (char == $colon) { - throw new FormatException("Missing package name", source, index - 1); + if (!allowDefaultPackage) { + throw FormatException("Missing package name", source, index - 1); + } + separatorIndex = index - 1; } isComment = char == $hash; while (index < source.length) { @@ -50,22 +60,36 @@ Map parse(List source, Uri baseLocation) { } if (isComment) continue; if (separatorIndex < 0) { - throw new FormatException("No ':' on line", source, index - 1); + throw FormatException("No ':' on line", source, index - 1); } var packageName = new String.fromCharCodes(source, start, separatorIndex); - if (!isValidPackageName(packageName)) { - throw new FormatException("Not a valid package name", packageName, 0); + if (packageName.isEmpty + ? !allowDefaultPackage + : !isValidPackageName(packageName)) { + throw FormatException("Not a valid package name", packageName, 0); } - var packageUri = new String.fromCharCodes(source, separatorIndex + 1, end); - var packageLocation = Uri.parse(packageUri); - packageLocation = baseLocation.resolveUri(packageLocation); - if (!packageLocation.path.endsWith('/')) { - packageLocation = - packageLocation.replace(path: packageLocation.path + "/"); + var packageValue = + new String.fromCharCodes(source, separatorIndex + 1, end); + Uri packageLocation; + if (packageName.isEmpty) { + if (!isValidPackageName(packageValue)) { + throw FormatException( + "Default package entry value is not a valid package name"); + } + packageLocation = Uri(path: packageValue); + } else { + packageLocation = baseLocation.resolve(packageValue); + if (!packageLocation.path.endsWith('/')) { + packageLocation = + packageLocation.replace(path: packageLocation.path + "/"); + } } if (result.containsKey(packageName)) { - throw new FormatException( - "Same package name occured twice.", source, start); + if (packageName.isEmpty) { + throw FormatException( + "More than one default package entry", source, start); + } + throw FormatException("Same package name occured twice", source, start); } result[packageName] = packageLocation; } diff --git a/pkgs/package_config/lib/src/packages_impl.dart b/pkgs/package_config/lib/src/packages_impl.dart index e89d94d22..817002f1e 100644 --- a/pkgs/package_config/lib/src/packages_impl.dart +++ b/pkgs/package_config/lib/src/packages_impl.dart @@ -26,6 +26,12 @@ class NoPackages implements Packages { Iterable get packages => new Iterable.empty(); Map asMap() => const {}; + + String get defaultPackageName => null; + + String packageMetadata(String packageName, String key) => null; + + String libraryMetadata(Uri libraryUri, String key) => null; } /// Base class for [Packages] implementations. @@ -51,6 +57,12 @@ abstract class PackagesBase implements Packages { /// Returns `null` if no package exists with that name, and that can be /// determined. Uri getBase(String packageName); + + String get defaultPackageName => null; + + String packageMetadata(String packageName, String key) => null; + + String libraryMetadata(Uri libraryUri, String key) => null; } /// A [Packages] implementation based on an existing map. @@ -58,11 +70,34 @@ class MapPackages extends PackagesBase { final Map _mapping; MapPackages(this._mapping); - Uri getBase(String packageName) => _mapping[packageName]; + Uri getBase(String packageName) => + packageName.isEmpty ? null : _mapping[packageName]; Iterable get packages => _mapping.keys; Map asMap() => new UnmodifiableMapView(_mapping); + + String get defaultPackageName => _mapping[""]?.toString(); + + String packageMetadata(String packageName, String key) { + if (packageName.isEmpty) return null; + Uri uri = _mapping[packageName]; + if (uri == null || !uri.hasFragment) return null; + // This can be optimized, either by caching the map or by + // parsing incrementally instead of parsing the entire fragment. + return Uri.splitQueryString(uri.fragment)[key]; + } + + String libraryMetadata(Uri libraryUri, String key) { + if (libraryUri.isScheme("package")) { + return packageMetadata(libraryUri.pathSegments.first, key); + } + var defaultPackageNameUri = _mapping[""]; + if (defaultPackageNameUri != null) { + return packageMetadata(defaultPackageNameUri.toString(), key); + } + return null; + } } /// A [Packages] implementation based on a remote (e.g., HTTP) directory. diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 4bad1cf52..a69096d58 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 1.0.5 +version: 1.1.0-pre description: Support for working with Package Resolution config files. author: Dart Team homepage: https://github.com/dart-lang/package_config diff --git a/pkgs/package_config/test/parse_test.dart b/pkgs/package_config/test/parse_test.dart index fb3a6fab4..b9b1bb510 100644 --- a/pkgs/package_config/test/parse_test.dart +++ b/pkgs/package_config/test/parse_test.dart @@ -116,6 +116,82 @@ main() { () => doParse(singleRelativeSample * 2, base), throwsFormatException); }); + test("disallow default package", () { + expect(() => doParse(":foo", base, allowDefaultPackage: false), + throwsFormatException); + }); + + test("allow default package", () { + var packages = doParse(":foo", base, allowDefaultPackage: true); + expect(packages.defaultPackageName, "foo"); + }); + + test("allow default package name with dot", () { + var packages = doParse(":foo.bar", base, allowDefaultPackage: true); + expect(packages.defaultPackageName, "foo.bar"); + }); + + test("not two default packages", () { + expect(() => doParse(":foo\n:bar", base, allowDefaultPackage: true), + throwsFormatException); + }); + + test("default package invalid package name", () { + // Not a valid *package name*. + expect(() => doParse(":foo/bar", base, allowDefaultPackage: true), + throwsFormatException); + }); + + group("metadata", () { + var packages = doParse( + ":foo\n" + "foo:foo#metafoo=1\n" + "bar:bar#metabar=2\n" + "baz:baz\n" + "qux:qux#metaqux1=3&metaqux2=4\n", + base, + allowDefaultPackage: true); + test("non-existing", () { + // non-package name. + expect(packages.packageMetadata("///", "f"), null); + expect(packages.packageMetadata("", "f"), null); + // unconfigured package name. + expect(packages.packageMetadata("absent", "f"), null); + // package name without that metadata + expect(packages.packageMetadata("foo", "notfoo"), null); + }); + test("lookup", () { + expect(packages.packageMetadata("foo", "metafoo"), "1"); + expect(packages.packageMetadata("bar", "metabar"), "2"); + expect(packages.packageMetadata("qux", "metaqux1"), "3"); + expect(packages.packageMetadata("qux", "metaqux2"), "4"); + }); + test("by library URI", () { + expect( + packages.libraryMetadata( + Uri.parse("package:foo/index.dart"), "metafoo"), + "1"); + expect( + packages.libraryMetadata( + Uri.parse("package:bar/index.dart"), "metabar"), + "2"); + expect( + packages.libraryMetadata( + Uri.parse("package:qux/index.dart"), "metaqux1"), + "3"); + expect( + packages.libraryMetadata( + Uri.parse("package:qux/index.dart"), "metaqux2"), + "4"); + }); + test("by default package", () { + expect( + packages.libraryMetadata( + Uri.parse("file:///whatever.dart"), "metafoo"), + "1"); + }); + }); + for (String invalidSample in invalid) { test("invalid '$invalidSample'", () { var result; @@ -130,8 +206,10 @@ main() { } } -Packages doParse(String sample, Uri baseUri) { - Map map = parse(sample.codeUnits, baseUri); +Packages doParse(String sample, Uri baseUri, + {bool allowDefaultPackage = false}) { + Map map = parse(sample.codeUnits, baseUri, + allowDefaultPackage: allowDefaultPackage); return new MapPackages(map); } From 95dada207519f41f974e8e63d7b702d47f8aff25 Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Fri, 16 Aug 2019 15:06:22 +0200 Subject: [PATCH 073/170] Add .vscode/ to .gitignore. --- pkgs/package_config/.gitignore | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 pkgs/package_config/.gitignore diff --git a/pkgs/package_config/.gitignore b/pkgs/package_config/.gitignore deleted file mode 100644 index e41fc1916..000000000 --- a/pkgs/package_config/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -.packages -.pub -.dart_tool/ -packages -pubspec.lock -doc/api/ From 50a840de189ed8da8125df9d21763e8243eec849 Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Fri, 16 Aug 2019 15:07:23 +0200 Subject: [PATCH 074/170] Readd .gitignore after deleting it. --- pkgs/package_config/.gitignore | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 pkgs/package_config/.gitignore diff --git a/pkgs/package_config/.gitignore b/pkgs/package_config/.gitignore new file mode 100644 index 000000000..7b888b84c --- /dev/null +++ b/pkgs/package_config/.gitignore @@ -0,0 +1,7 @@ +.packages +.pub +.dart_tool/ +.vscode/ +packages +pubspec.lock +doc/api/ From 375e28c38c17ca698999d1fd1fd3f383a5387a38 Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Fri, 16 Aug 2019 15:08:45 +0200 Subject: [PATCH 075/170] Make version number ready for release. --- pkgs/package_config/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index a69096d58..b51932eb7 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 1.1.0-pre +version: 1.1.0 description: Support for working with Package Resolution config files. author: Dart Team homepage: https://github.com/dart-lang/package_config From 8e0739f064dabc72e9b2c218d829749e04c4ac9e Mon Sep 17 00:00:00 2001 From: Jonas Finnemann Jensen Date: Mon, 2 Sep 2019 14:06:28 +0200 Subject: [PATCH 076/170] Add support for writing defaultPackageName (dart-lang/package_config#54) --- pkgs/package_config/CHANGELOG.md | 3 ++ pkgs/package_config/lib/packages_file.dart | 22 ++++++++- pkgs/package_config/pubspec.yaml | 2 +- .../package_config/test/parse_write_test.dart | 47 ++++++++++++++++++- 4 files changed, 70 insertions(+), 4 deletions(-) diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index db4bb00d6..048eedf94 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -1,3 +1,6 @@ +## 1.2.0 + - Added support for writing default-package entries. + ## 1.1.0 - Allow parsing files with default-package entries and metadata. diff --git a/pkgs/package_config/lib/packages_file.dart b/pkgs/package_config/lib/packages_file.dart index 284d8e90a..1fa18e740 100644 --- a/pkgs/package_config/lib/packages_file.dart +++ b/pkgs/package_config/lib/packages_file.dart @@ -106,10 +106,15 @@ Map parse(List source, Uri baseLocation, /// If [baseUri] is provided, package locations will be made relative /// to the base URI, if possible, before writing. /// +/// If [allowDefaultPackage] is `true`, the [packageMapping] may contain an +/// empty string mapping to the _default package name_. +/// /// All the keys of [packageMapping] must be valid package names, /// and the values must be URIs that do not have the `package:` scheme. void write(StringSink output, Map packageMapping, - {Uri baseUri, String comment}) { + {Uri baseUri, String comment, bool allowDefaultPackage = false}) { + ArgumentError.checkNotNull(allowDefaultPackage, 'allowDefaultPackage'); + if (baseUri != null && !baseUri.isAbsolute) { throw new ArgumentError.value(baseUri, "baseUri", "Must be absolute"); } @@ -128,6 +133,21 @@ void write(StringSink output, Map packageMapping, } packageMapping.forEach((String packageName, Uri uri) { + // If [packageName] is empty then [uri] is the _default package name_. + if (allowDefaultPackage && packageName.isEmpty) { + final defaultPackageName = uri.toString(); + if (!isValidPackageName(defaultPackageName)) { + throw ArgumentError.value( + defaultPackageName, + 'defaultPackageName', + '"$defaultPackageName" is not a valid package name', + ); + } + output.write(':'); + output.write(defaultPackageName); + output.writeln(); + return; + } // Validate packageName. if (!isValidPackageName(packageName)) { throw new ArgumentError('"$packageName" is not a valid package name'); diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index b51932eb7..72d299bf2 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 1.1.0 +version: 1.2.0 description: Support for working with Package Resolution config files. author: Dart Team homepage: https://github.com/dart-lang/package_config diff --git a/pkgs/package_config/test/parse_write_test.dart b/pkgs/package_config/test/parse_write_test.dart index b963eb5b5..415b479e9 100644 --- a/pkgs/package_config/test/parse_write_test.dart +++ b/pkgs/package_config/test/parse_write_test.dart @@ -4,6 +4,7 @@ library package_config.parse_write_test; +import "dart:convert" show utf8; import "package:package_config/packages_file.dart"; import "package:test/test.dart"; @@ -32,6 +33,40 @@ main() { var resultMap = parse(content, packagesFile); expect(resultMap, map); }); + + test("write with defaultPackageName", () { + var content = writeToString( + {'': Uri.parse('my_pkg')}..addAll(map), + allowDefaultPackage: true, + ).codeUnits; + var resultMap = parse( + content, + packagesFile, + allowDefaultPackage: true, + ); + expect(resultMap[''].toString(), 'my_pkg'); + expect( + resultMap, + {'': Uri.parse('my_pkg')}..addAll(map), + ); + }); + + test("write with defaultPackageName (utf8)", () { + var content = utf8.encode(writeToString( + {'': Uri.parse('my_pkg')}..addAll(map), + allowDefaultPackage: true, + )); + var resultMap = parse( + content, + packagesFile, + allowDefaultPackage: true, + ); + expect(resultMap[''].toString(), 'my_pkg'); + expect( + resultMap, + {'': Uri.parse('my_pkg')}..addAll(map), + ); + }); }); } @@ -82,8 +117,16 @@ main() { }); } -String writeToString(Map map, {Uri baseUri, String comment}) { +String writeToString( + Map map, { + Uri baseUri, + String comment, + bool allowDefaultPackage = false, +}) { var buffer = new StringBuffer(); - write(buffer, map, baseUri: baseUri, comment: comment); + write(buffer, map, + baseUri: baseUri, + comment: comment, + allowDefaultPackage: allowDefaultPackage); return buffer.toString(); } From fc6f50e6d9bde8135d3f4dbeea28d31eca8c5c7d Mon Sep 17 00:00:00 2001 From: Jonas Finnemann Jensen Date: Mon, 2 Sep 2019 15:54:17 +0200 Subject: [PATCH 077/170] Fix trailing slash logic when writing .packages (dart-lang/package_config#55) --- pkgs/package_config/CHANGELOG.md | 1 + pkgs/package_config/lib/packages_file.dart | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index 048eedf94..50f1ede5a 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -1,5 +1,6 @@ ## 1.2.0 - Added support for writing default-package entries. + - Fixed bug when writing `Uri`s containing a fragment. ## 1.1.0 diff --git a/pkgs/package_config/lib/packages_file.dart b/pkgs/package_config/lib/packages_file.dart index 1fa18e740..1c35d5b21 100644 --- a/pkgs/package_config/lib/packages_file.dart +++ b/pkgs/package_config/lib/packages_file.dart @@ -162,10 +162,10 @@ void write(StringSink output, Map packageMapping, if (baseUri != null) { uri = _relativize(uri, baseUri); } - output.write(uri); if (!uri.path.endsWith('/')) { - output.write('/'); + uri = uri.replace(path: uri.path + '/'); } + output.write(uri); output.writeln(); }); } From c0466fe4af21b652c54dcb1d6eea2777de5c8670 Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Fri, 20 Dec 2019 14:50:27 +0100 Subject: [PATCH 078/170] Version 2.0.0 supporting package_config.json (dart-lang/package_config#56) Giving it the package name package_config_2 to avoid conflict with the existing package_config which is used by the `test` package. This is the initial version. It will be updated to allow overlapping packages, as long as no file in the package URI root can be considered as belonging to a different package. --- pkgs/package_config/CHANGELOG.md | 3 + pkgs/package_config/CONTRIBUTING.md | 2 +- pkgs/package_config/LICENSE | 2 +- pkgs/package_config/lib/discovery.dart | 230 -------- .../lib/discovery_analysis.dart | 167 ------ pkgs/package_config/lib/package_config.dart | 141 +++++ pkgs/package_config/lib/packages.dart | 94 ---- pkgs/package_config/lib/packages_file.dart | 232 -------- pkgs/package_config/lib/src/discovery.dart | 132 +++++ pkgs/package_config/lib/src/errors.dart | 24 + .../lib/src/package_config.dart | 176 ++++++ .../lib/src/package_config_impl.dart | 181 +++++++ .../lib/src/package_config_json.dart | 327 ++++++++++++ .../package_config/lib/src/packages_file.dart | 150 ++++++ .../package_config/lib/src/packages_impl.dart | 127 ----- .../lib/src/packages_io_impl.dart | 45 -- pkgs/package_config/lib/src/util.dart | 251 ++++++++- pkgs/package_config/pubspec.yaml | 8 +- pkgs/package_config/test/all.dart | 17 - .../test/discovery_analysis_test.dart | 126 ----- pkgs/package_config/test/discovery_test.dart | 485 +++++++---------- .../test/discovery_uri_test.dart | 256 +++++++++ pkgs/package_config/test/parse_test.dart | 503 ++++++++++-------- .../package_config/test/parse_write_test.dart | 132 ----- pkgs/package_config/test/src/util.dart | 109 ++++ 25 files changed, 2223 insertions(+), 1697 deletions(-) delete mode 100644 pkgs/package_config/lib/discovery.dart delete mode 100644 pkgs/package_config/lib/discovery_analysis.dart create mode 100644 pkgs/package_config/lib/package_config.dart delete mode 100644 pkgs/package_config/lib/packages.dart delete mode 100644 pkgs/package_config/lib/packages_file.dart create mode 100644 pkgs/package_config/lib/src/discovery.dart create mode 100644 pkgs/package_config/lib/src/errors.dart create mode 100644 pkgs/package_config/lib/src/package_config.dart create mode 100644 pkgs/package_config/lib/src/package_config_impl.dart create mode 100644 pkgs/package_config/lib/src/package_config_json.dart create mode 100644 pkgs/package_config/lib/src/packages_file.dart delete mode 100644 pkgs/package_config/lib/src/packages_impl.dart delete mode 100644 pkgs/package_config/lib/src/packages_io_impl.dart delete mode 100644 pkgs/package_config/test/all.dart delete mode 100644 pkgs/package_config/test/discovery_analysis_test.dart create mode 100644 pkgs/package_config/test/discovery_uri_test.dart delete mode 100644 pkgs/package_config/test/parse_write_test.dart create mode 100644 pkgs/package_config/test/src/util.dart diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index 50f1ede5a..84384fc21 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -1,3 +1,6 @@ +## 2.0.0 + - Based on new JSON file format with more content. + ## 1.2.0 - Added support for writing default-package entries. - Fixed bug when writing `Uri`s containing a fragment. diff --git a/pkgs/package_config/CONTRIBUTING.md b/pkgs/package_config/CONTRIBUTING.md index 6f5e0ea67..8423ff94f 100644 --- a/pkgs/package_config/CONTRIBUTING.md +++ b/pkgs/package_config/CONTRIBUTING.md @@ -23,7 +23,7 @@ All submissions, including submissions by project members, require review. ### File headers All files in the project must start with the following header. - // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file + // Copyright (c) 2019, 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. diff --git a/pkgs/package_config/LICENSE b/pkgs/package_config/LICENSE index de31e1a0a..f75d7c237 100644 --- a/pkgs/package_config/LICENSE +++ b/pkgs/package_config/LICENSE @@ -1,4 +1,4 @@ -Copyright 2015, the Dart project authors. All rights reserved. +Copyright 2019, the Dart project authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/pkgs/package_config/lib/discovery.dart b/pkgs/package_config/lib/discovery.dart deleted file mode 100644 index 57584b682..000000000 --- a/pkgs/package_config/lib/discovery.dart +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright (c) 2015, 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. - -library package_config.discovery; - -import "dart:async"; -import "dart:io"; -import "dart:typed_data" show Uint8List; - -import "package:path/path.dart" as path; - -import "packages.dart"; -import "packages_file.dart" as pkgfile show parse; -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 loadPackagesFile(Uri packagesFile, - {Future> loader(Uri uri)}) async { - Packages parseBytes(List bytes) { - Map packageMap = pkgfile.parse(bytes, packagesFile); - return new MapPackages(packageMap); - } - - if (packagesFile.scheme == "file") { - File file = new File.fromUri(packagesFile); - return parseBytes(await file.readAsBytes()); - } - if (loader == null) { - return parseBytes(await _httpGet(packagesFile)); - } - return parseBytes(await loader(packagesFile)); -} - -/// 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. -/// A package resolution strategy is found by going through the following steps, -/// and stopping when something is found. -/// -/// * Check if a `.packages` file exists in the same directory. -/// * If `baseUri`'s scheme is not `file`, then assume a `packages` directory -/// in the same directory, and resolve packages relative to that. -/// * If `baseUri`'s scheme *is* `file`: -/// * Check if a `packages` directory exists. -/// * Otherwise check each successive parent directory of `baseUri` for a -/// `.packages` file. -/// -/// If any of these tests succeed, a `Packages` class is returned. -/// Returns the constant [noPackages] if no resolution strategy is found. -/// -/// This function currently only supports `file`, `http` and `https` URIs. -/// It needs to be able to load a `.packages` file from the URI, so only -/// recognized schemes are accepted. -/// -/// 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 findPackages(Uri baseUri, - {Future> loader(Uri unsupportedUri)}) { - if (baseUri.scheme == "file") { - return new Future.sync(() => findPackagesFromFile(baseUri)); - } else if (loader != null) { - return findPackagesFromNonFile(baseUri, loader: loader); - } else if (baseUri.scheme == "http" || baseUri.scheme == "https") { - return findPackagesFromNonFile(baseUri, loader: _httpGet); - } else { - return new Future.value(Packages.noPackages); - } -} - -/// Find the location of the package resolution file/directory for a Dart file. -/// -/// Checks for a `.packages` file in the [workingDirectory]. -/// If not found, checks for a `packages` directory in the same directory. -/// If still not found, starts checking parent directories for -/// `.packages` until reaching the root directory. -/// -/// Returns a [File] object of a `.packages` file if one is found, or a -/// [Directory] object for the `packages/` directory if that is found. -FileSystemEntity _findPackagesFile(String workingDirectory) { - var dir = new Directory(workingDirectory); - if (!dir.isAbsolute) dir = dir.absolute; - if (!dir.existsSync()) { - throw new ArgumentError.value( - workingDirectory, "workingDirectory", "Directory does not exist."); - } - File checkForConfigFile(Directory directory) { - assert(directory.isAbsolute); - var file = new File(path.join(directory.path, ".packages")); - if (file.existsSync()) return file; - return null; - } - - // Check for $cwd/.packages - var packagesCfgFile = checkForConfigFile(dir); - if (packagesCfgFile != null) return packagesCfgFile; - // Check for $cwd/packages/ - var packagesDir = new Directory(path.join(dir.path, "packages")); - if (packagesDir.existsSync()) return packagesDir; - // Check for cwd(/..)+/.packages - var parentDir = dir.parent; - while (parentDir.path != dir.path) { - packagesCfgFile = checkForConfigFile(parentDir); - if (packagesCfgFile != null) break; - dir = parentDir; - parentDir = dir.parent; - } - return packagesCfgFile; -} - -/// Finds a package resolution strategy for a local Dart script. -/// -/// The [fileBaseUri] points to either a Dart script or the directory of the -/// script. The `fileBaseUri` must be a `file:` URI. -/// -/// This function first tries to locate a `.packages` file in the `fileBaseUri` -/// directory. If that is not found, it instead checks for the presence of -/// a `packages/` directory in the same place. -/// If that also fails, it starts checking parent directories for a `.packages` -/// file, and stops if it finds it. -/// Otherwise it gives up and returns [Packages.noPackages]. -Packages findPackagesFromFile(Uri fileBaseUri) { - Uri baseDirectoryUri = fileBaseUri; - if (!fileBaseUri.path.endsWith('/')) { - baseDirectoryUri = baseDirectoryUri.resolve("."); - } - String baseDirectoryPath = baseDirectoryUri.toFilePath(); - FileSystemEntity location = _findPackagesFile(baseDirectoryPath); - if (location == null) return Packages.noPackages; - if (location is File) { - List fileBytes = location.readAsBytesSync(); - Map map = - pkgfile.parse(fileBytes, new Uri.file(location.path)); - return new MapPackages(map); - } - assert(location is Directory); - return new FilePackagesDirectoryPackages(location); -} - -/// Finds a package resolution strategy for a Dart script. -/// -/// The [nonFileUri] points to either a Dart script or the directory of the -/// script. -/// The [nonFileUri] should not be a `file:` URI since the algorithm for -/// finding a package resolution strategy is more elaborate for `file:` URIs. -/// In that case, use [findPackagesFromFile]. -/// -/// This function first tries to locate a `.packages` file in the [nonFileUri] -/// directory. If that is not found, it instead assumes a `packages/` directory -/// in the same place. -/// -/// By default, this function only works for `http:` and `https:` URIs. -/// To support other schemes, a loader must be provided, which is used to -/// try to load the `.packages` file. The loader should return the contents -/// of the requested `.packages` file as bytes, which will be assumed to be -/// UTF-8 encoded. -Future findPackagesFromNonFile(Uri nonFileUri, - {Future> loader(Uri name)}) async { - if (loader == null) loader = _httpGet; - Uri packagesFileUri = nonFileUri.resolve(".packages"); - - try { - List fileBytes = await loader(packagesFileUri); - Map map = pkgfile.parse(fileBytes, packagesFileUri); - return new MapPackages(map); - } catch (_) { - // Didn't manage to load ".packages". Assume a "packages/" directory. - Uri packagesDirectoryUri = nonFileUri.resolve("packages/"); - return new NonFilePackagesDirectoryPackages(packagesDirectoryUri); - } -} - -/// Fetches a file over http. -Future> _httpGet(Uri uri) async { - HttpClient client = new HttpClient(); - HttpClientRequest request = await client.getUrl(uri); - HttpClientResponse response = await request.close(); - if (response.statusCode != HttpStatus.ok) { - throw new HttpException('${response.statusCode} ${response.reasonPhrase}', - uri: uri); - } - List> splitContent = await response.toList(); - int totalLength = 0; - for (var list in splitContent) { - totalLength += list.length; - } - Uint8List result = new Uint8List(totalLength); - int offset = 0; - for (List contentPart in splitContent) { - result.setRange(offset, offset + contentPart.length, contentPart); - offset += contentPart.length; - } - return result; -} diff --git a/pkgs/package_config/lib/discovery_analysis.dart b/pkgs/package_config/lib/discovery_analysis.dart deleted file mode 100644 index d623303c8..000000000 --- a/pkgs/package_config/lib/discovery_analysis.dart +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright (c) 2015, 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. - -/// Analyse a directory structure and find packages resolvers for each -/// sub-directory. -/// -/// The resolvers are generally the same that would be found by using -/// the `discovery.dart` library on each sub-directory in turn, -/// but more efficiently and with some heuristics for directories that -/// wouldn't otherwise have a package resolution strategy, or that are -/// determined to be "package directories" themselves. -library package_config.discovery_analysis; - -import "dart:collection" show HashMap; -import "dart:io" show File, Directory; - -import "package:path/path.dart" as path; - -import "packages.dart"; -import "packages_file.dart" as pkgfile; -import "src/packages_impl.dart"; -import "src/packages_io_impl.dart"; - -/// Associates a [Packages] package resolution strategy with a directory. -/// -/// The package resolution applies to the directory and any sub-directory -/// that doesn't have its own overriding child [PackageContext]. -abstract class PackageContext { - /// The directory that introduced the [packages] resolver. - Directory get directory; - - /// A [Packages] resolver that applies to the directory. - /// - /// Introduced either by a `.packages` file or a `packages/` directory. - Packages get packages; - - /// Child contexts that apply to sub-directories of [directory]. - List get children; - - /// Look up the [PackageContext] that applies to a specific directory. - /// - /// The directory must be inside [directory]. - PackageContext operator [](Directory directory); - - /// A map from directory to package resolver. - /// - /// Has an entry for this package context and for each child context - /// contained in this one. - Map asMap(); - - /// Analyze [directory] and sub-directories for package resolution strategies. - /// - /// Returns a mapping from sub-directories to [Packages] objects. - /// - /// The analysis assumes that there are no `.packages` files in a parent - /// directory of `directory`. If there is, its corresponding `Packages` object - /// should be provided as `root`. - static PackageContext findAll(Directory directory, - {Packages root: Packages.noPackages}) { - if (!directory.existsSync()) { - throw ArgumentError("Directory not found: $directory"); - } - var contexts = []; - void findRoots(Directory directory) { - Packages packages; - List oldContexts; - File packagesFile = File(path.join(directory.path, ".packages")); - if (packagesFile.existsSync()) { - packages = _loadPackagesFile(packagesFile); - oldContexts = contexts; - contexts = []; - } else { - Directory packagesDir = - Directory(path.join(directory.path, "packages")); - if (packagesDir.existsSync()) { - packages = FilePackagesDirectoryPackages(packagesDir); - oldContexts = contexts; - contexts = []; - } - } - for (var entry in directory.listSync()) { - if (entry is Directory) { - if (packages == null || !entry.path.endsWith("/packages")) { - findRoots(entry); - } - } - } - if (packages != null) { - oldContexts.add(_PackageContext(directory, packages, contexts)); - contexts = oldContexts; - } - } - - findRoots(directory); - // If the root is not itself context root, add a the wrapper context. - if (contexts.length == 1 && contexts[0].directory == directory) { - return contexts[0]; - } - return _PackageContext(directory, root, contexts); - } -} - -class _PackageContext implements PackageContext { - final Directory directory; - final Packages packages; - final List children; - _PackageContext(this.directory, this.packages, List children) - : children = List.unmodifiable(children); - - Map asMap() { - var result = HashMap(); - recurse(_PackageContext current) { - result[current.directory] = current.packages; - for (var child in current.children) { - recurse(child); - } - } - - recurse(this); - return result; - } - - PackageContext operator [](Directory directory) { - String path = directory.path; - if (!path.startsWith(this.directory.path)) { - throw ArgumentError("Not inside $path: $directory"); - } - _PackageContext current = this; - // The current path is know to agree with directory until deltaIndex. - int deltaIndex = current.directory.path.length; - List children = current.children; - int i = 0; - while (i < children.length) { - // TODO(lrn): Sort children and use binary search. - _PackageContext child = children[i]; - String childPath = child.directory.path; - if (_stringsAgree(path, childPath, deltaIndex, childPath.length)) { - deltaIndex = childPath.length; - if (deltaIndex == path.length) { - return child; - } - current = child; - children = current.children; - i = 0; - continue; - } - i++; - } - return current; - } - - static bool _stringsAgree(String a, String b, int start, int end) { - if (a.length < end || b.length < end) return false; - for (int i = start; i < end; i++) { - if (a.codeUnitAt(i) != b.codeUnitAt(i)) return false; - } - return true; - } -} - -Packages _loadPackagesFile(File file) { - var uri = Uri.file(file.path); - var bytes = file.readAsBytesSync(); - var map = pkgfile.parse(bytes, uri); - return MapPackages(map); -} diff --git a/pkgs/package_config/lib/package_config.dart b/pkgs/package_config/lib/package_config.dart new file mode 100644 index 000000000..4d6f346d7 --- /dev/null +++ b/pkgs/package_config/lib/package_config.dart @@ -0,0 +1,141 @@ +// Copyright (c) 2019, 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. + +/// A package configuration is a way to assign file paths to package URIs, +/// and vice-versa, +library package_config.package_config; + +import "dart:io" show File, Directory; +import "dart:typed_data" show Uint8List; +import "src/discovery.dart" as discover; +import "src/package_config.dart"; +import "src/package_config_json.dart"; + +export "src/package_config.dart" show PackageConfig, Package; +export "src/errors.dart" show PackageConfigError; + +/// Reads a specific package configuration file. +/// +/// The file must exist and be readable. +/// It must be either a valid `package_config.json` file +/// or a valid `.packages` file. +/// It is considered a `package_config.json` file if its first character +/// is a `{`. +/// +/// If the file is a `.packages` file, also checks if there is a +/// `.dart_tool/package_config.json` file next to the original file, +/// and if so, loads that instead. +Future loadPackageConfig(File file) => readAnyConfigFile(file); + +/// Reads a specific package configuration URI. +/// +/// The file of the URI must exist and be readable. +/// It must be either a valid `package_config.json` file +/// or a valid `.packages` file. +/// It is considered a `package_config.json` file if its first +/// non-whitespace character is a `{`. +/// +/// If the file is a `.packages` file, first checks if there is a +/// `.dart_tool/package_config.json` file next to the original file, +/// and if so, loads that instead. +/// The [file] *must not* be a `package:` URI. +/// +/// If [loader] is provided, URIs are loaded using that function. +/// The future returned by the loader must complete with a [Uint8List] +/// containing the entire file content, +/// or with `null` if the file does not exist. +/// The loader may throw at its own discretion, for situations where +/// it determines that an error might be need user attention, +/// but it is always allowed to return `null`. +/// This function makes no attempt to catch such errors. +/// +/// If no [loader] is supplied, a default loader is used which +/// only accepts `file:`, `http:` and `https:` URIs, +/// and which uses the platform file system and HTTP requests to +/// fetch file content. The default loader never throws because +/// of an I/O issue, as long as the location URIs are valid. +/// As such, it does not distinguish between a file not existing, +/// and it being temporarily locked or unreachable. +Future loadPackageConfigUri(Uri file, + {Future loader(Uri uri) /*?*/}) => + readAnyConfigFileUri(file, loader); + +/// Finds a package configuration relative to [directory]. +/// +/// If [directory] contains a package configuration, +/// either a `.dart_tool/package_config.json` file or, +/// if not, a `.packages`, then that file is loaded. +/// +/// If no file is found in the current directory, +/// then the parent directories are checked recursively, +/// all the way to the root directory, to check if those contains +/// a package configuration. +/// If [recurse] is set to [false], this parent directory check is not +/// performed. +/// +/// Returns `null` if no configuration file is found. +Future findPackageConfig(Directory directory, + {bool recurse = true}) => + discover.findPackageConfig(directory, recurse); + +/// Finds a package configuration relative to [location]. +/// +/// If [location] contains a package configuration, +/// either a `.dart_tool/package_config.json` file or, +/// if not, a `.packages`, then that file is loaded. +/// The [location] URI *must not* be a `package:` URI. +/// It should be a hierarchical URI which is supported +/// by [loader]. +/// +/// If no file is found in the current directory, +/// then the parent directories are checked recursively, +/// all the way to the root directory, to check if those contains +/// a package configuration. +/// If [recurse] is set to [false], this parent directory check is not +/// performed. +/// +/// If [loader] is provided, URIs are loaded using that function. +/// The future returned by the loader must complete with a [Uint8List] +/// containing the entire file content, +/// or with `null` if the file does not exist. +/// The loader may throw at its own discretion, for situations where +/// it determines that an error might be need user attention, +/// but it is always allowed to return `null`. +/// This function makes no attempt to catch such errors. +/// +/// If no [loader] is supplied, a default loader is used which +/// only accepts `file:`, `http:` and `https:` URIs, +/// and which uses the platform file system and HTTP requests to +/// fetch file content. The default loader never throws because +/// of an I/O issue, as long as the location URIs are valid. +/// As such, it does not distinguish between a file not existing, +/// and it being temporarily locked or unreachable. +/// +/// Returns `null` if no configuration file is found. +Future findPackageConfigUri(Uri location, + {bool recurse = true, Future loader(Uri uri)}) => + discover.findPackageConfigUri(location, loader, recurse); + +/// Writes a package configuration to the provided directory. +/// +/// Writes `.dart_tool/package_config.json` relative to [directory]. +/// If the `.dart_tool/` directory does not exist, it is created. +/// If it cannot be created, this operation fails. +/// +/// If [extraData] contains any entries, they are added to the JSON +/// written to the `package_config.json` file. Entries with the names +/// `"configVersion"` or `"packages"` are ignored, all other entries +/// are added verbatim. +/// This is intended for, e.g., the +/// `"generator"`, `"generated"` and `"generatorVersion"` +/// properties. +/// +/// Also writes a `.packages` file in [directory]. +/// This will stop happening eventually as the `.packages` file becomes +/// discontinued. +/// A comment is generated if `[PackageConfig.extraData]` contains a +/// `"generator"` entry. +Future savePackageConfig( + PackageConfig configuration, Directory directory) => + writePackageConfigJson(configuration, directory); diff --git a/pkgs/package_config/lib/packages.dart b/pkgs/package_config/lib/packages.dart deleted file mode 100644 index 886fbc83c..000000000 --- a/pkgs/package_config/lib/packages.dart +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) 2015, 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. - -library package_config.packages; - -import "src/packages_impl.dart"; - -/// A package resolution strategy. -/// -/// Allows converting a `package:` URI to a different kind of URI. -/// -/// May also allow listing the available packages and converting -/// to a `Map` that gives the base location of each available -/// package. In some cases there is no way to find the available packages, -/// in which case [packages] and [asMap] will throw if used. -/// One such case is if the packages are resolved relative to a -/// `packages/` directory available over HTTP. -abstract class Packages { - /// A [Packages] resolver containing no packages. - /// - /// This constant object is returned by [find] above if no - /// package resolution strategy is found. - static const Packages noPackages = const NoPackages(); - - /// Resolve a package URI into a non-package URI. - /// - /// Translates a `package:` URI, according to the package resolution - /// strategy, into a URI that can be loaded. - /// By default, only `file`, `http` and `https` URIs are returned. - /// Custom `Packages` objects may return other URIs. - /// - /// If resolution fails because a package with the requested package name - /// is not available, the [notFound] function is called. - /// If no `notFound` function is provided, it defaults to throwing an error. - /// - /// The [packageUri] must be a valid package URI. - Uri resolve(Uri packageUri, {Uri notFound(Uri packageUri)}); - - /// Return the names of the available packages. - /// - /// Returns an iterable that allows iterating the names of available packages. - /// - /// Some `Packages` objects are unable to find the package names, - /// and getting `packages` from such a `Packages` object will throw. - Iterable get packages; - - /// Retrieve metadata associated with a package. - /// - /// Metadata have string keys and values, and are looked up by key. - /// - /// Returns `null` if the argument is not a valid package name, - /// or if the package is not one of the packages configured by - /// this packages object, or if the package does not have associated - /// metadata with the provided [key]. - /// - /// Not all `Packages` objects can support metadata. - /// Those will always return `null`. - String packageMetadata(String packageName, String key); - - /// Retrieve metadata associated with a library. - /// - /// If [libraryUri] is a `package:` URI, the returned value - /// is the same that would be returned by [packageMetadata] with - /// the package's name and the same key. - /// - /// If [libraryUri] is not a `package:` URI, and this [Packages] - /// object has a [defaultPackageName], then the [key] is looked - /// up on the default package instead. - /// - /// Otherwise the result is `null`. - String libraryMetadata(Uri libraryUri, String key); - - /// Return the names-to-base-URI mapping of the available packages. - /// - /// Returns a map from package name to a base URI. - /// The [resolve] method will resolve a package URI with a specific package - /// name to a path extending the base URI that this map gives for that - /// package name. - /// - /// Some `Packages` objects are unable to find the package names, - /// and calling `asMap` on such a `Packages` object will throw. - Map asMap(); - - /// The name of the "default package". - /// - /// A default package is a package that *non-package* libraries - /// may be considered part of for some purposes. - /// - /// The value is `null` if there is no default package. - /// Not all implementations of [Packages] supports a default package, - /// and will always have a `null` value for those. - String get defaultPackageName; -} diff --git a/pkgs/package_config/lib/packages_file.dart b/pkgs/package_config/lib/packages_file.dart deleted file mode 100644 index 1c35d5b21..000000000 --- a/pkgs/package_config/lib/packages_file.dart +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright (c) 2015, 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. - -library package_config.packages_file; - -import "package:charcode/ascii.dart"; - -import "src/util.dart" show isValidPackageName; - -/// Parses a `.packages` file into a map from package name to base URI. -/// -/// The [source] is the byte content of a `.packages` file, assumed to be -/// UTF-8 encoded. In practice, all significant parts of the file must be ASCII, -/// so Latin-1 or Windows-1252 encoding will also work fine. -/// -/// If the file content is available as a string, its [String.codeUnits] can -/// be used as the `source` argument of this function. -/// -/// The [baseLocation] is used as a base URI to resolve all relative -/// URI references against. -/// If the content was read from a file, `baseLocation` should be the -/// location of that file. -/// -/// If [allowDefaultPackage] is set to true, an entry with an empty package name -/// is accepted. This entry does not correspond to a package, but instead -/// represents a *default package* which non-package libraries may be considered -/// part of in some cases. The value of that entry must be a valid package name. -/// -/// Returns a simple mapping from package name to package location. -/// If default package is allowed, the map maps the empty string to the default package's name. -Map parse(List source, Uri baseLocation, - {bool allowDefaultPackage = false}) { - int index = 0; - Map result = {}; - while (index < source.length) { - bool isComment = false; - int start = index; - int separatorIndex = -1; - int end = source.length; - int char = source[index++]; - if (char == $cr || char == $lf) { - continue; - } - if (char == $colon) { - if (!allowDefaultPackage) { - throw FormatException("Missing package name", source, index - 1); - } - separatorIndex = index - 1; - } - isComment = char == $hash; - while (index < source.length) { - char = source[index++]; - if (char == $colon && separatorIndex < 0) { - separatorIndex = index - 1; - } else if (char == $cr || char == $lf) { - end = index - 1; - break; - } - } - if (isComment) continue; - if (separatorIndex < 0) { - throw FormatException("No ':' on line", source, index - 1); - } - var packageName = new String.fromCharCodes(source, start, separatorIndex); - if (packageName.isEmpty - ? !allowDefaultPackage - : !isValidPackageName(packageName)) { - throw FormatException("Not a valid package name", packageName, 0); - } - var packageValue = - new String.fromCharCodes(source, separatorIndex + 1, end); - Uri packageLocation; - if (packageName.isEmpty) { - if (!isValidPackageName(packageValue)) { - throw FormatException( - "Default package entry value is not a valid package name"); - } - packageLocation = Uri(path: packageValue); - } else { - packageLocation = baseLocation.resolve(packageValue); - if (!packageLocation.path.endsWith('/')) { - packageLocation = - packageLocation.replace(path: packageLocation.path + "/"); - } - } - if (result.containsKey(packageName)) { - if (packageName.isEmpty) { - throw FormatException( - "More than one default package entry", source, start); - } - throw FormatException("Same package name occured twice", source, start); - } - result[packageName] = packageLocation; - } - return result; -} - -/// Writes the mapping to a [StringSink]. -/// -/// If [comment] is provided, the output will contain this comment -/// with `# ` in front of each line. -/// Lines are defined as ending in line feed (`'\n'`). If the final -/// line of the comment doesn't end in a line feed, one will be added. -/// -/// If [baseUri] is provided, package locations will be made relative -/// to the base URI, if possible, before writing. -/// -/// If [allowDefaultPackage] is `true`, the [packageMapping] may contain an -/// empty string mapping to the _default package name_. -/// -/// All the keys of [packageMapping] must be valid package names, -/// and the values must be URIs that do not have the `package:` scheme. -void write(StringSink output, Map packageMapping, - {Uri baseUri, String comment, bool allowDefaultPackage = false}) { - ArgumentError.checkNotNull(allowDefaultPackage, 'allowDefaultPackage'); - - if (baseUri != null && !baseUri.isAbsolute) { - throw new ArgumentError.value(baseUri, "baseUri", "Must be absolute"); - } - - if (comment != null) { - var lines = comment.split('\n'); - if (lines.last.isEmpty) lines.removeLast(); - for (var commentLine in lines) { - output.write('# '); - output.writeln(commentLine); - } - } else { - output.write("# generated by package:package_config at "); - output.write(new DateTime.now()); - output.writeln(); - } - - packageMapping.forEach((String packageName, Uri uri) { - // If [packageName] is empty then [uri] is the _default package name_. - if (allowDefaultPackage && packageName.isEmpty) { - final defaultPackageName = uri.toString(); - if (!isValidPackageName(defaultPackageName)) { - throw ArgumentError.value( - defaultPackageName, - 'defaultPackageName', - '"$defaultPackageName" is not a valid package name', - ); - } - output.write(':'); - output.write(defaultPackageName); - output.writeln(); - return; - } - // Validate packageName. - if (!isValidPackageName(packageName)) { - throw new ArgumentError('"$packageName" is not a valid package name'); - } - if (uri.scheme == "package") { - throw new ArgumentError.value( - "Package location must not be a package: URI", uri.toString()); - } - output.write(packageName); - output.write(':'); - // If baseUri provided, make uri relative. - if (baseUri != null) { - uri = _relativize(uri, baseUri); - } - if (!uri.path.endsWith('/')) { - uri = uri.replace(path: uri.path + '/'); - } - output.write(uri); - output.writeln(); - }); -} - -/// Attempts to return a relative URI for [uri]. -/// -/// The result URI satisfies `baseUri.resolveUri(result) == uri`, -/// but may be relative. -/// The `baseUri` must be absolute. -Uri _relativize(Uri uri, Uri baseUri) { - assert(baseUri.isAbsolute); - if (uri.hasQuery || uri.hasFragment) { - uri = new Uri( - scheme: uri.scheme, - userInfo: uri.hasAuthority ? uri.userInfo : null, - host: uri.hasAuthority ? uri.host : null, - port: uri.hasAuthority ? uri.port : null, - path: uri.path); - } - - // Already relative. We assume the caller knows what they are doing. - if (!uri.isAbsolute) return uri; - - if (baseUri.scheme != uri.scheme) { - return uri; - } - - // If authority differs, we could remove the scheme, but it's not worth it. - if (uri.hasAuthority != baseUri.hasAuthority) return uri; - if (uri.hasAuthority) { - if (uri.userInfo != baseUri.userInfo || - uri.host.toLowerCase() != baseUri.host.toLowerCase() || - uri.port != baseUri.port) { - return uri; - } - } - - baseUri = baseUri.normalizePath(); - List base = baseUri.pathSegments.toList(); - if (base.isNotEmpty) { - base = new List.from(base)..removeLast(); - } - uri = uri.normalizePath(); - List target = uri.pathSegments.toList(); - if (target.isNotEmpty && target.last.isEmpty) target.removeLast(); - int index = 0; - while (index < base.length && index < target.length) { - if (base[index] != target[index]) { - break; - } - index++; - } - if (index == base.length) { - if (index == target.length) { - return new Uri(path: "./"); - } - return new Uri(path: target.skip(index).join('/')); - } else if (index > 0) { - return new Uri( - path: '../' * (base.length - index) + target.skip(index).join('/')); - } else { - return uri; - } -} diff --git a/pkgs/package_config/lib/src/discovery.dart b/pkgs/package_config/lib/src/discovery.dart new file mode 100644 index 000000000..6b0fc8f0d --- /dev/null +++ b/pkgs/package_config/lib/src/discovery.dart @@ -0,0 +1,132 @@ +// Copyright (c) 2019, 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. + +import "dart:io"; +import 'dart:typed_data'; + +import "package:path/path.dart" as path; + +import "errors.dart"; +import "package_config_impl.dart"; +import "package_config_json.dart"; +import "packages_file.dart" as packages_file; +import "util.dart" show defaultLoader; + +final Uri packageConfigJsonPath = Uri(path: ".dart_tool/package_config.json"); +final Uri dotPackagesPath = Uri(path: ".packages"); +final Uri currentPath = Uri(path: "."); +final Uri parentPath = Uri(path: ".."); + +/// Discover the package configuration for a Dart script. +/// +/// The [baseDirectory] points to the directory of the Dart script. +/// A package resolution strategy is found by going through the following steps, +/// and stopping when something is found. +/// +/// * Check if a `.dart_tool/package_config.json` file exists in the directory. +/// * Check if a `.packages` file exists in the directory. +/// * Repeat these checks for the parent directories until reaching the +/// root directory if [recursive] is true. +/// +/// If any of these tests succeed, a `PackageConfig` class is returned. +/// Returns `null` if no configuration was found. If a configuration +/// is needed, then the caller can supply [PackageConfig.empty]. +Future findPackageConfig( + Directory baseDirectory, bool recursive) async { + var directory = baseDirectory; + if (!directory.isAbsolute) directory = directory.absolute; + if (!await directory.exists()) { + return null; + } + do { + // Check for $cwd/.packages + var packageConfig = await findPackagConfigInDirectory(directory); + if (packageConfig != null) return packageConfig; + if (!recursive) break; + // Check in parent directories. + var parentDirectory = directory.parent; + if (parentDirectory.path == directory.path) break; + directory = parentDirectory; + } while (true); + return null; +} + +/// Similar to [findPackageConfig] but based on a URI. +Future findPackageConfigUri(Uri location, + Future loader(Uri uri) /*?*/, bool recursive) async { + if (location.isScheme("package")) { + throw PackageConfigArgumentError( + location, "location", "Must not be a package: URI"); + } + if (loader == null) { + if (location.isScheme("file")) { + return findPackageConfig( + Directory.fromUri(location.resolveUri(currentPath)), recursive); + } + loader = defaultLoader; + } + if (!location.path.endsWith("/")) location = location.resolveUri(currentPath); + while (true) { + var file = location.resolveUri(packageConfigJsonPath); + var bytes = await loader(file); + if (bytes != null) { + return parsePackageConfigBytes(bytes, file); + } + file = location.resolveUri(dotPackagesPath); + bytes = await loader(file); + if (bytes != null) { + return packages_file.parse(bytes, file); + } + if (!recursive) break; + var parent = location.resolveUri(parentPath); + if (parent == location) break; + location = parent; + } + return null; +} + +/// Finds a `.packages` or `.dart_tool/package_config.json` file in [directory]. +/// +/// Loads the file, if it is there, and returns the resulting [PackageConfig]. +/// Returns `null` if the file isn't there. +/// Throws [FormatException] if a file is there but is not valid. +/// +/// If [extraData] is supplied and the `package_config.json` contains extra +/// entries in the top JSON object, those extra entries are stored into +/// [extraData]. +Future findPackagConfigInDirectory( + Directory directory) async { + var packageConfigFile = await checkForPackageConfigJsonFile(directory); + if (packageConfigFile != null) { + return await readPackageConfigJsonFile(packageConfigFile); + } + packageConfigFile = await checkForDotPackagesFile(directory); + if (packageConfigFile != null) { + return await readDotPackagesFile(packageConfigFile); + } + return null; +} + +Future /*?*/ checkForPackageConfigJsonFile(Directory directory) async { + assert(directory.isAbsolute); + var file = + File(path.join(directory.path, ".dart_tool", "package_config.json")); + if (await file.exists()) return file; + return null; +} + +Future checkForDotPackagesFile(Directory directory) async { + var file = File(path.join(directory.path, ".packages")); + if (await file.exists()) return file; + return null; +} + +Future _loadFile(File file) async { + Uint8List bytes; + try { + return await file.readAsBytes(); + } catch (_) { + return null; + } +} diff --git a/pkgs/package_config/lib/src/errors.dart b/pkgs/package_config/lib/src/errors.dart new file mode 100644 index 000000000..6c31ccea1 --- /dev/null +++ b/pkgs/package_config/lib/src/errors.dart @@ -0,0 +1,24 @@ +// Copyright (c) 2019, 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. + +/// General superclass of most errors and exceptions thrown by this package. +/// +/// Only covers errors thrown while parsing package configuration files. +/// Programming errors and I/O exceptions are not covered. +abstract class PackageConfigError { + PackageConfigError._(); +} + +class PackageConfigArgumentError extends ArgumentError + implements PackageConfigError { + PackageConfigArgumentError(Object /*?*/ value, String name, String message) + : super.value(value, name, message); +} + +class PackageConfigFormatException extends FormatException + implements PackageConfigError { + PackageConfigFormatException(String message, Object /*?*/ value, + [int /*?*/ index]) + : super(message, value, index); +} diff --git a/pkgs/package_config/lib/src/package_config.dart b/pkgs/package_config/lib/src/package_config.dart new file mode 100644 index 000000000..f7b96b8a5 --- /dev/null +++ b/pkgs/package_config/lib/src/package_config.dart @@ -0,0 +1,176 @@ +// Copyright (c) 2019, 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. + +import "package_config_impl.dart"; + +/// A package configuration. +/// +/// Associates configuration data to packages and files in packages. +/// +/// More members may be added to this class in the future, +/// so classes outside of this package must not implement [PackageConfig] +/// or any subclass of it. +abstract class PackageConfig { + /// The largest configuration version currently recognized. + static const int maxVersion = 2; + + /// An empty package configuration. + /// + /// A package configuration with no available packages. + /// Is used as a default value where a package configuration + /// is expected, but none have been specified or found. + static const PackageConfig empty = const SimplePackageConfig.empty(); + + /// Creats a package configuration with the provided available [packages]. + /// + /// The packages must be valid packages (valid package name, valid + /// absolute directory URIs, valid language version, if any), + /// and there must not be two packages with the same name or with + /// overlapping root directories. + /// + /// If supplied, the [extraData] will be available as the + /// [PackageConfig.extraData] of the created configuration. + /// + /// The version of the resulting configuration is always [maxVersion]. + factory PackageConfig(Iterable packages, {dynamic extraData}) => + SimplePackageConfig(maxVersion, packages); + + /// The configuration version number. + /// + /// Currently this is 1 or 2, where + /// * Version one is the `.packages` file format and + /// * Version two is the first `package_config.json` format. + /// + /// Instances of this class supports both, and the version + /// is only useful for detecting which kind of file the configuration + /// was read from. + int get version; + + /// All the available packages of this configuration. + /// + /// No two of these packages have the same name, + /// and no two [Package.root] directories overlap. + Iterable get packages; + + /// Look up a package by name. + /// + /// Returns the [Package] fron [packages] with [packageName] as + /// [Package.name]. Returns `null` if the package is not available in the + /// current configuration. + Package /*?*/ operator [](String packageName); + + /// Provides the associated package for a specific [file] (or directory). + /// + /// Returns a [Package] which contains the [file]'s path, if any. + /// That is, the [Package.rootUri] directory is a parent directory + /// of the [file]'s location. + /// + /// Returns `null` if the file does not belong to any package. + Package /*?*/ packageOf(Uri file); + + /// Resolves a `package:` URI to a non-package URI + /// + /// The [packageUri] must be a valid package URI. That means: + /// * A URI with `package` as scheme, + /// * with no authority part (`package://...`), + /// * with a path starting with a valid package name followed by a slash, and + /// * with no query or fragment part. + /// + /// Throws an [ArgumentError] (which also implements [PackageConfigError]) + /// if the package URI is not valid. + /// + /// Returns `null` if the package name of [packageUri] is not available + /// in this package configuration. + /// Returns the remaining path of the package URI resolved relative to the + /// [Package.packageUriRoot] of the corresponding package. + Uri /*?*/ resolve(Uri packageUri); + + /// The package URI which resolves to [nonPackageUri]. + /// + /// The [nonPackageUri] must not have any query or fragment part, + /// and it must not have `package` as scheme. + /// Throws an [ArgumentError] (which also implements [PackageConfigError]) + /// if the non-package URI is not valid. + /// + /// Returns a package URI which [resolve] will convert to [nonPackageUri], + /// if any such URI exists. Returns `null` if no such package URI exists. + Uri /*?*/ toPackageUri(Uri nonPackageUri); + + /// Extra data associated with the package configuration. + /// + /// The data may be in any format, depending on who introduced it. + /// The standard `packjage_config.json` file storage will only store + /// JSON-like list/map data structures. + dynamic get extraData; +} + +/// Configuration data for a single package. +abstract class Package { + /// Creates a package with the provided properties. + /// + /// The [name] must be a valid package name. + /// The [root] must be an absolute directory URI, meaning an absolute URI + /// with no query or fragment path and a path starting and ending with `/`. + /// The [packageUriRoot], if provided, must be either an absolute + /// directory URI or a relative URI reference which is then resolved + /// relative to [root]. It must then also be a subdirectory of [root], + /// or the same directory. + /// If [languageVersion] is supplied, it must be a valid Dart language + /// version, which means two decimal integer literals separated by a `.`, + /// where the integer literals have no leading zeros unless they are + /// a single zero digit. + /// If [extraData] is supplied, it will be available as the + /// [Package.extraData] of the created package. + factory Package(String name, Uri root, + {Uri /*?*/ packageUriRoot, + String /*?*/ languageVersion, + dynamic extraData}) => + SimplePackage(name, root, packageUriRoot, languageVersion, extraData); + + /// The package-name of the package. + String get name; + + /// The location of the root of the package. + /// + /// Is always an absolute URI with no query or fragment parts, + /// and with a path ending in `/`. + /// + /// All files in the [rootUri] directory are considered + /// part of the package for purposes where that that matters. + Uri get root; + + /// The root of the files available through `package:` URIs. + /// + /// A `package:` URI with [name] as the package name is + /// resolved relative to this location. + /// + /// Is always an absolute URI with no query or fragment part + /// with a path ending in `/`, + /// and with a location which is a subdirectory + /// of the [root], or the same as the [root]. + Uri get packageUriRoot; + + /// The default language version associated with this package. + /// + /// Each package may have a default language version associated, + /// which is the language version used to parse and compile + /// Dart files in the package. + /// A package version is always of the form: + /// + /// * A numeral consisting of one or more decimal digits, + /// with no leading zero unless the entire numeral is a single zero digit. + /// * Followed by a `.` character. + /// * Followed by another numeral of the same form. + /// + /// There is no whitespace allowed around the numerals. + /// Valid version numbers include `2.5`, `3.0`, and `1234.5678`. + String /*?*/ get languageVersion; + + /// Extra data associated with the specific package. + /// + /// The data may be in any format, depending on who introduced it. + /// The standard `packjage_config.json` file storage will only store + /// JSON-like list/map data structures. + dynamic get extraData; +} diff --git a/pkgs/package_config/lib/src/package_config_impl.dart b/pkgs/package_config/lib/src/package_config_impl.dart new file mode 100644 index 000000000..0bbe18f5b --- /dev/null +++ b/pkgs/package_config/lib/src/package_config_impl.dart @@ -0,0 +1,181 @@ +// Copyright (c) 2019, 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. + +import 'errors.dart'; +import "package_config.dart"; +export "package_config.dart"; +import "util.dart"; + +class SimplePackageConfig implements PackageConfig { + final int version; + final Map _packages; + final dynamic extraData; + + SimplePackageConfig(int version, Iterable packages, [this.extraData]) + : version = _validateVersion(version), + _packages = _validatePackages(packages); + + SimplePackageConfig._( + int version, Iterable packages, this.extraData) + : version = _validateVersion(version), + _packages = {for (var package in packages) package.name: package}; + + /// Creates empty configuration. + /// + /// The empty configuration can be used in cases where no configuration is + /// found, but code expects a non-null configuration. + const SimplePackageConfig.empty() + : version = 1, + _packages = const {}, + extraData = null; + + static int _validateVersion(int version) { + if (version < 0 || version > PackageConfig.maxVersion) { + throw PackageConfigArgumentError(version, "version", + "Must be in the range 1 to ${PackageConfig.maxVersion}"); + } + return version; + } + + static Map _validatePackages(Iterable packages) { + Map result = {}; + for (var package in packages) { + if (package is! SimplePackage) { + // SimplePackage validates these properties. + try { + _validatePackageData(package.name, package.root, + package.packageUriRoot, package.languageVersion); + } catch (e) { + throw PackageConfigArgumentError( + packages, "packages", "Package ${package.name}: ${e.message}"); + } + } + var name = package.name; + if (result.containsKey(name)) { + throw PackageConfigArgumentError( + name, "packages", "Duplicate package name"); + } + result[name] = package; + } + + // Check that no root URI is a prefix of another. + if (result.length > 1) { + // Uris cache their toString, so this is not as bad as it looks. + var rootUris = [...result.values] + ..sort((a, b) => a.root.toString().compareTo(b.root.toString())); + var prev = rootUris[0]; + var prevRoot = prev.root.toString(); + for (int i = 1; i < rootUris.length; i++) { + var next = rootUris[i]; + var nextRoot = next.root.toString(); + // If one string is a prefix of another, + // the former sorts just before the latter. + if (nextRoot.startsWith(prevRoot)) { + throw PackageConfigArgumentError( + packages, + "packages", + "Package ${next.name} root overlaps " + "package ${prev.name} root.\n" + "${prev.name} root: $prevRoot\n" + "${next.name} root: $nextRoot\n"); + } + prev = next; + } + } + return result; + } + + Iterable get packages => _packages.values; + + Package /*?*/ operator [](String packageName) => _packages[packageName]; + + /// Provides the associated package for a specific [file] (or directory). + /// + /// Returns a [Package] which contains the [file]'s path. + /// That is, the [Package.rootUri] directory is a parent directory + /// of the [file]'s location. + /// Returns `null` if the file does not belong to any package. + Package /*?*/ packageOf(Uri file) { + String path = file.toString(); + for (var package in _packages.values) { + var rootPath = package.root.toString(); + if (path.startsWith(rootPath)) return package; + } + return null; + } + + Uri /*?*/ resolve(Uri packageUri) { + String packageName = checkValidPackageUri(packageUri, "packageUri"); + return _packages[packageName]?.packageUriRoot?.resolveUri( + Uri(path: packageUri.path.substring(packageName.length + 1))); + } + + Uri /*?*/ toPackageUri(Uri nonPackageUri) { + if (nonPackageUri.isScheme("package")) { + throw PackageConfigArgumentError( + nonPackageUri, "nonPackageUri", "Must not be a package URI"); + } + if (nonPackageUri.hasQuery || nonPackageUri.hasFragment) { + throw PackageConfigArgumentError(nonPackageUri, "nonPackageUri", + "Must not have query or fragment part"); + } + for (var package in _packages.values) { + var root = package.packageUriRoot; + if (isUriPrefix(root, nonPackageUri)) { + var rest = nonPackageUri.toString().substring(root.toString().length); + return Uri(scheme: "package", path: "${package.name}/$rest"); + } + } + return null; + } +} + +/// Configuration data for a single package. +class SimplePackage implements Package { + final String name; + final Uri root; + final Uri packageUriRoot; + final String /*?*/ languageVersion; + final dynamic extraData; + + SimplePackage._(this.name, this.root, this.packageUriRoot, + this.languageVersion, this.extraData); + + factory SimplePackage(String name, Uri root, Uri packageUriRoot, + String /*?*/ languageVersion, dynamic extraData) { + _validatePackageData(name, root, packageUriRoot, languageVersion); + return SimplePackage._( + name, root, packageUriRoot, languageVersion, extraData); + } +} + +void _validatePackageData( + String name, Uri root, Uri packageUriRoot, String /*?*/ languageVersion) { + if (!isValidPackageName(name)) { + throw PackageConfigArgumentError(name, "name", "Not a valid package name"); + } + if (!isAbsoluteDirectoryUri(root)) { + throw PackageConfigArgumentError( + "$root", + "root", + "Not an absolute URI with no query or fragment " + "with a path ending in /"); + } + if (!isAbsoluteDirectoryUri(packageUriRoot)) { + throw PackageConfigArgumentError( + packageUriRoot, + "packageUriRoot", + "Not an absolute URI with no query or fragment " + "with a path ending in /"); + } + if (!isUriPrefix(root, packageUriRoot)) { + throw PackageConfigArgumentError(packageUriRoot, "packageUriRoot", + "The package URI root is not below the package root"); + } + if (languageVersion != null && + checkValidVersionNumber(languageVersion) >= 0) { + throw PackageConfigArgumentError( + languageVersion, "languageVersion", "Invalid language version format"); + } +} diff --git a/pkgs/package_config/lib/src/package_config_json.dart b/pkgs/package_config/lib/src/package_config_json.dart new file mode 100644 index 000000000..8a6014cad --- /dev/null +++ b/pkgs/package_config/lib/src/package_config_json.dart @@ -0,0 +1,327 @@ +// Copyright (c) 2019, 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. + +import "dart:convert"; +import "dart:io"; +import "dart:typed_data"; + +import 'package:charcode/ascii.dart'; +import "package:path/path.dart" as path; + +import "discovery.dart" show packageConfigJsonPath; +import "errors.dart"; +import "package_config_impl.dart"; +import "packages_file.dart" as packages_file; +import "util.dart"; + +const String _configVersionKey = "configVersion"; +const String _packagesKey = "packages"; +const List _topNames = [_configVersionKey, _packagesKey]; +const String _nameKey = "name"; +const String _rootUriKey = "rootUri"; +const String _packageUriKey = "packageUri"; +const String _languageVersionKey = "languageVersion"; +const List _packageNames = [ + _nameKey, + _rootUriKey, + _packageUriKey, + _languageVersionKey +]; + +const String _generatedKey = "generated"; +const String _generatorKey = "generator"; +const String _generatorVersionKey = "generatorVersion"; + +/// Reads a package configuration file. +/// +/// Detects whether the [file] is a version one `.packages` file or +/// a version two `package_config.json` file. +/// +/// If the [file] is a `.packages` file, first checks whether there is an +/// adjacent `.dart_tool/package_config.json` file, and if so, +/// reads that instead. +/// +/// The file must exist and be a normal file. +Future readAnyConfigFile(File file) async { + var bytes = await file.readAsBytes(); + int firstChar = firstNonWhitespaceChar(bytes); + if (firstChar != $lbrace) { + // Definitely not a JSON object, probably a .packages. + var alternateFile = File(path.join( + path.dirname(file.path), ".dart_tool", "package_config.json")); + if (!alternateFile.existsSync()) { + return packages_file.parse(bytes, file.uri); + } + file = alternateFile; + bytes = await alternateFile.readAsBytes(); + } + return parsePackageConfigBytes(bytes, file.uri); +} + +/// Like [readAnyConfigFile] but uses a URI and an optional loader. +Future readAnyConfigFileUri( + Uri file, Future loader(Uri uri) /*?*/) async { + if (file.isScheme("package")) { + throw PackageConfigArgumentError( + file, "file", "Must not be a package: URI"); + } + if (loader == null) { + if (file.isScheme("file")) return readAnyConfigFile(File.fromUri(file)); + loader = defaultLoader; + } + var bytes = await loader(file); + if (bytes == null) { + throw PackageConfigArgumentError( + file.toString(), "file", "File cannot be read"); + } + int firstChar = firstNonWhitespaceChar(bytes); + if (firstChar != $lbrace) { + // Definitely not a JSON object, probably a .packages. + var alternateFile = file.resolveUri(packageConfigJsonPath); + var alternateBytes = await loader(alternateFile); + if (alternateBytes == null) { + return packages_file.parse(bytes, file); + } + bytes = alternateBytes; + file = alternateFile; + } + return parsePackageConfigBytes(bytes, file); +} + +Future readPackageConfigJsonFile(File file) async { + Uint8List bytes; + try { + bytes = await file.readAsBytes(); + } catch (_) { + return null; + } + return parsePackageConfigBytes(bytes, file.uri); +} + +Future readDotPackagesFile(File file) async { + Uint8List bytes; + try { + bytes = await file.readAsBytes(); + } catch (_) { + return null; + } + return packages_file.parse(bytes, file.uri); +} + +PackageConfig parsePackageConfigBytes(Uint8List bytes, Uri file) { + // TODO(lrn): Make this simpler. Maybe parse directly from bytes. + return parsePackageConfigJson(json.fuse(utf8).decode(bytes), file); +} + +/// Creates a [PackageConfig] from a parsed JSON-like object structure. +/// +/// The [json] argument must be a JSON object (`Map`) +/// containing a `"configVersion"` entry with an integer value in the range +/// 1 to [PackageConfig.maxVersion], +/// and with a `"packages"` entry which is a JSON array (`List`) +/// containing JSON objects which each has the following properties: +/// +/// * `"name"`: The package name as a string. +/// * `"rootUri"`: The root of the package as a URI stored as a string. +/// * `"packageUri"`: Optionally the root of for `package:` URI resolution +/// for the package, as a relative URI below the root URI +/// stored as a string. +/// * `"languageVersion"`: Optionally a language version string which is a +/// an integer numeral, a decimal point (`.`) and another integer numeral, +/// where the integer numeral cannot have a sign, and can only have a +/// leading zero if the entire numeral is a single zero. +/// +/// All other properties are stored in [extraData]. +/// +/// The [baseLocation] is used as base URI to resolve the "rootUri" +/// URI referencestring. +PackageConfig parsePackageConfigJson(dynamic json, Uri baseLocation) { + if (!baseLocation.hasScheme || baseLocation.isScheme("package")) { + throw PackageConfigArgumentError(baseLocation.toString(), "baseLocation", + "Must be an absolute non-package: URI"); + } + + if (!baseLocation.path.endsWith("/")) { + baseLocation = baseLocation.resolveUri(Uri(path: ".")); + } + + String typeName() { + if (0 is T) return "int"; + if ("" is T) return "string"; + if (const [] is T) return "array"; + return "object"; + } + + T checkType(dynamic value, String name, [String /*?*/ packageName]) { + if (value is T) return value; + // The only types we are called with are [int], [String], [List] + // and Map. Recognize which to give a better error message. + var message = + "$name${packageName != null ? " of package $packageName" : ""}" + " is not a JSON ${typeName()}"; + throw PackageConfigFormatException(message, value); + } + + Package parsePackage(Map entry) { + String /*?*/ name; + String /*?*/ rootUri; + String /*?*/ packageUri; + String /*?*/ languageVersion; + Map /*?*/ extraData; + entry.forEach((key, value) { + switch (key) { + case _nameKey: + name = checkType(value, _nameKey); + break; + case _rootUriKey: + rootUri = checkType(value, _rootUriKey, name); + break; + case _packageUriKey: + packageUri = checkType(value, _packageUriKey, name); + break; + case _languageVersionKey: + languageVersion = checkType(value, _languageVersionKey, name); + break; + default: + (extraData ??= {})[key] = value; + break; + } + }); + if (name == null) { + throw PackageConfigFormatException("Missing name entry", entry); + } + if (rootUri == null) { + throw PackageConfigFormatException("Missing rootUri entry", entry); + } + Uri root = baseLocation.resolve(rootUri); + Uri /*?*/ packageRoot = root; + if (packageUri != null) packageRoot = root.resolve(packageUri); + try { + return SimplePackage(name, root, packageRoot, languageVersion, extraData); + } on ArgumentError catch (e) { + throw PackageConfigFormatException(e.message, e.invalidValue); + } + } + + var map = checkType>(json, "value"); + Map /*?*/ extraData = null; + List /*?*/ packageList; + int /*?*/ configVersion; + map.forEach((key, value) { + switch (key) { + case _configVersionKey: + configVersion = checkType(value, _configVersionKey); + break; + case _packagesKey: + var packageArray = checkType>(value, _packagesKey); + var packages = []; + for (var package in packageArray) { + packages.add(parsePackage( + checkType>(package, "package entry"))); + } + packageList = packages; + break; + default: + (extraData ??= {})[key] = value; + break; + } + }); + if (configVersion == null) { + throw PackageConfigFormatException("Missing configVersion entry", json); + } + if (packageList == null) + throw PackageConfigFormatException("Missing packages list", json); + try { + return SimplePackageConfig(configVersion, packageList, extraData); + } on ArgumentError catch (e) { + throw PackageConfigFormatException(e.message, e.invalidValue); + } +} + +Future writePackageConfigJson( + PackageConfig config, Directory targetDirectory) async { + // Write .dart_tool/package_config.json first. + var file = File( + path.join(targetDirectory.path, ".dart_tool", "package_config.json")); + var baseUri = file.uri; + var extraData = config.extraData; + var data = { + _configVersionKey: PackageConfig.maxVersion, + _packagesKey: [ + for (var package in config.packages) + { + _nameKey: package.name, + _rootUriKey: relativizeUri(package.root, baseUri), + if (package.root != package.packageUriRoot) + _packageUriKey: relativizeUri(package.packageUriRoot, package.root), + if (package.languageVersion != null) + _languageVersionKey: package.languageVersion, + ...?_extractExtraData(package.extraData, _packageNames), + } + ], + ...?_extractExtraData(config.extraData, _topNames), + }; + + // Write .packages too. + String /*?*/ comment; + if (extraData != null) { + String /*?*/ generator = extraData[_generatorKey]; + if (generator != null) { + String /*?*/ generated = extraData[_generatedKey]; + String /*?*/ generatorVersion = extraData[_generatorVersionKey]; + comment = "Generated by $generator" + "${generatorVersion != null ? " $generatorVersion" : ""}" + "${generated != null ? " on $generated" : ""}."; + } + } + file = File(path.join(targetDirectory.path, ".packages")); + baseUri = file.uri; + var buffer = StringBuffer(); + packages_file.write(buffer, config, baseUri: baseUri, comment: comment); + + await Future.wait([ + file.writeAsString(JsonEncoder.withIndent(" ").convert(data)), + file.writeAsString(buffer.toString()), + ]); +} + +/// If "extraData" is a JSON map, then return it, otherwise return null. +/// +/// If the value contains any of the [reservedNames] for the current context, +/// entries with that name in the extra data are dropped. +Map /*?*/ _extractExtraData( + dynamic data, Iterable reservedNames) { + if (data is Map) { + if (data.isEmpty) return null; + for (var name in reservedNames) { + if (data.containsKey(name)) { + data = { + for (var key in data.keys) + if (!reservedNames.contains(key)) key: data[key] + }; + if (data.isEmpty) return null; + for (var value in data.values) { + if (!_validateJson(value)) return null; + } + } + } + return data; + } + return null; +} + +/// Checks that the object is a valid JSON-like data structure. +bool _validateJson(dynamic object) { + if (object == null || object == true || object == false) return true; + if (object is num || object is String) return true; + if (object is List) { + for (var element in object) if (!_validateJson(element)) return false; + return true; + } + if (object is Map) { + for (var value in object.values) if (!_validateJson(value)) return false; + return true; + } + return false; +} diff --git a/pkgs/package_config/lib/src/packages_file.dart b/pkgs/package_config/lib/src/packages_file.dart new file mode 100644 index 000000000..ac57b4f15 --- /dev/null +++ b/pkgs/package_config/lib/src/packages_file.dart @@ -0,0 +1,150 @@ +// Copyright (c) 2019, 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. + +import "package_config_impl.dart"; +import "package:charcode/ascii.dart"; + +import "util.dart" show isValidPackageName, relativizeUri; +import "errors.dart"; + +/// Parses a `.packages` file into a [PackageConfig]. +/// +/// The [source] is the byte content of a `.packages` file, assumed to be +/// UTF-8 encoded. In practice, all significant parts of the file must be ASCII, +/// so Latin-1 or Windows-1252 encoding will also work fine. +/// +/// If the file content is available as a string, its [String.codeUnits] can +/// be used as the `source` argument of this function. +/// +/// The [baseLocation] is used as a base URI to resolve all relative +/// URI references against. +/// If the content was read from a file, `baseLocation` should be the +/// location of that file. +/// +/// Returns a simple package configuration where each package's +/// [Package.packageUriRoot] is the same as its [Package.root] +/// and it has no [Package.languageVersion]. +PackageConfig parse(List source, Uri baseLocation) { + if (baseLocation.isScheme("package")) { + throw PackageConfigArgumentError( + baseLocation, "baseLocation", "Must not be a package: URI"); + } + int index = 0; + List packages = []; + Set packageNames = {}; + while (index < source.length) { + bool isComment = false; + int start = index; + int separatorIndex = -1; + int end = source.length; + int char = source[index++]; + if (char == $cr || char == $lf) { + continue; + } + if (char == $colon) { + throw PackageConfigFormatException( + "Missing package name", source, index - 1); + } + isComment = char == $hash; + while (index < source.length) { + char = source[index++]; + if (char == $colon && separatorIndex < 0) { + separatorIndex = index - 1; + } else if (char == $cr || char == $lf) { + end = index - 1; + break; + } + } + if (isComment) continue; + if (separatorIndex < 0) { + throw PackageConfigFormatException("No ':' on line", source, index - 1); + } + var packageName = String.fromCharCodes(source, start, separatorIndex); + if (!isValidPackageName(packageName)) { + throw PackageConfigFormatException( + "Not a valid package name", packageName, 0); + } + var packageValue = String.fromCharCodes(source, separatorIndex + 1, end); + Uri packageLocation = baseLocation.resolve(packageValue); + if (packageLocation.isScheme("package")) { + throw PackageConfigFormatException( + "Package URI as location for package", source, separatorIndex + 1); + } + if (packageLocation.hasQuery || packageLocation.hasFragment) { + throw PackageConfigFormatException( + "Location URI must not have query or fragment", source, start); + } + if (!packageLocation.path.endsWith('/')) { + packageLocation = + packageLocation.replace(path: packageLocation.path + "/"); + } + if (packageNames.contains(packageName)) { + throw PackageConfigFormatException( + "Same package name occured more than once", source, start); + } + packages.add(SimplePackage( + packageName, packageLocation, packageLocation, null, null)); + packageNames.add(packageName); + } + return SimplePackageConfig(1, packages, null); +} + +/// Writes the configuration to a [StringSink]. +/// +/// If [comment] is provided, the output will contain this comment +/// with `# ` in front of each line. +/// Lines are defined as ending in line feed (`'\n'`). If the final +/// line of the comment doesn't end in a line feed, one will be added. +/// +/// If [baseUri] is provided, package locations will be made relative +/// to the base URI, if possible, before writing. +/// +/// If [allowDefaultPackage] is `true`, the [packageMapping] may contain an +/// empty string mapping to the _default package name_. +/// +/// All the keys of [packageMapping] must be valid package names, +/// and the values must be URIs that do not have the `package:` scheme. +void write(StringSink output, PackageConfig config, + {Uri baseUri, String comment}) { + if (baseUri != null && !baseUri.isAbsolute) { + throw PackageConfigArgumentError(baseUri, "baseUri", "Must be absolute"); + } + + if (comment != null) { + var lines = comment.split('\n'); + if (lines.last.isEmpty) lines.removeLast(); + for (var commentLine in lines) { + output.write('# '); + output.writeln(commentLine); + } + } else { + output.write("# generated by package:package_config at "); + output.write(DateTime.now()); + output.writeln(); + } + for (var package in config.packages) { + var packageName = package.name; + var uri = package.packageUriRoot; + // Validate packageName. + if (!isValidPackageName(packageName)) { + throw PackageConfigArgumentError( + config, "config", '"$packageName" is not a valid package name'); + } + if (uri.scheme == "package") { + throw PackageConfigArgumentError( + config, "config", "Package location must not be a package URI: $uri"); + } + output.write(packageName); + output.write(':'); + // If baseUri provided, make uri relative. + if (baseUri != null) { + uri = relativizeUri(uri, baseUri); + } + if (!uri.path.endsWith('/')) { + uri = uri.replace(path: uri.path + '/'); + } + output.write(uri); + output.writeln(); + } +} diff --git a/pkgs/package_config/lib/src/packages_impl.dart b/pkgs/package_config/lib/src/packages_impl.dart deleted file mode 100644 index 817002f1e..000000000 --- a/pkgs/package_config/lib/src/packages_impl.dart +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright (c) 2015, 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. - -/// Implementations of [Packages] that may be used in either server or browser -/// based applications. For implementations that can only run in the browser, -/// see [package_config.packages_io_impl]. -library package_config.packages_impl; - -import "dart:collection" show UnmodifiableMapView; - -import "../packages.dart"; -import "util.dart" show checkValidPackageUri; - -/// A [Packages] null-object. -class NoPackages implements Packages { - const NoPackages(); - - Uri resolve(Uri packageUri, {Uri notFound(Uri packageUri)}) { - String packageName = checkValidPackageUri(packageUri); - if (notFound != null) return notFound(packageUri); - throw new ArgumentError.value( - packageUri, "packageUri", 'No package named "$packageName"'); - } - - Iterable get packages => new Iterable.empty(); - - Map asMap() => const {}; - - String get defaultPackageName => null; - - String packageMetadata(String packageName, String key) => null; - - String libraryMetadata(Uri libraryUri, String key) => null; -} - -/// Base class for [Packages] implementations. -/// -/// This class implements the [resolve] method in terms of a private -/// member -abstract class PackagesBase implements Packages { - Uri resolve(Uri packageUri, {Uri notFound(Uri packageUri)}) { - packageUri = packageUri.normalizePath(); - String packageName = checkValidPackageUri(packageUri); - Uri packageBase = getBase(packageName); - if (packageBase == null) { - if (notFound != null) return notFound(packageUri); - throw new ArgumentError.value( - packageUri, "packageUri", 'No package named "$packageName"'); - } - String packagePath = packageUri.path.substring(packageName.length + 1); - return packageBase.resolve(packagePath); - } - - /// Find a base location for a package name. - /// - /// Returns `null` if no package exists with that name, and that can be - /// determined. - Uri getBase(String packageName); - - String get defaultPackageName => null; - - String packageMetadata(String packageName, String key) => null; - - String libraryMetadata(Uri libraryUri, String key) => null; -} - -/// A [Packages] implementation based on an existing map. -class MapPackages extends PackagesBase { - final Map _mapping; - MapPackages(this._mapping); - - Uri getBase(String packageName) => - packageName.isEmpty ? null : _mapping[packageName]; - - Iterable get packages => _mapping.keys; - - Map asMap() => new UnmodifiableMapView(_mapping); - - String get defaultPackageName => _mapping[""]?.toString(); - - String packageMetadata(String packageName, String key) { - if (packageName.isEmpty) return null; - Uri uri = _mapping[packageName]; - if (uri == null || !uri.hasFragment) return null; - // This can be optimized, either by caching the map or by - // parsing incrementally instead of parsing the entire fragment. - return Uri.splitQueryString(uri.fragment)[key]; - } - - String libraryMetadata(Uri libraryUri, String key) { - if (libraryUri.isScheme("package")) { - return packageMetadata(libraryUri.pathSegments.first, key); - } - var defaultPackageNameUri = _mapping[""]; - if (defaultPackageNameUri != null) { - return packageMetadata(defaultPackageNameUri.toString(), key); - } - return null; - } -} - -/// A [Packages] implementation based on a remote (e.g., HTTP) directory. -/// -/// There is no way to detect which packages exist short of trying to use -/// them. You can't necessarily check whether a directory exists, -/// except by checking for a know file in the directory. -class NonFilePackagesDirectoryPackages extends PackagesBase { - final Uri _packageBase; - NonFilePackagesDirectoryPackages(this._packageBase); - - Uri getBase(String packageName) => _packageBase.resolve("$packageName/"); - - Error _failListingPackages() { - return new UnsupportedError( - "Cannot list packages for a ${_packageBase.scheme}: " - "based package root"); - } - - Iterable get packages { - throw _failListingPackages(); - } - - Map asMap() { - throw _failListingPackages(); - } -} diff --git a/pkgs/package_config/lib/src/packages_io_impl.dart b/pkgs/package_config/lib/src/packages_io_impl.dart deleted file mode 100644 index 9eba9ce44..000000000 --- a/pkgs/package_config/lib/src/packages_io_impl.dart +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2015, 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. - -/// Implementations of [Packages] that can only be used in server based -/// applications. -library package_config.packages_io_impl; - -import "dart:collection" show UnmodifiableMapView; -import "dart:io" show Directory; - -import "package:path/path.dart" as path; - -import "packages_impl.dart"; - -/// A [Packages] implementation based on a local directory. -class FilePackagesDirectoryPackages extends PackagesBase { - final Directory _packageDir; - final Map _packageToBaseUriMap = {}; - - FilePackagesDirectoryPackages(this._packageDir); - - Uri getBase(String packageName) { - return _packageToBaseUriMap.putIfAbsent(packageName, () { - return new Uri.file(path.join(_packageDir.path, packageName, '.')); - }); - } - - Iterable _listPackageNames() { - return _packageDir - .listSync() - .where((e) => e is Directory) - .map((e) => path.basename(e.path)); - } - - Iterable get packages => _listPackageNames(); - - Map asMap() { - var result = {}; - for (var packageName in _listPackageNames()) { - result[packageName] = getBase(packageName); - } - return new UnmodifiableMapView(result); - } -} diff --git a/pkgs/package_config/lib/src/util.dart b/pkgs/package_config/lib/src/util.dart index f1e1afd0a..25d7b89e4 100644 --- a/pkgs/package_config/lib/src/util.dart +++ b/pkgs/package_config/lib/src/util.dart @@ -1,12 +1,17 @@ -// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file +// Copyright (c) 2019, 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. /// Utility methods used by more than one library in the package. library package_config.util; +import 'dart:io'; +import 'dart:typed_data'; + import "package:charcode/ascii.dart"; +import "errors.dart"; + // All ASCII characters that are valid in a package name, with space // for all the invalid ones (including space). const String _validPackageNameCharacters = @@ -15,7 +20,7 @@ const String _validPackageNameCharacters = /// Tests whether something is a valid Dart package name. bool isValidPackageName(String string) { - return _findInvalidCharacter(string) < 0; + return checkPackageName(string) < 0; } /// Check if a string is a valid package name. @@ -26,7 +31,7 @@ bool isValidPackageName(String string) { /// Returns `-1` if the string is valid. /// Otherwise returns the index of the first invalid character, /// or `string.length` if the string contains no non-'.' character. -int _findInvalidCharacter(String string) { +int checkPackageName(String string) { // Becomes non-zero if any non-'.' character is encountered. int nonDot = 0; for (int i = 0; i < string.length; i++) { @@ -40,47 +45,46 @@ int _findInvalidCharacter(String string) { return -1; } -/// Validate that a Uri is a valid package:URI. -String checkValidPackageUri(Uri packageUri) { +/// Validate that a [Uri] is a valid `package:` URI. +String checkValidPackageUri(Uri packageUri, String name) { if (packageUri.scheme != "package") { - throw new ArgumentError.value( - packageUri, "packageUri", "Not a package: URI"); + throw PackageConfigArgumentError(packageUri, name, "Not a package: URI"); } if (packageUri.hasAuthority) { - throw new ArgumentError.value( - packageUri, "packageUri", "Package URIs must not have a host part"); + throw PackageConfigArgumentError( + packageUri, name, "Package URIs must not have a host part"); } if (packageUri.hasQuery) { // A query makes no sense if resolved to a file: URI. - throw new ArgumentError.value( - packageUri, "packageUri", "Package URIs must not have a query part"); + throw PackageConfigArgumentError( + packageUri, name, "Package URIs must not have a query part"); } if (packageUri.hasFragment) { // We could leave the fragment after the URL when resolving, // but it would be odd if "package:foo/foo.dart#1" and // "package:foo/foo.dart#2" were considered different libraries. // Keep the syntax open in case we ever get multiple libraries in one file. - throw new ArgumentError.value( - packageUri, "packageUri", "Package URIs must not have a fragment part"); + throw PackageConfigArgumentError( + packageUri, name, "Package URIs must not have a fragment part"); } if (packageUri.path.startsWith('/')) { - throw new ArgumentError.value( - packageUri, "packageUri", "Package URIs must not start with a '/'"); + throw PackageConfigArgumentError( + packageUri, name, "Package URIs must not start with a '/'"); } int firstSlash = packageUri.path.indexOf('/'); if (firstSlash == -1) { - throw new ArgumentError.value(packageUri, "packageUri", + throw PackageConfigArgumentError(packageUri, name, "Package URIs must start with the package name followed by a '/'"); } String packageName = packageUri.path.substring(0, firstSlash); - int badIndex = _findInvalidCharacter(packageName); + int badIndex = checkPackageName(packageName); if (badIndex >= 0) { if (packageName.isEmpty) { - throw new ArgumentError.value( - packageUri, "packageUri", "Package names mus be non-empty"); + throw PackageConfigArgumentError( + packageUri, name, "Package names mus be non-empty"); } if (badIndex == packageName.length) { - throw new ArgumentError.value(packageUri, "packageUri", + throw PackageConfigArgumentError(packageUri, name, "Package names must contain at least one non-'.' character"); } assert(badIndex < packageName.length); @@ -90,8 +94,211 @@ String checkValidPackageUri(Uri packageUri) { // Printable character. badChar = "'${packageName[badIndex]}' ($badChar)"; } - throw new ArgumentError.value( - packageUri, "packageUri", "Package names must not contain $badChar"); + throw PackageConfigArgumentError( + packageUri, name, "Package names must not contain $badChar"); } return packageName; } + +/// Checks whether [version] is a valid Dart language version string. +/// +/// The format is (as RegExp) `^(0|[1-9]\d+)\.(0|[1-9]\d+)$`. +/// +/// Returns the position of the first invalid character, or -1 if +/// the string is valid. +/// If the string is terminated early, the result is the length of the string. +int checkValidVersionNumber(String version) { + if (version == null) { + return 0; + } + int index = 0; + int dotsSeen = 0; + outer: + for (;;) { + // Check for numeral. + if (index == version.length) return index; + int char = version.codeUnitAt(index++); + int digit = char ^ 0x30; + if (digit != 0) { + if (digit < 9) { + while (index < version.length) { + char = version.codeUnitAt(index++); + digit = char ^ 0x30; + if (digit < 9) continue; + if (char == 0x2e /*.*/) { + if (dotsSeen > 0) return index - 1; + dotsSeen = 1; + continue outer; + } + return index - 1; + } + if (dotsSeen > 0) return -1; + return index; + } + return index - 1; + } + // Leading zero means numeral is over. + if (index >= version.length) { + if (dotsSeen > 0) return -1; + return index; + } + if (dotsSeen > 0) return index; + char = version.codeUnitAt(index++); + if (char != 0x2e /*.*/) return index - 1; + } +} + +/// Checks whether URI is just an absolute directory. +/// +/// * It must have a scheme. +/// * It must not have a query or fragment. +/// * The path must start and end with `/`. +bool isAbsoluteDirectoryUri(Uri uri) { + if (uri.hasQuery) return false; + if (uri.hasFragment) return false; + if (!uri.hasScheme) return false; + var path = uri.path; + if (!path.startsWith("/")) return false; + if (!path.endsWith("/")) return false; + return true; +} + +/// Whether the former URI is a prefix of the latter. +bool isUriPrefix(Uri prefix, Uri path) { + assert(!prefix.hasFragment); + assert(!prefix.hasQuery); + assert(!path.hasQuery); + assert(!path.hasFragment); + assert(prefix.path.endsWith('/')); + return path.toString().startsWith(prefix.toString()); +} + +/// Finds the first non-JSON-whitespace character in a file. +/// +/// Used to heuristically detect whether a file is a JSON file or an .ini file. +int firstNonWhitespaceChar(List bytes) { + for (int i = 0; i < bytes.length; i++) { + var char = bytes[i]; + if (char != 0x20 && char != 0x09 && char != 0x0a && char != 0x0d) { + return char; + } + } + return -1; +} + +/// Attempts to return a relative path-only URI for [uri]. +/// +/// First removes any query or fragment part from [uri]. +/// +/// If [uri] is already relative (has no scheme), it's returned as-is. +/// If that is not desired, the caller can pass `baseUri.resolveUri(uri)` +/// as the [uri] instead. +/// +/// If the [uri] has a scheme or authority part which differs from +/// the [baseUri], or if there is no overlap in the paths of the +/// two URIs at all, the [uri] is returned as-is. +/// +/// Otherwise the result is a path-only URI which satsifies +/// `baseUri.resolveUri(result) == uri`, +/// +/// The `baseUri` must be absolute. +Uri relativizeUri(Uri uri, Uri baseUri) { + assert(baseUri.isAbsolute); + if (uri.hasQuery || uri.hasFragment) { + uri = Uri( + scheme: uri.scheme, + userInfo: uri.hasAuthority ? uri.userInfo : null, + host: uri.hasAuthority ? uri.host : null, + port: uri.hasAuthority ? uri.port : null, + path: uri.path); + } + + // Already relative. We assume the caller knows what they are doing. + if (!uri.isAbsolute) return uri; + + if (baseUri.scheme != uri.scheme) { + return uri; + } + + // If authority differs, we could remove the scheme, but it's not worth it. + if (uri.hasAuthority != baseUri.hasAuthority) return uri; + if (uri.hasAuthority) { + if (uri.userInfo != baseUri.userInfo || + uri.host.toLowerCase() != baseUri.host.toLowerCase() || + uri.port != baseUri.port) { + return uri; + } + } + + baseUri = baseUri.normalizePath(); + List base = [...baseUri.pathSegments]; + if (base.isNotEmpty) base.removeLast(); + uri = uri.normalizePath(); + List target = [...uri.pathSegments]; + if (target.isNotEmpty && target.last.isEmpty) target.removeLast(); + int index = 0; + while (index < base.length && index < target.length) { + if (base[index] != target[index]) { + break; + } + index++; + } + if (index == base.length) { + if (index == target.length) { + return Uri(path: "./"); + } + return Uri(path: target.skip(index).join('/')); + } else if (index > 0) { + var buffer = StringBuffer(); + for (int n = base.length - index; n > 0; --n) { + buffer.write("../"); + } + buffer.writeAll(target.skip(index), "/"); + return Uri(path: buffer.toString()); + } else { + return uri; + } +} + +Future defaultLoader(Uri uri) async { + if (uri.isScheme("file")) { + var file = File.fromUri(uri); + try { + return file.readAsBytes(); + } catch (_) { + return null; + } + } + if (uri.isScheme("http") || uri.isScheme("https")) { + return _httpGet(uri); + } + throw UnsupportedError("Default URI unsupported scheme: $uri"); +} + +Future _httpGet(Uri uri) async { + assert(uri.isScheme("http") || uri.isScheme("https")); + HttpClient client = new HttpClient(); + HttpClientRequest request = await client.getUrl(uri); + HttpClientResponse response = await request.close(); + if (response.statusCode != HttpStatus.ok) { + return null; + } + List> splitContent = await response.toList(); + int totalLength = 0; + if (splitContent.length == 1) { + var part = splitContent[0]; + if (part is Uint8List) { + return part; + } + } + for (var list in splitContent) { + totalLength += list.length; + } + Uint8List result = new Uint8List(totalLength); + int offset = 0; + for (Uint8List contentPart in splitContent) { + result.setRange(offset, offset + contentPart.length, contentPart); + offset += contentPart.length; + } + return result; +} diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 72d299bf2..0cd7ddc52 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,11 +1,11 @@ -name: package_config -version: 1.2.0 -description: Support for working with Package Resolution config files. +name: package_config_2 +version: 2.0.0 +description: Support for working with Package Configuration files. author: Dart Team homepage: https://github.com/dart-lang/package_config environment: - sdk: '>=2.0.0-dev <3.0.0' + sdk: '>=2.5.0-dev <3.0.0' dependencies: charcode: ^1.1.0 diff --git a/pkgs/package_config/test/all.dart b/pkgs/package_config/test/all.dart deleted file mode 100644 index 78e6cffd1..000000000 --- a/pkgs/package_config/test/all.dart +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) 2015, 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. - -import "package:test/test.dart"; - -import "discovery_analysis_test.dart" as discovery_analysis; -import "discovery_test.dart" as discovery; -import "parse_test.dart" as parse; -import "parse_write_test.dart" as parse_write; - -main() { - group("parse:", parse.main); - group("discovery:", discovery.main); - group("discovery-analysis:", discovery_analysis.main); - group("parse/write:", parse_write.main); -} diff --git a/pkgs/package_config/test/discovery_analysis_test.dart b/pkgs/package_config/test/discovery_analysis_test.dart deleted file mode 100644 index e43245468..000000000 --- a/pkgs/package_config/test/discovery_analysis_test.dart +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) 2015, 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. - -library package_config.discovery_analysis_test; - -import "dart:async"; -import "dart:io"; - -import "package:package_config/discovery_analysis.dart"; -import "package:package_config/packages.dart"; -import "package:path/path.dart" as path; -import "package:test/test.dart"; - -main() { - fileTest("basic", { - ".packages": packagesFile, - "foo": {".packages": packagesFile}, - "bar": { - "packages": {"foo": {}, "bar": {}, "baz": {}} - }, - "baz": {} - }, (Directory directory) { - var dirUri = new Uri.directory(directory.path); - PackageContext ctx = PackageContext.findAll(directory); - PackageContext root = ctx[directory]; - expect(root, same(ctx)); - validatePackagesFile(root.packages, dirUri); - var fooDir = sub(directory, "foo"); - PackageContext foo = ctx[fooDir]; - expect(identical(root, foo), isFalse); - validatePackagesFile(foo.packages, dirUri.resolve("foo/")); - var barDir = sub(directory, "bar"); - PackageContext bar = ctx[sub(directory, "bar")]; - validatePackagesDir(bar.packages, dirUri.resolve("bar/")); - PackageContext barbar = ctx[sub(barDir, "bar")]; - expect(barbar, same(bar)); // inherited. - PackageContext baz = ctx[sub(directory, "baz")]; - expect(baz, same(root)); // inherited. - - var map = ctx.asMap(); - expect(map.keys.map((dir) => dir.path), - unorderedEquals([directory.path, fooDir.path, barDir.path])); - return null; - }); -} - -Directory sub(Directory parent, String dirName) { - return new Directory(path.join(parent.path, dirName)); -} - -const packagesFile = """ -# A comment -foo:file:///dart/packages/foo/ -bar:http://example.com/dart/packages/bar/ -baz:packages/baz/ -"""; - -void validatePackagesFile(Packages resolver, Uri location) { - expect(resolver, isNotNull); - expect(resolver.resolve(pkg("foo", "bar/baz")), - equals(Uri.parse("file:///dart/packages/foo/bar/baz"))); - expect(resolver.resolve(pkg("bar", "baz/qux")), - equals(Uri.parse("http://example.com/dart/packages/bar/baz/qux"))); - expect(resolver.resolve(pkg("baz", "qux/foo")), - equals(location.resolve("packages/baz/qux/foo"))); - expect(resolver.packages, unorderedEquals(["foo", "bar", "baz"])); -} - -void validatePackagesDir(Packages resolver, Uri location) { - // Expect three packages: foo, bar and baz - expect(resolver, isNotNull); - expect(resolver.resolve(pkg("foo", "bar/baz")), - equals(location.resolve("packages/foo/bar/baz"))); - expect(resolver.resolve(pkg("bar", "baz/qux")), - equals(location.resolve("packages/bar/baz/qux"))); - expect(resolver.resolve(pkg("baz", "qux/foo")), - equals(location.resolve("packages/baz/qux/foo"))); - if (location.scheme == "file") { - expect(resolver.packages, unorderedEquals(["foo", "bar", "baz"])); - } else { - expect(() => resolver.packages, throwsUnsupportedError); - } -} - -Uri pkg(String packageName, String packagePath) { - var path; - if (packagePath.startsWith('/')) { - path = "$packageName$packagePath"; - } else { - path = "$packageName/$packagePath"; - } - return new Uri(scheme: "package", path: path); -} - -/// Create a directory structure from [description] and run [fileTest]. -/// -/// Description is a map, each key is a file entry. If the value is a map, -/// it's a sub-dir, otherwise it's a file and the value is the content -/// as a string. -void fileTest( - String name, Map description, Future fileTest(Directory directory)) { - group("file-test", () { - Directory tempDir = Directory.systemTemp.createTempSync("file-test"); - setUp(() { - _createFiles(tempDir, description); - }); - tearDown(() { - tempDir.deleteSync(recursive: true); - }); - test(name, () => fileTest(tempDir)); - }); -} - -void _createFiles(Directory target, Map description) { - description.forEach((name, content) { - if (content is Map) { - Directory subDir = new Directory(path.join(target.path, name)); - subDir.createSync(); - _createFiles(subDir, content); - } else { - File file = new File(path.join(target.path, name)); - file.writeAsStringSync(content, flush: true); - } - }); -} diff --git a/pkgs/package_config/test/discovery_test.dart b/pkgs/package_config/test/discovery_test.dart index 282427289..5db24a100 100644 --- a/pkgs/package_config/test/discovery_test.dart +++ b/pkgs/package_config/test/discovery_test.dart @@ -1,327 +1,250 @@ -// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file +// Copyright (c) 2019, 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. library package_config.discovery_test; -import "dart:async"; import "dart:io"; import "package:test/test.dart"; -import "package:package_config/packages.dart"; -import "package:package_config/discovery.dart"; -import "package:path/path.dart" as path; +import "package:package_config_2/package_config.dart"; + +import "src/util.dart"; const packagesFile = """ # A comment foo:file:///dart/packages/foo/ -bar:http://example.com/dart/packages/bar/ +bar:/dart/packages/bar/ baz:packages/baz/ """; -void validatePackagesFile(Packages resolver, Uri location) { - expect(resolver, isNotNull); - expect(resolver.resolve(pkg("foo", "bar/baz")), - equals(Uri.parse("file:///dart/packages/foo/bar/baz"))); - expect(resolver.resolve(pkg("bar", "baz/qux")), - equals(Uri.parse("http://example.com/dart/packages/bar/baz/qux"))); - expect(resolver.resolve(pkg("baz", "qux/foo")), - equals(location.resolve("packages/baz/qux/foo"))); - expect(resolver.packages, unorderedEquals(["foo", "bar", "baz"])); +const packageConfigFile = """ +{ + "configVersion": 2, + "packages": [ + { + "name": "foo", + "rootUri": "file:///dart/packages/foo/" + }, + { + "name": "bar", + "rootUri": "/dart/packages/bar/" + }, + { + "name": "baz", + "rootUri": "../packages/baz/" + } + ], + "extra": [42] } +"""; -void validatePackagesDir(Packages resolver, Uri location) { - // Expect three packages: foo, bar and baz +void validatePackagesFile(PackageConfig resolver, Directory directory) { expect(resolver, isNotNull); expect(resolver.resolve(pkg("foo", "bar/baz")), - equals(location.resolve("packages/foo/bar/baz"))); + equals(Uri.parse("file:///dart/packages/foo/bar/baz"))); expect(resolver.resolve(pkg("bar", "baz/qux")), - equals(location.resolve("packages/bar/baz/qux"))); + equals(Uri.parse("file:///dart/packages/bar/baz/qux"))); expect(resolver.resolve(pkg("baz", "qux/foo")), - equals(location.resolve("packages/baz/qux/foo"))); - if (location.scheme == "file") { - expect(resolver.packages, unorderedEquals(["foo", "bar", "baz"])); - } else { - expect(() => resolver.packages, throwsUnsupportedError); - } -} - -Uri pkg(String packageName, String packagePath) { - var path; - if (packagePath.startsWith('/')) { - path = "$packageName$packagePath"; - } else { - path = "$packageName/$packagePath"; - } - return new Uri(scheme: "package", path: path); + equals(Uri.directory(directory.path).resolve("packages/baz/qux/foo"))); + expect([for (var p in resolver.packages) p.name], + unorderedEquals(["foo", "bar", "baz"])); } main() { - generalTest(".packages", { - ".packages": packagesFile, - "script.dart": "main(){}", - "packages": {"shouldNotBeFound": {}} - }, (Uri location) async { - Packages resolver; - resolver = await findPackages(location); - validatePackagesFile(resolver, location); - resolver = await findPackages(location.resolve("script.dart")); - validatePackagesFile(resolver, location); - var specificDiscovery = (location.scheme == "file") - ? findPackagesFromFile - : findPackagesFromNonFile; - resolver = await specificDiscovery(location); - validatePackagesFile(resolver, location); - resolver = await specificDiscovery(location.resolve("script.dart")); - validatePackagesFile(resolver, location); - }); - - generalTest("packages/", { - "packages": {"foo": {}, "bar": {}, "baz": {}}, - "script.dart": "main(){}" - }, (Uri location) async { - Packages resolver; - bool isFile = (location.scheme == "file"); - resolver = await findPackages(location); - validatePackagesDir(resolver, location); - resolver = await findPackages(location.resolve("script.dart")); - validatePackagesDir(resolver, location); - var specificDiscovery = - isFile ? findPackagesFromFile : findPackagesFromNonFile; - resolver = await specificDiscovery(location); - validatePackagesDir(resolver, location); - resolver = await specificDiscovery(location.resolve("script.dart")); - validatePackagesDir(resolver, location); - }); - - generalTest("underscore packages", { - "packages": {"_foo": {}} - }, (Uri location) async { - Packages resolver = await findPackages(location); - expect(resolver.resolve(pkg("_foo", "foo.dart")), - equals(location.resolve("packages/_foo/foo.dart"))); - }); - - fileTest(".packages recursive", { - ".packages": packagesFile, - "subdir": {"script.dart": "main(){}"} - }, (Uri location) async { - Packages resolver; - resolver = await findPackages(location.resolve("subdir/")); - validatePackagesFile(resolver, location); - resolver = await findPackages(location.resolve("subdir/script.dart")); - validatePackagesFile(resolver, location); - resolver = await findPackagesFromFile(location.resolve("subdir/")); - validatePackagesFile(resolver, location); - resolver = - await findPackagesFromFile(location.resolve("subdir/script.dart")); - validatePackagesFile(resolver, location); - }); + group("findPackages", () { + // Finds package_config.json if there. + fileTest("package_config.json", { + ".packages": "invalid .packages file", + "script.dart": "main(){}", + "packages": {"shouldNotBeFound": {}}, + ".dart_tool": { + "package_config.json": packageConfigFile, + } + }, (Directory directory) async { + PackageConfig config = await findPackageConfig(directory); + expect(config.version, 2); // Found package_config.json file. + validatePackagesFile(config, directory); + }); - httpTest(".packages not recursive", { - ".packages": packagesFile, - "subdir": {"script.dart": "main(){}"} - }, (Uri location) async { - Packages resolver; - var subdir = location.resolve("subdir/"); - resolver = await findPackages(subdir); - validatePackagesDir(resolver, subdir); - resolver = await findPackages(subdir.resolve("script.dart")); - validatePackagesDir(resolver, subdir); - resolver = await findPackagesFromNonFile(subdir); - validatePackagesDir(resolver, subdir); - resolver = await findPackagesFromNonFile(subdir.resolve("script.dart")); - validatePackagesDir(resolver, subdir); - }); + // Finds .packages if no package_config.json. + fileTest(".packages", { + ".packages": packagesFile, + "script.dart": "main(){}", + "packages": {"shouldNotBeFound": {}} + }, (Directory directory) async { + PackageConfig config = await findPackageConfig(directory); + expect(config.version, 1); // Found .packages file. + validatePackagesFile(config, directory); + }); - fileTest("no packages", {"script.dart": "main(){}"}, (Uri location) async { - // A file: location with no .packages or packages returns - // Packages.noPackages. - Packages resolver; - resolver = await findPackages(location); - expect(resolver, same(Packages.noPackages)); - resolver = await findPackages(location.resolve("script.dart")); - expect(resolver, same(Packages.noPackages)); - resolver = findPackagesFromFile(location); - expect(resolver, same(Packages.noPackages)); - resolver = findPackagesFromFile(location.resolve("script.dart")); - expect(resolver, same(Packages.noPackages)); - }); + // Finds package_config.json in super-directory. + fileTest("package_config.json recursive", { + ".packages": packagesFile, + ".dart_tool": { + "package_config.json": packageConfigFile, + }, + "subdir": { + "script.dart": "main(){}", + } + }, (Directory directory) async { + PackageConfig config = + await findPackageConfig(subdir(directory, "subdir/")); + expect(config.version, 2); + validatePackagesFile(config, directory); + }); - httpTest("no packages", {"script.dart": "main(){}"}, (Uri location) async { - // A non-file: location with no .packages or packages/: - // Assumes a packages dir exists, and resolves relative to that. - Packages resolver; - resolver = await findPackages(location); - validatePackagesDir(resolver, location); - resolver = await findPackages(location.resolve("script.dart")); - validatePackagesDir(resolver, location); - resolver = await findPackagesFromNonFile(location); - validatePackagesDir(resolver, location); - resolver = await findPackagesFromNonFile(location.resolve("script.dart")); - validatePackagesDir(resolver, location); - }); + // Finds .packages in super-directory. + fileTest(".packages recursive", { + ".packages": packagesFile, + "subdir": {"script.dart": "main(){}"} + }, (Directory directory) async { + PackageConfig config; + config = await findPackageConfig(subdir(directory, "subdir/")); + expect(config.version, 1); + validatePackagesFile(config, directory); + }); - test(".packages w/ loader", () async { - Uri location = Uri.parse("krutch://example.com/path/"); - Future> loader(Uri file) async { - if (file.path.endsWith(".packages")) { - return packagesFile.codeUnits; + // Does not find a packages/ directory, and returns null if nothing found. + fileTest("package directory packages not supported", { + "packages": { + "foo": {}, } - throw "not found"; - } - - // A non-file: location with no .packages or packages/: - // Assumes a packages dir exists, and resolves relative to that. - Packages resolver; - resolver = await findPackages(location, loader: loader); - validatePackagesFile(resolver, location); - resolver = - await findPackages(location.resolve("script.dart"), loader: loader); - validatePackagesFile(resolver, location); - resolver = await findPackagesFromNonFile(location, loader: loader); - validatePackagesFile(resolver, location); - resolver = await findPackagesFromNonFile(location.resolve("script.dart"), - loader: loader); - validatePackagesFile(resolver, location); - }); + }, (Directory directory) async { + PackageConfig config = await findPackageConfig(directory); + expect(config, null); + }); - test("no packages w/ loader", () async { - Uri location = Uri.parse("krutch://example.com/path/"); - Future> loader(Uri file) async { - throw "not found"; - } + fileTest("invalid .packages", { + ".packages": "not a .packages file", + }, (Directory directory) { + expect(() => findPackageConfig(directory), + throwsA(TypeMatcher())); + }); - // A non-file: location with no .packages or packages/: - // Assumes a packages dir exists, and resolves relative to that. - Packages resolver; - resolver = await findPackages(location, loader: loader); - validatePackagesDir(resolver, location); - resolver = - await findPackages(location.resolve("script.dart"), loader: loader); - validatePackagesDir(resolver, location); - resolver = await findPackagesFromNonFile(location, loader: loader); - validatePackagesDir(resolver, location); - resolver = await findPackagesFromNonFile(location.resolve("script.dart"), - loader: loader); - validatePackagesDir(resolver, location); - }); + fileTest("invalid .packages as JSON", { + ".packages": packageConfigFile, + }, (Directory directory) { + expect(() => findPackageConfig(directory), + throwsA(TypeMatcher())); + }); - generalTest("loadPackagesFile", {".packages": packagesFile}, - (Uri directory) async { - Uri file = directory.resolve(".packages"); - Packages resolver = await loadPackagesFile(file); - validatePackagesFile(resolver, file); - }); + fileTest("invalid .packages", { + ".dart_tool": { + "package_config.json": "not a JSON file", + } + }, (Directory directory) { + expect(() => findPackageConfig(directory), + throwsA(TypeMatcher())); + }); - generalTest( - "loadPackagesFile non-default name", {"pheldagriff": packagesFile}, - (Uri directory) async { - Uri file = directory.resolve("pheldagriff"); - Packages resolver = await loadPackagesFile(file); - validatePackagesFile(resolver, file); + fileTest("invalid .packages as INI", { + ".dart_tool": { + "package_config.json": packagesFile, + } + }, (Directory directory) { + expect(() => findPackageConfig(directory), + throwsA(TypeMatcher())); + }); }); - test("loadPackagesFile w/ loader", () async { - Future> loader(Uri uri) async => packagesFile.codeUnits; - Uri file = Uri.parse("krutz://example.com/.packages"); - Packages resolver = await loadPackagesFile(file, loader: loader); - validatePackagesFile(resolver, file); - }); + group("loadPackageConfig", () { + // Load a specific files + group("package_config.json", () { + var files = { + ".packages": packagesFile, + ".dart_tool": { + "package_config.json": packageConfigFile, + }, + }; + fileTest("directly", files, (Directory directory) async { + File file = + dirFile(subdir(directory, ".dart_tool"), "package_config.json"); + PackageConfig config = await loadPackageConfig(file); + expect(config.version, 2); + validatePackagesFile(config, directory); + }); + fileTest("indirectly through .packages", files, + (Directory directory) async { + File file = dirFile(directory, ".packages"); + PackageConfig config = await loadPackageConfig(file); + expect(config.version, 2); + validatePackagesFile(config, directory); + }); + }); - generalTest("loadPackagesFile not found", {}, (Uri directory) async { - Uri file = directory.resolve(".packages"); - expect( - loadPackagesFile(file), - throwsA(anyOf(new TypeMatcher(), - new TypeMatcher()))); - }); + fileTest("package_config.json non-default name", { + ".packages": packagesFile, + "subdir": { + "pheldagriff": packageConfigFile, + }, + }, (Directory directory) async { + File file = dirFile(directory, "subdir/pheldagriff"); + PackageConfig config = await loadPackageConfig(file); + expect(config.version, 2); + validatePackagesFile(config, directory); + }); - generalTest("loadPackagesFile syntax error", {".packages": "syntax error"}, - (Uri directory) async { - Uri file = directory.resolve(".packages"); - expect(loadPackagesFile(file), throwsFormatException); - }); + fileTest("package_config.json named .packages", { + "subdir": { + ".packages": packageConfigFile, + }, + }, (Directory directory) async { + File file = dirFile(directory, "subdir/.packages"); + PackageConfig config = await loadPackageConfig(file); + expect(config.version, 2); + validatePackagesFile(config, directory); + }); - 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")); - }); -} + fileTest(".packages", { + ".packages": packagesFile, + }, (Directory directory) async { + File file = dirFile(directory, ".packages"); + PackageConfig config = await loadPackageConfig(file); + expect(config.version, 1); + validatePackagesFile(config, directory); + }); -/// Create a directory structure from [description] and run [fileTest]. -/// -/// Description is a map, each key is a file entry. If the value is a map, -/// it's a sub-dir, otherwise it's a file and the value is the content -/// as a string. -void fileTest(String name, Map description, Future fileTest(Uri directory)) { - group("file-test", () { - Directory tempDir = Directory.systemTemp.createTempSync("file-test"); - setUp(() { - _createFiles(tempDir, description); + fileTest(".packages non-default name", { + "pheldagriff": packagesFile, + }, (Directory directory) async { + File file = dirFile(directory, "pheldagriff"); + PackageConfig config = await loadPackageConfig(file); + expect(config.version, 1); + validatePackagesFile(config, directory); }); - tearDown(() { - tempDir.deleteSync(recursive: true); + + fileTest("no config found", {}, (Directory directory) { + File file = dirFile(directory, "anyname"); + expect(() => loadPackageConfig(file), + throwsA(TypeMatcher())); }); - test(name, () => fileTest(new Uri.file(path.join(tempDir.path, ".")))); - }); -} -/// HTTP-server the directory structure from [description] and run [htpTest]. -/// -/// Description is a map, each key is a file entry. If the value is a map, -/// it's a sub-dir, otherwise it's a file and the value is the content -/// as a string. -void httpTest(String name, Map description, Future httpTest(Uri directory)) { - group("http-test", () { - var serverSub; - var uri; - setUp(() { - return HttpServer.bind(InternetAddress.loopbackIPv4, 0).then((server) { - uri = new Uri( - scheme: "http", host: "127.0.0.1", port: server.port, path: "/"); - serverSub = server.listen((HttpRequest request) { - // No error handling. - var path = request.uri.path; - if (path.startsWith('/')) path = path.substring(1); - if (path.endsWith('/')) path = path.substring(0, path.length - 1); - var parts = path.split('/'); - dynamic fileOrDir = description; - for (int i = 0; i < parts.length; i++) { - fileOrDir = fileOrDir[parts[i]]; - if (fileOrDir == null) { - request.response.statusCode = 404; - request.response.close(); - return; - } - } - request.response.write(fileOrDir); - request.response.close(); - }); - }); + fileTest("specified file syntax error", { + "anyname": "syntax error", + }, (Directory directory) { + File file = dirFile(directory, "anyname"); + expect(() => loadPackageConfig(file), throwsFormatException); }); - tearDown(() => serverSub.cancel()); - test(name, () => httpTest(uri)); - }); -} -void generalTest(String name, Map description, Future action(Uri location)) { - fileTest(name, description, action); - httpTest(name, description, action); -} + // Find package_config.json in subdir even if initial file syntax error. + fileTest("specified file syntax error", { + "anyname": "syntax error", + ".dart_tool": { + "package_config.json": packageConfigFile, + }, + }, (Directory directory) async { + File file = dirFile(directory, "anyname"); + PackageConfig config = await loadPackageConfig(file); + expect(config.version, 2); + validatePackagesFile(config, directory); + }); -void _createFiles(Directory target, Map description) { - description.forEach((name, content) { - if (content is Map) { - Directory subDir = new Directory(path.join(target.path, name)); - subDir.createSync(); - _createFiles(subDir, content); - } else { - File file = new File(path.join(target.path, name)); - file.writeAsStringSync(content, flush: true); - } + // A file starting with `{` is a package_config.json file. + fileTest("file syntax error with {", { + ".packages": "{syntax error", + }, (Directory directory) { + File file = dirFile(directory, ".packages"); + expect(() => loadPackageConfig(file), throwsFormatException); + }); }); } diff --git a/pkgs/package_config/test/discovery_uri_test.dart b/pkgs/package_config/test/discovery_uri_test.dart new file mode 100644 index 000000000..414a43add --- /dev/null +++ b/pkgs/package_config/test/discovery_uri_test.dart @@ -0,0 +1,256 @@ +// Copyright (c) 2019, 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. + +library package_config.discovery_test; + +import "dart:io"; +import "package:test/test.dart"; +import "package:package_config_2/package_config.dart"; + +import "src/util.dart"; + +const packagesFile = """ +# A comment +foo:file:///dart/packages/foo/ +bar:/dart/packages/bar/ +baz:packages/baz/ +"""; + +const packageConfigFile = """ +{ + "configVersion": 2, + "packages": [ + { + "name": "foo", + "rootUri": "file:///dart/packages/foo/" + }, + { + "name": "bar", + "rootUri": "/dart/packages/bar/" + }, + { + "name": "baz", + "rootUri": "../packages/baz/" + } + ], + "extra": [42] +} +"""; + +void validatePackagesFile(PackageConfig resolver, Uri directory) { + expect(resolver, isNotNull); + expect(resolver.resolve(pkg("foo", "bar/baz")), + equals(Uri.parse("file:///dart/packages/foo/bar/baz"))); + expect(resolver.resolve(pkg("bar", "baz/qux")), + equals(directory.resolve("/dart/packages/bar/baz/qux"))); + expect(resolver.resolve(pkg("baz", "qux/foo")), + equals(directory.resolve("packages/baz/qux/foo"))); + expect([for (var p in resolver.packages) p.name], + unorderedEquals(["foo", "bar", "baz"])); +} + +main() { + group("findPackages", () { + // Finds package_config.json if there. + loaderTest("package_config.json", { + ".packages": "invalid .packages file", + "script.dart": "main(){}", + "packages": {"shouldNotBeFound": {}}, + ".dart_tool": { + "package_config.json": packageConfigFile, + } + }, (Uri directory, loader) async { + PackageConfig config = + await findPackageConfigUri(directory, loader: loader); + expect(config.version, 2); // Found package_config.json file. + validatePackagesFile(config, directory); + }); + + // Finds .packages if no package_config.json. + loaderTest(".packages", { + ".packages": packagesFile, + "script.dart": "main(){}", + "packages": {"shouldNotBeFound": {}} + }, (Uri directory, loader) async { + PackageConfig config = + await findPackageConfigUri(directory, loader: loader); + expect(config.version, 1); // Found .packages file. + validatePackagesFile(config, directory); + }); + + // Finds package_config.json in super-directory. + loaderTest("package_config.json recursive", { + ".packages": packagesFile, + ".dart_tool": { + "package_config.json": packageConfigFile, + }, + "subdir": { + "script.dart": "main(){}", + } + }, (Uri directory, loader) async { + PackageConfig config = await findPackageConfigUri( + directory.resolve("subdir/"), + loader: loader); + expect(config.version, 2); + validatePackagesFile(config, directory); + }); + + // Finds .packages in super-directory. + loaderTest(".packages recursive", { + ".packages": packagesFile, + "subdir": {"script.dart": "main(){}"} + }, (Uri directory, loader) async { + PackageConfig config; + config = await findPackageConfigUri(directory.resolve("subdir/"), + loader: loader); + expect(config.version, 1); + validatePackagesFile(config, directory); + }); + + // Does not find a packages/ directory, and returns null if nothing found. + loaderTest("package directory packages not supported", { + "packages": { + "foo": {}, + } + }, (Uri directory, loader) async { + PackageConfig config = + await findPackageConfigUri(directory, loader: loader); + expect(config, null); + }); + + loaderTest("invalid .packages", { + ".packages": "not a .packages file", + }, (Uri directory, loader) { + expect(() => findPackageConfigUri(directory, loader: loader), + throwsA(TypeMatcher())); + }); + + loaderTest("invalid .packages as JSON", { + ".packages": packageConfigFile, + }, (Uri directory, loader) { + expect(() => findPackageConfigUri(directory, loader: loader), + throwsA(TypeMatcher())); + }); + + loaderTest("invalid .packages", { + ".dart_tool": { + "package_config.json": "not a JSON file", + } + }, (Uri directory, loader) { + expect(() => findPackageConfigUri(directory, loader: loader), + throwsA(TypeMatcher())); + }); + + loaderTest("invalid .packages as INI", { + ".dart_tool": { + "package_config.json": packagesFile, + } + }, (Uri directory, loader) { + expect(() => findPackageConfigUri(directory, loader: loader), + throwsA(TypeMatcher())); + }); + }); + + group("loadPackageConfig", () { + // Load a specific files + group("package_config.json", () { + var files = { + ".packages": packagesFile, + ".dart_tool": { + "package_config.json": packageConfigFile, + }, + }; + loaderTest("directly", files, (Uri directory, loader) async { + Uri file = directory.resolve(".dart_tool/package_config.json"); + PackageConfig config = await loadPackageConfigUri(file, loader: loader); + expect(config.version, 2); + validatePackagesFile(config, directory); + }); + loaderTest("indirectly through .packages", files, + (Uri directory, loader) async { + Uri file = directory.resolve(".packages"); + PackageConfig config = await loadPackageConfigUri(file, loader: loader); + expect(config.version, 2); + validatePackagesFile(config, directory); + }); + }); + + loaderTest("package_config.json non-default name", { + ".packages": packagesFile, + "subdir": { + "pheldagriff": packageConfigFile, + }, + }, (Uri directory, loader) async { + Uri file = directory.resolve("subdir/pheldagriff"); + PackageConfig config = await loadPackageConfigUri(file, loader: loader); + expect(config.version, 2); + validatePackagesFile(config, directory); + }); + + loaderTest("package_config.json named .packages", { + "subdir": { + ".packages": packageConfigFile, + }, + }, (Uri directory, loader) async { + Uri file = directory.resolve("subdir/.packages"); + PackageConfig config = await loadPackageConfigUri(file, loader: loader); + expect(config.version, 2); + validatePackagesFile(config, directory); + }); + + loaderTest(".packages", { + ".packages": packagesFile, + }, (Uri directory, loader) async { + Uri file = directory.resolve(".packages"); + PackageConfig config = await loadPackageConfigUri(file, loader: loader); + expect(config.version, 1); + validatePackagesFile(config, directory); + }); + + loaderTest(".packages non-default name", { + "pheldagriff": packagesFile, + }, (Uri directory, loader) async { + Uri file = directory.resolve("pheldagriff"); + PackageConfig config = await loadPackageConfigUri(file, loader: loader); + expect(config.version, 1); + validatePackagesFile(config, directory); + }); + + loaderTest("no config found", {}, (Uri directory, loader) { + Uri file = directory.resolve("anyname"); + expect(() => loadPackageConfigUri(file, loader: loader), + throwsArgumentError); + }); + + loaderTest("specified file syntax error", { + "anyname": "syntax error", + }, (Uri directory, loader) { + Uri file = directory.resolve("anyname"); + expect(() => loadPackageConfigUri(file, loader: loader), + throwsFormatException); + }); + + // Find package_config.json in subdir even if initial file syntax error. + loaderTest("specified file syntax error", { + "anyname": "syntax error", + ".dart_tool": { + "package_config.json": packageConfigFile, + }, + }, (Uri directory, loader) async { + Uri file = directory.resolve("anyname"); + PackageConfig config = await loadPackageConfigUri(file, loader: loader); + expect(config.version, 2); + validatePackagesFile(config, directory); + }); + + // A file starting with `{` is a package_config.json file. + loaderTest("file syntax error with {", { + ".packages": "{syntax error", + }, (Uri directory, loader) { + Uri file = directory.resolve(".packages"); + expect(() => loadPackageConfigUri(file, loader: loader), + throwsFormatException); + }); + }); +} diff --git a/pkgs/package_config/test/parse_test.dart b/pkgs/package_config/test/parse_test.dart index b9b1bb510..235f49381 100644 --- a/pkgs/package_config/test/parse_test.dart +++ b/pkgs/package_config/test/parse_test.dart @@ -1,245 +1,312 @@ -// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file +// Copyright (c) 2019, 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. -library package_config.parse_test; +import "dart:io"; +import "dart:convert"; -import "package:package_config/packages.dart"; -import "package:package_config/packages_file.dart" show parse; -import "package:package_config/src/packages_impl.dart"; import "package:test/test.dart"; -main() { - var base = Uri.parse("file:///one/two/three/packages.map"); - test("empty", () { - var packages = doParse(emptySample, base); - expect(packages.asMap(), isEmpty); - }); - test("comment only", () { - var packages = doParse(commentOnlySample, base); - expect(packages.asMap(), isEmpty); - }); - test("empty lines only", () { - var packages = doParse(emptyLinesSample, base); - expect(packages.asMap(), isEmpty); - }); - - test("empty lines only", () { - var packages = doParse(emptyLinesSample, base); - expect(packages.asMap(), isEmpty); - }); - - test("single", () { - var packages = doParse(singleRelativeSample, base); - expect(packages.packages.toList(), equals(["foo"])); - expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), - equals(base.resolve("../test/").resolve("bar/baz.dart"))); - }); - - test("single no slash", () { - var packages = doParse(singleRelativeSampleNoSlash, base); - expect(packages.packages.toList(), equals(["foo"])); - expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), - equals(base.resolve("../test/").resolve("bar/baz.dart"))); - }); - - test("single no newline", () { - var packages = doParse(singleRelativeSampleNoNewline, base); - expect(packages.packages.toList(), equals(["foo"])); - expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), - equals(base.resolve("../test/").resolve("bar/baz.dart"))); - }); - - test("single absolute authority", () { - var packages = doParse(singleAbsoluteSample, base); - expect(packages.packages.toList(), equals(["foo"])); - expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), - equals(Uri.parse("http://example.com/some/where/bar/baz.dart"))); - }); - - test("single empty path", () { - var packages = doParse(singleEmptyPathSample, base); - expect(packages.packages.toList(), equals(["foo"])); - expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), - equals(base.replace(path: "${base.path}/bar/baz.dart"))); - }); +import "package:package_config_2/src/packages_file.dart" as packages; +import "package:package_config_2/src/package_config_json.dart"; +import "src/util.dart"; - test("single absolute path", () { - var packages = doParse(singleAbsolutePathSample, base); - expect(packages.packages.toList(), equals(["foo"])); - expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), - equals(base.replace(path: "/test/bar/baz.dart"))); - }); +void main() { + group(".packages", () { + test("valid", () { + var packagesFile = "# Generated by pub yadda yadda\n" + "foo:file:///foo/lib/\n" + "bar:/bar/lib/\n" + "baz:lib/\n"; + var result = packages.parse( + utf8.encode(packagesFile), Uri.parse("file:///tmp/file.dart")); + expect(result.version, 1); + expect({for (var p in result.packages) p.name}, {"foo", "bar", "baz"}); + expect(result.resolve(pkg("foo", "foo.dart")), + Uri.parse("file:///foo/lib/foo.dart")); + expect(result.resolve(pkg("bar", "bar.dart")), + Uri.parse("file:///bar/lib/bar.dart")); + expect(result.resolve(pkg("baz", "baz.dart")), + Uri.parse("file:///tmp/lib/baz.dart")); - test("multiple", () { - var packages = doParse(multiRelativeSample, base); - expect(packages.packages.toList()..sort(), equals(["bar", "foo"])); - expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), - equals(base.resolve("../test/").resolve("bar/baz.dart"))); - expect(packages.resolve(Uri.parse("package:bar/foo/baz.dart")), - equals(base.resolve("../test2/").resolve("foo/baz.dart"))); - }); + var foo = result["foo"]; + expect(foo, isNotNull); + expect(foo.root, Uri.parse("file:///foo/lib/")); + expect(foo.packageUriRoot, Uri.parse("file:///foo/lib/")); + expect(foo.languageVersion, null); + }); - test("dot-dot 1", () { - var packages = doParse(singleRelativeSample, base); - expect(packages.packages.toList(), equals(["foo"])); - expect(packages.resolve(Uri.parse("package:foo/qux/../bar/baz.dart")), - equals(base.resolve("../test/").resolve("bar/baz.dart"))); - }); + test("valid empty", () { + var packagesFile = "# Generated by pub yadda yadda\n"; + var result = + packages.parse(utf8.encode(packagesFile), Uri.file("/tmp/file.dart")); + expect(result.version, 1); + expect({for (var p in result.packages) p.name}, {}); + }); - test("all valid chars can be used in URI segment", () { - var packages = doParse(allValidCharsSample, base); - expect(packages.packages.toList(), equals([allValidChars])); - expect(packages.resolve(Uri.parse("package:$allValidChars/bar/baz.dart")), - equals(base.resolve("../test/").resolve("bar/baz.dart"))); - }); + group("invalid", () { + var baseFile = Uri.file("/tmp/file.dart"); + testThrows(String name, String content) { + test(name, () { + expect(() => packages.parse(utf8.encode(content), baseFile), + throwsA(TypeMatcher())); + }); + } - test("no invalid chars accepted", () { - var map = {}; - for (int i = 0; i < allValidChars.length; i++) { - map[allValidChars.codeUnitAt(i)] = true; - } - for (int i = 0; i <= 255; i++) { - if (map[i] == true) continue; - var char = new String.fromCharCode(i); - expect(() => doParse("x${char}x:x", null), - anyOf(throwsNoSuchMethodError, throwsFormatException)); - } + testThrows("repeated package name", "foo:lib/\nfoo:lib\n"); + testThrows("no colon", "foo\n"); + testThrows("empty package name", ":lib/\n"); + testThrows("dot only package name", ".:lib/\n"); + testThrows("dot only package name", "..:lib/\n"); + testThrows("invalid package name character", "f\\o:lib/\n"); + testThrows("package URI", "foo:package:bar/lib/"); + testThrows("location with query", "f\\o:lib/?\n"); + testThrows("location with fragment", "f\\o:lib/#\n"); + }); }); - test("no escapes", () { - expect(() => doParse("x%41x:x", base), throwsFormatException); - }); + group("package_config.json", () { + test("valid", () { + var packageConfigFile = """ + { + "configVersion": 2, + "packages": [ + { + "name": "foo", + "rootUri": "file:///foo/", + "packageUri": "lib/", + "languageVersion": "2.5", + "nonstandard": true + }, + { + "name": "bar", + "rootUri": "/bar/", + "packageUri": "lib/", + "languageVersion": "100.100" + }, + { + "name": "baz", + "rootUri": "../", + "packageUri": "lib/" + } + ], + "generator": "pub", + "other": [42] + } + """; + var config = parsePackageConfigBytes(utf8.encode(packageConfigFile), + Uri.parse("file:///tmp/.dart_tool/file.dart")); + expect(config.version, 2); + expect({for (var p in config.packages) p.name}, {"foo", "bar", "baz"}); - test("same name twice", () { - expect( - () => doParse(singleRelativeSample * 2, base), throwsFormatException); - }); + expect(config.resolve(pkg("foo", "foo.dart")), + Uri.parse("file:///foo/lib/foo.dart")); + expect(config.resolve(pkg("bar", "bar.dart")), + Uri.parse("file:///bar/lib/bar.dart")); + expect(config.resolve(pkg("baz", "baz.dart")), + Uri.parse("file:///tmp/lib/baz.dart")); - test("disallow default package", () { - expect(() => doParse(":foo", base, allowDefaultPackage: false), - throwsFormatException); - }); + var foo = config["foo"]; + expect(foo, isNotNull); + expect(foo.root, Uri.parse("file:///foo/")); + expect(foo.packageUriRoot, Uri.parse("file:///foo/lib/")); + expect(foo.languageVersion, "2.5"); + expect(foo.extraData, {"nonstandard": true}); - test("allow default package", () { - var packages = doParse(":foo", base, allowDefaultPackage: true); - expect(packages.defaultPackageName, "foo"); - }); + var bar = config["bar"]; + expect(bar, isNotNull); + expect(bar.root, Uri.parse("file:///bar/")); + expect(bar.packageUriRoot, Uri.parse("file:///bar/lib/")); + expect(bar.languageVersion, "100.100"); + expect(bar.extraData, null); - test("allow default package name with dot", () { - var packages = doParse(":foo.bar", base, allowDefaultPackage: true); - expect(packages.defaultPackageName, "foo.bar"); - }); + var baz = config["baz"]; + expect(baz, isNotNull); + expect(baz.root, Uri.parse("file:///tmp/")); + expect(baz.packageUriRoot, Uri.parse("file:///tmp/lib/")); + expect(baz.languageVersion, null); - test("not two default packages", () { - expect(() => doParse(":foo\n:bar", base, allowDefaultPackage: true), - throwsFormatException); - }); + expect(config.extraData, { + "generator": "pub", + "other": [42] + }); + }); - test("default package invalid package name", () { - // Not a valid *package name*. - expect(() => doParse(":foo/bar", base, allowDefaultPackage: true), - throwsFormatException); - }); + test("valid other order", () { + // The ordering in the file is not important. + var packageConfigFile = """ + { + "generator": "pub", + "other": [42], + "packages": [ + { + "languageVersion": "2.5", + "packageUri": "lib/", + "rootUri": "file:///foo/", + "name": "foo" + }, + { + "packageUri": "lib/", + "languageVersion": "100.100", + "rootUri": "/bar/", + "name": "bar" + }, + { + "packageUri": "lib/", + "name": "baz", + "rootUri": "../" + } + ], + "configVersion": 2 + } + """; + var config = parsePackageConfigBytes(utf8.encode(packageConfigFile), + Uri.parse("file:///tmp/.dart_tool/file.dart")); + expect(config.version, 2); + expect({for (var p in config.packages) p.name}, {"foo", "bar", "baz"}); - group("metadata", () { - var packages = doParse( - ":foo\n" - "foo:foo#metafoo=1\n" - "bar:bar#metabar=2\n" - "baz:baz\n" - "qux:qux#metaqux1=3&metaqux2=4\n", - base, - allowDefaultPackage: true); - test("non-existing", () { - // non-package name. - expect(packages.packageMetadata("///", "f"), null); - expect(packages.packageMetadata("", "f"), null); - // unconfigured package name. - expect(packages.packageMetadata("absent", "f"), null); - // package name without that metadata - expect(packages.packageMetadata("foo", "notfoo"), null); - }); - test("lookup", () { - expect(packages.packageMetadata("foo", "metafoo"), "1"); - expect(packages.packageMetadata("bar", "metabar"), "2"); - expect(packages.packageMetadata("qux", "metaqux1"), "3"); - expect(packages.packageMetadata("qux", "metaqux2"), "4"); + expect(config.resolve(pkg("foo", "foo.dart")), + Uri.parse("file:///foo/lib/foo.dart")); + expect(config.resolve(pkg("bar", "bar.dart")), + Uri.parse("file:///bar/lib/bar.dart")); + expect(config.resolve(pkg("baz", "baz.dart")), + Uri.parse("file:///tmp/lib/baz.dart")); + expect(config.extraData, { + "generator": "pub", + "other": [42] + }); }); - test("by library URI", () { - expect( - packages.libraryMetadata( - Uri.parse("package:foo/index.dart"), "metafoo"), - "1"); - expect( - packages.libraryMetadata( - Uri.parse("package:bar/index.dart"), "metabar"), - "2"); - expect( - packages.libraryMetadata( - Uri.parse("package:qux/index.dart"), "metaqux1"), - "3"); - expect( - packages.libraryMetadata( - Uri.parse("package:qux/index.dart"), "metaqux2"), - "4"); + + // Check that a few minimal configurations are valid. + // These form the basis of invalid tests below. + var cfg = '"configVersion":2'; + var pkgs = '"packages":[]'; + var name = '"name":"foo"'; + var root = '"rootUri":"/foo/"'; + test("minimal", () { + var config = parsePackageConfigBytes(utf8.encode("{$cfg,$pkgs}"), + Uri.parse("file:///tmp/.dart_tool/file.dart")); + expect(config.version, 2); + expect(config.packages, isEmpty); }); - test("by default package", () { - expect( - packages.libraryMetadata( - Uri.parse("file:///whatever.dart"), "metafoo"), - "1"); + test("minimal package", () { + // A package must have a name and a rootUri, the remaining properties + // are optional. + var config = parsePackageConfigBytes( + utf8.encode('{$cfg,"packages":[{$name,$root}]}'), + Uri.parse("file:///tmp/.dart_tool/file.dart")); + expect(config.version, 2); + expect(config.packages.first.name, "foo"); }); - }); - for (String invalidSample in invalid) { - test("invalid '$invalidSample'", () { - var result; - try { - result = doParse(invalidSample, base); - } on FormatException { - // expected - return; + group("invalid", () { + testThrows(String name, String source) { + test(name, () { + expect( + () => parsePackageConfigBytes(utf8.encode(source), + Uri.parse("file:///tmp/.dart_tool/file.dart")), + throwsA(TypeMatcher())); + }); } - fail("Resolved to $result"); - }); - } -} -Packages doParse(String sample, Uri baseUri, - {bool allowDefaultPackage = false}) { - Map map = parse(sample.codeUnits, baseUri, - allowDefaultPackage: allowDefaultPackage); - return new MapPackages(map); -} + testThrows("comment", '# comment\n {$cfg,$pkgs}'); + testThrows(".packages file", 'foo:/foo\n'); + testThrows("no configVersion", '{$pkgs}'); + testThrows("no packages", '{$cfg}'); + group("config version:", () { + testThrows("null", '{"configVersion":null,$pkgs}'); + testThrows("string", '{"configVersion":"2",$pkgs}'); + testThrows("array", '{"configVersion":[2],$pkgs}'); + }); + group("packages:", () { + testThrows("null", '{$cfg,"packages":null}'); + testThrows("string", '{$cfg,"packages":"foo"}'); + testThrows("object", '{$cfg,"packages":{}}'); + }); + group("packages entry:", () { + testThrows("null", '{$cfg,"packages":[null]}'); + testThrows("string", '{$cfg,"packages":["foo"]}'); + testThrows("array", '{$cfg,"packages":[[]]}'); + }); + group("package", () { + testThrows("no name", '{$cfg,"packages":[{$root}]}'); + group("name:", () { + testThrows("null", '{$cfg,"packages":[{"name":null,$root}]}'); + testThrows("num", '{$cfg,"packages":[{"name":1,$root}]}'); + testThrows("object", '{$cfg,"packages":[{"name":{},$root}]}'); + testThrows("empty", '{$cfg,"packages":[{"name":"",$root}]}'); + testThrows("one-dot", '{$cfg,"packages":[{"name":".",$root}]}'); + testThrows("two-dot", '{$cfg,"packages":[{"name":"..",$root}]}'); + testThrows( + "invalid char '\\'", '{$cfg,"packages":[{"name":"\\",$root}]}'); + testThrows( + "invalid char ':'", '{$cfg,"packages":[{"name":":",$root}]}'); + testThrows( + "invalid char ' '", '{$cfg,"packages":[{"name":" ",$root}]}'); + }); -// Valid samples. -var emptySample = ""; -var commentOnlySample = "# comment only\n"; -var emptyLinesSample = "\n\n\r\n"; -var singleRelativeSample = "foo:../test/\n"; -var singleRelativeSampleNoSlash = "foo:../test\n"; -var singleRelativeSampleNoNewline = "foo:../test/"; -var singleAbsoluteSample = "foo:http://example.com/some/where/\n"; -var singleEmptyPathSample = "foo:\n"; -var singleAbsolutePathSample = "foo:/test/\n"; -var multiRelativeSample = "foo:../test/\nbar:../test2/\n"; -// All valid path segment characters in an URI. -var allValidChars = r"!$&'()*+,-.0123456789;=" - r"@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~"; - -var allValidCharsSample = "${allValidChars}:../test/\n"; - -// Invalid samples. -var invalid = [ - ":baz.dart", // empty. - "foobar=baz.dart", // no colon (but an equals, which is not the same) - ".:../test/", // dot segment - "..:../test/", // dot-dot segment - "...:../test/", // dot-dot-dot segment - "foo/bar:../test/", // slash in name - "/foo:../test/", // slash at start of name - "?:../test/", // invalid characters. - "[:../test/", // invalid characters. - "x#:../test/", // invalid characters. -]; + testThrows("no root", '{$cfg,"packages":[{$name}]}'); + group("root:", () { + testThrows("null", '{$cfg,"packages":[{$name,"rootUri":null}]}'); + testThrows("num", '{$cfg,"packages":[{$name,"rootUri":1}]}'); + testThrows("object", '{$cfg,"packages":[{$name,"rootUri":{}}]}'); + testThrows("fragment", '{$cfg,"packages":[{$name,"rootUri":"x/#"}]}'); + testThrows("query", '{$cfg,"packages":[{$name,"rootUri":"x/?"}]}'); + testThrows("package-URI", + '{$cfg,"packages":[{$name,"rootUri":"package:x/x/"}]}'); + }); + group("package-URI root:", () { + testThrows( + "null", '{$cfg,"packages":[{$name,$root,"packageUri":null}]}'); + testThrows("num", '{$cfg,"packages":[{$name,$root,"packageUri":1}]}'); + testThrows( + "object", '{$cfg,"packages":[{$name,$root,"packageUri":{}}]}'); + testThrows("fragment", + '{$cfg,"packages":[{$name,$root,"packageUri":"x/#"}]}'); + testThrows( + "query", '{$cfg,"packages":[{$name,$root,"packageUri":"x/?"}]}'); + testThrows("package: URI", + '{$cfg,"packages":[{$name,$root,"packageUri":"package:x/x/"}]}'); + testThrows("not inside root", + '{$cfg,"packages":[{$name,$root,"packageUri":"../other/"}]}'); + }); + group("language version", () { + testThrows("null", + '{$cfg,"packages":[{$name,$root,"languageVersion":null}]}'); + testThrows( + "num", '{$cfg,"packages":[{$name,$root,"languageVersion":1}]}'); + testThrows("object", + '{$cfg,"packages":[{$name,$root,"languageVersion":{}}]}'); + testThrows("empty", + '{$cfg,"packages":[{$name,$root,"languageVersion":""}]}'); + testThrows("non number.number", + '{$cfg,"packages":[{$name,$root,"languageVersion":"x.1"}]}'); + testThrows("number.non number", + '{$cfg,"packages":[{$name,$root,"languageVersion":"1.x"}]}'); + testThrows("non number", + '{$cfg,"packages":[{$name,$root,"languageVersion":"x"}]}'); + testThrows("one number", + '{$cfg,"packages":[{$name,$root,"languageVersion":"1"}]}'); + testThrows("three numbers", + '{$cfg,"packages":[{$name,$root,"languageVersion":"1.2.3"}]}'); + testThrows("leading zero first", + '{$cfg,"packages":[{$name,$root,"languageVersion":"01.1"}]}'); + testThrows("leading zero second", + '{$cfg,"packages":[{$name,$root,"languageVersion":"1.01"}]}'); + testThrows("trailing-", + '{$cfg,"packages":[{$name,$root,"languageVersion":"1.1-1"}]}'); + testThrows("trailing+", + '{$cfg,"packages":[{$name,$root,"languageVersion":"1.1+1"}]}'); + }); + }); + testThrows("duplicate package name", + '{$cfg,"packages":[{$name,$root},{$name,"rootUri":"/other/"}]}'); + testThrows("same roots", + '{$cfg,"packages":[{$name,$root},{"name":"bar",$root}]}'); + testThrows( + "overlapping roots", + '{$cfg,"packages":[{$name,$root},' + '{"name":"bar","rootUri":"/foo/sub/"}]}'); + }); + }); +} diff --git a/pkgs/package_config/test/parse_write_test.dart b/pkgs/package_config/test/parse_write_test.dart deleted file mode 100644 index 415b479e9..000000000 --- a/pkgs/package_config/test/parse_write_test.dart +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (c) 2015, 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. - -library package_config.parse_write_test; - -import "dart:convert" show utf8; -import "package:package_config/packages_file.dart"; -import "package:test/test.dart"; - -main() { - testBase(baseDirString) { - var baseDir = Uri.parse(baseDirString); - group("${baseDir.scheme} base", () { - Uri packagesFile = baseDir.resolve(".packages"); - - roundTripTest(String name, Map map) { - group(name, () { - test("write with no baseUri", () { - var content = writeToString(map).codeUnits; - var resultMap = parse(content, packagesFile); - expect(resultMap, map); - }); - - test("write with base directory", () { - var content = writeToString(map, baseUri: baseDir).codeUnits; - var resultMap = parse(content, packagesFile); - expect(resultMap, map); - }); - - test("write with base .packages file", () { - var content = writeToString(map, baseUri: packagesFile).codeUnits; - var resultMap = parse(content, packagesFile); - expect(resultMap, map); - }); - - test("write with defaultPackageName", () { - var content = writeToString( - {'': Uri.parse('my_pkg')}..addAll(map), - allowDefaultPackage: true, - ).codeUnits; - var resultMap = parse( - content, - packagesFile, - allowDefaultPackage: true, - ); - expect(resultMap[''].toString(), 'my_pkg'); - expect( - resultMap, - {'': Uri.parse('my_pkg')}..addAll(map), - ); - }); - - test("write with defaultPackageName (utf8)", () { - var content = utf8.encode(writeToString( - {'': Uri.parse('my_pkg')}..addAll(map), - allowDefaultPackage: true, - )); - var resultMap = parse( - content, - packagesFile, - allowDefaultPackage: true, - ); - expect(resultMap[''].toString(), 'my_pkg'); - expect( - resultMap, - {'': Uri.parse('my_pkg')}..addAll(map), - ); - }); - }); - } - - var lowerDir = baseDir.resolve("path3/path4/"); - var higherDir = baseDir.resolve("../"); - var parallelDir = baseDir.resolve("../path3/"); - var rootDir = baseDir.resolve("/"); - var fileDir = Uri.parse("file:///path1/part2/"); - var httpDir = Uri.parse("http://example.com/path1/path2/"); - var otherDir = Uri.parse("other:/path1/path2/"); - - roundTripTest("empty", {}); - roundTripTest("lower directory", {"foo": lowerDir}); - roundTripTest("higher directory", {"foo": higherDir}); - roundTripTest("parallel directory", {"foo": parallelDir}); - roundTripTest("same directory", {"foo": baseDir}); - roundTripTest("root directory", {"foo": rootDir}); - roundTripTest("file directory", {"foo": fileDir}); - roundTripTest("http directory", {"foo": httpDir}); - roundTripTest("other scheme directory", {"foo": otherDir}); - roundTripTest("multiple same-type directories", - {"foo": lowerDir, "bar": higherDir, "baz": parallelDir}); - roundTripTest("multiple scheme directories", - {"foo": fileDir, "bar": httpDir, "baz": otherDir}); - roundTripTest("multiple scheme directories and mutliple same type", { - "foo": fileDir, - "bar": httpDir, - "baz": otherDir, - "qux": lowerDir, - "hip": higherDir, - "dep": parallelDir - }); - }); - } - - testBase("file:///base1/base2/"); - testBase("http://example.com/base1/base2/"); - testBase("other:/base1/base2/"); - - // Check that writing adds the comment. - test("write preserves comment", () { - var comment = "comment line 1\ncomment line 2\ncomment line 3"; - var result = writeToString({}, comment: comment); - // Comment with "# " before each line and "\n" after last. - var expectedComment = - "# comment line 1\n# comment line 2\n# comment line 3\n"; - expect(result, startsWith(expectedComment)); - }); -} - -String writeToString( - Map map, { - Uri baseUri, - String comment, - bool allowDefaultPackage = false, -}) { - var buffer = new StringBuffer(); - write(buffer, map, - baseUri: baseUri, - comment: comment, - allowDefaultPackage: allowDefaultPackage); - return buffer.toString(); -} diff --git a/pkgs/package_config/test/src/util.dart b/pkgs/package_config/test/src/util.dart new file mode 100644 index 000000000..ec4e5e8bc --- /dev/null +++ b/pkgs/package_config/test/src/util.dart @@ -0,0 +1,109 @@ +// Copyright (c) 2019, 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. + +import 'dart:convert'; +import "dart:io"; +import 'dart:typed_data'; + +import "package:path/path.dart" as path; +import "package:test/test.dart"; + +/// Creates a directory structure from [description] and runs [fileTest]. +/// +/// Description is a map, each key is a file entry. If the value is a map, +/// it's a subdirectory, otherwise it's a file and the value is the content +/// as a string. +/// Introduces a group to hold the [setUp]/[tearDown] logic. +void fileTest(String name, Map description, + void fileTest(Directory directory)) { + group("file-test", () { + Directory tempDir = Directory.systemTemp.createTempSync("pkgcfgtest"); + setUp(() { + _createFiles(tempDir, description); + }); + tearDown(() { + tempDir.deleteSync(recursive: true); + }); + test(name, () => fileTest(tempDir)); + }); +} + +/// Creates a set of files under a new temporary directory. +/// Returns the temporary directory. +/// +/// The [description] is a map from file names to content. +/// If the content is again a map, it represents a subdirectory +/// with the content as description. +/// Otherwise the content should be a string, +/// which is written to the file as UTF-8. +Directory createTestFiles(Map description) { + var target = Directory.systemTemp.createTempSync("pkgcfgtest"); + _createFiles(target, description); + return target; +} + +// Creates temporary files in the target directory. +void _createFiles(Directory target, Map description) { + description.forEach((name, content) { + var entryName = path.join(target.path, "$name"); + if (content is Map) { + _createFiles(Directory(entryName)..createSync(), content); + } else { + File(entryName).writeAsStringSync(content, flush: true); + } + }); +} + +/// Creates a [Directory] for a subdirectory of [parent]. +Directory subdir(Directory parent, String dirName) => + Directory(path.joinAll([parent.path, ...dirName.split("/")])); + +/// Creates a [File] for an entry in the [directory] directory. +File dirFile(Directory directory, String fileName) => + File(path.join(directory.path, fileName)); + +/// Creates a package: URI. +Uri pkg(String packageName, String packagePath) { + var path = + "$packageName${packagePath.startsWith('/') ? "" : "/"}$packagePath"; + return new Uri(scheme: "package", path: path); +} + +// Remove if not used. +String configFromPackages(List> packages) => """ +{ + "configVersion": 2, + "packages": [ +${packages.map((nu) => """ + { + "name": "${nu[0]}", + "rootUri": "${nu[1]}" + }""").join(",\n")} + ] +} +"""; + +/// Mimics a directory structure of [description] and runs [fileTest]. +/// +/// Description is a map, each key is a file entry. If the value is a map, +/// it's a subdirectory, otherwise it's a file and the value is the content +/// as a string. +void loaderTest(String name, Map description, + void loaderTest(Uri root, Future loader(Uri uri))) { + Uri root = Uri(scheme: "test", path: "/"); + Future loader(Uri uri) async { + var path = uri.path; + if (!uri.isScheme("test") || !path.startsWith("/")) return null; + var parts = path.split("/"); + dynamic value = description; + for (int i = 1; i < parts.length; i++) { + if (value is! Map) return null; + value = value[parts[i]]; + } + if (value is String) return utf8.encode(value); + return null; + } + + test(name, () => loaderTest(root, loader)); +} From 7620e6b877ec39ebc0afb7ad1d3d9dea4ab635c5 Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Mon, 27 Jan 2020 12:50:59 +0100 Subject: [PATCH 079/170] Further tweaks on the API. (dart-lang/package_config#57) * Allow nested packages. --- pkgs/package_config/lib/package_config.dart | 38 +-- pkgs/package_config/lib/src/discovery.dart | 16 +- .../lib/src/package_config_impl.dart | 251 ++++++++++++++---- .../lib/src/package_config_json.dart | 56 ++-- pkgs/package_config/pubspec.yaml | 2 +- pkgs/package_config/test/discovery_test.dart | 7 + .../test/discovery_uri_test.dart | 1 - pkgs/package_config/test/parse_test.dart | 47 +++- 8 files changed, 309 insertions(+), 109 deletions(-) diff --git a/pkgs/package_config/lib/package_config.dart b/pkgs/package_config/lib/package_config.dart index 4d6f346d7..77e8d61bf 100644 --- a/pkgs/package_config/lib/package_config.dart +++ b/pkgs/package_config/lib/package_config.dart @@ -23,10 +23,16 @@ export "src/errors.dart" show PackageConfigError; /// It is considered a `package_config.json` file if its first character /// is a `{`. /// -/// If the file is a `.packages` file, also checks if there is a -/// `.dart_tool/package_config.json` file next to the original file, +/// If the file is a `.packages` file and [preferNewest] is true, the default, +/// also checks if there is a `.dart_tool/package_config.json` file next to the original file, /// and if so, loads that instead. -Future loadPackageConfig(File file) => readAnyConfigFile(file); +/// If [preferNewest] is set to false, a directly specified `.packages` file +/// is loaded even if there is an available `package_config.json` file. +/// The caller can determine this from the [PackageConfig.version] +/// being 1 and look for a `package_config.json` file themselves. +Future loadPackageConfig(File file, + {bool preferNewest = true}) => + readAnyConfigFile(file, preferNewest); /// Reads a specific package configuration URI. /// @@ -36,19 +42,24 @@ Future loadPackageConfig(File file) => readAnyConfigFile(file); /// It is considered a `package_config.json` file if its first /// non-whitespace character is a `{`. /// -/// If the file is a `.packages` file, first checks if there is a -/// `.dart_tool/package_config.json` file next to the original file, -/// and if so, loads that instead. +/// If [preferNewest] is true, the default, and the file is a `.packages` file, +/// first checks if there is a `.dart_tool/package_config.json` file +/// next to the original file, and if so, loads that instead. /// The [file] *must not* be a `package:` URI. +/// If [preferNewest] is set to false, a directly specified `.packages` file +/// is loaded even if there is an available `package_config.json` file. +/// The caller can determine this from the [PackageConfig.version] +/// being 1 and look for a `package_config.json` file themselves. /// /// If [loader] is provided, URIs are loaded using that function. /// The future returned by the loader must complete with a [Uint8List] -/// containing the entire file content, +/// containing the entire file content encoded as UTF-8, /// or with `null` if the file does not exist. /// The loader may throw at its own discretion, for situations where /// it determines that an error might be need user attention, /// but it is always allowed to return `null`. /// This function makes no attempt to catch such errors. +/// As such, it may throw any error that [loader] throws. /// /// If no [loader] is supplied, a default loader is used which /// only accepts `file:`, `http:` and `https:` URIs, @@ -58,8 +69,9 @@ Future loadPackageConfig(File file) => readAnyConfigFile(file); /// As such, it does not distinguish between a file not existing, /// and it being temporarily locked or unreachable. Future loadPackageConfigUri(Uri file, - {Future loader(Uri uri) /*?*/}) => - readAnyConfigFileUri(file, loader); + {Future loader(Uri uri) /*?*/, + bool preferNewest = true}) => + readAnyConfigFileUri(file, loader, preferNewest); /// Finds a package configuration relative to [directory]. /// @@ -123,14 +135,6 @@ Future findPackageConfigUri(Uri location, /// If the `.dart_tool/` directory does not exist, it is created. /// If it cannot be created, this operation fails. /// -/// If [extraData] contains any entries, they are added to the JSON -/// written to the `package_config.json` file. Entries with the names -/// `"configVersion"` or `"packages"` are ignored, all other entries -/// are added verbatim. -/// This is intended for, e.g., the -/// `"generator"`, `"generated"` and `"generatorVersion"` -/// properties. -/// /// Also writes a `.packages` file in [directory]. /// This will stop happening eventually as the `.packages` file becomes /// discontinued. diff --git a/pkgs/package_config/lib/src/discovery.dart b/pkgs/package_config/lib/src/discovery.dart index 6b0fc8f0d..5ad6ac54e 100644 --- a/pkgs/package_config/lib/src/discovery.dart +++ b/pkgs/package_config/lib/src/discovery.dart @@ -5,7 +5,7 @@ import "dart:io"; import 'dart:typed_data'; -import "package:path/path.dart" as path; +import "package:path/path.dart" as p; import "errors.dart"; import "package_config_impl.dart"; @@ -110,23 +110,13 @@ Future findPackagConfigInDirectory( Future /*?*/ checkForPackageConfigJsonFile(Directory directory) async { assert(directory.isAbsolute); - var file = - File(path.join(directory.path, ".dart_tool", "package_config.json")); + var file = File(p.join(directory.path, ".dart_tool", "package_config.json")); if (await file.exists()) return file; return null; } Future checkForDotPackagesFile(Directory directory) async { - var file = File(path.join(directory.path, ".packages")); + var file = File(p.join(directory.path, ".packages")); if (await file.exists()) return file; return null; } - -Future _loadFile(File file) async { - Uint8List bytes; - try { - return await file.readAsBytes(); - } catch (_) { - return null; - } -} diff --git a/pkgs/package_config/lib/src/package_config_impl.dart b/pkgs/package_config/lib/src/package_config_impl.dart index 0bbe18f5b..62579610c 100644 --- a/pkgs/package_config/lib/src/package_config_impl.dart +++ b/pkgs/package_config/lib/src/package_config_impl.dart @@ -4,22 +4,26 @@ import 'errors.dart'; import "package_config.dart"; -export "package_config.dart"; import "util.dart"; +export "package_config.dart"; + class SimplePackageConfig implements PackageConfig { final int version; final Map _packages; + final PackageTree _packageTree; final dynamic extraData; - SimplePackageConfig(int version, Iterable packages, [this.extraData]) - : version = _validateVersion(version), - _packages = _validatePackages(packages); + SimplePackageConfig(int version, Iterable packages, + [dynamic extraData]) + : this._(_validateVersion(version), packages, + [...packages]..sort(_compareRoot), extraData); - SimplePackageConfig._( - int version, Iterable packages, this.extraData) - : version = _validateVersion(version), - _packages = {for (var package in packages) package.name: package}; + /// Expects a list of [packages] sorted on root path. + SimplePackageConfig._(this.version, Iterable originalPackages, + List packages, this.extraData) + : _packageTree = _validatePackages(originalPackages, packages), + _packages = {for (var p in packages) p.name: p}; /// Creates empty configuration. /// @@ -27,6 +31,7 @@ class SimplePackageConfig implements PackageConfig { /// found, but code expects a non-null configuration. const SimplePackageConfig.empty() : version = 1, + _packageTree = const EmptyPackageTree(), _packages = const {}, extraData = null; @@ -38,18 +43,28 @@ class SimplePackageConfig implements PackageConfig { return version; } - static Map _validatePackages(Iterable packages) { + static PackageTree _validatePackages( + Iterable originalPackages, List packages) { + // Assumes packages are sorted. Map result = {}; - for (var package in packages) { - if (package is! SimplePackage) { + var tree = MutablePackageTree(); + SimplePackage package; + for (var originalPackage in packages) { + if (originalPackage is! SimplePackage) { // SimplePackage validates these properties. try { - _validatePackageData(package.name, package.root, - package.packageUriRoot, package.languageVersion); + package = SimplePackage( + originalPackage.name, + originalPackage.root, + originalPackage.packageUriRoot, + originalPackage.languageVersion, + originalPackage.extraData); } catch (e) { throw PackageConfigArgumentError( packages, "packages", "Package ${package.name}: ${e.message}"); } + } else { + package = originalPackage; } var name = package.name; if (result.containsKey(name)) { @@ -57,33 +72,31 @@ class SimplePackageConfig implements PackageConfig { name, "packages", "Duplicate package name"); } result[name] = package; - } - - // Check that no root URI is a prefix of another. - if (result.length > 1) { - // Uris cache their toString, so this is not as bad as it looks. - var rootUris = [...result.values] - ..sort((a, b) => a.root.toString().compareTo(b.root.toString())); - var prev = rootUris[0]; - var prevRoot = prev.root.toString(); - for (int i = 1; i < rootUris.length; i++) { - var next = rootUris[i]; - var nextRoot = next.root.toString(); - // If one string is a prefix of another, - // the former sorts just before the latter. - if (nextRoot.startsWith(prevRoot)) { + try { + tree.add(0, package); + } on ConflictException catch (e) { + // There is a conflict with an existing package. + var existingPackage = e.existingPackage; + if (e.isRootConflict) { throw PackageConfigArgumentError( - packages, + originalPackages, "packages", - "Package ${next.name} root overlaps " - "package ${prev.name} root.\n" - "${prev.name} root: $prevRoot\n" - "${next.name} root: $nextRoot\n"); + "Packages ${package.name} and ${existingPackage.name}" + "have the same root directory: ${package.root}.\n"); } - prev = next; + assert(e.isPackageRootConflict); + // Or package is inside the package URI root of the existing package. + throw PackageConfigArgumentError( + originalPackages, + "packages", + "Package ${package.name} is inside the package URI root of " + "package ${existingPackage.name}.\n" + "${existingPackage.name} URI root: " + "${existingPackage.packageUriRoot}\n" + "${package.name} root: ${package.root}\n"); } } - return result; + return tree; } Iterable get packages => _packages.values; @@ -96,14 +109,7 @@ class SimplePackageConfig implements PackageConfig { /// That is, the [Package.rootUri] directory is a parent directory /// of the [file]'s location. /// Returns `null` if the file does not belong to any package. - Package /*?*/ packageOf(Uri file) { - String path = file.toString(); - for (var package in _packages.values) { - var rootPath = package.root.toString(); - if (path.startsWith(rootPath)) return package; - } - return null; - } + Package /*?*/ packageOf(Uri file) => _packageTree.packageOf(file); Uri /*?*/ resolve(Uri packageUri) { String packageName = checkValidPackageUri(packageUri, "packageUri"); @@ -120,12 +126,15 @@ class SimplePackageConfig implements PackageConfig { throw PackageConfigArgumentError(nonPackageUri, "nonPackageUri", "Must not have query or fragment part"); } - for (var package in _packages.values) { - var root = package.packageUriRoot; - if (isUriPrefix(root, nonPackageUri)) { - var rest = nonPackageUri.toString().substring(root.toString().length); - return Uri(scheme: "package", path: "${package.name}/$rest"); - } + // Find package that file belongs to. + var package = _packageTree.packageOf(nonPackageUri); + if (package == null) return null; + // Check if it is inside the package URI root. + var path = nonPackageUri.toString(); + var root = package.packageUriRoot.toString(); + if (_beginsWith(package.root.toString().length, root, path)) { + var rest = path.substring(root.length); + return Uri(scheme: "package", path: "${package.name}/$rest"); } return null; } @@ -142,6 +151,9 @@ class SimplePackage implements Package { SimplePackage._(this.name, this.root, this.packageUriRoot, this.languageVersion, this.extraData); + /// Creates a [SimplePackage] with the provided content. + /// + /// The provided arguments must be valid. factory SimplePackage(String name, Uri root, Uri packageUriRoot, String /*?*/ languageVersion, dynamic extraData) { _validatePackageData(name, root, packageUriRoot, languageVersion); @@ -179,3 +191,144 @@ void _validatePackageData( languageVersion, "languageVersion", "Invalid language version format"); } } + +abstract class PackageTree { + SimplePackage /*?*/ packageOf(Uri file); +} + +/// Packages of a package configuration ordered by root path. +/// +/// A package is said to be inside another package if the root path URI of +/// the latter is a prefix of the root path URI of the former. +/// No two packages of a package may have the same root path, so this +/// path prefix ordering defines a tree-like partial ordering on packages +/// of a configuration. +/// +/// The package tree contains an ordered mapping of unrelated packages +/// (represented by their name) to their immediately nested packages' names. +class MutablePackageTree implements PackageTree { + final List packages = []; + Map /*?*/ _packageChildren; + + /// Tries to (add) `package` to the tree. + /// + /// Throws [ConflictException] if the added package conflicts with an + /// existing package. + /// It conflicts if it has the same root path, or if the new package + /// contains the existing package's package root. + void add(int start, SimplePackage package) { + var path = package.root.toString(); + for (var childPackage in packages) { + var childPath = childPackage.root.toString(); + assert(childPath.length > start); + assert(path.startsWith(childPath.substring(0, start))); + if (_beginsWith(start, childPath, path)) { + var childPathLength = childPath.length; + if (path.length == childPathLength) { + throw ConflictException.root(package, childPackage); + } + var childPackageRoot = childPackage.packageUriRoot.toString(); + if (_beginsWith(childPathLength, childPackageRoot, path)) { + throw ConflictException.packageRoot(package, childPackage); + } + _treeOf(childPackage).add(childPathLength, package); + return; + } + } + packages.add(package); + } + + SimplePackage /*?*/ packageOf(Uri file) { + return findPackageOf(0, file.toString()); + } + + /// Finds package containing [path] in this tree. + /// + /// Returns `null` if no such package is found. + /// + /// Assumes the first [start] characters of path agrees with all + /// the packages at this level of the tree. + SimplePackage /*?*/ findPackageOf(int start, String path) { + for (var childPackage in packages) { + var childPath = childPackage.root.toString(); + if (_beginsWith(start, childPath, path)) { + // The [package] is inside [childPackage]. + var childPathLength = childPath.length; + if (path.length == childPathLength) return childPackage; + var uriRoot = childPackage.packageUriRoot.toString(); + // Is [package] is inside the URI root of [childPackage]. + if (uriRoot.length == childPathLength || + _beginsWith(childPathLength, uriRoot, path)) { + return childPackage; + } + // Otherwise add [package] as child of [childPackage]. + // TODO(lrn): When NNBD comes, convert to: + // return _packageChildren?[childPackage.name] + // ?.packageOf(childPathLength, path) ?? childPackage; + if (_packageChildren == null) return childPackage; + var childTree = _packageChildren[childPackage.name]; + if (childTree == null) return childPackage; + return childTree.findPackageOf(childPathLength, path) ?? childPackage; + } + } + return null; + } + + /// Returns the [PackageTree] of the children of [package]. + /// + /// Ensures that the object is allocated if necessary. + MutablePackageTree _treeOf(SimplePackage package) { + var children = _packageChildren ??= {}; + return children[package.name] ??= MutablePackageTree(); + } +} + +class EmptyPackageTree implements PackageTree { + const EmptyPackageTree(); + + SimplePackage packageOf(Uri file) => null; +} + +/// Checks whether [longerPath] begins with [parentPath]. +/// +/// Skips checking the [start] first characters which are assumed to +/// already have been matched. +bool _beginsWith(int start, String parentPath, String longerPath) { + if (longerPath.length < parentPath.length) return false; + for (int i = start; i < parentPath.length; i++) { + if (longerPath.codeUnitAt(i) != parentPath.codeUnitAt(i)) return false; + } + return true; +} + +/// Conflict between packages added to the same configuration. +/// +/// The [package] conflicts with [existingPackage] if it has +/// the same root path ([isRootConflict]) or the package URI root path +/// of [existingPackage] is inside the root path of [package] +/// ([isPackageRootConflict]). +class ConflictException { + /// The existing package that [package] conflicts with. + final SimplePackage existingPackage; + + /// The package that could not be added without a conflict. + final SimplePackage package; + + /// Whether the conflict is with the package URI root of [existingPackage]. + final bool isPackageRootConflict; + + /// Creates a root conflict between [package] and [existingPackage]. + ConflictException.root(this.package, this.existingPackage) + : isPackageRootConflict = false; + + /// Creates a package root conflict between [package] and [existingPackage]. + ConflictException.packageRoot(this.package, this.existingPackage) + : isPackageRootConflict = true; + + /// WHether the conflict is with the root URI of [existingPackage]. + bool get isRootConflict => !isPackageRootConflict; +} + +/// Used for sorting packages by root path. +int _compareRoot(Package p1, Package p2) => + p1.root.toString().compareTo(p2.root.toString()); diff --git a/pkgs/package_config/lib/src/package_config_json.dart b/pkgs/package_config/lib/src/package_config_json.dart index 8a6014cad..8108102bd 100644 --- a/pkgs/package_config/lib/src/package_config_json.dart +++ b/pkgs/package_config/lib/src/package_config_json.dart @@ -7,7 +7,7 @@ import "dart:io"; import "dart:typed_data"; import 'package:charcode/ascii.dart'; -import "package:path/path.dart" as path; +import "package:path/path.dart" as p; import "discovery.dart" show packageConfigJsonPath; import "errors.dart"; @@ -38,36 +38,42 @@ const String _generatorVersionKey = "generatorVersion"; /// Detects whether the [file] is a version one `.packages` file or /// a version two `package_config.json` file. /// -/// If the [file] is a `.packages` file, first checks whether there is an -/// adjacent `.dart_tool/package_config.json` file, and if so, -/// reads that instead. +/// If the [file] is a `.packages` file and [preferNewest] is true, +/// first checks whether there is an adjacent `.dart_tool/package_config.json` +/// file, and if so, reads that instead. +/// If [preferNewset] is false, the specified file is loaded even if it is +/// a `.packages` file and there is an available `package_config.json` file. /// /// The file must exist and be a normal file. -Future readAnyConfigFile(File file) async { +Future readAnyConfigFile(File file, bool preferNewest) async { var bytes = await file.readAsBytes(); int firstChar = firstNonWhitespaceChar(bytes); if (firstChar != $lbrace) { // Definitely not a JSON object, probably a .packages. - var alternateFile = File(path.join( - path.dirname(file.path), ".dart_tool", "package_config.json")); - if (!alternateFile.existsSync()) { - return packages_file.parse(bytes, file.uri); + if (preferNewest) { + var alternateFile = File( + p.join(p.dirname(file.path), ".dart_tool", "package_config.json")); + if (alternateFile.existsSync()) { + return parsePackageConfigBytes( + await alternateFile.readAsBytes(), alternateFile.uri); + } } - file = alternateFile; - bytes = await alternateFile.readAsBytes(); + return packages_file.parse(bytes, file.uri); } return parsePackageConfigBytes(bytes, file.uri); } /// Like [readAnyConfigFile] but uses a URI and an optional loader. -Future readAnyConfigFileUri( - Uri file, Future loader(Uri uri) /*?*/) async { +Future readAnyConfigFileUri(Uri file, + Future loader(Uri uri) /*?*/, bool preferNewest) async { if (file.isScheme("package")) { throw PackageConfigArgumentError( file, "file", "Must not be a package: URI"); } if (loader == null) { - if (file.isScheme("file")) return readAnyConfigFile(File.fromUri(file)); + if (file.isScheme("file")) { + return readAnyConfigFile(File.fromUri(file), preferNewest); + } loader = defaultLoader; } var bytes = await loader(file); @@ -78,13 +84,15 @@ Future readAnyConfigFileUri( int firstChar = firstNonWhitespaceChar(bytes); if (firstChar != $lbrace) { // Definitely not a JSON object, probably a .packages. - var alternateFile = file.resolveUri(packageConfigJsonPath); - var alternateBytes = await loader(alternateFile); - if (alternateBytes == null) { - return packages_file.parse(bytes, file); + if (preferNewest) { + // Check if there is a package_config.json file. + var alternateFile = file.resolveUri(packageConfigJsonPath); + var alternateBytes = await loader(alternateFile); + if (alternateBytes != null) { + return parsePackageConfigBytes(alternateBytes, alternateFile); + } } - bytes = alternateBytes; - file = alternateFile; + return packages_file.parse(bytes, file); } return parsePackageConfigBytes(bytes, file); } @@ -242,8 +250,8 @@ PackageConfig parsePackageConfigJson(dynamic json, Uri baseLocation) { Future writePackageConfigJson( PackageConfig config, Directory targetDirectory) async { // Write .dart_tool/package_config.json first. - var file = File( - path.join(targetDirectory.path, ".dart_tool", "package_config.json")); + var file = + File(p.join(targetDirectory.path, ".dart_tool", "package_config.json")); var baseUri = file.uri; var extraData = config.extraData; var data = { @@ -275,7 +283,7 @@ Future writePackageConfigJson( "${generated != null ? " on $generated" : ""}."; } } - file = File(path.join(targetDirectory.path, ".packages")); + file = File(p.join(targetDirectory.path, ".packages")); baseUri = file.uri; var buffer = StringBuffer(); packages_file.write(buffer, config, baseUri: baseUri, comment: comment); @@ -313,7 +321,7 @@ Map /*?*/ _extractExtraData( /// Checks that the object is a valid JSON-like data structure. bool _validateJson(dynamic object) { - if (object == null || object == true || object == false) return true; + if (object == null || true == object || false == object) return true; if (object is num || object is String) return true; if (object is List) { for (var element in object) if (!_validateJson(element)) return false; diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 0cd7ddc52..781dc32a8 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -5,7 +5,7 @@ author: Dart Team homepage: https://github.com/dart-lang/package_config environment: - sdk: '>=2.5.0-dev <3.0.0' + sdk: '>=2.7.0 <3.0.0' dependencies: charcode: ^1.1.0 diff --git a/pkgs/package_config/test/discovery_test.dart b/pkgs/package_config/test/discovery_test.dart index 5db24a100..4dd1504e1 100644 --- a/pkgs/package_config/test/discovery_test.dart +++ b/pkgs/package_config/test/discovery_test.dart @@ -170,6 +170,13 @@ main() { expect(config.version, 2); validatePackagesFile(config, directory); }); + fileTest("prefer .packages", files, (Directory directory) async { + File file = dirFile(directory, ".packages"); + PackageConfig config = + await loadPackageConfig(file, preferNewest: false); + expect(config.version, 1); + validatePackagesFile(config, directory); + }); }); fileTest("package_config.json non-default name", { diff --git a/pkgs/package_config/test/discovery_uri_test.dart b/pkgs/package_config/test/discovery_uri_test.dart index 414a43add..9558f585e 100644 --- a/pkgs/package_config/test/discovery_uri_test.dart +++ b/pkgs/package_config/test/discovery_uri_test.dart @@ -4,7 +4,6 @@ library package_config.discovery_test; -import "dart:io"; import "package:test/test.dart"; import "package:package_config_2/package_config.dart"; diff --git a/pkgs/package_config/test/parse_test.dart b/pkgs/package_config/test/parse_test.dart index 235f49381..a07ef1d61 100644 --- a/pkgs/package_config/test/parse_test.dart +++ b/pkgs/package_config/test/parse_test.dart @@ -2,7 +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. -import "dart:io"; import "dart:convert"; import "package:test/test.dart"; @@ -199,9 +198,43 @@ void main() { expect(config.packages.first.name, "foo"); }); + test("nested packages", () { + var configBytes = utf8.encode(json.encode({ + "configVersion": 2, + "packages": [ + {"name": "foo", "rootUri": "/foo/", "packageUri": "lib/"}, + {"name": "bar", "rootUri": "/foo/bar/", "packageUri": "lib/"}, + {"name": "baz", "rootUri": "/foo/bar/baz/", "packageUri": "lib/"}, + {"name": "qux", "rootUri": "/foo/qux/", "packageUri": "lib/"}, + ] + })); + var config = parsePackageConfigBytes( + configBytes, Uri.parse("file:///tmp/.dart_tool/file.dart")); + expect(config.version, 2); + expect(config.packageOf(Uri.parse("file:///foo/lala/lala.dart")).name, + "foo"); + expect( + config.packageOf(Uri.parse("file:///foo/bar/lala.dart")).name, "bar"); + expect(config.packageOf(Uri.parse("file:///foo/bar/baz/lala.dart")).name, + "baz"); + expect( + config.packageOf(Uri.parse("file:///foo/qux/lala.dart")).name, "qux"); + expect(config.toPackageUri(Uri.parse("file:///foo/lib/diz")), + Uri.parse("package:foo/diz")); + expect(config.toPackageUri(Uri.parse("file:///foo/bar/lib/diz")), + Uri.parse("package:bar/diz")); + expect(config.toPackageUri(Uri.parse("file:///foo/bar/baz/lib/diz")), + Uri.parse("package:baz/diz")); + expect(config.toPackageUri(Uri.parse("file:///foo/qux/lib/diz")), + Uri.parse("package:qux/diz")); + }); + group("invalid", () { testThrows(String name, String source) { test(name, () { + if (name == "inside lib") { + print(name); + } expect( () => parsePackageConfigBytes(utf8.encode(source), Uri.parse("file:///tmp/.dart_tool/file.dart")), @@ -304,9 +337,15 @@ void main() { testThrows("same roots", '{$cfg,"packages":[{$name,$root},{"name":"bar",$root}]}'); testThrows( - "overlapping roots", - '{$cfg,"packages":[{$name,$root},' - '{"name":"bar","rootUri":"/foo/sub/"}]}'); + // The roots of foo and bar are the same. + "same roots", + '{$cfg,"packages":[{$name,$root},{"name":"bar",$root}]}'); + testThrows( + // The root of bar is inside the package root of foo. + "inside lib", + '{$cfg,"packages":[' + '{"name":"foo","rootUri":"/foo/","packageUri":"lib/"},' + '{"name":"bar","rootUri":"/foo/lib/qux/"}]}'); }); }); } From db13ed8bf9e2ad1700ef155249d5e8bac2c8b453 Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Mon, 27 Jan 2020 13:07:43 +0100 Subject: [PATCH 080/170] Prepare release of package_config 2.0.0. --- pkgs/package_config/README.md | 8 +++++--- pkgs/package_config/pubspec.yaml | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/pkgs/package_config/README.md b/pkgs/package_config/README.md index 942822002..9ab7f38a3 100644 --- a/pkgs/package_config/README.md +++ b/pkgs/package_config/README.md @@ -1,8 +1,10 @@ # package_config -Support for working with **Package Resolution Configuration** files as described -in this [DEP](https://github.com/lrhn/dep-pkgspec/blob/master/DEP-pkgspec.md), -under review [here](https://github.com/dart-lang/dart_enhancement_proposals/issues/5). +Support for working with **Package Configuration** files as described +in the Package Configuration v2 [design document](https://github.com/dart-lang/language/blob/master/accepted/future-releases/language-versioning/package-config-file-v2.md). + +This package is also available as `package_config_2`, which can be used by packages +which transitively depend on a version of package_config with a version <2.0.0. [![Build Status](https://travis-ci.org/dart-lang/package_config.svg?branch=master)](https://travis-ci.org/dart-lang/package_config) [![pub package](https://img.shields.io/pub/v/package_config.svg)](https://pub.dartlang.org/packages/package_config) diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 781dc32a8..66aeb7858 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,4 +1,4 @@ -name: package_config_2 +name: package_config version: 2.0.0 description: Support for working with Package Configuration files. author: Dart Team From 9bb0203bb07039889f2df85f045382692d7ffe88 Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Mon, 27 Jan 2020 13:07:43 +0100 Subject: [PATCH 081/170] Prepare release of package_config 2.0.0. --- pkgs/package_config/README.md | 5 +++-- pkgs/package_config/test/discovery_test.dart | 2 +- pkgs/package_config/test/discovery_uri_test.dart | 2 +- pkgs/package_config/test/parse_test.dart | 4 ++-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/pkgs/package_config/README.md b/pkgs/package_config/README.md index 9ab7f38a3..073a1c7e0 100644 --- a/pkgs/package_config/README.md +++ b/pkgs/package_config/README.md @@ -3,8 +3,9 @@ Support for working with **Package Configuration** files as described in the Package Configuration v2 [design document](https://github.com/dart-lang/language/blob/master/accepted/future-releases/language-versioning/package-config-file-v2.md). -This package is also available as `package_config_2`, which can be used by packages -which transitively depend on a version of package_config with a version <2.0.0. +This version of the `package_config` package is also available as `package_config_2`, +which can be used by packages which transitively depend on a version of `package_config` +with a version <2.0.0. [![Build Status](https://travis-ci.org/dart-lang/package_config.svg?branch=master)](https://travis-ci.org/dart-lang/package_config) [![pub package](https://img.shields.io/pub/v/package_config.svg)](https://pub.dartlang.org/packages/package_config) diff --git a/pkgs/package_config/test/discovery_test.dart b/pkgs/package_config/test/discovery_test.dart index 4dd1504e1..3256187d2 100644 --- a/pkgs/package_config/test/discovery_test.dart +++ b/pkgs/package_config/test/discovery_test.dart @@ -6,7 +6,7 @@ library package_config.discovery_test; import "dart:io"; import "package:test/test.dart"; -import "package:package_config_2/package_config.dart"; +import "package:package_config/package_config.dart"; import "src/util.dart"; diff --git a/pkgs/package_config/test/discovery_uri_test.dart b/pkgs/package_config/test/discovery_uri_test.dart index 9558f585e..8ad428ac0 100644 --- a/pkgs/package_config/test/discovery_uri_test.dart +++ b/pkgs/package_config/test/discovery_uri_test.dart @@ -5,7 +5,7 @@ library package_config.discovery_test; import "package:test/test.dart"; -import "package:package_config_2/package_config.dart"; +import "package:package_config/package_config.dart"; import "src/util.dart"; diff --git a/pkgs/package_config/test/parse_test.dart b/pkgs/package_config/test/parse_test.dart index a07ef1d61..3d1a20e4a 100644 --- a/pkgs/package_config/test/parse_test.dart +++ b/pkgs/package_config/test/parse_test.dart @@ -6,8 +6,8 @@ import "dart:convert"; import "package:test/test.dart"; -import "package:package_config_2/src/packages_file.dart" as packages; -import "package:package_config_2/src/package_config_json.dart"; +import "package:package_config/src/packages_file.dart" as packages; +import "package:package_config/src/package_config_json.dart"; import "src/util.dart"; void main() { From 86f3c5245a3aac86783819a35153b20c80fe0557 Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Tue, 11 Feb 2020 09:34:11 +0100 Subject: [PATCH 082/170] Make error handling optionally more permissive. (dart-lang/package_config#58) * Make error handling optionally more permissive. * Make the LanguageVersion be an object, not a string. * Make it version 3.0.0-dev --- pkgs/package_config/CHANGELOG.md | 19 +- pkgs/package_config/README.md | 6 +- pkgs/package_config/lib/package_config.dart | 49 ++- pkgs/package_config/lib/src/discovery.dart | 48 +-- pkgs/package_config/lib/src/errors.dart | 57 +-- .../lib/src/package_config.dart | 122 ++++++- .../lib/src/package_config_impl.dart | 331 +++++++++++++----- .../lib/src/package_config_json.dart | 194 +++++++--- .../package_config/lib/src/packages_file.dart | 91 +++-- pkgs/package_config/lib/src/util.dart | 118 ++++--- pkgs/package_config/pubspec.yaml | 6 +- pkgs/package_config/test/discovery_test.dart | 119 +++++-- .../test/discovery_uri_test.dart | 43 ++- pkgs/package_config/test/parse_test.dart | 63 ++-- pkgs/package_config/test/src/util.dart | 8 +- 15 files changed, 917 insertions(+), 357 deletions(-) diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index 84384fc21..317184075 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -1,9 +1,22 @@ +## 3.0.0 + +- Make the language version be represented as a `LanguageVersion` class + instead of a string. +- Made error handling interceptable. Passing an `onError` handler + makes the parsers attempt to do a best-effort error correction after + detecting an error. +- Do not require root URIs to have paths starting with `/`. That + only makes sense for `file` or `http`, and they enforce it anyway. +- Fixed bug in language version validation not accepting the digit `9`. + ## 2.0.0 - - Based on new JSON file format with more content. + +- Based on new JSON file format with more content. ## 1.2.0 - - Added support for writing default-package entries. - - Fixed bug when writing `Uri`s containing a fragment. + +- Added support for writing default-package entries. +- Fixed bug when writing `Uri`s containing a fragment. ## 1.1.0 diff --git a/pkgs/package_config/README.md b/pkgs/package_config/README.md index 073a1c7e0..45791aaf3 100644 --- a/pkgs/package_config/README.md +++ b/pkgs/package_config/README.md @@ -3,11 +3,7 @@ Support for working with **Package Configuration** files as described in the Package Configuration v2 [design document](https://github.com/dart-lang/language/blob/master/accepted/future-releases/language-versioning/package-config-file-v2.md). -This version of the `package_config` package is also available as `package_config_2`, -which can be used by packages which transitively depend on a version of `package_config` -with a version <2.0.0. - -[![Build Status](https://travis-ci.org/dart-lang/package_config.svg?branch=master)](https://travis-ci.org/dart-lang/package_config) [![pub package](https://img.shields.io/pub/v/package_config.svg)](https://pub.dartlang.org/packages/package_config) +[![Build Status](https://travis-ci.org/dart-lang/package_config.svg?branch=master)](https://travis-ci.org/dart-lang/package_config) [![pub package](https://img.shields.io/pub/v/package_config.svg)](https://pub.dartlang.org/packages/package_config) ## Features and bugs diff --git a/pkgs/package_config/lib/package_config.dart b/pkgs/package_config/lib/package_config.dart index 77e8d61bf..98b31f1f9 100644 --- a/pkgs/package_config/lib/package_config.dart +++ b/pkgs/package_config/lib/package_config.dart @@ -8,11 +8,14 @@ library package_config.package_config; import "dart:io" show File, Directory; import "dart:typed_data" show Uint8List; + import "src/discovery.dart" as discover; +import "src/errors.dart" show throwError; import "src/package_config.dart"; import "src/package_config_json.dart"; -export "src/package_config.dart" show PackageConfig, Package; +export "src/package_config.dart" + show PackageConfig, Package, LanguageVersion, InvalidLanguageVersion; export "src/errors.dart" show PackageConfigError; /// Reads a specific package configuration file. @@ -30,9 +33,15 @@ export "src/errors.dart" show PackageConfigError; /// is loaded even if there is an available `package_config.json` file. /// The caller can determine this from the [PackageConfig.version] /// being 1 and look for a `package_config.json` file themselves. +/// +/// If [onError] is provided, the configuration file parsing will report errors +/// by calling that function, and then try to recover. +/// The returned package configuration is a *best effort* attempt to create +/// a valid configuration from the invalid configuration file. +/// If no [onError] is provided, errors are thrown immediately. Future loadPackageConfig(File file, - {bool preferNewest = true}) => - readAnyConfigFile(file, preferNewest); + {bool preferNewest = true, void onError(Object error)}) => + readAnyConfigFile(file, preferNewest, onError ?? throwError); /// Reads a specific package configuration URI. /// @@ -68,10 +77,17 @@ Future loadPackageConfig(File file, /// of an I/O issue, as long as the location URIs are valid. /// As such, it does not distinguish between a file not existing, /// and it being temporarily locked or unreachable. +/// +/// If [onError] is provided, the configuration file parsing will report errors +/// by calling that function, and then try to recover. +/// The returned package configuration is a *best effort* attempt to create +/// a valid configuration from the invalid configuration file. +/// If no [onError] is provided, errors are thrown immediately. Future loadPackageConfigUri(Uri file, {Future loader(Uri uri) /*?*/, - bool preferNewest = true}) => - readAnyConfigFileUri(file, loader, preferNewest); + bool preferNewest = true, + void onError(Object error)}) => + readAnyConfigFileUri(file, loader, onError ?? throwError, preferNewest); /// Finds a package configuration relative to [directory]. /// @@ -86,10 +102,16 @@ Future loadPackageConfigUri(Uri file, /// If [recurse] is set to [false], this parent directory check is not /// performed. /// +/// If [onError] is provided, the configuration file parsing will report errors +/// by calling that function, and then try to recover. +/// The returned package configuration is a *best effort* attempt to create +/// a valid configuration from the invalid configuration file. +/// If no [onError] is provided, errors are thrown immediately. +/// /// Returns `null` if no configuration file is found. Future findPackageConfig(Directory directory, - {bool recurse = true}) => - discover.findPackageConfig(directory, recurse); + {bool recurse = true, void onError(Object error)}) => + discover.findPackageConfig(directory, recurse, onError ?? throwError); /// Finds a package configuration relative to [location]. /// @@ -124,10 +146,19 @@ Future findPackageConfig(Directory directory, /// As such, it does not distinguish between a file not existing, /// and it being temporarily locked or unreachable. /// +/// If [onError] is provided, the configuration file parsing will report errors +/// by calling that function, and then try to recover. +/// The returned package configuration is a *best effort* attempt to create +/// a valid configuration from the invalid configuration file. +/// If no [onError] is provided, errors are thrown immediately. +/// /// Returns `null` if no configuration file is found. Future findPackageConfigUri(Uri location, - {bool recurse = true, Future loader(Uri uri)}) => - discover.findPackageConfigUri(location, loader, recurse); + {bool recurse = true, + Future loader(Uri uri), + void onError(Object error)}) => + discover.findPackageConfigUri( + location, loader, onError ?? throwError, recurse); /// Writes a package configuration to the provided directory. /// diff --git a/pkgs/package_config/lib/src/discovery.dart b/pkgs/package_config/lib/src/discovery.dart index 5ad6ac54e..14033ed35 100644 --- a/pkgs/package_config/lib/src/discovery.dart +++ b/pkgs/package_config/lib/src/discovery.dart @@ -5,13 +5,11 @@ import "dart:io"; import 'dart:typed_data'; -import "package:path/path.dart" as p; - import "errors.dart"; import "package_config_impl.dart"; import "package_config_json.dart"; import "packages_file.dart" as packages_file; -import "util.dart" show defaultLoader; +import "util.dart" show defaultLoader, pathJoin; final Uri packageConfigJsonPath = Uri(path: ".dart_tool/package_config.json"); final Uri dotPackagesPath = Uri(path: ".packages"); @@ -33,7 +31,7 @@ final Uri parentPath = Uri(path: ".."); /// Returns `null` if no configuration was found. If a configuration /// is needed, then the caller can supply [PackageConfig.empty]. Future findPackageConfig( - Directory baseDirectory, bool recursive) async { + Directory baseDirectory, bool recursive, void onError(Object error)) async { var directory = baseDirectory; if (!directory.isAbsolute) directory = directory.absolute; if (!await directory.exists()) { @@ -41,7 +39,7 @@ Future findPackageConfig( } do { // Check for $cwd/.packages - var packageConfig = await findPackagConfigInDirectory(directory); + var packageConfig = await findPackagConfigInDirectory(directory, onError); if (packageConfig != null) return packageConfig; if (!recursive) break; // Check in parent directories. @@ -53,16 +51,22 @@ Future findPackageConfig( } /// Similar to [findPackageConfig] but based on a URI. -Future findPackageConfigUri(Uri location, - Future loader(Uri uri) /*?*/, bool recursive) async { +Future findPackageConfigUri( + Uri location, + Future loader(Uri uri) /*?*/, + void onError(Object error) /*?*/, + bool recursive) async { if (location.isScheme("package")) { - throw PackageConfigArgumentError( - location, "location", "Must not be a package: URI"); + onError(PackageConfigArgumentError( + location, "location", "Must not be a package: URI")); + return null; } if (loader == null) { if (location.isScheme("file")) { return findPackageConfig( - Directory.fromUri(location.resolveUri(currentPath)), recursive); + Directory.fromUri(location.resolveUri(currentPath)), + recursive, + onError); } loader = defaultLoader; } @@ -71,12 +75,12 @@ Future findPackageConfigUri(Uri location, var file = location.resolveUri(packageConfigJsonPath); var bytes = await loader(file); if (bytes != null) { - return parsePackageConfigBytes(bytes, file); + return parsePackageConfigBytes(bytes, file, onError); } file = location.resolveUri(dotPackagesPath); bytes = await loader(file); if (bytes != null) { - return packages_file.parse(bytes, file); + return packages_file.parse(bytes, file, onError); } if (!recursive) break; var parent = location.resolveUri(parentPath); @@ -90,33 +94,35 @@ Future findPackageConfigUri(Uri location, /// /// Loads the file, if it is there, and returns the resulting [PackageConfig]. /// Returns `null` if the file isn't there. -/// Throws [FormatException] if a file is there but is not valid. +/// Reports a [FormatException] if a file is there but the content is not valid. +/// If the file exists, but fails to be read, the file system error is reported. /// -/// If [extraData] is supplied and the `package_config.json` contains extra -/// entries in the top JSON object, those extra entries are stored into -/// [extraData]. +/// If [onError] is supplied, parsing errors are reported using that, and +/// a best-effort attempt is made to return a package configuration. +/// This may be the empty package configuration. Future findPackagConfigInDirectory( - Directory directory) async { + Directory directory, void onError(Object error)) async { var packageConfigFile = await checkForPackageConfigJsonFile(directory); if (packageConfigFile != null) { - return await readPackageConfigJsonFile(packageConfigFile); + return await readPackageConfigJsonFile(packageConfigFile, onError); } packageConfigFile = await checkForDotPackagesFile(directory); if (packageConfigFile != null) { - return await readDotPackagesFile(packageConfigFile); + return await readDotPackagesFile(packageConfigFile, onError); } return null; } Future /*?*/ checkForPackageConfigJsonFile(Directory directory) async { assert(directory.isAbsolute); - var file = File(p.join(directory.path, ".dart_tool", "package_config.json")); + var file = + File(pathJoin(directory.path, ".dart_tool", "package_config.json")); if (await file.exists()) return file; return null; } Future checkForDotPackagesFile(Directory directory) async { - var file = File(p.join(directory.path, ".packages")); + var file = File(pathJoin(directory.path, ".packages")); if (await file.exists()) return file; return null; } diff --git a/pkgs/package_config/lib/src/errors.dart b/pkgs/package_config/lib/src/errors.dart index 6c31ccea1..c9736177c 100644 --- a/pkgs/package_config/lib/src/errors.dart +++ b/pkgs/package_config/lib/src/errors.dart @@ -1,24 +1,33 @@ -// Copyright (c) 2019, 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. - -/// General superclass of most errors and exceptions thrown by this package. -/// -/// Only covers errors thrown while parsing package configuration files. -/// Programming errors and I/O exceptions are not covered. -abstract class PackageConfigError { - PackageConfigError._(); -} - -class PackageConfigArgumentError extends ArgumentError - implements PackageConfigError { - PackageConfigArgumentError(Object /*?*/ value, String name, String message) - : super.value(value, name, message); -} - -class PackageConfigFormatException extends FormatException - implements PackageConfigError { - PackageConfigFormatException(String message, Object /*?*/ value, - [int /*?*/ index]) - : super(message, value, index); -} +// Copyright (c) 2019, 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. + +/// General superclass of most errors and exceptions thrown by this package. +/// +/// Only covers errors thrown while parsing package configuration files. +/// Programming errors and I/O exceptions are not covered. +abstract class PackageConfigError { + PackageConfigError._(); +} + +class PackageConfigArgumentError extends ArgumentError + implements PackageConfigError { + PackageConfigArgumentError(Object /*?*/ value, String name, String message) + : super.value(value, name, message); + + PackageConfigArgumentError.from(ArgumentError error) + : super.value(error.invalidValue, error.name, error.message); +} + +class PackageConfigFormatException extends FormatException + implements PackageConfigError { + PackageConfigFormatException(String message, Object /*?*/ source, + [int /*?*/ offset]) + : super(message, source, offset); + + PackageConfigFormatException.from(FormatException exception) + : super(exception.message, exception.source, exception.offset); +} + +/// The default `onError` handler. +void /*Never*/ throwError(Object error) => throw error; diff --git a/pkgs/package_config/lib/src/package_config.dart b/pkgs/package_config/lib/src/package_config.dart index f7b96b8a5..08c4a9691 100644 --- a/pkgs/package_config/lib/src/package_config.dart +++ b/pkgs/package_config/lib/src/package_config.dart @@ -2,6 +2,7 @@ // 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. +import 'errors.dart'; import "package_config_impl.dart"; /// A package configuration. @@ -34,7 +35,7 @@ abstract class PackageConfig { /// /// The version of the resulting configuration is always [maxVersion]. factory PackageConfig(Iterable packages, {dynamic extraData}) => - SimplePackageConfig(maxVersion, packages); + SimplePackageConfig(maxVersion, packages, extraData); /// The configuration version number. /// @@ -124,9 +125,10 @@ abstract class Package { /// [Package.extraData] of the created package. factory Package(String name, Uri root, {Uri /*?*/ packageUriRoot, - String /*?*/ languageVersion, + LanguageVersion /*?*/ languageVersion, dynamic extraData}) => - SimplePackage(name, root, packageUriRoot, languageVersion, extraData); + SimplePackage.validate( + name, root, packageUriRoot, languageVersion, extraData, throwError); /// The package-name of the package. String get name; @@ -156,16 +158,9 @@ abstract class Package { /// Each package may have a default language version associated, /// which is the language version used to parse and compile /// Dart files in the package. - /// A package version is always of the form: - /// - /// * A numeral consisting of one or more decimal digits, - /// with no leading zero unless the entire numeral is a single zero digit. - /// * Followed by a `.` character. - /// * Followed by another numeral of the same form. - /// - /// There is no whitespace allowed around the numerals. - /// Valid version numbers include `2.5`, `3.0`, and `1234.5678`. - String /*?*/ get languageVersion; + /// A package version is defined by two non-negative numbers, + /// the *major* and *minor* version numbers. + LanguageVersion /*?*/ get languageVersion; /// Extra data associated with the specific package. /// @@ -174,3 +169,104 @@ abstract class Package { /// JSON-like list/map data structures. dynamic get extraData; } + +/// A language version. +/// +/// A language version is represented by two non-negative integers, +/// the [major] and [minor] version numbers. +/// +/// If errors during parsing are handled using an `onError` handler, +/// then an *invalid* language version may be represented by an +/// [InvalidLanguageVersion] object. +abstract class LanguageVersion implements Comparable { + /// The maximal value allowed by [major] and [minor] values; + static const int maxValue = 0x7FFFFFFF; + factory LanguageVersion(int major, int minor) { + RangeError.checkValueInInterval(major, 0, maxValue, "major"); + RangeError.checkValueInInterval(minor, 0, maxValue, "major"); + return SimpleLanguageVersion(major, minor, null); + } + + /// Parses a language version string. + /// + /// A valid language version string has the form + /// + /// > *decimalNumber* `.` *decimalNumber* + /// + /// where a *decimalNumber* is a non-empty sequence of decimal digits + /// with no unnecessary leading zeros (the decimal number only starts + /// with a zero digit if that digit is the entire number). + /// No spaces are allowed in the string. + /// + /// If the [source] is valid then it is parsed into a valid + /// [LanguageVersion] object. + /// If not, then the [onError] is called with a [FormatException]. + /// If [onError] is not supplied, it defaults to throwing the exception. + /// If the call does not throw, then an [InvalidLanguageVersion] is returned + /// containing the original [source]. + static LanguageVersion parse(String source, {void onError(Object error)}) => + parseLanguageVersion(source, onError ?? throwError); + + /// The major language version. + /// + /// A non-negative integer less than 231. + /// + /// The value is negative for objects representing *invalid* language + /// versions ([InvalidLanguageVersion]). + int get major; + + /// The minor language version. + /// + /// A non-negative integer less than 231. + /// + /// The value is negative for objects representing *invalid* language + /// versions ([InvalidLanguageVersion]). + int get minor; + + /// Compares language versions. + /// + /// Two language versions are considered equal if they have the + /// same major and minor version numbers. + /// + /// A language version is greater then another if the former's major version + /// is greater than the latter's major version, or if they have + /// the same major version and the former's minor version is greater than + /// the latter's. + int compareTo(LanguageVersion other); + + /// Valid language versions with the same [major] and [minor] values are + /// equal. + /// + /// Invalid language versions ([InvalidLanguageVersion]) are not equal to + /// any other object. + bool operator ==(Object other); + + int get hashCode; + + /// A string representation of the language version. + /// + /// A valid language version is represented as + /// `"${version.major}.${version.minor}"`. + String toString(); +} + +/// An *invalid* language version. +/// +/// Stored in a [Package] when the orginal language version string +/// was invalid and a `onError` handler was passed to the parser +/// which did not throw on an error. +abstract class InvalidLanguageVersion implements LanguageVersion { + /// The value -1 for an invalid language version. + int get major; + + /// The value -1 for an invalid language version. + int get minor; + + /// An invalid language version is only equal to itself. + bool operator ==(Object other); + + int get hashCode; + + /// The original invalid version string. + String toString(); +} diff --git a/pkgs/package_config/lib/src/package_config_impl.dart b/pkgs/package_config/lib/src/package_config_impl.dart index 62579610c..39633fe4b 100644 --- a/pkgs/package_config/lib/src/package_config_impl.dart +++ b/pkgs/package_config/lib/src/package_config_impl.dart @@ -14,16 +14,18 @@ class SimplePackageConfig implements PackageConfig { final PackageTree _packageTree; final dynamic extraData; - SimplePackageConfig(int version, Iterable packages, - [dynamic extraData]) - : this._(_validateVersion(version), packages, - [...packages]..sort(_compareRoot), extraData); + factory SimplePackageConfig(int version, Iterable packages, + [dynamic extraData, void onError(Object error)]) { + onError ??= throwError; + var validVersion = _validateVersion(version, onError); + var sortedPackages = [...packages]..sort(_compareRoot); + var packageTree = _validatePackages(packages, sortedPackages, onError); + return SimplePackageConfig._(validVersion, packageTree, + {for (var p in packageTree.allPackages) p.name: p}, extraData); + } - /// Expects a list of [packages] sorted on root path. - SimplePackageConfig._(this.version, Iterable originalPackages, - List packages, this.extraData) - : _packageTree = _validatePackages(originalPackages, packages), - _packages = {for (var p in packages) p.name: p}; + SimplePackageConfig._( + this.version, this._packageTree, this._packages, this.extraData); /// Creates empty configuration. /// @@ -35,66 +37,78 @@ class SimplePackageConfig implements PackageConfig { _packages = const {}, extraData = null; - static int _validateVersion(int version) { + static int _validateVersion(int version, void onError(Object error)) { if (version < 0 || version > PackageConfig.maxVersion) { - throw PackageConfigArgumentError(version, "version", - "Must be in the range 1 to ${PackageConfig.maxVersion}"); + onError(PackageConfigArgumentError(version, "version", + "Must be in the range 1 to ${PackageConfig.maxVersion}")); + return 2; // The minimal version supporting a SimplePackageConfig. } return version; } - static PackageTree _validatePackages( - Iterable originalPackages, List packages) { - // Assumes packages are sorted. - Map result = {}; + static PackageTree _validatePackages(Iterable originalPackages, + List packages, void onError(Object error)) { + var packageNames = {}; var tree = MutablePackageTree(); - SimplePackage package; for (var originalPackage in packages) { + if (originalPackage == null) { + onError(ArgumentError.notNull("element of packages")); + continue; + } + SimplePackage package; if (originalPackage is! SimplePackage) { // SimplePackage validates these properties. - try { - package = SimplePackage( - originalPackage.name, - originalPackage.root, - originalPackage.packageUriRoot, - originalPackage.languageVersion, - originalPackage.extraData); - } catch (e) { - throw PackageConfigArgumentError( - packages, "packages", "Package ${package.name}: ${e.message}"); - } + package = SimplePackage.validate( + originalPackage.name, + originalPackage.root, + originalPackage.packageUriRoot, + originalPackage.languageVersion, + originalPackage.extraData, (error) { + if (error is PackageConfigArgumentError) { + onError(PackageConfigArgumentError(packages, "packages", + "Package ${package.name}: ${error.message}")); + } else { + onError(error); + } + }); + if (package == null) continue; } else { package = originalPackage; } var name = package.name; - if (result.containsKey(name)) { - throw PackageConfigArgumentError( - name, "packages", "Duplicate package name"); + if (packageNames.contains(name)) { + onError(PackageConfigArgumentError( + name, "packages", "Duplicate package name")); + continue; } - result[name] = package; - try { - tree.add(0, package); - } on ConflictException catch (e) { - // There is a conflict with an existing package. - var existingPackage = e.existingPackage; - if (e.isRootConflict) { - throw PackageConfigArgumentError( - originalPackages, - "packages", - "Packages ${package.name} and ${existingPackage.name}" - "have the same root directory: ${package.root}.\n"); + packageNames.add(name); + tree.add(0, package, (error) { + if (error is ConflictException) { + // There is a conflict with an existing package. + var existingPackage = error.existingPackage; + if (error.isRootConflict) { + onError(PackageConfigArgumentError( + originalPackages, + "packages", + "Packages ${package.name} and ${existingPackage.name}" + "have the same root directory: ${package.root}.\n")); + } else { + assert(error.isPackageRootConflict); + // Package is inside the package URI root of the existing package. + onError(PackageConfigArgumentError( + originalPackages, + "packages", + "Package ${package.name} is inside the package URI root of " + "package ${existingPackage.name}.\n" + "${existingPackage.name} URI root: " + "${existingPackage.packageUriRoot}\n" + "${package.name} root: ${package.root}\n")); + } + } else { + // Any other error. + onError(error); } - assert(e.isPackageRootConflict); - // Or package is inside the package URI root of the existing package. - throw PackageConfigArgumentError( - originalPackages, - "packages", - "Package ${package.name} is inside the package URI root of " - "package ${existingPackage.name}.\n" - "${existingPackage.name} URI root: " - "${existingPackage.packageUriRoot}\n" - "${package.name} root: ${package.root}\n"); - } + }); } return tree; } @@ -145,7 +159,7 @@ class SimplePackage implements Package { final String name; final Uri root; final Uri packageUriRoot; - final String /*?*/ languageVersion; + final LanguageVersion /*?*/ languageVersion; final dynamic extraData; SimplePackage._(this.name, this.root, this.packageUriRoot, @@ -154,45 +168,175 @@ class SimplePackage implements Package { /// Creates a [SimplePackage] with the provided content. /// /// The provided arguments must be valid. - factory SimplePackage(String name, Uri root, Uri packageUriRoot, - String /*?*/ languageVersion, dynamic extraData) { - _validatePackageData(name, root, packageUriRoot, languageVersion); + /// + /// If the arguments are invalid then the error is reported by + /// calling [onError], then the erroneous entry is ignored. + /// + /// If [onError] is provided, the user is expected to be able to handle + /// errors themselves. An invalid [languageVersion] string + /// will be replaced with the string `"invalid"`. This allows + /// users to detect the difference between an absent version and + /// an invalid one. + /// + /// Returns `null` if the input is invalid and an approximately valid package + /// cannot be salvaged from the input. + static SimplePackage /*?*/ validate( + String name, + Uri root, + Uri packageUriRoot, + LanguageVersion /*?*/ languageVersion, + dynamic extraData, + void onError(Object error)) { + bool fatalError = false; + var invalidIndex = checkPackageName(name); + if (invalidIndex >= 0) { + onError(PackageConfigFormatException( + "Not a valid package name", name, invalidIndex)); + fatalError = true; + } + if (root.isScheme("package")) { + onError(PackageConfigArgumentError( + "$root", "root", "Must not be a package URI")); + fatalError = true; + } else if (!isAbsoluteDirectoryUri(root)) { + onError(PackageConfigArgumentError( + "$root", + "root", + "In package $name: Not an absolute URI with no query or fragment " + "with a path ending in /")); + // Try to recover. If the URI has a scheme, + // then ensure that the path ends with `/`. + if (!root.hasScheme) { + fatalError = true; + } else if (!root.path.endsWith("/")) { + root = root.replace(path: root.path + "/"); + } + } + if (!fatalError) { + if (!isAbsoluteDirectoryUri(packageUriRoot)) { + onError(PackageConfigArgumentError( + packageUriRoot, + "packageUriRoot", + "In package $name: Not an absolute URI with no query or fragment " + "with a path ending in /")); + packageUriRoot = root; + } else if (!isUriPrefix(root, packageUriRoot)) { + onError(PackageConfigArgumentError(packageUriRoot, "packageUriRoot", + "The package URI root is not below the package root")); + packageUriRoot = root; + } + } + if (fatalError) return null; return SimplePackage._( name, root, packageUriRoot, languageVersion, extraData); } } -void _validatePackageData( - String name, Uri root, Uri packageUriRoot, String /*?*/ languageVersion) { - if (!isValidPackageName(name)) { - throw PackageConfigArgumentError(name, "name", "Not a valid package name"); +/// Checks whether [version] is a valid Dart language version string. +/// +/// The format is (as RegExp) `^(0|[1-9]\d+)\.(0|[1-9]\d+)$`. +/// +/// Reports a format exception on [onError] if not, or if the numbers +/// are too large (at most 32-bit signed integers). +LanguageVersion parseLanguageVersion( + String source, void onError(Object error)) { + var index = 0; + // Reads a positive decimal numeral. Returns the value of the numeral, + // or a negative number in case of an error. + // Starts at [index] and increments the index to the position after + // the numeral. + // It is an error if the numeral value is greater than 0x7FFFFFFFF. + // It is a recoverable error if the numeral starts with leading zeros. + int readNumeral() { + const maxValue = 0x7FFFFFFF; + if (index == source.length) { + onError(PackageConfigFormatException("Missing number", source, index)); + return -1; + } + var start = index; + + var char = source.codeUnitAt(index); + var digit = char ^ 0x30; + if (digit > 9) { + onError(PackageConfigFormatException("Missing number", source, index)); + return -1; + } + var firstDigit = digit; + var value = 0; + do { + value = value * 10 + digit; + if (value > maxValue) { + onError( + PackageConfigFormatException("Number too large", source, start)); + return -1; + } + index++; + if (index == source.length) break; + char = source.codeUnitAt(index); + digit = char ^ 0x30; + } while (digit <= 9); + if (firstDigit == 0 && index > start + 1) { + onError(PackageConfigFormatException( + "Leading zero not allowed", source, start)); + } + return value; + } + + var major = readNumeral(); + if (major < 0) { + return SimpleInvalidLanguageVersion(source); } - if (!isAbsoluteDirectoryUri(root)) { - throw PackageConfigArgumentError( - "$root", - "root", - "Not an absolute URI with no query or fragment " - "with a path ending in /"); + if (index == source.length || source.codeUnitAt(index) != $dot) { + onError(PackageConfigFormatException("Missing '.'", source, index)); + return SimpleInvalidLanguageVersion(source); } - if (!isAbsoluteDirectoryUri(packageUriRoot)) { - throw PackageConfigArgumentError( - packageUriRoot, - "packageUriRoot", - "Not an absolute URI with no query or fragment " - "with a path ending in /"); + index++; + var minor = readNumeral(); + if (minor < 0) { + return SimpleInvalidLanguageVersion(source); } - if (!isUriPrefix(root, packageUriRoot)) { - throw PackageConfigArgumentError(packageUriRoot, "packageUriRoot", - "The package URI root is not below the package root"); + if (index != source.length) { + onError(PackageConfigFormatException( + "Unexpected trailing character", source, index)); + return SimpleInvalidLanguageVersion(source); } - if (languageVersion != null && - checkValidVersionNumber(languageVersion) >= 0) { - throw PackageConfigArgumentError( - languageVersion, "languageVersion", "Invalid language version format"); + return SimpleLanguageVersion(major, minor, source); +} + +abstract class _SimpleLanguageVersionBase implements LanguageVersion { + int compareTo(LanguageVersion other) { + int result = major.compareTo(other.major); + if (result != 0) return result; + return minor.compareTo(other.minor); } } +class SimpleLanguageVersion extends _SimpleLanguageVersionBase { + final int major; + final int minor; + String /*?*/ _source; + SimpleLanguageVersion(this.major, this.minor, this._source); + + bool operator ==(Object other) => + other is LanguageVersion && major == other.major && minor == other.minor; + + int get hashCode => (major * 17 ^ minor * 37) & 0x3FFFFFFF; + + String toString() => _source ??= "$major.$minor"; +} + +class SimpleInvalidLanguageVersion extends _SimpleLanguageVersionBase + implements InvalidLanguageVersion { + final String _source; + SimpleInvalidLanguageVersion(this._source); + int get major => -1; + int get minor => -1; + + String toString() => _source; +} + abstract class PackageTree { + Iterable get allPackages; SimplePackage /*?*/ packageOf(Uri file); } @@ -210,13 +354,24 @@ class MutablePackageTree implements PackageTree { final List packages = []; Map /*?*/ _packageChildren; + Iterable get allPackages sync* { + for (var package in packages) yield package; + if (_packageChildren != null) { + for (var tree in _packageChildren.values) yield* tree.allPackages; + } + } + /// Tries to (add) `package` to the tree. /// - /// Throws [ConflictException] if the added package conflicts with an + /// Reports a [ConflictException] if the added package conflicts with an /// existing package. /// It conflicts if it has the same root path, or if the new package /// contains the existing package's package root. - void add(int start, SimplePackage package) { + /// + /// If a conflict is detected between [package] and a previous package, + /// then [onError] is called with a [ConflictException] object + /// and the [package] is not added to the tree. + void add(int start, SimplePackage package, void onError(Object error)) { var path = package.root.toString(); for (var childPackage in packages) { var childPath = childPackage.root.toString(); @@ -225,13 +380,15 @@ class MutablePackageTree implements PackageTree { if (_beginsWith(start, childPath, path)) { var childPathLength = childPath.length; if (path.length == childPathLength) { - throw ConflictException.root(package, childPackage); + onError(ConflictException.root(package, childPackage)); + return; } var childPackageRoot = childPackage.packageUriRoot.toString(); if (_beginsWith(childPathLength, childPackageRoot, path)) { - throw ConflictException.packageRoot(package, childPackage); + onError(ConflictException.packageRoot(package, childPackage)); + return; } - _treeOf(childPackage).add(childPathLength, package); + _treeOf(childPackage).add(childPathLength, package, onError); return; } } @@ -286,6 +443,8 @@ class MutablePackageTree implements PackageTree { class EmptyPackageTree implements PackageTree { const EmptyPackageTree(); + Iterable get allPackages => const Iterable.empty(); + SimplePackage packageOf(Uri file) => null; } diff --git a/pkgs/package_config/lib/src/package_config_json.dart b/pkgs/package_config/lib/src/package_config_json.dart index 8108102bd..f56c91271 100644 --- a/pkgs/package_config/lib/src/package_config_json.dart +++ b/pkgs/package_config/lib/src/package_config_json.dart @@ -6,9 +6,6 @@ import "dart:convert"; import "dart:io"; import "dart:typed_data"; -import 'package:charcode/ascii.dart'; -import "package:path/path.dart" as p; - import "discovery.dart" show packageConfigJsonPath; import "errors.dart"; import "package_config_impl.dart"; @@ -45,41 +42,66 @@ const String _generatorVersionKey = "generatorVersion"; /// a `.packages` file and there is an available `package_config.json` file. /// /// The file must exist and be a normal file. -Future readAnyConfigFile(File file, bool preferNewest) async { - var bytes = await file.readAsBytes(); +Future readAnyConfigFile( + File file, bool preferNewest, void onError(Object error)) async { + Uint8List bytes; + try { + bytes = await file.readAsBytes(); + } catch (e) { + onError(e); + return const SimplePackageConfig.empty(); + } int firstChar = firstNonWhitespaceChar(bytes); if (firstChar != $lbrace) { // Definitely not a JSON object, probably a .packages. if (preferNewest) { var alternateFile = File( - p.join(p.dirname(file.path), ".dart_tool", "package_config.json")); + pathJoin(dirName(file.path), ".dart_tool", "package_config.json")); if (alternateFile.existsSync()) { - return parsePackageConfigBytes( - await alternateFile.readAsBytes(), alternateFile.uri); + Uint8List /*?*/ bytes; + try { + bytes = await alternateFile.readAsBytes(); + } catch (e) { + onError(e); + return const SimplePackageConfig.empty(); + } + if (bytes != null) { + return parsePackageConfigBytes(bytes, alternateFile.uri, onError); + } } } - return packages_file.parse(bytes, file.uri); + return packages_file.parse(bytes, file.uri, onError); } - return parsePackageConfigBytes(bytes, file.uri); + return parsePackageConfigBytes(bytes, file.uri, onError); } /// Like [readAnyConfigFile] but uses a URI and an optional loader. -Future readAnyConfigFileUri(Uri file, - Future loader(Uri uri) /*?*/, bool preferNewest) async { +Future readAnyConfigFileUri( + Uri file, + Future loader(Uri uri) /*?*/, + void onError(Object error), + bool preferNewest) async { if (file.isScheme("package")) { throw PackageConfigArgumentError( file, "file", "Must not be a package: URI"); } if (loader == null) { if (file.isScheme("file")) { - return readAnyConfigFile(File.fromUri(file), preferNewest); + return readAnyConfigFile(File.fromUri(file), preferNewest, onError); } loader = defaultLoader; } - var bytes = await loader(file); + Uint8List bytes; + try { + bytes = await loader(file); + } catch (e) { + onError(e); + return const SimplePackageConfig.empty(); + } if (bytes == null) { - throw PackageConfigArgumentError( - file.toString(), "file", "File cannot be read"); + onError(PackageConfigArgumentError( + file.toString(), "file", "File cannot be read")); + return const SimplePackageConfig.empty(); } int firstChar = firstNonWhitespaceChar(bytes); if (firstChar != $lbrace) { @@ -87,39 +109,59 @@ Future readAnyConfigFileUri(Uri file, if (preferNewest) { // Check if there is a package_config.json file. var alternateFile = file.resolveUri(packageConfigJsonPath); - var alternateBytes = await loader(alternateFile); + Uint8List alternateBytes; + try { + alternateBytes = await loader(alternateFile); + } catch (e) { + onError(e); + return const SimplePackageConfig.empty(); + } if (alternateBytes != null) { - return parsePackageConfigBytes(alternateBytes, alternateFile); + return parsePackageConfigBytes(alternateBytes, alternateFile, onError); } } - return packages_file.parse(bytes, file); + return packages_file.parse(bytes, file, onError); } - return parsePackageConfigBytes(bytes, file); + return parsePackageConfigBytes(bytes, file, onError); } -Future readPackageConfigJsonFile(File file) async { +Future readPackageConfigJsonFile( + File file, void onError(Object error)) async { Uint8List bytes; try { bytes = await file.readAsBytes(); - } catch (_) { - return null; + } catch (error) { + onError(error); + return const SimplePackageConfig.empty(); } - return parsePackageConfigBytes(bytes, file.uri); + return parsePackageConfigBytes(bytes, file.uri, onError); } -Future readDotPackagesFile(File file) async { +Future readDotPackagesFile( + File file, void onError(Object error)) async { Uint8List bytes; try { bytes = await file.readAsBytes(); - } catch (_) { - return null; + } catch (error) { + onError(error); + return const SimplePackageConfig.empty(); } - return packages_file.parse(bytes, file.uri); + return packages_file.parse(bytes, file.uri, onError); } -PackageConfig parsePackageConfigBytes(Uint8List bytes, Uri file) { +final _jsonUtf8Decoder = json.fuse(utf8).decoder; + +PackageConfig parsePackageConfigBytes( + Uint8List bytes, Uri file, void onError(Object error)) { // TODO(lrn): Make this simpler. Maybe parse directly from bytes. - return parsePackageConfigJson(json.fuse(utf8).decode(bytes), file); + var jsonObject; + try { + jsonObject = _jsonUtf8Decoder.convert(bytes); + } on FormatException catch (e) { + onError(PackageConfigFormatException(e.message, e.source, e.offset)); + return const SimplePackageConfig.empty(); + } + return parsePackageConfigJson(jsonObject, file, onError); } /// Creates a [PackageConfig] from a parsed JSON-like object structure. @@ -144,7 +186,8 @@ PackageConfig parsePackageConfigBytes(Uint8List bytes, Uri file) { /// /// The [baseLocation] is used as base URI to resolve the "rootUri" /// URI referencestring. -PackageConfig parsePackageConfigJson(dynamic json, Uri baseLocation) { +PackageConfig parsePackageConfigJson( + dynamic json, Uri baseLocation, void onError(Object error)) { if (!baseLocation.hasScheme || baseLocation.isScheme("package")) { throw PackageConfigArgumentError(baseLocation.toString(), "baseLocation", "Must be an absolute non-package: URI"); @@ -168,27 +211,34 @@ PackageConfig parsePackageConfigJson(dynamic json, Uri baseLocation) { var message = "$name${packageName != null ? " of package $packageName" : ""}" " is not a JSON ${typeName()}"; - throw PackageConfigFormatException(message, value); + onError(PackageConfigFormatException(message, value)); + return null; } - Package parsePackage(Map entry) { + Package /*?*/ parsePackage(Map entry) { String /*?*/ name; String /*?*/ rootUri; String /*?*/ packageUri; String /*?*/ languageVersion; Map /*?*/ extraData; + bool hasName = false; + bool hasRoot = false; + bool hasVersion = false; entry.forEach((key, value) { switch (key) { case _nameKey: + hasName = true; name = checkType(value, _nameKey); break; case _rootUriKey: + hasRoot = true; rootUri = checkType(value, _rootUriKey, name); break; case _packageUriKey: packageUri = checkType(value, _packageUriKey, name); break; case _languageVersionKey: + hasVersion = true; languageVersion = checkType(value, _languageVersionKey, name); break; default: @@ -196,37 +246,61 @@ PackageConfig parsePackageConfigJson(dynamic json, Uri baseLocation) { break; } }); - if (name == null) { - throw PackageConfigFormatException("Missing name entry", entry); + if (!hasName) { + onError(PackageConfigFormatException("Missing name entry", entry)); } - if (rootUri == null) { - throw PackageConfigFormatException("Missing rootUri entry", entry); + if (!hasRoot) { + onError(PackageConfigFormatException("Missing rootUri entry", entry)); } + if (name == null || rootUri == null) return null; Uri root = baseLocation.resolve(rootUri); - Uri /*?*/ packageRoot = root; + if (!root.path.endsWith("/")) root = root.replace(path: root.path + "/"); + Uri packageRoot = root; if (packageUri != null) packageRoot = root.resolve(packageUri); - try { - return SimplePackage(name, root, packageRoot, languageVersion, extraData); - } on ArgumentError catch (e) { - throw PackageConfigFormatException(e.message, e.invalidValue); + if (!packageRoot.path.endsWith("/")) { + packageRoot = packageRoot.replace(path: packageRoot.path + "/"); + } + + LanguageVersion /*?*/ version; + if (languageVersion != null) { + version = parseLanguageVersion(languageVersion, onError); + } else if (hasVersion) { + version = SimpleInvalidLanguageVersion("invalid"); } + + return SimplePackage.validate(name, root, packageRoot, version, extraData, + (error) { + if (error is ArgumentError) { + onError( + PackageConfigFormatException(error.message, error.invalidValue)); + } else { + onError(error); + } + }); } var map = checkType>(json, "value"); + if (map == null) return const SimplePackageConfig.empty(); Map /*?*/ extraData = null; List /*?*/ packageList; int /*?*/ configVersion; map.forEach((key, value) { switch (key) { case _configVersionKey: - configVersion = checkType(value, _configVersionKey); + configVersion = checkType(value, _configVersionKey) ?? 2; break; case _packagesKey: - var packageArray = checkType>(value, _packagesKey); + var packageArray = checkType>(value, _packagesKey) ?? []; var packages = []; for (var package in packageArray) { - packages.add(parsePackage( - checkType>(package, "package entry"))); + var packageMap = + checkType>(package, "package entry"); + if (packageMap != null) { + var entry = parsePackage(packageMap); + if (entry != null) { + packages.add(entry); + } + } } packageList = packages; break; @@ -236,22 +310,27 @@ PackageConfig parsePackageConfigJson(dynamic json, Uri baseLocation) { } }); if (configVersion == null) { - throw PackageConfigFormatException("Missing configVersion entry", json); + onError(PackageConfigFormatException("Missing configVersion entry", json)); + configVersion = 2; } - if (packageList == null) - throw PackageConfigFormatException("Missing packages list", json); - try { - return SimplePackageConfig(configVersion, packageList, extraData); - } on ArgumentError catch (e) { - throw PackageConfigFormatException(e.message, e.invalidValue); + if (packageList == null) { + onError(PackageConfigFormatException("Missing packages list", json)); + packageList = []; } + return SimplePackageConfig(configVersion, packageList, extraData, (error) { + if (error is ArgumentError) { + onError(PackageConfigFormatException(error.message, error.invalidValue)); + } else { + onError(error); + } + }); } Future writePackageConfigJson( PackageConfig config, Directory targetDirectory) async { // Write .dart_tool/package_config.json first. var file = - File(p.join(targetDirectory.path, ".dart_tool", "package_config.json")); + File(pathJoin(targetDirectory.path, ".dart_tool", "package_config.json")); var baseUri = file.uri; var extraData = config.extraData; var data = { @@ -263,8 +342,9 @@ Future writePackageConfigJson( _rootUriKey: relativizeUri(package.root, baseUri), if (package.root != package.packageUriRoot) _packageUriKey: relativizeUri(package.packageUriRoot, package.root), - if (package.languageVersion != null) - _languageVersionKey: package.languageVersion, + if (package.languageVersion != null && + package.languageVersion is! InvalidLanguageVersion) + _languageVersionKey: package.languageVersion.toString(), ...?_extractExtraData(package.extraData, _packageNames), } ], @@ -283,7 +363,7 @@ Future writePackageConfigJson( "${generated != null ? " on $generated" : ""}."; } } - file = File(p.join(targetDirectory.path, ".packages")); + file = File(pathJoin(targetDirectory.path, ".packages")); baseUri = file.uri; var buffer = StringBuffer(); packages_file.write(buffer, config, baseUri: baseUri, comment: comment); diff --git a/pkgs/package_config/lib/src/packages_file.dart b/pkgs/package_config/lib/src/packages_file.dart index ac57b4f15..475a782a2 100644 --- a/pkgs/package_config/lib/src/packages_file.dart +++ b/pkgs/package_config/lib/src/packages_file.dart @@ -3,9 +3,8 @@ // BSD-style license that can be found in the LICENSE file. import "package_config_impl.dart"; -import "package:charcode/ascii.dart"; -import "util.dart" show isValidPackageName, relativizeUri; +import "util.dart"; import "errors.dart"; /// Parses a `.packages` file into a [PackageConfig]. @@ -25,16 +24,18 @@ import "errors.dart"; /// Returns a simple package configuration where each package's /// [Package.packageUriRoot] is the same as its [Package.root] /// and it has no [Package.languageVersion]. -PackageConfig parse(List source, Uri baseLocation) { +PackageConfig parse( + List source, Uri baseLocation, void onError(Object error)) { if (baseLocation.isScheme("package")) { - throw PackageConfigArgumentError( - baseLocation, "baseLocation", "Must not be a package: URI"); + onError(PackageConfigArgumentError( + baseLocation, "baseLocation", "Must not be a package: URI")); + return PackageConfig.empty; } int index = 0; List packages = []; Set packageNames = {}; while (index < source.length) { - bool isComment = false; + bool ignoreLine = false; int start = index; int separatorIndex = -1; int end = source.length; @@ -43,10 +44,14 @@ PackageConfig parse(List source, Uri baseLocation) { continue; } if (char == $colon) { - throw PackageConfigFormatException( - "Missing package name", source, index - 1); + onError(PackageConfigFormatException( + "Missing package name", source, index - 1)); + ignoreLine = true; // Ignore if package name is invalid. + } else { + ignoreLine = char == $hash; // Ignore if comment. } - isComment = char == $hash; + int queryStart = -1; + int fragmentStart = -1; while (index < source.length) { char = source[index++]; if (char == $colon && separatorIndex < 0) { @@ -54,40 +59,70 @@ PackageConfig parse(List source, Uri baseLocation) { } else if (char == $cr || char == $lf) { end = index - 1; break; + } else if (char == $question && queryStart < 0 && fragmentStart < 0) { + queryStart = index - 1; + } else if (char == $hash && fragmentStart < 0) { + fragmentStart = index - 1; } } - if (isComment) continue; + if (ignoreLine) continue; if (separatorIndex < 0) { - throw PackageConfigFormatException("No ':' on line", source, index - 1); + onError( + PackageConfigFormatException("No ':' on line", source, index - 1)); + continue; } var packageName = String.fromCharCodes(source, start, separatorIndex); - if (!isValidPackageName(packageName)) { - throw PackageConfigFormatException( - "Not a valid package name", packageName, 0); + int invalidIndex = checkPackageName(packageName); + if (invalidIndex >= 0) { + onError(PackageConfigFormatException( + "Not a valid package name", source, start + invalidIndex)); + continue; + } + if (queryStart >= 0) { + onError(PackageConfigFormatException( + "Location URI must not have query", source, queryStart)); + end = queryStart; + } else if (fragmentStart >= 0) { + onError(PackageConfigFormatException( + "Location URI must not have fragment", source, fragmentStart)); + end = fragmentStart; } var packageValue = String.fromCharCodes(source, separatorIndex + 1, end); - Uri packageLocation = baseLocation.resolve(packageValue); - if (packageLocation.isScheme("package")) { - throw PackageConfigFormatException( - "Package URI as location for package", source, separatorIndex + 1); + Uri packageLocation; + try { + packageLocation = baseLocation.resolve(packageValue); + } on FormatException catch (e) { + onError(PackageConfigFormatException.from(e)); + continue; } - if (packageLocation.hasQuery || packageLocation.hasFragment) { - throw PackageConfigFormatException( - "Location URI must not have query or fragment", source, start); + if (packageLocation.isScheme("package")) { + onError(PackageConfigFormatException( + "Package URI as location for package", source, separatorIndex + 1)); + continue; } if (!packageLocation.path.endsWith('/')) { packageLocation = packageLocation.replace(path: packageLocation.path + "/"); } if (packageNames.contains(packageName)) { - throw PackageConfigFormatException( - "Same package name occured more than once", source, start); + onError(PackageConfigFormatException( + "Same package name occured more than once", source, start)); + continue; + } + var package = SimplePackage.validate( + packageName, packageLocation, packageLocation, null, null, (error) { + if (error is ArgumentError) { + onError(PackageConfigFormatException(error.message, source)); + } else { + onError(error); + } + }); + if (package != null) { + packages.add(package); + packageNames.add(packageName); } - packages.add(SimplePackage( - packageName, packageLocation, packageLocation, null, null)); - packageNames.add(packageName); } - return SimplePackageConfig(1, packages, null); + return SimplePackageConfig(1, packages, null, onError); } /// Writes the configuration to a [StringSink]. @@ -137,7 +172,7 @@ void write(StringSink output, PackageConfig config, } output.write(packageName); output.write(':'); - // If baseUri provided, make uri relative. + // If baseUri is provided, make the URI relative to baseUri. if (baseUri != null) { uri = relativizeUri(uri, baseUri); } diff --git a/pkgs/package_config/lib/src/util.dart b/pkgs/package_config/lib/src/util.dart index 25d7b89e4..2609a2f8a 100644 --- a/pkgs/package_config/lib/src/util.dart +++ b/pkgs/package_config/lib/src/util.dart @@ -8,8 +8,6 @@ library package_config.util; import 'dart:io'; import 'dart:typed_data'; -import "package:charcode/ascii.dart"; - import "errors.dart"; // All ASCII characters that are valid in a package name, with space @@ -46,6 +44,11 @@ int checkPackageName(String string) { } /// Validate that a [Uri] is a valid `package:` URI. +/// +/// Used to validate user input. +/// +/// Returns the package name extracted from the package URI, +/// which is the path segment between `package:` and the first `/`. String checkValidPackageUri(Uri packageUri, String name) { if (packageUri.scheme != "package") { throw PackageConfigArgumentError(packageUri, name, "Not a package: URI"); @@ -100,65 +103,16 @@ String checkValidPackageUri(Uri packageUri, String name) { return packageName; } -/// Checks whether [version] is a valid Dart language version string. -/// -/// The format is (as RegExp) `^(0|[1-9]\d+)\.(0|[1-9]\d+)$`. -/// -/// Returns the position of the first invalid character, or -1 if -/// the string is valid. -/// If the string is terminated early, the result is the length of the string. -int checkValidVersionNumber(String version) { - if (version == null) { - return 0; - } - int index = 0; - int dotsSeen = 0; - outer: - for (;;) { - // Check for numeral. - if (index == version.length) return index; - int char = version.codeUnitAt(index++); - int digit = char ^ 0x30; - if (digit != 0) { - if (digit < 9) { - while (index < version.length) { - char = version.codeUnitAt(index++); - digit = char ^ 0x30; - if (digit < 9) continue; - if (char == 0x2e /*.*/) { - if (dotsSeen > 0) return index - 1; - dotsSeen = 1; - continue outer; - } - return index - 1; - } - if (dotsSeen > 0) return -1; - return index; - } - return index - 1; - } - // Leading zero means numeral is over. - if (index >= version.length) { - if (dotsSeen > 0) return -1; - return index; - } - if (dotsSeen > 0) return index; - char = version.codeUnitAt(index++); - if (char != 0x2e /*.*/) return index - 1; - } -} - /// Checks whether URI is just an absolute directory. /// /// * It must have a scheme. /// * It must not have a query or fragment. -/// * The path must start and end with `/`. +/// * The path must end with `/`. bool isAbsoluteDirectoryUri(Uri uri) { if (uri.hasQuery) return false; if (uri.hasFragment) return false; if (!uri.hasScheme) return false; var path = uri.path; - if (!path.startsWith("/")) return false; if (!path.endsWith("/")) return false; return true; } @@ -302,3 +256,63 @@ Future _httpGet(Uri uri) async { } return result; } + +/// The file name of a path. +/// +/// The file name is everything after the last occurrence of +/// [Platform.pathSeparator]. +String fileName(String path) { + var separator = Platform.pathSeparator; + int lastSeparator = path.lastIndexOf(separator); + if (lastSeparator < 0) return path; + return path.substring(lastSeparator + separator.length); +} + +/// The file name of a path. +/// +/// The file name is everything before the last occurrence of +/// [Platform.pathSeparator]. +String dirName(String path) { + var separator = Platform.pathSeparator; + int lastSeparator = path.lastIndexOf(separator); + if (lastSeparator < 0) return ""; + return path.substring(0, lastSeparator); +} + +/// Join path parts with the [Platform.pathSeparator]. +String pathJoin(String part1, String part2, [String part3]) { + var separator = Platform.pathSeparator; + if (part3 == null) { + return "$part1$separator$part2"; + } + return "$part1$separator$part2$separator$part3"; +} + +/// Join an unknown number of path parts with [Platform.pathSeparator]. +String pathJoinAll(Iterable parts) => + parts.join(Platform.pathSeparator); + +// Character constants used by this package. +/// "Line feed" control character. +const int $lf = 0x0a; + +/// "Carriage return" control character. +const int $cr = 0x0d; + +/// Space character. +const int $space = 0x20; + +/// Character `#`. +const int $hash = 0x23; + +/// Character `.`. +const int $dot = 0x2e; + +/// Character `:`. +const int $colon = 0x3a; + +/// Character `?`. +const int $question = 0x3f; + +/// Character `{`. +const int $lbrace = 0x7b; diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 66aeb7858..7f47d2e2c 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 2.0.0 +version: 3.0.0-dev description: Support for working with Package Configuration files. author: Dart Team homepage: https://github.com/dart-lang/package_config @@ -7,9 +7,5 @@ homepage: https://github.com/dart-lang/package_config environment: sdk: '>=2.7.0 <3.0.0' -dependencies: - charcode: ^1.1.0 - path: ^1.0.0 - dev_dependencies: test: ^1.3.0 diff --git a/pkgs/package_config/test/discovery_test.dart b/pkgs/package_config/test/discovery_test.dart index 3256187d2..23efc6741 100644 --- a/pkgs/package_config/test/discovery_test.dart +++ b/pkgs/package_config/test/discovery_test.dart @@ -114,36 +114,92 @@ main() { expect(config, null); }); - fileTest("invalid .packages", { - ".packages": "not a .packages file", - }, (Directory directory) { - expect(() => findPackageConfig(directory), - throwsA(TypeMatcher())); - }); + group("throws", () { + fileTest("invalid .packages", { + ".packages": "not a .packages file", + }, (Directory directory) { + expect(findPackageConfig(directory), + throwsA(TypeMatcher())); + }); - fileTest("invalid .packages as JSON", { - ".packages": packageConfigFile, - }, (Directory directory) { - expect(() => findPackageConfig(directory), - throwsA(TypeMatcher())); - }); + fileTest("invalid .packages as JSON", { + ".packages": packageConfigFile, + }, (Directory directory) { + expect(findPackageConfig(directory), + throwsA(TypeMatcher())); + }); - fileTest("invalid .packages", { - ".dart_tool": { - "package_config.json": "not a JSON file", - } - }, (Directory directory) { - expect(() => findPackageConfig(directory), - throwsA(TypeMatcher())); + fileTest("invalid .packages", { + ".dart_tool": { + "package_config.json": "not a JSON file", + } + }, (Directory directory) { + expect(findPackageConfig(directory), + throwsA(TypeMatcher())); + }); + + fileTest("invalid .packages as INI", { + ".dart_tool": { + "package_config.json": packagesFile, + } + }, (Directory directory) { + expect(findPackageConfig(directory), + throwsA(TypeMatcher())); + }); }); - fileTest("invalid .packages as INI", { - ".dart_tool": { - "package_config.json": packagesFile, - } - }, (Directory directory) { - expect(() => findPackageConfig(directory), - throwsA(TypeMatcher())); + group("handles error", () { + fileTest("invalid .packages", { + ".packages": "not a .packages file", + }, (Directory directory) async { + bool hadError = false; + await findPackageConfig(directory, + onError: expectAsync1((error) { + hadError = true; + expect(error, isA()); + }, max: -1)); + expect(hadError, true); + }); + + fileTest("invalid .packages as JSON", { + ".packages": packageConfigFile, + }, (Directory directory) async { + bool hadError = false; + await findPackageConfig(directory, + onError: expectAsync1((error) { + hadError = true; + expect(error, isA()); + }, max: -1)); + expect(hadError, true); + }); + + fileTest("invalid package_config not JSON", { + ".dart_tool": { + "package_config.json": "not a JSON file", + } + }, (Directory directory) async { + bool hadError = false; + await findPackageConfig(directory, + onError: expectAsync1((error) { + hadError = true; + expect(error, isA()); + }, max: -1)); + expect(hadError, true); + }); + + fileTest("invalid package config as INI", { + ".dart_tool": { + "package_config.json": packagesFile, + } + }, (Directory directory) async { + bool hadError = false; + await findPackageConfig(directory, + onError: expectAsync1((error) { + hadError = true; + expect(error, isA()); + }, max: -1)); + expect(hadError, true); + }); }); }); @@ -226,6 +282,17 @@ main() { throwsA(TypeMatcher())); }); + fileTest("no config found, handled", {}, (Directory directory) async { + File file = dirFile(directory, "anyname"); + bool hadError = false; + await loadPackageConfig(file, + onError: expectAsync1((error) { + hadError = true; + expect(error, isA()); + }, max: -1)); + expect(hadError, true); + }); + fileTest("specified file syntax error", { "anyname": "syntax error", }, (Directory directory) { diff --git a/pkgs/package_config/test/discovery_uri_test.dart b/pkgs/package_config/test/discovery_uri_test.dart index 8ad428ac0..081ec608f 100644 --- a/pkgs/package_config/test/discovery_uri_test.dart +++ b/pkgs/package_config/test/discovery_uri_test.dart @@ -4,6 +4,8 @@ library package_config.discovery_test; +import 'dart:io'; + import "package:test/test.dart"; import "package:package_config/package_config.dart"; @@ -219,7 +221,20 @@ main() { loaderTest("no config found", {}, (Uri directory, loader) { Uri file = directory.resolve("anyname"); expect(() => loadPackageConfigUri(file, loader: loader), - throwsArgumentError); + throwsA(isA())); + }); + + loaderTest("no config found, handle error", {}, + (Uri directory, loader) async { + Uri file = directory.resolve("anyname"); + bool hadError = false; + await loadPackageConfigUri(file, + loader: loader, + onError: expectAsync1((error) { + hadError = true; + expect(error, isA()); + }, max: -1)); + expect(hadError, true); }); loaderTest("specified file syntax error", { @@ -230,6 +245,20 @@ main() { throwsFormatException); }); + loaderTest("specified file syntax error", { + "anyname": "syntax error", + }, (Uri directory, loader) async { + Uri file = directory.resolve("anyname"); + bool hadError = false; + await loadPackageConfigUri(file, + loader: loader, + onError: expectAsync1((error) { + hadError = true; + expect(error, isA()); + }, max: -1)); + expect(hadError, true); + }); + // Find package_config.json in subdir even if initial file syntax error. loaderTest("specified file syntax error", { "anyname": "syntax error", @@ -246,10 +275,16 @@ main() { // A file starting with `{` is a package_config.json file. loaderTest("file syntax error with {", { ".packages": "{syntax error", - }, (Uri directory, loader) { + }, (Uri directory, loader) async { Uri file = directory.resolve(".packages"); - expect(() => loadPackageConfigUri(file, loader: loader), - throwsFormatException); + var hadError = false; + await loadPackageConfigUri(file, + loader: loader, + onError: expectAsync1((error) { + hadError = true; + expect(error, isA()); + }, max: -1)); + expect(hadError, true); }); }); } diff --git a/pkgs/package_config/test/parse_test.dart b/pkgs/package_config/test/parse_test.dart index 3d1a20e4a..d9430953c 100644 --- a/pkgs/package_config/test/parse_test.dart +++ b/pkgs/package_config/test/parse_test.dart @@ -6,10 +6,13 @@ import "dart:convert"; import "package:test/test.dart"; +import "package:package_config/package_config.dart"; import "package:package_config/src/packages_file.dart" as packages; import "package:package_config/src/package_config_json.dart"; import "src/util.dart"; +void throwError(Object error) => throw error; + void main() { group(".packages", () { test("valid", () { @@ -17,8 +20,8 @@ void main() { "foo:file:///foo/lib/\n" "bar:/bar/lib/\n" "baz:lib/\n"; - var result = packages.parse( - utf8.encode(packagesFile), Uri.parse("file:///tmp/file.dart")); + var result = packages.parse(utf8.encode(packagesFile), + Uri.parse("file:///tmp/file.dart"), throwError); expect(result.version, 1); expect({for (var p in result.packages) p.name}, {"foo", "bar", "baz"}); expect(result.resolve(pkg("foo", "foo.dart")), @@ -37,8 +40,8 @@ void main() { test("valid empty", () { var packagesFile = "# Generated by pub yadda yadda\n"; - var result = - packages.parse(utf8.encode(packagesFile), Uri.file("/tmp/file.dart")); + var result = packages.parse( + utf8.encode(packagesFile), Uri.file("/tmp/file.dart"), throwError); expect(result.version, 1); expect({for (var p in result.packages) p.name}, {}); }); @@ -47,9 +50,18 @@ void main() { var baseFile = Uri.file("/tmp/file.dart"); testThrows(String name, String content) { test(name, () { - expect(() => packages.parse(utf8.encode(content), baseFile), + expect( + () => packages.parse(utf8.encode(content), baseFile, throwError), throwsA(TypeMatcher())); }); + test(name + ", handle error", () { + bool hadError = false; + packages.parse(utf8.encode(content), baseFile, (error) { + hadError = true; + expect(error, isA()); + }); + expect(hadError, true); + }); } testThrows("repeated package name", "foo:lib/\nfoo:lib\n"); @@ -81,12 +93,17 @@ void main() { "name": "bar", "rootUri": "/bar/", "packageUri": "lib/", - "languageVersion": "100.100" + "languageVersion": "9999.9999" }, { "name": "baz", "rootUri": "../", "packageUri": "lib/" + }, + { + "name": "noslash", + "rootUri": "../noslash", + "packageUri": "lib" } ], "generator": "pub", @@ -94,9 +111,10 @@ void main() { } """; var config = parsePackageConfigBytes(utf8.encode(packageConfigFile), - Uri.parse("file:///tmp/.dart_tool/file.dart")); + Uri.parse("file:///tmp/.dart_tool/file.dart"), throwError); expect(config.version, 2); - expect({for (var p in config.packages) p.name}, {"foo", "bar", "baz"}); + expect({for (var p in config.packages) p.name}, + {"foo", "bar", "baz", "noslash"}); expect(config.resolve(pkg("foo", "foo.dart")), Uri.parse("file:///foo/lib/foo.dart")); @@ -109,14 +127,14 @@ void main() { expect(foo, isNotNull); expect(foo.root, Uri.parse("file:///foo/")); expect(foo.packageUriRoot, Uri.parse("file:///foo/lib/")); - expect(foo.languageVersion, "2.5"); + expect(foo.languageVersion, LanguageVersion(2, 5)); expect(foo.extraData, {"nonstandard": true}); var bar = config["bar"]; expect(bar, isNotNull); expect(bar.root, Uri.parse("file:///bar/")); expect(bar.packageUriRoot, Uri.parse("file:///bar/lib/")); - expect(bar.languageVersion, "100.100"); + expect(bar.languageVersion, LanguageVersion(9999, 9999)); expect(bar.extraData, null); var baz = config["baz"]; @@ -125,6 +143,13 @@ void main() { expect(baz.packageUriRoot, Uri.parse("file:///tmp/lib/")); expect(baz.languageVersion, null); + // No slash after root or package root. One is inserted. + var noslash = config["noslash"]; + expect(noslash, isNotNull); + expect(noslash.root, Uri.parse("file:///tmp/noslash/")); + expect(noslash.packageUriRoot, Uri.parse("file:///tmp/noslash/lib/")); + expect(noslash.languageVersion, null); + expect(config.extraData, { "generator": "pub", "other": [42] @@ -146,7 +171,7 @@ void main() { }, { "packageUri": "lib/", - "languageVersion": "100.100", + "languageVersion": "9999.9999", "rootUri": "/bar/", "name": "bar" }, @@ -160,7 +185,7 @@ void main() { } """; var config = parsePackageConfigBytes(utf8.encode(packageConfigFile), - Uri.parse("file:///tmp/.dart_tool/file.dart")); + Uri.parse("file:///tmp/.dart_tool/file.dart"), throwError); expect(config.version, 2); expect({for (var p in config.packages) p.name}, {"foo", "bar", "baz"}); @@ -184,7 +209,7 @@ void main() { var root = '"rootUri":"/foo/"'; test("minimal", () { var config = parsePackageConfigBytes(utf8.encode("{$cfg,$pkgs}"), - Uri.parse("file:///tmp/.dart_tool/file.dart")); + Uri.parse("file:///tmp/.dart_tool/file.dart"), throwError); expect(config.version, 2); expect(config.packages, isEmpty); }); @@ -193,7 +218,8 @@ void main() { // are optional. var config = parsePackageConfigBytes( utf8.encode('{$cfg,"packages":[{$name,$root}]}'), - Uri.parse("file:///tmp/.dart_tool/file.dart")); + Uri.parse("file:///tmp/.dart_tool/file.dart"), + throwError); expect(config.version, 2); expect(config.packages.first.name, "foo"); }); @@ -208,8 +234,8 @@ void main() { {"name": "qux", "rootUri": "/foo/qux/", "packageUri": "lib/"}, ] })); - var config = parsePackageConfigBytes( - configBytes, Uri.parse("file:///tmp/.dart_tool/file.dart")); + var config = parsePackageConfigBytes(configBytes, + Uri.parse("file:///tmp/.dart_tool/file.dart"), throwError); expect(config.version, 2); expect(config.packageOf(Uri.parse("file:///foo/lala/lala.dart")).name, "foo"); @@ -232,12 +258,9 @@ void main() { group("invalid", () { testThrows(String name, String source) { test(name, () { - if (name == "inside lib") { - print(name); - } expect( () => parsePackageConfigBytes(utf8.encode(source), - Uri.parse("file:///tmp/.dart_tool/file.dart")), + Uri.parse("file:///tmp/.dart_tool/file.dart"), throwError), throwsA(TypeMatcher())); }); } diff --git a/pkgs/package_config/test/src/util.dart b/pkgs/package_config/test/src/util.dart index ec4e5e8bc..95670bdbb 100644 --- a/pkgs/package_config/test/src/util.dart +++ b/pkgs/package_config/test/src/util.dart @@ -6,8 +6,8 @@ import 'dart:convert'; import "dart:io"; import 'dart:typed_data'; -import "package:path/path.dart" as path; import "package:test/test.dart"; +import "package:package_config/src/util.dart"; /// Creates a directory structure from [description] and runs [fileTest]. /// @@ -46,7 +46,7 @@ Directory createTestFiles(Map description) { // Creates temporary files in the target directory. void _createFiles(Directory target, Map description) { description.forEach((name, content) { - var entryName = path.join(target.path, "$name"); + var entryName = pathJoin(target.path, "$name"); if (content is Map) { _createFiles(Directory(entryName)..createSync(), content); } else { @@ -57,11 +57,11 @@ void _createFiles(Directory target, Map description) { /// Creates a [Directory] for a subdirectory of [parent]. Directory subdir(Directory parent, String dirName) => - Directory(path.joinAll([parent.path, ...dirName.split("/")])); + Directory(pathJoinAll([parent.path, ...dirName.split("/")])); /// Creates a [File] for an entry in the [directory] directory. File dirFile(Directory directory, String fileName) => - File(path.join(directory.path, fileName)); + File(pathJoin(directory.path, fileName)); /// Creates a package: URI. Uri pkg(String packageName, String packagePath) { From 917abca9660d8e75ffda2cb5f2f3e0d0648fef4c Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Tue, 11 Feb 2020 14:28:07 +0100 Subject: [PATCH 083/170] Fix doc and bug in util.dart --- pkgs/package_config/lib/src/util.dart | 34 ++++++++++++++++++++------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/pkgs/package_config/lib/src/util.dart b/pkgs/package_config/lib/src/util.dart index 2609a2f8a..f39027d00 100644 --- a/pkgs/package_config/lib/src/util.dart +++ b/pkgs/package_config/lib/src/util.dart @@ -260,7 +260,8 @@ Future _httpGet(Uri uri) async { /// The file name of a path. /// /// The file name is everything after the last occurrence of -/// [Platform.pathSeparator]. +/// [Platform.pathSeparator], or the entire string if no +/// path separator occurs in the string. String fileName(String path) { var separator = Platform.pathSeparator; int lastSeparator = path.lastIndexOf(separator); @@ -268,10 +269,11 @@ String fileName(String path) { return path.substring(lastSeparator + separator.length); } -/// The file name of a path. +/// The directory name of a path. /// -/// The file name is everything before the last occurrence of -/// [Platform.pathSeparator]. +/// The directory name is everything before the last occurrence of +/// [Platform.pathSeparator], or the empty string if no +/// path separator occurs in the string. String dirName(String path) { var separator = Platform.pathSeparator; int lastSeparator = path.lastIndexOf(separator); @@ -280,17 +282,33 @@ String dirName(String path) { } /// Join path parts with the [Platform.pathSeparator]. +/// +/// If a part ends with a path separator, then no extra separator is +/// inserted. String pathJoin(String part1, String part2, [String part3]) { var separator = Platform.pathSeparator; + String separator1 = part1.endsWith(separator) ? "" : separator; if (part3 == null) { - return "$part1$separator$part2"; + return "$part1$separator1$part2"; } - return "$part1$separator$part2$separator$part3"; + String separator2 = part2.endsWith(separator) ? "" : separator; + return "$part1$separator1$part2$separator2$part3"; } /// Join an unknown number of path parts with [Platform.pathSeparator]. -String pathJoinAll(Iterable parts) => - parts.join(Platform.pathSeparator); +/// +/// If a part ends with a path separator, then no extra separator is +/// inserted. +String pathJoinAll(Iterable parts) { + var buffer = StringBuffer(); + String separator = ""; + for (var part in parts) { + buffer..write(separator)..write(part); + separator = + part.endsWith(Platform.pathSeparator) ? "" : Platform.pathSeparator; + } + return buffer.toString(); +} // Character constants used by this package. /// "Line feed" control character. From 0117f2517cb08173b4712f0eb937c629e111c02e Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Fri, 21 Feb 2020 09:36:22 +0100 Subject: [PATCH 084/170] Support the new package_config.json file format. Add support for new format. Retains, but deprecates, the existing functionality. A later 2.0 release will remove support for the old file format. --- pkgs/package_config/CHANGELOG.md | 16 +- pkgs/package_config/README.md | 13 + pkgs/package_config/analysis_options.yaml | 11 + pkgs/package_config/lib/discovery.dart | 227 ++++++++++++ .../lib/discovery_analysis.dart | 167 +++++++++ pkgs/package_config/lib/package_config.dart | 10 +- .../lib/package_config_types.dart | 11 + pkgs/package_config/lib/packages.dart | 96 +++++ pkgs/package_config/lib/packages_file.dart | 232 +++++++++++++ pkgs/package_config/lib/src/discovery.dart | 2 + .../lib/src/package_config.dart | 109 +++++- .../lib/src/package_config_impl.dart | 64 +++- .../lib/src/package_config_io.dart | 155 +++++++++ .../lib/src/package_config_json.dart | 220 ++++-------- .../package_config/lib/src/packages_file.dart | 22 +- .../package_config/lib/src/packages_impl.dart | 128 +++++++ .../lib/src/packages_io_impl.dart | 46 +++ pkgs/package_config/lib/src/util.dart | 49 +-- pkgs/package_config/pubspec.yaml | 6 +- pkgs/package_config/test/discovery_test.dart | 64 ++-- .../test/discovery_uri_test.dart | 60 ++-- pkgs/package_config/test/legacy/all.dart | 20 ++ .../test/legacy/discovery_analysis_test.dart | 127 +++++++ .../test/legacy/discovery_test.dart | 328 ++++++++++++++++++ .../test/legacy/parse_test.dart | 246 +++++++++++++ .../test/legacy/parse_write_test.dart | 133 +++++++ pkgs/package_config/test/parse_test.dart | 85 ++++- pkgs/package_config/test/src/util.dart | 8 +- 28 files changed, 2340 insertions(+), 315 deletions(-) create mode 100644 pkgs/package_config/analysis_options.yaml create mode 100644 pkgs/package_config/lib/discovery.dart create mode 100644 pkgs/package_config/lib/discovery_analysis.dart create mode 100644 pkgs/package_config/lib/package_config_types.dart create mode 100644 pkgs/package_config/lib/packages.dart create mode 100644 pkgs/package_config/lib/packages_file.dart create mode 100644 pkgs/package_config/lib/src/package_config_io.dart create mode 100644 pkgs/package_config/lib/src/packages_impl.dart create mode 100644 pkgs/package_config/lib/src/packages_io_impl.dart create mode 100644 pkgs/package_config/test/legacy/all.dart create mode 100644 pkgs/package_config/test/legacy/discovery_analysis_test.dart create mode 100644 pkgs/package_config/test/legacy/discovery_test.dart create mode 100644 pkgs/package_config/test/legacy/parse_test.dart create mode 100644 pkgs/package_config/test/legacy/parse_write_test.dart diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index 317184075..c6caf4d6e 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -1,17 +1,9 @@ -## 3.0.0 - -- Make the language version be represented as a `LanguageVersion` class - instead of a string. -- Made error handling interceptable. Passing an `onError` handler - makes the parsers attempt to do a best-effort error correction after - detecting an error. -- Do not require root URIs to have paths starting with `/`. That - only makes sense for `file` or `http`, and they enforce it anyway. -- Fixed bug in language version validation not accepting the digit `9`. - -## 2.0.0 +## 1.9.0 - Based on new JSON file format with more content. +- This version includes all the new functionality intended for a 2.0.0 + version, as well as the, now deprecated, version 1 functionality. + When we release 2.0.0, the deprectated functionality will be removed. ## 1.2.0 diff --git a/pkgs/package_config/README.md b/pkgs/package_config/README.md index 45791aaf3..ec51f6ea7 100644 --- a/pkgs/package_config/README.md +++ b/pkgs/package_config/README.md @@ -3,6 +3,19 @@ Support for working with **Package Configuration** files as described in the Package Configuration v2 [design document](https://github.com/dart-lang/language/blob/master/accepted/future-releases/language-versioning/package-config-file-v2.md). +The primary libraries are +* `package_config.dart`: + Defines the `PackageConfig` class and other types needed to use + package configurations. + +* `package_config_discovery.dart`: + Provides functions for reading configurations from files, + and writing them back out. + +The package includes deprecated backwards compatible functionality to +work with the `.packages` file. This functionality will not be maintained, +and will be removed in a future version of this package. + [![Build Status](https://travis-ci.org/dart-lang/package_config.svg?branch=master)](https://travis-ci.org/dart-lang/package_config) [![pub package](https://img.shields.io/pub/v/package_config.svg)](https://pub.dartlang.org/packages/package_config) ## Features and bugs diff --git a/pkgs/package_config/analysis_options.yaml b/pkgs/package_config/analysis_options.yaml new file mode 100644 index 000000000..82c00e5c8 --- /dev/null +++ b/pkgs/package_config/analysis_options.yaml @@ -0,0 +1,11 @@ +# Copyright (c) 2020, 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. + +include: package:pedantic/analysis_options.yaml +analyzer: + errors: + annotate_overrides: ignore + curly_braces_in_flow_control_structures: ignore + prefer_single_quotes: ignore + use_function_type_syntax_for_parameters: ignore diff --git a/pkgs/package_config/lib/discovery.dart b/pkgs/package_config/lib/discovery.dart new file mode 100644 index 000000000..a2f53c0e6 --- /dev/null +++ b/pkgs/package_config/lib/discovery.dart @@ -0,0 +1,227 @@ +// Copyright (c) 2015, 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. + +@Deprecated("Use the package_config.json based API") +library package_config.discovery; + +import "dart:async"; +import "dart:io"; +import "dart:typed_data" show Uint8List; + +import "package:path/path.dart" as path; + +import "packages.dart"; +import "packages_file.dart" as pkgfile show parse; +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 loadPackagesFile(Uri packagesFile, + {Future> loader(Uri uri)}) async { + Packages parseBytes(List bytes) { + return MapPackages(pkgfile.parse(bytes, packagesFile)); + } + + if (packagesFile.scheme == "file") { + return parseBytes(await File.fromUri(packagesFile).readAsBytes()); + } + if (loader == null) { + return parseBytes(await _httpGet(packagesFile)); + } + return parseBytes(await loader(packagesFile)); +} + +/// 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") { + return FilePackagesDirectoryPackages(Directory.fromUri(packagesDir)); + } + if (!packagesDir.path.endsWith('/')) { + packagesDir = packagesDir.replace(path: packagesDir.path + '/'); + } + return NonFilePackagesDirectoryPackages(packagesDir); +} + +/// Discover the package configuration for a Dart script. +/// +/// The [baseUri] points to either the Dart script or its directory. +/// A package resolution strategy is found by going through the following steps, +/// and stopping when something is found. +/// +/// * Check if a `.packages` file exists in the same directory. +/// * If `baseUri`'s scheme is not `file`, then assume a `packages` directory +/// in the same directory, and resolve packages relative to that. +/// * If `baseUri`'s scheme *is* `file`: +/// * Check if a `packages` directory exists. +/// * Otherwise check each successive parent directory of `baseUri` for a +/// `.packages` file. +/// +/// If any of these tests succeed, a `Packages` class is returned. +/// Returns the constant [noPackages] if no resolution strategy is found. +/// +/// This function currently only supports `file`, `http` and `https` URIs. +/// It needs to be able to load a `.packages` file from the URI, so only +/// recognized schemes are accepted. +/// +/// 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 findPackages(Uri baseUri, + {Future> loader(Uri unsupportedUri)}) { + if (baseUri.scheme == "file") { + return Future.sync(() => findPackagesFromFile(baseUri)); + } else if (loader != null) { + return findPackagesFromNonFile(baseUri, loader: loader); + } else if (baseUri.scheme == "http" || baseUri.scheme == "https") { + return findPackagesFromNonFile(baseUri, loader: _httpGet); + } else { + return Future.value(Packages.noPackages); + } +} + +/// Find the location of the package resolution file/directory for a Dart file. +/// +/// Checks for a `.packages` file in the [workingDirectory]. +/// If not found, checks for a `packages` directory in the same directory. +/// If still not found, starts checking parent directories for +/// `.packages` until reaching the root directory. +/// +/// Returns a [File] object of a `.packages` file if one is found, or a +/// [Directory] object for the `packages/` directory if that is found. +FileSystemEntity _findPackagesFile(String workingDirectory) { + var dir = Directory(workingDirectory); + if (!dir.isAbsolute) dir = dir.absolute; + if (!dir.existsSync()) { + throw ArgumentError.value( + workingDirectory, "workingDirectory", "Directory does not exist."); + } + File checkForConfigFile(Directory directory) { + assert(directory.isAbsolute); + var file = File(path.join(directory.path, ".packages")); + if (file.existsSync()) return file; + return null; + } + + // Check for $cwd/.packages + var packagesCfgFile = checkForConfigFile(dir); + if (packagesCfgFile != null) return packagesCfgFile; + // Check for $cwd/packages/ + var packagesDir = Directory(path.join(dir.path, "packages")); + if (packagesDir.existsSync()) return packagesDir; + // Check for cwd(/..)+/.packages + var parentDir = dir.parent; + while (parentDir.path != dir.path) { + packagesCfgFile = checkForConfigFile(parentDir); + if (packagesCfgFile != null) break; + dir = parentDir; + parentDir = dir.parent; + } + return packagesCfgFile; +} + +/// Finds a package resolution strategy for a local Dart script. +/// +/// The [fileBaseUri] points to either a Dart script or the directory of the +/// script. The `fileBaseUri` must be a `file:` URI. +/// +/// This function first tries to locate a `.packages` file in the `fileBaseUri` +/// directory. If that is not found, it instead checks for the presence of +/// a `packages/` directory in the same place. +/// If that also fails, it starts checking parent directories for a `.packages` +/// file, and stops if it finds it. +/// Otherwise it gives up and returns [Packages.noPackages]. +Packages findPackagesFromFile(Uri fileBaseUri) { + var baseDirectoryUri = fileBaseUri; + if (!fileBaseUri.path.endsWith('/')) { + baseDirectoryUri = baseDirectoryUri.resolve("."); + } + var baseDirectoryPath = baseDirectoryUri.toFilePath(); + var location = _findPackagesFile(baseDirectoryPath); + if (location == null) return Packages.noPackages; + if (location is File) { + var fileBytes = location.readAsBytesSync(); + var map = pkgfile.parse(fileBytes, Uri.file(location.path)); + return MapPackages(map); + } + assert(location is Directory); + return FilePackagesDirectoryPackages(location); +} + +/// Finds a package resolution strategy for a Dart script. +/// +/// The [nonFileUri] points to either a Dart script or the directory of the +/// script. +/// The [nonFileUri] should not be a `file:` URI since the algorithm for +/// finding a package resolution strategy is more elaborate for `file:` URIs. +/// In that case, use [findPackagesFromFile]. +/// +/// This function first tries to locate a `.packages` file in the [nonFileUri] +/// directory. If that is not found, it instead assumes a `packages/` directory +/// in the same place. +/// +/// By default, this function only works for `http:` and `https:` URIs. +/// To support other schemes, a loader must be provided, which is used to +/// try to load the `.packages` file. The loader should return the contents +/// of the requested `.packages` file as bytes, which will be assumed to be +/// UTF-8 encoded. +Future findPackagesFromNonFile(Uri nonFileUri, + {Future> loader(Uri name)}) async { + loader ??= _httpGet; + var packagesFileUri = nonFileUri.resolve(".packages"); + + try { + var fileBytes = await loader(packagesFileUri); + var map = pkgfile.parse(fileBytes, packagesFileUri); + return MapPackages(map); + } catch (_) { + // Didn't manage to load ".packages". Assume a "packages/" directory. + var packagesDirectoryUri = nonFileUri.resolve("packages/"); + return NonFilePackagesDirectoryPackages(packagesDirectoryUri); + } +} + +/// Fetches a file over http. +Future> _httpGet(Uri uri) async { + var client = HttpClient(); + var request = await client.getUrl(uri); + var response = await request.close(); + if (response.statusCode != HttpStatus.ok) { + throw HttpException('${response.statusCode} ${response.reasonPhrase}', + uri: uri); + } + var splitContent = await response.toList(); + var totalLength = 0; + for (var list in splitContent) { + totalLength += list.length; + } + var result = Uint8List(totalLength); + var offset = 0; + for (var contentPart in splitContent) { + result.setRange(offset, offset + contentPart.length, contentPart); + offset += contentPart.length; + } + return result; +} diff --git a/pkgs/package_config/lib/discovery_analysis.dart b/pkgs/package_config/lib/discovery_analysis.dart new file mode 100644 index 000000000..2af07292e --- /dev/null +++ b/pkgs/package_config/lib/discovery_analysis.dart @@ -0,0 +1,167 @@ +// Copyright (c) 2015, 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. + +/// Analyse a directory structure and find packages resolvers for each +/// sub-directory. +/// +/// The resolvers are generally the same that would be found by using +/// the `discovery.dart` library on each sub-directory in turn, +/// but more efficiently and with some heuristics for directories that +/// wouldn't otherwise have a package resolution strategy, or that are +/// determined to be "package directories" themselves. +@Deprecated("Use the package_config.json based API") +library package_config.discovery_analysis; + +import "dart:collection" show HashMap; +import "dart:io" show File, Directory; + +import "package:path/path.dart" as path; + +import "packages.dart"; +import "packages_file.dart" as pkgfile; +import "src/packages_impl.dart"; +import "src/packages_io_impl.dart"; + +/// Associates a [Packages] package resolution strategy with a directory. +/// +/// The package resolution applies to the directory and any sub-directory +/// that doesn't have its own overriding child [PackageContext]. +abstract class PackageContext { + /// The directory that introduced the [packages] resolver. + Directory get directory; + + /// A [Packages] resolver that applies to the directory. + /// + /// Introduced either by a `.packages` file or a `packages/` directory. + Packages get packages; + + /// Child contexts that apply to sub-directories of [directory]. + List get children; + + /// Look up the [PackageContext] that applies to a specific directory. + /// + /// The directory must be inside [directory]. + PackageContext operator [](Directory directory); + + /// A map from directory to package resolver. + /// + /// Has an entry for this package context and for each child context + /// contained in this one. + Map asMap(); + + /// Analyze [directory] and sub-directories for package resolution strategies. + /// + /// Returns a mapping from sub-directories to [Packages] objects. + /// + /// The analysis assumes that there are no `.packages` files in a parent + /// directory of `directory`. If there is, its corresponding `Packages` object + /// should be provided as `root`. + static PackageContext findAll(Directory directory, + {Packages root = Packages.noPackages}) { + if (!directory.existsSync()) { + throw ArgumentError("Directory not found: $directory"); + } + var contexts = []; + void findRoots(Directory directory) { + Packages packages; + List oldContexts; + var packagesFile = File(path.join(directory.path, ".packages")); + if (packagesFile.existsSync()) { + packages = _loadPackagesFile(packagesFile); + oldContexts = contexts; + contexts = []; + } else { + var packagesDir = Directory(path.join(directory.path, "packages")); + if (packagesDir.existsSync()) { + packages = FilePackagesDirectoryPackages(packagesDir); + oldContexts = contexts; + contexts = []; + } + } + for (var entry in directory.listSync()) { + if (entry is Directory) { + if (packages == null || !entry.path.endsWith("/packages")) { + findRoots(entry); + } + } + } + if (packages != null) { + oldContexts.add(_PackageContext(directory, packages, contexts)); + contexts = oldContexts; + } + } + + findRoots(directory); + // If the root is not itself context root, add a the wrapper context. + if (contexts.length == 1 && contexts[0].directory == directory) { + return contexts[0]; + } + return _PackageContext(directory, root, contexts); + } +} + +class _PackageContext implements PackageContext { + final Directory directory; + final Packages packages; + final List children; + _PackageContext(this.directory, this.packages, List children) + : children = List.unmodifiable(children); + + Map asMap() { + var result = HashMap(); + void recurse(_PackageContext current) { + result[current.directory] = current.packages; + for (var child in current.children) { + recurse(child); + } + } + + recurse(this); + return result; + } + + PackageContext operator [](Directory directory) { + var path = directory.path; + if (!path.startsWith(this.directory.path)) { + throw ArgumentError("Not inside $path: $directory"); + } + var current = this; + // The current path is know to agree with directory until deltaIndex. + var deltaIndex = current.directory.path.length; + List children = current.children; + var i = 0; + while (i < children.length) { + // TODO(lrn): Sort children and use binary search. + _PackageContext child = children[i]; + var childPath = child.directory.path; + if (_stringsAgree(path, childPath, deltaIndex, childPath.length)) { + deltaIndex = childPath.length; + if (deltaIndex == path.length) { + return child; + } + current = child; + children = current.children; + i = 0; + continue; + } + i++; + } + return current; + } + + static bool _stringsAgree(String a, String b, int start, int end) { + if (a.length < end || b.length < end) return false; + for (var i = start; i < end; i++) { + if (a.codeUnitAt(i) != b.codeUnitAt(i)) return false; + } + return true; + } +} + +Packages _loadPackagesFile(File file) { + var uri = Uri.file(file.path); + var bytes = file.readAsBytesSync(); + var map = pkgfile.parse(bytes, uri); + return MapPackages(map); +} diff --git a/pkgs/package_config/lib/package_config.dart b/pkgs/package_config/lib/package_config.dart index 98b31f1f9..bca865d70 100644 --- a/pkgs/package_config/lib/package_config.dart +++ b/pkgs/package_config/lib/package_config.dart @@ -4,7 +4,7 @@ /// A package configuration is a way to assign file paths to package URIs, /// and vice-versa, -library package_config.package_config; +library package_config.package_config_discovery; import "dart:io" show File, Directory; import "dart:typed_data" show Uint8List; @@ -12,11 +12,9 @@ import "dart:typed_data" show Uint8List; import "src/discovery.dart" as discover; import "src/errors.dart" show throwError; import "src/package_config.dart"; -import "src/package_config_json.dart"; +import "src/package_config_io.dart"; -export "src/package_config.dart" - show PackageConfig, Package, LanguageVersion, InvalidLanguageVersion; -export "src/errors.dart" show PackageConfigError; +export "package_config_types.dart"; /// Reads a specific package configuration file. /// @@ -173,4 +171,4 @@ Future findPackageConfigUri(Uri location, /// `"generator"` entry. Future savePackageConfig( PackageConfig configuration, Directory directory) => - writePackageConfigJson(configuration, directory); + writePackageConfigJsonFile(configuration, directory); diff --git a/pkgs/package_config/lib/package_config_types.dart b/pkgs/package_config/lib/package_config_types.dart new file mode 100644 index 000000000..f0637b11b --- /dev/null +++ b/pkgs/package_config/lib/package_config_types.dart @@ -0,0 +1,11 @@ +// Copyright (c) 2019, 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. + +/// A package configuration is a way to assign file paths to package URIs, +/// and vice-versa, +library package_config.package_config; + +export "src/package_config.dart" + show PackageConfig, Package, LanguageVersion, InvalidLanguageVersion; +export "src/errors.dart" show PackageConfigError; diff --git a/pkgs/package_config/lib/packages.dart b/pkgs/package_config/lib/packages.dart new file mode 100644 index 000000000..203f32fdb --- /dev/null +++ b/pkgs/package_config/lib/packages.dart @@ -0,0 +1,96 @@ +// Copyright (c) 2015, 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. + +@Deprecated("Use the package_config.json based API") +library package_config.packages; + +import "src/packages_impl.dart"; + +/// A package resolution strategy. +/// +/// Allows converting a `package:` URI to a different kind of URI. +/// +/// May also allow listing the available packages and converting +/// to a `Map` that gives the base location of each available +/// package. In some cases there is no way to find the available packages, +/// in which case [packages] and [asMap] will throw if used. +/// One such case is if the packages are resolved relative to a +/// `packages/` directory available over HTTP. +@Deprecated("Use the package_config.json based API") +abstract class Packages { + /// A [Packages] resolver containing no packages. + /// + /// This constant object is returned by [find] above if no + /// package resolution strategy is found. + static const Packages noPackages = NoPackages(); + + /// Resolve a package URI into a non-package URI. + /// + /// Translates a `package:` URI, according to the package resolution + /// strategy, into a URI that can be loaded. + /// By default, only `file`, `http` and `https` URIs are returned. + /// Custom `Packages` objects may return other URIs. + /// + /// If resolution fails because a package with the requested package name + /// is not available, the [notFound] function is called. + /// If no `notFound` function is provided, it defaults to throwing an error. + /// + /// The [packageUri] must be a valid package URI. + Uri resolve(Uri packageUri, {Uri notFound(Uri packageUri)}); + + /// Return the names of the available packages. + /// + /// Returns an iterable that allows iterating the names of available packages. + /// + /// Some `Packages` objects are unable to find the package names, + /// and getting `packages` from such a `Packages` object will throw. + Iterable get packages; + + /// Retrieve metadata associated with a package. + /// + /// Metadata have string keys and values, and are looked up by key. + /// + /// Returns `null` if the argument is not a valid package name, + /// or if the package is not one of the packages configured by + /// this packages object, or if the package does not have associated + /// metadata with the provided [key]. + /// + /// Not all `Packages` objects can support metadata. + /// Those will always return `null`. + String packageMetadata(String packageName, String key); + + /// Retrieve metadata associated with a library. + /// + /// If [libraryUri] is a `package:` URI, the returned value + /// is the same that would be returned by [packageMetadata] with + /// the package's name and the same key. + /// + /// If [libraryUri] is not a `package:` URI, and this [Packages] + /// object has a [defaultPackageName], then the [key] is looked + /// up on the default package instead. + /// + /// Otherwise the result is `null`. + String libraryMetadata(Uri libraryUri, String key); + + /// Return the names-to-base-URI mapping of the available packages. + /// + /// Returns a map from package name to a base URI. + /// The [resolve] method will resolve a package URI with a specific package + /// name to a path extending the base URI that this map gives for that + /// package name. + /// + /// Some `Packages` objects are unable to find the package names, + /// and calling `asMap` on such a `Packages` object will throw. + Map asMap(); + + /// The name of the "default package". + /// + /// A default package is a package that *non-package* libraries + /// may be considered part of for some purposes. + /// + /// The value is `null` if there is no default package. + /// Not all implementations of [Packages] supports a default package, + /// and will always have a `null` value for those. + String get defaultPackageName; +} diff --git a/pkgs/package_config/lib/packages_file.dart b/pkgs/package_config/lib/packages_file.dart new file mode 100644 index 000000000..ef0b0b3ca --- /dev/null +++ b/pkgs/package_config/lib/packages_file.dart @@ -0,0 +1,232 @@ +// Copyright (c) 2015, 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. + +@Deprecated("Use the package_config.json based API") +library package_config.packages_file; + +import "package:charcode/ascii.dart"; + +import "src/util.dart" show isValidPackageName; + +/// Parses a `.packages` file into a map from package name to base URI. +/// +/// The [source] is the byte content of a `.packages` file, assumed to be +/// UTF-8 encoded. In practice, all significant parts of the file must be ASCII, +/// so Latin-1 or Windows-1252 encoding will also work fine. +/// +/// If the file content is available as a string, its [String.codeUnits] can +/// be used as the `source` argument of this function. +/// +/// The [baseLocation] is used as a base URI to resolve all relative +/// URI references against. +/// If the content was read from a file, `baseLocation` should be the +/// location of that file. +/// +/// If [allowDefaultPackage] is set to true, an entry with an empty package name +/// is accepted. This entry does not correspond to a package, but instead +/// represents a *default package* which non-package libraries may be considered +/// part of in some cases. The value of that entry must be a valid package name. +/// +/// Returns a simple mapping from package name to package location. +/// If default package is allowed, the map maps the empty string to the default package's name. +Map parse(List source, Uri baseLocation, + {bool allowDefaultPackage = false}) { + var index = 0; + var result = {}; + while (index < source.length) { + var isComment = false; + var start = index; + var separatorIndex = -1; + var end = source.length; + var char = source[index++]; + if (char == $cr || char == $lf) { + continue; + } + if (char == $colon) { + if (!allowDefaultPackage) { + throw FormatException("Missing package name", source, index - 1); + } + separatorIndex = index - 1; + } + isComment = char == $hash; + while (index < source.length) { + char = source[index++]; + if (char == $colon && separatorIndex < 0) { + separatorIndex = index - 1; + } else if (char == $cr || char == $lf) { + end = index - 1; + break; + } + } + if (isComment) continue; + if (separatorIndex < 0) { + throw FormatException("No ':' on line", source, index - 1); + } + var packageName = String.fromCharCodes(source, start, separatorIndex); + if (packageName.isEmpty + ? !allowDefaultPackage + : !isValidPackageName(packageName)) { + throw FormatException("Not a valid package name", packageName, 0); + } + var packageValue = String.fromCharCodes(source, separatorIndex + 1, end); + Uri packageLocation; + if (packageName.isEmpty) { + if (!isValidPackageName(packageValue)) { + throw FormatException( + "Default package entry value is not a valid package name"); + } + packageLocation = Uri(path: packageValue); + } else { + packageLocation = baseLocation.resolve(packageValue); + if (!packageLocation.path.endsWith('/')) { + packageLocation = + packageLocation.replace(path: packageLocation.path + "/"); + } + } + if (result.containsKey(packageName)) { + if (packageName.isEmpty) { + throw FormatException( + "More than one default package entry", source, start); + } + throw FormatException("Same package name occured twice", source, start); + } + result[packageName] = packageLocation; + } + return result; +} + +/// Writes the mapping to a [StringSink]. +/// +/// If [comment] is provided, the output will contain this comment +/// with `# ` in front of each line. +/// Lines are defined as ending in line feed (`'\n'`). If the final +/// line of the comment doesn't end in a line feed, one will be added. +/// +/// If [baseUri] is provided, package locations will be made relative +/// to the base URI, if possible, before writing. +/// +/// If [allowDefaultPackage] is `true`, the [packageMapping] may contain an +/// empty string mapping to the _default package name_. +/// +/// All the keys of [packageMapping] must be valid package names, +/// and the values must be URIs that do not have the `package:` scheme. +void write(StringSink output, Map packageMapping, + {Uri baseUri, String comment, bool allowDefaultPackage = false}) { + ArgumentError.checkNotNull(allowDefaultPackage, 'allowDefaultPackage'); + + if (baseUri != null && !baseUri.isAbsolute) { + throw ArgumentError.value(baseUri, "baseUri", "Must be absolute"); + } + + if (comment != null) { + var lines = comment.split('\n'); + if (lines.last.isEmpty) lines.removeLast(); + for (var commentLine in lines) { + output.write('# '); + output.writeln(commentLine); + } + } else { + output.write("# generated by package:package_config at "); + output.write(DateTime.now()); + output.writeln(); + } + + packageMapping.forEach((String packageName, Uri uri) { + // If [packageName] is empty then [uri] is the _default package name_. + if (allowDefaultPackage && packageName.isEmpty) { + final defaultPackageName = uri.toString(); + if (!isValidPackageName(defaultPackageName)) { + throw ArgumentError.value( + defaultPackageName, + 'defaultPackageName', + '"$defaultPackageName" is not a valid package name', + ); + } + output.write(':'); + output.write(defaultPackageName); + output.writeln(); + return; + } + // Validate packageName. + if (!isValidPackageName(packageName)) { + throw ArgumentError('"$packageName" is not a valid package name'); + } + if (uri.scheme == "package") { + throw ArgumentError.value( + "Package location must not be a package: URI", uri.toString()); + } + output.write(packageName); + output.write(':'); + // If baseUri provided, make uri relative. + if (baseUri != null) { + uri = _relativize(uri, baseUri); + } + if (!uri.path.endsWith('/')) { + uri = uri.replace(path: uri.path + '/'); + } + output.write(uri); + output.writeln(); + }); +} + +/// Attempts to return a relative URI for [uri]. +/// +/// The result URI satisfies `baseUri.resolveUri(result) == uri`, +/// but may be relative. +/// The `baseUri` must be absolute. +Uri _relativize(Uri uri, Uri baseUri) { + assert(baseUri.isAbsolute); + if (uri.hasQuery || uri.hasFragment) { + uri = Uri( + scheme: uri.scheme, + userInfo: uri.hasAuthority ? uri.userInfo : null, + host: uri.hasAuthority ? uri.host : null, + port: uri.hasAuthority ? uri.port : null, + path: uri.path); + } + + // Already relative. We assume the caller knows what they are doing. + if (!uri.isAbsolute) return uri; + + if (baseUri.scheme != uri.scheme) { + return uri; + } + + // If authority differs, we could remove the scheme, but it's not worth it. + if (uri.hasAuthority != baseUri.hasAuthority) return uri; + if (uri.hasAuthority) { + if (uri.userInfo != baseUri.userInfo || + uri.host.toLowerCase() != baseUri.host.toLowerCase() || + uri.port != baseUri.port) { + return uri; + } + } + + baseUri = baseUri.normalizePath(); + var base = baseUri.pathSegments.toList(); + if (base.isNotEmpty) { + base = List.from(base)..removeLast(); + } + uri = uri.normalizePath(); + var target = uri.pathSegments.toList(); + if (target.isNotEmpty && target.last.isEmpty) target.removeLast(); + var index = 0; + while (index < base.length && index < target.length) { + if (base[index] != target[index]) { + break; + } + index++; + } + if (index == base.length) { + if (index == target.length) { + return Uri(path: "./"); + } + return Uri(path: target.skip(index).join('/')); + } else if (index > 0) { + return Uri( + path: '../' * (base.length - index) + target.skip(index).join('/')); + } else { + return uri; + } +} diff --git a/pkgs/package_config/lib/src/discovery.dart b/pkgs/package_config/lib/src/discovery.dart index 14033ed35..5d3172f26 100644 --- a/pkgs/package_config/lib/src/discovery.dart +++ b/pkgs/package_config/lib/src/discovery.dart @@ -5,6 +5,8 @@ import "dart:io"; import 'dart:typed_data'; +import 'package_config_io.dart'; + import "errors.dart"; import "package_config_impl.dart"; import "package_config_json.dart"; diff --git a/pkgs/package_config/lib/src/package_config.dart b/pkgs/package_config/lib/src/package_config.dart index 08c4a9691..364df75b1 100644 --- a/pkgs/package_config/lib/src/package_config.dart +++ b/pkgs/package_config/lib/src/package_config.dart @@ -2,8 +2,11 @@ // 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. +import 'dart:typed_data'; + import 'errors.dart'; import "package_config_impl.dart"; +import 'package_config_json.dart'; /// A package configuration. /// @@ -21,14 +24,27 @@ abstract class PackageConfig { /// A package configuration with no available packages. /// Is used as a default value where a package configuration /// is expected, but none have been specified or found. - static const PackageConfig empty = const SimplePackageConfig.empty(); + static const PackageConfig empty = SimplePackageConfig.empty(); /// Creats a package configuration with the provided available [packages]. /// /// The packages must be valid packages (valid package name, valid /// absolute directory URIs, valid language version, if any), - /// and there must not be two packages with the same name or with - /// overlapping root directories. + /// and there must not be two packages with the same name. + /// + /// The package's root ([Package.rootUri]) and package-root + /// ([Package.packageUriRoot]) paths must satisfy a number of constraints + /// We say that one path (which we know ends with a `/` charater) + /// is inside another path, if the latter path is a prefix of the former path, + /// including the two paths being the same. + /// + /// * No package's root must be the same as another package's root. + /// * The package-root of a package must be inside the pacakge's root. + /// * If one package's package-root is inside another package's root, + /// then the latter package's package root must not be inside the former + /// package's root. (No getting between a package and its package root!) + /// This also disallows a package's root being the same as another + /// package's package root. /// /// If supplied, the [extraData] will be available as the /// [PackageConfig.extraData] of the created configuration. @@ -37,6 +53,93 @@ abstract class PackageConfig { factory PackageConfig(Iterable packages, {dynamic extraData}) => SimplePackageConfig(maxVersion, packages, extraData); + /// Parses a package configuration file. + /// + /// The [bytes] must be an UTF-8 encoded JSON object + /// containing a valid package configuration. + /// + /// The [baseUri] is used as the base for resolving relative + /// URI references in the configuration file. If the configuration + /// has been read from a file, the [baseUri] can be the URI of that + /// file, or of the directory it occurs in. + /// + /// If [onError] is provided, errors found during parsing or building + /// the configuration are reported by calling [onError] instead of + /// throwing, and parser makes a *best effort* attempt to continue + /// despite the error. The input must still be valid JSON. + /// The result may be a [PackageConfig.empty] if there is no way to + /// extract useful information from the bytes. + static PackageConfig parseBytes(Uint8List bytes, Uri baseUri, + {void onError(Object error)}) => + parsePackageConfigBytes(bytes, baseUri, onError ?? throwError); + + /// Parses a package configuration file. + /// + /// The [configuration] must be a JSON object + /// containing a valid package configuration. + /// + /// The [baseUri] is used as the base for resolving relative + /// URI references in the configuration file. If the configuration + /// has been read from a file, the [baseUri] can be the URI of that + /// file, or of the directory it occurs in. + /// + /// If [onError] is provided, errors found during parsing or building + /// the configuration are reported by calling [onError] instead of + /// throwing, and parser makes a *best effort* attempt to continue + /// despite the error. The input must still be valid JSON. + /// The result may be a [PackageConfig.empty] if there is no way to + /// extract useful information from the bytes. + static PackageConfig parseString(String configuration, Uri baseUri, + {void onError(Object error)}) => + parsePackageConfigString(configuration, baseUri, onError ?? throwError); + + /// Parses the JSON data of a package configuration file. + /// + /// The [configuration] must be a JSON-like Dart data structure, + /// like the one provided by parsing JSON text using `dart:convert`, + /// containing a valid package configuration. + /// + /// The [baseUri] is used as the base for resolving relative + /// URI references in the configuration file. If the configuration + /// has been read from a file, the [baseUri] can be the URI of that + /// file, or of the directory it occurs in. + /// + /// If [onError] is provided, errors found during parsing or building + /// the configuration are reported by calling [onError] instead of + /// throwing, and parser makes a *best effort* attempt to continue + /// despite the error. The input must still be valid JSON. + /// The result may be a [PackageConfig.empty] if there is no way to + /// extract useful information from the bytes. + static PackageConfig parseJson(dynamic jsonData, Uri baseUri, + {void onError(Object error)}) => + parsePackageConfigJson(jsonData, baseUri, onError ?? throwError); + + /// Writes a configuration file for this configuration on [output]. + /// + /// If [baseUri] is provided, URI references in the generated file + /// will be made relative to [baseUri] where possible. + static void writeBytes(PackageConfig configuration, Sink output, + [Uri /*?*/ baseUri]) { + writePackageConfigJsonUtf8(configuration, baseUri, output); + } + + /// Writes a configuration JSON text for this configuration on [output]. + /// + /// If [baseUri] is provided, URI references in the generated file + /// will be made relative to [baseUri] where possible. + static void writeString(PackageConfig configuration, StringSink output, + [Uri /*?*/ baseUri]) { + writePackageConfigJsonString(configuration, baseUri, output); + } + + /// Converts a configuration to a JSON-like data structure. + /// + /// If [baseUri] is provided, URI references in the generated data + /// will be made relative to [baseUri] where possible. + static Map toJson(PackageConfig configuration, + [Uri /*?*/ baseUri]) => + packageConfigToJson(configuration, baseUri); + /// The configuration version number. /// /// Currently this is 1 or 2, where diff --git a/pkgs/package_config/lib/src/package_config_impl.dart b/pkgs/package_config/lib/src/package_config_impl.dart index 39633fe4b..f68a9ea75 100644 --- a/pkgs/package_config/lib/src/package_config_impl.dart +++ b/pkgs/package_config/lib/src/package_config_impl.dart @@ -8,6 +8,8 @@ import "util.dart"; export "package_config.dart"; +// Implementations of the main data types exposed by the API of this package. + class SimplePackageConfig implements PackageConfig { final int version; final Map _packages; @@ -90,7 +92,7 @@ class SimplePackageConfig implements PackageConfig { onError(PackageConfigArgumentError( originalPackages, "packages", - "Packages ${package.name} and ${existingPackage.name}" + "Packages ${package.name} and ${existingPackage.name} " "have the same root directory: ${package.root}.\n")); } else { assert(error.isPackageRootConflict); @@ -126,7 +128,7 @@ class SimplePackageConfig implements PackageConfig { Package /*?*/ packageOf(Uri file) => _packageTree.packageOf(file); Uri /*?*/ resolve(Uri packageUri) { - String packageName = checkValidPackageUri(packageUri, "packageUri"); + var packageName = checkValidPackageUri(packageUri, "packageUri"); return _packages[packageName]?.packageUriRoot?.resolveUri( Uri(path: packageUri.path.substring(packageName.length + 1))); } @@ -187,7 +189,7 @@ class SimplePackage implements Package { LanguageVersion /*?*/ languageVersion, dynamic extraData, void onError(Object error)) { - bool fatalError = false; + var fatalError = false; var invalidIndex = checkPackageName(name); if (invalidIndex >= 0) { onError(PackageConfigFormatException( @@ -305,7 +307,7 @@ LanguageVersion parseLanguageVersion( abstract class _SimpleLanguageVersionBase implements LanguageVersion { int compareTo(LanguageVersion other) { - int result = major.compareTo(other.major); + var result = major.compareTo(other.major); if (result != 0) return result; return minor.compareTo(other.minor); } @@ -342,16 +344,32 @@ abstract class PackageTree { /// Packages of a package configuration ordered by root path. /// +/// A package has a root path and a package root path, where the latter +/// contains the files exposed by `package:` URIs. +/// /// A package is said to be inside another package if the root path URI of /// the latter is a prefix of the root path URI of the former. +/// /// No two packages of a package may have the same root path, so this /// path prefix ordering defines a tree-like partial ordering on packages /// of a configuration. /// +/// The package root path of a package must not be inside another package's +/// root path. +/// Entire other packages are allowed inside a package's root or +/// package root path. +/// /// The package tree contains an ordered mapping of unrelated packages /// (represented by their name) to their immediately nested packages' names. class MutablePackageTree implements PackageTree { + /// A list of packages that are not nested inside each other. final List packages = []; + + /// The tree of the immediately nested packages inside each package. + /// + /// Indexed by [Package.name]. + /// If a package has no nested packages (which is most often the case), + /// there is no tree object associated with it. Map /*?*/ _packageChildren; Iterable get allPackages sync* { @@ -365,30 +383,38 @@ class MutablePackageTree implements PackageTree { /// /// Reports a [ConflictException] if the added package conflicts with an /// existing package. - /// It conflicts if it has the same root path, or if the new package - /// contains the existing package's package root. + /// It conflicts if its root or package root is the same as another + /// package's root or package root, or is between the two. /// /// If a conflict is detected between [package] and a previous package, /// then [onError] is called with a [ConflictException] object /// and the [package] is not added to the tree. + /// + /// The packages are added in order of their root path. + /// It is never necessary to insert a node between two existing levels. void add(int start, SimplePackage package, void onError(Object error)) { var path = package.root.toString(); - for (var childPackage in packages) { - var childPath = childPackage.root.toString(); - assert(childPath.length > start); - assert(path.startsWith(childPath.substring(0, start))); - if (_beginsWith(start, childPath, path)) { - var childPathLength = childPath.length; - if (path.length == childPathLength) { - onError(ConflictException.root(package, childPackage)); + for (var treePackage in packages) { + // Check is package is inside treePackage. + var treePackagePath = treePackage.root.toString(); + assert(treePackagePath.length > start); + assert(path.startsWith(treePackagePath.substring(0, start))); + if (_beginsWith(start, treePackagePath, path)) { + // Package *is* inside treePackage. + var treePackagePathLength = treePackagePath.length; + if (path.length == treePackagePathLength) { + // Has same root. Do not add package. + onError(ConflictException.root(package, treePackage)); return; } - var childPackageRoot = childPackage.packageUriRoot.toString(); - if (_beginsWith(childPathLength, childPackageRoot, path)) { - onError(ConflictException.packageRoot(package, childPackage)); + var treePackageUriRoot = treePackage.packageUriRoot.toString(); + if (_beginsWith(treePackagePathLength, path, treePackageUriRoot)) { + // The treePackage's package root is inside package, which is inside + // the treePackage. This is not allowed. + onError(ConflictException.packageRoot(package, treePackage)); return; } - _treeOf(childPackage).add(childPathLength, package, onError); + _treeOf(treePackage).add(treePackagePathLength, package, onError); return; } } @@ -454,7 +480,7 @@ class EmptyPackageTree implements PackageTree { /// already have been matched. bool _beginsWith(int start, String parentPath, String longerPath) { if (longerPath.length < parentPath.length) return false; - for (int i = start; i < parentPath.length; i++) { + for (var i = start; i < parentPath.length; i++) { if (longerPath.codeUnitAt(i) != parentPath.codeUnitAt(i)) return false; } return true; diff --git a/pkgs/package_config/lib/src/package_config_io.dart b/pkgs/package_config/lib/src/package_config_io.dart new file mode 100644 index 000000000..d59972f9a --- /dev/null +++ b/pkgs/package_config/lib/src/package_config_io.dart @@ -0,0 +1,155 @@ +// Copyright (c) 2019, 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:io dependent functionality for reading and writing configuration files. + +import "dart:convert"; +import "dart:io"; +import "dart:typed_data"; + +import "discovery.dart" show packageConfigJsonPath; +import "errors.dart"; +import "package_config_impl.dart"; +import "package_config_json.dart"; +import "packages_file.dart" as packages_file; +import "util.dart"; + +/// Reads a package configuration file. +/// +/// Detects whether the [file] is a version one `.packages` file or +/// a version two `package_config.json` file. +/// +/// If the [file] is a `.packages` file and [preferNewest] is true, +/// first checks whether there is an adjacent `.dart_tool/package_config.json` +/// file, and if so, reads that instead. +/// If [preferNewset] is false, the specified file is loaded even if it is +/// a `.packages` file and there is an available `package_config.json` file. +/// +/// The file must exist and be a normal file. +Future readAnyConfigFile( + File file, bool preferNewest, void onError(Object error)) async { + Uint8List bytes; + try { + bytes = await file.readAsBytes(); + } catch (e) { + onError(e); + return const SimplePackageConfig.empty(); + } + var firstChar = firstNonWhitespaceChar(bytes); + if (firstChar != $lbrace) { + // Definitely not a JSON object, probably a .packages. + if (preferNewest) { + var alternateFile = File( + pathJoin(dirName(file.path), ".dart_tool", "package_config.json")); + if (alternateFile.existsSync()) { + Uint8List /*?*/ bytes; + try { + bytes = await alternateFile.readAsBytes(); + } catch (e) { + onError(e); + return const SimplePackageConfig.empty(); + } + if (bytes != null) { + return parsePackageConfigBytes(bytes, alternateFile.uri, onError); + } + } + } + return packages_file.parse(bytes, file.uri, onError); + } + return parsePackageConfigBytes(bytes, file.uri, onError); +} + +/// Like [readAnyConfigFile] but uses a URI and an optional loader. +Future readAnyConfigFileUri( + Uri file, + Future loader(Uri uri) /*?*/, + void onError(Object error), + bool preferNewest) async { + if (file.isScheme("package")) { + throw PackageConfigArgumentError( + file, "file", "Must not be a package: URI"); + } + if (loader == null) { + if (file.isScheme("file")) { + return readAnyConfigFile(File.fromUri(file), preferNewest, onError); + } + loader = defaultLoader; + } + Uint8List bytes; + try { + bytes = await loader(file); + } catch (e) { + onError(e); + return const SimplePackageConfig.empty(); + } + if (bytes == null) { + onError(PackageConfigArgumentError( + file.toString(), "file", "File cannot be read")); + return const SimplePackageConfig.empty(); + } + var firstChar = firstNonWhitespaceChar(bytes); + if (firstChar != $lbrace) { + // Definitely not a JSON object, probably a .packages. + if (preferNewest) { + // Check if there is a package_config.json file. + var alternateFile = file.resolveUri(packageConfigJsonPath); + Uint8List alternateBytes; + try { + alternateBytes = await loader(alternateFile); + } catch (e) { + onError(e); + return const SimplePackageConfig.empty(); + } + if (alternateBytes != null) { + return parsePackageConfigBytes(alternateBytes, alternateFile, onError); + } + } + return packages_file.parse(bytes, file, onError); + } + return parsePackageConfigBytes(bytes, file, onError); +} + +Future readPackageConfigJsonFile( + File file, void onError(Object error)) async { + Uint8List bytes; + try { + bytes = await file.readAsBytes(); + } catch (error) { + onError(error); + return const SimplePackageConfig.empty(); + } + return parsePackageConfigBytes(bytes, file.uri, onError); +} + +Future readDotPackagesFile( + File file, void onError(Object error)) async { + Uint8List bytes; + try { + bytes = await file.readAsBytes(); + } catch (error) { + onError(error); + return const SimplePackageConfig.empty(); + } + return packages_file.parse(bytes, file.uri, onError); +} + +Future writePackageConfigJsonFile( + PackageConfig config, Directory targetDirectory) async { + // Write .dart_tool/package_config.json first. + var file = + File(pathJoin(targetDirectory.path, ".dart_tool", "package_config.json")); + var baseUri = file.uri; + var sink = file.openWrite(encoding: utf8); + writePackageConfigJsonUtf8(config, baseUri, sink); + var doneJson = sink.close(); + + // Write .packages too. + file = File(pathJoin(targetDirectory.path, ".packages")); + baseUri = file.uri; + sink = file.openWrite(encoding: utf8); + writeDotPackages(config, baseUri, sink); + var donePackages = sink.close(); + + await Future.wait([doneJson, donePackages]); +} diff --git a/pkgs/package_config/lib/src/package_config_json.dart b/pkgs/package_config/lib/src/package_config_json.dart index f56c91271..b9b34165b 100644 --- a/pkgs/package_config/lib/src/package_config_json.dart +++ b/pkgs/package_config/lib/src/package_config_json.dart @@ -2,11 +2,11 @@ // 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. +// Parsing and serialization of package configurations. + import "dart:convert"; -import "dart:io"; import "dart:typed_data"; -import "discovery.dart" show packageConfigJsonPath; import "errors.dart"; import "package_config_impl.dart"; import "packages_file.dart" as packages_file; @@ -30,125 +30,6 @@ const String _generatedKey = "generated"; const String _generatorKey = "generator"; const String _generatorVersionKey = "generatorVersion"; -/// Reads a package configuration file. -/// -/// Detects whether the [file] is a version one `.packages` file or -/// a version two `package_config.json` file. -/// -/// If the [file] is a `.packages` file and [preferNewest] is true, -/// first checks whether there is an adjacent `.dart_tool/package_config.json` -/// file, and if so, reads that instead. -/// If [preferNewset] is false, the specified file is loaded even if it is -/// a `.packages` file and there is an available `package_config.json` file. -/// -/// The file must exist and be a normal file. -Future readAnyConfigFile( - File file, bool preferNewest, void onError(Object error)) async { - Uint8List bytes; - try { - bytes = await file.readAsBytes(); - } catch (e) { - onError(e); - return const SimplePackageConfig.empty(); - } - int firstChar = firstNonWhitespaceChar(bytes); - if (firstChar != $lbrace) { - // Definitely not a JSON object, probably a .packages. - if (preferNewest) { - var alternateFile = File( - pathJoin(dirName(file.path), ".dart_tool", "package_config.json")); - if (alternateFile.existsSync()) { - Uint8List /*?*/ bytes; - try { - bytes = await alternateFile.readAsBytes(); - } catch (e) { - onError(e); - return const SimplePackageConfig.empty(); - } - if (bytes != null) { - return parsePackageConfigBytes(bytes, alternateFile.uri, onError); - } - } - } - return packages_file.parse(bytes, file.uri, onError); - } - return parsePackageConfigBytes(bytes, file.uri, onError); -} - -/// Like [readAnyConfigFile] but uses a URI and an optional loader. -Future readAnyConfigFileUri( - Uri file, - Future loader(Uri uri) /*?*/, - void onError(Object error), - bool preferNewest) async { - if (file.isScheme("package")) { - throw PackageConfigArgumentError( - file, "file", "Must not be a package: URI"); - } - if (loader == null) { - if (file.isScheme("file")) { - return readAnyConfigFile(File.fromUri(file), preferNewest, onError); - } - loader = defaultLoader; - } - Uint8List bytes; - try { - bytes = await loader(file); - } catch (e) { - onError(e); - return const SimplePackageConfig.empty(); - } - if (bytes == null) { - onError(PackageConfigArgumentError( - file.toString(), "file", "File cannot be read")); - return const SimplePackageConfig.empty(); - } - int firstChar = firstNonWhitespaceChar(bytes); - if (firstChar != $lbrace) { - // Definitely not a JSON object, probably a .packages. - if (preferNewest) { - // Check if there is a package_config.json file. - var alternateFile = file.resolveUri(packageConfigJsonPath); - Uint8List alternateBytes; - try { - alternateBytes = await loader(alternateFile); - } catch (e) { - onError(e); - return const SimplePackageConfig.empty(); - } - if (alternateBytes != null) { - return parsePackageConfigBytes(alternateBytes, alternateFile, onError); - } - } - return packages_file.parse(bytes, file, onError); - } - return parsePackageConfigBytes(bytes, file, onError); -} - -Future readPackageConfigJsonFile( - File file, void onError(Object error)) async { - Uint8List bytes; - try { - bytes = await file.readAsBytes(); - } catch (error) { - onError(error); - return const SimplePackageConfig.empty(); - } - return parsePackageConfigBytes(bytes, file.uri, onError); -} - -Future readDotPackagesFile( - File file, void onError(Object error)) async { - Uint8List bytes; - try { - bytes = await file.readAsBytes(); - } catch (error) { - onError(error); - return const SimplePackageConfig.empty(); - } - return packages_file.parse(bytes, file.uri, onError); -} - final _jsonUtf8Decoder = json.fuse(utf8).decoder; PackageConfig parsePackageConfigBytes( @@ -164,6 +45,18 @@ PackageConfig parsePackageConfigBytes( return parsePackageConfigJson(jsonObject, file, onError); } +PackageConfig parsePackageConfigString( + String source, Uri file, void onError(Object error)) { + var jsonObject; + try { + jsonObject = jsonDecode(source); + } on FormatException catch (e) { + onError(PackageConfigFormatException(e.message, e.source, e.offset)); + return const SimplePackageConfig.empty(); + } + return parsePackageConfigJson(jsonObject, file, onError); +} + /// Creates a [PackageConfig] from a parsed JSON-like object structure. /// /// The [json] argument must be a JSON object (`Map`) @@ -221,9 +114,9 @@ PackageConfig parsePackageConfigJson( String /*?*/ packageUri; String /*?*/ languageVersion; Map /*?*/ extraData; - bool hasName = false; - bool hasRoot = false; - bool hasVersion = false; + var hasName = false; + var hasRoot = false; + var hasVersion = false; entry.forEach((key, value) { switch (key) { case _nameKey: @@ -253,9 +146,9 @@ PackageConfig parsePackageConfigJson( onError(PackageConfigFormatException("Missing rootUri entry", entry)); } if (name == null || rootUri == null) return null; - Uri root = baseLocation.resolve(rootUri); + var root = baseLocation.resolve(rootUri); if (!root.path.endsWith("/")) root = root.replace(path: root.path + "/"); - Uri packageRoot = root; + var packageRoot = root; if (packageUri != null) packageRoot = root.resolve(packageUri); if (!packageRoot.path.endsWith("/")) { packageRoot = packageRoot.replace(path: packageRoot.path + "/"); @@ -281,7 +174,7 @@ PackageConfig parsePackageConfigJson( var map = checkType>(json, "value"); if (map == null) return const SimplePackageConfig.empty(); - Map /*?*/ extraData = null; + Map /*?*/ extraData; List /*?*/ packageList; int /*?*/ configVersion; map.forEach((key, value) { @@ -326,31 +219,45 @@ PackageConfig parsePackageConfigJson( }); } -Future writePackageConfigJson( - PackageConfig config, Directory targetDirectory) async { - // Write .dart_tool/package_config.json first. - var file = - File(pathJoin(targetDirectory.path, ".dart_tool", "package_config.json")); - var baseUri = file.uri; - var extraData = config.extraData; - var data = { - _configVersionKey: PackageConfig.maxVersion, - _packagesKey: [ - for (var package in config.packages) - { - _nameKey: package.name, - _rootUriKey: relativizeUri(package.root, baseUri), - if (package.root != package.packageUriRoot) - _packageUriKey: relativizeUri(package.packageUriRoot, package.root), - if (package.languageVersion != null && - package.languageVersion is! InvalidLanguageVersion) - _languageVersionKey: package.languageVersion.toString(), - ...?_extractExtraData(package.extraData, _packageNames), - } - ], - ...?_extractExtraData(config.extraData, _topNames), - }; +final _jsonUtf8Encoder = JsonUtf8Encoder(" "); + +void writePackageConfigJsonUtf8( + PackageConfig config, Uri baseUri, Sink> output) { + // Can be optimized. + var data = packageConfigToJson(config, baseUri); + output.add(_jsonUtf8Encoder.convert(data) as Uint8List); +} + +void writePackageConfigJsonString( + PackageConfig config, Uri baseUri, StringSink output) { + // Can be optimized. + var data = packageConfigToJson(config, baseUri); + output.write(JsonEncoder.withIndent(" ").convert(data) as Uint8List); +} +Map packageConfigToJson(PackageConfig config, Uri baseUri) => + { + ...?_extractExtraData(config.extraData, _topNames), + _configVersionKey: PackageConfig.maxVersion, + _packagesKey: [ + for (var package in config.packages) + { + _nameKey: package.name, + _rootUriKey: relativizeUri(package.root, baseUri).toString(), + if (package.root != package.packageUriRoot) + _packageUriKey: + relativizeUri(package.packageUriRoot, package.root) + .toString(), + if (package.languageVersion != null && + package.languageVersion is! InvalidLanguageVersion) + _languageVersionKey: package.languageVersion.toString(), + ...?_extractExtraData(package.extraData, _packageNames), + } + ], + }; + +void writeDotPackages(PackageConfig config, Uri baseUri, StringSink output) { + var extraData = config.extraData; // Write .packages too. String /*?*/ comment; if (extraData != null) { @@ -363,15 +270,8 @@ Future writePackageConfigJson( "${generated != null ? " on $generated" : ""}."; } } - file = File(pathJoin(targetDirectory.path, ".packages")); - baseUri = file.uri; - var buffer = StringBuffer(); - packages_file.write(buffer, config, baseUri: baseUri, comment: comment); - - await Future.wait([ - file.writeAsString(JsonEncoder.withIndent(" ").convert(data)), - file.writeAsString(buffer.toString()), - ]); + packages_file.write(output, config, baseUri: baseUri, comment: comment); + return; } /// If "extraData" is a JSON map, then return it, otherwise return null. diff --git a/pkgs/package_config/lib/src/packages_file.dart b/pkgs/package_config/lib/src/packages_file.dart index 475a782a2..e65e7e8a6 100644 --- a/pkgs/package_config/lib/src/packages_file.dart +++ b/pkgs/package_config/lib/src/packages_file.dart @@ -31,15 +31,15 @@ PackageConfig parse( baseLocation, "baseLocation", "Must not be a package: URI")); return PackageConfig.empty; } - int index = 0; - List packages = []; - Set packageNames = {}; + var index = 0; + var packages = []; + var packageNames = {}; while (index < source.length) { - bool ignoreLine = false; - int start = index; - int separatorIndex = -1; - int end = source.length; - int char = source[index++]; + var ignoreLine = false; + var start = index; + var separatorIndex = -1; + var end = source.length; + var char = source[index++]; if (char == $cr || char == $lf) { continue; } @@ -50,8 +50,8 @@ PackageConfig parse( } else { ignoreLine = char == $hash; // Ignore if comment. } - int queryStart = -1; - int fragmentStart = -1; + var queryStart = -1; + var fragmentStart = -1; while (index < source.length) { char = source[index++]; if (char == $colon && separatorIndex < 0) { @@ -72,7 +72,7 @@ PackageConfig parse( continue; } var packageName = String.fromCharCodes(source, start, separatorIndex); - int invalidIndex = checkPackageName(packageName); + var invalidIndex = checkPackageName(packageName); if (invalidIndex >= 0) { onError(PackageConfigFormatException( "Not a valid package name", source, start + invalidIndex)); diff --git a/pkgs/package_config/lib/src/packages_impl.dart b/pkgs/package_config/lib/src/packages_impl.dart new file mode 100644 index 000000000..19f103922 --- /dev/null +++ b/pkgs/package_config/lib/src/packages_impl.dart @@ -0,0 +1,128 @@ +// Copyright (c) 2015, 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. + +/// Implementations of [Packages] that may be used in either server or browser +/// based applications. For implementations that can only run in the browser, +/// see [package_config.packages_io_impl]. +@Deprecated("Use the package_config.json based API") +library package_config.packages_impl; + +import "dart:collection" show UnmodifiableMapView; + +import "../packages.dart"; +import "util.dart" show checkValidPackageUri; + +/// A [Packages] null-object. +class NoPackages implements Packages { + const NoPackages(); + + Uri resolve(Uri packageUri, {Uri notFound(Uri packageUri)}) { + var packageName = checkValidPackageUri(packageUri, "packageUri"); + if (notFound != null) return notFound(packageUri); + throw ArgumentError.value( + packageUri, "packageUri", 'No package named "$packageName"'); + } + + Iterable get packages => Iterable.empty(); + + Map asMap() => const {}; + + String get defaultPackageName => null; + + String packageMetadata(String packageName, String key) => null; + + String libraryMetadata(Uri libraryUri, String key) => null; +} + +/// Base class for [Packages] implementations. +/// +/// This class implements the [resolve] method in terms of a private +/// member +abstract class PackagesBase implements Packages { + Uri resolve(Uri packageUri, {Uri notFound(Uri packageUri)}) { + packageUri = packageUri.normalizePath(); + var packageName = checkValidPackageUri(packageUri, "packageUri"); + var packageBase = getBase(packageName); + if (packageBase == null) { + if (notFound != null) return notFound(packageUri); + throw ArgumentError.value( + packageUri, "packageUri", 'No package named "$packageName"'); + } + var packagePath = packageUri.path.substring(packageName.length + 1); + return packageBase.resolve(packagePath); + } + + /// Find a base location for a package name. + /// + /// Returns `null` if no package exists with that name, and that can be + /// determined. + Uri getBase(String packageName); + + String get defaultPackageName => null; + + String packageMetadata(String packageName, String key) => null; + + String libraryMetadata(Uri libraryUri, String key) => null; +} + +/// A [Packages] implementation based on an existing map. +class MapPackages extends PackagesBase { + final Map _mapping; + MapPackages(this._mapping); + + Uri getBase(String packageName) => + packageName.isEmpty ? null : _mapping[packageName]; + + Iterable get packages => _mapping.keys; + + Map asMap() => UnmodifiableMapView(_mapping); + + String get defaultPackageName => _mapping[""]?.toString(); + + String packageMetadata(String packageName, String key) { + if (packageName.isEmpty) return null; + var uri = _mapping[packageName]; + if (uri == null || !uri.hasFragment) return null; + // This can be optimized, either by caching the map or by + // parsing incrementally instead of parsing the entire fragment. + return Uri.splitQueryString(uri.fragment)[key]; + } + + String libraryMetadata(Uri libraryUri, String key) { + if (libraryUri.isScheme("package")) { + return packageMetadata(libraryUri.pathSegments.first, key); + } + var defaultPackageNameUri = _mapping[""]; + if (defaultPackageNameUri != null) { + return packageMetadata(defaultPackageNameUri.toString(), key); + } + return null; + } +} + +/// A [Packages] implementation based on a remote (e.g., HTTP) directory. +/// +/// There is no way to detect which packages exist short of trying to use +/// them. You can't necessarily check whether a directory exists, +/// except by checking for a know file in the directory. +class NonFilePackagesDirectoryPackages extends PackagesBase { + final Uri _packageBase; + NonFilePackagesDirectoryPackages(this._packageBase); + + Uri getBase(String packageName) => _packageBase.resolve("$packageName/"); + + Error _failListingPackages() { + return UnsupportedError( + "Cannot list packages for a ${_packageBase.scheme}: " + "based package root"); + } + + Iterable get packages { + throw _failListingPackages(); + } + + Map asMap() { + throw _failListingPackages(); + } +} diff --git a/pkgs/package_config/lib/src/packages_io_impl.dart b/pkgs/package_config/lib/src/packages_io_impl.dart new file mode 100644 index 000000000..b2277e7e0 --- /dev/null +++ b/pkgs/package_config/lib/src/packages_io_impl.dart @@ -0,0 +1,46 @@ +// Copyright (c) 2015, 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. + +/// Implementations of [Packages] that can only be used in server based +/// applications. +@Deprecated("Use the package_config.json based API") +library package_config.packages_io_impl; + +import "dart:collection" show UnmodifiableMapView; +import "dart:io" show Directory; + +import "packages_impl.dart"; + +import "util.dart"; + +/// A [Packages] implementation based on a local directory. +class FilePackagesDirectoryPackages extends PackagesBase { + final Directory _packageDir; + final Map _packageToBaseUriMap = {}; + + FilePackagesDirectoryPackages(this._packageDir); + + Uri getBase(String packageName) { + return _packageToBaseUriMap.putIfAbsent(packageName, () { + return Uri.file(pathJoin(_packageDir.path, packageName, '.')); + }); + } + + Iterable _listPackageNames() { + return _packageDir + .listSync() + .whereType() + .map((e) => fileName(e.path)); + } + + Iterable get packages => _listPackageNames(); + + Map asMap() { + var result = {}; + for (var packageName in _listPackageNames()) { + result[packageName] = getBase(packageName); + } + return UnmodifiableMapView(result); + } +} diff --git a/pkgs/package_config/lib/src/util.dart b/pkgs/package_config/lib/src/util.dart index f39027d00..548f61d98 100644 --- a/pkgs/package_config/lib/src/util.dart +++ b/pkgs/package_config/lib/src/util.dart @@ -31,8 +31,8 @@ bool isValidPackageName(String string) { /// or `string.length` if the string contains no non-'.' character. int checkPackageName(String string) { // Becomes non-zero if any non-'.' character is encountered. - int nonDot = 0; - for (int i = 0; i < string.length; i++) { + var nonDot = 0; + for (var i = 0; i < string.length; i++) { var c = string.codeUnitAt(i); if (c > 0x7f || _validPackageNameCharacters.codeUnitAt(c) <= $space) { return i; @@ -74,13 +74,13 @@ String checkValidPackageUri(Uri packageUri, String name) { throw PackageConfigArgumentError( packageUri, name, "Package URIs must not start with a '/'"); } - int firstSlash = packageUri.path.indexOf('/'); + var firstSlash = packageUri.path.indexOf('/'); if (firstSlash == -1) { throw PackageConfigArgumentError(packageUri, name, "Package URIs must start with the package name followed by a '/'"); } - String packageName = packageUri.path.substring(0, firstSlash); - int badIndex = checkPackageName(packageName); + var packageName = packageUri.path.substring(0, firstSlash); + var badIndex = checkPackageName(packageName); if (badIndex >= 0) { if (packageName.isEmpty) { throw PackageConfigArgumentError( @@ -91,7 +91,7 @@ String checkValidPackageUri(Uri packageUri, String name) { "Package names must contain at least one non-'.' character"); } assert(badIndex < packageName.length); - int badCharCode = packageName.codeUnitAt(badIndex); + var badCharCode = packageName.codeUnitAt(badIndex); var badChar = "U+" + badCharCode.toRadixString(16).padLeft(4, '0'); if (badCharCode >= 0x20 && badCharCode <= 0x7e) { // Printable character. @@ -131,7 +131,7 @@ bool isUriPrefix(Uri prefix, Uri path) { /// /// Used to heuristically detect whether a file is a JSON file or an .ini file. int firstNonWhitespaceChar(List bytes) { - for (int i = 0; i < bytes.length; i++) { + for (var i = 0; i < bytes.length; i++) { var char = bytes[i]; if (char != 0x20 && char != 0x09 && char != 0x0a && char != 0x0d) { return char; @@ -156,7 +156,8 @@ int firstNonWhitespaceChar(List bytes) { /// `baseUri.resolveUri(result) == uri`, /// /// The `baseUri` must be absolute. -Uri relativizeUri(Uri uri, Uri baseUri) { +Uri relativizeUri(Uri uri, Uri /*?*/ baseUri) { + if (baseUri == null) return uri; assert(baseUri.isAbsolute); if (uri.hasQuery || uri.hasFragment) { uri = Uri( @@ -185,12 +186,12 @@ Uri relativizeUri(Uri uri, Uri baseUri) { } baseUri = baseUri.normalizePath(); - List base = [...baseUri.pathSegments]; + var base = [...baseUri.pathSegments]; if (base.isNotEmpty) base.removeLast(); uri = uri.normalizePath(); - List target = [...uri.pathSegments]; + var target = [...uri.pathSegments]; if (target.isNotEmpty && target.last.isEmpty) target.removeLast(); - int index = 0; + var index = 0; while (index < base.length && index < target.length) { if (base[index] != target[index]) { break; @@ -204,7 +205,7 @@ Uri relativizeUri(Uri uri, Uri baseUri) { return Uri(path: target.skip(index).join('/')); } else if (index > 0) { var buffer = StringBuffer(); - for (int n = base.length - index; n > 0; --n) { + for (var n = base.length - index; n > 0; --n) { buffer.write("../"); } buffer.writeAll(target.skip(index), "/"); @@ -231,14 +232,14 @@ Future defaultLoader(Uri uri) async { Future _httpGet(Uri uri) async { assert(uri.isScheme("http") || uri.isScheme("https")); - HttpClient client = new HttpClient(); - HttpClientRequest request = await client.getUrl(uri); - HttpClientResponse response = await request.close(); + var client = HttpClient(); + var request = await client.getUrl(uri); + var response = await request.close(); if (response.statusCode != HttpStatus.ok) { return null; } - List> splitContent = await response.toList(); - int totalLength = 0; + var splitContent = await response.toList(); + var totalLength = 0; if (splitContent.length == 1) { var part = splitContent[0]; if (part is Uint8List) { @@ -248,8 +249,8 @@ Future _httpGet(Uri uri) async { for (var list in splitContent) { totalLength += list.length; } - Uint8List result = new Uint8List(totalLength); - int offset = 0; + var result = Uint8List(totalLength); + var offset = 0; for (Uint8List contentPart in splitContent) { result.setRange(offset, offset + contentPart.length, contentPart); offset += contentPart.length; @@ -264,7 +265,7 @@ Future _httpGet(Uri uri) async { /// path separator occurs in the string. String fileName(String path) { var separator = Platform.pathSeparator; - int lastSeparator = path.lastIndexOf(separator); + var lastSeparator = path.lastIndexOf(separator); if (lastSeparator < 0) return path; return path.substring(lastSeparator + separator.length); } @@ -276,7 +277,7 @@ String fileName(String path) { /// path separator occurs in the string. String dirName(String path) { var separator = Platform.pathSeparator; - int lastSeparator = path.lastIndexOf(separator); + var lastSeparator = path.lastIndexOf(separator); if (lastSeparator < 0) return ""; return path.substring(0, lastSeparator); } @@ -287,11 +288,11 @@ String dirName(String path) { /// inserted. String pathJoin(String part1, String part2, [String part3]) { var separator = Platform.pathSeparator; - String separator1 = part1.endsWith(separator) ? "" : separator; + var separator1 = part1.endsWith(separator) ? "" : separator; if (part3 == null) { return "$part1$separator1$part2"; } - String separator2 = part2.endsWith(separator) ? "" : separator; + var separator2 = part2.endsWith(separator) ? "" : separator; return "$part1$separator1$part2$separator2$part3"; } @@ -301,7 +302,7 @@ String pathJoin(String part1, String part2, [String part3]) { /// inserted. String pathJoinAll(Iterable parts) { var buffer = StringBuffer(); - String separator = ""; + var separator = ""; for (var part in parts) { buffer..write(separator)..write(part); separator = diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 7f47d2e2c..20a39c767 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 3.0.0-dev +version: 1.9.0-dev description: Support for working with Package Configuration files. author: Dart Team homepage: https://github.com/dart-lang/package_config @@ -8,4 +8,6 @@ environment: sdk: '>=2.7.0 <3.0.0' dev_dependencies: - test: ^1.3.0 + test: ^1.6.4 + matcher: ^0.12.5 + pedantic: 1.8.0 diff --git a/pkgs/package_config/test/discovery_test.dart b/pkgs/package_config/test/discovery_test.dart index 23efc6741..e4c93a592 100644 --- a/pkgs/package_config/test/discovery_test.dart +++ b/pkgs/package_config/test/discovery_test.dart @@ -50,7 +50,7 @@ void validatePackagesFile(PackageConfig resolver, Directory directory) { unorderedEquals(["foo", "bar", "baz"])); } -main() { +void main() { group("findPackages", () { // Finds package_config.json if there. fileTest("package_config.json", { @@ -61,7 +61,7 @@ main() { "package_config.json": packageConfigFile, } }, (Directory directory) async { - PackageConfig config = await findPackageConfig(directory); + var config = await findPackageConfig(directory); expect(config.version, 2); // Found package_config.json file. validatePackagesFile(config, directory); }); @@ -72,7 +72,7 @@ main() { "script.dart": "main(){}", "packages": {"shouldNotBeFound": {}} }, (Directory directory) async { - PackageConfig config = await findPackageConfig(directory); + var config = await findPackageConfig(directory); expect(config.version, 1); // Found .packages file. validatePackagesFile(config, directory); }); @@ -87,8 +87,7 @@ main() { "script.dart": "main(){}", } }, (Directory directory) async { - PackageConfig config = - await findPackageConfig(subdir(directory, "subdir/")); + var config = await findPackageConfig(subdir(directory, "subdir/")); expect(config.version, 2); validatePackagesFile(config, directory); }); @@ -98,7 +97,7 @@ main() { ".packages": packagesFile, "subdir": {"script.dart": "main(){}"} }, (Directory directory) async { - PackageConfig config; + var config; config = await findPackageConfig(subdir(directory, "subdir/")); expect(config.version, 1); validatePackagesFile(config, directory); @@ -110,7 +109,7 @@ main() { "foo": {}, } }, (Directory directory) async { - PackageConfig config = await findPackageConfig(directory); + var config = await findPackageConfig(directory); expect(config, null); }); @@ -152,7 +151,7 @@ main() { fileTest("invalid .packages", { ".packages": "not a .packages file", }, (Directory directory) async { - bool hadError = false; + var hadError = false; await findPackageConfig(directory, onError: expectAsync1((error) { hadError = true; @@ -164,7 +163,7 @@ main() { fileTest("invalid .packages as JSON", { ".packages": packageConfigFile, }, (Directory directory) async { - bool hadError = false; + var hadError = false; await findPackageConfig(directory, onError: expectAsync1((error) { hadError = true; @@ -178,7 +177,7 @@ main() { "package_config.json": "not a JSON file", } }, (Directory directory) async { - bool hadError = false; + var hadError = false; await findPackageConfig(directory, onError: expectAsync1((error) { hadError = true; @@ -192,7 +191,7 @@ main() { "package_config.json": packagesFile, } }, (Directory directory) async { - bool hadError = false; + var hadError = false; await findPackageConfig(directory, onError: expectAsync1((error) { hadError = true; @@ -213,23 +212,22 @@ main() { }, }; fileTest("directly", files, (Directory directory) async { - File file = + var file = dirFile(subdir(directory, ".dart_tool"), "package_config.json"); - PackageConfig config = await loadPackageConfig(file); + var config = await loadPackageConfig(file); expect(config.version, 2); validatePackagesFile(config, directory); }); fileTest("indirectly through .packages", files, (Directory directory) async { - File file = dirFile(directory, ".packages"); - PackageConfig config = await loadPackageConfig(file); + var file = dirFile(directory, ".packages"); + var config = await loadPackageConfig(file); expect(config.version, 2); validatePackagesFile(config, directory); }); fileTest("prefer .packages", files, (Directory directory) async { - File file = dirFile(directory, ".packages"); - PackageConfig config = - await loadPackageConfig(file, preferNewest: false); + var file = dirFile(directory, ".packages"); + var config = await loadPackageConfig(file, preferNewest: false); expect(config.version, 1); validatePackagesFile(config, directory); }); @@ -241,8 +239,8 @@ main() { "pheldagriff": packageConfigFile, }, }, (Directory directory) async { - File file = dirFile(directory, "subdir/pheldagriff"); - PackageConfig config = await loadPackageConfig(file); + var file = dirFile(directory, "subdir/pheldagriff"); + var config = await loadPackageConfig(file); expect(config.version, 2); validatePackagesFile(config, directory); }); @@ -252,8 +250,8 @@ main() { ".packages": packageConfigFile, }, }, (Directory directory) async { - File file = dirFile(directory, "subdir/.packages"); - PackageConfig config = await loadPackageConfig(file); + var file = dirFile(directory, "subdir/.packages"); + var config = await loadPackageConfig(file); expect(config.version, 2); validatePackagesFile(config, directory); }); @@ -261,8 +259,8 @@ main() { fileTest(".packages", { ".packages": packagesFile, }, (Directory directory) async { - File file = dirFile(directory, ".packages"); - PackageConfig config = await loadPackageConfig(file); + var file = dirFile(directory, ".packages"); + var config = await loadPackageConfig(file); expect(config.version, 1); validatePackagesFile(config, directory); }); @@ -270,21 +268,21 @@ main() { fileTest(".packages non-default name", { "pheldagriff": packagesFile, }, (Directory directory) async { - File file = dirFile(directory, "pheldagriff"); - PackageConfig config = await loadPackageConfig(file); + var file = dirFile(directory, "pheldagriff"); + var config = await loadPackageConfig(file); expect(config.version, 1); validatePackagesFile(config, directory); }); fileTest("no config found", {}, (Directory directory) { - File file = dirFile(directory, "anyname"); + var file = dirFile(directory, "anyname"); expect(() => loadPackageConfig(file), throwsA(TypeMatcher())); }); fileTest("no config found, handled", {}, (Directory directory) async { - File file = dirFile(directory, "anyname"); - bool hadError = false; + var file = dirFile(directory, "anyname"); + var hadError = false; await loadPackageConfig(file, onError: expectAsync1((error) { hadError = true; @@ -296,7 +294,7 @@ main() { fileTest("specified file syntax error", { "anyname": "syntax error", }, (Directory directory) { - File file = dirFile(directory, "anyname"); + var file = dirFile(directory, "anyname"); expect(() => loadPackageConfig(file), throwsFormatException); }); @@ -307,8 +305,8 @@ main() { "package_config.json": packageConfigFile, }, }, (Directory directory) async { - File file = dirFile(directory, "anyname"); - PackageConfig config = await loadPackageConfig(file); + var file = dirFile(directory, "anyname"); + var config = await loadPackageConfig(file); expect(config.version, 2); validatePackagesFile(config, directory); }); @@ -317,7 +315,7 @@ main() { fileTest("file syntax error with {", { ".packages": "{syntax error", }, (Directory directory) { - File file = dirFile(directory, ".packages"); + var file = dirFile(directory, ".packages"); expect(() => loadPackageConfig(file), throwsFormatException); }); }); diff --git a/pkgs/package_config/test/discovery_uri_test.dart b/pkgs/package_config/test/discovery_uri_test.dart index 081ec608f..109693c4c 100644 --- a/pkgs/package_config/test/discovery_uri_test.dart +++ b/pkgs/package_config/test/discovery_uri_test.dart @@ -4,8 +4,6 @@ library package_config.discovery_test; -import 'dart:io'; - import "package:test/test.dart"; import "package:package_config/package_config.dart"; @@ -51,7 +49,7 @@ void validatePackagesFile(PackageConfig resolver, Uri directory) { unorderedEquals(["foo", "bar", "baz"])); } -main() { +void main() { group("findPackages", () { // Finds package_config.json if there. loaderTest("package_config.json", { @@ -62,8 +60,7 @@ main() { "package_config.json": packageConfigFile, } }, (Uri directory, loader) async { - PackageConfig config = - await findPackageConfigUri(directory, loader: loader); + var config = await findPackageConfigUri(directory, loader: loader); expect(config.version, 2); // Found package_config.json file. validatePackagesFile(config, directory); }); @@ -74,8 +71,7 @@ main() { "script.dart": "main(){}", "packages": {"shouldNotBeFound": {}} }, (Uri directory, loader) async { - PackageConfig config = - await findPackageConfigUri(directory, loader: loader); + var config = await findPackageConfigUri(directory, loader: loader); expect(config.version, 1); // Found .packages file. validatePackagesFile(config, directory); }); @@ -90,8 +86,7 @@ main() { "script.dart": "main(){}", } }, (Uri directory, loader) async { - PackageConfig config = await findPackageConfigUri( - directory.resolve("subdir/"), + var config = await findPackageConfigUri(directory.resolve("subdir/"), loader: loader); expect(config.version, 2); validatePackagesFile(config, directory); @@ -102,7 +97,7 @@ main() { ".packages": packagesFile, "subdir": {"script.dart": "main(){}"} }, (Uri directory, loader) async { - PackageConfig config; + var config; config = await findPackageConfigUri(directory.resolve("subdir/"), loader: loader); expect(config.version, 1); @@ -115,8 +110,7 @@ main() { "foo": {}, } }, (Uri directory, loader) async { - PackageConfig config = - await findPackageConfigUri(directory, loader: loader); + var config = await findPackageConfigUri(directory, loader: loader); expect(config, null); }); @@ -163,15 +157,15 @@ main() { }, }; loaderTest("directly", files, (Uri directory, loader) async { - Uri file = directory.resolve(".dart_tool/package_config.json"); - PackageConfig config = await loadPackageConfigUri(file, loader: loader); + var file = directory.resolve(".dart_tool/package_config.json"); + var config = await loadPackageConfigUri(file, loader: loader); expect(config.version, 2); validatePackagesFile(config, directory); }); loaderTest("indirectly through .packages", files, (Uri directory, loader) async { - Uri file = directory.resolve(".packages"); - PackageConfig config = await loadPackageConfigUri(file, loader: loader); + var file = directory.resolve(".packages"); + var config = await loadPackageConfigUri(file, loader: loader); expect(config.version, 2); validatePackagesFile(config, directory); }); @@ -183,8 +177,8 @@ main() { "pheldagriff": packageConfigFile, }, }, (Uri directory, loader) async { - Uri file = directory.resolve("subdir/pheldagriff"); - PackageConfig config = await loadPackageConfigUri(file, loader: loader); + var file = directory.resolve("subdir/pheldagriff"); + var config = await loadPackageConfigUri(file, loader: loader); expect(config.version, 2); validatePackagesFile(config, directory); }); @@ -194,8 +188,8 @@ main() { ".packages": packageConfigFile, }, }, (Uri directory, loader) async { - Uri file = directory.resolve("subdir/.packages"); - PackageConfig config = await loadPackageConfigUri(file, loader: loader); + var file = directory.resolve("subdir/.packages"); + var config = await loadPackageConfigUri(file, loader: loader); expect(config.version, 2); validatePackagesFile(config, directory); }); @@ -203,8 +197,8 @@ main() { loaderTest(".packages", { ".packages": packagesFile, }, (Uri directory, loader) async { - Uri file = directory.resolve(".packages"); - PackageConfig config = await loadPackageConfigUri(file, loader: loader); + var file = directory.resolve(".packages"); + var config = await loadPackageConfigUri(file, loader: loader); expect(config.version, 1); validatePackagesFile(config, directory); }); @@ -212,22 +206,22 @@ main() { loaderTest(".packages non-default name", { "pheldagriff": packagesFile, }, (Uri directory, loader) async { - Uri file = directory.resolve("pheldagriff"); - PackageConfig config = await loadPackageConfigUri(file, loader: loader); + var file = directory.resolve("pheldagriff"); + var config = await loadPackageConfigUri(file, loader: loader); expect(config.version, 1); validatePackagesFile(config, directory); }); loaderTest("no config found", {}, (Uri directory, loader) { - Uri file = directory.resolve("anyname"); + var file = directory.resolve("anyname"); expect(() => loadPackageConfigUri(file, loader: loader), throwsA(isA())); }); loaderTest("no config found, handle error", {}, (Uri directory, loader) async { - Uri file = directory.resolve("anyname"); - bool hadError = false; + var file = directory.resolve("anyname"); + var hadError = false; await loadPackageConfigUri(file, loader: loader, onError: expectAsync1((error) { @@ -240,7 +234,7 @@ main() { loaderTest("specified file syntax error", { "anyname": "syntax error", }, (Uri directory, loader) { - Uri file = directory.resolve("anyname"); + var file = directory.resolve("anyname"); expect(() => loadPackageConfigUri(file, loader: loader), throwsFormatException); }); @@ -248,8 +242,8 @@ main() { loaderTest("specified file syntax error", { "anyname": "syntax error", }, (Uri directory, loader) async { - Uri file = directory.resolve("anyname"); - bool hadError = false; + var file = directory.resolve("anyname"); + var hadError = false; await loadPackageConfigUri(file, loader: loader, onError: expectAsync1((error) { @@ -266,8 +260,8 @@ main() { "package_config.json": packageConfigFile, }, }, (Uri directory, loader) async { - Uri file = directory.resolve("anyname"); - PackageConfig config = await loadPackageConfigUri(file, loader: loader); + var file = directory.resolve("anyname"); + var config = await loadPackageConfigUri(file, loader: loader); expect(config.version, 2); validatePackagesFile(config, directory); }); @@ -276,7 +270,7 @@ main() { loaderTest("file syntax error with {", { ".packages": "{syntax error", }, (Uri directory, loader) async { - Uri file = directory.resolve(".packages"); + var file = directory.resolve(".packages"); var hadError = false; await loadPackageConfigUri(file, loader: loader, diff --git a/pkgs/package_config/test/legacy/all.dart b/pkgs/package_config/test/legacy/all.dart new file mode 100644 index 000000000..22e2e4f9e --- /dev/null +++ b/pkgs/package_config/test/legacy/all.dart @@ -0,0 +1,20 @@ +// Copyright (c) 2015, 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. + +@deprecated +library package_config.all_test; + +import "package:test/test.dart"; + +import "discovery_analysis_test.dart" as discovery_analysis; +import "discovery_test.dart" as discovery; +import "parse_test.dart" as parse; +import "parse_write_test.dart" as parse_write; + +void main() { + group("parse:", parse.main); + group("discovery:", discovery.main); + group("discovery-analysis:", discovery_analysis.main); + group("parse/write:", parse_write.main); +} diff --git a/pkgs/package_config/test/legacy/discovery_analysis_test.dart b/pkgs/package_config/test/legacy/discovery_analysis_test.dart new file mode 100644 index 000000000..7d08f7b92 --- /dev/null +++ b/pkgs/package_config/test/legacy/discovery_analysis_test.dart @@ -0,0 +1,127 @@ +// Copyright (c) 2015, 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. + +@deprecated +library package_config.discovery_analysis_test; + +import "dart:async"; +import "dart:io"; + +import "package:package_config/discovery_analysis.dart"; +import "package:package_config/packages.dart"; +import "package:path/path.dart" as path; +import "package:test/test.dart"; + +void main() { + fileTest("basic", { + ".packages": packagesFile, + "foo": {".packages": packagesFile}, + "bar": { + "packages": {"foo": {}, "bar": {}, "baz": {}} + }, + "baz": {} + }, (Directory directory) { + var dirUri = Uri.directory(directory.path); + var ctx = PackageContext.findAll(directory); + var root = ctx[directory]; + expect(root, same(ctx)); + validatePackagesFile(root.packages, dirUri); + var fooDir = sub(directory, "foo"); + var foo = ctx[fooDir]; + expect(identical(root, foo), isFalse); + validatePackagesFile(foo.packages, dirUri.resolve("foo/")); + var barDir = sub(directory, "bar"); + var bar = ctx[sub(directory, "bar")]; + validatePackagesDir(bar.packages, dirUri.resolve("bar/")); + var barbar = ctx[sub(barDir, "bar")]; + expect(barbar, same(bar)); // inherited. + var baz = ctx[sub(directory, "baz")]; + expect(baz, same(root)); // inherited. + + var map = ctx.asMap(); + expect(map.keys.map((dir) => dir.path), + unorderedEquals([directory.path, fooDir.path, barDir.path])); + return null; + }); +} + +Directory sub(Directory parent, String dirName) { + return Directory(path.join(parent.path, dirName)); +} + +const packagesFile = """ +# A comment +foo:file:///dart/packages/foo/ +bar:http://example.com/dart/packages/bar/ +baz:packages/baz/ +"""; + +void validatePackagesFile(Packages resolver, Uri location) { + expect(resolver, isNotNull); + expect(resolver.resolve(pkg("foo", "bar/baz")), + equals(Uri.parse("file:///dart/packages/foo/bar/baz"))); + expect(resolver.resolve(pkg("bar", "baz/qux")), + equals(Uri.parse("http://example.com/dart/packages/bar/baz/qux"))); + expect(resolver.resolve(pkg("baz", "qux/foo")), + equals(location.resolve("packages/baz/qux/foo"))); + expect(resolver.packages, unorderedEquals(["foo", "bar", "baz"])); +} + +void validatePackagesDir(Packages resolver, Uri location) { + // Expect three packages: foo, bar and baz + expect(resolver, isNotNull); + expect(resolver.resolve(pkg("foo", "bar/baz")), + equals(location.resolve("packages/foo/bar/baz"))); + expect(resolver.resolve(pkg("bar", "baz/qux")), + equals(location.resolve("packages/bar/baz/qux"))); + expect(resolver.resolve(pkg("baz", "qux/foo")), + equals(location.resolve("packages/baz/qux/foo"))); + if (location.scheme == "file") { + expect(resolver.packages, unorderedEquals(["foo", "bar", "baz"])); + } else { + expect(() => resolver.packages, throwsUnsupportedError); + } +} + +Uri pkg(String packageName, String packagePath) { + var path; + if (packagePath.startsWith('/')) { + path = "$packageName$packagePath"; + } else { + path = "$packageName/$packagePath"; + } + return Uri(scheme: "package", path: path); +} + +/// Create a directory structure from [description] and run [fileTest]. +/// +/// Description is a map, each key is a file entry. If the value is a map, +/// it's a sub-dir, otherwise it's a file and the value is the content +/// as a string. +void fileTest( + String name, Map description, Future fileTest(Directory directory)) { + group("file-test", () { + var tempDir = Directory.systemTemp.createTempSync("file-test"); + setUp(() { + _createFiles(tempDir, description); + }); + tearDown(() { + tempDir.deleteSync(recursive: true); + }); + test(name, () => fileTest(tempDir)); + }); +} + +void _createFiles(Directory target, Map description) { + description.forEach((name, content) { + if (content is Map) { + var subDir = Directory(path.join(target.path, name)); + subDir.createSync(); + _createFiles(subDir, content); + } else { + var file = File(path.join(target.path, name)); + file.writeAsStringSync(content, flush: true); + } + }); +} diff --git a/pkgs/package_config/test/legacy/discovery_test.dart b/pkgs/package_config/test/legacy/discovery_test.dart new file mode 100644 index 000000000..684abcb4a --- /dev/null +++ b/pkgs/package_config/test/legacy/discovery_test.dart @@ -0,0 +1,328 @@ +// Copyright (c) 2015, 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. + +@deprecated +library package_config.discovery_test; + +import "dart:async"; +import "dart:io"; +import "package:test/test.dart"; +import "package:package_config/packages.dart"; +import "package:package_config/discovery.dart"; +import "package:path/path.dart" as path; + +const packagesFile = """ +# A comment +foo:file:///dart/packages/foo/ +bar:http://example.com/dart/packages/bar/ +baz:packages/baz/ +"""; + +void validatePackagesFile(Packages resolver, Uri location) { + expect(resolver, isNotNull); + expect(resolver.resolve(pkg("foo", "bar/baz")), + equals(Uri.parse("file:///dart/packages/foo/bar/baz"))); + expect(resolver.resolve(pkg("bar", "baz/qux")), + equals(Uri.parse("http://example.com/dart/packages/bar/baz/qux"))); + expect(resolver.resolve(pkg("baz", "qux/foo")), + equals(location.resolve("packages/baz/qux/foo"))); + expect(resolver.packages, unorderedEquals(["foo", "bar", "baz"])); +} + +void validatePackagesDir(Packages resolver, Uri location) { + // Expect three packages: foo, bar and baz + expect(resolver, isNotNull); + expect(resolver.resolve(pkg("foo", "bar/baz")), + equals(location.resolve("packages/foo/bar/baz"))); + expect(resolver.resolve(pkg("bar", "baz/qux")), + equals(location.resolve("packages/bar/baz/qux"))); + expect(resolver.resolve(pkg("baz", "qux/foo")), + equals(location.resolve("packages/baz/qux/foo"))); + if (location.scheme == "file") { + expect(resolver.packages, unorderedEquals(["foo", "bar", "baz"])); + } else { + expect(() => resolver.packages, throwsUnsupportedError); + } +} + +Uri pkg(String packageName, String packagePath) { + var path; + if (packagePath.startsWith('/')) { + path = "$packageName$packagePath"; + } else { + path = "$packageName/$packagePath"; + } + return Uri(scheme: "package", path: path); +} + +void main() { + generalTest(".packages", { + ".packages": packagesFile, + "script.dart": "main(){}", + "packages": {"shouldNotBeFound": {}} + }, (Uri location) async { + Packages resolver; + resolver = await findPackages(location); + validatePackagesFile(resolver, location); + resolver = await findPackages(location.resolve("script.dart")); + validatePackagesFile(resolver, location); + var specificDiscovery = (location.scheme == "file") + ? findPackagesFromFile + : findPackagesFromNonFile; + resolver = await specificDiscovery(location); + validatePackagesFile(resolver, location); + resolver = await specificDiscovery(location.resolve("script.dart")); + validatePackagesFile(resolver, location); + }); + + generalTest("packages/", { + "packages": {"foo": {}, "bar": {}, "baz": {}}, + "script.dart": "main(){}" + }, (Uri location) async { + Packages resolver; + var isFile = (location.scheme == "file"); + resolver = await findPackages(location); + validatePackagesDir(resolver, location); + resolver = await findPackages(location.resolve("script.dart")); + validatePackagesDir(resolver, location); + var specificDiscovery = + isFile ? findPackagesFromFile : findPackagesFromNonFile; + resolver = await specificDiscovery(location); + validatePackagesDir(resolver, location); + resolver = await specificDiscovery(location.resolve("script.dart")); + validatePackagesDir(resolver, location); + }); + + generalTest("underscore packages", { + "packages": {"_foo": {}} + }, (Uri location) async { + var resolver = await findPackages(location); + expect(resolver.resolve(pkg("_foo", "foo.dart")), + equals(location.resolve("packages/_foo/foo.dart"))); + }); + + fileTest(".packages recursive", { + ".packages": packagesFile, + "subdir": {"script.dart": "main(){}"} + }, (Uri location) async { + Packages resolver; + resolver = await findPackages(location.resolve("subdir/")); + validatePackagesFile(resolver, location); + resolver = await findPackages(location.resolve("subdir/script.dart")); + validatePackagesFile(resolver, location); + resolver = await findPackagesFromFile(location.resolve("subdir/")); + validatePackagesFile(resolver, location); + resolver = + await findPackagesFromFile(location.resolve("subdir/script.dart")); + validatePackagesFile(resolver, location); + }); + + httpTest(".packages not recursive", { + ".packages": packagesFile, + "subdir": {"script.dart": "main(){}"} + }, (Uri location) async { + Packages resolver; + var subdir = location.resolve("subdir/"); + resolver = await findPackages(subdir); + validatePackagesDir(resolver, subdir); + resolver = await findPackages(subdir.resolve("script.dart")); + validatePackagesDir(resolver, subdir); + resolver = await findPackagesFromNonFile(subdir); + validatePackagesDir(resolver, subdir); + resolver = await findPackagesFromNonFile(subdir.resolve("script.dart")); + validatePackagesDir(resolver, subdir); + }); + + fileTest("no packages", {"script.dart": "main(){}"}, (Uri location) async { + // A file: location with no .packages or packages returns + // Packages.noPackages. + Packages resolver; + resolver = await findPackages(location); + expect(resolver, same(Packages.noPackages)); + resolver = await findPackages(location.resolve("script.dart")); + expect(resolver, same(Packages.noPackages)); + resolver = findPackagesFromFile(location); + expect(resolver, same(Packages.noPackages)); + resolver = findPackagesFromFile(location.resolve("script.dart")); + expect(resolver, same(Packages.noPackages)); + }); + + httpTest("no packages", {"script.dart": "main(){}"}, (Uri location) async { + // A non-file: location with no .packages or packages/: + // Assumes a packages dir exists, and resolves relative to that. + Packages resolver; + resolver = await findPackages(location); + validatePackagesDir(resolver, location); + resolver = await findPackages(location.resolve("script.dart")); + validatePackagesDir(resolver, location); + resolver = await findPackagesFromNonFile(location); + validatePackagesDir(resolver, location); + resolver = await findPackagesFromNonFile(location.resolve("script.dart")); + validatePackagesDir(resolver, location); + }); + + test(".packages w/ loader", () async { + var location = Uri.parse("krutch://example.com/path/"); + Future> loader(Uri file) async { + if (file.path.endsWith(".packages")) { + return packagesFile.codeUnits; + } + throw "not found"; + } + + // A non-file: location with no .packages or packages/: + // Assumes a packages dir exists, and resolves relative to that. + Packages resolver; + resolver = await findPackages(location, loader: loader); + validatePackagesFile(resolver, location); + resolver = + await findPackages(location.resolve("script.dart"), loader: loader); + validatePackagesFile(resolver, location); + resolver = await findPackagesFromNonFile(location, loader: loader); + validatePackagesFile(resolver, location); + resolver = await findPackagesFromNonFile(location.resolve("script.dart"), + loader: loader); + validatePackagesFile(resolver, location); + }); + + test("no packages w/ loader", () async { + var location = Uri.parse("krutch://example.com/path/"); + Future> loader(Uri file) async { + throw "not found"; + } + + // A non-file: location with no .packages or packages/: + // Assumes a packages dir exists, and resolves relative to that. + Packages resolver; + resolver = await findPackages(location, loader: loader); + validatePackagesDir(resolver, location); + resolver = + await findPackages(location.resolve("script.dart"), loader: loader); + validatePackagesDir(resolver, location); + resolver = await findPackagesFromNonFile(location, loader: loader); + validatePackagesDir(resolver, location); + resolver = await findPackagesFromNonFile(location.resolve("script.dart"), + loader: loader); + validatePackagesDir(resolver, location); + }); + + generalTest("loadPackagesFile", {".packages": packagesFile}, + (Uri directory) async { + var file = directory.resolve(".packages"); + var resolver = await loadPackagesFile(file); + validatePackagesFile(resolver, file); + }); + + generalTest( + "loadPackagesFile non-default name", {"pheldagriff": packagesFile}, + (Uri directory) async { + var file = directory.resolve("pheldagriff"); + var resolver = await loadPackagesFile(file); + validatePackagesFile(resolver, file); + }); + + test("loadPackagesFile w/ loader", () async { + Future> loader(Uri uri) async => packagesFile.codeUnits; + var file = Uri.parse("krutz://example.com/.packages"); + var resolver = await loadPackagesFile(file, loader: loader); + validatePackagesFile(resolver, file); + }); + + generalTest("loadPackagesFile not found", {}, (Uri directory) async { + var file = directory.resolve(".packages"); + expect( + loadPackagesFile(file), + throwsA(anyOf( + TypeMatcher(), TypeMatcher()))); + }); + + generalTest("loadPackagesFile syntax error", {".packages": "syntax error"}, + (Uri directory) async { + var file = directory.resolve(".packages"); + expect(loadPackagesFile(file), throwsFormatException); + }); + + generalTest("getPackagesDir", { + "packages": {"foo": {}, "bar": {}, "baz": {}} + }, (Uri directory) async { + var packages = directory.resolve("packages/"); + var resolver = getPackagesDirectory(packages); + var resolved = resolver.resolve(pkg("foo", "flip/flop")); + expect(resolved, packages.resolve("foo/flip/flop")); + }); +} + +/// Create a directory structure from [description] and run [fileTest]. +/// +/// Description is a map, each key is a file entry. If the value is a map, +/// it's a sub-dir, otherwise it's a file and the value is the content +/// as a string. +void fileTest(String name, Map description, Future fileTest(Uri directory)) { + group("file-test", () { + var tempDir = Directory.systemTemp.createTempSync("file-test"); + setUp(() { + _createFiles(tempDir, description); + }); + tearDown(() { + tempDir.deleteSync(recursive: true); + }); + test(name, () => fileTest(Uri.file(path.join(tempDir.path, ".")))); + }); +} + +/// HTTP-server the directory structure from [description] and run [htpTest]. +/// +/// Description is a map, each key is a file entry. If the value is a map, +/// it's a sub-dir, otherwise it's a file and the value is the content +/// as a string. +void httpTest(String name, Map description, Future httpTest(Uri directory)) { + group("http-test", () { + var serverSub; + var uri; + setUp(() { + return HttpServer.bind(InternetAddress.loopbackIPv4, 0).then((server) { + uri = Uri( + scheme: "http", host: "127.0.0.1", port: server.port, path: "/"); + serverSub = server.listen((HttpRequest request) { + // No error handling. + var path = request.uri.path; + if (path.startsWith('/')) path = path.substring(1); + if (path.endsWith('/')) path = path.substring(0, path.length - 1); + var parts = path.split('/'); + dynamic fileOrDir = description; + for (var i = 0; i < parts.length; i++) { + fileOrDir = fileOrDir[parts[i]]; + if (fileOrDir == null) { + request.response.statusCode = 404; + request.response.close(); + return; + } + } + request.response.write(fileOrDir); + request.response.close(); + }); + }); + }); + tearDown(() => serverSub.cancel()); + test(name, () => httpTest(uri)); + }); +} + +void generalTest(String name, Map description, Future action(Uri location)) { + fileTest(name, description, action); + httpTest(name, description, action); +} + +void _createFiles(Directory target, Map description) { + description.forEach((name, content) { + if (content is Map) { + var subDir = Directory(path.join(target.path, name)); + subDir.createSync(); + _createFiles(subDir, content); + } else { + var file = File(path.join(target.path, name)); + file.writeAsStringSync(content, flush: true); + } + }); +} diff --git a/pkgs/package_config/test/legacy/parse_test.dart b/pkgs/package_config/test/legacy/parse_test.dart new file mode 100644 index 000000000..b9cf1f8fd --- /dev/null +++ b/pkgs/package_config/test/legacy/parse_test.dart @@ -0,0 +1,246 @@ +// Copyright (c) 2015, 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. + +@deprecated +library package_config.parse_test; + +import "package:package_config/packages.dart"; +import "package:package_config/packages_file.dart" show parse; +import "package:package_config/src/packages_impl.dart"; +import "package:test/test.dart"; + +void main() { + var base = Uri.parse("file:///one/two/three/packages.map"); + test("empty", () { + var packages = doParse(emptySample, base); + expect(packages.asMap(), isEmpty); + }); + test("comment only", () { + var packages = doParse(commentOnlySample, base); + expect(packages.asMap(), isEmpty); + }); + test("empty lines only", () { + var packages = doParse(emptyLinesSample, base); + expect(packages.asMap(), isEmpty); + }); + + test("empty lines only", () { + var packages = doParse(emptyLinesSample, base); + expect(packages.asMap(), isEmpty); + }); + + test("single", () { + var packages = doParse(singleRelativeSample, base); + expect(packages.packages.toList(), equals(["foo"])); + expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), + equals(base.resolve("../test/").resolve("bar/baz.dart"))); + }); + + test("single no slash", () { + var packages = doParse(singleRelativeSampleNoSlash, base); + expect(packages.packages.toList(), equals(["foo"])); + expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), + equals(base.resolve("../test/").resolve("bar/baz.dart"))); + }); + + test("single no newline", () { + var packages = doParse(singleRelativeSampleNoNewline, base); + expect(packages.packages.toList(), equals(["foo"])); + expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), + equals(base.resolve("../test/").resolve("bar/baz.dart"))); + }); + + test("single absolute authority", () { + var packages = doParse(singleAbsoluteSample, base); + expect(packages.packages.toList(), equals(["foo"])); + expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), + equals(Uri.parse("http://example.com/some/where/bar/baz.dart"))); + }); + + test("single empty path", () { + var packages = doParse(singleEmptyPathSample, base); + expect(packages.packages.toList(), equals(["foo"])); + expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), + equals(base.replace(path: "${base.path}/bar/baz.dart"))); + }); + + test("single absolute path", () { + var packages = doParse(singleAbsolutePathSample, base); + expect(packages.packages.toList(), equals(["foo"])); + expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), + equals(base.replace(path: "/test/bar/baz.dart"))); + }); + + test("multiple", () { + var packages = doParse(multiRelativeSample, base); + expect(packages.packages.toList()..sort(), equals(["bar", "foo"])); + expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), + equals(base.resolve("../test/").resolve("bar/baz.dart"))); + expect(packages.resolve(Uri.parse("package:bar/foo/baz.dart")), + equals(base.resolve("../test2/").resolve("foo/baz.dart"))); + }); + + test("dot-dot 1", () { + var packages = doParse(singleRelativeSample, base); + expect(packages.packages.toList(), equals(["foo"])); + expect(packages.resolve(Uri.parse("package:foo/qux/../bar/baz.dart")), + equals(base.resolve("../test/").resolve("bar/baz.dart"))); + }); + + test("all valid chars can be used in URI segment", () { + var packages = doParse(allValidCharsSample, base); + expect(packages.packages.toList(), equals([allValidChars])); + expect(packages.resolve(Uri.parse("package:$allValidChars/bar/baz.dart")), + equals(base.resolve("../test/").resolve("bar/baz.dart"))); + }); + + test("no invalid chars accepted", () { + var map = {}; + for (var i = 0; i < allValidChars.length; i++) { + map[allValidChars.codeUnitAt(i)] = true; + } + for (var i = 0; i <= 255; i++) { + if (map[i] == true) continue; + var char = String.fromCharCode(i); + expect(() => doParse("x${char}x:x", null), + anyOf(throwsNoSuchMethodError, throwsFormatException)); + } + }); + + test("no escapes", () { + expect(() => doParse("x%41x:x", base), throwsFormatException); + }); + + test("same name twice", () { + expect( + () => doParse(singleRelativeSample * 2, base), throwsFormatException); + }); + + test("disallow default package", () { + expect(() => doParse(":foo", base, allowDefaultPackage: false), + throwsFormatException); + }); + + test("allow default package", () { + var packages = doParse(":foo", base, allowDefaultPackage: true); + expect(packages.defaultPackageName, "foo"); + }); + + test("allow default package name with dot", () { + var packages = doParse(":foo.bar", base, allowDefaultPackage: true); + expect(packages.defaultPackageName, "foo.bar"); + }); + + test("not two default packages", () { + expect(() => doParse(":foo\n:bar", base, allowDefaultPackage: true), + throwsFormatException); + }); + + test("default package invalid package name", () { + // Not a valid *package name*. + expect(() => doParse(":foo/bar", base, allowDefaultPackage: true), + throwsFormatException); + }); + + group("metadata", () { + var packages = doParse( + ":foo\n" + "foo:foo#metafoo=1\n" + "bar:bar#metabar=2\n" + "baz:baz\n" + "qux:qux#metaqux1=3&metaqux2=4\n", + base, + allowDefaultPackage: true); + test("non-existing", () { + // non-package name. + expect(packages.packageMetadata("///", "f"), null); + expect(packages.packageMetadata("", "f"), null); + // unconfigured package name. + expect(packages.packageMetadata("absent", "f"), null); + // package name without that metadata + expect(packages.packageMetadata("foo", "notfoo"), null); + }); + test("lookup", () { + expect(packages.packageMetadata("foo", "metafoo"), "1"); + expect(packages.packageMetadata("bar", "metabar"), "2"); + expect(packages.packageMetadata("qux", "metaqux1"), "3"); + expect(packages.packageMetadata("qux", "metaqux2"), "4"); + }); + test("by library URI", () { + expect( + packages.libraryMetadata( + Uri.parse("package:foo/index.dart"), "metafoo"), + "1"); + expect( + packages.libraryMetadata( + Uri.parse("package:bar/index.dart"), "metabar"), + "2"); + expect( + packages.libraryMetadata( + Uri.parse("package:qux/index.dart"), "metaqux1"), + "3"); + expect( + packages.libraryMetadata( + Uri.parse("package:qux/index.dart"), "metaqux2"), + "4"); + }); + test("by default package", () { + expect( + packages.libraryMetadata( + Uri.parse("file:///whatever.dart"), "metafoo"), + "1"); + }); + }); + + for (var invalidSample in invalid) { + test("invalid '$invalidSample'", () { + var result; + try { + result = doParse(invalidSample, base); + } on FormatException { + // expected + return; + } + fail("Resolved to $result"); + }); + } +} + +Packages doParse(String sample, Uri baseUri, + {bool allowDefaultPackage = false}) { + var map = parse(sample.codeUnits, baseUri, + allowDefaultPackage: allowDefaultPackage); + return MapPackages(map); +} + +// Valid samples. +var emptySample = ""; +var commentOnlySample = "# comment only\n"; +var emptyLinesSample = "\n\n\r\n"; +var singleRelativeSample = "foo:../test/\n"; +var singleRelativeSampleNoSlash = "foo:../test\n"; +var singleRelativeSampleNoNewline = "foo:../test/"; +var singleAbsoluteSample = "foo:http://example.com/some/where/\n"; +var singleEmptyPathSample = "foo:\n"; +var singleAbsolutePathSample = "foo:/test/\n"; +var multiRelativeSample = "foo:../test/\nbar:../test2/\n"; +// All valid path segment characters in an URI. +var allValidChars = r"!$&'()*+,-.0123456789;=" + r"@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~"; + +var allValidCharsSample = "${allValidChars}:../test/\n"; + +// Invalid samples. +var invalid = [ + ":baz.dart", // empty. + "foobar=baz.dart", // no colon (but an equals, which is not the same) + ".:../test/", // dot segment + "..:../test/", // dot-dot segment + "...:../test/", // dot-dot-dot segment + "foo/bar:../test/", // slash in name + "/foo:../test/", // slash at start of name + "?:../test/", // invalid characters. + "[:../test/", // invalid characters. + "x#:../test/", // invalid characters. +]; diff --git a/pkgs/package_config/test/legacy/parse_write_test.dart b/pkgs/package_config/test/legacy/parse_write_test.dart new file mode 100644 index 000000000..a51ced1ba --- /dev/null +++ b/pkgs/package_config/test/legacy/parse_write_test.dart @@ -0,0 +1,133 @@ +// Copyright (c) 2015, 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. + +@deprecated +library package_config.parse_write_test; + +import "dart:convert" show utf8; +import "package:package_config/packages_file.dart"; +import "package:test/test.dart"; + +void main() { + void testBase(baseDirString) { + var baseDir = Uri.parse(baseDirString); + group("${baseDir.scheme} base", () { + var packagesFile = baseDir.resolve(".packages"); + + void roundTripTest(String name, Map map) { + group(name, () { + test("write with no baseUri", () { + var content = writeToString(map).codeUnits; + var resultMap = parse(content, packagesFile); + expect(resultMap, map); + }); + + test("write with base directory", () { + var content = writeToString(map, baseUri: baseDir).codeUnits; + var resultMap = parse(content, packagesFile); + expect(resultMap, map); + }); + + test("write with base .packages file", () { + var content = writeToString(map, baseUri: packagesFile).codeUnits; + var resultMap = parse(content, packagesFile); + expect(resultMap, map); + }); + + test("write with defaultPackageName", () { + var content = writeToString( + {'': Uri.parse('my_pkg')}..addAll(map), + allowDefaultPackage: true, + ).codeUnits; + var resultMap = parse( + content, + packagesFile, + allowDefaultPackage: true, + ); + expect(resultMap[''].toString(), 'my_pkg'); + expect( + resultMap, + {'': Uri.parse('my_pkg')}..addAll(map), + ); + }); + + test("write with defaultPackageName (utf8)", () { + var content = utf8.encode(writeToString( + {'': Uri.parse('my_pkg')}..addAll(map), + allowDefaultPackage: true, + )); + var resultMap = parse( + content, + packagesFile, + allowDefaultPackage: true, + ); + expect(resultMap[''].toString(), 'my_pkg'); + expect( + resultMap, + {'': Uri.parse('my_pkg')}..addAll(map), + ); + }); + }); + } + + var lowerDir = baseDir.resolve("path3/path4/"); + var higherDir = baseDir.resolve("../"); + var parallelDir = baseDir.resolve("../path3/"); + var rootDir = baseDir.resolve("/"); + var fileDir = Uri.parse("file:///path1/part2/"); + var httpDir = Uri.parse("http://example.com/path1/path2/"); + var otherDir = Uri.parse("other:/path1/path2/"); + + roundTripTest("empty", {}); + roundTripTest("lower directory", {"foo": lowerDir}); + roundTripTest("higher directory", {"foo": higherDir}); + roundTripTest("parallel directory", {"foo": parallelDir}); + roundTripTest("same directory", {"foo": baseDir}); + roundTripTest("root directory", {"foo": rootDir}); + roundTripTest("file directory", {"foo": fileDir}); + roundTripTest("http directory", {"foo": httpDir}); + roundTripTest("other scheme directory", {"foo": otherDir}); + roundTripTest("multiple same-type directories", + {"foo": lowerDir, "bar": higherDir, "baz": parallelDir}); + roundTripTest("multiple scheme directories", + {"foo": fileDir, "bar": httpDir, "baz": otherDir}); + roundTripTest("multiple scheme directories and mutliple same type", { + "foo": fileDir, + "bar": httpDir, + "baz": otherDir, + "qux": lowerDir, + "hip": higherDir, + "dep": parallelDir + }); + }); + } + + testBase("file:///base1/base2/"); + testBase("http://example.com/base1/base2/"); + testBase("other:/base1/base2/"); + + // Check that writing adds the comment. + test("write preserves comment", () { + var comment = "comment line 1\ncomment line 2\ncomment line 3"; + var result = writeToString({}, comment: comment); + // Comment with "# " before each line and "\n" after last. + var expectedComment = + "# comment line 1\n# comment line 2\n# comment line 3\n"; + expect(result, startsWith(expectedComment)); + }); +} + +String writeToString( + Map map, { + Uri baseUri, + String comment, + bool allowDefaultPackage = false, +}) { + var buffer = StringBuffer(); + write(buffer, map, + baseUri: baseUri, + comment: comment, + allowDefaultPackage: allowDefaultPackage); + return buffer.toString(); +} diff --git a/pkgs/package_config/test/parse_test.dart b/pkgs/package_config/test/parse_test.dart index d9430953c..367b64384 100644 --- a/pkgs/package_config/test/parse_test.dart +++ b/pkgs/package_config/test/parse_test.dart @@ -3,10 +3,11 @@ // BSD-style license that can be found in the LICENSE file. import "dart:convert"; +import 'dart:typed_data'; import "package:test/test.dart"; -import "package:package_config/package_config.dart"; +import "package:package_config/package_config_types.dart"; import "package:package_config/src/packages_file.dart" as packages; import "package:package_config/src/package_config_json.dart"; import "src/util.dart"; @@ -48,14 +49,14 @@ void main() { group("invalid", () { var baseFile = Uri.file("/tmp/file.dart"); - testThrows(String name, String content) { + void testThrows(String name, String content) { test(name, () { expect( () => packages.parse(utf8.encode(content), baseFile, throwError), throwsA(TypeMatcher())); }); test(name + ", handle error", () { - bool hadError = false; + var hadError = false; packages.parse(utf8.encode(content), baseFile, (error) { hadError = true; expect(error, isA()); @@ -256,7 +257,7 @@ void main() { }); group("invalid", () { - testThrows(String name, String source) { + void testThrows(String name, String source) { test(name, () { expect( () => parsePackageConfigBytes(utf8.encode(source), @@ -364,11 +365,79 @@ void main() { "same roots", '{$cfg,"packages":[{$name,$root},{"name":"bar",$root}]}'); testThrows( - // The root of bar is inside the package root of foo. - "inside lib", + // The root of bar is inside the root of foo, + // but the package root of foo is inside the root of bar. + "between root and lib", '{$cfg,"packages":[' - '{"name":"foo","rootUri":"/foo/","packageUri":"lib/"},' - '{"name":"bar","rootUri":"/foo/lib/qux/"}]}'); + '{"name":"foo","rootUri":"/foo/","packageUri":"bar/lib/"},' + '{"name":"bar","rootUri":"/foo/bar/"},"packageUri":"baz/lib"]}'); }); }); + + group("factories", () { + void testConfig(String name, PackageConfig config, PackageConfig expected) { + group(name, () { + test("structure", () { + expect(config.version, expected.version); + var expectedPackages = {for (var p in expected.packages) p.name}; + var actualPackages = {for (var p in config.packages) p.name}; + expect(actualPackages, expectedPackages); + }); + for (var package in config.packages) { + var name = package.name; + test("package $name", () { + var expectedPackage = expected[name]; + expect(expectedPackage, isNotNull); + expect(package.root, expectedPackage.root, reason: "root"); + expect(package.packageUriRoot, expectedPackage.packageUriRoot, + reason: "package root"); + expect(package.languageVersion, expectedPackage.languageVersion, + reason: "languageVersion"); + }); + } + }); + } + + var configText = """ + {"configVersion": 2, "packages": [ + { + "name": "foo", + "rootUri": "foo/", + "packageUri": "bar/", + "languageVersion": "1.2" + } + ]} + """; + var baseUri = Uri.parse("file:///start/"); + var config = PackageConfig([ + Package("foo", Uri.parse("file:///start/foo/"), + packageUriRoot: Uri.parse("file:///start/foo/bar/"), + languageVersion: LanguageVersion(1, 2)) + ]); + testConfig( + "string", PackageConfig.parseString(configText, baseUri), config); + testConfig( + "bytes", + PackageConfig.parseBytes( + Uint8List.fromList(configText.codeUnits), baseUri), + config); + testConfig("json", PackageConfig.parseJson(jsonDecode(configText), baseUri), + config); + + baseUri = Uri.parse("file:///start2/"); + config = PackageConfig([ + Package("foo", Uri.parse("file:///start2/foo/"), + packageUriRoot: Uri.parse("file:///start2/foo/bar/"), + languageVersion: LanguageVersion(1, 2)) + ]); + testConfig( + "string2", PackageConfig.parseString(configText, baseUri), config); + testConfig( + "bytes2", + PackageConfig.parseBytes( + Uint8List.fromList(configText.codeUnits), baseUri), + config); + testConfig("json2", + PackageConfig.parseJson(jsonDecode(configText), baseUri), config); + }); } diff --git a/pkgs/package_config/test/src/util.dart b/pkgs/package_config/test/src/util.dart index 95670bdbb..2b91b2130 100644 --- a/pkgs/package_config/test/src/util.dart +++ b/pkgs/package_config/test/src/util.dart @@ -18,7 +18,7 @@ import "package:package_config/src/util.dart"; void fileTest(String name, Map description, void fileTest(Directory directory)) { group("file-test", () { - Directory tempDir = Directory.systemTemp.createTempSync("pkgcfgtest"); + var tempDir = Directory.systemTemp.createTempSync("pkgcfgtest"); setUp(() { _createFiles(tempDir, description); }); @@ -67,7 +67,7 @@ File dirFile(Directory directory, String fileName) => Uri pkg(String packageName, String packagePath) { var path = "$packageName${packagePath.startsWith('/') ? "" : "/"}$packagePath"; - return new Uri(scheme: "package", path: path); + return Uri(scheme: "package", path: path); } // Remove if not used. @@ -91,13 +91,13 @@ ${packages.map((nu) => """ /// as a string. void loaderTest(String name, Map description, void loaderTest(Uri root, Future loader(Uri uri))) { - Uri root = Uri(scheme: "test", path: "/"); + var root = Uri(scheme: "test", path: "/"); Future loader(Uri uri) async { var path = uri.path; if (!uri.isScheme("test") || !path.startsWith("/")) return null; var parts = path.split("/"); dynamic value = description; - for (int i = 1; i < parts.length; i++) { + for (var i = 1; i < parts.length; i++) { if (value is! Map) return null; value = value[parts[i]]; } From af58162f9d26235eed94104c4a7c2c522ac68b1c Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Wed, 26 Feb 2020 00:09:03 -0800 Subject: [PATCH 085/170] Tweak readme (dart-lang/package_config#69) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Tweak readme Remove gratuitous title Move badges to top, as is tradition * Update README.md Remove issue/feature request blurb – this is automatically done on the pub site! --- pkgs/package_config/README.md | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/pkgs/package_config/README.md b/pkgs/package_config/README.md index ec51f6ea7..5a76a7ab1 100644 --- a/pkgs/package_config/README.md +++ b/pkgs/package_config/README.md @@ -1,4 +1,5 @@ -# package_config +[![Build Status](https://travis-ci.org/dart-lang/package_config.svg?branch=master)](https://travis-ci.org/dart-lang/package_config) +[![pub package](https://img.shields.io/pub/v/package_config.svg)](https://pub.dartlang.org/packages/package_config) Support for working with **Package Configuration** files as described in the Package Configuration v2 [design document](https://github.com/dart-lang/language/blob/master/accepted/future-releases/language-versioning/package-config-file-v2.md). @@ -15,11 +16,3 @@ The primary libraries are The package includes deprecated backwards compatible functionality to work with the `.packages` file. This functionality will not be maintained, and will be removed in a future version of this package. - -[![Build Status](https://travis-ci.org/dart-lang/package_config.svg?branch=master)](https://travis-ci.org/dart-lang/package_config) [![pub package](https://img.shields.io/pub/v/package_config.svg)](https://pub.dartlang.org/packages/package_config) - -## Features and bugs - -Please file feature requests and bugs at the [issue tracker][tracker]. - -[tracker]: https://github.com/dart-lang/package_config/issues From b69e8ac948775b58bffe2f119eb1e88ce754cc56 Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Wed, 26 Feb 2020 09:10:03 +0100 Subject: [PATCH 086/170] Remove 1.2.0 from changelog. That version was never released. --- pkgs/package_config/CHANGELOG.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index c6caf4d6e..a86d1a54f 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -5,11 +5,6 @@ version, as well as the, now deprecated, version 1 functionality. When we release 2.0.0, the deprectated functionality will be removed. -## 1.2.0 - -- Added support for writing default-package entries. -- Fixed bug when writing `Uri`s containing a fragment. - ## 1.1.0 - Allow parsing files with default-package entries and metadata. From 267c75ab3c875d335cf294a10de340713a62ac4a Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Wed, 26 Feb 2020 08:50:41 -0800 Subject: [PATCH 087/170] Remove pubspec author, fix URL in readme (dart-lang/package_config#71) --- pkgs/package_config/README.md | 2 +- pkgs/package_config/pubspec.yaml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/pkgs/package_config/README.md b/pkgs/package_config/README.md index 5a76a7ab1..b47a6825b 100644 --- a/pkgs/package_config/README.md +++ b/pkgs/package_config/README.md @@ -1,5 +1,5 @@ [![Build Status](https://travis-ci.org/dart-lang/package_config.svg?branch=master)](https://travis-ci.org/dart-lang/package_config) -[![pub package](https://img.shields.io/pub/v/package_config.svg)](https://pub.dartlang.org/packages/package_config) +[![pub package](https://img.shields.io/pub/v/package_config.svg)](https://pub.dev/packages/package_config) Support for working with **Package Configuration** files as described in the Package Configuration v2 [design document](https://github.com/dart-lang/language/blob/master/accepted/future-releases/language-versioning/package-config-file-v2.md). diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 20a39c767..0eaeeda93 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,7 +1,6 @@ name: package_config version: 1.9.0-dev description: Support for working with Package Configuration files. -author: Dart Team homepage: https://github.com/dart-lang/package_config environment: From 45477a6a7d1f62d4c4f97efa0e45bc685321e530 Mon Sep 17 00:00:00 2001 From: Lasse Nielsen Date: Wed, 26 Feb 2020 19:18:52 +0000 Subject: [PATCH 088/170] Add missing dependency on package:path. --- pkgs/package_config/pubspec.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 0eaeeda93..c37dda616 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -6,6 +6,9 @@ homepage: https://github.com/dart-lang/package_config environment: sdk: '>=2.7.0 <3.0.0' +dependencies: + path: ^1.6.4 + dev_dependencies: test: ^1.6.4 matcher: ^0.12.5 From 48ab5081081ff91362dde900a1f0cbea9138e150 Mon Sep 17 00:00:00 2001 From: Lasse Nielsen Date: Wed, 26 Feb 2020 19:23:20 +0000 Subject: [PATCH 089/170] Add another missing dependency. --- pkgs/package_config/pubspec.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index c37dda616..651dbec28 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -8,6 +8,7 @@ environment: dependencies: path: ^1.6.4 + charcode: ^1.1.0 dev_dependencies: test: ^1.6.4 From 6c4b1492ffbdea9becd3acf41b3b43e2ff06962b Mon Sep 17 00:00:00 2001 From: Lasse Nielsen Date: Wed, 26 Feb 2020 19:31:03 +0000 Subject: [PATCH 090/170] Set version to 1.9.0 (no -dev) for release. --- pkgs/package_config/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 651dbec28..abaddd9e9 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 1.9.0-dev +version: 1.9.0 description: Support for working with Package Configuration files. homepage: https://github.com/dart-lang/package_config From 6d7290406dd7f7416212eeb4361405b0b2d1f32a Mon Sep 17 00:00:00 2001 From: Jacob MacDonald Date: Wed, 26 Feb 2020 14:30:43 -0800 Subject: [PATCH 091/170] move io utils to their own library, release 1.9.1 (dart-lang/package_config#74) --- pkgs/package_config/.travis.yml | 5 + pkgs/package_config/CHANGELOG.md | 5 + pkgs/package_config/lib/src/discovery.dart | 2 +- .../lib/src/package_config_io.dart | 1 + .../lib/src/packages_io_impl.dart | 2 +- pkgs/package_config/lib/src/util.dart | 99 ---------------- pkgs/package_config/lib/src/util_io.dart | 106 ++++++++++++++++++ pkgs/package_config/pubspec.yaml | 5 +- pkgs/package_config/test/discovery_test.dart | 2 + .../test/discovery_uri_test.dart | 1 + .../test/legacy/discovery_analysis_test.dart | 1 + .../test/legacy/discovery_test.dart | 1 + pkgs/package_config/test/src/util.dart | 56 --------- pkgs/package_config/test/src/util_io.dart | 62 ++++++++++ 14 files changed, 190 insertions(+), 158 deletions(-) create mode 100644 pkgs/package_config/lib/src/util_io.dart create mode 100644 pkgs/package_config/test/src/util_io.dart diff --git a/pkgs/package_config/.travis.yml b/pkgs/package_config/.travis.yml index 655bf3dc1..09fc296c2 100644 --- a/pkgs/package_config/.travis.yml +++ b/pkgs/package_config/.travis.yml @@ -7,6 +7,11 @@ dart_task: - dartfmt - dartanalyzer: --fatal-warnings . +matrix: + include: + - dart: dev + script: pub run build_runner test -- -p chrome + # Only building master means that we don't run two builds for each pull request. branches: only: [master] diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index a86d1a54f..1cd45d007 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.9.1 + +- Remove accidental transitive import of `dart:io` from entrypoints that are + supposed to be cross-platform compatible. + ## 1.9.0 - Based on new JSON file format with more content. diff --git a/pkgs/package_config/lib/src/discovery.dart b/pkgs/package_config/lib/src/discovery.dart index 5d3172f26..8ac6a0128 100644 --- a/pkgs/package_config/lib/src/discovery.dart +++ b/pkgs/package_config/lib/src/discovery.dart @@ -11,7 +11,7 @@ import "errors.dart"; import "package_config_impl.dart"; import "package_config_json.dart"; import "packages_file.dart" as packages_file; -import "util.dart" show defaultLoader, pathJoin; +import "util_io.dart" show defaultLoader, pathJoin; final Uri packageConfigJsonPath = Uri(path: ".dart_tool/package_config.json"); final Uri dotPackagesPath = Uri(path: ".packages"); diff --git a/pkgs/package_config/lib/src/package_config_io.dart b/pkgs/package_config/lib/src/package_config_io.dart index d59972f9a..954be6b1e 100644 --- a/pkgs/package_config/lib/src/package_config_io.dart +++ b/pkgs/package_config/lib/src/package_config_io.dart @@ -14,6 +14,7 @@ import "package_config_impl.dart"; import "package_config_json.dart"; import "packages_file.dart" as packages_file; import "util.dart"; +import "util_io.dart"; /// Reads a package configuration file. /// diff --git a/pkgs/package_config/lib/src/packages_io_impl.dart b/pkgs/package_config/lib/src/packages_io_impl.dart index b2277e7e0..c623f4d5d 100644 --- a/pkgs/package_config/lib/src/packages_io_impl.dart +++ b/pkgs/package_config/lib/src/packages_io_impl.dart @@ -12,7 +12,7 @@ import "dart:io" show Directory; import "packages_impl.dart"; -import "util.dart"; +import "util_io.dart"; /// A [Packages] implementation based on a local directory. class FilePackagesDirectoryPackages extends PackagesBase { diff --git a/pkgs/package_config/lib/src/util.dart b/pkgs/package_config/lib/src/util.dart index 548f61d98..50b140fa0 100644 --- a/pkgs/package_config/lib/src/util.dart +++ b/pkgs/package_config/lib/src/util.dart @@ -5,9 +5,6 @@ /// Utility methods used by more than one library in the package. library package_config.util; -import 'dart:io'; -import 'dart:typed_data'; - import "errors.dart"; // All ASCII characters that are valid in a package name, with space @@ -215,102 +212,6 @@ Uri relativizeUri(Uri uri, Uri /*?*/ baseUri) { } } -Future defaultLoader(Uri uri) async { - if (uri.isScheme("file")) { - var file = File.fromUri(uri); - try { - return file.readAsBytes(); - } catch (_) { - return null; - } - } - if (uri.isScheme("http") || uri.isScheme("https")) { - return _httpGet(uri); - } - throw UnsupportedError("Default URI unsupported scheme: $uri"); -} - -Future _httpGet(Uri uri) async { - assert(uri.isScheme("http") || uri.isScheme("https")); - var client = HttpClient(); - var request = await client.getUrl(uri); - var response = await request.close(); - if (response.statusCode != HttpStatus.ok) { - return null; - } - var splitContent = await response.toList(); - var totalLength = 0; - if (splitContent.length == 1) { - var part = splitContent[0]; - if (part is Uint8List) { - return part; - } - } - for (var list in splitContent) { - totalLength += list.length; - } - var result = Uint8List(totalLength); - var offset = 0; - for (Uint8List contentPart in splitContent) { - result.setRange(offset, offset + contentPart.length, contentPart); - offset += contentPart.length; - } - return result; -} - -/// The file name of a path. -/// -/// The file name is everything after the last occurrence of -/// [Platform.pathSeparator], or the entire string if no -/// path separator occurs in the string. -String fileName(String path) { - var separator = Platform.pathSeparator; - var lastSeparator = path.lastIndexOf(separator); - if (lastSeparator < 0) return path; - return path.substring(lastSeparator + separator.length); -} - -/// The directory name of a path. -/// -/// The directory name is everything before the last occurrence of -/// [Platform.pathSeparator], or the empty string if no -/// path separator occurs in the string. -String dirName(String path) { - var separator = Platform.pathSeparator; - var lastSeparator = path.lastIndexOf(separator); - if (lastSeparator < 0) return ""; - return path.substring(0, lastSeparator); -} - -/// Join path parts with the [Platform.pathSeparator]. -/// -/// If a part ends with a path separator, then no extra separator is -/// inserted. -String pathJoin(String part1, String part2, [String part3]) { - var separator = Platform.pathSeparator; - var separator1 = part1.endsWith(separator) ? "" : separator; - if (part3 == null) { - return "$part1$separator1$part2"; - } - var separator2 = part2.endsWith(separator) ? "" : separator; - return "$part1$separator1$part2$separator2$part3"; -} - -/// Join an unknown number of path parts with [Platform.pathSeparator]. -/// -/// If a part ends with a path separator, then no extra separator is -/// inserted. -String pathJoinAll(Iterable parts) { - var buffer = StringBuffer(); - var separator = ""; - for (var part in parts) { - buffer..write(separator)..write(part); - separator = - part.endsWith(Platform.pathSeparator) ? "" : Platform.pathSeparator; - } - return buffer.toString(); -} - // Character constants used by this package. /// "Line feed" control character. const int $lf = 0x0a; diff --git a/pkgs/package_config/lib/src/util_io.dart b/pkgs/package_config/lib/src/util_io.dart new file mode 100644 index 000000000..7f21a8dcd --- /dev/null +++ b/pkgs/package_config/lib/src/util_io.dart @@ -0,0 +1,106 @@ +// Copyright (c) 2020, 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. + +/// Utility methods requiring dart:io and used by more than one library in the +/// package. +library package_config.util_io; + +import 'dart:io'; +import 'dart:typed_data'; + +Future defaultLoader(Uri uri) async { + if (uri.isScheme("file")) { + var file = File.fromUri(uri); + try { + return file.readAsBytes(); + } catch (_) { + return null; + } + } + if (uri.isScheme("http") || uri.isScheme("https")) { + return _httpGet(uri); + } + throw UnsupportedError("Default URI unsupported scheme: $uri"); +} + +Future _httpGet(Uri uri) async { + assert(uri.isScheme("http") || uri.isScheme("https")); + var client = HttpClient(); + var request = await client.getUrl(uri); + var response = await request.close(); + if (response.statusCode != HttpStatus.ok) { + return null; + } + var splitContent = await response.toList(); + var totalLength = 0; + if (splitContent.length == 1) { + var part = splitContent[0]; + if (part is Uint8List) { + return part; + } + } + for (var list in splitContent) { + totalLength += list.length; + } + var result = Uint8List(totalLength); + var offset = 0; + for (Uint8List contentPart in splitContent) { + result.setRange(offset, offset + contentPart.length, contentPart); + offset += contentPart.length; + } + return result; +} + +/// The file name of a path. +/// +/// The file name is everything after the last occurrence of +/// [Platform.pathSeparator], or the entire string if no +/// path separator occurs in the string. +String fileName(String path) { + var separator = Platform.pathSeparator; + var lastSeparator = path.lastIndexOf(separator); + if (lastSeparator < 0) return path; + return path.substring(lastSeparator + separator.length); +} + +/// The directory name of a path. +/// +/// The directory name is everything before the last occurrence of +/// [Platform.pathSeparator], or the empty string if no +/// path separator occurs in the string. +String dirName(String path) { + var separator = Platform.pathSeparator; + var lastSeparator = path.lastIndexOf(separator); + if (lastSeparator < 0) return ""; + return path.substring(0, lastSeparator); +} + +/// Join path parts with the [Platform.pathSeparator]. +/// +/// If a part ends with a path separator, then no extra separator is +/// inserted. +String pathJoin(String part1, String part2, [String part3]) { + var separator = Platform.pathSeparator; + var separator1 = part1.endsWith(separator) ? "" : separator; + if (part3 == null) { + return "$part1$separator1$part2"; + } + var separator2 = part2.endsWith(separator) ? "" : separator; + return "$part1$separator1$part2$separator2$part3"; +} + +/// Join an unknown number of path parts with [Platform.pathSeparator]. +/// +/// If a part ends with a path separator, then no extra separator is +/// inserted. +String pathJoinAll(Iterable parts) { + var buffer = StringBuffer(); + var separator = ""; + for (var part in parts) { + buffer..write(separator)..write(part); + separator = + part.endsWith(Platform.pathSeparator) ? "" : Platform.pathSeparator; + } + return buffer.toString(); +} diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index abaddd9e9..5299fdf79 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 1.9.0 +version: 1.9.1 description: Support for working with Package Configuration files. homepage: https://github.com/dart-lang/package_config @@ -14,3 +14,6 @@ dev_dependencies: test: ^1.6.4 matcher: ^0.12.5 pedantic: 1.8.0 + build_runner: ^1.0.0 + build_web_compilers: ^2.0.0 + build_test: ^0.10.0 diff --git a/pkgs/package_config/test/discovery_test.dart b/pkgs/package_config/test/discovery_test.dart index e4c93a592..1a9a61c1f 100644 --- a/pkgs/package_config/test/discovery_test.dart +++ b/pkgs/package_config/test/discovery_test.dart @@ -2,6 +2,7 @@ // 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. +@TestOn('vm') library package_config.discovery_test; import "dart:io"; @@ -9,6 +10,7 @@ import "package:test/test.dart"; import "package:package_config/package_config.dart"; import "src/util.dart"; +import "src/util_io.dart"; const packagesFile = """ # A comment diff --git a/pkgs/package_config/test/discovery_uri_test.dart b/pkgs/package_config/test/discovery_uri_test.dart index 109693c4c..52fca3ffa 100644 --- a/pkgs/package_config/test/discovery_uri_test.dart +++ b/pkgs/package_config/test/discovery_uri_test.dart @@ -2,6 +2,7 @@ // 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. +@TestOn('vm') library package_config.discovery_test; import "package:test/test.dart"; diff --git a/pkgs/package_config/test/legacy/discovery_analysis_test.dart b/pkgs/package_config/test/legacy/discovery_analysis_test.dart index 7d08f7b92..4be636d13 100644 --- a/pkgs/package_config/test/legacy/discovery_analysis_test.dart +++ b/pkgs/package_config/test/legacy/discovery_analysis_test.dart @@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. @deprecated +@TestOn('vm') library package_config.discovery_analysis_test; import "dart:async"; diff --git a/pkgs/package_config/test/legacy/discovery_test.dart b/pkgs/package_config/test/legacy/discovery_test.dart index 684abcb4a..72874c8df 100644 --- a/pkgs/package_config/test/legacy/discovery_test.dart +++ b/pkgs/package_config/test/legacy/discovery_test.dart @@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. @deprecated +@TestOn('vm') library package_config.discovery_test; import "dart:async"; diff --git a/pkgs/package_config/test/src/util.dart b/pkgs/package_config/test/src/util.dart index 2b91b2130..6e689b734 100644 --- a/pkgs/package_config/test/src/util.dart +++ b/pkgs/package_config/test/src/util.dart @@ -3,65 +3,9 @@ // BSD-style license that can be found in the LICENSE file. import 'dart:convert'; -import "dart:io"; import 'dart:typed_data'; import "package:test/test.dart"; -import "package:package_config/src/util.dart"; - -/// Creates a directory structure from [description] and runs [fileTest]. -/// -/// Description is a map, each key is a file entry. If the value is a map, -/// it's a subdirectory, otherwise it's a file and the value is the content -/// as a string. -/// Introduces a group to hold the [setUp]/[tearDown] logic. -void fileTest(String name, Map description, - void fileTest(Directory directory)) { - group("file-test", () { - var tempDir = Directory.systemTemp.createTempSync("pkgcfgtest"); - setUp(() { - _createFiles(tempDir, description); - }); - tearDown(() { - tempDir.deleteSync(recursive: true); - }); - test(name, () => fileTest(tempDir)); - }); -} - -/// Creates a set of files under a new temporary directory. -/// Returns the temporary directory. -/// -/// The [description] is a map from file names to content. -/// If the content is again a map, it represents a subdirectory -/// with the content as description. -/// Otherwise the content should be a string, -/// which is written to the file as UTF-8. -Directory createTestFiles(Map description) { - var target = Directory.systemTemp.createTempSync("pkgcfgtest"); - _createFiles(target, description); - return target; -} - -// Creates temporary files in the target directory. -void _createFiles(Directory target, Map description) { - description.forEach((name, content) { - var entryName = pathJoin(target.path, "$name"); - if (content is Map) { - _createFiles(Directory(entryName)..createSync(), content); - } else { - File(entryName).writeAsStringSync(content, flush: true); - } - }); -} - -/// Creates a [Directory] for a subdirectory of [parent]. -Directory subdir(Directory parent, String dirName) => - Directory(pathJoinAll([parent.path, ...dirName.split("/")])); - -/// Creates a [File] for an entry in the [directory] directory. -File dirFile(Directory directory, String fileName) => - File(pathJoin(directory.path, fileName)); /// Creates a package: URI. Uri pkg(String packageName, String packagePath) { diff --git a/pkgs/package_config/test/src/util_io.dart b/pkgs/package_config/test/src/util_io.dart new file mode 100644 index 000000000..d05618a07 --- /dev/null +++ b/pkgs/package_config/test/src/util_io.dart @@ -0,0 +1,62 @@ +// Copyright (c) 2020, 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. + +import "dart:io"; + +import "package:test/test.dart"; +import "package:package_config/src/util_io.dart"; + +/// Creates a directory structure from [description] and runs [fileTest]. +/// +/// Description is a map, each key is a file entry. If the value is a map, +/// it's a subdirectory, otherwise it's a file and the value is the content +/// as a string. +/// Introduces a group to hold the [setUp]/[tearDown] logic. +void fileTest(String name, Map description, + void fileTest(Directory directory)) { + group("file-test", () { + var tempDir = Directory.systemTemp.createTempSync("pkgcfgtest"); + setUp(() { + _createFiles(tempDir, description); + }); + tearDown(() { + tempDir.deleteSync(recursive: true); + }); + test(name, () => fileTest(tempDir)); + }); +} + +/// Creates a set of files under a new temporary directory. +/// Returns the temporary directory. +/// +/// The [description] is a map from file names to content. +/// If the content is again a map, it represents a subdirectory +/// with the content as description. +/// Otherwise the content should be a string, +/// which is written to the file as UTF-8. +Directory createTestFiles(Map description) { + var target = Directory.systemTemp.createTempSync("pkgcfgtest"); + _createFiles(target, description); + return target; +} + +// Creates temporary files in the target directory. +void _createFiles(Directory target, Map description) { + description.forEach((name, content) { + var entryName = pathJoin(target.path, "$name"); + if (content is Map) { + _createFiles(Directory(entryName)..createSync(), content); + } else { + File(entryName).writeAsStringSync(content, flush: true); + } + }); +} + +/// Creates a [Directory] for a subdirectory of [parent]. +Directory subdir(Directory parent, String dirName) => + Directory(pathJoinAll([parent.path, ...dirName.split("/")])); + +/// Creates a [File] for an entry in the [directory] directory. +File dirFile(Directory directory, String fileName) => + File(pathJoin(directory.path, fileName)); From 76d2d33cb621ba722603ac4a7c35a8892a2ad3de Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Wed, 26 Feb 2020 14:35:04 -0800 Subject: [PATCH 092/170] Fix reference to pedantic lints (dart-lang/package_config#73) --- pkgs/package_config/analysis_options.yaml | 2 +- pkgs/package_config/pubspec.yaml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pkgs/package_config/analysis_options.yaml b/pkgs/package_config/analysis_options.yaml index 82c00e5c8..66639ec1a 100644 --- a/pkgs/package_config/analysis_options.yaml +++ b/pkgs/package_config/analysis_options.yaml @@ -2,7 +2,7 @@ # 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. -include: package:pedantic/analysis_options.yaml +include: package:pedantic/analysis_options.1.9.0.yaml analyzer: errors: annotate_overrides: ignore diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 5299fdf79..5c0589145 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -13,7 +13,8 @@ dependencies: dev_dependencies: test: ^1.6.4 matcher: ^0.12.5 - pedantic: 1.8.0 + pedantic: ^1.8.0 + build_runner: ^1.0.0 build_web_compilers: ^2.0.0 build_test: ^0.10.0 From c1b6ac18cc49dc3c924c9798ffec420961987d1c Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Wed, 26 Feb 2020 15:52:13 -0800 Subject: [PATCH 093/170] Fix version constraint on pkg:pedantic --- pkgs/package_config/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 5c0589145..853c0514b 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: dev_dependencies: test: ^1.6.4 matcher: ^0.12.5 - pedantic: ^1.8.0 + pedantic: ^1.9.0 build_runner: ^1.0.0 build_web_compilers: ^2.0.0 From c886dde0251b2e78b6824da7ef2f8462c8e578a9 Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Thu, 12 Mar 2020 12:47:02 +0100 Subject: [PATCH 094/170] Change to only look for package_config.json if asked for .packages by name. (dart-lang/package_config#78) Some clean-up. --- pkgs/package_config/CHANGELOG.md | 5 ++ pkgs/package_config/lib/package_config.dart | 8 ++- .../lib/src/package_config_io.dart | 70 +++++++++---------- .../lib/src/package_config_json.dart | 11 ++- pkgs/package_config/lib/src/util_io.dart | 2 +- pkgs/package_config/pubspec.yaml | 2 +- pkgs/package_config/test/discovery_test.dart | 6 +- .../test/discovery_uri_test.dart | 25 ++++--- 8 files changed, 63 insertions(+), 66 deletions(-) diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index 1cd45d007..0b5e1563e 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.9.2 + +- Updated to support new rules for picking `package_config.json` over + a specified `.packages`. + ## 1.9.1 - Remove accidental transitive import of `dart:io` from entrypoints that are diff --git a/pkgs/package_config/lib/package_config.dart b/pkgs/package_config/lib/package_config.dart index bca865d70..1113ac872 100644 --- a/pkgs/package_config/lib/package_config.dart +++ b/pkgs/package_config/lib/package_config.dart @@ -24,9 +24,10 @@ export "package_config_types.dart"; /// It is considered a `package_config.json` file if its first character /// is a `{`. /// -/// If the file is a `.packages` file and [preferNewest] is true, the default, -/// also checks if there is a `.dart_tool/package_config.json` file next to the original file, -/// and if so, loads that instead. +/// If the file is a `.packages` file (the file name is `.packages`) +/// and [preferNewest] is true, the default, also checks if there is +/// a `.dart_tool/package_config.json` file next +/// to the original file, and if so, loads that instead. /// If [preferNewest] is set to false, a directly specified `.packages` file /// is loaded even if there is an available `package_config.json` file. /// The caller can determine this from the [PackageConfig.version] @@ -50,6 +51,7 @@ Future loadPackageConfig(File file, /// non-whitespace character is a `{`. /// /// If [preferNewest] is true, the default, and the file is a `.packages` file, +/// as determined by its file name being `.packages`, /// first checks if there is a `.dart_tool/package_config.json` file /// next to the original file, and if so, loads that instead. /// The [file] *must not* be a `package:` URI. diff --git a/pkgs/package_config/lib/src/package_config_io.dart b/pkgs/package_config/lib/src/package_config_io.dart index 954be6b1e..31bc1cc99 100644 --- a/pkgs/package_config/lib/src/package_config_io.dart +++ b/pkgs/package_config/lib/src/package_config_io.dart @@ -30,6 +30,13 @@ import "util_io.dart"; /// The file must exist and be a normal file. Future readAnyConfigFile( File file, bool preferNewest, void onError(Object error)) async { + if (preferNewest && fileName(file.path) == ".packages") { + var alternateFile = + File(pathJoin(dirName(file.path), ".dart_tool", "package_config.json")); + if (alternateFile.existsSync()) { + return await readPackageConfigJsonFile(alternateFile, onError); + } + } Uint8List bytes; try { bytes = await file.readAsBytes(); @@ -37,28 +44,7 @@ Future readAnyConfigFile( onError(e); return const SimplePackageConfig.empty(); } - var firstChar = firstNonWhitespaceChar(bytes); - if (firstChar != $lbrace) { - // Definitely not a JSON object, probably a .packages. - if (preferNewest) { - var alternateFile = File( - pathJoin(dirName(file.path), ".dart_tool", "package_config.json")); - if (alternateFile.existsSync()) { - Uint8List /*?*/ bytes; - try { - bytes = await alternateFile.readAsBytes(); - } catch (e) { - onError(e); - return const SimplePackageConfig.empty(); - } - if (bytes != null) { - return parsePackageConfigBytes(bytes, alternateFile.uri, onError); - } - } - } - return packages_file.parse(bytes, file.uri, onError); - } - return parsePackageConfigBytes(bytes, file.uri, onError); + return parseAnyConfigFile(bytes, file.uri, onError); } /// Like [readAnyConfigFile] but uses a URI and an optional loader. @@ -73,11 +59,24 @@ Future readAnyConfigFileUri( } if (loader == null) { if (file.isScheme("file")) { - return readAnyConfigFile(File.fromUri(file), preferNewest, onError); + return await readAnyConfigFile(File.fromUri(file), preferNewest, onError); } loader = defaultLoader; } - Uint8List bytes; + if (preferNewest && file.pathSegments.last == ".packages") { + var alternateFile = file.resolve(".dart_tool/package_config.json"); + Uint8List /*?*/ bytes; + try { + bytes = await loader(alternateFile); + } catch (e) { + onError(e); + return const SimplePackageConfig.empty(); + } + if (bytes != null) { + return parsePackageConfigBytes(bytes, alternateFile, onError); + } + } + Uint8List /*?*/ bytes; try { bytes = await loader(file); } catch (e) { @@ -89,23 +88,18 @@ Future readAnyConfigFileUri( file.toString(), "file", "File cannot be read")); return const SimplePackageConfig.empty(); } + return parseAnyConfigFile(bytes, file, onError); +} + +/// Parses a `.packages` or `package_config.json` file's contents. +/// +/// Assumes it's a JSON file if the first non-whitespace character +/// is `{`, otherwise assumes it's a `.packages` file. +PackageConfig parseAnyConfigFile( + Uint8List bytes, Uri file, void onError(Object error)) { var firstChar = firstNonWhitespaceChar(bytes); if (firstChar != $lbrace) { // Definitely not a JSON object, probably a .packages. - if (preferNewest) { - // Check if there is a package_config.json file. - var alternateFile = file.resolveUri(packageConfigJsonPath); - Uint8List alternateBytes; - try { - alternateBytes = await loader(alternateFile); - } catch (e) { - onError(e); - return const SimplePackageConfig.empty(); - } - if (alternateBytes != null) { - return parsePackageConfigBytes(alternateBytes, alternateFile, onError); - } - } return packages_file.parse(bytes, file, onError); } return parsePackageConfigBytes(bytes, file, onError); diff --git a/pkgs/package_config/lib/src/package_config_json.dart b/pkgs/package_config/lib/src/package_config_json.dart index b9b34165b..27abf505c 100644 --- a/pkgs/package_config/lib/src/package_config_json.dart +++ b/pkgs/package_config/lib/src/package_config_json.dart @@ -39,7 +39,7 @@ PackageConfig parsePackageConfigBytes( try { jsonObject = _jsonUtf8Decoder.convert(bytes); } on FormatException catch (e) { - onError(PackageConfigFormatException(e.message, e.source, e.offset)); + onError(PackageConfigFormatException.from(e)); return const SimplePackageConfig.empty(); } return parsePackageConfigJson(jsonObject, file, onError); @@ -51,7 +51,7 @@ PackageConfig parsePackageConfigString( try { jsonObject = jsonDecode(source); } on FormatException catch (e) { - onError(PackageConfigFormatException(e.message, e.source, e.offset)); + onError(PackageConfigFormatException.from(e)); return const SimplePackageConfig.empty(); } return parsePackageConfigJson(jsonObject, file, onError); @@ -271,7 +271,6 @@ void writeDotPackages(PackageConfig config, Uri baseUri, StringSink output) { } } packages_file.write(output, config, baseUri: baseUri, comment: comment); - return; } /// If "extraData" is a JSON map, then return it, otherwise return null. @@ -304,12 +303,10 @@ bool _validateJson(dynamic object) { if (object == null || true == object || false == object) return true; if (object is num || object is String) return true; if (object is List) { - for (var element in object) if (!_validateJson(element)) return false; - return true; + return object.every(_validateJson); } if (object is Map) { - for (var value in object.values) if (!_validateJson(value)) return false; - return true; + return object.values.every(_validateJson); } return false; } diff --git a/pkgs/package_config/lib/src/util_io.dart b/pkgs/package_config/lib/src/util_io.dart index 7f21a8dcd..2aa8c94bf 100644 --- a/pkgs/package_config/lib/src/util_io.dart +++ b/pkgs/package_config/lib/src/util_io.dart @@ -13,7 +13,7 @@ Future defaultLoader(Uri uri) async { if (uri.isScheme("file")) { var file = File.fromUri(uri); try { - return file.readAsBytes(); + return await file.readAsBytes(); } catch (_) { return null; } diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 853c0514b..3f5ec27e0 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 1.9.1 +version: 1.9.2 description: Support for working with Package Configuration files. homepage: https://github.com/dart-lang/package_config diff --git a/pkgs/package_config/test/discovery_test.dart b/pkgs/package_config/test/discovery_test.dart index 1a9a61c1f..5cbc99214 100644 --- a/pkgs/package_config/test/discovery_test.dart +++ b/pkgs/package_config/test/discovery_test.dart @@ -301,13 +301,13 @@ void main() { }); // Find package_config.json in subdir even if initial file syntax error. - fileTest("specified file syntax error", { - "anyname": "syntax error", + fileTest("specified file syntax onError", { + ".packages": "syntax error", ".dart_tool": { "package_config.json": packageConfigFile, }, }, (Directory directory) async { - var file = dirFile(directory, "anyname"); + var file = dirFile(directory, ".packages"); var config = await loadPackageConfig(file); expect(config.version, 2); validatePackagesFile(config, directory); diff --git a/pkgs/package_config/test/discovery_uri_test.dart b/pkgs/package_config/test/discovery_uri_test.dart index 52fca3ffa..23c02d7bc 100644 --- a/pkgs/package_config/test/discovery_uri_test.dart +++ b/pkgs/package_config/test/discovery_uri_test.dart @@ -60,7 +60,7 @@ void main() { ".dart_tool": { "package_config.json": packageConfigFile, } - }, (Uri directory, loader) async { + }, (directory, loader) async { var config = await findPackageConfigUri(directory, loader: loader); expect(config.version, 2); // Found package_config.json file. validatePackagesFile(config, directory); @@ -71,7 +71,7 @@ void main() { ".packages": packagesFile, "script.dart": "main(){}", "packages": {"shouldNotBeFound": {}} - }, (Uri directory, loader) async { + }, (directory, loader) async { var config = await findPackageConfigUri(directory, loader: loader); expect(config.version, 1); // Found .packages file. validatePackagesFile(config, directory); @@ -86,7 +86,7 @@ void main() { "subdir": { "script.dart": "main(){}", } - }, (Uri directory, loader) async { + }, (directory, loader) async { var config = await findPackageConfigUri(directory.resolve("subdir/"), loader: loader); expect(config.version, 2); @@ -97,7 +97,7 @@ void main() { loaderTest(".packages recursive", { ".packages": packagesFile, "subdir": {"script.dart": "main(){}"} - }, (Uri directory, loader) async { + }, (directory, loader) async { var config; config = await findPackageConfigUri(directory.resolve("subdir/"), loader: loader); @@ -240,9 +240,9 @@ void main() { throwsFormatException); }); - loaderTest("specified file syntax error", { + loaderTest("specified file syntax onError", { "anyname": "syntax error", - }, (Uri directory, loader) async { + }, (directory, loader) async { var file = directory.resolve("anyname"); var hadError = false; await loadPackageConfigUri(file, @@ -254,23 +254,22 @@ void main() { expect(hadError, true); }); - // Find package_config.json in subdir even if initial file syntax error. - loaderTest("specified file syntax error", { + // Don't look for package_config.json if original file not named .packages. + loaderTest("specified file syntax error with alternative", { "anyname": "syntax error", ".dart_tool": { "package_config.json": packageConfigFile, }, - }, (Uri directory, loader) async { + }, (directory, loader) async { var file = directory.resolve("anyname"); - var config = await loadPackageConfigUri(file, loader: loader); - expect(config.version, 2); - validatePackagesFile(config, directory); + expect(() => loadPackageConfigUri(file, loader: loader), + throwsFormatException); }); // A file starting with `{` is a package_config.json file. loaderTest("file syntax error with {", { ".packages": "{syntax error", - }, (Uri directory, loader) async { + }, (directory, loader) async { var file = directory.resolve(".packages"); var hadError = false; await loadPackageConfigUri(file, From 9caf0c1923cef73305a371b5fafedb543ef56c22 Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Wed, 18 Mar 2020 15:23:02 +0100 Subject: [PATCH 095/170] Make `.packages` files be more clever about defaults. (dart-lang/package_config#80) * Make `.packages` files be more clever about defaults. The `PackageConfig` for a `.packages` file now assigns a default language version of 2.7 to all packages, and if the package location ends in `/lib/`, it assumes the package's root directory is the parent directory of that. * Fix test. * Fix another test. --- pkgs/package_config/CHANGELOG.md | 2 ++ .../package_config/lib/src/packages_file.dart | 21 +++++++++++++++---- pkgs/package_config/test/parse_test.dart | 4 ++-- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index 0b5e1563e..3015523c2 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -2,6 +2,8 @@ - Updated to support new rules for picking `package_config.json` over a specified `.packages`. +- Deduce package root from `.packages` derived package configuration, + and default all such packages to language version 2.7. ## 1.9.1 diff --git a/pkgs/package_config/lib/src/packages_file.dart b/pkgs/package_config/lib/src/packages_file.dart index e65e7e8a6..184b0dd04 100644 --- a/pkgs/package_config/lib/src/packages_file.dart +++ b/pkgs/package_config/lib/src/packages_file.dart @@ -7,6 +7,12 @@ import "package_config_impl.dart"; import "util.dart"; import "errors.dart"; +/// The language version prior to the release of language versioning. +/// +/// This is the default language version used by all packages from a +/// `.packages` file. +final LanguageVersion _languageVersion = LanguageVersion(2, 7); + /// Parses a `.packages` file into a [PackageConfig]. /// /// The [source] is the byte content of a `.packages` file, assumed to be @@ -100,17 +106,24 @@ PackageConfig parse( "Package URI as location for package", source, separatorIndex + 1)); continue; } - if (!packageLocation.path.endsWith('/')) { - packageLocation = - packageLocation.replace(path: packageLocation.path + "/"); + var path = packageLocation.path; + if (!path.endsWith('/')) { + path += "/"; + packageLocation = packageLocation.replace(path: path); } if (packageNames.contains(packageName)) { onError(PackageConfigFormatException( "Same package name occured more than once", source, start)); continue; } + var rootUri = packageLocation; + if (path.endsWith("/lib/")) { + // Assume default Pub package layout. Include package itself in root. + rootUri = + packageLocation.replace(path: path.substring(0, path.length - 4)); + } var package = SimplePackage.validate( - packageName, packageLocation, packageLocation, null, null, (error) { + packageName, rootUri, packageLocation, _languageVersion, null, (error) { if (error is ArgumentError) { onError(PackageConfigFormatException(error.message, source)); } else { diff --git a/pkgs/package_config/test/parse_test.dart b/pkgs/package_config/test/parse_test.dart index 367b64384..59a7e7126 100644 --- a/pkgs/package_config/test/parse_test.dart +++ b/pkgs/package_config/test/parse_test.dart @@ -34,9 +34,9 @@ void main() { var foo = result["foo"]; expect(foo, isNotNull); - expect(foo.root, Uri.parse("file:///foo/lib/")); + expect(foo.root, Uri.parse("file:///foo/")); expect(foo.packageUriRoot, Uri.parse("file:///foo/lib/")); - expect(foo.languageVersion, null); + expect(foo.languageVersion, LanguageVersion(2, 7)); }); test("valid empty", () { From 19182255aaa1a5b1869606264c20bafcccee25a3 Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Thu, 26 Mar 2020 17:09:12 +0100 Subject: [PATCH 096/170] Fix Package constructor not accepting relative packageUriRoot. (dart-lang/package_config#82) * Fix Package constructor not accepting relative packageUriRoot. --- pkgs/package_config/CHANGELOG.md | 4 + .../lib/src/package_config.dart | 2 +- .../lib/src/package_config_impl.dart | 5 +- pkgs/package_config/pubspec.yaml | 2 +- .../test/package_config_impl_test.dart | 145 ++++++++++++++++++ 5 files changed, 155 insertions(+), 3 deletions(-) create mode 100644 pkgs/package_config/test/package_config_impl_test.dart diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index 3015523c2..6dcae80cf 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.9.3 + +- Fix `Package` constructor not accepting relative `packageUriRoot`. + ## 1.9.2 - Updated to support new rules for picking `package_config.json` over diff --git a/pkgs/package_config/lib/src/package_config.dart b/pkgs/package_config/lib/src/package_config.dart index 364df75b1..30c758a96 100644 --- a/pkgs/package_config/lib/src/package_config.dart +++ b/pkgs/package_config/lib/src/package_config.dart @@ -219,7 +219,7 @@ abstract class Package { /// The [packageUriRoot], if provided, must be either an absolute /// directory URI or a relative URI reference which is then resolved /// relative to [root]. It must then also be a subdirectory of [root], - /// or the same directory. + /// or the same directory, and must end with `/`. /// If [languageVersion] is supplied, it must be a valid Dart language /// version, which means two decimal integer literals separated by a `.`, /// where the integer literals have no leading zeros unless they are diff --git a/pkgs/package_config/lib/src/package_config_impl.dart b/pkgs/package_config/lib/src/package_config_impl.dart index f68a9ea75..9e23af063 100644 --- a/pkgs/package_config/lib/src/package_config_impl.dart +++ b/pkgs/package_config/lib/src/package_config_impl.dart @@ -214,7 +214,10 @@ class SimplePackage implements Package { root = root.replace(path: root.path + "/"); } } - if (!fatalError) { + if (packageUriRoot == null) { + packageUriRoot = root; + } else if (!fatalError) { + packageUriRoot = root.resolveUri(packageUriRoot); if (!isAbsoluteDirectoryUri(packageUriRoot)) { onError(PackageConfigArgumentError( packageUriRoot, diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 3f5ec27e0..b7d596910 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 1.9.2 +version: 1.9.3 description: Support for working with Package Configuration files. homepage: https://github.com/dart-lang/package_config diff --git a/pkgs/package_config/test/package_config_impl_test.dart b/pkgs/package_config/test/package_config_impl_test.dart new file mode 100644 index 000000000..6921118f3 --- /dev/null +++ b/pkgs/package_config/test/package_config_impl_test.dart @@ -0,0 +1,145 @@ +// Copyright (c) 2020, 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. + +import "package:package_config/package_config_types.dart"; +import "package:test/test.dart"; +import "src/util.dart"; + +void main() { + var unique = Object(); + var root = Uri.file("/tmp/root/"); + + group("LanguageVersion", () { + test("minimal", () { + var version = LanguageVersion(3, 5); + expect(version.major, 3); + expect(version.minor, 5); + }); + + test("negative major", () { + expect(() => LanguageVersion(-1, 1), throwsArgumentError); + }); + + test("negative minor", () { + expect(() => LanguageVersion(1, -1), throwsArgumentError); + }); + + test("minimal parse", () { + var version = LanguageVersion.parse("3.5"); + expect(version.major, 3); + expect(version.minor, 5); + }); + + void failParse(String name, String input) { + test("$name - error", () { + expect(() => LanguageVersion.parse(input), + throwsA(TypeMatcher())); + expect(() => LanguageVersion.parse(input), throwsFormatException); + var failed = false; + var actual = LanguageVersion.parse(input, onError: (_) { + failed = true; + }); + expect(failed, true); + expect(actual, isA()); + }); + } + + failParse("Leading zero major", "01.1"); + failParse("Leading zero minor", "1.01"); + failParse("Sign+ major", "+1.1"); + failParse("Sign- major", "-1.1"); + failParse("Sign+ minor", "1.+1"); + failParse("Sign- minor", "1.-1"); + failParse("WhiteSpace 1", " 1.1"); + failParse("WhiteSpace 2", "1 .1"); + failParse("WhiteSpace 3", "1. 1"); + failParse("WhiteSpace 4", "1.1 "); + }); + + group("Package", () { + test("minimal", () { + var package = Package("name", root, extraData: unique); + expect(package.name, "name"); + expect(package.root, root); + expect(package.packageUriRoot, root); + expect(package.languageVersion, null); + expect(package.extraData, same(unique)); + }); + + test("absolute package root", () { + var version = LanguageVersion(1, 1); + var absolute = root.resolve("foo/bar/"); + var package = Package("name", root, + packageUriRoot: absolute, + languageVersion: version, + extraData: unique); + expect(package.name, "name"); + expect(package.root, root); + expect(package.packageUriRoot, absolute); + expect(package.languageVersion, version); + expect(package.extraData, same(unique)); + }); + + test("relative package root", () { + var relative = Uri.parse("foo/bar/"); + var absolute = root.resolveUri(relative); + var package = + Package("name", root, packageUriRoot: relative, extraData: unique); + expect(package.name, "name"); + expect(package.root, root); + expect(package.packageUriRoot, absolute); + expect(package.languageVersion, null); + expect(package.extraData, same(unique)); + }); + + for (var badName in ["a/z", "a:z", "", "..."]) { + test("Invalid name '$badName'", () { + expect(() => Package(badName, root), throwsPackageConfigError); + }); + } + + test("Invalid root, not absolute", () { + expect( + () => Package("name", Uri.parse("/foo/")), throwsPackageConfigError); + }); + + test("Invalid root, not ending in slash", () { + expect(() => Package("name", Uri.parse("file:///foo")), + throwsPackageConfigError); + }); + + test("invalid package root, not ending in slash", () { + expect(() => Package("name", root, packageUriRoot: Uri.parse("foo")), + throwsPackageConfigError); + }); + + test("invalid package root, not inside root", () { + expect(() => Package("name", root, packageUriRoot: Uri.parse("../baz/")), + throwsPackageConfigError); + }); + }); + + group("package config", () { + test("emtpy", () { + var empty = PackageConfig([], extraData: unique); + expect(empty.version, 2); + expect(empty.packages, isEmpty); + expect(empty.extraData, same(unique)); + expect(empty.resolve(pkg("a", "b")), isNull); + }); + + test("single", () { + var package = Package("name", root); + var single = PackageConfig([package], extraData: unique); + expect(single.version, 2); + expect(single.packages, hasLength(1)); + expect(single.extraData, same(unique)); + expect(single.resolve(pkg("a", "b")), isNull); + var resolved = single.resolve(pkg("name", "a/b")); + expect(resolved, root.resolve("a/b")); + }); + }); +} + +final Matcher throwsPackageConfigError = throwsA(isA()); From 5f06761b02746ce88a5f269b1b09a146a9e6e0a3 Mon Sep 17 00:00:00 2001 From: Devon Carew Date: Wed, 6 May 2020 14:59:21 -0700 Subject: [PATCH 097/170] fix a lint about an unused import --- pkgs/package_config/.travis.yml | 2 +- pkgs/package_config/lib/src/package_config_io.dart | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/pkgs/package_config/.travis.yml b/pkgs/package_config/.travis.yml index 09fc296c2..3a47bb586 100644 --- a/pkgs/package_config/.travis.yml +++ b/pkgs/package_config/.travis.yml @@ -5,7 +5,7 @@ dart: dart_task: - test - dartfmt - - dartanalyzer: --fatal-warnings . + - dartanalyzer: --fatal-warnings --fatal-infos . matrix: include: diff --git a/pkgs/package_config/lib/src/package_config_io.dart b/pkgs/package_config/lib/src/package_config_io.dart index 31bc1cc99..bfbb1e373 100644 --- a/pkgs/package_config/lib/src/package_config_io.dart +++ b/pkgs/package_config/lib/src/package_config_io.dart @@ -8,7 +8,6 @@ import "dart:convert"; import "dart:io"; import "dart:typed_data"; -import "discovery.dart" show packageConfigJsonPath; import "errors.dart"; import "package_config_impl.dart"; import "package_config_json.dart"; From 8897a35cdd881ebf735193c80642c67f7152a697 Mon Sep 17 00:00:00 2001 From: Michael R Fairhurst Date: Mon, 28 Sep 2020 02:54:40 -0700 Subject: [PATCH 098/170] Remove unused async imports (dart-lang/package_config#91) Since this version doesn't support Dart pre 2.0, these imports are unnecessary. --- pkgs/package_config/lib/discovery.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/pkgs/package_config/lib/discovery.dart b/pkgs/package_config/lib/discovery.dart index a2f53c0e6..a72bb1255 100644 --- a/pkgs/package_config/lib/discovery.dart +++ b/pkgs/package_config/lib/discovery.dart @@ -5,7 +5,6 @@ @Deprecated("Use the package_config.json based API") library package_config.discovery; -import "dart:async"; import "dart:io"; import "dart:typed_data" show Uint8List; From e3c69b9be3add6635a22564e592803cd4e2f1c9b Mon Sep 17 00:00:00 2001 From: Sam Rawlins Date: Mon, 9 Nov 2020 20:06:33 -0800 Subject: [PATCH 099/170] Remove unused dart:async imports. As of Dart 2.1, Future/Stream have been exported from dart:core. --- pkgs/package_config/test/legacy/discovery_analysis_test.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/pkgs/package_config/test/legacy/discovery_analysis_test.dart b/pkgs/package_config/test/legacy/discovery_analysis_test.dart index 4be636d13..7554d85d9 100644 --- a/pkgs/package_config/test/legacy/discovery_analysis_test.dart +++ b/pkgs/package_config/test/legacy/discovery_analysis_test.dart @@ -6,7 +6,6 @@ @TestOn('vm') library package_config.discovery_analysis_test; -import "dart:async"; import "dart:io"; import "package:package_config/discovery_analysis.dart"; From c86d4c98c8286e2fc7263df3407834d5f3c5f612 Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Wed, 2 Dec 2020 16:23:00 +0100 Subject: [PATCH 100/170] Migrate to null safety (dart-lang/package_config#93) * Migrate non-deprecated libraries to null safety. * Major version increment, removing deprecated APIs. This is the null safe, non-deprecated API for package_config.json file manipulation. Also address dart-lang/package_config#86. --- pkgs/package_config/CHANGELOG.md | 5 + pkgs/package_config/README.md | 9 +- pkgs/package_config/analysis_options.yaml | 1 - pkgs/package_config/lib/discovery.dart | 226 ------------ .../lib/discovery_analysis.dart | 167 --------- pkgs/package_config/lib/package_config.dart | 23 +- pkgs/package_config/lib/packages.dart | 96 ----- pkgs/package_config/lib/packages_file.dart | 232 ------------ pkgs/package_config/lib/src/discovery.dart | 14 +- pkgs/package_config/lib/src/errors.dart | 7 +- .../lib/src/package_config.dart | 54 +-- .../lib/src/package_config_impl.dart | 82 +++-- .../lib/src/package_config_io.dart | 39 ++- .../lib/src/package_config_json.dart | 91 ++--- .../package_config/lib/src/packages_file.dart | 4 +- .../package_config/lib/src/packages_impl.dart | 128 ------- .../lib/src/packages_io_impl.dart | 46 --- pkgs/package_config/lib/src/util.dart | 4 +- pkgs/package_config/lib/src/util_io.dart | 8 +- pkgs/package_config/pubspec.yaml | 55 ++- pkgs/package_config/test/discovery_test.dart | 6 +- .../test/discovery_uri_test.dart | 8 +- pkgs/package_config/test/legacy/all.dart | 20 -- .../test/legacy/discovery_analysis_test.dart | 127 ------- .../test/legacy/discovery_test.dart | 329 ------------------ .../test/legacy/parse_test.dart | 246 ------------- .../test/legacy/parse_write_test.dart | 133 ------- pkgs/package_config/test/parse_test.dart | 48 +-- pkgs/package_config/test/src/util.dart | 10 +- pkgs/package_config/test/src/util_io.dart | 16 +- 30 files changed, 275 insertions(+), 1959 deletions(-) delete mode 100644 pkgs/package_config/lib/discovery.dart delete mode 100644 pkgs/package_config/lib/discovery_analysis.dart delete mode 100644 pkgs/package_config/lib/packages.dart delete mode 100644 pkgs/package_config/lib/packages_file.dart delete mode 100644 pkgs/package_config/lib/src/packages_impl.dart delete mode 100644 pkgs/package_config/lib/src/packages_io_impl.dart delete mode 100644 pkgs/package_config/test/legacy/all.dart delete mode 100644 pkgs/package_config/test/legacy/discovery_analysis_test.dart delete mode 100644 pkgs/package_config/test/legacy/discovery_test.dart delete mode 100644 pkgs/package_config/test/legacy/parse_test.dart delete mode 100644 pkgs/package_config/test/legacy/parse_write_test.dart diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index 6dcae80cf..32ff3f17f 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -1,3 +1,8 @@ +## 2.0.0 + +- Migrate to null safety. +- Remove legacy APIs. + ## 1.9.3 - Fix `Package` constructor not accepting relative `packageUriRoot`. diff --git a/pkgs/package_config/README.md b/pkgs/package_config/README.md index b47a6825b..1ad4b41c1 100644 --- a/pkgs/package_config/README.md +++ b/pkgs/package_config/README.md @@ -7,11 +7,12 @@ in the Package Configuration v2 [design document](https://github.com/dart-lang/l The primary libraries are * `package_config.dart`: Defines the `PackageConfig` class and other types needed to use - package configurations. + package configurations, and provides functions to find, read and + write package configuration files. -* `package_config_discovery.dart`: - Provides functions for reading configurations from files, - and writing them back out. +* `package_config_types.dart`: + Just the `PackageConfig` class and other types needed to use + package configurations. This library does not depend on `dart:io`. The package includes deprecated backwards compatible functionality to work with the `.packages` file. This functionality will not be maintained, diff --git a/pkgs/package_config/analysis_options.yaml b/pkgs/package_config/analysis_options.yaml index 66639ec1a..a7854087c 100644 --- a/pkgs/package_config/analysis_options.yaml +++ b/pkgs/package_config/analysis_options.yaml @@ -6,6 +6,5 @@ include: package:pedantic/analysis_options.1.9.0.yaml analyzer: errors: annotate_overrides: ignore - curly_braces_in_flow_control_structures: ignore prefer_single_quotes: ignore use_function_type_syntax_for_parameters: ignore diff --git a/pkgs/package_config/lib/discovery.dart b/pkgs/package_config/lib/discovery.dart deleted file mode 100644 index a72bb1255..000000000 --- a/pkgs/package_config/lib/discovery.dart +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright (c) 2015, 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. - -@Deprecated("Use the package_config.json based API") -library package_config.discovery; - -import "dart:io"; -import "dart:typed_data" show Uint8List; - -import "package:path/path.dart" as path; - -import "packages.dart"; -import "packages_file.dart" as pkgfile show parse; -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 loadPackagesFile(Uri packagesFile, - {Future> loader(Uri uri)}) async { - Packages parseBytes(List bytes) { - return MapPackages(pkgfile.parse(bytes, packagesFile)); - } - - if (packagesFile.scheme == "file") { - return parseBytes(await File.fromUri(packagesFile).readAsBytes()); - } - if (loader == null) { - return parseBytes(await _httpGet(packagesFile)); - } - return parseBytes(await loader(packagesFile)); -} - -/// 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") { - return FilePackagesDirectoryPackages(Directory.fromUri(packagesDir)); - } - if (!packagesDir.path.endsWith('/')) { - packagesDir = packagesDir.replace(path: packagesDir.path + '/'); - } - return NonFilePackagesDirectoryPackages(packagesDir); -} - -/// Discover the package configuration for a Dart script. -/// -/// The [baseUri] points to either the Dart script or its directory. -/// A package resolution strategy is found by going through the following steps, -/// and stopping when something is found. -/// -/// * Check if a `.packages` file exists in the same directory. -/// * If `baseUri`'s scheme is not `file`, then assume a `packages` directory -/// in the same directory, and resolve packages relative to that. -/// * If `baseUri`'s scheme *is* `file`: -/// * Check if a `packages` directory exists. -/// * Otherwise check each successive parent directory of `baseUri` for a -/// `.packages` file. -/// -/// If any of these tests succeed, a `Packages` class is returned. -/// Returns the constant [noPackages] if no resolution strategy is found. -/// -/// This function currently only supports `file`, `http` and `https` URIs. -/// It needs to be able to load a `.packages` file from the URI, so only -/// recognized schemes are accepted. -/// -/// 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 findPackages(Uri baseUri, - {Future> loader(Uri unsupportedUri)}) { - if (baseUri.scheme == "file") { - return Future.sync(() => findPackagesFromFile(baseUri)); - } else if (loader != null) { - return findPackagesFromNonFile(baseUri, loader: loader); - } else if (baseUri.scheme == "http" || baseUri.scheme == "https") { - return findPackagesFromNonFile(baseUri, loader: _httpGet); - } else { - return Future.value(Packages.noPackages); - } -} - -/// Find the location of the package resolution file/directory for a Dart file. -/// -/// Checks for a `.packages` file in the [workingDirectory]. -/// If not found, checks for a `packages` directory in the same directory. -/// If still not found, starts checking parent directories for -/// `.packages` until reaching the root directory. -/// -/// Returns a [File] object of a `.packages` file if one is found, or a -/// [Directory] object for the `packages/` directory if that is found. -FileSystemEntity _findPackagesFile(String workingDirectory) { - var dir = Directory(workingDirectory); - if (!dir.isAbsolute) dir = dir.absolute; - if (!dir.existsSync()) { - throw ArgumentError.value( - workingDirectory, "workingDirectory", "Directory does not exist."); - } - File checkForConfigFile(Directory directory) { - assert(directory.isAbsolute); - var file = File(path.join(directory.path, ".packages")); - if (file.existsSync()) return file; - return null; - } - - // Check for $cwd/.packages - var packagesCfgFile = checkForConfigFile(dir); - if (packagesCfgFile != null) return packagesCfgFile; - // Check for $cwd/packages/ - var packagesDir = Directory(path.join(dir.path, "packages")); - if (packagesDir.existsSync()) return packagesDir; - // Check for cwd(/..)+/.packages - var parentDir = dir.parent; - while (parentDir.path != dir.path) { - packagesCfgFile = checkForConfigFile(parentDir); - if (packagesCfgFile != null) break; - dir = parentDir; - parentDir = dir.parent; - } - return packagesCfgFile; -} - -/// Finds a package resolution strategy for a local Dart script. -/// -/// The [fileBaseUri] points to either a Dart script or the directory of the -/// script. The `fileBaseUri` must be a `file:` URI. -/// -/// This function first tries to locate a `.packages` file in the `fileBaseUri` -/// directory. If that is not found, it instead checks for the presence of -/// a `packages/` directory in the same place. -/// If that also fails, it starts checking parent directories for a `.packages` -/// file, and stops if it finds it. -/// Otherwise it gives up and returns [Packages.noPackages]. -Packages findPackagesFromFile(Uri fileBaseUri) { - var baseDirectoryUri = fileBaseUri; - if (!fileBaseUri.path.endsWith('/')) { - baseDirectoryUri = baseDirectoryUri.resolve("."); - } - var baseDirectoryPath = baseDirectoryUri.toFilePath(); - var location = _findPackagesFile(baseDirectoryPath); - if (location == null) return Packages.noPackages; - if (location is File) { - var fileBytes = location.readAsBytesSync(); - var map = pkgfile.parse(fileBytes, Uri.file(location.path)); - return MapPackages(map); - } - assert(location is Directory); - return FilePackagesDirectoryPackages(location); -} - -/// Finds a package resolution strategy for a Dart script. -/// -/// The [nonFileUri] points to either a Dart script or the directory of the -/// script. -/// The [nonFileUri] should not be a `file:` URI since the algorithm for -/// finding a package resolution strategy is more elaborate for `file:` URIs. -/// In that case, use [findPackagesFromFile]. -/// -/// This function first tries to locate a `.packages` file in the [nonFileUri] -/// directory. If that is not found, it instead assumes a `packages/` directory -/// in the same place. -/// -/// By default, this function only works for `http:` and `https:` URIs. -/// To support other schemes, a loader must be provided, which is used to -/// try to load the `.packages` file. The loader should return the contents -/// of the requested `.packages` file as bytes, which will be assumed to be -/// UTF-8 encoded. -Future findPackagesFromNonFile(Uri nonFileUri, - {Future> loader(Uri name)}) async { - loader ??= _httpGet; - var packagesFileUri = nonFileUri.resolve(".packages"); - - try { - var fileBytes = await loader(packagesFileUri); - var map = pkgfile.parse(fileBytes, packagesFileUri); - return MapPackages(map); - } catch (_) { - // Didn't manage to load ".packages". Assume a "packages/" directory. - var packagesDirectoryUri = nonFileUri.resolve("packages/"); - return NonFilePackagesDirectoryPackages(packagesDirectoryUri); - } -} - -/// Fetches a file over http. -Future> _httpGet(Uri uri) async { - var client = HttpClient(); - var request = await client.getUrl(uri); - var response = await request.close(); - if (response.statusCode != HttpStatus.ok) { - throw HttpException('${response.statusCode} ${response.reasonPhrase}', - uri: uri); - } - var splitContent = await response.toList(); - var totalLength = 0; - for (var list in splitContent) { - totalLength += list.length; - } - var result = Uint8List(totalLength); - var offset = 0; - for (var contentPart in splitContent) { - result.setRange(offset, offset + contentPart.length, contentPart); - offset += contentPart.length; - } - return result; -} diff --git a/pkgs/package_config/lib/discovery_analysis.dart b/pkgs/package_config/lib/discovery_analysis.dart deleted file mode 100644 index 2af07292e..000000000 --- a/pkgs/package_config/lib/discovery_analysis.dart +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright (c) 2015, 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. - -/// Analyse a directory structure and find packages resolvers for each -/// sub-directory. -/// -/// The resolvers are generally the same that would be found by using -/// the `discovery.dart` library on each sub-directory in turn, -/// but more efficiently and with some heuristics for directories that -/// wouldn't otherwise have a package resolution strategy, or that are -/// determined to be "package directories" themselves. -@Deprecated("Use the package_config.json based API") -library package_config.discovery_analysis; - -import "dart:collection" show HashMap; -import "dart:io" show File, Directory; - -import "package:path/path.dart" as path; - -import "packages.dart"; -import "packages_file.dart" as pkgfile; -import "src/packages_impl.dart"; -import "src/packages_io_impl.dart"; - -/// Associates a [Packages] package resolution strategy with a directory. -/// -/// The package resolution applies to the directory and any sub-directory -/// that doesn't have its own overriding child [PackageContext]. -abstract class PackageContext { - /// The directory that introduced the [packages] resolver. - Directory get directory; - - /// A [Packages] resolver that applies to the directory. - /// - /// Introduced either by a `.packages` file or a `packages/` directory. - Packages get packages; - - /// Child contexts that apply to sub-directories of [directory]. - List get children; - - /// Look up the [PackageContext] that applies to a specific directory. - /// - /// The directory must be inside [directory]. - PackageContext operator [](Directory directory); - - /// A map from directory to package resolver. - /// - /// Has an entry for this package context and for each child context - /// contained in this one. - Map asMap(); - - /// Analyze [directory] and sub-directories for package resolution strategies. - /// - /// Returns a mapping from sub-directories to [Packages] objects. - /// - /// The analysis assumes that there are no `.packages` files in a parent - /// directory of `directory`. If there is, its corresponding `Packages` object - /// should be provided as `root`. - static PackageContext findAll(Directory directory, - {Packages root = Packages.noPackages}) { - if (!directory.existsSync()) { - throw ArgumentError("Directory not found: $directory"); - } - var contexts = []; - void findRoots(Directory directory) { - Packages packages; - List oldContexts; - var packagesFile = File(path.join(directory.path, ".packages")); - if (packagesFile.existsSync()) { - packages = _loadPackagesFile(packagesFile); - oldContexts = contexts; - contexts = []; - } else { - var packagesDir = Directory(path.join(directory.path, "packages")); - if (packagesDir.existsSync()) { - packages = FilePackagesDirectoryPackages(packagesDir); - oldContexts = contexts; - contexts = []; - } - } - for (var entry in directory.listSync()) { - if (entry is Directory) { - if (packages == null || !entry.path.endsWith("/packages")) { - findRoots(entry); - } - } - } - if (packages != null) { - oldContexts.add(_PackageContext(directory, packages, contexts)); - contexts = oldContexts; - } - } - - findRoots(directory); - // If the root is not itself context root, add a the wrapper context. - if (contexts.length == 1 && contexts[0].directory == directory) { - return contexts[0]; - } - return _PackageContext(directory, root, contexts); - } -} - -class _PackageContext implements PackageContext { - final Directory directory; - final Packages packages; - final List children; - _PackageContext(this.directory, this.packages, List children) - : children = List.unmodifiable(children); - - Map asMap() { - var result = HashMap(); - void recurse(_PackageContext current) { - result[current.directory] = current.packages; - for (var child in current.children) { - recurse(child); - } - } - - recurse(this); - return result; - } - - PackageContext operator [](Directory directory) { - var path = directory.path; - if (!path.startsWith(this.directory.path)) { - throw ArgumentError("Not inside $path: $directory"); - } - var current = this; - // The current path is know to agree with directory until deltaIndex. - var deltaIndex = current.directory.path.length; - List children = current.children; - var i = 0; - while (i < children.length) { - // TODO(lrn): Sort children and use binary search. - _PackageContext child = children[i]; - var childPath = child.directory.path; - if (_stringsAgree(path, childPath, deltaIndex, childPath.length)) { - deltaIndex = childPath.length; - if (deltaIndex == path.length) { - return child; - } - current = child; - children = current.children; - i = 0; - continue; - } - i++; - } - return current; - } - - static bool _stringsAgree(String a, String b, int start, int end) { - if (a.length < end || b.length < end) return false; - for (var i = start; i < end; i++) { - if (a.codeUnitAt(i) != b.codeUnitAt(i)) return false; - } - return true; - } -} - -Packages _loadPackagesFile(File file) { - var uri = Uri.file(file.path); - var bytes = file.readAsBytesSync(); - var map = pkgfile.parse(bytes, uri); - return MapPackages(map); -} diff --git a/pkgs/package_config/lib/package_config.dart b/pkgs/package_config/lib/package_config.dart index 1113ac872..3dfd8ef29 100644 --- a/pkgs/package_config/lib/package_config.dart +++ b/pkgs/package_config/lib/package_config.dart @@ -3,8 +3,11 @@ // BSD-style license that can be found in the LICENSE file. /// A package configuration is a way to assign file paths to package URIs, -/// and vice-versa, -library package_config.package_config_discovery; +/// and vice-versa. +/// +/// This package provides functionality to find, read and write package +/// configurations in the [specified format](https://github.com/dart-lang/language/blob/master/accepted/future-releases/language-versioning/package-config-file-v2.md). +library package_config.package_config; import "dart:io" show File, Directory; import "dart:typed_data" show Uint8List; @@ -39,7 +42,7 @@ export "package_config_types.dart"; /// a valid configuration from the invalid configuration file. /// If no [onError] is provided, errors are thrown immediately. Future loadPackageConfig(File file, - {bool preferNewest = true, void onError(Object error)}) => + {bool preferNewest = true, void onError(Object error)?}) => readAnyConfigFile(file, preferNewest, onError ?? throwError); /// Reads a specific package configuration URI. @@ -84,9 +87,9 @@ Future loadPackageConfig(File file, /// a valid configuration from the invalid configuration file. /// If no [onError] is provided, errors are thrown immediately. Future loadPackageConfigUri(Uri file, - {Future loader(Uri uri) /*?*/, + {Future loader(Uri uri)?, bool preferNewest = true, - void onError(Object error)}) => + void onError(Object error)?}) => readAnyConfigFileUri(file, loader, onError ?? throwError, preferNewest); /// Finds a package configuration relative to [directory]. @@ -109,8 +112,8 @@ Future loadPackageConfigUri(Uri file, /// If no [onError] is provided, errors are thrown immediately. /// /// Returns `null` if no configuration file is found. -Future findPackageConfig(Directory directory, - {bool recurse = true, void onError(Object error)}) => +Future findPackageConfig(Directory directory, + {bool recurse = true, void onError(Object error)?}) => discover.findPackageConfig(directory, recurse, onError ?? throwError); /// Finds a package configuration relative to [location]. @@ -153,10 +156,10 @@ Future findPackageConfig(Directory directory, /// If no [onError] is provided, errors are thrown immediately. /// /// Returns `null` if no configuration file is found. -Future findPackageConfigUri(Uri location, +Future findPackageConfigUri(Uri location, {bool recurse = true, - Future loader(Uri uri), - void onError(Object error)}) => + Future loader(Uri uri)?, + void onError(Object error)?}) => discover.findPackageConfigUri( location, loader, onError ?? throwError, recurse); diff --git a/pkgs/package_config/lib/packages.dart b/pkgs/package_config/lib/packages.dart deleted file mode 100644 index 203f32fdb..000000000 --- a/pkgs/package_config/lib/packages.dart +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) 2015, 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. - -@Deprecated("Use the package_config.json based API") -library package_config.packages; - -import "src/packages_impl.dart"; - -/// A package resolution strategy. -/// -/// Allows converting a `package:` URI to a different kind of URI. -/// -/// May also allow listing the available packages and converting -/// to a `Map` that gives the base location of each available -/// package. In some cases there is no way to find the available packages, -/// in which case [packages] and [asMap] will throw if used. -/// One such case is if the packages are resolved relative to a -/// `packages/` directory available over HTTP. -@Deprecated("Use the package_config.json based API") -abstract class Packages { - /// A [Packages] resolver containing no packages. - /// - /// This constant object is returned by [find] above if no - /// package resolution strategy is found. - static const Packages noPackages = NoPackages(); - - /// Resolve a package URI into a non-package URI. - /// - /// Translates a `package:` URI, according to the package resolution - /// strategy, into a URI that can be loaded. - /// By default, only `file`, `http` and `https` URIs are returned. - /// Custom `Packages` objects may return other URIs. - /// - /// If resolution fails because a package with the requested package name - /// is not available, the [notFound] function is called. - /// If no `notFound` function is provided, it defaults to throwing an error. - /// - /// The [packageUri] must be a valid package URI. - Uri resolve(Uri packageUri, {Uri notFound(Uri packageUri)}); - - /// Return the names of the available packages. - /// - /// Returns an iterable that allows iterating the names of available packages. - /// - /// Some `Packages` objects are unable to find the package names, - /// and getting `packages` from such a `Packages` object will throw. - Iterable get packages; - - /// Retrieve metadata associated with a package. - /// - /// Metadata have string keys and values, and are looked up by key. - /// - /// Returns `null` if the argument is not a valid package name, - /// or if the package is not one of the packages configured by - /// this packages object, or if the package does not have associated - /// metadata with the provided [key]. - /// - /// Not all `Packages` objects can support metadata. - /// Those will always return `null`. - String packageMetadata(String packageName, String key); - - /// Retrieve metadata associated with a library. - /// - /// If [libraryUri] is a `package:` URI, the returned value - /// is the same that would be returned by [packageMetadata] with - /// the package's name and the same key. - /// - /// If [libraryUri] is not a `package:` URI, and this [Packages] - /// object has a [defaultPackageName], then the [key] is looked - /// up on the default package instead. - /// - /// Otherwise the result is `null`. - String libraryMetadata(Uri libraryUri, String key); - - /// Return the names-to-base-URI mapping of the available packages. - /// - /// Returns a map from package name to a base URI. - /// The [resolve] method will resolve a package URI with a specific package - /// name to a path extending the base URI that this map gives for that - /// package name. - /// - /// Some `Packages` objects are unable to find the package names, - /// and calling `asMap` on such a `Packages` object will throw. - Map asMap(); - - /// The name of the "default package". - /// - /// A default package is a package that *non-package* libraries - /// may be considered part of for some purposes. - /// - /// The value is `null` if there is no default package. - /// Not all implementations of [Packages] supports a default package, - /// and will always have a `null` value for those. - String get defaultPackageName; -} diff --git a/pkgs/package_config/lib/packages_file.dart b/pkgs/package_config/lib/packages_file.dart deleted file mode 100644 index ef0b0b3ca..000000000 --- a/pkgs/package_config/lib/packages_file.dart +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright (c) 2015, 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. - -@Deprecated("Use the package_config.json based API") -library package_config.packages_file; - -import "package:charcode/ascii.dart"; - -import "src/util.dart" show isValidPackageName; - -/// Parses a `.packages` file into a map from package name to base URI. -/// -/// The [source] is the byte content of a `.packages` file, assumed to be -/// UTF-8 encoded. In practice, all significant parts of the file must be ASCII, -/// so Latin-1 or Windows-1252 encoding will also work fine. -/// -/// If the file content is available as a string, its [String.codeUnits] can -/// be used as the `source` argument of this function. -/// -/// The [baseLocation] is used as a base URI to resolve all relative -/// URI references against. -/// If the content was read from a file, `baseLocation` should be the -/// location of that file. -/// -/// If [allowDefaultPackage] is set to true, an entry with an empty package name -/// is accepted. This entry does not correspond to a package, but instead -/// represents a *default package* which non-package libraries may be considered -/// part of in some cases. The value of that entry must be a valid package name. -/// -/// Returns a simple mapping from package name to package location. -/// If default package is allowed, the map maps the empty string to the default package's name. -Map parse(List source, Uri baseLocation, - {bool allowDefaultPackage = false}) { - var index = 0; - var result = {}; - while (index < source.length) { - var isComment = false; - var start = index; - var separatorIndex = -1; - var end = source.length; - var char = source[index++]; - if (char == $cr || char == $lf) { - continue; - } - if (char == $colon) { - if (!allowDefaultPackage) { - throw FormatException("Missing package name", source, index - 1); - } - separatorIndex = index - 1; - } - isComment = char == $hash; - while (index < source.length) { - char = source[index++]; - if (char == $colon && separatorIndex < 0) { - separatorIndex = index - 1; - } else if (char == $cr || char == $lf) { - end = index - 1; - break; - } - } - if (isComment) continue; - if (separatorIndex < 0) { - throw FormatException("No ':' on line", source, index - 1); - } - var packageName = String.fromCharCodes(source, start, separatorIndex); - if (packageName.isEmpty - ? !allowDefaultPackage - : !isValidPackageName(packageName)) { - throw FormatException("Not a valid package name", packageName, 0); - } - var packageValue = String.fromCharCodes(source, separatorIndex + 1, end); - Uri packageLocation; - if (packageName.isEmpty) { - if (!isValidPackageName(packageValue)) { - throw FormatException( - "Default package entry value is not a valid package name"); - } - packageLocation = Uri(path: packageValue); - } else { - packageLocation = baseLocation.resolve(packageValue); - if (!packageLocation.path.endsWith('/')) { - packageLocation = - packageLocation.replace(path: packageLocation.path + "/"); - } - } - if (result.containsKey(packageName)) { - if (packageName.isEmpty) { - throw FormatException( - "More than one default package entry", source, start); - } - throw FormatException("Same package name occured twice", source, start); - } - result[packageName] = packageLocation; - } - return result; -} - -/// Writes the mapping to a [StringSink]. -/// -/// If [comment] is provided, the output will contain this comment -/// with `# ` in front of each line. -/// Lines are defined as ending in line feed (`'\n'`). If the final -/// line of the comment doesn't end in a line feed, one will be added. -/// -/// If [baseUri] is provided, package locations will be made relative -/// to the base URI, if possible, before writing. -/// -/// If [allowDefaultPackage] is `true`, the [packageMapping] may contain an -/// empty string mapping to the _default package name_. -/// -/// All the keys of [packageMapping] must be valid package names, -/// and the values must be URIs that do not have the `package:` scheme. -void write(StringSink output, Map packageMapping, - {Uri baseUri, String comment, bool allowDefaultPackage = false}) { - ArgumentError.checkNotNull(allowDefaultPackage, 'allowDefaultPackage'); - - if (baseUri != null && !baseUri.isAbsolute) { - throw ArgumentError.value(baseUri, "baseUri", "Must be absolute"); - } - - if (comment != null) { - var lines = comment.split('\n'); - if (lines.last.isEmpty) lines.removeLast(); - for (var commentLine in lines) { - output.write('# '); - output.writeln(commentLine); - } - } else { - output.write("# generated by package:package_config at "); - output.write(DateTime.now()); - output.writeln(); - } - - packageMapping.forEach((String packageName, Uri uri) { - // If [packageName] is empty then [uri] is the _default package name_. - if (allowDefaultPackage && packageName.isEmpty) { - final defaultPackageName = uri.toString(); - if (!isValidPackageName(defaultPackageName)) { - throw ArgumentError.value( - defaultPackageName, - 'defaultPackageName', - '"$defaultPackageName" is not a valid package name', - ); - } - output.write(':'); - output.write(defaultPackageName); - output.writeln(); - return; - } - // Validate packageName. - if (!isValidPackageName(packageName)) { - throw ArgumentError('"$packageName" is not a valid package name'); - } - if (uri.scheme == "package") { - throw ArgumentError.value( - "Package location must not be a package: URI", uri.toString()); - } - output.write(packageName); - output.write(':'); - // If baseUri provided, make uri relative. - if (baseUri != null) { - uri = _relativize(uri, baseUri); - } - if (!uri.path.endsWith('/')) { - uri = uri.replace(path: uri.path + '/'); - } - output.write(uri); - output.writeln(); - }); -} - -/// Attempts to return a relative URI for [uri]. -/// -/// The result URI satisfies `baseUri.resolveUri(result) == uri`, -/// but may be relative. -/// The `baseUri` must be absolute. -Uri _relativize(Uri uri, Uri baseUri) { - assert(baseUri.isAbsolute); - if (uri.hasQuery || uri.hasFragment) { - uri = Uri( - scheme: uri.scheme, - userInfo: uri.hasAuthority ? uri.userInfo : null, - host: uri.hasAuthority ? uri.host : null, - port: uri.hasAuthority ? uri.port : null, - path: uri.path); - } - - // Already relative. We assume the caller knows what they are doing. - if (!uri.isAbsolute) return uri; - - if (baseUri.scheme != uri.scheme) { - return uri; - } - - // If authority differs, we could remove the scheme, but it's not worth it. - if (uri.hasAuthority != baseUri.hasAuthority) return uri; - if (uri.hasAuthority) { - if (uri.userInfo != baseUri.userInfo || - uri.host.toLowerCase() != baseUri.host.toLowerCase() || - uri.port != baseUri.port) { - return uri; - } - } - - baseUri = baseUri.normalizePath(); - var base = baseUri.pathSegments.toList(); - if (base.isNotEmpty) { - base = List.from(base)..removeLast(); - } - uri = uri.normalizePath(); - var target = uri.pathSegments.toList(); - if (target.isNotEmpty && target.last.isEmpty) target.removeLast(); - var index = 0; - while (index < base.length && index < target.length) { - if (base[index] != target[index]) { - break; - } - index++; - } - if (index == base.length) { - if (index == target.length) { - return Uri(path: "./"); - } - return Uri(path: target.skip(index).join('/')); - } else if (index > 0) { - return Uri( - path: '../' * (base.length - index) + target.skip(index).join('/')); - } else { - return uri; - } -} diff --git a/pkgs/package_config/lib/src/discovery.dart b/pkgs/package_config/lib/src/discovery.dart index 8ac6a0128..a3e01d710 100644 --- a/pkgs/package_config/lib/src/discovery.dart +++ b/pkgs/package_config/lib/src/discovery.dart @@ -32,7 +32,7 @@ final Uri parentPath = Uri(path: ".."); /// If any of these tests succeed, a `PackageConfig` class is returned. /// Returns `null` if no configuration was found. If a configuration /// is needed, then the caller can supply [PackageConfig.empty]. -Future findPackageConfig( +Future findPackageConfig( Directory baseDirectory, bool recursive, void onError(Object error)) async { var directory = baseDirectory; if (!directory.isAbsolute) directory = directory.absolute; @@ -53,10 +53,10 @@ Future findPackageConfig( } /// Similar to [findPackageConfig] but based on a URI. -Future findPackageConfigUri( +Future findPackageConfigUri( Uri location, - Future loader(Uri uri) /*?*/, - void onError(Object error) /*?*/, + Future loader(Uri uri)?, + void onError(Object error), bool recursive) async { if (location.isScheme("package")) { onError(PackageConfigArgumentError( @@ -102,7 +102,7 @@ Future findPackageConfigUri( /// If [onError] is supplied, parsing errors are reported using that, and /// a best-effort attempt is made to return a package configuration. /// This may be the empty package configuration. -Future findPackagConfigInDirectory( +Future findPackagConfigInDirectory( Directory directory, void onError(Object error)) async { var packageConfigFile = await checkForPackageConfigJsonFile(directory); if (packageConfigFile != null) { @@ -115,7 +115,7 @@ Future findPackagConfigInDirectory( return null; } -Future /*?*/ checkForPackageConfigJsonFile(Directory directory) async { +Future checkForPackageConfigJsonFile(Directory directory) async { assert(directory.isAbsolute); var file = File(pathJoin(directory.path, ".dart_tool", "package_config.json")); @@ -123,7 +123,7 @@ Future /*?*/ checkForPackageConfigJsonFile(Directory directory) async { return null; } -Future checkForDotPackagesFile(Directory directory) async { +Future checkForDotPackagesFile(Directory directory) async { var file = File(pathJoin(directory.path, ".packages")); if (await file.exists()) return file; return null; diff --git a/pkgs/package_config/lib/src/errors.dart b/pkgs/package_config/lib/src/errors.dart index c9736177c..f3515711d 100644 --- a/pkgs/package_config/lib/src/errors.dart +++ b/pkgs/package_config/lib/src/errors.dart @@ -12,7 +12,7 @@ abstract class PackageConfigError { class PackageConfigArgumentError extends ArgumentError implements PackageConfigError { - PackageConfigArgumentError(Object /*?*/ value, String name, String message) + PackageConfigArgumentError(Object? value, String name, String message) : super.value(value, name, message); PackageConfigArgumentError.from(ArgumentError error) @@ -21,8 +21,7 @@ class PackageConfigArgumentError extends ArgumentError class PackageConfigFormatException extends FormatException implements PackageConfigError { - PackageConfigFormatException(String message, Object /*?*/ source, - [int /*?*/ offset]) + PackageConfigFormatException(String message, Object? source, [int? offset]) : super(message, source, offset); PackageConfigFormatException.from(FormatException exception) @@ -30,4 +29,4 @@ class PackageConfigFormatException extends FormatException } /// The default `onError` handler. -void /*Never*/ throwError(Object error) => throw error; +Never throwError(Object error) => throw error; diff --git a/pkgs/package_config/lib/src/package_config.dart b/pkgs/package_config/lib/src/package_config.dart index 30c758a96..63d01eacd 100644 --- a/pkgs/package_config/lib/src/package_config.dart +++ b/pkgs/package_config/lib/src/package_config.dart @@ -50,7 +50,7 @@ abstract class PackageConfig { /// [PackageConfig.extraData] of the created configuration. /// /// The version of the resulting configuration is always [maxVersion]. - factory PackageConfig(Iterable packages, {dynamic extraData}) => + factory PackageConfig(Iterable packages, {Object? extraData}) => SimplePackageConfig(maxVersion, packages, extraData); /// Parses a package configuration file. @@ -67,10 +67,10 @@ abstract class PackageConfig { /// the configuration are reported by calling [onError] instead of /// throwing, and parser makes a *best effort* attempt to continue /// despite the error. The input must still be valid JSON. - /// The result may be a [PackageConfig.empty] if there is no way to + /// The result may be [PackageConfig.empty] if there is no way to /// extract useful information from the bytes. static PackageConfig parseBytes(Uint8List bytes, Uri baseUri, - {void onError(Object error)}) => + {void onError(Object error)?}) => parsePackageConfigBytes(bytes, baseUri, onError ?? throwError); /// Parses a package configuration file. @@ -87,10 +87,10 @@ abstract class PackageConfig { /// the configuration are reported by calling [onError] instead of /// throwing, and parser makes a *best effort* attempt to continue /// despite the error. The input must still be valid JSON. - /// The result may be a [PackageConfig.empty] if there is no way to + /// The result may be [PackageConfig.empty] if there is no way to /// extract useful information from the bytes. static PackageConfig parseString(String configuration, Uri baseUri, - {void onError(Object error)}) => + {void onError(Object error)?}) => parsePackageConfigString(configuration, baseUri, onError ?? throwError); /// Parses the JSON data of a package configuration file. @@ -108,10 +108,10 @@ abstract class PackageConfig { /// the configuration are reported by calling [onError] instead of /// throwing, and parser makes a *best effort* attempt to continue /// despite the error. The input must still be valid JSON. - /// The result may be a [PackageConfig.empty] if there is no way to + /// The result may be [PackageConfig.empty] if there is no way to /// extract useful information from the bytes. - static PackageConfig parseJson(dynamic jsonData, Uri baseUri, - {void onError(Object error)}) => + static PackageConfig parseJson(Object? jsonData, Uri baseUri, + {void onError(Object error)?}) => parsePackageConfigJson(jsonData, baseUri, onError ?? throwError); /// Writes a configuration file for this configuration on [output]. @@ -119,7 +119,7 @@ abstract class PackageConfig { /// If [baseUri] is provided, URI references in the generated file /// will be made relative to [baseUri] where possible. static void writeBytes(PackageConfig configuration, Sink output, - [Uri /*?*/ baseUri]) { + [Uri? baseUri]) { writePackageConfigJsonUtf8(configuration, baseUri, output); } @@ -128,7 +128,7 @@ abstract class PackageConfig { /// If [baseUri] is provided, URI references in the generated file /// will be made relative to [baseUri] where possible. static void writeString(PackageConfig configuration, StringSink output, - [Uri /*?*/ baseUri]) { + [Uri? baseUri]) { writePackageConfigJsonString(configuration, baseUri, output); } @@ -136,8 +136,8 @@ abstract class PackageConfig { /// /// If [baseUri] is provided, URI references in the generated data /// will be made relative to [baseUri] where possible. - static Map toJson(PackageConfig configuration, - [Uri /*?*/ baseUri]) => + static Map toJson(PackageConfig configuration, + [Uri? baseUri]) => packageConfigToJson(configuration, baseUri); /// The configuration version number. @@ -162,7 +162,7 @@ abstract class PackageConfig { /// Returns the [Package] fron [packages] with [packageName] as /// [Package.name]. Returns `null` if the package is not available in the /// current configuration. - Package /*?*/ operator [](String packageName); + Package? operator [](String packageName); /// Provides the associated package for a specific [file] (or directory). /// @@ -171,7 +171,7 @@ abstract class PackageConfig { /// of the [file]'s location. /// /// Returns `null` if the file does not belong to any package. - Package /*?*/ packageOf(Uri file); + Package? packageOf(Uri file); /// Resolves a `package:` URI to a non-package URI /// @@ -188,7 +188,7 @@ abstract class PackageConfig { /// in this package configuration. /// Returns the remaining path of the package URI resolved relative to the /// [Package.packageUriRoot] of the corresponding package. - Uri /*?*/ resolve(Uri packageUri); + Uri? resolve(Uri packageUri); /// The package URI which resolves to [nonPackageUri]. /// @@ -199,14 +199,14 @@ abstract class PackageConfig { /// /// Returns a package URI which [resolve] will convert to [nonPackageUri], /// if any such URI exists. Returns `null` if no such package URI exists. - Uri /*?*/ toPackageUri(Uri nonPackageUri); + Uri? toPackageUri(Uri nonPackageUri); /// Extra data associated with the package configuration. /// /// The data may be in any format, depending on who introduced it. /// The standard `packjage_config.json` file storage will only store /// JSON-like list/map data structures. - dynamic get extraData; + Object? get extraData; } /// Configuration data for a single package. @@ -227,11 +227,11 @@ abstract class Package { /// If [extraData] is supplied, it will be available as the /// [Package.extraData] of the created package. factory Package(String name, Uri root, - {Uri /*?*/ packageUriRoot, - LanguageVersion /*?*/ languageVersion, - dynamic extraData}) => + {Uri? packageUriRoot, + LanguageVersion? languageVersion, + Object? extraData}) => SimplePackage.validate( - name, root, packageUriRoot, languageVersion, extraData, throwError); + name, root, packageUriRoot, languageVersion, extraData, throwError)!; /// The package-name of the package. String get name; @@ -263,14 +263,18 @@ abstract class Package { /// Dart files in the package. /// A package version is defined by two non-negative numbers, /// the *major* and *minor* version numbers. - LanguageVersion /*?*/ get languageVersion; + /// + /// A package may have no language version associated with it + /// in the package configuration, in which case tools should + /// use a default behavior for the package. + LanguageVersion? get languageVersion; /// Extra data associated with the specific package. /// /// The data may be in any format, depending on who introduced it. - /// The standard `packjage_config.json` file storage will only store + /// The standard `package_config.json` file storage will only store /// JSON-like list/map data structures. - dynamic get extraData; + Object? get extraData; } /// A language version. @@ -307,7 +311,7 @@ abstract class LanguageVersion implements Comparable { /// If [onError] is not supplied, it defaults to throwing the exception. /// If the call does not throw, then an [InvalidLanguageVersion] is returned /// containing the original [source]. - static LanguageVersion parse(String source, {void onError(Object error)}) => + static LanguageVersion parse(String source, {void onError(Object error)?}) => parseLanguageVersion(source, onError ?? throwError); /// The major language version. diff --git a/pkgs/package_config/lib/src/package_config_impl.dart b/pkgs/package_config/lib/src/package_config_impl.dart index 9e23af063..5c6b7f728 100644 --- a/pkgs/package_config/lib/src/package_config_impl.dart +++ b/pkgs/package_config/lib/src/package_config_impl.dart @@ -14,10 +14,10 @@ class SimplePackageConfig implements PackageConfig { final int version; final Map _packages; final PackageTree _packageTree; - final dynamic extraData; + final Object? extraData; factory SimplePackageConfig(int version, Iterable packages, - [dynamic extraData, void onError(Object error)]) { + [Object? extraData, void onError(Object error)?]) { onError ??= throwError; var validVersion = _validateVersion(version, onError); var sortedPackages = [...packages]..sort(_compareRoot); @@ -53,11 +53,7 @@ class SimplePackageConfig implements PackageConfig { var packageNames = {}; var tree = MutablePackageTree(); for (var originalPackage in packages) { - if (originalPackage == null) { - onError(ArgumentError.notNull("element of packages")); - continue; - } - SimplePackage package; + SimplePackage? package; if (originalPackage is! SimplePackage) { // SimplePackage validates these properties. package = SimplePackage.validate( @@ -68,7 +64,7 @@ class SimplePackageConfig implements PackageConfig { originalPackage.extraData, (error) { if (error is PackageConfigArgumentError) { onError(PackageConfigArgumentError(packages, "packages", - "Package ${package.name}: ${error.message}")); + "Package ${package!.name}: ${error.message}")); } else { onError(error); } @@ -92,7 +88,7 @@ class SimplePackageConfig implements PackageConfig { onError(PackageConfigArgumentError( originalPackages, "packages", - "Packages ${package.name} and ${existingPackage.name} " + "Packages ${package!.name} and ${existingPackage.name} " "have the same root directory: ${package.root}.\n")); } else { assert(error.isPackageRootConflict); @@ -100,7 +96,7 @@ class SimplePackageConfig implements PackageConfig { onError(PackageConfigArgumentError( originalPackages, "packages", - "Package ${package.name} is inside the package URI root of " + "Package ${package!.name} is inside the package URI root of " "package ${existingPackage.name}.\n" "${existingPackage.name} URI root: " "${existingPackage.packageUriRoot}\n" @@ -117,7 +113,7 @@ class SimplePackageConfig implements PackageConfig { Iterable get packages => _packages.values; - Package /*?*/ operator [](String packageName) => _packages[packageName]; + Package? operator [](String packageName) => _packages[packageName]; /// Provides the associated package for a specific [file] (or directory). /// @@ -125,15 +121,15 @@ class SimplePackageConfig implements PackageConfig { /// That is, the [Package.rootUri] directory is a parent directory /// of the [file]'s location. /// Returns `null` if the file does not belong to any package. - Package /*?*/ packageOf(Uri file) => _packageTree.packageOf(file); + Package? packageOf(Uri file) => _packageTree.packageOf(file); - Uri /*?*/ resolve(Uri packageUri) { + Uri? resolve(Uri packageUri) { var packageName = checkValidPackageUri(packageUri, "packageUri"); - return _packages[packageName]?.packageUriRoot?.resolveUri( + return _packages[packageName]?.packageUriRoot.resolveUri( Uri(path: packageUri.path.substring(packageName.length + 1))); } - Uri /*?*/ toPackageUri(Uri nonPackageUri) { + Uri? toPackageUri(Uri nonPackageUri) { if (nonPackageUri.isScheme("package")) { throw PackageConfigArgumentError( nonPackageUri, "nonPackageUri", "Must not be a package URI"); @@ -161,8 +157,8 @@ class SimplePackage implements Package { final String name; final Uri root; final Uri packageUriRoot; - final LanguageVersion /*?*/ languageVersion; - final dynamic extraData; + final LanguageVersion? languageVersion; + final Object? extraData; SimplePackage._(this.name, this.root, this.packageUriRoot, this.languageVersion, this.extraData); @@ -182,12 +178,12 @@ class SimplePackage implements Package { /// /// Returns `null` if the input is invalid and an approximately valid package /// cannot be salvaged from the input. - static SimplePackage /*?*/ validate( + static SimplePackage? validate( String name, Uri root, - Uri packageUriRoot, - LanguageVersion /*?*/ languageVersion, - dynamic extraData, + Uri? packageUriRoot, + LanguageVersion? languageVersion, + Object? extraData, void onError(Object error)) { var fatalError = false; var invalidIndex = checkPackageName(name); @@ -244,7 +240,7 @@ class SimplePackage implements Package { /// Reports a format exception on [onError] if not, or if the numbers /// are too large (at most 32-bit signed integers). LanguageVersion parseLanguageVersion( - String source, void onError(Object error)) { + String? source, void onError(Object error)) { var index = 0; // Reads a positive decimal numeral. Returns the value of the numeral, // or a negative number in case of an error. @@ -254,7 +250,7 @@ LanguageVersion parseLanguageVersion( // It is a recoverable error if the numeral starts with leading zeros. int readNumeral() { const maxValue = 0x7FFFFFFF; - if (index == source.length) { + if (index == source!.length) { onError(PackageConfigFormatException("Missing number", source, index)); return -1; } @@ -291,7 +287,7 @@ LanguageVersion parseLanguageVersion( if (major < 0) { return SimpleInvalidLanguageVersion(source); } - if (index == source.length || source.codeUnitAt(index) != $dot) { + if (index == source!.length || source.codeUnitAt(index) != $dot) { onError(PackageConfigFormatException("Missing '.'", source, index)); return SimpleInvalidLanguageVersion(source); } @@ -319,7 +315,7 @@ abstract class _SimpleLanguageVersionBase implements LanguageVersion { class SimpleLanguageVersion extends _SimpleLanguageVersionBase { final int major; final int minor; - String /*?*/ _source; + String? _source; SimpleLanguageVersion(this.major, this.minor, this._source); bool operator ==(Object other) => @@ -332,17 +328,17 @@ class SimpleLanguageVersion extends _SimpleLanguageVersionBase { class SimpleInvalidLanguageVersion extends _SimpleLanguageVersionBase implements InvalidLanguageVersion { - final String _source; + final String? _source; SimpleInvalidLanguageVersion(this._source); int get major => -1; int get minor => -1; - String toString() => _source; + String toString() => _source!; } abstract class PackageTree { Iterable get allPackages; - SimplePackage /*?*/ packageOf(Uri file); + SimplePackage? packageOf(Uri file); } /// Packages of a package configuration ordered by root path. @@ -373,12 +369,17 @@ class MutablePackageTree implements PackageTree { /// Indexed by [Package.name]. /// If a package has no nested packages (which is most often the case), /// there is no tree object associated with it. - Map /*?*/ _packageChildren; + Map? _packageChildren; Iterable get allPackages sync* { - for (var package in packages) yield package; - if (_packageChildren != null) { - for (var tree in _packageChildren.values) yield* tree.allPackages; + for (var package in packages) { + yield package; + } + var children = _packageChildren; + if (children != null) { + for (var tree in children.values) { + yield* tree.allPackages; + } } } @@ -424,7 +425,7 @@ class MutablePackageTree implements PackageTree { packages.add(package); } - SimplePackage /*?*/ packageOf(Uri file) { + SimplePackage? packageOf(Uri file) { return findPackageOf(0, file.toString()); } @@ -434,7 +435,7 @@ class MutablePackageTree implements PackageTree { /// /// Assumes the first [start] characters of path agrees with all /// the packages at this level of the tree. - SimplePackage /*?*/ findPackageOf(int start, String path) { + SimplePackage? findPackageOf(int start, String path) { for (var childPackage in packages) { var childPath = childPackage.root.toString(); if (_beginsWith(start, childPath, path)) { @@ -447,14 +448,9 @@ class MutablePackageTree implements PackageTree { _beginsWith(childPathLength, uriRoot, path)) { return childPackage; } - // Otherwise add [package] as child of [childPackage]. - // TODO(lrn): When NNBD comes, convert to: - // return _packageChildren?[childPackage.name] - // ?.packageOf(childPathLength, path) ?? childPackage; - if (_packageChildren == null) return childPackage; - var childTree = _packageChildren[childPackage.name]; - if (childTree == null) return childPackage; - return childTree.findPackageOf(childPathLength, path) ?? childPackage; + return _packageChildren?[childPackage.name] + ?.findPackageOf(childPathLength, path) ?? + childPackage; } } return null; @@ -474,7 +470,7 @@ class EmptyPackageTree implements PackageTree { Iterable get allPackages => const Iterable.empty(); - SimplePackage packageOf(Uri file) => null; + SimplePackage? packageOf(Uri file) => null; } /// Checks whether [longerPath] begins with [parentPath]. diff --git a/pkgs/package_config/lib/src/package_config_io.dart b/pkgs/package_config/lib/src/package_config_io.dart index bfbb1e373..d3e59be47 100644 --- a/pkgs/package_config/lib/src/package_config_io.dart +++ b/pkgs/package_config/lib/src/package_config_io.dart @@ -15,6 +15,21 @@ import "packages_file.dart" as packages_file; import "util.dart"; import "util_io.dart"; +/// Name of directory where Dart tools store their configuration. +/// +/// Directory is created in the package root directory. +const dartToolDirName = ".dart_tool"; + +/// Name of file containing new package configuration data. +/// +/// File is stored in the dart tool directory. +const packageConfigFileName = "package_config.json"; + +/// Name of file containing legacy package configuration data. +/// +/// File is stored in the package root directory. +const packagesFileName = ".packages"; + /// Reads a package configuration file. /// /// Detects whether the [file] is a version one `.packages` file or @@ -29,9 +44,9 @@ import "util_io.dart"; /// The file must exist and be a normal file. Future readAnyConfigFile( File file, bool preferNewest, void onError(Object error)) async { - if (preferNewest && fileName(file.path) == ".packages") { - var alternateFile = - File(pathJoin(dirName(file.path), ".dart_tool", "package_config.json")); + if (preferNewest && fileName(file.path) == packagesFileName) { + var alternateFile = File( + pathJoin(dirName(file.path), dartToolDirName, packageConfigFileName)); if (alternateFile.existsSync()) { return await readPackageConfigJsonFile(alternateFile, onError); } @@ -49,7 +64,7 @@ Future readAnyConfigFile( /// Like [readAnyConfigFile] but uses a URI and an optional loader. Future readAnyConfigFileUri( Uri file, - Future loader(Uri uri) /*?*/, + Future loader(Uri uri)?, void onError(Object error), bool preferNewest) async { if (file.isScheme("package")) { @@ -62,9 +77,9 @@ Future readAnyConfigFileUri( } loader = defaultLoader; } - if (preferNewest && file.pathSegments.last == ".packages") { - var alternateFile = file.resolve(".dart_tool/package_config.json"); - Uint8List /*?*/ bytes; + if (preferNewest && file.pathSegments.last == packagesFileName) { + var alternateFile = file.resolve("$dartToolDirName/$packageConfigFileName"); + Uint8List? bytes; try { bytes = await loader(alternateFile); } catch (e) { @@ -75,7 +90,7 @@ Future readAnyConfigFileUri( return parsePackageConfigBytes(bytes, alternateFile, onError); } } - Uint8List /*?*/ bytes; + Uint8List? bytes; try { bytes = await loader(file); } catch (e) { @@ -131,15 +146,17 @@ Future readDotPackagesFile( Future writePackageConfigJsonFile( PackageConfig config, Directory targetDirectory) async { // Write .dart_tool/package_config.json first. - var file = - File(pathJoin(targetDirectory.path, ".dart_tool", "package_config.json")); + var dartToolDir = Directory(pathJoin(targetDirectory.path, dartToolDirName)); + await dartToolDir.create(recursive: true); + var file = File(pathJoin(dartToolDir.path, packageConfigFileName)); var baseUri = file.uri; + var sink = file.openWrite(encoding: utf8); writePackageConfigJsonUtf8(config, baseUri, sink); var doneJson = sink.close(); // Write .packages too. - file = File(pathJoin(targetDirectory.path, ".packages")); + file = File(pathJoin(targetDirectory.path, packagesFileName)); baseUri = file.uri; sink = file.openWrite(encoding: utf8); writeDotPackages(config, baseUri, sink); diff --git a/pkgs/package_config/lib/src/package_config_json.dart b/pkgs/package_config/lib/src/package_config_json.dart index 27abf505c..25b04c4d1 100644 --- a/pkgs/package_config/lib/src/package_config_json.dart +++ b/pkgs/package_config/lib/src/package_config_json.dart @@ -59,10 +59,10 @@ PackageConfig parsePackageConfigString( /// Creates a [PackageConfig] from a parsed JSON-like object structure. /// -/// The [json] argument must be a JSON object (`Map`) +/// The [json] argument must be a JSON object (`Map`) /// containing a `"configVersion"` entry with an integer value in the range /// 1 to [PackageConfig.maxVersion], -/// and with a `"packages"` entry which is a JSON array (`List`) +/// and with a `"packages"` entry which is a JSON array (`List`) /// containing JSON objects which each has the following properties: /// /// * `"name"`: The package name as a string. @@ -80,7 +80,7 @@ PackageConfig parsePackageConfigString( /// The [baseLocation] is used as base URI to resolve the "rootUri" /// URI referencestring. PackageConfig parsePackageConfigJson( - dynamic json, Uri baseLocation, void onError(Object error)) { + Object? json, Uri baseLocation, void onError(Object error)) { if (!baseLocation.hasScheme || baseLocation.isScheme("package")) { throw PackageConfigArgumentError(baseLocation.toString(), "baseLocation", "Must be an absolute non-package: URI"); @@ -97,10 +97,10 @@ PackageConfig parsePackageConfigJson( return "object"; } - T checkType(dynamic value, String name, [String /*?*/ packageName]) { + T? checkType(Object? value, String name, [String? packageName]) { if (value is T) return value; - // The only types we are called with are [int], [String], [List] - // and Map. Recognize which to give a better error message. + // The only types we are called with are [int], [String], [List] + // and Map. Recognize which to give a better error message. var message = "$name${packageName != null ? " of package $packageName" : ""}" " is not a JSON ${typeName()}"; @@ -108,12 +108,12 @@ PackageConfig parsePackageConfigJson( return null; } - Package /*?*/ parsePackage(Map entry) { - String /*?*/ name; - String /*?*/ rootUri; - String /*?*/ packageUri; - String /*?*/ languageVersion; - Map /*?*/ extraData; + Package? parsePackage(Map entry) { + String? name; + String? rootUri; + String? packageUri; + String? languageVersion; + Map? extraData; var hasName = false; var hasRoot = false; var hasVersion = false; @@ -146,22 +146,22 @@ PackageConfig parsePackageConfigJson( onError(PackageConfigFormatException("Missing rootUri entry", entry)); } if (name == null || rootUri == null) return null; - var root = baseLocation.resolve(rootUri); + var root = baseLocation.resolve(rootUri!); if (!root.path.endsWith("/")) root = root.replace(path: root.path + "/"); var packageRoot = root; - if (packageUri != null) packageRoot = root.resolve(packageUri); + if (packageUri != null) packageRoot = root.resolve(packageUri!); if (!packageRoot.path.endsWith("/")) { packageRoot = packageRoot.replace(path: packageRoot.path + "/"); } - LanguageVersion /*?*/ version; + LanguageVersion? version; if (languageVersion != null) { version = parseLanguageVersion(languageVersion, onError); } else if (hasVersion) { version = SimpleInvalidLanguageVersion("invalid"); } - return SimplePackage.validate(name, root, packageRoot, version, extraData, + return SimplePackage.validate(name!, root, packageRoot, version, extraData, (error) { if (error is ArgumentError) { onError( @@ -172,22 +172,22 @@ PackageConfig parsePackageConfigJson( }); } - var map = checkType>(json, "value"); + var map = checkType>(json, "value"); if (map == null) return const SimplePackageConfig.empty(); - Map /*?*/ extraData; - List /*?*/ packageList; - int /*?*/ configVersion; + Map? extraData; + List? packageList; + int? configVersion; map.forEach((key, value) { switch (key) { case _configVersionKey: configVersion = checkType(value, _configVersionKey) ?? 2; break; case _packagesKey: - var packageArray = checkType>(value, _packagesKey) ?? []; + var packageArray = checkType>(value, _packagesKey) ?? []; var packages = []; for (var package in packageArray) { var packageMap = - checkType>(package, "package entry"); + checkType>(package, "package entry"); if (packageMap != null) { var entry = parsePackage(packageMap); if (entry != null) { @@ -210,7 +210,7 @@ PackageConfig parsePackageConfigJson( onError(PackageConfigFormatException("Missing packages list", json)); packageList = []; } - return SimplePackageConfig(configVersion, packageList, extraData, (error) { + return SimplePackageConfig(configVersion!, packageList!, extraData, (error) { if (error is ArgumentError) { onError(PackageConfigFormatException(error.message, error.invalidValue)); } else { @@ -222,26 +222,26 @@ PackageConfig parsePackageConfigJson( final _jsonUtf8Encoder = JsonUtf8Encoder(" "); void writePackageConfigJsonUtf8( - PackageConfig config, Uri baseUri, Sink> output) { + PackageConfig config, Uri? baseUri, Sink> output) { // Can be optimized. var data = packageConfigToJson(config, baseUri); output.add(_jsonUtf8Encoder.convert(data) as Uint8List); } void writePackageConfigJsonString( - PackageConfig config, Uri baseUri, StringSink output) { + PackageConfig config, Uri? baseUri, StringSink output) { // Can be optimized. var data = packageConfigToJson(config, baseUri); output.write(JsonEncoder.withIndent(" ").convert(data) as Uint8List); } -Map packageConfigToJson(PackageConfig config, Uri baseUri) => - { +Map packageConfigToJson(PackageConfig config, Uri? baseUri) => + { ...?_extractExtraData(config.extraData, _topNames), _configVersionKey: PackageConfig.maxVersion, _packagesKey: [ for (var package in config.packages) - { + { _nameKey: package.name, _rootUriKey: relativizeUri(package.root, baseUri).toString(), if (package.root != package.packageUriRoot) @@ -259,15 +259,15 @@ Map packageConfigToJson(PackageConfig config, Uri baseUri) => void writeDotPackages(PackageConfig config, Uri baseUri, StringSink output) { var extraData = config.extraData; // Write .packages too. - String /*?*/ comment; - if (extraData != null) { - String /*?*/ generator = extraData[_generatorKey]; - if (generator != null) { - String /*?*/ generated = extraData[_generatedKey]; - String /*?*/ generatorVersion = extraData[_generatorVersionKey]; + String? comment; + if (extraData is Map) { + var generator = extraData[_generatorKey]; + if (generator is String) { + var generated = extraData[_generatedKey]; + var generatorVersion = extraData[_generatorVersionKey]; comment = "Generated by $generator" - "${generatorVersion != null ? " $generatorVersion" : ""}" - "${generated != null ? " on $generated" : ""}."; + "${generatorVersion is String ? " $generatorVersion" : ""}" + "${generated is String ? " on $generated" : ""}."; } } packages_file.write(output, config, baseUri: baseUri, comment: comment); @@ -277,20 +277,21 @@ void writeDotPackages(PackageConfig config, Uri baseUri, StringSink output) { /// /// If the value contains any of the [reservedNames] for the current context, /// entries with that name in the extra data are dropped. -Map /*?*/ _extractExtraData( - dynamic data, Iterable reservedNames) { - if (data is Map) { +Map? _extractExtraData( + Object? data, Iterable reservedNames) { + if (data is Map) { if (data.isEmpty) return null; for (var name in reservedNames) { if (data.containsKey(name)) { - data = { + var filteredData = { for (var key in data.keys) if (!reservedNames.contains(key)) key: data[key] }; - if (data.isEmpty) return null; - for (var value in data.values) { + if (filteredData.isEmpty) return null; + for (var value in filteredData.values) { if (!_validateJson(value)) return null; } + return filteredData; } } return data; @@ -299,13 +300,13 @@ Map /*?*/ _extractExtraData( } /// Checks that the object is a valid JSON-like data structure. -bool _validateJson(dynamic object) { +bool _validateJson(Object? object) { if (object == null || true == object || false == object) return true; if (object is num || object is String) return true; - if (object is List) { + if (object is List) { return object.every(_validateJson); } - if (object is Map) { + if (object is Map) { return object.values.every(_validateJson); } return false; diff --git a/pkgs/package_config/lib/src/packages_file.dart b/pkgs/package_config/lib/src/packages_file.dart index 184b0dd04..071d548a5 100644 --- a/pkgs/package_config/lib/src/packages_file.dart +++ b/pkgs/package_config/lib/src/packages_file.dart @@ -154,7 +154,7 @@ PackageConfig parse( /// All the keys of [packageMapping] must be valid package names, /// and the values must be URIs that do not have the `package:` scheme. void write(StringSink output, PackageConfig config, - {Uri baseUri, String comment}) { + {Uri? baseUri, String? comment}) { if (baseUri != null && !baseUri.isAbsolute) { throw PackageConfigArgumentError(baseUri, "baseUri", "Must be absolute"); } @@ -187,7 +187,7 @@ void write(StringSink output, PackageConfig config, output.write(':'); // If baseUri is provided, make the URI relative to baseUri. if (baseUri != null) { - uri = relativizeUri(uri, baseUri); + uri = relativizeUri(uri, baseUri)!; } if (!uri.path.endsWith('/')) { uri = uri.replace(path: uri.path + '/'); diff --git a/pkgs/package_config/lib/src/packages_impl.dart b/pkgs/package_config/lib/src/packages_impl.dart deleted file mode 100644 index 19f103922..000000000 --- a/pkgs/package_config/lib/src/packages_impl.dart +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (c) 2015, 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. - -/// Implementations of [Packages] that may be used in either server or browser -/// based applications. For implementations that can only run in the browser, -/// see [package_config.packages_io_impl]. -@Deprecated("Use the package_config.json based API") -library package_config.packages_impl; - -import "dart:collection" show UnmodifiableMapView; - -import "../packages.dart"; -import "util.dart" show checkValidPackageUri; - -/// A [Packages] null-object. -class NoPackages implements Packages { - const NoPackages(); - - Uri resolve(Uri packageUri, {Uri notFound(Uri packageUri)}) { - var packageName = checkValidPackageUri(packageUri, "packageUri"); - if (notFound != null) return notFound(packageUri); - throw ArgumentError.value( - packageUri, "packageUri", 'No package named "$packageName"'); - } - - Iterable get packages => Iterable.empty(); - - Map asMap() => const {}; - - String get defaultPackageName => null; - - String packageMetadata(String packageName, String key) => null; - - String libraryMetadata(Uri libraryUri, String key) => null; -} - -/// Base class for [Packages] implementations. -/// -/// This class implements the [resolve] method in terms of a private -/// member -abstract class PackagesBase implements Packages { - Uri resolve(Uri packageUri, {Uri notFound(Uri packageUri)}) { - packageUri = packageUri.normalizePath(); - var packageName = checkValidPackageUri(packageUri, "packageUri"); - var packageBase = getBase(packageName); - if (packageBase == null) { - if (notFound != null) return notFound(packageUri); - throw ArgumentError.value( - packageUri, "packageUri", 'No package named "$packageName"'); - } - var packagePath = packageUri.path.substring(packageName.length + 1); - return packageBase.resolve(packagePath); - } - - /// Find a base location for a package name. - /// - /// Returns `null` if no package exists with that name, and that can be - /// determined. - Uri getBase(String packageName); - - String get defaultPackageName => null; - - String packageMetadata(String packageName, String key) => null; - - String libraryMetadata(Uri libraryUri, String key) => null; -} - -/// A [Packages] implementation based on an existing map. -class MapPackages extends PackagesBase { - final Map _mapping; - MapPackages(this._mapping); - - Uri getBase(String packageName) => - packageName.isEmpty ? null : _mapping[packageName]; - - Iterable get packages => _mapping.keys; - - Map asMap() => UnmodifiableMapView(_mapping); - - String get defaultPackageName => _mapping[""]?.toString(); - - String packageMetadata(String packageName, String key) { - if (packageName.isEmpty) return null; - var uri = _mapping[packageName]; - if (uri == null || !uri.hasFragment) return null; - // This can be optimized, either by caching the map or by - // parsing incrementally instead of parsing the entire fragment. - return Uri.splitQueryString(uri.fragment)[key]; - } - - String libraryMetadata(Uri libraryUri, String key) { - if (libraryUri.isScheme("package")) { - return packageMetadata(libraryUri.pathSegments.first, key); - } - var defaultPackageNameUri = _mapping[""]; - if (defaultPackageNameUri != null) { - return packageMetadata(defaultPackageNameUri.toString(), key); - } - return null; - } -} - -/// A [Packages] implementation based on a remote (e.g., HTTP) directory. -/// -/// There is no way to detect which packages exist short of trying to use -/// them. You can't necessarily check whether a directory exists, -/// except by checking for a know file in the directory. -class NonFilePackagesDirectoryPackages extends PackagesBase { - final Uri _packageBase; - NonFilePackagesDirectoryPackages(this._packageBase); - - Uri getBase(String packageName) => _packageBase.resolve("$packageName/"); - - Error _failListingPackages() { - return UnsupportedError( - "Cannot list packages for a ${_packageBase.scheme}: " - "based package root"); - } - - Iterable get packages { - throw _failListingPackages(); - } - - Map asMap() { - throw _failListingPackages(); - } -} diff --git a/pkgs/package_config/lib/src/packages_io_impl.dart b/pkgs/package_config/lib/src/packages_io_impl.dart deleted file mode 100644 index c623f4d5d..000000000 --- a/pkgs/package_config/lib/src/packages_io_impl.dart +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2015, 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. - -/// Implementations of [Packages] that can only be used in server based -/// applications. -@Deprecated("Use the package_config.json based API") -library package_config.packages_io_impl; - -import "dart:collection" show UnmodifiableMapView; -import "dart:io" show Directory; - -import "packages_impl.dart"; - -import "util_io.dart"; - -/// A [Packages] implementation based on a local directory. -class FilePackagesDirectoryPackages extends PackagesBase { - final Directory _packageDir; - final Map _packageToBaseUriMap = {}; - - FilePackagesDirectoryPackages(this._packageDir); - - Uri getBase(String packageName) { - return _packageToBaseUriMap.putIfAbsent(packageName, () { - return Uri.file(pathJoin(_packageDir.path, packageName, '.')); - }); - } - - Iterable _listPackageNames() { - return _packageDir - .listSync() - .whereType() - .map((e) => fileName(e.path)); - } - - Iterable get packages => _listPackageNames(); - - Map asMap() { - var result = {}; - for (var packageName in _listPackageNames()) { - result[packageName] = getBase(packageName); - } - return UnmodifiableMapView(result); - } -} diff --git a/pkgs/package_config/lib/src/util.dart b/pkgs/package_config/lib/src/util.dart index 50b140fa0..9b263ae7a 100644 --- a/pkgs/package_config/lib/src/util.dart +++ b/pkgs/package_config/lib/src/util.dart @@ -153,10 +153,10 @@ int firstNonWhitespaceChar(List bytes) { /// `baseUri.resolveUri(result) == uri`, /// /// The `baseUri` must be absolute. -Uri relativizeUri(Uri uri, Uri /*?*/ baseUri) { +Uri? relativizeUri(Uri? uri, Uri? baseUri) { if (baseUri == null) return uri; assert(baseUri.isAbsolute); - if (uri.hasQuery || uri.hasFragment) { + if (uri!.hasQuery || uri.hasFragment) { uri = Uri( scheme: uri.scheme, userInfo: uri.hasAuthority ? uri.userInfo : null, diff --git a/pkgs/package_config/lib/src/util_io.dart b/pkgs/package_config/lib/src/util_io.dart index 2aa8c94bf..8e5f0b88e 100644 --- a/pkgs/package_config/lib/src/util_io.dart +++ b/pkgs/package_config/lib/src/util_io.dart @@ -9,7 +9,7 @@ library package_config.util_io; import 'dart:io'; import 'dart:typed_data'; -Future defaultLoader(Uri uri) async { +Future defaultLoader(Uri uri) async { if (uri.isScheme("file")) { var file = File.fromUri(uri); try { @@ -24,7 +24,7 @@ Future defaultLoader(Uri uri) async { throw UnsupportedError("Default URI unsupported scheme: $uri"); } -Future _httpGet(Uri uri) async { +Future _httpGet(Uri uri) async { assert(uri.isScheme("http") || uri.isScheme("https")); var client = HttpClient(); var request = await client.getUrl(uri); @@ -45,7 +45,7 @@ Future _httpGet(Uri uri) async { } var result = Uint8List(totalLength); var offset = 0; - for (Uint8List contentPart in splitContent) { + for (var contentPart in splitContent as Iterable) { result.setRange(offset, offset + contentPart.length, contentPart); offset += contentPart.length; } @@ -80,7 +80,7 @@ String dirName(String path) { /// /// If a part ends with a path separator, then no extra separator is /// inserted. -String pathJoin(String part1, String part2, [String part3]) { +String pathJoin(String part1, String part2, [String? part3]) { var separator = Platform.pathSeparator; var separator1 = part1.endsWith(separator) ? "" : separator; if (part3 == null) { diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index b7d596910..05c5266b2 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,20 +1,55 @@ name: package_config -version: 1.9.3 +version: 2.0.0-dev description: Support for working with Package Configuration files. homepage: https://github.com/dart-lang/package_config environment: - sdk: '>=2.7.0 <3.0.0' + sdk: '>=2.12.0-0 <3.0.0' dependencies: - path: ^1.6.4 - charcode: ^1.1.0 + path: ^1.8.0-nullsafety.3 dev_dependencies: - test: ^1.6.4 - matcher: ^0.12.5 - pedantic: ^1.9.0 + build_resolvers: ^1.10.0 + build_runner: ^1.10.0 + build_runner_core: ^1.10.0 + build_test: ^1.3.0 + build_web_compilers: ^2.15.0 + pedantic: ^1.10.0-nullsafety.3 + test: ^1.16.0-nullsafety.4 - build_runner: ^1.0.0 - build_web_compilers: ^2.0.0 - build_test: ^0.10.0 +dependency_overrides: + analyzer: + git: + url: git://github.com/dart-lang/sdk.git + path: pkg/analyzer + build_resolvers: + git: + url: git://github.com/dart-lang/build.git + path: build_resolvers + build_runner: + git: + url: git://github.com/dart-lang/build.git + path: build_runner + build_runner_core: + git: + url: git://github.com/dart-lang/build.git + path: build_runner_core + build_test: + git: + url: git://github.com/dart-lang/build.git + path: build_test + coverage: + git: git://github.com/dart-lang/coverage.git + test: + git: + url: git://github.com/dart-lang/test.git + path: pkgs/test + test_api: + git: + url: git://github.com/dart-lang/test.git + path: pkgs/test_api + test_core: + git: + url: git://github.com/dart-lang/test.git + path: pkgs/test_core diff --git a/pkgs/package_config/test/discovery_test.dart b/pkgs/package_config/test/discovery_test.dart index 5cbc99214..df2374d0b 100644 --- a/pkgs/package_config/test/discovery_test.dart +++ b/pkgs/package_config/test/discovery_test.dart @@ -63,7 +63,7 @@ void main() { "package_config.json": packageConfigFile, } }, (Directory directory) async { - var config = await findPackageConfig(directory); + var config = (await findPackageConfig(directory))!; expect(config.version, 2); // Found package_config.json file. validatePackagesFile(config, directory); }); @@ -74,7 +74,7 @@ void main() { "script.dart": "main(){}", "packages": {"shouldNotBeFound": {}} }, (Directory directory) async { - var config = await findPackageConfig(directory); + var config = (await findPackageConfig(directory))!; expect(config.version, 1); // Found .packages file. validatePackagesFile(config, directory); }); @@ -89,7 +89,7 @@ void main() { "script.dart": "main(){}", } }, (Directory directory) async { - var config = await findPackageConfig(subdir(directory, "subdir/")); + var config = (await findPackageConfig(subdir(directory, "subdir/")))!; expect(config.version, 2); validatePackagesFile(config, directory); }); diff --git a/pkgs/package_config/test/discovery_uri_test.dart b/pkgs/package_config/test/discovery_uri_test.dart index 23c02d7bc..a89527918 100644 --- a/pkgs/package_config/test/discovery_uri_test.dart +++ b/pkgs/package_config/test/discovery_uri_test.dart @@ -61,7 +61,7 @@ void main() { "package_config.json": packageConfigFile, } }, (directory, loader) async { - var config = await findPackageConfigUri(directory, loader: loader); + var config = (await findPackageConfigUri(directory, loader: loader))!; expect(config.version, 2); // Found package_config.json file. validatePackagesFile(config, directory); }); @@ -72,7 +72,7 @@ void main() { "script.dart": "main(){}", "packages": {"shouldNotBeFound": {}} }, (directory, loader) async { - var config = await findPackageConfigUri(directory, loader: loader); + var config = (await findPackageConfigUri(directory, loader: loader))!; expect(config.version, 1); // Found .packages file. validatePackagesFile(config, directory); }); @@ -87,8 +87,8 @@ void main() { "script.dart": "main(){}", } }, (directory, loader) async { - var config = await findPackageConfigUri(directory.resolve("subdir/"), - loader: loader); + var config = (await findPackageConfigUri(directory.resolve("subdir/"), + loader: loader))!; expect(config.version, 2); validatePackagesFile(config, directory); }); diff --git a/pkgs/package_config/test/legacy/all.dart b/pkgs/package_config/test/legacy/all.dart deleted file mode 100644 index 22e2e4f9e..000000000 --- a/pkgs/package_config/test/legacy/all.dart +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) 2015, 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. - -@deprecated -library package_config.all_test; - -import "package:test/test.dart"; - -import "discovery_analysis_test.dart" as discovery_analysis; -import "discovery_test.dart" as discovery; -import "parse_test.dart" as parse; -import "parse_write_test.dart" as parse_write; - -void main() { - group("parse:", parse.main); - group("discovery:", discovery.main); - group("discovery-analysis:", discovery_analysis.main); - group("parse/write:", parse_write.main); -} diff --git a/pkgs/package_config/test/legacy/discovery_analysis_test.dart b/pkgs/package_config/test/legacy/discovery_analysis_test.dart deleted file mode 100644 index 7554d85d9..000000000 --- a/pkgs/package_config/test/legacy/discovery_analysis_test.dart +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright (c) 2015, 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. - -@deprecated -@TestOn('vm') -library package_config.discovery_analysis_test; - -import "dart:io"; - -import "package:package_config/discovery_analysis.dart"; -import "package:package_config/packages.dart"; -import "package:path/path.dart" as path; -import "package:test/test.dart"; - -void main() { - fileTest("basic", { - ".packages": packagesFile, - "foo": {".packages": packagesFile}, - "bar": { - "packages": {"foo": {}, "bar": {}, "baz": {}} - }, - "baz": {} - }, (Directory directory) { - var dirUri = Uri.directory(directory.path); - var ctx = PackageContext.findAll(directory); - var root = ctx[directory]; - expect(root, same(ctx)); - validatePackagesFile(root.packages, dirUri); - var fooDir = sub(directory, "foo"); - var foo = ctx[fooDir]; - expect(identical(root, foo), isFalse); - validatePackagesFile(foo.packages, dirUri.resolve("foo/")); - var barDir = sub(directory, "bar"); - var bar = ctx[sub(directory, "bar")]; - validatePackagesDir(bar.packages, dirUri.resolve("bar/")); - var barbar = ctx[sub(barDir, "bar")]; - expect(barbar, same(bar)); // inherited. - var baz = ctx[sub(directory, "baz")]; - expect(baz, same(root)); // inherited. - - var map = ctx.asMap(); - expect(map.keys.map((dir) => dir.path), - unorderedEquals([directory.path, fooDir.path, barDir.path])); - return null; - }); -} - -Directory sub(Directory parent, String dirName) { - return Directory(path.join(parent.path, dirName)); -} - -const packagesFile = """ -# A comment -foo:file:///dart/packages/foo/ -bar:http://example.com/dart/packages/bar/ -baz:packages/baz/ -"""; - -void validatePackagesFile(Packages resolver, Uri location) { - expect(resolver, isNotNull); - expect(resolver.resolve(pkg("foo", "bar/baz")), - equals(Uri.parse("file:///dart/packages/foo/bar/baz"))); - expect(resolver.resolve(pkg("bar", "baz/qux")), - equals(Uri.parse("http://example.com/dart/packages/bar/baz/qux"))); - expect(resolver.resolve(pkg("baz", "qux/foo")), - equals(location.resolve("packages/baz/qux/foo"))); - expect(resolver.packages, unorderedEquals(["foo", "bar", "baz"])); -} - -void validatePackagesDir(Packages resolver, Uri location) { - // Expect three packages: foo, bar and baz - expect(resolver, isNotNull); - expect(resolver.resolve(pkg("foo", "bar/baz")), - equals(location.resolve("packages/foo/bar/baz"))); - expect(resolver.resolve(pkg("bar", "baz/qux")), - equals(location.resolve("packages/bar/baz/qux"))); - expect(resolver.resolve(pkg("baz", "qux/foo")), - equals(location.resolve("packages/baz/qux/foo"))); - if (location.scheme == "file") { - expect(resolver.packages, unorderedEquals(["foo", "bar", "baz"])); - } else { - expect(() => resolver.packages, throwsUnsupportedError); - } -} - -Uri pkg(String packageName, String packagePath) { - var path; - if (packagePath.startsWith('/')) { - path = "$packageName$packagePath"; - } else { - path = "$packageName/$packagePath"; - } - return Uri(scheme: "package", path: path); -} - -/// Create a directory structure from [description] and run [fileTest]. -/// -/// Description is a map, each key is a file entry. If the value is a map, -/// it's a sub-dir, otherwise it's a file and the value is the content -/// as a string. -void fileTest( - String name, Map description, Future fileTest(Directory directory)) { - group("file-test", () { - var tempDir = Directory.systemTemp.createTempSync("file-test"); - setUp(() { - _createFiles(tempDir, description); - }); - tearDown(() { - tempDir.deleteSync(recursive: true); - }); - test(name, () => fileTest(tempDir)); - }); -} - -void _createFiles(Directory target, Map description) { - description.forEach((name, content) { - if (content is Map) { - var subDir = Directory(path.join(target.path, name)); - subDir.createSync(); - _createFiles(subDir, content); - } else { - var file = File(path.join(target.path, name)); - file.writeAsStringSync(content, flush: true); - } - }); -} diff --git a/pkgs/package_config/test/legacy/discovery_test.dart b/pkgs/package_config/test/legacy/discovery_test.dart deleted file mode 100644 index 72874c8df..000000000 --- a/pkgs/package_config/test/legacy/discovery_test.dart +++ /dev/null @@ -1,329 +0,0 @@ -// Copyright (c) 2015, 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. - -@deprecated -@TestOn('vm') -library package_config.discovery_test; - -import "dart:async"; -import "dart:io"; -import "package:test/test.dart"; -import "package:package_config/packages.dart"; -import "package:package_config/discovery.dart"; -import "package:path/path.dart" as path; - -const packagesFile = """ -# A comment -foo:file:///dart/packages/foo/ -bar:http://example.com/dart/packages/bar/ -baz:packages/baz/ -"""; - -void validatePackagesFile(Packages resolver, Uri location) { - expect(resolver, isNotNull); - expect(resolver.resolve(pkg("foo", "bar/baz")), - equals(Uri.parse("file:///dart/packages/foo/bar/baz"))); - expect(resolver.resolve(pkg("bar", "baz/qux")), - equals(Uri.parse("http://example.com/dart/packages/bar/baz/qux"))); - expect(resolver.resolve(pkg("baz", "qux/foo")), - equals(location.resolve("packages/baz/qux/foo"))); - expect(resolver.packages, unorderedEquals(["foo", "bar", "baz"])); -} - -void validatePackagesDir(Packages resolver, Uri location) { - // Expect three packages: foo, bar and baz - expect(resolver, isNotNull); - expect(resolver.resolve(pkg("foo", "bar/baz")), - equals(location.resolve("packages/foo/bar/baz"))); - expect(resolver.resolve(pkg("bar", "baz/qux")), - equals(location.resolve("packages/bar/baz/qux"))); - expect(resolver.resolve(pkg("baz", "qux/foo")), - equals(location.resolve("packages/baz/qux/foo"))); - if (location.scheme == "file") { - expect(resolver.packages, unorderedEquals(["foo", "bar", "baz"])); - } else { - expect(() => resolver.packages, throwsUnsupportedError); - } -} - -Uri pkg(String packageName, String packagePath) { - var path; - if (packagePath.startsWith('/')) { - path = "$packageName$packagePath"; - } else { - path = "$packageName/$packagePath"; - } - return Uri(scheme: "package", path: path); -} - -void main() { - generalTest(".packages", { - ".packages": packagesFile, - "script.dart": "main(){}", - "packages": {"shouldNotBeFound": {}} - }, (Uri location) async { - Packages resolver; - resolver = await findPackages(location); - validatePackagesFile(resolver, location); - resolver = await findPackages(location.resolve("script.dart")); - validatePackagesFile(resolver, location); - var specificDiscovery = (location.scheme == "file") - ? findPackagesFromFile - : findPackagesFromNonFile; - resolver = await specificDiscovery(location); - validatePackagesFile(resolver, location); - resolver = await specificDiscovery(location.resolve("script.dart")); - validatePackagesFile(resolver, location); - }); - - generalTest("packages/", { - "packages": {"foo": {}, "bar": {}, "baz": {}}, - "script.dart": "main(){}" - }, (Uri location) async { - Packages resolver; - var isFile = (location.scheme == "file"); - resolver = await findPackages(location); - validatePackagesDir(resolver, location); - resolver = await findPackages(location.resolve("script.dart")); - validatePackagesDir(resolver, location); - var specificDiscovery = - isFile ? findPackagesFromFile : findPackagesFromNonFile; - resolver = await specificDiscovery(location); - validatePackagesDir(resolver, location); - resolver = await specificDiscovery(location.resolve("script.dart")); - validatePackagesDir(resolver, location); - }); - - generalTest("underscore packages", { - "packages": {"_foo": {}} - }, (Uri location) async { - var resolver = await findPackages(location); - expect(resolver.resolve(pkg("_foo", "foo.dart")), - equals(location.resolve("packages/_foo/foo.dart"))); - }); - - fileTest(".packages recursive", { - ".packages": packagesFile, - "subdir": {"script.dart": "main(){}"} - }, (Uri location) async { - Packages resolver; - resolver = await findPackages(location.resolve("subdir/")); - validatePackagesFile(resolver, location); - resolver = await findPackages(location.resolve("subdir/script.dart")); - validatePackagesFile(resolver, location); - resolver = await findPackagesFromFile(location.resolve("subdir/")); - validatePackagesFile(resolver, location); - resolver = - await findPackagesFromFile(location.resolve("subdir/script.dart")); - validatePackagesFile(resolver, location); - }); - - httpTest(".packages not recursive", { - ".packages": packagesFile, - "subdir": {"script.dart": "main(){}"} - }, (Uri location) async { - Packages resolver; - var subdir = location.resolve("subdir/"); - resolver = await findPackages(subdir); - validatePackagesDir(resolver, subdir); - resolver = await findPackages(subdir.resolve("script.dart")); - validatePackagesDir(resolver, subdir); - resolver = await findPackagesFromNonFile(subdir); - validatePackagesDir(resolver, subdir); - resolver = await findPackagesFromNonFile(subdir.resolve("script.dart")); - validatePackagesDir(resolver, subdir); - }); - - fileTest("no packages", {"script.dart": "main(){}"}, (Uri location) async { - // A file: location with no .packages or packages returns - // Packages.noPackages. - Packages resolver; - resolver = await findPackages(location); - expect(resolver, same(Packages.noPackages)); - resolver = await findPackages(location.resolve("script.dart")); - expect(resolver, same(Packages.noPackages)); - resolver = findPackagesFromFile(location); - expect(resolver, same(Packages.noPackages)); - resolver = findPackagesFromFile(location.resolve("script.dart")); - expect(resolver, same(Packages.noPackages)); - }); - - httpTest("no packages", {"script.dart": "main(){}"}, (Uri location) async { - // A non-file: location with no .packages or packages/: - // Assumes a packages dir exists, and resolves relative to that. - Packages resolver; - resolver = await findPackages(location); - validatePackagesDir(resolver, location); - resolver = await findPackages(location.resolve("script.dart")); - validatePackagesDir(resolver, location); - resolver = await findPackagesFromNonFile(location); - validatePackagesDir(resolver, location); - resolver = await findPackagesFromNonFile(location.resolve("script.dart")); - validatePackagesDir(resolver, location); - }); - - test(".packages w/ loader", () async { - var location = Uri.parse("krutch://example.com/path/"); - Future> loader(Uri file) async { - if (file.path.endsWith(".packages")) { - return packagesFile.codeUnits; - } - throw "not found"; - } - - // A non-file: location with no .packages or packages/: - // Assumes a packages dir exists, and resolves relative to that. - Packages resolver; - resolver = await findPackages(location, loader: loader); - validatePackagesFile(resolver, location); - resolver = - await findPackages(location.resolve("script.dart"), loader: loader); - validatePackagesFile(resolver, location); - resolver = await findPackagesFromNonFile(location, loader: loader); - validatePackagesFile(resolver, location); - resolver = await findPackagesFromNonFile(location.resolve("script.dart"), - loader: loader); - validatePackagesFile(resolver, location); - }); - - test("no packages w/ loader", () async { - var location = Uri.parse("krutch://example.com/path/"); - Future> loader(Uri file) async { - throw "not found"; - } - - // A non-file: location with no .packages or packages/: - // Assumes a packages dir exists, and resolves relative to that. - Packages resolver; - resolver = await findPackages(location, loader: loader); - validatePackagesDir(resolver, location); - resolver = - await findPackages(location.resolve("script.dart"), loader: loader); - validatePackagesDir(resolver, location); - resolver = await findPackagesFromNonFile(location, loader: loader); - validatePackagesDir(resolver, location); - resolver = await findPackagesFromNonFile(location.resolve("script.dart"), - loader: loader); - validatePackagesDir(resolver, location); - }); - - generalTest("loadPackagesFile", {".packages": packagesFile}, - (Uri directory) async { - var file = directory.resolve(".packages"); - var resolver = await loadPackagesFile(file); - validatePackagesFile(resolver, file); - }); - - generalTest( - "loadPackagesFile non-default name", {"pheldagriff": packagesFile}, - (Uri directory) async { - var file = directory.resolve("pheldagriff"); - var resolver = await loadPackagesFile(file); - validatePackagesFile(resolver, file); - }); - - test("loadPackagesFile w/ loader", () async { - Future> loader(Uri uri) async => packagesFile.codeUnits; - var file = Uri.parse("krutz://example.com/.packages"); - var resolver = await loadPackagesFile(file, loader: loader); - validatePackagesFile(resolver, file); - }); - - generalTest("loadPackagesFile not found", {}, (Uri directory) async { - var file = directory.resolve(".packages"); - expect( - loadPackagesFile(file), - throwsA(anyOf( - TypeMatcher(), TypeMatcher()))); - }); - - generalTest("loadPackagesFile syntax error", {".packages": "syntax error"}, - (Uri directory) async { - var file = directory.resolve(".packages"); - expect(loadPackagesFile(file), throwsFormatException); - }); - - generalTest("getPackagesDir", { - "packages": {"foo": {}, "bar": {}, "baz": {}} - }, (Uri directory) async { - var packages = directory.resolve("packages/"); - var resolver = getPackagesDirectory(packages); - var resolved = resolver.resolve(pkg("foo", "flip/flop")); - expect(resolved, packages.resolve("foo/flip/flop")); - }); -} - -/// Create a directory structure from [description] and run [fileTest]. -/// -/// Description is a map, each key is a file entry. If the value is a map, -/// it's a sub-dir, otherwise it's a file and the value is the content -/// as a string. -void fileTest(String name, Map description, Future fileTest(Uri directory)) { - group("file-test", () { - var tempDir = Directory.systemTemp.createTempSync("file-test"); - setUp(() { - _createFiles(tempDir, description); - }); - tearDown(() { - tempDir.deleteSync(recursive: true); - }); - test(name, () => fileTest(Uri.file(path.join(tempDir.path, ".")))); - }); -} - -/// HTTP-server the directory structure from [description] and run [htpTest]. -/// -/// Description is a map, each key is a file entry. If the value is a map, -/// it's a sub-dir, otherwise it's a file and the value is the content -/// as a string. -void httpTest(String name, Map description, Future httpTest(Uri directory)) { - group("http-test", () { - var serverSub; - var uri; - setUp(() { - return HttpServer.bind(InternetAddress.loopbackIPv4, 0).then((server) { - uri = Uri( - scheme: "http", host: "127.0.0.1", port: server.port, path: "/"); - serverSub = server.listen((HttpRequest request) { - // No error handling. - var path = request.uri.path; - if (path.startsWith('/')) path = path.substring(1); - if (path.endsWith('/')) path = path.substring(0, path.length - 1); - var parts = path.split('/'); - dynamic fileOrDir = description; - for (var i = 0; i < parts.length; i++) { - fileOrDir = fileOrDir[parts[i]]; - if (fileOrDir == null) { - request.response.statusCode = 404; - request.response.close(); - return; - } - } - request.response.write(fileOrDir); - request.response.close(); - }); - }); - }); - tearDown(() => serverSub.cancel()); - test(name, () => httpTest(uri)); - }); -} - -void generalTest(String name, Map description, Future action(Uri location)) { - fileTest(name, description, action); - httpTest(name, description, action); -} - -void _createFiles(Directory target, Map description) { - description.forEach((name, content) { - if (content is Map) { - var subDir = Directory(path.join(target.path, name)); - subDir.createSync(); - _createFiles(subDir, content); - } else { - var file = File(path.join(target.path, name)); - file.writeAsStringSync(content, flush: true); - } - }); -} diff --git a/pkgs/package_config/test/legacy/parse_test.dart b/pkgs/package_config/test/legacy/parse_test.dart deleted file mode 100644 index b9cf1f8fd..000000000 --- a/pkgs/package_config/test/legacy/parse_test.dart +++ /dev/null @@ -1,246 +0,0 @@ -// Copyright (c) 2015, 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. - -@deprecated -library package_config.parse_test; - -import "package:package_config/packages.dart"; -import "package:package_config/packages_file.dart" show parse; -import "package:package_config/src/packages_impl.dart"; -import "package:test/test.dart"; - -void main() { - var base = Uri.parse("file:///one/two/three/packages.map"); - test("empty", () { - var packages = doParse(emptySample, base); - expect(packages.asMap(), isEmpty); - }); - test("comment only", () { - var packages = doParse(commentOnlySample, base); - expect(packages.asMap(), isEmpty); - }); - test("empty lines only", () { - var packages = doParse(emptyLinesSample, base); - expect(packages.asMap(), isEmpty); - }); - - test("empty lines only", () { - var packages = doParse(emptyLinesSample, base); - expect(packages.asMap(), isEmpty); - }); - - test("single", () { - var packages = doParse(singleRelativeSample, base); - expect(packages.packages.toList(), equals(["foo"])); - expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), - equals(base.resolve("../test/").resolve("bar/baz.dart"))); - }); - - test("single no slash", () { - var packages = doParse(singleRelativeSampleNoSlash, base); - expect(packages.packages.toList(), equals(["foo"])); - expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), - equals(base.resolve("../test/").resolve("bar/baz.dart"))); - }); - - test("single no newline", () { - var packages = doParse(singleRelativeSampleNoNewline, base); - expect(packages.packages.toList(), equals(["foo"])); - expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), - equals(base.resolve("../test/").resolve("bar/baz.dart"))); - }); - - test("single absolute authority", () { - var packages = doParse(singleAbsoluteSample, base); - expect(packages.packages.toList(), equals(["foo"])); - expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), - equals(Uri.parse("http://example.com/some/where/bar/baz.dart"))); - }); - - test("single empty path", () { - var packages = doParse(singleEmptyPathSample, base); - expect(packages.packages.toList(), equals(["foo"])); - expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), - equals(base.replace(path: "${base.path}/bar/baz.dart"))); - }); - - test("single absolute path", () { - var packages = doParse(singleAbsolutePathSample, base); - expect(packages.packages.toList(), equals(["foo"])); - expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), - equals(base.replace(path: "/test/bar/baz.dart"))); - }); - - test("multiple", () { - var packages = doParse(multiRelativeSample, base); - expect(packages.packages.toList()..sort(), equals(["bar", "foo"])); - expect(packages.resolve(Uri.parse("package:foo/bar/baz.dart")), - equals(base.resolve("../test/").resolve("bar/baz.dart"))); - expect(packages.resolve(Uri.parse("package:bar/foo/baz.dart")), - equals(base.resolve("../test2/").resolve("foo/baz.dart"))); - }); - - test("dot-dot 1", () { - var packages = doParse(singleRelativeSample, base); - expect(packages.packages.toList(), equals(["foo"])); - expect(packages.resolve(Uri.parse("package:foo/qux/../bar/baz.dart")), - equals(base.resolve("../test/").resolve("bar/baz.dart"))); - }); - - test("all valid chars can be used in URI segment", () { - var packages = doParse(allValidCharsSample, base); - expect(packages.packages.toList(), equals([allValidChars])); - expect(packages.resolve(Uri.parse("package:$allValidChars/bar/baz.dart")), - equals(base.resolve("../test/").resolve("bar/baz.dart"))); - }); - - test("no invalid chars accepted", () { - var map = {}; - for (var i = 0; i < allValidChars.length; i++) { - map[allValidChars.codeUnitAt(i)] = true; - } - for (var i = 0; i <= 255; i++) { - if (map[i] == true) continue; - var char = String.fromCharCode(i); - expect(() => doParse("x${char}x:x", null), - anyOf(throwsNoSuchMethodError, throwsFormatException)); - } - }); - - test("no escapes", () { - expect(() => doParse("x%41x:x", base), throwsFormatException); - }); - - test("same name twice", () { - expect( - () => doParse(singleRelativeSample * 2, base), throwsFormatException); - }); - - test("disallow default package", () { - expect(() => doParse(":foo", base, allowDefaultPackage: false), - throwsFormatException); - }); - - test("allow default package", () { - var packages = doParse(":foo", base, allowDefaultPackage: true); - expect(packages.defaultPackageName, "foo"); - }); - - test("allow default package name with dot", () { - var packages = doParse(":foo.bar", base, allowDefaultPackage: true); - expect(packages.defaultPackageName, "foo.bar"); - }); - - test("not two default packages", () { - expect(() => doParse(":foo\n:bar", base, allowDefaultPackage: true), - throwsFormatException); - }); - - test("default package invalid package name", () { - // Not a valid *package name*. - expect(() => doParse(":foo/bar", base, allowDefaultPackage: true), - throwsFormatException); - }); - - group("metadata", () { - var packages = doParse( - ":foo\n" - "foo:foo#metafoo=1\n" - "bar:bar#metabar=2\n" - "baz:baz\n" - "qux:qux#metaqux1=3&metaqux2=4\n", - base, - allowDefaultPackage: true); - test("non-existing", () { - // non-package name. - expect(packages.packageMetadata("///", "f"), null); - expect(packages.packageMetadata("", "f"), null); - // unconfigured package name. - expect(packages.packageMetadata("absent", "f"), null); - // package name without that metadata - expect(packages.packageMetadata("foo", "notfoo"), null); - }); - test("lookup", () { - expect(packages.packageMetadata("foo", "metafoo"), "1"); - expect(packages.packageMetadata("bar", "metabar"), "2"); - expect(packages.packageMetadata("qux", "metaqux1"), "3"); - expect(packages.packageMetadata("qux", "metaqux2"), "4"); - }); - test("by library URI", () { - expect( - packages.libraryMetadata( - Uri.parse("package:foo/index.dart"), "metafoo"), - "1"); - expect( - packages.libraryMetadata( - Uri.parse("package:bar/index.dart"), "metabar"), - "2"); - expect( - packages.libraryMetadata( - Uri.parse("package:qux/index.dart"), "metaqux1"), - "3"); - expect( - packages.libraryMetadata( - Uri.parse("package:qux/index.dart"), "metaqux2"), - "4"); - }); - test("by default package", () { - expect( - packages.libraryMetadata( - Uri.parse("file:///whatever.dart"), "metafoo"), - "1"); - }); - }); - - for (var invalidSample in invalid) { - test("invalid '$invalidSample'", () { - var result; - try { - result = doParse(invalidSample, base); - } on FormatException { - // expected - return; - } - fail("Resolved to $result"); - }); - } -} - -Packages doParse(String sample, Uri baseUri, - {bool allowDefaultPackage = false}) { - var map = parse(sample.codeUnits, baseUri, - allowDefaultPackage: allowDefaultPackage); - return MapPackages(map); -} - -// Valid samples. -var emptySample = ""; -var commentOnlySample = "# comment only\n"; -var emptyLinesSample = "\n\n\r\n"; -var singleRelativeSample = "foo:../test/\n"; -var singleRelativeSampleNoSlash = "foo:../test\n"; -var singleRelativeSampleNoNewline = "foo:../test/"; -var singleAbsoluteSample = "foo:http://example.com/some/where/\n"; -var singleEmptyPathSample = "foo:\n"; -var singleAbsolutePathSample = "foo:/test/\n"; -var multiRelativeSample = "foo:../test/\nbar:../test2/\n"; -// All valid path segment characters in an URI. -var allValidChars = r"!$&'()*+,-.0123456789;=" - r"@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~"; - -var allValidCharsSample = "${allValidChars}:../test/\n"; - -// Invalid samples. -var invalid = [ - ":baz.dart", // empty. - "foobar=baz.dart", // no colon (but an equals, which is not the same) - ".:../test/", // dot segment - "..:../test/", // dot-dot segment - "...:../test/", // dot-dot-dot segment - "foo/bar:../test/", // slash in name - "/foo:../test/", // slash at start of name - "?:../test/", // invalid characters. - "[:../test/", // invalid characters. - "x#:../test/", // invalid characters. -]; diff --git a/pkgs/package_config/test/legacy/parse_write_test.dart b/pkgs/package_config/test/legacy/parse_write_test.dart deleted file mode 100644 index a51ced1ba..000000000 --- a/pkgs/package_config/test/legacy/parse_write_test.dart +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright (c) 2015, 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. - -@deprecated -library package_config.parse_write_test; - -import "dart:convert" show utf8; -import "package:package_config/packages_file.dart"; -import "package:test/test.dart"; - -void main() { - void testBase(baseDirString) { - var baseDir = Uri.parse(baseDirString); - group("${baseDir.scheme} base", () { - var packagesFile = baseDir.resolve(".packages"); - - void roundTripTest(String name, Map map) { - group(name, () { - test("write with no baseUri", () { - var content = writeToString(map).codeUnits; - var resultMap = parse(content, packagesFile); - expect(resultMap, map); - }); - - test("write with base directory", () { - var content = writeToString(map, baseUri: baseDir).codeUnits; - var resultMap = parse(content, packagesFile); - expect(resultMap, map); - }); - - test("write with base .packages file", () { - var content = writeToString(map, baseUri: packagesFile).codeUnits; - var resultMap = parse(content, packagesFile); - expect(resultMap, map); - }); - - test("write with defaultPackageName", () { - var content = writeToString( - {'': Uri.parse('my_pkg')}..addAll(map), - allowDefaultPackage: true, - ).codeUnits; - var resultMap = parse( - content, - packagesFile, - allowDefaultPackage: true, - ); - expect(resultMap[''].toString(), 'my_pkg'); - expect( - resultMap, - {'': Uri.parse('my_pkg')}..addAll(map), - ); - }); - - test("write with defaultPackageName (utf8)", () { - var content = utf8.encode(writeToString( - {'': Uri.parse('my_pkg')}..addAll(map), - allowDefaultPackage: true, - )); - var resultMap = parse( - content, - packagesFile, - allowDefaultPackage: true, - ); - expect(resultMap[''].toString(), 'my_pkg'); - expect( - resultMap, - {'': Uri.parse('my_pkg')}..addAll(map), - ); - }); - }); - } - - var lowerDir = baseDir.resolve("path3/path4/"); - var higherDir = baseDir.resolve("../"); - var parallelDir = baseDir.resolve("../path3/"); - var rootDir = baseDir.resolve("/"); - var fileDir = Uri.parse("file:///path1/part2/"); - var httpDir = Uri.parse("http://example.com/path1/path2/"); - var otherDir = Uri.parse("other:/path1/path2/"); - - roundTripTest("empty", {}); - roundTripTest("lower directory", {"foo": lowerDir}); - roundTripTest("higher directory", {"foo": higherDir}); - roundTripTest("parallel directory", {"foo": parallelDir}); - roundTripTest("same directory", {"foo": baseDir}); - roundTripTest("root directory", {"foo": rootDir}); - roundTripTest("file directory", {"foo": fileDir}); - roundTripTest("http directory", {"foo": httpDir}); - roundTripTest("other scheme directory", {"foo": otherDir}); - roundTripTest("multiple same-type directories", - {"foo": lowerDir, "bar": higherDir, "baz": parallelDir}); - roundTripTest("multiple scheme directories", - {"foo": fileDir, "bar": httpDir, "baz": otherDir}); - roundTripTest("multiple scheme directories and mutliple same type", { - "foo": fileDir, - "bar": httpDir, - "baz": otherDir, - "qux": lowerDir, - "hip": higherDir, - "dep": parallelDir - }); - }); - } - - testBase("file:///base1/base2/"); - testBase("http://example.com/base1/base2/"); - testBase("other:/base1/base2/"); - - // Check that writing adds the comment. - test("write preserves comment", () { - var comment = "comment line 1\ncomment line 2\ncomment line 3"; - var result = writeToString({}, comment: comment); - // Comment with "# " before each line and "\n" after last. - var expectedComment = - "# comment line 1\n# comment line 2\n# comment line 3\n"; - expect(result, startsWith(expectedComment)); - }); -} - -String writeToString( - Map map, { - Uri baseUri, - String comment, - bool allowDefaultPackage = false, -}) { - var buffer = StringBuffer(); - write(buffer, map, - baseUri: baseUri, - comment: comment, - allowDefaultPackage: allowDefaultPackage); - return buffer.toString(); -} diff --git a/pkgs/package_config/test/parse_test.dart b/pkgs/package_config/test/parse_test.dart index 59a7e7126..385be368e 100644 --- a/pkgs/package_config/test/parse_test.dart +++ b/pkgs/package_config/test/parse_test.dart @@ -32,7 +32,7 @@ void main() { expect(result.resolve(pkg("baz", "baz.dart")), Uri.parse("file:///tmp/lib/baz.dart")); - var foo = result["foo"]; + var foo = result["foo"]!; expect(foo, isNotNull); expect(foo.root, Uri.parse("file:///foo/")); expect(foo.packageUriRoot, Uri.parse("file:///foo/lib/")); @@ -111,8 +111,10 @@ void main() { "other": [42] } """; - var config = parsePackageConfigBytes(utf8.encode(packageConfigFile), - Uri.parse("file:///tmp/.dart_tool/file.dart"), throwError); + var config = parsePackageConfigBytes( + utf8.encode(packageConfigFile) as Uint8List, + Uri.parse("file:///tmp/.dart_tool/file.dart"), + throwError); expect(config.version, 2); expect({for (var p in config.packages) p.name}, {"foo", "bar", "baz", "noslash"}); @@ -124,28 +126,28 @@ void main() { expect(config.resolve(pkg("baz", "baz.dart")), Uri.parse("file:///tmp/lib/baz.dart")); - var foo = config["foo"]; + var foo = config["foo"]!; expect(foo, isNotNull); expect(foo.root, Uri.parse("file:///foo/")); expect(foo.packageUriRoot, Uri.parse("file:///foo/lib/")); expect(foo.languageVersion, LanguageVersion(2, 5)); expect(foo.extraData, {"nonstandard": true}); - var bar = config["bar"]; + var bar = config["bar"]!; expect(bar, isNotNull); expect(bar.root, Uri.parse("file:///bar/")); expect(bar.packageUriRoot, Uri.parse("file:///bar/lib/")); expect(bar.languageVersion, LanguageVersion(9999, 9999)); expect(bar.extraData, null); - var baz = config["baz"]; + var baz = config["baz"]!; expect(baz, isNotNull); expect(baz.root, Uri.parse("file:///tmp/")); expect(baz.packageUriRoot, Uri.parse("file:///tmp/lib/")); expect(baz.languageVersion, null); // No slash after root or package root. One is inserted. - var noslash = config["noslash"]; + var noslash = config["noslash"]!; expect(noslash, isNotNull); expect(noslash.root, Uri.parse("file:///tmp/noslash/")); expect(noslash.packageUriRoot, Uri.parse("file:///tmp/noslash/lib/")); @@ -185,8 +187,10 @@ void main() { "configVersion": 2 } """; - var config = parsePackageConfigBytes(utf8.encode(packageConfigFile), - Uri.parse("file:///tmp/.dart_tool/file.dart"), throwError); + var config = parsePackageConfigBytes( + utf8.encode(packageConfigFile) as Uint8List, + Uri.parse("file:///tmp/.dart_tool/file.dart"), + throwError); expect(config.version, 2); expect({for (var p in config.packages) p.name}, {"foo", "bar", "baz"}); @@ -209,8 +213,10 @@ void main() { var name = '"name":"foo"'; var root = '"rootUri":"/foo/"'; test("minimal", () { - var config = parsePackageConfigBytes(utf8.encode("{$cfg,$pkgs}"), - Uri.parse("file:///tmp/.dart_tool/file.dart"), throwError); + var config = parsePackageConfigBytes( + utf8.encode("{$cfg,$pkgs}") as Uint8List, + Uri.parse("file:///tmp/.dart_tool/file.dart"), + throwError); expect(config.version, 2); expect(config.packages, isEmpty); }); @@ -218,7 +224,7 @@ void main() { // A package must have a name and a rootUri, the remaining properties // are optional. var config = parsePackageConfigBytes( - utf8.encode('{$cfg,"packages":[{$name,$root}]}'), + utf8.encode('{$cfg,"packages":[{$name,$root}]}') as Uint8List, Uri.parse("file:///tmp/.dart_tool/file.dart"), throwError); expect(config.version, 2); @@ -235,17 +241,17 @@ void main() { {"name": "qux", "rootUri": "/foo/qux/", "packageUri": "lib/"}, ] })); - var config = parsePackageConfigBytes(configBytes, + var config = parsePackageConfigBytes(configBytes as Uint8List, Uri.parse("file:///tmp/.dart_tool/file.dart"), throwError); expect(config.version, 2); - expect(config.packageOf(Uri.parse("file:///foo/lala/lala.dart")).name, + expect(config.packageOf(Uri.parse("file:///foo/lala/lala.dart"))!.name, "foo"); - expect( - config.packageOf(Uri.parse("file:///foo/bar/lala.dart")).name, "bar"); - expect(config.packageOf(Uri.parse("file:///foo/bar/baz/lala.dart")).name, + expect(config.packageOf(Uri.parse("file:///foo/bar/lala.dart"))!.name, + "bar"); + expect(config.packageOf(Uri.parse("file:///foo/bar/baz/lala.dart"))!.name, "baz"); - expect( - config.packageOf(Uri.parse("file:///foo/qux/lala.dart")).name, "qux"); + expect(config.packageOf(Uri.parse("file:///foo/qux/lala.dart"))!.name, + "qux"); expect(config.toPackageUri(Uri.parse("file:///foo/lib/diz")), Uri.parse("package:foo/diz")); expect(config.toPackageUri(Uri.parse("file:///foo/bar/lib/diz")), @@ -260,7 +266,7 @@ void main() { void testThrows(String name, String source) { test(name, () { expect( - () => parsePackageConfigBytes(utf8.encode(source), + () => parsePackageConfigBytes(utf8.encode(source) as Uint8List, Uri.parse("file:///tmp/.dart_tool/file.dart"), throwError), throwsA(TypeMatcher())); }); @@ -386,7 +392,7 @@ void main() { for (var package in config.packages) { var name = package.name; test("package $name", () { - var expectedPackage = expected[name]; + var expectedPackage = expected[name]!; expect(expectedPackage, isNotNull); expect(package.root, expectedPackage.root, reason: "root"); expect(package.packageUriRoot, expectedPackage.packageUriRoot, diff --git a/pkgs/package_config/test/src/util.dart b/pkgs/package_config/test/src/util.dart index 6e689b734..2b262e1b2 100644 --- a/pkgs/package_config/test/src/util.dart +++ b/pkgs/package_config/test/src/util.dart @@ -34,18 +34,18 @@ ${packages.map((nu) => """ /// it's a subdirectory, otherwise it's a file and the value is the content /// as a string. void loaderTest(String name, Map description, - void loaderTest(Uri root, Future loader(Uri uri))) { + void loaderTest(Uri root, Future loader(Uri uri))) { var root = Uri(scheme: "test", path: "/"); - Future loader(Uri uri) async { + Future loader(Uri uri) async { var path = uri.path; if (!uri.isScheme("test") || !path.startsWith("/")) return null; var parts = path.split("/"); - dynamic value = description; + Object? value = description; for (var i = 1; i < parts.length; i++) { - if (value is! Map) return null; + if (value is! Map) return null; value = value[parts[i]]; } - if (value is String) return utf8.encode(value); + if (value is String) return utf8.encode(value) as Uint8List; return null; } diff --git a/pkgs/package_config/test/src/util_io.dart b/pkgs/package_config/test/src/util_io.dart index d05618a07..37deee9e1 100644 --- a/pkgs/package_config/test/src/util_io.dart +++ b/pkgs/package_config/test/src/util_io.dart @@ -35,20 +35,20 @@ void fileTest(String name, Map description, /// with the content as description. /// Otherwise the content should be a string, /// which is written to the file as UTF-8. -Directory createTestFiles(Map description) { - var target = Directory.systemTemp.createTempSync("pkgcfgtest"); - _createFiles(target, description); - return target; -} +// Directory createTestFiles(Map description) { +// var target = Directory.systemTemp.createTempSync("pkgcfgtest"); +// _createFiles(target, description); +// return target; +// } // Creates temporary files in the target directory. -void _createFiles(Directory target, Map description) { +void _createFiles(Directory target, Map description) { description.forEach((name, content) { var entryName = pathJoin(target.path, "$name"); - if (content is Map) { + if (content is Map) { _createFiles(Directory(entryName)..createSync(), content); } else { - File(entryName).writeAsStringSync(content, flush: true); + File(entryName).writeAsStringSync(content as String, flush: true); } }); } From ba5cc8d21bdbeccffa9327d0287511b430767433 Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Wed, 9 Dec 2020 15:06:53 -0800 Subject: [PATCH 101/170] Add override for _fe_analyzer_shared (dart-lang/package_config#96) We currently need the dependency overrides because of the circular dev_dependencies and the major version change. It is still safe to publish since no normal dependencies are overridden. The dependency overrides are causing us to pull in incompatible versions of `analyzer` and `_fe_analyzer_shared` since there was a breaking change in the latter. Pulling it in from the SDK should cause both to be compatible until we can drop the overrides entirely. --- pkgs/package_config/pubspec.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 05c5266b2..48b8d3c95 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -19,6 +19,10 @@ dev_dependencies: test: ^1.16.0-nullsafety.4 dependency_overrides: + _fe_analyzer_shared: + git: + url: git://github.com/dart-lang/sdk.git + path: pkg/_fe_analyzer_shared analyzer: git: url: git://github.com/dart-lang/sdk.git From 02e6eb5c0c6e6f1e295377caa56d06ad8689a5d2 Mon Sep 17 00:00:00 2001 From: Phil Quitslund Date: Thu, 10 Dec 2020 10:41:31 -0800 Subject: [PATCH 102/170] migrate to `dart analyze` (warnings are now fatal by default) --- pkgs/package_config/.travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/package_config/.travis.yml b/pkgs/package_config/.travis.yml index 3a47bb586..c4e5bdb8f 100644 --- a/pkgs/package_config/.travis.yml +++ b/pkgs/package_config/.travis.yml @@ -5,7 +5,7 @@ dart: dart_task: - test - dartfmt - - dartanalyzer: --fatal-warnings --fatal-infos . + - dart analyze --fatal-infos . matrix: include: From c9395552ff2def38ea8e858560c766185522c6ce Mon Sep 17 00:00:00 2001 From: Lasse Reichstein Holst Nielsen Date: Tue, 19 Jan 2021 15:00:16 +0100 Subject: [PATCH 103/170] Change version to 2.0.0-nullsafety.0 for consistency. --- pkgs/package_config/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 48b8d3c95..c1cfd9456 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 2.0.0-dev +version: 2.0.0-nullsafety.0 description: Support for working with Package Configuration files. homepage: https://github.com/dart-lang/package_config From 43d80949f6710a34c66df5a4c34247e4079ae03c Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Thu, 21 Jan 2021 16:32:45 +0100 Subject: [PATCH 104/170] Make it possible to control whether the `rootUri` path is relativized. (dart-lang/package_config#102) * Make it possible to control whether the `rootUri` path is relativized. Adds `relativeRoot` boolean to `PackageConfig` which does nothing except to control whether the `root` URI is made relative to the configuration file when written to a configuration file. The parsers remember whether the root URI was relative originally. Also fixes bad cast. --- pkgs/package_config/CHANGELOG.md | 2 + .../lib/src/package_config.dart | 19 ++++++-- .../lib/src/package_config_impl.dart | 9 ++-- .../lib/src/package_config_json.dart | 19 +++++--- .../package_config/lib/src/packages_file.dart | 8 ++-- pkgs/package_config/lib/src/util.dart | 15 ++++++ pkgs/package_config/pubspec.yaml | 2 +- .../test/package_config_impl_test.dart | 47 ++++++++++++++++++- pkgs/package_config/test/parse_test.dart | 5 ++ 9 files changed, 107 insertions(+), 19 deletions(-) diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index 32ff3f17f..4a04782b4 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -2,6 +2,8 @@ - Migrate to null safety. - Remove legacy APIs. +- Adds `relativeRoot` property to `Package` which controls whether to + make the root URI relative when writing a configuration file. ## 1.9.3 diff --git a/pkgs/package_config/lib/src/package_config.dart b/pkgs/package_config/lib/src/package_config.dart index 63d01eacd..26aa39622 100644 --- a/pkgs/package_config/lib/src/package_config.dart +++ b/pkgs/package_config/lib/src/package_config.dart @@ -224,14 +224,20 @@ abstract class Package { /// version, which means two decimal integer literals separated by a `.`, /// where the integer literals have no leading zeros unless they are /// a single zero digit. + /// + /// The [relativeRoot] controls whether the [root] is written as + /// relative to the `package_config.json` file when the package + /// configuration is written to a file. It defaults to being relative. + /// /// If [extraData] is supplied, it will be available as the /// [Package.extraData] of the created package. factory Package(String name, Uri root, {Uri? packageUriRoot, LanguageVersion? languageVersion, - Object? extraData}) => - SimplePackage.validate( - name, root, packageUriRoot, languageVersion, extraData, throwError)!; + Object? extraData, + bool relativeRoot = true}) => + SimplePackage.validate(name, root, packageUriRoot, languageVersion, + extraData, relativeRoot, throwError)!; /// The package-name of the package. String get name; @@ -275,6 +281,13 @@ abstract class Package { /// The standard `package_config.json` file storage will only store /// JSON-like list/map data structures. Object? get extraData; + + /// Whether the [root] URI should be written as relative. + /// + /// When the configuration is written to a `package_config.json` + /// file, the [root] URI can be either relative to the file + /// location or absolute, controller by this value. + bool get relativeRoot; } /// A language version. diff --git a/pkgs/package_config/lib/src/package_config_impl.dart b/pkgs/package_config/lib/src/package_config_impl.dart index 5c6b7f728..c75111580 100644 --- a/pkgs/package_config/lib/src/package_config_impl.dart +++ b/pkgs/package_config/lib/src/package_config_impl.dart @@ -61,7 +61,8 @@ class SimplePackageConfig implements PackageConfig { originalPackage.root, originalPackage.packageUriRoot, originalPackage.languageVersion, - originalPackage.extraData, (error) { + originalPackage.extraData, + originalPackage.relativeRoot, (error) { if (error is PackageConfigArgumentError) { onError(PackageConfigArgumentError(packages, "packages", "Package ${package!.name}: ${error.message}")); @@ -159,9 +160,10 @@ class SimplePackage implements Package { final Uri packageUriRoot; final LanguageVersion? languageVersion; final Object? extraData; + final bool relativeRoot; SimplePackage._(this.name, this.root, this.packageUriRoot, - this.languageVersion, this.extraData); + this.languageVersion, this.extraData, this.relativeRoot); /// Creates a [SimplePackage] with the provided content. /// @@ -184,6 +186,7 @@ class SimplePackage implements Package { Uri? packageUriRoot, LanguageVersion? languageVersion, Object? extraData, + bool relativeRoot, void onError(Object error)) { var fatalError = false; var invalidIndex = checkPackageName(name); @@ -229,7 +232,7 @@ class SimplePackage implements Package { } if (fatalError) return null; return SimplePackage._( - name, root, packageUriRoot, languageVersion, extraData); + name, root, packageUriRoot, languageVersion, extraData, relativeRoot); } } diff --git a/pkgs/package_config/lib/src/package_config_json.dart b/pkgs/package_config/lib/src/package_config_json.dart index 25b04c4d1..979c35ed4 100644 --- a/pkgs/package_config/lib/src/package_config_json.dart +++ b/pkgs/package_config/lib/src/package_config_json.dart @@ -146,7 +146,9 @@ PackageConfig parsePackageConfigJson( onError(PackageConfigFormatException("Missing rootUri entry", entry)); } if (name == null || rootUri == null) return null; - var root = baseLocation.resolve(rootUri!); + var parsedRootUri = Uri.parse(rootUri!); + var relativeRoot = !hasAbsolutePath(parsedRootUri); + var root = baseLocation.resolveUri(parsedRootUri); if (!root.path.endsWith("/")) root = root.replace(path: root.path + "/"); var packageRoot = root; if (packageUri != null) packageRoot = root.resolve(packageUri!); @@ -161,8 +163,8 @@ PackageConfig parsePackageConfigJson( version = SimpleInvalidLanguageVersion("invalid"); } - return SimplePackage.validate(name!, root, packageRoot, version, extraData, - (error) { + return SimplePackage.validate( + name!, root, packageRoot, version, extraData, relativeRoot, (error) { if (error is ArgumentError) { onError( PackageConfigFormatException(error.message, error.invalidValue)); @@ -232,7 +234,7 @@ void writePackageConfigJsonString( PackageConfig config, Uri? baseUri, StringSink output) { // Can be optimized. var data = packageConfigToJson(config, baseUri); - output.write(JsonEncoder.withIndent(" ").convert(data) as Uint8List); + output.write(JsonEncoder.withIndent(" ").convert(data)); } Map packageConfigToJson(PackageConfig config, Uri? baseUri) => @@ -243,11 +245,14 @@ Map packageConfigToJson(PackageConfig config, Uri? baseUri) => for (var package in config.packages) { _nameKey: package.name, - _rootUriKey: relativizeUri(package.root, baseUri).toString(), + _rootUriKey: trailingSlash((package.relativeRoot + ? relativizeUri(package.root, baseUri) + : package.root) + .toString()), if (package.root != package.packageUriRoot) - _packageUriKey: + _packageUriKey: trailingSlash( relativizeUri(package.packageUriRoot, package.root) - .toString(), + .toString()), if (package.languageVersion != null && package.languageVersion is! InvalidLanguageVersion) _languageVersionKey: package.languageVersion.toString(), diff --git a/pkgs/package_config/lib/src/packages_file.dart b/pkgs/package_config/lib/src/packages_file.dart index 071d548a5..ddcf8563b 100644 --- a/pkgs/package_config/lib/src/packages_file.dart +++ b/pkgs/package_config/lib/src/packages_file.dart @@ -96,11 +96,13 @@ PackageConfig parse( var packageValue = String.fromCharCodes(source, separatorIndex + 1, end); Uri packageLocation; try { - packageLocation = baseLocation.resolve(packageValue); + packageLocation = Uri.parse(packageValue); } on FormatException catch (e) { onError(PackageConfigFormatException.from(e)); continue; } + var relativeRoot = !hasAbsolutePath(packageLocation); + packageLocation = baseLocation.resolveUri(packageLocation); if (packageLocation.isScheme("package")) { onError(PackageConfigFormatException( "Package URI as location for package", source, separatorIndex + 1)); @@ -122,8 +124,8 @@ PackageConfig parse( rootUri = packageLocation.replace(path: path.substring(0, path.length - 4)); } - var package = SimplePackage.validate( - packageName, rootUri, packageLocation, _languageVersion, null, (error) { + var package = SimplePackage.validate(packageName, rootUri, packageLocation, + _languageVersion, null, relativeRoot, (error) { if (error is ArgumentError) { onError(PackageConfigFormatException(error.message, source)); } else { diff --git a/pkgs/package_config/lib/src/util.dart b/pkgs/package_config/lib/src/util.dart index 9b263ae7a..f490cdc1c 100644 --- a/pkgs/package_config/lib/src/util.dart +++ b/pkgs/package_config/lib/src/util.dart @@ -137,6 +137,21 @@ int firstNonWhitespaceChar(List bytes) { return -1; } +/// Appends a trailing `/` if the path doesn't end with one. +String trailingSlash(String path) { + if (path.isEmpty || path.endsWith("/")) return path; + return path + "/"; +} + +/// Whether a URI should not be considered relative to the base URI. +/// +/// Used to determine whether a parsed root URI is relative +/// to the configuration file or not. +/// If it is relative, then it's rewritten as relative when +/// output again later. If not, it's output as absolute. +bool hasAbsolutePath(Uri uri) => + uri.hasScheme || uri.hasAuthority || uri.hasAbsolutePath; + /// Attempts to return a relative path-only URI for [uri]. /// /// First removes any query or fragment part from [uri]. diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index c1cfd9456..5903bc8ac 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 2.0.0-nullsafety.0 +version: 2.0.0-nullsafety.1 description: Support for working with Package Configuration files. homepage: https://github.com/dart-lang/package_config diff --git a/pkgs/package_config/test/package_config_impl_test.dart b/pkgs/package_config/test/package_config_impl_test.dart index 6921118f3..bb00d1210 100644 --- a/pkgs/package_config/test/package_config_impl_test.dart +++ b/pkgs/package_config/test/package_config_impl_test.dart @@ -2,6 +2,8 @@ // 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. +import "dart:convert" show jsonDecode; + import "package:package_config/package_config_types.dart"; import "package:test/test.dart"; import "src/util.dart"; @@ -72,6 +74,7 @@ void main() { var absolute = root.resolve("foo/bar/"); var package = Package("name", root, packageUriRoot: absolute, + relativeRoot: false, languageVersion: version, extraData: unique); expect(package.name, "name"); @@ -79,16 +82,18 @@ void main() { expect(package.packageUriRoot, absolute); expect(package.languageVersion, version); expect(package.extraData, same(unique)); + expect(package.relativeRoot, false); }); test("relative package root", () { var relative = Uri.parse("foo/bar/"); var absolute = root.resolveUri(relative); - var package = - Package("name", root, packageUriRoot: relative, extraData: unique); + var package = Package("name", root, + packageUriRoot: relative, relativeRoot: true, extraData: unique); expect(package.name, "name"); expect(package.root, root); expect(package.packageUriRoot, absolute); + expect(package.relativeRoot, true); expect(package.languageVersion, null); expect(package.extraData, same(unique)); }); @@ -140,6 +145,44 @@ void main() { expect(resolved, root.resolve("a/b")); }); }); + test("writeString", () { + var config = PackageConfig([ + Package("foo", Uri.parse("file:///pkg/foo/"), + packageUriRoot: Uri.parse("file:///pkg/foo/lib/"), + relativeRoot: false, + languageVersion: LanguageVersion(2, 4), + extraData: {"foo": "foo!"}), + Package("bar", Uri.parse("file:///pkg/bar/"), + packageUriRoot: Uri.parse("file:///pkg/bar/lib/"), + relativeRoot: true, + extraData: {"bar": "bar!"}), + ], extraData: { + "extra": "data" + }); + var buffer = StringBuffer(); + PackageConfig.writeString(config, buffer, Uri.parse("file:///pkg/")); + var text = buffer.toString(); + var json = jsonDecode(text); // Is valid JSON. + expect(json, { + "configVersion": 2, + "packages": unorderedEquals([ + { + "name": "foo", + "rootUri": "file:///pkg/foo/", + "packageUri": "lib/", + "languageVersion": "2.4", + "foo": "foo!", + }, + { + "name": "bar", + "rootUri": "bar/", + "packageUri": "lib/", + "bar": "bar!", + }, + ]), + "extra": "data", + }); + }); } final Matcher throwsPackageConfigError = throwsA(isA()); diff --git a/pkgs/package_config/test/parse_test.dart b/pkgs/package_config/test/parse_test.dart index 385be368e..ef73c2e1e 100644 --- a/pkgs/package_config/test/parse_test.dart +++ b/pkgs/package_config/test/parse_test.dart @@ -37,6 +37,7 @@ void main() { expect(foo.root, Uri.parse("file:///foo/")); expect(foo.packageUriRoot, Uri.parse("file:///foo/lib/")); expect(foo.languageVersion, LanguageVersion(2, 7)); + expect(foo.relativeRoot, false); }); test("valid empty", () { @@ -132,6 +133,7 @@ void main() { expect(foo.packageUriRoot, Uri.parse("file:///foo/lib/")); expect(foo.languageVersion, LanguageVersion(2, 5)); expect(foo.extraData, {"nonstandard": true}); + expect(foo.relativeRoot, false); var bar = config["bar"]!; expect(bar, isNotNull); @@ -139,12 +141,14 @@ void main() { expect(bar.packageUriRoot, Uri.parse("file:///bar/lib/")); expect(bar.languageVersion, LanguageVersion(9999, 9999)); expect(bar.extraData, null); + expect(bar.relativeRoot, false); var baz = config["baz"]!; expect(baz, isNotNull); expect(baz.root, Uri.parse("file:///tmp/")); expect(baz.packageUriRoot, Uri.parse("file:///tmp/lib/")); expect(baz.languageVersion, null); + expect(baz.relativeRoot, true); // No slash after root or package root. One is inserted. var noslash = config["noslash"]!; @@ -152,6 +156,7 @@ void main() { expect(noslash.root, Uri.parse("file:///tmp/noslash/")); expect(noslash.packageUriRoot, Uri.parse("file:///tmp/noslash/lib/")); expect(noslash.languageVersion, null); + expect(noslash.relativeRoot, true); expect(config.extraData, { "generator": "pub", From 9bf6b87cb42b2817d0c0d8cb874268ee6d6c07f3 Mon Sep 17 00:00:00 2001 From: Alexander Thomas Date: Thu, 28 Jan 2021 16:24:37 +0100 Subject: [PATCH 105/170] Migrate to GitHub Actions (dart-lang/package_config#103) --- .../.github/workflows/test-package.yml | 61 +++++++++++++++++++ pkgs/package_config/.travis.yml | 21 ------- pkgs/package_config/README.md | 2 +- 3 files changed, 62 insertions(+), 22 deletions(-) create mode 100644 pkgs/package_config/.github/workflows/test-package.yml delete mode 100644 pkgs/package_config/.travis.yml diff --git a/pkgs/package_config/.github/workflows/test-package.yml b/pkgs/package_config/.github/workflows/test-package.yml new file mode 100644 index 000000000..20220ab61 --- /dev/null +++ b/pkgs/package_config/.github/workflows/test-package.yml @@ -0,0 +1,61 @@ +name: Dart CI + +on: + # Run on PRs and pushes to the default branch. + push: + branches: [ master ] + pull_request: + branches: [ master ] + schedule: + - cron: "0 0 * * 0" + +env: + PUB_ENVIRONMENT: bot.github + +jobs: + # Check code formatting and static analysis on a single OS (linux) + # against Dart dev. + analyze: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + sdk: [dev] + steps: + - uses: actions/checkout@v2 + - uses: dart-lang/setup-dart@v0.3 + with: + sdk: ${{ matrix.sdk }} + - id: install + name: Install dependencies + run: dart pub get + - name: Check formatting + run: dart format --output=none --set-exit-if-changed . + if: always() && steps.install.outcome == 'success' + - name: Analyze code + run: dart analyze --fatal-infos + if: always() && steps.install.outcome == 'success' + + # Run tests on a matrix consisting of two dimensions: + # 1. OS: ubuntu-latest, (macos-latest, windows-latest) + # 2. release channel: dev + test: + needs: analyze + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + # Add macos-latest and/or windows-latest if relevant for this package. + os: [ubuntu-latest] + sdk: [dev] + steps: + - uses: actions/checkout@v2 + - uses: dart-lang/setup-dart@v0.3 + with: + sdk: ${{ matrix.sdk }} + - id: install + name: Install dependencies + run: dart pub get + - name: Run tests + run: dart run build_runner test -- -p chrome,vm + if: always() && steps.install.outcome == 'success' diff --git a/pkgs/package_config/.travis.yml b/pkgs/package_config/.travis.yml deleted file mode 100644 index c4e5bdb8f..000000000 --- a/pkgs/package_config/.travis.yml +++ /dev/null @@ -1,21 +0,0 @@ -language: dart -sudo: false -dart: - - dev -dart_task: - - test - - dartfmt - - dart analyze --fatal-infos . - -matrix: - include: - - dart: dev - script: pub run build_runner test -- -p chrome - -# Only building master means that we don't run two builds for each pull request. -branches: - only: [master] - -cache: - directories: - - $HOME/.pub-cache diff --git a/pkgs/package_config/README.md b/pkgs/package_config/README.md index 1ad4b41c1..ada1bd0ec 100644 --- a/pkgs/package_config/README.md +++ b/pkgs/package_config/README.md @@ -1,4 +1,4 @@ -[![Build Status](https://travis-ci.org/dart-lang/package_config.svg?branch=master)](https://travis-ci.org/dart-lang/package_config) +[![Build Status](https://github.com/dart-lang/package_config/workflows/Dart%20CI/badge.svg)](https://github.com/dart-lang/package_config/actions?query=workflow%3A"Dart+CI"+branch%3Amaster) [![pub package](https://img.shields.io/pub/v/package_config.svg)](https://pub.dev/packages/package_config) Support for working with **Package Configuration** files as described From e96a1b0651fdd5ea397c51baf123ec0e068eedcd Mon Sep 17 00:00:00 2001 From: Jacob MacDonald Date: Fri, 5 Feb 2021 09:39:15 -0800 Subject: [PATCH 106/170] stable null safety release, clean up deps (dart-lang/package_config#105) --- pkgs/package_config/pubspec.yaml | 54 ++++++-------------------------- 1 file changed, 9 insertions(+), 45 deletions(-) diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 5903bc8ac..4f74712d6 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 2.0.0-nullsafety.1 +version: 2.0.0 description: Support for working with Package Configuration files. homepage: https://github.com/dart-lang/package_config @@ -7,53 +7,17 @@ environment: sdk: '>=2.12.0-0 <3.0.0' dependencies: - path: ^1.8.0-nullsafety.3 + path: ^1.8.0 dev_dependencies: - build_resolvers: ^1.10.0 build_runner: ^1.10.0 - build_runner_core: ^1.10.0 build_test: ^1.3.0 - build_web_compilers: ^2.15.0 - pedantic: ^1.10.0-nullsafety.3 - test: ^1.16.0-nullsafety.4 + build_web_compilers: ^2.12.2 + pedantic: ^1.10.0-nullsafety.0 + test: ^1.16.0-nullsafety.19 +# Required due to dependency cycles dependency_overrides: - _fe_analyzer_shared: - git: - url: git://github.com/dart-lang/sdk.git - path: pkg/_fe_analyzer_shared - analyzer: - git: - url: git://github.com/dart-lang/sdk.git - path: pkg/analyzer - build_resolvers: - git: - url: git://github.com/dart-lang/build.git - path: build_resolvers - build_runner: - git: - url: git://github.com/dart-lang/build.git - path: build_runner - build_runner_core: - git: - url: git://github.com/dart-lang/build.git - path: build_runner_core - build_test: - git: - url: git://github.com/dart-lang/build.git - path: build_test - coverage: - git: git://github.com/dart-lang/coverage.git - test: - git: - url: git://github.com/dart-lang/test.git - path: pkgs/test - test_api: - git: - url: git://github.com/dart-lang/test.git - path: pkgs/test_api - test_core: - git: - url: git://github.com/dart-lang/test.git - path: pkgs/test_core + test: ^1.16.0-nullsafety.19 + coverage: ^0.15.1 + analyzer: ^0.41.0 From ec2b4685ecbb4ed93b1e7e8ed8e8519df810d98d Mon Sep 17 00:00:00 2001 From: Alexander Thomas Date: Tue, 9 Feb 2021 11:53:19 +0100 Subject: [PATCH 107/170] Include duplicate package name in error message (dart-lang/package_config#104) --- pkgs/package_config/lib/src/package_config_impl.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/package_config/lib/src/package_config_impl.dart b/pkgs/package_config/lib/src/package_config_impl.dart index c75111580..122999106 100644 --- a/pkgs/package_config/lib/src/package_config_impl.dart +++ b/pkgs/package_config/lib/src/package_config_impl.dart @@ -77,7 +77,7 @@ class SimplePackageConfig implements PackageConfig { var name = package.name; if (packageNames.contains(name)) { onError(PackageConfigArgumentError( - name, "packages", "Duplicate package name")); + name, "packages", "Duplicate package name '$name'")); continue; } packageNames.add(name); From 56a74123ffd838842e1bdf6068fa054e975435a2 Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Fri, 19 Mar 2021 13:36:04 -0700 Subject: [PATCH 108/170] Use unique library names (dart-lang/package_config#107) The current dartdocs output does not link correctly because of the conflicting library names. - Use a stable SDK and dependencies. - Test on the oldest supported SDK. - Remove dependency overrides. --- .../.github/workflows/test-package.yml | 2 +- pkgs/package_config/CHANGELOG.md | 4 ++++ pkgs/package_config/lib/package_config_types.dart | 2 +- pkgs/package_config/pubspec.yaml | 14 ++++---------- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/pkgs/package_config/.github/workflows/test-package.yml b/pkgs/package_config/.github/workflows/test-package.yml index 20220ab61..d0e1e23e5 100644 --- a/pkgs/package_config/.github/workflows/test-package.yml +++ b/pkgs/package_config/.github/workflows/test-package.yml @@ -47,7 +47,7 @@ jobs: matrix: # Add macos-latest and/or windows-latest if relevant for this package. os: [ubuntu-latest] - sdk: [dev] + sdk: [2.12.0, dev] steps: - uses: actions/checkout@v2 - uses: dart-lang/setup-dart@v0.3 diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index 4a04782b4..9949b51db 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.1 + +- Use unique library names to correct docs issue. + ## 2.0.0 - Migrate to null safety. diff --git a/pkgs/package_config/lib/package_config_types.dart b/pkgs/package_config/lib/package_config_types.dart index f0637b11b..b3fca164c 100644 --- a/pkgs/package_config/lib/package_config_types.dart +++ b/pkgs/package_config/lib/package_config_types.dart @@ -4,7 +4,7 @@ /// A package configuration is a way to assign file paths to package URIs, /// and vice-versa, -library package_config.package_config; +library package_config.package_config_types; export "src/package_config.dart" show PackageConfig, Package, LanguageVersion, InvalidLanguageVersion; diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 4f74712d6..1ee725098 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,10 +1,10 @@ name: package_config -version: 2.0.0 +version: 2.0.1 description: Support for working with Package Configuration files. homepage: https://github.com/dart-lang/package_config environment: - sdk: '>=2.12.0-0 <3.0.0' + sdk: '>=2.12.0 <3.0.0' dependencies: path: ^1.8.0 @@ -13,11 +13,5 @@ dev_dependencies: build_runner: ^1.10.0 build_test: ^1.3.0 build_web_compilers: ^2.12.2 - pedantic: ^1.10.0-nullsafety.0 - test: ^1.16.0-nullsafety.19 - -# Required due to dependency cycles -dependency_overrides: - test: ^1.16.0-nullsafety.19 - coverage: ^0.15.1 - analyzer: ^0.41.0 + pedantic: ^1.10.0 + test: ^1.16.0 From f72b4a0098553482101113d83296e078022a2287 Mon Sep 17 00:00:00 2001 From: Franklin Yow <58489007+franklinyow@users.noreply.github.com> Date: Fri, 2 Apr 2021 16:07:34 -0700 Subject: [PATCH 109/170] Update LICENSE Changes to comply with internal review --- pkgs/package_config/LICENSE | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkgs/package_config/LICENSE b/pkgs/package_config/LICENSE index f75d7c237..767000764 100644 --- a/pkgs/package_config/LICENSE +++ b/pkgs/package_config/LICENSE @@ -1,4 +1,5 @@ -Copyright 2019, the Dart project authors. All rights reserved. +Copyright 2019, the Dart project authors. + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -9,7 +10,7 @@ met: copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of Google Inc. nor the names of its + * Neither the name of Google LLC nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. From c7adc8b35de00acd672991f76dee61d41f75e5c8 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Sat, 5 Jun 2021 13:28:33 -0700 Subject: [PATCH 110/170] Add dependabot --- pkgs/package_config/.github/dependabot.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 pkgs/package_config/.github/dependabot.yml diff --git a/pkgs/package_config/.github/dependabot.yml b/pkgs/package_config/.github/dependabot.yml new file mode 100644 index 000000000..430a85e7d --- /dev/null +++ b/pkgs/package_config/.github/dependabot.yml @@ -0,0 +1,11 @@ +# Set update schedule for GitHub Actions +# See https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/keeping-your-actions-up-to-date-with-dependabot + +version: 2 +updates: + +- package-ecosystem: "github-actions" + directory: "/" + schedule: + # Check for updates to GitHub Actions every weekday + interval: "daily" From 273066187fb72762eab1fdc2fbe041bd39086564 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 5 Jun 2021 13:36:53 -0700 Subject: [PATCH 111/170] Bump dart-lang/setup-dart from 0.3 to 1 (dart-lang/package_config#110) Bumps [dart-lang/setup-dart](https://github.com/dart-lang/setup-dart) from 0.3 to 1. - [Release notes](https://github.com/dart-lang/setup-dart/releases) - [Changelog](https://github.com/dart-lang/setup-dart/blob/main/CHANGELOG.md) - [Commits](https://github.com/dart-lang/setup-dart/compare/v0.3...v1) --- updated-dependencies: - dependency-name: dart-lang/setup-dart dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pkgs/package_config/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/package_config/.github/workflows/test-package.yml b/pkgs/package_config/.github/workflows/test-package.yml index d0e1e23e5..33bf62bd9 100644 --- a/pkgs/package_config/.github/workflows/test-package.yml +++ b/pkgs/package_config/.github/workflows/test-package.yml @@ -23,7 +23,7 @@ jobs: sdk: [dev] steps: - uses: actions/checkout@v2 - - uses: dart-lang/setup-dart@v0.3 + - uses: dart-lang/setup-dart@v1 with: sdk: ${{ matrix.sdk }} - id: install @@ -50,7 +50,7 @@ jobs: sdk: [2.12.0, dev] steps: - uses: actions/checkout@v2 - - uses: dart-lang/setup-dart@v0.3 + - uses: dart-lang/setup-dart@v1 with: sdk: ${{ matrix.sdk }} - id: install From 8049cb6e3338ffcc00e7c5baaf43af20955a3ef3 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Sat, 10 Jul 2021 20:59:52 -0700 Subject: [PATCH 112/170] Dart format with latest SDK (dart-lang/package_config#111) --- pkgs/package_config/lib/src/util_io.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkgs/package_config/lib/src/util_io.dart b/pkgs/package_config/lib/src/util_io.dart index 8e5f0b88e..9c48f049e 100644 --- a/pkgs/package_config/lib/src/util_io.dart +++ b/pkgs/package_config/lib/src/util_io.dart @@ -98,7 +98,9 @@ String pathJoinAll(Iterable parts) { var buffer = StringBuffer(); var separator = ""; for (var part in parts) { - buffer..write(separator)..write(part); + buffer + ..write(separator) + ..write(part); separator = part.endsWith(Platform.pathSeparator) ? "" : Platform.pathSeparator; } From df19c5c971463a5a744fae21e20de5c7ac8cd8a9 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Thu, 15 Jul 2021 10:35:22 -0700 Subject: [PATCH 113/170] Update to latest deps, fix remaining lints (dart-lang/package_config#112) --- pkgs/package_config/analysis_options.yaml | 5 - pkgs/package_config/lib/package_config.dart | 26 +- .../lib/package_config_types.dart | 4 +- pkgs/package_config/lib/src/discovery.dart | 42 +- .../lib/src/package_config.dart | 24 +- .../lib/src/package_config_impl.dart | 126 +++--- .../lib/src/package_config_io.dart | 46 +-- .../lib/src/package_config_json.dart | 82 ++-- .../package_config/lib/src/packages_file.dart | 40 +- pkgs/package_config/lib/src/util.dart | 32 +- pkgs/package_config/lib/src/util_io.dart | 22 +- pkgs/package_config/pubspec.yaml | 6 +- pkgs/package_config/test/discovery_test.dart | 208 +++++----- .../test/discovery_uri_test.dart | 182 ++++----- .../test/package_config_impl_test.dart | 144 +++---- pkgs/package_config/test/parse_test.dart | 378 +++++++++--------- pkgs/package_config/test/src/util.dart | 17 +- pkgs/package_config/test/src/util_io.dart | 16 +- 18 files changed, 718 insertions(+), 682 deletions(-) diff --git a/pkgs/package_config/analysis_options.yaml b/pkgs/package_config/analysis_options.yaml index a7854087c..a0ba68de2 100644 --- a/pkgs/package_config/analysis_options.yaml +++ b/pkgs/package_config/analysis_options.yaml @@ -3,8 +3,3 @@ # BSD-style license that can be found in the LICENSE file. include: package:pedantic/analysis_options.1.9.0.yaml -analyzer: - errors: - annotate_overrides: ignore - prefer_single_quotes: ignore - use_function_type_syntax_for_parameters: ignore diff --git a/pkgs/package_config/lib/package_config.dart b/pkgs/package_config/lib/package_config.dart index 3dfd8ef29..bd227e4e5 100644 --- a/pkgs/package_config/lib/package_config.dart +++ b/pkgs/package_config/lib/package_config.dart @@ -9,15 +9,15 @@ /// configurations in the [specified format](https://github.com/dart-lang/language/blob/master/accepted/future-releases/language-versioning/package-config-file-v2.md). library package_config.package_config; -import "dart:io" show File, Directory; -import "dart:typed_data" show Uint8List; +import 'dart:io' show File, Directory; +import 'dart:typed_data' show Uint8List; -import "src/discovery.dart" as discover; -import "src/errors.dart" show throwError; -import "src/package_config.dart"; -import "src/package_config_io.dart"; +import 'src/discovery.dart' as discover; +import 'src/errors.dart' show throwError; +import 'src/package_config.dart'; +import 'src/package_config_io.dart'; -export "package_config_types.dart"; +export 'package_config_types.dart'; /// Reads a specific package configuration file. /// @@ -42,7 +42,7 @@ export "package_config_types.dart"; /// a valid configuration from the invalid configuration file. /// If no [onError] is provided, errors are thrown immediately. Future loadPackageConfig(File file, - {bool preferNewest = true, void onError(Object error)?}) => + {bool preferNewest = true, void Function(Object error)? onError}) => readAnyConfigFile(file, preferNewest, onError ?? throwError); /// Reads a specific package configuration URI. @@ -87,9 +87,9 @@ Future loadPackageConfig(File file, /// a valid configuration from the invalid configuration file. /// If no [onError] is provided, errors are thrown immediately. Future loadPackageConfigUri(Uri file, - {Future loader(Uri uri)?, + {Future Function(Uri uri)? loader, bool preferNewest = true, - void onError(Object error)?}) => + void Function(Object error)? onError}) => readAnyConfigFileUri(file, loader, onError ?? throwError, preferNewest); /// Finds a package configuration relative to [directory]. @@ -113,7 +113,7 @@ Future loadPackageConfigUri(Uri file, /// /// Returns `null` if no configuration file is found. Future findPackageConfig(Directory directory, - {bool recurse = true, void onError(Object error)?}) => + {bool recurse = true, void Function(Object error)? onError}) => discover.findPackageConfig(directory, recurse, onError ?? throwError); /// Finds a package configuration relative to [location]. @@ -158,8 +158,8 @@ Future findPackageConfig(Directory directory, /// Returns `null` if no configuration file is found. Future findPackageConfigUri(Uri location, {bool recurse = true, - Future loader(Uri uri)?, - void onError(Object error)?}) => + Future Function(Uri uri)? loader, + void Function(Object error)? onError}) => discover.findPackageConfigUri( location, loader, onError ?? throwError, recurse); diff --git a/pkgs/package_config/lib/package_config_types.dart b/pkgs/package_config/lib/package_config_types.dart index b3fca164c..482f82ac2 100644 --- a/pkgs/package_config/lib/package_config_types.dart +++ b/pkgs/package_config/lib/package_config_types.dart @@ -6,6 +6,6 @@ /// and vice-versa, library package_config.package_config_types; -export "src/package_config.dart" +export 'src/package_config.dart' show PackageConfig, Package, LanguageVersion, InvalidLanguageVersion; -export "src/errors.dart" show PackageConfigError; +export 'src/errors.dart' show PackageConfigError; diff --git a/pkgs/package_config/lib/src/discovery.dart b/pkgs/package_config/lib/src/discovery.dart index a3e01d710..a6cc451f2 100644 --- a/pkgs/package_config/lib/src/discovery.dart +++ b/pkgs/package_config/lib/src/discovery.dart @@ -2,21 +2,21 @@ // 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. -import "dart:io"; +import 'dart:io'; import 'dart:typed_data'; import 'package_config_io.dart'; -import "errors.dart"; -import "package_config_impl.dart"; -import "package_config_json.dart"; -import "packages_file.dart" as packages_file; -import "util_io.dart" show defaultLoader, pathJoin; +import 'errors.dart'; +import 'package_config_impl.dart'; +import 'package_config_json.dart'; +import 'packages_file.dart' as packages_file; +import 'util_io.dart' show defaultLoader, pathJoin; -final Uri packageConfigJsonPath = Uri(path: ".dart_tool/package_config.json"); -final Uri dotPackagesPath = Uri(path: ".packages"); -final Uri currentPath = Uri(path: "."); -final Uri parentPath = Uri(path: ".."); +final Uri packageConfigJsonPath = Uri(path: '.dart_tool/package_config.json'); +final Uri dotPackagesPath = Uri(path: '.packages'); +final Uri currentPath = Uri(path: '.'); +final Uri parentPath = Uri(path: '..'); /// Discover the package configuration for a Dart script. /// @@ -32,8 +32,8 @@ final Uri parentPath = Uri(path: ".."); /// If any of these tests succeed, a `PackageConfig` class is returned. /// Returns `null` if no configuration was found. If a configuration /// is needed, then the caller can supply [PackageConfig.empty]. -Future findPackageConfig( - Directory baseDirectory, bool recursive, void onError(Object error)) async { +Future findPackageConfig(Directory baseDirectory, + bool recursive, void Function(Object error) onError) async { var directory = baseDirectory; if (!directory.isAbsolute) directory = directory.absolute; if (!await directory.exists()) { @@ -55,16 +55,16 @@ Future findPackageConfig( /// Similar to [findPackageConfig] but based on a URI. Future findPackageConfigUri( Uri location, - Future loader(Uri uri)?, - void onError(Object error), + Future Function(Uri uri)? loader, + void Function(Object error) onError, bool recursive) async { - if (location.isScheme("package")) { + if (location.isScheme('package')) { onError(PackageConfigArgumentError( - location, "location", "Must not be a package: URI")); + location, 'location', 'Must not be a package: URI')); return null; } if (loader == null) { - if (location.isScheme("file")) { + if (location.isScheme('file')) { return findPackageConfig( Directory.fromUri(location.resolveUri(currentPath)), recursive, @@ -72,7 +72,7 @@ Future findPackageConfigUri( } loader = defaultLoader; } - if (!location.path.endsWith("/")) location = location.resolveUri(currentPath); + if (!location.path.endsWith('/')) location = location.resolveUri(currentPath); while (true) { var file = location.resolveUri(packageConfigJsonPath); var bytes = await loader(file); @@ -103,7 +103,7 @@ Future findPackageConfigUri( /// a best-effort attempt is made to return a package configuration. /// This may be the empty package configuration. Future findPackagConfigInDirectory( - Directory directory, void onError(Object error)) async { + Directory directory, void Function(Object error) onError) async { var packageConfigFile = await checkForPackageConfigJsonFile(directory); if (packageConfigFile != null) { return await readPackageConfigJsonFile(packageConfigFile, onError); @@ -118,13 +118,13 @@ Future findPackagConfigInDirectory( Future checkForPackageConfigJsonFile(Directory directory) async { assert(directory.isAbsolute); var file = - File(pathJoin(directory.path, ".dart_tool", "package_config.json")); + File(pathJoin(directory.path, '.dart_tool', 'package_config.json')); if (await file.exists()) return file; return null; } Future checkForDotPackagesFile(Directory directory) async { - var file = File(pathJoin(directory.path, ".packages")); + var file = File(pathJoin(directory.path, '.packages')); if (await file.exists()) return file; return null; } diff --git a/pkgs/package_config/lib/src/package_config.dart b/pkgs/package_config/lib/src/package_config.dart index 26aa39622..8210132a1 100644 --- a/pkgs/package_config/lib/src/package_config.dart +++ b/pkgs/package_config/lib/src/package_config.dart @@ -5,7 +5,7 @@ import 'dart:typed_data'; import 'errors.dart'; -import "package_config_impl.dart"; +import 'package_config_impl.dart'; import 'package_config_json.dart'; /// A package configuration. @@ -70,7 +70,7 @@ abstract class PackageConfig { /// The result may be [PackageConfig.empty] if there is no way to /// extract useful information from the bytes. static PackageConfig parseBytes(Uint8List bytes, Uri baseUri, - {void onError(Object error)?}) => + {void Function(Object error)? onError}) => parsePackageConfigBytes(bytes, baseUri, onError ?? throwError); /// Parses a package configuration file. @@ -90,7 +90,7 @@ abstract class PackageConfig { /// The result may be [PackageConfig.empty] if there is no way to /// extract useful information from the bytes. static PackageConfig parseString(String configuration, Uri baseUri, - {void onError(Object error)?}) => + {void Function(Object error)? onError}) => parsePackageConfigString(configuration, baseUri, onError ?? throwError); /// Parses the JSON data of a package configuration file. @@ -111,7 +111,7 @@ abstract class PackageConfig { /// The result may be [PackageConfig.empty] if there is no way to /// extract useful information from the bytes. static PackageConfig parseJson(Object? jsonData, Uri baseUri, - {void onError(Object error)?}) => + {void Function(Object error)? onError}) => parsePackageConfigJson(jsonData, baseUri, onError ?? throwError); /// Writes a configuration file for this configuration on [output]. @@ -302,8 +302,8 @@ abstract class LanguageVersion implements Comparable { /// The maximal value allowed by [major] and [minor] values; static const int maxValue = 0x7FFFFFFF; factory LanguageVersion(int major, int minor) { - RangeError.checkValueInInterval(major, 0, maxValue, "major"); - RangeError.checkValueInInterval(minor, 0, maxValue, "major"); + RangeError.checkValueInInterval(major, 0, maxValue, 'major'); + RangeError.checkValueInInterval(minor, 0, maxValue, 'major'); return SimpleLanguageVersion(major, minor, null); } @@ -324,7 +324,8 @@ abstract class LanguageVersion implements Comparable { /// If [onError] is not supplied, it defaults to throwing the exception. /// If the call does not throw, then an [InvalidLanguageVersion] is returned /// containing the original [source]. - static LanguageVersion parse(String source, {void onError(Object error)?}) => + static LanguageVersion parse(String source, + {void Function(Object error)? onError}) => parseLanguageVersion(source, onError ?? throwError); /// The major language version. @@ -352,6 +353,7 @@ abstract class LanguageVersion implements Comparable { /// is greater than the latter's major version, or if they have /// the same major version and the former's minor version is greater than /// the latter's. + @override int compareTo(LanguageVersion other); /// Valid language versions with the same [major] and [minor] values are @@ -359,14 +361,17 @@ abstract class LanguageVersion implements Comparable { /// /// Invalid language versions ([InvalidLanguageVersion]) are not equal to /// any other object. + @override bool operator ==(Object other); + @override int get hashCode; /// A string representation of the language version. /// /// A valid language version is represented as /// `"${version.major}.${version.minor}"`. + @override String toString(); } @@ -377,16 +382,21 @@ abstract class LanguageVersion implements Comparable { /// which did not throw on an error. abstract class InvalidLanguageVersion implements LanguageVersion { /// The value -1 for an invalid language version. + @override int get major; /// The value -1 for an invalid language version. + @override int get minor; /// An invalid language version is only equal to itself. + @override bool operator ==(Object other); + @override int get hashCode; /// The original invalid version string. + @override String toString(); } diff --git a/pkgs/package_config/lib/src/package_config_impl.dart b/pkgs/package_config/lib/src/package_config_impl.dart index 122999106..4167d35f8 100644 --- a/pkgs/package_config/lib/src/package_config_impl.dart +++ b/pkgs/package_config/lib/src/package_config_impl.dart @@ -3,21 +3,23 @@ // BSD-style license that can be found in the LICENSE file. import 'errors.dart'; -import "package_config.dart"; -import "util.dart"; +import 'package_config.dart'; +import 'util.dart'; -export "package_config.dart"; +export 'package_config.dart'; // Implementations of the main data types exposed by the API of this package. class SimplePackageConfig implements PackageConfig { + @override final int version; final Map _packages; final PackageTree _packageTree; + @override final Object? extraData; factory SimplePackageConfig(int version, Iterable packages, - [Object? extraData, void onError(Object error)?]) { + [Object? extraData, void Function(Object error)? onError]) { onError ??= throwError; var validVersion = _validateVersion(version, onError); var sortedPackages = [...packages]..sort(_compareRoot); @@ -39,17 +41,18 @@ class SimplePackageConfig implements PackageConfig { _packages = const {}, extraData = null; - static int _validateVersion(int version, void onError(Object error)) { + static int _validateVersion( + int version, void Function(Object error) onError) { if (version < 0 || version > PackageConfig.maxVersion) { - onError(PackageConfigArgumentError(version, "version", - "Must be in the range 1 to ${PackageConfig.maxVersion}")); + onError(PackageConfigArgumentError(version, 'version', + 'Must be in the range 1 to ${PackageConfig.maxVersion}')); return 2; // The minimal version supporting a SimplePackageConfig. } return version; } static PackageTree _validatePackages(Iterable originalPackages, - List packages, void onError(Object error)) { + List packages, void Function(Object error) onError) { var packageNames = {}; var tree = MutablePackageTree(); for (var originalPackage in packages) { @@ -64,8 +67,8 @@ class SimplePackageConfig implements PackageConfig { originalPackage.extraData, originalPackage.relativeRoot, (error) { if (error is PackageConfigArgumentError) { - onError(PackageConfigArgumentError(packages, "packages", - "Package ${package!.name}: ${error.message}")); + onError(PackageConfigArgumentError(packages, 'packages', + 'Package ${package!.name}: ${error.message}')); } else { onError(error); } @@ -77,7 +80,7 @@ class SimplePackageConfig implements PackageConfig { var name = package.name; if (packageNames.contains(name)) { onError(PackageConfigArgumentError( - name, "packages", "Duplicate package name '$name'")); + name, 'packages', "Duplicate package name '$name'")); continue; } packageNames.add(name); @@ -88,20 +91,20 @@ class SimplePackageConfig implements PackageConfig { if (error.isRootConflict) { onError(PackageConfigArgumentError( originalPackages, - "packages", - "Packages ${package!.name} and ${existingPackage.name} " - "have the same root directory: ${package.root}.\n")); + 'packages', + 'Packages ${package!.name} and ${existingPackage.name} ' + 'have the same root directory: ${package.root}.\n')); } else { assert(error.isPackageRootConflict); // Package is inside the package URI root of the existing package. onError(PackageConfigArgumentError( originalPackages, - "packages", - "Package ${package!.name} is inside the package URI root of " - "package ${existingPackage.name}.\n" - "${existingPackage.name} URI root: " - "${existingPackage.packageUriRoot}\n" - "${package.name} root: ${package.root}\n")); + 'packages', + 'Package ${package!.name} is inside the package URI root of ' + 'package ${existingPackage.name}.\n' + '${existingPackage.name} URI root: ' + '${existingPackage.packageUriRoot}\n' + '${package.name} root: ${package.root}\n')); } } else { // Any other error. @@ -112,8 +115,10 @@ class SimplePackageConfig implements PackageConfig { return tree; } + @override Iterable get packages => _packages.values; + @override Package? operator [](String packageName) => _packages[packageName]; /// Provides the associated package for a specific [file] (or directory). @@ -122,22 +127,25 @@ class SimplePackageConfig implements PackageConfig { /// That is, the [Package.rootUri] directory is a parent directory /// of the [file]'s location. /// Returns `null` if the file does not belong to any package. + @override Package? packageOf(Uri file) => _packageTree.packageOf(file); + @override Uri? resolve(Uri packageUri) { - var packageName = checkValidPackageUri(packageUri, "packageUri"); + var packageName = checkValidPackageUri(packageUri, 'packageUri'); return _packages[packageName]?.packageUriRoot.resolveUri( Uri(path: packageUri.path.substring(packageName.length + 1))); } + @override Uri? toPackageUri(Uri nonPackageUri) { - if (nonPackageUri.isScheme("package")) { + if (nonPackageUri.isScheme('package')) { throw PackageConfigArgumentError( - nonPackageUri, "nonPackageUri", "Must not be a package URI"); + nonPackageUri, 'nonPackageUri', 'Must not be a package URI'); } if (nonPackageUri.hasQuery || nonPackageUri.hasFragment) { - throw PackageConfigArgumentError(nonPackageUri, "nonPackageUri", - "Must not have query or fragment part"); + throw PackageConfigArgumentError(nonPackageUri, 'nonPackageUri', + 'Must not have query or fragment part'); } // Find package that file belongs to. var package = _packageTree.packageOf(nonPackageUri); @@ -147,7 +155,7 @@ class SimplePackageConfig implements PackageConfig { var root = package.packageUriRoot.toString(); if (_beginsWith(package.root.toString().length, root, path)) { var rest = path.substring(root.length); - return Uri(scheme: "package", path: "${package.name}/$rest"); + return Uri(scheme: 'package', path: '${package.name}/$rest'); } return null; } @@ -155,11 +163,17 @@ class SimplePackageConfig implements PackageConfig { /// Configuration data for a single package. class SimplePackage implements Package { + @override final String name; + @override final Uri root; + @override final Uri packageUriRoot; + @override final LanguageVersion? languageVersion; + @override final Object? extraData; + @override final bool relativeRoot; SimplePackage._(this.name, this.root, this.packageUriRoot, @@ -187,30 +201,30 @@ class SimplePackage implements Package { LanguageVersion? languageVersion, Object? extraData, bool relativeRoot, - void onError(Object error)) { + void Function(Object error) onError) { var fatalError = false; var invalidIndex = checkPackageName(name); if (invalidIndex >= 0) { onError(PackageConfigFormatException( - "Not a valid package name", name, invalidIndex)); + 'Not a valid package name', name, invalidIndex)); fatalError = true; } - if (root.isScheme("package")) { + if (root.isScheme('package')) { onError(PackageConfigArgumentError( - "$root", "root", "Must not be a package URI")); + '$root', 'root', 'Must not be a package URI')); fatalError = true; } else if (!isAbsoluteDirectoryUri(root)) { onError(PackageConfigArgumentError( - "$root", - "root", - "In package $name: Not an absolute URI with no query or fragment " - "with a path ending in /")); + '$root', + 'root', + 'In package $name: Not an absolute URI with no query or fragment ' + 'with a path ending in /')); // Try to recover. If the URI has a scheme, // then ensure that the path ends with `/`. if (!root.hasScheme) { fatalError = true; - } else if (!root.path.endsWith("/")) { - root = root.replace(path: root.path + "/"); + } else if (!root.path.endsWith('/')) { + root = root.replace(path: root.path + '/'); } } if (packageUriRoot == null) { @@ -220,13 +234,13 @@ class SimplePackage implements Package { if (!isAbsoluteDirectoryUri(packageUriRoot)) { onError(PackageConfigArgumentError( packageUriRoot, - "packageUriRoot", - "In package $name: Not an absolute URI with no query or fragment " - "with a path ending in /")); + 'packageUriRoot', + 'In package $name: Not an absolute URI with no query or fragment ' + 'with a path ending in /')); packageUriRoot = root; } else if (!isUriPrefix(root, packageUriRoot)) { - onError(PackageConfigArgumentError(packageUriRoot, "packageUriRoot", - "The package URI root is not below the package root")); + onError(PackageConfigArgumentError(packageUriRoot, 'packageUriRoot', + 'The package URI root is not below the package root')); packageUriRoot = root; } } @@ -243,7 +257,7 @@ class SimplePackage implements Package { /// Reports a format exception on [onError] if not, or if the numbers /// are too large (at most 32-bit signed integers). LanguageVersion parseLanguageVersion( - String? source, void onError(Object error)) { + String? source, void Function(Object error) onError) { var index = 0; // Reads a positive decimal numeral. Returns the value of the numeral, // or a negative number in case of an error. @@ -254,7 +268,7 @@ LanguageVersion parseLanguageVersion( int readNumeral() { const maxValue = 0x7FFFFFFF; if (index == source!.length) { - onError(PackageConfigFormatException("Missing number", source, index)); + onError(PackageConfigFormatException('Missing number', source, index)); return -1; } var start = index; @@ -262,7 +276,7 @@ LanguageVersion parseLanguageVersion( var char = source.codeUnitAt(index); var digit = char ^ 0x30; if (digit > 9) { - onError(PackageConfigFormatException("Missing number", source, index)); + onError(PackageConfigFormatException('Missing number', source, index)); return -1; } var firstDigit = digit; @@ -271,7 +285,7 @@ LanguageVersion parseLanguageVersion( value = value * 10 + digit; if (value > maxValue) { onError( - PackageConfigFormatException("Number too large", source, start)); + PackageConfigFormatException('Number too large', source, start)); return -1; } index++; @@ -281,7 +295,7 @@ LanguageVersion parseLanguageVersion( } while (digit <= 9); if (firstDigit == 0 && index > start + 1) { onError(PackageConfigFormatException( - "Leading zero not allowed", source, start)); + 'Leading zero not allowed', source, start)); } return value; } @@ -301,13 +315,14 @@ LanguageVersion parseLanguageVersion( } if (index != source.length) { onError(PackageConfigFormatException( - "Unexpected trailing character", source, index)); + 'Unexpected trailing character', source, index)); return SimpleInvalidLanguageVersion(source); } return SimpleLanguageVersion(major, minor, source); } abstract class _SimpleLanguageVersionBase implements LanguageVersion { + @override int compareTo(LanguageVersion other) { var result = major.compareTo(other.major); if (result != 0) return result; @@ -316,26 +331,34 @@ abstract class _SimpleLanguageVersionBase implements LanguageVersion { } class SimpleLanguageVersion extends _SimpleLanguageVersionBase { + @override final int major; + @override final int minor; String? _source; SimpleLanguageVersion(this.major, this.minor, this._source); + @override bool operator ==(Object other) => other is LanguageVersion && major == other.major && minor == other.minor; + @override int get hashCode => (major * 17 ^ minor * 37) & 0x3FFFFFFF; - String toString() => _source ??= "$major.$minor"; + @override + String toString() => _source ??= '$major.$minor'; } class SimpleInvalidLanguageVersion extends _SimpleLanguageVersionBase implements InvalidLanguageVersion { final String? _source; SimpleInvalidLanguageVersion(this._source); + @override int get major => -1; + @override int get minor => -1; + @override String toString() => _source!; } @@ -374,6 +397,7 @@ class MutablePackageTree implements PackageTree { /// there is no tree object associated with it. Map? _packageChildren; + @override Iterable get allPackages sync* { for (var package in packages) { yield package; @@ -399,7 +423,8 @@ class MutablePackageTree implements PackageTree { /// /// The packages are added in order of their root path. /// It is never necessary to insert a node between two existing levels. - void add(int start, SimplePackage package, void onError(Object error)) { + void add( + int start, SimplePackage package, void Function(Object error) onError) { var path = package.root.toString(); for (var treePackage in packages) { // Check is package is inside treePackage. @@ -428,6 +453,7 @@ class MutablePackageTree implements PackageTree { packages.add(package); } + @override SimplePackage? packageOf(Uri file) { return findPackageOf(0, file.toString()); } @@ -471,8 +497,10 @@ class MutablePackageTree implements PackageTree { class EmptyPackageTree implements PackageTree { const EmptyPackageTree(); + @override Iterable get allPackages => const Iterable.empty(); + @override SimplePackage? packageOf(Uri file) => null; } diff --git a/pkgs/package_config/lib/src/package_config_io.dart b/pkgs/package_config/lib/src/package_config_io.dart index d3e59be47..9aed621e0 100644 --- a/pkgs/package_config/lib/src/package_config_io.dart +++ b/pkgs/package_config/lib/src/package_config_io.dart @@ -4,31 +4,31 @@ // dart:io dependent functionality for reading and writing configuration files. -import "dart:convert"; -import "dart:io"; -import "dart:typed_data"; +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; -import "errors.dart"; -import "package_config_impl.dart"; -import "package_config_json.dart"; -import "packages_file.dart" as packages_file; -import "util.dart"; -import "util_io.dart"; +import 'errors.dart'; +import 'package_config_impl.dart'; +import 'package_config_json.dart'; +import 'packages_file.dart' as packages_file; +import 'util.dart'; +import 'util_io.dart'; /// Name of directory where Dart tools store their configuration. /// /// Directory is created in the package root directory. -const dartToolDirName = ".dart_tool"; +const dartToolDirName = '.dart_tool'; /// Name of file containing new package configuration data. /// /// File is stored in the dart tool directory. -const packageConfigFileName = "package_config.json"; +const packageConfigFileName = 'package_config.json'; /// Name of file containing legacy package configuration data. /// /// File is stored in the package root directory. -const packagesFileName = ".packages"; +const packagesFileName = '.packages'; /// Reads a package configuration file. /// @@ -43,7 +43,7 @@ const packagesFileName = ".packages"; /// /// The file must exist and be a normal file. Future readAnyConfigFile( - File file, bool preferNewest, void onError(Object error)) async { + File file, bool preferNewest, void Function(Object error) onError) async { if (preferNewest && fileName(file.path) == packagesFileName) { var alternateFile = File( pathJoin(dirName(file.path), dartToolDirName, packageConfigFileName)); @@ -64,21 +64,21 @@ Future readAnyConfigFile( /// Like [readAnyConfigFile] but uses a URI and an optional loader. Future readAnyConfigFileUri( Uri file, - Future loader(Uri uri)?, - void onError(Object error), + Future Function(Uri uri)? loader, + void Function(Object error) onError, bool preferNewest) async { - if (file.isScheme("package")) { + if (file.isScheme('package')) { throw PackageConfigArgumentError( - file, "file", "Must not be a package: URI"); + file, 'file', 'Must not be a package: URI'); } if (loader == null) { - if (file.isScheme("file")) { + if (file.isScheme('file')) { return await readAnyConfigFile(File.fromUri(file), preferNewest, onError); } loader = defaultLoader; } if (preferNewest && file.pathSegments.last == packagesFileName) { - var alternateFile = file.resolve("$dartToolDirName/$packageConfigFileName"); + var alternateFile = file.resolve('$dartToolDirName/$packageConfigFileName'); Uint8List? bytes; try { bytes = await loader(alternateFile); @@ -99,7 +99,7 @@ Future readAnyConfigFileUri( } if (bytes == null) { onError(PackageConfigArgumentError( - file.toString(), "file", "File cannot be read")); + file.toString(), 'file', 'File cannot be read')); return const SimplePackageConfig.empty(); } return parseAnyConfigFile(bytes, file, onError); @@ -110,7 +110,7 @@ Future readAnyConfigFileUri( /// Assumes it's a JSON file if the first non-whitespace character /// is `{`, otherwise assumes it's a `.packages` file. PackageConfig parseAnyConfigFile( - Uint8List bytes, Uri file, void onError(Object error)) { + Uint8List bytes, Uri file, void Function(Object error) onError) { var firstChar = firstNonWhitespaceChar(bytes); if (firstChar != $lbrace) { // Definitely not a JSON object, probably a .packages. @@ -120,7 +120,7 @@ PackageConfig parseAnyConfigFile( } Future readPackageConfigJsonFile( - File file, void onError(Object error)) async { + File file, void Function(Object error) onError) async { Uint8List bytes; try { bytes = await file.readAsBytes(); @@ -132,7 +132,7 @@ Future readPackageConfigJsonFile( } Future readDotPackagesFile( - File file, void onError(Object error)) async { + File file, void Function(Object error) onError) async { Uint8List bytes; try { bytes = await file.readAsBytes(); diff --git a/pkgs/package_config/lib/src/package_config_json.dart b/pkgs/package_config/lib/src/package_config_json.dart index 979c35ed4..1998b6606 100644 --- a/pkgs/package_config/lib/src/package_config_json.dart +++ b/pkgs/package_config/lib/src/package_config_json.dart @@ -4,21 +4,21 @@ // Parsing and serialization of package configurations. -import "dart:convert"; -import "dart:typed_data"; +import 'dart:convert'; +import 'dart:typed_data'; -import "errors.dart"; -import "package_config_impl.dart"; -import "packages_file.dart" as packages_file; -import "util.dart"; +import 'errors.dart'; +import 'package_config_impl.dart'; +import 'packages_file.dart' as packages_file; +import 'util.dart'; -const String _configVersionKey = "configVersion"; -const String _packagesKey = "packages"; +const String _configVersionKey = 'configVersion'; +const String _packagesKey = 'packages'; const List _topNames = [_configVersionKey, _packagesKey]; -const String _nameKey = "name"; -const String _rootUriKey = "rootUri"; -const String _packageUriKey = "packageUri"; -const String _languageVersionKey = "languageVersion"; +const String _nameKey = 'name'; +const String _rootUriKey = 'rootUri'; +const String _packageUriKey = 'packageUri'; +const String _languageVersionKey = 'languageVersion'; const List _packageNames = [ _nameKey, _rootUriKey, @@ -26,14 +26,14 @@ const List _packageNames = [ _languageVersionKey ]; -const String _generatedKey = "generated"; -const String _generatorKey = "generator"; -const String _generatorVersionKey = "generatorVersion"; +const String _generatedKey = 'generated'; +const String _generatorKey = 'generator'; +const String _generatorVersionKey = 'generatorVersion'; final _jsonUtf8Decoder = json.fuse(utf8).decoder; PackageConfig parsePackageConfigBytes( - Uint8List bytes, Uri file, void onError(Object error)) { + Uint8List bytes, Uri file, void Function(Object error) onError) { // TODO(lrn): Make this simpler. Maybe parse directly from bytes. var jsonObject; try { @@ -46,7 +46,7 @@ PackageConfig parsePackageConfigBytes( } PackageConfig parsePackageConfigString( - String source, Uri file, void onError(Object error)) { + String source, Uri file, void Function(Object error) onError) { var jsonObject; try { jsonObject = jsonDecode(source); @@ -80,21 +80,21 @@ PackageConfig parsePackageConfigString( /// The [baseLocation] is used as base URI to resolve the "rootUri" /// URI referencestring. PackageConfig parsePackageConfigJson( - Object? json, Uri baseLocation, void onError(Object error)) { - if (!baseLocation.hasScheme || baseLocation.isScheme("package")) { - throw PackageConfigArgumentError(baseLocation.toString(), "baseLocation", - "Must be an absolute non-package: URI"); + Object? json, Uri baseLocation, void Function(Object error) onError) { + if (!baseLocation.hasScheme || baseLocation.isScheme('package')) { + throw PackageConfigArgumentError(baseLocation.toString(), 'baseLocation', + 'Must be an absolute non-package: URI'); } - if (!baseLocation.path.endsWith("/")) { - baseLocation = baseLocation.resolveUri(Uri(path: ".")); + if (!baseLocation.path.endsWith('/')) { + baseLocation = baseLocation.resolveUri(Uri(path: '.')); } String typeName() { - if (0 is T) return "int"; - if ("" is T) return "string"; - if (const [] is T) return "array"; - return "object"; + if (0 is T) return 'int'; + if ('' is T) return 'string'; + if (const [] is T) return 'array'; + return 'object'; } T? checkType(Object? value, String name, [String? packageName]) { @@ -103,7 +103,7 @@ PackageConfig parsePackageConfigJson( // and Map. Recognize which to give a better error message. var message = "$name${packageName != null ? " of package $packageName" : ""}" - " is not a JSON ${typeName()}"; + ' is not a JSON ${typeName()}'; onError(PackageConfigFormatException(message, value)); return null; } @@ -140,27 +140,27 @@ PackageConfig parsePackageConfigJson( } }); if (!hasName) { - onError(PackageConfigFormatException("Missing name entry", entry)); + onError(PackageConfigFormatException('Missing name entry', entry)); } if (!hasRoot) { - onError(PackageConfigFormatException("Missing rootUri entry", entry)); + onError(PackageConfigFormatException('Missing rootUri entry', entry)); } if (name == null || rootUri == null) return null; var parsedRootUri = Uri.parse(rootUri!); var relativeRoot = !hasAbsolutePath(parsedRootUri); var root = baseLocation.resolveUri(parsedRootUri); - if (!root.path.endsWith("/")) root = root.replace(path: root.path + "/"); + if (!root.path.endsWith('/')) root = root.replace(path: root.path + '/'); var packageRoot = root; if (packageUri != null) packageRoot = root.resolve(packageUri!); - if (!packageRoot.path.endsWith("/")) { - packageRoot = packageRoot.replace(path: packageRoot.path + "/"); + if (!packageRoot.path.endsWith('/')) { + packageRoot = packageRoot.replace(path: packageRoot.path + '/'); } LanguageVersion? version; if (languageVersion != null) { version = parseLanguageVersion(languageVersion, onError); } else if (hasVersion) { - version = SimpleInvalidLanguageVersion("invalid"); + version = SimpleInvalidLanguageVersion('invalid'); } return SimplePackage.validate( @@ -174,7 +174,7 @@ PackageConfig parsePackageConfigJson( }); } - var map = checkType>(json, "value"); + var map = checkType>(json, 'value'); if (map == null) return const SimplePackageConfig.empty(); Map? extraData; List? packageList; @@ -189,7 +189,7 @@ PackageConfig parsePackageConfigJson( var packages = []; for (var package in packageArray) { var packageMap = - checkType>(package, "package entry"); + checkType>(package, 'package entry'); if (packageMap != null) { var entry = parsePackage(packageMap); if (entry != null) { @@ -205,11 +205,11 @@ PackageConfig parsePackageConfigJson( } }); if (configVersion == null) { - onError(PackageConfigFormatException("Missing configVersion entry", json)); + onError(PackageConfigFormatException('Missing configVersion entry', json)); configVersion = 2; } if (packageList == null) { - onError(PackageConfigFormatException("Missing packages list", json)); + onError(PackageConfigFormatException('Missing packages list', json)); packageList = []; } return SimplePackageConfig(configVersion!, packageList!, extraData, (error) { @@ -221,7 +221,7 @@ PackageConfig parsePackageConfigJson( }); } -final _jsonUtf8Encoder = JsonUtf8Encoder(" "); +final _jsonUtf8Encoder = JsonUtf8Encoder(' '); void writePackageConfigJsonUtf8( PackageConfig config, Uri? baseUri, Sink> output) { @@ -234,7 +234,7 @@ void writePackageConfigJsonString( PackageConfig config, Uri? baseUri, StringSink output) { // Can be optimized. var data = packageConfigToJson(config, baseUri); - output.write(JsonEncoder.withIndent(" ").convert(data)); + output.write(JsonEncoder.withIndent(' ').convert(data)); } Map packageConfigToJson(PackageConfig config, Uri? baseUri) => @@ -270,7 +270,7 @@ void writeDotPackages(PackageConfig config, Uri baseUri, StringSink output) { if (generator is String) { var generated = extraData[_generatedKey]; var generatorVersion = extraData[_generatorVersionKey]; - comment = "Generated by $generator" + comment = 'Generated by $generator' "${generatorVersion is String ? " $generatorVersion" : ""}" "${generated is String ? " on $generated" : ""}."; } diff --git a/pkgs/package_config/lib/src/packages_file.dart b/pkgs/package_config/lib/src/packages_file.dart index ddcf8563b..244663326 100644 --- a/pkgs/package_config/lib/src/packages_file.dart +++ b/pkgs/package_config/lib/src/packages_file.dart @@ -2,10 +2,10 @@ // 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. -import "package_config_impl.dart"; +import 'package_config_impl.dart'; -import "util.dart"; -import "errors.dart"; +import 'util.dart'; +import 'errors.dart'; /// The language version prior to the release of language versioning. /// @@ -31,10 +31,10 @@ final LanguageVersion _languageVersion = LanguageVersion(2, 7); /// [Package.packageUriRoot] is the same as its [Package.root] /// and it has no [Package.languageVersion]. PackageConfig parse( - List source, Uri baseLocation, void onError(Object error)) { - if (baseLocation.isScheme("package")) { + List source, Uri baseLocation, void Function(Object error) onError) { + if (baseLocation.isScheme('package')) { onError(PackageConfigArgumentError( - baseLocation, "baseLocation", "Must not be a package: URI")); + baseLocation, 'baseLocation', 'Must not be a package: URI')); return PackageConfig.empty; } var index = 0; @@ -51,7 +51,7 @@ PackageConfig parse( } if (char == $colon) { onError(PackageConfigFormatException( - "Missing package name", source, index - 1)); + 'Missing package name', source, index - 1)); ignoreLine = true; // Ignore if package name is invalid. } else { ignoreLine = char == $hash; // Ignore if comment. @@ -81,16 +81,16 @@ PackageConfig parse( var invalidIndex = checkPackageName(packageName); if (invalidIndex >= 0) { onError(PackageConfigFormatException( - "Not a valid package name", source, start + invalidIndex)); + 'Not a valid package name', source, start + invalidIndex)); continue; } if (queryStart >= 0) { onError(PackageConfigFormatException( - "Location URI must not have query", source, queryStart)); + 'Location URI must not have query', source, queryStart)); end = queryStart; } else if (fragmentStart >= 0) { onError(PackageConfigFormatException( - "Location URI must not have fragment", source, fragmentStart)); + 'Location URI must not have fragment', source, fragmentStart)); end = fragmentStart; } var packageValue = String.fromCharCodes(source, separatorIndex + 1, end); @@ -103,23 +103,23 @@ PackageConfig parse( } var relativeRoot = !hasAbsolutePath(packageLocation); packageLocation = baseLocation.resolveUri(packageLocation); - if (packageLocation.isScheme("package")) { + if (packageLocation.isScheme('package')) { onError(PackageConfigFormatException( - "Package URI as location for package", source, separatorIndex + 1)); + 'Package URI as location for package', source, separatorIndex + 1)); continue; } var path = packageLocation.path; if (!path.endsWith('/')) { - path += "/"; + path += '/'; packageLocation = packageLocation.replace(path: path); } if (packageNames.contains(packageName)) { onError(PackageConfigFormatException( - "Same package name occured more than once", source, start)); + 'Same package name occured more than once', source, start)); continue; } var rootUri = packageLocation; - if (path.endsWith("/lib/")) { + if (path.endsWith('/lib/')) { // Assume default Pub package layout. Include package itself in root. rootUri = packageLocation.replace(path: path.substring(0, path.length - 4)); @@ -158,7 +158,7 @@ PackageConfig parse( void write(StringSink output, PackageConfig config, {Uri? baseUri, String? comment}) { if (baseUri != null && !baseUri.isAbsolute) { - throw PackageConfigArgumentError(baseUri, "baseUri", "Must be absolute"); + throw PackageConfigArgumentError(baseUri, 'baseUri', 'Must be absolute'); } if (comment != null) { @@ -169,7 +169,7 @@ void write(StringSink output, PackageConfig config, output.writeln(commentLine); } } else { - output.write("# generated by package:package_config at "); + output.write('# generated by package:package_config at '); output.write(DateTime.now()); output.writeln(); } @@ -179,11 +179,11 @@ void write(StringSink output, PackageConfig config, // Validate packageName. if (!isValidPackageName(packageName)) { throw PackageConfigArgumentError( - config, "config", '"$packageName" is not a valid package name'); + config, 'config', '"$packageName" is not a valid package name'); } - if (uri.scheme == "package") { + if (uri.scheme == 'package') { throw PackageConfigArgumentError( - config, "config", "Package location must not be a package URI: $uri"); + config, 'config', 'Package location must not be a package URI: $uri'); } output.write(packageName); output.write(':'); diff --git a/pkgs/package_config/lib/src/util.dart b/pkgs/package_config/lib/src/util.dart index f490cdc1c..61488ac41 100644 --- a/pkgs/package_config/lib/src/util.dart +++ b/pkgs/package_config/lib/src/util.dart @@ -5,13 +5,13 @@ /// Utility methods used by more than one library in the package. library package_config.util; -import "errors.dart"; +import 'errors.dart'; // All ASCII characters that are valid in a package name, with space // for all the invalid ones (including space). const String _validPackageNameCharacters = r" ! $ &'()*+,-. 0123456789 ; = " - r"@ABCDEFGHIJKLMNOPQRSTUVWXYZ _ abcdefghijklmnopqrstuvwxyz ~ "; + r'@ABCDEFGHIJKLMNOPQRSTUVWXYZ _ abcdefghijklmnopqrstuvwxyz ~ '; /// Tests whether something is a valid Dart package name. bool isValidPackageName(String string) { @@ -47,17 +47,17 @@ int checkPackageName(String string) { /// Returns the package name extracted from the package URI, /// which is the path segment between `package:` and the first `/`. String checkValidPackageUri(Uri packageUri, String name) { - if (packageUri.scheme != "package") { - throw PackageConfigArgumentError(packageUri, name, "Not a package: URI"); + if (packageUri.scheme != 'package') { + throw PackageConfigArgumentError(packageUri, name, 'Not a package: URI'); } if (packageUri.hasAuthority) { throw PackageConfigArgumentError( - packageUri, name, "Package URIs must not have a host part"); + packageUri, name, 'Package URIs must not have a host part'); } if (packageUri.hasQuery) { // A query makes no sense if resolved to a file: URI. throw PackageConfigArgumentError( - packageUri, name, "Package URIs must not have a query part"); + packageUri, name, 'Package URIs must not have a query part'); } if (packageUri.hasFragment) { // We could leave the fragment after the URL when resolving, @@ -65,7 +65,7 @@ String checkValidPackageUri(Uri packageUri, String name) { // "package:foo/foo.dart#2" were considered different libraries. // Keep the syntax open in case we ever get multiple libraries in one file. throw PackageConfigArgumentError( - packageUri, name, "Package URIs must not have a fragment part"); + packageUri, name, 'Package URIs must not have a fragment part'); } if (packageUri.path.startsWith('/')) { throw PackageConfigArgumentError( @@ -81,7 +81,7 @@ String checkValidPackageUri(Uri packageUri, String name) { if (badIndex >= 0) { if (packageName.isEmpty) { throw PackageConfigArgumentError( - packageUri, name, "Package names mus be non-empty"); + packageUri, name, 'Package names mus be non-empty'); } if (badIndex == packageName.length) { throw PackageConfigArgumentError(packageUri, name, @@ -89,13 +89,13 @@ String checkValidPackageUri(Uri packageUri, String name) { } assert(badIndex < packageName.length); var badCharCode = packageName.codeUnitAt(badIndex); - var badChar = "U+" + badCharCode.toRadixString(16).padLeft(4, '0'); + var badChar = 'U+' + badCharCode.toRadixString(16).padLeft(4, '0'); if (badCharCode >= 0x20 && badCharCode <= 0x7e) { // Printable character. badChar = "'${packageName[badIndex]}' ($badChar)"; } throw PackageConfigArgumentError( - packageUri, name, "Package names must not contain $badChar"); + packageUri, name, 'Package names must not contain $badChar'); } return packageName; } @@ -110,7 +110,7 @@ bool isAbsoluteDirectoryUri(Uri uri) { if (uri.hasFragment) return false; if (!uri.hasScheme) return false; var path = uri.path; - if (!path.endsWith("/")) return false; + if (!path.endsWith('/')) return false; return true; } @@ -139,8 +139,8 @@ int firstNonWhitespaceChar(List bytes) { /// Appends a trailing `/` if the path doesn't end with one. String trailingSlash(String path) { - if (path.isEmpty || path.endsWith("/")) return path; - return path + "/"; + if (path.isEmpty || path.endsWith('/')) return path; + return path + '/'; } /// Whether a URI should not be considered relative to the base URI. @@ -212,15 +212,15 @@ Uri? relativizeUri(Uri? uri, Uri? baseUri) { } if (index == base.length) { if (index == target.length) { - return Uri(path: "./"); + return Uri(path: './'); } return Uri(path: target.skip(index).join('/')); } else if (index > 0) { var buffer = StringBuffer(); for (var n = base.length - index; n > 0; --n) { - buffer.write("../"); + buffer.write('../'); } - buffer.writeAll(target.skip(index), "/"); + buffer.writeAll(target.skip(index), '/'); return Uri(path: buffer.toString()); } else { return uri; diff --git a/pkgs/package_config/lib/src/util_io.dart b/pkgs/package_config/lib/src/util_io.dart index 9c48f049e..914ea384e 100644 --- a/pkgs/package_config/lib/src/util_io.dart +++ b/pkgs/package_config/lib/src/util_io.dart @@ -10,7 +10,7 @@ import 'dart:io'; import 'dart:typed_data'; Future defaultLoader(Uri uri) async { - if (uri.isScheme("file")) { + if (uri.isScheme('file')) { var file = File.fromUri(uri); try { return await file.readAsBytes(); @@ -18,14 +18,14 @@ Future defaultLoader(Uri uri) async { return null; } } - if (uri.isScheme("http") || uri.isScheme("https")) { + if (uri.isScheme('http') || uri.isScheme('https')) { return _httpGet(uri); } - throw UnsupportedError("Default URI unsupported scheme: $uri"); + throw UnsupportedError('Default URI unsupported scheme: $uri'); } Future _httpGet(Uri uri) async { - assert(uri.isScheme("http") || uri.isScheme("https")); + assert(uri.isScheme('http') || uri.isScheme('https')); var client = HttpClient(); var request = await client.getUrl(uri); var response = await request.close(); @@ -72,7 +72,7 @@ String fileName(String path) { String dirName(String path) { var separator = Platform.pathSeparator; var lastSeparator = path.lastIndexOf(separator); - if (lastSeparator < 0) return ""; + if (lastSeparator < 0) return ''; return path.substring(0, lastSeparator); } @@ -82,12 +82,12 @@ String dirName(String path) { /// inserted. String pathJoin(String part1, String part2, [String? part3]) { var separator = Platform.pathSeparator; - var separator1 = part1.endsWith(separator) ? "" : separator; + var separator1 = part1.endsWith(separator) ? '' : separator; if (part3 == null) { - return "$part1$separator1$part2"; + return '$part1$separator1$part2'; } - var separator2 = part2.endsWith(separator) ? "" : separator; - return "$part1$separator1$part2$separator2$part3"; + var separator2 = part2.endsWith(separator) ? '' : separator; + return '$part1$separator1$part2$separator2$part3'; } /// Join an unknown number of path parts with [Platform.pathSeparator]. @@ -96,13 +96,13 @@ String pathJoin(String part1, String part2, [String? part3]) { /// inserted. String pathJoinAll(Iterable parts) { var buffer = StringBuffer(); - var separator = ""; + var separator = ''; for (var part in parts) { buffer ..write(separator) ..write(part); separator = - part.endsWith(Platform.pathSeparator) ? "" : Platform.pathSeparator; + part.endsWith(Platform.pathSeparator) ? '' : Platform.pathSeparator; } return buffer.toString(); } diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 1ee725098..687c3d303 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -10,8 +10,8 @@ dependencies: path: ^1.8.0 dev_dependencies: - build_runner: ^1.10.0 - build_test: ^1.3.0 - build_web_compilers: ^2.12.2 + build_runner: ^2.0.0 + build_test: ^2.1.2 + build_web_compilers: ^3.0.0 pedantic: ^1.10.0 test: ^1.16.0 diff --git a/pkgs/package_config/test/discovery_test.dart b/pkgs/package_config/test/discovery_test.dart index df2374d0b..d2c3d8330 100644 --- a/pkgs/package_config/test/discovery_test.dart +++ b/pkgs/package_config/test/discovery_test.dart @@ -5,21 +5,21 @@ @TestOn('vm') library package_config.discovery_test; -import "dart:io"; -import "package:test/test.dart"; -import "package:package_config/package_config.dart"; +import 'dart:io'; +import 'package:test/test.dart'; +import 'package:package_config/package_config.dart'; -import "src/util.dart"; -import "src/util_io.dart"; +import 'src/util.dart'; +import 'src/util_io.dart'; -const packagesFile = """ +const packagesFile = ''' # A comment foo:file:///dart/packages/foo/ bar:/dart/packages/bar/ baz:packages/baz/ -"""; +'''; -const packageConfigFile = """ +const packageConfigFile = ''' { "configVersion": 2, "packages": [ @@ -38,29 +38,29 @@ const packageConfigFile = """ ], "extra": [42] } -"""; +'''; void validatePackagesFile(PackageConfig resolver, Directory directory) { expect(resolver, isNotNull); - expect(resolver.resolve(pkg("foo", "bar/baz")), - equals(Uri.parse("file:///dart/packages/foo/bar/baz"))); - expect(resolver.resolve(pkg("bar", "baz/qux")), - equals(Uri.parse("file:///dart/packages/bar/baz/qux"))); - expect(resolver.resolve(pkg("baz", "qux/foo")), - equals(Uri.directory(directory.path).resolve("packages/baz/qux/foo"))); + expect(resolver.resolve(pkg('foo', 'bar/baz')), + equals(Uri.parse('file:///dart/packages/foo/bar/baz'))); + expect(resolver.resolve(pkg('bar', 'baz/qux')), + equals(Uri.parse('file:///dart/packages/bar/baz/qux'))); + expect(resolver.resolve(pkg('baz', 'qux/foo')), + equals(Uri.directory(directory.path).resolve('packages/baz/qux/foo'))); expect([for (var p in resolver.packages) p.name], - unorderedEquals(["foo", "bar", "baz"])); + unorderedEquals(['foo', 'bar', 'baz'])); } void main() { - group("findPackages", () { + group('findPackages', () { // Finds package_config.json if there. - fileTest("package_config.json", { - ".packages": "invalid .packages file", - "script.dart": "main(){}", - "packages": {"shouldNotBeFound": {}}, - ".dart_tool": { - "package_config.json": packageConfigFile, + fileTest('package_config.json', { + '.packages': 'invalid .packages file', + 'script.dart': 'main(){}', + 'packages': {'shouldNotBeFound': {}}, + '.dart_tool': { + 'package_config.json': packageConfigFile, } }, (Directory directory) async { var config = (await findPackageConfig(directory))!; @@ -69,10 +69,10 @@ void main() { }); // Finds .packages if no package_config.json. - fileTest(".packages", { - ".packages": packagesFile, - "script.dart": "main(){}", - "packages": {"shouldNotBeFound": {}} + fileTest('.packages', { + '.packages': packagesFile, + 'script.dart': 'main(){}', + 'packages': {'shouldNotBeFound': {}} }, (Directory directory) async { var config = (await findPackageConfig(directory))!; expect(config.version, 1); // Found .packages file. @@ -80,68 +80,68 @@ void main() { }); // Finds package_config.json in super-directory. - fileTest("package_config.json recursive", { - ".packages": packagesFile, - ".dart_tool": { - "package_config.json": packageConfigFile, + fileTest('package_config.json recursive', { + '.packages': packagesFile, + '.dart_tool': { + 'package_config.json': packageConfigFile, }, - "subdir": { - "script.dart": "main(){}", + 'subdir': { + 'script.dart': 'main(){}', } }, (Directory directory) async { - var config = (await findPackageConfig(subdir(directory, "subdir/")))!; + var config = (await findPackageConfig(subdir(directory, 'subdir/')))!; expect(config.version, 2); validatePackagesFile(config, directory); }); // Finds .packages in super-directory. - fileTest(".packages recursive", { - ".packages": packagesFile, - "subdir": {"script.dart": "main(){}"} + fileTest('.packages recursive', { + '.packages': packagesFile, + 'subdir': {'script.dart': 'main(){}'} }, (Directory directory) async { var config; - config = await findPackageConfig(subdir(directory, "subdir/")); + config = await findPackageConfig(subdir(directory, 'subdir/')); expect(config.version, 1); validatePackagesFile(config, directory); }); // Does not find a packages/ directory, and returns null if nothing found. - fileTest("package directory packages not supported", { - "packages": { - "foo": {}, + fileTest('package directory packages not supported', { + 'packages': { + 'foo': {}, } }, (Directory directory) async { var config = await findPackageConfig(directory); expect(config, null); }); - group("throws", () { - fileTest("invalid .packages", { - ".packages": "not a .packages file", + group('throws', () { + fileTest('invalid .packages', { + '.packages': 'not a .packages file', }, (Directory directory) { expect(findPackageConfig(directory), throwsA(TypeMatcher())); }); - fileTest("invalid .packages as JSON", { - ".packages": packageConfigFile, + fileTest('invalid .packages as JSON', { + '.packages': packageConfigFile, }, (Directory directory) { expect(findPackageConfig(directory), throwsA(TypeMatcher())); }); - fileTest("invalid .packages", { - ".dart_tool": { - "package_config.json": "not a JSON file", + fileTest('invalid .packages', { + '.dart_tool': { + 'package_config.json': 'not a JSON file', } }, (Directory directory) { expect(findPackageConfig(directory), throwsA(TypeMatcher())); }); - fileTest("invalid .packages as INI", { - ".dart_tool": { - "package_config.json": packagesFile, + fileTest('invalid .packages as INI', { + '.dart_tool': { + 'package_config.json': packagesFile, } }, (Directory directory) { expect(findPackageConfig(directory), @@ -149,9 +149,9 @@ void main() { }); }); - group("handles error", () { - fileTest("invalid .packages", { - ".packages": "not a .packages file", + group('handles error', () { + fileTest('invalid .packages', { + '.packages': 'not a .packages file', }, (Directory directory) async { var hadError = false; await findPackageConfig(directory, @@ -162,8 +162,8 @@ void main() { expect(hadError, true); }); - fileTest("invalid .packages as JSON", { - ".packages": packageConfigFile, + fileTest('invalid .packages as JSON', { + '.packages': packageConfigFile, }, (Directory directory) async { var hadError = false; await findPackageConfig(directory, @@ -174,9 +174,9 @@ void main() { expect(hadError, true); }); - fileTest("invalid package_config not JSON", { - ".dart_tool": { - "package_config.json": "not a JSON file", + fileTest('invalid package_config not JSON', { + '.dart_tool': { + 'package_config.json': 'not a JSON file', } }, (Directory directory) async { var hadError = false; @@ -188,9 +188,9 @@ void main() { expect(hadError, true); }); - fileTest("invalid package config as INI", { - ".dart_tool": { - "package_config.json": packagesFile, + fileTest('invalid package config as INI', { + '.dart_tool': { + 'package_config.json': packagesFile, } }, (Directory directory) async { var hadError = false; @@ -204,86 +204,86 @@ void main() { }); }); - group("loadPackageConfig", () { + group('loadPackageConfig', () { // Load a specific files - group("package_config.json", () { + group('package_config.json', () { var files = { - ".packages": packagesFile, - ".dart_tool": { - "package_config.json": packageConfigFile, + '.packages': packagesFile, + '.dart_tool': { + 'package_config.json': packageConfigFile, }, }; - fileTest("directly", files, (Directory directory) async { + fileTest('directly', files, (Directory directory) async { var file = - dirFile(subdir(directory, ".dart_tool"), "package_config.json"); + dirFile(subdir(directory, '.dart_tool'), 'package_config.json'); var config = await loadPackageConfig(file); expect(config.version, 2); validatePackagesFile(config, directory); }); - fileTest("indirectly through .packages", files, + fileTest('indirectly through .packages', files, (Directory directory) async { - var file = dirFile(directory, ".packages"); + var file = dirFile(directory, '.packages'); var config = await loadPackageConfig(file); expect(config.version, 2); validatePackagesFile(config, directory); }); - fileTest("prefer .packages", files, (Directory directory) async { - var file = dirFile(directory, ".packages"); + fileTest('prefer .packages', files, (Directory directory) async { + var file = dirFile(directory, '.packages'); var config = await loadPackageConfig(file, preferNewest: false); expect(config.version, 1); validatePackagesFile(config, directory); }); }); - fileTest("package_config.json non-default name", { - ".packages": packagesFile, - "subdir": { - "pheldagriff": packageConfigFile, + fileTest('package_config.json non-default name', { + '.packages': packagesFile, + 'subdir': { + 'pheldagriff': packageConfigFile, }, }, (Directory directory) async { - var file = dirFile(directory, "subdir/pheldagriff"); + var file = dirFile(directory, 'subdir/pheldagriff'); var config = await loadPackageConfig(file); expect(config.version, 2); validatePackagesFile(config, directory); }); - fileTest("package_config.json named .packages", { - "subdir": { - ".packages": packageConfigFile, + fileTest('package_config.json named .packages', { + 'subdir': { + '.packages': packageConfigFile, }, }, (Directory directory) async { - var file = dirFile(directory, "subdir/.packages"); + var file = dirFile(directory, 'subdir/.packages'); var config = await loadPackageConfig(file); expect(config.version, 2); validatePackagesFile(config, directory); }); - fileTest(".packages", { - ".packages": packagesFile, + fileTest('.packages', { + '.packages': packagesFile, }, (Directory directory) async { - var file = dirFile(directory, ".packages"); + var file = dirFile(directory, '.packages'); var config = await loadPackageConfig(file); expect(config.version, 1); validatePackagesFile(config, directory); }); - fileTest(".packages non-default name", { - "pheldagriff": packagesFile, + fileTest('.packages non-default name', { + 'pheldagriff': packagesFile, }, (Directory directory) async { - var file = dirFile(directory, "pheldagriff"); + var file = dirFile(directory, 'pheldagriff'); var config = await loadPackageConfig(file); expect(config.version, 1); validatePackagesFile(config, directory); }); - fileTest("no config found", {}, (Directory directory) { - var file = dirFile(directory, "anyname"); + fileTest('no config found', {}, (Directory directory) { + var file = dirFile(directory, 'anyname'); expect(() => loadPackageConfig(file), throwsA(TypeMatcher())); }); - fileTest("no config found, handled", {}, (Directory directory) async { - var file = dirFile(directory, "anyname"); + fileTest('no config found, handled', {}, (Directory directory) async { + var file = dirFile(directory, 'anyname'); var hadError = false; await loadPackageConfig(file, onError: expectAsync1((error) { @@ -293,31 +293,31 @@ void main() { expect(hadError, true); }); - fileTest("specified file syntax error", { - "anyname": "syntax error", + fileTest('specified file syntax error', { + 'anyname': 'syntax error', }, (Directory directory) { - var file = dirFile(directory, "anyname"); + var file = dirFile(directory, 'anyname'); expect(() => loadPackageConfig(file), throwsFormatException); }); // Find package_config.json in subdir even if initial file syntax error. - fileTest("specified file syntax onError", { - ".packages": "syntax error", - ".dart_tool": { - "package_config.json": packageConfigFile, + fileTest('specified file syntax onError', { + '.packages': 'syntax error', + '.dart_tool': { + 'package_config.json': packageConfigFile, }, }, (Directory directory) async { - var file = dirFile(directory, ".packages"); + var file = dirFile(directory, '.packages'); var config = await loadPackageConfig(file); expect(config.version, 2); validatePackagesFile(config, directory); }); // A file starting with `{` is a package_config.json file. - fileTest("file syntax error with {", { - ".packages": "{syntax error", + fileTest('file syntax error with {', { + '.packages': '{syntax error', }, (Directory directory) { - var file = dirFile(directory, ".packages"); + var file = dirFile(directory, '.packages'); expect(() => loadPackageConfig(file), throwsFormatException); }); }); diff --git a/pkgs/package_config/test/discovery_uri_test.dart b/pkgs/package_config/test/discovery_uri_test.dart index a89527918..0a9b91720 100644 --- a/pkgs/package_config/test/discovery_uri_test.dart +++ b/pkgs/package_config/test/discovery_uri_test.dart @@ -5,19 +5,19 @@ @TestOn('vm') library package_config.discovery_test; -import "package:test/test.dart"; -import "package:package_config/package_config.dart"; +import 'package:test/test.dart'; +import 'package:package_config/package_config.dart'; -import "src/util.dart"; +import 'src/util.dart'; -const packagesFile = """ +const packagesFile = ''' # A comment foo:file:///dart/packages/foo/ bar:/dart/packages/bar/ baz:packages/baz/ -"""; +'''; -const packageConfigFile = """ +const packageConfigFile = ''' { "configVersion": 2, "packages": [ @@ -36,29 +36,29 @@ const packageConfigFile = """ ], "extra": [42] } -"""; +'''; void validatePackagesFile(PackageConfig resolver, Uri directory) { expect(resolver, isNotNull); - expect(resolver.resolve(pkg("foo", "bar/baz")), - equals(Uri.parse("file:///dart/packages/foo/bar/baz"))); - expect(resolver.resolve(pkg("bar", "baz/qux")), - equals(directory.resolve("/dart/packages/bar/baz/qux"))); - expect(resolver.resolve(pkg("baz", "qux/foo")), - equals(directory.resolve("packages/baz/qux/foo"))); + expect(resolver.resolve(pkg('foo', 'bar/baz')), + equals(Uri.parse('file:///dart/packages/foo/bar/baz'))); + expect(resolver.resolve(pkg('bar', 'baz/qux')), + equals(directory.resolve('/dart/packages/bar/baz/qux'))); + expect(resolver.resolve(pkg('baz', 'qux/foo')), + equals(directory.resolve('packages/baz/qux/foo'))); expect([for (var p in resolver.packages) p.name], - unorderedEquals(["foo", "bar", "baz"])); + unorderedEquals(['foo', 'bar', 'baz'])); } void main() { - group("findPackages", () { + group('findPackages', () { // Finds package_config.json if there. - loaderTest("package_config.json", { - ".packages": "invalid .packages file", - "script.dart": "main(){}", - "packages": {"shouldNotBeFound": {}}, - ".dart_tool": { - "package_config.json": packageConfigFile, + loaderTest('package_config.json', { + '.packages': 'invalid .packages file', + 'script.dart': 'main(){}', + 'packages': {'shouldNotBeFound': {}}, + '.dart_tool': { + 'package_config.json': packageConfigFile, } }, (directory, loader) async { var config = (await findPackageConfigUri(directory, loader: loader))!; @@ -67,10 +67,10 @@ void main() { }); // Finds .packages if no package_config.json. - loaderTest(".packages", { - ".packages": packagesFile, - "script.dart": "main(){}", - "packages": {"shouldNotBeFound": {}} + loaderTest('.packages', { + '.packages': packagesFile, + 'script.dart': 'main(){}', + 'packages': {'shouldNotBeFound': {}} }, (directory, loader) async { var config = (await findPackageConfigUri(directory, loader: loader))!; expect(config.version, 1); // Found .packages file. @@ -78,69 +78,69 @@ void main() { }); // Finds package_config.json in super-directory. - loaderTest("package_config.json recursive", { - ".packages": packagesFile, - ".dart_tool": { - "package_config.json": packageConfigFile, + loaderTest('package_config.json recursive', { + '.packages': packagesFile, + '.dart_tool': { + 'package_config.json': packageConfigFile, }, - "subdir": { - "script.dart": "main(){}", + 'subdir': { + 'script.dart': 'main(){}', } }, (directory, loader) async { - var config = (await findPackageConfigUri(directory.resolve("subdir/"), + var config = (await findPackageConfigUri(directory.resolve('subdir/'), loader: loader))!; expect(config.version, 2); validatePackagesFile(config, directory); }); // Finds .packages in super-directory. - loaderTest(".packages recursive", { - ".packages": packagesFile, - "subdir": {"script.dart": "main(){}"} + loaderTest('.packages recursive', { + '.packages': packagesFile, + 'subdir': {'script.dart': 'main(){}'} }, (directory, loader) async { var config; - config = await findPackageConfigUri(directory.resolve("subdir/"), + config = await findPackageConfigUri(directory.resolve('subdir/'), loader: loader); expect(config.version, 1); validatePackagesFile(config, directory); }); // Does not find a packages/ directory, and returns null if nothing found. - loaderTest("package directory packages not supported", { - "packages": { - "foo": {}, + loaderTest('package directory packages not supported', { + 'packages': { + 'foo': {}, } }, (Uri directory, loader) async { var config = await findPackageConfigUri(directory, loader: loader); expect(config, null); }); - loaderTest("invalid .packages", { - ".packages": "not a .packages file", + loaderTest('invalid .packages', { + '.packages': 'not a .packages file', }, (Uri directory, loader) { expect(() => findPackageConfigUri(directory, loader: loader), throwsA(TypeMatcher())); }); - loaderTest("invalid .packages as JSON", { - ".packages": packageConfigFile, + loaderTest('invalid .packages as JSON', { + '.packages': packageConfigFile, }, (Uri directory, loader) { expect(() => findPackageConfigUri(directory, loader: loader), throwsA(TypeMatcher())); }); - loaderTest("invalid .packages", { - ".dart_tool": { - "package_config.json": "not a JSON file", + loaderTest('invalid .packages', { + '.dart_tool': { + 'package_config.json': 'not a JSON file', } }, (Uri directory, loader) { expect(() => findPackageConfigUri(directory, loader: loader), throwsA(TypeMatcher())); }); - loaderTest("invalid .packages as INI", { - ".dart_tool": { - "package_config.json": packagesFile, + loaderTest('invalid .packages as INI', { + '.dart_tool': { + 'package_config.json': packagesFile, } }, (Uri directory, loader) { expect(() => findPackageConfigUri(directory, loader: loader), @@ -148,80 +148,80 @@ void main() { }); }); - group("loadPackageConfig", () { + group('loadPackageConfig', () { // Load a specific files - group("package_config.json", () { + group('package_config.json', () { var files = { - ".packages": packagesFile, - ".dart_tool": { - "package_config.json": packageConfigFile, + '.packages': packagesFile, + '.dart_tool': { + 'package_config.json': packageConfigFile, }, }; - loaderTest("directly", files, (Uri directory, loader) async { - var file = directory.resolve(".dart_tool/package_config.json"); + loaderTest('directly', files, (Uri directory, loader) async { + var file = directory.resolve('.dart_tool/package_config.json'); var config = await loadPackageConfigUri(file, loader: loader); expect(config.version, 2); validatePackagesFile(config, directory); }); - loaderTest("indirectly through .packages", files, + loaderTest('indirectly through .packages', files, (Uri directory, loader) async { - var file = directory.resolve(".packages"); + var file = directory.resolve('.packages'); var config = await loadPackageConfigUri(file, loader: loader); expect(config.version, 2); validatePackagesFile(config, directory); }); }); - loaderTest("package_config.json non-default name", { - ".packages": packagesFile, - "subdir": { - "pheldagriff": packageConfigFile, + loaderTest('package_config.json non-default name', { + '.packages': packagesFile, + 'subdir': { + 'pheldagriff': packageConfigFile, }, }, (Uri directory, loader) async { - var file = directory.resolve("subdir/pheldagriff"); + var file = directory.resolve('subdir/pheldagriff'); var config = await loadPackageConfigUri(file, loader: loader); expect(config.version, 2); validatePackagesFile(config, directory); }); - loaderTest("package_config.json named .packages", { - "subdir": { - ".packages": packageConfigFile, + loaderTest('package_config.json named .packages', { + 'subdir': { + '.packages': packageConfigFile, }, }, (Uri directory, loader) async { - var file = directory.resolve("subdir/.packages"); + var file = directory.resolve('subdir/.packages'); var config = await loadPackageConfigUri(file, loader: loader); expect(config.version, 2); validatePackagesFile(config, directory); }); - loaderTest(".packages", { - ".packages": packagesFile, + loaderTest('.packages', { + '.packages': packagesFile, }, (Uri directory, loader) async { - var file = directory.resolve(".packages"); + var file = directory.resolve('.packages'); var config = await loadPackageConfigUri(file, loader: loader); expect(config.version, 1); validatePackagesFile(config, directory); }); - loaderTest(".packages non-default name", { - "pheldagriff": packagesFile, + loaderTest('.packages non-default name', { + 'pheldagriff': packagesFile, }, (Uri directory, loader) async { - var file = directory.resolve("pheldagriff"); + var file = directory.resolve('pheldagriff'); var config = await loadPackageConfigUri(file, loader: loader); expect(config.version, 1); validatePackagesFile(config, directory); }); - loaderTest("no config found", {}, (Uri directory, loader) { - var file = directory.resolve("anyname"); + loaderTest('no config found', {}, (Uri directory, loader) { + var file = directory.resolve('anyname'); expect(() => loadPackageConfigUri(file, loader: loader), throwsA(isA())); }); - loaderTest("no config found, handle error", {}, + loaderTest('no config found, handle error', {}, (Uri directory, loader) async { - var file = directory.resolve("anyname"); + var file = directory.resolve('anyname'); var hadError = false; await loadPackageConfigUri(file, loader: loader, @@ -232,18 +232,18 @@ void main() { expect(hadError, true); }); - loaderTest("specified file syntax error", { - "anyname": "syntax error", + loaderTest('specified file syntax error', { + 'anyname': 'syntax error', }, (Uri directory, loader) { - var file = directory.resolve("anyname"); + var file = directory.resolve('anyname'); expect(() => loadPackageConfigUri(file, loader: loader), throwsFormatException); }); - loaderTest("specified file syntax onError", { - "anyname": "syntax error", + loaderTest('specified file syntax onError', { + 'anyname': 'syntax error', }, (directory, loader) async { - var file = directory.resolve("anyname"); + var file = directory.resolve('anyname'); var hadError = false; await loadPackageConfigUri(file, loader: loader, @@ -255,22 +255,22 @@ void main() { }); // Don't look for package_config.json if original file not named .packages. - loaderTest("specified file syntax error with alternative", { - "anyname": "syntax error", - ".dart_tool": { - "package_config.json": packageConfigFile, + loaderTest('specified file syntax error with alternative', { + 'anyname': 'syntax error', + '.dart_tool': { + 'package_config.json': packageConfigFile, }, }, (directory, loader) async { - var file = directory.resolve("anyname"); + var file = directory.resolve('anyname'); expect(() => loadPackageConfigUri(file, loader: loader), throwsFormatException); }); // A file starting with `{` is a package_config.json file. - loaderTest("file syntax error with {", { - ".packages": "{syntax error", + loaderTest('file syntax error with {', { + '.packages': '{syntax error', }, (directory, loader) async { - var file = directory.resolve(".packages"); + var file = directory.resolve('.packages'); var hadError = false; await loadPackageConfigUri(file, loader: loader, diff --git a/pkgs/package_config/test/package_config_impl_test.dart b/pkgs/package_config/test/package_config_impl_test.dart index bb00d1210..cef121713 100644 --- a/pkgs/package_config/test/package_config_impl_test.dart +++ b/pkgs/package_config/test/package_config_impl_test.dart @@ -2,39 +2,39 @@ // 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. -import "dart:convert" show jsonDecode; +import 'dart:convert' show jsonDecode; -import "package:package_config/package_config_types.dart"; -import "package:test/test.dart"; -import "src/util.dart"; +import 'package:package_config/package_config_types.dart'; +import 'package:test/test.dart'; +import 'src/util.dart'; void main() { var unique = Object(); - var root = Uri.file("/tmp/root/"); + var root = Uri.file('/tmp/root/'); - group("LanguageVersion", () { - test("minimal", () { + group('LanguageVersion', () { + test('minimal', () { var version = LanguageVersion(3, 5); expect(version.major, 3); expect(version.minor, 5); }); - test("negative major", () { + test('negative major', () { expect(() => LanguageVersion(-1, 1), throwsArgumentError); }); - test("negative minor", () { + test('negative minor', () { expect(() => LanguageVersion(1, -1), throwsArgumentError); }); - test("minimal parse", () { - var version = LanguageVersion.parse("3.5"); + test('minimal parse', () { + var version = LanguageVersion.parse('3.5'); expect(version.major, 3); expect(version.minor, 5); }); void failParse(String name, String input) { - test("$name - error", () { + test('$name - error', () { expect(() => LanguageVersion.parse(input), throwsA(TypeMatcher())); expect(() => LanguageVersion.parse(input), throwsFormatException); @@ -47,37 +47,37 @@ void main() { }); } - failParse("Leading zero major", "01.1"); - failParse("Leading zero minor", "1.01"); - failParse("Sign+ major", "+1.1"); - failParse("Sign- major", "-1.1"); - failParse("Sign+ minor", "1.+1"); - failParse("Sign- minor", "1.-1"); - failParse("WhiteSpace 1", " 1.1"); - failParse("WhiteSpace 2", "1 .1"); - failParse("WhiteSpace 3", "1. 1"); - failParse("WhiteSpace 4", "1.1 "); + failParse('Leading zero major', '01.1'); + failParse('Leading zero minor', '1.01'); + failParse('Sign+ major', '+1.1'); + failParse('Sign- major', '-1.1'); + failParse('Sign+ minor', '1.+1'); + failParse('Sign- minor', '1.-1'); + failParse('WhiteSpace 1', ' 1.1'); + failParse('WhiteSpace 2', '1 .1'); + failParse('WhiteSpace 3', '1. 1'); + failParse('WhiteSpace 4', '1.1 '); }); - group("Package", () { - test("minimal", () { - var package = Package("name", root, extraData: unique); - expect(package.name, "name"); + group('Package', () { + test('minimal', () { + var package = Package('name', root, extraData: unique); + expect(package.name, 'name'); expect(package.root, root); expect(package.packageUriRoot, root); expect(package.languageVersion, null); expect(package.extraData, same(unique)); }); - test("absolute package root", () { + test('absolute package root', () { var version = LanguageVersion(1, 1); - var absolute = root.resolve("foo/bar/"); - var package = Package("name", root, + var absolute = root.resolve('foo/bar/'); + var package = Package('name', root, packageUriRoot: absolute, relativeRoot: false, languageVersion: version, extraData: unique); - expect(package.name, "name"); + expect(package.name, 'name'); expect(package.root, root); expect(package.packageUriRoot, absolute); expect(package.languageVersion, version); @@ -85,12 +85,12 @@ void main() { expect(package.relativeRoot, false); }); - test("relative package root", () { - var relative = Uri.parse("foo/bar/"); + test('relative package root', () { + var relative = Uri.parse('foo/bar/'); var absolute = root.resolveUri(relative); - var package = Package("name", root, + var package = Package('name', root, packageUriRoot: relative, relativeRoot: true, extraData: unique); - expect(package.name, "name"); + expect(package.name, 'name'); expect(package.root, root); expect(package.packageUriRoot, absolute); expect(package.relativeRoot, true); @@ -98,89 +98,89 @@ void main() { expect(package.extraData, same(unique)); }); - for (var badName in ["a/z", "a:z", "", "..."]) { + for (var badName in ['a/z', 'a:z', '', '...']) { test("Invalid name '$badName'", () { expect(() => Package(badName, root), throwsPackageConfigError); }); } - test("Invalid root, not absolute", () { + test('Invalid root, not absolute', () { expect( - () => Package("name", Uri.parse("/foo/")), throwsPackageConfigError); + () => Package('name', Uri.parse('/foo/')), throwsPackageConfigError); }); - test("Invalid root, not ending in slash", () { - expect(() => Package("name", Uri.parse("file:///foo")), + test('Invalid root, not ending in slash', () { + expect(() => Package('name', Uri.parse('file:///foo')), throwsPackageConfigError); }); - test("invalid package root, not ending in slash", () { - expect(() => Package("name", root, packageUriRoot: Uri.parse("foo")), + test('invalid package root, not ending in slash', () { + expect(() => Package('name', root, packageUriRoot: Uri.parse('foo')), throwsPackageConfigError); }); - test("invalid package root, not inside root", () { - expect(() => Package("name", root, packageUriRoot: Uri.parse("../baz/")), + test('invalid package root, not inside root', () { + expect(() => Package('name', root, packageUriRoot: Uri.parse('../baz/')), throwsPackageConfigError); }); }); - group("package config", () { - test("emtpy", () { + group('package config', () { + test('emtpy', () { var empty = PackageConfig([], extraData: unique); expect(empty.version, 2); expect(empty.packages, isEmpty); expect(empty.extraData, same(unique)); - expect(empty.resolve(pkg("a", "b")), isNull); + expect(empty.resolve(pkg('a', 'b')), isNull); }); - test("single", () { - var package = Package("name", root); + test('single', () { + var package = Package('name', root); var single = PackageConfig([package], extraData: unique); expect(single.version, 2); expect(single.packages, hasLength(1)); expect(single.extraData, same(unique)); - expect(single.resolve(pkg("a", "b")), isNull); - var resolved = single.resolve(pkg("name", "a/b")); - expect(resolved, root.resolve("a/b")); + expect(single.resolve(pkg('a', 'b')), isNull); + var resolved = single.resolve(pkg('name', 'a/b')); + expect(resolved, root.resolve('a/b')); }); }); - test("writeString", () { + test('writeString', () { var config = PackageConfig([ - Package("foo", Uri.parse("file:///pkg/foo/"), - packageUriRoot: Uri.parse("file:///pkg/foo/lib/"), + Package('foo', Uri.parse('file:///pkg/foo/'), + packageUriRoot: Uri.parse('file:///pkg/foo/lib/'), relativeRoot: false, languageVersion: LanguageVersion(2, 4), - extraData: {"foo": "foo!"}), - Package("bar", Uri.parse("file:///pkg/bar/"), - packageUriRoot: Uri.parse("file:///pkg/bar/lib/"), + extraData: {'foo': 'foo!'}), + Package('bar', Uri.parse('file:///pkg/bar/'), + packageUriRoot: Uri.parse('file:///pkg/bar/lib/'), relativeRoot: true, - extraData: {"bar": "bar!"}), + extraData: {'bar': 'bar!'}), ], extraData: { - "extra": "data" + 'extra': 'data' }); var buffer = StringBuffer(); - PackageConfig.writeString(config, buffer, Uri.parse("file:///pkg/")); + PackageConfig.writeString(config, buffer, Uri.parse('file:///pkg/')); var text = buffer.toString(); var json = jsonDecode(text); // Is valid JSON. expect(json, { - "configVersion": 2, - "packages": unorderedEquals([ + 'configVersion': 2, + 'packages': unorderedEquals([ { - "name": "foo", - "rootUri": "file:///pkg/foo/", - "packageUri": "lib/", - "languageVersion": "2.4", - "foo": "foo!", + 'name': 'foo', + 'rootUri': 'file:///pkg/foo/', + 'packageUri': 'lib/', + 'languageVersion': '2.4', + 'foo': 'foo!', }, { - "name": "bar", - "rootUri": "bar/", - "packageUri": "lib/", - "bar": "bar!", + 'name': 'bar', + 'rootUri': 'bar/', + 'packageUri': 'lib/', + 'bar': 'bar!', }, ]), - "extra": "data", + 'extra': 'data', }); }); } diff --git a/pkgs/package_config/test/parse_test.dart b/pkgs/package_config/test/parse_test.dart index ef73c2e1e..a163e127f 100644 --- a/pkgs/package_config/test/parse_test.dart +++ b/pkgs/package_config/test/parse_test.dart @@ -2,61 +2,61 @@ // 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. -import "dart:convert"; +import 'dart:convert'; import 'dart:typed_data'; -import "package:test/test.dart"; +import 'package:test/test.dart'; -import "package:package_config/package_config_types.dart"; -import "package:package_config/src/packages_file.dart" as packages; -import "package:package_config/src/package_config_json.dart"; -import "src/util.dart"; +import 'package:package_config/package_config_types.dart'; +import 'package:package_config/src/packages_file.dart' as packages; +import 'package:package_config/src/package_config_json.dart'; +import 'src/util.dart'; void throwError(Object error) => throw error; void main() { - group(".packages", () { - test("valid", () { - var packagesFile = "# Generated by pub yadda yadda\n" - "foo:file:///foo/lib/\n" - "bar:/bar/lib/\n" - "baz:lib/\n"; + group('.packages', () { + test('valid', () { + var packagesFile = '# Generated by pub yadda yadda\n' + 'foo:file:///foo/lib/\n' + 'bar:/bar/lib/\n' + 'baz:lib/\n'; var result = packages.parse(utf8.encode(packagesFile), - Uri.parse("file:///tmp/file.dart"), throwError); + Uri.parse('file:///tmp/file.dart'), throwError); expect(result.version, 1); - expect({for (var p in result.packages) p.name}, {"foo", "bar", "baz"}); - expect(result.resolve(pkg("foo", "foo.dart")), - Uri.parse("file:///foo/lib/foo.dart")); - expect(result.resolve(pkg("bar", "bar.dart")), - Uri.parse("file:///bar/lib/bar.dart")); - expect(result.resolve(pkg("baz", "baz.dart")), - Uri.parse("file:///tmp/lib/baz.dart")); + expect({for (var p in result.packages) p.name}, {'foo', 'bar', 'baz'}); + expect(result.resolve(pkg('foo', 'foo.dart')), + Uri.parse('file:///foo/lib/foo.dart')); + expect(result.resolve(pkg('bar', 'bar.dart')), + Uri.parse('file:///bar/lib/bar.dart')); + expect(result.resolve(pkg('baz', 'baz.dart')), + Uri.parse('file:///tmp/lib/baz.dart')); - var foo = result["foo"]!; + var foo = result['foo']!; expect(foo, isNotNull); - expect(foo.root, Uri.parse("file:///foo/")); - expect(foo.packageUriRoot, Uri.parse("file:///foo/lib/")); + expect(foo.root, Uri.parse('file:///foo/')); + expect(foo.packageUriRoot, Uri.parse('file:///foo/lib/')); expect(foo.languageVersion, LanguageVersion(2, 7)); expect(foo.relativeRoot, false); }); - test("valid empty", () { - var packagesFile = "# Generated by pub yadda yadda\n"; + test('valid empty', () { + var packagesFile = '# Generated by pub yadda yadda\n'; var result = packages.parse( - utf8.encode(packagesFile), Uri.file("/tmp/file.dart"), throwError); + utf8.encode(packagesFile), Uri.file('/tmp/file.dart'), throwError); expect(result.version, 1); expect({for (var p in result.packages) p.name}, {}); }); - group("invalid", () { - var baseFile = Uri.file("/tmp/file.dart"); + group('invalid', () { + var baseFile = Uri.file('/tmp/file.dart'); void testThrows(String name, String content) { test(name, () { expect( () => packages.parse(utf8.encode(content), baseFile, throwError), throwsA(TypeMatcher())); }); - test(name + ", handle error", () { + test(name + ', handle error', () { var hadError = false; packages.parse(utf8.encode(content), baseFile, (error) { hadError = true; @@ -66,21 +66,21 @@ void main() { }); } - testThrows("repeated package name", "foo:lib/\nfoo:lib\n"); - testThrows("no colon", "foo\n"); - testThrows("empty package name", ":lib/\n"); - testThrows("dot only package name", ".:lib/\n"); - testThrows("dot only package name", "..:lib/\n"); - testThrows("invalid package name character", "f\\o:lib/\n"); - testThrows("package URI", "foo:package:bar/lib/"); - testThrows("location with query", "f\\o:lib/?\n"); - testThrows("location with fragment", "f\\o:lib/#\n"); + testThrows('repeated package name', 'foo:lib/\nfoo:lib\n'); + testThrows('no colon', 'foo\n'); + testThrows('empty package name', ':lib/\n'); + testThrows('dot only package name', '.:lib/\n'); + testThrows('dot only package name', '..:lib/\n'); + testThrows('invalid package name character', 'f\\o:lib/\n'); + testThrows('package URI', 'foo:package:bar/lib/'); + testThrows('location with query', 'f\\o:lib/?\n'); + testThrows('location with fragment', 'f\\o:lib/#\n'); }); }); - group("package_config.json", () { - test("valid", () { - var packageConfigFile = """ + group('package_config.json', () { + test('valid', () { + var packageConfigFile = ''' { "configVersion": 2, "packages": [ @@ -111,62 +111,62 @@ void main() { "generator": "pub", "other": [42] } - """; + '''; var config = parsePackageConfigBytes( utf8.encode(packageConfigFile) as Uint8List, - Uri.parse("file:///tmp/.dart_tool/file.dart"), + Uri.parse('file:///tmp/.dart_tool/file.dart'), throwError); expect(config.version, 2); expect({for (var p in config.packages) p.name}, - {"foo", "bar", "baz", "noslash"}); + {'foo', 'bar', 'baz', 'noslash'}); - expect(config.resolve(pkg("foo", "foo.dart")), - Uri.parse("file:///foo/lib/foo.dart")); - expect(config.resolve(pkg("bar", "bar.dart")), - Uri.parse("file:///bar/lib/bar.dart")); - expect(config.resolve(pkg("baz", "baz.dart")), - Uri.parse("file:///tmp/lib/baz.dart")); + expect(config.resolve(pkg('foo', 'foo.dart')), + Uri.parse('file:///foo/lib/foo.dart')); + expect(config.resolve(pkg('bar', 'bar.dart')), + Uri.parse('file:///bar/lib/bar.dart')); + expect(config.resolve(pkg('baz', 'baz.dart')), + Uri.parse('file:///tmp/lib/baz.dart')); - var foo = config["foo"]!; + var foo = config['foo']!; expect(foo, isNotNull); - expect(foo.root, Uri.parse("file:///foo/")); - expect(foo.packageUriRoot, Uri.parse("file:///foo/lib/")); + expect(foo.root, Uri.parse('file:///foo/')); + expect(foo.packageUriRoot, Uri.parse('file:///foo/lib/')); expect(foo.languageVersion, LanguageVersion(2, 5)); - expect(foo.extraData, {"nonstandard": true}); + expect(foo.extraData, {'nonstandard': true}); expect(foo.relativeRoot, false); - var bar = config["bar"]!; + var bar = config['bar']!; expect(bar, isNotNull); - expect(bar.root, Uri.parse("file:///bar/")); - expect(bar.packageUriRoot, Uri.parse("file:///bar/lib/")); + expect(bar.root, Uri.parse('file:///bar/')); + expect(bar.packageUriRoot, Uri.parse('file:///bar/lib/')); expect(bar.languageVersion, LanguageVersion(9999, 9999)); expect(bar.extraData, null); expect(bar.relativeRoot, false); - var baz = config["baz"]!; + var baz = config['baz']!; expect(baz, isNotNull); - expect(baz.root, Uri.parse("file:///tmp/")); - expect(baz.packageUriRoot, Uri.parse("file:///tmp/lib/")); + expect(baz.root, Uri.parse('file:///tmp/')); + expect(baz.packageUriRoot, Uri.parse('file:///tmp/lib/')); expect(baz.languageVersion, null); expect(baz.relativeRoot, true); // No slash after root or package root. One is inserted. - var noslash = config["noslash"]!; + var noslash = config['noslash']!; expect(noslash, isNotNull); - expect(noslash.root, Uri.parse("file:///tmp/noslash/")); - expect(noslash.packageUriRoot, Uri.parse("file:///tmp/noslash/lib/")); + expect(noslash.root, Uri.parse('file:///tmp/noslash/')); + expect(noslash.packageUriRoot, Uri.parse('file:///tmp/noslash/lib/')); expect(noslash.languageVersion, null); expect(noslash.relativeRoot, true); expect(config.extraData, { - "generator": "pub", - "other": [42] + 'generator': 'pub', + 'other': [42] }); }); - test("valid other order", () { + test('valid other order', () { // The ordering in the file is not important. - var packageConfigFile = """ + var packageConfigFile = ''' { "generator": "pub", "other": [42], @@ -191,23 +191,23 @@ void main() { ], "configVersion": 2 } - """; + '''; var config = parsePackageConfigBytes( utf8.encode(packageConfigFile) as Uint8List, - Uri.parse("file:///tmp/.dart_tool/file.dart"), + Uri.parse('file:///tmp/.dart_tool/file.dart'), throwError); expect(config.version, 2); - expect({for (var p in config.packages) p.name}, {"foo", "bar", "baz"}); + expect({for (var p in config.packages) p.name}, {'foo', 'bar', 'baz'}); - expect(config.resolve(pkg("foo", "foo.dart")), - Uri.parse("file:///foo/lib/foo.dart")); - expect(config.resolve(pkg("bar", "bar.dart")), - Uri.parse("file:///bar/lib/bar.dart")); - expect(config.resolve(pkg("baz", "baz.dart")), - Uri.parse("file:///tmp/lib/baz.dart")); + expect(config.resolve(pkg('foo', 'foo.dart')), + Uri.parse('file:///foo/lib/foo.dart')); + expect(config.resolve(pkg('bar', 'bar.dart')), + Uri.parse('file:///bar/lib/bar.dart')); + expect(config.resolve(pkg('baz', 'baz.dart')), + Uri.parse('file:///tmp/lib/baz.dart')); expect(config.extraData, { - "generator": "pub", - "other": [42] + 'generator': 'pub', + 'other': [42] }); }); @@ -217,94 +217,94 @@ void main() { var pkgs = '"packages":[]'; var name = '"name":"foo"'; var root = '"rootUri":"/foo/"'; - test("minimal", () { + test('minimal', () { var config = parsePackageConfigBytes( - utf8.encode("{$cfg,$pkgs}") as Uint8List, - Uri.parse("file:///tmp/.dart_tool/file.dart"), + utf8.encode('{$cfg,$pkgs}') as Uint8List, + Uri.parse('file:///tmp/.dart_tool/file.dart'), throwError); expect(config.version, 2); expect(config.packages, isEmpty); }); - test("minimal package", () { + test('minimal package', () { // A package must have a name and a rootUri, the remaining properties // are optional. var config = parsePackageConfigBytes( utf8.encode('{$cfg,"packages":[{$name,$root}]}') as Uint8List, - Uri.parse("file:///tmp/.dart_tool/file.dart"), + Uri.parse('file:///tmp/.dart_tool/file.dart'), throwError); expect(config.version, 2); - expect(config.packages.first.name, "foo"); + expect(config.packages.first.name, 'foo'); }); - test("nested packages", () { + test('nested packages', () { var configBytes = utf8.encode(json.encode({ - "configVersion": 2, - "packages": [ - {"name": "foo", "rootUri": "/foo/", "packageUri": "lib/"}, - {"name": "bar", "rootUri": "/foo/bar/", "packageUri": "lib/"}, - {"name": "baz", "rootUri": "/foo/bar/baz/", "packageUri": "lib/"}, - {"name": "qux", "rootUri": "/foo/qux/", "packageUri": "lib/"}, + 'configVersion': 2, + 'packages': [ + {'name': 'foo', 'rootUri': '/foo/', 'packageUri': 'lib/'}, + {'name': 'bar', 'rootUri': '/foo/bar/', 'packageUri': 'lib/'}, + {'name': 'baz', 'rootUri': '/foo/bar/baz/', 'packageUri': 'lib/'}, + {'name': 'qux', 'rootUri': '/foo/qux/', 'packageUri': 'lib/'}, ] })); var config = parsePackageConfigBytes(configBytes as Uint8List, - Uri.parse("file:///tmp/.dart_tool/file.dart"), throwError); + Uri.parse('file:///tmp/.dart_tool/file.dart'), throwError); expect(config.version, 2); - expect(config.packageOf(Uri.parse("file:///foo/lala/lala.dart"))!.name, - "foo"); - expect(config.packageOf(Uri.parse("file:///foo/bar/lala.dart"))!.name, - "bar"); - expect(config.packageOf(Uri.parse("file:///foo/bar/baz/lala.dart"))!.name, - "baz"); - expect(config.packageOf(Uri.parse("file:///foo/qux/lala.dart"))!.name, - "qux"); - expect(config.toPackageUri(Uri.parse("file:///foo/lib/diz")), - Uri.parse("package:foo/diz")); - expect(config.toPackageUri(Uri.parse("file:///foo/bar/lib/diz")), - Uri.parse("package:bar/diz")); - expect(config.toPackageUri(Uri.parse("file:///foo/bar/baz/lib/diz")), - Uri.parse("package:baz/diz")); - expect(config.toPackageUri(Uri.parse("file:///foo/qux/lib/diz")), - Uri.parse("package:qux/diz")); + expect(config.packageOf(Uri.parse('file:///foo/lala/lala.dart'))!.name, + 'foo'); + expect(config.packageOf(Uri.parse('file:///foo/bar/lala.dart'))!.name, + 'bar'); + expect(config.packageOf(Uri.parse('file:///foo/bar/baz/lala.dart'))!.name, + 'baz'); + expect(config.packageOf(Uri.parse('file:///foo/qux/lala.dart'))!.name, + 'qux'); + expect(config.toPackageUri(Uri.parse('file:///foo/lib/diz')), + Uri.parse('package:foo/diz')); + expect(config.toPackageUri(Uri.parse('file:///foo/bar/lib/diz')), + Uri.parse('package:bar/diz')); + expect(config.toPackageUri(Uri.parse('file:///foo/bar/baz/lib/diz')), + Uri.parse('package:baz/diz')); + expect(config.toPackageUri(Uri.parse('file:///foo/qux/lib/diz')), + Uri.parse('package:qux/diz')); }); - group("invalid", () { + group('invalid', () { void testThrows(String name, String source) { test(name, () { expect( () => parsePackageConfigBytes(utf8.encode(source) as Uint8List, - Uri.parse("file:///tmp/.dart_tool/file.dart"), throwError), + Uri.parse('file:///tmp/.dart_tool/file.dart'), throwError), throwsA(TypeMatcher())); }); } - testThrows("comment", '# comment\n {$cfg,$pkgs}'); - testThrows(".packages file", 'foo:/foo\n'); - testThrows("no configVersion", '{$pkgs}'); - testThrows("no packages", '{$cfg}'); - group("config version:", () { - testThrows("null", '{"configVersion":null,$pkgs}'); - testThrows("string", '{"configVersion":"2",$pkgs}'); - testThrows("array", '{"configVersion":[2],$pkgs}'); + testThrows('comment', '# comment\n {$cfg,$pkgs}'); + testThrows('.packages file', 'foo:/foo\n'); + testThrows('no configVersion', '{$pkgs}'); + testThrows('no packages', '{$cfg}'); + group('config version:', () { + testThrows('null', '{"configVersion":null,$pkgs}'); + testThrows('string', '{"configVersion":"2",$pkgs}'); + testThrows('array', '{"configVersion":[2],$pkgs}'); }); - group("packages:", () { - testThrows("null", '{$cfg,"packages":null}'); - testThrows("string", '{$cfg,"packages":"foo"}'); - testThrows("object", '{$cfg,"packages":{}}'); + group('packages:', () { + testThrows('null', '{$cfg,"packages":null}'); + testThrows('string', '{$cfg,"packages":"foo"}'); + testThrows('object', '{$cfg,"packages":{}}'); }); - group("packages entry:", () { - testThrows("null", '{$cfg,"packages":[null]}'); - testThrows("string", '{$cfg,"packages":["foo"]}'); - testThrows("array", '{$cfg,"packages":[[]]}'); + group('packages entry:', () { + testThrows('null', '{$cfg,"packages":[null]}'); + testThrows('string', '{$cfg,"packages":["foo"]}'); + testThrows('array', '{$cfg,"packages":[[]]}'); }); - group("package", () { - testThrows("no name", '{$cfg,"packages":[{$root}]}'); - group("name:", () { - testThrows("null", '{$cfg,"packages":[{"name":null,$root}]}'); - testThrows("num", '{$cfg,"packages":[{"name":1,$root}]}'); - testThrows("object", '{$cfg,"packages":[{"name":{},$root}]}'); - testThrows("empty", '{$cfg,"packages":[{"name":"",$root}]}'); - testThrows("one-dot", '{$cfg,"packages":[{"name":".",$root}]}'); - testThrows("two-dot", '{$cfg,"packages":[{"name":"..",$root}]}'); + group('package', () { + testThrows('no name', '{$cfg,"packages":[{$root}]}'); + group('name:', () { + testThrows('null', '{$cfg,"packages":[{"name":null,$root}]}'); + testThrows('num', '{$cfg,"packages":[{"name":1,$root}]}'); + testThrows('object', '{$cfg,"packages":[{"name":{},$root}]}'); + testThrows('empty', '{$cfg,"packages":[{"name":"",$root}]}'); + testThrows('one-dot', '{$cfg,"packages":[{"name":".",$root}]}'); + testThrows('two-dot', '{$cfg,"packages":[{"name":"..",$root}]}'); testThrows( "invalid char '\\'", '{$cfg,"packages":[{"name":"\\",$root}]}'); testThrows( @@ -313,82 +313,82 @@ void main() { "invalid char ' '", '{$cfg,"packages":[{"name":" ",$root}]}'); }); - testThrows("no root", '{$cfg,"packages":[{$name}]}'); - group("root:", () { - testThrows("null", '{$cfg,"packages":[{$name,"rootUri":null}]}'); - testThrows("num", '{$cfg,"packages":[{$name,"rootUri":1}]}'); - testThrows("object", '{$cfg,"packages":[{$name,"rootUri":{}}]}'); - testThrows("fragment", '{$cfg,"packages":[{$name,"rootUri":"x/#"}]}'); - testThrows("query", '{$cfg,"packages":[{$name,"rootUri":"x/?"}]}'); - testThrows("package-URI", + testThrows('no root', '{$cfg,"packages":[{$name}]}'); + group('root:', () { + testThrows('null', '{$cfg,"packages":[{$name,"rootUri":null}]}'); + testThrows('num', '{$cfg,"packages":[{$name,"rootUri":1}]}'); + testThrows('object', '{$cfg,"packages":[{$name,"rootUri":{}}]}'); + testThrows('fragment', '{$cfg,"packages":[{$name,"rootUri":"x/#"}]}'); + testThrows('query', '{$cfg,"packages":[{$name,"rootUri":"x/?"}]}'); + testThrows('package-URI', '{$cfg,"packages":[{$name,"rootUri":"package:x/x/"}]}'); }); - group("package-URI root:", () { + group('package-URI root:', () { testThrows( - "null", '{$cfg,"packages":[{$name,$root,"packageUri":null}]}'); - testThrows("num", '{$cfg,"packages":[{$name,$root,"packageUri":1}]}'); + 'null', '{$cfg,"packages":[{$name,$root,"packageUri":null}]}'); + testThrows('num', '{$cfg,"packages":[{$name,$root,"packageUri":1}]}'); testThrows( - "object", '{$cfg,"packages":[{$name,$root,"packageUri":{}}]}'); - testThrows("fragment", + 'object', '{$cfg,"packages":[{$name,$root,"packageUri":{}}]}'); + testThrows('fragment', '{$cfg,"packages":[{$name,$root,"packageUri":"x/#"}]}'); testThrows( - "query", '{$cfg,"packages":[{$name,$root,"packageUri":"x/?"}]}'); - testThrows("package: URI", + 'query', '{$cfg,"packages":[{$name,$root,"packageUri":"x/?"}]}'); + testThrows('package: URI', '{$cfg,"packages":[{$name,$root,"packageUri":"package:x/x/"}]}'); - testThrows("not inside root", + testThrows('not inside root', '{$cfg,"packages":[{$name,$root,"packageUri":"../other/"}]}'); }); - group("language version", () { - testThrows("null", + group('language version', () { + testThrows('null', '{$cfg,"packages":[{$name,$root,"languageVersion":null}]}'); testThrows( - "num", '{$cfg,"packages":[{$name,$root,"languageVersion":1}]}'); - testThrows("object", + 'num', '{$cfg,"packages":[{$name,$root,"languageVersion":1}]}'); + testThrows('object', '{$cfg,"packages":[{$name,$root,"languageVersion":{}}]}'); - testThrows("empty", + testThrows('empty', '{$cfg,"packages":[{$name,$root,"languageVersion":""}]}'); - testThrows("non number.number", + testThrows('non number.number', '{$cfg,"packages":[{$name,$root,"languageVersion":"x.1"}]}'); - testThrows("number.non number", + testThrows('number.non number', '{$cfg,"packages":[{$name,$root,"languageVersion":"1.x"}]}'); - testThrows("non number", + testThrows('non number', '{$cfg,"packages":[{$name,$root,"languageVersion":"x"}]}'); - testThrows("one number", + testThrows('one number', '{$cfg,"packages":[{$name,$root,"languageVersion":"1"}]}'); - testThrows("three numbers", + testThrows('three numbers', '{$cfg,"packages":[{$name,$root,"languageVersion":"1.2.3"}]}'); - testThrows("leading zero first", + testThrows('leading zero first', '{$cfg,"packages":[{$name,$root,"languageVersion":"01.1"}]}'); - testThrows("leading zero second", + testThrows('leading zero second', '{$cfg,"packages":[{$name,$root,"languageVersion":"1.01"}]}'); - testThrows("trailing-", + testThrows('trailing-', '{$cfg,"packages":[{$name,$root,"languageVersion":"1.1-1"}]}'); - testThrows("trailing+", + testThrows('trailing+', '{$cfg,"packages":[{$name,$root,"languageVersion":"1.1+1"}]}'); }); }); - testThrows("duplicate package name", + testThrows('duplicate package name', '{$cfg,"packages":[{$name,$root},{$name,"rootUri":"/other/"}]}'); - testThrows("same roots", + testThrows('same roots', '{$cfg,"packages":[{$name,$root},{"name":"bar",$root}]}'); testThrows( // The roots of foo and bar are the same. - "same roots", + 'same roots', '{$cfg,"packages":[{$name,$root},{"name":"bar",$root}]}'); testThrows( // The root of bar is inside the root of foo, // but the package root of foo is inside the root of bar. - "between root and lib", + 'between root and lib', '{$cfg,"packages":[' '{"name":"foo","rootUri":"/foo/","packageUri":"bar/lib/"},' '{"name":"bar","rootUri":"/foo/bar/"},"packageUri":"baz/lib"]}'); }); }); - group("factories", () { + group('factories', () { void testConfig(String name, PackageConfig config, PackageConfig expected) { group(name, () { - test("structure", () { + test('structure', () { expect(config.version, expected.version); var expectedPackages = {for (var p in expected.packages) p.name}; var actualPackages = {for (var p in config.packages) p.name}; @@ -396,20 +396,20 @@ void main() { }); for (var package in config.packages) { var name = package.name; - test("package $name", () { + test('package $name', () { var expectedPackage = expected[name]!; expect(expectedPackage, isNotNull); - expect(package.root, expectedPackage.root, reason: "root"); + expect(package.root, expectedPackage.root, reason: 'root'); expect(package.packageUriRoot, expectedPackage.packageUriRoot, - reason: "package root"); + reason: 'package root'); expect(package.languageVersion, expectedPackage.languageVersion, - reason: "languageVersion"); + reason: 'languageVersion'); }); } }); } - var configText = """ + var configText = ''' {"configVersion": 2, "packages": [ { "name": "foo", @@ -418,37 +418,37 @@ void main() { "languageVersion": "1.2" } ]} - """; - var baseUri = Uri.parse("file:///start/"); + '''; + var baseUri = Uri.parse('file:///start/'); var config = PackageConfig([ - Package("foo", Uri.parse("file:///start/foo/"), - packageUriRoot: Uri.parse("file:///start/foo/bar/"), + Package('foo', Uri.parse('file:///start/foo/'), + packageUriRoot: Uri.parse('file:///start/foo/bar/'), languageVersion: LanguageVersion(1, 2)) ]); testConfig( - "string", PackageConfig.parseString(configText, baseUri), config); + 'string', PackageConfig.parseString(configText, baseUri), config); testConfig( - "bytes", + 'bytes', PackageConfig.parseBytes( Uint8List.fromList(configText.codeUnits), baseUri), config); - testConfig("json", PackageConfig.parseJson(jsonDecode(configText), baseUri), + testConfig('json', PackageConfig.parseJson(jsonDecode(configText), baseUri), config); - baseUri = Uri.parse("file:///start2/"); + baseUri = Uri.parse('file:///start2/'); config = PackageConfig([ - Package("foo", Uri.parse("file:///start2/foo/"), - packageUriRoot: Uri.parse("file:///start2/foo/bar/"), + Package('foo', Uri.parse('file:///start2/foo/'), + packageUriRoot: Uri.parse('file:///start2/foo/bar/'), languageVersion: LanguageVersion(1, 2)) ]); testConfig( - "string2", PackageConfig.parseString(configText, baseUri), config); + 'string2', PackageConfig.parseString(configText, baseUri), config); testConfig( - "bytes2", + 'bytes2', PackageConfig.parseBytes( Uint8List.fromList(configText.codeUnits), baseUri), config); - testConfig("json2", + testConfig('json2', PackageConfig.parseJson(jsonDecode(configText), baseUri), config); }); } diff --git a/pkgs/package_config/test/src/util.dart b/pkgs/package_config/test/src/util.dart index 2b262e1b2..32e92174c 100644 --- a/pkgs/package_config/test/src/util.dart +++ b/pkgs/package_config/test/src/util.dart @@ -5,13 +5,13 @@ import 'dart:convert'; import 'dart:typed_data'; -import "package:test/test.dart"; +import 'package:test/test.dart'; /// Creates a package: URI. Uri pkg(String packageName, String packagePath) { var path = "$packageName${packagePath.startsWith('/') ? "" : "/"}$packagePath"; - return Uri(scheme: "package", path: path); + return Uri(scheme: 'package', path: path); } // Remove if not used. @@ -33,13 +33,16 @@ ${packages.map((nu) => """ /// Description is a map, each key is a file entry. If the value is a map, /// it's a subdirectory, otherwise it's a file and the value is the content /// as a string. -void loaderTest(String name, Map description, - void loaderTest(Uri root, Future loader(Uri uri))) { - var root = Uri(scheme: "test", path: "/"); +void loaderTest( + String name, + Map description, + void Function(Uri root, Future Function(Uri) loader) loaderTest, +) { + var root = Uri(scheme: 'test', path: '/'); Future loader(Uri uri) async { var path = uri.path; - if (!uri.isScheme("test") || !path.startsWith("/")) return null; - var parts = path.split("/"); + if (!uri.isScheme('test') || !path.startsWith('/')) return null; + var parts = path.split('/'); Object? value = description; for (var i = 1; i < parts.length; i++) { if (value is! Map) return null; diff --git a/pkgs/package_config/test/src/util_io.dart b/pkgs/package_config/test/src/util_io.dart index 37deee9e1..109dff112 100644 --- a/pkgs/package_config/test/src/util_io.dart +++ b/pkgs/package_config/test/src/util_io.dart @@ -2,10 +2,10 @@ // 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. -import "dart:io"; +import 'dart:io'; -import "package:test/test.dart"; -import "package:package_config/src/util_io.dart"; +import 'package:test/test.dart'; +import 'package:package_config/src/util_io.dart'; /// Creates a directory structure from [description] and runs [fileTest]. /// @@ -14,9 +14,9 @@ import "package:package_config/src/util_io.dart"; /// as a string. /// Introduces a group to hold the [setUp]/[tearDown] logic. void fileTest(String name, Map description, - void fileTest(Directory directory)) { - group("file-test", () { - var tempDir = Directory.systemTemp.createTempSync("pkgcfgtest"); + void Function(Directory directory) fileTest) { + group('file-test', () { + var tempDir = Directory.systemTemp.createTempSync('pkgcfgtest'); setUp(() { _createFiles(tempDir, description); }); @@ -44,7 +44,7 @@ void fileTest(String name, Map description, // Creates temporary files in the target directory. void _createFiles(Directory target, Map description) { description.forEach((name, content) { - var entryName = pathJoin(target.path, "$name"); + var entryName = pathJoin(target.path, '$name'); if (content is Map) { _createFiles(Directory(entryName)..createSync(), content); } else { @@ -55,7 +55,7 @@ void _createFiles(Directory target, Map description) { /// Creates a [Directory] for a subdirectory of [parent]. Directory subdir(Directory parent, String dirName) => - Directory(pathJoinAll([parent.path, ...dirName.split("/")])); + Directory(pathJoinAll([parent.path, ...dirName.split('/')])); /// Creates a [File] for an entry in the [directory] directory. File dirFile(Directory directory, String fileName) => From 028521a02f773c2ef8841eee3dd9d8c4e83bb25b Mon Sep 17 00:00:00 2001 From: Danny Tuppeny Date: Mon, 2 Aug 2021 15:56:51 +0100 Subject: [PATCH 114/170] Fix typo: "packjage_config" (dart-lang/package_config#113) --- pkgs/package_config/lib/src/package_config.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/package_config/lib/src/package_config.dart b/pkgs/package_config/lib/src/package_config.dart index 8210132a1..3c5cc5196 100644 --- a/pkgs/package_config/lib/src/package_config.dart +++ b/pkgs/package_config/lib/src/package_config.dart @@ -204,7 +204,7 @@ abstract class PackageConfig { /// Extra data associated with the package configuration. /// /// The data may be in any format, depending on who introduced it. - /// The standard `packjage_config.json` file storage will only store + /// The standard `package_config.json` file storage will only store /// JSON-like list/map data structures. Object? get extraData; } From 0061cdb33d393d3732ff897c1e6d10911369d927 Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Fri, 6 Aug 2021 00:57:55 -0700 Subject: [PATCH 115/170] Ignore unnecessary casts from utf8.encode (dart-lang/package_config#114) An upcoming SDK change will change the return type to `Uint8List` which makes the casts unnecessary and introduces analyzer diagnostics. Preemptively ignore these to make it easier to roll the SDK. https://dart-review.googlesource.com/c/sdk/+/208190 --- pkgs/package_config/CHANGELOG.md | 2 ++ pkgs/package_config/pubspec.yaml | 2 +- pkgs/package_config/test/parse_test.dart | 6 ++++++ pkgs/package_config/test/src/util.dart | 1 + 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index 9949b51db..898ebc4bb 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -1,3 +1,5 @@ +## 2.0.2-dev + ## 2.0.1 - Use unique library names to correct docs issue. diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 687c3d303..5cc9cc0a5 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 2.0.1 +version: 2.0.2-dev description: Support for working with Package Configuration files. homepage: https://github.com/dart-lang/package_config diff --git a/pkgs/package_config/test/parse_test.dart b/pkgs/package_config/test/parse_test.dart index a163e127f..d5c2e7268 100644 --- a/pkgs/package_config/test/parse_test.dart +++ b/pkgs/package_config/test/parse_test.dart @@ -113,6 +113,7 @@ void main() { } '''; var config = parsePackageConfigBytes( + // ignore: unnecessary_cast utf8.encode(packageConfigFile) as Uint8List, Uri.parse('file:///tmp/.dart_tool/file.dart'), throwError); @@ -193,6 +194,7 @@ void main() { } '''; var config = parsePackageConfigBytes( + // ignore: unnecessary_cast utf8.encode(packageConfigFile) as Uint8List, Uri.parse('file:///tmp/.dart_tool/file.dart'), throwError); @@ -219,6 +221,7 @@ void main() { var root = '"rootUri":"/foo/"'; test('minimal', () { var config = parsePackageConfigBytes( + // ignore: unnecessary_cast utf8.encode('{$cfg,$pkgs}') as Uint8List, Uri.parse('file:///tmp/.dart_tool/file.dart'), throwError); @@ -229,6 +232,7 @@ void main() { // A package must have a name and a rootUri, the remaining properties // are optional. var config = parsePackageConfigBytes( + // ignore: unnecessary_cast utf8.encode('{$cfg,"packages":[{$name,$root}]}') as Uint8List, Uri.parse('file:///tmp/.dart_tool/file.dart'), throwError); @@ -246,6 +250,7 @@ void main() { {'name': 'qux', 'rootUri': '/foo/qux/', 'packageUri': 'lib/'}, ] })); + // ignore: unnecessary_cast var config = parsePackageConfigBytes(configBytes as Uint8List, Uri.parse('file:///tmp/.dart_tool/file.dart'), throwError); expect(config.version, 2); @@ -271,6 +276,7 @@ void main() { void testThrows(String name, String source) { test(name, () { expect( + // ignore: unnecessary_cast () => parsePackageConfigBytes(utf8.encode(source) as Uint8List, Uri.parse('file:///tmp/.dart_tool/file.dart'), throwError), throwsA(TypeMatcher())); diff --git a/pkgs/package_config/test/src/util.dart b/pkgs/package_config/test/src/util.dart index 32e92174c..246e12964 100644 --- a/pkgs/package_config/test/src/util.dart +++ b/pkgs/package_config/test/src/util.dart @@ -48,6 +48,7 @@ void loaderTest( if (value is! Map) return null; value = value[parts[i]]; } + // ignore: unnecessary_cast if (value is String) return utf8.encode(value) as Uint8List; return null; } From c1531e295d5a64c2740a805842a52ed7e2f8fd8f Mon Sep 17 00:00:00 2001 From: Michael Thomsen Date: Mon, 13 Sep 2021 14:06:47 +0200 Subject: [PATCH 116/170] Switch to package:lints --- pkgs/package_config/analysis_options.yaml | 2 +- pkgs/package_config/lib/src/package_config_json.dart | 4 ++-- pkgs/package_config/pubspec.yaml | 2 +- pkgs/package_config/test/discovery_test.dart | 3 +-- pkgs/package_config/test/discovery_uri_test.dart | 5 ++--- 5 files changed, 7 insertions(+), 9 deletions(-) diff --git a/pkgs/package_config/analysis_options.yaml b/pkgs/package_config/analysis_options.yaml index a0ba68de2..278ec4868 100644 --- a/pkgs/package_config/analysis_options.yaml +++ b/pkgs/package_config/analysis_options.yaml @@ -2,4 +2,4 @@ # 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. -include: package:pedantic/analysis_options.1.9.0.yaml +include: package:lints/recommended.yaml diff --git a/pkgs/package_config/lib/src/package_config_json.dart b/pkgs/package_config/lib/src/package_config_json.dart index 1998b6606..fe185a2ea 100644 --- a/pkgs/package_config/lib/src/package_config_json.dart +++ b/pkgs/package_config/lib/src/package_config_json.dart @@ -35,7 +35,7 @@ final _jsonUtf8Decoder = json.fuse(utf8).decoder; PackageConfig parsePackageConfigBytes( Uint8List bytes, Uri file, void Function(Object error) onError) { // TODO(lrn): Make this simpler. Maybe parse directly from bytes. - var jsonObject; + Object? jsonObject; try { jsonObject = _jsonUtf8Decoder.convert(bytes); } on FormatException catch (e) { @@ -47,7 +47,7 @@ PackageConfig parsePackageConfigBytes( PackageConfig parsePackageConfigString( String source, Uri file, void Function(Object error) onError) { - var jsonObject; + Object? jsonObject; try { jsonObject = jsonDecode(source); } on FormatException catch (e) { diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 5cc9cc0a5..e7c9a0a3a 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -13,5 +13,5 @@ dev_dependencies: build_runner: ^2.0.0 build_test: ^2.1.2 build_web_compilers: ^3.0.0 - pedantic: ^1.10.0 + lints: ^1.0.0 test: ^1.16.0 diff --git a/pkgs/package_config/test/discovery_test.dart b/pkgs/package_config/test/discovery_test.dart index d2c3d8330..4a1bba0a6 100644 --- a/pkgs/package_config/test/discovery_test.dart +++ b/pkgs/package_config/test/discovery_test.dart @@ -99,8 +99,7 @@ void main() { '.packages': packagesFile, 'subdir': {'script.dart': 'main(){}'} }, (Directory directory) async { - var config; - config = await findPackageConfig(subdir(directory, 'subdir/')); + var config = (await findPackageConfig(subdir(directory, 'subdir/')))!; expect(config.version, 1); validatePackagesFile(config, directory); }); diff --git a/pkgs/package_config/test/discovery_uri_test.dart b/pkgs/package_config/test/discovery_uri_test.dart index 0a9b91720..e487e471d 100644 --- a/pkgs/package_config/test/discovery_uri_test.dart +++ b/pkgs/package_config/test/discovery_uri_test.dart @@ -98,9 +98,8 @@ void main() { '.packages': packagesFile, 'subdir': {'script.dart': 'main(){}'} }, (directory, loader) async { - var config; - config = await findPackageConfigUri(directory.resolve('subdir/'), - loader: loader); + var config = (await findPackageConfigUri(directory.resolve('subdir/'), + loader: loader))!; expect(config.version, 1); validatePackagesFile(config, directory); }); From 89cfab15a5bf72b9d8d04dc70f237392eaff4dfc Mon Sep 17 00:00:00 2001 From: Michael Thomsen Date: Mon, 13 Sep 2021 14:32:57 +0200 Subject: [PATCH 117/170] Update description --- pkgs/package_config/pubspec.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index e7c9a0a3a..6f80473c9 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,6 +1,6 @@ name: package_config -version: 2.0.2-dev -description: Support for working with Package Configuration files. +version: 2.0.2 +description: Support for reading and writing Dart Package Configuration files. homepage: https://github.com/dart-lang/package_config environment: From 8d518f7a0ec94304c35c673f775948099d63c1ac Mon Sep 17 00:00:00 2001 From: Michael Thomsen Date: Mon, 13 Sep 2021 14:33:03 +0200 Subject: [PATCH 118/170] Add example --- pkgs/package_config/example/main.dart | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 pkgs/package_config/example/main.dart diff --git a/pkgs/package_config/example/main.dart b/pkgs/package_config/example/main.dart new file mode 100644 index 000000000..42a596375 --- /dev/null +++ b/pkgs/package_config/example/main.dart @@ -0,0 +1,18 @@ +// Copyright (c) 2020, 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. + +import 'package:package_config/package_config.dart'; +import 'dart:io' show Directory; + +void main() async { + var packageConfig = await findPackageConfig(Directory.current); + if (packageConfig == null) { + print('Failed to locate or read package config.'); + } else { + print('This package depends on ${packageConfig.packages.length} packages:'); + for (var package in packageConfig.packages) { + print('- ${package.name}'); + } + } +} From 9b60f7b3b70179036251993cec28e418e68f894b Mon Sep 17 00:00:00 2001 From: Michael Thomsen Date: Mon, 13 Sep 2021 14:37:50 +0200 Subject: [PATCH 119/170] Expand readme --- pkgs/package_config/CHANGELOG.md | 6 +++++- pkgs/package_config/README.md | 8 +++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index 898ebc4bb..c85ac5011 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -1,4 +1,8 @@ -## 2.0.2-dev +## 2.0.2 + +- Update package description and README. +- Change to package:lints for style checking. +- Add an example. ## 2.0.1 diff --git a/pkgs/package_config/README.md b/pkgs/package_config/README.md index ada1bd0ec..15ed4f6b2 100644 --- a/pkgs/package_config/README.md +++ b/pkgs/package_config/README.md @@ -4,7 +4,13 @@ Support for working with **Package Configuration** files as described in the Package Configuration v2 [design document](https://github.com/dart-lang/language/blob/master/accepted/future-releases/language-versioning/package-config-file-v2.md). -The primary libraries are +A Dart package configuration file is used to resolve Dart package names (e.g. +`foobar`) to Dart files containing the source code for that package (e.g. +`file:///Users/myuser/.pub-cache/hosted/pub.dartlang.org/foobar-1.1.0`). The +standard package configuration file is `.dart_tool/package_config.json`, and is +written by the Dart tool when the command `dart pub get` is run. + +The primary libraries of this package are * `package_config.dart`: Defines the `PackageConfig` class and other types needed to use package configurations, and provides functions to find, read and From 38958749c9d2bc7403c9b67b54f90a981672bd32 Mon Sep 17 00:00:00 2001 From: Michael Thomsen Date: Mon, 13 Sep 2021 15:06:24 +0200 Subject: [PATCH 120/170] Fix dartdoc generation --- pkgs/package_config/lib/package_config_types.dart | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pkgs/package_config/lib/package_config_types.dart b/pkgs/package_config/lib/package_config_types.dart index 482f82ac2..38b68ce6d 100644 --- a/pkgs/package_config/lib/package_config_types.dart +++ b/pkgs/package_config/lib/package_config_types.dart @@ -3,7 +3,13 @@ // BSD-style license that can be found in the LICENSE file. /// A package configuration is a way to assign file paths to package URIs, -/// and vice-versa, +/// and vice-versa. + +/// {@canonicalFor package_config.InvalidLanguageVersion} +/// {@canonicalFor package_config.LanguageVersion} +/// {@canonicalFor package_config.Package} +/// {@canonicalFor package_config.PackageConfig} +/// {@canonicalFor errors.PackageConfigError} library package_config.package_config_types; export 'src/package_config.dart' From 754c0a831f0db6d2c739e6abc3ab0cc6ccf06da4 Mon Sep 17 00:00:00 2001 From: Michael Thomsen Date: Mon, 13 Sep 2021 16:16:00 +0200 Subject: [PATCH 121/170] Add /// --- pkgs/package_config/lib/package_config_types.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/package_config/lib/package_config_types.dart b/pkgs/package_config/lib/package_config_types.dart index 38b68ce6d..976009b6c 100644 --- a/pkgs/package_config/lib/package_config_types.dart +++ b/pkgs/package_config/lib/package_config_types.dart @@ -4,7 +4,7 @@ /// A package configuration is a way to assign file paths to package URIs, /// and vice-versa. - +/// /// {@canonicalFor package_config.InvalidLanguageVersion} /// {@canonicalFor package_config.LanguageVersion} /// {@canonicalFor package_config.Package} From 0674a0fcbd6126f03a28121e6c620155e978d014 Mon Sep 17 00:00:00 2001 From: Jens Johansen Date: Thu, 25 Nov 2021 11:00:11 +0100 Subject: [PATCH 122/170] Faster read; faster lookup; more tests; error on new package inside existing package root Previously adding (reading a file consisting of) n non-overlapping packages took O(n^2) time. Looking up a single package in a structure with n non-overlapping packages took O(n) time. Here this is changed so the timings are more like O(n) and O(1), respectively. (all of these should be taken with a grain of salt as not only the number of packages influence the time, but also the length of the paths which I completely ignore here). Run like this: ``` $ for i in 1 10 100 1000 5000 10000 50000; do dart test/bench.dart $i; done ``` (With no warmup, only run once etc --- there's lots of variations between runs, but for this purpose it doesn't really matter.) Before: Read file with 1 packages in 18 ms, looked up all packages in 0 ms Read file with 10 packages in 22 ms, looked up all packages in 0 ms Read file with 100 packages in 28 ms, looked up all packages in 1 ms Read file with 1000 packages in 78 ms, looked up all packages in 14 ms Read file with 5000 packages in 442 ms, looked up all packages in 384 ms Read file with 10000 packages in 2254 ms, looked up all packages in 1826 ms Read file with 50000 packages in 67572 ms, looked up all packages in 84050 ms After: Read file with 1 packages in 24 ms, looked up all packages in 0 ms Read file with 10 packages in 23 ms, looked up all packages in 0 ms Read file with 100 packages in 25 ms, looked up all packages in 1 ms Read file with 1000 packages in 60 ms, looked up all packages in 6 ms Read file with 5000 packages in 127 ms, looked up all packages in 10 ms Read file with 10000 packages in 187 ms, looked up all packages in 13 ms Read file with 50000 packages in 525 ms, looked up all packages in 61 ms Furthermore: * Previously no error was given if a package was inside the package root of another package. Now an error is given and tests are added. * Previously at least one test didn't work because of a json syntax error. This has been fixed. --- .../lib/src/package_config_impl.dart | 260 +++++++++--------- pkgs/package_config/test/bench.dart | 71 +++++ pkgs/package_config/test/parse_test.dart | 68 ++++- 3 files changed, 269 insertions(+), 130 deletions(-) create mode 100644 pkgs/package_config/test/bench.dart diff --git a/pkgs/package_config/lib/src/package_config_impl.dart b/pkgs/package_config/lib/src/package_config_impl.dart index 4167d35f8..c22622b3a 100644 --- a/pkgs/package_config/lib/src/package_config_impl.dart +++ b/pkgs/package_config/lib/src/package_config_impl.dart @@ -54,12 +54,12 @@ class SimplePackageConfig implements PackageConfig { static PackageTree _validatePackages(Iterable originalPackages, List packages, void Function(Object error) onError) { var packageNames = {}; - var tree = MutablePackageTree(); + var tree = TrielikePackageTree(); for (var originalPackage in packages) { - SimplePackage? package; + SimplePackage? newPackage; if (originalPackage is! SimplePackage) { // SimplePackage validates these properties. - package = SimplePackage.validate( + newPackage = SimplePackage.validate( originalPackage.name, originalPackage.root, originalPackage.packageUriRoot, @@ -68,43 +68,58 @@ class SimplePackageConfig implements PackageConfig { originalPackage.relativeRoot, (error) { if (error is PackageConfigArgumentError) { onError(PackageConfigArgumentError(packages, 'packages', - 'Package ${package!.name}: ${error.message}')); + 'Package ${newPackage!.name}: ${error.message}')); } else { onError(error); } }); - if (package == null) continue; + if (newPackage == null) continue; } else { - package = originalPackage; + newPackage = originalPackage; } - var name = package.name; + var name = newPackage.name; if (packageNames.contains(name)) { onError(PackageConfigArgumentError( name, 'packages', "Duplicate package name '$name'")); continue; } packageNames.add(name); - tree.add(0, package, (error) { + tree.add(newPackage, (error) { if (error is ConflictException) { // There is a conflict with an existing package. var existingPackage = error.existingPackage; - if (error.isRootConflict) { - onError(PackageConfigArgumentError( - originalPackages, - 'packages', - 'Packages ${package!.name} and ${existingPackage.name} ' - 'have the same root directory: ${package.root}.\n')); - } else { - assert(error.isPackageRootConflict); - // Package is inside the package URI root of the existing package. - onError(PackageConfigArgumentError( - originalPackages, - 'packages', - 'Package ${package!.name} is inside the package URI root of ' - 'package ${existingPackage.name}.\n' - '${existingPackage.name} URI root: ' - '${existingPackage.packageUriRoot}\n' - '${package.name} root: ${package.root}\n')); + switch (error.conflictType) { + case ConflictType.SameRoots: + onError(PackageConfigArgumentError( + originalPackages, + 'packages', + 'Packages ${newPackage!.name} and ${existingPackage.name} ' + 'have the same root directory: ${newPackage.root}.\n')); + break; + case ConflictType.Interleaving: + // The new package is inside the package URI root of the existing + // package. + onError(PackageConfigArgumentError( + originalPackages, + 'packages', + 'Package ${newPackage!.name} is inside the root of ' + 'package ${existingPackage.name}, and the package root ' + 'of ${existingPackage.name} is inside the root of ' + '${newPackage.name}.\n' + '${existingPackage.name} package root: ' + '${existingPackage.packageUriRoot}\n' + '${newPackage.name} root: ${newPackage.root}\n')); + break; + case ConflictType.InsidePackageRoot: + onError(PackageConfigArgumentError( + originalPackages, + 'packages', + 'Package ${newPackage!.name} is inside the package root of ' + 'package ${existingPackage.name}.\n' + '${existingPackage.name} package root: ' + '${existingPackage.packageUriRoot}\n' + '${newPackage.name} root: ${newPackage.root}\n')); + break; } } else { // Any other error. @@ -367,6 +382,11 @@ abstract class PackageTree { SimplePackage? packageOf(Uri file); } +class _TrielikePackageTreeHelper { + SimplePackage? package; + Map map = {}; +} + /// Packages of a package configuration ordered by root path. /// /// A package has a root path and a package root path, where the latter @@ -375,122 +395,120 @@ abstract class PackageTree { /// A package is said to be inside another package if the root path URI of /// the latter is a prefix of the root path URI of the former. /// -/// No two packages of a package may have the same root path, so this -/// path prefix ordering defines a tree-like partial ordering on packages -/// of a configuration. -/// +/// No two packages of a package may have the same root path. /// The package root path of a package must not be inside another package's /// root path. -/// Entire other packages are allowed inside a package's root or -/// package root path. -/// -/// The package tree contains an ordered mapping of unrelated packages -/// (represented by their name) to their immediately nested packages' names. -class MutablePackageTree implements PackageTree { - /// A list of packages that are not nested inside each other. - final List packages = []; +/// Entire other packages are allowed inside a package's root. +class TrielikePackageTree implements PackageTree { + final Map _map = {}; - /// The tree of the immediately nested packages inside each package. - /// - /// Indexed by [Package.name]. - /// If a package has no nested packages (which is most often the case), - /// there is no tree object associated with it. - Map? _packageChildren; + /// A list of all packages. + final List _packages = []; @override Iterable get allPackages sync* { - for (var package in packages) { + for (var package in _packages) { yield package; } - var children = _packageChildren; - if (children != null) { - for (var tree in children.values) { - yield* tree.allPackages; + } + + bool _checkConflict(_TrielikePackageTreeHelper currentMapHelper, + SimplePackage newPackage, void Function(Object error) onError) { + if (currentMapHelper.package != null) { + var existingPackage = currentMapHelper.package!; + // Trying to add package that is inside the existing package. + // 1) If it's an exact match it's not allowed (i.e. the roots can't be + // the same). + if (newPackage.root.path.length == existingPackage.root.path.length) { + onError(ConflictException( + newPackage, existingPackage, ConflictType.SameRoots)); + return true; + } + // 2) The existing package has a packageUriRoot thats inside the + // root of the new package. + if (_beginsWith(0, newPackage.root.toString(), + existingPackage.packageUriRoot.toString())) { + onError(ConflictException( + newPackage, existingPackage, ConflictType.Interleaving)); + return true; + } + // 3) The new package is inside the packageUriRoot of existing package. + if (_beginsWith(0, existingPackage.packageUriRoot.toString(), + newPackage.root.toString())) { + onError(ConflictException( + newPackage, existingPackage, ConflictType.InsidePackageRoot)); + return true; } } + return false; } - /// Tries to (add) `package` to the tree. + /// Tries to add `newPackage` to the tree. /// /// Reports a [ConflictException] if the added package conflicts with an /// existing package. - /// It conflicts if its root or package root is the same as another - /// package's root or package root, or is between the two. + /// It conflicts if its root or package root is the same as an existing + /// package's root or package root, is between the two, or if it's inside the + /// package root of an existing package. /// - /// If a conflict is detected between [package] and a previous package, + /// If a conflict is detected between [newPackage] and a previous package, /// then [onError] is called with a [ConflictException] object - /// and the [package] is not added to the tree. + /// and the [newPackage] is not added to the tree. /// /// The packages are added in order of their root path. - /// It is never necessary to insert a node between two existing levels. - void add( - int start, SimplePackage package, void Function(Object error) onError) { - var path = package.root.toString(); - for (var treePackage in packages) { - // Check is package is inside treePackage. - var treePackagePath = treePackage.root.toString(); - assert(treePackagePath.length > start); - assert(path.startsWith(treePackagePath.substring(0, start))); - if (_beginsWith(start, treePackagePath, path)) { - // Package *is* inside treePackage. - var treePackagePathLength = treePackagePath.length; - if (path.length == treePackagePathLength) { - // Has same root. Do not add package. - onError(ConflictException.root(package, treePackage)); - return; - } - var treePackageUriRoot = treePackage.packageUriRoot.toString(); - if (_beginsWith(treePackagePathLength, path, treePackageUriRoot)) { - // The treePackage's package root is inside package, which is inside - // the treePackage. This is not allowed. - onError(ConflictException.packageRoot(package, treePackage)); - return; - } - _treeOf(treePackage).add(treePackagePathLength, package, onError); - return; + void add(SimplePackage newPackage, void Function(Object error) onError) { + var root = newPackage.root; + var currentMapHelper = _map[root.scheme] ??= _TrielikePackageTreeHelper(); + if (_checkConflict(currentMapHelper, newPackage, onError)) return; + var segments = root.pathSegments; + for (var i = 0; i < segments.length - 1; i++) { + var path = segments[i]; + currentMapHelper = + currentMapHelper.map[path] ??= _TrielikePackageTreeHelper(); + if (_checkConflict(currentMapHelper, newPackage, onError)) return; + } + currentMapHelper.package = newPackage; + _packages.add(newPackage); + } + + bool _isMatch(String path, _TrielikePackageTreeHelper currentMapHelper, + List potential) { + if (currentMapHelper.package != null) { + var currentPackage = currentMapHelper.package!; + var currentPackageRootLength = currentPackage.root.toString().length; + if (path.length == currentPackageRootLength) return true; + var currentPackageUriRoot = currentPackage.packageUriRoot.toString(); + // Is [file] is inside the package root of [currentPackage]? + if (currentPackageUriRoot.length == currentPackageRootLength || + _beginsWith(currentPackageRootLength, currentPackageUriRoot, path)) { + return true; } + potential.add(currentPackage); } - packages.add(package); + return false; } @override SimplePackage? packageOf(Uri file) { - return findPackageOf(0, file.toString()); - } - - /// Finds package containing [path] in this tree. - /// - /// Returns `null` if no such package is found. - /// - /// Assumes the first [start] characters of path agrees with all - /// the packages at this level of the tree. - SimplePackage? findPackageOf(int start, String path) { - for (var childPackage in packages) { - var childPath = childPackage.root.toString(); - if (_beginsWith(start, childPath, path)) { - // The [package] is inside [childPackage]. - var childPathLength = childPath.length; - if (path.length == childPathLength) return childPackage; - var uriRoot = childPackage.packageUriRoot.toString(); - // Is [package] is inside the URI root of [childPackage]. - if (uriRoot.length == childPathLength || - _beginsWith(childPathLength, uriRoot, path)) { - return childPackage; - } - return _packageChildren?[childPackage.name] - ?.findPackageOf(childPathLength, path) ?? - childPackage; + var currentMapHelper = _map[file.scheme]; + if (currentMapHelper == null) return null; + var path = file.toString(); + var potential = []; + if (_isMatch(path, currentMapHelper, potential)) { + return currentMapHelper.package; + } + var segments = file.pathSegments; + + for (var i = 0; i < segments.length - 1; i++) { + var segment = segments[i]; + currentMapHelper = currentMapHelper!.map[segment]; + if (currentMapHelper == null) break; + if (_isMatch(path, currentMapHelper, potential)) { + return currentMapHelper.package; } } - return null; - } - - /// Returns the [PackageTree] of the children of [package]. - /// - /// Ensures that the object is allocated if necessary. - MutablePackageTree _treeOf(SimplePackage package) { - var children = _packageChildren ??= {}; - return children[package.name] ??= MutablePackageTree(); + if (potential.isEmpty) return null; + return potential.last; } } @@ -516,6 +534,8 @@ bool _beginsWith(int start, String parentPath, String longerPath) { return true; } +enum ConflictType { SameRoots, Interleaving, InsidePackageRoot } + /// Conflict between packages added to the same configuration. /// /// The [package] conflicts with [existingPackage] if it has @@ -530,18 +550,10 @@ class ConflictException { final SimplePackage package; /// Whether the conflict is with the package URI root of [existingPackage]. - final bool isPackageRootConflict; + final ConflictType conflictType; /// Creates a root conflict between [package] and [existingPackage]. - ConflictException.root(this.package, this.existingPackage) - : isPackageRootConflict = false; - - /// Creates a package root conflict between [package] and [existingPackage]. - ConflictException.packageRoot(this.package, this.existingPackage) - : isPackageRootConflict = true; - - /// WHether the conflict is with the root URI of [existingPackage]. - bool get isRootConflict => !isPackageRootConflict; + ConflictException(this.package, this.existingPackage, this.conflictType); } /// Used for sorting packages by root path. diff --git a/pkgs/package_config/test/bench.dart b/pkgs/package_config/test/bench.dart new file mode 100644 index 000000000..746643185 --- /dev/null +++ b/pkgs/package_config/test/bench.dart @@ -0,0 +1,71 @@ +// Copyright (c) 2021, 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. + +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:package_config/src/package_config_json.dart'; + +void throwError(Object error) => throw error; + +void bench(final int size, final bool doPrint) { + var sb = StringBuffer(); + sb.writeln('{'); + sb.writeln('"configVersion": 2,'); + sb.writeln('"packages": ['); + for (var i = 0; i < size; i++) { + if (i != 0) { + sb.writeln(','); + } + sb.writeln('{'); + sb.writeln(' "name": "p_$i",'); + sb.writeln(' "rootUri": "file:///p_$i/",'); + sb.writeln(' "packageUri": "lib/",'); + sb.writeln(' "languageVersion": "2.5",'); + sb.writeln(' "nonstandard": true'); + sb.writeln('}'); + } + sb.writeln('],'); + sb.writeln('"generator": "pub",'); + sb.writeln('"other": [42]'); + sb.writeln('}'); + var stopwatch = Stopwatch()..start(); + var config = parsePackageConfigBytes( + // ignore: unnecessary_cast + utf8.encode(sb.toString()) as Uint8List, + Uri.parse('file:///tmp/.dart_tool/file.dart'), + throwError); + final int read = stopwatch.elapsedMilliseconds; + + stopwatch.reset(); + for (var i = 0; i < size; i++) { + if (config.packageOf(Uri.parse('file:///p_$i/lib/src/foo.dart'))!.name != + 'p_$i') { + throw "Unexpected result!"; + } + } + final int lookup = stopwatch.elapsedMilliseconds; + + if (doPrint) { + print('Read file with $size packages in $read ms, ' + 'looked up all packages in $lookup ms'); + } +} + +void main(List args) { + if (args.length != 1 && args.length != 2) { + throw "Expects arguments: ?"; + } + final size = int.parse(args[0]); + if (args.length > 1) { + final warmups = int.parse(args[1]); + print("Performing $warmups warmup iterations."); + for (var i = 0; i < warmups; i++) { + bench(10, false); + } + } + + // Benchmark. + bench(size, true); +} diff --git a/pkgs/package_config/test/parse_test.dart b/pkgs/package_config/test/parse_test.dart index d5c2e7268..0a7770d58 100644 --- a/pkgs/package_config/test/parse_test.dart +++ b/pkgs/package_config/test/parse_test.dart @@ -272,6 +272,36 @@ void main() { Uri.parse('package:qux/diz')); }); + test('nested packages 2', () { + var configBytes = utf8.encode(json.encode({ + 'configVersion': 2, + 'packages': [ + {'name': 'foo', 'rootUri': '/', 'packageUri': 'lib/'}, + {'name': 'bar', 'rootUri': '/bar/', 'packageUri': 'lib/'}, + {'name': 'baz', 'rootUri': '/bar/baz/', 'packageUri': 'lib/'}, + {'name': 'qux', 'rootUri': '/qux/', 'packageUri': 'lib/'}, + ] + })); + // ignore: unnecessary_cast + var config = parsePackageConfigBytes(configBytes as Uint8List, + Uri.parse('file:///tmp/.dart_tool/file.dart'), throwError); + expect(config.version, 2); + expect( + config.packageOf(Uri.parse('file:///lala/lala.dart'))!.name, 'foo'); + expect(config.packageOf(Uri.parse('file:///bar/lala.dart'))!.name, 'bar'); + expect(config.packageOf(Uri.parse('file:///bar/baz/lala.dart'))!.name, + 'baz'); + expect(config.packageOf(Uri.parse('file:///qux/lala.dart'))!.name, 'qux'); + expect(config.toPackageUri(Uri.parse('file:///lib/diz')), + Uri.parse('package:foo/diz')); + expect(config.toPackageUri(Uri.parse('file:///bar/lib/diz')), + Uri.parse('package:bar/diz')); + expect(config.toPackageUri(Uri.parse('file:///bar/baz/lib/diz')), + Uri.parse('package:baz/diz')); + expect(config.toPackageUri(Uri.parse('file:///qux/lib/diz')), + Uri.parse('package:qux/diz')); + }); + group('invalid', () { void testThrows(String name, String source) { test(name, () { @@ -283,6 +313,21 @@ void main() { }); } + void testThrowsContains( + String name, String source, String containsString) { + test(name, () { + dynamic exception; + try { + parsePackageConfigBytes(utf8.encode(source) as Uint8List, + Uri.parse('file:///tmp/.dart_tool/file.dart'), throwError); + } catch (e) { + exception = e; + } + if (exception == null) fail("Didn't get exception"); + expect('$exception', contains(containsString)); + }); + } + testThrows('comment', '# comment\n {$cfg,$pkgs}'); testThrows('.packages file', 'foo:/foo\n'); testThrows('no configVersion', '{$pkgs}'); @@ -375,19 +420,30 @@ void main() { }); testThrows('duplicate package name', '{$cfg,"packages":[{$name,$root},{$name,"rootUri":"/other/"}]}'); - testThrows('same roots', - '{$cfg,"packages":[{$name,$root},{"name":"bar",$root}]}'); - testThrows( + testThrowsContains( // The roots of foo and bar are the same. 'same roots', - '{$cfg,"packages":[{$name,$root},{"name":"bar",$root}]}'); - testThrows( + '{$cfg,"packages":[{$name,$root},{"name":"bar",$root}]}', + 'the same root directory'); + testThrowsContains( + // The roots of foo and bar are the same. + 'same roots 2', + '{$cfg,"packages":[{$name,"rootUri":"/"},{"name":"bar","rootUri":"/"}]}', + 'the same root directory'); + testThrowsContains( // The root of bar is inside the root of foo, // but the package root of foo is inside the root of bar. 'between root and lib', '{$cfg,"packages":[' '{"name":"foo","rootUri":"/foo/","packageUri":"bar/lib/"},' - '{"name":"bar","rootUri":"/foo/bar/"},"packageUri":"baz/lib"]}'); + '{"name":"bar","rootUri":"/foo/bar/","packageUri":"baz/lib"}]}', + 'package root of foo is inside the root of bar'); + testThrowsContains( + 'root in lib', + '{$cfg,"packages":[' + '{"name":"foo","rootUri":"/foo/","packageUri":"lib/"},' + '{"name":"bar","rootUri":"/foo/lib/bar/","packageUri":"lib"}]}', + 'Package bar is inside the package root of package foo'); }); }); From c3b52af04b3a3e880c28fd988041341181c12cd1 Mon Sep 17 00:00:00 2001 From: Jens Johansen Date: Thu, 25 Nov 2021 11:07:49 +0100 Subject: [PATCH 123/170] Fix for 'Prefer using lowerCamelCase for constant names.' --- .../lib/src/package_config_impl.dart | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pkgs/package_config/lib/src/package_config_impl.dart b/pkgs/package_config/lib/src/package_config_impl.dart index c22622b3a..90862e344 100644 --- a/pkgs/package_config/lib/src/package_config_impl.dart +++ b/pkgs/package_config/lib/src/package_config_impl.dart @@ -89,14 +89,14 @@ class SimplePackageConfig implements PackageConfig { // There is a conflict with an existing package. var existingPackage = error.existingPackage; switch (error.conflictType) { - case ConflictType.SameRoots: + case ConflictType.sameRoots: onError(PackageConfigArgumentError( originalPackages, 'packages', 'Packages ${newPackage!.name} and ${existingPackage.name} ' 'have the same root directory: ${newPackage.root}.\n')); break; - case ConflictType.Interleaving: + case ConflictType.interleaving: // The new package is inside the package URI root of the existing // package. onError(PackageConfigArgumentError( @@ -110,7 +110,7 @@ class SimplePackageConfig implements PackageConfig { '${existingPackage.packageUriRoot}\n' '${newPackage.name} root: ${newPackage.root}\n')); break; - case ConflictType.InsidePackageRoot: + case ConflictType.insidePackageRoot: onError(PackageConfigArgumentError( originalPackages, 'packages', @@ -421,7 +421,7 @@ class TrielikePackageTree implements PackageTree { // the same). if (newPackage.root.path.length == existingPackage.root.path.length) { onError(ConflictException( - newPackage, existingPackage, ConflictType.SameRoots)); + newPackage, existingPackage, ConflictType.sameRoots)); return true; } // 2) The existing package has a packageUriRoot thats inside the @@ -429,14 +429,14 @@ class TrielikePackageTree implements PackageTree { if (_beginsWith(0, newPackage.root.toString(), existingPackage.packageUriRoot.toString())) { onError(ConflictException( - newPackage, existingPackage, ConflictType.Interleaving)); + newPackage, existingPackage, ConflictType.interleaving)); return true; } // 3) The new package is inside the packageUriRoot of existing package. if (_beginsWith(0, existingPackage.packageUriRoot.toString(), newPackage.root.toString())) { onError(ConflictException( - newPackage, existingPackage, ConflictType.InsidePackageRoot)); + newPackage, existingPackage, ConflictType.insidePackageRoot)); return true; } } @@ -534,7 +534,7 @@ bool _beginsWith(int start, String parentPath, String longerPath) { return true; } -enum ConflictType { SameRoots, Interleaving, InsidePackageRoot } +enum ConflictType { sameRoots, interleaving, insidePackageRoot } /// Conflict between packages added to the same configuration. /// From a0159d4239e8c5728ba9ab3b1f3920082a376ecb Mon Sep 17 00:00:00 2001 From: Jens Johansen Date: Thu, 25 Nov 2021 11:43:45 +0100 Subject: [PATCH 124/170] Allow inside lib anyway, for internal reasons --- .../lib/src/package_config_impl.dart | 4 ++++ pkgs/package_config/test/parse_test.dart | 21 +++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/pkgs/package_config/lib/src/package_config_impl.dart b/pkgs/package_config/lib/src/package_config_impl.dart index 90862e344..3ae54c2af 100644 --- a/pkgs/package_config/lib/src/package_config_impl.dart +++ b/pkgs/package_config/lib/src/package_config_impl.dart @@ -432,6 +432,9 @@ class TrielikePackageTree implements PackageTree { newPackage, existingPackage, ConflictType.interleaving)); return true; } + /* + For internal reasons we allow this (for now). One should still never do it + though. // 3) The new package is inside the packageUriRoot of existing package. if (_beginsWith(0, existingPackage.packageUriRoot.toString(), newPackage.root.toString())) { @@ -439,6 +442,7 @@ class TrielikePackageTree implements PackageTree { newPackage, existingPackage, ConflictType.insidePackageRoot)); return true; } + */ } return false; } diff --git a/pkgs/package_config/test/parse_test.dart b/pkgs/package_config/test/parse_test.dart index 0a7770d58..174a099e0 100644 --- a/pkgs/package_config/test/parse_test.dart +++ b/pkgs/package_config/test/parse_test.dart @@ -438,12 +438,25 @@ void main() { '{"name":"foo","rootUri":"/foo/","packageUri":"bar/lib/"},' '{"name":"bar","rootUri":"/foo/bar/","packageUri":"baz/lib"}]}', 'package root of foo is inside the root of bar'); - testThrowsContains( - 'root in lib', - '{$cfg,"packages":[' + + // This shouldn't be allowed, but for internal reasons it is. + test("package inside package root", () { + var config = parsePackageConfigBytes( + utf8.encode( + '{$cfg,"packages":[' '{"name":"foo","rootUri":"/foo/","packageUri":"lib/"},' '{"name":"bar","rootUri":"/foo/lib/bar/","packageUri":"lib"}]}', - 'Package bar is inside the package root of package foo'); + ) as Uint8List, + Uri.parse('file:///tmp/.dart_tool/file.dart'), + throwError); + expect( + config + .packageOf(Uri.parse('file:///foo/lib/bar/lib/lala.dart'))! + .name, + 'foo'); // why not bar? + expect(config.toPackageUri(Uri.parse('file:///foo/lib/bar/lib/diz')), + Uri.parse('package:foo/bar/lib/diz')); // why not package:bar/diz? + }); }); }); From 4e5c229f81ec508fa2f8bbcb2ed7b520df05ac50 Mon Sep 17 00:00:00 2001 From: Jens Johansen Date: Thu, 25 Nov 2021 12:33:40 +0100 Subject: [PATCH 125/170] Feedback --- .../lib/src/package_config_impl.dart | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/pkgs/package_config/lib/src/package_config_impl.dart b/pkgs/package_config/lib/src/package_config_impl.dart index 3ae54c2af..86f31db8b 100644 --- a/pkgs/package_config/lib/src/package_config_impl.dart +++ b/pkgs/package_config/lib/src/package_config_impl.dart @@ -8,6 +8,8 @@ import 'util.dart'; export 'package_config.dart'; +const bool _disallowPackagesInsidePackageUriRoot = false; + // Implementations of the main data types exposed by the API of this package. class SimplePackageConfig implements PackageConfig { @@ -432,17 +434,18 @@ class TrielikePackageTree implements PackageTree { newPackage, existingPackage, ConflictType.interleaving)); return true; } - /* - For internal reasons we allow this (for now). One should still never do it - though. + + // For internal reasons we allow this (for now). One should still never do + // it thouh. // 3) The new package is inside the packageUriRoot of existing package. - if (_beginsWith(0, existingPackage.packageUriRoot.toString(), - newPackage.root.toString())) { - onError(ConflictException( - newPackage, existingPackage, ConflictType.insidePackageRoot)); - return true; + if (_disallowPackagesInsidePackageUriRoot) { + if (_beginsWith(0, existingPackage.packageUriRoot.toString(), + newPackage.root.toString())) { + onError(ConflictException( + newPackage, existingPackage, ConflictType.insidePackageRoot)); + return true; + } } - */ } return false; } From a731f2ec5454fbba1c3ebcd26eac76ad5edbf0b3 Mon Sep 17 00:00:00 2001 From: Jens Johansen Date: Thu, 25 Nov 2021 12:35:57 +0100 Subject: [PATCH 126/170] Feedback --- .../lib/src/package_config_impl.dart | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/pkgs/package_config/lib/src/package_config_impl.dart b/pkgs/package_config/lib/src/package_config_impl.dart index 86f31db8b..64bc50a8a 100644 --- a/pkgs/package_config/lib/src/package_config_impl.dart +++ b/pkgs/package_config/lib/src/package_config_impl.dart @@ -384,9 +384,9 @@ abstract class PackageTree { SimplePackage? packageOf(Uri file); } -class _TrielikePackageTreeHelper { +class _PackageTrieNode { SimplePackage? package; - Map map = {}; + Map map = {}; } /// Packages of a package configuration ordered by root path. @@ -402,7 +402,7 @@ class _TrielikePackageTreeHelper { /// root path. /// Entire other packages are allowed inside a package's root. class TrielikePackageTree implements PackageTree { - final Map _map = {}; + final Map _map = {}; /// A list of all packages. final List _packages = []; @@ -414,10 +414,10 @@ class TrielikePackageTree implements PackageTree { } } - bool _checkConflict(_TrielikePackageTreeHelper currentMapHelper, + bool _checkConflict(_PackageTrieNode currentTrieNode, SimplePackage newPackage, void Function(Object error) onError) { - if (currentMapHelper.package != null) { - var existingPackage = currentMapHelper.package!; + if (currentTrieNode.package != null) { + var existingPackage = currentTrieNode.package!; // Trying to add package that is inside the existing package. // 1) If it's an exact match it's not allowed (i.e. the roots can't be // the same). @@ -465,23 +465,23 @@ class TrielikePackageTree implements PackageTree { /// The packages are added in order of their root path. void add(SimplePackage newPackage, void Function(Object error) onError) { var root = newPackage.root; - var currentMapHelper = _map[root.scheme] ??= _TrielikePackageTreeHelper(); - if (_checkConflict(currentMapHelper, newPackage, onError)) return; + var currentTrieNode = _map[root.scheme] ??= _PackageTrieNode(); + if (_checkConflict(currentTrieNode, newPackage, onError)) return; var segments = root.pathSegments; for (var i = 0; i < segments.length - 1; i++) { var path = segments[i]; - currentMapHelper = - currentMapHelper.map[path] ??= _TrielikePackageTreeHelper(); - if (_checkConflict(currentMapHelper, newPackage, onError)) return; + currentTrieNode = + currentTrieNode.map[path] ??= _PackageTrieNode(); + if (_checkConflict(currentTrieNode, newPackage, onError)) return; } - currentMapHelper.package = newPackage; + currentTrieNode.package = newPackage; _packages.add(newPackage); } - bool _isMatch(String path, _TrielikePackageTreeHelper currentMapHelper, + bool _isMatch(String path, _PackageTrieNode currentTrieNode, List potential) { - if (currentMapHelper.package != null) { - var currentPackage = currentMapHelper.package!; + if (currentTrieNode.package != null) { + var currentPackage = currentTrieNode.package!; var currentPackageRootLength = currentPackage.root.toString().length; if (path.length == currentPackageRootLength) return true; var currentPackageUriRoot = currentPackage.packageUriRoot.toString(); @@ -497,21 +497,21 @@ class TrielikePackageTree implements PackageTree { @override SimplePackage? packageOf(Uri file) { - var currentMapHelper = _map[file.scheme]; - if (currentMapHelper == null) return null; + var currentTrieNode = _map[file.scheme]; + if (currentTrieNode == null) return null; var path = file.toString(); var potential = []; - if (_isMatch(path, currentMapHelper, potential)) { - return currentMapHelper.package; + if (_isMatch(path, currentTrieNode, potential)) { + return currentTrieNode.package; } var segments = file.pathSegments; for (var i = 0; i < segments.length - 1; i++) { var segment = segments[i]; - currentMapHelper = currentMapHelper!.map[segment]; - if (currentMapHelper == null) break; - if (_isMatch(path, currentMapHelper, potential)) { - return currentMapHelper.package; + currentTrieNode = currentTrieNode!.map[segment]; + if (currentTrieNode == null) break; + if (_isMatch(path, currentTrieNode, potential)) { + return currentTrieNode.package; } } if (potential.isEmpty) return null; From b280a3ed9a444102f14808592dcf040c286a1270 Mon Sep 17 00:00:00 2001 From: Jens Johansen Date: Thu, 25 Nov 2021 12:37:42 +0100 Subject: [PATCH 127/170] Formatting --- pkgs/package_config/lib/src/package_config_impl.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkgs/package_config/lib/src/package_config_impl.dart b/pkgs/package_config/lib/src/package_config_impl.dart index 64bc50a8a..9966bb088 100644 --- a/pkgs/package_config/lib/src/package_config_impl.dart +++ b/pkgs/package_config/lib/src/package_config_impl.dart @@ -470,8 +470,7 @@ class TrielikePackageTree implements PackageTree { var segments = root.pathSegments; for (var i = 0; i < segments.length - 1; i++) { var path = segments[i]; - currentTrieNode = - currentTrieNode.map[path] ??= _PackageTrieNode(); + currentTrieNode = currentTrieNode.map[path] ??= _PackageTrieNode(); if (_checkConflict(currentTrieNode, newPackage, onError)) return; } currentTrieNode.package = newPackage; From fd7708b60bc8e8792cc1fb9af9f9408c75494bea Mon Sep 17 00:00:00 2001 From: Jens Johansen Date: Thu, 25 Nov 2021 15:11:35 +0100 Subject: [PATCH 128/170] feedback --- .../lib/src/package_config_impl.dart | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/pkgs/package_config/lib/src/package_config_impl.dart b/pkgs/package_config/lib/src/package_config_impl.dart index 9966bb088..aef817664 100644 --- a/pkgs/package_config/lib/src/package_config_impl.dart +++ b/pkgs/package_config/lib/src/package_config_impl.dart @@ -56,7 +56,7 @@ class SimplePackageConfig implements PackageConfig { static PackageTree _validatePackages(Iterable originalPackages, List packages, void Function(Object error) onError) { var packageNames = {}; - var tree = TrielikePackageTree(); + var tree = TriePackageTree(); for (var originalPackage in packages) { SimplePackage? newPackage; if (originalPackage is! SimplePackage) { @@ -386,6 +386,8 @@ abstract class PackageTree { class _PackageTrieNode { SimplePackage? package; + + /// Indexed by path segment. Map map = {}; } @@ -401,7 +403,8 @@ class _PackageTrieNode { /// The package root path of a package must not be inside another package's /// root path. /// Entire other packages are allowed inside a package's root. -class TrielikePackageTree implements PackageTree { +class TriePackageTree implements PackageTree { + /// Indexed by URI scheme. final Map _map = {}; /// A list of all packages. @@ -414,10 +417,10 @@ class TrielikePackageTree implements PackageTree { } } - bool _checkConflict(_PackageTrieNode currentTrieNode, - SimplePackage newPackage, void Function(Object error) onError) { - if (currentTrieNode.package != null) { - var existingPackage = currentTrieNode.package!; + bool _checkConflict(_PackageTrieNode node, SimplePackage newPackage, + void Function(Object error) onError) { + var existingPackage = node.package; + if (existingPackage != null) { // Trying to add package that is inside the existing package. // 1) If it's an exact match it's not allowed (i.e. the roots can't be // the same). @@ -465,26 +468,28 @@ class TrielikePackageTree implements PackageTree { /// The packages are added in order of their root path. void add(SimplePackage newPackage, void Function(Object error) onError) { var root = newPackage.root; - var currentTrieNode = _map[root.scheme] ??= _PackageTrieNode(); - if (_checkConflict(currentTrieNode, newPackage, onError)) return; + var node = _map[root.scheme] ??= _PackageTrieNode(); + if (_checkConflict(node, newPackage, onError)) return; var segments = root.pathSegments; + // Notice that we're skipping the last segment as it's always the empty + // string because roots are directories. for (var i = 0; i < segments.length - 1; i++) { var path = segments[i]; - currentTrieNode = currentTrieNode.map[path] ??= _PackageTrieNode(); - if (_checkConflict(currentTrieNode, newPackage, onError)) return; + node = node.map[path] ??= _PackageTrieNode(); + if (_checkConflict(node, newPackage, onError)) return; } - currentTrieNode.package = newPackage; + node.package = newPackage; _packages.add(newPackage); } - bool _isMatch(String path, _PackageTrieNode currentTrieNode, - List potential) { - if (currentTrieNode.package != null) { - var currentPackage = currentTrieNode.package!; + bool _isMatch( + String path, _PackageTrieNode node, List potential) { + var currentPackage = node.package; + if (currentPackage != null) { var currentPackageRootLength = currentPackage.root.toString().length; if (path.length == currentPackageRootLength) return true; var currentPackageUriRoot = currentPackage.packageUriRoot.toString(); - // Is [file] is inside the package root of [currentPackage]? + // Is [file] inside the package root of [currentPackage]? if (currentPackageUriRoot.length == currentPackageRootLength || _beginsWith(currentPackageRootLength, currentPackageUriRoot, path)) { return true; From 7095a039c0953341dc3176360091326913cba628 Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Mon, 31 Jan 2022 10:26:28 -0800 Subject: [PATCH 129/170] Preemptively bump to a -dev version (dart-lang/package_config#118) The code in the repo has diverged from what was published in `2.0.2` so we don't want the pubspec to still have that version. There are no user facing changes. --- pkgs/package_config/CHANGELOG.md | 2 ++ pkgs/package_config/pubspec.yaml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index c85ac5011..8c58fbb63 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -1,3 +1,5 @@ +## 2.0.3-dev + ## 2.0.2 - Update package description and README. diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 6f80473c9..def12cbb7 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 2.0.2 +version: 2.0.3-dev description: Support for reading and writing Dart Package Configuration files. homepage: https://github.com/dart-lang/package_config From 66077cdbaa04489f86d4b14d2123519928f4db6e Mon Sep 17 00:00:00 2001 From: Jonas Finnemann Jensen Date: Mon, 7 Feb 2022 13:14:18 +0100 Subject: [PATCH 130/170] Fix broken link for language-versioning spec (dart-lang/package_config#120) Thanks! And yes, it's an issue that files do not have permalinks, but we also do want to use the hierarchical structure of the repo for placing them where they belong, and we don't want to keep copies around, because that risks older copies being stale. No good solution found. (If only you could tag files and refer to them by tag.) --- pkgs/package_config/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/package_config/README.md b/pkgs/package_config/README.md index 15ed4f6b2..712a23c80 100644 --- a/pkgs/package_config/README.md +++ b/pkgs/package_config/README.md @@ -2,7 +2,7 @@ [![pub package](https://img.shields.io/pub/v/package_config.svg)](https://pub.dev/packages/package_config) Support for working with **Package Configuration** files as described -in the Package Configuration v2 [design document](https://github.com/dart-lang/language/blob/master/accepted/future-releases/language-versioning/package-config-file-v2.md). +in the Package Configuration v2 [design document](https://github.com/dart-lang/language/blob/master/accepted/2.8/language-versioning/package-config-file-v2.md). A Dart package configuration file is used to resolve Dart package names (e.g. `foobar`) to Dart files containing the source code for that package (e.g. From fcea93be4967077f73dba731aa7f04728f0e2229 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 2 Mar 2022 11:16:35 -0800 Subject: [PATCH 131/170] Bump actions/checkout from 2 to 3 (dart-lang/package_config#122) Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v2...v3) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pkgs/package_config/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/package_config/.github/workflows/test-package.yml b/pkgs/package_config/.github/workflows/test-package.yml index 33bf62bd9..3db1d6c24 100644 --- a/pkgs/package_config/.github/workflows/test-package.yml +++ b/pkgs/package_config/.github/workflows/test-package.yml @@ -22,7 +22,7 @@ jobs: matrix: sdk: [dev] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: dart-lang/setup-dart@v1 with: sdk: ${{ matrix.sdk }} @@ -49,7 +49,7 @@ jobs: os: [ubuntu-latest] sdk: [2.12.0, dev] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: dart-lang/setup-dart@v1 with: sdk: ${{ matrix.sdk }} From 87732e1abedb65a30fc357a5bace952a8f34e88c Mon Sep 17 00:00:00 2001 From: Devon Carew Date: Mon, 2 May 2022 10:06:06 -0700 Subject: [PATCH 132/170] Update pubspec.yaml (dart-lang/package_config#123) --- pkgs/package_config/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index def12cbb7..d4ed6b94f 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,7 +1,7 @@ name: package_config version: 2.0.3-dev description: Support for reading and writing Dart Package Configuration files. -homepage: https://github.com/dart-lang/package_config +repository: https://github.com/dart-lang/package_config environment: sdk: '>=2.12.0 <3.0.0' From 43742539e3a04673f79fe68842a4285ce58eb8c1 Mon Sep 17 00:00:00 2001 From: Devon Carew Date: Thu, 19 May 2022 03:03:04 +0000 Subject: [PATCH 133/170] prep for publishing 2.0.3 --- pkgs/package_config/CHANGELOG.md | 6 +++++- pkgs/package_config/README.md | 1 + pkgs/package_config/pubspec.yaml | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index 8c58fbb63..4e095f2b0 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -1,4 +1,8 @@ -## 2.0.3-dev +## 2.0.3 + +- Improve file read performance; improve lookup performance. +- Emit an error when a package is inside the package root of another package. +- Fix a link in the readme. ## 2.0.2 diff --git a/pkgs/package_config/README.md b/pkgs/package_config/README.md index 712a23c80..9e2e41f0b 100644 --- a/pkgs/package_config/README.md +++ b/pkgs/package_config/README.md @@ -1,5 +1,6 @@ [![Build Status](https://github.com/dart-lang/package_config/workflows/Dart%20CI/badge.svg)](https://github.com/dart-lang/package_config/actions?query=workflow%3A"Dart+CI"+branch%3Amaster) [![pub package](https://img.shields.io/pub/v/package_config.svg)](https://pub.dev/packages/package_config) +[![package publisher](https://img.shields.io/pub/publisher/package_config.svg)](https://pub.dev/packages/package_config/publisher) Support for working with **Package Configuration** files as described in the Package Configuration v2 [design document](https://github.com/dart-lang/language/blob/master/accepted/2.8/language-versioning/package-config-file-v2.md). diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index d4ed6b94f..ea0f3b456 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 2.0.3-dev +version: 2.0.3 description: Support for reading and writing Dart Package Configuration files. repository: https://github.com/dart-lang/package_config From 20062b37f8a62b521bcbe1f4f2c300b25f4efcb1 Mon Sep 17 00:00:00 2001 From: Devon Carew Date: Fri, 20 May 2022 18:59:01 +0000 Subject: [PATCH 134/170] revert version change --- pkgs/package_config/CHANGELOG.md | 2 +- pkgs/package_config/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index 4e095f2b0..9ecfe22b3 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -1,4 +1,4 @@ -## 2.0.3 +## 2.0.3-dev - Improve file read performance; improve lookup performance. - Emit an error when a package is inside the package root of another package. diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index ea0f3b456..d4ed6b94f 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 2.0.3 +version: 2.0.3-dev description: Support for reading and writing Dart Package Configuration files. repository: https://github.com/dart-lang/package_config From cd86f83cbd32bfe7221b3265b5516ea8e0b38756 Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Mon, 23 May 2022 16:01:41 +0200 Subject: [PATCH 135/170] Adds `minVersion` to `findPackageConfig{,Uri}` methods. (dart-lang/package_config#125) * Adds `minVersion` to `findPackageConfig{,Uri}` methods. This parameter currently allows you to ignore `.packages` files while searching for a configuration file. If we later add a version 3 of the configuration, it should also allow ignoring version 2 configurations. --- pkgs/package_config/CHANGELOG.md | 9 +++- pkgs/package_config/lib/package_config.dart | 34 +++++++++++--- pkgs/package_config/lib/src/discovery.dart | 47 +++++++++++++------ .../lib/src/package_config.dart | 2 +- .../lib/src/package_config_impl.dart | 5 +- pkgs/package_config/pubspec.yaml | 2 +- pkgs/package_config/test/discovery_test.dart | 26 ++++++++++ .../test/discovery_uri_test.dart | 27 +++++++++++ 8 files changed, 127 insertions(+), 25 deletions(-) diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index 9ecfe22b3..b6e91bbd3 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -1,4 +1,11 @@ -## 2.0.3-dev +## 2.1.0 + +- Adds `minVersion` to `findPackageConfig` and `findPackageConfigVersion` + which allows ignoring earlier versions (which currently only means + ignoring version 1, aka. `.packages` files.) + +- Changes the version number of `SimplePackageConfig.empty` to the + current maximum version. - Improve file read performance; improve lookup performance. - Emit an error when a package is inside the package root of another package. diff --git a/pkgs/package_config/lib/package_config.dart b/pkgs/package_config/lib/package_config.dart index bd227e4e5..a2c0321b8 100644 --- a/pkgs/package_config/lib/package_config.dart +++ b/pkgs/package_config/lib/package_config.dart @@ -111,10 +111,21 @@ Future loadPackageConfigUri(Uri file, /// a valid configuration from the invalid configuration file. /// If no [onError] is provided, errors are thrown immediately. /// +/// If [minVersion] is set to something greater than its default, +/// any lower-version configuration files are ignored in the search. +/// /// Returns `null` if no configuration file is found. Future findPackageConfig(Directory directory, - {bool recurse = true, void Function(Object error)? onError}) => - discover.findPackageConfig(directory, recurse, onError ?? throwError); + {bool recurse = true, + void Function(Object error)? onError, + int minVersion = 1}) { + if (minVersion > PackageConfig.maxVersion) { + throw ArgumentError.value(minVersion, 'minVersion', + 'Maximum known version is ${PackageConfig.maxVersion}'); + } + return discover.findPackageConfig( + directory, minVersion, recurse, onError ?? throwError); +} /// Finds a package configuration relative to [location]. /// @@ -155,13 +166,22 @@ Future findPackageConfig(Directory directory, /// a valid configuration from the invalid configuration file. /// If no [onError] is provided, errors are thrown immediately. /// +/// If [minVersion] is set to something greater than its default, +/// any lower-version configuration files are ignored in the search. +/// /// Returns `null` if no configuration file is found. Future findPackageConfigUri(Uri location, - {bool recurse = true, - Future Function(Uri uri)? loader, - void Function(Object error)? onError}) => - discover.findPackageConfigUri( - location, loader, onError ?? throwError, recurse); + {bool recurse = true, + int minVersion = 1, + Future Function(Uri uri)? loader, + void Function(Object error)? onError}) { + if (minVersion > PackageConfig.maxVersion) { + throw ArgumentError.value(minVersion, 'minVersion', + 'Maximum known version is ${PackageConfig.maxVersion}'); + } + return discover.findPackageConfigUri( + location, minVersion, loader, onError ?? throwError, recurse); +} /// Writes a package configuration to the provided directory. /// diff --git a/pkgs/package_config/lib/src/discovery.dart b/pkgs/package_config/lib/src/discovery.dart index a6cc451f2..ccc86ea23 100644 --- a/pkgs/package_config/lib/src/discovery.dart +++ b/pkgs/package_config/lib/src/discovery.dart @@ -25,15 +25,20 @@ final Uri parentPath = Uri(path: '..'); /// and stopping when something is found. /// /// * Check if a `.dart_tool/package_config.json` file exists in the directory. -/// * Check if a `.packages` file exists in the directory. +/// * Check if a `.packages` file exists in the directory +/// (if `minVersion <= 1`). /// * Repeat these checks for the parent directories until reaching the /// root directory if [recursive] is true. /// /// If any of these tests succeed, a `PackageConfig` class is returned. /// Returns `null` if no configuration was found. If a configuration /// is needed, then the caller can supply [PackageConfig.empty]. +/// +/// If [minVersion] is greated than 1, `.packages` files are ignored. +/// If [minVersion] is greater than the version read from the +/// `package_config.json` file, it too is ignored. Future findPackageConfig(Directory baseDirectory, - bool recursive, void Function(Object error) onError) async { + int minVersion, bool recursive, void Function(Object error) onError) async { var directory = baseDirectory; if (!directory.isAbsolute) directory = directory.absolute; if (!await directory.exists()) { @@ -41,7 +46,8 @@ Future findPackageConfig(Directory baseDirectory, } do { // Check for $cwd/.packages - var packageConfig = await findPackagConfigInDirectory(directory, onError); + var packageConfig = + await findPackagConfigInDirectory(directory, minVersion, onError); if (packageConfig != null) return packageConfig; if (!recursive) break; // Check in parent directories. @@ -55,6 +61,7 @@ Future findPackageConfig(Directory baseDirectory, /// Similar to [findPackageConfig] but based on a URI. Future findPackageConfigUri( Uri location, + int minVersion, Future Function(Uri uri)? loader, void Function(Object error) onError, bool recursive) async { @@ -67,6 +74,7 @@ Future findPackageConfigUri( if (location.isScheme('file')) { return findPackageConfig( Directory.fromUri(location.resolveUri(currentPath)), + minVersion, recursive, onError); } @@ -77,12 +85,15 @@ Future findPackageConfigUri( var file = location.resolveUri(packageConfigJsonPath); var bytes = await loader(file); if (bytes != null) { - return parsePackageConfigBytes(bytes, file, onError); + var config = parsePackageConfigBytes(bytes, file, onError); + if (config.version >= minVersion) return config; } - file = location.resolveUri(dotPackagesPath); - bytes = await loader(file); - if (bytes != null) { - return packages_file.parse(bytes, file, onError); + if (minVersion <= 1) { + file = location.resolveUri(dotPackagesPath); + bytes = await loader(file); + if (bytes != null) { + return packages_file.parse(bytes, file, onError); + } } if (!recursive) break; var parent = location.resolveUri(parentPath); @@ -102,15 +113,23 @@ Future findPackageConfigUri( /// If [onError] is supplied, parsing errors are reported using that, and /// a best-effort attempt is made to return a package configuration. /// This may be the empty package configuration. -Future findPackagConfigInDirectory( - Directory directory, void Function(Object error) onError) async { +/// +/// If [minVersion] is greated than 1, `.packages` files are ignored. +/// If [minVersion] is greater than the version read from the +/// `package_config.json` file, it too is ignored. +Future findPackagConfigInDirectory(Directory directory, + int minVersion, void Function(Object error) onError) async { var packageConfigFile = await checkForPackageConfigJsonFile(directory); if (packageConfigFile != null) { - return await readPackageConfigJsonFile(packageConfigFile, onError); + var config = await readPackageConfigJsonFile(packageConfigFile, onError); + if (config.version < minVersion) return null; + return config; } - packageConfigFile = await checkForDotPackagesFile(directory); - if (packageConfigFile != null) { - return await readDotPackagesFile(packageConfigFile, onError); + if (minVersion <= 1) { + packageConfigFile = await checkForDotPackagesFile(directory); + if (packageConfigFile != null) { + return await readDotPackagesFile(packageConfigFile, onError); + } } return null; } diff --git a/pkgs/package_config/lib/src/package_config.dart b/pkgs/package_config/lib/src/package_config.dart index 3c5cc5196..ba52c147d 100644 --- a/pkgs/package_config/lib/src/package_config.dart +++ b/pkgs/package_config/lib/src/package_config.dart @@ -39,7 +39,7 @@ abstract class PackageConfig { /// including the two paths being the same. /// /// * No package's root must be the same as another package's root. - /// * The package-root of a package must be inside the pacakge's root. + /// * The package-root of a package must be inside the package's root. /// * If one package's package-root is inside another package's root, /// then the latter package's package root must not be inside the former /// package's root. (No getting between a package and its package root!) diff --git a/pkgs/package_config/lib/src/package_config_impl.dart b/pkgs/package_config/lib/src/package_config_impl.dart index aef817664..4c8f23443 100644 --- a/pkgs/package_config/lib/src/package_config_impl.dart +++ b/pkgs/package_config/lib/src/package_config_impl.dart @@ -37,8 +37,11 @@ class SimplePackageConfig implements PackageConfig { /// /// The empty configuration can be used in cases where no configuration is /// found, but code expects a non-null configuration. + /// + /// The version number is [PackageConfig.maxVersion] to avoid + /// minimum-version filters discarding the configuration. const SimplePackageConfig.empty() - : version = 1, + : version = PackageConfig.maxVersion, _packageTree = const EmptyPackageTree(), _packages = const {}, extraData = null; diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index d4ed6b94f..56e30b5df 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 2.0.3-dev +version: 2.1.0 description: Support for reading and writing Dart Package Configuration files. repository: https://github.com/dart-lang/package_config diff --git a/pkgs/package_config/test/discovery_test.dart b/pkgs/package_config/test/discovery_test.dart index 4a1bba0a6..17b6aa099 100644 --- a/pkgs/package_config/test/discovery_test.dart +++ b/pkgs/package_config/test/discovery_test.dart @@ -201,6 +201,32 @@ void main() { expect(hadError, true); }); }); + + // Does not find .packages if no package_config.json and minVersion > 1. + fileTest('.packages ignored', { + '.packages': packagesFile, + 'script.dart': 'main(){}' + }, (Directory directory) async { + var config = (await findPackageConfig(directory, minVersion: 2)); + expect(config, null); + }); + + // Finds package_config.json in super-directory, with .packages in + // subdir and minVersion > 1. + fileTest('package_config.json recursive .packages ignored', { + '.dart_tool': { + 'package_config.json': packageConfigFile, + }, + 'subdir': { + '.packages': packagesFile, + 'script.dart': 'main(){}', + } + }, (Directory directory) async { + var config = (await findPackageConfig(subdir(directory, 'subdir/'), + minVersion: 2))!; + expect(config.version, 2); + validatePackagesFile(config, directory); + }); }); group('loadPackageConfig', () { diff --git a/pkgs/package_config/test/discovery_uri_test.dart b/pkgs/package_config/test/discovery_uri_test.dart index e487e471d..6183ce3ba 100644 --- a/pkgs/package_config/test/discovery_uri_test.dart +++ b/pkgs/package_config/test/discovery_uri_test.dart @@ -145,6 +145,33 @@ void main() { expect(() => findPackageConfigUri(directory, loader: loader), throwsA(TypeMatcher())); }); + + // Does not find .packages if no package_config.json and minVersion > 1. + loaderTest('.packages ignored', { + '.packages': packagesFile, + 'script.dart': 'main(){}' + }, (directory, loader) async { + var config = (await findPackageConfigUri(directory, + minVersion: 2, loader: loader)); + expect(config, null); + }); + + // Finds package_config.json in super-directory, with .packages in + // subdir and minVersion > 1. + loaderTest('package_config.json recursive ignores .packages', { + '.dart_tool': { + 'package_config.json': packageConfigFile, + }, + 'subdir': { + '.packages': packagesFile, + 'script.dart': 'main(){}', + } + }, (directory, loader) async { + var config = (await findPackageConfigUri(directory.resolve('subdir/'), + minVersion: 2, loader: loader))!; + expect(config.version, 2); + validatePackagesFile(config, directory); + }); }); group('loadPackageConfig', () { From 8c91bc23a9602502e8756dfd83bb2c25c3fb7baa Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Tue, 15 Nov 2022 12:29:53 -0800 Subject: [PATCH 136/170] blast_repo fixes (dart-lang/package_config#127) Dependabot GitHub Action --- pkgs/package_config/.github/dependabot.yml | 7 +++---- pkgs/package_config/.github/workflows/test-package.yml | 8 ++++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/pkgs/package_config/.github/dependabot.yml b/pkgs/package_config/.github/dependabot.yml index 430a85e7d..b2f1dec5a 100644 --- a/pkgs/package_config/.github/dependabot.yml +++ b/pkgs/package_config/.github/dependabot.yml @@ -4,8 +4,7 @@ version: 2 updates: -- package-ecosystem: "github-actions" - directory: "/" +- package-ecosystem: github-actions + directory: / schedule: - # Check for updates to GitHub Actions every weekday - interval: "daily" + interval: monthly diff --git a/pkgs/package_config/.github/workflows/test-package.yml b/pkgs/package_config/.github/workflows/test-package.yml index 3db1d6c24..6b28e8555 100644 --- a/pkgs/package_config/.github/workflows/test-package.yml +++ b/pkgs/package_config/.github/workflows/test-package.yml @@ -22,8 +22,8 @@ jobs: matrix: sdk: [dev] steps: - - uses: actions/checkout@v3 - - uses: dart-lang/setup-dart@v1 + - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + - uses: dart-lang/setup-dart@6a218f2413a3e78e9087f638a238f6b40893203d with: sdk: ${{ matrix.sdk }} - id: install @@ -49,8 +49,8 @@ jobs: os: [ubuntu-latest] sdk: [2.12.0, dev] steps: - - uses: actions/checkout@v3 - - uses: dart-lang/setup-dart@v1 + - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + - uses: dart-lang/setup-dart@6a218f2413a3e78e9087f638a238f6b40893203d with: sdk: ${{ matrix.sdk }} - id: install From ca63b528422112514abc5c124b9c436f4ccb7576 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Jan 2023 09:33:39 -0800 Subject: [PATCH 137/170] Bump actions/checkout from 3.1.0 to 3.2.0 (dart-lang/package_config#128) Bumps [actions/checkout](https://github.com/actions/checkout) from 3.1.0 to 3.2.0. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8...755da8c3cf115ac066823e79a1e1788f8940201b) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pkgs/package_config/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/package_config/.github/workflows/test-package.yml b/pkgs/package_config/.github/workflows/test-package.yml index 6b28e8555..9c89e08ce 100644 --- a/pkgs/package_config/.github/workflows/test-package.yml +++ b/pkgs/package_config/.github/workflows/test-package.yml @@ -22,7 +22,7 @@ jobs: matrix: sdk: [dev] steps: - - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + - uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b - uses: dart-lang/setup-dart@6a218f2413a3e78e9087f638a238f6b40893203d with: sdk: ${{ matrix.sdk }} @@ -49,7 +49,7 @@ jobs: os: [ubuntu-latest] sdk: [2.12.0, dev] steps: - - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + - uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b - uses: dart-lang/setup-dart@6a218f2413a3e78e9087f638a238f6b40893203d with: sdk: ${{ matrix.sdk }} From 681f007bdc748d94b1730624659d3d5725d3ec3b Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Mon, 30 Jan 2023 09:23:49 -0800 Subject: [PATCH 138/170] Support latest pkg:build_web_compilers, lints. Update min SDK (dart-lang/package_config#129) --- pkgs/package_config/.github/workflows/test-package.yml | 2 +- pkgs/package_config/CHANGELOG.md | 4 ++++ pkgs/package_config/lib/src/package_config_impl.dart | 2 +- pkgs/package_config/lib/src/package_config_json.dart | 4 ++-- pkgs/package_config/lib/src/packages_file.dart | 2 +- pkgs/package_config/lib/src/util.dart | 4 ++-- pkgs/package_config/pubspec.yaml | 8 ++++---- pkgs/package_config/test/parse_test.dart | 2 +- 8 files changed, 16 insertions(+), 12 deletions(-) diff --git a/pkgs/package_config/.github/workflows/test-package.yml b/pkgs/package_config/.github/workflows/test-package.yml index 9c89e08ce..b28046588 100644 --- a/pkgs/package_config/.github/workflows/test-package.yml +++ b/pkgs/package_config/.github/workflows/test-package.yml @@ -47,7 +47,7 @@ jobs: matrix: # Add macos-latest and/or windows-latest if relevant for this package. os: [ubuntu-latest] - sdk: [2.12.0, dev] + sdk: [2.18.0, dev] steps: - uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b - uses: dart-lang/setup-dart@6a218f2413a3e78e9087f638a238f6b40893203d diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index b6e91bbd3..62ef87d6e 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.1.1-dev + +- Require Dart 2.18 + ## 2.1.0 - Adds `minVersion` to `findPackageConfig` and `findPackageConfigVersion` diff --git a/pkgs/package_config/lib/src/package_config_impl.dart b/pkgs/package_config/lib/src/package_config_impl.dart index 4c8f23443..f832d6adf 100644 --- a/pkgs/package_config/lib/src/package_config_impl.dart +++ b/pkgs/package_config/lib/src/package_config_impl.dart @@ -244,7 +244,7 @@ class SimplePackage implements Package { if (!root.hasScheme) { fatalError = true; } else if (!root.path.endsWith('/')) { - root = root.replace(path: root.path + '/'); + root = root.replace(path: '${root.path}/'); } } if (packageUriRoot == null) { diff --git a/pkgs/package_config/lib/src/package_config_json.dart b/pkgs/package_config/lib/src/package_config_json.dart index fe185a2ea..bd22db4ec 100644 --- a/pkgs/package_config/lib/src/package_config_json.dart +++ b/pkgs/package_config/lib/src/package_config_json.dart @@ -149,11 +149,11 @@ PackageConfig parsePackageConfigJson( var parsedRootUri = Uri.parse(rootUri!); var relativeRoot = !hasAbsolutePath(parsedRootUri); var root = baseLocation.resolveUri(parsedRootUri); - if (!root.path.endsWith('/')) root = root.replace(path: root.path + '/'); + if (!root.path.endsWith('/')) root = root.replace(path: '${root.path}/'); var packageRoot = root; if (packageUri != null) packageRoot = root.resolve(packageUri!); if (!packageRoot.path.endsWith('/')) { - packageRoot = packageRoot.replace(path: packageRoot.path + '/'); + packageRoot = packageRoot.replace(path: '${packageRoot.path}/'); } LanguageVersion? version; diff --git a/pkgs/package_config/lib/src/packages_file.dart b/pkgs/package_config/lib/src/packages_file.dart index 244663326..3fd7db9b5 100644 --- a/pkgs/package_config/lib/src/packages_file.dart +++ b/pkgs/package_config/lib/src/packages_file.dart @@ -192,7 +192,7 @@ void write(StringSink output, PackageConfig config, uri = relativizeUri(uri, baseUri)!; } if (!uri.path.endsWith('/')) { - uri = uri.replace(path: uri.path + '/'); + uri = uri.replace(path: '${uri.path}/'); } output.write(uri); output.writeln(); diff --git a/pkgs/package_config/lib/src/util.dart b/pkgs/package_config/lib/src/util.dart index 61488ac41..3bf1bece3 100644 --- a/pkgs/package_config/lib/src/util.dart +++ b/pkgs/package_config/lib/src/util.dart @@ -89,7 +89,7 @@ String checkValidPackageUri(Uri packageUri, String name) { } assert(badIndex < packageName.length); var badCharCode = packageName.codeUnitAt(badIndex); - var badChar = 'U+' + badCharCode.toRadixString(16).padLeft(4, '0'); + var badChar = 'U+${badCharCode.toRadixString(16).padLeft(4, '0')}'; if (badCharCode >= 0x20 && badCharCode <= 0x7e) { // Printable character. badChar = "'${packageName[badIndex]}' ($badChar)"; @@ -140,7 +140,7 @@ int firstNonWhitespaceChar(List bytes) { /// Appends a trailing `/` if the path doesn't end with one. String trailingSlash(String path) { if (path.isEmpty || path.endsWith('/')) return path; - return path + '/'; + return '$path/'; } /// Whether a URI should not be considered relative to the base URI. diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 56e30b5df..08255ffa9 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,10 +1,10 @@ name: package_config -version: 2.1.0 +version: 2.1.1-dev description: Support for reading and writing Dart Package Configuration files. repository: https://github.com/dart-lang/package_config environment: - sdk: '>=2.12.0 <3.0.0' + sdk: '>=2.18.0 <3.0.0' dependencies: path: ^1.8.0 @@ -12,6 +12,6 @@ dependencies: dev_dependencies: build_runner: ^2.0.0 build_test: ^2.1.2 - build_web_compilers: ^3.0.0 - lints: ^1.0.0 + build_web_compilers: '>=3.0.0 <5.0.0' + lints: ^2.0.0 test: ^1.16.0 diff --git a/pkgs/package_config/test/parse_test.dart b/pkgs/package_config/test/parse_test.dart index 174a099e0..94269e20f 100644 --- a/pkgs/package_config/test/parse_test.dart +++ b/pkgs/package_config/test/parse_test.dart @@ -56,7 +56,7 @@ void main() { () => packages.parse(utf8.encode(content), baseFile, throwError), throwsA(TypeMatcher())); }); - test(name + ', handle error', () { + test('$name, handle error', () { var hadError = false; packages.parse(utf8.encode(content), baseFile, (error) { hadError = true; From f4e80817eb0b9ae444833887a510ca1c6eee39f1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Feb 2023 12:37:33 -0800 Subject: [PATCH 139/170] Bump actions/checkout from 3.2.0 to 3.3.0 (dart-lang/package_config#131) Bumps [actions/checkout](https://github.com/actions/checkout) from 3.2.0 to 3.3.0. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/755da8c3cf115ac066823e79a1e1788f8940201b...ac593985615ec2ede58e132d2e21d2b1cbd6127c) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pkgs/package_config/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/package_config/.github/workflows/test-package.yml b/pkgs/package_config/.github/workflows/test-package.yml index b28046588..0123c53bb 100644 --- a/pkgs/package_config/.github/workflows/test-package.yml +++ b/pkgs/package_config/.github/workflows/test-package.yml @@ -22,7 +22,7 @@ jobs: matrix: sdk: [dev] steps: - - uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c - uses: dart-lang/setup-dart@6a218f2413a3e78e9087f638a238f6b40893203d with: sdk: ${{ matrix.sdk }} @@ -49,7 +49,7 @@ jobs: os: [ubuntu-latest] sdk: [2.18.0, dev] steps: - - uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c - uses: dart-lang/setup-dart@6a218f2413a3e78e9087f638a238f6b40893203d with: sdk: ${{ matrix.sdk }} From 6adef6143472173f725497c02cc895a44ad31041 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Feb 2023 12:42:17 -0800 Subject: [PATCH 140/170] Bump dart-lang/setup-dart from 1.3 to 1.4 (dart-lang/package_config#130) Bumps [dart-lang/setup-dart](https://github.com/dart-lang/setup-dart) from 1.3 to 1.4. - [Release notes](https://github.com/dart-lang/setup-dart/releases) - [Changelog](https://github.com/dart-lang/setup-dart/blob/main/CHANGELOG.md) - [Commits](https://github.com/dart-lang/setup-dart/compare/6a218f2413a3e78e9087f638a238f6b40893203d...a57a6c04cf7d4840e88432aad6281d1e125f0d46) --- updated-dependencies: - dependency-name: dart-lang/setup-dart dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pkgs/package_config/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/package_config/.github/workflows/test-package.yml b/pkgs/package_config/.github/workflows/test-package.yml index 0123c53bb..2fdd91f4e 100644 --- a/pkgs/package_config/.github/workflows/test-package.yml +++ b/pkgs/package_config/.github/workflows/test-package.yml @@ -23,7 +23,7 @@ jobs: sdk: [dev] steps: - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c - - uses: dart-lang/setup-dart@6a218f2413a3e78e9087f638a238f6b40893203d + - uses: dart-lang/setup-dart@a57a6c04cf7d4840e88432aad6281d1e125f0d46 with: sdk: ${{ matrix.sdk }} - id: install @@ -50,7 +50,7 @@ jobs: sdk: [2.18.0, dev] steps: - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c - - uses: dart-lang/setup-dart@6a218f2413a3e78e9087f638a238f6b40893203d + - uses: dart-lang/setup-dart@a57a6c04cf7d4840e88432aad6281d1e125f0d46 with: sdk: ${{ matrix.sdk }} - id: install From 1debd19e12803969fdb8c8b7b7e2580c8da21a1b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Apr 2023 14:39:09 -0700 Subject: [PATCH 141/170] Bump actions/checkout from 3.3.0 to 3.5.0 (dart-lang/package_config#133) Bumps [actions/checkout](https://github.com/actions/checkout) from 3.3.0 to 3.5.0. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/ac593985615ec2ede58e132d2e21d2b1cbd6127c...8f4b7f84864484a7bf31766abe9204da3cbe65b3) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pkgs/package_config/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/package_config/.github/workflows/test-package.yml b/pkgs/package_config/.github/workflows/test-package.yml index 2fdd91f4e..8ca52ec84 100644 --- a/pkgs/package_config/.github/workflows/test-package.yml +++ b/pkgs/package_config/.github/workflows/test-package.yml @@ -22,7 +22,7 @@ jobs: matrix: sdk: [dev] steps: - - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c + - uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 - uses: dart-lang/setup-dart@a57a6c04cf7d4840e88432aad6281d1e125f0d46 with: sdk: ${{ matrix.sdk }} @@ -49,7 +49,7 @@ jobs: os: [ubuntu-latest] sdk: [2.18.0, dev] steps: - - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c + - uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 - uses: dart-lang/setup-dart@a57a6c04cf7d4840e88432aad6281d1e125f0d46 with: sdk: ${{ matrix.sdk }} From df5710bafce012c8b492f8a4d554d77e4feb944f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Apr 2023 14:54:23 -0700 Subject: [PATCH 142/170] Bump dart-lang/setup-dart from 1.4.0 to 1.5.0 (dart-lang/package_config#132) Bumps [dart-lang/setup-dart](https://github.com/dart-lang/setup-dart) from 1.4.0 to 1.5.0. - [Release notes](https://github.com/dart-lang/setup-dart/releases) - [Changelog](https://github.com/dart-lang/setup-dart/blob/main/CHANGELOG.md) - [Commits](https://github.com/dart-lang/setup-dart/compare/a57a6c04cf7d4840e88432aad6281d1e125f0d46...d6a63dab3335f427404425de0fbfed4686d93c4f) --- updated-dependencies: - dependency-name: dart-lang/setup-dart dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pkgs/package_config/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/package_config/.github/workflows/test-package.yml b/pkgs/package_config/.github/workflows/test-package.yml index 8ca52ec84..edf05e203 100644 --- a/pkgs/package_config/.github/workflows/test-package.yml +++ b/pkgs/package_config/.github/workflows/test-package.yml @@ -23,7 +23,7 @@ jobs: sdk: [dev] steps: - uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 - - uses: dart-lang/setup-dart@a57a6c04cf7d4840e88432aad6281d1e125f0d46 + - uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f with: sdk: ${{ matrix.sdk }} - id: install @@ -50,7 +50,7 @@ jobs: sdk: [2.18.0, dev] steps: - uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 - - uses: dart-lang/setup-dart@a57a6c04cf7d4840e88432aad6281d1e125f0d46 + - uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f with: sdk: ${{ matrix.sdk }} - id: install From a543f2f29afe1a398ce53ddccc07ec4569838465 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 May 2023 12:20:25 -0700 Subject: [PATCH 143/170] Bump actions/checkout from 3.5.0 to 3.5.2 (dart-lang/package_config#134) Bumps [actions/checkout](https://github.com/actions/checkout) from 3.5.0 to 3.5.2. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/8f4b7f84864484a7bf31766abe9204da3cbe65b3...8e5e7e5ab8b370d6c329ec480221332ada57f0ab) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pkgs/package_config/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/package_config/.github/workflows/test-package.yml b/pkgs/package_config/.github/workflows/test-package.yml index edf05e203..2c1be945f 100644 --- a/pkgs/package_config/.github/workflows/test-package.yml +++ b/pkgs/package_config/.github/workflows/test-package.yml @@ -22,7 +22,7 @@ jobs: matrix: sdk: [dev] steps: - - uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 + - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab - uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f with: sdk: ${{ matrix.sdk }} @@ -49,7 +49,7 @@ jobs: os: [ubuntu-latest] sdk: [2.18.0, dev] steps: - - uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 + - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab - uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f with: sdk: ${{ matrix.sdk }} From 3af89623aacf60144f2449d0fe397d5b9ab95b05 Mon Sep 17 00:00:00 2001 From: Devon Carew Date: Mon, 22 May 2023 09:22:56 -0700 Subject: [PATCH 144/170] blast_repo fixes (dart-lang/package_config#135) dependabot --- pkgs/package_config/.github/dependabot.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkgs/package_config/.github/dependabot.yml b/pkgs/package_config/.github/dependabot.yml index b2f1dec5a..c84404dc9 100644 --- a/pkgs/package_config/.github/dependabot.yml +++ b/pkgs/package_config/.github/dependabot.yml @@ -8,3 +8,5 @@ updates: directory: / schedule: interval: monthly + labels: + - autosubmit From 52722601cb0bf2f90ba34b3e89f24c8f6028b746 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Jul 2023 20:23:57 +0000 Subject: [PATCH 145/170] Bump actions/checkout from 3.5.2 to 3.5.3 (dart-lang/package_config#138) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/checkout](https://github.com/actions/checkout) from 3.5.2 to 3.5.3.
Release notes

Sourced from actions/checkout's releases.

v3.5.3

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v3...v3.5.3

Changelog

Sourced from actions/checkout's changelog.

Changelog

v3.5.3

v3.5.2

v3.5.1

v3.5.0

v3.4.0

v3.3.0

v3.2.0

v3.1.0

v3.0.2

v3.0.1

v3.0.0

v2.3.1

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=3.5.2&new-version=3.5.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- pkgs/package_config/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/package_config/.github/workflows/test-package.yml b/pkgs/package_config/.github/workflows/test-package.yml index 2c1be945f..34b8073d5 100644 --- a/pkgs/package_config/.github/workflows/test-package.yml +++ b/pkgs/package_config/.github/workflows/test-package.yml @@ -22,7 +22,7 @@ jobs: matrix: sdk: [dev] steps: - - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 - uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f with: sdk: ${{ matrix.sdk }} @@ -49,7 +49,7 @@ jobs: os: [ubuntu-latest] sdk: [2.18.0, dev] steps: - - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 - uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f with: sdk: ${{ matrix.sdk }} From 1b7fb96dbc5a3ff3f46f17eccd8872b16bcf2647 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Fri, 21 Jul 2023 10:37:29 -0700 Subject: [PATCH 146/170] Update to team lints, require Dart 3.0 (dart-lang/package_config#139) --- .../.github/workflows/test-package.yml | 2 +- pkgs/package_config/CHANGELOG.md | 4 ++-- pkgs/package_config/analysis_options.yaml | 2 +- pkgs/package_config/example/main.dart | 3 ++- pkgs/package_config/lib/package_config.dart | 2 +- .../lib/package_config_types.dart | 4 ++-- pkgs/package_config/lib/src/discovery.dart | 3 +-- pkgs/package_config/lib/src/errors.dart | 1 + .../lib/src/package_config_json.dart | 9 ++++++-- .../package_config/lib/src/packages_file.dart | 5 ++--- pkgs/package_config/pubspec.yaml | 8 +++---- pkgs/package_config/test/bench.dart | 22 +++++++++---------- pkgs/package_config/test/discovery_test.dart | 5 +++-- .../test/discovery_uri_test.dart | 6 ++--- pkgs/package_config/test/parse_test.dart | 20 ++++++++++------- pkgs/package_config/test/src/util_io.dart | 2 +- 16 files changed, 54 insertions(+), 44 deletions(-) diff --git a/pkgs/package_config/.github/workflows/test-package.yml b/pkgs/package_config/.github/workflows/test-package.yml index 34b8073d5..d14e9f416 100644 --- a/pkgs/package_config/.github/workflows/test-package.yml +++ b/pkgs/package_config/.github/workflows/test-package.yml @@ -47,7 +47,7 @@ jobs: matrix: # Add macos-latest and/or windows-latest if relevant for this package. os: [ubuntu-latest] - sdk: [2.18.0, dev] + sdk: [3.0.0, dev] steps: - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 - uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index 62ef87d6e..d084d8514 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -1,6 +1,6 @@ -## 2.1.1-dev +## 2.1.1-wip -- Require Dart 2.18 +- Require Dart 3.0 ## 2.1.0 diff --git a/pkgs/package_config/analysis_options.yaml b/pkgs/package_config/analysis_options.yaml index 278ec4868..c0249e5e1 100644 --- a/pkgs/package_config/analysis_options.yaml +++ b/pkgs/package_config/analysis_options.yaml @@ -2,4 +2,4 @@ # 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. -include: package:lints/recommended.yaml +include: package:dart_flutter_team_lints/analysis_options.yaml diff --git a/pkgs/package_config/example/main.dart b/pkgs/package_config/example/main.dart index 42a596375..db137caf4 100644 --- a/pkgs/package_config/example/main.dart +++ b/pkgs/package_config/example/main.dart @@ -2,9 +2,10 @@ // 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. -import 'package:package_config/package_config.dart'; import 'dart:io' show Directory; +import 'package:package_config/package_config.dart'; + void main() async { var packageConfig = await findPackageConfig(Directory.current); if (packageConfig == null) { diff --git a/pkgs/package_config/lib/package_config.dart b/pkgs/package_config/lib/package_config.dart index a2c0321b8..8f40a8b65 100644 --- a/pkgs/package_config/lib/package_config.dart +++ b/pkgs/package_config/lib/package_config.dart @@ -9,7 +9,7 @@ /// configurations in the [specified format](https://github.com/dart-lang/language/blob/master/accepted/future-releases/language-versioning/package-config-file-v2.md). library package_config.package_config; -import 'dart:io' show File, Directory; +import 'dart:io' show Directory, File; import 'dart:typed_data' show Uint8List; import 'src/discovery.dart' as discover; diff --git a/pkgs/package_config/lib/package_config_types.dart b/pkgs/package_config/lib/package_config_types.dart index 976009b6c..756be0518 100644 --- a/pkgs/package_config/lib/package_config_types.dart +++ b/pkgs/package_config/lib/package_config_types.dart @@ -12,6 +12,6 @@ /// {@canonicalFor errors.PackageConfigError} library package_config.package_config_types; -export 'src/package_config.dart' - show PackageConfig, Package, LanguageVersion, InvalidLanguageVersion; export 'src/errors.dart' show PackageConfigError; +export 'src/package_config.dart' + show InvalidLanguageVersion, LanguageVersion, Package, PackageConfig; diff --git a/pkgs/package_config/lib/src/discovery.dart b/pkgs/package_config/lib/src/discovery.dart index ccc86ea23..352bed8ca 100644 --- a/pkgs/package_config/lib/src/discovery.dart +++ b/pkgs/package_config/lib/src/discovery.dart @@ -5,10 +5,9 @@ import 'dart:io'; import 'dart:typed_data'; -import 'package_config_io.dart'; - import 'errors.dart'; import 'package_config_impl.dart'; +import 'package_config_io.dart'; import 'package_config_json.dart'; import 'packages_file.dart' as packages_file; import 'util_io.dart' show defaultLoader, pathJoin; diff --git a/pkgs/package_config/lib/src/errors.dart b/pkgs/package_config/lib/src/errors.dart index f3515711d..69c41370a 100644 --- a/pkgs/package_config/lib/src/errors.dart +++ b/pkgs/package_config/lib/src/errors.dart @@ -29,4 +29,5 @@ class PackageConfigFormatException extends FormatException } /// The default `onError` handler. +// ignore: only_throw_errors Never throwError(Object error) => throw error; diff --git a/pkgs/package_config/lib/src/package_config_json.dart b/pkgs/package_config/lib/src/package_config_json.dart index bd22db4ec..47e7e96b6 100644 --- a/pkgs/package_config/lib/src/package_config_json.dart +++ b/pkgs/package_config/lib/src/package_config_json.dart @@ -167,7 +167,9 @@ PackageConfig parsePackageConfigJson( name!, root, packageRoot, version, extraData, relativeRoot, (error) { if (error is ArgumentError) { onError( - PackageConfigFormatException(error.message, error.invalidValue)); + PackageConfigFormatException( + error.message.toString(), error.invalidValue), + ); } else { onError(error); } @@ -214,7 +216,10 @@ PackageConfig parsePackageConfigJson( } return SimplePackageConfig(configVersion!, packageList!, extraData, (error) { if (error is ArgumentError) { - onError(PackageConfigFormatException(error.message, error.invalidValue)); + onError( + PackageConfigFormatException( + error.message.toString(), error.invalidValue), + ); } else { onError(error); } diff --git a/pkgs/package_config/lib/src/packages_file.dart b/pkgs/package_config/lib/src/packages_file.dart index 3fd7db9b5..5d1467755 100644 --- a/pkgs/package_config/lib/src/packages_file.dart +++ b/pkgs/package_config/lib/src/packages_file.dart @@ -2,10 +2,9 @@ // 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. +import 'errors.dart'; import 'package_config_impl.dart'; - import 'util.dart'; -import 'errors.dart'; /// The language version prior to the release of language versioning. /// @@ -127,7 +126,7 @@ PackageConfig parse( var package = SimplePackage.validate(packageName, rootUri, packageLocation, _languageVersion, null, relativeRoot, (error) { if (error is ArgumentError) { - onError(PackageConfigFormatException(error.message, source)); + onError(PackageConfigFormatException(error.message.toString(), source)); } else { onError(error); } diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 08255ffa9..e121ab033 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,10 +1,10 @@ name: package_config -version: 2.1.1-dev +version: 2.1.1-wip description: Support for reading and writing Dart Package Configuration files. repository: https://github.com/dart-lang/package_config environment: - sdk: '>=2.18.0 <3.0.0' + sdk: ^3.0.0 dependencies: path: ^1.8.0 @@ -12,6 +12,6 @@ dependencies: dev_dependencies: build_runner: ^2.0.0 build_test: ^2.1.2 - build_web_compilers: '>=3.0.0 <5.0.0' - lints: ^2.0.0 + build_web_compilers: ^4.0.0 + dart_flutter_team_lints: ^1.0.0 test: ^1.16.0 diff --git a/pkgs/package_config/test/bench.dart b/pkgs/package_config/test/bench.dart index 746643185..8428481f7 100644 --- a/pkgs/package_config/test/bench.dart +++ b/pkgs/package_config/test/bench.dart @@ -5,10 +5,9 @@ import 'dart:convert'; import 'dart:typed_data'; +import 'package:package_config/src/errors.dart'; import 'package:package_config/src/package_config_json.dart'; -void throwError(Object error) => throw error; - void bench(final int size, final bool doPrint) { var sb = StringBuffer(); sb.writeln('{'); @@ -32,20 +31,21 @@ void bench(final int size, final bool doPrint) { sb.writeln('}'); var stopwatch = Stopwatch()..start(); var config = parsePackageConfigBytes( - // ignore: unnecessary_cast - utf8.encode(sb.toString()) as Uint8List, - Uri.parse('file:///tmp/.dart_tool/file.dart'), - throwError); - final int read = stopwatch.elapsedMilliseconds; + // ignore: unnecessary_cast + utf8.encode(sb.toString()) as Uint8List, + Uri.parse('file:///tmp/.dart_tool/file.dart'), + throwError, + ); + final read = stopwatch.elapsedMilliseconds; stopwatch.reset(); for (var i = 0; i < size; i++) { if (config.packageOf(Uri.parse('file:///p_$i/lib/src/foo.dart'))!.name != 'p_$i') { - throw "Unexpected result!"; + throw StateError('Unexpected result!'); } } - final int lookup = stopwatch.elapsedMilliseconds; + final lookup = stopwatch.elapsedMilliseconds; if (doPrint) { print('Read file with $size packages in $read ms, ' @@ -55,12 +55,12 @@ void bench(final int size, final bool doPrint) { void main(List args) { if (args.length != 1 && args.length != 2) { - throw "Expects arguments: ?"; + throw ArgumentError('Expects arguments: ?'); } final size = int.parse(args[0]); if (args.length > 1) { final warmups = int.parse(args[1]); - print("Performing $warmups warmup iterations."); + print('Performing $warmups warmup iterations.'); for (var i = 0; i < warmups; i++) { bench(10, false); } diff --git a/pkgs/package_config/test/discovery_test.dart b/pkgs/package_config/test/discovery_test.dart index 17b6aa099..3eb0ea153 100644 --- a/pkgs/package_config/test/discovery_test.dart +++ b/pkgs/package_config/test/discovery_test.dart @@ -6,8 +6,9 @@ library package_config.discovery_test; import 'dart:io'; -import 'package:test/test.dart'; + import 'package:package_config/package_config.dart'; +import 'package:test/test.dart'; import 'src/util.dart'; import 'src/util_io.dart'; @@ -207,7 +208,7 @@ void main() { '.packages': packagesFile, 'script.dart': 'main(){}' }, (Directory directory) async { - var config = (await findPackageConfig(directory, minVersion: 2)); + var config = await findPackageConfig(directory, minVersion: 2); expect(config, null); }); diff --git a/pkgs/package_config/test/discovery_uri_test.dart b/pkgs/package_config/test/discovery_uri_test.dart index 6183ce3ba..c8fbcb87c 100644 --- a/pkgs/package_config/test/discovery_uri_test.dart +++ b/pkgs/package_config/test/discovery_uri_test.dart @@ -5,8 +5,8 @@ @TestOn('vm') library package_config.discovery_test; -import 'package:test/test.dart'; import 'package:package_config/package_config.dart'; +import 'package:test/test.dart'; import 'src/util.dart'; @@ -151,8 +151,8 @@ void main() { '.packages': packagesFile, 'script.dart': 'main(){}' }, (directory, loader) async { - var config = (await findPackageConfigUri(directory, - minVersion: 2, loader: loader)); + var config = + await findPackageConfigUri(directory, minVersion: 2, loader: loader); expect(config, null); }); diff --git a/pkgs/package_config/test/parse_test.dart b/pkgs/package_config/test/parse_test.dart index 94269e20f..ad4c74949 100644 --- a/pkgs/package_config/test/parse_test.dart +++ b/pkgs/package_config/test/parse_test.dart @@ -5,14 +5,13 @@ import 'dart:convert'; import 'dart:typed_data'; -import 'package:test/test.dart'; - import 'package:package_config/package_config_types.dart'; -import 'package:package_config/src/packages_file.dart' as packages; +import 'package:package_config/src/errors.dart'; import 'package:package_config/src/package_config_json.dart'; -import 'src/util.dart'; +import 'package:package_config/src/packages_file.dart' as packages; +import 'package:test/test.dart'; -void throwError(Object error) => throw error; +import 'src/util.dart'; void main() { group('.packages', () { @@ -318,8 +317,12 @@ void main() { test(name, () { dynamic exception; try { - parsePackageConfigBytes(utf8.encode(source) as Uint8List, - Uri.parse('file:///tmp/.dart_tool/file.dart'), throwError); + parsePackageConfigBytes( + // ignore: unnecessary_cast + utf8.encode(source) as Uint8List, + Uri.parse('file:///tmp/.dart_tool/file.dart'), + throwError, + ); } catch (e) { exception = e; } @@ -440,8 +443,9 @@ void main() { 'package root of foo is inside the root of bar'); // This shouldn't be allowed, but for internal reasons it is. - test("package inside package root", () { + test('package inside package root', () { var config = parsePackageConfigBytes( + // ignore: unnecessary_cast utf8.encode( '{$cfg,"packages":[' '{"name":"foo","rootUri":"/foo/","packageUri":"lib/"},' diff --git a/pkgs/package_config/test/src/util_io.dart b/pkgs/package_config/test/src/util_io.dart index 109dff112..e032556f4 100644 --- a/pkgs/package_config/test/src/util_io.dart +++ b/pkgs/package_config/test/src/util_io.dart @@ -4,8 +4,8 @@ import 'dart:io'; -import 'package:test/test.dart'; import 'package:package_config/src/util_io.dart'; +import 'package:test/test.dart'; /// Creates a directory structure from [description] and runs [fileTest]. /// From 9c69749f299fb5f031f6a8a281b4b2799feb8303 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:17:04 +0000 Subject: [PATCH 147/170] Bump actions/checkout from 3.5.3 to 3.6.0 (dart-lang/package_config#140) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/checkout](https://github.com/actions/checkout) from 3.5.3 to 3.6.0.
Release notes

Sourced from actions/checkout's releases.

v3.6.0

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v3.5.3...v3.6.0

Changelog

Sourced from actions/checkout's changelog.

Changelog

v3.6.0

v3.5.3

v3.5.2

v3.5.1

v3.5.0

v3.4.0

v3.3.0

v3.2.0

v3.1.0

v3.0.2

v3.0.1

v3.0.0

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=3.5.3&new-version=3.6.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- pkgs/package_config/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/package_config/.github/workflows/test-package.yml b/pkgs/package_config/.github/workflows/test-package.yml index d14e9f416..5ee9b9226 100644 --- a/pkgs/package_config/.github/workflows/test-package.yml +++ b/pkgs/package_config/.github/workflows/test-package.yml @@ -22,7 +22,7 @@ jobs: matrix: sdk: [dev] steps: - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 + - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 - uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f with: sdk: ${{ matrix.sdk }} @@ -49,7 +49,7 @@ jobs: os: [ubuntu-latest] sdk: [3.0.0, dev] steps: - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 + - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 - uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f with: sdk: ${{ matrix.sdk }} From 4225920dc204d378248efa525b1cefcbe6988ca3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Oct 2023 20:24:54 +0000 Subject: [PATCH 148/170] Bump dart-lang/setup-dart from 1.5.0 to 1.5.1 (dart-lang/package_config#142) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [dart-lang/setup-dart](https://github.com/dart-lang/setup-dart) from 1.5.0 to 1.5.1.
Release notes

Sourced from dart-lang/setup-dart's releases.

v1.5.1

  • No longer test the setup-dart action on pre-2.12 SDKs.
  • Upgrade JS interop code to use extension types (the new name for inline classes).
  • The upcoming rename of the be channel to main is now supported with forward compatibility that switches when the rename happens.
Changelog

Sourced from dart-lang/setup-dart's changelog.

v1.6.0

  • Enable provisioning of the latest Dart SDK patch release by specifying just the major and minor version (e.g. 3.2).

v1.5.1

  • No longer test the setup-dart action on pre-2.12 SDKs.
  • Upgrade JS interop code to use extension types (the new name for inline classes).
  • The upcoming rename of the be channel to main is now supported with forward compatibility that switches when the rename happens.

v1.5.0

  • Re-wrote the implementation of the action into Dart.
  • Auto-detect the platform architecture (x64, ia32, arm, arm64).
  • Improved the caching and download resilience of the sdk.
  • Added a new action output: dart-version - the installed version of the sdk.

v1.4.0

  • Automatically create OIDC token for pub.dev.
  • Add a reusable workflow for publishing.

v1.3.0

v1.2.0

  • Fixed a path issue impacting git dependencies on Windows.

v1.1.0

  • Added a flavor option setup.sh to allow downloading unpublished builds.

v1.0.0

  • Promoted to 1.0 stable.

v0.5

  • Fixed a Windows pub global activate path issue.

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=dart-lang/setup-dart&package-manager=github_actions&previous-version=1.5.0&new-version=1.5.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- pkgs/package_config/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/package_config/.github/workflows/test-package.yml b/pkgs/package_config/.github/workflows/test-package.yml index 5ee9b9226..6a09c5a68 100644 --- a/pkgs/package_config/.github/workflows/test-package.yml +++ b/pkgs/package_config/.github/workflows/test-package.yml @@ -23,7 +23,7 @@ jobs: sdk: [dev] steps: - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 - - uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f + - uses: dart-lang/setup-dart@8a4b97ea2017cc079571daec46542f76189836b1 with: sdk: ${{ matrix.sdk }} - id: install @@ -50,7 +50,7 @@ jobs: sdk: [3.0.0, dev] steps: - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 - - uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f + - uses: dart-lang/setup-dart@8a4b97ea2017cc079571daec46542f76189836b1 with: sdk: ${{ matrix.sdk }} - id: install From a8ce33657f705a401c8a5322bce18e7f617e44f0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Oct 2023 18:26:42 +0000 Subject: [PATCH 149/170] Bump actions/checkout from 3.6.0 to 4.1.0 (dart-lang/package_config#141) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/checkout](https://github.com/actions/checkout) from 3.6.0 to 4.1.0.
Release notes

Sourced from actions/checkout's releases.

v4.1.0

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v4.0.0...v4.1.0

v4.0.0

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v3...v4.0.0

Changelog

Sourced from actions/checkout's changelog.

Changelog

v4.1.0

v4.0.0

v3.6.0

v3.5.3

v3.5.2

v3.5.1

v3.5.0

v3.4.0

v3.3.0

v3.2.0

v3.1.0

v3.0.2

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=3.6.0&new-version=4.1.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- pkgs/package_config/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/package_config/.github/workflows/test-package.yml b/pkgs/package_config/.github/workflows/test-package.yml index 6a09c5a68..c3e89aacd 100644 --- a/pkgs/package_config/.github/workflows/test-package.yml +++ b/pkgs/package_config/.github/workflows/test-package.yml @@ -22,7 +22,7 @@ jobs: matrix: sdk: [dev] steps: - - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 - uses: dart-lang/setup-dart@8a4b97ea2017cc079571daec46542f76189836b1 with: sdk: ${{ matrix.sdk }} @@ -49,7 +49,7 @@ jobs: os: [ubuntu-latest] sdk: [3.0.0, dev] steps: - - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 - uses: dart-lang/setup-dart@8a4b97ea2017cc079571daec46542f76189836b1 with: sdk: ${{ matrix.sdk }} From aff00e80119d63faa70d6ba7bb7caa230f1003be Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Nov 2023 20:33:04 +0000 Subject: [PATCH 150/170] Bump dart-lang/setup-dart from 1.5.1 to 1.6.0 (dart-lang/package_config#143) Bumps [dart-lang/setup-dart](https://github.com/dart-lang/setup-dart) from 1.5.1 to 1.6.0.
Release notes

Sourced from dart-lang/setup-dart's releases.

v1.6.0

  • Enable provisioning of the latest Dart SDK patch release by specifying just the major and minor version (e.g. 3.2).
Changelog

Sourced from dart-lang/setup-dart's changelog.

v1.6.0

  • Enable provisioning of the latest Dart SDK patch release by specifying just the major and minor version (e.g. 3.2).

v1.5.1

  • No longer test the setup-dart action on pre-2.12 SDKs.
  • Upgrade JS interop code to use extension types (the new name for inline classes).
  • The upcoming rename of the be channel to main is now supported with forward compatibility that switches when the rename happens.

v1.5.0

  • Re-wrote the implementation of the action into Dart.
  • Auto-detect the platform architecture (x64, ia32, arm, arm64).
  • Improved the caching and download resilience of the sdk.
  • Added a new action output: dart-version - the installed version of the sdk.

v1.4.0

  • Automatically create OIDC token for pub.dev.
  • Add a reusable workflow for publishing.

v1.3.0

v1.2.0

  • Fixed a path issue impacting git dependencies on Windows.

v1.1.0

  • Added a flavor option setup.sh to allow downloading unpublished builds.

v1.0.0

  • Promoted to 1.0 stable.

v0.5

  • Fixed a Windows pub global activate path issue.

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=dart-lang/setup-dart&package-manager=github_actions&previous-version=1.5.1&new-version=1.6.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- pkgs/package_config/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/package_config/.github/workflows/test-package.yml b/pkgs/package_config/.github/workflows/test-package.yml index c3e89aacd..dd76bff17 100644 --- a/pkgs/package_config/.github/workflows/test-package.yml +++ b/pkgs/package_config/.github/workflows/test-package.yml @@ -23,7 +23,7 @@ jobs: sdk: [dev] steps: - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 - - uses: dart-lang/setup-dart@8a4b97ea2017cc079571daec46542f76189836b1 + - uses: dart-lang/setup-dart@b64355ae6ca0b5d484f0106a033dd1388965d06d with: sdk: ${{ matrix.sdk }} - id: install @@ -50,7 +50,7 @@ jobs: sdk: [3.0.0, dev] steps: - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 - - uses: dart-lang/setup-dart@8a4b97ea2017cc079571daec46542f76189836b1 + - uses: dart-lang/setup-dart@b64355ae6ca0b5d484f0106a033dd1388965d06d with: sdk: ${{ matrix.sdk }} - id: install From 2019cfabc7ee175b6b9c204a2c98e1e728de926e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Nov 2023 21:39:05 +0000 Subject: [PATCH 151/170] Bump actions/checkout from 4.1.0 to 4.1.1 (dart-lang/package_config#144) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.0 to 4.1.1.
Release notes

Sourced from actions/checkout's releases.

v4.1.1

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v4.1.0...v4.1.1

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=4.1.0&new-version=4.1.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- pkgs/package_config/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/package_config/.github/workflows/test-package.yml b/pkgs/package_config/.github/workflows/test-package.yml index dd76bff17..2aa74dfe3 100644 --- a/pkgs/package_config/.github/workflows/test-package.yml +++ b/pkgs/package_config/.github/workflows/test-package.yml @@ -22,7 +22,7 @@ jobs: matrix: sdk: [dev] steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 - uses: dart-lang/setup-dart@b64355ae6ca0b5d484f0106a033dd1388965d06d with: sdk: ${{ matrix.sdk }} @@ -49,7 +49,7 @@ jobs: os: [ubuntu-latest] sdk: [3.0.0, dev] steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 - uses: dart-lang/setup-dart@b64355ae6ca0b5d484f0106a033dd1388965d06d with: sdk: ${{ matrix.sdk }} From a9396b06c4c4a2a32072962293ae4345d79201bf Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Wed, 10 Jan 2024 13:21:18 -0800 Subject: [PATCH 152/170] Update to latest lints, Require Dart 3.2 (dart-lang/package_config#145) --- .../.github/workflows/test-package.yml | 2 +- pkgs/package_config/CHANGELOG.md | 2 +- pkgs/package_config/lib/package_config.dart | 4 ++-- pkgs/package_config/lib/src/errors.dart | 9 ++++---- .../lib/src/package_config.dart | 8 +++---- .../lib/src/package_config_impl.dart | 13 +++-------- .../lib/src/package_config_io.dart | 2 +- .../lib/src/package_config_json.dart | 8 +++---- .../package_config/lib/src/packages_file.dart | 6 ----- pkgs/package_config/pubspec.yaml | 4 ++-- pkgs/package_config/test/discovery_test.dart | 22 ++++++++----------- .../test/discovery_uri_test.dart | 14 ++++++------ .../test/package_config_impl_test.dart | 2 +- pkgs/package_config/test/parse_test.dart | 4 ++-- pkgs/package_config/test/src/util.dart | 2 +- 15 files changed, 42 insertions(+), 60 deletions(-) diff --git a/pkgs/package_config/.github/workflows/test-package.yml b/pkgs/package_config/.github/workflows/test-package.yml index 2aa74dfe3..2e475912a 100644 --- a/pkgs/package_config/.github/workflows/test-package.yml +++ b/pkgs/package_config/.github/workflows/test-package.yml @@ -47,7 +47,7 @@ jobs: matrix: # Add macos-latest and/or windows-latest if relevant for this package. os: [ubuntu-latest] - sdk: [3.0.0, dev] + sdk: [3.2, dev] steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 - uses: dart-lang/setup-dart@b64355ae6ca0b5d484f0106a033dd1388965d06d diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index d084d8514..a682bc3a4 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -1,6 +1,6 @@ ## 2.1.1-wip -- Require Dart 3.0 +- Require Dart 3.2 ## 2.1.0 diff --git a/pkgs/package_config/lib/package_config.dart b/pkgs/package_config/lib/package_config.dart index 8f40a8b65..194fe894e 100644 --- a/pkgs/package_config/lib/package_config.dart +++ b/pkgs/package_config/lib/package_config.dart @@ -102,7 +102,7 @@ Future loadPackageConfigUri(Uri file, /// then the parent directories are checked recursively, /// all the way to the root directory, to check if those contains /// a package configuration. -/// If [recurse] is set to [false], this parent directory check is not +/// If [recurse] is set to `false`, this parent directory check is not /// performed. /// /// If [onError] is provided, the configuration file parsing will report errors @@ -140,7 +140,7 @@ Future findPackageConfig(Directory directory, /// then the parent directories are checked recursively, /// all the way to the root directory, to check if those contains /// a package configuration. -/// If [recurse] is set to [false], this parent directory check is not +/// If [recurse] is set to `false`, this parent directory check is not /// performed. /// /// If [loader] is provided, URIs are loaded using that function. diff --git a/pkgs/package_config/lib/src/errors.dart b/pkgs/package_config/lib/src/errors.dart index 69c41370a..a66fef7f3 100644 --- a/pkgs/package_config/lib/src/errors.dart +++ b/pkgs/package_config/lib/src/errors.dart @@ -12,8 +12,9 @@ abstract class PackageConfigError { class PackageConfigArgumentError extends ArgumentError implements PackageConfigError { - PackageConfigArgumentError(Object? value, String name, String message) - : super.value(value, name, message); + PackageConfigArgumentError( + Object? super.value, String super.name, String super.message) + : super.value(); PackageConfigArgumentError.from(ArgumentError error) : super.value(error.invalidValue, error.name, error.message); @@ -21,8 +22,8 @@ class PackageConfigArgumentError extends ArgumentError class PackageConfigFormatException extends FormatException implements PackageConfigError { - PackageConfigFormatException(String message, Object? source, [int? offset]) - : super(message, source, offset); + PackageConfigFormatException(super.message, Object? super.source, + [super.offset]); PackageConfigFormatException.from(FormatException exception) : super(exception.message, exception.source, exception.offset); diff --git a/pkgs/package_config/lib/src/package_config.dart b/pkgs/package_config/lib/src/package_config.dart index ba52c147d..c00ac67af 100644 --- a/pkgs/package_config/lib/src/package_config.dart +++ b/pkgs/package_config/lib/src/package_config.dart @@ -32,7 +32,7 @@ abstract class PackageConfig { /// absolute directory URIs, valid language version, if any), /// and there must not be two packages with the same name. /// - /// The package's root ([Package.rootUri]) and package-root + /// The package's root ([Package.root]) and package-root /// ([Package.packageUriRoot]) paths must satisfy a number of constraints /// We say that one path (which we know ends with a `/` charater) /// is inside another path, if the latter path is a prefix of the former path, @@ -95,7 +95,7 @@ abstract class PackageConfig { /// Parses the JSON data of a package configuration file. /// - /// The [configuration] must be a JSON-like Dart data structure, + /// The [jsonData] must be a JSON-like Dart data structure, /// like the one provided by parsing JSON text using `dart:convert`, /// containing a valid package configuration. /// @@ -167,7 +167,7 @@ abstract class PackageConfig { /// Provides the associated package for a specific [file] (or directory). /// /// Returns a [Package] which contains the [file]'s path, if any. - /// That is, the [Package.rootUri] directory is a parent directory + /// That is, the [Package.root] directory is a parent directory /// of the [file]'s location. /// /// Returns `null` if the file does not belong to any package. @@ -247,7 +247,7 @@ abstract class Package { /// Is always an absolute URI with no query or fragment parts, /// and with a path ending in `/`. /// - /// All files in the [rootUri] directory are considered + /// All files in the [root] directory are considered /// part of the package for purposes where that that matters. Uri get root; diff --git a/pkgs/package_config/lib/src/package_config_impl.dart b/pkgs/package_config/lib/src/package_config_impl.dart index f832d6adf..d8e8d495f 100644 --- a/pkgs/package_config/lib/src/package_config_impl.dart +++ b/pkgs/package_config/lib/src/package_config_impl.dart @@ -141,12 +141,6 @@ class SimplePackageConfig implements PackageConfig { @override Package? operator [](String packageName) => _packages[packageName]; - /// Provides the associated package for a specific [file] (or directory). - /// - /// Returns a [Package] which contains the [file]'s path. - /// That is, the [Package.rootUri] directory is a parent directory - /// of the [file]'s location. - /// Returns `null` if the file does not belong to any package. @override Package? packageOf(Uri file) => _packageTree.packageOf(file); @@ -270,7 +264,7 @@ class SimplePackage implements Package { } } -/// Checks whether [version] is a valid Dart language version string. +/// Checks whether [source] is a valid Dart language version string. /// /// The format is (as RegExp) `^(0|[1-9]\d+)\.(0|[1-9]\d+)$`. /// @@ -553,9 +547,8 @@ enum ConflictType { sameRoots, interleaving, insidePackageRoot } /// Conflict between packages added to the same configuration. /// /// The [package] conflicts with [existingPackage] if it has -/// the same root path ([isRootConflict]) or the package URI root path -/// of [existingPackage] is inside the root path of [package] -/// ([isPackageRootConflict]). +/// the same root path or the package URI root path +/// of [existingPackage] is inside the root path of [package]. class ConflictException { /// The existing package that [package] conflicts with. final SimplePackage existingPackage; diff --git a/pkgs/package_config/lib/src/package_config_io.dart b/pkgs/package_config/lib/src/package_config_io.dart index 9aed621e0..8c5773b2b 100644 --- a/pkgs/package_config/lib/src/package_config_io.dart +++ b/pkgs/package_config/lib/src/package_config_io.dart @@ -38,7 +38,7 @@ const packagesFileName = '.packages'; /// If the [file] is a `.packages` file and [preferNewest] is true, /// first checks whether there is an adjacent `.dart_tool/package_config.json` /// file, and if so, reads that instead. -/// If [preferNewset] is false, the specified file is loaded even if it is +/// If [preferNewest] is false, the specified file is loaded even if it is /// a `.packages` file and there is an available `package_config.json` file. /// /// The file must exist and be a normal file. diff --git a/pkgs/package_config/lib/src/package_config_json.dart b/pkgs/package_config/lib/src/package_config_json.dart index 47e7e96b6..65560a0f0 100644 --- a/pkgs/package_config/lib/src/package_config_json.dart +++ b/pkgs/package_config/lib/src/package_config_json.dart @@ -75,10 +75,8 @@ PackageConfig parsePackageConfigString( /// where the integer numeral cannot have a sign, and can only have a /// leading zero if the entire numeral is a single zero. /// -/// All other properties are stored in [extraData]. -/// /// The [baseLocation] is used as base URI to resolve the "rootUri" -/// URI referencestring. +/// URI reference string. PackageConfig parsePackageConfigJson( Object? json, Uri baseLocation, void Function(Object error) onError) { if (!baseLocation.hasScheme || baseLocation.isScheme('package')) { @@ -93,7 +91,7 @@ PackageConfig parsePackageConfigJson( String typeName() { if (0 is T) return 'int'; if ('' is T) return 'string'; - if (const [] is T) return 'array'; + if (const [] is T) return 'array'; return 'object'; } @@ -239,7 +237,7 @@ void writePackageConfigJsonString( PackageConfig config, Uri? baseUri, StringSink output) { // Can be optimized. var data = packageConfigToJson(config, baseUri); - output.write(JsonEncoder.withIndent(' ').convert(data)); + output.write(const JsonEncoder.withIndent(' ').convert(data)); } Map packageConfigToJson(PackageConfig config, Uri? baseUri) => diff --git a/pkgs/package_config/lib/src/packages_file.dart b/pkgs/package_config/lib/src/packages_file.dart index 5d1467755..f84db1075 100644 --- a/pkgs/package_config/lib/src/packages_file.dart +++ b/pkgs/package_config/lib/src/packages_file.dart @@ -148,12 +148,6 @@ PackageConfig parse( /// /// If [baseUri] is provided, package locations will be made relative /// to the base URI, if possible, before writing. -/// -/// If [allowDefaultPackage] is `true`, the [packageMapping] may contain an -/// empty string mapping to the _default package name_. -/// -/// All the keys of [packageMapping] must be valid package names, -/// and the values must be URIs that do not have the `package:` scheme. void write(StringSink output, PackageConfig config, {Uri? baseUri, String? comment}) { if (baseUri != null && !baseUri.isAbsolute) { diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index e121ab033..b7130793f 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -4,7 +4,7 @@ description: Support for reading and writing Dart Package Configuration files. repository: https://github.com/dart-lang/package_config environment: - sdk: ^3.0.0 + sdk: ^3.2.0 dependencies: path: ^1.8.0 @@ -13,5 +13,5 @@ dev_dependencies: build_runner: ^2.0.0 build_test: ^2.1.2 build_web_compilers: ^4.0.0 - dart_flutter_team_lints: ^1.0.0 + dart_flutter_team_lints: ^2.0.0 test: ^1.16.0 diff --git a/pkgs/package_config/test/discovery_test.dart b/pkgs/package_config/test/discovery_test.dart index 3eb0ea153..ee77559b1 100644 --- a/pkgs/package_config/test/discovery_test.dart +++ b/pkgs/package_config/test/discovery_test.dart @@ -59,7 +59,7 @@ void main() { fileTest('package_config.json', { '.packages': 'invalid .packages file', 'script.dart': 'main(){}', - 'packages': {'shouldNotBeFound': {}}, + 'packages': {'shouldNotBeFound': {}}, '.dart_tool': { 'package_config.json': packageConfigFile, } @@ -73,7 +73,7 @@ void main() { fileTest('.packages', { '.packages': packagesFile, 'script.dart': 'main(){}', - 'packages': {'shouldNotBeFound': {}} + 'packages': {'shouldNotBeFound': {}} }, (Directory directory) async { var config = (await findPackageConfig(directory))!; expect(config.version, 1); // Found .packages file. @@ -108,7 +108,7 @@ void main() { // Does not find a packages/ directory, and returns null if nothing found. fileTest('package directory packages not supported', { 'packages': { - 'foo': {}, + 'foo': {}, } }, (Directory directory) async { var config = await findPackageConfig(directory); @@ -119,15 +119,13 @@ void main() { fileTest('invalid .packages', { '.packages': 'not a .packages file', }, (Directory directory) { - expect(findPackageConfig(directory), - throwsA(TypeMatcher())); + expect(findPackageConfig(directory), throwsA(isA())); }); fileTest('invalid .packages as JSON', { '.packages': packageConfigFile, }, (Directory directory) { - expect(findPackageConfig(directory), - throwsA(TypeMatcher())); + expect(findPackageConfig(directory), throwsA(isA())); }); fileTest('invalid .packages', { @@ -135,8 +133,7 @@ void main() { 'package_config.json': 'not a JSON file', } }, (Directory directory) { - expect(findPackageConfig(directory), - throwsA(TypeMatcher())); + expect(findPackageConfig(directory), throwsA(isA())); }); fileTest('invalid .packages as INI', { @@ -144,8 +141,7 @@ void main() { 'package_config.json': packagesFile, } }, (Directory directory) { - expect(findPackageConfig(directory), - throwsA(TypeMatcher())); + expect(findPackageConfig(directory), throwsA(isA())); }); }); @@ -304,8 +300,8 @@ void main() { fileTest('no config found', {}, (Directory directory) { var file = dirFile(directory, 'anyname'); - expect(() => loadPackageConfig(file), - throwsA(TypeMatcher())); + expect( + () => loadPackageConfig(file), throwsA(isA())); }); fileTest('no config found, handled', {}, (Directory directory) async { diff --git a/pkgs/package_config/test/discovery_uri_test.dart b/pkgs/package_config/test/discovery_uri_test.dart index c8fbcb87c..b71ed5172 100644 --- a/pkgs/package_config/test/discovery_uri_test.dart +++ b/pkgs/package_config/test/discovery_uri_test.dart @@ -56,7 +56,7 @@ void main() { loaderTest('package_config.json', { '.packages': 'invalid .packages file', 'script.dart': 'main(){}', - 'packages': {'shouldNotBeFound': {}}, + 'packages': {'shouldNotBeFound': {}}, '.dart_tool': { 'package_config.json': packageConfigFile, } @@ -70,7 +70,7 @@ void main() { loaderTest('.packages', { '.packages': packagesFile, 'script.dart': 'main(){}', - 'packages': {'shouldNotBeFound': {}} + 'packages': {'shouldNotBeFound': {}} }, (directory, loader) async { var config = (await findPackageConfigUri(directory, loader: loader))!; expect(config.version, 1); // Found .packages file. @@ -107,7 +107,7 @@ void main() { // Does not find a packages/ directory, and returns null if nothing found. loaderTest('package directory packages not supported', { 'packages': { - 'foo': {}, + 'foo': {}, } }, (Uri directory, loader) async { var config = await findPackageConfigUri(directory, loader: loader); @@ -118,14 +118,14 @@ void main() { '.packages': 'not a .packages file', }, (Uri directory, loader) { expect(() => findPackageConfigUri(directory, loader: loader), - throwsA(TypeMatcher())); + throwsA(isA())); }); loaderTest('invalid .packages as JSON', { '.packages': packageConfigFile, }, (Uri directory, loader) { expect(() => findPackageConfigUri(directory, loader: loader), - throwsA(TypeMatcher())); + throwsA(isA())); }); loaderTest('invalid .packages', { @@ -134,7 +134,7 @@ void main() { } }, (Uri directory, loader) { expect(() => findPackageConfigUri(directory, loader: loader), - throwsA(TypeMatcher())); + throwsA(isA())); }); loaderTest('invalid .packages as INI', { @@ -143,7 +143,7 @@ void main() { } }, (Uri directory, loader) { expect(() => findPackageConfigUri(directory, loader: loader), - throwsA(TypeMatcher())); + throwsA(isA())); }); // Does not find .packages if no package_config.json and minVersion > 1. diff --git a/pkgs/package_config/test/package_config_impl_test.dart b/pkgs/package_config/test/package_config_impl_test.dart index cef121713..87d1fd413 100644 --- a/pkgs/package_config/test/package_config_impl_test.dart +++ b/pkgs/package_config/test/package_config_impl_test.dart @@ -36,7 +36,7 @@ void main() { void failParse(String name, String input) { test('$name - error', () { expect(() => LanguageVersion.parse(input), - throwsA(TypeMatcher())); + throwsA(isA())); expect(() => LanguageVersion.parse(input), throwsFormatException); var failed = false; var actual = LanguageVersion.parse(input, onError: (_) { diff --git a/pkgs/package_config/test/parse_test.dart b/pkgs/package_config/test/parse_test.dart index ad4c74949..402fe8c42 100644 --- a/pkgs/package_config/test/parse_test.dart +++ b/pkgs/package_config/test/parse_test.dart @@ -53,7 +53,7 @@ void main() { test(name, () { expect( () => packages.parse(utf8.encode(content), baseFile, throwError), - throwsA(TypeMatcher())); + throwsA(isA())); }); test('$name, handle error', () { var hadError = false; @@ -308,7 +308,7 @@ void main() { // ignore: unnecessary_cast () => parsePackageConfigBytes(utf8.encode(source) as Uint8List, Uri.parse('file:///tmp/.dart_tool/file.dart'), throwError), - throwsA(TypeMatcher())); + throwsA(isA())); }); } diff --git a/pkgs/package_config/test/src/util.dart b/pkgs/package_config/test/src/util.dart index 246e12964..780ee80dc 100644 --- a/pkgs/package_config/test/src/util.dart +++ b/pkgs/package_config/test/src/util.dart @@ -28,7 +28,7 @@ ${packages.map((nu) => """ } """; -/// Mimics a directory structure of [description] and runs [fileTest]. +/// Mimics a directory structure of [description] and runs [loaderTest]. /// /// Description is a map, each key is a file entry. If the value is a map, /// it's a subdirectory, otherwise it's a file and the value is the content From 936e0cfb559180537679e56a46bb59b07f57e83c Mon Sep 17 00:00:00 2001 From: Jacob MacDonald Date: Wed, 10 Jan 2024 14:51:25 -0800 Subject: [PATCH 153/170] add test validating current behavior of packageOf, run CI on windows (dart-lang/package_config#137) - validates the behavior of https://github.com/dart-lang/package_config/issues/136 today (but does not change it) - removes build_runner deps for testing, there is no need to use it for such a small package - fixes a bug in discovery_test.dart that was probably landed due to inability to run tests --- .../.github/workflows/test-package.yml | 5 ++--- pkgs/package_config/pubspec.yaml | 3 --- pkgs/package_config/test/discovery_test.dart | 2 +- pkgs/package_config/test/parse_test.dart | 19 +++++++++++++++++++ 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/pkgs/package_config/.github/workflows/test-package.yml b/pkgs/package_config/.github/workflows/test-package.yml index 2e475912a..1768fc834 100644 --- a/pkgs/package_config/.github/workflows/test-package.yml +++ b/pkgs/package_config/.github/workflows/test-package.yml @@ -45,8 +45,7 @@ jobs: strategy: fail-fast: false matrix: - # Add macos-latest and/or windows-latest if relevant for this package. - os: [ubuntu-latest] + os: [ubuntu-latest, windows-latest] sdk: [3.2, dev] steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 @@ -57,5 +56,5 @@ jobs: name: Install dependencies run: dart pub get - name: Run tests - run: dart run build_runner test -- -p chrome,vm + run: dart test -p chrome,vm if: always() && steps.install.outcome == 'success' diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index b7130793f..6ac7f54dd 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -10,8 +10,5 @@ dependencies: path: ^1.8.0 dev_dependencies: - build_runner: ^2.0.0 - build_test: ^2.1.2 - build_web_compilers: ^4.0.0 dart_flutter_team_lints: ^2.0.0 test: ^1.16.0 diff --git a/pkgs/package_config/test/discovery_test.dart b/pkgs/package_config/test/discovery_test.dart index ee77559b1..2ca337a19 100644 --- a/pkgs/package_config/test/discovery_test.dart +++ b/pkgs/package_config/test/discovery_test.dart @@ -59,7 +59,7 @@ void main() { fileTest('package_config.json', { '.packages': 'invalid .packages file', 'script.dart': 'main(){}', - 'packages': {'shouldNotBeFound': {}}, + 'packages': {'shouldNotBeFound': {}}, '.dart_tool': { 'package_config.json': packageConfigFile, } diff --git a/pkgs/package_config/test/parse_test.dart b/pkgs/package_config/test/parse_test.dart index 402fe8c42..a92b9bfcc 100644 --- a/pkgs/package_config/test/parse_test.dart +++ b/pkgs/package_config/test/parse_test.dart @@ -301,6 +301,25 @@ void main() { Uri.parse('package:qux/diz')); }); + test('packageOf is case sensitive on windows', () { + var configBytes = utf8.encode(json.encode({ + 'configVersion': 2, + 'packages': [ + {'name': 'foo', 'rootUri': 'file:///C:/Foo/', 'packageUri': 'lib/'}, + ] + })); + var config = parsePackageConfigBytes( + // ignore: unnecessary_cast + configBytes as Uint8List, + Uri.parse('file:///C:/tmp/.dart_tool/file.dart'), + throwError); + expect(config.version, 2); + expect( + config.packageOf(Uri.parse('file:///C:/foo/lala/lala.dart')), null); + expect(config.packageOf(Uri.parse('file:///C:/Foo/lala/lala.dart'))!.name, + 'foo'); + }); + group('invalid', () { void testThrows(String name, String source) { test(name, () { From 935c91e7617aaf72d8df1471400cb5c8eb52a6d3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Feb 2024 20:17:20 +0000 Subject: [PATCH 154/170] Bump dart-lang/setup-dart from 1.6.0 to 1.6.2 (dart-lang/package_config#146) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [dart-lang/setup-dart](https://github.com/dart-lang/setup-dart) from 1.6.0 to 1.6.2.
Release notes

Sourced from dart-lang/setup-dart's releases.

v1.6.2

v1.6.1

  • Updated the google storage url for main channel releases.
Changelog

Sourced from dart-lang/setup-dart's changelog.

v1.6.2

v1.6.1

  • Updated the google storage url for main channel releases.

v1.6.0

  • Enable provisioning of the latest Dart SDK patch release by specifying just the major and minor version (e.g. 3.2).

v1.5.1

  • No longer test the setup-dart action on pre-2.12 SDKs.
  • Upgrade JS interop code to use extension types (the new name for inline classes).
  • The upcoming rename of the be channel to main is now supported with forward compatibility that switches when the rename happens.

v1.5.0

  • Re-wrote the implementation of the action into Dart.
  • Auto-detect the platform architecture (x64, ia32, arm, arm64).
  • Improved the caching and download resilience of the sdk.
  • Added a new action output: dart-version - the installed version of the sdk.

v1.4.0

  • Automatically create OIDC token for pub.dev.
  • Add a reusable workflow for publishing.

v1.3.0

v1.2.0

  • Fixed a path issue impacting git dependencies on Windows.

v1.1.0

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=dart-lang/setup-dart&package-manager=github_actions&previous-version=1.6.0&new-version=1.6.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- pkgs/package_config/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/package_config/.github/workflows/test-package.yml b/pkgs/package_config/.github/workflows/test-package.yml index 1768fc834..0fdbdeaf4 100644 --- a/pkgs/package_config/.github/workflows/test-package.yml +++ b/pkgs/package_config/.github/workflows/test-package.yml @@ -23,7 +23,7 @@ jobs: sdk: [dev] steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 - - uses: dart-lang/setup-dart@b64355ae6ca0b5d484f0106a033dd1388965d06d + - uses: dart-lang/setup-dart@fedb1266e91cf51be2fdb382869461a434b920a3 with: sdk: ${{ matrix.sdk }} - id: install @@ -49,7 +49,7 @@ jobs: sdk: [3.2, dev] steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 - - uses: dart-lang/setup-dart@b64355ae6ca0b5d484f0106a033dd1388965d06d + - uses: dart-lang/setup-dart@fedb1266e91cf51be2fdb382869461a434b920a3 with: sdk: ${{ matrix.sdk }} - id: install From bff0401456cb06981c345e875ecd370be66c302a Mon Sep 17 00:00:00 2001 From: Michael Thomsen Date: Tue, 5 Mar 2024 01:20:14 +0100 Subject: [PATCH 155/170] Fix typo (dart-lang/package_config#149) --- pkgs/package_config/lib/src/package_config.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/package_config/lib/src/package_config.dart b/pkgs/package_config/lib/src/package_config.dart index c00ac67af..048555fc1 100644 --- a/pkgs/package_config/lib/src/package_config.dart +++ b/pkgs/package_config/lib/src/package_config.dart @@ -26,7 +26,7 @@ abstract class PackageConfig { /// is expected, but none have been specified or found. static const PackageConfig empty = SimplePackageConfig.empty(); - /// Creats a package configuration with the provided available [packages]. + /// Creates a package configuration with the provided available [packages]. /// /// The packages must be valid packages (valid package name, valid /// absolute directory URIs, valid language version, if any), From b9ca0553113924fffba7b6d8b2879e775d3ce5e7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Apr 2024 20:35:07 +0000 Subject: [PATCH 156/170] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/package_config#150) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.1 to 4.1.2.
Release notes

Sourced from actions/checkout's releases.

v4.1.2

We are investigating the following issue with this release and have rolled-back the v4 tag to point to v4.1.1

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v4.1.1...v4.1.2

Changelog

Sourced from actions/checkout's changelog.

Changelog

v4.1.2

v4.1.1

v4.1.0

v4.0.0

v3.6.0

v3.5.3

v3.5.2

v3.5.1

v3.5.0

v3.4.0

v3.3.0

v3.2.0

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=4.1.1&new-version=4.1.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- pkgs/package_config/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/package_config/.github/workflows/test-package.yml b/pkgs/package_config/.github/workflows/test-package.yml index 0fdbdeaf4..88c5dffee 100644 --- a/pkgs/package_config/.github/workflows/test-package.yml +++ b/pkgs/package_config/.github/workflows/test-package.yml @@ -22,7 +22,7 @@ jobs: matrix: sdk: [dev] steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 - uses: dart-lang/setup-dart@fedb1266e91cf51be2fdb382869461a434b920a3 with: sdk: ${{ matrix.sdk }} @@ -48,7 +48,7 @@ jobs: os: [ubuntu-latest, windows-latest] sdk: [3.2, dev] steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 - uses: dart-lang/setup-dart@fedb1266e91cf51be2fdb382869461a434b920a3 with: sdk: ${{ matrix.sdk }} From 84b8800af21e24663d24dfab239d5cac4fbe2984 Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Thu, 11 Apr 2024 08:56:47 +0200 Subject: [PATCH 157/170] Fix typos. (dart-lang/package_config#147) The wonders of in-IDE spell checking. Also ask for newest lints (no changes needed). --- pkgs/package_config/CHANGELOG.md | 2 +- pkgs/package_config/lib/src/discovery.dart | 8 ++++---- pkgs/package_config/lib/src/package_config.dart | 6 +++--- pkgs/package_config/lib/src/package_config_impl.dart | 2 +- pkgs/package_config/lib/src/packages_file.dart | 2 +- pkgs/package_config/lib/src/util.dart | 2 +- pkgs/package_config/pubspec.yaml | 2 +- pkgs/package_config/test/package_config_impl_test.dart | 2 +- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index a682bc3a4..2870c8c08 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -53,7 +53,7 @@ - Based on new JSON file format with more content. - This version includes all the new functionality intended for a 2.0.0 version, as well as the, now deprecated, version 1 functionality. - When we release 2.0.0, the deprectated functionality will be removed. + When we release 2.0.0, the deprecated functionality will be removed. ## 1.1.0 diff --git a/pkgs/package_config/lib/src/discovery.dart b/pkgs/package_config/lib/src/discovery.dart index 352bed8ca..b67841099 100644 --- a/pkgs/package_config/lib/src/discovery.dart +++ b/pkgs/package_config/lib/src/discovery.dart @@ -33,7 +33,7 @@ final Uri parentPath = Uri(path: '..'); /// Returns `null` if no configuration was found. If a configuration /// is needed, then the caller can supply [PackageConfig.empty]. /// -/// If [minVersion] is greated than 1, `.packages` files are ignored. +/// If [minVersion] is greater than 1, `.packages` files are ignored. /// If [minVersion] is greater than the version read from the /// `package_config.json` file, it too is ignored. Future findPackageConfig(Directory baseDirectory, @@ -46,7 +46,7 @@ Future findPackageConfig(Directory baseDirectory, do { // Check for $cwd/.packages var packageConfig = - await findPackagConfigInDirectory(directory, minVersion, onError); + await findPackageConfigInDirectory(directory, minVersion, onError); if (packageConfig != null) return packageConfig; if (!recursive) break; // Check in parent directories. @@ -113,10 +113,10 @@ Future findPackageConfigUri( /// a best-effort attempt is made to return a package configuration. /// This may be the empty package configuration. /// -/// If [minVersion] is greated than 1, `.packages` files are ignored. +/// If [minVersion] is greater than 1, `.packages` files are ignored. /// If [minVersion] is greater than the version read from the /// `package_config.json` file, it too is ignored. -Future findPackagConfigInDirectory(Directory directory, +Future findPackageConfigInDirectory(Directory directory, int minVersion, void Function(Object error) onError) async { var packageConfigFile = await checkForPackageConfigJsonFile(directory); if (packageConfigFile != null) { diff --git a/pkgs/package_config/lib/src/package_config.dart b/pkgs/package_config/lib/src/package_config.dart index 048555fc1..155dfc539 100644 --- a/pkgs/package_config/lib/src/package_config.dart +++ b/pkgs/package_config/lib/src/package_config.dart @@ -34,7 +34,7 @@ abstract class PackageConfig { /// /// The package's root ([Package.root]) and package-root /// ([Package.packageUriRoot]) paths must satisfy a number of constraints - /// We say that one path (which we know ends with a `/` charater) + /// We say that one path (which we know ends with a `/` character) /// is inside another path, if the latter path is a prefix of the former path, /// including the two paths being the same. /// @@ -159,7 +159,7 @@ abstract class PackageConfig { /// Look up a package by name. /// - /// Returns the [Package] fron [packages] with [packageName] as + /// Returns the [Package] from [packages] with [packageName] as /// [Package.name]. Returns `null` if the package is not available in the /// current configuration. Package? operator [](String packageName); @@ -377,7 +377,7 @@ abstract class LanguageVersion implements Comparable { /// An *invalid* language version. /// -/// Stored in a [Package] when the orginal language version string +/// Stored in a [Package] when the original language version string /// was invalid and a `onError` handler was passed to the parser /// which did not throw on an error. abstract class InvalidLanguageVersion implements LanguageVersion { diff --git a/pkgs/package_config/lib/src/package_config_impl.dart b/pkgs/package_config/lib/src/package_config_impl.dart index d8e8d495f..865e99a8e 100644 --- a/pkgs/package_config/lib/src/package_config_impl.dart +++ b/pkgs/package_config/lib/src/package_config_impl.dart @@ -436,7 +436,7 @@ class TriePackageTree implements PackageTree { } // For internal reasons we allow this (for now). One should still never do - // it thouh. + // it though. // 3) The new package is inside the packageUriRoot of existing package. if (_disallowPackagesInsidePackageUriRoot) { if (_beginsWith(0, existingPackage.packageUriRoot.toString(), diff --git a/pkgs/package_config/lib/src/packages_file.dart b/pkgs/package_config/lib/src/packages_file.dart index f84db1075..bf68f2c88 100644 --- a/pkgs/package_config/lib/src/packages_file.dart +++ b/pkgs/package_config/lib/src/packages_file.dart @@ -114,7 +114,7 @@ PackageConfig parse( } if (packageNames.contains(packageName)) { onError(PackageConfigFormatException( - 'Same package name occured more than once', source, start)); + 'Same package name occurred more than once', source, start)); continue; } var rootUri = packageLocation; diff --git a/pkgs/package_config/lib/src/util.dart b/pkgs/package_config/lib/src/util.dart index 3bf1bece3..f1fa20790 100644 --- a/pkgs/package_config/lib/src/util.dart +++ b/pkgs/package_config/lib/src/util.dart @@ -164,7 +164,7 @@ bool hasAbsolutePath(Uri uri) => /// the [baseUri], or if there is no overlap in the paths of the /// two URIs at all, the [uri] is returned as-is. /// -/// Otherwise the result is a path-only URI which satsifies +/// Otherwise the result is a path-only URI which satisfies /// `baseUri.resolveUri(result) == uri`, /// /// The `baseUri` must be absolute. diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 6ac7f54dd..9db82c64f 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -10,5 +10,5 @@ dependencies: path: ^1.8.0 dev_dependencies: - dart_flutter_team_lints: ^2.0.0 + dart_flutter_team_lints: ^2.1.0 test: ^1.16.0 diff --git a/pkgs/package_config/test/package_config_impl_test.dart b/pkgs/package_config/test/package_config_impl_test.dart index 87d1fd413..0f399636f 100644 --- a/pkgs/package_config/test/package_config_impl_test.dart +++ b/pkgs/package_config/test/package_config_impl_test.dart @@ -126,7 +126,7 @@ void main() { }); group('package config', () { - test('emtpy', () { + test('empty', () { var empty = PackageConfig([], extraData: unique); expect(empty.version, 2); expect(empty.packages, isEmpty); From 1f2920db3e8b68eda3990e1607628d81b2554b47 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 May 2024 20:46:46 +0000 Subject: [PATCH 158/170] Bump dart-lang/setup-dart from 1.6.2 to 1.6.4 (dart-lang/package_config#152) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [dart-lang/setup-dart](https://github.com/dart-lang/setup-dart) from 1.6.2 to 1.6.4.
Release notes

Sourced from dart-lang/setup-dart's releases.

v1.6.4

  • Rebuild JS code to include changes from v1.6.3

v1.6.3

Changelog

Sourced from dart-lang/setup-dart's changelog.

v1.6.4

  • Rebuild JS code.

v1.6.3

v1.6.2

v1.6.1

  • Updated the google storage url for main channel releases.

v1.6.0

  • Enable provisioning of the latest Dart SDK patch release by specifying just the major and minor version (e.g. 3.2).

v1.5.1

  • No longer test the setup-dart action on pre-2.12 SDKs.
  • Upgrade JS interop code to use extension types (the new name for inline classes).
  • The upcoming rename of the be channel to main is now supported with forward compatibility that switches when the rename happens.

v1.5.0

  • Re-wrote the implementation of the action into Dart.
  • Auto-detect the platform architecture (x64, ia32, arm, arm64).
  • Improved the caching and download resilience of the sdk.
  • Added a new action output: dart-version - the installed version of the sdk.

v1.4.0

  • Automatically create OIDC token for pub.dev.
  • Add a reusable workflow for publishing.

v1.3.0

  • The install location of the Dart SDK is now available

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=dart-lang/setup-dart&package-manager=github_actions&previous-version=1.6.2&new-version=1.6.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- pkgs/package_config/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/package_config/.github/workflows/test-package.yml b/pkgs/package_config/.github/workflows/test-package.yml index 88c5dffee..9196439e4 100644 --- a/pkgs/package_config/.github/workflows/test-package.yml +++ b/pkgs/package_config/.github/workflows/test-package.yml @@ -23,7 +23,7 @@ jobs: sdk: [dev] steps: - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 - - uses: dart-lang/setup-dart@fedb1266e91cf51be2fdb382869461a434b920a3 + - uses: dart-lang/setup-dart@f0ead981b4d9a35b37f30d36160575d60931ec30 with: sdk: ${{ matrix.sdk }} - id: install @@ -49,7 +49,7 @@ jobs: sdk: [3.2, dev] steps: - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 - - uses: dart-lang/setup-dart@fedb1266e91cf51be2fdb382869461a434b920a3 + - uses: dart-lang/setup-dart@f0ead981b4d9a35b37f30d36160575d60931ec30 with: sdk: ${{ matrix.sdk }} - id: install From 709cf70e99fbae9fd38659f69d81e8823eab3bb6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 May 2024 02:58:43 +0000 Subject: [PATCH 159/170] Bump actions/checkout from 4.1.2 to 4.1.4 (dart-lang/package_config#151) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.2 to 4.1.4.
Release notes

Sourced from actions/checkout's releases.

v4.1.4

What's Changed

Full Changelog: https://github.com/actions/checkout/compare/v4.1.3...v4.1.4

v4.1.3

What's Changed

Full Changelog: https://github.com/actions/checkout/compare/v4.1.2...v4.1.3

Changelog

Sourced from actions/checkout's changelog.

Changelog

v4.1.4

v4.1.3

v4.1.2

v4.1.1

v4.1.0

v4.0.0

v3.6.0

v3.5.3

v3.5.2

v3.5.1

v3.5.0

v3.4.0

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=4.1.2&new-version=4.1.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- pkgs/package_config/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/package_config/.github/workflows/test-package.yml b/pkgs/package_config/.github/workflows/test-package.yml index 9196439e4..2c2893435 100644 --- a/pkgs/package_config/.github/workflows/test-package.yml +++ b/pkgs/package_config/.github/workflows/test-package.yml @@ -22,7 +22,7 @@ jobs: matrix: sdk: [dev] steps: - - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b - uses: dart-lang/setup-dart@f0ead981b4d9a35b37f30d36160575d60931ec30 with: sdk: ${{ matrix.sdk }} @@ -48,7 +48,7 @@ jobs: os: [ubuntu-latest, windows-latest] sdk: [3.2, dev] steps: - - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b - uses: dart-lang/setup-dart@f0ead981b4d9a35b37f30d36160575d60931ec30 with: sdk: ${{ matrix.sdk }} From bc259463ae9bc33de667734b7d802eec7aeaec0e Mon Sep 17 00:00:00 2001 From: Devon Carew Date: Thu, 9 May 2024 13:46:44 -0700 Subject: [PATCH 160/170] blast_repo fixes (dart-lang/package_config#153) dependabot --- pkgs/package_config/.github/dependabot.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkgs/package_config/.github/dependabot.yml b/pkgs/package_config/.github/dependabot.yml index c84404dc9..a19a66adf 100644 --- a/pkgs/package_config/.github/dependabot.yml +++ b/pkgs/package_config/.github/dependabot.yml @@ -10,3 +10,7 @@ updates: interval: monthly labels: - autosubmit + groups: + github-actions: + patterns: + - "*" From 4031629a7ed3eaae045bab1a1b0313d9b2539a3c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 May 2024 20:53:27 +0000 Subject: [PATCH 161/170] Bump actions/checkout from 4.1.4 to 4.1.5 in the github-actions group (dart-lang/package_config#154) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the github-actions group with 1 update: [actions/checkout](https://github.com/actions/checkout). Updates `actions/checkout` from 4.1.4 to 4.1.5
Release notes

Sourced from actions/checkout's releases.

v4.1.5

What's Changed

Full Changelog: https://github.com/actions/checkout/compare/v4.1.4...v4.1.5

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=4.1.4&new-version=4.1.5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
--- pkgs/package_config/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/package_config/.github/workflows/test-package.yml b/pkgs/package_config/.github/workflows/test-package.yml index 2c2893435..c9d757965 100644 --- a/pkgs/package_config/.github/workflows/test-package.yml +++ b/pkgs/package_config/.github/workflows/test-package.yml @@ -22,7 +22,7 @@ jobs: matrix: sdk: [dev] steps: - - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b + - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b - uses: dart-lang/setup-dart@f0ead981b4d9a35b37f30d36160575d60931ec30 with: sdk: ${{ matrix.sdk }} @@ -48,7 +48,7 @@ jobs: os: [ubuntu-latest, windows-latest] sdk: [3.2, dev] steps: - - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b + - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b - uses: dart-lang/setup-dart@f0ead981b4d9a35b37f30d36160575d60931ec30 with: sdk: ${{ matrix.sdk }} From 80670e18721ea8f36b8fba01591cd416b94eaa20 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Jun 2024 20:59:14 +0000 Subject: [PATCH 162/170] Bump actions/checkout from 4.1.5 to 4.1.6 in the github-actions group (dart-lang/package_config#155) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the github-actions group with 1 update: [actions/checkout](https://github.com/actions/checkout). Updates `actions/checkout` from 4.1.5 to 4.1.6
Release notes

Sourced from actions/checkout's releases.

v4.1.6

What's Changed

Full Changelog: https://github.com/actions/checkout/compare/v4.1.5...v4.1.6

Changelog

Sourced from actions/checkout's changelog.

Changelog

v4.1.6

v4.1.5

v4.1.4

v4.1.3

v4.1.2

v4.1.1

v4.1.0

v4.0.0

v3.6.0

v3.5.3

v3.5.2

v3.5.1

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=4.1.5&new-version=4.1.6)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
--- pkgs/package_config/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/package_config/.github/workflows/test-package.yml b/pkgs/package_config/.github/workflows/test-package.yml index c9d757965..3fd2c820b 100644 --- a/pkgs/package_config/.github/workflows/test-package.yml +++ b/pkgs/package_config/.github/workflows/test-package.yml @@ -22,7 +22,7 @@ jobs: matrix: sdk: [dev] steps: - - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 - uses: dart-lang/setup-dart@f0ead981b4d9a35b37f30d36160575d60931ec30 with: sdk: ${{ matrix.sdk }} @@ -48,7 +48,7 @@ jobs: os: [ubuntu-latest, windows-latest] sdk: [3.2, dev] steps: - - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 - uses: dart-lang/setup-dart@f0ead981b4d9a35b37f30d36160575d60931ec30 with: sdk: ${{ matrix.sdk }} From 58f90e988ff570a86be87da2631fe345aed60d5e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Jul 2024 20:38:26 +0000 Subject: [PATCH 163/170] Bump the github-actions group with 2 updates (dart-lang/package_config#156) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the github-actions group with 2 updates: [actions/checkout](https://github.com/actions/checkout) and [dart-lang/setup-dart](https://github.com/dart-lang/setup-dart). Updates `actions/checkout` from 4.1.6 to 4.1.7
Release notes

Sourced from actions/checkout's releases.

v4.1.7

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v4.1.6...v4.1.7

Changelog

Sourced from actions/checkout's changelog.

Changelog

v4.1.7

v4.1.6

v4.1.5

v4.1.4

v4.1.3

v4.1.2

v4.1.1

v4.1.0

v4.0.0

v3.6.0

v3.5.3

... (truncated)

Commits

Updates `dart-lang/setup-dart` from 1.6.4 to 1.6.5
Release notes

Sourced from dart-lang/setup-dart's releases.

v1.6.5

dart-lang/package_config#118: dart-lang/setup-dartdart-lang/package_config#118

Changelog

Sourced from dart-lang/setup-dart's changelog.

v1.6.5

dart-lang/package_config#118: dart-lang/setup-dartdart-lang/package_config#118

v1.6.4

  • Rebuild JS code.

v1.6.3

v1.6.2

v1.6.1

  • Updated the google storage url for main channel releases.

v1.6.0

  • Enable provisioning of the latest Dart SDK patch release by specifying just the major and minor version (e.g. 3.2).

v1.5.1

  • No longer test the setup-dart action on pre-2.12 SDKs.
  • Upgrade JS interop code to use extension types (the new name for inline classes).
  • The upcoming rename of the be channel to main is now supported with forward compatibility that switches when the rename happens.

v1.5.0

  • Re-wrote the implementation of the action into Dart.
  • Auto-detect the platform architecture (x64, ia32, arm, arm64).
  • Improved the caching and download resilience of the sdk.
  • Added a new action output: dart-version - the installed version of the sdk.

v1.4.0

... (truncated)

Commits

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
--- pkgs/package_config/.github/workflows/test-package.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkgs/package_config/.github/workflows/test-package.yml b/pkgs/package_config/.github/workflows/test-package.yml index 3fd2c820b..33717105d 100644 --- a/pkgs/package_config/.github/workflows/test-package.yml +++ b/pkgs/package_config/.github/workflows/test-package.yml @@ -22,8 +22,8 @@ jobs: matrix: sdk: [dev] steps: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 - - uses: dart-lang/setup-dart@f0ead981b4d9a35b37f30d36160575d60931ec30 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 with: sdk: ${{ matrix.sdk }} - id: install @@ -48,8 +48,8 @@ jobs: os: [ubuntu-latest, windows-latest] sdk: [3.2, dev] steps: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 - - uses: dart-lang/setup-dart@f0ead981b4d9a35b37f30d36160575d60931ec30 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 with: sdk: ${{ matrix.sdk }} - id: install From 5bfdcd8e92db637a134f188e5204b970b306c79c Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Tue, 6 Aug 2024 09:04:47 -0700 Subject: [PATCH 164/170] Latest lints, require Dart 3.4 (dart-lang/package_config#157) --- pkgs/package_config/.github/workflows/test-package.yml | 2 +- pkgs/package_config/CHANGELOG.md | 2 +- pkgs/package_config/lib/package_config.dart | 2 +- pkgs/package_config/lib/package_config_types.dart | 2 +- pkgs/package_config/lib/src/util.dart | 2 +- pkgs/package_config/lib/src/util_io.dart | 2 +- pkgs/package_config/pubspec.yaml | 4 ++-- pkgs/package_config/test/discovery_test.dart | 2 +- pkgs/package_config/test/discovery_uri_test.dart | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/pkgs/package_config/.github/workflows/test-package.yml b/pkgs/package_config/.github/workflows/test-package.yml index 33717105d..704ee2e3c 100644 --- a/pkgs/package_config/.github/workflows/test-package.yml +++ b/pkgs/package_config/.github/workflows/test-package.yml @@ -46,7 +46,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest] - sdk: [3.2, dev] + sdk: [3.4, dev] steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index 2870c8c08..f9fec1d00 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -1,6 +1,6 @@ ## 2.1.1-wip -- Require Dart 3.2 +- Require Dart 3.4 ## 2.1.0 diff --git a/pkgs/package_config/lib/package_config.dart b/pkgs/package_config/lib/package_config.dart index 194fe894e..074c97707 100644 --- a/pkgs/package_config/lib/package_config.dart +++ b/pkgs/package_config/lib/package_config.dart @@ -7,7 +7,7 @@ /// /// This package provides functionality to find, read and write package /// configurations in the [specified format](https://github.com/dart-lang/language/blob/master/accepted/future-releases/language-versioning/package-config-file-v2.md). -library package_config.package_config; +library; import 'dart:io' show Directory, File; import 'dart:typed_data' show Uint8List; diff --git a/pkgs/package_config/lib/package_config_types.dart b/pkgs/package_config/lib/package_config_types.dart index 756be0518..825f7acec 100644 --- a/pkgs/package_config/lib/package_config_types.dart +++ b/pkgs/package_config/lib/package_config_types.dart @@ -10,7 +10,7 @@ /// {@canonicalFor package_config.Package} /// {@canonicalFor package_config.PackageConfig} /// {@canonicalFor errors.PackageConfigError} -library package_config.package_config_types; +library; export 'src/errors.dart' show PackageConfigError; export 'src/package_config.dart' diff --git a/pkgs/package_config/lib/src/util.dart b/pkgs/package_config/lib/src/util.dart index f1fa20790..4f0210cda 100644 --- a/pkgs/package_config/lib/src/util.dart +++ b/pkgs/package_config/lib/src/util.dart @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. /// Utility methods used by more than one library in the package. -library package_config.util; +library; import 'errors.dart'; diff --git a/pkgs/package_config/lib/src/util_io.dart b/pkgs/package_config/lib/src/util_io.dart index 914ea384e..4680eefd4 100644 --- a/pkgs/package_config/lib/src/util_io.dart +++ b/pkgs/package_config/lib/src/util_io.dart @@ -4,7 +4,7 @@ /// Utility methods requiring dart:io and used by more than one library in the /// package. -library package_config.util_io; +library; import 'dart:io'; import 'dart:typed_data'; diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 9db82c64f..545701d6d 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -4,11 +4,11 @@ description: Support for reading and writing Dart Package Configuration files. repository: https://github.com/dart-lang/package_config environment: - sdk: ^3.2.0 + sdk: ^3.4.0 dependencies: path: ^1.8.0 dev_dependencies: - dart_flutter_team_lints: ^2.1.0 + dart_flutter_team_lints: ^3.0.0 test: ^1.16.0 diff --git a/pkgs/package_config/test/discovery_test.dart b/pkgs/package_config/test/discovery_test.dart index 2ca337a19..6d1b65529 100644 --- a/pkgs/package_config/test/discovery_test.dart +++ b/pkgs/package_config/test/discovery_test.dart @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. @TestOn('vm') -library package_config.discovery_test; +library; import 'dart:io'; diff --git a/pkgs/package_config/test/discovery_uri_test.dart b/pkgs/package_config/test/discovery_uri_test.dart index b71ed5172..542bf0a65 100644 --- a/pkgs/package_config/test/discovery_uri_test.dart +++ b/pkgs/package_config/test/discovery_uri_test.dart @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. @TestOn('vm') -library package_config.discovery_test; +library; import 'package:package_config/package_config.dart'; import 'package:test/test.dart'; From 3b5c3516779f6bec9bb5374966674841a46172f4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 20:49:51 +0000 Subject: [PATCH 165/170] Bump actions/checkout from 4.1.7 to 4.2.0 in the github-actions group (dart-lang/package_config#159) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the github-actions group with 1 update: [actions/checkout](https://github.com/actions/checkout). Updates `actions/checkout` from 4.1.7 to 4.2.0
Release notes

Sourced from actions/checkout's releases.

v4.2.0

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v4.1.7...v4.2.0

Changelog

Sourced from actions/checkout's changelog.

Changelog

v4.2.0

v4.1.7

v4.1.6

v4.1.5

v4.1.4

v4.1.3

v4.1.2

v4.1.1

v4.1.0

v4.0.0

v3.6.0

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=4.1.7&new-version=4.2.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
--- pkgs/package_config/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/package_config/.github/workflows/test-package.yml b/pkgs/package_config/.github/workflows/test-package.yml index 704ee2e3c..629a95d64 100644 --- a/pkgs/package_config/.github/workflows/test-package.yml +++ b/pkgs/package_config/.github/workflows/test-package.yml @@ -22,7 +22,7 @@ jobs: matrix: sdk: [dev] steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 with: sdk: ${{ matrix.sdk }} @@ -48,7 +48,7 @@ jobs: os: [ubuntu-latest, windows-latest] sdk: [3.4, dev] steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 with: sdk: ${{ matrix.sdk }} From 34d75539e5838239d12b3d3b548c6c82d16465e1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 20:39:05 +0000 Subject: [PATCH 166/170] Bump actions/checkout from 4.2.0 to 4.2.2 in the github-actions group (dart-lang/package_config#160) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the github-actions group with 1 update: [actions/checkout](https://github.com/actions/checkout). Updates `actions/checkout` from 4.2.0 to 4.2.2
Release notes

Sourced from actions/checkout's releases.

v4.2.2

What's Changed

Full Changelog: https://github.com/actions/checkout/compare/v4.2.1...v4.2.2

v4.2.1

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v4.2.0...v4.2.1

Changelog

Sourced from actions/checkout's changelog.

Changelog

v4.2.2

v4.2.1

v4.2.0

v4.1.7

v4.1.6

v4.1.5

v4.1.4

v4.1.3

v4.1.2

v4.1.1

v4.1.0

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=4.2.0&new-version=4.2.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
--- pkgs/package_config/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/package_config/.github/workflows/test-package.yml b/pkgs/package_config/.github/workflows/test-package.yml index 629a95d64..526e05593 100644 --- a/pkgs/package_config/.github/workflows/test-package.yml +++ b/pkgs/package_config/.github/workflows/test-package.yml @@ -22,7 +22,7 @@ jobs: matrix: sdk: [dev] steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 with: sdk: ${{ matrix.sdk }} @@ -48,7 +48,7 @@ jobs: os: [ubuntu-latest, windows-latest] sdk: [3.4, dev] steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 with: sdk: ${{ matrix.sdk }} From adca221376fef5545f3a997c8004aba8780ce0b9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Dec 2024 20:07:57 +0000 Subject: [PATCH 167/170] Bump dart-lang/setup-dart in the github-actions group (dart-lang/package_config#161) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the github-actions group with 1 update: [dart-lang/setup-dart](https://github.com/dart-lang/setup-dart). Updates `dart-lang/setup-dart` from 1.6.5 to 1.7.0
Release notes

Sourced from dart-lang/setup-dart's releases.

v1.7.0

What's Changed

  • Install a Flutter SDK in the publish workflow allowing for publication of flutter packages.
Changelog

Sourced from dart-lang/setup-dart's changelog.

v1.7.0

v1.6.5

dart-lang/package_config#118: dart-lang/setup-dartdart-lang/package_config#118

v1.6.4

  • Rebuild JS code.

v1.6.3

v1.6.2

v1.6.1

  • Updated the google storage url for main channel releases.

v1.6.0

  • Enable provisioning of the latest Dart SDK patch release by specifying just the major and minor version (e.g. 3.2).

v1.5.1

  • No longer test the setup-dart action on pre-2.12 SDKs.
  • Upgrade JS interop code to use extension types (the new name for inline classes).
  • The upcoming rename of the be channel to main is now supported with forward compatibility that switches when the rename happens.

v1.5.0

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=dart-lang/setup-dart&package-manager=github_actions&previous-version=1.6.5&new-version=1.7.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
--- pkgs/package_config/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/package_config/.github/workflows/test-package.yml b/pkgs/package_config/.github/workflows/test-package.yml index 526e05593..718ec07b8 100644 --- a/pkgs/package_config/.github/workflows/test-package.yml +++ b/pkgs/package_config/.github/workflows/test-package.yml @@ -23,7 +23,7 @@ jobs: sdk: [dev] steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 + - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94 with: sdk: ${{ matrix.sdk }} - id: install @@ -49,7 +49,7 @@ jobs: sdk: [3.4, dev] steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 + - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94 with: sdk: ${{ matrix.sdk }} - id: install From a9b1487e63fe99389ff269eaee7c5a9653566b9d Mon Sep 17 00:00:00 2001 From: Moritz Date: Mon, 9 Dec 2024 16:56:09 +0100 Subject: [PATCH 168/170] Add issue template and other fixes --- .github/ISSUE_TEMPLATE/package_config.md | 5 ++++ pkgs/package_config/CONTRIBUTING.md | 33 ------------------------ pkgs/package_config/pubspec.yaml | 2 +- 3 files changed, 6 insertions(+), 34 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/package_config.md delete mode 100644 pkgs/package_config/CONTRIBUTING.md diff --git a/.github/ISSUE_TEMPLATE/package_config.md b/.github/ISSUE_TEMPLATE/package_config.md new file mode 100644 index 000000000..f6322d0fa --- /dev/null +++ b/.github/ISSUE_TEMPLATE/package_config.md @@ -0,0 +1,5 @@ +--- +name: "package:package_config" +about: "Create a bug or file a feature request against package:package_config." +labels: "package:package_config" +--- \ No newline at end of file diff --git a/pkgs/package_config/CONTRIBUTING.md b/pkgs/package_config/CONTRIBUTING.md deleted file mode 100644 index 8423ff94f..000000000 --- a/pkgs/package_config/CONTRIBUTING.md +++ /dev/null @@ -1,33 +0,0 @@ -Want to contribute? Great! First, read this page (including the small print at -the end). - -### Before you contribute -Before we can use your code, you must sign the -[Google Individual Contributor License Agreement](https://cla.developers.google.com/about/google-individual) -(CLA), which you can do online. The CLA is necessary mainly because you own the -copyright to your changes, even after your contribution becomes part of our -codebase, so we need your permission to use and distribute your code. We also -need to be sure of various other things—for instance that you'll tell us if you -know that your code infringes on other people's patents. You don't have to sign -the CLA until after you've submitted your code for review and a member has -approved it, but you must do it before we can put your code into our codebase. - -Before you start working on a larger contribution, you should get in touch with -us first through the issue tracker with your idea so that we can help out and -possibly guide you. Coordinating up front makes it much easier to avoid -frustration later on. - -### Code reviews -All submissions, including submissions by project members, require review. - -### File headers -All files in the project must start with the following header. - - // Copyright (c) 2019, 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. - -### The small print -Contributions made by corporations are covered by a different agreement than the -one above, the -[Software Grant and Corporate Contributor License Agreement](https://developers.google.com/open-source/cla/corporate). diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 545701d6d..5e1356b02 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,7 +1,7 @@ name: package_config version: 2.1.1-wip description: Support for reading and writing Dart Package Configuration files. -repository: https://github.com/dart-lang/package_config +repository: https://github.com/dart-lang/tools/tree/main/pkgs/package_config environment: sdk: ^3.4.0 From 3327cbf89b56b0234fd4da728f1f181394609b1a Mon Sep 17 00:00:00 2001 From: Moritz Date: Tue, 10 Dec 2024 11:33:46 +0100 Subject: [PATCH 169/170] Moving fixes --- .github/labeler.yml | 4 ++++ .../workflows/package_config.yaml | 17 ++++++++++++++--- README.md | 1 + pkgs/package_config/.github/dependabot.yml | 16 ---------------- pkgs/package_config/CHANGELOG.md | 1 + pkgs/package_config/README.md | 2 +- pkgs/package_config/pubspec.yaml | 2 +- 7 files changed, 22 insertions(+), 21 deletions(-) rename pkgs/package_config/.github/workflows/test-package.yml => .github/workflows/package_config.yaml (83%) delete mode 100644 pkgs/package_config/.github/dependabot.yml diff --git a/.github/labeler.yml b/.github/labeler.yml index 45c2239b1..31b8b4733 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -76,6 +76,10 @@ - changed-files: - any-glob-to-any-file: 'pkgs/oauth2/**' +'package:package_config': + - changed-files: + - any-glob-to-any-file: 'pkgs/package_config/**' + 'package:source_map_stack_trace': - changed-files: - any-glob-to-any-file: 'pkgs/source_map_stack_trace/**' diff --git a/pkgs/package_config/.github/workflows/test-package.yml b/.github/workflows/package_config.yaml similarity index 83% rename from pkgs/package_config/.github/workflows/test-package.yml rename to .github/workflows/package_config.yaml index 718ec07b8..416ea1a11 100644 --- a/pkgs/package_config/.github/workflows/test-package.yml +++ b/.github/workflows/package_config.yaml @@ -1,17 +1,28 @@ -name: Dart CI +name: package:package_config on: # Run on PRs and pushes to the default branch. push: - branches: [ master ] + branches: [ main ] + paths: + - '.github/workflows/package_config.yml' + - 'pkgs/package_config/**' pull_request: - branches: [ master ] + branches: [ main ] + paths: + - '.github/workflows/package_config.yml' + - 'pkgs/package_config/**' schedule: - cron: "0 0 * * 0" env: PUB_ENVIRONMENT: bot.github + +defaults: + run: + working-directory: pkgs/package_config/ + jobs: # Check code formatting and static analysis on a single OS (linux) # against Dart dev. diff --git a/README.md b/README.md index ed90416dd..01360e92b 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ don't naturally belong to other topic monorepos (like | [json_rpc_2](pkgs/json_rpc_2/) | Utilities to write a client or server using the JSON-RPC 2.0 spec. | [![package issues](https://img.shields.io/badge/package:json_rpc_2-4774bc)](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Ajson_rpc_2) | [![pub package](https://img.shields.io/pub/v/json_rpc_2.svg)](https://pub.dev/packages/json_rpc_2) | | [mime](pkgs/mime/) | Utilities for handling media (MIME) types, including determining a type from a file extension and file contents. | [![package issues](https://img.shields.io/badge/package:mime-4774bc)](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Amime) | [![pub package](https://img.shields.io/pub/v/mime.svg)](https://pub.dev/packages/mime) | | [oauth2](pkgs/oauth2/) | A client library for authenticating with a remote service via OAuth2 on behalf of a user, and making authorized HTTP requests with the user's OAuth2 credentials. | [![package issues](https://img.shields.io/badge/package:oauth2-4774bc)](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Aoauth2) | [![pub package](https://img.shields.io/pub/v/oauth2.svg)](https://pub.dev/packages/oauth2) | +| [package_config](pkgs/package_config/) | Support for reading and writing Dart Package Configuration files. | [![package issues](https://img.shields.io/badge/package:package_config-4774bc)](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Apackage_config) | [![pub package](https://img.shields.io/pub/v/package_config.svg)](https://pub.dev/packages/package_config) | | [source_map_stack_trace](pkgs/source_map_stack_trace/) | A package for applying source maps to stack traces. | [![package issues](https://img.shields.io/badge/package:source_map_stack_trace-4774bc)](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Asource_map_stack_trace) | [![pub package](https://img.shields.io/pub/v/source_map_stack_trace.svg)](https://pub.dev/packages/source_map_stack_trace) | | [unified_analytics](pkgs/unified_analytics/) | A package for logging analytics for all Dart and Flutter related tooling to Google Analytics. | [![package issues](https://img.shields.io/badge/package:unified_analytics-4774bc)](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Aunified_analytics) | [![pub package](https://img.shields.io/pub/v/unified_analytics.svg)](https://pub.dev/packages/unified_analytics) | diff --git a/pkgs/package_config/.github/dependabot.yml b/pkgs/package_config/.github/dependabot.yml deleted file mode 100644 index a19a66adf..000000000 --- a/pkgs/package_config/.github/dependabot.yml +++ /dev/null @@ -1,16 +0,0 @@ -# Set update schedule for GitHub Actions -# See https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/keeping-your-actions-up-to-date-with-dependabot - -version: 2 -updates: - -- package-ecosystem: github-actions - directory: / - schedule: - interval: monthly - labels: - - autosubmit - groups: - github-actions: - patterns: - - "*" diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index f9fec1d00..93033ed6e 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -1,6 +1,7 @@ ## 2.1.1-wip - Require Dart 3.4 +- Move to `dart-lang/tools` monorepo. ## 2.1.0 diff --git a/pkgs/package_config/README.md b/pkgs/package_config/README.md index 9e2e41f0b..76fd3cbed 100644 --- a/pkgs/package_config/README.md +++ b/pkgs/package_config/README.md @@ -1,4 +1,4 @@ -[![Build Status](https://github.com/dart-lang/package_config/workflows/Dart%20CI/badge.svg)](https://github.com/dart-lang/package_config/actions?query=workflow%3A"Dart+CI"+branch%3Amaster) +[![Build Status](https://github.com/dart-lang/tools/actions/workflows/package_config.yaml/badge.svg)](https://github.com/dart-lang/tools/actions/workflows/package_config.yaml) [![pub package](https://img.shields.io/pub/v/package_config.svg)](https://pub.dev/packages/package_config) [![package publisher](https://img.shields.io/pub/publisher/package_config.svg)](https://pub.dev/packages/package_config/publisher) diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml index 5e1356b02..28f3e1364 100644 --- a/pkgs/package_config/pubspec.yaml +++ b/pkgs/package_config/pubspec.yaml @@ -1,5 +1,5 @@ name: package_config -version: 2.1.1-wip +version: 2.1.1 description: Support for reading and writing Dart Package Configuration files. repository: https://github.com/dart-lang/tools/tree/main/pkgs/package_config From 3655677c5fa2af487a2d443282266cda0ef1f193 Mon Sep 17 00:00:00 2001 From: Moritz Date: Tue, 10 Dec 2024 14:03:01 +0100 Subject: [PATCH 170/170] Remove wip --- pkgs/package_config/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md index 93033ed6e..101a0fe76 100644 --- a/pkgs/package_config/CHANGELOG.md +++ b/pkgs/package_config/CHANGELOG.md @@ -1,4 +1,4 @@ -## 2.1.1-wip +## 2.1.1 - Require Dart 3.4 - Move to `dart-lang/tools` monorepo.