mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-11-04 07:49:35 +00:00 
			
		
		
		
	- add blkio as an optionally required cgroup - update blang/semver to v4 - bump the min go version to 1.16
		
			
				
	
	
		
			417 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			417 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package semver
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"strconv"
 | 
						|
	"strings"
 | 
						|
	"unicode"
 | 
						|
)
 | 
						|
 | 
						|
type wildcardType int
 | 
						|
 | 
						|
const (
 | 
						|
	noneWildcard  wildcardType = iota
 | 
						|
	majorWildcard wildcardType = 1
 | 
						|
	minorWildcard wildcardType = 2
 | 
						|
	patchWildcard wildcardType = 3
 | 
						|
)
 | 
						|
 | 
						|
func wildcardTypefromInt(i int) wildcardType {
 | 
						|
	switch i {
 | 
						|
	case 1:
 | 
						|
		return majorWildcard
 | 
						|
	case 2:
 | 
						|
		return minorWildcard
 | 
						|
	case 3:
 | 
						|
		return patchWildcard
 | 
						|
	default:
 | 
						|
		return noneWildcard
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
type comparator func(Version, Version) bool
 | 
						|
 | 
						|
var (
 | 
						|
	compEQ comparator = func(v1 Version, v2 Version) bool {
 | 
						|
		return v1.Compare(v2) == 0
 | 
						|
	}
 | 
						|
	compNE = func(v1 Version, v2 Version) bool {
 | 
						|
		return v1.Compare(v2) != 0
 | 
						|
	}
 | 
						|
	compGT = func(v1 Version, v2 Version) bool {
 | 
						|
		return v1.Compare(v2) == 1
 | 
						|
	}
 | 
						|
	compGE = func(v1 Version, v2 Version) bool {
 | 
						|
		return v1.Compare(v2) >= 0
 | 
						|
	}
 | 
						|
	compLT = func(v1 Version, v2 Version) bool {
 | 
						|
		return v1.Compare(v2) == -1
 | 
						|
	}
 | 
						|
	compLE = func(v1 Version, v2 Version) bool {
 | 
						|
		return v1.Compare(v2) <= 0
 | 
						|
	}
 | 
						|
)
 | 
						|
 | 
						|
type versionRange struct {
 | 
						|
	v Version
 | 
						|
	c comparator
 | 
						|
}
 | 
						|
 | 
						|
// rangeFunc creates a Range from the given versionRange.
 | 
						|
func (vr *versionRange) rangeFunc() Range {
 | 
						|
	return Range(func(v Version) bool {
 | 
						|
		return vr.c(v, vr.v)
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
// Range represents a range of versions.
 | 
						|
// A Range can be used to check if a Version satisfies it:
 | 
						|
//
 | 
						|
//     range, err := semver.ParseRange(">1.0.0 <2.0.0")
 | 
						|
//     range(semver.MustParse("1.1.1") // returns true
 | 
						|
type Range func(Version) bool
 | 
						|
 | 
						|
// OR combines the existing Range with another Range using logical OR.
 | 
						|
func (rf Range) OR(f Range) Range {
 | 
						|
	return Range(func(v Version) bool {
 | 
						|
		return rf(v) || f(v)
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
// AND combines the existing Range with another Range using logical AND.
 | 
						|
func (rf Range) AND(f Range) Range {
 | 
						|
	return Range(func(v Version) bool {
 | 
						|
		return rf(v) && f(v)
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
// ParseRange parses a range and returns a Range.
 | 
						|
// If the range could not be parsed an error is returned.
 | 
						|
//
 | 
						|
// Valid ranges are:
 | 
						|
//   - "<1.0.0"
 | 
						|
//   - "<=1.0.0"
 | 
						|
//   - ">1.0.0"
 | 
						|
//   - ">=1.0.0"
 | 
						|
//   - "1.0.0", "=1.0.0", "==1.0.0"
 | 
						|
//   - "!1.0.0", "!=1.0.0"
 | 
						|
//
 | 
						|
// A Range can consist of multiple ranges separated by space:
 | 
						|
// Ranges can be linked by logical AND:
 | 
						|
//   - ">1.0.0 <2.0.0" would match between both ranges, so "1.1.1" and "1.8.7" but not "1.0.0" or "2.0.0"
 | 
						|
//   - ">1.0.0 <3.0.0 !2.0.3-beta.2" would match every version between 1.0.0 and 3.0.0 except 2.0.3-beta.2
 | 
						|
//
 | 
						|
// Ranges can also be linked by logical OR:
 | 
						|
//   - "<2.0.0 || >=3.0.0" would match "1.x.x" and "3.x.x" but not "2.x.x"
 | 
						|
//
 | 
						|
// AND has a higher precedence than OR. It's not possible to use brackets.
 | 
						|
//
 | 
						|
// Ranges can be combined by both AND and OR
 | 
						|
//
 | 
						|
//  - `>1.0.0 <2.0.0 || >3.0.0 !4.2.1` would match `1.2.3`, `1.9.9`, `3.1.1`, but not `4.2.1`, `2.1.1`
 | 
						|
func ParseRange(s string) (Range, error) {
 | 
						|
	parts := splitAndTrim(s)
 | 
						|
	orParts, err := splitORParts(parts)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	expandedParts, err := expandWildcardVersion(orParts)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	var orFn Range
 | 
						|
	for _, p := range expandedParts {
 | 
						|
		var andFn Range
 | 
						|
		for _, ap := range p {
 | 
						|
			opStr, vStr, err := splitComparatorVersion(ap)
 | 
						|
			if err != nil {
 | 
						|
				return nil, err
 | 
						|
			}
 | 
						|
			vr, err := buildVersionRange(opStr, vStr)
 | 
						|
			if err != nil {
 | 
						|
				return nil, fmt.Errorf("Could not parse Range %q: %s", ap, err)
 | 
						|
			}
 | 
						|
			rf := vr.rangeFunc()
 | 
						|
 | 
						|
			// Set function
 | 
						|
			if andFn == nil {
 | 
						|
				andFn = rf
 | 
						|
			} else { // Combine with existing function
 | 
						|
				andFn = andFn.AND(rf)
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if orFn == nil {
 | 
						|
			orFn = andFn
 | 
						|
		} else {
 | 
						|
			orFn = orFn.OR(andFn)
 | 
						|
		}
 | 
						|
 | 
						|
	}
 | 
						|
	return orFn, nil
 | 
						|
}
 | 
						|
 | 
						|
// splitORParts splits the already cleaned parts by '||'.
 | 
						|
// Checks for invalid positions of the operator and returns an
 | 
						|
// error if found.
 | 
						|
func splitORParts(parts []string) ([][]string, error) {
 | 
						|
	var ORparts [][]string
 | 
						|
	last := 0
 | 
						|
	for i, p := range parts {
 | 
						|
		if p == "||" {
 | 
						|
			if i == 0 {
 | 
						|
				return nil, fmt.Errorf("First element in range is '||'")
 | 
						|
			}
 | 
						|
			ORparts = append(ORparts, parts[last:i])
 | 
						|
			last = i + 1
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if last == len(parts) {
 | 
						|
		return nil, fmt.Errorf("Last element in range is '||'")
 | 
						|
	}
 | 
						|
	ORparts = append(ORparts, parts[last:])
 | 
						|
	return ORparts, nil
 | 
						|
}
 | 
						|
 | 
						|
// buildVersionRange takes a slice of 2: operator and version
 | 
						|
// and builds a versionRange, otherwise an error.
 | 
						|
func buildVersionRange(opStr, vStr string) (*versionRange, error) {
 | 
						|
	c := parseComparator(opStr)
 | 
						|
	if c == nil {
 | 
						|
		return nil, fmt.Errorf("Could not parse comparator %q in %q", opStr, strings.Join([]string{opStr, vStr}, ""))
 | 
						|
	}
 | 
						|
	v, err := Parse(vStr)
 | 
						|
	if err != nil {
 | 
						|
		return nil, fmt.Errorf("Could not parse version %q in %q: %s", vStr, strings.Join([]string{opStr, vStr}, ""), err)
 | 
						|
	}
 | 
						|
 | 
						|
	return &versionRange{
 | 
						|
		v: v,
 | 
						|
		c: c,
 | 
						|
	}, nil
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
// inArray checks if a byte is contained in an array of bytes
 | 
						|
func inArray(s byte, list []byte) bool {
 | 
						|
	for _, el := range list {
 | 
						|
		if el == s {
 | 
						|
			return true
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return false
 | 
						|
}
 | 
						|
 | 
						|
// splitAndTrim splits a range string by spaces and cleans whitespaces
 | 
						|
func splitAndTrim(s string) (result []string) {
 | 
						|
	last := 0
 | 
						|
	var lastChar byte
 | 
						|
	excludeFromSplit := []byte{'>', '<', '='}
 | 
						|
	for i := 0; i < len(s); i++ {
 | 
						|
		if s[i] == ' ' && !inArray(lastChar, excludeFromSplit) {
 | 
						|
			if last < i-1 {
 | 
						|
				result = append(result, s[last:i])
 | 
						|
			}
 | 
						|
			last = i + 1
 | 
						|
		} else if s[i] != ' ' {
 | 
						|
			lastChar = s[i]
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if last < len(s)-1 {
 | 
						|
		result = append(result, s[last:])
 | 
						|
	}
 | 
						|
 | 
						|
	for i, v := range result {
 | 
						|
		result[i] = strings.Replace(v, " ", "", -1)
 | 
						|
	}
 | 
						|
 | 
						|
	// parts := strings.Split(s, " ")
 | 
						|
	// for _, x := range parts {
 | 
						|
	// 	if s := strings.TrimSpace(x); len(s) != 0 {
 | 
						|
	// 		result = append(result, s)
 | 
						|
	// 	}
 | 
						|
	// }
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
// splitComparatorVersion splits the comparator from the version.
 | 
						|
// Input must be free of leading or trailing spaces.
 | 
						|
func splitComparatorVersion(s string) (string, string, error) {
 | 
						|
	i := strings.IndexFunc(s, unicode.IsDigit)
 | 
						|
	if i == -1 {
 | 
						|
		return "", "", fmt.Errorf("Could not get version from string: %q", s)
 | 
						|
	}
 | 
						|
	return strings.TrimSpace(s[0:i]), s[i:], nil
 | 
						|
}
 | 
						|
 | 
						|
// getWildcardType will return the type of wildcard that the
 | 
						|
// passed version contains
 | 
						|
func getWildcardType(vStr string) wildcardType {
 | 
						|
	parts := strings.Split(vStr, ".")
 | 
						|
	nparts := len(parts)
 | 
						|
	wildcard := parts[nparts-1]
 | 
						|
 | 
						|
	possibleWildcardType := wildcardTypefromInt(nparts)
 | 
						|
	if wildcard == "x" {
 | 
						|
		return possibleWildcardType
 | 
						|
	}
 | 
						|
 | 
						|
	return noneWildcard
 | 
						|
}
 | 
						|
 | 
						|
// createVersionFromWildcard will convert a wildcard version
 | 
						|
// into a regular version, replacing 'x's with '0's, handling
 | 
						|
// special cases like '1.x.x' and '1.x'
 | 
						|
func createVersionFromWildcard(vStr string) string {
 | 
						|
	// handle 1.x.x
 | 
						|
	vStr2 := strings.Replace(vStr, ".x.x", ".x", 1)
 | 
						|
	vStr2 = strings.Replace(vStr2, ".x", ".0", 1)
 | 
						|
	parts := strings.Split(vStr2, ".")
 | 
						|
 | 
						|
	// handle 1.x
 | 
						|
	if len(parts) == 2 {
 | 
						|
		return vStr2 + ".0"
 | 
						|
	}
 | 
						|
 | 
						|
	return vStr2
 | 
						|
}
 | 
						|
 | 
						|
// incrementMajorVersion will increment the major version
 | 
						|
// of the passed version
 | 
						|
func incrementMajorVersion(vStr string) (string, error) {
 | 
						|
	parts := strings.Split(vStr, ".")
 | 
						|
	i, err := strconv.Atoi(parts[0])
 | 
						|
	if err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
	parts[0] = strconv.Itoa(i + 1)
 | 
						|
 | 
						|
	return strings.Join(parts, "."), nil
 | 
						|
}
 | 
						|
 | 
						|
// incrementMajorVersion will increment the minor version
 | 
						|
// of the passed version
 | 
						|
func incrementMinorVersion(vStr string) (string, error) {
 | 
						|
	parts := strings.Split(vStr, ".")
 | 
						|
	i, err := strconv.Atoi(parts[1])
 | 
						|
	if err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
	parts[1] = strconv.Itoa(i + 1)
 | 
						|
 | 
						|
	return strings.Join(parts, "."), nil
 | 
						|
}
 | 
						|
 | 
						|
// expandWildcardVersion will expand wildcards inside versions
 | 
						|
// following these rules:
 | 
						|
//
 | 
						|
// * when dealing with patch wildcards:
 | 
						|
// >= 1.2.x    will become    >= 1.2.0
 | 
						|
// <= 1.2.x    will become    <  1.3.0
 | 
						|
// >  1.2.x    will become    >= 1.3.0
 | 
						|
// <  1.2.x    will become    <  1.2.0
 | 
						|
// != 1.2.x    will become    <  1.2.0 >= 1.3.0
 | 
						|
//
 | 
						|
// * when dealing with minor wildcards:
 | 
						|
// >= 1.x      will become    >= 1.0.0
 | 
						|
// <= 1.x      will become    <  2.0.0
 | 
						|
// >  1.x      will become    >= 2.0.0
 | 
						|
// <  1.0      will become    <  1.0.0
 | 
						|
// != 1.x      will become    <  1.0.0 >= 2.0.0
 | 
						|
//
 | 
						|
// * when dealing with wildcards without
 | 
						|
// version operator:
 | 
						|
// 1.2.x       will become    >= 1.2.0 < 1.3.0
 | 
						|
// 1.x         will become    >= 1.0.0 < 2.0.0
 | 
						|
func expandWildcardVersion(parts [][]string) ([][]string, error) {
 | 
						|
	var expandedParts [][]string
 | 
						|
	for _, p := range parts {
 | 
						|
		var newParts []string
 | 
						|
		for _, ap := range p {
 | 
						|
			if strings.Contains(ap, "x") {
 | 
						|
				opStr, vStr, err := splitComparatorVersion(ap)
 | 
						|
				if err != nil {
 | 
						|
					return nil, err
 | 
						|
				}
 | 
						|
 | 
						|
				versionWildcardType := getWildcardType(vStr)
 | 
						|
				flatVersion := createVersionFromWildcard(vStr)
 | 
						|
 | 
						|
				var resultOperator string
 | 
						|
				var shouldIncrementVersion bool
 | 
						|
				switch opStr {
 | 
						|
				case ">":
 | 
						|
					resultOperator = ">="
 | 
						|
					shouldIncrementVersion = true
 | 
						|
				case ">=":
 | 
						|
					resultOperator = ">="
 | 
						|
				case "<":
 | 
						|
					resultOperator = "<"
 | 
						|
				case "<=":
 | 
						|
					resultOperator = "<"
 | 
						|
					shouldIncrementVersion = true
 | 
						|
				case "", "=", "==":
 | 
						|
					newParts = append(newParts, ">="+flatVersion)
 | 
						|
					resultOperator = "<"
 | 
						|
					shouldIncrementVersion = true
 | 
						|
				case "!=", "!":
 | 
						|
					newParts = append(newParts, "<"+flatVersion)
 | 
						|
					resultOperator = ">="
 | 
						|
					shouldIncrementVersion = true
 | 
						|
				}
 | 
						|
 | 
						|
				var resultVersion string
 | 
						|
				if shouldIncrementVersion {
 | 
						|
					switch versionWildcardType {
 | 
						|
					case patchWildcard:
 | 
						|
						resultVersion, _ = incrementMinorVersion(flatVersion)
 | 
						|
					case minorWildcard:
 | 
						|
						resultVersion, _ = incrementMajorVersion(flatVersion)
 | 
						|
					}
 | 
						|
				} else {
 | 
						|
					resultVersion = flatVersion
 | 
						|
				}
 | 
						|
 | 
						|
				ap = resultOperator + resultVersion
 | 
						|
			}
 | 
						|
			newParts = append(newParts, ap)
 | 
						|
		}
 | 
						|
		expandedParts = append(expandedParts, newParts)
 | 
						|
	}
 | 
						|
 | 
						|
	return expandedParts, nil
 | 
						|
}
 | 
						|
 | 
						|
func parseComparator(s string) comparator {
 | 
						|
	switch s {
 | 
						|
	case "==":
 | 
						|
		fallthrough
 | 
						|
	case "":
 | 
						|
		fallthrough
 | 
						|
	case "=":
 | 
						|
		return compEQ
 | 
						|
	case ">":
 | 
						|
		return compGT
 | 
						|
	case ">=":
 | 
						|
		return compGE
 | 
						|
	case "<":
 | 
						|
		return compLT
 | 
						|
	case "<=":
 | 
						|
		return compLE
 | 
						|
	case "!":
 | 
						|
		fallthrough
 | 
						|
	case "!=":
 | 
						|
		return compNE
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// MustParseRange is like ParseRange but panics if the range cannot be parsed.
 | 
						|
func MustParseRange(s string) Range {
 | 
						|
	r, err := ParseRange(s)
 | 
						|
	if err != nil {
 | 
						|
		panic(`semver: ParseRange(` + s + `): ` + err.Error())
 | 
						|
	}
 | 
						|
	return r
 | 
						|
}
 |