diff --git a/cmd/syncthing/upgrade_common.go b/cmd/syncthing/upgrade_common.go index 0d48b1402..68db47678 100644 --- a/cmd/syncthing/upgrade_common.go +++ b/cmd/syncthing/upgrade_common.go @@ -1,7 +1,6 @@ package main import ( - "bytes" "strconv" "strings" ) @@ -17,17 +16,114 @@ type githubAsset struct { Name string `json:"name"` } +// Returns 1 if a>b, -1 if a brel[i] { + return 1 + } + } + + // Longer version is newer, when the preceding parts are equal + if len(arel) < len(brel) { + return -1 + } + if len(arel) > len(brel) { + return 1 + } + + // Prerelease versions are older, if the versions are the same + if len(apre) == 0 && len(bpre) > 0 { + return 1 + } + if len(apre) > 0 && len(bpre) == 0 { + return -1 + } + + minlen = len(apre) + if l := len(bpre); l < minlen { + minlen = l + } + + // Compare prerelease strings + for i := 0; i < minlen; i++ { + switch av := apre[i].(type) { + case int: + switch bv := bpre[i].(type) { + case int: + if av < bv { + return -1 + } + if av > bv { + return 1 + } + case string: + return -1 + } + case string: + switch bv := bpre[i].(type) { + case int: + return 1 + case string: + if av < bv { + return -1 + } + if av > bv { + return 1 + } + } + } + } + + // If all else is equal, longer prerelease string is newer + if len(apre) < len(bpre) { + return -1 + } + if len(apre) > len(bpre) { + return 1 + } + + // Looks like they're actually the same + return 0 } -func versionParts(v string) []byte { - parts := strings.Split(v, "-") +// Split a version into parts. +// "1.2.3-beta.2" -> []int{1, 2, 3}, []interface{}{"beta", 2} +func versionParts(v string) ([]int, []interface{}) { + parts := strings.SplitN(v, "-", 2) fields := strings.Split(parts[0], ".") - res := make([]byte, len(fields)) + + release := make([]int, len(fields)) for i, s := range fields { v, _ := strconv.Atoi(s) - res[i] = byte(v) + release[i] = v } - return res + + var prerelease []interface{} + if len(parts) > 1 { + fields = strings.Split(parts[1], ".") + prerelease = make([]interface{}, len(fields)) + for i, s := range fields { + v, err := strconv.Atoi(s) + if err == nil { + prerelease[i] = v + } else { + prerelease[i] = s + } + } + } + + return release, prerelease } diff --git a/cmd/syncthing/upgrade_test.go b/cmd/syncthing/upgrade_test.go index 6bb2a86e4..ae7d8f6bb 100644 --- a/cmd/syncthing/upgrade_test.go +++ b/cmd/syncthing/upgrade_test.go @@ -20,6 +20,14 @@ var testcases = []struct { {"0.1.10", "0.1.9", 1}, {"0.10.0", "0.2.0", 1}, {"30.10.0", "4.9.0", 1}, + {"0.9.0-beta7", "0.9.0-beta6", 1}, + {"1.0.0-alpha", "1.0.0-alpha.1", -1}, + {"1.0.0-alpha.1", "1.0.0-alpha.beta", -1}, + {"1.0.0-alpha.beta", "1.0.0-beta", -1}, + {"1.0.0-beta", "1.0.0-beta.2", -1}, + {"1.0.0-beta.2", "1.0.0-beta.11", -1}, + {"1.0.0-beta.11", "1.0.0-rc.1", -1}, + {"1.0.0-rc.1", "1.0.0", -1}, } func TestCompareVersions(t *testing.T) {