github.com/ndau/noms@v1.0.5/go/config/config.go (about) 1 // Copyright 2016 Attic Labs, Inc. All rights reserved. 2 // Licensed under the Apache License, version 2.0: 3 // http://www.apache.org/licenses/LICENSE-2.0 4 5 package config 6 7 import ( 8 "bytes" 9 "errors" 10 "fmt" 11 "io/ioutil" 12 "os" 13 "path/filepath" 14 15 "github.com/BurntSushi/toml" 16 "github.com/ndau/noms/go/spec" 17 ) 18 19 type Config struct { 20 File string 21 Db map[string]DbConfig 22 } 23 24 type DbConfig struct { 25 Url string 26 } 27 28 const ( 29 NomsConfigFile = ".nomsconfig" 30 DefaultDbAlias = "default" 31 ) 32 33 var NoConfig = errors.New(fmt.Sprintf("no %s found", NomsConfigFile)) 34 35 // Find the closest directory containing .nomsconfig starting 36 // in cwd and then searching up ancestor tree. 37 // Look first looking in cwd and then up through its ancestors 38 func FindNomsConfig() (*Config, error) { 39 curDir, err := os.Getwd() 40 if err != nil { 41 return nil, err 42 } 43 for { 44 nomsConfig := filepath.Join(curDir, NomsConfigFile) 45 info, err := os.Stat(nomsConfig) 46 if err == nil && !info.IsDir() { 47 // found 48 return ReadConfig(nomsConfig) 49 } else if err != nil && !os.IsNotExist(err) { 50 // can't read 51 return nil, err 52 } 53 nextDir := filepath.Dir(curDir) 54 if nextDir == curDir { 55 // stop at root 56 return nil, NoConfig 57 } 58 curDir = nextDir 59 } 60 } 61 62 func ReadConfig(name string) (*Config, error) { 63 data, err := ioutil.ReadFile(name) 64 if err != nil { 65 return nil, err 66 } 67 c, err := NewConfig(string(data)) 68 if err != nil { 69 return nil, err 70 } 71 c.File = name 72 return qualifyPaths(name, c) 73 } 74 75 func NewConfig(data string) (*Config, error) { 76 c := new(Config) 77 if _, err := toml.Decode(data, c); err != nil { 78 return nil, err 79 } 80 return c, nil 81 } 82 83 func (c *Config) WriteTo(configHome string) (string, error) { 84 file := filepath.Join(configHome, NomsConfigFile) 85 if err := os.MkdirAll(filepath.Dir(file), os.ModePerm); err != nil { 86 return "", err 87 } 88 if err := ioutil.WriteFile(file, []byte(c.writeableString()), os.ModePerm); err != nil { 89 return "", err 90 } 91 return file, nil 92 } 93 94 // Replace relative directory in path part of spec with an absolute 95 // directory. Assumes the path is relative to the location of the config file 96 func absDbSpec(configHome string, url string) string { 97 dbSpec, err := spec.ForDatabase(url) 98 if err != nil { 99 return url 100 } 101 if dbSpec.Protocol != "nbs" { 102 return url 103 } 104 dbName := dbSpec.DatabaseName 105 if !filepath.IsAbs(dbName) { 106 dbName = filepath.Join(configHome, dbName) 107 } 108 return "nbs:" + dbName 109 } 110 111 func qualifyPaths(configPath string, c *Config) (*Config, error) { 112 file, err := filepath.Abs(configPath) 113 if err != nil { 114 return nil, err 115 } 116 dir := filepath.Dir(file) 117 qc := *c 118 qc.File = file 119 for k, r := range c.Db { 120 qc.Db[k] = DbConfig{absDbSpec(dir, r.Url)} 121 } 122 return &qc, nil 123 } 124 125 func (c *Config) String() string { 126 var buffer bytes.Buffer 127 if c.File != "" { 128 buffer.WriteString(fmt.Sprintf("file = %s\n", c.File)) 129 } 130 buffer.WriteString(c.writeableString()) 131 return buffer.String() 132 } 133 134 func (c *Config) writeableString() string { 135 var buffer bytes.Buffer 136 for k, r := range c.Db { 137 buffer.WriteString(fmt.Sprintf("[db.%s]\n", k)) 138 buffer.WriteString(fmt.Sprintf("\t"+`url = "%s"`+"\n", r.Url)) 139 } 140 return buffer.String() 141 }