Skip to content

Commit

Permalink
small refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
raulb committed Dec 18, 2024
1 parent 35a8695 commit 3fe7c6f
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 49 deletions.
44 changes: 40 additions & 4 deletions configuration.go → config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,20 @@
package ecdysis

import (
"fmt"
"reflect"
"strings"

"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/spf13/viper"
)

type Config struct {
EnvPrefix string
ParsedCfg any
DefaultCfg any
ConfigPath string
EnvPrefix string
Parsed any
DefaultValues any
Path string
}

// setDefaults sets the default values for the configuration. slices and maps are not supported.
Expand Down Expand Up @@ -71,3 +75,35 @@ func setDefaults(v *viper.Viper, defaults interface{}) {
}
}
}

// parseConfig parses the configuration (from cfg and cmd) into the viper instance.
func parseConfig(v *viper.Viper, cfg Config, cmd *cobra.Command) error {
// Handle env variables
v.SetEnvPrefix(cfg.EnvPrefix)
v.AutomaticEnv()
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))

// Handle config file
v.SetConfigFile(cfg.Path)
if err := v.ReadInConfig(); err != nil {
return fmt.Errorf("fatal error config file: %w", err)
}

var errors []error

// Handle flags
cmd.Flags().VisitAll(func(f *pflag.Flag) {
if err := v.BindPFlag(f.Name, f); err != nil {
errors = append(errors, err)
}
})

if len(errors) > 0 {
var errStrs []string
for _, err := range errors {
errStrs = append(errStrs, err.Error())
}
return fmt.Errorf("error binding flags: %s", strings.Join(errStrs, "; "))
}
return nil
}
65 changes: 20 additions & 45 deletions decorators.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ var DefaultDecorators = []Decorator{
CommandWithAliasesDecorator{},
CommandWithFlagsDecorator{},

// CommandWithParsingConfigDecorator needs to be after CommandWithFlagsDecorator to make sure the flags are parsed.
CommandWithParsingConfigDecorator{},
// CommandWithConfigDecorator needs to be after CommandWithFlagsDecorator to make sure the flags are parsed.
CommandWithConfigDecorator{},

CommandWithDocsDecorator{},
CommandWithHiddenDecorator{},
Expand Down Expand Up @@ -250,19 +250,19 @@ func (CommandWithFlagsDecorator) Decorate(_ *Ecdysis, cmd *cobra.Command, c Comm

// -- PARSING CONFIGURATION --------------------------------------------------------------------

// CommandWithConfiguration can be implemented by a command to parsing configuration.
type CommandWithConfiguration interface {
// CommandWithConfig can be implemented by a command to parsing configuration.
type CommandWithConfig interface {
Command

ParseConfig() Config
Config() Config
}

// CommandWithParsingConfigDecorator is a decorator that sets the command flags.
type CommandWithParsingConfigDecorator struct{}
// CommandWithConfigDecorator is a decorator that sets the command flags.
type CommandWithConfigDecorator struct{}

// Decorate parses the configuration based on flags.
func (CommandWithParsingConfigDecorator) Decorate(_ *Ecdysis, cmd *cobra.Command, c Command) error {
v, ok := c.(CommandWithConfiguration)
func (CommandWithConfigDecorator) Decorate(_ *Ecdysis, cmd *cobra.Command, c Command) error {
v, ok := c.(CommandWithConfig)
if !ok {
return nil
}
Expand All @@ -276,52 +276,27 @@ func (CommandWithParsingConfigDecorator) Decorate(_ *Ecdysis, cmd *cobra.Command
}
}

usrCfg := v.ParseConfig()
cfg := v.Config()

// Ensure ParsedCfg is a pointer
if reflect.ValueOf(usrCfg.ParsedCfg).Kind() != reflect.Ptr {
return fmt.Errorf("ParsedCfg must be a pointer")
// Ensure Parsed is a pointer
if reflect.ValueOf(cfg.Parsed).Kind() != reflect.Ptr {
return fmt.Errorf("parsed must be a pointer")
}

// Ensure both usrCfg.ParsedCfg and usrCfg.DefaultCfg are the same type
if reflect.TypeOf(usrCfg.ParsedCfg) != reflect.TypeOf(usrCfg.DefaultCfg) {
return fmt.Errorf("ParsedCfg and DefaultCfg must be the same type")
// Ensure both cfg.Parsed and cfg.DefaultValues are the same type
if reflect.TypeOf(cfg.Parsed) != reflect.TypeOf(cfg.DefaultValues) {
return fmt.Errorf("parsed and DefaultValues must be the same type")
}

viper := viper.New()

// Set default values
setDefaults(viper, usrCfg.DefaultCfg)
setDefaults(viper, cfg.DefaultValues)

// Handle env variables
viper.SetEnvPrefix(usrCfg.EnvPrefix)
viper.AutomaticEnv()
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))

// Handle config file
viper.SetConfigFile(usrCfg.ConfigPath)
if err := viper.ReadInConfig(); err != nil {
return fmt.Errorf("fatal error config file: %w", err)
}

var errors []error

// Handle flags
cmd.Flags().VisitAll(func(f *pflag.Flag) {
if err := viper.BindPFlag(f.Name, f); err != nil {
errors = append(errors, err)
}
})

if len(errors) > 0 {
var errStrs []string
for _, err := range errors {
errStrs = append(errStrs, err.Error())
}
return fmt.Errorf("error binding flags: %s", strings.Join(errStrs, "; "))
if err := parseConfig(viper, cfg, cmd); err != nil {
return fmt.Errorf("error parsing config: %w", err)
}

if err := viper.Unmarshal(usrCfg.ParsedCfg); err != nil {
if err := viper.Unmarshal(cfg.Parsed); err != nil {
return fmt.Errorf("error unmarshalling config: %w", err)
}
return nil
Expand Down

0 comments on commit 3fe7c6f

Please sign in to comment.