| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library pub.source.git; | 5 library pub.source.git; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 | 8 |
| 9 import 'package:path/path.dart' as path; | 9 import 'package:path/path.dart' as path; |
| 10 | 10 |
| 11 import '../git.dart' as git; | 11 import '../git.dart' as git; |
| 12 import '../io.dart'; | 12 import '../io.dart'; |
| 13 import '../log.dart' as log; | 13 import '../log.dart' as log; |
| 14 import '../package.dart'; | 14 import '../package.dart'; |
| 15 import '../source.dart'; | 15 import '../pubspec.dart'; |
| 16 import '../utils.dart'; | 16 import '../utils.dart'; |
| 17 import 'cached.dart'; |
| 17 | 18 |
| 18 /// A package source that gets packages from Git repos. | 19 /// A package source that gets packages from Git repos. |
| 19 class GitSource extends Source { | 20 class GitSource extends CachedSource { |
| 20 final String name = "git"; | 21 final name = "git"; |
| 21 | |
| 22 final bool shouldCache = true; | |
| 23 | 22 |
| 24 /// The paths to the canonical clones of repositories for which "git fetch" | 23 /// The paths to the canonical clones of repositories for which "git fetch" |
| 25 /// has already been run during this run of pub. | 24 /// has already been run during this run of pub. |
| 26 final _updatedRepos = new Set<String>(); | 25 final _updatedRepos = new Set<String>(); |
| 27 | 26 |
| 28 GitSource(); | 27 GitSource(); |
| 29 | 28 |
| 29 /// Since we don't have an easy way to read from a remote Git repo, this |
| 30 /// just installs [id] into the system cache, then describes it from there. |
| 31 Future<Pubspec> describeUncached(PackageId id) { |
| 32 return downloadToSystemCache(id).then((package) => package.pubspec); |
| 33 } |
| 34 |
| 30 /// Clones a Git repo to the local filesystem. | 35 /// Clones a Git repo to the local filesystem. |
| 31 /// | 36 /// |
| 32 /// The Git cache directory is a little idiosyncratic. At the top level, it | 37 /// The Git cache directory is a little idiosyncratic. At the top level, it |
| 33 /// contains a directory for each commit of each repository, named `<package | 38 /// contains a directory for each commit of each repository, named `<package |
| 34 /// name>-<commit hash>`. These are the canonical package directories that are | 39 /// name>-<commit hash>`. These are the canonical package directories that are |
| 35 /// linked to from the `packages/` directory. | 40 /// linked to from the `packages/` directory. |
| 36 /// | 41 /// |
| 37 /// In addition, the Git system cache contains a subdirectory named `cache/` | 42 /// In addition, the Git system cache contains a subdirectory named `cache/` |
| 38 /// which contains a directory for each separate repository URL, named | 43 /// which contains a directory for each separate repository URL, named |
| 39 /// `<package name>-<url hash>`. These are used to check out the repository | 44 /// `<package name>-<url hash>`. These are used to check out the repository |
| 40 /// itself; each of the commit-specific directories are clones of a directory | 45 /// itself; each of the commit-specific directories are clones of a directory |
| 41 /// in `cache/`. | 46 /// in `cache/`. |
| 42 Future<Package> downloadToSystemCache(PackageId id, {bool force}) { | 47 Future<Package> downloadToSystemCache(PackageId id, {bool force}) { |
| 43 // Force is not supported because the cache repair command doesn't need it. | 48 // Force is not supported because the cache repair command doesn't need it. |
| 44 // Instead, it uses [resetCachedPackages]. | 49 // Instead, it uses [resetCachedPackages]. |
| 45 assert(force != true); | 50 assert(force != true); |
| 46 | 51 |
| 47 var revisionCachePath; | 52 var revisionCachePath; |
| 48 | 53 |
| 49 return git.isInstalled.then((installed) { | 54 return git.isInstalled.then((installed) { |
| 50 if (!installed) { | 55 if (!installed) { |
| 51 throw new Exception( | 56 throw new Exception( |
| 52 "Cannot get ${id.name} from Git (${_getUrl(id)}).\n" | 57 "Cannot get ${id.name} from Git (${_getUrl(id)}).\n" |
| 53 "Please ensure Git is correctly installed."); | 58 "Please ensure Git is correctly installed."); |
| 54 } | 59 } |
| 55 | 60 |
| 56 ensureDir(path.join(systemCacheRoot, 'cache')); | 61 ensureDir(path.join(systemCacheRoot, 'cache')); |
| 57 return _ensureRevision(id); | 62 return _ensureRevision(id); |
| 58 }).then((_) => systemCacheDirectory(id)).then((path) { | 63 }).then((_) => getDirectory(id)).then((path) { |
| 59 revisionCachePath = path; | 64 revisionCachePath = path; |
| 60 if (entryExists(revisionCachePath)) return null; | 65 if (entryExists(revisionCachePath)) return null; |
| 61 return _clone(_repoCachePath(id), revisionCachePath, mirror: false); | 66 return _clone(_repoCachePath(id), revisionCachePath, mirror: false); |
| 62 }).then((_) { | 67 }).then((_) { |
| 63 var ref = _getEffectiveRef(id); | 68 var ref = _getEffectiveRef(id); |
| 64 if (ref == 'HEAD') return null; | 69 if (ref == 'HEAD') return null; |
| 65 return _checkOut(revisionCachePath, ref); | 70 return _checkOut(revisionCachePath, ref); |
| 66 }).then((_) { | 71 }).then((_) { |
| 67 return new Package.load(id.name, revisionCachePath, systemCache.sources); | 72 return new Package.load(id.name, revisionCachePath, systemCache.sources); |
| 68 }); | 73 }); |
| 69 } | 74 } |
| 70 | 75 |
| 71 /// Returns the path to the revision-specific cache of [id]. | 76 /// Returns the path to the revision-specific cache of [id]. |
| 72 Future<String> systemCacheDirectory(PackageId id) { | 77 Future<String> getDirectory(PackageId id) { |
| 73 return _ensureRevision(id).then((rev) { | 78 return _ensureRevision(id).then((rev) { |
| 74 var revisionCacheName = '${id.name}-$rev'; | 79 var revisionCacheName = '${id.name}-$rev'; |
| 75 return path.join(systemCacheRoot, revisionCacheName); | 80 return path.join(systemCacheRoot, revisionCacheName); |
| 76 }); | 81 }); |
| 77 } | 82 } |
| 78 | 83 |
| 79 /// Ensures [description] is a Git URL. | 84 /// Ensures [description] is a Git URL. |
| 80 dynamic parseDescription(String containingPath, description, | 85 dynamic parseDescription(String containingPath, description, |
| 81 {bool fromLockFile: false}) { | 86 {bool fromLockFile: false}) { |
| 82 // TODO(rnystrom): Handle git URLs that are relative file paths (#8570). | 87 // TODO(rnystrom): Handle git URLs that are relative file paths (#8570). |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 116 | 121 |
| 117 /// Attaches a specific commit to [id] to disambiguate it. | 122 /// Attaches a specific commit to [id] to disambiguate it. |
| 118 Future<PackageId> resolveId(PackageId id) { | 123 Future<PackageId> resolveId(PackageId id) { |
| 119 return _ensureRevision(id).then((revision) { | 124 return _ensureRevision(id).then((revision) { |
| 120 var description = {'url': _getUrl(id), 'ref': _getRef(id)}; | 125 var description = {'url': _getUrl(id), 'ref': _getRef(id)}; |
| 121 description['resolved-ref'] = revision; | 126 description['resolved-ref'] = revision; |
| 122 return new PackageId(id.name, name, id.version, description); | 127 return new PackageId(id.name, name, id.version, description); |
| 123 }); | 128 }); |
| 124 } | 129 } |
| 125 | 130 |
| 131 List<Package> getCachedPackages() { |
| 132 // TODO(keertip): Implement getCachedPackages(). |
| 133 throw new UnimplementedError( |
| 134 "The git source doesn't support listing its cached packages yet."); |
| 135 } |
| 136 |
| 126 /// Resets all cached packages back to the pristine state of the Git | 137 /// Resets all cached packages back to the pristine state of the Git |
| 127 /// repository at the revision they are pinned to. | 138 /// repository at the revision they are pinned to. |
| 128 Future<Pair<int, int>> repairCachedPackages() { | 139 Future<Pair<int, int>> repairCachedPackages() { |
| 129 if (!dirExists(systemCacheRoot)) return new Future.value(new Pair(0, 0)); | 140 if (!dirExists(systemCacheRoot)) return new Future.value(new Pair(0, 0)); |
| 130 | 141 |
| 131 var successes = 0; | 142 var successes = 0; |
| 132 var failures = 0; | 143 var failures = 0; |
| 133 | 144 |
| 134 var packages = listDir(systemCacheRoot) | 145 var packages = listDir(systemCacheRoot) |
| 135 .where((entry) => dirExists(path.join(entry, ".git"))) | 146 .where((entry) => dirExists(path.join(entry, ".git"))) |
| (...skipping 19 matching lines...) Expand all Loading... |
| 155 }).catchError((error, stackTrace) { | 166 }).catchError((error, stackTrace) { |
| 156 failures++; | 167 failures++; |
| 157 log.error("Failed to reset ${log.bold(package.name)} " | 168 log.error("Failed to reset ${log.bold(package.name)} " |
| 158 "${package.version}. Error:\n$error"); | 169 "${package.version}. Error:\n$error"); |
| 159 log.fine(stackTrace); | 170 log.fine(stackTrace); |
| 160 failures++; | 171 failures++; |
| 161 }, test: (error) => error is git.GitException); | 172 }, test: (error) => error is git.GitException); |
| 162 })).then((_) => new Pair(successes, failures)); | 173 })).then((_) => new Pair(successes, failures)); |
| 163 } | 174 } |
| 164 | 175 |
| 165 // TODO(keertip): Implement getCachedPackages(). | |
| 166 | |
| 167 /// Ensure that the canonical clone of the repository referred to by [id] (the | 176 /// Ensure that the canonical clone of the repository referred to by [id] (the |
| 168 /// one in `<system cache>/git/cache`) exists and contains the revision | 177 /// one in `<system cache>/git/cache`) exists and contains the revision |
| 169 /// referred to by [id]. | 178 /// referred to by [id]. |
| 170 /// | 179 /// |
| 171 /// Returns a future that completes to the hash of the revision identified by | 180 /// Returns a future that completes to the hash of the revision identified by |
| 172 /// [id]. | 181 /// [id]. |
| 173 Future<String> _ensureRevision(PackageId id) { | 182 Future<String> _ensureRevision(PackageId id) { |
| 174 return syncFuture(() { | 183 return syncFuture(() { |
| 175 var path = _repoCachePath(id); | 184 var path = _repoCachePath(id); |
| 176 if (!entryExists(path)) { | 185 if (!entryExists(path)) { |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 282 return description['ref']; | 291 return description['ref']; |
| 283 } | 292 } |
| 284 | 293 |
| 285 /// Returns [description] if it's a description, or [PackageId.description] if | 294 /// Returns [description] if it's a description, or [PackageId.description] if |
| 286 /// it's a [PackageId]. | 295 /// it's a [PackageId]. |
| 287 _getDescription(description) { | 296 _getDescription(description) { |
| 288 if (description is PackageId) return description.description; | 297 if (description is PackageId) return description.description; |
| 289 return description; | 298 return description; |
| 290 } | 299 } |
| 291 } | 300 } |
| OLD | NEW |