package config import ( "bytes" "fmt" "io" "os" "path/filepath" ) const ( ConfigEnvPrefix = "CONFIG_ENV_PREFIX" ConfigTagEnv = "env" ) type Config interface { SetConfigPath(in string) error Load(target interface{}, files ...string) error LoadReader(target interface{}, ext string, in io.Reader) error SetEnvPrefix(in string) } type configuration struct { configPath string // Name of file to look for inside the path envPrefix string } func New() Config { return &configuration{} } var _c *configuration func init() { _c = New().(*configuration) } // SetConfigPath set a path to search for the config file in. func SetConfigPath(in string) error { return _c.SetConfigPath(in) } func (c *configuration) 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 *configuration) 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 *configuration) Load(target interface{}, files ...string) error { filenames := c.getConfigFiles(files...) if 0 == len(filenames) { return fmt.Errorf("Config: have no config files in [%v]", 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 *configuration) 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 { var absPath string var err error if absPath, err = ABSPathify(file); nil != err { return err } return marshalFile(target, absPath, overWrite) } // 1. file // 2. configPath/file func (c *configuration) getConfigFiles(files ...string) []string { var results []string for _, file := range files { // check configuration if absin, err := ABSPathify(file); nil == err { if Exists(absin) { results = append(results, absin) } } } 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 *configuration) getENVPrefix() string { if c.envPrefix == "" { if prefix := os.Getenv(ConfigEnvPrefix); prefix != "" { return prefix } return "" } return c.envPrefix }