github.com/nshntarora/pop@v0.1.2/config.go (about)

     1  package pop
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  	"io/ioutil"
     9  	"os"
    10  	"path/filepath"
    11  	"text/template"
    12  
    13  	"github.com/gobuffalo/envy"
    14  	"github.com/nshntarora/pop/logging"
    15  	"gopkg.in/yaml.v2"
    16  )
    17  
    18  // ErrConfigFileNotFound is returned when the pop config file can't be found,
    19  // after looking for it.
    20  var ErrConfigFileNotFound = errors.New("unable to find pop config file")
    21  
    22  var lookupPaths = []string{"", "./config", "/config", "../", "../config", "../..", "../../config"}
    23  
    24  // ConfigName is the name of the YAML databases config file
    25  var ConfigName = "database.yml"
    26  
    27  func init() {
    28  	ap := os.Getenv("APP_PATH")
    29  	if ap != "" {
    30  		_ = AddLookupPaths(ap)
    31  	}
    32  	ap = os.Getenv("POP_PATH")
    33  	if ap != "" {
    34  		_ = AddLookupPaths(ap)
    35  	}
    36  }
    37  
    38  // LoadConfigFile loads a POP config file from the configured lookup paths
    39  func LoadConfigFile() error {
    40  	path, err := findConfigPath()
    41  	if err != nil {
    42  		return err
    43  	}
    44  	Connections = map[string]*Connection{}
    45  	log(logging.Debug, "Loading config file from %s", path)
    46  	f, err := os.Open(path)
    47  	if err != nil {
    48  		return err
    49  	}
    50  	defer f.Close()
    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, fmt.Errorf("couldn't parse config template: %w", err)
   112  	}
   113  
   114  	var bb bytes.Buffer
   115  	err = t.Execute(&bb, nil)
   116  	if err != nil {
   117  		return nil, fmt.Errorf("couldn't execute config template: %w", err)
   118  	}
   119  
   120  	deets := map[string]*ConnectionDetails{}
   121  	err = yaml.Unmarshal(bb.Bytes(), &deets)
   122  	if err != nil {
   123  		return nil, fmt.Errorf("couldn't unmarshal config to yaml: %w", err)
   124  	}
   125  	return deets, nil
   126  }