VersionNumber.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  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. else 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. else
  81. {
  82. version = new(int.Parse(match.Groups["major"].Value),
  83. int.Parse(match.Groups["minor"].Value),
  84. 0
  85. );
  86. }
  87. return true;
  88. }
  89. public int CompareTo(object? obj)
  90. {
  91. if (obj is not VersionNumber other)
  92. throw new ArgumentException($"Object must be of type {nameof(VersionNumber)}");
  93. var _result = this < other ? -1 : this == other ? 0 : 1;
  94. return _result;
  95. }
  96. public static bool operator <(VersionNumber a, VersionNumber b)
  97. {
  98. if (a.IsDevelopmentVersion) return false;
  99. if (b.IsDevelopmentVersion) return true;
  100. if (a.MajorVersion != b.MajorVersion)
  101. return a.MajorVersion < b.MajorVersion;
  102. if (a.MinorVersion != b.MinorVersion)
  103. return a.MinorVersion < b.MinorVersion;
  104. if (a.IsNewStyle && b.IsNewStyle)
  105. return int.Parse(a.Release) < int.Parse(b.Release);
  106. return String.Compare(a.Release,b.Release, StringComparison.OrdinalIgnoreCase) < 0;
  107. }
  108. public static bool operator >(VersionNumber a, VersionNumber b)
  109. {
  110. return b < a;
  111. }
  112. public static bool operator <=(VersionNumber a, VersionNumber b)
  113. {
  114. return !(b < a);
  115. }
  116. public static bool operator >=(VersionNumber a, VersionNumber b)
  117. {
  118. return !(a < b);
  119. }
  120. public override bool Equals(object? obj)
  121. {
  122. if(obj is VersionNumber v)
  123. {
  124. return this == v;
  125. }
  126. return false;
  127. }
  128. public override int GetHashCode()
  129. {
  130. if (IsDevelopmentVersion)
  131. return 0;
  132. return MajorVersion ^ MinorVersion ^ Release.GetHashCode();
  133. }
  134. public static bool operator ==(VersionNumber a, VersionNumber b)
  135. {
  136. if (a.IsDevelopmentVersion)
  137. return b.IsDevelopmentVersion;
  138. if (b.IsDevelopmentVersion)
  139. return false;
  140. return a.MajorVersion == b.MajorVersion
  141. && a.MinorVersion == b.MinorVersion
  142. && String.Compare(a.Release,b.Release, StringComparison.OrdinalIgnoreCase) == 0;
  143. }
  144. public static bool operator !=(VersionNumber a, VersionNumber b)
  145. {
  146. if (a.IsDevelopmentVersion)
  147. return !b.IsDevelopmentVersion;
  148. if (b.IsDevelopmentVersion)
  149. return true;
  150. return a.MajorVersion != b.MajorVersion
  151. || a.MinorVersion != b.MinorVersion
  152. || String.Compare(a.Release, b.Release, StringComparison.OrdinalIgnoreCase) != 0;
  153. }
  154. public override string ToString()
  155. {
  156. return IsDevelopmentVersion
  157. ? "???"
  158. : IsNewStyle
  159. ? !Release.Equals("0")
  160. ? $"{MajorVersion}.{MinorVersion:D2}.{Release}"
  161. : $"{MajorVersion}.{MinorVersion:D2}"
  162. : $"{MajorVersion}.{MinorVersion:D2}{Release}";
  163. }
  164. }