summaryrefslogtreecommitdiff
path: root/cmd/podman/common/completion.go
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/podman/common/completion.go')
-rw-r--r--cmd/podman/common/completion.go941
1 files changed, 941 insertions, 0 deletions
diff --git a/cmd/podman/common/completion.go b/cmd/podman/common/completion.go
new file mode 100644
index 000000000..9856e46ef
--- /dev/null
+++ b/cmd/podman/common/completion.go
@@ -0,0 +1,941 @@
+package common
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+ "strings"
+
+ "github.com/containers/common/pkg/config"
+ "github.com/containers/podman/v2/cmd/podman/registry"
+ "github.com/containers/podman/v2/libpod"
+ "github.com/containers/podman/v2/libpod/define"
+ "github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/registries"
+ "github.com/containers/podman/v2/pkg/rootless"
+ systemdGen "github.com/containers/podman/v2/pkg/systemd/generate"
+ "github.com/containers/podman/v2/pkg/util"
+ "github.com/spf13/cobra"
+)
+
+var (
+ // ChangeCmds is the list of valid Change commands to passed to the Commit call
+ ChangeCmds = []string{"CMD", "ENTRYPOINT", "ENV", "EXPOSE", "LABEL", "ONBUILD", "STOPSIGNAL", "USER", "VOLUME", "WORKDIR"}
+ // LogLevels supported by podman
+ LogLevels = []string{"debug", "info", "warn", "error", "fatal", "panic"}
+)
+
+type completeType int
+
+const (
+ // complete names and IDs after two chars
+ completeDefault completeType = iota
+ // only complete IDs
+ completeIDs
+ // only complete Names
+ completeNames
+)
+
+type keyValueCompletion map[string]func(s string) ([]string, cobra.ShellCompDirective)
+
+func setupContainerEngine(cmd *cobra.Command) (entities.ContainerEngine, error) {
+ containerEngine, err := registry.NewContainerEngine(cmd, []string{})
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, err
+ }
+ if !registry.IsRemote() && rootless.IsRootless() {
+ err := containerEngine.SetupRootless(registry.Context(), cmd)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return containerEngine, nil
+}
+
+func setupImageEngine(cmd *cobra.Command) (entities.ImageEngine, error) {
+ imageEngine, err := registry.NewImageEngine(cmd, []string{})
+ if err != nil {
+ return nil, err
+ }
+ // we also need to set up the container engine since this
+ // is required to setup the rootless namespace
+ if _, err = setupContainerEngine(cmd); err != nil {
+ return nil, err
+ }
+ return imageEngine, nil
+}
+
+func getContainers(cmd *cobra.Command, toComplete string, cType completeType, statuses ...string) ([]string, cobra.ShellCompDirective) {
+ suggestions := []string{}
+ listOpts := entities.ContainerListOptions{
+ Filters: make(map[string][]string),
+ }
+ listOpts.All = true
+ listOpts.Pod = true
+ if len(statuses) > 0 {
+ listOpts.Filters["status"] = statuses
+ }
+
+ engine, err := setupContainerEngine(cmd)
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ containers, err := engine.ContainerList(registry.GetContext(), listOpts)
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+
+ for _, c := range containers {
+ // include ids in suggestions if cType == completeIDs or
+ // more then 2 chars are typed and cType == completeDefault
+ if ((len(toComplete) > 1 && cType == completeDefault) ||
+ cType == completeIDs) && strings.HasPrefix(c.ID, toComplete) {
+ suggestions = append(suggestions, c.ID[0:12]+"\t"+c.PodName)
+ }
+ // include name in suggestions
+ if cType != completeIDs && strings.HasPrefix(c.Names[0], toComplete) {
+ suggestions = append(suggestions, c.Names[0]+"\t"+c.PodName)
+ }
+ }
+ return suggestions, cobra.ShellCompDirectiveNoFileComp
+}
+
+func getPods(cmd *cobra.Command, toComplete string, cType completeType, statuses ...string) ([]string, cobra.ShellCompDirective) {
+ suggestions := []string{}
+ listOpts := entities.PodPSOptions{
+ Filters: make(map[string][]string),
+ }
+ if len(statuses) > 0 {
+ listOpts.Filters["status"] = statuses
+ }
+
+ engine, err := setupContainerEngine(cmd)
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ pods, err := engine.PodPs(registry.GetContext(), listOpts)
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+
+ for _, pod := range pods {
+ // include ids in suggestions if cType == completeIDs or
+ // more then 2 chars are typed and cType == completeDefault
+ if ((len(toComplete) > 1 && cType == completeDefault) ||
+ cType == completeIDs) && strings.HasPrefix(pod.Id, toComplete) {
+ suggestions = append(suggestions, pod.Id[0:12])
+ }
+ // include name in suggestions
+ if cType != completeIDs && strings.HasPrefix(pod.Name, toComplete) {
+ suggestions = append(suggestions, pod.Name)
+ }
+ }
+ return suggestions, cobra.ShellCompDirectiveNoFileComp
+}
+
+func getVolumes(cmd *cobra.Command, toComplete string) ([]string, cobra.ShellCompDirective) {
+ suggestions := []string{}
+ lsOpts := entities.VolumeListOptions{}
+
+ engine, err := setupContainerEngine(cmd)
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ volumes, err := engine.VolumeList(registry.GetContext(), lsOpts)
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+
+ for _, v := range volumes {
+ if strings.HasPrefix(v.Name, toComplete) {
+ suggestions = append(suggestions, v.Name)
+ }
+ }
+ return suggestions, cobra.ShellCompDirectiveNoFileComp
+}
+
+func getImages(cmd *cobra.Command, toComplete string) ([]string, cobra.ShellCompDirective) {
+ suggestions := []string{}
+ listOptions := entities.ImageListOptions{}
+
+ engine, err := setupImageEngine(cmd)
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ images, err := engine.List(registry.GetContext(), listOptions)
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+
+ for _, image := range images {
+ // include ids in suggestions if more then 2 chars are typed
+ if len(toComplete) > 1 && strings.HasPrefix(image.ID, toComplete) {
+ suggestions = append(suggestions, image.ID[0:12])
+ }
+ for _, repo := range image.RepoTags {
+ if toComplete == "" {
+ // suggest only full repo path if no input is given
+ if strings.HasPrefix(repo, toComplete) {
+ suggestions = append(suggestions, repo)
+ }
+ } else {
+ // suggested "registry.fedoraproject.org/f29/httpd:latest" as
+ // - "registry.fedoraproject.org/f29/httpd:latest"
+ // - "registry.fedoraproject.org/f29/httpd"
+ // - "f29/httpd:latest"
+ // - "f29/httpd"
+ // - "httpd:latest"
+ // - "httpd"
+ paths := strings.Split(repo, "/")
+ for i := range paths {
+ suggestionWithTag := strings.Join(paths[i:], "/")
+ if strings.HasPrefix(suggestionWithTag, toComplete) {
+ suggestions = append(suggestions, suggestionWithTag)
+ }
+ suggestionWithoutTag := strings.SplitN(strings.SplitN(suggestionWithTag, ":", 2)[0], "@", 2)[0]
+ if strings.HasPrefix(suggestionWithoutTag, toComplete) {
+ suggestions = append(suggestions, suggestionWithoutTag)
+ }
+ }
+ }
+ }
+ }
+ return suggestions, cobra.ShellCompDirectiveNoFileComp
+}
+
+func getRegistries() ([]string, cobra.ShellCompDirective) {
+ regs, err := registries.GetRegistries()
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ return regs, cobra.ShellCompDirectiveNoFileComp
+}
+
+func getNetworks(cmd *cobra.Command, toComplete string) ([]string, cobra.ShellCompDirective) {
+ suggestions := []string{}
+ networkListOptions := entities.NetworkListOptions{}
+
+ engine, err := setupContainerEngine(cmd)
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ networks, err := engine.NetworkList(registry.Context(), networkListOptions)
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+
+ for _, n := range networks {
+ if strings.HasPrefix(n.Name, toComplete) {
+ suggestions = append(suggestions, n.Name)
+ }
+ }
+ return suggestions, cobra.ShellCompDirectiveNoFileComp
+}
+
+// validCurrentCmdLine validates the current cmd line
+// It utilizes the Args function from the cmd struct
+// In most cases the Args function validates the args length but it
+// is also used to verify that --latest is not given with an argument.
+// This function helps to makes sure we only complete valid arguments.
+func validCurrentCmdLine(cmd *cobra.Command, args []string, toComplete string) bool {
+ if cmd.Args == nil {
+ // Without an Args function we cannot check so assume it's correct
+ return true
+ }
+ // We have to append toComplete to the args otherwise the
+ // argument count would not match the expected behavior
+ if err := cmd.Args(cmd, append(args, toComplete)); err != nil {
+ // Special case if we use ExactArgs(2) or MinimumNArgs(2),
+ // They will error if we try to complete the first arg.
+ // Lets try to parse the common error and compare if we have less args than
+ // required. In this case we are fine and should provide completion.
+
+ // Clean the err msg so we can parse it with fmt.Sscanf
+ // Trim MinimumNArgs prefix
+ cleanErr := strings.TrimPrefix(err.Error(), "requires at least ")
+ // Trim MinimumNArgs "only" part
+ cleanErr = strings.ReplaceAll(cleanErr, "only received", "received")
+ // Trim ExactArgs prefix
+ cleanErr = strings.TrimPrefix(cleanErr, "accepts ")
+ var need, got int
+ cobra.CompDebugln(cleanErr, true)
+ _, err = fmt.Sscanf(cleanErr, "%d arg(s), received %d", &need, &got)
+ if err == nil {
+ if need >= got {
+ // We still need more arguments so provide more completions
+ return true
+ }
+ }
+ cobra.CompDebugln(err.Error(), true)
+ return false
+ }
+ return true
+}
+
+func prefixSlice(pre string, slice []string) []string {
+ for i := range slice {
+ slice[i] = pre + slice[i]
+ }
+ return slice
+}
+
+func completeKeyValues(toComplete string, k keyValueCompletion) ([]string, cobra.ShellCompDirective) {
+ suggestions := make([]string, 0, len(k))
+ directive := cobra.ShellCompDirectiveNoFileComp
+ for key, getComps := range k {
+ if strings.HasPrefix(toComplete, key) {
+ if getComps != nil {
+ suggestions, dir := getComps(toComplete[len(key):])
+ return prefixSlice(key, suggestions), dir
+ }
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ if strings.HasPrefix(key, toComplete) {
+ suggestions = append(suggestions, key)
+ latKey := key[len(key)-1:]
+ if latKey == "=" || latKey == ":" {
+ // make sure we don't add a space after ':' or '='
+ directive = cobra.ShellCompDirectiveNoSpace | cobra.ShellCompDirectiveNoFileComp
+ }
+ }
+ }
+ return suggestions, directive
+}
+
+/* Autocomplete Functions for cobra ValidArgsFunction */
+
+// AutocompleteContainers - Autocomplete all container names.
+func AutocompleteContainers(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ if !validCurrentCmdLine(cmd, args, toComplete) {
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ return getContainers(cmd, toComplete, completeDefault)
+}
+
+// AutocompleteContainersCreated - Autocomplete only created container names.
+func AutocompleteContainersCreated(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ if !validCurrentCmdLine(cmd, args, toComplete) {
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ return getContainers(cmd, toComplete, completeDefault, "created")
+}
+
+// AutocompleteContainersExited - Autocomplete only exited container names.
+func AutocompleteContainersExited(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ if !validCurrentCmdLine(cmd, args, toComplete) {
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ return getContainers(cmd, toComplete, completeDefault, "exited")
+}
+
+// AutocompleteContainersPaused - Autocomplete only paused container names.
+func AutocompleteContainersPaused(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ if !validCurrentCmdLine(cmd, args, toComplete) {
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ return getContainers(cmd, toComplete, completeDefault, "paused")
+}
+
+// AutocompleteContainersRunning - Autocomplete only running container names.
+func AutocompleteContainersRunning(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ if !validCurrentCmdLine(cmd, args, toComplete) {
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ return getContainers(cmd, toComplete, completeDefault, "running")
+}
+
+// AutocompleteContainersStartable - Autocomplete only created and exited container names.
+func AutocompleteContainersStartable(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ if !validCurrentCmdLine(cmd, args, toComplete) {
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ return getContainers(cmd, toComplete, completeDefault, "created", "exited")
+}
+
+// AutocompletePods - Autocomplete all pod names.
+func AutocompletePods(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ if !validCurrentCmdLine(cmd, args, toComplete) {
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ return getPods(cmd, toComplete, completeDefault)
+}
+
+// AutocompletePodsRunning - Autocomplete only running pod names.
+// It considers degraded as running.
+func AutocompletePodsRunning(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ if !validCurrentCmdLine(cmd, args, toComplete) {
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ return getPods(cmd, toComplete, completeDefault, "running", "degraded")
+}
+
+// AutocompleteContainersAndPods - Autocomplete container names and pod names.
+func AutocompleteContainersAndPods(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ if !validCurrentCmdLine(cmd, args, toComplete) {
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ containers, _ := getContainers(cmd, toComplete, completeDefault)
+ pods, _ := getPods(cmd, toComplete, completeDefault)
+ return append(containers, pods...), cobra.ShellCompDirectiveNoFileComp
+}
+
+// AutocompleteContainersAndImages - Autocomplete container names and pod names.
+func AutocompleteContainersAndImages(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ if !validCurrentCmdLine(cmd, args, toComplete) {
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ containers, _ := getContainers(cmd, toComplete, completeDefault)
+ images, _ := getImages(cmd, toComplete)
+ return append(containers, images...), cobra.ShellCompDirectiveNoFileComp
+}
+
+// AutocompleteVolumes - Autocomplete volumes.
+func AutocompleteVolumes(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ if !validCurrentCmdLine(cmd, args, toComplete) {
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ return getVolumes(cmd, toComplete)
+}
+
+// AutocompleteImages - Autocomplete images.
+func AutocompleteImages(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ if !validCurrentCmdLine(cmd, args, toComplete) {
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ return getImages(cmd, toComplete)
+}
+
+// AutocompleteCreateRun - Autocomplete only the fist argument as image and then do file completion.
+func AutocompleteCreateRun(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ if !validCurrentCmdLine(cmd, args, toComplete) {
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ if len(args) < 1 {
+ return getImages(cmd, toComplete)
+ }
+ // TODO: add path completion for files in the image
+ return nil, cobra.ShellCompDirectiveDefault
+}
+
+// AutocompleteRegistries - Autocomplete registries.
+func AutocompleteRegistries(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ if !validCurrentCmdLine(cmd, args, toComplete) {
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ return getRegistries()
+}
+
+// AutocompleteNetworks - Autocomplete networks.
+func AutocompleteNetworks(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ if !validCurrentCmdLine(cmd, args, toComplete) {
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ return getNetworks(cmd, toComplete)
+}
+
+// AutocompleteCpCommand - Autocomplete podman cp command args.
+func AutocompleteCpCommand(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ if !validCurrentCmdLine(cmd, args, toComplete) {
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ if len(args) < 2 {
+ containers, _ := getContainers(cmd, toComplete, completeDefault)
+ for _, container := range containers {
+ // TODO: Add path completion for inside the container if possible
+ if strings.HasPrefix(container, toComplete) {
+ return containers, cobra.ShellCompDirectiveNoSpace
+ }
+ }
+ // else complete paths
+ return nil, cobra.ShellCompDirectiveDefault
+ }
+ // don't complete more than 2 args
+ return nil, cobra.ShellCompDirectiveNoFileComp
+}
+
+// AutocompleteNetworkConnectCmd - Autocomplete podman network connect/disconnect command args.
+func AutocompleteNetworkConnectCmd(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ if len(args) == 0 {
+ return getNetworks(cmd, toComplete)
+ }
+ if len(args) == 1 {
+ return getContainers(cmd, toComplete, completeDefault)
+ }
+ // don't complete more than 2 args
+ return nil, cobra.ShellCompDirectiveNoFileComp
+}
+
+// AutocompleteTopCmd - Autocomplete podman top/pod top command args.
+func AutocompleteTopCmd(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ latest := cmd.Flags().Lookup("latest")
+ // only complete containers/pods as first arg if latest is not set
+ if len(args) == 0 && (latest == nil || !latest.Changed) {
+ if cmd.Parent().Name() == "pod" {
+ // need to complete pods since we are using pod top
+ return getPods(cmd, toComplete, completeDefault)
+ }
+ return getContainers(cmd, toComplete, completeDefault)
+ }
+ descriptors, err := util.GetContainerPidInformationDescriptors()
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ return descriptors, cobra.ShellCompDirectiveNoFileComp
+}
+
+// AutocompleteSystemConnections - Autocomplete system connections.
+func AutocompleteSystemConnections(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ if !validCurrentCmdLine(cmd, args, toComplete) {
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ suggestions := []string{}
+ cfg, err := config.ReadCustomConfig()
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+
+ for k, v := range cfg.Engine.ServiceDestinations {
+ // the URI will be show as description in shells like zsh
+ suggestions = append(suggestions, k+"\t"+v.URI)
+ }
+
+ return suggestions, cobra.ShellCompDirectiveNoFileComp
+}
+
+/* -------------- Flags ----------------- */
+
+// AutocompleteDetachKeys - Autocomplete detach-keys options.
+// -> "ctrl-"
+func AutocompleteDetachKeys(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ if strings.HasSuffix(toComplete, ",") {
+ return []string{toComplete + "ctrl-"}, cobra.ShellCompDirectiveNoSpace
+ }
+ return []string{"ctrl-"}, cobra.ShellCompDirectiveNoSpace
+}
+
+// AutocompleteChangeInstructions - Autocomplete change instructions options for commit and import.
+// -> "CMD", "ENTRYPOINT", "ENV", "EXPOSE", "LABEL", "ONBUILD", "STOPSIGNAL", "USER", "VOLUME", "WORKDIR"
+func AutocompleteChangeInstructions(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ return ChangeCmds, cobra.ShellCompDirectiveNoSpace
+}
+
+// AutocompleteImageFormat - Autocomplete image format options.
+// -> "oci", "docker"
+func AutocompleteImageFormat(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ ImageFormat := []string{"oci", "docker"}
+ return ImageFormat, cobra.ShellCompDirectiveNoFileComp
+}
+
+// AutocompleteCreateAttach - Autocomplete create --attach options.
+// -> "stdin", "stdout", "stderr"
+func AutocompleteCreateAttach(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ return []string{"stdin", "stdout", "stderr"}, cobra.ShellCompDirectiveNoFileComp
+}
+
+// AutocompleteNamespace - Autocomplete namespace options.
+// -> host,container:[name],ns:[path],private
+func AutocompleteNamespace(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ kv := keyValueCompletion{
+ "container:": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(cmd, s, completeDefault) },
+ "ns:": func(s string) ([]string, cobra.ShellCompDirective) { return nil, cobra.ShellCompDirectiveDefault },
+ "host": nil,
+ "private": nil,
+ }
+ return completeKeyValues(toComplete, kv)
+}
+
+// AutocompleteUserNamespace - Autocomplete namespace options.
+// -> same as AutocompleteNamespace with "auto", "keep-id" added
+func AutocompleteUserNamespace(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ results, directive := AutocompleteNamespace(cmd, args, toComplete)
+ results = append(results, "auto", "keep-id")
+ return results, directive
+}
+
+// AutocompleteCgroupMode - Autocomplete cgroup mode options.
+// -> "enabled", "disabled", "no-conmon", "split"
+func AutocompleteCgroupMode(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ cgroupModes := []string{"enabled", "disabled", "no-conmon", "split"}
+ return cgroupModes, cobra.ShellCompDirectiveNoFileComp
+}
+
+// AutocompleteImageVolume - Autocomplete image volume options.
+// -> "bind", "tmpfs", "ignore"
+func AutocompleteImageVolume(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ imageVolumes := []string{"bind", "tmpfs", "ignore"}
+ return imageVolumes, cobra.ShellCompDirectiveNoFileComp
+}
+
+// AutocompleteLogDriver - Autocomplete log-driver options.
+// -> "journald", "none", "k8s-file"
+func AutocompleteLogDriver(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ // don't show json-file
+ logDrivers := []string{define.JournaldLogging, define.NoLogging, define.KubernetesLogging}
+ return logDrivers, cobra.ShellCompDirectiveNoFileComp
+}
+
+// AutocompleteLogOpt - Autocomplete log-opt options.
+// -> "path=", "tag="
+func AutocompleteLogOpt(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ // FIXME: are these the only one? the man page states these but in the current shell completion they are more options
+ logOptions := []string{"path=", "tag="}
+ if strings.HasPrefix(toComplete, "path=") {
+ return nil, cobra.ShellCompDirectiveDefault
+ }
+ return logOptions, cobra.ShellCompDirectiveNoFileComp | cobra.ShellCompDirectiveNoSpace
+}
+
+// AutocompletePullOption - Autocomplete pull options for create and run command.
+// -> "always", "missing", "never"
+func AutocompletePullOption(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ pullOptions := []string{"always", "missing", "never"}
+ return pullOptions, cobra.ShellCompDirectiveNoFileComp
+}
+
+// AutocompleteRestartOption - Autocomplete restart options for create and run command.
+// -> "always", "no", "on-failure", "unless-stopped"
+func AutocompleteRestartOption(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ restartOptions := []string{libpod.RestartPolicyAlways, libpod.RestartPolicyNo,
+ libpod.RestartPolicyOnFailure, libpod.RestartPolicyUnlessStopped}
+ return restartOptions, cobra.ShellCompDirectiveNoFileComp
+}
+
+// AutocompleteSecurityOption - Autocomplete security options options.
+func AutocompleteSecurityOption(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ kv := keyValueCompletion{
+ "apparmor=": nil,
+ "no-new-privileges": nil,
+ "seccomp=": func(s string) ([]string, cobra.ShellCompDirective) { return nil, cobra.ShellCompDirectiveDefault },
+ "label=": func(s string) ([]string, cobra.ShellCompDirective) {
+ if strings.HasPrefix(s, "d") {
+ return []string{"disable"}, cobra.ShellCompDirectiveNoFileComp
+ }
+ return []string{"user:", "role:", "type:", "level:", "filetype:", "disable"}, cobra.ShellCompDirectiveNoSpace | cobra.ShellCompDirectiveNoFileComp
+ },
+ }
+ return completeKeyValues(toComplete, kv)
+}
+
+// AutocompleteStopSignal - Autocomplete stop signal options.
+// -> "SIGHUP", "SIGINT", "SIGKILL", "SIGTERM"
+func AutocompleteStopSignal(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ // FIXME: add more/different signals?
+ stopSignals := []string{"SIGHUP", "SIGINT", "SIGKILL", "SIGTERM"}
+ return stopSignals, cobra.ShellCompDirectiveNoFileComp
+}
+
+// AutocompleteSystemdFlag - Autocomplete systemd flag options.
+// -> "true", "false", "always"
+func AutocompleteSystemdFlag(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ systemd := []string{"true", "false", "always"}
+ return systemd, cobra.ShellCompDirectiveNoFileComp
+}
+
+// AutocompleteUserFlag - Autocomplete user flag based on the names and groups (includes ids after first char) in /etc/passwd and /etc/group files.
+// -> user:group
+func AutocompleteUserFlag(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ if strings.Contains(toComplete, ":") {
+ // It would be nice to read the file in the image
+ // but at this point we don't know the image.
+ file, err := os.Open("/etc/group")
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ defer file.Close()
+
+ var groups []string
+ scanner := bufio.NewScanner(file)
+ user := strings.SplitN(toComplete, ":", 2)[0]
+ for scanner.Scan() {
+ entries := strings.SplitN(scanner.Text(), ":", 4)
+ groups = append(groups, user+":"+entries[0])
+ // complete ids after at least one char is given
+ if len(user)+1 < len(toComplete) {
+ groups = append(groups, user+":"+entries[2])
+ }
+ }
+ if err = scanner.Err(); err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ return groups, cobra.ShellCompDirectiveNoFileComp
+ }
+
+ // It would be nice to read the file in the image
+ // but at this point we don't know the image.
+ file, err := os.Open("/etc/passwd")
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ defer file.Close()
+
+ var users []string
+ scanner := bufio.NewScanner(file)
+ for scanner.Scan() {
+ entries := strings.SplitN(scanner.Text(), ":", 7)
+ users = append(users, entries[0]+":")
+ // complete ids after at least one char is given
+ if len(toComplete) > 0 {
+ users = append(users, entries[2]+":")
+ }
+ }
+ if err = scanner.Err(); err != nil {
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ return users, cobra.ShellCompDirectiveNoSpace
+}
+
+// AutocompleteMountFlag - Autocomplete mount flag options.
+// -> "type=bind,", "type=volume,", "type=tmpfs,"
+func AutocompleteMountFlag(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ types := []string{"type=bind,", "type=volume,", "type=tmpfs,"}
+ // TODO: Add support for all different options
+ return types, cobra.ShellCompDirectiveNoSpace
+}
+
+// AutocompleteVolumeFlag - Autocomplete volume flag options.
+// -> volumes and paths
+func AutocompleteVolumeFlag(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ volumes, _ := getVolumes(cmd, toComplete)
+ directive := cobra.ShellCompDirectiveNoSpace | cobra.ShellCompDirectiveDefault
+ if strings.Contains(toComplete, ":") {
+ // add space after second path
+ directive = cobra.ShellCompDirectiveDefault
+ }
+ return volumes, directive
+}
+
+// AutocompleteJSONFormat - Autocomplete format flag option.
+// -> "json"
+func AutocompleteJSONFormat(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ return []string{"json"}, cobra.ShellCompDirectiveNoFileComp
+}
+
+// AutocompleteEventFilter - Autocomplete event filter flag options.
+// -> "container=", "event=", "image=", "pod=", "volume=", "type="
+func AutocompleteEventFilter(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ eventTypes := func(_ string) ([]string, cobra.ShellCompDirective) {
+ return []string{"attach", "checkpoint", "cleanup", "commit", "create", "exec",
+ "export", "import", "init", "kill", "mount", "pause", "prune", "remove",
+ "restart", "restore", "start", "stop", "sync", "unmount", "unpause",
+ "pull", "push", "save", "tag", "untag", "refresh", "renumber",
+ }, cobra.ShellCompDirectiveNoFileComp
+ }
+ kv := keyValueCompletion{
+ "container=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(cmd, s, completeDefault) },
+ "image=": func(s string) ([]string, cobra.ShellCompDirective) { return getImages(cmd, s) },
+ "pod=": func(s string) ([]string, cobra.ShellCompDirective) { return getPods(cmd, s, completeDefault) },
+ "volume=": func(s string) ([]string, cobra.ShellCompDirective) { return getVolumes(cmd, s) },
+ "event=": eventTypes,
+ "type=": eventTypes,
+ }
+ return completeKeyValues(toComplete, kv)
+}
+
+// AutocompleteSystemdRestartOptions - Autocomplete systemd restart options.
+// -> "no", "on-success", "on-failure", "on-abnormal", "on-watchdog", "on-abort", "always"
+func AutocompleteSystemdRestartOptions(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ return systemdGen.RestartPolicies, cobra.ShellCompDirectiveNoFileComp
+}
+
+// AutocompleteTrustType - Autocomplete trust type options.
+// -> "signedBy", "accept", "reject"
+func AutocompleteTrustType(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ types := []string{"signedBy", "accept", "reject"}
+ return types, cobra.ShellCompDirectiveNoFileComp
+}
+
+// AutocompleteImageSort - Autocomplete images sort options.
+// -> "created", "id", "repository", "size", "tag"
+func AutocompleteImageSort(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ sortBy := []string{"created", "id", "repository", "size", "tag"}
+ return sortBy, cobra.ShellCompDirectiveNoFileComp
+}
+
+// AutocompleteInspectType - Autocomplete inspect type options.
+// -> "container", "image", "all"
+func AutocompleteInspectType(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ types := []string{"container", "image", "all"}
+ return types, cobra.ShellCompDirectiveNoFileComp
+}
+
+// AutocompleteManifestFormat - Autocomplete manifest format options.
+// -> "oci", "v2s2"
+func AutocompleteManifestFormat(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ types := []string{"oci", "v2s2"}
+ return types, cobra.ShellCompDirectiveNoFileComp
+}
+
+// AutocompleteNetworkDriver - Autocomplete network driver option.
+// -> "bridge"
+func AutocompleteNetworkDriver(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ drivers := []string{"bridge"}
+ return drivers, cobra.ShellCompDirectiveNoFileComp
+}
+
+// AutocompletePodShareNamespace - Autocomplete pod create --share flag option.
+// -> "ipc", "net", "pid", "user", "uts", "cgroup", "none"
+func AutocompletePodShareNamespace(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ namespaces := []string{"ipc", "net", "pid", "user", "uts", "cgroup", "none"}
+ return namespaces, cobra.ShellCompDirectiveNoFileComp
+}
+
+// AutocompletePodPsSort - Autocomplete images sort options.
+// -> "created", "id", "name", "status", "number"
+func AutocompletePodPsSort(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ sortBy := []string{"created", "id", "name", "status", "number"}
+ return sortBy, cobra.ShellCompDirectiveNoFileComp
+}
+
+// AutocompletePsSort - Autocomplete images sort options.
+// -> "command", "created", "id", "image", "names", "runningfor", "size", "status"
+func AutocompletePsSort(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ sortBy := []string{"command", "created", "id", "image", "names", "runningfor", "size", "status"}
+ return sortBy, cobra.ShellCompDirectiveNoFileComp
+}
+
+// AutocompleteImageSaveFormat - Autocomplete image save format options.
+// -> "oci-archive", "oci-dir", "docker-dir"
+func AutocompleteImageSaveFormat(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ formats := []string{"oci-archive", "oci-dir", "docker-dir"}
+ return formats, cobra.ShellCompDirectiveNoFileComp
+}
+
+// AutocompleteWaitCondition - Autocomplete wait condition options.
+// -> "unknown", "configured", "created", "running", "stopped", "paused", "exited", "removing"
+func AutocompleteWaitCondition(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ states := []string{"unknown", "configured", "created", "running", "stopped", "paused", "exited", "removing"}
+ return states, cobra.ShellCompDirectiveNoFileComp
+}
+
+// AutocompleteCgroupManager - Autocomplete cgroup manager options.
+// -> "cgroupfs", "systemd"
+func AutocompleteCgroupManager(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ types := []string{"cgroupfs", "systemd"}
+ return types, cobra.ShellCompDirectiveNoFileComp
+}
+
+// AutocompleteEventBackend - Autocomplete event backend options.
+// -> "file", "journald", "none"
+func AutocompleteEventBackend(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ types := []string{"file", "journald", "none"}
+ return types, cobra.ShellCompDirectiveNoFileComp
+}
+
+// AutocompleteLogLevel - Autocomplete log level options.
+// -> "debug", "info", "warn", "error", "fatal", "panic"
+func AutocompleteLogLevel(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ return LogLevels, cobra.ShellCompDirectiveNoFileComp
+}
+
+// AutocompleteSDNotify - Autocomplete sdnotify options.
+// -> "container", "conmon", "ignore"
+func AutocompleteSDNotify(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ types := []string{"container", "conmon", "ignore"}
+ return types, cobra.ShellCompDirectiveNoFileComp
+}
+
+var containerStatuses = []string{"created", "running", "paused", "stopped", "exited", "unknown"}
+
+// AutocompletePsFilters - Autocomplete ps filter options.
+func AutocompletePsFilters(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ kv := keyValueCompletion{
+ "id=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(cmd, s, completeIDs) },
+ "name=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(cmd, s, completeNames) },
+ "status=": func(_ string) ([]string, cobra.ShellCompDirective) {
+ return containerStatuses, cobra.ShellCompDirectiveNoFileComp
+ },
+ "ancestor": func(s string) ([]string, cobra.ShellCompDirective) { return getImages(cmd, s) },
+ "before=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(cmd, s, completeDefault) },
+ "since=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(cmd, s, completeDefault) },
+ "volume=": func(s string) ([]string, cobra.ShellCompDirective) { return getVolumes(cmd, s) },
+ "health=": func(_ string) ([]string, cobra.ShellCompDirective) {
+ return []string{define.HealthCheckHealthy,
+ define.HealthCheckUnhealthy}, cobra.ShellCompDirectiveNoFileComp
+ },
+ "label=": nil,
+ "exited=": nil,
+ "until=": nil,
+ }
+ return completeKeyValues(toComplete, kv)
+}
+
+// AutocompletePodPsFilters - Autocomplete pod ps filter options.
+func AutocompletePodPsFilters(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ kv := keyValueCompletion{
+ "id=": func(s string) ([]string, cobra.ShellCompDirective) { return getPods(cmd, s, completeIDs) },
+ "name=": func(s string) ([]string, cobra.ShellCompDirective) { return getPods(cmd, s, completeNames) },
+ "status=": func(_ string) ([]string, cobra.ShellCompDirective) {
+ return []string{"stopped", "running",
+ "paused", "exited", "dead", "created", "degraded"}, cobra.ShellCompDirectiveNoFileComp
+ },
+ "ctr-ids=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(cmd, s, completeIDs) },
+ "ctr-names=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(cmd, s, completeNames) },
+ "ctr-number=": nil,
+ "ctr-status=": func(_ string) ([]string, cobra.ShellCompDirective) {
+ return containerStatuses, cobra.ShellCompDirectiveNoFileComp
+ },
+ "label=": nil,
+ }
+ return completeKeyValues(toComplete, kv)
+}
+
+// AutocompleteImageFilters - Autocomplete image ls --filter options.
+func AutocompleteImageFilters(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ getBool := func(_ string) ([]string, cobra.ShellCompDirective) {
+ return []string{"true", "false"}, cobra.ShellCompDirectiveNoFileComp
+ }
+ getImg := func(s string) ([]string, cobra.ShellCompDirective) { return getImages(cmd, s) }
+ kv := keyValueCompletion{
+ "before=": getImg,
+ "since=": getImg,
+ "label=": nil,
+ "reference=": nil,
+ "dangling=": getBool,
+ "readonly=": getBool,
+ }
+ return completeKeyValues(toComplete, kv)
+}
+
+// AutocompleteNetworkFilters - Autocomplete network ls --filter options.
+func AutocompleteNetworkFilters(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ kv := keyValueCompletion{
+ "name=": func(s string) ([]string, cobra.ShellCompDirective) { return getNetworks(cmd, s) },
+ "plugin=": nil,
+ }
+ return completeKeyValues(toComplete, kv)
+}
+
+// AutocompleteVolumeFilters - Autocomplete volume ls --filter options.
+func AutocompleteVolumeFilters(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ local := func(_ string) ([]string, cobra.ShellCompDirective) {
+ return []string{"local"}, cobra.ShellCompDirectiveNoFileComp
+ }
+ kv := keyValueCompletion{
+ "name=": func(s string) ([]string, cobra.ShellCompDirective) { return getVolumes(cmd, s) },
+ "driver=": local,
+ "scope=": local,
+ "label=": nil,
+ "opt=": nil,
+ "dangling=": func(_ string) ([]string, cobra.ShellCompDirective) {
+ return []string{"true", "false"}, cobra.ShellCompDirectiveNoFileComp
+ },
+ }
+ return completeKeyValues(toComplete, kv)
+}