github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/cmd/podman/search.go (about) 1 package main 2 3 import ( 4 "os" 5 "reflect" 6 "strings" 7 8 buildahcli "github.com/containers/buildah/pkg/cli" 9 "github.com/containers/buildah/pkg/formats" 10 "github.com/containers/image/v5/types" 11 "github.com/containers/libpod/cmd/podman/cliconfig" 12 "github.com/containers/libpod/libpod/image" 13 "github.com/pkg/errors" 14 "github.com/spf13/cobra" 15 ) 16 17 var ( 18 searchCommand cliconfig.SearchValues 19 searchDescription = `Search registries for a given image. Can search all the default registries or a specific registry. 20 21 Users can limit the number of results, and filter the output based on certain conditions.` 22 _searchCommand = &cobra.Command{ 23 Use: "search [flags] TERM", 24 Short: "Search registry for image", 25 Long: searchDescription, 26 RunE: func(cmd *cobra.Command, args []string) error { 27 searchCommand.InputArgs = args 28 searchCommand.GlobalFlags = MainGlobalOpts 29 searchCommand.Remote = remoteclient 30 return searchCmd(&searchCommand) 31 }, 32 Example: `podman search --filter=is-official --limit 3 alpine 33 podman search registry.fedoraproject.org/ # only works with v2 registries 34 podman search --format "table {{.Index}} {{.Name}}" registry.fedoraproject.org/fedora`, 35 } 36 ) 37 38 func init() { 39 searchCommand.Command = _searchCommand 40 searchCommand.SetHelpTemplate(HelpTemplate()) 41 searchCommand.SetUsageTemplate(UsageTemplate()) 42 flags := searchCommand.Flags() 43 flags.StringSliceVarP(&searchCommand.Filter, "filter", "f", []string{}, "Filter output based on conditions provided (default [])") 44 flags.StringVar(&searchCommand.Format, "format", "", "Change the output format to a Go template") 45 flags.IntVar(&searchCommand.Limit, "limit", 0, "Limit the number of results") 46 flags.BoolVar(&searchCommand.NoTrunc, "no-trunc", false, "Do not truncate the output") 47 // Disabled flags for the remote client 48 if !remote { 49 flags.StringVar(&searchCommand.Authfile, "authfile", buildahcli.GetDefaultAuthFile(), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override") 50 flags.BoolVar(&searchCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries") 51 } 52 } 53 54 func searchCmd(c *cliconfig.SearchValues) error { 55 args := c.InputArgs 56 if len(args) > 1 { 57 return errors.Errorf("too many arguments. Requires exactly 1") 58 } 59 if len(args) == 0 { 60 return errors.Errorf("no argument given, requires exactly 1 argument") 61 } 62 term := args[0] 63 64 filter, err := image.ParseSearchFilter(c.Filter) 65 if err != nil { 66 return err 67 } 68 69 if c.Authfile != "" { 70 if _, err := os.Stat(c.Authfile); err != nil { 71 return errors.Wrapf(err, "error getting authfile %s", c.Authfile) 72 } 73 } 74 75 searchOptions := image.SearchOptions{ 76 NoTrunc: c.NoTrunc, 77 Limit: c.Limit, 78 Filter: *filter, 79 Authfile: c.Authfile, 80 } 81 if c.Flag("tls-verify").Changed { 82 searchOptions.InsecureSkipTLSVerify = types.NewOptionalBool(!c.TlsVerify) 83 } 84 85 results, err := image.SearchImages(term, searchOptions) 86 if err != nil { 87 return err 88 } 89 format := genSearchFormat(c.Format) 90 if len(results) == 0 { 91 return nil 92 } 93 out := formats.StdoutTemplateArray{Output: searchToGeneric(results), Template: format, Fields: searchHeaderMap()} 94 return out.Out() 95 } 96 97 // searchHeaderMap returns the headers of a SearchResult. 98 func searchHeaderMap() map[string]string { 99 s := new(image.SearchResult) 100 v := reflect.Indirect(reflect.ValueOf(s)) 101 values := make(map[string]string, v.NumField()) 102 103 for i := 0; i < v.NumField(); i++ { 104 key := v.Type().Field(i).Name 105 value := key 106 values[key] = strings.ToUpper(splitCamelCase(value)) 107 } 108 return values 109 } 110 111 func genSearchFormat(format string) string { 112 if format != "" { 113 // "\t" from the command line is not being recognized as a tab 114 // replacing the string "\t" to a tab character if the user passes in "\t" 115 return strings.Replace(format, `\t`, "\t", -1) 116 } 117 return "table {{.Index}}\t{{.Name}}\t{{.Description}}\t{{.Stars}}\t{{.Official}}\t{{.Automated}}\t" 118 } 119 120 func searchToGeneric(params []image.SearchResult) (genericParams []interface{}) { 121 for _, v := range params { 122 genericParams = append(genericParams, interface{}(v)) 123 } 124 return genericParams 125 }