Browse Source

Move penv package

Volodymyr Tkach 2 years ago
parent
commit
5edc8193bf
1 changed files with 175 additions and 0 deletions
  1. 175 0
      utils/penv/penv.go

+ 175 - 0
utils/penv/penv.go

@@ -0,0 +1,175 @@
+package penv
+
+import (
+	"flag"
+	"fmt"
+	"os"
+	"reflect"
+	"strconv"
+	"strings"
+
+	"golang.org/x/text/cases"
+	"golang.org/x/text/language"
+)
+
+var Prefix = "ENV_"
+
+type DumpVar struct {
+	Name     string
+	NameEnv  string
+	NameFlag string
+	Desc     string
+	Type     string
+	Value    string
+	Secret   bool
+}
+
+func generate(name string) string {
+	n := ""
+	prevBig := true
+	for i, char := range name {
+		if i > 0 && string(char) == strings.ToUpper(string(char)) && !prevBig {
+			n += "_"
+		}
+		if string(char) == strings.ToUpper(string(char)) {
+			prevBig = true
+		} else {
+			prevBig = false
+		}
+		n += string(char)
+	}
+	return n
+}
+
+func generateEnvName(name string) string {
+	return strings.ToUpper(Prefix + generate(name))
+}
+
+func generateFlagName(name string) string {
+	return strings.ToLower(generate(name))
+}
+
+func stringToInt(value string) (int, error) {
+	return strconv.Atoi(value)
+}
+
+func stringToInt64(value string) (int64, error) {
+	return strconv.ParseInt(value, 10, 64)
+}
+
+func DumpConfig(config any) map[string]DumpVar {
+	res := map[string]DumpVar{}
+
+	v := reflect.ValueOf(config).Elem()
+	t := v.Type()
+
+	for i := 0; i < t.NumField(); i++ {
+		nameEnv := generateEnvName(t.Field(i).Name)
+		fieldType := t.Field(i).Type.Kind().String()
+		nameFlag := generateFlagName(t.Field(i).Name)
+		description := t.Field(i).Tag.Get("description")
+		if description == "" {
+			description = "No description"
+		}
+		secret := t.Field(i).Tag.Get("secret")
+		if fieldType == "string" {
+			res[t.Field(i).Name] = DumpVar{
+				Name:     t.Field(i).Name,
+				NameEnv:  nameEnv,
+				NameFlag: nameFlag,
+				Desc:     description,
+				Type:     cases.Title(language.English).String(fieldType),
+				Value:    *v.Field(i).Addr().Interface().(*string),
+				Secret:   secret == "1" || secret == "true",
+			}
+		} else if fieldType == "int" {
+			res[t.Field(i).Name] = DumpVar{
+				Name:     t.Field(i).Name,
+				NameEnv:  nameEnv,
+				NameFlag: nameFlag,
+				Desc:     description,
+				Type:     cases.Title(language.English).String(fieldType),
+				Value:    fmt.Sprintf("%d", *v.Field(i).Addr().Interface().(*int)),
+				Secret:   secret == "1" || secret == "true",
+			}
+		} else if fieldType == "int64" {
+			res[t.Field(i).Name] = DumpVar{
+				Name:     t.Field(i).Name,
+				NameEnv:  nameEnv,
+				NameFlag: nameFlag,
+				Desc:     description,
+				Type:     cases.Title(language.English).String(fieldType),
+				Value:    fmt.Sprintf("%d", *v.Field(i).Addr().Interface().(*int64)),
+				Secret:   secret == "1" || secret == "true",
+			}
+		}
+	}
+
+	return res
+}
+
+func ProcessConfig(config any) error {
+	v := reflect.ValueOf(config).Elem()
+	t := v.Type()
+
+	// Process flags
+	for i := 0; i < t.NumField(); i++ {
+		nameEnv := generateEnvName(t.Field(i).Name)
+		nameFlag := generateFlagName(t.Field(i).Name)
+		fieldType := t.Field(i).Type.Kind().String()
+		defvalue := t.Field(i).Tag.Get("default")
+		description := t.Field(i).Tag.Get("description")
+		if description == "" {
+			description = "No description"
+		}
+
+		if fieldType == "string" {
+			value := v.Field(i).Addr().Interface().(*string)
+			flag.StringVar(value, nameFlag, defvalue, "Or "+nameEnv+": "+description)
+		} else if fieldType == "int" {
+			if ndefvalue, err := stringToInt(defvalue); err == nil {
+				value := v.Field(i).Addr().Interface().(*int)
+				flag.IntVar(value, nameFlag, ndefvalue, "Or "+nameEnv+": "+description)
+			} else {
+				return err
+			}
+		} else if fieldType == "int64" {
+			if ndefvalue, err := stringToInt64(defvalue); err == nil {
+				value := v.Field(i).Addr().Interface().(*int64)
+				flag.Int64Var(value, nameFlag, ndefvalue, "Or "+nameEnv+": "+description)
+			} else {
+				return err
+			}
+		}
+	}
+	flag.Parse()
+
+	// Process ENVs
+	for i := 0; i < t.NumField(); i++ {
+		nameEnv := generateEnvName(t.Field(i).Name)
+		fieldType := t.Field(i).Type.Kind().String()
+
+		if os.Getenv(nameEnv) != "" {
+			if fieldType == "string" {
+				value := v.Field(i).Addr().Interface().(*string)
+				*value = os.Getenv(nameEnv)
+			} else if fieldType == "int" {
+				if nvalue, err := stringToInt(os.Getenv(nameEnv)); err == nil {
+					value := v.Field(i).Addr().Interface().(*int)
+					*value = nvalue
+				} else {
+					return err
+				}
+			} else if fieldType == "int64" {
+				if nvalue, err := stringToInt64(os.Getenv(nameEnv)); err == nil {
+					value := v.Field(i).Addr().Interface().(*int64)
+					*value = nvalue
+				} else {
+					return err
+				}
+			}
+		}
+	}
+
+	return nil
+}