You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

159 lines
3.6 KiB

  1. package version
  2. import (
  3. "regexp"
  4. "strconv"
  5. "strings"
  6. )
  7. var regexpSigns = regexp.MustCompile(`[_\-+]`)
  8. var regexpDotBeforeDigit = regexp.MustCompile(`([^.\d]+)`)
  9. var regexpMultipleDots = regexp.MustCompile(`\.{2,}`)
  10. var specialForms = map[string]int{
  11. "dev": -6,
  12. "alpha": -5,
  13. "a": -5,
  14. "beta": -4,
  15. "b": -4,
  16. "RC": -3,
  17. "rc": -3,
  18. "#": -2,
  19. "p": 1,
  20. "pl": 1,
  21. }
  22. // Compares two version number strings, for a particular relationship
  23. //
  24. // Usage
  25. // version.Compare("2.3.4", "v3.1.2", "<")
  26. // Returns: true
  27. //
  28. // version.Compare("1.0rc1", "1.0", ">=")
  29. // Returns: false
  30. func Compare(version1, version2, operator string) bool {
  31. version1N := Normalize(version1)
  32. version2N := Normalize(version2)
  33. return CompareNormalized(version1N, version2N, operator)
  34. }
  35. // Compares two normalizated version number strings, for a particular relationship
  36. //
  37. // The function first replaces _, - and + with a dot . in the version strings
  38. // and also inserts dots . before and after any non number so that for example
  39. // '4.3.2RC1' becomes '4.3.2.RC.1'.
  40. //
  41. // Then it splits the results like if you were using Split(version, '.').
  42. // Then it compares the parts starting from left to right. If a part contains
  43. // special version strings these are handled in the following order: any string
  44. // not found in this list:
  45. // < dev < alpha = a < beta = b < RC = rc < # < pl = p.
  46. //
  47. // Usage
  48. // version.CompareNormalized("1.0-dev", "1.0", "<")
  49. // Returns: true
  50. //
  51. // version.CompareNormalized("1.0rc1", "1.0", ">=")
  52. // Returns: false
  53. //
  54. // version.CompareNormalized("1.0", "1.0b1", "ge")
  55. // Returns: true
  56. func CompareNormalized(version1, version2, operator string) bool {
  57. compare := CompareSimple(version1, version2)
  58. switch {
  59. case operator == ">" || operator == "gt":
  60. return compare > 0
  61. case operator == ">=" || operator == "ge":
  62. return compare >= 0
  63. case operator == "<=" || operator == "le":
  64. return compare <= 0
  65. case operator == "==" || operator == "=" || operator == "eq":
  66. return compare == 0
  67. case operator == "<>" || operator == "!=" || operator == "ne":
  68. return compare != 0
  69. case operator == "" || operator == "<" || operator == "lt":
  70. return compare < 0
  71. }
  72. return false
  73. }
  74. // Compares two normalizated version number strings
  75. //
  76. // Just the same of CompareVersion but return a int result, 0 if both version
  77. // are equal, 1 if the right side is bigger and -1 if the right side is lower
  78. //
  79. // Usage
  80. // version.CompareSimple("1.2", "1.0.1")
  81. // Returns: 1
  82. //
  83. // version.CompareSimple("1.0rc1", "1.0")
  84. // Returns: -1
  85. func CompareSimple(version1, version2 string) int {
  86. var x, r, l int = 0, 0, 0
  87. v1, v2 := prepVersion(version1), prepVersion(version2)
  88. len1, len2 := len(v1), len(v2)
  89. if len1 > len2 {
  90. x = len1
  91. } else {
  92. x = len2
  93. }
  94. for i := 0; i < x; i++ {
  95. if i < len1 && i < len2 {
  96. if v1[i] == v2[i] {
  97. continue
  98. }
  99. }
  100. r = 0
  101. if i < len1 {
  102. r = numVersion(v1[i])
  103. }
  104. l = 0
  105. if i < len2 {
  106. l = numVersion(v2[i])
  107. }
  108. if r < l {
  109. return -1
  110. } else if r > l {
  111. return 1
  112. }
  113. }
  114. return 0
  115. }
  116. func prepVersion(version string) []string {
  117. if len(version) == 0 {
  118. return []string{""}
  119. }
  120. version = regexpSigns.ReplaceAllString(version, ".")
  121. version = regexpDotBeforeDigit.ReplaceAllString(version, ".$1.")
  122. version = regexpMultipleDots.ReplaceAllString(version, ".")
  123. return strings.Split(version, ".")
  124. }
  125. func numVersion(value string) int {
  126. if value == "" {
  127. return 0
  128. }
  129. if number, err := strconv.Atoi(value); err == nil {
  130. return number
  131. }
  132. if special, ok := specialForms[value]; ok {
  133. return special
  134. }
  135. return -7
  136. }