2a7c1cc1d6
Taking the same approach as was taken in containerd The new library has a slightly different output; - keys at the same level are sorted alphabetically - empty sections not omitted (`proxy_plugins`, `stream_processors`, `timeouts`), which could possibly be be addressed with an "omitempty" in containerd's struct. - empty slices are not omitted (`imports`, `required_plugins`) After sorting the "before" configuration the diff looks like this: ```patch diff --git a/config-before-sorted.toml b/config-after.toml index cc771ce7ab..43a727f589 100644 --- a/config-before-sorted.toml +++ b/config-after.toml @@ -1,6 +1,8 @@ disabled_plugins = ["cri"] +imports = [] oom_score = 0 plugin_dir = "" +required_plugins = [] root = "/var/lib/docker/containerd/daemon" state = "/var/run/docker/containerd/daemon" version = 0 @@ -37,6 +39,12 @@ version = 0 shim = "containerd-shim" shim_debug = true +[proxy_plugins] + +[stream_processors] + +[timeouts] + [ttrpc] address = "" gid = 0 ``` Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
112 lines
2.4 KiB
Go
112 lines
2.4 KiB
Go
// Parsing keys handling both bare and quoted keys.
|
|
|
|
package toml
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
)
|
|
|
|
// Convert the bare key group string to an array.
|
|
// The input supports double quotation and single quotation,
|
|
// but escape sequences are not supported. Lexers must unescape them beforehand.
|
|
func parseKey(key string) ([]string, error) {
|
|
runes := []rune(key)
|
|
var groups []string
|
|
|
|
if len(key) == 0 {
|
|
return nil, errors.New("empty key")
|
|
}
|
|
|
|
idx := 0
|
|
for idx < len(runes) {
|
|
for ; idx < len(runes) && isSpace(runes[idx]); idx++ {
|
|
// skip leading whitespace
|
|
}
|
|
if idx >= len(runes) {
|
|
break
|
|
}
|
|
r := runes[idx]
|
|
if isValidBareChar(r) {
|
|
// parse bare key
|
|
startIdx := idx
|
|
endIdx := -1
|
|
idx++
|
|
for idx < len(runes) {
|
|
r = runes[idx]
|
|
if isValidBareChar(r) {
|
|
idx++
|
|
} else if r == '.' {
|
|
endIdx = idx
|
|
break
|
|
} else if isSpace(r) {
|
|
endIdx = idx
|
|
for ; idx < len(runes) && isSpace(runes[idx]); idx++ {
|
|
// skip trailing whitespace
|
|
}
|
|
if idx < len(runes) && runes[idx] != '.' {
|
|
return nil, fmt.Errorf("invalid key character after whitespace: %c", runes[idx])
|
|
}
|
|
break
|
|
} else {
|
|
return nil, fmt.Errorf("invalid bare key character: %c", r)
|
|
}
|
|
}
|
|
if endIdx == -1 {
|
|
endIdx = idx
|
|
}
|
|
groups = append(groups, string(runes[startIdx:endIdx]))
|
|
} else if r == '\'' {
|
|
// parse single quoted key
|
|
idx++
|
|
startIdx := idx
|
|
for {
|
|
if idx >= len(runes) {
|
|
return nil, fmt.Errorf("unclosed single-quoted key")
|
|
}
|
|
r = runes[idx]
|
|
if r == '\'' {
|
|
groups = append(groups, string(runes[startIdx:idx]))
|
|
idx++
|
|
break
|
|
}
|
|
idx++
|
|
}
|
|
} else if r == '"' {
|
|
// parse double quoted key
|
|
idx++
|
|
startIdx := idx
|
|
for {
|
|
if idx >= len(runes) {
|
|
return nil, fmt.Errorf("unclosed double-quoted key")
|
|
}
|
|
r = runes[idx]
|
|
if r == '"' {
|
|
groups = append(groups, string(runes[startIdx:idx]))
|
|
idx++
|
|
break
|
|
}
|
|
idx++
|
|
}
|
|
} else if r == '.' {
|
|
idx++
|
|
if idx >= len(runes) {
|
|
return nil, fmt.Errorf("unexpected end of key")
|
|
}
|
|
r = runes[idx]
|
|
if !isValidBareChar(r) && r != '\'' && r != '"' && r != ' ' {
|
|
return nil, fmt.Errorf("expecting key part after dot")
|
|
}
|
|
} else {
|
|
return nil, fmt.Errorf("invalid key character: %c", r)
|
|
}
|
|
}
|
|
if len(groups) == 0 {
|
|
return nil, fmt.Errorf("empty key")
|
|
}
|
|
return groups, nil
|
|
}
|
|
|
|
func isValidBareChar(r rune) bool {
|
|
return isAlphanumeric(r) || r == '-' || isDigit(r)
|
|
}
|