gitea源码

vercmp.go 1.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. // Copyright 2025 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package arch
  4. import (
  5. "strconv"
  6. "strings"
  7. "unicode"
  8. )
  9. // https://gitlab.archlinux.org/pacman/pacman/-/blob/d55b47e5512808b67bc944feb20c2bcc6c1a4c45/lib/libalpm/version.c
  10. func parseEVR(evr string) (epoch, version, release string) {
  11. if before, after, f := strings.Cut(evr, ":"); f {
  12. epoch = before
  13. evr = after
  14. } else {
  15. epoch = "0"
  16. }
  17. if before, after, f := strings.Cut(evr, "-"); f {
  18. version = before
  19. release = after
  20. } else {
  21. version = evr
  22. release = "1"
  23. }
  24. return epoch, version, release
  25. }
  26. func compareSegments(a, b []string) int {
  27. lenA, lenB := len(a), len(b)
  28. l := min(lenA, lenB)
  29. for i := range l {
  30. if r := compare(a[i], b[i]); r != 0 {
  31. return r
  32. }
  33. }
  34. if lenA == lenB {
  35. return 0
  36. } else if l == lenA {
  37. return -1
  38. }
  39. return 1
  40. }
  41. func compare(a, b string) int {
  42. if a == b {
  43. return 0
  44. }
  45. aNumeric := isNumeric(a)
  46. bNumeric := isNumeric(b)
  47. if aNumeric && bNumeric {
  48. aInt, _ := strconv.Atoi(a)
  49. bInt, _ := strconv.Atoi(b)
  50. switch {
  51. case aInt < bInt:
  52. return -1
  53. case aInt > bInt:
  54. return 1
  55. default:
  56. return 0
  57. }
  58. }
  59. if aNumeric {
  60. return 1
  61. }
  62. if bNumeric {
  63. return -1
  64. }
  65. return strings.Compare(a, b)
  66. }
  67. func isNumeric(s string) bool {
  68. for _, c := range s {
  69. if !unicode.IsDigit(c) {
  70. return false
  71. }
  72. }
  73. return true
  74. }
  75. func compareVersions(a, b string) int {
  76. if a == b {
  77. return 0
  78. }
  79. epochA, versionA, releaseA := parseEVR(a)
  80. epochB, versionB, releaseB := parseEVR(b)
  81. if res := compareSegments([]string{epochA}, []string{epochB}); res != 0 {
  82. return res
  83. }
  84. if res := compareSegments(strings.Split(versionA, "."), strings.Split(versionB, ".")); res != 0 {
  85. return res
  86. }
  87. return compareSegments([]string{releaseA}, []string{releaseB})
  88. }