version.go 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. package version
  2. import (
  3. "bytes"
  4. "fmt"
  5. "reflect"
  6. "regexp"
  7. "strconv"
  8. "strings"
  9. )
  10. // The compiled regular expression used to test the validity of a version.
  11. var versionRegexp *regexp.Regexp
  12. // The raw regular expression string used for testing the validity
  13. // of a version.
  14. const VersionRegexpRaw string = `v?([0-9]+(\.[0-9]+)*?)` +
  15. `(-([0-9]+[0-9A-Za-z\-~]*(\.[0-9A-Za-z\-~]+)*)|(-?([A-Za-z\-~]+[0-9A-Za-z\-~]*(\.[0-9A-Za-z\-~]+)*)))?` +
  16. `(\+([0-9A-Za-z\-~]+(\.[0-9A-Za-z\-~]+)*))?` +
  17. `?`
  18. // Version represents a single version.
  19. type Version struct {
  20. metadata string
  21. pre string
  22. segments []int64
  23. si int
  24. original string
  25. }
  26. func init() {
  27. versionRegexp = regexp.MustCompile("^" + VersionRegexpRaw + "$")
  28. }
  29. // NewVersion parses the given version and returns a new
  30. // Version.
  31. func NewVersion(v string) (*Version, error) {
  32. matches := versionRegexp.FindStringSubmatch(v)
  33. if matches == nil {
  34. return nil, fmt.Errorf("Malformed version: %s", v)
  35. }
  36. segmentsStr := strings.Split(matches[1], ".")
  37. segments := make([]int64, len(segmentsStr))
  38. si := 0
  39. for i, str := range segmentsStr {
  40. val, err := strconv.ParseInt(str, 10, 64)
  41. if err != nil {
  42. return nil, fmt.Errorf(
  43. "Error parsing version: %s", err)
  44. }
  45. segments[i] = int64(val)
  46. si++
  47. }
  48. // Even though we could support more than three segments, if we
  49. // got less than three, pad it with 0s. This is to cover the basic
  50. // default usecase of semver, which is MAJOR.MINOR.PATCH at the minimum
  51. for i := len(segments); i < 3; i++ {
  52. segments = append(segments, 0)
  53. }
  54. pre := matches[7]
  55. if pre == "" {
  56. pre = matches[4]
  57. }
  58. return &Version{
  59. metadata: matches[10],
  60. pre: pre,
  61. segments: segments,
  62. si: si,
  63. original: v,
  64. }, nil
  65. }
  66. // Must is a helper that wraps a call to a function returning (*Version, error)
  67. // and panics if error is non-nil.
  68. func Must(v *Version, err error) *Version {
  69. if err != nil {
  70. panic(err)
  71. }
  72. return v
  73. }
  74. // Compare compares this version to another version. This
  75. // returns -1, 0, or 1 if this version is smaller, equal,
  76. // or larger than the other version, respectively.
  77. //
  78. // If you want boolean results, use the LessThan, Equal,
  79. // or GreaterThan methods.
  80. func (v *Version) Compare(other *Version) int {
  81. // A quick, efficient equality check
  82. if v.String() == other.String() {
  83. return 0
  84. }
  85. segmentsSelf := v.Segments64()
  86. segmentsOther := other.Segments64()
  87. // If the segments are the same, we must compare on prerelease info
  88. if reflect.DeepEqual(segmentsSelf, segmentsOther) {
  89. preSelf := v.Prerelease()
  90. preOther := other.Prerelease()
  91. if preSelf == "" && preOther == "" {
  92. return 0
  93. }
  94. if preSelf == "" {
  95. return 1
  96. }
  97. if preOther == "" {
  98. return -1
  99. }
  100. return comparePrereleases(preSelf, preOther)
  101. }
  102. // Get the highest specificity (hS), or if they're equal, just use segmentSelf length
  103. lenSelf := len(segmentsSelf)
  104. lenOther := len(segmentsOther)
  105. hS := lenSelf
  106. if lenSelf < lenOther {
  107. hS = lenOther
  108. }
  109. // Compare the segments
  110. // Because a constraint could have more/less specificity than the version it's
  111. // checking, we need to account for a lopsided or jagged comparison
  112. for i := 0; i < hS; i++ {
  113. if i > lenSelf-1 {
  114. // This means Self had the lower specificity
  115. // Check to see if the remaining segments in Other are all zeros
  116. if !allZero(segmentsOther[i:]) {
  117. // if not, it means that Other has to be greater than Self
  118. return -1
  119. }
  120. break
  121. } else if i > lenOther-1 {
  122. // this means Other had the lower specificity
  123. // Check to see if the remaining segments in Self are all zeros -
  124. if !allZero(segmentsSelf[i:]) {
  125. //if not, it means that Self has to be greater than Other
  126. return 1
  127. }
  128. break
  129. }
  130. lhs := segmentsSelf[i]
  131. rhs := segmentsOther[i]
  132. if lhs == rhs {
  133. continue
  134. } else if lhs < rhs {
  135. return -1
  136. }
  137. // Otherwis, rhs was > lhs, they're not equal
  138. return 1
  139. }
  140. // if we got this far, they're equal
  141. return 0
  142. }
  143. func allZero(segs []int64) bool {
  144. for _, s := range segs {
  145. if s != 0 {
  146. return false
  147. }
  148. }
  149. return true
  150. }
  151. func comparePart(preSelf string, preOther string) int {
  152. if preSelf == preOther {
  153. return 0
  154. }
  155. var selfInt int64
  156. selfNumeric := true
  157. selfInt, err := strconv.ParseInt(preSelf, 10, 64)
  158. if err != nil {
  159. selfNumeric = false
  160. }
  161. var otherInt int64
  162. otherNumeric := true
  163. otherInt, err = strconv.ParseInt(preOther, 10, 64)
  164. if err != nil {
  165. otherNumeric = false
  166. }
  167. // if a part is empty, we use the other to decide
  168. if preSelf == "" {
  169. if otherNumeric {
  170. return -1
  171. }
  172. return 1
  173. }
  174. if preOther == "" {
  175. if selfNumeric {
  176. return 1
  177. }
  178. return -1
  179. }
  180. if selfNumeric && !otherNumeric {
  181. return -1
  182. } else if !selfNumeric && otherNumeric {
  183. return 1
  184. } else if !selfNumeric && !otherNumeric && preSelf > preOther {
  185. return 1
  186. } else if selfInt > otherInt {
  187. return 1
  188. }
  189. return -1
  190. }
  191. func comparePrereleases(v string, other string) int {
  192. // the same pre release!
  193. if v == other {
  194. return 0
  195. }
  196. // split both pre releases for analyse their parts
  197. selfPreReleaseMeta := strings.Split(v, ".")
  198. otherPreReleaseMeta := strings.Split(other, ".")
  199. selfPreReleaseLen := len(selfPreReleaseMeta)
  200. otherPreReleaseLen := len(otherPreReleaseMeta)
  201. biggestLen := otherPreReleaseLen
  202. if selfPreReleaseLen > otherPreReleaseLen {
  203. biggestLen = selfPreReleaseLen
  204. }
  205. // loop for parts to find the first difference
  206. for i := 0; i < biggestLen; i = i + 1 {
  207. partSelfPre := ""
  208. if i < selfPreReleaseLen {
  209. partSelfPre = selfPreReleaseMeta[i]
  210. }
  211. partOtherPre := ""
  212. if i < otherPreReleaseLen {
  213. partOtherPre = otherPreReleaseMeta[i]
  214. }
  215. compare := comparePart(partSelfPre, partOtherPre)
  216. // if parts are equals, continue the loop
  217. if compare != 0 {
  218. return compare
  219. }
  220. }
  221. return 0
  222. }
  223. // Equal tests if two versions are equal.
  224. func (v *Version) Equal(o *Version) bool {
  225. return v.Compare(o) == 0
  226. }
  227. // GreaterThan tests if this version is greater than another version.
  228. func (v *Version) GreaterThan(o *Version) bool {
  229. return v.Compare(o) > 0
  230. }
  231. // LessThan tests if this version is less than another version.
  232. func (v *Version) LessThan(o *Version) bool {
  233. return v.Compare(o) < 0
  234. }
  235. // Metadata returns any metadata that was part of the version
  236. // string.
  237. //
  238. // Metadata is anything that comes after the "+" in the version.
  239. // For example, with "1.2.3+beta", the metadata is "beta".
  240. func (v *Version) Metadata() string {
  241. return v.metadata
  242. }
  243. // Prerelease returns any prerelease data that is part of the version,
  244. // or blank if there is no prerelease data.
  245. //
  246. // Prerelease information is anything that comes after the "-" in the
  247. // version (but before any metadata). For example, with "1.2.3-beta",
  248. // the prerelease information is "beta".
  249. func (v *Version) Prerelease() string {
  250. return v.pre
  251. }
  252. // Segments returns the numeric segments of the version as a slice of ints.
  253. //
  254. // This excludes any metadata or pre-release information. For example,
  255. // for a version "1.2.3-beta", segments will return a slice of
  256. // 1, 2, 3.
  257. func (v *Version) Segments() []int {
  258. segmentSlice := make([]int, len(v.segments))
  259. for i, v := range v.segments {
  260. segmentSlice[i] = int(v)
  261. }
  262. return segmentSlice
  263. }
  264. // Segments64 returns the numeric segments of the version as a slice of int64s.
  265. //
  266. // This excludes any metadata or pre-release information. For example,
  267. // for a version "1.2.3-beta", segments will return a slice of
  268. // 1, 2, 3.
  269. func (v *Version) Segments64() []int64 {
  270. result := make([]int64, len(v.segments))
  271. copy(result, v.segments)
  272. return result
  273. }
  274. // String returns the full version string included pre-release
  275. // and metadata information.
  276. //
  277. // This value is rebuilt according to the parsed segments and other
  278. // information. Therefore, ambiguities in the version string such as
  279. // prefixed zeroes (1.04.0 => 1.4.0), `v` prefix (v1.0.0 => 1.0.0), and
  280. // missing parts (1.0 => 1.0.0) will be made into a canonicalized form
  281. // as shown in the parenthesized examples.
  282. func (v *Version) String() string {
  283. var buf bytes.Buffer
  284. fmtParts := make([]string, len(v.segments))
  285. for i, s := range v.segments {
  286. // We can ignore err here since we've pre-parsed the values in segments
  287. str := strconv.FormatInt(s, 10)
  288. fmtParts[i] = str
  289. }
  290. fmt.Fprintf(&buf, strings.Join(fmtParts, "."))
  291. if v.pre != "" {
  292. fmt.Fprintf(&buf, "-%s", v.pre)
  293. }
  294. if v.metadata != "" {
  295. fmt.Fprintf(&buf, "+%s", v.metadata)
  296. }
  297. return buf.String()
  298. }
  299. // Original returns the original parsed version as-is, including any
  300. // potential whitespace, `v` prefix, etc.
  301. func (v *Version) Original() string {
  302. return v.original
  303. }