Research
Security News
Malicious npm Package Targets Solana Developers and Hijacks Funds
A malicious npm package targets Solana developers, rerouting funds in 2% of transactions to a hardcoded address.
github.com/gookit/config/v2
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.ParseEnv: will parse env var in string value. eg: shell: ${SHELL}
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 https://github.com/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 in string 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
// 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
}
Examples for set options:
config.WithOptions(config.WithTagName("mytag"))
config.WithOptions(func(opt *Options) {
opt.SetTagNames("config")
})
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 https://github.com/gookit/config :
MIT
FAQs
Unknown package
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
A malicious npm package targets Solana developers, rerouting funds in 2% of transactions to a hardcoded address.
Security News
Research
Socket researchers have discovered malicious npm packages targeting crypto developers, stealing credentials and wallet data using spyware delivered through typosquats of popular cryptographic libraries.
Security News
Socket's package search now displays weekly downloads for npm packages, helping developers quickly assess popularity and make more informed decisions.