英文:
How can I use Cobra and Viper to bind a value as the first item in an array in the configuration?
问题
我有以下配置模型:
type Config struct {
Project []Project `mapstructure:"project"`
}
type Project struct {
Name string `mapstructure:"name"`
}
我希望能够使用配置文件和命令行选项来配置它。我知道如何通过传递正确格式的配置文件并进行解组来实现配置文件。
然而,我无法弄清楚如何使用Cobra在命令行上设置项目名称,然后让Viper将该值绑定为Project数组中的第一个项目。
以下是我编写的一个简单程序,用于展示我遇到的问题:
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
运行此程序时,我得到以下输出:
所以我知道viper.BindPFlag("project.0.name", rootCmd.Flags().Lookup(("project")))
这一行不起作用。如果我将其更改为project[0].name
,我会得到一个堆栈跟踪。问题是如何将这个(和其他属性)添加为复杂对象数组中的第一个项目?我可以有第二个Viper读取另一个对象并添加到主配置中吗?还是还有其他方法?
英文:
I have the following configuration model:
type Config struct {
Project []Project `mapstructure:"project"`
}
type Project struct {
Name string `mapstructure:"name"`
}
I want to be able to configure this using a configuration file as well as options on the command line. I know how to do the config file by passing it in the correct format and then unmarshalling it.
However what I cannot work out how to do is have the name of the project set on the command line using Cobra and then have Viper bind that value as the first item in the Project array.
The following is a simple program I put together to show the problem I have:
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()
}
When I run this with the command go run .\binding.go -n Russell -p Turtle
I get the following output:
So I know that the line viper.BindPFlag("project.0.name", rootCmd.Flags().Lookup(("project")))
is not working. If I change this to project[0].name
I get a stack trace. The question is how do I add this (and other attributes) as an the first item in array of complex objects? Can I have a second Viper that would read into another object and then add to the main config or is there another way?
答案1
得分: 1
在玩弄了一番之后,我找到了答案。
尽管我已经设置了配置,使其具有项目Project []Project
的切片,但Viper足够聪明,可以解决这个问题。
因此,要将项目名称绑定到切片的第一个元素,只需简单地使用:
viper.BindPFlag("project.name", runCmd.Flags().Lookup("name"))
不需要索引。但是,我可以使用以下代码打印该值:
fmt.Println(Config.Project[0].Name)
我过于复杂化了这个问题。
英文:
After playing around with this I have the answer.
Even though I have set the configuation so that it has a slice of project Project []Project
, Viper is clever enough to work this out.
So to bind the project name to the first element of the slice, it is as simple as using:
viper.BindPFlag("project.name", runCmd.Flags().Lookup("name"))
No index is required. However I can print the value with:
fmt.Println(Config.Project[0].Name)
I was over thinking this
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论