From b5d1d89a377e38762a75c2042dcc50a370ba6707 Mon Sep 17 00:00:00 2001 From: Paul Holzinger Date: Sun, 31 May 2020 17:35:59 +0200 Subject: Add shell completion with cobra Allow automatic generation for shell completion scripts with the internal cobra functions (requires v1.0.0+). This should replace the handwritten completion scripts and even adds support for fish. With this approach it is less likley that completions and code are out of sync. We can now create the scripts with - podman completion bash - podman completion zsh - podman completion fish To test the completion run: source <(podman completion bash) The same works for podman-remote and podman --remote and it will complete your remote containers/images with the correct endpoints values from --url/--connection. The completion logic is written in go and provided by the cobra library. The completion functions lives in `cmd/podman/completion/completion.go`. The unit test at cmd/podman/shell_completion_test.go checks if each command and flag has an autocompletion function set. This prevents that commands and flags have no shell completion set. This commit does not replace the current autocompletion scripts. Closes #6440 Signed-off-by: Paul Holzinger --- cmd/podman/images/build.go | 39 ++++++++++++++--------- cmd/podman/images/diff.go | 16 ++++++---- cmd/podman/images/exists.go | 12 ++++--- cmd/podman/images/history.go | 41 ++++++++++++++---------- cmd/podman/images/images.go | 3 +- cmd/podman/images/import.go | 42 ++++++++++++++++--------- cmd/podman/images/inspect.go | 15 ++++++--- cmd/podman/images/list.go | 40 +++++++++++++++++------- cmd/podman/images/load.go | 37 +++++++++++++--------- cmd/podman/images/mount.go | 22 ++++++++----- cmd/podman/images/prune.go | 20 +++++++----- cmd/podman/images/pull.go | 69 +++++++++++++++++++++++++++-------------- cmd/podman/images/push.go | 69 +++++++++++++++++++++++++++-------------- cmd/podman/images/rm.go | 10 +++--- cmd/podman/images/rmi.go | 13 ++++---- cmd/podman/images/save.go | 34 +++++++++++++------- cmd/podman/images/search.go | 60 +++++++++++++++++++++-------------- cmd/podman/images/sign.go | 27 +++++++++++----- cmd/podman/images/tag.go | 3 ++ cmd/podman/images/tree.go | 14 +++++---- cmd/podman/images/trust_set.go | 25 ++++++++++----- cmd/podman/images/trust_show.go | 14 +++++---- cmd/podman/images/unmount.go | 12 ++++--- cmd/podman/images/untag.go | 3 ++ 24 files changed, 411 insertions(+), 229 deletions(-) (limited to 'cmd/podman/images') diff --git a/cmd/podman/images/build.go b/cmd/podman/images/build.go index f48d1cd94..b9aabe64e 100644 --- a/cmd/podman/images/build.go +++ b/cmd/podman/images/build.go @@ -9,6 +9,7 @@ import ( "github.com/containers/buildah/imagebuildah" buildahCLI "github.com/containers/buildah/pkg/cli" "github.com/containers/buildah/pkg/parse" + "github.com/containers/common/pkg/completion" "github.com/containers/common/pkg/config" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/cmd/podman/utils" @@ -18,7 +19,6 @@ import ( "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/spf13/cobra" - "github.com/spf13/pflag" ) // buildFlagsWrapper are local to cmd/ as the build code is using Buildah-internal @@ -40,22 +40,24 @@ var ( // Command: podman _diff_ Object_ID buildDescription = "Builds an OCI or Docker image using instructions from one or more Containerfiles and a specified build context directory." buildCmd = &cobra.Command{ - Use: "build [options] [CONTEXT]", - Short: "Build an image using instructions from Containerfiles", - Long: buildDescription, - Args: cobra.MaximumNArgs(1), - RunE: build, + Use: "build [options] [CONTEXT]", + Short: "Build an image using instructions from Containerfiles", + Long: buildDescription, + Args: cobra.MaximumNArgs(1), + RunE: build, + ValidArgsFunction: completion.AutocompleteDefault, Example: `podman build . podman build --creds=username:password -t imageName -f Containerfile.simple . podman build --layers --force-rm --tag imageName .`, } imageBuildCmd = &cobra.Command{ - Args: buildCmd.Args, - Use: buildCmd.Use, - Short: buildCmd.Short, - Long: buildCmd.Long, - RunE: buildCmd.RunE, + Args: buildCmd.Args, + Use: buildCmd.Use, + Short: buildCmd.Short, + Long: buildCmd.Long, + RunE: buildCmd.RunE, + ValidArgsFunction: buildCmd.ValidArgsFunction, Example: `podman image build . podman image build --creds=username:password -t imageName -f Containerfile.simple . podman image build --layers --force-rm --tag imageName .`, @@ -79,22 +81,25 @@ func init() { Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, Command: buildCmd, }) - buildFlags(buildCmd.Flags()) + buildFlags(buildCmd) registry.Commands = append(registry.Commands, registry.CliCommand{ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, Command: imageBuildCmd, Parent: imageCmd, }) - buildFlags(imageBuildCmd.Flags()) + buildFlags(imageBuildCmd) } -func buildFlags(flags *pflag.FlagSet) { +func buildFlags(cmd *cobra.Command) { + flags := cmd.Flags() + // Podman flags flags.BoolVarP(&buildOpts.SquashAll, "squash-all", "", false, "Squash all layers into a single layer") // Bud flags budFlags := buildahCLI.GetBudFlags(&buildOpts.BudResults) + // --pull flag flag := budFlags.Lookup("pull") if err := flag.Value.Set("true"); err != nil { @@ -102,6 +107,9 @@ func buildFlags(flags *pflag.FlagSet) { } flag.DefValue = "true" flags.AddFlagSet(&budFlags) + // Add the completion functions + budCompletions := buildahCLI.GetBudFlagsCompletions() + completion.CompleteCommandFlags(cmd, budCompletions) // Layer flags layerFlags := buildahCLI.GetLayerFlags(&buildOpts.LayerResults) @@ -127,6 +135,9 @@ func buildFlags(flags *pflag.FlagSet) { os.Exit(1) } flags.AddFlagSet(&fromAndBudFlags) + // Add the completion functions + fromAndBudFlagsCompletions := buildahCLI.GetFromAndBudFlagsCompletions() + completion.CompleteCommandFlags(cmd, fromAndBudFlagsCompletions) _ = flags.MarkHidden("signature-policy") } diff --git a/cmd/podman/images/diff.go b/cmd/podman/images/diff.go index b7722e5e5..71793c707 100644 --- a/cmd/podman/images/diff.go +++ b/cmd/podman/images/diff.go @@ -13,11 +13,12 @@ import ( var ( // podman container _inspect_ diffCmd = &cobra.Command{ - Use: "diff [options] IMAGE", - Args: cobra.ExactArgs(1), - Short: "Inspect changes to the image's file systems", - Long: `Displays changes to the image's filesystem. The image will be compared to its parent layer.`, - RunE: diff, + Use: "diff [options] IMAGE", + Args: cobra.ExactArgs(1), + Short: "Inspect changes to the image's file systems", + Long: `Displays changes to the image's filesystem. The image will be compared to its parent layer.`, + RunE: diff, + ValidArgsFunction: common.AutocompleteImages, Example: `podman image diff myImage podman image diff --format json redis:alpine`, } @@ -37,7 +38,10 @@ func diffFlags(flags *pflag.FlagSet) { diffOpts = &entities.DiffOptions{} flags.BoolVar(&diffOpts.Archive, "archive", true, "Save the diff as a tar archive") _ = flags.MarkDeprecated("archive", "Provided for backwards compatibility, has no impact on output.") - flags.StringVar(&diffOpts.Format, "format", "", "Change the output format") + + formatFlagName := "format" + flags.StringVar(&diffOpts.Format, formatFlagName, "", "Change the output format") + _ = diffCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat) } func diff(cmd *cobra.Command, args []string) error { diff --git a/cmd/podman/images/exists.go b/cmd/podman/images/exists.go index 31bdc791e..cb1ca0295 100644 --- a/cmd/podman/images/exists.go +++ b/cmd/podman/images/exists.go @@ -1,6 +1,7 @@ package images import ( + "github.com/containers/podman/v2/cmd/podman/common" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/pkg/domain/entities" "github.com/spf13/cobra" @@ -8,11 +9,12 @@ import ( var ( existsCmd = &cobra.Command{ - Use: "exists IMAGE", - Short: "Check if an image exists in local storage", - Long: `If the named image exists in local storage, podman image exists exits with 0, otherwise the exit code will be 1.`, - Args: cobra.ExactArgs(1), - RunE: exists, + Use: "exists IMAGE", + Short: "Check if an image exists in local storage", + Long: `If the named image exists in local storage, podman image exists exits with 0, otherwise the exit code will be 1.`, + Args: cobra.ExactArgs(1), + RunE: exists, + ValidArgsFunction: common.AutocompleteImages, Example: `podman image exists ID podman image exists IMAGE && podman pull IMAGE`, DisableFlagsInUseLine: true, diff --git a/cmd/podman/images/history.go b/cmd/podman/images/history.go index e9751b365..964c7a975 100644 --- a/cmd/podman/images/history.go +++ b/cmd/podman/images/history.go @@ -11,13 +11,13 @@ import ( "unicode" "github.com/containers/common/pkg/report" + "github.com/containers/podman/v2/cmd/podman/common" "github.com/containers/podman/v2/cmd/podman/parse" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/pkg/domain/entities" "github.com/docker/go-units" "github.com/pkg/errors" "github.com/spf13/cobra" - "github.com/spf13/pflag" ) var ( @@ -27,21 +27,23 @@ var ( // podman _history_ historyCmd = &cobra.Command{ - Use: "history [options] IMAGE", - Short: "Show history of a specified image", - Long: long, - Args: cobra.ExactArgs(1), - RunE: history, - Example: "podman history quay.io/fedora/fedora", + Use: "history [options] IMAGE", + Short: "Show history of a specified image", + Long: long, + Args: cobra.ExactArgs(1), + RunE: history, + ValidArgsFunction: common.AutocompleteImages, + Example: "podman history quay.io/fedora/fedora", } imageHistoryCmd = &cobra.Command{ - Args: historyCmd.Args, - Use: historyCmd.Use, - Short: historyCmd.Short, - Long: historyCmd.Long, - RunE: historyCmd.RunE, - Example: `podman image history quay.io/fedora/fedora`, + Args: historyCmd.Args, + Use: historyCmd.Use, + Short: historyCmd.Short, + Long: historyCmd.Long, + ValidArgsFunction: historyCmd.ValidArgsFunction, + RunE: historyCmd.RunE, + Example: `podman image history quay.io/fedora/fedora`, } opts = struct { @@ -57,18 +59,23 @@ func init() { Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, Command: historyCmd, }) - historyFlags(historyCmd.Flags()) + historyFlags(historyCmd) registry.Commands = append(registry.Commands, registry.CliCommand{ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, Command: imageHistoryCmd, Parent: imageCmd, }) - historyFlags(imageHistoryCmd.Flags()) + historyFlags(imageHistoryCmd) } -func historyFlags(flags *pflag.FlagSet) { - flags.StringVar(&opts.format, "format", "", "Change the output to JSON or a Go template") +func historyFlags(cmd *cobra.Command) { + flags := cmd.Flags() + + formatFlagName := "format" + flags.StringVar(&opts.format, formatFlagName, "", "Change the output to JSON or a Go template") + _ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat) + flags.BoolVarP(&opts.human, "human", "H", true, "Display sizes and dates in human readable format") flags.BoolVar(&opts.noTrunc, "no-trunc", false, "Do not truncate the output") flags.BoolVar(&opts.noTrunc, "notruncate", false, "Do not truncate the output") diff --git a/cmd/podman/images/images.go b/cmd/podman/images/images.go index 14ea01047..499bfd2ad 100644 --- a/cmd/podman/images/images.go +++ b/cmd/podman/images/images.go @@ -16,6 +16,7 @@ var ( Short: listCmd.Short, Long: listCmd.Long, RunE: listCmd.RunE, + ValidArgsFunction: listCmd.ValidArgsFunction, Example: strings.Replace(listCmd.Example, "podman image list", "podman images", -1), DisableFlagsInUseLine: true, } @@ -27,5 +28,5 @@ func init() { Command: imagesCmd, }) - imageListFlagSet(imagesCmd.Flags()) + imageListFlagSet(imagesCmd) } diff --git a/cmd/podman/images/import.go b/cmd/podman/images/import.go index e3545da69..f38ab3b19 100644 --- a/cmd/podman/images/import.go +++ b/cmd/podman/images/import.go @@ -3,14 +3,16 @@ package images import ( "context" "fmt" + "strings" + "github.com/containers/common/pkg/completion" + "github.com/containers/podman/v2/cmd/podman/common" "github.com/containers/podman/v2/cmd/podman/parse" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/pkg/domain/entities" "github.com/hashicorp/go-multierror" "github.com/pkg/errors" "github.com/spf13/cobra" - "github.com/spf13/pflag" ) var ( @@ -19,21 +21,23 @@ var ( Note remote tar balls can be specified, via web address. Optionally tag the image. You can specify the instructions using the --change option.` importCommand = &cobra.Command{ - Use: "import [options] PATH [REFERENCE]", - Short: "Import a tarball to create a filesystem image", - Long: importDescription, - RunE: importCon, + Use: "import [options] PATH [REFERENCE]", + Short: "Import a tarball to create a filesystem image", + Long: importDescription, + RunE: importCon, + ValidArgsFunction: completion.AutocompleteDefault, Example: `podman import http://example.com/ctr.tar url-image cat ctr.tar | podman -q import --message "importing the ctr.tar tarball" - image-imported cat ctr.tar | podman import -`, } imageImportCommand = &cobra.Command{ - Args: cobra.MinimumNArgs(1), - Use: importCommand.Use, - Short: importCommand.Short, - Long: importCommand.Long, - RunE: importCommand.RunE, + Args: cobra.MinimumNArgs(1), + Use: importCommand.Use, + Short: importCommand.Short, + Long: importCommand.Long, + RunE: importCommand.RunE, + ValidArgsFunction: importCommand.ValidArgsFunction, Example: `podman image import http://example.com/ctr.tar url-image cat ctr.tar | podman -q image import --message "importing the ctr.tar tarball" - image-imported cat ctr.tar | podman image import -`, @@ -49,19 +53,27 @@ func init() { Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, Command: importCommand, }) - importFlags(importCommand.Flags()) + importFlags(importCommand) registry.Commands = append(registry.Commands, registry.CliCommand{ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, Command: imageImportCommand, Parent: imageCmd, }) - importFlags(imageImportCommand.Flags()) + importFlags(imageImportCommand) } -func importFlags(flags *pflag.FlagSet) { - flags.StringArrayVarP(&importOpts.Changes, "change", "c", []string{}, "Apply the following possible instructions to the created image (default []): CMD | ENTRYPOINT | ENV | EXPOSE | LABEL | STOPSIGNAL | USER | VOLUME | WORKDIR") - flags.StringVarP(&importOpts.Message, "message", "m", "", "Set commit message for imported image") +func importFlags(cmd *cobra.Command) { + flags := cmd.Flags() + + changeFlagName := "change" + flags.StringArrayVarP(&importOpts.Changes, changeFlagName, "c", []string{}, "Apply the following possible instructions to the created image (default []): "+strings.Join(common.ChangeCmds, " | ")) + _ = cmd.RegisterFlagCompletionFunc(changeFlagName, common.AutocompleteChangeInstructions) + + messageFlagName := "message" + flags.StringVarP(&importOpts.Message, messageFlagName, "m", "", "Set commit message for imported image") + _ = cmd.RegisterFlagCompletionFunc(messageFlagName, completion.AutocompleteNone) + flags.BoolVarP(&importOpts.Quiet, "quiet", "q", false, "Suppress output") flags.StringVar(&importOpts.SignaturePolicy, "signature-policy", "", "Path to a signature-policy file") _ = flags.MarkHidden("signature-policy") diff --git a/cmd/podman/images/inspect.go b/cmd/podman/images/inspect.go index 8f005553d..488f03760 100644 --- a/cmd/podman/images/inspect.go +++ b/cmd/podman/images/inspect.go @@ -1,6 +1,7 @@ package images import ( + "github.com/containers/podman/v2/cmd/podman/common" "github.com/containers/podman/v2/cmd/podman/inspect" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/pkg/domain/entities" @@ -10,10 +11,11 @@ import ( var ( // Command: podman image _inspect_ inspectCmd = &cobra.Command{ - Use: "inspect [options] IMAGE [IMAGE...]", - Short: "Display the configuration of an image", - Long: `Displays the low-level information of an image identified by name or ID.`, - RunE: inspectExec, + Use: "inspect [options] IMAGE [IMAGE...]", + Short: "Display the configuration of an image", + Long: `Displays the low-level information of an image identified by name or ID.`, + RunE: inspectExec, + ValidArgsFunction: common.AutocompleteImages, Example: `podman inspect alpine podman inspect --format "imageId: {{.Id}} size: {{.Size}}" alpine podman inspect --format "image: {{.ImageName}} driver: {{.Driver}}" myctr`, @@ -29,7 +31,10 @@ func init() { }) inspectOpts = new(entities.InspectOptions) flags := inspectCmd.Flags() - flags.StringVarP(&inspectOpts.Format, "format", "f", "json", "Format the output to a Go template or json") + + formatFlagName := "format" + flags.StringVarP(&inspectOpts.Format, formatFlagName, "f", "json", "Format the output to a Go template or json") + _ = inspectCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat) } func inspectExec(cmd *cobra.Command, args []string) error { diff --git a/cmd/podman/images/list.go b/cmd/podman/images/list.go index e24631b24..4692699f2 100644 --- a/cmd/podman/images/list.go +++ b/cmd/podman/images/list.go @@ -10,15 +10,16 @@ import ( "time" "unicode" + "github.com/containers/common/pkg/completion" "github.com/containers/common/pkg/report" "github.com/containers/image/v5/docker/reference" + "github.com/containers/podman/v2/cmd/podman/common" "github.com/containers/podman/v2/cmd/podman/parse" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/pkg/domain/entities" "github.com/docker/go-units" "github.com/pkg/errors" "github.com/spf13/cobra" - "github.com/spf13/pflag" ) type listFlagType struct { @@ -35,12 +36,13 @@ type listFlagType struct { var ( // Command: podman image _list_ listCmd = &cobra.Command{ - Use: "list [options] [IMAGE]", - Aliases: []string{"ls"}, - Args: cobra.MaximumNArgs(1), - Short: "List images in local storage", - Long: "Lists images previously pulled to the system or created on the system.", - RunE: images, + Use: "list [options] [IMAGE]", + Aliases: []string{"ls"}, + Args: cobra.MaximumNArgs(1), + Short: "List images in local storage", + Long: "Lists images previously pulled to the system or created on the system.", + RunE: images, + ValidArgsFunction: common.AutocompleteImages, Example: `podman image list --format json podman image list --sort repository --format "table {{.ID}} {{.Repository}} {{.Tag}}" podman image list --filter dangling=true`, @@ -67,18 +69,32 @@ func init() { Command: listCmd, Parent: imageCmd, }) - imageListFlagSet(listCmd.Flags()) + imageListFlagSet(listCmd) } -func imageListFlagSet(flags *pflag.FlagSet) { +func imageListFlagSet(cmd *cobra.Command) { + flags := cmd.Flags() + flags.BoolVarP(&listOptions.All, "all", "a", false, "Show all images (default hides intermediate images)") - flags.StringSliceVarP(&listOptions.Filter, "filter", "f", []string{}, "Filter output based on conditions provided (default [])") - flags.StringVar(&listFlag.format, "format", "", "Change the output format to JSON or a Go template") + + filterFlagName := "filter" + flags.StringSliceVarP(&listOptions.Filter, filterFlagName, "f", []string{}, "Filter output based on conditions provided (default [])") + // TODO: add completion function for filters + _ = cmd.RegisterFlagCompletionFunc(filterFlagName, completion.AutocompleteNone) + + formatFlagName := "format" + flags.StringVar(&listFlag.format, formatFlagName, "", "Change the output format to JSON or a Go template") + _ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat) + flags.BoolVar(&listFlag.digests, "digests", false, "Show digests") flags.BoolVarP(&listFlag.noHeading, "noheading", "n", false, "Do not print column headings") flags.BoolVar(&listFlag.noTrunc, "no-trunc", false, "Do not truncate output") flags.BoolVarP(&listFlag.quiet, "quiet", "q", false, "Display only image IDs") - flags.StringVar(&listFlag.sort, "sort", "created", "Sort by "+sortFields.String()) + + sortFlagName := "sort" + flags.StringVar(&listFlag.sort, sortFlagName, "created", "Sort by "+sortFields.String()) + _ = cmd.RegisterFlagCompletionFunc(sortFlagName, completion.AutocompleteNone) + flags.BoolVarP(&listFlag.history, "history", "", false, "Display the image name history") } diff --git a/cmd/podman/images/load.go b/cmd/podman/images/load.go index 02f1b3b39..a7884f4c5 100644 --- a/cmd/podman/images/load.go +++ b/cmd/podman/images/load.go @@ -8,6 +8,7 @@ import ( "os" "strings" + "github.com/containers/common/pkg/completion" "github.com/containers/image/v5/docker/reference" "github.com/containers/podman/v2/cmd/podman/parse" "github.com/containers/podman/v2/cmd/podman/registry" @@ -15,26 +16,27 @@ import ( "github.com/containers/podman/v2/pkg/util" "github.com/pkg/errors" "github.com/spf13/cobra" - "github.com/spf13/pflag" "golang.org/x/crypto/ssh/terminal" ) var ( loadDescription = "Loads an image from a locally stored archive (tar file) into container storage." loadCommand = &cobra.Command{ - Use: "load [options] [NAME[:TAG]]", - Short: "Load an image from container archive", - Long: loadDescription, - RunE: load, - Args: cobra.MaximumNArgs(1), + Use: "load [options] [NAME[:TAG]]", + Short: "Load an image from container archive", + Long: loadDescription, + RunE: load, + Args: cobra.MaximumNArgs(1), + ValidArgsFunction: completion.AutocompleteNone, } imageLoadCommand = &cobra.Command{ - Args: loadCommand.Args, - Use: loadCommand.Use, - Short: loadCommand.Short, - Long: loadCommand.Long, - RunE: loadCommand.RunE, + Args: loadCommand.Args, + Use: loadCommand.Use, + Short: loadCommand.Short, + Long: loadCommand.Long, + ValidArgsFunction: loadCommand.ValidArgsFunction, + RunE: loadCommand.RunE, } ) @@ -47,17 +49,22 @@ func init() { Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, Command: loadCommand, }) - loadFlags(loadCommand.Flags()) + loadFlags(loadCommand) registry.Commands = append(registry.Commands, registry.CliCommand{ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, Command: imageLoadCommand, Parent: imageCmd, }) - loadFlags(imageLoadCommand.Flags()) + loadFlags(imageLoadCommand) } -func loadFlags(flags *pflag.FlagSet) { - flags.StringVarP(&loadOpts.Input, "input", "i", "", "Read from specified archive file (default: stdin)") +func loadFlags(cmd *cobra.Command) { + flags := cmd.Flags() + + inputFlagName := "input" + flags.StringVarP(&loadOpts.Input, inputFlagName, "i", "", "Read from specified archive file (default: stdin)") + _ = cmd.RegisterFlagCompletionFunc(inputFlagName, completion.AutocompleteDefault) + flags.BoolVarP(&loadOpts.Quiet, "quiet", "q", false, "Suppress the output") flags.StringVar(&loadOpts.SignaturePolicy, "signature-policy", "", "Pathname of signature policy file") _ = flags.MarkHidden("signature-policy") diff --git a/cmd/podman/images/mount.go b/cmd/podman/images/mount.go index 28e9264ee..1eac59ef9 100644 --- a/cmd/podman/images/mount.go +++ b/cmd/podman/images/mount.go @@ -7,12 +7,12 @@ import ( "text/template" "github.com/containers/common/pkg/report" + "github.com/containers/podman/v2/cmd/podman/common" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/cmd/podman/utils" "github.com/containers/podman/v2/pkg/domain/entities" "github.com/pkg/errors" "github.com/spf13/cobra" - "github.com/spf13/pflag" ) var ( @@ -24,10 +24,11 @@ var ( ` mountCommand = &cobra.Command{ - Use: "mount [options] [IMAGE...]", - Short: "Mount an image's root filesystem", - Long: mountDescription, - RunE: mount, + Use: "mount [options] [IMAGE...]", + Short: "Mount an image's root filesystem", + Long: mountDescription, + RunE: mount, + ValidArgsFunction: common.AutocompleteImages, Example: `podman image mount imgID podman image mount imgID1 imgID2 imgID3 podman image mount @@ -43,9 +44,14 @@ var ( mountOpts entities.ImageMountOptions ) -func mountFlags(flags *pflag.FlagSet) { +func mountFlags(cmd *cobra.Command) { + flags := cmd.Flags() + flags.BoolVarP(&mountOpts.All, "all", "a", false, "Mount all images") - flags.StringVar(&mountOpts.Format, "format", "", "Print the mounted images in specified format (json)") + + formatFlagName := "format" + flags.StringVar(&mountOpts.Format, formatFlagName, "", "Print the mounted images in specified format (json)") + _ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat) } func init() { @@ -54,7 +60,7 @@ func init() { Command: mountCommand, Parent: imageCmd, }) - mountFlags(mountCommand.Flags()) + mountFlags(mountCommand) } func mount(cmd *cobra.Command, args []string) error { diff --git a/cmd/podman/images/prune.go b/cmd/podman/images/prune.go index b6e6b9562..3af56b015 100644 --- a/cmd/podman/images/prune.go +++ b/cmd/podman/images/prune.go @@ -6,6 +6,7 @@ import ( "os" "strings" + "github.com/containers/common/pkg/completion" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/cmd/podman/utils" "github.com/containers/podman/v2/cmd/podman/validate" @@ -19,12 +20,13 @@ var ( If an image is not being used by a container, it will be removed from the system.` pruneCmd = &cobra.Command{ - Use: "prune [options]", - Args: validate.NoArgs, - Short: "Remove unused images", - Long: pruneDescription, - RunE: prune, - Example: `podman image prune`, + Use: "prune [options]", + Args: validate.NoArgs, + Short: "Remove unused images", + Long: pruneDescription, + RunE: prune, + ValidArgsFunction: completion.AutocompleteNone, + Example: `podman image prune`, } pruneOpts = entities.ImagePruneOptions{} @@ -42,7 +44,11 @@ func init() { flags := pruneCmd.Flags() flags.BoolVarP(&pruneOpts.All, "all", "a", false, "Remove all unused images, not just dangling ones") flags.BoolVarP(&force, "force", "f", false, "Do not prompt for confirmation") - flags.StringArrayVar(&filter, "filter", []string{}, "Provide filter values (e.g. 'label==')") + + filterFlagName := "filter" + flags.StringArrayVar(&filter, filterFlagName, []string{}, "Provide filter values (e.g. 'label==')") + //TODO: add completion for filters + _ = pruneCmd.RegisterFlagCompletionFunc(filterFlagName, completion.AutocompleteNone) } diff --git a/cmd/podman/images/pull.go b/cmd/podman/images/pull.go index ab3b0a197..a6f41688c 100644 --- a/cmd/podman/images/pull.go +++ b/cmd/podman/images/pull.go @@ -5,12 +5,13 @@ import ( "os" "github.com/containers/common/pkg/auth" + "github.com/containers/common/pkg/completion" "github.com/containers/image/v5/types" + "github.com/containers/podman/v2/cmd/podman/common" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/pkg/domain/entities" "github.com/containers/podman/v2/pkg/util" "github.com/spf13/cobra" - "github.com/spf13/pflag" ) // pullOptionsWrapper wraps entities.ImagePullOptions and prevents leaking @@ -29,11 +30,12 @@ var ( // Command: podman pull pullCmd = &cobra.Command{ - Use: "pull [options] IMAGE", - Args: cobra.ExactArgs(1), - Short: "Pull an image from a registry", - Long: pullDescription, - RunE: imagePull, + Use: "pull [options] IMAGE", + Args: cobra.ExactArgs(1), + Short: "Pull an image from a registry", + Long: pullDescription, + RunE: imagePull, + ValidArgsFunction: common.AutocompleteImages, Example: `podman pull imageName podman pull fedora:latest`, } @@ -42,11 +44,12 @@ var ( // It's basically a clone of `pullCmd` with the exception of being a // child of the images command. imagesPullCmd = &cobra.Command{ - Use: pullCmd.Use, - Args: pullCmd.Args, - Short: pullCmd.Short, - Long: pullCmd.Long, - RunE: pullCmd.RunE, + Use: pullCmd.Use, + Args: pullCmd.Args, + Short: pullCmd.Short, + Long: pullCmd.Long, + RunE: pullCmd.RunE, + ValidArgsFunction: pullCmd.ValidArgsFunction, Example: `podman image pull imageName podman image pull fedora:latest`, } @@ -58,9 +61,7 @@ func init() { Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, Command: pullCmd, }) - - flags := pullCmd.Flags() - pullFlags(flags) + pullFlags(pullCmd) // images pull registry.Commands = append(registry.Commands, registry.CliCommand{ @@ -68,26 +69,46 @@ func init() { Command: imagesPullCmd, Parent: imageCmd, }) - - imagesPullFlags := imagesPullCmd.Flags() - pullFlags(imagesPullFlags) + pullFlags(imagesPullCmd) } // pullFlags set the flags for the pull command. -func pullFlags(flags *pflag.FlagSet) { +func pullFlags(cmd *cobra.Command) { + flags := cmd.Flags() + flags.BoolVar(&pullOptions.AllTags, "all-tags", false, "All tagged images in the repository will be pulled") - flags.StringVar(&pullOptions.CredentialsCLI, "creds", "", "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry") - flags.StringVar(&pullOptions.OverrideArch, "override-arch", "", "Use `ARCH` instead of the architecture of the machine for choosing images") - flags.StringVar(&pullOptions.OverrideOS, "override-os", "", "Use `OS` instead of the running OS for choosing images") - flags.StringVar(&pullOptions.OverrideVariant, "override-variant", "", " use VARIANT instead of the running architecture variant for choosing images") + + credsFlagName := "creds" + flags.StringVar(&pullOptions.CredentialsCLI, credsFlagName, "", "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry") + _ = cmd.RegisterFlagCompletionFunc(credsFlagName, completion.AutocompleteNone) + + overrideArchFlagName := "override-arch" + flags.StringVar(&pullOptions.OverrideArch, overrideArchFlagName, "", "Use `ARCH` instead of the architecture of the machine for choosing images") + _ = cmd.RegisterFlagCompletionFunc(overrideArchFlagName, completion.AutocompleteNone) + + overrideOsFlagName := "override-os" + flags.StringVar(&pullOptions.OverrideOS, overrideOsFlagName, "", "Use `OS` instead of the running OS for choosing images") + _ = cmd.RegisterFlagCompletionFunc(overrideOsFlagName, completion.AutocompleteNone) + + overrideVariantFlagName := "override-variant" + flags.StringVar(&pullOptions.OverrideVariant, overrideVariantFlagName, "", " use VARIANT instead of the running architecture variant for choosing images") + _ = cmd.RegisterFlagCompletionFunc(overrideVariantFlagName, completion.AutocompleteNone) + flags.Bool("disable-content-trust", false, "This is a Docker specific option and is a NOOP") flags.BoolVarP(&pullOptions.Quiet, "quiet", "q", false, "Suppress output information when pulling images") flags.StringVar(&pullOptions.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)") flags.BoolVar(&pullOptions.TLSVerifyCLI, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries") - flags.StringVar(&pullOptions.Authfile, "authfile", auth.GetDefaultAuthFile(), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override") + + authfileFlagName := "authfile" + flags.StringVar(&pullOptions.Authfile, authfileFlagName, auth.GetDefaultAuthFile(), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override") + _ = cmd.RegisterFlagCompletionFunc(authfileFlagName, completion.AutocompleteDefault) if !registry.IsRemote() { - flags.StringVar(&pullOptions.CertDir, "cert-dir", "", "`Pathname` of a directory containing TLS certificates and keys") + + certDirFlagName := "cert-dir" + flags.StringVar(&pullOptions.CertDir, certDirFlagName, "", "`Pathname` of a directory containing TLS certificates and keys") + _ = cmd.RegisterFlagCompletionFunc(certDirFlagName, completion.AutocompleteDefault) + } _ = flags.MarkHidden("signature-policy") } diff --git a/cmd/podman/images/push.go b/cmd/podman/images/push.go index dd45a790f..447b02fbe 100644 --- a/cmd/podman/images/push.go +++ b/cmd/podman/images/push.go @@ -4,12 +4,13 @@ import ( "os" "github.com/containers/common/pkg/auth" + "github.com/containers/common/pkg/completion" "github.com/containers/image/v5/types" + "github.com/containers/podman/v2/cmd/podman/common" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/pkg/domain/entities" "github.com/containers/podman/v2/pkg/util" "github.com/spf13/cobra" - "github.com/spf13/pflag" ) // pushOptionsWrapper wraps entities.ImagepushOptions and prevents leaking @@ -28,11 +29,12 @@ var ( // Command: podman push pushCmd = &cobra.Command{ - Use: "push [options] SOURCE [DESTINATION]", - Short: "Push an image to a specified destination", - Long: pushDescription, - RunE: imagePush, - Args: cobra.RangeArgs(1, 2), + Use: "push [options] SOURCE [DESTINATION]", + Short: "Push an image to a specified destination", + Long: pushDescription, + RunE: imagePush, + Args: cobra.RangeArgs(1, 2), + ValidArgsFunction: common.AutocompleteImages, Example: `podman push imageID docker://registry.example.com/repository:tag podman push imageID oci-archive:/path/to/layout:image:tag`, } @@ -41,11 +43,12 @@ var ( // It's basically a clone of `pushCmd` with the exception of being a // child of the images command. imagePushCmd = &cobra.Command{ - Use: pushCmd.Use, - Short: pushCmd.Short, - Long: pushCmd.Long, - RunE: pushCmd.RunE, - Args: pushCmd.Args, + Use: pushCmd.Use, + Short: pushCmd.Short, + Long: pushCmd.Long, + RunE: pushCmd.RunE, + Args: pushCmd.Args, + ValidArgsFunction: pushCmd.ValidArgsFunction, Example: `podman image push imageID docker://registry.example.com/repository:tag podman image push imageID oci-archive:/path/to/layout:image:tag`, } @@ -57,9 +60,7 @@ func init() { Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, Command: pushCmd, }) - - flags := pushCmd.Flags() - pushFlags(flags) + pushFlags(pushCmd) // images push registry.Commands = append(registry.Commands, registry.CliCommand{ @@ -67,23 +68,45 @@ func init() { Command: imagePushCmd, Parent: imageCmd, }) - - pushFlags(imagePushCmd.Flags()) + pushFlags(imagePushCmd) } // pushFlags set the flags for the push command. -func pushFlags(flags *pflag.FlagSet) { - flags.StringVar(&pushOptions.Authfile, "authfile", auth.GetDefaultAuthFile(), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override") - flags.StringVar(&pushOptions.CertDir, "cert-dir", "", "Path to a directory containing TLS certificates and keys") +func pushFlags(cmd *cobra.Command) { + flags := cmd.Flags() + + authfileFlagName := "authfile" + flags.StringVar(&pushOptions.Authfile, authfileFlagName, auth.GetDefaultAuthFile(), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override") + _ = cmd.RegisterFlagCompletionFunc(authfileFlagName, completion.AutocompleteDefault) + + certDirFlagName := "cert-dir" + flags.StringVar(&pushOptions.CertDir, certDirFlagName, "", "Path to a directory containing TLS certificates and keys") + _ = cmd.RegisterFlagCompletionFunc(certDirFlagName, completion.AutocompleteDefault) + flags.BoolVar(&pushOptions.Compress, "compress", false, "Compress tarball image layers when pushing to a directory using the 'dir' transport. (default is same compression type as source)") - flags.StringVar(&pushOptions.CredentialsCLI, "creds", "", "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry") - flags.StringVar(&pushOptions.DigestFile, "digestfile", "", "Write the digest of the pushed image to the specified file") + + credsFlagName := "creds" + flags.StringVar(&pushOptions.CredentialsCLI, credsFlagName, "", "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry") + _ = cmd.RegisterFlagCompletionFunc(credsFlagName, completion.AutocompleteNone) + flags.Bool("disable-content-trust", false, "This is a Docker specific option and is a NOOP") - flags.StringVarP(&pushOptions.Format, "format", "f", "", "Manifest type (oci, v2s1, or v2s2) to use when pushing an image using the 'dir' transport (default is manifest type of source)") + + digestfileFlagName := "digestfile" + flags.StringVar(&pushOptions.DigestFile, digestfileFlagName, "", "Write the digest of the pushed image to the specified file") + _ = cmd.RegisterFlagCompletionFunc(digestfileFlagName, completion.AutocompleteDefault) + + formatFlagName := "format" + flags.StringVarP(&pushOptions.Format, formatFlagName, "f", "", "Manifest type (oci, v2s1, or v2s2) to use when pushing an image using the 'dir' transport (default is manifest type of source)") + _ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteManifestFormat) + flags.BoolVarP(&pushOptions.Quiet, "quiet", "q", false, "Suppress output information when pushing images") flags.BoolVar(&pushOptions.RemoveSignatures, "remove-signatures", false, "Discard any pre-existing signatures in the image") flags.StringVar(&pushOptions.SignaturePolicy, "signature-policy", "", "Path to a signature-policy file") - flags.StringVar(&pushOptions.SignBy, "sign-by", "", "Add a signature at the destination using the specified key") + + signByFlagName := "sign-by" + flags.StringVar(&pushOptions.SignBy, signByFlagName, "", "Add a signature at the destination using the specified key") + _ = cmd.RegisterFlagCompletionFunc(signByFlagName, completion.AutocompleteNone) + flags.BoolVar(&pushOptions.TLSVerifyCLI, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries") if registry.IsRemote() { diff --git a/cmd/podman/images/rm.go b/cmd/podman/images/rm.go index 9dddef48f..587f08c29 100644 --- a/cmd/podman/images/rm.go +++ b/cmd/podman/images/rm.go @@ -3,6 +3,7 @@ package images import ( "fmt" + "github.com/containers/podman/v2/cmd/podman/common" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/pkg/domain/entities" "github.com/containers/podman/v2/pkg/errorhandling" @@ -14,10 +15,11 @@ import ( var ( rmDescription = "Removes one or more previously pulled or locally created images." rmCmd = &cobra.Command{ - Use: "rm [options] IMAGE [IMAGE...]", - Short: "Removes one or more images from local storage", - Long: rmDescription, - RunE: rm, + Use: "rm [options] IMAGE [IMAGE...]", + Short: "Removes one or more images from local storage", + Long: rmDescription, + RunE: rm, + ValidArgsFunction: common.AutocompleteImages, Example: `podman image rm imageID podman image rm --force alpine podman image rm c4dfb1609ee2 93fd78260bd1 c0ed59d05ff7`, diff --git a/cmd/podman/images/rmi.go b/cmd/podman/images/rmi.go index 520847890..ab174d750 100644 --- a/cmd/podman/images/rmi.go +++ b/cmd/podman/images/rmi.go @@ -10,12 +10,13 @@ import ( var ( rmiCmd = &cobra.Command{ - Use: strings.Replace(rmCmd.Use, "rm ", "rmi ", 1), - Args: rmCmd.Args, - Short: rmCmd.Short, - Long: rmCmd.Long, - RunE: rmCmd.RunE, - Example: strings.Replace(rmCmd.Example, "podman image rm", "podman rmi", -1), + Use: strings.Replace(rmCmd.Use, "rm ", "rmi ", 1), + Args: rmCmd.Args, + Short: rmCmd.Short, + Long: rmCmd.Long, + RunE: rmCmd.RunE, + ValidArgsFunction: rmCmd.ValidArgsFunction, + Example: strings.Replace(rmCmd.Example, "podman image rm", "podman rmi", -1), } ) diff --git a/cmd/podman/images/save.go b/cmd/podman/images/save.go index db1fa7159..9ef2d0c91 100644 --- a/cmd/podman/images/save.go +++ b/cmd/podman/images/save.go @@ -5,6 +5,8 @@ import ( "os" "strings" + "github.com/containers/common/pkg/completion" + "github.com/containers/podman/v2/cmd/podman/common" "github.com/containers/podman/v2/cmd/podman/parse" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/libpod/define" @@ -12,7 +14,6 @@ import ( "github.com/containers/podman/v2/pkg/util" "github.com/pkg/errors" "github.com/spf13/cobra" - "github.com/spf13/pflag" "golang.org/x/crypto/ssh/terminal" ) @@ -42,16 +43,18 @@ var ( } return nil }, + ValidArgsFunction: completion.AutocompleteNone, Example: `podman save --quiet -o myimage.tar imageID podman save --format docker-dir -o ubuntu-dir ubuntu podman save > alpine-all.tar alpine:latest`, } imageSaveCommand = &cobra.Command{ - Args: saveCommand.Args, - Use: saveCommand.Use, - Short: saveCommand.Short, - Long: saveCommand.Long, - RunE: saveCommand.RunE, + Args: saveCommand.Args, + Use: saveCommand.Use, + Short: saveCommand.Short, + Long: saveCommand.Long, + RunE: saveCommand.RunE, + ValidArgsFunction: saveCommand.ValidArgsFunction, Example: `podman image save --quiet -o myimage.tar imageID podman image save --format docker-dir -o ubuntu-dir ubuntu podman image save > alpine-all.tar alpine:latest`, @@ -67,20 +70,29 @@ func init() { Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, Command: saveCommand, }) - saveFlags(saveCommand.Flags()) + saveFlags(saveCommand) registry.Commands = append(registry.Commands, registry.CliCommand{ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, Command: imageSaveCommand, Parent: imageCmd, }) - saveFlags(imageSaveCommand.Flags()) + saveFlags(imageSaveCommand) } -func saveFlags(flags *pflag.FlagSet) { +func saveFlags(cmd *cobra.Command) { + flags := cmd.Flags() + flags.BoolVar(&saveOpts.Compress, "compress", false, "Compress tarball image layers when saving to a directory using the 'dir' transport. (default is same compression type as source)") - flags.StringVar(&saveOpts.Format, "format", define.V2s2Archive, "Save image to oci-archive, oci-dir (directory with oci manifest type), docker-archive, docker-dir (directory with v2s2 manifest type)") - flags.StringVarP(&saveOpts.Output, "output", "o", "", "Write to a specified file (default: stdout, which must be redirected)") + + formatFlagName := "format" + flags.StringVar(&saveOpts.Format, formatFlagName, define.V2s2Archive, "Save image to oci-archive, oci-dir (directory with oci manifest type), docker-archive, docker-dir (directory with v2s2 manifest type)") + _ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteImageSaveFormat) + + outputFlagName := "output" + flags.StringVarP(&saveOpts.Output, outputFlagName, "o", "", "Write to a specified file (default: stdout, which must be redirected)") + _ = cmd.RegisterFlagCompletionFunc(outputFlagName, completion.AutocompleteDefault) + flags.BoolVarP(&saveOpts.Quiet, "quiet", "q", false, "Suppress the output") flags.BoolVarP(&saveOpts.MultiImageArchive, "multi-image-archive", "m", containerConfig.Engine.MultiImageArchive, "Interpret additional arguments as images not tags and create a multi-image-archive (only for docker-archive)") } diff --git a/cmd/podman/images/search.go b/cmd/podman/images/search.go index 7de6a7316..c2ef7d767 100644 --- a/cmd/podman/images/search.go +++ b/cmd/podman/images/search.go @@ -7,6 +7,7 @@ import ( "text/template" "github.com/containers/common/pkg/auth" + "github.com/containers/common/pkg/completion" "github.com/containers/common/pkg/report" "github.com/containers/image/v5/types" "github.com/containers/podman/v2/cmd/podman/parse" @@ -14,7 +15,6 @@ import ( "github.com/containers/podman/v2/pkg/domain/entities" "github.com/pkg/errors" "github.com/spf13/cobra" - "github.com/spf13/pflag" ) // searchOptionsWrapper wraps entities.ImagePullOptions and prevents leaking @@ -34,11 +34,12 @@ var ( // Command: podman search searchCmd = &cobra.Command{ - Use: "search [options] TERM", - Short: "Search registry for image", - Long: searchDescription, - RunE: imageSearch, - Args: cobra.ExactArgs(1), + Use: "search [options] TERM", + Short: "Search registry for image", + Long: searchDescription, + RunE: imageSearch, + Args: cobra.ExactArgs(1), + ValidArgsFunction: completion.AutocompleteNone, Example: `podman search --filter=is-official --limit 3 alpine podman search registry.fedoraproject.org/ # only works with v2 registries podman search --format "table {{.Index}} {{.Name}}" registry.fedoraproject.org/fedora`, @@ -46,12 +47,13 @@ var ( // Command: podman image search imageSearchCmd = &cobra.Command{ - Use: searchCmd.Use, - Short: searchCmd.Short, - Long: searchCmd.Long, - RunE: searchCmd.RunE, - Args: searchCmd.Args, - Annotations: searchCmd.Annotations, + Use: searchCmd.Use, + Short: searchCmd.Short, + Long: searchCmd.Long, + RunE: searchCmd.RunE, + Args: searchCmd.Args, + Annotations: searchCmd.Annotations, + ValidArgsFunction: searchCmd.ValidArgsFunction, Example: `podman image search --filter=is-official --limit 3 alpine podman image search registry.fedoraproject.org/ # only works with v2 registries podman image search --format "table {{.Index}} {{.Name}}" registry.fedoraproject.org/fedora`, @@ -64,9 +66,7 @@ func init() { Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, Command: searchCmd, }) - - flags := searchCmd.Flags() - searchFlags(flags) + searchFlags(searchCmd) // images search registry.Commands = append(registry.Commands, registry.CliCommand{ @@ -74,18 +74,32 @@ func init() { Command: imageSearchCmd, Parent: imageCmd, }) - - imageSearchFlags := imageSearchCmd.Flags() - searchFlags(imageSearchFlags) + searchFlags(imageSearchCmd) } // searchFlags set the flags for the pull command. -func searchFlags(flags *pflag.FlagSet) { - flags.StringSliceVarP(&searchOptions.Filters, "filter", "f", []string{}, "Filter output based on conditions provided (default [])") - flags.StringVar(&searchOptions.Format, "format", "", "Change the output format to JSON or a Go template") - flags.IntVar(&searchOptions.Limit, "limit", 0, "Limit the number of results") +func searchFlags(cmd *cobra.Command) { + flags := cmd.Flags() + + filterFlagName := "filter" + flags.StringSliceVarP(&searchOptions.Filters, filterFlagName, "f", []string{}, "Filter output based on conditions provided (default [])") + //TODO add custom filter function + _ = cmd.RegisterFlagCompletionFunc(filterFlagName, completion.AutocompleteNone) + + formatFlagName := "format" + flags.StringVar(&searchOptions.Format, formatFlagName, "", "Change the output format to JSON or a Go template") + _ = cmd.RegisterFlagCompletionFunc(formatFlagName, completion.AutocompleteNone) + + limitFlagName := "limit" + flags.IntVar(&searchOptions.Limit, limitFlagName, 0, "Limit the number of results") + _ = cmd.RegisterFlagCompletionFunc(limitFlagName, completion.AutocompleteNone) + flags.BoolVar(&searchOptions.NoTrunc, "no-trunc", false, "Do not truncate the output") - flags.StringVar(&searchOptions.Authfile, "authfile", auth.GetDefaultAuthFile(), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override") + + authfileFlagName := "authfile" + flags.StringVar(&searchOptions.Authfile, authfileFlagName, auth.GetDefaultAuthFile(), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override") + _ = cmd.RegisterFlagCompletionFunc(authfileFlagName, completion.AutocompleteDefault) + flags.BoolVar(&searchOptions.TLSVerifyCLI, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries") flags.BoolVar(&searchOptions.ListTags, "list-tags", false, "List the tags of the input registry") } diff --git a/cmd/podman/images/sign.go b/cmd/podman/images/sign.go index f6c1f9856..529fb3d92 100644 --- a/cmd/podman/images/sign.go +++ b/cmd/podman/images/sign.go @@ -3,6 +3,8 @@ package images import ( "os" + "github.com/containers/common/pkg/completion" + "github.com/containers/podman/v2/cmd/podman/common" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/pkg/domain/entities" "github.com/pkg/errors" @@ -12,11 +14,12 @@ import ( var ( signDescription = "Create a signature file that can be used later to verify the image." signCommand = &cobra.Command{ - Use: "sign [options] IMAGE [IMAGE...]", - Short: "Sign an image", - Long: signDescription, - RunE: sign, - Args: cobra.MinimumNArgs(1), + Use: "sign [options] IMAGE [IMAGE...]", + Short: "Sign an image", + Long: signDescription, + RunE: sign, + Args: cobra.MinimumNArgs(1), + ValidArgsFunction: common.AutocompleteImages, Example: `podman image sign --sign-by mykey imageID podman image sign --sign-by mykey --directory ./mykeydir imageID`, } @@ -33,9 +36,17 @@ func init() { Parent: imageCmd, }) flags := signCommand.Flags() - flags.StringVarP(&signOptions.Directory, "directory", "d", "", "Define an alternate directory to store signatures") - flags.StringVar(&signOptions.SignBy, "sign-by", "", "Name of the signing key") - flags.StringVar(&signOptions.CertDir, "cert-dir", "", "`Pathname` of a directory containing TLS certificates and keys") + directoryFlagName := "directory" + flags.StringVarP(&signOptions.Directory, directoryFlagName, "d", "", "Define an alternate directory to store signatures") + _ = signCommand.RegisterFlagCompletionFunc(directoryFlagName, completion.AutocompleteDefault) + + signByFlagName := "sign-by" + flags.StringVar(&signOptions.SignBy, signByFlagName, "", "Name of the signing key") + _ = signCommand.RegisterFlagCompletionFunc(signByFlagName, completion.AutocompleteNone) + + certDirFlagName := "cert-dir" + flags.StringVar(&signOptions.CertDir, certDirFlagName, "", "`Pathname` of a directory containing TLS certificates and keys") + _ = signCommand.RegisterFlagCompletionFunc(certDirFlagName, completion.AutocompleteDefault) } func sign(cmd *cobra.Command, args []string) error { diff --git a/cmd/podman/images/tag.go b/cmd/podman/images/tag.go index be7f84588..157db49ca 100644 --- a/cmd/podman/images/tag.go +++ b/cmd/podman/images/tag.go @@ -1,6 +1,7 @@ package images import ( + "github.com/containers/podman/v2/cmd/podman/common" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/pkg/domain/entities" "github.com/spf13/cobra" @@ -15,6 +16,7 @@ var ( RunE: tag, Args: cobra.MinimumNArgs(2), DisableFlagsInUseLine: true, + ValidArgsFunction: common.AutocompleteImages, Example: `podman tag 0e3bbc2 fedora:latest podman tag imageID:latest myNewImage:newTag podman tag httpd myregistryhost:5000/fedora/httpd:v2`, @@ -27,6 +29,7 @@ var ( Short: tagCommand.Short, Long: tagCommand.Long, RunE: tagCommand.RunE, + ValidArgsFunction: tagCommand.ValidArgsFunction, Example: `podman image tag 0e3bbc2 fedora:latest podman image tag imageID:latest myNewImage:newTag podman image tag httpd myregistryhost:5000/fedora/httpd:v2`, diff --git a/cmd/podman/images/tree.go b/cmd/podman/images/tree.go index 237a2ab91..76c69b37e 100644 --- a/cmd/podman/images/tree.go +++ b/cmd/podman/images/tree.go @@ -3,6 +3,7 @@ package images import ( "fmt" + "github.com/containers/podman/v2/cmd/podman/common" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/pkg/domain/entities" "github.com/spf13/cobra" @@ -11,12 +12,13 @@ import ( var ( treeDescription = "Prints layer hierarchy of an image in a tree format" treeCmd = &cobra.Command{ - Use: "tree [options] IMAGE", - Args: cobra.ExactArgs(1), - Short: treeDescription, - Long: treeDescription, - RunE: tree, - Example: "podman image tree alpine:latest", + Use: "tree [options] IMAGE", + Args: cobra.ExactArgs(1), + Short: treeDescription, + Long: treeDescription, + RunE: tree, + ValidArgsFunction: common.AutocompleteImages, + Example: "podman image tree alpine:latest", } treeOpts entities.ImageTreeOptions ) diff --git a/cmd/podman/images/trust_set.go b/cmd/podman/images/trust_set.go index 2e4b4fe17..f0399b110 100644 --- a/cmd/podman/images/trust_set.go +++ b/cmd/podman/images/trust_set.go @@ -1,6 +1,8 @@ package images import ( + "github.com/containers/common/pkg/completion" + "github.com/containers/podman/v2/cmd/podman/common" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/libpod/image" "github.com/containers/podman/v2/pkg/domain/entities" @@ -12,12 +14,13 @@ import ( var ( setTrustDescription = "Set default trust policy or add a new trust policy for a registry" setTrustCommand = &cobra.Command{ - Use: "set [options] REGISTRY", - Short: "Set default trust policy or a new trust policy for a registry", - Long: setTrustDescription, - Example: "", - RunE: setTrust, - Args: cobra.ExactArgs(1), + Use: "set [options] REGISTRY", + Short: "Set default trust policy or a new trust policy for a registry", + Long: setTrustDescription, + Example: "", + RunE: setTrust, + Args: cobra.ExactArgs(1), + ValidArgsFunction: common.AutocompleteRegistries, } ) @@ -34,11 +37,17 @@ func init() { setFlags := setTrustCommand.Flags() setFlags.StringVar(&setOptions.PolicyPath, "policypath", "", "") _ = setFlags.MarkHidden("policypath") - setFlags.StringSliceVarP(&setOptions.PubKeysFile, "pubkeysfile", "f", []string{}, `Path of installed public key(s) to trust for TARGET. + + pubkeysfileFlagName := "pubkeysfile" + setFlags.StringSliceVarP(&setOptions.PubKeysFile, pubkeysfileFlagName, "f", []string{}, `Path of installed public key(s) to trust for TARGET. Absolute path to keys is added to policy.json. May used multiple times to define multiple public keys. File(s) must exist before using this command`) - setFlags.StringVarP(&setOptions.Type, "type", "t", "signedBy", "Trust type, accept values: signedBy(default), accept, reject") + _ = setTrustCommand.RegisterFlagCompletionFunc(pubkeysfileFlagName, completion.AutocompleteDefault) + + typeFlagName := "type" + setFlags.StringVarP(&setOptions.Type, typeFlagName, "t", "signedBy", "Trust type, accept values: signedBy(default), accept, reject") + _ = setTrustCommand.RegisterFlagCompletionFunc(typeFlagName, common.AutocompleteTrustType) } func setTrust(cmd *cobra.Command, args []string) error { diff --git a/cmd/podman/images/trust_show.go b/cmd/podman/images/trust_show.go index ba3b4e7fb..dc35dc6a1 100644 --- a/cmd/podman/images/trust_show.go +++ b/cmd/podman/images/trust_show.go @@ -6,6 +6,7 @@ import ( "text/tabwriter" "text/template" + "github.com/containers/podman/v2/cmd/podman/common" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/pkg/domain/entities" "github.com/spf13/cobra" @@ -14,12 +15,13 @@ import ( var ( showTrustDescription = "Display trust policy for the system" showTrustCommand = &cobra.Command{ - Use: "show [options] [REGISTRY]", - Short: "Display trust policy for the system", - Long: showTrustDescription, - RunE: showTrust, - Args: cobra.MaximumNArgs(1), - Example: "", + Use: "show [options] [REGISTRY]", + Short: "Display trust policy for the system", + Long: showTrustDescription, + RunE: showTrust, + Args: cobra.MaximumNArgs(1), + ValidArgsFunction: common.AutocompleteRegistries, + Example: "", } ) diff --git a/cmd/podman/images/unmount.go b/cmd/podman/images/unmount.go index 50dc972e8..3af959b9f 100644 --- a/cmd/podman/images/unmount.go +++ b/cmd/podman/images/unmount.go @@ -3,6 +3,7 @@ package images import ( "fmt" + "github.com/containers/podman/v2/cmd/podman/common" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/cmd/podman/utils" "github.com/containers/podman/v2/pkg/domain/entities" @@ -19,11 +20,12 @@ var ( An unmount can be forced with the --force flag. ` unmountCommand = &cobra.Command{ - Use: "unmount [options] IMAGE [IMAGE...]", - Aliases: []string{"umount"}, - Short: "Unmount an image's root filesystem", - Long: description, - RunE: unmount, + Use: "unmount [options] IMAGE [IMAGE...]", + Aliases: []string{"umount"}, + Short: "Unmount an image's root filesystem", + Long: description, + RunE: unmount, + ValidArgsFunction: common.AutocompleteImages, Example: `podman unmount imgID podman unmount imgID1 imgID2 imgID3 podman unmount --all`, diff --git a/cmd/podman/images/untag.go b/cmd/podman/images/untag.go index da749c8a5..17dc21203 100644 --- a/cmd/podman/images/untag.go +++ b/cmd/podman/images/untag.go @@ -1,6 +1,7 @@ package images import ( + "github.com/containers/podman/v2/cmd/podman/common" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/pkg/domain/entities" "github.com/spf13/cobra" @@ -14,6 +15,7 @@ var ( RunE: untag, Args: cobra.MinimumNArgs(1), DisableFlagsInUseLine: true, + ValidArgsFunction: common.AutocompleteImages, Example: `podman untag 0e3bbc2 podman untag imageID:latest otherImageName:latest podman untag httpd myregistryhost:5000/fedora/httpd:v2`, @@ -26,6 +28,7 @@ var ( Short: untagCommand.Short, Long: untagCommand.Long, RunE: untagCommand.RunE, + ValidArgsFunction: untagCommand.ValidArgsFunction, Example: `podman image untag 0e3bbc2 podman image untag imageID:latest otherImageName:latest podman image untag httpd myregistryhost:5000/fedora/httpd:v2`, -- cgit v1.2.3-54-g00ecf