aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/hashicorp/go-version/constraint.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/hashicorp/go-version/constraint.go')
-rw-r--r--vendor/github.com/hashicorp/go-version/constraint.go178
1 files changed, 178 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/go-version/constraint.go b/vendor/github.com/hashicorp/go-version/constraint.go
new file mode 100644
index 0000000..8c73df0
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-version/constraint.go
@@ -0,0 +1,178 @@
1package version
2
3import (
4 "fmt"
5 "regexp"
6 "strings"
7)
8
9// Constraint represents a single constraint for a version, such as
10// ">= 1.0".
11type Constraint struct {
12 f constraintFunc
13 check *Version
14 original string
15}
16
17// Constraints is a slice of constraints. We make a custom type so that
18// we can add methods to it.
19type Constraints []*Constraint
20
21type constraintFunc func(v, c *Version) bool
22
23var constraintOperators map[string]constraintFunc
24
25var constraintRegexp *regexp.Regexp
26
27func init() {
28 constraintOperators = map[string]constraintFunc{
29 "": constraintEqual,
30 "=": constraintEqual,
31 "!=": constraintNotEqual,
32 ">": constraintGreaterThan,
33 "<": constraintLessThan,
34 ">=": constraintGreaterThanEqual,
35 "<=": constraintLessThanEqual,
36 "~>": constraintPessimistic,
37 }
38
39 ops := make([]string, 0, len(constraintOperators))
40 for k := range constraintOperators {
41 ops = append(ops, regexp.QuoteMeta(k))
42 }
43
44 constraintRegexp = regexp.MustCompile(fmt.Sprintf(
45 `^\s*(%s)\s*(%s)\s*$`,
46 strings.Join(ops, "|"),
47 VersionRegexpRaw))
48}
49
50// NewConstraint will parse one or more constraints from the given
51// constraint string. The string must be a comma-separated list of
52// constraints.
53func NewConstraint(v string) (Constraints, error) {
54 vs := strings.Split(v, ",")
55 result := make([]*Constraint, len(vs))
56 for i, single := range vs {
57 c, err := parseSingle(single)
58 if err != nil {
59 return nil, err
60 }
61
62 result[i] = c
63 }
64
65 return Constraints(result), nil
66}
67
68// Check tests if a version satisfies all the constraints.
69func (cs Constraints) Check(v *Version) bool {
70 for _, c := range cs {
71 if !c.Check(v) {
72 return false
73 }
74 }
75
76 return true
77}
78
79// Returns the string format of the constraints
80func (cs Constraints) String() string {
81 csStr := make([]string, len(cs))
82 for i, c := range cs {
83 csStr[i] = c.String()
84 }
85
86 return strings.Join(csStr, ",")
87}
88
89// Check tests if a constraint is validated by the given version.
90func (c *Constraint) Check(v *Version) bool {
91 return c.f(v, c.check)
92}
93
94func (c *Constraint) String() string {
95 return c.original
96}
97
98func parseSingle(v string) (*Constraint, error) {
99 matches := constraintRegexp.FindStringSubmatch(v)
100 if matches == nil {
101 return nil, fmt.Errorf("Malformed constraint: %s", v)
102 }
103
104 check, err := NewVersion(matches[2])
105 if err != nil {
106 return nil, err
107 }
108
109 return &Constraint{
110 f: constraintOperators[matches[1]],
111 check: check,
112 original: v,
113 }, nil
114}
115
116//-------------------------------------------------------------------
117// Constraint functions
118//-------------------------------------------------------------------
119
120func constraintEqual(v, c *Version) bool {
121 return v.Equal(c)
122}
123
124func constraintNotEqual(v, c *Version) bool {
125 return !v.Equal(c)
126}
127
128func constraintGreaterThan(v, c *Version) bool {
129 return v.Compare(c) == 1
130}
131
132func constraintLessThan(v, c *Version) bool {
133 return v.Compare(c) == -1
134}
135
136func constraintGreaterThanEqual(v, c *Version) bool {
137 return v.Compare(c) >= 0
138}
139
140func constraintLessThanEqual(v, c *Version) bool {
141 return v.Compare(c) <= 0
142}
143
144func constraintPessimistic(v, c *Version) bool {
145 // If the version being checked is naturally less than the constraint, then there
146 // is no way for the version to be valid against the constraint
147 if v.LessThan(c) {
148 return false
149 }
150 // We'll use this more than once, so grab the length now so it's a little cleaner
151 // to write the later checks
152 cs := len(c.segments)
153
154 // If the version being checked has less specificity than the constraint, then there
155 // is no way for the version to be valid against the constraint
156 if cs > len(v.segments) {
157 return false
158 }
159
160 // Check the segments in the constraint against those in the version. If the version
161 // being checked, at any point, does not have the same values in each index of the
162 // constraints segments, then it cannot be valid against the constraint.
163 for i := 0; i < c.si-1; i++ {
164 if v.segments[i] != c.segments[i] {
165 return false
166 }
167 }
168
169 // Check the last part of the segment in the constraint. If the version segment at
170 // this index is less than the constraints segment at this index, then it cannot
171 // be valid against the constraint
172 if c.segments[cs-1] > v.segments[cs-1] {
173 return false
174 }
175
176 // If nothing has rejected the version by now, it's valid
177 return true
178}