aboutsummaryrefslogtreecommitdiffstats
path: root/plumbing/protocol
diff options
context:
space:
mode:
authorSantiago M. Mola <santi@mola.io>2017-01-04 11:18:41 +0100
committerGitHub <noreply@github.com>2017-01-04 11:18:41 +0100
commit841abfb7dc640755c443432064252907e3e55c95 (patch)
tree8af69dcd3b301a10a3e493e2cd805cdec6dcaecd /plumbing/protocol
parent90d67bb648ae32d5b1a0f7b1af011da6dfb24315 (diff)
downloadgo-git-841abfb7dc640755c443432064252907e3e55c95.tar.gz
server: add git server implementation (#190)
* server: add generic server implementation (transport-independent), both for git-upload-pack and git-receive-pack. * server: move internal functions to internal/common. * cli: add git-receive-pack and git-upload-pack implementations. * format/packfile: add UpdateObjectStorage function, extracted from Remote. * transport: implement tranport RPC-like, only with git-upload-pack and git-receive-pack methods. Client renamed to Transport. * storer: add storer.Storer interface. * protocol/packp: add UploadPackResponse constructor with packfile. * protocol/packp: fix UploadPackResponse encoding, add tests. * protocol/packp/capability: implement All.
Diffstat (limited to 'plumbing/protocol')
-rw-r--r--plumbing/protocol/packp/capability/list.go10
-rw-r--r--plumbing/protocol/packp/capability/list_test.go11
-rw-r--r--plumbing/protocol/packp/shallowupd.go19
-rw-r--r--plumbing/protocol/packp/shallowupd_test.go87
-rw-r--r--plumbing/protocol/packp/srvresp.go14
-rw-r--r--plumbing/protocol/packp/updreq_decode.go2
-rw-r--r--plumbing/protocol/packp/uppackresp.go30
-rw-r--r--plumbing/protocol/packp/uppackresp_test.go44
8 files changed, 215 insertions, 2 deletions
diff --git a/plumbing/protocol/packp/capability/list.go b/plumbing/protocol/packp/capability/list.go
index 2847580..69fdb51 100644
--- a/plumbing/protocol/packp/capability/list.go
+++ b/plumbing/protocol/packp/capability/list.go
@@ -167,6 +167,16 @@ func (l *List) Delete(capability Capability) {
}
}
+// All returns a slice with all defined capabilities.
+func (l *List) All() []Capability {
+ var cs []Capability
+ for _, key := range l.sort {
+ cs = append(cs, Capability(key))
+ }
+
+ return cs
+}
+
// String generates the capabilities strings, the capabilities are sorted in
// insertion order
func (l *List) String() string {
diff --git a/plumbing/protocol/packp/capability/list_test.go b/plumbing/protocol/packp/capability/list_test.go
index 42f0179..0a0ad26 100644
--- a/plumbing/protocol/packp/capability/list_test.go
+++ b/plumbing/protocol/packp/capability/list_test.go
@@ -171,3 +171,14 @@ func (s *SuiteCapabilities) TestAddErrMultipleArgumentsAtTheSameTime(c *check.C)
err := cap.Add(Agent, "foo", "bar")
c.Assert(err, check.Equals, ErrMultipleArguments)
}
+
+func (s *SuiteCapabilities) TestAll(c *check.C) {
+ cap := NewList()
+ c.Assert(NewList().All(), check.IsNil)
+
+ cap.Add(Agent, "foo")
+ c.Assert(cap.All(), check.DeepEquals, []Capability{Agent})
+
+ cap.Add(OFSDelta)
+ c.Assert(cap.All(), check.DeepEquals, []Capability{Agent, OFSDelta})
+}
diff --git a/plumbing/protocol/packp/shallowupd.go b/plumbing/protocol/packp/shallowupd.go
index 89063de..40f58e8 100644
--- a/plumbing/protocol/packp/shallowupd.go
+++ b/plumbing/protocol/packp/shallowupd.go
@@ -24,6 +24,7 @@ func (r *ShallowUpdate) Decode(reader io.Reader) error {
for s.Scan() {
line := s.Bytes()
+ line = bytes.TrimSpace(line)
var err error
switch {
@@ -71,3 +72,21 @@ func (r *ShallowUpdate) decodeLine(line, prefix []byte, expLen int) (plumbing.Ha
raw := string(line[expLen-40 : expLen])
return plumbing.NewHash(raw), nil
}
+
+func (r *ShallowUpdate) Encode(w io.Writer) error {
+ e := pktline.NewEncoder(w)
+
+ for _, h := range r.Shallows {
+ if err := e.Encodef("%s%s\n", shallow, h.String()); err != nil {
+ return err
+ }
+ }
+
+ for _, h := range r.Unshallows {
+ if err := e.Encodef("%s%s\n", unshallow, h.String()); err != nil {
+ return err
+ }
+ }
+
+ return e.Flush()
+}
diff --git a/plumbing/protocol/packp/shallowupd_test.go b/plumbing/protocol/packp/shallowupd_test.go
index d64fb5d..97a13fc 100644
--- a/plumbing/protocol/packp/shallowupd_test.go
+++ b/plumbing/protocol/packp/shallowupd_test.go
@@ -12,6 +12,26 @@ type ShallowUpdateSuite struct{}
var _ = Suite(&ShallowUpdateSuite{})
+func (s *ShallowUpdateSuite) TestDecodeWithLF(c *C) {
+ raw := "" +
+ "0035shallow aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" +
+ "0035shallow bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n" +
+ "0000"
+
+ su := &ShallowUpdate{}
+ err := su.Decode(bytes.NewBufferString(raw))
+ c.Assert(err, IsNil)
+
+ plumbing.HashesSort(su.Shallows)
+
+ c.Assert(su.Unshallows, HasLen, 0)
+ c.Assert(su.Shallows, HasLen, 2)
+ c.Assert(su.Shallows, DeepEquals, []plumbing.Hash{
+ plumbing.NewHash("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
+ plumbing.NewHash("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"),
+ })
+}
+
func (s *ShallowUpdateSuite) TestDecode(c *C) {
raw := "" +
"0034shallow aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
@@ -61,3 +81,70 @@ func (s *ShallowUpdateSuite) TestDecodeMalformed(c *C) {
err := su.Decode(bytes.NewBufferString(raw))
c.Assert(err, NotNil)
}
+
+func (s *ShallowUpdateSuite) TestEncodeEmpty(c *C) {
+ su := &ShallowUpdate{}
+ buf := bytes.NewBuffer(nil)
+ c.Assert(su.Encode(buf), IsNil)
+ c.Assert(buf.String(), Equals, "0000")
+}
+
+func (s *ShallowUpdateSuite) TestEncode(c *C) {
+ su := &ShallowUpdate{
+ Shallows: []plumbing.Hash{
+ plumbing.NewHash("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
+ plumbing.NewHash("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"),
+ },
+ Unshallows: []plumbing.Hash{
+ plumbing.NewHash("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
+ plumbing.NewHash("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"),
+ },
+ }
+ buf := bytes.NewBuffer(nil)
+ c.Assert(su.Encode(buf), IsNil)
+
+ expected := "" +
+ "0035shallow aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" +
+ "0035shallow bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n" +
+ "0037unshallow aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" +
+ "0037unshallow bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n" +
+ "0000"
+
+ c.Assert(buf.String(), Equals, expected)
+}
+
+func (s *ShallowUpdateSuite) TestEncodeShallow(c *C) {
+ su := &ShallowUpdate{
+ Shallows: []plumbing.Hash{
+ plumbing.NewHash("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
+ plumbing.NewHash("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"),
+ },
+ }
+ buf := bytes.NewBuffer(nil)
+ c.Assert(su.Encode(buf), IsNil)
+
+ expected := "" +
+ "0035shallow aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" +
+ "0035shallow bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n" +
+ "0000"
+
+ c.Assert(buf.String(), Equals, expected)
+}
+
+func (s *ShallowUpdateSuite) TestEncodeUnshallow(c *C) {
+ su := &ShallowUpdate{
+ Unshallows: []plumbing.Hash{
+ plumbing.NewHash("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
+ plumbing.NewHash("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"),
+ },
+ }
+ buf := bytes.NewBuffer(nil)
+ c.Assert(su.Encode(buf), IsNil)
+
+ expected := "" +
+ "0037unshallow aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" +
+ "0037unshallow bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n" +
+ "0000"
+
+ c.Assert(buf.String(), Equals, expected)
+}
diff --git a/plumbing/protocol/packp/srvresp.go b/plumbing/protocol/packp/srvresp.go
index 3284fa2..d41b50d 100644
--- a/plumbing/protocol/packp/srvresp.go
+++ b/plumbing/protocol/packp/srvresp.go
@@ -68,3 +68,17 @@ func (r *ServerResponse) decodeACKLine(line []byte) error {
r.ACKs = append(r.ACKs, h)
return nil
}
+
+// Encode encodes the ServerResponse into a writer.
+func (r *ServerResponse) Encode(w io.Writer) error {
+ if len(r.ACKs) > 1 {
+ return errors.New("multi_ack and multi_ack_detailed are not supported")
+ }
+
+ e := pktline.NewEncoder(w)
+ if len(r.ACKs) == 0 {
+ return e.Encodef("%s\n", nak)
+ }
+
+ return e.Encodef("%s %s\n", ack, r.ACKs[0].String())
+}
diff --git a/plumbing/protocol/packp/updreq_decode.go b/plumbing/protocol/packp/updreq_decode.go
index 51e8183..c15d49c 100644
--- a/plumbing/protocol/packp/updreq_decode.go
+++ b/plumbing/protocol/packp/updreq_decode.go
@@ -225,7 +225,7 @@ func parseCommand(b []byte) (*Command, error) {
return nil, errInvalidNewObjId(err)
}
- return &Command{Old: oh, New: nh, Name: n}, nil
+ return &Command{Old: oh, New: nh, Name: plumbing.ReferenceName(n)}, nil
}
func parseHash(s string) (plumbing.Hash, error) {
diff --git a/plumbing/protocol/packp/uppackresp.go b/plumbing/protocol/packp/uppackresp.go
index a117956..ac456f3 100644
--- a/plumbing/protocol/packp/uppackresp.go
+++ b/plumbing/protocol/packp/uppackresp.go
@@ -5,6 +5,7 @@ import (
"io"
"gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/capability"
+ "gopkg.in/src-d/go-git.v4/utils/ioutil"
)
// ErrUploadPackResponseNotDecoded is returned if Read is called without
@@ -17,8 +18,8 @@ var ErrUploadPackResponseNotDecoded = errors.New("upload-pack-response should be
type UploadPackResponse struct {
ShallowUpdate
ServerResponse
- r io.ReadCloser
+ r io.ReadCloser
isShallow bool
isMultiACK bool
isOk bool
@@ -37,6 +38,16 @@ func NewUploadPackResponse(req *UploadPackRequest) *UploadPackResponse {
}
}
+// NewUploadPackResponseWithPackfile creates a new UploadPackResponse instance,
+// and sets its packfile reader.
+func NewUploadPackResponseWithPackfile(req *UploadPackRequest,
+ pf io.ReadCloser) *UploadPackResponse {
+
+ r := NewUploadPackResponse(req)
+ r.r = pf
+ return r
+}
+
// Decode decodes all the responses sent by upload-pack service into the struct
// and prepares it to read the packfile using the Read method
func (r *UploadPackResponse) Decode(reader io.ReadCloser) error {
@@ -56,6 +67,23 @@ func (r *UploadPackResponse) Decode(reader io.ReadCloser) error {
return nil
}
+// Encode encodes an UploadPackResponse.
+func (r *UploadPackResponse) Encode(w io.Writer) (err error) {
+ if r.isShallow {
+ if err := r.ShallowUpdate.Encode(w); err != nil {
+ return err
+ }
+ }
+
+ if err := r.ServerResponse.Encode(w); err != nil {
+ return err
+ }
+
+ defer ioutil.CheckClose(r.r, &err)
+ _, err = io.Copy(w, r.r)
+ return err
+}
+
// Read reads the packfile data, if the request was done with any Sideband
// capability the content read should be demultiplexed. If the methods wasn't
// called before the ErrUploadPackResponseNotDecoded will be return
diff --git a/plumbing/protocol/packp/uppackresp_test.go b/plumbing/protocol/packp/uppackresp_test.go
index c81bb76..c27fdda 100644
--- a/plumbing/protocol/packp/uppackresp_test.go
+++ b/plumbing/protocol/packp/uppackresp_test.go
@@ -7,6 +7,7 @@ import (
"gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/capability"
. "gopkg.in/check.v1"
+ "gopkg.in/src-d/go-git.v4/plumbing"
)
type UploadPackResponseSuite struct{}
@@ -80,3 +81,46 @@ func (s *UploadPackResponseSuite) TestReadNoDecode(c *C) {
c.Assert(err, Equals, ErrUploadPackResponseNotDecoded)
c.Assert(n, Equals, 0)
}
+
+func (s *UploadPackResponseSuite) TestEncodeNAK(c *C) {
+ pf := ioutil.NopCloser(bytes.NewBuffer([]byte("[PACK]")))
+ req := NewUploadPackRequest()
+ res := NewUploadPackResponseWithPackfile(req, pf)
+ defer func() { c.Assert(res.Close(), IsNil) }()
+
+ b := bytes.NewBuffer(nil)
+ c.Assert(res.Encode(b), IsNil)
+
+ expected := "0008NAK\n[PACK]"
+ c.Assert(string(b.Bytes()), Equals, expected)
+}
+
+func (s *UploadPackResponseSuite) TestEncodeDepth(c *C) {
+ pf := ioutil.NopCloser(bytes.NewBuffer([]byte("[PACK]")))
+ req := NewUploadPackRequest()
+ req.Depth = DepthCommits(1)
+
+ res := NewUploadPackResponseWithPackfile(req, pf)
+ defer func() { c.Assert(res.Close(), IsNil) }()
+
+ b := bytes.NewBuffer(nil)
+ c.Assert(res.Encode(b), IsNil)
+
+ expected := "00000008NAK\n[PACK]"
+ c.Assert(string(b.Bytes()), Equals, expected)
+}
+
+func (s *UploadPackResponseSuite) TestEncodeMultiACK(c *C) {
+ pf := ioutil.NopCloser(bytes.NewBuffer([]byte("[PACK]")))
+ req := NewUploadPackRequest()
+
+ res := NewUploadPackResponseWithPackfile(req, pf)
+ defer func() { c.Assert(res.Close(), IsNil) }()
+ res.ACKs = []plumbing.Hash{
+ plumbing.NewHash("5dc01c595e6c6ec9ccda4f6f69c131c0dd945f81"),
+ plumbing.NewHash("5dc01c595e6c6ec9ccda4f6f69c131c0dd945f82"),
+ }
+
+ b := bytes.NewBuffer(nil)
+ c.Assert(res.Encode(b), NotNil)
+}