-
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Move pkg diff to separate package
- Loading branch information
Showing
9 changed files
with
186 additions
and
120 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
package diff | ||
|
||
import ( | ||
"cmp" | ||
"regexp" | ||
"strconv" | ||
) | ||
|
||
type Package map[string]string | ||
|
||
type PackageDiff struct { | ||
Name string `json:"name"` | ||
NewVersion string `json:"new_version,omitempty"` | ||
PreviousVersion string `json:"previous_version,omitempty"` | ||
} | ||
|
||
// This monstruosity is an adaptation of the regex for semver (available in https://semver.org/). | ||
// It SHOULD be able to capture every type of exoteric versioning scheme out there. | ||
var versionRegex = regexp.MustCompile(`^(?:(?P<prefix>\d+):)?(?P<major>\d+[a-zA-Z]?)(?:\.(?P<minor>\d+))?(?:\.(?P<patch>\d+))?(?:[-~](?P<prerelease>(?:\d+|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:\d+|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:[+.](?P<buildmetadata>[0-9a-zA-Z-+.]+(?:\.[0-9a-zA-Z-]+)*))?$`) | ||
|
||
// compareVersions has the same behavior as cmp.Compare, but for package versions. It parses | ||
// both version strings and checks for differences in major, minor, patch, pre-release, etc. | ||
func CompareVersions(a, b string) int { | ||
aMatchStr := versionRegex.FindStringSubmatch(a) | ||
aMatch := make(map[string]string) | ||
for i, name := range versionRegex.SubexpNames() { | ||
if i != 0 && name != "" && aMatchStr[i] != "" { | ||
aMatch[name] = aMatchStr[i] | ||
} | ||
} | ||
|
||
bMatchStr := versionRegex.FindStringSubmatch(b) | ||
bMatch := make(map[string]string) | ||
for i, name := range versionRegex.SubexpNames() { | ||
if i != 0 && name != "" && bMatchStr[i] != "" { | ||
bMatch[name] = bMatchStr[i] | ||
} | ||
} | ||
|
||
compResult := 0 | ||
|
||
compOrder := []string{"prefix", "major", "minor", "patch", "prerelease", "buildmetadata"} | ||
for _, comp := range compOrder { | ||
aValue, aOk := aMatch[comp] | ||
bValue, bOk := bMatch[comp] | ||
// If neither version has component or if they equal | ||
if !aOk && !bOk { | ||
continue | ||
} | ||
// If a has component but b doesn't, package was upgraded, unless it's prerelease | ||
if aOk && !bOk { | ||
if comp == "prerelease" { | ||
compResult = -1 | ||
} else { | ||
compResult = 1 | ||
} | ||
break | ||
} | ||
// If b has component but a doesn't, package was downgraded | ||
if !aOk && bOk { | ||
compResult = -1 | ||
break | ||
} | ||
|
||
// If both have, do regular compare | ||
aValueInt, aErr := strconv.Atoi(aValue) | ||
bValueInt, bErr := strconv.Atoi(bValue) | ||
|
||
var abComp int | ||
if aErr == nil && bErr == nil { | ||
abComp = cmp.Compare(aValueInt, bValueInt) | ||
} else { | ||
abComp = cmp.Compare(aValue, bValue) | ||
} | ||
if abComp == 0 { | ||
continue | ||
} | ||
compResult = abComp | ||
break | ||
} | ||
|
||
return compResult | ||
} | ||
|
||
// PackageDiff returns the difference in packages between two images, organized into | ||
// four slices: Added, Upgraded, Downgraded, and Removed packages, respectively. | ||
func DiffPackages(oldPackages, newPackages Package) ([]PackageDiff, []PackageDiff, []PackageDiff, []PackageDiff) { | ||
c := make(chan struct { | ||
PackageDiff | ||
int | ||
}) | ||
|
||
newPkgsCopy := make(Package, len(newPackages)) | ||
for k, v := range newPackages { | ||
newPkgsCopy[k] = v | ||
} | ||
|
||
for pkg, oldVersion := range oldPackages { | ||
if newVersion, ok := newPkgsCopy[pkg]; ok { | ||
go func(diff PackageDiff) { | ||
result := CompareVersions(diff.PreviousVersion, diff.NewVersion) | ||
c <- struct { | ||
PackageDiff | ||
int | ||
}{diff, result} | ||
}(PackageDiff{pkg, newVersion, oldVersion}) | ||
} else { | ||
go func(diff PackageDiff) { | ||
c <- struct { | ||
PackageDiff | ||
int | ||
}{diff, 2} | ||
}(PackageDiff{pkg, oldVersion, ""}) | ||
} | ||
|
||
// Clear package from copy so we can later check for removed packages | ||
delete(newPkgsCopy, pkg) | ||
} | ||
|
||
removed := []PackageDiff{} | ||
for pkg, version := range newPkgsCopy { | ||
removed = append(removed, PackageDiff{pkg, "", version}) | ||
} | ||
|
||
added := []PackageDiff{} | ||
upgraded := []PackageDiff{} | ||
downgraded := []PackageDiff{} | ||
for i := 0; i < len(oldPackages); i++ { | ||
pkg := <-c | ||
switch pkg.int { | ||
case -1: | ||
downgraded = append(downgraded, pkg.PackageDiff) | ||
case 1: | ||
upgraded = append(upgraded, pkg.PackageDiff) | ||
case 2: | ||
added = append(added, pkg.PackageDiff) | ||
} | ||
} | ||
|
||
return added, upgraded, downgraded, removed | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module github.com/vanilla-os/differ/diff | ||
|
||
go 1.21.4 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
go 1.21.4 | ||
|
||
use ( | ||
. | ||
./diff | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= | ||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= | ||
github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= | ||
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= | ||
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= | ||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= | ||
golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= | ||
golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= | ||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= | ||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.