update input/outpu
This commit is contained in:
16
app.go
16
app.go
@@ -5,10 +5,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"gitoa.ru/go-4devs/console/input"
|
"gitoa.ru/go-4devs/console/input"
|
||||||
"gitoa.ru/go-4devs/console/input/argv"
|
|
||||||
"gitoa.ru/go-4devs/console/input/value"
|
"gitoa.ru/go-4devs/console/input/value"
|
||||||
"gitoa.ru/go-4devs/console/output"
|
"gitoa.ru/go-4devs/console/output"
|
||||||
"gitoa.ru/go-4devs/console/output/writer"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// WithOutput sets outpu,^ by default output os.Stdout.
|
// WithOutput sets outpu,^ by default output os.Stdout.
|
||||||
@@ -42,7 +40,7 @@ func WithExit(f func(int)) func(*App) {
|
|||||||
// New creates and configure new console app.
|
// New creates and configure new console app.
|
||||||
func New(opts ...func(*App)) *App {
|
func New(opts ...func(*App)) *App {
|
||||||
a := &App{
|
a := &App{
|
||||||
out: writer.Stdout(),
|
out: output.Stdout(),
|
||||||
exit: os.Exit,
|
exit: os.Exit,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +62,9 @@ func New(opts ...func(*App)) *App {
|
|||||||
skip = 1
|
skip = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
a.in = argv.New(os.Args[skip:])
|
a.in = &input.Argv{
|
||||||
|
Args: os.Args[skip:],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return a
|
return a
|
||||||
@@ -130,10 +130,12 @@ func (a *App) list(ctx context.Context) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
in := &input.Wrap{
|
||||||
|
Input: a.in,
|
||||||
|
}
|
||||||
|
in.SetArgument("command_name", value.New(CommandList))
|
||||||
|
|
||||||
a.in.SetArgument("command_name", value.New(CommandList))
|
return Run(ctx, cmd, in, a.out)
|
||||||
|
|
||||||
return Run(ctx, cmd, a.in, a.out)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) printError(ctx context.Context, err error) {
|
func (a *App) printError(ctx context.Context, err error) {
|
||||||
|
|||||||
@@ -11,10 +11,8 @@ import (
|
|||||||
"gitoa.ru/go-4devs/console/example/pkg/command"
|
"gitoa.ru/go-4devs/console/example/pkg/command"
|
||||||
"gitoa.ru/go-4devs/console/input"
|
"gitoa.ru/go-4devs/console/input"
|
||||||
"gitoa.ru/go-4devs/console/input/argument"
|
"gitoa.ru/go-4devs/console/input/argument"
|
||||||
"gitoa.ru/go-4devs/console/input/array"
|
|
||||||
"gitoa.ru/go-4devs/console/input/option"
|
"gitoa.ru/go-4devs/console/input/option"
|
||||||
"gitoa.ru/go-4devs/console/output"
|
"gitoa.ru/go-4devs/console/output"
|
||||||
"gitoa.ru/go-4devs/console/output/writer"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//nolint: gochecknoinits
|
//nolint: gochecknoinits
|
||||||
@@ -91,8 +89,8 @@ func TestChainHandle(t *testing.T) {
|
|||||||
var cnt int32
|
var cnt int32
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
in := array.New()
|
in := &input.Array{}
|
||||||
out := writer.Stdout()
|
out := output.Stdout()
|
||||||
|
|
||||||
handle := func(ctx context.Context, in input.Input, out output.Output, next console.Action) error {
|
handle := func(ctx context.Context, in input.Input, out output.Output, next console.Action) error {
|
||||||
atomic.AddInt32(&cnt, 1)
|
atomic.AddInt32(&cnt, 1)
|
||||||
|
|||||||
31
console.go
31
console.go
@@ -10,7 +10,6 @@ import (
|
|||||||
"gitoa.ru/go-4devs/console/input/value"
|
"gitoa.ru/go-4devs/console/input/value"
|
||||||
"gitoa.ru/go-4devs/console/output"
|
"gitoa.ru/go-4devs/console/output"
|
||||||
"gitoa.ru/go-4devs/console/output/verbosity"
|
"gitoa.ru/go-4devs/console/output/verbosity"
|
||||||
"gitoa.ru/go-4devs/console/output/wrap"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -36,7 +35,7 @@ func Run(ctx context.Context, cmd *Command, in input.Input, out output.Output) e
|
|||||||
if err := in.Bind(ctx, Default(def)); err != nil {
|
if err := in.Bind(ctx, Default(def)); err != nil {
|
||||||
ansi(ctx, in, out).Print(ctx, "<error>\n\n ", err, "\n</error>\n")
|
ansi(ctx, in, out).Print(ctx, "<error>\n\n ", err, "\n</error>\n")
|
||||||
|
|
||||||
return showHelp(ctx, cmd, in, wrap.Ansi(out))
|
return showHelp(ctx, cmd, in, output.Ansi(out))
|
||||||
}
|
}
|
||||||
|
|
||||||
out = ansi(ctx, in, out)
|
out = ansi(ctx, in, out)
|
||||||
@@ -64,13 +63,13 @@ 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 {
|
func ansi(ctx context.Context, in input.Input, out output.Output) output.Output {
|
||||||
switch {
|
switch {
|
||||||
case in.Option(ctx, "ansi").Bool():
|
case in.Option(ctx, "ansi").Bool():
|
||||||
out = wrap.Ansi(out)
|
out = output.Ansi(out)
|
||||||
case in.Option(ctx, "no-ansi").Bool():
|
case in.Option(ctx, "no-ansi").Bool():
|
||||||
out = wrap.None(out)
|
out = output.None(out)
|
||||||
case lookupEnv("NO_COLOR"):
|
case lookupEnv("NO_COLOR"):
|
||||||
out = wrap.None(out)
|
out = output.None(out)
|
||||||
default:
|
default:
|
||||||
out = wrap.Ansi(out)
|
out = output.Ansi(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
return out
|
return out
|
||||||
@@ -85,19 +84,19 @@ func lookupEnv(name string) bool {
|
|||||||
func verbose(ctx context.Context, in input.Input, out output.Output) output.Output {
|
func verbose(ctx context.Context, in input.Input, out output.Output) output.Output {
|
||||||
switch {
|
switch {
|
||||||
case in.Option(ctx, "quiet").Bool():
|
case in.Option(ctx, "quiet").Bool():
|
||||||
out = verbosity.Quiet()
|
out = output.Quiet()
|
||||||
default:
|
default:
|
||||||
v := in.Option(ctx, "verbose").Bools()
|
v := in.Option(ctx, "verbose").Bools()
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case len(v) == verboseInfo:
|
case len(v) == verboseInfo:
|
||||||
out = verbosity.Verb(out, output.VerbosityInfo)
|
out = output.Verbosity(out, verbosity.Info)
|
||||||
case len(v) == verboseDebug:
|
case len(v) == verboseDebug:
|
||||||
out = verbosity.Verb(out, output.VerbosityDebug)
|
out = output.Verbosity(out, verbosity.Debug)
|
||||||
case len(v) >= verboseTrace:
|
case len(v) >= verboseTrace:
|
||||||
out = verbosity.Verb(out, output.VerbosityTrace)
|
out = output.Verbosity(out, verbosity.Trace)
|
||||||
default:
|
default:
|
||||||
out = verbosity.Verb(out, output.VerbosityNorm)
|
out = output.Verbosity(out, verbosity.Norm)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,8 +104,12 @@ 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 {
|
func showHelp(ctx context.Context, cmd *Command, in input.Input, out output.Output) error {
|
||||||
in.SetArgument(HelpArgumentCommandName, value.New(cmd.Name))
|
w := &input.Wrap{
|
||||||
in.SetOption("help", value.New(false))
|
Input: in,
|
||||||
|
}
|
||||||
|
|
||||||
|
w.SetArgument(HelpArgumentCommandName, value.New(cmd.Name))
|
||||||
|
w.SetOption("help", value.New(false))
|
||||||
|
|
||||||
if _, err := Find(cmd.Name); errors.Is(err, ErrNotFound) {
|
if _, err := Find(cmd.Name); errors.Is(err, ErrNotFound) {
|
||||||
register(cmd)
|
register(cmd)
|
||||||
@@ -117,7 +120,7 @@ func showHelp(ctx context.Context, cmd *Command, in input.Input, out output.Outp
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return Run(ctx, help, in, out)
|
return Run(ctx, help, w, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default options and argument command.
|
// Default options and argument command.
|
||||||
|
|||||||
@@ -5,16 +5,16 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"gitoa.ru/go-4devs/console"
|
"gitoa.ru/go-4devs/console"
|
||||||
"gitoa.ru/go-4devs/console/input/array"
|
"gitoa.ru/go-4devs/console/input"
|
||||||
"gitoa.ru/go-4devs/console/input/value"
|
"gitoa.ru/go-4devs/console/input/value"
|
||||||
"gitoa.ru/go-4devs/console/output/writer"
|
"gitoa.ru/go-4devs/console/output"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ExampleRun() {
|
func ExampleRun() {
|
||||||
cmd := Command()
|
cmd := Command()
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
out := writer.Stdout()
|
out := output.Stdout()
|
||||||
in := array.New()
|
in := &input.Array{}
|
||||||
|
|
||||||
err := console.Run(ctx, cmd, in, out)
|
err := console.Run(ctx, cmd, in, out)
|
||||||
fmt.Println("err:", err)
|
fmt.Println("err:", err)
|
||||||
@@ -29,7 +29,7 @@ func ExampleRun() {
|
|||||||
func ExampleExecute() {
|
func ExampleExecute() {
|
||||||
cmd := Command()
|
cmd := Command()
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
in := array.New()
|
in := &input.Array{}
|
||||||
|
|
||||||
// Run command: ./bin "argument value" -b --string="same value" --string="other value"
|
// Run command: ./bin "argument value" -b --string="same value" --string="other value"
|
||||||
in.SetOption("bool", value.New(true))
|
in.SetOption("bool", value.New(true))
|
||||||
|
|||||||
@@ -7,15 +7,16 @@ import (
|
|||||||
|
|
||||||
"gitoa.ru/go-4devs/console"
|
"gitoa.ru/go-4devs/console"
|
||||||
"gitoa.ru/go-4devs/console/example/pkg/command"
|
"gitoa.ru/go-4devs/console/example/pkg/command"
|
||||||
"gitoa.ru/go-4devs/console/input/array"
|
"gitoa.ru/go-4devs/console/input"
|
||||||
"gitoa.ru/go-4devs/console/output/writer"
|
"gitoa.ru/go-4devs/console/output"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCreateUser(t *testing.T) {
|
func TestCreateUser(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
in := array.New(array.Argument("username", "andrey"))
|
in := &input.Array{}
|
||||||
|
in.SetArgument("username", "andrey")
|
||||||
buf := bytes.Buffer{}
|
buf := bytes.Buffer{}
|
||||||
out := writer.Buffer(&buf)
|
out := output.Buffer(&buf)
|
||||||
|
|
||||||
err := console.Run(ctx, command.CreateUser(false), in, out)
|
err := console.Run(ctx, command.CreateUser(false), in, out)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
153
input/argv.go
Normal file
153
input/argv.go
Normal file
@@ -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
|
|
||||||
}
|
|
||||||
168
input/array.go
Normal file
168
input/array.go
Normal file
@@ -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
|
|
||||||
}
|
|
||||||
@@ -2,6 +2,7 @@ package input
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"gitoa.ru/go-4devs/console/input/argument"
|
"gitoa.ru/go-4devs/console/input/argument"
|
||||||
|
"gitoa.ru/go-4devs/console/input/errs"
|
||||||
"gitoa.ru/go-4devs/console/input/option"
|
"gitoa.ru/go-4devs/console/input/option"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -66,7 +67,7 @@ func (d *Definition) SetArguments(args ...argument.Argument) *Definition {
|
|||||||
|
|
||||||
func (d *Definition) Argument(pos int) (argument.Argument, error) {
|
func (d *Definition) Argument(pos int) (argument.Argument, error) {
|
||||||
if len(d.posArgs) == 0 {
|
if len(d.posArgs) == 0 {
|
||||||
return argument.Argument{}, ErrNoArgs
|
return argument.Argument{}, errs.ErrNoArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
lastPos := len(d.posArgs) - 1
|
lastPos := len(d.posArgs) - 1
|
||||||
@@ -76,7 +77,7 @@ func (d *Definition) Argument(pos int) (argument.Argument, error) {
|
|||||||
return arg, nil
|
return arg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return argument.Argument{}, ErrToManyArgs
|
return argument.Argument{}, errs.ErrToManyArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
return d.args[d.posArgs[pos]], nil
|
return d.args[d.posArgs[pos]], nil
|
||||||
@@ -85,7 +86,7 @@ func (d *Definition) Argument(pos int) (argument.Argument, error) {
|
|||||||
func (d *Definition) ShortOption(short string) (option.Option, error) {
|
func (d *Definition) ShortOption(short string) (option.Option, error) {
|
||||||
name, ok := d.short[short]
|
name, ok := d.short[short]
|
||||||
if !ok {
|
if !ok {
|
||||||
return option.Option{}, ErrNotFound
|
return option.Option{}, errs.ErrNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
return d.Option(name)
|
return d.Option(name)
|
||||||
@@ -96,5 +97,5 @@ func (d *Definition) Option(name string) (option.Option, error) {
|
|||||||
return opt, nil
|
return opt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return option.Option{}, ErrNotFound
|
return option.Option{}, errs.ErrNotFound
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package input
|
package errs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
@@ -15,6 +15,14 @@ var (
|
|||||||
ErrInvalidName = errors.New("invalid name")
|
ErrInvalidName = errors.New("invalid name")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func New(name, t string, err error) Error {
|
||||||
|
return Error{
|
||||||
|
name: name,
|
||||||
|
t: t,
|
||||||
|
err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type Error struct {
|
type Error struct {
|
||||||
name string
|
name string
|
||||||
err error
|
err error
|
||||||
@@ -33,7 +41,7 @@ func (o Error) Unwrap() error {
|
|||||||
return o.err
|
return o.err
|
||||||
}
|
}
|
||||||
|
|
||||||
func ErrorOption(name string, err error) Error {
|
func Option(name string, err error) Error {
|
||||||
return Error{
|
return Error{
|
||||||
name: name,
|
name: name,
|
||||||
err: err,
|
err: err,
|
||||||
@@ -41,7 +49,7 @@ func ErrorOption(name string, err error) Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ErrorArgument(name string, err error) Error {
|
func Argument(name string, err error) Error {
|
||||||
return Error{
|
return Error{
|
||||||
name: name,
|
name: name,
|
||||||
err: err,
|
err: err,
|
||||||
@@ -6,18 +6,8 @@ import (
|
|||||||
"gitoa.ru/go-4devs/console/input/value"
|
"gitoa.ru/go-4devs/console/input/value"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ReadInput interface {
|
|
||||||
Bind(ctx context.Context, def *Definition) error
|
|
||||||
|
|
||||||
ReadOption(ctx context.Context, name string) (value.Value, error)
|
|
||||||
SetOption(name string, v value.Value)
|
|
||||||
|
|
||||||
ReadArgument(ctx context.Context, name string) (value.Value, error)
|
|
||||||
SetArgument(name string, v value.Value)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Input interface {
|
type Input interface {
|
||||||
Option(ctx context.Context, name string) value.Value
|
Option(ctx context.Context, name string) value.Value
|
||||||
Argument(ctx context.Context, name string) value.Value
|
Argument(ctx context.Context, name string) value.Value
|
||||||
ReadInput
|
Bind(ctx context.Context, def *Definition) error
|
||||||
}
|
}
|
||||||
|
|||||||
18
input/type.go
Normal file
18
input/type.go
Normal file
@@ -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
|
||||||
|
}
|
||||||
24
input/type_string.go
Normal file
24
input/type_string.go
Normal file
@@ -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]]
|
||||||
|
}
|
||||||
@@ -99,7 +99,7 @@ func TestNotBlank(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ca.empty == nil {
|
if ca.empty == nil {
|
||||||
ca.empty = &value.Empty{}
|
ca.empty = value.Empty
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := valid(ca.empty); err == nil || !errors.Is(err, validator.ErrNotBlank) {
|
if err := valid(ca.empty); err == nil || !errors.Is(err, validator.ErrNotBlank) {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package value
|
|||||||
import "gitoa.ru/go-4devs/console/input/flag"
|
import "gitoa.ru/go-4devs/console/input/flag"
|
||||||
|
|
||||||
type Any struct {
|
type Any struct {
|
||||||
Empty
|
empty
|
||||||
Val []interface{}
|
Val []interface{}
|
||||||
Flag flag.Flag
|
Flag flag.Flag
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Bool struct {
|
type Bool struct {
|
||||||
Empty
|
empty
|
||||||
Val []bool
|
Val []bool
|
||||||
Flag flag.Flag
|
Flag flag.Flag
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Duration struct {
|
type Duration struct {
|
||||||
Empty
|
empty
|
||||||
Val []time.Duration
|
Val []time.Duration
|
||||||
Flag flag.Flag
|
Flag flag.Flag
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,84 +4,90 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Empty struct{}
|
var Empty = &empty{}
|
||||||
|
|
||||||
func (e *Empty) Append(string) error {
|
func IsEmpty(v Value) bool {
|
||||||
|
return v == Empty
|
||||||
|
}
|
||||||
|
|
||||||
|
type empty struct{}
|
||||||
|
|
||||||
|
func (e *empty) Append(string) error {
|
||||||
return ErrAppendEmpty
|
return ErrAppendEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Empty) String() string {
|
func (e *empty) String() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Empty) Int() int {
|
func (e *empty) Int() int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Empty) Int64() int64 {
|
func (e *empty) Int64() int64 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Empty) Uint() uint {
|
func (e *empty) Uint() uint {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Empty) Uint64() uint64 {
|
func (e *empty) Uint64() uint64 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Empty) Float64() float64 {
|
func (e *empty) Float64() float64 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Empty) Bool() bool {
|
func (e *empty) Bool() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Empty) Duration() time.Duration {
|
func (e *empty) Duration() time.Duration {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Empty) Time() time.Time {
|
func (e *empty) Time() time.Time {
|
||||||
return time.Time{}
|
return time.Time{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Empty) Strings() []string {
|
func (e *empty) Strings() []string {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Empty) Ints() []int {
|
func (e *empty) Ints() []int {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Empty) Int64s() []int64 {
|
func (e *empty) Int64s() []int64 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Empty) Uints() []uint {
|
func (e *empty) Uints() []uint {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Empty) Uint64s() []uint64 {
|
func (e *empty) Uint64s() []uint64 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Empty) Float64s() []float64 {
|
func (e *empty) Float64s() []float64 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Empty) Bools() []bool {
|
func (e *empty) Bools() []bool {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Empty) Durations() []time.Duration {
|
func (e *empty) Durations() []time.Duration {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Empty) Times() []time.Time {
|
func (e *empty) Times() []time.Time {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Empty) Any() interface{} {
|
func (e *empty) Any() interface{} {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Float64 struct {
|
type Float64 struct {
|
||||||
Empty
|
empty
|
||||||
Val []float64
|
Val []float64
|
||||||
Flag flag.Flag
|
Flag flag.Flag
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Int struct {
|
type Int struct {
|
||||||
Empty
|
empty
|
||||||
Val []int
|
Val []int
|
||||||
Flag flag.Flag
|
Flag flag.Flag
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Int64 struct {
|
type Int64 struct {
|
||||||
Empty
|
empty
|
||||||
Val []int64
|
Val []int64
|
||||||
Flag flag.Flag
|
Flag flag.Flag
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ AppendValue = (*Read)(nil)
|
var _ Append = (*Read)(nil)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrAppendRead = errors.New("invalid append data to read value")
|
ErrAppendRead = errors.New("invalid append data to read value")
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package value
|
|||||||
import "gitoa.ru/go-4devs/console/input/flag"
|
import "gitoa.ru/go-4devs/console/input/flag"
|
||||||
|
|
||||||
type String struct {
|
type String struct {
|
||||||
Empty
|
empty
|
||||||
Val []string
|
Val []string
|
||||||
Flag flag.Flag
|
Flag flag.Flag
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Time struct {
|
type Time struct {
|
||||||
Empty
|
empty
|
||||||
Val []time.Time
|
Val []time.Time
|
||||||
Flag flag.Flag
|
Flag flag.Flag
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Uint struct {
|
type Uint struct {
|
||||||
Empty
|
empty
|
||||||
Val []uint
|
Val []uint
|
||||||
Flag flag.Flag
|
Flag flag.Flag
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Uint64 struct {
|
type Uint64 struct {
|
||||||
Empty
|
empty
|
||||||
Val []uint64
|
Val []uint64
|
||||||
Flag flag.Flag
|
Flag flag.Flag
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,13 +29,13 @@ type Value interface {
|
|||||||
Times() []time.Time
|
Times() []time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppendValue interface {
|
type Append interface {
|
||||||
Value
|
Value
|
||||||
Append(string) error
|
Append(string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint: gocyclo
|
//nolint: gocyclo
|
||||||
func New(v interface{}) Value {
|
func New(v interface{}) Append {
|
||||||
switch val := v.(type) {
|
switch val := v.(type) {
|
||||||
case string:
|
case string:
|
||||||
return &String{Val: []string{val}, Flag: flag.String}
|
return &String{Val: []string{val}, Flag: flag.String}
|
||||||
@@ -75,18 +75,20 @@ func New(v interface{}) Value {
|
|||||||
return &Int{Val: val, Flag: flag.Int | flag.Array}
|
return &Int{Val: val, Flag: flag.Int | flag.Array}
|
||||||
case []interface{}:
|
case []interface{}:
|
||||||
return &Any{Val: val, Flag: flag.Any | flag.Array}
|
return &Any{Val: val, Flag: flag.Any | flag.Array}
|
||||||
case Value:
|
case Append:
|
||||||
return val
|
return val
|
||||||
|
case Value:
|
||||||
|
return &Read{Value: val}
|
||||||
default:
|
default:
|
||||||
if v != nil {
|
if v != nil {
|
||||||
return &Any{Val: []interface{}{v}, Flag: flag.Any}
|
return &Any{Val: []interface{}{v}, Flag: flag.Any}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Empty{}
|
return &empty{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ByFlag(f flag.Flag) AppendValue {
|
func ByFlag(f flag.Flag) Append {
|
||||||
switch {
|
switch {
|
||||||
case f.IsInt():
|
case f.IsInt():
|
||||||
return &Int{Flag: f | flag.Int}
|
return &Int{Flag: f | flag.Int}
|
||||||
|
|||||||
36
input/wrap.go
Normal file
36
input/wrap.go
Normal file
@@ -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
|
|
||||||
}
|
|
||||||
22
output/formatter.go
Normal file
22
output/formatter.go
Normal file
@@ -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())
|
||||||
|
}
|
||||||
@@ -5,76 +5,70 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"gitoa.ru/go-4devs/console/output/verbosity"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Verbosity int
|
func writeError(_ int, err error) {
|
||||||
|
if err != nil {
|
||||||
const (
|
|
||||||
VerbosityQuiet Verbosity = iota - 1
|
|
||||||
VerbosityNorm
|
|
||||||
VerbosityInfo
|
|
||||||
VerbosityDebug
|
|
||||||
VerbosityTrace
|
|
||||||
)
|
|
||||||
|
|
||||||
func writeError(n int, err error) {
|
|
||||||
fmt.Fprint(os.Stderr, err)
|
fmt.Fprint(os.Stderr, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Output func(ctx context.Context, verb Verbosity, msg string, args ...KeyValue) (int, error)
|
type Output func(ctx context.Context, verb verbosity.Verbosity, msg string, args ...KeyValue) (int, error)
|
||||||
|
|
||||||
func (o Output) Print(ctx context.Context, args ...interface{}) {
|
func (o Output) Print(ctx context.Context, args ...interface{}) {
|
||||||
writeError(o(ctx, VerbosityNorm, fmt.Sprint(args...)))
|
writeError(o(ctx, verbosity.Norm, fmt.Sprint(args...)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o Output) PrintKV(ctx context.Context, msg string, kv ...KeyValue) {
|
func (o Output) PrintKV(ctx context.Context, msg string, kv ...KeyValue) {
|
||||||
writeError(o(ctx, VerbosityNorm, msg, kv...))
|
writeError(o(ctx, verbosity.Norm, msg, kv...))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o Output) Printf(ctx context.Context, format string, args ...interface{}) {
|
func (o Output) Printf(ctx context.Context, format string, args ...interface{}) {
|
||||||
writeError(o(ctx, VerbosityNorm, fmt.Sprintf(format, args...)))
|
writeError(o(ctx, verbosity.Norm, fmt.Sprintf(format, args...)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o Output) Println(ctx context.Context, args ...interface{}) {
|
func (o Output) Println(ctx context.Context, args ...interface{}) {
|
||||||
writeError(o(ctx, VerbosityNorm, fmt.Sprintln(args...)))
|
writeError(o(ctx, verbosity.Norm, fmt.Sprintln(args...)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o Output) Info(ctx context.Context, args ...interface{}) {
|
func (o Output) Info(ctx context.Context, args ...interface{}) {
|
||||||
writeError(o(ctx, VerbosityInfo, fmt.Sprint(args...)))
|
writeError(o(ctx, verbosity.Info, fmt.Sprint(args...)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o Output) InfoKV(ctx context.Context, msg string, kv ...KeyValue) {
|
func (o Output) InfoKV(ctx context.Context, msg string, kv ...KeyValue) {
|
||||||
writeError(o(ctx, VerbosityInfo, msg, kv...))
|
writeError(o(ctx, verbosity.Info, msg, kv...))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o Output) Debug(ctx context.Context, args ...interface{}) {
|
func (o Output) Debug(ctx context.Context, args ...interface{}) {
|
||||||
writeError(o(ctx, VerbosityDebug, fmt.Sprint(args...)))
|
writeError(o(ctx, verbosity.Debug, fmt.Sprint(args...)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o Output) DebugKV(ctx context.Context, msg string, kv ...KeyValue) {
|
func (o Output) DebugKV(ctx context.Context, msg string, kv ...KeyValue) {
|
||||||
writeError(o(ctx, VerbosityDebug, msg, kv...))
|
writeError(o(ctx, verbosity.Debug, msg, kv...))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o Output) Trace(ctx context.Context, args ...interface{}) {
|
func (o Output) Trace(ctx context.Context, args ...interface{}) {
|
||||||
writeError(o(ctx, VerbosityTrace, fmt.Sprint(args...)))
|
writeError(o(ctx, verbosity.Trace, fmt.Sprint(args...)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o Output) TraceKV(ctx context.Context, msg string, kv ...KeyValue) {
|
func (o Output) TraceKV(ctx context.Context, msg string, kv ...KeyValue) {
|
||||||
writeError(o(ctx, VerbosityTrace, msg, kv...))
|
writeError(o(ctx, verbosity.Trace, msg, kv...))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o Output) Write(b []byte) (int, error) {
|
func (o Output) Write(b []byte) (int, error) {
|
||||||
return o(context.Background(), VerbosityNorm, string(b))
|
return o(context.Background(), verbosity.Norm, string(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o Output) Writer(ctx context.Context, verb Verbosity) io.Writer {
|
func (o Output) Writer(ctx context.Context, verb verbosity.Verbosity) io.Writer {
|
||||||
return verbosityWriter{ctx, o, verb}
|
return verbosityWriter{ctx, o, verb}
|
||||||
}
|
}
|
||||||
|
|
||||||
type verbosityWriter struct {
|
type verbosityWriter struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
out Output
|
out Output
|
||||||
verb Verbosity
|
verb verbosity.Verbosity
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w verbosityWriter) Write(b []byte) (int, error) {
|
func (w verbosityWriter) Write(b []byte) (int, error) {
|
||||||
|
|||||||
13
output/quiet.go
Normal file
13
output/quiet.go
Normal file
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
17
output/verbosity.go
Normal file
17
output/verbosity.go
Normal file
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
13
output/verbosity/verbosity.go
Normal file
13
output/verbosity/verbosity.go
Normal file
@@ -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
|
||||||
|
)
|
||||||
28
output/verbosity/verbosity_string.go
Normal file
28
output/verbosity/verbosity_string.go
Normal file
@@ -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())
|
|
||||||
}
|
|
||||||
45
output/writer.go
Normal file
45
output/writer.go
Normal file
@@ -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...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package writer_test
|
package output_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -6,13 +6,12 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gitoa.ru/go-4devs/console/output"
|
"gitoa.ru/go-4devs/console/output"
|
||||||
"gitoa.ru/go-4devs/console/output/writer"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNew(t *testing.T) {
|
func TestNew(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
buf := bytes.Buffer{}
|
buf := bytes.Buffer{}
|
||||||
wr := writer.New(&buf, writer.String)
|
wr := output.New(&buf, output.FormatString)
|
||||||
|
|
||||||
cases := map[string]struct {
|
cases := map[string]struct {
|
||||||
ex string
|
ex string
|
||||||
Reference in New Issue
Block a user