spf13 / viper

Go configuration with fangs
MIT License
27.36k stars 2.02k forks source link

Nested `.` separated flags with common prefix not working with pflag in Viper >= `1.18.0` #1922

Open shani1998 opened 2 months ago

shani1998 commented 2 months ago

Preflight Checklist

Viper Version

1.18.0

Go Version

1.22.6

Config Source

Flags

Format

Other (specify below)

Repl.it link

No response

Code reproducing the issue

package main

import (
    "fmt"

    "github.com/spf13/pflag"
    "github.com/spf13/viper"
)

var (
    _ = pflag.String("gateway.endpoint.v1", "some/path/v1", "endpoint of gateway server v2")
    _ = pflag.String("gateway.endpoint", "some/path/", "endpoint of gateway server v3")
)

func init() {
    pflag.Parse()
    viper.BindPFlags(pflag.CommandLine)
    viper.AutomaticEnv()
}

func main() {
    fmt.Println("viper.GetString(\"gateway.endpoint\"):", viper.GetString("gateway.endpoint"))
    fmt.Println("viper.GetString(\"gateway.endpoint.v1\"):", viper.GetString("gateway.endpoint.v1")) // getting empty 
}
got output for this:
viper.GetString("gateway.endpoint"): some/path/
viper.GetString("gateway.endpoint.v1"):

Expected Behavior

it should print:

~ go run test.go                                                                    
viper.GetString("gateway.endpoint"): some/path/
viper.GetString("gateway.endpoint.v1"): some/path/v1

Actual Behavior

in v1.17.0 it is working as expected returning output as

~ go run test.go                                                                    
viper.GetString("gateway.endpoint"): some/path/
viper.GetString("gateway.endpoint.v1"): some/path/v1

Steps To Reproduce

  1. 
    ✗ go env                                                                                  
    GO111MODULE=''
    GOARCH='arm64'
    GOBIN=''
    GOCACHE='/Users/spahk/Library/Caches/go-build'
    GOENV='/Users/spahk/Library/Application Support/go/env'
    GOEXE=''
    GOEXPERIMENT=''
    GOFLAGS=''
    GOHOSTARCH='arm64'
    GOHOSTOS='darwin'
    GOINSECURE=''
    GOMODCACHE='/Users/spahk/go/pkg/mod'
    GONOPROXY=''
    GONOSUMDB=''
    GOOS='darwin'
    GOPATH='/Users/spahk/go'
    GOPRIVATE=''
    GOPROXY='https://proxy.golang.org,direct'
    GOROOT='/opt/homebrew/Cellar/go/1.22.4/libexec'
    GOSUMDB='sum.golang.org'
    GOTMPDIR=''
    GOTOOLCHAIN='auto'
    GOTOOLDIR='/opt/homebrew/Cellar/go/1.22.4/libexec/pkg/tool/darwin_arm64'
    GOVCS=''
    GOVERSION='go1.22.4'
    GCCGO='gccgo'
    AR='ar'
    CC='cc'
    CXX='c++'
    CGO_ENABLED='1'
    GOMOD='/Users/spahk/projects/test/go.mod'
    GOWORK=''
    CGO_CFLAGS='-O2 -g'
    CGO_CPPFLAGS=''
    CGO_CXXFLAGS='-O2 -g'
    CGO_FFLAGS='-O2 -g'
    CGO_LDFLAGS='-O2 -g'
    PKG_CONFIG='pkg-config'
    GOGCCFLAGS='-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -ffile-prefix-map=/var/folders/jx/dpklpdss291clqs9t6xrh0c00000gp/T/go-build851702384=/tmp/go-build -gno-record-gcc-switches -fno-common'

go mod

module test

go 1.22.4

require ( github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.18.0 )

require ( github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.6.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect golang.org/x/sys v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect )



### Additional Information

Updated:
I can see it is working with another nested flags like `_ = pflag.String("a.b.c.d.v1", "some/path/abc", "endpoint of gateway server v4")`
but i am wondering what is the special with key `gateway.endpoint.*`
github-actions[bot] commented 2 months ago

👋 Thanks for reporting!

A maintainer will take a look at your issue shortly. 👀

In the meantime: We are working on Viper v2 and we would love to hear your thoughts about what you like or don't like about Viper, so we can improve or fix those issues.

⏰ If you have a couple minutes, please take some time and share your thoughts: https://forms.gle/R6faU74qPRPAzchZ9

📣 If you've already given us your feedback, you can still help by spreading the news, either by sharing the above link or telling people about this on Twitter:

https://twitter.com/sagikazarmark/status/1306904078967074816

Thank you! ❤️

akshay8 commented 2 months ago

I am also facing the same issue. I found a pattern where in two flags registered with same common prefix, then it is returning empty for the child flags. For example:

    _ = pflag.String("akshay.barik.v1", "akshay barik v1 value", "some v1 description")
    _ = pflag.String("akshay.barik", "akshay barik value", "some description")

    fmt.Println(viper.GetString("akshay.barik.v1"))         // getting empty
    fmt.Println( viper.GetString("akshay.barik"))       
shani1998 commented 2 months ago

I am also facing the same issue. I found a pattern where in two flags registered with same common prefix, then it is returning empty for the child flags. For example:

  _ = pflag.String("akshay.barik.v1", "akshay barik v1 value", "some v1 description")
  _ = pflag.String("akshay.barik", "akshay barik value", "some description")

  fmt.Println(viper.GetString("akshay.barik.v1"))         // getting empty
  fmt.Println( viper.GetString("akshay.barik"))       

Thanks, Akshay, for noticing this pattern. I see the same pattern now. I initially thought it was specific to gateway.endpoint, but it seems like multiple nested flags with a common prefix are having issues in Viper 1.18.0. Hopefully, we’ll get an update on this soon.