diff options
author | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2021-01-14 00:04:31 -0500 |
---|---|---|
committer | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2021-01-15 18:21:28 -0500 |
commit | de789fb3e8f344a09032c23f56e800717ea801a0 (patch) | |
tree | 703082118fe8ae9f198e00e4d74908cbcc312150 | |
parent | d31370b1d702511fd2d08c66a1f58aac5d454edd (diff) | |
download | SMAPI-de789fb3e8f344a09032c23f56e800717ea801a0.tar.gz SMAPI-de789fb3e8f344a09032c23f56e800717ea801a0.tar.bz2 SMAPI-de789fb3e8f344a09032c23f56e800717ea801a0.zip |
fix semantic version comparison returning wrong value in rare cases
-rw-r--r-- | docs/release-notes.md | 2 | ||||
-rw-r--r-- | src/SMAPI.Toolkit/SemanticVersion.cs | 80 |
2 files changed, 51 insertions, 31 deletions
diff --git a/docs/release-notes.md b/docs/release-notes.md index f4f65653..0d8fc0ac 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -11,6 +11,8 @@ * For players: * Fixed issue where title screen music didn't stop after loading a save. +* For modders: + * Fixed `SemanticVersion` comparisons returning wrong value in rare cases. ## 3.8.3 Released 08 January 2021 for Stardew Valley 1.5.2 or later. diff --git a/src/SMAPI.Toolkit/SemanticVersion.cs b/src/SMAPI.Toolkit/SemanticVersion.cs index 0f341665..d58dce0c 100644 --- a/src/SMAPI.Toolkit/SemanticVersion.cs +++ b/src/SMAPI.Toolkit/SemanticVersion.cs @@ -230,38 +230,49 @@ namespace StardewModdingAPI.Toolkit const int curNewer = 1; const int curOlder = -1; - // compare stable versions - if (this.MajorVersion != otherMajor) - return this.MajorVersion.CompareTo(otherMajor); - if (this.MinorVersion != otherMinor) - return this.MinorVersion.CompareTo(otherMinor); - if (this.PatchVersion != otherPatch) - return this.PatchVersion.CompareTo(otherPatch); - if (this.PlatformRelease != otherPlatformRelease) - return this.PlatformRelease.CompareTo(otherPlatformRelease); - if (this.PrereleaseTag == otherTag) - return same; - - // stable supersedes prerelease - bool curIsStable = string.IsNullOrWhiteSpace(this.PrereleaseTag); - bool otherIsStable = string.IsNullOrWhiteSpace(otherTag); - if (curIsStable) - return curNewer; - if (otherIsStable) - return curOlder; - - // compare two prerelease tag values - string[] curParts = this.PrereleaseTag.Split('.', '-'); - string[] otherParts = otherTag.Split('.', '-'); - for (int i = 0; i < curParts.Length; i++) + int CompareToRaw() { - // longer prerelease tag supersedes if otherwise equal - if (otherParts.Length <= i) + // compare stable versions + if (this.MajorVersion != otherMajor) + return this.MajorVersion.CompareTo(otherMajor); + if (this.MinorVersion != otherMinor) + return this.MinorVersion.CompareTo(otherMinor); + if (this.PatchVersion != otherPatch) + return this.PatchVersion.CompareTo(otherPatch); + if (this.PlatformRelease != otherPlatformRelease) + return this.PlatformRelease.CompareTo(otherPlatformRelease); + if (this.PrereleaseTag == otherTag) + return same; + + // stable supersedes prerelease + bool curIsStable = string.IsNullOrWhiteSpace(this.PrereleaseTag); + bool otherIsStable = string.IsNullOrWhiteSpace(otherTag); + if (curIsStable) return curNewer; - - // compare if different - if (curParts[i] != otherParts[i]) + if (otherIsStable) + return curOlder; + + // compare two prerelease tag values + string[] curParts = this.PrereleaseTag.Split('.', '-'); + string[] otherParts = otherTag.Split('.', '-'); + int length = Math.Max(curParts.Length, otherParts.Length); + for (int i = 0; i < length; i++) { + // longer prerelease tag supersedes if otherwise equal + if (curParts.Length <= i) + return curOlder; + if (otherParts.Length <= i) + return curNewer; + + // skip if same value, unless we've reached the end + if (curParts[i] == otherParts[i]) + { + if (i == length - 1) + return same; + + continue; + } + // unofficial is always lower-precedence if (otherParts[i].Equals("unofficial", StringComparison.OrdinalIgnoreCase)) return curNewer; @@ -277,10 +288,17 @@ namespace StardewModdingAPI.Toolkit // else compare lexically return string.Compare(curParts[i], otherParts[i], StringComparison.OrdinalIgnoreCase); } + + // fallback (this should never happen) + return string.Compare(this.ToString(), new SemanticVersion(otherMajor, otherMinor, otherPatch, otherPlatformRelease, otherTag).ToString(), StringComparison.OrdinalIgnoreCase); } - // fallback (this should never happen) - return string.Compare(this.ToString(), new SemanticVersion(otherMajor, otherMinor, otherPatch, otherPlatformRelease, otherTag).ToString(), StringComparison.OrdinalIgnoreCase); + return CompareToRaw() switch + { + (< 0) => curOlder, + (> 0) => curNewer, + _ => same + }; } /// <summary>Assert that the current version is valid.</summary> |