Elastic.Console/ElasticVersion.cs (84 lines of code) (raw):
// A simple version implementation based on
// https://github.com/maxhauser/semver/blob/master/src/Semver/SemVersion.cs
// MIT License
// Copyright (c) 2013 Max Hauser
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Globalization;
using System.Runtime.Serialization;
using System.Security.Permissions;
using System.Text.RegularExpressions;
namespace Elastic
{
/// <summary>
/// An Elastic product version
/// </summary>
public sealed class ElasticVersion : IEquatable<ElasticVersion>, IComparable<ElasticVersion>, IComparable
{
private static Regex VersionRegex = new Regex(
@"^(?<major>\d+)(\.(?<minor>\d+))?(\.(?<patch>\d+))?(\-(?<pre>[0-9A-Za-z]+))?$",
RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture);
public ElasticVersion(object version) : this(version.ToString())
{
}
public ElasticVersion(string version)
{
var match = VersionRegex.Match(version);
if (!match.Success)
throw new ArgumentException(string.Format("Invalid version '{0}'", version), "version");
var major = int.Parse(match.Groups["major"].Value, CultureInfo.InvariantCulture);
var minorMatch = match.Groups["minor"];
int minor = 0;
if (minorMatch.Success)
minor = int.Parse(minorMatch.Value, CultureInfo.InvariantCulture);
var patchMatch = match.Groups["patch"];
int patch = 0;
if (patchMatch.Success)
patch = int.Parse(patchMatch.Value, CultureInfo.InvariantCulture);
var prerelease = match.Groups["pre"].Value;
this.Major = major;
this.Minor = minor;
this.Patch = patch;
this.Prerelease = prerelease;
}
public ElasticVersion(int major, int minor, int patch, string prerelease)
{
this.Major = major;
this.Minor = minor;
this.Patch = patch;
this.Prerelease = prerelease;
}
public static bool TryParse(string version, out ElasticVersion ElasticVersion)
{
try
{
ElasticVersion = new ElasticVersion(version);
return true;
}
catch (Exception)
{
ElasticVersion = null;
return false;
}
}
public static bool Equals(ElasticVersion versionA, ElasticVersion versionB)
{
if (ReferenceEquals(versionA, null))
return ReferenceEquals(versionB, null);
return versionA.Equals(versionB);
}
public static int Compare(ElasticVersion versionA, ElasticVersion versionB)
{
if (ReferenceEquals(versionA, null))
return ReferenceEquals(versionB, null) ? 0 : -1;
return versionA.CompareTo(versionB);
}
public ElasticVersion Change(int? major = null, int? minor = null, int? patch = null, string prerelease = null)
{
return new ElasticVersion(
major ?? this.Major,
minor ?? this.Minor,
patch ?? this.Patch,
prerelease ?? this.Prerelease);
}
public int Major { get; private set; }
public int Minor { get; private set; }
public int Patch { get; private set; }
public string Prerelease { get; private set; }
public override string ToString()
{
var version = "" + Major + "." + Minor + "." + Patch;
if (!String.IsNullOrEmpty(Prerelease))
version += "-" + Prerelease;
return version;
}
public int CompareTo(object obj)
{
return CompareTo((ElasticVersion)obj);
}
public int CompareTo(ElasticVersion other)
{
if (ReferenceEquals(other, null))
return 1;
var r = this.CompareByPrecedence(other);
return r;
}
public bool PrecedenceMatches(ElasticVersion other)
{
return CompareByPrecedence(other) == 0;
}
public int CompareByPrecedence(ElasticVersion other)
{
if (ReferenceEquals(other, null))
return 1;
var r = this.Major.CompareTo(other.Major);
if (r != 0) return r;
r = this.Minor.CompareTo(other.Minor);
if (r != 0) return r;
r = this.Patch.CompareTo(other.Patch);
if (r != 0) return r;
r = CompareComponent(this.Prerelease, other.Prerelease, true);
return r;
}
static int CompareComponent(string a, string b, bool lower = false)
{
var aEmpty = String.IsNullOrEmpty(a);
var bEmpty = String.IsNullOrEmpty(b);
if (aEmpty && bEmpty)
return 0;
if (aEmpty)
return lower ? 1 : -1;
if (bEmpty)
return lower ? -1 : 1;
var aComps = a.Split('.');
var bComps = b.Split('.');
var minLen = Math.Min(aComps.Length, bComps.Length);
for (int i = 0; i < minLen; i++)
{
var ac = aComps[i];
var bc = bComps[i];
int anum, bnum;
var isanum = Int32.TryParse(ac, out anum);
var isbnum = Int32.TryParse(bc, out bnum);
int r;
if (isanum && isbnum)
{
r = anum.CompareTo(bnum);
if (r != 0) return anum.CompareTo(bnum);
}
else
{
if (isanum)
return -1;
if (isbnum)
return 1;
r = String.CompareOrdinal(ac, bc);
if (r != 0)
return r;
}
}
return aComps.Length.CompareTo(bComps.Length);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(obj, null))
return false;
if (ReferenceEquals(this, obj))
return true;
var other = (ElasticVersion)obj;
return Equals(other);
}
public bool Equals(ElasticVersion other)
{
if (other == null)
return false;
return this.Major == other.Major &&
this.Minor == other.Minor &&
this.Patch == other.Patch &&
string.Equals(this.Prerelease, other.Prerelease, StringComparison.Ordinal);
}
public override int GetHashCode()
{
unchecked
{
int result = this.Major.GetHashCode();
result = result * 31 + this.Minor.GetHashCode();
result = result * 31 + this.Patch.GetHashCode();
result = result * 31 + this.Prerelease.GetHashCode();
return result;
}
}
public static bool operator ==(ElasticVersion left, ElasticVersion right)
{
return ElasticVersion.Equals(left, right);
}
public static bool operator !=(ElasticVersion left, ElasticVersion right)
{
return !ElasticVersion.Equals(left, right);
}
public static bool operator >(ElasticVersion left, ElasticVersion right)
{
return ElasticVersion.Compare(left, right) > 0;
}
public static bool operator >=(ElasticVersion left, ElasticVersion right)
{
return left == right || left > right;
}
public static bool operator <(ElasticVersion left, ElasticVersion right)
{
return ElasticVersion.Compare(left, right) < 0;
}
public static bool operator <=(ElasticVersion left, ElasticVersion right)
{
return left == right || left < right;
}
}
}