Как Unmarshall Viper config значение правильно структурировать массив строк?

Я заметил, что это, возможно, ошибка, когда viper пытается разобрать структуру. Чтобы объяснить это лучше, рассмотрим это:

У меня есть команда cli, как показано ниже dd-cli submit-bug --name "Bug 1" --tag reason1 --tag reason2

Вот мой исходный код командной строки

package cmd

import (
    "fmt"

    "github.com/spf13/viper"

    "github.com/spf13/cobra"
)

// SubmitBugOpts is a set of flags being exposed by this Deploy command
type SubmitBugOpts struct {
    Name string `mapstructure:"bug-name"`

    ReasonTags []string `mapstructure:"tags"`
}

var (
    submitBugOpts = SubmitBugOpts{}
)

func submitBugRun(cmd *cobra.Command, args []string) {
    fmt.Printf("Bug Name is %+v\n", submitBugOpts.Name)
    fmt.Printf("List of tags is %+v\n", submitBugOpts.ReasonTags)
    fmt.Printf("Length of tags is %d\n", len(submitBugOpts.ReasonTags))
    for index, el := range submitBugOpts.ReasonTags {
        fmt.Printf("tag[%d] = %s\n", index, el)
    }
}

var submitBugCmd = &cobra.Command{
    Use:   "submit-bug",
    Short: "Deploy/Install a helm chart to Kubernetes cluster",
    Run:   submitBugRun,
    PreRun: func(cmd *cobra.Command, args []string) {
        pFlags := cmd.PersistentFlags()
        viper.BindPFlag("bug-name", pFlags.Lookup("name"))
        viper.BindPFlag("tags", pFlags.Lookup("tag"))

        fmt.Printf("Viper all setting value: %+v\n", viper.AllSettings())
        fmt.Printf("Before unmarshall: %+v\n", submitBugOpts)
        viper.Unmarshal(&submitBugOpts)
        fmt.Printf("After unmarshall: %+v\n", submitBugOpts)
    },
}

func init() {
    rootCmd.AddCommand(submitBugCmd)

    pFlags := submitBugCmd.PersistentFlags()
    pFlags.StringVar(&submitBugOpts.Name, "name", "", "the bug name")
    pFlags.StringArrayVar(&submitBugOpts.ReasonTags, "tag", nil, "the bug's reason tag. You can define it multiple times")

    submitBugCmd.MarkPersistentFlagRequired("name")
    submitBugCmd.MarkPersistentFlagRequired("tag")
}

Я запускаю эту команду:

dd-cli submit-bug --name "Bug 1" --tag reason1 --tag reason2

И выход ниже

Viper all setting value: map[bug-name:Bug 1 tags:[reason1,reason2]]
Before unmarshall: {Name:Bug 1 ReasonTags:[reason1 reason2]}
After unmarshall: {Name:Bug 1 ReasonTags:[[reason1 reason2]]}
Bug Name is Bug 1
List of tags is [[reason1 reason2]]
Length of tags is 2
tag[0] = [reason1
tag[1] = reason2]

Я ожидаю viper.Unmarshall() будет правильно опускать [ за submitBugOpts.ReasonTags [0] и опустить ] за submitBugOpts.ReasonTags[1], Таким образом, ожидаемое значение submitBugOpts.ReasonTags не содержит никаких [ а также ],

Любой указатель, как это исправить? Я отправил этот вопрос на репо Viper: https://github.com/spf13/viper/issues/527. Однако я спрашиваю об этом на всякий случай, если вы, ребята, знаете, как с этим справиться.

1 ответ

Решение

Покопавшись в кодах github.com/spf13/{cobra,viper,pflag}довольно долго я наконец-то нашел проблему.

Когда вы звоните pFlags.StringArrayVar(&submitBugOpts.ReasonTags, "tag", nil, ...), ReasonTags, конечно, привязывается к обертке pflag.stringArrayValue, источник.

И когда вы звоните viper.UnmarshallВайпер использует v.Get чтобы получить значение привязывается к ReasonTags а потом это вызывает v.find,

В v.findпосле того, как значение найдено, оно использует обертку ValueType() метод, чтобы определить его тип, оболочка затем вызывает Type метод обернутого типа, pflag.stringArrayValueи возвращает "stringArray", источник

Но вайпер только ручкой "stringSlice" как особый случай, поэтому значение получает default часть типа switch, которая использует его ValueString() метод - превращение в строку, с "[" а также "]" с обеих сторон. источник

И когда, наконец, демарширует, как ваш выходной параметр, ReasonTags имеет []stringпрограмма просто разбила строку и установила ее в поле.

Что касается решения, если вы в порядке с запретом tag содержать ,, просто поменяй StringArrayVar в StringSliceVar, но это приведет к --tag "Yet, the problem re-occurs" в []string{"Yet"," the problem re-occrus"},

Если это важно, вам нужно попросить разработчиков Viper создать кейс для stringArray,

Другие вопросы по тегам