Codebase list golang-github-hashicorp-go-version / 1a38092
New upstream release. Debian Janitor 2 years ago
5 changed file(s) with 213 addition(s) and 15 deletion(s). Raw diff Collapse all Expand all
0 # 1.4.0 (January 5, 2021)
1
2 FEATURES:
3
4 - Introduce `MustConstraints()` ([#87](https://github.com/hashicorp/go-version/pull/87))
5 - `Constraints`: Introduce `Equals()` and `sort.Interface` methods ([#88](https://github.com/hashicorp/go-version/pull/88))
6
07 # 1.3.0 (March 31, 2021)
18
29 Please note that CHANGELOG.md does not exist in the source code prior to this release.
33 "fmt"
44 "reflect"
55 "regexp"
6 "sort"
67 "strings"
78 )
89
1011 // ">= 1.0".
1112 type Constraint struct {
1213 f constraintFunc
14 op operator
1315 check *Version
1416 original string
17 }
18
19 func (c *Constraint) Equals(con *Constraint) bool {
20 return c.op == con.op && c.check.Equal(con.check)
1521 }
1622
1723 // Constraints is a slice of constraints. We make a custom type so that
2026
2127 type constraintFunc func(v, c *Version) bool
2228
23 var constraintOperators map[string]constraintFunc
29 var constraintOperators map[string]constraintOperation
30
31 type constraintOperation struct {
32 op operator
33 f constraintFunc
34 }
2435
2536 var constraintRegexp *regexp.Regexp
2637
2738 func init() {
28 constraintOperators = map[string]constraintFunc{
29 "": constraintEqual,
30 "=": constraintEqual,
31 "!=": constraintNotEqual,
32 ">": constraintGreaterThan,
33 "<": constraintLessThan,
34 ">=": constraintGreaterThanEqual,
35 "<=": constraintLessThanEqual,
36 "~>": constraintPessimistic,
39 constraintOperators = map[string]constraintOperation{
40 "": {op: equal, f: constraintEqual},
41 "=": {op: equal, f: constraintEqual},
42 "!=": {op: notEqual, f: constraintNotEqual},
43 ">": {op: greaterThan, f: constraintGreaterThan},
44 "<": {op: lessThan, f: constraintLessThan},
45 ">=": {op: greaterThanEqual, f: constraintGreaterThanEqual},
46 "<=": {op: lessThanEqual, f: constraintLessThanEqual},
47 "~>": {op: pessimistic, f: constraintPessimistic},
3748 }
3849
3950 ops := make([]string, 0, len(constraintOperators))
6576 return Constraints(result), nil
6677 }
6778
79 // MustConstraints is a helper that wraps a call to a function
80 // returning (Constraints, error) and panics if error is non-nil.
81 func MustConstraints(c Constraints, err error) Constraints {
82 if err != nil {
83 panic(err)
84 }
85
86 return c
87 }
88
6889 // Check tests if a version satisfies all the constraints.
6990 func (cs Constraints) Check(v *Version) bool {
7091 for _, c := range cs {
7697 return true
7798 }
7899
100 // Equals compares Constraints with other Constraints
101 // for equality. This may not represent logical equivalence
102 // of compared constraints.
103 // e.g. even though '>0.1,>0.2' is logically equivalent
104 // to '>0.2' it is *NOT* treated as equal.
105 //
106 // Missing operator is treated as equal to '=', whitespaces
107 // are ignored and constraints are sorted before comaparison.
108 func (cs Constraints) Equals(c Constraints) bool {
109 if len(cs) != len(c) {
110 return false
111 }
112
113 // make copies to retain order of the original slices
114 left := make(Constraints, len(cs))
115 copy(left, cs)
116 sort.Stable(left)
117 right := make(Constraints, len(c))
118 copy(right, c)
119 sort.Stable(right)
120
121 // compare sorted slices
122 for i, con := range left {
123 if !con.Equals(right[i]) {
124 return false
125 }
126 }
127
128 return true
129 }
130
131 func (cs Constraints) Len() int {
132 return len(cs)
133 }
134
135 func (cs Constraints) Less(i, j int) bool {
136 if cs[i].op < cs[j].op {
137 return true
138 }
139 if cs[i].op > cs[j].op {
140 return false
141 }
142
143 return cs[i].check.LessThan(cs[j].check)
144 }
145
146 func (cs Constraints) Swap(i, j int) {
147 cs[i], cs[j] = cs[j], cs[i]
148 }
149
79150 // Returns the string format of the constraints
80151 func (cs Constraints) String() string {
81152 csStr := make([]string, len(cs))
106177 return nil, err
107178 }
108179
180 cop := constraintOperators[matches[1]]
181
109182 return &Constraint{
110 f: constraintOperators[matches[1]],
183 f: cop.f,
184 op: cop.op,
111185 check: check,
112186 original: v,
113187 }, nil
137211 // Constraint functions
138212 //-------------------------------------------------------------------
139213
214 type operator rune
215
216 const (
217 equal operator = '='
218 notEqual operator = '≠'
219 greaterThan operator = '>'
220 lessThan operator = '<'
221 greaterThanEqual operator = '≥'
222 lessThanEqual operator = '≤'
223 pessimistic operator = '~'
224 )
225
140226 func constraintEqual(v, c *Version) bool {
141227 return v.Equal(c)
142228 }
00 package version
11
22 import (
3 "fmt"
4 "reflect"
5 "sort"
36 "testing"
47 )
58
9699 }
97100 }
98101
102 func TestConstraintEqual(t *testing.T) {
103 cases := []struct {
104 leftConstraint string
105 rightConstraint string
106 expectedEqual bool
107 }{
108 {
109 "0.0.1",
110 "0.0.1",
111 true,
112 },
113 { // whitespaces
114 " 0.0.1 ",
115 "0.0.1",
116 true,
117 },
118 { // equal op implied
119 "=0.0.1 ",
120 "0.0.1",
121 true,
122 },
123 { // version difference
124 "=0.0.1",
125 "=0.0.2",
126 false,
127 },
128 { // operator difference
129 ">0.0.1",
130 "=0.0.1",
131 false,
132 },
133 { // different order
134 ">0.1.0, <=1.0.0",
135 "<=1.0.0, >0.1.0",
136 true,
137 },
138 }
139
140 for _, tc := range cases {
141 leftCon, err := NewConstraint(tc.leftConstraint)
142 if err != nil {
143 t.Fatalf("err: %s", err)
144 }
145 rightCon, err := NewConstraint(tc.rightConstraint)
146 if err != nil {
147 t.Fatalf("err: %s", err)
148 }
149
150 actual := leftCon.Equals(rightCon)
151 if actual != tc.expectedEqual {
152 t.Fatalf("Constraints: %s vs %s\nExpected: %t\nActual: %t",
153 tc.leftConstraint, tc.rightConstraint, tc.expectedEqual, actual)
154 }
155 }
156 }
157
158 func TestConstraint_sort(t *testing.T) {
159 cases := []struct {
160 constraint string
161 expectedConstraints string
162 }{
163 {
164 ">= 0.1.0,< 1.12",
165 "< 1.12,>= 0.1.0",
166 },
167 {
168 "< 1.12,>= 0.1.0",
169 "< 1.12,>= 0.1.0",
170 },
171 {
172 "< 1.12,>= 0.1.0,0.2.0",
173 "< 1.12,0.2.0,>= 0.1.0",
174 },
175 {
176 ">1.0,>0.1.0,>0.3.0,>0.2.0",
177 ">0.1.0,>0.2.0,>0.3.0,>1.0",
178 },
179 }
180
181 for i, tc := range cases {
182 t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
183 c, err := NewConstraint(tc.constraint)
184 if err != nil {
185 t.Fatalf("err: %s", err)
186 }
187
188 sort.Sort(c)
189
190 actual := c.String()
191
192 if !reflect.DeepEqual(actual, tc.expectedConstraints) {
193 t.Fatalf("unexpected order\nexpected: %#v\nactual: %#v",
194 tc.expectedConstraints, actual)
195 }
196 })
197 }
198 }
199
99200 func TestConstraintsString(t *testing.T) {
100201 cases := []struct {
101202 constraint string
0 golang-github-hashicorp-go-version (1.4.0-1) UNRELEASED; urgency=low
1
2 * New upstream release.
3
4 -- Debian Janitor <janitor@jelmer.uk> Mon, 16 May 2022 08:45:33 -0000
5
06 golang-github-hashicorp-go-version (1.3.0-1) unstable; urgency=medium
17
28 * Team upload.
6363 }
6464 segmentsStr := strings.Split(matches[1], ".")
6565 segments := make([]int64, len(segmentsStr))
66 si := 0
6766 for i, str := range segmentsStr {
6867 val, err := strconv.ParseInt(str, 10, 64)
6968 if err != nil {
7170 "Error parsing version: %s", err)
7271 }
7372
74 segments[i] = int64(val)
75 si++
73 segments[i] = val
7674 }
7775
7876 // Even though we could support more than three segments, if we
9189 metadata: matches[10],
9290 pre: pre,
9391 segments: segments,
94 si: si,
92 si: len(segmentsStr),
9593 original: v,
9694 }, nil
9795 }