penv.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. package penv
  2. import (
  3. "flag"
  4. "fmt"
  5. "os"
  6. "reflect"
  7. "strconv"
  8. "strings"
  9. "golang.org/x/text/cases"
  10. "golang.org/x/text/language"
  11. )
  12. var Prefix = "ENV_"
  13. type DumpVar struct {
  14. Name string
  15. NameEnv string
  16. NameFlag string
  17. Desc string
  18. Type string
  19. Value string
  20. Secret bool
  21. }
  22. func generate(name string) string {
  23. n := ""
  24. prevBig := true
  25. for i, char := range name {
  26. if i > 0 && string(char) == strings.ToUpper(string(char)) && !prevBig {
  27. n += "_"
  28. }
  29. if string(char) == strings.ToUpper(string(char)) {
  30. prevBig = true
  31. } else {
  32. prevBig = false
  33. }
  34. n += string(char)
  35. }
  36. return n
  37. }
  38. func generateEnvName(name string) string {
  39. return strings.ToUpper(Prefix + generate(name))
  40. }
  41. func generateFlagName(name string) string {
  42. return strings.ToLower(generate(name))
  43. }
  44. func stringToInt(value string) (int, error) {
  45. return strconv.Atoi(value)
  46. }
  47. func stringToInt64(value string) (int64, error) {
  48. return strconv.ParseInt(value, 10, 64)
  49. }
  50. func DumpConfig(config any) map[string]DumpVar {
  51. res := map[string]DumpVar{}
  52. v := reflect.ValueOf(config).Elem()
  53. t := v.Type()
  54. for i := 0; i < t.NumField(); i++ {
  55. nameEnv := generateEnvName(t.Field(i).Name)
  56. fieldType := t.Field(i).Type.Kind().String()
  57. nameFlag := generateFlagName(t.Field(i).Name)
  58. description := t.Field(i).Tag.Get("description")
  59. if description == "" {
  60. description = "No description"
  61. }
  62. secret := t.Field(i).Tag.Get("secret")
  63. if fieldType == "string" {
  64. res[t.Field(i).Name] = DumpVar{
  65. Name: t.Field(i).Name,
  66. NameEnv: nameEnv,
  67. NameFlag: nameFlag,
  68. Desc: description,
  69. Type: cases.Title(language.English).String(fieldType),
  70. Value: *v.Field(i).Addr().Interface().(*string),
  71. Secret: secret == "1" || secret == "true",
  72. }
  73. } else if fieldType == "int" {
  74. res[t.Field(i).Name] = DumpVar{
  75. Name: t.Field(i).Name,
  76. NameEnv: nameEnv,
  77. NameFlag: nameFlag,
  78. Desc: description,
  79. Type: cases.Title(language.English).String(fieldType),
  80. Value: fmt.Sprintf("%d", *v.Field(i).Addr().Interface().(*int)),
  81. Secret: secret == "1" || secret == "true",
  82. }
  83. } else if fieldType == "int64" {
  84. res[t.Field(i).Name] = DumpVar{
  85. Name: t.Field(i).Name,
  86. NameEnv: nameEnv,
  87. NameFlag: nameFlag,
  88. Desc: description,
  89. Type: cases.Title(language.English).String(fieldType),
  90. Value: fmt.Sprintf("%d", *v.Field(i).Addr().Interface().(*int64)),
  91. Secret: secret == "1" || secret == "true",
  92. }
  93. }
  94. }
  95. return res
  96. }
  97. func ProcessConfig(config any) error {
  98. v := reflect.ValueOf(config).Elem()
  99. t := v.Type()
  100. // Process flags
  101. for i := 0; i < t.NumField(); i++ {
  102. nameEnv := generateEnvName(t.Field(i).Name)
  103. nameFlag := generateFlagName(t.Field(i).Name)
  104. fieldType := t.Field(i).Type.Kind().String()
  105. defvalue := t.Field(i).Tag.Get("default")
  106. description := t.Field(i).Tag.Get("description")
  107. if description == "" {
  108. description = "No description"
  109. }
  110. if fieldType == "string" {
  111. value := v.Field(i).Addr().Interface().(*string)
  112. flag.StringVar(value, nameFlag, defvalue, "Or "+nameEnv+": "+description)
  113. } else if fieldType == "int" {
  114. if ndefvalue, err := stringToInt(defvalue); err == nil {
  115. value := v.Field(i).Addr().Interface().(*int)
  116. flag.IntVar(value, nameFlag, ndefvalue, "Or "+nameEnv+": "+description)
  117. } else {
  118. return err
  119. }
  120. } else if fieldType == "int64" {
  121. if ndefvalue, err := stringToInt64(defvalue); err == nil {
  122. value := v.Field(i).Addr().Interface().(*int64)
  123. flag.Int64Var(value, nameFlag, ndefvalue, "Or "+nameEnv+": "+description)
  124. } else {
  125. return err
  126. }
  127. }
  128. }
  129. flag.Parse()
  130. // Process ENVs
  131. for i := 0; i < t.NumField(); i++ {
  132. nameEnv := generateEnvName(t.Field(i).Name)
  133. fieldType := t.Field(i).Type.Kind().String()
  134. if os.Getenv(nameEnv) != "" {
  135. if fieldType == "string" {
  136. value := v.Field(i).Addr().Interface().(*string)
  137. *value = os.Getenv(nameEnv)
  138. } else if fieldType == "int" {
  139. if nvalue, err := stringToInt(os.Getenv(nameEnv)); err == nil {
  140. value := v.Field(i).Addr().Interface().(*int)
  141. *value = nvalue
  142. } else {
  143. return err
  144. }
  145. } else if fieldType == "int64" {
  146. if nvalue, err := stringToInt64(os.Getenv(nameEnv)); err == nil {
  147. value := v.Field(i).Addr().Interface().(*int64)
  148. *value = nvalue
  149. } else {
  150. return err
  151. }
  152. }
  153. }
  154. }
  155. return nil
  156. }