Skip to content

Commit

Permalink
fix issue setting complex options via flags
Browse files Browse the repository at this point in the history
If the Option[T].Value implements a Setter interface, call it when
assigning a string option, which is common with command line flag usage.
  • Loading branch information
coryb committed Aug 11, 2023
1 parent 26070a2 commit 9353e35
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 5 deletions.
14 changes: 14 additions & 0 deletions convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ import (

// dst must be a pointer type
func convertString(src string, dst interface{}) (err error) {
// allow destinations that implement the kingping.Value interface:
// https://github.com/alecthomas/kingpin/blob/v2.3.2/values.go#L30-L33
type setter interface {
Set(string) error
}
// allow destinations that implement the kingpin.Setter interface:
// https://github.com/alecthomas/kingpin/blob/v2.3.2/parsers.go#L12-L14
type setValuer interface {
SetValue(any) error
}
switch v := dst.(type) {
case *bool:
*v, err = strconv.ParseBool(src)
Expand Down Expand Up @@ -82,6 +92,10 @@ func convertString(src string, dst interface{}) (err error) {
*v = tmp
case *any:
*v = src
case setter:
return v.Set(src)
case setValuer:
return v.SetValue(src)
default:
err = fmt.Errorf("Cannot convert string %q to type %T", src, dst)
}
Expand Down
26 changes: 21 additions & 5 deletions kingpin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,23 @@ import (
kingpin "gopkg.in/alecthomas/kingpin.v2"
)

type Stringish struct {
value string
}

// implement the
func (s *Stringish) Set(v string) error {
s.value = v
return nil
}

func TestCommandLine(t *testing.T) {
type CommandLineOptions struct {
Str1 StringOption `yaml:"str1,omitempty"`
Int1 IntOption `yaml:"int1,omitempty"`
Map1 MapStringOption `yaml:"map1,omitempty"`
Arr1 ListStringOption `yaml:"arr1,omitempty"`
Str1 StringOption `yaml:"str1,omitempty"`
Int1 IntOption `yaml:"int1,omitempty"`
Map1 MapStringOption `yaml:"map1,omitempty"`
Arr1 ListStringOption `yaml:"arr1,omitempty"`
Strs ListOption[Stringish] `yaml:"strs,omitempty"`
}

opts := CommandLineOptions{}
Expand All @@ -31,7 +42,8 @@ func TestCommandLine(t *testing.T) {
app.Flag("int1", "Int1").SetValue(&opts.Int1)
app.Flag("map1", "Map1").SetValue(&opts.Map1)
app.Flag("arr1", "Arr1").SetValue(&opts.Arr1)
_, err = app.Parse([]string{"--int1", "999", "--map1", "k1=v1", "--map1", "k2=v2", "--arr1", "v1", "--arr1", "v2"})
app.Flag("str", "Strs").SetValue(&opts.Strs)
_, err = app.Parse([]string{"--int1", "999", "--map1", "k1=v1", "--map1", "k2=v2", "--arr1", "v1", "--arr1", "v2", "--str", "abc", "--str", "def"})
require.NoError(t, err)

arr1 := ListStringOption{}
Expand All @@ -58,6 +70,10 @@ func TestCommandLine(t *testing.T) {
"k2": {NewSource("override"), true, "v2"},
},
Arr1: arr1,
Strs: ListOption[Stringish]{
{NewSource("override"), true, Stringish{"abc"}},
{NewSource("override"), true, Stringish{"def"}},
},
}

require.Equal(t, expected, opts)
Expand Down

0 comments on commit 9353e35

Please sign in to comment.