-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Expand file tree
/
Copy pathsearch.go
More file actions
127 lines (110 loc) · 4.08 KB
/
search.go
File metadata and controls
127 lines (110 loc) · 4.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package registry
import (
"context"
"fmt"
"strings"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/formatter"
"github.com/docker/cli/internal/commands"
"github.com/docker/cli/opts"
"github.com/moby/moby/api/pkg/authconfig"
registrytypes "github.com/moby/moby/api/types/registry"
"github.com/moby/moby/client"
"github.com/spf13/cobra"
)
func init() {
commands.Register(newSearchCommand)
}
type searchOptions struct {
format string
term string
noTrunc bool
limit int
filter opts.FilterOpt
}
// newSearchCommand creates a new `docker search` command
func newSearchCommand(dockerCLI command.Cli) *cobra.Command {
options := searchOptions{filter: opts.NewFilterOpt()}
cmd := &cobra.Command{
Use: "search [OPTIONS] TERM",
Short: "Search Docker Hub for images",
Args: cli.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
options.term = args[0]
return runSearch(cmd.Context(), dockerCLI, options)
},
Annotations: map[string]string{
"category-top": "10",
},
DisableFlagsInUseLine: true,
}
flags := cmd.Flags()
flags.BoolVar(&options.noTrunc, "no-trunc", false, "Don't truncate output")
flags.VarP(&options.filter, "filter", "f", "Filter output based on conditions provided")
flags.IntVar(&options.limit, "limit", 0, "Max number of search results")
flags.StringVar(&options.format, "format", "", "Pretty-print search using a Go template")
return cmd
}
func runSearch(ctx context.Context, dockerCli command.Cli, options searchOptions) error {
if _, ok := options.filter.Value()["is-automated"]; ok {
_, _ = fmt.Fprintln(dockerCli.Err(), `WARNING: the "is-automated" filter is deprecated, and searching for "is-automated=true" will not yield any results in future.`)
}
encodedAuth, err := getAuth(dockerCli, options.term)
if err != nil {
return err
}
results, err := dockerCli.Client().ImageSearch(ctx, options.term, client.ImageSearchOptions{
RegistryAuth: encodedAuth,
PrivilegeFunc: nil,
Filters: options.filter.Value(),
Limit: options.limit,
})
if err != nil {
return err
}
searchCtx := formatter.Context{
Output: dockerCli.Out(),
Format: newFormat(options.format),
Trunc: !options.noTrunc,
}
return formatWrite(searchCtx, results)
}
// authConfigKey is the key used to store credentials for Docker Hub. It is
// a copy of [registry.IndexServer].
//
// [registry.IndexServer]: https://pkg.go.dev/github.com/docker/docker/registry#IndexServer
const authConfigKey = "https://index.docker.io/v1/"
// getAuth will use fetch auth based on the given search-term. If the search
// does not contain a hostname for the registry, it assumes Docker Hub is used,
// and resolves authentication for Docker Hub, otherwise it resolves authentication
// for the given registry.
func getAuth(dockerCLI command.Cli, reposName string) (encodedAuth string, err error) {
authCfgKey := splitReposSearchTerm(reposName)
if authCfgKey == "docker.io" || authCfgKey == "index.docker.io" {
authCfgKey = authConfigKey
}
// Ignoring errors here, which was the existing behavior (likely
// "no credentials found"). We'll get an error when search failed,
// so fine to ignore in most situations.
authConfig, _ := dockerCLI.ConfigFile().GetAuthConfig(authCfgKey)
return authconfig.Encode(registrytypes.AuthConfig{
Username: authConfig.Username,
Password: authConfig.Password,
ServerAddress: authConfig.ServerAddress,
// TODO(thaJeztah): Are these expected to be included?
Auth: authConfig.Auth,
IdentityToken: authConfig.IdentityToken,
RegistryToken: authConfig.RegistryToken,
})
}
// splitReposSearchTerm breaks a search term into an index name and remote name
func splitReposSearchTerm(reposName string) string {
nameParts := strings.SplitN(reposName, "/", 2)
if len(nameParts) == 1 || (!strings.Contains(nameParts[0], ".") && !strings.Contains(nameParts[0], ":") && nameParts[0] != "localhost") {
// This is a Docker Hub repository (ex: samalba/hipache or ubuntu),
// use the default Docker Hub registry (docker.io)
return "docker.io"
}
return nameParts[0]
}