aboutsummaryrefslogtreecommitdiffstats
path: root/plumbing/transport
diff options
context:
space:
mode:
Diffstat (limited to 'plumbing/transport')
-rw-r--r--plumbing/transport/client/client.go8
-rw-r--r--plumbing/transport/client/client_test.go4
-rw-r--r--plumbing/transport/common.go207
-rw-r--r--plumbing/transport/common_test.go147
-rw-r--r--plumbing/transport/file/client.go4
-rw-r--r--plumbing/transport/file/client_test.go2
-rw-r--r--plumbing/transport/file/common_test.go3
-rw-r--r--plumbing/transport/file/receive_pack_test.go2
-rw-r--r--plumbing/transport/file/server_test.go3
-rw-r--r--plumbing/transport/file/upload_pack_test.go2
-rw-r--r--plumbing/transport/git/common.go18
-rw-r--r--plumbing/transport/git/common_test.go99
-rw-r--r--plumbing/transport/git/receive_pack_test.go136
-rw-r--r--plumbing/transport/git/upload_pack_test.go23
-rw-r--r--plumbing/transport/http/common.go33
-rw-r--r--plumbing/transport/http/common_test.go75
-rw-r--r--plumbing/transport/http/receive_pack.go4
-rw-r--r--plumbing/transport/http/receive_pack_test.go112
-rw-r--r--plumbing/transport/http/upload_pack.go5
-rw-r--r--plumbing/transport/http/upload_pack_test.go43
-rw-r--r--plumbing/transport/internal/common/common.go8
-rw-r--r--plumbing/transport/server/loader.go12
-rw-r--r--plumbing/transport/server/loader_test.go2
-rw-r--r--plumbing/transport/server/receive_pack_test.go4
-rw-r--r--plumbing/transport/server/server.go7
-rw-r--r--plumbing/transport/server/server_test.go29
-rw-r--r--plumbing/transport/server/upload_pack_test.go17
-rw-r--r--plumbing/transport/ssh/auth_method.go82
-rw-r--r--plumbing/transport/ssh/auth_method_test.go8
-rw-r--r--plumbing/transport/ssh/common.go25
-rw-r--r--plumbing/transport/ssh/common_test.go2
-rw-r--r--plumbing/transport/ssh/upload_pack_test.go124
-rw-r--r--plumbing/transport/test/receive_pack.go18
-rw-r--r--plumbing/transport/test/upload_pack.go6
34 files changed, 678 insertions, 596 deletions
diff --git a/plumbing/transport/client/client.go b/plumbing/transport/client/client.go
index 76c1469..90635a5 100644
--- a/plumbing/transport/client/client.go
+++ b/plumbing/transport/client/client.go
@@ -34,14 +34,14 @@ func InstallProtocol(scheme string, c transport.Transport) {
// NewClient returns the appropriate client among of the set of known protocols:
// http://, https://, ssh:// and file://.
// See `InstallProtocol` to add or modify protocols.
-func NewClient(endpoint transport.Endpoint) (transport.Transport, error) {
- f, ok := Protocols[endpoint.Protocol()]
+func NewClient(endpoint *transport.Endpoint) (transport.Transport, error) {
+ f, ok := Protocols[endpoint.Protocol]
if !ok {
- return nil, fmt.Errorf("unsupported scheme %q", endpoint.Protocol())
+ return nil, fmt.Errorf("unsupported scheme %q", endpoint.Protocol)
}
if f == nil {
- return nil, fmt.Errorf("malformed client for scheme %q, client is defined as nil", endpoint.Protocol())
+ return nil, fmt.Errorf("malformed client for scheme %q, client is defined as nil", endpoint.Protocol)
}
return f, nil
diff --git a/plumbing/transport/client/client_test.go b/plumbing/transport/client/client_test.go
index 2b686b6..65cf574 100644
--- a/plumbing/transport/client/client_test.go
+++ b/plumbing/transport/client/client_test.go
@@ -59,12 +59,12 @@ type dummyClient struct {
*http.Client
}
-func (*dummyClient) NewUploadPackSession(transport.Endpoint, transport.AuthMethod) (
+func (*dummyClient) NewUploadPackSession(*transport.Endpoint, transport.AuthMethod) (
transport.UploadPackSession, error) {
return nil, nil
}
-func (*dummyClient) NewReceivePackSession(transport.Endpoint, transport.AuthMethod) (
+func (*dummyClient) NewReceivePackSession(*transport.Endpoint, transport.AuthMethod) (
transport.ReceivePackSession, error) {
return nil, nil
}
diff --git a/plumbing/transport/common.go b/plumbing/transport/common.go
index 2088500..cc9682f 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).
+ 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 ""
+ var user, pass string
+ if u.User != nil {
+ user = u.User.Username()
+ pass, _ = u.User.Password()
}
- return e.URL.User.Username()
+ return &Endpoint{
+ Protocol: u.Scheme,
+ User: user,
+ Password: pass,
+ Host: u.Hostname(),
+ Port: getPort(u),
+ Path: getPath(u),
+ }, nil
}
-func (e urlEndpoint) Password() string {
- if e.URL.User == nil {
- return ""
- }
-
- p, _ := e.URL.User.Password()
- return p
-}
-
-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,78 +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
- 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) Port() int { return 22 }
-func (e *scpEndpoint) Path() string { return e.path }
-
-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<path>[^\\].*)$`)
+ 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],
- path: m[3],
+
+ 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 ec617bd..4203ce9 100644
--- a/plumbing/transport/common_test.go
+++ b/plumbing/transport/common_test.go
@@ -17,108 +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, "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")
}
diff --git a/plumbing/transport/file/client.go b/plumbing/transport/file/client.go
index d229fdd..e799ee1 100644
--- a/plumbing/transport/file/client.go
+++ b/plumbing/transport/file/client.go
@@ -73,7 +73,7 @@ func prefixExecPath(cmd string) (string, error) {
return cmd, nil
}
-func (r *runner) Command(cmd string, ep transport.Endpoint, auth transport.AuthMethod,
+func (r *runner) Command(cmd string, ep *transport.Endpoint, auth transport.AuthMethod,
) (common.Command, error) {
switch cmd {
@@ -95,7 +95,7 @@ func (r *runner) Command(cmd string, ep transport.Endpoint, auth transport.AuthM
}
}
- return &command{cmd: exec.Command(cmd, ep.Path())}, nil
+ return &command{cmd: exec.Command(cmd, ep.Path)}, nil
}
type command struct {
diff --git a/plumbing/transport/file/client_test.go b/plumbing/transport/file/client_test.go
index 864cddc..25ea278 100644
--- a/plumbing/transport/file/client_test.go
+++ b/plumbing/transport/file/client_test.go
@@ -41,7 +41,7 @@ repositoryformatversion = 0
filemode = true
bare = true`
-func prepareRepo(c *C, path string) transport.Endpoint {
+func prepareRepo(c *C, path string) *transport.Endpoint {
ep, err := transport.NewEndpoint(path)
c.Assert(err, IsNil)
diff --git a/plumbing/transport/file/common_test.go b/plumbing/transport/file/common_test.go
index 4f3ae8f..99866d7 100644
--- a/plumbing/transport/file/common_test.go
+++ b/plumbing/transport/file/common_test.go
@@ -6,9 +6,8 @@ import (
"os/exec"
"path/filepath"
- "github.com/src-d/go-git-fixtures"
-
. "gopkg.in/check.v1"
+ "gopkg.in/src-d/go-git-fixtures.v3"
)
type CommonSuite struct {
diff --git a/plumbing/transport/file/receive_pack_test.go b/plumbing/transport/file/receive_pack_test.go
index a7dc399..3e7b140 100644
--- a/plumbing/transport/file/receive_pack_test.go
+++ b/plumbing/transport/file/receive_pack_test.go
@@ -3,10 +3,10 @@ package file
import (
"os"
- "github.com/src-d/go-git-fixtures"
"gopkg.in/src-d/go-git.v4/plumbing/transport/test"
. "gopkg.in/check.v1"
+ "gopkg.in/src-d/go-git-fixtures.v3"
)
type ReceivePackSuite struct {
diff --git a/plumbing/transport/file/server_test.go b/plumbing/transport/file/server_test.go
index 080beef..1793c0f 100644
--- a/plumbing/transport/file/server_test.go
+++ b/plumbing/transport/file/server_test.go
@@ -4,9 +4,8 @@ import (
"os"
"os/exec"
- "github.com/src-d/go-git-fixtures"
-
. "gopkg.in/check.v1"
+ "gopkg.in/src-d/go-git-fixtures.v3"
)
type ServerSuite struct {
diff --git a/plumbing/transport/file/upload_pack_test.go b/plumbing/transport/file/upload_pack_test.go
index 9a922d1..0b9b562 100644
--- a/plumbing/transport/file/upload_pack_test.go
+++ b/plumbing/transport/file/upload_pack_test.go
@@ -4,11 +4,11 @@ import (
"os"
"path/filepath"
- "github.com/src-d/go-git-fixtures"
"gopkg.in/src-d/go-git.v4/plumbing/transport"
"gopkg.in/src-d/go-git.v4/plumbing/transport/test"
. "gopkg.in/check.v1"
+ "gopkg.in/src-d/go-git-fixtures.v3"
)
type UploadPackSuite struct {
diff --git a/plumbing/transport/git/common.go b/plumbing/transport/git/common.go
index fcd02f8..78aaa3b 100644
--- a/plumbing/transport/git/common.go
+++ b/plumbing/transport/git/common.go
@@ -20,7 +20,7 @@ const DefaultPort = 9418
type runner struct{}
// Command returns a new Command for the given cmd in the given Endpoint
-func (r *runner) Command(cmd string, ep transport.Endpoint, auth transport.AuthMethod) (common.Command, error) {
+func (r *runner) Command(cmd string, ep *transport.Endpoint, auth transport.AuthMethod) (common.Command, error) {
// auth not allowed since git protocol doesn't support authentication
if auth != nil {
return nil, transport.ErrInvalidAuthMethod
@@ -36,7 +36,7 @@ type command struct {
conn net.Conn
connected bool
command string
- endpoint transport.Endpoint
+ endpoint *transport.Endpoint
}
// Start executes the command sending the required message to the TCP connection
@@ -63,8 +63,8 @@ func (c *command) connect() error {
}
func (c *command) getHostWithPort() string {
- host := c.endpoint.Host()
- port := c.endpoint.Port()
+ host := c.endpoint.Host
+ port := c.endpoint.Port
if port <= 0 {
port = DefaultPort
}
@@ -89,13 +89,13 @@ func (c *command) StdoutPipe() (io.Reader, error) {
return c.conn, nil
}
-func endpointToCommand(cmd string, ep transport.Endpoint) string {
- host := ep.Host()
- if ep.Port() != DefaultPort {
- host = fmt.Sprintf("%s:%d", ep.Host(), ep.Port())
+func endpointToCommand(cmd string, ep *transport.Endpoint) string {
+ host := ep.Host
+ if ep.Port != DefaultPort {
+ host = fmt.Sprintf("%s:%d", ep.Host, ep.Port)
}
- return fmt.Sprintf("%s %s%chost=%s%c", cmd, ep.Path(), 0, host, 0)
+ return fmt.Sprintf("%s %s%chost=%s%c", cmd, ep.Path, 0, host, 0)
}
// Close closes the TCP connection and connection.
diff --git a/plumbing/transport/git/common_test.go b/plumbing/transport/git/common_test.go
index 3f25ad9..61097e7 100644
--- a/plumbing/transport/git/common_test.go
+++ b/plumbing/transport/git/common_test.go
@@ -1,9 +1,108 @@
package git
import (
+ "fmt"
+ "io/ioutil"
+ "net"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "runtime"
"testing"
+ "time"
+
+ "gopkg.in/src-d/go-git.v4/plumbing/transport"
. "gopkg.in/check.v1"
+ "gopkg.in/src-d/go-git-fixtures.v3"
)
func Test(t *testing.T) { TestingT(t) }
+
+type BaseSuite struct {
+ fixtures.Suite
+
+ base string
+ port int
+ daemon *exec.Cmd
+}
+
+func (s *BaseSuite) SetUpTest(c *C) {
+ if runtime.GOOS == "windows" {
+ c.Skip(`git for windows has issues with write operations through git:// protocol.
+ See https://github.com/git-for-windows/git/issues/907`)
+ }
+
+ var err error
+ s.port, err = freePort()
+ c.Assert(err, IsNil)
+
+ s.base, err = ioutil.TempDir(os.TempDir(), fmt.Sprintf("go-git-protocol-%d", s.port))
+ c.Assert(err, IsNil)
+}
+
+func (s *BaseSuite) StartDaemon(c *C) {
+ s.daemon = exec.Command(
+ "git",
+ "daemon",
+ fmt.Sprintf("--base-path=%s", s.base),
+ "--export-all",
+ "--enable=receive-pack",
+ "--reuseaddr",
+ fmt.Sprintf("--port=%d", s.port),
+ // Unless max-connections is limited to 1, a git-receive-pack
+ // might not be seen by a subsequent operation.
+ "--max-connections=1",
+ )
+
+ // Environment must be inherited in order to acknowledge GIT_EXEC_PATH if set.
+ s.daemon.Env = os.Environ()
+
+ err := s.daemon.Start()
+ c.Assert(err, IsNil)
+
+ // Connections might be refused if we start sending request too early.
+ time.Sleep(time.Millisecond * 500)
+}
+
+func (s *BaseSuite) newEndpoint(c *C, name string) *transport.Endpoint {
+ ep, err := transport.NewEndpoint(fmt.Sprintf("git://localhost:%d/%s", s.port, name))
+ c.Assert(err, IsNil)
+
+ return ep
+}
+
+func (s *BaseSuite) prepareRepository(c *C, f *fixtures.Fixture, name string) *transport.Endpoint {
+ fs := f.DotGit()
+
+ err := fixtures.EnsureIsBare(fs)
+ c.Assert(err, IsNil)
+
+ path := filepath.Join(s.base, name)
+ err = os.Rename(fs.Root(), path)
+ c.Assert(err, IsNil)
+
+ return s.newEndpoint(c, name)
+}
+
+func (s *BaseSuite) TearDownTest(c *C) {
+ _ = s.daemon.Process.Signal(os.Kill)
+ _ = s.daemon.Wait()
+
+ err := os.RemoveAll(s.base)
+ c.Assert(err, IsNil)
+}
+
+func freePort() (int, error) {
+ addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
+ if err != nil {
+ return 0, err
+ }
+
+ l, err := net.ListenTCP("tcp", addr)
+ if err != nil {
+ return 0, err
+ }
+
+ return l.Addr().(*net.TCPAddr).Port, l.Close()
+}
diff --git a/plumbing/transport/git/receive_pack_test.go b/plumbing/transport/git/receive_pack_test.go
index 7b0fa46..fa10735 100644
--- a/plumbing/transport/git/receive_pack_test.go
+++ b/plumbing/transport/git/receive_pack_test.go
@@ -1,148 +1,26 @@
package git
import (
- "fmt"
- "io"
- "io/ioutil"
- "net"
- "os"
- "os/exec"
- "path/filepath"
- "runtime"
- "strings"
- "time"
-
- "github.com/src-d/go-git-fixtures"
- "gopkg.in/src-d/go-git.v4/plumbing/transport"
"gopkg.in/src-d/go-git.v4/plumbing/transport/test"
. "gopkg.in/check.v1"
+ "gopkg.in/src-d/go-git-fixtures.v3"
)
type ReceivePackSuite struct {
test.ReceivePackSuite
- fixtures.Suite
-
- base string
- daemon *exec.Cmd
+ BaseSuite
}
var _ = Suite(&ReceivePackSuite{})
func (s *ReceivePackSuite) SetUpTest(c *C) {
- if runtime.GOOS == "windows" {
- c.Skip(`git for windows has issues with write operations through git:// protocol.
- See https://github.com/git-for-windows/git/issues/907`)
- }
+ s.BaseSuite.SetUpTest(c)
s.ReceivePackSuite.Client = DefaultClient
+ s.ReceivePackSuite.Endpoint = s.prepareRepository(c, fixtures.Basic().One(), "basic.git")
+ s.ReceivePackSuite.EmptyEndpoint = s.prepareRepository(c, fixtures.ByTag("empty").One(), "empty.git")
+ s.ReceivePackSuite.NonExistentEndpoint = s.newEndpoint(c, "non-existent.git")
- port, err := freePort()
- c.Assert(err, IsNil)
-
- base, err := ioutil.TempDir(os.TempDir(), "go-git-daemon-test")
- c.Assert(err, IsNil)
- s.base = base
-
- host := fmt.Sprintf("localhost_%d", port)
- interpolatedBase := filepath.Join(base, host)
- err = os.MkdirAll(interpolatedBase, 0755)
- c.Assert(err, IsNil)
-
- dotgit := fixtures.Basic().One().DotGit().Root()
- prepareRepo(c, dotgit)
- err = os.Rename(dotgit, filepath.Join(interpolatedBase, "basic.git"))
- c.Assert(err, IsNil)
-
- ep, err := transport.NewEndpoint(fmt.Sprintf("git://localhost:%d/basic.git", port))
- c.Assert(err, IsNil)
- s.ReceivePackSuite.Endpoint = ep
-
- dotgit = fixtures.ByTag("empty").One().DotGit().Root()
- prepareRepo(c, dotgit)
- err = os.Rename(dotgit, filepath.Join(interpolatedBase, "empty.git"))
- c.Assert(err, IsNil)
-
- ep, err = transport.NewEndpoint(fmt.Sprintf("git://localhost:%d/empty.git", port))
- c.Assert(err, IsNil)
- s.ReceivePackSuite.EmptyEndpoint = ep
-
- ep, err = transport.NewEndpoint(fmt.Sprintf("git://localhost:%d/non-existent.git", port))
- c.Assert(err, IsNil)
- s.ReceivePackSuite.NonExistentEndpoint = ep
-
- s.daemon = exec.Command(
- "git",
- "daemon",
- fmt.Sprintf("--base-path=%s", base),
- "--export-all",
- "--enable=receive-pack",
- "--reuseaddr",
- fmt.Sprintf("--port=%d", port),
- // Use interpolated paths to validate that clients are specifying
- // host and port properly.
- // Note that some git versions (e.g. v2.11.0) had a bug that prevented
- // the use of repository paths containing colons (:), so we use
- // underscore (_) instead of colon in the interpolation.
- // See https://github.com/git/git/commit/fe050334074c5132d01e1df2c1b9a82c9b8d394c
- fmt.Sprintf("--interpolated-path=%s/%%H_%%P%%D", base),
- // Unless max-connections is limited to 1, a git-receive-pack
- // might not be seen by a subsequent operation.
- "--max-connections=1",
- // Whitelist required for interpolated paths.
- fmt.Sprintf("%s/%s", interpolatedBase, "basic.git"),
- fmt.Sprintf("%s/%s", interpolatedBase, "empty.git"),
- )
-
- // Environment must be inherited in order to acknowledge GIT_EXEC_PATH if set.
- s.daemon.Env = os.Environ()
-
- err = s.daemon.Start()
- c.Assert(err, IsNil)
-
- // Connections might be refused if we start sending request too early.
- time.Sleep(time.Millisecond * 500)
-}
-
-func (s *ReceivePackSuite) TearDownTest(c *C) {
- err := s.daemon.Process.Signal(os.Kill)
- c.Assert(err, IsNil)
-
- _ = s.daemon.Wait()
-
- err = os.RemoveAll(s.base)
- c.Assert(err, IsNil)
-}
-
-func freePort() (int, error) {
- addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
- if err != nil {
- return 0, err
- }
-
- l, err := net.ListenTCP("tcp", addr)
- if err != nil {
- return 0, err
- }
-
- return l.Addr().(*net.TCPAddr).Port, l.Close()
-}
-
-const bareConfig = `[core]
-repositoryformatversion = 0
-filemode = true
-bare = true`
-
-func prepareRepo(c *C, path string) {
- // git-receive-pack refuses to update refs/heads/master on non-bare repo
- // so we ensure bare repo config.
- config := filepath.Join(path, "config")
- if _, err := os.Stat(config); err == nil {
- f, err := os.OpenFile(config, os.O_TRUNC|os.O_WRONLY, 0)
- c.Assert(err, IsNil)
- content := strings.NewReader(bareConfig)
- _, err = io.Copy(f, content)
- c.Assert(err, IsNil)
- c.Assert(f.Close(), IsNil)
- }
+ s.StartDaemon(c)
}
diff --git a/plumbing/transport/git/upload_pack_test.go b/plumbing/transport/git/upload_pack_test.go
index d367a7f..7058564 100644
--- a/plumbing/transport/git/upload_pack_test.go
+++ b/plumbing/transport/git/upload_pack_test.go
@@ -1,35 +1,26 @@
package git
import (
- "github.com/src-d/go-git-fixtures"
- "gopkg.in/src-d/go-git.v4/plumbing/transport"
"gopkg.in/src-d/go-git.v4/plumbing/transport/test"
. "gopkg.in/check.v1"
+ "gopkg.in/src-d/go-git-fixtures.v3"
)
type UploadPackSuite struct {
test.UploadPackSuite
- fixtures.Suite
+ BaseSuite
}
var _ = Suite(&UploadPackSuite{})
func (s *UploadPackSuite) SetUpSuite(c *C) {
- s.Suite.SetUpSuite(c)
+ s.BaseSuite.SetUpTest(c)
s.UploadPackSuite.Client = DefaultClient
+ s.UploadPackSuite.Endpoint = s.prepareRepository(c, fixtures.Basic().One(), "basic.git")
+ s.UploadPackSuite.EmptyEndpoint = s.prepareRepository(c, fixtures.ByTag("empty").One(), "empty.git")
+ s.UploadPackSuite.NonExistentEndpoint = s.newEndpoint(c, "non-existent.git")
- ep, err := transport.NewEndpoint("git://github.com/git-fixtures/basic.git")
- c.Assert(err, IsNil)
- s.UploadPackSuite.Endpoint = ep
-
- ep, err = transport.NewEndpoint("git://github.com/git-fixtures/empty.git")
- c.Assert(err, IsNil)
- s.UploadPackSuite.EmptyEndpoint = ep
-
- ep, err = transport.NewEndpoint("git://github.com/git-fixtures/non-existent.git")
- c.Assert(err, IsNil)
- s.UploadPackSuite.NonExistentEndpoint = ep
-
+ s.StartDaemon(c)
}
diff --git a/plumbing/transport/http/common.go b/plumbing/transport/http/common.go
index 6b40d42..edf1c6c 100644
--- a/plumbing/transport/http/common.go
+++ b/plumbing/transport/http/common.go
@@ -10,6 +10,7 @@ import (
"gopkg.in/src-d/go-git.v4/plumbing"
"gopkg.in/src-d/go-git.v4/plumbing/protocol/packp"
"gopkg.in/src-d/go-git.v4/plumbing/transport"
+ "gopkg.in/src-d/go-git.v4/utils/ioutil"
)
// it requires a bytes.Buffer, because we need to know the length
@@ -39,14 +40,15 @@ func advertisedReferences(s *session, serviceName string) (*packp.AdvRefs, error
}
s.applyAuthToRequest(req)
- applyHeadersToRequest(req, nil, s.endpoint.Host(), serviceName)
+ applyHeadersToRequest(req, nil, s.endpoint.Host, serviceName)
res, err := s.client.Do(req)
if err != nil {
return nil, err
}
+ defer ioutil.CheckClose(res.Body, &err)
+
if err := NewErr(res); err != nil {
- _ = res.Body.Close()
return nil, err
}
@@ -90,13 +92,13 @@ func NewClient(c *http.Client) transport.Transport {
}
}
-func (c *client) NewUploadPackSession(ep transport.Endpoint, auth transport.AuthMethod) (
+func (c *client) NewUploadPackSession(ep *transport.Endpoint, auth transport.AuthMethod) (
transport.UploadPackSession, error) {
return newUploadPackSession(c.c, ep, auth)
}
-func (c *client) NewReceivePackSession(ep transport.Endpoint, auth transport.AuthMethod) (
+func (c *client) NewReceivePackSession(ep *transport.Endpoint, auth transport.AuthMethod) (
transport.ReceivePackSession, error) {
return newReceivePackSession(c.c, ep, auth)
@@ -105,11 +107,11 @@ func (c *client) NewReceivePackSession(ep transport.Endpoint, auth transport.Aut
type session struct {
auth AuthMethod
client *http.Client
- endpoint transport.Endpoint
+ endpoint *transport.Endpoint
advRefs *packp.AdvRefs
}
-func newSession(c *http.Client, ep transport.Endpoint, auth transport.AuthMethod) (*session, error) {
+func newSession(c *http.Client, ep *transport.Endpoint, auth transport.AuthMethod) (*session, error) {
s := &session{
auth: basicAuthFromEndpoint(ep),
client: c,
@@ -145,23 +147,18 @@ type AuthMethod interface {
setAuth(r *http.Request)
}
-func basicAuthFromEndpoint(ep transport.Endpoint) *BasicAuth {
- u := ep.User()
+func basicAuthFromEndpoint(ep *transport.Endpoint) *BasicAuth {
+ u := ep.User
if u == "" {
return nil
}
- return NewBasicAuth(u, ep.Password())
+ return &BasicAuth{u, ep.Password}
}
// BasicAuth represent a HTTP basic auth
type BasicAuth struct {
- username, password string
-}
-
-// NewBasicAuth returns a basicAuth base on the given user and password
-func NewBasicAuth(username, password string) *BasicAuth {
- return &BasicAuth{username, password}
+ Username, Password string
}
func (a *BasicAuth) setAuth(r *http.Request) {
@@ -169,7 +166,7 @@ func (a *BasicAuth) setAuth(r *http.Request) {
return
}
- r.SetBasicAuth(a.username, a.password)
+ r.SetBasicAuth(a.Username, a.Password)
}
// Name is name of the auth
@@ -179,11 +176,11 @@ func (a *BasicAuth) Name() string {
func (a *BasicAuth) String() string {
masked := "*******"
- if a.password == "" {
+ if a.Password == "" {
masked = "<empty>"
}
- return fmt.Sprintf("%s - %s:%s", a.Name(), a.username, masked)
+ return fmt.Sprintf("%s - %s:%s", a.Name(), a.Username, masked)
}
// Err is a dedicated error to return errors based on status code
diff --git a/plumbing/transport/http/common_test.go b/plumbing/transport/http/common_test.go
index d1f36d3..8d57996 100644
--- a/plumbing/transport/http/common_test.go
+++ b/plumbing/transport/http/common_test.go
@@ -2,18 +2,28 @@ package http
import (
"crypto/tls"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "net"
"net/http"
+ "net/http/cgi"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
"testing"
"gopkg.in/src-d/go-git.v4/plumbing/transport"
. "gopkg.in/check.v1"
+ "gopkg.in/src-d/go-git-fixtures.v3"
)
func Test(t *testing.T) { TestingT(t) }
type ClientSuite struct {
- Endpoint transport.Endpoint
+ Endpoint *transport.Endpoint
EmptyAuth transport.AuthMethod
}
@@ -38,7 +48,7 @@ func (s *UploadPackSuite) TestNewClient(c *C) {
}
func (s *ClientSuite) TestNewBasicAuth(c *C) {
- a := NewBasicAuth("foo", "qux")
+ a := &BasicAuth{"foo", "qux"}
c.Assert(a.Name(), Equals, "http-basic-auth")
c.Assert(a.String(), Equals, "http-basic-auth - foo:*******")
@@ -95,3 +105,64 @@ func (s *ClientSuite) TestSetAuthWrongType(c *C) {
_, err := DefaultClient.NewUploadPackSession(s.Endpoint, &mockAuth{})
c.Assert(err, Equals, transport.ErrInvalidAuthMethod)
}
+
+type BaseSuite struct {
+ fixtures.Suite
+
+ base string
+ host string
+ port int
+}
+
+func (s *BaseSuite) SetUpTest(c *C) {
+ l, err := net.Listen("tcp", "localhost:0")
+ c.Assert(err, IsNil)
+
+ base, err := ioutil.TempDir(os.TempDir(), fmt.Sprintf("go-git-http-%d", s.port))
+ c.Assert(err, IsNil)
+
+ s.port = l.Addr().(*net.TCPAddr).Port
+ s.base = filepath.Join(base, s.host)
+
+ err = os.MkdirAll(s.base, 0755)
+ c.Assert(err, IsNil)
+
+ cmd := exec.Command("git", "--exec-path")
+ out, err := cmd.CombinedOutput()
+ c.Assert(err, IsNil)
+
+ server := &http.Server{
+ Handler: &cgi.Handler{
+ Path: filepath.Join(strings.Trim(string(out), "\n"), "git-http-backend"),
+ Env: []string{"GIT_HTTP_EXPORT_ALL=true", fmt.Sprintf("GIT_PROJECT_ROOT=%s", s.base)},
+ },
+ }
+ go func() {
+ log.Fatal(server.Serve(l))
+ }()
+}
+
+func (s *BaseSuite) prepareRepository(c *C, f *fixtures.Fixture, name string) *transport.Endpoint {
+ fs := f.DotGit()
+
+ err := fixtures.EnsureIsBare(fs)
+ c.Assert(err, IsNil)
+
+ path := filepath.Join(s.base, name)
+ err = os.Rename(fs.Root(), path)
+ c.Assert(err, IsNil)
+
+ return s.newEndpoint(c, name)
+}
+
+func (s *BaseSuite) newEndpoint(c *C, name string) *transport.Endpoint {
+ ep, err := transport.NewEndpoint(fmt.Sprintf("http://localhost:%d/%s", s.port, name))
+ c.Assert(err, IsNil)
+
+ return ep
+}
+
+func (s *BaseSuite) TearDownTest(c *C) {
+ err := os.RemoveAll(s.base)
+ c.Assert(err, IsNil)
+}
diff --git a/plumbing/transport/http/receive_pack.go b/plumbing/transport/http/receive_pack.go
index d2dfeb7..e5cae28 100644
--- a/plumbing/transport/http/receive_pack.go
+++ b/plumbing/transport/http/receive_pack.go
@@ -19,7 +19,7 @@ type rpSession struct {
*session
}
-func newReceivePackSession(c *http.Client, ep transport.Endpoint, auth transport.AuthMethod) (transport.ReceivePackSession, error) {
+func newReceivePackSession(c *http.Client, ep *transport.Endpoint, auth transport.AuthMethod) (transport.ReceivePackSession, error) {
s, err := newSession(c, ep, auth)
return &rpSession{s}, err
}
@@ -89,7 +89,7 @@ func (s *rpSession) doRequest(
return nil, plumbing.NewPermanentError(err)
}
- applyHeadersToRequest(req, content, s.endpoint.Host(), transport.ReceivePackServiceName)
+ applyHeadersToRequest(req, content, s.endpoint.Host, transport.ReceivePackServiceName)
s.applyAuthToRequest(req)
res, err := s.client.Do(req.WithContext(ctx))
diff --git a/plumbing/transport/http/receive_pack_test.go b/plumbing/transport/http/receive_pack_test.go
index d870e5d..737d792 100644
--- a/plumbing/transport/http/receive_pack_test.go
+++ b/plumbing/transport/http/receive_pack_test.go
@@ -1,122 +1,24 @@
package http
import (
- "fmt"
- "io"
- "io/ioutil"
- "log"
- "net"
- "net/http"
- "net/http/cgi"
- "os"
- "os/exec"
- "path/filepath"
- "strings"
-
- "gopkg.in/src-d/go-git.v4/plumbing/transport"
"gopkg.in/src-d/go-git.v4/plumbing/transport/test"
- "github.com/src-d/go-git-fixtures"
+ "gopkg.in/src-d/go-git-fixtures.v3"
. "gopkg.in/check.v1"
)
type ReceivePackSuite struct {
test.ReceivePackSuite
- fixtures.Suite
-
- base string
+ BaseSuite
}
var _ = Suite(&ReceivePackSuite{})
func (s *ReceivePackSuite) SetUpTest(c *C) {
- s.ReceivePackSuite.Client = DefaultClient
-
- port, err := freePort()
- c.Assert(err, IsNil)
-
- base, err := ioutil.TempDir(os.TempDir(), "go-git-http-backend-test")
- c.Assert(err, IsNil)
- s.base = base
-
- host := fmt.Sprintf("localhost_%d", port)
- interpolatedBase := filepath.Join(base, host)
- err = os.MkdirAll(interpolatedBase, 0755)
- c.Assert(err, IsNil)
-
- dotgit := fixtures.Basic().One().DotGit().Root()
- prepareRepo(c, dotgit)
- err = os.Rename(dotgit, filepath.Join(interpolatedBase, "basic.git"))
- c.Assert(err, IsNil)
-
- ep, err := transport.NewEndpoint(fmt.Sprintf("http://localhost:%d/basic.git", port))
- c.Assert(err, IsNil)
- s.ReceivePackSuite.Endpoint = ep
-
- dotgit = fixtures.ByTag("empty").One().DotGit().Root()
- prepareRepo(c, dotgit)
- err = os.Rename(dotgit, filepath.Join(interpolatedBase, "empty.git"))
- c.Assert(err, IsNil)
-
- ep, err = transport.NewEndpoint(fmt.Sprintf("http://localhost:%d/empty.git", port))
- c.Assert(err, IsNil)
- s.ReceivePackSuite.EmptyEndpoint = ep
-
- ep, err = transport.NewEndpoint(fmt.Sprintf("http://localhost:%d/non-existent.git", port))
- c.Assert(err, IsNil)
- s.ReceivePackSuite.NonExistentEndpoint = ep
-
- cmd := exec.Command("git", "--exec-path")
- out, err := cmd.CombinedOutput()
- c.Assert(err, IsNil)
- p := filepath.Join(strings.Trim(string(out), "\n"), "git-http-backend")
+ s.BaseSuite.SetUpTest(c)
- h := &cgi.Handler{
- Path: p,
- Env: []string{"GIT_HTTP_EXPORT_ALL=true", fmt.Sprintf("GIT_PROJECT_ROOT=%s", interpolatedBase)},
- }
-
- go func() {
- log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), h))
- }()
-}
-
-func (s *ReceivePackSuite) TearDownTest(c *C) {
- err := os.RemoveAll(s.base)
- c.Assert(err, IsNil)
-}
-
-func freePort() (int, error) {
- addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
- if err != nil {
- return 0, err
- }
-
- l, err := net.ListenTCP("tcp", addr)
- if err != nil {
- return 0, err
- }
-
- return l.Addr().(*net.TCPAddr).Port, l.Close()
-}
-
-const bareConfig = `[core]
-repositoryformatversion = 0
-filemode = true
-bare = true
-[http]
-receivepack = true`
-
-func prepareRepo(c *C, path string) {
- // git-receive-pack refuses to update refs/heads/master on non-bare repo
- // so we ensure bare repo config.
- config := filepath.Join(path, "config")
- if _, err := os.Stat(config); err == nil {
- f, err := os.OpenFile(config, os.O_TRUNC|os.O_WRONLY, 0)
- c.Assert(err, IsNil)
- content := strings.NewReader(bareConfig)
- _, err = io.Copy(f, content)
- c.Assert(err, IsNil)
- c.Assert(f.Close(), IsNil)
- }
+ s.ReceivePackSuite.Client = DefaultClient
+ s.ReceivePackSuite.Endpoint = s.prepareRepository(c, fixtures.Basic().One(), "basic.git")
+ s.ReceivePackSuite.EmptyEndpoint = s.prepareRepository(c, fixtures.ByTag("empty").One(), "empty.git")
+ s.ReceivePackSuite.NonExistentEndpoint = s.newEndpoint(c, "non-existent.git")
}
diff --git a/plumbing/transport/http/upload_pack.go b/plumbing/transport/http/upload_pack.go
index c5ac325..85a57a5 100644
--- a/plumbing/transport/http/upload_pack.go
+++ b/plumbing/transport/http/upload_pack.go
@@ -19,9 +19,8 @@ type upSession struct {
*session
}
-func newUploadPackSession(c *http.Client, ep transport.Endpoint, auth transport.AuthMethod) (transport.UploadPackSession, error) {
+func newUploadPackSession(c *http.Client, ep *transport.Endpoint, auth transport.AuthMethod) (transport.UploadPackSession, error) {
s, err := newSession(c, ep, auth)
-
return &upSession{s}, err
}
@@ -88,7 +87,7 @@ func (s *upSession) doRequest(
return nil, plumbing.NewPermanentError(err)
}
- applyHeadersToRequest(req, content, s.endpoint.Host(), transport.UploadPackServiceName)
+ applyHeadersToRequest(req, content, s.endpoint.Host, transport.UploadPackServiceName)
s.applyAuthToRequest(req)
res, err := s.client.Do(req.WithContext(ctx))
diff --git a/plumbing/transport/http/upload_pack_test.go b/plumbing/transport/http/upload_pack_test.go
index 57d5f46..fbd28c7 100644
--- a/plumbing/transport/http/upload_pack_test.go
+++ b/plumbing/transport/http/upload_pack_test.go
@@ -1,7 +1,10 @@
package http
import (
+ "fmt"
"io/ioutil"
+ "os"
+ "path/filepath"
"gopkg.in/src-d/go-git.v4/plumbing"
"gopkg.in/src-d/go-git.v4/plumbing/protocol/packp"
@@ -9,28 +12,22 @@ import (
"gopkg.in/src-d/go-git.v4/plumbing/transport/test"
. "gopkg.in/check.v1"
+ "gopkg.in/src-d/go-git-fixtures.v3"
)
type UploadPackSuite struct {
test.UploadPackSuite
+ BaseSuite
}
var _ = Suite(&UploadPackSuite{})
func (s *UploadPackSuite) SetUpSuite(c *C) {
+ s.BaseSuite.SetUpTest(c)
s.UploadPackSuite.Client = DefaultClient
-
- ep, err := transport.NewEndpoint("https://github.com/git-fixtures/basic.git")
- c.Assert(err, IsNil)
- s.UploadPackSuite.Endpoint = ep
-
- ep, err = transport.NewEndpoint("https://github.com/git-fixtures/empty.git")
- c.Assert(err, IsNil)
- s.UploadPackSuite.EmptyEndpoint = ep
-
- ep, err = transport.NewEndpoint("https://github.com/git-fixtures/non-existent.git")
- c.Assert(err, IsNil)
- s.UploadPackSuite.NonExistentEndpoint = ep
+ s.UploadPackSuite.Endpoint = s.prepareRepository(c, fixtures.Basic().One(), "basic.git")
+ s.UploadPackSuite.EmptyEndpoint = s.prepareRepository(c, fixtures.ByTag("empty").One(), "empty.git")
+ s.UploadPackSuite.NonExistentEndpoint = s.newEndpoint(c, "non-existent.git")
}
// Overwritten, different behaviour for HTTP.
@@ -38,7 +35,7 @@ func (s *UploadPackSuite) TestAdvertisedReferencesNotExists(c *C) {
r, err := s.Client.NewUploadPackSession(s.NonExistentEndpoint, s.EmptyAuth)
c.Assert(err, IsNil)
info, err := r.AdvertisedReferences()
- c.Assert(err, Equals, transport.ErrAuthenticationRequired)
+ c.Assert(err, Equals, transport.ErrRepositoryNotFound)
c.Assert(info, IsNil)
}
@@ -58,3 +55,23 @@ func (s *UploadPackSuite) TestuploadPackRequestToReader(c *C) {
"0009done\n",
)
}
+
+func (s *UploadPackSuite) prepareRepository(c *C, f *fixtures.Fixture, name string) *transport.Endpoint {
+ fs := f.DotGit()
+
+ err := fixtures.EnsureIsBare(fs)
+ c.Assert(err, IsNil)
+
+ path := filepath.Join(s.base, name)
+ err = os.Rename(fs.Root(), path)
+ c.Assert(err, IsNil)
+
+ return s.newEndpoint(c, name)
+}
+
+func (s *UploadPackSuite) newEndpoint(c *C, name string) *transport.Endpoint {
+ ep, err := transport.NewEndpoint(fmt.Sprintf("http://localhost:%d/%s", s.port, name))
+ c.Assert(err, IsNil)
+
+ return ep
+}
diff --git a/plumbing/transport/internal/common/common.go b/plumbing/transport/internal/common/common.go
index 598c6b1..8ec1ea5 100644
--- a/plumbing/transport/internal/common/common.go
+++ b/plumbing/transport/internal/common/common.go
@@ -39,7 +39,7 @@ type Commander interface {
// error should be returned if the endpoint is not supported or the
// command cannot be created (e.g. binary does not exist, connection
// cannot be established).
- Command(cmd string, ep transport.Endpoint, auth transport.AuthMethod) (Command, error)
+ Command(cmd string, ep *transport.Endpoint, auth transport.AuthMethod) (Command, error)
}
// Command is used for a single command execution.
@@ -83,14 +83,14 @@ func NewClient(runner Commander) transport.Transport {
}
// NewUploadPackSession creates a new UploadPackSession.
-func (c *client) NewUploadPackSession(ep transport.Endpoint, auth transport.AuthMethod) (
+func (c *client) NewUploadPackSession(ep *transport.Endpoint, auth transport.AuthMethod) (
transport.UploadPackSession, error) {
return c.newSession(transport.UploadPackServiceName, ep, auth)
}
// NewReceivePackSession creates a new ReceivePackSession.
-func (c *client) NewReceivePackSession(ep transport.Endpoint, auth transport.AuthMethod) (
+func (c *client) NewReceivePackSession(ep *transport.Endpoint, auth transport.AuthMethod) (
transport.ReceivePackSession, error) {
return c.newSession(transport.ReceivePackServiceName, ep, auth)
@@ -108,7 +108,7 @@ type session struct {
firstErrLine chan string
}
-func (c *client) newSession(s string, ep transport.Endpoint, auth transport.AuthMethod) (*session, error) {
+func (c *client) newSession(s string, ep *transport.Endpoint, auth transport.AuthMethod) (*session, error) {
cmd, err := c.cmdr.Command(s, ep, auth)
if err != nil {
return nil, err
diff --git a/plumbing/transport/server/loader.go b/plumbing/transport/server/loader.go
index 028ead4..c83752c 100644
--- a/plumbing/transport/server/loader.go
+++ b/plumbing/transport/server/loader.go
@@ -5,8 +5,8 @@ import (
"gopkg.in/src-d/go-git.v4/plumbing/transport"
"gopkg.in/src-d/go-git.v4/storage/filesystem"
- "gopkg.in/src-d/go-billy.v3"
- "gopkg.in/src-d/go-billy.v3/osfs"
+ "gopkg.in/src-d/go-billy.v4"
+ "gopkg.in/src-d/go-billy.v4/osfs"
)
// DefaultLoader is a filesystem loader ignoring host and resolving paths to /.
@@ -17,7 +17,7 @@ type Loader interface {
// Load loads a storer.Storer given a transport.Endpoint.
// Returns transport.ErrRepositoryNotFound if the repository does not
// exist.
- Load(ep transport.Endpoint) (storer.Storer, error)
+ Load(ep *transport.Endpoint) (storer.Storer, error)
}
type fsLoader struct {
@@ -33,8 +33,8 @@ func NewFilesystemLoader(base billy.Filesystem) Loader {
// Load looks up the endpoint's path in the base file system and returns a
// storer for it. Returns transport.ErrRepositoryNotFound if a repository does
// not exist in the given path.
-func (l *fsLoader) Load(ep transport.Endpoint) (storer.Storer, error) {
- fs, err := l.base.Chroot(ep.Path())
+func (l *fsLoader) Load(ep *transport.Endpoint) (storer.Storer, error) {
+ fs, err := l.base.Chroot(ep.Path)
if err != nil {
return nil, err
}
@@ -53,7 +53,7 @@ type MapLoader map[string]storer.Storer
// Load returns a storer.Storer for given a transport.Endpoint by looking it up
// in the map. Returns transport.ErrRepositoryNotFound if the endpoint does not
// exist.
-func (l MapLoader) Load(ep transport.Endpoint) (storer.Storer, error) {
+func (l MapLoader) Load(ep *transport.Endpoint) (storer.Storer, error) {
s, ok := l[ep.String()]
if !ok {
return nil, transport.ErrRepositoryNotFound
diff --git a/plumbing/transport/server/loader_test.go b/plumbing/transport/server/loader_test.go
index 38fabe3..f35511d 100644
--- a/plumbing/transport/server/loader_test.go
+++ b/plumbing/transport/server/loader_test.go
@@ -26,7 +26,7 @@ func (s *LoaderSuite) SetUpSuite(c *C) {
c.Assert(exec.Command("git", "init", "--bare", s.RepoPath).Run(), IsNil)
}
-func (s *LoaderSuite) endpoint(c *C, url string) transport.Endpoint {
+func (s *LoaderSuite) endpoint(c *C, url string) *transport.Endpoint {
ep, err := transport.NewEndpoint(url)
c.Assert(err, IsNil)
return ep
diff --git a/plumbing/transport/server/receive_pack_test.go b/plumbing/transport/server/receive_pack_test.go
index 54c2fba..39fa979 100644
--- a/plumbing/transport/server/receive_pack_test.go
+++ b/plumbing/transport/server/receive_pack_test.go
@@ -2,14 +2,12 @@ package server_test
import (
"gopkg.in/src-d/go-git.v4/plumbing/transport"
- "gopkg.in/src-d/go-git.v4/plumbing/transport/test"
. "gopkg.in/check.v1"
)
type ReceivePackSuite struct {
BaseSuite
- test.ReceivePackSuite
}
var _ = Suite(&ReceivePackSuite{})
@@ -20,7 +18,7 @@ func (s *ReceivePackSuite) SetUpSuite(c *C) {
}
func (s *ReceivePackSuite) SetUpTest(c *C) {
- s.prepareRepositories(c, &s.Endpoint, &s.EmptyEndpoint, &s.NonExistentEndpoint)
+ s.prepareRepositories(c)
}
func (s *ReceivePackSuite) TearDownTest(c *C) {
diff --git a/plumbing/transport/server/server.go b/plumbing/transport/server/server.go
index be36de5..2357bd6 100644
--- a/plumbing/transport/server/server.go
+++ b/plumbing/transport/server/server.go
@@ -43,7 +43,7 @@ func NewClient(loader Loader) transport.Transport {
}
}
-func (s *server) NewUploadPackSession(ep transport.Endpoint, auth transport.AuthMethod) (transport.UploadPackSession, error) {
+func (s *server) NewUploadPackSession(ep *transport.Endpoint, auth transport.AuthMethod) (transport.UploadPackSession, error) {
sto, err := s.loader.Load(ep)
if err != nil {
return nil, err
@@ -52,7 +52,7 @@ func (s *server) NewUploadPackSession(ep transport.Endpoint, auth transport.Auth
return s.handler.NewUploadPackSession(sto)
}
-func (s *server) NewReceivePackSession(ep transport.Endpoint, auth transport.AuthMethod) (transport.ReceivePackSession, error) {
+func (s *server) NewReceivePackSession(ep *transport.Endpoint, auth transport.AuthMethod) (transport.ReceivePackSession, error) {
sto, err := s.loader.Load(ep)
if err != nil {
return nil, err
@@ -165,7 +165,8 @@ func (s *upSession) UploadPack(ctx context.Context, req *packp.UploadPackRequest
pr, pw := io.Pipe()
e := packfile.NewEncoder(pw, s.storer, false)
go func() {
- _, err := e.Encode(objs)
+ // TODO: plumb through a pack window.
+ _, err := e.Encode(objs, 10)
pw.CloseWithError(err)
}()
diff --git a/plumbing/transport/server/server_test.go b/plumbing/transport/server/server_test.go
index 7912768..33d74d1 100644
--- a/plumbing/transport/server/server_test.go
+++ b/plumbing/transport/server/server_test.go
@@ -3,20 +3,23 @@ package server_test
import (
"testing"
- "github.com/src-d/go-git-fixtures"
"gopkg.in/src-d/go-git.v4/plumbing/transport"
"gopkg.in/src-d/go-git.v4/plumbing/transport/client"
"gopkg.in/src-d/go-git.v4/plumbing/transport/server"
+ "gopkg.in/src-d/go-git.v4/plumbing/transport/test"
"gopkg.in/src-d/go-git.v4/storage/filesystem"
"gopkg.in/src-d/go-git.v4/storage/memory"
. "gopkg.in/check.v1"
+ "gopkg.in/src-d/go-git-fixtures.v3"
)
func Test(t *testing.T) { TestingT(t) }
type BaseSuite struct {
fixtures.Suite
+ test.ReceivePackSuite
+
loader server.MapLoader
client transport.Transport
clientBackup transport.Transport
@@ -44,27 +47,19 @@ func (s *BaseSuite) TearDownSuite(c *C) {
}
}
-func (s *BaseSuite) prepareRepositories(c *C, basic *transport.Endpoint,
- empty *transport.Endpoint, nonExistent *transport.Endpoint) {
+func (s *BaseSuite) prepareRepositories(c *C) {
+ var err error
- f := fixtures.Basic().One()
- fs := f.DotGit()
- path := fs.Root()
- ep, err := transport.NewEndpoint(path)
+ fs := fixtures.Basic().One().DotGit()
+ s.Endpoint, err = transport.NewEndpoint(fs.Root())
c.Assert(err, IsNil)
- *basic = ep
- sto, err := filesystem.NewStorage(fs)
+ s.loader[s.Endpoint.String()], err = filesystem.NewStorage(fs)
c.Assert(err, IsNil)
- s.loader[ep.String()] = sto
- path = "/empty.git"
- ep, err = transport.NewEndpoint(path)
+ s.EmptyEndpoint, err = transport.NewEndpoint("/empty.git")
c.Assert(err, IsNil)
- *empty = ep
- s.loader[ep.String()] = memory.NewStorage()
+ s.loader[s.EmptyEndpoint.String()] = memory.NewStorage()
- path = "/non-existent.git"
- ep, err = transport.NewEndpoint(path)
+ s.NonExistentEndpoint, err = transport.NewEndpoint("/non-existent.git")
c.Assert(err, IsNil)
- *nonExistent = ep
}
diff --git a/plumbing/transport/server/upload_pack_test.go b/plumbing/transport/server/upload_pack_test.go
index 99473d3..f252a75 100644
--- a/plumbing/transport/server/upload_pack_test.go
+++ b/plumbing/transport/server/upload_pack_test.go
@@ -2,34 +2,23 @@ package server_test
import (
"gopkg.in/src-d/go-git.v4/plumbing/transport"
- "gopkg.in/src-d/go-git.v4/plumbing/transport/test"
. "gopkg.in/check.v1"
)
type UploadPackSuite struct {
BaseSuite
- test.UploadPackSuite
}
var _ = Suite(&UploadPackSuite{})
func (s *UploadPackSuite) SetUpSuite(c *C) {
s.BaseSuite.SetUpSuite(c)
- s.UploadPackSuite.Client = s.client
+ s.Client = s.client
}
func (s *UploadPackSuite) SetUpTest(c *C) {
- s.prepareRepositories(c, &s.Endpoint, &s.EmptyEndpoint, &s.NonExistentEndpoint)
-}
-
-// Overwritten, it's not an error in server-side.
-func (s *UploadPackSuite) TestAdvertisedReferencesEmpty(c *C) {
- r, err := s.Client.NewUploadPackSession(s.EmptyEndpoint, s.EmptyAuth)
- c.Assert(err, IsNil)
- ar, err := r.AdvertisedReferences()
- c.Assert(err, IsNil)
- c.Assert(len(ar.References), Equals, 0)
+ s.prepareRepositories(c)
}
// Overwritten, server returns error earlier.
@@ -57,5 +46,5 @@ func (s *ClientLikeUploadPackSuite) SetUpSuite(c *C) {
}
func (s *ClientLikeUploadPackSuite) TestAdvertisedReferencesEmpty(c *C) {
- s.UploadPackSuite.UploadPackSuite.TestAdvertisedReferencesEmpty(c)
+ s.UploadPackSuite.TestAdvertisedReferencesEmpty(c)
}
diff --git a/plumbing/transport/ssh/auth_method.go b/plumbing/transport/ssh/auth_method.go
index baae181..a092b29 100644
--- a/plumbing/transport/ssh/auth_method.go
+++ b/plumbing/transport/ssh/auth_method.go
@@ -25,8 +25,9 @@ const DefaultUsername = "git"
// configuration needed to establish an ssh connection.
type AuthMethod interface {
transport.AuthMethod
- clientConfig() *ssh.ClientConfig
- hostKeyCallback() (ssh.HostKeyCallback, error)
+ // ClientConfig should return a valid ssh.ClientConfig to be used to create
+ // a connection to the SSH server.
+ ClientConfig() (*ssh.ClientConfig, error)
}
// The names of the AuthMethod implementations. To be returned by the
@@ -45,7 +46,7 @@ const (
type KeyboardInteractive struct {
User string
Challenge ssh.KeyboardInteractiveChallenge
- baseAuthMethod
+ HostKeyCallbackHelper
}
func (a *KeyboardInteractive) Name() string {
@@ -56,18 +57,20 @@ func (a *KeyboardInteractive) String() string {
return fmt.Sprintf("user: %s, name: %s", a.User, a.Name())
}
-func (a *KeyboardInteractive) clientConfig() *ssh.ClientConfig {
- return &ssh.ClientConfig{
+func (a *KeyboardInteractive) ClientConfig() (*ssh.ClientConfig, error) {
+ return a.SetHostKeyCallback(&ssh.ClientConfig{
User: a.User,
- Auth: []ssh.AuthMethod{ssh.KeyboardInteractiveChallenge(a.Challenge)},
- }
+ Auth: []ssh.AuthMethod{
+ ssh.KeyboardInteractiveChallenge(a.Challenge),
+ },
+ })
}
// Password implements AuthMethod by using the given password.
type Password struct {
- User string
- Pass string
- baseAuthMethod
+ User string
+ Password string
+ HostKeyCallbackHelper
}
func (a *Password) Name() string {
@@ -78,11 +81,11 @@ func (a *Password) String() string {
return fmt.Sprintf("user: %s, name: %s", a.User, a.Name())
}
-func (a *Password) clientConfig() *ssh.ClientConfig {
- return &ssh.ClientConfig{
+func (a *Password) ClientConfig() (*ssh.ClientConfig, error) {
+ return a.SetHostKeyCallback(&ssh.ClientConfig{
User: a.User,
- Auth: []ssh.AuthMethod{ssh.Password(a.Pass)},
- }
+ Auth: []ssh.AuthMethod{ssh.Password(a.Password)},
+ })
}
// PasswordCallback implements AuthMethod by using a callback
@@ -90,7 +93,7 @@ func (a *Password) clientConfig() *ssh.ClientConfig {
type PasswordCallback struct {
User string
Callback func() (pass string, err error)
- baseAuthMethod
+ HostKeyCallbackHelper
}
func (a *PasswordCallback) Name() string {
@@ -101,25 +104,25 @@ func (a *PasswordCallback) String() string {
return fmt.Sprintf("user: %s, name: %s", a.User, a.Name())
}
-func (a *PasswordCallback) clientConfig() *ssh.ClientConfig {
- return &ssh.ClientConfig{
+func (a *PasswordCallback) ClientConfig() (*ssh.ClientConfig, error) {
+ return a.SetHostKeyCallback(&ssh.ClientConfig{
User: a.User,
Auth: []ssh.AuthMethod{ssh.PasswordCallback(a.Callback)},
- }
+ })
}
// PublicKeys implements AuthMethod by using the given key pairs.
type PublicKeys struct {
User string
Signer ssh.Signer
- baseAuthMethod
+ HostKeyCallbackHelper
}
// NewPublicKeys returns a PublicKeys from a PEM encoded private key. An
// encryption password should be given if the pemBytes contains a password
// encrypted PEM block otherwise password should be empty. It supports RSA
// (PKCS#1), DSA (OpenSSL), and ECDSA private keys.
-func NewPublicKeys(user string, pemBytes []byte, password string) (AuthMethod, error) {
+func NewPublicKeys(user string, pemBytes []byte, password string) (*PublicKeys, error) {
block, _ := pem.Decode(pemBytes)
if x509.IsEncryptedPEMBlock(block) {
key, err := x509.DecryptPEMBlock(block, []byte(password))
@@ -142,7 +145,7 @@ func NewPublicKeys(user string, pemBytes []byte, password string) (AuthMethod, e
// NewPublicKeysFromFile returns a PublicKeys from a file containing a PEM
// encoded private key. An encryption password should be given if the pemBytes
// contains a password encrypted PEM block otherwise password should be empty.
-func NewPublicKeysFromFile(user, pemFile, password string) (AuthMethod, error) {
+func NewPublicKeysFromFile(user, pemFile, password string) (*PublicKeys, error) {
bytes, err := ioutil.ReadFile(pemFile)
if err != nil {
return nil, err
@@ -159,11 +162,11 @@ func (a *PublicKeys) String() string {
return fmt.Sprintf("user: %s, name: %s", a.User, a.Name())
}
-func (a *PublicKeys) clientConfig() *ssh.ClientConfig {
- return &ssh.ClientConfig{
+func (a *PublicKeys) ClientConfig() (*ssh.ClientConfig, error) {
+ return a.SetHostKeyCallback(&ssh.ClientConfig{
User: a.User,
Auth: []ssh.AuthMethod{ssh.PublicKeys(a.Signer)},
- }
+ })
}
func username() (string, error) {
@@ -173,9 +176,11 @@ func username() (string, error) {
} else {
username = os.Getenv("USER")
}
+
if username == "" {
return "", errors.New("failed to get username")
}
+
return username, nil
}
@@ -184,13 +189,13 @@ func username() (string, error) {
type PublicKeysCallback struct {
User string
Callback func() (signers []ssh.Signer, err error)
- baseAuthMethod
+ HostKeyCallbackHelper
}
// NewSSHAgentAuth returns a PublicKeysCallback based on a SSH agent, it opens
// a pipe with the SSH agent and uses the pipe as the implementer of the public
// key callback function.
-func NewSSHAgentAuth(u string) (AuthMethod, error) {
+func NewSSHAgentAuth(u string) (*PublicKeysCallback, error) {
var err error
if u == "" {
u, err = username()
@@ -218,11 +223,11 @@ func (a *PublicKeysCallback) String() string {
return fmt.Sprintf("user: %s, name: %s", a.User, a.Name())
}
-func (a *PublicKeysCallback) clientConfig() *ssh.ClientConfig {
- return &ssh.ClientConfig{
+func (a *PublicKeysCallback) ClientConfig() (*ssh.ClientConfig, error) {
+ return a.SetHostKeyCallback(&ssh.ClientConfig{
User: a.User,
Auth: []ssh.AuthMethod{ssh.PublicKeysCallback(a.Callback)},
- }
+ })
}
// NewKnownHostsCallback returns ssh.HostKeyCallback based on a file based on a
@@ -287,17 +292,26 @@ func filterKnownHostsFiles(files ...string) ([]string, error) {
return out, nil
}
-type baseAuthMethod struct {
+// HostKeyCallbackHelper is a helper that provides common functionality to
+// configure HostKeyCallback into a ssh.ClientConfig.
+type HostKeyCallbackHelper struct {
// HostKeyCallback is the function type used for verifying server keys.
- // If nil default callback will be create using NewKnownHostsHostKeyCallback
+ // If nil default callback will be create using NewKnownHostsCallback
// without argument.
HostKeyCallback ssh.HostKeyCallback
}
-func (m *baseAuthMethod) hostKeyCallback() (ssh.HostKeyCallback, error) {
+// SetHostKeyCallback sets the field HostKeyCallback in the given cfg. If
+// HostKeyCallback is empty a default callback is created using
+// NewKnownHostsCallback.
+func (m *HostKeyCallbackHelper) SetHostKeyCallback(cfg *ssh.ClientConfig) (*ssh.ClientConfig, error) {
+ var err error
if m.HostKeyCallback == nil {
- return NewKnownHostsCallback()
+ if m.HostKeyCallback, err = NewKnownHostsCallback(); err != nil {
+ return cfg, err
+ }
}
- return m.HostKeyCallback, nil
+ cfg.HostKeyCallback = m.HostKeyCallback
+ return cfg, nil
}
diff --git a/plumbing/transport/ssh/auth_method_test.go b/plumbing/transport/ssh/auth_method_test.go
index 2ee5100..1e77ca0 100644
--- a/plumbing/transport/ssh/auth_method_test.go
+++ b/plumbing/transport/ssh/auth_method_test.go
@@ -32,16 +32,16 @@ func (s *SuiteCommon) TestKeyboardInteractiveString(c *C) {
func (s *SuiteCommon) TestPasswordName(c *C) {
a := &Password{
- User: "test",
- Pass: "",
+ User: "test",
+ Password: "",
}
c.Assert(a.Name(), Equals, PasswordName)
}
func (s *SuiteCommon) TestPasswordString(c *C) {
a := &Password{
- User: "test",
- Pass: "",
+ User: "test",
+ Password: "",
}
c.Assert(a.String(), Equals, fmt.Sprintf("user: test, name: %s", PasswordName))
}
diff --git a/plumbing/transport/ssh/common.go b/plumbing/transport/ssh/common.go
index af79dfb..f5bc9a7 100644
--- a/plumbing/transport/ssh/common.go
+++ b/plumbing/transport/ssh/common.go
@@ -31,7 +31,7 @@ type runner struct {
config *ssh.ClientConfig
}
-func (r *runner) Command(cmd string, ep transport.Endpoint, auth transport.AuthMethod) (common.Command, error) {
+func (r *runner) Command(cmd string, ep *transport.Endpoint, auth transport.AuthMethod) (common.Command, error) {
c := &command{command: cmd, endpoint: ep, config: r.config}
if auth != nil {
c.setAuth(auth)
@@ -47,7 +47,7 @@ type command struct {
*ssh.Session
connected bool
command string
- endpoint transport.Endpoint
+ endpoint *transport.Endpoint
client *ssh.Client
auth AuthMethod
config *ssh.ClientConfig
@@ -98,8 +98,7 @@ func (c *command) connect() error {
}
var err error
- config := c.auth.clientConfig()
- config.HostKeyCallback, err = c.auth.hostKeyCallback()
+ config, err := c.auth.ClientConfig()
if err != nil {
return err
}
@@ -122,8 +121,8 @@ func (c *command) connect() error {
}
func (c *command) getHostWithPort() string {
- host := c.endpoint.Host()
- port := c.endpoint.Port()
+ host := c.endpoint.Host
+ port := c.endpoint.Port
if port <= 0 {
port = DefaultPort
}
@@ -133,12 +132,12 @@ func (c *command) getHostWithPort() string {
func (c *command) setAuthFromEndpoint() error {
var err error
- c.auth, err = DefaultAuthBuilder(c.endpoint.User())
+ c.auth, err = DefaultAuthBuilder(c.endpoint.User)
return err
}
-func endpointToCommand(cmd string, ep transport.Endpoint) string {
- return fmt.Sprintf("%s '%s'", cmd, ep.Path())
+func endpointToCommand(cmd string, ep *transport.Endpoint) string {
+ return fmt.Sprintf("%s '%s'", cmd, ep.Path)
}
func overrideConfig(overrides *ssh.ClientConfig, c *ssh.ClientConfig) {
@@ -154,14 +153,8 @@ func overrideConfig(overrides *ssh.ClientConfig, c *ssh.ClientConfig) {
f := t.Field(i)
vcf := vc.FieldByName(f.Name)
vof := vo.FieldByName(f.Name)
- if isZeroValue(vcf) {
- vcf.Set(vof)
- }
+ vcf.Set(vof)
}
*c = vc.Interface().(ssh.ClientConfig)
}
-
-func isZeroValue(v reflect.Value) bool {
- return reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface())
-}
diff --git a/plumbing/transport/ssh/common_test.go b/plumbing/transport/ssh/common_test.go
index 1b07eee..5315e28 100644
--- a/plumbing/transport/ssh/common_test.go
+++ b/plumbing/transport/ssh/common_test.go
@@ -37,5 +37,5 @@ func (s *SuiteCommon) TestOverrideConfigKeep(c *C) {
}
overrideConfig(config, target)
- c.Assert(target.User, Equals, "bar")
+ c.Assert(target.User, Equals, "foo")
}
diff --git a/plumbing/transport/ssh/upload_pack_test.go b/plumbing/transport/ssh/upload_pack_test.go
index cb9baa5..56d1601 100644
--- a/plumbing/transport/ssh/upload_pack_test.go
+++ b/plumbing/transport/ssh/upload_pack_test.go
@@ -1,47 +1,139 @@
package ssh
import (
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "net"
"os"
+ "os/exec"
+ "path/filepath"
+ "strings"
"gopkg.in/src-d/go-git.v4/plumbing/transport"
"gopkg.in/src-d/go-git.v4/plumbing/transport/test"
+ "github.com/gliderlabs/ssh"
+ "gopkg.in/src-d/go-git-fixtures.v3"
+ stdssh "golang.org/x/crypto/ssh"
. "gopkg.in/check.v1"
)
type UploadPackSuite struct {
test.UploadPackSuite
+ fixtures.Suite
+
+ port int
+ base string
}
var _ = Suite(&UploadPackSuite{})
func (s *UploadPackSuite) SetUpSuite(c *C) {
- s.setAuthBuilder(c)
- s.UploadPackSuite.Client = DefaultClient
+ s.Suite.SetUpSuite(c)
+
+ l, err := net.Listen("tcp", "localhost:0")
+ c.Assert(err, IsNil)
- ep, err := transport.NewEndpoint("git@github.com:git-fixtures/basic.git")
+ s.port = l.Addr().(*net.TCPAddr).Port
+ s.base, err = ioutil.TempDir(os.TempDir(), fmt.Sprintf("go-git-ssh-%d", s.port))
c.Assert(err, IsNil)
- s.UploadPackSuite.Endpoint = ep
- ep, err = transport.NewEndpoint("git@github.com:git-fixtures/empty.git")
+ DefaultAuthBuilder = func(user string) (AuthMethod, error) {
+ return &Password{User: user}, nil
+ }
+
+ s.UploadPackSuite.Client = NewClient(&stdssh.ClientConfig{
+ HostKeyCallback: stdssh.InsecureIgnoreHostKey(),
+ })
+
+ s.UploadPackSuite.Endpoint = s.prepareRepository(c, fixtures.Basic().One(), "basic.git")
+ s.UploadPackSuite.EmptyEndpoint = s.prepareRepository(c, fixtures.ByTag("empty").One(), "empty.git")
+ s.UploadPackSuite.NonExistentEndpoint = s.newEndpoint(c, "non-existent.git")
+
+ server := &ssh.Server{Handler: handlerSSH}
+ go func() {
+ log.Fatal(server.Serve(l))
+ }()
+}
+
+func (s *UploadPackSuite) prepareRepository(c *C, f *fixtures.Fixture, name string) *transport.Endpoint {
+ fs := f.DotGit()
+
+ err := fixtures.EnsureIsBare(fs)
c.Assert(err, IsNil)
- s.UploadPackSuite.EmptyEndpoint = ep
- ep, err = transport.NewEndpoint("git@github.com:git-fixtures/non-existent.git")
+ path := filepath.Join(s.base, name)
+ err = os.Rename(fs.Root(), path)
c.Assert(err, IsNil)
- s.UploadPackSuite.NonExistentEndpoint = ep
+
+ return s.newEndpoint(c, name)
+}
+
+func (s *UploadPackSuite) newEndpoint(c *C, name string) *transport.Endpoint {
+ ep, err := transport.NewEndpoint(fmt.Sprintf(
+ "ssh://git@localhost:%d/%s/%s", s.port, filepath.ToSlash(s.base), name,
+ ))
+
+ c.Assert(err, IsNil)
+ return ep
}
-func (s *UploadPackSuite) setAuthBuilder(c *C) {
- privateKey := os.Getenv("SSH_TEST_PRIVATE_KEY")
- if privateKey != "" {
- DefaultAuthBuilder = func(user string) (AuthMethod, error) {
- return NewPublicKeysFromFile(user, privateKey, "")
- }
+func handlerSSH(s ssh.Session) {
+ cmd, stdin, stderr, stdout, err := buildCommand(s.Command())
+ if err != nil {
+ fmt.Println(err)
+ return
}
- if privateKey == "" && os.Getenv("SSH_AUTH_SOCK") == "" {
- c.Skip("SSH_AUTH_SOCK or SSH_TEST_PRIVATE_KEY are required")
+ if err := cmd.Start(); err != nil {
+ fmt.Println(err)
return
}
+
+ go func() {
+ defer stdin.Close()
+ io.Copy(stdin, s)
+ }()
+
+ go func() {
+ defer stderr.Close()
+ io.Copy(s.Stderr(), stderr)
+ }()
+
+ defer stdout.Close()
+ io.Copy(s, stdout)
+
+ if err := cmd.Wait(); err != nil {
+ return
+ }
+}
+
+func buildCommand(c []string) (cmd *exec.Cmd, stdin io.WriteCloser, stderr, stdout io.ReadCloser, err error) {
+ if len(c) != 2 {
+ err = fmt.Errorf("invalid command")
+ return
+ }
+
+ // fix for Windows environments
+ path := strings.Replace(c[1], "/C:/", "C:/", 1)
+
+ cmd = exec.Command(c[0], path)
+ stdout, err = cmd.StdoutPipe()
+ if err != nil {
+ return
+ }
+
+ stdin, err = cmd.StdinPipe()
+ if err != nil {
+ return
+ }
+
+ stderr, err = cmd.StderrPipe()
+ if err != nil {
+ return
+ }
+
+ return
}
diff --git a/plumbing/transport/test/receive_pack.go b/plumbing/transport/test/receive_pack.go
index d29d9ca..0f3352c 100644
--- a/plumbing/transport/test/receive_pack.go
+++ b/plumbing/transport/test/receive_pack.go
@@ -9,7 +9,6 @@ import (
"io"
"io/ioutil"
- "github.com/src-d/go-git-fixtures"
"gopkg.in/src-d/go-git.v4/plumbing"
"gopkg.in/src-d/go-git.v4/plumbing/format/packfile"
"gopkg.in/src-d/go-git.v4/plumbing/protocol/packp"
@@ -18,12 +17,13 @@ import (
"gopkg.in/src-d/go-git.v4/storage/memory"
. "gopkg.in/check.v1"
+ "gopkg.in/src-d/go-git-fixtures.v3"
)
type ReceivePackSuite struct {
- Endpoint transport.Endpoint
- EmptyEndpoint transport.Endpoint
- NonExistentEndpoint transport.Endpoint
+ Endpoint *transport.Endpoint
+ EmptyEndpoint *transport.Endpoint
+ NonExistentEndpoint *transport.Endpoint
EmptyAuth transport.AuthMethod
Client transport.Transport
}
@@ -213,7 +213,7 @@ func (s *ReceivePackSuite) TestSendPackOnNonEmptyWithReportStatusWithError(c *C)
s.checkRemoteHead(c, endpoint, fixture.Head)
}
-func (s *ReceivePackSuite) receivePackNoCheck(c *C, ep transport.Endpoint,
+func (s *ReceivePackSuite) receivePackNoCheck(c *C, ep *transport.Endpoint,
req *packp.ReferenceUpdateRequest, fixture *fixtures.Fixture,
callAdvertisedReferences bool) (*packp.ReportStatus, error) {
url := ""
@@ -245,7 +245,7 @@ func (s *ReceivePackSuite) receivePackNoCheck(c *C, ep transport.Endpoint,
return r.ReceivePack(context.Background(), req)
}
-func (s *ReceivePackSuite) receivePack(c *C, ep transport.Endpoint,
+func (s *ReceivePackSuite) receivePack(c *C, ep *transport.Endpoint,
req *packp.ReferenceUpdateRequest, fixture *fixtures.Fixture,
callAdvertisedReferences bool) {
@@ -269,11 +269,11 @@ func (s *ReceivePackSuite) receivePack(c *C, ep transport.Endpoint,
}
}
-func (s *ReceivePackSuite) checkRemoteHead(c *C, ep transport.Endpoint, head plumbing.Hash) {
+func (s *ReceivePackSuite) checkRemoteHead(c *C, ep *transport.Endpoint, head plumbing.Hash) {
s.checkRemoteReference(c, ep, "refs/heads/master", head)
}
-func (s *ReceivePackSuite) checkRemoteReference(c *C, ep transport.Endpoint,
+func (s *ReceivePackSuite) checkRemoteReference(c *C, ep *transport.Endpoint,
refName string, head plumbing.Hash) {
r, err := s.Client.NewUploadPackSession(ep, s.EmptyAuth)
@@ -348,7 +348,7 @@ func (s *ReceivePackSuite) testSendPackDeleteReference(c *C) {
func (s *ReceivePackSuite) emptyPackfile() io.ReadCloser {
var buf bytes.Buffer
e := packfile.NewEncoder(&buf, memory.NewStorage(), false)
- _, err := e.Encode(nil)
+ _, err := e.Encode(nil, 10)
if err != nil {
panic(err)
}
diff --git a/plumbing/transport/test/upload_pack.go b/plumbing/transport/test/upload_pack.go
index b3acc4f..70e4e56 100644
--- a/plumbing/transport/test/upload_pack.go
+++ b/plumbing/transport/test/upload_pack.go
@@ -21,9 +21,9 @@ import (
)
type UploadPackSuite struct {
- Endpoint transport.Endpoint
- EmptyEndpoint transport.Endpoint
- NonExistentEndpoint transport.Endpoint
+ Endpoint *transport.Endpoint
+ EmptyEndpoint *transport.Endpoint
+ NonExistentEndpoint *transport.Endpoint
EmptyAuth transport.AuthMethod
Client transport.Transport
}