pkg/cfgstruct: add pflag support to bind (#2425)

This commit is contained in:
Egon Elbre 2019-07-02 20:53:01 +03:00 committed by Jennifer Li Johnson
parent 6d55bbdb57
commit 9e26149a2d
4 changed files with 86 additions and 20 deletions

View File

@ -16,7 +16,6 @@ import (
"github.com/spf13/pflag"
"go.uber.org/zap"
"storj.io/storj/internal/memory"
"storj.io/storj/internal/version"
)
@ -139,6 +138,37 @@ func bindConfig(flags FlagSet, prefix string, val reflect.Value, vars map[string
continue
}
fieldaddr := fieldval.Addr().Interface()
if fieldvalue, ok := fieldaddr.(pflag.Value); ok {
help := field.Tag.Get("help")
var def string
if isDev {
def = getDefault(field.Tag, "devDefault", "releaseDefault", "default", flagname)
} else {
def = getDefault(field.Tag, "releaseDefault", "devDefault", "default", flagname)
}
err := fieldvalue.Set(def)
if err != nil {
panic(fmt.Sprintf("invalid default value for %s: %#v, %v", flagname, def, err))
}
flags.Var(fieldvalue, flagname, help)
if onlyForSetup {
setBoolAnnotation(flags, flagname, "setup")
}
if field.Tag.Get("user") == "true" {
setBoolAnnotation(flags, flagname, "user")
}
if field.Tag.Get("hidden") == "true" {
err := flags.MarkHidden(flagname)
if err != nil {
panic(fmt.Sprintf("mark hidden failed %s: %v", flagname, err))
}
}
continue
}
switch field.Type.Kind() {
case reflect.Struct:
if field.Anonymous {
@ -167,9 +197,6 @@ func bindConfig(flags FlagSet, prefix string, val reflect.Value, vars map[string
}
}
switch field.Type {
case reflect.TypeOf(memory.Size(0)):
check(fieldaddr.(*memory.Size).Set(def))
flags.Var(fieldaddr.(*memory.Size), flagname, help)
case reflect.TypeOf(int(0)):
val, err := strconv.ParseInt(def, 0, strconv.IntSize)
check(err)

View File

@ -10,6 +10,10 @@ import (
"time"
"github.com/spf13/pflag"
"github.com/stretchr/testify/require"
"storj.io/storj/internal/memory"
"storj.io/storj/pkg/storj"
)
func assertEqual(actual, expected interface{}) {
@ -21,14 +25,17 @@ func assertEqual(actual, expected interface{}) {
func TestBind(t *testing.T) {
f := pflag.NewFlagSet("test", pflag.PanicOnError)
var c struct {
String string `default:""`
Bool bool `releaseDefault:"false" devDefault:"true"`
Int64 int64 `releaseDefault:"0" devDefault:"1"`
Int int `default:"0"`
Uint64 uint64 `default:"0"`
Uint uint `default:"0"`
Float64 float64 `default:"0"`
Duration time.Duration `default:"0"`
String string `default:""`
Bool bool `releaseDefault:"false" devDefault:"true"`
Int64 int64 `releaseDefault:"0" devDefault:"1"`
Int int `default:"0"`
Uint64 uint64 `default:"0"`
Uint uint `default:"0"`
Float64 float64 `default:"0"`
Size memory.Size `default:"0"`
Duration time.Duration `default:"0"`
NodeURL storj.NodeURL `releaseDefault:"" devDefault:""`
NodeURLs storj.NodeURLs `releaseDefault:"" devDefault:""`
Struct struct {
AnotherString string `default:""`
}
@ -45,11 +52,20 @@ func TestBind(t *testing.T) {
assertEqual(c.Uint64, uint64(0))
assertEqual(c.Uint, uint(0))
assertEqual(c.Float64, float64(0))
assertEqual(c.Size, memory.Size(0))
assertEqual(c.Duration, time.Duration(0))
assertEqual(c.NodeURL, storj.NodeURL{})
assertEqual(c.NodeURLs, storj.NodeURLs(nil))
assertEqual(c.Struct.AnotherString, string(""))
assertEqual(c.Fields[0].AnotherInt, int(0))
assertEqual(c.Fields[3].AnotherInt, int(0))
err := f.Parse([]string{
node1, err := storj.NodeIDFromString("12EayRS2V1kEsWESU9QMRseFhdxYxKicsiFmxrsLZHeLUtdps3S")
require.NoError(t, err)
node2, err := storj.NodeIDFromString("12L9ZFwhzVpuEKMUNUqkaTLGzwY9G24tbiigLiXpmZWKwmcNDDs")
require.NoError(t, err)
err = f.Parse([]string{
"--string=1",
"--bool=true",
"--int64=1",
@ -57,7 +73,10 @@ func TestBind(t *testing.T) {
"--uint64=1",
"--uint=1",
"--float64=1",
"--size=1MiB",
"--duration=1h",
"--node-url=12EayRS2V1kEsWESU9QMRseFhdxYxKicsiFmxrsLZHeLUtdps3S@mars.tardigrade.io:7777",
"--node-ur-ls=12EayRS2V1kEsWESU9QMRseFhdxYxKicsiFmxrsLZHeLUtdps3S@mars.tardigrade.io:7777,12L9ZFwhzVpuEKMUNUqkaTLGzwY9G24tbiigLiXpmZWKwmcNDDs@jupiter.tardigrade.io:7777",
"--struct.another-string=1",
"--fields.03.another-int=1"})
if err != nil {
@ -70,7 +89,13 @@ func TestBind(t *testing.T) {
assertEqual(c.Uint64, uint64(1))
assertEqual(c.Uint, uint(1))
assertEqual(c.Float64, float64(1))
assertEqual(c.Size, memory.MiB)
assertEqual(c.Duration, time.Hour)
assertEqual(c.NodeURL, storj.NodeURL{ID: node1, Address: "mars.tardigrade.io:7777"})
assertEqual(c.NodeURLs, storj.NodeURLs{
storj.NodeURL{ID: node1, Address: "mars.tardigrade.io:7777"},
storj.NodeURL{ID: node2, Address: "jupiter.tardigrade.io:7777"},
})
assertEqual(c.Struct.AnotherString, string("1"))
assertEqual(c.Fields[0].AnotherInt, int(0))
assertEqual(c.Fields[3].AnotherInt, int(1))
@ -154,11 +179,12 @@ func TestBindDevDefaults(t *testing.T) {
func TestHiddenDev(t *testing.T) {
f := pflag.NewFlagSet("test", pflag.PanicOnError)
var c struct {
String string `default:"dev" hidden:"true"`
String2 string `default:"dev" hidden:"false"`
Bool bool `releaseDefault:"false" devDefault:"true" hidden:"true"`
Int64 int64 `releaseDefault:"0" devDefault:"1"`
Int int `default:"2"`
String string `default:"dev" hidden:"true"`
String2 string `default:"dev" hidden:"false"`
Bool bool `releaseDefault:"false" devDefault:"true" hidden:"true"`
Int64 int64 `releaseDefault:"0" devDefault:"1"`
Int int `default:"2"`
Size memory.Size `default:"0" hidden:"true"`
}
Bind(f, &c, UseDevDefaults())
@ -167,11 +193,13 @@ func TestHiddenDev(t *testing.T) {
flagBool := f.Lookup("bool")
flagInt64 := f.Lookup("int64")
flagInt := f.Lookup("int")
flagSize := f.Lookup("size")
assertEqual(flagString.Hidden, true)
assertEqual(flagStringHide.Hidden, false)
assertEqual(flagBool.Hidden, true)
assertEqual(flagInt64.Hidden, false)
assertEqual(flagInt.Hidden, false)
assertEqual(flagSize.Hidden, true)
}
func TestHiddenRelease(t *testing.T) {

View File

@ -37,7 +37,7 @@ type NodeURL struct {
// 12vha9oTFnerxYRgeQ2BZqoFrLrnmmf5UWTCY2jA77dF3YvWew7@
func ParseNodeURL(s string) (NodeURL, error) {
if s == "" {
return NodeURL{}, ErrNodeURL.New("empty string")
return NodeURL{}, nil
}
if !strings.HasPrefix(s, "storj://") {
if strings.Index(s, "://") < 0 {
@ -65,6 +65,11 @@ func ParseNodeURL(s string) (NodeURL, error) {
return node, nil
}
// IsZero returns whether tthe url is empty.
func (url NodeURL) IsZero() bool {
return url == NodeURL{}
}
// String converts NodeURL to a string
func (url NodeURL) String() string {
if url.ID.IsZero() {
@ -84,6 +89,9 @@ func (url *NodeURL) Set(s string) error {
return nil
}
// Type implements pflag.Value
func (NodeURL) Type() string { return "storj.NodeURL" }
// NodeURLs defines a comma delimited flag for defining a list node url-s.
type NodeURLs []NodeURL
@ -124,3 +132,6 @@ func (urls *NodeURLs) Set(s string) error {
*urls = parsed
return nil
}
// Type implements pflag.Value
func (NodeURLs) Type() string { return "storj.NodeURLs" }

View File

@ -24,6 +24,7 @@ func TestNodeURL(t *testing.T) {
}
for _, testcase := range []Test{
{"", storj.NodeURL{}},
// host
{"33.20.0.1:7777", storj.NodeURL{emptyID, "33.20.0.1:7777"}},
{"[2001:db8:1f70::999:de8:7648:6e8]:7777", storj.NodeURL{emptyID, "[2001:db8:1f70::999:de8:7648:6e8]:7777"}},
@ -45,7 +46,6 @@ func TestNodeURL(t *testing.T) {
t.Run("Invalid", func(t *testing.T) {
for _, testcase := range []string{
"",
// invalid host
"exampl e.com:7777",
// invalid node id