From 8147596ed32b1846af3bf78e36ca2736eff5a634 Mon Sep 17 00:00:00 2001 From: pyqlsa <26353308+pyqlsa@users.noreply.github.com> Date: Sun, 17 Jul 2022 12:43:05 -0700 Subject: [PATCH] add active member to nodes and values --- context.go | 2 ++ mapper.go | 4 ++-- mapper_test.go | 44 ++++++++++++++++++++++++++++++++++++++++++++ model.go | 3 +++ 4 files changed, 51 insertions(+), 2 deletions(-) diff --git a/context.go b/context.go index 45c412a..b5c6e6d 100644 --- a/context.go +++ b/context.go @@ -346,6 +346,7 @@ func (c *Context) endParsing() { func (c *Context) trace(node *Node) (err error) { // nolint: gocyclo positional := 0 + node.Active = true flags := []*Flag{} flagNode := node @@ -438,6 +439,7 @@ func (c *Context) trace(node *Node) (err error) { // nolint: gocyclo c.endParsing() } + arg.Active = true err := arg.Parse(c.scan, c.getValue(arg)) if err != nil { return err diff --git a/mapper.go b/mapper.go index e93d2d4..6e17d9e 100644 --- a/mapper.go +++ b/mapper.go @@ -613,7 +613,7 @@ func existingFileMapper(r *Registry) MapperFunc { return err } - if ctx.Value.Set { + if !ctx.Value.Active || ctx.Value.Set { // early return to avoid checking extra files that may not exist; // this hack only works because the value provided on the cli is // checked before the default value is checked (if default is set). @@ -649,7 +649,7 @@ func existingDirMapper(r *Registry) MapperFunc { return err } - if ctx.Value.Set { + if !ctx.Value.Active || ctx.Value.Set { // early return to avoid checking extra dirs that may not exist; // this hack only works because the value provided on the cli is // checked before the default value is checked (if default is set). diff --git a/mapper_test.go b/mapper_test.go index ae4c3f1..1818f20 100644 --- a/mapper_test.go +++ b/mapper_test.go @@ -453,6 +453,28 @@ func TestExistingFileMapperDefaultMissing(t *testing.T) { assert.NoError(t, err) assert.NotZero(t, cli.File) assert.Contains(t, cli.File, file) + p = mustNew(t, &cli) + _, err = p.Parse([]string{}) + assert.Error(t, err) + assert.Contains(t, err.Error(), "missing.txt: no such file or directory") +} + +func TestExistingFileMapperDefaultMissingCmds(t *testing.T) { + type CLI struct { + CmdA struct { + FileA string `type:"existingfile" default:"testdata/aaa-missing.txt"` + } `cmd:""` + CmdB struct { + FileB string `type:"existingfile" default:"testdata/bbb-missing.txt"` + } `cmd:""` + } + var cli CLI + p := mustNew(t, &cli) + file := "testdata/file.txt" + _, err := p.Parse([]string{"cmd-a", "--file-a", file}) + assert.NoError(t, err) + assert.NotZero(t, cli.CmdA.FileA) + assert.Contains(t, cli.CmdA.FileA, file) } //nolint:dupl @@ -486,6 +508,28 @@ func TestExistingDirMapperDefaultMissing(t *testing.T) { assert.NoError(t, err) assert.NotZero(t, cli.Dir) assert.Contains(t, cli.Dir, dir) + p = mustNew(t, &cli) + _, err = p.Parse([]string{}) + assert.Error(t, err) + assert.Contains(t, err.Error(), "missing-dir: no such file or directory") +} + +func TestExistingDirMapperDefaultMissingCmds(t *testing.T) { + type CLI struct { + CmdA struct { + DirA string `type:"existingdir" default:"aaa-missing-dir"` + } `cmd:""` + CmdB struct { + DirB string `type:"existingdir" default:"bbb-missing-dir"` + } `cmd:""` + } + var cli CLI + p := mustNew(t, &cli) + dir := "testdata" + _, err := p.Parse([]string{"cmd-a", "--dir-a", dir}) + assert.NoError(t, err) + assert.NotZero(t, cli.CmdA.DirA) + assert.Contains(t, cli.CmdA.DirA, dir) } func TestMapperPlaceHolder(t *testing.T) { diff --git a/model.go b/model.go index af2cdaf..5879a4b 100644 --- a/model.go +++ b/model.go @@ -54,6 +54,7 @@ type Node struct { Tag *Tag Aliases []string Passthrough bool // Set to true to stop flag parsing when encountered. + Active bool // Denotes the node is part of an active branch in the CLI. Argument *Value // Populated when Type is ArgumentNode. } @@ -98,6 +99,7 @@ func (n *Node) AllFlags(hide bool) (out [][]*Flag) { group := []*Flag{} for _, flag := range n.Flags { if !hide || !flag.Hidden { + flag.Active = true group = append(group, flag) } } @@ -243,6 +245,7 @@ type Value struct { Format string // Formatting directive, if applicable. Position int // Position (for positional arguments). Passthrough bool // Set to true to stop flag parsing when encountered. + Active bool // Denotes the value is part of an active branch in the CLI. } // EnumMap returns a map of the enums in this value.