github.com/Benchkram/bob@v0.0.0-20220321080157-7c8f3876e225/cli/config.go (about)

     1  package cli
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/Benchkram/errz"
     7  
     8  	"github.com/fatih/structs"
     9  	"github.com/sanity-io/litter"
    10  	"github.com/spf13/viper"
    11  )
    12  
    13  // global configuration through a config file, environment vars  cli parameters.
    14  
    15  //  Config the global config object
    16  var GlobalConfig *config // nolint:varcheck, unused
    17  
    18  // Create private data struct to hold config options.
    19  // `mapstructure` => viper tags
    20  // `struct` => fatih structs tag
    21  type config struct {
    22  	Verbosity  int  `mapstructure:"verbosity" structs:"verbosity"`
    23  	CPUProfile bool `mapstructure:"cpuprofile" structs:"cpuprofile"`
    24  	MEMProfile bool `mapstructure:"memprofile" structs:"memprofile"`
    25  }
    26  
    27  var defaultConfig = &config{
    28  	Verbosity:  1,
    29  	CPUProfile: false,
    30  	MEMProfile: false,
    31  }
    32  
    33  func (c *config) AsMap() map[string]interface{} {
    34  	return structs.Map(c)
    35  }
    36  
    37  func (c *config) Print() {
    38  	litter.Dump(c)
    39  }
    40  
    41  // configInit must be called from the packages init() func
    42  func configInit() {
    43  	flags()
    44  	bind()
    45  	env()
    46  }
    47  
    48  func flags() {
    49  	rootCmd.PersistentFlags().IntP("verbosity", "v", defaultConfig.Verbosity, "set verbosity level")
    50  	rootCmd.PersistentFlags().Bool("cpuprofile", defaultConfig.CPUProfile, "write cpu profile to file")
    51  	rootCmd.PersistentFlags().Bool("memprofile", defaultConfig.MEMProfile, "write memory profile to file")
    52  }
    53  func bind() {
    54  	errz.Fatal(viper.BindPFlag("verbosity", rootCmd.PersistentFlags().Lookup("verbosity")))
    55  	errz.Fatal(viper.BindPFlag("cpuprofile", rootCmd.PersistentFlags().Lookup("cpuprofile")))
    56  	errz.Fatal(viper.BindPFlag("memprofile", rootCmd.PersistentFlags().Lookup("memprofile")))
    57  }
    58  func env() {
    59  	errz.Fatal(viper.BindEnv("verbosity", "BOB_VERBOSITY"))
    60  	errz.Fatal(viper.BindEnv("cpuprofile", "BOB_CPU_PROFILE"))
    61  	errz.Fatal(viper.BindEnv("memprofile", "BOB_MEM_PROFILE"))
    62  }
    63  
    64  // readConfig a helper to read default from a default config object.
    65  func readConfig(defaults map[string]interface{}) (*config, error) {
    66  	for key, value := range defaults {
    67  		viper.SetDefault(key, value)
    68  	}
    69  
    70  	//Read config from file
    71  	viper.SetConfigName("config")
    72  	viper.AddConfigPath(".")
    73  	err := viper.ReadInConfig()
    74  	switch err.(type) {
    75  	case viper.ConfigFileNotFoundError:
    76  		// fmt.Printf("%s\n", aurora.Yellow("Could not find a config file"))
    77  	default:
    78  		return nil, fmt.Errorf("config file invalid: %w", err)
    79  	}
    80  
    81  	c := &config{}
    82  	err = viper.Unmarshal(c)
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  	return c, nil
    87  }
    88  
    89  func readGlobalConfig() {
    90  	// Priority of configuration options
    91  	// 1: CLI Parameters
    92  	// 2: environment
    93  	// 2: config.yaml
    94  	// 3: defaults
    95  	config, err := readConfig(defaultConfig.AsMap())
    96  	if err != nil {
    97  		fmt.Println(err.Error())
    98  		return
    99  	}
   100  	GlobalConfig = config
   101  }