spf13 / viper

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

It is not very clear how to use viper with cobra together #82

Closed leolara closed 3 years ago

leolara commented 9 years ago

From the documentation it is clear that both Viper and Cobra use pflags, but is it possible to use Cobra and get all te power of Viper inside the Cobra commands?

bep commented 9 years ago

If you look at Hugo, which I believe was the origin of both Cobra and Viper, these are used together. But the interaction does look kind of funky:

https://github.com/spf13/hugo/blob/master/commands/hugo.go#L173

leolara commented 9 years ago

@bep Would it make sense a way implement a way to pass a pflags from Cobra to Viper?

bep commented 9 years ago

It would make totally sense -- and would get rid of the hack linked to above.

But I think you would have some rule(s) of what do do when the flag is defined in both collections. I guess checking the Changed flag in Cobra makes sense as an override-indicator.

WGH- commented 6 years ago

I ended up writing this helper type to copy flags from Viper back to pflags. Why not use Viper directly, you might ask? pflags are somewhat more convenient to work with, as you can define custom datatypes and bind flags to variables (e.g.StringVar vs String).

type viperPFlagBinding struct {
        configName string
        flagValue  pflag.Value
}

type viperPFlagHelper struct {
        bindings []viperPFlagBinding
}

func (vch *viperPFlagHelper) BindPFlag(configName string, flag *pflag.Flag) (err error) {
        err = viper.BindPFlag(configName, flag)
        if err == nil {
                vch.bindings = append(vch.bindings, viperPFlagBinding{configName, flag.Value})
        }
        return
}

func (vch *viperPFlagHelper) setPFlagsFromViper() {
        for _, v := range vch.bindings {
                v.flagValue.Set(viper.GetString(v.configName))
        }
}

func main() {
        var rootCmd = &cobra.Command{}
        var viperPFlagHelper viperPFlagHelper

        rootCmd.PersistentFlags().StringVar(&config.Password, "password", "", "API server password (remote HTTPS mode only)")
        viperPFlagHelper.BindPFlag("password", rootCmd.Flag("password"))

        rootCmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
                err := viper.ReadInConfig()
                if err != nil {
                        if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
                                return err
                        }
                }

                viperPFlagHelper.setPFlagsFromViper()

                return nil
        }
}
amyadzuki commented 6 years ago

@WGH- May I use a derivative of that snippet in a repo licensed CC0-1.0 please? I will give you credit in a code comment.

WGH- commented 6 years ago

Sure.

On August 11, 2018 11:06:23 AM GMT+03:00, Amy notifications@github.com wrote:

@WGH- May I use a derivative of that snippet in a repo licensed CC0-1.0 please? I will give you credit in a code comment.

-- You are receiving this because you were mentioned. Reply to this email directly or view it on GitHub: https://github.com/spf13/viper/issues/82#issuecomment-412259423

desdic commented 5 years ago

If for any reason someone needs it I have created an example that shows how coba and viper works together with 4 simple tests. Default values, default values overwritten by cmd line, config file and config file options overwritten by command line. Hope it helps someone:

https://github.com/desdic/playground/tree/master/go/cobraviper

cpliakas commented 3 years ago

I also created a small utility at https://github.com/cpliakas/cliutil#flagger that made it easier for me to add flags using Cobra and Viper. I am sharing here in case it is helpful to anyone else.

sagikazarmark commented 3 years ago

Closing in favor of #1061