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

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

Issue 11638010: Convert /** comments to /// in pub. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Respond to review. Created 8 years 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
« no previous file with comments | « utils/pub/utils.dart ('k') | utils/pub/version_solver.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 /** 5 /// Handles version numbers, following the [Semantic Versioning][semver] spec.
6 * Handles version numbers, following the [Semantic Versioning][semver] spec. 6 ///
7 * 7 /// [semver]: http://semver.org/
8 * [semver]: http://semver.org/
9 */
10 library version; 8 library version;
11 9
12 import 'dart:math'; 10 import 'dart:math';
13 11
14 import 'utils.dart'; 12 import 'utils.dart';
15 13
16 /** A parsed semantic version number. */ 14 /// A parsed semantic version number.
17 class Version implements Comparable, VersionConstraint { 15 class Version implements Comparable, VersionConstraint {
18 /** No released version: i.e. "0.0.0". */ 16 /// No released version: i.e. "0.0.0".
19 static Version get none => new Version(0, 0, 0); 17 static Version get none => new Version(0, 0, 0);
20 18
21 static final _PARSE_REGEX = new RegExp( 19 static final _PARSE_REGEX = new RegExp(
22 r'^' // Start at beginning. 20 r'^' // Start at beginning.
23 r'(\d+).(\d+).(\d+)' // Version number. 21 r'(\d+).(\d+).(\d+)' // Version number.
24 r'(-([0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?' // Pre-release. 22 r'(-([0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?' // Pre-release.
25 r'(\+([0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?' // Build. 23 r'(\+([0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?' // Build.
26 r'$'); // Consume entire string. 24 r'$'); // Consume entire string.
27 25
28 /** The major version number: "1" in "1.2.3". */ 26 /// The major version number: "1" in "1.2.3".
29 final int major; 27 final int major;
30 28
31 /** The minor version number: "2" in "1.2.3". */ 29 /// The minor version number: "2" in "1.2.3".
32 final int minor; 30 final int minor;
33 31
34 /** The patch version number: "3" in "1.2.3". */ 32 /// The patch version number: "3" in "1.2.3".
35 final int patch; 33 final int patch;
36 34
37 /** The pre-release identifier: "foo" in "1.2.3-foo". May be `null`. */ 35 /// The pre-release identifier: "foo" in "1.2.3-foo". May be `null`.
38 final String preRelease; 36 final String preRelease;
39 37
40 /** The build identifier: "foo" in "1.2.3+foo". May be `null`. */ 38 /// The build identifier: "foo" in "1.2.3+foo". May be `null`.
41 final String build; 39 final String build;
42 40
43 /** Creates a new [Version] object. */ 41 /// Creates a new [Version] object.
44 Version(this.major, this.minor, this.patch, {String pre, this.build}) 42 Version(this.major, this.minor, this.patch, {String pre, this.build})
45 : preRelease = pre { 43 : preRelease = pre {
46 if (major < 0) throw new ArgumentError( 44 if (major < 0) throw new ArgumentError(
47 'Major version must be non-negative.'); 45 'Major version must be non-negative.');
48 if (minor < 0) throw new ArgumentError( 46 if (minor < 0) throw new ArgumentError(
49 'Minor version must be non-negative.'); 47 'Minor version must be non-negative.');
50 if (patch < 0) throw new ArgumentError( 48 if (patch < 0) throw new ArgumentError(
51 'Patch version must be non-negative.'); 49 'Patch version must be non-negative.');
52 } 50 }
53 51
54 /** 52 /// Creates a new [Version] by parsing [text].
55 * Creates a new [Version] by parsing [text].
56 */
57 factory Version.parse(String text) { 53 factory Version.parse(String text) {
58 final match = _PARSE_REGEX.firstMatch(text); 54 final match = _PARSE_REGEX.firstMatch(text);
59 if (match == null) { 55 if (match == null) {
60 throw new FormatException('Could not parse "$text".'); 56 throw new FormatException('Could not parse "$text".');
61 } 57 }
62 58
63 try { 59 try {
64 int major = parseInt(match[1]); 60 int major = parseInt(match[1]);
65 int minor = parseInt(match[2]); 61 int minor = parseInt(match[2]);
66 int patch = parseInt(match[3]); 62 int patch = parseInt(match[3]);
(...skipping 12 matching lines...) Expand all
79 return compareTo(other) == 0; 75 return compareTo(other) == 0;
80 } 76 }
81 77
82 bool operator <(Version other) => compareTo(other) < 0; 78 bool operator <(Version other) => compareTo(other) < 0;
83 bool operator >(Version other) => compareTo(other) > 0; 79 bool operator >(Version other) => compareTo(other) > 0;
84 bool operator <=(Version other) => compareTo(other) <= 0; 80 bool operator <=(Version other) => compareTo(other) <= 0;
85 bool operator >=(Version other) => compareTo(other) >= 0; 81 bool operator >=(Version other) => compareTo(other) >= 0;
86 82
87 bool get isEmpty => false; 83 bool get isEmpty => false;
88 84
89 /** Tests if [other] matches this version exactly. */ 85 /// Tests if [other] matches this version exactly.
90 bool allows(Version other) => this == other; 86 bool allows(Version other) => this == other;
91 87
92 VersionConstraint intersect(VersionConstraint other) { 88 VersionConstraint intersect(VersionConstraint other) {
93 if (other.isEmpty) return other; 89 if (other.isEmpty) return other;
94 90
95 // Intersect a version and a range. 91 // Intersect a version and a range.
96 if (other is VersionRange) return other.intersect(this); 92 if (other is VersionRange) return other.intersect(this);
97 93
98 // Intersecting two versions only works if they are the same. 94 // Intersecting two versions only works if they are the same.
99 if (other is Version) return this == other ? this : const _EmptyVersion(); 95 if (other is Version) return this == other ? this : const _EmptyVersion();
(...skipping 29 matching lines...) Expand all
129 int get hashCode => toString().hashCode; 125 int get hashCode => toString().hashCode;
130 126
131 String toString() { 127 String toString() {
132 var buffer = new StringBuffer(); 128 var buffer = new StringBuffer();
133 buffer.add('$major.$minor.$patch'); 129 buffer.add('$major.$minor.$patch');
134 if (preRelease != null) buffer.add('-$preRelease'); 130 if (preRelease != null) buffer.add('-$preRelease');
135 if (build != null) buffer.add('+$build'); 131 if (build != null) buffer.add('+$build');
136 return buffer.toString(); 132 return buffer.toString();
137 } 133 }
138 134
139 /** 135 /// Compares the string part of two versions. This is used for the pre-release
140 * Compares the string part of two versions. This is used for the pre-release 136 /// and build version parts. This follows Rule 12. of the Semantic Versioning
141 * and build version parts. This follows Rule 12. of the Semantic Versioning 137 /// spec.
142 * spec.
143 */
144 int _compareStrings(String a, String b) { 138 int _compareStrings(String a, String b) {
145 var aParts = _splitParts(a); 139 var aParts = _splitParts(a);
146 var bParts = _splitParts(b); 140 var bParts = _splitParts(b);
147 141
148 for (int i = 0; i < max(aParts.length, bParts.length); i++) { 142 for (int i = 0; i < max(aParts.length, bParts.length); i++) {
149 var aPart = (i < aParts.length) ? aParts[i] : null; 143 var aPart = (i < aParts.length) ? aParts[i] : null;
150 var bPart = (i < bParts.length) ? bParts[i] : null; 144 var bPart = (i < bParts.length) ? bParts[i] : null;
151 145
152 if (aPart != bPart) { 146 if (aPart != bPart) {
153 // Missing parts come before present ones. 147 // Missing parts come before present ones.
(...skipping 14 matching lines...) Expand all
168 return 1; 162 return 1;
169 } else { 163 } else {
170 // Compare two strings. 164 // Compare two strings.
171 return aPart.compareTo(bPart); 165 return aPart.compareTo(bPart);
172 } 166 }
173 } 167 }
174 } 168 }
175 } 169 }
176 } 170 }
177 171
178 /** 172 /// Splits a string of dot-delimited identifiers into their component parts.
179 * Splits a string of dot-delimited identifiers into their component parts. 173 /// Identifiers that are numeric are converted to numbers.
180 * Identifiers that are numeric are converted to numbers.
181 */
182 List _splitParts(String text) { 174 List _splitParts(String text) {
183 return text.split('.').map((part) { 175 return text.split('.').map((part) {
184 try { 176 try {
185 return parseInt(part); 177 return parseInt(part);
186 } on FormatException catch (ex) { 178 } on FormatException catch (ex) {
187 // Not a number. 179 // Not a number.
188 return part; 180 return part;
189 } 181 }
190 }); 182 });
191 } 183 }
192 } 184 }
193 185
194 /** 186 /// A [VersionConstraint] is a predicate that can determine whether a given
195 * A [VersionConstraint] is a predicate that can determine whether a given 187 /// version is valid or not. For example, a ">= 2.0.0" constraint allows any
196 * version is valid or not. For example, a ">= 2.0.0" constraint allows any 188 /// version that is "2.0.0" or greater. Version objects themselves implement
197 * version that is "2.0.0" or greater. Version objects themselves implement 189 /// this to match a specific version.
198 * this to match a specific version.
199 */
200 abstract class VersionConstraint { 190 abstract class VersionConstraint {
201 /** 191 /// A [VersionConstraint] that allows no versions: i.e. the empty set.
202 * A [VersionConstraint] that allows no versions: i.e. the empty set.
203 */
204 factory VersionConstraint.empty() => const _EmptyVersion(); 192 factory VersionConstraint.empty() => const _EmptyVersion();
205 193
206 /** 194 /// Parses a version constraint. This string is a space-separated series of
207 * Parses a version constraint. This string is a space-separated series of 195 /// version parts. Each part can be one of:
208 * version parts. Each part can be one of: 196 ///
209 * 197 /// * A version string like `1.2.3`. In other words, anything that can be
210 * * A version string like `1.2.3`. In other words, anything that can be 198 /// parsed by [Version.parse()].
211 * parsed by [Version.parse()]. 199 /// * A comparison operator (`<`, `>`, `<=`, or `>=`) followed by a version
212 * * A comparison operator (`<`, `>`, `<=`, or `>=`) followed by a version 200 /// string. There cannot be a space between the operator and the version.
213 * string. There cannot be a space between the operator and the version. 201 ///
214 * 202 /// Examples:
215 * Examples: 203 ///
216 * 204 /// 1.2.3-alpha
217 * 1.2.3-alpha 205 /// <=5.1.4
218 * <=5.1.4 206 /// >2.0.4 <=2.4.6
219 * >2.0.4 <=2.4.6
220 */
221 factory VersionConstraint.parse(String text) { 207 factory VersionConstraint.parse(String text) {
222 if (text.trim() == '') { 208 if (text.trim() == '') {
223 throw new FormatException('Cannot parse an empty string.'); 209 throw new FormatException('Cannot parse an empty string.');
224 } 210 }
225 211
226 // Split it into space-separated parts. 212 // Split it into space-separated parts.
227 var constraints = <VersionConstraint>[]; 213 var constraints = <VersionConstraint>[];
228 for (var part in text.split(' ')) { 214 for (var part in text.split(' ')) {
229 constraints.add(_parseSingleConstraint(part)); 215 constraints.add(_parseSingleConstraint(part));
230 } 216 }
231 217
232 return new VersionConstraint.intersection(constraints); 218 return new VersionConstraint.intersection(constraints);
233 } 219 }
234 220
235 /** 221 /// Creates a new version constraint that is the intersection of
236 * Creates a new version constraint that is the intersection of [constraints]. 222 /// [constraints]. It will only allow versions that all of those constraints
237 * It will only allow versions that all of those constraints allow. If 223 /// allow. If constraints is empty, then it returns a VersionConstraint that
238 * constraints is empty, then it returns a VersionConstraint that allows all 224 /// allows all versions.
239 * versions.
240 */
241 factory VersionConstraint.intersection( 225 factory VersionConstraint.intersection(
242 Collection<VersionConstraint> constraints) { 226 Collection<VersionConstraint> constraints) {
243 var constraint = new VersionRange(); 227 var constraint = new VersionRange();
244 for (var other in constraints) { 228 for (var other in constraints) {
245 constraint = constraint.intersect(other); 229 constraint = constraint.intersect(other);
246 } 230 }
247 return constraint; 231 return constraint;
248 } 232 }
249 233
250 /** 234 /// Returns `true` if this constraint allows no versions.
251 * Returns `true` if this constraint allows no versions.
252 */
253 bool get isEmpty; 235 bool get isEmpty;
254 236
255 /** 237 /// Returns `true` if this constraint allows [version].
256 * Returns `true` if this constraint allows [version].
257 */
258 bool allows(Version version); 238 bool allows(Version version);
259 239
260 /** 240 /// Creates a new [VersionConstraint] that only allows [Version]s allowed by
261 * Creates a new [VersionConstraint] that only allows [Version]s allowed by 241 /// both this and [other].
262 * both this and [other].
263 */
264 VersionConstraint intersect(VersionConstraint other); 242 VersionConstraint intersect(VersionConstraint other);
265 243
266 static VersionConstraint _parseSingleConstraint(String text) { 244 static VersionConstraint _parseSingleConstraint(String text) {
267 if (text == 'any') { 245 if (text == 'any') {
268 return new VersionRange(); 246 return new VersionRange();
269 } 247 }
270 248
271 // TODO(rnystrom): Consider other syntaxes for version constraints. This 249 // TODO(rnystrom): Consider other syntaxes for version constraints. This
272 // one is whitespace sensitive (you can't do "< 1.2.3") and "<" is 250 // one is whitespace sensitive (you can't do "< 1.2.3") and "<" is
273 // unfortunately meaningful in YAML, requiring it to be quoted in a 251 // unfortunately meaningful in YAML, requiring it to be quoted in a
274 // pubspec. 252 // pubspec.
275 // See if it's a comparison operator followed by a version, like ">1.2.3". 253 // See if it's a comparison operator followed by a version, like ">1.2.3".
276 var match = new RegExp(r"^([<>]=?)?(.*)$").firstMatch(text); 254 var match = new RegExp(r"^([<>]=?)?(.*)$").firstMatch(text);
277 if (match != null) { 255 if (match != null) {
278 var comparison = match[1]; 256 var comparison = match[1];
279 var version = new Version.parse(match[2]); 257 var version = new Version.parse(match[2]);
280 switch (match[1]) { 258 switch (match[1]) {
281 case '<=': return new VersionRange(max: version, includeMax: true); 259 case '<=': return new VersionRange(max: version, includeMax: true);
282 case '<': return new VersionRange(max: version, includeMax: false); 260 case '<': return new VersionRange(max: version, includeMax: false);
283 case '>=': return new VersionRange(min: version, includeMin: true); 261 case '>=': return new VersionRange(min: version, includeMin: true);
284 case '>': return new VersionRange(min: version, includeMin: false); 262 case '>': return new VersionRange(min: version, includeMin: false);
285 } 263 }
286 } 264 }
287 265
288 // Otherwise, it must be an explicit version. 266 // Otherwise, it must be an explicit version.
289 return new Version.parse(text); 267 return new Version.parse(text);
290 } 268 }
291 } 269 }
292 270
293 /** 271 /// Constrains versions to a fall within a given range. If there is a minimum,
294 * Constrains versions to a fall within a given range. If there is a minimum, 272 /// then this only allows versions that are at that minimum or greater. If there
295 * then this only allows versions that are at that minimum or greater. If there 273 /// is a maximum, then only versions less than that are allowed. In other words,
296 * is a maximum, then only versions less than that are allowed. In other words, 274 /// this allows `>= min, < max`.
297 * this allows `>= min, < max`.
298 */
299 class VersionRange implements VersionConstraint { 275 class VersionRange implements VersionConstraint {
300 final Version min; 276 final Version min;
301 final Version max; 277 final Version max;
302 final bool includeMin; 278 final bool includeMin;
303 final bool includeMax; 279 final bool includeMax;
304 280
305 VersionRange({this.min, this.max, 281 VersionRange({this.min, this.max,
306 this.includeMin: false, this.includeMax: false}) { 282 this.includeMin: false, this.includeMax: false}) {
307 if (min != null && max != null && min > max) { 283 if (min != null && max != null && min > max) {
308 throw new ArgumentError( 284 throw new ArgumentError(
309 'Minimum version ("$min") must be less than maximum ("$max").'); 285 'Minimum version ("$min") must be less than maximum ("$max").');
310 } 286 }
311 } 287 }
312 288
313 bool operator ==(other) { 289 bool operator ==(other) {
314 if (other is! VersionRange) return false; 290 if (other is! VersionRange) return false;
315 291
316 return min == other.min && 292 return min == other.min &&
317 max == other.max && 293 max == other.max &&
318 includeMin == other.includeMin && 294 includeMin == other.includeMin &&
319 includeMax == other.includeMax; 295 includeMax == other.includeMax;
320 } 296 }
321 297
322 bool get isEmpty => false; 298 bool get isEmpty => false;
323 299
324 /** Tests if [other] matches falls within this version range. */ 300 /// Tests if [other] matches falls within this version range.
325 bool allows(Version other) { 301 bool allows(Version other) {
326 if (min != null && other < min) return false; 302 if (min != null && other < min) return false;
327 if (min != null && !includeMin && other == min) return false; 303 if (min != null && !includeMin && other == min) return false;
328 if (max != null && other > max) return false; 304 if (max != null && other > max) return false;
329 if (max != null && !includeMax && other == max) return false; 305 if (max != null && !includeMax && other == max) return false;
330 return true; 306 return true;
331 } 307 }
332 308
333 VersionConstraint intersect(VersionConstraint other) { 309 VersionConstraint intersect(VersionConstraint other) {
334 if (other.isEmpty) return other; 310 if (other.isEmpty) return other;
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
412 } 388 }
413 389
414 class _EmptyVersion implements VersionConstraint { 390 class _EmptyVersion implements VersionConstraint {
415 const _EmptyVersion(); 391 const _EmptyVersion();
416 392
417 bool get isEmpty => true; 393 bool get isEmpty => true;
418 bool allows(Version other) => false; 394 bool allows(Version other) => false;
419 VersionConstraint intersect(VersionConstraint other) => this; 395 VersionConstraint intersect(VersionConstraint other) => this;
420 String toString() => '<empty>'; 396 String toString() => '<empty>';
421 } 397 }
OLDNEW
« no previous file with comments | « utils/pub/utils.dart ('k') | utils/pub/version_solver.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698