upgrade_common.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. // Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
  2. // All rights reserved. Use of this source code is governed by an MIT-style
  3. // license that can be found in the LICENSE file.
  4. // Package upgrade downloads and compares releases, and upgrades the running binary.
  5. package upgrade
  6. import (
  7. "errors"
  8. "strconv"
  9. "strings"
  10. )
  11. type Release struct {
  12. Tag string `json:"tag_name"`
  13. Prerelease bool `json:"prerelease"`
  14. Assets []Asset `json:"assets"`
  15. }
  16. type Asset struct {
  17. URL string `json:"url"`
  18. Name string `json:"name"`
  19. }
  20. var (
  21. ErrVersionUpToDate = errors.New("current version is up to date")
  22. ErrVersionUnknown = errors.New("couldn't fetch release information")
  23. ErrUpgradeUnsupported = errors.New("upgrade unsupported")
  24. )
  25. // Returns 1 if a>b, -1 if a<b and 0 if they are equal
  26. func CompareVersions(a, b string) int {
  27. arel, apre := versionParts(a)
  28. brel, bpre := versionParts(b)
  29. minlen := len(arel)
  30. if l := len(brel); l < minlen {
  31. minlen = l
  32. }
  33. // First compare major-minor-patch versions
  34. for i := 0; i < minlen; i++ {
  35. if arel[i] < brel[i] {
  36. return -1
  37. }
  38. if arel[i] > brel[i] {
  39. return 1
  40. }
  41. }
  42. // Longer version is newer, when the preceding parts are equal
  43. if len(arel) < len(brel) {
  44. return -1
  45. }
  46. if len(arel) > len(brel) {
  47. return 1
  48. }
  49. // Prerelease versions are older, if the versions are the same
  50. if len(apre) == 0 && len(bpre) > 0 {
  51. return 1
  52. }
  53. if len(apre) > 0 && len(bpre) == 0 {
  54. return -1
  55. }
  56. minlen = len(apre)
  57. if l := len(bpre); l < minlen {
  58. minlen = l
  59. }
  60. // Compare prerelease strings
  61. for i := 0; i < minlen; i++ {
  62. switch av := apre[i].(type) {
  63. case int:
  64. switch bv := bpre[i].(type) {
  65. case int:
  66. if av < bv {
  67. return -1
  68. }
  69. if av > bv {
  70. return 1
  71. }
  72. case string:
  73. return -1
  74. }
  75. case string:
  76. switch bv := bpre[i].(type) {
  77. case int:
  78. return 1
  79. case string:
  80. if av < bv {
  81. return -1
  82. }
  83. if av > bv {
  84. return 1
  85. }
  86. }
  87. }
  88. }
  89. // If all else is equal, longer prerelease string is newer
  90. if len(apre) < len(bpre) {
  91. return -1
  92. }
  93. if len(apre) > len(bpre) {
  94. return 1
  95. }
  96. // Looks like they're actually the same
  97. return 0
  98. }
  99. // Split a version into parts.
  100. // "1.2.3-beta.2" -> []int{1, 2, 3}, []interface{}{"beta", 2}
  101. func versionParts(v string) ([]int, []interface{}) {
  102. parts := strings.SplitN(v, "+", 2)
  103. parts = strings.SplitN(parts[0], "-", 2)
  104. fields := strings.Split(parts[0], ".")
  105. release := make([]int, len(fields))
  106. for i, s := range fields {
  107. v, _ := strconv.Atoi(s)
  108. release[i] = v
  109. }
  110. var prerelease []interface{}
  111. if len(parts) > 1 {
  112. fields = strings.Split(parts[1], ".")
  113. prerelease = make([]interface{}, len(fields))
  114. for i, s := range fields {
  115. v, err := strconv.Atoi(s)
  116. if err == nil {
  117. prerelease[i] = v
  118. } else {
  119. prerelease[i] = s
  120. }
  121. }
  122. }
  123. return release, prerelease
  124. }