github.com/git-lfs/git-lfs@v2.5.2+incompatible/lfsapi/endpoint.go (about)

     1  package lfsapi
     2  
     3  import (
     4  	"fmt"
     5  	"net/url"
     6  	"regexp"
     7  	"strings"
     8  )
     9  
    10  const UrlUnknown = "<unknown>"
    11  
    12  // An Endpoint describes how to access a Git LFS server.
    13  type Endpoint struct {
    14  	Url            string
    15  	SshUserAndHost string
    16  	SshPath        string
    17  	SshPort        string
    18  	Operation      string
    19  }
    20  
    21  func endpointOperation(e Endpoint, method string) string {
    22  	if len(e.Operation) > 0 {
    23  		return e.Operation
    24  	}
    25  
    26  	switch method {
    27  	case "GET", "HEAD":
    28  		return "download"
    29  	default:
    30  		return "upload"
    31  	}
    32  }
    33  
    34  // endpointFromBareSshUrl constructs a new endpoint from a bare SSH URL:
    35  //
    36  //   user@host.com:path/to/repo.git or
    37  //   [user@host.com:port]:path/to/repo.git
    38  //
    39  func endpointFromBareSshUrl(rawurl string) Endpoint {
    40  	parts := strings.Split(rawurl, ":")
    41  	partsLen := len(parts)
    42  	if partsLen < 2 {
    43  		return Endpoint{Url: rawurl}
    44  	}
    45  
    46  	// Treat presence of ':' as a bare URL
    47  	var newPath string
    48  	if len(parts) > 2 { // port included; really should only ever be 3 parts
    49  		// Correctly handle [host:port]:path URLs
    50  		parts[0] = strings.TrimPrefix(parts[0], "[")
    51  		parts[1] = strings.TrimSuffix(parts[1], "]")
    52  		newPath = fmt.Sprintf("%v:%v", parts[0], strings.Join(parts[1:], "/"))
    53  	} else {
    54  		newPath = strings.Join(parts, "/")
    55  	}
    56  	newrawurl := fmt.Sprintf("ssh://%v", newPath)
    57  	newu, err := url.Parse(newrawurl)
    58  	if err != nil {
    59  		return Endpoint{Url: UrlUnknown}
    60  	}
    61  
    62  	return endpointFromSshUrl(newu)
    63  }
    64  
    65  // endpointFromSshUrl constructs a new endpoint from an ssh:// URL
    66  func endpointFromSshUrl(u *url.URL) Endpoint {
    67  	var endpoint Endpoint
    68  	// Pull out port now, we need it separately for SSH
    69  	regex := regexp.MustCompile(`^([^\:]+)(?:\:(\d+))?$`)
    70  	match := regex.FindStringSubmatch(u.Host)
    71  	if match == nil || len(match) < 2 {
    72  		endpoint.Url = UrlUnknown
    73  		return endpoint
    74  	}
    75  
    76  	host := match[1]
    77  	if u.User != nil && u.User.Username() != "" {
    78  		endpoint.SshUserAndHost = fmt.Sprintf("%s@%s", u.User.Username(), host)
    79  	} else {
    80  		endpoint.SshUserAndHost = host
    81  	}
    82  
    83  	if len(match) > 2 {
    84  		endpoint.SshPort = match[2]
    85  	}
    86  
    87  	// u.Path includes a preceding '/', strip off manually
    88  	// rooted paths in the URL will be '//path/to/blah'
    89  	// this is just how Go's URL parsing works
    90  	if strings.HasPrefix(u.Path, "/") {
    91  		endpoint.SshPath = u.Path[1:]
    92  	} else {
    93  		endpoint.SshPath = u.Path
    94  	}
    95  
    96  	// Fallback URL for using HTTPS while still using SSH for git
    97  	// u.Host includes host & port so can't use SSH port
    98  	endpoint.Url = fmt.Sprintf("https://%s%s", host, u.Path)
    99  
   100  	return endpoint
   101  }
   102  
   103  // Construct a new endpoint from a HTTP URL
   104  func endpointFromHttpUrl(u *url.URL) Endpoint {
   105  	// just pass this straight through
   106  	return Endpoint{Url: u.String()}
   107  }
   108  
   109  func endpointFromGitUrl(u *url.URL, e *endpointGitFinder) Endpoint {
   110  	u.Scheme = e.gitProtocol
   111  	return Endpoint{Url: u.String()}
   112  }
   113  
   114  func endpointFromLocalPath(path string) Endpoint {
   115  	if !strings.HasSuffix(path, ".git") {
   116  		path = fmt.Sprintf("%s/.git", path)
   117  	}
   118  	return Endpoint{Url: fmt.Sprintf("file://%s", path)}
   119  }