Skip to content

Commit

Permalink
feat: use engine API instead of Hub directly
Browse files Browse the repository at this point in the history
Signed-off-by: Alano Terblanche <[email protected]>
  • Loading branch information
Benehiko committed Oct 18, 2024
1 parent 5760a3d commit 5667a95
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 131 deletions.
124 changes: 0 additions & 124 deletions cli/command/completion/functions.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
package completion

import (
"encoding/json"
"net/http"
"net/url"
"os"
"strings"
"time"

"github.com/docker/cli/cli/command/formatter"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/volume"
"github.com/docker/docker/client"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -194,122 +189,3 @@ var commonPlatforms = []string{
func Platforms(_ *cobra.Command, _ []string, _ string) (platforms []string, _ cobra.ShellCompDirective) {
return commonPlatforms, cobra.ShellCompDirectiveNoFileComp
}

type ImageSearchResult struct {
ID string `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
Type string `json:"type"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
ShortDesc string `json:"short_description"`
Source string `json:"source"`
StarCount int `json:"star_count"`
}

type ImageSearch struct {
Totals int `json:"totals"`
Results []ImageSearchResult `json:"results"`
}

type Image struct {
ID int `json:"id"`
Name string `json:"name"`
TagStatus string `json:"tag_status"`
V2 bool `json:"v2"`
Digest string `json:"digest"`
LastUpdated time.Time `json:"last_updated"`
LastUpdater int `json:"last_updater"`
Creator int `json:"creator"`
Repository int `json:"repository"`
}

type ImageTags struct {
Count int `json:"count"`
Next string `json:"next"`
Prev string `json:"prev"`
Results []Image `json:"results"`
}

func RemoteImages(cmd *cobra.Command, arg []string, toComplete string) ([]string, cobra.ShellCompDirective) {
ctx := cmd.Context()
c := &http.Client{
Timeout: 2 * time.Second,
}

if imageName, imageTag, ok := strings.Cut(toComplete, ":"); ok {
u, err := url.Parse("https://hub.docker.com/v2/repositories/library/" + imageName + "/tags/")
if err != nil {
logrus.Errorf("Error parsing hub image tags URL: %v", err)
return nil, cobra.ShellCompDirectiveError
}
q := u.Query()
q.Set("ordering", "last_updated")
q.Set("page_size", "25")
q.Set("name", imageTag)
u.RawQuery = q.Encode()

req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)
if err != nil {
logrus.Errorf("Error creating hub image tags request: %v", err)
return nil, cobra.ShellCompDirectiveError
}

resp, err := c.Do(req)
if err != nil {
logrus.Errorf("Error sending hub image tags request: %v", err)
return nil, cobra.ShellCompDirectiveError
}
defer resp.Body.Close()

var tags *ImageTags
if err := json.NewDecoder(resp.Body).Decode(&tags); err != nil {
logrus.Errorf("Error decoding hub image tags response: %v", err)
return nil, cobra.ShellCompDirectiveError
}

names := make([]string, 0, len(tags.Results))
for _, i := range tags.Results {
names = append(names, imageName+":"+i.Name)
}
return names, cobra.ShellCompDirectiveNoFileComp
}

u, err := url.Parse("https://hub.docker.com/api/search/v3/catalog/search")
if err != nil {
logrus.Errorf("Error parsing hub image search URL: %v", err)
return nil, cobra.ShellCompDirectiveError
}
q := u.Query()
q.Set("query", toComplete)
q.Set("extension_reviewed", "")
q.Set("from", "0")
q.Set("size", "25")
u.RawQuery = q.Encode()

req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)
if err != nil {
logrus.Errorf("Error creating hub image search request: %v", err)
return nil, cobra.ShellCompDirectiveError
}

resp, err := c.Do(req)
if err != nil {
logrus.Errorf("Error sending hub image search request: %v", err)
return nil, cobra.ShellCompDirectiveError
}
defer resp.Body.Close()

var images *ImageSearch
if err := json.NewDecoder(resp.Body).Decode(&images); err != nil {
logrus.Errorf("Error decoding hub image search response: %v", err)
return nil, cobra.ShellCompDirectiveError
}

names := make([]string, 0, len(images.Results))
for _, i := range images.Results {
names = append(names, i.Name)
}

return names, cobra.ShellCompDirectiveNoFileComp
}
43 changes: 37 additions & 6 deletions cli/command/container/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/opts"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/hub"
"github.com/moby/sys/signal"
"github.com/moby/term"
"github.com/pkg/errors"
Expand Down Expand Up @@ -61,14 +62,44 @@ func NewRunCommand(dockerCli command.Cli) *cobra.Command {
}
}

remoteImages, shellCompRemote := completion.RemoteImages(cmd, args, toComplete)
if shellCompRemote != cobra.ShellCompDirectiveError {
if image, tag, found := strings.Cut(toComplete, ":"); found {
remoteTags, err := dockerCli.Client().ImageHubTags(cmd.Context(), image, hub.ImageOptions{
Name: tag,
Ordering: "last_updated",
Page: 0,
PageSize: 25,
})
if err == nil {
if len(all) == 0 {
all = make([]string, 0, len(remoteTags.Results))
}
for _, tag := range remoteTags.Results {
fullName := image + ":" + tag.Name
if _, ok := unique[fullName]; !ok {
all = append(all, fullName+"\tremote")
}
}
}
return all, cobra.ShellCompDirectiveKeepOrder | cobra.ShellCompDirectiveNoFileComp
}

remoteImages, err := dockerCli.Client().ImageHubSearch(cmd.Context(), toComplete, hub.SearchOptions{
From: 0,
Size: 25,
Type: hub.SearchTypeImage,
Order: hub.SearchOrderDesc,
Official: true,
Source: hub.SearchSourceStore,
OpenSource: true,
ExtensionReviewed: true,
})
if err == nil {
if len(all) == 0 {
all = make([]string, 0, len(remoteImages))
all = make([]string, 0, len(remoteImages.Results))
}
for _, img := range remoteImages {
if _, ok := unique[img]; !ok {
all = append(all, img+"\tremote")
for _, img := range remoteImages.Results {
if _, ok := unique[img.Name]; !ok {
all = append(all, img.Name+"\tremote")
}
}
}
Expand Down
46 changes: 45 additions & 1 deletion cli/command/image/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/trust"
"github.com/docker/docker/api/types/hub"

Check failure on line 13 in cli/command/image/pull.go

View workflow job for this annotation

GitHub Actions / codeql

cannot find module providing package github.com/docker/docker/api/types/hub: import lookup disabled by -mod=vendor
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -43,7 +44,50 @@ func NewPullCommand(dockerCli command.Cli) *cobra.Command {
if len(args) > 0 {
return nil, cobra.ShellCompDirectiveNoFileComp
}
return completion.RemoteImages(cmd, args, toComplete)

if image, tag, found := strings.Cut(toComplete, ":"); found {
remoteTags, err := dockerCli.Client().ImageHubTags(cmd.Context(), image, hub.ImageOptions{
Name: tag,
Ordering: "last_updated",
Page: 0,
PageSize: 25,
})
if err != nil {
return nil, cobra.ShellCompDirectiveError
}

images := make([]string, 0, len(remoteTags.Results))
for _, tag := range remoteTags.Results {
fullName := image + ":" + tag.Name
images = append(images, fullName+"\t"+tag.LastUpdated.String())
}
return images, cobra.ShellCompDirectiveKeepOrder | cobra.ShellCompDirectiveNoFileComp
}

remoteImages, err := dockerCli.Client().ImageHubSearch(cmd.Context(), toComplete, hub.SearchOptions{
From: 0,
Size: 25,
Type: hub.SearchTypeImage,
Order: hub.SearchOrderDesc,
Official: true,
Source: hub.SearchSourceStore,
OpenSource: true,
ExtensionReviewed: true,
})
if err != nil {
return nil, cobra.ShellCompDirectiveError
}

images := make([]string, 0, len(remoteImages.Results))
for _, img := range remoteImages.Results {
categories := make([]string, 0, len(img.Categories))
for _, cat := range img.Categories {
categories = append(categories, cat.Name)
}
images = append(images, img.Name+"\t"+strings.Join(categories, ", "))
}

return images, cobra.ShellCompDirectiveKeepOrder | cobra.ShellCompDirectiveNoFileComp
},
}

Expand Down

0 comments on commit 5667a95

Please sign in to comment.