From 1382bea590abbe562a618db0aa40f43cc3668bce Mon Sep 17 00:00:00 2001 From: andrey Date: Tue, 6 Jan 2026 16:19:45 +0300 Subject: [PATCH] update commands --- app.go | 15 ++- command.go | 4 +- command/command.go | 32 ++++--- command/commands.go | 16 ++-- command/dump/reference.go | 67 ++++++++++++++ command/dump/reference_config.go | 89 ++++++++++++++++++ command/help/command.go | 28 ++++-- command/list/command.go | 16 ++-- command/list/help.go | 4 +- command_test.go | 6 +- console.go | 13 ++- {errors => errs}/errors.go | 2 +- go.mod | 7 +- go.sum | 6 +- output/descriptor/descriptor.go | 1 + output/descriptor/txt.go | 32 +++++-- param/keys.go | 90 ------------------ {param => setting}/helper.go | 6 +- setting/keys.go | 127 ++++++++++++++++++++++++++ param/params.go => setting/setting.go | 18 ++-- 20 files changed, 414 insertions(+), 165 deletions(-) create mode 100644 command/dump/reference.go create mode 100644 command/dump/reference_config.go rename {errors => errs}/errors.go (95%) delete mode 100644 param/keys.go rename {param => setting}/helper.go (65%) create mode 100644 setting/keys.go rename param/params.go => setting/setting.go (66%) diff --git a/app.go b/app.go index 6b41af9..93822bb 100644 --- a/app.go +++ b/app.go @@ -33,7 +33,10 @@ func WithInput(in config.BindProvider) func(*App) { // WithSkipArgs sets how many arguments are passed. For example, you don't need to pass the name of a single command. func WithSkipArgs(l int) func(*App) { - return WithInput(chain.New(arg.New(arg.WithArgs(os.Args[resolveSkip(l):])), &memory.Default{})) + return WithInput(chain.New( + arg.New(arg.WithArgs(os.Args[ResolveSkip(l):])), + &memory.Default{}), + ) } // WithExit sets exit callback by default os.Exit. @@ -53,7 +56,7 @@ func New(opts ...func(*App)) *App { out: output.Stdout(), exit: os.Exit, in: chain.New( - arg.New(arg.WithArgs(os.Args[resolveSkip(0):])), + arg.New(arg.WithArgs(os.Args[ResolveSkip(0):])), &memory.Default{}, ), registry: registry.Add, @@ -134,10 +137,14 @@ func (a *App) list(ctx context.Context) error { } func (a *App) printError(ctx context.Context, err error) { - command.Ansi(ctx, a.in, a.out).Println(ctx, "\n\n ", err, "\n") + printErr(ctx, a.in, a.out, err) } -func resolveSkip(in int) int { +func printErr(ctx context.Context, in config.Provider, out output.Output, err error) { + command.Ansi(ctx, in, out).Printf(ctx, "\n\n %v\n\n", err) +} + +func ResolveSkip(in int) int { res := 2 switch { diff --git a/command.go b/command.go index ffe344b..52f6705 100644 --- a/command.go +++ b/command.go @@ -6,7 +6,7 @@ import ( "gitoa.ru/go-4devs/config" "gitoa.ru/go-4devs/console/command" - "gitoa.ru/go-4devs/console/errors" + "gitoa.ru/go-4devs/console/errs" "gitoa.ru/go-4devs/console/output" ) @@ -115,7 +115,7 @@ func (c *Command) With(opts ...Option) *Command { // Run run command with input and output. func (c *Command) Run(ctx context.Context, in config.Provider, out output.Output) error { if c.Execute == nil { - return fmt.Errorf("%w", errors.ErrExecuteNil) + return fmt.Errorf("%w", errs.ErrExecuteNil) } if c.Handle != nil { diff --git a/command/command.go b/command/command.go index f656af0..bc9d0d2 100644 --- a/command/command.go +++ b/command/command.go @@ -3,11 +3,10 @@ package command import ( "context" "fmt" - "log" "gitoa.ru/go-4devs/config" "gitoa.ru/go-4devs/console/output" - "gitoa.ru/go-4devs/console/param" + "gitoa.ru/go-4devs/console/setting" ) type ( @@ -27,17 +26,17 @@ func Configure(fn ConfigureFn) Option { func Version(in string) Option { return func(c *Command) { - c.Params = param.WithVersion(in)(c.Params) + c.Setting = setting.WithVersion(in)(c.Setting) } } func Hidden(c *Command) { - c.Params = param.Hidden(c.Params) + c.Setting = setting.Hidden(c.Setting) } -func Help(fn param.HelpFn) Option { +func Help(fn setting.HelpFn) Option { return func(c *Command) { - c.Params = param.WithHelp(fn)(c.Params) + c.Setting = setting.WithHelp(fn)(c.Setting) } } @@ -61,6 +60,18 @@ func Prepare(fn PrepareFn) Option { } } +func Usage(fn setting.UsageFn) Option { + return func(c *Command) { + c.Setting = setting.WithUsage(fn)(c.Setting) + } +} + +func EmptyUsage(cmd *Command) { + cmd.Setting = setting.WithUsage(func(setting.UData) (string, error) { + return "", nil + })(cmd.Setting) +} + func New(name, desc string, execute ExecuteFn, opts ...Option) Command { cmd := Command{ name: name, @@ -68,7 +79,7 @@ func New(name, desc string, execute ExecuteFn, opts ...Option) Command { configure: emptyConfigure, handle: emptyHandle, prepare: emptyPrepare, - Params: param.New(param.WithDescription(desc)), + Setting: setting.New(setting.WithDescription(desc)), } for _, opt := range opts { @@ -79,7 +90,7 @@ func New(name, desc string, execute ExecuteFn, opts ...Option) Command { } type Command struct { - param.Params + setting.Setting name string execute ExecuteFn @@ -109,13 +120,12 @@ func (c Command) IsZero() bool { } func (c Command) String() string { - return fmt.Sprintf("command:%v, version:%v", c.Name(), param.Version(c)) + return fmt.Sprintf("command:%v, version:%v", c.Name(), setting.Version(c)) } func With(parent Command, opts ...Option) Command { - log.Print(parent.Name()) cmd := Command{ - Params: parent.Params, + Setting: parent.Setting, name: parent.Name(), execute: parent.Execute, configure: parent.Configure, diff --git a/command/commands.go b/command/commands.go index 81a7041..085fcac 100644 --- a/command/commands.go +++ b/command/commands.go @@ -6,8 +6,8 @@ import ( "sort" "sync" - cerr "gitoa.ru/go-4devs/console/errors" - "gitoa.ru/go-4devs/console/param" + "gitoa.ru/go-4devs/console/errs" + "gitoa.ru/go-4devs/console/setting" ) var findCommand = regexp.MustCompile("([^:]+|)") @@ -71,7 +71,7 @@ func (c *Commands) find(name string) (Command, error) { } for name, idx := range c.names { - if cmdRegexp.MatchString(name) && !param.IsHidden(c.cmds[idx]) { + if cmdRegexp.MatchString(name) && !setting.IsHidden(c.cmds[idx]) { findCommands = append(findCommands, c.cmds[idx]) } } @@ -86,10 +86,10 @@ func (c *Commands) find(name string) (Command, error) { names[i] = findCommands[i].Name() } - return Command{}, cerr.AlternativesError{Alt: names, Err: cerr.ErrCommandDplicate} + return Command{}, errs.AlternativesError{Alt: names, Err: errs.ErrCommandDplicate} } - return Command{}, fmt.Errorf("%w", cerr.ErrNotFound) + return Command{}, fmt.Errorf("%w", errs.ErrNotFound) } func (c *Commands) set(cmds ...Command) error { @@ -99,7 +99,7 @@ func (c *Commands) set(cmds ...Command) error { for _, cmd := range cmds { if cmd.IsZero() { - return fmt.Errorf("command:%w", cerr.ErrCommandNil) + return fmt.Errorf("command:%w", errs.ErrCommandNil) } if idx, ok := c.names[cmd.Name()]; ok { @@ -122,11 +122,11 @@ func (c *Commands) add(cmds ...Command) error { for _, cmd := range cmds { if cmd.IsZero() { - return fmt.Errorf("command:%w", cerr.ErrCommandNil) + return fmt.Errorf("command:%w", errs.ErrCommandNil) } if _, ok := c.names[cmd.Name()]; ok { - return fmt.Errorf("command %s:%w", cmd.Name(), cerr.ErrCommandDplicate) + return fmt.Errorf("command %s:%w", cmd.Name(), errs.ErrCommandDplicate) } c.names[cmd.Name()] = len(c.cmds) diff --git a/command/dump/reference.go b/command/dump/reference.go new file mode 100644 index 0000000..552460b --- /dev/null +++ b/command/dump/reference.go @@ -0,0 +1,67 @@ +package dump + +import ( + "context" + "fmt" + + "gitoa.ru/go-4devs/config" + "gitoa.ru/go-4devs/config/definition" + "gitoa.ru/go-4devs/config/definition/option" + "gitoa.ru/go-4devs/config/provider/arg" + "gitoa.ru/go-4devs/console/command" + "gitoa.ru/go-4devs/console/errs" + "gitoa.ru/go-4devs/console/internal/registry" + "gitoa.ru/go-4devs/console/output" +) + +//go:generate go tool config config:generate + +const NameRefernce = "config:dump-reference" + +func Command() command.Command { + return command.New(NameRefernce, "dump reference by command", RExecute, command.Configure(RConfigure)) +} + +func RExecute(ctx context.Context, in config.Provider, out output.Output) error { + provs, ok := in.(config.Providers) + if !ok { + return fmt.Errorf("%w: expect %T got %T", errs.ErrWrongType, (config.Providers)(nil), in) + } + + cfg := NewRConfigureConfig(in) + + cmd, err := registry.Find(cfg.CommandName(ctx)) + if err != nil { + return fmt.Errorf("cmd:%w", err) + } + + def := definition.New() + if err := cmd.Configure(ctx, def); err != nil { + return fmt.Errorf("configure:%w", err) + } + + prov, err := provs.Provider(cfg.Format(ctx)) + if err != nil { + return fmt.Errorf("prov:%w", errs.AlternativesError{Alt: provs.Names(), Err: err}) + } + + bind, ok := prov.(config.DumpProvider) + if !ok { + return fmt.Errorf("%w: expect config.DunpProvider got %T", errs.ErrWrongType, prov) + } + + if err := bind.DumpReference(ctx, out, def); err != nil { + return fmt.Errorf("dump:%w", err) + } + + return nil +} + +func RConfigure(_ context.Context, def config.Definition) error { + def.Add( + arg.String("command-name", "command name", option.Required), + option.String("format", "format", option.Default(arg.Name)), + ) + + return nil +} diff --git a/command/dump/reference_config.go b/command/dump/reference_config.go new file mode 100644 index 0000000..3ba74ec --- /dev/null +++ b/command/dump/reference_config.go @@ -0,0 +1,89 @@ +// Code generated gitoa.ru/go-4devs/config DO NOT EDIT. +package dump + +import ( + "context" + "fmt" + "gitoa.ru/go-4devs/config" +) + +func WithRConfigureConfigHandle(fn func(context.Context, error)) func(*RConfigureConfig) { + return func(ci *RConfigureConfig) { + ci.handle = fn + } +} + +func NewRConfigureConfig(prov config.Provider, opts ...func(*RConfigureConfig)) RConfigureConfig { + i := RConfigureConfig{ + Provider: prov, + handle: func(_ context.Context, err error) { + fmt.Printf("RConfigureConfig:%v", err) + }, + } + + for _, opt := range opts { + opt(&i) + } + + return i +} + +type RConfigureConfig struct { + config.Provider + handle func(context.Context, error) +} + +// readCommandName command name. +func (i RConfigureConfig) readCommandName(ctx context.Context) (v string, e error) { + val, err := i.Value(ctx, "command-name") + if err != nil { + return v, fmt.Errorf("read [%v]:%w", []string{"command-name"}, err) + + } + + return val.ParseString() + +} + +// ReadCommandName command name. +func (i RConfigureConfig) ReadCommandName(ctx context.Context) (string, error) { + return i.readCommandName(ctx) +} + +// CommandName command name. +func (i RConfigureConfig) CommandName(ctx context.Context) string { + val, err := i.readCommandName(ctx) + if err != nil { + i.handle(ctx, err) + } + + return val +} + +// readFormat format. +func (i RConfigureConfig) readFormat(ctx context.Context) (v string, e error) { + val, err := i.Value(ctx, "format") + if err != nil { + i.handle(ctx, err) + + return "arg", nil + } + + return val.ParseString() + +} + +// ReadFormat format. +func (i RConfigureConfig) ReadFormat(ctx context.Context) (string, error) { + return i.readFormat(ctx) +} + +// Format format. +func (i RConfigureConfig) Format(ctx context.Context) string { + val, err := i.readFormat(ctx) + if err != nil { + i.handle(ctx, err) + } + + return val +} diff --git a/command/help/command.go b/command/help/command.go index 31b8c94..0f192e0 100644 --- a/command/help/command.go +++ b/command/help/command.go @@ -2,6 +2,7 @@ package help import ( "context" + "errors" "fmt" "os" "strings" @@ -9,15 +10,16 @@ import ( "gitoa.ru/go-4devs/config" "gitoa.ru/go-4devs/config/definition" "gitoa.ru/go-4devs/config/definition/option" - cparam "gitoa.ru/go-4devs/config/param" + "gitoa.ru/go-4devs/config/param" "gitoa.ru/go-4devs/config/provider/arg" "gitoa.ru/go-4devs/config/validator" "gitoa.ru/go-4devs/config/value" "gitoa.ru/go-4devs/console/command" + "gitoa.ru/go-4devs/console/errs" "gitoa.ru/go-4devs/console/internal/registry" "gitoa.ru/go-4devs/console/output" "gitoa.ru/go-4devs/console/output/descriptor" - "gitoa.ru/go-4devs/console/param" + "gitoa.ru/go-4devs/console/setting" ) //nolint:gochecknoinits @@ -91,17 +93,31 @@ func Execute(ctx context.Context, in config.Provider, out output.Output) error { bin = os.Args[0] } - help, err := param.Help(cmd, param.HelpData(bin, cmd.Name())) + help, err := setting.Help(cmd, setting.HelpData(bin, cmd.Name())) if err != nil { return fmt.Errorf("create help:%w", err) } + hasUsage := true + + usage, err := setting.Usage(cmd, setting.UsageData(cmd.Name(), def)) + if err != nil { + if !errors.Is(err, errs.ErrNotFound) { + return fmt.Errorf("create usage:%w", err) + } + + hasUsage = false + } + derr := des.Command(ctx, out, descriptor.Command{ Bin: bin, Name: cmd.Name(), - Description: param.Description(cmd), + Description: setting.Description(cmd), Help: help, - Options: def.With(cparam.New(descriptor.TxtStyle())), + Usage: func() (string, bool) { + return usage, hasUsage + }, + Options: def.With(param.New(descriptor.TxtStyle())), }) if derr != nil { return fmt.Errorf("descriptor help:%w", derr) @@ -118,7 +134,7 @@ You can also output the help in other formats by using the --formatlist command. ` -func Help(data param.HData) (string, error) { +func Help(data setting.HData) (string, error) { return fmt.Sprintf(tpl, data.Bin, data.Name), nil } diff --git a/command/list/command.go b/command/list/command.go index c1dce90..6ae3b0d 100644 --- a/command/list/command.go +++ b/command/list/command.go @@ -8,16 +8,16 @@ import ( "gitoa.ru/go-4devs/config" "gitoa.ru/go-4devs/config/definition" "gitoa.ru/go-4devs/config/definition/option" - cparam "gitoa.ru/go-4devs/config/param" + "gitoa.ru/go-4devs/config/param" "gitoa.ru/go-4devs/config/provider/arg" "gitoa.ru/go-4devs/config/validator" "gitoa.ru/go-4devs/config/value" "gitoa.ru/go-4devs/console/command" - cerr "gitoa.ru/go-4devs/console/errors" + "gitoa.ru/go-4devs/console/errs" "gitoa.ru/go-4devs/console/internal/registry" "gitoa.ru/go-4devs/console/output" "gitoa.ru/go-4devs/console/output/descriptor" - "gitoa.ru/go-4devs/console/param" + "gitoa.ru/go-4devs/console/setting" ) //nolint:gochecknoinits @@ -80,7 +80,7 @@ func Execite(ctx context.Context, in config.Provider, out output.Output) error { cmds := registry.Commands() commands := descriptor.Commands{ Namespace: ns, - Options: def.With(cparam.New(descriptor.TxtStyle())), + Options: def.With(param.New(descriptor.TxtStyle())), } groups := make(map[string]*descriptor.NSCommand) namespaces := make([]string, 0, len(cmds)) @@ -92,13 +92,13 @@ func Execite(ctx context.Context, in config.Provider, out output.Output) error { } cmd, _ := registry.Find(name) - if param.IsHidden(cmd) { + if setting.IsHidden(cmd) { continue } gn := strings.SplitN(name, ":", defaultLenNamespace) if len(gn) != defaultLenNamespace { - empty.Append(cmd.Name(), param.Description(cmd)) + empty.Append(cmd.Name(), setting.Description(cmd)) continue } @@ -111,7 +111,7 @@ func Execite(ctx context.Context, in config.Provider, out output.Output) error { namespaces = append(namespaces, gn[0]) } - groups[gn[0]].Append(name, param.Description(cmd)) + groups[gn[0]].Append(name, setting.Description(cmd)) } if len(empty.Commands) > 0 { @@ -123,7 +123,7 @@ func Execite(ctx context.Context, in config.Provider, out output.Output) error { } if ns != "" && len(commands.Commands) == 0 { - return fmt.Errorf("%w: namespace %s", cerr.ErrNotFound, ns) + return fmt.Errorf("%w: namespace %s", errs.ErrNotFound, ns) } if err := des.Commands(ctx, out, commands); err != nil { diff --git a/command/list/help.go b/command/list/help.go index 816ddbd..5c5393f 100644 --- a/command/list/help.go +++ b/command/list/help.go @@ -3,7 +3,7 @@ package list import ( "fmt" - "gitoa.ru/go-4devs/console/param" + "gitoa.ru/go-4devs/console/setting" ) const tpl = ` @@ -15,6 +15,6 @@ You can also output the information in other formats by using the --for %[1]s %[2]s --format=xml ` -func Help(data param.HData) (string, error) { +func Help(data setting.HData) (string, error) { return fmt.Sprintf(tpl, data.Bin, data.Name), nil } diff --git a/command_test.go b/command_test.go index ead79bd..89ce5ea 100644 --- a/command_test.go +++ b/command_test.go @@ -17,7 +17,7 @@ import ( "gitoa.ru/go-4devs/config/value" "gitoa.ru/go-4devs/console" "gitoa.ru/go-4devs/console/command" - cerr "gitoa.ru/go-4devs/console/errors" + "gitoa.ru/go-4devs/console/errs" "gitoa.ru/go-4devs/console/output" ) @@ -82,7 +82,7 @@ func TestRunEmptyExecute(t *testing.T) { out := output.Stdout() err := empty.Run(ctx, in, out) - if !errors.Is(err, cerr.ErrExecuteNil) { - t.Fatalf("expected: %v, got: %v ", cerr.ErrExecuteNil, err) + if !errors.Is(err, errs.ErrExecuteNil) { + t.Fatalf("expected: %v, got: %v ", errs.ErrExecuteNil, err) } } diff --git a/console.go b/console.go index 5892142..b4b6df8 100644 --- a/console.go +++ b/console.go @@ -4,7 +4,6 @@ import ( "context" "errors" "fmt" - "log" "gitoa.ru/go-4devs/config" "gitoa.ru/go-4devs/config/definition" @@ -13,16 +12,16 @@ import ( "gitoa.ru/go-4devs/config/value" "gitoa.ru/go-4devs/console/command" "gitoa.ru/go-4devs/console/command/help" - cerr "gitoa.ru/go-4devs/console/errors" + "gitoa.ru/go-4devs/console/errs" "gitoa.ru/go-4devs/console/internal/registry" "gitoa.ru/go-4devs/console/output" - "gitoa.ru/go-4devs/console/param" + "gitoa.ru/go-4devs/console/setting" ) // Execute the current command with option. func Execute(ctx context.Context, cmd command.Command, opts ...func(*App)) { opts = append([]func(*App){WithSkipArgs(1)}, opts...) - New(opts...).exec(ctx, cmd) + New(opts...).exec(ctx, command.With(cmd, command.EmptyUsage)) } // Run current command by input and output. @@ -38,7 +37,7 @@ func Run(ctx context.Context, cmd command.Command, in config.BindProvider, out o berr := in.Bind(ctx, config.NewVars(def.Options()...)) if berr != nil { - log.Print(berr) + printErr(ctx, in, out, berr) return showHelp(ctx, cmd, in, output.Ansi(out)) } @@ -46,7 +45,7 @@ func Run(ctx context.Context, cmd command.Command, in config.BindProvider, out o out = command.Verbose(ctx, in, out) if command.IsShowVersion(ctx, in) { - out.Println(ctx, "command ", cmd.Name(), " version: ", param.Version(cmd), "") + out.Println(ctx, "command ", cmd.Name(), " version: ", setting.Version(cmd), "") return nil } @@ -67,7 +66,7 @@ func showHelp(ctx context.Context, cmd command.Command, in config.Provider, out arr.SetOption(value.New(cmd.Name()), help.ArgumentCommandName) arr.SetOption(value.New(false), command.OptionHelp) - if _, err := registry.Find(cmd.Name()); errors.Is(err, cerr.ErrNotFound) { + if _, err := registry.Find(cmd.Name()); errors.Is(err, errs.ErrNotFound) { _ = registry.Add(cmd) } diff --git a/errors/errors.go b/errs/errors.go similarity index 95% rename from errors/errors.go rename to errs/errors.go index 13a3132..4b22548 100644 --- a/errors/errors.go +++ b/errs/errors.go @@ -1,4 +1,4 @@ -package errors //nolint:revive +package errs import ( "errors" diff --git a/go.mod b/go.mod index 4108a0b..e7b1e52 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module gitoa.ru/go-4devs/console go 1.24.0 -require gitoa.ru/go-4devs/config v0.0.8 +require gitoa.ru/go-4devs/config v0.0.10 require ( golang.org/x/mod v0.31.0 // indirect @@ -10,4 +10,7 @@ require ( golang.org/x/tools v0.40.0 // indirect ) -tool golang.org/x/tools/cmd/stringer +tool ( + gitoa.ru/go-4devs/config/cmd/config + golang.org/x/tools/cmd/stringer +) diff --git a/go.sum b/go.sum index 28f9a61..0ccf0bb 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,9 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -gitoa.ru/go-4devs/config v0.0.8 h1:o4p8I9jWJMfiFVVKr50IqCGj1fF+8kmSPDkH0deRvn4= -gitoa.ru/go-4devs/config v0.0.8/go.mod h1:jHKqVafFVW400LC0M4i1ifPapiI9sqpX/QTh+VMadKw= +gitoa.ru/go-4devs/config v0.0.9 h1:Z43kM6k6ocC2YIRQkELq5zWO9LO8fl1l14RyqjLC4I4= +gitoa.ru/go-4devs/config v0.0.9/go.mod h1:cLW1+4E4uM4Pw+z4RuKEKbO1Lz6UTs2b2fTPyeEgTx8= +gitoa.ru/go-4devs/config v0.0.10 h1:NSagD0voj77/IGqRGsbR0DZmDvFcxbx+oRoWQnLnSy4= +gitoa.ru/go-4devs/config v0.0.10/go.mod h1:cLW1+4E4uM4Pw+z4RuKEKbO1Lz6UTs2b2fTPyeEgTx8= golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= diff --git a/output/descriptor/descriptor.go b/output/descriptor/descriptor.go index 405afb1..2bc5f05 100644 --- a/output/descriptor/descriptor.go +++ b/output/descriptor/descriptor.go @@ -25,6 +25,7 @@ type Command struct { Bin string Name string Description string + Usage func() (string, bool) Help string } diff --git a/output/descriptor/txt.go b/output/descriptor/txt.go index acde1ac..2fef9f5 100644 --- a/output/descriptor/txt.go +++ b/output/descriptor/txt.go @@ -12,6 +12,7 @@ import ( "gitoa.ru/go-4devs/config/param" "gitoa.ru/go-4devs/config/provider/arg" "gitoa.ru/go-4devs/console/output" + "gitoa.ru/go-4devs/console/setting" ) const ( @@ -22,9 +23,9 @@ const ( //nolint:gochecknoglobals var ( txtFunc = template.FuncMap{ - "synopsis": txtSynopsis, "definition": txtDefinition, "help": txtHelp, + "usage": txtUsage, "commands": txtCommands, } @@ -34,11 +35,9 @@ var ( {{- if .Description -}} Description: {{ .Description }} - {{ end -}} -Usage: - {{ .Name }} {{ synopsis .Options }} -{{ definition .Options }} +{{- usage . }} +{{- definition .Options }} {{- help . }} `)) @@ -128,6 +127,23 @@ func txtCommands(cmds []NSCommand) string { return buf.String() } +func txtUsage(cmd Command) string { + if cmd.Usage == nil { + return "" + } + + data, has := cmd.Usage() + if has && data == "" { + return "" + } + + if data == "" { + data = defaultUsage(setting.UsageData(cmd.Name, cmd.Options)) + } + + return "\nUsage:\n " + data + "\n" +} + func txtHelp(cmd Command) string { if cmd.Help == "" { return "" @@ -152,10 +168,12 @@ func txtDefinition(options config.Options) string { return buf.String() } -func txtSynopsis(options config.Options) string { - def := arg.NewViews(options, nil) +func defaultUsage(data setting.UData) string { + def := arg.NewViews(data.Options, nil) var buf bytes.Buffer + buf.WriteString(data.Name) + buf.WriteString(" ") if len(def.Options()) > 0 { buf.WriteString("[options] ") diff --git a/param/keys.go b/param/keys.go deleted file mode 100644 index 231a848..0000000 --- a/param/keys.go +++ /dev/null @@ -1,90 +0,0 @@ -package param - -import ( - "fmt" - - cerr "gitoa.ru/go-4devs/console/errors" -) - -type key uint8 - -const ( - paramHidden key = iota + 1 - paramDescription - paramVerssion - paramHelp -) - -const ( - defaultVersion = "undefined" -) - -func IsHidden(in Params) bool { - data, ok := Bool(in, paramHidden) - - return ok && data -} - -func Hidden(in Params) Params { - return in.With(paramHidden, true) -} - -func Description(in Params) string { - data, _ := String(in, paramDescription) - - return data -} - -func WithDescription(desc string) Option { - return func(p Params) Params { - return p.With(paramDescription, desc) - } -} - -func Version(in Params) string { - if data, ok := String(in, paramVerssion); ok { - return data - } - - return defaultVersion -} - -func WithVersion(in string) Option { - return func(p Params) Params { - return p.With(paramVerssion, in) - } -} - -func HelpData(bin, name string) HData { - return HData{ - Bin: bin, - Name: name, - } -} - -type HData struct { - Bin string - Name string -} - -type HelpFn func(data HData) (string, error) - -func WithHelp(fn HelpFn) Option { - return func(p Params) Params { - return p.With(paramHelp, fn) - } -} - -func Help(in Params, data HData) (string, error) { - fn, ok := in.Param(paramHelp) - if !ok { - return "", nil - } - - hfn, fok := fn.(HelpFn) - if !fok { - return "", fmt.Errorf("%w: expect:%T, got:%T", cerr.ErrWrongType, (HelpFn)(nil), fn) - } - - return hfn(data) -} diff --git a/param/helper.go b/setting/helper.go similarity index 65% rename from param/helper.go rename to setting/helper.go index d9ef017..66c0a1e 100644 --- a/param/helper.go +++ b/setting/helper.go @@ -1,6 +1,6 @@ -package param +package setting -func Bool(in Params, key any) (bool, bool) { +func Bool(in Setting, key any) (bool, bool) { data, ok := in.Param(key) if !ok { return false, false @@ -11,7 +11,7 @@ func Bool(in Params, key any) (bool, bool) { return res, ok } -func String(in Params, key any) (string, bool) { +func String(in Setting, key any) (string, bool) { data, ok := in.Param(key) if !ok { return "", false diff --git a/setting/keys.go b/setting/keys.go new file mode 100644 index 0000000..21aa9be --- /dev/null +++ b/setting/keys.go @@ -0,0 +1,127 @@ +package setting + +import ( + "fmt" + + "gitoa.ru/go-4devs/config" + "gitoa.ru/go-4devs/console/errs" +) + +type key uint8 + +const ( + paramHidden key = iota + 1 + paramDescription + paramVerssion + paramHelp + paramUsage +) + +const ( + defaultVersion = "undefined" +) + +func IsHidden(in Setting) bool { + data, ok := Bool(in, paramHidden) + + return ok && data +} + +func Hidden(in Setting) Setting { + return in.With(paramHidden, true) +} + +func Description(in Setting) string { + data, _ := String(in, paramDescription) + + return data +} + +func WithDescription(desc string) Option { + return func(p Setting) Setting { + return p.With(paramDescription, desc) + } +} + +func Version(in Setting) string { + if data, ok := String(in, paramVerssion); ok { + return data + } + + return defaultVersion +} + +func WithVersion(in string) Option { + return func(p Setting) Setting { + return p.With(paramVerssion, in) + } +} + +func HelpData(bin, name string) HData { + return HData{ + Bin: bin, + Name: name, + } +} + +type HData struct { + Bin string + Name string +} + +type HelpFn func(data HData) (string, error) + +func WithHelp(fn HelpFn) Option { + return func(p Setting) Setting { + return p.With(paramHelp, fn) + } +} + +func Help(in Setting, data HData) (string, error) { + fn, ok := in.Param(paramHelp) + if !ok { + return "", nil + } + + hfn, fok := fn.(HelpFn) + if !fok { + return "", fmt.Errorf("%w: expect:func(data HData) (string, error), got:%T", errs.ErrWrongType, fn) + } + + return hfn(data) +} + +func UsageData(name string, opts config.Options) UData { + return UData{ + Options: opts, + Name: name, + } +} + +type UData struct { + config.Options + + Name string +} + +type UsageFn func(data UData) (string, error) + +func WithUsage(fn UsageFn) Option { + return func(p Setting) Setting { + return p.With(paramUsage, fn) + } +} + +func Usage(in Setting, data UData) (string, error) { + fn, ok := in.Param(paramUsage) + if !ok { + return "", fmt.Errorf("%w", errs.ErrNotFound) + } + + ufn, ok := fn.(UsageFn) + if !ok { + return "", fmt.Errorf("%w: expect: func(data Udata) (string, error), got:%T", errs.ErrWrongType, fn) + } + + return ufn(data) +} diff --git a/param/params.go b/setting/setting.go similarity index 66% rename from param/params.go rename to setting/setting.go index 8038bc5..c2e33d5 100644 --- a/param/params.go +++ b/setting/setting.go @@ -1,10 +1,10 @@ -package param +package setting //nolint:gochecknoglobals var eparam = empty{} -func New(opts ...Option) Params { - var param Params +func New(opts ...Option) Setting { + var param Setting param = eparam for _, opt := range opts { @@ -14,12 +14,12 @@ func New(opts ...Option) Params { return param } -type Params interface { +type Setting interface { Param(key any) (any, bool) - With(key, val any) Params + With(key, val any) Setting } -type Option func(Params) Params +type Option func(Setting) Setting type empty struct{} @@ -27,7 +27,7 @@ func (e empty) Param(any) (any, bool) { return nil, false } -func (e empty) With(key, val any) Params { +func (e empty) With(key, val any) Setting { return data{ parent: e, key: key, @@ -36,7 +36,7 @@ func (e empty) With(key, val any) Params { } type data struct { - parent Params + parent Setting key, val any } @@ -48,7 +48,7 @@ func (d data) Param(key any) (any, bool) { return d.parent.Param(key) } -func (d data) With(key, val any) Params { +func (d data) With(key, val any) Setting { return data{ parent: d, key: key,