VersionNumber.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. using System.Diagnostics.CodeAnalysis;
  2. using System.Text.RegularExpressions;
  3. namespace InABox.Database;
  4. public class VersionNumber : IComparable
  5. {
  6. public int MajorVersion { get; }
  7. public int MinorVersion { get; }
  8. public string Release { get; }
  9. public bool IsDevelopmentVersion { get; }
  10. public bool IsNewStyle { get; private set; }
  11. public VersionNumber()
  12. {
  13. IsDevelopmentVersion = true;
  14. MajorVersion = 0;
  15. MinorVersion = 0;
  16. Release = "0";
  17. IsNewStyle = true;
  18. }
  19. public VersionNumber(int majorVersion, int minorVersion)
  20. {
  21. IsDevelopmentVersion = false;
  22. MajorVersion = majorVersion;
  23. MinorVersion = minorVersion;
  24. Release = "0";
  25. IsNewStyle = true;
  26. }
  27. public VersionNumber(int majorVersion, int minorVersion, int release)
  28. {
  29. IsDevelopmentVersion = false;
  30. MajorVersion = majorVersion;
  31. MinorVersion = minorVersion;
  32. Release = release.ToString();
  33. IsNewStyle = true;
  34. }
  35. public VersionNumber(int majorVersion, int minorVersion, string release)
  36. {
  37. IsDevelopmentVersion = false;
  38. MajorVersion = majorVersion;
  39. MinorVersion = minorVersion;
  40. Release = release;
  41. IsNewStyle = false;
  42. }
  43. private static readonly Regex _format =
  44. new Regex(
  45. @"^(?<major>\d+)\.(?<minor>\d+)(?:(?<oldstyle>[A-Za-z]+)|\.(?<newstyle>\d+))?$",
  46. RegexOptions.Compiled);
  47. public static VersionNumber Parse(string versionStr)
  48. {
  49. if (!TryParse(versionStr, out var _result))
  50. throw new FormatException($"'{versionStr}' is not a valid version!");
  51. return _result;
  52. }
  53. public static bool TryParse(string versionStr, [NotNullWhen(true)] out VersionNumber? version)
  54. {
  55. if (versionStr == "???")
  56. {
  57. version = new();
  58. return true;
  59. }
  60. var match = _format.Match(versionStr);
  61. if (!match.Success)
  62. {
  63. version = null;
  64. return false;
  65. }
  66. if (match.Groups["oldstyle"].Success)
  67. {
  68. version = new(int.Parse(match.Groups["major"].Value),
  69. int.Parse(match.Groups["minor"].Value),
  70. match.Groups["release"].Value
  71. );
  72. }
  73. if (match.Groups["newstyle"].Success)
  74. {
  75. version = new(int.Parse(match.Groups["major"].Value),
  76. int.Parse(match.Groups["minor"].Value),
  77. int.Parse(match.Groups["newstyle"].Value)
  78. );
  79. }
  80. version = new(int.Parse(match.Groups["major"].Value),
  81. int.Parse(match.Groups["minor"].Value),
  82. 0
  83. );
  84. return true;
  85. }
  86. public int CompareTo(object? obj)
  87. {
  88. if (obj is not VersionNumber other)
  89. throw new ArgumentException($"Object must be of type {nameof(VersionNumber)}");
  90. var _result = this < other ? -1 : this == other ? 0 : 1;
  91. return _result;
  92. }
  93. public static bool operator <(VersionNumber a, VersionNumber b)
  94. {
  95. if (a.IsDevelopmentVersion) return false;
  96. if (b.IsDevelopmentVersion) return true;
  97. if (a.MajorVersion != b.MajorVersion)
  98. return a.MajorVersion < b.MajorVersion;
  99. if (a.MinorVersion != b.MinorVersion)
  100. return a.MinorVersion < b.MinorVersion;
  101. if (a.IsNewStyle && b.IsNewStyle)
  102. return int.Parse(a.Release) < int.Parse(b.Release);
  103. return String.Compare(a.Release,b.Release, StringComparison.OrdinalIgnoreCase) < 0;
  104. }
  105. public static bool operator >(VersionNumber a, VersionNumber b)
  106. {
  107. return b < a;
  108. }
  109. public static bool operator <=(VersionNumber a, VersionNumber b)
  110. {
  111. return !(b < a);
  112. }
  113. public static bool operator >=(VersionNumber a, VersionNumber b)
  114. {
  115. return !(a < b);
  116. }
  117. public override bool Equals(object? obj)
  118. {
  119. if(obj is VersionNumber v)
  120. {
  121. return this == v;
  122. }
  123. return false;
  124. }
  125. public override int GetHashCode()
  126. {
  127. if (IsDevelopmentVersion)
  128. return 0;
  129. return MajorVersion ^ MinorVersion ^ Release.GetHashCode();
  130. }
  131. public static bool operator ==(VersionNumber a, VersionNumber b)
  132. {
  133. if (a.IsDevelopmentVersion)
  134. return b.IsDevelopmentVersion;
  135. if (b.IsDevelopmentVersion)
  136. return false;
  137. return a.MajorVersion == b.MajorVersion
  138. && a.MinorVersion == b.MinorVersion
  139. && String.Compare(a.Release,b.Release, StringComparison.OrdinalIgnoreCase) == 0;
  140. }
  141. public static bool operator !=(VersionNumber a, VersionNumber b)
  142. {
  143. if (a.IsDevelopmentVersion)
  144. return !b.IsDevelopmentVersion;
  145. if (b.IsDevelopmentVersion)
  146. return true;
  147. return a.MajorVersion != b.MajorVersion
  148. || a.MinorVersion != b.MinorVersion
  149. || String.Compare(a.Release, b.Release, StringComparison.OrdinalIgnoreCase) != 0;
  150. }
  151. public override string ToString()
  152. {
  153. return IsDevelopmentVersion
  154. ? "???"
  155. : IsNewStyle
  156. ? !Release.Equals("0")
  157. ? $"{MajorVersion}.{MinorVersion:D2}.{Release}"
  158. : $"{MajorVersion}.{MinorVersion:D2}"
  159. : $"{MajorVersion}.{MinorVersion:D2}{Release}";
  160. }
  161. }