Chromium Code Reviews| 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 import 'package:pub_semver/pub_semver.dart'; | |
| 10 | 11 |
| 11 import '../git.dart' as git; | 12 import '../git.dart' as git; |
| 12 import '../io.dart'; | 13 import '../io.dart'; |
| 13 import '../log.dart' as log; | 14 import '../log.dart' as log; |
| 14 import '../package.dart'; | 15 import '../package.dart'; |
| 15 import '../pubspec.dart'; | 16 import '../pubspec.dart'; |
| 16 import '../utils.dart'; | 17 import '../utils.dart'; |
| 17 import 'cached.dart'; | 18 import 'cached.dart'; |
| 18 | 19 |
| 19 /// A package source that gets packages from Git repos. | 20 /// A package source that gets packages from Git repos. |
| 20 class GitSource extends CachedSource { | 21 class GitSource extends CachedSource { |
| 22 /// Returns a reference to a git package with the given [name] and [url]. | |
| 23 /// | |
| 24 /// If passed, [reference] is the Git reference. It defaults to `"HEAD"`. | |
| 25 static PackageRef refFor(String name, String url, {String reference}) => | |
| 26 new PackageRef(name, "git", {'url': url, 'ref': reference ?? 'HEAD'}); | |
| 27 | |
| 21 /// Given a valid git package description, returns the URL of the repository | 28 /// Given a valid git package description, returns the URL of the repository |
| 22 /// it pulls from. | 29 /// it pulls from. |
| 23 static String urlFromDescription(description) => description["url"]; | 30 static String urlFromDescription(description) => description["url"]; |
| 24 | 31 |
| 25 final name = "git"; | 32 final name = "git"; |
| 26 | 33 |
| 27 /// The paths to the canonical clones of repositories for which "git fetch" | 34 /// The paths to the canonical clones of repositories for which "git fetch" |
| 28 /// has already been run during this run of pub. | 35 /// has already been run during this run of pub. |
| 29 final _updatedRepos = new Set<String>(); | 36 final _updatedRepos = new Set<String>(); |
| 30 | 37 |
| 31 /// Given a Git repo that contains a pub package, gets the name of the pub | 38 /// Given a Git repo that contains a pub package, gets the name of the pub |
| 32 /// package. | 39 /// package. |
| 33 Future<String> getPackageNameFromRepo(String repo) { | 40 Future<String> getPackageNameFromRepo(String repo) { |
| 34 // Clone the repo to a temp directory. | 41 // Clone the repo to a temp directory. |
| 35 return withTempDir((tempDir) { | 42 return withTempDir((tempDir) { |
| 36 return _clone(repo, tempDir, shallow: true).then((_) { | 43 return _clone(repo, tempDir, shallow: true).then((_) { |
| 37 var pubspec = new Pubspec.load(tempDir, systemCache.sources); | 44 var pubspec = new Pubspec.load(tempDir, systemCache.sources); |
| 38 return pubspec.name; | 45 return pubspec.name; |
| 39 }); | 46 }); |
| 40 }); | 47 }); |
| 41 } | 48 } |
| 42 | 49 |
| 50 Future<List<PackageId>> doGetVersions(PackageRef ref) async { | |
| 51 await _ensureRepoCache(ref); | |
| 52 var path = _repoCachePath(ref); | |
| 53 var revision = await _firstRevision(path, ref.description['ref']); | |
| 54 var pubspec = await _describeUncached(ref, revision); | |
| 55 | |
| 56 return [ | |
| 57 new PackageId(ref.name, name, pubspec.version, { | |
| 58 'url': ref.description['url'], | |
| 59 'ref': ref.description['ref'], | |
| 60 'resolved-ref': revision | |
| 61 }) | |
| 62 ]; | |
| 63 } | |
| 64 | |
| 43 /// Since we don't have an easy way to read from a remote Git repo, this | 65 /// Since we don't have an easy way to read from a remote Git repo, this |
| 44 /// just installs [id] into the system cache, then describes it from there. | 66 /// just installs [id] into the system cache, then describes it from there. |
| 45 Future<Pubspec> describeUncached(PackageId id) { | 67 Future<Pubspec> describeUncached(PackageId id) => |
| 46 return downloadToSystemCache(id).then((package) => package.pubspec); | 68 _describeUncached(id.toRef(), id.description['resolved-ref']); |
| 69 | |
| 70 /// Like [describeUncached], but takes a separate [ref] and Git [revision] | |
| 71 /// rather than a single ID. | |
| 72 Future<Pubspec> _describeUncached(PackageRef ref, String revision) async { | |
| 73 await _ensureRevision(ref, revision); | |
| 74 var path = _repoCachePath(ref); | |
| 75 | |
| 76 var lines; | |
| 77 try { | |
| 78 lines = await git.run(["show", "$revision:pubspec.yaml"], | |
| 79 workingDir: path); | |
| 80 } on git.GitException catch (_) { | |
| 81 fail('Could not find a file named "pubspec.yaml" in ' | |
| 82 '${ref.description['url']} $revision.'); | |
| 83 } | |
| 84 | |
| 85 return new Pubspec.parse(lines.join("\n"), systemCache.sources, | |
| 86 expectedName: ref.name); | |
| 47 } | 87 } |
| 48 | 88 |
| 49 /// Clones a Git repo to the local filesystem. | 89 /// Clones a Git repo to the local filesystem. |
| 50 /// | 90 /// |
| 51 /// The Git cache directory is a little idiosyncratic. At the top level, it | 91 /// The Git cache directory is a little idiosyncratic. At the top level, it |
| 52 /// contains a directory for each commit of each repository, named `<package | 92 /// contains a directory for each commit of each repository, named `<package |
| 53 /// name>-<commit hash>`. These are the canonical package directories that are | 93 /// name>-<commit hash>`. These are the canonical package directories that are |
| 54 /// linked to from the `packages/` directory. | 94 /// linked to from the `packages/` directory. |
| 55 /// | 95 /// |
| 56 /// In addition, the Git system cache contains a subdirectory named `cache/` | 96 /// In addition, the Git system cache contains a subdirectory named `cache/` |
| 57 /// which contains a directory for each separate repository URL, named | 97 /// which contains a directory for each separate repository URL, named |
| 58 /// `<package name>-<url hash>`. These are used to check out the repository | 98 /// `<package name>-<url hash>`. These are used to check out the repository |
| 59 /// itself; each of the commit-specific directories are clones of a directory | 99 /// itself; each of the commit-specific directories are clones of a directory |
| 60 /// in `cache/`. | 100 /// in `cache/`. |
| 61 Future<Package> downloadToSystemCache(PackageId id) async { | 101 Future<Package> downloadToSystemCache(PackageId id) async { |
| 102 var ref = id.toRef(); | |
| 62 if (!git.isInstalled) { | 103 if (!git.isInstalled) { |
| 63 fail("Cannot get ${id.name} from Git (${_getUrl(id)}).\n" | 104 fail("Cannot get ${id.name} from Git (${ref.description['url']}).\n" |
| 64 "Please ensure Git is correctly installed."); | 105 "Please ensure Git is correctly installed."); |
| 65 } | 106 } |
| 66 | 107 |
| 67 ensureDir(path.join(systemCacheRoot, 'cache')); | 108 ensureDir(path.join(systemCacheRoot, 'cache')); |
| 68 await _ensureRevision(id); | 109 await _ensureRevision(ref, id.description['resolved-ref']); |
| 69 var revisionCachePath = getDirectory(await resolveId(id)); | 110 |
| 111 var revisionCachePath = getDirectory(id); | |
| 70 if (!entryExists(revisionCachePath)) { | 112 if (!entryExists(revisionCachePath)) { |
| 71 await _clone(_repoCachePath(id), revisionCachePath, mirror: false); | 113 await _clone(_repoCachePath(ref), revisionCachePath); |
| 114 await _checkOut(revisionCachePath, id.description['resolved-ref']); | |
| 72 } | 115 } |
| 73 | 116 |
| 74 var ref = _getEffectiveRef(id); | |
| 75 if (ref != 'HEAD') await _checkOut(revisionCachePath, ref); | |
| 76 | |
| 77 return new Package.load(id.name, revisionCachePath, systemCache.sources); | 117 return new Package.load(id.name, revisionCachePath, systemCache.sources); |
| 78 } | 118 } |
| 79 | 119 |
| 80 /// Returns the path to the revision-specific cache of [id]. | 120 /// Returns the path to the revision-specific cache of [id]. |
| 81 String getDirectory(PackageId id) { | 121 String getDirectory(PackageId id) => path.join( |
| 82 if (id.description is! Map || !id.description.containsKey('resolved-ref')) { | 122 systemCacheRoot, "${id.name}-${id.description['resolved-ref']}"); |
| 83 throw new ArgumentError("Can't get the directory for unresolved id $id."); | |
| 84 } | |
| 85 | 123 |
| 86 return path.join(systemCacheRoot, | 124 PackageRef parseRef(String name, description, {String containingPath}) { |
| 87 "${id.name}-${id.description['resolved-ref']}"); | 125 // TODO(rnystrom): Handle git URLs that are relative file paths (#8570). |
| 88 } | 126 if (description is String) description = {'url': description}; |
| 89 | 127 |
| 90 /// Ensures [description] is a Git URL. | 128 if (description is! Map) { |
| 91 dynamic parseDescription(String containingPath, description, | |
| 92 {bool fromLockFile: false}) { | |
| 93 // TODO(rnystrom): Handle git URLs that are relative file paths (#8570). | |
| 94 // TODO(rnystrom): Now that this function can modify the description, it | |
| 95 // may as well canonicalize it to a map so that other code in the source | |
| 96 // can assume that. | |
| 97 // A single string is assumed to be a Git URL. | |
| 98 if (description is String) return description; | |
| 99 if (description is! Map || !description.containsKey('url')) { | |
| 100 throw new FormatException("The description must be a Git URL or a map " | 129 throw new FormatException("The description must be a Git URL or a map " |
| 101 "with a 'url' key."); | 130 "with a 'url' key."); |
| 102 } | 131 } |
| 103 | 132 |
| 104 var parsed = new Map.from(description); | 133 if (description["url"] is! String) { |
| 105 parsed.remove('url'); | 134 throw new FormatException("The 'url' field of the description must be a " |
| 106 parsed.remove('ref'); | 135 "string."); |
| 107 if (fromLockFile) parsed.remove('resolved-ref'); | |
| 108 | |
| 109 if (!parsed.isEmpty) { | |
| 110 var plural = parsed.length > 1; | |
| 111 var keys = parsed.keys.join(', '); | |
| 112 throw new FormatException("Invalid key${plural ? 's' : ''}: $keys."); | |
| 113 } | 136 } |
| 114 | 137 |
| 115 return description; | 138 // Ensure that it's a valid URL. |
| 139 Uri.parse(description["url"]); | |
| 140 | |
| 141 var ref = description["ref"]; | |
| 142 if (ref != null && ref is! String) { | |
| 143 throw new FormatException("The 'ref' field of the description must be a " | |
| 144 "string."); | |
| 145 } | |
| 146 | |
| 147 return new PackageRef(name, this.name, { | |
| 148 "url": description["url"], | |
| 149 "ref": description["ref"] ?? "HEAD" | |
| 150 }); | |
| 151 } | |
| 152 | |
| 153 PackageId parseId(String name, Version version, description) { | |
| 154 if (description is! Map) { | |
| 155 throw new FormatException("The description must be a map with a 'url' " | |
| 156 "key."); | |
| 157 } | |
| 158 | |
| 159 if (description["url"] is! String) { | |
| 160 throw new FormatException("The 'url' field of the description must be a " | |
| 161 "string."); | |
| 162 } | |
| 163 | |
| 164 // Ensure that it's a valid URL. | |
| 165 Uri.parse(description["url"]); | |
| 166 | |
| 167 var ref = description["ref"]; | |
| 168 if (ref != null && ref is! String) { | |
| 169 throw new FormatException("The 'ref' field of the description must be a " | |
| 170 "string."); | |
| 171 } | |
| 172 | |
| 173 if (description["resolved-ref"] is! String) { | |
| 174 throw new FormatException("The 'resolved-ref' field of the description " | |
| 175 "must be a string."); | |
| 176 } | |
| 177 | |
| 178 return new PackageId(name, this.name, version, { | |
| 179 "url": description["url"], | |
| 180 "ref": description["ref"] ?? "HEAD", | |
| 181 "resolved-ref": description["resolved-ref"] | |
| 182 }); | |
| 116 } | 183 } |
| 117 | 184 |
| 118 /// If [description] has a resolved ref, print it out in short-form. | 185 /// If [description] has a resolved ref, print it out in short-form. |
| 119 /// | 186 /// |
| 120 /// This helps distinguish different git commits with the same pubspec | 187 /// This helps distinguish different git commits with the same pubspec |
| 121 /// version. | 188 /// version. |
| 122 String formatDescription(String containingPath, description) { | 189 String formatDescription(String containingPath, description) { |
| 123 if (description is Map && description.containsKey('resolved-ref')) { | 190 if (description is Map && description.containsKey('resolved-ref')) { |
| 124 return "${description['url']} at " | 191 return "${description['url']} at " |
| 125 "${description['resolved-ref'].substring(0, 6)}"; | 192 "${description['resolved-ref'].substring(0, 6)}"; |
| 126 } else { | 193 } else { |
| 127 return super.formatDescription(containingPath, description); | 194 return super.formatDescription(containingPath, description); |
| 128 } | 195 } |
| 129 } | 196 } |
| 130 | 197 |
| 131 /// Two Git descriptions are equal if both their URLs and their refs are | 198 /// Two Git descriptions are equal if both their URLs and their refs are |
| 132 /// equal. | 199 /// equal. |
| 133 bool descriptionsEqual(description1, description2) { | 200 bool descriptionsEqual(description1, description2) { |
| 134 // TODO(nweiz): Do we really want to throw an error if you have two | 201 // TODO(nweiz): Do we really want to throw an error if you have two |
| 135 // dependencies on some repo, one of which specifies a ref and one of which | 202 // dependencies on some repo, one of which specifies a ref and one of which |
| 136 // doesn't? If not, how do we handle that case in the version solver? | 203 // doesn't? If not, how do we handle that case in the version solver? |
| 137 if (_getUrl(description1) != _getUrl(description2)) return false; | 204 if (description1['url'] != description2['url']) return false; |
| 138 if (_getRef(description1) != _getRef(description2)) return false; | 205 |
| 206 if (description1['ref'] != description2['ref']) { | |
| 207 return false; | |
|
Bob Nystrom
2015/12/17 22:57:17
Make this one line too.
| |
| 208 } | |
| 139 | 209 |
| 140 if (description1 is Map && description1.containsKey('resolved-ref') && | 210 if (description1 is Map && description1.containsKey('resolved-ref') && |
| 141 description2 is Map && description2.containsKey('resolved-ref')) { | 211 description2 is Map && description2.containsKey('resolved-ref')) { |
|
Bob Nystrom
2015/12/17 22:57:17
These "is Map" checks aren't needed any more.
| |
| 142 return description1['resolved-ref'] == description2['resolved-ref']; | 212 return description1['resolved-ref'] == description2['resolved-ref']; |
| 143 } | 213 } |
| 144 | 214 |
| 145 return true; | 215 return true; |
| 146 } | 216 } |
| 147 | 217 |
| 148 /// Attaches a specific commit to [id] to disambiguate it. | |
| 149 Future<PackageId> resolveId(PackageId id) { | |
| 150 return _ensureRevision(id).then((revision) { | |
| 151 var description = {'url': _getUrl(id), 'ref': _getRef(id)}; | |
| 152 description['resolved-ref'] = revision; | |
| 153 return new PackageId(id.name, name, id.version, description); | |
| 154 }); | |
| 155 } | |
| 156 | |
| 157 List<Package> getCachedPackages() { | 218 List<Package> getCachedPackages() { |
| 158 // TODO(keertip): Implement getCachedPackages(). | 219 // TODO(keertip): Implement getCachedPackages(). |
| 159 throw new UnimplementedError( | 220 throw new UnimplementedError( |
| 160 "The git source doesn't support listing its cached packages yet."); | 221 "The git source doesn't support listing its cached packages yet."); |
| 161 } | 222 } |
| 162 | 223 |
| 163 /// Resets all cached packages back to the pristine state of the Git | 224 /// Resets all cached packages back to the pristine state of the Git |
| 164 /// repository at the revision they are pinned to. | 225 /// repository at the revision they are pinned to. |
| 165 Future<Pair<List<PackageId>, List<PackageId>>> repairCachedPackages() async { | 226 Future<Pair<List<PackageId>, List<PackageId>>> repairCachedPackages() async { |
| 166 if (!dirExists(systemCacheRoot)) return new Pair([], []); | 227 if (!dirExists(systemCacheRoot)) return new Pair([], []); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 199 log.fine(stackTrace); | 260 log.fine(stackTrace); |
| 200 failures.add(id); | 261 failures.add(id); |
| 201 | 262 |
| 202 tryDeleteEntry(package.dir); | 263 tryDeleteEntry(package.dir); |
| 203 } | 264 } |
| 204 } | 265 } |
| 205 | 266 |
| 206 return new Pair(successes, failures); | 267 return new Pair(successes, failures); |
| 207 } | 268 } |
| 208 | 269 |
| 209 /// Ensure that the canonical clone of the repository referred to by [id] (the | 270 /// Ensures that the canonical clone of the repository referred to by [ref] |
| 210 /// one in `<system cache>/git/cache`) exists and contains the revision | 271 /// contains the given Git [revision]. |
| 211 /// referred to by [id]. | 272 Future _ensureRevision(PackageRef ref, String revision) async { |
| 273 var path = _repoCachePath(ref); | |
| 274 if (_updatedRepos.contains(path)) return; | |
| 275 | |
| 276 if (!entryExists(path)) await _createRepoCache(ref); | |
| 277 | |
| 278 try { | |
| 279 return await _firstRevision(path, revision); | |
| 280 } on git.GitException catch (_) { | |
|
Bob Nystrom
2015/12/17 22:57:17
Document what this is about.
| |
| 281 await _updateRepoCache(ref); | |
| 282 return await _firstRevision(path, revision); | |
| 283 } | |
| 284 } | |
| 285 | |
| 286 /// Ensures that the canonical clone of the repository referred to by [ref] | |
| 287 /// exists and is up-to-date. | |
| 288 Future _ensureRepoCache(PackageRef ref) async { | |
| 289 var path = _repoCachePath(ref); | |
| 290 if (_updatedRepos.contains(path)) return; | |
| 291 | |
| 292 if (!entryExists(path)) { | |
| 293 await _createRepoCache(ref); | |
| 294 } else { | |
| 295 await _updateRepoCache(ref); | |
| 296 } | |
| 297 } | |
| 298 | |
| 299 /// Creates the canonical clone of the repository referred to by [ref]. | |
| 212 /// | 300 /// |
| 213 /// Returns a future that completes to the hash of the revision identified by | 301 /// This assumes that the canonical clone doesn't yet exist. |
| 214 /// [id]. | 302 Future _createRepoCache(PackageRef ref) async { |
| 215 Future<String> _ensureRevision(PackageId id) { | 303 var path = _repoCachePath(ref); |
| 216 return new Future.sync(() { | 304 assert(!_updatedRepos.contains(path)); |
| 217 var path = _repoCachePath(id); | |
| 218 if (!entryExists(path)) { | |
| 219 return _clone(_getUrl(id), path, mirror: true) | |
| 220 .then((_) => _getRev(id)); | |
| 221 } | |
| 222 | 305 |
| 223 // If [id] didn't come from a lockfile, it may be using a symbolic | 306 await _clone(ref.description['url'], path, mirror: true); |
| 224 // reference. We want to get the latest version of that reference. | 307 _updatedRepos.add(path); |
| 225 var description = id.description; | |
| 226 if (description is! Map || !description.containsKey('resolved-ref')) { | |
| 227 return _updateRepoCache(id).then((_) => _getRev(id)); | |
| 228 } | |
| 229 | |
| 230 // If [id] did come from a lockfile, then we want to avoid running "git | |
| 231 // fetch" if possible to avoid networking time and errors. See if the | |
| 232 // revision exists in the repo cache before updating it. | |
| 233 return _getRev(id).catchError((error) { | |
| 234 if (error is! git.GitException) throw error; | |
| 235 return _updateRepoCache(id).then((_) => _getRev(id)); | |
| 236 }); | |
| 237 }); | |
| 238 } | 308 } |
| 239 | 309 |
| 240 /// Runs "git fetch" in the canonical clone of the repository referred to by | 310 /// Runs "git fetch" in the canonical clone of the repository referred to by |
| 241 /// [id]. | 311 /// [ref]. |
| 242 /// | 312 /// |
| 243 /// This assumes that the canonical clone already exists. | 313 /// This assumes that the canonical clone already exists. |
| 244 Future _updateRepoCache(PackageId id) { | 314 Future _updateRepoCache(PackageRef ref) async { |
| 245 var path = _repoCachePath(id); | 315 var path = _repoCachePath(ref); |
| 246 if (_updatedRepos.contains(path)) return new Future.value(); | 316 if (_updatedRepos.contains(path)) return new Future.value(); |
| 247 return git.run(["fetch"], workingDir: path).then((_) { | 317 await git.run(["fetch"], workingDir: path); |
| 248 _updatedRepos.add(path); | 318 _updatedRepos.add(path); |
| 249 }); | |
| 250 } | 319 } |
| 251 | 320 |
| 252 /// Runs "git rev-list" in the canonical clone of the repository referred to | 321 /// Runs "git rev-list" on [reference] in [path] and returns the first result. |
| 253 /// by [id] on the effective ref of [id]. | |
| 254 /// | 322 /// |
| 255 /// This assumes that the canonical clone already exists. | 323 /// This assumes that the canonical clone already exists. |
| 256 Future<String> _getRev(PackageId id) { | 324 Future<String> _firstRevision(String path, String reference) async { |
| 257 return git.run(["rev-list", "--max-count=1", _getEffectiveRef(id)], | 325 var lines = await git.run(["rev-list", "--max-count=1", reference], |
| 258 workingDir: _repoCachePath(id)).then((result) => result.first); | 326 workingDir: path); |
| 327 return lines.first; | |
| 259 } | 328 } |
| 260 | 329 |
| 261 /// Clones the repo at the URI [from] to the path [to] on the local | 330 /// Clones the repo at the URI [from] to the path [to] on the local |
| 262 /// filesystem. | 331 /// filesystem. |
| 263 /// | 332 /// |
| 264 /// If [mirror] is true, creates a bare, mirrored clone. This doesn't check | 333 /// If [mirror] is true, creates a bare, mirrored clone. This doesn't check |
| 265 /// out the working tree, but instead makes the repository a local mirror of | 334 /// out the working tree, but instead makes the repository a local mirror of |
| 266 /// the remote repository. See the manpage for `git clone` for more | 335 /// the remote repository. See the manpage for `git clone` for more |
| 267 /// information. | 336 /// information. |
| 268 /// | 337 /// |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 284 } | 353 } |
| 285 | 354 |
| 286 /// Checks out the reference [ref] in [repoPath]. | 355 /// Checks out the reference [ref] in [repoPath]. |
| 287 Future _checkOut(String repoPath, String ref) { | 356 Future _checkOut(String repoPath, String ref) { |
| 288 return git.run(["checkout", ref], workingDir: repoPath).then( | 357 return git.run(["checkout", ref], workingDir: repoPath).then( |
| 289 (result) => null); | 358 (result) => null); |
| 290 } | 359 } |
| 291 | 360 |
| 292 /// Returns the path to the canonical clone of the repository referred to by | 361 /// Returns the path to the canonical clone of the repository referred to by |
| 293 /// [id] (the one in `<system cache>/git/cache`). | 362 /// [id] (the one in `<system cache>/git/cache`). |
| 294 String _repoCachePath(PackageId id) { | 363 String _repoCachePath(PackageRef ref) { |
| 295 var repoCacheName = '${id.name}-${sha1(_getUrl(id))}'; | 364 var repoCacheName = '${ref.name}-${sha1(ref.description['url'])}'; |
| 296 return path.join(systemCacheRoot, 'cache', repoCacheName); | 365 return path.join(systemCacheRoot, 'cache', repoCacheName); |
| 297 } | 366 } |
| 298 | |
| 299 /// Returns the repository URL for [id]. | |
| 300 /// | |
| 301 /// [description] may be a description or a [PackageId]. | |
| 302 String _getUrl(description) { | |
| 303 description = _getDescription(description); | |
| 304 if (description is String) return description; | |
| 305 return description['url']; | |
| 306 } | |
| 307 | |
| 308 /// Returns the commit ref that should be checked out for [description]. | |
| 309 /// | |
| 310 /// This differs from [_getRef] in that it doesn't just return the ref in | |
| 311 /// [description]. It will return a sensible default if that ref doesn't | |
| 312 /// exist, and it will respect the "resolved-ref" parameter set by | |
| 313 /// [resolveId]. | |
| 314 /// | |
| 315 /// [description] may be a description or a [PackageId]. | |
| 316 String _getEffectiveRef(description) { | |
| 317 description = _getDescription(description); | |
| 318 if (description is Map && description.containsKey('resolved-ref')) { | |
| 319 return description['resolved-ref']; | |
| 320 } | |
| 321 | |
| 322 var ref = _getRef(description); | |
| 323 return ref == null ? 'HEAD' : ref; | |
| 324 } | |
| 325 | |
| 326 /// Returns the commit ref for [description], or null if none is given. | |
| 327 /// | |
| 328 /// [description] may be a description or a [PackageId]. | |
| 329 String _getRef(description) { | |
| 330 description = _getDescription(description); | |
| 331 if (description is String) return null; | |
| 332 return description['ref']; | |
| 333 } | |
| 334 | |
| 335 /// Returns [description] if it's a description, or [PackageId.description] if | |
| 336 /// it's a [PackageId]. | |
| 337 _getDescription(description) { | |
| 338 if (description is PackageId) return description.description; | |
| 339 return description; | |
| 340 } | |
| 341 } | 367 } |
| OLD | NEW |