From df9748cfb51db9c406e3df063badbd8c78ee819d Mon Sep 17 00:00:00 2001 From: Máximo Cuadros Date: Mon, 12 Dec 2016 15:50:15 +0100 Subject: transport: new git protocol (#175) --- plumbing/transport/internal/common/common.go | 91 ++++++++++++++++++---------- 1 file changed, 59 insertions(+), 32 deletions(-) (limited to 'plumbing/transport/internal/common/common.go') diff --git a/plumbing/transport/internal/common/common.go b/plumbing/transport/internal/common/common.go index f0e1691..f6d1249 100644 --- a/plumbing/transport/internal/common/common.go +++ b/plumbing/transport/internal/common/common.go @@ -132,22 +132,30 @@ func (c *client) newSession(s string, ep transport.Endpoint) (*session, error) { return nil, err } + return &session{ + Stdin: stdin, + Stdout: stdout, + Command: cmd, + errLines: c.listenErrors(stderr), + isReceivePack: s == transport.ReceivePackServiceName, + }, nil +} + +func (c *client) listenErrors(r io.Reader) chan string { + if r == nil { + return nil + } + errLines := make(chan string, errLinesBuffer) go func() { - s := bufio.NewScanner(stderr) + s := bufio.NewScanner(r) for s.Scan() { line := string(s.Bytes()) errLines <- line } }() - return &session{ - Stdin: stdin, - Stdout: stdout, - Command: cmd, - errLines: errLines, - isReceivePack: s == transport.ReceivePackServiceName, - }, nil + return errLines } // SetAuth delegates to the command's SetAuth. @@ -163,38 +171,52 @@ func (s *session) AdvertisedReferences() (*packp.AdvRefs, error) { ar := packp.NewAdvRefs() if err := ar.Decode(s.Stdout); err != nil { - // If repository is not found, we get empty stdout and server - // writes an error to stderr. - if err == packp.ErrEmptyInput { - if err := s.checkNotFoundError(); err != nil { - return nil, err - } - - return nil, io.ErrUnexpectedEOF + if err := s.handleAdvRefDecodeError(err); err != nil { + return nil, err } + } - // For empty (but existing) repositories, we get empty - // advertised-references message. But valid. That is, it - // includes at least a flush. - if err == packp.ErrEmptyAdvRefs { - // Empty repositories are valid for git-receive-pack. - if s.isReceivePack { - return ar, nil - } + transport.FilterUnsupportedCapabilities(ar.Capabilities) + s.advRefs = ar + return ar, nil +} + +func (s *session) handleAdvRefDecodeError(err error) error { + // If repository is not found, we get empty stdout and server writes an + // error to stderr. + if err == packp.ErrEmptyInput { + if err := s.checkNotFoundError(); err != nil { + return err + } + + return io.ErrUnexpectedEOF + } - if err := s.finish(); err != nil { - return nil, err - } + // For empty (but existing) repositories, we get empty advertised-references + // message. But valid. That is, it includes at least a flush. + if err == packp.ErrEmptyAdvRefs { + // Empty repositories are valid for git-receive-pack. + if s.isReceivePack { + return nil + } - return nil, transport.ErrEmptyRemoteRepository + if err := s.finish(); err != nil { + return err } - return nil, err + return transport.ErrEmptyRemoteRepository } - transport.FilterUnsupportedCapabilities(ar.Capabilities) - s.advRefs = ar - return ar, nil + // Some server sends the errors as normal content (git protocol), so when + // we try to decode it fails, we need to check the content of it, to detect + // not found errors + if uerr, ok := err.(*packp.ErrUnexpectedData); ok { + if isRepoNotFoundError(string(uerr.Data)) { + return transport.ErrRepositoryNotFound + } + } + + return err } // FetchPack performs a request to the server to fetch a packfile. A reader is @@ -317,6 +339,7 @@ var ( githubRepoNotFoundErr = "ERROR: Repository not found." bitbucketRepoNotFoundErr = "conq: repository does not exist." localRepoNotFoundErr = "does not appear to be a git repository" + gitProtocolNotFoundErr = "ERR \n Repository not found." ) func isRepoNotFoundError(s string) bool { @@ -332,6 +355,10 @@ func isRepoNotFoundError(s string) bool { return true } + if strings.HasPrefix(s, gitProtocolNotFoundErr) { + return true + } + return false } -- cgit