github.com/rjgonzale/pop/v5@v5.1.3-dev/config.go (about) 1 package pop 2 3 import ( 4 "bytes" 5 "io" 6 "io/ioutil" 7 "os" 8 "path/filepath" 9 "text/template" 10 11 "github.com/gobuffalo/envy" 12 "github.com/gobuffalo/pop/v5/logging" 13 "github.com/pkg/errors" 14 "gopkg.in/yaml.v2" 15 ) 16 17 // ErrConfigFileNotFound is returned when the pop config file can't be found, 18 // after looking for it. 19 var ErrConfigFileNotFound = errors.New("unable to find pop config file") 20 21 var lookupPaths = []string{"", "./config", "/config", "../", "../config", "../..", "../../config"} 22 23 // ConfigName is the name of the YAML databases config file 24 var ConfigName = "database.yml" 25 26 func init() { 27 SetLogger(defaultLogger) 28 29 ap := os.Getenv("APP_PATH") 30 if ap != "" { 31 _ = AddLookupPaths(ap) 32 } 33 ap = os.Getenv("POP_PATH") 34 if ap != "" { 35 _ = AddLookupPaths(ap) 36 } 37 } 38 39 // LoadConfigFile loads a POP config file from the configured lookup paths 40 func LoadConfigFile() error { 41 path, err := findConfigPath() 42 if err != nil { 43 return err 44 } 45 Connections = map[string]*Connection{} 46 log(logging.Debug, "Loading config file from %s", path) 47 f, err := os.Open(path) 48 if err != nil { 49 return err 50 } 51 defer f.Close() 52 return LoadFrom(f) 53 } 54 55 // LookupPaths returns the current configuration lookup paths 56 func LookupPaths() []string { 57 return lookupPaths 58 } 59 60 // AddLookupPaths add paths to the current lookup paths list 61 func AddLookupPaths(paths ...string) error { 62 lookupPaths = append(paths, lookupPaths...) 63 return nil 64 } 65 66 func findConfigPath() (string, error) { 67 for _, p := range LookupPaths() { 68 path, _ := filepath.Abs(filepath.Join(p, ConfigName)) 69 if _, err := os.Stat(path); err == nil { 70 return path, err 71 } 72 } 73 return "", ErrConfigFileNotFound 74 } 75 76 // LoadFrom reads a configuration from the reader and sets up the connections 77 func LoadFrom(r io.Reader) error { 78 envy.Load() 79 deets, err := ParseConfig(r) 80 if err != nil { 81 return err 82 } 83 for n, d := range deets { 84 con, err := NewConnection(d) 85 if err != nil { 86 log(logging.Warn, "unable to load connection %s: %v", n, err) 87 continue 88 } 89 Connections[n] = con 90 } 91 return nil 92 } 93 94 // ParseConfig reads the pop config from the given io.Reader and returns 95 // the parsed ConnectionDetails map. 96 func ParseConfig(r io.Reader) (map[string]*ConnectionDetails, error) { 97 tmpl := template.New("test") 98 tmpl.Funcs(map[string]interface{}{ 99 "envOr": func(s1, s2 string) string { 100 return envy.Get(s1, s2) 101 }, 102 "env": func(s1 string) string { 103 return envy.Get(s1, "") 104 }, 105 }) 106 b, err := ioutil.ReadAll(r) 107 if err != nil { 108 return nil, err 109 } 110 t, err := tmpl.Parse(string(b)) 111 if err != nil { 112 return nil, errors.Wrap(err, "couldn't parse config template") 113 } 114 115 var bb bytes.Buffer 116 err = t.Execute(&bb, nil) 117 if err != nil { 118 return nil, errors.Wrap(err, "couldn't execute config template") 119 } 120 121 deets := map[string]*ConnectionDetails{} 122 err = yaml.Unmarshal(bb.Bytes(), &deets) 123 return deets, errors.Wrap(err, "couldn't unmarshal config to yaml") 124 }