Making the field name matching when merging respect the toml struct tag.
If the field has a toml struct tag, don't try fuzzy matching, thanks to @ekini.
This commit is contained in:
parent
f7eae86cdb
commit
23e6715a02
33
config.go
33
config.go
|
@ -369,12 +369,29 @@ func PrintOutputConfig(name string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used for fuzzy matching struct field names in FieldByNameFunc calls below
|
// Find the field with a name matching fieldName, respecting the struct tag and ignoring case and underscores.
|
||||||
func fieldMatch(field string) func(string) bool {
|
// If no field is found, return the zero reflect.Value, which should be checked for with .IsValid().
|
||||||
return func(name string) bool {
|
func findField(fieldName string, value reflect.Value) reflect.Value {
|
||||||
r := strings.NewReplacer("_", "")
|
r := strings.NewReplacer("_", "")
|
||||||
return strings.ToLower(name) == strings.ToLower(r.Replace(field))
|
vType := value.Type()
|
||||||
|
for i := 0; i < vType.NumField(); i++ {
|
||||||
|
fieldType := vType.Field(i)
|
||||||
|
|
||||||
|
// if we have toml tag, use it
|
||||||
|
if tag := fieldType.Tag.Get("toml"); tag != "" {
|
||||||
|
if tag == "-" { // omit
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if tag == fieldName {
|
||||||
|
return value.Field(i)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if strings.ToLower(fieldType.Name) == strings.ToLower(r.Replace(fieldName)) {
|
||||||
|
return value.Field(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return reflect.Value{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A very limited merge. Merges the fields named in the fields parameter, replacing most values, but appending to arrays.
|
// A very limited merge. Merges the fields named in the fields parameter, replacing most values, but appending to arrays.
|
||||||
|
@ -388,15 +405,15 @@ func mergeStruct(base, overlay interface{}, fields []string) error {
|
||||||
return fmt.Errorf("Tried to merge two different types: %v and %v", baseValue.Type(), overlayValue.Type())
|
return fmt.Errorf("Tried to merge two different types: %v and %v", baseValue.Type(), overlayValue.Type())
|
||||||
}
|
}
|
||||||
for _, field := range fields {
|
for _, field := range fields {
|
||||||
overlayFieldValue := overlayValue.FieldByNameFunc(fieldMatch(field))
|
overlayFieldValue := findField(field, overlayValue)
|
||||||
if !overlayFieldValue.IsValid() {
|
if !overlayFieldValue.IsValid() {
|
||||||
return fmt.Errorf("could not find field in %v matching %v", overlayValue.Type(), field)
|
return fmt.Errorf("could not find field in %v matching %v", overlayValue.Type(), field)
|
||||||
}
|
}
|
||||||
|
baseFieldValue := findField(field, baseValue)
|
||||||
if overlayFieldValue.Kind() == reflect.Slice {
|
if overlayFieldValue.Kind() == reflect.Slice {
|
||||||
baseFieldValue := baseValue.FieldByNameFunc(fieldMatch(field))
|
|
||||||
baseFieldValue.Set(reflect.AppendSlice(baseFieldValue, overlayFieldValue))
|
baseFieldValue.Set(reflect.AppendSlice(baseFieldValue, overlayFieldValue))
|
||||||
} else {
|
} else {
|
||||||
baseValue.FieldByNameFunc(fieldMatch(field)).Set(overlayFieldValue)
|
baseFieldValue.Set(overlayFieldValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -16,22 +16,6 @@ import (
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestConfig_fieldMatch(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
|
|
||||||
matchFunc := fieldMatch("testfield")
|
|
||||||
assert.True(matchFunc("testField"), "testfield should match testField")
|
|
||||||
assert.True(matchFunc("TestField"), "testfield should match TestField")
|
|
||||||
assert.True(matchFunc("TESTFIELD"), "testfield should match TESTFIELD")
|
|
||||||
assert.False(matchFunc("OtherField"), "testfield should not match OtherField")
|
|
||||||
|
|
||||||
matchFunc = fieldMatch("test_field")
|
|
||||||
assert.True(matchFunc("testField"), "test_field should match testField")
|
|
||||||
assert.True(matchFunc("TestField"), "test_field should match TestField")
|
|
||||||
assert.True(matchFunc("TESTFIELD"), "test_field should match TESTFIELD")
|
|
||||||
assert.False(matchFunc("OtherField"), "test_field should not match OtherField")
|
|
||||||
}
|
|
||||||
|
|
||||||
type subTest struct {
|
type subTest struct {
|
||||||
AField string
|
AField string
|
||||||
AnotherField int
|
AnotherField int
|
||||||
|
@ -40,7 +24,7 @@ type test struct {
|
||||||
StringField string
|
StringField string
|
||||||
IntegerField int
|
IntegerField int
|
||||||
FloatField float32
|
FloatField float32
|
||||||
BooleanField bool
|
BooleansField bool `toml:"boolean_field"`
|
||||||
DatetimeField time.Time
|
DatetimeField time.Time
|
||||||
ArrayField []string
|
ArrayField []string
|
||||||
TableArrayField []subTest
|
TableArrayField []subTest
|
||||||
|
@ -67,7 +51,7 @@ func (s *MergeStructSuite) SetupTest() {
|
||||||
StringField: "one",
|
StringField: "one",
|
||||||
IntegerField: 1,
|
IntegerField: 1,
|
||||||
FloatField: 1.1,
|
FloatField: 1.1,
|
||||||
BooleanField: false,
|
BooleansField: false,
|
||||||
DatetimeField: time.Date(1963, time.August, 28, 17, 0, 0, 0, time.UTC),
|
DatetimeField: time.Date(1963, time.August, 28, 17, 0, 0, 0, time.UTC),
|
||||||
ArrayField: []string{"one", "two", "three"},
|
ArrayField: []string{"one", "two", "three"},
|
||||||
TableArrayField: []subTest{
|
TableArrayField: []subTest{
|
||||||
|
@ -85,7 +69,7 @@ func (s *MergeStructSuite) SetupTest() {
|
||||||
StringField: "two",
|
StringField: "two",
|
||||||
IntegerField: 2,
|
IntegerField: 2,
|
||||||
FloatField: 2.2,
|
FloatField: 2.2,
|
||||||
BooleanField: true,
|
BooleansField: true,
|
||||||
DatetimeField: time.Date(1965, time.March, 25, 17, 0, 0, 0, time.UTC),
|
DatetimeField: time.Date(1965, time.March, 25, 17, 0, 0, 0, time.UTC),
|
||||||
ArrayField: []string{"four", "five", "six"},
|
ArrayField: []string{"four", "five", "six"},
|
||||||
TableArrayField: []subTest{
|
TableArrayField: []subTest{
|
||||||
|
@ -114,7 +98,7 @@ func (s *MergeStructSuite) TestFullMerge() {
|
||||||
StringField: "two",
|
StringField: "two",
|
||||||
IntegerField: 2,
|
IntegerField: 2,
|
||||||
FloatField: 2.2,
|
FloatField: 2.2,
|
||||||
BooleanField: true,
|
BooleansField: true,
|
||||||
DatetimeField: time.Date(1965, time.March, 25, 17, 0, 0, 0, time.UTC),
|
DatetimeField: time.Date(1965, time.March, 25, 17, 0, 0, 0, time.UTC),
|
||||||
ArrayField: []string{"one", "two", "three", "four", "five", "six"},
|
ArrayField: []string{"one", "two", "three", "four", "five", "six"},
|
||||||
TableArrayField: []subTest{
|
TableArrayField: []subTest{
|
||||||
|
@ -149,7 +133,7 @@ func (s *MergeStructSuite) TestPartialMergeWithoutSlices() {
|
||||||
StringField: "two",
|
StringField: "two",
|
||||||
IntegerField: 1,
|
IntegerField: 1,
|
||||||
FloatField: 2.2,
|
FloatField: 2.2,
|
||||||
BooleanField: false,
|
BooleansField: false,
|
||||||
DatetimeField: time.Date(1965, time.March, 25, 17, 0, 0, 0, time.UTC),
|
DatetimeField: time.Date(1965, time.March, 25, 17, 0, 0, 0, time.UTC),
|
||||||
ArrayField: []string{"one", "two", "three"},
|
ArrayField: []string{"one", "two", "three"},
|
||||||
TableArrayField: []subTest{
|
TableArrayField: []subTest{
|
||||||
|
@ -176,7 +160,7 @@ func (s *MergeStructSuite) TestPartialMergeWithSlices() {
|
||||||
StringField: "two",
|
StringField: "two",
|
||||||
IntegerField: 1,
|
IntegerField: 1,
|
||||||
FloatField: 2.2,
|
FloatField: 2.2,
|
||||||
BooleanField: false,
|
BooleansField: false,
|
||||||
DatetimeField: time.Date(1965, time.March, 25, 17, 0, 0, 0, time.UTC),
|
DatetimeField: time.Date(1965, time.March, 25, 17, 0, 0, 0, time.UTC),
|
||||||
ArrayField: []string{"one", "two", "three"},
|
ArrayField: []string{"one", "two", "three"},
|
||||||
TableArrayField: []subTest{
|
TableArrayField: []subTest{
|
||||||
|
|
Loading…
Reference in New Issue