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
21
vendor/github.com/containous/flaeg/LICENSE.md
generated
vendored
21
vendor/github.com/containous/flaeg/LICENSE.md
generated
vendored
|
@ -1,21 +0,0 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Containous SAS, Emile Vauge, emile@vauge.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
742
vendor/github.com/containous/flaeg/flaeg.go
generated
vendored
742
vendor/github.com/containous/flaeg/flaeg.go
generated
vendored
|
@ -1,742 +0,0 @@
|
|||
package flaeg
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"text/template"
|
||||
|
||||
"github.com/containous/flaeg/parse"
|
||||
flag "github.com/ogier/pflag"
|
||||
)
|
||||
|
||||
// ErrParserNotFound is thrown when a field is flaged but not parser match its type
|
||||
var ErrParserNotFound = errors.New("parser not found or custom parser missing")
|
||||
|
||||
// GetTypesRecursive links in flagMap a flag with its reflect.StructField
|
||||
// You can whether provide objValue on a structure or a pointer to structure as first argument
|
||||
// Flags are generated from field name or from StructTag
|
||||
func getTypesRecursive(objValue reflect.Value, flagMap map[string]reflect.StructField, key string) error {
|
||||
name := key
|
||||
switch objValue.Kind() {
|
||||
case reflect.Struct:
|
||||
for i := 0; i < objValue.NumField(); i++ {
|
||||
if objValue.Type().Field(i).Anonymous {
|
||||
if err := getTypesRecursive(objValue.Field(i), flagMap, name); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if len(objValue.Type().Field(i).Tag.Get("description")) > 0 {
|
||||
fieldName := objValue.Type().Field(i).Name
|
||||
if !isExported(fieldName) {
|
||||
return fmt.Errorf("field %s is an unexported field", fieldName)
|
||||
}
|
||||
|
||||
if tag := objValue.Type().Field(i).Tag.Get("long"); len(tag) > 0 {
|
||||
fieldName = tag
|
||||
}
|
||||
|
||||
if len(key) == 0 {
|
||||
name = strings.ToLower(fieldName)
|
||||
} else {
|
||||
name = key + "." + strings.ToLower(fieldName)
|
||||
}
|
||||
|
||||
if _, ok := flagMap[name]; ok {
|
||||
return fmt.Errorf("tag already exists: %s", name)
|
||||
}
|
||||
flagMap[name] = objValue.Type().Field(i)
|
||||
|
||||
if err := getTypesRecursive(objValue.Field(i), flagMap, name); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
case reflect.Ptr:
|
||||
if len(key) > 0 {
|
||||
field := flagMap[name]
|
||||
field.Type = reflect.TypeOf(false)
|
||||
flagMap[name] = field
|
||||
}
|
||||
|
||||
typ := objValue.Type().Elem()
|
||||
inst := reflect.New(typ).Elem()
|
||||
|
||||
if err := getTypesRecursive(inst, flagMap, name); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetBoolFlags returns flags on pointers
|
||||
func GetBoolFlags(config interface{}) ([]string, error) {
|
||||
flagMap := make(map[string]reflect.StructField)
|
||||
if err := getTypesRecursive(reflect.ValueOf(config), flagMap, ""); err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
|
||||
flags := make([]string, 0, len(flagMap))
|
||||
for f, structField := range flagMap {
|
||||
if structField.Type.Kind() == reflect.Bool {
|
||||
flags = append(flags, f)
|
||||
}
|
||||
}
|
||||
return flags, nil
|
||||
}
|
||||
|
||||
// GetFlags returns flags
|
||||
func GetFlags(config interface{}) ([]string, error) {
|
||||
flagMap := make(map[string]reflect.StructField)
|
||||
if err := getTypesRecursive(reflect.ValueOf(config), flagMap, ""); err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
|
||||
flags := make([]string, 0, len(flagMap))
|
||||
for f := range flagMap {
|
||||
flags = append(flags, f)
|
||||
}
|
||||
return flags, nil
|
||||
}
|
||||
|
||||
// ParseArgs : parses args return a map[flag]Getter, using parsers map[type]Getter
|
||||
// args must be formatted as like as flag documentation. See https://golang.org/pkg/flag
|
||||
func parseArgs(args []string, flagMap map[string]reflect.StructField, parsers map[reflect.Type]parse.Parser) (map[string]parse.Parser, error) {
|
||||
newParsers := map[string]parse.Parser{}
|
||||
flagSet := flag.NewFlagSet("flaeg.Load", flag.ContinueOnError)
|
||||
|
||||
// Disable output
|
||||
flagSet.SetOutput(ioutil.Discard)
|
||||
|
||||
var err error
|
||||
for flg, structField := range flagMap {
|
||||
if parser, ok := parsers[structField.Type]; ok {
|
||||
newParserValue := reflect.New(reflect.TypeOf(parser).Elem())
|
||||
newParserValue.Elem().Set(reflect.ValueOf(parser).Elem())
|
||||
newParser := newParserValue.Interface().(parse.Parser)
|
||||
|
||||
if short := structField.Tag.Get("short"); len(short) == 1 {
|
||||
flagSet.VarP(newParser, flg, short, structField.Tag.Get("description"))
|
||||
} else {
|
||||
flagSet.Var(newParser, flg, structField.Tag.Get("description"))
|
||||
}
|
||||
newParsers[flg] = newParser
|
||||
} else {
|
||||
err = ErrParserNotFound
|
||||
}
|
||||
}
|
||||
|
||||
// prevents case sensitivity issue
|
||||
args = argsToLower(args)
|
||||
if errParse := flagSet.Parse(args); errParse != nil {
|
||||
return nil, errParse
|
||||
}
|
||||
|
||||
// Visitor in flag.Parse
|
||||
var flagList []*flag.Flag
|
||||
visitor := func(fl *flag.Flag) {
|
||||
flagList = append(flagList, fl)
|
||||
}
|
||||
|
||||
// Fill flagList with parsed flags
|
||||
flagSet.Visit(visitor)
|
||||
|
||||
// Return var
|
||||
valMap := make(map[string]parse.Parser)
|
||||
|
||||
// Return parsers on parsed flag
|
||||
for _, flg := range flagList {
|
||||
valMap[flg.Name] = newParsers[flg.Name]
|
||||
}
|
||||
|
||||
return valMap, err
|
||||
}
|
||||
|
||||
func getDefaultValue(defaultValue reflect.Value, defaultPointersValue reflect.Value, defaultValmap map[string]reflect.Value, key string) error {
|
||||
if defaultValue.Type() != defaultPointersValue.Type() {
|
||||
return fmt.Errorf("parameters defaultValue and defaultPointersValue must be the same struct. defaultValue type: %s is not defaultPointersValue type: %s", defaultValue.Type().String(), defaultPointersValue.Type().String())
|
||||
}
|
||||
|
||||
name := key
|
||||
switch defaultValue.Kind() {
|
||||
case reflect.Struct:
|
||||
for i := 0; i < defaultValue.NumField(); i++ {
|
||||
if defaultValue.Type().Field(i).Anonymous {
|
||||
if err := getDefaultValue(defaultValue.Field(i), defaultPointersValue.Field(i), defaultValmap, name); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if len(defaultValue.Type().Field(i).Tag.Get("description")) > 0 {
|
||||
fieldName := defaultValue.Type().Field(i).Name
|
||||
if tag := defaultValue.Type().Field(i).Tag.Get("long"); len(tag) > 0 {
|
||||
fieldName = tag
|
||||
}
|
||||
|
||||
if len(key) == 0 {
|
||||
name = strings.ToLower(fieldName)
|
||||
} else {
|
||||
name = key + "." + strings.ToLower(fieldName)
|
||||
}
|
||||
|
||||
if defaultValue.Field(i).Kind() != reflect.Ptr {
|
||||
defaultValmap[name] = defaultValue.Field(i)
|
||||
}
|
||||
if err := getDefaultValue(defaultValue.Field(i), defaultPointersValue.Field(i), defaultValmap, name); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
case reflect.Ptr:
|
||||
if !defaultPointersValue.IsNil() {
|
||||
if len(key) != 0 {
|
||||
// turn ptr fields to nil
|
||||
defaultPointersNilValue, err := setPointersNil(defaultPointersValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defaultValmap[name] = defaultPointersNilValue
|
||||
}
|
||||
|
||||
if !defaultValue.IsNil() {
|
||||
if err := getDefaultValue(defaultValue.Elem(), defaultPointersValue.Elem(), defaultValmap, name); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := getDefaultValue(defaultPointersValue.Elem(), defaultPointersValue.Elem(), defaultValmap, name); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
instValue := reflect.New(defaultPointersValue.Type().Elem())
|
||||
if len(key) != 0 {
|
||||
defaultValmap[name] = instValue
|
||||
}
|
||||
|
||||
if !defaultValue.IsNil() {
|
||||
if err := getDefaultValue(defaultValue.Elem(), instValue.Elem(), defaultValmap, name); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := getDefaultValue(instValue.Elem(), instValue.Elem(), defaultValmap, name); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// objValue a reflect.Value of a not-nil pointer on a struct
|
||||
func setPointersNil(objValue reflect.Value) (reflect.Value, error) {
|
||||
if objValue.Kind() != reflect.Ptr {
|
||||
return objValue, fmt.Errorf("parameters objValue must be a not-nil pointer on a struct, not a %s", objValue.Kind())
|
||||
} else if objValue.IsNil() {
|
||||
return objValue, errors.New("parameters objValue must be a not-nil pointer")
|
||||
} else if objValue.Elem().Kind() != reflect.Struct {
|
||||
// fmt.Printf("Parameters objValue must be a not-nil pointer on a struct, not a pointer on a %s\n", objValue.Elem().Kind().String())
|
||||
return objValue, nil
|
||||
}
|
||||
|
||||
// Clone
|
||||
starObjValue := objValue.Elem()
|
||||
nilPointersObjVal := reflect.New(starObjValue.Type())
|
||||
starNilPointersObjVal := nilPointersObjVal.Elem()
|
||||
starNilPointersObjVal.Set(starObjValue)
|
||||
|
||||
for i := 0; i < nilPointersObjVal.Elem().NumField(); i++ {
|
||||
if field := nilPointersObjVal.Elem().Field(i); field.Kind() == reflect.Ptr && field.CanSet() {
|
||||
field.Set(reflect.Zero(field.Type()))
|
||||
}
|
||||
}
|
||||
return nilPointersObjVal, nil
|
||||
}
|
||||
|
||||
// FillStructRecursive initialize a value of any tagged Struct given by reference
|
||||
func fillStructRecursive(objValue reflect.Value, defaultPointerValMap map[string]reflect.Value, valMap map[string]parse.Parser, key string) error {
|
||||
name := key
|
||||
switch objValue.Kind() {
|
||||
case reflect.Struct:
|
||||
|
||||
for i := 0; i < objValue.Type().NumField(); i++ {
|
||||
if objValue.Type().Field(i).Anonymous {
|
||||
if err := fillStructRecursive(objValue.Field(i), defaultPointerValMap, valMap, name); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if len(objValue.Type().Field(i).Tag.Get("description")) > 0 {
|
||||
fieldName := objValue.Type().Field(i).Name
|
||||
if tag := objValue.Type().Field(i).Tag.Get("long"); len(tag) > 0 {
|
||||
fieldName = tag
|
||||
}
|
||||
|
||||
if len(key) == 0 {
|
||||
name = strings.ToLower(fieldName)
|
||||
} else {
|
||||
name = key + "." + strings.ToLower(fieldName)
|
||||
}
|
||||
|
||||
if objValue.Field(i).Kind() != reflect.Ptr {
|
||||
if val, ok := valMap[name]; ok {
|
||||
if err := setFields(objValue.Field(i), val); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := fillStructRecursive(objValue.Field(i), defaultPointerValMap, valMap, name); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case reflect.Ptr:
|
||||
if len(key) == 0 && !objValue.IsNil() {
|
||||
return fillStructRecursive(objValue.Elem(), defaultPointerValMap, valMap, name)
|
||||
}
|
||||
|
||||
contains := false
|
||||
for flg := range valMap {
|
||||
// TODO replace by regexp
|
||||
if strings.HasPrefix(flg, name+".") {
|
||||
contains = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
needDefault := false
|
||||
if _, ok := valMap[name]; ok {
|
||||
needDefault = valMap[name].Get().(bool)
|
||||
}
|
||||
if contains && objValue.IsNil() {
|
||||
needDefault = true
|
||||
}
|
||||
|
||||
if needDefault {
|
||||
if defVal, ok := defaultPointerValMap[name]; ok {
|
||||
// set default pointer value
|
||||
objValue.Set(defVal)
|
||||
} else {
|
||||
return fmt.Errorf("flag %s default value not provided", name)
|
||||
}
|
||||
}
|
||||
|
||||
if !objValue.IsNil() && contains {
|
||||
if objValue.Type().Elem().Kind() == reflect.Struct {
|
||||
if err := fillStructRecursive(objValue.Elem(), defaultPointerValMap, valMap, name); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetFields sets value to fieldValue using tag as key in valMap
|
||||
func setFields(fieldValue reflect.Value, val parse.Parser) error {
|
||||
if fieldValue.CanSet() {
|
||||
fieldValue.Set(reflect.ValueOf(val).Elem().Convert(fieldValue.Type()))
|
||||
} else {
|
||||
return fmt.Errorf("%s is not settable", fieldValue.Type().String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PrintHelp generates and prints command line help
|
||||
func PrintHelp(flagMap map[string]reflect.StructField, defaultValmap map[string]reflect.Value, parsers map[reflect.Type]parse.Parser) error {
|
||||
return PrintHelpWithCommand(flagMap, defaultValmap, parsers, nil, nil)
|
||||
}
|
||||
|
||||
// PrintError takes a not nil error and prints command line help
|
||||
func PrintError(err error, flagMap map[string]reflect.StructField, defaultValmap map[string]reflect.Value, parsers map[reflect.Type]parse.Parser) error {
|
||||
if err != flag.ErrHelp {
|
||||
fmt.Printf("Error: %s\n", err)
|
||||
}
|
||||
if !strings.Contains(err.Error(), ":No parser for type") {
|
||||
PrintHelp(flagMap, defaultValmap, parsers)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// LoadWithParsers initializes config : struct fields given by reference, with args : arguments.
|
||||
// Some custom parsers may be given.
|
||||
func LoadWithParsers(config interface{}, defaultValue interface{}, args []string, customParsers map[reflect.Type]parse.Parser) error {
|
||||
cmd := &Command{
|
||||
Config: config,
|
||||
DefaultPointersConfig: defaultValue,
|
||||
}
|
||||
_, cmd.Name = path.Split(os.Args[0])
|
||||
return LoadWithCommand(cmd, args, customParsers, nil)
|
||||
}
|
||||
|
||||
// Load initializes config : struct fields given by reference, with args : arguments.
|
||||
// Some custom parsers may be given.
|
||||
func Load(config interface{}, defaultValue interface{}, args []string) error {
|
||||
return LoadWithParsers(config, defaultValue, args, nil)
|
||||
}
|
||||
|
||||
// Command structure contains program/command information (command name and description)
|
||||
// Config must be a pointer on the configuration struct to parse (it contains default values of field)
|
||||
// DefaultPointersConfig contains default pointers values: those values are set on pointers fields if their flags are called
|
||||
// It must be the same type(struct) as Config
|
||||
// Run is the func which launch the program using initialized configuration structure
|
||||
type Command struct {
|
||||
Name string
|
||||
Description string
|
||||
Config interface{}
|
||||
DefaultPointersConfig interface{} // TODO: case DefaultPointersConfig is nil
|
||||
Run func() error
|
||||
Metadata map[string]string
|
||||
HideHelp bool
|
||||
}
|
||||
|
||||
// LoadWithCommand initializes config : struct fields given by reference, with args : arguments.
|
||||
// Some custom parsers and some subCommand may be given.
|
||||
func LoadWithCommand(cmd *Command, cmdArgs []string, customParsers map[reflect.Type]parse.Parser, subCommand []*Command) error {
|
||||
parsers, err := parse.LoadParsers(customParsers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tagsMap := make(map[string]reflect.StructField)
|
||||
if err := getTypesRecursive(reflect.ValueOf(cmd.Config), tagsMap, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
defaultValMap := make(map[string]reflect.Value)
|
||||
if err := getDefaultValue(reflect.ValueOf(cmd.Config), reflect.ValueOf(cmd.DefaultPointersConfig), defaultValMap, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
valMap, errParseArgs := parseArgs(cmdArgs, tagsMap, parsers)
|
||||
if errParseArgs != nil && errParseArgs != ErrParserNotFound {
|
||||
return PrintErrorWithCommand(errParseArgs, tagsMap, defaultValMap, parsers, cmd, subCommand)
|
||||
}
|
||||
|
||||
if err := fillStructRecursive(reflect.ValueOf(cmd.Config), defaultValMap, valMap, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if errParseArgs == ErrParserNotFound {
|
||||
return errParseArgs
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PrintHelpWithCommand generates and prints command line help for a Command
|
||||
func PrintHelpWithCommand(flagMap map[string]reflect.StructField, defaultValMap map[string]reflect.Value, parsers map[reflect.Type]parse.Parser, cmd *Command, subCmd []*Command) error {
|
||||
// Hide command from help
|
||||
if cmd != nil && cmd.HideHelp {
|
||||
return fmt.Errorf("command %s not found", cmd.Name)
|
||||
}
|
||||
|
||||
// Define a templates
|
||||
// Using POSXE STD : http://pubs.opengroup.org/onlinepubs/9699919799/
|
||||
const helper = `{{if .ProgDescription}}{{.ProgDescription}}
|
||||
|
||||
{{end}}Usage: {{.ProgName}} [flags] <command> [<arguments>]
|
||||
|
||||
Use "{{.ProgName}} <command> --help" for help on any command.
|
||||
{{if .SubCommands}}
|
||||
Commands:{{range $subCmdName, $subCmdDesc := .SubCommands}}
|
||||
{{printf "\t%-50s %s" $subCmdName $subCmdDesc}}{{end}}
|
||||
{{end}}
|
||||
Flag's usage: {{.ProgName}} [--flag=flag_argument] [-f[flag_argument]] ... set flag_argument to flag(s)
|
||||
or: {{.ProgName}} [--flag[=true|false| ]] [-f[true|false| ]] ... set true/false to boolean flag(s)
|
||||
|
||||
Flags:
|
||||
`
|
||||
// Use a struct to give data to template
|
||||
type TempStruct struct {
|
||||
ProgName string
|
||||
ProgDescription string
|
||||
SubCommands map[string]string
|
||||
}
|
||||
tempStruct := TempStruct{}
|
||||
if cmd != nil {
|
||||
tempStruct.ProgName = cmd.Name
|
||||
tempStruct.ProgDescription = cmd.Description
|
||||
tempStruct.SubCommands = map[string]string{}
|
||||
if len(subCmd) > 1 && cmd == subCmd[0] {
|
||||
for _, c := range subCmd[1:] {
|
||||
if !c.HideHelp {
|
||||
tempStruct.SubCommands[c.Name] = c.Description
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_, tempStruct.ProgName = path.Split(os.Args[0])
|
||||
}
|
||||
|
||||
// Run Template
|
||||
tmplHelper, err := template.New("helper").Parse(helper)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = tmplHelper.Execute(os.Stdout, tempStruct)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return printFlagsDescriptionsDefaultValues(flagMap, defaultValMap, parsers, os.Stdout)
|
||||
}
|
||||
|
||||
func printFlagsDescriptionsDefaultValues(flagMap map[string]reflect.StructField, defaultValMap map[string]reflect.Value, parsers map[reflect.Type]parse.Parser, output io.Writer) error {
|
||||
// Sort alphabetically & Delete unparsable flags in a slice
|
||||
var flags []string
|
||||
for flg, field := range flagMap {
|
||||
if _, ok := parsers[field.Type]; ok {
|
||||
flags = append(flags, flg)
|
||||
}
|
||||
}
|
||||
sort.Strings(flags)
|
||||
|
||||
// Process data
|
||||
var descriptions []string
|
||||
var defaultValues []string
|
||||
var flagsWithDash []string
|
||||
var shortFlagsWithDash []string
|
||||
for _, flg := range flags {
|
||||
field := flagMap[flg]
|
||||
if short := field.Tag.Get("short"); len(short) == 1 {
|
||||
shortFlagsWithDash = append(shortFlagsWithDash, "-"+short+",")
|
||||
} else {
|
||||
shortFlagsWithDash = append(shortFlagsWithDash, "")
|
||||
}
|
||||
flagsWithDash = append(flagsWithDash, "--"+flg)
|
||||
|
||||
// flag on pointer ?
|
||||
if defVal, ok := defaultValMap[flg]; ok {
|
||||
if defVal.Kind() != reflect.Ptr {
|
||||
// Set defaultValue on parsers
|
||||
parsers[field.Type].SetValue(defaultValMap[flg].Interface())
|
||||
}
|
||||
|
||||
if defVal := parsers[field.Type].String(); len(defVal) > 0 {
|
||||
defaultValues = append(defaultValues, fmt.Sprintf("(default \"%s\")", defVal))
|
||||
} else {
|
||||
defaultValues = append(defaultValues, "")
|
||||
}
|
||||
}
|
||||
|
||||
splittedDescriptions := split(field.Tag.Get("description"), 80)
|
||||
for i, description := range splittedDescriptions {
|
||||
descriptions = append(descriptions, description)
|
||||
if i != 0 {
|
||||
defaultValues = append(defaultValues, "")
|
||||
flagsWithDash = append(flagsWithDash, "")
|
||||
shortFlagsWithDash = append(shortFlagsWithDash, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add help flag
|
||||
shortFlagsWithDash = append(shortFlagsWithDash, "-h,")
|
||||
flagsWithDash = append(flagsWithDash, "--help")
|
||||
descriptions = append(descriptions, "Print Help (this message) and exit")
|
||||
defaultValues = append(defaultValues, "")
|
||||
|
||||
return displayTab(output, shortFlagsWithDash, flagsWithDash, descriptions, defaultValues)
|
||||
}
|
||||
|
||||
func split(str string, width int) []string {
|
||||
if len(str) > width {
|
||||
index := strings.LastIndex(str[:width], " ")
|
||||
if index == -1 {
|
||||
index = width
|
||||
}
|
||||
|
||||
return append([]string{strings.TrimSpace(str[:index])}, split(strings.TrimSpace(str[index:]), width)...)
|
||||
}
|
||||
return []string{str}
|
||||
}
|
||||
|
||||
func displayTab(output io.Writer, columns ...[]string) error {
|
||||
w := new(tabwriter.Writer)
|
||||
w.Init(output, 0, 4, 1, ' ', 0)
|
||||
|
||||
nbRow := len(columns[0])
|
||||
nbCol := len(columns)
|
||||
|
||||
for i := 0; i < nbRow; i++ {
|
||||
row := ""
|
||||
for j, col := range columns {
|
||||
row += col[i]
|
||||
if j != nbCol-1 {
|
||||
row += "\t"
|
||||
}
|
||||
}
|
||||
fmt.Fprintln(w, row)
|
||||
}
|
||||
|
||||
return w.Flush()
|
||||
}
|
||||
|
||||
// PrintErrorWithCommand takes a not nil error and prints command line help
|
||||
func PrintErrorWithCommand(err error, flagMap map[string]reflect.StructField, defaultValMap map[string]reflect.Value, parsers map[reflect.Type]parse.Parser, cmd *Command, subCmd []*Command) error {
|
||||
if err != flag.ErrHelp {
|
||||
fmt.Printf("Error here : %s\n", err)
|
||||
}
|
||||
|
||||
if errHelp := PrintHelpWithCommand(flagMap, defaultValMap, parsers, cmd, subCmd); errHelp != nil {
|
||||
return errHelp
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Flaeg struct contains commands (at least the root one)
|
||||
// and row arguments (command and/or flags)
|
||||
// a map of custom parsers could be use
|
||||
type Flaeg struct {
|
||||
calledCommand *Command
|
||||
commands []*Command // rootCommand is th fist one in this slice
|
||||
args []string
|
||||
commandArgs []string
|
||||
customParsers map[reflect.Type]parse.Parser
|
||||
}
|
||||
|
||||
// New creates and initialize a pointer on Flaeg
|
||||
func New(rootCommand *Command, args []string) *Flaeg {
|
||||
var f Flaeg
|
||||
f.commands = []*Command{rootCommand}
|
||||
f.args = args
|
||||
f.customParsers = map[reflect.Type]parse.Parser{}
|
||||
return &f
|
||||
}
|
||||
|
||||
// AddCommand adds sub-command to the root command
|
||||
func (f *Flaeg) AddCommand(command *Command) {
|
||||
f.commands = append(f.commands, command)
|
||||
}
|
||||
|
||||
// AddParser adds custom parser for a type to the map of custom parsers
|
||||
func (f *Flaeg) AddParser(typ reflect.Type, parser parse.Parser) {
|
||||
f.customParsers[typ] = parser
|
||||
}
|
||||
|
||||
// Run calls the command with flags given as arguments
|
||||
func (f *Flaeg) Run() error {
|
||||
if f.calledCommand == nil {
|
||||
if _, _, err := f.findCommandWithCommandArgs(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := f.Parse(f.calledCommand); err != nil {
|
||||
return err
|
||||
}
|
||||
return f.calledCommand.Run()
|
||||
}
|
||||
|
||||
// Parse calls Flaeg Load Function end returns the parsed command structure (by reference)
|
||||
// It returns nil and a not nil error if it fails
|
||||
func (f *Flaeg) Parse(cmd *Command) (*Command, error) {
|
||||
if f.calledCommand == nil {
|
||||
f.commandArgs = f.args
|
||||
}
|
||||
|
||||
if err := LoadWithCommand(cmd, f.commandArgs, f.customParsers, f.commands); err != nil {
|
||||
return cmd, err
|
||||
}
|
||||
return cmd, nil
|
||||
}
|
||||
|
||||
// splitArgs takes args (type []string) and return command ("" if rootCommand) and command's args
|
||||
func splitArgs(args []string) (string, []string) {
|
||||
if len(args) >= 1 && len(args[0]) >= 1 && string(args[0][0]) != "-" {
|
||||
if len(args) == 1 {
|
||||
return strings.ToLower(args[0]), []string{}
|
||||
}
|
||||
return strings.ToLower(args[0]), args[1:]
|
||||
}
|
||||
return "", args
|
||||
}
|
||||
|
||||
// findCommandWithCommandArgs returns the called command (by reference) and command's args
|
||||
// the error returned is not nil if it fails
|
||||
func (f *Flaeg) findCommandWithCommandArgs() (*Command, []string, error) {
|
||||
var commandName string
|
||||
commandName, f.commandArgs = splitArgs(f.args)
|
||||
if len(commandName) > 0 {
|
||||
for _, command := range f.commands {
|
||||
if commandName == command.Name {
|
||||
f.calledCommand = command
|
||||
return f.calledCommand, f.commandArgs, nil
|
||||
}
|
||||
}
|
||||
return nil, []string{}, fmt.Errorf("command %s not found", commandName)
|
||||
}
|
||||
|
||||
f.calledCommand = f.commands[0]
|
||||
return f.calledCommand, f.commandArgs, nil
|
||||
}
|
||||
|
||||
// GetCommand splits args and returns the called command (by reference)
|
||||
// It returns nil and a not nil error if it fails
|
||||
func (f *Flaeg) GetCommand() (*Command, error) {
|
||||
if f.calledCommand == nil {
|
||||
_, _, err := f.findCommandWithCommandArgs()
|
||||
return f.calledCommand, err
|
||||
}
|
||||
return f.calledCommand, nil
|
||||
}
|
||||
|
||||
// isExported return true is the field (from fieldName) is exported,
|
||||
// else false
|
||||
func isExported(fieldName string) bool {
|
||||
if len(fieldName) < 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
if string(fieldName[0]) == strings.ToUpper(string(fieldName[0])) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func argToLower(inArg string) string {
|
||||
if len(inArg) < 2 {
|
||||
return strings.ToLower(inArg)
|
||||
}
|
||||
|
||||
var outArg string
|
||||
dashIndex := strings.Index(inArg, "--")
|
||||
if dashIndex == -1 {
|
||||
if dashIndex = strings.Index(inArg, "-"); dashIndex == -1 {
|
||||
return inArg
|
||||
}
|
||||
// -fValue
|
||||
outArg = strings.ToLower(inArg[dashIndex:dashIndex+2]) + inArg[dashIndex+2:]
|
||||
return outArg
|
||||
}
|
||||
|
||||
// --flag
|
||||
if equalIndex := strings.Index(inArg, "="); equalIndex != -1 {
|
||||
// --flag=value
|
||||
outArg = strings.ToLower(inArg[dashIndex:equalIndex]) + inArg[equalIndex:]
|
||||
} else {
|
||||
// --boolflag
|
||||
outArg = strings.ToLower(inArg[dashIndex:])
|
||||
}
|
||||
|
||||
return outArg
|
||||
}
|
||||
|
||||
func argsToLower(inArgs []string) []string {
|
||||
outArgs := make([]string, len(inArgs))
|
||||
for i, inArg := range inArgs {
|
||||
outArgs[i] = argToLower(inArg)
|
||||
}
|
||||
return outArgs
|
||||
}
|
7
vendor/github.com/containous/flaeg/flaeg_types.go
generated
vendored
7
vendor/github.com/containous/flaeg/flaeg_types.go
generated
vendored
|
@ -1,7 +0,0 @@
|
|||
package flaeg
|
||||
|
||||
import "github.com/containous/flaeg/parse"
|
||||
|
||||
// Duration is deprecated use parse.Duration instead
|
||||
// Deprecated
|
||||
type Duration = parse.Duration
|
313
vendor/github.com/containous/flaeg/parse/parse.go
generated
vendored
313
vendor/github.com/containous/flaeg/parse/parse.go
generated
vendored
|
@ -1,313 +0,0 @@
|
|||
package parse
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Parser is an interface that allows the contents of a flag.Getter to be set.
|
||||
type Parser interface {
|
||||
flag.Getter
|
||||
SetValue(interface{})
|
||||
}
|
||||
|
||||
// BoolValue bool Value type
|
||||
type BoolValue bool
|
||||
|
||||
// Set sets bool value from the given string value.
|
||||
func (b *BoolValue) Set(s string) error {
|
||||
v, err := strconv.ParseBool(s)
|
||||
*b = BoolValue(v)
|
||||
return err
|
||||
}
|
||||
|
||||
// Get returns the bool value.
|
||||
func (b *BoolValue) Get() interface{} { return bool(*b) }
|
||||
|
||||
func (b *BoolValue) String() string { return fmt.Sprintf("%v", *b) }
|
||||
|
||||
// IsBoolFlag return true
|
||||
func (b *BoolValue) IsBoolFlag() bool { return true }
|
||||
|
||||
// SetValue sets the duration from the given bool-asserted value.
|
||||
func (b *BoolValue) SetValue(val interface{}) {
|
||||
*b = BoolValue(val.(bool))
|
||||
}
|
||||
|
||||
// BoolFlag optional interface to indicate boolean flags that can be
|
||||
// supplied without "=value" text
|
||||
type BoolFlag interface {
|
||||
flag.Value
|
||||
IsBoolFlag() bool
|
||||
}
|
||||
|
||||
// IntValue int Value
|
||||
type IntValue int
|
||||
|
||||
// Set sets int value from the given string value.
|
||||
func (i *IntValue) Set(s string) error {
|
||||
v, err := strconv.ParseInt(s, 0, 64)
|
||||
*i = IntValue(v)
|
||||
return err
|
||||
}
|
||||
|
||||
// Get returns the int value.
|
||||
func (i *IntValue) Get() interface{} { return int(*i) }
|
||||
|
||||
func (i *IntValue) String() string { return fmt.Sprintf("%v", *i) }
|
||||
|
||||
// SetValue sets the IntValue from the given int-asserted value.
|
||||
func (i *IntValue) SetValue(val interface{}) {
|
||||
*i = IntValue(val.(int))
|
||||
}
|
||||
|
||||
// Int64Value int64 Value
|
||||
type Int64Value int64
|
||||
|
||||
// Set sets int64 value from the given string value.
|
||||
func (i *Int64Value) Set(s string) error {
|
||||
v, err := strconv.ParseInt(s, 0, 64)
|
||||
*i = Int64Value(v)
|
||||
return err
|
||||
}
|
||||
|
||||
// Get returns the int64 value.
|
||||
func (i *Int64Value) Get() interface{} { return int64(*i) }
|
||||
|
||||
func (i *Int64Value) String() string { return fmt.Sprintf("%v", *i) }
|
||||
|
||||
// SetValue sets the Int64Value from the given int64-asserted value.
|
||||
func (i *Int64Value) SetValue(val interface{}) {
|
||||
*i = Int64Value(val.(int64))
|
||||
}
|
||||
|
||||
// UintValue uint Value
|
||||
type UintValue uint
|
||||
|
||||
// Set sets uint value from the given string value.
|
||||
func (i *UintValue) Set(s string) error {
|
||||
v, err := strconv.ParseUint(s, 0, 64)
|
||||
*i = UintValue(v)
|
||||
return err
|
||||
}
|
||||
|
||||
// Get returns the uint value.
|
||||
func (i *UintValue) Get() interface{} { return uint(*i) }
|
||||
|
||||
func (i *UintValue) String() string { return fmt.Sprintf("%v", *i) }
|
||||
|
||||
// SetValue sets the UintValue from the given uint-asserted value.
|
||||
func (i *UintValue) SetValue(val interface{}) {
|
||||
*i = UintValue(val.(uint))
|
||||
}
|
||||
|
||||
// Uint64Value uint64 Value
|
||||
type Uint64Value uint64
|
||||
|
||||
// Set sets uint64 value from the given string value.
|
||||
func (i *Uint64Value) Set(s string) error {
|
||||
v, err := strconv.ParseUint(s, 0, 64)
|
||||
*i = Uint64Value(v)
|
||||
return err
|
||||
}
|
||||
|
||||
// Get returns the uint64 value.
|
||||
func (i *Uint64Value) Get() interface{} { return uint64(*i) }
|
||||
|
||||
func (i *Uint64Value) String() string { return fmt.Sprintf("%v", *i) }
|
||||
|
||||
// SetValue sets the Uint64Value from the given uint64-asserted value.
|
||||
func (i *Uint64Value) SetValue(val interface{}) {
|
||||
*i = Uint64Value(val.(uint64))
|
||||
}
|
||||
|
||||
// StringValue string Value
|
||||
type StringValue string
|
||||
|
||||
// Set sets string value from the given string value.
|
||||
func (s *StringValue) Set(val string) error {
|
||||
*s = StringValue(val)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get returns the string value.
|
||||
func (s *StringValue) Get() interface{} { return string(*s) }
|
||||
|
||||
func (s *StringValue) String() string { return string(*s) }
|
||||
|
||||
// SetValue sets the StringValue from the given string-asserted value.
|
||||
func (s *StringValue) SetValue(val interface{}) {
|
||||
*s = StringValue(val.(string))
|
||||
}
|
||||
|
||||
// Float64Value float64 Value
|
||||
type Float64Value float64
|
||||
|
||||
// Set sets float64 value from the given string value.
|
||||
func (f *Float64Value) Set(s string) error {
|
||||
v, err := strconv.ParseFloat(s, 64)
|
||||
*f = Float64Value(v)
|
||||
return err
|
||||
}
|
||||
|
||||
// Get returns the float64 value.
|
||||
func (f *Float64Value) Get() interface{} { return float64(*f) }
|
||||
|
||||
func (f *Float64Value) String() string { return fmt.Sprintf("%v", *f) }
|
||||
|
||||
// SetValue sets the Float64Value from the given float64-asserted value.
|
||||
func (f *Float64Value) SetValue(val interface{}) {
|
||||
*f = Float64Value(val.(float64))
|
||||
}
|
||||
|
||||
// Duration is a custom type suitable for parsing duration values.
|
||||
// It supports `time.ParseDuration`-compatible values and suffix-less digits; in
|
||||
// the latter case, seconds are assumed.
|
||||
type Duration time.Duration
|
||||
|
||||
// Set sets the duration from the given string value.
|
||||
func (d *Duration) Set(s string) error {
|
||||
if v, err := strconv.ParseInt(s, 10, 64); err == nil {
|
||||
*d = Duration(time.Duration(v) * time.Second)
|
||||
return nil
|
||||
}
|
||||
|
||||
v, err := time.ParseDuration(s)
|
||||
*d = Duration(v)
|
||||
return err
|
||||
}
|
||||
|
||||
// Get returns the duration value.
|
||||
func (d *Duration) Get() interface{} { return time.Duration(*d) }
|
||||
|
||||
// String returns a string representation of the duration value.
|
||||
func (d *Duration) String() string { return (*time.Duration)(d).String() }
|
||||
|
||||
// SetValue sets the duration from the given Duration-asserted value.
|
||||
func (d *Duration) SetValue(val interface{}) {
|
||||
*d = val.(Duration)
|
||||
}
|
||||
|
||||
// MarshalText serialize the given duration value into a text.
|
||||
func (d *Duration) MarshalText() ([]byte, error) {
|
||||
return []byte(d.String()), nil
|
||||
}
|
||||
|
||||
// UnmarshalText deserializes the given text into a duration value.
|
||||
// It is meant to support TOML decoding of durations.
|
||||
func (d *Duration) UnmarshalText(text []byte) error {
|
||||
return d.Set(string(text))
|
||||
}
|
||||
|
||||
// MarshalJSON serializes the given duration value.
|
||||
func (d *Duration) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(time.Duration(*d))
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes the given text into a duration value.
|
||||
func (d *Duration) UnmarshalJSON(text []byte) error {
|
||||
if v, err := strconv.ParseInt(string(text), 10, 64); err == nil {
|
||||
*d = Duration(time.Duration(v))
|
||||
return nil
|
||||
}
|
||||
|
||||
// We use json unmarshal on value because we have the quoted version
|
||||
var value string
|
||||
err := json.Unmarshal(text, &value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v, err := time.ParseDuration(value)
|
||||
*d = Duration(v)
|
||||
return err
|
||||
}
|
||||
|
||||
// TimeValue time.Time Value
|
||||
type TimeValue time.Time
|
||||
|
||||
// Set sets time.Time value from the given string value.
|
||||
func (t *TimeValue) Set(s string) error {
|
||||
v, err := time.Parse(time.RFC3339, s)
|
||||
*t = TimeValue(v)
|
||||
return err
|
||||
}
|
||||
|
||||
// Get returns the time.Time value.
|
||||
func (t *TimeValue) Get() interface{} { return time.Time(*t) }
|
||||
|
||||
func (t *TimeValue) String() string { return (*time.Time)(t).String() }
|
||||
|
||||
// SetValue sets the TimeValue from the given time.Time-asserted value.
|
||||
func (t *TimeValue) SetValue(val interface{}) {
|
||||
*t = TimeValue(val.(time.Time))
|
||||
}
|
||||
|
||||
// SliceStrings parse slice of strings
|
||||
type SliceStrings []string
|
||||
|
||||
// Set adds strings elem into the the parser.
|
||||
// It splits str on , and ;
|
||||
func (s *SliceStrings) Set(str string) error {
|
||||
fargs := func(c rune) bool {
|
||||
return c == ',' || c == ';'
|
||||
}
|
||||
// get function
|
||||
slice := strings.FieldsFunc(str, fargs)
|
||||
*s = append(*s, slice...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get []string
|
||||
func (s *SliceStrings) Get() interface{} { return []string(*s) }
|
||||
|
||||
// String return slice in a string
|
||||
func (s *SliceStrings) String() string { return fmt.Sprintf("%v", *s) }
|
||||
|
||||
// SetValue sets []string into the parser
|
||||
func (s *SliceStrings) SetValue(val interface{}) {
|
||||
*s = SliceStrings(val.([]string))
|
||||
}
|
||||
|
||||
// LoadParsers loads default parsers and custom parsers given as parameter.
|
||||
// Return a map [reflect.Type]parsers
|
||||
// bool, int, int64, uint, uint64, float64,
|
||||
func LoadParsers(customParsers map[reflect.Type]Parser) (map[reflect.Type]Parser, error) {
|
||||
parsers := map[reflect.Type]Parser{}
|
||||
|
||||
var boolParser BoolValue
|
||||
parsers[reflect.TypeOf(true)] = &boolParser
|
||||
|
||||
var intParser IntValue
|
||||
parsers[reflect.TypeOf(1)] = &intParser
|
||||
|
||||
var int64Parser Int64Value
|
||||
parsers[reflect.TypeOf(int64(1))] = &int64Parser
|
||||
|
||||
var uintParser UintValue
|
||||
parsers[reflect.TypeOf(uint(1))] = &uintParser
|
||||
|
||||
var uint64Parser Uint64Value
|
||||
parsers[reflect.TypeOf(uint64(1))] = &uint64Parser
|
||||
|
||||
var stringParser StringValue
|
||||
parsers[reflect.TypeOf("")] = &stringParser
|
||||
|
||||
var float64Parser Float64Value
|
||||
parsers[reflect.TypeOf(float64(1.5))] = &float64Parser
|
||||
|
||||
var durationParser Duration
|
||||
parsers[reflect.TypeOf(Duration(time.Second))] = &durationParser
|
||||
|
||||
var timeParser TimeValue
|
||||
parsers[reflect.TypeOf(time.Now())] = &timeParser
|
||||
|
||||
for rType, parser := range customParsers {
|
||||
parsers[rType] = parser
|
||||
}
|
||||
return parsers, nil
|
||||
}
|
21
vendor/github.com/containous/staert/LICENSE.md
generated
vendored
21
vendor/github.com/containous/staert/LICENSE.md
generated
vendored
|
@ -1,21 +0,0 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Containous SAS, Emile Vauge, emile@vauge.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
395
vendor/github.com/containous/staert/kv.go
generated
vendored
395
vendor/github.com/containous/staert/kv.go
generated
vendored
|
@ -1,395 +0,0 @@
|
|||
package staert
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"encoding"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/abronan/valkeyrie"
|
||||
"github.com/abronan/valkeyrie/store"
|
||||
"github.com/containous/flaeg"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
// KvSource implements Source
|
||||
// It handles all mapstructure features(Squashed Embedded Sub-Structures, Maps, Pointers)
|
||||
// It supports Slices (and maybe Arrays). They must be sorted in the KvStore like this :
|
||||
// Key : ".../[sliceIndex]" -> Value
|
||||
type KvSource struct {
|
||||
store.Store
|
||||
Prefix string // like this "prefix" (without the /)
|
||||
}
|
||||
|
||||
// NewKvSource creates a new KvSource
|
||||
func NewKvSource(backend store.Backend, addrs []string, options *store.Config, prefix string) (*KvSource, error) {
|
||||
kvStore, err := valkeyrie.NewStore(backend, addrs, options)
|
||||
return &KvSource{Store: kvStore, Prefix: prefix}, err
|
||||
}
|
||||
|
||||
// Parse uses valkeyrie and mapstructure to fill the structure
|
||||
func (kv *KvSource) Parse(cmd *flaeg.Command) (*flaeg.Command, error) {
|
||||
err := kv.LoadConfig(cmd.Config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cmd, nil
|
||||
}
|
||||
|
||||
// LoadConfig loads data from the KV Store into the config structure (given by reference)
|
||||
func (kv *KvSource) LoadConfig(config interface{}) error {
|
||||
pairs, err := kv.ListValuedPairWithPrefix(kv.Prefix)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mapStruct, err := generateMapstructure(convertPairs(pairs), kv.Prefix)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
configDecoder := &mapstructure.DecoderConfig{
|
||||
Metadata: nil,
|
||||
Result: config,
|
||||
WeaklyTypedInput: true,
|
||||
DecodeHook: decodeHook,
|
||||
}
|
||||
decoder, err := mapstructure.NewDecoder(configDecoder)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := decoder.Decode(mapStruct); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func generateMapstructure(pairs []*store.KVPair, prefix string) (map[string]interface{}, error) {
|
||||
raw := make(map[string]interface{})
|
||||
for _, p := range pairs {
|
||||
// Trim the prefix off our key first
|
||||
key := strings.TrimPrefix(strings.Trim(p.Key, "/"), strings.Trim(prefix, "/")+"/")
|
||||
var err error
|
||||
raw, err = processKV(key, p.Value, raw)
|
||||
if err != nil {
|
||||
return raw, err
|
||||
}
|
||||
}
|
||||
return raw, nil
|
||||
}
|
||||
|
||||
func processKV(key string, v []byte, raw map[string]interface{}) (map[string]interface{}, error) {
|
||||
// Determine which map we're writing the value to.
|
||||
// We split by '/' to determine any sub-maps that need to be created.
|
||||
m := raw
|
||||
children := strings.Split(key, "/")
|
||||
if len(children) > 0 {
|
||||
key = children[len(children)-1]
|
||||
children = children[:len(children)-1]
|
||||
for _, child := range children {
|
||||
if m[child] == nil {
|
||||
m[child] = make(map[string]interface{})
|
||||
}
|
||||
subm, ok := m[child].(map[string]interface{})
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("child is both a data item and dir: %s", child)
|
||||
}
|
||||
m = subm
|
||||
}
|
||||
}
|
||||
m[key] = string(v)
|
||||
return raw, nil
|
||||
}
|
||||
|
||||
func decodeHook(fromType reflect.Type, toType reflect.Type, data interface{}) (interface{}, error) {
|
||||
// TODO : Array support
|
||||
|
||||
// custom unmarshaler
|
||||
textUnmarshalerType := reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
|
||||
if toType.Implements(textUnmarshalerType) {
|
||||
object := reflect.New(toType.Elem()).Interface()
|
||||
err := object.(encoding.TextUnmarshaler).UnmarshalText([]byte(data.(string)))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error unmarshaling %v: %v", data, err)
|
||||
}
|
||||
return object, nil
|
||||
}
|
||||
switch toType.Kind() {
|
||||
case reflect.Ptr:
|
||||
if fromType.Kind() == reflect.String {
|
||||
if data == "" {
|
||||
// default value Pointer
|
||||
return make(map[string]interface{}), nil
|
||||
}
|
||||
}
|
||||
case reflect.Slice:
|
||||
if fromType.Kind() == reflect.Map {
|
||||
// Type assertion
|
||||
dataMap, ok := data.(map[string]interface{})
|
||||
if !ok {
|
||||
return data, fmt.Errorf("input data is not a map : %#v", data)
|
||||
}
|
||||
// Sorting map
|
||||
indexes := make([]int, len(dataMap))
|
||||
i := 0
|
||||
for k := range dataMap {
|
||||
ind, err := strconv.Atoi(k)
|
||||
if err != nil {
|
||||
return dataMap, err
|
||||
}
|
||||
indexes[i] = ind
|
||||
i++
|
||||
}
|
||||
sort.Ints(indexes)
|
||||
// Building slice
|
||||
dataOutput := make([]interface{}, i)
|
||||
i = 0
|
||||
for _, k := range indexes {
|
||||
dataOutput[i] = dataMap[strconv.Itoa(k)]
|
||||
i++
|
||||
}
|
||||
|
||||
return dataOutput, nil
|
||||
} else if fromType.Kind() == reflect.String {
|
||||
return readCompressedData(data.(string), gzipReader, base64Reader)
|
||||
}
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func readCompressedData(data string, fs ...func(io.Reader) (io.Reader, error)) ([]byte, error) {
|
||||
var err error
|
||||
for _, f := range fs {
|
||||
var reader io.Reader
|
||||
reader, err = f(bytes.NewBufferString(data))
|
||||
if err == nil {
|
||||
return ioutil.ReadAll(reader)
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func base64Reader(r io.Reader) (io.Reader, error) {
|
||||
return base64.NewDecoder(base64.StdEncoding, r), nil
|
||||
}
|
||||
|
||||
func gzipReader(r io.Reader) (io.Reader, error) {
|
||||
return gzip.NewReader(r)
|
||||
}
|
||||
|
||||
// StoreConfig stores the config into the KV Store
|
||||
func (kv *KvSource) StoreConfig(config interface{}) error {
|
||||
kvMap := map[string]string{}
|
||||
if err := collateKvRecursive(reflect.ValueOf(config), kvMap, kv.Prefix); err != nil {
|
||||
return err
|
||||
}
|
||||
var keys []string
|
||||
for key := range kvMap {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
var writeOptions *store.WriteOptions
|
||||
// is it a directory ?
|
||||
if strings.HasSuffix(k, "/") {
|
||||
writeOptions = &store.WriteOptions{
|
||||
IsDir: true,
|
||||
}
|
||||
}
|
||||
if err := kv.Put(k, []byte(kvMap[k]), writeOptions); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func collateKvRecursive(objValue reflect.Value, kv map[string]string, key string) error {
|
||||
name := key
|
||||
kind := objValue.Kind()
|
||||
|
||||
// custom marshaler
|
||||
if marshaler, ok := objValue.Interface().(encoding.TextMarshaler); ok {
|
||||
test, err := marshaler.MarshalText()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error marshaling key %s: %v", name, err)
|
||||
}
|
||||
kv[name] = string(test)
|
||||
return nil
|
||||
}
|
||||
switch kind {
|
||||
case reflect.Struct:
|
||||
for i := 0; i < objValue.NumField(); i++ {
|
||||
objType := objValue.Type()
|
||||
if objType.Field(i).Name[:1] != strings.ToUpper(objType.Field(i).Name[:1]) {
|
||||
//if unexported field
|
||||
continue
|
||||
}
|
||||
squashed := false
|
||||
if objType.Field(i).Anonymous {
|
||||
if objValue.Field(i).Kind() == reflect.Struct {
|
||||
tags := objType.Field(i).Tag
|
||||
if strings.Contains(string(tags), "squash") {
|
||||
squashed = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if squashed {
|
||||
if err := collateKvRecursive(objValue.Field(i), kv, name); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
fieldName := objType.Field(i).Name
|
||||
//useless if not empty Prefix is required ?
|
||||
if len(key) == 0 {
|
||||
name = strings.ToLower(fieldName)
|
||||
} else {
|
||||
name = key + "/" + strings.ToLower(fieldName)
|
||||
}
|
||||
|
||||
if err := collateKvRecursive(objValue.Field(i), kv, name); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case reflect.Ptr:
|
||||
if !objValue.IsNil() {
|
||||
// hack to avoid calling this at the beginning
|
||||
if len(kv) > 0 {
|
||||
kv[name+"/"] = ""
|
||||
}
|
||||
if err := collateKvRecursive(objValue.Elem(), kv, name); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case reflect.Map:
|
||||
for _, k := range objValue.MapKeys() {
|
||||
if k.Kind() == reflect.Struct {
|
||||
return errors.New("struct as key not supported")
|
||||
}
|
||||
name = key + "/" + fmt.Sprint(k)
|
||||
if err := collateKvRecursive(objValue.MapIndex(k), kv, name); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case reflect.Array, reflect.Slice:
|
||||
// Byte slices get special treatment
|
||||
if objValue.Type().Elem().Kind() == reflect.Uint8 {
|
||||
compressedData, err := writeCompressedData(objValue.Bytes())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
kv[name] = compressedData
|
||||
} else {
|
||||
for i := 0; i < objValue.Len(); i++ {
|
||||
name = key + "/" + strconv.Itoa(i)
|
||||
if err := collateKvRecursive(objValue.Index(i), kv, name); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
case reflect.Interface, reflect.String, reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16,
|
||||
reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16,
|
||||
reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64:
|
||||
if _, ok := kv[name]; ok {
|
||||
return errors.New("key already exists: " + name)
|
||||
}
|
||||
kv[name] = fmt.Sprint(objValue)
|
||||
|
||||
default:
|
||||
return fmt.Errorf("kind %s not supported", kind.String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeCompressedData(data []byte) (string, error) {
|
||||
var buffer bytes.Buffer
|
||||
gzipWriter := gzip.NewWriter(&buffer)
|
||||
|
||||
_, err := gzipWriter.Write(data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
err = gzipWriter.Close()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return buffer.String(), nil
|
||||
}
|
||||
|
||||
// ListRecursive lists all key value children under key
|
||||
// Replaced by ListValuedPairWithPrefix
|
||||
// Deprecated
|
||||
func (kv *KvSource) ListRecursive(key string, pairs map[string][]byte) error {
|
||||
pairsN1, err := kv.List(key, nil)
|
||||
if err == store.ErrKeyNotFound {
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(pairsN1) == 0 {
|
||||
pairLeaf, err := kv.Get(key, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if pairLeaf == nil {
|
||||
return nil
|
||||
}
|
||||
pairs[pairLeaf.Key] = pairLeaf.Value
|
||||
return nil
|
||||
}
|
||||
for _, p := range pairsN1 {
|
||||
if p.Key != key {
|
||||
err := kv.ListRecursive(p.Key, pairs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListValuedPairWithPrefix lists all key value children under key
|
||||
func (kv *KvSource) ListValuedPairWithPrefix(key string) (map[string][]byte, error) {
|
||||
pairs := make(map[string][]byte)
|
||||
|
||||
pairsN1, err := kv.List(key, nil)
|
||||
if err == store.ErrKeyNotFound {
|
||||
return pairs, nil
|
||||
}
|
||||
if err != nil {
|
||||
return pairs, err
|
||||
}
|
||||
|
||||
for _, p := range pairsN1 {
|
||||
if len(p.Value) > 0 {
|
||||
pairs[p.Key] = p.Value
|
||||
}
|
||||
}
|
||||
|
||||
return pairs, nil
|
||||
}
|
||||
|
||||
func convertPairs(pairs map[string][]byte) []*store.KVPair {
|
||||
slicePairs := make([]*store.KVPair, len(pairs))
|
||||
i := 0
|
||||
for k, v := range pairs {
|
||||
slicePairs[i] = &store.KVPair{
|
||||
Key: k,
|
||||
Value: v,
|
||||
}
|
||||
i++
|
||||
}
|
||||
return slicePairs
|
||||
}
|
80
vendor/github.com/containous/staert/staert.go
generated
vendored
80
vendor/github.com/containous/staert/staert.go
generated
vendored
|
@ -1,80 +0,0 @@
|
|||
package staert
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/containous/flaeg"
|
||||
)
|
||||
|
||||
// Source interface must be satisfy to Add any kink of Source to Staert as like as TomlFile or Flaeg
|
||||
type Source interface {
|
||||
Parse(cmd *flaeg.Command) (*flaeg.Command, error)
|
||||
}
|
||||
|
||||
// Staert contains the struct to configure, thee default values inside structs and the sources
|
||||
type Staert struct {
|
||||
command *flaeg.Command
|
||||
sources []Source
|
||||
}
|
||||
|
||||
// NewStaert creates and return a pointer on Staert. Need defaultConfig and defaultPointersConfig given by references
|
||||
func NewStaert(rootCommand *flaeg.Command) *Staert {
|
||||
return &Staert{command: rootCommand}
|
||||
}
|
||||
|
||||
// AddSource adds new Source to Staert, give it by reference
|
||||
func (s *Staert) AddSource(src Source) {
|
||||
s.sources = append(s.sources, src)
|
||||
}
|
||||
|
||||
// LoadConfig check which command is called and parses config
|
||||
// It returns the the parsed config or an error if it fails
|
||||
func (s *Staert) LoadConfig() (interface{}, error) {
|
||||
for _, src := range s.sources {
|
||||
// Type assertion
|
||||
if flg, ok := src.(*flaeg.Flaeg); ok {
|
||||
fCmd, err := flg.GetCommand()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// if fleag sub-command
|
||||
if s.command != fCmd {
|
||||
// if parseAllSources
|
||||
if fCmd.Metadata["parseAllSources"] == "true" {
|
||||
fCmdConfigType := reflect.TypeOf(fCmd.Config)
|
||||
sCmdConfigType := reflect.TypeOf(s.command.Config)
|
||||
if fCmdConfigType != sCmdConfigType {
|
||||
return nil, fmt.Errorf("command %s : Config type doesn't match with root command config type. Expected %s got %s",
|
||||
fCmd.Name, sCmdConfigType.Name(), fCmdConfigType.Name())
|
||||
}
|
||||
s.command = fCmd
|
||||
} else {
|
||||
// (not parseAllSources)
|
||||
s.command, err = flg.Parse(fCmd)
|
||||
return s.command.Config, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
err := s.parseConfigAllSources(s.command)
|
||||
return s.command.Config, err
|
||||
}
|
||||
|
||||
// parseConfigAllSources getConfig for a flaeg.Command run sources Parse func in the raw
|
||||
func (s *Staert) parseConfigAllSources(cmd *flaeg.Command) error {
|
||||
for _, src := range s.sources {
|
||||
_, err := src.Parse(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Run calls the Run func of the command
|
||||
// Warning, Run doesn't parse the config
|
||||
func (s *Staert) Run() error {
|
||||
return s.command.Run()
|
||||
}
|
118
vendor/github.com/containous/staert/toml.go
generated
vendored
118
vendor/github.com/containous/staert/toml.go
generated
vendored
|
@ -1,118 +0,0 @@
|
|||
package staert
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/containous/flaeg"
|
||||
)
|
||||
|
||||
var _ Source = (*TomlSource)(nil)
|
||||
|
||||
// TomlSource implement staert.Source
|
||||
type TomlSource struct {
|
||||
filename string
|
||||
dirNFullPath []string
|
||||
fullPath string
|
||||
}
|
||||
|
||||
// NewTomlSource creates and return a pointer on Source.
|
||||
// Parameter filename is the file name (without extension type, ".toml" will be added)
|
||||
// dirNFullPath may contain directories or fullPath to the file.
|
||||
func NewTomlSource(filename string, dirNFullPath []string) *TomlSource {
|
||||
return &TomlSource{filename, dirNFullPath, ""}
|
||||
}
|
||||
|
||||
// ConfigFileUsed return config file used
|
||||
func (ts *TomlSource) ConfigFileUsed() string {
|
||||
return ts.fullPath
|
||||
}
|
||||
|
||||
// Parse calls toml.DecodeFile() func
|
||||
func (ts *TomlSource) Parse(cmd *flaeg.Command) (*flaeg.Command, error) {
|
||||
ts.fullPath = findFile(ts.filename, ts.dirNFullPath)
|
||||
if len(ts.fullPath) < 2 {
|
||||
return cmd, nil
|
||||
}
|
||||
|
||||
metadata, err := toml.DecodeFile(ts.fullPath, cmd.Config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
boolFlags, err := flaeg.GetBoolFlags(cmd.Config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
flgArgs, hasUnderField := generateArgs(metadata, boolFlags)
|
||||
|
||||
err = flaeg.Load(cmd.Config, cmd.DefaultPointersConfig, flgArgs)
|
||||
if err != nil && err != flaeg.ErrParserNotFound {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if hasUnderField {
|
||||
_, err := toml.DecodeFile(ts.fullPath, cmd.Config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return cmd, nil
|
||||
}
|
||||
|
||||
func preProcessDir(dirIn string) (string, error) {
|
||||
expanded := os.ExpandEnv(dirIn)
|
||||
return filepath.Abs(expanded)
|
||||
}
|
||||
|
||||
func findFile(filename string, dirNFile []string) string {
|
||||
for _, df := range dirNFile {
|
||||
if df != "" {
|
||||
fullPath, _ := preProcessDir(df)
|
||||
if fileInfo, err := os.Stat(fullPath); err == nil && !fileInfo.IsDir() {
|
||||
return fullPath
|
||||
}
|
||||
|
||||
fullPath = filepath.Join(fullPath, filename+".toml")
|
||||
if fileInfo, err := os.Stat(fullPath); err == nil && !fileInfo.IsDir() {
|
||||
return fullPath
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func generateArgs(metadata toml.MetaData, flags []string) ([]string, bool) {
|
||||
var flgArgs []string
|
||||
keys := metadata.Keys()
|
||||
hasUnderField := false
|
||||
|
||||
for i, key := range keys {
|
||||
if metadata.Type(key.String()) == "Hash" {
|
||||
// TOML hashes correspond to Go structs or maps.
|
||||
for j := i; j < len(keys); j++ {
|
||||
if strings.Contains(keys[j].String(), key.String()+".") {
|
||||
hasUnderField = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
match := false
|
||||
for _, flag := range flags {
|
||||
if flag == strings.ToLower(key.String()) {
|
||||
match = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if match {
|
||||
flgArgs = append(flgArgs, "--"+strings.ToLower(key.String()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return flgArgs, hasUnderField
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue