github.com/tonyhb/nomad@v0.11.8/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  }