Project Name | Stars | Downloads | Repos Using This | Packages Using This | Most Recent Commit | Total Releases | Latest Release | Open Issues | License | Language |
---|---|---|---|---|---|---|---|---|---|---|
Config | 464 | 18 | a day ago | 59 | October 16, 2022 | 6 | mit | Go | ||
📝 Go configuration manage(load,get,set,export). support JSON, YAML, TOML, Properties, INI, HCL, ENV and Flags. Multi file load, data override merge, parse ENV var. Go应用配置加载管理,支持多种格式,多文件加载,远程文件加载,支持数据合并,解析环境变量名 | ||||||||||
Aconfig | 436 | 16 | a month ago | 65 | October 15, 2022 | 11 | mit | Go | ||
Simple, useful and opinionated config loader. | ||||||||||
Kong Hcl | 3 | 2 years ago | 3 | mit | Go | |||||
config
- Simple, full-featured Go application configuration management tool library.
JSON
(default), JSON5
, INI
, Properties
, YAML
, TOML
, HCL
, ENV
, Flags
JSON
content support comments. will auto clear commentsflags
)set.value
, set.data
, load.data
, clean.data
, reload.data
default:"def_value"
default:"${APP_ENV | dev}"
map.key
arr.2
envKey: ${SHELL|/bin/bash}
-> envKey: /bin/zsh
Get
Int
Uint
Int64
Float
String
Bool
Ints
IntMap
Strings
StringMap
...If you just want to use INI for simple config management, recommended use gookit/ini
On gookit/ini
: Provide a sub-package dotenv
that supports importing data from files (eg .env
) to ENV
go get github.com/gookit/ini/v2/dotenv
go get github.com/gookit/config/v2
Here using the yaml format as an example(testdata/yml_other.yml
):
name: app2
debug: false
baseKey: value2
shell: ${SHELL}
envKey1: ${NotExist|defValue}
map1:
key: val2
key2: val20
arr1:
- val1
- val21
examples code please see _examples/yaml.go:
package main
import (
"github.com/gookit/config/v2"
"github.com/gookit/config/v2/yaml"
)
// go run ./examples/yaml.go
func main() {
config.WithOptions(config.ParseEnv)
// add driver for support yaml content
config.AddDriver(yaml.Driver)
err := config.LoadFiles("testdata/yml_base.yml")
if err != nil {
panic(err)
}
// load more files
err = config.LoadFiles("testdata/yml_other.yml")
// can also load multi at once
// err := config.LoadFiles("testdata/yml_base.yml", "testdata/yml_other.yml")
if err != nil {
panic(err)
}
// fmt.Printf("config data: \n %#v\n", config.Data())
}
Usage tips:
WithOptions()
. For example: ParseEnv
, ParseDefault
AddDriver()
to add the required format driver (json
is loaded by default, no need to add)LoadFiles()
LoadStrings()
etc.
Note: The default binding mapping tag of a structure is
mapstructure
, which can be changed by setting the decoder's optionoptions.DecoderConfig.TagName
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
Change struct tag name
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:
config.Decode(&myConf)
// can also
config.BindStruct("", &myConf)
config.MapOnExists
likeBindStruct
,but map binding only if key exists
age := config.Int("age")
fmt.Print(age) // 100
val := config.Bool("debug")
fmt.Print(val) // true
name := config.String("name")
fmt.Print(name) // inhere
arr1 := config.Strings("arr1")
fmt.Printf("%#v", arr1) // []string{"val1", "val21"}
val := config.StringMap("map1")
fmt.Printf("%#v",val) // map[string]string{"key":"val2", "key2":"val20"}
value := config.String("shell")
fmt.Print(value) // "/bin/zsh"
// from array
value := config.String("arr1.0")
fmt.Print(value) // "val1"
// from map
value := config.String("map1.key")
fmt.Print(value) // "val2"
// set value
config.Set("name", "new name")
name = config.String("name")
fmt.Print(name) // "new name"
Support simple flags parameter parsing, loading
// flags like: --name inhere --env dev --age 99 --debug
// load flag info
keys := []string{"name", "env", "age:int" "debug:bool"}
err := config.LoadFlags(keys)
// read
config.String("name") // "inhere"
config.String("env") // "dev"
config.Int("age") // 99
config.Bool("debug") // true
// os env: APP_NAME=config APP_DEBUG=true
// load ENV info
config.LoadOSEnvs(map[string]string{"APP_NAME": "app_name", "APP_DEBUG": "app_debug"})
// read
config.Bool("app_debug") // true
config.String("app_name") // "config"
You can create custom config instance
// create new instance, will auto register JSON driver
myConf := config.New("my-conf")
// create empty instance
myConf := config.NewEmpty("my-conf")
// create and with some options
myConf := config.NewWithOptions("my-conf", config.ParseEnv, config.ReadOnly)
Now, you can add a hook func for listen config data change. then, you can do something like: write data to file
Add hook func on create config:
hookFn := func(event string, c *Config) {
fmt.Println("fire the:", event)
}
c := NewWithOptions("test", config.WithHookFunc(hookFn))
// for global config
config.WithOptions(config.WithHookFunc(hookFn))
After that, when calling LoadXXX, Set, SetData, ClearData
methods, it will output:
fire the: load.data
fire the: set.value
fire the: set.data
fire the: clean.data
To listen for changes to loaded config files, and reload the config when it changes, you need to use the fsnotify/fsnotify library. For usage, please refer to the example ./_example/watch_file.go
Also, you need to listen to the reload.data
event:
config.WithOptions(config.WithHookFunc(func(event string, c *config.Config) {
if event == config.OnReloadData {
fmt.Println("config reloaded, you can do something ....")
}
}))
When the configuration changes, you can do related things, for example: rebind the configuration to your struct.
Can use
config.DumpTo()
export the configuration data to the specifiedwriter
, such as: buffer,file
Dump to JSON file
buf := new(bytes.Buffer)
_, err := config.DumpTo(buf, config.JSON)
ioutil.WriteFile("my-config.json", buf.Bytes(), 0755)
Dump pretty JSON
You can set the default var JSONMarshalIndent
or custom a new JSON driver.
config.JSONMarshalIndent = " "
Dump to YAML file
_, err := config.DumpTo(buf, config.YAML)
ioutil.WriteFile("my-config.yaml", buf.Bytes(), 0755)
// Options config options
type Options struct {
// parse env value. like: "${EnvName}" "${EnvName|default}"
ParseEnv bool
// ParseTime parses a duration string to time.Duration
// eg: 10s, 2m
ParseTime bool
// config is readonly. default is False
Readonly bool
// enable config data cache. default is False
EnableCache bool
// parse key, allow find value by key path. default is True eg: 'key.sub' will find `map[key]sub`
ParseKey bool
// tag name for binding data to struct
// Deprecated
// please set tag name by DecoderConfig
TagName string
// the delimiter char for split key path, if `FindByPath=true`. default is '.'
Delimiter byte
// default write format
DumpFormat string
// default input format
ReadFormat string
// DecoderConfig setting for binding data to struct
DecoderConfig *mapstructure.DecoderConfig
// HookFunc on data changed.
HookFunc HookFunc
// ParseDefault tag on binding data to struct. tag: default
ParseDefault bool
}
Support parse default value by struct tag default
// add option: config.ParseDefault
c := config.New("test").WithOptions(config.ParseDefault)
// only set name
c.SetData(map[string]any{
"name": "inhere",
})
// age load from default tag
type User struct {
Age int `default:"30"`
Name string
Tags []int
}
user := &User{}
goutil.MustOk(c.Decode(user))
dump.Println(user)
Output:
&config_test.User {
Age: int(30),
Name: string("inhere"), #len=6
Tags: []int [ #len=0
],
},
LoadOSEnvs(nameToKeyMap map[string]string)
Load data from os ENVLoadData(dataSource ...any) (err error)
Load from struts or mapsLoadFlags(keys []string) (err error)
Load from CLI flagsLoadExists(sourceFiles ...string) (err error)
LoadFiles(sourceFiles ...string) (err error)
LoadFromDir(dirPath, format string) (err error)
Load custom format files from the given directory, the file name will be used as the keyLoadRemote(format, url string) (err error)
LoadSources(format string, src []byte, more ...[]byte) (err error)
LoadStrings(format string, str string, more ...string) (err error)
LoadFilesByFormat(format string, sourceFiles ...string) (err error)
LoadExistsByFormat(format string, sourceFiles ...string) error
Bool(key string, defVal ...bool) bool
Int(key string, defVal ...int) int
Uint(key string, defVal ...uint) uint
Int64(key string, defVal ...int64) int64
Ints(key string) (arr []int)
IntMap(key string) (mp map[string]int)
Float(key string, defVal ...float64) float64
String(key string, defVal ...string) string
Strings(key string) (arr []string)
SubDataMap(key string) maputi.Data
StringMap(key string) (mp map[string]string)
Get(key string, findByPath ...bool) (value any)
Mapping data to struct:
Decode(dst any) error
BindStruct(key string, dst any) error
MapOnExists(key string, dst any) error
Set(key string, val any, setByPath ...bool) (err error)
Getenv(name string, defVal ...string) (val string)
AddDriver(driver Driver)
Data() map[string]any
SetData(data map[string]any)
set data to override the Config.DataExists(key string, findByPath ...bool) bool
DumpTo(out io.Writer, format string) (n int64, err error)
go test -cover
// contains all sub-folder
go test -cover ./...
Check out these projects, which use gookit/config :
MIT