Bump spf13/cobra to v0.0.3, spf13/pflag to v1.0.1

Use a tagged release of Cobra

Relevant changes:

- spf13/cobra#567 Add `CalledAs` method to cobra.Command
- spf13/cobra#580 Update error message for missing required flags
- spf13/cobra#584 Add support for --version flag
- spf13/cobra#614 If user has a project in symlink, just use its destination folder and work there
- spf13/cobra#649 terminates the flags when -- is found in commandline
- spf13/cobra#662 Add support for ignoring parse errors
- spf13/cobra#686 doc: hide hidden parent flags

Also various improvements were added for generating Bash
completion scripts (currently not used by us)

Bump spf13/pflag to v1.0.1

Relevant changes:

- spf13/pflag#122 DurationSlice: implementation and tests
- spf13/pflag#115 Implement BytesHex type of argument
- spf13/pflag#150 Add uintSlice and boolSlice to name prettifier
- spf13/pflag#155 Add multiline wrapping support
- spf13/pflag#158 doc: clarify difference between string slice vs. array
- spf13/pflag#160 add ability to ignore unknown flags
- spf13/pflag#163 Allow Users To Show Deprecated Flags

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn 2018-05-18 22:27:23 +02:00
parent 824ce49aff
commit 0acb2522bd
No known key found for this signature in database
GPG Key ID: 76698F39D527CE8C
14 changed files with 618 additions and 121 deletions

View File

@ -64,8 +64,8 @@ github.com/PuerkitoBio/urlesc 5bd2802263f21d8788851d5305584c82a5c75d7e
github.com/russross/blackfriday 1d6b8e9301e720b08a8938b8c25c018285885438 github.com/russross/blackfriday 1d6b8e9301e720b08a8938b8c25c018285885438
github.com/shurcooL/sanitized_anchor_name 10ef21a441db47d8b13ebcc5fd2310f636973c77 github.com/shurcooL/sanitized_anchor_name 10ef21a441db47d8b13ebcc5fd2310f636973c77
github.com/sirupsen/logrus v1.0.3 github.com/sirupsen/logrus v1.0.3
github.com/spf13/cobra 34ceca591bcf34a17a8b7bad5b3ce5f9c165bee5 github.com/spf13/cobra v0.0.3
github.com/spf13/pflag 97afa5e7ca8a08a383cb259e06636b5e2cc7897f github.com/spf13/pflag v1.0.1
github.com/theupdateframework/notary v0.6.1 github.com/theupdateframework/notary v0.6.1
github.com/tonistiigi/fsutil dea3a0da73aee887fc02142d995be764106ac5e2 github.com/tonistiigi/fsutil dea3a0da73aee887fc02142d995be764106ac5e2
github.com/xeipuuv/gojsonpointer e0fe6f68307607d540ed8eac07a342c33fa1b54a github.com/xeipuuv/gojsonpointer e0fe6f68307607d540ed8eac07a342c33fa1b54a

View File

@ -20,6 +20,7 @@ Many of the most widely used Go projects are built using Cobra including:
* [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)
[![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) [![CircleCI status](https://circleci.com/gh/spf13/cobra.png?circle-token=:circle-token "CircleCI status")](https://circleci.com/gh/spf13/cobra)
@ -158,10 +159,7 @@ import (
) )
func main() { func main() {
if err := cmd.RootCmd.Execute(); err != nil { cmd.Execute()
fmt.Println(err)
os.Exit(1)
}
} }
``` ```
@ -174,7 +172,7 @@ commands you want. It's the easiest way to incorporate Cobra into your applicati
## Using the Cobra Library ## Using the Cobra Library
To manually implement Cobra you need to create a bare main.go file and a RootCmd file. To manually implement Cobra you need to create a bare main.go file and a rootCmd file.
You will optionally provide additional commands as you see fit. You will optionally provide additional commands as you see fit.
### Create rootCmd ### Create rootCmd
@ -184,7 +182,7 @@ Cobra doesn't require any special constructors. Simply create your commands.
Ideally you place this in app/cmd/root.go: Ideally you place this in app/cmd/root.go:
```go ```go
var RootCmd = &cobra.Command{ var rootCmd = &cobra.Command{
Use: "hugo", Use: "hugo",
Short: "Hugo is a very fast static site generator", Short: "Hugo is a very fast static site generator",
Long: `A Fast and Flexible Static Site Generator built with Long: `A Fast and Flexible Static Site Generator built with
@ -194,6 +192,13 @@ var RootCmd = &cobra.Command{
// Do Stuff Here // Do Stuff Here
}, },
} }
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
``` ```
You will additionally define flags and handle configuration in your init() function. You will additionally define flags and handle configuration in your init() function.
@ -212,14 +217,14 @@ import (
func init() { func init() {
cobra.OnInitialize(initConfig) cobra.OnInitialize(initConfig)
RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)") 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().StringVarP(&projectBase, "projectbase", "b", "", "base project directory eg. github.com/spf13/")
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 (can provide `licensetext` in config)")
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("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")
} }
@ -267,10 +272,7 @@ import (
) )
func main() { func main() {
if err := cmd.RootCmd.Execute(); err != nil { cmd.Execute()
fmt.Println(err)
os.Exit(1)
}
} }
``` ```
@ -286,12 +288,13 @@ populate it with the following:
package cmd package cmd
import ( import (
"github.com/spf13/cobra"
"fmt" "fmt"
"github.com/spf13/cobra"
) )
func init() { func init() {
RootCmd.AddCommand(versionCmd) rootCmd.AddCommand(versionCmd)
} }
var versionCmd = &cobra.Command{ var versionCmd = &cobra.Command{
@ -328,7 +331,7 @@ command it's assigned to as well as every command under that command. For
global flags, assign a flag as a persistent flag on the root. global flags, assign a flag as a persistent flag on the root.
```go ```go
RootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output") rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output")
``` ```
### Local Flags ### Local Flags
@ -336,13 +339,13 @@ 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") rootCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from")
``` ```
### Local Flag on Parent Commands ### Local Flag on Parent Commands
By default Cobra only parses local flags on the target command, any local flags on By default Cobra only parses local flags on the target command, any local flags on
parent commands are ignored. By enabling `Command.TraverseChildren` Cobra will parent commands are ignored. By enabling `Command.TraverseChildren` Cobra will
parse local flags on each command before executing the target command. parse local flags on each command before executing the target command.
```go ```go
@ -359,8 +362,8 @@ You can also bind your flags with [viper](https://github.com/spf13/viper):
var author string var author string
func init() { func init() {
RootCmd.PersistentFlags().StringVar(&author, "author", "YOUR NAME", "Author name for copyright attribution") rootCmd.PersistentFlags().StringVar(&author, "author", "YOUR NAME", "Author name for copyright attribution")
viper.BindPFlag("author", RootCmd.PersistentFlags().Lookup("author")) viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author"))
} }
``` ```
@ -370,6 +373,15 @@ when the `--author` flag is not provided by user.
More in [viper documentation](https://github.com/spf13/viper#working-with-flags). More in [viper documentation](https://github.com/spf13/viper#working-with-flags).
### Required flags
Flags are optional by default. If instead you wish your command to report an error
when a flag has not been set, mark it as required:
```go
rootCmd.Flags().StringVarP(&Region, "region", "r", "", "AWS region (required)")
rootCmd.MarkFlagRequired("region")
```
## Positional and Custom Arguments ## Positional and Custom Arguments
Validation of positional arguments can be specified using the `Args` field Validation of positional arguments can be specified using the `Args` field
@ -565,6 +577,13 @@ cmd.SetUsageFunc(f func(*Command) error)
cmd.SetUsageTemplate(s string) cmd.SetUsageTemplate(s string)
``` ```
## Version Flag
Cobra adds a top-level '--version' flag if the Version field is set on the root command.
Running an application with the '--version' flag will print the version to stdout using
the version template. The template can be customized using the
`cmd.SetVersionTemplate(s string)` function.
## PreRun and PostRun Hooks ## PreRun and PostRun Hooks
It is possible to run functions before or after the main `Run` function of your command. The `PersistentPreRun` and `PreRun` functions will be executed before `Run`. `PersistentPostRun` and `PostRun` will be executed after `Run`. The `Persistent*Run` functions will be inherited by children if they do not declare their own. These functions are run in the following order: It is possible to run functions before or after the main `Run` function of your command. The `PersistentPreRun` and `PreRun` functions will be executed before `Run`. `PersistentPostRun` and `PostRun` will be executed after `Run`. The `Persistent*Run` functions will be inherited by children if they do not declare their own. These functions are run in the following order:

View File

@ -21,8 +21,8 @@ const (
func writePreamble(buf *bytes.Buffer, name string) { func writePreamble(buf *bytes.Buffer, name string) {
buf.WriteString(fmt.Sprintf("# bash completion for %-36s -*- shell-script -*-\n", name)) buf.WriteString(fmt.Sprintf("# bash completion for %-36s -*- shell-script -*-\n", name))
buf.WriteString(` buf.WriteString(fmt.Sprintf(`
__debug() __%[1]s_debug()
{ {
if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then
echo "$*" >> "${BASH_COMP_DEBUG_FILE}" echo "$*" >> "${BASH_COMP_DEBUG_FILE}"
@ -31,13 +31,13 @@ __debug()
# Homebrew on Macs have version 1.3 of bash-completion which doesn't include # Homebrew on Macs have version 1.3 of bash-completion which doesn't include
# _init_completion. This is a very minimal version of that function. # _init_completion. This is a very minimal version of that function.
__my_init_completion() __%[1]s_init_completion()
{ {
COMPREPLY=() COMPREPLY=()
_get_comp_words_by_ref "$@" cur prev words cword _get_comp_words_by_ref "$@" cur prev words cword
} }
__index_of_word() __%[1]s_index_of_word()
{ {
local w word=$1 local w word=$1
shift shift
@ -49,7 +49,7 @@ __index_of_word()
index=-1 index=-1
} }
__contains_word() __%[1]s_contains_word()
{ {
local w word=$1; shift local w word=$1; shift
for w in "$@"; do for w in "$@"; do
@ -58,9 +58,9 @@ __contains_word()
return 1 return 1
} }
__handle_reply() __%[1]s_handle_reply()
{ {
__debug "${FUNCNAME[0]}" __%[1]s_debug "${FUNCNAME[0]}"
case $cur in case $cur in
-*) -*)
if [[ $(type -t compopt) = "builtin" ]]; then if [[ $(type -t compopt) = "builtin" ]]; then
@ -85,7 +85,7 @@ __handle_reply()
local index flag local index flag
flag="${cur%%=*}" flag="${cur%%=*}"
__index_of_word "${flag}" "${flags_with_completion[@]}" __%[1]s_index_of_word "${flag}" "${flags_with_completion[@]}"
COMPREPLY=() COMPREPLY=()
if [[ ${index} -ge 0 ]]; then if [[ ${index} -ge 0 ]]; then
PREFIX="" PREFIX=""
@ -103,7 +103,7 @@ __handle_reply()
# check if we are handling a flag with special work handling # check if we are handling a flag with special work handling
local index local index
__index_of_word "${prev}" "${flags_with_completion[@]}" __%[1]s_index_of_word "${prev}" "${flags_with_completion[@]}"
if [[ ${index} -ge 0 ]]; then if [[ ${index} -ge 0 ]]; then
${flags_completion[${index}]} ${flags_completion[${index}]}
return return
@ -136,24 +136,30 @@ __handle_reply()
if declare -F __ltrim_colon_completions >/dev/null; then if declare -F __ltrim_colon_completions >/dev/null; then
__ltrim_colon_completions "$cur" __ltrim_colon_completions "$cur"
fi fi
# If there is only 1 completion and it is a flag with an = it will be completed
# but we don't want a space after the =
if [[ "${#COMPREPLY[@]}" -eq "1" ]] && [[ $(type -t compopt) = "builtin" ]] && [[ "${COMPREPLY[0]}" == --*= ]]; then
compopt -o nospace
fi
} }
# The arguments should be in the form "ext1|ext2|extn" # The arguments should be in the form "ext1|ext2|extn"
__handle_filename_extension_flag() __%[1]s_handle_filename_extension_flag()
{ {
local ext="$1" local ext="$1"
_filedir "@(${ext})" _filedir "@(${ext})"
} }
__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
} }
__handle_flag() __%[1]s_handle_flag()
{ {
__debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" __%[1]s_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
# if a command required a flag, and we found it, unset must_have_one_flag() # if a command required a flag, and we found it, unset must_have_one_flag()
local flagname=${words[c]} local flagname=${words[c]}
@ -164,27 +170,30 @@ __handle_flag()
flagname=${flagname%%=*} # strip everything after the = flagname=${flagname%%=*} # strip everything after the =
flagname="${flagname}=" # but put the = back flagname="${flagname}=" # but put the = back
fi fi
__debug "${FUNCNAME[0]}: looking for ${flagname}" __%[1]s_debug "${FUNCNAME[0]}: looking for ${flagname}"
if __contains_word "${flagname}" "${must_have_one_flag[@]}"; then if __%[1]s_contains_word "${flagname}" "${must_have_one_flag[@]}"; then
must_have_one_flag=() must_have_one_flag=()
fi fi
# if you set a flag which only applies to this command, don't show subcommands # if you set a flag which only applies to this command, don't show subcommands
if __contains_word "${flagname}" "${local_nonpersistent_flags[@]}"; then if __%[1]s_contains_word "${flagname}" "${local_nonpersistent_flags[@]}"; then
commands=() commands=()
fi fi
# keep flag value with flagname as flaghash # keep flag value with flagname as flaghash
if [ -n "${flagvalue}" ] ; then # flaghash variable is an associative array which is only supported in bash > 3.
flaghash[${flagname}]=${flagvalue} if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then
elif [ -n "${words[ $((c+1)) ]}" ] ; then if [ -n "${flagvalue}" ] ; then
flaghash[${flagname}]=${words[ $((c+1)) ]} flaghash[${flagname}]=${flagvalue}
else elif [ -n "${words[ $((c+1)) ]}" ] ; then
flaghash[${flagname}]="true" # pad "true" for bool flag flaghash[${flagname}]=${words[ $((c+1)) ]}
else
flaghash[${flagname}]="true" # pad "true" for bool flag
fi
fi fi
# skip the argument to a two word flag # skip the argument to a two word flag
if __contains_word "${words[c]}" "${two_word_flags[@]}"; then if __%[1]s_contains_word "${words[c]}" "${two_word_flags[@]}"; then
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
@ -196,13 +205,13 @@ __handle_flag()
} }
__handle_noun() __%[1]s_handle_noun()
{ {
__debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" __%[1]s_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
if __contains_word "${words[c]}" "${must_have_one_noun[@]}"; then if __%[1]s_contains_word "${words[c]}" "${must_have_one_noun[@]}"; then
must_have_one_noun=() must_have_one_noun=()
elif __contains_word "${words[c]}" "${noun_aliases[@]}"; then elif __%[1]s_contains_word "${words[c]}" "${noun_aliases[@]}"; then
must_have_one_noun=() must_have_one_noun=()
fi fi
@ -210,45 +219,53 @@ __handle_noun()
c=$((c+1)) c=$((c+1))
} }
__handle_command() __%[1]s_handle_command()
{ {
__debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" __%[1]s_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
local next_command local next_command
if [[ -n ${last_command} ]]; then if [[ -n ${last_command} ]]; then
next_command="_${last_command}_${words[c]//:/__}" next_command="_${last_command}_${words[c]//:/__}"
else else
if [[ $c -eq 0 ]]; then if [[ $c -eq 0 ]]; then
next_command="_$(basename "${words[c]//:/__}")" next_command="_%[1]s_root_command"
else else
next_command="_${words[c]//:/__}" next_command="_${words[c]//:/__}"
fi fi
fi fi
c=$((c+1)) c=$((c+1))
__debug "${FUNCNAME[0]}: looking for ${next_command}" __%[1]s_debug "${FUNCNAME[0]}: looking for ${next_command}"
declare -F "$next_command" >/dev/null && $next_command declare -F "$next_command" >/dev/null && $next_command
} }
__handle_word() __%[1]s_handle_word()
{ {
if [[ $c -ge $cword ]]; then if [[ $c -ge $cword ]]; then
__handle_reply __%[1]s_handle_reply
return return
fi fi
__debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" __%[1]s_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
if [[ "${words[c]}" == -* ]]; then if [[ "${words[c]}" == -* ]]; then
__handle_flag __%[1]s_handle_flag
elif __contains_word "${words[c]}" "${commands[@]}"; then elif __%[1]s_contains_word "${words[c]}" "${commands[@]}"; then
__handle_command __%[1]s_handle_command
elif [[ $c -eq 0 ]] && __contains_word "$(basename "${words[c]}")" "${commands[@]}"; then elif [[ $c -eq 0 ]]; then
__handle_command __%[1]s_handle_command
elif __%[1]s_contains_word "${words[c]}" "${command_aliases[@]}"; then
# aliashash variable is an associative array which is only supported in bash > 3.
if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then
words[c]=${aliashash[${words[c]}]}
__%[1]s_handle_command
else
__%[1]s_handle_noun
fi
else else
__handle_noun __%[1]s_handle_noun
fi fi
__handle_word __%[1]s_handle_word
} }
`) `, name))
} }
func writePostscript(buf *bytes.Buffer, name string) { func writePostscript(buf *bytes.Buffer, name string) {
@ -257,10 +274,11 @@ func writePostscript(buf *bytes.Buffer, name string) {
buf.WriteString(fmt.Sprintf(`{ buf.WriteString(fmt.Sprintf(`{
local cur prev words cword local cur prev words cword
declare -A flaghash 2>/dev/null || : declare -A flaghash 2>/dev/null || :
declare -A aliashash 2>/dev/null || :
if declare -F _init_completion >/dev/null 2>&1; then if declare -F _init_completion >/dev/null 2>&1; then
_init_completion -s || return _init_completion -s || return
else else
__my_init_completion -n "=" || return __%[1]s_init_completion -n "=" || return
fi fi
local c=0 local c=0
@ -269,13 +287,13 @@ func writePostscript(buf *bytes.Buffer, name string) {
local local_nonpersistent_flags=() local local_nonpersistent_flags=()
local flags_with_completion=() local flags_with_completion=()
local flags_completion=() local flags_completion=()
local commands=("%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 last_command local last_command
local nouns=() local nouns=()
__handle_word __%[1]s_handle_word
} }
`, name)) `, name))
@ -296,11 +314,12 @@ func writeCommands(buf *bytes.Buffer, cmd *Command) {
continue continue
} }
buf.WriteString(fmt.Sprintf(" commands+=(%q)\n", c.Name())) buf.WriteString(fmt.Sprintf(" commands+=(%q)\n", c.Name()))
writeCmdAliases(buf, c)
} }
buf.WriteString("\n") buf.WriteString("\n")
} }
func writeFlagHandler(buf *bytes.Buffer, name string, annotations map[string][]string) { func writeFlagHandler(buf *bytes.Buffer, name string, annotations map[string][]string, cmd *Command) {
for key, value := range annotations { for key, value := range annotations {
switch key { switch key {
case BashCompFilenameExt: case BashCompFilenameExt:
@ -308,7 +327,7 @@ func writeFlagHandler(buf *bytes.Buffer, name string, annotations map[string][]s
var ext string var ext string
if len(value) > 0 { if len(value) > 0 {
ext = "__handle_filename_extension_flag " + strings.Join(value, "|") ext = fmt.Sprintf("__%s_handle_filename_extension_flag ", cmd.Root().Name()) + strings.Join(value, "|")
} else { } else {
ext = "_filedir" ext = "_filedir"
} }
@ -326,7 +345,7 @@ func writeFlagHandler(buf *bytes.Buffer, name string, annotations map[string][]s
var ext string var ext string
if len(value) == 1 { if len(value) == 1 {
ext = "__handle_subdirs_in_dir_flag " + value[0] ext = fmt.Sprintf("__%s_handle_subdirs_in_dir_flag ", cmd.Root().Name()) + value[0]
} else { } else {
ext = "_filedir -d" ext = "_filedir -d"
} }
@ -335,7 +354,7 @@ func writeFlagHandler(buf *bytes.Buffer, name string, annotations map[string][]s
} }
} }
func writeShortFlag(buf *bytes.Buffer, flag *pflag.Flag) { func writeShortFlag(buf *bytes.Buffer, flag *pflag.Flag, cmd *Command) {
name := flag.Shorthand name := flag.Shorthand
format := " " format := " "
if len(flag.NoOptDefVal) == 0 { if len(flag.NoOptDefVal) == 0 {
@ -343,10 +362,10 @@ func writeShortFlag(buf *bytes.Buffer, flag *pflag.Flag) {
} }
format += "flags+=(\"-%s\")\n" format += "flags+=(\"-%s\")\n"
buf.WriteString(fmt.Sprintf(format, name)) buf.WriteString(fmt.Sprintf(format, name))
writeFlagHandler(buf, "-"+name, flag.Annotations) writeFlagHandler(buf, "-"+name, flag.Annotations, cmd)
} }
func writeFlag(buf *bytes.Buffer, flag *pflag.Flag) { func writeFlag(buf *bytes.Buffer, flag *pflag.Flag, cmd *Command) {
name := flag.Name name := flag.Name
format := " flags+=(\"--%s" format := " flags+=(\"--%s"
if len(flag.NoOptDefVal) == 0 { if len(flag.NoOptDefVal) == 0 {
@ -354,7 +373,7 @@ func writeFlag(buf *bytes.Buffer, flag *pflag.Flag) {
} }
format += "\")\n" format += "\")\n"
buf.WriteString(fmt.Sprintf(format, name)) buf.WriteString(fmt.Sprintf(format, name))
writeFlagHandler(buf, "--"+name, flag.Annotations) writeFlagHandler(buf, "--"+name, flag.Annotations, cmd)
} }
func writeLocalNonPersistentFlag(buf *bytes.Buffer, flag *pflag.Flag) { func writeLocalNonPersistentFlag(buf *bytes.Buffer, flag *pflag.Flag) {
@ -380,9 +399,9 @@ func writeFlags(buf *bytes.Buffer, cmd *Command) {
if nonCompletableFlag(flag) { if nonCompletableFlag(flag) {
return return
} }
writeFlag(buf, flag) writeFlag(buf, flag, cmd)
if len(flag.Shorthand) > 0 { if len(flag.Shorthand) > 0 {
writeShortFlag(buf, flag) writeShortFlag(buf, flag, cmd)
} }
if localNonPersistentFlags.Lookup(flag.Name) != nil { if localNonPersistentFlags.Lookup(flag.Name) != nil {
writeLocalNonPersistentFlag(buf, flag) writeLocalNonPersistentFlag(buf, flag)
@ -392,9 +411,9 @@ func writeFlags(buf *bytes.Buffer, cmd *Command) {
if nonCompletableFlag(flag) { if nonCompletableFlag(flag) {
return return
} }
writeFlag(buf, flag) writeFlag(buf, flag, cmd)
if len(flag.Shorthand) > 0 { if len(flag.Shorthand) > 0 {
writeShortFlag(buf, flag) writeShortFlag(buf, flag, cmd)
} }
}) })
@ -434,6 +453,21 @@ func writeRequiredNouns(buf *bytes.Buffer, cmd *Command) {
} }
} }
func writeCmdAliases(buf *bytes.Buffer, cmd *Command) {
if len(cmd.Aliases) == 0 {
return
}
sort.Sort(sort.StringSlice(cmd.Aliases))
buf.WriteString(fmt.Sprint(` if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then`, "\n"))
for _, value := range cmd.Aliases {
buf.WriteString(fmt.Sprintf(" command_aliases+=(%q)\n", value))
buf.WriteString(fmt.Sprintf(" aliashash[%q]=%q\n", value, cmd.Name()))
}
buf.WriteString(` fi`)
buf.WriteString("\n")
}
func writeArgAliases(buf *bytes.Buffer, cmd *Command) { func writeArgAliases(buf *bytes.Buffer, cmd *Command) {
buf.WriteString(" noun_aliases=()\n") buf.WriteString(" noun_aliases=()\n")
sort.Sort(sort.StringSlice(cmd.ArgAliases)) sort.Sort(sort.StringSlice(cmd.ArgAliases))
@ -452,8 +486,18 @@ func gen(buf *bytes.Buffer, cmd *Command) {
commandName := cmd.CommandPath() commandName := cmd.CommandPath()
commandName = strings.Replace(commandName, " ", "_", -1) commandName = strings.Replace(commandName, " ", "_", -1)
commandName = strings.Replace(commandName, ":", "__", -1) commandName = strings.Replace(commandName, ":", "__", -1)
buf.WriteString(fmt.Sprintf("_%s()\n{\n", commandName))
if cmd.Root() == cmd {
buf.WriteString(fmt.Sprintf("_%s_root_command()\n{\n", commandName))
} else {
buf.WriteString(fmt.Sprintf("_%s()\n{\n", commandName))
}
buf.WriteString(fmt.Sprintf(" last_command=%q\n", commandName)) buf.WriteString(fmt.Sprintf(" last_command=%q\n", commandName))
buf.WriteString("\n")
buf.WriteString(" command_aliases=()\n")
buf.WriteString("\n")
writeCommands(buf, cmd) writeCommands(buf, cmd)
writeFlags(buf, cmd) writeFlags(buf, cmd)
writeRequiredFlag(buf, cmd) writeRequiredFlag(buf, cmd)
@ -491,17 +535,20 @@ 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. // 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 { func (c *Command) MarkFlagRequired(name string) error {
return MarkFlagRequired(c.Flags(), name) return MarkFlagRequired(c.Flags(), name)
} }
// MarkPersistentFlagRequired adds the BashCompOneRequiredFlag annotation to the named persistent flag, if it exists. // 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 { func (c *Command) MarkPersistentFlagRequired(name string) error {
return MarkFlagRequired(c.PersistentFlags(), name) return MarkFlagRequired(c.PersistentFlags(), name)
} }
// MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag in the flag set, if it exists. // 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 { func MarkFlagRequired(flags *pflag.FlagSet, name string) error {
return flags.SetAnnotation(name, BashCompOneRequiredFlag, []string{"true"}) return flags.SetAnnotation(name, BashCompOneRequiredFlag, []string{"true"})
} }

View File

@ -70,7 +70,8 @@ func AddTemplateFuncs(tmplFuncs template.FuncMap) {
} }
} }
// OnInitialize takes a series of func() arguments and appends them to a slice of func(). // OnInitialize sets the passed functions to be run when each command's
// Execute method is called.
func OnInitialize(y ...func()) { func OnInitialize(y ...func()) {
initializers = append(initializers, y...) initializers = append(initializers, y...)
} }

View File

@ -27,6 +27,9 @@ import (
flag "github.com/spf13/pflag" flag "github.com/spf13/pflag"
) )
// FParseErrWhitelist configures Flag parse errors to be ignored
type FParseErrWhitelist flag.ParseErrorsWhitelist
// Command is just that, a command for your application. // Command is just that, a command for your application.
// E.g. 'go run ...' - 'run' is the command. Cobra requires // E.g. 'go run ...' - 'run' is the command. Cobra requires
// you to define the usage and description as part of your command // you to define the usage and description as part of your command
@ -75,6 +78,11 @@ type Command struct {
// group commands. // group commands.
Annotations map[string]string Annotations map[string]string
// 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,
// will print content of the "Version" variable.
Version string
// The *Run functions are executed in the following order: // The *Run functions are executed in the following order:
// * PersistentPreRun() // * PersistentPreRun()
// * PreRun() // * PreRun()
@ -132,6 +140,9 @@ 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 FParseErrWhitelist
// 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.
@ -142,6 +153,11 @@ type Command struct {
commandsMaxNameLen int commandsMaxNameLen int
// commandsAreSorted defines, if command slice are sorted or not. // commandsAreSorted defines, if command slice are sorted or not.
commandsAreSorted bool commandsAreSorted bool
// commandCalledAs is the name or alias value used to call this command.
commandCalledAs struct {
name string
called bool
}
// args is actual args parsed from flags. // args is actual args parsed from flags.
args []string args []string
@ -177,6 +193,8 @@ type Command struct {
// helpCommand is command with usage 'help'. If it's not defined by user, // helpCommand is command with usage 'help'. If it's not defined by user,
// cobra uses default help command. // cobra uses default help command.
helpCommand *Command helpCommand *Command
// versionTemplate is the version template defined by user.
versionTemplate string
} }
// 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
@ -222,6 +240,11 @@ func (c *Command) SetHelpTemplate(s string) {
c.helpTemplate = s c.helpTemplate = s
} }
// SetVersionTemplate sets version template to be used. Application can use it to set custom template.
func (c *Command) SetVersionTemplate(s string) {
c.versionTemplate = s
}
// SetGlobalNormalizationFunc sets a normalization function to all flag sets and also to child commands. // SetGlobalNormalizationFunc sets a normalization function to all flag sets and also to child commands.
// The user should not have a cyclic dependency on commands. // The user should not have a cyclic dependency on commands.
func (c *Command) SetGlobalNormalizationFunc(n func(f *flag.FlagSet, name string) flag.NormalizedName) { func (c *Command) SetGlobalNormalizationFunc(n func(f *flag.FlagSet, name string) flag.NormalizedName) {
@ -411,6 +434,19 @@ func (c *Command) HelpTemplate() string {
{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}` {{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}`
} }
// VersionTemplate return version template for the command.
func (c *Command) VersionTemplate() string {
if c.versionTemplate != "" {
return c.versionTemplate
}
if c.HasParent() {
return c.parent.VersionTemplate()
}
return `{{with .Name}}{{printf "%s " .}}{{end}}{{printf "version %s" .Version}}
`
}
func hasNoOptDefVal(name string, fs *flag.FlagSet) bool { func hasNoOptDefVal(name string, fs *flag.FlagSet) bool {
flag := fs.Lookup(name) flag := fs.Lookup(name)
if flag == nil { if flag == nil {
@ -445,6 +481,9 @@ Loop:
s := args[0] s := args[0]
args = args[1:] args = args[1:]
switch { switch {
case s == "--":
// "--" terminates the flags
break Loop
case strings.HasPrefix(s, "--") && !strings.Contains(s, "=") && !hasNoOptDefVal(s[2:], flags): case strings.HasPrefix(s, "--") && !strings.Contains(s, "=") && !hasNoOptDefVal(s[2:], flags):
// If '--flag arg' then // If '--flag arg' then
// delete arg from args. // delete arg from args.
@ -532,6 +571,7 @@ func (c *Command) findNext(next string) *Command {
matches := make([]*Command, 0) matches := make([]*Command, 0)
for _, cmd := range c.commands { for _, cmd := range c.commands {
if cmd.Name() == next || cmd.HasAlias(next) { if cmd.Name() == next || cmd.HasAlias(next) {
cmd.commandCalledAs.name = next
return cmd return cmd
} }
if EnablePrefixMatching && cmd.hasNameOrAliasPrefix(next) { if EnablePrefixMatching && cmd.hasNameOrAliasPrefix(next) {
@ -542,6 +582,7 @@ func (c *Command) findNext(next string) *Command {
if len(matches) == 1 { if len(matches) == 1 {
return matches[0] return matches[0]
} }
return nil return nil
} }
@ -640,9 +681,10 @@ func (c *Command) execute(a []string) (err error) {
c.Printf("Command %q is deprecated, %s\n", c.Name(), c.Deprecated) c.Printf("Command %q is deprecated, %s\n", c.Name(), c.Deprecated)
} }
// initialize help flag as the last point possible to allow for user // initialize help and version flag at the last point possible to allow for user
// overriding // overriding
c.InitDefaultHelpFlag() c.InitDefaultHelpFlag()
c.InitDefaultVersionFlag()
err = c.ParseFlags(a) err = c.ParseFlags(a)
if err != nil { if err != nil {
@ -659,7 +701,27 @@ func (c *Command) execute(a []string) (err error) {
return err return err
} }
if helpVal || !c.Runnable() { if helpVal {
return flag.ErrHelp
}
// for back-compat, only add version flag behavior if version is defined
if c.Version != "" {
versionVal, err := c.Flags().GetBool("version")
if err != nil {
c.Println("\"version\" flag declared as non-bool. Please correct your code")
return err
}
if versionVal {
err := tmpl(c.OutOrStdout(), c.VersionTemplate(), c)
if err != nil {
c.Println(err)
}
return err
}
}
if !c.Runnable() {
return flag.ErrHelp return flag.ErrHelp
} }
@ -782,6 +844,11 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
return c, err return c, err
} }
cmd.commandCalledAs.called = true
if cmd.commandCalledAs.name == "" {
cmd.commandCalledAs.name = cmd.Name()
}
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
@ -827,7 +894,7 @@ func (c *Command) validateRequiredFlags() error {
}) })
if len(missingFlagNames) > 0 { if len(missingFlagNames) > 0 {
return fmt.Errorf(`Required flag(s) "%s" have/has not been set`, strings.Join(missingFlagNames, `", "`)) return fmt.Errorf(`required flag(s) "%s" not set`, strings.Join(missingFlagNames, `", "`))
} }
return nil return nil
} }
@ -848,6 +915,27 @@ func (c *Command) InitDefaultHelpFlag() {
} }
} }
// InitDefaultVersionFlag adds default version flag to c.
// It is called automatically by executing the c.
// If c already has a version flag, it will do nothing.
// If c.Version is empty, it will do nothing.
func (c *Command) InitDefaultVersionFlag() {
if c.Version == "" {
return
}
c.mergePersistentFlags()
if c.Flags().Lookup("version") == nil {
usage := "version for "
if c.Name() == "" {
usage += "this command"
} else {
usage += c.Name()
}
c.Flags().Bool("version", false, usage)
}
}
// InitDefaultHelpCmd adds default help command to c. // InitDefaultHelpCmd adds default help command to c.
// It is called automatically by executing the c or by calling help and usage. // It is called automatically by executing the c or by calling help and usage.
// If c already has help command or c has no subcommands, it will do nothing. // If c already has help command or c has no subcommands, it will do nothing.
@ -1068,14 +1156,25 @@ func (c *Command) HasAlias(s string) bool {
return false return false
} }
// CalledAs returns the command name or alias that was used to invoke
// this command or an empty string if the command has not been called.
func (c *Command) CalledAs() string {
if c.commandCalledAs.called {
return c.commandCalledAs.name
}
return ""
}
// hasNameOrAliasPrefix returns true if the Name or any of aliases start // hasNameOrAliasPrefix returns true if the Name or any of aliases start
// with prefix // with prefix
func (c *Command) hasNameOrAliasPrefix(prefix string) bool { func (c *Command) hasNameOrAliasPrefix(prefix string) bool {
if strings.HasPrefix(c.Name(), prefix) { if strings.HasPrefix(c.Name(), prefix) {
c.commandCalledAs.name = c.Name()
return true return true
} }
for _, alias := range c.Aliases { for _, alias := range c.Aliases {
if strings.HasPrefix(alias, prefix) { if strings.HasPrefix(alias, prefix) {
c.commandCalledAs.name = alias
return true return true
} }
} }
@ -1178,7 +1277,7 @@ func (c *Command) HasParent() bool {
return c.parent != nil return c.parent != nil
} }
// GlobalNormalizationFunc returns the global normalization function or nil if doesn't exists. // GlobalNormalizationFunc returns the global normalization function or nil if it doesn't exist.
func (c *Command) GlobalNormalizationFunc() func(f *flag.FlagSet, name string) flag.NormalizedName { func (c *Command) GlobalNormalizationFunc() func(f *flag.FlagSet, name string) flag.NormalizedName {
return c.globNormFunc return c.globNormFunc
} }
@ -1370,6 +1469,10 @@ 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
c.Flags().ParseErrorsWhitelist = flag.ParseErrorsWhitelist(c.FParseErrWhitelist)
err := c.Flags().Parse(args) err := c.Flags().Parse(args)
// Print warnings if they occurred (e.g. deprecated flag messages). // Print warnings if they occurred (e.g. deprecated flag messages).
if c.flagErrorBuf.Len()-beforeErrorBufLen > 0 && err == nil { if c.flagErrorBuf.Len()-beforeErrorBufLen > 0 && err == nil {

View File

@ -176,13 +176,13 @@ func manPrintFlags(buf *bytes.Buffer, flags *pflag.FlagSet) {
func manPrintOptions(buf *bytes.Buffer, command *cobra.Command) { func manPrintOptions(buf *bytes.Buffer, command *cobra.Command) {
flags := command.NonInheritedFlags() flags := command.NonInheritedFlags()
if flags.HasFlags() { if flags.HasAvailableFlags() {
buf.WriteString("# OPTIONS\n") buf.WriteString("# OPTIONS\n")
manPrintFlags(buf, flags) manPrintFlags(buf, flags)
buf.WriteString("\n") buf.WriteString("\n")
} }
flags = command.InheritedFlags() flags = command.InheritedFlags()
if flags.HasFlags() { if flags.HasAvailableFlags() {
buf.WriteString("# OPTIONS INHERITED FROM PARENT COMMANDS\n") buf.WriteString("# OPTIONS INHERITED FROM PARENT COMMANDS\n")
manPrintFlags(buf, flags) manPrintFlags(buf, flags)
buf.WriteString("\n") buf.WriteString("\n")

View File

@ -29,7 +29,7 @@ import (
func printOptions(buf *bytes.Buffer, cmd *cobra.Command, name string) error { func printOptions(buf *bytes.Buffer, cmd *cobra.Command, name string) error {
flags := cmd.NonInheritedFlags() flags := cmd.NonInheritedFlags()
flags.SetOutput(buf) flags.SetOutput(buf)
if flags.HasFlags() { if flags.HasAvailableFlags() {
buf.WriteString("### Options\n\n```\n") buf.WriteString("### Options\n\n```\n")
flags.PrintDefaults() flags.PrintDefaults()
buf.WriteString("```\n\n") buf.WriteString("```\n\n")
@ -37,7 +37,7 @@ func printOptions(buf *bytes.Buffer, cmd *cobra.Command, name string) error {
parentFlags := cmd.InheritedFlags() parentFlags := cmd.InheritedFlags()
parentFlags.SetOutput(buf) parentFlags.SetOutput(buf)
if parentFlags.HasFlags() { if parentFlags.HasAvailableFlags() {
buf.WriteString("### Options inherited from parent commands\n\n```\n") buf.WriteString("### Options inherited from parent commands\n\n```\n")
parentFlags.PrintDefaults() parentFlags.PrintDefaults()
buf.WriteString("```\n\n") buf.WriteString("```\n\n")
@ -67,7 +67,7 @@ func GenMarkdownCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string)
buf.WriteString("## " + name + "\n\n") buf.WriteString("## " + name + "\n\n")
buf.WriteString(short + "\n\n") buf.WriteString(short + "\n\n")
buf.WriteString("### Synopsis\n\n") buf.WriteString("### Synopsis\n\n")
buf.WriteString("\n" + long + "\n\n") buf.WriteString(long + "\n\n")
if cmd.Runnable() { if cmd.Runnable() {
buf.WriteString(fmt.Sprintf("```\n%s\n```\n\n", cmd.UseLine())) buf.WriteString(fmt.Sprintf("```\n%s\n```\n\n", cmd.UseLine()))
@ -82,7 +82,7 @@ func GenMarkdownCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string)
return err return err
} }
if hasSeeAlso(cmd) { if hasSeeAlso(cmd) {
buf.WriteString("### SEE ALSO\n") buf.WriteString("### SEE ALSO\n\n")
if cmd.HasParent() { if cmd.HasParent() {
parent := cmd.Parent() parent := cmd.Parent()
pname := parent.CommandPath() pname := parent.CommandPath()

View File

@ -29,7 +29,7 @@ import (
func printOptionsReST(buf *bytes.Buffer, cmd *cobra.Command, name string) error { func printOptionsReST(buf *bytes.Buffer, cmd *cobra.Command, name string) error {
flags := cmd.NonInheritedFlags() flags := cmd.NonInheritedFlags()
flags.SetOutput(buf) flags.SetOutput(buf)
if flags.HasFlags() { if flags.HasAvailableFlags() {
buf.WriteString("Options\n") buf.WriteString("Options\n")
buf.WriteString("~~~~~~~\n\n::\n\n") buf.WriteString("~~~~~~~\n\n::\n\n")
flags.PrintDefaults() flags.PrintDefaults()
@ -38,7 +38,7 @@ func printOptionsReST(buf *bytes.Buffer, cmd *cobra.Command, name string) error
parentFlags := cmd.InheritedFlags() parentFlags := cmd.InheritedFlags()
parentFlags.SetOutput(buf) parentFlags.SetOutput(buf)
if parentFlags.HasFlags() { if parentFlags.HasAvailableFlags() {
buf.WriteString("Options inherited from parent commands\n") buf.WriteString("Options inherited from parent commands\n")
buf.WriteString("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n::\n\n") buf.WriteString("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n::\n\n")
parentFlags.PrintDefaults() parentFlags.PrintDefaults()

105
vendor/github.com/spf13/pflag/bytes.go generated vendored Normal file
View File

@ -0,0 +1,105 @@
package pflag
import (
"encoding/hex"
"fmt"
"strings"
)
// BytesHex adapts []byte for use as a flag. Value of flag is HEX encoded
type bytesHexValue []byte
func (bytesHex bytesHexValue) String() string {
return fmt.Sprintf("%X", []byte(bytesHex))
}
func (bytesHex *bytesHexValue) Set(value string) error {
bin, err := hex.DecodeString(strings.TrimSpace(value))
if err != nil {
return err
}
*bytesHex = bin
return nil
}
func (*bytesHexValue) Type() string {
return "bytesHex"
}
func newBytesHexValue(val []byte, p *[]byte) *bytesHexValue {
*p = val
return (*bytesHexValue)(p)
}
func bytesHexConv(sval string) (interface{}, error) {
bin, err := hex.DecodeString(sval)
if err == nil {
return bin, nil
}
return nil, fmt.Errorf("invalid string being converted to Bytes: %s %s", sval, err)
}
// GetBytesHex return the []byte value of a flag with the given name
func (f *FlagSet) GetBytesHex(name string) ([]byte, error) {
val, err := f.getFlagType(name, "bytesHex", bytesHexConv)
if err != nil {
return []byte{}, err
}
return val.([]byte), nil
}
// BytesHexVar 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) BytesHexVar(p *[]byte, name string, value []byte, usage string) {
f.VarP(newBytesHexValue(value, p), name, "", usage)
}
// BytesHexVarP is like BytesHexVar, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) BytesHexVarP(p *[]byte, name, shorthand string, value []byte, usage string) {
f.VarP(newBytesHexValue(value, p), name, shorthand, usage)
}
// BytesHexVar 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 BytesHexVar(p *[]byte, name string, value []byte, usage string) {
CommandLine.VarP(newBytesHexValue(value, p), name, "", usage)
}
// BytesHexVarP is like BytesHexVar, but accepts a shorthand letter that can be used after a single dash.
func BytesHexVarP(p *[]byte, name, shorthand string, value []byte, usage string) {
CommandLine.VarP(newBytesHexValue(value, p), name, shorthand, usage)
}
// BytesHex 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) BytesHex(name string, value []byte, usage string) *[]byte {
p := new([]byte)
f.BytesHexVarP(p, name, "", value, usage)
return p
}
// BytesHexP is like BytesHex, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) BytesHexP(name, shorthand string, value []byte, usage string) *[]byte {
p := new([]byte)
f.BytesHexVarP(p, name, shorthand, value, usage)
return p
}
// BytesHex 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 BytesHex(name string, value []byte, usage string) *[]byte {
return CommandLine.BytesHexP(name, "", value, usage)
}
// BytesHexP is like BytesHex, but accepts a shorthand letter that can be used after a single dash.
func BytesHexP(name, shorthand string, value []byte, usage string) *[]byte {
return CommandLine.BytesHexP(name, shorthand, value, usage)
}

128
vendor/github.com/spf13/pflag/duration_slice.go generated vendored Normal file
View File

@ -0,0 +1,128 @@
package pflag
import (
"fmt"
"strings"
"time"
)
// -- durationSlice Value
type durationSliceValue struct {
value *[]time.Duration
changed bool
}
func newDurationSliceValue(val []time.Duration, p *[]time.Duration) *durationSliceValue {
dsv := new(durationSliceValue)
dsv.value = p
*dsv.value = val
return dsv
}
func (s *durationSliceValue) Set(val string) error {
ss := strings.Split(val, ",")
out := make([]time.Duration, len(ss))
for i, d := range ss {
var err error
out[i], err = time.ParseDuration(d)
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 *durationSliceValue) Type() string {
return "durationSlice"
}
func (s *durationSliceValue) String() string {
out := make([]string, len(*s.value))
for i, d := range *s.value {
out[i] = fmt.Sprintf("%s", d)
}
return "[" + strings.Join(out, ",") + "]"
}
func durationSliceConv(val string) (interface{}, error) {
val = strings.Trim(val, "[]")
// Empty string would cause a slice with one (empty) entry
if len(val) == 0 {
return []time.Duration{}, nil
}
ss := strings.Split(val, ",")
out := make([]time.Duration, len(ss))
for i, d := range ss {
var err error
out[i], err = time.ParseDuration(d)
if err != nil {
return nil, err
}
}
return out, nil
}
// GetDurationSlice returns the []time.Duration value of a flag with the given name
func (f *FlagSet) GetDurationSlice(name string) ([]time.Duration, error) {
val, err := f.getFlagType(name, "durationSlice", durationSliceConv)
if err != nil {
return []time.Duration{}, err
}
return val.([]time.Duration), nil
}
// DurationSliceVar defines a durationSlice flag with specified name, default value, and usage string.
// The argument p points to a []time.Duration variable in which to store the value of the flag.
func (f *FlagSet) DurationSliceVar(p *[]time.Duration, name string, value []time.Duration, usage string) {
f.VarP(newDurationSliceValue(value, p), name, "", usage)
}
// DurationSliceVarP is like DurationSliceVar, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) DurationSliceVarP(p *[]time.Duration, name, shorthand string, value []time.Duration, usage string) {
f.VarP(newDurationSliceValue(value, p), name, shorthand, usage)
}
// DurationSliceVar defines a duration[] flag with specified name, default value, and usage string.
// The argument p points to a duration[] variable in which to store the value of the flag.
func DurationSliceVar(p *[]time.Duration, name string, value []time.Duration, usage string) {
CommandLine.VarP(newDurationSliceValue(value, p), name, "", usage)
}
// DurationSliceVarP is like DurationSliceVar, but accepts a shorthand letter that can be used after a single dash.
func DurationSliceVarP(p *[]time.Duration, name, shorthand string, value []time.Duration, usage string) {
CommandLine.VarP(newDurationSliceValue(value, p), name, shorthand, usage)
}
// DurationSlice defines a []time.Duration flag with specified name, default value, and usage string.
// The return value is the address of a []time.Duration variable that stores the value of the flag.
func (f *FlagSet) DurationSlice(name string, value []time.Duration, usage string) *[]time.Duration {
p := []time.Duration{}
f.DurationSliceVarP(&p, name, "", value, usage)
return &p
}
// DurationSliceP is like DurationSlice, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) DurationSliceP(name, shorthand string, value []time.Duration, usage string) *[]time.Duration {
p := []time.Duration{}
f.DurationSliceVarP(&p, name, shorthand, value, usage)
return &p
}
// DurationSlice defines a []time.Duration flag with specified name, default value, and usage string.
// The return value is the address of a []time.Duration variable that stores the value of the flag.
func DurationSlice(name string, value []time.Duration, usage string) *[]time.Duration {
return CommandLine.DurationSliceP(name, "", value, usage)
}
// DurationSliceP is like DurationSlice, but accepts a shorthand letter that can be used after a single dash.
func DurationSliceP(name, shorthand string, value []time.Duration, usage string) *[]time.Duration {
return CommandLine.DurationSliceP(name, shorthand, value, usage)
}

102
vendor/github.com/spf13/pflag/flag.go generated vendored
View File

@ -101,6 +101,7 @@ package pflag
import ( import (
"bytes" "bytes"
"errors" "errors"
goflag "flag"
"fmt" "fmt"
"io" "io"
"os" "os"
@ -123,6 +124,12 @@ const (
PanicOnError PanicOnError
) )
// ParseErrorsWhitelist defines the parsing errors that can be ignored
type ParseErrorsWhitelist struct {
// UnknownFlags will ignore unknown flags errors and continue parsing rest of the flags
UnknownFlags bool
}
// NormalizedName is a flag name that has been normalized according to rules // NormalizedName is a flag name that has been normalized according to rules
// for the FlagSet (e.g. making '-' and '_' equivalent). // for the FlagSet (e.g. making '-' and '_' equivalent).
type NormalizedName string type NormalizedName string
@ -138,6 +145,9 @@ type FlagSet struct {
// help/usage messages. // help/usage messages.
SortFlags bool SortFlags bool
// ParseErrorsWhitelist is used to configure a whitelist of errors
ParseErrorsWhitelist ParseErrorsWhitelist
name string name string
parsed bool parsed bool
actual map[NormalizedName]*Flag actual map[NormalizedName]*Flag
@ -153,6 +163,8 @@ type FlagSet struct {
output io.Writer // nil means stderr; use out() accessor output io.Writer // nil means stderr; use out() accessor
interspersed bool // allow interspersed option/non-option args interspersed bool // allow interspersed option/non-option args
normalizeNameFunc func(f *FlagSet, name string) NormalizedName normalizeNameFunc func(f *FlagSet, name string) NormalizedName
addedGoFlagSets []*goflag.FlagSet
} }
// A Flag represents the state of a flag. // A Flag represents the state of a flag.
@ -267,16 +279,16 @@ func (f *FlagSet) VisitAll(fn func(*Flag)) {
} }
} }
// HasFlags returns a bool to indicate if the FlagSet has any flags definied. // HasFlags returns a bool to indicate if the FlagSet has any flags defined.
func (f *FlagSet) HasFlags() bool { func (f *FlagSet) HasFlags() bool {
return len(f.formal) > 0 return len(f.formal) > 0
} }
// HasAvailableFlags returns a bool to indicate if the FlagSet has any flags // HasAvailableFlags returns a bool to indicate if the FlagSet has any flags
// definied that are not hidden or deprecated. // that are not hidden.
func (f *FlagSet) HasAvailableFlags() bool { func (f *FlagSet) HasAvailableFlags() bool {
for _, flag := range f.formal { for _, flag := range f.formal {
if !flag.Hidden && len(flag.Deprecated) == 0 { if !flag.Hidden {
return true return true
} }
} }
@ -386,6 +398,7 @@ func (f *FlagSet) MarkDeprecated(name string, usageMessage string) error {
return fmt.Errorf("deprecated message for flag %q must be set", name) return fmt.Errorf("deprecated message for flag %q must be set", name)
} }
flag.Deprecated = usageMessage flag.Deprecated = usageMessage
flag.Hidden = true
return nil return nil
} }
@ -568,6 +581,10 @@ func UnquoteUsage(flag *Flag) (name string, usage string) {
name = "strings" name = "strings"
case "intSlice": case "intSlice":
name = "ints" name = "ints"
case "uintSlice":
name = "uints"
case "boolSlice":
name = "bools"
} }
return return
@ -582,11 +599,14 @@ func wrapN(i, slop int, s string) (string, string) {
return s, "" return s, ""
} }
w := strings.LastIndexAny(s[:i], " \t") w := strings.LastIndexAny(s[:i], " \t\n")
if w <= 0 { if w <= 0 {
return s, "" return s, ""
} }
nlPos := strings.LastIndex(s[:i], "\n")
if nlPos > 0 && nlPos < w {
return s[:nlPos], s[nlPos+1:]
}
return s[:w], s[w+1:] return s[:w], s[w+1:]
} }
@ -595,7 +615,7 @@ func wrapN(i, slop int, s string) (string, string) {
// caller). Pass `w` == 0 to do no wrapping // caller). Pass `w` == 0 to do no wrapping
func wrap(i, w int, s string) string { func wrap(i, w int, s string) string {
if w == 0 { if w == 0 {
return s return strings.Replace(s, "\n", "\n"+strings.Repeat(" ", i), -1)
} }
// space between indent i and end of line width w into which // space between indent i and end of line width w into which
@ -613,7 +633,7 @@ func wrap(i, w int, s string) string {
} }
// If still not enough space then don't even try to wrap. // If still not enough space then don't even try to wrap.
if wrap < 24 { if wrap < 24 {
return s return strings.Replace(s, "\n", r, -1)
} }
// Try to avoid short orphan words on the final line, by // Try to avoid short orphan words on the final line, by
@ -625,14 +645,14 @@ func wrap(i, w int, s string) string {
// Handle first line, which is indented by the caller (or the // Handle first line, which is indented by the caller (or the
// special case above) // special case above)
l, s = wrapN(wrap, slop, s) l, s = wrapN(wrap, slop, s)
r = r + l r = r + strings.Replace(l, "\n", "\n"+strings.Repeat(" ", i), -1)
// Now wrap the rest // Now wrap the rest
for s != "" { for s != "" {
var t string var t string
t, s = wrapN(wrap, slop, s) t, s = wrapN(wrap, slop, s)
r = r + "\n" + strings.Repeat(" ", i) + t r = r + "\n" + strings.Repeat(" ", i) + strings.Replace(t, "\n", "\n"+strings.Repeat(" ", i), -1)
} }
return r return r
@ -649,7 +669,7 @@ func (f *FlagSet) FlagUsagesWrapped(cols int) string {
maxlen := 0 maxlen := 0
f.VisitAll(func(flag *Flag) { f.VisitAll(func(flag *Flag) {
if flag.Deprecated != "" || flag.Hidden { if flag.Hidden {
return return
} }
@ -696,6 +716,9 @@ func (f *FlagSet) FlagUsagesWrapped(cols int) string {
line += fmt.Sprintf(" (default %s)", flag.DefValue) line += fmt.Sprintf(" (default %s)", flag.DefValue)
} }
} }
if len(flag.Deprecated) != 0 {
line += fmt.Sprintf(" (DEPRECATED: %s)", flag.Deprecated)
}
lines = append(lines, line) lines = append(lines, line)
}) })
@ -892,6 +915,25 @@ func (f *FlagSet) usage() {
} }
} }
//--unknown (args will be empty)
//--unknown --next-flag ... (args will be --next-flag ...)
//--unknown arg ... (args will be arg ...)
func stripUnknownFlagValue(args []string) []string {
if len(args) == 0 {
//--unknown
return args
}
first := args[0]
if first[0] == '-' {
//--unknown --next-flag ...
return args
}
//--unknown arg ... (args will be arg ...)
return args[1:]
}
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) {
a = args a = args
name := s[2:] name := s[2:]
@ -903,13 +945,24 @@ func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []strin
split := strings.SplitN(name, "=", 2) split := strings.SplitN(name, "=", 2)
name = split[0] name = split[0]
flag, exists := f.formal[f.normalizeFlagName(name)] flag, exists := f.formal[f.normalizeFlagName(name)]
if !exists { if !exists {
if name == "help" { // special case for nice help message. switch {
case name == "help":
f.usage() f.usage()
return a, ErrHelp return a, ErrHelp
case f.ParseErrorsWhitelist.UnknownFlags:
// --unknown=unknownval arg ...
// we do not want to lose arg in this case
if len(split) >= 2 {
return a, nil
}
return stripUnknownFlagValue(a), nil
default:
err = f.failf("unknown flag: --%s", name)
return
} }
err = f.failf("unknown flag: --%s", name)
return
} }
var value string var value string
@ -947,13 +1000,25 @@ func (f *FlagSet) parseSingleShortArg(shorthands string, args []string, fn parse
flag, exists := f.shorthands[c] flag, exists := f.shorthands[c]
if !exists { if !exists {
if c == 'h' { // special case for nice help message. switch {
case c == 'h':
f.usage() f.usage()
err = ErrHelp err = ErrHelp
return return
case f.ParseErrorsWhitelist.UnknownFlags:
// '-f=arg arg ...'
// we do not want to lose arg in this case
if len(shorthands) > 2 && shorthands[1] == '=' {
outShorts = ""
return
}
outArgs = stripUnknownFlagValue(outArgs)
return
default:
err = f.failf("unknown shorthand flag: %q in -%s", c, shorthands)
return
} }
err = f.failf("unknown shorthand flag: %q in -%s", c, shorthands)
return
} }
var value string var value string
@ -1040,6 +1105,11 @@ func (f *FlagSet) parseArgs(args []string, fn parseFunc) (err error) {
// are defined and before flags are accessed by the program. // are defined and before flags are accessed by the program.
// The return value will be ErrHelp if -help was set but not defined. // The return value will be ErrHelp if -help was set but not defined.
func (f *FlagSet) Parse(arguments []string) error { func (f *FlagSet) Parse(arguments []string) error {
if f.addedGoFlagSets != nil {
for _, goFlagSet := range f.addedGoFlagSets {
goFlagSet.Parse(nil)
}
}
f.parsed = true f.parsed = true
if len(arguments) < 0 { if len(arguments) < 0 {

View File

@ -98,4 +98,8 @@ func (f *FlagSet) AddGoFlagSet(newSet *goflag.FlagSet) {
newSet.VisitAll(func(goflag *goflag.Flag) { newSet.VisitAll(func(goflag *goflag.Flag) {
f.AddGoFlag(goflag) f.AddGoFlag(goflag)
}) })
if f.addedGoFlagSets == nil {
f.addedGoFlagSets = make([]*goflag.FlagSet, 0)
}
f.addedGoFlagSets = append(f.addedGoFlagSets, newSet)
} }

View File

@ -52,7 +52,7 @@ func (f *FlagSet) GetStringArray(name string) ([]string, error) {
// StringArrayVar defines a string flag with specified name, default value, and usage string. // StringArrayVar defines a string flag with specified name, default value, and usage string.
// The argument p points to a []string variable in which to store the values of the multiple flags. // The argument p points to a []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 // The value of each argument will not try to be separated by comma. Use a StringSlice for that.
func (f *FlagSet) StringArrayVar(p *[]string, name string, value []string, usage string) { func (f *FlagSet) StringArrayVar(p *[]string, name string, value []string, usage string) {
f.VarP(newStringArrayValue(value, p), name, "", usage) f.VarP(newStringArrayValue(value, p), name, "", usage)
} }
@ -64,7 +64,7 @@ func (f *FlagSet) StringArrayVarP(p *[]string, name, shorthand string, value []s
// StringArrayVar defines a string flag with specified name, default value, and usage string. // StringArrayVar defines a string flag with specified name, default value, and usage string.
// 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.
// The value of each argument will not try to be separated by comma // The value of each argument will not try to be separated by comma. Use a StringSlice for that.
func StringArrayVar(p *[]string, name string, value []string, usage string) { func StringArrayVar(p *[]string, name string, value []string, usage string) {
CommandLine.VarP(newStringArrayValue(value, p), name, "", usage) CommandLine.VarP(newStringArrayValue(value, p), name, "", usage)
} }
@ -76,7 +76,7 @@ func StringArrayVarP(p *[]string, name, shorthand string, value []string, usage
// StringArray defines a string flag with specified name, default value, and usage string. // StringArray defines a string flag with specified name, default value, and usage string.
// 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.
// The value of each argument will not try to be separated by comma // The value of each argument will not try to be separated by comma. Use a StringSlice for that.
func (f *FlagSet) StringArray(name string, value []string, usage string) *[]string { func (f *FlagSet) StringArray(name string, value []string, usage string) *[]string {
p := []string{} p := []string{}
f.StringArrayVarP(&p, name, "", value, usage) f.StringArrayVarP(&p, name, "", value, usage)
@ -92,7 +92,7 @@ func (f *FlagSet) StringArrayP(name, shorthand string, value []string, usage str
// StringArray defines a string flag with specified name, default value, and usage string. // StringArray defines a string flag with specified name, default value, and usage string.
// 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.
// The value of each argument will not try to be separated by comma // The value of each argument will not try to be separated by comma. Use a StringSlice for that.
func StringArray(name string, value []string, usage string) *[]string { func StringArray(name string, value []string, usage string) *[]string {
return CommandLine.StringArrayP(name, "", value, usage) return CommandLine.StringArrayP(name, "", value, usage)
} }

View File

@ -82,6 +82,11 @@ func (f *FlagSet) GetStringSlice(name string) ([]string, error) {
// StringSliceVar defines a string flag with specified name, default value, and usage string. // StringSliceVar defines a string flag with specified name, default value, and usage string.
// 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.
// For example:
// --ss="v1,v2" -ss="v3"
// will result in
// []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) {
f.VarP(newStringSliceValue(value, p), name, "", usage) f.VarP(newStringSliceValue(value, p), name, "", usage)
} }
@ -93,6 +98,11 @@ func (f *FlagSet) StringSliceVarP(p *[]string, name, shorthand string, value []s
// StringSliceVar defines a string flag with specified name, default value, and usage string. // StringSliceVar defines a string flag with specified name, default value, and usage string.
// 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.
// For example:
// --ss="v1,v2" -ss="v3"
// will result in
// []string{"v1", "v2", "v3"}
func StringSliceVar(p *[]string, name string, value []string, usage string) { func StringSliceVar(p *[]string, name string, value []string, usage string) {
CommandLine.VarP(newStringSliceValue(value, p), name, "", usage) CommandLine.VarP(newStringSliceValue(value, p), name, "", usage)
} }
@ -104,6 +114,11 @@ func StringSliceVarP(p *[]string, name, shorthand string, value []string, usage
// StringSlice defines a string flag with specified name, default value, and usage string. // StringSlice defines a string flag with specified name, default value, and usage string.
// 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.
// For example:
// --ss="v1,v2" -ss="v3"
// will result in
// []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 {
p := []string{} p := []string{}
f.StringSliceVarP(&p, name, "", value, usage) f.StringSliceVarP(&p, name, "", value, usage)
@ -119,6 +134,11 @@ func (f *FlagSet) StringSliceP(name, shorthand string, value []string, usage str
// StringSlice defines a string flag with specified name, default value, and usage string. // StringSlice defines a string flag with specified name, default value, and usage string.
// 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.
// For example:
// --ss="v1,v2" -ss="v3"
// will result in
// []string{"v1", "v2", "v3"}
func StringSlice(name string, value []string, usage string) *[]string { func StringSlice(name string, value []string, usage string) *[]string {
return CommandLine.StringSliceP(name, "", value, usage) return CommandLine.StringSliceP(name, "", value, usage)
} }