Imported Upstream version 2.3.3
[scm/test.git] / config / url_config.go
1 package config
2
3 import (
4         "fmt"
5         "net/url"
6         "strings"
7 )
8
9 type URLConfig struct {
10         git Environment
11 }
12
13 func NewURLConfig(git Environment) *URLConfig {
14         if git == nil {
15                 git = EnvironmentOf(make(mapFetcher))
16         }
17
18         return &URLConfig{
19                 git: git,
20         }
21 }
22
23 // Get retrieves a `http.{url}.{key}` for the given key and urls, following the
24 // rules in https://git-scm.com/docs/git-config#git-config-httplturlgt.
25 // The value for `http.{key}` is returned as a fallback if no config keys are
26 // set for the given urls.
27 func (c *URLConfig) Get(prefix, rawurl, key string) (string, bool) {
28         if c == nil {
29                 return "", false
30         }
31
32         key = strings.ToLower(key)
33         prefix = strings.ToLower(prefix)
34         if v := c.getAll(prefix, rawurl, key); len(v) > 0 {
35                 return v[len(v)-1], true
36         }
37         return c.git.Get(strings.Join([]string{prefix, key}, "."))
38 }
39
40 func (c *URLConfig) GetAll(prefix, rawurl, key string) []string {
41         if c == nil {
42                 return nil
43         }
44
45         key = strings.ToLower(key)
46         prefix = strings.ToLower(prefix)
47         if v := c.getAll(prefix, rawurl, key); len(v) > 0 {
48                 return v
49         }
50         return c.git.GetAll(strings.Join([]string{prefix, key}, "."))
51 }
52
53 func (c *URLConfig) getAll(prefix, rawurl, key string) []string {
54         hosts, paths := c.hostsAndPaths(rawurl)
55
56         for i := len(paths); i > 0; i-- {
57                 for _, host := range hosts {
58                         path := strings.Join(paths[:i], slash)
59                         if v := c.git.GetAll(fmt.Sprintf("%s.%s/%s.%s", prefix, host, path, key)); len(v) > 0 {
60                                 return v
61                         }
62                         if v := c.git.GetAll(fmt.Sprintf("%s.%s/%s/.%s", prefix, host, path, key)); len(v) > 0 {
63                                 return v
64                         }
65
66                         if isDefaultLFSUrl(path, paths, i) {
67                                 path = path[0 : len(path)-4]
68                                 if v := c.git.GetAll(fmt.Sprintf("%s.%s/%s.%s", prefix, host, path, key)); len(v) > 0 {
69                                         return v
70                                 }
71                         }
72                 }
73         }
74
75         for _, host := range hosts {
76                 if v := c.git.GetAll(fmt.Sprintf("%s.%s.%s", prefix, host, key)); len(v) > 0 {
77                         return v
78                 }
79                 if v := c.git.GetAll(fmt.Sprintf("%s.%s/.%s", prefix, host, key)); len(v) > 0 {
80                         return v
81                 }
82         }
83         return nil
84
85 }
86 func (c *URLConfig) hostsAndPaths(rawurl string) (hosts, paths []string) {
87         u, err := url.Parse(rawurl)
88         if err != nil {
89                 return nil, nil
90         }
91
92         return c.hosts(u), c.paths(u.Path)
93 }
94
95 func (c *URLConfig) hosts(u *url.URL) []string {
96         hosts := make([]string, 0, 1)
97
98         if u.User != nil {
99                 hosts = append(hosts, fmt.Sprintf("%s://%s@%s", u.Scheme, u.User.Username(), u.Host))
100         }
101         hosts = append(hosts, fmt.Sprintf("%s://%s", u.Scheme, u.Host))
102
103         return hosts
104 }
105
106 func (c *URLConfig) paths(path string) []string {
107         pLen := len(path)
108         if pLen <= 2 {
109                 return nil
110         }
111
112         end := pLen
113         if strings.HasSuffix(path, slash) {
114                 end--
115         }
116         return strings.Split(path[1:end], slash)
117 }
118
119 const (
120         gitExt   = ".git"
121         infoPart = "info"
122         lfsPart  = "lfs"
123         slash    = "/"
124 )
125
126 func isDefaultLFSUrl(path string, parts []string, index int) bool {
127         if len(path) < 5 {
128                 return false // shorter than ".git"
129         }
130
131         if !strings.HasSuffix(path, gitExt) {
132                 return false
133         }
134
135         if index > len(parts)-2 {
136                 return false
137         }
138
139         return parts[index] == infoPart && parts[index+1] == lfsPart
140 }