summaryrefslogtreecommitdiff
path: root/src/StardewModdingAPI/SemanticVersion.cs
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <github@jplamondonw.com>2016-12-21 11:45:52 -0500
committerJesse Plamondon-Willard <github@jplamondonw.com>2016-12-21 11:45:52 -0500
commitea65b2b7df78fd075caecac96937e9870e06e646 (patch)
tree77db25cfd1890e3d00c0bcf3347f64ce35b7f44b /src/StardewModdingAPI/SemanticVersion.cs
parent45ee74219ee931b5fef3b67c08adf79d55aa091d (diff)
downloadSMAPI-ea65b2b7df78fd075caecac96937e9870e06e646.tar.gz
SMAPI-ea65b2b7df78fd075caecac96937e9870e06e646.tar.bz2
SMAPI-ea65b2b7df78fd075caecac96937e9870e06e646.zip
correct semantic version pre-release label precedence (#195)
Diffstat (limited to 'src/StardewModdingAPI/SemanticVersion.cs')
-rw-r--r--src/StardewModdingAPI/SemanticVersion.cs59
1 files changed, 45 insertions, 14 deletions
diff --git a/src/StardewModdingAPI/SemanticVersion.cs b/src/StardewModdingAPI/SemanticVersion.cs
index b3d9ee4a..cf435aaa 100644
--- a/src/StardewModdingAPI/SemanticVersion.cs
+++ b/src/StardewModdingAPI/SemanticVersion.cs
@@ -48,25 +48,56 @@ namespace StardewModdingAPI
/// <summary>Get an integer indicating whether this version precedes (less than 0), supercedes (more than 0), or is equivalent to (0) the specified version.</summary>
/// <param name="other">The version to compare with this instance.</param>
+ /// <remarks>The implementation is defined by Semantic Version 2.0 (http://semver.org/).</remarks>
public int CompareTo(ISemanticVersion other)
{
- // compare version numbers
+ const int same = 0;
+ const int curNewer = 1;
+ const int curOlder = -1;
+
+ // compare stable versions
if (this.MajorVersion != other.MajorVersion)
- return this.MajorVersion - other.MajorVersion;
+ return this.MajorVersion.CompareTo(other.MajorVersion);
if (this.MinorVersion != other.MinorVersion)
- return this.MinorVersion - other.MinorVersion;
+ return this.MinorVersion.CompareTo(other.MinorVersion);
if (this.PatchVersion != other.PatchVersion)
- return this.PatchVersion - other.PatchVersion;
-
- // stable version (without tag) supercedes prerelease (with tag)
- bool curHasTag = !string.IsNullOrWhiteSpace(this.Build);
- bool otherHasTag = !string.IsNullOrWhiteSpace(other.Build);
- if (!curHasTag && otherHasTag)
- return 1;
- if (curHasTag && !otherHasTag)
- return -1;
-
- // else compare by string
+ return this.PatchVersion.CompareTo(other.PatchVersion);
+ if (this.Build == other.Build)
+ return same;
+
+ // stable supercedes pre-release
+ bool curIsStable = string.IsNullOrWhiteSpace(this.Build);
+ bool otherIsStable = string.IsNullOrWhiteSpace(other.Build);
+ if (curIsStable)
+ return curNewer;
+ if (otherIsStable)
+ return curOlder;
+
+ // compare two pre-release tag values
+ string[] curParts = this.Build.Split('.');
+ string[] otherParts = other.Build.Split('.');
+ for (int i = 0; i < curParts.Length; i++)
+ {
+ // longer prerelease tag supercedes if otherwise equal
+ if (otherParts.Length <= i)
+ return curNewer;
+
+ // compare if different
+ if (curParts[i] != otherParts[i])
+ {
+ // compare numerically if possible
+ {
+ int curNum, otherNum;
+ if (int.TryParse(curParts[i], out curNum) && int.TryParse(otherParts[i], out otherNum))
+ return curNum.CompareTo(otherNum);
+ }
+
+ // else compare lexically
+ return string.Compare(curParts[i], otherParts[i], StringComparison.OrdinalIgnoreCase);
+ }
+ }
+
+ // fallback (this should never happen)
return string.Compare(this.ToString(), other.ToString(), StringComparison.InvariantCultureIgnoreCase);
}