github.com/pjdufour-truss/pop@v4.11.2-0.20190705085848-4c90b0ff4d5a+incompatible/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/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 return LoadFrom(f) 52 } 53 54 // LookupPaths returns the current configuration lookup paths 55 func LookupPaths() []string { 56 return lookupPaths 57 } 58 59 // AddLookupPaths add paths to the current lookup paths list 60 func AddLookupPaths(paths ...string) error { 61 lookupPaths = append(paths, lookupPaths...) 62 return nil 63 } 64 65 func findConfigPath() (string, error) { 66 for _, p := range LookupPaths() { 67 path, _ := filepath.Abs(filepath.Join(p, ConfigName)) 68 if _, err := os.Stat(path); err == nil { 69 return path, err 70 } 71 } 72 return "", ErrConfigFileNotFound 73 } 74 75 // LoadFrom reads a configuration from the reader and sets up the connections 76 func LoadFrom(r io.Reader) error { 77 envy.Load() 78 deets, err := ParseConfig(r) 79 if err != nil { 80 return err 81 } 82 for n, d := range deets { 83 con, err := NewConnection(d) 84 if err != nil { 85 log(logging.Warn, "unable to load connection %s: %v", n, err) 86 continue 87 } 88 Connections[n] = con 89 } 90 return nil 91 } 92 93 // ParseConfig reads the pop config from the given io.Reader and returns 94 // the parsed ConnectionDetails map. 95 func ParseConfig(r io.Reader) (map[string]*ConnectionDetails, error) { 96 tmpl := template.New("test") 97 tmpl.Funcs(map[string]interface{}{ 98 "envOr": func(s1, s2 string) string { 99 return envy.Get(s1, s2) 100 }, 101 "env": func(s1 string) string { 102 return envy.Get(s1, "") 103 }, 104 }) 105 b, err := ioutil.ReadAll(r) 106 if err != nil { 107 return nil, err 108 } 109 t, err := tmpl.Parse(string(b)) 110 if err != nil { 111 return nil, errors.Wrap(err, "couldn't parse config template") 112 } 113 114 var bb bytes.Buffer 115 err = t.Execute(&bb, nil) 116 if err != nil { 117 return nil, errors.Wrap(err, "couldn't execute config template") 118 } 119 120 deets := map[string]*ConnectionDetails{} 121 err = yaml.Unmarshal(bb.Bytes(), &deets) 122 return deets, errors.Wrap(err, "couldn't unmarshal config to yaml") 123 }