aboutsummaryrefslogtreecommitdiffstats
path: root/plumbing/client
diff options
context:
space:
mode:
Diffstat (limited to 'plumbing/client')
-rw-r--r--plumbing/client/common.go46
-rw-r--r--plumbing/client/common/common.go222
-rw-r--r--plumbing/client/common/common_test.go126
-rw-r--r--plumbing/client/common_test.go85
-rw-r--r--plumbing/client/http/common.go76
-rw-r--r--plumbing/client/http/common_test.go51
-rw-r--r--plumbing/client/http/git_upload_pack.go202
-rw-r--r--plumbing/client/http/git_upload_pack_test.go149
-rw-r--r--plumbing/client/ssh/auth_method.go159
-rw-r--r--plumbing/client/ssh/auth_method_test.go94
-rw-r--r--plumbing/client/ssh/git_upload_pack.go311
-rw-r--r--plumbing/client/ssh/git_upload_pack_test.go144
12 files changed, 0 insertions, 1665 deletions
diff --git a/plumbing/client/common.go b/plumbing/client/common.go
deleted file mode 100644
index 1524753..0000000
--- a/plumbing/client/common.go
+++ /dev/null
@@ -1,46 +0,0 @@
-// Package clients includes the implementation for different transport protocols
-//
-// 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 `Protocols`) 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"
-
- "gopkg.in/src-d/go-git.v4/plumbing/client/common"
- "gopkg.in/src-d/go-git.v4/plumbing/client/http"
- "gopkg.in/src-d/go-git.v4/plumbing/client/ssh"
-)
-
-// Protocols are the protocols supported by default.
-var Protocols = map[string]common.GitUploadPackServiceFactory{
- "http": http.NewGitUploadPackService,
- "https": http.NewGitUploadPackService,
- "ssh": ssh.NewGitUploadPackService,
-}
-
-// InstallProtocol adds or modifies an existing protocol.
-func InstallProtocol(scheme string, f common.GitUploadPackServiceFactory) {
- Protocols[scheme] = f
-}
-
-// NewGitUploadPackService returns the appropriate upload pack service
-// among of the set of known protocols: HTTP, SSH. See `InstallProtocol`
-// to add or modify protocols.
-func NewGitUploadPackService(endpoint common.Endpoint) (common.GitUploadPackService, error) {
- f, ok := Protocols[endpoint.Scheme]
- if !ok {
- return nil, fmt.Errorf("unsupported scheme %q", endpoint.Scheme)
- }
-
- return f(endpoint), nil
-}
diff --git a/plumbing/client/common/common.go b/plumbing/client/common/common.go
deleted file mode 100644
index b2d52e8..0000000
--- a/plumbing/client/common/common.go
+++ /dev/null
@@ -1,222 +0,0 @@
-// Package common contains interfaces and non-specific protocol entities
-package common
-
-import (
- "bytes"
- "errors"
- "fmt"
- "io"
- "io/ioutil"
- "net/url"
- "regexp"
- "strings"
-
- "gopkg.in/src-d/go-git.v4/plumbing"
- "gopkg.in/src-d/go-git.v4/plumbing/format/packp"
- "gopkg.in/src-d/go-git.v4/plumbing/format/packp/advrefs"
- "gopkg.in/src-d/go-git.v4/plumbing/format/packp/pktline"
- "gopkg.in/src-d/go-git.v4/plumbing/storer"
- "gopkg.in/src-d/go-git.v4/storage/memory"
-)
-
-var (
- ErrRepositoryNotFound = errors.New("repository not found")
- ErrAuthorizationRequired = errors.New("authorization required")
- ErrEmptyGitUploadPack = errors.New("empty git-upload-pack given")
- ErrInvalidAuthMethod = errors.New("invalid auth method")
-)
-
-const GitUploadPackServiceName = "git-upload-pack"
-
-type GitUploadPackService interface {
- Connect() error
- SetAuth(AuthMethod) error
- Info() (*GitUploadPackInfo, error)
- Fetch(*GitUploadPackRequest) (io.ReadCloser, error)
- Disconnect() error
-}
-
-// GitUploadPackServiceFactory is capable of instantiating GitUploadPackService with given endpoint
-type GitUploadPackServiceFactory func(Endpoint) GitUploadPackService
-
-type AuthMethod interface {
- Name() string
- String() string
-}
-
-type Endpoint url.URL
-
-var (
- isSchemeRegExp = regexp.MustCompile("^[^:]+://")
- scpLikeUrlRegExp = regexp.MustCompile("^(?P<user>[^@]+@)?(?P<host>[^:]+):/?(?P<path>.+)$")
-)
-
-func NewEndpoint(endpoint string) (Endpoint, error) {
- endpoint = transformSCPLikeIfNeeded(endpoint)
-
- u, err := url.Parse(endpoint)
- if err != nil {
- return Endpoint{}, plumbing.NewPermanentError(err)
- }
-
- if !u.IsAbs() {
- return Endpoint{}, plumbing.NewPermanentError(fmt.Errorf(
- "invalid endpoint: %s", endpoint,
- ))
- }
-
- return Endpoint(*u), nil
-}
-
-func transformSCPLikeIfNeeded(endpoint string) string {
- if !isSchemeRegExp.MatchString(endpoint) && scpLikeUrlRegExp.MatchString(endpoint) {
- m := scpLikeUrlRegExp.FindStringSubmatch(endpoint)
- return fmt.Sprintf("ssh://%s%s/%s", m[1], m[2], m[3])
- }
-
- return endpoint
-}
-
-func (e *Endpoint) String() string {
- u := url.URL(*e)
- return u.String()
-}
-
-type GitUploadPackInfo struct {
- Capabilities *packp.Capabilities
- Refs memory.ReferenceStorage
-}
-
-func NewGitUploadPackInfo() *GitUploadPackInfo {
- return &GitUploadPackInfo{
- Capabilities: packp.NewCapabilities(),
- Refs: make(memory.ReferenceStorage, 0),
- }
-}
-
-func (i *GitUploadPackInfo) Decode(r io.Reader) error {
- d := advrefs.NewDecoder(r)
- ar := advrefs.New()
- if err := d.Decode(ar); err != nil {
- if err == advrefs.ErrEmpty {
- return plumbing.NewPermanentError(err)
- }
- return plumbing.NewUnexpectedError(err)
- }
-
- i.Capabilities = ar.Capabilities
-
- if err := i.addRefs(ar); err != nil {
- return plumbing.NewUnexpectedError(err)
- }
-
- return nil
-}
-
-func (i *GitUploadPackInfo) addRefs(ar *advrefs.AdvRefs) error {
- for name, hash := range ar.References {
- ref := plumbing.NewReferenceFromStrings(name, hash.String())
- i.Refs.SetReference(ref)
- }
-
- return i.addSymbolicRefs(ar)
-}
-
-func (i *GitUploadPackInfo) addSymbolicRefs(ar *advrefs.AdvRefs) error {
- if !hasSymrefs(ar) {
- return nil
- }
-
- for _, symref := range ar.Capabilities.Get("symref").Values {
- chunks := strings.Split(symref, ":")
- if len(chunks) != 2 {
- err := fmt.Errorf("bad number of `:` in symref value (%q)", symref)
- return plumbing.NewUnexpectedError(err)
- }
- name := plumbing.ReferenceName(chunks[0])
- target := plumbing.ReferenceName(chunks[1])
- ref := plumbing.NewSymbolicReference(name, target)
- i.Refs.SetReference(ref)
- }
-
- return nil
-}
-
-func hasSymrefs(ar *advrefs.AdvRefs) bool {
- return ar.Capabilities.Supports("symref")
-}
-
-func (i *GitUploadPackInfo) Head() *plumbing.Reference {
- ref, _ := storer.ResolveReference(i.Refs, plumbing.HEAD)
- return ref
-}
-
-func (i *GitUploadPackInfo) String() string {
- return string(i.Bytes())
-}
-
-func (i *GitUploadPackInfo) Bytes() []byte {
- var buf bytes.Buffer
- e := pktline.NewEncoder(&buf)
-
- _ = e.EncodeString("# service=git-upload-pack\n")
-
- // inserting a flush-pkt here violates the protocol spec, but some
- // servers do it, like Github.com
- e.Flush()
-
- _ = e.Encodef("%s HEAD\x00%s\n", i.Head().Hash(), i.Capabilities.String())
-
- for _, ref := range i.Refs {
- if ref.Type() != plumbing.HashReference {
- continue
- }
-
- _ = e.Encodef("%s %s\n", ref.Hash(), ref.Name())
- }
-
- e.Flush()
-
- return buf.Bytes()
-}
-
-type GitUploadPackRequest struct {
- Wants []plumbing.Hash
- Haves []plumbing.Hash
- Depth int
-}
-
-func (r *GitUploadPackRequest) Want(h ...plumbing.Hash) {
- r.Wants = append(r.Wants, h...)
-}
-
-func (r *GitUploadPackRequest) Have(h ...plumbing.Hash) {
- r.Haves = append(r.Haves, h...)
-}
-
-func (r *GitUploadPackRequest) String() string {
- b, _ := ioutil.ReadAll(r.Reader())
- return string(b)
-}
-
-func (r *GitUploadPackRequest) Reader() *strings.Reader {
- var buf bytes.Buffer
- e := pktline.NewEncoder(&buf)
-
- for _, want := range r.Wants {
- _ = e.Encodef("want %s\n", want)
- }
-
- for _, have := range r.Haves {
- _ = e.Encodef("have %s\n", have)
- }
-
- if r.Depth != 0 {
- _ = e.Encodef("deepen %d\n", r.Depth)
- }
-
- _ = e.Flush()
- _ = e.EncodeString("done\n")
-
- return strings.NewReader(buf.String())
-}
diff --git a/plumbing/client/common/common_test.go b/plumbing/client/common/common_test.go
deleted file mode 100644
index cf4d871..0000000
--- a/plumbing/client/common/common_test.go
+++ /dev/null
@@ -1,126 +0,0 @@
-package common
-
-import (
- "bytes"
- "encoding/base64"
- "testing"
-
- "gopkg.in/src-d/go-git.v4/plumbing"
- "gopkg.in/src-d/go-git.v4/plumbing/format/packp"
-
- . "gopkg.in/check.v1"
-)
-
-func Test(t *testing.T) { TestingT(t) }
-
-type SuiteCommon struct{}
-
-var _ = Suite(&SuiteCommon{})
-
-func (s *SuiteCommon) TestNewEndpoint(c *C) {
- e, err := NewEndpoint("ssh://git@github.com/user/repository.git")
- c.Assert(err, IsNil)
- c.Assert(e.String(), Equals, "ssh://git@github.com/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.String(), Equals, "ssh://git@github.com/user/repository.git")
-}
-
-func (s *SuiteCommon) TestNewEndpointWrongForgat(c *C) {
- e, err := NewEndpoint("foo")
- c.Assert(err, Not(IsNil))
- c.Assert(e.Host, Equals, "")
-}
-
-const CapabilitiesFixture = "6ecf0ef2c2dffb796033e5a02219af86ec6584e5 HEADmulti_ack thin-pack side-band side-band-64k ofs-delta shallow no-progress include-tag multi_ack_detailed no-done symref=HEAD:refs/heads/master agent=git/2:2.4.8~dbussink-fix-enterprise-tokens-compilation-1167-gc7006cf"
-
-func (s *SuiteCommon) TestCapabilitiesSymbolicReference(c *C) {
- cap := packp.NewCapabilities()
- cap.Decode(CapabilitiesFixture)
- c.Assert(cap.SymbolicReference("HEAD"), Equals, "refs/heads/master")
-}
-
-const GitUploadPackInfoFixture = "MDAxZSMgc2VydmljZT1naXQtdXBsb2FkLXBhY2sKMDAwMDAxMGM2ZWNmMGVmMmMyZGZmYjc5NjAzM2U1YTAyMjE5YWY4NmVjNjU4NGU1IEhFQUQAbXVsdGlfYWNrIHRoaW4tcGFjayBzaWRlLWJhbmQgc2lkZS1iYW5kLTY0ayBvZnMtZGVsdGEgc2hhbGxvdyBuby1wcm9ncmVzcyBpbmNsdWRlLXRhZyBtdWx0aV9hY2tfZGV0YWlsZWQgbm8tZG9uZSBzeW1yZWY9SEVBRDpyZWZzL2hlYWRzL21hc3RlciBhZ2VudD1naXQvMjoyLjQuOH5kYnVzc2luay1maXgtZW50ZXJwcmlzZS10b2tlbnMtY29tcGlsYXRpb24tMTE2Ny1nYzcwMDZjZgowMDNmZThkM2ZmYWI1NTI4OTVjMTliOWZjZjdhYTI2NGQyNzdjZGUzMzg4MSByZWZzL2hlYWRzL2JyYW5jaAowMDNmNmVjZjBlZjJjMmRmZmI3OTYwMzNlNWEwMjIxOWFmODZlYzY1ODRlNSByZWZzL2hlYWRzL21hc3RlcgowMDNlYjhlNDcxZjU4YmNiY2E2M2IwN2JkYTIwZTQyODE5MDQwOWMyZGI0NyByZWZzL3B1bGwvMS9oZWFkCjAwMDA="
-
-func (s *SuiteCommon) TestGitUploadPackInfo(c *C) {
- b, _ := base64.StdEncoding.DecodeString(GitUploadPackInfoFixture)
-
- i := NewGitUploadPackInfo()
- err := i.Decode(bytes.NewBuffer(b))
- c.Assert(err, IsNil)
-
- name := i.Capabilities.SymbolicReference("HEAD")
- c.Assert(name, Equals, "refs/heads/master")
- c.Assert(i.Refs, HasLen, 4)
-
- ref := i.Refs[plumbing.ReferenceName(name)]
- c.Assert(ref, NotNil)
- c.Assert(ref.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5")
-
- ref = i.Refs[plumbing.HEAD]
- c.Assert(ref, NotNil)
- c.Assert(ref.Target(), Equals, plumbing.ReferenceName(name))
-}
-
-const GitUploadPackInfoNoHEADFixture = "MDAxZSMgc2VydmljZT1naXQtdXBsb2FkLXBhY2sKMDAwMDAwYmNkN2UxZmVlMjYxMjM0YmIzYTQzYzA5NmY1NTg3NDhhNTY5ZDc5ZWZmIHJlZnMvaGVhZHMvdjQAbXVsdGlfYWNrIHRoaW4tcGFjayBzaWRlLWJhbmQgc2lkZS1iYW5kLTY0ayBvZnMtZGVsdGEgc2hhbGxvdyBuby1wcm9ncmVzcyBpbmNsdWRlLXRhZyBtdWx0aV9hY2tfZGV0YWlsZWQgbm8tZG9uZSBhZ2VudD1naXQvMS45LjEKMDAwMA=="
-
-func (s *SuiteCommon) TestGitUploadPackInfoNoHEAD(c *C) {
- b, _ := base64.StdEncoding.DecodeString(GitUploadPackInfoNoHEADFixture)
-
- i := NewGitUploadPackInfo()
- err := i.Decode(bytes.NewBuffer(b))
- c.Assert(err, IsNil)
-
- name := i.Capabilities.SymbolicReference("HEAD")
- c.Assert(name, Equals, "")
- c.Assert(i.Refs, HasLen, 1)
-
- ref := i.Refs["refs/heads/v4"]
- c.Assert(ref, NotNil)
- c.Assert(ref.Hash().String(), Equals, "d7e1fee261234bb3a43c096f558748a569d79eff")
-}
-
-func (s *SuiteCommon) TestGitUploadPackInfoEmpty(c *C) {
- b := bytes.NewBuffer(nil)
-
- i := NewGitUploadPackInfo()
- err := i.Decode(b)
- c.Assert(err, ErrorMatches, "permanent.*empty.*")
-}
-
-func (s *SuiteCommon) TestGitUploadPackEncode(c *C) {
- info := NewGitUploadPackInfo()
- info.Capabilities.Add("symref", "HEAD:refs/heads/master")
-
- ref := plumbing.ReferenceName("refs/heads/master")
- hash := plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5")
- info.Refs = map[plumbing.ReferenceName]*plumbing.Reference{
- plumbing.HEAD: plumbing.NewSymbolicReference(plumbing.HEAD, ref),
- ref: plumbing.NewHashReference(ref, hash),
- }
-
- c.Assert(info.Head(), NotNil)
- c.Assert(info.String(), Equals,
- "001e# service=git-upload-pack\n"+
- "000000506ecf0ef2c2dffb796033e5a02219af86ec6584e5 HEAD\x00symref=HEAD:refs/heads/master\n"+
- "003f6ecf0ef2c2dffb796033e5a02219af86ec6584e5 refs/heads/master\n"+
- "0000",
- )
-}
-
-func (s *SuiteCommon) TestGitUploadPackRequest(c *C) {
- r := &GitUploadPackRequest{}
- r.Want(plumbing.NewHash("d82f291cde9987322c8a0c81a325e1ba6159684c"))
- r.Want(plumbing.NewHash("2b41ef280fdb67a9b250678686a0c3e03b0a9989"))
- r.Have(plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"))
-
- c.Assert(r.String(), Equals,
- "0032want d82f291cde9987322c8a0c81a325e1ba6159684c\n"+
- "0032want 2b41ef280fdb67a9b250678686a0c3e03b0a9989\n"+
- "0032have 6ecf0ef2c2dffb796033e5a02219af86ec6584e5\n0000"+
- "0009done\n",
- )
-}
diff --git a/plumbing/client/common_test.go b/plumbing/client/common_test.go
deleted file mode 100644
index 058c4d3..0000000
--- a/plumbing/client/common_test.go
+++ /dev/null
@@ -1,85 +0,0 @@
-package clients
-
-import (
- "fmt"
- "io"
- "testing"
-
- "gopkg.in/src-d/go-git.v4/plumbing/client/common"
-
- . "gopkg.in/check.v1"
-)
-
-func Test(t *testing.T) { TestingT(t) }
-
-type SuiteCommon struct{}
-
-var _ = Suite(&SuiteCommon{})
-
-func (s *SuiteCommon) TestNewGitUploadPackServiceHTTP(c *C) {
- e, err := common.NewEndpoint("http://github.com/src-d/go-git")
- c.Assert(err, IsNil)
-
- output, err := NewGitUploadPackService(e)
- c.Assert(err, IsNil)
- c.Assert(typeAsString(output), Equals, "*http.GitUploadPackService")
-
- e, err = common.NewEndpoint("https://github.com/src-d/go-git")
- c.Assert(err, IsNil)
-
- output, err = NewGitUploadPackService(e)
- c.Assert(err, IsNil)
- c.Assert(typeAsString(output), Equals, "*http.GitUploadPackService")
-}
-
-func (s *SuiteCommon) TestNewGitUploadPackServiceSSH(c *C) {
- e, err := common.NewEndpoint("ssh://github.com/src-d/go-git")
- c.Assert(err, IsNil)
-
- output, err := NewGitUploadPackService(e)
- c.Assert(err, IsNil)
- c.Assert(typeAsString(output), Equals, "*ssh.GitUploadPackService")
-}
-
-func (s *SuiteCommon) TestNewGitUploadPackServiceUnknown(c *C) {
- e, err := common.NewEndpoint("unknown://github.com/src-d/go-git")
- c.Assert(err, IsNil)
-
- _, err = NewGitUploadPackService(e)
- c.Assert(err, NotNil)
-}
-
-func (s *SuiteCommon) TestInstallProtocol(c *C) {
- InstallProtocol("newscheme", newDummyProtocolService)
- c.Assert(Protocols["newscheme"], NotNil)
-}
-
-type dummyProtocolService struct{}
-
-func newDummyProtocolService(common.Endpoint) common.GitUploadPackService {
- return &dummyProtocolService{}
-}
-
-func (s *dummyProtocolService) Connect() error {
- return nil
-}
-
-func (s *dummyProtocolService) SetAuth(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 *dummyProtocolService) Disconnect() error {
- return nil
-}
-
-func typeAsString(v interface{}) string {
- return fmt.Sprintf("%T", v)
-}
diff --git a/plumbing/client/http/common.go b/plumbing/client/http/common.go
deleted file mode 100644
index 2447995..0000000
--- a/plumbing/client/http/common.go
+++ /dev/null
@@ -1,76 +0,0 @@
-// Package http implements a HTTP client for go-git.
-package http
-
-import (
- "fmt"
- "net/http"
-
- "gopkg.in/src-d/go-git.v4/plumbing"
- "gopkg.in/src-d/go-git.v4/plumbing/client/common"
-)
-
-// AuthMethod is concrete implementation of common.AuthMethod for HTTP services
-type AuthMethod interface {
- common.AuthMethod
- setAuth(r *http.Request)
-}
-
-// 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}
-}
-
-func (a *BasicAuth) setAuth(r *http.Request) {
- r.SetBasicAuth(a.username, a.password)
-}
-
-// Name is name of the auth
-func (a *BasicAuth) Name() string {
- return "http-basic-auth"
-}
-
-func (a *BasicAuth) String() string {
- masked := "*******"
- if a.password == "" {
- masked = "<empty>"
- }
-
- return fmt.Sprintf("%s - %s:%s", a.Name(), a.username, masked)
-}
-
-// Err is a dedicated error to return errors based on status code
-type Err struct {
- Response *http.Response
-}
-
-// NewErr returns a new Err based on a http response
-func NewErr(r *http.Response) error {
- if r.StatusCode >= http.StatusOK && r.StatusCode < http.StatusMultipleChoices {
- return nil
- }
-
- switch r.StatusCode {
- case http.StatusUnauthorized:
- return common.ErrAuthorizationRequired
- case http.StatusNotFound:
- return common.ErrRepositoryNotFound
- }
-
- return plumbing.NewUnexpectedError(&Err{r})
-}
-
-// StatusCode returns the status code of the response
-func (e *Err) StatusCode() int {
- return e.Response.StatusCode
-}
-
-func (e *Err) Error() string {
- return fmt.Sprintf("unexpected requesting %q status code: %d",
- e.Response.Request.URL, e.Response.StatusCode,
- )
-}
diff --git a/plumbing/client/http/common_test.go b/plumbing/client/http/common_test.go
deleted file mode 100644
index 7503d84..0000000
--- a/plumbing/client/http/common_test.go
+++ /dev/null
@@ -1,51 +0,0 @@
-package http
-
-import (
- "net/http"
- "testing"
-
- . "gopkg.in/check.v1"
-)
-
-func Test(t *testing.T) { TestingT(t) }
-
-type SuiteCommon struct{}
-
-var _ = Suite(&SuiteCommon{})
-
-func (s *SuiteCommon) TestNewBasicAuth(c *C) {
- a := NewBasicAuth("foo", "qux")
-
- c.Assert(a.Name(), Equals, "http-basic-auth")
- c.Assert(a.String(), Equals, "http-basic-auth - foo:*******")
-}
-
-func (s *SuiteCommon) TestNewErrOK(c *C) {
- res := &http.Response{StatusCode: http.StatusOK}
- err := NewErr(res)
- c.Assert(err, IsNil)
-}
-
-func (s *SuiteCommon) TestNewErrUnauthorized(c *C) {
- s.testNewHTTPError(c, http.StatusUnauthorized, "authorization required")
-}
-
-func (s *SuiteCommon) TestNewErrNotFound(c *C) {
- s.testNewHTTPError(c, http.StatusNotFound, "repository not found")
-}
-
-func (s *SuiteCommon) TestNewHTTPError40x(c *C) {
- s.testNewHTTPError(c, http.StatusPaymentRequired, "unexpected client error.*")
-}
-
-func (s *SuiteCommon) testNewHTTPError(c *C, code int, msg string) {
- req, _ := http.NewRequest("GET", "foo", nil)
- res := &http.Response{
- StatusCode: code,
- Request: req,
- }
-
- err := NewErr(res)
- c.Assert(err, NotNil)
- c.Assert(err, ErrorMatches, msg)
-}
diff --git a/plumbing/client/http/git_upload_pack.go b/plumbing/client/http/git_upload_pack.go
deleted file mode 100644
index 1ecf299..0000000
--- a/plumbing/client/http/git_upload_pack.go
+++ /dev/null
@@ -1,202 +0,0 @@
-package http
-
-import (
- "bufio"
- "bytes"
- "fmt"
- "io"
- "net/http"
- "strings"
-
- "gopkg.in/src-d/go-git.v4/plumbing"
- "gopkg.in/src-d/go-git.v4/plumbing/client/common"
- "gopkg.in/src-d/go-git.v4/plumbing/format/packp/pktline"
-)
-
-// GitUploadPackService git-upload-pack service over HTTP
-type GitUploadPackService struct {
- client *http.Client
- endpoint common.Endpoint
- auth AuthMethod
-}
-
-// NewGitUploadPackService connects to a git-upload-pack service over HTTP, the
-// auth is extracted from the URL, or can be provided using the SetAuth method
-func NewGitUploadPackService(endpoint common.Endpoint) common.GitUploadPackService {
- return newGitUploadPackService(endpoint, http.DefaultClient)
-}
-
-// NewGitUploadPackServiceFactory creates a http client factory with a customizable client
-// See `InstallProtocol` to install and override default http client.
-// Unless a properly initialized client is given, it will fall back into `http.DefaultClient`.
-func NewGitUploadPackServiceFactory(client *http.Client) common.GitUploadPackServiceFactory {
- return func(endpoint common.Endpoint) common.GitUploadPackService {
- return newGitUploadPackService(endpoint, client)
- }
-}
-
-func newGitUploadPackService(endpoint common.Endpoint, client *http.Client) common.GitUploadPackService {
- if client == nil {
- client = http.DefaultClient
- }
- s := &GitUploadPackService{
- client: client,
- endpoint: endpoint,
- }
- s.setBasicAuthFromEndpoint()
- return s
-}
-
-// Connect has not any effect, is here to satisfy interface
-func (s *GitUploadPackService) Connect() error {
- return nil
-}
-
-func (s *GitUploadPackService) setBasicAuthFromEndpoint() {
- info := s.endpoint.User
- if info == nil {
- return
- }
-
- p, ok := info.Password()
- if !ok {
- return
- }
-
- u := info.Username()
- s.auth = NewBasicAuth(u, p)
-}
-
-// SetAuth sets the AuthMethod
-func (s *GitUploadPackService) SetAuth(auth common.AuthMethod) error {
- httpAuth, ok := auth.(AuthMethod)
- if !ok {
- return common.ErrInvalidAuthMethod
- }
-
- s.auth = httpAuth
- return nil
-}
-
-// Info returns the references info and capabilities from the service
-func (s *GitUploadPackService) Info() (*common.GitUploadPackInfo, error) {
- url := fmt.Sprintf(
- "%s/info/refs?service=%s",
- s.endpoint.String(), common.GitUploadPackServiceName,
- )
-
- res, err := s.doRequest("GET", url, nil)
- if err != nil {
- return nil, err
- }
-
- defer res.Body.Close()
-
- i := common.NewGitUploadPackInfo()
- return i, i.Decode(res.Body)
-}
-
-// Fetch request and returns a reader to a packfile
-func (s *GitUploadPackService) Fetch(r *common.GitUploadPackRequest) (io.ReadCloser, error) {
- url := fmt.Sprintf(
- "%s/%s",
- s.endpoint.String(), common.GitUploadPackServiceName,
- )
-
- res, err := s.doRequest("POST", url, r.Reader())
- if err != nil {
- return nil, err
- }
-
- reader := newBufferedReadCloser(res.Body)
- if _, err := reader.Peek(1); err != nil {
- if err == io.ErrUnexpectedEOF {
- return nil, common.ErrEmptyGitUploadPack
- }
-
- return nil, err
- }
-
- if err := discardResponseInfo(reader); err != nil {
- return nil, err
- }
-
- return reader, nil
-}
-
-func discardResponseInfo(r io.Reader) error {
- s := pktline.NewScanner(r)
- for s.Scan() {
- if bytes.Equal(s.Bytes(), []byte{'N', 'A', 'K', '\n'}) {
- break
- }
- }
-
- return s.Err()
-}
-
-func (s *GitUploadPackService) doRequest(method, url string, content *strings.Reader) (*http.Response, error) {
- var body io.Reader
- if content != nil {
- body = content
- }
-
- req, err := http.NewRequest(method, url, body)
- if err != nil {
- return nil, plumbing.NewPermanentError(err)
- }
-
- s.applyHeadersToRequest(req, content)
- s.applyAuthToRequest(req)
-
- res, err := s.client.Do(req)
- if err != nil {
- return nil, plumbing.NewUnexpectedError(err)
- }
-
- if err := NewErr(res); err != nil {
- _ = res.Body.Close()
- return nil, err
- }
-
- return res, nil
-}
-
-func (s *GitUploadPackService) applyHeadersToRequest(req *http.Request, content *strings.Reader) {
- req.Header.Add("User-Agent", "git/1.0")
- req.Header.Add("Host", "github.com")
-
- if content == nil {
- req.Header.Add("Accept", "*/*")
- } else {
- req.Header.Add("Accept", "application/x-git-upload-pack-result")
- req.Header.Add("Content-Type", "application/x-git-upload-pack-request")
- req.Header.Add("Content-Length", string(content.Len()))
- }
-}
-
-func (s *GitUploadPackService) applyAuthToRequest(req *http.Request) {
- if s.auth == nil {
- return
- }
-
- s.auth.setAuth(req)
-}
-
-// Disconnect do nothing
-func (s *GitUploadPackService) Disconnect() error {
- return nil
-}
-
-type bufferedReadCloser struct {
- *bufio.Reader
- closer io.Closer
-}
-
-func newBufferedReadCloser(r io.ReadCloser) *bufferedReadCloser {
- return &bufferedReadCloser{bufio.NewReader(r), r}
-}
-
-func (r *bufferedReadCloser) Close() error {
- return r.closer.Close()
-}
diff --git a/plumbing/client/http/git_upload_pack_test.go b/plumbing/client/http/git_upload_pack_test.go
deleted file mode 100644
index 8010cea..0000000
--- a/plumbing/client/http/git_upload_pack_test.go
+++ /dev/null
@@ -1,149 +0,0 @@
-package http
-
-import (
- "crypto/tls"
- "io/ioutil"
- "net/http"
-
- . "gopkg.in/check.v1"
- "gopkg.in/src-d/go-git.v4/plumbing"
- "gopkg.in/src-d/go-git.v4/plumbing/client/common"
-)
-
-type RemoteSuite struct {
- Endpoint common.Endpoint
-}
-
-var _ = Suite(&RemoteSuite{})
-
-func (s *RemoteSuite) SetUpSuite(c *C) {
- var err error
- s.Endpoint, err = common.NewEndpoint("https://github.com/git-fixtures/basic")
- c.Assert(err, IsNil)
-}
-
-func (s *RemoteSuite) TestNewGitUploadPackServiceAuth(c *C) {
- e, err := common.NewEndpoint("https://foo:bar@github.com/git-fixtures/basic")
- c.Assert(err, IsNil)
-
- r := NewGitUploadPackService(e)
- auth := r.(*GitUploadPackService).auth
-
- c.Assert(auth.String(), Equals, "http-basic-auth - foo:*******")
-}
-
-func (s *RemoteSuite) TestNewGitUploadPackServiceFactory(c *C) {
- e, err := common.NewEndpoint("https://foo:bar@github.com/git-fixtures/basic")
- c.Assert(err, IsNil)
-
- roundTripper := &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
- client := &http.Client{Transport: roundTripper}
- r := NewGitUploadPackServiceFactory(client)(e).(*GitUploadPackService)
-
- c.Assert(r.auth.String(), Equals, "http-basic-auth - foo:*******")
- c.Assert(r.client.Transport, Equals, roundTripper)
-}
-
-func (s *RemoteSuite) TestConnect(c *C) {
- r := NewGitUploadPackService(s.Endpoint)
- c.Assert(r.Connect(), IsNil)
-}
-
-func (s *RemoteSuite) TestSetAuth(c *C) {
- auth := &BasicAuth{}
- r := NewGitUploadPackService(s.Endpoint)
- r.SetAuth(auth)
- c.Assert(auth, Equals, r.(*GitUploadPackService).auth)
-}
-
-type mockAuth struct{}
-
-func (*mockAuth) Name() string { return "" }
-func (*mockAuth) String() string { return "" }
-
-func (s *RemoteSuite) TestSetAuthWrongType(c *C) {
- r := NewGitUploadPackService(s.Endpoint)
- c.Assert(r.SetAuth(&mockAuth{}), Equals, common.ErrInvalidAuthMethod)
-}
-
-func (s *RemoteSuite) TestInfoEmpty(c *C) {
- endpoint, _ := common.NewEndpoint("https://github.com/git-fixture/empty")
- r := NewGitUploadPackService(endpoint)
- c.Assert(r.Connect(), IsNil)
-
- info, err := r.Info()
- c.Assert(err, Equals, common.ErrAuthorizationRequired)
- c.Assert(info, IsNil)
-}
-
-func (s *RemoteSuite) TestInfoNotExists(c *C) {
- endpoint, _ := common.NewEndpoint("https://github.com/git-fixture/not-exists")
- r := NewGitUploadPackService(endpoint)
- c.Assert(r.Connect(), IsNil)
-
- info, err := r.Info()
- c.Assert(err, Equals, common.ErrAuthorizationRequired)
- c.Assert(info, IsNil)
-}
-
-func (s *RemoteSuite) TestDefaultBranch(c *C) {
- r := NewGitUploadPackService(s.Endpoint)
- c.Assert(r.Connect(), IsNil)
-
- info, err := r.Info()
- c.Assert(err, IsNil)
- c.Assert(info.Capabilities.SymbolicReference("HEAD"), Equals, "refs/heads/master")
-}
-
-func (s *RemoteSuite) TestCapabilities(c *C) {
- r := NewGitUploadPackService(s.Endpoint)
- c.Assert(r.Connect(), IsNil)
-
- info, err := r.Info()
- c.Assert(err, IsNil)
- c.Assert(info.Capabilities.Get("agent").Values, HasLen, 1)
-}
-
-func (s *RemoteSuite) TestFetch(c *C) {
- r := NewGitUploadPackService(s.Endpoint)
- c.Assert(r.Connect(), IsNil)
-
- req := &common.GitUploadPackRequest{}
- req.Want(plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"))
-
- reader, err := r.Fetch(req)
- c.Assert(err, IsNil)
-
- b, err := ioutil.ReadAll(reader)
- c.Assert(err, IsNil)
- c.Assert(b, HasLen, 85374)
-}
-
-func (s *RemoteSuite) TestFetchNoChanges(c *C) {
- r := NewGitUploadPackService(s.Endpoint)
- c.Assert(r.Connect(), IsNil)
-
- req := &common.GitUploadPackRequest{}
- req.Want(plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"))
- req.Have(plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"))
-
- reader, err := r.Fetch(req)
- c.Assert(err, Equals, common.ErrEmptyGitUploadPack)
- c.Assert(reader, IsNil)
-}
-
-func (s *RemoteSuite) TestFetchMulti(c *C) {
- r := NewGitUploadPackService(s.Endpoint)
- c.Assert(r.Connect(), IsNil)
-
- req := &common.GitUploadPackRequest{}
- req.Want(plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"))
- req.Want(plumbing.NewHash("e8d3ffab552895c19b9fcf7aa264d277cde33881"))
-
- reader, err := r.Fetch(req)
- c.Assert(err, IsNil)
-
- b, err := ioutil.ReadAll(reader)
- c.Assert(err, IsNil)
- c.Assert(b, HasLen, 85585)
-}
diff --git a/plumbing/client/ssh/auth_method.go b/plumbing/client/ssh/auth_method.go
deleted file mode 100644
index 587f59a..0000000
--- a/plumbing/client/ssh/auth_method.go
+++ /dev/null
@@ -1,159 +0,0 @@
-package ssh
-
-import (
- "fmt"
- "net"
- "os"
-
- "golang.org/x/crypto/ssh"
- "golang.org/x/crypto/ssh/agent"
- "gopkg.in/src-d/go-git.v4/plumbing/client/common"
-)
-
-// AuthMethod is the interface all auth methods for the ssh client
-// must implement. The clientConfig method returns the ssh client
-// configuration needed to establish an ssh connection.
-type AuthMethod interface {
- common.AuthMethod
- clientConfig() *ssh.ClientConfig
-}
-
-// The names of the AuthMethod implementations. To be returned by the
-// Name() method. Most git servers only allow PublicKeysName and
-// PublicKeysCallbackName.
-const (
- KeyboardInteractiveName = "ssh-keyboard-interactive"
- PasswordName = "ssh-password"
- PasswordCallbackName = "ssh-password-callback"
- PublicKeysName = "ssh-public-keys"
- PublicKeysCallbackName = "ssh-public-key-callback"
-)
-
-// KeyboardInteractive implements AuthMethod by using a
-// prompt/response sequence controlled by the server.
-type KeyboardInteractive struct {
- User string
- Challenge ssh.KeyboardInteractiveChallenge
-}
-
-func (a *KeyboardInteractive) Name() string {
- return KeyboardInteractiveName
-}
-
-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{
- User: a.User,
- Auth: []ssh.AuthMethod{ssh.KeyboardInteractiveChallenge(a.Challenge)},
- }
-}
-
-// Password implements AuthMethod by using the given password.
-type Password struct {
- User string
- Pass string
-}
-
-func (a *Password) Name() string {
- return PasswordName
-}
-
-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{
- User: a.User,
- Auth: []ssh.AuthMethod{ssh.Password(a.Pass)},
- }
-}
-
-// PasswordCallback implements AuthMethod by using a callback
-// to fetch the password.
-type PasswordCallback struct {
- User string
- Callback func() (pass string, err error)
-}
-
-func (a *PasswordCallback) Name() string {
- return PasswordCallbackName
-}
-
-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{
- 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
-}
-
-func (a *PublicKeys) Name() string {
- return PublicKeysName
-}
-
-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{
- User: a.User,
- Auth: []ssh.AuthMethod{ssh.PublicKeys(a.Signer)},
- }
-}
-
-// PublicKeysCallback implements AuthMethod by asking a
-// ssh.agent.Agent to act as a signer.
-type PublicKeysCallback struct {
- User string
- Callback func() (signers []ssh.Signer, err error)
-}
-
-func (a *PublicKeysCallback) Name() string {
- return PublicKeysCallbackName
-}
-
-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{
- User: a.User,
- Auth: []ssh.AuthMethod{ssh.PublicKeysCallback(a.Callback)},
- }
-}
-
-const DefaultSSHUsername = "git"
-
-// Opens a pipe with the ssh agent and uses the pipe
-// as the implementer of the public key callback function.
-func NewSSHAgentAuth(user string) (*PublicKeysCallback, error) {
- if user == "" {
- user = DefaultSSHUsername
- }
-
- pipe, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK"))
- if err != nil {
- return nil, err
- }
-
- return &PublicKeysCallback{
- User: user,
- Callback: agent.NewClient(pipe).Signers,
- }, nil
-}
diff --git a/plumbing/client/ssh/auth_method_test.go b/plumbing/client/ssh/auth_method_test.go
deleted file mode 100644
index a87c950..0000000
--- a/plumbing/client/ssh/auth_method_test.go
+++ /dev/null
@@ -1,94 +0,0 @@
-package ssh
-
-import (
- "fmt"
- "testing"
-
- . "gopkg.in/check.v1"
-)
-
-func Test(t *testing.T) { TestingT(t) }
-
-type SuiteCommon struct{}
-
-var _ = Suite(&SuiteCommon{})
-
-func (s *SuiteCommon) TestKeyboardInteractiveName(c *C) {
- a := &KeyboardInteractive{
- User: "test",
- Challenge: nil,
- }
- c.Assert(a.Name(), Equals, KeyboardInteractiveName)
-}
-
-func (s *SuiteCommon) TestKeyboardInteractiveString(c *C) {
- a := &KeyboardInteractive{
- User: "test",
- Challenge: nil,
- }
- c.Assert(a.String(), Equals, fmt.Sprintf("user: test, name: %s", KeyboardInteractiveName))
-}
-
-func (s *SuiteCommon) TestPasswordName(c *C) {
- a := &Password{
- User: "test",
- Pass: "",
- }
- c.Assert(a.Name(), Equals, PasswordName)
-}
-
-func (s *SuiteCommon) TestPasswordString(c *C) {
- a := &Password{
- User: "test",
- Pass: "",
- }
- c.Assert(a.String(), Equals, fmt.Sprintf("user: test, name: %s", PasswordName))
-}
-
-func (s *SuiteCommon) TestPasswordCallbackName(c *C) {
- a := &PasswordCallback{
- User: "test",
- Callback: nil,
- }
- c.Assert(a.Name(), Equals, PasswordCallbackName)
-}
-
-func (s *SuiteCommon) TestPasswordCallbackString(c *C) {
- a := &PasswordCallback{
- User: "test",
- Callback: nil,
- }
- c.Assert(a.String(), Equals, fmt.Sprintf("user: test, name: %s", PasswordCallbackName))
-}
-
-func (s *SuiteCommon) TestPublicKeysName(c *C) {
- a := &PublicKeys{
- User: "test",
- Signer: nil,
- }
- c.Assert(a.Name(), Equals, PublicKeysName)
-}
-
-func (s *SuiteCommon) TestPublicKeysString(c *C) {
- a := &PublicKeys{
- User: "test",
- Signer: nil,
- }
- c.Assert(a.String(), Equals, fmt.Sprintf("user: test, name: %s", PublicKeysName))
-}
-
-func (s *SuiteCommon) TestPublicKeysCallbackName(c *C) {
- a := &PublicKeysCallback{
- User: "test",
- Callback: nil,
- }
- c.Assert(a.Name(), Equals, PublicKeysCallbackName)
-}
-
-func (s *SuiteCommon) TestPublicKeysCallbackString(c *C) {
- a := &PublicKeysCallback{
- User: "test",
- Callback: nil,
- }
- c.Assert(a.String(), Equals, fmt.Sprintf("user: test, name: %s", PublicKeysCallbackName))
-}
diff --git a/plumbing/client/ssh/git_upload_pack.go b/plumbing/client/ssh/git_upload_pack.go
deleted file mode 100644
index db7fa93..0000000
--- a/plumbing/client/ssh/git_upload_pack.go
+++ /dev/null
@@ -1,311 +0,0 @@
-// Package ssh implements a ssh client for go-git.
-package ssh
-
-import (
- "bytes"
- "errors"
- "fmt"
- "io"
- "strings"
-
- "gopkg.in/src-d/go-git.v4/plumbing/client/common"
- "gopkg.in/src-d/go-git.v4/plumbing/format/packp/advrefs"
- "gopkg.in/src-d/go-git.v4/plumbing/format/packp/pktline"
- "gopkg.in/src-d/go-git.v4/plumbing/format/packp/ulreq"
-
- "golang.org/x/crypto/ssh"
-)
-
-// New errors introduced by this package.
-var (
- ErrInvalidAuthMethod = errors.New("invalid ssh auth method")
- ErrAuthRequired = errors.New("cannot connect: auth required")
- ErrNotConnected = errors.New("not connected")
- ErrAlreadyConnected = errors.New("already connected")
- ErrUploadPackAnswerFormat = errors.New("git-upload-pack bad answer format")
- ErrUnsupportedVCS = errors.New("only git is supported")
- ErrUnsupportedRepo = errors.New("only github.com is supported")
-
- nak = []byte("NAK")
- eol = []byte("\n")
-)
-
-// GitUploadPackService holds the service information.
-// The zero value is safe to use.
-type GitUploadPackService struct {
- connected bool
- endpoint common.Endpoint
- client *ssh.Client
- auth AuthMethod
-}
-
-// NewGitUploadPackService initialises a GitUploadPackService,
-func NewGitUploadPackService(endpoint common.Endpoint) common.GitUploadPackService {
- return &GitUploadPackService{endpoint: endpoint}
-}
-
-// Connect connects to the SSH server, unless a AuthMethod was set with SetAuth
-// method, by default uses an auth method based on PublicKeysCallback, it
-// connects to a SSH agent, using the address stored in the SSH_AUTH_SOCK
-// environment var
-func (s *GitUploadPackService) Connect() error {
- if s.connected {
- return ErrAlreadyConnected
- }
-
- if err := s.setAuthFromEndpoint(); err != nil {
- return err
- }
-
- var err error
- s.client, err = ssh.Dial("tcp", s.getHostWithPort(), s.auth.clientConfig())
- if err != nil {
- return err
- }
-
- s.connected = true
- return nil
-}
-
-func (s *GitUploadPackService) getHostWithPort() string {
- host := s.endpoint.Host
- if strings.Index(s.endpoint.Host, ":") == -1 {
- host += ":22"
- }
-
- return host
-}
-
-func (s *GitUploadPackService) setAuthFromEndpoint() error {
- var u string
- if info := s.endpoint.User; info != nil {
- u = info.Username()
- }
-
- var err error
- s.auth, err = NewSSHAgentAuth(u)
- return err
-}
-
-// SetAuth sets the AuthMethod
-func (s *GitUploadPackService) SetAuth(auth common.AuthMethod) error {
- var ok bool
- s.auth, ok = auth.(AuthMethod)
- if !ok {
- return ErrInvalidAuthMethod
- }
-
- return nil
-}
-
-// Info returns the GitUploadPackInfo of the repository. The client must be
-// connected with the repository (using the ConnectWithAuth() method) before
-// using this method.
-func (s *GitUploadPackService) Info() (*common.GitUploadPackInfo, error) {
- if !s.connected {
- return nil, ErrNotConnected
- }
-
- session, err := s.client.NewSession()
- if err != nil {
- return nil, err
- }
- defer func() {
- // the session can be closed by the other endpoint,
- // therefore we must ignore a close error.
- _ = session.Close()
- }()
-
- out, err := session.Output(s.getCommand())
- if err != nil {
- return nil, err
- }
-
- i := common.NewGitUploadPackInfo()
- return i, i.Decode(bytes.NewReader(out))
-}
-
-// Disconnect the SSH client.
-func (s *GitUploadPackService) Disconnect() error {
- if !s.connected {
- return ErrNotConnected
- }
- s.connected = false
- return s.client.Close()
-}
-
-// Fetch returns a packfile for a given upload request. It opens a new
-// SSH session on a connected GitUploadPackService, sends the given
-// upload request to the server and returns a reader for the received
-// packfile. Closing the returned reader will close the SSH session.
-func (s *GitUploadPackService) Fetch(req *common.GitUploadPackRequest) (io.ReadCloser, error) {
- if !s.connected {
- return nil, ErrNotConnected
- }
-
- session, i, o, done, err := openSSHSession(s.client, s.getCommand())
- if err != nil {
- return nil, fmt.Errorf("cannot open SSH session: %s", err)
- }
-
- if err := talkPackProtocol(i, o, req); err != nil {
- return nil, err
- }
-
- return &fetchSession{
- Reader: o,
- session: session,
- done: done,
- }, nil
-}
-
-func openSSHSession(c *ssh.Client, cmd string) (
- *ssh.Session, io.WriteCloser, io.Reader, <-chan error, error) {
-
- session, err := c.NewSession()
- if err != nil {
- return nil, nil, nil, nil, fmt.Errorf("cannot open SSH session: %s", err)
- }
-
- i, err := session.StdinPipe()
- if err != nil {
- return nil, nil, nil, nil, fmt.Errorf("cannot pipe remote stdin: %s", err)
- }
-
- o, err := session.StdoutPipe()
- if err != nil {
- return nil, nil, nil, nil, fmt.Errorf("cannot pipe remote stdout: %s", err)
- }
-
- done := make(chan error)
- go func() {
- done <- session.Run(cmd)
- }()
-
- return session, i, o, done, nil
-}
-
-// TODO support multi_ack mode
-// TODO support multi_ack_detailed mode
-// TODO support acks for common objects
-// TODO build a proper state machine for all these processing options
-func talkPackProtocol(w io.WriteCloser, r io.Reader,
- req *common.GitUploadPackRequest) error {
-
- if err := skipAdvRef(r); err != nil {
- return fmt.Errorf("skipping advertised-refs: %s", err)
- }
-
- if err := sendUlReq(w, req); err != nil {
- return fmt.Errorf("sending upload-req message: %s", err)
- }
-
- if err := sendHaves(w, req); err != nil {
- return fmt.Errorf("sending haves message: %s", err)
- }
-
- if err := sendDone(w); err != nil {
- return fmt.Errorf("sending done message: %s", err)
- }
-
- if err := w.Close(); err != nil {
- return fmt.Errorf("closing input: %s", err)
- }
-
- if err := readNAK(r); err != nil {
- return fmt.Errorf("reading NAK: %s", err)
- }
-
- return nil
-}
-
-func skipAdvRef(r io.Reader) error {
- d := advrefs.NewDecoder(r)
- ar := advrefs.New()
-
- return d.Decode(ar)
-}
-
-func sendUlReq(w io.Writer, req *common.GitUploadPackRequest) error {
- ur := ulreq.New()
- ur.Wants = req.Wants
- ur.Depth = ulreq.DepthCommits(req.Depth)
- e := ulreq.NewEncoder(w)
-
- return e.Encode(ur)
-}
-
-func sendHaves(w io.Writer, req *common.GitUploadPackRequest) error {
- e := pktline.NewEncoder(w)
- for _, have := range req.Haves {
- if err := e.Encodef("have %s\n", have); err != nil {
- return fmt.Errorf("sending haves for %q: %s", have, err)
- }
- }
-
- if len(req.Haves) != 0 {
- if err := e.Flush(); err != nil {
- return fmt.Errorf("sending flush-pkt after haves: %s", err)
- }
- }
-
- return nil
-}
-
-func sendDone(w io.Writer) error {
- e := pktline.NewEncoder(w)
-
- return e.Encodef("done\n")
-}
-
-func readNAK(r io.Reader) error {
- s := pktline.NewScanner(r)
- if !s.Scan() {
- return s.Err()
- }
-
- b := s.Bytes()
- b = bytes.TrimSuffix(b, eol)
- if !bytes.Equal(b, nak) {
- return fmt.Errorf("expecting NAK, found %q instead", string(b))
- }
-
- return nil
-}
-
-type fetchSession struct {
- io.Reader
- session *ssh.Session
- done <-chan error
-}
-
-// Close closes the session and collects the output state of the remote
-// SSH command.
-//
-// If both the remote command and the closing of the session completes
-// susccessfully it returns nil.
-//
-// If the remote command completes unsuccessfully or is interrupted by a
-// signal, it returns the corresponding *ExitError.
-//
-// Otherwise, if clossing the SSH session fails it returns the close
-// error. Closing the session when the other has already close it is
-// not cosidered an error.
-func (f *fetchSession) Close() (err error) {
- if err := <-f.done; err != nil {
- return err
- }
-
- if err := f.session.Close(); err != nil && err != io.EOF {
- return err
- }
-
- return nil
-}
-
-func (s *GitUploadPackService) getCommand() string {
- directory := s.endpoint.Path
- directory = directory[1:]
-
- return fmt.Sprintf("git-upload-pack '%s'", directory)
-}
diff --git a/plumbing/client/ssh/git_upload_pack_test.go b/plumbing/client/ssh/git_upload_pack_test.go
deleted file mode 100644
index 4d5b2b1..0000000
--- a/plumbing/client/ssh/git_upload_pack_test.go
+++ /dev/null
@@ -1,144 +0,0 @@
-package ssh
-
-import (
- "io/ioutil"
- "os"
-
- . "gopkg.in/check.v1"
- "gopkg.in/src-d/go-git.v4/plumbing"
- "gopkg.in/src-d/go-git.v4/plumbing/client/common"
-)
-
-type RemoteSuite struct {
- Endpoint common.Endpoint
-}
-
-var _ = Suite(&RemoteSuite{})
-
-func (s *RemoteSuite) SetUpSuite(c *C) {
- var err error
- s.Endpoint, err = common.NewEndpoint("git@github.com:git-fixtures/basic.git")
- c.Assert(err, IsNil)
-
- if os.Getenv("SSH_AUTH_SOCK") == "" {
- c.Skip("SSH_AUTH_SOCK is not set")
- }
-}
-
-// A mock implementation of client.common.AuthMethod
-// to test non ssh auth method detection.
-type mockAuth struct{}
-
-func (*mockAuth) Name() string { return "" }
-func (*mockAuth) String() string { return "" }
-
-func (s *RemoteSuite) TestSetAuthWrongType(c *C) {
- r := NewGitUploadPackService(s.Endpoint)
- c.Assert(r.SetAuth(&mockAuth{}), Equals, ErrInvalidAuthMethod)
-}
-
-func (s *RemoteSuite) TestAlreadyConnected(c *C) {
- r := NewGitUploadPackService(s.Endpoint)
- c.Assert(r.Connect(), IsNil)
- defer func() {
- c.Assert(r.Disconnect(), IsNil)
- }()
-
- c.Assert(r.Connect(), Equals, ErrAlreadyConnected)
-}
-
-func (s *RemoteSuite) TestDisconnect(c *C) {
- r := NewGitUploadPackService(s.Endpoint)
- c.Assert(r.Connect(), IsNil)
- c.Assert(r.Disconnect(), IsNil)
-}
-
-func (s *RemoteSuite) TestDisconnectedWhenNonConnected(c *C) {
- r := NewGitUploadPackService(s.Endpoint)
- c.Assert(r.Disconnect(), Equals, ErrNotConnected)
-}
-
-func (s *RemoteSuite) TestAlreadyDisconnected(c *C) {
- r := NewGitUploadPackService(s.Endpoint)
- c.Assert(r.Connect(), IsNil)
- c.Assert(r.Disconnect(), IsNil)
- c.Assert(r.Disconnect(), Equals, ErrNotConnected)
-}
-
-func (s *RemoteSuite) TestServeralConnections(c *C) {
- r := NewGitUploadPackService(s.Endpoint)
- c.Assert(r.Connect(), IsNil)
- c.Assert(r.Disconnect(), IsNil)
-
- c.Assert(r.Connect(), IsNil)
- c.Assert(r.Disconnect(), IsNil)
-
- c.Assert(r.Connect(), IsNil)
- c.Assert(r.Disconnect(), IsNil)
-}
-
-func (s *RemoteSuite) TestInfoNotConnected(c *C) {
- r := NewGitUploadPackService(s.Endpoint)
- _, err := r.Info()
- c.Assert(err, Equals, ErrNotConnected)
-}
-
-func (s *RemoteSuite) TestDefaultBranch(c *C) {
- r := NewGitUploadPackService(s.Endpoint)
- c.Assert(r.Connect(), IsNil)
- defer func() { c.Assert(r.Disconnect(), IsNil) }()
-
- info, err := r.Info()
- c.Assert(err, IsNil)
- c.Assert(info.Capabilities.SymbolicReference("HEAD"), Equals, "refs/heads/master")
-}
-
-func (s *RemoteSuite) TestCapabilities(c *C) {
- r := NewGitUploadPackService(s.Endpoint)
- c.Assert(r.Connect(), IsNil)
- defer func() { c.Assert(r.Disconnect(), IsNil) }()
-
- info, err := r.Info()
- c.Assert(err, IsNil)
- c.Assert(info.Capabilities.Get("agent").Values, HasLen, 1)
-}
-
-func (s *RemoteSuite) TestFetchNotConnected(c *C) {
- r := NewGitUploadPackService(s.Endpoint)
- pr := &common.GitUploadPackRequest{}
- pr.Want(plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"))
- _, err := r.Fetch(pr)
- c.Assert(err, Equals, ErrNotConnected)
-}
-
-func (s *RemoteSuite) TestFetch(c *C) {
- r := NewGitUploadPackService(s.Endpoint)
- c.Assert(r.Connect(), IsNil)
- defer func() { c.Assert(r.Disconnect(), IsNil) }()
-
- req := &common.GitUploadPackRequest{}
- req.Want(plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"))
- req.Want(plumbing.NewHash("e8d3ffab552895c19b9fcf7aa264d277cde33881"))
- reader, err := r.Fetch(req)
- c.Assert(err, IsNil)
- defer func() { c.Assert(reader.Close(), IsNil) }()
-
- b, err := ioutil.ReadAll(reader)
- c.Assert(err, IsNil)
- c.Check(len(b), Equals, 85585)
-}
-
-func (s *RemoteSuite) TestFetchError(c *C) {
- r := NewGitUploadPackService(s.Endpoint)
- c.Assert(r.Connect(), IsNil)
- defer func() { c.Assert(r.Disconnect(), IsNil) }()
-
- req := &common.GitUploadPackRequest{}
- req.Want(plumbing.NewHash("1111111111111111111111111111111111111111"))
-
- reader, err := r.Fetch(req)
- c.Assert(err, IsNil)
-
- err = reader.Close()
- c.Assert(err, Not(IsNil))
-}