如何使用 Cobra 和 Viper 将值绑定为配置中数组中的第一项?

问题描述

我有以下配置模型:

type Config struct {
  Project []Project `mapstructure:"project"`
}

type Project struct {
  Name string `mapstructure:"name"`
}

我希望能够使用配置文件以及命令行上的选项进行配置。我知道如何通过以正确的格式传递配置文件然后对其进行解组来处理配置文件

但是,我无法弄清楚如何使用 Cobra 在命令行上设置项目名称,然后让 Viper 将该值绑定为项目数组中的第一项。

以下是我整理的一个简单程序,用于显示我遇到的问题:

package main

import (
    "fmt"
    "log"

    "github.com/spf13/cobra"
    "github.com/spf13/viper"
)

type Config struct {
    Project []Project `mapstructure:"project"`
    Name    string    `mapstructure:"name"`
}

type Project struct {
    Name string `mapstructure:"name"`
}

var (
    config Config

    rootCmd = &cobra.Command{
        Use:              "rjsdummy",Short:            "Dummy app to understand Viper BindPFlags",Long:             "",PersistentPreRun: preRun,Run:              executeRun,}
)

func init() {

    var name string
    var project_name string

    cobra.OnInitialize()

    // configure the flags on the command line
    rootCmd.Flags().StringVarP(&name,"name","n","","Your name")
    rootCmd.Flags().StringVarP(&project_name,"project","p","Project name")

    // bind the flags to the configuration
    viper.BindPFlag("name",rootCmd.Flags().Lookup(("name")))
    viper.BindPFlag("project.0.name",rootCmd.Flags().Lookup(("project")))
}

func preRun(ccmd *cobra.Command,args []string) {
    err := viper.Unmarshal(&config)
    if err != nil {
        log.Fatalf("Unable to read Viper options into configuration: %v",err)
    }
}

func executeRun(ccmd *cobra.Command,args []string) {
    fmt.Printf("Your name: %s\n",config.Name)
    fmt.Printf("Project name: %s\n",config.Project[0].Name)
}

func main() {
    rootCmd.Execute()
}

当我使用命令 go run .\binding.go -n Russell -p Turtle 运行它时,我得到以下输出

Dummy app output

所以我知道 viper.BindPFlag("project.0.name",rootCmd.Flags().Lookup(("project"))) 行不起作用。如果我将其更改为 project[0].name,我会得到一个堆栈跟踪。问题是如何将这个(和其他属性添加为复杂对象数组中的第一项?我可以有第二个 Viper 来读入另一个对象然后添加到主配置中还是有其他方法

解决方法

在玩弄这个之后,我有了答案。

即使我已经设置了配置,让它拥有一个项目 Project []Project,但 Viper 足够聪明,可以解决这个问题。

所以要将项目名称绑定到切片的第一个元素,就像使用一样简单:

viper.BindPFlag("project.name",runCmd.Flags().Lookup("name"))

不需要索引。但是我可以打印值:

fmt.Println(Config.Project[0].Name)

enter image description here

我想多了