github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/cmd/podmanV2/images/search.go (about) 1 package images 2 3 import ( 4 "reflect" 5 "strings" 6 7 buildahcli "github.com/containers/buildah/pkg/cli" 8 "github.com/containers/buildah/pkg/formats" 9 "github.com/containers/image/v5/types" 10 "github.com/containers/libpod/cmd/podmanV2/registry" 11 "github.com/containers/libpod/pkg/domain/entities" 12 "github.com/containers/libpod/pkg/util/camelcase" 13 "github.com/pkg/errors" 14 "github.com/spf13/cobra" 15 "github.com/spf13/pflag" 16 ) 17 18 // searchOptionsWrapper wraps entities.ImagePullOptions and prevents leaking 19 // CLI-only fields into the API types. 20 type searchOptionsWrapper struct { 21 entities.ImageSearchOptions 22 // CLI only flags 23 TLSVerifyCLI bool // Used to convert to an optional bool later 24 Format string // For go templating 25 } 26 27 var ( 28 searchOptions = searchOptionsWrapper{} 29 searchDescription = `Search registries for a given image. Can search all the default registries or a specific registry. 30 31 Users can limit the number of results, and filter the output based on certain conditions.` 32 33 // Command: podman search 34 searchCmd = &cobra.Command{ 35 Use: "search [flags] TERM", 36 Short: "Search registry for image", 37 Long: searchDescription, 38 PreRunE: preRunE, 39 RunE: imageSearch, 40 Args: cobra.ExactArgs(1), 41 Example: `podman search --filter=is-official --limit 3 alpine 42 podman search registry.fedoraproject.org/ # only works with v2 registries 43 podman search --format "table {{.Index}} {{.Name}}" registry.fedoraproject.org/fedora`, 44 } 45 46 // Command: podman image search 47 imageSearchCmd = &cobra.Command{ 48 Use: searchCmd.Use, 49 Short: searchCmd.Short, 50 Long: searchCmd.Long, 51 PreRunE: searchCmd.PreRunE, 52 RunE: searchCmd.RunE, 53 Args: searchCmd.Args, 54 Example: `podman image search --filter=is-official --limit 3 alpine 55 podman image search registry.fedoraproject.org/ # only works with v2 registries 56 podman image search --format "table {{.Index}} {{.Name}}" registry.fedoraproject.org/fedora`, 57 } 58 ) 59 60 func init() { 61 // search 62 registry.Commands = append(registry.Commands, registry.CliCommand{ 63 Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, 64 Command: searchCmd, 65 }) 66 67 searchCmd.SetHelpTemplate(registry.HelpTemplate()) 68 searchCmd.SetUsageTemplate(registry.UsageTemplate()) 69 flags := searchCmd.Flags() 70 searchFlags(flags) 71 72 // images search 73 registry.Commands = append(registry.Commands, registry.CliCommand{ 74 Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, 75 Command: imageSearchCmd, 76 Parent: imageCmd, 77 }) 78 79 imageSearchFlags := imageSearchCmd.Flags() 80 searchFlags(imageSearchFlags) 81 } 82 83 // searchFlags set the flags for the pull command. 84 func searchFlags(flags *pflag.FlagSet) { 85 flags.StringSliceVarP(&searchOptions.Filters, "filter", "f", []string{}, "Filter output based on conditions provided (default [])") 86 flags.StringVar(&searchOptions.Format, "format", "", "Change the output format to a Go template") 87 flags.IntVar(&searchOptions.Limit, "limit", 0, "Limit the number of results") 88 flags.BoolVar(&searchOptions.NoTrunc, "no-trunc", false, "Do not truncate the output") 89 flags.StringVar(&searchOptions.Authfile, "authfile", buildahcli.GetDefaultAuthFile(), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override") 90 flags.BoolVar(&searchOptions.TLSVerifyCLI, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries") 91 if registry.IsRemote() { 92 _ = flags.MarkHidden("authfile") 93 _ = flags.MarkHidden("tls-verify") 94 } 95 } 96 97 // imageSearch implements the command for searching images. 98 func imageSearch(cmd *cobra.Command, args []string) error { 99 searchTerm := "" 100 switch len(args) { 101 case 1: 102 searchTerm = args[0] 103 default: 104 return errors.Errorf("search requires exactly one argument") 105 } 106 107 sarchOptsAPI := searchOptions.ImageSearchOptions 108 // TLS verification in c/image is controlled via a `types.OptionalBool` 109 // which allows for distinguishing among set-true, set-false, unspecified 110 // which is important to implement a sane way of dealing with defaults of 111 // boolean CLI flags. 112 if cmd.Flags().Changed("tls-verify") { 113 sarchOptsAPI.TLSVerify = types.NewOptionalBool(pullOptions.TLSVerifyCLI) 114 } 115 116 searchReport, err := registry.ImageEngine().Search(registry.GetContext(), searchTerm, sarchOptsAPI) 117 if err != nil { 118 return err 119 } 120 121 format := genSearchFormat(searchOptions.Format) 122 if len(searchReport) == 0 { 123 return nil 124 } 125 out := formats.StdoutTemplateArray{Output: searchToGeneric(searchReport), Template: format, Fields: searchHeaderMap()} 126 return out.Out() 127 } 128 129 // searchHeaderMap returns the headers of a SearchResult. 130 func searchHeaderMap() map[string]string { 131 s := new(entities.ImageSearchReport) 132 v := reflect.Indirect(reflect.ValueOf(s)) 133 values := make(map[string]string, v.NumField()) 134 135 for i := 0; i < v.NumField(); i++ { 136 key := v.Type().Field(i).Name 137 value := key 138 values[key] = strings.ToUpper(strings.Join(camelcase.Split(value), " ")) 139 } 140 return values 141 } 142 143 func genSearchFormat(format string) string { 144 if format != "" { 145 // "\t" from the command line is not being recognized as a tab 146 // replacing the string "\t" to a tab character if the user passes in "\t" 147 return strings.Replace(format, `\t`, "\t", -1) 148 } 149 return "table {{.Index}}\t{{.Name}}\t{{.Description}}\t{{.Stars}}\t{{.Official}}\t{{.Automated}}\t" 150 } 151 152 func searchToGeneric(params []entities.ImageSearchReport) (genericParams []interface{}) { 153 for _, v := range params { 154 genericParams = append(genericParams, interface{}(v)) 155 } 156 return genericParams 157 }