You can use multiple keys tag to simplify the look like this (supported feature**):
// single tag key
type MyConfig struct {
Token string `json:token_json" xml:"token_xml" arg:"token" env:"token" environ:"TOKEN"`
}
// multiple tag keys
type MyConfig struct {
Token string `json xml bson yaml toml arg env:"token" environ:"TOKEN"`
}
Below is default mapping implementation of binder.RegisterCmdArgs = defaultRegisterCmdArgsFlagStd
that use standard golang flag
package to perform command flag.
The
is a placeholder for parent key, binder.BindArgs(Loaded, "my")
this case
will be replaced with my
, if there's field with type struct
in the component, it'll be replaced to my.
Tag | Go Code | Description |
---|---|---|
arg:"token" |
flag.StringVar(val, " |
Used for binding flag with contextual key
|
argx:"token" |
flag.StringVar(val, "token", *val, argUsage) |
Used for binding flag |
bind:"log" |
No equivalent | Used for binder to differ struct parent sub context
|
env:"token" |
os env(" |
Used for binding to environment variable with contextual key
|
environ:"token" |
os env("token") |
Used for binding to environment |
usage:" |
Used as argUsage |
Description for flag |
Other:
arg
andargx
(dedicated) basically has same function.env
andenviron
(dedicated) basically has same function.- Currently you can't have dedicated key for configuration because the way it parsed is from Unmarshaller that results in
map[string]interface{}
, but this definitely possible to implement.
More thing you can learn from the example below.
Example
package main
import (
"flag"
"fmt"
"os"
"github.com/ii64/go-binder/binder"
"github.com/pkg/errors"
)
type MyConfig struct {
Token string `json xml bson yaml toml arg:"token,omitempty" env:"TOKEN" environ:"TOKEN"`
Count int `json xml bson yaml toml arg:"count,omitempty" env:"COUNT" usage:"this is the usage"`
Ktes *int
Sub **struct {
Hello *string
SubOfSub struct {
InSub **bool
}
PtrOfSub *struct {
YourName **string `json xml bson yaml toml bind:"your_name,omitempty" env:"COUNT" usage:"this is the usage"`
}
}
Log struct {
SubLog int
Directory string
Filename string `json xml bson yaml toml arg:"filename" env:"FILENAME"`
DedicatedArg string `json xml bson yaml toml argx:"dedicatedArg" env:"DEDICATED_ARG"`
} `json xml bson yaml toml arg env bind:"log"`
}
var (
configFile = os env("CONFIG_FILE")
Loaded *MyConfig
)
func registerToBinder() {
Loaded = &MyConfig{
Token: "some default value",
Count: 121,
}
binder.BindArgsConf(Loaded, "my")
}
func main() {
var err error
if configFile == "" {
configFile = "config.json"
}
binder.LoadConfig = binder.LoadConfigJSON(configFile)
binder.SaveConfig = binder.SaveConfigJSON(configFile)
binder.SaveOnClose = true
// register component to binder
registerToBinder()
// perform binding
if err = binder.Init(); err != nil {
if errors.Is(err, os.ErrNotExist) {
if err = binder.Save(); err != nil {
panic(err)
}
} else {
panic(err)
}
}
flag.Parse()
// reflect back to component
binder.In()
defer binder.Close()
// runtime
fmt.Printf("%+#v\n", Loaded)
}
Output help:
$ main -h
Usage of main:
-dedicatedArg string
-my.Sub.Hello string
-my.count int
this is the usage (default 121)
-my.log.Directory string
-my.log.filename string
-my.token string
(default "some default value")
Output JSON:
{
"my": {
"token": "some default value",
"count": 121,
"Ktes": 0,
"Sub": {
"Hello": "",
"SubOfSub": {
"InSub": false
},
"PtrOfSub": {
"your_name": ""
}
},
"log": {
"SubLog": 0,
"Directory": "",
"filename": "",
"dedicatedArg": ""
}
}
}
Output TOML:
[my]
token = "some default value"
count = 121
Ktes = 0
[my.Sub]
Hello = ""
[my.Sub.SubOfSub]
InSub = false
[my.Sub.PtrOfSub]
your_name = ""
[my.log]
SubLog = 0
Directory = ""
filename = ""
dedicatedArg = ""
Output YAML:
my:
token: some default value
count: 121
ktes: 0
sub:
hello: ""
subofsub:
insub: false
ptrofsub:
your_name: ""
log:
sublog: 0
directory: ""
filename: ""
dedicatedArg: ""
Note
Contributions are welcome
**) Reverted feature as from 1.16 but found it useful