Skip to content

Commit ed7b458

Browse files
committed
fixes, add optional args
1 parent 8f433dd commit ed7b458

File tree

9 files changed

+63
-19
lines changed

9 files changed

+63
-19
lines changed

argument.go

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ import (
99
)
1010

1111
type Argument struct {
12-
name string
13-
description string
14-
parser argParser
12+
name string
13+
description string
14+
parser argParser
15+
defaultValue any
1516

1617
value any
1718
}
@@ -31,7 +32,19 @@ func newArgument(name, description string, options ...option.Option[*Argument])
3132
return argument, nil
3233
}
3334

35+
func (a *Argument) isRequired() bool {
36+
return a.defaultValue == nil
37+
}
38+
39+
func (a *Argument) isOptional() bool {
40+
return !a.isRequired()
41+
}
42+
3443
func (a *Argument) inBrackets() string {
44+
if a.isOptional() {
45+
return fmt.Sprintf("<%s?>", a.name)
46+
}
47+
3548
return fmt.Sprintf("<%s>", a.name)
3649
}
3750

argument_input_validation.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import "github.com/bobg/errors"
55
var ArgumentMissingValueError = errors.New("argument missing value")
66

77
func (a *Argument) validateInput() error {
8-
if a.value == nil {
8+
if a.isRequired() && a.value == nil {
99
return errors.Wrapf(ArgumentMissingValueError, "argument %q", a.name)
1010
}
1111

argument_options.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,17 @@ func SetArgParser[T any](parser ArgParser[T]) option.Func[*Argument] {
99
return argument, nil
1010
}
1111
}
12+
13+
// SetArgDefault sets the default value of the argument.
14+
func SetArgDefault[T Parseable](defaultValue T) option.Func[*Argument] {
15+
return func(argument *Argument) (*Argument, error) {
16+
argParser, err := argParserFromParseable[T]()
17+
if err != nil {
18+
return nil, err
19+
}
20+
21+
argument.parser = argParser
22+
argument.defaultValue = defaultValue
23+
return argument, nil
24+
}
25+
}

command.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ func Run(name, description string, options ...option.Option[*Command]) {
5555
if err := command.Run(context.Background(), os.Args[1:]); err != nil {
5656
fmt.Println(err)
5757

58-
if exitErr := new(exec.ExitError); errors.As(err, exitErr) {
58+
if exitErr := new(exec.ExitError); errors.As(err, &exitErr) {
5959
os.Exit(exitErr.ExitCode())
6060
} else {
6161
os.Exit(1)
@@ -65,8 +65,10 @@ func Run(name, description string, options ...option.Option[*Command]) {
6565

6666
// Run runs the command.
6767
func (c *Command) Run(ctx context.Context, rawArgs []string) error {
68-
if err := c.newParser(rawArgs).parse(ctx); err != nil {
68+
if commandProcessed, err := c.newParser(rawArgs).parse(ctx); err != nil {
6969
return err
70+
} else if commandProcessed {
71+
return nil
7072
}
7173

7274
return c.runHandler(ctx)
@@ -78,7 +80,13 @@ func (c *Command) runHandler(ctx context.Context) error {
7880
} else if c.isVersionFlagAsserted() {
7981
fmt.Println(c.findVersion())
8082
return nil
81-
} else if c.handler == nil {
83+
}
84+
85+
if err := c.validateInput(); err != nil {
86+
return err
87+
}
88+
89+
if c.handler == nil {
8290
return c.renderHelp(os.Stdout)
8391
}
8492

command_options.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package cli
22

3-
import "github.com/broothie/option"
3+
import (
4+
"sort"
5+
6+
"github.com/broothie/option"
7+
)
48

59
const versionFlagName = "version"
610

@@ -64,6 +68,8 @@ func AddArg(name, description string, options ...option.Option[*Argument]) optio
6468
}
6569

6670
command.arguments = append(command.arguments, argument)
71+
sort.SliceStable(command.arguments, func(i, j int) bool { return command.arguments[i].isRequired() && command.arguments[j].isOptional() })
72+
6773
return command, nil
6874
}
6975
}

context.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,11 @@ func ArgValue[T any](ctx context.Context, name string) (T, error) {
4545
return zero, errors.Wrapf(ArgumentNotFoundError, "finding argument %q", name)
4646
}
4747

48-
return arg.value.(T), nil
48+
if arg.value != nil {
49+
return arg.value.(T), nil
50+
}
51+
52+
return arg.defaultValue.(T), nil
4953
}
5054

5155
var commandContextKey struct{}

flag.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,14 @@ func (c *Command) findFlag(name string) (*Flag, bool) {
5151

5252
func (c *Command) findFlagUpToRoot(predicate func(*Flag) bool) (*Flag, bool) {
5353
for current := c; current != nil; current = current.parent {
54+
currentIsSelf := current == c
55+
5456
flags := current.flags
55-
if currentIsSelf := current == c; !currentIsSelf {
57+
if !currentIsSelf {
5658
flags = lo.Filter(flags, func(flag *Flag, _ int) bool { return flag.isInherited })
5759
}
5860

59-
flag, found := lo.Find(c.flags, predicate)
61+
flag, found := lo.Find(flags, predicate)
6062
if found {
6163
return flag, true
6264
}

flag_options.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package cli
22

33
import (
4-
"github.com/bobg/errors"
54
"github.com/broothie/option"
65
)
76

@@ -42,7 +41,7 @@ func SetFlagDefault[T Parseable](defaultValue T) option.Func[*Flag] {
4241
return func(flag *Flag) (*Flag, error) {
4342
argParser, err := argParserFromParseable[T]()
4443
if err != nil {
45-
return nil, errors.Wrapf(err, "")
44+
return nil, err
4645
}
4746

4847
flag.parser = argParser

parser.go

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,15 @@ func (c *Command) newParser(tokens []string) *parser {
4040
return newParser(c, tokens)
4141
}
4242

43-
func (p *parser) parse(ctx context.Context) error {
43+
func (p *parser) parse(ctx context.Context) (bool, error) {
4444
for p.index < len(p.tokens) {
4545
commandProcessed, err := p.parseArg(ctx)
46-
if err != nil {
47-
return err
48-
} else if commandProcessed {
49-
return nil
46+
if err != nil || commandProcessed {
47+
return true, err
5048
}
5149
}
5250

53-
return p.command.validateInput()
51+
return false, nil
5452
}
5553

5654
func (p *parser) parseArg(ctx context.Context) (bool, error) {

0 commit comments

Comments
 (0)