vendor: update kingpin
This commit is contained in:
parent
cc50aa2c6b
commit
4acb1d2b21
|
@ -1,4 +1,7 @@
|
|||
# Kingpin - A Go (golang) command line and flag parser [![](https://godoc.org/github.com/alecthomas/kingpin?status.svg)](http://godoc.org/github.com/alecthomas/kingpin) [![Build Status](https://travis-ci.org/alecthomas/kingpin.png)](https://travis-ci.org/alecthomas/kingpin)
|
||||
# Kingpin - A Go (golang) command line and flag parser
|
||||
[![](https://godoc.org/github.com/alecthomas/kingpin?status.svg)](http://godoc.org/github.com/alecthomas/kingpin) [![Build Status](https://travis-ci.org/alecthomas/kingpin.svg?branch=master)](https://travis-ci.org/alecthomas/kingpin) [![Gitter chat](https://badges.gitter.im/alecthomas.png)](https://gitter.im/alecthomas/Lobby)
|
||||
|
||||
|
||||
|
||||
<!-- MarkdownTOC -->
|
||||
|
||||
|
@ -54,7 +57,7 @@ func main() {
|
|||
}
|
||||
```
|
||||
|
||||
More [examples](https://github.com/alecthomas/kingpin/tree/master/examples) are available.
|
||||
More [examples](https://github.com/alecthomas/kingpin/tree/master/_examples) are available.
|
||||
|
||||
Second to parsing, providing the user with useful help is probably the most
|
||||
important thing a command-line parser does. Kingpin tries to provide detailed
|
||||
|
@ -138,7 +141,7 @@ $ go get gopkg.in/alecthomas/kingpin.v1
|
|||
- *2015-09-19* -- Stable v2.1.0 release.
|
||||
- Added `command.Default()` to specify a default command to use if no other
|
||||
command matches. This allows for convenient user shortcuts.
|
||||
- Exposed `HelpFlag` and `VersionFlag` for further cusomisation.
|
||||
- Exposed `HelpFlag` and `VersionFlag` for further customisation.
|
||||
- `Action()` and `PreAction()` added and both now support an arbitrary
|
||||
number of callbacks.
|
||||
- `kingpin.SeparateOptionalFlagsUsageTemplate`.
|
||||
|
@ -243,7 +246,7 @@ var (
|
|||
func main() {
|
||||
kingpin.Version("0.0.1")
|
||||
kingpin.Parse()
|
||||
fmt.Printf("Would ping: %s with timeout %s and count %d", *ip, *timeout, *count)
|
||||
fmt.Printf("Would ping: %s with timeout %s and count %d\n", *ip, *timeout, *count)
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -384,7 +387,7 @@ func main() {
|
|||
|
||||
Kingpin supports both flag and positional argument parsers for converting to
|
||||
Go types. For example, some included parsers are `Int()`, `Float()`,
|
||||
`Duration()` and `ExistingFile()`.
|
||||
`Duration()` and `ExistingFile()` (see [parsers.go](./parsers.go) for a complete list of included parsers).
|
||||
|
||||
Parsers conform to Go's [`flag.Value`](http://godoc.org/flag#Value)
|
||||
interface, so any existing implementations will work.
|
||||
|
@ -412,7 +415,7 @@ As a convenience, I would recommend something like this:
|
|||
|
||||
```go
|
||||
func HTTPHeader(s Settings) (target *http.Header) {
|
||||
target = new(http.Header)
|
||||
target = &http.Header{}
|
||||
s.SetValue((*HTTPHeaderValue)(target))
|
||||
return
|
||||
}
|
||||
|
@ -578,7 +581,7 @@ Consider the case that you needed to read a local database or a file to
|
|||
provide suggestions. You can dynamically generate the options
|
||||
|
||||
```
|
||||
func listHosts(args []string) []string {
|
||||
func listHosts() []string {
|
||||
// Provide a dynamic list of hosts from a hosts file or otherwise
|
||||
// for bash completion. In this example we simply return static slice.
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ var (
|
|||
)
|
||||
|
||||
var (
|
||||
envarTransformRegexp = regexp.MustCompile(`[^a-zA-Z_]+`)
|
||||
envarTransformRegexp = regexp.MustCompile(`[^a-zA-Z0-9_]+`)
|
||||
)
|
||||
|
||||
type ApplicationValidator func(*Application) error
|
||||
|
@ -29,7 +29,8 @@ type Application struct {
|
|||
|
||||
author string
|
||||
version string
|
||||
writer io.Writer // Destination for usage and errors.
|
||||
errorWriter io.Writer // Destination for errors.
|
||||
usageWriter io.Writer // Destination for usage
|
||||
usageTemplate string
|
||||
validator ApplicationValidator
|
||||
terminate func(status int) // See Terminate()
|
||||
|
@ -50,7 +51,8 @@ func New(name, help string) *Application {
|
|||
a := &Application{
|
||||
Name: name,
|
||||
Help: help,
|
||||
writer: os.Stderr,
|
||||
errorWriter: os.Stderr, // Left for backwards compatibility purposes.
|
||||
usageWriter: os.Stderr,
|
||||
usageTemplate: DefaultUsageTemplate,
|
||||
terminate: os.Exit,
|
||||
}
|
||||
|
@ -124,9 +126,23 @@ func (a *Application) Terminate(terminate func(int)) *Application {
|
|||
return a
|
||||
}
|
||||
|
||||
// Specify the writer to use for usage and errors. Defaults to os.Stderr.
|
||||
// Writer specifies the writer to use for usage and errors. Defaults to os.Stderr.
|
||||
// DEPRECATED: See ErrorWriter and UsageWriter.
|
||||
func (a *Application) Writer(w io.Writer) *Application {
|
||||
a.writer = w
|
||||
a.errorWriter = w
|
||||
a.usageWriter = w
|
||||
return a
|
||||
}
|
||||
|
||||
// ErrorWriter sets the io.Writer to use for errors.
|
||||
func (a *Application) ErrorWriter(w io.Writer) *Application {
|
||||
a.errorWriter = w
|
||||
return a
|
||||
}
|
||||
|
||||
// UsageWriter sets the io.Writer to use for errors.
|
||||
func (a *Application) UsageWriter(w io.Writer) *Application {
|
||||
a.usageWriter = w
|
||||
return a
|
||||
}
|
||||
|
||||
|
@ -218,45 +234,28 @@ func (a *Application) writeUsage(context *ParseContext, err error) {
|
|||
if err := a.UsageForContext(context); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
a.terminate(1)
|
||||
if err != nil {
|
||||
a.terminate(1)
|
||||
} else {
|
||||
a.terminate(0)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Application) maybeHelp(context *ParseContext) {
|
||||
for _, element := range context.Elements {
|
||||
if flag, ok := element.Clause.(*FlagClause); ok && flag == a.HelpFlag {
|
||||
// Re-parse the command-line ignoring defaults, so that help works correctly.
|
||||
context, _ = a.parseContext(true, context.rawArgs)
|
||||
a.writeUsage(context, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// findCommandFromArgs finds a command (if any) from the given command line arguments.
|
||||
func (a *Application) findCommandFromArgs(args []string) (command string, err error) {
|
||||
if err := a.init(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
context := tokenize(args, false)
|
||||
if _, err := a.parse(context); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return a.findCommandFromContext(context), nil
|
||||
}
|
||||
|
||||
// findCommandFromContext finds a command (if any) from a parsed context.
|
||||
func (a *Application) findCommandFromContext(context *ParseContext) string {
|
||||
commands := []string{}
|
||||
for _, element := range context.Elements {
|
||||
if c, ok := element.Clause.(*CmdClause); ok {
|
||||
commands = append(commands, c.name)
|
||||
}
|
||||
}
|
||||
return strings.Join(commands, " ")
|
||||
}
|
||||
|
||||
// Version adds a --version flag for displaying the application version.
|
||||
func (a *Application) Version(version string) *Application {
|
||||
a.version = version
|
||||
a.VersionFlag = a.Flag("version", "Show application version.").PreAction(func(*ParseContext) error {
|
||||
fmt.Fprintln(a.writer, version)
|
||||
fmt.Fprintln(a.usageWriter, version)
|
||||
a.terminate(0)
|
||||
return nil
|
||||
})
|
||||
|
@ -264,6 +263,7 @@ func (a *Application) Version(version string) *Application {
|
|||
return a
|
||||
}
|
||||
|
||||
// Author sets the author output by some help templates.
|
||||
func (a *Application) Author(author string) *Application {
|
||||
a.author = author
|
||||
return a
|
||||
|
@ -424,11 +424,8 @@ func (a *Application) setDefaults(context *ParseContext) error {
|
|||
|
||||
for _, arg := range context.arguments.args {
|
||||
if argElements[arg.name] == nil {
|
||||
// Set defaults, if any.
|
||||
for _, defaultValue := range arg.defaultValues {
|
||||
if err := arg.value.Set(defaultValue); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := arg.setDefault(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -463,7 +460,7 @@ func (a *Application) validateRequired(context *ParseContext) error {
|
|||
|
||||
for _, arg := range context.arguments.args {
|
||||
if argElements[arg.name] == nil {
|
||||
if arg.required {
|
||||
if arg.needsValue() {
|
||||
return fmt.Errorf("required argument '%s' not provided", arg.name)
|
||||
}
|
||||
}
|
||||
|
@ -564,7 +561,7 @@ func (a *Application) applyActions(context *ParseContext) error {
|
|||
|
||||
// Errorf prints an error message to w in the format "<appname>: error: <message>".
|
||||
func (a *Application) Errorf(format string, args ...interface{}) {
|
||||
fmt.Fprintf(a.writer, a.Name+": error: "+format+"\n", args...)
|
||||
fmt.Fprintf(a.errorWriter, a.Name+": error: "+format+"\n", args...)
|
||||
}
|
||||
|
||||
// Fatalf writes a formatted error to w then terminates with exit status 1.
|
||||
|
@ -577,6 +574,8 @@ func (a *Application) Fatalf(format string, args ...interface{}) {
|
|||
// exits with a non-zero status.
|
||||
func (a *Application) FatalUsage(format string, args ...interface{}) {
|
||||
a.Errorf(format, args...)
|
||||
// Force usage to go to error output.
|
||||
a.usageWriter = a.errorWriter
|
||||
a.Usage([]string{})
|
||||
a.terminate(1)
|
||||
}
|
||||
|
@ -650,15 +649,15 @@ func (a *Application) completionOptions(context *ParseContext) []string {
|
|||
options, flagMatched, valueMatched := target.FlagCompletion(flagName, flagValue)
|
||||
if valueMatched {
|
||||
// Value Matched. Show cmdCompletions
|
||||
return target.CmdCompletion()
|
||||
return target.CmdCompletion(context)
|
||||
}
|
||||
|
||||
// Add top level flags if we're not at the top level and no match was found.
|
||||
if context.SelectedCommand != nil && flagMatched == false {
|
||||
if context.SelectedCommand != nil && !flagMatched {
|
||||
topOptions, topFlagMatched, topValueMatched := a.FlagCompletion(flagName, flagValue)
|
||||
if topValueMatched {
|
||||
// Value Matched. Back to cmdCompletions
|
||||
return target.CmdCompletion()
|
||||
return target.CmdCompletion(context)
|
||||
}
|
||||
|
||||
if topFlagMatched {
|
||||
|
@ -670,10 +669,10 @@ func (a *Application) completionOptions(context *ParseContext) []string {
|
|||
}
|
||||
}
|
||||
return options
|
||||
} else {
|
||||
// Perform completion for sub commands.
|
||||
return target.CmdCompletion()
|
||||
}
|
||||
|
||||
// Perform completion for sub commands and arguments.
|
||||
return target.CmdCompletion(context)
|
||||
}
|
||||
|
||||
func (a *Application) generateBashCompletion(context *ParseContext) {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package kingpin
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type argGroup struct {
|
||||
args []*ArgClause
|
||||
|
@ -64,6 +66,8 @@ func (a *argGroup) init() error {
|
|||
type ArgClause struct {
|
||||
actionMixin
|
||||
parserMixin
|
||||
completionsMixin
|
||||
envarMixin
|
||||
name string
|
||||
help string
|
||||
defaultValues []string
|
||||
|
@ -78,6 +82,37 @@ func newArg(name, help string) *ArgClause {
|
|||
return a
|
||||
}
|
||||
|
||||
func (a *ArgClause) setDefault() error {
|
||||
if a.HasEnvarValue() {
|
||||
if v, ok := a.value.(remainderArg); !ok || !v.IsCumulative() {
|
||||
// Use the value as-is
|
||||
return a.value.Set(a.GetEnvarValue())
|
||||
}
|
||||
for _, value := range a.GetSplitEnvarValue() {
|
||||
if err := a.value.Set(value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(a.defaultValues) > 0 {
|
||||
for _, defaultValue := range a.defaultValues {
|
||||
if err := a.value.Set(defaultValue); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *ArgClause) needsValue() bool {
|
||||
haveDefault := len(a.defaultValues) > 0
|
||||
return a.required && !(haveDefault || a.HasEnvarValue())
|
||||
}
|
||||
|
||||
func (a *ArgClause) consumesRemainder() bool {
|
||||
if r, ok := a.value.(remainderArg); ok {
|
||||
return r.IsCumulative()
|
||||
|
@ -97,6 +132,23 @@ func (a *ArgClause) Default(values ...string) *ArgClause {
|
|||
return a
|
||||
}
|
||||
|
||||
// Envar overrides the default value(s) for a flag from an environment variable,
|
||||
// if it is set. Several default values can be provided by using new lines to
|
||||
// separate them.
|
||||
func (a *ArgClause) Envar(name string) *ArgClause {
|
||||
a.envar = name
|
||||
a.noEnvar = false
|
||||
return a
|
||||
}
|
||||
|
||||
// NoEnvar forces environment variable defaults to be disabled for this flag.
|
||||
// Most useful in conjunction with app.DefaultEnvars().
|
||||
func (a *ArgClause) NoEnvar() *ArgClause {
|
||||
a.envar = ""
|
||||
a.noEnvar = true
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *ArgClause) Action(action Action) *ArgClause {
|
||||
a.addAction(action)
|
||||
return a
|
||||
|
@ -107,6 +159,20 @@ func (a *ArgClause) PreAction(action Action) *ArgClause {
|
|||
return a
|
||||
}
|
||||
|
||||
// HintAction registers a HintAction (function) for the arg to provide completions
|
||||
func (a *ArgClause) HintAction(action HintAction) *ArgClause {
|
||||
a.addHintAction(action)
|
||||
return a
|
||||
}
|
||||
|
||||
// HintOptions registers any number of options for the flag to provide completions
|
||||
func (a *ArgClause) HintOptions(options ...string) *ArgClause {
|
||||
a.addHintAction(func() []string {
|
||||
return options
|
||||
})
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *ArgClause) init() error {
|
||||
if a.required && len(a.defaultValues) > 0 {
|
||||
return fmt.Errorf("required argument '%s' with unusable default value", a.name)
|
||||
|
|
|
@ -12,19 +12,40 @@ type cmdMixin struct {
|
|||
actionMixin
|
||||
}
|
||||
|
||||
func (c *cmdMixin) CmdCompletion() []string {
|
||||
rv := []string{}
|
||||
if len(c.cmdGroup.commandOrder) > 0 {
|
||||
// This command has subcommands. We should
|
||||
// show these to the user.
|
||||
for _, option := range c.cmdGroup.commandOrder {
|
||||
rv = append(rv, option.name)
|
||||
// CmdCompletion returns completion options for arguments, if that's where
|
||||
// parsing left off, or commands if there aren't any unsatisfied args.
|
||||
func (c *cmdMixin) CmdCompletion(context *ParseContext) []string {
|
||||
var options []string
|
||||
|
||||
// Count args already satisfied - we won't complete those, and add any
|
||||
// default commands' alternatives, since they weren't listed explicitly
|
||||
// and the user may want to explicitly list something else.
|
||||
argsSatisfied := 0
|
||||
for _, el := range context.Elements {
|
||||
switch clause := el.Clause.(type) {
|
||||
case *ArgClause:
|
||||
if el.Value != nil && *el.Value != "" {
|
||||
argsSatisfied++
|
||||
}
|
||||
case *CmdClause:
|
||||
options = append(options, clause.completionAlts...)
|
||||
default:
|
||||
}
|
||||
} else {
|
||||
// No subcommands
|
||||
rv = nil
|
||||
}
|
||||
return rv
|
||||
|
||||
if argsSatisfied < len(c.argGroup.args) {
|
||||
// Since not all args have been satisfied, show options for the current one
|
||||
options = append(options, c.argGroup.args[argsSatisfied].resolveCompletions()...)
|
||||
} else {
|
||||
// If all args are satisfied, then go back to completing commands
|
||||
for _, cmd := range c.cmdGroup.commandOrder {
|
||||
if !cmd.hidden {
|
||||
options = append(options, cmd.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
func (c *cmdMixin) FlagCompletion(flagName string, flagValue string) (choices []string, flagMatch bool, optionMatch bool) {
|
||||
|
@ -86,6 +107,14 @@ func (c *cmdGroup) defaultSubcommand() *CmdClause {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *cmdGroup) cmdNames() []string {
|
||||
names := make([]string, 0, len(c.commandOrder))
|
||||
for _, cmd := range c.commandOrder {
|
||||
names = append(names, cmd.name)
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
// GetArg gets a command definition.
|
||||
//
|
||||
// This allows existing commands to be modified after definition but before parsing. Useful for
|
||||
|
@ -158,13 +187,14 @@ type CmdClauseValidator func(*CmdClause) error
|
|||
// and either subcommands or positional arguments.
|
||||
type CmdClause struct {
|
||||
cmdMixin
|
||||
app *Application
|
||||
name string
|
||||
aliases []string
|
||||
help string
|
||||
isDefault bool
|
||||
validator CmdClauseValidator
|
||||
hidden bool
|
||||
app *Application
|
||||
name string
|
||||
aliases []string
|
||||
help string
|
||||
isDefault bool
|
||||
validator CmdClauseValidator
|
||||
hidden bool
|
||||
completionAlts []string
|
||||
}
|
||||
|
||||
func newCommand(app *Application, name, help string) *CmdClause {
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
//
|
||||
// package main
|
||||
//
|
||||
// import "gopkg.in/alecthomas/kingpin.v1"
|
||||
// import "gopkg.in/alecthomas/kingpin.v2"
|
||||
//
|
||||
// var (
|
||||
// debug = kingpin.Flag("debug", "enable debug mode").Default("false").Bool()
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
package kingpin
|
||||
|
||||
import (
|
||||
"os"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
var (
|
||||
envVarValuesSeparator = "\r?\n"
|
||||
envVarValuesTrimmer = regexp.MustCompile(envVarValuesSeparator + "$")
|
||||
envVarValuesSplitter = regexp.MustCompile(envVarValuesSeparator)
|
||||
)
|
||||
|
||||
type envarMixin struct {
|
||||
envar string
|
||||
noEnvar bool
|
||||
}
|
||||
|
||||
func (e *envarMixin) HasEnvarValue() bool {
|
||||
return e.GetEnvarValue() != ""
|
||||
}
|
||||
|
||||
func (e *envarMixin) GetEnvarValue() string {
|
||||
if e.noEnvar || e.envar == "" {
|
||||
return ""
|
||||
}
|
||||
return os.Getenv(e.envar)
|
||||
}
|
||||
|
||||
func (e *envarMixin) GetSplitEnvarValue() []string {
|
||||
values := make([]string, 0)
|
||||
|
||||
envarValue := e.GetEnvarValue()
|
||||
if envarValue == "" {
|
||||
return values
|
||||
}
|
||||
|
||||
// Split by new line to extract multiple values, if any.
|
||||
trimmed := envVarValuesTrimmer.ReplaceAllString(envarValue, "")
|
||||
for _, value := range envVarValuesSplitter.Split(trimmed, -1) {
|
||||
values = append(values, value)
|
||||
}
|
||||
|
||||
return values
|
||||
}
|
|
@ -2,17 +2,9 @@ package kingpin
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
envVarValuesSeparator = "\r?\n"
|
||||
envVarValuesTrimmer = regexp.MustCompile(envVarValuesSeparator + "$")
|
||||
envVarValuesSplitter = regexp.MustCompile(envVarValuesSeparator)
|
||||
)
|
||||
|
||||
type flagGroup struct {
|
||||
short map[string]*FlagClause
|
||||
long map[string]*FlagClause
|
||||
|
@ -61,7 +53,7 @@ func (f *flagGroup) init(defaultEnvarPrefix string) error {
|
|||
}
|
||||
|
||||
func (f *flagGroup) checkDuplicates() error {
|
||||
seenShort := map[byte]bool{}
|
||||
seenShort := map[rune]bool{}
|
||||
seenLong := map[string]bool{}
|
||||
for _, flag := range f.flagOrder {
|
||||
if flag.shorthand != 0 {
|
||||
|
@ -97,11 +89,14 @@ loop:
|
|||
|
||||
name := token.Value
|
||||
if token.Type == TokenLong {
|
||||
if strings.HasPrefix(name, "no-") {
|
||||
name = name[3:]
|
||||
invert = true
|
||||
}
|
||||
flag, ok = f.long[name]
|
||||
if !ok {
|
||||
if strings.HasPrefix(name, "no-") {
|
||||
name = name[3:]
|
||||
invert = true
|
||||
}
|
||||
flag, ok = f.long[name]
|
||||
}
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unknown long flag '%s'", flagToken)
|
||||
}
|
||||
|
@ -145,26 +140,15 @@ loop:
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
func (f *flagGroup) visibleFlags() int {
|
||||
count := 0
|
||||
for _, flag := range f.long {
|
||||
if !flag.hidden {
|
||||
count++
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
// FlagClause is a fluid interface used to build flags.
|
||||
type FlagClause struct {
|
||||
parserMixin
|
||||
actionMixin
|
||||
completionsMixin
|
||||
envarMixin
|
||||
name string
|
||||
shorthand byte
|
||||
shorthand rune
|
||||
help string
|
||||
envar string
|
||||
noEnvar bool
|
||||
defaultValues []string
|
||||
placeholder string
|
||||
hidden bool
|
||||
|
@ -179,21 +163,17 @@ func newFlag(name, help string) *FlagClause {
|
|||
}
|
||||
|
||||
func (f *FlagClause) setDefault() error {
|
||||
if !f.noEnvar && f.envar != "" {
|
||||
if envarValue := os.Getenv(f.envar); envarValue != "" {
|
||||
if v, ok := f.value.(repeatableFlag); !ok || !v.IsCumulative() {
|
||||
// Use the value as-is
|
||||
return f.value.Set(envarValue)
|
||||
} else {
|
||||
// Split by new line to extract multiple values, if any.
|
||||
trimmed := envVarValuesTrimmer.ReplaceAllString(envarValue, "")
|
||||
for _, value := range envVarValuesSplitter.Split(trimmed, -1) {
|
||||
if err := f.value.Set(value); err != nil {
|
||||
return err
|
||||
}
|
||||
if f.HasEnvarValue() {
|
||||
if v, ok := f.value.(repeatableFlag); !ok || !v.IsCumulative() {
|
||||
// Use the value as-is
|
||||
return f.value.Set(f.GetEnvarValue())
|
||||
} else {
|
||||
for _, value := range f.GetSplitEnvarValue() {
|
||||
if err := f.value.Set(value); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -211,8 +191,7 @@ func (f *FlagClause) setDefault() error {
|
|||
|
||||
func (f *FlagClause) needsValue() bool {
|
||||
haveDefault := len(f.defaultValues) > 0
|
||||
haveEnvar := !f.noEnvar && f.envar != "" && os.Getenv(f.envar) != ""
|
||||
return f.required && !(haveDefault || haveEnvar)
|
||||
return f.required && !(haveDefault || f.HasEnvarValue())
|
||||
}
|
||||
|
||||
func (f *FlagClause) init() error {
|
||||
|
@ -316,7 +295,7 @@ func (f *FlagClause) Required() *FlagClause {
|
|||
}
|
||||
|
||||
// Short sets the short flag name.
|
||||
func (f *FlagClause) Short(name byte) *FlagClause {
|
||||
func (f *FlagClause) Short(name rune) *FlagClause {
|
||||
f.shorthand = name
|
||||
return f
|
||||
}
|
||||
|
|
|
@ -96,6 +96,7 @@ type ArgModel struct {
|
|||
Name string
|
||||
Help string
|
||||
Default []string
|
||||
Envar string
|
||||
Required bool
|
||||
Value Value
|
||||
}
|
||||
|
@ -170,6 +171,7 @@ func (a *ArgClause) Model() *ArgModel {
|
|||
Name: a.name,
|
||||
Help: a.help,
|
||||
Default: a.defaultValues,
|
||||
Envar: a.envar,
|
||||
Required: a.required,
|
||||
Value: a.value,
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
type TokenType int
|
||||
|
@ -189,7 +190,8 @@ func (p *ParseContext) Next() *Token {
|
|||
if len(arg) == 1 {
|
||||
return &Token{Index: p.argi, Type: TokenShort}
|
||||
}
|
||||
short := arg[1:2]
|
||||
shortRune, size := utf8.DecodeRuneInString(arg[1:])
|
||||
short := string(shortRune)
|
||||
flag, ok := p.flags.short[short]
|
||||
// Not a known short flag, we'll just return it anyway.
|
||||
if !ok {
|
||||
|
@ -198,14 +200,14 @@ func (p *ParseContext) Next() *Token {
|
|||
} else {
|
||||
// Short flag with combined argument: -fARG
|
||||
token := &Token{p.argi, TokenShort, short}
|
||||
if len(arg) > 2 {
|
||||
p.Push(&Token{p.argi, TokenArg, arg[2:]})
|
||||
if len(arg) > size+1 {
|
||||
p.Push(&Token{p.argi, TokenArg, arg[size+1:]})
|
||||
}
|
||||
return token
|
||||
}
|
||||
|
||||
if len(arg) > 2 {
|
||||
p.args = append([]string{"-" + arg[2:]}, p.args...)
|
||||
if len(arg) > size+1 {
|
||||
p.args = append([]string{"-" + arg[size+1:]}, p.args...)
|
||||
}
|
||||
return &Token{p.argi, TokenShort, short}
|
||||
} else if strings.HasPrefix(arg, "@") {
|
||||
|
@ -213,10 +215,10 @@ func (p *ParseContext) Next() *Token {
|
|||
if err != nil {
|
||||
return &Token{p.argi, TokenError, err.Error()}
|
||||
}
|
||||
if p.argi >= len(p.args) {
|
||||
p.args = append(p.args[:p.argi-1], expanded...)
|
||||
if len(p.args) == 0 {
|
||||
p.args = expanded
|
||||
} else {
|
||||
p.args = append(p.args[:p.argi-1], append(expanded, p.args[p.argi+1:]...)...)
|
||||
p.args = append(expanded, p.args...)
|
||||
}
|
||||
return p.Next()
|
||||
}
|
||||
|
@ -297,6 +299,7 @@ loop:
|
|||
if flag, err := context.flags.parse(context); err != nil {
|
||||
if !ignoreDefault {
|
||||
if cmd := cmds.defaultSubcommand(); cmd != nil {
|
||||
cmd.completionAlts = cmds.cmdNames()
|
||||
context.matchedCmd(cmd)
|
||||
cmds = cmd.cmdGroup
|
||||
break
|
||||
|
@ -314,6 +317,7 @@ loop:
|
|||
if !ok {
|
||||
if !ignoreDefault {
|
||||
if cmd = cmds.defaultSubcommand(); cmd != nil {
|
||||
cmd.completionAlts = cmds.cmdNames()
|
||||
selectedDefault = true
|
||||
}
|
||||
}
|
||||
|
@ -324,6 +328,7 @@ loop:
|
|||
if cmd == HelpCommand {
|
||||
ignoreDefault = true
|
||||
}
|
||||
cmd.completionAlts = nil
|
||||
context.matchedCmd(cmd)
|
||||
cmds = cmd.cmdGroup
|
||||
if !selectedDefault {
|
||||
|
@ -352,6 +357,7 @@ loop:
|
|||
// Move to innermost default command.
|
||||
for !ignoreDefault {
|
||||
if cmd := cmds.defaultSubcommand(); cmd != nil {
|
||||
cmd.completionAlts = cmds.cmdNames()
|
||||
context.matchedCmd(cmd)
|
||||
cmds = cmd.cmdGroup
|
||||
} else {
|
||||
|
|
|
@ -113,7 +113,7 @@ func (a *Application) UsageForContext(context *ParseContext) error {
|
|||
|
||||
// UsageForContextWithTemplate is the base usage function. You generally don't need to use this.
|
||||
func (a *Application) UsageForContextWithTemplate(context *ParseContext, indent int, tmpl string) error {
|
||||
width := guessWidth(a.writer)
|
||||
width := guessWidth(a.usageWriter)
|
||||
funcs := template.FuncMap{
|
||||
"Indent": func(level int) string {
|
||||
return strings.Repeat(" ", level*indent)
|
||||
|
@ -121,7 +121,7 @@ func (a *Application) UsageForContextWithTemplate(context *ParseContext, indent
|
|||
"Wrap": func(indent int, s string) string {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
indentText := strings.Repeat(" ", indent)
|
||||
doc.ToText(buf, s, indentText, indentText, width-indent)
|
||||
doc.ToText(buf, s, indentText, " "+indentText, width-indent)
|
||||
return buf.String()
|
||||
},
|
||||
"FormatFlag": formatFlag,
|
||||
|
@ -144,7 +144,7 @@ func (a *Application) UsageForContextWithTemplate(context *ParseContext, indent
|
|||
"RequiredFlags": func(f []*FlagModel) []*FlagModel {
|
||||
requiredFlags := []*FlagModel{}
|
||||
for _, flag := range f {
|
||||
if flag.Required == true {
|
||||
if flag.Required {
|
||||
requiredFlags = append(requiredFlags, flag)
|
||||
}
|
||||
}
|
||||
|
@ -153,7 +153,7 @@ func (a *Application) UsageForContextWithTemplate(context *ParseContext, indent
|
|||
"OptionalFlags": func(f []*FlagModel) []*FlagModel {
|
||||
optionalFlags := []*FlagModel{}
|
||||
for _, flag := range f {
|
||||
if flag.Required == false {
|
||||
if !flag.Required {
|
||||
optionalFlags = append(optionalFlags, flag)
|
||||
}
|
||||
}
|
||||
|
@ -207,5 +207,5 @@ func (a *Application) UsageForContextWithTemplate(context *ParseContext, indent
|
|||
ArgGroupModel: context.arguments.Model(),
|
||||
},
|
||||
}
|
||||
return t.Execute(a.writer, ctx)
|
||||
return t.Execute(a.usageWriter, ctx)
|
||||
}
|
||||
|
|
|
@ -332,6 +332,10 @@ func (u *urlListValue) String() string {
|
|||
return strings.Join(out, ",")
|
||||
}
|
||||
|
||||
func (u *urlListValue) IsCumulative() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// A flag whose value must be in a set of options.
|
||||
type enumValue struct {
|
||||
value *string
|
||||
|
|
|
@ -28,7 +28,7 @@ func (f *boolValue) Set(s string) error {
|
|||
|
||||
func (f *boolValue) Get() interface{} { return (bool)(*f.v) }
|
||||
|
||||
func (f *boolValue) String() string { return fmt.Sprintf("%v", *f) }
|
||||
func (f *boolValue) String() string { return fmt.Sprintf("%v", *f.v) }
|
||||
|
||||
// Bool parses the next command-line value as bool.
|
||||
func (p *parserMixin) Bool() (target *bool) {
|
||||
|
@ -114,7 +114,7 @@ func (f *uintValue) Set(s string) error {
|
|||
|
||||
func (f *uintValue) Get() interface{} { return (uint)(*f.v) }
|
||||
|
||||
func (f *uintValue) String() string { return fmt.Sprintf("%v", *f) }
|
||||
func (f *uintValue) String() string { return fmt.Sprintf("%v", *f.v) }
|
||||
|
||||
// Uint parses the next command-line value as uint.
|
||||
func (p *parserMixin) Uint() (target *uint) {
|
||||
|
@ -157,7 +157,7 @@ func (f *uint8Value) Set(s string) error {
|
|||
|
||||
func (f *uint8Value) Get() interface{} { return (uint8)(*f.v) }
|
||||
|
||||
func (f *uint8Value) String() string { return fmt.Sprintf("%v", *f) }
|
||||
func (f *uint8Value) String() string { return fmt.Sprintf("%v", *f.v) }
|
||||
|
||||
// Uint8 parses the next command-line value as uint8.
|
||||
func (p *parserMixin) Uint8() (target *uint8) {
|
||||
|
@ -200,7 +200,7 @@ func (f *uint16Value) Set(s string) error {
|
|||
|
||||
func (f *uint16Value) Get() interface{} { return (uint16)(*f.v) }
|
||||
|
||||
func (f *uint16Value) String() string { return fmt.Sprintf("%v", *f) }
|
||||
func (f *uint16Value) String() string { return fmt.Sprintf("%v", *f.v) }
|
||||
|
||||
// Uint16 parses the next command-line value as uint16.
|
||||
func (p *parserMixin) Uint16() (target *uint16) {
|
||||
|
@ -243,7 +243,7 @@ func (f *uint32Value) Set(s string) error {
|
|||
|
||||
func (f *uint32Value) Get() interface{} { return (uint32)(*f.v) }
|
||||
|
||||
func (f *uint32Value) String() string { return fmt.Sprintf("%v", *f) }
|
||||
func (f *uint32Value) String() string { return fmt.Sprintf("%v", *f.v) }
|
||||
|
||||
// Uint32 parses the next command-line value as uint32.
|
||||
func (p *parserMixin) Uint32() (target *uint32) {
|
||||
|
@ -286,7 +286,7 @@ func (f *uint64Value) Set(s string) error {
|
|||
|
||||
func (f *uint64Value) Get() interface{} { return (uint64)(*f.v) }
|
||||
|
||||
func (f *uint64Value) String() string { return fmt.Sprintf("%v", *f) }
|
||||
func (f *uint64Value) String() string { return fmt.Sprintf("%v", *f.v) }
|
||||
|
||||
// Uint64 parses the next command-line value as uint64.
|
||||
func (p *parserMixin) Uint64() (target *uint64) {
|
||||
|
@ -329,7 +329,7 @@ func (f *intValue) Set(s string) error {
|
|||
|
||||
func (f *intValue) Get() interface{} { return (int)(*f.v) }
|
||||
|
||||
func (f *intValue) String() string { return fmt.Sprintf("%v", *f) }
|
||||
func (f *intValue) String() string { return fmt.Sprintf("%v", *f.v) }
|
||||
|
||||
// Int parses the next command-line value as int.
|
||||
func (p *parserMixin) Int() (target *int) {
|
||||
|
@ -372,7 +372,7 @@ func (f *int8Value) Set(s string) error {
|
|||
|
||||
func (f *int8Value) Get() interface{} { return (int8)(*f.v) }
|
||||
|
||||
func (f *int8Value) String() string { return fmt.Sprintf("%v", *f) }
|
||||
func (f *int8Value) String() string { return fmt.Sprintf("%v", *f.v) }
|
||||
|
||||
// Int8 parses the next command-line value as int8.
|
||||
func (p *parserMixin) Int8() (target *int8) {
|
||||
|
@ -415,7 +415,7 @@ func (f *int16Value) Set(s string) error {
|
|||
|
||||
func (f *int16Value) Get() interface{} { return (int16)(*f.v) }
|
||||
|
||||
func (f *int16Value) String() string { return fmt.Sprintf("%v", *f) }
|
||||
func (f *int16Value) String() string { return fmt.Sprintf("%v", *f.v) }
|
||||
|
||||
// Int16 parses the next command-line value as int16.
|
||||
func (p *parserMixin) Int16() (target *int16) {
|
||||
|
@ -458,7 +458,7 @@ func (f *int32Value) Set(s string) error {
|
|||
|
||||
func (f *int32Value) Get() interface{} { return (int32)(*f.v) }
|
||||
|
||||
func (f *int32Value) String() string { return fmt.Sprintf("%v", *f) }
|
||||
func (f *int32Value) String() string { return fmt.Sprintf("%v", *f.v) }
|
||||
|
||||
// Int32 parses the next command-line value as int32.
|
||||
func (p *parserMixin) Int32() (target *int32) {
|
||||
|
@ -501,7 +501,7 @@ func (f *int64Value) Set(s string) error {
|
|||
|
||||
func (f *int64Value) Get() interface{} { return (int64)(*f.v) }
|
||||
|
||||
func (f *int64Value) String() string { return fmt.Sprintf("%v", *f) }
|
||||
func (f *int64Value) String() string { return fmt.Sprintf("%v", *f.v) }
|
||||
|
||||
// Int64 parses the next command-line value as int64.
|
||||
func (p *parserMixin) Int64() (target *int64) {
|
||||
|
@ -544,7 +544,7 @@ func (f *float64Value) Set(s string) error {
|
|||
|
||||
func (f *float64Value) Get() interface{} { return (float64)(*f.v) }
|
||||
|
||||
func (f *float64Value) String() string { return fmt.Sprintf("%v", *f) }
|
||||
func (f *float64Value) String() string { return fmt.Sprintf("%v", *f.v) }
|
||||
|
||||
// Float64 parses the next command-line value as float64.
|
||||
func (p *parserMixin) Float64() (target *float64) {
|
||||
|
@ -587,7 +587,7 @@ func (f *float32Value) Set(s string) error {
|
|||
|
||||
func (f *float32Value) Get() interface{} { return (float32)(*f.v) }
|
||||
|
||||
func (f *float32Value) String() string { return fmt.Sprintf("%v", *f) }
|
||||
func (f *float32Value) String() string { return fmt.Sprintf("%v", *f.v) }
|
||||
|
||||
// Float32 parses the next command-line value as float32.
|
||||
func (p *parserMixin) Float32() (target *float32) {
|
||||
|
@ -708,7 +708,7 @@ func (f *regexpValue) Set(s string) error {
|
|||
|
||||
func (f *regexpValue) Get() interface{} { return (*regexp.Regexp)(*f.v) }
|
||||
|
||||
func (f *regexpValue) String() string { return fmt.Sprintf("%v", *f) }
|
||||
func (f *regexpValue) String() string { return fmt.Sprintf("%v", *f.v) }
|
||||
|
||||
// Regexp parses the next command-line value as *regexp.Regexp.
|
||||
func (p *parserMixin) Regexp() (target **regexp.Regexp) {
|
||||
|
@ -751,7 +751,7 @@ func (f *resolvedIPValue) Set(s string) error {
|
|||
|
||||
func (f *resolvedIPValue) Get() interface{} { return (net.IP)(*f.v) }
|
||||
|
||||
func (f *resolvedIPValue) String() string { return fmt.Sprintf("%v", *f) }
|
||||
func (f *resolvedIPValue) String() string { return fmt.Sprintf("%v", *f.v) }
|
||||
|
||||
// Resolve a hostname or IP to an IP.
|
||||
func (p *parserMixin) ResolvedIP() (target *net.IP) {
|
||||
|
@ -794,7 +794,7 @@ func (f *hexBytesValue) Set(s string) error {
|
|||
|
||||
func (f *hexBytesValue) Get() interface{} { return ([]byte)(*f.v) }
|
||||
|
||||
func (f *hexBytesValue) String() string { return fmt.Sprintf("%v", *f) }
|
||||
func (f *hexBytesValue) String() string { return fmt.Sprintf("%v", *f.v) }
|
||||
|
||||
// Bytes as a hex string.
|
||||
func (p *parserMixin) HexBytes() (target *[]byte) {
|
||||
|
|
|
@ -1290,10 +1290,10 @@
|
|||
"revisionTime": "2017-06-08T03:40:07Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "QPs8F/aqKAAQJr8dLc3CVQ5SxlM=",
|
||||
"checksumSHA1": "3SZTatHIy9OTKc95YlVfXKnoySg=",
|
||||
"path": "gopkg.in/alecthomas/kingpin.v2",
|
||||
"revision": "8cccfa8eb2e3183254457fb1749b2667fbc364c7",
|
||||
"revisionTime": "2016-02-17T09:03:01Z"
|
||||
"revision": "1087e65c9441605df944fb12c33f0fe7072d18ca",
|
||||
"revisionTime": "2017-07-27T04:22:29Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "JfVmsMwyeeepbdw4q4wpN07BuFg=",
|
||||
|
|
Loading…
Reference in New Issue