diff options
Diffstat (limited to 'vendor/github.com/hashicorp/go-version/constraint.go')
-rw-r--r-- | vendor/github.com/hashicorp/go-version/constraint.go | 178 |
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 @@ | |||
1 | package version | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | "regexp" | ||
6 | "strings" | ||
7 | ) | ||
8 | |||
9 | // Constraint represents a single constraint for a version, such as | ||
10 | // ">= 1.0". | ||
11 | type 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. | ||
19 | type Constraints []*Constraint | ||
20 | |||
21 | type constraintFunc func(v, c *Version) bool | ||
22 | |||
23 | var constraintOperators map[string]constraintFunc | ||
24 | |||
25 | var constraintRegexp *regexp.Regexp | ||
26 | |||
27 | func 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. | ||
53 | func 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. | ||
69 | func (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 | ||
80 | func (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. | ||
90 | func (c *Constraint) Check(v *Version) bool { | ||
91 | return c.f(v, c.check) | ||
92 | } | ||
93 | |||
94 | func (c *Constraint) String() string { | ||
95 | return c.original | ||
96 | } | ||
97 | |||
98 | func 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 | |||
120 | func constraintEqual(v, c *Version) bool { | ||
121 | return v.Equal(c) | ||
122 | } | ||
123 | |||
124 | func constraintNotEqual(v, c *Version) bool { | ||
125 | return !v.Equal(c) | ||
126 | } | ||
127 | |||
128 | func constraintGreaterThan(v, c *Version) bool { | ||
129 | return v.Compare(c) == 1 | ||
130 | } | ||
131 | |||
132 | func constraintLessThan(v, c *Version) bool { | ||
133 | return v.Compare(c) == -1 | ||
134 | } | ||
135 | |||
136 | func constraintGreaterThanEqual(v, c *Version) bool { | ||
137 | return v.Compare(c) >= 0 | ||
138 | } | ||
139 | |||
140 | func constraintLessThanEqual(v, c *Version) bool { | ||
141 | return v.Compare(c) <= 0 | ||
142 | } | ||
143 | |||
144 | func 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 | } | ||