我使用cobra和viper编写了一个简单的 CLI 工具。我最近一直在重构它以避免包全局变量,主要是因为使用 eg 建议的布局很难测试cobra init
。
代替...
var rootCmd = &cobra.Command{
...
}
func main() {
rootCmd.Execute()
}
我有更多类似的东西:
func NewCmdRoot() *cobra.Command {
cmd := &cobra.Command{
...
}
return cmd
}
func main() {
rootCmd := NewCmdRoot()
rootCmd.Execute()
}
这实际上效果很好,并且使测试从一组干净的 cli 选项开始变得更加容易。我在将 Viper 集成到新方案中时遇到了一些困难。如果我只关心 root 命令,我可以在PersistentPreRun
命令中进行设置,如下所示:
func initConfig(cmd *cobra.Command) {
config := viper.New()
rootCmd := cmd.Root()
config.BindPFlag("my-nifty-option", rootCmd.Flag("my-nifty-option")); err != nil {
// ...stuff happens here...
config.ReadInConfig()
// What happens next?
}
func NewCmdRoot() *cobra.Command {
cmd := &cobra.Command{
PersistentPreRun: func(cmd *cobra.Command, args []string) {
initConfig(cmd)
},
}
这种工作方式:只要我只对与 Cobra 命令行选项相对应的配置选项感兴趣,事情就会按预期工作。但是如果我想访问config
变量本身呢?
我不确定如何config
在方法之外公开变量
initConfig
而不将其转换为全局包。我想要实例化多个命令树的可能性,每个命令树都有自己独立的 Viper 配置对象,但我不清楚把它放在哪里。