Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(167)

Side by Side Diff: utils/pub/git_source.dart

Issue 10790079: Use a lockfile to persist Pub's installed version constellation. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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('git_source'); 5 #library('git_source');
6 6
7 #import('io.dart'); 7 #import('io.dart');
8 #import('package.dart'); 8 #import('package.dart');
9 #import('source.dart'); 9 #import('source.dart');
10 #import('source_registry.dart'); 10 #import('source_registry.dart');
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
47 return ensureDir(join(systemCacheRoot, 'cache')); 47 return ensureDir(join(systemCacheRoot, 'cache'));
48 }).chain((_) => _ensureRepoCache(id)) 48 }).chain((_) => _ensureRepoCache(id))
49 .chain((_) => _revisionCachePath(id)) 49 .chain((_) => _revisionCachePath(id))
50 .chain((path) { 50 .chain((path) {
51 revisionCachePath = path; 51 revisionCachePath = path;
52 return exists(revisionCachePath); 52 return exists(revisionCachePath);
53 }).chain((exists) { 53 }).chain((exists) {
54 if (exists) return new Future.immediate(null); 54 if (exists) return new Future.immediate(null);
55 return _clone(_repoCachePath(id), revisionCachePath); 55 return _clone(_repoCachePath(id), revisionCachePath);
56 }).chain((_) { 56 }).chain((_) {
57 var ref = _getRef(id); 57 var ref = _getEffectiveRef(id);
58 if (ref == null) return new Future.immediate(null); 58 if (ref == 'HEAD') return new Future.immediate(null);
59 return _checkOut(revisionCachePath, ref); 59 return _checkOut(revisionCachePath, ref);
60 }).chain((_) => Package.load(revisionCachePath, systemCache.sources)); 60 }).chain((_) => Package.load(revisionCachePath, systemCache.sources));
61 } 61 }
62 62
63 /** 63 /**
64 * The package name of a Git repo is the name of the directory into which 64 * The package name of a Git repo is the name of the directory into which
65 * it'll be cloned. 65 * it'll be cloned.
66 */ 66 */
67 String packageName(description) => 67 String packageName(description) =>
68 basename(_getUrl(description)).replaceFirst(const RegExp("\.git\$"), ""); 68 basename(_getUrl(description)).replaceFirst(const RegExp("\.git\$"), "");
69 69
70 /** 70 /**
71 * Ensures [description] is a Git URL. 71 * Ensures [description] is a Git URL.
72 */ 72 */
73 void validateDescription(description) { 73 void validateDescription(description, [bool fromLockFile = false]) {
74 // A single string is assumed to be a Git URL. 74 // A single string is assumed to be a Git URL.
75 if (description is String) return; 75 if (description is String) return;
76 if (description is! Map || !description.containsKey('url')) { 76 if (description is! Map || !description.containsKey('url')) {
77 throw new FormatException("The description must be a Git URL or a map " 77 throw new FormatException("The description must be a Git URL or a map "
78 "with a 'url' key."); 78 "with a 'url' key.");
79 } 79 }
80 description = new Map.from(description); 80 description = new Map.from(description);
81 description.remove('url'); 81 description.remove('url');
82 description.remove('ref'); 82 description.remove('ref');
83 if (fromLockFile) description.remove('resolved-ref');
83 84
84 if (!description.isEmpty()) { 85 if (!description.isEmpty()) {
85 var plural = description.length > 1; 86 var plural = description.length > 1;
86 var keys = Strings.join(description.keys, ', '); 87 var keys = Strings.join(description.getKeys(), ', ');
87 throw new FormatException("Invalid key${plural ? 's' : ''}: $keys."); 88 throw new FormatException("Invalid key${plural ? 's' : ''}: $keys.");
88 } 89 }
89 } 90 }
90 91
91 /** 92 /**
92 * Two Git descriptions are equal if both their URLs and their refs are equal. 93 * Two Git descriptions are equal if both their URLs and their refs are equal.
93 */ 94 */
94 bool descriptionsEqual(description1, description2) { 95 bool descriptionsEqual(description1, description2) {
95 // TODO(nweiz): Do we really want to throw an error if you have two 96 // TODO(nweiz): Do we really want to throw an error if you have two
96 // dependencies on some repo, one of which specifies a ref and one of which 97 // dependencies on some repo, one of which specifies a ref and one of which
97 // doesn't? If not, how do we handle that case in the version solver? 98 // doesn't? If not, how do we handle that case in the version solver?
98 return _getUrl(description1) == _getUrl(description2) && 99 return _getUrl(description1) == _getUrl(description2) &&
99 _getRef(description1) == _getRef(description2); 100 _getRef(description1) == _getRef(description2);
100 } 101 }
101 102
102 /** 103 /**
104 * Attaches a specific commit to [id] to disambiguate it.
105 */
106 Future<PackageId> resolveId(PackageId id) {
107 return _revisionAt(id).transform((revision) {
108 var description = {'url': _getUrl(id), 'ref': _getRef(id)};
109 description['resolved-ref'] = revision;
110 return new PackageId(this, id.version, description);
111 });
112 }
113
114 /**
103 * Ensure that the canonical clone of the repository referred to by [id] (the 115 * Ensure that the canonical clone of the repository referred to by [id] (the
104 * one in `<system cache>/git/cache`) exists and is up-to-date. Returns a 116 * one in `<system cache>/git/cache`) exists and is up-to-date. Returns a
105 * future that completes once this is finished and throws an exception if it 117 * future that completes once this is finished and throws an exception if it
106 * fails. 118 * fails.
107 */ 119 */
108 Future _ensureRepoCache(PackageId id) { 120 Future _ensureRepoCache(PackageId id) {
109 var path = _repoCachePath(id); 121 var path = _repoCachePath(id);
110 return exists(path).chain((exists) { 122 return exists(path).chain((exists) {
111 if (!exists) return _clone(_getUrl(id), path); 123 if (!exists) return _clone(_getUrl(id), path);
112 124
113 return runProcess("git", ["pull", "--force"], workingDir: path, 125 return runProcess("git", ["pull", "--force"], workingDir: path,
114 pipeStdout: true, pipeStderr: true).transform((result) { 126 pipeStdout: true, pipeStderr: true).transform((result) {
115 if (!result.success) throw 'Git failed.'; 127 if (!result.success) throw 'Git failed.';
116 return null; 128 return null;
117 }); 129 });
118 }); 130 });
119 } 131 }
120 132
121 /** 133 /**
122 * Returns a future that completes to the revision hash of the repository for 134 * Returns a future that completes to the revision hash of [id].
123 * [id] at [ref], which can be any Git ref.
124 */ 135 */
125 Future<String> _revisionAt(PackageId id, String ref) { 136 Future<String> _revisionAt(PackageId id) {
126 return runProcess("git", ["rev-parse", ref], 137 return runProcess("git", ["rev-parse", _getEffectiveRef(id)],
127 workingDir: _repoCachePath(id), pipeStderr: true).transform((result) { 138 workingDir: _repoCachePath(id), pipeStderr: true).transform((result) {
128 if (!result.success) throw 'Git failed.'; 139 if (!result.success) throw 'Git failed.';
129 return result.stdout[0]; 140 return result.stdout[0];
130 }); 141 });
131 } 142 }
132 143
133 /** 144 /**
134 * Returns the path to the revision-specific cache of [id] at [ref], which can 145 * Returns the path to the revision-specific cache of [id].
135 * be any Git ref.
136 */ 146 */
137 Future<String> _revisionCachePath(PackageId id) { 147 Future<String> _revisionCachePath(PackageId id) {
138 var ref = _getRef(id); 148 return _revisionAt(id).transform((rev) {
139 if (ref == null) ref = 'HEAD';
140 return _revisionAt(id, ref).transform((rev) {
141 var revisionCacheName = '${id.name}-$rev'; 149 var revisionCacheName = '${id.name}-$rev';
142 return join(systemCacheRoot, revisionCacheName); 150 return join(systemCacheRoot, revisionCacheName);
143 }); 151 });
144 } 152 }
145 153
146 /** 154 /**
147 * Clones the repo at the URI [from] to the path [to] on the local filesystem. 155 * Clones the repo at the URI [from] to the path [to] on the local filesystem.
148 */ 156 */
149 Future _clone(String from, String to) { 157 Future _clone(String from, String to) {
150 return runProcess("git", ["clone", from, to], pipeStdout: true, 158 return runProcess("git", ["clone", from, to], pipeStdout: true,
(...skipping 28 matching lines...) Expand all
179 * 187 *
180 * [description] may be a description or a [PackageId]. 188 * [description] may be a description or a [PackageId].
181 */ 189 */
182 String _getUrl(description) { 190 String _getUrl(description) {
183 description = _getDescription(description); 191 description = _getDescription(description);
184 if (description is String) return description; 192 if (description is String) return description;
185 return description['url']; 193 return description['url'];
186 } 194 }
187 195
188 /** 196 /**
189 * Returns the commit ref for [id], or null if none is given. 197 * Returns the commit ref that should be checked out for [description].
198 *
199 * This differs from [_getRef] in that it doesn't just return the ref in
200 * [description]. It will return a sensible default if that ref doesn't exist,
201 * and it will respect the "resolved-ref" parameter set by [resolveId].
190 * 202 *
191 * [description] may be a description or a [PackageId]. 203 * [description] may be a description or a [PackageId].
192 */ 204 */
205 String _getEffectiveRef(description) {
206 description = _getDescription(description);
207 if (description is Map && description.containsKey('resolved-ref')) {
208 return description['resolved-ref'];
209 }
210
211 var ref = _getRef(description);
212 return ref == null ? 'HEAD' : ref;
213 }
214
215 /**
216 * Returns the commit ref for [description], or null if none is given.
217 *
218 * [description] may be a description or a [PackageId].
219 */
193 String _getRef(description) { 220 String _getRef(description) {
194 description = _getDescription(description); 221 description = _getDescription(description);
195 if (description is String) return null; 222 if (description is String) return null;
196 return description['ref']; 223 return description['ref'];
197 } 224 }
198 225
199 /** 226 /**
200 * Returns [description] if it's a description, or [PackageId.description] if 227 * Returns [description] if it's a description, or [PackageId.description] if
201 * it's a [PackageId]. 228 * it's a [PackageId].
202 */ 229 */
203 _getDescription(description) { 230 _getDescription(description) {
204 if (description is PackageId) return description.description; 231 if (description is PackageId) return description.description;
205 return description; 232 return description;
206 } 233 }
207 } 234 }
OLDNEW
« no previous file with comments | « utils/pub/entrypoint.dart ('k') | utils/pub/io.dart » ('j') | utils/tests/pub/test_pub.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698