aboutsummaryrefslogtreecommitdiffstats
path: root/plumbing/transport/common.go
diff options
context:
space:
mode:
authorMáximo Cuadros <mcuadros@gmail.com>2017-11-21 11:27:37 +0100
committerGitHub <noreply@github.com>2017-11-21 11:27:37 +0100
commit97fb5e93083fbe4ea02078312ae2cbca3b145ab1 (patch)
tree4ce4c4b5616edb713ea2bc0ebbf485376933cc91 /plumbing/transport/common.go
parentdd81bc9156afb8102dd4c082a81bdb285d2e0a4b (diff)
parent5eb1c562e7deb4191cb160af91a864fb783c1041 (diff)
downloadgo-git-97fb5e93083fbe4ea02078312ae2cbca3b145ab1.tar.gz
Merge pull request #650 from mcuadros/endpoint
transport: converts Endpoint interface into a struct
Diffstat (limited to 'plumbing/transport/common.go')
-rw-r--r--plumbing/transport/common.go213
1 files changed, 111 insertions, 102 deletions
diff --git a/plumbing/transport/common.go b/plumbing/transport/common.go
index ac71bb3..f3ef4e6 100644
--- a/plumbing/transport/common.go
+++ b/plumbing/transport/common.go
@@ -13,6 +13,7 @@
package transport
import (
+ "bytes"
"context"
"errors"
"fmt"
@@ -20,6 +21,7 @@ import (
"net/url"
"regexp"
"strconv"
+ "strings"
"gopkg.in/src-d/go-git.v4/plumbing"
"gopkg.in/src-d/go-git.v4/plumbing/protocol/packp"
@@ -45,9 +47,9 @@ const (
// It is implemented both by the client and the server, making this a RPC.
type Transport interface {
// NewUploadPackSession starts a git-upload-pack session for an endpoint.
- NewUploadPackSession(Endpoint, AuthMethod) (UploadPackSession, error)
+ NewUploadPackSession(*Endpoint, AuthMethod) (UploadPackSession, error)
// NewReceivePackSession starts a git-receive-pack session for an endpoint.
- NewReceivePackSession(Endpoint, AuthMethod) (ReceivePackSession, error)
+ NewReceivePackSession(*Endpoint, AuthMethod) (ReceivePackSession, error)
}
type Session interface {
@@ -91,26 +93,71 @@ type ReceivePackSession interface {
}
// Endpoint represents a Git URL in any supported protocol.
-type Endpoint interface {
- // Protocol returns the protocol (e.g. git, https, file). It should never
- // return the empty string.
- Protocol() string
- // User returns the user or an empty string if none is given.
- User() string
- // Password returns the password or an empty string if none is given.
- Password() string
- // Host returns the host or an empty string if none is given.
- Host() string
- // Port returns the port or 0 if there is no port or a default should be
- // used.
- Port() int
- // Path returns the repository path.
- Path() string
- // String returns a string representation of the Git URL.
- String() string
+type Endpoint struct {
+ // Protocol is the protocol of the endpoint (e.g. git, https, file). I
+ Protocol string
+ // User is the user.
+ User string
+ // Password is the password.
+ Password string
+ // Host is the host.
+ Host string
+ // Port is the port to connect, if 0 the default port for the given protocol
+ // wil be used.
+ Port int
+ // Path is the repository path.
+ Path string
}
-func NewEndpoint(endpoint string) (Endpoint, error) {
+var defaultPorts = map[string]int{
+ "http": 80,
+ "https": 443,
+ "git": 9418,
+ "ssh": 22,
+}
+
+// String returns a string representation of the Git URL.
+func (u *Endpoint) String() string {
+ var buf bytes.Buffer
+ if u.Protocol != "" {
+ buf.WriteString(u.Protocol)
+ buf.WriteByte(':')
+ }
+
+ if u.Protocol != "" || u.Host != "" || u.User != "" || u.Password != "" {
+ buf.WriteString("//")
+
+ if u.User != "" || u.Password != "" {
+ buf.WriteString(u.User)
+ if u.Password != "" {
+ buf.WriteByte(':')
+ buf.WriteString(u.Password)
+ }
+
+ buf.WriteByte('@')
+ }
+
+ if u.Host != "" {
+ buf.WriteString(u.Host)
+
+ if u.Port != 0 {
+ port, ok := defaultPorts[strings.ToLower(u.Protocol)]
+ if !ok || ok && port != u.Port {
+ fmt.Fprintf(&buf, ":%d", u.Port)
+ }
+ }
+ }
+ }
+
+ if u.Path != "" && u.Path[0] != '/' && u.Host != "" {
+ buf.WriteByte('/')
+ }
+
+ buf.WriteString(u.Path)
+ return buf.String()
+}
+
+func NewEndpoint(endpoint string) (*Endpoint, error) {
if e, ok := parseSCPLike(endpoint); ok {
return e, nil
}
@@ -119,9 +166,13 @@ func NewEndpoint(endpoint string) (Endpoint, error) {
return e, nil
}
+ return parseURL(endpoint)
+}
+
+func parseURL(endpoint string) (*Endpoint, error) {
u, err := url.Parse(endpoint)
if err != nil {
- return nil, plumbing.NewPermanentError(err)
+ return nil, err
}
if !u.IsAbs() {
@@ -130,40 +181,29 @@ func NewEndpoint(endpoint string) (Endpoint, error) {
))
}
- return urlEndpoint{u}, nil
-}
-
-type urlEndpoint struct {
- *url.URL
-}
-
-func (e urlEndpoint) Protocol() string { return e.URL.Scheme }
-func (e urlEndpoint) Host() string { return e.URL.Hostname() }
-
-func (e urlEndpoint) User() string {
- if e.URL.User == nil {
- return ""
- }
-
- return e.URL.User.Username()
-}
-
-func (e urlEndpoint) Password() string {
- if e.URL.User == nil {
- return ""
+ var user, pass string
+ if u.User != nil {
+ user = u.User.Username()
+ pass, _ = u.User.Password()
}
- p, _ := e.URL.User.Password()
- return p
+ return &Endpoint{
+ Protocol: u.Scheme,
+ User: user,
+ Password: pass,
+ Host: u.Hostname(),
+ Port: getPort(u),
+ Path: getPath(u),
+ }, nil
}
-func (e urlEndpoint) Port() int {
- p := e.URL.Port()
+func getPort(u *url.URL) int {
+ p := u.Port()
if p == "" {
return 0
}
- i, err := strconv.Atoi(e.URL.Port())
+ i, err := strconv.Atoi(p)
if err != nil {
return 0
}
@@ -171,86 +211,55 @@ func (e urlEndpoint) Port() int {
return i
}
-func (e urlEndpoint) Path() string {
- var res string = e.URL.Path
- if e.URL.RawQuery != "" {
- res += "?" + e.URL.RawQuery
+func getPath(u *url.URL) string {
+ var res string = u.Path
+ if u.RawQuery != "" {
+ res += "?" + u.RawQuery
}
- if e.URL.Fragment != "" {
- res += "#" + e.URL.Fragment
+ if u.Fragment != "" {
+ res += "#" + u.Fragment
}
return res
}
-type scpEndpoint struct {
- user string
- host string
- port string
- path string
-}
-
-func (e *scpEndpoint) Protocol() string { return "ssh" }
-func (e *scpEndpoint) User() string { return e.user }
-func (e *scpEndpoint) Password() string { return "" }
-func (e *scpEndpoint) Host() string { return e.host }
-func (e *scpEndpoint) Path() string { return e.path }
-func (e *scpEndpoint) Port() int {
- i, err := strconv.Atoi(e.port)
- if err != nil {
- return 22
- }
- return i
-}
-
-func (e *scpEndpoint) String() string {
- var user string
- if e.user != "" {
- user = fmt.Sprintf("%s@", e.user)
- }
-
- return fmt.Sprintf("%s%s:%s", user, e.host, e.path)
-}
-
-type fileEndpoint struct {
- path string
-}
-
-func (e *fileEndpoint) Protocol() string { return "file" }
-func (e *fileEndpoint) User() string { return "" }
-func (e *fileEndpoint) Password() string { return "" }
-func (e *fileEndpoint) Host() string { return "" }
-func (e *fileEndpoint) Port() int { return 0 }
-func (e *fileEndpoint) Path() string { return e.path }
-func (e *fileEndpoint) String() string { return e.path }
-
var (
isSchemeRegExp = regexp.MustCompile(`^[^:]+://`)
scpLikeUrlRegExp = regexp.MustCompile(`^(?:(?P<user>[^@]+)@)?(?P<host>[^:\s]+):(?:(?P<port>[0-9]{1,5})/)?(?P<path>[^\\].*)$`)
)
-func parseSCPLike(endpoint string) (Endpoint, bool) {
+func parseSCPLike(endpoint string) (*Endpoint, bool) {
if isSchemeRegExp.MatchString(endpoint) || !scpLikeUrlRegExp.MatchString(endpoint) {
return nil, false
}
m := scpLikeUrlRegExp.FindStringSubmatch(endpoint)
- return &scpEndpoint{
- user: m[1],
- host: m[2],
- port: m[3],
- path: m[4],
+
+ port, err := strconv.Atoi(m[3])
+ if err != nil {
+ port = 22
+ }
+
+ return &Endpoint{
+ Protocol: "ssh",
+ User: m[1],
+ Host: m[2],
+ Port: port,
+ Path: m[4],
}, true
}
-func parseFile(endpoint string) (Endpoint, bool) {
+func parseFile(endpoint string) (*Endpoint, bool) {
if isSchemeRegExp.MatchString(endpoint) {
return nil, false
}
path := endpoint
- return &fileEndpoint{path}, true
+ return &Endpoint{
+ Protocol: "file",
+ Path: path,
+ }, true
}
// UnsupportedCapabilities are the capabilities not supported by any client