Vendor main dependencies.
This commit is contained in:
parent
49a09ab7dd
commit
dd5e3fba01
2738 changed files with 1045689 additions and 0 deletions
752
vendor/github.com/containous/flaeg/flaeg.go
generated
vendored
Normal file
752
vendor/github.com/containous/flaeg/flaeg.go
generated
vendored
Normal file
|
@ -0,0 +1,752 @@
|
|||
package flaeg
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
flag "github.com/ogier/pflag"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"text/template"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 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 genereted 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)
|
||||
}
|
||||
|
||||
name += objValue.Type().Name()
|
||||
if tag := objValue.Type().Field(i).Tag.Get("long"); len(tag) > 0 {
|
||||
fieldName = tag
|
||||
}
|
||||
if len(key) == 0 {
|
||||
//Lower Camel Case
|
||||
//name = strings.ToLower(string(fieldName[0])) + fieldName[1:]
|
||||
name = strings.ToLower(fieldName)
|
||||
} else {
|
||||
name = key + "." + strings.ToLower(fieldName)
|
||||
}
|
||||
if _, ok := flagmap[name]; ok {
|
||||
return errors.New("Tag already exists: " + 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
|
||||
}
|
||||
|
||||
//GetPointerFlags 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
|
||||
}
|
||||
|
||||
//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 durationValue
|
||||
parsers[reflect.TypeOf(time.Second)] = &durationParser
|
||||
|
||||
var timeParser timeValue
|
||||
parsers[reflect.TypeOf(time.Now())] = &timeParser
|
||||
|
||||
for rType, parser := range customParsers {
|
||||
parsers[rType] = parser
|
||||
}
|
||||
return parsers, nil
|
||||
}
|
||||
|
||||
//ParseArgs : parses args return valmap map[flag]Getter, using parsers map[type]Getter
|
||||
//args must be formated as like as flag documentation. See https://golang.org/pkg/flag
|
||||
func parseArgs(args []string, flagmap map[string]reflect.StructField, parsers map[reflect.Type]Parser) (map[string]Parser, error) {
|
||||
//Return var
|
||||
valmap := make(map[string]Parser)
|
||||
//Visitor in flag.Parse
|
||||
flagList := []*flag.Flag{}
|
||||
visitor := func(fl *flag.Flag) {
|
||||
flagList = append(flagList, fl)
|
||||
}
|
||||
newParsers := map[string]Parser{}
|
||||
flagSet := flag.NewFlagSet("flaeg.Load", flag.ContinueOnError)
|
||||
//Disable output
|
||||
flagSet.SetOutput(ioutil.Discard)
|
||||
var err error
|
||||
for flag, structField := range flagmap {
|
||||
//for _, flag := range flags {
|
||||
//structField := flagmap[flag]
|
||||
if parser, ok := parsers[structField.Type]; ok {
|
||||
newparserValue := reflect.New(reflect.TypeOf(parser).Elem())
|
||||
newparserValue.Elem().Set(reflect.ValueOf(parser).Elem())
|
||||
newparser := newparserValue.Interface().(Parser)
|
||||
if short := structField.Tag.Get("short"); len(short) == 1 {
|
||||
// fmt.Printf("short : %s long : %s\n", short, flag)
|
||||
flagSet.VarP(newparser, flag, short, structField.Tag.Get("description"))
|
||||
} else {
|
||||
flagSet.Var(newparser, flag, structField.Tag.Get("description"))
|
||||
}
|
||||
newParsers[flag] = newparser
|
||||
} else {
|
||||
err = ErrParserNotFound
|
||||
}
|
||||
}
|
||||
|
||||
// prevents case sensitivity issue
|
||||
args = argsToLower(args)
|
||||
if err := flagSet.Parse(args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//Fill flagList with parsed flags
|
||||
flagSet.Visit(visitor)
|
||||
//Return parsers on parsed flag
|
||||
for _, flag := range flagList {
|
||||
valmap[flag.Name] = newParsers[flag.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 {
|
||||
name += defaultValue.Type().Name()
|
||||
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 {
|
||||
// if _, ok := defaultValmap[name]; ok {
|
||||
// return errors.New("Tag already exists: " + name)
|
||||
// }
|
||||
defaultValmap[name] = defaultValue.Field(i)
|
||||
// fmt.Printf("%s: got default value %+v\n", 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
|
||||
// fmt.Printf("%s: got default value %+v\n", 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
|
||||
// fmt.Printf("%s: got default value %+v\n", 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().String())
|
||||
} else if objValue.IsNil() {
|
||||
return objValue, fmt.Errorf("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 taged Struct given by reference
|
||||
func fillStructRecursive(objValue reflect.Value, defaultPointerValmap map[string]reflect.Value, valmap map[string]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 {
|
||||
name += objValue.Type().Name()
|
||||
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)
|
||||
}
|
||||
// fmt.Println(name)
|
||||
if objValue.Field(i).Kind() != reflect.Ptr {
|
||||
|
||||
if val, ok := valmap[name]; ok {
|
||||
// fmt.Printf("%s : set def val\n", name)
|
||||
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() {
|
||||
if err := fillStructRecursive(objValue.Elem(), defaultPointerValmap, valmap, name); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
contains := false
|
||||
for flag := range valmap {
|
||||
// TODO replace by regexp
|
||||
if strings.Contains(flag, 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
|
||||
// fmt.Printf("%s : set default value %+v\n", name, defVal)
|
||||
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 Parser) error {
|
||||
if fieldValue.CanSet() {
|
||||
fieldValue.Set(reflect.ValueOf(val).Elem().Convert(fieldValue.Type()))
|
||||
} else {
|
||||
return errors.New(fieldValue.Type().String() + " is not settable.")
|
||||
}
|
||||
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]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]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]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
|
||||
}
|
||||
|
||||
//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]Parser, subCommand []*Command) error {
|
||||
|
||||
parsers, err := 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]Parser, cmd *Command, subCmd []*Command) error {
|
||||
// Define a templates
|
||||
// Using POSXE STD : http://pubs.opengroup.org/onlinepubs/9699919799/
|
||||
const helper = `{{if .ProgDescription}}{{.ProgDescription}}
|
||||
|
||||
{{end}}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)
|
||||
{{if .SubCommands}}
|
||||
Available Commands:{{range $subCmdName, $subCmdDesc := .SubCommands}}
|
||||
{{printf "\t%-50s %s" $subCmdName $subCmdDesc}}{{end}}
|
||||
Use "{{.ProgName}} [command] --help" for more information about a command.
|
||||
{{end}}
|
||||
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:] {
|
||||
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]Parser, output io.Writer) error {
|
||||
// Sort alphabetically & Delete unparsable flags in a slice
|
||||
flags := []string{}
|
||||
for flag, field := range flagmap {
|
||||
if _, ok := parsers[field.Type]; ok {
|
||||
flags = append(flags, flag)
|
||||
}
|
||||
}
|
||||
sort.Strings(flags)
|
||||
|
||||
// Process data
|
||||
descriptions := []string{}
|
||||
defaultValues := []string{}
|
||||
flagsWithDashs := []string{}
|
||||
shortFlagsWithDash := []string{}
|
||||
for _, flag := range flags {
|
||||
field := flagmap[flag]
|
||||
if short := field.Tag.Get("short"); len(short) == 1 {
|
||||
shortFlagsWithDash = append(shortFlagsWithDash, "-"+short+",")
|
||||
} else {
|
||||
shortFlagsWithDash = append(shortFlagsWithDash, "")
|
||||
}
|
||||
flagsWithDashs = append(flagsWithDashs, "--"+flag)
|
||||
|
||||
//flag on pointer ?
|
||||
if defVal, ok := defaultValmap[flag]; ok {
|
||||
if defVal.Kind() != reflect.Ptr {
|
||||
// Set defaultValue on parsers
|
||||
parsers[field.Type].SetValue(defaultValmap[flag].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, "")
|
||||
flagsWithDashs = append(flagsWithDashs, "")
|
||||
shortFlagsWithDash = append(shortFlagsWithDash, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
//add help flag
|
||||
shortFlagsWithDash = append(shortFlagsWithDash, "-h,")
|
||||
flagsWithDashs = append(flagsWithDashs, "--help")
|
||||
descriptions = append(descriptions, "Print Help (this message) and exit")
|
||||
defaultValues = append(defaultValues, "")
|
||||
return displayTab(output, shortFlagsWithDash, flagsWithDashs, 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 {
|
||||
nbRow := len(columns[0])
|
||||
nbCol := len(columns)
|
||||
w := new(tabwriter.Writer)
|
||||
w.Init(output, 0, 4, 1, ' ', 0)
|
||||
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)
|
||||
}
|
||||
w.Flush()
|
||||
return nil
|
||||
}
|
||||
|
||||
//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]Parser, cmd *Command, subCmd []*Command) error {
|
||||
if err != flag.ErrHelp {
|
||||
fmt.Printf("Error here : %s\n", err)
|
||||
}
|
||||
PrintHelpWithCommand(flagmap, defaultValmap, parsers, cmd, subCmd)
|
||||
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
|
||||
commmandArgs []string
|
||||
customParsers map[reflect.Type]Parser
|
||||
}
|
||||
|
||||
//New creats 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]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 Parser) {
|
||||
f.customParsers[typ] = parser
|
||||
}
|
||||
|
||||
// Run calls the command with flags given as agruments
|
||||
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.commmandArgs = f.args
|
||||
}
|
||||
if err := LoadWithCommand(cmd, f.commmandArgs, 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) {
|
||||
commandName := ""
|
||||
commandName, f.commmandArgs = splitArgs(f.args)
|
||||
if len(commandName) > 0 {
|
||||
for _, command := range f.commands {
|
||||
if commandName == command.Name {
|
||||
f.calledCommand = command
|
||||
return f.calledCommand, f.commmandArgs, nil
|
||||
}
|
||||
}
|
||||
return nil, []string{}, fmt.Errorf("Command %s not found", commandName)
|
||||
}
|
||||
|
||||
f.calledCommand = f.commands[0]
|
||||
return f.calledCommand, f.commmandArgs, 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), len(inArgs))
|
||||
for i, inArg := range inArgs {
|
||||
outArgs[i] = argToLower(inArg)
|
||||
}
|
||||
return outArgs
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue