Skip to content

Commit 2f47f02

Browse files
authored
Merge pull request #1828 from FabianKramm/master
refactor: allow beta / alpha in require
2 parents 82b8b99 + a530e56 commit 2f47f02

File tree

14 files changed

+996
-517
lines changed

14 files changed

+996
-517
lines changed

go.mod

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ require (
1717
github.com/golang/protobuf v1.5.2
1818
github.com/google/uuid v1.1.2
1919
github.com/gorilla/websocket v1.4.2
20-
github.com/hashicorp/go-version v1.3.0
2120
github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf // indirect
2221
github.com/joho/godotenv v1.3.0
2322
github.com/json-iterator/go v1.1.12

go.sum

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -644,8 +644,6 @@ github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdv
644644
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
645645
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
646646
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
647-
github.com/hashicorp/go-version v1.3.0 h1:McDWVJIU/y+u1BRV06dPaLfLCaT7fUTJLp5r04x7iNw=
648-
github.com/hashicorp/go-version v1.3.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
649647
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
650648
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
651649
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=

pkg/devspace/config/loader/loader.go

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package loader
22

33
import (
44
"fmt"
5+
"github.com/loft-sh/devspace/pkg/util/constraint"
56
"io/ioutil"
67
"os"
78
"os/exec"
@@ -26,8 +27,6 @@ import (
2627
"github.com/loft-sh/devspace/pkg/util/kubeconfig"
2728
"github.com/loft-sh/devspace/pkg/util/log"
2829
"github.com/loft-sh/devspace/pkg/util/vars"
29-
30-
version "github.com/hashicorp/go-version"
3130
)
3231

3332
// DefaultCommandVersionRegEx is the default regex to use if no regex is specified for determining the commands version
@@ -166,17 +165,17 @@ func (l *configLoader) ensureRequires(config *latest.Config, log log.Logger) err
166165
}
167166

168167
if config.Require.DevSpace != "" {
169-
constraint, err := version.NewConstraint(config.Require.DevSpace)
168+
parsedConstraint, err := constraint.NewConstraint(config.Require.DevSpace)
170169
if err != nil {
171170
return errors.Wrap(err, "parsing require.devspace")
172171
}
173172

174-
v, err := version.NewSemver(upgrade.GetVersion())
173+
v, err := constraint.NewSemver(upgrade.GetVersion())
175174
if err != nil {
176175
return errors.Wrap(err, "parsing devspace version")
177176
}
178177

179-
if !constraint.Check(v) {
178+
if !parsedConstraint.Check(v) {
180179
return fmt.Errorf("DevSpace version mismatch: %s (currently installed) does not match %s (required by config). Please make sure you have installed DevSpace with version %s", upgrade.GetVersion(), config.Require.DevSpace, config.Require.DevSpace)
181180
}
182181
}
@@ -191,17 +190,17 @@ func (l *configLoader) ensureRequires(config *latest.Config, log log.Logger) err
191190
return fmt.Errorf("cannot find plugin '%s', however it is required by the config. Please make sure you have installed the plugin '%s' with version %s", p.Name, p.Name, p.Version)
192191
}
193192

194-
constraint, err := version.NewConstraint(p.Version)
193+
parsedConstraint, err := constraint.NewConstraint(p.Version)
195194
if err != nil {
196195
return errors.Wrapf(err, "parsing require.plugins[%d].version", index)
197196
}
198197

199-
v, err := version.NewSemver(metadata.Version)
198+
v, err := constraint.NewSemver(metadata.Version)
200199
if err != nil {
201200
return errors.Wrapf(err, "parsing plugin %s version", p.Name)
202201
}
203202

204-
if !constraint.Check(v) {
203+
if !parsedConstraint.Check(v) {
205204
return fmt.Errorf("plugin '%s' version mismatch: %s (currently installed) does not match %s (required by config). Please make sure you have installed the plugin '%s' with version %s", p.Name, metadata.Version, p.Version, p.Name, p.Version)
206205
}
207206
}
@@ -223,7 +222,7 @@ func (l *configLoader) ensureRequires(config *latest.Config, log log.Logger) err
223222
return errors.Wrapf(err, "parsing require.commands[%d].versionRegEx", index)
224223
}
225224

226-
constraint, err := version.NewConstraint(c.Version)
225+
parsedConstraint, err := constraint.NewConstraint(c.Version)
227226
if err != nil {
228227
return errors.Wrapf(err, "parsing require.commands[%d].version", index)
229228
}
@@ -238,12 +237,12 @@ func (l *configLoader) ensureRequires(config *latest.Config, log log.Logger) err
238237
return fmt.Errorf("command %s %s output does not match the provided regex '%s', however the command is required by the config. Please make sure you have correctly installed '%s' with version %s", c.Name, strings.Join(versionArgs, " "), regExString, c.Name, c.Version)
239238
}
240239

241-
v, err := version.NewSemver(matches[1])
240+
v, err := constraint.NewSemver(matches[1])
242241
if err != nil {
243242
return fmt.Errorf("command %s %s output does not return a semver version, however the command is required by the config. Please make sure you have correctly installed '%s' with version %s", c.Name, strings.Join(versionArgs, " "), c.Name, c.Version)
244243
}
245244

246-
if !constraint.Check(v) {
245+
if !parsedConstraint.Check(v) {
247246
return fmt.Errorf("command '%s' version mismatch: %s (currently installed) does not match %s (required by config). Please make sure you have correctly installed '%s' with version %s", c.Name, matches[1], c.Version, c.Name, c.Version)
248247
}
249248
}

pkg/devspace/deploy/deployer/kubectl/builder.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ package kubectl
22

33
import (
44
"fmt"
5+
"github.com/loft-sh/devspace/pkg/util/constraint"
56
"os/exec"
67
"regexp"
78
"strings"
89

910
"github.com/ghodss/yaml"
10-
version "github.com/hashicorp/go-version"
1111
"github.com/loft-sh/devspace/pkg/devspace/config/versions/latest"
1212
"github.com/loft-sh/devspace/pkg/util/command"
1313
"github.com/loft-sh/devspace/pkg/util/log"
@@ -83,13 +83,13 @@ var useOldDryRun = func(path string) (bool, error) {
8383
return false, err
8484
}
8585

86-
v1, err := version.NewVersion(strings.TrimPrefix(strings.TrimSpace(string(out)), "Client Version: v"))
86+
v1, err := constraint.NewVersion(strings.TrimPrefix(strings.TrimSpace(string(out)), "Client Version: v"))
8787
if err != nil {
8888

8989
return false, err
9090
}
9191

92-
v2, err := version.NewVersion("1.18.0")
92+
v2, err := constraint.NewVersion("1.18.0")
9393
if err != nil {
9494
return false, err
9595
}

vendor/github.com/hashicorp/go-version/constraint.go renamed to pkg/util/constraint/constraint.go

Lines changed: 92 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,51 @@
1-
package version
1+
package constraint
22

33
import (
44
"fmt"
55
"reflect"
66
"regexp"
7+
"sort"
78
"strings"
89
)
910

1011
// Constraint represents a single constraint for a version, such as
1112
// ">= 1.0".
1213
type Constraint struct {
1314
f constraintFunc
15+
op operator
1416
check *Version
1517
original string
1618
}
1719

20+
func (c *Constraint) Equals(con *Constraint) bool {
21+
return c.op == con.op && c.check.Equal(con.check)
22+
}
23+
1824
// Constraints is a slice of constraints. We make a custom type so that
1925
// we can add methods to it.
2026
type Constraints []*Constraint
2127

2228
type constraintFunc func(v, c *Version) bool
2329

24-
var constraintOperators map[string]constraintFunc
30+
var constraintOperators map[string]constraintOperation
31+
32+
type constraintOperation struct {
33+
op operator
34+
f constraintFunc
35+
}
2536

2637
var constraintRegexp *regexp.Regexp
2738

2839
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},
3849
}
3950

4051
ops := make([]string, 0, len(constraintOperators))
@@ -63,7 +74,7 @@ func NewConstraint(v string) (Constraints, error) {
6374
result[i] = c
6475
}
6576

66-
return Constraints(result), nil
77+
return result, nil
6778
}
6879

6980
// Check tests if a version satisfies all the constraints.
@@ -77,6 +88,56 @@ func (cs Constraints) Check(v *Version) bool {
7788
return true
7889
}
7990

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 comparison.
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+
80141
// Returns the string format of the constraints
81142
func (cs Constraints) String() string {
82143
csStr := make([]string, len(cs))
@@ -99,16 +160,19 @@ func (c *Constraint) String() string {
99160
func parseSingle(v string) (*Constraint, error) {
100161
matches := constraintRegexp.FindStringSubmatch(v)
101162
if matches == nil {
102-
return nil, fmt.Errorf("Malformed constraint: %s", v)
163+
return nil, fmt.Errorf("malformed constraint: %s", v)
103164
}
104165

105166
check, err := NewVersion(matches[2])
106167
if err != nil {
107168
return nil, err
108169
}
109170

171+
cop := constraintOperators[matches[1]]
172+
110173
return &Constraint{
111-
f: constraintOperators[matches[1]],
174+
f: cop.f,
175+
op: cop.op,
112176
check: check,
113177
original: v,
114178
}, nil
@@ -122,10 +186,7 @@ func prereleaseCheck(v, c *Version) bool {
122186
return reflect.DeepEqual(c.Segments64(), v.Segments64())
123187

124188
case !cPre && vPre:
125-
// A constraint without a pre-release can only match a version without a
126-
// pre-release.
127-
return false
128-
189+
// OK
129190
case cPre && !vPre:
130191
// OK, except with the pessimistic operator
131192
case !cPre && !vPre:
@@ -138,6 +199,18 @@ func prereleaseCheck(v, c *Version) bool {
138199
// Constraint functions
139200
//-------------------------------------------------------------------
140201

202+
type operator rune
203+
204+
const (
205+
equal operator = '='
206+
notEqual operator = '≠'
207+
greaterThan operator = '>'
208+
lessThan operator = '<'
209+
greaterThanEqual operator = '≥'
210+
lessThanEqual operator = '≤'
211+
pessimistic operator = '~'
212+
)
213+
141214
func constraintEqual(v, c *Version) bool {
142215
return v.Equal(c)
143216
}
@@ -195,10 +268,5 @@ func constraintPessimistic(v, c *Version) bool {
195268
// Check the last part of the segment in the constraint. If the version segment at
196269
// this index is less than the constraints segment at this index, then it cannot
197270
// be valid against the constraint
198-
if c.segments[cs-1] > v.segments[cs-1] {
199-
return false
200-
}
201-
202-
// If nothing has rejected the version by now, it's valid
203-
return true
271+
return c.segments[cs-1] <= v.segments[cs-1]
204272
}

0 commit comments

Comments
 (0)