From 3d7a4cbf2130977036e96d50d56bcfba42307006 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Mar 2025 13:16:09 +0000 Subject: [PATCH] build(deps): bump github.com/alecthomas/kong from 1.6.1 to 1.9.0 Bumps [github.com/alecthomas/kong](https://github.com/alecthomas/kong) from 1.6.1 to 1.9.0. - [Release notes](https://github.com/alecthomas/kong/releases) - [Commits](https://github.com/alecthomas/kong/compare/v1.6.1...v1.9.0) --- updated-dependencies: - dependency-name: github.com/alecthomas/kong dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 +- .../github.com/alecthomas/kong/.golangci.yml | 5 +- vendor/github.com/alecthomas/kong/README.md | 41 ++++- vendor/github.com/alecthomas/kong/build.go | 22 ++- .../github.com/alecthomas/kong/callbacks.go | 148 ++++++++++++++---- vendor/github.com/alecthomas/kong/context.go | 79 +++++++--- vendor/github.com/alecthomas/kong/error.go | 11 +- vendor/github.com/alecthomas/kong/exit.go | 32 ++++ vendor/github.com/alecthomas/kong/help.go | 10 +- vendor/github.com/alecthomas/kong/kong.go | 19 ++- .../github.com/alecthomas/kong/lefthook.yml | 11 ++ vendor/github.com/alecthomas/kong/model.go | 3 + vendor/github.com/alecthomas/kong/options.go | 24 ++- vendor/github.com/alecthomas/kong/resolver.go | 2 +- vendor/github.com/alecthomas/kong/scanner.go | 5 + vendor/modules.txt | 2 +- 17 files changed, 341 insertions(+), 79 deletions(-) create mode 100644 vendor/github.com/alecthomas/kong/exit.go create mode 100644 vendor/github.com/alecthomas/kong/lefthook.yml diff --git a/go.mod b/go.mod index b6c2db81..1dd33e17 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/crazy-max/undock go 1.23.0 require ( - github.com/alecthomas/kong v1.6.1 + github.com/alecthomas/kong v1.9.0 github.com/containerd/platforms v0.2.1 github.com/containers/image/v5 v5.33.1 github.com/docker/docker v27.3.1+incompatible diff --git a/go.sum b/go.sum index 9ede9ae8..6ed52fea 100644 --- a/go.sum +++ b/go.sum @@ -37,8 +37,8 @@ github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpH github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= -github.com/alecthomas/kong v1.6.1 h1:/7bVimARU3uxPD0hbryPE8qWrS3Oz3kPQoxA/H2NKG8= -github.com/alecthomas/kong v1.6.1/go.mod h1:p2vqieVMeTAnaC83txKtXe8FLke2X07aruPWXyMPQrU= +github.com/alecthomas/kong v1.9.0 h1:Wgg0ll5Ys7xDnpgYBuBn/wPeLGAuK0NvYmEcisJgrIs= +github.com/alecthomas/kong v1.9.0/go.mod h1:p2vqieVMeTAnaC83txKtXe8FLke2X07aruPWXyMPQrU= github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= diff --git a/vendor/github.com/alecthomas/kong/.golangci.yml b/vendor/github.com/alecthomas/kong/.golangci.yml index 844092f9..1eb0b92e 100644 --- a/vendor/github.com/alecthomas/kong/.golangci.yml +++ b/vendor/github.com/alecthomas/kong/.golangci.yml @@ -12,7 +12,6 @@ linters: - wsl - funlen - gocognit - - gomnd - goprintffuncname - paralleltest - nlreturn @@ -36,12 +35,14 @@ linters: - nilnil - depguard # nothing to guard against yet - tagalign # hurts readability of kong tags + - tenv # deprecated since v1.64, but not removed yet - mnd - perfsprint - err113 - copyloopvar - intrange - - execinquery + - nakedret + - recvcheck # value receivers are intentionally used for copies linters-settings: govet: diff --git a/vendor/github.com/alecthomas/kong/README.md b/vendor/github.com/alecthomas/kong/README.md index 4a86251c..3b623443 100644 --- a/vendor/github.com/alecthomas/kong/README.md +++ b/vendor/github.com/alecthomas/kong/README.md @@ -13,7 +13,8 @@ - [Command handling](#command-handling) - [Switch on the command string](#switch-on-the-command-string) - [Attach a `Run(...) error` method to each command](#attach-a-run-error-method-to-each-command) -- [Hooks: BeforeReset(), BeforeResolve(), BeforeApply(), AfterApply() and the Bind() option](#hooks-beforereset-beforeresolve-beforeapply-afterapply-and-the-bind-option) +- [Hooks: BeforeReset(), BeforeResolve(), BeforeApply(), AfterApply()](#hooks-beforereset-beforeresolve-beforeapply-afterapply) +- [The Bind() option](#the-bind-option) - [Flags](#flags) - [Commands and sub-commands](#commands-and-sub-commands) - [Branching positional arguments](#branching-positional-arguments) @@ -305,7 +306,7 @@ func main() { ``` -## Hooks: BeforeReset(), BeforeResolve(), BeforeApply(), AfterApply() and the Bind() option +## Hooks: BeforeReset(), BeforeResolve(), BeforeApply(), AfterApply() If a node in the CLI, or any of its embedded fields, has a `BeforeReset(...) error`, `BeforeResolve (...) error`, `BeforeApply(...) error` and/or `AfterApply(...) error` method, those @@ -314,8 +315,6 @@ and after validation/assignment, respectively. The `--help` flag is implemented with a `BeforeReset` hook. -Arguments to hooks are provided via the `Run(...)` method or `Bind(...)` option. `*Kong`, `*Context` and `*Path` are also bound and finally, hooks can also contribute bindings via `kong.Context.Bind()` and `kong.Context.BindTo()`. - eg. ```go @@ -341,6 +340,40 @@ func main() { } ``` +## The Bind() option + +Arguments to hooks are provided via the `Run(...)` method or `Bind(...)` option. `*Kong`, `*Context`, `*Path` and parent commands are also bound and finally, hooks can also contribute bindings via `kong.Context.Bind()` and `kong.Context.BindTo()`. + +eg: + +```go +type CLI struct { + Debug bool `help:"Enable debug mode."` + + Rm RmCmd `cmd:"" help:"Remove files."` + Ls LsCmd `cmd:"" help:"List paths."` +} + +type AuthorName string + +// ... +func (l *LsCmd) Run(cli *CLI) error { +// use cli.Debug here !! + return nil +} + +func (r *RmCmD) Run(author AuthorName) error{ +// use binded author here + return nil +} + +func main() { + var cli CLI + + ctx := kong.Parse(&cli, Bind(AuthorName("penguin"))) + err := ctx.Run() +``` + ## Flags Any [mapped](#mapper---customising-how-the-command-line-is-mapped-to-go-values) field in the command structure _not_ tagged with `cmd` or `arg` will be a flag. Flags are optional by default. diff --git a/vendor/github.com/alecthomas/kong/build.go b/vendor/github.com/alecthomas/kong/build.go index 5d17f53f..63afcd4c 100644 --- a/vendor/github.com/alecthomas/kong/build.go +++ b/vendor/github.com/alecthomas/kong/build.go @@ -54,6 +54,7 @@ func flattenedFields(v reflect.Value, ptag *Tag) (out []flattenedField, err erro if v.Kind() != reflect.Struct { return out, nil } + ignored := map[string]bool{} for i := 0; i < v.NumField(); i++ { ft := v.Type().Field(i) fv := v.Field(i) @@ -61,7 +62,8 @@ func flattenedFields(v reflect.Value, ptag *Tag) (out []flattenedField, err erro if err != nil { return nil, err } - if tag.Ignored { + if tag.Ignored || ignored[ft.Name] { + ignored[ft.Name] = true continue } // Assign group if it's not already set. @@ -106,9 +108,27 @@ func flattenedFields(v reflect.Value, ptag *Tag) (out []flattenedField, err erro } out = append(out, sub...) } + out = removeIgnored(out, ignored) return out, nil } +func removeIgnored(fields []flattenedField, ignored map[string]bool) []flattenedField { + j := 0 + for i := 0; i < len(fields); i++ { + if ignored[fields[i].field.Name] { + continue + } + if i != j { + fields[j] = fields[i] + } + j++ + } + if j != len(fields) { + fields = fields[:j] + } + return fields +} + // Build a Node in the Kong data model. // // "v" is the value to create the node from, "typ" is the output Node type. diff --git a/vendor/github.com/alecthomas/kong/callbacks.go b/vendor/github.com/alecthomas/kong/callbacks.go index c1fac817..6096a260 100644 --- a/vendor/github.com/alecthomas/kong/callbacks.go +++ b/vendor/github.com/alecthomas/kong/callbacks.go @@ -6,10 +6,59 @@ import ( "strings" ) +// binding is a single binding registered with Kong. +type binding struct { + // fn is a function that returns a value of the target type. + fn reflect.Value + + // val is a value of the target type. + // Must be set if done and singleton are true. + val reflect.Value + + // singleton indicates whether the binding is a singleton. + // If true, the binding will be resolved once and cached. + singleton bool + + // done indicates whether a singleton binding has been resolved. + // If singleton is false, this field is ignored. + done bool +} + +// newValueBinding builds a binding with an already resolved value. +func newValueBinding(v reflect.Value) *binding { + return &binding{val: v, done: true, singleton: true} +} + +// newFunctionBinding builds a binding with a function +// that will return a value of the target type. +// +// The function signature must be func(...) (T, error) or func(...) T +// where parameters are recursively resolved. +func newFunctionBinding(f reflect.Value, singleton bool) *binding { + return &binding{fn: f, singleton: singleton} +} + +// Get returns the pre-resolved value for the binding, +// or false if the binding is not resolved. +func (b *binding) Get() (v reflect.Value, ok bool) { + return b.val, b.done +} + +// Set sets the value of the binding to the given value, +// marking it as resolved. +// +// If the binding is not a singleton, this method does nothing. +func (b *binding) Set(v reflect.Value) { + if b.singleton { + b.val = v + b.done = true + } +} + // A map of type to function that returns a value of that type. // // The function should have the signature func(...) (T, error). Arguments are recursively resolved. -type bindings map[reflect.Type]any +type bindings map[reflect.Type]*binding func (b bindings) String() string { out := []string{} @@ -21,24 +70,34 @@ func (b bindings) String() string { func (b bindings) add(values ...any) bindings { for _, v := range values { - v := v - b[reflect.TypeOf(v)] = func() (any, error) { return v, nil } + val := reflect.ValueOf(v) + b[val.Type()] = newValueBinding(val) } return b } func (b bindings) addTo(impl, iface any) { - b[reflect.TypeOf(iface).Elem()] = func() (any, error) { return impl, nil } + val := reflect.ValueOf(impl) + b[reflect.TypeOf(iface).Elem()] = newValueBinding(val) } -func (b bindings) addProvider(provider any) error { +func (b bindings) addProvider(provider any, singleton bool) error { pv := reflect.ValueOf(provider) t := pv.Type() - if t.Kind() != reflect.Func || t.NumOut() != 2 || t.Out(1) != reflect.TypeOf((*error)(nil)).Elem() { - return fmt.Errorf("%T must be a function with the signature func(...)(T, error)", provider) + if t.Kind() != reflect.Func { + return fmt.Errorf("%T must be a function", provider) + } + + if t.NumOut() == 0 { + return fmt.Errorf("%T must be a function with the signature func(...)(T, error) or func(...) T", provider) + } + if t.NumOut() == 2 { + if t.Out(1) != reflect.TypeOf((*error)(nil)).Elem() { + return fmt.Errorf("missing error; %T must be a function with the signature func(...)(T, error) or func(...) T", provider) + } } rt := pv.Type().Out(0) - b[rt] = provider + b[rt] = newFunctionBinding(pv, singleton) return nil } @@ -68,31 +127,48 @@ func getMethod(value reflect.Value, name string) reflect.Value { return method } -// Get methods from the given value and any embedded fields. -func getMethods(value reflect.Value, name string) []reflect.Value { - // Collect all possible receivers - receivers := []reflect.Value{value} +// getMethods gets all methods with the given name from the given value +// and any embedded fields. +// +// Returns a slice of bound methods that can be called directly. +func getMethods(value reflect.Value, name string) (methods []reflect.Value) { if value.Kind() == reflect.Ptr { value = value.Elem() } - if value.Kind() == reflect.Struct { - t := value.Type() - for i := 0; i < value.NumField(); i++ { - field := value.Field(i) - fieldType := t.Field(i) - if fieldType.IsExported() && fieldType.Anonymous { - receivers = append(receivers, field) - } - } + if !value.IsValid() { + return + } + + if method := getMethod(value, name); method.IsValid() { + methods = append(methods, method) } - // Search all receivers for methods - var methods []reflect.Value - for _, receiver := range receivers { - if method := getMethod(receiver, name); method.IsValid() { - methods = append(methods, method) + + if value.Kind() != reflect.Struct { + return + } + // If the current value is a struct, also consider embedded fields. + // Two kinds of embedded fields are considered if they're exported: + // + // - standard Go embedded fields + // - fields tagged with `embed:""` + t := value.Type() + for i := 0; i < value.NumField(); i++ { + fieldValue := value.Field(i) + field := t.Field(i) + + if !field.IsExported() { + continue + } + + // Consider a field embedded if it's actually embedded + // or if it's tagged with `embed:""`. + _, isEmbedded := field.Tag.Lookup("embed") + isEmbedded = isEmbedded || field.Anonymous + if isEmbedded { + methods = append(methods, getMethods(fieldValue, name)...) } } - return methods + return } func callFunction(f reflect.Value, bindings bindings) error { @@ -122,19 +198,29 @@ func callAnyFunction(f reflect.Value, bindings bindings) (out []any, err error) t := f.Type() for i := 0; i < t.NumIn(); i++ { pt := t.In(i) - argf, ok := bindings[pt] + binding, ok := bindings[pt] if !ok { return nil, fmt.Errorf("couldn't find binding of type %s for parameter %d of %s(), use kong.Bind(%s)", pt, i, t, pt) } + + // Don't need to call the function if the value is already resolved. + if val, ok := binding.Get(); ok { + in = append(in, val) + continue + } + // Recursively resolve binding functions. - argv, err := callAnyFunction(reflect.ValueOf(argf), bindings) + argv, err := callAnyFunction(binding.fn, bindings) if err != nil { return nil, fmt.Errorf("%s: %w", pt, err) } - if ferrv := reflect.ValueOf(argv[len(argv)-1]); ferrv.IsValid() && !ferrv.IsNil() { + if ferrv := reflect.ValueOf(argv[len(argv)-1]); ferrv.IsValid() && ferrv.Type().Implements(callbackReturnSignature) && !ferrv.IsNil() { return nil, ferrv.Interface().(error) //nolint:forcetypeassert } - in = append(in, reflect.ValueOf(argv[0])) + + val := reflect.ValueOf(argv[0]) + binding.Set(val) + in = append(in, val) } outv := f.Call(in) out = make([]any, len(outv)) diff --git a/vendor/github.com/alecthomas/kong/context.go b/vendor/github.com/alecthomas/kong/context.go index b6a56e33..16a73539 100644 --- a/vendor/github.com/alecthomas/kong/context.go +++ b/vendor/github.com/alecthomas/kong/context.go @@ -26,6 +26,9 @@ type Path struct { // True if this Path element was created as the result of a resolver. Resolved bool + + // Remaining tokens after this node + remainder []Token } // Node returns the Node associated with this Path, or nil if Path is a non-Node. @@ -64,6 +67,15 @@ func (p *Path) Visitable() Visitable { return nil } +// Remainder returns the remaining unparsed args after this Path element. +func (p *Path) Remainder() []string { + args := []string{} + for _, token := range p.remainder { + args = append(args, token.String()) + } + return args +} + // Context contains the current parse context. type Context struct { *Kong @@ -87,14 +99,15 @@ type Context struct { // This just constructs a new trace. To fully apply the trace you must call Reset(), Resolve(), // Validate() and Apply(). func Trace(k *Kong, args []string) (*Context, error) { + s := Scan(args...) c := &Context{ Kong: k, Args: args, Path: []*Path{ - {App: k.Model, Flags: k.Model.Flags}, + {App: k.Model, Flags: k.Model.Flags, remainder: s.PeekAll()}, }, values: map[*Value]reflect.Value{}, - scan: Scan(args...), + scan: s, bindings: bindings{}, } c.Error = c.trace(c.Model.Node) @@ -119,8 +132,20 @@ func (c *Context) BindTo(impl, iface any) { // // This is useful when the Run() function of different commands require different values that may // not all be initialisable from the main() function. +// +// "provider" must be a function with the signature func(...) (T, error) or func(...) T, +// where ... will be recursively injected with bound values. func (c *Context) BindToProvider(provider any) error { - return c.bindings.addProvider(provider) + return c.bindings.addProvider(provider, false /* singleton */) +} + +// BindSingletonProvider allows binding of provider functions. +// The provider will be called once and the result cached. +// +// "provider" must be a function with the signature func(...) (T, error) or func(...) T, +// where ... will be recursively injected with bound values. +func (c *Context) BindSingletonProvider(provider any) error { + return c.bindings.addProvider(provider, true /* singleton */) } // Value returns the value for a particular path element. @@ -465,6 +490,7 @@ func (c *Context) trace(node *Node) (err error) { //nolint: gocyclo c.Path = append(c.Path, &Path{ Parent: node, Positional: arg, + remainder: c.scan.PeekAll(), }) positional++ break @@ -496,9 +522,10 @@ func (c *Context) trace(node *Node) (err error) { //nolint: gocyclo if branch.Type == CommandNode && branch.Name == token.Value { c.scan.Pop() c.Path = append(c.Path, &Path{ - Parent: node, - Command: branch, - Flags: branch.Flags, + Parent: node, + Command: branch, + Flags: branch.Flags, + remainder: c.scan.PeekAll(), }) return c.trace(branch) } @@ -510,9 +537,10 @@ func (c *Context) trace(node *Node) (err error) { //nolint: gocyclo arg := branch.Argument if err := arg.Parse(c.scan, c.getValue(arg)); err == nil { c.Path = append(c.Path, &Path{ - Parent: node, - Argument: branch, - Flags: branch.Flags, + Parent: node, + Argument: branch, + Flags: branch.Flags, + remainder: c.scan.PeekAll(), }) return c.trace(branch) } @@ -523,9 +551,10 @@ func (c *Context) trace(node *Node) (err error) { //nolint: gocyclo // matches, take the branch of the default command if node.DefaultCmd != nil && node.DefaultCmd.Tag.Default == "withargs" { c.Path = append(c.Path, &Path{ - Parent: node, - Command: node.DefaultCmd, - Flags: node.DefaultCmd.Flags, + Parent: node, + Command: node.DefaultCmd, + Flags: node.DefaultCmd.Flags, + remainder: c.scan.PeekAll(), }) return c.trace(node.DefaultCmd) } @@ -538,19 +567,25 @@ func (c *Context) trace(node *Node) (err error) { //nolint: gocyclo return c.maybeSelectDefault(flags, node) } +// IgnoreDefault can be implemented by flags that want to be applied before any default commands. +type IgnoreDefault interface { + IgnoreDefault() +} + // End of the line, check for a default command, but only if we're not displaying help, // otherwise we'd only ever display the help for the default command. func (c *Context) maybeSelectDefault(flags []*Flag, node *Node) error { for _, flag := range flags { - if flag.Name == "help" && flag.Set { + if _, ok := flag.Target.Interface().(IgnoreDefault); ok && flag.Set { return nil } } if node.DefaultCmd != nil { c.Path = append(c.Path, &Path{ - Parent: node.DefaultCmd, - Command: node.DefaultCmd, - Flags: node.DefaultCmd.Flags, + Parent: node.DefaultCmd, + Command: node.DefaultCmd, + Flags: node.DefaultCmd.Flags, + remainder: c.scan.PeekAll(), }) } return nil @@ -595,8 +630,9 @@ func (c *Context) Resolve() error { return err } inserted = append(inserted, &Path{ - Flag: flag, - Resolved: true, + Flag: flag, + Resolved: true, + remainder: c.scan.PeekAll(), }) } } @@ -740,7 +776,10 @@ func (c *Context) parseFlag(flags []*Flag, match string) (err error) { } flag.Value.Apply(value) } - c.Path = append(c.Path, &Path{Flag: flag}) + c.Path = append(c.Path, &Path{ + Flag: flag, + remainder: c.scan.PeekAll(), + }) return nil } return &unknownFlagError{Cause: findPotentialCandidates(match, candidates, "unknown flag %s", match)} @@ -789,7 +828,7 @@ func (c *Context) RunNode(node *Node, binds ...any) (err error) { methodt := t.Method(i) if strings.HasPrefix(methodt.Name, "Provide") { method := p.Method(i) - if err := methodBinds.addProvider(method.Interface()); err != nil { + if err := methodBinds.addProvider(method.Interface(), false /* singleton */); err != nil { return fmt.Errorf("%s.%s: %w", t.Name(), methodt.Name, err) } } diff --git a/vendor/github.com/alecthomas/kong/error.go b/vendor/github.com/alecthomas/kong/error.go index 18225ef5..e79a15dc 100644 --- a/vendor/github.com/alecthomas/kong/error.go +++ b/vendor/github.com/alecthomas/kong/error.go @@ -5,8 +5,17 @@ package kong // It contains the parse Context that triggered the error. type ParseError struct { error - Context *Context + Context *Context + exitCode int } // Unwrap returns the original cause of the error. func (p *ParseError) Unwrap() error { return p.error } + +// ExitCode returns the status that Kong should exit with if it fails with a ParseError. +func (p *ParseError) ExitCode() int { + if p.exitCode == 0 { + return exitNotOk + } + return p.exitCode +} diff --git a/vendor/github.com/alecthomas/kong/exit.go b/vendor/github.com/alecthomas/kong/exit.go new file mode 100644 index 00000000..4925f483 --- /dev/null +++ b/vendor/github.com/alecthomas/kong/exit.go @@ -0,0 +1,32 @@ +package kong + +import "errors" + +const ( + exitOk = 0 + exitNotOk = 1 + + // Semantic exit codes from https://github.com/square/exit?tab=readme-ov-file#about + exitUsageError = 80 +) + +// ExitCoder is an interface that may be implemented by an error value to +// provide an integer exit code. The method ExitCode should return an integer +// that is intended to be used as the exit code for the application. +type ExitCoder interface { + ExitCode() int +} + +// exitCodeFromError returns the exit code for the given error. +// If err implements the exitCoder interface, the ExitCode method is called. +// Otherwise, exitCodeFromError returns 0 if err is nil, and 1 if it is not. +func exitCodeFromError(err error) int { + var e ExitCoder + if errors.As(err, &e) { + return e.ExitCode() + } else if err == nil { + return exitOk + } + + return exitNotOk +} diff --git a/vendor/github.com/alecthomas/kong/help.go b/vendor/github.com/alecthomas/kong/help.go index 6363ea21..8da15557 100644 --- a/vendor/github.com/alecthomas/kong/help.go +++ b/vendor/github.com/alecthomas/kong/help.go @@ -14,9 +14,11 @@ const ( ) // Help flag. -type helpValue bool +type helpFlag bool -func (h helpValue) BeforeReset(ctx *Context) error { +func (h helpFlag) IgnoreDefault() {} + +func (h helpFlag) BeforeReset(ctx *Context) error { options := ctx.Kong.helpOptions options.Summary = false err := ctx.Kong.help(options, ctx) @@ -415,7 +417,7 @@ func (h *helpWriter) Write(w io.Writer) error { func (h *helpWriter) Wrap(text string) { w := bytes.NewBuffer(nil) - doc.ToText(w, strings.TrimSpace(text), "", " ", h.width) + doc.ToText(w, strings.TrimSpace(text), "", " ", h.width) //nolint:staticcheck // cross-package links not possible for _, line := range strings.Split(strings.TrimSpace(w.String()), "\n") { h.Print(line) } @@ -470,7 +472,7 @@ func writeTwoColumns(w *helpWriter, rows [][2]string) { for _, row := range rows { buf := bytes.NewBuffer(nil) - doc.ToText(buf, row[1], "", strings.Repeat(" ", defaultIndent), w.width-leftSize-defaultColumnPadding) + doc.ToText(buf, row[1], "", strings.Repeat(" ", defaultIndent), w.width-leftSize-defaultColumnPadding) //nolint:staticcheck // cross-package links not possible lines := strings.Split(strings.TrimRight(buf.String(), "\n"), "\n") line := fmt.Sprintf("%-*s", leftSize, row[0]) diff --git a/vendor/github.com/alecthomas/kong/kong.go b/vendor/github.com/alecthomas/kong/kong.go index b85e1452..4f6be877 100644 --- a/vendor/github.com/alecthomas/kong/kong.go +++ b/vendor/github.com/alecthomas/kong/kong.go @@ -283,7 +283,7 @@ func (k *Kong) extraFlags() []*Flag { if k.noDefaultHelp { return nil } - var helpTarget helpValue + var helpTarget helpFlag value := reflect.ValueOf(&helpTarget).Elem() helpFlag := &Flag{ Short: 'h', @@ -311,11 +311,11 @@ func (k *Kong) extraFlags() []*Flag { // invalid one, which will report a normal error). func (k *Kong) Parse(args []string) (ctx *Context, err error) { ctx, err = Trace(k, args) - if err != nil { - return nil, err + if err != nil { // Trace is not expected to return an err + return nil, &ParseError{error: err, Context: ctx, exitCode: exitUsageError} } if ctx.Error != nil { - return nil, &ParseError{error: ctx.Error, Context: ctx} + return nil, &ParseError{error: ctx.Error, Context: ctx, exitCode: exitUsageError} } if err = k.applyHook(ctx, "BeforeReset"); err != nil { return nil, &ParseError{error: err, Context: ctx} @@ -332,11 +332,11 @@ func (k *Kong) Parse(args []string) (ctx *Context, err error) { if err = k.applyHook(ctx, "BeforeApply"); err != nil { return nil, &ParseError{error: err, Context: ctx} } - if _, err = ctx.Apply(); err != nil { + if _, err = ctx.Apply(); err != nil { // Apply is not expected to return an err return nil, &ParseError{error: err, Context: ctx} } if err = ctx.Validate(); err != nil { - return nil, &ParseError{error: err, Context: ctx} + return nil, &ParseError{error: err, Context: ctx, exitCode: exitUsageError} } if err = k.applyHook(ctx, "AfterApply"); err != nil { return nil, &ParseError{error: err, Context: ctx} @@ -428,13 +428,15 @@ func (k *Kong) Errorf(format string, args ...any) *Kong { return k } -// Fatalf writes a message to Kong.Stderr with the application name prefixed then exits with a non-zero status. +// Fatalf writes a message to Kong.Stderr with the application name prefixed then exits with status 1. func (k *Kong) Fatalf(format string, args ...any) { k.Errorf(format, args...) k.Exit(1) } // FatalIfErrorf terminates with an error message if err != nil. +// If the error implements the ExitCoder interface, the ExitCode() method is called and +// the application exits with that status. Otherwise, the application exits with status 1. func (k *Kong) FatalIfErrorf(err error, args ...any) { if err == nil { return @@ -455,7 +457,8 @@ func (k *Kong) FatalIfErrorf(err error, args ...any) { fmt.Fprintln(k.Stdout) } } - k.Fatalf("%s", msg) + k.Errorf("%s", msg) + k.Exit(exitCodeFromError(err)) } // LoadConfig from path using the loader configured via Configuration(loader). diff --git a/vendor/github.com/alecthomas/kong/lefthook.yml b/vendor/github.com/alecthomas/kong/lefthook.yml new file mode 100644 index 00000000..28ba9ad9 --- /dev/null +++ b/vendor/github.com/alecthomas/kong/lefthook.yml @@ -0,0 +1,11 @@ +output: + - success + - failure +pre-push: + parallel: true + jobs: + - name: test + run: go test -v ./... + + - name: lint + run: golangci-lint run diff --git a/vendor/github.com/alecthomas/kong/model.go b/vendor/github.com/alecthomas/kong/model.go index 065fcdd0..33a6f333 100644 --- a/vendor/github.com/alecthomas/kong/model.go +++ b/vendor/github.com/alecthomas/kong/model.go @@ -167,6 +167,9 @@ func (n *Node) Summary() string { allFlags = append(allFlags, n.Parent.Flags...) } for _, flag := range allFlags { + if _, ok := flag.Target.Interface().(helpFlag); ok { + continue + } if !flag.Required { summary += " [flags]" break diff --git a/vendor/github.com/alecthomas/kong/options.go b/vendor/github.com/alecthomas/kong/options.go index 6263202b..d20b2fba 100644 --- a/vendor/github.com/alecthomas/kong/options.go +++ b/vendor/github.com/alecthomas/kong/options.go @@ -210,15 +210,33 @@ func BindTo(impl, iface any) Option { // BindToProvider binds an injected value to a provider function. // -// The provider function must have the signature: +// The provider function must have one of the following signatures: +// +// func(...) (T, error) +// func(...) T // -// func() (any, error) +// Where arguments to the function are injected by Kong. // // This is useful when the Run() function of different commands require different values that may // not all be initialisable from the main() function. func BindToProvider(provider any) Option { return OptionFunc(func(k *Kong) error { - return k.bindings.addProvider(provider) + return k.bindings.addProvider(provider, false /* singleton */) + }) +} + +// BindSingletonProvider binds an injected value to a provider function. +// The provider function must have the signature: +// +// func(...) (T, error) +// func(...) T +// +// Unlike [BindToProvider], the provider function will only be called +// at most once, and the result will be cached and reused +// across multiple recipients of the injected value. +func BindSingletonProvider(provider any) Option { + return OptionFunc(func(k *Kong) error { + return k.bindings.addProvider(provider, true /* singleton */) }) } diff --git a/vendor/github.com/alecthomas/kong/resolver.go b/vendor/github.com/alecthomas/kong/resolver.go index 29be1b91..3e37ca73 100644 --- a/vendor/github.com/alecthomas/kong/resolver.go +++ b/vendor/github.com/alecthomas/kong/resolver.go @@ -63,6 +63,6 @@ func JSON(r io.Reader) (Resolver, error) { } func snakeCase(name string) string { - name = strings.Join(strings.Split(strings.Title(name), "-"), "") + name = strings.Join(strings.Split(strings.Title(name), "-"), "") //nolint:staticcheck // Unicode punctuation not an issue return strings.ToLower(name[:1]) + name[1:] } diff --git a/vendor/github.com/alecthomas/kong/scanner.go b/vendor/github.com/alecthomas/kong/scanner.go index 262d16f1..68f708e8 100644 --- a/vendor/github.com/alecthomas/kong/scanner.go +++ b/vendor/github.com/alecthomas/kong/scanner.go @@ -203,6 +203,11 @@ func (s *Scanner) Peek() Token { return s.args[0] } +// PeekAll remaining tokens +func (s *Scanner) PeekAll() []Token { + return s.args +} + // Push an untyped Token onto the front of the Scanner. func (s *Scanner) Push(arg any) *Scanner { s.PushToken(Token{Value: arg}) diff --git a/vendor/modules.txt b/vendor/modules.txt index ae24ea09..e9666981 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -50,7 +50,7 @@ github.com/VividCortex/ewma # github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d ## explicit github.com/acarl005/stripansi -# github.com/alecthomas/kong v1.6.1 +# github.com/alecthomas/kong v1.9.0 ## explicit; go 1.20 github.com/alecthomas/kong # github.com/andybalholm/brotli v1.1.1