Bump github.com/containers/common from 0.22.0 to 0.23.0
Bumps [github.com/containers/common](https://github.com/containers/common) from 0.22.0 to 0.23.0. - [Release notes](https://github.com/containers/common/releases) - [Commits](https://github.com/containers/common/compare/v0.22.0...v0.23.0) Signed-off-by: dependabot-preview[bot] <support@dependabot.com> Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:
		
							parent
							
								
									90c2cc6c83
								
							
						
					
					
						commit
						017f8d6a63
					
				
							
								
								
									
										4
									
								
								go.mod
								
								
								
								
							
							
						
						
									
										4
									
								
								go.mod
								
								
								
								
							| 
						 | 
				
			
			@ -12,7 +12,7 @@ require (
 | 
			
		|||
	github.com/containernetworking/cni v0.8.0
 | 
			
		||||
	github.com/containernetworking/plugins v0.8.7
 | 
			
		||||
	github.com/containers/buildah v1.16.2
 | 
			
		||||
	github.com/containers/common v0.22.0
 | 
			
		||||
	github.com/containers/common v0.23.0
 | 
			
		||||
	github.com/containers/conmon v2.0.20+incompatible
 | 
			
		||||
	github.com/containers/image/v5 v5.6.0
 | 
			
		||||
	github.com/containers/psgo v1.5.1
 | 
			
		||||
| 
						 | 
				
			
			@ -51,7 +51,7 @@ require (
 | 
			
		|||
	github.com/pmezard/go-difflib v1.0.0
 | 
			
		||||
	github.com/rootless-containers/rootlesskit v0.10.1
 | 
			
		||||
	github.com/sirupsen/logrus v1.6.0
 | 
			
		||||
	github.com/spf13/cobra v0.0.7
 | 
			
		||||
	github.com/spf13/cobra v1.0.0
 | 
			
		||||
	github.com/spf13/pflag v1.0.5
 | 
			
		||||
	github.com/stretchr/testify v1.6.1
 | 
			
		||||
	github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										6
									
								
								go.sum
								
								
								
								
							
							
						
						
									
										6
									
								
								go.sum
								
								
								
								
							| 
						 | 
				
			
			@ -73,8 +73,8 @@ github.com/containernetworking/plugins v0.8.7/go.mod h1:R7lXeZaBzpfqapcAbHRW8/CY
 | 
			
		|||
github.com/containers/buildah v1.16.2 h1:u8RA0r9sp3d5df/QRm0glG7L6ZN40UVJcYedwcZGt8w=
 | 
			
		||||
github.com/containers/buildah v1.16.2/go.mod h1:i1XqXgpCROnfcq4oNtfrFEk7UzNDxLJ/PZ+CnPyoIq8=
 | 
			
		||||
github.com/containers/common v0.21.0/go.mod h1:8w8SVwc+P2p1MOnRMbSKNWXt1Iwd2bKFu2LLZx55DTM=
 | 
			
		||||
github.com/containers/common v0.22.0 h1:MjJIMka4pJddHsfZpQCF7jOmX6vXqMs0ojDeYmPKoSk=
 | 
			
		||||
github.com/containers/common v0.22.0/go.mod h1:qsLcLHM7ha5Nc+JDp5duBwfwEfrnlfjXL/K8HO96QHw=
 | 
			
		||||
github.com/containers/common v0.23.0 h1:+g4mI3wUYSzOtoWU9TNVoV4K52/aN6JEz0qs1YdPEe8=
 | 
			
		||||
github.com/containers/common v0.23.0/go.mod h1:E56/N0beWGf+lrrJX32atuo2hkjzHwSC8n1vCG+TAR0=
 | 
			
		||||
github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg=
 | 
			
		||||
github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
 | 
			
		||||
github.com/containers/image/v5 v5.5.2/go.mod h1:4PyNYR0nwlGq/ybVJD9hWlhmIsNra4Q8uOQX2s6E2uM=
 | 
			
		||||
| 
						 | 
				
			
			@ -436,6 +436,8 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU
 | 
			
		|||
github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
 | 
			
		||||
github.com/spf13/cobra v0.0.7 h1:FfTH+vuMXOas8jmfb5/M7dzEYx7LpcLb7a0LPe34uOU=
 | 
			
		||||
github.com/spf13/cobra v0.0.7/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
 | 
			
		||||
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
 | 
			
		||||
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
 | 
			
		||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
 | 
			
		||||
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 | 
			
		||||
github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,7 @@ package auth
 | 
			
		|||
import (
 | 
			
		||||
	"io"
 | 
			
		||||
 | 
			
		||||
	"github.com/containers/common/pkg/completion"
 | 
			
		||||
	"github.com/spf13/pflag"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -49,6 +50,16 @@ func GetLoginFlags(flags *LoginOptions) *pflag.FlagSet {
 | 
			
		|||
	return &fs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetLoginFlagsCompletions returns the FlagCompletions for the login flags
 | 
			
		||||
func GetLoginFlagsCompletions() completion.FlagCompletions {
 | 
			
		||||
	flagCompletion := completion.FlagCompletions{}
 | 
			
		||||
	flagCompletion["authfile"] = completion.AutocompleteDefault
 | 
			
		||||
	flagCompletion["cert-dir"] = completion.AutocompleteDefault
 | 
			
		||||
	flagCompletion["password"] = completion.AutocompleteNone
 | 
			
		||||
	flagCompletion["username"] = completion.AutocompleteNone
 | 
			
		||||
	return flagCompletion
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetLogoutFlags defines and returns logout flags for containers tools
 | 
			
		||||
func GetLogoutFlags(flags *LogoutOptions) *pflag.FlagSet {
 | 
			
		||||
	fs := pflag.FlagSet{}
 | 
			
		||||
| 
						 | 
				
			
			@ -56,3 +67,10 @@ func GetLogoutFlags(flags *LogoutOptions) *pflag.FlagSet {
 | 
			
		|||
	fs.BoolVarP(&flags.All, "all", "a", false, "Remove the cached credentials for all registries in the auth file")
 | 
			
		||||
	return &fs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetLogoutFlagsCompletions returns the FlagCompletions for the logout flags
 | 
			
		||||
func GetLogoutFlagsCompletions() completion.FlagCompletions {
 | 
			
		||||
	flagCompletion := completion.FlagCompletions{}
 | 
			
		||||
	flagCompletion["authfile"] = completion.AutocompleteDefault
 | 
			
		||||
	return flagCompletion
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,26 @@
 | 
			
		|||
package completion
 | 
			
		||||
 | 
			
		||||
import "github.com/spf13/cobra"
 | 
			
		||||
 | 
			
		||||
// FlagCompletions - hold flag completion functions to be applied later with CompleteCommandFlags()
 | 
			
		||||
type FlagCompletions map[string]func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective)
 | 
			
		||||
 | 
			
		||||
// CompleteCommandFlags - Add completion functions for each flagname in FlagCompletions.
 | 
			
		||||
func CompleteCommandFlags(cmd *cobra.Command, flags FlagCompletions) {
 | 
			
		||||
	for flagName, completionFunc := range flags {
 | 
			
		||||
		_ = cmd.RegisterFlagCompletionFunc(flagName, completionFunc)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Autocomplete Functions for cobra ValidArgsFunction */
 | 
			
		||||
 | 
			
		||||
// AutocompleteNone - Block the default shell completion (no paths)
 | 
			
		||||
func AutocompleteNone(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 | 
			
		||||
	return nil, cobra.ShellCompDirectiveNoFileComp
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AutocompleteDefault - Use the default shell completion,
 | 
			
		||||
// allows path completion.
 | 
			
		||||
func AutocompleteDefault(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 | 
			
		||||
	return nil, cobra.ShellCompDirectiveDefault
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -183,6 +183,10 @@ type ContainersConfig struct {
 | 
			
		|||
 | 
			
		||||
// EngineConfig contains configuration options used to set up a engine runtime
 | 
			
		||||
type EngineConfig struct {
 | 
			
		||||
	// ImageBuildFormat indicates the default image format to building
 | 
			
		||||
	// container images.  Valid values are "oci" (default) or "docker".
 | 
			
		||||
	ImageBuildFormat string `toml:"image_build_format,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// CgroupCheck indicates the configuration has been rewritten after an
 | 
			
		||||
	// upgrade to Fedora 31 to change the default OCI runtime for cgroupv2v2.
 | 
			
		||||
	CgroupCheck bool `toml:"cgroup_check,omitempty"`
 | 
			
		||||
| 
						 | 
				
			
			@ -309,7 +313,7 @@ type EngineConfig struct {
 | 
			
		|||
	RuntimeSupportsNoCgroups []string `toml:"runtime_supports_nocgroupv2,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// RuntimeSupportsKVM is a list of OCI runtimes that support
 | 
			
		||||
	// KVM separation for conatainers.
 | 
			
		||||
	// KVM separation for containers.
 | 
			
		||||
	RuntimeSupportsKVM []string `toml:"runtime_supports_kvm,omitempty"`
 | 
			
		||||
 | 
			
		||||
	// SetOptions contains a subset of config options. It's used to indicate if
 | 
			
		||||
| 
						 | 
				
			
			@ -980,8 +984,15 @@ func (c *Config) ActiveDestination() (uri, identity string, err error) {
 | 
			
		|||
		}
 | 
			
		||||
		return uri, identity, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	connEnv := os.Getenv("CONTAINER_CONNECTION")
 | 
			
		||||
	switch {
 | 
			
		||||
	case connEnv != "":
 | 
			
		||||
		d, found := c.Engine.ServiceDestinations[connEnv]
 | 
			
		||||
		if !found {
 | 
			
		||||
			return "", "", errors.Errorf("environment variable CONTAINER_CONNECTION=%q service destination not found", connEnv)
 | 
			
		||||
		}
 | 
			
		||||
		return d.URI, d.Identity, nil
 | 
			
		||||
 | 
			
		||||
	case c.Engine.ActiveService != "":
 | 
			
		||||
		d, found := c.Engine.ServiceDestinations[c.Engine.ActiveService]
 | 
			
		||||
		if !found {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -243,6 +243,9 @@
 | 
			
		|||
# network_config_dir = "/etc/cni/net.d/"
 | 
			
		||||
 | 
			
		||||
[engine]
 | 
			
		||||
# ImageBuildFormat indicates the default image format to building
 | 
			
		||||
# container images. Valid values are "oci" (default) or "docker".
 | 
			
		||||
# image_build_format = "oci"
 | 
			
		||||
 | 
			
		||||
# Cgroup management implementation used for the runtime.
 | 
			
		||||
# Valid options "systemd" or "cgroupfs"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -250,6 +250,8 @@ func defaultConfigFromMemory() (*EngineConfig, error) {
 | 
			
		|||
	if cgroup2, _ := cgroupv2.Enabled(); cgroup2 {
 | 
			
		||||
		c.OCIRuntime = "crun"
 | 
			
		||||
	}
 | 
			
		||||
	c.ImageBuildFormat = "oci"
 | 
			
		||||
 | 
			
		||||
	c.CgroupManager = defaultCgroupManager()
 | 
			
		||||
	c.StopTimeout = uint(10)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -186,7 +186,7 @@ type ConfigFromLibpod struct {
 | 
			
		|||
// with cgroupv2v2. Other OCI runtimes are not yet supporting cgroupv2v2. This
 | 
			
		||||
// might change in the future.
 | 
			
		||||
func newLibpodConfig(c *Config) error {
 | 
			
		||||
	// Start with the default config and interatively merge
 | 
			
		||||
	// Start with the default config and iteratively merge
 | 
			
		||||
	// fields in the system configs.
 | 
			
		||||
	config := c.libpodConfig()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -99,7 +99,6 @@ func DefaultProfile() *Seccomp {
 | 
			
		|||
				"fchdir",
 | 
			
		||||
				"fchmod",
 | 
			
		||||
				"fchmodat",
 | 
			
		||||
				"fchmodat2",
 | 
			
		||||
				"fchown",
 | 
			
		||||
				"fchown32",
 | 
			
		||||
				"fchownat",
 | 
			
		||||
| 
						 | 
				
			
			@ -221,6 +220,7 @@ func DefaultProfile() *Seccomp {
 | 
			
		|||
				"openat",
 | 
			
		||||
				"openat2",
 | 
			
		||||
				"pause",
 | 
			
		||||
				"pidfd_getfd",
 | 
			
		||||
				"pipe",
 | 
			
		||||
				"pipe2",
 | 
			
		||||
				"pivot_root",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -101,7 +101,6 @@
 | 
			
		|||
				"fchdir",
 | 
			
		||||
				"fchmod",
 | 
			
		||||
				"fchmodat",
 | 
			
		||||
				"fchmodat2",
 | 
			
		||||
				"fchown",
 | 
			
		||||
				"fchown32",
 | 
			
		||||
				"fchownat",
 | 
			
		||||
| 
						 | 
				
			
			@ -223,6 +222,7 @@
 | 
			
		|||
				"openat",
 | 
			
		||||
				"openat2",
 | 
			
		||||
				"pause",
 | 
			
		||||
				"pidfd_getfd",
 | 
			
		||||
				"pipe",
 | 
			
		||||
				"pipe2",
 | 
			
		||||
				"pivot_root",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
package version
 | 
			
		||||
 | 
			
		||||
// Version is the version of the build.
 | 
			
		||||
const Version = "0.22.0"
 | 
			
		||||
const Version = "0.23.0"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,10 +25,10 @@ Many of the most widely used Go projects are built using Cobra, such as:
 | 
			
		|||
[mattermost-server](https://github.com/mattermost/mattermost-server),
 | 
			
		||||
[Gardener](https://github.com/gardener/gardenctl),
 | 
			
		||||
[Linkerd](https://linkerd.io/),
 | 
			
		||||
[Github CLI](https://github.com/cli/cli)
 | 
			
		||||
etc.
 | 
			
		||||
 | 
			
		||||
[](https://travis-ci.org/spf13/cobra)
 | 
			
		||||
[](https://circleci.com/gh/spf13/cobra)
 | 
			
		||||
[](https://godoc.org/github.com/spf13/cobra)
 | 
			
		||||
[](https://goreportcard.com/report/github.com/spf13/cobra)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@ package cobra
 | 
			
		|||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type PositionalArgs func(cmd *Command, args []string) error
 | 
			
		||||
| 
						 | 
				
			
			@ -34,8 +35,15 @@ func NoArgs(cmd *Command, args []string) error {
 | 
			
		|||
// OnlyValidArgs returns an error if any args are not in the list of ValidArgs.
 | 
			
		||||
func OnlyValidArgs(cmd *Command, args []string) error {
 | 
			
		||||
	if len(cmd.ValidArgs) > 0 {
 | 
			
		||||
		// Remove any description that may be included in ValidArgs.
 | 
			
		||||
		// A description is following a tab character.
 | 
			
		||||
		var validArgs []string
 | 
			
		||||
		for _, v := range cmd.ValidArgs {
 | 
			
		||||
			validArgs = append(validArgs, strings.Split(v, "\t")[0])
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for _, v := range args {
 | 
			
		||||
			if !stringInSlice(v, cmd.ValidArgs) {
 | 
			
		||||
			if !stringInSlice(v, validArgs) {
 | 
			
		||||
				return fmt.Errorf("invalid argument %q for %q%s", v, cmd.CommandPath(), cmd.findSuggestions(args[0]))
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -58,6 +58,67 @@ __%[1]s_contains_word()
 | 
			
		|||
    return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
__%[1]s_handle_go_custom_completion()
 | 
			
		||||
{
 | 
			
		||||
    __%[1]s_debug "${FUNCNAME[0]}: cur is ${cur}, words[*] is ${words[*]}, #words[@] is ${#words[@]}"
 | 
			
		||||
 | 
			
		||||
    local out requestComp lastParam lastChar comp directive args
 | 
			
		||||
 | 
			
		||||
    # Prepare the command to request completions for the program.
 | 
			
		||||
    # Calling ${words[0]} instead of directly %[1]s allows to handle aliases
 | 
			
		||||
    args=("${words[@]:1}")
 | 
			
		||||
    requestComp="${words[0]} %[2]s ${args[*]}"
 | 
			
		||||
 | 
			
		||||
    lastParam=${words[$((${#words[@]}-1))]}
 | 
			
		||||
    lastChar=${lastParam:$((${#lastParam}-1)):1}
 | 
			
		||||
    __%[1]s_debug "${FUNCNAME[0]}: lastParam ${lastParam}, lastChar ${lastChar}"
 | 
			
		||||
 | 
			
		||||
    if [ -z "${cur}" ] && [ "${lastChar}" != "=" ]; then
 | 
			
		||||
        # If the last parameter is complete (there is a space following it)
 | 
			
		||||
        # We add an extra empty parameter so we can indicate this to the go method.
 | 
			
		||||
        __%[1]s_debug "${FUNCNAME[0]}: Adding extra empty parameter"
 | 
			
		||||
        requestComp="${requestComp} \"\""
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    __%[1]s_debug "${FUNCNAME[0]}: calling ${requestComp}"
 | 
			
		||||
    # Use eval to handle any environment variables and such
 | 
			
		||||
    out=$(eval "${requestComp}" 2>/dev/null)
 | 
			
		||||
 | 
			
		||||
    # Extract the directive integer at the very end of the output following a colon (:)
 | 
			
		||||
    directive=${out##*:}
 | 
			
		||||
    # Remove the directive
 | 
			
		||||
    out=${out%%:*}
 | 
			
		||||
    if [ "${directive}" = "${out}" ]; then
 | 
			
		||||
        # There is not directive specified
 | 
			
		||||
        directive=0
 | 
			
		||||
    fi
 | 
			
		||||
    __%[1]s_debug "${FUNCNAME[0]}: the completion directive is: ${directive}"
 | 
			
		||||
    __%[1]s_debug "${FUNCNAME[0]}: the completions are: ${out[*]}"
 | 
			
		||||
 | 
			
		||||
    if [ $((directive & %[3]d)) -ne 0 ]; then
 | 
			
		||||
        # Error code.  No completion.
 | 
			
		||||
        __%[1]s_debug "${FUNCNAME[0]}: received error from custom completion go code"
 | 
			
		||||
        return
 | 
			
		||||
    else
 | 
			
		||||
        if [ $((directive & %[4]d)) -ne 0 ]; then
 | 
			
		||||
            if [[ $(type -t compopt) = "builtin" ]]; then
 | 
			
		||||
                __%[1]s_debug "${FUNCNAME[0]}: activating no space"
 | 
			
		||||
                compopt -o nospace
 | 
			
		||||
            fi
 | 
			
		||||
        fi
 | 
			
		||||
        if [ $((directive & %[5]d)) -ne 0 ]; then
 | 
			
		||||
            if [[ $(type -t compopt) = "builtin" ]]; then
 | 
			
		||||
                __%[1]s_debug "${FUNCNAME[0]}: activating no file completion"
 | 
			
		||||
                compopt +o default
 | 
			
		||||
            fi
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
        while IFS='' read -r comp; do
 | 
			
		||||
            COMPREPLY+=("$comp")
 | 
			
		||||
        done < <(compgen -W "${out[*]}" -- "$cur")
 | 
			
		||||
    fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
__%[1]s_handle_reply()
 | 
			
		||||
{
 | 
			
		||||
    __%[1]s_debug "${FUNCNAME[0]}"
 | 
			
		||||
| 
						 | 
				
			
			@ -121,6 +182,10 @@ __%[1]s_handle_reply()
 | 
			
		|||
    completions=("${commands[@]}")
 | 
			
		||||
    if [[ ${#must_have_one_noun[@]} -ne 0 ]]; then
 | 
			
		||||
        completions=("${must_have_one_noun[@]}")
 | 
			
		||||
    elif [[ -n "${has_completion_function}" ]]; then
 | 
			
		||||
        # if a go completion function is provided, defer to that function
 | 
			
		||||
        completions=()
 | 
			
		||||
        __%[1]s_handle_go_custom_completion
 | 
			
		||||
    fi
 | 
			
		||||
    if [[ ${#must_have_one_flag[@]} -ne 0 ]]; then
 | 
			
		||||
        completions+=("${must_have_one_flag[@]}")
 | 
			
		||||
| 
						 | 
				
			
			@ -279,7 +344,7 @@ __%[1]s_handle_word()
 | 
			
		|||
    __%[1]s_handle_word
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
`, name))
 | 
			
		||||
`, name, ShellCompNoDescRequestCmd, ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func writePostscript(buf *bytes.Buffer, name string) {
 | 
			
		||||
| 
						 | 
				
			
			@ -304,6 +369,7 @@ func writePostscript(buf *bytes.Buffer, name string) {
 | 
			
		|||
    local commands=("%[1]s")
 | 
			
		||||
    local must_have_one_flag=()
 | 
			
		||||
    local must_have_one_noun=()
 | 
			
		||||
    local has_completion_function
 | 
			
		||||
    local last_command
 | 
			
		||||
    local nouns=()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -404,7 +470,22 @@ func writeLocalNonPersistentFlag(buf *bytes.Buffer, flag *pflag.Flag) {
 | 
			
		|||
	buf.WriteString(fmt.Sprintf(format, name))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Setup annotations for go completions for registered flags
 | 
			
		||||
func prepareCustomAnnotationsForFlags(cmd *Command) {
 | 
			
		||||
	for flag := range flagCompletionFunctions {
 | 
			
		||||
		// Make sure the completion script calls the __*_go_custom_completion function for
 | 
			
		||||
		// every registered flag.  We need to do this here (and not when the flag was registered
 | 
			
		||||
		// for completion) so that we can know the root command name for the prefix
 | 
			
		||||
		// of __<prefix>_go_custom_completion
 | 
			
		||||
		if flag.Annotations == nil {
 | 
			
		||||
			flag.Annotations = map[string][]string{}
 | 
			
		||||
		}
 | 
			
		||||
		flag.Annotations[BashCompCustom] = []string{fmt.Sprintf("__%[1]s_handle_go_custom_completion", cmd.Root().Name())}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func writeFlags(buf *bytes.Buffer, cmd *Command) {
 | 
			
		||||
	prepareCustomAnnotationsForFlags(cmd)
 | 
			
		||||
	buf.WriteString(`    flags=()
 | 
			
		||||
    two_word_flags=()
 | 
			
		||||
    local_nonpersistent_flags=()
 | 
			
		||||
| 
						 | 
				
			
			@ -467,8 +548,14 @@ func writeRequiredNouns(buf *bytes.Buffer, cmd *Command) {
 | 
			
		|||
	buf.WriteString("    must_have_one_noun=()\n")
 | 
			
		||||
	sort.Sort(sort.StringSlice(cmd.ValidArgs))
 | 
			
		||||
	for _, value := range cmd.ValidArgs {
 | 
			
		||||
		// Remove any description that may be included following a tab character.
 | 
			
		||||
		// Descriptions are not supported by bash completion.
 | 
			
		||||
		value = strings.Split(value, "\t")[0]
 | 
			
		||||
		buf.WriteString(fmt.Sprintf("    must_have_one_noun+=(%q)\n", value))
 | 
			
		||||
	}
 | 
			
		||||
	if cmd.ValidArgsFunction != nil {
 | 
			
		||||
		buf.WriteString("    has_completion_function=1\n")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func writeCmdAliases(buf *bytes.Buffer, cmd *Command) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -56,7 +56,149 @@ func main() {
 | 
			
		|||
 | 
			
		||||
`out.sh` will get you completions of subcommands and flags. Copy it to `/etc/bash_completion.d/` as described [here](https://debian-administration.org/article/316/An_introduction_to_bash_completion_part_1) and reset your terminal to use autocompletion. If you make additional annotations to your code, you can get even more intelligent and flexible behavior.
 | 
			
		||||
 | 
			
		||||
## Creating your own custom functions
 | 
			
		||||
## Have the completions code complete your 'nouns'
 | 
			
		||||
 | 
			
		||||
### Static completion of nouns
 | 
			
		||||
 | 
			
		||||
This method allows you to provide a pre-defined list of completion choices for your nouns using the `validArgs` field.
 | 
			
		||||
For example, if you want `kubectl get [tab][tab]` to show a list of valid "nouns" you have to set them. Simplified code from `kubectl get` looks like:
 | 
			
		||||
 | 
			
		||||
```go
 | 
			
		||||
validArgs []string = { "pod", "node", "service", "replicationcontroller" }
 | 
			
		||||
 | 
			
		||||
cmd := &cobra.Command{
 | 
			
		||||
	Use:     "get [(-o|--output=)json|yaml|template|...] (RESOURCE [NAME] | RESOURCE/NAME ...)",
 | 
			
		||||
	Short:   "Display one or many resources",
 | 
			
		||||
	Long:    get_long,
 | 
			
		||||
	Example: get_example,
 | 
			
		||||
	Run: func(cmd *cobra.Command, args []string) {
 | 
			
		||||
		err := RunGet(f, out, cmd, args)
 | 
			
		||||
		util.CheckErr(err)
 | 
			
		||||
	},
 | 
			
		||||
	ValidArgs: validArgs,
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Notice we put the "ValidArgs" on the "get" subcommand. Doing so will give results like
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
# kubectl get [tab][tab]
 | 
			
		||||
node                 pod                    replicationcontroller  service
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Plural form and shortcuts for nouns
 | 
			
		||||
 | 
			
		||||
If your nouns have a number of aliases, you can define them alongside `ValidArgs` using `ArgAliases`:
 | 
			
		||||
 | 
			
		||||
```go
 | 
			
		||||
argAliases []string = { "pods", "nodes", "services", "svc", "replicationcontrollers", "rc" }
 | 
			
		||||
 | 
			
		||||
cmd := &cobra.Command{
 | 
			
		||||
    ...
 | 
			
		||||
	ValidArgs:  validArgs,
 | 
			
		||||
	ArgAliases: argAliases
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The aliases are not shown to the user on tab completion, but they are accepted as valid nouns by
 | 
			
		||||
the completion algorithm if entered manually, e.g. in:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
# kubectl get rc [tab][tab]
 | 
			
		||||
backend        frontend       database 
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Note that without declaring `rc` as an alias, the completion algorithm would show the list of nouns
 | 
			
		||||
in this example again instead of the replication controllers.
 | 
			
		||||
 | 
			
		||||
### Dynamic completion of nouns
 | 
			
		||||
 | 
			
		||||
In some cases it is not possible to provide a list of possible completions in advance.  Instead, the list of completions must be determined at execution-time.  Cobra provides two ways of defining such dynamic completion of nouns. Note that both these methods can be used along-side each other as long as they are not both used for the same command.
 | 
			
		||||
 | 
			
		||||
**Note**: *Custom Completions written in Go* will automatically work for other shell-completion scripts (e.g., Fish shell), while *Custom Completions written in Bash* will only work for Bash shell-completion.  It is therefore recommended to use *Custom Completions written in Go*.
 | 
			
		||||
 | 
			
		||||
#### 1. Custom completions of nouns written in Go
 | 
			
		||||
 | 
			
		||||
In a similar fashion as for static completions, you can use the `ValidArgsFunction` field to provide a Go function that Cobra will execute when it needs the list of completion choices for the nouns of a command.  Note that either `ValidArgs` or `ValidArgsFunction` can be used for a single cobra command, but not both.
 | 
			
		||||
Simplified code from `helm status` looks like:
 | 
			
		||||
 | 
			
		||||
```go
 | 
			
		||||
cmd := &cobra.Command{
 | 
			
		||||
	Use:   "status RELEASE_NAME",
 | 
			
		||||
	Short: "Display the status of the named release",
 | 
			
		||||
	Long:  status_long,
 | 
			
		||||
	RunE: func(cmd *cobra.Command, args []string) {
 | 
			
		||||
		RunGet(args[0])
 | 
			
		||||
	},
 | 
			
		||||
	ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 | 
			
		||||
		if len(args) != 0 {
 | 
			
		||||
			return nil, cobra.ShellCompDirectiveNoFileComp
 | 
			
		||||
		}
 | 
			
		||||
		return getReleasesFromCluster(toComplete), cobra.ShellCompDirectiveNoFileComp
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
Where `getReleasesFromCluster()` is a Go function that obtains the list of current Helm releases running on the Kubernetes cluster.
 | 
			
		||||
Notice we put the `ValidArgsFunction` on the `status` subcommand. Let's assume the Helm releases on the cluster are: `harbor`, `notary`, `rook` and `thanos` then this dynamic completion will give results like
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
# helm status [tab][tab]
 | 
			
		||||
harbor notary rook thanos
 | 
			
		||||
```
 | 
			
		||||
You may have noticed the use of `cobra.ShellCompDirective`.  These directives are bit fields allowing to control some shell completion behaviors for your particular completion.  You can combine them with the bit-or operator such as `cobra.ShellCompDirectiveNoSpace | cobra.ShellCompDirectiveNoFileComp`
 | 
			
		||||
```go
 | 
			
		||||
// Indicates an error occurred and completions should be ignored.
 | 
			
		||||
ShellCompDirectiveError
 | 
			
		||||
// Indicates that the shell should not add a space after the completion,
 | 
			
		||||
// even if there is a single completion provided.
 | 
			
		||||
ShellCompDirectiveNoSpace
 | 
			
		||||
// Indicates that the shell should not provide file completion even when
 | 
			
		||||
// no completion is provided.
 | 
			
		||||
// This currently does not work for zsh or bash < 4
 | 
			
		||||
ShellCompDirectiveNoFileComp
 | 
			
		||||
// Indicates that the shell will perform its default behavior after completions
 | 
			
		||||
// have been provided (this implies !ShellCompDirectiveNoSpace && !ShellCompDirectiveNoFileComp).
 | 
			
		||||
ShellCompDirectiveDefault
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
When using the `ValidArgsFunction`, Cobra will call your registered function after having parsed all flags and arguments provided in the command-line.  You therefore don't need to do this parsing yourself.  For example, when a user calls `helm status --namespace my-rook-ns [tab][tab]`, Cobra will call your registered `ValidArgsFunction` after having parsed the `--namespace` flag, as it would have done when calling the `RunE` function.
 | 
			
		||||
 | 
			
		||||
##### Debugging
 | 
			
		||||
 | 
			
		||||
Cobra achieves dynamic completions written in Go through the use of a hidden command called by the completion script.  To debug your Go completion code, you can call this hidden command directly:
 | 
			
		||||
```bash
 | 
			
		||||
# helm __complete status har<ENTER>
 | 
			
		||||
harbor
 | 
			
		||||
:4
 | 
			
		||||
Completion ended with directive: ShellCompDirectiveNoFileComp # This is on stderr
 | 
			
		||||
```
 | 
			
		||||
***Important:*** If the noun to complete is empty, you must pass an empty parameter to the `__complete` command:
 | 
			
		||||
```bash
 | 
			
		||||
# helm __complete status ""<ENTER>
 | 
			
		||||
harbor
 | 
			
		||||
notary
 | 
			
		||||
rook
 | 
			
		||||
thanos
 | 
			
		||||
:4
 | 
			
		||||
Completion ended with directive: ShellCompDirectiveNoFileComp # This is on stderr
 | 
			
		||||
```
 | 
			
		||||
Calling the `__complete` command directly allows you to run the Go debugger to troubleshoot your code.  You can also add printouts to your code; Cobra provides the following functions to use for printouts in Go completion code:
 | 
			
		||||
```go
 | 
			
		||||
// Prints to the completion script debug file (if BASH_COMP_DEBUG_FILE
 | 
			
		||||
// is set to a file path) and optionally prints to stderr.
 | 
			
		||||
cobra.CompDebug(msg string, printToStdErr bool) {
 | 
			
		||||
cobra.CompDebugln(msg string, printToStdErr bool)
 | 
			
		||||
 | 
			
		||||
// Prints to the completion script debug file (if BASH_COMP_DEBUG_FILE
 | 
			
		||||
// is set to a file path) and to stderr.
 | 
			
		||||
cobra.CompError(msg string)
 | 
			
		||||
cobra.CompErrorln(msg string)
 | 
			
		||||
```
 | 
			
		||||
***Important:*** You should **not** leave traces that print to stdout in your completion code as they will be interpreted as completion choices by the completion script.  Instead, use the cobra-provided debugging traces functions mentioned above.
 | 
			
		||||
 | 
			
		||||
#### 2. Custom completions of nouns written in Bash
 | 
			
		||||
 | 
			
		||||
This method allows you to inject bash functions into the completion script.  Those bash functions are responsible for providing the completion choices for your own completions.
 | 
			
		||||
 | 
			
		||||
Some more actual code that works in kubernetes:
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -111,58 +253,6 @@ Find more information at https://github.com/GoogleCloudPlatform/kubernetes.`,
 | 
			
		|||
 | 
			
		||||
The `BashCompletionFunction` option is really only valid/useful on the root command. Doing the above will cause `__kubectl_custom_func()` (`__<command-use>_custom_func()`) to be called when the built in processor was unable to find a solution. In the case of kubernetes a valid command might look something like `kubectl get pod [mypod]`. If you type `kubectl get pod [tab][tab]` the `__kubectl_customc_func()` will run because the cobra.Command only understood "kubectl" and "get." `__kubectl_custom_func()` will see that the cobra.Command is "kubectl_get" and will thus call another helper `__kubectl_get_resource()`.  `__kubectl_get_resource` will look at the 'nouns' collected. In our example the only noun will be `pod`.  So it will call `__kubectl_parse_get pod`.  `__kubectl_parse_get` will actually call out to kubernetes and get any pods.  It will then set `COMPREPLY` to valid pods!
 | 
			
		||||
 | 
			
		||||
## Have the completions code complete your 'nouns'
 | 
			
		||||
 | 
			
		||||
In the above example "pod" was assumed to already be typed. But if you want `kubectl get [tab][tab]` to show a list of valid "nouns" you have to set them. Simplified code from `kubectl get` looks like:
 | 
			
		||||
 | 
			
		||||
```go
 | 
			
		||||
validArgs []string = { "pod", "node", "service", "replicationcontroller" }
 | 
			
		||||
 | 
			
		||||
cmd := &cobra.Command{
 | 
			
		||||
	Use:     "get [(-o|--output=)json|yaml|template|...] (RESOURCE [NAME] | RESOURCE/NAME ...)",
 | 
			
		||||
	Short:   "Display one or many resources",
 | 
			
		||||
	Long:    get_long,
 | 
			
		||||
	Example: get_example,
 | 
			
		||||
	Run: func(cmd *cobra.Command, args []string) {
 | 
			
		||||
		err := RunGet(f, out, cmd, args)
 | 
			
		||||
		util.CheckErr(err)
 | 
			
		||||
	},
 | 
			
		||||
	ValidArgs: validArgs,
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Notice we put the "ValidArgs" on the "get" subcommand. Doing so will give results like
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
# kubectl get [tab][tab]
 | 
			
		||||
node                 pod                    replicationcontroller  service
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Plural form and shortcuts for nouns
 | 
			
		||||
 | 
			
		||||
If your nouns have a number of aliases, you can define them alongside `ValidArgs` using `ArgAliases`:
 | 
			
		||||
 | 
			
		||||
```go
 | 
			
		||||
argAliases []string = { "pods", "nodes", "services", "svc", "replicationcontrollers", "rc" }
 | 
			
		||||
 | 
			
		||||
cmd := &cobra.Command{
 | 
			
		||||
    ...
 | 
			
		||||
	ValidArgs:  validArgs,
 | 
			
		||||
	ArgAliases: argAliases
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The aliases are not shown to the user on tab completion, but they are accepted as valid nouns by
 | 
			
		||||
the completion algorithm if entered manually, e.g. in:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
# kubectl get rc [tab][tab]
 | 
			
		||||
backend        frontend       database 
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Note that without declaring `rc` as an alias, the completion algorithm would show the list of nouns
 | 
			
		||||
in this example again instead of the replication controllers.
 | 
			
		||||
 | 
			
		||||
## Mark flags as required
 | 
			
		||||
 | 
			
		||||
Most of the time completions will only show subcommands. But if a flag is required to make a subcommand work, you probably want it to show up when the user types [tab][tab].  Marking a flag as 'Required' is incredibly easy.
 | 
			
		||||
| 
						 | 
				
			
			@ -211,8 +301,45 @@ So while there are many other files in the CWD it only shows me subdirs and thos
 | 
			
		|||
 | 
			
		||||
# Specify custom flag completion
 | 
			
		||||
 | 
			
		||||
Similar to the filename completion and filtering using cobra.BashCompFilenameExt, you can specify
 | 
			
		||||
a custom flag completion function with cobra.BashCompCustom:
 | 
			
		||||
As for nouns, Cobra provides two ways of defining dynamic completion of flags.  Note that both these methods can be used along-side each other as long as they are not both used for the same flag.
 | 
			
		||||
 | 
			
		||||
**Note**: *Custom Completions written in Go* will automatically work for other shell-completion scripts (e.g., Fish shell), while *Custom Completions written in Bash* will only work for Bash shell-completion.  It is therefore recommended to use *Custom Completions written in Go*.
 | 
			
		||||
 | 
			
		||||
## 1. Custom completions of flags written in Go
 | 
			
		||||
 | 
			
		||||
To provide a Go function that Cobra will execute when it needs the list of completion choices for a flag, you must register the function in the following manner:
 | 
			
		||||
 | 
			
		||||
```go
 | 
			
		||||
flagName := "output"
 | 
			
		||||
cmd.RegisterFlagCompletionFunc(flagName, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 | 
			
		||||
	return []string{"json", "table", "yaml"}, cobra.ShellCompDirectiveDefault
 | 
			
		||||
})
 | 
			
		||||
```
 | 
			
		||||
Notice that calling `RegisterFlagCompletionFunc()` is done through the `command` with which the flag is associated.  In our example this dynamic completion will give results like so:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
# helm status --output [tab][tab]
 | 
			
		||||
json table yaml
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Debugging
 | 
			
		||||
 | 
			
		||||
You can also easily debug your Go completion code for flags:
 | 
			
		||||
```bash
 | 
			
		||||
# helm __complete status --output ""
 | 
			
		||||
json
 | 
			
		||||
table
 | 
			
		||||
yaml
 | 
			
		||||
:4
 | 
			
		||||
Completion ended with directive: ShellCompDirectiveNoFileComp # This is on stderr
 | 
			
		||||
```
 | 
			
		||||
***Important:*** You should **not** leave traces that print to stdout in your completion code as they will be interpreted as completion choices by the completion script.  Instead, use the cobra-provided debugging traces functions mentioned in the above section.
 | 
			
		||||
 | 
			
		||||
## 2. Custom completions of flags written in Bash
 | 
			
		||||
 | 
			
		||||
Alternatively, you can use bash code for flag custom completion. Similar to the filename
 | 
			
		||||
completion and filtering using `cobra.BashCompFilenameExt`, you can specify
 | 
			
		||||
a custom flag completion bash function with `cobra.BashCompCustom`:
 | 
			
		||||
 | 
			
		||||
```go
 | 
			
		||||
	annotation := make(map[string][]string)
 | 
			
		||||
| 
						 | 
				
			
			@ -226,7 +353,7 @@ a custom flag completion function with cobra.BashCompCustom:
 | 
			
		|||
	cmd.Flags().AddFlag(flag)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
In addition add the `__handle_namespace_flag` implementation in the `BashCompletionFunction`
 | 
			
		||||
In addition add the `__kubectl_get_namespaces` implementation in the `BashCompletionFunction`
 | 
			
		||||
value, e.g.:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -57,6 +57,10 @@ type Command struct {
 | 
			
		|||
 | 
			
		||||
	// ValidArgs is list of all valid non-flag arguments that are accepted in bash completions
 | 
			
		||||
	ValidArgs []string
 | 
			
		||||
	// ValidArgsFunction is an optional function that provides valid non-flag arguments for bash completion.
 | 
			
		||||
	// It is a dynamic version of using ValidArgs.
 | 
			
		||||
	// Only one of ValidArgs and ValidArgsFunction can be used for a command.
 | 
			
		||||
	ValidArgsFunction func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective)
 | 
			
		||||
 | 
			
		||||
	// Expected arguments
 | 
			
		||||
	Args PositionalArgs
 | 
			
		||||
| 
						 | 
				
			
			@ -911,6 +915,9 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
 | 
			
		|||
		args = os.Args[1:]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// initialize the hidden command to be used for bash completion
 | 
			
		||||
	c.initCompleteCmd(args)
 | 
			
		||||
 | 
			
		||||
	var flags []string
 | 
			
		||||
	if c.TraverseChildren {
 | 
			
		||||
		cmd, flags, err = c.Traverse(args)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,384 @@
 | 
			
		|||
package cobra
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/spf13/pflag"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// ShellCompRequestCmd is the name of the hidden command that is used to request
 | 
			
		||||
	// completion results from the program.  It is used by the shell completion scripts.
 | 
			
		||||
	ShellCompRequestCmd = "__complete"
 | 
			
		||||
	// ShellCompNoDescRequestCmd is the name of the hidden command that is used to request
 | 
			
		||||
	// completion results without their description.  It is used by the shell completion scripts.
 | 
			
		||||
	ShellCompNoDescRequestCmd = "__completeNoDesc"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Global map of flag completion functions.
 | 
			
		||||
var flagCompletionFunctions = map[*pflag.Flag]func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective){}
 | 
			
		||||
 | 
			
		||||
// ShellCompDirective is a bit map representing the different behaviors the shell
 | 
			
		||||
// can be instructed to have once completions have been provided.
 | 
			
		||||
type ShellCompDirective int
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// ShellCompDirectiveError indicates an error occurred and completions should be ignored.
 | 
			
		||||
	ShellCompDirectiveError ShellCompDirective = 1 << iota
 | 
			
		||||
 | 
			
		||||
	// ShellCompDirectiveNoSpace indicates that the shell should not add a space
 | 
			
		||||
	// after the completion even if there is a single completion provided.
 | 
			
		||||
	ShellCompDirectiveNoSpace
 | 
			
		||||
 | 
			
		||||
	// ShellCompDirectiveNoFileComp indicates that the shell should not provide
 | 
			
		||||
	// file completion even when no completion is provided.
 | 
			
		||||
	// This currently does not work for zsh or bash < 4
 | 
			
		||||
	ShellCompDirectiveNoFileComp
 | 
			
		||||
 | 
			
		||||
	// ShellCompDirectiveDefault indicates to let the shell perform its default
 | 
			
		||||
	// behavior after completions have been provided.
 | 
			
		||||
	ShellCompDirectiveDefault ShellCompDirective = 0
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// RegisterFlagCompletionFunc should be called to register a function to provide completion for a flag.
 | 
			
		||||
func (c *Command) RegisterFlagCompletionFunc(flagName string, f func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective)) error {
 | 
			
		||||
	flag := c.Flag(flagName)
 | 
			
		||||
	if flag == nil {
 | 
			
		||||
		return fmt.Errorf("RegisterFlagCompletionFunc: flag '%s' does not exist", flagName)
 | 
			
		||||
	}
 | 
			
		||||
	if _, exists := flagCompletionFunctions[flag]; exists {
 | 
			
		||||
		return fmt.Errorf("RegisterFlagCompletionFunc: flag '%s' already registered", flagName)
 | 
			
		||||
	}
 | 
			
		||||
	flagCompletionFunctions[flag] = f
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns a string listing the different directive enabled in the specified parameter
 | 
			
		||||
func (d ShellCompDirective) string() string {
 | 
			
		||||
	var directives []string
 | 
			
		||||
	if d&ShellCompDirectiveError != 0 {
 | 
			
		||||
		directives = append(directives, "ShellCompDirectiveError")
 | 
			
		||||
	}
 | 
			
		||||
	if d&ShellCompDirectiveNoSpace != 0 {
 | 
			
		||||
		directives = append(directives, "ShellCompDirectiveNoSpace")
 | 
			
		||||
	}
 | 
			
		||||
	if d&ShellCompDirectiveNoFileComp != 0 {
 | 
			
		||||
		directives = append(directives, "ShellCompDirectiveNoFileComp")
 | 
			
		||||
	}
 | 
			
		||||
	if len(directives) == 0 {
 | 
			
		||||
		directives = append(directives, "ShellCompDirectiveDefault")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if d > ShellCompDirectiveError+ShellCompDirectiveNoSpace+ShellCompDirectiveNoFileComp {
 | 
			
		||||
		return fmt.Sprintf("ERROR: unexpected ShellCompDirective value: %d", d)
 | 
			
		||||
	}
 | 
			
		||||
	return strings.Join(directives, ", ")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Adds a special hidden command that can be used to request custom completions.
 | 
			
		||||
func (c *Command) initCompleteCmd(args []string) {
 | 
			
		||||
	completeCmd := &Command{
 | 
			
		||||
		Use:                   fmt.Sprintf("%s [command-line]", ShellCompRequestCmd),
 | 
			
		||||
		Aliases:               []string{ShellCompNoDescRequestCmd},
 | 
			
		||||
		DisableFlagsInUseLine: true,
 | 
			
		||||
		Hidden:                true,
 | 
			
		||||
		DisableFlagParsing:    true,
 | 
			
		||||
		Args:                  MinimumNArgs(1),
 | 
			
		||||
		Short:                 "Request shell completion choices for the specified command-line",
 | 
			
		||||
		Long: fmt.Sprintf("%[2]s is a special command that is used by the shell completion logic\n%[1]s",
 | 
			
		||||
			"to request completion choices for the specified command-line.", ShellCompRequestCmd),
 | 
			
		||||
		Run: func(cmd *Command, args []string) {
 | 
			
		||||
			finalCmd, completions, directive, err := cmd.getCompletions(args)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				CompErrorln(err.Error())
 | 
			
		||||
				// Keep going for multiple reasons:
 | 
			
		||||
				// 1- There could be some valid completions even though there was an error
 | 
			
		||||
				// 2- Even without completions, we need to print the directive
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			noDescriptions := (cmd.CalledAs() == ShellCompNoDescRequestCmd)
 | 
			
		||||
			for _, comp := range completions {
 | 
			
		||||
				if noDescriptions {
 | 
			
		||||
					// Remove any description that may be included following a tab character.
 | 
			
		||||
					comp = strings.Split(comp, "\t")[0]
 | 
			
		||||
				}
 | 
			
		||||
				// Print each possible completion to stdout for the completion script to consume.
 | 
			
		||||
				fmt.Fprintln(finalCmd.OutOrStdout(), comp)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if directive > ShellCompDirectiveError+ShellCompDirectiveNoSpace+ShellCompDirectiveNoFileComp {
 | 
			
		||||
				directive = ShellCompDirectiveDefault
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// As the last printout, print the completion directive for the completion script to parse.
 | 
			
		||||
			// The directive integer must be that last character following a single colon (:).
 | 
			
		||||
			// The completion script expects :<directive>
 | 
			
		||||
			fmt.Fprintf(finalCmd.OutOrStdout(), ":%d\n", directive)
 | 
			
		||||
 | 
			
		||||
			// Print some helpful info to stderr for the user to understand.
 | 
			
		||||
			// Output from stderr must be ignored by the completion script.
 | 
			
		||||
			fmt.Fprintf(finalCmd.ErrOrStderr(), "Completion ended with directive: %s\n", directive.string())
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	c.AddCommand(completeCmd)
 | 
			
		||||
	subCmd, _, err := c.Find(args)
 | 
			
		||||
	if err != nil || subCmd.Name() != ShellCompRequestCmd {
 | 
			
		||||
		// Only create this special command if it is actually being called.
 | 
			
		||||
		// This reduces possible side-effects of creating such a command;
 | 
			
		||||
		// for example, having this command would cause problems to a
 | 
			
		||||
		// cobra program that only consists of the root command, since this
 | 
			
		||||
		// command would cause the root command to suddenly have a subcommand.
 | 
			
		||||
		c.RemoveCommand(completeCmd)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDirective, error) {
 | 
			
		||||
	var completions []string
 | 
			
		||||
 | 
			
		||||
	// The last argument, which is not completely typed by the user,
 | 
			
		||||
	// should not be part of the list of arguments
 | 
			
		||||
	toComplete := args[len(args)-1]
 | 
			
		||||
	trimmedArgs := args[:len(args)-1]
 | 
			
		||||
 | 
			
		||||
	// Find the real command for which completion must be performed
 | 
			
		||||
	finalCmd, finalArgs, err := c.Root().Find(trimmedArgs)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		// Unable to find the real command. E.g., <program> someInvalidCmd <TAB>
 | 
			
		||||
		return c, completions, ShellCompDirectiveDefault, fmt.Errorf("Unable to find a command for arguments: %v", trimmedArgs)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// When doing completion of a flag name, as soon as an argument starts with
 | 
			
		||||
	// a '-' we know it is a flag.  We cannot use isFlagArg() here as it requires
 | 
			
		||||
	// the flag to be complete
 | 
			
		||||
	if len(toComplete) > 0 && toComplete[0] == '-' && !strings.Contains(toComplete, "=") {
 | 
			
		||||
		// We are completing a flag name
 | 
			
		||||
		finalCmd.NonInheritedFlags().VisitAll(func(flag *pflag.Flag) {
 | 
			
		||||
			completions = append(completions, getFlagNameCompletions(flag, toComplete)...)
 | 
			
		||||
		})
 | 
			
		||||
		finalCmd.InheritedFlags().VisitAll(func(flag *pflag.Flag) {
 | 
			
		||||
			completions = append(completions, getFlagNameCompletions(flag, toComplete)...)
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		directive := ShellCompDirectiveDefault
 | 
			
		||||
		if len(completions) > 0 {
 | 
			
		||||
			if strings.HasSuffix(completions[0], "=") {
 | 
			
		||||
				directive = ShellCompDirectiveNoSpace
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return finalCmd, completions, directive, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var flag *pflag.Flag
 | 
			
		||||
	if !finalCmd.DisableFlagParsing {
 | 
			
		||||
		// We only do flag completion if we are allowed to parse flags
 | 
			
		||||
		// This is important for commands which have requested to do their own flag completion.
 | 
			
		||||
		flag, finalArgs, toComplete, err = checkIfFlagCompletion(finalCmd, finalArgs, toComplete)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			// Error while attempting to parse flags
 | 
			
		||||
			return finalCmd, completions, ShellCompDirectiveDefault, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if flag == nil {
 | 
			
		||||
		// Complete subcommand names
 | 
			
		||||
		for _, subCmd := range finalCmd.Commands() {
 | 
			
		||||
			if subCmd.IsAvailableCommand() && strings.HasPrefix(subCmd.Name(), toComplete) {
 | 
			
		||||
				completions = append(completions, fmt.Sprintf("%s\t%s", subCmd.Name(), subCmd.Short))
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if len(finalCmd.ValidArgs) > 0 {
 | 
			
		||||
			// Always complete ValidArgs, even if we are completing a subcommand name.
 | 
			
		||||
			// This is for commands that have both subcommands and ValidArgs.
 | 
			
		||||
			for _, validArg := range finalCmd.ValidArgs {
 | 
			
		||||
				if strings.HasPrefix(validArg, toComplete) {
 | 
			
		||||
					completions = append(completions, validArg)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// If there are ValidArgs specified (even if they don't match), we stop completion.
 | 
			
		||||
			// Only one of ValidArgs or ValidArgsFunction can be used for a single command.
 | 
			
		||||
			return finalCmd, completions, ShellCompDirectiveNoFileComp, nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Always let the logic continue so as to add any ValidArgsFunction completions,
 | 
			
		||||
		// even if we already found sub-commands.
 | 
			
		||||
		// This is for commands that have subcommands but also specify a ValidArgsFunction.
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Parse the flags and extract the arguments to prepare for calling the completion function
 | 
			
		||||
	if err = finalCmd.ParseFlags(finalArgs); err != nil {
 | 
			
		||||
		return finalCmd, completions, ShellCompDirectiveDefault, fmt.Errorf("Error while parsing flags from args %v: %s", finalArgs, err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// We only remove the flags from the arguments if DisableFlagParsing is not set.
 | 
			
		||||
	// This is important for commands which have requested to do their own flag completion.
 | 
			
		||||
	if !finalCmd.DisableFlagParsing {
 | 
			
		||||
		finalArgs = finalCmd.Flags().Args()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Find the completion function for the flag or command
 | 
			
		||||
	var completionFn func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective)
 | 
			
		||||
	if flag != nil {
 | 
			
		||||
		completionFn = flagCompletionFunctions[flag]
 | 
			
		||||
	} else {
 | 
			
		||||
		completionFn = finalCmd.ValidArgsFunction
 | 
			
		||||
	}
 | 
			
		||||
	if completionFn == nil {
 | 
			
		||||
		// Go custom completion not supported/needed for this flag or command
 | 
			
		||||
		return finalCmd, completions, ShellCompDirectiveDefault, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Call the registered completion function to get the completions
 | 
			
		||||
	comps, directive := completionFn(finalCmd, finalArgs, toComplete)
 | 
			
		||||
	completions = append(completions, comps...)
 | 
			
		||||
	return finalCmd, completions, directive, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getFlagNameCompletions(flag *pflag.Flag, toComplete string) []string {
 | 
			
		||||
	if nonCompletableFlag(flag) {
 | 
			
		||||
		return []string{}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var completions []string
 | 
			
		||||
	flagName := "--" + flag.Name
 | 
			
		||||
	if strings.HasPrefix(flagName, toComplete) {
 | 
			
		||||
		// Flag without the =
 | 
			
		||||
		completions = append(completions, fmt.Sprintf("%s\t%s", flagName, flag.Usage))
 | 
			
		||||
 | 
			
		||||
		if len(flag.NoOptDefVal) == 0 {
 | 
			
		||||
			// Flag requires a value, so it can be suffixed with =
 | 
			
		||||
			flagName += "="
 | 
			
		||||
			completions = append(completions, fmt.Sprintf("%s\t%s", flagName, flag.Usage))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	flagName = "-" + flag.Shorthand
 | 
			
		||||
	if len(flag.Shorthand) > 0 && strings.HasPrefix(flagName, toComplete) {
 | 
			
		||||
		completions = append(completions, fmt.Sprintf("%s\t%s", flagName, flag.Usage))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return completions
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func checkIfFlagCompletion(finalCmd *Command, args []string, lastArg string) (*pflag.Flag, []string, string, error) {
 | 
			
		||||
	var flagName string
 | 
			
		||||
	trimmedArgs := args
 | 
			
		||||
	flagWithEqual := false
 | 
			
		||||
	if isFlagArg(lastArg) {
 | 
			
		||||
		if index := strings.Index(lastArg, "="); index >= 0 {
 | 
			
		||||
			flagName = strings.TrimLeft(lastArg[:index], "-")
 | 
			
		||||
			lastArg = lastArg[index+1:]
 | 
			
		||||
			flagWithEqual = true
 | 
			
		||||
		} else {
 | 
			
		||||
			return nil, nil, "", errors.New("Unexpected completion request for flag")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(flagName) == 0 {
 | 
			
		||||
		if len(args) > 0 {
 | 
			
		||||
			prevArg := args[len(args)-1]
 | 
			
		||||
			if isFlagArg(prevArg) {
 | 
			
		||||
				// Only consider the case where the flag does not contain an =.
 | 
			
		||||
				// If the flag contains an = it means it has already been fully processed,
 | 
			
		||||
				// so we don't need to deal with it here.
 | 
			
		||||
				if index := strings.Index(prevArg, "="); index < 0 {
 | 
			
		||||
					flagName = strings.TrimLeft(prevArg, "-")
 | 
			
		||||
 | 
			
		||||
					// Remove the uncompleted flag or else there could be an error created
 | 
			
		||||
					// for an invalid value for that flag
 | 
			
		||||
					trimmedArgs = args[:len(args)-1]
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(flagName) == 0 {
 | 
			
		||||
		// Not doing flag completion
 | 
			
		||||
		return nil, trimmedArgs, lastArg, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	flag := findFlag(finalCmd, flagName)
 | 
			
		||||
	if flag == nil {
 | 
			
		||||
		// Flag not supported by this command, nothing to complete
 | 
			
		||||
		err := fmt.Errorf("Subcommand '%s' does not support flag '%s'", finalCmd.Name(), flagName)
 | 
			
		||||
		return nil, nil, "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !flagWithEqual {
 | 
			
		||||
		if len(flag.NoOptDefVal) != 0 {
 | 
			
		||||
			// We had assumed dealing with a two-word flag but the flag is a boolean flag.
 | 
			
		||||
			// In that case, there is no value following it, so we are not really doing flag completion.
 | 
			
		||||
			// Reset everything to do noun completion.
 | 
			
		||||
			trimmedArgs = args
 | 
			
		||||
			flag = nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return flag, trimmedArgs, lastArg, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func findFlag(cmd *Command, name string) *pflag.Flag {
 | 
			
		||||
	flagSet := cmd.Flags()
 | 
			
		||||
	if len(name) == 1 {
 | 
			
		||||
		// First convert the short flag into a long flag
 | 
			
		||||
		// as the cmd.Flag() search only accepts long flags
 | 
			
		||||
		if short := flagSet.ShorthandLookup(name); short != nil {
 | 
			
		||||
			name = short.Name
 | 
			
		||||
		} else {
 | 
			
		||||
			set := cmd.InheritedFlags()
 | 
			
		||||
			if short = set.ShorthandLookup(name); short != nil {
 | 
			
		||||
				name = short.Name
 | 
			
		||||
			} else {
 | 
			
		||||
				return nil
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return cmd.Flag(name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CompDebug prints the specified string to the same file as where the
 | 
			
		||||
// completion script prints its logs.
 | 
			
		||||
// Note that completion printouts should never be on stdout as they would
 | 
			
		||||
// be wrongly interpreted as actual completion choices by the completion script.
 | 
			
		||||
func CompDebug(msg string, printToStdErr bool) {
 | 
			
		||||
	msg = fmt.Sprintf("[Debug] %s", msg)
 | 
			
		||||
 | 
			
		||||
	// Such logs are only printed when the user has set the environment
 | 
			
		||||
	// variable BASH_COMP_DEBUG_FILE to the path of some file to be used.
 | 
			
		||||
	if path := os.Getenv("BASH_COMP_DEBUG_FILE"); path != "" {
 | 
			
		||||
		f, err := os.OpenFile(path,
 | 
			
		||||
			os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			defer f.Close()
 | 
			
		||||
			f.WriteString(msg)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if printToStdErr {
 | 
			
		||||
		// Must print to stderr for this not to be read by the completion script.
 | 
			
		||||
		fmt.Fprintf(os.Stderr, msg)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CompDebugln prints the specified string with a newline at the end
 | 
			
		||||
// to the same file as where the completion script prints its logs.
 | 
			
		||||
// Such logs are only printed when the user has set the environment
 | 
			
		||||
// variable BASH_COMP_DEBUG_FILE to the path of some file to be used.
 | 
			
		||||
func CompDebugln(msg string, printToStdErr bool) {
 | 
			
		||||
	CompDebug(fmt.Sprintf("%s\n", msg), printToStdErr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CompError prints the specified completion message to stderr.
 | 
			
		||||
func CompError(msg string) {
 | 
			
		||||
	msg = fmt.Sprintf("[Error] %s", msg)
 | 
			
		||||
	CompDebug(msg, true)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CompErrorln prints the specified completion message to stderr with a newline at the end.
 | 
			
		||||
func CompErrorln(msg string) {
 | 
			
		||||
	CompError(fmt.Sprintf("%s\n", msg))
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,172 @@
 | 
			
		|||
package cobra
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func genFishComp(buf *bytes.Buffer, name string, includeDesc bool) {
 | 
			
		||||
	compCmd := ShellCompRequestCmd
 | 
			
		||||
	if !includeDesc {
 | 
			
		||||
		compCmd = ShellCompNoDescRequestCmd
 | 
			
		||||
	}
 | 
			
		||||
	buf.WriteString(fmt.Sprintf("# fish completion for %-36s -*- shell-script -*-\n", name))
 | 
			
		||||
	buf.WriteString(fmt.Sprintf(`
 | 
			
		||||
function __%[1]s_debug
 | 
			
		||||
    set file "$BASH_COMP_DEBUG_FILE"
 | 
			
		||||
    if test -n "$file"
 | 
			
		||||
        echo "$argv" >> $file
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function __%[1]s_perform_completion
 | 
			
		||||
    __%[1]s_debug "Starting __%[1]s_perform_completion with: $argv"
 | 
			
		||||
 | 
			
		||||
    set args (string split -- " " "$argv")
 | 
			
		||||
    set lastArg "$args[-1]"
 | 
			
		||||
 | 
			
		||||
    __%[1]s_debug "args: $args"
 | 
			
		||||
    __%[1]s_debug "last arg: $lastArg"
 | 
			
		||||
 | 
			
		||||
    set emptyArg ""
 | 
			
		||||
    if test -z "$lastArg"
 | 
			
		||||
        __%[1]s_debug "Setting emptyArg"
 | 
			
		||||
        set emptyArg \"\"
 | 
			
		||||
    end
 | 
			
		||||
    __%[1]s_debug "emptyArg: $emptyArg"
 | 
			
		||||
 | 
			
		||||
    set requestComp "$args[1] %[2]s $args[2..-1] $emptyArg"
 | 
			
		||||
    __%[1]s_debug "Calling $requestComp"
 | 
			
		||||
 | 
			
		||||
    set results (eval $requestComp 2> /dev/null)
 | 
			
		||||
    set comps $results[1..-2]
 | 
			
		||||
    set directiveLine $results[-1]
 | 
			
		||||
 | 
			
		||||
    # For Fish, when completing a flag with an = (e.g., <program> -n=<TAB>)
 | 
			
		||||
    # completions must be prefixed with the flag
 | 
			
		||||
    set flagPrefix (string match -r -- '-.*=' "$lastArg")
 | 
			
		||||
 | 
			
		||||
    __%[1]s_debug "Comps: $comps"
 | 
			
		||||
    __%[1]s_debug "DirectiveLine: $directiveLine"
 | 
			
		||||
    __%[1]s_debug "flagPrefix: $flagPrefix"
 | 
			
		||||
 | 
			
		||||
    for comp in $comps
 | 
			
		||||
        printf "%%s%%s\n" "$flagPrefix" "$comp"
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    printf "%%s\n" "$directiveLine"
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
# This function does three things:
 | 
			
		||||
# 1- Obtain the completions and store them in the global __%[1]s_comp_results
 | 
			
		||||
# 2- Set the __%[1]s_comp_do_file_comp flag if file completion should be performed
 | 
			
		||||
#    and unset it otherwise
 | 
			
		||||
# 3- Return true if the completion results are not empty
 | 
			
		||||
function __%[1]s_prepare_completions
 | 
			
		||||
    # Start fresh
 | 
			
		||||
    set --erase __%[1]s_comp_do_file_comp
 | 
			
		||||
    set --erase __%[1]s_comp_results
 | 
			
		||||
 | 
			
		||||
    # Check if the command-line is already provided.  This is useful for testing.
 | 
			
		||||
    if not set --query __%[1]s_comp_commandLine
 | 
			
		||||
        set __%[1]s_comp_commandLine (commandline)
 | 
			
		||||
    end
 | 
			
		||||
    __%[1]s_debug "commandLine is: $__%[1]s_comp_commandLine"
 | 
			
		||||
 | 
			
		||||
    set results (__%[1]s_perform_completion "$__%[1]s_comp_commandLine")
 | 
			
		||||
    set --erase __%[1]s_comp_commandLine
 | 
			
		||||
    __%[1]s_debug "Completion results: $results"
 | 
			
		||||
 | 
			
		||||
    if test -z "$results"
 | 
			
		||||
        __%[1]s_debug "No completion, probably due to a failure"
 | 
			
		||||
        # Might as well do file completion, in case it helps
 | 
			
		||||
        set --global __%[1]s_comp_do_file_comp 1
 | 
			
		||||
        return 0
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    set directive (string sub --start 2 $results[-1])
 | 
			
		||||
    set --global __%[1]s_comp_results $results[1..-2]
 | 
			
		||||
 | 
			
		||||
    __%[1]s_debug "Completions are: $__%[1]s_comp_results"
 | 
			
		||||
    __%[1]s_debug "Directive is: $directive"
 | 
			
		||||
 | 
			
		||||
    if test -z "$directive"
 | 
			
		||||
        set directive 0
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    set compErr (math (math --scale 0 $directive / %[3]d) %% 2)
 | 
			
		||||
    if test $compErr -eq 1
 | 
			
		||||
        __%[1]s_debug "Received error directive: aborting."
 | 
			
		||||
        # Might as well do file completion, in case it helps
 | 
			
		||||
        set --global __%[1]s_comp_do_file_comp 1
 | 
			
		||||
        return 0
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    set nospace (math (math --scale 0 $directive / %[4]d) %% 2)
 | 
			
		||||
    set nofiles (math (math --scale 0 $directive / %[5]d) %% 2)
 | 
			
		||||
 | 
			
		||||
    __%[1]s_debug "nospace: $nospace, nofiles: $nofiles"
 | 
			
		||||
 | 
			
		||||
    # Important not to quote the variable for count to work
 | 
			
		||||
    set numComps (count $__%[1]s_comp_results)
 | 
			
		||||
    __%[1]s_debug "numComps: $numComps"
 | 
			
		||||
 | 
			
		||||
    if test $numComps -eq 1; and test $nospace -ne 0
 | 
			
		||||
        # To support the "nospace" directive we trick the shell
 | 
			
		||||
        # by outputting an extra, longer completion.
 | 
			
		||||
        __%[1]s_debug "Adding second completion to perform nospace directive"
 | 
			
		||||
        set --append __%[1]s_comp_results $__%[1]s_comp_results[1].
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    if test $numComps -eq 0; and test $nofiles -eq 0
 | 
			
		||||
        __%[1]s_debug "Requesting file completion"
 | 
			
		||||
        set --global __%[1]s_comp_do_file_comp 1
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    # If we don't want file completion, we must return true even if there
 | 
			
		||||
    # are no completions found.  This is because fish will perform the last
 | 
			
		||||
    # completion command, even if its condition is false, if no other
 | 
			
		||||
    # completion command was triggered
 | 
			
		||||
    return (not set --query __%[1]s_comp_do_file_comp)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
# Remove any pre-existing completions for the program since we will be handling all of them
 | 
			
		||||
# TODO this cleanup is not sufficient.  Fish completions are only loaded once the user triggers
 | 
			
		||||
# them, so the below deletion will not work as it is run too early.  What else can we do?
 | 
			
		||||
complete -c %[1]s -e
 | 
			
		||||
 | 
			
		||||
# The order in which the below two lines are defined is very important so that __%[1]s_prepare_completions
 | 
			
		||||
# is called first.  It is __%[1]s_prepare_completions that sets up the __%[1]s_comp_do_file_comp variable.
 | 
			
		||||
#
 | 
			
		||||
# This completion will be run second as complete commands are added FILO.
 | 
			
		||||
# It triggers file completion choices when __%[1]s_comp_do_file_comp is set.
 | 
			
		||||
complete -c %[1]s -n 'set --query __%[1]s_comp_do_file_comp'
 | 
			
		||||
 | 
			
		||||
# This completion will be run first as complete commands are added FILO.
 | 
			
		||||
# The call to __%[1]s_prepare_completions will setup both __%[1]s_comp_results abd __%[1]s_comp_do_file_comp.
 | 
			
		||||
# It provides the program's completion choices.
 | 
			
		||||
complete -c %[1]s -n '__%[1]s_prepare_completions' -f -a '$__%[1]s_comp_results'
 | 
			
		||||
 | 
			
		||||
`, name, compCmd, ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GenFishCompletion generates fish completion file and writes to the passed writer.
 | 
			
		||||
func (c *Command) GenFishCompletion(w io.Writer, includeDesc bool) error {
 | 
			
		||||
	buf := new(bytes.Buffer)
 | 
			
		||||
	genFishComp(buf, c.Name(), includeDesc)
 | 
			
		||||
	_, err := buf.WriteTo(w)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GenFishCompletionFile generates fish completion file.
 | 
			
		||||
func (c *Command) GenFishCompletionFile(filename string, includeDesc bool) error {
 | 
			
		||||
	outFile, err := os.Create(filename)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer outFile.Close()
 | 
			
		||||
 | 
			
		||||
	return c.GenFishCompletion(outFile, includeDesc)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,7 @@
 | 
			
		|||
## Generating Fish Completions for your own cobra.Command
 | 
			
		||||
 | 
			
		||||
Cobra supports native Fish completions generated from the root `cobra.Command`.  You can use the `command.GenFishCompletion()` or `command.GenFishCompletionFile()` functions. You must provide these functions with a parameter indicating if the completions should be annotated with a description; Cobra will provide the description automatically based on usage information.  You can choose to make this option configurable by your users.
 | 
			
		||||
 | 
			
		||||
### Limitations
 | 
			
		||||
 | 
			
		||||
* Custom completions implemented using the `ValidArgsFunction` and `RegisterFlagCompletionFunc()` are supported automatically but the ones implemented in Bash scripting are not.
 | 
			
		||||
| 
						 | 
				
			
			@ -87,12 +87,13 @@ github.com/containers/buildah/pkg/secrets
 | 
			
		|||
github.com/containers/buildah/pkg/supplemented
 | 
			
		||||
github.com/containers/buildah/pkg/umask
 | 
			
		||||
github.com/containers/buildah/util
 | 
			
		||||
# github.com/containers/common v0.22.0
 | 
			
		||||
# github.com/containers/common v0.23.0
 | 
			
		||||
github.com/containers/common/pkg/apparmor
 | 
			
		||||
github.com/containers/common/pkg/apparmor/internal/supported
 | 
			
		||||
github.com/containers/common/pkg/auth
 | 
			
		||||
github.com/containers/common/pkg/capabilities
 | 
			
		||||
github.com/containers/common/pkg/cgroupv2
 | 
			
		||||
github.com/containers/common/pkg/completion
 | 
			
		||||
github.com/containers/common/pkg/config
 | 
			
		||||
github.com/containers/common/pkg/retry
 | 
			
		||||
github.com/containers/common/pkg/seccomp
 | 
			
		||||
| 
						 | 
				
			
			@ -496,7 +497,7 @@ github.com/seccomp/libseccomp-golang
 | 
			
		|||
# github.com/sirupsen/logrus v1.6.0
 | 
			
		||||
github.com/sirupsen/logrus
 | 
			
		||||
github.com/sirupsen/logrus/hooks/syslog
 | 
			
		||||
# github.com/spf13/cobra v0.0.7
 | 
			
		||||
# github.com/spf13/cobra v1.0.0
 | 
			
		||||
github.com/spf13/cobra
 | 
			
		||||
# github.com/spf13/pflag v1.0.5
 | 
			
		||||
github.com/spf13/pflag
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue