diff --git a/config/default.go b/config/default.go index 39cc3ff1..e8c91b89 100644 --- a/config/default.go +++ b/config/default.go @@ -24,19 +24,19 @@ func (c *defaultConfig) Init(opts ...Option) error { func (c *defaultConfig) Load(ctx context.Context) error { for _, fn := range c.opts.BeforeLoad { - if err := fn(ctx, c); err != nil { + if err := fn(ctx, c); err != nil && !c.opts.AllowFail { return err } } valueOf := reflect.ValueOf(c.opts.Struct) - if err := c.fillValues(ctx, valueOf); err != nil { + if err := c.fillValues(ctx, valueOf); err != nil && !c.opts.AllowFail { return err } for _, fn := range c.opts.AfterLoad { - if err := fn(ctx, c); err != nil { + if err := fn(ctx, c); err != nil && !c.opts.AllowFail { return err } } @@ -45,6 +45,9 @@ func (c *defaultConfig) Load(ctx context.Context) error { } func (c *defaultConfig) fillValue(ctx context.Context, value reflect.Value, val string) error { + if !IsEmpty(value) { + return nil + } switch value.Kind() { case reflect.Map: t := value.Type() @@ -221,13 +224,13 @@ func (c *defaultConfig) fillValues(ctx context.Context, valueOf reflect.Value) e func (c *defaultConfig) Save(ctx context.Context) error { for _, fn := range c.opts.BeforeSave { - if err := fn(ctx, c); err != nil { + if err := fn(ctx, c); err != nil && !c.opts.AllowFail { return err } } for _, fn := range c.opts.AfterSave { - if err := fn(ctx, c); err != nil { + if err := fn(ctx, c); err != nil && !c.opts.AllowFail { return err } } diff --git a/config/default_test.go b/config/default_test.go index 7a6d749e..9164f0b0 100644 --- a/config/default_test.go +++ b/config/default_test.go @@ -19,7 +19,7 @@ type Cfg struct { func TestDefault(t *testing.T) { ctx := context.Background() - conf := &Cfg{} + conf := &Cfg{IntValue: 10} blfn := func(ctx context.Context, cfg config.Config) error { conf, ok := cfg.Options().Struct.(*Cfg) if !ok { diff --git a/config/options.go b/config/options.go index 9e87f391..b50c477c 100644 --- a/config/options.go +++ b/config/options.go @@ -8,6 +8,7 @@ import ( ) type Options struct { + AllowFail bool BeforeLoad []func(context.Context, Config) error AfterLoad []func(context.Context, Config) error BeforeSave []func(context.Context, Config) error @@ -38,6 +39,12 @@ func NewOptions(opts ...Option) Options { return options } +func AllowFail(b bool) Option { + return func(o *Options) { + o.AllowFail = b + } +} + func BeforeLoad(fn ...func(context.Context, Config) error) Option { return func(o *Options) { o.BeforeLoad = fn diff --git a/config/reflect.go b/config/reflect.go new file mode 100644 index 00000000..dfc408ff --- /dev/null +++ b/config/reflect.go @@ -0,0 +1,28 @@ +package config + +import "reflect" + +func IsEmpty(v reflect.Value) bool { + switch v.Kind() { + case reflect.Array, reflect.Map, reflect.Slice, reflect.String: + return v.Len() == 0 + case reflect.Bool: + return !v.Bool() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return v.Uint() == 0 + case reflect.Float32, reflect.Float64: + return v.Float() == 0 + case reflect.Interface, reflect.Ptr: + if v.IsNil() { + return true + } + return IsEmpty(v.Elem()) + case reflect.Func: + return v.IsNil() + case reflect.Invalid: + return true + } + return false +}