Upgrade go-version to one compatible with Nomad versioning

This commit is contained in:
Michael Schurter 2017-04-21 12:20:48 -07:00
parent a305b68159
commit 709c9425e4
5 changed files with 120 additions and 36 deletions

View file

@ -1,11 +0,0 @@
language: go
go:
- 1.0
- 1.1
- 1.2
- 1.3
- 1.4
script:
- go test

View file

@ -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

View file

@ -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))
}
@ -142,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
}

View file

@ -14,8 +14,8 @@ var versionRegexp *regexp.Regexp
// The raw regular expression string used for testing the validity
// of a version.
const VersionRegexpRaw string = `v?([0-9]+(\.[0-9]+){0,2})` +
`(-([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\-]+)*))?` +
`?`
@ -23,7 +23,7 @@ const VersionRegexpRaw string = `v?([0-9]+(\.[0-9]+){0,2})` +
type Version struct {
metadata string
pre string
segments []int
segments []int64
si int
}
@ -38,20 +38,23 @@ func NewVersion(v string) (*Version, error) {
if matches == nil {
return nil, fmt.Errorf("Malformed version: %s", v)
}
segmentsStr := strings.Split(matches[1], ".")
segments := make([]int, len(segmentsStr), 3)
segments := make([]int64, len(segmentsStr))
si := 0
for i, str := range segmentsStr {
val, err := strconv.ParseInt(str, 10, 32)
val, err := strconv.ParseInt(str, 10, 64)
if err != nil {
return nil, fmt.Errorf(
"Error parsing version: %s", err)
}
segments[i] = int(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)
}
@ -86,8 +89,8 @@ func (v *Version) Compare(other *Version) int {
return 0
}
segmentsSelf := v.Segments()
segmentsOther := other.Segments()
segmentsSelf := v.Segments64()
segmentsOther := other.Segments64()
// If the segments are the same, we must compare on prerelease info
if reflect.DeepEqual(segmentsSelf, segmentsOther) {
@ -106,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 []int64) bool {
for _, s := range segs {
if s != 0 {
return false
}
}
return true
}
func comparePart(preSelf string, preOther string) int {
@ -128,24 +166,38 @@ func comparePart(preSelf string, preOther string) int {
return 0
}
selfNumeric := true
_, err := strconv.ParseInt(preSelf, 10, 64)
if err != nil {
selfNumeric = false
}
otherNumeric := true
_, err = strconv.ParseInt(preOther, 10, 64)
if err != nil {
otherNumeric = false
}
// if a part is empty, we use the other to decide
if preSelf == "" {
_, notIsNumeric := strconv.ParseInt(preOther, 10, 64)
if notIsNumeric == nil {
if otherNumeric {
return -1
}
return 1
}
if preOther == "" {
_, notIsNumeric := strconv.ParseInt(preSelf, 10, 64)
if notIsNumeric == nil {
if selfNumeric {
return 1
}
return -1
}
if preSelf > preOther {
if selfNumeric && !otherNumeric {
return -1
} else if !selfNumeric && otherNumeric {
return 1
} else if preSelf > preOther {
return 1
}
@ -226,12 +278,25 @@ func (v *Version) Prerelease() string {
return v.pre
}
// Segments returns the numeric segments of the version as a slice.
// Segments returns the numeric segments of the version as a slice of ints.
//
// This excludes any metadata or pre-release information. For example,
// for a version "1.2.3-beta", segments will return a slice of
// 1, 2, 3.
func (v *Version) Segments() []int {
segmentSlice := make([]int, len(v.segments))
for i, v := range v.segments {
segmentSlice[i] = int(v)
}
return segmentSlice
}
// Segments64 returns the numeric segments of the version as a slice of int64s.
//
// This excludes any metadata or pre-release information. For example,
// for a version "1.2.3-beta", segments will return a slice of
// 1, 2, 3.
func (v *Version) Segments64() []int64 {
return v.segments
}
@ -239,7 +304,13 @@ func (v *Version) Segments() []int {
// 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.FormatInt(s, 10)
fmtParts[i] = str
}
fmt.Fprintf(&buf, strings.Join(fmtParts, "."))
if v.pre != "" {
fmt.Fprintf(&buf, "-%s", v.pre)
}

4
vendor/vendor.json vendored
View file

@ -743,8 +743,10 @@
"revision": "42a2b573b664dbf281bd48c3cc12c086b17a39ba"
},
{
"checksumSHA1": "tUGxc7rfX0cmhOOUDhMuAZ9rWsA=",
"path": "github.com/hashicorp/go-version",
"revision": "2e7f5ea8e27bb3fdf9baa0881d16757ac4637332"
"revision": "03c5bf6be031b6dd45afec16b1cf94fc8938bc77",
"revisionTime": "2017-02-02T08:07:59Z"
},
{
"checksumSHA1": "d9PxF1XQGLMJZRct2R8qVM/eYlE=",