Skip to content

Instantly share code, notes, and snippets.

@fkautz
Created July 26, 2024 18:33
Show Gist options
  • Save fkautz/fc8cdf92b58777881e82d75b34b547e5 to your computer and use it in GitHub Desktop.
Save fkautz/fc8cdf92b58777881e82d75b34b547e5 to your computer and use it in GitHub Desktop.
// SPDX-License-Identifier: Apache-2.0
package ubuntu
import (
"regexp"
"sort"
"strconv"
"strings"
)
// Version represents a parsed version string
type Version struct {
Epoch int
Upstream string
Debian string
Ubuntu string
}
// ParseVersion parses a version string into its components
func ParseVersion(version string) Version {
var epoch int
upstream := version
debian := ""
ubuntu := ""
epochParts := strings.SplitN(version, ":", 2)
if len(epochParts) == 2 {
epoch, _ = strconv.Atoi(epochParts[0])
upstream = epochParts[1]
}
parts := strings.SplitN(upstream, "-", 2)
upstream = parts[0]
if len(parts) > 1 {
if strings.Contains(parts[1], "ubuntu") {
debianParts := strings.Split(parts[1], "ubuntu")
debian = debianParts[0]
ubuntu = debianParts[1]
} else {
debian = parts[1]
}
}
return Version{
Epoch: epoch,
Upstream: upstream,
Debian: debian,
Ubuntu: ubuntu,
}
}
// CompareVersions compares two version strings based on the Ubuntu version format
func CompareVersions(v1, v2 Version) bool {
if v1.Epoch != v2.Epoch {
return v1.Epoch < v2.Epoch
}
if v1.Upstream != v2.Upstream {
return compareSubversions(v1.Upstream, v2.Upstream)
}
if v1.Debian != v2.Debian {
return compareSubversions(v1.Debian, v2.Debian)
}
return compareSubversions(v1.Ubuntu, v2.Ubuntu)
}
// compareSubversions compares subversion strings correctly, handling numeric and alphanumeric parts
func compareSubversions(v1, v2 string) bool {
re := regexp.MustCompile(`(\d+|\D+)`)
v1Parts := re.FindAllString(v1, -1)
v2Parts := re.FindAllString(v2, -1)
for i := 0; i < len(v1Parts) && i < len(v2Parts); i++ {
v1Part := v1Parts[i]
v2Part := v2Parts[i]
v1Num, v1Err := strconv.Atoi(v1Part)
v2Num, v2Err := strconv.Atoi(v2Part)
if v1Err == nil && v2Err == nil {
if v1Num != v2Num {
return v1Num < v2Num
}
} else {
if v1Part != v2Part {
return v1Part < v2Part
}
}
}
return len(v1Parts) < len(v2Parts)
}
func Sort(versions []string) {
sort.Slice(versions, func(i, j int) bool {
vi := ParseVersion(versions[i])
vj := ParseVersion(versions[j])
return CompareVersions(vi, vj)
})
}
// SPDX-License-Identifier: Apache-2.0
package ubuntu
import (
"fmt"
"github.com/stretchr/testify/assert"
"testing"
)
func TestParseVersion1(t *testing.T) {
version := "14-20240412-0ubuntu1"
parsedVersion := ParseVersion(version)
fmt.Println(parsedVersion)
}
func TestParseVersion2(t *testing.T) {
version := "13ubuntu10"
parsedVersion := ParseVersion(version)
fmt.Println(parsedVersion)
}
func TestCompareVersion1(t *testing.T) {
small := "openssl-3.0.2-0ubuntu1.15"
large := "openssl-3.0.13-0ubuntu3.1"
res := CompareVersions(ParseVersion(small), ParseVersion(large))
assert.True(t, res, "expected true, got false")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment