mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 08:02:36 +09:00 
			
		
		
		
	* vendor: switch from "mcuadros/go-version" to "hashicorp/go-version" * Adapt P1 * simplify * fix lint * adapt * fix lint & rm old code * no deadlock * rm RWMutex and check GoVersion only 1-time * Copyright header Co-authored-by: techknowlogick <techknowlogick@gitea.io>
		
			
				
	
	
		
			205 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
			
		
		
	
	
			205 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
package version
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"reflect"
 | 
						|
	"regexp"
 | 
						|
	"strings"
 | 
						|
)
 | 
						|
 | 
						|
// Constraint represents a single constraint for a version, such as
 | 
						|
// ">= 1.0".
 | 
						|
type Constraint struct {
 | 
						|
	f        constraintFunc
 | 
						|
	check    *Version
 | 
						|
	original string
 | 
						|
}
 | 
						|
 | 
						|
// Constraints is a slice of constraints. We make a custom type so that
 | 
						|
// we can add methods to it.
 | 
						|
type Constraints []*Constraint
 | 
						|
 | 
						|
type constraintFunc func(v, c *Version) bool
 | 
						|
 | 
						|
var constraintOperators map[string]constraintFunc
 | 
						|
 | 
						|
var constraintRegexp *regexp.Regexp
 | 
						|
 | 
						|
func init() {
 | 
						|
	constraintOperators = map[string]constraintFunc{
 | 
						|
		"":   constraintEqual,
 | 
						|
		"=":  constraintEqual,
 | 
						|
		"!=": constraintNotEqual,
 | 
						|
		">":  constraintGreaterThan,
 | 
						|
		"<":  constraintLessThan,
 | 
						|
		">=": constraintGreaterThanEqual,
 | 
						|
		"<=": constraintLessThanEqual,
 | 
						|
		"~>": constraintPessimistic,
 | 
						|
	}
 | 
						|
 | 
						|
	ops := make([]string, 0, len(constraintOperators))
 | 
						|
	for k := range constraintOperators {
 | 
						|
		ops = append(ops, regexp.QuoteMeta(k))
 | 
						|
	}
 | 
						|
 | 
						|
	constraintRegexp = regexp.MustCompile(fmt.Sprintf(
 | 
						|
		`^\s*(%s)\s*(%s)\s*$`,
 | 
						|
		strings.Join(ops, "|"),
 | 
						|
		VersionRegexpRaw))
 | 
						|
}
 | 
						|
 | 
						|
// NewConstraint will parse one or more constraints from the given
 | 
						|
// constraint string. The string must be a comma-separated list of
 | 
						|
// constraints.
 | 
						|
func NewConstraint(v string) (Constraints, error) {
 | 
						|
	vs := strings.Split(v, ",")
 | 
						|
	result := make([]*Constraint, len(vs))
 | 
						|
	for i, single := range vs {
 | 
						|
		c, err := parseSingle(single)
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
 | 
						|
		result[i] = c
 | 
						|
	}
 | 
						|
 | 
						|
	return Constraints(result), nil
 | 
						|
}
 | 
						|
 | 
						|
// Check tests if a version satisfies all the constraints.
 | 
						|
func (cs Constraints) Check(v *Version) bool {
 | 
						|
	for _, c := range cs {
 | 
						|
		if !c.Check(v) {
 | 
						|
			return false
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return true
 | 
						|
}
 | 
						|
 | 
						|
// Returns the string format of the constraints
 | 
						|
func (cs Constraints) String() string {
 | 
						|
	csStr := make([]string, len(cs))
 | 
						|
	for i, c := range cs {
 | 
						|
		csStr[i] = c.String()
 | 
						|
	}
 | 
						|
 | 
						|
	return strings.Join(csStr, ",")
 | 
						|
}
 | 
						|
 | 
						|
// Check tests if a constraint is validated by the given version.
 | 
						|
func (c *Constraint) Check(v *Version) bool {
 | 
						|
	return c.f(v, c.check)
 | 
						|
}
 | 
						|
 | 
						|
func (c *Constraint) String() string {
 | 
						|
	return c.original
 | 
						|
}
 | 
						|
 | 
						|
func parseSingle(v string) (*Constraint, error) {
 | 
						|
	matches := constraintRegexp.FindStringSubmatch(v)
 | 
						|
	if matches == nil {
 | 
						|
		return nil, fmt.Errorf("Malformed constraint: %s", v)
 | 
						|
	}
 | 
						|
 | 
						|
	check, err := NewVersion(matches[2])
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	return &Constraint{
 | 
						|
		f:        constraintOperators[matches[1]],
 | 
						|
		check:    check,
 | 
						|
		original: v,
 | 
						|
	}, nil
 | 
						|
}
 | 
						|
 | 
						|
func prereleaseCheck(v, c *Version) bool {
 | 
						|
	switch vPre, cPre := v.Prerelease() != "", c.Prerelease() != ""; {
 | 
						|
	case cPre && vPre:
 | 
						|
		// A constraint with a pre-release can only match a pre-release version
 | 
						|
		// with the same base segments.
 | 
						|
		return reflect.DeepEqual(c.Segments64(), v.Segments64())
 | 
						|
 | 
						|
	case !cPre && vPre:
 | 
						|
		// A constraint without a pre-release can only match a version without a
 | 
						|
		// pre-release.
 | 
						|
		return false
 | 
						|
 | 
						|
	case cPre && !vPre:
 | 
						|
		// OK, except with the pessimistic operator
 | 
						|
	case !cPre && !vPre:
 | 
						|
		// OK
 | 
						|
	}
 | 
						|
	return true
 | 
						|
}
 | 
						|
 | 
						|
//-------------------------------------------------------------------
 | 
						|
// Constraint functions
 | 
						|
//-------------------------------------------------------------------
 | 
						|
 | 
						|
func constraintEqual(v, c *Version) bool {
 | 
						|
	return v.Equal(c)
 | 
						|
}
 | 
						|
 | 
						|
func constraintNotEqual(v, c *Version) bool {
 | 
						|
	return !v.Equal(c)
 | 
						|
}
 | 
						|
 | 
						|
func constraintGreaterThan(v, c *Version) bool {
 | 
						|
	return prereleaseCheck(v, c) && v.Compare(c) == 1
 | 
						|
}
 | 
						|
 | 
						|
func constraintLessThan(v, c *Version) bool {
 | 
						|
	return prereleaseCheck(v, c) && v.Compare(c) == -1
 | 
						|
}
 | 
						|
 | 
						|
func constraintGreaterThanEqual(v, c *Version) bool {
 | 
						|
	return prereleaseCheck(v, c) && v.Compare(c) >= 0
 | 
						|
}
 | 
						|
 | 
						|
func constraintLessThanEqual(v, c *Version) bool {
 | 
						|
	return prereleaseCheck(v, c) && v.Compare(c) <= 0
 | 
						|
}
 | 
						|
 | 
						|
func constraintPessimistic(v, c *Version) bool {
 | 
						|
	// Using a pessimistic constraint with a pre-release, restricts versions to pre-releases
 | 
						|
	if !prereleaseCheck(v, c) || (c.Prerelease() != "" && v.Prerelease() == "") {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	// If the version being checked is naturally less than the constraint, then there
 | 
						|
	// is no way for the version to be valid against the constraint
 | 
						|
	if v.LessThan(c) {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
	// We'll use this more than once, so grab the length now so it's a little cleaner
 | 
						|
	// to write the later checks
 | 
						|
	cs := len(c.segments)
 | 
						|
 | 
						|
	// If the version being checked has less specificity than the constraint, then there
 | 
						|
	// is no way for the version to be valid against the constraint
 | 
						|
	if cs > len(v.segments) {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	// Check the segments in the constraint against those in the version. If the version
 | 
						|
	// being checked, at any point, does not have the same values in each index of the
 | 
						|
	// constraints segments, then it cannot be valid against the constraint.
 | 
						|
	for i := 0; i < c.si-1; i++ {
 | 
						|
		if v.segments[i] != c.segments[i] {
 | 
						|
			return false
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// Check the last part of the segment in the constraint. If the version segment at
 | 
						|
	// this index is less than the constraints segment at this index, then it cannot
 | 
						|
	// be valid against the constraint
 | 
						|
	if c.segments[cs-1] > v.segments[cs-1] {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	// If nothing has rejected the version by now, it's valid
 | 
						|
	return true
 | 
						|
}
 |