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 }