update vendored

This commit is contained in:
Louis Abel 2022-11-14 18:57:22 -07:00
parent 08b382b51f
commit 174f0860a7
Signed by: label
GPG Key ID: 6735C0E1BD65D048
25 changed files with 532 additions and 402 deletions

2
go.mod
View File

@ -2,7 +2,7 @@ module github.com/rocky-linux/rpaste
go 1.18 go 1.18
require github.com/urfave/cli/v2 v2.19.2 require github.com/urfave/cli/v2 v2.23.5
require ( require (
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect

4
go.sum
View File

@ -2,7 +2,7 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHH
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/urfave/cli/v2 v2.19.2 h1:eXu5089gqqiDQKSnFW+H/FhjrxRGztwSxlTsVK7IuqQ= github.com/urfave/cli/v2 v2.23.5 h1:xbrU7tAYviSpqeR3X4nEFWUdB/uDZ6DE+HxmRU7Xtyw=
github.com/urfave/cli/v2 v2.19.2/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI= github.com/urfave/cli/v2 v2.23.5/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=

View File

@ -7,8 +7,8 @@ import (
"io" "io"
"os" "os"
"path/filepath" "path/filepath"
"reflect"
"sort" "sort"
"strings"
"time" "time"
) )
@ -21,6 +21,7 @@ var (
errInvalidActionType = NewExitError("ERROR invalid Action type. "+ errInvalidActionType = NewExitError("ERROR invalid Action type. "+
fmt.Sprintf("Must be `func(*Context`)` or `func(*Context) error). %s", contactSysadmin)+ fmt.Sprintf("Must be `func(*Context`)` or `func(*Context) error). %s", contactSysadmin)+
fmt.Sprintf("See %s", appActionDeprecationURL), 2) fmt.Sprintf("See %s", appActionDeprecationURL), 2)
ignoreFlagPrefix = "test." // this is to ignore test flags when adding flags from other packages
SuggestFlag SuggestFlagFunc = suggestFlag SuggestFlag SuggestFlagFunc = suggestFlag
SuggestCommand SuggestCommandFunc = suggestCommand SuggestCommand SuggestCommandFunc = suggestCommand
@ -104,14 +105,23 @@ type App struct {
// cli.go uses text/template to render templates. You can // cli.go uses text/template to render templates. You can
// render custom help text by setting this variable. // render custom help text by setting this variable.
CustomAppHelpTemplate string CustomAppHelpTemplate string
// SliceFlagSeparator is used to customize the separator for SliceFlag, the default is ","
SliceFlagSeparator string
// Boolean to enable short-option handling so user can combine several // Boolean to enable short-option handling so user can combine several
// single-character bool arguments into one // single-character bool arguments into one
// i.e. foobar -o -v -> foobar -ov // i.e. foobar -o -v -> foobar -ov
UseShortOptionHandling bool UseShortOptionHandling bool
// Enable suggestions for commands and flags // Enable suggestions for commands and flags
Suggest bool Suggest bool
// Allows global flags set by libraries which use flag.XXXVar(...) directly
// to be parsed through this library
AllowExtFlags bool
// Treat all flags as normal arguments if true
SkipFlagParsing bool
didSetup bool didSetup bool
rootCommand *Command
} }
type SuggestFlagFunc func(flags []Flag, provided string, hideHelp bool) string type SuggestFlagFunc func(flags []Flag, provided string, hideHelp bool) string
@ -194,12 +204,24 @@ func (a *App) Setup() {
a.ErrWriter = os.Stderr a.ErrWriter = os.Stderr
} }
if a.AllowExtFlags {
// add global flags added by other packages
flag.VisitAll(func(f *flag.Flag) {
// skip test flags
if !strings.HasPrefix(f.Name, ignoreFlagPrefix) {
a.Flags = append(a.Flags, &extFlag{f})
}
})
}
var newCommands []*Command var newCommands []*Command
for _, c := range a.Commands { for _, c := range a.Commands {
if c.HelpName == "" { cname := c.Name
c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name) if c.HelpName != "" {
cname = c.HelpName
} }
c.HelpName = fmt.Sprintf("%s %s", a.HelpName, cname)
c.flagCategories = newFlagCategoriesFromFlags(c.Flags) c.flagCategories = newFlagCategoriesFromFlags(c.Flags)
newCommands = append(newCommands, c) newCommands = append(newCommands, c)
@ -238,6 +260,36 @@ func (a *App) Setup() {
if a.Metadata == nil { if a.Metadata == nil {
a.Metadata = make(map[string]interface{}) a.Metadata = make(map[string]interface{})
} }
if len(a.SliceFlagSeparator) != 0 {
defaultSliceFlagSeparator = a.SliceFlagSeparator
}
}
func (a *App) newRootCommand() *Command {
return &Command{
Name: a.Name,
Usage: a.Usage,
UsageText: a.UsageText,
Description: a.Description,
ArgsUsage: a.ArgsUsage,
BashComplete: a.BashComplete,
Before: a.Before,
After: a.After,
Action: a.Action,
OnUsageError: a.OnUsageError,
Subcommands: a.Commands,
Flags: a.Flags,
flagCategories: a.flagCategories,
HideHelp: a.HideHelp,
HideHelpCommand: a.HideHelpCommand,
UseShortOptionHandling: a.UseShortOptionHandling,
HelpName: a.HelpName,
CustomHelpTemplate: a.CustomAppHelpTemplate,
categories: a.categories,
SkipFlagParsing: a.SkipFlagParsing,
isRoot: true,
}
} }
func (a *App) newFlagSet() (*flag.FlagSet, error) { func (a *App) newFlagSet() (*flag.FlagSet, error) {
@ -268,136 +320,20 @@ func (a *App) RunContext(ctx context.Context, arguments []string) (err error) {
// always appends the completion flag at the end of the command // always appends the completion flag at the end of the command
shellComplete, arguments := checkShellCompleteFlag(a, arguments) shellComplete, arguments := checkShellCompleteFlag(a, arguments)
set, err := a.newFlagSet() cCtx := NewContext(a, nil, &Context{Context: ctx})
if err != nil {
return err
}
err = parseIter(set, a, arguments[1:], shellComplete)
nerr := normalizeFlags(a.Flags, set)
cCtx := NewContext(a, set, &Context{Context: ctx})
if nerr != nil {
_, _ = fmt.Fprintln(a.Writer, nerr)
if !a.HideHelp {
_ = ShowAppHelp(cCtx)
}
return nerr
}
cCtx.shellComplete = shellComplete cCtx.shellComplete = shellComplete
if checkCompletions(cCtx) { a.rootCommand = a.newRootCommand()
return nil cCtx.Command = a.rootCommand
}
if err != nil { return a.rootCommand.Run(cCtx, arguments...)
if a.OnUsageError != nil { }
err := a.OnUsageError(cCtx, err, false)
a.handleExitCoder(cCtx, err)
return err
}
_, _ = fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error())
if a.Suggest {
if suggestion, err := a.suggestFlagFromError(err, ""); err == nil {
fmt.Fprintf(a.Writer, suggestion)
}
}
if !a.HideHelp {
_ = ShowAppHelp(cCtx)
}
return err
}
if a.After != nil && !cCtx.shellComplete { // This is a stub function to keep public API unchanged from old code
defer func() { //
if afterErr := a.After(cCtx); afterErr != nil { // Deprecated: use App.Run or App.RunContext
if err != nil { func (a *App) RunAsSubcommand(ctx *Context) (err error) {
err = newMultiError(err, afterErr) return a.RunContext(ctx.Context, ctx.Args().Slice())
} else {
err = afterErr
}
}
}()
}
if !a.HideHelp && checkHelp(cCtx) {
_ = ShowAppHelp(cCtx)
return nil
}
if !a.HideVersion && checkVersion(cCtx) {
ShowVersion(cCtx)
return nil
}
cerr := cCtx.checkRequiredFlags(a.Flags)
if cerr != nil {
_ = ShowAppHelp(cCtx)
return cerr
}
if a.Before != nil && !cCtx.shellComplete {
beforeErr := a.Before(cCtx)
if beforeErr != nil {
a.handleExitCoder(cCtx, beforeErr)
err = beforeErr
return err
}
}
if err = runFlagActions(cCtx, a.Flags); err != nil {
return err
}
var c *Command
args := cCtx.Args()
if args.Present() {
name := args.First()
if a.validCommandName(name) {
c = a.Command(name)
} else {
hasDefault := a.DefaultCommand != ""
isFlagName := checkStringSliceIncludes(name, cCtx.FlagNames())
var (
isDefaultSubcommand = false
defaultHasSubcommands = false
)
if hasDefault {
dc := a.Command(a.DefaultCommand)
defaultHasSubcommands = len(dc.Subcommands) > 0
for _, dcSub := range dc.Subcommands {
if checkStringSliceIncludes(name, dcSub.Names()) {
isDefaultSubcommand = true
break
}
}
}
if isFlagName || (hasDefault && (defaultHasSubcommands && isDefaultSubcommand)) {
argsWithDefault := a.argsWithDefaultCommand(args)
if !reflect.DeepEqual(args, argsWithDefault) {
c = a.Command(argsWithDefault.First())
}
}
}
} else if a.DefaultCommand != "" {
c = a.Command(a.DefaultCommand)
}
if c != nil {
return c.Run(cCtx)
}
if a.Action == nil {
a.Action = helpCommand.Action
}
// Run default Action
err = a.Action(cCtx)
a.handleExitCoder(cCtx, err)
return err
} }
func (a *App) suggestFlagFromError(err error, command string) (string, error) { func (a *App) suggestFlagFromError(err error, command string) (string, error) {
@ -407,15 +343,17 @@ func (a *App) suggestFlagFromError(err error, command string) (string, error) {
} }
flags := a.Flags flags := a.Flags
hideHelp := a.HideHelp
if command != "" { if command != "" {
cmd := a.Command(command) cmd := a.Command(command)
if cmd == nil { if cmd == nil {
return "", err return "", err
} }
flags = cmd.Flags flags = cmd.Flags
hideHelp = hideHelp || cmd.HideHelp
} }
suggestion := SuggestFlag(flags, flag, a.HideHelp) suggestion := SuggestFlag(flags, flag, hideHelp)
if len(suggestion) == 0 { if len(suggestion) == 0 {
return "", err return "", err
} }
@ -435,120 +373,6 @@ func (a *App) RunAndExitOnError() {
} }
} }
// RunAsSubcommand invokes the subcommand given the context, parses ctx.Args() to
// generate command-specific flags
func (a *App) RunAsSubcommand(ctx *Context) (err error) {
// Setup also handles HideHelp and HideHelpCommand
a.Setup()
var newCmds []*Command
for _, c := range a.Commands {
if c.HelpName == "" {
c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
}
newCmds = append(newCmds, c)
}
a.Commands = newCmds
set, err := a.newFlagSet()
if err != nil {
return err
}
err = parseIter(set, a, ctx.Args().Tail(), ctx.shellComplete)
nerr := normalizeFlags(a.Flags, set)
cCtx := NewContext(a, set, ctx)
if nerr != nil {
_, _ = fmt.Fprintln(a.Writer, nerr)
_, _ = fmt.Fprintln(a.Writer)
if len(a.Commands) > 0 {
_ = ShowSubcommandHelp(cCtx)
} else {
_ = ShowCommandHelp(ctx, cCtx.Args().First())
}
return nerr
}
if checkCompletions(cCtx) {
return nil
}
if err != nil {
if a.OnUsageError != nil {
err = a.OnUsageError(cCtx, err, true)
a.handleExitCoder(cCtx, err)
return err
}
_, _ = fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error())
if a.Suggest {
if suggestion, err := a.suggestFlagFromError(err, cCtx.Command.Name); err == nil {
fmt.Fprintf(a.Writer, suggestion)
}
}
_ = ShowSubcommandHelp(cCtx)
return err
}
if len(a.Commands) > 0 {
if checkSubcommandHelp(cCtx) {
return nil
}
} else {
if checkCommandHelp(ctx, cCtx.Args().First()) {
return nil
}
}
cerr := cCtx.checkRequiredFlags(a.Flags)
if cerr != nil {
_ = ShowSubcommandHelp(cCtx)
return cerr
}
if a.After != nil && !cCtx.shellComplete {
defer func() {
afterErr := a.After(cCtx)
if afterErr != nil {
a.handleExitCoder(cCtx, err)
if err != nil {
err = newMultiError(err, afterErr)
} else {
err = afterErr
}
}
}()
}
if a.Before != nil && !cCtx.shellComplete {
beforeErr := a.Before(cCtx)
if beforeErr != nil {
a.handleExitCoder(cCtx, beforeErr)
err = beforeErr
return err
}
}
if err = runFlagActions(cCtx, a.Flags); err != nil {
return err
}
args := cCtx.Args()
if args.Present() {
name := args.First()
c := a.Command(name)
if c != nil {
return c.Run(cCtx)
}
}
// Run default Action
err = a.Action(cCtx)
a.handleExitCoder(cCtx, err)
return err
}
// Command returns the named command on App. Returns nil if the command does not exist // Command returns the named command on App. Returns nil if the command does not exist
func (a *App) Command(name string) *Command { func (a *App) Command(name string) *Command {
for _, c := range a.Commands { for _, c := range a.Commands {

View File

@ -22,4 +22,4 @@
// } // }
package cli package cli
//go:generate go run cmd/urfave-cli-genflags/main.go //go:generate make -C cmd/urfave-cli-genflags run

View File

@ -3,6 +3,7 @@ package cli
import ( import (
"flag" "flag"
"fmt" "fmt"
"reflect"
"sort" "sort"
"strings" "strings"
) )
@ -62,6 +63,12 @@ type Command struct {
// cli.go uses text/template to render templates. You can // cli.go uses text/template to render templates. You can
// render custom help text by setting this variable. // render custom help text by setting this variable.
CustomHelpTemplate string CustomHelpTemplate string
// categories contains the categorized commands and is populated on app startup
categories CommandCategories
// if this is a root "special" command
isRoot bool
} }
type Commands []*Command type Commands []*Command
@ -89,10 +96,21 @@ func (c *Command) FullName() string {
return strings.Join(c.commandNamePath, " ") return strings.Join(c.commandNamePath, " ")
} }
// Run invokes the command given the context, parses ctx.Args() to generate command-specific flags func (cmd *Command) Command(name string) *Command {
func (c *Command) Run(ctx *Context) (err error) { for _, c := range cmd.Subcommands {
if len(c.Subcommands) > 0 { if c.HasName(name) {
return c.startApp(ctx) return c
}
}
return nil
}
func (c *Command) setup(ctx *Context) {
if c.Command(helpCommand.Name) == nil && !c.HideHelp {
if !c.HideHelpCommand {
c.Subcommands = append(c.Subcommands, helpCommand)
}
} }
if !c.HideHelp && HelpFlag != nil { if !c.HideHelp && HelpFlag != nil {
@ -104,46 +122,72 @@ func (c *Command) Run(ctx *Context) (err error) {
c.UseShortOptionHandling = true c.UseShortOptionHandling = true
} }
set, err := c.parseFlags(ctx.Args(), ctx.shellComplete) c.categories = newCommandCategories()
for _, command := range c.Subcommands {
c.categories.AddCommand(command.Category, command)
}
sort.Sort(c.categories.(*commandCategories))
cCtx := NewContext(ctx.App, set, ctx) var newCmds []*Command
cCtx.Command = c for _, scmd := range c.Subcommands {
if checkCommandCompletions(cCtx, c.Name) { if scmd.HelpName == "" {
scmd.HelpName = fmt.Sprintf("%s %s", c.HelpName, scmd.Name)
}
newCmds = append(newCmds, scmd)
}
c.Subcommands = newCmds
}
func (c *Command) Run(cCtx *Context, arguments ...string) (err error) {
if !c.isRoot {
c.setup(cCtx)
}
a := args(arguments)
set, err := c.parseFlags(&a, cCtx.shellComplete)
cCtx.flagSet = set
if c.isRoot {
if checkCompletions(cCtx) {
return nil
}
} else if checkCommandCompletions(cCtx, c.Name) {
return nil return nil
} }
if err != nil { if err != nil {
if c.OnUsageError != nil { if c.OnUsageError != nil {
err = c.OnUsageError(cCtx, err, false) err = c.OnUsageError(cCtx, err, !c.isRoot)
cCtx.App.handleExitCoder(cCtx, err) cCtx.App.handleExitCoder(cCtx, err)
return err return err
} }
_, _ = fmt.Fprintln(cCtx.App.Writer, "Incorrect Usage:", err.Error()) _, _ = fmt.Fprintf(cCtx.App.Writer, "%s %s\n\n", "Incorrect Usage:", err.Error())
_, _ = fmt.Fprintln(cCtx.App.Writer) if cCtx.App.Suggest {
if ctx.App.Suggest { if suggestion, err := c.suggestFlagFromError(err, ""); err == nil {
if suggestion, err := ctx.App.suggestFlagFromError(err, c.Name); err == nil { fmt.Fprintf(cCtx.App.Writer, "%s", suggestion)
fmt.Fprintf(cCtx.App.Writer, suggestion)
} }
} }
if !c.HideHelp { if !c.HideHelp {
_ = ShowCommandHelp(cCtx, c.Name) if c.isRoot {
_ = ShowAppHelp(cCtx)
} else {
_ = ShowCommandHelp(cCtx.parentContext, c.Name)
}
} }
return err return err
} }
if checkCommandHelp(cCtx, c.Name) { if checkHelp(cCtx) {
return helpCommand.Action(cCtx)
}
if c.isRoot && !cCtx.App.HideVersion && checkVersion(cCtx) {
ShowVersion(cCtx)
return nil return nil
} }
cerr := cCtx.checkRequiredFlags(c.Flags) if c.After != nil && !cCtx.shellComplete {
if cerr != nil {
if !c.HideHelp {
_ = ShowCommandHelp(cCtx, c.Name)
}
return cerr
}
if c.After != nil {
defer func() { defer func() {
afterErr := c.After(cCtx) afterErr := c.After(cCtx)
if afterErr != nil { if afterErr != nil {
@ -157,10 +201,17 @@ func (c *Command) Run(ctx *Context) (err error) {
}() }()
} }
if c.Before != nil { cerr := cCtx.checkRequiredFlags(c.Flags)
err = c.Before(cCtx) if cerr != nil {
if err != nil { _ = ShowSubcommandHelp(cCtx)
cCtx.App.handleExitCoder(cCtx, err) return cerr
}
if c.Before != nil && !cCtx.shellComplete {
beforeErr := c.Before(cCtx)
if beforeErr != nil {
cCtx.App.handleExitCoder(cCtx, beforeErr)
err = beforeErr
return err return err
} }
} }
@ -169,16 +220,57 @@ func (c *Command) Run(ctx *Context) (err error) {
return err return err
} }
var cmd *Command
args := cCtx.Args()
if args.Present() {
name := args.First()
cmd = c.Command(name)
if cmd == nil {
hasDefault := cCtx.App.DefaultCommand != ""
isFlagName := checkStringSliceIncludes(name, cCtx.FlagNames())
var (
isDefaultSubcommand = false
defaultHasSubcommands = false
)
if hasDefault {
dc := cCtx.App.Command(cCtx.App.DefaultCommand)
defaultHasSubcommands = len(dc.Subcommands) > 0
for _, dcSub := range dc.Subcommands {
if checkStringSliceIncludes(name, dcSub.Names()) {
isDefaultSubcommand = true
break
}
}
}
if isFlagName || (hasDefault && (defaultHasSubcommands && isDefaultSubcommand)) {
argsWithDefault := cCtx.App.argsWithDefaultCommand(args)
if !reflect.DeepEqual(args, argsWithDefault) {
cmd = cCtx.App.rootCommand.Command(argsWithDefault.First())
}
}
}
} else if c.isRoot && cCtx.App.DefaultCommand != "" {
if dc := cCtx.App.Command(cCtx.App.DefaultCommand); dc != c {
cmd = dc
}
}
if cmd != nil {
newcCtx := NewContext(cCtx.App, nil, cCtx)
newcCtx.Command = cmd
return cmd.Run(newcCtx, cCtx.Args().Slice()...)
}
if c.Action == nil { if c.Action == nil {
c.Action = helpCommand.Action c.Action = helpCommand.Action
} }
cCtx.Command = c
err = c.Action(cCtx) err = c.Action(cCtx)
if err != nil { cCtx.App.handleExitCoder(cCtx, err)
cCtx.App.handleExitCoder(cCtx, err)
}
return err return err
} }
@ -190,6 +282,31 @@ func (c *Command) useShortOptionHandling() bool {
return c.UseShortOptionHandling return c.UseShortOptionHandling
} }
func (c *Command) suggestFlagFromError(err error, command string) (string, error) {
flag, parseErr := flagFromError(err)
if parseErr != nil {
return "", err
}
flags := c.Flags
hideHelp := c.HideHelp
if command != "" {
cmd := c.Command(command)
if cmd == nil {
return "", err
}
flags = cmd.Flags
hideHelp = hideHelp || cmd.HideHelp
}
suggestion := SuggestFlag(flags, flag, hideHelp)
if len(suggestion) == 0 {
return "", err
}
return fmt.Sprintf(SuggestDidYouMeanTemplate, suggestion) + "\n\n", nil
}
func (c *Command) parseFlags(args Args, shellComplete bool) (*flag.FlagSet, error) { func (c *Command) parseFlags(args Args, shellComplete bool) (*flag.FlagSet, error) {
set, err := c.newFlagSet() set, err := c.newFlagSet()
if err != nil { if err != nil {
@ -228,71 +345,21 @@ func (c *Command) HasName(name string) bool {
return false return false
} }
func (c *Command) startApp(ctx *Context) error { // VisibleCategories returns a slice of categories and commands that are
app := &App{ // Hidden=false
Metadata: ctx.App.Metadata, func (c *Command) VisibleCategories() []CommandCategory {
Name: fmt.Sprintf("%s %s", ctx.App.Name, c.Name), ret := []CommandCategory{}
for _, category := range c.categories.Categories() {
if visible := func() CommandCategory {
if len(category.VisibleCommands()) > 0 {
return category
}
return nil
}(); visible != nil {
ret = append(ret, visible)
}
} }
return ret
if c.HelpName == "" {
app.HelpName = c.HelpName
} else {
app.HelpName = app.Name
}
app.Usage = c.Usage
app.UsageText = c.UsageText
app.Description = c.Description
app.ArgsUsage = c.ArgsUsage
// set CommandNotFound
app.CommandNotFound = ctx.App.CommandNotFound
app.CustomAppHelpTemplate = c.CustomHelpTemplate
// set the flags and commands
app.Commands = c.Subcommands
app.Flags = c.Flags
app.HideHelp = c.HideHelp
app.HideHelpCommand = c.HideHelpCommand
app.Version = ctx.App.Version
app.HideVersion = true
app.Compiled = ctx.App.Compiled
app.Reader = ctx.App.Reader
app.Writer = ctx.App.Writer
app.ErrWriter = ctx.App.ErrWriter
app.ExitErrHandler = ctx.App.ExitErrHandler
app.UseShortOptionHandling = ctx.App.UseShortOptionHandling
app.Suggest = ctx.App.Suggest
app.categories = newCommandCategories()
for _, command := range c.Subcommands {
app.categories.AddCommand(command.Category, command)
}
sort.Sort(app.categories.(*commandCategories))
// bash completion
app.EnableBashCompletion = ctx.App.EnableBashCompletion
if c.BashComplete != nil {
app.BashComplete = c.BashComplete
}
// set the actions
app.Before = c.Before
app.After = c.After
if c.Action != nil {
app.Action = c.Action
} else {
app.Action = helpCommand.Action
}
app.OnUsageError = c.OnUsageError
for index, cc := range app.Commands {
app.Commands[index].commandNamePath = []string{c.Name, cc.Name}
}
return app.RunAsSubcommand(ctx)
} }
// VisibleCommands returns a slice of the Commands with Hidden=false // VisibleCommands returns a slice of the Commands with Hidden=false

View File

@ -82,7 +82,27 @@ func (cCtx *Context) IsSet(name string) bool {
func (cCtx *Context) LocalFlagNames() []string { func (cCtx *Context) LocalFlagNames() []string {
var names []string var names []string
cCtx.flagSet.Visit(makeFlagNameVisitor(&names)) cCtx.flagSet.Visit(makeFlagNameVisitor(&names))
return names // Check the flags which have been set via env or file
if cCtx.Command != nil && cCtx.Command.Flags != nil {
for _, f := range cCtx.Command.Flags {
if f.IsSet() {
names = append(names, f.Names()...)
}
}
}
// Sort out the duplicates since flag could be set via multiple
// paths
m := map[string]struct{}{}
var unames []string
for _, name := range names {
if _, ok := m[name]; !ok {
m[name] = struct{}{}
unames = append(unames, name)
}
}
return unames
} }
// FlagNames returns a slice of flag names used by the this context and all of // FlagNames returns a slice of flag names used by the this context and all of
@ -90,7 +110,7 @@ func (cCtx *Context) LocalFlagNames() []string {
func (cCtx *Context) FlagNames() []string { func (cCtx *Context) FlagNames() []string {
var names []string var names []string
for _, pCtx := range cCtx.Lineage() { for _, pCtx := range cCtx.Lineage() {
pCtx.flagSet.Visit(makeFlagNameVisitor(&names)) names = append(names, pCtx.LocalFlagNames()...)
} }
return names return names
} }

View File

@ -83,7 +83,7 @@ type ExitCoder interface {
type exitError struct { type exitError struct {
exitCode int exitCode int
message interface{} err error
} }
// NewExitError calls Exit to create a new ExitCoder. // NewExitError calls Exit to create a new ExitCoder.
@ -98,23 +98,38 @@ func NewExitError(message interface{}, exitCode int) ExitCoder {
// //
// This is the simplest way to trigger a non-zero exit code for an App without // This is the simplest way to trigger a non-zero exit code for an App without
// having to call os.Exit manually. During testing, this behavior can be avoided // having to call os.Exit manually. During testing, this behavior can be avoided
// by overiding the ExitErrHandler function on an App or the package-global // by overriding the ExitErrHandler function on an App or the package-global
// OsExiter function. // OsExiter function.
func Exit(message interface{}, exitCode int) ExitCoder { func Exit(message interface{}, exitCode int) ExitCoder {
var err error
switch e := message.(type) {
case ErrorFormatter:
err = fmt.Errorf("%+v", message)
case error:
err = e
default:
err = fmt.Errorf("%+v", message)
}
return &exitError{ return &exitError{
message: message, err: err,
exitCode: exitCode, exitCode: exitCode,
} }
} }
func (ee *exitError) Error() string { func (ee *exitError) Error() string {
return fmt.Sprintf("%v", ee.message) return ee.err.Error()
} }
func (ee *exitError) ExitCode() int { func (ee *exitError) ExitCode() int {
return ee.exitCode return ee.exitCode
} }
func (ee *exitError) Unwrap() error {
return ee.err
}
// HandleExitCoder handles errors implementing ExitCoder by printing their // HandleExitCoder handles errors implementing ExitCoder by printing their
// message and calling OsExiter with the given exit code. // message and calling OsExiter with the given exit code.
// //

View File

@ -98,7 +98,7 @@ func (a *App) prepareFishCommands(commands []*Command, allCommands *[]string, pr
a.prepareFishFlags(command.VisibleFlags(), command.Names())..., a.prepareFishFlags(command.VisibleFlags(), command.Names())...,
) )
// recursevly iterate subcommands // recursively iterate subcommands
if len(command.Subcommands) > 0 { if len(command.Subcommands) > 0 {
completions = append( completions = append(
completions, completions,

View File

@ -5,6 +5,7 @@ import (
"flag" "flag"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os"
"regexp" "regexp"
"runtime" "runtime"
"strings" "strings"
@ -14,6 +15,8 @@ import (
const defaultPlaceholder = "value" const defaultPlaceholder = "value"
var defaultSliceFlagSeparator = ","
var ( var (
slPfx = fmt.Sprintf("sl:::%d:::", time.Now().UTC().UnixNano()) slPfx = fmt.Sprintf("sl:::%d:::", time.Now().UTC().UnixNano())
@ -268,19 +271,23 @@ func prefixedNames(names []string, placeholder string) string {
return prefixed return prefixed
} }
func envFormat(envVars []string, prefix, sep, suffix string) string {
if len(envVars) > 0 {
return fmt.Sprintf(" [%s%s%s]", prefix, strings.Join(envVars, sep), suffix)
}
return ""
}
func defaultEnvFormat(envVars []string) string {
return envFormat(envVars, "$", ", $", "")
}
func withEnvHint(envVars []string, str string) string { func withEnvHint(envVars []string, str string) string {
envText := "" envText := ""
if len(envVars) > 0 { if runtime.GOOS != "windows" || os.Getenv("PSHOME") != "" {
prefix := "$" envText = defaultEnvFormat(envVars)
suffix := "" } else {
sep := ", $" envText = envFormat(envVars, "%", "%, %", "%")
if runtime.GOOS == "windows" {
prefix = "%"
suffix = "%"
sep = "%, %"
}
envText = fmt.Sprintf(" [%s%s%s]", prefix, strings.Join(envVars, sep), suffix)
} }
return str + envText return str + envText
} }
@ -373,5 +380,5 @@ func flagFromEnvOrFile(envVars []string, filePath string) (value string, fromWhe
} }
func flagSplitMultiValues(val string) []string { func flagSplitMultiValues(val string) []string {
return strings.Split(val, ",") return strings.Split(val, defaultSliceFlagSeparator)
} }

View File

@ -84,7 +84,7 @@ func (f *BoolFlag) GetDefaultText() string {
if f.DefaultText != "" { if f.DefaultText != "" {
return f.DefaultText return f.DefaultText
} }
return fmt.Sprintf("%v", f.Value) return fmt.Sprintf("%v", f.defaultValue)
} }
// GetEnvVars returns the env vars for this flag // GetEnvVars returns the env vars for this flag
@ -103,6 +103,9 @@ func (f *BoolFlag) RunAction(c *Context) error {
// Apply populates the flag given the flag set and environment // Apply populates the flag given the flag set and environment
func (f *BoolFlag) Apply(set *flag.FlagSet) error { func (f *BoolFlag) Apply(set *flag.FlagSet) error {
// set default value so that environment wont be able to overwrite it
f.defaultValue = f.Value
if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found { if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
if val != "" { if val != "" {
valBool, err := strconv.ParseBool(val) valBool, err := strconv.ParseBool(val)

View File

@ -32,7 +32,7 @@ func (f *DurationFlag) GetDefaultText() string {
if f.DefaultText != "" { if f.DefaultText != "" {
return f.DefaultText return f.DefaultText
} }
return f.GetValue() return f.defaultValue.String()
} }
// GetEnvVars returns the env vars for this flag // GetEnvVars returns the env vars for this flag
@ -42,6 +42,9 @@ func (f *DurationFlag) GetEnvVars() []string {
// Apply populates the flag given the flag set and environment // Apply populates the flag given the flag set and environment
func (f *DurationFlag) Apply(set *flag.FlagSet) error { func (f *DurationFlag) Apply(set *flag.FlagSet) error {
// set default value so that environment wont be able to overwrite it
f.defaultValue = f.Value
if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found { if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
if val != "" { if val != "" {
valDuration, err := time.ParseDuration(val) valDuration, err := time.ParseDuration(val)

48
vendor/github.com/urfave/cli/v2/flag_ext.go generated vendored Normal file
View File

@ -0,0 +1,48 @@
package cli
import "flag"
type extFlag struct {
f *flag.Flag
}
func (e *extFlag) Apply(fs *flag.FlagSet) error {
fs.Var(e.f.Value, e.f.Name, e.f.Usage)
return nil
}
func (e *extFlag) Names() []string {
return []string{e.f.Name}
}
func (e *extFlag) IsSet() bool {
return false
}
func (e *extFlag) String() string {
return FlagStringer(e)
}
func (e *extFlag) IsVisible() bool {
return true
}
func (e *extFlag) TakesValue() bool {
return false
}
func (e *extFlag) GetUsage() string {
return e.f.Usage
}
func (e *extFlag) GetValue() string {
return e.f.Value.String()
}
func (e *extFlag) GetDefaultText() string {
return e.f.DefValue
}
func (e *extFlag) GetEnvVars() []string {
return nil
}

View File

@ -11,6 +11,19 @@ type Generic interface {
String() string String() string
} }
type stringGeneric struct {
value string
}
func (s *stringGeneric) Set(value string) error {
s.value = value
return nil
}
func (s *stringGeneric) String() string {
return s.value
}
// TakesValue returns true of the flag takes a value, otherwise false // TakesValue returns true of the flag takes a value, otherwise false
func (f *GenericFlag) TakesValue() bool { func (f *GenericFlag) TakesValue() bool {
return true return true
@ -40,7 +53,10 @@ func (f *GenericFlag) GetDefaultText() string {
if f.DefaultText != "" { if f.DefaultText != "" {
return f.DefaultText return f.DefaultText
} }
return f.GetValue() if f.defaultValue != nil {
return f.defaultValue.String()
}
return ""
} }
// GetEnvVars returns the env vars for this flag // GetEnvVars returns the env vars for this flag
@ -51,6 +67,11 @@ func (f *GenericFlag) GetEnvVars() []string {
// Apply takes the flagset and calls Set on the generic flag with the value // Apply takes the flagset and calls Set on the generic flag with the value
// provided by the user for parsing by the flag // provided by the user for parsing by the flag
func (f *GenericFlag) Apply(set *flag.FlagSet) error { func (f *GenericFlag) Apply(set *flag.FlagSet) error {
// set default value so that environment wont be able to overwrite it
if f.Value != nil {
f.defaultValue = &stringGeneric{value: f.Value.String()}
}
if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found { if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
if val != "" { if val != "" {
if err := f.Value.Set(val); err != nil { if err := f.Value.Set(val); err != nil {

View File

@ -32,7 +32,7 @@ func (f *IntFlag) GetDefaultText() string {
if f.DefaultText != "" { if f.DefaultText != "" {
return f.DefaultText return f.DefaultText
} }
return f.GetValue() return fmt.Sprintf("%d", f.defaultValue)
} }
// GetEnvVars returns the env vars for this flag // GetEnvVars returns the env vars for this flag
@ -42,6 +42,9 @@ func (f *IntFlag) GetEnvVars() []string {
// Apply populates the flag given the flag set and environment // Apply populates the flag given the flag set and environment
func (f *IntFlag) Apply(set *flag.FlagSet) error { func (f *IntFlag) Apply(set *flag.FlagSet) error {
// set default value so that environment wont be able to overwrite it
f.defaultValue = f.Value
if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found { if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
if val != "" { if val != "" {
valInt, err := strconv.ParseInt(val, f.Base, 64) valInt, err := strconv.ParseInt(val, f.Base, 64)

View File

@ -32,7 +32,7 @@ func (f *Int64Flag) GetDefaultText() string {
if f.DefaultText != "" { if f.DefaultText != "" {
return f.DefaultText return f.DefaultText
} }
return f.GetValue() return fmt.Sprintf("%d", f.defaultValue)
} }
// GetEnvVars returns the env vars for this flag // GetEnvVars returns the env vars for this flag
@ -42,6 +42,9 @@ func (f *Int64Flag) GetEnvVars() []string {
// Apply populates the flag given the flag set and environment // Apply populates the flag given the flag set and environment
func (f *Int64Flag) Apply(set *flag.FlagSet) error { func (f *Int64Flag) Apply(set *flag.FlagSet) error {
// set default value so that environment wont be able to overwrite it
f.defaultValue = f.Value
if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found { if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
if val != "" { if val != "" {
valInt, err := strconv.ParseInt(val, f.Base, 64) valInt, err := strconv.ParseInt(val, f.Base, 64)

View File

@ -33,10 +33,10 @@ func (f *PathFlag) GetDefaultText() string {
if f.DefaultText != "" { if f.DefaultText != "" {
return f.DefaultText return f.DefaultText
} }
if f.Value == "" { if f.defaultValue == "" {
return f.Value return f.defaultValue
} }
return fmt.Sprintf("%q", f.Value) return fmt.Sprintf("%q", f.defaultValue)
} }
// GetEnvVars returns the env vars for this flag // GetEnvVars returns the env vars for this flag
@ -46,6 +46,9 @@ func (f *PathFlag) GetEnvVars() []string {
// Apply populates the flag given the flag set and environment // Apply populates the flag given the flag set and environment
func (f *PathFlag) Apply(set *flag.FlagSet) error { func (f *PathFlag) Apply(set *flag.FlagSet) error {
// set default value so that environment wont be able to overwrite it
f.defaultValue = f.Value
if val, _, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found { if val, _, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
f.Value = val f.Value = val
f.HasBeenSet = true f.HasBeenSet = true

View File

@ -31,10 +31,10 @@ func (f *StringFlag) GetDefaultText() string {
if f.DefaultText != "" { if f.DefaultText != "" {
return f.DefaultText return f.DefaultText
} }
if f.Value == "" { if f.defaultValue == "" {
return f.Value return f.defaultValue
} }
return fmt.Sprintf("%q", f.Value) return fmt.Sprintf("%q", f.defaultValue)
} }
// GetEnvVars returns the env vars for this flag // GetEnvVars returns the env vars for this flag
@ -44,6 +44,9 @@ func (f *StringFlag) GetEnvVars() []string {
// Apply populates the flag given the flag set and environment // Apply populates the flag given the flag set and environment
func (f *StringFlag) Apply(set *flag.FlagSet) error { func (f *StringFlag) Apply(set *flag.FlagSet) error {
// set default value so that environment wont be able to overwrite it
f.defaultValue = f.Value
if val, _, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found { if val, _, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
f.Value = val f.Value = val
f.HasBeenSet = true f.HasBeenSet = true

View File

@ -72,6 +72,25 @@ func (t *Timestamp) Get() interface{} {
return *t return *t
} }
// clone timestamp
func (t *Timestamp) clone() *Timestamp {
tc := &Timestamp{
timestamp: nil,
hasBeenSet: t.hasBeenSet,
layout: t.layout,
location: nil,
}
if t.timestamp != nil {
tts := *t.timestamp
tc.timestamp = &tts
}
if t.location != nil {
loc := *t.location
tc.location = &loc
}
return tc
}
// TakesValue returns true of the flag takes a value, otherwise false // TakesValue returns true of the flag takes a value, otherwise false
func (f *TimestampFlag) TakesValue() bool { func (f *TimestampFlag) TakesValue() bool {
return true return true
@ -101,7 +120,11 @@ func (f *TimestampFlag) GetDefaultText() string {
if f.DefaultText != "" { if f.DefaultText != "" {
return f.DefaultText return f.DefaultText
} }
return f.GetValue() if f.defaultValue != nil && f.defaultValue.timestamp != nil {
return f.defaultValue.timestamp.String()
}
return ""
} }
// GetEnvVars returns the env vars for this flag // GetEnvVars returns the env vars for this flag
@ -120,6 +143,8 @@ func (f *TimestampFlag) Apply(set *flag.FlagSet) error {
f.Value.SetLayout(f.Layout) f.Value.SetLayout(f.Layout)
f.Value.SetLocation(f.Timezone) f.Value.SetLocation(f.Timezone)
f.defaultValue = f.Value.clone()
if f.Destination != nil { if f.Destination != nil {
f.Destination.SetLayout(f.Layout) f.Destination.SetLayout(f.Layout)
f.Destination.SetLocation(f.Timezone) f.Destination.SetLocation(f.Timezone)

View File

@ -23,6 +23,9 @@ func (f *UintFlag) GetCategory() string {
// Apply populates the flag given the flag set and environment // Apply populates the flag given the flag set and environment
func (f *UintFlag) Apply(set *flag.FlagSet) error { func (f *UintFlag) Apply(set *flag.FlagSet) error {
// set default value so that environment wont be able to overwrite it
f.defaultValue = f.Value
if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found { if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
if val != "" { if val != "" {
valInt, err := strconv.ParseUint(val, f.Base, 64) valInt, err := strconv.ParseUint(val, f.Base, 64)
@ -66,7 +69,7 @@ func (f *UintFlag) GetDefaultText() string {
if f.DefaultText != "" { if f.DefaultText != "" {
return f.DefaultText return f.DefaultText
} }
return f.GetValue() return fmt.Sprintf("%d", f.defaultValue)
} }
// GetEnvVars returns the env vars for this flag // GetEnvVars returns the env vars for this flag

View File

@ -23,6 +23,9 @@ func (f *Uint64Flag) GetCategory() string {
// Apply populates the flag given the flag set and environment // Apply populates the flag given the flag set and environment
func (f *Uint64Flag) Apply(set *flag.FlagSet) error { func (f *Uint64Flag) Apply(set *flag.FlagSet) error {
// set default value so that environment wont be able to overwrite it
f.defaultValue = f.Value
if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found { if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
if val != "" { if val != "" {
valInt, err := strconv.ParseUint(val, f.Base, 64) valInt, err := strconv.ParseUint(val, f.Base, 64)
@ -66,7 +69,7 @@ func (f *Uint64Flag) GetDefaultText() string {
if f.DefaultText != "" { if f.DefaultText != "" {
return f.DefaultText return f.DefaultText
} }
return f.GetValue() return fmt.Sprintf("%d", f.defaultValue)
} }
// GetEnvVars returns the env vars for this flag // GetEnvVars returns the env vars for this flag

View File

@ -136,7 +136,7 @@ var SubcommandHelpTemplate = `NAME:
{{template "helpNameTemplate" .}} {{template "helpNameTemplate" .}}
USAGE: USAGE:
{{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}} command{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Description}} {{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}} {{if .VisibleFlags}}command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Description}}
DESCRIPTION: DESCRIPTION:
{{template "descriptionTemplate" .}}{{end}}{{if .VisibleCommands}} {{template "descriptionTemplate" .}}{{end}}{{if .VisibleCommands}}
@ -316,12 +316,19 @@ type App struct {
// cli.go uses text/template to render templates. You can // cli.go uses text/template to render templates. You can
// render custom help text by setting this variable. // render custom help text by setting this variable.
CustomAppHelpTemplate string CustomAppHelpTemplate string
// SliceFlagSeparator is used to customize the separator for SliceFlag, the default is ","
SliceFlagSeparator string
// Boolean to enable short-option handling so user can combine several // Boolean to enable short-option handling so user can combine several
// single-character bool arguments into one // single-character bool arguments into one
// i.e. foobar -o -v -> foobar -ov // i.e. foobar -o -v -> foobar -ov
UseShortOptionHandling bool UseShortOptionHandling bool
// Enable suggestions for commands and flags // Enable suggestions for commands and flags
Suggest bool Suggest bool
// Allows global flags set by libraries which use flag.XXXVar(...) directly
// to be parsed through this library
AllowExtFlags bool
// Treat all flags as normal arguments if true
SkipFlagParsing bool
// Has unexported fields. // Has unexported fields.
} }
@ -348,8 +355,9 @@ func (a *App) RunAndExitOnError()
code in the cli.ExitCoder code in the cli.ExitCoder
func (a *App) RunAsSubcommand(ctx *Context) (err error) func (a *App) RunAsSubcommand(ctx *Context) (err error)
RunAsSubcommand invokes the subcommand given the context, parses ctx.Args() This is a stub function to keep public API unchanged from old code
to generate command-specific flags
Deprecated: use App.Run or App.RunContext
func (a *App) RunContext(ctx context.Context, arguments []string) (err error) func (a *App) RunContext(ctx context.Context, arguments []string) (err error)
RunContext is like Run except it takes a Context that will be passed to RunContext is like Run except it takes a Context that will be passed to
@ -446,6 +454,7 @@ type BoolFlag struct {
Count *int Count *int
Action func(*Context, bool) error Action func(*Context, bool) error
// Has unexported fields.
} }
BoolFlag is a flag with type bool BoolFlag is a flag with type bool
@ -553,10 +562,13 @@ type Command struct {
// cli.go uses text/template to render templates. You can // cli.go uses text/template to render templates. You can
// render custom help text by setting this variable. // render custom help text by setting this variable.
CustomHelpTemplate string CustomHelpTemplate string
// Has unexported fields. // Has unexported fields.
} }
Command is a subcommand for a cli.App. Command is a subcommand for a cli.App.
func (cmd *Command) Command(name string) *Command
func (c *Command) FullName() string func (c *Command) FullName() string
FullName returns the full name of the command. For subcommands this ensures FullName returns the full name of the command. For subcommands this ensures
that parent commands are part of the command path that parent commands are part of the command path
@ -567,9 +579,11 @@ func (c *Command) HasName(name string) bool
func (c *Command) Names() []string func (c *Command) Names() []string
Names returns the names including short names and aliases. Names returns the names including short names and aliases.
func (c *Command) Run(ctx *Context) (err error) func (c *Command) Run(cCtx *Context, arguments ...string) (err error)
Run invokes the command given the context, parses ctx.Args() to generate
command-specific flags func (c *Command) VisibleCategories() []CommandCategory
VisibleCategories returns a slice of categories and commands that are
Hidden=false
func (c *Command) VisibleCommands() []*Command func (c *Command) VisibleCommands() []*Command
VisibleCommands returns a slice of the Commands with Hidden=false VisibleCommands returns a slice of the Commands with Hidden=false
@ -769,6 +783,7 @@ type DurationFlag struct {
EnvVars []string EnvVars []string
Action func(*Context, time.Duration) error Action func(*Context, time.Duration) error
// Has unexported fields.
} }
DurationFlag is a flag with type time.Duration DurationFlag is a flag with type time.Duration
@ -833,7 +848,7 @@ func Exit(message interface{}, exitCode int) ExitCoder
This is the simplest way to trigger a non-zero exit code for an App This is the simplest way to trigger a non-zero exit code for an App
without having to call os.Exit manually. During testing, this behavior without having to call os.Exit manually. During testing, this behavior
can be avoided by overiding the ExitErrHandler function on an App or the can be avoided by overriding the ExitErrHandler function on an App or the
package-global OsExiter function. package-global OsExiter function.
func NewExitError(message interface{}, exitCode int) ExitCoder func NewExitError(message interface{}, exitCode int) ExitCoder
@ -947,6 +962,7 @@ type Float64Flag struct {
EnvVars []string EnvVars []string
Action func(*Context, float64) error Action func(*Context, float64) error
// Has unexported fields.
} }
Float64Flag is a flag with type float64 Float64Flag is a flag with type float64
@ -1035,6 +1051,7 @@ type Float64SliceFlag struct {
EnvVars []string EnvVars []string
Action func(*Context, []float64) error Action func(*Context, []float64) error
// Has unexported fields.
} }
Float64SliceFlag is a flag with type *Float64Slice Float64SliceFlag is a flag with type *Float64Slice
@ -1117,6 +1134,7 @@ type GenericFlag struct {
TakesFile bool TakesFile bool
Action func(*Context, interface{}) error Action func(*Context, interface{}) error
// Has unexported fields.
} }
GenericFlag is a flag with type Generic GenericFlag is a flag with type Generic
@ -1185,6 +1203,7 @@ type Int64Flag struct {
Base int Base int
Action func(*Context, int64) error Action func(*Context, int64) error
// Has unexported fields.
} }
Int64Flag is a flag with type int64 Int64Flag is a flag with type int64
@ -1273,6 +1292,7 @@ type Int64SliceFlag struct {
EnvVars []string EnvVars []string
Action func(*Context, []int64) error Action func(*Context, []int64) error
// Has unexported fields.
} }
Int64SliceFlag is a flag with type *Int64Slice Int64SliceFlag is a flag with type *Int64Slice
@ -1349,6 +1369,7 @@ type IntFlag struct {
Base int Base int
Action func(*Context, int) error Action func(*Context, int) error
// Has unexported fields.
} }
IntFlag is a flag with type int IntFlag is a flag with type int
@ -1441,6 +1462,7 @@ type IntSliceFlag struct {
EnvVars []string EnvVars []string
Action func(*Context, []int) error Action func(*Context, []int) error
// Has unexported fields.
} }
IntSliceFlag is a flag with type *IntSlice IntSliceFlag is a flag with type *IntSlice
@ -1551,6 +1573,7 @@ type PathFlag struct {
TakesFile bool TakesFile bool
Action func(*Context, Path) error Action func(*Context, Path) error
// Has unexported fields.
} }
PathFlag is a flag with type Path PathFlag is a flag with type Path
@ -1693,6 +1716,7 @@ type StringFlag struct {
TakesFile bool TakesFile bool
Action func(*Context, string) error Action func(*Context, string) error
// Has unexported fields.
} }
StringFlag is a flag with type string StringFlag is a flag with type string
@ -1783,6 +1807,7 @@ type StringSliceFlag struct {
TakesFile bool TakesFile bool
Action func(*Context, []string) error Action func(*Context, []string) error
// Has unexported fields.
} }
StringSliceFlag is a flag with type *StringSlice StringSliceFlag is a flag with type *StringSlice
@ -1894,6 +1919,7 @@ type TimestampFlag struct {
Timezone *time.Location Timezone *time.Location
Action func(*Context, *time.Time) error Action func(*Context, *time.Time) error
// Has unexported fields.
} }
TimestampFlag is a flag with type *Timestamp TimestampFlag is a flag with type *Timestamp
@ -1961,6 +1987,7 @@ type Uint64Flag struct {
Base int Base int
Action func(*Context, uint64) error Action func(*Context, uint64) error
// Has unexported fields.
} }
Uint64Flag is a flag with type uint64 Uint64Flag is a flag with type uint64
@ -2049,6 +2076,7 @@ type Uint64SliceFlag struct {
EnvVars []string EnvVars []string
Action func(*Context, []uint64) error Action func(*Context, []uint64) error
// Has unexported fields.
} }
Uint64SliceFlag is a flag with type *Uint64Slice Uint64SliceFlag is a flag with type *Uint64Slice
@ -2116,6 +2144,7 @@ type UintFlag struct {
Base int Base int
Action func(*Context, uint) error Action func(*Context, uint) error
// Has unexported fields.
} }
UintFlag is a flag with type uint UintFlag is a flag with type uint
@ -2208,6 +2237,7 @@ type UintSliceFlag struct {
EnvVars []string EnvVars []string
Action func(*Context, []uint) error Action func(*Context, []uint) error
// Has unexported fields.
} }
UintSliceFlag is a flag with type *UintSlice UintSliceFlag is a flag with type *UintSlice
@ -2407,6 +2437,7 @@ type InputSourceContext interface {
String(name string) (string, error) String(name string) (string, error)
StringSlice(name string) ([]string, error) StringSlice(name string) ([]string, error)
IntSlice(name string) ([]int, error) IntSlice(name string) ([]int, error)
Int64Slice(name string) ([]int64, error)
Generic(name string) (cli.Generic, error) Generic(name string) (cli.Generic, error)
Bool(name string) (bool, error) Bool(name string) (bool, error)
@ -2464,6 +2495,9 @@ func (f *Int64SliceFlag) Apply(set *flag.FlagSet) error
Apply saves the flagSet for later usage calls, then calls the wrapped Apply saves the flagSet for later usage calls, then calls the wrapped
Int64SliceFlag.Apply Int64SliceFlag.Apply
func (f *Int64SliceFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error
ApplyInputSourceValue applies a Int64Slice value if required
type IntFlag struct { type IntFlag struct {
*cli.IntFlag *cli.IntFlag
// Has unexported fields. // Has unexported fields.
@ -2524,6 +2558,10 @@ func (fsm *MapInputSource) Generic(name string) (cli.Generic, error)
func (fsm *MapInputSource) Int(name string) (int, error) func (fsm *MapInputSource) Int(name string) (int, error)
Int returns an int from the map if it exists otherwise returns 0 Int returns an int from the map if it exists otherwise returns 0
func (fsm *MapInputSource) Int64Slice(name string) ([]int64, error)
Int64Slice returns an []int64 from the map if it exists otherwise returns
nil
func (fsm *MapInputSource) IntSlice(name string) ([]int, error) func (fsm *MapInputSource) IntSlice(name string) ([]int, error)
IntSlice returns an []int from the map if it exists otherwise returns nil IntSlice returns an []int from the map if it exists otherwise returns nil

View File

@ -60,7 +60,7 @@ var helpCommand = &Command{
} }
// Case 1 & 2 // Case 1 & 2
// Special case when running help on main app itself as opposed to indivdual // Special case when running help on main app itself as opposed to individual
// commands/subcommands // commands/subcommands
if cCtx.parentContext.App == nil { if cCtx.parentContext.App == nil {
_ = ShowAppHelp(cCtx) _ = ShowAppHelp(cCtx)
@ -68,6 +68,15 @@ var helpCommand = &Command{
} }
// Case 3, 5 // Case 3, 5
if (len(cCtx.Command.Subcommands) == 1 && !cCtx.Command.HideHelp) ||
(len(cCtx.Command.Subcommands) == 0 && cCtx.Command.HideHelp) {
templ := cCtx.Command.CustomHelpTemplate
if templ == "" {
templ = CommandHelpTemplate
}
HelpPrinter(cCtx.App.Writer, templ, cCtx.Command)
return nil
}
return ShowSubcommandHelp(cCtx) return ShowSubcommandHelp(cCtx)
}, },
} }
@ -179,7 +188,7 @@ func printFlagSuggestions(lastArg string, flags []Flag, writer io.Writer) {
// this will get total count utf8 letters in flag name // this will get total count utf8 letters in flag name
count := utf8.RuneCountInString(name) count := utf8.RuneCountInString(name)
if count > 2 { if count > 2 {
count = 2 // resuse this count to generate single - or -- in flag completion count = 2 // reuse this count to generate single - or -- in flag completion
} }
// if flag name has more than one utf8 letter and last argument in cli has -- prefix then // if flag name has more than one utf8 letter and last argument in cli has -- prefix then
// skip flag completion for short flags example -v or -x // skip flag completion for short flags example -v or -x
@ -230,15 +239,14 @@ func ShowCommandHelpAndExit(c *Context, command string, code int) {
// ShowCommandHelp prints help for the given command // ShowCommandHelp prints help for the given command
func ShowCommandHelp(ctx *Context, command string) error { func ShowCommandHelp(ctx *Context, command string) error {
// show the subcommand help for a command with subcommands
if command == "" {
HelpPrinter(ctx.App.Writer, SubcommandHelpTemplate, ctx.App)
return nil
}
for _, c := range ctx.App.Commands { commands := ctx.App.Commands
if ctx.Command.Subcommands != nil {
commands = ctx.Command.Subcommands
}
for _, c := range commands {
if c.HasName(command) { if c.HasName(command) {
if !ctx.App.HideHelpCommand && !c.HasName(helpName) && len(c.Subcommands) != 0 { if !ctx.App.HideHelpCommand && !c.HasName(helpName) && len(c.Subcommands) != 0 && c.Command(helpName) == nil {
c.Subcommands = append(c.Subcommands, helpCommandDontUse) c.Subcommands = append(c.Subcommands, helpCommandDontUse)
} }
if !ctx.App.HideHelp && HelpFlag != nil { if !ctx.App.HideHelp && HelpFlag != nil {
@ -262,7 +270,7 @@ func ShowCommandHelp(ctx *Context, command string) error {
if ctx.App.CommandNotFound == nil { if ctx.App.CommandNotFound == nil {
errMsg := fmt.Sprintf("No help topic for '%v'", command) errMsg := fmt.Sprintf("No help topic for '%v'", command)
if ctx.App.Suggest { if ctx.App.Suggest {
if suggestion := SuggestCommand(ctx.App.Commands, command); suggestion != "" { if suggestion := SuggestCommand(ctx.Command.Subcommands, command); suggestion != "" {
errMsg += ". " + suggestion errMsg += ". " + suggestion
} }
} }
@ -285,11 +293,8 @@ func ShowSubcommandHelp(cCtx *Context) error {
return nil return nil
} }
if cCtx.Command != nil { HelpPrinter(cCtx.App.Writer, SubcommandHelpTemplate, cCtx.Command)
return ShowCommandHelp(cCtx, cCtx.Command.Name) return nil
}
return ShowCommandHelp(cCtx, "")
} }
// ShowVersion prints the version number of the App // ShowVersion prints the version number of the App
@ -401,8 +406,10 @@ func checkHelp(cCtx *Context) bool {
for _, name := range HelpFlag.Names() { for _, name := range HelpFlag.Names() {
if cCtx.Bool(name) { if cCtx.Bool(name) {
found = true found = true
break
} }
} }
return found return found
} }

View File

@ -83,7 +83,7 @@ var SubcommandHelpTemplate = `NAME:
{{template "helpNameTemplate" .}} {{template "helpNameTemplate" .}}
USAGE: USAGE:
{{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}} command{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Description}} {{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}} {{if .VisibleFlags}}command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Description}}
DESCRIPTION: DESCRIPTION:
{{template "descriptionTemplate" .}}{{end}}{{if .VisibleCommands}} {{template "descriptionTemplate" .}}{{end}}{{if .VisibleCommands}}

View File

@ -23,6 +23,8 @@ type Float64SliceFlag struct {
Aliases []string Aliases []string
EnvVars []string EnvVars []string
defaultValue *Float64Slice
Action func(*Context, []float64) error Action func(*Context, []float64) error
} }
@ -65,6 +67,8 @@ type GenericFlag struct {
Aliases []string Aliases []string
EnvVars []string EnvVars []string
defaultValue Generic
TakesFile bool TakesFile bool
Action func(*Context, interface{}) error Action func(*Context, interface{}) error
@ -114,6 +118,8 @@ type Int64SliceFlag struct {
Aliases []string Aliases []string
EnvVars []string EnvVars []string
defaultValue *Int64Slice
Action func(*Context, []int64) error Action func(*Context, []int64) error
} }
@ -156,6 +162,8 @@ type IntSliceFlag struct {
Aliases []string Aliases []string
EnvVars []string EnvVars []string
defaultValue *IntSlice
Action func(*Context, []int) error Action func(*Context, []int) error
} }
@ -198,6 +206,8 @@ type PathFlag struct {
Aliases []string Aliases []string
EnvVars []string EnvVars []string
defaultValue Path
TakesFile bool TakesFile bool
Action func(*Context, Path) error Action func(*Context, Path) error
@ -247,6 +257,8 @@ type StringSliceFlag struct {
Aliases []string Aliases []string
EnvVars []string EnvVars []string
defaultValue *StringSlice
TakesFile bool TakesFile bool
Action func(*Context, []string) error Action func(*Context, []string) error
@ -291,6 +303,8 @@ type TimestampFlag struct {
Aliases []string Aliases []string
EnvVars []string EnvVars []string
defaultValue *Timestamp
Layout string Layout string
Timezone *time.Location Timezone *time.Location
@ -342,6 +356,8 @@ type Uint64SliceFlag struct {
Aliases []string Aliases []string
EnvVars []string EnvVars []string
defaultValue *Uint64Slice
Action func(*Context, []uint64) error Action func(*Context, []uint64) error
} }
@ -384,6 +400,8 @@ type UintSliceFlag struct {
Aliases []string Aliases []string
EnvVars []string EnvVars []string
defaultValue *UintSlice
Action func(*Context, []uint) error Action func(*Context, []uint) error
} }
@ -426,6 +444,8 @@ type BoolFlag struct {
Aliases []string Aliases []string
EnvVars []string EnvVars []string
defaultValue bool
Count *int Count *int
Action func(*Context, bool) error Action func(*Context, bool) error
@ -475,6 +495,8 @@ type Float64Flag struct {
Aliases []string Aliases []string
EnvVars []string EnvVars []string
defaultValue float64
Action func(*Context, float64) error Action func(*Context, float64) error
} }
@ -522,6 +544,8 @@ type IntFlag struct {
Aliases []string Aliases []string
EnvVars []string EnvVars []string
defaultValue int
Base int Base int
Action func(*Context, int) error Action func(*Context, int) error
@ -571,6 +595,8 @@ type Int64Flag struct {
Aliases []string Aliases []string
EnvVars []string EnvVars []string
defaultValue int64
Base int Base int
Action func(*Context, int64) error Action func(*Context, int64) error
@ -620,6 +646,8 @@ type StringFlag struct {
Aliases []string Aliases []string
EnvVars []string EnvVars []string
defaultValue string
TakesFile bool TakesFile bool
Action func(*Context, string) error Action func(*Context, string) error
@ -669,6 +697,8 @@ type DurationFlag struct {
Aliases []string Aliases []string
EnvVars []string EnvVars []string
defaultValue time.Duration
Action func(*Context, time.Duration) error Action func(*Context, time.Duration) error
} }
@ -716,6 +746,8 @@ type UintFlag struct {
Aliases []string Aliases []string
EnvVars []string EnvVars []string
defaultValue uint
Base int Base int
Action func(*Context, uint) error Action func(*Context, uint) error
@ -765,6 +797,8 @@ type Uint64Flag struct {
Aliases []string Aliases []string
EnvVars []string EnvVars []string
defaultValue uint64
Base int Base int
Action func(*Context, uint64) error Action func(*Context, uint64) error

2
vendor/modules.txt vendored
View File

@ -4,7 +4,7 @@ github.com/cpuguy83/go-md2man/v2/md2man
# github.com/russross/blackfriday/v2 v2.1.0 # github.com/russross/blackfriday/v2 v2.1.0
## explicit ## explicit
github.com/russross/blackfriday/v2 github.com/russross/blackfriday/v2
# github.com/urfave/cli/v2 v2.19.2 # github.com/urfave/cli/v2 v2.23.5
## explicit; go 1.18 ## explicit; go 1.18
github.com/urfave/cli/v2 github.com/urfave/cli/v2
# github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 # github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673