Stært

Stært is a Go library for loading and merging a program configuration structure from many sources.
Overview
Stært was born in order to merge two sources of Configuration (Flæg, Toml).
Now it also supports Key-Value Store.
We developed Flæg and Stært in order to simplify configuration maintenance on Træfik.
Features
- Load your Configuration structure from many sources
- Keep your Configuration structure values unchanged if no overwriting (support defaults values)
- Three native sources :
- An Interface to add your own sources
- Handle pointers field :
- You can give a structure of default values for pointers
- Same comportment as Flæg
- Stært is Command oriented
- It use
flaeg.Command
- Same comportment as Flæg commands
- Stært supports only one Command (the Root-Command)
- Flæg allows you to use many Commands
- Only Flæg will be used if a Sub-Command is called. (because Config type could be different from one Command to another)
- You can add Metadata
"parseAllSources" -> "true" to a Sub-Command if you want to parse all sources (it requires the same Config type on the Sub-Command and the Root-Command)
Getting Started
The configuration
It works on your own Configuration structure, like this one :
package example
import (
"fmt"
"github.com/containous/flaeg"
"github.com/containous/staert"
"os"
)
//Configuration is a struct which contains all differents type to field
type Configuration struct {
IntField int `description:"An integer field"`
StringField string `description:"A string field"`
PointerField *PointerSubConfiguration `description:"A pointer field"`
}
//PointerSubConfiguration is a SubStructure Configuration
type PointerSubConfiguration struct {
BoolField bool `description:"A boolean field"`
FloatField float64 `description:"A float field"`
}
Let's initialize it:
func main() {
//Init with default value
config := &Configuration{
IntField: 1,
StringField: "init",
PointerField: &PointerSubConfiguration{
FloatField: 1.1,
},
}
//Set default pointers value
defaultPointersConfig := &Configuration{
PointerField: &PointerSubConfiguration{
BoolField: true,
FloatField: 99.99,
},
}
The command
Stært uses flaeg.Command Structure, like this :
//Create Command
command:=&flaeg.Command{
Name:"example",
Description:"This is an example of description",
Config:config,
DefaultPointersConfig:defaultPointersConfig,
Run: func() error {
fmt.Printf("Run example with the config :\n%+v\n",config)
fmt.Printf("PointerField contains:%+v\n", config.PointerField)
return nil
}
}
Use stært with sources
Init Stært
s:=staert.NewStaert(command)
Init TOML source
toml:=staert.NewTomlSource("example", []string{"./toml/", "/any/other/path"})
Init Flæg source
f:=flaeg.New(command, os.Args[1:])
Add sources
Add TOML and flæg sources
s.AddSource(toml)
s.AddSource(f)
NB : You can change order, so that, flaeg configuration will overwrite toml one
Load your configuration
Just call LoadConfig function :
loadedConfig, err := s.LoadConfig();
if err != nil {
//OOPS
}
//DO WHAT YOU WANT WITH loadedConfig
//OR CALL RUN FUNC
You can call Run
Run function will call the func run() from the command :
if err := s.Run(); err != nil {
//OOPS
}
}
NB : If you didn't call LoadConfig() before, your func run() will use your original configuration
Let's run example
TOML file ./toml/example.toml :
IntField= 2
[PointerField]
We can run the example program using folowing CLI arguments :
$ ./example --stringfield=owerwrittenFromFlag --pointerfield.floatfield=55.55
Run example with the config :
&{IntField:2 StringField:owerwrittenFromFlag PointerField:0xc82000ec80}
PointerField contains:&{BoolField:true FloatField:55.55}
Full example :
Tagoæl is a trivial example which shows how Stært can be use.
This funny golang progam takes its configuration from both TOML and Flaeg sources to display messages.
$ ./tagoael -h
tagoæl is an enhanced Hello World program to display messages with
an advanced configuration mechanism provided by flæg & stært.
flæg: https://github.com/containous/flaeg
stært: https://github.com/containous/staert
tagoæl: https://github.com/debovema/tagoael
Usage: tagoael [--flag=flag_argument] [-f[flag_argument]] ... set flag_argument to flag(s)
or: tagoael [--flag[=true|false| ]] [-f[true|false| ]] ... set true/false to boolean flag(s)
Flags:
-c, --commandlineoverridesconfigfile Whether configuration from command line overrides configuration from configuration file or not. (default "true")
--configfile Configuration file to use (TOML). (default "tagoael")
-i, --displayindex Whether to display index of each message (default "false")
-m, --messagetodisplay Message to display (default "HELLO WOLRD")
-n, --numbertodisplay Number of messages to display (default "1000")
-h, --help Print Help (this message) and exit
Thank you @debovema for this work :)
KvStore
As with Flæg and Toml sources, the configuration structure can be loaded from a Key-Value Store.
The package libkv provides connection to many KV Store like Consul, Etcd or Zookeeper.
The whole configuration structure is stored, using architecture like this pattern :
- Key :
<prefix1>/<prefix2>/.../<fieldNameLevel1>/<fieldNameLevel2>/.../<fieldName>
- Value :
<value>
It handles :
- All mapstructure features(
bool, int, ... , Squashed Embedded Sub struct, Pointer).
- Maps with pattern :
.../<MapFieldName>/<mapKey> -> <mapValue> (Struct as key not supported)
- Slices (and Arrays) with pattern :
.../<SliceFieldName>/<SliceIndex> -> <value>
Note : Hopefully, we provide the function StoreConfig to store your configuration structure ;)
KvSource
KvSource implements Source:
type KvSource struct {
store.Store
Prefix string // like this "prefix" (witout the /)
}
Initialize
It can be initialized like this :
kv, err := staert.NewKvSource(backend store.Backend, addrs []string, options *store.Config, prefix string)
LoadConfig
You can directly load data from the KV Store into the config structure (given by reference)
config := &ConfigStruct{} // Here your configuration structure by reference
err := kv.Parse(config)
//DO WHAT YOU WANT WITH config
Add to Stært sources
Or you can add this source to Stært, as with other sources
s.AddSource(kv)
StoreConfig
You can also store your whole configuration structure into the KV Store :
// We assume that config is Initialazed
err := kv.StoreConfig(config)
Contributing
- Fork it!
- Create your feature branch:
git checkout -b my-new-feature
- Commit your changes:
git commit -am 'Add some feature'
- Push to the branch:
git push origin my-new-feature
- Submit a pull request :D