Skip to content

Commit

Permalink
fix merging upstream
Browse files Browse the repository at this point in the history
  • Loading branch information
ctdk committed Oct 31, 2016
2 parents 098575c + deeb027 commit 0929ab3
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 19 deletions.
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ go:
- 1.0
- 1.1
- 1.2
- 1.3
- 1.4

script:
- go test
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Versioning Library for Go
[![Build Status](https://travis-ci.org/hashicorp/go-version.svg?branch=master)](https://travis-ci.org/hashicorp/go-version)
[![Build Status](https://travis-ci.org/hashicorp/go-version.svg?branch=master)](https://travis-ci.org/hashicorp/go-version)

go-version is a library for parsing versions and version constraints,
and verifying versions against a set of constraints. go-version
Expand Down
28 changes: 24 additions & 4 deletions constraint.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func init() {
}

ops := make([]string, 0, len(constraintOperators))
for k, _ := range constraintOperators {
for k := range constraintOperators {
ops = append(ops, regexp.QuoteMeta(k))
}

Expand Down Expand Up @@ -103,9 +103,7 @@ func parseSingle(v string) (*Constraint, error) {

check, err := NewVersion(matches[2])
if err != nil {
// This is a panic because the regular expression above should
// properly validate any version.
panic(err)
return nil, err
}

return &Constraint{
Expand Down Expand Up @@ -144,15 +142,37 @@ func constraintLessThanEqual(v, c *Version) bool {
}

func constraintPessimistic(v, c *Version) bool {
// If the version being checked is naturally less than the constraint, then there
// is no way for the version to be valid against the constraint
if v.LessThan(c) {
return false
}
// We'll use this more than once, so grab the length now so it's a little cleaner
// to write the later checks
cs := len(c.segments)

// If the version being checked has less specificity than the constraint, then there
// is no way for the version to be valid against the constraint
if cs > len(v.segments) {
return false
}

// Check the segments in the constraint against those in the version. If the version
// being checked, at any point, does not have the same values in each index of the
// constraints segments, then it cannot be valid against the constraint.
for i := 0; i < c.si-1; i++ {
if v.segments[i] != c.segments[i] {
return false
}
}

// Check the last part of the segment in the constraint. If the version segment at
// this index is less than the constraints segment at this index, then it cannot
// be valid against the constraint
if c.segments[cs-1] > v.segments[cs-1] {
return false
}

// If nothing has rejected the version by now, it's valid
return true
}
13 changes: 13 additions & 0 deletions constraint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ func TestNewConstraint(t *testing.T) {
{"1.0", 1, false},
{">= 1.x", 0, true},
{">= 1.2, < 1.0", 2, false},

// Out of bounds
{"11387778780781445675529500000000000000000", 0, true},
}

for _, tc := range cases {
Expand Down Expand Up @@ -49,6 +52,16 @@ func TestConstraintCheck(t *testing.T) {
{"~> 1.0.0", "1.0.7", true},
{"~> 1.0.0", "1.1.0", false},
{"~> 1.0.7", "1.0.4", false},
{"~> 1.0.7", "1.0.7", true},
{"~> 1.0.7", "1.0.8", true},
{"~> 1.0.7", "1.0.7.5", true},
{"~> 1.0.7", "1.0.6.99", false},
{"~> 1.0.7", "1.0.8.0", true},
{"~> 1.0.9.5", "1.0.9.5", true},
{"~> 1.0.9.5", "1.0.9.4", false},
{"~> 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},
}

for _, tc := range cases {
Expand Down
80 changes: 67 additions & 13 deletions version.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ var versionRegexp *regexp.Regexp

// The raw regular expression string used for testing the validity
// of a version.
const VersionRegexpRaw string = `([0-9]+(\.[0-9]+){0,2})` +
`(-([0-9A-Za-z]+(\.[0-9A-Za-z]+)*))?` +
`(\+([0-9A-Za-z]+(\.[0-9A-Za-z]+)*))?` +
const VersionRegexpRaw string = `v?([0-9]+(\.[0-9]+)*?)` +
`(-?([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` +
`(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` +
`?`

// Version represents a single version.
Expand All @@ -38,9 +38,8 @@ func NewVersion(v string) (*Version, error) {
if matches == nil {
return nil, fmt.Errorf("Malformed version: %s", v)
}

segmentsStr := strings.Split(matches[1], ".")
segments := make([]int64, len(segmentsStr), 3)
segments := make([]int64, len(segmentsStr))
si := 0
for i, str := range segmentsStr {
val, err := strconv.ParseInt(str, 10, 64)
Expand All @@ -49,9 +48,13 @@ func NewVersion(v string) (*Version, error) {
"Error parsing version: %s", err)
}

segments[i] = val
si += 1
segments[i] = int64(val)
si++
}

// Even though we could support more than three segments, if we
// got less than three, pad it with 0s. This is to cover the basic
// default usecase of semver, which is MAJOR.MINOR.PATCH at the minimum
for i := len(segments); i < 3; i++ {
segments = append(segments, 0)
}
Expand All @@ -64,6 +67,16 @@ func NewVersion(v string) (*Version, error) {
}, nil
}

// Must is a helper that wraps a call to a function returning (*Version, error)
// and panics if error is non-nil.
func Must(v *Version, err error) *Version {
if err != nil {
panic(err)
}

return v
}

// Compare compares this version to another version. This
// returns -1, 0, or 1 if this version is smaller, equal,
// or larger than the other version, respectively.
Expand Down Expand Up @@ -96,21 +109,56 @@ func (v *Version) Compare(other *Version) int {
return comparePrereleases(preSelf, preOther)
}

// Get the highest specificity (hS), or if they're equal, just use segmentSelf length
lenSelf := len(segmentsSelf)
lenOther := len(segmentsOther)
hS := lenSelf
if lenSelf < lenOther {
hS = lenOther
}
// Compare the segments
for i := 0; i < len(segmentsSelf); i++ {
// Because a constraint could have more/less specificity than the version it's
// checking, we need to account for a lopsided or jagged comparison
for i := 0; i < hS; i++ {
if i > lenSelf-1 {
// This means Self had the lower specificity
// Check to see if the remaining segments in Other are all zeros
if !allZero(segmentsOther[i:]) {
// if not, it means that Other has to be greater than Self
return -1
}
break
} else if i > lenOther-1 {
// this means Other had the lower specificity
// Check to see if the remaining segments in Self are all zeros -
if !allZero(segmentsSelf[i:]) {
//if not, it means that Self has to be greater than Other
return 1
}
break
}
lhs := segmentsSelf[i]
rhs := segmentsOther[i]

if lhs == rhs {
continue
} else if lhs < rhs {
return -1
} else {
return 1
}
// Otherwis, rhs was > lhs, they're not equal
return 1
}

panic("should not be reached")
// if we got this far, they're equal
return 0
}

func allZero(segs []int) bool {
for _, s := range segs {
if s != 0 {
return false
}
}
return true
}

func comparePart(preSelf string, preOther string) int {
Expand Down Expand Up @@ -229,7 +277,13 @@ func (v *Version) Segments() []int64 {
// and metadata information.
func (v *Version) String() string {
var buf bytes.Buffer
fmt.Fprintf(&buf, "%d.%d.%d", v.segments[0], v.segments[1], v.segments[2])
fmtParts := make([]string, len(v.segments))
for i, s := range v.segments {
// We can ignore err here since we've pre-parsed the values in segments
str := strconv.Itoa(s)
fmtParts[i] = str
}
fmt.Fprintf(&buf, strings.Join(fmtParts, "."))
if v.pre != "" {
fmt.Fprintf(&buf, "-%s", v.pre)
}
Expand Down
26 changes: 25 additions & 1 deletion version_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,17 @@ func TestNewVersion(t *testing.T) {
{"1.2-beta.5", false},
{"\n1.2", true},
{"1.2.0-x.Y.0+metadata", false},
{"1.2.3.4", true},
{"1.2.0-x.Y.0+metadata-width-hypen", false},
{"1.2.3-rc1-with-hypen", false},
{"1.2.3.4", false},
{"1.2.0.4-x.Y.0+metadata", false},
{"1.2.0.4-x.Y.0+metadata-width-hypen", false},
{"1.2.3.4-rc1-with-hypen", false},
{"1.2.3.4", false},
{"v1.2.3", false},
{"foo1.2.3", true},
{"1.7rc2", false},
{"v1.7rc2", false},
}

for _, tc := range cases {
Expand All @@ -43,6 +53,17 @@ func TestVersionCompare(t *testing.T) {
{"1.2", "1.1.4", 1},
{"1.2", "1.2-beta", 1},
{"1.2+foo", "1.2+beta", 0},
{"v1.2", "v1.2-beta", 1},
{"v1.2+foo", "v1.2+beta", 0},
{"v1.2.3.4", "v1.2.3.4", 0},
{"v1.2.0.0", "v1.2", 0},
{"v1.2.0.0.1", "v1.2", 1},
{"v1.2", "v1.2.0.0", 0},
{"v1.2", "v1.2.0.0.1", -1},
{"v1.2.0.0", "v1.2.0.0.1", -1},
{"v1.2.3.0", "v1.2.3.4", -1},
{"1.7rc2", "1.7rc1", 1},
{"1.7rc2", "1.7", -1},
}

for _, tc := range cases {
Expand Down Expand Up @@ -84,6 +105,9 @@ func TestComparePreReleases(t *testing.T) {
{"3.0-alpha3", "3.0-rc1", -1},
{"3.0-alpha.1", "3.0-alpha.beta", -1},
{"5.4-alpha", "5.4-alpha.beta", 1},
{"v1.2-beta.2", "v1.2-beta.2", 0},
{"v1.2-beta.1", "v1.2-beta.2", -1},
{"v3.2-alpha.1", "v3.2-alpha", 1},
}

for _, tc := range cases {
Expand Down

0 comments on commit 0929ab3

Please sign in to comment.