From d2a705aab6c94e930e2139adb593a14d377d567d Mon Sep 17 00:00:00 2001 From: Muhammad Hewedy Date: Thu, 10 Dec 2020 02:09:43 +0300 Subject: [PATCH] #35 consider vagrant images is the default add suggestion for images that appears in case of invalid image passed in create cmd --- command/images.go | 2 +- images/images.go | 2 +- images/vagrant/image_url.go | 83 +++++++++++++++++++++++++++++-------- 3 files changed, 68 insertions(+), 19 deletions(-) diff --git a/command/images.go b/command/images.go index da95657..3eeb78b 100644 --- a/command/images.go +++ b/command/images.go @@ -34,7 +34,7 @@ Images are cached after the first time it is downloaded. You can find images from Vagrant at: https://app.vagrantup.com/search example images: -* ubuntu/trusty64 +* ubuntu/focal64 * hashicorp/precise64 * generic/centos8 * generic/alpine38 diff --git a/images/images.go b/images/images.go index 6014ca5..82566c0 100644 --- a/images/images.go +++ b/images/images.go @@ -24,7 +24,7 @@ func Display() (string, error) { if len(list) == 0 { return `You can find images from Vagrant at: https://app.vagrantup.com/search example images: -* ubuntu/trusty64 +* ubuntu/focal64 * hashicorp/precise64 * generic/centos8 * generic/alpine38 diff --git a/images/vagrant/image_url.go b/images/vagrant/image_url.go index 17eac35..6e0533e 100644 --- a/images/vagrant/image_url.go +++ b/images/vagrant/image_url.go @@ -2,6 +2,7 @@ package vagrant import ( "encoding/json" + "errors" "fmt" "github.com/mhewedy/vermin/hypervisor" "github.com/mhewedy/vermin/progress" @@ -23,6 +24,12 @@ type version struct { Providers []provider `json:"providers"` } +type suggestionResp struct { + Boxes []struct { + Tag string `json:"tag"` + } `json:"boxes"` +} + func GetImageURL(image string) (string, error) { stop := progress.Show("Getting Image info from Vagrant Cloud", false) @@ -30,32 +37,22 @@ func GetImageURL(image string) (string, error) { user, imageName, imageVersion := getImageParts(image) - req, err := http.NewRequest("GET", fmt.Sprintf("https://app.vagrantup.com/%s/boxes/%s", user, imageName), nil) - if err != nil { - return "", err - } - - req.Header.Set("Accept", "application/json") - - client := &http.Client{} - resp, err := client.Do(req) - if err != nil { - return "", err - } - defer resp.Body.Close() - - b, err := ioutil.ReadAll(resp.Body) + bytes, err := sendAndReceive(fmt.Sprintf("https://app.vagrantup.com/%s/boxes/%s", user, imageName)) if err != nil { - return "", err + return "", nil } var obj vagrantResp - if err := json.Unmarshal(b, &obj); err != nil { + if err := json.Unmarshal(bytes, &obj); err != nil { return "", err } p, err := filterByVersion(obj, user, imageName, imageVersion) if err != nil { + suggest, _ := getSuggestion(imageName, "* ") + if suggest != nil && len(suggest) > 0 { + return "", errors.New(err.Error() + ", do you mean:\n" + strings.Join(suggest, "\n")) + } return "", err } @@ -114,3 +111,55 @@ func getImageParts(image string) (user string, imageName string, imageVersion st } return user, imageName, imageVersion } + +func getSuggestion(imageName, prepend string) ([]string, error) { + + h, err := hypervisor.GetHypervisorName(false) + if err != nil { + return nil, err + } + + bytes, err := sendAndReceive(fmt.Sprintf("https://app.vagrantup.com/api/v1/search?sort=downloads&provider=%s&q=%s&limit=2", + h, imageName)) + if err != nil { + return nil, nil + } + + var obj suggestionResp + if err := json.Unmarshal(bytes, &obj); err != nil { + return nil, err + } + + size := len(obj.Boxes) + if size == 0 { + return []string{}, nil + } + + result := make([]string, size) + for i, b := range obj.Boxes { + result[i] = prepend + b.Tag + } + return result, nil +} + +func sendAndReceive(url string) ([]byte, error) { + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return nil, err + } + + req.Header.Set("Accept", "application/json") + + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + b, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + return b, nil +}