github.com/whyrusleeping/gx@v0.14.3/gxutil/config.go (about) 1 package gxutil 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "os" 8 9 homedir "github.com/mitchellh/go-homedir" 10 "path/filepath" 11 ) 12 13 const CfgFileName = ".gxrc" 14 15 type Config struct { 16 Repos map[string]string `json:"repos,omitempty"` 17 ExtraRepos map[string]string `json:"extra_repos,omitempty"` 18 User User `json:"user,omitempty"` 19 } 20 21 func (c *Config) GetRepos() map[string]string { 22 if len(c.ExtraRepos) == 0 { 23 return c.Repos 24 } 25 26 combined := make(map[string]string) 27 for k, v := range c.Repos { 28 combined[k] = v 29 } 30 31 for k, v := range c.ExtraRepos { 32 combined[k] = v 33 } 34 35 return combined 36 } 37 38 type User struct { 39 Name string `json:"name,omitempty"` 40 Email string `json:"email,omitempty"` 41 } 42 43 func LoadConfig() (*Config, error) { 44 home, err := homedir.Dir() 45 if err != nil { 46 return nil, err 47 } 48 49 // first check $HOME/.gxrc 50 cfg, err := loadFile(filepath.Join(home, CfgFileName)) 51 if err != nil { 52 if !os.IsNotExist(err) { 53 return nil, err 54 } 55 } 56 57 cwd, err := os.Getwd() 58 if err != nil { 59 return nil, err 60 } 61 62 local, err := loadFile(filepath.Join(cwd, CfgFileName)) 63 if err != nil { 64 if !os.IsNotExist(err) { 65 return nil, err 66 } 67 } 68 69 if local == nil { 70 return mapToCfg(cfg) 71 } 72 73 if cfg == nil { 74 return mapToCfg(local) 75 } 76 77 merged := mergeMaps(cfg, local) 78 79 return mapToCfg(merged) 80 } 81 82 func mergeMaps(base, extra map[string]interface{}) map[string]interface{} { 83 if base == nil { 84 return extra 85 } 86 87 for k, v := range extra { 88 bk, ok := base[k] 89 if !ok { 90 base[k] = v 91 continue 92 } 93 94 bmp, bmpok := bk.(map[string]interface{}) 95 emp, empok := v.(map[string]interface{}) 96 if !bmpok || !empok { 97 // if the field is not an object, overwrite 98 base[k] = v 99 continue 100 } 101 102 base[k] = mergeMaps(bmp, emp) 103 } 104 105 return base 106 } 107 108 func LoadConfigFrom(paths ...string) (*Config, error) { 109 if len(paths) == 0 { 110 return nil, fmt.Errorf("no path specified!") 111 } 112 113 base := paths[0] 114 paths = paths[1:] 115 116 cfg, err := loadFile(base) 117 if err != nil { 118 if !os.IsNotExist(err) { 119 return nil, err 120 } 121 } 122 123 for _, np := range paths { 124 next, err := loadFile(np) 125 if err != nil { 126 if !os.IsNotExist(err) { 127 return nil, err 128 } 129 } 130 131 cfg = mergeMaps(cfg, next) 132 } 133 134 rcfg, err := mapToCfg(cfg) 135 if err != nil { 136 return nil, err 137 } 138 139 sanityFill(rcfg) 140 return rcfg, nil 141 } 142 143 func sanityFill(c *Config) { 144 if c.ExtraRepos == nil { 145 c.ExtraRepos = make(map[string]string) 146 } 147 148 if c.Repos == nil { 149 c.Repos = make(map[string]string) 150 } 151 } 152 153 func loadFile(fname string) (map[string]interface{}, error) { 154 var cfg map[string]interface{} 155 fi, err := os.Open(fname) 156 if err != nil { 157 return nil, err 158 } 159 160 err = json.NewDecoder(fi).Decode(&cfg) 161 if err != nil { 162 return nil, err 163 } 164 165 return cfg, nil 166 } 167 168 func mapToCfg(cfg map[string]interface{}) (*Config, error) { 169 if cfg == nil { 170 return new(Config), nil 171 } 172 173 buf := new(bytes.Buffer) 174 err := json.NewEncoder(buf).Encode(cfg) 175 if err != nil { 176 return nil, err 177 } 178 179 out := new(Config) 180 err = json.NewDecoder(buf).Decode(out) 181 if err != nil { 182 return nil, err 183 } 184 185 return out, nil 186 } 187 188 func WriteConfig(cfg *Config, file string) error { 189 fi, err := os.Create(file) 190 if err != nil { 191 return err 192 } 193 defer fi.Close() 194 return json.NewEncoder(fi).Encode(cfg) 195 }