From de23397e03c0b9c4072082fa4f2a050abafc1011 Mon Sep 17 00:00:00 2001 From: Oleg Kovalov Date: Sun, 15 Aug 2021 13:12:32 +0200 Subject: [PATCH] Check duplicate flag (#98) Signed-off-by: Oleg Kovalov --- aconfig.go | 22 ++++++++++++++++------ aconfig_test.go | 14 ++++++++++++++ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/aconfig.go b/aconfig.go index 3eef7eb..d6c4fbd 100644 --- a/aconfig.go +++ b/aconfig.go @@ -25,6 +25,7 @@ type Loader struct { dst interface{} fields []*fieldData flagSet *flag.FlagSet + errInit error } // Config to configure configuration loader. @@ -156,11 +157,17 @@ func (l *Loader) init() { l.flagSet = flag.NewFlagSet(l.config.FlagPrefix, flag.ContinueOnError) if !l.config.SkipFlags { + names := make(map[string]bool, len(l.fields)) for _, field := range l.fields { flagName := l.fullTag(l.config.FlagPrefix, field, flagNameTag) if flagName == "" { continue } + if names[flagName] && !l.config.AllowDuplicates { + l.errInit = fmt.Errorf("duplicate flag %q", flagName) + return + } + names[flagName] = true l.flagSet.String(flagName, field.Tag(defaultValueTag), field.Tag(usageTag)) } } @@ -188,6 +195,9 @@ func (l *Loader) WalkFields(fn func(f Field) bool) { // Load configuration into a given param. func (l *Loader) Load() error { + if l.errInit != nil { + return fmt.Errorf("aconfig: cannot init loader: %w", l.errInit) + } if err := l.loadConfig(); err != nil { return fmt.Errorf("aconfig: cannot load config: %w", err) } @@ -370,12 +380,12 @@ func (l *Loader) loadEnvironment() error { } func (l *Loader) postEnvCheck(values map[string]interface{}, dupls map[string]struct{}) error { - for name := range dupls { - delete(values, name) - } if l.config.AllowUnknownEnvs || l.config.EnvPrefix == "" { return nil } + for name := range dupls { + delete(values, name) + } for env, value := range values { if strings.HasPrefix(env, l.config.EnvPrefix) { return fmt.Errorf("unknown environment var %s=%v (see AllowUnknownEnvs config param)", env, value) @@ -402,12 +412,12 @@ func (l *Loader) loadFlags() error { } func (l *Loader) postFlagCheck(values map[string]interface{}, dupls map[string]struct{}) error { - for name := range dupls { - delete(values, name) - } if l.config.AllowUnknownFlags || l.config.FlagPrefix == "" { return nil } + for name := range dupls { + delete(values, name) + } for flag, value := range values { if strings.HasPrefix(flag, l.config.EnvPrefix) { return fmt.Errorf("unknown flag %s=%v (see AllowUnknownFlags config param)", flag, value) diff --git a/aconfig_test.go b/aconfig_test.go index e86a04f..e22d413 100644 --- a/aconfig_test.go +++ b/aconfig_test.go @@ -544,6 +544,20 @@ func TestFailOnDuplicatedName(t *testing.T) { } } +func TestFailOnDuplicatedFlag(t *testing.T) { + type Foo struct { + Bar string `flag:"yes"` + Baz string `flag:"yes"` + } + + err := LoaderFor(&Foo{}, Config{}).Load() + + want := `aconfig: cannot init loader: duplicate flag "yes"` + if got := err.Error(); got != want { + t.Fatalf("got %s want %s", got, want) + } +} + func TestUsage(t *testing.T) { loader := LoaderFor(&EmbeddedConfig{}, Config{})