From e4abf485677cd1d93d584753e19545e6ec8c2335 Mon Sep 17 00:00:00 2001 From: David Calavera <david.calavera@gmail.com> Date: Sun, 6 Dec 2015 19:29:15 -0500 Subject: [PATCH] Implement docker search with standalone client lib. Signed-off-by: David Calavera <david.calavera@gmail.com> --- api/client/client.go | 2 ++ api/client/lib/image_search.go | 39 ++++++++++++++++++++++++++++++++++ api/client/search.go | 33 ++++++++++++++++------------ 3 files changed, 61 insertions(+), 13 deletions(-) create mode 100644 api/client/lib/image_search.go diff --git a/api/client/client.go b/api/client/client.go index e3be35beb6..52dd4e5cd3 100644 --- a/api/client/client.go +++ b/api/client/client.go @@ -11,6 +11,7 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/cliconfig" "github.com/docker/docker/pkg/parsers/filters" + "github.com/docker/docker/registry" "github.com/docker/docker/runconfig" ) @@ -56,6 +57,7 @@ type apiClient interface { ImagePull(options types.ImagePullOptions, privilegeFunc lib.RequestPrivilegeFunc) (io.ReadCloser, error) ImagePush(options types.ImagePushOptions, privilegeFunc lib.RequestPrivilegeFunc) (io.ReadCloser, error) ImageRemove(options types.ImageRemoveOptions) ([]types.ImageDelete, error) + ImageSearch(options types.ImageSearchOptions, privilegeFunc lib.RequestPrivilegeFunc) ([]registry.SearchResult, error) ImageSave(imageIDs []string) (io.ReadCloser, error) ImageTag(options types.ImageTagOptions) error Info() (types.Info, error) diff --git a/api/client/lib/image_search.go b/api/client/lib/image_search.go new file mode 100644 index 0000000000..9d4a9ce81a --- /dev/null +++ b/api/client/lib/image_search.go @@ -0,0 +1,39 @@ +package lib + +import ( + "encoding/json" + "net/http" + "net/url" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/registry" +) + +// ImageSearch makes the docker host to search by a term in a remote registry. +// The list of results is not sorted in any fashion. +func (cli *Client) ImageSearch(options types.ImageSearchOptions, privilegeFunc RequestPrivilegeFunc) ([]registry.SearchResult, error) { + var results []registry.SearchResult + query := url.Values{} + query.Set("term", options.Term) + + resp, err := cli.tryImageSearch(query, options.RegistryAuth) + if resp.statusCode == http.StatusUnauthorized { + newAuthHeader, privilegeErr := privilegeFunc() + if privilegeErr != nil { + return results, privilegeErr + } + resp, err = cli.tryImageSearch(query, newAuthHeader) + } + if err != nil { + return results, err + } + defer ensureReaderClosed(resp) + + err = json.NewDecoder(resp.body).Decode(&results) + return results, err +} + +func (cli *Client) tryImageSearch(query url.Values, registryAuth string) (*serverResponse, error) { + headers := map[string][]string{"X-Registry-Auth": {registryAuth}} + return cli.get("/images/search", query, headers) +} diff --git a/api/client/search.go b/api/client/search.go index 1a47064477..fea66d55b7 100644 --- a/api/client/search.go +++ b/api/client/search.go @@ -1,26 +1,19 @@ package client import ( - "encoding/json" "fmt" "net/url" "sort" "strings" "text/tabwriter" + "github.com/docker/docker/api/types" Cli "github.com/docker/docker/cli" flag "github.com/docker/docker/pkg/mflag" "github.com/docker/docker/pkg/stringutils" "github.com/docker/docker/registry" ) -// ByStars sorts search results in ascending order by number of stars. -type ByStars []registry.SearchResult - -func (r ByStars) Len() int { return len(r) } -func (r ByStars) Swap(i, j int) { r[i], r[j] = r[j], r[i] } -func (r ByStars) Less(i, j int) bool { return r[i].StarCount < r[j].StarCount } - // CmdSearch searches the Docker Hub for images. // // Usage: docker search [OPTIONS] TERM @@ -42,19 +35,26 @@ func (cli *DockerCli) CmdSearch(args ...string) error { return err } - rdr, _, err := cli.clientRequestAttemptLogin("GET", "/images/search?"+v.Encode(), nil, nil, indexInfo, "search") + authConfig := registry.ResolveAuthConfig(cli.configFile, indexInfo) + requestPrivilege := cli.registryAuthenticationPrivilegedFunc(indexInfo, "search") + + encodedAuth, err := authConfig.EncodeToBase64() if err != nil { return err } - defer rdr.Close() + options := types.ImageSearchOptions{ + Term: name, + RegistryAuth: encodedAuth, + } - results := ByStars{} - if err := json.NewDecoder(rdr).Decode(&results); err != nil { + unorderedResults, err := cli.client.ImageSearch(options, requestPrivilege) + if err != nil { return err } - sort.Sort(sort.Reverse(results)) + results := searchResultsByStars(unorderedResults) + sort.Sort(results) w := tabwriter.NewWriter(cli.out, 10, 1, 3, ' ', 0) fmt.Fprintf(w, "NAME\tDESCRIPTION\tSTARS\tOFFICIAL\tAUTOMATED\n") @@ -81,3 +81,10 @@ func (cli *DockerCli) CmdSearch(args ...string) error { w.Flush() return nil } + +// SearchResultsByStars sorts search results in descending order by number of stars. +type searchResultsByStars []registry.SearchResult + +func (r searchResultsByStars) Len() int { return len(r) } +func (r searchResultsByStars) Swap(i, j int) { r[i], r[j] = r[j], r[i] } +func (r searchResultsByStars) Less(i, j int) bool { return r[j].StarCount < r[i].StarCount }