complete
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
This commit is contained in:
parent
29add63cc6
commit
05720a433e
61
flag.go
61
flag.go
@ -5,17 +5,26 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"time"
|
||||||
|
|
||||||
"github.com/unistack-org/micro/v3/config"
|
"github.com/unistack-org/micro/v3/config"
|
||||||
rutil "github.com/unistack-org/micro/v3/util/reflect"
|
rutil "github.com/unistack-org/micro/v3/util/reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
DefaultStructTag = "flag"
|
DefaultStructTag = "flag"
|
||||||
ErrInvalidStruct = errors.New("invalid struct specified")
|
ErrInvalidValue = errors.New("invalid value specified")
|
||||||
|
DefaultSliceDelim = ","
|
||||||
|
DefaultMapDelim = ","
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
var (
|
||||||
|
timeTimeKind = reflect.TypeOf(time.Time{}).Kind()
|
||||||
|
timeDurationKind = reflect.TypeOf(time.Duration(0)).Kind()
|
||||||
|
)
|
||||||
|
*/
|
||||||
|
|
||||||
type flagConfig struct {
|
type flagConfig struct {
|
||||||
opts config.Options
|
opts config.Options
|
||||||
}
|
}
|
||||||
@ -41,15 +50,51 @@ func (c *flagConfig) Init(opts ...config.Option) error {
|
|||||||
}
|
}
|
||||||
fn, fv, fd := getFlagOpts(tf)
|
fn, fv, fd := getFlagOpts(tf)
|
||||||
|
|
||||||
|
rcheck := true
|
||||||
|
switch sf.Value.Interface().(type) {
|
||||||
|
case time.Duration:
|
||||||
|
err = c.flagDuration(sf.Value, fn, fv, fd)
|
||||||
|
rcheck = false
|
||||||
|
case time.Time:
|
||||||
|
err = c.flagTime(sf.Value, fn, fv, fd)
|
||||||
|
rcheck = false
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !rcheck {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if sf.Value.Kind() == reflect.Ptr {
|
||||||
|
sf.Value = sf.Value.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
switch sf.Value.Kind() {
|
switch sf.Value.Kind() {
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
v := sf.Value.Addr().Interface().(*string)
|
err = c.flagString(sf.Value, fn, fv, fd)
|
||||||
flag.StringVar(v, fn, fv, fd)
|
|
||||||
case reflect.Bool:
|
case reflect.Bool:
|
||||||
v := sf.Value.Addr().Interface().(*bool)
|
err = c.flagBool(sf.Value, fn, fv, fd)
|
||||||
i, _ := strconv.ParseBool(fv)
|
case reflect.Int:
|
||||||
flag.BoolVar(v, fn, i, fd)
|
err = c.flagInt(sf.Value, fn, fv, fd)
|
||||||
|
case reflect.Int64:
|
||||||
|
err = c.flagInt64(sf.Value, fn, fv, fd)
|
||||||
|
case reflect.Float64:
|
||||||
|
err = c.flagFloat64(sf.Value, fn, fv, fd)
|
||||||
|
case reflect.Uint:
|
||||||
|
err = c.flagUint(sf.Value, fn, fv, fd)
|
||||||
|
case reflect.Uint64:
|
||||||
|
err = c.flagUint64(sf.Value, fn, fv, fd)
|
||||||
|
case reflect.Slice:
|
||||||
|
err = c.flagSlice(sf.Value, fn, fv, fd)
|
||||||
|
case reflect.Map:
|
||||||
|
err = c.flagMap(sf.Value, fn, fv, fd)
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
51
flag_test.go
51
flag_test.go
@ -1,49 +1,46 @@
|
|||||||
package flag
|
package flag
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
"context"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
|
||||||
"strconv"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
rutil "github.com/unistack-org/micro/v3/util/reflect"
|
"github.com/unistack-org/micro/v3/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLoad(t *testing.T) {
|
func TestLoad(t *testing.T) {
|
||||||
os.Args = append(os.Args, "-broker", "5566:33")
|
os.Args = append(os.Args, "-broker", "5566:33")
|
||||||
type config struct {
|
os.Args = append(os.Args, "-verbose")
|
||||||
Broker string `flag:"name=broker,desc='description with, comma',default='127.0.0.1:9092'"`
|
os.Args = append(os.Args, "-wait", "5s")
|
||||||
Verbose bool `flag:"name=verbose,desc='verbose output',default='false value'"`
|
os.Args = append(os.Args, "-addr", "33,44")
|
||||||
|
os.Args = append(os.Args, "-time", time.RFC822)
|
||||||
|
type Config struct {
|
||||||
|
Broker string `flag:"name=broker,desc='description with, comma',default='127.0.0.1:9092'"`
|
||||||
|
Verbose bool `flag:"name=verbose,desc='verbose output',default='false'"`
|
||||||
|
Addr []string `flag:"name=addr,desc='addrs',default='127.0.0.1:9092'"`
|
||||||
|
Wait time.Duration `flag:"name=wait,desc='wait time',default='2s'"`
|
||||||
|
Time time.Time `flag:"name=time,desc='some time',default='02 Jan 06 15:04 MST'"`
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg := &config{}
|
ctx := context.Background()
|
||||||
|
cfg := &Config{}
|
||||||
|
|
||||||
fields, err := rutil.StructFields(cfg)
|
c := NewConfig(config.Struct(cfg), TimeFormat(time.RFC822))
|
||||||
if err != nil {
|
if err := c.Init(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, sf := range fields {
|
if err := c.Load(ctx); err != nil {
|
||||||
tf, ok := sf.Field.Tag.Lookup("flag")
|
t.Fatal(err)
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fn, fv, fd := getFlagOpts(tf)
|
|
||||||
|
|
||||||
switch sf.Value.Kind() {
|
|
||||||
case reflect.String:
|
|
||||||
v := sf.Value.Addr().Interface().(*string)
|
|
||||||
flag.StringVar(v, fn, fv, fd)
|
|
||||||
case reflect.Bool:
|
|
||||||
v := sf.Value.Addr().Interface().(*bool)
|
|
||||||
i, _ := strconv.ParseBool(fv)
|
|
||||||
flag.BoolVar(v, fn, i, fd)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
flag.Parse()
|
|
||||||
if cfg.Broker != "5566:33" {
|
if cfg.Broker != "5566:33" {
|
||||||
t.Fatalf("failed to parse flags broker value invalid: %#+v", cfg)
|
t.Fatalf("failed to parse flags broker value invalid: %#+v", cfg)
|
||||||
}
|
}
|
||||||
|
if tf := cfg.Time.Format(time.RFC822); tf != "02 Jan 06 14:32 MSK" {
|
||||||
|
t.Fatalf("parse time error: %v", cfg.Time)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("cfg %#+v", cfg)
|
||||||
}
|
}
|
||||||
|
2
go.mod
2
go.mod
@ -2,4 +2,4 @@ module github.com/unistack-org/micro-config-flag/v3
|
|||||||
|
|
||||||
go 1.16
|
go 1.16
|
||||||
|
|
||||||
require github.com/unistack-org/micro/v3 v3.3.22
|
require github.com/unistack-org/micro/v3 v3.3.23
|
||||||
|
4
go.sum
4
go.sum
@ -5,8 +5,8 @@ github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
|||||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||||
github.com/silas/dag v0.0.0-20210121180416-41cf55125c34/go.mod h1:7RTUFBdIRC9nZ7/3RyRNH1bdqIShrDejd1YbLwgPS+I=
|
github.com/silas/dag v0.0.0-20210121180416-41cf55125c34/go.mod h1:7RTUFBdIRC9nZ7/3RyRNH1bdqIShrDejd1YbLwgPS+I=
|
||||||
github.com/unistack-org/micro/v3 v3.3.22 h1:4mY+lhqW6N/3A0LSfAnGHE65TakGOrbU144/FQEjZIs=
|
github.com/unistack-org/micro/v3 v3.3.23 h1:iQtvVF4p+HPtWgm/zPt7+gN78EQMf1rHSMppxYlbRHQ=
|
||||||
github.com/unistack-org/micro/v3 v3.3.22/go.mod h1:LXmPfbJnJNvL0kQs8HfnkV3Wya2Wb+C7keVq++RCZnk=
|
github.com/unistack-org/micro/v3 v3.3.23/go.mod h1:LXmPfbJnJNvL0kQs8HfnkV3Wya2Wb+C7keVq++RCZnk=
|
||||||
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
26
options.go
Normal file
26
options.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package flag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/unistack-org/micro/v3/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
type sliceDelimKey struct{}
|
||||||
|
|
||||||
|
// SliceDelim set the slice delimeter
|
||||||
|
func SliceDelim(s string) config.Option {
|
||||||
|
return config.SetOption(sliceDelimKey{}, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
type mapDelimKey struct{}
|
||||||
|
|
||||||
|
// MapDelim set the map delimeter
|
||||||
|
func MapDelim(s string) config.Option {
|
||||||
|
return config.SetOption(mapDelimKey{}, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
type timeFormatKey struct{}
|
||||||
|
|
||||||
|
// TimeFormat set the time format
|
||||||
|
func TimeFormat(s string) config.Option {
|
||||||
|
return config.SetOption(timeFormatKey{}, s)
|
||||||
|
}
|
194
util.go
194
util.go
@ -1,9 +1,203 @@
|
|||||||
package flag
|
package flag
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"flag"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (c *flagConfig) flagSlice(v reflect.Value, fn, fv, fd string) error {
|
||||||
|
delim := DefaultSliceDelim
|
||||||
|
if c.opts.Context != nil {
|
||||||
|
if d, ok := c.opts.Context.Value(sliceDelimKey{}).(string); ok {
|
||||||
|
delim = d
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
flag.Func(fn, fd, func(s string) error {
|
||||||
|
p := strings.Split(s, delim)
|
||||||
|
v.Set(reflect.MakeSlice(v.Type(), len(p), len(p)))
|
||||||
|
switch v.Type().Elem().Kind() {
|
||||||
|
case reflect.Int, reflect.Int64:
|
||||||
|
for idx := range p {
|
||||||
|
i, err := strconv.ParseInt(p[idx], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.Index(idx).SetInt(i)
|
||||||
|
}
|
||||||
|
case reflect.Uint, reflect.Uint64:
|
||||||
|
for idx := range p {
|
||||||
|
i, err := strconv.ParseUint(p[idx], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.Index(idx).SetUint(i)
|
||||||
|
}
|
||||||
|
case reflect.Float64:
|
||||||
|
for idx := range p {
|
||||||
|
i, err := strconv.ParseFloat(p[idx], 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.Index(idx).SetFloat(i)
|
||||||
|
}
|
||||||
|
case reflect.Bool:
|
||||||
|
for idx := range p {
|
||||||
|
i, err := strconv.ParseBool(p[idx])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.Index(idx).SetBool(i)
|
||||||
|
}
|
||||||
|
case reflect.String:
|
||||||
|
for idx := range p {
|
||||||
|
v.Index(idx).SetString(p[idx])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *flagConfig) flagMap(v reflect.Value, fn, fv, fd string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *flagConfig) flagTime(v reflect.Value, fn, fv, fd string) error {
|
||||||
|
var format string
|
||||||
|
if c.opts.Context != nil {
|
||||||
|
if tf, ok := c.opts.Context.Value(timeFormatKey{}).(string); ok {
|
||||||
|
format = tf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if format == "" {
|
||||||
|
return ErrInvalidValue
|
||||||
|
}
|
||||||
|
flag.Func(fn, fd, func(s string) error {
|
||||||
|
t, err := time.Parse(s, format)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.Set(reflect.ValueOf(t))
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *flagConfig) flagDuration(v reflect.Value, fn, fv, fd string) error {
|
||||||
|
nv, ok := v.Addr().Interface().(*time.Duration)
|
||||||
|
if !ok {
|
||||||
|
return ErrInvalidValue
|
||||||
|
}
|
||||||
|
i, err := time.ParseDuration(fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
flag.DurationVar(nv, fn, i, fd)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *flagConfig) flagBool(v reflect.Value, fn, fv, fd string) error {
|
||||||
|
nv, ok := v.Addr().Interface().(*bool)
|
||||||
|
if !ok {
|
||||||
|
return ErrInvalidValue
|
||||||
|
}
|
||||||
|
i, err := strconv.ParseBool(fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
flag.BoolVar(nv, fn, i, fd)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *flagConfig) flagString(v reflect.Value, fn, fv, fd string) error {
|
||||||
|
nv, ok := v.Addr().Interface().(*string)
|
||||||
|
if !ok {
|
||||||
|
return ErrInvalidValue
|
||||||
|
}
|
||||||
|
flag.StringVar(nv, fn, fv, fd)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *flagConfig) flagInt(v reflect.Value, fn, fv, fd string) error {
|
||||||
|
nv, ok := v.Addr().Interface().(*int)
|
||||||
|
if !ok {
|
||||||
|
return ErrInvalidValue
|
||||||
|
}
|
||||||
|
i, err := strconv.ParseInt(fd, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
flag.IntVar(nv, fn, int(i), fd)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *flagConfig) flagInt64(v reflect.Value, fn, fv, fd string) error {
|
||||||
|
nv, ok := v.Addr().Interface().(*int64)
|
||||||
|
if !ok {
|
||||||
|
return ErrInvalidValue
|
||||||
|
}
|
||||||
|
i, err := strconv.ParseInt(fd, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
flag.Int64Var(nv, fn, int64(i), fd)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *flagConfig) flagUint(v reflect.Value, fn, fv, fd string) error {
|
||||||
|
nv, ok := v.Addr().Interface().(*uint)
|
||||||
|
if !ok {
|
||||||
|
return ErrInvalidValue
|
||||||
|
}
|
||||||
|
i, err := strconv.ParseUint(fd, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
flag.UintVar(nv, fn, uint(i), fd)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *flagConfig) flagUint64(v reflect.Value, fn, fv, fd string) error {
|
||||||
|
nv, ok := v.Addr().Interface().(*uint64)
|
||||||
|
if !ok {
|
||||||
|
return ErrInvalidValue
|
||||||
|
}
|
||||||
|
i, err := strconv.ParseUint(fd, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
flag.Uint64Var(nv, fn, uint64(i), fd)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *flagConfig) flagFloat64(v reflect.Value, fn, fv, fd string) error {
|
||||||
|
nv, ok := v.Addr().Interface().(*float64)
|
||||||
|
if !ok {
|
||||||
|
return ErrInvalidValue
|
||||||
|
}
|
||||||
|
i, err := strconv.ParseFloat(fd, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
flag.Float64Var(nv, fn, float64(i), fd)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *flagConfig) flagStringSlice(v reflect.Value, fn, fv, fd string) error {
|
||||||
|
nv, ok := v.Addr().Interface().(*string)
|
||||||
|
if !ok {
|
||||||
|
return ErrInvalidValue
|
||||||
|
}
|
||||||
|
flag.StringVar(nv, fn, fv, fd)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func getFlagOpts(tf string) (string, string, string) {
|
func getFlagOpts(tf string) (string, string, string) {
|
||||||
ret := make([]string, 3)
|
ret := make([]string, 3)
|
||||||
vals := strings.Split(tf, ",")
|
vals := strings.Split(tf, ",")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user