New static configuration loading system.
Co-authored-by: Mathieu Lonjaret <mathieu.lonjaret@gmail.com>
This commit is contained in:
parent
d18edd6f77
commit
8d7eccad5d
165 changed files with 10894 additions and 6076 deletions
166
pkg/config/parser/flat_encode.go
Normal file
166
pkg/config/parser/flat_encode.go
Normal file
|
@ -0,0 +1,166 @@
|
|||
package parser
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/containous/traefik/pkg/types"
|
||||
)
|
||||
|
||||
const defaultPtrValue = "false"
|
||||
|
||||
// FlatOpts holds options used when encoding to Flat.
|
||||
type FlatOpts struct {
|
||||
Case string // "lower" or "upper", defaults to "lower".
|
||||
Separator string
|
||||
SkipRoot bool
|
||||
}
|
||||
|
||||
// Flat is a configuration item representation.
|
||||
type Flat struct {
|
||||
Name string
|
||||
Description string
|
||||
Default string
|
||||
}
|
||||
|
||||
// EncodeToFlat encodes a node to a Flat representation.
|
||||
// Even though the given node argument should have already been augmented with metadata such as kind,
|
||||
// the element (and its type information) is still needed to treat remaining edge cases.
|
||||
func EncodeToFlat(element interface{}, node *Node, opts FlatOpts) ([]Flat, error) {
|
||||
if element == nil || node == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if node.Kind == 0 {
|
||||
return nil, fmt.Errorf("missing node type: %s", node.Name)
|
||||
}
|
||||
|
||||
elem := reflect.ValueOf(element)
|
||||
if elem.Kind() == reflect.Struct {
|
||||
return nil, fmt.Errorf("structs are not supported, use pointer instead")
|
||||
}
|
||||
|
||||
encoder := encoderToFlat{FlatOpts: opts}
|
||||
|
||||
var entries []Flat
|
||||
if encoder.SkipRoot {
|
||||
for _, child := range node.Children {
|
||||
field := encoder.getField(elem.Elem(), child)
|
||||
entries = append(entries, encoder.createFlat(field, child.Name, child)...)
|
||||
}
|
||||
} else {
|
||||
entries = encoder.createFlat(elem, strings.ToLower(node.Name), node)
|
||||
}
|
||||
|
||||
sort.Slice(entries, func(i, j int) bool { return entries[i].Name < entries[j].Name })
|
||||
|
||||
return entries, nil
|
||||
}
|
||||
|
||||
type encoderToFlat struct {
|
||||
FlatOpts
|
||||
}
|
||||
|
||||
func (e encoderToFlat) createFlat(field reflect.Value, name string, node *Node) []Flat {
|
||||
var entries []Flat
|
||||
if node.Kind != reflect.Map && node.Description != "-" {
|
||||
if !(node.Kind == reflect.Ptr && len(node.Children) > 0) ||
|
||||
(node.Kind == reflect.Ptr && node.Tag.Get("label") == TagLabelAllowEmpty) {
|
||||
if node.Name[0] != '[' {
|
||||
entries = append(entries, Flat{
|
||||
Name: e.getName(name),
|
||||
Description: node.Description,
|
||||
Default: e.getNodeValue(e.getField(field, node), node),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, child := range node.Children {
|
||||
if node.Kind == reflect.Map {
|
||||
fChild := e.getField(field, child)
|
||||
|
||||
var v string
|
||||
if child.Kind == reflect.Struct {
|
||||
v = defaultPtrValue
|
||||
} else {
|
||||
v = e.getNodeValue(fChild, child)
|
||||
}
|
||||
|
||||
if node.Description != "-" {
|
||||
entries = append(entries, Flat{
|
||||
Name: e.getName(name, child.Name),
|
||||
Description: node.Description,
|
||||
Default: v,
|
||||
})
|
||||
}
|
||||
|
||||
if child.Kind == reflect.Struct || child.Kind == reflect.Ptr {
|
||||
for _, ch := range child.Children {
|
||||
f := e.getField(fChild, ch)
|
||||
n := e.getName(name, child.Name, ch.Name)
|
||||
entries = append(entries, e.createFlat(f, n, ch)...)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
f := e.getField(field, child)
|
||||
n := e.getName(name, child.Name)
|
||||
entries = append(entries, e.createFlat(f, n, child)...)
|
||||
}
|
||||
}
|
||||
|
||||
return entries
|
||||
}
|
||||
|
||||
func (e encoderToFlat) getField(field reflect.Value, node *Node) reflect.Value {
|
||||
switch field.Kind() {
|
||||
case reflect.Struct:
|
||||
return field.FieldByName(node.FieldName)
|
||||
case reflect.Ptr:
|
||||
if field.Elem().Kind() == reflect.Struct {
|
||||
return field.Elem().FieldByName(node.FieldName)
|
||||
}
|
||||
return field.Elem()
|
||||
case reflect.Map:
|
||||
return field.MapIndex(reflect.ValueOf(node.FieldName))
|
||||
default:
|
||||
return field
|
||||
}
|
||||
}
|
||||
|
||||
func (e encoderToFlat) getNodeValue(field reflect.Value, node *Node) string {
|
||||
if node.Kind == reflect.Ptr && len(node.Children) > 0 {
|
||||
return defaultPtrValue
|
||||
}
|
||||
|
||||
if field.Kind() == reflect.Int64 {
|
||||
i, _ := strconv.ParseInt(node.Value, 10, 64)
|
||||
|
||||
switch field.Type() {
|
||||
case reflect.TypeOf(types.Duration(time.Second)):
|
||||
return strconv.Itoa(int(i) / int(time.Second))
|
||||
case reflect.TypeOf(time.Second):
|
||||
return time.Duration(i).String()
|
||||
}
|
||||
}
|
||||
|
||||
return node.Value
|
||||
}
|
||||
|
||||
func (e encoderToFlat) getName(names ...string) string {
|
||||
var name string
|
||||
if names[len(names)-1][0] == '[' {
|
||||
name = strings.Join(names, "")
|
||||
} else {
|
||||
name = strings.Join(names, e.Separator)
|
||||
}
|
||||
|
||||
if strings.EqualFold(e.Case, "upper") {
|
||||
return strings.ToUpper(name)
|
||||
}
|
||||
return strings.ToLower(name)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue