Cannot use tags with same delimiter within struct using env provider
UnAfraid opened this issue · comments
Describe the bug
Hi,
I am trying to use koanf with env provider with _ as separator, and i am unable to bind property that contains the same separator, for example MYVAR_NESTED_BASE_URL always comes empty.
Environment variables:
MYVAR_TEST=asdf;MYVAR_NESTED_USERNAME=usr;MYVAR_NESTED_PASSWORD=pwd;MYVAR_NESTED_BASE_URL=https://localhost;MYVAR_NESTED_VALIDATE_SSL=true
To Reproduce
package main
import (
"fmt"
"strings"
"github.com/knadh/koanf"
"github.com/knadh/koanf/providers/env"
)
func main() {
var k = koanf.New("_")
err := k.Load(env.Provider("MYVAR_", "_", func(s string) string {
return strings.ToLower(strings.TrimPrefix(s, "MYVAR_"))
}), nil)
if err != nil {
panic(err)
}
type Nested struct {
Username string `koanf:"username"`
Password string `koanf:"password"`
BaseUrl string `koanf:"base_url"`
ValidateSSL bool `koanf:"validate_ssl"`
}
type Config struct {
Test string `koanf:"test"`
Nested Nested `koanf:"nested"`
}
var config Config
if err = k.UnmarshalWithConf("", &config, koanf.UnmarshalConf{Tag: "koanf"}); err != nil {
panic(err)
}
fmt.Printf("%#v", config)
}
Output:
main.Config{Test:"asdf", Nested:main.Nested{Username:"usr", Password:"pwd", BaseUrl:"", ValidateSSL:false}}
Expected behavior
main.Config{Test:"asdf", Nested:main.Nested{Username:"usr", Password:"pwd", BaseUrl:"https://localhost", ValidateSSL:true}}
Please provide the following information):
- OS: Linux
- Koanf Version v1.4.4
- Go Version: 1.19.4
Additional context:
If i switch it over to flat path and convert the nested struct into fields within my main struct it works:
package main
import (
"fmt"
"strings"
"github.com/knadh/koanf"
"github.com/knadh/koanf/providers/env"
)
func main() {
var k = koanf.New("_")
err := k.Load(env.Provider("MYVAR_", "_", func(s string) string {
return strings.ToLower(strings.TrimPrefix(s, "MYVAR_"))
}), nil)
if err != nil {
panic(err)
}
type Config struct {
Test string `koanf:"test"`
NestedUsername string `koanf:"nested_username"`
NestedPassword string `koanf:"nested_password"`
NestedBaseUrl string `koanf:"nested_base_url"`
NestedValidateSSL bool `koanf:"nested_validate_ssl"`
}
var config Config
if err = k.UnmarshalWithConf("", &config, koanf.UnmarshalConf{Tag: "koanf", FlatPaths: true}); err != nil {
panic(err)
}
fmt.Printf("%#v", config)
}
Output
main.Config{Test:"asdf", NestedUsername:"usr", NestedPassword:"pwd", NestedBaseUrl:"https://localhost", NestedValidateSSL:true}
This is correct behaviour @UnAfraid. If your variables have _
in them (eg: base_url
) and your nesting separator is also _
, it's impossible to figure out what is what. The simple trick here is to use some other character to indicate nesting, for example, __
(double underscore).
Eg: https://github.com/knadh/listmonk/blob/master/cmd/main.go#L116
LISTMONK_app__admin_username
which translates to app.admin_username
.
Thank you for the quick reply!
The double underscores trick works, but not for me, because it forces me to make changes on existing configuration.
Thanks for the suggestion anyway, i'll figure it out.
Best Regards!
Something like this could work, in that case. But you'll have to replace every instance of such nested keys in the function.
err := k.Load(env.Provider("", "_", func(s string) string {
return strings.ToLower(strings.Replace(s, "nested_", "nested."))
}), nil)