diff --git a/go.mod b/go.mod index a006470fd2b..6a7af490303 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/opencontainers/selinux v1.15.1 github.com/seccomp/libseccomp-golang v0.11.1 github.com/sirupsen/logrus v1.9.4 - github.com/urfave/cli/v3 v3.10.0 + github.com/urfave/cli/v3 v3.10.1 github.com/vishvananda/netlink v1.3.1 github.com/vishvananda/netns v0.0.5 golang.org/x/net v0.56.0 diff --git a/go.sum b/go.sum index a550e0cf34d..211326b8590 100644 --- a/go.sum +++ b/go.sum @@ -62,8 +62,8 @@ github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w 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/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -github.com/urfave/cli/v3 v3.10.0 h1:0aU8yOObVDMkM13Cj4G+zb4P0PdeJMec65f81Ak1ioM= -github.com/urfave/cli/v3 v3.10.0/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso= +github.com/urfave/cli/v3 v3.10.1 h1:7Kx9H50hrHbRbyxgO1KP6/BcbiGRz0uYh5YyQ30JEEY= +github.com/urfave/cli/v3 v3.10.1/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso= 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/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY= diff --git a/vendor/github.com/urfave/cli/v3/command_parse.go b/vendor/github.com/urfave/cli/v3/command_parse.go index 2b9a481df2f..939ad90b858 100644 --- a/vendor/github.com/urfave/cli/v3/command_parse.go +++ b/vendor/github.com/urfave/cli/v3/command_parse.go @@ -199,6 +199,12 @@ func (cmd *Command) parseFlags(args Args) (Args, error) { posArgs = append(posArgs, rargs...) return &stringSliceArgs{posArgs}, nil } + // When DefaultCommand is set, pass unknown flags through as positional args + // so the default command can handle them (fixes #2249) + if cmd.DefaultCommand != "" { + posArgs = append(posArgs, rargs...) + return &stringSliceArgs{posArgs}, nil + } return &stringSliceArgs{posArgs}, fmt.Errorf("%s%s", providedButNotDefinedErrMsg, flagName) } @@ -206,6 +212,10 @@ func (cmd *Command) parseFlags(args Args) (Args, error) { for index, c := range flagName { tracef("processing flag (fName=%[1]q)", string(c)) if sf := cmd.lookupFlag(string(c)); sf == nil { + if index == 0 && cmd.DefaultCommand != "" { + posArgs = append(posArgs, rargs...) + return &stringSliceArgs{posArgs}, nil + } return &stringSliceArgs{posArgs}, fmt.Errorf("%s%s", providedButNotDefinedErrMsg, flagName) } else if fb, ok := sf.(boolFlag); ok && fb.IsBoolFlag() { fv := flagVal diff --git a/vendor/github.com/urfave/cli/v3/command_setup.go b/vendor/github.com/urfave/cli/v3/command_setup.go index 8cc73a02fc0..646e270ce7c 100644 --- a/vendor/github.com/urfave/cli/v3/command_setup.go +++ b/vendor/github.com/urfave/cli/v3/command_setup.go @@ -99,6 +99,10 @@ func (cmd *Command) setupDefaults(osArgs []string) { var localVersionFlag Flag if globalVersionFlag, ok := VersionFlag.(*BoolFlag); ok { flag := *globalVersionFlag + // Drop any alias a user flag already claims (e.g. -v + // for --verbose) so the user flag wins but --version + // still works. See #2229. + flag.Aliases = dropClashingAliases(flag.Aliases, cmd.allFlags(), flag.Name) localVersionFlag = &flag } else { localVersionFlag = VersionFlag @@ -255,3 +259,31 @@ func (cmd *Command) ensureHelp() { } } } + +// dropClashingAliases removes aliases from `aliases` that are already +// claimed by a flag in `userFlags` (either as a primary name or as one +// of its own aliases). Aliases equal to `selfName` are kept so the +// flag's primary name doesn't accidentally remove itself. +func dropClashingAliases(aliases []string, userFlags []Flag, selfName string) []string { + if len(aliases) == 0 || len(userFlags) == 0 { + return aliases + } + taken := map[string]struct{}{} + for _, f := range userFlags { + for _, n := range f.Names() { + taken[n] = struct{}{} + } + } + kept := aliases[:0:0] + for _, a := range aliases { + if a == selfName { + kept = append(kept, a) + continue + } + if _, ok := taken[a]; ok { + continue + } + kept = append(kept, a) + } + return kept +} diff --git a/vendor/github.com/urfave/cli/v3/completion.go b/vendor/github.com/urfave/cli/v3/completion.go index 167b0c0123a..f14b01430a1 100644 --- a/vendor/github.com/urfave/cli/v3/completion.go +++ b/vendor/github.com/urfave/cli/v3/completion.go @@ -20,6 +20,12 @@ var ( //go:embed autocomplete autoCompleteFS embed.FS + // completionShells defines the order in which the shell completion + // subcommands appear in help output. Iterating shellCompletions directly + // would use Go's randomized map order, making the listing nondeterministic. + // Keep this in sync with shellCompletions. + completionShells = []string{"bash", "zsh", "fish", "pwsh"} + shellCompletions = map[string]renderCompletion{ "bash": func(c *Command, appName string) (string, error) { b, err := autoCompleteFS.ReadFile("autocomplete/bash_autocomplete") @@ -65,8 +71,8 @@ func buildCompletionCommand(appName string) *Command { isCompletionCommand: true, } - for shell, render := range shellCompletions { - cmd.Commands = append(cmd.Commands, buildShellCompletionSubcommand(shell, render, appName)) + for _, shell := range completionShells { + cmd.Commands = append(cmd.Commands, buildShellCompletionSubcommand(shell, shellCompletions[shell], appName)) } return cmd diff --git a/vendor/modules.txt b/vendor/modules.txt index b2ae77b2580..81256526a29 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -98,7 +98,7 @@ github.com/seccomp/libseccomp-golang ## explicit; go 1.17 github.com/sirupsen/logrus github.com/sirupsen/logrus/hooks/test -# github.com/urfave/cli/v3 v3.10.0 +# github.com/urfave/cli/v3 v3.10.1 ## explicit; go 1.22 github.com/urfave/cli/v3 # github.com/vishvananda/netlink v1.3.1