Skip to content

Commit

Permalink
update code format, update some logic for load ENV
Browse files Browse the repository at this point in the history
  • Loading branch information
inhere committed Aug 4, 2019
1 parent 73ca423 commit eec2ec4
Show file tree
Hide file tree
Showing 15 changed files with 147 additions and 130 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
@@ -1,7 +1,7 @@
language: go
dist: xenial
go:
# - '1.10' mod v2 is not support
# - '1.10' go mod v2 is not support
- '1.11'
- '1.12'

Expand All @@ -14,4 +14,4 @@ before_install:

script:
# - go test -v -cover
- $HOME/gopath/bin/goveralls -service=travis-ci
- $HOME/gopath/bin/goveralls -v -service=travis-ci
12 changes: 12 additions & 0 deletions README.md
Expand Up @@ -20,6 +20,7 @@ Golang application config manage tool library.
- Support for loading configuration data from remote URLs
- Support for setting configuration data from command line arguments(`flags`)
- Support data overlay and merge, automatically load by key when loading multiple copies of data
- Support for binding all or part of the configuration data to the structure
- Support get sub value by path, like `map.key` `arr.2`
- Support parse ENV name and allow with default value. like `envKey: ${SHELL|/bin/bash}` -> `envKey: /bin/zsh`
- Generic api `Get` `Int` `Uint` `Int64` `Float` `String` `Bool` `Ints` `IntMap` `Strings` `StringMap` ...
Expand Down Expand Up @@ -187,6 +188,17 @@ config.Bool("app_debug") // true
config.String("app_name") // "config"
```

## Bind data to structure

```go
user := struct {
Age int
Kye string
Tags []int
}{}
err = BindStruct("user", &user)
```

## API Methods Refer

### Load Config
Expand Down
17 changes: 15 additions & 2 deletions README.zh-CN.md
Expand Up @@ -6,7 +6,7 @@
[![Coverage Status](https://coveralls.io/repos/github/gookit/config/badge.svg?branch=master)](https://coveralls.io/github/gookit/config?branch=master)
[![Go Report Card](https://goreportcard.com/badge/github.com/gookit/config)](https://goreportcard.com/report/github.com/gookit/config)

功能完善的Golang应用程序配置管理工具库
简洁、功能完善的Golang应用程序配置管理工具库

> **[EN README](README.md)**
Expand All @@ -18,8 +18,9 @@
- 支持多个文件、多数据加载
- 支持从 OS ENV 变量数据加载配置
- 支持从远程 URL 加载配置数据
- 支持从命令行参数(flags)设置配置数据
- 支持从命令行参数(`flags`)设置配置数据
- 支持数据覆盖合并,加载多份数据时将按key自动合并
- 支持将全部或部分配置数据绑定到结构体 `config.BindStruct("key", &s)`
- 支持通过 `.` 分隔符来按路径获取子级值。 e.g `map.key` `arr.2`
- 支持解析ENV变量名称。 like `shell: ${SHELL}` -> `shell: /bin/zsh`
- 简洁的使用API `Get` `Int` `Uint` `Int64` `String` `Bool` `Ints` `IntMap` `Strings` `StringMap` ...
Expand Down Expand Up @@ -140,6 +141,17 @@ name = config.String("name")
fmt.Print(name) // new name
```

### 绑定数据到结构体

```go
user := struct {
Age int
Kye string
Tags []int
}{}
err = BindStruct("user", &user)
```

## API方法参考

### 载入配置
Expand Down Expand Up @@ -178,6 +190,7 @@ fmt.Print(name) // new name
- `Data() map[string]interface{}`
- `Exists(key string, findByPath ...bool) bool`
- `DumpTo(out io.Writer, format string) (n int64, err error)`
- `BindStruct(key string, dst interface{}) error`

## 单元测试

Expand Down
3 changes: 2 additions & 1 deletion config.go
Expand Up @@ -369,8 +369,9 @@ func GetEnv(name string, defVal ...string) (val string) {
}

// Getenv get os ENV value by name. like os.Getenv, but support default value
// Notice:
// - Key is not case sensitive when getting
func Getenv(name string, defVal ...string) (val string) {
// name = strings.ToUpper(name)
if val = os.Getenv(name); val != "" {
return
}
Expand Down
16 changes: 8 additions & 8 deletions config_test.go
Expand Up @@ -6,7 +6,7 @@ import (
"os"
"testing"

"github.com/gookit/config/v2/dotnev"
"github.com/gookit/goutil/testutil"
"github.com/stretchr/testify/assert"
)

Expand Down Expand Up @@ -171,14 +171,14 @@ func TestBasic(t *testing.T) {
}

func TestGetEnv(t *testing.T) {
_ = dotnev.LoadFromMap(map[string]string{
"app_name": "config",
"app_debug": "true",
testutil.MockEnvValues(map[string]string{
"APP_NAME": "config",
"APP_DEBUG": "true",
}, func() {
assert.Equal(t, "config", Getenv("APP_NAME"))
assert.Equal(t, "true", Getenv("APP_DEBUG"))
assert.Equal(t, "defVal", GetEnv("not-exsit", "defVal"))
})

assert.Equal(t, "config", Getenv("APP_NAME"))
assert.Equal(t, "true", Getenv("APP_DEBUG"))
assert.Equal(t, "defVal", GetEnv("not-exsit", "defVal"))
}

func TestSetDecoderEncoder(t *testing.T) {
Expand Down
4 changes: 2 additions & 2 deletions dotnev/dotenv.go
Expand Up @@ -36,15 +36,15 @@ func LoadedData() map[string]string {
// ClearLoaded clear the previously set ENV value
func ClearLoaded() {
for key := range loadedData {
_= os.Unsetenv(key)
_ = os.Unsetenv(key)
}

// reset
loadedData = map[string]string{}
}

// DontUpperEnvKey dont change key to upper on set ENV
func DontUpperEnvKey() {
func DontUpperEnvKey() {
UpperEnvKey = false
}

Expand Down
2 changes: 1 addition & 1 deletion dotnev/dotenv_test.go
Expand Up @@ -46,7 +46,7 @@ func TestLoadFromMap(t *testing.T) {
assert.Equal(t, "", os.Getenv("DONT_ENV_TEST"))

err := LoadFromMap(map[string]string{
"DONT_ENV_TEST": "blog",
"DONT_ENV_TEST": "blog",
"dont_env_test1": "val1",
"dont_env_test2": "23",
})
Expand Down
75 changes: 75 additions & 0 deletions export_test.go
Expand Up @@ -36,3 +36,78 @@ func TestExport(t *testing.T) {
_, err = c.DumpTo(buf, JSON)
at.Nil(err)
}

func TestConfig_Structure(t *testing.T) {
st := assert.New(t)

cfg := Default()
cfg.ClearAll()

err := cfg.LoadStrings(JSON, `{
"age": 28,
"name": "inhere",
"sports": ["pingPong", "跑步"]
}`)

st.Nil(err)

user := &struct {
Age int // always float64 from JSON
Name string
Sports []string
}{}
// map all data
err = MapStruct("", user)
st.Nil(err)

st.Equal(28, user.Age)
st.Equal("inhere", user.Name)
st.Equal("pingPong", user.Sports[0])

// map some data
err = cfg.LoadStrings(JSON, `{
"sec": {
"key": "val",
"age": 120,
"tags": [12, 34]
}
}`)
st.Nil(err)

some := struct {
Age int
Kye string
Tags []int
}{}
err = BindStruct("sec", &some)
st.Nil(err)
st.Equal(120, some.Age)
st.Equal(12, some.Tags[0])
cfg.ClearAll()

// custom data
cfg = New("test")
err = cfg.LoadData(map[string]interface{}{
"key": "val",
"age": 120,
"tags": []int{12, 34},
})
st.NoError(err)

s1 := struct {
Age int
Kye string
Tags []int
}{}
err = cfg.BindStruct("", &s1)
st.Nil(err)
st.Equal(120, s1.Age)
st.Equal(12, s1.Tags[0])

// key not exist
err = cfg.BindStruct("not-exist", &s1)
st.Error(err)
st.Equal("this key does not exist in the config", err.Error())

cfg.ClearAll()
}
1 change: 1 addition & 0 deletions go.mod
Expand Up @@ -10,6 +10,7 @@ require (
github.com/imdario/mergo v0.3.7
github.com/json-iterator/go v1.1.7
github.com/kr/pretty v0.1.0 // indirect
github.com/mitchellh/mapstructure v1.1.2
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/stretchr/testify v1.3.0
Expand Down
6 changes: 3 additions & 3 deletions json_driver.go
Expand Up @@ -32,17 +32,17 @@ type jsonDriver struct {
ClearComments bool
}

// Name
// Name of the driver
func (d *jsonDriver) Name() string {
return d.name
}

// GetDecoder for json
// GetDecoder for the driver
func (d *jsonDriver) GetDecoder() Decoder {
return JSONDecoder
}

// GetEncoder for json
// GetEncoder for the driver
func (d *jsonDriver) GetEncoder() Encoder {
return JSONEncoder
}
12 changes: 4 additions & 8 deletions load.go
Expand Up @@ -74,17 +74,13 @@ func (c *Config) LoadRemote(format, url string) (err error) {
}

// LoadOSEnv load data from OS ENV
func LoadOSEnv(keys []string, upKeyOnGetenv bool) { dc.LoadOSEnv(keys, upKeyOnGetenv) }
func LoadOSEnv(keys []string) { dc.LoadOSEnv(keys) }

// LoadOSEnv load data from os ENV
func (c *Config) LoadOSEnv(keys []string, upKeyOnGetenv bool) {
func (c *Config) LoadOSEnv(keys []string) {
for _, key := range keys {
envKey := key
if upKeyOnGetenv {
envKey = strings.ToUpper(key)
}

val := os.Getenv(envKey)
// os.Getenv() Key is not case sensitive
val := os.Getenv(key)
_ = c.Set(key, val)
}
}
Expand Down
20 changes: 13 additions & 7 deletions load_test.go
Expand Up @@ -5,7 +5,7 @@ import (
"runtime"
"testing"

"github.com/gookit/config/v2/dotnev"
"github.com/gookit/goutil/testutil"
"github.com/stretchr/testify/assert"
)

Expand Down Expand Up @@ -180,14 +180,20 @@ func TestLoadFlags(t *testing.T) {
func TestLoadOSEnv(t *testing.T) {
ClearAll()

_ = dotnev.LoadFromMap(map[string]string{
"app_name": "config",
testutil.MockEnvValues(map[string]string{
"APP_NAME": "config",
"app_debug": "true",
"test_env0": "val0",
"TEST_ENV1": "val1",
}, func() {
assert.Equal(t, "", String("test_env0"))

LoadOSEnv([]string{"app_name", "app_debug", "test_env0"})
assert.True(t, Bool("app_debug"))
assert.Equal(t, "config", String("app_name"))
assert.Equal(t, "val0", String("test_env0"))
assert.Equal(t, "", String("test_env1"))
})

LoadOSEnv([]string{"app_name", "app_debug"})
assert.True(t, Bool("app_debug"))
assert.Equal(t, "config", String("app_name"))

ClearAll()
}
44 changes: 2 additions & 42 deletions read.go
Expand Up @@ -11,7 +11,7 @@ import (

var (
errInvalidKey = errors.New("invalid config key string")
// errNotFound = errors.New("this key does not exist in the configuration data")
errNotFound = errors.New("this key does not exist in the config")
)

// Exists key exists check
Expand Down Expand Up @@ -531,7 +531,7 @@ func (c *Config) StringMap(key string) (mp map[string]string) {
for k, v := range typeData {
mp[k] = fmt.Sprintf("%v", v)
}
case map[interface{}]interface{}: // if decode from yaml
case map[interface{}]interface{}: // decode from yaml
mp = make(map[string]string)
for k, v := range typeData {
sk := fmt.Sprintf("%v", k)
Expand All @@ -551,43 +551,3 @@ func (c *Config) StringMap(key string) (mp map[string]string) {
}
return
}

// MapStruct alias method of the 'Structure'
func MapStruct(key string, v interface{}) error { return dc.Structure(key, v) }

// MapStruct alias method of the 'Structure'
func (c *Config) MapStruct(key string, v interface{}) (err error) {
return c.Structure(key, v)
}

// Structure get config data and map to a structure.
// usage:
// dbInfo := Db{}
// config.Structure("db", &dbInfo)
func (c *Config) Structure(key string, v interface{}) (err error) {
var ok bool
var data interface{}

// map all data
if key == "" {
ok = true
data = c.data
} else {
data, ok = c.GetValue(key)
}

if ok {
blob, err := JSONEncoder(data)
if err != nil {
return err
}

err = JSONDecoder(blob, v)
}
return
}

// format key
func formatKey(key string) string {
return strings.Trim(strings.TrimSpace(key), ".")
}

0 comments on commit eec2ec4

Please sign in to comment.