diff options
author | Wes Morgan <wesmorgan@icloud.com> | 2020-04-06 10:32:06 -0600 |
---|---|---|
committer | Wes Morgan <wesmorgan@icloud.com> | 2020-04-06 10:32:06 -0600 |
commit | ecb64c048179fbc6086e7eff23136802720c8972 (patch) | |
tree | 5fba37333c2dcabccadee73f2c152f6b5df46fab /config | |
parent | 8fddd7abcc436d77e9f7449a7b7aa15ee13f7c60 (diff) | |
download | go-git-ecb64c048179fbc6086e7eff23136802720c8972.tar.gz |
Add Merged config
...for reading and writing global (~/.git/config) and reading system (/etc/gitconfig) configs in addition to local repo config
Diffstat (limited to 'config')
-rw-r--r-- | config/config.go | 49 | ||||
-rw-r--r-- | config/config_test.go | 160 |
2 files changed, 196 insertions, 13 deletions
diff --git a/config/config.go b/config/config.go index bec35b0..2b427cb 100644 --- a/config/config.go +++ b/config/config.go @@ -66,6 +66,9 @@ type Config struct { // preserve the parsed information from the original format, to avoid // dropping unsupported fields. Raw *format.Config + // Merged contains the raw form of how git views the system (/etc/gitconfig), + // global (~/.gitconfig), and local (./.git/config) config params. + Merged *format.Merged } // NewConfig returns a new empty Config. @@ -74,9 +77,11 @@ func NewConfig() *Config { Remotes: make(map[string]*RemoteConfig), Submodules: make(map[string]*Submodule), Branches: make(map[string]*Branch), - Raw: format.New(), + Merged: format.NewMerged(), } + config.Raw = config.Merged.LocalConfig() + config.Pack.Window = DefaultPackWindow return config @@ -129,25 +134,38 @@ const ( // Unmarshal parses a git-config file and stores it. func (c *Config) Unmarshal(b []byte) error { + return c.UnmarshalScoped(format.LocalScope, b) +} + +func (c *Config) UnmarshalScoped(scope format.Scope, b []byte) error { r := bytes.NewBuffer(b) d := format.NewDecoder(r) - c.Raw = format.New() - if err := d.Decode(c.Raw); err != nil { - return err - } + c.Merged.ResetScopedConfig(scope) - c.unmarshalCore() - if err := c.unmarshalPack(); err != nil { + if err := d.Decode(c.Merged.ScopedConfig(scope)); err != nil { return err } - unmarshalSubmodules(c.Raw, c.Submodules) - if err := c.unmarshalBranches(); err != nil { - return err + if scope == format.LocalScope { + c.Raw = c.Merged.LocalConfig() + + c.unmarshalCore() + if err := c.unmarshalPack(); err != nil { + return err + } + unmarshalSubmodules(c.Raw, c.Submodules) + + if err := c.unmarshalBranches(); err != nil { + return err + } + + if err := c.unmarshalRemotes(); err != nil { + return err + } } - return c.unmarshalRemotes() + return nil } func (c *Config) unmarshalCore() { @@ -218,7 +236,7 @@ func (c *Config) unmarshalBranches() error { } // Marshal returns Config encoded as a git-config file. -func (c *Config) Marshal() ([]byte, error) { +func (c *Config) MarshalScope(scope format.Scope) ([]byte, error) { c.marshalCore() c.marshalPack() c.marshalRemotes() @@ -226,13 +244,18 @@ func (c *Config) Marshal() ([]byte, error) { c.marshalBranches() buf := bytes.NewBuffer(nil) - if err := format.NewEncoder(buf).Encode(c.Raw); err != nil { + cfg := c.Merged.ScopedConfig(scope) + if err := format.NewEncoder(buf).Encode(cfg); err != nil { return nil, err } return buf.Bytes(), nil } +func (c *Config) Marshal() ([]byte, error) { + return c.MarshalScope(format.LocalScope) +} + func (c *Config) marshalCore() { s := c.Raw.Section(coreSection) s.SetOption(bareKey, fmt.Sprintf("%t", c.Core.IsBare)) diff --git a/config/config_test.go b/config/config_test.go index e5e3be5..a2ece2a 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -3,6 +3,7 @@ package config import ( . "gopkg.in/check.v1" "github.com/go-git/go-git/v5/plumbing" + format "github.com/go-git/go-git/v5/plumbing/format/config" ) type ConfigSuite struct{} @@ -60,6 +61,76 @@ func (s *ConfigSuite) TestUnmarshal(c *C) { c.Assert(cfg.Branches["master"].Merge, Equals, plumbing.ReferenceName("refs/heads/master")) } +func (s *ConfigSuite) TestMergedUnmarshal(c *C) { + localInput := []byte(`[core] + bare = true + worktree = foo + commentchar = bar +[pack] + window = 20 +[remote "origin"] + url = git@github.com:mcuadros/go-git.git + fetch = +refs/heads/*:refs/remotes/origin/* +[remote "alt"] + url = git@github.com:mcuadros/go-git.git + url = git@github.com:src-d/go-git.git + fetch = +refs/heads/*:refs/remotes/origin/* + fetch = +refs/pull/*:refs/remotes/origin/pull/* +[remote "win-local"] + url = X:\\Git\\ +[submodule "qux"] + path = qux + url = https://github.com/foo/qux.git + branch = bar +[branch "master"] + remote = origin + merge = refs/heads/master +[user] + name = Override +`) + + globalInput := []byte(` +[user] + name = Soandso + email = soandso@example.com +[core] + editor = nvim +[push] + default = simple +`) + + cfg := NewConfig() + + err := cfg.UnmarshalScoped(format.LocalScope, localInput) + c.Assert(err, IsNil) + + err = cfg.UnmarshalScoped(format.GlobalScope, globalInput) + c.Assert(err, IsNil) + + c.Assert(cfg.Core.IsBare, Equals, true) + c.Assert(cfg.Core.Worktree, Equals, "foo") + c.Assert(cfg.Core.CommentChar, Equals, "bar") + c.Assert(cfg.Pack.Window, Equals, uint(20)) + c.Assert(cfg.Remotes, HasLen, 3) + c.Assert(cfg.Remotes["origin"].Name, Equals, "origin") + c.Assert(cfg.Remotes["origin"].URLs, DeepEquals, []string{"git@github.com:mcuadros/go-git.git"}) + c.Assert(cfg.Remotes["origin"].Fetch, DeepEquals, []RefSpec{"+refs/heads/*:refs/remotes/origin/*"}) + c.Assert(cfg.Remotes["alt"].Name, Equals, "alt") + c.Assert(cfg.Remotes["alt"].URLs, DeepEquals, []string{"git@github.com:mcuadros/go-git.git", "git@github.com:src-d/go-git.git"}) + c.Assert(cfg.Remotes["alt"].Fetch, DeepEquals, []RefSpec{"+refs/heads/*:refs/remotes/origin/*", "+refs/pull/*:refs/remotes/origin/pull/*"}) + c.Assert(cfg.Remotes["win-local"].Name, Equals, "win-local") + c.Assert(cfg.Remotes["win-local"].URLs, DeepEquals, []string{"X:\\Git\\"}) + c.Assert(cfg.Submodules, HasLen, 1) + c.Assert(cfg.Submodules["qux"].Name, Equals, "qux") + c.Assert(cfg.Submodules["qux"].URL, Equals, "https://github.com/foo/qux.git") + c.Assert(cfg.Submodules["qux"].Branch, Equals, "bar") + c.Assert(cfg.Branches["master"].Remote, Equals, "origin") + c.Assert(cfg.Branches["master"].Merge, Equals, plumbing.ReferenceName("refs/heads/master")) + c.Assert(cfg.Merged.Section("user").Option("name"), Equals, "Override") + c.Assert(cfg.Merged.Section("user").Option("email"), Equals, "soandso@example.com") + c.Assert(cfg.Merged.Section("push").Option("default"), Equals, "simple") +} + func (s *ConfigSuite) TestMarshal(c *C) { output := []byte(`[core] bare = true @@ -119,6 +190,95 @@ func (s *ConfigSuite) TestMarshal(c *C) { c.Assert(string(b), Equals, string(output)) } +func (s *ConfigSuite) TestMergedMarshal(c *C) { + localOutput := []byte(`[user] + name = Override +[custom] + key = value +[core] + bare = true + worktree = bar +[pack] + window = 20 +[remote "alt"] + url = git@github.com:mcuadros/go-git.git + url = git@github.com:src-d/go-git.git + fetch = +refs/heads/*:refs/remotes/origin/* + fetch = +refs/pull/*:refs/remotes/origin/pull/* +[remote "origin"] + url = git@github.com:mcuadros/go-git.git +[remote "win-local"] + url = "X:\\Git\\" +[submodule "qux"] + url = https://github.com/foo/qux.git +[branch "master"] + remote = origin + merge = refs/heads/master +`) + + globalOutput := []byte(`[user] + name = Soandso + email = soandso@example.com +[core] + editor = nvim +[push] + default = simple +`) + + cfg := NewConfig() + + cfg.Core.IsBare = true + cfg.Core.Worktree = "bar" + cfg.Pack.Window = 20 + cfg.Remotes["origin"] = &RemoteConfig{ + Name: "origin", + URLs: []string{"git@github.com:mcuadros/go-git.git"}, + } + + cfg.Remotes["alt"] = &RemoteConfig{ + Name: "alt", + URLs: []string{"git@github.com:mcuadros/go-git.git", "git@github.com:src-d/go-git.git"}, + Fetch: []RefSpec{"+refs/heads/*:refs/remotes/origin/*", "+refs/pull/*:refs/remotes/origin/pull/*"}, + } + + cfg.Remotes["win-local"] = &RemoteConfig{ + Name: "win-local", + URLs: []string{"X:\\Git\\"}, + } + + cfg.Submodules["qux"] = &Submodule{ + Name: "qux", + URL: "https://github.com/foo/qux.git", + } + + cfg.Branches["master"] = &Branch{ + Name: "master", + Remote: "origin", + Merge: "refs/heads/master", + } + + cfg.Merged.GlobalConfig().Section("user").SetOption("name", "Soandso") + cfg.Merged.LocalConfig().Section("user").SetOption("name", "Override") + cfg.Merged.GlobalConfig().Section("user").SetOption("email", "soandso@example.com") + cfg.Merged.GlobalConfig().Section("core").AddOption("editor", "nvim") + cfg.Merged.LocalConfig().Section("custom").SetOption("key", "value") + cfg.Merged.GlobalConfig().Section("push").AddOption("default", "simple") + + c.Assert(cfg.Merged.Section("user").Option("name"), Equals, "Override") + + localBytes, err := cfg.Marshal() + c.Assert(err, IsNil) + c.Assert(string(localBytes), Equals, string(localOutput)) + + globalBytes, err := cfg.MarshalScope(format.GlobalScope) + c.Assert(err, IsNil) + c.Assert(string(globalBytes), Equals, string(globalOutput)) + + systemBytes, err := cfg.MarshalScope(format.SystemScope) + c.Assert(err, IsNil) + c.Assert(string(systemBytes), Equals, "") +} + func (s *ConfigSuite) TestUnmarshalMarshal(c *C) { input := []byte(`[core] bare = true |