aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMáximo Cuadros <mcuadros@gmail.com>2020-05-24 11:22:32 +0200
committerMáximo Cuadros <mcuadros@gmail.com>2020-05-24 11:22:32 +0200
commit26d02b3fec4434d663445d580497204e79284db0 (patch)
tree979557eb9427829331fedcc80f9f8879b590b7cb
parent16207827862af21b6e822df9aafd0007ba19a36f (diff)
downloadgo-git-26d02b3fec4434d663445d580497204e79284db0.tar.gz
config: ReadConfig and LoadConfig from scopes
-rw-r--r--config/config.go86
-rw-r--r--config/config_test.go6
-rw-r--r--storage/filesystem/config.go17
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) {