configor.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. package configor
  2. import (
  3. "fmt"
  4. "os"
  5. "reflect"
  6. "regexp"
  7. "time"
  8. )
  9. type Configor struct {
  10. *Config
  11. configModTimes map[string]time.Time
  12. }
  13. type Config struct {
  14. Environment string
  15. ENVPrefix string
  16. Debug bool
  17. Verbose bool
  18. Silent bool
  19. AutoReload bool
  20. AutoReloadInterval time.Duration
  21. AutoReloadCallback func(config interface{})
  22. // In case of json files, this field will be used only when compiled with
  23. // go 1.10 or later.
  24. // This field will be ignored when compiled with go versions lower than 1.10.
  25. ErrorOnUnmatchedKeys bool
  26. }
  27. // New initialize a Configor
  28. func New(config *Config) *Configor {
  29. if config == nil {
  30. config = &Config{}
  31. }
  32. if os.Getenv("CONFIGOR_DEBUG_MODE") != "" {
  33. config.Debug = true
  34. }
  35. if os.Getenv("CONFIGOR_VERBOSE_MODE") != "" {
  36. config.Verbose = true
  37. }
  38. if os.Getenv("CONFIGOR_SILENT_MODE") != "" {
  39. config.Silent = true
  40. }
  41. if config.AutoReload && config.AutoReloadInterval == 0 {
  42. config.AutoReloadInterval = time.Second
  43. }
  44. return &Configor{Config: config}
  45. }
  46. var testRegexp = regexp.MustCompile("_test|(\\.test$)")
  47. // GetEnvironment get environment
  48. func (configor *Configor) GetEnvironment() string {
  49. if configor.Environment == "" {
  50. if env := os.Getenv("CONFIGOR_ENV"); env != "" {
  51. return env
  52. }
  53. if testRegexp.MatchString(os.Args[0]) {
  54. return "test"
  55. }
  56. return "development"
  57. }
  58. return configor.Environment
  59. }
  60. // GetErrorOnUnmatchedKeys returns a boolean indicating if an error should be
  61. // thrown if there are keys in the config file that do not correspond to the
  62. // config struct
  63. func (configor *Configor) GetErrorOnUnmatchedKeys() bool {
  64. return configor.ErrorOnUnmatchedKeys
  65. }
  66. // Load will unmarshal configurations to struct from files that you provide
  67. func (configor *Configor) Load(config interface{}, files ...string) (err error) {
  68. defaultValue := reflect.Indirect(reflect.ValueOf(config))
  69. if !defaultValue.CanAddr() {
  70. return fmt.Errorf("Config %v should be addressable", config)
  71. }
  72. err, _ = configor.load(config, false, files...)
  73. if configor.Config.AutoReload {
  74. go func() {
  75. timer := time.NewTimer(configor.Config.AutoReloadInterval)
  76. for range timer.C {
  77. reflectPtr := reflect.New(reflect.ValueOf(config).Elem().Type())
  78. reflectPtr.Elem().Set(defaultValue)
  79. var changed bool
  80. if err, changed = configor.load(reflectPtr.Interface(), true, files...); err == nil && changed {
  81. reflect.ValueOf(config).Elem().Set(reflectPtr.Elem())
  82. if configor.Config.AutoReloadCallback != nil {
  83. configor.Config.AutoReloadCallback(config)
  84. }
  85. } else if err != nil {
  86. fmt.Printf("Failed to reload configuration from %v, got error %v\n", files, err)
  87. }
  88. timer.Reset(configor.Config.AutoReloadInterval)
  89. }
  90. }()
  91. }
  92. return
  93. }
  94. // ENV return environment
  95. func ENV() string {
  96. return New(nil).GetEnvironment()
  97. }
  98. // Load will unmarshal configurations to struct from files that you provide
  99. func Load(config interface{}, files ...string) error {
  100. return New(nil).Load(config, files...)
  101. }