Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix nested struct conflict & should not flatten nested field #69

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions env_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,13 @@ func setEnvVars(t *testing.T, structName, prefix string) {
"INTERVAL": "10s",
"ID": "1234567890",
"LABELS": "123,456",
"LOG_FILE": "/var/log/global.log",
"POSTGRES_ENABLED": "true",
"POSTGRES_PORT": "5432",
"POSTGRES_HOSTS": "192.168.2.1,192.168.2.2,192.168.2.3",
"POSTGRES_DBNAME": "configdb",
"POSTGRES_AVAILABILITYRATIO": "8.23",
"POSTGRES_LOG_FILE": "/var/log/postgres.log",
"POSTGRES_FOO": "8.23,9.12,11,90",
}
case "CamelCaseServer":
Expand All @@ -112,6 +114,7 @@ func setEnvVars(t *testing.T, structName, prefix string) {
"HOSTS": "192.168.2.1,192.168.2.2,192.168.2.3",
"DBNAME": "configdb",
"AVAILABILITYRATIO": "8.23",
"LOG_FILE": "/var/log/postgres.log",
"FOO": "8.23,9.12,11,90",
}
}
Expand Down
24 changes: 17 additions & 7 deletions flag.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/fatih/camelcase"
"github.com/fatih/structs"
"github.com/kballard/go-shellquote"
)

// FlagLoader satisfies the loader interface. It creates on the fly flags based
Expand Down Expand Up @@ -44,9 +45,12 @@ type FlagLoader struct {
// By default it's flag.ContinueOnError.
ErrorHandling flag.ErrorHandling

// Args defines a custom argument list. If nil, os.Args[1:] is used.
// Args defines a custom argument list. If nil and RawArgs is empty, os.Args[1:] is used.
Args []string

// RawArgs define a custom shell command line args, When not empty and Args is nil.
RawArgs string

// FlagUsageFunc an optional function that is called to set a flag.Usage value
// The input is the raw flag name, and the output should be a string
// that will used in passed into the flag for Usage.
Expand All @@ -65,7 +69,7 @@ func (f *FlagLoader) Load(s interface{}) error {
f.flagSet = flagSet

for _, field := range strct.Fields() {
f.processField(field.Name(), field)
f.processField(field.Name(), field, 0)
}

flagSet.Usage = func() {
Expand All @@ -83,6 +87,12 @@ func (f *FlagLoader) Load(s interface{}) error {
args := filterArgs(os.Args[1:])
if f.Args != nil {
args = f.Args
} else if f.RawArgs != "" {
var err error
args, err = shellquote.Split(f.RawArgs)
if err != nil {
return err
}
}

return flagSet.Parse(args)
Expand All @@ -92,7 +102,7 @@ func filterArgs(args []string) []string {
r := []string{}
for i := 0; i < len(args); i++ {
if strings.Index(args[i], "test.") >= 0 {
if i + 1 < len(args) && strings.Index(args[i + 1], "-") == -1 {
if i+1 < len(args) && strings.Index(args[i+1], "-") == -1 {
i++
}
i++
Expand All @@ -106,7 +116,7 @@ func filterArgs(args []string) []string {
// processField generates a flag based on the given field and fieldName. If a
// nested struct is detected, a flag for each field of that nested struct is
// generated too.
func (f *FlagLoader) processField(fieldName string, field *structs.Field) error {
func (f *FlagLoader) processField(fieldName string, field *structs.Field, nestedLevel int) error {
if f.CamelCase {
fieldName = strings.Join(camelcase.Split(fieldName), "-")
fieldName = strings.Replace(fieldName, "---", "-", -1)
Expand All @@ -115,9 +125,9 @@ func (f *FlagLoader) processField(fieldName string, field *structs.Field) error
switch field.Kind() {
case reflect.Struct:
for _, ff := range field.Fields() {
flagName := field.Name() + "-" + ff.Name()
flagName := fieldName + "-" + ff.Name()

if f.Flatten {
if f.Flatten && nestedLevel == 0 {
// first check if it's set or not, because if we have duplicate
// we don't want to break the flag. Panic by giving a readable
// output
Expand All @@ -131,7 +141,7 @@ func (f *FlagLoader) processField(fieldName string, field *structs.Field) error
flagName = ff.Name()
}

if err := f.processField(flagName, ff); err != nil {
if err := f.processField(flagName, ff, nestedLevel+1); err != nil {
return err
}
}
Expand Down
3 changes: 3 additions & 0 deletions flag_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,11 +201,13 @@ func getFlags(t *testing.T, structName, prefix string) []string {
"-interval": "10s",
"-id": "1234567890",
"-labels": "123,456",
"-log-file": "/var/log/global.log",
"-postgres-enabled": "",
"-postgres-port": "5432",
"-postgres-hosts": "192.168.2.1,192.168.2.2,192.168.2.3",
"-postgres-dbname": "configdb",
"-postgres-availabilityratio": "8.23",
"-postgres-log-file": "/var/log/postgres.log",
}
case "FlattenedServer":
flags = map[string]string{
Expand All @@ -214,6 +216,7 @@ func getFlags(t *testing.T, structName, prefix string) []string {
"--hosts": "192.168.2.1,192.168.2.2,192.168.2.3",
"--dbname": "configdb",
"--availabilityratio": "8.23",
"-log-file": "/var/log/postgres.log",
}
case "FlattenedCamelCaseServer":
flags = map[string]string{
Expand Down
23 changes: 23 additions & 0 deletions multiconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,20 @@ func fieldSet(field *structs.Field, v string) error {
list = append(list, i)
}

if err := field.Set(list); err != nil {
return err
}
case []float32:
var list []float32
for _, in := range strings.Split(v, ",") {
i, err := strconv.ParseFloat(in, 32)
if err != nil {
return err
}

list = append(list, float32(i))
}

if err := field.Set(list); err != nil {
return err
}
Expand All @@ -194,6 +208,15 @@ func fieldSet(field *structs.Field, v string) error {
if err := field.Set(f); err != nil {
return err
}
case reflect.Float32:
f, err := strconv.ParseFloat(v, 32)
if err != nil {
return err
}

if err := field.Set(float32(f)); err != nil {
return err
}
case reflect.Int64:
switch t := field.Value().(type) {
case time.Duration:
Expand Down
16 changes: 16 additions & 0 deletions multiconfig_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type (
Labels []int
Enabled bool
Users []string
Log Log
Postgres Postgres
unexported string
Interval time.Duration
Expand All @@ -25,13 +26,18 @@ type (
Hosts []string `required:"true"`
DBName string `default:"configdb"`
AvailabilityRatio float64
Log Log
unexported string
}

TaggedServer struct {
Name string `required:"true"`
Postgres `structs:",flatten"`
}

Log struct {
File string
}
)

type FlattenedServer struct {
Expand Down Expand Up @@ -60,12 +66,14 @@ func getDefaultServer() *Server {
Labels: []int{123, 456},
Users: []string{"ankara", "istanbul"},
Interval: 10 * time.Second,
Log: Log{File: "/var/log/global.log"},
Postgres: Postgres{
Enabled: true,
Port: 5432,
Hosts: []string{"192.168.2.1", "192.168.2.2", "192.168.2.3"},
DBName: "configdb",
AvailabilityRatio: 8.23,
Log: Log{File: "/var/log/postgres.log"},
},
}
}
Expand Down Expand Up @@ -154,6 +162,10 @@ func testStruct(t *testing.T, s *Server, d *Server) {
}
}

if s.Log.File != d.Log.File {
t.Errorf("Log value is wrong: %s, want: %s", s.Log.File, d.Log.File)
}

testPostgres(t, s.Postgres, d.Postgres)
}

Expand All @@ -180,6 +192,10 @@ func testPostgres(t *testing.T, s Postgres, d Postgres) {
t.Errorf("AvailabilityRatio is wrong: %f, want: %f", s.AvailabilityRatio, d.AvailabilityRatio)
}

if s.Log.File != d.Log.File {
t.Errorf("Postgres Log value is wrong: %s, want: %s", s.Log.File, d.Log.File)
}

if len(s.Hosts) != len(d.Hosts) {
// do not continue testing if this fails, because others is depending on this test
t.Fatalf("Hosts len is wrong: %v, want: %v", s.Hosts, d.Hosts)
Expand Down
8 changes: 7 additions & 1 deletion testdata/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
"ankara",
"istanbul"
],
"Log": {
"File": "/var/log/global.log"
},
"Postgres": {
"Enabled": true,
"Port": 5432,
Expand All @@ -19,6 +22,9 @@
"192.168.2.2",
"192.168.2.3"
],
"AvailabilityRatio": 8.23
"AvailabilityRatio": 8.23,
"Log": {
"File": "/var/log/postgres.log"
}
}
}
10 changes: 7 additions & 3 deletions testdata/config.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
Name = "koding"
Enabled = true
Users = ["ankara", "istanbul"]
Interval = 10000000000
ID = 1234567890
Labels = [123,456]
Interval = 10000000000
ID = 1234567890
Labels = [123,456]
[Log]
File = "/var/log/global.log"

[Postgres]
Enabled = true
Port = 5432
Hosts = ["192.168.2.1", "192.168.2.2", "192.168.2.3"]
AvailabilityRatio = 8.23
[Postgres.Log]
File = "/var/log/postgres.log"
5 changes: 5 additions & 0 deletions testdata/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ labels:
- 123
- 456

log:
file: /var/log/global.log

# postgres configure
postgres:
enabled: true
Expand All @@ -25,4 +28,6 @@ postgres:
- 192.168.2.2
- 192.168.2.3
availabilityratio: 8.23
log:
file: /var/log/postgres.log