knadh / koanf

Simple, extremely lightweight, extensible, configuration management library for Go. Support for JSON, TOML, YAML, env, command line, file, S3 etc. Alternative to viper.
MIT License
2.71k stars 150 forks source link

posflag provider overrides values even if flags are not set for special delimiters #283

Closed callebjorkell closed 5 months ago

callebjorkell commented 6 months ago

Describe the bug When loading flags from a cobra application, if using - as the delimiter, existing loaded values are overridden by empty values.

To Reproduce Given a specified, but unused, pflag s3-bucket and an environment variable MYAPP_S3_BUCKET="five", if I have the following config loading:

        k := koanf.New(".")
    k.Load(env.Provider("MYAPP_", ".", func(s string) string {
        return strings.ReplaceAll(strings.ToLower(
            strings.TrimPrefix(s, "MYAPP_")), "_", ".")
    }), nil)
    k.Load(posflag.Provider(cmd.Flags(), "-", k), nil)

k.String("s3.bucket") will return "" when I have not set the s3-bucket flag for the application, even though the environment variable has a value.

Expected behavior k.String("s3.bucket") should return "five"

Please provide the following information):

Additional context I think this is because of the delimiter replacement happening only after the "existence check", so the provider is checking if "s3-bucket" exists as a key already in my koanf instance (which it doesn't) and then goes on to apply the delimiter (so "s3.bucket") before merging.

callebjorkell commented 6 months ago

I was able to work around this by passing a callback to the load, rewriting the key value to use dots instead to align with what has already been loaded into the koanf map:

err = k.Load(posflag.ProviderWithValue(cmd.Flags(), ".", k, func(key string, value string) (string, interface{}) {
    return strings.ReplaceAll(key, "-", "."), value
}), nil)

In this way, the overrides work as expected. I assume that wrapping the koanf instance passed to replace the key before checking if it exists would also work, but I haven't tried that.