diff --git a/README.md b/README.md index b38e4f8..49a3b59 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,9 @@ golang application config manage tool library. - support multi format: `JSON`(default), `INI`, `YAML`, `TOML`, `HCL` - `JSON` content support comments. will auto clear comments - support multi file/data load -- support data override merge +- support for loading configuration data from remote URLs +- support for setting configuration data from command line arguments +- support data overlay and merge, automatically load by key when loading multiple copies of data - support get sub value by path, like `map.key` `arr.2` - support parse ENV name. like `envKey: ${SHELL}` -> `envKey: /bin/zsh` - generic api `Get` `Int` `String` `Bool` `Ints` `IntMap` `Strings` `StringMap` ... @@ -154,8 +156,10 @@ fmt.Print(ok, name) // true "new name" ### Load Config - `LoadData(dataSource ...interface{}) (err error)` +- `LoadFlags(keys []string) (err error)` - `LoadExists(sourceFiles ...string) (err error)` - `LoadFiles(sourceFiles ...string) (err error)` +- `LoadRemote(format, url string) (err error)` - `LoadSources(format string, src []byte, more ...[]byte) (err error)` - `LoadStrings(format string, str string, more ...string) (err error)` diff --git a/README_cn.md b/README_cn.md index 0f830aa..b7f9c75 100644 --- a/README_cn.md +++ b/README_cn.md @@ -12,7 +12,9 @@ golang应用程序配置管理工具库。 - 支持多种格式: `JSON`(default), `INI`, `YAML`, `TOML`, `HCL` - `JSON` 内容支持注释,将自动清除注释 - 支持多个文件/数据加载 -- 支持数据覆盖合并,将按key自动合并 +- 支持数据覆盖合并,加载多份数据时将按key自动合并 +- 支持从远程URL加载配置数据 +- 支持从命令行参数设置配置数据 - 支持按路径获取子级值。 e.g `map.key` `arr.2` - 支持解析ENV变量名称。 like `shell: ${SHELL}` -> `shell: /bin/zsh` - 简洁的使用API `Get` `Int` `String` `Bool` `Ints` `IntMap` `Strings` `StringMap` ... @@ -155,8 +157,10 @@ fmt.Print(ok, name) // true "new name" ### 载入配置 - `LoadData(dataSource ...interface{}) (err error)` +- `LoadFlags(keys []string) (err error)` - `LoadExists(sourceFiles ...string) (err error)` - `LoadFiles(sourceFiles ...string) (err error)` +- `LoadRemote(format, url string) (err error)` - `LoadSources(format string, src []byte, more ...[]byte) (err error)` - `LoadStrings(format string, str string, more ...string) (err error)` diff --git a/config_get_test.go b/config_get_test.go index c97718a..40f7aa8 100644 --- a/config_get_test.go +++ b/config_get_test.go @@ -124,7 +124,8 @@ func TestGet(t *testing.T) { st.Equal("", str) // get float - c.Set("flVal", 23.45) + err = c.Set("flVal", 23.45) + st.Nil(err) flt, ok := c.Float("flVal") st.True(ok) st.Equal(23.45, flt) @@ -196,7 +197,8 @@ func TestGet(t *testing.T) { st.False(ok) // set a intMap - Set("intMap0", map[string]int{"a": 1, "b": 2}) + err = Set("intMap0", map[string]int{"a": 1, "b": 2}) + st.Nil(err) imp, ok = IntMap("intMap0") st.True(ok) st.NotEmpty(imp) diff --git a/config_load.go b/config_load.go index 6fa911a..e752d81 100644 --- a/config_load.go +++ b/config_load.go @@ -2,6 +2,7 @@ package config import ( "errors" + "flag" "fmt" "github.com/imdario/mergo" "io/ioutil" @@ -99,6 +100,36 @@ func (c *Config) LoadRemote(format, url string) (err error) { return } +// LoadFlags parse command line arguments, based on provide keys. +// Usage: +// c.LoadFlags([]string{"env", "debug"}) +func (c *Config) LoadFlags(keys []string) (err error) { + hash := map[string]*string{} + for _, key := range keys { + hash[key] = new(string) + defVal, _ := c.String(key) + flag.StringVar(hash[key], key, defVal, "") + } + + flag.Parse() + flag.Visit(func(f *flag.Flag) { + name := f.Name + // name := strings.Replace(f.Name, "-", ".", -1) + + // only get name in the keys. + if _, ok := hash[name]; !ok { + return + } + + err = c.Set(name, f.Value.String()) + if err != nil { + return + } + }) + + return +} + // LoadData load data from map OR struct func (c *Config) LoadData(dataSources ...interface{}) (err error) { for _, ds := range dataSources { diff --git a/config_test.go b/config_test.go index 64a47ce..53babe1 100644 --- a/config_test.go +++ b/config_test.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "github.com/stretchr/testify/assert" + "os" "testing" ) @@ -53,7 +54,10 @@ func Example() { } // load from string - LoadSources(JSON, []byte(jsonStr)) + err = LoadSources(JSON, []byte(jsonStr)) + if err != nil { + panic(err) + } // fmt.Printf("config data: \n %#v\n", Data()) fmt.Print("get config example:\n") @@ -274,6 +278,30 @@ func TestConfig_LoadRemote(t *testing.T) { is.Error(err) } +func TestConfig_LoadFlags(t *testing.T) { + is := assert.New(t) + + // load flag info + c := New("flag") + bakArgs := os.Args + os.Args = []string{ + "./cliapp", + "--name", "my-app", + "--env", "dev", + "--debug", "true", + } + + err := c.LoadFlags([]string{"name", "env", "debug"}) + is.Nil(err) + is.Equal("my-app", c.DefString("name", "")) + is.Equal("dev", c.DefString("env", "")) + is.True(c.DefBool("debug", false)) + + fmt.Printf("%#v\n",c.Data()) + + os.Args = bakArgs +} + func TestJSONDriver(t *testing.T) { st := assert.New(t) @@ -322,7 +350,11 @@ func TestOptions(t *testing.T) { err := c.LoadStrings(JSON, jsonStr) st.Nil(err) - str, ok := c.String("envKey") + str, ok := c.String("name") + st.True(ok) + st.Equal("app", str) + + str, ok = c.String("envKey") st.True(ok) st.NotContains(str, "${") @@ -371,6 +403,9 @@ func TestExport(t *testing.T) { _, err = c.DumpTo(buf, "invalid") at.Error(err) + _, err = c.DumpTo(buf, Yml) + at.Error(err) + _, err = c.DumpTo(buf, JSON) at.Nil(err) }