Skip to content

Commit

Permalink
Add support for urfave/cli.v3 (#7)
Browse files Browse the repository at this point in the history
* Add support for urfave/cli.v3

* Update to latest cli v3
  • Loading branch information
dearchap authored Nov 9, 2024
1 parent ad41f69 commit d62daa3
Show file tree
Hide file tree
Showing 5 changed files with 1,346 additions and 1,112 deletions.
75 changes: 75 additions & 0 deletions gen/gcli/gcliv3.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package gcli

import (
"github.com/octago/sflags"
"github.com/urfave/cli/v3"
)

type boolFlag interface {
IsBoolFlag() bool
}

type value struct {
v sflags.Value
}

func (v value) Get() any {
return v.v
}

func (v value) Set(s string) error {
return v.v.Set(s)
}

func (v value) String() string {
return v.v.String()
}

func (v value) IsBoolFlag() bool {
b, ok := v.v.(boolFlag)
return ok && b.IsBoolFlag()
}

// GenerateToV3 takes a list of sflag.Flag,
// that are parsed from some config structure, and put it to dst.
func GenerateToV3(src []*sflags.Flag, dst *[]cli.Flag) {
for _, srcFlag := range src {
name := srcFlag.Name
var aliases []string
if srcFlag.Short != "" {
aliases = append(aliases, srcFlag.Short)
}
*dst = append(*dst, &cli.GenericFlag{
Name: name,
Sources: cli.EnvVars(srcFlag.EnvName),
Aliases: aliases,
Hidden: srcFlag.Hidden,
Usage: srcFlag.Usage,
Value: &value{
v: srcFlag.Value,
},
})
}
}

// ParseToV3 parses cfg, that is a pointer to some structure,
// and puts it to dst.
func ParseToV3(cfg interface{}, dst *[]cli.Flag, optFuncs ...sflags.OptFunc) error {
flags, err := sflags.ParseStruct(cfg, optFuncs...)
if err != nil {
return err
}
GenerateToV3(flags, dst)
return nil
}

// ParseV3 parses cfg, that is a pointer to some structure,
// puts it to the new flag.FlagSet and returns it.
func ParseV3(cfg interface{}, optFuncs ...sflags.OptFunc) ([]cli.Flag, error) {
flags := make([]cli.Flag, 0)
err := ParseToV3(cfg, &flags, optFuncs...)
if err != nil {
return nil, err
}
return flags, nil
}
156 changes: 156 additions & 0 deletions gen/gcli/gcliv3_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
package gcli

import (
"context"
"errors"
"io"
"testing"

"github.com/octago/sflags"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/urfave/cli/v3"
)

type cfg2 struct {
StringValue1 string
StringValue2 string `flag:"string-value-two s"`

CounterValue1 sflags.Counter

StringSliceValue1 []string
}

func TestParseV3(t *testing.T) {
tests := []struct {
name string

cfg interface{}
args []string
expCfg interface{}
expErr1 error // sflag Parse error
expErr2 error // cli Parse error
}{
{
name: "Test cfg2",
cfg: &cfg2{
StringValue1: "string_value1_value",
StringValue2: "string_value2_value",

CounterValue1: 1,

StringSliceValue1: []string{"one", "two"},
},
expCfg: &cfg2{
StringValue1: "string_value1_value2",
StringValue2: "string_value2_value2",

CounterValue1: 3,

StringSliceValue1: []string{
"one2", "two2", "three", "4"},
},
args: []string{
"--string-value1", "string_value1_value2",
"--string-value-two", "string_value2_value2",
"--counter-value1", "--counter-value1",
"--string-slice-value1", "one2",
"--string-slice-value1", "two2",
"--string-slice-value1", "three,4",
},
},
{
name: "Test cfg2 no args",
cfg: &cfg2{
StringValue1: "string_value1_value",
StringValue2: "",
},
expCfg: &cfg2{
StringValue1: "string_value1_value",
StringValue2: "",
},
args: []string{},
},
{
name: "Test cfg2 short option",
cfg: &cfg2{
StringValue2: "string_value2_value",
},
expCfg: &cfg2{
StringValue2: "string_value2_value2",
},
args: []string{
"-s=string_value2_value2",
},
},
{
name: "Test cfg2 without default values",
cfg: &cfg2{},
expCfg: &cfg2{
StringValue1: "string_value1_value2",
StringValue2: "string_value2_value2",

CounterValue1: 3,
},
args: []string{
"--string-value1", "string_value1_value2",
"--string-value-two", "string_value2_value2",
"--counter-value1=2", "--counter-value1",
},
},
{
name: "Test cfg2 bad option",
cfg: &cfg2{
StringValue1: "string_value1_value",
},
args: []string{
"--bad-value=string_value1_value2",
},
expErr2: errors.New("flag provided but not defined: -bad-value"),
},
{
name: "Test bad cfg value",
cfg: "bad config",
expErr1: errors.New("object must be a pointer to struct or interface"),
},
}
// forbid urfave/cli to exit
cli.OsExiter = func(i int) {}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
flags, err := ParseV3(test.cfg)
if test.expErr1 != nil {
require.Error(t, err)
require.Equal(t, test.expErr1, err)
} else {
require.NoError(t, err)
}
if err != nil {
return
}
cmd := &cli.Command{}
cmd.Action = func(_ context.Context, c *cli.Command) error {
return nil
}
cmd.UseShortOptionHandling = true
cli.ErrWriter = io.Discard
cmd.OnUsageError = func(ctx context.Context, cmd *cli.Command, err error, isSubcommand bool) error {
return err
}

cmd.Flags = flags
args := append([]string{"cliApp"}, test.args...)
err = cmd.Run(context.Background(), args)
if test.expErr2 != nil {
require.Error(t, err)
require.Equal(t, test.expErr2, err)
} else {
require.NoError(t, err)
}
if err != nil {
return
}
assert.Equal(t, test.expCfg, test.cfg)
})
}
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require (
github.com/spf13/pflag v1.0.3
github.com/stretchr/testify v1.9.0
github.com/urfave/cli/v2 v2.27.5
github.com/urfave/cli/v3 v3.0.0-alpha9.3
golang.org/x/text v0.19.0
)

Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w=
github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
github.com/urfave/cli/v3 v3.0.0-alpha9.3 h1:RfQlgUHMRxDMwEEmGsrHd+mXYJpWpXlcJM8w86cpjGs=
github.com/urfave/cli/v3 v3.0.0-alpha9.3/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y=
github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc=
github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
Expand Down
Loading

0 comments on commit d62daa3

Please sign in to comment.