Index: sdk/lib/_internal/pub/lib/src/source.dart |
diff --git a/sdk/lib/_internal/pub/lib/src/source.dart b/sdk/lib/_internal/pub/lib/src/source.dart |
index 06181c5197a5ee46803b9e9ac5e5fbc074b48a5b..b68fe8a210f4e9b5e8753fa39ff26ab9518de411 100644 |
--- a/sdk/lib/_internal/pub/lib/src/source.dart |
+++ b/sdk/lib/_internal/pub/lib/src/source.dart |
@@ -6,20 +6,20 @@ library pub.source; |
import 'dart:async'; |
-import 'package:path/path.dart' as path; |
-import 'package:stack_trace/stack_trace.dart'; |
- |
-import 'io.dart'; |
import 'package.dart'; |
import 'pubspec.dart'; |
import 'system_cache.dart'; |
-import 'utils.dart'; |
import 'version.dart'; |
/// A source from which to get packages. |
/// |
-/// Each source has many packages that it looks up using [PackageId]s. The |
-/// source is responsible for getting these packages into the package cache. |
+/// Each source has many packages that it looks up using [PackageId]s. Sources |
+/// that inherit this directly (currently just [PathSource]) are *uncached* |
+/// sources. They deliver a package directly to the package that depends on it. |
+/// |
+/// 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. |
abstract class Source { |
/// The name of the source. Should be lower-case, suitable for use in a |
/// filename, and unique accross all sources. |
@@ -28,27 +28,16 @@ abstract class Source { |
/// Whether or not this source is the default source. |
bool get isDefault => systemCache.sources.defaultSource == this; |
- /// Whether this source's packages should be cached in Pub's global cache |
- /// directory. |
- /// |
- /// A source should be cached if it requires network access to retrieve |
- /// packages. It doesn't need to be cached if all packages are available |
- /// locally. |
- bool get shouldCache; |
- |
/// The system cache with which this source is registered. |
SystemCache get systemCache { |
assert(_systemCache != null); |
return _systemCache; |
} |
- /// The system cache variable. Set by [_bind]. |
- SystemCache _systemCache; |
- |
- /// The root directory of this source's cache within the system cache. |
+ /// The system cache variable. |
/// |
- /// This shouldn't be overridden by subclasses. |
- String get systemCacheRoot => path.join(systemCache.rootDir, name); |
+ /// Set by [_bind]. |
+ SystemCache _systemCache; |
/// Records the system cache to which this source belongs. |
/// |
@@ -62,7 +51,7 @@ abstract class Source { |
/// Get the list of all versions that exist for the package described by |
/// [description]. [name] is the expected name of the package. |
/// |
- /// Note that this does *not* require the package to be downloaded locally, |
+ /// Note that this does *not* require the packages to be downloaded locally, |
/// which is the point. This is used during version resolution to determine |
/// which package versions are available to be downloaded (or already |
/// downloaded). |
@@ -71,176 +60,44 @@ abstract class Source { |
/// uses [describe] to get that version. |
Future<List<Version>> getVersions(String name, description) { |
var id = new PackageId(name, this.name, Version.none, description); |
- return describeUncached(id).then((pubspec) => [pubspec.version]); |
+ return describe(id).then((pubspec) => [pubspec.version]); |
} |
/// Loads the (possibly remote) pubspec for the package version identified by |
/// [id]. This may be called for packages that have not yet been downloaded |
/// during the version resolution process. |
/// |
- /// If the package has been downloaded to the system cache, the cached pubspec |
- /// will be used. Otherwise, it delegates to host-specific lookup behavior. |
- /// |
- /// For cached sources, by default this uses [downloadToSystemCache] to get |
- /// the pubspec. There is no default implementation for non-cached sources; |
- /// they must implement it manually. |
+ /// Sources should not override this. Instead, they implement [onDescribe]. |
Future<Pubspec> describe(PackageId id) { |
if (id.isRoot) throw new ArgumentError("Cannot describe the root package."); |
if (id.source != name) { |
throw new ArgumentError("Package $id does not use source $name."); |
} |
- // Try to get it from the system cache first. |
- if (shouldCache) { |
- return systemCacheDirectory(id).then((packageDir) { |
- if (!fileExists(path.join(packageDir, "pubspec.yaml"))) { |
- return describeUncached(id); |
- } |
- |
- return new Pubspec.load(packageDir, _systemCache.sources, |
- expectedName: id.name); |
- }); |
- } |
- |
- // Not cached, so get it from the source. |
- return describeUncached(id); |
+ // Delegate to the overridden one. |
+ return onDescribe(id); |
} |
- /// Loads the pubspec for the package version identified by [id] which is not |
- /// already in the system cache. |
- /// |
- /// For cached sources, by default this uses [downloadToSystemCache] to get |
- /// the pubspec. There is no default implementation for non-cached sources; |
- /// they must implement it manually. |
+ /// Loads the (possibly remote) pubspec for the package version identified by |
+ /// [id]. This may be called for packages that have not yet been downloaded |
+ /// during the version resolution process. |
/// |
- /// This method is effectively protected. Derived classes may override it, |
- /// but external code should not call it. Call [describe()] instead. |
- Future<Pubspec> describeUncached(PackageId id) { |
- if (!shouldCache) { |
- throw new UnimplementedError( |
- "Source $name must implement describeUncached(id)."); |
- } |
- return downloadToSystemCache(id).then((package) => package.pubspec); |
- } |
+ /// This method is effectively protected: subclasses must implement it, but |
+ /// external code should not call this. Instead, call [describe]. |
+ Future<Pubspec> onDescribe(PackageId id); |
/// Gets the package identified by [id] and places it at [path]. |
/// |
- /// Returns a [Future] that completes when the operation finishes. The |
- /// [Future] should resolve to true if the package was found in the source |
- /// and false if it wasn't. For all other error conditions, it should complete |
- /// with an exception. |
- /// |
- /// [path] is guaranteed not to exist, and its parent directory is guaranteed |
- /// to exist. |
- /// |
- /// Note that [path] may be deleted. If re-getting a package that has already |
- /// been gotten would be costly or impossible, [downloadToSystemCache] |
- /// should be implemented instead of [get]. |
- /// |
- /// This doesn't need to be implemented if [downloadToSystemCache] is |
- /// implemented. |
- Future<bool> get(PackageId id, String path) { |
- throw new UnimplementedError("Either get() or downloadToSystemCache() must " |
- "be implemented for source $name."); |
- } |
- |
- /// Determines if the package with [id] is already downloaded to the system |
- /// cache. |
- /// |
- /// This should only be called for sources with [shouldCache] set to true. |
- /// Completes to true if the package is in the cache and appears to be |
- /// uncorrupted. |
- Future<bool> isInSystemCache(PackageId id) { |
- return systemCacheDirectory(id).then((packageDir) { |
- return dirExists(packageDir) && !_isCachedPackageCorrupted(packageDir); |
- }); |
- } |
- |
- /// Downloads the package identified by [id] to the system cache. |
- /// |
- /// This is only called for sources with [shouldCache] set to true. By |
- /// default, this uses [systemCacheDirectory] and [get]. |
- /// |
- /// If [force] is `true`, then the package is downloaded even if it already |
- /// exists in the cache. The previous one will be deleted. |
- Future<Package> downloadToSystemCache(PackageId id, {bool force}) { |
- if (force == null) force = false; |
- |
- var packageDir; |
- return systemCacheDirectory(id).then((p) { |
- packageDir = p; |
- |
- // See if it's already cached. |
- if (dirExists(packageDir)) { |
- if (force || _isCachedPackageCorrupted(packageDir)) { |
- // Wipe it out and re-install it. |
- deleteEntry(packageDir); |
- } else { |
- // Already downloaded. |
- return true; |
- } |
- } |
+ /// Returns a [Future] that completes when the operation finishes. [path] is |
+ /// guaranteed not to exist, and its parent directory is guaranteed to exist. |
+ Future get(PackageId id, String path); |
- ensureDir(path.dirname(packageDir)); |
- return get(id, packageDir); |
- }).then((found) { |
- if (!found) fail('Package $id not found.'); |
- return new Package.load(id.name, packageDir, systemCache.sources); |
- }); |
- } |
- |
- /// Since pub generates symlinks that point into the system cache (in |
- /// particular, targeting the "lib" directories of cached packages), it's |
- /// possible to accidentally break cached packages if something traverses |
- /// that symlink. |
- /// |
- /// This tries to determine if the cached package at [packageDir] has been |
- /// corrupted. The heuristics are it is corrupted if any of the following are |
- /// true: |
+ /// Returns the directory where this package can (or could) be found locally. |
/// |
- /// * It has an empty "lib" directory. |
- /// * It has no pubspec. |
- bool _isCachedPackageCorrupted(String packageDir) { |
- if (!fileExists(path.join(packageDir, "pubspec.yaml"))) return true; |
- |
- var libDir = path.join(packageDir, "lib"); |
- if (dirExists(libDir)) return listDir(libDir).length == 0; |
- |
- // If we got here, it's OK. |
- return false; |
- } |
- |
- /// Returns the directory where this package can be found locally. If this is |
- /// a cached source, it will be in the system cache. Otherwise, it will |
- /// depend on the source. |
- Future<String> getDirectory(PackageId id) { |
- if (shouldCache) return systemCacheDirectory(id); |
- throw new UnimplementedError("Source $name must implement this."); |
- } |
- |
- /// Returns the directory in the system cache that the package identified by |
- /// [id] should be downloaded to. This should return a path to a subdirectory |
- /// of [systemCacheRoot]. |
- /// |
- /// This doesn't need to be implemented if [shouldCache] is false. |
- Future<String> systemCacheDirectory(PackageId id) { |
- return new Future.error( |
- "systemCacheDirectory() must be implemented if shouldCache is true.", |
- new Chain.current()); |
- } |
- |
- /// Reinstalls all packages that have been previously installed into the |
- /// system cache by this source. |
- /// |
- /// Returns a [Pair] whose first element is the number of packages |
- /// successfully repaired and the second is the number of failures. |
- Future<Pair<int, int>> repairCachedPackages() { |
- if (shouldCache) { |
- throw new UnimplementedError("Source $name must implement this."); |
- } |
- throw new UnsupportedError("Cannot call repairCachedPackages() on an " |
- "uncached source."); |
- } |
+ /// If the source is cached, this will be a path in the system cache. In that |
+ /// case, this will return a directory even if the package has not been |
+ /// installed into the cache yet. |
+ Future<String> getDirectory(PackageId id); |
/// 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 |
@@ -259,9 +116,7 @@ abstract class Source { |
/// [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}) { |
- return description; |
- } |
+ {bool fromLockFile: false}); |
/// When a [LockFile] is serialized, it uses this method to get the |
/// [description] in the right format. |
@@ -284,10 +139,7 @@ abstract class Source { |
/// Returns whether or not [description1] describes the same package as |
/// [description2] for this source. This method should be light-weight. It |
/// doesn't need to validate that either package exists. |
- /// |
- /// By default, just uses regular equality. |
- bool descriptionsEqual(description1, description2) => |
- description1 == description2; |
+ bool descriptionsEqual(description1, description2); |
/// 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 |
@@ -309,15 +161,6 @@ abstract class Source { |
/// By default, this just returns [id]. |
Future<PackageId> resolveId(PackageId id) => new Future.value(id); |
- /// Returns the [Package]s that have been downloaded to the system cache. |
- List<Package> getCachedPackages() { |
- if (shouldCache) { |
- throw new UnimplementedError("Source $name must implement this."); |
- } |
- throw new UnsupportedError("Cannot call getCachedPackages() on an " |
- "uncached source."); |
- } |
- |
/// Returns the source's name. |
String toString() => name; |
} |