Index: utils/pub/source.dart |
diff --git a/utils/pub/source.dart b/utils/pub/source.dart |
index 777c1a0222fc8f8ffbd1e4e9229cc5ca77009279..da6b0b72db7d82e7d30d8e00dd5ece569463b7b7 100644 |
--- a/utils/pub/source.dart |
+++ b/utils/pub/source.dart |
@@ -108,7 +108,18 @@ abstract class Source { |
var path; |
return systemCacheDirectory(id).then((p) { |
path = p; |
- if (dirExists(path)) return true; |
+ |
+ // See if it's already cached. |
+ if (!dirExists(path)) return false; |
+ |
+ return _isCachedPackageCorrupted(path).then((isCorrupted) { |
+ if (!isCorrupted) return true; |
+ |
+ // Busted, so wipe out the package and reinstall. |
+ return deleteDir(path).then((_) => false); |
+ }); |
+ }).then((isInstalled) { |
+ if (isInstalled) return true; |
ensureDir(dirname(path)); |
return install(id, path); |
}).then((found) { |
@@ -117,6 +128,31 @@ abstract class Source { |
}); |
} |
+ /// 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. |
+ Future<bool> _isCachedPackageCorrupted(String packageDir) { |
+ return defer(() { |
+ if (!fileExists(join(packageDir, "pubspec.yaml"))) return true; |
+ |
+ var libDir = join(packageDir, "lib"); |
+ if (dirExists(libDir)) { |
+ return listDir(libDir).then((contents) => contents.length == 0); |
+ } |
+ |
+ // If we got here, it's OK. |
+ return false; |
+ }); |
+ } |
+ |
/// Returns the directory in the system cache that the package identified by |
/// [id] should be installed to. This should return a path to a subdirectory |
/// of [systemCacheRoot]. |