github.com/tufanbarisyildirim/pop@v4.13.1+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  	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  }