Index: sdk/lib/_internal/pub/lib/src/source/cached.dart |
diff --git a/sdk/lib/_internal/pub/lib/src/source/cached.dart b/sdk/lib/_internal/pub/lib/src/source/cached.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..2be69be42ffc34e79abae1cbb6552582c8951b35 |
--- /dev/null |
+++ b/sdk/lib/_internal/pub/lib/src/source/cached.dart |
@@ -0,0 +1,101 @@ |
+// Copyright (c) 2014, 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 pub.source.cached; |
+ |
+import 'dart:async'; |
+ |
+import 'package:path/path.dart' as path; |
+ |
+import '../io.dart'; |
+import '../package.dart'; |
+import '../pubspec.dart'; |
+import '../source.dart'; |
+import '../utils.dart'; |
+ |
+/// Base class for a [Source] that installs packages into pub's [SystemCache]. |
+/// |
+/// A source should be cached if it requires network access to retrieve |
+/// packages or the package needs to be "frozen" at the point in time that it's |
+/// installed. (For example, Git packages are cached because installing from |
+/// the same repo over time may yield different commits.) |
+abstract class CachedSource extends Source { |
+ /// The root directory of this source's cache within the system cache. |
+ /// |
+ /// This shouldn't be overridden by subclasses. |
+ String get systemCacheRoot => path.join(systemCache.rootDir, name); |
+ |
+ /// If [id] is already in the system cache, just loads it from there. |
+ /// |
+ /// Otherwise, defers to the subclass. |
+ Future<Pubspec> onDescribe(PackageId id) { |
+ return getDirectory(id).then((packageDir) { |
+ if (fileExists(path.join(packageDir, "pubspec.yaml"))) { |
+ return new Pubspec.load(packageDir, systemCache.sources, |
+ expectedName: id.name); |
+ } |
+ |
+ return describeUncached(id); |
+ }); |
+ } |
+ |
+ /// Loads the (possibly remote) pubspec for the package version identified by |
+ /// [id]. |
+ /// |
+ /// This will only be called for packages that have not yet been installed in |
+ /// the system cache. |
+ Future<Pubspec> describeUncached(PackageId id); |
+ |
+ Future get(PackageId id, String packageDir) { |
+ return downloadToSystemCache(id).then( |
+ (pkg) => createPackageSymlink(id.name, pkg.dir, packageDir)); |
+ } |
+ |
+ /// Determines if the package with [id] is already downloaded to the system |
+ /// cache. |
+ /// |
+ /// Completes to true if the package is in the cache and appears to be |
+ /// uncorrupted. |
+ Future<bool> isInSystemCache(PackageId id) { |
+ // Let the system cache initiate the download so that it can handle |
+ // multiple concurrent downloads of the same package. |
+ return getDirectory(id).then((packageDir) { |
+ return dirExists(packageDir) && !isCachedPackageCorrupted(packageDir); |
+ }); |
+ } |
+ |
+ /// Downloads the package identified by [id] to the system cache. |
+ Future<Package> downloadToSystemCache(PackageId id); |
+ |
+ /// Returns the [Package]s that have been downloaded to the system cache. |
+ List<Package> getCachedPackages(); |
+ |
+ /// 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(); |
+ |
+ /// 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: |
+ /// |
+ /// * 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; |
+ } |
+} |