6 Commits

Author SHA1 Message Date
ad5cf18535 Merge pull request 'check empty execute' (#6) from execute into master
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
Reviewed-on: #6
2022-09-24 12:20:33 +03:00
andrey1s
1151e7c3ad check empty execute
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-09-24 12:16:23 +03:00
44d8837dbc Merge pull request 'add example hidden option' (#5) from example into master
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
Reviewed-on: #5
2022-09-18 23:14:22 +03:00
andrey1s
0b6a6ee99b add example hidden option
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-09-18 23:11:24 +03:00
7771ff495d Merge pull request 'add hidden option' (#4) from hidden into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #4
2022-09-18 22:36:09 +03:00
andrey1s
662cbdb510 add hidden option
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-09-18 22:34:16 +03:00
13 changed files with 114 additions and 55 deletions

2
app.go
View File

@@ -111,7 +111,7 @@ func (a *App) list(ctx context.Context) error {
}
arr := &input.Array{}
arr.SetArgument("command_name", value.New(CommandList))
arr.SetArgument(ArgumentCommandName, value.New(CommandList))
in := input.Chain(arr, a.in)
return Run(ctx, cmd, in, a.out)

View File

@@ -100,6 +100,10 @@ func (c *Command) With(opts ...Option) *Command {
// Run run command with input and output.
func (c *Command) Run(ctx context.Context, in input.Input, out output.Output) error {
if c.Execute == nil {
return fmt.Errorf("%w", ErrExecuteNil)
}
if c.Handle != nil {
return c.Handle(ctx, in, out, c.Execute)
}

View File

@@ -2,6 +2,7 @@ package console_test
import (
"context"
"errors"
"strings"
"sync/atomic"
"testing"
@@ -43,6 +44,7 @@ func Command() *console.Command {
option.String("string", "array string", option.Array),
option.Bool("bool", "test bool option"),
option.Duration("duration", "test duration with default", option.Default(time.Second)),
option.Time("hidden", "hidden time", option.Default(time.Second), option.Hidden),
)
return nil
@@ -124,3 +126,21 @@ func TestChainHandle(t *testing.T) {
}
}
}
func TestRunEmptyExecute(t *testing.T) {
t.Parallel()
ctx := context.Background()
empty := console.Command{
Name: "empty",
}
in := &input.Array{
Map: input.Map{},
}
out := output.Stdout()
err := empty.Run(ctx, in, out)
if !errors.Is(err, console.ErrExecuteNil) {
t.Fatalf("expected: %v, got: %v ", console.ErrExecuteNil, err)
}
}

View File

@@ -18,6 +18,15 @@ const (
verboseInfo = 1
)
const (
OptionHelp = "help"
OptionVersion = "version"
OptionAnsi = "ansi"
OptionNoAnsi = "no-ansi"
OptionQuiet = "quiet"
OptionVerbose = "verbose"
)
// Execute the current command with option.
func Execute(ctx context.Context, cmd *Command, opts ...func(*App)) {
opts = append([]func(*App){WithSkipArgs(1)}, opts...)
@@ -42,7 +51,7 @@ func Run(ctx context.Context, cmd *Command, in input.Input, out output.Output) e
out = verbose(ctx, in, out)
if in.Option(ctx, "version").Bool() {
if in.Option(ctx, OptionVersion).Bool() {
version := cmd.Version
if version == "" {
version = "unknown"
@@ -53,7 +62,7 @@ func Run(ctx context.Context, cmd *Command, in input.Input, out output.Output) e
return nil
}
if in.Option(ctx, "help").Bool() {
if in.Option(ctx, OptionHelp).Bool() {
return showHelp(ctx, cmd, in, out)
}
@@ -62,9 +71,9 @@ func Run(ctx context.Context, cmd *Command, in input.Input, out output.Output) e
func ansi(ctx context.Context, in input.Input, out output.Output) output.Output {
switch {
case in.Option(ctx, "ansi").Bool():
case in.Option(ctx, OptionAnsi).Bool():
out = output.Ansi(out)
case in.Option(ctx, "no-ansi").Bool():
case in.Option(ctx, OptionNoAnsi).Bool():
out = output.None(out)
case lookupEnv("NO_COLOR"):
out = output.None(out)
@@ -83,10 +92,10 @@ func lookupEnv(name string) bool {
func verbose(ctx context.Context, in input.Input, out output.Output) output.Output {
switch {
case in.Option(ctx, "quiet").Bool():
case in.Option(ctx, OptionQuiet).Bool():
out = output.Quiet()
default:
verb := in.Option(ctx, "verbose").Bools()
verb := in.Option(ctx, OptionVerbose).Bools()
switch {
case len(verb) == verboseInfo:
@@ -105,8 +114,8 @@ func verbose(ctx context.Context, in input.Input, out output.Output) output.Outp
func showHelp(ctx context.Context, cmd *Command, in input.Input, out output.Output) error {
arr := &input.Array{}
arr.SetArgument(HelpArgumentCommandName, value.New(cmd.Name))
arr.SetOption("help", value.New(false))
arr.SetArgument(ArgumentCommandName, value.New(cmd.Name))
arr.SetOption(OptionHelp, value.New(false))
if _, err := Find(cmd.Name); errors.Is(err, ErrNotFound) {
register(cmd)
@@ -125,13 +134,13 @@ func showHelp(ctx context.Context, cmd *Command, in input.Input, out output.Outp
// Default options and argument command.
func Default(d *input.Definition) *input.Definition {
return d.SetOptions(
option.Bool("no-ansi", "Disable ANSI output"),
option.Bool("ansi", "Do not ask any interactive question"),
option.Bool("version", "Display this application version", option.Short('V')),
option.Bool("help", "Display this help message", option.Short('h')),
option.Bool("verbose",
option.Bool(OptionNoAnsi, "Disable ANSI output"),
option.Bool(OptionAnsi, "Do not ask any interactive question"),
option.Bool(OptionVersion, "Display this application version", option.Short('V')),
option.Bool(OptionHelp, "Display this help message", option.Short('h')),
option.Bool(OptionVerbose,
"Increase the verbosity of messages: -v for info output, -vv for debug and -vvv for trace",
option.Short('v'), option.Array),
option.Bool("quiet", "Do not output any message", option.Short('q')),
option.Bool(OptionQuiet, "Do not output any message", option.Short('q')),
)
}

31
error.go Normal file
View File

@@ -0,0 +1,31 @@
package console
import (
"errors"
"fmt"
"strings"
)
var (
ErrNotFound = errors.New("command not found")
ErrCommandNil = errors.New("console: Register command is nil")
ErrExecuteNil = errors.New("console: execute is nil")
ErrCommandDuplicate = errors.New("console: duplicate command")
)
type AlternativesError struct {
Alt []string
Err error
}
func (e AlternativesError) Error() string {
return fmt.Sprintf("%s, alternatives: [%s]", e.Err, strings.Join(e.Alt, ","))
}
func (e AlternativesError) Is(err error) bool {
return errors.Is(e.Err, err)
}
func (e AlternativesError) Unwrap() error {
return e.Err
}

View File

@@ -16,7 +16,8 @@ const (
AppName = "console"
)
// FDEVS_CONSOLE_CAT=env go run cmd/config/main.go fdevs:console:arg -b tmp.
// FDEVS_CONSOLE_CAT=env FDEVS_CONSOLE_HIDDEN=2022-09-18T23:07:49+03:00 go run cmd/config/main.go fdevs:console:arg -b tmp.
// FDEVS_CONSOLE_CAT=env go run cmd/config/main.go fdevs:console:arg --hidden=2022-09-18T23:07:49+03:00 -b tmp.
func main() {
env := config.New(Namespace, AppName, []config.Provider{
env.New(),

View File

@@ -20,6 +20,7 @@ func Args() *console.Command {
option.String("bar", "required bar option", option.Required, option.Short('b')),
option.String("cat", "cat option", option.Short('c')),
option.Time("time", "time example"),
option.Time("hidden", "hidden time example", option.Hidden),
)
return nil
@@ -29,6 +30,7 @@ func Args() *console.Command {
out.Println(ctx, "bar: <info>", in.Option(ctx, "bar").String(), "</info>")
out.Println(ctx, "cat: <info>", in.Option(ctx, "cat").String(), "</info>")
out.Println(ctx, "time: <info>", in.Option(ctx, "time").Time().Format(time.RFC3339), "</info>")
out.Println(ctx, "hidden: <info>", in.Option(ctx, "hidden").Time().Format(time.RFC3339), "</info>")
return nil
},

12
help.go
View File

@@ -22,8 +22,8 @@ func init() {
}
const (
HelpArgumentCommandName = "command_name"
helpOptFormat = "format"
ArgumentCommandName = "command_name"
OptionFormat = "format"
)
func help() *Command {
@@ -39,8 +39,8 @@ To display the list of available commands, please use the <info>list</info> comm
`,
Execute: func(ctx context.Context, in input.Input, out output.Output) error {
var err error
name := in.Argument(ctx, HelpArgumentCommandName).String()
format := in.Option(ctx, helpOptFormat).String()
name := in.Argument(ctx, ArgumentCommandName).String()
format := in.Option(ctx, OptionFormat).String()
des, err := descriptor.Find(format)
if err != nil {
@@ -81,10 +81,10 @@ To display the list of available commands, please use the <info>list</info> comm
formats := descriptor.Descriptors()
config.
SetArguments(
argument.String(HelpArgumentCommandName, "The command name", argument.Default(value.New("help"))),
argument.String(ArgumentCommandName, "The command name", argument.Default(value.New("help"))),
).
SetOptions(
option.String(helpOptFormat, fmt.Sprintf("The output format (%s)", strings.Join(formats, ", ")),
option.String(OptionFormat, fmt.Sprintf("The output format (%s)", strings.Join(formats, ", ")),
option.Required,
option.Default(formats[0]),
option.Valid(

View File

@@ -15,6 +15,10 @@ func Default(in interface{}) variable.Option {
return variable.Default(value.New(in))
}
func Hidden(in *variable.Variable) {
variable.Hidden(in)
}
func Required(v *variable.Variable) {
variable.Required(v)
}

View File

@@ -40,6 +40,10 @@ func Required(v *Variable) {
v.Flag |= flag.Required
}
func Hidden(v *Variable) {
v.hidden = true
}
func WithParse(create Create, update Append) Option {
return func(v *Variable) {
v.append = func(Param) Append { return update }
@@ -99,6 +103,7 @@ type Variable struct {
Flag flag.Flag
Type ArgType
Default value.Value
hidden bool
Valid []func(value.Value) error
params Params
create func(Param) Create
@@ -115,6 +120,10 @@ func (v Variable) Validate(in value.Value) error {
return nil
}
func (v Variable) IsHidden() bool {
return v.hidden
}
func (v Variable) IsArray() bool {
return v.Flag.IsArray()
}

12
list.go
View File

@@ -20,6 +20,10 @@ func init() {
MustRegister(list())
}
const (
ArgumentNamespace = "namespace"
)
func list() *Command {
return &Command{
Name: CommandList,
@@ -37,10 +41,10 @@ You can also output the information in other formats by using the <comment>--for
formats := descriptor.Descriptors()
config.
SetArguments(
argument.String("namespace", "The namespace name"),
argument.String(ArgumentNamespace, "The namespace name"),
).
SetOptions(
option.String(helpOptFormat, fmt.Sprintf("The output format (%s)", strings.Join(formats, ", ")),
option.String(OptionFormat, fmt.Sprintf("The output format (%s)", strings.Join(formats, ", ")),
option.Required,
option.Default(formats[0]),
option.Valid(
@@ -57,8 +61,8 @@ You can also output the information in other formats by using the <comment>--for
//nolint:cyclop
func executeList(ctx context.Context, in input.Input, out output.Output) error {
ns := in.Argument(ctx, "namespace").String()
format := in.Option(ctx, helpOptFormat).String()
ns := in.Argument(ctx, ArgumentNamespace).String()
format := in.Option(ctx, OptionFormat).String()
des, err := descriptor.Find(format)
if err != nil {

View File

@@ -209,6 +209,9 @@ func txtDefinitionOption(maxLen int, def *input.Definition) string {
for _, name := range opts {
opt, _ := def.Option(name)
if opt.IsHidden() {
continue
}
var op bytes.Buffer

View File

@@ -5,7 +5,6 @@ import (
"fmt"
"regexp"
"sort"
"strings"
"sync"
)
@@ -14,12 +13,6 @@ const (
CommandList = "list"
)
var (
ErrNotFound = errors.New("command not found")
ErrCommandNil = errors.New("console: Register command is nil")
ErrCommandDuplicate = errors.New("console: duplicate command")
)
//nolint:gochecknoglobals
var (
commandsMu sync.RWMutex
@@ -27,27 +20,6 @@ var (
findCommand = regexp.MustCompile("([^:]+|)")
)
type AlternativesError struct {
alt []string
err error
}
func (e AlternativesError) Error() string {
return fmt.Sprintf("%s, alternatives: [%s]", e.err, strings.Join(e.alt, ","))
}
func (e AlternativesError) Is(err error) bool {
return errors.Is(e.err, err)
}
func (e AlternativesError) Unwrap() error {
return e.err
}
func (e AlternativesError) Alternatives() []string {
return e.alt
}
// MustRegister register command or panic if err.
func MustRegister(cmd *Command) {
if err := Register(cmd); err != nil {
@@ -134,7 +106,7 @@ func Find(name string) (*Command, error) {
names[i] = findCommands[i].Name
}
return nil, AlternativesError{alt: names, err: ErrNotFound}
return nil, AlternativesError{Alt: names, Err: ErrNotFound}
}
return nil, ErrNotFound