From 7400f7f2b164a76b397a81d5b8d9e357c18ca1ad Mon Sep 17 00:00:00 2001 From: Radek Simko Date: Thu, 11 Nov 2021 13:48:36 +0000 Subject: [PATCH] Sort versions from releases JSON response --- internal/releasesjson/checksum_downloader.go | 4 +- internal/releasesjson/product_version.go | 41 ++++++++++++++++++++ internal/releasesjson/releases.go | 20 +++------- releases/latest_version.go | 13 ++----- releases/versions.go | 15 ++++--- 5 files changed, 60 insertions(+), 33 deletions(-) create mode 100644 internal/releasesjson/product_version.go diff --git a/internal/releasesjson/checksum_downloader.go b/internal/releasesjson/checksum_downloader.go index e37b985..4936dda 100644 --- a/internal/releasesjson/checksum_downloader.go +++ b/internal/releasesjson/checksum_downloader.go @@ -51,7 +51,7 @@ func (cd *ChecksumDownloader) DownloadAndVerifyChecksums() (ChecksumFileMap, err client := httpclient.NewHTTPClient() sigURL := fmt.Sprintf("%s/%s/%s/%s", cd.BaseURL, url.PathEscape(cd.ProductVersion.Name), - url.PathEscape(cd.ProductVersion.Version), + url.PathEscape(cd.ProductVersion.RawVersion), url.PathEscape(sigFilename)) cd.Logger.Printf("downloading signature from %s", sigURL) sigResp, err := client.Get(sigURL) @@ -67,7 +67,7 @@ func (cd *ChecksumDownloader) DownloadAndVerifyChecksums() (ChecksumFileMap, err shasumsURL := fmt.Sprintf("%s/%s/%s/%s", cd.BaseURL, url.PathEscape(cd.ProductVersion.Name), - url.PathEscape(cd.ProductVersion.Version), + url.PathEscape(cd.ProductVersion.RawVersion), url.PathEscape(cd.ProductVersion.SHASUMS)) cd.Logger.Printf("downloading checksums from %s", shasumsURL) sumsResp, err := client.Get(shasumsURL) diff --git a/internal/releasesjson/product_version.go b/internal/releasesjson/product_version.go new file mode 100644 index 0000000..5eecb01 --- /dev/null +++ b/internal/releasesjson/product_version.go @@ -0,0 +1,41 @@ +package releasesjson + +import "github.com/hashicorp/go-version" + +// ProductVersion is a wrapper around a particular product version like +// "consul 0.5.1". A ProductVersion may have one or more builds. +type ProductVersion struct { + Name string `json:"name"` + RawVersion string `json:"version"` + Version *version.Version `json:"-"` + SHASUMS string `json:"shasums,omitempty"` + SHASUMSSig string `json:"shasums_signature,omitempty"` + SHASUMSSigs []string `json:"shasums_signatures,omitempty"` + Builds ProductBuilds `json:"builds"` +} + +type ProductVersionsMap map[string]*ProductVersion + +type ProductVersions []*ProductVersion + +func (pv ProductVersions) Len() int { + return len(pv) +} + +func (pv ProductVersions) Less(i, j int) bool { + return pv[i].Version.LessThan(pv[j].Version) +} + +func (pv ProductVersions) Swap(i, j int) { + pv[i], pv[j] = pv[j], pv[i] +} + +func (pvm ProductVersionsMap) AsSlice() ProductVersions { + versions := make(ProductVersions, 0) + + for _, pVersion := range pvm { + versions = append(versions, pVersion) + } + + return versions +} diff --git a/internal/releasesjson/releases.go b/internal/releasesjson/releases.go index 3de19fa..24e32ff 100644 --- a/internal/releasesjson/releases.go +++ b/internal/releasesjson/releases.go @@ -18,19 +18,8 @@ const defaultBaseURL = "https://releases.hashicorp.com" // Product is a top-level product like "Consul" or "Nomad". A Product may have // one or more versions. type Product struct { - Name string `json:"name"` - Versions map[string]*ProductVersion `json:"versions"` -} - -// ProductVersion is a wrapper around a particular product version like -// "consul 0.5.1". A ProductVersion may have one or more builds. -type ProductVersion struct { - Name string `json:"name"` - Version string `json:"version"` - SHASUMS string `json:"shasums,omitempty"` - SHASUMSSig string `json:"shasums_signature,omitempty"` - SHASUMSSigs []string `json:"shasums_signatures,omitempty"` - Builds ProductBuilds `json:"builds"` + Name string `json:"name"` + Versions ProductVersionsMap `json:"versions"` } type ProductBuilds []*ProductBuild @@ -71,7 +60,7 @@ func (r *Releases) SetLogger(logger *log.Logger) { r.logger = logger } -func (r *Releases) ListProductVersions(ctx context.Context, productName string) (map[string]*ProductVersion, error) { +func (r *Releases) ListProductVersions(ctx context.Context, productName string) (ProductVersionsMap, error) { client := httpclient.NewHTTPClient() productIndexURL := fmt.Sprintf("%s/%s/index.json", @@ -122,7 +111,10 @@ func (r *Releases) ListProductVersions(ctx context.Context, productName string) // Remove (currently unsupported) enterprise // version and any other "custom" build delete(p.Versions, rawVersion) + continue } + + p.Versions[rawVersion].Version = v } return p.Versions, nil diff --git a/releases/latest_version.go b/releases/latest_version.go index c0bae40..c5c1807 100644 --- a/releases/latest_version.go +++ b/releases/latest_version.go @@ -149,20 +149,15 @@ func (lv *LatestVersion) Remove(ctx context.Context) error { return nil } -func (lv *LatestVersion) findLatestMatchingVersion(pvs map[string]*rjson.ProductVersion, vc version.Constraints) (*rjson.ProductVersion, bool) { +func (lv *LatestVersion) findLatestMatchingVersion(pvs rjson.ProductVersionsMap, vc version.Constraints) (*rjson.ProductVersion, bool) { versions := make(version.Collection, 0) - for _, pv := range pvs { - v, err := version.NewVersion(pv.Version) - if err != nil { - continue - } - - if !lv.IncludePrereleases && v.Prerelease() != "" { + for _, pv := range pvs.AsSlice() { + if !lv.IncludePrereleases && pv.Version.Prerelease() != "" { // skip prereleases if desired continue } - versions = append(versions, v) + versions = append(versions, pv.Version) } if len(versions) == 0 { diff --git a/releases/versions.go b/releases/versions.go index 618ec9b..bf0f799 100644 --- a/releases/versions.go +++ b/releases/versions.go @@ -3,6 +3,7 @@ package releases import ( "context" "fmt" + "sort" "time" "github.com/hashicorp/go-version" @@ -54,21 +55,19 @@ func (v *Versions) List(ctx context.Context) ([]src.Source, error) { return nil, err } - installables := make([]src.Source, 0) - for _, pv := range pvs { - installableVersion, err := version.NewVersion(pv.Version) - if err != nil { - continue - } + versions := pvs.AsSlice() + sort.Stable(versions) - if !v.Constraints.Check(installableVersion) { + installables := make([]src.Source, 0) + for _, pv := range versions { + if !v.Constraints.Check(pv.Version) { // skip version which doesn't match constraint continue } ev := &ExactVersion{ Product: v.Product, - Version: installableVersion, + Version: pv.Version, InstallDir: v.Install.Dir, Timeout: v.Install.Timeout,