Skip to content

String Slices from pflags are not handled correctly by viper. #200

@aarondl

Description

@aarondl

The slice of strings just contains one element that is the stringified version of the string
ie: []string{"[firstarg,secondarg]"}
or in the case of nil/empty: []string{"[]"}

It appears that this is coming from the Pflag libraries ValueString() function. I've included a patch that "helps" the issue but I suspect it's a little bit more deep-seated as the cast package also doesn't seem to handle this case well at all hence I'm not making trying to make a PR for this.

For others hitting this issue the workaround is to simply use pflags directly for string slices until this is fixed.

diff --git a/viper.go b/viper.go
index a2633b0..d1cce44 100644
--- a/viper.go
+++ b/viper.go
@@ -479,6 +479,8 @@ func (v *Viper) Get(key string) interface{} {
                                val = cast.ToInt(flag.ValueString())
                        case "bool":
                                val = cast.ToBool(flag.ValueString())
+                       case "stringSlice":
+                               val = []string{}
                        default:
                                val = flag.ValueString()
                        }
@@ -742,6 +744,8 @@ func (v *Viper) find(key string) interface{} {
                        return cast.ToInt(flag.ValueString())
                case "bool":
                        return cast.ToBool(flag.ValueString())
+               case "stringSlice":
+                       return strings.Split(strings.Trim(flag.ValueString(), "[]"), ",")
                default:
                        return flag.ValueString()
                }

Example program that shows the the failure:

package main

import (
    "fmt"
    "os"

    "github.com/davecgh/go-spew/spew"
    "github.com/spf13/cobra"
    "github.com/spf13/viper"
)

func main() {
    var rootCmd = &cobra.Command{
        Run: run,
    }

    rootCmd.PersistentFlags().StringSliceP("thing", "t", nil, "")
    viper.BindPFlags(rootCmd.PersistentFlags())

    if err := rootCmd.Execute(); err != nil {
        fmt.Printf("\n%+v\n", err)
        os.Exit(1)
    }
}

func run(cmd *cobra.Command, args []string) {
    str := viper.Get("thing")
    slice := viper.GetStringSlice("thing")
    slicePFlag, _ := cmd.PersistentFlags().GetStringSlice("thing")

    spew.Dump(str, slice, slicePFlag)
}

Output (annotated for clarity) of go run main.go

str   = (string) (len=2) "[]"
slice = ([]string) (len=1 cap=1) {
 (string) (len=2) "[]"
}
slicePFlag = ([]string) {}

Output (annotated for clarity) of go run main.go -t thing1 -t thing2

str   = (string) (len=15) "[thing1,thing2]"
slice = ([]string) (len=1 cap=1) {
 (string) (len=15) "[thing1,thing2]"
}
slicePFlag = ([]string) (len=2 cap=2) {
 (string) (len=6) "thing1",
 (string) (len=6) "thing2"
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions