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

Unified 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, 3 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « lib/src/patterns.dart ('k') | lib/src/version_constraint.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/src/version.dart
diff --git a/lib/src/version.dart b/lib/src/version.dart
new file mode 100644
index 0000000000000000000000000000000000000000..866d89c30131720b6eb35f31e6edd9b527c8160f
--- /dev/null
+++ b/lib/src/version.dart
@@ -0,0 +1,295 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library pub_semver.src.version;
+
+import 'dart:math';
+
+import 'package:collection/equality.dart';
+
+import 'patterns.dart';
+import 'version_constraint.dart';
+import 'version_range.dart';
+
+/// The equality operator to use for comparing version components.
+final _equality = const IterableEquality();
+
+/// A parsed semantic version number.
+class Version implements Comparable<Version>, VersionConstraint {
+ /// No released version: i.e. "0.0.0".
+ static Version get none => new Version(0, 0, 0);
+
+ /// Compares [a] and [b] to see which takes priority over the other.
+ ///
+ /// Returns `1` if [a] takes priority over [b] and `-1` if vice versa. If
+ /// [a] and [b] are equivalent, returns `0`.
+ ///
+ /// Unlike [compareTo], which *orders* versions, this determines which
+ /// version a user is likely to prefer. In particular, it prioritizes
+ /// pre-release versions lower than stable versions, regardless of their
+ /// version numbers. Pub uses this when determining which version to prefer
+ /// when a number of versions are allowed. In that case, it will always
+ /// choose a stable version when possible.
+ ///
+ /// When used to sort a list, orders in ascending priority so that the
+ /// highest priority version is *last* in the result.
+ static int prioritize(Version a, Version b) {
+ // Sort all prerelease versions after all normal versions. This way
+ // the solver will prefer stable packages over unstable ones.
+ if (a.isPreRelease && !b.isPreRelease) return -1;
+ if (!a.isPreRelease && b.isPreRelease) return 1;
+
+ return a.compareTo(b);
+ }
+
+ /// Like [proiritize], but lower version numbers are considered greater than
+ /// higher version numbers.
+ ///
+ /// This still considers prerelease versions to be lower than non-prerelease
+ /// versions. Pub uses this when downgrading -- it chooses the lowest version
+ /// but still excludes pre-release versions when possible.
+ static int antiprioritize(Version a, Version b) {
+ if (a.isPreRelease && !b.isPreRelease) return -1;
+ if (!a.isPreRelease && b.isPreRelease) return 1;
+
+ return b.compareTo(a);
+ }
+
+ /// The major version number: "1" in "1.2.3".
+ final int major;
+
+ /// The minor version number: "2" in "1.2.3".
+ final int minor;
+
+ /// The patch version number: "3" in "1.2.3".
+ final int patch;
+
+ /// The pre-release identifier: "foo" in "1.2.3-foo".
+ ///
+ /// This is split into a list of components, each of which may be either a
+ /// string or a non-negative integer. It may also be empty, indicating that
+ /// this version has no pre-release identifier.
+ final List preRelease;
+
+ /// The build identifier: "foo" in "1.2.3+foo".
+ ///
+ /// This is split into a list of components, each of which may be either a
+ /// string or a non-negative integer. It may also be empty, indicating that
+ /// this version has no build identifier.
+ final List build;
+
+ /// The original string representation of the version number.
+ ///
+ /// This preserves textual artifacts like leading zeros that may be left out
+ /// of the parsed version.
+ final String _text;
+
+ Version._(this.major, this.minor, this.patch, String preRelease, String build,
+ this._text)
+ : preRelease = preRelease == null ? [] : _splitParts(preRelease),
+ build = build == null ? [] : _splitParts(build) {
+ if (major < 0) throw new ArgumentError(
+ 'Major version must be non-negative.');
+ if (minor < 0) throw new ArgumentError(
+ 'Minor version must be non-negative.');
+ if (patch < 0) throw new ArgumentError(
+ 'Patch version must be non-negative.');
+ }
+
+ /// Creates a new [Version] object.
+ factory Version(int major, int minor, int patch, {String pre, String build}) {
+ var text = "$major.$minor.$patch";
+ if (pre != null) text += "-$pre";
+ if (build != null) text += "+$build";
+
+ return new Version._(major, minor, patch, pre, build, text);
+ }
+
+ /// Creates a new [Version] by parsing [text].
+ factory Version.parse(String text) {
+ final match = COMPLETE_VERSION.firstMatch(text);
+ if (match == null) {
+ throw new FormatException('Could not parse "$text".');
+ }
+
+ try {
+ int major = int.parse(match[1]);
+ int minor = int.parse(match[2]);
+ int patch = int.parse(match[3]);
+
+ String preRelease = match[5];
+ String build = match[8];
+
+ return new Version._(major, minor, patch, preRelease, build, text);
+ } on FormatException catch (ex) {
+ throw new FormatException('Could not parse "$text".');
+ }
+ }
+
+ /// Returns the primary version out of a list of candidates.
+ ///
+ /// This is the highest-numbered stable (non-prerelease) version. If there
+ /// are no stable versions, it's just the highest-numbered version.
+ static Version primary(List<Version> versions) {
+ var primary;
+ for (var version in versions) {
+ if (primary == null || (!version.isPreRelease && primary.isPreRelease) ||
+ (version.isPreRelease == primary.isPreRelease && version > primary)) {
+ primary = version;
+ }
+ }
+ return primary;
+ }
+
+ /// Splits a string of dot-delimited identifiers into their component parts.
+ ///
+ /// Identifiers that are numeric are converted to numbers.
+ static List _splitParts(String text) {
+ return text.split('.').map((part) {
+ try {
+ return int.parse(part);
+ } on FormatException catch (ex) {
+ // Not a number.
+ return part;
+ }
+ }).toList();
+ }
+
+ bool operator ==(other) {
+ if (other is! Version) return false;
+ return major == other.major && minor == other.minor &&
+ patch == other.patch &&
+ _equality.equals(preRelease, other.preRelease) &&
+ _equality.equals(build, other.build);
+ }
+
+ int get hashCode => major ^ minor ^ patch ^ _equality.hash(preRelease) ^
+ _equality.hash(build);
+
+ bool operator <(Version other) => compareTo(other) < 0;
+ bool operator >(Version other) => compareTo(other) > 0;
+ bool operator <=(Version other) => compareTo(other) <= 0;
+ bool operator >=(Version other) => compareTo(other) >= 0;
+
+ bool get isAny => false;
+ bool get isEmpty => false;
+
+ /// Whether or not this is a pre-release version.
+ bool get isPreRelease => preRelease.isNotEmpty;
+
+ /// Gets the next major version number that follows this one.
+ ///
+ /// If this version is a pre-release of a major version release (i.e. the
+ /// minor and patch versions are zero), then it just strips the pre-release
+ /// suffix. Otherwise, it increments the major version and resets the minor
+ /// and patch.
+ Version get nextMajor {
+ if (isPreRelease && minor == 0 && patch == 0) {
+ return new Version(major, minor, patch);
+ }
+
+ return new Version(major + 1, 0, 0);
+ }
+
+ /// Gets the next minor version number that follows this one.
+ ///
+ /// If this version is a pre-release of a minor version release (i.e. the
+ /// patch version is zero), then it just strips the pre-release suffix.
+ /// Otherwise, it increments the minor version and resets the patch.
+ Version get nextMinor {
+ if (isPreRelease && patch == 0) {
+ return new Version(major, minor, patch);
+ }
+
+ return new Version(major, minor + 1, 0);
+ }
+
+ /// Gets the next patch version number that follows this one.
+ ///
+ /// If this version is a pre-release, then it just strips the pre-release
+ /// suffix. Otherwise, it increments the patch version.
+ Version get nextPatch {
+ if (isPreRelease) {
+ return new Version(major, minor, patch);
+ }
+
+ return new Version(major, minor, patch + 1);
+ }
+
+ /// Tests if [other] matches this version exactly.
+ bool allows(Version other) => this == other;
+
+ VersionConstraint intersect(VersionConstraint other) {
+ if (other.isEmpty) return other;
+
+ // Intersect a version and a range.
+ if (other is VersionRange) return other.intersect(this);
+
+ // Intersecting two versions only works if they are the same.
+ if (other is Version) {
+ return this == other ? this : VersionConstraint.empty;
+ }
+
+ throw new ArgumentError(
+ 'Unknown VersionConstraint type $other.');
+ }
+
+ int compareTo(Version other) {
+ if (major != other.major) return major.compareTo(other.major);
+ if (minor != other.minor) return minor.compareTo(other.minor);
+ if (patch != other.patch) return patch.compareTo(other.patch);
+
+ // Pre-releases always come before no pre-release string.
+ if (!isPreRelease && other.isPreRelease) return 1;
+ if (!other.isPreRelease && isPreRelease) return -1;
+
+ var comparison = _compareLists(preRelease, other.preRelease);
+ if (comparison != 0) return comparison;
+
+ // Builds always come after no build string.
+ if (build.isEmpty && other.build.isNotEmpty) return -1;
+ if (other.build.isEmpty && build.isNotEmpty) return 1;
+ return _compareLists(build, other.build);
+ }
+
+ String toString() => _text;
+
+ /// Compares a dot-separated component of two versions.
+ ///
+ /// This is used for the pre-release and build version parts. This follows
+ /// Rule 12 of the Semantic Versioning spec (v2.0.0-rc.1).
+ int _compareLists(List a, List b) {
+ for (var i = 0; i < max(a.length, b.length); i++) {
+ var aPart = (i < a.length) ? a[i] : null;
+ var bPart = (i < b.length) ? b[i] : null;
+
+ if (aPart == bPart) continue;
+
+ // Missing parts come before present ones.
+ if (aPart == null) return -1;
+ if (bPart == null) return 1;
+
+ if (aPart is num) {
+ if (bPart is num) {
+ // Compare two numbers.
+ return aPart.compareTo(bPart);
+ } else {
+ // Numbers come before strings.
+ return -1;
+ }
+ } else {
+ if (bPart is num) {
+ // Strings come after numbers.
+ return 1;
+ } else {
+ // Compare two strings.
+ return aPart.compareTo(bPart);
+ }
+ }
+ }
+
+ // The lists are entirely equal.
+ return 0;
+ }
+}
« 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