diff --git a/constraints.go b/constraints.go index 8461c7e..5b20b4e 100644 --- a/constraints.go +++ b/constraints.go @@ -74,6 +74,28 @@ func (cs Constraints) Check(v *Version) bool { return false } +func (cs Constraints) CheckConstraints(cs2 *Constraints) bool { + for _, o := range cs.constraints { + joy := true + for _, c := range o { + for _, o2 := range cs2.constraints { + for _, c2 := range o2 { + if check, _ := c.checkConstraints(c2); !check { + joy = false + break + } + } + } + } + + if joy { + return true + } + } + + return false +} + // Validate checks if a version satisfies a constraint. If not a slice of // reasons for the failure are returned in addition to a bool. func (cs Constraints) Validate(v *Version) (bool, []error) { @@ -592,3 +614,44 @@ func rewriteRange(i string) string { return o } + +func (c *constraint) minVersionInConstraint() *Version { + switch c.origfunc { + case ">": + v, _ := NewVersion(c.con.String()) + + newV := v.IncPatch() + + return &newV + case ">=", "^": + v, _ := NewVersion(c.con.String()) + return v + case "~", "~>": + if c.con.Major() == 0 && c.con.Minor() == 0 && c.con.Patch() == 0 && !c.minorDirty && !c.patchDirty { + v, _ := NewVersion("0.0.0") + return v + } + + _c := *c + _c.origfunc = ">=" + return _c.minVersionInConstraint() + default: + return nil + } +} + +func (c *constraint) checkConstraints(c2 *constraint) (bool, error) { + min1 := c.minVersionInConstraint() + + min2 := c2.minVersionInConstraint() + + if min1 != nil { + return constraintOps[c2.origfunc](min1, c2) + } + + if min2 != nil { + return constraintOps[c.origfunc](min2, c) + } + + return true, nil +} diff --git a/constraints_test.go b/constraints_test.go index f519a48..a10748c 100644 --- a/constraints_test.go +++ b/constraints_test.go @@ -422,6 +422,39 @@ func TestConstraintsCheck(t *testing.T) { } } +func TestConstraintConstraintCheck(t *testing.T) { + tests := []struct { + con1 string + con2 string + expected bool + }{ + {"<1.2.3", "~1.3", false}, + {"<1.2.3", ">2", false}, + {">2.0.0", "<3.0.0", true}, + {">1", "<2.1", true}, + {">=1.2.x", "<=1.1.x", false}, + {">=1.2.x", "<=1.2.x", true}, + } + + for _, tc := range tests { + c, err := NewConstraint(tc.con1) + if err != nil { + t.Errorf("err: %s", err) + continue + } + + c2, err := NewConstraint(tc.con2) + if err != nil { + t.Errorf("err: %s", err) + continue + } + + if c.CheckConstraints(c2) != tc.expected { + t.Errorf("constraint '%s' did not match with constraint '%s'", tc.con1, tc.con2) + } + } +} + func TestRewriteRange(t *testing.T) { tests := []struct { c string