| Index: lib/src/source.dart
|
| diff --git a/lib/src/source.dart b/lib/src/source.dart
|
| index 7e5625a2a5b079ca0479afca0a711caa04422f0d..ff590b2404940cbbcd26a8ed027803bec57eab71 100644
|
| --- a/lib/src/source.dart
|
| +++ b/lib/src/source.dart
|
| @@ -11,6 +11,7 @@ import 'package:pub_semver/pub_semver.dart';
|
| import 'package.dart';
|
| import 'pubspec.dart';
|
| import 'system_cache.dart';
|
| +import 'utils.dart';
|
|
|
| /// A source from which to get packages.
|
| ///
|
| @@ -21,6 +22,28 @@ import 'system_cache.dart';
|
| /// Other sources are *cached* sources. These extend [CachedSource]. When a
|
| /// package needs a dependency from a cached source, it is first installed in
|
| /// the [SystemCache] and then acquired from there.
|
| +///
|
| +/// ## Subclassing
|
| +///
|
| +/// All sources should extend this class. In addition to defining the behavior
|
| +/// of various methods, sources define the structure of package descriptions
|
| +/// used in [PackageRef]s, [PackageDep]s, and [PackageId]s. There are three
|
| +/// distinct types of description, although in practice most sources use the
|
| +/// same format for one or more of these:
|
| +///
|
| +/// * User descriptions. These are included in pubspecs and usually written by
|
| +/// hand. They're typically more flexible in the formats they allow to
|
| +/// optimize for ease of authoring.
|
| +///
|
| +/// * Reference descriptions. These are the descriptions in [PackageRef]s and
|
| +/// [PackageDep]. They're parsed directly from user descriptions using
|
| +/// [parseRef], and so add no additional information.
|
| +///
|
| +/// * ID descriptions. These are the descriptions in [PackageId]s, which
|
| +/// uniquely identify and provide the means to locate the concrete code of a
|
| +/// package. They may contain additional expensive-to-compute information
|
| +/// relative to the corresponding reference descriptions. These are the
|
| +/// descriptions stored in lock files.
|
| abstract class Source {
|
| /// The name of the source.
|
| ///
|
| @@ -94,10 +117,7 @@ abstract class Source {
|
| ///
|
| /// This method is effectively protected: subclasses must implement it, but
|
| /// external code should not call this. Instead, call [getVersions].
|
| - Future<List<PackageId>> doGetVersions(PackageRef ref) async {
|
| - var pubspec = await describe(ref.atVersion(Version.none));
|
| - return [ref.atVersion(pubspec.version)];
|
| - }
|
| + Future<List<PackageId>> doGetVersions(PackageRef ref);
|
|
|
| /// Loads the (possibly remote) pubspec for the package version identified by
|
| /// [id].
|
| @@ -105,6 +125,9 @@ abstract class Source {
|
| /// This may be called for packages that have not yet been downloaded during
|
| /// the version resolution process. Its results are automatically memoized.
|
| ///
|
| + /// Throws a [DataException] if the pubspec's version doesn't match [id]'s
|
| + /// version.
|
| + ///
|
| /// Sources should not override this. Instead, they implement [doDescribe].
|
| Future<Pubspec> describe(PackageId id) async {
|
| if (id.isRoot) throw new ArgumentError("Cannot describe the root package.");
|
| @@ -117,7 +140,11 @@ abstract class Source {
|
|
|
| // Delegate to the overridden one.
|
| pubspec = await doDescribe(id);
|
| - _pubspecs[id.atVersion(pubspec.version)] = pubspec;
|
| + if (pubspec.version != id.version) {
|
| + dataError("The pubspec for $id has version ${pubspec.version}.");
|
| + }
|
| +
|
| + _pubspecs[id] = pubspec;
|
| return pubspec;
|
| }
|
|
|
| @@ -138,31 +165,34 @@ abstract class Source {
|
| /// Returns the directory where this package can (or could) be found locally.
|
| ///
|
| /// If the source is cached, this will be a path in the system cache.
|
| - /// Depending on the source, this may throw an [ArgumentError] if [id] isn't
|
| - /// resolved using [resolveId].
|
| String getDirectory(PackageId id);
|
|
|
| - /// Gives the source a chance to interpret and validate the description for
|
| - /// a package coming from this source.
|
| + /// Parses a [PackageRef] from a name and a user-provided [description].
|
| ///
|
| - /// When a [Pubspec] or [LockFile] is parsed, it reads in the description for
|
| - /// each dependency. It is up to the dependency's [Source] to determine how
|
| - /// that should be interpreted. This will be called during parsing to validate
|
| - /// that the given [description] is well-formed according to this source, and
|
| - /// to give the source a chance to canonicalize the description.
|
| + /// When a [Pubspec] is parsed, it reads in the description for each
|
| + /// dependency. It is up to the dependency's [Source] to determine how that
|
| + /// should be interpreted. This will be called during parsing to validate that
|
| + /// the given [description] is well-formed according to this source, and to
|
| + /// give the source a chance to canonicalize the description.
|
| ///
|
| /// [containingPath] is the path to the local file (pubspec or lockfile)
|
| /// where this description appears. It may be `null` if the description is
|
| /// coming from some in-memory source (such as pulling down a pubspec from
|
| /// pub.dartlang.org).
|
| ///
|
| - /// It should return if a (possibly modified) valid description, or throw a
|
| - /// [FormatException] if not valid.
|
| + /// The description in the returned [PackageRef] need bear no resemblance to
|
| + /// the original user-provided description.
|
| ///
|
| - /// [fromLockFile] is true when the description comes from a [LockFile], to
|
| - /// allow the source to use lockfile-specific descriptions via [resolveId].
|
| - dynamic parseDescription(String containingPath, description,
|
| - {bool fromLockFile: false});
|
| + /// Throws a [FormatException] if the description is not valid.
|
| + PackageRef parseRef(String name, description, {String containingPath});
|
| +
|
| + /// Parses a [PackageId] from a name and a serialized description.
|
| + ///
|
| + /// This only accepts descriptions serialized using [serializeDescription]. It
|
| + /// should not be used with user-authored descriptions.
|
| + ///
|
| + /// Throws a [FormatException] if the description is not valid.
|
| + PackageId parseId(String name, Version version, description);
|
|
|
| /// When a [LockFile] is serialized, it uses this method to get the
|
| /// [description] in the right format.
|
| @@ -187,33 +217,11 @@ abstract class Source {
|
| ///
|
| /// This method should be light-weight. It doesn't need to validate that
|
| /// either package exists.
|
| - bool descriptionsEqual(description1, description2);
|
| -
|
| - /// Resolves [id] to a more possibly more precise that will uniquely identify
|
| - /// a package regardless of when the package is requested.
|
| - ///
|
| - /// For some sources, [PackageId]s can point to different chunks of code at
|
| - /// different times. This takes such an [id] and returns a future that
|
| - /// completes to a [PackageId] that will uniquely specify a single chunk of
|
| - /// code forever.
|
| ///
|
| - /// For example, [GitSource] might take an [id] with description
|
| - /// `http://github.com/dart-lang/some-lib.git` and return an id with a
|
| - /// description that includes the current commit of the Git repository.
|
| - ///
|
| - /// Pub calls this after getting a package, so the source can use the local
|
| - /// package to determine information about the resolved id.
|
| - ///
|
| - /// The returned [PackageId] may have a description field that's invalid
|
| - /// according to [parseDescription], although it must still be serializable
|
| - /// to JSON and YAML. It must also be equal to [id] according to
|
| - /// [descriptionsEqual].
|
| - ///
|
| - /// By default, this just returns [id].
|
| - Future<PackageId> resolveId(PackageId id) => new Future.value(id);
|
| -
|
| - /// Returns whether [id] is fully-resolved, according to [resolveId].
|
| - bool isResolved(PackageId id) => true;
|
| + /// Note that either description may be a reference description or an ID
|
| + /// description; they need not be the same type. ID descriptions should be
|
| + /// considered equal to the reference descriptions that produced them.
|
| + bool descriptionsEqual(description1, description2);
|
|
|
| /// Stores [pubspec] so it's returned when [describe] is called with [id].
|
| ///
|
|
|