102 lines
2.0 KiB
Go
102 lines
2.0 KiB
Go
package update
|
|
|
|
import (
|
|
"cmp"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type Version struct {
|
|
numbers []int
|
|
pre []string
|
|
}
|
|
|
|
func ParseVersion(raw string) (Version, error) {
|
|
trimmed := strings.TrimPrefix(strings.TrimSpace(raw), "v")
|
|
core, pre, hasPre := strings.Cut(trimmed, "-")
|
|
if core == "" || (hasPre && pre == "") {
|
|
return Version{}, ErrInvalidVersion
|
|
}
|
|
var version Version
|
|
for _, segment := range strings.Split(core, ".") {
|
|
number, err := strconv.Atoi(segment)
|
|
if err != nil || number < 0 {
|
|
return Version{}, ErrInvalidVersion
|
|
}
|
|
version.numbers = append(version.numbers, number)
|
|
}
|
|
if hasPre {
|
|
version.pre = strings.Split(pre, ".")
|
|
}
|
|
return version, nil
|
|
}
|
|
|
|
func IsNewer(current, latest string) bool {
|
|
currentVersion, err := ParseVersion(current)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
latestVersion, err := ParseVersion(latest)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
return compareVersions(latestVersion, currentVersion) > 0
|
|
}
|
|
|
|
func compareVersions(a, b Version) int {
|
|
if order := compareNumbers(a.numbers, b.numbers); order != 0 {
|
|
return order
|
|
}
|
|
return comparePreRelease(a.pre, b.pre)
|
|
}
|
|
|
|
func compareNumbers(a, b []int) int {
|
|
for i := range max(len(a), len(b)) {
|
|
if order := cmp.Compare(segmentAt(a, i), segmentAt(b, i)); order != 0 {
|
|
return order
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func segmentAt(numbers []int, index int) int {
|
|
if index < len(numbers) {
|
|
return numbers[index]
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func comparePreRelease(a, b []string) int {
|
|
if len(a) == 0 && len(b) == 0 {
|
|
return 0
|
|
}
|
|
if len(a) == 0 {
|
|
return 1
|
|
}
|
|
if len(b) == 0 {
|
|
return -1
|
|
}
|
|
length := min(len(a), len(b))
|
|
for i := 0; i < length; i++ {
|
|
if order := compareIdentifiers(a[i], b[i]); order != 0 {
|
|
return order
|
|
}
|
|
}
|
|
return cmp.Compare(len(a), len(b))
|
|
}
|
|
|
|
func compareIdentifiers(a, b string) int {
|
|
numberA, errA := strconv.Atoi(a)
|
|
numberB, errB := strconv.Atoi(b)
|
|
if errA == nil && errB == nil {
|
|
return cmp.Compare(numberA, numberB)
|
|
}
|
|
if errA == nil {
|
|
return -1
|
|
}
|
|
if errB == nil {
|
|
return 1
|
|
}
|
|
return strings.Compare(a, b)
|
|
}
|