rc: allow setting rc config and filter options as flat parameters
This commit allows global config options to be set as flat parameters on all rc commands. This makes the rc commands much more like command line parameters and will aid understanding of how the rc is used. It is backwards compatible with the old method using _config and _filter.
This commit is contained in:
@@ -133,6 +133,19 @@ func InterfaceToString(in any) (strValue string, err error) {
|
||||
if do, ok := in.(fmt.Stringer); ok {
|
||||
strValue = do.String()
|
||||
} else {
|
||||
// Check if it is a slice or array
|
||||
val := reflect.ValueOf(in)
|
||||
if val.Kind() == reflect.Slice || val.Kind() == reflect.Array {
|
||||
strSlice := make([]string, val.Len())
|
||||
for i := 0; i < val.Len(); i++ {
|
||||
strValue, err = InterfaceToString(val.Index(i).Interface())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
strSlice[i] = strValue
|
||||
}
|
||||
return InterfaceToString(strSlice)
|
||||
}
|
||||
err = errors.New("don't know how to convert this")
|
||||
}
|
||||
}
|
||||
@@ -262,14 +275,35 @@ func Set(config configmap.Getter, opt any) (err error) {
|
||||
|
||||
// setIfSameType set aPtr with b if they are the same type or returns false.
|
||||
func setIfSameType(aPtr any, b any) bool {
|
||||
if b == nil {
|
||||
return false
|
||||
}
|
||||
aVal := reflect.ValueOf(aPtr).Elem()
|
||||
bVal := reflect.ValueOf(b)
|
||||
|
||||
if aVal.Type() != bVal.Type() {
|
||||
return false
|
||||
if aVal.Type() == bVal.Type() {
|
||||
aVal.Set(bVal)
|
||||
return true
|
||||
}
|
||||
aVal.Set(bVal)
|
||||
return true
|
||||
|
||||
// Special case: if target is []string and source is a slice or array
|
||||
if aVal.Type() == reflect.TypeOf([]string(nil)) && (bVal.Kind() == reflect.Slice || bVal.Kind() == reflect.Array) {
|
||||
strSlice := make([]string, bVal.Len())
|
||||
ok := true
|
||||
for i := 0; i < bVal.Len(); i++ {
|
||||
var err error
|
||||
strSlice[i], err = InterfaceToString(bVal.Index(i).Interface())
|
||||
if err != nil {
|
||||
ok = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if ok {
|
||||
aVal.Set(reflect.ValueOf(strSlice))
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// SetAny interprets the field names in defaults and looks up config
|
||||
|
||||
@@ -209,6 +209,45 @@ func TestSetAnyFull(t *testing.T) {
|
||||
assert.Equal(t, want, in)
|
||||
}
|
||||
|
||||
func TestSetAnyWithSlice(t *testing.T) {
|
||||
type ConfWithSlice struct {
|
||||
ExcludeRule []string `config:"exclude"`
|
||||
}
|
||||
|
||||
// 1. Test []any (JSON array of strings)
|
||||
in := &ConfWithSlice{
|
||||
ExcludeRule: []string{"original"},
|
||||
}
|
||||
m := map[string]any{
|
||||
"exclude": []any{"foo", "bar"},
|
||||
}
|
||||
err := configstruct.SetAny(m, in)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []string{"foo", "bar"}, in.ExcludeRule)
|
||||
|
||||
// 2. Test []string directly
|
||||
in2 := &ConfWithSlice{
|
||||
ExcludeRule: []string{"original"},
|
||||
}
|
||||
m2 := map[string]any{
|
||||
"exclude": []string{"hello", "world"},
|
||||
}
|
||||
err = configstruct.SetAny(m2, in2)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []string{"hello", "world"}, in2.ExcludeRule)
|
||||
|
||||
// 3. Test []any with mixed convertible types (e.g. ints/floats/bools)
|
||||
in3 := &ConfWithSlice{
|
||||
ExcludeRule: []string{"original"},
|
||||
}
|
||||
m3 := map[string]any{
|
||||
"exclude": []any{"foo", 123, true, 45.6},
|
||||
}
|
||||
err = configstruct.SetAny(m3, in3)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []string{"foo", "123", "true", "45.6"}, in3.ExcludeRule)
|
||||
}
|
||||
|
||||
func TestStringToInterface(t *testing.T) {
|
||||
item := struct{ A int }{2}
|
||||
for _, test := range []struct {
|
||||
@@ -288,6 +327,13 @@ func TestInterfaceToString(t *testing.T) {
|
||||
{[]string{"hello", "world"}, `hello,world`, ""},
|
||||
{[]string{"hello", "", "world"}, `hello,,world`, ""},
|
||||
{[]string{`hello, world`, `goodbye, world!`}, `"hello, world","goodbye, world!"`, ""},
|
||||
{[]any{"hello", "world"}, `hello,world`, ""},
|
||||
{[]any{123, 456}, `123,456`, ""},
|
||||
{[]any{"hello", 45.6, true}, `hello,45.6,true`, ""},
|
||||
{[2]string{"a", "b"}, `a,b`, ""},
|
||||
{[2]any{"x", 12}, `x,12`, ""},
|
||||
{fs.SpaceSepList{"a", "b"}, `a b`, ""},
|
||||
{fs.CommaSepList{"x", "y"}, `x,y`, ""},
|
||||
{time.Second, "1s", ""},
|
||||
{61 * time.Second, "1m1s", ""},
|
||||
{fs.Mebi, "1Mi", ""},
|
||||
|
||||
Reference in New Issue
Block a user