Stable APIs for Go. https://go.code.as

version.go 3.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. package main
  2. import (
  3. "fmt"
  4. )
  5. // Version represents a version number.
  6. // An element that is not present is represented as -1.
  7. type Version struct {
  8. Major int
  9. Minor int
  10. Patch int
  11. Unstable bool
  12. }
  13. const unstableSuffix = "-unstable"
  14. func (v Version) String() string {
  15. if v.Major < 0 {
  16. panic(fmt.Sprintf("cannot stringify invalid version (major is %d)", v.Major))
  17. }
  18. suffix := ""
  19. if v.Unstable {
  20. suffix = unstableSuffix
  21. }
  22. if v.Minor < 0 {
  23. return fmt.Sprintf("v%d%s", v.Major, suffix)
  24. }
  25. if v.Patch < 0 {
  26. return fmt.Sprintf("v%d.%d%s", v.Major, v.Minor, suffix)
  27. }
  28. return fmt.Sprintf("v%d.%d.%d%s", v.Major, v.Minor, v.Patch, suffix)
  29. }
  30. // Less returns whether v is less than other.
  31. func (v Version) Less(other Version) bool {
  32. if v.Major != other.Major {
  33. return v.Major < other.Major
  34. }
  35. if v.Minor != other.Minor {
  36. return v.Minor < other.Minor
  37. }
  38. if v.Patch != other.Patch {
  39. return v.Patch < other.Patch
  40. }
  41. return v.Unstable && !other.Unstable
  42. }
  43. // Contains returns whether version v contains version other.
  44. // Version v is defined to contain version other when they both have the same Major
  45. // version and v.Minor and v.Patch are either undefined or are equal to other's.
  46. //
  47. // For example, Version{1, 1, -1} contains both Version{1, 1, -1} and Version{1, 1, 2},
  48. // but not Version{1, -1, -1} or Version{1, 2, -1}.
  49. //
  50. // Unstable versions (-unstable) only contain unstable versions, and stable
  51. // versions only contain stable versions.
  52. func (v Version) Contains(other Version) bool {
  53. if v.Unstable != other.Unstable {
  54. return false
  55. }
  56. if v.Patch != -1 {
  57. return v == other
  58. }
  59. if v.Minor != -1 {
  60. return v.Major == other.Major && v.Minor == other.Minor
  61. }
  62. return v.Major == other.Major
  63. }
  64. func (v Version) IsValid() bool {
  65. return v != InvalidVersion
  66. }
  67. // InvalidVersion represents a version that can't be parsed.
  68. var InvalidVersion = Version{-1, -1, -1, false}
  69. func parseVersion(s string) (v Version, ok bool) {
  70. v = InvalidVersion
  71. if len(s) < 2 {
  72. return
  73. }
  74. if s[0] != 'v' {
  75. return
  76. }
  77. vout := InvalidVersion
  78. unstable := false
  79. i := 1
  80. for _, vptr := range []*int{&vout.Major, &vout.Minor, &vout.Patch} {
  81. *vptr, unstable, i = parseVersionPart(s, i)
  82. if i < 0 {
  83. return
  84. }
  85. if i == len(s) {
  86. vout.Unstable = unstable
  87. return vout, true
  88. }
  89. }
  90. return
  91. }
  92. func parseVersionPart(s string, i int) (part int, unstable bool, newi int) {
  93. j := i
  94. for j < len(s) && s[j] != '.' && s[j] != '-' {
  95. j++
  96. }
  97. if j == i || j-i > 1 && s[i] == '0' {
  98. return -1, false, -1
  99. }
  100. c := s[i]
  101. for {
  102. if c < '0' || c > '9' {
  103. return -1, false, -1
  104. }
  105. part *= 10
  106. part += int(c - '0')
  107. if part < 0 {
  108. return -1, false, -1
  109. }
  110. i++
  111. if i == len(s) {
  112. return part, false, i
  113. }
  114. c = s[i]
  115. if i+1 < len(s) {
  116. if c == '.' {
  117. return part, false, i + 1
  118. }
  119. if c == '-' && s[i:] == unstableSuffix {
  120. return part, true, i + len(unstableSuffix)
  121. }
  122. }
  123. }
  124. panic("unreachable")
  125. }
  126. // VersionList implements sort.Interface
  127. type VersionList []Version
  128. func (vl VersionList) Len() int { return len(vl) }
  129. func (vl VersionList) Less(i, j int) bool { return vl[i].Less(vl[j]) }
  130. func (vl VersionList) Swap(i, j int) { vl[i], vl[j] = vl[j], vl[i] }