github.com/psexton/git-lfs@v2.1.1-0.20170517224304-289a18b2bc53+incompatible/config/url_config.go (about)

     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  }