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.

compare.go 3.9KB

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