Как я могу использовать Cobra и Viper для привязки значения в качестве первого элемента массива в конфигурации?

# #go #go-cobra

Вопрос:

У меня есть следующая модель конфигурации:

 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 = amp;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(amp;name, "name", "n", "", "Your name")
    rootCmd.Flags().StringVarP(amp;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(amp;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: %sn", config.Name)
    fmt.Printf("Project name: %sn", config.Project[0].Name)
}

func main() {
    rootCmd.Execute()
}

 

Когда я запускаю это с помощью команды go run .binding.go -n Russell -p Turtle , я получаю следующий вывод:

Фиктивный вывод приложения

Поэтому я знаю, что линия viper.BindPFlag("project.0.name", rootCmd.Flags().Lookup(("project"))) не работает. Если я изменю это на project[0].name «Я получу трассировку стека». Вопрос в том, как добавить этот (и другие атрибуты) в качестве первого элемента в массиве сложных объектов? Могу ли я получить вторую гадюку, которая будет считываться в другой объект, а затем добавляться в основную конфигурацию, или есть другой способ?

Ответ №1:

После игры с этим у меня есть ответ.

Несмотря на то , что я настроил конфигурацию так, чтобы в ней был фрагмент проекта Project []Project , Viper достаточно умен, чтобы разобраться в этом.

Поэтому, чтобы привязать имя проекта к первому элементу среза, достаточно просто использовать:

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

Индекс не требуется. Однако я могу распечатать значение с помощью:

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

введите описание изображения здесь

Я перестарался, думая об этом