From bf98b6096fd1e813ebadbb1f71d4b2d4e48bdb4b Mon Sep 17 00:00:00 2001 From: Alberto Cortés Date: Wed, 16 Dec 2015 19:41:29 +0100 Subject: Add client selection based on repo URL scheme --- clients/common.go | 25 +++++++++++++++++++++++-- clients/common_test.go | 38 ++++++++++++++++++++++++++++++++++++++ clients/file/git_upload_pack.go | 29 +++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 clients/common_test.go create mode 100644 clients/file/git_upload_pack.go (limited to 'clients') diff --git a/clients/common.go b/clients/common.go index fcbacf5..b2e906d 100644 --- a/clients/common.go +++ b/clients/common.go @@ -1,10 +1,31 @@ package clients import ( + "fmt" + "net/url" + "gopkg.in/src-d/go-git.v2/clients/common" + "gopkg.in/src-d/go-git.v2/clients/file" "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() +// NewGitUploadPackService returns the appropiate upload pack service +// among of the set of supported protocols: HTTP, SSH or file. +// TODO: should this get a scheme as an argument instead of an URL? +func NewGitUploadPackService(repoURL string) (common.GitUploadPackService, error) { + u, err := url.Parse(repoURL) + if err != nil { + return nil, fmt.Errorf("invalid url %q", repoURL) + } + switch u.Scheme { + case "http", "https": + return http.NewGitUploadPackService(), nil + case "ssh": + return ssh.NewGitUploadPackService(), nil + case "file": + return file.NewGitUploadPackService(), nil + default: + return nil, fmt.Errorf("unsupported scheme %q", u.Scheme) + } } diff --git a/clients/common_test.go b/clients/common_test.go new file mode 100644 index 0000000..f8bcbd3 --- /dev/null +++ b/clients/common_test.go @@ -0,0 +1,38 @@ +package clients + +import ( + "fmt" + "testing" + + . "gopkg.in/check.v1" +) + +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 + }{ + {"ht/ml://example.com", true, ""}, + {"", true, ""}, + {"-", true, ""}, + {"!@", true, ""}, + {"badscheme://github.com/src-d/go-git", true, ""}, + {"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"}, + {"file://github.com/src-d/go-git", false, "*file.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(fmt.Sprintf("%T", output), Equals, t.expected, Commentf("%d) %q: wrong type", i, t.input)) + } +} diff --git a/clients/file/git_upload_pack.go b/clients/file/git_upload_pack.go new file mode 100644 index 0000000..34ee958 --- /dev/null +++ b/clients/file/git_upload_pack.go @@ -0,0 +1,29 @@ +package file + +import ( + "io" + + "gopkg.in/src-d/go-git.v2/clients/common" +) + +type GitUploadPackService struct{} + +func NewGitUploadPackService() *GitUploadPackService { + return &GitUploadPackService{} +} + +func (s *GitUploadPackService) Connect(url common.Endpoint) error { + return nil +} + +func (s *GitUploadPackService) ConnectWithAuth(url common.Endpoint, auth common.AuthMethod) error { + return nil +} + +func (s *GitUploadPackService) Info() (*common.GitUploadPackInfo, error) { + return nil, nil +} + +func (s *GitUploadPackService) Fetch(r *common.GitUploadPackRequest) (io.ReadCloser, error) { + return nil, nil +} -- cgit From c8c4a69045f75e0a6dce601387bc2ff49f7c1e84 Mon Sep 17 00:00:00 2001 From: Alberto Cortés Date: Thu, 17 Dec 2015 18:01:38 +0100 Subject: Add install protocols capabilities to GitUploadPackService --- clients/common.go | 60 +++++++++++++++++++++++++++------- clients/common_test.go | 62 ++++++++++++++++++++++++++++++++---- clients/file/git_upload_pack.go | 29 ----------------- clients/http/git_upload_pack.go | 3 +- clients/http/git_upload_pack_test.go | 12 +++---- clients/ssh/git_upload_pack.go | 3 +- clients/ssh/git_upload_pack_test.go | 32 +++++++++---------- 7 files changed, 131 insertions(+), 70 deletions(-) delete mode 100644 clients/file/git_upload_pack.go (limited to 'clients') diff --git a/clients/common.go b/clients/common.go index b2e906d..ce36dd1 100644 --- a/clients/common.go +++ b/clients/common.go @@ -1,3 +1,14 @@ +// 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 ( @@ -5,27 +16,54 @@ import ( "net/url" "gopkg.in/src-d/go-git.v2/clients/common" - "gopkg.in/src-d/go-git.v2/clients/file" "gopkg.in/src-d/go-git.v2/clients/http" "gopkg.in/src-d/go-git.v2/clients/ssh" ) +// 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 supported protocols: HTTP, SSH or file. -// TODO: should this get a scheme as an argument instead of an URL? +// 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) } - switch u.Scheme { - case "http", "https": - return http.NewGitUploadPackService(), nil - case "ssh": - return ssh.NewGitUploadPackService(), nil - case "file": - return file.NewGitUploadPackService(), nil - default: + 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 } diff --git a/clients/common_test.go b/clients/common_test.go index f8bcbd3..ff9ca32 100644 --- a/clients/common_test.go +++ b/clients/common_test.go @@ -2,9 +2,11 @@ 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) } @@ -19,20 +21,68 @@ func (s *SuiteCommon) TestNewGitUploadPackService(c *C) { err bool expected string }{ - {"ht/ml://example.com", true, ""}, - {"", true, ""}, - {"-", true, ""}, - {"!@", true, ""}, + {"://example.com", true, ""}, {"badscheme://github.com/src-d/go-git", true, ""}, {"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"}, - {"file://github.com/src-d/go-git", false, "*file.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(fmt.Sprintf("%T", output), Equals, t.expected, Commentf("%d) %q: wrong type", 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) +} diff --git a/clients/file/git_upload_pack.go b/clients/file/git_upload_pack.go deleted file mode 100644 index 34ee958..0000000 --- a/clients/file/git_upload_pack.go +++ /dev/null @@ -1,29 +0,0 @@ -package file - -import ( - "io" - - "gopkg.in/src-d/go-git.v2/clients/common" -) - -type GitUploadPackService struct{} - -func NewGitUploadPackService() *GitUploadPackService { - return &GitUploadPackService{} -} - -func (s *GitUploadPackService) Connect(url common.Endpoint) error { - return nil -} - -func (s *GitUploadPackService) ConnectWithAuth(url common.Endpoint, auth common.AuthMethod) error { - return nil -} - -func (s *GitUploadPackService) Info() (*common.GitUploadPackInfo, error) { - return nil, nil -} - -func (s *GitUploadPackService) Fetch(r *common.GitUploadPackRequest) (io.ReadCloser, error) { - return nil, nil -} diff --git a/clients/http/git_upload_pack.go b/clients/http/git_upload_pack.go index 2d38d42..4b06c72 100644 --- a/clients/http/git_upload_pack.go +++ b/clients/http/git_upload_pack.go @@ -18,7 +18,8 @@ type GitUploadPackService struct { auth HTTPAuthMethod } -func NewGitUploadPackService() *GitUploadPackService { +func NewGitUploadPackService(url string) *GitUploadPackService { + // url ignored return &GitUploadPackService{ Client: http.DefaultClient, } diff --git a/clients/http/git_upload_pack_test.go b/clients/http/git_upload_pack_test.go index f9ec424..b479155 100644 --- a/clients/http/git_upload_pack_test.go +++ b/clients/http/git_upload_pack_test.go @@ -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) } @@ -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() @@ -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() @@ -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{} diff --git a/clients/ssh/git_upload_pack.go b/clients/ssh/git_upload_pack.go index 09cb5ab..4a4021d 100644 --- a/clients/ssh/git_upload_pack.go +++ b/clients/ssh/git_upload_pack.go @@ -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{} } diff --git a/clients/ssh/git_upload_pack_test.go b/clients/ssh/git_upload_pack_test.go index 66ac306..8626b50 100644 --- a/clients/ssh/git_upload_pack_test.go +++ b/clients/ssh/git_upload_pack_test.go @@ -25,7 +25,7 @@ const ( ) func (s *SuiteRemote) TestConnect(c *C) { - r := NewGitUploadPackService() + r := NewGitUploadPackService(fixRepo) c.Assert(r.Connect(fixRepo), Equals, ErrAuthRequired) } @@ -62,7 +62,7 @@ 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) @@ -70,17 +70,17 @@ func (s *SuiteRemote) TestConnectWithPublicKeysCallback(c *C) { } 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) } @@ -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) } @@ -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) @@ -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) } @@ -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) @@ -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) @@ -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) } @@ -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) }() @@ -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) }() @@ -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) @@ -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) }() -- cgit