refactor: openpitrix module
Signed-off-by: hongming <talonwan@yunify.com>
This commit is contained in:
25
vendor/github.com/koding/multiconfig/.gitignore
generated
vendored
Normal file
25
vendor/github.com/koding/multiconfig/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
|
||||
*~
|
||||
4
vendor/github.com/koding/multiconfig/.travis.yml
generated
vendored
Normal file
4
vendor/github.com/koding/multiconfig/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
language: go
|
||||
go: 1.3
|
||||
script: go test ./...
|
||||
|
||||
21
vendor/github.com/koding/multiconfig/LICENSE
generated
vendored
Normal file
21
vendor/github.com/koding/multiconfig/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Koding, Inc.
|
||||
|
||||
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.
|
||||
92
vendor/github.com/koding/multiconfig/README.md
generated
vendored
Normal file
92
vendor/github.com/koding/multiconfig/README.md
generated
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
# Multiconfig [](http://godoc.org/github.com/koding/multiconfig) [](https://travis-ci.org/koding/multiconfig)
|
||||
|
||||
Load configuration from multiple sources. Multiconfig makes loading/parsing
|
||||
from different configuration sources an easy task. The problem with any app is
|
||||
that with time there are many options how to populate a set of configs.
|
||||
Multiconfig makes it easy by dynamically creating all necessary options.
|
||||
Checkout the example below to see it in action.
|
||||
|
||||
## Features
|
||||
|
||||
Multiconfig is able to read configuration automatically based on the given struct's field names from the following sources:
|
||||
|
||||
* Struct tags
|
||||
* TOML file
|
||||
* JSON file
|
||||
* YAML file
|
||||
* Environment variables
|
||||
* Flags
|
||||
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
go get github.com/koding/multiconfig
|
||||
```
|
||||
|
||||
## Usage and Examples
|
||||
|
||||
Lets define and struct that defines our configuration
|
||||
|
||||
```go
|
||||
type Server struct {
|
||||
Name string `required:"true"`
|
||||
Port int `default:"6060"`
|
||||
Enabled bool
|
||||
Users []string
|
||||
}
|
||||
```
|
||||
|
||||
Load the configuration into multiconfig:
|
||||
|
||||
```go
|
||||
// Create a new DefaultLoader without or with an initial config file
|
||||
m := multiconfig.New()
|
||||
m := multiconfig.NewWithPath("config.toml") // supports TOML, JSON and YAML
|
||||
|
||||
// Get an empty struct for your configuration
|
||||
serverConf := new(Server)
|
||||
|
||||
// Populated the serverConf struct
|
||||
err := m.Load(serverConf) // Check for error
|
||||
m.MustLoad(serverConf) // Panic's if there is any error
|
||||
|
||||
// Access now populated fields
|
||||
serverConf.Port // by default 6060
|
||||
serverConf.Name // "koding"
|
||||
```
|
||||
|
||||
Run your app:
|
||||
|
||||
```sh
|
||||
# Sets default values first which are defined in each field tag value.
|
||||
# Starts to load from config.toml
|
||||
$ app
|
||||
|
||||
# Override any config easily with environment variables, environment variables
|
||||
# are automatically generated in the form of STRUCTNAME_FIELDNAME
|
||||
$ SERVER_PORT=4000 SERVER_NAME="koding" app
|
||||
|
||||
# Or pass via flag. Flags are also automatically generated based on the field
|
||||
# name
|
||||
$ app -port 4000 -users "gopher,koding"
|
||||
|
||||
# Print dynamically generated flags and environment variables:
|
||||
$ app -help
|
||||
Usage of app:
|
||||
-enabled=true: Change value of Enabled.
|
||||
-name=Koding: Change value of Name.
|
||||
-port=6060: Change value of Port.
|
||||
-users=[ankara istanbul]: Change value of Users.
|
||||
|
||||
Generated environment variables:
|
||||
SERVER_NAME
|
||||
SERVER_PORT
|
||||
SERVER_ENABLED
|
||||
SERVER_USERS
|
||||
```
|
||||
|
||||
|
||||
## License
|
||||
|
||||
The MIT License (MIT) - see [LICENSE](/LICENSE) for more details
|
||||
5
vendor/github.com/koding/multiconfig/doc.go
generated
vendored
Normal file
5
vendor/github.com/koding/multiconfig/doc.go
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
// Package multiconfig provides a way to load and read configurations from
|
||||
// multiple sources. You can read from TOML file, JSON file, YAML file, Environment
|
||||
// Variables and flags. You can set the order of reader with MultiLoader. Package
|
||||
// is extensible, you can add your custom Loader by implementing the Load interface.
|
||||
package multiconfig
|
||||
129
vendor/github.com/koding/multiconfig/env.go
generated
vendored
Normal file
129
vendor/github.com/koding/multiconfig/env.go
generated
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
package multiconfig
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/camelcase"
|
||||
"github.com/fatih/structs"
|
||||
)
|
||||
|
||||
// EnvironmentLoader satisifies the loader interface. It loads the
|
||||
// configuration from the environment variables in the form of
|
||||
// STRUCTNAME_FIELDNAME.
|
||||
type EnvironmentLoader struct {
|
||||
// Prefix prepends given string to every environment variable
|
||||
// {STRUCTNAME}_FIELDNAME will be {PREFIX}_FIELDNAME
|
||||
Prefix string
|
||||
|
||||
// CamelCase adds a separator for field names in camelcase form. A
|
||||
// fieldname of "AccessKey" would generate a environment name of
|
||||
// "STRUCTNAME_ACCESSKEY". If CamelCase is enabled, the environment name
|
||||
// will be generated in the form of "STRUCTNAME_ACCESS_KEY"
|
||||
CamelCase bool
|
||||
}
|
||||
|
||||
func (e *EnvironmentLoader) getPrefix(s *structs.Struct) string {
|
||||
if e.Prefix != "" {
|
||||
return e.Prefix
|
||||
}
|
||||
|
||||
return s.Name()
|
||||
}
|
||||
|
||||
// Load loads the source into the config defined by struct s
|
||||
func (e *EnvironmentLoader) Load(s interface{}) error {
|
||||
strct := structs.New(s)
|
||||
strctMap := strct.Map()
|
||||
prefix := e.getPrefix(strct)
|
||||
|
||||
for key, val := range strctMap {
|
||||
field := strct.Field(key)
|
||||
|
||||
if err := e.processField(prefix, field, key, val); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// processField gets leading name for the env variable and combines the current
|
||||
// field's name and generates environment variable names recursively
|
||||
func (e *EnvironmentLoader) processField(prefix string, field *structs.Field, name string, strctMap interface{}) error {
|
||||
fieldName := e.generateFieldName(prefix, name)
|
||||
|
||||
switch strctMap.(type) {
|
||||
case map[string]interface{}:
|
||||
for key, val := range strctMap.(map[string]interface{}) {
|
||||
field := field.Field(key)
|
||||
|
||||
if err := e.processField(fieldName, field, key, val); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
default:
|
||||
v := os.Getenv(fieldName)
|
||||
if v == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := fieldSet(field, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PrintEnvs prints the generated environment variables to the std out.
|
||||
func (e *EnvironmentLoader) PrintEnvs(s interface{}) {
|
||||
strct := structs.New(s)
|
||||
strctMap := strct.Map()
|
||||
prefix := e.getPrefix(strct)
|
||||
|
||||
keys := make([]string, 0, len(strctMap))
|
||||
for key := range strctMap {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, key := range keys {
|
||||
field := strct.Field(key)
|
||||
e.printField(prefix, field, key, strctMap[key])
|
||||
}
|
||||
}
|
||||
|
||||
// printField prints the field of the config struct for the flag.Usage
|
||||
func (e *EnvironmentLoader) printField(prefix string, field *structs.Field, name string, strctMap interface{}) {
|
||||
fieldName := e.generateFieldName(prefix, name)
|
||||
|
||||
switch strctMap.(type) {
|
||||
case map[string]interface{}:
|
||||
smap := strctMap.(map[string]interface{})
|
||||
keys := make([]string, 0, len(smap))
|
||||
for key := range smap {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, key := range keys {
|
||||
field := field.Field(key)
|
||||
e.printField(fieldName, field, key, smap[key])
|
||||
}
|
||||
default:
|
||||
fmt.Println(" ", fieldName)
|
||||
}
|
||||
}
|
||||
|
||||
// generateFieldName generates the field name combined with the prefix and the
|
||||
// struct's field name
|
||||
func (e *EnvironmentLoader) generateFieldName(prefix string, name string) string {
|
||||
fieldName := strings.ToUpper(name)
|
||||
if e.CamelCase {
|
||||
fieldName = strings.ToUpper(strings.Join(camelcase.Split(name), "_"))
|
||||
}
|
||||
|
||||
return strings.ToUpper(prefix) + "_" + fieldName
|
||||
}
|
||||
139
vendor/github.com/koding/multiconfig/file.go
generated
vendored
Normal file
139
vendor/github.com/koding/multiconfig/file.go
generated
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
package multiconfig
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrSourceNotSet states that neither the path or the reader is set on the loader
|
||||
ErrSourceNotSet = errors.New("config path or reader is not set")
|
||||
|
||||
// ErrFileNotFound states that given file is not exists
|
||||
ErrFileNotFound = errors.New("config file not found")
|
||||
)
|
||||
|
||||
// TOMLLoader satisifies the loader interface. It loads the configuration from
|
||||
// the given toml file or Reader.
|
||||
type TOMLLoader struct {
|
||||
Path string
|
||||
Reader io.Reader
|
||||
}
|
||||
|
||||
// Load loads the source into the config defined by struct s
|
||||
// Defaults to using the Reader if provided, otherwise tries to read from the
|
||||
// file
|
||||
func (t *TOMLLoader) Load(s interface{}) error {
|
||||
var r io.Reader
|
||||
|
||||
if t.Reader != nil {
|
||||
r = t.Reader
|
||||
} else if t.Path != "" {
|
||||
file, err := getConfig(t.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
r = file
|
||||
} else {
|
||||
return ErrSourceNotSet
|
||||
}
|
||||
|
||||
if _, err := toml.DecodeReader(r, s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// JSONLoader satisifies the loader interface. It loads the configuration from
|
||||
// the given json file or Reader.
|
||||
type JSONLoader struct {
|
||||
Path string
|
||||
Reader io.Reader
|
||||
}
|
||||
|
||||
// Load loads the source into the config defined by struct s.
|
||||
// Defaults to using the Reader if provided, otherwise tries to read from the
|
||||
// file
|
||||
func (j *JSONLoader) Load(s interface{}) error {
|
||||
var r io.Reader
|
||||
if j.Reader != nil {
|
||||
r = j.Reader
|
||||
} else if j.Path != "" {
|
||||
file, err := getConfig(j.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
r = file
|
||||
} else {
|
||||
return ErrSourceNotSet
|
||||
}
|
||||
|
||||
return json.NewDecoder(r).Decode(s)
|
||||
}
|
||||
|
||||
// YAMLLoader satisifies the loader interface. It loads the configuration from
|
||||
// the given yaml file.
|
||||
type YAMLLoader struct {
|
||||
Path string
|
||||
Reader io.Reader
|
||||
}
|
||||
|
||||
// Load loads the source into the config defined by struct s.
|
||||
// Defaults to using the Reader if provided, otherwise tries to read from the
|
||||
// file
|
||||
func (y *YAMLLoader) Load(s interface{}) error {
|
||||
var r io.Reader
|
||||
|
||||
if y.Reader != nil {
|
||||
r = y.Reader
|
||||
} else if y.Path != "" {
|
||||
file, err := getConfig(y.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
r = file
|
||||
} else {
|
||||
return ErrSourceNotSet
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return yaml.Unmarshal(data, s)
|
||||
}
|
||||
|
||||
func getConfig(path string) (*os.File, error) {
|
||||
pwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
configPath := path
|
||||
if !filepath.IsAbs(path) {
|
||||
configPath = filepath.Join(pwd, path)
|
||||
}
|
||||
|
||||
// check if file with combined path is exists(relative path)
|
||||
if _, err := os.Stat(configPath); !os.IsNotExist(err) {
|
||||
return os.Open(configPath)
|
||||
}
|
||||
|
||||
f, err := os.Open(path)
|
||||
if os.IsNotExist(err) {
|
||||
return nil, ErrFileNotFound
|
||||
}
|
||||
return f, err
|
||||
}
|
||||
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) }
|
||||
227
vendor/github.com/koding/multiconfig/multiconfig.go
generated
vendored
Normal file
227
vendor/github.com/koding/multiconfig/multiconfig.go
generated
vendored
Normal file
@@ -0,0 +1,227 @@
|
||||
package multiconfig
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/structs"
|
||||
)
|
||||
|
||||
// Loader loads the configuration from a source. The implementer of Loader is
|
||||
// responsible for setting the default values of the struct.
|
||||
type Loader interface {
|
||||
// Load loads the source into the config defined by struct s
|
||||
Load(s interface{}) error
|
||||
}
|
||||
|
||||
// DefaultLoader implements the Loader interface. It initializes the given
|
||||
// pointer of struct s with configuration from the default sources. The order
|
||||
// of load is TagLoader, FileLoader, EnvLoader and lastly FlagLoader. An error
|
||||
// in any step stops the loading process. Each step overrides the previous
|
||||
// step's config (i.e: defining a flag will override previous environment or
|
||||
// file config). To customize the order use the individual load functions.
|
||||
type DefaultLoader struct {
|
||||
Loader
|
||||
Validator
|
||||
}
|
||||
|
||||
// NewWithPath returns a new instance of Loader to read from the given
|
||||
// configuration file.
|
||||
func NewWithPath(path string) *DefaultLoader {
|
||||
loaders := []Loader{}
|
||||
|
||||
// Read default values defined via tag fields "default"
|
||||
loaders = append(loaders, &TagLoader{})
|
||||
|
||||
// Choose what while is passed
|
||||
if strings.HasSuffix(path, "toml") {
|
||||
loaders = append(loaders, &TOMLLoader{Path: path})
|
||||
}
|
||||
|
||||
if strings.HasSuffix(path, "json") {
|
||||
loaders = append(loaders, &JSONLoader{Path: path})
|
||||
}
|
||||
|
||||
if strings.HasSuffix(path, "yml") || strings.HasSuffix(path, "yaml") {
|
||||
loaders = append(loaders, &YAMLLoader{Path: path})
|
||||
}
|
||||
|
||||
e := &EnvironmentLoader{}
|
||||
f := &FlagLoader{}
|
||||
|
||||
loaders = append(loaders, e, f)
|
||||
loader := MultiLoader(loaders...)
|
||||
|
||||
d := &DefaultLoader{}
|
||||
d.Loader = loader
|
||||
d.Validator = MultiValidator(&RequiredValidator{})
|
||||
return d
|
||||
}
|
||||
|
||||
// New returns a new instance of DefaultLoader without any file loaders.
|
||||
func New() *DefaultLoader {
|
||||
loader := MultiLoader(
|
||||
&TagLoader{},
|
||||
&EnvironmentLoader{},
|
||||
&FlagLoader{},
|
||||
)
|
||||
|
||||
d := &DefaultLoader{}
|
||||
d.Loader = loader
|
||||
d.Validator = MultiValidator(&RequiredValidator{})
|
||||
return d
|
||||
}
|
||||
|
||||
// MustLoadWithPath loads with the DefaultLoader settings and from the given
|
||||
// Path. It exits if the config cannot be parsed.
|
||||
func MustLoadWithPath(path string, conf interface{}) {
|
||||
d := NewWithPath(path)
|
||||
d.MustLoad(conf)
|
||||
}
|
||||
|
||||
// MustLoad loads with the DefaultLoader settings. It exits if the config
|
||||
// cannot be parsed.
|
||||
func MustLoad(conf interface{}) {
|
||||
d := New()
|
||||
d.MustLoad(conf)
|
||||
}
|
||||
|
||||
// MustLoad is like Load but panics if the config cannot be parsed.
|
||||
func (d *DefaultLoader) MustLoad(conf interface{}) {
|
||||
if err := d.Load(conf); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
// we at koding, believe having sane defaults in our system, this is the
|
||||
// reason why we have default validators in DefaultLoader. But do not cause
|
||||
// nil pointer panics if one uses DefaultLoader directly.
|
||||
if d.Validator != nil {
|
||||
d.MustValidate(conf)
|
||||
}
|
||||
}
|
||||
|
||||
// MustValidate validates the struct. It exits with status 1 if it can't
|
||||
// validate.
|
||||
func (d *DefaultLoader) MustValidate(conf interface{}) {
|
||||
if err := d.Validate(conf); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(2)
|
||||
}
|
||||
}
|
||||
|
||||
// fieldSet sets field value from the given string value. It converts the
|
||||
// string value in a sane way and is usefulf or environment variables or flags
|
||||
// which are by nature in string types.
|
||||
func fieldSet(field *structs.Field, v string) error {
|
||||
switch f := field.Value().(type) {
|
||||
case flag.Value:
|
||||
if v := reflect.ValueOf(field.Value()); v.IsNil() {
|
||||
typ := v.Type()
|
||||
if typ.Kind() == reflect.Ptr {
|
||||
typ = typ.Elem()
|
||||
}
|
||||
|
||||
if err := field.Set(reflect.New(typ).Interface()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f = field.Value().(flag.Value)
|
||||
}
|
||||
|
||||
return f.Set(v)
|
||||
}
|
||||
|
||||
// TODO: add support for other types
|
||||
switch field.Kind() {
|
||||
case reflect.Bool:
|
||||
val, err := strconv.ParseBool(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := field.Set(val); err != nil {
|
||||
return err
|
||||
}
|
||||
case reflect.Int:
|
||||
i, err := strconv.Atoi(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := field.Set(i); err != nil {
|
||||
return err
|
||||
}
|
||||
case reflect.String:
|
||||
if err := field.Set(v); err != nil {
|
||||
return err
|
||||
}
|
||||
case reflect.Slice:
|
||||
switch t := field.Value().(type) {
|
||||
case []string:
|
||||
if err := field.Set(strings.Split(v, ",")); err != nil {
|
||||
return err
|
||||
}
|
||||
case []int:
|
||||
var list []int
|
||||
for _, in := range strings.Split(v, ",") {
|
||||
i, err := strconv.Atoi(in)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
list = append(list, i)
|
||||
}
|
||||
|
||||
if err := field.Set(list); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("multiconfig: field '%s' of type slice is unsupported: %s (%T)",
|
||||
field.Name(), field.Kind(), t)
|
||||
}
|
||||
case reflect.Float64:
|
||||
f, err := strconv.ParseFloat(v, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := field.Set(f); err != nil {
|
||||
return err
|
||||
}
|
||||
case reflect.Int64:
|
||||
switch t := field.Value().(type) {
|
||||
case time.Duration:
|
||||
d, err := time.ParseDuration(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := field.Set(d); err != nil {
|
||||
return err
|
||||
}
|
||||
case int64:
|
||||
p, err := strconv.ParseInt(v, 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := field.Set(p); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("multiconfig: field '%s' of type int64 is unsupported: %s (%T)",
|
||||
field.Name(), field.Kind(), t)
|
||||
}
|
||||
|
||||
default:
|
||||
return fmt.Errorf("multiconfig: field '%s' has unsupported type: %s", field.Name(), field.Kind())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
27
vendor/github.com/koding/multiconfig/multiloader.go
generated
vendored
Normal file
27
vendor/github.com/koding/multiconfig/multiloader.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
package multiconfig
|
||||
|
||||
type multiLoader []Loader
|
||||
|
||||
// MultiLoader creates a loader that executes the loaders one by one in order
|
||||
// and returns on the first error.
|
||||
func MultiLoader(loader ...Loader) Loader {
|
||||
return multiLoader(loader)
|
||||
}
|
||||
|
||||
// Load loads the source into the config defined by struct s
|
||||
func (m multiLoader) Load(s interface{}) error {
|
||||
for _, loader := range m {
|
||||
if err := loader.Load(s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MustLoad loads the source into the struct, it panics if gets any error
|
||||
func (m multiLoader) MustLoad(s interface{}) {
|
||||
if err := m.Load(s); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
28
vendor/github.com/koding/multiconfig/multivalidator.go
generated
vendored
Normal file
28
vendor/github.com/koding/multiconfig/multivalidator.go
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
package multiconfig
|
||||
|
||||
type multiValidator []Validator
|
||||
|
||||
// MultiValidator accepts variadic validators and satisfies Validator interface.
|
||||
func MultiValidator(validators ...Validator) Validator {
|
||||
return multiValidator(validators)
|
||||
}
|
||||
|
||||
// Validate tries to validate given struct with all the validators. If it doesn't
|
||||
// have any Validator it will simply skip the validation step. If any of the
|
||||
// given validators return err, it will stop validating and return it.
|
||||
func (d multiValidator) Validate(s interface{}) error {
|
||||
for _, validator := range d {
|
||||
if err := validator.Validate(s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MustValidate validates the struct, it panics if gets any error
|
||||
func (d multiValidator) MustValidate(s interface{}) {
|
||||
if err := d.Validate(s); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
60
vendor/github.com/koding/multiconfig/tag.go
generated
vendored
Normal file
60
vendor/github.com/koding/multiconfig/tag.go
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
package multiconfig
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/fatih/structs"
|
||||
)
|
||||
|
||||
// TagLoader satisfies the loader interface. It parses a struct's field tags
|
||||
// and populates the each field with that given tag.
|
||||
type TagLoader struct {
|
||||
// DefaultTagName is the default tag name for struct fields to define
|
||||
// default values for a field. Example:
|
||||
//
|
||||
// // Field's default value is "koding".
|
||||
// Name string `default:"koding"`
|
||||
//
|
||||
// The default value is "default" if it's not set explicitly.
|
||||
DefaultTagName string
|
||||
}
|
||||
|
||||
func (t *TagLoader) Load(s interface{}) error {
|
||||
if t.DefaultTagName == "" {
|
||||
t.DefaultTagName = "default"
|
||||
}
|
||||
|
||||
for _, field := range structs.Fields(s) {
|
||||
|
||||
if err := t.processField(t.DefaultTagName, field); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// processField gets tagName and the field, recursively checks if the field has the given
|
||||
// tag, if yes, sets it otherwise ignores
|
||||
func (t *TagLoader) processField(tagName string, field *structs.Field) error {
|
||||
switch field.Kind() {
|
||||
case reflect.Struct:
|
||||
for _, f := range field.Fields() {
|
||||
if err := t.processField(tagName, f); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
default:
|
||||
defaultVal := field.Tag(t.DefaultTagName)
|
||||
if defaultVal == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := fieldSet(field, defaultVal)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
73
vendor/github.com/koding/multiconfig/validator.go
generated
vendored
Normal file
73
vendor/github.com/koding/multiconfig/validator.go
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
package multiconfig
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/fatih/structs"
|
||||
)
|
||||
|
||||
// Validator validates the config against any predefined rules, those predefined
|
||||
// rules should be given to this package. The implementer will be responsible
|
||||
// for the logic.
|
||||
type Validator interface {
|
||||
// Validate validates the config struct
|
||||
Validate(s interface{}) error
|
||||
}
|
||||
|
||||
// RequiredValidator validates the struct against zero values.
|
||||
type RequiredValidator struct {
|
||||
// TagName holds the validator tag name. The default is "required"
|
||||
TagName string
|
||||
|
||||
// TagValue holds the expected value of the validator. The default is "true"
|
||||
TagValue string
|
||||
}
|
||||
|
||||
// Validate validates the given struct agaist field's zero values. If
|
||||
// intentionaly, the value of a field is `zero-valued`(e.g false, 0, "")
|
||||
// required tag should not be set for that field.
|
||||
func (e *RequiredValidator) Validate(s interface{}) error {
|
||||
if e.TagName == "" {
|
||||
e.TagName = "required"
|
||||
}
|
||||
|
||||
if e.TagValue == "" {
|
||||
e.TagValue = "true"
|
||||
}
|
||||
|
||||
for _, field := range structs.Fields(s) {
|
||||
if err := e.processField("", field); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *RequiredValidator) processField(fieldName string, field *structs.Field) error {
|
||||
fieldName += field.Name()
|
||||
switch field.Kind() {
|
||||
case reflect.Struct:
|
||||
// this is used for error messages below, when we have an error at the
|
||||
// child properties add parent properties into the error message as well
|
||||
fieldName += "."
|
||||
|
||||
for _, f := range field.Fields() {
|
||||
if err := e.processField(fieldName, f); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
default:
|
||||
val := field.Tag(e.TagName)
|
||||
if val != e.TagValue {
|
||||
return nil
|
||||
}
|
||||
|
||||
if field.IsZero() {
|
||||
return fmt.Errorf("multiconfig: field '%s' is required", fieldName)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user