aboutsummaryrefslogtreecommitdiffstats
path: root/config/config.go
diff options
context:
space:
mode:
authorKostya Ostrovsky <kostyay@users.noreply.github.com>2020-12-01 11:52:53 +0200
committerGitHub <noreply@github.com>2020-12-01 10:52:53 +0100
commit51cbc24bbecfecbbcea9cd733ad44eaf74b8ae4b (patch)
tree73a4fdcb346d3233181781e37d1929b457a65216 /config/config.go
parentd525a514057f97bc2b183e2c67f542dd6f0ac0aa (diff)
downloadgo-git-51cbc24bbecfecbbcea9cd733ad44eaf74b8ae4b.tar.gz
config: support insteadOf for remotes' URLs (#79)
Diffstat (limited to 'config/config.go')
-rw-r--r--config/config.go73
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
+ }
+}