Fix slice parsing for plugins

This commit is contained in:
Ludovic Fernandez 2022-03-28 15:24:08 +02:00 committed by GitHub
parent 16d7b89cb1
commit b6bfa905db
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 86 additions and 2 deletions

View file

@ -86,7 +86,7 @@ func (p middlewareBuilder) createConfig(config map[string]interface{}) (reflect.
vConfig := results[0] vConfig := results[0]
cfg := &mapstructure.DecoderConfig{ cfg := &mapstructure.DecoderConfig{
DecodeHook: mapstructure.StringToSliceHookFunc(","), DecodeHook: stringToSliceHookFunc,
WeaklyTypedInput: true, WeaklyTypedInput: true,
Result: vConfig.Interface(), Result: vConfig.Interface(),
} }

View file

@ -4,6 +4,7 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"reflect"
"strings" "strings"
"github.com/hashicorp/go-multierror" "github.com/hashicorp/go-multierror"
@ -166,3 +167,26 @@ func checkLocalPluginManifest(descriptor LocalDescriptor) error {
return errs.ErrorOrNil() return errs.ErrorOrNil()
} }
func stringToSliceHookFunc(f reflect.Kind, t reflect.Kind, data interface{}) (interface{}, error) {
if f != reflect.String || t != reflect.Slice {
return data, nil
}
raw := data.(string)
if raw == "" {
return []string{}, nil
}
if strings.Contains(raw, "║") {
values := strings.Split(raw, "║")
// Removes the first value if the slice has a length of 2 and a first value empty.
// It's a workaround to escape the parsing on `,`.
if len(values) == 2 && values[0] == "" {
return values[1:], nil
}
return values, nil
}
return strings.Split(raw, ","), nil
}

View file

@ -0,0 +1,60 @@
package plugins
import (
"reflect"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func Test_stringToSliceHookFunc(t *testing.T) {
testCases := []struct {
desc string
data string
expected []string
}{
{
desc: "without separator",
data: "abc",
expected: []string{"abc"},
},
{
desc: "with the file separator",
data: "a║b║c",
expected: []string{"a", "b", "c"},
},
{
desc: "with the label separator",
data: "a,b,c",
expected: []string{"a", "b", "c"},
},
{
desc: "with the file separator and values with commas",
data: "a,z║b,w║c,x,y",
expected: []string{"a,z", "b,w", "c,x,y"},
},
{
desc: "escaping workaround",
data: "║a,z",
expected: []string{"a,z"},
},
{
desc: "with the file separator and empty item",
data: "║a║z",
expected: []string{"", "a", "z"},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
values, err := stringToSliceHookFunc(reflect.String, reflect.Slice, test.data)
require.NoError(t, err)
assert.EqualValues(t, test.expected, values)
})
}
}

View file

@ -93,7 +93,7 @@ func newProvider(builder providerBuilder, config map[string]interface{}, provide
} }
cfg := &mapstructure.DecoderConfig{ cfg := &mapstructure.DecoderConfig{
DecodeHook: mapstructure.StringToSliceHookFunc(","), DecodeHook: stringToSliceHookFunc,
WeaklyTypedInput: true, WeaklyTypedInput: true,
Result: vConfig.Interface(), Result: vConfig.Interface(),
} }