Исправлены замечания линтера, обновлена зависимость yaml.v2 => yaml.v3
This commit is contained in:
parent
a50330fa13
commit
1979c8dce6
79
.gitignore
vendored
79
.gitignore
vendored
@ -1,49 +1,40 @@
|
|||||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
# ---> Go
|
||||||
*.o
|
# If you prefer the allow list template instead of the deny list, see community template:
|
||||||
*.a
|
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
|
||||||
*.so
|
#
|
||||||
*.swp
|
# Binaries for programs and plugins
|
||||||
main
|
|
||||||
|
|
||||||
# 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
|
*.exe
|
||||||
|
*.exe~
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
|
||||||
|
# Test binary, built with `go test -c`
|
||||||
*.test
|
*.test
|
||||||
*.prof
|
|
||||||
|
|
||||||
# OS generated files #
|
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||||
.DS_Store
|
*.out
|
||||||
.DS_Store?
|
|
||||||
._*
|
|
||||||
.Spotlight-V100
|
|
||||||
.Trashes
|
|
||||||
ehthumbs.db
|
|
||||||
Thumbs.db
|
|
||||||
|
|
||||||
# Eclipse generated files #
|
# Dependency directories (remove the comment below to include it)
|
||||||
.project
|
vendor/
|
||||||
.classpath
|
|
||||||
.settings
|
|
||||||
**/target/
|
|
||||||
*/bin/
|
|
||||||
.metadata/
|
|
||||||
clientdb.xml
|
|
||||||
# jazz files #
|
|
||||||
.jazzignore
|
|
||||||
.factorypath
|
|
||||||
.gitignore
|
|
||||||
|
|
||||||
|
# Go workspace file
|
||||||
|
go.work
|
||||||
|
|
||||||
|
# ---> VisualStudioCode
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
!.vscode/*.code-snippets
|
||||||
|
|
||||||
|
# Local History for Visual Studio Code
|
||||||
|
.history/
|
||||||
|
|
||||||
|
# Built Visual Studio Code Extensions
|
||||||
|
*.vsix
|
||||||
|
|
||||||
|
# Build outputs
|
||||||
|
tmp/
|
||||||
|
out/
|
||||||
|
6
.vscode/settings.json
vendored
Normal file
6
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"cSpell.words": [
|
||||||
|
"eschao",
|
||||||
|
"stretchr"
|
||||||
|
]
|
||||||
|
}
|
18
README.md
18
README.md
@ -4,7 +4,7 @@
|
|||||||
## Installation
|
## Installation
|
||||||
1. Install [Yaml](https://github.com/go-yaml/yaml) library first:
|
1. Install [Yaml](https://github.com/go-yaml/yaml) library first:
|
||||||
```
|
```
|
||||||
go get gopkg.in/yaml.v2
|
go get gopkg.in/yaml.v3
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Install **config** library:
|
2. Install **config** library:
|
||||||
@ -16,14 +16,14 @@ go get github.com/eschao/config
|
|||||||
### I. Define configuration name in structure tags
|
### I. Define configuration name in structure tags
|
||||||
Like JSON, Yaml, **config** uses tags to define configurations:
|
Like JSON, Yaml, **config** uses tags to define configurations:
|
||||||
|
|
||||||
| Tag | Example | Function |
|
| Tag | Example | Function |
|
||||||
|-----|---------|------|
|
| --------- | --------------------------------------- | --------------------------------------------------------------- |
|
||||||
| json | Host string `json:"host"` | Maps `Host` to a JSON field: **host** |
|
| json | Host string `json:"host"` | Maps `Host` to a JSON field: **host** |
|
||||||
| yaml | Host string `yaml:"host"` | Maps `Host` to a Yaml field: **host** |
|
| yaml | Host string `yaml:"host"` | Maps `Host` to a Yaml field: **host** |
|
||||||
| env | Host string `env:"HOST"` | Maps `Host` to a Environment variable: **HOST** |
|
| env | Host string `env:"HOST"` | Maps `Host` to a Environment variable: **HOST** |
|
||||||
| cli | Host string `cli:"host database host"` | Maps `Host` to a command line argument: **-host** or **--host** |
|
| cli | Host string `cli:"host database host"` | Maps `Host` to a command line argument: **-host** or **--host** |
|
||||||
| default | Port int `default:"8080"` | Defines the port with default value: **8080** |
|
| default | Port int `default:"8080"` | Defines the port with default value: **8080** |
|
||||||
| separator | Path string `json:"path" separator:";"` | Separator is used to split string to a slice |
|
| separator | Path string `json:"path" separator:";"` | Separator is used to split string to a slice |
|
||||||
|
|
||||||
|
|
||||||
#### 1. Data types
|
#### 1. Data types
|
||||||
|
104
cli/cli.go
104
cli/cli.go
@ -37,60 +37,60 @@ func newAnyValue(v reflect.Value) *anyValue {
|
|||||||
return &anyValue{any: v}
|
return &anyValue{any: v}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *anyValue) String() string {
|
func (v *anyValue) String() string {
|
||||||
kind := this.any.Kind()
|
kind := v.any.Kind()
|
||||||
switch kind {
|
switch kind {
|
||||||
case reflect.Bool:
|
case reflect.Bool:
|
||||||
return strconv.FormatBool(this.any.Bool())
|
return strconv.FormatBool(v.any.Bool())
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
return this.any.String()
|
return v.any.String()
|
||||||
case reflect.Int8,
|
case reflect.Int8,
|
||||||
reflect.Int16,
|
reflect.Int16,
|
||||||
reflect.Int,
|
reflect.Int,
|
||||||
reflect.Int32,
|
reflect.Int32,
|
||||||
reflect.Int64:
|
reflect.Int64:
|
||||||
return strconv.FormatInt(this.any.Int(), 10)
|
return strconv.FormatInt(v.any.Int(), 10)
|
||||||
case reflect.Uint8,
|
case reflect.Uint8,
|
||||||
reflect.Uint16,
|
reflect.Uint16,
|
||||||
reflect.Uint,
|
reflect.Uint,
|
||||||
reflect.Uint32,
|
reflect.Uint32,
|
||||||
reflect.Uint64:
|
reflect.Uint64:
|
||||||
return strconv.FormatUint(this.any.Uint(), 10)
|
return strconv.FormatUint(v.any.Uint(), 10)
|
||||||
case reflect.Float32:
|
case reflect.Float32:
|
||||||
return strconv.FormatFloat(this.any.Float(), 'E', -1, 32)
|
return strconv.FormatFloat(v.any.Float(), 'E', -1, 32)
|
||||||
case reflect.Float64:
|
case reflect.Float64:
|
||||||
return strconv.FormatFloat(this.any.Float(), 'E', -1, 64)
|
return strconv.FormatFloat(v.any.Float(), 'E', -1, 64)
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("unsupport type %s", kind.String())
|
return fmt.Sprintf("unsupported type: %s", kind.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *anyValue) Set(v string) error {
|
func (av *anyValue) Set(v string) error {
|
||||||
kind := this.any.Kind()
|
kind := av.any.Kind()
|
||||||
switch kind {
|
switch kind {
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
this.any.SetString(v)
|
av.any.SetString(v)
|
||||||
case reflect.Float32:
|
case reflect.Float32:
|
||||||
return utils.SetValueWithFloatX(this.any, v, 32)
|
return utils.SetValueWithFloatX(av.any, v, 32)
|
||||||
case reflect.Float64:
|
case reflect.Float64:
|
||||||
return utils.SetValueWithFloatX(this.any, v, 64)
|
return utils.SetValueWithFloatX(av.any, v, 64)
|
||||||
case reflect.Int8:
|
case reflect.Int8:
|
||||||
return utils.SetValueWithIntX(this.any, v, 8)
|
return utils.SetValueWithIntX(av.any, v, 8)
|
||||||
case reflect.Int16:
|
case reflect.Int16:
|
||||||
return utils.SetValueWithIntX(this.any, v, 16)
|
return utils.SetValueWithIntX(av.any, v, 16)
|
||||||
case reflect.Int, reflect.Int32:
|
case reflect.Int, reflect.Int32:
|
||||||
return utils.SetValueWithIntX(this.any, v, 32)
|
return utils.SetValueWithIntX(av.any, v, 32)
|
||||||
case reflect.Int64:
|
case reflect.Int64:
|
||||||
return utils.SetValueWithIntX(this.any, v, 64)
|
return utils.SetValueWithIntX(av.any, v, 64)
|
||||||
case reflect.Uint8:
|
case reflect.Uint8:
|
||||||
return utils.SetValueWithUintX(this.any, v, 8)
|
return utils.SetValueWithUintX(av.any, v, 8)
|
||||||
case reflect.Uint16:
|
case reflect.Uint16:
|
||||||
return utils.SetValueWithUintX(this.any, v, 16)
|
return utils.SetValueWithUintX(av.any, v, 16)
|
||||||
case reflect.Uint, reflect.Uint32:
|
case reflect.Uint, reflect.Uint32:
|
||||||
return utils.SetValueWithUintX(this.any, v, 32)
|
return utils.SetValueWithUintX(av.any, v, 32)
|
||||||
case reflect.Uint64:
|
case reflect.Uint64:
|
||||||
return utils.SetValueWithUintX(this.any, v, 64)
|
return utils.SetValueWithUintX(av.any, v, 64)
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("Can't support type %s", kind.String())
|
return fmt.Errorf("unsupported type: %s", kind.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -107,19 +107,19 @@ func newSliceValue(v reflect.Value, separator string) *sliceValue {
|
|||||||
return &sliceValue{value: v, separator: separator}
|
return &sliceValue{value: v, separator: separator}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *sliceValue) String() string {
|
func (sv *sliceValue) String() string {
|
||||||
return this.value.String()
|
return sv.value.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *sliceValue) Set(v string) error {
|
func (sv *sliceValue) Set(v string) error {
|
||||||
sp := this.separator
|
sp := sv.separator
|
||||||
if sp == "" {
|
if sp == "" {
|
||||||
sp = ":"
|
sp = ":"
|
||||||
}
|
}
|
||||||
return utils.SetValueWithSlice(this.value, v, sp)
|
return utils.SetValueWithSlice(sv.value, v, sp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// errorHanling is a global flag.ErrorHandling
|
// errorHandling is a global flag.ErrorHandling
|
||||||
var errorHandling = flag.ExitOnError
|
var errorHandling = flag.ExitOnError
|
||||||
|
|
||||||
// UsageFunc defines a callback function for printing command usage
|
// UsageFunc defines a callback function for printing command usage
|
||||||
@ -171,25 +171,25 @@ func NewWith(name string, errHandling flag.ErrorHandling,
|
|||||||
// Init analyzes the given structure interface, extracts cli definitions from
|
// Init analyzes the given structure interface, extracts cli definitions from
|
||||||
// its tag and installs command flagset by flag APIs. The interface must be a
|
// its tag and installs command flagset by flag APIs. The interface must be a
|
||||||
// structure pointer, otherwise will return an error
|
// structure pointer, otherwise will return an error
|
||||||
func (this *Command) Init(i interface{}) error {
|
func (c *Command) Init(i interface{}) error {
|
||||||
ptrRef := reflect.ValueOf(i)
|
ptrRef := reflect.ValueOf(i)
|
||||||
|
|
||||||
if ptrRef.IsNil() || ptrRef.Kind() != reflect.Ptr {
|
if ptrRef.IsNil() || ptrRef.Kind() != reflect.Ptr {
|
||||||
return fmt.Errorf("Expect a structure pointer type instead of %s",
|
return fmt.Errorf("expect a structure pointer type instead of %s",
|
||||||
ptrRef.Kind().String())
|
ptrRef.Kind().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
valueOfStruct := ptrRef.Elem()
|
valueOfStruct := ptrRef.Elem()
|
||||||
if valueOfStruct.Kind() != reflect.Struct {
|
if valueOfStruct.Kind() != reflect.Struct {
|
||||||
return fmt.Errorf("Expect a structure type instead of %s",
|
return fmt.Errorf("expect a structure type instead of %s",
|
||||||
valueOfStruct.Kind().String())
|
valueOfStruct.Kind().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.parseValue(valueOfStruct)
|
return c.parseValue(valueOfStruct)
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseValue parses a reflect.Value object and extracts cli definitions
|
// parseValue parses a reflect.Value object and extracts cli definitions
|
||||||
func (this *Command) parseValue(v reflect.Value) error {
|
func (c *Command) parseValue(v reflect.Value) error {
|
||||||
typeOfStruct := v.Type()
|
typeOfStruct := v.Type()
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
@ -200,14 +200,14 @@ func (this *Command) parseValue(v reflect.Value) error {
|
|||||||
|
|
||||||
if kindOfField == reflect.Ptr {
|
if kindOfField == reflect.Ptr {
|
||||||
if !valueOfField.IsNil() && valueOfField.CanSet() {
|
if !valueOfField.IsNil() && valueOfField.CanSet() {
|
||||||
cmd := this.createSubCommand(structOfField.Tag)
|
cmd := c.createSubCommand(structOfField.Tag)
|
||||||
err = cmd.Init(valueOfField.Interface())
|
err = cmd.Init(valueOfField.Interface())
|
||||||
}
|
}
|
||||||
} else if kindOfField == reflect.Struct {
|
} else if kindOfField == reflect.Struct {
|
||||||
cmd := this.createSubCommand(structOfField.Tag)
|
cmd := c.createSubCommand(structOfField.Tag)
|
||||||
err = cmd.parseValue(valueOfField)
|
err = cmd.parseValue(valueOfField)
|
||||||
} else {
|
} else {
|
||||||
err = this.addFlag(valueOfField, structOfField)
|
err = c.addFlag(valueOfField, structOfField)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,7 +215,7 @@ func (this *Command) parseValue(v reflect.Value) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// addFlag installs a command flag variable by flag API
|
// addFlag installs a command flag variable by flag API
|
||||||
func (this *Command) addFlag(v reflect.Value, f reflect.StructField) error {
|
func (c *Command) addFlag(v reflect.Value, f reflect.StructField) error {
|
||||||
cmdTag, ok := f.Tag.Lookup("cli")
|
cmdTag, ok := f.Tag.Lookup("cli")
|
||||||
if !ok || cmdTag == "" {
|
if !ok || cmdTag == "" {
|
||||||
return nil
|
return nil
|
||||||
@ -232,7 +232,7 @@ func (this *Command) addFlag(v reflect.Value, f reflect.StructField) error {
|
|||||||
kind := v.Kind()
|
kind := v.Kind()
|
||||||
switch kind {
|
switch kind {
|
||||||
case reflect.Bool:
|
case reflect.Bool:
|
||||||
this.FlagSet.BoolVar((*bool)(unsafe.Pointer(v.UnsafeAddr())), name,
|
c.FlagSet.BoolVar((*bool)(unsafe.Pointer(v.UnsafeAddr())), name,
|
||||||
false, usage)
|
false, usage)
|
||||||
return nil
|
return nil
|
||||||
case reflect.String,
|
case reflect.String,
|
||||||
@ -249,22 +249,22 @@ func (this *Command) addFlag(v reflect.Value, f reflect.StructField) error {
|
|||||||
reflect.Float32,
|
reflect.Float32,
|
||||||
reflect.Float64:
|
reflect.Float64:
|
||||||
anyValue := newAnyValue(v)
|
anyValue := newAnyValue(v)
|
||||||
this.FlagSet.Var(anyValue, name, usage)
|
c.FlagSet.Var(anyValue, name, usage)
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
sliceValue := newSliceValue(v, f.Tag.Get("separator"))
|
sliceValue := newSliceValue(v, f.Tag.Get("separator"))
|
||||||
this.FlagSet.Var(sliceValue, name, usage)
|
c.FlagSet.Var(sliceValue, name, usage)
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("Can't support type %s", kind.String())
|
return fmt.Errorf("unsupported type: %s", kind.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// createSubCommand creates sub-commands
|
// createSubCommand creates sub-commands
|
||||||
func (this *Command) createSubCommand(tag reflect.StructTag) *Command {
|
func (c *Command) createSubCommand(tag reflect.StructTag) *Command {
|
||||||
cmdTag, ok := tag.Lookup("cli")
|
cmdTag, ok := tag.Lookup("cli")
|
||||||
if !ok || cmdTag == "" {
|
if !ok || cmdTag == "" {
|
||||||
return this
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := Command{SubCommands: make(map[string]*Command)}
|
cmd := Command{SubCommands: make(map[string]*Command)}
|
||||||
@ -284,29 +284,29 @@ func (this *Command) createSubCommand(tag reflect.StructTag) *Command {
|
|||||||
cmd.FlagSet.Usage = usageHandler(&cmd)
|
cmd.FlagSet.Usage = usageHandler(&cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.SubCommands[name] = &cmd
|
c.SubCommands[name] = &cmd
|
||||||
return &cmd
|
return &cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse parses values from command line and save values into given structure.
|
// Parse parses values from command line and save values into given structure.
|
||||||
// The Init(interface{}) function must be called before parsing
|
// The Init(interface{}) function must be called before parsing
|
||||||
func (this *Command) Parse(args []string) error {
|
func (c *Command) Parse(args []string) error {
|
||||||
if err := this.FlagSet.Parse(args); err != nil {
|
if err := c.FlagSet.Parse(args); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
unprocessed := this.FlagSet.Args()
|
unprocessed := c.FlagSet.Args()
|
||||||
if len(unprocessed) < 1 {
|
if len(unprocessed) < 1 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if this.SubCommands == nil {
|
if c.SubCommands == nil {
|
||||||
return fmt.Errorf("Command: %s is unsupport", unprocessed[0])
|
return fmt.Errorf("unsupported command: %s", unprocessed[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := this.SubCommands[unprocessed[0]]
|
cmd := c.SubCommands[unprocessed[0]]
|
||||||
if cmd == nil {
|
if cmd == nil {
|
||||||
return fmt.Errorf("Command: %s is unsupport", unprocessed[0])
|
return fmt.Errorf("unsupported command: %s", unprocessed[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
return cmd.Parse(unprocessed[1:])
|
return cmd.Parse(unprocessed[1:])
|
||||||
|
@ -145,6 +145,7 @@ func TestVariousTypeCommand(t *testing.T) {
|
|||||||
typesConfig := test.TypesConfig{}
|
typesConfig := test.TypesConfig{}
|
||||||
cmd := NewWith("Types", flag.ContinueOnError, func(cmd *Command) func() {
|
cmd := NewWith("Types", flag.ContinueOnError, func(cmd *Command) func() {
|
||||||
return func() {
|
return func() {
|
||||||
|
// Stub
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
assert.NoError(cmd.Init(&typesConfig))
|
assert.NoError(cmd.Init(&typesConfig))
|
||||||
|
34
config.go
34
config.go
@ -27,7 +27,7 @@ import (
|
|||||||
"github.com/eschao/config/cli"
|
"github.com/eschao/config/cli"
|
||||||
"github.com/eschao/config/env"
|
"github.com/eschao/config/env"
|
||||||
"github.com/eschao/config/utils"
|
"github.com/eschao/config/utils"
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Default configuration file
|
// Default configuration file
|
||||||
@ -51,13 +51,13 @@ func ParseDefault(i interface{}) error {
|
|||||||
ptrRef := reflect.ValueOf(i)
|
ptrRef := reflect.ValueOf(i)
|
||||||
|
|
||||||
if ptrRef.IsNil() || ptrRef.Kind() != reflect.Ptr {
|
if ptrRef.IsNil() || ptrRef.Kind() != reflect.Ptr {
|
||||||
return fmt.Errorf("Expect a structure pointer type instead of %s",
|
return fmt.Errorf("expect a structure pointer type instead of %s",
|
||||||
ptrRef.Kind().String())
|
ptrRef.Kind().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
valueOfStruct := ptrRef.Elem()
|
valueOfStruct := ptrRef.Elem()
|
||||||
if valueOfStruct.Kind() != reflect.Struct {
|
if valueOfStruct.Kind() != reflect.Struct {
|
||||||
return fmt.Errorf("Expect a structure pointer type instead of %s",
|
return fmt.Errorf("expect a structure pointer type instead of %s",
|
||||||
valueOfStruct.Kind().String())
|
valueOfStruct.Kind().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,7 +121,7 @@ func parseValue(v reflect.Value) error {
|
|||||||
err = utils.SetValueWithSlice(valueOfField, defValue, sp)
|
err = utils.SetValueWithSlice(valueOfField, defValue, sp)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("Can't support type: %s", kind.String())
|
return fmt.Errorf("unsupported type: %s", kind.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,7 +153,7 @@ func ParseCli(i interface{}) error {
|
|||||||
// under the same folder with the fixed order: config.json, config.yaml and
|
// under the same folder with the fixed order: config.json, config.yaml and
|
||||||
// config.properties
|
// config.properties
|
||||||
func ParseConfig(i interface{}, configFlag string) error {
|
func ParseConfig(i interface{}, configFlag string) error {
|
||||||
configFile := flag.String(configFlag, "", "Specifiy configuration file")
|
configFile := flag.String(configFlag, "", "Specify configuration file")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
return ParseConfigFile(i, *configFile)
|
return ParseConfigFile(i, *configFile)
|
||||||
}
|
}
|
||||||
@ -176,23 +176,23 @@ func ParseConfigFile(i interface{}, configFile string) error {
|
|||||||
|
|
||||||
switch configType {
|
switch configType {
|
||||||
case JSONConfigType:
|
case JSONConfigType:
|
||||||
return parseJSON(i, configFile)
|
err = parseJSON(i, configFile)
|
||||||
case YamlConfigType:
|
case YamlConfigType:
|
||||||
return parseYaml(i, configFile)
|
err = parseYaml(i, configFile)
|
||||||
case PropConfigType:
|
case PropConfigType:
|
||||||
return parseProp(i, configFile)
|
err = parseProp(i, configFile)
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("Can't support config file: %s", configFile)
|
err = fmt.Errorf("unsupported config file: %s", configFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseJSON parses JSON file and set structure with its value
|
// parseJSON parses JSON file and set structure with its value
|
||||||
func parseJSON(i interface{}, jsonFile string) error {
|
func parseJSON(i interface{}, jsonFile string) error {
|
||||||
raw, err := ioutil.ReadFile(jsonFile)
|
raw, err := ioutil.ReadFile(jsonFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Can't open json config file. %s", err.Error())
|
return fmt.Errorf("open json config file: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
return json.Unmarshal(raw, i)
|
return json.Unmarshal(raw, i)
|
||||||
@ -202,15 +202,15 @@ func parseJSON(i interface{}, jsonFile string) error {
|
|||||||
func parseYaml(i interface{}, yamlFile string) error {
|
func parseYaml(i interface{}, yamlFile string) error {
|
||||||
raw, err := ioutil.ReadFile(yamlFile)
|
raw, err := ioutil.ReadFile(yamlFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Can't open yaml config file. %s", err.Error())
|
return fmt.Errorf("open yaml config file: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
return yaml.Unmarshal(raw, i)
|
return yaml.Unmarshal(raw, i)
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseProp parses Properties file and set structure with its value
|
// parseProp parses Properties file and set structure with its value
|
||||||
func parseProp(i interface{}, propFile string) error {
|
func parseProp(_ interface{}, _ /*propFile*/ string) error {
|
||||||
return fmt.Errorf("Properties config has not implemented!")
|
return fmt.Errorf("properties config is not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
// getDefaultConfigFile returns a existing default config file. The checking
|
// getDefaultConfigFile returns a existing default config file. The checking
|
||||||
@ -219,7 +219,7 @@ func parseProp(i interface{}, propFile string) error {
|
|||||||
func getDefaultConfigFile() (string, error) {
|
func getDefaultConfigFile() (string, error) {
|
||||||
exe, err := os.Executable()
|
exe, err := os.Executable()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("Can't find default config file. %s", err.Error())
|
return "", fmt.Errorf("find default config file: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
path := filepath.Dir(exe) + string(filepath.Separator)
|
path := filepath.Dir(exe) + string(filepath.Separator)
|
||||||
@ -242,7 +242,7 @@ func getDefaultConfigFile() (string, error) {
|
|||||||
return propConfig, nil
|
return propConfig, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", fmt.Errorf("No default config file found in path: %s", path)
|
return "", fmt.Errorf("default config file not found in path: %s", path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// getConfigFileType analyzes config file extension name and return
|
// getConfigFileType analyzes config file extension name and return
|
||||||
@ -257,5 +257,5 @@ func getConfigFileType(configFile string) (string, error) {
|
|||||||
return PropConfigType, nil
|
return PropConfigType, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", fmt.Errorf("Can't support file type: %s", configFile)
|
return "", fmt.Errorf("unsupported file type: %s", configFile)
|
||||||
}
|
}
|
||||||
|
32
env/env.go
vendored
32
env/env.go
vendored
@ -24,7 +24,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Parse parses given structure interface, extracts environment definitions
|
// Parse parses given structure interface, extracts environment definitions
|
||||||
// from its tag and sets structure with defined environement variables
|
// from its tag and sets structure with defined environment variables
|
||||||
func Parse(i interface{}) error {
|
func Parse(i interface{}) error {
|
||||||
return ParseWith(i, "")
|
return ParseWith(i, "")
|
||||||
}
|
}
|
||||||
@ -36,23 +36,24 @@ func Parse(i interface{}) error {
|
|||||||
// Host string `env:"HOST"`
|
// Host string `env:"HOST"`
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// type Server struct {
|
// type Server struct {
|
||||||
// Server string `env:"SERVER"`
|
// Server string `env:"SERVER"`
|
||||||
// DB Database `env:"DB_"`
|
// DB Database `env:"DB_"`
|
||||||
// }
|
// }
|
||||||
|
//
|
||||||
// The Server.DB.Host will be mapped to environment variable: DB_HOST which is
|
// The Server.DB.Host will be mapped to environment variable: DB_HOST which is
|
||||||
// concatenated from DB tag in Server struct and Host tag in Database struct
|
// concatenated from DB tag in Server struct and Host tag in Database struct
|
||||||
func ParseWith(i interface{}, prefix string) error {
|
func ParseWith(i interface{}, prefix string) error {
|
||||||
ptrRef := reflect.ValueOf(i)
|
ptrRef := reflect.ValueOf(i)
|
||||||
|
|
||||||
if ptrRef.IsNil() || ptrRef.Kind() != reflect.Ptr {
|
if ptrRef.IsNil() || ptrRef.Kind() != reflect.Ptr {
|
||||||
return fmt.Errorf("Expect a structure pointer type instead of %s",
|
return fmt.Errorf("expect a structure pointer type instead of %s",
|
||||||
ptrRef.Kind().String())
|
ptrRef.Kind().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
valueOfStruct := ptrRef.Elem()
|
valueOfStruct := ptrRef.Elem()
|
||||||
if valueOfStruct.Kind() != reflect.Struct {
|
if valueOfStruct.Kind() != reflect.Struct {
|
||||||
return fmt.Errorf("Expect a structure pointer type instead of %s",
|
return fmt.Errorf("expect a structure pointer type instead of %s",
|
||||||
valueOfStruct.Kind().String())
|
valueOfStruct.Kind().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,23 +81,16 @@ func parseValue(v reflect.Value, prefix string) error {
|
|||||||
err = parseValue(valueOfField, prefix+structOfField.Tag.Get("env"))
|
err = parseValue(valueOfField, prefix+structOfField.Tag.Get("env"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
err = setFieldValue(valueOfField, structOfField, prefix)
|
err = setFieldValue(valueOfField, structOfField, prefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// getEnvValue get environment value
|
|
||||||
func getEnvValue(envName string, f reflect.StructField) (string, bool) {
|
|
||||||
//fmt.Printf("Lookup ENV: %s\n", envName)
|
|
||||||
envValue, ok := os.LookupEnv(envName)
|
|
||||||
if !ok {
|
|
||||||
envValue, ok = f.Tag.Lookup("default")
|
|
||||||
}
|
|
||||||
|
|
||||||
return envValue, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// setFieldValue sets a reflect.Value with environment value
|
// setFieldValue sets a reflect.Value with environment value
|
||||||
func setFieldValue(v reflect.Value, f reflect.StructField, prefix string) error {
|
func setFieldValue(v reflect.Value, f reflect.StructField, prefix string) error {
|
||||||
envName := f.Tag.Get("env")
|
envName := f.Tag.Get("env")
|
||||||
@ -149,7 +143,7 @@ func setFieldValue(v reflect.Value, f reflect.StructField, prefix string) error
|
|||||||
err = utils.SetValueWithSlice(v, envValue, sp)
|
err = utils.SetValueWithSlice(v, envValue, sp)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("Can't support type: %s", kind.String())
|
return fmt.Errorf("unsupported type: %s", kind.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
14
go.mod
Normal file
14
go.mod
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
module git.mousesoft.ru/ms/config
|
||||||
|
|
||||||
|
go 1.23
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/eschao/config v0.1.0
|
||||||
|
github.com/stretchr/testify v1.9.0
|
||||||
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
)
|
17
go.sum
Normal file
17
go.sum
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/eschao/config v0.1.0 h1:vtlNamzs6dC9pE0zyplqql16PFUUlst3VttQ+IT2/rk=
|
||||||
|
github.com/eschao/config v0.1.0/go.mod h1:XMilcx0dPfk+tlJowGZPZdmdCRnd7AZuFhYA93tYBgA=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
Loading…
Reference in New Issue
Block a user