@@ -4,37 +4,48 @@ import (
4
4
"fmt"
5
5
"reflect"
6
6
"regexp"
7
+ "sort"
7
8
"strings"
8
9
)
9
10
10
11
// Constraint represents a single constraint for a version, such as
11
12
// ">= 1.0".
12
13
type Constraint struct {
13
14
f constraintFunc
15
+ op operator
14
16
check * Version
15
17
original string
16
18
}
17
19
20
+ func (c * Constraint ) Equals (con * Constraint ) bool {
21
+ return c .op == con .op && c .check .Equal (con .check )
22
+ }
23
+
18
24
// Constraints is a slice of constraints. We make a custom type so that
19
25
// we can add methods to it.
20
26
type Constraints []* Constraint
21
27
22
28
type constraintFunc func (v , c * Version ) bool
23
29
24
- var constraintOperators map [string ]constraintFunc
30
+ var constraintOperators map [string ]constraintOperation
31
+
32
+ type constraintOperation struct {
33
+ op operator
34
+ f constraintFunc
35
+ }
25
36
26
37
var constraintRegexp * regexp.Regexp
27
38
28
39
func init () {
29
- constraintOperators = map [string ]constraintFunc {
30
- "" : constraintEqual ,
31
- "=" : constraintEqual ,
32
- "!=" : constraintNotEqual ,
33
- ">" : constraintGreaterThan ,
34
- "<" : constraintLessThan ,
35
- ">=" : constraintGreaterThanEqual ,
36
- "<=" : constraintLessThanEqual ,
37
- "~>" : constraintPessimistic ,
40
+ constraintOperators = map [string ]constraintOperation {
41
+ "" : { op : equal , f : constraintEqual } ,
42
+ "=" : { op : equal , f : constraintEqual } ,
43
+ "!=" : { op : notEqual , f : constraintNotEqual } ,
44
+ ">" : { op : greaterThan , f : constraintGreaterThan } ,
45
+ "<" : { op : lessThan , f : constraintLessThan } ,
46
+ ">=" : { op : greaterThanEqual , f : constraintGreaterThanEqual } ,
47
+ "<=" : { op : lessThanEqual , f : constraintLessThanEqual } ,
48
+ "~>" : { op : pessimistic , f : constraintPessimistic } ,
38
49
}
39
50
40
51
ops := make ([]string , 0 , len (constraintOperators ))
@@ -87,6 +98,56 @@ func (cs Constraints) Check(v *Version) bool {
87
98
return true
88
99
}
89
100
101
+ // Equals compares Constraints with other Constraints
102
+ // for equality. This may not represent logical equivalence
103
+ // of compared constraints.
104
+ // e.g. even though '>0.1,>0.2' is logically equivalent
105
+ // to '>0.2' it is *NOT* treated as equal.
106
+ //
107
+ // Missing operator is treated as equal to '=', whitespaces
108
+ // are ignored and constraints are sorted before comaparison.
109
+ func (cs Constraints ) Equals (c Constraints ) bool {
110
+ if len (cs ) != len (c ) {
111
+ return false
112
+ }
113
+
114
+ // make copies to retain order of the original slices
115
+ left := make (Constraints , len (cs ))
116
+ copy (left , cs )
117
+ sort .Stable (left )
118
+ right := make (Constraints , len (c ))
119
+ copy (right , c )
120
+ sort .Stable (right )
121
+
122
+ // compare sorted slices
123
+ for i , con := range left {
124
+ if ! con .Equals (right [i ]) {
125
+ return false
126
+ }
127
+ }
128
+
129
+ return true
130
+ }
131
+
132
+ func (cs Constraints ) Len () int {
133
+ return len (cs )
134
+ }
135
+
136
+ func (cs Constraints ) Less (i , j int ) bool {
137
+ if cs [i ].op < cs [j ].op {
138
+ return true
139
+ }
140
+ if cs [i ].op > cs [j ].op {
141
+ return false
142
+ }
143
+
144
+ return cs [i ].check .LessThan (cs [j ].check )
145
+ }
146
+
147
+ func (cs Constraints ) Swap (i , j int ) {
148
+ cs [i ], cs [j ] = cs [j ], cs [i ]
149
+ }
150
+
90
151
// Returns the string format of the constraints
91
152
func (cs Constraints ) String () string {
92
153
csStr := make ([]string , len (cs ))
@@ -117,8 +178,11 @@ func parseSingle(v string) (*Constraint, error) {
117
178
return nil , err
118
179
}
119
180
181
+ cop := constraintOperators [matches [1 ]]
182
+
120
183
return & Constraint {
121
- f : constraintOperators [matches [1 ]],
184
+ f : cop .f ,
185
+ op : cop .op ,
122
186
check : check ,
123
187
original : v ,
124
188
}, nil
@@ -148,6 +212,18 @@ func prereleaseCheck(v, c *Version) bool {
148
212
// Constraint functions
149
213
//-------------------------------------------------------------------
150
214
215
+ type operator rune
216
+
217
+ const (
218
+ equal operator = '='
219
+ notEqual operator = '≠'
220
+ greaterThan operator = '>'
221
+ lessThan operator = '<'
222
+ greaterThanEqual operator = '≥'
223
+ lessThanEqual operator = '≤'
224
+ pessimistic operator = '~'
225
+ )
226
+
151
227
func constraintEqual (v , c * Version ) bool {
152
228
return v .Equal (c )
153
229
}
0 commit comments