refactor: openpitrix module
Signed-off-by: hongming <talonwan@yunify.com>
This commit is contained in:
207
vendor/github.com/koding/multiconfig/flag.go
generated
vendored
Normal file
207
vendor/github.com/koding/multiconfig/flag.go
generated
vendored
Normal file
@@ -0,0 +1,207 @@
|
||||
package multiconfig
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/camelcase"
|
||||
"github.com/fatih/structs"
|
||||
)
|
||||
|
||||
// FlagLoader satisfies the loader interface. It creates on the fly flags based
|
||||
// on the field names and parses them to load into the given pointer of struct
|
||||
// s.
|
||||
type FlagLoader struct {
|
||||
// Prefix prepends the prefix to each flag name i.e:
|
||||
// --foo is converted to --prefix-foo.
|
||||
// --foo-bar is converted to --prefix-foo-bar.
|
||||
Prefix string
|
||||
|
||||
// Flatten doesn't add prefixes for nested structs. So previously if we had
|
||||
// a nested struct `type T struct{Name struct{ ...}}`, this would generate
|
||||
// --name-foo, --name-bar, etc. When Flatten is enabled, the flags will be
|
||||
// flattend to the form: --foo, --bar, etc.. Panics if the nested structs
|
||||
// has a duplicate field name in the root level of the struct (outer
|
||||
// struct). Use this option only if you know what you do.
|
||||
Flatten bool
|
||||
|
||||
// CamelCase adds a separator for field names in camelcase form. A
|
||||
// fieldname of "AccessKey" would generate a flag name "--accesskey". If
|
||||
// CamelCase is enabled, the flag name will be generated in the form of
|
||||
// "--access-key"
|
||||
CamelCase bool
|
||||
|
||||
// EnvPrefix is just a placeholder to print the correct usages when an
|
||||
// EnvLoader is used
|
||||
EnvPrefix string
|
||||
|
||||
// ErrorHandling is used to configure error handling used by
|
||||
// *flag.FlagSet.
|
||||
//
|
||||
// By default it's flag.ContinueOnError.
|
||||
ErrorHandling flag.ErrorHandling
|
||||
|
||||
// Args defines a custom argument list. If nil, os.Args[1:] is used.
|
||||
Args []string
|
||||
|
||||
// FlagUsageFunc an optional function that is called to set a flag.Usage value
|
||||
// The input is the raw flag name, and the output should be a string
|
||||
// that will used in passed into the flag for Usage.
|
||||
FlagUsageFunc func(name string) string
|
||||
|
||||
// only exists for testing. This is the raw flagset that is to parse
|
||||
flagSet *flag.FlagSet
|
||||
}
|
||||
|
||||
// Load loads the source into the config defined by struct s
|
||||
func (f *FlagLoader) Load(s interface{}) error {
|
||||
strct := structs.New(s)
|
||||
structName := strct.Name()
|
||||
|
||||
flagSet := flag.NewFlagSet(structName, f.ErrorHandling)
|
||||
f.flagSet = flagSet
|
||||
|
||||
for _, field := range strct.Fields() {
|
||||
f.processField(field.Name(), field)
|
||||
}
|
||||
|
||||
flagSet.Usage = func() {
|
||||
fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
|
||||
flagSet.PrintDefaults()
|
||||
fmt.Fprintf(os.Stderr, "\nGenerated environment variables:\n")
|
||||
e := &EnvironmentLoader{
|
||||
Prefix: f.EnvPrefix,
|
||||
CamelCase: f.CamelCase,
|
||||
}
|
||||
e.PrintEnvs(s)
|
||||
fmt.Println("")
|
||||
}
|
||||
|
||||
args := filterArgs(os.Args[1:])
|
||||
if f.Args != nil {
|
||||
args = f.Args
|
||||
}
|
||||
|
||||
return flagSet.Parse(args)
|
||||
}
|
||||
|
||||
func filterArgs(args []string) []string {
|
||||
r := []string{}
|
||||
for i := 0; i < len(args); i++ {
|
||||
if strings.Index(args[i], "test.") >= 0 {
|
||||
if i + 1 < len(args) && strings.Index(args[i + 1], "-") == -1 {
|
||||
i++
|
||||
}
|
||||
i++
|
||||
} else {
|
||||
r = append(r, args[i])
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// processField generates a flag based on the given field and fieldName. If a
|
||||
// nested struct is detected, a flag for each field of that nested struct is
|
||||
// generated too.
|
||||
func (f *FlagLoader) processField(fieldName string, field *structs.Field) error {
|
||||
if f.CamelCase {
|
||||
fieldName = strings.Join(camelcase.Split(fieldName), "-")
|
||||
fieldName = strings.Replace(fieldName, "---", "-", -1)
|
||||
}
|
||||
|
||||
switch field.Kind() {
|
||||
case reflect.Struct:
|
||||
for _, ff := range field.Fields() {
|
||||
flagName := field.Name() + "-" + ff.Name()
|
||||
|
||||
if f.Flatten {
|
||||
// first check if it's set or not, because if we have duplicate
|
||||
// we don't want to break the flag. Panic by giving a readable
|
||||
// output
|
||||
f.flagSet.VisitAll(func(fl *flag.Flag) {
|
||||
if strings.ToLower(ff.Name()) == fl.Name {
|
||||
// already defined
|
||||
panic(fmt.Sprintf("flag '%s' is already defined in outer struct", fl.Name))
|
||||
}
|
||||
})
|
||||
|
||||
flagName = ff.Name()
|
||||
}
|
||||
|
||||
if err := f.processField(flagName, ff); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
default:
|
||||
// Add custom prefix to the flag if it's set
|
||||
if f.Prefix != "" {
|
||||
fieldName = f.Prefix + "-" + fieldName
|
||||
}
|
||||
|
||||
// we only can get the value from expored fields, unexported fields panics
|
||||
if field.IsExported() {
|
||||
f.flagSet.Var(newFieldValue(field), flagName(fieldName), f.flagUsage(fieldName, field))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *FlagLoader) flagUsage(fieldName string, field *structs.Field) string {
|
||||
if f.FlagUsageFunc != nil {
|
||||
return f.FlagUsageFunc(fieldName)
|
||||
}
|
||||
|
||||
usage := field.Tag("flagUsage")
|
||||
if usage != "" {
|
||||
return usage
|
||||
}
|
||||
|
||||
return fmt.Sprintf("Change value of %s.", fieldName)
|
||||
}
|
||||
|
||||
// fieldValue satisfies the flag.Value and flag.Getter interfaces
|
||||
type fieldValue struct {
|
||||
field *structs.Field
|
||||
}
|
||||
|
||||
func newFieldValue(f *structs.Field) *fieldValue {
|
||||
return &fieldValue{
|
||||
field: f,
|
||||
}
|
||||
}
|
||||
|
||||
func (f *fieldValue) Set(val string) error {
|
||||
return fieldSet(f.field, val)
|
||||
}
|
||||
|
||||
func (f *fieldValue) String() string {
|
||||
if f.IsZero() {
|
||||
return ""
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%v", f.field.Value())
|
||||
}
|
||||
|
||||
func (f *fieldValue) Get() interface{} {
|
||||
if f.IsZero() {
|
||||
return nil
|
||||
}
|
||||
|
||||
return f.field.Value()
|
||||
}
|
||||
|
||||
func (f *fieldValue) IsZero() bool {
|
||||
return f.field == nil
|
||||
}
|
||||
|
||||
// This is an unexported interface, be careful about it.
|
||||
// https://code.google.com/p/go/source/browse/src/pkg/flag/flag.go?name=release#101
|
||||
func (f *fieldValue) IsBoolFlag() bool {
|
||||
return f.field.Kind() == reflect.Bool
|
||||
}
|
||||
|
||||
func flagName(name string) string { return strings.ToLower(name) }
|
||||
Reference in New Issue
Block a user