You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
terraformDummyRepo2/vendor/github.com/hashicorp/hc-install/internal/releasesjson/releases.go

187 lines
4.6 KiB
Go

package releasesjson
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"strings"
"github.com/hashicorp/go-version"
"github.com/hashicorp/hc-install/internal/httpclient"
)
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 ProductVersionsMap `json:"versions"`
}
type ProductBuilds []*ProductBuild
func (pbs ProductBuilds) FilterBuild(os string, arch string, suffix string) (*ProductBuild, bool) {
for _, pb := range pbs {
if pb.OS == os && pb.Arch == arch && strings.HasSuffix(pb.Filename, suffix) {
return pb, true
}
}
return nil, false
}
// ProductBuild is an OS/arch-specific representation of a product. This is the
// actual file that a user would download, like "consul_0.5.1_linux_amd64".
type ProductBuild struct {
Name string `json:"name"`
Version string `json:"version"`
OS string `json:"os"`
Arch string `json:"arch"`
Filename string `json:"filename"`
URL string `json:"url"`
}
type Releases struct {
logger *log.Logger
BaseURL string
}
func NewReleases() *Releases {
return &Releases{
logger: log.New(ioutil.Discard, "", 0),
BaseURL: defaultBaseURL,
}
}
func (r *Releases) SetLogger(logger *log.Logger) {
r.logger = logger
}
func (r *Releases) ListProductVersions(ctx context.Context, productName string) (ProductVersionsMap, error) {
client := httpclient.NewHTTPClient()
productIndexURL := fmt.Sprintf("%s/%s/index.json",
r.BaseURL,
url.PathEscape(productName))
r.logger.Printf("requesting versions from %s", productIndexURL)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, productIndexURL, nil)
if err != nil {
return nil, fmt.Errorf("failed to create request for %q: %w", productIndexURL, err)
}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
if resp.StatusCode != 200 {
return nil, fmt.Errorf("failed to obtain product versions from %q: %s ",
productIndexURL, resp.Status)
}
contentType := resp.Header.Get("content-type")
if contentType != "application/json" && contentType != "application/vnd+hashicorp.releases-api.v0+json" {
return nil, fmt.Errorf("unexpected Content-Type: %q", contentType)
}
defer resp.Body.Close()
r.logger.Printf("received %s", resp.Status)
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
p := Product{}
err = json.Unmarshal(body, &p)
if err != nil {
return nil, fmt.Errorf("%w: failed to unmarshal: %q",
err, string(body))
}
for rawVersion := range p.Versions {
v, err := version.NewVersion(rawVersion)
if err != nil {
// remove unparseable version
delete(p.Versions, rawVersion)
continue
}
if ok, _ := versionIsSupported(v); !ok {
// Remove (currently unsupported) enterprise
// version and any other "custom" build
delete(p.Versions, rawVersion)
continue
}
p.Versions[rawVersion].Version = v
}
return p.Versions, nil
}
func (r *Releases) GetProductVersion(ctx context.Context, product string, version *version.Version) (*ProductVersion, error) {
if ok, err := versionIsSupported(version); !ok {
return nil, fmt.Errorf("%s: %w", product, err)
}
client := httpclient.NewHTTPClient()
indexURL := fmt.Sprintf("%s/%s/%s/index.json",
r.BaseURL,
url.PathEscape(product),
url.PathEscape(version.String()))
r.logger.Printf("requesting version from %s", indexURL)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, indexURL, nil)
if err != nil {
return nil, fmt.Errorf("failed to create request for %q: %w", indexURL, err)
}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
if resp.StatusCode != 200 {
return nil, fmt.Errorf("failed to obtain product version from %q: %s ",
indexURL, resp.Status)
}
contentType := resp.Header.Get("content-type")
if contentType != "application/json" && contentType != "application/vnd+hashicorp.releases-api.v0+json" {
return nil, fmt.Errorf("unexpected Content-Type: %q", contentType)
}
defer resp.Body.Close()
r.logger.Printf("received %s", resp.Status)
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
pv := &ProductVersion{}
err = json.Unmarshal(body, pv)
if err != nil {
return nil, fmt.Errorf("%w: failed to unmarshal response: %q",
err, string(body))
}
return pv, nil
}
func versionIsSupported(v *version.Version) (bool, error) {
isSupported := v.Metadata() == ""
if !isSupported {
return false, fmt.Errorf("cannot obtain %s (enterprise versions are not supported)",
v.String())
}
return true, nil
}