Command line flags features and cleanup (#2068)
* change BindSetup to be an option to Bind * add process.Bind to allow composite structures * hack fix for noprefix flags * used tagged version of structs Before this PR, some flags were created by calling `cfgstruct.Bind` and having their fields create a flag. Once the flags were parsed, `viper` was used to acquire all the values from them and config files, and the fields in the struct were set through the flag interface. This doesn't work for slices of things on config structs very well, since it can only set strings, and for a string slice, it turns out that the implementation in `pflag` appends an entry rather than setting it. This changes three things: 1. Only have a `Bind` call instead of `Bind` and `BindSetup`, and make `BindSetup` an option instead. 2. Add a `process.Bind` call that takes in a `*cobra.Cmd`, binds the struct to the command's flags, and keeps track of that struct in a global map keyed by the command. 3. Use `viper` to get the values and load them into the bound configuration structs instead of using the flags to propagate the changes. In this way, we can support whatever rich configuration we want in the config yaml files, while still getting command like flags when important.
This commit is contained in:
parent
771271e7b8
commit
e74cac52ab
@ -56,8 +56,8 @@ func init() {
|
||||
defaults := cfgstruct.DefaultsFlag(rootCmd)
|
||||
rootCmd.AddCommand(runCmd)
|
||||
rootCmd.AddCommand(setupCmd)
|
||||
cfgstruct.Bind(runCmd.Flags(), &runCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||
cfgstruct.BindSetup(setupCmd.Flags(), &setupCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||
process.Bind(runCmd, &runCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||
process.Bind(setupCmd, &setupCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir), cfgstruct.SetupMode())
|
||||
}
|
||||
|
||||
func cmdRun(cmd *cobra.Command, args []string) (err error) {
|
||||
|
@ -82,15 +82,15 @@ func main() {
|
||||
authCmd.AddCommand(authInfoCmd)
|
||||
authCmd.AddCommand(authExportCmd)
|
||||
|
||||
cfgstruct.Bind(authCreateCmd.Flags(), &config, defaults, cfgstruct.ConfDir(confDir))
|
||||
cfgstruct.Bind(authInfoCmd.Flags(), &config, defaults, cfgstruct.ConfDir(confDir))
|
||||
cfgstruct.Bind(authExportCmd.Flags(), &config, defaults, cfgstruct.ConfDir(confDir))
|
||||
cfgstruct.Bind(runCmd.Flags(), &config, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||
cfgstruct.BindSetup(setupCmd.Flags(), &config, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||
cfgstruct.Bind(signCmd.Flags(), &signCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||
cfgstruct.Bind(verifyCmd.Flags(), &verifyCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||
cfgstruct.Bind(claimsExportCmd.Flags(), &claimsExportCfg, defaults, cfgstruct.ConfDir(confDir))
|
||||
cfgstruct.Bind(claimDeleteCmd.Flags(), &claimsDeleteCfg, defaults, cfgstruct.ConfDir(confDir))
|
||||
process.Bind(authCreateCmd, &config, defaults, cfgstruct.ConfDir(confDir))
|
||||
process.Bind(authInfoCmd, &config, defaults, cfgstruct.ConfDir(confDir))
|
||||
process.Bind(authExportCmd, &config, defaults, cfgstruct.ConfDir(confDir))
|
||||
process.Bind(runCmd, &config, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||
process.Bind(setupCmd, &config, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir), cfgstruct.SetupMode())
|
||||
process.Bind(signCmd, &signCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||
process.Bind(verifyCmd, &verifyCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||
process.Bind(claimsExportCmd, &claimsExportCfg, defaults, cfgstruct.ConfDir(confDir))
|
||||
process.Bind(claimDeleteCmd, &claimsDeleteCfg, defaults, cfgstruct.ConfDir(confDir))
|
||||
|
||||
process.Exec(rootCmd)
|
||||
}
|
||||
|
@ -74,8 +74,8 @@ func init() {
|
||||
|
||||
rootCmd.AddCommand(runCmd)
|
||||
rootCmd.AddCommand(setupCmd)
|
||||
cfgstruct.Bind(runCmd.Flags(), &runCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||
cfgstruct.BindSetup(setupCmd.Flags(), &setupCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||
process.Bind(runCmd, &runCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||
process.Bind(setupCmd, &setupCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir), cfgstruct.SetupMode())
|
||||
}
|
||||
|
||||
func cmdSetup(cmd *cobra.Command, args []string) (err error) {
|
||||
|
@ -52,7 +52,7 @@ var (
|
||||
func init() {
|
||||
defaults = cfgstruct.DefaultsFlag(rootCmd)
|
||||
rootCmd.AddCommand(keyGenerateCmd)
|
||||
cfgstruct.Bind(keyGenerateCmd.Flags(), &keyCfg, defaults)
|
||||
process.Bind(keyGenerateCmd, &keyCfg, defaults)
|
||||
}
|
||||
|
||||
func cmdKeyGenerate(cmd *cobra.Command, args []string) (err error) {
|
||||
|
@ -106,11 +106,11 @@ func init() {
|
||||
caCmd.AddCommand(revokeCACmd)
|
||||
caCmd.AddCommand(revokePeerCACmd)
|
||||
|
||||
cfgstruct.Bind(newCACmd.Flags(), &newCACfg, defaults, cfgstruct.IdentityDir(defaultIdentityDir))
|
||||
cfgstruct.Bind(getIDCmd.Flags(), &getIDCfg, defaults, cfgstruct.IdentityDir(defaultIdentityDir))
|
||||
cfgstruct.Bind(caExtCmd.Flags(), &caExtCfg, defaults, cfgstruct.IdentityDir(defaultIdentityDir))
|
||||
cfgstruct.Bind(revokeCACmd.Flags(), &revokeCACfg, defaults, cfgstruct.IdentityDir(defaultIdentityDir))
|
||||
cfgstruct.Bind(revokePeerCACmd.Flags(), &revokePeerCACfg, defaults, cfgstruct.ConfDir(defaultConfigDir), cfgstruct.IdentityDir(defaultIdentityDir))
|
||||
process.Bind(newCACmd, &newCACfg, defaults, cfgstruct.IdentityDir(defaultIdentityDir))
|
||||
process.Bind(getIDCmd, &getIDCfg, defaults, cfgstruct.IdentityDir(defaultIdentityDir))
|
||||
process.Bind(caExtCmd, &caExtCfg, defaults, cfgstruct.IdentityDir(defaultIdentityDir))
|
||||
process.Bind(revokeCACmd, &revokeCACfg, defaults, cfgstruct.IdentityDir(defaultIdentityDir))
|
||||
process.Bind(revokePeerCACmd, &revokePeerCACfg, defaults, cfgstruct.ConfDir(defaultConfigDir), cfgstruct.IdentityDir(defaultIdentityDir))
|
||||
}
|
||||
|
||||
func cmdNewCA(cmd *cobra.Command, args []string) error {
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
|
||||
"storj.io/storj/pkg/cfgstruct"
|
||||
"storj.io/storj/pkg/identity"
|
||||
"storj.io/storj/pkg/process"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -67,9 +68,9 @@ func init() {
|
||||
idCmd.AddCommand(leafExtCmd)
|
||||
idCmd.AddCommand(revokeLeafCmd)
|
||||
|
||||
cfgstruct.Bind(newIDCmd.Flags(), &newIDCfg, defaults, cfgstruct.IdentityDir(defaultIdentityDir))
|
||||
cfgstruct.Bind(leafExtCmd.Flags(), &leafExtCfg, defaults, cfgstruct.IdentityDir(defaultIdentityDir))
|
||||
cfgstruct.Bind(revokeLeafCmd.Flags(), &revokeLeafCfg, defaults, cfgstruct.IdentityDir(defaultIdentityDir))
|
||||
process.Bind(newIDCmd, &newIDCfg, defaults, cfgstruct.IdentityDir(defaultIdentityDir))
|
||||
process.Bind(leafExtCmd, &leafExtCfg, defaults, cfgstruct.IdentityDir(defaultIdentityDir))
|
||||
process.Bind(revokeLeafCmd, &revokeLeafCfg, defaults, cfgstruct.IdentityDir(defaultIdentityDir))
|
||||
}
|
||||
|
||||
func cmdNewID(cmd *cobra.Command, args []string) (err error) {
|
||||
|
@ -69,8 +69,8 @@ func init() {
|
||||
rootCmd.AddCommand(newServiceCmd)
|
||||
rootCmd.AddCommand(authorizeCmd)
|
||||
|
||||
cfgstruct.Bind(newServiceCmd.Flags(), &config, defaults, cfgstruct.ConfDir(defaultConfigDir), cfgstruct.IdentityDir(defaultIdentityDir))
|
||||
cfgstruct.Bind(authorizeCmd.Flags(), &config, defaults, cfgstruct.ConfDir(defaultConfigDir), cfgstruct.IdentityDir(defaultIdentityDir))
|
||||
process.Bind(newServiceCmd, &config, defaults, cfgstruct.ConfDir(defaultConfigDir), cfgstruct.IdentityDir(defaultIdentityDir))
|
||||
process.Bind(authorizeCmd, &config, defaults, cfgstruct.ConfDir(defaultConfigDir), cfgstruct.IdentityDir(defaultIdentityDir))
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
|
||||
"storj.io/storj/pkg/cfgstruct"
|
||||
"storj.io/storj/pkg/identity"
|
||||
"storj.io/storj/pkg/process"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -33,7 +34,7 @@ var (
|
||||
func init() {
|
||||
rootCmd.AddCommand(revocationsCmd)
|
||||
|
||||
cfgstruct.Bind(revocationsCmd.Flags(), &revCfg, defaults, cfgstruct.ConfDir(defaultConfigDir), cfgstruct.IdentityDir(defaultIdentityDir))
|
||||
process.Bind(revocationsCmd, &revCfg, defaults, cfgstruct.ConfDir(defaultConfigDir), cfgstruct.IdentityDir(defaultIdentityDir))
|
||||
}
|
||||
|
||||
func cmdRevocations(cmd *cobra.Command, args []string) error {
|
||||
|
@ -45,8 +45,8 @@ func init() {
|
||||
defaults := cfgstruct.DefaultsFlag(rootCmd)
|
||||
rootCmd.AddCommand(addCmd)
|
||||
rootCmd.AddCommand(listCmd)
|
||||
cfgstruct.Bind(addCmd.Flags(), &cacheCfg, defaults)
|
||||
cfgstruct.Bind(listCmd.Flags(), &cacheCfg, defaults)
|
||||
process.Bind(addCmd, &cacheCfg, defaults)
|
||||
process.Bind(listCmd, &cacheCfg, defaults)
|
||||
}
|
||||
|
||||
func cmdList(cmd *cobra.Command, args []string) (err error) {
|
||||
|
@ -98,11 +98,11 @@ func init() {
|
||||
rootCmd.AddCommand(qdiagCmd)
|
||||
rootCmd.AddCommand(reportsCmd)
|
||||
reportsCmd.AddCommand(nodeUsageCmd)
|
||||
cfgstruct.Bind(runCmd.Flags(), &runCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||
cfgstruct.BindSetup(setupCmd.Flags(), &setupCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||
cfgstruct.Bind(diagCmd.Flags(), &diagCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||
cfgstruct.Bind(qdiagCmd.Flags(), &qdiagCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||
cfgstruct.Bind(nodeUsageCmd.Flags(), &nodeUsageCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||
process.Bind(runCmd, &runCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||
process.Bind(setupCmd, &setupCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir), cfgstruct.SetupMode())
|
||||
process.Bind(diagCmd, &diagCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||
process.Bind(qdiagCmd, &qdiagCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||
process.Bind(nodeUsageCmd, &nodeUsageCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||
}
|
||||
|
||||
func cmdRun(cmd *cobra.Command, args []string) (err error) {
|
||||
|
@ -33,7 +33,7 @@ func main() {
|
||||
RunE: Main,
|
||||
}
|
||||
defaults := cfgstruct.DefaultsFlag(cmd)
|
||||
cfgstruct.Bind(cmd.Flags(), &Config, defaults, cfgstruct.ConfDir(defaultConfDir))
|
||||
process.Bind(cmd, &Config, defaults, cfgstruct.ConfDir(defaultConfDir))
|
||||
cmd.Flags().String("config", filepath.Join(defaultConfDir, "config.yaml"), "path to configuration")
|
||||
process.Exec(cmd)
|
||||
}
|
||||
|
@ -98,11 +98,11 @@ func init() {
|
||||
rootCmd.AddCommand(configCmd)
|
||||
rootCmd.AddCommand(diagCmd)
|
||||
rootCmd.AddCommand(dashboardCmd)
|
||||
cfgstruct.Bind(runCmd.Flags(), &runCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||
cfgstruct.BindSetup(setupCmd.Flags(), &setupCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||
cfgstruct.BindSetup(configCmd.Flags(), &setupCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||
cfgstruct.Bind(diagCmd.Flags(), &diagCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||
cfgstruct.Bind(dashboardCmd.Flags(), &dashboardCfg, defaults, cfgstruct.ConfDir(defaultDiagDir))
|
||||
process.Bind(runCmd, &runCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||
process.Bind(setupCmd, &setupCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir), cfgstruct.SetupMode())
|
||||
process.Bind(configCmd, &setupCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir), cfgstruct.SetupMode())
|
||||
process.Bind(diagCmd, &diagCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
||||
process.Bind(dashboardCmd, &dashboardCfg, defaults, cfgstruct.ConfDir(defaultDiagDir))
|
||||
}
|
||||
|
||||
func databaseConfig(config storagenode.Config) storagenodedb.Config {
|
||||
|
@ -16,6 +16,7 @@ import (
|
||||
"storj.io/storj/internal/fpath"
|
||||
libuplink "storj.io/storj/lib/uplink"
|
||||
"storj.io/storj/pkg/cfgstruct"
|
||||
"storj.io/storj/pkg/process"
|
||||
"storj.io/storj/pkg/storj"
|
||||
"storj.io/storj/uplink"
|
||||
)
|
||||
@ -50,7 +51,7 @@ func addCmd(cmd *cobra.Command, root *cobra.Command) *cobra.Command {
|
||||
defaultConfDir = confDirParam
|
||||
}
|
||||
|
||||
cfgstruct.Bind(cmd.Flags(), &cfg, defaults, cfgstruct.ConfDir(defaultConfDir))
|
||||
process.Bind(cmd, &cfg, defaults, cfgstruct.ConfDir(defaultConfDir))
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ func init() {
|
||||
cfgstruct.SetupFlag(zap.L(), RootCmd, &confDir, "config-dir", defaultConfDir, "main directory for uplink configuration")
|
||||
defaults = cfgstruct.DefaultsFlag(RootCmd)
|
||||
RootCmd.AddCommand(setupCmd)
|
||||
cfgstruct.BindSetup(setupCmd.Flags(), &setupCfg, defaults, cfgstruct.ConfDir(confDir))
|
||||
process.Bind(setupCmd, &setupCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.SetupMode())
|
||||
}
|
||||
|
||||
func cmdSetup(cmd *cobra.Command, args []string) (err error) {
|
||||
|
@ -13,7 +13,6 @@ import (
|
||||
|
||||
"storj.io/storj/internal/fpath"
|
||||
libuplink "storj.io/storj/lib/uplink"
|
||||
"storj.io/storj/pkg/cfgstruct"
|
||||
"storj.io/storj/pkg/encryption"
|
||||
"storj.io/storj/pkg/macaroon"
|
||||
"storj.io/storj/pkg/process"
|
||||
@ -41,7 +40,7 @@ func init() {
|
||||
RunE: shareMain,
|
||||
}, RootCmd)
|
||||
|
||||
cfgstruct.Bind(shareCmd.Flags(), &shareCfg)
|
||||
process.Bind(shareCmd, &shareCfg)
|
||||
}
|
||||
|
||||
const shareISO8601 = "2006-01-02T15:04:05-0700"
|
||||
|
@ -50,8 +50,8 @@ func init() {
|
||||
defaults := cfgstruct.DefaultsFlag(rootCmd)
|
||||
rootCmd.AddCommand(runCmd)
|
||||
rootCmd.AddCommand(setupCmd)
|
||||
cfgstruct.Bind(runCmd.Flags(), &runCfg, defaults, cfgstruct.ConfDir(confDir))
|
||||
cfgstruct.BindSetup(setupCmd.Flags(), &setupCfg, defaults, cfgstruct.ConfDir(confDir))
|
||||
process.Bind(runCmd, &runCfg, defaults, cfgstruct.ConfDir(confDir))
|
||||
process.Bind(setupCmd, &setupCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.SetupMode())
|
||||
}
|
||||
|
||||
func cmdRun(cmd *cobra.Command, args []string) (err error) {
|
||||
|
3
go.mod
3
go.mod
@ -102,9 +102,10 @@ require (
|
||||
github.com/vivint/infectious v0.0.0-20190108171102-2455b059135b
|
||||
github.com/yuin/gopher-lua v0.0.0-20180918061612-799fa34954fb // indirect
|
||||
github.com/zeebo/admission v0.0.0-20180821192747-f24f2a94a40c
|
||||
github.com/zeebo/errs v1.1.0
|
||||
github.com/zeebo/errs v1.1.1
|
||||
github.com/zeebo/float16 v0.1.0 // indirect
|
||||
github.com/zeebo/incenc v0.0.0-20180505221441-0d92902eec54 // indirect
|
||||
github.com/zeebo/structs v1.0.1
|
||||
go.etcd.io/bbolt v1.3.2 // indirect
|
||||
go.uber.org/atomic v1.3.2 // indirect
|
||||
go.uber.org/multierr v1.1.0 // indirect
|
||||
|
10
go.sum
10
go.sum
@ -340,6 +340,8 @@ github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.2.0 h1:HHl1DSRbEQN2i8tJmtS6ViPyHx35+p51amrdsiTCrkg=
|
||||
github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
|
||||
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8=
|
||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
|
||||
@ -369,12 +371,16 @@ github.com/yuin/gopher-lua v0.0.0-20180918061612-799fa34954fb h1:Jmfk7z2f/+gxVFA
|
||||
github.com/yuin/gopher-lua v0.0.0-20180918061612-799fa34954fb/go.mod h1:aEV29XrmTYFr3CiRxZeGHpkvbwq+prZduBqMaascyCU=
|
||||
github.com/zeebo/admission v0.0.0-20180821192747-f24f2a94a40c h1:WoYvMZp+keiJz+ZogLAhwsUZvWe81W+mCnpfdgEUOl4=
|
||||
github.com/zeebo/admission v0.0.0-20180821192747-f24f2a94a40c/go.mod h1:Aq7yiXoKLFIDzh4eR6EG4owIO9alpttZ0XJ5c/z/QrE=
|
||||
github.com/zeebo/errs v1.1.0 h1:4dNyQKsWPyBDqLzZUpx+QMP0Qil9STQPdBsKk6+O2qA=
|
||||
github.com/zeebo/errs v1.1.0/go.mod h1:Yj8dHrUQwls1bF3dr/vcSIu+qf4mI7idnTcHfoACc6I=
|
||||
github.com/zeebo/assert v0.0.0-20181109011804-10f827ce2ed6 h1:bs7mSHVrLRQHxqWcm0hyez0sA23YuXb8Pwnq5NhyZ8A=
|
||||
github.com/zeebo/assert v0.0.0-20181109011804-10f827ce2ed6/go.mod h1:yssERNPivllc1yU3BvpjYI5BUW+zglcz6QWqeVRL5t0=
|
||||
github.com/zeebo/errs v1.1.1 h1:Cs5Noqj/tj3Ql/hLkD9WdumKlssx/IN2zr7CRGNOKZA=
|
||||
github.com/zeebo/errs v1.1.1/go.mod h1:Yj8dHrUQwls1bF3dr/vcSIu+qf4mI7idnTcHfoACc6I=
|
||||
github.com/zeebo/float16 v0.1.0 h1:kRqxv5og6z1emEyz5FpW0/BVHe5VfxEAw6b1ljCZlUc=
|
||||
github.com/zeebo/float16 v0.1.0/go.mod h1:fssGvvXu+XS8MH57cKmyrLB/cqioYeYX/2mXCN3a5wo=
|
||||
github.com/zeebo/incenc v0.0.0-20180505221441-0d92902eec54 h1:+cwNE5KJ3pika4HuzmDHkDlK5myo0G9Sv+eO7WWxnUQ=
|
||||
github.com/zeebo/incenc v0.0.0-20180505221441-0d92902eec54/go.mod h1:EI8LcOBDlSL3POyqwC1eJhOYlMBMidES+613EtmmT5w=
|
||||
github.com/zeebo/structs v1.0.1 h1:MopCKn+ah1DF83tdMjcN+1V/gFpPO8eUnXEaiarwFLI=
|
||||
github.com/zeebo/structs v1.0.1/go.mod h1:LphfpprlqJQcbCq+eA3iIK/NsejMwk9mlfH/tM1XuKQ=
|
||||
go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.opencensus.io v0.15.0/go.mod h1:UffZAU+4sDEINUGP/B7UfBBkq4fqLu9zXAX7ke6CHW0=
|
||||
|
@ -22,8 +22,9 @@ import (
|
||||
|
||||
// BindOpt is an option for the Bind method
|
||||
type BindOpt struct {
|
||||
isDev *bool
|
||||
varfn func(vars map[string]confVar)
|
||||
isDev *bool
|
||||
isSetup *bool
|
||||
varfn func(vars map[string]confVar)
|
||||
}
|
||||
|
||||
// ConfDir sets variables for default options called $CONFDIR and $CONFNAME.
|
||||
@ -31,18 +32,6 @@ func ConfDir(path string) BindOpt {
|
||||
val := filepath.Clean(os.ExpandEnv(path))
|
||||
return BindOpt{varfn: func(vars map[string]confVar) {
|
||||
vars["CONFDIR"] = confVar{val: val, nested: false}
|
||||
vars["CONFNAME"] = confVar{val: val, nested: false}
|
||||
}}
|
||||
}
|
||||
|
||||
// ConfDirNested sets variables for default options called $CONFDIR and $CONFNAME.
|
||||
// ConfDirNested also appends the parent struct field name to the paths before
|
||||
// descending into substructs.
|
||||
func ConfDirNested(confdir string) BindOpt {
|
||||
val := filepath.Clean(os.ExpandEnv(confdir))
|
||||
return BindOpt{varfn: func(vars map[string]confVar) {
|
||||
vars["CONFDIR"] = confVar{val: val, nested: true}
|
||||
vars["CONFNAME"] = confVar{val: val, nested: true}
|
||||
}}
|
||||
}
|
||||
|
||||
@ -54,6 +43,13 @@ func IdentityDir(path string) BindOpt {
|
||||
}}
|
||||
}
|
||||
|
||||
// SetupMode issues the bind in a mode where it does not ignore fields with the
|
||||
// `setup:"true"` tag.
|
||||
func SetupMode() BindOpt {
|
||||
setup := true
|
||||
return BindOpt{isSetup: &setup}
|
||||
}
|
||||
|
||||
// UseDevDefaults forces the bind call to use development defaults unless
|
||||
// UseReleaseDefaults is provided as a subsequent option.
|
||||
// Without either, Bind will default to determining which defaults to use
|
||||
@ -79,24 +75,18 @@ type confVar struct {
|
||||
|
||||
// Bind sets flags on a FlagSet that match the configuration struct
|
||||
// 'config'. This works by traversing the config struct using the 'reflect'
|
||||
// package. Will ignore fields with `setup:"true"` tag.
|
||||
func Bind(flags FlagSet, config interface{}, opts ...BindOpt) {
|
||||
bind(flags, config, false, opts...)
|
||||
}
|
||||
|
||||
// BindSetup sets flags on a FlagSet that match the configuration struct
|
||||
// 'config'. This works by traversing the config struct using the 'reflect'
|
||||
// package.
|
||||
func BindSetup(flags FlagSet, config interface{}, opts ...BindOpt) {
|
||||
bind(flags, config, true, opts...)
|
||||
func Bind(flags FlagSet, config interface{}, opts ...BindOpt) {
|
||||
bind(flags, config, opts...)
|
||||
}
|
||||
|
||||
func bind(flags FlagSet, config interface{}, setupCommand bool, opts ...BindOpt) {
|
||||
func bind(flags FlagSet, config interface{}, opts ...BindOpt) {
|
||||
ptrtype := reflect.TypeOf(config)
|
||||
if ptrtype.Kind() != reflect.Ptr {
|
||||
panic(fmt.Sprintf("invalid config type: %#v. Expecting pointer to struct.", config))
|
||||
}
|
||||
isDev := !version.Build.Release
|
||||
setupCommand := false
|
||||
vars := map[string]confVar{}
|
||||
for _, opt := range opts {
|
||||
if opt.varfn != nil {
|
||||
@ -105,6 +95,9 @@ func bind(flags FlagSet, config interface{}, setupCommand bool, opts ...BindOpt)
|
||||
if opt.isDev != nil {
|
||||
isDev = *opt.isDev
|
||||
}
|
||||
if opt.isSetup != nil {
|
||||
setupCommand = *opt.isSetup
|
||||
}
|
||||
}
|
||||
|
||||
bindConfig(flags, "", reflect.ValueOf(config).Elem(), vars, setupCommand, false, isDev)
|
||||
@ -117,7 +110,7 @@ func bindConfig(flags FlagSet, prefix string, val reflect.Value, vars map[string
|
||||
typ := val.Type()
|
||||
resolvedVars := make(map[string]string, len(vars))
|
||||
{
|
||||
structpath := strings.Replace(prefix, ".", "/", -1)
|
||||
structpath := strings.Replace(prefix, ".", string(filepath.Separator), -1)
|
||||
for k, v := range vars {
|
||||
if !v.nested {
|
||||
resolvedVars[k] = v.val
|
||||
|
@ -5,7 +5,6 @@ package cfgstruct
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
@ -94,23 +93,6 @@ func TestConfDir(t *testing.T) {
|
||||
assertEqual(f.Lookup("my-struct1.my-struct2.string").DefValue, "2confpath3")
|
||||
}
|
||||
|
||||
func TestNesting(t *testing.T) {
|
||||
f := pflag.NewFlagSet("test", pflag.PanicOnError)
|
||||
var c struct {
|
||||
String string `default:"-$CONFDIR+"`
|
||||
MyStruct1 struct {
|
||||
String string `default:"1${CONFDIR}2"`
|
||||
MyStruct2 struct {
|
||||
String string `default:"2${CONFDIR}3"`
|
||||
}
|
||||
}
|
||||
}
|
||||
Bind(f, &c, UseReleaseDefaults(), ConfDirNested("confpath"))
|
||||
assertEqual(f.Lookup("string").DefValue, "-confpath+")
|
||||
assertEqual(f.Lookup("my-struct1.string").DefValue, filepath.FromSlash("1confpath/my-struct12"))
|
||||
assertEqual(f.Lookup("my-struct1.my-struct2.string").DefValue, filepath.FromSlash("2confpath/my-struct1/my-struct23"))
|
||||
}
|
||||
|
||||
func TestBindDevDefaults(t *testing.T) {
|
||||
f := pflag.NewFlagSet("test", pflag.PanicOnError)
|
||||
var c struct {
|
||||
|
@ -22,12 +22,14 @@ import (
|
||||
"github.com/spf13/pflag"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/zeebo/errs"
|
||||
"github.com/zeebo/structs"
|
||||
"go.uber.org/zap"
|
||||
monkit "gopkg.in/spacemonkeygo/monkit.v2"
|
||||
"gopkg.in/spacemonkeygo/monkit.v2/collect"
|
||||
"gopkg.in/spacemonkeygo/monkit.v2/present"
|
||||
|
||||
"storj.io/storj/internal/version"
|
||||
"storj.io/storj/pkg/cfgstruct"
|
||||
)
|
||||
|
||||
// DefaultCfgFilename is the default filename used for storing a configuration.
|
||||
@ -38,8 +40,22 @@ var (
|
||||
|
||||
contextMtx sync.Mutex
|
||||
contexts = map[*cobra.Command]context.Context{}
|
||||
|
||||
configMtx sync.Mutex
|
||||
configs = map[*cobra.Command][]interface{}{}
|
||||
)
|
||||
|
||||
// Bind sets flags on a command that match the configuration struct
|
||||
// 'config'. It ensures that the config has all of the values loaded into it
|
||||
// when the command runs.
|
||||
func Bind(cmd *cobra.Command, config interface{}, opts ...cfgstruct.BindOpt) {
|
||||
configMtx.Lock()
|
||||
defer configMtx.Unlock()
|
||||
|
||||
cfgstruct.Bind(cmd.Flags(), config, opts...)
|
||||
configs[cmd] = append(configs[cmd], config)
|
||||
}
|
||||
|
||||
// Exec runs a Cobra command. If a "config" flag is defined it will be parsed
|
||||
// and loaded using viper.
|
||||
func Exec(cmd *cobra.Command) {
|
||||
@ -195,30 +211,48 @@ func cleanup(cmd *cobra.Command) {
|
||||
}
|
||||
}
|
||||
|
||||
// go back and propagate changed config values to appropriate flags
|
||||
var brokenKeys []string
|
||||
var brokenVals []string
|
||||
for _, key := range vip.AllKeys() {
|
||||
if cmd.Flags().Lookup(key) == nil {
|
||||
// flag couldn't be found
|
||||
brokenKeys = append(brokenKeys, key)
|
||||
} else {
|
||||
flag := cmd.Flag(key)
|
||||
// It's very hard to support string arrays from pflag
|
||||
// because there's no way to unset some value. For now
|
||||
// skip them. They can't be set from viper.
|
||||
if flag.Value.Type() != "stringArray" {
|
||||
oldChanged := flag.Changed
|
||||
configMtx.Lock()
|
||||
configValues := configs[cmd]
|
||||
configMtx.Unlock()
|
||||
|
||||
err := cmd.Flags().Set(key, vip.GetString(key))
|
||||
if err != nil {
|
||||
// flag couldn't be set
|
||||
brokenVals = append(brokenVals, key)
|
||||
}
|
||||
var (
|
||||
brokenKeys = map[string]struct{}{}
|
||||
missingKeys = map[string]struct{}{}
|
||||
usedKeys = map[string]struct{}{}
|
||||
allSettings = vip.AllSettings()
|
||||
)
|
||||
|
||||
// revert Changed value
|
||||
flag.Changed = oldChanged
|
||||
}
|
||||
// Hacky hack: these two keys are noprefix which breaks all scoping
|
||||
if val, ok := allSettings["api-key"]; ok {
|
||||
allSettings["client.api-key"] = val
|
||||
delete(allSettings, "api-key")
|
||||
}
|
||||
if val, ok := allSettings["satellite-addr"]; ok {
|
||||
allSettings["client.satellite-addr"] = val
|
||||
delete(allSettings, "satellite-addr")
|
||||
}
|
||||
|
||||
for _, config := range configValues {
|
||||
// Decode and all of the resulting keys into our sets
|
||||
res := structs.Decode(allSettings, config)
|
||||
for key := range res.Used {
|
||||
usedKeys[key] = struct{}{}
|
||||
}
|
||||
for key := range res.Missing {
|
||||
missingKeys[key] = struct{}{}
|
||||
}
|
||||
for key := range res.Broken {
|
||||
brokenKeys[key] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// Filter the missing keys by removing ones that were used and ones that are flags.
|
||||
for key := range usedKeys {
|
||||
delete(missingKeys, key)
|
||||
}
|
||||
for key := range missingKeys {
|
||||
if cmd.Flags().Lookup(key) != nil {
|
||||
delete(missingKeys, key)
|
||||
}
|
||||
}
|
||||
|
||||
@ -243,11 +277,11 @@ func cleanup(cmd *cobra.Command) {
|
||||
|
||||
// okay now that logging is working, inform about the broken keys
|
||||
if cmd.Annotations["type"] != "helper" {
|
||||
for _, key := range brokenKeys {
|
||||
for key := range missingKeys {
|
||||
logger.Sugar().Infof("Invalid configuration file key: %s", key)
|
||||
}
|
||||
}
|
||||
for _, key := range brokenVals {
|
||||
for key := range brokenKeys {
|
||||
logger.Sugar().Infof("Invalid configuration file value for key: %s", key)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user