I use json
file to configure my program arguments and use flag
package to configure the same arguments.
When some argument parsed by json
file and flag
at the same time, I wish use the arguments parsed through flag
.
The trouble is that the json
file path is also parsed through flag
.
The json path can be obtained after calling flag.parse()
, but the arguments is also parsed, then Unmarshal
json will overwrite the arguments of flag parsing.
example json:
{
"opt1": 1,
"opt2": "hello"
}
example code:
var Config = struct {
Opt1 int `json:"opt1"`
Opt2 string `json:"opt2"`
}{
Opt1: 0,
Opt2: "none",
}
func main() {
// parse config file path
var configFile string
flag.StringVar(&configFile, "config", "", "config file path")
// parse options
flag.IntVar(&Config.Opt1, "opt1", Config.Opt1, "")
flag.StringVar(&Config.Opt2, "opt2", Config.Opt2, "")
// parse flags
flag.Parse()
// load config options from config.json file
if configFile != "" {
if data, err := ioutil.ReadFile(configFile); err != nil {
fmt.Printf("read config file error: %v\n", err)
} else if err = json.Unmarshal(data, &Config); err != nil {
fmt.Printf("parse config file error: %v\n", err)
}
}
fmt.Printf("% v", Config)
}
program example output:
./foo.exe -opt2 world
out: {Opt1:0 Opt2:world}
./foo.exe -config config.json
out: {Opt1:1 Opt2:hello}
./foo.exe -config config.json -opt2 world
real out: {Opt1:1 Opt2:hello}
hope out: {Opt1:1 Opt2:world}
CodePudding user response:
One easy solution would be to first parse the JSON config file, and once that's done, then proceed to parse CLI arguments.
The problem with this is that the JSON config file is also a CLI arg.
The simplest solution would be to call flag.Parse()
again after parsing the config file:
// load config options from config.json file
if configFile != "" {
if data, err := ioutil.ReadFile(configFile); err != nil {
fmt.Printf("read config file error: %v\n", err)
} else if err = json.Unmarshal(data, &Config); err != nil {
fmt.Printf("parse config file error: %v\n", err)
}
// parse flags again to have precedence
flag.Parse()
}
The second flag.Parse()
will override and thus have precedence over data coming from the JSON file.
With this addition, running
./foo.exe -config config.json -opt2 world
Output will be what you desire:
{Opt1:1 Opt2:world}