refactor: openpitrix module

Signed-off-by: hongming <talonwan@yunify.com>
This commit is contained in:
hongming
2019-09-25 14:07:15 +08:00
parent d0dc66cf28
commit 1b5681c12b
314 changed files with 72092 additions and 25762 deletions

25
vendor/github.com/koding/multiconfig/.gitignore generated vendored Normal file
View 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
View File

@@ -0,0 +1,4 @@
language: go
go: 1.3
script: go test ./...

21
vendor/github.com/koding/multiconfig/LICENSE generated vendored Normal file
View 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
View File

@@ -0,0 +1,92 @@
# Multiconfig [![GoDoc](https://godoc.org/github.com/koding/multiconfig?status.svg)](http://godoc.org/github.com/koding/multiconfig) [![Build Status](https://travis-ci.org/koding/multiconfig.svg?branch=master)](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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
}