package config import ( "bytes" "io" "os" "path/filepath" ) const ( ConfigEnvPrefix = "CONFIG_ENV_PREFIX" ConfigTagEnv = "env" ) type Configurator interface { SetConfigPath(in string) error Load(target interface{}, files ...string) error LoadReader(target interface{}, ext string, in io.Reader) error Save(target interface{}, file string, overWrite bool) error SetEnvPrefix(in string) } type config struct { configPath string // Name of file to look for inside the path envPrefix string } func New() Configurator { return &config{} } var _c *config func init() { _c = New().(*config) } // SetConfigPath set a path to search for the config file in. func SetConfigPath(in string) error { return _c.SetConfigPath(in) } func (c *config) SetConfigPath(in string) error { if in != "" { absin, err := absPathify(in) if nil != err { return err } c.configPath = absin } return nil } // SetEnvPrefix set a prefix to search for the env variable. func SetEnvPrefix(in string) { _c.SetEnvPrefix(in) } func (c *config) SetEnvPrefix(in string) { if in != "" { c.envPrefix = in } } // Load will unmarshal from configuration file from disk func Load(target interface{}, files ...string) error { return _c.Load(target, files...) } func (c *config) Load(target interface{}, files ...string) error { filenames := c.getConfigFiles(files...) for _, file := range filenames { if err := unmarshalFile(target, file); err != nil { return err } } return unmarshalTags(target, c.getENVPrefix()) } // LoadReader will unmarshal from configuration bytes func LoadReader(target interface{}, ext string, in io.Reader) error { return _c.LoadReader(target, ext, in) } func (c *config) LoadReader(target interface{}, ext string, in io.Reader) error { buf := new(bytes.Buffer) buf.ReadFrom(in) return unmarshalData(target, ext, buf.Bytes()) } // Save store to configuration file from disk func Save(target interface{}, file string, overWrite bool) error { return _c.Save(target, file, overWrite) } func (c *config) Save(target interface{}, file string, overWrite bool) error { return marshalFile(target, file, overWrite) } // 1. file // 2. configPath/file func (c *config) getConfigFiles(files ...string) []string { var results []string for _, file := range files { // check configuration if exists(file) { results = append(results, file) } } for _, file := range files { // check configuration if absin, err := absPathify(filepath.Join(c.configPath, file)); nil == err { if exists(absin) { results = append(results, absin) } } } return results } func (c *config) getENVPrefix() string { if c.envPrefix == "" { if prefix := os.Getenv(ConfigEnvPrefix); prefix != "" { return prefix } return "" } return c.envPrefix }