Merge pull request #40930 from thaJeztah/bump_cobra

vendor: spf13/cobra v1.0.0, spf13/pflag v1.0.5
This commit is contained in:
Sebastiaan van Stijn 2020-05-14 21:28:51 +02:00 committed by GitHub
commit 2f003f7774
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 2944 additions and 253 deletions

View file

@ -93,7 +93,7 @@ func main() {
if err != nil { if err != nil {
onError(err) onError(err)
} }
cmd.SetOutput(stdout) cmd.SetOut(stdout)
if err := cmd.Execute(); err != nil { if err := cmd.Execute(); err != nil {
onError(err) onError(err)
} }

View file

@ -160,8 +160,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus c225b8c3b01faf2899099b768856
github.com/cespare/xxhash/v2 d7df74196a9e781ede915320c11c378c1b2f3a1f # v2.1.1 github.com/cespare/xxhash/v2 d7df74196a9e781ede915320c11c378c1b2f3a1f # v2.1.1
# cli # cli
github.com/spf13/cobra ef82de70bb3f60c65fb8eebacbb2d122ef517385 # v0.0.3 github.com/spf13/cobra a684a6d7f5e37385d954dd3b5a14fc6912c6ab9d # v1.0.0
github.com/spf13/pflag 583c0c0531f06d5278b7d917446061adc344b5cd # v1.0.1 github.com/spf13/pflag 2e9d26c8c37aae03e3f9d4e90b7116f5accb7cab # v1.0.5
github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75 # v1.0.0 github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75 # v1.0.0
github.com/morikuni/aec 39771216ff4c63d11f5e604076f9c45e8be1067b # v1.0.0 github.com/morikuni/aec 39771216ff4c63d11f5e604076f9c45e8be1067b # v1.0.0

View file

@ -2,29 +2,35 @@
Cobra is both a library for creating powerful modern CLI applications as well as a program to generate applications and command files. Cobra is both a library for creating powerful modern CLI applications as well as a program to generate applications and command files.
Many of the most widely used Go projects are built using Cobra including: Many of the most widely used Go projects are built using Cobra, such as:
[Kubernetes](http://kubernetes.io/),
* [Kubernetes](http://kubernetes.io/) [Hugo](http://gohugo.io),
* [Hugo](http://gohugo.io) [rkt](https://github.com/coreos/rkt),
* [rkt](https://github.com/coreos/rkt) [etcd](https://github.com/coreos/etcd),
* [etcd](https://github.com/coreos/etcd) [Moby (former Docker)](https://github.com/moby/moby),
* [Moby (former Docker)](https://github.com/moby/moby) [Docker (distribution)](https://github.com/docker/distribution),
* [Docker (distribution)](https://github.com/docker/distribution) [OpenShift](https://www.openshift.com/),
* [OpenShift](https://www.openshift.com/) [Delve](https://github.com/derekparker/delve),
* [Delve](https://github.com/derekparker/delve) [GopherJS](http://www.gopherjs.org/),
* [GopherJS](http://www.gopherjs.org/) [CockroachDB](http://www.cockroachlabs.com/),
* [CockroachDB](http://www.cockroachlabs.com/) [Bleve](http://www.blevesearch.com/),
* [Bleve](http://www.blevesearch.com/) [ProjectAtomic (enterprise)](http://www.projectatomic.io/),
* [ProjectAtomic (enterprise)](http://www.projectatomic.io/) [Giant Swarm's gsctl](https://github.com/giantswarm/gsctl),
* [GiantSwarm's swarm](https://github.com/giantswarm/cli) [Nanobox](https://github.com/nanobox-io/nanobox)/[Nanopack](https://github.com/nanopack),
* [Nanobox](https://github.com/nanobox-io/nanobox)/[Nanopack](https://github.com/nanopack) [rclone](http://rclone.org/),
* [rclone](http://rclone.org/) [nehm](https://github.com/bogem/nehm),
* [nehm](https://github.com/bogem/nehm) [Pouch](https://github.com/alibaba/pouch),
* [Pouch](https://github.com/alibaba/pouch) [Istio](https://istio.io),
[Prototool](https://github.com/uber/prototool),
[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.
[![Build Status](https://travis-ci.org/spf13/cobra.svg "Travis CI status")](https://travis-ci.org/spf13/cobra) [![Build Status](https://travis-ci.org/spf13/cobra.svg "Travis CI status")](https://travis-ci.org/spf13/cobra)
[![CircleCI status](https://circleci.com/gh/spf13/cobra.png?circle-token=:circle-token "CircleCI status")](https://circleci.com/gh/spf13/cobra)
[![GoDoc](https://godoc.org/github.com/spf13/cobra?status.svg)](https://godoc.org/github.com/spf13/cobra) [![GoDoc](https://godoc.org/github.com/spf13/cobra?status.svg)](https://godoc.org/github.com/spf13/cobra)
[![Go Report Card](https://goreportcard.com/badge/github.com/spf13/cobra)](https://goreportcard.com/report/github.com/spf13/cobra)
# Table of Contents # Table of Contents
@ -45,6 +51,7 @@ Many of the most widely used Go projects are built using Cobra including:
* [Suggestions when "unknown command" happens](#suggestions-when-unknown-command-happens) * [Suggestions when "unknown command" happens](#suggestions-when-unknown-command-happens)
* [Generating documentation for your command](#generating-documentation-for-your-command) * [Generating documentation for your command](#generating-documentation-for-your-command)
* [Generating bash completions](#generating-bash-completions) * [Generating bash completions](#generating-bash-completions)
* [Generating zsh completions](#generating-zsh-completions)
- [Contributing](#contributing) - [Contributing](#contributing)
- [License](#license) - [License](#license)
@ -152,9 +159,6 @@ In a Cobra app, typically the main.go file is very bare. It serves one purpose:
package main package main
import ( import (
"fmt"
"os"
"{pathToYourApp}/cmd" "{pathToYourApp}/cmd"
) )
@ -206,51 +210,78 @@ You will additionally define flags and handle configuration in your init() funct
For example cmd/root.go: For example cmd/root.go:
```go ```go
import ( package cmd
"fmt"
"os"
homedir "github.com/mitchellh/go-homedir" import (
"github.com/spf13/cobra" "fmt"
"github.com/spf13/viper" "os"
homedir "github.com/mitchellh/go-homedir"
"github.com/spf13/cobra"
"github.com/spf13/viper"
) )
var (
// Used for flags.
cfgFile string
userLicense string
rootCmd = &cobra.Command{
Use: "cobra",
Short: "A generator for Cobra based Applications",
Long: `Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
}
)
// Execute executes the root command.
func Execute() error {
return rootCmd.Execute()
}
func init() { func init() {
cobra.OnInitialize(initConfig) cobra.OnInitialize(initConfig)
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)")
rootCmd.PersistentFlags().StringVarP(&projectBase, "projectbase", "b", "", "base project directory eg. github.com/spf13/") rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)")
rootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "Author name for copyright attribution") rootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "author name for copyright attribution")
rootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "Name of license for the project (can provide `licensetext` in config)") rootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "name of license for the project")
rootCmd.PersistentFlags().Bool("viper", true, "Use Viper for configuration") rootCmd.PersistentFlags().Bool("viper", true, "use Viper for configuration")
viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author")) viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author"))
viper.BindPFlag("projectbase", rootCmd.PersistentFlags().Lookup("projectbase")) viper.BindPFlag("useViper", rootCmd.PersistentFlags().Lookup("viper"))
viper.BindPFlag("useViper", rootCmd.PersistentFlags().Lookup("viper")) viper.SetDefault("author", "NAME HERE <EMAIL ADDRESS>")
viper.SetDefault("author", "NAME HERE <EMAIL ADDRESS>") viper.SetDefault("license", "apache")
viper.SetDefault("license", "apache")
rootCmd.AddCommand(addCmd)
rootCmd.AddCommand(initCmd)
}
func er(msg interface{}) {
fmt.Println("Error:", msg)
os.Exit(1)
} }
func initConfig() { func initConfig() {
// Don't forget to read config either from cfgFile or from home directory! if cfgFile != "" {
if cfgFile != "" { // Use config file from the flag.
// Use config file from the flag. viper.SetConfigFile(cfgFile)
viper.SetConfigFile(cfgFile) } else {
} else { // Find home directory.
// Find home directory. home, err := homedir.Dir()
home, err := homedir.Dir() if err != nil {
if err != nil { er(err)
fmt.Println(err) }
os.Exit(1)
}
// Search config in home directory with name ".cobra" (without extension). // Search config in home directory with name ".cobra" (without extension).
viper.AddConfigPath(home) viper.AddConfigPath(home)
viper.SetConfigName(".cobra") viper.SetConfigName(".cobra")
} }
if err := viper.ReadInConfig(); err != nil { viper.AutomaticEnv()
fmt.Println("Can't read config:", err)
os.Exit(1) if err := viper.ReadInConfig(); err == nil {
} fmt.Println("Using config file:", viper.ConfigFileUsed())
}
} }
``` ```
@ -265,9 +296,6 @@ In a Cobra app, typically the main.go file is very bare. It serves, one purpose,
package main package main
import ( import (
"fmt"
"os"
"{pathToYourApp}/cmd" "{pathToYourApp}/cmd"
) )
@ -339,7 +367,7 @@ rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose out
A flag can also be assigned locally which will only apply to that specific command. A flag can also be assigned locally which will only apply to that specific command.
```go ```go
rootCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from") localCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from")
``` ```
### Local Flag on Parent Commands ### Local Flag on Parent Commands
@ -395,6 +423,7 @@ The following validators are built in:
- `MinimumNArgs(int)` - the command will report an error if there are not at least N positional args. - `MinimumNArgs(int)` - the command will report an error if there are not at least N positional args.
- `MaximumNArgs(int)` - the command will report an error if there are more than N positional args. - `MaximumNArgs(int)` - the command will report an error if there are more than N positional args.
- `ExactArgs(int)` - the command will report an error if there are not exactly N positional args. - `ExactArgs(int)` - the command will report an error if there are not exactly N positional args.
- `ExactValidArgs(int)` - the command will report an error if there are not exactly N positional args OR if there are any positional args that are not in the `ValidArgs` field of `Command`
- `RangeArgs(min, max)` - the command will report an error if the number of args is not between the minimum and maximum number of expected args. - `RangeArgs(min, max)` - the command will report an error if the number of args is not between the minimum and maximum number of expected args.
An example of setting the custom validator: An example of setting the custom validator:
@ -404,7 +433,7 @@ var cmd = &cobra.Command{
Short: "hello", Short: "hello",
Args: func(cmd *cobra.Command, args []string) error { Args: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 { if len(args) < 1 {
return errors.New("requires at least one arg") return errors.New("requires a color argument")
} }
if myapp.IsValidColor(args[0]) { if myapp.IsValidColor(args[0]) {
return nil return nil
@ -459,12 +488,12 @@ For many years people have printed back to the screen.`,
Echo works a lot like print, except it has a child command.`, Echo works a lot like print, except it has a child command.`,
Args: cobra.MinimumNArgs(1), Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Print: " + strings.Join(args, " ")) fmt.Println("Echo: " + strings.Join(args, " "))
}, },
} }
var cmdTimes = &cobra.Command{ var cmdTimes = &cobra.Command{
Use: "times [# times] [string to echo]", Use: "times [string to echo]",
Short: "Echo anything to the screen more times", Short: "Echo anything to the screen more times",
Long: `echo things multiple times back to the user by providing Long: `echo things multiple times back to the user by providing
a count and a string.`, a count and a string.`,
@ -721,6 +750,11 @@ Cobra can generate documentation based on subcommands, flags, etc. in the follow
Cobra can generate a bash-completion file. If you add more information to your command, these completions can be amazingly powerful and flexible. Read more about it in [Bash Completions](bash_completions.md). Cobra can generate a bash-completion file. If you add more information to your command, these completions can be amazingly powerful and flexible. Read more about it in [Bash Completions](bash_completions.md).
## Generating zsh completions
Cobra can generate zsh-completion file. Read more about it in
[Zsh Completions](zsh_completions.md).
# Contributing # Contributing
1. Fork it 1. Fork it

View file

@ -2,6 +2,7 @@ package cobra
import ( import (
"fmt" "fmt"
"strings"
) )
type PositionalArgs func(cmd *Command, args []string) error 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. // OnlyValidArgs returns an error if any args are not in the list of ValidArgs.
func OnlyValidArgs(cmd *Command, args []string) error { func OnlyValidArgs(cmd *Command, args []string) error {
if len(cmd.ValidArgs) > 0 { 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 { 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])) return fmt.Errorf("invalid argument %q for %q%s", v, cmd.CommandPath(), cmd.findSuggestions(args[0]))
} }
} }
@ -78,6 +86,18 @@ func ExactArgs(n int) PositionalArgs {
} }
} }
// ExactValidArgs returns an error if
// there are not exactly N positional args OR
// there are any positional args that are not in the `ValidArgs` field of `Command`
func ExactValidArgs(n int) PositionalArgs {
return func(cmd *Command, args []string) error {
if err := ExactArgs(n)(cmd, args); err != nil {
return err
}
return OnlyValidArgs(cmd, args)
}
}
// RangeArgs returns an error if the number of args is not within the expected range. // RangeArgs returns an error if the number of args is not within the expected range.
func RangeArgs(min int, max int) PositionalArgs { func RangeArgs(min int, max int) PositionalArgs {
return func(cmd *Command, args []string) error { return func(cmd *Command, args []string) error {

View file

@ -58,9 +58,71 @@ __%[1]s_contains_word()
return 1 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_handle_reply()
{ {
__%[1]s_debug "${FUNCNAME[0]}" __%[1]s_debug "${FUNCNAME[0]}"
local comp
case $cur in case $cur in
-*) -*)
if [[ $(type -t compopt) = "builtin" ]]; then if [[ $(type -t compopt) = "builtin" ]]; then
@ -72,7 +134,9 @@ __%[1]s_handle_reply()
else else
allflags=("${flags[*]} ${two_word_flags[*]}") allflags=("${flags[*]} ${two_word_flags[*]}")
fi fi
COMPREPLY=( $(compgen -W "${allflags[*]}" -- "$cur") ) while IFS='' read -r comp; do
COMPREPLY+=("$comp")
done < <(compgen -W "${allflags[*]}" -- "$cur")
if [[ $(type -t compopt) = "builtin" ]]; then if [[ $(type -t compopt) = "builtin" ]]; then
[[ "${COMPREPLY[0]}" == *= ]] || compopt +o nospace [[ "${COMPREPLY[0]}" == *= ]] || compopt +o nospace
fi fi
@ -118,18 +182,32 @@ __%[1]s_handle_reply()
completions=("${commands[@]}") completions=("${commands[@]}")
if [[ ${#must_have_one_noun[@]} -ne 0 ]]; then if [[ ${#must_have_one_noun[@]} -ne 0 ]]; then
completions=("${must_have_one_noun[@]}") 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 fi
if [[ ${#must_have_one_flag[@]} -ne 0 ]]; then if [[ ${#must_have_one_flag[@]} -ne 0 ]]; then
completions+=("${must_have_one_flag[@]}") completions+=("${must_have_one_flag[@]}")
fi fi
COMPREPLY=( $(compgen -W "${completions[*]}" -- "$cur") ) while IFS='' read -r comp; do
COMPREPLY+=("$comp")
done < <(compgen -W "${completions[*]}" -- "$cur")
if [[ ${#COMPREPLY[@]} -eq 0 && ${#noun_aliases[@]} -gt 0 && ${#must_have_one_noun[@]} -ne 0 ]]; then if [[ ${#COMPREPLY[@]} -eq 0 && ${#noun_aliases[@]} -gt 0 && ${#must_have_one_noun[@]} -ne 0 ]]; then
COMPREPLY=( $(compgen -W "${noun_aliases[*]}" -- "$cur") ) while IFS='' read -r comp; do
COMPREPLY+=("$comp")
done < <(compgen -W "${noun_aliases[*]}" -- "$cur")
fi fi
if [[ ${#COMPREPLY[@]} -eq 0 ]]; then if [[ ${#COMPREPLY[@]} -eq 0 ]]; then
declare -F __custom_func >/dev/null && __custom_func if declare -F __%[1]s_custom_func >/dev/null; then
# try command name qualified custom func
__%[1]s_custom_func
else
# otherwise fall back to unqualified for compatibility
declare -F __custom_func >/dev/null && __custom_func
fi
fi fi
# available in bash-completion >= 2, not always present on macOS # available in bash-completion >= 2, not always present on macOS
@ -154,7 +232,7 @@ __%[1]s_handle_filename_extension_flag()
__%[1]s_handle_subdirs_in_dir_flag() __%[1]s_handle_subdirs_in_dir_flag()
{ {
local dir="$1" local dir="$1"
pushd "${dir}" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 pushd "${dir}" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 || return
} }
__%[1]s_handle_flag() __%[1]s_handle_flag()
@ -193,7 +271,8 @@ __%[1]s_handle_flag()
fi fi
# skip the argument to a two word flag # skip the argument to a two word flag
if __%[1]s_contains_word "${words[c]}" "${two_word_flags[@]}"; then if [[ ${words[c]} != *"="* ]] && __%[1]s_contains_word "${words[c]}" "${two_word_flags[@]}"; then
__%[1]s_debug "${FUNCNAME[0]}: found a flag ${words[c]}, skip the next argument"
c=$((c+1)) c=$((c+1))
# if we are looking for a flags value, don't show commands # if we are looking for a flags value, don't show commands
if [[ $c -eq $cword ]]; then if [[ $c -eq $cword ]]; then
@ -265,7 +344,7 @@ __%[1]s_handle_word()
__%[1]s_handle_word __%[1]s_handle_word
} }
`, name)) `, name, ShellCompNoDescRequestCmd, ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp))
} }
func writePostscript(buf *bytes.Buffer, name string) { func writePostscript(buf *bytes.Buffer, name string) {
@ -290,6 +369,7 @@ func writePostscript(buf *bytes.Buffer, name string) {
local commands=("%[1]s") local commands=("%[1]s")
local must_have_one_flag=() local must_have_one_flag=()
local must_have_one_noun=() local must_have_one_noun=()
local has_completion_function
local last_command local last_command
local nouns=() local nouns=()
@ -373,6 +453,10 @@ func writeFlag(buf *bytes.Buffer, flag *pflag.Flag, cmd *Command) {
} }
format += "\")\n" format += "\")\n"
buf.WriteString(fmt.Sprintf(format, name)) buf.WriteString(fmt.Sprintf(format, name))
if len(flag.NoOptDefVal) == 0 {
format = " two_word_flags+=(\"--%s\")\n"
buf.WriteString(fmt.Sprintf(format, name))
}
writeFlagHandler(buf, "--"+name, flag.Annotations, cmd) writeFlagHandler(buf, "--"+name, flag.Annotations, cmd)
} }
@ -386,7 +470,22 @@ func writeLocalNonPersistentFlag(buf *bytes.Buffer, flag *pflag.Flag) {
buf.WriteString(fmt.Sprintf(format, name)) 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) { func writeFlags(buf *bytes.Buffer, cmd *Command) {
prepareCustomAnnotationsForFlags(cmd)
buf.WriteString(` flags=() buf.WriteString(` flags=()
two_word_flags=() two_word_flags=()
local_nonpersistent_flags=() local_nonpersistent_flags=()
@ -449,8 +548,14 @@ func writeRequiredNouns(buf *bytes.Buffer, cmd *Command) {
buf.WriteString(" must_have_one_noun=()\n") buf.WriteString(" must_have_one_noun=()\n")
sort.Sort(sort.StringSlice(cmd.ValidArgs)) sort.Sort(sort.StringSlice(cmd.ValidArgs))
for _, value := range 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)) 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) { func writeCmdAliases(buf *bytes.Buffer, cmd *Command) {
@ -534,51 +639,3 @@ func (c *Command) GenBashCompletionFile(filename string) error {
return c.GenBashCompletion(outFile) return c.GenBashCompletion(outFile)
} }
// MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag if it exists,
// and causes your command to report an error if invoked without the flag.
func (c *Command) MarkFlagRequired(name string) error {
return MarkFlagRequired(c.Flags(), name)
}
// MarkPersistentFlagRequired adds the BashCompOneRequiredFlag annotation to the named persistent flag if it exists,
// and causes your command to report an error if invoked without the flag.
func (c *Command) MarkPersistentFlagRequired(name string) error {
return MarkFlagRequired(c.PersistentFlags(), name)
}
// MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag if it exists,
// and causes your command to report an error if invoked without the flag.
func MarkFlagRequired(flags *pflag.FlagSet, name string) error {
return flags.SetAnnotation(name, BashCompOneRequiredFlag, []string{"true"})
}
// MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag, if it exists.
// Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided.
func (c *Command) MarkFlagFilename(name string, extensions ...string) error {
return MarkFlagFilename(c.Flags(), name, extensions...)
}
// MarkFlagCustom adds the BashCompCustom annotation to the named flag, if it exists.
// Generated bash autocompletion will call the bash function f for the flag.
func (c *Command) MarkFlagCustom(name string, f string) error {
return MarkFlagCustom(c.Flags(), name, f)
}
// MarkPersistentFlagFilename adds the BashCompFilenameExt annotation to the named persistent flag, if it exists.
// Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided.
func (c *Command) MarkPersistentFlagFilename(name string, extensions ...string) error {
return MarkFlagFilename(c.PersistentFlags(), name, extensions...)
}
// MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag in the flag set, if it exists.
// Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided.
func MarkFlagFilename(flags *pflag.FlagSet, name string, extensions ...string) error {
return flags.SetAnnotation(name, BashCompFilenameExt, extensions)
}
// MarkFlagCustom adds the BashCompCustom annotation to the named flag in the flag set, if it exists.
// Generated bash autocompletion will call the bash function f for the flag.
func MarkFlagCustom(flags *pflag.FlagSet, name string, f string) error {
return flags.SetAnnotation(name, BashCompCustom, []string{f})
}

View file

@ -23,6 +23,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"text/template" "text/template"
"time"
"unicode" "unicode"
) )
@ -51,11 +52,17 @@ var EnableCommandSorting = true
// if the CLI is started from explorer.exe. // if the CLI is started from explorer.exe.
// To disable the mousetrap, just set this variable to blank string (""). // To disable the mousetrap, just set this variable to blank string ("").
// Works only on Microsoft Windows. // Works only on Microsoft Windows.
var MousetrapHelpText string = `This is a command line tool. var MousetrapHelpText = `This is a command line tool.
You need to open cmd.exe and run it from there. You need to open cmd.exe and run it from there.
` `
// MousetrapDisplayDuration controls how long the MousetrapHelpText message is displayed on Windows
// if the CLI is started from explorer.exe. Set to 0 to wait for the return key to be pressed.
// To disable the mousetrap, just set MousetrapHelpText to blank string ("").
// Works only on Microsoft Windows.
var MousetrapDisplayDuration = 5 * time.Second
// AddTemplateFunc adds a template function that's available to Usage and Help // AddTemplateFunc adds a template function that's available to Usage and Help
// template generation. // template generation.
func AddTemplateFunc(name string, tmplFunc interface{}) { func AddTemplateFunc(name string, tmplFunc interface{}) {

View file

@ -17,6 +17,7 @@ package cobra
import ( import (
"bytes" "bytes"
"context"
"fmt" "fmt"
"io" "io"
"os" "os"
@ -56,6 +57,10 @@ type Command struct {
// ValidArgs is list of all valid non-flag arguments that are accepted in bash completions // ValidArgs is list of all valid non-flag arguments that are accepted in bash completions
ValidArgs []string 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 // Expected arguments
Args PositionalArgs Args PositionalArgs
@ -80,7 +85,8 @@ type Command struct {
// Version defines the version for this command. If this value is non-empty and the command does not // Version defines the version for this command. If this value is non-empty and the command does not
// define a "version" flag, a "version" boolean flag will be added to the command and, if specified, // define a "version" flag, a "version" boolean flag will be added to the command and, if specified,
// will print content of the "Version" variable. // will print content of the "Version" variable. A shorthand "v" flag will also be added if the
// command does not define one.
Version string Version string
// The *Run functions are executed in the following order: // The *Run functions are executed in the following order:
@ -140,9 +146,11 @@ type Command struct {
// TraverseChildren parses flags on all parents before executing child command. // TraverseChildren parses flags on all parents before executing child command.
TraverseChildren bool TraverseChildren bool
//FParseErrWhitelist flag parse errors to be ignored // FParseErrWhitelist flag parse errors to be ignored
FParseErrWhitelist FParseErrWhitelist FParseErrWhitelist FParseErrWhitelist
ctx context.Context
// commands is the list of commands supported by this program. // commands is the list of commands supported by this program.
commands []*Command commands []*Command
// parent is a parent command for this command. // parent is a parent command for this command.
@ -177,8 +185,6 @@ type Command struct {
// that we can use on every pflag set and children commands // that we can use on every pflag set and children commands
globNormFunc func(f *flag.FlagSet, name string) flag.NormalizedName globNormFunc func(f *flag.FlagSet, name string) flag.NormalizedName
// output is an output writer defined by user.
output io.Writer
// usageFunc is usage func defined by user. // usageFunc is usage func defined by user.
usageFunc func(*Command) error usageFunc func(*Command) error
// usageTemplate is usage template defined by user. // usageTemplate is usage template defined by user.
@ -195,6 +201,19 @@ type Command struct {
helpCommand *Command helpCommand *Command
// versionTemplate is the version template defined by user. // versionTemplate is the version template defined by user.
versionTemplate string versionTemplate string
// inReader is a reader defined by the user that replaces stdin
inReader io.Reader
// outWriter is a writer defined by the user that replaces stdout
outWriter io.Writer
// errWriter is a writer defined by the user that replaces stderr
errWriter io.Writer
}
// Context returns underlying command context. If command wasn't
// executed with ExecuteContext Context returns Background context.
func (c *Command) Context() context.Context {
return c.ctx
} }
// SetArgs sets arguments for the command. It is set to os.Args[1:] by default, if desired, can be overridden // SetArgs sets arguments for the command. It is set to os.Args[1:] by default, if desired, can be overridden
@ -205,8 +224,28 @@ func (c *Command) SetArgs(a []string) {
// SetOutput sets the destination for usage and error messages. // SetOutput sets the destination for usage and error messages.
// If output is nil, os.Stderr is used. // If output is nil, os.Stderr is used.
// Deprecated: Use SetOut and/or SetErr instead
func (c *Command) SetOutput(output io.Writer) { func (c *Command) SetOutput(output io.Writer) {
c.output = output c.outWriter = output
c.errWriter = output
}
// SetOut sets the destination for usage messages.
// If newOut is nil, os.Stdout is used.
func (c *Command) SetOut(newOut io.Writer) {
c.outWriter = newOut
}
// SetErr sets the destination for error messages.
// If newErr is nil, os.Stderr is used.
func (c *Command) SetErr(newErr io.Writer) {
c.errWriter = newErr
}
// SetIn sets the source for input data
// If newIn is nil, os.Stdin is used.
func (c *Command) SetIn(newIn io.Reader) {
c.inReader = newIn
} }
// SetUsageFunc sets usage function. Usage can be defined by application. // SetUsageFunc sets usage function. Usage can be defined by application.
@ -267,9 +306,19 @@ func (c *Command) OutOrStderr() io.Writer {
return c.getOut(os.Stderr) return c.getOut(os.Stderr)
} }
// ErrOrStderr returns output to stderr
func (c *Command) ErrOrStderr() io.Writer {
return c.getErr(os.Stderr)
}
// InOrStdin returns input to stdin
func (c *Command) InOrStdin() io.Reader {
return c.getIn(os.Stdin)
}
func (c *Command) getOut(def io.Writer) io.Writer { func (c *Command) getOut(def io.Writer) io.Writer {
if c.output != nil { if c.outWriter != nil {
return c.output return c.outWriter
} }
if c.HasParent() { if c.HasParent() {
return c.parent.getOut(def) return c.parent.getOut(def)
@ -277,6 +326,26 @@ func (c *Command) getOut(def io.Writer) io.Writer {
return def return def
} }
func (c *Command) getErr(def io.Writer) io.Writer {
if c.errWriter != nil {
return c.errWriter
}
if c.HasParent() {
return c.parent.getErr(def)
}
return def
}
func (c *Command) getIn(def io.Reader) io.Reader {
if c.inReader != nil {
return c.inReader
}
if c.HasParent() {
return c.parent.getIn(def)
}
return def
}
// UsageFunc returns either the function set by SetUsageFunc for this command // UsageFunc returns either the function set by SetUsageFunc for this command
// or a parent, or it returns a default usage function. // or a parent, or it returns a default usage function.
func (c *Command) UsageFunc() (f func(*Command) error) { func (c *Command) UsageFunc() (f func(*Command) error) {
@ -314,6 +383,8 @@ func (c *Command) HelpFunc() func(*Command, []string) {
} }
return func(c *Command, a []string) { return func(c *Command, a []string) {
c.mergePersistentFlags() c.mergePersistentFlags()
// The help should be sent to stdout
// See https://github.com/spf13/cobra/issues/1002
err := tmpl(c.OutOrStdout(), c.HelpTemplate(), c) err := tmpl(c.OutOrStdout(), c.HelpTemplate(), c)
if err != nil { if err != nil {
c.Println(err) c.Println(err)
@ -329,13 +400,22 @@ func (c *Command) Help() error {
return nil return nil
} }
// UsageString return usage string. // UsageString returns usage string.
func (c *Command) UsageString() string { func (c *Command) UsageString() string {
tmpOutput := c.output // Storing normal writers
tmpOutput := c.outWriter
tmpErr := c.errWriter
bb := new(bytes.Buffer) bb := new(bytes.Buffer)
c.SetOutput(bb) c.outWriter = bb
c.errWriter = bb
c.Usage() c.Usage()
c.output = tmpOutput
// Setting things back to normal
c.outWriter = tmpOutput
c.errWriter = tmpErr
return bb.String() return bb.String()
} }
@ -793,6 +873,13 @@ func (c *Command) preRun() {
} }
} }
// ExecuteContext is the same as Execute(), but sets the ctx on the command.
// Retrieve ctx by calling cmd.Context() inside your *Run lifecycle functions.
func (c *Command) ExecuteContext(ctx context.Context) error {
c.ctx = ctx
return c.Execute()
}
// Execute uses the args (os.Args[1:] by default) // Execute uses the args (os.Args[1:] by default)
// and run through the command tree finding appropriate matches // and run through the command tree finding appropriate matches
// for commands and then corresponding flags. // for commands and then corresponding flags.
@ -803,6 +890,10 @@ func (c *Command) Execute() error {
// ExecuteC executes the command. // ExecuteC executes the command.
func (c *Command) ExecuteC() (cmd *Command, err error) { func (c *Command) ExecuteC() (cmd *Command, err error) {
if c.ctx == nil {
c.ctx = context.Background()
}
// Regardless of what command execute is called on, run on Root only // Regardless of what command execute is called on, run on Root only
if c.HasParent() { if c.HasParent() {
return c.Root().ExecuteC() return c.Root().ExecuteC()
@ -817,15 +908,16 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
// overriding // overriding
c.InitDefaultHelpCmd() c.InitDefaultHelpCmd()
var args []string args := c.args
// Workaround FAIL with "go test -v" or "cobra.test -test.v", see #155 // Workaround FAIL with "go test -v" or "cobra.test -test.v", see #155
if c.args == nil && filepath.Base(os.Args[0]) != "cobra.test" { if c.args == nil && filepath.Base(os.Args[0]) != "cobra.test" {
args = os.Args[1:] args = os.Args[1:]
} else {
args = c.args
} }
// initialize the hidden command to be used for bash completion
c.initCompleteCmd(args)
var flags []string var flags []string
if c.TraverseChildren { if c.TraverseChildren {
cmd, flags, err = c.Traverse(args) cmd, flags, err = c.Traverse(args)
@ -849,6 +941,12 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
cmd.commandCalledAs.name = cmd.Name() cmd.commandCalledAs.name = cmd.Name()
} }
// We have to pass global context to children command
// if context is present on the parent command.
if cmd.ctx == nil {
cmd.ctx = c.ctx
}
err = cmd.execute(flags) err = cmd.execute(flags)
if err != nil { if err != nil {
// Always show help if requested, even if SilenceErrors is in // Always show help if requested, even if SilenceErrors is in
@ -932,7 +1030,11 @@ func (c *Command) InitDefaultVersionFlag() {
} else { } else {
usage += c.Name() usage += c.Name()
} }
c.Flags().Bool("version", false, usage) if c.Flags().ShorthandLookup("v") == nil {
c.Flags().BoolP("version", "v", false, usage)
} else {
c.Flags().Bool("version", false, usage)
}
} }
} }
@ -1070,6 +1172,21 @@ func (c *Command) Printf(format string, i ...interface{}) {
c.Print(fmt.Sprintf(format, i...)) c.Print(fmt.Sprintf(format, i...))
} }
// PrintErr is a convenience method to Print to the defined Err output, fallback to Stderr if not set.
func (c *Command) PrintErr(i ...interface{}) {
fmt.Fprint(c.ErrOrStderr(), i...)
}
// PrintErrln is a convenience method to Println to the defined Err output, fallback to Stderr if not set.
func (c *Command) PrintErrln(i ...interface{}) {
c.Print(fmt.Sprintln(i...))
}
// PrintErrf is a convenience method to Printf to the defined Err output, fallback to Stderr if not set.
func (c *Command) PrintErrf(format string, i ...interface{}) {
c.Print(fmt.Sprintf(format, i...))
}
// CommandPath returns the full path to this command. // CommandPath returns the full path to this command.
func (c *Command) CommandPath() string { func (c *Command) CommandPath() string {
if c.HasParent() { if c.HasParent() {
@ -1335,7 +1452,7 @@ func (c *Command) LocalFlags() *flag.FlagSet {
return c.lflags return c.lflags
} }
// InheritedFlags returns all flags which were inherited from parents commands. // InheritedFlags returns all flags which were inherited from parent commands.
func (c *Command) InheritedFlags() *flag.FlagSet { func (c *Command) InheritedFlags() *flag.FlagSet {
c.mergePersistentFlags() c.mergePersistentFlags()
@ -1470,7 +1587,7 @@ func (c *Command) ParseFlags(args []string) error {
beforeErrorBufLen := c.flagErrorBuf.Len() beforeErrorBufLen := c.flagErrorBuf.Len()
c.mergePersistentFlags() c.mergePersistentFlags()
//do it here after merging all flags and just before parse // do it here after merging all flags and just before parse
c.Flags().ParseErrorsWhitelist = flag.ParseErrorsWhitelist(c.FParseErrWhitelist) c.Flags().ParseErrorsWhitelist = flag.ParseErrorsWhitelist(c.FParseErrWhitelist)
err := c.Flags().Parse(args) err := c.Flags().Parse(args)

View file

@ -3,6 +3,7 @@
package cobra package cobra
import ( import (
"fmt"
"os" "os"
"time" "time"
@ -14,7 +15,12 @@ var preExecHookFn = preExecHook
func preExecHook(c *Command) { func preExecHook(c *Command) {
if MousetrapHelpText != "" && mousetrap.StartedByExplorer() { if MousetrapHelpText != "" && mousetrap.StartedByExplorer() {
c.Print(MousetrapHelpText) c.Print(MousetrapHelpText)
time.Sleep(5 * time.Second) if MousetrapDisplayDuration > 0 {
time.Sleep(MousetrapDisplayDuration)
} else {
c.Println("Press return to continue...")
fmt.Scanln()
}
os.Exit(1) os.Exit(1)
} }
} }

384
vendor/github.com/spf13/cobra/custom_completions.go generated vendored Normal file
View file

@ -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))
}

172
vendor/github.com/spf13/cobra/fish_completions.go generated vendored Normal file
View file

@ -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)
}

12
vendor/github.com/spf13/cobra/go.mod generated vendored Normal file
View file

@ -0,0 +1,12 @@
module github.com/spf13/cobra
go 1.12
require (
github.com/cpuguy83/go-md2man/v2 v2.0.0
github.com/inconshreveable/mousetrap v1.0.0
github.com/mitchellh/go-homedir v1.1.0
github.com/spf13/pflag v1.0.3
github.com/spf13/viper v1.4.0
gopkg.in/yaml.v2 v2.2.2
)

100
vendor/github.com/spf13/cobra/powershell_completions.go generated vendored Normal file
View file

@ -0,0 +1,100 @@
// PowerShell completions are based on the amazing work from clap:
// https://github.com/clap-rs/clap/blob/3294d18efe5f264d12c9035f404c7d189d4824e1/src/completions/powershell.rs
//
// The generated scripts require PowerShell v5.0+ (which comes Windows 10, but
// can be downloaded separately for windows 7 or 8.1).
package cobra
import (
"bytes"
"fmt"
"io"
"os"
"strings"
"github.com/spf13/pflag"
)
var powerShellCompletionTemplate = `using namespace System.Management.Automation
using namespace System.Management.Automation.Language
Register-ArgumentCompleter -Native -CommandName '%s' -ScriptBlock {
param($wordToComplete, $commandAst, $cursorPosition)
$commandElements = $commandAst.CommandElements
$command = @(
'%s'
for ($i = 1; $i -lt $commandElements.Count; $i++) {
$element = $commandElements[$i]
if ($element -isnot [StringConstantExpressionAst] -or
$element.StringConstantType -ne [StringConstantType]::BareWord -or
$element.Value.StartsWith('-')) {
break
}
$element.Value
}
) -join ';'
$completions = @(switch ($command) {%s
})
$completions.Where{ $_.CompletionText -like "$wordToComplete*" } |
Sort-Object -Property ListItemText
}`
func generatePowerShellSubcommandCases(out io.Writer, cmd *Command, previousCommandName string) {
var cmdName string
if previousCommandName == "" {
cmdName = cmd.Name()
} else {
cmdName = fmt.Sprintf("%s;%s", previousCommandName, cmd.Name())
}
fmt.Fprintf(out, "\n '%s' {", cmdName)
cmd.Flags().VisitAll(func(flag *pflag.Flag) {
if nonCompletableFlag(flag) {
return
}
usage := escapeStringForPowerShell(flag.Usage)
if len(flag.Shorthand) > 0 {
fmt.Fprintf(out, "\n [CompletionResult]::new('-%s', '%s', [CompletionResultType]::ParameterName, '%s')", flag.Shorthand, flag.Shorthand, usage)
}
fmt.Fprintf(out, "\n [CompletionResult]::new('--%s', '%s', [CompletionResultType]::ParameterName, '%s')", flag.Name, flag.Name, usage)
})
for _, subCmd := range cmd.Commands() {
usage := escapeStringForPowerShell(subCmd.Short)
fmt.Fprintf(out, "\n [CompletionResult]::new('%s', '%s', [CompletionResultType]::ParameterValue, '%s')", subCmd.Name(), subCmd.Name(), usage)
}
fmt.Fprint(out, "\n break\n }")
for _, subCmd := range cmd.Commands() {
generatePowerShellSubcommandCases(out, subCmd, cmdName)
}
}
func escapeStringForPowerShell(s string) string {
return strings.Replace(s, "'", "''", -1)
}
// GenPowerShellCompletion generates PowerShell completion file and writes to the passed writer.
func (c *Command) GenPowerShellCompletion(w io.Writer) error {
buf := new(bytes.Buffer)
var subCommandCases bytes.Buffer
generatePowerShellSubcommandCases(&subCommandCases, c, "")
fmt.Fprintf(buf, powerShellCompletionTemplate, c.Name(), c.Name(), subCommandCases.String())
_, err := buf.WriteTo(w)
return err
}
// GenPowerShellCompletionFile generates PowerShell completion file.
func (c *Command) GenPowerShellCompletionFile(filename string) error {
outFile, err := os.Create(filename)
if err != nil {
return err
}
defer outFile.Close()
return c.GenPowerShellCompletion(outFile)
}

85
vendor/github.com/spf13/cobra/shell_completions.go generated vendored Normal file
View file

@ -0,0 +1,85 @@
package cobra
import (
"github.com/spf13/pflag"
)
// MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag if it exists,
// and causes your command to report an error if invoked without the flag.
func (c *Command) MarkFlagRequired(name string) error {
return MarkFlagRequired(c.Flags(), name)
}
// MarkPersistentFlagRequired adds the BashCompOneRequiredFlag annotation to the named persistent flag if it exists,
// and causes your command to report an error if invoked without the flag.
func (c *Command) MarkPersistentFlagRequired(name string) error {
return MarkFlagRequired(c.PersistentFlags(), name)
}
// MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag if it exists,
// and causes your command to report an error if invoked without the flag.
func MarkFlagRequired(flags *pflag.FlagSet, name string) error {
return flags.SetAnnotation(name, BashCompOneRequiredFlag, []string{"true"})
}
// MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag, if it exists.
// Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided.
func (c *Command) MarkFlagFilename(name string, extensions ...string) error {
return MarkFlagFilename(c.Flags(), name, extensions...)
}
// MarkFlagCustom adds the BashCompCustom annotation to the named flag, if it exists.
// Generated bash autocompletion will call the bash function f for the flag.
func (c *Command) MarkFlagCustom(name string, f string) error {
return MarkFlagCustom(c.Flags(), name, f)
}
// MarkPersistentFlagFilename instructs the various shell completion
// implementations to limit completions for this persistent flag to the
// specified extensions (patterns).
//
// Shell Completion compatibility matrix: bash, zsh
func (c *Command) MarkPersistentFlagFilename(name string, extensions ...string) error {
return MarkFlagFilename(c.PersistentFlags(), name, extensions...)
}
// MarkFlagFilename instructs the various shell completion implementations to
// limit completions for this flag to the specified extensions (patterns).
//
// Shell Completion compatibility matrix: bash, zsh
func MarkFlagFilename(flags *pflag.FlagSet, name string, extensions ...string) error {
return flags.SetAnnotation(name, BashCompFilenameExt, extensions)
}
// MarkFlagCustom instructs the various shell completion implementations to
// limit completions for this flag to the specified extensions (patterns).
//
// Shell Completion compatibility matrix: bash, zsh
func MarkFlagCustom(flags *pflag.FlagSet, name string, f string) error {
return flags.SetAnnotation(name, BashCompCustom, []string{f})
}
// MarkFlagDirname instructs the various shell completion implementations to
// complete only directories with this named flag.
//
// Shell Completion compatibility matrix: zsh
func (c *Command) MarkFlagDirname(name string) error {
return MarkFlagDirname(c.Flags(), name)
}
// MarkPersistentFlagDirname instructs the various shell completion
// implementations to complete only directories with this persistent named flag.
//
// Shell Completion compatibility matrix: zsh
func (c *Command) MarkPersistentFlagDirname(name string) error {
return MarkFlagDirname(c.PersistentFlags(), name)
}
// MarkFlagDirname instructs the various shell completion implementations to
// complete only directories with this specified flag.
//
// Shell Completion compatibility matrix: zsh
func MarkFlagDirname(flags *pflag.FlagSet, name string) error {
zshPattern := "-(/)"
return flags.SetAnnotation(name, zshCompDirname, []string{zshPattern})
}

View file

@ -1,13 +1,102 @@
package cobra package cobra
import ( import (
"bytes" "encoding/json"
"fmt" "fmt"
"io" "io"
"os" "os"
"sort"
"strings" "strings"
"text/template"
"github.com/spf13/pflag"
) )
const (
zshCompArgumentAnnotation = "cobra_annotations_zsh_completion_argument_annotation"
zshCompArgumentFilenameComp = "cobra_annotations_zsh_completion_argument_file_completion"
zshCompArgumentWordComp = "cobra_annotations_zsh_completion_argument_word_completion"
zshCompDirname = "cobra_annotations_zsh_dirname"
)
var (
zshCompFuncMap = template.FuncMap{
"genZshFuncName": zshCompGenFuncName,
"extractFlags": zshCompExtractFlag,
"genFlagEntryForZshArguments": zshCompGenFlagEntryForArguments,
"extractArgsCompletions": zshCompExtractArgumentCompletionHintsForRendering,
}
zshCompletionText = `
{{/* should accept Command (that contains subcommands) as parameter */}}
{{define "argumentsC" -}}
{{ $cmdPath := genZshFuncName .}}
function {{$cmdPath}} {
local -a commands
_arguments -C \{{- range extractFlags .}}
{{genFlagEntryForZshArguments .}} \{{- end}}
"1: :->cmnds" \
"*::arg:->args"
case $state in
cmnds)
commands=({{range .Commands}}{{if not .Hidden}}
"{{.Name}}:{{.Short}}"{{end}}{{end}}
)
_describe "command" commands
;;
esac
case "$words[1]" in {{- range .Commands}}{{if not .Hidden}}
{{.Name}})
{{$cmdPath}}_{{.Name}}
;;{{end}}{{end}}
esac
}
{{range .Commands}}{{if not .Hidden}}
{{template "selectCmdTemplate" .}}
{{- end}}{{end}}
{{- end}}
{{/* should accept Command without subcommands as parameter */}}
{{define "arguments" -}}
function {{genZshFuncName .}} {
{{" _arguments"}}{{range extractFlags .}} \
{{genFlagEntryForZshArguments . -}}
{{end}}{{range extractArgsCompletions .}} \
{{.}}{{end}}
}
{{end}}
{{/* dispatcher for commands with or without subcommands */}}
{{define "selectCmdTemplate" -}}
{{if .Hidden}}{{/* ignore hidden*/}}{{else -}}
{{if .Commands}}{{template "argumentsC" .}}{{else}}{{template "arguments" .}}{{end}}
{{- end}}
{{- end}}
{{/* template entry point */}}
{{define "Main" -}}
#compdef _{{.Name}} {{.Name}}
{{template "selectCmdTemplate" .}}
{{end}}
`
)
// zshCompArgsAnnotation is used to encode/decode zsh completion for
// arguments to/from Command.Annotations.
type zshCompArgsAnnotation map[int]zshCompArgHint
type zshCompArgHint struct {
// Indicates the type of the completion to use. One of:
// zshCompArgumentFilenameComp or zshCompArgumentWordComp
Tipe string `json:"type"`
// A value for the type above (globs for file completion or words)
Options []string `json:"options"`
}
// GenZshCompletionFile generates zsh completion file. // GenZshCompletionFile generates zsh completion file.
func (c *Command) GenZshCompletionFile(filename string) error { func (c *Command) GenZshCompletionFile(filename string) error {
outFile, err := os.Create(filename) outFile, err := os.Create(filename)
@ -19,108 +108,229 @@ func (c *Command) GenZshCompletionFile(filename string) error {
return c.GenZshCompletion(outFile) return c.GenZshCompletion(outFile)
} }
// GenZshCompletion generates a zsh completion file and writes to the passed writer. // GenZshCompletion generates a zsh completion file and writes to the passed
// writer. The completion always run on the root command regardless of the
// command it was called from.
func (c *Command) GenZshCompletion(w io.Writer) error { func (c *Command) GenZshCompletion(w io.Writer) error {
buf := new(bytes.Buffer) tmpl, err := template.New("Main").Funcs(zshCompFuncMap).Parse(zshCompletionText)
if err != nil {
writeHeader(buf, c) return fmt.Errorf("error creating zsh completion template: %v", err)
maxDepth := maxDepth(c)
writeLevelMapping(buf, maxDepth)
writeLevelCases(buf, maxDepth, c)
_, err := buf.WriteTo(w)
return err
}
func writeHeader(w io.Writer, cmd *Command) {
fmt.Fprintf(w, "#compdef %s\n\n", cmd.Name())
}
func maxDepth(c *Command) int {
if len(c.Commands()) == 0 {
return 0
} }
maxDepthSub := 0 return tmpl.Execute(w, c.Root())
for _, s := range c.Commands() { }
subDepth := maxDepth(s)
if subDepth > maxDepthSub { // MarkZshCompPositionalArgumentFile marks the specified argument (first
maxDepthSub = subDepth // argument is 1) as completed by file selection. patterns (e.g. "*.txt") are
// optional - if not provided the completion will search for all files.
func (c *Command) MarkZshCompPositionalArgumentFile(argPosition int, patterns ...string) error {
if argPosition < 1 {
return fmt.Errorf("Invalid argument position (%d)", argPosition)
}
annotation, err := c.zshCompGetArgsAnnotations()
if err != nil {
return err
}
if c.zshcompArgsAnnotationnIsDuplicatePosition(annotation, argPosition) {
return fmt.Errorf("Duplicate annotation for positional argument at index %d", argPosition)
}
annotation[argPosition] = zshCompArgHint{
Tipe: zshCompArgumentFilenameComp,
Options: patterns,
}
return c.zshCompSetArgsAnnotations(annotation)
}
// MarkZshCompPositionalArgumentWords marks the specified positional argument
// (first argument is 1) as completed by the provided words. At east one word
// must be provided, spaces within words will be offered completion with
// "word\ word".
func (c *Command) MarkZshCompPositionalArgumentWords(argPosition int, words ...string) error {
if argPosition < 1 {
return fmt.Errorf("Invalid argument position (%d)", argPosition)
}
if len(words) == 0 {
return fmt.Errorf("Trying to set empty word list for positional argument %d", argPosition)
}
annotation, err := c.zshCompGetArgsAnnotations()
if err != nil {
return err
}
if c.zshcompArgsAnnotationnIsDuplicatePosition(annotation, argPosition) {
return fmt.Errorf("Duplicate annotation for positional argument at index %d", argPosition)
}
annotation[argPosition] = zshCompArgHint{
Tipe: zshCompArgumentWordComp,
Options: words,
}
return c.zshCompSetArgsAnnotations(annotation)
}
func zshCompExtractArgumentCompletionHintsForRendering(c *Command) ([]string, error) {
var result []string
annotation, err := c.zshCompGetArgsAnnotations()
if err != nil {
return nil, err
}
for k, v := range annotation {
s, err := zshCompRenderZshCompArgHint(k, v)
if err != nil {
return nil, err
}
result = append(result, s)
}
if len(c.ValidArgs) > 0 {
if _, positionOneExists := annotation[1]; !positionOneExists {
s, err := zshCompRenderZshCompArgHint(1, zshCompArgHint{
Tipe: zshCompArgumentWordComp,
Options: c.ValidArgs,
})
if err != nil {
return nil, err
}
result = append(result, s)
} }
} }
return 1 + maxDepthSub sort.Strings(result)
return result, nil
} }
func writeLevelMapping(w io.Writer, numLevels int) { func zshCompRenderZshCompArgHint(i int, z zshCompArgHint) (string, error) {
fmt.Fprintln(w, `_arguments \`) switch t := z.Tipe; t {
for i := 1; i <= numLevels; i++ { case zshCompArgumentFilenameComp:
fmt.Fprintf(w, ` '%d: :->level%d' \`, i, i) var globs []string
fmt.Fprintln(w) for _, g := range z.Options {
} globs = append(globs, fmt.Sprintf(`-g "%s"`, g))
fmt.Fprintf(w, ` '%d: :%s'`, numLevels+1, "_files")
fmt.Fprintln(w)
}
func writeLevelCases(w io.Writer, maxDepth int, root *Command) {
fmt.Fprintln(w, "case $state in")
defer fmt.Fprintln(w, "esac")
for i := 1; i <= maxDepth; i++ {
fmt.Fprintf(w, " level%d)\n", i)
writeLevel(w, root, i)
fmt.Fprintln(w, " ;;")
}
fmt.Fprintln(w, " *)")
fmt.Fprintln(w, " _arguments '*: :_files'")
fmt.Fprintln(w, " ;;")
}
func writeLevel(w io.Writer, root *Command, i int) {
fmt.Fprintf(w, " case $words[%d] in\n", i)
defer fmt.Fprintln(w, " esac")
commands := filterByLevel(root, i)
byParent := groupByParent(commands)
for p, c := range byParent {
names := names(c)
fmt.Fprintf(w, " %s)\n", p)
fmt.Fprintf(w, " _arguments '%d: :(%s)'\n", i, strings.Join(names, " "))
fmt.Fprintln(w, " ;;")
}
fmt.Fprintln(w, " *)")
fmt.Fprintln(w, " _arguments '*: :_files'")
fmt.Fprintln(w, " ;;")
}
func filterByLevel(c *Command, l int) []*Command {
cs := make([]*Command, 0)
if l == 0 {
cs = append(cs, c)
return cs
}
for _, s := range c.Commands() {
cs = append(cs, filterByLevel(s, l-1)...)
}
return cs
}
func groupByParent(commands []*Command) map[string][]*Command {
m := make(map[string][]*Command)
for _, c := range commands {
parent := c.Parent()
if parent == nil {
continue
} }
m[parent.Name()] = append(m[parent.Name()], c) return fmt.Sprintf(`'%d: :_files %s'`, i, strings.Join(globs, " ")), nil
case zshCompArgumentWordComp:
var words []string
for _, w := range z.Options {
words = append(words, fmt.Sprintf("%q", w))
}
return fmt.Sprintf(`'%d: :(%s)'`, i, strings.Join(words, " ")), nil
default:
return "", fmt.Errorf("Invalid zsh argument completion annotation: %s", t)
} }
return m
} }
func names(commands []*Command) []string { func (c *Command) zshcompArgsAnnotationnIsDuplicatePosition(annotation zshCompArgsAnnotation, position int) bool {
ns := make([]string, len(commands)) _, dup := annotation[position]
for i, c := range commands { return dup
ns[i] = c.Name() }
}
return ns func (c *Command) zshCompGetArgsAnnotations() (zshCompArgsAnnotation, error) {
annotation := make(zshCompArgsAnnotation)
annotationString, ok := c.Annotations[zshCompArgumentAnnotation]
if !ok {
return annotation, nil
}
err := json.Unmarshal([]byte(annotationString), &annotation)
if err != nil {
return annotation, fmt.Errorf("Error unmarshaling zsh argument annotation: %v", err)
}
return annotation, nil
}
func (c *Command) zshCompSetArgsAnnotations(annotation zshCompArgsAnnotation) error {
jsn, err := json.Marshal(annotation)
if err != nil {
return fmt.Errorf("Error marshaling zsh argument annotation: %v", err)
}
if c.Annotations == nil {
c.Annotations = make(map[string]string)
}
c.Annotations[zshCompArgumentAnnotation] = string(jsn)
return nil
}
func zshCompGenFuncName(c *Command) string {
if c.HasParent() {
return zshCompGenFuncName(c.Parent()) + "_" + c.Name()
}
return "_" + c.Name()
}
func zshCompExtractFlag(c *Command) []*pflag.Flag {
var flags []*pflag.Flag
c.LocalFlags().VisitAll(func(f *pflag.Flag) {
if !f.Hidden {
flags = append(flags, f)
}
})
c.InheritedFlags().VisitAll(func(f *pflag.Flag) {
if !f.Hidden {
flags = append(flags, f)
}
})
return flags
}
// zshCompGenFlagEntryForArguments returns an entry that matches _arguments
// zsh-completion parameters. It's too complicated to generate in a template.
func zshCompGenFlagEntryForArguments(f *pflag.Flag) string {
if f.Name == "" || f.Shorthand == "" {
return zshCompGenFlagEntryForSingleOptionFlag(f)
}
return zshCompGenFlagEntryForMultiOptionFlag(f)
}
func zshCompGenFlagEntryForSingleOptionFlag(f *pflag.Flag) string {
var option, multiMark, extras string
if zshCompFlagCouldBeSpecifiedMoreThenOnce(f) {
multiMark = "*"
}
option = "--" + f.Name
if option == "--" {
option = "-" + f.Shorthand
}
extras = zshCompGenFlagEntryExtras(f)
return fmt.Sprintf(`'%s%s[%s]%s'`, multiMark, option, zshCompQuoteFlagDescription(f.Usage), extras)
}
func zshCompGenFlagEntryForMultiOptionFlag(f *pflag.Flag) string {
var options, parenMultiMark, curlyMultiMark, extras string
if zshCompFlagCouldBeSpecifiedMoreThenOnce(f) {
parenMultiMark = "*"
curlyMultiMark = "\\*"
}
options = fmt.Sprintf(`'(%s-%s %s--%s)'{%s-%s,%s--%s}`,
parenMultiMark, f.Shorthand, parenMultiMark, f.Name, curlyMultiMark, f.Shorthand, curlyMultiMark, f.Name)
extras = zshCompGenFlagEntryExtras(f)
return fmt.Sprintf(`%s'[%s]%s'`, options, zshCompQuoteFlagDescription(f.Usage), extras)
}
func zshCompGenFlagEntryExtras(f *pflag.Flag) string {
if f.NoOptDefVal != "" {
return ""
}
extras := ":" // allow options for flag (even without assistance)
for key, values := range f.Annotations {
switch key {
case zshCompDirname:
extras = fmt.Sprintf(":filename:_files -g %q", values[0])
case BashCompFilenameExt:
extras = ":filename:_files"
for _, pattern := range values {
extras = extras + fmt.Sprintf(` -g "%s"`, pattern)
}
}
}
return extras
}
func zshCompFlagCouldBeSpecifiedMoreThenOnce(f *pflag.Flag) bool {
return strings.Contains(f.Value.Type(), "Slice") ||
strings.Contains(f.Value.Type(), "Array")
}
func zshCompQuoteFlagDescription(s string) string {
return strings.Replace(s, "'", `'\''`, -1)
} }

View file

@ -86,8 +86,8 @@ fmt.Println("ip has value ", *ip)
fmt.Println("flagvar has value ", flagvar) fmt.Println("flagvar has value ", flagvar)
``` ```
There are helpers function to get values later if you have the FlagSet but There are helper functions available to get the value stored in a Flag if you have a FlagSet but find
it was difficult to keep up with all of the flag pointers in your code. it difficult to keep up with all of the pointers in your code.
If you have a pflag.FlagSet with a flag called 'flagname' of type int you If you have a pflag.FlagSet with a flag called 'flagname' of type int you
can use GetInt() to get the int value. But notice that 'flagname' must exist can use GetInt() to get the int value. But notice that 'flagname' must exist
and it must be an int. GetString("flagname") will fail. and it must be an int. GetString("flagname") will fail.

View file

@ -71,6 +71,44 @@ func (s *boolSliceValue) String() string {
return "[" + out + "]" return "[" + out + "]"
} }
func (s *boolSliceValue) fromString(val string) (bool, error) {
return strconv.ParseBool(val)
}
func (s *boolSliceValue) toString(val bool) string {
return strconv.FormatBool(val)
}
func (s *boolSliceValue) Append(val string) error {
i, err := s.fromString(val)
if err != nil {
return err
}
*s.value = append(*s.value, i)
return nil
}
func (s *boolSliceValue) Replace(val []string) error {
out := make([]bool, len(val))
for i, d := range val {
var err error
out[i], err = s.fromString(d)
if err != nil {
return err
}
}
*s.value = out
return nil
}
func (s *boolSliceValue) GetSlice() []string {
out := make([]string, len(*s.value))
for i, d := range *s.value {
out[i] = s.toString(d)
}
return out
}
func boolSliceConv(val string) (interface{}, error) { func boolSliceConv(val string) (interface{}, error) {
val = strings.Trim(val, "[]") val = strings.Trim(val, "[]")
// Empty string would cause a slice with one (empty) entry // Empty string would cause a slice with one (empty) entry

View file

@ -1,6 +1,7 @@
package pflag package pflag
import ( import (
"encoding/base64"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"strings" "strings"
@ -9,10 +10,12 @@ import (
// BytesHex adapts []byte for use as a flag. Value of flag is HEX encoded // BytesHex adapts []byte for use as a flag. Value of flag is HEX encoded
type bytesHexValue []byte type bytesHexValue []byte
// String implements pflag.Value.String.
func (bytesHex bytesHexValue) String() string { func (bytesHex bytesHexValue) String() string {
return fmt.Sprintf("%X", []byte(bytesHex)) return fmt.Sprintf("%X", []byte(bytesHex))
} }
// Set implements pflag.Value.Set.
func (bytesHex *bytesHexValue) Set(value string) error { func (bytesHex *bytesHexValue) Set(value string) error {
bin, err := hex.DecodeString(strings.TrimSpace(value)) bin, err := hex.DecodeString(strings.TrimSpace(value))
@ -25,6 +28,7 @@ func (bytesHex *bytesHexValue) Set(value string) error {
return nil return nil
} }
// Type implements pflag.Value.Type.
func (*bytesHexValue) Type() string { func (*bytesHexValue) Type() string {
return "bytesHex" return "bytesHex"
} }
@ -103,3 +107,103 @@ func BytesHex(name string, value []byte, usage string) *[]byte {
func BytesHexP(name, shorthand string, value []byte, usage string) *[]byte { func BytesHexP(name, shorthand string, value []byte, usage string) *[]byte {
return CommandLine.BytesHexP(name, shorthand, value, usage) return CommandLine.BytesHexP(name, shorthand, value, usage)
} }
// BytesBase64 adapts []byte for use as a flag. Value of flag is Base64 encoded
type bytesBase64Value []byte
// String implements pflag.Value.String.
func (bytesBase64 bytesBase64Value) String() string {
return base64.StdEncoding.EncodeToString([]byte(bytesBase64))
}
// Set implements pflag.Value.Set.
func (bytesBase64 *bytesBase64Value) Set(value string) error {
bin, err := base64.StdEncoding.DecodeString(strings.TrimSpace(value))
if err != nil {
return err
}
*bytesBase64 = bin
return nil
}
// Type implements pflag.Value.Type.
func (*bytesBase64Value) Type() string {
return "bytesBase64"
}
func newBytesBase64Value(val []byte, p *[]byte) *bytesBase64Value {
*p = val
return (*bytesBase64Value)(p)
}
func bytesBase64ValueConv(sval string) (interface{}, error) {
bin, err := base64.StdEncoding.DecodeString(sval)
if err == nil {
return bin, nil
}
return nil, fmt.Errorf("invalid string being converted to Bytes: %s %s", sval, err)
}
// GetBytesBase64 return the []byte value of a flag with the given name
func (f *FlagSet) GetBytesBase64(name string) ([]byte, error) {
val, err := f.getFlagType(name, "bytesBase64", bytesBase64ValueConv)
if err != nil {
return []byte{}, err
}
return val.([]byte), nil
}
// BytesBase64Var defines an []byte flag with specified name, default value, and usage string.
// The argument p points to an []byte variable in which to store the value of the flag.
func (f *FlagSet) BytesBase64Var(p *[]byte, name string, value []byte, usage string) {
f.VarP(newBytesBase64Value(value, p), name, "", usage)
}
// BytesBase64VarP is like BytesBase64Var, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) BytesBase64VarP(p *[]byte, name, shorthand string, value []byte, usage string) {
f.VarP(newBytesBase64Value(value, p), name, shorthand, usage)
}
// BytesBase64Var defines an []byte flag with specified name, default value, and usage string.
// The argument p points to an []byte variable in which to store the value of the flag.
func BytesBase64Var(p *[]byte, name string, value []byte, usage string) {
CommandLine.VarP(newBytesBase64Value(value, p), name, "", usage)
}
// BytesBase64VarP is like BytesBase64Var, but accepts a shorthand letter that can be used after a single dash.
func BytesBase64VarP(p *[]byte, name, shorthand string, value []byte, usage string) {
CommandLine.VarP(newBytesBase64Value(value, p), name, shorthand, usage)
}
// BytesBase64 defines an []byte flag with specified name, default value, and usage string.
// The return value is the address of an []byte variable that stores the value of the flag.
func (f *FlagSet) BytesBase64(name string, value []byte, usage string) *[]byte {
p := new([]byte)
f.BytesBase64VarP(p, name, "", value, usage)
return p
}
// BytesBase64P is like BytesBase64, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) BytesBase64P(name, shorthand string, value []byte, usage string) *[]byte {
p := new([]byte)
f.BytesBase64VarP(p, name, shorthand, value, usage)
return p
}
// BytesBase64 defines an []byte flag with specified name, default value, and usage string.
// The return value is the address of an []byte variable that stores the value of the flag.
func BytesBase64(name string, value []byte, usage string) *[]byte {
return CommandLine.BytesBase64P(name, "", value, usage)
}
// BytesBase64P is like BytesBase64, but accepts a shorthand letter that can be used after a single dash.
func BytesBase64P(name, shorthand string, value []byte, usage string) *[]byte {
return CommandLine.BytesBase64P(name, shorthand, value, usage)
}

View file

@ -46,7 +46,7 @@ func (f *FlagSet) GetCount(name string) (int, error) {
// CountVar defines a count flag with specified name, default value, and usage string. // CountVar defines a count flag with specified name, default value, and usage string.
// The argument p points to an int variable in which to store the value of the flag. // The argument p points to an int variable in which to store the value of the flag.
// A count flag will add 1 to its value evey time it is found on the command line // A count flag will add 1 to its value every time it is found on the command line
func (f *FlagSet) CountVar(p *int, name string, usage string) { func (f *FlagSet) CountVar(p *int, name string, usage string) {
f.CountVarP(p, name, "", usage) f.CountVarP(p, name, "", usage)
} }
@ -69,7 +69,7 @@ func CountVarP(p *int, name, shorthand string, usage string) {
// Count defines a count flag with specified name, default value, and usage string. // Count defines a count flag with specified name, default value, and usage string.
// The return value is the address of an int variable that stores the value of the flag. // The return value is the address of an int variable that stores the value of the flag.
// A count flag will add 1 to its value evey time it is found on the command line // A count flag will add 1 to its value every time it is found on the command line
func (f *FlagSet) Count(name string, usage string) *int { func (f *FlagSet) Count(name string, usage string) *int {
p := new(int) p := new(int)
f.CountVarP(p, name, "", usage) f.CountVarP(p, name, "", usage)

View file

@ -51,6 +51,44 @@ func (s *durationSliceValue) String() string {
return "[" + strings.Join(out, ",") + "]" return "[" + strings.Join(out, ",") + "]"
} }
func (s *durationSliceValue) fromString(val string) (time.Duration, error) {
return time.ParseDuration(val)
}
func (s *durationSliceValue) toString(val time.Duration) string {
return fmt.Sprintf("%s", val)
}
func (s *durationSliceValue) Append(val string) error {
i, err := s.fromString(val)
if err != nil {
return err
}
*s.value = append(*s.value, i)
return nil
}
func (s *durationSliceValue) Replace(val []string) error {
out := make([]time.Duration, len(val))
for i, d := range val {
var err error
out[i], err = s.fromString(d)
if err != nil {
return err
}
}
*s.value = out
return nil
}
func (s *durationSliceValue) GetSlice() []string {
out := make([]string, len(*s.value))
for i, d := range *s.value {
out[i] = s.toString(d)
}
return out
}
func durationSliceConv(val string) (interface{}, error) { func durationSliceConv(val string) (interface{}, error) {
val = strings.Trim(val, "[]") val = strings.Trim(val, "[]")
// Empty string would cause a slice with one (empty) entry // Empty string would cause a slice with one (empty) entry

View file

@ -57,9 +57,9 @@ that give one-letter shorthands for flags. You can use these by appending
var ip = flag.IntP("flagname", "f", 1234, "help message") var ip = flag.IntP("flagname", "f", 1234, "help message")
var flagvar bool var flagvar bool
func init() { func init() {
flag.BoolVarP("boolname", "b", true, "help message") flag.BoolVarP(&flagvar, "boolname", "b", true, "help message")
} }
flag.VarP(&flagVar, "varname", "v", 1234, "help message") flag.VarP(&flagval, "varname", "v", "help message")
Shorthand letters can be used with single dashes on the command line. Shorthand letters can be used with single dashes on the command line.
Boolean shorthand flags can be combined with other shorthand flags. Boolean shorthand flags can be combined with other shorthand flags.
@ -190,6 +190,18 @@ type Value interface {
Type() string Type() string
} }
// SliceValue is a secondary interface to all flags which hold a list
// of values. This allows full control over the value of list flags,
// and avoids complicated marshalling and unmarshalling to csv.
type SliceValue interface {
// Append adds the specified value to the end of the flag value list.
Append(string) error
// Replace will fully overwrite any data currently in the flag value list.
Replace([]string) error
// GetSlice returns the flag value list as an array of strings.
GetSlice() []string
}
// sortFlags returns the flags as a slice in lexicographical sorted order. // sortFlags returns the flags as a slice in lexicographical sorted order.
func sortFlags(flags map[NormalizedName]*Flag) []*Flag { func sortFlags(flags map[NormalizedName]*Flag) []*Flag {
list := make(sort.StringSlice, len(flags)) list := make(sort.StringSlice, len(flags))
@ -925,13 +937,16 @@ func stripUnknownFlagValue(args []string) []string {
} }
first := args[0] first := args[0]
if first[0] == '-' { if len(first) > 0 && first[0] == '-' {
//--unknown --next-flag ... //--unknown --next-flag ...
return args return args
} }
//--unknown arg ... (args will be arg ...) //--unknown arg ... (args will be arg ...)
return args[1:] if len(args) > 1 {
return args[1:]
}
return nil
} }
func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []string, err error) { func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []string, err error) {
@ -990,11 +1005,12 @@ func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []strin
} }
func (f *FlagSet) parseSingleShortArg(shorthands string, args []string, fn parseFunc) (outShorts string, outArgs []string, err error) { func (f *FlagSet) parseSingleShortArg(shorthands string, args []string, fn parseFunc) (outShorts string, outArgs []string, err error) {
outArgs = args
if strings.HasPrefix(shorthands, "test.") { if strings.HasPrefix(shorthands, "test.") {
return return
} }
outArgs = args
outShorts = shorthands[1:] outShorts = shorthands[1:]
c := shorthands[0] c := shorthands[0]

174
vendor/github.com/spf13/pflag/float32_slice.go generated vendored Normal file
View file

@ -0,0 +1,174 @@
package pflag
import (
"fmt"
"strconv"
"strings"
)
// -- float32Slice Value
type float32SliceValue struct {
value *[]float32
changed bool
}
func newFloat32SliceValue(val []float32, p *[]float32) *float32SliceValue {
isv := new(float32SliceValue)
isv.value = p
*isv.value = val
return isv
}
func (s *float32SliceValue) Set(val string) error {
ss := strings.Split(val, ",")
out := make([]float32, len(ss))
for i, d := range ss {
var err error
var temp64 float64
temp64, err = strconv.ParseFloat(d, 32)
if err != nil {
return err
}
out[i] = float32(temp64)
}
if !s.changed {
*s.value = out
} else {
*s.value = append(*s.value, out...)
}
s.changed = true
return nil
}
func (s *float32SliceValue) Type() string {
return "float32Slice"
}
func (s *float32SliceValue) String() string {
out := make([]string, len(*s.value))
for i, d := range *s.value {
out[i] = fmt.Sprintf("%f", d)
}
return "[" + strings.Join(out, ",") + "]"
}
func (s *float32SliceValue) fromString(val string) (float32, error) {
t64, err := strconv.ParseFloat(val, 32)
if err != nil {
return 0, err
}
return float32(t64), nil
}
func (s *float32SliceValue) toString(val float32) string {
return fmt.Sprintf("%f", val)
}
func (s *float32SliceValue) Append(val string) error {
i, err := s.fromString(val)
if err != nil {
return err
}
*s.value = append(*s.value, i)
return nil
}
func (s *float32SliceValue) Replace(val []string) error {
out := make([]float32, len(val))
for i, d := range val {
var err error
out[i], err = s.fromString(d)
if err != nil {
return err
}
}
*s.value = out
return nil
}
func (s *float32SliceValue) GetSlice() []string {
out := make([]string, len(*s.value))
for i, d := range *s.value {
out[i] = s.toString(d)
}
return out
}
func float32SliceConv(val string) (interface{}, error) {
val = strings.Trim(val, "[]")
// Empty string would cause a slice with one (empty) entry
if len(val) == 0 {
return []float32{}, nil
}
ss := strings.Split(val, ",")
out := make([]float32, len(ss))
for i, d := range ss {
var err error
var temp64 float64
temp64, err = strconv.ParseFloat(d, 32)
if err != nil {
return nil, err
}
out[i] = float32(temp64)
}
return out, nil
}
// GetFloat32Slice return the []float32 value of a flag with the given name
func (f *FlagSet) GetFloat32Slice(name string) ([]float32, error) {
val, err := f.getFlagType(name, "float32Slice", float32SliceConv)
if err != nil {
return []float32{}, err
}
return val.([]float32), nil
}
// Float32SliceVar defines a float32Slice flag with specified name, default value, and usage string.
// The argument p points to a []float32 variable in which to store the value of the flag.
func (f *FlagSet) Float32SliceVar(p *[]float32, name string, value []float32, usage string) {
f.VarP(newFloat32SliceValue(value, p), name, "", usage)
}
// Float32SliceVarP is like Float32SliceVar, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) Float32SliceVarP(p *[]float32, name, shorthand string, value []float32, usage string) {
f.VarP(newFloat32SliceValue(value, p), name, shorthand, usage)
}
// Float32SliceVar defines a float32[] flag with specified name, default value, and usage string.
// The argument p points to a float32[] variable in which to store the value of the flag.
func Float32SliceVar(p *[]float32, name string, value []float32, usage string) {
CommandLine.VarP(newFloat32SliceValue(value, p), name, "", usage)
}
// Float32SliceVarP is like Float32SliceVar, but accepts a shorthand letter that can be used after a single dash.
func Float32SliceVarP(p *[]float32, name, shorthand string, value []float32, usage string) {
CommandLine.VarP(newFloat32SliceValue(value, p), name, shorthand, usage)
}
// Float32Slice defines a []float32 flag with specified name, default value, and usage string.
// The return value is the address of a []float32 variable that stores the value of the flag.
func (f *FlagSet) Float32Slice(name string, value []float32, usage string) *[]float32 {
p := []float32{}
f.Float32SliceVarP(&p, name, "", value, usage)
return &p
}
// Float32SliceP is like Float32Slice, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) Float32SliceP(name, shorthand string, value []float32, usage string) *[]float32 {
p := []float32{}
f.Float32SliceVarP(&p, name, shorthand, value, usage)
return &p
}
// Float32Slice defines a []float32 flag with specified name, default value, and usage string.
// The return value is the address of a []float32 variable that stores the value of the flag.
func Float32Slice(name string, value []float32, usage string) *[]float32 {
return CommandLine.Float32SliceP(name, "", value, usage)
}
// Float32SliceP is like Float32Slice, but accepts a shorthand letter that can be used after a single dash.
func Float32SliceP(name, shorthand string, value []float32, usage string) *[]float32 {
return CommandLine.Float32SliceP(name, shorthand, value, usage)
}

166
vendor/github.com/spf13/pflag/float64_slice.go generated vendored Normal file
View file

@ -0,0 +1,166 @@
package pflag
import (
"fmt"
"strconv"
"strings"
)
// -- float64Slice Value
type float64SliceValue struct {
value *[]float64
changed bool
}
func newFloat64SliceValue(val []float64, p *[]float64) *float64SliceValue {
isv := new(float64SliceValue)
isv.value = p
*isv.value = val
return isv
}
func (s *float64SliceValue) Set(val string) error {
ss := strings.Split(val, ",")
out := make([]float64, len(ss))
for i, d := range ss {
var err error
out[i], err = strconv.ParseFloat(d, 64)
if err != nil {
return err
}
}
if !s.changed {
*s.value = out
} else {
*s.value = append(*s.value, out...)
}
s.changed = true
return nil
}
func (s *float64SliceValue) Type() string {
return "float64Slice"
}
func (s *float64SliceValue) String() string {
out := make([]string, len(*s.value))
for i, d := range *s.value {
out[i] = fmt.Sprintf("%f", d)
}
return "[" + strings.Join(out, ",") + "]"
}
func (s *float64SliceValue) fromString(val string) (float64, error) {
return strconv.ParseFloat(val, 64)
}
func (s *float64SliceValue) toString(val float64) string {
return fmt.Sprintf("%f", val)
}
func (s *float64SliceValue) Append(val string) error {
i, err := s.fromString(val)
if err != nil {
return err
}
*s.value = append(*s.value, i)
return nil
}
func (s *float64SliceValue) Replace(val []string) error {
out := make([]float64, len(val))
for i, d := range val {
var err error
out[i], err = s.fromString(d)
if err != nil {
return err
}
}
*s.value = out
return nil
}
func (s *float64SliceValue) GetSlice() []string {
out := make([]string, len(*s.value))
for i, d := range *s.value {
out[i] = s.toString(d)
}
return out
}
func float64SliceConv(val string) (interface{}, error) {
val = strings.Trim(val, "[]")
// Empty string would cause a slice with one (empty) entry
if len(val) == 0 {
return []float64{}, nil
}
ss := strings.Split(val, ",")
out := make([]float64, len(ss))
for i, d := range ss {
var err error
out[i], err = strconv.ParseFloat(d, 64)
if err != nil {
return nil, err
}
}
return out, nil
}
// GetFloat64Slice return the []float64 value of a flag with the given name
func (f *FlagSet) GetFloat64Slice(name string) ([]float64, error) {
val, err := f.getFlagType(name, "float64Slice", float64SliceConv)
if err != nil {
return []float64{}, err
}
return val.([]float64), nil
}
// Float64SliceVar defines a float64Slice flag with specified name, default value, and usage string.
// The argument p points to a []float64 variable in which to store the value of the flag.
func (f *FlagSet) Float64SliceVar(p *[]float64, name string, value []float64, usage string) {
f.VarP(newFloat64SliceValue(value, p), name, "", usage)
}
// Float64SliceVarP is like Float64SliceVar, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) Float64SliceVarP(p *[]float64, name, shorthand string, value []float64, usage string) {
f.VarP(newFloat64SliceValue(value, p), name, shorthand, usage)
}
// Float64SliceVar defines a float64[] flag with specified name, default value, and usage string.
// The argument p points to a float64[] variable in which to store the value of the flag.
func Float64SliceVar(p *[]float64, name string, value []float64, usage string) {
CommandLine.VarP(newFloat64SliceValue(value, p), name, "", usage)
}
// Float64SliceVarP is like Float64SliceVar, but accepts a shorthand letter that can be used after a single dash.
func Float64SliceVarP(p *[]float64, name, shorthand string, value []float64, usage string) {
CommandLine.VarP(newFloat64SliceValue(value, p), name, shorthand, usage)
}
// Float64Slice defines a []float64 flag with specified name, default value, and usage string.
// The return value is the address of a []float64 variable that stores the value of the flag.
func (f *FlagSet) Float64Slice(name string, value []float64, usage string) *[]float64 {
p := []float64{}
f.Float64SliceVarP(&p, name, "", value, usage)
return &p
}
// Float64SliceP is like Float64Slice, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) Float64SliceP(name, shorthand string, value []float64, usage string) *[]float64 {
p := []float64{}
f.Float64SliceVarP(&p, name, shorthand, value, usage)
return &p
}
// Float64Slice defines a []float64 flag with specified name, default value, and usage string.
// The return value is the address of a []float64 variable that stores the value of the flag.
func Float64Slice(name string, value []float64, usage string) *[]float64 {
return CommandLine.Float64SliceP(name, "", value, usage)
}
// Float64SliceP is like Float64Slice, but accepts a shorthand letter that can be used after a single dash.
func Float64SliceP(name, shorthand string, value []float64, usage string) *[]float64 {
return CommandLine.Float64SliceP(name, shorthand, value, usage)
}

3
vendor/github.com/spf13/pflag/go.mod generated vendored Normal file
View file

@ -0,0 +1,3 @@
module github.com/spf13/pflag
go 1.12

174
vendor/github.com/spf13/pflag/int32_slice.go generated vendored Normal file
View file

@ -0,0 +1,174 @@
package pflag
import (
"fmt"
"strconv"
"strings"
)
// -- int32Slice Value
type int32SliceValue struct {
value *[]int32
changed bool
}
func newInt32SliceValue(val []int32, p *[]int32) *int32SliceValue {
isv := new(int32SliceValue)
isv.value = p
*isv.value = val
return isv
}
func (s *int32SliceValue) Set(val string) error {
ss := strings.Split(val, ",")
out := make([]int32, len(ss))
for i, d := range ss {
var err error
var temp64 int64
temp64, err = strconv.ParseInt(d, 0, 32)
if err != nil {
return err
}
out[i] = int32(temp64)
}
if !s.changed {
*s.value = out
} else {
*s.value = append(*s.value, out...)
}
s.changed = true
return nil
}
func (s *int32SliceValue) Type() string {
return "int32Slice"
}
func (s *int32SliceValue) String() string {
out := make([]string, len(*s.value))
for i, d := range *s.value {
out[i] = fmt.Sprintf("%d", d)
}
return "[" + strings.Join(out, ",") + "]"
}
func (s *int32SliceValue) fromString(val string) (int32, error) {
t64, err := strconv.ParseInt(val, 0, 32)
if err != nil {
return 0, err
}
return int32(t64), nil
}
func (s *int32SliceValue) toString(val int32) string {
return fmt.Sprintf("%d", val)
}
func (s *int32SliceValue) Append(val string) error {
i, err := s.fromString(val)
if err != nil {
return err
}
*s.value = append(*s.value, i)
return nil
}
func (s *int32SliceValue) Replace(val []string) error {
out := make([]int32, len(val))
for i, d := range val {
var err error
out[i], err = s.fromString(d)
if err != nil {
return err
}
}
*s.value = out
return nil
}
func (s *int32SliceValue) GetSlice() []string {
out := make([]string, len(*s.value))
for i, d := range *s.value {
out[i] = s.toString(d)
}
return out
}
func int32SliceConv(val string) (interface{}, error) {
val = strings.Trim(val, "[]")
// Empty string would cause a slice with one (empty) entry
if len(val) == 0 {
return []int32{}, nil
}
ss := strings.Split(val, ",")
out := make([]int32, len(ss))
for i, d := range ss {
var err error
var temp64 int64
temp64, err = strconv.ParseInt(d, 0, 32)
if err != nil {
return nil, err
}
out[i] = int32(temp64)
}
return out, nil
}
// GetInt32Slice return the []int32 value of a flag with the given name
func (f *FlagSet) GetInt32Slice(name string) ([]int32, error) {
val, err := f.getFlagType(name, "int32Slice", int32SliceConv)
if err != nil {
return []int32{}, err
}
return val.([]int32), nil
}
// Int32SliceVar defines a int32Slice flag with specified name, default value, and usage string.
// The argument p points to a []int32 variable in which to store the value of the flag.
func (f *FlagSet) Int32SliceVar(p *[]int32, name string, value []int32, usage string) {
f.VarP(newInt32SliceValue(value, p), name, "", usage)
}
// Int32SliceVarP is like Int32SliceVar, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) Int32SliceVarP(p *[]int32, name, shorthand string, value []int32, usage string) {
f.VarP(newInt32SliceValue(value, p), name, shorthand, usage)
}
// Int32SliceVar defines a int32[] flag with specified name, default value, and usage string.
// The argument p points to a int32[] variable in which to store the value of the flag.
func Int32SliceVar(p *[]int32, name string, value []int32, usage string) {
CommandLine.VarP(newInt32SliceValue(value, p), name, "", usage)
}
// Int32SliceVarP is like Int32SliceVar, but accepts a shorthand letter that can be used after a single dash.
func Int32SliceVarP(p *[]int32, name, shorthand string, value []int32, usage string) {
CommandLine.VarP(newInt32SliceValue(value, p), name, shorthand, usage)
}
// Int32Slice defines a []int32 flag with specified name, default value, and usage string.
// The return value is the address of a []int32 variable that stores the value of the flag.
func (f *FlagSet) Int32Slice(name string, value []int32, usage string) *[]int32 {
p := []int32{}
f.Int32SliceVarP(&p, name, "", value, usage)
return &p
}
// Int32SliceP is like Int32Slice, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) Int32SliceP(name, shorthand string, value []int32, usage string) *[]int32 {
p := []int32{}
f.Int32SliceVarP(&p, name, shorthand, value, usage)
return &p
}
// Int32Slice defines a []int32 flag with specified name, default value, and usage string.
// The return value is the address of a []int32 variable that stores the value of the flag.
func Int32Slice(name string, value []int32, usage string) *[]int32 {
return CommandLine.Int32SliceP(name, "", value, usage)
}
// Int32SliceP is like Int32Slice, but accepts a shorthand letter that can be used after a single dash.
func Int32SliceP(name, shorthand string, value []int32, usage string) *[]int32 {
return CommandLine.Int32SliceP(name, shorthand, value, usage)
}

166
vendor/github.com/spf13/pflag/int64_slice.go generated vendored Normal file
View file

@ -0,0 +1,166 @@
package pflag
import (
"fmt"
"strconv"
"strings"
)
// -- int64Slice Value
type int64SliceValue struct {
value *[]int64
changed bool
}
func newInt64SliceValue(val []int64, p *[]int64) *int64SliceValue {
isv := new(int64SliceValue)
isv.value = p
*isv.value = val
return isv
}
func (s *int64SliceValue) Set(val string) error {
ss := strings.Split(val, ",")
out := make([]int64, len(ss))
for i, d := range ss {
var err error
out[i], err = strconv.ParseInt(d, 0, 64)
if err != nil {
return err
}
}
if !s.changed {
*s.value = out
} else {
*s.value = append(*s.value, out...)
}
s.changed = true
return nil
}
func (s *int64SliceValue) Type() string {
return "int64Slice"
}
func (s *int64SliceValue) String() string {
out := make([]string, len(*s.value))
for i, d := range *s.value {
out[i] = fmt.Sprintf("%d", d)
}
return "[" + strings.Join(out, ",") + "]"
}
func (s *int64SliceValue) fromString(val string) (int64, error) {
return strconv.ParseInt(val, 0, 64)
}
func (s *int64SliceValue) toString(val int64) string {
return fmt.Sprintf("%d", val)
}
func (s *int64SliceValue) Append(val string) error {
i, err := s.fromString(val)
if err != nil {
return err
}
*s.value = append(*s.value, i)
return nil
}
func (s *int64SliceValue) Replace(val []string) error {
out := make([]int64, len(val))
for i, d := range val {
var err error
out[i], err = s.fromString(d)
if err != nil {
return err
}
}
*s.value = out
return nil
}
func (s *int64SliceValue) GetSlice() []string {
out := make([]string, len(*s.value))
for i, d := range *s.value {
out[i] = s.toString(d)
}
return out
}
func int64SliceConv(val string) (interface{}, error) {
val = strings.Trim(val, "[]")
// Empty string would cause a slice with one (empty) entry
if len(val) == 0 {
return []int64{}, nil
}
ss := strings.Split(val, ",")
out := make([]int64, len(ss))
for i, d := range ss {
var err error
out[i], err = strconv.ParseInt(d, 0, 64)
if err != nil {
return nil, err
}
}
return out, nil
}
// GetInt64Slice return the []int64 value of a flag with the given name
func (f *FlagSet) GetInt64Slice(name string) ([]int64, error) {
val, err := f.getFlagType(name, "int64Slice", int64SliceConv)
if err != nil {
return []int64{}, err
}
return val.([]int64), nil
}
// Int64SliceVar defines a int64Slice flag with specified name, default value, and usage string.
// The argument p points to a []int64 variable in which to store the value of the flag.
func (f *FlagSet) Int64SliceVar(p *[]int64, name string, value []int64, usage string) {
f.VarP(newInt64SliceValue(value, p), name, "", usage)
}
// Int64SliceVarP is like Int64SliceVar, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) Int64SliceVarP(p *[]int64, name, shorthand string, value []int64, usage string) {
f.VarP(newInt64SliceValue(value, p), name, shorthand, usage)
}
// Int64SliceVar defines a int64[] flag with specified name, default value, and usage string.
// The argument p points to a int64[] variable in which to store the value of the flag.
func Int64SliceVar(p *[]int64, name string, value []int64, usage string) {
CommandLine.VarP(newInt64SliceValue(value, p), name, "", usage)
}
// Int64SliceVarP is like Int64SliceVar, but accepts a shorthand letter that can be used after a single dash.
func Int64SliceVarP(p *[]int64, name, shorthand string, value []int64, usage string) {
CommandLine.VarP(newInt64SliceValue(value, p), name, shorthand, usage)
}
// Int64Slice defines a []int64 flag with specified name, default value, and usage string.
// The return value is the address of a []int64 variable that stores the value of the flag.
func (f *FlagSet) Int64Slice(name string, value []int64, usage string) *[]int64 {
p := []int64{}
f.Int64SliceVarP(&p, name, "", value, usage)
return &p
}
// Int64SliceP is like Int64Slice, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) Int64SliceP(name, shorthand string, value []int64, usage string) *[]int64 {
p := []int64{}
f.Int64SliceVarP(&p, name, shorthand, value, usage)
return &p
}
// Int64Slice defines a []int64 flag with specified name, default value, and usage string.
// The return value is the address of a []int64 variable that stores the value of the flag.
func Int64Slice(name string, value []int64, usage string) *[]int64 {
return CommandLine.Int64SliceP(name, "", value, usage)
}
// Int64SliceP is like Int64Slice, but accepts a shorthand letter that can be used after a single dash.
func Int64SliceP(name, shorthand string, value []int64, usage string) *[]int64 {
return CommandLine.Int64SliceP(name, shorthand, value, usage)
}

View file

@ -51,6 +51,36 @@ func (s *intSliceValue) String() string {
return "[" + strings.Join(out, ",") + "]" return "[" + strings.Join(out, ",") + "]"
} }
func (s *intSliceValue) Append(val string) error {
i, err := strconv.Atoi(val)
if err != nil {
return err
}
*s.value = append(*s.value, i)
return nil
}
func (s *intSliceValue) Replace(val []string) error {
out := make([]int, len(val))
for i, d := range val {
var err error
out[i], err = strconv.Atoi(d)
if err != nil {
return err
}
}
*s.value = out
return nil
}
func (s *intSliceValue) GetSlice() []string {
out := make([]string, len(*s.value))
for i, d := range *s.value {
out[i] = strconv.Itoa(d)
}
return out
}
func intSliceConv(val string) (interface{}, error) { func intSliceConv(val string) (interface{}, error) {
val = strings.Trim(val, "[]") val = strings.Trim(val, "[]")
// Empty string would cause a slice with one (empty) entry // Empty string would cause a slice with one (empty) entry

View file

@ -72,9 +72,47 @@ func (s *ipSliceValue) String() string {
return "[" + out + "]" return "[" + out + "]"
} }
func (s *ipSliceValue) fromString(val string) (net.IP, error) {
return net.ParseIP(strings.TrimSpace(val)), nil
}
func (s *ipSliceValue) toString(val net.IP) string {
return val.String()
}
func (s *ipSliceValue) Append(val string) error {
i, err := s.fromString(val)
if err != nil {
return err
}
*s.value = append(*s.value, i)
return nil
}
func (s *ipSliceValue) Replace(val []string) error {
out := make([]net.IP, len(val))
for i, d := range val {
var err error
out[i], err = s.fromString(d)
if err != nil {
return err
}
}
*s.value = out
return nil
}
func (s *ipSliceValue) GetSlice() []string {
out := make([]string, len(*s.value))
for i, d := range *s.value {
out[i] = s.toString(d)
}
return out
}
func ipSliceConv(val string) (interface{}, error) { func ipSliceConv(val string) (interface{}, error) {
val = strings.Trim(val, "[]") val = strings.Trim(val, "[]")
// Emtpy string would cause a slice with one (empty) entry // Empty string would cause a slice with one (empty) entry
if len(val) == 0 { if len(val) == 0 {
return []net.IP{}, nil return []net.IP{}, nil
} }

View file

@ -23,6 +23,32 @@ func (s *stringArrayValue) Set(val string) error {
return nil return nil
} }
func (s *stringArrayValue) Append(val string) error {
*s.value = append(*s.value, val)
return nil
}
func (s *stringArrayValue) Replace(val []string) error {
out := make([]string, len(val))
for i, d := range val {
var err error
out[i] = d
if err != nil {
return err
}
}
*s.value = out
return nil
}
func (s *stringArrayValue) GetSlice() []string {
out := make([]string, len(*s.value))
for i, d := range *s.value {
out[i] = d
}
return out
}
func (s *stringArrayValue) Type() string { func (s *stringArrayValue) Type() string {
return "stringArray" return "stringArray"
} }

View file

@ -62,6 +62,20 @@ func (s *stringSliceValue) String() string {
return "[" + str + "]" return "[" + str + "]"
} }
func (s *stringSliceValue) Append(val string) error {
*s.value = append(*s.value, val)
return nil
}
func (s *stringSliceValue) Replace(val []string) error {
*s.value = val
return nil
}
func (s *stringSliceValue) GetSlice() []string {
return *s.value
}
func stringSliceConv(sval string) (interface{}, error) { func stringSliceConv(sval string) (interface{}, error) {
sval = sval[1 : len(sval)-1] sval = sval[1 : len(sval)-1]
// An empty string would cause a slice with one (empty) string // An empty string would cause a slice with one (empty) string
@ -84,7 +98,7 @@ func (f *FlagSet) GetStringSlice(name string) ([]string, error) {
// The argument p points to a []string variable in which to store the value of the flag. // The argument p points to a []string variable in which to store the value of the flag.
// Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly. // Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly.
// For example: // For example:
// --ss="v1,v2" -ss="v3" // --ss="v1,v2" --ss="v3"
// will result in // will result in
// []string{"v1", "v2", "v3"} // []string{"v1", "v2", "v3"}
func (f *FlagSet) StringSliceVar(p *[]string, name string, value []string, usage string) { func (f *FlagSet) StringSliceVar(p *[]string, name string, value []string, usage string) {
@ -100,7 +114,7 @@ func (f *FlagSet) StringSliceVarP(p *[]string, name, shorthand string, value []s
// The argument p points to a []string variable in which to store the value of the flag. // The argument p points to a []string variable in which to store the value of the flag.
// Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly. // Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly.
// For example: // For example:
// --ss="v1,v2" -ss="v3" // --ss="v1,v2" --ss="v3"
// will result in // will result in
// []string{"v1", "v2", "v3"} // []string{"v1", "v2", "v3"}
func StringSliceVar(p *[]string, name string, value []string, usage string) { func StringSliceVar(p *[]string, name string, value []string, usage string) {
@ -116,7 +130,7 @@ func StringSliceVarP(p *[]string, name, shorthand string, value []string, usage
// The return value is the address of a []string variable that stores the value of the flag. // The return value is the address of a []string variable that stores the value of the flag.
// Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly. // Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly.
// For example: // For example:
// --ss="v1,v2" -ss="v3" // --ss="v1,v2" --ss="v3"
// will result in // will result in
// []string{"v1", "v2", "v3"} // []string{"v1", "v2", "v3"}
func (f *FlagSet) StringSlice(name string, value []string, usage string) *[]string { func (f *FlagSet) StringSlice(name string, value []string, usage string) *[]string {
@ -136,7 +150,7 @@ func (f *FlagSet) StringSliceP(name, shorthand string, value []string, usage str
// The return value is the address of a []string variable that stores the value of the flag. // The return value is the address of a []string variable that stores the value of the flag.
// Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly. // Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly.
// For example: // For example:
// --ss="v1,v2" -ss="v3" // --ss="v1,v2" --ss="v3"
// will result in // will result in
// []string{"v1", "v2", "v3"} // []string{"v1", "v2", "v3"}
func StringSlice(name string, value []string, usage string) *[]string { func StringSlice(name string, value []string, usage string) *[]string {

149
vendor/github.com/spf13/pflag/string_to_int.go generated vendored Normal file
View file

@ -0,0 +1,149 @@
package pflag
import (
"bytes"
"fmt"
"strconv"
"strings"
)
// -- stringToInt Value
type stringToIntValue struct {
value *map[string]int
changed bool
}
func newStringToIntValue(val map[string]int, p *map[string]int) *stringToIntValue {
ssv := new(stringToIntValue)
ssv.value = p
*ssv.value = val
return ssv
}
// Format: a=1,b=2
func (s *stringToIntValue) Set(val string) error {
ss := strings.Split(val, ",")
out := make(map[string]int, len(ss))
for _, pair := range ss {
kv := strings.SplitN(pair, "=", 2)
if len(kv) != 2 {
return fmt.Errorf("%s must be formatted as key=value", pair)
}
var err error
out[kv[0]], err = strconv.Atoi(kv[1])
if err != nil {
return err
}
}
if !s.changed {
*s.value = out
} else {
for k, v := range out {
(*s.value)[k] = v
}
}
s.changed = true
return nil
}
func (s *stringToIntValue) Type() string {
return "stringToInt"
}
func (s *stringToIntValue) String() string {
var buf bytes.Buffer
i := 0
for k, v := range *s.value {
if i > 0 {
buf.WriteRune(',')
}
buf.WriteString(k)
buf.WriteRune('=')
buf.WriteString(strconv.Itoa(v))
i++
}
return "[" + buf.String() + "]"
}
func stringToIntConv(val string) (interface{}, error) {
val = strings.Trim(val, "[]")
// An empty string would cause an empty map
if len(val) == 0 {
return map[string]int{}, nil
}
ss := strings.Split(val, ",")
out := make(map[string]int, len(ss))
for _, pair := range ss {
kv := strings.SplitN(pair, "=", 2)
if len(kv) != 2 {
return nil, fmt.Errorf("%s must be formatted as key=value", pair)
}
var err error
out[kv[0]], err = strconv.Atoi(kv[1])
if err != nil {
return nil, err
}
}
return out, nil
}
// GetStringToInt return the map[string]int value of a flag with the given name
func (f *FlagSet) GetStringToInt(name string) (map[string]int, error) {
val, err := f.getFlagType(name, "stringToInt", stringToIntConv)
if err != nil {
return map[string]int{}, err
}
return val.(map[string]int), nil
}
// StringToIntVar defines a string flag with specified name, default value, and usage string.
// The argument p points to a map[string]int variable in which to store the values of the multiple flags.
// The value of each argument will not try to be separated by comma
func (f *FlagSet) StringToIntVar(p *map[string]int, name string, value map[string]int, usage string) {
f.VarP(newStringToIntValue(value, p), name, "", usage)
}
// StringToIntVarP is like StringToIntVar, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) StringToIntVarP(p *map[string]int, name, shorthand string, value map[string]int, usage string) {
f.VarP(newStringToIntValue(value, p), name, shorthand, usage)
}
// StringToIntVar defines a string flag with specified name, default value, and usage string.
// The argument p points to a map[string]int variable in which to store the value of the flag.
// The value of each argument will not try to be separated by comma
func StringToIntVar(p *map[string]int, name string, value map[string]int, usage string) {
CommandLine.VarP(newStringToIntValue(value, p), name, "", usage)
}
// StringToIntVarP is like StringToIntVar, but accepts a shorthand letter that can be used after a single dash.
func StringToIntVarP(p *map[string]int, name, shorthand string, value map[string]int, usage string) {
CommandLine.VarP(newStringToIntValue(value, p), name, shorthand, usage)
}
// StringToInt defines a string flag with specified name, default value, and usage string.
// The return value is the address of a map[string]int variable that stores the value of the flag.
// The value of each argument will not try to be separated by comma
func (f *FlagSet) StringToInt(name string, value map[string]int, usage string) *map[string]int {
p := map[string]int{}
f.StringToIntVarP(&p, name, "", value, usage)
return &p
}
// StringToIntP is like StringToInt, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) StringToIntP(name, shorthand string, value map[string]int, usage string) *map[string]int {
p := map[string]int{}
f.StringToIntVarP(&p, name, shorthand, value, usage)
return &p
}
// StringToInt defines a string flag with specified name, default value, and usage string.
// The return value is the address of a map[string]int variable that stores the value of the flag.
// The value of each argument will not try to be separated by comma
func StringToInt(name string, value map[string]int, usage string) *map[string]int {
return CommandLine.StringToIntP(name, "", value, usage)
}
// StringToIntP is like StringToInt, but accepts a shorthand letter that can be used after a single dash.
func StringToIntP(name, shorthand string, value map[string]int, usage string) *map[string]int {
return CommandLine.StringToIntP(name, shorthand, value, usage)
}

149
vendor/github.com/spf13/pflag/string_to_int64.go generated vendored Normal file
View file

@ -0,0 +1,149 @@
package pflag
import (
"bytes"
"fmt"
"strconv"
"strings"
)
// -- stringToInt64 Value
type stringToInt64Value struct {
value *map[string]int64
changed bool
}
func newStringToInt64Value(val map[string]int64, p *map[string]int64) *stringToInt64Value {
ssv := new(stringToInt64Value)
ssv.value = p
*ssv.value = val
return ssv
}
// Format: a=1,b=2
func (s *stringToInt64Value) Set(val string) error {
ss := strings.Split(val, ",")
out := make(map[string]int64, len(ss))
for _, pair := range ss {
kv := strings.SplitN(pair, "=", 2)
if len(kv) != 2 {
return fmt.Errorf("%s must be formatted as key=value", pair)
}
var err error
out[kv[0]], err = strconv.ParseInt(kv[1], 10, 64)
if err != nil {
return err
}
}
if !s.changed {
*s.value = out
} else {
for k, v := range out {
(*s.value)[k] = v
}
}
s.changed = true
return nil
}
func (s *stringToInt64Value) Type() string {
return "stringToInt64"
}
func (s *stringToInt64Value) String() string {
var buf bytes.Buffer
i := 0
for k, v := range *s.value {
if i > 0 {
buf.WriteRune(',')
}
buf.WriteString(k)
buf.WriteRune('=')
buf.WriteString(strconv.FormatInt(v, 10))
i++
}
return "[" + buf.String() + "]"
}
func stringToInt64Conv(val string) (interface{}, error) {
val = strings.Trim(val, "[]")
// An empty string would cause an empty map
if len(val) == 0 {
return map[string]int64{}, nil
}
ss := strings.Split(val, ",")
out := make(map[string]int64, len(ss))
for _, pair := range ss {
kv := strings.SplitN(pair, "=", 2)
if len(kv) != 2 {
return nil, fmt.Errorf("%s must be formatted as key=value", pair)
}
var err error
out[kv[0]], err = strconv.ParseInt(kv[1], 10, 64)
if err != nil {
return nil, err
}
}
return out, nil
}
// GetStringToInt64 return the map[string]int64 value of a flag with the given name
func (f *FlagSet) GetStringToInt64(name string) (map[string]int64, error) {
val, err := f.getFlagType(name, "stringToInt64", stringToInt64Conv)
if err != nil {
return map[string]int64{}, err
}
return val.(map[string]int64), nil
}
// StringToInt64Var defines a string flag with specified name, default value, and usage string.
// The argument p point64s to a map[string]int64 variable in which to store the values of the multiple flags.
// The value of each argument will not try to be separated by comma
func (f *FlagSet) StringToInt64Var(p *map[string]int64, name string, value map[string]int64, usage string) {
f.VarP(newStringToInt64Value(value, p), name, "", usage)
}
// StringToInt64VarP is like StringToInt64Var, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) StringToInt64VarP(p *map[string]int64, name, shorthand string, value map[string]int64, usage string) {
f.VarP(newStringToInt64Value(value, p), name, shorthand, usage)
}
// StringToInt64Var defines a string flag with specified name, default value, and usage string.
// The argument p point64s to a map[string]int64 variable in which to store the value of the flag.
// The value of each argument will not try to be separated by comma
func StringToInt64Var(p *map[string]int64, name string, value map[string]int64, usage string) {
CommandLine.VarP(newStringToInt64Value(value, p), name, "", usage)
}
// StringToInt64VarP is like StringToInt64Var, but accepts a shorthand letter that can be used after a single dash.
func StringToInt64VarP(p *map[string]int64, name, shorthand string, value map[string]int64, usage string) {
CommandLine.VarP(newStringToInt64Value(value, p), name, shorthand, usage)
}
// StringToInt64 defines a string flag with specified name, default value, and usage string.
// The return value is the address of a map[string]int64 variable that stores the value of the flag.
// The value of each argument will not try to be separated by comma
func (f *FlagSet) StringToInt64(name string, value map[string]int64, usage string) *map[string]int64 {
p := map[string]int64{}
f.StringToInt64VarP(&p, name, "", value, usage)
return &p
}
// StringToInt64P is like StringToInt64, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) StringToInt64P(name, shorthand string, value map[string]int64, usage string) *map[string]int64 {
p := map[string]int64{}
f.StringToInt64VarP(&p, name, shorthand, value, usage)
return &p
}
// StringToInt64 defines a string flag with specified name, default value, and usage string.
// The return value is the address of a map[string]int64 variable that stores the value of the flag.
// The value of each argument will not try to be separated by comma
func StringToInt64(name string, value map[string]int64, usage string) *map[string]int64 {
return CommandLine.StringToInt64P(name, "", value, usage)
}
// StringToInt64P is like StringToInt64, but accepts a shorthand letter that can be used after a single dash.
func StringToInt64P(name, shorthand string, value map[string]int64, usage string) *map[string]int64 {
return CommandLine.StringToInt64P(name, shorthand, value, usage)
}

160
vendor/github.com/spf13/pflag/string_to_string.go generated vendored Normal file
View file

@ -0,0 +1,160 @@
package pflag
import (
"bytes"
"encoding/csv"
"fmt"
"strings"
)
// -- stringToString Value
type stringToStringValue struct {
value *map[string]string
changed bool
}
func newStringToStringValue(val map[string]string, p *map[string]string) *stringToStringValue {
ssv := new(stringToStringValue)
ssv.value = p
*ssv.value = val
return ssv
}
// Format: a=1,b=2
func (s *stringToStringValue) Set(val string) error {
var ss []string
n := strings.Count(val, "=")
switch n {
case 0:
return fmt.Errorf("%s must be formatted as key=value", val)
case 1:
ss = append(ss, strings.Trim(val, `"`))
default:
r := csv.NewReader(strings.NewReader(val))
var err error
ss, err = r.Read()
if err != nil {
return err
}
}
out := make(map[string]string, len(ss))
for _, pair := range ss {
kv := strings.SplitN(pair, "=", 2)
if len(kv) != 2 {
return fmt.Errorf("%s must be formatted as key=value", pair)
}
out[kv[0]] = kv[1]
}
if !s.changed {
*s.value = out
} else {
for k, v := range out {
(*s.value)[k] = v
}
}
s.changed = true
return nil
}
func (s *stringToStringValue) Type() string {
return "stringToString"
}
func (s *stringToStringValue) String() string {
records := make([]string, 0, len(*s.value)>>1)
for k, v := range *s.value {
records = append(records, k+"="+v)
}
var buf bytes.Buffer
w := csv.NewWriter(&buf)
if err := w.Write(records); err != nil {
panic(err)
}
w.Flush()
return "[" + strings.TrimSpace(buf.String()) + "]"
}
func stringToStringConv(val string) (interface{}, error) {
val = strings.Trim(val, "[]")
// An empty string would cause an empty map
if len(val) == 0 {
return map[string]string{}, nil
}
r := csv.NewReader(strings.NewReader(val))
ss, err := r.Read()
if err != nil {
return nil, err
}
out := make(map[string]string, len(ss))
for _, pair := range ss {
kv := strings.SplitN(pair, "=", 2)
if len(kv) != 2 {
return nil, fmt.Errorf("%s must be formatted as key=value", pair)
}
out[kv[0]] = kv[1]
}
return out, nil
}
// GetStringToString return the map[string]string value of a flag with the given name
func (f *FlagSet) GetStringToString(name string) (map[string]string, error) {
val, err := f.getFlagType(name, "stringToString", stringToStringConv)
if err != nil {
return map[string]string{}, err
}
return val.(map[string]string), nil
}
// StringToStringVar defines a string flag with specified name, default value, and usage string.
// The argument p points to a map[string]string variable in which to store the values of the multiple flags.
// The value of each argument will not try to be separated by comma
func (f *FlagSet) StringToStringVar(p *map[string]string, name string, value map[string]string, usage string) {
f.VarP(newStringToStringValue(value, p), name, "", usage)
}
// StringToStringVarP is like StringToStringVar, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) StringToStringVarP(p *map[string]string, name, shorthand string, value map[string]string, usage string) {
f.VarP(newStringToStringValue(value, p), name, shorthand, usage)
}
// StringToStringVar defines a string flag with specified name, default value, and usage string.
// The argument p points to a map[string]string variable in which to store the value of the flag.
// The value of each argument will not try to be separated by comma
func StringToStringVar(p *map[string]string, name string, value map[string]string, usage string) {
CommandLine.VarP(newStringToStringValue(value, p), name, "", usage)
}
// StringToStringVarP is like StringToStringVar, but accepts a shorthand letter that can be used after a single dash.
func StringToStringVarP(p *map[string]string, name, shorthand string, value map[string]string, usage string) {
CommandLine.VarP(newStringToStringValue(value, p), name, shorthand, usage)
}
// StringToString defines a string flag with specified name, default value, and usage string.
// The return value is the address of a map[string]string variable that stores the value of the flag.
// The value of each argument will not try to be separated by comma
func (f *FlagSet) StringToString(name string, value map[string]string, usage string) *map[string]string {
p := map[string]string{}
f.StringToStringVarP(&p, name, "", value, usage)
return &p
}
// StringToStringP is like StringToString, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) StringToStringP(name, shorthand string, value map[string]string, usage string) *map[string]string {
p := map[string]string{}
f.StringToStringVarP(&p, name, shorthand, value, usage)
return &p
}
// StringToString defines a string flag with specified name, default value, and usage string.
// The return value is the address of a map[string]string variable that stores the value of the flag.
// The value of each argument will not try to be separated by comma
func StringToString(name string, value map[string]string, usage string) *map[string]string {
return CommandLine.StringToStringP(name, "", value, usage)
}
// StringToStringP is like StringToString, but accepts a shorthand letter that can be used after a single dash.
func StringToStringP(name, shorthand string, value map[string]string, usage string) *map[string]string {
return CommandLine.StringToStringP(name, shorthand, value, usage)
}

View file

@ -50,6 +50,48 @@ func (s *uintSliceValue) String() string {
return "[" + strings.Join(out, ",") + "]" return "[" + strings.Join(out, ",") + "]"
} }
func (s *uintSliceValue) fromString(val string) (uint, error) {
t, err := strconv.ParseUint(val, 10, 0)
if err != nil {
return 0, err
}
return uint(t), nil
}
func (s *uintSliceValue) toString(val uint) string {
return fmt.Sprintf("%d", val)
}
func (s *uintSliceValue) Append(val string) error {
i, err := s.fromString(val)
if err != nil {
return err
}
*s.value = append(*s.value, i)
return nil
}
func (s *uintSliceValue) Replace(val []string) error {
out := make([]uint, len(val))
for i, d := range val {
var err error
out[i], err = s.fromString(d)
if err != nil {
return err
}
}
*s.value = out
return nil
}
func (s *uintSliceValue) GetSlice() []string {
out := make([]string, len(*s.value))
for i, d := range *s.value {
out[i] = s.toString(d)
}
return out
}
func uintSliceConv(val string) (interface{}, error) { func uintSliceConv(val string) (interface{}, error) {
val = strings.Trim(val, "[]") val = strings.Trim(val, "[]")
// Empty string would cause a slice with one (empty) entry // Empty string would cause a slice with one (empty) entry