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

Side by Side Diff: lib/src/version.dart

Issue 607663002: Harvest from pub. Mostly a straight copy, except: (Closed) Base URL: https://github.com/dart-lang/pub_semver.git@master
Patch Set: Revise! Created 6 years, 2 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
« no previous file with comments | « lib/src/patterns.dart ('k') | lib/src/version_constraint.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
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.
4
5 library pub_semver.src.version;
6
7 import 'dart:math';
8
9 import 'package:collection/equality.dart';
10
11 import 'patterns.dart';
12 import 'version_constraint.dart';
13 import 'version_range.dart';
14
15 /// The equality operator to use for comparing version components.
16 final _equality = const IterableEquality();
17
18 /// A parsed semantic version number.
19 class Version implements Comparable<Version>, VersionConstraint {
20 /// No released version: i.e. "0.0.0".
21 static Version get none => new Version(0, 0, 0);
22
23 /// Compares [a] and [b] to see which takes priority over the other.
24 ///
25 /// Returns `1` if [a] takes priority over [b] and `-1` if vice versa. If
26 /// [a] and [b] are equivalent, returns `0`.
27 ///
28 /// Unlike [compareTo], which *orders* versions, this determines which
29 /// version a user is likely to prefer. In particular, it prioritizes
30 /// pre-release versions lower than stable versions, regardless of their
31 /// version numbers. Pub uses this when determining which version to prefer
32 /// when a number of versions are allowed. In that case, it will always
33 /// choose a stable version when possible.
34 ///
35 /// When used to sort a list, orders in ascending priority so that the
36 /// highest priority version is *last* in the result.
37 static int prioritize(Version a, Version b) {
38 // Sort all prerelease versions after all normal versions. This way
39 // the solver will prefer stable packages over unstable ones.
40 if (a.isPreRelease && !b.isPreRelease) return -1;
41 if (!a.isPreRelease && b.isPreRelease) return 1;
42
43 return a.compareTo(b);
44 }
45
46 /// Like [proiritize], but lower version numbers are considered greater than
47 /// higher version numbers.
48 ///
49 /// This still considers prerelease versions to be lower than non-prerelease
50 /// versions. Pub uses this when downgrading -- it chooses the lowest version
51 /// but still excludes pre-release versions when possible.
52 static int antiprioritize(Version a, Version b) {
53 if (a.isPreRelease && !b.isPreRelease) return -1;
54 if (!a.isPreRelease && b.isPreRelease) return 1;
55
56 return b.compareTo(a);
57 }
58
59 /// The major version number: "1" in "1.2.3".
60 final int major;
61
62 /// The minor version number: "2" in "1.2.3".
63 final int minor;
64
65 /// The patch version number: "3" in "1.2.3".
66 final int patch;
67
68 /// The pre-release identifier: "foo" in "1.2.3-foo".
69 ///
70 /// This is split into a list of components, each of which may be either a
71 /// string or a non-negative integer. It may also be empty, indicating that
72 /// this version has no pre-release identifier.
73 final List preRelease;
74
75 /// The build identifier: "foo" in "1.2.3+foo".
76 ///
77 /// This is split into a list of components, each of which may be either a
78 /// string or a non-negative integer. It may also be empty, indicating that
79 /// this version has no build identifier.
80 final List build;
81
82 /// The original string representation of the version number.
83 ///
84 /// This preserves textual artifacts like leading zeros that may be left out
85 /// of the parsed version.
86 final String _text;
87
88 Version._(this.major, this.minor, this.patch, String preRelease, String build,
89 this._text)
90 : preRelease = preRelease == null ? [] : _splitParts(preRelease),
91 build = build == null ? [] : _splitParts(build) {
92 if (major < 0) throw new ArgumentError(
93 'Major version must be non-negative.');
94 if (minor < 0) throw new ArgumentError(
95 'Minor version must be non-negative.');
96 if (patch < 0) throw new ArgumentError(
97 'Patch version must be non-negative.');
98 }
99
100 /// Creates a new [Version] object.
101 factory Version(int major, int minor, int patch, {String pre, String build}) {
102 var text = "$major.$minor.$patch";
103 if (pre != null) text += "-$pre";
104 if (build != null) text += "+$build";
105
106 return new Version._(major, minor, patch, pre, build, text);
107 }
108
109 /// Creates a new [Version] by parsing [text].
110 factory Version.parse(String text) {
111 final match = COMPLETE_VERSION.firstMatch(text);
112 if (match == null) {
113 throw new FormatException('Could not parse "$text".');
114 }
115
116 try {
117 int major = int.parse(match[1]);
118 int minor = int.parse(match[2]);
119 int patch = int.parse(match[3]);
120
121 String preRelease = match[5];
122 String build = match[8];
123
124 return new Version._(major, minor, patch, preRelease, build, text);
125 } on FormatException catch (ex) {
126 throw new FormatException('Could not parse "$text".');
127 }
128 }
129
130 /// Returns the primary version out of a list of candidates.
131 ///
132 /// This is the highest-numbered stable (non-prerelease) version. If there
133 /// are no stable versions, it's just the highest-numbered version.
134 static Version primary(List<Version> versions) {
135 var primary;
136 for (var version in versions) {
137 if (primary == null || (!version.isPreRelease && primary.isPreRelease) ||
138 (version.isPreRelease == primary.isPreRelease && version > primary)) {
139 primary = version;
140 }
141 }
142 return primary;
143 }
144
145 /// Splits a string of dot-delimited identifiers into their component parts.
146 ///
147 /// Identifiers that are numeric are converted to numbers.
148 static List _splitParts(String text) {
149 return text.split('.').map((part) {
150 try {
151 return int.parse(part);
152 } on FormatException catch (ex) {
153 // Not a number.
154 return part;
155 }
156 }).toList();
157 }
158
159 bool operator ==(other) {
160 if (other is! Version) return false;
161 return major == other.major && minor == other.minor &&
162 patch == other.patch &&
163 _equality.equals(preRelease, other.preRelease) &&
164 _equality.equals(build, other.build);
165 }
166
167 int get hashCode => major ^ minor ^ patch ^ _equality.hash(preRelease) ^
168 _equality.hash(build);
169
170 bool operator <(Version other) => compareTo(other) < 0;
171 bool operator >(Version other) => compareTo(other) > 0;
172 bool operator <=(Version other) => compareTo(other) <= 0;
173 bool operator >=(Version other) => compareTo(other) >= 0;
174
175 bool get isAny => false;
176 bool get isEmpty => false;
177
178 /// Whether or not this is a pre-release version.
179 bool get isPreRelease => preRelease.isNotEmpty;
180
181 /// Gets the next major version number that follows this one.
182 ///
183 /// If this version is a pre-release of a major version release (i.e. the
184 /// minor and patch versions are zero), then it just strips the pre-release
185 /// suffix. Otherwise, it increments the major version and resets the minor
186 /// and patch.
187 Version get nextMajor {
188 if (isPreRelease && minor == 0 && patch == 0) {
189 return new Version(major, minor, patch);
190 }
191
192 return new Version(major + 1, 0, 0);
193 }
194
195 /// Gets the next minor version number that follows this one.
196 ///
197 /// If this version is a pre-release of a minor version release (i.e. the
198 /// patch version is zero), then it just strips the pre-release suffix.
199 /// Otherwise, it increments the minor version and resets the patch.
200 Version get nextMinor {
201 if (isPreRelease && patch == 0) {
202 return new Version(major, minor, patch);
203 }
204
205 return new Version(major, minor + 1, 0);
206 }
207
208 /// Gets the next patch version number that follows this one.
209 ///
210 /// If this version is a pre-release, then it just strips the pre-release
211 /// suffix. Otherwise, it increments the patch version.
212 Version get nextPatch {
213 if (isPreRelease) {
214 return new Version(major, minor, patch);
215 }
216
217 return new Version(major, minor, patch + 1);
218 }
219
220 /// Tests if [other] matches this version exactly.
221 bool allows(Version other) => this == other;
222
223 VersionConstraint intersect(VersionConstraint other) {
224 if (other.isEmpty) return other;
225
226 // Intersect a version and a range.
227 if (other is VersionRange) return other.intersect(this);
228
229 // Intersecting two versions only works if they are the same.
230 if (other is Version) {
231 return this == other ? this : VersionConstraint.empty;
232 }
233
234 throw new ArgumentError(
235 'Unknown VersionConstraint type $other.');
236 }
237
238 int compareTo(Version other) {
239 if (major != other.major) return major.compareTo(other.major);
240 if (minor != other.minor) return minor.compareTo(other.minor);
241 if (patch != other.patch) return patch.compareTo(other.patch);
242
243 // Pre-releases always come before no pre-release string.
244 if (!isPreRelease && other.isPreRelease) return 1;
245 if (!other.isPreRelease && isPreRelease) return -1;
246
247 var comparison = _compareLists(preRelease, other.preRelease);
248 if (comparison != 0) return comparison;
249
250 // Builds always come after no build string.
251 if (build.isEmpty && other.build.isNotEmpty) return -1;
252 if (other.build.isEmpty && build.isNotEmpty) return 1;
253 return _compareLists(build, other.build);
254 }
255
256 String toString() => _text;
257
258 /// Compares a dot-separated component of two versions.
259 ///
260 /// This is used for the pre-release and build version parts. This follows
261 /// Rule 12 of the Semantic Versioning spec (v2.0.0-rc.1).
262 int _compareLists(List a, List b) {
263 for (var i = 0; i < max(a.length, b.length); i++) {
264 var aPart = (i < a.length) ? a[i] : null;
265 var bPart = (i < b.length) ? b[i] : null;
266
267 if (aPart == bPart) continue;
268
269 // Missing parts come before present ones.
270 if (aPart == null) return -1;
271 if (bPart == null) return 1;
272
273 if (aPart is num) {
274 if (bPart is num) {
275 // Compare two numbers.
276 return aPart.compareTo(bPart);
277 } else {
278 // Numbers come before strings.
279 return -1;
280 }
281 } else {
282 if (bPart is num) {
283 // Strings come after numbers.
284 return 1;
285 } else {
286 // Compare two strings.
287 return aPart.compareTo(bPart);
288 }
289 }
290 }
291
292 // The lists are entirely equal.
293 return 0;
294 }
295 }
OLDNEW
« no previous file with comments | « lib/src/patterns.dart ('k') | lib/src/version_constraint.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698