6 Commits

Author SHA1 Message Date
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
65a754363f add config example (#3)
All checks were successful
continuous-integration/drone/push Build is passing
Co-authored-by: andrey1s <andrey@4devs.pro>
Reviewed-on: #3
Co-authored-by: andrey <andrey@4devs.io>
Co-committed-by: andrey <andrey@4devs.io>
2022-09-18 22:12:29 +03:00
ef4d5d126a Merge pull request 'add input config pkg' (#2) from config into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #2
2022-09-18 21:56:37 +03:00
andrey1s
4ddc526abf add input config pkg
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
continuous-integration/drone/pr Build is passing
2022-09-18 21:43:18 +03:00
4fdeb73e8a add value vithh error (#1)
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
Co-authored-by: andrey1s <andrey@4devs.pro>
Reviewed-on: #1
Co-authored-by: andrey <andrey@4devs.io>
Co-committed-by: andrey <andrey@4devs.io>
2022-09-18 21:37:25 +03:00
80 changed files with 3364 additions and 952 deletions

View File

@@ -3,7 +3,7 @@ name: default
steps: steps:
- name: golangci-lint - name: golangci-lint
image: golangci/golangci-lint:v1.26 image: golangci/golangci-lint:v1.49
volumes: volumes:
- name: deps - name: deps
path: /go/src/mod path: /go/src/mod
@@ -18,6 +18,24 @@ steps:
commands: commands:
- go test ./... - go test ./...
- name: example golangci-lint
image: golangci/golangci-lint:v1.49
volumes:
- name: deps
path: /go/src/mod
commands:
- cd example
- golangci-lint run --timeout 5m
- name: example test
image: golang
volumes:
- name: deps
path: /go/src/mod
commands:
- cd example
- go test ./...
volumes: volumes:
- name: deps - name: deps
temp: {} temp: {}

View File

@@ -16,6 +16,9 @@ linters-settings:
mnd: mnd:
# don't include the "operation" and "assign" # don't include the "operation" and "assign"
checks: argument,case,condition,return checks: argument,case,condition,return
ignored-functions:
- "strconv.*"
- "strings.*"
govet: govet:
check-shadowing: true check-shadowing: true
lll: lll:
@@ -24,9 +27,28 @@ linters-settings:
suggest-new: true suggest-new: true
misspell: misspell:
locale: US locale: US
varnamelen:
min-name-length: 2
staticcheck:
checks: ["all","-SA1030"]
linters: linters:
enable-all: true enable-all: true
disable:
- varcheck
- maligned
- scopelint
- nosnakecase
- ifshort
- golint
- interfacer
- structcheck
- deadcode
- exhaustivestruct
- ireturn
- exhaustruct
- gomoddirectives
issues: issues:
# Excluding configuration per-path, per-linter, per-text and per-source # Excluding configuration per-path, per-linter, per-text and per-source
@@ -34,3 +56,7 @@ issues:
- path: _test\.go - path: _test\.go
linters: linters:
- gomnd - gomnd
- varnamelen
- path: input/variable
linters:
- dupl

41
app.go
View File

@@ -25,9 +25,7 @@ func WithInput(in input.Input) func(*App) {
// WithSkipArgs sets how many arguments are passed. For example, you don't need to pass the name of a single command. // WithSkipArgs sets how many arguments are passed. For example, you don't need to pass the name of a single command.
func WithSkipArgs(l int) func(*App) { func WithSkipArgs(l int) func(*App) {
return func(a *App) { return WithInput(input.NewArgs(l))
a.skipArgv = l
}
} }
// WithExit sets exit callback by default os.Exit. // WithExit sets exit callback by default os.Exit.
@@ -39,44 +37,25 @@ 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{ app := &App{
out: output.Stdout(), out: output.Stdout(),
exit: os.Exit, exit: os.Exit,
in: input.NewArgs(0),
} }
for _, opt := range opts { for _, opt := range opts {
opt(a) opt(app)
} }
if a.in == nil { return app
skip := 2
switch {
case a.skipArgv > 0 && len(os.Args) > a.skipArgv:
skip = a.skipArgv
case a.skipArgv > 0:
skip = len(os.Args)
case len(os.Args) == 1:
skip = 1
case len(os.Args) > 1 && os.Args[1][0] == '-':
skip = 1
}
a.in = &input.Argv{
Args: os.Args[skip:],
}
}
return a
} }
// App is collection of command and configure env. // App is collection of command and configure env.
type App struct { type App struct {
cmds []*Command cmds []*Command
out output.Output out output.Output
in input.Input in input.Input
skipArgv int exit func(int)
exit func(int)
} }
// Add add or replace command. // Add add or replace command.
@@ -132,7 +111,7 @@ func (a *App) list(ctx context.Context) error {
} }
arr := &input.Array{} arr := &input.Array{}
arr.SetArgument("command_name", value.New(CommandList)) arr.SetArgument(ArgumentCommandName, value.New(CommandList))
in := input.Chain(arr, a.in) in := input.Chain(arr, a.in)
return Run(ctx, cmd, in, a.out) return Run(ctx, cmd, in, a.out)

View File

@@ -5,10 +5,9 @@ import (
"os" "os"
"gitoa.ru/go-4devs/console" "gitoa.ru/go-4devs/console"
"gitoa.ru/go-4devs/console/example/pkg/command"
) )
//nolint: lll //nolint:lll
func ExampleNew_help() { func ExampleNew_help() {
ctx := context.Background() ctx := context.Background()
os.Args = []string{ os.Args = []string{
@@ -56,9 +55,18 @@ func ExampleNew_list() {
console.New(console.WithExit(func(int) {})). console.New(console.WithExit(func(int) {})).
Add( Add(
Command(), Command(),
command.Hello(), &console.Command{
command.Args(), Name: "fdevs:console:arg",
command.Namespace(), Description: "Understanding how Console Arguments and Options Are Handled",
},
&console.Command{
Name: "fdevs:console:hello",
Description: "example hello command",
},
&console.Command{
Name: "app:start",
Description: "example command in other namespace",
},
). ).
Execute(ctx) Execute(ctx)
// Output: // Output:

View File

@@ -17,38 +17,38 @@ type (
) )
// WithPrepare append middleware for configuration command. // WithPrepare append middleware for configuration command.
func WithPrepare(p ...Prepare) Option { func WithPrepare(prepares ...Prepare) Option {
return func(c *Command) { return func(c *Command) {
if c.Prepare != nil { if c.Prepare != nil {
p = append([]Prepare{c.Prepare}, p...) prepares = append([]Prepare{c.Prepare}, prepares...)
} }
c.Prepare = ChainPrepare(p...) c.Prepare = ChainPrepare(prepares...)
} }
} }
// WithHandle append middleware for executed command. // WithHandle append middleware for executed command.
func WithHandle(h ...Handle) Option { func WithHandle(handles ...Handle) Option {
return func(c *Command) { return func(c *Command) {
if c.Handle != nil { if c.Handle != nil {
h = append([]Handle{c.Handle}, h...) handles = append([]Handle{c.Handle}, handles...)
} }
c.Handle = ChainHandle(h...) c.Handle = ChainHandle(handles...)
} }
} }
// WithHidden sets hidden command. // WithHidden sets hidden command.
func WithHidden(v bool) Option { func WithHidden(hidden bool) Option {
return func(c *Command) { return func(c *Command) {
c.Hidden = v c.Hidden = hidden
} }
} }
// WithName sets name command. // WithName sets name command.
func WithName(n string) Option { func WithName(name string) Option {
return func(c *Command) { return func(c *Command) {
c.Name = n c.Name = name
} }
} }
@@ -125,13 +125,13 @@ func (c *Command) Init(ctx context.Context, cfg *input.Definition) error {
// ChainPrepare creates middleware for configures command. // ChainPrepare creates middleware for configures command.
func ChainPrepare(prepare ...Prepare) Prepare { func ChainPrepare(prepare ...Prepare) Prepare {
n := len(prepare) num := len(prepare)
if n == 1 { if num == 1 {
return prepare[0] return prepare[0]
} }
if n > 1 { if num > 1 {
lastI := n - 1 lastI := num - 1
return func(ctx context.Context, def *input.Definition, next Configure) error { return func(ctx context.Context, def *input.Definition, next Configure) error {
var ( var (
@@ -161,13 +161,13 @@ func ChainPrepare(prepare ...Prepare) Prepare {
// ChainHandle creates middleware for executes command. // ChainHandle creates middleware for executes command.
func ChainHandle(handlers ...Handle) Handle { func ChainHandle(handlers ...Handle) Handle {
n := len(handlers) num := len(handlers)
if n == 1 { if num == 1 {
return handlers[0] return handlers[0]
} }
if n > 1 { if num > 1 {
lastI := n - 1 lastI := num - 1
return func(ctx context.Context, in input.Input, out output.Output, next Action) error { return func(ctx context.Context, in input.Input, out output.Output, next Action) error {
var ( var (

View File

@@ -8,17 +8,16 @@ import (
"time" "time"
"gitoa.ru/go-4devs/console" "gitoa.ru/go-4devs/console"
"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/option" "gitoa.ru/go-4devs/console/input/option"
"gitoa.ru/go-4devs/console/output" "gitoa.ru/go-4devs/console/output"
) )
//nolint: gochecknoinits //nolint:gochecknoinits
func init() { func init() {
console.MustRegister(Command().With(console.WithName("fdevs:console:test"))) console.MustRegister(Command().With(console.WithName("fdevs:console:test")))
console.MustRegister(command.Args()) console.MustRegister(Command().With(console.WithName("fdevs:console:arg")))
} }
func Command() *console.Command { func Command() *console.Command {
@@ -38,12 +37,13 @@ func Command() *console.Command {
Configure: func(ctx context.Context, def *input.Definition) error { Configure: func(ctx context.Context, def *input.Definition) error {
def. def.
SetArguments( SetArguments(
argument.New("test_argument", "test argument"), argument.String("test_argument", "test argument"),
). ).
SetOptions( SetOptions(
option.New("string", "array string", option.Array), option.String("string", "array string", option.Array),
option.Bool("bool", "test bool option"), option.Bool("bool", "test bool option"),
option.Duration("duration", "test duration with default", option.Default(time.Second)), option.Duration("duration", "test duration with default", option.Default(time.Second)),
option.Time("hidden", "hidden time", option.Default(time.Second), option.Hidden),
) )
return nil return nil
@@ -52,6 +52,8 @@ func Command() *console.Command {
} }
func TestChainPrepare(t *testing.T) { func TestChainPrepare(t *testing.T) {
t.Parallel()
var cnt int32 var cnt int32
ctx := context.Background() ctx := context.Background()
@@ -86,10 +88,14 @@ func TestChainPrepare(t *testing.T) {
} }
func TestChainHandle(t *testing.T) { func TestChainHandle(t *testing.T) {
t.Parallel()
var cnt int32 var cnt int32
ctx := context.Background() ctx := context.Background()
in := &input.Array{} in := &input.Array{
Map: input.Map{},
}
out := output.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 {

View File

@@ -18,6 +18,15 @@ const (
verboseInfo = 1 verboseInfo = 1
) )
const (
OptionHelp = "help"
OptionVersion = "version"
OptionAnsi = "ansi"
OptionNoAnsi = "no-ansi"
OptionQuiet = "quiet"
OptionVerbose = "verbose"
)
// Execute the current command with option. // Execute the current command with option.
func Execute(ctx context.Context, cmd *Command, opts ...func(*App)) { func Execute(ctx context.Context, cmd *Command, opts ...func(*App)) {
opts = append([]func(*App){WithSkipArgs(1)}, opts...) 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) out = verbose(ctx, in, out)
if in.Option(ctx, "version").Bool() { if in.Option(ctx, OptionVersion).Bool() {
version := cmd.Version version := cmd.Version
if version == "" { if version == "" {
version = "unknown" version = "unknown"
@@ -53,7 +62,7 @@ func Run(ctx context.Context, cmd *Command, in input.Input, out output.Output) e
return nil return nil
} }
if in.Option(ctx, "help").Bool() { if in.Option(ctx, OptionHelp).Bool() {
return showHelp(ctx, cmd, in, out) 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 { 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, OptionAnsi).Bool():
out = output.Ansi(out) out = output.Ansi(out)
case in.Option(ctx, "no-ansi").Bool(): case in.Option(ctx, OptionNoAnsi).Bool():
out = output.None(out) out = output.None(out)
case lookupEnv("NO_COLOR"): case lookupEnv("NO_COLOR"):
out = output.None(out) out = output.None(out)
@@ -83,17 +92,17 @@ 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, OptionQuiet).Bool():
out = output.Quiet() out = output.Quiet()
default: default:
v := in.Option(ctx, "verbose").Bools() verb := in.Option(ctx, OptionVerbose).Bools()
switch { switch {
case len(v) == verboseInfo: case len(verb) == verboseInfo:
out = output.Verbosity(out, verbosity.Info) out = output.Verbosity(out, verbosity.Info)
case len(v) == verboseDebug: case len(verb) == verboseDebug:
out = output.Verbosity(out, verbosity.Debug) out = output.Verbosity(out, verbosity.Debug)
case len(v) >= verboseTrace: case len(verb) >= verboseTrace:
out = output.Verbosity(out, verbosity.Trace) out = output.Verbosity(out, verbosity.Trace)
default: default:
out = output.Verbosity(out, verbosity.Norm) out = output.Verbosity(out, verbosity.Norm)
@@ -104,9 +113,9 @@ 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 {
a := &input.Array{} arr := &input.Array{}
a.SetArgument(HelpArgumentCommandName, value.New(cmd.Name)) arr.SetArgument(ArgumentCommandName, value.New(cmd.Name))
a.SetOption("help", value.New(false)) arr.SetOption(OptionHelp, 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 +126,7 @@ func showHelp(ctx context.Context, cmd *Command, in input.Input, out output.Outp
return err return err
} }
w := input.Chain(a, in) w := input.Chain(arr, in)
return Run(ctx, help, w, out) return Run(ctx, help, w, out)
} }
@@ -125,13 +134,13 @@ func showHelp(ctx context.Context, cmd *Command, in input.Input, out output.Outp
// Default options and argument command. // Default options and argument command.
func Default(d *input.Definition) *input.Definition { func Default(d *input.Definition) *input.Definition {
return d.SetOptions( return d.SetOptions(
option.Bool("no-ansi", "Disable ANSI output"), option.Bool(OptionNoAnsi, "Disable ANSI output"),
option.Bool("ansi", "Do not ask any interactive question"), option.Bool(OptionAnsi, "Do not ask any interactive question"),
option.Bool("version", "Display this application version", option.Short("V")), option.Bool(OptionVersion, "Display this application version", option.Short('V')),
option.Bool("help", "Display this help message", option.Short("h")), option.Bool(OptionHelp, "Display this help message", option.Short('h')),
option.Bool("verbose", option.Bool(OptionVerbose,
"Increase the verbosity of messages: -v for info output, -vv for debug and -vvv for trace", "Increase the verbosity of messages: -v for info output, -vv for debug and -vvv for trace",
option.Short("v"), option.Array), 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')),
) )
} }

45
doc.go
View File

@@ -2,29 +2,32 @@
// The Console package allows you to create command-line commands. // The Console package allows you to create command-line commands.
// Your console commands can be used for any recurring task, such as cronjobs, imports, or other batch jobs. // Your console commands can be used for any recurring task, such as cronjobs, imports, or other batch jobs.
// console application can be written as follows: // console application can be written as follows:
// //cmd/console/main.go //
// func main() { // //cmd/console/main.go
// console.New().Execute(context.Background()) // func main() {
// } // console.New().Execute(context.Background())
// }
//
// Then, you can register the commands using Add(): // Then, you can register the commands using Add():
// package main
// //
// import ( // package main
// "context"
// //
// "gitoa.ru/go-4devs/console" // import (
// "gitoa.ru/go-4devs/console/example/pkg/command" // "context"
// )
// //
// func main() { // "gitoa.ru/go-4devs/console"
// console. // "gitoa.ru/go-4devs/console/example/pkg/command"
// New(). // )
// Add( //
// command.Hello(), // func main() {
// command.Args(), // console.
// command.Hidden(), // New().
// command.Namespace(), // Add(
// ). // command.Hello(),
// Execute(context.Background()) // command.Args(),
// } // command.Hidden(),
// command.Namespace(),
// ).
// Execute(context.Background())
// }
package console package console

View File

@@ -0,0 +1,37 @@
package main
import (
"context"
"gitoa.ru/go-4devs/config"
"gitoa.ru/go-4devs/config/provider/env"
"gitoa.ru/go-4devs/console"
"gitoa.ru/go-4devs/console/example/pkg/command"
"gitoa.ru/go-4devs/console/input"
"gitoa.ru/go-4devs/console/input/cfg"
)
const (
Namespace = "fdevs"
AppName = "console"
)
// FDEVS_CONSOLE_CAT=env go run cmd/config/main.go fdevs:console:arg -b tmp.
func main() {
env := config.New(Namespace, AppName, []config.Provider{
env.New(),
})
console.
New(console.WithInput(
input.Chain(
input.NewArgs(0),
cfg.New(env.Value),
),
)).
Add(
command.Long(),
command.Args(),
).
Execute(context.Background())
}

13
example/go.mod Normal file
View File

@@ -0,0 +1,13 @@
module gitoa.ru/go-4devs/console/example
go 1.19
replace gitoa.ru/go-4devs/console => ../
replace gitoa.ru/go-4devs/console/input/cfg => ../input/cfg
require (
gitoa.ru/go-4devs/config v0.0.0-20210427173104-3ba6b4c71578
gitoa.ru/go-4devs/console v0.1.0
gitoa.ru/go-4devs/console/input/cfg v0.0.1
)

302
example/go.sum Normal file
View File

@@ -0,0 +1,302 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/go-metrics v0.3.0/go.mod h1:zXjbSimjXTd7vOpY8B0/2LpvNvDoXBuplAD+gJD3GYs=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aws/aws-sdk-go v1.25.37/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd/v22 v22.1.0 h1:kq/SbG2BCKLkDKkjQf5OWwKWUKj1lgs3lFI4PxnR5lg=
github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-ldap/ldap/v3 v3.1.3/go.mod h1:3rbOH3jRS2u6jg2rJnKAMLE/xQyCKIveG2Sa/Cohzb8=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-kms-wrapping/entropy v0.1.0/go.mod h1:d1g9WGtAunDNpek8jUIEJnBlbgKS1N2Q61QkHiZyR1g=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY=
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP3V9oNE4hmsM=
github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=
github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/vault/api v1.1.0 h1:QcxC7FuqEl0sZaIjcXB/kNEeBa0DH5z57qbWBvZwLC4=
github.com/hashicorp/vault/api v1.1.0/go.mod h1:R3Umvhlxi2TN7Ex2hzOowyeNb+SfbVWI973N+ctaFMk=
github.com/hashicorp/vault/sdk v0.1.14-0.20200519221838-e0cfd64bc267 h1:e1ok06zGrWJW91rzRroyl5nRNqraaBe4d5hiKcVZuHM=
github.com/hashicorp/vault/sdk v0.1.14-0.20200519221838-e0cfd64bc267/go.mod h1:WX57W2PwkrOPQ6rVQk+dy5/htHIaB4aBM70EwKThu10=
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.3.2 h1:mRS76wmkOn3KkKAyXDu42V+6ebnXWIztFSYGN7GeoRg=
github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.9.0/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/tidwall/gjson v1.7.5 h1:zmAN/xmX7OtpAkv4Ovfso60r/BiCi5IErCDYGNJu+uc=
github.com/tidwall/gjson v1.7.5/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk=
github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE=
github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.1.0 h1:K3hMW5epkdAVwibsQEfR/7Zj0Qgt4DxtNumTq/VloO8=
github.com/tidwall/pretty v1.1.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
gitoa.ru/go-4devs/config v0.0.0-20210427173104-3ba6b4c71578 h1:VecgkaFAv+eoGOfSbRrnH2pRHzZa9gF98x71jYuvqFo=
gitoa.ru/go-4devs/config v0.0.0-20210427173104-3ba6b4c71578/go.mod h1:gpSbYuLQRK2PXgA1AQc1Pwf56pAPpPlXbQ8fLg8vwPk=
go.etcd.io/etcd/api/v3 v3.5.0-alpha.0 h1:+e5nrluATIy3GP53znpkHMFzPTHGYyzvJGFCbuI6ZLc=
go.etcd.io/etcd/api/v3 v3.5.0-alpha.0/go.mod h1:mPcW6aZJukV6Aa81LSKpBjQXTWlXB5r74ymPoSWa3Sw=
go.etcd.io/etcd/client/v3 v3.5.0-alpha.0 h1:dr1EOILak2pu4Nf5XbRIOCNIBjcz6UmkQd7hHRXwxaM=
go.etcd.io/etcd/client/v3 v3.5.0-alpha.0/go.mod h1:wKt7jgDgf/OfKiYmCq5WFGxOFAkVMLxiiXgLDFhECr8=
go.etcd.io/etcd/pkg/v3 v3.5.0-alpha.0 h1:3yLUEC0nFCxw/RArImOyRUI4OAFbg4PFpBbAhSNzKNY=
go.etcd.io/etcd/pkg/v3 v3.5.0-alpha.0/go.mod h1:tV31atvwzcybuqejDoY3oaNRTtlD2l/Ot78Pc9w7DMY=
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM=
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 h1:iMGN4xG0cnqj3t+zOM8wUB0BiPKHEwSxEZCvzcbZuvk=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM=
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634 h1:bNEHhJCnrwMKNMmOx3yAynp5vs5/gRy+XWFtZFu7NBM=
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI=
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884 h1:fiNLklpBwWK1mth30Hlwk+fcdBmIALlgF5iy77O37Ig=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.32.0 h1:zWTV+LMdc3kaiJMSTOFz2UgSBgx8RNQoTGiZu3fR9S0=
google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w=
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=

View File

@@ -2,6 +2,7 @@ package command
import ( import (
"context" "context"
"time"
"gitoa.ru/go-4devs/console" "gitoa.ru/go-4devs/console"
"gitoa.ru/go-4devs/console/input" "gitoa.ru/go-4devs/console/input"
@@ -15,9 +16,10 @@ func Args() *console.Command {
Description: "Understanding how Console Arguments and Options Are Handled", Description: "Understanding how Console Arguments and Options Are Handled",
Configure: func(ctx context.Context, def *input.Definition) error { Configure: func(ctx context.Context, def *input.Definition) error {
def.SetOptions( def.SetOptions(
option.Bool("foo", "foo option", option.Short("f")), option.Bool("foo", "foo option", option.Short('f')),
option.New("bar", "required bar option", option.Required, option.Short("b")), option.String("bar", "required bar option", option.Required, option.Short('b')),
option.New("cat", "cat option", option.Short("c")), option.String("cat", "cat option", option.Short('c')),
option.Time("time", "time example"),
) )
return nil return nil
@@ -26,6 +28,7 @@ func Args() *console.Command {
out.Println(ctx, "foo: <info>", in.Option(ctx, "foo").Bool(), "</info>") out.Println(ctx, "foo: <info>", in.Option(ctx, "foo").Bool(), "</info>")
out.Println(ctx, "bar: <info>", in.Option(ctx, "bar").String(), "</info>") 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, "cat: <info>", in.Option(ctx, "cat").String(), "</info>")
out.Println(ctx, "time: <info>", in.Option(ctx, "time").Time().Format(time.RFC3339), "</info>")
return nil return nil
}, },

View File

@@ -6,6 +6,7 @@ import (
"gitoa.ru/go-4devs/console" "gitoa.ru/go-4devs/console"
"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/variable"
"gitoa.ru/go-4devs/console/output" "gitoa.ru/go-4devs/console/output"
) )
@@ -15,7 +16,7 @@ func CreateUser(required bool) *console.Command {
Description: "Creates a new user.", Description: "Creates a new user.",
Help: "This command allows you to create a user...", Help: "This command allows you to create a user...",
Configure: func(ctx context.Context, cfg *input.Definition) error { Configure: func(ctx context.Context, cfg *input.Definition) error {
var opts []func(*argument.Argument) var opts []variable.Option
if required { if required {
opts = append(opts, argument.Required) opts = append(opts, argument.Required)
} }

View File

@@ -12,6 +12,8 @@ import (
) )
func TestCreateUser(t *testing.T) { func TestCreateUser(t *testing.T) {
t.Parallel()
ctx := context.Background() ctx := context.Background()
buf := bytes.Buffer{} buf := bytes.Buffer{}
out := output.Buffer(&buf) out := output.Buffer(&buf)

View File

@@ -25,7 +25,7 @@ func Hello() *console.Command {
}, },
Configure: func(_ context.Context, def *input.Definition) error { Configure: func(_ context.Context, def *input.Definition) error {
def.SetArguments( def.SetArguments(
argument.New("name", "Same name", argument.Default("World")), argument.String("name", "Same name", argument.Default("World")),
) )
return nil return nil

View File

@@ -6,9 +6,9 @@ import (
"gitoa.ru/go-4devs/console" "gitoa.ru/go-4devs/console"
"gitoa.ru/go-4devs/console/input" "gitoa.ru/go-4devs/console/input"
"gitoa.ru/go-4devs/console/input/flag"
"gitoa.ru/go-4devs/console/input/option" "gitoa.ru/go-4devs/console/input/option"
"gitoa.ru/go-4devs/console/input/validator" "gitoa.ru/go-4devs/console/input/validator"
"gitoa.ru/go-4devs/console/input/value/flag"
"gitoa.ru/go-4devs/console/output" "gitoa.ru/go-4devs/console/output"
) )
@@ -41,7 +41,7 @@ func Long() *console.Command {
Configure: func(ctx context.Context, def *input.Definition) error { Configure: func(ctx context.Context, def *input.Definition) error {
def.SetOptions(option.Duration("timeout", "set duration run command", def.SetOptions(option.Duration("timeout", "set duration run command",
option.Default(defaultTimeout), option.Default(defaultTimeout),
option.Short("t"), option.Short('t'),
option.Valid(validator.NotBlank(flag.Duration)), option.Valid(validator.NotBlank(flag.Duration)),
)) ))

6
go.mod
View File

@@ -1,3 +1,9 @@
module gitoa.ru/go-4devs/console module gitoa.ru/go-4devs/console
go 1.15 go 1.15
require (
github.com/kr/pretty v0.1.0 // indirect
github.com/stretchr/testify v1.8.0
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
)

21
go.sum
View File

@@ -0,0 +1,21 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

31
help.go
View File

@@ -8,21 +8,22 @@ import (
"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/flag"
"gitoa.ru/go-4devs/console/input/option" "gitoa.ru/go-4devs/console/input/option"
"gitoa.ru/go-4devs/console/input/validator" "gitoa.ru/go-4devs/console/input/validator"
"gitoa.ru/go-4devs/console/input/value/flag" "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/descriptor" "gitoa.ru/go-4devs/console/output/descriptor"
) )
//nolint: gochecknoinits //nolint:gochecknoinits
func init() { func init() {
MustRegister(help()) MustRegister(help())
} }
const ( const (
HelpArgumentCommandName = "command_name" ArgumentCommandName = "command_name"
helpOptFormat = "format" OptionFormat = "format"
) )
func help() *Command { func help() *Command {
@@ -38,23 +39,23 @@ 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 { Execute: func(ctx context.Context, in input.Input, out output.Output) error {
var err error var err error
name := in.Argument(ctx, HelpArgumentCommandName).String() name := in.Argument(ctx, ArgumentCommandName).String()
format := in.Option(ctx, helpOptFormat).String() format := in.Option(ctx, OptionFormat).String()
des, err := descriptor.Find(format) des, err := descriptor.Find(format)
if err != nil { if err != nil {
return err return fmt.Errorf("find descriptor: %w", err)
} }
cmd, err := Find(name) cmd, err := Find(name)
if err != nil { if err != nil {
return err return fmt.Errorf("find cmd: %w", err)
} }
def := input.NewDefinition() def := input.NewDefinition()
if err := cmd.Init(ctx, Default(def)); err != nil { if err := cmd.Init(ctx, Default(def)); err != nil {
return err return fmt.Errorf("init cmd: %w", err)
} }
var bin string var bin string
@@ -62,22 +63,28 @@ To display the list of available commands, please use the <info>list</info> comm
bin = os.Args[0] bin = os.Args[0]
} }
return des.Command(ctx, out, descriptor.Command{ derr := des.Command(ctx, out, descriptor.Command{
Bin: bin, Bin: bin,
Name: cmd.Name, Name: cmd.Name,
Description: cmd.Description, Description: cmd.Description,
Help: cmd.Help, Help: cmd.Help,
Definition: def, Definition: def,
}) })
if derr != nil {
return fmt.Errorf("descriptor help:%w", derr)
}
return nil
}, },
Configure: func(ctx context.Context, config *input.Definition) error { Configure: func(ctx context.Context, config *input.Definition) error {
formats := descriptor.Descriptors() formats := descriptor.Descriptors()
config. config.
SetArguments( SetArguments(
argument.New(HelpArgumentCommandName, "The command name", argument.Default("help")), argument.String(ArgumentCommandName, "The command name", argument.Default(value.New("help"))),
). ).
SetOptions( SetOptions(
option.New(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.Required,
option.Default(formats[0]), option.Default(formats[0]),
option.Valid( option.Valid(

View File

@@ -1,54 +1,58 @@
package argument package argument
import ( import (
"gitoa.ru/go-4devs/console/input/errs"
"gitoa.ru/go-4devs/console/input/value" "gitoa.ru/go-4devs/console/input/value"
"gitoa.ru/go-4devs/console/input/value/flag" "gitoa.ru/go-4devs/console/input/variable"
) )
func New(name, description string, opts ...func(*Argument)) Argument { func Default(in interface{}) variable.Option {
a := Argument{ return variable.Default(value.New(in))
Name: name,
Description: description,
}
for _, opt := range opts {
opt(&a)
}
return a
} }
type Argument struct { func Required(v *variable.Variable) {
Name string variable.Required(v)
Description string
Default value.Value
Flag flag.Flag
Valid []func(value.Value) error
} }
func (a Argument) HasDefault() bool { func Array(v *variable.Variable) {
return a.Default != nil variable.Array(v)
} }
func (a Argument) IsBool() bool { func String(name, description string, opts ...variable.Option) variable.Variable {
return a.Flag.IsBool() return variable.String(name, description, append(opts, variable.ArgArgument)...)
} }
func (a Argument) IsRequired() bool { func Bool(name, description string, opts ...variable.Option) variable.Variable {
return a.Flag.IsRequired() return variable.Bool(name, description, append(opts, variable.ArgArgument)...)
} }
func (a Argument) IsArray() bool { func Duration(name, description string, opts ...variable.Option) variable.Variable {
return a.Flag.IsArray() return variable.Duration(name, description, append(opts, variable.ArgArgument)...)
} }
func (a Argument) Validate(v value.Value) error { func Float64(name, description string, opts ...variable.Option) variable.Variable {
for _, valid := range a.Valid { return variable.Float64(name, description, append(opts, variable.ArgArgument)...)
if err := valid(v); err != nil { }
return errs.Argument(a.Name, err)
} func Int(name, description string, opts ...variable.Option) variable.Variable {
} return variable.Int(name, description, append(opts, variable.ArgArgument)...)
}
return nil
func Int64(name, description string, opts ...variable.Option) variable.Variable {
return variable.Int64(name, description, append(opts, variable.ArgArgument)...)
}
func Time(name, description string, opts ...variable.Option) variable.Variable {
return variable.Time(name, description, append(opts, variable.ArgArgument)...)
}
func Uint(name, description string, opts ...variable.Option) variable.Variable {
return variable.Uint(name, description, append(opts, variable.ArgArgument)...)
}
func Uint64(name, descriontion string, opts ...variable.Option) variable.Variable {
return variable.Uint64(name, descriontion, append(opts, variable.ArgArgument)...)
}
func Err(name string, err error) variable.Error {
return variable.Err(name, variable.TypeArgument, err)
} }

View File

@@ -1,26 +0,0 @@
package argument
import (
"gitoa.ru/go-4devs/console/input/value"
"gitoa.ru/go-4devs/console/input/value/flag"
)
func Required(a *Argument) {
a.Flag |= flag.Required
}
func Default(v interface{}) func(*Argument) {
return func(a *Argument) {
a.Default = value.New(v)
}
}
func Flag(flag flag.Flag) func(*Argument) {
return func(a *Argument) {
a.Flag = flag
}
}
func Array(a *Argument) {
a.Flag |= flag.Array
}

View File

@@ -3,20 +3,41 @@ package input
import ( import (
"context" "context"
"fmt" "fmt"
"os"
"strings" "strings"
"gitoa.ru/go-4devs/console/input/argument"
"gitoa.ru/go-4devs/console/input/errs" "gitoa.ru/go-4devs/console/input/errs"
"gitoa.ru/go-4devs/console/input/option" "gitoa.ru/go-4devs/console/input/option"
"gitoa.ru/go-4devs/console/input/variable"
) )
const doubleDash = `--` const doubleDash = `--`
func NewArgs(skip int) *Argv {
res := 2
switch {
case skip > 0 && len(os.Args) > skip:
res = skip
case skip > 0:
res = len(os.Args)
case len(os.Args) == 1:
res = 1
case len(os.Args) > 1 && os.Args[1][0] == '-':
res = 1
}
return &Argv{Args: os.Args[res:]}
}
type Argv struct { type Argv struct {
Array Array
Args []string Args []string
ErrHandle func(error) error ErrHandle func(error) error
} }
//nolint:cyclop
func (i *Argv) Bind(ctx context.Context, def *Definition) error { func (i *Argv) Bind(ctx context.Context, def *Definition) error {
options := true options := true
@@ -64,13 +85,13 @@ func (i *Argv) parseLongOption(arg string, def *Definition) error {
opt, err := def.Option(name) opt, err := def.Option(name)
if err != nil { if err != nil {
return errs.Option(name, err) return option.Err(name, err)
} }
return i.appendOption(name, value, opt) return i.appendOption(name, value, opt)
} }
func (i *Argv) appendOption(name string, data *string, opt option.Option) error { func (i *Argv) appendOption(name string, data *string, opt variable.Variable) error {
if i.HasOption(name) && !opt.IsArray() { if i.HasOption(name) && !opt.IsArray() {
return fmt.Errorf("%w: got: array, expect: %s", errs.ErrUnexpectedType, opt.Flag.Type()) return fmt.Errorf("%w: got: array, expect: %s", errs.ErrUnexpectedType, opt.Flag.Type())
} }
@@ -86,11 +107,11 @@ func (i *Argv) appendOption(name string, data *string, opt option.Option) error
val = i.Args[0] val = i.Args[0]
i.Args = i.Args[1:] i.Args = i.Args[1:]
default: default:
return errs.Option(name, errs.ErrRequired) return option.Err(name, errs.ErrRequired)
} }
if err := i.AppendOption(opt.Flag, name, val); err != nil { if err := i.AppendOption(opt, val); err != nil {
return errs.Option(name, err) return option.Err(name, err)
} }
return nil return nil
@@ -131,8 +152,8 @@ func (i *Argv) parseArgument(arg string, def *Definition) error {
return err return err
} }
if err := i.AppendArgument(opt.Flag, opt.Name, arg); err != nil { if err := i.AppendArgument(opt, arg); err != nil {
return errs.Argument(opt.Name, err) return argument.Err(opt.Name, err)
} }
return nil return nil

View File

@@ -3,7 +3,9 @@ package input
import ( import (
"context" "context"
"gitoa.ru/go-4devs/console/input/argument"
"gitoa.ru/go-4devs/console/input/errs" "gitoa.ru/go-4devs/console/input/errs"
"gitoa.ru/go-4devs/console/input/option"
"gitoa.ru/go-4devs/console/input/value" "gitoa.ru/go-4devs/console/input/value"
) )
@@ -58,7 +60,7 @@ func (a *Array) bindOption(ctx context.Context, def *Definition) error {
continue continue
case opt.IsRequired(): case opt.IsRequired():
return errs.Option(name, errs.ErrRequired) return option.Err(name, errs.ErrRequired)
default: default:
continue continue
} }
@@ -70,7 +72,7 @@ func (a *Array) bindOption(ctx context.Context, def *Definition) error {
} }
if err := opt.Validate(v); err != nil { if err := opt.Validate(v); err != nil {
return errs.Option(name, err) return option.Err(name, err)
} }
} }
@@ -91,7 +93,7 @@ func (a *Array) bindArguments(ctx context.Context, def *Definition) error {
continue continue
case arg.IsRequired(): case arg.IsRequired():
return errs.Argument(name, errs.ErrRequired) return argument.Err(name, errs.ErrRequired)
default: default:
continue continue
} }
@@ -99,7 +101,7 @@ func (a *Array) bindArguments(ctx context.Context, def *Definition) error {
if v := a.Map.Argument(ctx, name); !value.IsEmpty(v) { if v := a.Map.Argument(ctx, name); !value.IsEmpty(v) {
if err := arg.Validate(v); err != nil { if err := arg.Validate(v); err != nil {
return errs.Argument(name, err) return argument.Err(name, err)
} }
} }
} }

10
input/cfg/go.mod Normal file
View File

@@ -0,0 +1,10 @@
module gitoa.ru/go-4devs/console/input/cfg
go 1.19
require (
gitoa.ru/go-4devs/config v0.0.0-20210427173104-3ba6b4c71578
gitoa.ru/go-4devs/console v0.1.0
)
replace gitoa.ru/go-4devs/console => ../../

302
input/cfg/go.sum Normal file
View File

@@ -0,0 +1,302 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/go-metrics v0.3.0/go.mod h1:zXjbSimjXTd7vOpY8B0/2LpvNvDoXBuplAD+gJD3GYs=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aws/aws-sdk-go v1.25.37/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd/v22 v22.1.0 h1:kq/SbG2BCKLkDKkjQf5OWwKWUKj1lgs3lFI4PxnR5lg=
github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-ldap/ldap/v3 v3.1.3/go.mod h1:3rbOH3jRS2u6jg2rJnKAMLE/xQyCKIveG2Sa/Cohzb8=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-kms-wrapping/entropy v0.1.0/go.mod h1:d1g9WGtAunDNpek8jUIEJnBlbgKS1N2Q61QkHiZyR1g=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY=
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP3V9oNE4hmsM=
github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=
github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/vault/api v1.1.0 h1:QcxC7FuqEl0sZaIjcXB/kNEeBa0DH5z57qbWBvZwLC4=
github.com/hashicorp/vault/api v1.1.0/go.mod h1:R3Umvhlxi2TN7Ex2hzOowyeNb+SfbVWI973N+ctaFMk=
github.com/hashicorp/vault/sdk v0.1.14-0.20200519221838-e0cfd64bc267 h1:e1ok06zGrWJW91rzRroyl5nRNqraaBe4d5hiKcVZuHM=
github.com/hashicorp/vault/sdk v0.1.14-0.20200519221838-e0cfd64bc267/go.mod h1:WX57W2PwkrOPQ6rVQk+dy5/htHIaB4aBM70EwKThu10=
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.3.2 h1:mRS76wmkOn3KkKAyXDu42V+6ebnXWIztFSYGN7GeoRg=
github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.9.0/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/tidwall/gjson v1.7.5 h1:zmAN/xmX7OtpAkv4Ovfso60r/BiCi5IErCDYGNJu+uc=
github.com/tidwall/gjson v1.7.5/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk=
github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE=
github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.1.0 h1:K3hMW5epkdAVwibsQEfR/7Zj0Qgt4DxtNumTq/VloO8=
github.com/tidwall/pretty v1.1.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
gitoa.ru/go-4devs/config v0.0.0-20210427173104-3ba6b4c71578 h1:VecgkaFAv+eoGOfSbRrnH2pRHzZa9gF98x71jYuvqFo=
gitoa.ru/go-4devs/config v0.0.0-20210427173104-3ba6b4c71578/go.mod h1:gpSbYuLQRK2PXgA1AQc1Pwf56pAPpPlXbQ8fLg8vwPk=
go.etcd.io/etcd/api/v3 v3.5.0-alpha.0 h1:+e5nrluATIy3GP53znpkHMFzPTHGYyzvJGFCbuI6ZLc=
go.etcd.io/etcd/api/v3 v3.5.0-alpha.0/go.mod h1:mPcW6aZJukV6Aa81LSKpBjQXTWlXB5r74ymPoSWa3Sw=
go.etcd.io/etcd/client/v3 v3.5.0-alpha.0 h1:dr1EOILak2pu4Nf5XbRIOCNIBjcz6UmkQd7hHRXwxaM=
go.etcd.io/etcd/client/v3 v3.5.0-alpha.0/go.mod h1:wKt7jgDgf/OfKiYmCq5WFGxOFAkVMLxiiXgLDFhECr8=
go.etcd.io/etcd/pkg/v3 v3.5.0-alpha.0 h1:3yLUEC0nFCxw/RArImOyRUI4OAFbg4PFpBbAhSNzKNY=
go.etcd.io/etcd/pkg/v3 v3.5.0-alpha.0/go.mod h1:tV31atvwzcybuqejDoY3oaNRTtlD2l/Ot78Pc9w7DMY=
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM=
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 h1:iMGN4xG0cnqj3t+zOM8wUB0BiPKHEwSxEZCvzcbZuvk=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM=
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634 h1:bNEHhJCnrwMKNMmOx3yAynp5vs5/gRy+XWFtZFu7NBM=
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI=
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884 h1:fiNLklpBwWK1mth30Hlwk+fcdBmIALlgF5iy77O37Ig=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.32.0 h1:zWTV+LMdc3kaiJMSTOFz2UgSBgx8RNQoTGiZu3fR9S0=
google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w=
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=

50
input/cfg/input.go Normal file
View File

@@ -0,0 +1,50 @@
package cfg
import (
"context"
"errors"
"gitoa.ru/go-4devs/config"
"gitoa.ru/go-4devs/console/input"
"gitoa.ru/go-4devs/console/input/value"
)
type Resolver func(ctx context.Context, name string) (config.Value, error)
func New(resolver func(ctx context.Context, name string) (config.Value, error)) *Input {
return &Input{
resolver: resolver,
}
}
type Input struct {
resolver Resolver
}
type Value struct {
config.Value
}
func (v Value) Any() interface{} {
var out interface{}
_ = v.Value.Unmarshal(&out)
return out
}
func (i *Input) Option(ctx context.Context, name string) value.Value {
val, err := i.resolver(ctx, name)
if errors.Is(err, config.ErrVariableNotFound) {
return value.Empty()
}
return value.Read{ParseValue: Value{Value: val}}
}
func (i *Input) Argument(ctx context.Context, name string) value.Value {
return value.Empty()
}
func (i *Input) Bind(ctx context.Context, def *input.Definition) error {
return nil
}

View File

@@ -2,6 +2,7 @@ package input
import ( import (
"context" "context"
"fmt"
"gitoa.ru/go-4devs/console/input/value" "gitoa.ru/go-4devs/console/input/value"
) )
@@ -35,7 +36,7 @@ func (c chain) Argument(ctx context.Context, name string) value.Value {
func (c chain) Bind(ctx context.Context, def *Definition) error { func (c chain) Bind(ctx context.Context, def *Definition) error {
for _, input := range c { for _, input := range c {
if err := input.Bind(ctx, def); err != nil { if err := input.Bind(ctx, def); err != nil {
return err return fmt.Errorf("%T:%w", input, err)
} }
} }

View File

@@ -4,20 +4,21 @@ 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/errs"
"gitoa.ru/go-4devs/console/input/option" "gitoa.ru/go-4devs/console/input/option"
"gitoa.ru/go-4devs/console/input/variable"
) )
func NewDefinition() *Definition { func NewDefinition() *Definition {
return &Definition{ return &Definition{
options: make(map[string]option.Option), options: make(map[string]variable.Variable),
args: make(map[string]argument.Argument), args: make(map[string]variable.Variable),
short: make(map[string]string), short: make(map[string]string),
} }
} }
type Definition struct { type Definition struct {
options map[string]option.Option options map[string]variable.Variable
posOpt []string posOpt []string
args map[string]argument.Argument args map[string]variable.Variable
posArgs []string posArgs []string
short map[string]string short map[string]string
} }
@@ -30,11 +31,11 @@ func (d *Definition) Arguments() []string {
return d.posArgs return d.posArgs
} }
func (d *Definition) SetOption(name, description string, opts ...func(*option.Option)) *Definition { func (d *Definition) SetOption(name, description string, opts ...variable.Option) *Definition {
return d.SetOptions(option.New(name, description, opts...)) return d.SetOptions(option.String(name, description, opts...))
} }
func (d *Definition) SetOptions(opts ...option.Option) *Definition { func (d *Definition) SetOptions(opts ...variable.Variable) *Definition {
for _, opt := range opts { for _, opt := range opts {
if _, has := d.options[opt.Name]; !has { if _, has := d.options[opt.Name]; !has {
d.posOpt = append([]string{opt.Name}, d.posOpt...) d.posOpt = append([]string{opt.Name}, d.posOpt...)
@@ -42,18 +43,18 @@ func (d *Definition) SetOptions(opts ...option.Option) *Definition {
d.options[opt.Name] = opt d.options[opt.Name] = opt
if opt.HasShort() { if opt.HasShort() {
d.short[opt.Short] = opt.Name d.short[opt.Alias] = opt.Name
} }
} }
return d return d
} }
func (d *Definition) SetArgument(name, description string, opts ...func(*argument.Argument)) *Definition { func (d *Definition) SetArgument(name, description string, opts ...variable.Option) *Definition {
return d.SetArguments(argument.New(name, description, opts...)) return d.SetArguments(argument.String(name, description, opts...))
} }
func (d *Definition) SetArguments(args ...argument.Argument) *Definition { func (d *Definition) SetArguments(args ...variable.Variable) *Definition {
for _, arg := range args { for _, arg := range args {
if _, ok := d.args[arg.Name]; !ok { if _, ok := d.args[arg.Name]; !ok {
d.posArgs = append(d.posArgs, arg.Name) d.posArgs = append(d.posArgs, arg.Name)
@@ -65,9 +66,9 @@ func (d *Definition) SetArguments(args ...argument.Argument) *Definition {
return d return d
} }
func (d *Definition) Argument(pos int) (argument.Argument, error) { func (d *Definition) Argument(pos int) (variable.Variable, error) {
if len(d.posArgs) == 0 { if len(d.posArgs) == 0 {
return argument.Argument{}, errs.ErrNoArgs return variable.Variable{}, errs.ErrNoArgs
} }
lastPos := len(d.posArgs) - 1 lastPos := len(d.posArgs) - 1
@@ -77,25 +78,25 @@ func (d *Definition) Argument(pos int) (argument.Argument, error) {
return arg, nil return arg, nil
} }
return argument.Argument{}, errs.ErrToManyArgs return variable.Variable{}, errs.ErrToManyArgs
} }
return d.args[d.posArgs[pos]], nil return d.args[d.posArgs[pos]], nil
} }
func (d *Definition) ShortOption(short string) (option.Option, error) { func (d *Definition) ShortOption(short string) (variable.Variable, error) {
name, ok := d.short[short] name, ok := d.short[short]
if !ok { if !ok {
return option.Option{}, errs.ErrNotFound return variable.Variable{}, errs.ErrNotFound
} }
return d.Option(name) return d.Option(name)
} }
func (d *Definition) Option(name string) (option.Option, error) { func (d *Definition) Option(name string) (variable.Variable, error) {
if opt, ok := d.options[name]; ok { if opt, ok := d.options[name]; ok {
return opt, nil return opt, nil
} }
return option.Option{}, errs.ErrNotFound return variable.Variable{}, errs.ErrNotFound
} }

View File

@@ -2,7 +2,6 @@ package errs
import ( import (
"errors" "errors"
"fmt"
) )
var ( var (
@@ -13,46 +12,5 @@ var (
ErrRequired = errors.New("is required") ErrRequired = errors.New("is required")
ErrAppend = errors.New("failed append") ErrAppend = errors.New("failed append")
ErrInvalidName = errors.New("invalid name") ErrInvalidName = errors.New("invalid name")
ErrWrongType = errors.New("wrong type")
) )
func New(name, t string, err error) Error {
return Error{
name: name,
t: t,
err: err,
}
}
type Error struct {
name string
err error
t string
}
func (o Error) Error() string {
return fmt.Sprintf("%s: '%s' %s", o.t, o.name, o.err)
}
func (o Error) Is(err error) bool {
return errors.Is(err, o.err)
}
func (o Error) Unwrap() error {
return o.err
}
func Option(name string, err error) Error {
return Error{
name: name,
err: err,
t: "option",
}
}
func Argument(name string, err error) Error {
return Error{
name: name,
err: err,
t: "argument",
}
}

View File

@@ -71,6 +71,7 @@ func (i Flag) IsAny() bool {
return i&Any > 0 return i&Any > 0
} }
//nolint:cyclop
func (i Flag) Type() Flag { func (i Flag) Type() Flag {
switch { switch {
case i.IsInt(): case i.IsInt():

View File

@@ -2,15 +2,16 @@ package input
import ( import (
"context" "context"
"fmt"
"sync" "sync"
"gitoa.ru/go-4devs/console/input/value" "gitoa.ru/go-4devs/console/input/value"
"gitoa.ru/go-4devs/console/input/value/flag" "gitoa.ru/go-4devs/console/input/variable"
) )
type Map struct { type Map struct {
opts map[string]value.Append opts map[string]value.Value
args map[string]value.Append args map[string]value.Value
sync.Mutex sync.Mutex
} }
@@ -42,15 +43,15 @@ func (m *Map) HasOption(name string) bool {
return ok return ok
} }
func (m *Map) SetOption(name string, v interface{}) { func (m *Map) SetOption(name string, val interface{}) {
m.Lock() m.Lock()
defer m.Unlock() defer m.Unlock()
if m.opts == nil { if m.opts == nil {
m.opts = make(map[string]value.Append) m.opts = make(map[string]value.Value)
} }
m.opts[name] = value.New(v) m.opts[name] = value.New(val)
} }
func (m *Map) HasArgument(name string) bool { func (m *Map) HasArgument(name string) bool {
@@ -59,29 +60,59 @@ func (m *Map) HasArgument(name string) bool {
return ok return ok
} }
func (m *Map) SetArgument(name string, v interface{}) { func (m *Map) SetArgument(name string, val interface{}) {
m.Lock() m.Lock()
defer m.Unlock() defer m.Unlock()
if m.args == nil { if m.args == nil {
m.args = make(map[string]value.Append) m.args = make(map[string]value.Value)
} }
m.args[name] = value.New(v) m.args[name] = value.New(val)
} }
func (m *Map) AppendOption(f flag.Flag, name, val string) error { func (m *Map) AppendOption(opt variable.Variable, val string) error {
if _, ok := m.opts[name]; !ok { old, ok := m.opts[opt.Name]
m.SetOption(name, value.ByFlag(f)) if !ok {
value, err := opt.Create(val)
if err != nil {
return fmt.Errorf("append option:%w", err)
}
m.SetOption(opt.Name, value)
return nil
} }
return m.opts[name].Append(val) value, err := opt.Append(old, val)
} if err != nil {
return fmt.Errorf("append option:%w", err)
func (m *Map) AppendArgument(f flag.Flag, name, val string) error {
if _, ok := m.args[name]; !ok {
m.SetArgument(name, value.ByFlag(f))
} }
return m.args[name].Append(val) m.SetOption(opt.Name, value)
return nil
}
func (m *Map) AppendArgument(arg variable.Variable, val string) error {
old, ok := m.args[arg.Name]
if !ok {
value, err := arg.Create(val)
if err != nil {
return fmt.Errorf("append option:%w", err)
}
m.SetArgument(arg.Name, value)
return nil
}
value, err := arg.Append(old, val)
if err != nil {
return fmt.Errorf("append option:%w", err)
}
m.SetArgument(arg.Name, value)
return nil
} }

View File

@@ -1,37 +0,0 @@
package option
import (
"gitoa.ru/go-4devs/console/input/value/flag"
)
func Bool(name, description string, opts ...func(*Option)) Option {
return New(name, description, append(opts, Value(flag.Bool))...)
}
func Duration(name, description string, opts ...func(*Option)) Option {
return New(name, description, append(opts, Value(flag.Duration))...)
}
func Float64(name, description string, opts ...func(*Option)) Option {
return New(name, description, append(opts, Value(flag.Float64))...)
}
func Int(name, description string, opts ...func(*Option)) Option {
return New(name, description, append(opts, Value(flag.Int))...)
}
func Int64(name, description string, opts ...func(*Option)) Option {
return New(name, description, append(opts, Value(flag.Int64))...)
}
func Time(name, description string, opts ...func(*Option)) Option {
return New(name, description, append(opts, Value(flag.Time))...)
}
func Uint(name, description string, opts ...func(*Option)) Option {
return New(name, description, append(opts, Value(flag.Uint))...)
}
func Uint64(name, descriontion string, opts ...func(*Option)) Option {
return New(name, descriontion, append(opts, Value(flag.Uint64))...)
}

View File

@@ -1,97 +1,72 @@
package option package option
import ( import (
"gitoa.ru/go-4devs/console/input/errs"
"gitoa.ru/go-4devs/console/input/value" "gitoa.ru/go-4devs/console/input/value"
"gitoa.ru/go-4devs/console/input/value/flag" "gitoa.ru/go-4devs/console/input/variable"
) )
func Required(o *Option) { func Short(in rune) variable.Option {
o.Flag |= flag.Required return func(v *variable.Variable) {
} v.Alias = string(in)
func Default(in interface{}) func(*Option) {
return func(o *Option) {
o.Default = value.New(in)
} }
} }
func Short(s string) func(*Option) { func Default(in interface{}) variable.Option {
return func(o *Option) { return variable.Default(value.New(in))
o.Short = s
}
} }
func Array(o *Option) { func Hidden(in *variable.Variable) {
o.Flag |= flag.Array variable.Hidden(in)
} }
func Value(flag flag.Flag) func(*Option) { func Required(v *variable.Variable) {
return func(o *Option) { variable.Required(v)
o.Flag |= flag
}
} }
func Flag(in flag.Flag) func(*Option) { func Valid(f ...func(value.Value) error) variable.Option {
return func(o *Option) { return variable.Valid(f...)
o.Flag = in
}
} }
func Valid(f ...func(value.Value) error) func(*Option) { func Array(v *variable.Variable) {
return func(o *Option) { variable.Array(v)
o.Valid = f
}
} }
func New(name, description string, opts ...func(*Option)) Option { func String(name, description string, opts ...variable.Option) variable.Variable {
o := Option{ return variable.String(name, description, append(opts, variable.ArgOption)...)
Name: name,
Description: description,
}
for _, opt := range opts {
opt(&o)
}
return o
} }
type Option struct { func Bool(name, description string, opts ...variable.Option) variable.Variable {
Name string return variable.Bool(name, description, append(opts, variable.ArgOption)...)
Description string
Short string
Flag flag.Flag
Default value.Value
Valid []func(value.Value) error
} }
func (o Option) HasShort() bool { func Duration(name, description string, opts ...variable.Option) variable.Variable {
return len(o.Short) == 1 return variable.Duration(name, description, append(opts, variable.ArgOption)...)
} }
func (o Option) HasDefault() bool { func Float64(name, description string, opts ...variable.Option) variable.Variable {
return o.Default != nil return variable.Float64(name, description, append(opts, variable.ArgOption)...)
} }
func (o Option) IsBool() bool { func Int(name, description string, opts ...variable.Option) variable.Variable {
return o.Flag.IsBool() return variable.Int(name, description, append(opts, variable.ArgOption)...)
} }
func (o Option) IsArray() bool { func Int64(name, description string, opts ...variable.Option) variable.Variable {
return o.Flag.IsArray() return variable.Int64(name, description, append(opts, variable.ArgOption)...)
} }
func (o Option) IsRequired() bool { func Time(name, description string, opts ...variable.Option) variable.Variable {
return o.Flag.IsRequired() return variable.Time(name, description, append(opts, variable.ArgOption)...)
} }
func (o Option) Validate(v value.Value) error { func Uint(name, description string, opts ...variable.Option) variable.Variable {
for _, valid := range o.Valid { return variable.Uint(name, description, append(opts, variable.ArgOption)...)
if err := valid(v); err != nil { }
return errs.Option(o.Name, err)
} func Uint64(name, descriontion string, opts ...variable.Option) variable.Variable {
} return variable.Uint64(name, descriontion, append(opts, variable.ArgOption)...)
}
return nil
func Err(name string, err error) variable.Error {
return variable.Err(name, variable.TypeOption, err)
} }

View File

@@ -4,13 +4,13 @@ import "gitoa.ru/go-4devs/console/input/value"
func Enum(enum ...string) func(value.Value) error { func Enum(enum ...string) func(value.Value) error {
return func(in value.Value) error { return func(in value.Value) error {
v := in.String() val := in.String()
for _, e := range enum { for _, e := range enum {
if e == v { if e == val {
return nil return nil
} }
} }
return NewError(ErrInvalid, v, enum) return NewError(ErrInvalid, val, enum)
} }
} }

View File

@@ -9,6 +9,8 @@ import (
) )
func TestEnum(t *testing.T) { func TestEnum(t *testing.T) {
t.Parallel()
validValue := value.New("valid") validValue := value.New("valid")
invalidValue := value.New("invalid") invalidValue := value.New("invalid")

View File

@@ -1,33 +1,33 @@
package validator package validator
import ( import (
"gitoa.ru/go-4devs/console/input/flag"
"gitoa.ru/go-4devs/console/input/value" "gitoa.ru/go-4devs/console/input/value"
"gitoa.ru/go-4devs/console/input/value/flag"
) )
//nolint: gocyclo //nolint:gocyclo,cyclop
func NotBlank(f flag.Flag) func(value.Value) error { func NotBlank(fl flag.Flag) func(value.Value) error {
return func(in value.Value) error { return func(in value.Value) error {
switch { switch {
case f.IsAny() && in.Any() != nil: case fl.IsAny() && in.Any() != nil:
return nil return nil
case f.IsArray(): case fl.IsArray():
return arrayNotBlank(f, in) return arrayNotBlank(fl, in)
case f.IsInt() && in.Int() != 0: case fl.IsInt() && in.Int() != 0:
return nil return nil
case f.IsInt64() && in.Int64() != 0: case fl.IsInt64() && in.Int64() != 0:
return nil return nil
case f.IsUint() && in.Uint() != 0: case fl.IsUint() && in.Uint() != 0:
return nil return nil
case f.IsUint64() && in.Uint64() != 0: case fl.IsUint64() && in.Uint64() != 0:
return nil return nil
case f.IsFloat64() && in.Float64() != 0: case fl.IsFloat64() && in.Float64() != 0:
return nil return nil
case f.IsDuration() && in.Duration() != 0: case fl.IsDuration() && in.Duration() != 0:
return nil return nil
case f.IsTime() && !in.Time().IsZero(): case fl.IsTime() && !in.Time().IsZero():
return nil return nil
case f.IsString() && len(in.String()) > 0: case fl.IsString() && len(in.String()) > 0:
return nil return nil
} }
@@ -35,10 +35,10 @@ func NotBlank(f flag.Flag) func(value.Value) error {
} }
} }
//nolint: gocyclo,gocognit //nolint:gocyclo,gocognit,cyclop
func arrayNotBlank(f flag.Flag, in value.Value) error { func arrayNotBlank(fl flag.Flag, in value.Value) error {
switch { switch {
case f.IsInt() && len(in.Ints()) > 0: case fl.IsInt() && len(in.Ints()) > 0:
for _, i := range in.Ints() { for _, i := range in.Ints() {
if i == 0 { if i == 0 {
return ErrNotBlank return ErrNotBlank
@@ -46,7 +46,7 @@ func arrayNotBlank(f flag.Flag, in value.Value) error {
} }
return nil return nil
case f.IsInt64() && len(in.Int64s()) > 0: case fl.IsInt64() && len(in.Int64s()) > 0:
for _, i := range in.Int64s() { for _, i := range in.Int64s() {
if i == 0 { if i == 0 {
return ErrNotBlank return ErrNotBlank
@@ -54,7 +54,7 @@ func arrayNotBlank(f flag.Flag, in value.Value) error {
} }
return nil return nil
case f.IsUint() && len(in.Uints()) > 0: case fl.IsUint() && len(in.Uints()) > 0:
for _, u := range in.Uints() { for _, u := range in.Uints() {
if u == 0 { if u == 0 {
return ErrNotBlank return ErrNotBlank
@@ -62,7 +62,7 @@ func arrayNotBlank(f flag.Flag, in value.Value) error {
} }
return nil return nil
case f.IsUint64() && len(in.Uint64s()) > 0: case fl.IsUint64() && len(in.Uint64s()) > 0:
for _, u := range in.Uint64s() { for _, u := range in.Uint64s() {
if u == 0 { if u == 0 {
return ErrNotBlank return ErrNotBlank
@@ -70,7 +70,7 @@ func arrayNotBlank(f flag.Flag, in value.Value) error {
} }
return nil return nil
case f.IsFloat64() && len(in.Float64s()) > 0: case fl.IsFloat64() && len(in.Float64s()) > 0:
for _, f := range in.Float64s() { for _, f := range in.Float64s() {
if f == 0 { if f == 0 {
return ErrNotBlank return ErrNotBlank
@@ -78,9 +78,9 @@ func arrayNotBlank(f flag.Flag, in value.Value) error {
} }
return nil return nil
case f.IsBool() && len(in.Bools()) > 0: case fl.IsBool() && len(in.Bools()) > 0:
return nil return nil
case f.IsDuration() && len(in.Durations()) > 0: case fl.IsDuration() && len(in.Durations()) > 0:
for _, d := range in.Durations() { for _, d := range in.Durations() {
if d == 0 { if d == 0 {
return ErrNotBlank return ErrNotBlank
@@ -88,7 +88,7 @@ func arrayNotBlank(f flag.Flag, in value.Value) error {
} }
return nil return nil
case f.IsTime() && len(in.Times()) > 0: case fl.IsTime() && len(in.Times()) > 0:
for _, t := range in.Times() { for _, t := range in.Times() {
if t.IsZero() { if t.IsZero() {
return ErrNotBlank return ErrNotBlank
@@ -96,7 +96,7 @@ func arrayNotBlank(f flag.Flag, in value.Value) error {
} }
return nil return nil
case f.IsString() && len(in.Strings()) > 0: case fl.IsString() && len(in.Strings()) > 0:
for _, st := range in.Strings() { for _, st := range in.Strings() {
if len(st) == 0 { if len(st) == 0 {
return ErrNotBlank return ErrNotBlank

View File

@@ -5,12 +5,14 @@ import (
"testing" "testing"
"time" "time"
"gitoa.ru/go-4devs/console/input/flag"
"gitoa.ru/go-4devs/console/input/validator" "gitoa.ru/go-4devs/console/input/validator"
"gitoa.ru/go-4devs/console/input/value" "gitoa.ru/go-4devs/console/input/value"
"gitoa.ru/go-4devs/console/input/value/flag"
) )
func TestNotBlank(t *testing.T) { func TestNotBlank(t *testing.T) {
t.Parallel()
cases := map[string]struct { cases := map[string]struct {
flag flag.Flag flag flag.Flag
value value.Value value value.Value
@@ -103,7 +105,7 @@ func TestNotBlank(t *testing.T) {
} }
if err := valid(ca.empty); err == nil || !errors.Is(err, validator.ErrNotBlank) { if err := valid(ca.empty); err == nil || !errors.Is(err, validator.ErrNotBlank) {
t.Errorf("case: %s, expect: %s, got:%s", name, validator.ErrNotBlank, err) t.Errorf("case empty: %s, expect: %s, got:%s", name, validator.ErrNotBlank, err)
} }
} }
} }

View File

@@ -4,12 +4,14 @@ import (
"errors" "errors"
"testing" "testing"
"gitoa.ru/go-4devs/console/input/flag"
"gitoa.ru/go-4devs/console/input/validator" "gitoa.ru/go-4devs/console/input/validator"
"gitoa.ru/go-4devs/console/input/value" "gitoa.ru/go-4devs/console/input/value"
"gitoa.ru/go-4devs/console/input/value/flag"
) )
func TestValid(t *testing.T) { func TestValid(t *testing.T) {
t.Parallel()
validValue := value.New("one") validValue := value.New("one")
invalidValue := value.New([]string{"one"}) invalidValue := value.New([]string{"one"})

View File

@@ -1,21 +1,137 @@
package value package value
import "gitoa.ru/go-4devs/console/input/value/flag" import (
"encoding/json"
"fmt"
"time"
)
type Any struct { var _ Value = NewAny(nil)
empty
Val []interface{} //nolint:gochecknoglobals
Flag flag.Flag var (
emptyValue = NewAny(nil)
)
func Empty() Value {
return emptyValue
} }
func (a *Any) Any() interface{} { func IsEmpty(v Value) bool {
if a.Flag.IsArray() { return v == nil || v == emptyValue
return a.Val }
func NewAny(in interface{}) Value {
return Read{Any{v: in}}
}
type Any struct {
v interface{}
}
func (a Any) Any() interface{} {
return a.v
}
func (a Any) Unmarshal(val interface{}) error {
out, err := a.ParseString()
if err != nil {
return fmt.Errorf("any parse string:%w", err)
} }
if len(a.Val) > 0 { uerr := json.Unmarshal([]byte(out), val)
return a.Val[0] if uerr != nil {
return fmt.Errorf("any unmarshal: %w", uerr)
} }
return nil return nil
} }
func (a Any) ParseString() (string, error) {
if a.v == nil {
return "", nil
}
bout, err := json.Marshal(a.v)
if err != nil {
return "", fmt.Errorf("any string:%w", err)
}
return string(bout), err
}
func (a Any) ParseInt() (int, error) {
out, ok := a.v.(int)
if !ok {
return 0, a.wrongType("int")
}
return out, nil
}
func (a Any) ParseInt64() (int64, error) {
out, ok := a.v.(int64)
if !ok {
return 0, a.wrongType("int64")
}
return out, nil
}
func (a Any) ParseUint() (uint, error) {
out, ok := a.v.(uint)
if !ok {
return 0, a.wrongType("uint")
}
return out, nil
}
func (a Any) ParseUint64() (uint64, error) {
out, ok := a.v.(uint64)
if !ok {
return 0, a.wrongType("uint64")
}
return out, nil
}
func (a Any) ParseFloat64() (float64, error) {
out, ok := a.v.(float64)
if !ok {
return 0, a.wrongType("float64")
}
return out, nil
}
func (a Any) ParseBool() (bool, error) {
out, ok := a.v.(bool)
if !ok {
return false, a.wrongType("bool")
}
return out, nil
}
func (a Any) ParseDuration() (time.Duration, error) {
out, ok := a.v.(time.Duration)
if !ok {
return 0, a.wrongType("time.Duration")
}
return out, nil
}
func (a Any) ParseTime() (time.Time, error) {
out, ok := a.v.(time.Time)
if !ok {
return time.Time{}, a.wrongType("time.Time")
}
return out, nil
}
func (a Any) wrongType(ex String) error {
return fmt.Errorf("%w any: got: %T expect: %s", ErrWrongType, a.v, ex)
}

View File

@@ -1,44 +1,148 @@
package value package value
import ( import (
"strconv" "fmt"
"time"
"gitoa.ru/go-4devs/console/input/value/flag"
) )
type Bool struct { var (
empty _ ParseValue = Bool(false)
Val []bool _ SliceValue = Bools{}
Flag flag.Flag )
func NewBools(in []bool) Slice {
return Slice{SliceValue: Bools(in)}
} }
func (b *Bool) Append(in string) error { type Bools []bool
v, err := strconv.ParseBool(in)
if err != nil { func (b Bools) Any() interface{} {
return err return b.Bools()
}
func (b Bools) Unmarshal(val interface{}) error {
v, ok := val.(*[]bool)
if !ok {
return fmt.Errorf("%w: expect: *[]bool got: %T", ErrWrongType, val)
} }
b.Val = append(b.Val, v) *v = b
return nil return nil
} }
func (b *Bool) Bool() bool { func (b Bools) Strings() []string {
if !b.Flag.IsArray() && len(b.Val) == 1 { return nil
return b.Val[0] }
func (b Bools) Ints() []int {
return nil
}
func (b Bools) Int64s() []int64 {
return nil
}
func (b Bools) Uints() []uint {
return nil
}
func (b Bools) Uint64s() []uint64 {
return nil
}
func (b Bools) Float64s() []float64 {
return nil
}
func (b Bools) Bools() []bool {
out := make([]bool, len(b))
copy(out, b)
return out
}
func (b Bools) Durations() []time.Duration {
return nil
}
func (b Bools) Times() []time.Time {
return nil
}
func NewBool(in bool) Read {
return Read{ParseValue: Bool(in)}
}
type Bool bool
func (b Bool) Unmarshal(val interface{}) error {
v, ok := val.(*bool)
if !ok {
return fmt.Errorf("%w: expect: *bool got: %T", ErrWrongType, val)
} }
return false *v = bool(b)
return nil
} }
func (b *Bool) Bools() []bool { func (b Bool) ParseString() (string, error) {
return b.Val return fmt.Sprintf("%v", b), nil
} }
func (b *Bool) Any() interface{} { func (b Bool) ParseInt() (int, error) {
if b.Flag.IsArray() { if b {
return b.Bools() return 1, nil
} }
return b.Bool() return 0, nil
}
func (b Bool) ParseInt64() (int64, error) {
if b {
return 1, nil
}
return 0, nil
}
func (b Bool) ParseUint() (uint, error) {
if b {
return 1, nil
}
return 0, nil
}
func (b Bool) ParseUint64() (uint64, error) {
if b {
return 1, nil
}
return 0, nil
}
func (b Bool) ParseFloat64() (float64, error) {
if b {
return 1, nil
}
return 0, nil
}
func (b Bool) ParseBool() (bool, error) {
return bool(b), nil
}
func (b Bool) ParseDuration() (time.Duration, error) {
return 0, fmt.Errorf("bool to duration:%w", ErrWrongType)
}
func (b Bool) ParseTime() (time.Time, error) {
return time.Time{}, fmt.Errorf("bool to time:%w", ErrWrongType)
}
func (b Bool) Any() interface{} {
return bool(b)
} }

View File

@@ -1,44 +1,128 @@
package value package value
import ( import (
"fmt"
"time" "time"
"gitoa.ru/go-4devs/console/input/value/flag"
) )
type Duration struct { var (
empty _ ParseValue = Duration(0)
Val []time.Duration _ SliceValue = Durations{}
Flag flag.Flag )
func NewDurations(in []time.Duration) Slice {
return Slice{SliceValue: Durations(in)}
} }
func (d *Duration) Append(in string) error { type Durations []time.Duration
v, err := time.ParseDuration(in)
if err != nil { func (d Durations) Unmarshal(val interface{}) error {
return err v, ok := val.(*[]time.Duration)
if !ok {
return fmt.Errorf("%w: expect: *[]time.Duration got: %T", ErrWrongType, val)
} }
d.Val = append(d.Val, v) *v = d
return nil return nil
} }
func (d *Duration) Duration() time.Duration { func (d Durations) Any() interface{} {
if !d.Flag.IsArray() && len(d.Val) == 1 { return d.Durations()
return d.Val[0] }
func (d Durations) Strings() []string {
return nil
}
func (d Durations) Ints() []int {
return nil
}
func (d Durations) Int64s() []int64 {
return nil
}
func (d Durations) Uints() []uint {
return nil
}
func (d Durations) Uint64s() []uint64 {
return nil
}
func (d Durations) Float64s() []float64 {
return nil
}
func (d Durations) Bools() []bool {
return nil
}
func (d Durations) Durations() []time.Duration {
out := make([]time.Duration, len(d))
copy(out, d)
return out
}
func (d Durations) Times() []time.Time {
return nil
}
func NewDuration(in time.Duration) Read {
return Read{ParseValue: Duration(in)}
}
type Duration time.Duration
func (d Duration) ParseDuration() (time.Duration, error) {
return time.Duration(d), nil
}
func (d Duration) ParseString() (string, error) {
return time.Duration(d).String(), nil
}
func (d Duration) ParseInt() (int, error) {
return int(d), nil
}
func (d Duration) ParseInt64() (int64, error) {
return int64(d), nil
}
func (d Duration) ParseUint() (uint, error) {
return uint(d), nil
}
func (d Duration) ParseUint64() (uint64, error) {
return uint64(d), nil
}
func (d Duration) ParseFloat64() (float64, error) {
return float64(d), nil
}
func (d Duration) ParseBool() (bool, error) {
return false, fmt.Errorf("duration:%w", ErrWrongType)
}
func (d Duration) ParseTime() (time.Time, error) {
return time.Time{}, fmt.Errorf("duration:%w", ErrWrongType)
}
func (d Duration) Unmarshal(val interface{}) error {
v, ok := val.(*time.Duration)
if !ok {
return fmt.Errorf("%w: expect: *[]time.Duration got: %T", ErrWrongType, val)
} }
return 0 *v = time.Duration(d)
return nil
} }
func (d *Duration) Durations() []time.Duration { func (d Duration) Any() interface{} {
return d.Val return time.Duration(d)
}
func (d *Duration) Any() interface{} {
if d.Flag.IsArray() {
return d.Durations()
}
return d.Duration()
} }

View File

@@ -1,100 +0,0 @@
package value
import (
"time"
)
// nolint: gochecknoglobals
var (
emptyValue = &empty{}
)
func Empty() Value {
return emptyValue
}
func IsEmpty(v Value) bool {
return v == nil || v == emptyValue
}
type empty struct{}
func (e *empty) Append(string) error {
return ErrAppendEmpty
}
func (e *empty) String() string {
return ""
}
func (e *empty) Int() int {
return 0
}
func (e *empty) Int64() int64 {
return 0
}
func (e *empty) Uint() uint {
return 0
}
func (e *empty) Uint64() uint64 {
return 0
}
func (e *empty) Float64() float64 {
return 0
}
func (e *empty) Bool() bool {
return false
}
func (e *empty) Duration() time.Duration {
return 0
}
func (e *empty) Time() time.Time {
return time.Time{}
}
func (e *empty) Strings() []string {
return nil
}
func (e *empty) Ints() []int {
return nil
}
func (e *empty) Int64s() []int64 {
return nil
}
func (e *empty) Uints() []uint {
return nil
}
func (e *empty) Uint64s() []uint64 {
return nil
}
func (e *empty) Float64s() []float64 {
return nil
}
func (e *empty) Bools() []bool {
return nil
}
func (e *empty) Durations() []time.Duration {
return nil
}
func (e *empty) Times() []time.Time {
return nil
}
func (e *empty) Any() interface{} {
return nil
}

View File

@@ -1,44 +1,128 @@
package value package value
import ( import (
"strconv" "fmt"
"time"
"gitoa.ru/go-4devs/console/input/value/flag"
) )
type Float64 struct { var (
empty _ ParseValue = Float64(0)
Val []float64 _ SliceValue = Float64s{}
Flag flag.Flag )
func NewFloat64s(in []float64) Slice {
return Slice{SliceValue: Float64s(in)}
} }
func (f *Float64) Append(in string) error { type Float64s []float64
v, err := strconv.ParseFloat(in, 64)
if err != nil { func (f Float64s) Any() interface{} {
return err return f.Float64s()
}
func (f Float64s) Unmarshal(val interface{}) error {
v, ok := val.(*[]float64)
if !ok {
return fmt.Errorf("%w: expect *[]float64", ErrWrongType)
} }
f.Val = append(f.Val, v) *v = f
return nil return nil
} }
func (f *Float64) Float64() float64 { func (f Float64s) Strings() []string {
if !f.Flag.IsArray() && len(f.Val) == 1 { return nil
return f.Val[0] }
func (f Float64s) Ints() []int {
return nil
}
func (f Float64s) Int64s() []int64 {
return nil
}
func (f Float64s) Uints() []uint {
return nil
}
func (f Float64s) Uint64s() []uint64 {
return nil
}
func (f Float64s) Float64s() []float64 {
out := make([]float64, len(f))
copy(out, f)
return out
}
func (f Float64s) Bools() []bool {
return nil
}
func (f Float64s) Durations() []time.Duration {
return nil
}
func (f Float64s) Times() []time.Time {
return nil
}
func NewFloat64(in float64) Read {
return Read{ParseValue: Float64(in)}
}
type Float64 float64
func (f Float64) Any() interface{} {
return float64(f)
}
func (f Float64) ParseString() (string, error) {
return fmt.Sprint(float64(f)), nil
}
func (f Float64) ParseInt() (int, error) {
return int(f), nil
}
func (f Float64) ParseInt64() (int64, error) {
return int64(f), nil
}
func (f Float64) ParseUint() (uint, error) {
return uint(f), nil
}
func (f Float64) ParseUint64() (uint64, error) {
return uint64(f), nil
}
func (f Float64) ParseFloat64() (float64, error) {
return float64(f), nil
}
func (f Float64) ParseBool() (bool, error) {
return false, fmt.Errorf("float64:%w", ErrWrongType)
}
func (f Float64) ParseDuration() (time.Duration, error) {
return time.Duration(f), nil
}
func (f Float64) ParseTime() (time.Time, error) {
return time.Unix(0, int64(f*Float64(time.Second))), nil
}
func (f Float64) Unmarshal(in interface{}) error {
v, ok := in.(*float64)
if !ok {
return fmt.Errorf("%w: expect *float64", ErrWrongType)
} }
return 0 *v = float64(f)
}
func (f *Float64) Float64s() []float64 { return nil
return f.Val
}
func (f *Float64) Any() interface{} {
if f.Flag.IsArray() {
return f.Float64s()
}
return f.Float64()
} }

View File

@@ -0,0 +1,47 @@
package value_test
import (
"math"
"testing"
"github.com/stretchr/testify/require"
"gitoa.ru/go-4devs/console/input/value"
)
func TestFloat64_Unmarshal(t *testing.T) {
t.Parallel()
f := value.Float64(math.Pi)
var out float64
require.NoError(t, f.Unmarshal(&out))
require.Equal(t, math.Pi, out)
}
func TestFloat64_Any(t *testing.T) {
t.Parallel()
f := value.Float64(math.Pi)
require.Equal(t, math.Pi, f.Any())
}
func TestFloat64s_Unmarshal(t *testing.T) {
t.Parallel()
f := value.Float64s{math.Pi, math.Sqrt2}
var out []float64
require.NoError(t, f.Unmarshal(&out))
require.Equal(t, []float64{math.Pi, math.Sqrt2}, out)
}
func TestFloat64s_Any(t *testing.T) {
t.Parallel()
f := value.Float64s{math.Pi, math.Sqrt2}
require.Equal(t, []float64{math.Pi, math.Sqrt2}, f.Any())
}

View File

@@ -1,44 +1,129 @@
package value package value
import ( import (
"fmt"
"strconv" "strconv"
"time"
"gitoa.ru/go-4devs/console/input/value/flag"
) )
type Int struct { var (
empty _ ParseValue = Int(0)
Val []int _ SliceValue = Ints{}
Flag flag.Flag )
func NewInts(in []int) Slice {
return Slice{SliceValue: Ints(in)}
} }
func (i *Int) Append(in string) error { type Ints []int
v, err := strconv.Atoi(in)
if err != nil { func (i Ints) Unmarshal(in interface{}) error {
return err val, ok := in.(*[]int)
if !ok {
return fmt.Errorf("%w: expect *[]int", ErrWrongType)
} }
i.Val = append(i.Val, v) *val = i
return nil return nil
} }
func (i *Int) Int() int { func (i Ints) Any() interface{} {
if !i.Flag.IsArray() && len(i.Val) == 1 { return i.Ints()
return i.Val[0] }
func (i Ints) Strings() []string {
return nil
}
func (i Ints) Ints() []int {
out := make([]int, len(i))
copy(out, i)
return out
}
func (i Ints) Int64s() []int64 {
return nil
}
func (i Ints) Uints() []uint {
return nil
}
func (i Ints) Uint64s() []uint64 {
return nil
}
func (i Ints) Float64s() []float64 {
return nil
}
func (i Ints) Bools() []bool {
return nil
}
func (i Ints) Durations() []time.Duration {
return nil
}
func (i Ints) Times() []time.Time {
return nil
}
func NewInt(in int) Read {
return Read{ParseValue: Int(in)}
}
type Int int
func (i Int) Unmarshal(in interface{}) error {
v, ok := in.(*int)
if !ok {
return fmt.Errorf("%w: expect *int", ErrWrongType)
} }
return 0 *v = int(i)
return nil
} }
func (i *Int) Ints() []int { func (i Int) ParseString() (string, error) {
return i.Val return strconv.Itoa(int(i)), nil
} }
func (i *Int) Any() interface{} { func (i Int) ParseInt() (int, error) {
if i.Flag.IsArray() { return int(i), nil
return i.Ints() }
}
func (i Int) ParseInt64() (int64, error) {
return i.Int() return int64(i), nil
}
func (i Int) ParseUint() (uint, error) {
return uint(i), nil
}
func (i Int) ParseUint64() (uint64, error) {
return uint64(i), nil
}
func (i Int) ParseFloat64() (float64, error) {
return float64(i), nil
}
func (i Int) ParseBool() (bool, error) {
return false, fmt.Errorf("int:%w", ErrWrongType)
}
func (i Int) ParseDuration() (time.Duration, error) {
return time.Duration(i), nil
}
func (i Int) ParseTime() (time.Time, error) {
return time.Unix(0, int64(i)), nil
}
func (i Int) Any() interface{} {
return int(i)
} }

View File

@@ -1,44 +1,129 @@
package value package value
import ( import (
"fmt"
"strconv" "strconv"
"time"
"gitoa.ru/go-4devs/console/input/value/flag"
) )
type Int64 struct { var (
empty _ ParseValue = Int64(0)
Val []int64 _ SliceValue = Int64s{}
Flag flag.Flag )
func NewInt64s(in []int64) Slice {
return Slice{SliceValue: Int64s(in)}
} }
func (i *Int64) Int64() int64 { type Int64s []int64
if !i.Flag.IsArray() && len(i.Val) == 1 {
return i.Val[0] func (i Int64s) Any() interface{} {
return i.Int64s()
}
func (i Int64s) Unmarshal(val interface{}) error {
v, ok := val.(*[]int64)
if !ok {
return fmt.Errorf("%w: expect *[]int64", ErrWrongType)
} }
return 0 *v = i
}
return nil
func (i *Int64) Int64s() []int64 { }
return i.Val
} func (i Int64s) Strings() []string {
return nil
func (i *Int64) Any() interface{} { }
if i.Flag.IsArray() {
return i.Int64s() func (i Int64s) Ints() []int {
} return nil
}
return i.Int64()
} func (i Int64s) Int64s() []int64 {
out := make([]int64, len(i))
func (i *Int64) Append(in string) error { copy(out, i)
v, err := strconv.ParseInt(in, 10, 64)
if err != nil { return out
return err }
}
func (i Int64s) Uints() []uint {
i.Val = append(i.Val, v) return nil
}
func (i Int64s) Uint64s() []uint64 {
return nil
}
func (i Int64s) Float64s() []float64 {
return nil
}
func (i Int64s) Bools() []bool {
return nil
}
func (i Int64s) Durations() []time.Duration {
return nil
}
func (i Int64s) Times() []time.Time {
return nil
}
func NewInt64(in int64) Read {
return Read{ParseValue: Int64(in)}
}
type Int64 int64
func (i Int64) Any() interface{} {
return int64(i)
}
func (i Int64) ParseString() (string, error) {
return strconv.FormatInt(int64(i), 10), nil
}
func (i Int64) ParseInt() (int, error) {
return int(i), nil
}
func (i Int64) ParseInt64() (int64, error) {
return int64(i), nil
}
func (i Int64) ParseUint() (uint, error) {
return uint(i), nil
}
func (i Int64) ParseUint64() (uint64, error) {
return uint64(i), nil
}
func (i Int64) ParseFloat64() (float64, error) {
return float64(i), nil
}
func (i Int64) ParseBool() (bool, error) {
return false, fmt.Errorf("int64:%w", ErrWrongType)
}
func (i Int64) ParseDuration() (time.Duration, error) {
return time.Duration(i), nil
}
func (i Int64) ParseTime() (time.Time, error) {
return time.Unix(0, int64(i)), nil
}
func (i Int64) Unmarshal(val interface{}) error {
v, ok := val.(*int64)
if !ok {
return fmt.Errorf("%w: expect *int64", ErrWrongType)
}
*v = int64(i)
return nil return nil
} }

View File

@@ -1,20 +1,189 @@
package value package value
import ( import (
"errors" "fmt"
) "time"
var _ Append = (*Read)(nil) "gitoa.ru/go-4devs/console/input/errs"
)
var ( var (
ErrAppendRead = errors.New("invalid append data to read value") _ Value = Read{}
ErrAppendEmpty = errors.New("invalid apped data to empty value") _ Value = Slice{}
) )
var ErrWrongType = errs.ErrWrongType
type Read struct { type Read struct {
Value ParseValue
} }
func (r *Read) Append(string) error { func (r Read) String() string {
return ErrAppendRead sout, _ := r.ParseValue.ParseString()
return sout
}
func (r Read) Int() int {
iout, _ := r.ParseValue.ParseInt()
return iout
}
func (r Read) Int64() int64 {
iout, _ := r.ParseValue.ParseInt64()
return iout
}
func (r Read) Uint() uint {
uout, _ := r.ParseValue.ParseUint()
return uout
}
func (r Read) Uint64() uint64 {
uout, _ := r.ParseValue.ParseUint64()
return uout
}
func (r Read) Float64() float64 {
fout, _ := r.ParseValue.ParseFloat64()
return fout
}
func (r Read) Bool() bool {
bout, _ := r.ParseValue.ParseBool()
return bout
}
func (r Read) Duration() time.Duration {
dout, _ := r.ParseValue.ParseDuration()
return dout
}
func (r Read) Time() time.Time {
tout, _ := r.ParseValue.ParseTime()
return tout
}
func (r Read) Strings() []string {
return []string{r.String()}
}
func (r Read) Ints() []int {
return []int{r.Int()}
}
func (r Read) Int64s() []int64 {
return []int64{r.Int64()}
}
func (r Read) Uints() []uint {
return []uint{r.Uint()}
}
func (r Read) Uint64s() []uint64 {
return []uint64{r.Uint64()}
}
func (r Read) Float64s() []float64 {
return []float64{r.Float64()}
}
func (r Read) Bools() []bool {
return []bool{r.Bool()}
}
func (r Read) Durations() []time.Duration {
return []time.Duration{r.Duration()}
}
func (r Read) Times() []time.Time {
return []time.Time{r.Time()}
}
type Slice struct {
SliceValue
}
func (s Slice) String() string {
return ""
}
func (s Slice) Int() int {
return 0
}
func (s Slice) Int64() int64 {
return 0
}
func (s Slice) Uint() uint {
return 0
}
func (s Slice) Uint64() uint64 {
return 0
}
func (s Slice) Float64() float64 {
return 0
}
func (s Slice) Bool() bool {
return false
}
func (s Slice) Duration() time.Duration {
return 0
}
func (s Slice) Time() time.Time {
return time.Time{}
}
func (s Slice) wrongType() error {
return fmt.Errorf("%w: for %T", ErrWrongType, s.SliceValue)
}
func (s Slice) ParseString() (string, error) {
return "", s.wrongType()
}
func (s Slice) ParseInt() (int, error) {
return 0, s.wrongType()
}
func (s Slice) ParseInt64() (int64, error) {
return 0, s.wrongType()
}
func (s Slice) ParseUint() (uint, error) {
return 0, s.wrongType()
}
func (s Slice) ParseUint64() (uint64, error) {
return 0, s.wrongType()
}
func (s Slice) ParseFloat64() (float64, error) {
return 0, s.wrongType()
}
func (s Slice) ParseBool() (bool, error) {
return false, s.wrongType()
}
func (s Slice) ParseDuration() (time.Duration, error) {
return 0, s.wrongType()
}
func (s Slice) ParseTime() (time.Time, error) {
return time.Time{}, s.wrongType()
} }

View File

@@ -1,39 +1,172 @@
package value package value
import "gitoa.ru/go-4devs/console/input/value/flag" import (
"fmt"
"strconv"
"time"
)
type String struct { var (
empty _ ParseValue = (String)("")
Val []string _ SliceValue = (Strings)(nil)
Flag flag.Flag )
func NewStrings(in []string) Slice {
return Slice{SliceValue: Strings(in)}
} }
func (s *String) Append(in string) error { type Strings []string
s.Val = append(s.Val, in)
func (s Strings) Unmarshal(in interface{}) error {
val, ok := in.(*[]string)
if !ok {
return fmt.Errorf("%w: expect *[]string", ErrWrongType)
}
*val = s
return nil return nil
} }
func (s *String) String() string { func (s Strings) Any() interface{} {
if s.Flag.IsArray() { return s.Strings()
return ""
}
if len(s.Val) == 1 {
return s.Val[0]
}
return ""
} }
func (s *String) Strings() []string { func (s Strings) Strings() []string {
return s.Val out := make([]string, len(s))
copy(out, s)
return out
} }
func (s *String) Any() interface{} { func (s Strings) Ints() []int {
if s.Flag.IsArray() { return nil
return s.Strings() }
func (s Strings) Int64s() []int64 {
return nil
}
func (s Strings) Uints() []uint {
return nil
}
func (s Strings) Uint64s() []uint64 {
return nil
}
func (s Strings) Float64s() []float64 {
return nil
}
func (s Strings) Bools() []bool {
return nil
}
func (s Strings) Durations() []time.Duration {
return nil
}
func (s Strings) Times() []time.Time {
return nil
}
func NewString(in string) Value {
return Read{ParseValue: String(in)}
}
type String string
func (s String) ParseString() (string, error) {
return string(s), nil
}
func (s String) Unmarshal(in interface{}) error {
v, ok := in.(*string)
if !ok {
return fmt.Errorf("%w: expect *string", ErrWrongType)
} }
return s.String() *v = string(s)
return nil
}
func (s String) Any() interface{} {
return string(s)
}
func (s String) ParseInt() (int, error) {
v, err := strconv.Atoi(string(s))
if err != nil {
return 0, fmt.Errorf("string int:%w", err)
}
return v, nil
}
func (s String) Int64() int64 {
out, _ := s.ParseInt64()
return out
}
func (s String) ParseInt64() (int64, error) {
v, err := strconv.ParseInt(string(s), 10, 64)
if err != nil {
return 0, fmt.Errorf("string int64:%w", err)
}
return v, nil
}
func (s String) ParseUint() (uint, error) {
uout, err := s.ParseUint64()
return uint(uout), err
}
func (s String) ParseUint64() (uint64, error) {
uout, err := strconv.ParseUint(string(s), 10, 64)
if err != nil {
return 0, fmt.Errorf("string uint:%w", err)
}
return uout, nil
}
func (s String) ParseFloat64() (float64, error) {
fout, err := strconv.ParseFloat(string(s), 64)
if err != nil {
return 0, fmt.Errorf("string float64:%w", err)
}
return fout, nil
}
func (s String) ParseBool() (bool, error) {
v, err := strconv.ParseBool(string(s))
if err != nil {
return false, fmt.Errorf("string bool:%w", err)
}
return v, nil
}
func (s String) ParseDuration() (time.Duration, error) {
v, err := time.ParseDuration(string(s))
if err != nil {
return 0, fmt.Errorf("string duration:%w", err)
}
return v, nil
}
func (s String) ParseTime() (time.Time, error) {
v, err := time.Parse(time.RFC3339, string(s))
if err != nil {
return time.Time{}, fmt.Errorf("string time:%w", err)
}
return v, nil
} }

View File

@@ -0,0 +1,28 @@
package value_test
import (
"testing"
"github.com/stretchr/testify/require"
"gitoa.ru/go-4devs/console/input/value"
)
func TestStringUnmarshal(t *testing.T) {
t.Parallel()
st := value.New("test")
sta := value.New([]string{"test1", "test2"})
ac := ""
require.NoError(t, st.Unmarshal(&ac))
require.Equal(t, "test", ac)
aca := []string{}
require.NoError(t, sta.Unmarshal(&aca))
require.Equal(t, []string{"test1", "test2"}, aca)
require.ErrorIs(t, sta.Unmarshal(ac), value.ErrWrongType)
require.ErrorIs(t, sta.Unmarshal(&ac), value.ErrWrongType)
require.ErrorIs(t, st.Unmarshal(aca), value.ErrWrongType)
require.ErrorIs(t, st.Unmarshal(&aca), value.ErrWrongType)
}

View File

@@ -1,44 +1,130 @@
package value package value
import ( import (
"fmt"
"time" "time"
"gitoa.ru/go-4devs/console/input/value/flag"
) )
type Time struct { var (
empty _ ParseValue = Time{time.Now()}
Val []time.Time _ SliceValue = (Times)(nil)
Flag flag.Flag )
func NewTimes(in []time.Time) Slice {
return Slice{SliceValue: Times(in)}
} }
func (t *Time) Append(in string) error { type Times []time.Time
v, err := time.Parse(time.RFC3339, in)
if err != nil { func (t Times) Any() interface{} {
return err return t.Times()
}
func (t Times) Unmarshal(val interface{}) error {
res, ok := val.(*[]time.Time)
if !ok {
return fmt.Errorf("%w: expect *[]time.Time", ErrWrongType)
} }
t.Val = append(t.Val, v) *res = t
return nil return nil
} }
func (t *Time) Time() time.Time { func (t Times) Strings() []string {
if !t.Flag.IsArray() && len(t.Val) == 1 { return nil
return t.Val[0] }
func (t Times) Ints() []int {
return nil
}
func (t Times) Int64s() []int64 {
return nil
}
func (t Times) Uints() []uint {
return nil
}
func (t Times) Uint64s() []uint64 {
return nil
}
func (t Times) Float64s() []float64 {
return nil
}
func (t Times) Bools() []bool {
return nil
}
func (t Times) Durations() []time.Duration {
return nil
}
func (t Times) Times() []time.Time {
out := make([]time.Time, len(t))
copy(out, t)
return out
}
func NewTime(in time.Time) Read {
return Read{ParseValue: Time{Time: in}}
}
type Time struct {
time.Time
}
func (t Time) ParseString() (string, error) {
return t.Format(time.RFC3339), nil
}
func (t Time) ParseInt() (int, error) {
return int(t.Unix()), nil
}
func (t Time) ParseInt64() (int64, error) {
return t.Unix(), nil
}
func (t Time) ParseUint() (uint, error) {
return uint(t.Unix()), nil
}
func (t Time) ParseUint64() (uint64, error) {
return uint64(t.Unix()), nil
}
func (t Time) ParseFloat64() (float64, error) {
return float64(t.UnixNano()), nil
}
func (t Time) ParseBool() (bool, error) {
return false, fmt.Errorf("time bool:%w", ErrWrongType)
}
func (t Time) ParseDuration() (time.Duration, error) {
return 0, fmt.Errorf("time duration:%w", ErrWrongType)
}
func (t Time) ParseTime() (time.Time, error) {
return t.Time, nil
}
func (t Time) Unmarshal(val interface{}) error {
res, ok := val.(*time.Time)
if !ok {
return fmt.Errorf("%w: expect *time.Time", ErrWrongType)
} }
return time.Time{} *res = t.Time
return nil
} }
func (t *Time) Times() []time.Time { func (t Time) Any() interface{} {
return t.Val return t.Time
}
func (t *Time) Amy() interface{} {
if t.Flag.IsArray() {
return t.Times()
}
return t.Time()
} }

View File

@@ -1,44 +1,129 @@
package value package value
import ( import (
"fmt"
"strconv" "strconv"
"time"
"gitoa.ru/go-4devs/console/input/value/flag"
) )
type Uint struct { var (
empty _ ParseValue = Uint(0)
Val []uint _ SliceValue = (Uints)(nil)
Flag flag.Flag )
func NewUints(in []uint) Slice {
return Slice{SliceValue: Uints(in)}
} }
func (u *Uint) Append(in string) error { type Uints []uint
v, err := strconv.ParseUint(in, 10, 64)
if err != nil { func (u Uints) Any() interface{} {
return err return u.Uints()
}
func (u Uints) Unmarshal(val interface{}) error {
res, ok := val.(*[]uint)
if !ok {
return fmt.Errorf("%w: expect *[]uint", ErrWrongType)
} }
u.Val = append(u.Val, uint(v)) *res = u
return nil return nil
} }
func (u *Uint) Uint() uint { func (u Uints) Strings() []string {
if !u.Flag.IsArray() && len(u.Val) == 1 { return nil
return u.Val[0] }
func (u Uints) Ints() []int {
return nil
}
func (u Uints) Int64s() []int64 {
return nil
}
func (u Uints) Uints() []uint {
out := make([]uint, len(u))
copy(out, u)
return out
}
func (u Uints) Uint64s() []uint64 {
return nil
}
func (u Uints) Float64s() []float64 {
return nil
}
func (u Uints) Bools() []bool {
return nil
}
func (u Uints) Durations() []time.Duration {
return nil
}
func (u Uints) Times() []time.Time {
return nil
}
func NewUint(in uint) Read {
return Read{ParseValue: Uint(in)}
}
type Uint uint
func (u Uint) ParseString() (string, error) {
return strconv.FormatUint(uint64(u), 10), nil
}
func (u Uint) ParseInt() (int, error) {
return int(u), nil
}
func (u Uint) ParseInt64() (int64, error) {
return int64(u), nil
}
func (u Uint) ParseUint() (uint, error) {
return uint(u), nil
}
func (u Uint) ParseUint64() (uint64, error) {
return uint64(u), nil
}
func (u Uint) ParseFloat64() (float64, error) {
return float64(u), nil
}
func (u Uint) ParseBool() (bool, error) {
return false, fmt.Errorf("uint:%w", ErrWrongType)
}
func (u Uint) ParseDuration() (time.Duration, error) {
return time.Duration(u), nil
}
func (u Uint) ParseTime() (time.Time, error) {
return time.Unix(0, int64(u)), nil
}
func (u Uint) Unmarshal(val interface{}) error {
res, ok := val.(*uint)
if !ok {
return fmt.Errorf("%w: expect *uint", ErrWrongType)
} }
return 0 *res = uint(u)
return nil
} }
func (u *Uint) Uints() []uint { func (u Uint) Any() interface{} {
return u.Val return uint(u)
}
func (u *Uint) Any() interface{} {
if u.Flag.IsArray() {
return u.Uints()
}
return u.Uint()
} }

View File

@@ -1,44 +1,129 @@
package value package value
import ( import (
"fmt"
"strconv" "strconv"
"time"
"gitoa.ru/go-4devs/console/input/value/flag"
) )
type Uint64 struct { var (
empty _ ParseValue = Uint64(0)
Val []uint64 _ SliceValue = (Uint64s)(nil)
Flag flag.Flag )
func NewUint64s(in []uint64) Slice {
return Slice{SliceValue: Uint64s(in)}
} }
func (u *Uint64) Append(in string) error { type Uint64s []uint64
v, err := strconv.ParseUint(in, 10, 64)
if err != nil { func (u Uint64s) Any() interface{} {
return err return u.Uint64s()
}
func (u Uint64s) Unmarshal(val interface{}) error {
res, ok := val.(*[]uint64)
if !ok {
return fmt.Errorf("%w: expect *[]uint64", ErrWrongType)
} }
u.Val = append(u.Val, v) *res = u
return nil return nil
} }
func (u *Uint64) Uint64() uint64 { func (u Uint64s) Strings() []string {
if !u.Flag.IsArray() && len(u.Val) == 1 { return nil
return u.Val[0] }
func (u Uint64s) Ints() []int {
return nil
}
func (u Uint64s) Int64s() []int64 {
return nil
}
func (u Uint64s) Uints() []uint {
return nil
}
func (u Uint64s) Uint64s() []uint64 {
out := make([]uint64, len(u))
copy(out, u)
return out
}
func (u Uint64s) Float64s() []float64 {
return nil
}
func (u Uint64s) Bools() []bool {
return nil
}
func (u Uint64s) Durations() []time.Duration {
return nil
}
func (u Uint64s) Times() []time.Time {
return nil
}
func NewUint64(in uint64) Read {
return Read{ParseValue: Uint64(in)}
}
type Uint64 uint64
func (u Uint64) ParseString() (string, error) {
return strconv.FormatUint(uint64(u), 10), nil
}
func (u Uint64) ParseInt() (int, error) {
return int(u), nil
}
func (u Uint64) ParseInt64() (int64, error) {
return int64(u), nil
}
func (u Uint64) ParseUint() (uint, error) {
return uint(u), nil
}
func (u Uint64) ParseUint64() (uint64, error) {
return uint64(u), nil
}
func (u Uint64) ParseFloat64() (float64, error) {
return float64(u), nil
}
func (u Uint64) ParseBool() (bool, error) {
return false, fmt.Errorf("uint64 bool:%w", ErrWrongType)
}
func (u Uint64) ParseDuration() (time.Duration, error) {
return time.Duration(u), nil
}
func (u Uint64) ParseTime() (time.Time, error) {
return time.Unix(0, int64(0)), nil
}
func (u Uint64) Unmarshal(val interface{}) error {
res, ok := val.(*uint64)
if !ok {
return fmt.Errorf("%w: expect *uint64", ErrWrongType)
} }
return 0 *res = uint64(u)
return nil
} }
func (u *Uint64) Uint64s() []uint64 { func (u Uint64) Any() interface{} {
return u.Val return uint64(u)
}
func (u *Uint64) Any() interface{} {
if u.Flag.IsArray() {
return u.Uint64s()
}
return u.Uint64()
} }

View File

@@ -2,11 +2,19 @@ package value
import ( import (
"time" "time"
"gitoa.ru/go-4devs/console/input/value/flag"
) )
type Value interface { type Value interface {
ReadValue
ParseValue
ArrValue
}
type UnmarshalValue interface {
Unmarshal(val interface{}) error
}
type ReadValue interface {
String() string String() string
Int() int Int() int
Int64() int64 Int64() int64
@@ -16,8 +24,19 @@ type Value interface {
Bool() bool Bool() bool
Duration() time.Duration Duration() time.Duration
Time() time.Time Time() time.Time
Any() interface{} }
type AnyValue interface {
Any() interface{}
}
type SliceValue interface {
AnyValue
UnmarshalValue
ArrValue
}
type ArrValue interface {
Strings() []string Strings() []string
Ints() []int Ints() []int
Int64s() []int64 Int64s() []int64
@@ -29,86 +48,74 @@ type Value interface {
Times() []time.Time Times() []time.Time
} }
//nolint:interfacebloat
type ParseValue interface {
ParseString() (string, error)
ParseInt() (int, error)
ParseInt64() (int64, error)
ParseUint() (uint, error)
ParseUint64() (uint64, error)
ParseFloat64() (float64, error)
ParseBool() (bool, error)
ParseDuration() (time.Duration, error)
ParseTime() (time.Time, error)
UnmarshalValue
AnyValue
}
type Append interface { type Append interface {
Value Value
Append(string) error Append(string) (Value, error)
} }
//nolint: gocyclo //nolint:gocyclo,cyclop
func New(v interface{}) Append { func New(in interface{}) Value {
switch val := v.(type) { switch val := in.(type) {
case string:
return &String{Val: []string{val}, Flag: flag.String}
case int:
return &Int{Val: []int{val}, Flag: flag.Int}
case int64:
return &Int64{Val: []int64{val}, Flag: flag.Int64}
case uint:
return &Uint{Val: []uint{val}, Flag: flag.Uint}
case uint64:
return &Uint64{Val: []uint64{val}, Flag: flag.Uint64}
case float64:
return &Float64{Val: []float64{val}, Flag: flag.Float64}
case bool: case bool:
return &Bool{Val: []bool{val}, Flag: flag.Bool} return Read{Bool(val)}
case time.Duration:
return &Duration{Val: []time.Duration{val}, Flag: flag.Duration}
case time.Time:
return &Time{Val: []time.Time{val}, Flag: flag.Time}
case []int64:
return &Int64{Val: val, Flag: flag.Int64 | flag.Array}
case []uint:
return &Uint{Val: val, Flag: flag.Uint | flag.Array}
case []uint64:
return &Uint64{Val: val, Flag: flag.Uint64 | flag.Array}
case []float64:
return &Float64{Val: val, Flag: flag.Float64 | flag.Array}
case []bool: case []bool:
return &Bool{Val: val, Flag: flag.Bool | flag.Array} return NewBools(val)
case string:
return Read{String(val)}
case int:
return Read{Int(val)}
case int64:
return Read{Int64(val)}
case uint:
return Read{Uint(val)}
case uint64:
return Read{Uint64(val)}
case float64:
return Read{Float64(val)}
case time.Duration:
return Read{Duration(val)}
case time.Time:
return Read{Time{val}}
case []int64:
return Slice{Int64s(val)}
case []uint:
return Slice{Uints(val)}
case []uint64:
return Slice{Uint64s(val)}
case []float64:
return Slice{Float64s(val)}
case []time.Duration: case []time.Duration:
return &Duration{Val: val, Flag: flag.Duration | flag.Array} return Slice{Durations(val)}
case []time.Time: case []time.Time:
return &Time{Val: val, Flag: flag.Time | flag.Array} return Slice{Times(val)}
case []string: case []string:
return &String{Val: val, Flag: flag.String | flag.Array} return Slice{Strings(val)}
case []int: case []int:
return &Int{Val: val, Flag: flag.Int | flag.Array} return Slice{Ints(val)}
case []interface{}: case []interface{}:
return &Any{Val: val, Flag: flag.Any | flag.Array} return Read{Any{v: val}}
case Append:
return val
case Value: case Value:
return &Read{Value: val} return val
default: default:
if v != nil { if in != nil {
return &Any{Val: []interface{}{v}, Flag: flag.Any} return Read{Any{v: in}}
} }
return &empty{} return Empty()
}
}
func ByFlag(f flag.Flag) Append {
switch {
case f.IsInt():
return &Int{Flag: f | flag.Int}
case f.IsInt64():
return &Int64{Flag: f | flag.Int64}
case f.IsUint():
return &Uint{Flag: f | flag.Uint}
case f.IsUint64():
return &Uint64{Flag: f | flag.Uint64}
case f.IsFloat64():
return &Float64{Flag: f | flag.Float64}
case f.IsBool():
return &Bool{Flag: f | flag.Bool}
case f.IsDuration():
return &Duration{Flag: f | flag.Duration}
case f.IsTime():
return &Time{Flag: f | flag.Time}
case f.IsAny():
return &Any{Flag: f | flag.Any}
default:
return &String{}
} }
} }

10
input/variable/argtype.go Normal file
View File

@@ -0,0 +1,10 @@
package variable
//go:generate stringer -type=ArgType -linecomment
type ArgType int
const (
TypeOption ArgType = iota + 1 // option
TypeArgument // argument
)

View File

@@ -0,0 +1,25 @@
// Code generated by "stringer -type=ArgType -linecomment"; DO NOT EDIT.
package variable
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[TypeOption-1]
_ = x[TypeArgument-2]
}
const _ArgType_name = "optionargument"
var _ArgType_index = [...]uint8{0, 6, 14}
func (i ArgType) String() string {
i -= 1
if i < 0 || i >= ArgType(len(_ArgType_index)-1) {
return "ArgType(" + strconv.FormatInt(int64(i+1), 10) + ")"
}
return _ArgType_name[_ArgType_index[i]:_ArgType_index[i+1]]
}

31
input/variable/bool.go Normal file
View File

@@ -0,0 +1,31 @@
package variable
import (
"fmt"
"strconv"
"gitoa.ru/go-4devs/console/input/flag"
"gitoa.ru/go-4devs/console/input/value"
)
func Bool(name, description string, opts ...Option) Variable {
return String(name, description, append(opts, WithParse(CreateBool, AppendBool), Value(flag.Bool))...)
}
func CreateBool(in string) (value.Value, error) {
out, err := strconv.ParseBool(in)
if err != nil {
return nil, fmt.Errorf("create bool:%w", err)
}
return value.NewBool(out), nil
}
func AppendBool(old value.Value, in string) (value.Value, error) {
out, err := strconv.ParseBool(in)
if err != nil {
return nil, fmt.Errorf("create bool:%w", err)
}
return value.NewBools(append(old.Bools(), out)), nil
}

View File

@@ -0,0 +1,31 @@
package variable
import (
"fmt"
"time"
"gitoa.ru/go-4devs/console/input/flag"
"gitoa.ru/go-4devs/console/input/value"
)
func Duration(name, description string, opts ...Option) Variable {
return String(name, description, append(opts, WithParse(CreateDuration, AppendDuration), Value(flag.Duration))...)
}
func CreateDuration(in string) (value.Value, error) {
out, err := time.ParseDuration(in)
if err != nil {
return nil, fmt.Errorf("create duration:%w", err)
}
return value.NewDuration(out), nil
}
func AppendDuration(old value.Value, in string) (value.Value, error) {
out, err := time.ParseDuration(in)
if err != nil {
return nil, fmt.Errorf("append duration:%w", err)
}
return value.NewDurations(append(old.Durations(), out)), nil
}

32
input/variable/err.go Normal file
View File

@@ -0,0 +1,32 @@
package variable
import (
"errors"
"fmt"
)
type Error struct {
Name string
Err error
Type ArgType
}
func (o Error) Error() string {
return fmt.Sprintf("%s: '%s' %s", o.Type, o.Name, o.Err)
}
func (o Error) Is(err error) bool {
return errors.Is(err, o.Err)
}
func (o Error) Unwrap() error {
return o.Err
}
func Err(name string, t ArgType, err error) Error {
return Error{
Name: name,
Type: t,
Err: err,
}
}

31
input/variable/float64.go Normal file
View File

@@ -0,0 +1,31 @@
package variable
import (
"fmt"
"strconv"
"gitoa.ru/go-4devs/console/input/flag"
"gitoa.ru/go-4devs/console/input/value"
)
func Float64(name, description string, opts ...Option) Variable {
return String(name, description, append(opts, WithParse(CreateFloat64, AppendFloat64), Value(flag.Float64))...)
}
func CreateFloat64(in string) (value.Value, error) {
out, err := strconv.ParseFloat(in, 10)
if err != nil {
return nil, fmt.Errorf("create float64:%w", err)
}
return value.NewFloat64(out), nil
}
func AppendFloat64(old value.Value, in string) (value.Value, error) {
out, err := strconv.ParseFloat(in, 10)
if err != nil {
return nil, fmt.Errorf("append float64:%w", err)
}
return value.NewFloat64s(append(old.Float64s(), out)), nil
}

31
input/variable/int.go Normal file
View File

@@ -0,0 +1,31 @@
package variable
import (
"fmt"
"strconv"
"gitoa.ru/go-4devs/console/input/flag"
"gitoa.ru/go-4devs/console/input/value"
)
func Int(name, description string, opts ...Option) Variable {
return New(name, description, append(opts, WithParse(CreateInt, AppendInt), Value(flag.Int))...)
}
func AppendInt(old value.Value, in string) (value.Value, error) {
out, err := strconv.Atoi(in)
if err != nil {
return nil, fmt.Errorf("append int:%w", err)
}
return value.NewInts(append(old.Ints(), out)), nil
}
func CreateInt(in string) (value.Value, error) {
out, err := strconv.Atoi(in)
if err != nil {
return nil, fmt.Errorf("create int:%w", err)
}
return value.NewInt(out), nil
}

31
input/variable/int64.go Normal file
View File

@@ -0,0 +1,31 @@
package variable
import (
"fmt"
"strconv"
"gitoa.ru/go-4devs/console/input/flag"
"gitoa.ru/go-4devs/console/input/value"
)
func Int64(name, description string, opts ...Option) Variable {
return String(name, description, append(opts, WithParse(CreateInt64, AppendInt64), Value(flag.Int64))...)
}
func CreateInt64(in string) (value.Value, error) {
out, err := strconv.ParseInt(in, 10, 64)
if err != nil {
return nil, fmt.Errorf("create int64:%w", err)
}
return value.NewInt64(out), nil
}
func AppendInt64(old value.Value, in string) (value.Value, error) {
out, err := strconv.ParseInt(in, 10, 64)
if err != nil {
return nil, fmt.Errorf("append int64:%w", err)
}
return value.NewInt64s(append(old.Int64s(), out)), nil
}

17
input/variable/string.go Normal file
View File

@@ -0,0 +1,17 @@
package variable
import (
"gitoa.ru/go-4devs/console/input/value"
)
func String(name, description string, opts ...Option) Variable {
return New(name, description, opts...)
}
func CreateString(in string) (value.Value, error) {
return value.NewString(in), nil
}
func AppendString(old value.Value, in string) (value.Value, error) {
return value.NewStrings(append(old.Strings(), in)), nil
}

77
input/variable/time.go Normal file
View File

@@ -0,0 +1,77 @@
package variable
import (
"fmt"
"time"
"gitoa.ru/go-4devs/console/input/errs"
"gitoa.ru/go-4devs/console/input/flag"
"gitoa.ru/go-4devs/console/input/value"
)
const (
ParamFormat = "format"
)
func Time(name, description string, opts ...Option) Variable {
return String(name, description, append(opts,
WithParamParse(CreateTime, AppendTime),
WithParam(ParamFormat, RFC3339),
Value(flag.Time),
)...)
}
func RFC3339(in interface{}) error {
v, ok := in.(*string)
if !ok {
return fmt.Errorf("%w: expect *string got %T", errs.ErrWrongType, in)
}
*v = time.RFC3339
return nil
}
func CreateTime(param Param) Create {
var (
formatErr error
format string
)
formatErr = param.Value(ParamFormat, &format)
return func(in string) (value.Value, error) {
if formatErr != nil {
return nil, fmt.Errorf("create format:%w", formatErr)
}
out, err := time.Parse(format, in)
if err != nil {
return nil, fmt.Errorf("create time:%w", err)
}
return value.NewTime(out), nil
}
}
func AppendTime(param Param) Append {
var (
formatErr error
format string
)
formatErr = param.Value(ParamFormat, &format)
return func(old value.Value, in string) (value.Value, error) {
if formatErr != nil {
return nil, fmt.Errorf("append format:%w", formatErr)
}
out, err := time.Parse(format, in)
if err != nil {
return nil, fmt.Errorf("append time:%w", err)
}
return value.NewTimes(append(old.Times(), out)), nil
}
}

31
input/variable/uint.go Normal file
View File

@@ -0,0 +1,31 @@
package variable
import (
"fmt"
"strconv"
"gitoa.ru/go-4devs/console/input/flag"
"gitoa.ru/go-4devs/console/input/value"
)
func Uint(name, description string, opts ...Option) Variable {
return String(name, description, append(opts, WithParse(CreateUint, AppendUint), Value(flag.Uint))...)
}
func CreateUint(in string) (value.Value, error) {
out, err := strconv.ParseUint(in, 10, 64)
if err != nil {
return nil, fmt.Errorf("create uint:%w", err)
}
return value.NewUint(uint(out)), nil
}
func AppendUint(old value.Value, in string) (value.Value, error) {
out, err := strconv.ParseUint(in, 10, 64)
if err != nil {
return nil, fmt.Errorf("append uint:%w", err)
}
return value.NewUints(append(old.Uints(), uint(out))), nil
}

31
input/variable/uint64.go Normal file
View File

@@ -0,0 +1,31 @@
package variable
import (
"fmt"
"strconv"
"gitoa.ru/go-4devs/console/input/flag"
"gitoa.ru/go-4devs/console/input/value"
)
func Uint64(name, descriontion string, opts ...Option) Variable {
return String(name, descriontion, append(opts, WithParse(CreateUint64, AppendUint64), Value(flag.Uint64))...)
}
func CreateUint64(in string) (value.Value, error) {
out, err := strconv.ParseUint(in, 10, 64)
if err != nil {
return nil, fmt.Errorf("create uint64:%w", err)
}
return value.NewUint64(out), nil
}
func AppendUint64(old value.Value, in string) (value.Value, error) {
out, err := strconv.ParseUint(in, 10, 64)
if err != nil {
return nil, fmt.Errorf("append uint64:%w", err)
}
return value.NewUint64s(append(old.Uint64s(), out)), nil
}

167
input/variable/variable.go Normal file
View File

@@ -0,0 +1,167 @@
package variable
import (
"fmt"
"gitoa.ru/go-4devs/console/input/errs"
"gitoa.ru/go-4devs/console/input/flag"
"gitoa.ru/go-4devs/console/input/value"
)
type Option func(*Variable)
func WithType(t ArgType) Option {
return func(v *Variable) {
v.Type = t
}
}
func ArgOption(v *Variable) {
v.Type = TypeOption
}
func ArgArgument(v *Variable) {
v.Type = TypeArgument
}
func Value(in flag.Flag) Option {
return func(v *Variable) {
v.Flag |= in
}
}
func Default(in value.Value) Option {
return func(v *Variable) {
v.Default = in
}
}
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 }
v.create = func(Param) Create { return create }
}
}
func WithParamParse(create func(Param) Create, update func(Param) Append) Option {
return func(v *Variable) {
v.append = update
v.create = create
}
}
func Valid(f ...func(value.Value) error) Option {
return func(v *Variable) {
v.Valid = f
}
}
func Array(o *Variable) {
o.Flag |= flag.Array
}
func WithParam(name string, fn func(interface{}) error) Option {
return func(v *Variable) {
v.params[name] = fn
}
}
type (
Create func(s string) (value.Value, error)
Append func(old value.Value, s string) (value.Value, error)
)
func New(name, description string, opts ...Option) Variable {
res := Variable{
Name: name,
Description: description,
Type: TypeOption,
create: func(Param) Create { return CreateString },
append: func(Param) Append { return AppendString },
params: make(Params),
}
for _, opt := range opts {
opt(&res)
}
return res
}
type Variable struct {
Name string
Description string
Alias string
Flag flag.Flag
Type ArgType
Default value.Value
hidden bool
Valid []func(value.Value) error
params Params
create func(Param) Create
append func(Param) Append
}
func (v Variable) Validate(in value.Value) error {
for _, valid := range v.Valid {
if err := valid(in); err != nil {
return Err(v.Name, v.Type, err)
}
}
return nil
}
func (v Variable) IsHidden() bool {
return v.hidden
}
func (v Variable) IsArray() bool {
return v.Flag.IsArray()
}
func (v Variable) IsRequired() bool {
return v.Flag.IsRequired()
}
func (v Variable) HasDefault() bool {
return v.Default != nil
}
func (v Variable) IsBool() bool {
return v.Flag.IsBool()
}
func (v Variable) HasShort() bool {
return v.Type == TypeOption && len(v.Alias) == 1
}
func (v Variable) Create(s string) (value.Value, error) {
return v.create(v.params)(s)
}
func (v Variable) Append(old value.Value, s string) (value.Value, error) {
return v.append(v.params)(old, s)
}
type Param interface {
Value(name string, v interface{}) error
}
type Params map[string]func(interface{}) error
func (p Params) Value(name string, v interface{}) error {
if p, ok := p[name]; ok {
return p(v)
}
return fmt.Errorf("%w: param %v", errs.ErrNotFound, name)
}

134
list.go
View File

@@ -15,11 +15,15 @@ import (
const defaultLenNamespace = 2 const defaultLenNamespace = 2
//nolint: gochecknoinits //nolint:gochecknoinits
func init() { func init() {
MustRegister(list()) MustRegister(list())
} }
const (
ArgumentNamespace = "namespace"
)
func list() *Command { func list() *Command {
return &Command{ return &Command{
Name: CommandList, Name: CommandList,
@@ -32,71 +36,15 @@ You can also display the commands for a specific namespace:
You can also output the information in other formats by using the <comment>--format</comment> option: You can also output the information in other formats by using the <comment>--format</comment> option:
<info>{{ .Bin }} {{ .Name }} --format=xml</info> <info>{{ .Bin }} {{ .Name }} --format=xml</info>
`, `,
Execute: func(ctx context.Context, in input.Input, out output.Output) error { Execute: executeList,
ns := in.Argument(ctx, "namespace").String()
format := in.Option(ctx, helpOptFormat).String()
des, err := descriptor.Find(format)
if err != nil {
return err
}
cmds := Commands()
commands := descriptor.Commands{
Namespace: ns,
Definition: Default(input.NewDefinition()),
}
groups := make(map[string]*descriptor.NSCommand)
namespaces := make([]string, 0, len(cmds))
empty := descriptor.NSCommand{}
for _, name := range cmds {
if ns != "" && !strings.HasPrefix(name, ns+":") {
continue
}
cmd, _ := Find(name)
if cmd.Hidden {
continue
}
gn := strings.SplitN(name, ":", 2)
if len(gn) != defaultLenNamespace {
empty.Append(cmd.Name, cmd.Description)
continue
}
if _, ok := groups[gn[0]]; !ok {
groups[gn[0]] = &descriptor.NSCommand{
Name: gn[0],
}
namespaces = append(namespaces, gn[0])
}
groups[gn[0]].Append(name, cmd.Description)
}
if len(empty.Commands) > 0 {
commands.Commands = append(commands.Commands, empty)
}
for _, name := range namespaces {
commands.Commands = append(commands.Commands, *groups[name])
}
if ns != "" && len(commands.Commands) == 0 {
return fmt.Errorf("%w: namespace %s", ErrNotFound, ns)
}
return des.Commands(ctx, out, commands)
},
Configure: func(ctx context.Context, config *input.Definition) error { Configure: func(ctx context.Context, config *input.Definition) error {
formats := descriptor.Descriptors() formats := descriptor.Descriptors()
config. config.
SetArguments( SetArguments(
argument.New("namespace", "The namespace name"), argument.String(ArgumentNamespace, "The namespace name"),
). ).
SetOptions( SetOptions(
option.New(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.Required,
option.Default(formats[0]), option.Default(formats[0]),
option.Valid( option.Valid(
@@ -110,3 +58,69 @@ 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, ArgumentNamespace).String()
format := in.Option(ctx, OptionFormat).String()
des, err := descriptor.Find(format)
if err != nil {
return fmt.Errorf("find descriptor: %w", err)
}
cmds := Commands()
commands := descriptor.Commands{
Namespace: ns,
Definition: Default(input.NewDefinition()),
}
groups := make(map[string]*descriptor.NSCommand)
namespaces := make([]string, 0, len(cmds))
empty := descriptor.NSCommand{}
for _, name := range cmds {
if ns != "" && !strings.HasPrefix(name, ns+":") {
continue
}
cmd, _ := Find(name)
if cmd.Hidden {
continue
}
gn := strings.SplitN(name, ":", 2)
if len(gn) != defaultLenNamespace {
empty.Append(cmd.Name, cmd.Description)
continue
}
if _, ok := groups[gn[0]]; !ok {
groups[gn[0]] = &descriptor.NSCommand{
Name: gn[0],
}
namespaces = append(namespaces, gn[0])
}
groups[gn[0]].Append(name, cmd.Description)
}
if len(empty.Commands) > 0 {
commands.Commands = append(commands.Commands, empty)
}
for _, name := range namespaces {
commands.Commands = append(commands.Commands, *groups[name])
}
if ns != "" && len(commands.Commands) == 0 {
return fmt.Errorf("%w: namespace %s", ErrNotFound, ns)
}
if err := des.Commands(ctx, out, commands); err != nil {
return fmt.Errorf("descriptor:%w", err)
}
return nil
}

View File

@@ -11,7 +11,7 @@ import (
var ErrDescriptorNotFound = errors.New("descriptor not found") var ErrDescriptorNotFound = errors.New("descriptor not found")
//nolint: gochecknoglobals //nolint:gochecknoglobals
var ( var (
descriptors = map[string]Descriptor{ descriptors = map[string]Descriptor{
"txt": &txt{}, "txt": &txt{},

View File

@@ -10,8 +10,8 @@ import (
"time" "time"
"gitoa.ru/go-4devs/console/input" "gitoa.ru/go-4devs/console/input"
"gitoa.ru/go-4devs/console/input/flag"
"gitoa.ru/go-4devs/console/input/value" "gitoa.ru/go-4devs/console/input/value"
"gitoa.ru/go-4devs/console/input/value/flag"
"gitoa.ru/go-4devs/console/output" "gitoa.ru/go-4devs/console/output"
) )
@@ -43,7 +43,7 @@ var (
{{- help . }} {{- help . }}
`)) `))
txtListTempkate = template.Must(template.New("txt_list"). txtListTemplate = template.Must(template.New("txt_list").
Funcs(txtFunc). Funcs(txtFunc).
Parse(`<comment>Usage:</comment> Parse(`<comment>Usage:</comment>
command [options] [arguments] command [options] [arguments]
@@ -58,7 +58,7 @@ func (t *txt) Command(ctx context.Context, out output.Output, cmd Command) error
var tpl bytes.Buffer var tpl bytes.Buffer
if err := txtHelpTemplate.Execute(&tpl, cmd); err != nil { if err := txtHelpTemplate.Execute(&tpl, cmd); err != nil {
return err return fmt.Errorf("execute txt help tpl:%w", err)
} }
out.Println(ctx, tpl.String()) out.Println(ctx, tpl.String())
@@ -69,8 +69,8 @@ func (t *txt) Command(ctx context.Context, out output.Output, cmd Command) error
func (t *txt) Commands(ctx context.Context, out output.Output, cmds Commands) error { func (t *txt) Commands(ctx context.Context, out output.Output, cmds Commands) error {
var buf bytes.Buffer var buf bytes.Buffer
if err := txtListTempkate.Execute(&buf, cmds); err != nil { if err := txtListTemplate.Execute(&buf, cmds); err != nil {
return err return fmt.Errorf("execute txt list tpl:%w", err)
} }
out.Println(ctx, buf.String()) out.Println(ctx, buf.String())
@@ -78,36 +78,37 @@ func (t *txt) Commands(ctx context.Context, out output.Output, cmds Commands) er
return nil return nil
} }
func txtDefaultArray(v value.Value, f flag.Flag) string { //nolint:cyclop
st := v.Strings() func txtDefaultArray(val value.Value, fl flag.Flag) string {
st := val.Strings()
switch { switch {
case f.IsInt(): case fl.IsInt():
for _, i := range v.Ints() { for _, i := range val.Ints() {
st = append(st, strconv.Itoa(i)) st = append(st, strconv.Itoa(i))
} }
case f.IsInt64(): case fl.IsInt64():
for _, i := range v.Int64s() { for _, i := range val.Int64s() {
st = append(st, strconv.FormatInt(i, 10)) st = append(st, strconv.FormatInt(i, 10))
} }
case f.IsUint(): case fl.IsUint():
for _, u := range v.Uints() { for _, u := range val.Uints() {
st = append(st, strconv.FormatUint(uint64(u), 10)) st = append(st, strconv.FormatUint(uint64(u), 10))
} }
case f.IsUint64(): case fl.IsUint64():
for _, u := range v.Uint64s() { for _, u := range val.Uint64s() {
st = append(st, strconv.FormatUint(u, 10)) st = append(st, strconv.FormatUint(u, 10))
} }
case f.IsFloat64(): case fl.IsFloat64():
for _, f := range v.Float64s() { for _, f := range val.Float64s() {
st = append(st, strconv.FormatFloat(f, 'g', -1, 64)) st = append(st, strconv.FormatFloat(f, 'g', -1, 64))
} }
case f.IsDuration(): case fl.IsDuration():
for _, d := range v.Durations() { for _, d := range val.Durations() {
st = append(st, d.String()) st = append(st, d.String())
} }
case f.IsTime(): case fl.IsTime():
for _, d := range v.Times() { for _, d := range val.Times() {
st = append(st, d.Format(time.RFC3339)) st = append(st, d.Format(time.RFC3339))
} }
} }
@@ -115,32 +116,33 @@ func txtDefaultArray(v value.Value, f flag.Flag) string {
return strings.Join(st, ",") return strings.Join(st, ",")
} }
func txtDefault(v value.Value, f flag.Flag) []byte { //nolint:cyclop
func txtDefault(val value.Value, fl flag.Flag) []byte {
var buf bytes.Buffer var buf bytes.Buffer
buf.WriteString("<comment> [default: ") buf.WriteString("<comment> [default: ")
switch { switch {
case f.IsArray(): case fl.IsArray():
buf.WriteString(txtDefaultArray(v, f)) buf.WriteString(txtDefaultArray(val, fl))
case f.IsInt(): case fl.IsInt():
buf.WriteString(strconv.Itoa(v.Int())) buf.WriteString(strconv.Itoa(val.Int()))
case f.IsInt64(): case fl.IsInt64():
buf.WriteString(strconv.FormatInt(v.Int64(), 10)) buf.WriteString(strconv.FormatInt(val.Int64(), 10))
case f.IsUint(): case fl.IsUint():
buf.WriteString(strconv.FormatUint(uint64(v.Uint()), 10)) buf.WriteString(strconv.FormatUint(uint64(val.Uint()), 10))
case f.IsUint64(): case fl.IsUint64():
buf.WriteString(strconv.FormatUint(v.Uint64(), 10)) buf.WriteString(strconv.FormatUint(val.Uint64(), 10))
case f.IsFloat64(): case fl.IsFloat64():
buf.WriteString(strconv.FormatFloat(v.Float64(), 'g', -1, 64)) buf.WriteString(strconv.FormatFloat(val.Float64(), 'g', -1, 64))
case f.IsDuration(): case fl.IsDuration():
buf.WriteString(v.Duration().String()) buf.WriteString(val.Duration().String())
case f.IsTime(): case fl.IsTime():
buf.WriteString(v.Time().Format(time.RFC3339)) buf.WriteString(val.Time().Format(time.RFC3339))
case f.IsAny(): case fl.IsAny():
buf.WriteString(fmt.Sprint(v.Any())) buf.WriteString(fmt.Sprint(val.Any()))
default: default:
buf.WriteString(v.String()) buf.WriteString(val.String())
} }
buf.WriteString("]</comment>") buf.WriteString("]</comment>")
@@ -207,6 +209,9 @@ func txtDefinitionOption(maxLen int, def *input.Definition) string {
for _, name := range opts { for _, name := range opts {
opt, _ := def.Option(name) opt, _ := def.Option(name)
if opt.IsHidden() {
continue
}
var op bytes.Buffer var op bytes.Buffer
@@ -214,7 +219,7 @@ func txtDefinitionOption(maxLen int, def *input.Definition) string {
if opt.HasShort() { if opt.HasShort() {
op.WriteString("-") op.WriteString("-")
op.WriteString(opt.Short) op.WriteString(opt.Alias)
op.WriteString(", ") op.WriteString(", ")
} else { } else {
op.WriteString(" ") op.WriteString(" ")
@@ -354,18 +359,18 @@ func totalWidth(def *input.Definition) int {
for _, name := range def.Options() { for _, name := range def.Options() {
opt, _ := def.Option(name) opt, _ := def.Option(name)
l := len(opt.Name) + 6 current := len(opt.Name) + 6
if !opt.IsBool() { if !opt.IsBool() {
l = l*2 + 1 current = current*2 + 1
} }
if opt.HasDefault() { if opt.HasDefault() {
l += 2 current += 2
} }
if l > max { if current > max {
max = l max = current
} }
} }

View File

@@ -8,7 +8,6 @@ import (
"gitoa.ru/go-4devs/console/output/style" "gitoa.ru/go-4devs/console/output/style"
) )
//nolint: gochecknoglobals
var re = regexp.MustCompile(`<(([a-z][^<>]+)|/([a-z][^<>]+)?)>`) var re = regexp.MustCompile(`<(([a-z][^<>]+)|/([a-z][^<>]+)?)>`)
func WithStyle(styles func(string) (style.Style, error)) func(*Formatter) { func WithStyle(styles func(string) (style.Style, error)) func(*Formatter) {
@@ -18,15 +17,15 @@ func WithStyle(styles func(string) (style.Style, error)) func(*Formatter) {
} }
func New(opts ...func(*Formatter)) *Formatter { func New(opts ...func(*Formatter)) *Formatter {
f := &Formatter{ formatter := &Formatter{
styles: style.Find, styles: style.Find,
} }
for _, opt := range opts { for _, opt := range opts {
opt(f) opt(formatter)
} }
return f return formatter
} }
type Formatter struct { type Formatter struct {

View File

@@ -8,6 +8,8 @@ import (
) )
func TestFormatter(t *testing.T) { func TestFormatter(t *testing.T) {
t.Parallel()
ctx := context.Background() ctx := context.Background()
formatter := formatter.New() formatter := formatter.New()

View File

@@ -8,6 +8,8 @@ import (
) )
func TestNone(t *testing.T) { func TestNone(t *testing.T) {
t.Parallel()
ctx := context.Background() ctx := context.Background()
none := formatter.None() none := formatter.None()

View File

@@ -63,15 +63,13 @@ func (o Output) Write(b []byte) (int, error) {
} }
func (o Output) Writer(ctx context.Context, verb verbosity.Verbosity) io.Writer { func (o Output) Writer(ctx context.Context, verb verbosity.Verbosity) io.Writer {
return verbosityWriter{ctx, o, verb} return verbosityWriter(func(b []byte) (int, error) {
return o(ctx, verb, string(b))
})
} }
type verbosityWriter struct { type verbosityWriter func(b []byte) (int, error)
ctx context.Context
out Output
verb verbosity.Verbosity
}
func (w verbosityWriter) Write(b []byte) (int, error) { func (w verbosityWriter) Write(b []byte) (int, error) {
return w.out(w.ctx, w.verb, string(b)) return w(b)
} }

View File

@@ -28,13 +28,13 @@ const (
type Option string type Option string
func (o Option) Apply(action int) string { func (o Option) Apply(action int) string {
v := string(o) out := string(o)
switch action { switch action {
case ActionSet: case ActionSet:
return v[0:1] return out[0:1]
case ActionUnset: case ActionUnset:
return v[1:] return out[1:]
} }
return "" return ""

View File

@@ -7,7 +7,7 @@ import (
"sync" "sync"
) )
//nolint: gochecknoglobals //nolint:gochecknoglobals
var ( var (
styles = map[string]Style{ styles = map[string]Style{
"error": {Foreground: White, Background: Red}, "error": {Foreground: White, Background: Red},

View File

@@ -41,6 +41,11 @@ func FormatString(_ verbosity.Verbosity, msg string, kv ...label.KeyValue) strin
func New(w io.Writer, format func(verb verbosity.Verbosity, msg string, kv ...label.KeyValue) string) Output { func New(w io.Writer, format func(verb verbosity.Verbosity, msg string, kv ...label.KeyValue) string) Output {
return func(ctx context.Context, verb verbosity.Verbosity, msg string, kv ...label.KeyValue) (int, error) { return func(ctx context.Context, verb verbosity.Verbosity, msg string, kv ...label.KeyValue) (int, error) {
return fmt.Fprint(w, format(verb, msg, kv...)) out, err := fmt.Fprint(w, format(verb, msg, kv...))
if err != nil {
return 0, fmt.Errorf("writer fprint:%w", err)
}
return out, nil
} }
} }

View File

@@ -10,6 +10,8 @@ import (
) )
func TestNew(t *testing.T) { func TestNew(t *testing.T) {
t.Parallel()
ctx := context.Background() ctx := context.Background()
buf := bytes.Buffer{} buf := bytes.Buffer{}
wr := output.New(&buf, output.FormatString) wr := output.New(&buf, output.FormatString)

View File

@@ -20,31 +20,31 @@ var (
ErrCommandDuplicate = errors.New("console: duplicate command") ErrCommandDuplicate = errors.New("console: duplicate command")
) )
//nolint: gochecknoglobals //nolint:gochecknoglobals
var ( var (
commandsMu sync.RWMutex commandsMu sync.RWMutex
commands = make(map[string]*Command) commands = make(map[string]*Command)
findCommand = regexp.MustCompile("([^:]+|)") findCommand = regexp.MustCompile("([^:]+|)")
) )
type ErrorAlternatives struct { type AlternativesError struct {
alt []string alt []string
err error err error
} }
func (e ErrorAlternatives) Error() string { func (e AlternativesError) Error() string {
return fmt.Sprintf("%s, alternatives: [%s]", e.err, strings.Join(e.alt, ",")) return fmt.Sprintf("%s, alternatives: [%s]", e.err, strings.Join(e.alt, ","))
} }
func (e ErrorAlternatives) Is(err error) bool { func (e AlternativesError) Is(err error) bool {
return errors.Is(e.err, err) return errors.Is(e.err, err)
} }
func (e ErrorAlternatives) Unwrap() error { func (e AlternativesError) Unwrap() error {
return e.err return e.err
} }
func (e ErrorAlternatives) Alternatives() []string { func (e AlternativesError) Alternatives() []string {
return e.alt return e.alt
} }
@@ -115,7 +115,7 @@ func Find(name string) (*Command, error) {
cmdRegexp, err := regexp.Compile("^" + nameRegexp + "$") cmdRegexp, err := regexp.Compile("^" + nameRegexp + "$")
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("find by regexp:%w", err)
} }
for name := range commands { for name := range commands {
@@ -134,7 +134,7 @@ func Find(name string) (*Command, error) {
names[i] = findCommands[i].Name names[i] = findCommands[i].Name
} }
return nil, ErrorAlternatives{alt: names, err: ErrNotFound} return nil, AlternativesError{alt: names, err: ErrNotFound}
} }
return nil, ErrNotFound return nil, ErrNotFound

View File

@@ -7,6 +7,8 @@ import (
) )
func TestFind(t *testing.T) { func TestFind(t *testing.T) {
t.Parallel()
cases := map[string]string{ cases := map[string]string{
"fdevs:console:test": "fdevs:console:test", "fdevs:console:test": "fdevs:console:test",
"fd:c:t": "fdevs:console:test", "fd:c:t": "fdevs:console:test",
@@ -18,13 +20,13 @@ func TestFind(t *testing.T) {
for name, ex := range cases { for name, ex := range cases {
res, err := console.Find(name) res, err := console.Find(name)
if err != nil { if err != nil {
t.Errorf("expect <nil> err, got:%s", err) t.Errorf("%v expect <nil> err, got:%s", name, err)
continue continue
} }
if res.Name != ex { if res.Name != ex {
t.Errorf("expect: %s, got: %s", ex, res) t.Errorf("%v expect: %s, got: %s", name, ex, res)
} }
} }
} }