Index: utils/pub/git_source.dart |
diff --git a/utils/pub/git_source.dart b/utils/pub/git_source.dart |
index 90f619bb500e26dd166af3e997f6cd4b4898bc2d..e5775df734c36eb2f00fa21b81825a30a0af0ffa 100644 |
--- a/utils/pub/git_source.dart |
+++ b/utils/pub/git_source.dart |
@@ -40,19 +40,23 @@ class GitSource extends Source { |
return isGitInstalled.chain((installed) { |
if (!installed) { |
throw new Exception( |
- "Cannot install '${id.name}' from Git (${id.description}).\n" |
+ "Cannot install '${id.name}' from Git (${_getUrl(id)}).\n" |
"Please ensure Git is correctly installed."); |
} |
return ensureDir(join(systemCacheRoot, 'cache')); |
}).chain((_) => _ensureRepoCache(id)) |
- .chain((_) => _revisionCachePath(id, "HEAD")) |
+ .chain((_) => _revisionCachePath(id)) |
.chain((path) { |
revisionCachePath = path; |
return exists(revisionCachePath); |
}).chain((exists) { |
if (exists) return new Future.immediate(null); |
return _clone(_repoCachePath(id), revisionCachePath); |
+ }).chain((_) { |
+ var ref = _getRef(id); |
+ if (ref == null) return new Future.immediate(null); |
+ return _checkOut(revisionCachePath, ref); |
}).chain((_) => Package.load(revisionCachePath, systemCache.sources)); |
} |
@@ -61,14 +65,26 @@ class GitSource extends Source { |
* it'll be cloned. |
*/ |
String packageName(description) => |
- basename(description).replaceFirst(const RegExp("\.git\$"), ""); |
+ basename(_getUrl(description)).replaceFirst(const RegExp("\.git\$"), ""); |
/** |
* Ensures [description] is a Git URL. |
*/ |
void validateDescription(description) { |
- if (description is! String) { |
- throw new FormatException("The description must be a git URL."); |
+ // A single string is assumed to be a Git URL. |
+ if (description is String) return; |
+ if (description is! Map || !description.containsKey('url')) { |
+ throw new FormatException("The description must be a Git URL or a map " |
+ "with a 'url' key."); |
+ } |
+ description = new Map.from(description); |
+ description.remove('url'); |
+ description.remove('ref'); |
+ |
+ if (!description.isEmpty()) { |
+ var plural = description.length > 1; |
+ var keys = Strings.join(description.keys, ', '); |
+ throw new FormatException("Invalid key${plural ? 's' : ''}: $keys."); |
} |
} |
@@ -81,7 +97,7 @@ class GitSource extends Source { |
Future _ensureRepoCache(PackageId id) { |
var path = _repoCachePath(id); |
return exists(path).chain((exists) { |
- if (!exists) return _clone(id.description, path); |
+ if (!exists) return _clone(_getUrl(id), path); |
return runProcess("git", ["pull", "--force"], workingDir: path, |
pipeStdout: true, pipeStderr: true).transform((result) { |
@@ -107,7 +123,9 @@ class GitSource extends Source { |
* Returns the path to the revision-specific cache of [id] at [ref], which can |
* be any Git ref. |
*/ |
- Future<String> _revisionCachePath(PackageId id, String ref) { |
+ Future<String> _revisionCachePath(PackageId id) { |
+ var ref = _getRef(id); |
+ if (ref == null) ref = 'HEAD'; |
return _revisionAt(id, ref).transform((rev) { |
var revisionCacheName = '${id.name}-$rev'; |
return join(systemCacheRoot, revisionCacheName); |
@@ -126,11 +144,53 @@ class GitSource extends Source { |
} |
/** |
+ * Checks out the reference [ref] in [repoPath]. |
+ */ |
+ Future _checkOut(String repoPath, String ref) { |
+ return runProcess("git", ["checkout", ref], pipeStdout: true, |
+ pipeStderr: true, workingDir: repoPath).transform((result) { |
+ if (!result.success) throw 'Git failed.'; |
+ return null; |
+ }); |
+ } |
+ |
+ /** |
* Returns the path to the canonical clone of the repository referred to by |
* [id] (the one in `<system cache>/git/cache`). |
*/ |
String _repoCachePath(PackageId id) { |
- var repoCacheName = '${id.name}-${sha1(id.description)}'; |
+ var repoCacheName = '${id.name}-${sha1(_getUrl(id))}'; |
return join(systemCacheRoot, 'cache', repoCacheName); |
} |
+ |
+ /** |
+ * Returns the repository URL for [id]. |
+ * |
+ * [description] may be a description or a [PackageId]. |
+ */ |
+ String _getUrl(description) { |
+ description = _getDescription(description); |
+ if (description is String) return description; |
+ return description['url']; |
+ } |
+ |
+ /** |
+ * Returns the commit ref for [id], or null if none is given. |
+ * |
+ * [description] may be a description or a [PackageId]. |
+ */ |
+ String _getRef(description) { |
+ description = _getDescription(description); |
+ if (description is String) return null; |
+ return description['ref']; |
+ } |
+ |
+ /** |
+ * Returns [description] if it's a description, or [PackageId.description] if |
+ * it's a [PackageId]. |
+ */ |
+ _getDescription(description) { |
+ if (description is PackageId) return description.description; |
+ return description; |
+ } |
} |