Почему кобра не читает мой конфигурационный файл

Документы в кобре и гадюке сбивают меня с толку. я сделал cobra init fooproject а затем внутри проекта DIR я сделал cobra add bar, у меня есть PersistentFlag это называется foo и вот функция init из root команда.

func Execute() {
    if err := RootCmd.Execute(); err != nil {
        fmt.Println(err)
        os.Exit(-1)
    }

    fmt.Println(cfgFile)
    fmt.Println("fooString is: ", fooString)
}


func init() {
    cobra.OnInitialize(initConfig)

    // Here you will define your flags and configuration settings.
    // Cobra supports Persistent Flags, which, if defined here,
    // will be global for your application.

    RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.fooproject.yaml)")
    RootCmd.PersistentFlags().StringVar(&fooString, "foo", "", "loaded from config")

    viper.BindPFlag("foo", RootCmd.PersistentFlags().Lookup("foo"))
    // Cobra also supports local flags, which will only run
    // when this action is called directly.
    RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

мой конфигурационный файл выглядит так...

---
foo: aFooString

и когда я звоню go run main.go Я вижу это...

A longer description that spans multiple lines and likely contains
examples and usage of using your application. For example:

Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.

Usage:
  fooproject [command]

Available Commands:
  bar         A brief description of your command
  help        Help about any command

Flags:
      --config string   config file (default is $HOME/.fooproject.yaml)
      --foo string      loaded from config
  -h, --help            help for fooproject
  -t, --toggle          Help message for toggle

Use "fooproject [command] --help" for more information about a command.

fooString is:

Когда я звоню go run main.go bar Я вижу это...

Using config file: my/gopath/github.com/user/fooproject/.fooproject.yaml
bar called

fooString is:

так что он использует конфигурационный файл, но ни один из них, кажется, не читает его, может быть, я неправильно понимаю, как работают кобра и гадюка, есть идеи?

4 ответа

Решение

Комбинировать spf13/cobra а также spf13/viper,

сначала определим флаг с коброй:

RootCmd.PersistentFlags().StringP("foo", "", "loaded from config")

свяжи это с гадюкой:

viper.BindPFlag("foo", RootCmd.PersistentFlags().Lookup("foo"))

и получить переменную с помощью метода гадюки:

fmt.Println("fooString is: ", viper.GetString("foo"))

Так как значения Viper несколько уступают pflags (например, нет поддержки пользовательских типов данных), я не был удовлетворен ответом "использовать Viper для получения значений", и в итоге я написал небольшой вспомогательный тип для возврата значений в pflags.

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
        }
}

Для тех, кто сталкивается с той же проблемой, проблема заключается в следующем звонке:

cobra.OnInitialize(initConfig)

Функция initConfig не выполняется напрямую, а добавляется к массиву инициализаторов https://github.com/spf13/cobra/blob/master/cobra.go

Итак, значения, хранящиеся в вашем файле конфигурации, будут загружены, когда Run поле выполняется:

  rootCmd = &cobra.Command{
    Use:   "example",
    Short: "example cmd",
    Run: func(cmd *cobra.Command, args []string) { // OnInitialize is called first
      fmt.Println(viper.AllKeys())
    },  
  }

Ответ @WGH правильный, вы можете что-то сделать с постоянным флагом в rootCmd.PersistenPreRun, который будет доступен во всех других подкомандах.

      var rootCmd = &cobra.Command{
    PersistentPreRun: func(_ *cobra.Command, _ []string) {
        if persistentflag {
            // do something with persistentflag
        }
    },
Другие вопросы по тегам