From 1878de27329cba29066dc088d84b3ce743885f82 Mon Sep 17 00:00:00 2001 From: Jesse van den Kieboom Date: Sun, 21 Mar 2021 11:31:49 +0100 Subject: [PATCH] Clear reference values (maps and slices) when first set Fixes #323. --- ini.go | 4 ++++ ini_test.go | 24 ++++++++++++++++++++++++ option.go | 16 +++++++++++----- parser.go | 13 +------------ 4 files changed, 40 insertions(+), 17 deletions(-) diff --git a/ini.go b/ini.go index 2223d7b..60b36c7 100644 --- a/ini.go +++ b/ini.go @@ -499,6 +499,10 @@ func (i *IniParser) matchingGroups(name string) []*Group { func (i *IniParser) parse(ini *ini) error { p := i.parser + p.eachOption(func(cmd *Command, group *Group, option *Option) { + option.clearReferenceBeforeSet = true + }) + var quotesLookup = make(map[*Option]bool) for name, section := range ini.Sections { diff --git a/ini_test.go b/ini_test.go index 72bc386..72c890c 100644 --- a/ini_test.go +++ b/ini_test.go @@ -971,6 +971,30 @@ func TestIniRequired(t *testing.T) { assertString(t, opts.Required, "cli-value") } +func TestIniRequiredSlice_ShouldNotNeedToBeSpecifiedOnCli(t *testing.T) { + type options struct { + Items []string `long:"item" required:"true"` + } + var opts options + ini := ` +[Application Options] +item=abc` + args := []string{} + + parser := NewParser(&opts, Default) + inip := NewIniParser(parser) + + inip.Parse(strings.NewReader(ini)) + + _, err := parser.ParseArgs(args) + + if err != nil { + t.Fatalf("Unexpected failure: %v", err) + } + + assertString(t, opts.Items[0], "abc") +} + func TestWriteFile(t *testing.T) { file, err := ioutil.TempFile("", "") if err != nil { diff --git a/option.go b/option.go index cc441f8..f6d6941 100644 --- a/option.go +++ b/option.go @@ -80,10 +80,11 @@ type Option struct { // Determines if the option will be always quoted in the INI output iniQuote bool - tag multiTag - isSet bool - isSetDefault bool - preventDefault bool + tag multiTag + isSet bool + isSetDefault bool + preventDefault bool + clearReferenceBeforeSet bool defaultLiteral string } @@ -241,12 +242,13 @@ func (option *Option) IsSetDefault() bool { func (option *Option) set(value *string) error { kind := option.value.Type().Kind() - if (kind == reflect.Map || kind == reflect.Slice) && !option.isSet { + if (kind == reflect.Map || kind == reflect.Slice) && option.clearReferenceBeforeSet { option.empty() } option.isSet = true option.preventDefault = true + option.clearReferenceBeforeSet = false if len(option.Choices) != 0 { found := false @@ -281,6 +283,10 @@ func (option *Option) set(value *string) error { } func (option *Option) setDefault(value *string) error { + if option.preventDefault { + return nil + } + if err := option.set(value); err != nil { return err } diff --git a/parser.go b/parser.go index 1ebce81..3fc3f7b 100644 --- a/parser.go +++ b/parser.go @@ -208,8 +208,7 @@ func (p *Parser) ParseArgs(args []string) ([]string, error) { } p.eachOption(func(c *Command, g *Group, option *Option) { - option.isSet = false - option.isSetDefault = false + option.clearReferenceBeforeSet = true option.updateDefaultLiteral() }) @@ -713,13 +712,3 @@ func (p *Parser) printError(err error) error { return err } - -func (p *Parser) clearIsSet() { - p.eachCommand(func(c *Command) { - c.eachGroup(func(g *Group) { - for _, option := range g.options { - option.isSet = false - } - }) - }, true) -}