build(deps): bump github.com/urfave/cli/v3 from 3.9.1 to 3.10.0

Bumps [github.com/urfave/cli/v3](https://github.com/urfave/cli) from 3.9.1 to 3.10.0.
- [Release notes](https://github.com/urfave/cli/releases)
- [Changelog](https://github.com/urfave/cli/blob/main/docs/CHANGELOG.md)
- [Commits](https://github.com/urfave/cli/compare/v3.9.1...v3.10.0)

---
updated-dependencies:
- dependency-name: github.com/urfave/cli/v3
  dependency-version: 3.10.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
dependabot[bot]
2026-06-15 04:52:27 +00:00
committed by GitHub
parent 122fb7a642
commit 8c112e2f63
14 changed files with 306 additions and 75 deletions
+1 -1
View File
@@ -20,7 +20,7 @@ require (
github.com/opencontainers/selinux v1.15.1 github.com/opencontainers/selinux v1.15.1
github.com/seccomp/libseccomp-golang v0.11.1 github.com/seccomp/libseccomp-golang v0.11.1
github.com/sirupsen/logrus v1.9.4 github.com/sirupsen/logrus v1.9.4
github.com/urfave/cli/v3 v3.9.1 github.com/urfave/cli/v3 v3.10.0
github.com/vishvananda/netlink v1.3.1 github.com/vishvananda/netlink v1.3.1
github.com/vishvananda/netns v0.0.5 github.com/vishvananda/netns v0.0.5
golang.org/x/net v0.56.0 golang.org/x/net v0.56.0
+2 -2
View File
@@ -60,8 +60,8 @@ github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/urfave/cli/v3 v3.9.1 h1:OLU13atWZ0M+a4xmyBuBNOLZsSRYXyPeMeNjOvgYP54= github.com/urfave/cli/v3 v3.10.0 h1:0aU8yOObVDMkM13Cj4G+zb4P0PdeJMec65f81Ak1ioM=
github.com/urfave/cli/v3 v3.9.1/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso= github.com/urfave/cli/v3 v3.10.0/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso=
github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW6bV0= github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW6bV0=
github.com/vishvananda/netlink v1.3.1/go.mod h1:ARtKouGSTGchR8aMwmkzC0qiNPrrWO5JS/XMVl45+b4= github.com/vishvananda/netlink v1.3.1/go.mod h1:ARtKouGSTGchR8aMwmkzC0qiNPrrWO5JS/XMVl45+b4=
github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY= github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY=
+38 -14
View File
@@ -161,21 +161,12 @@ type Command struct {
globaHelpFlagAdded bool globaHelpFlagAdded bool
// whether global version flag was added // whether global version flag was added
globaVersionFlagAdded bool globaVersionFlagAdded bool
// generated root version flag
versionFlag Flag
// whether this is a completion command // whether this is a completion command
isCompletionCommand bool isCompletionCommand bool
} // whether this is the built-in help command
builtInHelp bool
// FullName returns the full name of the command.
// For commands with parents this ensures that the parent commands
// are part of the command path.
func (cmd *Command) FullName() string {
namePath := []string{}
if cmd.parent != nil {
namePath = append(namePath, cmd.parent.FullName())
}
return strings.Join(append(namePath, cmd.Name), " ")
} }
func (cmd *Command) Command(name string) *Command { func (cmd *Command) Command(name string) *Command {
@@ -430,7 +421,7 @@ func (cmd *Command) checkAllRequiredFlags() requiredFlagsErr {
// The help and completion commands are allowed to run without // The help and completion commands are allowed to run without
// enforcement of required flags, since they do not invoke user // enforcement of required flags, since they do not invoke user
// actions that depend on those flag values. // actions that depend on those flag values.
if cmd.Name == helpName || cmd.isCompletionCommand { if cmd.builtInHelp || cmd.isCompletionCommand {
return nil return nil
} }
for pCmd := cmd; pCmd != nil; pCmd = pCmd.parent { for pCmd := cmd; pCmd != nil; pCmd = pCmd.parent {
@@ -575,6 +566,39 @@ func (cmd *Command) Lineage() []*Command {
return lineage return lineage
} }
// FullName returns the full name of the command.
// Includes parent commands separated by space.
func (cmd *Command) FullName() string {
return strings.Join(cmd.Path(), " ")
}
// Path returns the path of command names from the root to cmd, inclusive.
// Each element is a Command.Name. Path traverses upward via parent pointers
// similar to Lineage. FullName() is equivalent to strings.Join(cmd.Path(), " ").
func (cmd *Command) Path() []string {
if cmd.parent != nil {
return append(cmd.parent.Path(), cmd.Name)
}
return []string{cmd.Name}
}
// Walk visits cmd and every descendant. If fn returns a non-nil error, the
// walk terminates and the error is returned to the caller.
func (cmd *Command) Walk(fn func(*Command) error) error {
if fn == nil {
return nil
}
if err := fn(cmd); err != nil {
return err
}
for _, sub := range cmd.Commands {
if err := sub.Walk(fn); err != nil {
return err
}
}
return nil
}
// Count returns the num of occurrences of this flag // Count returns the num of occurrences of this flag
func (cmd *Command) Count(name string) int { func (cmd *Command) Count(name string) int {
if cf, ok := cmd.lookupFlag(name).(Countable); ok { if cf, ok := cmd.lookupFlag(name).(Countable); ok {
+66 -22
View File
@@ -9,6 +9,8 @@ import (
"unicode" "unicode"
) )
type helpShownKey struct{}
func (cmd *Command) parseArgsFromStdin() ([]string, error) { func (cmd *Command) parseArgsFromStdin() ([]string, error) {
type state int type state int
const ( const (
@@ -161,7 +163,12 @@ func (cmd *Command) run(ctx context.Context, osArgs []string) (_ context.Context
tracef("using post-parse arguments %[1]q (cmd=%[2]q)", args, cmd.Name) tracef("using post-parse arguments %[1]q (cmd=%[2]q)", args, cmd.Name)
if checkCompletions(ctx, cmd) { if shouldRunCompletion(cmd) {
var beforeErr error
if ctx, beforeErr = runBefore(ctx, commandChain(cmd)); beforeErr != nil {
return ctx, beforeErr
}
runCompletion(ctx, cmd)
return ctx, nil return ctx, nil
} }
@@ -170,6 +177,15 @@ func (cmd *Command) run(ctx context.Context, osArgs []string) (_ context.Context
deferErr = err deferErr = err
cmd.isInError = true cmd.isInError = true
if cmd.checkHelp() {
ctx = context.WithValue(ctx, helpShownKey{}, true)
if cmd.parent == nil {
_ = ShowRootCommandHelp(cmd)
} else {
_ = ShowSubcommandHelp(cmd)
}
return ctx, nil
}
if cmd.OnUsageError != nil { if cmd.OnUsageError != nil {
err = cmd.OnUsageError(ctx, cmd, err, cmd.parent != nil) err = cmd.OnUsageError(ctx, cmd, err, cmd.parent != nil)
err = cmd.handleExitCoder(ctx, err) err = cmd.handleExitCoder(ctx, err)
@@ -188,10 +204,8 @@ func (cmd *Command) run(ctx context.Context, osArgs []string) (_ context.Context
tracef("SILENTLY IGNORING ERROR running ShowRootCommandHelp %[1]v (cmd=%[2]q)", err, cmd.Name) tracef("SILENTLY IGNORING ERROR running ShowRootCommandHelp %[1]v (cmd=%[2]q)", err, cmd.Name)
} }
} else { } else {
tracef("running ShowCommandHelp with %[1]q", cmd.Name) tracef("running ShowSubcommandHelp for %[1]q", cmd.Name)
if err := ShowCommandHelp(ctx, cmd, cmd.Name); err != nil { _ = ShowSubcommandHelp(cmd)
tracef("SILENTLY IGNORING ERROR running ShowCommandHelp with %[1]q %[2]v", cmd.Name, err)
}
} }
} }
@@ -199,6 +213,7 @@ func (cmd *Command) run(ctx context.Context, osArgs []string) (_ context.Context
} }
if cmd.checkHelp() { if cmd.checkHelp() {
ctx = context.WithValue(ctx, helpShownKey{}, true)
return ctx, helpCommandAction(ctx, cmd) return ctx, helpCommandAction(ctx, cmd)
} else { } else {
tracef("no help is wanted (cmd=%[1]q)", cmd.Name) tracef("no help is wanted (cmd=%[1]q)", cmd.Name)
@@ -223,6 +238,9 @@ func (cmd *Command) run(ctx context.Context, osArgs []string) (_ context.Context
if cmd.After != nil && !cmd.Root().shellCompletion { if cmd.After != nil && !cmd.Root().shellCompletion {
defer func() { defer func() {
if ctx.Value(helpShownKey{}) != nil {
return
}
if err := cmd.After(ctx, cmd); err != nil { if err := cmd.After(ctx, cmd); err != nil {
err = cmd.handleExitCoder(ctx, err) err = cmd.handleExitCoder(ctx, err)
@@ -243,7 +261,14 @@ func (cmd *Command) run(ctx context.Context, osArgs []string) (_ context.Context
if cmd.OnUsageError != nil { if cmd.OnUsageError != nil {
err = cmd.OnUsageError(ctx, cmd, err, cmd.parent != nil) err = cmd.OnUsageError(ctx, cmd, err, cmd.parent != nil)
} else { } else {
_ = ShowSubcommandHelp(cmd) fmt.Fprintf(cmd.Root().ErrWriter, "Incorrect Usage: %s\n\n", err.Error())
if cmd.parent == nil {
_ = ShowRootCommandHelp(cmd)
} else {
if err := ShowCommandHelp(ctx, cmd.parent, cmd.Name); err != nil {
_ = ShowSubcommandHelp(cmd)
}
}
} }
return ctx, err return ctx, err
} }
@@ -300,23 +325,12 @@ func (cmd *Command) run(ctx context.Context, osArgs []string) (_ context.Context
// perform the command action. // perform the command action.
// //
// First, resolve the chain of nested commands up to the parent. // First, resolve the chain of nested commands up to the parent.
var cmdChain []*Command cmdChain := commandChain(cmd)
for p := cmd; p != nil; p = p.parent {
cmdChain = append(cmdChain, p)
}
slices.Reverse(cmdChain)
// Run Before actions in order. // Run Before actions in order.
for _, cmd := range cmdChain { if ctx, err = runBefore(ctx, cmdChain); err != nil {
if cmd.Before == nil { deferErr = err
continue return ctx, deferErr
}
if bctx, err := cmd.Before(ctx, cmd); err != nil {
deferErr = cmd.handleExitCoder(ctx, err)
return ctx, deferErr
} else if bctx != nil {
ctx = bctx
}
} }
// Run flag actions in order. // Run flag actions in order.
@@ -334,7 +348,14 @@ func (cmd *Command) run(ctx context.Context, osArgs []string) (_ context.Context
if cmd.OnUsageError != nil { if cmd.OnUsageError != nil {
err = cmd.OnUsageError(ctx, cmd, err, cmd.parent != nil) err = cmd.OnUsageError(ctx, cmd, err, cmd.parent != nil)
} else { } else {
_ = ShowSubcommandHelp(cmd) fmt.Fprintf(cmd.Root().ErrWriter, "Incorrect Usage: %s\n\n", err.Error())
if cmd.parent == nil {
_ = ShowRootCommandHelp(cmd)
} else {
if err := ShowCommandHelp(ctx, cmd.parent, cmd.Name); err != nil {
_ = ShowSubcommandHelp(cmd)
}
}
} }
return ctx, err return ctx, err
} }
@@ -366,3 +387,26 @@ func (cmd *Command) run(ctx context.Context, osArgs []string) (_ context.Context
tracef("returning deferErr (cmd=%[1]q) %[2]q", cmd.Name, deferErr) tracef("returning deferErr (cmd=%[1]q) %[2]q", cmd.Name, deferErr)
return ctx, deferErr return ctx, deferErr
} }
func commandChain(cmd *Command) []*Command {
var cmdChain []*Command
for p := cmd; p != nil; p = p.parent {
cmdChain = append(cmdChain, p)
}
slices.Reverse(cmdChain)
return cmdChain
}
func runBefore(ctx context.Context, cmdChain []*Command) (context.Context, error) {
for _, cmd := range cmdChain {
if cmd.Before == nil {
continue
}
if bctx, err := cmd.Before(ctx, cmd); err != nil {
return ctx, cmd.handleExitCoder(ctx, err)
} else if bctx != nil {
ctx = bctx
}
}
return ctx, nil
}
+26 -7
View File
@@ -104,8 +104,11 @@ func (cmd *Command) setupDefaults(osArgs []string) {
localVersionFlag = VersionFlag localVersionFlag = VersionFlag
} }
cmd.appendFlag(localVersionFlag) if !flagNamesInUse(cmd.allFlags(), localVersionFlag.Names()) {
cmd.globaVersionFlagAdded = true cmd.appendFlag(localVersionFlag)
cmd.versionFlag = localVersionFlag
cmd.globaVersionFlagAdded = true
}
} }
} }
@@ -162,11 +165,13 @@ func (cmd *Command) setupDefaults(osArgs []string) {
func (cmd *Command) setupCommandGraph() { func (cmd *Command) setupCommandGraph() {
tracef("setting up command graph (cmd=%[1]q)", cmd.Name) tracef("setting up command graph (cmd=%[1]q)", cmd.Name)
for _, subCmd := range cmd.Commands { _ = cmd.Walk(func(sub *Command) error {
subCmd.parent = cmd for _, subCmd := range sub.Commands {
subCmd.setupSubcommand() subCmd.parent = sub
subCmd.setupCommandGraph() subCmd.setupSubcommand()
} }
return nil
})
} }
func (cmd *Command) setupSubcommand() { func (cmd *Command) setupSubcommand() {
@@ -193,6 +198,20 @@ func (cmd *Command) setupSubcommand() {
cmd.flagCategories = newFlagCategoriesFromFlags(cmd.allFlags()) cmd.flagCategories = newFlagCategoriesFromFlags(cmd.allFlags())
} }
func flagNamesInUse(flags []Flag, names []string) bool {
for _, name := range names {
for _, fl := range flags {
for _, flagName := range fl.Names() {
if flagName == name {
return true
}
}
}
}
return false
}
func (cmd *Command) hideHelp() bool { func (cmd *Command) hideHelp() bool {
tracef("hide help (cmd=%[1]q)", cmd.Name) tracef("hide help (cmd=%[1]q)", cmd.Name)
for c := cmd; c != nil; c = c.parent { for c := cmd; c != nil; c = c.parent {
+17
View File
@@ -151,6 +151,23 @@ type DocGenerationMultiValueFlag interface {
IsMultiValueFlag() bool IsMultiValueFlag() bool
} }
// SchemaTyper is an optional interface for flags that can report their
// JSON Schema type for programmatic introspection.
type SchemaTyper interface {
// SchemaType returns the JSON Schema type name for the value this
// flag accepts: "boolean", "integer", "number", "string", "array",
// "object". Returns "" if the flag does not map cleanly.
SchemaType() string
}
// SchemaItemsTyper is an optional interface for multi-value flags that
// can report the JSON Schema type of their elements.
type SchemaItemsTyper interface {
// SchemaItemsType returns the JSON Schema type of elements for
// array-type flags. Returns "" for single-value or object flags.
SchemaItemsType() string
}
// Countable is an interface to enable detection of flag values which support // Countable is an interface to enable detection of flag values which support
// repetitive flags // repetitive flags
type Countable interface { type Countable interface {
+8
View File
@@ -263,3 +263,11 @@ func (bif *BoolWithInverseFlag) IsDefaultVisible() bool {
func (bif *BoolWithInverseFlag) TypeName() string { func (bif *BoolWithInverseFlag) TypeName() string {
return "bool" return "bool"
} }
func (bif *BoolWithInverseFlag) SchemaType() string {
return "boolean"
}
func (bif *BoolWithInverseFlag) SchemaItemsType() string {
return ""
}
+27 -1
View File
@@ -1,6 +1,9 @@
package cli package cli
import "flag" import (
"flag"
"time"
)
type extFlag struct { type extFlag struct {
f *flag.Flag f *flag.Flag
@@ -61,3 +64,26 @@ func (e *extFlag) GetDefaultText() string {
func (e *extFlag) GetEnvVars() []string { func (e *extFlag) GetEnvVars() []string {
return nil return nil
} }
func (e *extFlag) SchemaType() string {
switch e.Get().(type) {
case bool:
return "boolean"
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
return "integer"
case float32, float64:
return "number"
case string:
return "string"
case time.Duration:
return "duration"
case time.Time:
return "date-time"
default:
return ""
}
}
func (e *extFlag) SchemaItemsType() string {
return ""
}
+46
View File
@@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"reflect" "reflect"
"strings" "strings"
"time"
) )
// Value represents a value as used by cli. // Value represents a value as used by cli.
@@ -285,6 +286,51 @@ func (f *FlagBase[T, C, V]) RunAction(ctx context.Context, cmd *Command) error {
return nil return nil
} }
// SchemaType returns the JSON Schema type for the flag's value type.
func (f *FlagBase[T, C, V]) SchemaType() string {
var zero T
switch any(zero).(type) {
case bool:
return "boolean"
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
return "integer"
case float32, float64:
return "number"
case string:
return "string"
case time.Duration:
return "duration"
case time.Time:
return "date-time"
case []string, []int, []int8, []int16, []int32, []int64,
[]uint, []uint8, []uint16, []uint32, []uint64,
[]float32, []float64:
return "array"
case map[string]string:
return "object"
default:
return ""
}
}
// SchemaItemsType returns the JSON Schema element type for slice flags.
func (f *FlagBase[T, C, V]) SchemaItemsType() string {
var zero T
t := reflect.TypeOf(zero)
if t.Kind() == reflect.Slice {
switch t.Elem().Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return "integer"
case reflect.Float32, reflect.Float64:
return "number"
case reflect.String:
return "string"
}
}
return ""
}
// IsMultiValueFlag returns true if the value type T can take multiple // IsMultiValueFlag returns true if the value type T can take multiple
// values from cmd line. This is true for slice and map type flags // values from cmd line. This is true for slice and map type flags
func (f *FlagBase[T, C, VC]) IsMultiValueFlag() bool { func (f *FlagBase[T, C, VC]) IsMultiValueFlag() bool {
+42 -3
View File
@@ -170,7 +170,9 @@ COMMANDS:{{template "visibleCommandTemplate" .}}{{end}}{{if .VisibleFlagCategori
OPTIONS:{{template "visibleFlagCategoryTemplate" .}}{{else if .VisibleFlags}} OPTIONS:{{template "visibleFlagCategoryTemplate" .}}{{else if .VisibleFlags}}
OPTIONS:{{template "visibleFlagTemplate" .}}{{end}} OPTIONS:{{template "visibleFlagTemplate" .}}{{end}}{{if .VisiblePersistentFlags}}
GLOBAL OPTIONS:{{template "visiblePersistentFlagTemplate" .}}{{end}}
` `
SubcommandHelpTemplate is the text template for the subcommand help topic. SubcommandHelpTemplate is the text template for the subcommand help topic.
cli.go uses text/template to render templates. You can render custom help cli.go uses text/template to render templates. You can render custom help
@@ -405,6 +407,10 @@ func (bif *BoolWithInverseFlag) PreParse() error
func (bif *BoolWithInverseFlag) RunAction(ctx context.Context, cmd *Command) error func (bif *BoolWithInverseFlag) RunAction(ctx context.Context, cmd *Command) error
func (bif *BoolWithInverseFlag) SchemaItemsType() string
func (bif *BoolWithInverseFlag) SchemaType() string
func (bif *BoolWithInverseFlag) Set(name, val string) error func (bif *BoolWithInverseFlag) Set(name, val string) error
func (bif *BoolWithInverseFlag) SetCategory(c string) func (bif *BoolWithInverseFlag) SetCategory(c string)
@@ -606,8 +612,8 @@ func (cmd *Command) FloatSlice(name string) []float64
found found
func (cmd *Command) FullName() string func (cmd *Command) FullName() string
FullName returns the full name of the command. For commands with parents FullName returns the full name of the command. Includes parent commands
this ensures that the parent commands are part of the command path. separated by space.
func (cmd *Command) Generic(name string) Value func (cmd *Command) Generic(name string) Value
Generic looks up the value of a local GenericFlag, returns nil if not found Generic looks up the value of a local GenericFlag, returns nil if not found
@@ -689,6 +695,12 @@ func (cmd *Command) Names() []string
func (cmd *Command) NumFlags() int func (cmd *Command) NumFlags() int
NumFlags returns the number of flags set NumFlags returns the number of flags set
func (cmd *Command) Path() []string
Path returns the path of command names from the root to cmd, inclusive.
Each element is a Command.Name. Path traverses upward via parent pointers
similar to Lineage. FullName() is equivalent to strings.Join(cmd.Path(),
" ").
func (cmd *Command) Root() *Command func (cmd *Command) Root() *Command
Root returns the Command at the root of the graph Root returns the Command at the root of the graph
@@ -801,6 +813,10 @@ func (cmd *Command) VisiblePersistentFlags() []Flag
VisiblePersistentFlags returns a slice of LocalFlag with Persistent=true and VisiblePersistentFlags returns a slice of LocalFlag with Persistent=true and
Hidden=false. Hidden=false.
func (cmd *Command) Walk(fn func(*Command) error) error
Walk visits cmd and every descendant. If fn returns a non-nil error,
the walk terminates and the error is returned to the caller.
type CommandCategories interface { type CommandCategories interface {
// AddCommand adds a command to a category, creating a new category if necessary. // AddCommand adds a command to a category, creating a new category if necessary.
AddCommand(category string, command *Command) AddCommand(category string, command *Command)
@@ -1032,6 +1048,12 @@ func (f *FlagBase[T, C, V]) PreParse() error
func (f *FlagBase[T, C, V]) RunAction(ctx context.Context, cmd *Command) error func (f *FlagBase[T, C, V]) RunAction(ctx context.Context, cmd *Command) error
RunAction executes flag action if set RunAction executes flag action if set
func (f *FlagBase[T, C, V]) SchemaItemsType() string
SchemaItemsType returns the JSON Schema element type for slice flags.
func (f *FlagBase[T, C, V]) SchemaType() string
SchemaType returns the JSON Schema type for the flag's value type.
func (f *FlagBase[T, C, V]) Set(_ string, val string) error func (f *FlagBase[T, C, V]) Set(_ string, val string) error
Set applies given value from string Set applies given value from string
@@ -1296,6 +1318,23 @@ type RequiredFlag interface {
it allows flags required flags to be backwards compatible with the Flag it allows flags required flags to be backwards compatible with the Flag
interface interface
type SchemaItemsTyper interface {
// SchemaItemsType returns the JSON Schema type of elements for
// array-type flags. Returns "" for single-value or object flags.
SchemaItemsType() string
}
SchemaItemsTyper is an optional interface for multi-value flags that can
report the JSON Schema type of their elements.
type SchemaTyper interface {
// SchemaType returns the JSON Schema type name for the value this
// flag accepts: "boolean", "integer", "number", "string", "array",
// "object". Returns "" if the flag does not map cleanly.
SchemaType() string
}
SchemaTyper is an optional interface for flags that can report their JSON
Schema type for programmatic introspection.
type Serializer interface { type Serializer interface {
Serialize() string Serialize() string
} }
+27 -23
View File
@@ -65,11 +65,12 @@ var ArgsUsageCommandHelp = "[command]"
func buildHelpCommand(withAction bool) *Command { func buildHelpCommand(withAction bool) *Command {
cmd := &Command{ cmd := &Command{
Name: helpName, Name: helpName,
Aliases: []string{helpAlias}, Aliases: []string{helpAlias},
Usage: UsageCommandHelp, Usage: UsageCommandHelp,
ArgsUsage: ArgsUsageCommandHelp, ArgsUsage: ArgsUsageCommandHelp,
HideHelp: true, HideHelp: true,
builtInHelp: true,
} }
if withAction { if withAction {
@@ -85,14 +86,22 @@ func helpCommandAction(ctx context.Context, cmd *Command) error {
tracef("doing help for cmd %[1]q with args %[2]q", cmd, args) tracef("doing help for cmd %[1]q with args %[2]q", cmd, args)
// This action can be triggered by a "default" action of a command // helpCommandAction is triggered in several ways:
// or via cmd.Run when cmd == helpCmd. So we have following possibilities
// //
// 1 $ app // * the command has no user-defined Action (default action fallback)
// 2 $ app help // * the --help / -h flag was parsed (via cmd.checkHelp())
// 3 $ app foo // * the "help" subcommand (or "h" alias) was dispatched
// 4 $ app help foo //
// 5 $ app foo help // Possible invocations:
//
// $ app # default action; show root help
// $ app --help / -h # flag; show root help (ignores subsequent args)
// $ app help / h # subcommand; show root help
// $ app help / h foo # subcommand; show help for subcommand "foo"
// $ app --help / -h foo # flag; show help for subcommand "foo"
// $ app foo --help / -h # flag on subcommand; show help for "foo"
// $ app foo help / h # subcommand on subcommand; show help for "foo"
// $ app foo (no action) # default action on subcommand; show help for "foo"
// Case 4. when executing a help command set the context to parent // Case 4. when executing a help command set the context to parent
// to allow resolution of subsequent args. This will transform // to allow resolution of subsequent args. This will transform
@@ -100,7 +109,7 @@ func helpCommandAction(ctx context.Context, cmd *Command) error {
// to // to
// $ app foo // $ app foo
// which will then be handled as case 3 // which will then be handled as case 3
if cmd.parent != nil && (cmd.HasName(helpName) || cmd.HasName(helpAlias)) { if cmd.parent != nil && cmd.builtInHelp {
tracef("setting cmd to cmd.parent") tracef("setting cmd to cmd.parent")
cmd = cmd.parent cmd = cmd.parent
} }
@@ -459,13 +468,7 @@ func DefaultPrintHelp(out io.Writer, templ string, data any) {
} }
func checkVersion(cmd *Command) bool { func checkVersion(cmd *Command) bool {
found := false return cmd.versionFlag != nil && cmd.versionFlag.IsSet()
for _, name := range VersionFlag.Names() {
if cmd.Bool(name) {
found = true
}
}
return found
} }
func checkShellCompleteFlag(c *Command, arguments []string) (bool, []string) { func checkShellCompleteFlag(c *Command, arguments []string) (bool, []string) {
@@ -492,7 +495,7 @@ func checkShellCompleteFlag(c *Command, arguments []string) (bool, []string) {
return true, arguments[:pos] return true, arguments[:pos]
} }
func checkCompletions(ctx context.Context, cmd *Command) bool { func shouldRunCompletion(cmd *Command) bool {
tracef("checking completions on command %[1]q", cmd.Name) tracef("checking completions on command %[1]q", cmd.Name)
if !cmd.Root().shellCompletion { if !cmd.Root().shellCompletion {
@@ -509,13 +512,14 @@ func checkCompletions(ctx context.Context, cmd *Command) bool {
} }
tracef("no subcommand found for completion %[1]q", cmd.Name) tracef("no subcommand found for completion %[1]q", cmd.Name)
return true
}
func runCompletion(ctx context.Context, cmd *Command) {
if cmd.ShellComplete != nil { if cmd.ShellComplete != nil {
tracef("running shell completion func for command %[1]q", cmd.Name) tracef("running shell completion func for command %[1]q", cmd.Name)
cmd.ShellComplete(ctx, cmd) cmd.ShellComplete(ctx, cmd)
} }
return true
} }
func subtract(a, b int) int { func subtract(a, b int) int {
+2
View File
@@ -20,6 +20,8 @@ nav:
- v3 Manual: - v3 Manual:
- Getting Started: v3/getting-started.md - Getting Started: v3/getting-started.md
- Migrating From Older Releases: v3/migrating-from-older-releases.md - Migrating From Older Releases: v3/migrating-from-older-releases.md
- Path and Walk: v3/path-and-walk.md
- Binary Size: v3/binary-size.md
- Examples: - Examples:
- Greet: v3/examples/greet.md - Greet: v3/examples/greet.md
- Flags: - Flags:
+3 -1
View File
@@ -107,7 +107,9 @@ COMMANDS:{{template "visibleCommandTemplate" .}}{{end}}{{if .VisibleFlagCategori
OPTIONS:{{template "visibleFlagCategoryTemplate" .}}{{else if .VisibleFlags}} OPTIONS:{{template "visibleFlagCategoryTemplate" .}}{{else if .VisibleFlags}}
OPTIONS:{{template "visibleFlagTemplate" .}}{{end}} OPTIONS:{{template "visibleFlagTemplate" .}}{{end}}{{if .VisiblePersistentFlags}}
GLOBAL OPTIONS:{{template "visiblePersistentFlagTemplate" .}}{{end}}
` `
var FishCompletionTemplate = `# {{ .Command.Name }} fish shell completion var FishCompletionTemplate = `# {{ .Command.Name }} fish shell completion
+1 -1
View File
@@ -94,7 +94,7 @@ github.com/seccomp/libseccomp-golang
## explicit; go 1.17 ## explicit; go 1.17
github.com/sirupsen/logrus github.com/sirupsen/logrus
github.com/sirupsen/logrus/hooks/test github.com/sirupsen/logrus/hooks/test
# github.com/urfave/cli/v3 v3.9.1 # github.com/urfave/cli/v3 v3.10.0
## explicit; go 1.22 ## explicit; go 1.22
github.com/urfave/cli/v3 github.com/urfave/cli/v3
# github.com/vishvananda/netlink v1.3.1 # github.com/vishvananda/netlink v1.3.1