Skip to content

Default value of Cobra flag overrides the viper env variable  #671

Closed

Description

@ankur22

Hi,

I maybe mistaken here but i'm currently under the assumption that viper takes care of the order of precedence when it comes to where the value comes from: config file -> env var -> flag.

I'm finding that the default value that is used in the flag always overrides the env var. To overcome this i have to set the default value to be empty and then i have to check to see if the value is empty before using the env var value. Is this correct?

Here's the test code:

package cmd

import (
	"fmt"
	"os"

	"github.com/mitchellh/go-homedir"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var defaultConfigFilename = "abc-config"
var defaultConfigExt = "json"
var defaultLogPath = "/var/logs/abc/"

func NewRootCommand() *cobra.Command {
	configFile := ""

	rootCmd := &cobra.Command{
		Use:   "test",
		Short: "Test",
		Long:  `Test`,
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Println(configFile)
		},
	}

	initConfig := func() {

		if configFile == "" {
			// Try and get from env
			configFile = viper.GetString("configFile")
		}

		// Don't forget to read config either from configFile or from home directory!
		if configFile != "" {
			// Use config file from the flag.
			viper.SetConfigFile(configFile)
		} else {
			// Find home directory.
			home, err := homedir.Dir()
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}

			// Search config in home directory with name "abc-config" (without extension).
			viper.AddConfigPath(home)
			viper.SetConfigName(defaultConfigFilename)
		}

		if err := viper.ReadInConfig(); err != nil {
			fmt.Println("Can't read config:", err)
			os.Exit(1)
		}
	}

	cobra.OnInitialize(initConfig)

	viper.SetEnvPrefix("ABC")
	viper.AutomaticEnv()

	rootCmd.Flags().StringVarP(&configFile, "configFile", "c", "", fmt.Sprintf("config file (default is ~/%s.%s)", defaultConfigFilename, defaultConfigExt))
	viper.BindPFlag("configFile", rootCmd.Flags().Lookup("configFile"))

	return rootCmd
}

Thanks,
Ankur

Activity

  1. sagikazarmark commented on Mar 20, 2019

    @sagikazarmark
    Collaborator

    Yup, currently you can't really do anything else, but not define a default value for flags.

  2. ankur22 commented on Mar 20, 2019

    @ankur22
    Author

    Thank you for the quick response. I'll close this ticket since it's known. It might be worth mentioning in the readme... i guess i could change it and open a pull request too :)

  3. ekampf commented on Aug 29, 2019

    @ekampf

    Why is this a known accepted behavior?!
    Cobra integration with Viper is broken and can't be used with environment variable - it should be in big bold letters on the README

  4. carolynvs commented on Aug 9, 2020

    @carolynvs
    Contributor

    I've been using viper and cobra together on multiple CLIs for a couple years now and with a bit of custom code you can get them to integrate such that the config stacks:

    flags > environment variables > configuration files > flag defaults

    I wrote a sample working app with tests that demonstrates how to integrate them and a blog post that explains it in a bit more detail. Apologies if I am misunderstanding the OP (if I did, let me know and I'll remove/edit this), but hopefully the sample helps them out.

  5. hyorigo commented on Aug 20, 2020

    @hyorigo

    @carolynvs Great works! Thanks!

  6. ezk84 commented on Aug 23, 2022

    @ezk84

    The Sting of the Viper demo by @carolynvs was written end of 2020, and uses BindEnv directly. There's a simplification possible by using viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_")). Have submitted a PR in that repo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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