diff options
author | Máximo Cuadros <mcuadros@gmail.com> | 2020-05-24 11:22:32 +0200 |
---|---|---|
committer | Máximo Cuadros <mcuadros@gmail.com> | 2020-05-24 11:22:32 +0200 |
commit | 26d02b3fec4434d663445d580497204e79284db0 (patch) | |
tree | 979557eb9427829331fedcc80f9f8879b590b7cb | |
parent | 16207827862af21b6e822df9aafd0007ba19a36f (diff) | |
download | go-git-26d02b3fec4434d663445d580497204e79284db0.tar.gz |
config: ReadConfig and LoadConfig from scopes
-rw-r--r-- | config/config.go | 86 | ||||
-rw-r--r-- | config/config_test.go | 6 | ||||
-rw-r--r-- | storage/filesystem/config.go | 17 |
3 files changed, 94 insertions, 15 deletions
diff --git a/config/config.go b/config/config.go index e17ec5d..7d6ab58 100644 --- a/config/config.go +++ b/config/config.go @@ -5,11 +5,16 @@ import ( "bytes" "errors" "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" "sort" "strconv" "github.com/go-git/go-git/v5/internal/url" format "github.com/go-git/go-git/v5/plumbing/format/config" + "github.com/mitchellh/go-homedir" ) const ( @@ -32,6 +37,16 @@ var ( ErrRemoteConfigEmptyName = errors.New("remote config: empty name") ) +// Scope defines the scope of a config file, such as local, global or system. +type Scope int + +// Available ConfigScope's +const ( + LocalScope Scope = iota + GlobalScope + SystemScope +) + // Config contains the repository configuration // https://www.kernel.org/pub/software/scm/git/docs/git-config.html#FILES type Config struct { @@ -103,6 +118,77 @@ func NewConfig() *Config { return config } +// ReadConfig reads a config file from a io.Reader. +func ReadConfig(r io.Reader) (*Config, error) { + b, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + + cfg := NewConfig() + if err = cfg.Unmarshal(b); err != nil { + return nil, err + } + + return cfg, nil +} + +// LoadConfig loads a config file from a given scope. The returned Config, +// contains exclusively information fom the given scope. If couldn't find a +// config file to the given scope, a empty one is returned. +func LoadConfig(scope Scope) (*Config, error) { + if scope == LocalScope { + return nil, fmt.Errorf("LocalScope should be read from the a ConfigStorer.") + } + + files, err := Paths(scope) + if err != nil { + return nil, err + } + + for _, file := range files { + f, err := os.Open(file) + if err != nil { + if os.IsNotExist(err) { + continue + } + + return nil, err + } + + defer f.Close() + return ReadConfig(f) + } + + return NewConfig(), nil +} + +// Paths returns the config file location for a given scope. +func Paths(scope Scope) ([]string, error) { + var files []string + switch scope { + case GlobalScope: + xdg := os.Getenv("XDG_CONFIG_HOME") + if xdg != "" { + files = append(files, filepath.Join(xdg, "git/config")) + } + + home, err := homedir.Dir() + if err != nil { + return nil, err + } + + files = append(files, + filepath.Join(home, ".gitconfig"), + filepath.Join(home, ".config/git/config"), + ) + case SystemScope: + files = append(files, "/etc/gitconfig") + } + + return files, nil +} + // Validate validates the fields and sets the default values. func (c *Config) Validate() error { for name, r := range c.Remotes { diff --git a/config/config_test.go b/config/config_test.go index 157be95..e68626b 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -170,6 +170,12 @@ func (s *ConfigSuite) TestUnmarshalMarshal(c *C) { c.Assert(string(output), DeepEquals, string(input)) } +func (s *ConfigSuite) TestLoadConfig(c *C) { + cfg, err := LoadConfig(GlobalScope) + c.Assert(err, IsNil) + c.Assert(cfg.User.Email, Not(Equals), "") +} + func (s *ConfigSuite) TestValidateConfig(c *C) { config := &Config{ Remotes: map[string]*RemoteConfig{ diff --git a/storage/filesystem/config.go b/storage/filesystem/config.go index 01b35b4..78a6464 100644 --- a/storage/filesystem/config.go +++ b/storage/filesystem/config.go @@ -1,7 +1,6 @@ package filesystem import ( - stdioutil "io/ioutil" "os" "github.com/go-git/go-git/v5/config" @@ -14,29 +13,17 @@ type ConfigStorage struct { } func (c *ConfigStorage) Config() (conf *config.Config, err error) { - cfg := config.NewConfig() - f, err := c.dir.Config() if err != nil { if os.IsNotExist(err) { - return cfg, nil + return config.NewConfig(), nil } return nil, err } defer ioutil.CheckClose(f, &err) - - b, err := stdioutil.ReadAll(f) - if err != nil { - return nil, err - } - - if err = cfg.Unmarshal(b); err != nil { - return nil, err - } - - return cfg, err + return config.ReadConfig(f) } func (c *ConfigStorage) SetConfig(cfg *config.Config) (err error) { |