Loading flags with defaults in struct:
type Config struct {
Host string
}
cfg := &Config{
Host: "example.com",
}
if b,err := yaml.Marshal(cfg); err != nil {
log.Panicf("cannot marshal defaults?! %s", err)
} else {
viper.SetConfigType("yaml")
r := bytes.NewReader(b)
viper.ReadConfig(r)
}
viper.AddConfigPath(".")
if err := viper.ReadInConfig(); err != nil {
log.Panicf("cannot read: %s", err)
}
cfg = &Config{}
if err := viper.Unmarshal(cfg); err != nil {
log.Panicf("cannot unmarshal config: %s", err)
}
spew.Dump(cfg)
config.yaml
addr: localhost:8080
output:
(*main.Config)(0xc4200d3de0)({
Host: (string) (len=11) "example.com",
Addr: (string) (len=14) "localhost:8080"
})
The solution is trivial, pass the initialized values to Unmarshal, it won't modify the values not present in config file:
cfg := &Config{
Host: "example.com",
}
viper.AddConfigPath(".")
if err := viper.ReadInConfig(); err != nil {
logrus.Fatalf("cannot read: %s", err)
}
if err := viper.Unmarshal(cfg); err != nil {
logrus.Fatalf("cannot unmarshal config: %s", err)
}
spew.Dump(cfg)
Please close the issue. Maybe add a note to FAQ?
@orian, it actually doesn't modify values already in the struct either.
cfg := &Config{
Host: "example.com",
}
viper.AddConfigPath(".")
if err := viper.ReadInConfig(); err != nil {
logrus.Fatalf("cannot read: %s", err)
}
if err := viper.Unmarshal(cfg); err != nil {
logrus.Fatalf("cannot unmarshal config: %s", err)
}
fmt.Println(cfg.Host) // will print "example.com" instead of the value in the config file.
host: localhost:8080
This must have been fixed along the way or was working as expected:
type Config struct {
Host string
Url string
}
func TestDefaults(t *testing.T) {
cfg := &Config{
Host: "default",
Url: "default",
}
vv := viper.New()
vv.SetConfigType("yaml")
err := vv.ReadConfig(bytes.NewReader([]byte(`Host: "blue" `)))
if err != nil {
t.Error("Failed to read config")
}
vv.Unmarshal(&cfg)
fmt.Printf("%+v\n", cfg)
}
&{Host:blue Url:default}
Default values provided by viper.SetDefault are being overrided as well, if only server.database is specified in config file then server.timeout = 0
viper.SetDefault("server.database", DefaultDatabase)
viper.SetDefault("server.timeout", 30*time.Second)
Most helpful comment
@orian, it actually doesn't modify values already in the struct either.