Files
gitea-release-resource/vendor/github.com/cppforlife/go-semi-semantic/version/version_segment.go
2016-07-09 18:32:35 -07:00

183 lines
4.3 KiB
Go

package version
import (
"errors"
"fmt"
"strings"
)
type VerSegComp interface {
Validate() error
// Compare should panic if incompatible interface is given
Compare(VerSegComp) int
AsString() string
}
type VersionSegment struct {
Components []VerSegComp
}
func MustNewVersionSegmentFromString(v string) VersionSegment {
verSeg, err := NewVersionSegmentFromString(v)
if err != nil {
panic(fmt.Sprintf("Invalid version segment '%s': %s", v, err))
}
return verSeg
}
func NewVersionSegmentFromString(v string) (VersionSegment, error) {
pieces := strings.Split(v, ".")
components := []VerSegComp{}
for _, p := range pieces {
i, matchedI, err := NewVerSegCompIntFromString(p)
if err != nil {
errMsg := fmt.Sprintf("Expected component '%s' from version segment '%s' to be a parseable integer: %s", p, v, err)
return VersionSegment{}, errors.New(errMsg)
}
if matchedI {
components = append(components, i)
} else if s, matched := NewVerSegCompStrFromString(p); matched {
components = append(components, s)
} else {
errMsg := fmt.Sprintf("Expected component '%s' from version segment '%s' to be either an integer or a formatted string", p, v)
return VersionSegment{}, errors.New(errMsg)
}
}
return VersionSegment{components}, nil
}
func NewVersionSegment(components []VerSegComp) (VersionSegment, error) {
if len(components) == 0 {
return VersionSegment{}, errors.New("Expected version segment to be build from at least one component")
}
for _, c := range components {
err := c.Validate()
if err != nil {
return VersionSegment{}, err
}
}
return VersionSegment{components}, nil
}
func (s VersionSegment) Increment() (VersionSegment, error) {
if len(s.Components) == 0 {
errMsg := "Expected version segment to have at least one component to be incremented"
return VersionSegment{}, errors.New(errMsg)
}
lastComp := s.Components[len(s.Components)-1]
lastCompInt, isInt := lastComp.(VerSegCompInt)
if !isInt {
errMsg := fmt.Sprintf("Expected version segment '%s' to have last component '%s' to be an integer", s, lastComp)
return VersionSegment{}, errors.New(errMsg)
}
copiedComponents := make([]VerSegComp, len(s.Components))
copy(copiedComponents, s.Components)
copiedComponents[len(copiedComponents)-1] = VerSegCompInt{I: lastCompInt.I + 1}
return NewVersionSegment(copiedComponents)
}
func (s VersionSegment) Copy() VersionSegment {
// Don't use constructor; assuming that original components are valid
copiedComponents := make([]VerSegComp, len(s.Components))
copy(copiedComponents, s.Components)
return VersionSegment{copiedComponents}
}
func (s VersionSegment) Empty() bool { return len(s.Components) == 0 }
func (s VersionSegment) String() string { return s.AsString() }
func (s VersionSegment) AsString() string {
result := ""
for i, c := range s.Components {
result += c.AsString()
if i < len(s.Components)-1 {
result += "."
}
}
return result
}
func (s VersionSegment) Compare(other VersionSegment) int {
a := s.Components
b := other.Components
if len(a) > len(b) {
comparison := s.compareArrays(a[0:len(b)], b)
if comparison != 0 {
return comparison
}
if !s.isAllZeros(a[len(b):len(a)]) {
return 1
}
return 0
}
if len(a) < len(b) {
comparison := s.compareArrays(a, b[0:len(a)])
if comparison != 0 {
return comparison
}
if !s.isAllZeros(b[len(a):len(b)]) {
return -1
}
return 0
}
return s.compareArrays(a, b)
}
func (s VersionSegment) IsEq(other VersionSegment) bool { return s.Compare(other) == 0 }
func (s VersionSegment) IsGt(other VersionSegment) bool { return s.Compare(other) == 1 }
func (s VersionSegment) IsLt(other VersionSegment) bool { return s.Compare(other) == -1 }
// compareArrays compares 2 equally sized a & b
func (s VersionSegment) compareArrays(a, b []VerSegComp) int {
for i, v1 := range a {
v2 := b[i]
_, v1IsStr := v1.(VerSegCompStr)
_, v1IsInt := v1.(VerSegCompInt)
_, v2IsStr := v2.(VerSegCompStr)
_, v2IsInt := v2.(VerSegCompInt)
if v1IsStr && v2IsInt {
return 1
} else if v1IsInt && v2IsStr {
return -1
}
comparison := v1.Compare(v2)
if comparison != 0 {
return comparison
}
}
return 0
}
func (s VersionSegment) isAllZeros(a []VerSegComp) bool {
for _, v := range a {
vTyped, ok := v.(VerSegCompInt)
if !ok || vTyped.I != 0 {
return false
}
}
return true
}