support inline yaml for docker labels, serveral minor fixes

This commit is contained in:
yusing
2025-01-03 15:35:40 +08:00
parent 6e30d39b78
commit b38bff41d8
7 changed files with 248 additions and 42 deletions

View File

@@ -24,8 +24,6 @@ var (
ErrNilValue = E.New("nil")
ErrUnsettable = E.New("unsettable")
ErrUnsupportedConversion = E.New("unsupported conversion")
ErrMapMissingColon = E.New("map missing colon")
ErrMapTooManyColons = E.New("map too many colons")
ErrUnknownField = E.New("unknown field")
)
@@ -422,19 +420,12 @@ func ConvertString(src string, dst reflect.Value) (convertible bool, convErr E.E
return true, E.From(parser.Parse(src))
}
// yaml like
lines := []string{}
src = strings.TrimSpace(src)
if src != "" {
lines = strutils.SplitLine(src)
for i := range lines {
lines[i] = strings.TrimSpace(lines[i])
}
}
isMultiline := strings.ContainsRune(src, '\n')
var tmp any
switch dst.Kind() {
case reflect.Slice:
// one liner is comma separated list
if len(lines) == 1 {
if !isMultiline {
values := strutils.CommaSeperatedList(src)
dst.Set(reflect.MakeSlice(dst.Type(), len(values), len(values)))
errs := E.NewBuilder("invalid slice values")
@@ -449,38 +440,25 @@ func ConvertString(src string, dst reflect.Value) (convertible bool, convErr E.E
}
return
}
lines := strutils.SplitLine(src)
sl := make([]string, 0, len(lines))
for _, line := range lines {
line = strings.TrimLeftFunc(line, func(r rune) bool {
return r == '-' || unicode.IsSpace(r)
})
if line == "" {
if line == "" || line[0] == '#' {
continue
}
sl = append(sl, line)
}
tmp = sl
case reflect.Map:
m := make(map[string]string, len(lines))
errs := E.NewBuilder("invalid map")
for i, line := range lines {
parts := strings.Split(line, ":")
if len(parts) < 2 {
errs.Add(ErrMapMissingColon.Subjectf("line %d", i+1))
continue
}
if len(parts) > 2 {
errs.Add(ErrMapTooManyColons.Subjectf("line %d", i+1))
continue
}
k := strings.TrimSpace(parts[0])
v := strings.TrimSpace(parts[1])
m[k] = v
case reflect.Map, reflect.Struct:
rawMap := make(SerializedObject)
err := yaml.Unmarshal([]byte(src), &rawMap)
if err != nil {
return true, E.From(err)
}
if errs.HasError() {
return true, errs.Error()
}
tmp = m
tmp = rawMap
default:
return false, nil
}

View File

@@ -163,3 +163,53 @@ func TestConvertor(t *testing.T) {
ExpectError(t, ErrUnsupportedConversion, Deserialize(map[string]any{"Test": struct{}{}}, m))
})
}
func TestStringToSlice(t *testing.T) {
t.Run("comma_separated", func(t *testing.T) {
dst := make([]string, 0)
convertible, err := ConvertString("a,b,c", reflect.ValueOf(&dst))
ExpectTrue(t, convertible)
ExpectNoError(t, err)
ExpectDeepEqual(t, dst, []string{"a", "b", "c"})
})
t.Run("multiline", func(t *testing.T) {
dst := make([]string, 0)
convertible, err := ConvertString(" a\n b\n c", reflect.ValueOf(&dst))
ExpectTrue(t, convertible)
ExpectNoError(t, err)
ExpectDeepEqual(t, dst, []string{"a", "b", "c"})
})
t.Run("yaml-like", func(t *testing.T) {
dst := make([]string, 0)
convertible, err := ConvertString(" - a\n - b\n - c", reflect.ValueOf(&dst))
ExpectTrue(t, convertible)
ExpectNoError(t, err)
ExpectDeepEqual(t, dst, []string{"a", "b", "c"})
})
}
func TestStringToMap(t *testing.T) {
t.Run("yaml-like", func(t *testing.T) {
dst := make(map[string]string)
convertible, err := ConvertString(" a: b\n c: d", reflect.ValueOf(&dst))
ExpectTrue(t, convertible)
ExpectNoError(t, err)
ExpectDeepEqual(t, dst, map[string]string{"a": "b", "c": "d"})
})
}
func TestStringToStruct(t *testing.T) {
t.Run("yaml-like", func(t *testing.T) {
dst := struct {
A string
B int
}{}
convertible, err := ConvertString(" A: a\n B: 123", reflect.ValueOf(&dst))
ExpectTrue(t, convertible)
ExpectNoError(t, err)
ExpectDeepEqual(t, dst, struct {
A string
B int
}{"a", 123})
})
}