diff --git a/config/config_test.go b/config/config_test.go index 7e9483f6f..c7608a97e 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -160,7 +160,7 @@ func (s *ConfigSuite) TestMarshal(c *C) { cfg.URLs["ssh://git@github.com/"] = &URL{ Name: "ssh://git@github.com/", - InsteadOf: "https://github.com/", + InsteadOf: []string{"https://github.com/"}, } b, err := cfg.Marshal() diff --git a/config/url.go b/config/url.go index 114d6b266..8429a4444 100644 --- a/config/url.go +++ b/config/url.go @@ -17,7 +17,7 @@ type URL struct { Name string // Any URL that starts with this value will be rewritten to start, instead, with . // When more than one insteadOf strings match a given URL, the longest match is used. - InsteadOf string + InsteadOf []string // raw representation of the subsection, filled by marshal or unmarshal are // called. @@ -26,7 +26,7 @@ type URL struct { // Validate validates fields of branch func (b *URL) Validate() error { - if b.InsteadOf == "" { + if len(b.InsteadOf) == 0 { return errURLEmptyInsteadOf } @@ -41,7 +41,7 @@ func (u *URL) unmarshal(s *format.Subsection) error { u.raw = s u.Name = s.Name - u.InsteadOf = u.raw.Option(insteadOfKey) + u.InsteadOf = u.raw.OptionAll(insteadOfKey) return nil } @@ -51,21 +51,28 @@ func (u *URL) marshal() *format.Subsection { } u.raw.Name = u.Name - u.raw.SetOption(insteadOfKey, u.InsteadOf) + u.raw.SetOption(insteadOfKey, u.InsteadOf...) return u.raw } func findLongestInsteadOfMatch(remoteURL string, urls map[string]*URL) *URL { var longestMatch *URL - for _, u := range urls { - if !strings.HasPrefix(remoteURL, u.InsteadOf) { - continue - } + var longestMatchLength int - // according to spec if there is more than one match, take the logest - if longestMatch == nil || len(longestMatch.InsteadOf) < len(u.InsteadOf) { - longestMatch = u + for _, u := range urls { + for _, currentInsteadOf := range u.InsteadOf { + if !strings.HasPrefix(remoteURL, currentInsteadOf) { + continue + } + + lengthCurrentInsteadOf := len(currentInsteadOf) + + // according to spec if there is more than one match, take the longest + if longestMatch == nil || longestMatchLength < lengthCurrentInsteadOf { + longestMatch = u + longestMatchLength = lengthCurrentInsteadOf + } } } @@ -73,9 +80,11 @@ func findLongestInsteadOfMatch(remoteURL string, urls map[string]*URL) *URL { } func (u *URL) ApplyInsteadOf(url string) string { - if !strings.HasPrefix(url, u.InsteadOf) { - return url + for _, j := range u.InsteadOf { + if strings.HasPrefix(url, j) { + return u.Name + url[len(j):] + } } - return u.Name + url[len(u.InsteadOf):] + return url } diff --git a/config/url_test.go b/config/url_test.go index 5afc9f39b..0b2304360 100644 --- a/config/url_test.go +++ b/config/url_test.go @@ -11,7 +11,7 @@ var _ = Suite(&URLSuite{}) func (b *URLSuite) TestValidateInsteadOf(c *C) { goodURL := URL{ Name: "ssh://github.com", - InsteadOf: "http://github.com", + InsteadOf: []string{"http://github.com"}, } badURL := URL{} c.Assert(goodURL.Validate(), IsNil) @@ -28,7 +28,26 @@ func (b *URLSuite) TestMarshal(c *C) { cfg := NewConfig() cfg.URLs["ssh://git@github.com/"] = &URL{ Name: "ssh://git@github.com/", - InsteadOf: "https://github.com/", + InsteadOf: []string{"https://github.com/"}, + } + + actual, err := cfg.Marshal() + c.Assert(err, IsNil) + c.Assert(string(actual), Equals, string(expected)) +} + +func (b *URLSuite) TestMarshalMultipleInsteadOf(c *C) { + expected := []byte(`[core] + bare = false +[url "ssh://git@github.com/"] + insteadOf = https://github.com/ + insteadOf = https://google.com/ +`) + + cfg := NewConfig() + cfg.URLs["ssh://git@github.com/"] = &URL{ + Name: "ssh://git@github.com/", + InsteadOf: []string{"https://github.com/", "https://google.com/"}, } actual, err := cfg.Marshal() @@ -48,15 +67,69 @@ func (b *URLSuite) TestUnmarshal(c *C) { c.Assert(err, IsNil) url := cfg.URLs["ssh://git@github.com/"] c.Assert(url.Name, Equals, "ssh://git@github.com/") - c.Assert(url.InsteadOf, Equals, "https://github.com/") + c.Assert(url.InsteadOf[0], Equals, "https://github.com/") +} + +func (b *URLSuite) TestUnmarshalMultipleInsteadOf(c *C) { + input := []byte(`[core] + bare = false +[url "ssh://git@github.com/"] + insteadOf = https://github.com/ + insteadOf = https://google.com/ +`) + + cfg := NewConfig() + err := cfg.Unmarshal(input) + c.Assert(err, IsNil) + url := cfg.URLs["ssh://git@github.com/"] + c.Assert(url.Name, Equals, "ssh://git@github.com/") + + c.Assert(url.ApplyInsteadOf("https://github.com/foobar"), Equals, "ssh://git@github.com/foobar") + c.Assert(url.ApplyInsteadOf("https://google.com/foobar"), Equals, "ssh://git@github.com/foobar") +} + +func (b *URLSuite) TestUnmarshalDuplicateUrls(c *C) { + input := []byte(`[core] + bare = false +[url "ssh://git@github.com/"] + insteadOf = https://github.com/ +[url "ssh://git@github.com/"] + insteadOf = https://google.com/ +`) + + cfg := NewConfig() + err := cfg.Unmarshal(input) + c.Assert(err, IsNil) + url := cfg.URLs["ssh://git@github.com/"] + c.Assert(url.Name, Equals, "ssh://git@github.com/") + + c.Assert(url.ApplyInsteadOf("https://github.com/foobar"), Equals, "ssh://git@github.com/foobar") + c.Assert(url.ApplyInsteadOf("https://google.com/foobar"), Equals, "ssh://git@github.com/foobar") } func (b *URLSuite) TestApplyInsteadOf(c *C) { urlRule := URL{ Name: "ssh://github.com", - InsteadOf: "http://github.com", + InsteadOf: []string{"http://github.com"}, } c.Assert(urlRule.ApplyInsteadOf("http://google.com"), Equals, "http://google.com") c.Assert(urlRule.ApplyInsteadOf("http://github.com/myrepo"), Equals, "ssh://github.com/myrepo") } + +func (b *URLSuite) TestFindLongestInsteadOfMatch(c *C) { + urlRules := map[string]*URL{ + "ssh://github.com": &URL{ + Name: "ssh://github.com", + InsteadOf: []string{"http://github.com"}, + }, + "ssh://somethingelse.com": &URL{ + Name: "ssh://somethingelse.com", + InsteadOf: []string{"http://github.com/foobar"}, + }, + } + + longestUrl := findLongestInsteadOfMatch("http://github.com/foobar/bingbash.git", urlRules) + + c.Assert(longestUrl.Name, Equals, "ssh://somethingelse.com") +}