@@ -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 ))
@@ -77,6 +88,56 @@ func (cs Constraints) Check(v *Version) bool {
77
88
return true
78
89
}
79
90
91
+ // Equals compares Constraints with other Constraints
92
+ // for equality. This may not represent logical equivalence
93
+ // of compared constraints.
94
+ // e.g. even though '>0.1,>0.2' is logically equivalent
95
+ // to '>0.2' it is *NOT* treated as equal.
96
+ //
97
+ // Missing operator is treated as equal to '=', whitespaces
98
+ // are ignored and constraints are sorted before comaparison.
99
+ func (cs Constraints ) Equals (c Constraints ) bool {
100
+ if len (cs ) != len (c ) {
101
+ return false
102
+ }
103
+
104
+ // make copies to retain order of the original slices
105
+ left := make (Constraints , len (cs ))
106
+ copy (left , cs )
107
+ sort .Stable (left )
108
+ right := make (Constraints , len (c ))
109
+ copy (right , c )
110
+ sort .Stable (right )
111
+
112
+ // compare sorted slices
113
+ for i , con := range left {
114
+ if ! con .Equals (right [i ]) {
115
+ return false
116
+ }
117
+ }
118
+
119
+ return true
120
+ }
121
+
122
+ func (cs Constraints ) Len () int {
123
+ return len (cs )
124
+ }
125
+
126
+ func (cs Constraints ) Less (i , j int ) bool {
127
+ if cs [i ].op < cs [j ].op {
128
+ return true
129
+ }
130
+ if cs [i ].op > cs [j ].op {
131
+ return false
132
+ }
133
+
134
+ return cs [i ].check .LessThan (cs [j ].check )
135
+ }
136
+
137
+ func (cs Constraints ) Swap (i , j int ) {
138
+ cs [i ], cs [j ] = cs [j ], cs [i ]
139
+ }
140
+
80
141
// Returns the string format of the constraints
81
142
func (cs Constraints ) String () string {
82
143
csStr := make ([]string , len (cs ))
@@ -107,8 +168,11 @@ func parseSingle(v string) (*Constraint, error) {
107
168
return nil , err
108
169
}
109
170
171
+ cop := constraintOperators [matches [1 ]]
172
+
110
173
return & Constraint {
111
- f : constraintOperators [matches [1 ]],
174
+ f : cop .f ,
175
+ op : cop .op ,
112
176
check : check ,
113
177
original : v ,
114
178
}, nil
@@ -138,6 +202,18 @@ func prereleaseCheck(v, c *Version) bool {
138
202
// Constraint functions
139
203
//-------------------------------------------------------------------
140
204
205
+ type operator rune
206
+
207
+ const (
208
+ equal operator = '='
209
+ notEqual operator = '≠'
210
+ greaterThan operator = '>'
211
+ lessThan operator = '<'
212
+ greaterThanEqual operator = '≥'
213
+ lessThanEqual operator = '≤'
214
+ pessimistic operator = '~'
215
+ )
216
+
141
217
func constraintEqual (v , c * Version ) bool {
142
218
return v .Equal (c )
143
219
}
0 commit comments