248 lines
5.7 KiB
Go
248 lines
5.7 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package core
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"reflect"
|
|
|
|
"github.com/hashicorp/go-version"
|
|
"github.com/hashicorp/vagrant-plugin-sdk/core"
|
|
"github.com/mitchellh/mapstructure"
|
|
)
|
|
|
|
type BoxVersionProvider struct {
|
|
Name string
|
|
Url string
|
|
Checksum string
|
|
ChecksumType string
|
|
}
|
|
|
|
func (b *BoxVersionProvider) MatchesAny(p ...*BoxVersionProvider) (matches bool) {
|
|
for _, provider := range p {
|
|
if b.Matches(provider) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (b *BoxVersionProvider) Matches(p *BoxVersionProvider) (matches bool) {
|
|
pVal := reflect.ValueOf(*p)
|
|
bVal := reflect.ValueOf(*b)
|
|
typeOfMatcher := pVal.Type()
|
|
matches = true
|
|
|
|
fields := pVal.NumField()
|
|
for i := 0; i < fields; i++ {
|
|
if pVal.Field(i).Interface() != "" {
|
|
bField := bVal.FieldByName(typeOfMatcher.Field(i).Name).Interface()
|
|
pField := pVal.Field(i).Interface()
|
|
if pField != bField {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
type BoxVersion struct {
|
|
Version string
|
|
Status string
|
|
Description string
|
|
Providers []*BoxVersionProvider
|
|
}
|
|
|
|
func (b *BoxVersion) Provider(name string) (p *BoxVersionProvider, err error) {
|
|
for _, provider := range b.Providers {
|
|
if provider.Name == name {
|
|
return provider, nil
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func (b *BoxVersion) ListProviders() ([]string, error) {
|
|
p := []string{}
|
|
for _, provider := range b.Providers {
|
|
p = append(p, provider.Name)
|
|
}
|
|
return p, nil
|
|
}
|
|
|
|
type BoxMetadata struct {
|
|
Name string
|
|
Description string
|
|
Versions []*BoxVersion
|
|
}
|
|
|
|
func LoadBoxMetadata(data []byte) (*BoxMetadata, error) {
|
|
var metadata map[string]interface{}
|
|
if err := json.Unmarshal(data, &metadata); err != nil {
|
|
return nil, err
|
|
}
|
|
var result BoxMetadata
|
|
err := mapstructure.Decode(metadata, &result)
|
|
return &result, err
|
|
}
|
|
|
|
func (b *BoxMetadata) matches(version string, name string, p *core.BoxProvider) (matches bool, err error) {
|
|
ver, err := b.version(version, &core.BoxProvider{Name: name})
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
provider, err := ver.Provider(name)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
var boxVersionProvider *BoxVersionProvider
|
|
mapstructure.Decode(p, &boxVersionProvider)
|
|
return provider.Matches(boxVersionProvider), nil
|
|
}
|
|
|
|
func (b *BoxMetadata) matchesAny(version string, name string, p ...*core.BoxProvider) (matches bool, err error) {
|
|
for _, provider := range p {
|
|
m, err := b.matches(version, name, provider)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
if m {
|
|
return true, nil
|
|
}
|
|
}
|
|
return false, nil
|
|
}
|
|
|
|
func (b *BoxMetadata) version(ver string, providerOpts *core.BoxProvider) (v *BoxVersion, err error) {
|
|
matchesProvider := false
|
|
inputVersion, err := version.NewConstraint(ver)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, boxVer := range b.Versions {
|
|
boxVersion, err := version.NewVersion(boxVer.Version)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if inputVersion.Check(boxVersion) {
|
|
// Check for the provider in the version
|
|
if providerOpts == nil {
|
|
matchesProvider = true
|
|
} else {
|
|
for _, p := range boxVer.Providers {
|
|
boxVersionProvider := &BoxVersionProvider{
|
|
Name: providerOpts.Name, Url: providerOpts.Url, Checksum: providerOpts.Checksum,
|
|
ChecksumType: providerOpts.ChecksumType,
|
|
}
|
|
if p.Matches(boxVersionProvider) {
|
|
matchesProvider = true
|
|
}
|
|
}
|
|
}
|
|
if matchesProvider {
|
|
return boxVer, nil
|
|
}
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func (b *BoxMetadata) LoadMetadata(url string) (err error) {
|
|
client := &http.Client{}
|
|
req, _ := http.NewRequest("GET", url, nil)
|
|
req.Header.Set("Accept", "application/json")
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer resp.Body.Close()
|
|
raw, err := ioutil.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var metadata map[string]interface{}
|
|
if err := json.Unmarshal(raw, &metadata); err != nil {
|
|
return err
|
|
}
|
|
err = mapstructure.Decode(metadata, &b)
|
|
return
|
|
}
|
|
|
|
func (b *BoxMetadata) BoxName() string {
|
|
return b.Name
|
|
}
|
|
|
|
func (b *BoxMetadata) Version(ver string, providerOpts ...*core.BoxProvider) (v *core.BoxVersion, err error) {
|
|
if len(providerOpts) == 0 {
|
|
providerOpts = []*core.BoxProvider{
|
|
nil,
|
|
}
|
|
}
|
|
for _, p := range providerOpts {
|
|
boxVer, err := b.version(ver, p)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if boxVer != nil {
|
|
var coreBoxVersion *core.BoxVersion
|
|
mapstructure.Decode(boxVer, &coreBoxVersion)
|
|
return coreBoxVersion, nil
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func (b *BoxMetadata) ListVersions(providerOpts ...*core.BoxProvider) ([]string, error) {
|
|
v := []string{}
|
|
for _, version := range b.Versions {
|
|
if providerOpts != nil {
|
|
var boxVersionProvider []*BoxVersionProvider
|
|
mapstructure.Decode(providerOpts, &boxVersionProvider)
|
|
for _, p := range version.Providers {
|
|
if p.MatchesAny(boxVersionProvider...) {
|
|
v = append(v, version.Version)
|
|
}
|
|
}
|
|
} else {
|
|
v = append(v, version.Version)
|
|
}
|
|
}
|
|
return v, nil
|
|
}
|
|
|
|
func (b *BoxMetadata) Provider(version string, name string) (p *core.BoxProvider, err error) {
|
|
ver, err := b.version(version, &core.BoxProvider{Name: name})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if ver == nil {
|
|
return nil, err
|
|
}
|
|
provider, err := ver.Provider(name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if provider != nil {
|
|
var coreProvider *core.BoxProvider
|
|
mapstructure.Decode(provider, &coreProvider)
|
|
var coreVersion *core.BoxVersion
|
|
mapstructure.Decode(ver, &coreVersion)
|
|
coreProvider.Version = coreVersion
|
|
return coreProvider, nil
|
|
}
|
|
return
|
|
}
|
|
|
|
func (b *BoxMetadata) ListProviders(version string) (providers []string, err error) {
|
|
ver, err := b.version(version, &core.BoxProvider{})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return ver.ListProviders()
|
|
}
|
|
|
|
var _ core.BoxMetadata = (*BoxMetadata)(nil)
|