Stable APIs for Go. https://go.code.as
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.

121 lines
2.7 KiB

  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, Minor, Patch int
  9. }
  10. func (v Version) String() string {
  11. if v.Major < 0 {
  12. panic(fmt.Sprintf("cannot stringify invalid version (major is %d)", v.Major))
  13. }
  14. if v.Minor < 0 {
  15. return fmt.Sprintf("v%d", v.Major)
  16. }
  17. if v.Patch < 0 {
  18. return fmt.Sprintf("v%d.%d", v.Major, v.Minor)
  19. }
  20. return fmt.Sprintf("v%d.%d.%d", v.Major, v.Minor, v.Patch)
  21. }
  22. // Less returns whether v is less than other.
  23. func (v Version) Less(other Version) bool {
  24. if v.Major != other.Major {
  25. return v.Major < other.Major
  26. }
  27. if v.Minor != other.Minor {
  28. return v.Minor < other.Minor
  29. }
  30. return v.Patch < other.Patch
  31. }
  32. // Contains returns whether version v contains version other.
  33. // Version v is defined to contain version other when they both have the same Major
  34. // version and v.Minor and v.Patch are either undefined or are equal to other's.
  35. //
  36. // For example, Version{1, 1, -1} contains both Version{1, 1, -1} and Version{1, 1, 2},
  37. // but not Version{1, -1, -1} or Version{1, 2, -1}.
  38. func (v Version) Contains(other Version) bool {
  39. if v.Patch != -1 {
  40. return v == other
  41. }
  42. if v.Minor != -1 {
  43. return v.Major == other.Major && v.Minor == other.Minor
  44. }
  45. return v.Major == other.Major
  46. }
  47. func (v Version) IsValid() bool {
  48. return v != InvalidVersion
  49. }
  50. // InvalidVersion represents a version that can't be parsed.
  51. var InvalidVersion = Version{-1, -1, -1}
  52. func parseVersion(s string) (Version, bool) {
  53. if len(s) < 2 {
  54. return InvalidVersion, false
  55. }
  56. if s[0] != 'v' {
  57. return InvalidVersion, false
  58. }
  59. v := Version{-1, -1, -1}
  60. i := 1
  61. v.Major, i = parseVersionPart(s, i)
  62. if i < 0 {
  63. return InvalidVersion, false
  64. }
  65. if i == len(s) {
  66. return v, true
  67. }
  68. v.Minor, i = parseVersionPart(s, i)
  69. if i < 0 {
  70. return InvalidVersion, false
  71. }
  72. if i == len(s) {
  73. return v, true
  74. }
  75. v.Patch, i = parseVersionPart(s, i)
  76. if i < 0 || i < len(s) {
  77. return InvalidVersion, false
  78. }
  79. return v, true
  80. }
  81. func parseVersionPart(s string, i int) (part int, newi int) {
  82. dot := i
  83. for dot < len(s) && s[dot] != '.' {
  84. dot++
  85. }
  86. if dot == i || dot-i > 1 && s[i] == '0' {
  87. return -1, -1
  88. }
  89. for i < len(s) {
  90. if s[i] < '0' || s[i] > '9' {
  91. return -1, -1
  92. }
  93. part *= 10
  94. part += int(s[i] - '0')
  95. if part < 0 {
  96. return -1, -1
  97. }
  98. i++
  99. if i+1 < len(s) && s[i] == '.' {
  100. return part, i + 1
  101. }
  102. }
  103. return part, i
  104. }
  105. // VersionList implements sort.Interface
  106. type VersionList []Version
  107. func (vl VersionList) Len() int { return len(vl) }
  108. func (vl VersionList) Less(i, j int) bool { return vl[i].Less(vl[j]) }
  109. func (vl VersionList) Swap(i, j int) { vl[i], vl[j] = vl[j], vl[i] }