我使用 Viper https://github.com/spf13/viper来管理 GO 应用程序中的项目配置,以及将配置值解组到结构体。
var config c.Configuration // Configuration is my configuration struct
err := viper.Unmarshal(&config)
Run Code Online (Sandbox Code Playgroud)
当我错过 .yml 配置文件中的某些配置时,它在解组期间不会抛出任何错误(正如我所猜测的)。
那么我怎样才能强制实施所有配置呢?如果结构体中的任何字段在 yaml 中没有值,我想查看错误。
我正在使用Go开发一个Web应用程序.到目前为止一切顺利,但现在我正在将Wercker整合为CI工具并开始关注测试.但我的应用程序在很大程度上依赖于Cobra/Viper配置/ flags/environment_variables方案,我不知道在运行我的测试套件之前如何正确初始化Viper值.任何帮助将非常感激.
我试图让Viper读取我的环境变量,但它无法正常工作.这是我的配置:
# app.yaml
dsn: RESTFUL_APP_DSN
jwt_verification_key: RESTFUL_APP_JWT_VERIFICATION_KEY
jwt_signing_key: RESTFUL_APP_JWT_SIGNING_KEY
jwt_signing_method: "HS256"
Run Code Online (Sandbox Code Playgroud)
我的config.go档案:
package config
import (
"fmt"
"strings"
"github.com/go-ozzo/ozzo-validation"
"github.com/spf13/viper"
)
// Config stores the application-wide configurations
var Config appConfig
type appConfig struct {
// the path to the error message file. Defaults to "config/errors.yaml"
ErrorFile string `mapstructure:"error_file"`
// the server port. Defaults to 8080
ServerPort int `mapstructure:"server_port"`
// the data source name (DSN) for connecting to the database. required.
DSN string `mapstructure:"dsn"`
// the signing method for …Run Code Online (Sandbox Code Playgroud) 我不太明白 viper 是如何工作的。这是我的代码:
配置.go
var Config *Configuration
type ServerConfiguration struct {
Port string
}
type Configuration struct {
Server ServerConfiguration
}
func Init() {
var configuration *Configuration
viper.SetConfigFile(".env")
viper.AutomaticEnv()
if err := viper.ReadInConfig(); err != nil {
log.Fatalf("Error reading config file, %s", err)
}
err := viper.Unmarshal(&configuration)
if err != nil {
log.Fatalf("Unable to decode into struct, %v", err)
}
Config = configuration
}
func GetConfig() *Configuration {
return Config
}
Run Code Online (Sandbox Code Playgroud)
.env
SERVER_PORT=:4747
问题是 Unmarshal 不起作用当我使用例如配置时。Server.Port 它是空的
所以我有一个非常基本的配置,Viper 从我的基目录读取 .env 文件。如果没有 .env 文件,我会致命终止该进程。正常运行我的应用程序时一切顺利。当我使用 运行测试时go test -v ./..,测试框架似乎会进入每个文件的目录,并每次调用我的 config init() 函数,因此它viper.AddConfigPath(".")指向错误的位置。
这是我的目录结构:
/
/restapi
items.go
items_test.go
/util
env.go
main.go
.env
Run Code Online (Sandbox Code Playgroud)
环境go
/
/restapi
items.go
items_test.go
/util
env.go
main.go
.env
Run Code Online (Sandbox Code Playgroud)
每个包基本上都依赖于我的 util 包,因此这个 init 函数会针对每个测试运行。有没有办法让 viper 始终从基本目录中提取 .env 文件,即使有测试正在运行?我尝试了一些不同的 AddConfigPath() 调用。对 Go 有点陌生。或者这个环境变量的结构设置不会工作,因为它每次都失败我的测试?
我最近才开始使用 Go,并且在使用 Cobra 和 Viper 时遇到了一些我不确定我是否理解的行为。
这是您通过运行获得的示例代码的略微修改版本cobra init。在main.go我有:
package main
import (
"github.com/larsks/example/cmd"
"github.com/spf13/cobra"
)
func main() {
rootCmd := cmd.NewCmdRoot()
cobra.CheckErr(rootCmd.Execute())
}
Run Code Online (Sandbox Code Playgroud)
在cmd/root.go我有:
package cmd
import (
"fmt"
"os"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var cfgFile string
func NewCmdRoot() *cobra.Command {
config := viper.New()
var cmd = &cobra.Command{
Use: "example",
Short: "A brief description of your application",
PersistentPreRun: func(cmd *cobra.Command, args []string) {
initConfig(cmd, config)
},
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("This is a …Run Code Online (Sandbox Code Playgroud) 我正在使用Viper和Cobra构建一个小应用程序。目前,我有一个yaml文件,如下所示:
hosts:
- name: host1
port: 90
key: my_key
- name: host2
port: 90
key: prompt
Run Code Online (Sandbox Code Playgroud)
而且我已经使用Viper读取了配置文件。
当我运行viper.Get("hosts")它时,它返回一个接口(或接口的一部分?)。这是我最终得到的数据结构:
([]interface {}) (len=2 cap=2) {
(map[interface {}]interface {}) (len=3) {
(string) (len=4) "name": (string) (len=20) "host1",
(string) (len=4) "port": (int) 90,
(string) (len=3) "key": (string) (len=6) "my_key"
},
(map[interface {}]interface {}) (len=3) {
(string) (len=3) "key": (string) (len=6) "prompt",
(string) (len=4) "name": (string) (len=20) "host2",
(string) (len=4) "port": (int) 90
}
}
Run Code Online (Sandbox Code Playgroud)
我想在这里做的是遍历每个数组元素,并使用name,port和key的值执行操作。
我是Golang接口的新手,所以这还不是很清楚,关于此的文献非常令人困惑:(
任何帮助表示赞赏。
我将以下配置文件定义为toml文件:
[staging]
project-id = "projectId"
cluster-name = "cluster"
zone = "asia-southeast1-a"
Run Code Online (Sandbox Code Playgroud)
然后,我有这个结构
type ConfigureOpts struct {
GCPProjectID string `json:"project-id"`
ClusterName string `json:"cluster-name"`
Zone string `json:"zone"`
}
Run Code Online (Sandbox Code Playgroud)
请注意,与配置文件中定义的格式不同,ConfigureOpts字段名具有不同的格式。
我已经尝试过此代码,但失败了
test_opts := ConfigureOpts{}
fmt.Printf("viper.staging value %+v\n", viper.GetStringMap("staging"))
viper.UnmarshalKey("staging", &test_opts)
fmt.Printf("testUnmarshall %+v\n", test_opts)
Run Code Online (Sandbox Code Playgroud)
这是输出
viper.staging value map[zone:asia-southeast1-a project-id:projectId cluster-name:cluster]
testUnmarshall {GCPProjectID: ClusterName: Zone:asia-southeast1-a AuthMode: AuthServiceAccount:}
Run Code Online (Sandbox Code Playgroud) 我的问题:
如何编写下面的代码以从嵌套的 yaml 结构中获取字符串?
这是我的 yaml:
element:
- one:
url: http://test
nested: 123
- two:
url: http://test
nested: 123
weather:
- test:
zipcode: 12345
- ca:
zipcode: 90210
Run Code Online (Sandbox Code Playgroud)
这是示例代码
viper.SetConfigName("main_config")
viper.AddConfigPath(".")
err := viper.ReadInConfig()
if err != nil {
panic(err)
}
testvar := viper.GetString("element.one.url")
Run Code Online (Sandbox Code Playgroud)
我的问题:
当我打印这个时,我得到一个空字符串。根据文档,这是获得嵌套元素的方式。我怀疑它不起作用,因为元素是列表。我需要做一个结构吗?我是新手,所以不确定如何制作一个,特别是如果它需要嵌套。
我正在维护一些使用 Go (golang)、Viper和Cobra编写的代码。
一方面,它有:
rootCmd.PersistentFlags().String("cfg", "", "A description")
Run Code Online (Sandbox Code Playgroud)
然后在下一行它有
rootCmd.PersistentFlags().StringP("output", "o", ".", "Another description")
Run Code Online (Sandbox Code Playgroud)
在这种情况下String和StringP在这种情况下有什么区别?
查看各种教程中的示例用法,似乎有各种方法的版本P和非P版本,例如StringVarP和StringVar。
这些版本之间有什么区别?的意义P何在?
有没有一种方法可以判断给定的方法是否具有对应物P或非P对应物?
搜索引擎倾向于将我带到 cobra 或 viper 教程页面,这些页面使用这些方法而不解释P或非P对应。
我发现一些材料pflags表明它可能与参数是否具有短(一个字母)形式有关。会是这样吗?
编辑后说明:收到这个问题的答案后,spf13/pflag上面提到的 golang 框架似乎确实在幕后使用了它。然而,在使用 cobra 或 viper 时是否应该查看 pflags 文档并不清楚。
由于这是一个问答网站,我已经恢复了一项编辑,该编辑删除了我在寻找此答案时会输入的许多关键字,因为我觉得其他人在寻找相同的信息时会以这种方式得到更好的服务。