diff options
author | Kostya Ostrovsky <kostyay@users.noreply.github.com> | 2020-12-01 11:52:53 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-12-01 10:52:53 +0100 |
commit | 51cbc24bbecfecbbcea9cd733ad44eaf74b8ae4b (patch) | |
tree | 73a4fdcb346d3233181781e37d1929b457a65216 /config/config.go | |
parent | d525a514057f97bc2b183e2c67f542dd6f0ac0aa (diff) | |
download | go-git-51cbc24bbecfecbbcea9cd733ad44eaf74b8ae4b.tar.gz |
config: support insteadOf for remotes' URLs (#79)
Diffstat (limited to 'config/config.go')
-rw-r--r-- | config/config.go | 73 |
1 files changed, 72 insertions, 1 deletions
diff --git a/config/config.go b/config/config.go index 8a99e8d..1f737b5 100644 --- a/config/config.go +++ b/config/config.go @@ -105,6 +105,9 @@ type Config struct { // Branches list of branches, the key is the branch name and should // equal Branch.Name Branches map[string]*Branch + // URLs list of url rewrite rules, if repo url starts with URL.InsteadOf value, it will be replaced with the + // key instead. + URLs map[string]*URL // Raw contains the raw information of a config file. The main goal is // preserve the parsed information from the original format, to avoid // dropping unsupported fields. @@ -117,6 +120,7 @@ func NewConfig() *Config { Remotes: make(map[string]*RemoteConfig), Submodules: make(map[string]*Submodule), Branches: make(map[string]*Branch), + URLs: make(map[string]*URL), Raw: format.New(), } @@ -231,6 +235,7 @@ const ( authorSection = "author" committerSection = "committer" initSection = "init" + urlSection = "url" fetchKey = "fetch" urlKey = "url" bareKey = "bare" @@ -270,6 +275,10 @@ func (c *Config) Unmarshal(b []byte) error { return err } + if err := c.unmarshalURLs(); err != nil { + return err + } + return c.unmarshalRemotes() } @@ -323,6 +332,25 @@ func (c *Config) unmarshalRemotes() error { c.Remotes[r.Name] = r } + // Apply insteadOf url rules + for _, r := range c.Remotes { + r.applyURLRules(c.URLs) + } + + return nil +} + +func (c *Config) unmarshalURLs() error { + s := c.Raw.Section(urlSection) + for _, sub := range s.Subsections { + r := &URL{} + if err := r.unmarshal(sub); err != nil { + return err + } + + c.URLs[r.Name] = r + } + return nil } @@ -367,6 +395,7 @@ func (c *Config) Marshal() ([]byte, error) { c.marshalRemotes() c.marshalSubmodules() c.marshalBranches() + c.marshalURLs() c.marshalInit() buf := bytes.NewBuffer(nil) @@ -491,6 +520,20 @@ func (c *Config) marshalBranches() { s.Subsections = newSubsections } +func (c *Config) marshalURLs() { + s := c.Raw.Section(urlSection) + s.Subsections = make(format.Subsections, len(c.URLs)) + + var i int + for _, r := range c.URLs { + section := r.marshal() + // the submodule section at config is a subset of the .gitmodule file + // we should remove the non-valid options for the config file. + s.Subsections[i] = section + i++ + } +} + func (c *Config) marshalInit() { s := c.Raw.Section(initSection) if c.Init.DefaultBranch != "" { @@ -505,6 +548,12 @@ type RemoteConfig struct { // URLs the URLs of a remote repository. It must be non-empty. Fetch will // always use the first URL, while push will use all of them. URLs []string + + // insteadOfRulesApplied have urls been modified + insteadOfRulesApplied bool + // originalURLs are the urls before applying insteadOf rules + originalURLs []string + // Fetch the default set of "refspec" for fetch operation Fetch []RefSpec @@ -565,7 +614,12 @@ func (c *RemoteConfig) marshal() *format.Subsection { if len(c.URLs) == 0 { c.raw.RemoveOption(urlKey) } else { - c.raw.SetOption(urlKey, c.URLs...) + urls := c.URLs + if c.insteadOfRulesApplied { + urls = c.originalURLs + } + + c.raw.SetOption(urlKey, urls...) } if len(c.Fetch) == 0 { @@ -585,3 +639,20 @@ func (c *RemoteConfig) marshal() *format.Subsection { func (c *RemoteConfig) IsFirstURLLocal() bool { return url.IsLocalEndpoint(c.URLs[0]) } + +func (c *RemoteConfig) applyURLRules(urlRules map[string]*URL) { + // save original urls + originalURLs := make([]string, len(c.URLs)) + copy(originalURLs, c.URLs) + + for i, url := range c.URLs { + if matchingURLRule := findLongestInsteadOfMatch(url, urlRules); matchingURLRule != nil { + c.URLs[i] = matchingURLRule.ApplyInsteadOf(c.URLs[i]) + c.insteadOfRulesApplied = true + } + } + + if c.insteadOfRulesApplied { + c.originalURLs = originalURLs + } +} |