Cobra: Expand upon config file usage in README

Created on 30 Apr 2017  路  10Comments  路  Source: spf13/cobra

I didn't see this in the README about the usage of the config file aside from the flag option of it being there. Does Cobra automatically read the config file from the location specified in the root.go, or is that for us to read and parse on our own?

arecmd aredocumentation kinbug

Most helpful comment

If I take the example from the readme...

func init() {
    cobra.OnInitialize(initConfig)
    RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)")
    RootCmd.PersistentFlags().StringVarP(&projectBase, "projectbase", "b", "", "base project directory eg. github.com/spf13/")
    RootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "Author name for copyright attribution")
    RootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "Name of license for the project (can provide `licensetext` in config)")
    RootCmd.PersistentFlags().Bool("viper", true, "Use Viper for configuration")
    viper.BindPFlag("author", RootCmd.PersistentFlags().Lookup("author"))
    viper.BindPFlag("projectbase", RootCmd.PersistentFlags().Lookup("projectbase"))
    viper.BindPFlag("useViper", RootCmd.PersistentFlags().Lookup("viper"))
    viper.SetDefault("author", "NAME HERE <EMAIL ADDRESS>")
    viper.SetDefault("license", "apache")
}

the pointer referred to by &projectBase will not store the value from the config file unless I do this somewhere down the line after the above code...

projectBase = viper.GetString("projectbase")

All 10 comments

Does Cobra automatically read the config file from the location specified in the root.go

Yes

These lines read config with name .cobra.yaml/.cobra.toml/.cobra.json from the home directory:

    if err := viper.ReadInConfig(); err == nil {
        fmt.Println("Using config file:", viper.ConfigFileUsed())
    }

I was going to start a similar issue because there is no explanation of how to go about using the config file.

How do I call a command from the config?
How do I set a flag from the config?
Which things get nested or indented in the YAML?

I am trying to figure out how to do all of these right now

How do I call a command from the config?

Sorry, but can you explain better, what do you mean?

How do I set a flag from the config?

From README

You will additionally define flags and handle configuration in your init() function.

for example cmd/root.go:
func init() {
    cobra.OnInitialize(initConfig)
    RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)")
    RootCmd.PersistentFlags().StringVarP(&projectBase, "projectbase", "b", "", "base project directory eg. github.com/spf13/")
    RootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "Author name for copyright attribution")
    RootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "Name of license for the project (can provide `licensetext` in config)")
    RootCmd.PersistentFlags().Bool("viper", true, "Use Viper for configuration")
    viper.BindPFlag("author", RootCmd.PersistentFlags().Lookup("author"))
    viper.BindPFlag("projectbase", RootCmd.PersistentFlags().Lookup("projectbase"))
    viper.BindPFlag("useViper", RootCmd.PersistentFlags().Lookup("viper"))
    viper.SetDefault("author", "NAME HERE <EMAIL ADDRESS>")
    viper.SetDefault("license", "apache")
}

viper.BindPFlag binds flag with config.

Which things get nested or indented in the YAML?

Answer is same as for first question.

@bogem, I see that the config is being parsed there, but the problem I am having is that I don't know what the config file is capable of doing. From playing with it I would suspect that it is only for declaring flag values, but I am left wondering:

Can it run commands? (can this be declred in config...)

config declares some commands and flags so that when I run...

./cli-tool

it parses the config and runs as

./cli-tool cmd1 --flag foo

What the readme is saying now might be clear to those who are very familiar with the code, but confusing to me when I am first looking at it. I think all of the main features (config file being one of them) should have a direct example rather than an indirect example through code which basically says "config is here, deal with it."

I am left with the questions...

how do I handle config in init()?

is this example showcasing the extent of the possibilities with the config file?

I have an idea of how to present the information, I will make a PR to show you after I hear back from this comment

config declares some commands and flags so that when I run...

Config file doesn't declare any commands. Cobra declares commands and flags and viper (config) reads the values from config and sets them to binded flags.

is this example showcasing the extent of the possibilities with the config file?

Not all possibilities. More about viper.

After reading the Viper README and looking at the first comment @bogem posted, it seems the configuration file is loaded into viper and is used as viper.GetString or whatever the option is set to.

https://github.com/spf13/viper/blob/master/README.md#getting-values-from-viper

This has sufficiently answer my question. Thank you @bogem

I think I have figured out what is confusing about this now...

1. viper handles all of the config files, which means that after viper.BindPFlag() is called, you should retrieve the flag value by calling viper.Get[type]() methods

2. If you had used a PersistentFlag().[type]Var() method then the variable which had its value set by the RootCmd.PersistentFlags() method call will not have its value changed, and must be reset elsewhere if that variable is still to be used.

Do I have the thought process correct? I can suggest some changes to the docs if my thinking is on track...

  1. Yes
  2. Can you please give a code example for a better understanding?

If I take the example from the readme...

func init() {
    cobra.OnInitialize(initConfig)
    RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)")
    RootCmd.PersistentFlags().StringVarP(&projectBase, "projectbase", "b", "", "base project directory eg. github.com/spf13/")
    RootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "Author name for copyright attribution")
    RootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "Name of license for the project (can provide `licensetext` in config)")
    RootCmd.PersistentFlags().Bool("viper", true, "Use Viper for configuration")
    viper.BindPFlag("author", RootCmd.PersistentFlags().Lookup("author"))
    viper.BindPFlag("projectbase", RootCmd.PersistentFlags().Lookup("projectbase"))
    viper.BindPFlag("useViper", RootCmd.PersistentFlags().Lookup("viper"))
    viper.SetDefault("author", "NAME HERE <EMAIL ADDRESS>")
    viper.SetDefault("license", "apache")
}

the pointer referred to by &projectBase will not store the value from the config file unless I do this somewhere down the line after the above code...

projectBase = viper.GetString("projectbase")

Yes

Was this page helpful?
0 / 5 - 0 ratings

Related issues

rogercoll picture rogercoll  路  5Comments

supershal picture supershal  路  4Comments

niski84 picture niski84  路  4Comments

anentropic picture anentropic  路  4Comments

lukasmalkmus picture lukasmalkmus  路  4Comments