Skip to content

Commit

Permalink
feat: add viper bindpflags in cmd config (#48)
Browse files Browse the repository at this point in the history
* feat: add viper bindpflags in config

* fix: lint and run go fmt

* fix: config and cmdx

* feat: add loader opts to Load function

* fix(cmdx): recursion on hook

* refactor(cmdx): pass pflags instead of cmd to WithBindFlags

Co-authored-by: Ravi Suhag <[email protected]>
  • Loading branch information
mabdh and ravisuhag authored Sep 12, 2022
1 parent 3e2ab0b commit d28f61d
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 14 deletions.
31 changes: 25 additions & 6 deletions cmdx/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ package cmdx

import (
"errors"
"io/ioutil"
"os"
"path/filepath"
"runtime"

"github.com/mcuadros/go-defaults"
"github.com/odpf/salt/config"
"github.com/spf13/pflag"
"gopkg.in/yaml.v3"
)

Expand All @@ -19,6 +19,14 @@ const (
LOCAL_APP_DATA = "LocalAppData"
)

type ConfigLoaderOpts func(c *Config)

func WithFlags(pfs *pflag.FlagSet) ConfigLoaderOpts {
return func(c *Config) {
c.boundedPFlags = pfs
}
}

// SetConfig allows to set a client config file. It is used to
// load and save a config file for command line clients.
func SetConfig(app string) *Config {
Expand All @@ -28,7 +36,8 @@ func SetConfig(app string) *Config {
}

type Config struct {
filename string
filename string
boundedPFlags *pflag.FlagSet
}

func (c *Config) File() string {
Expand All @@ -55,19 +64,29 @@ func (c *Config) Init(cfg interface{}) error {
os.MkdirAll(configDir("odpf"), 0700)
}

if err := ioutil.WriteFile(c.filename, data, 0655); err != nil {
if err := os.WriteFile(c.filename, data, 0655); err != nil {
return err
}
return nil
}

func (c *Config) Read() (string, error) {
cfg, err := ioutil.ReadFile(c.filename)
cfg, err := os.ReadFile(c.filename)
return string(cfg), err
}

func (c *Config) Load(cfg interface{}) error {
loader := config.NewLoader(config.WithFile(c.filename))
func (c *Config) Load(cfg interface{}, opts ...ConfigLoaderOpts) error {
for _, opt := range opts {
opt(c)
}

loaderOpts := []config.LoaderOption{config.WithFile(c.filename)}

if c.boundedPFlags != nil {
loaderOpts = append(loaderOpts, config.WithBindPFlags(c.boundedPFlags, cfg))
}

loader := config.NewLoader(loaderOpts...)

if err := loader.Load(cfg); err != nil {
return err
Expand Down
14 changes: 14 additions & 0 deletions cmdx/hook.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package cmdx

import "github.com/spf13/cobra"

// SetClientHook applies custom cobra config specific
// for client or cmd that have annotation `client:true`
func SetClientHook(rootCmd *cobra.Command, applyFunc func(cmd *cobra.Command)) {
for _, subCmd := range rootCmd.Commands() {
if subCmd.Annotations != nil && subCmd.Annotations["client"] == "true" {
applyFunc(subCmd)
}
SetClientHook(subCmd, applyFunc)
}
}
28 changes: 28 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/jeremywohl/flatten"
"github.com/mcuadros/go-defaults"
"github.com/mitchellh/mapstructure"
"github.com/spf13/pflag"
"github.com/spf13/viper"
)

Expand Down Expand Up @@ -74,6 +75,33 @@ func WithType(in string) LoaderOption {
}
}

// WithBindPFlags binds viper to pflags based on the
// tags in the struct. Use tag `cmdx` to bind struct
// field to cli flag.
// e.g.
//
// type Config struct {
// Host string `yaml:"host" cmdx:"host"`
// }
func WithBindPFlags(pfs *pflag.FlagSet, cfg interface{}) LoaderOption {
return func(l *Loader) {
reflectedCfg := reflect.TypeOf(cfg).Elem()

var flagTags = []string{}
for i := 0; i < reflectedCfg.NumField(); i++ {
if tag := reflectedCfg.Field(i).Tag.Get("cmdx"); tag != "" {
flagTags = append(flagTags, tag)
}
}

if pfs != nil {
for _, tag := range flagTags {
l.v.BindPFlag(tag, pfs.Lookup(tag))
}
}
}
}

// WithEnvPrefix sets the prefix for keys when checking for configs
// in environment variables. Internally concatenates with keys
// with `_` in between
Expand Down
9 changes: 6 additions & 3 deletions log/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@ type Option func(interface{})
// Each log method must take first string as message and then one or
// more key,value arguments.
// For example:
// timeTaken := time.Duration(time.Second * 1)
// l.Debug("processed request", "time taken", timeTaken)
//
// timeTaken := time.Duration(time.Second * 1)
// l.Debug("processed request", "time taken", timeTaken)
//
// here key should always be a `string` and value could be of any type as
// long as it is printable.
// l.Info("processed request", "time taken", timeTaken, "started at", startedAt)
//
// l.Info("processed request", "time taken", timeTaken, "started at", startedAt)
type Logger interface {

// Debug level message with alternating key/value pairs
Expand Down
11 changes: 6 additions & 5 deletions log/logrus.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,12 @@ func LogrusWithWriter(writer io.Writer) Option {
// LogrusWithFormatter can be used to change default formatting
// by implementing logrus.Formatter
// For example:
// type PlainFormatter struct{}
// func (p *PlainFormatter) Format(entry *logrus.Entry) ([]byte, error) {
// return []byte(entry.Message), nil
// }
// l := log.NewLogrus(log.LogrusWithFormatter(&PlainFormatter{}))
//
// type PlainFormatter struct{}
// func (p *PlainFormatter) Format(entry *logrus.Entry) ([]byte, error) {
// return []byte(entry.Message), nil
// }
// l := log.NewLogrus(log.LogrusWithFormatter(&PlainFormatter{}))
func LogrusWithFormatter(f logrus.Formatter) Option {
return func(logger interface{}) {
logger.(*Logrus).log.SetFormatter(f)
Expand Down
4 changes: 4 additions & 0 deletions printer/text.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,7 @@ func ErrorIcon() {
func InfoIcon() {
fmt.Print(term.Cyan("⛭"))
}

func Space() {
fmt.Print(" ")
}

0 comments on commit d28f61d

Please sign in to comment.