From c2e02d39cafe4b1a03e5320a8921be815299aead Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Sep 2026 07:23:09 +0000 Subject: [PATCH] build(deps): Bump github.com/urfave/cli/v3 from 3.11.0 to 3.12.0 Bumps [github.com/urfave/cli/v3](https://github.com/urfave/cli) from 3.11.0 to 3.12.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.11.0...v3.12.0) --- updated-dependencies: - dependency-name: github.com/urfave/cli/v3 dependency-version: 3.12.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 +- vendor/github.com/urfave/cli/v3/args.go | 23 ++++- vendor/github.com/urfave/cli/v3/command.go | 70 +++++++++++++-- .../github.com/urfave/cli/v3/command_parse.go | 8 +- .../github.com/urfave/cli/v3/command_run.go | 61 ++++++++++--- .../github.com/urfave/cli/v3/command_setup.go | 2 + vendor/github.com/urfave/cli/v3/errors.go | 16 ++++ vendor/github.com/urfave/cli/v3/flag.go | 12 +++ .../urfave/cli/v3/flag_bool_with_inverse.go | 21 ++++- vendor/github.com/urfave/cli/v3/flag_impl.go | 22 +++-- vendor/github.com/urfave/cli/v3/flag_mutex.go | 30 +++++++ vendor/github.com/urfave/cli/v3/flag_text.go | 86 +++++++++++++++++++ .../urfave/cli/v3/flag_timestamp.go | 13 ++- vendor/github.com/urfave/cli/v3/funcs.go | 7 ++ .../urfave/cli/v3/godoc-current.txt | 68 +++++++++++++++ vendor/github.com/urfave/cli/v3/help.go | 29 +++++-- .../urfave/cli/v3/mkdocs-requirements.txt | 4 +- .../github.com/urfave/cli/v3/value_source.go | 1 + vendor/modules.txt | 2 +- 20 files changed, 436 insertions(+), 45 deletions(-) create mode 100644 vendor/github.com/urfave/cli/v3/flag_text.go diff --git a/go.mod b/go.mod index cfbd01e4d7..10927c0318 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/regclient/regclient v0.11.5 github.com/sirupsen/logrus v1.10.2 github.com/stretchr/testify v1.12.1 - github.com/urfave/cli/v3 v3.11.0 + github.com/urfave/cli/v3 v3.12.0 go.uber.org/zap v1.28.0 golang.org/x/mod v0.41.0 k8s.io/api v0.37.0 diff --git a/go.sum b/go.sum index 6874b280df..2e994d5eef 100644 --- a/go.sum +++ b/go.sum @@ -230,8 +230,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY= github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/urfave/cli/v3 v3.11.0 h1:P/euJp99kb9p0tlVY+iYTLYYTAQlfl0hR2gUO1Img1Q= -github.com/urfave/cli/v3 v3.11.0/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso= +github.com/urfave/cli/v3 v3.12.0 h1:p2iMu5yeXB+ORzD1AAqwP2kHV9Q6QObnwyQXFFdnXYQ= +github.com/urfave/cli/v3 v3.12.0/go.mod h1:vXn6HxPNccJSzQr2QvwVncOKrgYGIHU0HY5h8B2nQj4= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= diff --git a/vendor/github.com/urfave/cli/v3/args.go b/vendor/github.com/urfave/cli/v3/args.go index b3acfd5ccc..0dad209914 100644 --- a/vendor/github.com/urfave/cli/v3/args.go +++ b/vendor/github.com/urfave/cli/v3/args.go @@ -77,6 +77,11 @@ type Argument interface { Get() any } +type requiredArgument interface { + name() string + required() bool +} + // AnyArguments to differentiate between no arguments(nil) vs aleast one var AnyArguments = []Argument{ &StringArgs{ @@ -89,6 +94,7 @@ type ArgumentBase[T any, C any, VC ValueCreator[T, C]] struct { Value T `json:"value"` // the default value of this argument Destination *T `json:"-"` // the destination point for this argument UsageText string `json:"usageText"` // the usage text to show + Required bool `json:"required"` // whether the argument is required or not Config C `json:"config"` // config for this argument similar to Flag Config value *T @@ -98,18 +104,33 @@ func (a *ArgumentBase[T, C, VC]) HasName(s string) bool { return s == a.Name } +func (a *ArgumentBase[T, C, VC]) name() string { + return a.Name +} + +func (a *ArgumentBase[T, C, VC]) required() bool { + return a.Required +} + func (a *ArgumentBase[T, C, VC]) Usage() string { if a.UsageText != "" { return a.UsageText } - usageFormat := "%[1]s" + usageFormat := "[%[1]s]" + if a.Required { + usageFormat = "%[1]s" + } return fmt.Sprintf(usageFormat, a.Name) } func (a *ArgumentBase[T, C, VC]) Parse(s []string) ([]string, error) { tracef("calling arg%[1] parse with args %[2]", a.Name, s) + if a.Required && len(s) == 0 { + return s, &errRequiredArguments{missingArguments: []string{a.Name}} + } + var vc VC var t T value := vc.Create(a.Value, &t, a.Config) diff --git a/vendor/github.com/urfave/cli/v3/command.go b/vendor/github.com/urfave/cli/v3/command.go index f0cf9a715d..02f9f76658 100644 --- a/vendor/github.com/urfave/cli/v3/command.go +++ b/vendor/github.com/urfave/cli/v3/command.go @@ -67,6 +67,11 @@ type Command struct { // An action to execute after any subcommands are run, but after the subcommand has finished // It is run even if Action() panics After AfterFunc `json:"-"` + // An action to validate arguments before the command is run. If non-nil, it + // is called before Before and Action. If the current command does not set + // ArgValidator, the nearest ancestor that does is used instead. + // Returning a non-nil error short-circuits the command. + ArgValidator ArgValidatorFunc `json:"-"` // The function to call when this command is invoked Action ActionFunc `json:"-"` // Execute this function if the proper command cannot be found @@ -160,6 +165,10 @@ type Command struct { didSetupDefaults bool // whether in shell completion mode shellCompletion bool + // whether the shell completion request came after a "--" separator, + // after which only positional arguments are accepted and nothing is + // suggested. The request is still a completion, never a command run. + shellCompletionPastDoubleDash bool // whether global help flag was added globaHelpFlagAdded bool // whether global version flag was added @@ -301,12 +310,25 @@ func (cmd *Command) VisiblePersistentFlags() []Flag { return nil } var flags []Flag - for _, fl := range cmd.Root().Flags { - pfl, ok := fl.(LocalFlag) - if !ok || pfl.IsLocal() { - continue + lineage := cmd.Lineage() + for i := len(lineage) - 1; i > 0; i-- { + for _, fl := range lineage[i].allFlags() { + pfl, ok := fl.(LocalFlag) + if !ok || pfl.IsLocal() { + continue + } + applies := true + for _, name := range fl.Names() { + if cmd.lookupFlag(name) != fl { + applies = false + break + } + } + if !applies { + continue + } + flags = append(flags, fl) } - flags = append(flags, fl) } return visibleFlags(flags) } @@ -457,6 +479,40 @@ func (cmd *Command) checkRequiredFlags() requiredFlagsErr { return nil } +func (cmd *Command) checkRequiredArguments() requiredArgumentsErr { + // The help and completion commands are allowed to run without + // enforcement of required arguments, since they do not invoke user + // actions that depend on those argument values. + if cmd.builtInHelp || cmd.isCompletionCommand { + return nil + } + + tracef("checking for required arguments (cmd=%[1]q)", cmd.Name) + + missingArguments := []string{} + // This count-based precheck relies on required single-value arguments + // being declared before optional or multi-value arguments, as documented. + // Argument.Parse remains the backstop for unsupported orderings. + providedArguments := cmd.Args().Len() + + for index, arg := range cmd.Arguments { + requiredArg, ok := arg.(requiredArgument) + if ok && requiredArg.required() && index >= providedArguments { + missingArguments = append(missingArguments, requiredArg.name()) + } + } + + if len(missingArguments) != 0 { + tracef("found missing required arguments %[1]q (cmd=%[2]q)", missingArguments, cmd.Name) + + return &errRequiredArguments{missingArguments: missingArguments} + } + + tracef("all required arguments set (cmd=%[1]q)", cmd.Name) + + return nil +} + func (cmd *Command) onInvalidFlag(ctx context.Context, name string) { for cmd != nil { if cmd.InvalidFlagAccessHandler != nil { @@ -622,7 +678,9 @@ func (cmd *Command) Value(name string) any { } // Args returns the command line arguments associated with the -// command. +// command. If the command declares named Arguments, the arguments +// consumed by them are not included in the returned Args and should +// be retrieved via the command.{Type}Arg(name) functions instead. func (cmd *Command) Args() Args { return cmd.parsedArgs } diff --git a/vendor/github.com/urfave/cli/v3/command_parse.go b/vendor/github.com/urfave/cli/v3/command_parse.go index 939ad90b85..a4d943848e 100644 --- a/vendor/github.com/urfave/cli/v3/command_parse.go +++ b/vendor/github.com/urfave/cli/v3/command_parse.go @@ -114,7 +114,9 @@ func (cmd *Command) parseFlags(args Args) (Args, error) { return &stringSliceArgs{posArgs}, nil } - posArgs = append(posArgs, firstArg) + // firstArg is a trimmed copy that classifies the argument; the + // argument itself is what the action receives, byte for byte. + posArgs = append(posArgs, rargs[0]) continue } @@ -145,7 +147,9 @@ func (cmd *Command) parseFlags(args Args) (Args, error) { valFromEqual := false tracef("flagName:1 (fName=%[1]q)", flagName) if index := strings.Index(flagName, "="); index != -1 { - flagVal = flagName[index+1:] + // Classify the flag using the trimmed token, but leave value + // whitespace handling to the flag's value parser. + _, flagVal, _ = strings.Cut(rargs[0], "=") flagName = flagName[:index] valFromEqual = true } diff --git a/vendor/github.com/urfave/cli/v3/command_run.go b/vendor/github.com/urfave/cli/v3/command_run.go index 8d5907151e..34398f8e98 100644 --- a/vendor/github.com/urfave/cli/v3/command_run.go +++ b/vendor/github.com/urfave/cli/v3/command_run.go @@ -125,6 +125,11 @@ func (cmd *Command) run(ctx context.Context, osArgs []string) (_ context.Context // note that we can only do this because the shell autocomplete function // always appends the completion flag at the end of the command tracef("checking osArgs %v (cmd=%[2]q)", osArgs, cmd.Name) + // completion request state is per-run: a Command answering several + // requests (tests, REPL, embedded use) must not carry one request + // into the next + cmd.shellCompletion = false + cmd.shellCompletionPastDoubleDash = false cmd.shellCompletion, osArgs = checkShellCompleteFlag(cmd, osArgs) tracef("setting cmd.shellCompletion=%[1]v from checkShellCompleteFlag (cmd=%[2]q)", cmd.shellCompletion && cmd.EnableShellCompletion, cmd.Name) @@ -327,6 +332,14 @@ func (cmd *Command) run(ctx context.Context, osArgs []string) (_ context.Context // First, resolve the chain of nested commands up to the parent. cmdChain := commandChain(cmd) + // Run ArgValidator from the nearest ancestor that sets one. + if validator := findArgValidator(cmd); validator != nil { + if err := validator(ctx, cmd); err != nil { + deferErr = cmd.handleExitCoder(ctx, err) + return ctx, deferErr + } + } + // Run Before actions in order. if ctx, err = runBefore(ctx, cmdChain); err != nil { deferErr = err @@ -343,21 +356,14 @@ func (cmd *Command) run(ctx context.Context, osArgs []string) (_ context.Context } } + var requiredErr error if err := cmd.checkAllRequiredFlags(); err != nil { - cmd.isInError = true - if cmd.OnUsageError != nil { - err = cmd.OnUsageError(ctx, cmd, err, cmd.parent != nil) - } else { - 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 + requiredErr = err + } else if err := cmd.checkRequiredArguments(); err != nil { + requiredErr = err + } + if requiredErr != nil { + return cmd.handleRequiredError(ctx, requiredErr) } // Run the command action. @@ -369,6 +375,9 @@ func (cmd *Command) run(ctx context.Context, osArgs []string) (_ context.Context rargs, err = arg.Parse(rargs) if err != nil { tracef("calling with %[1]v (cmd=%[2]q)", err, cmd.Name) + if _, ok := err.(*errRequiredArguments); ok { + return cmd.handleRequiredError(ctx, err) + } if cmd.OnUsageError != nil { err = cmd.OnUsageError(ctx, cmd, err, cmd.parent != nil) } @@ -388,6 +397,21 @@ func (cmd *Command) run(ctx context.Context, osArgs []string) (_ context.Context return ctx, deferErr } +func (cmd *Command) handleRequiredError(ctx context.Context, err error) (context.Context, error) { + cmd.isInError = true + if cmd.OnUsageError != nil { + err = cmd.OnUsageError(ctx, cmd, err, cmd.parent != nil) + } else { + fmt.Fprintf(cmd.Root().ErrWriter, "Incorrect Usage: %s\n\n", err.Error()) + if cmd.parent == nil { + _ = ShowRootCommandHelp(cmd) + } else if helpErr := ShowCommandHelp(ctx, cmd.parent, cmd.Name); helpErr != nil { + _ = ShowSubcommandHelp(cmd) + } + } + return ctx, err +} + func commandChain(cmd *Command) []*Command { var cmdChain []*Command for p := cmd; p != nil; p = p.parent { @@ -397,6 +421,15 @@ func commandChain(cmd *Command) []*Command { return cmdChain } +func findArgValidator(cmd *Command) ArgValidatorFunc { + for c := cmd; c != nil; c = c.parent { + if c.ArgValidator != nil { + return c.ArgValidator + } + } + return nil +} + func runBefore(ctx context.Context, cmdChain []*Command) (context.Context, error) { for _, cmd := range cmdChain { if cmd.Before == nil { diff --git a/vendor/github.com/urfave/cli/v3/command_setup.go b/vendor/github.com/urfave/cli/v3/command_setup.go index 13ef706315..3ea2fa851e 100644 --- a/vendor/github.com/urfave/cli/v3/command_setup.go +++ b/vendor/github.com/urfave/cli/v3/command_setup.go @@ -153,6 +153,7 @@ func (cmd *Command) setupDefaults(osArgs []string) { tracef("setting category on mutually exclusive flags (cmd=%[1]q)", cmd.Name) for _, grp := range cmd.MutuallyExclusiveFlags { grp.propagateCategory() + grp.propagateStringer() } tracef("setting flag categories (cmd=%[1]q)", cmd.Name) @@ -196,6 +197,7 @@ func (cmd *Command) setupSubcommand() { tracef("setting category on mutually exclusive flags (cmd=%[1]q)", cmd.Name) for _, grp := range cmd.MutuallyExclusiveFlags { grp.propagateCategory() + grp.propagateStringer() } tracef("setting flag categories (cmd=%[1]q)", cmd.Name) diff --git a/vendor/github.com/urfave/cli/v3/errors.go b/vendor/github.com/urfave/cli/v3/errors.go index ffd6471f23..ff0dfa51d7 100644 --- a/vendor/github.com/urfave/cli/v3/errors.go +++ b/vendor/github.com/urfave/cli/v3/errors.go @@ -61,6 +61,22 @@ func (e *errRequiredFlags) Error() string { return fmt.Sprintf("Required flags %q not set", joinedMissingFlags) } +type requiredArgumentsErr interface { + error +} + +type errRequiredArguments struct { + missingArguments []string +} + +func (e *errRequiredArguments) Error() string { + if len(e.missingArguments) == 1 { + return fmt.Sprintf("Required argument %q not set", e.missingArguments[0]) + } + joinedMissingArguments := strings.Join(e.missingArguments, ", ") + return fmt.Sprintf("Required arguments %q not set", joinedMissingArguments) +} + type mutuallyExclusiveGroup struct { flag1Name string flag2Name string diff --git a/vendor/github.com/urfave/cli/v3/flag.go b/vendor/github.com/urfave/cli/v3/flag.go index 3cb9ab9608..9dbe0199ef 100644 --- a/vendor/github.com/urfave/cli/v3/flag.go +++ b/vendor/github.com/urfave/cli/v3/flag.go @@ -190,6 +190,18 @@ type CategorizableFlag interface { SetCategory(string) } +// StringerSetter is an optional interface that allows an individual +// flag to be given a per-flag override of [FlagStringer]. FlagBase and +// BoolWithInverseFlag implement this. It's used by +// [MutuallyExclusiveFlags.Stringer] to customize how flags within a +// mutually exclusive group are displayed in help output. +type StringerSetter interface { + // SetStringer overrides the [FlagStringFunc] used by this flag's + // String method. Passing nil restores the default behavior of using + // the package-level [FlagStringer]. + SetStringer(FlagStringFunc) +} + // LocalFlag is an interface to enable detection of flags which are local // to current command type LocalFlag interface { diff --git a/vendor/github.com/urfave/cli/v3/flag_bool_with_inverse.go b/vendor/github.com/urfave/cli/v3/flag_bool_with_inverse.go index 33c0927257..d57225dc17 100644 --- a/vendor/github.com/urfave/cli/v3/flag_bool_with_inverse.go +++ b/vendor/github.com/urfave/cli/v3/flag_bool_with_inverse.go @@ -37,6 +37,21 @@ type BoolWithInverseFlag struct { value Value // value representing this flag's value pset bool nset bool + stringer FlagStringFunc // optional per-flag override of FlagStringer +} + +// SetStringer overrides the [FlagStringFunc] used by this flag's String +// method. Passing nil restores the default behavior of using the +// package-level [FlagStringer]. This is used e.g. by +// [MutuallyExclusiveFlags.Stringer]. +// +// Note: unlike [FlagBase], BoolWithInverseFlag.String only honors the +// stringer partially. The names segment (the part before the first tab, +// e.g. "--[no-]env, -e") is always recomputed from Name/Aliases/InversePrefix +// and cannot be overridden; only the tab-delimited details after it come +// from the stringer's output. +func (bif *BoolWithInverseFlag) SetStringer(s FlagStringFunc) { + bif.stringer = s } func (bif *BoolWithInverseFlag) IsSet() bool { @@ -171,7 +186,11 @@ func (bif *BoolWithInverseFlag) IsVisible() bool { // Example for BoolFlag{Name: "env", Aliases: []string{"e"}} // --[no-]env, -e (default: false) func (bif *BoolWithInverseFlag) String() string { - out := FlagStringer(bif) + fs := FlagStringer + if bif.stringer != nil { + fs = bif.stringer + } + out := fs(bif) i := strings.Index(out, "\t") diff --git a/vendor/github.com/urfave/cli/v3/flag_impl.go b/vendor/github.com/urfave/cli/v3/flag_impl.go index be702d33f4..e829d6814e 100644 --- a/vendor/github.com/urfave/cli/v3/flag_impl.go +++ b/vendor/github.com/urfave/cli/v3/flag_impl.go @@ -75,11 +75,12 @@ type FlagBase[T any, C any, VC ValueCreator[T, C]] struct { ValidateDefaults bool `json:"validateDefaults"` // whether to validate defaults or not // unexported fields for internal use - count int // number of times the flag has been set - hasBeenSet bool // whether the flag has been set from env or file - applied bool // whether the flag has been applied to a flag set already - creator VC // value creator for this flag type - value Value // value representing this flag's value + count int // number of times the flag has been set + hasBeenSet bool // whether the flag has been set from env or file + applied bool // whether the flag has been applied to a flag set already + creator VC // value creator for this flag type + value Value // value representing this flag's value + stringer FlagStringFunc // optional per-flag override of FlagStringer } // GetValue returns the flags value as string representation and an empty @@ -232,9 +233,20 @@ func (f *FlagBase[T, C, V]) IsDefaultVisible() bool { // String returns a readable representation of this value (for usage defaults) func (f *FlagBase[T, C, V]) String() string { + if f.stringer != nil { + return f.stringer(f) + } return FlagStringer(f) } +// SetStringer overrides the [FlagStringFunc] used by this flag's String +// method. Passing nil restores the default behavior of using the +// package-level [FlagStringer]. This is used e.g. by +// [MutuallyExclusiveFlags.Stringer]. +func (f *FlagBase[T, C, V]) SetStringer(s FlagStringFunc) { + f.stringer = s +} + // IsSet returns whether or not the flag has been set through env or file func (f *FlagBase[T, C, V]) IsSet() bool { return f.hasBeenSet diff --git a/vendor/github.com/urfave/cli/v3/flag_mutex.go b/vendor/github.com/urfave/cli/v3/flag_mutex.go index 5a1e87cfb5..bd016988e9 100644 --- a/vendor/github.com/urfave/cli/v3/flag_mutex.go +++ b/vendor/github.com/urfave/cli/v3/flag_mutex.go @@ -14,6 +14,17 @@ type MutuallyExclusiveFlags struct { // Category to apply to all flags within group Category string + + // Stringer overrides how each flag within this group is displayed in + // help output. If nil, flags use [FlagStringer] as usual. + // + // The returned string must be unique per flag within the group (the + // default [stringifyFlag] guarantees this by embedding the flag's + // name). Help rendering keys flags by their String() output + // (flagCategories.AddFlag), so a Stringer that returns identical text + // for two or more flags in the same category will cause the later + // flag to silently overwrite the earlier one in help output. + Stringer FlagStringFunc `json:"-"` } func (grp MutuallyExclusiveFlags) check(_ *Command) error { @@ -69,3 +80,22 @@ func (grp MutuallyExclusiveFlags) propagateCategory() { } } } + +// propagateStringer applies [MutuallyExclusiveFlags.Stringer], if set, to +// every flag within the group that supports a [StringerSetter]. Like +// [MutuallyExclusiveFlags.propagateCategory], this only runs during command +// setup, so mutating Stringer between runs of a reused [Command] will not +// re-propagate the change. +func (grp MutuallyExclusiveFlags) propagateStringer() { + if grp.Stringer == nil { + return + } + + for _, grpf := range grp.Flags { + for _, f := range grpf { + if sf, ok := f.(StringerSetter); ok { + sf.SetStringer(grp.Stringer) + } + } + } +} diff --git a/vendor/github.com/urfave/cli/v3/flag_text.go b/vendor/github.com/urfave/cli/v3/flag_text.go new file mode 100644 index 0000000000..a1cc2c3636 --- /dev/null +++ b/vendor/github.com/urfave/cli/v3/flag_text.go @@ -0,0 +1,86 @@ +package cli + +import ( + "encoding" + "strings" +) + +// TextMarshalUnmarshaler is the interface implemented by types that can marshal +// themselves to and from a textual form. It is the value type used by TextFlag, +// mirroring the standard library's flag.TextVar, and is satisfied by types such +// as *slog.LevelVar, *net/netip.Addr, and *time.Time. +type TextMarshalUnmarshaler interface { + encoding.TextMarshaler + encoding.TextUnmarshaler +} + +type TextFlag = FlagBase[TextMarshalUnmarshaler, StringConfig, textValue] + +// -- TextMarshalUnmarshaler Value +type textValue struct { + destination TextMarshalUnmarshaler + trimSpace bool +} + +// Below functions are to satisfy the ValueCreator interface + +func (t textValue) Create(val TextMarshalUnmarshaler, p *TextMarshalUnmarshaler, c StringConfig) Value { + // Only overwrite the target when a non-nil default value is given, so that + // a Destination pointing at an existing target is preserved (unlike the + // concrete flag types, T here is an interface whose nil default would + // otherwise clobber the destination). + if val != nil { + *p = val + } + return &textValue{ + destination: *p, + trimSpace: c.TrimSpace, + } +} + +func (t textValue) ToString(val TextMarshalUnmarshaler) string { + if val == nil { + return "" + } + text, err := val.MarshalText() + if err != nil { + return "" + } + return string(text) +} + +// Below functions are to satisfy the flag.Value interface + +func (t *textValue) Set(val string) error { + if t.destination == nil { + return nil + } + if t.trimSpace { + val = strings.TrimSpace(val) + } + return t.destination.UnmarshalText([]byte(val)) +} + +func (t *textValue) Get() any { return t.destination } + +func (t *textValue) String() string { + if t.destination == nil { + return "" + } + text, err := t.destination.MarshalText() + if err != nil { + return "" + } + return string(text) +} + +// Text looks up the value of a local TextFlag, returns nil if not found +func (cmd *Command) Text(name string) TextMarshalUnmarshaler { + if v, ok := cmd.Value(name).(TextMarshalUnmarshaler); ok { + tracef("text available for flag name %[1]q with value=%[2]v (cmd=%[3]q)", name, v, cmd.Name) + return v + } + + tracef("text NOT available for flag name %[1]q (cmd=%[2]q)", name, cmd.Name) + return nil +} diff --git a/vendor/github.com/urfave/cli/v3/flag_timestamp.go b/vendor/github.com/urfave/cli/v3/flag_timestamp.go index 82b1cb5cf0..83723e6f9a 100644 --- a/vendor/github.com/urfave/cli/v3/flag_timestamp.go +++ b/vendor/github.com/urfave/cli/v3/flag_timestamp.go @@ -63,6 +63,7 @@ func (t *timestampValue) Set(value string) error { return errors.New("got nil/empty layouts slice") } + matchedLayout := "" for _, layout := range t.layouts { var locErr error @@ -78,6 +79,7 @@ func (t *timestampValue) Set(value string) error { } err = nil + matchedLayout = layout break } @@ -90,7 +92,8 @@ func (t *timestampValue) Set(value string) error { n := time.Now().In(timestamp.Location()) // If format is missing date (or year only), set it explicitly to current - if timestamp.Truncate(time.Hour*24).UnixNano() == defaultTS.Truncate(time.Hour*24).UnixNano() { + // A layout that carries a date parses "January 1" to the same instant a date-less layout does, so ask the layout. + if !layoutHasDate(matchedLayout) && timestamp.Truncate(time.Hour*24).UnixNano() == defaultTS.Truncate(time.Hour*24).UnixNano() { timestamp = time.Date( n.Year(), n.Month(), @@ -121,6 +124,14 @@ func (t *timestampValue) Set(value string) error { return nil } +// layoutHasDate reports whether layout carries month/day components, probed by +// round-tripping a reference date that is not January 1. +func layoutHasDate(layout string) bool { + ref := time.Date(2, time.March, 4, 5, 6, 7, 0, time.UTC) + p, err := time.Parse(layout, ref.Format(layout)) + return err == nil && (p.Month() != time.January || p.Day() != 1) +} + // String returns a readable representation of this value (for usage defaults) func (t *timestampValue) String() string { return fmt.Sprintf("%v", t.timestamp) diff --git a/vendor/github.com/urfave/cli/v3/funcs.go b/vendor/github.com/urfave/cli/v3/funcs.go index fe1224c44e..17a73eca67 100644 --- a/vendor/github.com/urfave/cli/v3/funcs.go +++ b/vendor/github.com/urfave/cli/v3/funcs.go @@ -17,6 +17,13 @@ type AfterFunc func(context.Context, *Command) error // ActionFunc is the action to execute when no subcommands are specified type ActionFunc func(context.Context, *Command) error +// ArgValidatorFunc is an action to validate arguments before the command is run. +// If non-nil, it is called before the command's After and Action functions. +// Returning a non-nil error short-circuits the command and propagates as +// the exit error. If the current command does not set ArgValidator, the +// nearest ancestor that does is used instead. +type ArgValidatorFunc func(context.Context, *Command) error + // CommandNotFoundFunc is executed if the proper command cannot be found type CommandNotFoundFunc func(context.Context, *Command, string) diff --git a/vendor/github.com/urfave/cli/v3/godoc-current.txt b/vendor/github.com/urfave/cli/v3/godoc-current.txt index b3e9797175..dc41e1bd8b 100644 --- a/vendor/github.com/urfave/cli/v3/godoc-current.txt +++ b/vendor/github.com/urfave/cli/v3/godoc-current.txt @@ -258,6 +258,13 @@ type AfterFunc func(context.Context, *Command) error AfterFunc is an action that executes after any subcommands are run and have finished. The AfterFunc is run even if Action() panics. +type ArgValidatorFunc func(context.Context, *Command) error + ArgValidatorFunc is an action to validate arguments before the command + is run. If non-nil, it is called before the command's After and Action + functions. Returning a non-nil error short-circuits the command and + propagates as the exit error. If the current command does not set + ArgValidator, the nearest ancestor that does is used instead. + type Args interface { // Get returns the nth argument, or else a blank string Get(n int) string @@ -294,6 +301,7 @@ type ArgumentBase[T any, C any, VC ValueCreator[T, C]] struct { Value T `json:"value"` // the default value of this argument Destination *T `json:"-"` // the destination point for this argument UsageText string `json:"usageText"` // the usage text to show + Required bool `json:"required"` // whether the argument is required or not Config C `json:"config"` // config for this argument similar to Flag Config // Has unexported fields. @@ -415,6 +423,17 @@ func (bif *BoolWithInverseFlag) Set(name, val string) error func (bif *BoolWithInverseFlag) SetCategory(c string) +func (bif *BoolWithInverseFlag) SetStringer(s FlagStringFunc) + SetStringer overrides the FlagStringFunc used by this flag's String method. + Passing nil restores the default behavior of using the package-level + FlagStringer. This is used e.g. by MutuallyExclusiveFlags.Stringer. + + Note: unlike FlagBase, BoolWithInverseFlag.String only honors the + stringer partially. The names segment (the part before the first tab, e.g. + "--[no-]env, -e") is always recomputed from Name/Aliases/InversePrefix and + cannot be overridden; only the tab-delimited details after it come from the + stringer's output. + func (bif *BoolWithInverseFlag) String() string String implements the standard Stringer interface. @@ -485,6 +504,11 @@ type Command struct { // An action to execute after any subcommands are run, but after the subcommand has finished // It is run even if Action() panics After AfterFunc `json:"-"` + // An action to validate arguments before the command is run. If non-nil, it + // is called before Before and Action. If the current command does not set + // ArgValidator, the nearest ancestor that does is used instead. + // Returning a non-nil error short-circuits the command. + ArgValidator ArgValidatorFunc `json:"-"` // The function to call when this command is invoked Action ActionFunc `json:"-"` // Execute this function if the proper command cannot be found @@ -567,6 +591,9 @@ type Command struct { func (cmd *Command) Args() Args Args returns the command line arguments associated with the command. + If the command declares named Arguments, the arguments consumed by them + are not included in the returned Args and should be retrieved via the + command.{Type}Arg(name) functions instead. func (cmd *Command) Bool(name string) bool @@ -729,6 +756,9 @@ func (cmd *Command) StringSlice(name string) []string StringSlice looks up the value of a local StringSliceFlag, returns nil if not found +func (cmd *Command) Text(name string) TextMarshalUnmarshaler + Text looks up the value of a local TextFlag, returns nil if not found + func (cmd *Command) Timestamp(name string) time.Time Timestamp gets the timestamp from a flag name @@ -1062,6 +1092,11 @@ func (f *FlagBase[T, C, V]) Set(_ string, val string) error func (f *FlagBase[T, C, V]) SetCategory(c string) +func (f *FlagBase[T, C, V]) SetStringer(s FlagStringFunc) + SetStringer overrides the FlagStringFunc used by this flag's String method. + Passing nil restores the default behavior of using the package-level + FlagStringer. This is used e.g. by MutuallyExclusiveFlags.Stringer. + func (f *FlagBase[T, C, V]) String() string String returns a readable representation of this value (for usage defaults) @@ -1299,6 +1334,17 @@ type MutuallyExclusiveFlags struct { // Category to apply to all flags within group Category string + + // Stringer overrides how each flag within this group is displayed in + // help output. If nil, flags use [FlagStringer] as usual. + // + // The returned string must be unique per flag within the group (the + // default [stringifyFlag] guarantees this by embedding the flag's + // name). Help rendering keys flags by their String() output + // (flagCategories.AddFlag), so a Stringer that returns identical text + // for two or more flags in the same category will cause the later + // flag to silently overwrite the earlier one in help output. + Stringer FlagStringFunc `json:"-"` } MutuallyExclusiveFlags defines a mutually exclusive flag group Multiple option paths can be provided out of which only one can be defined on cmdline @@ -1396,10 +1442,32 @@ type StringSlice = SliceBase[string, StringConfig, stringValue] type StringSliceFlag = FlagBase[[]string, StringConfig, StringSlice] +type StringerSetter interface { + // SetStringer overrides the [FlagStringFunc] used by this flag's + // String method. Passing nil restores the default behavior of using + // the package-level [FlagStringer]. + SetStringer(FlagStringFunc) +} + StringerSetter is an optional interface that allows an individual flag to be + given a per-flag override of FlagStringer. FlagBase and BoolWithInverseFlag + implement this. It's used by MutuallyExclusiveFlags.Stringer to customize + how flags within a mutually exclusive group are displayed in help output. + type SuggestCommandFunc func(commands []*Command, provided string) string type SuggestFlagFunc func(flags []Flag, provided string, hideHelp bool) string +type TextFlag = FlagBase[TextMarshalUnmarshaler, StringConfig, textValue] + +type TextMarshalUnmarshaler interface { + encoding.TextMarshaler + encoding.TextUnmarshaler +} + TextMarshalUnmarshaler is the interface implemented by types that can + marshal themselves to and from a textual form. It is the value type used by + TextFlag, mirroring the standard library's flag.TextVar, and is satisfied by + types such as *slog.LevelVar, *net/netip.Addr, and *time.Time. + type TimestampArg = ArgumentBase[time.Time, TimestampConfig, timestampValue] type TimestampArgs = ArgumentsBase[time.Time, TimestampConfig, timestampValue] diff --git a/vendor/github.com/urfave/cli/v3/help.go b/vendor/github.com/urfave/cli/v3/help.go index a0f6c8cd5d..7a2480e565 100644 --- a/vendor/github.com/urfave/cli/v3/help.go +++ b/vendor/github.com/urfave/cli/v3/help.go @@ -257,12 +257,13 @@ func DefaultCompleteWithFlags(ctx context.Context, cmd *Command) { } argsLen := len(args) lastArg := "" - // parent command will have --generate-shell-completion so we need - // to account for that - if argsLen > 1 { - lastArg = args[argsLen-2] - } else if argsLen > 0 { + // os.Args retains the completion marker, but a child's parsed arguments + // have already had it removed. + if argsLen > 0 { lastArg = args[argsLen-1] + if lastArg == completionFlag && argsLen > 1 { + lastArg = args[argsLen-2] + } } if lastArg == completionFlag { @@ -487,13 +488,16 @@ func checkShellCompleteFlag(c *Command, arguments []string) (bool, []string) { return false, arguments } - // If arguments include "--" before the token being completed, shell completion - // is disabled because after "--" only positional arguments are accepted. + // If the token being completed is preceded by a "--", only positional + // arguments are accepted after it, so nothing will be suggested. // https://unix.stackexchange.com/a/11382 // Note: The token being completed is at position pos-1 (immediately before completionFlag). - // We only check arguments before that position, so completing "--" itself still works. + // A "--" at exactly that position is the token being completed, not a + // separator, so completing "--" itself still suggests flags. + // The request is still recognized as a completion so that the command + // action is never executed (https://github.com/urfave/cli/issues/1993). if pos >= 1 && slices.Contains(arguments[:pos-1], "--") { - return false, arguments[:pos] + c.shellCompletionPastDoubleDash = true } return true, arguments[:pos] @@ -520,6 +524,13 @@ func shouldRunCompletion(cmd *Command) bool { } func runCompletion(ctx context.Context, cmd *Command) { + // Nothing is suggested past a "--": after it, only positional arguments + // are accepted. The request is still treated as a completion so that the + // command action is never executed (https://github.com/urfave/cli/issues/1993). + if cmd.Root().shellCompletionPastDoubleDash { + tracef("completion requested past double dash; suggesting nothing (cmd=%[1]q)", cmd.Name) + return + } if cmd.ShellComplete != nil { tracef("running shell completion func for command %[1]q", cmd.Name) cmd.ShellComplete(ctx, cmd) diff --git a/vendor/github.com/urfave/cli/v3/mkdocs-requirements.txt b/vendor/github.com/urfave/cli/v3/mkdocs-requirements.txt index 479c8e8abb..9091cb7b69 100644 --- a/vendor/github.com/urfave/cli/v3/mkdocs-requirements.txt +++ b/vendor/github.com/urfave/cli/v3/mkdocs-requirements.txt @@ -1,5 +1,5 @@ -mkdocs-git-revision-date-localized-plugin==1.5.3 +mkdocs-git-revision-date-localized-plugin==1.5.4 mkdocs-material==9.7.7 mkdocs==1.6.1 mkdocs-redirects==1.2.3 -pygments==2.20.0 +pygments==2.21.0 diff --git a/vendor/github.com/urfave/cli/v3/value_source.go b/vendor/github.com/urfave/cli/v3/value_source.go index 44b0173b41..2dcee75870 100644 --- a/vendor/github.com/urfave/cli/v3/value_source.go +++ b/vendor/github.com/urfave/cli/v3/value_source.go @@ -119,6 +119,7 @@ func (e *envVarValueSource) Key() string { } func (e *envVarValueSource) String() string { return fmt.Sprintf("environment variable %[1]q", e.key) } + func (e *envVarValueSource) GoString() string { return fmt.Sprintf("&envVarValueSource{Key:%[1]q}", e.key) } diff --git a/vendor/modules.txt b/vendor/modules.txt index 0b4ed88e55..cd7171942b 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -415,7 +415,7 @@ github.com/ulikunitz/xz github.com/ulikunitz/xz/internal/hash github.com/ulikunitz/xz/internal/xlog github.com/ulikunitz/xz/lzma -# github.com/urfave/cli/v3 v3.11.0 +# github.com/urfave/cli/v3 v3.12.0 ## explicit; go 1.22 github.com/urfave/cli/v3 # github.com/x448/float16 v0.8.4