Merge pull request #27855 from andreykurilin/cobra_update

Automatic merge from submit-queue

Update github.com/spf13/pflag and github.com/spf13/cobra

Update github.com/spf13/pflag and github.com/spf13/cobra
    
Update:
    github.com/spf13/cobra to f62e98d28ab7ad31d707ba837a966378465c7b57
    github.com/spf13/cobra/doc to f62e98d28ab7ad31d707ba837a966378465c7b57
    github.com/spf13/pflag to 1560c1005499d61b80f865c04d39ca7505bf7f0b

Closes issue #29852

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.kubernetes.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.kubernetes.io/reviews/kubernetes/kubernetes/27855)
<!-- Reviewable:end -->
This commit is contained in:
Kubernetes Submit Queue 2016-08-11 19:05:13 -07:00 committed by GitHub
commit ca92a205d9
15 changed files with 410 additions and 141 deletions

6
Godeps/Godeps.json generated
View File

@ -1989,15 +1989,15 @@
},
{
"ImportPath": "github.com/spf13/cobra",
"Rev": "4c05eb1145f16d0e6bb4a3e1b6d769f4713cb41f"
"Rev": "f62e98d28ab7ad31d707ba837a966378465c7b57"
},
{
"ImportPath": "github.com/spf13/cobra/doc",
"Rev": "4c05eb1145f16d0e6bb4a3e1b6d769f4713cb41f"
"Rev": "f62e98d28ab7ad31d707ba837a966378465c7b57"
},
{
"ImportPath": "github.com/spf13/pflag",
"Rev": "08b1a584251b5b62f458943640fc8ebd4d50aaa5"
"Rev": "1560c1005499d61b80f865c04d39ca7505bf7f0b"
},
{
"ImportPath": "github.com/stretchr/objx",

View File

@ -177,7 +177,7 @@ func TestServerHelp(t *testing.T) {
x := runFull(t, "hyperkube test1 --help")
assert.NoError(t, x.err)
assert.Contains(t, x.output, "A simple server named test1")
assert.Contains(t, x.output, "--help[=false]: help for hyperkube")
assert.Contains(t, x.output, "-h, --help help for hyperkube")
assert.NotContains(t, x.output, "test1 Run")
}
@ -185,7 +185,7 @@ func TestServerFlagsBad(t *testing.T) {
x := runFull(t, "hyperkube test1 --bad-flag")
assert.EqualError(t, x.err, "unknown flag: --bad-flag")
assert.Contains(t, x.output, "A simple server named test1")
assert.Contains(t, x.output, "--help[=false]: help for hyperkube")
assert.Contains(t, x.output, "-h, --help help for hyperkube")
assert.NotContains(t, x.output, "test1 Run")
}

View File

@ -125,7 +125,7 @@ func TestServerHelp(t *testing.T) {
x := runFull(t, "hyperkube test1 --help")
assert.NoError(t, x.err)
assert.Contains(t, x.output, "A simple server named test1")
assert.Contains(t, x.output, "--help[=false]: help for hyperkube")
assert.Contains(t, x.output, "-h, --help help for hyperkube")
assert.NotContains(t, x.output, "test1 Run")
}
@ -133,7 +133,7 @@ func TestServerFlagsBad(t *testing.T) {
x := runFull(t, "hyperkube test1 --bad-flag")
assert.EqualError(t, x.err, "unknown flag: --bad-flag")
assert.Contains(t, x.output, "A simple server named test1")
assert.Contains(t, x.output, "--help[=false]: help for hyperkube")
assert.Contains(t, x.output, "-h, --help help for hyperkube")
assert.NotContains(t, x.output, "test1 Run")
}

View File

@ -19,6 +19,18 @@ _cgo_export.*
_testmain.go
# Vim files https://github.com/github/gitignore/blob/master/Global/Vim.gitignore
# swap
[._]*.s[a-w][a-z]
[._]s[a-w][a-z]
# session
Session.vim
# temporary
.netrwhist
*~
# auto-generated tag files
tags
*.exe
cobra.test

View File

@ -1,9 +1,14 @@
language: go
go:
- 1.3.3
- 1.4.2
- 1.5.1
- 1.4.3
- 1.5.4
- 1.6.3
- tip
matrix:
allow_failures:
- go: tip
before_install:
- mkdir -p bin
- curl -Lso bin/shellcheck https://github.com/caarlos0/shellcheck-docker/releases/download/v0.4.3/shellcheck

View File

@ -22,6 +22,7 @@ Many of the most widely used Go projects are built using Cobra including:
[![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)
![cobra](https://cloud.githubusercontent.com/assets/173412/10911369/84832a8e-8212-11e5-9f82-cc96660a4794.gif)
@ -171,6 +172,12 @@ func main() {
Cobra provides its own program that will create your application and add any
commands you want. It's the easiest way to incorporate Cobra into your application.
In order to use the cobra command, compile it using the following command:
> go install github.com/spf13/cobra/cobra
This will create the cobra executable under your go path bin directory!
### cobra init
The `cobra init [yourApp]` command will create your initial application code
@ -226,13 +233,27 @@ The cobra generator will be easier to use if you provide a simple configuration
file which will help you eliminate providing a bunch of repeated information in
flags over and over.
an example ~/.cobra.yaml file:
An example ~/.cobra.yaml file:
```yaml
author: Steve Francia <spf@spf13.com>
license: MIT
```
You can specify no license by setting `license` to `none` or you can specify
a custom license:
```yaml
license:
header: This file is part of {{ .appName }}.
text: |
{{ .copyright }}
This is my license. There are many like it, but this one is mine.
My license is my best friend. It is my life. I must master it as I must
master my life.
```
## Manually implementing Cobra
To manually implement cobra you need to create a bare main.go file and a RootCmd file.

View File

@ -116,12 +116,12 @@ __handle_reply()
fi
local completions
if [[ ${#must_have_one_flag[@]} -ne 0 ]]; then
completions=("${must_have_one_flag[@]}")
elif [[ ${#must_have_one_noun[@]} -ne 0 ]]; then
completions=("${commands[@]}")
if [[ ${#must_have_one_noun[@]} -ne 0 ]]; then
completions=("${must_have_one_noun[@]}")
else
completions=("${commands[@]}")
fi
if [[ ${#must_have_one_flag[@]} -ne 0 ]]; then
completions+=("${must_have_one_flag[@]}")
fi
COMPREPLY=( $(compgen -W "${completions[*]}" -- "$cur") )
@ -167,6 +167,11 @@ __handle_flag()
must_have_one_flag=()
fi
# if you set a flag which only applies to this command, don't show subcommands
if __contains_word "${flagname}" "${local_nonpersistent_flags[@]}"; then
commands=()
fi
# keep flag value with flagname as flaghash
if [ -n "${flagvalue}" ] ; then
flaghash[${flagname}]=${flagvalue}
@ -263,6 +268,7 @@ func postscript(w io.Writer, name string) error {
local c=0
local flags=()
local two_word_flags=()
local local_nonpersistent_flags=()
local flags_with_completion=()
local flags_completion=()
local commands=("%s")
@ -360,7 +366,7 @@ func writeFlagHandler(name string, annotations map[string][]string, w io.Writer)
}
func writeShortFlag(flag *pflag.Flag, w io.Writer) error {
b := (flag.Value.Type() == "bool")
b := (len(flag.NoOptDefVal) > 0)
name := flag.Shorthand
format := " "
if !b {
@ -374,7 +380,7 @@ func writeShortFlag(flag *pflag.Flag, w io.Writer) error {
}
func writeFlag(flag *pflag.Flag, w io.Writer) error {
b := (flag.Value.Type() == "bool")
b := (len(flag.NoOptDefVal) > 0)
name := flag.Name
format := " flags+=(\"--%s"
if !b {
@ -387,9 +393,24 @@ func writeFlag(flag *pflag.Flag, w io.Writer) error {
return writeFlagHandler("--"+name, flag.Annotations, w)
}
func writeLocalNonPersistentFlag(flag *pflag.Flag, w io.Writer) error {
b := (len(flag.NoOptDefVal) > 0)
name := flag.Name
format := " local_nonpersistent_flags+=(\"--%s"
if !b {
format += "="
}
format += "\")\n"
if _, err := fmt.Fprintf(w, format, name); err != nil {
return err
}
return nil
}
func writeFlags(cmd *Command, w io.Writer) error {
_, err := fmt.Fprintf(w, ` flags=()
two_word_flags=()
local_nonpersistent_flags=()
flags_with_completion=()
flags_completion=()
@ -397,6 +418,7 @@ func writeFlags(cmd *Command, w io.Writer) error {
if err != nil {
return err
}
localNonPersistentFlags := cmd.LocalNonPersistentFlags()
var visitErr error
cmd.NonInheritedFlags().VisitAll(func(flag *pflag.Flag) {
if err := writeFlag(flag, w); err != nil {
@ -409,6 +431,12 @@ func writeFlags(cmd *Command, w io.Writer) error {
return
}
}
if localNonPersistentFlags.Lookup(flag.Name) != nil {
if err := writeLocalNonPersistentFlag(flag, w); err != nil {
visitErr = err
return
}
}
})
if visitErr != nil {
return visitErr

View File

@ -117,7 +117,7 @@ cmd := &cobra.Command{
```
The aliases are not shown to the user on tab completion, but they are accepted as valid nouns by
the completion aglorithm if entered manually, e.g. in:
the completion algorithm if entered manually, e.g. in:
```bash
# kubectl get rc [tab][tab]
@ -175,7 +175,7 @@ So while there are many other files in the CWD it only shows me subdirs and thos
# Specifiy custom flag completion
Similar to the filename completion and filtering usingn cobra.BashCompFilenameExt, you can specifiy
Similar to the filename completion and filtering using cobra.BashCompFilenameExt, you can specifiy
a custom flag completion function with cobra.BashCompCustom:
```go

View File

@ -41,6 +41,10 @@ var initializers []func()
// Set this to true to enable it
var EnablePrefixMatching = false
//EnableCommandSorting controls sorting of the slice of commands, which is turned on by default.
//To disable sorting, set it to false.
var EnableCommandSorting = true
//AddTemplateFunc adds a template function that's available to Usage and Help
//template generation.
func AddTemplateFunc(name string, tmplFunc interface{}) {

View File

@ -21,6 +21,7 @@ import (
"io"
"os"
"path/filepath"
"sort"
"strings"
flag "github.com/spf13/pflag"
@ -103,11 +104,13 @@ type Command struct {
commandsMaxUseLen int
commandsMaxCommandPathLen int
commandsMaxNameLen int
// is commands slice are sorted or not
commandsAreSorted bool
flagErrorBuf *bytes.Buffer
args []string // actual args parsed from flags
output *io.Writer // nil means stderr; use Out() method instead
output *io.Writer // out writer if set in SetOutput(w)
usageFunc func(*Command) error // Usage can be defined by application
usageTemplate string // Can be defined by Application
helpTemplate string // Can be defined by Application
@ -120,6 +123,9 @@ type Command struct {
DisableSuggestions bool
// If displaying suggestions, allows to set the minimum levenshtein distance to display, must be > 0
SuggestionsMinimumDistance int
// Disable the flag parsing. If this is true all flags will be passed to the command as arguments.
DisableFlagParsing bool
}
// os.Args[1:] by default, if desired, can be overridden
@ -128,25 +134,6 @@ func (c *Command) SetArgs(a []string) {
c.args = a
}
func (c *Command) getOut(def io.Writer) io.Writer {
if c.output != nil {
return *c.output
}
if c.HasParent() {
return c.parent.Out()
}
return def
}
func (c *Command) Out() io.Writer {
return c.getOut(os.Stderr)
}
func (c *Command) getOutOrStdout() io.Writer {
return c.getOut(os.Stdout)
}
// SetOutput sets the destination for usage and error messages.
// If output is nil, os.Stderr is used.
func (c *Command) SetOutput(output io.Writer) {
@ -189,6 +176,26 @@ func (c *Command) SetGlobalNormalizationFunc(n func(f *flag.FlagSet, name string
}
}
func (c *Command) OutOrStdout() io.Writer {
return c.getOut(os.Stdout)
}
func (c *Command) OutOrStderr() io.Writer {
return c.getOut(os.Stderr)
}
func (c *Command) getOut(def io.Writer) io.Writer {
if c.output != nil {
return *c.output
}
if c.HasParent() {
return c.parent.getOut(def)
}
return def
}
// UsageFunc returns either the function set by SetUsageFunc for this command
// or a parent, or it returns a default usage function
func (c *Command) UsageFunc() (f func(*Command) error) {
if c.usageFunc != nil {
return c.usageFunc
@ -198,16 +205,24 @@ func (c *Command) UsageFunc() (f func(*Command) error) {
return c.parent.UsageFunc()
}
return func(c *Command) error {
err := tmpl(c.Out(), c.UsageTemplate(), c)
c.mergePersistentFlags()
err := tmpl(c.OutOrStderr(), c.UsageTemplate(), c)
if err != nil {
fmt.Print(err)
c.Println(err)
}
return err
}
}
// Output the usage for the command
// Used when a user provides invalid input
// Can be defined by user by overriding UsageFunc
func (c *Command) Usage() error {
return c.UsageFunc()(c)
}
// HelpFunc returns either the function set by SetHelpFunc for this command
// or a parent, or it returns a function which calls c.Help()
// or a parent, or it returns a function with default help behavior
func (c *Command) HelpFunc() func(*Command, []string) {
cmd := c
for cmd != nil {
@ -217,13 +232,31 @@ func (c *Command) HelpFunc() func(*Command, []string) {
cmd = cmd.parent
}
return func(*Command, []string) {
err := c.Help()
c.mergePersistentFlags()
err := tmpl(c.OutOrStdout(), c.HelpTemplate(), c)
if err != nil {
c.Println(err)
}
}
}
// Output the help for the command
// Used when a user calls help [command]
// Can be defined by user by overriding HelpFunc
func (c *Command) Help() error {
c.HelpFunc()(c, []string{})
return nil
}
func (c *Command) UsageString() string {
tmpOutput := c.output
bb := new(bytes.Buffer)
c.SetOutput(bb)
c.Usage()
c.output = tmpOutput
return bb.String()
}
var minUsagePadding = 25
func (c *Command) UsagePadding() int {
@ -261,7 +294,7 @@ func (c *Command) UsageTemplate() string {
return c.parent.UsageTemplate()
}
return `Usage:{{if .Runnable}}
{{if .HasFlags}}{{appendIfNotPresent .UseLine "[flags]"}}{{else}}{{.UseLine}}{{end}}{{end}}{{if .HasSubCommands}}
{{if .HasAvailableFlags}}{{appendIfNotPresent .UseLine "[flags]"}}{{else}}{{.UseLine}}{{end}}{{end}}{{if .HasAvailableSubCommands}}
{{ .CommandPath}} [command]{{end}}{{if gt .Aliases 0}}
Aliases:
@ -272,16 +305,16 @@ Examples:
{{ .Example }}{{end}}{{ if .HasAvailableSubCommands}}
Available Commands:{{range .Commands}}{{if .IsAvailableCommand}}
{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{ if .HasLocalFlags}}
{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{ if .HasAvailableLocalFlags}}
Flags:
{{.LocalFlags.FlagUsages | trimRightSpace}}{{end}}{{ if .HasInheritedFlags}}
{{.LocalFlags.FlagUsages | trimRightSpace}}{{end}}{{ if .HasAvailableInheritedFlags}}
Global Flags:
{{.InheritedFlags.FlagUsages | trimRightSpace}}{{end}}{{if .HasHelpSubCommands}}
Additional help topics:{{range .Commands}}{{if .IsHelpCommand}}
{{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{ if .HasSubCommands }}
{{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{ if .HasAvailableSubCommands }}
Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}}
`
@ -531,12 +564,17 @@ func (c *Command) execute(a []string) (err error) {
c.Println("\"help\" flag declared as non-bool. Please correct your code")
return err
}
if helpVal || !c.Runnable() {
return flag.ErrHelp
}
c.preRun()
argWoFlags := c.Flags().Args()
if c.DisableFlagParsing {
argWoFlags = a
}
for p := c; p != nil; p = p.Parent() {
if p.PersistentPreRunE != nil {
@ -699,8 +737,7 @@ func (c *Command) initHelpCmd() {
c.Printf("Unknown help topic %#q.", args)
c.Root().Usage()
} else {
helpFunc := cmd.HelpFunc()
helpFunc(cmd, args)
cmd.Help()
}
},
}
@ -714,8 +751,20 @@ func (c *Command) ResetCommands() {
c.helpCommand = nil
}
//Commands returns a slice of child commands.
// Sorts commands by their names
type commandSorterByName []*Command
func (c commandSorterByName) Len() int { return len(c) }
func (c commandSorterByName) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c commandSorterByName) Less(i, j int) bool { return c[i].Name() < c[j].Name() }
// Commands returns a sorted slice of child commands.
func (c *Command) Commands() []*Command {
// do not sort commands if it already sorted or sorting was disabled
if EnableCommandSorting && !c.commandsAreSorted {
sort.Sort(commandSorterByName(c.commands))
c.commandsAreSorted = true
}
return c.commands
}
@ -744,10 +793,11 @@ func (c *Command) AddCommand(cmds ...*Command) {
x.SetGlobalNormalizationFunc(c.globNormFunc)
}
c.commands = append(c.commands, x)
c.commandsAreSorted = false
}
}
// AddCommand removes one or more commands from a parent command.
// RemoveCommand removes one or more commands from a parent command.
func (c *Command) RemoveCommand(cmds ...*Command) {
commands := []*Command{}
main:
@ -781,50 +831,23 @@ main:
}
}
// Print is a convenience method to Print to the defined output
// Print is a convenience method to Print to the defined output, fallback to Stderr if not set
func (c *Command) Print(i ...interface{}) {
fmt.Fprint(c.Out(), i...)
fmt.Fprint(c.OutOrStderr(), i...)
}
// Println is a convenience method to Println to the defined output
// Println is a convenience method to Println to the defined output, fallback to Stderr if not set
func (c *Command) Println(i ...interface{}) {
str := fmt.Sprintln(i...)
c.Print(str)
}
// Printf is a convenience method to Printf to the defined output
// Printf is a convenience method to Printf to the defined output, fallback to Stderr if not set
func (c *Command) Printf(format string, i ...interface{}) {
str := fmt.Sprintf(format, i...)
c.Print(str)
}
// Output the usage for the command
// Used when a user provides invalid input
// Can be defined by user by overriding UsageFunc
func (c *Command) Usage() error {
c.mergePersistentFlags()
err := c.UsageFunc()(c)
return err
}
// Output the help for the command
// Used when a user calls help [command]
// by the default HelpFunc in the commander
func (c *Command) Help() error {
c.mergePersistentFlags()
err := tmpl(c.getOutOrStdout(), c.HelpTemplate(), c)
return err
}
func (c *Command) UsageString() string {
tmpOutput := c.output
bb := new(bytes.Buffer)
c.SetOutput(bb)
c.Usage()
c.output = tmpOutput
return bb.String()
}
// CommandPath returns the full path to this command.
func (c *Command) CommandPath() string {
str := c.Name()
@ -1025,6 +1048,19 @@ func (c *Command) Flags() *flag.FlagSet {
return c.flags
}
// LocalNonPersistentFlags are flags specific to this command which will NOT persist to subcommands
func (c *Command) LocalNonPersistentFlags() *flag.FlagSet {
persistentFlags := c.PersistentFlags()
out := flag.NewFlagSet(c.Name(), flag.ContinueOnError)
c.LocalFlags().VisitAll(func(f *flag.Flag) {
if persistentFlags.Lookup(f.Name) == nil {
out.AddFlag(f)
}
})
return out
}
// Get the local FlagSet specifically set in the current command
func (c *Command) LocalFlags() *flag.FlagSet {
c.mergePersistentFlags()
@ -1114,10 +1150,34 @@ func (c *Command) HasLocalFlags() bool {
return c.LocalFlags().HasFlags()
}
// Does the command have flags inherited from its parent command
func (c *Command) HasInheritedFlags() bool {
return c.InheritedFlags().HasFlags()
}
// Does the command contain any flags (local plus persistent from the entire
// structure) which are not hidden or deprecated
func (c *Command) HasAvailableFlags() bool {
return c.Flags().HasAvailableFlags()
}
// Does the command contain persistent flags which are not hidden or deprecated
func (c *Command) HasAvailablePersistentFlags() bool {
return c.PersistentFlags().HasAvailableFlags()
}
// Does the command has flags specifically declared locally which are not hidden
// or deprecated
func (c *Command) HasAvailableLocalFlags() bool {
return c.LocalFlags().HasAvailableFlags()
}
// Does the command have flags inherited from its parent command which are
// not hidden or deprecated
func (c *Command) HasAvailableInheritedFlags() bool {
return c.InheritedFlags().HasAvailableFlags()
}
// Flag climbs up the command tree looking for matching flag
func (c *Command) Flag(name string) (flag *flag.Flag) {
flag = c.Flags().Lookup(name)
@ -1143,6 +1203,9 @@ func (c *Command) persistentFlag(name string) (flag *flag.Flag) {
// ParseFlags parses persistent flag tree & local flags
func (c *Command) ParseFlags(args []string) (err error) {
if c.DisableFlagParsing {
return nil
}
c.mergePersistentFlags()
err = c.Flags().Parse(args)
return

View File

@ -28,12 +28,23 @@ import (
"github.com/spf13/pflag"
)
// GenManTree will generate a man page for this command and all decendants
// GenManTree will generate a man page for this command and all descendants
// in the directory given. The header may be nil. This function may not work
// correctly if your command names have - in them. If you have `cmd` with two
// subcmds, `sub` and `sub-third`. And `sub` has a subcommand called `third`
// it is undefined which help output will be in the file `cmd-sub-third.1`.
func GenManTree(cmd *cobra.Command, header *GenManHeader, dir string) error {
return GenManTreeFromOpts(cmd, GenManTreeOptions{
Header: header,
Path: dir,
CommandSeparator: "_",
})
}
// GenManTreeFromOpts generates a man page for the command and all descendants.
// The pages are written to the opts.Path directory.
func GenManTreeFromOpts(cmd *cobra.Command, opts GenManTreeOptions) error {
header := opts.Header
if header == nil {
header = &GenManHeader{}
}
@ -41,28 +52,35 @@ func GenManTree(cmd *cobra.Command, header *GenManHeader, dir string) error {
if !c.IsAvailableCommand() || c.IsHelpCommand() {
continue
}
if err := GenManTree(c, header, dir); err != nil {
if err := GenManTreeFromOpts(c, opts); err != nil {
return err
}
}
needToResetTitle := header.Title == ""
section := "1"
if header.Section != "" {
section = header.Section
}
basename := strings.Replace(cmd.CommandPath(), " ", "_", -1) + ".1"
filename := filepath.Join(dir, basename)
separator := "_"
if opts.CommandSeparator != "" {
separator = opts.CommandSeparator
}
basename := strings.Replace(cmd.CommandPath(), " ", separator, -1)
filename := filepath.Join(opts.Path, basename + "." + section)
f, err := os.Create(filename)
if err != nil {
return err
}
defer f.Close()
if err := GenMan(cmd, header, f); err != nil {
return err
}
headerCopy := *header
return GenMan(cmd, &headerCopy, f)
}
if needToResetTitle {
header.Title = ""
}
return nil
type GenManTreeOptions struct {
Header *GenManHeader
Path string
CommandSeparator string
}
// GenManHeader is a lot like the .TH header at the start of man pages. These
@ -84,9 +102,10 @@ func GenMan(cmd *cobra.Command, header *GenManHeader, w io.Writer) error {
if header == nil {
header = &GenManHeader{}
}
fillHeader(header, cmd.CommandPath())
b := genMan(cmd, header)
final := mangen.Render(b)
_, err := w.Write(final)
_, err := w.Write(mangen.Render(b))
return err
}
@ -107,18 +126,22 @@ func fillHeader(header *GenManHeader, name string) {
}
}
func manPreamble(out io.Writer, header *GenManHeader, name, short, long string) {
dashName := strings.Replace(name, " ", "-", -1)
func manPreamble(out io.Writer, header *GenManHeader, cmd *cobra.Command, dashedName string) {
description := cmd.Long
if len(description) == 0 {
description = cmd.Short
}
fmt.Fprintf(out, `%% %s(%s)%s
%% %s
%% %s
# NAME
`, header.Title, header.Section, header.date, header.Source, header.Manual)
fmt.Fprintf(out, "%s \\- %s\n\n", dashName, short)
fmt.Fprintf(out, "%s \\- %s\n\n", dashedName, cmd.Short)
fmt.Fprintf(out, "# SYNOPSIS\n")
fmt.Fprintf(out, "**%s** [OPTIONS]\n\n", name)
fmt.Fprintf(out, "**%s**\n\n", cmd.UseLine())
fmt.Fprintf(out, "# DESCRIPTION\n")
fmt.Fprintf(out, "%s\n\n", long)
fmt.Fprintf(out, "%s\n\n", description)
}
func manPrintFlags(out io.Writer, flags *pflag.FlagSet) {
@ -127,10 +150,10 @@ func manPrintFlags(out io.Writer, flags *pflag.FlagSet) {
return
}
format := ""
if len(flag.Shorthand) > 0 {
format = "**-%s**, **--%s**"
if len(flag.Shorthand) > 0 && len(flag.ShorthandDeprecated) == 0 {
format = fmt.Sprintf("**-%s**, **--%s**", flag.Shorthand, flag.Name)
} else {
format = "%s**--%s**"
format = fmt.Sprintf("**--%s**", flag.Name)
}
if len(flag.NoOptDefVal) > 0 {
format = format + "["
@ -145,7 +168,7 @@ func manPrintFlags(out io.Writer, flags *pflag.FlagSet) {
format = format + "]"
}
format = format + "\n\t%s\n\n"
fmt.Fprintf(out, format, flag.Shorthand, flag.Name, flag.DefValue, flag.Usage)
fmt.Fprintf(out, format, flag.DefValue, flag.Usage)
})
}
@ -165,22 +188,12 @@ func manPrintOptions(out io.Writer, command *cobra.Command) {
}
func genMan(cmd *cobra.Command, header *GenManHeader) []byte {
// something like `rootcmd subcmd1 subcmd2`
commandName := cmd.CommandPath()
// something like `rootcmd-subcmd1-subcmd2`
dashCommandName := strings.Replace(commandName, " ", "-", -1)
fillHeader(header, commandName)
dashCommandName := strings.Replace(cmd.CommandPath(), " ", "-", -1)
buf := new(bytes.Buffer)
short := cmd.Short
long := cmd.Long
if len(long) == 0 {
long = short
}
manPreamble(buf, header, commandName, short, long)
manPreamble(buf, header, cmd, dashCommandName)
manPrintOptions(buf, cmd)
if len(cmd.Example) > 0 {
fmt.Fprintf(buf, "# EXAMPLE\n")

View File

@ -3,9 +3,8 @@ sudo: false
language: go
go:
- 1.3
- 1.4
- 1.5
- 1.5.4
- 1.6.3
- tip
install:
@ -14,5 +13,5 @@ install:
- go install ./...
script:
- verify/all.sh
- verify/all.sh -v
- go test ./...

View File

@ -85,7 +85,7 @@ fmt.Println("flagvar has value ", flagvar)
```
There are helpers function to get values later if you have the FlagSet but
it was difficult to keep up with all of the the flag pointers in your code.
it was difficult to keep up with all of the flag pointers in your code.
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
and it must be an int. GetString("flagname") will fail.
@ -244,6 +244,25 @@ It is possible to mark a flag as hidden, meaning it will still function as norma
flags.MarkHidden("secretFlag")
```
## Supporting Go flags when using pflag
In order to support flags defined using Go's `flag` package, they must be added to the `pflag` flagset. This is usually necessary
to support flags defined by third-party dependencies (e.g. `golang/glog`).
**Example**: You want to add the Go flags to the `CommandLine` flagset
```go
import (
goflag "flag"
flag "github.com/spf13/pflag"
)
var ip *int = flag.Int("flagname", 1234, "help message for flagname")
func main() {
flag.CommandLine.AddGoFlagSet(goflag.CommandLine)
flag.Parse()
}
```
## More info
You can see the full reference documentation of the pflag package

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

@ -242,6 +242,17 @@ func (f *FlagSet) HasFlags() bool {
return len(f.formal) > 0
}
// HasAvailableFlags returns a bool to indicate if the FlagSet has any flags
// definied that are not hidden or deprecated.
func (f *FlagSet) HasAvailableFlags() bool {
for _, flag := range f.formal {
if !flag.Hidden && len(flag.Deprecated) == 0 {
return true
}
}
return false
}
// VisitAll visits the command-line flags in lexicographical order, calling
// fn for each. It visits all flags, even those not set.
func VisitAll(fn func(*Flag)) {
@ -408,41 +419,123 @@ func (f *FlagSet) PrintDefaults() {
fmt.Fprintf(f.out(), "%s", usages)
}
// isZeroValue guesses whether the string represents the zero
// value for a flag. It is not accurate but in practice works OK.
func isZeroValue(value string) bool {
switch value {
case "false":
return true
case "<nil>":
return true
case "":
return true
case "0":
return true
}
return false
}
// UnquoteUsage extracts a back-quoted name from the usage
// string for a flag and returns it and the un-quoted usage.
// Given "a `name` to show" it returns ("name", "a name to show").
// If there are no back quotes, the name is an educated guess of the
// type of the flag's value, or the empty string if the flag is boolean.
func UnquoteUsage(flag *Flag) (name string, usage string) {
// Look for a back-quoted name, but avoid the strings package.
usage = flag.Usage
for i := 0; i < len(usage); i++ {
if usage[i] == '`' {
for j := i + 1; j < len(usage); j++ {
if usage[j] == '`' {
name = usage[i+1 : j]
usage = usage[:i] + name + usage[j+1:]
return name, usage
}
}
break // Only one back quote; use type name.
}
}
// No explicit name, so use type if we can find one.
name = "value"
switch flag.Value.(type) {
case boolFlag:
name = ""
case *durationValue:
name = "duration"
case *float64Value:
name = "float"
case *intValue, *int64Value:
name = "int"
case *stringValue:
name = "string"
case *uintValue, *uint64Value:
name = "uint"
}
return
}
// FlagUsages Returns a string containing the usage information for all flags in
// the FlagSet
func (f *FlagSet) FlagUsages() string {
x := new(bytes.Buffer)
lines := make([]string, 0, len(f.formal))
maxlen := 0
f.VisitAll(func(flag *Flag) {
if len(flag.Deprecated) > 0 || flag.Hidden {
return
}
format := ""
line := ""
if len(flag.Shorthand) > 0 && len(flag.ShorthandDeprecated) == 0 {
format = " -%s, --%s"
line = fmt.Sprintf(" -%s, --%s", flag.Shorthand, flag.Name)
} else {
format = " %s --%s"
line = fmt.Sprintf(" --%s", flag.Name)
}
varname, usage := UnquoteUsage(flag)
if len(varname) > 0 {
line += " " + varname
}
if len(flag.NoOptDefVal) > 0 {
format = format + "["
switch flag.Value.Type() {
case "string":
line += fmt.Sprintf("[=%q]", flag.NoOptDefVal)
case "bool":
if flag.NoOptDefVal != "true" {
line += fmt.Sprintf("[=%s]", flag.NoOptDefVal)
}
default:
line += fmt.Sprintf("[=%s]", flag.NoOptDefVal)
}
}
if flag.Value.Type() == "string" {
// put quotes on the value
format = format + "=%q"
} else {
format = format + "=%s"
// This special character will be replaced with spacing once the
// correct alignment is calculated
line += "\x00"
if len(line) > maxlen {
maxlen = len(line)
}
if len(flag.NoOptDefVal) > 0 {
format = format + "]"
line += usage
if !isZeroValue(flag.DefValue) {
if flag.Value.Type() == "string" {
line += fmt.Sprintf(" (default %q)", flag.DefValue)
} else {
line += fmt.Sprintf(" (default %s)", flag.DefValue)
}
}
format = format + ": %s\n"
shorthand := flag.Shorthand
if len(flag.ShorthandDeprecated) > 0 {
shorthand = ""
}
fmt.Fprintf(x, format, shorthand, flag.Name, flag.DefValue, flag.Usage)
lines = append(lines, line)
})
for _, line := range lines {
sidx := strings.Index(line, "\x00")
spacing := strings.Repeat(" ", maxlen-sidx)
fmt.Fprintln(x, line[:sidx], spacing, line[sidx+1:])
}
return x.String()
}
@ -463,6 +556,8 @@ func defaultUsage(f *FlagSet) {
// Usage prints to standard error a usage message documenting all defined command-line flags.
// The function is a variable that may be changed to point to a custom function.
// By default it prints a simple header and calls PrintDefaults; for details about the
// format of the output and how to control it, see the documentation for PrintDefaults.
var Usage = func() {
fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
PrintDefaults()
@ -683,6 +778,9 @@ func (f *FlagSet) parseLongArg(s string, args []string) (a []string, err error)
}
func (f *FlagSet) parseSingleShortArg(shorthands string, args []string) (outShorts string, outArgs []string, err error) {
if strings.HasPrefix(shorthands, "test.") {
return
}
outArgs = args
outShorts = shorthands[1:]
c := shorthands[0]
@ -806,7 +904,7 @@ func Parsed() bool {
return CommandLine.Parsed()
}
// The default set of command-line flags, parsed from os.Args.
// CommandLine is the default set of command-line flags, parsed from os.Args.
var CommandLine = NewFlagSet(os.Args[0], ExitOnError)
// NewFlagSet returns a new, empty flag set with the specified name and

View File

@ -61,6 +61,9 @@ func (v *flagValueWrapper) Type() string {
}
// PFlagFromGoFlag will return a *pflag.Flag given a *flag.Flag
// If the *flag.Flag.Name was a single character (ex: `v`) it will be accessiblei
// with both `-v` and `--v` in flags. If the golang flag was more than a single
// character (ex: `verbose`) it will only be accessible via `--verbose`
func PFlagFromGoFlag(goflag *goflag.Flag) *Flag {
// Remember the default value as a string; it won't change.
flag := &Flag{
@ -71,6 +74,10 @@ func PFlagFromGoFlag(goflag *goflag.Flag) *Flag {
//DefValue: goflag.DefValue,
DefValue: goflag.Value.String(),
}
// Ex: if the golang flag was -v, allow both -v and --v to work
if len(flag.Name) == 1 {
flag.Shorthand = flag.Name
}
if fv, ok := goflag.Value.(goBoolFlag); ok && fv.IsBoolFlag() {
flag.NoOptDefVal = "true"
}