Skip to content
This repository has been archived by the owner on Sep 11, 2020. It is now read-only.

Commit

Permalink
Merge pull request #10 from alcortesm/file-client
Browse files Browse the repository at this point in the history
Adds external protocol insertion for the clients and protocol selection based on the scheme
  • Loading branch information
mcuadros committed Dec 23, 2015
2 parents 990573b + c8c4a69 commit da5ab9d
Show file tree
Hide file tree
Showing 7 changed files with 180 additions and 27 deletions.
63 changes: 61 additions & 2 deletions clients/common.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,69 @@
// Go-git needs the packfile and the refs of the repo. The
// `NewGitUploadPackService` function returns an object that allows to
// download them.
//
// Go-git supports HTTP and SSH (see `KnownProtocols`) for downloading
// the packfile and the refs, but you can also install your own
// protocols (see `InstallProtocol` below).
//
// Each protocol has its own implementation of
// `NewGitUploadPackService`, but you should generally not use them
// directly, use this package's `NewGitUploadPackService` instead.
package clients

import (
"fmt"
"net/url"

"gopkg.in/src-d/go-git.v2/clients/common"
"gopkg.in/src-d/go-git.v2/clients/http"
"gopkg.in/src-d/go-git.v2/clients/ssh"
)

func NewGitUploadPackService() common.GitUploadPackService {
return http.NewGitUploadPackService()
// ServiceFromURLFunc defines a service returning function for a given
// URL.
type ServiceFromURLFunc func(url string) common.GitUploadPackService

// DefaultProtocols are the protocols supported by default.
// Wrapping is needed because you can not cast a function that
// returns an implementation of an interface to a function that
// returns the interface.
var DefaultProtocols = map[string]ServiceFromURLFunc{
"http": func(s string) common.GitUploadPackService { return http.NewGitUploadPackService(s) },
"https": func(s string) common.GitUploadPackService { return http.NewGitUploadPackService(s) },
"ssh": func(s string) common.GitUploadPackService { return ssh.NewGitUploadPackService(s) },
}

// KnownProtocols holds the current set of known protocols. Initially
// it gets its contents from `DefaultProtocols`. See `InstallProtocol`
// below to add or modify this variable.
var KnownProtocols = make(map[string]ServiceFromURLFunc, len(DefaultProtocols))

func init() {
for k, v := range DefaultProtocols {
KnownProtocols[k] = v
}
}

// NewGitUploadPackService returns the appropiate upload pack service
// among of the set of known protocols: HTTP, SSH. See `InstallProtocol`
// to add or modify protocols.
func NewGitUploadPackService(repoURL string) (common.GitUploadPackService, error) {
u, err := url.Parse(repoURL)
if err != nil {
return nil, fmt.Errorf("invalid url %q", repoURL)
}
srvFn, ok := KnownProtocols[u.Scheme]
if !ok {
return nil, fmt.Errorf("unsupported scheme %q", u.Scheme)
}
return srvFn(repoURL), nil
}

// InstallProtocol adds or modifies an existing protocol.
func InstallProtocol(scheme string, serviceFn ServiceFromURLFunc) {
if serviceFn == nil {
panic("nil service")
}
KnownProtocols[scheme] = serviceFn
}
88 changes: 88 additions & 0 deletions clients/common_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package clients

import (
"fmt"
"io"
"testing"

. "gopkg.in/check.v1"
"gopkg.in/src-d/go-git.v2/clients/common"
)

func Test(t *testing.T) { TestingT(t) }

type SuiteCommon struct{}

var _ = Suite(&SuiteCommon{})

func (s *SuiteCommon) TestNewGitUploadPackService(c *C) {
var tests = [...]struct {
input string
err bool
expected string
}{
{"://example.com", true, "<nil>"},
{"badscheme://github.com/src-d/go-git", true, "<nil>"},
{"http://github.com/src-d/go-git", false, "*http.GitUploadPackService"},
{"https://github.com/src-d/go-git", false, "*http.GitUploadPackService"},
{"ssh://github.com/src-d/go-git", false, "*ssh.GitUploadPackService"},
}

for i, t := range tests {
output, err := NewGitUploadPackService(t.input)
c.Assert(err != nil, Equals, t.err, Commentf("%d) %q: wrong error value", i, t.input))
c.Assert(typeAsString(output), Equals, t.expected, Commentf("%d) %q: wrong type", i, t.input))
}
}

type dummyProtocolService struct{}

func newDummyProtocolService(url string) common.GitUploadPackService {
return &dummyProtocolService{}
}

func (s *dummyProtocolService) Connect(url common.Endpoint) error {
return nil
}

func (s *dummyProtocolService) ConnectWithAuth(url common.Endpoint, auth common.AuthMethod) error {
return nil
}

func (s *dummyProtocolService) Info() (*common.GitUploadPackInfo, error) {
return nil, nil
}

func (s *dummyProtocolService) Fetch(r *common.GitUploadPackRequest) (io.ReadCloser, error) {
return nil, nil
}

func (s *SuiteCommon) TestInstallProtocol(c *C) {
var tests = [...]struct {
scheme string
serviceFn ServiceFromURLFunc
panic bool
}{
{"panic", nil, true},
{"newscheme", newDummyProtocolService, false},
{"http", newDummyProtocolService, false},
}

for i, t := range tests {
if t.panic {
fmt.Println(t.serviceFn == nil)
c.Assert(func() { InstallProtocol(t.scheme, t.serviceFn) }, PanicMatches, `nil service`)
continue
}
InstallProtocol(t.scheme, t.serviceFn)
c.Assert(typeAsString(KnownProtocols[t.scheme]), Equals, typeAsString(t.serviceFn), Commentf("%d) wrong service", i))
// reset to default protocols after installing
if v, ok := DefaultProtocols[t.scheme]; ok {
InstallProtocol(t.scheme, v)
}
}
}

func typeAsString(v interface{}) string {
return fmt.Sprintf("%T", v)
}
3 changes: 2 additions & 1 deletion clients/http/git_upload_pack.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ type GitUploadPackService struct {
auth HTTPAuthMethod
}

func NewGitUploadPackService() *GitUploadPackService {
func NewGitUploadPackService(url string) *GitUploadPackService {
// url ignored
return &GitUploadPackService{
Client: http.DefaultClient,
}
Expand Down
12 changes: 6 additions & 6 deletions clients/http/git_upload_pack_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ var _ = Suite(&SuiteRemote{})
const RepositoryFixture = "https://github.com/tyba/git-fixture"

func (s *SuiteRemote) TestConnect(c *C) {
r := NewGitUploadPackService()
r := NewGitUploadPackService(RepositoryFixture)
c.Assert(r.Connect(RepositoryFixture), IsNil)
}

func (s *SuiteRemote) TestConnectWithAuth(c *C) {
auth := &BasicAuth{}
r := NewGitUploadPackService()
r := NewGitUploadPackService(RepositoryFixture)
c.Assert(r.ConnectWithAuth(RepositoryFixture, auth), IsNil)
c.Assert(r.auth, Equals, auth)
}
Expand All @@ -32,12 +32,12 @@ func (*mockAuth) Name() string { return "" }
func (*mockAuth) String() string { return "" }

func (s *SuiteRemote) TestConnectWithAuthWrongType(c *C) {
r := NewGitUploadPackService()
r := NewGitUploadPackService(RepositoryFixture)
c.Assert(r.ConnectWithAuth(RepositoryFixture, &mockAuth{}), Equals, InvalidAuthMethodErr)
}

func (s *SuiteRemote) TestDefaultBranch(c *C) {
r := NewGitUploadPackService()
r := NewGitUploadPackService(RepositoryFixture)
c.Assert(r.Connect(RepositoryFixture), IsNil)

info, err := r.Info()
Expand All @@ -46,7 +46,7 @@ func (s *SuiteRemote) TestDefaultBranch(c *C) {
}

func (s *SuiteRemote) TestCapabilities(c *C) {
r := NewGitUploadPackService()
r := NewGitUploadPackService(RepositoryFixture)
c.Assert(r.Connect(RepositoryFixture), IsNil)

info, err := r.Info()
Expand All @@ -55,7 +55,7 @@ func (s *SuiteRemote) TestCapabilities(c *C) {
}

func (s *SuiteRemote) TestFetch(c *C) {
r := NewGitUploadPackService()
r := NewGitUploadPackService(RepositoryFixture)
c.Assert(r.Connect(RepositoryFixture), IsNil)

req := &common.GitUploadPackRequest{}
Expand Down
3 changes: 2 additions & 1 deletion clients/ssh/git_upload_pack.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ type GitUploadPackService struct {

// NewGitUploadPackService initialises a GitUploadPackService.
// TODO: remove this, as the struct is zero-value safe.
func NewGitUploadPackService() *GitUploadPackService {
func NewGitUploadPackService(url string) *GitUploadPackService {
// url ignored
return &GitUploadPackService{}
}

Expand Down
32 changes: 16 additions & 16 deletions clients/ssh/git_upload_pack_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const (
)

func (s *SuiteRemote) TestConnect(c *C) {
r := NewGitUploadPackService()
r := NewGitUploadPackService(fixRepo)
c.Assert(r.Connect(fixRepo), Equals, ErrAuthRequired)
}

Expand Down Expand Up @@ -62,25 +62,25 @@ func (s *SuiteRemote) TestConnectWithPublicKeysCallback(c *C) {
c.Assert(err, IsNil)
defer func() { c.Assert(agent.close(), IsNil) }()

r := NewGitUploadPackService()
r := NewGitUploadPackService(fixRepo)
c.Assert(r.ConnectWithAuth(fixRepo, agent.auth), IsNil)
defer func() { c.Assert(r.Disconnect(), IsNil) }()
c.Assert(r.connected, Equals, true)
c.Assert(r.auth, Equals, agent.auth)
}

func (s *SuiteRemote) TestConnectBadVcs(c *C) {
r := NewGitUploadPackService()
r := NewGitUploadPackService(fixRepoBadVcs)
c.Assert(r.ConnectWithAuth(fixRepoBadVcs, nil), ErrorMatches, fmt.Sprintf(".*%s.*", fixRepoBadVcs))
}

func (s *SuiteRemote) TestConnectNonGit(c *C) {
r := NewGitUploadPackService()
r := NewGitUploadPackService(fixRepoNonGit)
c.Assert(r.ConnectWithAuth(fixRepoNonGit, nil), Equals, ErrUnsupportedVCS)
}

func (s *SuiteRemote) TestConnectNonGithub(c *C) {
r := NewGitUploadPackService()
r := NewGitUploadPackService(fixGitRepoNonGithub)
c.Assert(r.ConnectWithAuth(fixGitRepoNonGithub, nil), Equals, ErrUnsupportedRepo)
}

Expand All @@ -92,7 +92,7 @@ func (*mockAuth) Name() string { return "" }
func (*mockAuth) String() string { return "" }

func (s *SuiteRemote) TestConnectWithAuthWrongType(c *C) {
r := NewGitUploadPackService()
r := NewGitUploadPackService(fixRepo)
c.Assert(r.ConnectWithAuth(fixRepo, &mockAuth{}), Equals, ErrInvalidAuthMethod)
c.Assert(r.connected, Equals, false)
}
Expand All @@ -102,7 +102,7 @@ func (s *SuiteRemote) TestAlreadyConnected(c *C) {
c.Assert(err, IsNil)
defer func() { c.Assert(agent.close(), IsNil) }()

r := NewGitUploadPackService()
r := NewGitUploadPackService(fixRepo)
c.Assert(r.ConnectWithAuth(fixRepo, agent.auth), IsNil)
defer func() { c.Assert(r.Disconnect(), IsNil) }()
c.Assert(r.ConnectWithAuth(fixRepo, agent.auth), Equals, ErrAlreadyConnected)
Expand All @@ -114,14 +114,14 @@ func (s *SuiteRemote) TestDisconnect(c *C) {
c.Assert(err, IsNil)
defer func() { c.Assert(agent.close(), IsNil) }()

r := NewGitUploadPackService()
r := NewGitUploadPackService(fixRepo)
c.Assert(r.ConnectWithAuth(fixRepo, agent.auth), IsNil)
c.Assert(r.Disconnect(), IsNil)
c.Assert(r.connected, Equals, false)
}

func (s *SuiteRemote) TestDisconnectedWhenNonConnected(c *C) {
r := NewGitUploadPackService()
r := NewGitUploadPackService("Dear Twinkle")
c.Assert(r.Disconnect(), Equals, ErrNotConnected)
}

Expand All @@ -130,7 +130,7 @@ func (s *SuiteRemote) TestAlreadyDisconnected(c *C) {
c.Assert(err, IsNil)
defer func() { c.Assert(agent.close(), IsNil) }()

r := NewGitUploadPackService()
r := NewGitUploadPackService(fixRepo)
c.Assert(r.ConnectWithAuth(fixRepo, agent.auth), IsNil)
c.Assert(r.Disconnect(), IsNil)
c.Assert(r.Disconnect(), Equals, ErrNotConnected)
Expand All @@ -142,7 +142,7 @@ func (s *SuiteRemote) TestServeralConnections(c *C) {
c.Assert(err, IsNil)
defer func() { c.Assert(agent.close(), IsNil) }()

r := NewGitUploadPackService()
r := NewGitUploadPackService(fixRepo)
c.Assert(r.ConnectWithAuth(fixRepo, agent.auth), IsNil)
c.Assert(r.Disconnect(), IsNil)

Expand All @@ -158,7 +158,7 @@ func (s *SuiteRemote) TestServeralConnections(c *C) {
}

func (s *SuiteRemote) TestInfoNotConnected(c *C) {
r := NewGitUploadPackService()
r := NewGitUploadPackService(fixRepo)
_, err := r.Info()
c.Assert(err, Equals, ErrNotConnected)
}
Expand All @@ -168,7 +168,7 @@ func (s *SuiteRemote) TestDefaultBranch(c *C) {
c.Assert(err, IsNil)
defer func() { c.Assert(agent.close(), IsNil) }()

r := NewGitUploadPackService()
r := NewGitUploadPackService(fixRepo)
c.Assert(r.ConnectWithAuth(fixRepo, agent.auth), IsNil)
defer func() { c.Assert(r.Disconnect(), IsNil) }()

Expand All @@ -182,7 +182,7 @@ func (s *SuiteRemote) TestCapabilities(c *C) {
c.Assert(err, IsNil)
defer func() { c.Assert(agent.close(), IsNil) }()

r := NewGitUploadPackService()
r := NewGitUploadPackService(fixRepo)
c.Assert(r.ConnectWithAuth(fixRepo, agent.auth), IsNil)
defer func() { c.Assert(r.Disconnect(), IsNil) }()

Expand All @@ -192,7 +192,7 @@ func (s *SuiteRemote) TestCapabilities(c *C) {
}

func (s *SuiteRemote) TestFetchNotConnected(c *C) {
r := NewGitUploadPackService()
r := NewGitUploadPackService("foo bar")
pr := &common.GitUploadPackRequest{}
pr.Want(core.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"))
_, err := r.Fetch(pr)
Expand All @@ -204,7 +204,7 @@ func (s *SuiteRemote) TestFetch(c *C) {
c.Assert(err, IsNil)
defer func() { c.Assert(agent.close(), IsNil) }()

r := NewGitUploadPackService()
r := NewGitUploadPackService(fixRepo)
c.Assert(r.ConnectWithAuth(fixRepo, agent.auth), IsNil)
defer func() { c.Assert(r.Disconnect(), IsNil) }()

Expand Down
6 changes: 5 additions & 1 deletion remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,14 @@ func NewAuthenticatedRemote(url string, auth common.AuthMethod) (*Remote, error)
return nil, err
}

upSrv, err := clients.NewGitUploadPackService(url)
if err != nil {
return nil, err
}
return &Remote{
Endpoint: end,
Auth: auth,
upSrv: clients.NewGitUploadPackService(),
upSrv: upSrv,
}, nil
}

Expand Down

0 comments on commit da5ab9d

Please sign in to comment.