Yet another configuration library for Go.
This library parses command line flags, environment variables, and configuration files (yaml) into a struct.
With the go's default flag package there is only the possibility to define "flat" flags: there is no possibility to define dynamic structures.
This library tackle that issue. They can parse arguments like this:
$> myApp --map[key]=value --entry[0].key=key1 --entry[0].value=val1
The "key-mechanic" is converting command line arguments to yaml-content and then use yaml parser to parse the content into a struct. Therefore, you have to use the yaml-tags for defining the key names.
package main
import (
"github.com/rainu/go-yacl"
)
type MyConfig struct {
Help bool `yaml:"help" short:"h" usage:"Show help"`
Map map[string]string `yaml:"map"`
Entries []struct{
Key string `yaml:"key"`
Value string `yaml:"value"`
} `yaml:"entry"`
}
func main() {
c := MyConfig{}
config := yacl.NewConfig(&c)
err := config.ParseArguments("--help")
if err != nil {
panic(err)
}
if c.Help {
println(config.HelpFlags())
return
}
}package main
import (
"github.com/rainu/go-yacl"
)
type MyConfig struct {
Help bool `yaml:"help" short:"h" usage:"Show help"`
}
func main() {
c := MyConfig{}
config := yacl.NewConfig(&c)
err := config.ParseEnvironment("CFG_0=--help")
if err != nil {
panic(err)
}
if c.Help {
println(config.HelpFlags())
return
}
}package main
import (
"github.com/rainu/go-yacl"
"os"
)
type MyConfig struct {
Help bool `yaml:"help" short:"h" usage:"Show help"`
}
func main() {
c := MyConfig{}
config := yacl.NewConfig(&c)
yamlFile, err := os.Open("/path/to/config.yaml")
if err != nil {
panic(err)
}
defer yamlFile.Close()
err = config.ParseYaml(yamlFile)
if err != nil {
panic(err)
}
if c.Help {
println(config.HelpFlags())
return
}
}For applying default values you have to define a function which is responsible for setting those values. Attention: This function will be called after the unmarshalling! So you have to check if a field is already filled before setting a default value. Otherwise, you will override the provided value! Because of that it is recommended to use pointers for primitive types. Otherwise, you cannot really be sure if the field is intended to be empty.
To define suche a function there are two ways to do this:
package main
import (
"github.com/rainu/go-yacl"
)
type MyConfig struct {
String *string `yaml:"string"`
}
func Default(m *MyConfig) {
// check if the field is already set
if m.String == nil {
m.String = yacl.P("default")
}
}
func main() {
c := MyConfig{}
config := yacl.NewConfig(&c, yacl.WithDefaults(Default))
err := config.ParseArguments()
if err != nil {
panic(err)
}
println(c.String) // should be "default"
}package main
import (
"github.com/rainu/go-yacl"
)
type MyConfig struct {
String *string `yaml:"string"`
}
// implements the interface >yacl.DefaultSetter<
func (m *MyConfig) SetDefaults() {
// check if the field is already set
if m.String == nil {
m.String = yacl.P("default")
}
}
func main() {
c := MyConfig{}
config := yacl.NewConfig(&c)
err := config.ParseArguments()
if err != nil {
panic(err)
}
println(c.String) // should be "default"
}There are three ways to define the usage
type MyConfig struct {
String string `yaml:"string" usage:"Put a string here"`
}package main
import (
"github.com/rainu/go-yacl"
)
type MyConfig struct {
String string `yaml:"string"`
}
func main() {
c := MyConfig{}
config := yacl.NewConfig(&c, yacl.WithUsage(func(t *MyConfig, f string) string {
if f == "String" {
return "Put a string here"
}
return ""
}))
println(config.HelpFlags())
}package main
import (
"github.com/rainu/go-yacl"
)
type MyConfig struct {
String string `yaml:"string"`
}
// implements the interface >yacl.UsageProvider<
func (m *MyConfig) GetUsage(field string) string {
if field == "String" {
return "Put a string here"
}
return ""
}
func main() {
c := MyConfig{}
config := yacl.NewConfig(&c)
println(config.HelpFlags())
}package main
import (
"github.com/rainu/go-yacl"
)
type MyConfig struct {
Inner struct {
Bool bool `yaml:"bool" usage:"bool"`
} `yaml:"inner" usage:"Inner: "`
}
func main() {
c := MyConfig{}
config := yacl.NewConfig(&c)
err := config.ParseArguments("--inner.bool=true")
if err != nil {
panic(err)
}
println(config.HelpFlags())
}package main
import (
"github.com/rainu/go-yacl"
)
type MyConfig struct {
Inner struct {
Bool bool `yaml:"bool" usage:"bool"`
} `yaml:",inline"`
}
func main() {
c := MyConfig{}
config := yacl.NewConfig(&c)
err := config.ParseArguments("--inner.bool=true")
if err != nil {
panic(err)
}
println(config.HelpFlags())
}For more options, have a look into the option.go file.