Skip to content

Commit

Permalink
Add recursively configuration lookup
Browse files Browse the repository at this point in the history
  • Loading branch information
berlam committed Oct 4, 2019
1 parent aa36466 commit ff435d1
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 25 deletions.
78 changes: 61 additions & 17 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package cmd

import (
"bytes"
"eager/internal"
"fmt"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/spf13/viper"
"io/ioutil"
"log"
"os"
"path/filepath"
Expand All @@ -23,24 +25,18 @@ func init() {
}

// Lookup Configuration by going up the current directory
wd, err := os.Getwd()
file, err := os.Getwd()
if err != nil {
return
}
viper.SetConfigName("eager")
for true {
file := filepath.Clean(wd + string(filepath.Separator) + "eager.yaml")
_, err := os.Stat(file)
if os.IsNotExist(err) {
nd, err := filepath.Abs(wd + string(filepath.Separator) + "..")
if err != nil || nd == wd {
break
}
wd = nd
continue
viper.AddConfigPath(file)
nd, err := filepath.Abs(file + string(filepath.Separator) + "..")
if err != nil || nd == file {
break
}
// Found Configuration file
viper.SetConfigFile(file)
break
file = nd
}
})

Expand All @@ -58,14 +54,35 @@ var rootCmd = &cobra.Command{
Args: cobra.NoArgs,
Version: internal.Version,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
cmd.Flags().VisitAll(func(flag *pflag.Flag) {
// Unbind configuration flag, otherwise argument would overwrite config file values
if flag.Name == internal.FlagConfiguration {
return
}
// Bind the rest
err := viper.BindPFlag(flag.Name, flag)
if err != nil {
return
}
})
err := viper.ReadInConfig()
if viper.ConfigFileUsed() != "" {
viper.BindPFlags(cmd.Flags())
if err := viper.ReadInConfig(); err != nil {
if err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
return fmt.Errorf("can't read conf. %s", err.Error())
return fmt.Errorf("cannot read conf. %s", err.Error())
}
}
if viper.GetString(internal.FlagConfiguration) != "" {
known := make(map[string]*struct{})
err := parseConfiguration(known, viper.ConfigFileUsed())
if err != nil {
return fmt.Errorf("cannot read conf. %s", err.Error())
}
}
viper.Unmarshal(&conf)
err = viper.Unmarshal(&conf)
if err != nil {
return err
}
}
// Remove required annotation if the user has that flag given with viper.
cmd.Flags().VisitAll(func(flag *pflag.Flag) {
Expand All @@ -78,6 +95,33 @@ var rootCmd = &cobra.Command{
},
}

func parseConfiguration(configurations map[string]*struct{}, parent string) error {
parent, _ = filepath.Abs(parent)
if configurations[parent] != nil {
return fmt.Errorf("there is a recursion in you configuration definition")
}
configurations[parent] = &struct{}{}
file, err := ioutil.ReadFile(parent)
if err != nil {
return fmt.Errorf("cannot read file %s", parent)
}
err = viper.ReadConfig(bytes.NewReader(file))
if err != nil {
return fmt.Errorf("cannot parse file %s", parent)
}
parent = viper.GetString(internal.FlagConfiguration)
if parent == "" {
// Nu further parent. Take that already read config
return nil
}
err = parseConfiguration(configurations, parent)
if err != nil {
return err
}
// Merge the rest
return viper.MergeConfig(bytes.NewReader(file))
}

func Execute() {
if err := rootCmd.Execute(); err != nil {
log.Fatal(err)
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require (
github.com/headzoo/ut v0.0.0-20181013193318-a13b5a7a02ca // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/magiconair/properties v1.8.0
github.com/mitchellh/mapstructure v1.1.2
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c // indirect
github.com/opencontainers/runc v0.1.1 // indirect
github.com/spf13/afero v1.2.2 // indirect
Expand Down
17 changes: 9 additions & 8 deletions internal/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,15 @@ const (
)

type Configuration struct {
Http bool `mapstructure:"http"`
Host string `mapstructure:"host"`
Username string `mapstructure:"username"`
Password string `mapstructure:"password"`
Projects []string `mapstructure:"projects"`
Users []string `mapstructure:"users"`
Report string `mapstructure:"report"`
Duration DurationOptions `mapstructure:",squash"`
ParentConfiguration string `mapstructure:"configuration"`
Http bool `mapstructure:"http"`
Host string `mapstructure:"host"`
Username string `mapstructure:"username"`
Password string `mapstructure:"password"`
Projects []string `mapstructure:"projects"`
Users []string `mapstructure:"users"`
Report string `mapstructure:"report"`
Duration DurationOptions `mapstructure:",squash"`
// These items make no sense to have inside a configuration file
Year int
Month int
Expand Down

0 comments on commit ff435d1

Please sign in to comment.