refactor!: create and use TagDelta struct et al

add a TagDelta struct with accompanying function String()
rename UpgradeElement() to UpgradeDelta() and change the return type
move UpgradeType() to be a function of TagDelta
add ParseDelta() that returns a TagDelta from string
This commit is contained in:
knoflook 2021-10-11 14:29:22 +02:00
parent da6a8b1949
commit 0fed62dc8e
Signed by: knoflook
GPG Key ID: D6A1D0E8FC4FEF1C
1 changed files with 72 additions and 49 deletions

121
tagcmp.go
View File

@ -19,6 +19,12 @@ type Tag struct {
Metadata string // metadata: what's after + and after the first "-"
}
type TagDelta struct {
Major int // major semver difference
Minor int // minor semver difference
Patch int // patch semver difference
}
// ByTagAsc sorts tags in ascending order where the last element is the latest tag.
type ByTagAsc []Tag
@ -148,6 +154,12 @@ func (t Tag) String() string {
return repr
}
func (t TagDelta) String() string {
var repr string
repr = fmt.Sprintf("%d.%d.%d", t.Major, t.Minor, t.Patch)
return repr
}
// IsCompatible determines if two tags can be compared together
func (t Tag) IsCompatible(tag Tag) bool {
if t.UsesV && !tag.UsesV || tag.UsesV && !t.UsesV {
@ -175,43 +187,30 @@ func (t Tag) IsCompatible(tag Tag) bool {
return true
}
// UpgradeElement returns a Tag object which is the difference between an old and new tag
// UpgradeDelta returns a TagDelta object which is the difference between an old and new tag
// It can contain negative numbers if comparing with an older tag.
func (curTag Tag) UpgradeElement(newTag Tag) (Tag, error) {
func (curTag Tag) UpgradeDelta(newTag Tag) (TagDelta, error) {
if !curTag.IsCompatible(newTag) {
return Tag{}, fmt.Errorf("%s and %s are not compatible with each other", curTag.String(), newTag.String())
return TagDelta{}, fmt.Errorf("%s and %s are not compatible with each other", curTag.String(), newTag.String())
}
diff := curTag
curMajor, err := strconv.Atoi(curTag.Major)
if err != nil {
return Tag{}, err
diff := TagDelta{
Major: 0,
Minor: 0,
Patch: 0,
}
newMajor, err := strconv.Atoi(newTag.Major)
if err != nil {
return Tag{}, err
}
diff.Major = strconv.Itoa(newMajor - curMajor)
// assuming tags are correctly formatted
curMajor, _ := strconv.Atoi(curTag.Major)
newMajor, _ := strconv.Atoi(newTag.Major)
diff.Major = newMajor - curMajor
if !curTag.MissingMinor {
curMinor, err := strconv.Atoi(curTag.Minor)
if err != nil {
return Tag{}, err
}
newMinor, err := strconv.Atoi(newTag.Minor)
if err != nil {
return Tag{}, err
}
diff.Minor = strconv.Itoa(newMinor - curMinor)
curMinor, _ := strconv.Atoi(curTag.Minor)
newMinor, _ := strconv.Atoi(newTag.Minor)
diff.Minor = newMinor - curMinor
}
if !curTag.MissingPatch {
curPatch, err := strconv.Atoi(curTag.Patch)
if err != nil {
return Tag{}, err
}
newPatch, err := strconv.Atoi(newTag.Patch)
if err != nil {
return Tag{}, err
}
diff.Patch = strconv.Itoa(newPatch - curPatch)
curPatch, _ := strconv.Atoi(curTag.Patch)
newPatch, _ := strconv.Atoi(newTag.Patch)
diff.Patch = newPatch - curPatch
}
return diff, nil
@ -219,35 +218,23 @@ func (curTag Tag) UpgradeElement(newTag Tag) (Tag, error) {
// UpgradeType takes exit from UpgradeElemene and returns a numeric representation of upgrade or downgrade
// 1/-1: patch 2/-2: minor 4/-4: major 0: no change
func UpgradeType(t Tag) int {
var major, minor, patch int
major, _ = strconv.Atoi(t.Major)
if t.MissingMinor {
minor = 0
} else {
minor, _ = strconv.Atoi(t.Minor)
}
if t.MissingPatch {
patch = 0
} else {
patch, _ = strconv.Atoi(t.Patch)
}
if major > 0 {
func (d TagDelta) UpgradeType() int {
if d.Major > 0 {
return 4
}
if major < 0 {
if d.Major < 0 {
return -4
}
if minor > 0 {
if d.Minor > 0 {
return 2
}
if minor < 0 {
if d.Minor < 0 {
return -2
}
if patch > 0 {
if d.Patch > 0 {
return 1
}
if patch < 0 {
if d.Patch < 0 {
return -1
}
return 0
@ -306,6 +293,42 @@ func parseVersionPart(part string) (int, error) {
return p, nil
}
// ParseDelta converts a tag difference in the format of X, X.Y or X.Y.Z where
// X, Y, Z are positive or negative integers or 0
func ParseDelta(delta string) (TagDelta, error) {
tagDelta := TagDelta{
Major: 0,
Minor: 0,
Patch: 0,
}
splits := strings.Split(delta, ".")
if len(splits) > 3 {
return TagDelta{}, fmt.Errorf("'%s' has too much dots", delta)
}
major, err := strconv.Atoi(splits[0])
if err != nil {
return TagDelta{}, fmt.Errorf("Major part of '%s' is not an integer", delta)
}
tagDelta.Major = major
if len(splits) > 1 {
minor, err := strconv.Atoi(splits[1])
if err != nil {
return TagDelta{}, fmt.Errorf("Minor part of '%s' is not an integer", delta)
}
tagDelta.Minor = minor
}
if len(splits) > 2 {
patch, err := strconv.Atoi(splits[2])
if err != nil {
return TagDelta{}, fmt.Errorf("Minor part of '%s' is not an integer", delta)
}
tagDelta.Patch = patch
}
return tagDelta, nil
}
// Parse converts an image tag into a structured data format. It aims to to
// support the general case of tags which are "semver-like" and/or stable and
// parseable by heuristics. Image tags follow no formal specification and