github.com/portworx/docker@v1.12.1/api/client/image/search.go (about) 1 package image 2 3 import ( 4 "fmt" 5 "sort" 6 "strings" 7 "text/tabwriter" 8 9 "golang.org/x/net/context" 10 11 "github.com/docker/docker/api/client" 12 "github.com/docker/docker/cli" 13 "github.com/docker/docker/pkg/stringutils" 14 "github.com/docker/docker/registry" 15 "github.com/docker/engine-api/types" 16 "github.com/docker/engine-api/types/filters" 17 registrytypes "github.com/docker/engine-api/types/registry" 18 "github.com/spf13/cobra" 19 ) 20 21 type searchOptions struct { 22 term string 23 noTrunc bool 24 limit int 25 filter []string 26 27 // Deprecated 28 stars uint 29 automated bool 30 } 31 32 // NewSearchCommand create a new `docker search` command 33 func NewSearchCommand(dockerCli *client.DockerCli) *cobra.Command { 34 var opts searchOptions 35 36 cmd := &cobra.Command{ 37 Use: "search [OPTIONS] TERM", 38 Short: "Search the Docker Hub for images", 39 Args: cli.ExactArgs(1), 40 RunE: func(cmd *cobra.Command, args []string) error { 41 opts.term = args[0] 42 return runSearch(dockerCli, opts) 43 }, 44 } 45 46 flags := cmd.Flags() 47 48 flags.BoolVar(&opts.noTrunc, "no-trunc", false, "Don't truncate output") 49 flags.StringSliceVarP(&opts.filter, "filter", "f", []string{}, "Filter output based on conditions provided") 50 flags.IntVar(&opts.limit, "limit", registry.DefaultSearchLimit, "Max number of search results") 51 52 flags.BoolVar(&opts.automated, "automated", false, "Only show automated builds") 53 flags.UintVarP(&opts.stars, "stars", "s", 0, "Only displays with at least x stars") 54 55 flags.MarkDeprecated("automated", "use --filter=automated=true instead") 56 flags.MarkDeprecated("stars", "use --filter=stars=3 instead") 57 58 return cmd 59 } 60 61 func runSearch(dockerCli *client.DockerCli, opts searchOptions) error { 62 indexInfo, err := registry.ParseSearchIndexInfo(opts.term) 63 if err != nil { 64 return err 65 } 66 67 ctx := context.Background() 68 69 authConfig := dockerCli.ResolveAuthConfig(ctx, indexInfo) 70 requestPrivilege := dockerCli.RegistryAuthenticationPrivilegedFunc(indexInfo, "search") 71 72 encodedAuth, err := client.EncodeAuthToBase64(authConfig) 73 if err != nil { 74 return err 75 } 76 77 searchFilters := filters.NewArgs() 78 for _, f := range opts.filter { 79 var err error 80 searchFilters, err = filters.ParseFlag(f, searchFilters) 81 if err != nil { 82 return err 83 } 84 } 85 86 options := types.ImageSearchOptions{ 87 RegistryAuth: encodedAuth, 88 PrivilegeFunc: requestPrivilege, 89 Filters: searchFilters, 90 Limit: opts.limit, 91 } 92 93 clnt := dockerCli.Client() 94 95 unorderedResults, err := clnt.ImageSearch(ctx, opts.term, options) 96 if err != nil { 97 return err 98 } 99 100 results := searchResultsByStars(unorderedResults) 101 sort.Sort(results) 102 103 w := tabwriter.NewWriter(dockerCli.Out(), 10, 1, 3, ' ', 0) 104 fmt.Fprintf(w, "NAME\tDESCRIPTION\tSTARS\tOFFICIAL\tAUTOMATED\n") 105 for _, res := range results { 106 // --automated and -s, --stars are deprecated since Docker 1.12 107 if (opts.automated && !res.IsAutomated) || (int(opts.stars) > res.StarCount) { 108 continue 109 } 110 desc := strings.Replace(res.Description, "\n", " ", -1) 111 desc = strings.Replace(desc, "\r", " ", -1) 112 if !opts.noTrunc && len(desc) > 45 { 113 desc = stringutils.Truncate(desc, 42) + "..." 114 } 115 fmt.Fprintf(w, "%s\t%s\t%d\t", res.Name, desc, res.StarCount) 116 if res.IsOfficial { 117 fmt.Fprint(w, "[OK]") 118 119 } 120 fmt.Fprint(w, "\t") 121 if res.IsAutomated { 122 fmt.Fprint(w, "[OK]") 123 } 124 fmt.Fprint(w, "\n") 125 } 126 w.Flush() 127 return nil 128 } 129 130 // SearchResultsByStars sorts search results in descending order by number of stars. 131 type searchResultsByStars []registrytypes.SearchResult 132 133 func (r searchResultsByStars) Len() int { return len(r) } 134 func (r searchResultsByStars) Swap(i, j int) { r[i], r[j] = r[j], r[i] } 135 func (r searchResultsByStars) Less(i, j int) bool { return r[j].StarCount < r[i].StarCount }