config/shared.go (65 lines of code) (raw):
package config
import (
"errors"
"fmt"
"github.com/spf13/viper"
"os"
"reflect"
"unicode"
)
func load(path string, data interface{}) error {
if path == "" {
return errors.New("empty path to config")
}
_, err := os.ReadFile(path)
if err != nil {
return err
}
v := viper.New()
v.SetConfigFile(path)
v.SetConfigType("json")
if err := v.ReadInConfig(); err != nil {
return err
}
return v.Unmarshal(data)
}
func override(prefix string, data interface{}) error {
v := viper.New()
v.SetEnvPrefix(prefix)
pointerType := reflect.TypeOf(data)
if pointerType.Kind() != reflect.Ptr {
return errors.New("data not a pointer to struct")
}
dataType := pointerType.Elem()
if dataType.Kind() != reflect.Struct {
return errors.New("data not a pointer to struct")
}
keys := make([]string, dataType.NumField())
for i := 0; i < dataType.NumField(); i++ {
keys = append(keys, dataType.Field(i).Name)
}
for _, key := range keys {
if key == "" {
continue
}
variable := fmt.Sprintf("%s_%s", prefix, toEnvironmentVariable(key))
if err := v.BindEnv(key, variable); err != nil {
return err
}
}
return v.Unmarshal(data)
}
func toEnvironmentVariable(name string) string {
output := ""
runes := []rune(name)
var c, p rune
for i := 0; i < len(runes); i++ {
c = runes[i]
if unicode.IsUpper(c) && unicode.IsLower(p) {
output += "_"
}
output += string(unicode.ToUpper(c))
p = c
}
return output
}