github.com/Ilhicas/nomad@v1.0.4-0.20210304152020-e86851182bc3/helper/constraints/semver/constraints.go (about) 1 // semver is a Semver Constraints package copied from 2 // github.com/hashicorp/go-version @ 2046c9d0f0b03c779670f5186a2a4b2c85493a71 3 // 4 // Unlike Constraints in go-version, Semver constraints use Semver 2.0 ordering 5 // rules and only accept properly formatted Semver versions. 6 package semver 7 8 import ( 9 "fmt" 10 "regexp" 11 "strings" 12 13 "github.com/hashicorp/go-version" 14 ) 15 16 // Constraint represents a single constraint for a version, such as ">= 17 // 1.0". 18 type Constraint struct { 19 f constraintFunc 20 check *version.Version 21 original string 22 } 23 24 // Constraints is a slice of constraints. We make a custom type so that 25 // we can add methods to it. 26 type Constraints []*Constraint 27 28 type constraintFunc func(v, c *version.Version) bool 29 30 var constraintOperators map[string]constraintFunc 31 32 var constraintRegexp *regexp.Regexp 33 34 func init() { 35 constraintOperators = map[string]constraintFunc{ 36 "": constraintEqual, 37 "=": constraintEqual, 38 "!=": constraintNotEqual, 39 ">": constraintGreaterThan, 40 "<": constraintLessThan, 41 ">=": constraintGreaterThanEqual, 42 "<=": constraintLessThanEqual, 43 } 44 45 ops := make([]string, 0, len(constraintOperators)) 46 for k := range constraintOperators { 47 ops = append(ops, regexp.QuoteMeta(k)) 48 } 49 50 constraintRegexp = regexp.MustCompile(fmt.Sprintf( 51 `^\s*(%s)\s*(%s)\s*$`, 52 strings.Join(ops, "|"), 53 version.SemverRegexpRaw)) 54 } 55 56 // NewConstraint will parse one or more constraints from the given 57 // constraint string. The string must be a comma-separated list of constraints. 58 func NewConstraint(v string) (Constraints, error) { 59 vs := strings.Split(v, ",") 60 result := make([]*Constraint, len(vs)) 61 for i, single := range vs { 62 c, err := parseSingle(single) 63 if err != nil { 64 return nil, err 65 } 66 67 result[i] = c 68 } 69 70 return Constraints(result), nil 71 } 72 73 // Check tests if a version satisfies all the constraints. 74 func (cs Constraints) Check(v *version.Version) bool { 75 for _, c := range cs { 76 if !c.Check(v) { 77 return false 78 } 79 } 80 81 return true 82 } 83 84 // Returns the string format of the constraints 85 func (cs Constraints) String() string { 86 csStr := make([]string, len(cs)) 87 for i, c := range cs { 88 csStr[i] = c.String() 89 } 90 91 return strings.Join(csStr, ",") 92 } 93 94 // Check tests if a constraint is validated by the given version. 95 func (c *Constraint) Check(v *version.Version) bool { 96 return c.f(v, c.check) 97 } 98 99 func (c *Constraint) String() string { 100 return c.original 101 } 102 103 func parseSingle(v string) (*Constraint, error) { 104 matches := constraintRegexp.FindStringSubmatch(v) 105 if matches == nil { 106 return nil, fmt.Errorf("Malformed constraint: %s", v) 107 } 108 109 check, err := version.NewSemver(matches[2]) 110 if err != nil { 111 return nil, err 112 } 113 114 return &Constraint{ 115 f: constraintOperators[matches[1]], 116 check: check, 117 original: v, 118 }, nil 119 } 120 121 //------------------------------------------------------------------- 122 // Constraint functions 123 //------------------------------------------------------------------- 124 125 func constraintEqual(v, c *version.Version) bool { 126 return v.Equal(c) 127 } 128 129 func constraintNotEqual(v, c *version.Version) bool { 130 return !v.Equal(c) 131 } 132 133 func constraintGreaterThan(v, c *version.Version) bool { 134 return v.Compare(c) == 1 135 } 136 137 func constraintLessThan(v, c *version.Version) bool { 138 return v.Compare(c) == -1 139 } 140 141 func constraintGreaterThanEqual(v, c *version.Version) bool { 142 return v.Compare(c) >= 0 143 } 144 145 func constraintLessThanEqual(v, c *version.Version) bool { 146 return v.Compare(c) <= 0 147 }