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  }