diff --git a/util/distro.go b/util/distro.go new file mode 100644 index 00000000..ac191312 --- /dev/null +++ b/util/distro.go @@ -0,0 +1,112 @@ +// Mgmt +// Copyright (C) 2013-2024+ James Shubin and the project contributors +// Written by James Shubin and the project contributors +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// Additional permission under GNU GPL version 3 section 7 +// +// If you modify this program, or any covered work, by linking or combining it +// with embedded mcl code and modules (and that the embedded mcl code and +// modules which link with this program, contain a copy of their source code in +// the authoritative form) containing parts covered by the terms of any other +// license, the licensors of this program grant you additional permission to +// convey the resulting work. Furthermore, the licensors of this program grant +// the original author, James Shubin, additional permission to update this +// additional permission if he deems it necessary to achieve the goals of this +// additional permission. + +package util + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "strconv" +) + +const ( + // FedoraReleasesEndpointJSON is the location of the fedora release data + // as specified in json format. + FedoraReleasesEndpointJSON = "https://fedoraproject.org/releases.json" +) + +// FedoraRelease is a partial struct of the available data in the json releases +// file found. This was determined by inspection. +type FedoraRelease struct { + Version string `json:"version"` + Arch string `json:"arch"` + Variant string `json:"variant"` +} + +// LatestFedoraVersion returns the version number (as a string) of the latest +// fedora release known. This looks at a well-known endpoint to get the value. +// If you specify a non-empty arch, it will filter to that. +func LatestFedoraVersion(ctx context.Context, arch string) (string, error) { + client := &http.Client{} + + req, err := http.NewRequestWithContext(ctx, "GET", FedoraReleasesEndpointJSON, nil) + if err != nil { + return "", err + } + + res, err := client.Do(req) + if err != nil { + return "", err + } + defer res.Body.Close() + + // XXX: We should stream decode this instead. + b, err := io.ReadAll(res.Body) + if err != nil { + return "", err + } + + var data []FedoraRelease + if err := json.Unmarshal(b, &data); err != nil { + return "", err + } + + //fmt.Printf("len: %d\n", len(data)) + m := 0 + for _, r := range data { + version, err := strconv.Atoi(r.Version) + if err != nil { + return "", err + } + if arch != "" && arch != r.Arch { // skip others + continue + } + + m = max(m, version) + } + if m == 0 { + if arch == "" { + return "", fmt.Errorf("no versions found") + } + return "", fmt.Errorf("no versions found with arch: %s", arch) + } + //fmt.Printf("max: %d\n", m) + return strconv.Itoa(m), nil +} + +// TODO: remove this once golang 1.21 is out and it's a built-in. +func max(x, y int) int { + if x > y { + return x + } + return y +}