andrey1s
4 years ago
41 changed files with 659 additions and 612 deletions
@ -0,0 +1,153 @@ |
|||||
|
package input |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"fmt" |
||||
|
"strings" |
||||
|
|
||||
|
"gitoa.ru/go-4devs/console/input/errs" |
||||
|
"gitoa.ru/go-4devs/console/input/option" |
||||
|
"gitoa.ru/go-4devs/console/input/value" |
||||
|
) |
||||
|
|
||||
|
const doubleDash = `--` |
||||
|
|
||||
|
type Argv struct { |
||||
|
Array |
||||
|
Args []string |
||||
|
ErrHandle func(error) error |
||||
|
} |
||||
|
|
||||
|
func (i *Argv) Bind(ctx context.Context, def *Definition) error { |
||||
|
options := true |
||||
|
|
||||
|
for len(i.Args) > 0 { |
||||
|
var err error |
||||
|
|
||||
|
arg := i.Args[0] |
||||
|
i.Args = i.Args[1:] |
||||
|
|
||||
|
switch { |
||||
|
case options && arg == doubleDash: |
||||
|
options = false |
||||
|
case options && len(arg) > 2 && arg[0:2] == doubleDash: |
||||
|
err = i.parseLongOption(arg[2:], def) |
||||
|
case options && arg[0:1] == "-": |
||||
|
if len(arg) == 1 { |
||||
|
return fmt.Errorf("%w: option name required given '-'", errs.ErrInvalidName) |
||||
|
} |
||||
|
|
||||
|
err = i.parseShortOption(arg[1:], def) |
||||
|
default: |
||||
|
err = i.parseArgument(arg, def) |
||||
|
} |
||||
|
|
||||
|
if err != nil && i.ErrHandle != nil { |
||||
|
if herr := i.ErrHandle(err); herr != nil { |
||||
|
return herr |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return i.Array.Bind(ctx, def) |
||||
|
} |
||||
|
|
||||
|
func (i *Argv) parseLongOption(arg string, def *Definition) error { |
||||
|
var value *string |
||||
|
|
||||
|
name := arg |
||||
|
|
||||
|
if strings.Contains(arg, "=") { |
||||
|
vals := strings.SplitN(arg, "=", 2) |
||||
|
name = vals[0] |
||||
|
value = &vals[1] |
||||
|
} |
||||
|
|
||||
|
opt, err := def.Option(name) |
||||
|
if err != nil { |
||||
|
return errs.Option(name, err) |
||||
|
} |
||||
|
|
||||
|
return i.appendOption(name, value, opt) |
||||
|
} |
||||
|
|
||||
|
func (i *Argv) appendOption(name string, data *string, opt option.Option) error { |
||||
|
v, ok := i.GetOption(name) |
||||
|
|
||||
|
if ok && !opt.IsArray() { |
||||
|
return fmt.Errorf("%w: got: array, expect: %s", errs.ErrUnexpectedType, opt.Flag.Type()) |
||||
|
} |
||||
|
|
||||
|
var val string |
||||
|
|
||||
|
switch { |
||||
|
case data != nil: |
||||
|
val = *data |
||||
|
case opt.IsBool(): |
||||
|
val = "true" |
||||
|
case len(i.Args) > 0 && len(i.Args[0]) > 0 && i.Args[0][0:1] != "-": |
||||
|
val = i.Args[0] |
||||
|
i.Args = i.Args[1:] |
||||
|
default: |
||||
|
return errs.Option(name, errs.ErrRequired) |
||||
|
} |
||||
|
|
||||
|
if !ok { |
||||
|
v = value.ByFlag(opt.Flag) |
||||
|
i.SetOption(name, v) |
||||
|
} |
||||
|
|
||||
|
if err := v.Append(val); err != nil { |
||||
|
return errs.Option(name, err) |
||||
|
} |
||||
|
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (i *Argv) parseShortOption(arg string, def *Definition) error { |
||||
|
name := arg |
||||
|
|
||||
|
var value string |
||||
|
|
||||
|
if len(name) > 1 { |
||||
|
name, value = arg[0:1], arg[1:] |
||||
|
} |
||||
|
|
||||
|
opt, err := def.ShortOption(name) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
if opt.IsBool() && value != "" { |
||||
|
if err := i.parseShortOption(value, def); err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
value = "" |
||||
|
} |
||||
|
|
||||
|
if value == "" { |
||||
|
return i.appendOption(opt.Name, nil, opt) |
||||
|
} |
||||
|
|
||||
|
return i.appendOption(opt.Name, &value, opt) |
||||
|
} |
||||
|
|
||||
|
func (i *Argv) parseArgument(arg string, def *Definition) error { |
||||
|
opt, err := def.Argument(i.LenArguments()) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
v, ok := i.GetArgument(opt.Name) |
||||
|
if !ok { |
||||
|
v = value.ByFlag(opt.Flag) |
||||
|
i.SetArgument(opt.Name, v) |
||||
|
} |
||||
|
|
||||
|
if err := v.Append(arg); err != nil { |
||||
|
return errs.Argument(opt.Name, err) |
||||
|
} |
||||
|
|
||||
|
return nil |
||||
|
} |
@ -1,212 +0,0 @@ |
|||||
package argv |
|
||||
|
|
||||
import ( |
|
||||
"context" |
|
||||
"fmt" |
|
||||
"strings" |
|
||||
"sync" |
|
||||
|
|
||||
"gitoa.ru/go-4devs/console/input" |
|
||||
"gitoa.ru/go-4devs/console/input/option" |
|
||||
"gitoa.ru/go-4devs/console/input/value" |
|
||||
"gitoa.ru/go-4devs/console/input/wrap" |
|
||||
) |
|
||||
|
|
||||
const doubleDash = `--` |
|
||||
|
|
||||
var _ input.ReadInput = (*Input)(nil) |
|
||||
|
|
||||
func WithErrorHandle(h func(error) error) func(*Input) { |
|
||||
return func(i *Input) { |
|
||||
i.errorHandle = h |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
func New(args []string, opts ...func(*Input)) *wrap.Input { |
|
||||
i := &Input{ |
|
||||
args: args, |
|
||||
arguments: make(map[string]value.AppendValue), |
|
||||
options: make(map[string]value.AppendValue), |
|
||||
errorHandle: func(err error) error { |
|
||||
return err |
|
||||
}, |
|
||||
} |
|
||||
|
|
||||
for _, opt := range opts { |
|
||||
opt(i) |
|
||||
} |
|
||||
|
|
||||
return &wrap.Input{ReadInput: i} |
|
||||
} |
|
||||
|
|
||||
type Input struct { |
|
||||
args []string |
|
||||
arguments map[string]value.AppendValue |
|
||||
options map[string]value.AppendValue |
|
||||
mu sync.RWMutex |
|
||||
errorHandle func(error) error |
|
||||
} |
|
||||
|
|
||||
func (i *Input) ReadOption(ctx context.Context, name string) (value.Value, error) { |
|
||||
if v, ok := i.options[name]; ok { |
|
||||
return v, nil |
|
||||
} |
|
||||
|
|
||||
return nil, input.ErrNotFound |
|
||||
} |
|
||||
|
|
||||
func (i *Input) SetOption(name string, val value.Value) { |
|
||||
i.mu.Lock() |
|
||||
defer i.mu.Unlock() |
|
||||
|
|
||||
i.options[name] = &value.Read{Value: val} |
|
||||
} |
|
||||
|
|
||||
func (i *Input) ReadArgument(ctx context.Context, name string) (value.Value, error) { |
|
||||
if v, ok := i.arguments[name]; ok { |
|
||||
return v, nil |
|
||||
} |
|
||||
|
|
||||
return nil, input.ErrNotFound |
|
||||
} |
|
||||
|
|
||||
func (i *Input) SetArgument(name string, val value.Value) { |
|
||||
i.mu.Lock() |
|
||||
defer i.mu.Unlock() |
|
||||
|
|
||||
i.arguments[name] = &value.Read{Value: val} |
|
||||
} |
|
||||
|
|
||||
func (i *Input) Bind(ctx context.Context, def *input.Definition) error { |
|
||||
options := true |
|
||||
|
|
||||
for len(i.args) > 0 { |
|
||||
var err error |
|
||||
|
|
||||
arg := i.args[0] |
|
||||
i.args = i.args[1:] |
|
||||
|
|
||||
switch { |
|
||||
case options && arg == doubleDash: |
|
||||
options = false |
|
||||
case options && len(arg) > 2 && arg[0:2] == doubleDash: |
|
||||
err = i.parseLongOption(arg[2:], def) |
|
||||
case options && arg[0:1] == "-": |
|
||||
if len(arg) == 1 { |
|
||||
return fmt.Errorf("%w: option name required given '-'", input.ErrInvalidName) |
|
||||
} |
|
||||
|
|
||||
err = i.parseShortOption(arg[1:], def) |
|
||||
default: |
|
||||
err = i.parseArgument(arg, def) |
|
||||
} |
|
||||
|
|
||||
if err != nil { |
|
||||
if herr := i.errorHandle(err); herr != nil { |
|
||||
return herr |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return nil |
|
||||
} |
|
||||
|
|
||||
func (i *Input) parseLongOption(arg string, def *input.Definition) error { |
|
||||
var value *string |
|
||||
|
|
||||
name := arg |
|
||||
|
|
||||
if strings.Contains(arg, "=") { |
|
||||
vals := strings.SplitN(arg, "=", 2) |
|
||||
name = vals[0] |
|
||||
value = &vals[1] |
|
||||
} |
|
||||
|
|
||||
opt, err := def.Option(name) |
|
||||
if err != nil { |
|
||||
return input.ErrorOption(name, err) |
|
||||
} |
|
||||
|
|
||||
return i.appendOption(name, value, opt) |
|
||||
} |
|
||||
|
|
||||
func (i *Input) appendOption(name string, data *string, opt option.Option) error { |
|
||||
v, ok := i.options[name] |
|
||||
|
|
||||
if ok && !opt.IsArray() { |
|
||||
return fmt.Errorf("%w: got: array, expect: %s", input.ErrUnexpectedType, opt.Flag.Type()) |
|
||||
} |
|
||||
|
|
||||
var val string |
|
||||
|
|
||||
switch { |
|
||||
case data != nil: |
|
||||
val = *data |
|
||||
case opt.IsBool(): |
|
||||
val = "true" |
|
||||
case len(i.args) > 0 && len(i.args[0]) > 0 && i.args[0][0:1] != "-": |
|
||||
val = i.args[0] |
|
||||
i.args = i.args[1:] |
|
||||
default: |
|
||||
return input.ErrorOption(name, input.ErrRequired) |
|
||||
} |
|
||||
|
|
||||
if !ok { |
|
||||
v = value.ByFlag(opt.Flag) |
|
||||
i.options[name] = v |
|
||||
} |
|
||||
|
|
||||
if err := v.Append(val); err != nil { |
|
||||
return input.ErrorOption(name, err) |
|
||||
} |
|
||||
|
|
||||
return nil |
|
||||
} |
|
||||
|
|
||||
func (i *Input) parseShortOption(arg string, def *input.Definition) error { |
|
||||
name := arg |
|
||||
|
|
||||
var value string |
|
||||
|
|
||||
if len(name) > 1 { |
|
||||
name, value = arg[0:1], arg[1:] |
|
||||
} |
|
||||
|
|
||||
opt, err := def.ShortOption(name) |
|
||||
if err != nil { |
|
||||
return err |
|
||||
} |
|
||||
|
|
||||
if opt.IsBool() && value != "" { |
|
||||
if err := i.parseShortOption(value, def); err != nil { |
|
||||
return err |
|
||||
} |
|
||||
|
|
||||
value = "" |
|
||||
} |
|
||||
|
|
||||
if value == "" { |
|
||||
return i.appendOption(opt.Name, nil, opt) |
|
||||
} |
|
||||
|
|
||||
return i.appendOption(opt.Name, &value, opt) |
|
||||
} |
|
||||
|
|
||||
func (i *Input) parseArgument(arg string, def *input.Definition) error { |
|
||||
opt, err := def.Argument(len(i.arguments)) |
|
||||
if err != nil { |
|
||||
return err |
|
||||
} |
|
||||
|
|
||||
v, ok := i.arguments[opt.Name] |
|
||||
if !ok { |
|
||||
v = value.ByFlag(opt.Flag) |
|
||||
i.arguments[opt.Name] = v |
|
||||
} |
|
||||
|
|
||||
if err := v.Append(arg); err != nil { |
|
||||
return input.ErrorArgument(opt.Name, err) |
|
||||
} |
|
||||
|
|
||||
return nil |
|
||||
} |
|
@ -0,0 +1,168 @@ |
|||||
|
package input |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"sync" |
||||
|
|
||||
|
"gitoa.ru/go-4devs/console/input/errs" |
||||
|
"gitoa.ru/go-4devs/console/input/value" |
||||
|
) |
||||
|
|
||||
|
type Array struct { |
||||
|
defaults array |
||||
|
value array |
||||
|
} |
||||
|
|
||||
|
func (a *Array) GetOption(name string) (value.Append, bool) { |
||||
|
return a.value.GetOption(name) |
||||
|
} |
||||
|
|
||||
|
func (a *Array) SetOption(name string, v interface{}) { |
||||
|
a.value.SetOption(name, v) |
||||
|
} |
||||
|
|
||||
|
func (a *Array) LenArguments() int { |
||||
|
return a.value.LenArguments() |
||||
|
} |
||||
|
|
||||
|
func (a *Array) GetArgument(name string) (value.Append, bool) { |
||||
|
return a.value.GetArgument(name) |
||||
|
} |
||||
|
|
||||
|
func (a *Array) SetArgument(name string, v interface{}) { |
||||
|
a.value.SetArgument(name, v) |
||||
|
} |
||||
|
|
||||
|
func (a *Array) Option(_ context.Context, name string) value.Value { |
||||
|
if v, ok := a.value.GetOption(name); ok { |
||||
|
return v |
||||
|
} |
||||
|
|
||||
|
if v, ok := a.defaults.GetOption(name); ok { |
||||
|
return v |
||||
|
} |
||||
|
|
||||
|
return value.Empty |
||||
|
} |
||||
|
|
||||
|
func (a *Array) Argument(_ context.Context, name string) value.Value { |
||||
|
if v, ok := a.value.GetArgument(name); ok { |
||||
|
return v |
||||
|
} |
||||
|
|
||||
|
if v, ok := a.defaults.GetArgument(name); ok { |
||||
|
return v |
||||
|
} |
||||
|
|
||||
|
return value.Empty |
||||
|
} |
||||
|
|
||||
|
func (a *Array) Bind(ctx context.Context, d *Definition) error { |
||||
|
if err := a.bindArguments(ctx, d); err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
return a.bindOption(ctx, d) |
||||
|
} |
||||
|
|
||||
|
func (a *Array) bindOption(ctx context.Context, def *Definition) error { |
||||
|
for _, name := range def.Options() { |
||||
|
opt, err := def.Option(name) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
v, ok := a.value.GetOption(name) |
||||
|
if !ok { |
||||
|
switch { |
||||
|
case opt.HasDefault(): |
||||
|
a.defaults.SetOption(name, opt.Default) |
||||
|
continue |
||||
|
case opt.IsRequired(): |
||||
|
return errs.Option(name, errs.ErrRequired) |
||||
|
default: |
||||
|
continue |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if err := opt.Validate(v); err != nil { |
||||
|
return errs.Option(name, err) |
||||
|
} |
||||
|
|
||||
|
a.SetOption(name, v) |
||||
|
} |
||||
|
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (a *Array) bindArguments(ctx context.Context, def *Definition) error { |
||||
|
for pos, name := range def.Arguments() { |
||||
|
arg, err := def.Argument(pos) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
v, ok := a.value.GetArgument(name) |
||||
|
if !ok { |
||||
|
switch { |
||||
|
case arg.HasDefault(): |
||||
|
a.defaults.SetArgument(name, arg.Default) |
||||
|
continue |
||||
|
case arg.IsRequired(): |
||||
|
return errs.Argument(name, errs.ErrRequired) |
||||
|
default: |
||||
|
continue |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if err := arg.Validate(v); err != nil { |
||||
|
return errs.Argument(name, err) |
||||
|
} |
||||
|
|
||||
|
a.SetArgument(name, v) |
||||
|
} |
||||
|
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
type array struct { |
||||
|
opts map[string]value.Append |
||||
|
args map[string]value.Append |
||||
|
mu sync.Mutex |
||||
|
} |
||||
|
|
||||
|
func (a *array) GetOption(name string) (value.Append, bool) { |
||||
|
v, ok := a.opts[name] |
||||
|
|
||||
|
return v, ok |
||||
|
} |
||||
|
|
||||
|
func (a *array) SetOption(name string, v interface{}) { |
||||
|
if a.opts == nil { |
||||
|
a.opts = make(map[string]value.Append) |
||||
|
} |
||||
|
|
||||
|
a.mu.Lock() |
||||
|
a.opts[name] = value.New(v) |
||||
|
a.mu.Unlock() |
||||
|
} |
||||
|
|
||||
|
func (a *array) LenArguments() int { |
||||
|
return len(a.args) |
||||
|
} |
||||
|
|
||||
|
func (a *array) GetArgument(name string) (value.Append, bool) { |
||||
|
v, ok := a.args[name] |
||||
|
|
||||
|
return v, ok |
||||
|
} |
||||
|
|
||||
|
func (a *array) SetArgument(name string, v interface{}) { |
||||
|
if a.args == nil { |
||||
|
a.args = make(map[string]value.Append) |
||||
|
} |
||||
|
|
||||
|
a.mu.Lock() |
||||
|
a.args[name] = value.New(v) |
||||
|
a.mu.Unlock() |
||||
|
} |
@ -1,87 +0,0 @@ |
|||||
package array |
|
||||
|
|
||||
import ( |
|
||||
"context" |
|
||||
"sync" |
|
||||
|
|
||||
"gitoa.ru/go-4devs/console/input" |
|
||||
"gitoa.ru/go-4devs/console/input/value" |
|
||||
"gitoa.ru/go-4devs/console/input/wrap" |
|
||||
) |
|
||||
|
|
||||
var _ input.ReadInput = (*Input)(nil) |
|
||||
|
|
||||
func Argument(name string, v interface{}) func(*Input) { |
|
||||
return func(i *Input) { |
|
||||
i.args[name] = value.New(v) |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
func Option(name string, v interface{}) func(*Input) { |
|
||||
return func(i *Input) { |
|
||||
i.opt[name] = value.New(v) |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
func New(opts ...func(*Input)) *wrap.Input { |
|
||||
i := &Input{ |
|
||||
args: make(map[string]value.Value), |
|
||||
opt: make(map[string]value.Value), |
|
||||
} |
|
||||
|
|
||||
for _, opt := range opts { |
|
||||
opt(i) |
|
||||
} |
|
||||
|
|
||||
return &wrap.Input{ReadInput: i} |
|
||||
} |
|
||||
|
|
||||
type Input struct { |
|
||||
args map[string]value.Value |
|
||||
opt map[string]value.Value |
|
||||
mu sync.Mutex |
|
||||
} |
|
||||
|
|
||||
func (i *Input) ReadOption(_ context.Context, name string) (value.Value, error) { |
|
||||
if o, has := i.opt[name]; has { |
|
||||
return o, nil |
|
||||
} |
|
||||
|
|
||||
return nil, input.ErrorOption(name, input.ErrNotFound) |
|
||||
} |
|
||||
|
|
||||
func (i *Input) HasOption(name string) bool { |
|
||||
_, has := i.opt[name] |
|
||||
|
|
||||
return has |
|
||||
} |
|
||||
|
|
||||
func (i *Input) SetOption(name string, val value.Value) { |
|
||||
i.mu.Lock() |
|
||||
i.opt[name] = val |
|
||||
i.mu.Unlock() |
|
||||
} |
|
||||
|
|
||||
func (i *Input) ReadArgument(_ context.Context, name string) (value.Value, error) { |
|
||||
if a, has := i.args[name]; has { |
|
||||
return a, nil |
|
||||
} |
|
||||
|
|
||||
return nil, input.ErrorArgument(name, input.ErrNotFound) |
|
||||
} |
|
||||
|
|
||||
func (i *Input) HasArgument(name string) bool { |
|
||||
_, has := i.args[name] |
|
||||
|
|
||||
return has |
|
||||
} |
|
||||
|
|
||||
func (i *Input) SetArgument(name string, val value.Value) { |
|
||||
i.mu.Lock() |
|
||||
i.args[name] = val |
|
||||
i.mu.Unlock() |
|
||||
} |
|
||||
|
|
||||
func (i *Input) Bind(_ context.Context, def *input.Definition) error { |
|
||||
return nil |
|
||||
} |
|
@ -0,0 +1,18 @@ |
|||||
|
package input |
||||
|
|
||||
|
//go:generate stringer -type=Type -linecomment
|
||||
|
|
||||
|
type Type int |
||||
|
|
||||
|
const ( |
||||
|
Argument Type = iota // argument
|
||||
|
Option // option
|
||||
|
) |
||||
|
|
||||
|
func (t Type) IsArgument() bool { |
||||
|
return t == Argument |
||||
|
} |
||||
|
|
||||
|
func (t Type) IsOption() bool { |
||||
|
return t == Option |
||||
|
} |
@ -0,0 +1,24 @@ |
|||||
|
// Code generated by "stringer -type=Type -linecomment"; DO NOT EDIT.
|
||||
|
|
||||
|
package input |
||||
|
|
||||
|
import "strconv" |
||||
|
|
||||
|
func _() { |
||||
|
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
|
// Re-run the stringer command to generate them again.
|
||||
|
var x [1]struct{} |
||||
|
_ = x[Argument-0] |
||||
|
_ = x[Option-1] |
||||
|
} |
||||
|
|
||||
|
const _Type_name = "argumentoption" |
||||
|
|
||||
|
var _Type_index = [...]uint8{0, 8, 14} |
||||
|
|
||||
|
func (i Type) String() string { |
||||
|
if i < 0 || i >= Type(len(_Type_index)-1) { |
||||
|
return "Type(" + strconv.FormatInt(int64(i), 10) + ")" |
||||
|
} |
||||
|
return _Type_name[_Type_index[i]:_Type_index[i+1]] |
||||
|
} |
@ -0,0 +1,36 @@ |
|||||
|
package input |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
|
||||
|
"gitoa.ru/go-4devs/console/input/value" |
||||
|
) |
||||
|
|
||||
|
type Wrap struct { |
||||
|
Input |
||||
|
Array |
||||
|
} |
||||
|
|
||||
|
func (w *Wrap) Option(ctx context.Context, name string) value.Value { |
||||
|
if v, ok := w.Array.GetOption(name); ok { |
||||
|
return v |
||||
|
} |
||||
|
|
||||
|
return w.Input.Option(ctx, name) |
||||
|
} |
||||
|
|
||||
|
func (w *Wrap) Argument(ctx context.Context, name string) value.Value { |
||||
|
if v, ok := w.Array.GetArgument(name); ok { |
||||
|
return v |
||||
|
} |
||||
|
|
||||
|
return w.Input.Argument(ctx, name) |
||||
|
} |
||||
|
|
||||
|
func (w *Wrap) Bind(ctx context.Context, def *Definition) error { |
||||
|
if err := w.Input.Bind(ctx, def); err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
return w.Array.Bind(ctx, def) |
||||
|
} |
@ -1,105 +0,0 @@ |
|||||
package wrap |
|
||||
|
|
||||
import ( |
|
||||
"context" |
|
||||
"errors" |
|
||||
|
|
||||
"gitoa.ru/go-4devs/console/input" |
|
||||
"gitoa.ru/go-4devs/console/input/value" |
|
||||
) |
|
||||
|
|
||||
type Input struct { |
|
||||
input.ReadInput |
|
||||
} |
|
||||
|
|
||||
func (i *Input) Option(ctx context.Context, name string) value.Value { |
|
||||
if v, err := i.ReadOption(ctx, name); err == nil { |
|
||||
return v |
|
||||
} |
|
||||
|
|
||||
return &value.Empty{} |
|
||||
} |
|
||||
|
|
||||
func (i *Input) Argument(ctx context.Context, name string) value.Value { |
|
||||
if v, err := i.ReadArgument(ctx, name); err == nil { |
|
||||
return v |
|
||||
} |
|
||||
|
|
||||
return &value.Empty{} |
|
||||
} |
|
||||
|
|
||||
func (i *Input) Bind(ctx context.Context, def *input.Definition) error { |
|
||||
if err := i.ReadInput.Bind(ctx, def); err != nil { |
|
||||
return err |
|
||||
} |
|
||||
|
|
||||
if err := i.bindArguments(ctx, def); err != nil { |
|
||||
return err |
|
||||
} |
|
||||
|
|
||||
return i.bindOptions(ctx, def) |
|
||||
} |
|
||||
|
|
||||
func (i *Input) bindOptions(ctx context.Context, def *input.Definition) error { |
|
||||
for _, name := range def.Options() { |
|
||||
opt, err := def.Option(name) |
|
||||
if err != nil { |
|
||||
return err |
|
||||
} |
|
||||
|
|
||||
v, err := i.ReadOption(ctx, name) |
|
||||
if err != nil && !errors.Is(err, input.ErrNotFound) { |
|
||||
return input.ErrorOption(name, err) |
|
||||
} |
|
||||
|
|
||||
if err == nil { |
|
||||
if err := opt.Validate(v); err != nil { |
|
||||
return input.ErrorOption(name, err) |
|
||||
} |
|
||||
|
|
||||
continue |
|
||||
} |
|
||||
|
|
||||
if opt.IsRequired() && !opt.HasDefault() { |
|
||||
return input.ErrorOption(name, input.ErrRequired) |
|
||||
} |
|
||||
|
|
||||
if opt.HasDefault() { |
|
||||
i.SetOption(name, opt.Default) |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return nil |
|
||||
} |
|
||||
|
|
||||
func (i *Input) bindArguments(ctx context.Context, def *input.Definition) error { |
|
||||
for pos, name := range def.Arguments() { |
|
||||
arg, err := def.Argument(pos) |
|
||||
if err != nil { |
|
||||
return err |
|
||||
} |
|
||||
|
|
||||
v, err := i.ReadArgument(ctx, name) |
|
||||
if err != nil && !errors.Is(err, input.ErrNotFound) { |
|
||||
return input.ErrorArgument(name, err) |
|
||||
} |
|
||||
|
|
||||
if err == nil { |
|
||||
if err := arg.Validate(v); err != nil { |
|
||||
return input.ErrorArgument(name, err) |
|
||||
} |
|
||||
|
|
||||
continue |
|
||||
} |
|
||||
|
|
||||
if arg.IsRequired() && !arg.HasDefault() { |
|
||||
return input.ErrorArgument(name, input.ErrRequired) |
|
||||
} |
|
||||
|
|
||||
if arg.HasDefault() { |
|
||||
i.SetArgument(name, arg.Default) |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return nil |
|
||||
} |
|
@ -0,0 +1,22 @@ |
|||||
|
package output |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
|
||||
|
"gitoa.ru/go-4devs/console/output/formatter" |
||||
|
"gitoa.ru/go-4devs/console/output/verbosity" |
||||
|
) |
||||
|
|
||||
|
func Format(out Output, format *formatter.Formatter) Output { |
||||
|
return func(ctx context.Context, v verbosity.Verbosity, msg string, kv ...KeyValue) (int, error) { |
||||
|
return out(ctx, v, format.Format(ctx, msg), kv...) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func Ansi(out Output) Output { |
||||
|
return Format(out, formatter.Ansi()) |
||||
|
} |
||||
|
|
||||
|
func None(out Output) Output { |
||||
|
return Format(out, formatter.None()) |
||||
|
} |
@ -0,0 +1,13 @@ |
|||||
|
package output |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
|
||||
|
"gitoa.ru/go-4devs/console/output/verbosity" |
||||
|
) |
||||
|
|
||||
|
func Quiet() Output { |
||||
|
return func(context.Context, verbosity.Verbosity, string, ...KeyValue) (int, error) { |
||||
|
return 0, nil |
||||
|
} |
||||
|
} |
@ -0,0 +1,17 @@ |
|||||
|
package output |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
|
||||
|
"gitoa.ru/go-4devs/console/output/verbosity" |
||||
|
) |
||||
|
|
||||
|
func Verbosity(out Output, verb verbosity.Verbosity) Output { |
||||
|
return func(ctx context.Context, v verbosity.Verbosity, msg string, kv ...KeyValue) (int, error) { |
||||
|
if verb >= v { |
||||
|
return out(ctx, v, msg, kv...) |
||||
|
} |
||||
|
|
||||
|
return 0, nil |
||||
|
} |
||||
|
} |
@ -1,23 +0,0 @@ |
|||||
package verbosity |
|
||||
|
|
||||
import ( |
|
||||
"context" |
|
||||
|
|
||||
"gitoa.ru/go-4devs/console/output" |
|
||||
) |
|
||||
|
|
||||
func Verb(out output.Output, verb output.Verbosity) output.Output { |
|
||||
return func(ctx context.Context, v output.Verbosity, msg string, kv ...output.KeyValue) (int, error) { |
|
||||
if verb >= v { |
|
||||
return out(ctx, v, msg, kv...) |
|
||||
} |
|
||||
|
|
||||
return 0, nil |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
func Quiet() output.Output { |
|
||||
return func(context.Context, output.Verbosity, string, ...output.KeyValue) (int, error) { |
|
||||
return 0, nil |
|
||||
} |
|
||||
} |
|
@ -0,0 +1,13 @@ |
|||||
|
package verbosity |
||||
|
|
||||
|
//go:generate stringer -type=Verbosity -linecomment
|
||||
|
|
||||
|
type Verbosity int |
||||
|
|
||||
|
const ( |
||||
|
Quiet Verbosity = iota - 1 // quiet
|
||||
|
Norm // norm
|
||||
|
Info // info
|
||||
|
Debug // debug
|
||||
|
Trace // trace
|
||||
|
) |
@ -0,0 +1,28 @@ |
|||||
|
// Code generated by "stringer -type=Verbosity -linecomment"; DO NOT EDIT.
|
||||
|
|
||||
|
package verbosity |
||||
|
|
||||
|
import "strconv" |
||||
|
|
||||
|
func _() { |
||||
|
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
|
// Re-run the stringer command to generate them again.
|
||||
|
var x [1]struct{} |
||||
|
_ = x[Quiet - -1] |
||||
|
_ = x[Norm-0] |
||||
|
_ = x[Info-1] |
||||
|
_ = x[Debug-2] |
||||
|
_ = x[Trace-3] |
||||
|
} |
||||
|
|
||||
|
const _Verbosity_name = "quietnorminfodebugtrace" |
||||
|
|
||||
|
var _Verbosity_index = [...]uint8{0, 5, 9, 13, 18, 23} |
||||
|
|
||||
|
func (i Verbosity) String() string { |
||||
|
i -= -1 |
||||
|
if i < 0 || i >= Verbosity(len(_Verbosity_index)-1) { |
||||
|
return "Verbosity(" + strconv.FormatInt(int64(i+-1), 10) + ")" |
||||
|
} |
||||
|
return _Verbosity_name[_Verbosity_index[i]:_Verbosity_index[i+1]] |
||||
|
} |
@ -1,22 +0,0 @@ |
|||||
package wrap |
|
||||
|
|
||||
import ( |
|
||||
"context" |
|
||||
|
|
||||
"gitoa.ru/go-4devs/console/output" |
|
||||
"gitoa.ru/go-4devs/console/output/formatter" |
|
||||
) |
|
||||
|
|
||||
func Format(out output.Output, format *formatter.Formatter) output.Output { |
|
||||
return func(ctx context.Context, v output.Verbosity, msg string, kv ...output.KeyValue) (int, error) { |
|
||||
return out(ctx, v, format.Format(ctx, msg), kv...) |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
func Ansi(out output.Output) output.Output { |
|
||||
return Format(out, formatter.Ansi()) |
|
||||
} |
|
||||
|
|
||||
func None(out output.Output) output.Output { |
|
||||
return Format(out, formatter.None()) |
|
||||
} |
|
@ -0,0 +1,45 @@ |
|||||
|
package output |
||||
|
|
||||
|
import ( |
||||
|
"bytes" |
||||
|
"context" |
||||
|
"fmt" |
||||
|
"io" |
||||
|
"os" |
||||
|
"strings" |
||||
|
|
||||
|
"gitoa.ru/go-4devs/console/output/verbosity" |
||||
|
) |
||||
|
|
||||
|
const newline = "\n" |
||||
|
|
||||
|
func Stderr() Output { |
||||
|
return New(os.Stderr, FormatString) |
||||
|
} |
||||
|
|
||||
|
func Stdout() Output { |
||||
|
return New(os.Stdout, FormatString) |
||||
|
} |
||||
|
|
||||
|
func Buffer(buf *bytes.Buffer) Output { |
||||
|
return New(buf, FormatString) |
||||
|
} |
||||
|
|
||||
|
func FormatString(_ verbosity.Verbosity, msg string, kv ...KeyValue) string { |
||||
|
if len(kv) > 0 { |
||||
|
nline := "" |
||||
|
if msg[len(msg)-1:] == newline { |
||||
|
nline = newline |
||||
|
} |
||||
|
|
||||
|
return "msg=\"" + strings.TrimSpace(msg) + "\", " + KeyValues(kv).String() + nline |
||||
|
} |
||||
|
|
||||
|
return msg |
||||
|
} |
||||
|
|
||||
|
func New(w io.Writer, format func(verb verbosity.Verbosity, msg string, kv ...KeyValue) string) Output { |
||||
|
return func(ctx context.Context, verb verbosity.Verbosity, msg string, kv ...KeyValue) (int, error) { |
||||
|
return fmt.Fprint(w, format(verb, msg, kv...)) |
||||
|
} |
||||
|
} |
@ -1,45 +0,0 @@ |
|||||
package writer |
|
||||
|
|
||||
import ( |
|
||||
"bytes" |
|
||||
"context" |
|
||||
"fmt" |
|
||||
"io" |
|
||||
"os" |
|
||||
"strings" |
|
||||
|
|
||||
"gitoa.ru/go-4devs/console/output" |
|
||||
) |
|
||||
|
|
||||
const newline = "\n" |
|
||||
|
|
||||
func Stderr() output.Output { |
|
||||
return New(os.Stderr, String) |
|
||||
} |
|
||||
|
|
||||
func Stdout() output.Output { |
|
||||
return New(os.Stdout, String) |
|
||||
} |
|
||||
|
|
||||
func Buffer(buf *bytes.Buffer) output.Output { |
|
||||
return New(buf, String) |
|
||||
} |
|
||||
|
|
||||
func String(_ output.Verbosity, msg string, kv ...output.KeyValue) string { |
|
||||
if len(kv) > 0 { |
|
||||
nline := "" |
|
||||
if msg[len(msg)-1:] == newline { |
|
||||
nline = newline |
|
||||
} |
|
||||
|
|
||||
return "msg=\"" + strings.TrimSpace(msg) + "\", " + output.KeyValues(kv).String() + nline |
|
||||
} |
|
||||
|
|
||||
return msg |
|
||||
} |
|
||||
|
|
||||
func New(w io.Writer, format func(verb output.Verbosity, msg string, kv ...output.KeyValue) string) output.Output { |
|
||||
return func(ctx context.Context, verb output.Verbosity, msg string, kv ...output.KeyValue) (int, error) { |
|
||||
return fmt.Fprint(w, format(verb, msg, kv...)) |
|
||||
} |
|
||||
} |
|
Loading…
Reference in new issue