github.com/catandhorse/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 }