basicflag Provider does not exclude default values
jkroepke opened this issue · comments
Describe the bug
I would like to use koanf with multiple providers in a chain. In my case
defaults (struct) -> file -> env -> flags
The flagset is enriched with default values, because then --help
will display all default values for each option.
With posflag
Provider, everything work fine. Since it will only include changed values. However the basicflag
provider does not have an behavior (see #254)
To Reproduce
package main
import (
"flag"
"fmt"
"github.com/knadh/koanf/providers/basicflag"
"log"
"os"
"strings"
"github.com/knadh/koanf/providers/env"
"github.com/knadh/koanf/providers/structs"
"github.com/knadh/koanf/v2"
)
// Global koanf instance. Use "." as the key path delimiter. This can be "/" or any character.
var k = koanf.New(".")
type parentStruct struct {
Name string `koanf:"name"`
ID int `koanf:"id"`
}
func init() {
os.Setenv("MYVAR_ID", "5000")
}
func main() {
defaults := parentStruct{
Name: "parent1",
ID: 1234,
}
k.Load(structs.Provider(defaults, "koanf"), nil)
k.Load(env.Provider("MYVAR_", ".", func(s string) string {
return strings.Replace(strings.ToLower(
strings.TrimPrefix(s, "MYVAR_")), "_", ".", -1)
}), nil)
f := flag.NewFlagSet("config", flag.ContinueOnError)
f.String("name", defaults.Name, "")
f.Int("id", defaults.ID, "")
f.Parse([]string{"--name", "changed-from-flags"})
if err := k.Load(basicflag.Provider(f, "."), nil); err != nil {
log.Fatalf("error loading config: %v", err)
}
fmt.Printf("id is = `%d`\n", k.Int("id"))
fmt.Printf("name is = `%s`\n", k.String("name"))
}
Output
id is = `1234`
name is = `changed-from-flags`
Expected behavior
A clear and concise description of what you expected to happen.
Defaults values from flagset are not used in final config,
Output
id is = `5000`
name is = `changed-from-flags`
Please provide the following information):
- OS: [e.g. linux/osx/windows]
- Koanf Version [e.g. v1.0.0]
Additional context
Add any other context about the problem here.
With posflag, everything works as expected:
package main
import (
"fmt"
"log"
"os"
"strings"
"github.com/knadh/koanf/providers/env"
"github.com/knadh/koanf/providers/posflag"
"github.com/knadh/koanf/providers/structs"
"github.com/knadh/koanf/v2"
flag "github.com/spf13/pflag"
)
// Global koanf instance. Use "." as the key path delimiter. This can be "/" or any character.
var k = koanf.New(".")
type parentStruct struct {
Name string `koanf:"name"`
ID int `koanf:"id"`
}
func init() {
os.Setenv("MYVAR_ID", "5000")
}
func main() {
defaults := parentStruct{
Name: "parent1",
ID: 1234,
}
k.Load(structs.Provider(defaults, "koanf"), nil)
k.Load(env.Provider("MYVAR_", ".", func(s string) string {
return strings.Replace(strings.ToLower(
strings.TrimPrefix(s, "MYVAR_")), "_", ".", -1)
}), nil)
f := flag.NewFlagSet("config", flag.ContinueOnError)
f.String("name", defaults.Name, "")
f.Int("id", defaults.ID, "")
f.Parse([]string{"--name", "changed-from-flags"})
if err := k.Load(posflag.Provider(f, ".", k), nil); err != nil {
log.Fatalf("error loading config: %v", err)
}
fmt.Printf("id is = `%d`\n", k.Int("id"))
fmt.Printf("name is = `%s`\n", k.String("name"))
}
# id is = `5000`
# name is = `changed-from-flags`
Correct. But my proposal was closed, but the bug still exists.
I took a slightly different approach here without having to break Provider()'s backwards compatibility. It's a bit hacky, but preserves old behaviour and can take more options and config in the future. Please take a look at #259
basicflag.Provider(flags, ".", &basicflag.Opt{KeyMap: existingKoanfInstance}), nil)