diff --git a/constraint.go b/constraint.go index 8c73df0..b53e497 100644 --- a/constraint.go +++ b/constraint.go @@ -34,6 +34,8 @@ func init() { ">=": constraintGreaterThanEqual, "<=": constraintLessThanEqual, "~>": constraintPessimistic, + "^": constraintCaret, + "~": constraintTilde, } ops := make([]string, 0, len(constraintOperators)) @@ -176,3 +178,29 @@ func constraintPessimistic(v, c *Version) bool { // If nothing has rejected the version by now, it's valid return true } + +func constraintCaret(v, c *Version) bool { + segments := c.Segments() + if segments[MajorPart] > 0 { + upperConstraint, _ := NewVersion(fmt.Sprintf("%d.%d.%d", segments[MajorPart]+1, 0, 0)) + return constraintGreaterThanEqual(v, c) && constraintLessThan(v, upperConstraint) + } + if segments[MinorPart] > 0 { + upperConstraint, _ := NewVersion(fmt.Sprintf("%d.%d.%d", 0, segments[MinorPart]+1, 0)) + return constraintGreaterThanEqual(v, c) && constraintLessThan(v, upperConstraint) + } + return constraintEqual(v, c) +} + +func constraintTilde(v, c *Version) bool { + segments := c.Segments() + if segments[MajorPart] > 0 { + upperConstraint, _ := NewVersion(fmt.Sprintf("%d.%d.%d", segments[MajorPart], segments[MinorPart]+1, 0)) + return constraintGreaterThanEqual(v, c) && constraintLessThan(v, upperConstraint) + } + if segments[MinorPart] > 0 { + upperConstraint, _ := NewVersion(fmt.Sprintf("%d.%d.%d", 0, segments[MinorPart]+1, 0)) + return constraintGreaterThanEqual(v, c) && constraintLessThan(v, upperConstraint) + } + return constraintEqual(v, c) +} diff --git a/constraint_test.go b/constraint_test.go index 2e733a4..568eb04 100644 --- a/constraint_test.go +++ b/constraint_test.go @@ -62,6 +62,28 @@ func TestConstraintCheck(t *testing.T) { {"~> 1.0.9.5", "1.0.9.6", true}, {"~> 1.0.9.5", "1.0.9.5.0", true}, {"~> 1.0.9.5", "1.0.9.5.1", true}, + {"^1.0.0", "1.0.0", true}, + {"^1.0.0", "1.0.1", true}, + {"^1.0.0", "1.9.1", true}, + {"^1.0.0", "2.0.0", false}, + {"^0.1.0", "0.1.0", true}, + {"^0.1.0", "0.2.0", false}, + {"^0.1.0", "0.1.4", true}, + {"^0.0.1", "0.0.0", false}, + {"^0.0.1", "0.0.1", true}, + {"^0.0.1", "0.0.2", false}, + {"^0.0.1", "0.2.0", false}, + {"~1.0.0", "1.0.0", true}, + {"~1.0.0", "1.0.1", true}, + {"~1.0.0", "1.9.1", false}, + {"~1.0.0", "2.0.0", false}, + {"~0.1.0", "0.1.0", true}, + {"~0.1.0", "0.2.0", false}, + {"~0.1.0", "0.1.4", true}, + {"~0.0.1", "0.0.0", false}, + {"~0.0.1", "0.0.1", true}, + {"~0.0.1", "0.0.2", false}, + {"~0.0.1", "0.2.0", false}, } for _, tc := range cases { diff --git a/version.go b/version.go index 488bd84..ef792a8 100644 --- a/version.go +++ b/version.go @@ -19,6 +19,16 @@ const VersionRegexpRaw string = `v?([0-9]+(\.[0-9]+)*?)` + `(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` + `?` +type VersionPart int + +const ( + MajorPart VersionPart = iota + MinorPart + PatchPart + PreReleasePart + MetadataPart +) + // Version represents a single version. type Version struct { metadata string