aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSantiago M. Mola <santi@mola.io>2017-07-27 17:17:34 +0200
committerSantiago M. Mola <santi@mola.io>2017-08-01 13:01:59 +0200
commite5c6fa237776870483cbe227d7f7ea943f35cb12 (patch)
treed8708626c6e4bdacdf3d3b796a17025908b6606b
parent1e70916ca7e4d5c0ad00edbfd1877e06d7587fc6 (diff)
downloadgo-git-e5c6fa237776870483cbe227d7f7ea943f35cb12.tar.gz
config: preserve option order on config marshalling
Do not change order of options (e.g. in RemoteConfig) when serializing for any option whose value has not changed.
-rw-r--r--config/config.go38
-rw-r--r--config/config_test.go2
-rw-r--r--plumbing/format/config/decoder_test.go5
-rw-r--r--plumbing/format/config/fixtures_test.go14
-rw-r--r--plumbing/format/config/option.go41
-rw-r--r--plumbing/format/config/section.go4
-rw-r--r--plumbing/format/config/section_test.go19
7 files changed, 99 insertions, 24 deletions
diff --git a/config/config.go b/config/config.go
index 1f3cd77..cb10738 100644
--- a/config/config.go
+++ b/config/config.go
@@ -159,13 +159,22 @@ func (c *Config) marshalCore() {
func (c *Config) marshalRemotes() {
s := c.Raw.Section(remoteSection)
- s.Subsections = make(format.Subsections, len(c.Remotes))
+ newSubsections := make(format.Subsections, 0, len(c.Remotes))
+ added := make(map[string]bool)
+ for _, subsection := range s.Subsections {
+ if remote, ok := c.Remotes[subsection.Name]; ok {
+ newSubsections = append(newSubsections, remote.marshal())
+ added[subsection.Name] = true
+ }
+ }
- var i int
- for _, r := range c.Remotes {
- s.Subsections[i] = r.marshal()
- i++
+ for name, remote := range c.Remotes {
+ if !added[name] {
+ newSubsections = append(newSubsections, remote.marshal())
+ }
}
+
+ s.Subsections = newSubsections
}
func (c *Config) marshalSubmodules() {
@@ -252,14 +261,21 @@ func (c *RemoteConfig) marshal() *format.Subsection {
}
c.raw.Name = c.Name
- c.raw.RemoveOption(urlKey)
- for _, url := range c.URLs {
- c.raw.AddOption(urlKey, url)
+ if len(c.URLs) == 0 {
+ c.raw.RemoveOption(urlKey)
+ } else {
+ c.raw.SetOption(urlKey, c.URLs...)
}
- c.raw.RemoveOption(fetchKey)
- for _, rs := range c.Fetch {
- c.raw.AddOption(fetchKey, rs.String())
+ if len(c.Fetch) == 0 {
+ c.raw.RemoveOption(fetchKey)
+ } else {
+ var values []string
+ for _, rs := range c.Fetch {
+ values = append(values, rs.String())
+ }
+
+ c.raw.SetOption(fetchKey, values...)
}
return c.raw
diff --git a/config/config_test.go b/config/config_test.go
index e958677..97f4bbf 100644
--- a/config/config_test.go
+++ b/config/config_test.go
@@ -107,7 +107,7 @@ func (s *ConfigSuite) TestUnmarshallMarshall(c *C) {
output, err := cfg.Marshal()
c.Assert(err, IsNil)
- c.Assert(output, DeepEquals, input)
+ c.Assert(string(output), DeepEquals, string(input))
}
func (s *ConfigSuite) TestValidateInvalidRemote(c *C) {
diff --git a/plumbing/format/config/decoder_test.go b/plumbing/format/config/decoder_test.go
index 412549f..0a8e92c 100644
--- a/plumbing/format/config/decoder_test.go
+++ b/plumbing/format/config/decoder_test.go
@@ -17,7 +17,10 @@ func (s *DecoderSuite) TestDecode(c *C) {
cfg := &Config{}
err := d.Decode(cfg)
c.Assert(err, IsNil, Commentf("decoder error for fixture: %d", idx))
- c.Assert(cfg, DeepEquals, fixture.Config, Commentf("bad result for fixture: %d", idx))
+ buf := bytes.NewBuffer(nil)
+ e := NewEncoder(buf)
+ _ = e.Encode(cfg)
+ c.Assert(cfg, DeepEquals, fixture.Config, Commentf("bad result for fixture: %d, %s", idx, buf.String()))
}
}
diff --git a/plumbing/format/config/fixtures_test.go b/plumbing/format/config/fixtures_test.go
index 12ff288..f3533df 100644
--- a/plumbing/format/config/fixtures_test.go
+++ b/plumbing/format/config/fixtures_test.go
@@ -87,4 +87,18 @@ var fixtures = []*Fixture{
AddOption("sect1", "subsect1", "opt2", "value2b").
AddOption("sect1", "subsect2", "opt2", "value2"),
},
+ {
+ Raw: `
+ [sect1]
+ opt1 = value1
+ opt1 = value2
+ `,
+ Text: `[sect1]
+ opt1 = value1
+ opt1 = value2
+`,
+ Config: New().
+ AddOption("sect1", "", "opt1", "value1").
+ AddOption("sect1", "", "opt1", "value2"),
+ },
}
diff --git a/plumbing/format/config/option.go b/plumbing/format/config/option.go
index 481af02..d4775e4 100644
--- a/plumbing/format/config/option.go
+++ b/plumbing/format/config/option.go
@@ -79,16 +79,39 @@ func (opts Options) withAddedOption(key string, value string) Options {
return append(opts, &Option{key, value})
}
-func (opts Options) withSettedOption(key string, value string) Options {
- for i := len(opts) - 1; i >= 0; i-- {
- o := opts[i]
- if o.IsKey(key) {
- result := make(Options, len(opts))
- copy(result, opts)
- result[i] = &Option{key, value}
- return result
+func (opts Options) withSettedOption(key string, values ...string) Options {
+ var result Options
+ var added []string
+ for _, o := range opts {
+ if !o.IsKey(key) {
+ result = append(result, o)
+ continue
+ }
+
+ if contains(values, o.Value) {
+ added = append(added, o.Value)
+ result = append(result, o)
+ continue
+ }
+ }
+
+ for _, value := range values {
+ if contains(added, value) {
+ continue
+ }
+
+ result = result.withAddedOption(key, value)
+ }
+
+ return result
+}
+
+func contains(haystack []string, needle string) bool {
+ for _, s := range haystack {
+ if s == needle {
+ return true
}
}
- return opts.withAddedOption(key, value)
+ return false
}
diff --git a/plumbing/format/config/section.go b/plumbing/format/config/section.go
index eeefe84..4a17e3b 100644
--- a/plumbing/format/config/section.go
+++ b/plumbing/format/config/section.go
@@ -134,8 +134,8 @@ func (s *Subsection) AddOption(key string, value string) *Subsection {
// SetOption adds a new Option to the Subsection. If the option already exists, is replaced.
// The updated Subsection is returned.
-func (s *Subsection) SetOption(key string, value string) *Subsection {
- s.Options = s.Options.withSettedOption(key, value)
+func (s *Subsection) SetOption(key string, value ...string) *Subsection {
+ s.Options = s.Options.withSettedOption(key, value...)
return s
}
diff --git a/plumbing/format/config/section_test.go b/plumbing/format/config/section_test.go
index cfd9f3f..0290386 100644
--- a/plumbing/format/config/section_test.go
+++ b/plumbing/format/config/section_test.go
@@ -69,3 +69,22 @@ func (s *SectionSuite) TestSubsection_RemoveOption(c *C) {
}
c.Assert(sect.RemoveOption("key1"), DeepEquals, expected)
}
+
+func (s *SectionSuite) TestSubsection_SetOption(c *C) {
+ sect := &Subsection{
+ Options: []*Option{
+ {Key: "key1", Value: "value1"},
+ {Key: "key2", Value: "value2"},
+ {Key: "key1", Value: "value3"},
+ },
+ }
+
+ expected := &Subsection{
+ Options: []*Option{
+ {Key: "key1", Value: "value1"},
+ {Key: "key2", Value: "value2"},
+ {Key: "key1", Value: "value4"},
+ },
+ }
+ c.Assert(sect.SetOption("key1", "value1", "value4"), DeepEquals, expected)
+}