Skip to content

Commit

Permalink
up: update the load data from env logic, update readme
Browse files Browse the repository at this point in the history
  • Loading branch information
inhere committed Oct 8, 2022
1 parent 2d283cf commit 5f2f89e
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 37 deletions.
27 changes: 23 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,19 +104,27 @@ func main() {
// fmt.Printf("config data: \n %#v\n", config.Data())
}
```
**Usage tips**:

- More extra options can be added using `WithOptions()`. For example: `ParseEnv`, `ParseDefault`
- You can use `AddDriver()` to add the required format driver (`json` is loaded by default, no need to add)
- The configuration data can then be loaded using `LoadFiles()` `LoadStrings()` etc.
- You can pass in multiple files or call multiple times
- Data loaded multiple times will be automatically merged by key

## Bind Structure

> Note: The default binding mapping tag of a structure is `mapstructure`, which can be changed by setting the decoder's option `options.DecoderConfig.TagName`
```go
user := struct {
type User struct {
Age int `mapstructure:"age"`
Key string `mapstructure:"key"`
UserName string `mapstructure:"user_name"`
Tags []int `mapstructure:"tags"`
}{}
}

user := User{}
err = config.BindStruct("user", &user)

fmt.Println(user.UserName) // inhere
Expand All @@ -128,6 +136,17 @@ fmt.Println(user.UserName) // inhere
config.WithOptions(func(opt *Options) {
options.DecoderConfig.TagName = "config"
})

// use custom tag name.
type User struct {
Age int `config:"age"`
Key string `config:"key"`
UserName string `config:"user_name"`
Tags []int `config:"tags"`
}

user := User{}
err = config.Decode(&user)
```

**Can bind all config data to a struct**:
Expand Down Expand Up @@ -228,7 +247,7 @@ config.Bool("debug") // true
```go
// os env: APP_NAME=config APP_DEBUG=true
// load ENV info
config.LoadOSEnv([]string{"APP_NAME", "APP_DEBUG"}, true)
config.LoadOSEnvs(map[string]string{"APP_NAME": "app_name", "APP_DEBUG": "app_debug"})

// read
config.Bool("app_debug") // true
Expand Down Expand Up @@ -378,7 +397,7 @@ Support parse default value by struct tag `default`

### Load Config

- `LoadOSEnv(keys []string)` Load from os ENV
- `LoadOSEnvs(nameToKeyMap map[string]string)` Load data from os ENV
- `LoadData(dataSource ...interface{}) (err error)` Load from struts or maps
- `LoadFlags(keys []string) (err error)` Load from CLI flags
- `LoadExists(sourceFiles ...string) (err error)`
Expand Down
53 changes: 37 additions & 16 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,17 +106,27 @@ func main() {
}
```

**使用提示**:

- 可以使用 `WithOptions()` 添加更多额外选项功能. 例如: `ParseEnv`, `ParseDefault`
- 可以使用 `AddDriver()` 添加需要使用的格式驱动器(`json` 是默认加载的的,无需添加)
- 然后就可以使用 `LoadFiles()` `LoadStrings()` 等方法加载配置数据
- 可以传入多个文件,也可以调用多次
- 多次加载的数据会自动按key进行合并处理

### 绑定数据到结构体

> 注意:结构体默认的绑定映射tag是 `mapstructure`,可以通过设置 `Options.TagName` 来更改它
```go
user := struct {
Age int
Kye string
UserName string `mapstructure:"user_name"`
Tags []int
}{}
type User struct {
Age int `mapstructure:"age"`
Key string `mapstructure:"key"`
UserName string `mapstructure:"user_name"`
Tags []int `mapstructure:"tags"`
}

user := User{}
err = config.BindStruct("user", &user)

fmt.Println(user.UserName) // inhere
Expand All @@ -126,8 +136,19 @@ fmt.Println(user.UserName) // inhere

```go
config.WithOptions(func(opt *Options) {
opt.TagName = "config"
options.DecoderConfig.TagName = "config"
})

// use custom tag name.
type User struct {
Age int `config:"age"`
Key string `config:"key"`
UserName string `config:"user_name"`
Tags []int `config:"tags"`
}

user := User{}
err = config.Decode(&user)
```

将所有配置数据绑定到结构:
Expand Down Expand Up @@ -192,7 +213,7 @@ fmt.Print(name) // new name
```go
// os env: APP_NAME=config APP_DEBUG=true
// load ENV info
config.LoadOSEnv([]string{"APP_NAME", "APP_NAME"}, true)
config.LoadOSEnvs(map[string]string{"APP_NAME": "app_name", "APP_DEBUG": "app_debug"})

// read
config.Bool("app_debug") // true
Expand All @@ -201,7 +222,7 @@ config.String("app_name") // "config"

## 从命令行参数载入数据

> 支持简单的命令行 `flag` 参数解析,加载数据
支持简单的从命令行 `flag` 参数解析,加载数据

```go
// flags like: --name inhere --env dev --age 99 --debug
Expand Down Expand Up @@ -239,13 +260,13 @@ myConf := config.NewWithOptions("my-conf", config.ParseEnv, config.ReadOnly)
在创建配置时添加钩子函数:

```go
hookFn := func(event string, c *Config) {
fmt.Println("fire the:", event)
}
hookFn := func(event string, c *Config) {
fmt.Println("fire the:", event)
}

c := NewWithOptions("test", WithHookFunc(hookFn))
// for global config
config.WithOptions(WithHookFunc(hookFn))
c := NewWithOptions("test", WithHookFunc(hookFn))
// for global config
config.WithOptions(WithHookFunc(hookFn))
```

之后, 当调用 `LoadXXX, Set, SetData, ClearData` 等方法时, 就会输出:
Expand Down Expand Up @@ -358,9 +379,9 @@ NEW: 支持通过结构标签 `default` 解析并设置默认值

### 载入配置

- `LoadOSEnv(keys []string)` 从ENV载入数据
- `LoadData(dataSource ...interface{}) (err error)` 从struct或map加载数据
- `LoadFlags(keys []string) (err error)` 从命令行参数载入数据
- `LoadOSEnvs(nameToKeyMap map[string]string)` 从ENV载入数据
- `LoadExists(sourceFiles ...string) (err error)` 从存在的配置文件里加载数据,会忽略不存在的文件
- `LoadFiles(sourceFiles ...string) (err error)` 从给定的配置文件里加载数据,有文件不存在则会panic
- `LoadRemote(format, url string) (err error)` 从远程 URL 加载配置数据
Expand Down
28 changes: 13 additions & 15 deletions hclv2/hcl_v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,23 @@ import (
"errors"

"github.com/gookit/config/v2"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/gohcl"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/hashicorp/hcl/v2/hclsimple"
)

// Decoder the hcl content decoder
var Decoder config.Decoder = func(blob []byte, v interface{}) (err error) {
// return hclsimple.Decode("hcl2/config.hcl", blob, nil, v)
file, diags := hclsyntax.ParseConfig(
blob,
"hcl2/config.hcl",
hcl.Pos{Line: 0, Column: 0},
)
// if diags.HasErrors() {
if len(diags) != 0 {
return diags
}

return gohcl.DecodeBody(file.Body, nil, v)
return hclsimple.Decode("hcl2/config.hcl", blob, nil, v)
// file, diags := hclsyntax.ParseConfig(
// blob,
// "hcl2/config.hcl",
// hcl.Pos{Line: 0, Column: 0},
// )
// // if diags.HasErrors() {
// if len(diags) != 0 {
// return diags
// }
//
// return gohcl.DecodeBody(file.Body, nil, v)
}

// Encoder the hcl content encoder
Expand Down
2 changes: 2 additions & 0 deletions hclv2/hcl_v2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
func TestDriver(t *testing.T) {
is := assert.New(t)
is.Equal("hcl", Driver.Name())
is.Equal(config.Hcl, Driver.Name())

c := config.NewEmpty("test")
is.False(c.HasDecoder(config.Hcl))
Expand All @@ -29,6 +30,7 @@ func TestLoadFile(t *testing.T) {
c.AddDriver(Driver)
is.True(c.HasDecoder(config.Hcl))

t.Skip("Not completed")
return
err := c.LoadFiles("../testdata/hcl2_base.hcl")
is.NoError(err)
Expand Down
25 changes: 23 additions & 2 deletions load.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,16 @@ func (c *Config) LoadRemote(format, url string) (err error) {
}

// LoadOSEnv load data from OS ENV
//
// Deprecated: please use LoadOSEnvs()
func LoadOSEnv(keys []string, keyToLower bool) { dc.LoadOSEnv(keys, keyToLower) }

// LoadOSEnv load data from os ENV
//
// Deprecated: please use Config.LoadOSEnvs()
func (c *Config) LoadOSEnv(keys []string, keyToLower bool) {
for _, key := range keys {
// NOTICE:
// if is windows os, os.Getenv() Key is not case-sensitive
// NOTICE: if is Windows os, os.Getenv() Key is not case-sensitive
val := os.Getenv(key)
if keyToLower {
key = strings.ToLower(key)
Expand All @@ -93,6 +96,24 @@ func (c *Config) LoadOSEnv(keys []string, keyToLower bool) {
c.fireHook(OnLoadData)
}

// LoadOSEnvs load data from OS ENVs. format: {ENV_NAME: config_key}
func LoadOSEnvs(nameToKeyMap map[string]string) { dc.LoadOSEnvs(nameToKeyMap) }

// LoadOSEnvs load data from os ENVs. format: {ENV_NAME: config_key}
func (c *Config) LoadOSEnvs(nameToKeyMap map[string]string) {
for name, key := range nameToKeyMap {
if val := os.Getenv(name); val != "" {
if key == "" {
key = strings.ToLower(name)
}

_ = c.Set(key, val)
}
}

c.fireHook(OnLoadData)
}

// support bound types for CLI flags vars
var validTypes = map[string]int{
"int": 1,
Expand Down
27 changes: 27 additions & 0 deletions load_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,3 +212,30 @@ func TestLoadOSEnv(t *testing.T) {

ClearAll()
}

func TestLoadOSEnvs(t *testing.T) {
ClearAll()

testutil.MockEnvValues(map[string]string{
"APP_NAME": "config",
"APP_DEBUG": "true",
"TEST_ENV0": "val0",
"TEST_ENV1": "val1",
}, func() {
assert.Equal(t, "", String("test_env0"))
assert.Equal(t, "val0", Getenv("TEST_ENV0"))

LoadOSEnvs(map[string]string{
"APP_NAME": "",
"APP_DEBUG": "app_debug",
"TEST_ENV0": "test0",
})

assert.True(t, Bool("app_debug"))
assert.Equal(t, "config", String("app_name"))
assert.Equal(t, "val0", String("test0"))
assert.Equal(t, "", String("test_env1"))
})

ClearAll()
}

0 comments on commit 5f2f89e

Please sign in to comment.