- RegistryAPIPath, RegistryPlugin, RegistryPluginDetail, RegistryVersion, envelopes, errors, ingest types - ValidVersion, CompareVersions, BaseVersion, Satisfies, NewestCompatible - docs: Registry API v1 reference in plugins/marketplace.md
106 lines
3.0 KiB
Go
106 lines
3.0 KiB
Go
package kiosk
|
|
|
|
import (
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
var (
|
|
validVersionRe = regexp.MustCompile(`^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$`)
|
|
describeRe = regexp.MustCompile(`^(v(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*))(?:-[0-9]+-g[0-9a-f]+)?$`)
|
|
pseudoBaseRe = regexp.MustCompile(`^(v[0-9]+\.[0-9]+\.[0-9]+)-`)
|
|
)
|
|
|
|
// ValidVersion reports whether v is a release version in the strict form
|
|
// vX.Y.Z: no pre-release, no build metadata, no leading zeros.
|
|
func ValidVersion(v string) bool {
|
|
return validVersionRe.MatchString(v)
|
|
}
|
|
|
|
// CompareVersions compares two valid versions numerically per component
|
|
// and returns -1, 0 or +1. It is only defined for versions ValidVersion
|
|
// accepts; never pass a git describe string (use BaseVersion first).
|
|
func CompareVersions(a, b string) int {
|
|
pa := strings.Split(strings.TrimPrefix(a, "v"), ".")
|
|
pb := strings.Split(strings.TrimPrefix(b, "v"), ".")
|
|
for i := 0; i < len(pa) && i < len(pb); i++ {
|
|
if c := compareNumeric(pa[i], pb[i]); c != 0 {
|
|
return c
|
|
}
|
|
}
|
|
switch {
|
|
case len(pa) < len(pb):
|
|
return -1
|
|
case len(pa) > len(pb):
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// compareNumeric compares two decimal strings without leading zeros, of
|
|
// any length.
|
|
func compareNumeric(a, b string) int {
|
|
switch {
|
|
case len(a) != len(b):
|
|
if len(a) < len(b) {
|
|
return -1
|
|
}
|
|
return 1
|
|
case a < b:
|
|
return -1
|
|
case a > b:
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// BaseVersion returns the vX.Y.Z tag a `git describe --tags` string starts
|
|
// from: "v0.3.1" for "v0.3.1" and for "v0.3.1-4-gabc1234". Anything else
|
|
// (a bare commit hash, an empty string, a pre-release tag) gives "".
|
|
func BaseVersion(describe string) string {
|
|
m := describeRe.FindStringSubmatch(describe)
|
|
if m == nil {
|
|
return ""
|
|
}
|
|
return m[1]
|
|
}
|
|
|
|
// Satisfies reports whether the release have meets the minimum min. An
|
|
// empty minimum is always met. A pseudo-version minimum such as
|
|
// vX.Y.Z-0.<timestamp>-<hash> sorts just below vX.Y.Z, so it is met by
|
|
// vX.Y.Z and later. have must be a valid release; anything else meets
|
|
// only the empty minimum.
|
|
func Satisfies(have, min string) bool {
|
|
if min == "" {
|
|
return true
|
|
}
|
|
if !ValidVersion(have) {
|
|
return false
|
|
}
|
|
if ValidVersion(min) {
|
|
return CompareVersions(have, min) >= 0
|
|
}
|
|
if isPseudoVersion(min) {
|
|
base := pseudoBaseRe.FindStringSubmatch(min)
|
|
return base != nil && ValidVersion(base[1]) && CompareVersions(have, base[1]) >= 0
|
|
}
|
|
return false
|
|
}
|
|
|
|
// NewestCompatible returns the newest release in versions whose framework
|
|
// minimum the given framework version satisfies, and false when there is
|
|
// none. Entries whose Version is not a valid release are skipped.
|
|
func NewestCompatible(versions []RegistryVersion, framework string) (RegistryVersion, bool) {
|
|
var best RegistryVersion
|
|
found := false
|
|
for _, v := range versions {
|
|
if !ValidVersion(v.Version) || !Satisfies(framework, v.Framework) {
|
|
continue
|
|
}
|
|
if !found || CompareVersions(v.Version, best.Version) > 0 {
|
|
best, found = v, true
|
|
}
|
|
}
|
|
return best, found
|
|
}
|