aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--plumbing/transport/common.go213
-rw-r--r--plumbing/transport/common_test.go149
2 files changed, 195 insertions, 167 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
diff --git a/plumbing/transport/common_test.go b/plumbing/transport/common_test.go
index 52759e6..4203ce9 100644
--- a/plumbing/transport/common_test.go
+++ b/plumbing/transport/common_test.go
@@ -17,120 +17,139 @@ var _ = Suite(&SuiteCommon{})
func (s *SuiteCommon) TestNewEndpointHTTP(c *C) {
e, err := NewEndpoint("http://git:pass@github.com/user/repository.git?foo#bar")
c.Assert(err, IsNil)
- c.Assert(e.Protocol(), Equals, "http")
- c.Assert(e.User(), Equals, "git")
- c.Assert(e.Password(), Equals, "pass")
- c.Assert(e.Host(), Equals, "github.com")
- c.Assert(e.Port(), Equals, 0)
- c.Assert(e.Path(), Equals, "/user/repository.git?foo#bar")
+ c.Assert(e.Protocol, Equals, "http")
+ c.Assert(e.User, Equals, "git")
+ c.Assert(e.Password, Equals, "pass")
+ c.Assert(e.Host, Equals, "github.com")
+ c.Assert(e.Port, Equals, 0)
+ c.Assert(e.Path, Equals, "/user/repository.git?foo#bar")
c.Assert(e.String(), Equals, "http://git:pass@github.com/user/repository.git?foo#bar")
}
+func (s *SuiteCommon) TestNewEndpointPorts(c *C) {
+ e, err := NewEndpoint("http://git:pass@github.com:8080/user/repository.git?foo#bar")
+ c.Assert(err, IsNil)
+ c.Assert(e.String(), Equals, "http://git:pass@github.com:8080/user/repository.git?foo#bar")
+
+ e, err = NewEndpoint("https://git:pass@github.com:443/user/repository.git?foo#bar")
+ c.Assert(err, IsNil)
+ c.Assert(e.String(), Equals, "https://git:pass@github.com/user/repository.git?foo#bar")
+
+ e, err = NewEndpoint("ssh://git:pass@github.com:22/user/repository.git?foo#bar")
+ c.Assert(err, IsNil)
+ c.Assert(e.String(), Equals, "ssh://git:pass@github.com/user/repository.git?foo#bar")
+
+ e, err = NewEndpoint("git://github.com:9418/user/repository.git?foo#bar")
+ c.Assert(err, IsNil)
+ c.Assert(e.String(), Equals, "git://github.com/user/repository.git?foo#bar")
+
+}
+
func (s *SuiteCommon) TestNewEndpointSSH(c *C) {
e, err := NewEndpoint("ssh://git@github.com/user/repository.git")
c.Assert(err, IsNil)
- c.Assert(e.Protocol(), Equals, "ssh")
- c.Assert(e.User(), Equals, "git")
- c.Assert(e.Password(), Equals, "")
- c.Assert(e.Host(), Equals, "github.com")
- c.Assert(e.Port(), Equals, 0)
- c.Assert(e.Path(), Equals, "/user/repository.git")
+ c.Assert(e.Protocol, Equals, "ssh")
+ c.Assert(e.User, Equals, "git")
+ c.Assert(e.Password, Equals, "")
+ c.Assert(e.Host, Equals, "github.com")
+ c.Assert(e.Port, Equals, 0)
+ c.Assert(e.Path, Equals, "/user/repository.git")
c.Assert(e.String(), Equals, "ssh://git@github.com/user/repository.git")
}
func (s *SuiteCommon) TestNewEndpointSSHNoUser(c *C) {
e, err := NewEndpoint("ssh://github.com/user/repository.git")
c.Assert(err, IsNil)
- c.Assert(e.Protocol(), Equals, "ssh")
- c.Assert(e.User(), Equals, "")
- c.Assert(e.Password(), Equals, "")
- c.Assert(e.Host(), Equals, "github.com")
- c.Assert(e.Port(), Equals, 0)
- c.Assert(e.Path(), Equals, "/user/repository.git")
+ c.Assert(e.Protocol, Equals, "ssh")
+ c.Assert(e.User, Equals, "")
+ c.Assert(e.Password, Equals, "")
+ c.Assert(e.Host, Equals, "github.com")
+ c.Assert(e.Port, Equals, 0)
+ c.Assert(e.Path, Equals, "/user/repository.git")
c.Assert(e.String(), Equals, "ssh://github.com/user/repository.git")
}
func (s *SuiteCommon) TestNewEndpointSSHWithPort(c *C) {
e, err := NewEndpoint("ssh://git@github.com:777/user/repository.git")
c.Assert(err, IsNil)
- c.Assert(e.Protocol(), Equals, "ssh")
- c.Assert(e.User(), Equals, "git")
- c.Assert(e.Password(), Equals, "")
- c.Assert(e.Host(), Equals, "github.com")
- c.Assert(e.Port(), Equals, 777)
- c.Assert(e.Path(), Equals, "/user/repository.git")
+ c.Assert(e.Protocol, Equals, "ssh")
+ c.Assert(e.User, Equals, "git")
+ c.Assert(e.Password, Equals, "")
+ c.Assert(e.Host, Equals, "github.com")
+ c.Assert(e.Port, Equals, 777)
+ c.Assert(e.Path, Equals, "/user/repository.git")
c.Assert(e.String(), Equals, "ssh://git@github.com:777/user/repository.git")
}
func (s *SuiteCommon) TestNewEndpointSCPLike(c *C) {
e, err := NewEndpoint("git@github.com:user/repository.git")
c.Assert(err, IsNil)
- c.Assert(e.Protocol(), Equals, "ssh")
- c.Assert(e.User(), Equals, "git")
- c.Assert(e.Password(), Equals, "")
- c.Assert(e.Host(), Equals, "github.com")
- c.Assert(e.Port(), Equals, 22)
- c.Assert(e.Path(), Equals, "user/repository.git")
- c.Assert(e.String(), Equals, "git@github.com:user/repository.git")
+ c.Assert(e.Protocol, Equals, "ssh")
+ c.Assert(e.User, Equals, "git")
+ c.Assert(e.Password, Equals, "")
+ c.Assert(e.Host, Equals, "github.com")
+ c.Assert(e.Port, Equals, 22)
+ c.Assert(e.Path, Equals, "user/repository.git")
+ c.Assert(e.String(), Equals, "ssh://git@github.com/user/repository.git")
}
func (s *SuiteCommon) TestNewEndpointSCPLikeWithPort(c *C) {
e, err := NewEndpoint("git@github.com:9999/user/repository.git")
c.Assert(err, IsNil)
- c.Assert(e.Protocol(), Equals, "ssh")
- c.Assert(e.User(), Equals, "git")
- c.Assert(e.Password(), Equals, "")
- c.Assert(e.Host(), Equals, "github.com")
- c.Assert(e.Port(), Equals, 9999)
- c.Assert(e.Path(), Equals, "user/repository.git")
- c.Assert(e.String(), Equals, "git@github.com:user/repository.git")
+ c.Assert(e.Protocol, Equals, "ssh")
+ c.Assert(e.User, Equals, "git")
+ c.Assert(e.Password, Equals, "")
+ c.Assert(e.Host, Equals, "github.com")
+ c.Assert(e.Port, Equals, 9999)
+ c.Assert(e.Path, Equals, "user/repository.git")
+ c.Assert(e.String(), Equals, "ssh://git@github.com:9999/user/repository.git")
}
func (s *SuiteCommon) TestNewEndpointFileAbs(c *C) {
e, err := NewEndpoint("/foo.git")
c.Assert(err, IsNil)
- c.Assert(e.Protocol(), Equals, "file")
- c.Assert(e.User(), Equals, "")
- c.Assert(e.Password(), Equals, "")
- c.Assert(e.Host(), Equals, "")
- c.Assert(e.Port(), Equals, 0)
- c.Assert(e.Path(), Equals, "/foo.git")
- c.Assert(e.String(), Equals, "/foo.git")
+ c.Assert(e.Protocol, Equals, "file")
+ c.Assert(e.User, Equals, "")
+ c.Assert(e.Password, Equals, "")
+ c.Assert(e.Host, Equals, "")
+ c.Assert(e.Port, Equals, 0)
+ c.Assert(e.Path, Equals, "/foo.git")
+ c.Assert(e.String(), Equals, "file:///foo.git")
}
func (s *SuiteCommon) TestNewEndpointFileRel(c *C) {
e, err := NewEndpoint("foo.git")
c.Assert(err, IsNil)
- c.Assert(e.Protocol(), Equals, "file")
- c.Assert(e.User(), Equals, "")
- c.Assert(e.Password(), Equals, "")
- c.Assert(e.Host(), Equals, "")
- c.Assert(e.Port(), Equals, 0)
- c.Assert(e.Path(), Equals, "foo.git")
- c.Assert(e.String(), Equals, "foo.git")
+ c.Assert(e.Protocol, Equals, "file")
+ c.Assert(e.User, Equals, "")
+ c.Assert(e.Password, Equals, "")
+ c.Assert(e.Host, Equals, "")
+ c.Assert(e.Port, Equals, 0)
+ c.Assert(e.Path, Equals, "foo.git")
+ c.Assert(e.String(), Equals, "file://foo.git")
}
func (s *SuiteCommon) TestNewEndpointFileWindows(c *C) {
e, err := NewEndpoint("C:\\foo.git")
c.Assert(err, IsNil)
- c.Assert(e.Protocol(), Equals, "file")
- c.Assert(e.User(), Equals, "")
- c.Assert(e.Password(), Equals, "")
- c.Assert(e.Host(), Equals, "")
- c.Assert(e.Port(), Equals, 0)
- c.Assert(e.Path(), Equals, "C:\\foo.git")
- c.Assert(e.String(), Equals, "C:\\foo.git")
+ c.Assert(e.Protocol, Equals, "file")
+ c.Assert(e.User, Equals, "")
+ c.Assert(e.Password, Equals, "")
+ c.Assert(e.Host, Equals, "")
+ c.Assert(e.Port, Equals, 0)
+ c.Assert(e.Path, Equals, "C:\\foo.git")
+ c.Assert(e.String(), Equals, "file://C:\\foo.git")
}
func (s *SuiteCommon) TestNewEndpointFileURL(c *C) {
e, err := NewEndpoint("file:///foo.git")
c.Assert(err, IsNil)
- c.Assert(e.Protocol(), Equals, "file")
- c.Assert(e.User(), Equals, "")
- c.Assert(e.Password(), Equals, "")
- c.Assert(e.Host(), Equals, "")
- c.Assert(e.Port(), Equals, 0)
- c.Assert(e.Path(), Equals, "/foo.git")
+ c.Assert(e.Protocol, Equals, "file")
+ c.Assert(e.User, Equals, "")
+ c.Assert(e.Password, Equals, "")
+ c.Assert(e.Host, Equals, "")
+ c.Assert(e.Port, Equals, 0)
+ c.Assert(e.Path, Equals, "/foo.git")
c.Assert(e.String(), Equals, "file:///foo.git")
}