Vasiliy Tolstov 1dd7e71881 add check for already defined flag
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2022-03-25 14:06:21 +03:00

154 lines
3.0 KiB
Go

package flag // import "go.unistack.org/micro-config-flag/v3"
import (
"context"
"errors"
"flag"
"fmt"
"reflect"
"time"
"go.unistack.org/micro/v3/config"
rutil "go.unistack.org/micro/v3/util/reflect"
)
var (
DefaultStructTag = "flag"
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 {
opts config.Options
}
func (c *flagConfig) Options() config.Options {
return c.opts
}
func (c *flagConfig) Init(opts ...config.Option) error {
for _, o := range opts {
o(&c.opts)
}
fields, err := rutil.StructFields(c.opts.Struct)
if err != nil {
return err
}
for _, sf := range fields {
tf, ok := sf.Field.Tag.Lookup(c.opts.StructTag)
if !ok {
continue
}
fn, fd, fv := getFlagOpts(tf)
rcheck := true
if !sf.Value.IsValid() {
continue
}
vi := sf.Value.Interface()
if vi == nil {
continue
}
if f := flag.Lookup(fn); f != nil {
return nil
}
switch vi.(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 {
c.opts.Logger.Errorf(c.opts.Context, "flag init error: %v", err)
if !c.opts.AllowFail {
return err
}
return nil
}
if !rcheck {
continue
}
if sf.Value.Kind() == reflect.Ptr {
sf.Value = sf.Value.Elem()
}
switch sf.Value.Kind() {
case reflect.String:
err = c.flagString(sf.Value, fn, fv, fd)
case reflect.Bool:
err = c.flagBool(sf.Value, fn, fv, fd)
case reflect.Int:
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 {
c.opts.Logger.Errorf(c.opts.Context, "flag init error: %v", err)
if !c.opts.AllowFail {
return err
}
return nil
}
}
return nil
}
func (c *flagConfig) Load(ctx context.Context, opts ...config.LoadOption) error {
options := config.NewLoadOptions(opts...)
_ = options
// TODO: allow merge, append and so
flag.Parse()
return nil
}
func (c *flagConfig) Save(ctx context.Context, opts ...config.SaveOption) error {
return nil
}
func (c *flagConfig) String() string {
return "flag"
}
func (c *flagConfig) Name() string {
return c.opts.Name
}
func (c *flagConfig) Watch(ctx context.Context, opts ...config.WatchOption) (config.Watcher, error) {
return nil, fmt.Errorf("not implemented")
}
func NewConfig(opts ...config.Option) config.Config {
options := config.NewOptions(opts...)
if len(options.StructTag) == 0 {
options.StructTag = DefaultStructTag
}
return &flagConfig{opts: options}
}