diff options
Diffstat (limited to 'plumbing/protocol/packp')
-rw-r--r-- | plumbing/protocol/packp/capability/capability.go | 2 | ||||
-rw-r--r-- | plumbing/protocol/packp/report_status.go | 15 | ||||
-rw-r--r-- | plumbing/protocol/packp/report_status_test.go | 44 | ||||
-rw-r--r-- | plumbing/protocol/packp/ulreq.go | 4 | ||||
-rw-r--r-- | plumbing/protocol/packp/updreq.go | 34 | ||||
-rw-r--r-- | plumbing/protocol/packp/updreq_decode.go | 36 | ||||
-rw-r--r-- | plumbing/protocol/packp/updreq_decode_test.go | 69 | ||||
-rw-r--r-- | plumbing/protocol/packp/updreq_encode.go | 8 | ||||
-rw-r--r-- | plumbing/protocol/packp/updreq_encode_test.go | 25 | ||||
-rw-r--r-- | plumbing/protocol/packp/updreq_test.go | 39 |
10 files changed, 229 insertions, 47 deletions
diff --git a/plumbing/protocol/packp/capability/capability.go b/plumbing/protocol/packp/capability/capability.go index 06fbfca..351ba0b 100644 --- a/plumbing/protocol/packp/capability/capability.go +++ b/plumbing/protocol/packp/capability/capability.go @@ -231,6 +231,8 @@ const ( SymRef Capability = "symref" ) +const DefaultAgent = "go-git/4.x" + var valid = map[Capability]bool{ MultiACK: true, MultiACKDetailed: true, NoDone: true, ThinPack: true, Sideband: true, Sideband64k: true, OFSDelta: true, Agent: true, diff --git a/plumbing/protocol/packp/report_status.go b/plumbing/protocol/packp/report_status.go index f480b34..ead4bb6 100644 --- a/plumbing/protocol/packp/report_status.go +++ b/plumbing/protocol/packp/report_status.go @@ -1,12 +1,13 @@ package packp import ( + "bytes" + "fmt" "io" + "strings" - "fmt" "gopkg.in/src-d/go-git.v4/plumbing" "gopkg.in/src-d/go-git.v4/plumbing/format/pktline" - "strings" ) const ( @@ -33,7 +34,7 @@ func (s *ReportStatus) Ok() bool { // Encode writes the report status to a writer. func (s *ReportStatus) Encode(w io.Writer) error { e := pktline.NewEncoder(w) - if err := e.Encodef("unpack %s", s.UnpackStatus); err != nil { + if err := e.Encodef("unpack %s\n", s.UnpackStatus); err != nil { return err } @@ -95,6 +96,8 @@ func (s *ReportStatus) decodeReportStatus(b []byte) error { return fmt.Errorf("premature flush") } + b = bytes.TrimSuffix(b, eol) + line := string(b) fields := strings.SplitN(line, " ", 2) if len(fields) != 2 || fields[0] != "unpack" { @@ -106,6 +109,8 @@ func (s *ReportStatus) decodeReportStatus(b []byte) error { } func (s *ReportStatus) decodeCommandStatus(b []byte) error { + b = bytes.TrimSuffix(b, eol) + line := string(b) fields := strings.SplitN(line, " ", 3) status := ok @@ -138,8 +143,8 @@ func (s *CommandStatus) Ok() bool { func (s *CommandStatus) encode(w io.Writer) error { e := pktline.NewEncoder(w) if s.Ok() { - return e.Encodef("ok %s", s.ReferenceName.String()) + return e.Encodef("ok %s\n", s.ReferenceName.String()) } - return e.Encodef("ng %s %s", s.ReferenceName.String(), s.Status) + return e.Encodef("ng %s %s\n", s.ReferenceName.String(), s.Status) } diff --git a/plumbing/protocol/packp/report_status_test.go b/plumbing/protocol/packp/report_status_test.go index 064e514..168d25b 100644 --- a/plumbing/protocol/packp/report_status_test.go +++ b/plumbing/protocol/packp/report_status_test.go @@ -69,8 +69,8 @@ func (s *ReportStatusSuite) TestEncodeDecodeOkOneReference(c *C) { }} s.testEncodeDecodeOk(c, rs, - "unpack ok", - "ok refs/heads/master", + "unpack ok\n", + "ok refs/heads/master\n", pktline.FlushString, ) } @@ -84,8 +84,8 @@ func (s *ReportStatusSuite) TestEncodeDecodeOkOneReferenceFailed(c *C) { }} s.testEncodeDecodeOk(c, rs, - "unpack my error", - "ng refs/heads/master command error", + "unpack my error\n", + "ng refs/heads/master command error\n", pktline.FlushString, ) } @@ -105,10 +105,10 @@ func (s *ReportStatusSuite) TestEncodeDecodeOkMoreReferences(c *C) { }} s.testEncodeDecodeOk(c, rs, - "unpack ok", - "ok refs/heads/master", - "ok refs/heads/a", - "ok refs/heads/b", + "unpack ok\n", + "ok refs/heads/master\n", + "ok refs/heads/a\n", + "ok refs/heads/b\n", pktline.FlushString, ) } @@ -128,10 +128,10 @@ func (s *ReportStatusSuite) TestEncodeDecodeOkMoreReferencesFailed(c *C) { }} s.testEncodeDecodeOk(c, rs, - "unpack my error", - "ok refs/heads/master", - "ng refs/heads/a command error", - "ok refs/heads/b", + "unpack my error\n", + "ok refs/heads/master\n", + "ng refs/heads/a command error\n", + "ok refs/heads/b\n", pktline.FlushString, ) } @@ -141,7 +141,7 @@ func (s *ReportStatusSuite) TestEncodeDecodeOkNoReferences(c *C) { expected.UnpackStatus = "ok" s.testEncodeDecodeOk(c, expected, - "unpack ok", + "unpack ok\n", pktline.FlushString, ) } @@ -151,7 +151,7 @@ func (s *ReportStatusSuite) TestEncodeDecodeOkNoReferencesFailed(c *C) { rs.UnpackStatus = "my error" s.testEncodeDecodeOk(c, rs, - "unpack my error", + "unpack my error\n", pktline.FlushString, ) } @@ -165,8 +165,8 @@ func (s *ReportStatusSuite) TestDecodeErrorOneReferenceNoFlush(c *C) { }} s.testDecodeError(c, "missing flush", - "unpack ok", - "ok refs/heads/master", + "unpack ok\n", + "ok refs/heads/master\n", ) } @@ -190,7 +190,7 @@ func (s *ReportStatusSuite) TestDecodeErrorMalformed(c *C) { }} s.testDecodeError(c, "malformed unpack status: unpackok", - "unpackok", + "unpackok\n", pktline.FlushString, ) } @@ -204,7 +204,7 @@ func (s *ReportStatusSuite) TestDecodeErrorMalformed2(c *C) { }} s.testDecodeError(c, "malformed unpack status: UNPACK OK", - "UNPACK OK", + "UNPACK OK\n", pktline.FlushString, ) } @@ -218,8 +218,8 @@ func (s *ReportStatusSuite) TestDecodeErrorMalformedCommandStatus(c *C) { }} s.testDecodeError(c, "malformed command status: ko refs/heads/master", - "unpack ok", - "ko refs/heads/master", + "unpack ok\n", + "ko refs/heads/master\n", pktline.FlushString, ) } @@ -233,8 +233,8 @@ func (s *ReportStatusSuite) TestDecodeErrorMalformedCommandStatus2(c *C) { }} s.testDecodeError(c, "malformed command status: ng refs/heads/master", - "unpack ok", - "ng refs/heads/master", + "unpack ok\n", + "ng refs/heads/master\n", pktline.FlushString, ) } diff --git a/plumbing/protocol/packp/ulreq.go b/plumbing/protocol/packp/ulreq.go index faf0885..7832007 100644 --- a/plumbing/protocol/packp/ulreq.go +++ b/plumbing/protocol/packp/ulreq.go @@ -8,8 +8,6 @@ import ( "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/capability" ) -const DefaultAgent = "go-git/4.x" - // UploadRequest values represent the information transmitted on a // upload-request message. Values from this type are not zero-value // safe, use the New function instead. @@ -97,7 +95,7 @@ func NewUploadRequestFromCapabilities(adv *capability.List) *UploadRequest { } if adv.Supports(capability.Agent) { - r.Capabilities.Set(capability.Agent, DefaultAgent) + r.Capabilities.Set(capability.Agent, capability.DefaultAgent) } return r diff --git a/plumbing/protocol/packp/updreq.go b/plumbing/protocol/packp/updreq.go index 90d6e09..a2deb89 100644 --- a/plumbing/protocol/packp/updreq.go +++ b/plumbing/protocol/packp/updreq.go @@ -2,6 +2,7 @@ package packp import ( "errors" + "io" "gopkg.in/src-d/go-git.v4/plumbing" "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/capability" @@ -20,6 +21,8 @@ type ReferenceUpdateRequest struct { Capabilities *capability.List Commands []*Command Shallow *plumbing.Hash + // Packfile contains an optional packfile reader. + Packfile io.ReadCloser } // New returns a pointer to a new ReferenceUpdateRequest value. @@ -30,6 +33,37 @@ func NewReferenceUpdateRequest() *ReferenceUpdateRequest { } } +// NewReferenceUpdateRequestFromCapabilities returns a pointer to a new +// ReferenceUpdateRequest value, the request capabilities are filled with the +// most optimal ones, based on the adv value (advertised capabilities), the +// ReferenceUpdateRequest contains no commands +// +// It does set the following capabilities: +// - agent +// - report-status +// - ofs-delta +// - ref-delta +// It leaves up to the user to add the following capabilities later: +// - atomic +// - ofs-delta +// - side-band +// - side-band-64k +// - quiet +// - push-cert +func NewReferenceUpdateRequestFromCapabilities(adv *capability.List) *ReferenceUpdateRequest { + r := NewReferenceUpdateRequest() + + if adv.Supports(capability.Agent) { + r.Capabilities.Set(capability.Agent, capability.DefaultAgent) + } + + if adv.Supports(capability.ReportStatus) { + r.Capabilities.Set(capability.ReportStatus) + } + + return r +} + func (r *ReferenceUpdateRequest) validate() error { if len(r.Commands) == 0 { return ErrEmptyCommands diff --git a/plumbing/protocol/packp/updreq_decode.go b/plumbing/protocol/packp/updreq_decode.go index 0740871..2ebe2a3 100644 --- a/plumbing/protocol/packp/updreq_decode.go +++ b/plumbing/protocol/packp/updreq_decode.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "io" + "io/ioutil" "gopkg.in/src-d/go-git.v4/plumbing" "gopkg.in/src-d/go-git.v4/plumbing/format/pktline" @@ -76,23 +77,32 @@ func errMalformedCommand(err error) error { // Decode reads the next update-request message form the reader and wr func (req *ReferenceUpdateRequest) Decode(r io.Reader) error { - d := &updReqDecoder{s: pktline.NewScanner(r)} + var rc io.ReadCloser + var ok bool + rc, ok = r.(io.ReadCloser) + if !ok { + rc = ioutil.NopCloser(r) + } + + d := &updReqDecoder{r: rc, s: pktline.NewScanner(r)} return d.Decode(req) } type updReqDecoder struct { - s *pktline.Scanner - r *ReferenceUpdateRequest + r io.ReadCloser + s *pktline.Scanner + req *ReferenceUpdateRequest } -func (d *updReqDecoder) Decode(r *ReferenceUpdateRequest) error { - d.r = r +func (d *updReqDecoder) Decode(req *ReferenceUpdateRequest) error { + d.req = req funcs := []func() error{ d.scanLine, d.decodeShallow, d.decodeCommandAndCapabilities, d.decodeCommands, - r.validate, + d.setPackfile, + req.validate, } for _, f := range funcs { @@ -132,7 +142,7 @@ func (d *updReqDecoder) decodeShallow() error { return d.scanErrorOr(errNoCommands) } - d.r.Shallow = &h + d.req.Shallow = &h return nil } @@ -149,7 +159,7 @@ func (d *updReqDecoder) decodeCommands() error { return err } - d.r.Commands = append(d.r.Commands, c) + d.req.Commands = append(d.req.Commands, c) if ok := d.s.Scan(); !ok { return d.s.Err() @@ -173,9 +183,9 @@ func (d *updReqDecoder) decodeCommandAndCapabilities() error { return err } - d.r.Commands = append(d.r.Commands, cmd) + d.req.Commands = append(d.req.Commands, cmd) - if err := d.r.Capabilities.Decode(b[i+1:]); err != nil { + if err := d.req.Capabilities.Decode(b[i+1:]); err != nil { return err } @@ -186,6 +196,12 @@ func (d *updReqDecoder) decodeCommandAndCapabilities() error { return nil } +func (d *updReqDecoder) setPackfile() error { + d.req.Packfile = d.r + + return nil +} + func parseCommand(b []byte) (*Command, error) { if len(b) < minCommandLength { return nil, errInvalidCommandLineLength(len(b)) diff --git a/plumbing/protocol/packp/updreq_decode_test.go b/plumbing/protocol/packp/updreq_decode_test.go index 66d9180..6cbab2b 100644 --- a/plumbing/protocol/packp/updreq_decode_test.go +++ b/plumbing/protocol/packp/updreq_decode_test.go @@ -3,6 +3,7 @@ package packp import ( "bytes" "io" + "io/ioutil" "gopkg.in/src-d/go-git.v4/plumbing" "gopkg.in/src-d/go-git.v4/plumbing/format/pktline" @@ -156,13 +157,14 @@ func (s *UpdReqDecodeSuite) TestOneUpdateCommand(c *C) { expected.Commands = []*Command{ {Name: name, Old: hash1, New: hash2}, } + expected.Packfile = ioutil.NopCloser(bytes.NewReader([]byte{})) payloads := []string{ "1ecf0ef2c2dffb796033e5a02219af86ec6584e5 2ecf0ef2c2dffb796033e5a02219af86ec6584e5 myref\x00", pktline.FlushString, } - c.Assert(s.testDecodeOK(c, payloads), DeepEquals, expected) + s.testDecodeOkExpected(c, expected, payloads) } func (s *UpdReqDecodeSuite) TestMultipleCommands(c *C) { @@ -175,6 +177,7 @@ func (s *UpdReqDecodeSuite) TestMultipleCommands(c *C) { {Name: "myref2", Old: plumbing.ZeroHash, New: hash2}, {Name: "myref3", Old: hash1, New: plumbing.ZeroHash}, } + expected.Packfile = ioutil.NopCloser(bytes.NewReader([]byte{})) payloads := []string{ "1ecf0ef2c2dffb796033e5a02219af86ec6584e5 2ecf0ef2c2dffb796033e5a02219af86ec6584e5 myref1\x00", @@ -183,10 +186,7 @@ func (s *UpdReqDecodeSuite) TestMultipleCommands(c *C) { pktline.FlushString, } - c.Assert(s.testDecodeOK(c, payloads).Commands, DeepEquals, expected.Commands) - c.Assert(s.testDecodeOK(c, payloads).Shallow, DeepEquals, expected.Shallow) - c.Assert(s.testDecodeOK(c, payloads).Capabilities, DeepEquals, expected.Capabilities) - c.Assert(s.testDecodeOK(c, payloads), DeepEquals, expected) + s.testDecodeOkExpected(c, expected, payloads) } func (s *UpdReqDecodeSuite) TestMultipleCommandsAndCapabilities(c *C) { @@ -200,6 +200,7 @@ func (s *UpdReqDecodeSuite) TestMultipleCommandsAndCapabilities(c *C) { {Name: "myref3", Old: hash1, New: plumbing.ZeroHash}, } expected.Capabilities.Add("shallow") + expected.Packfile = ioutil.NopCloser(bytes.NewReader([]byte{})) payloads := []string{ "1ecf0ef2c2dffb796033e5a02219af86ec6584e5 2ecf0ef2c2dffb796033e5a02219af86ec6584e5 myref1\x00shallow", @@ -208,7 +209,7 @@ func (s *UpdReqDecodeSuite) TestMultipleCommandsAndCapabilities(c *C) { pktline.FlushString, } - c.Assert(s.testDecodeOK(c, payloads), DeepEquals, expected) + s.testDecodeOkExpected(c, expected, payloads) } func (s *UpdReqDecodeSuite) TestMultipleCommandsAndCapabilitiesShallow(c *C) { @@ -223,6 +224,7 @@ func (s *UpdReqDecodeSuite) TestMultipleCommandsAndCapabilitiesShallow(c *C) { } expected.Capabilities.Add("shallow") expected.Shallow = &hash1 + expected.Packfile = ioutil.NopCloser(bytes.NewReader([]byte{})) payloads := []string{ "shallow 1ecf0ef2c2dffb796033e5a02219af86ec6584e5", @@ -232,7 +234,31 @@ func (s *UpdReqDecodeSuite) TestMultipleCommandsAndCapabilitiesShallow(c *C) { pktline.FlushString, } - c.Assert(s.testDecodeOK(c, payloads), DeepEquals, expected) + s.testDecodeOkExpected(c, expected, payloads) +} + +func (s *UpdReqDecodeSuite) TestWithPackfile(c *C) { + hash1 := plumbing.NewHash("1ecf0ef2c2dffb796033e5a02219af86ec6584e5") + hash2 := plumbing.NewHash("2ecf0ef2c2dffb796033e5a02219af86ec6584e5") + name := "myref" + + expected := NewReferenceUpdateRequest() + expected.Commands = []*Command{ + {Name: name, Old: hash1, New: hash2}, + } + packfileContent := []byte("PACKabc") + expected.Packfile = ioutil.NopCloser(bytes.NewReader(packfileContent)) + + payloads := []string{ + "1ecf0ef2c2dffb796033e5a02219af86ec6584e5 2ecf0ef2c2dffb796033e5a02219af86ec6584e5 myref\x00", + pktline.FlushString, + } + var buf bytes.Buffer + e := pktline.NewEncoder(&buf) + c.Assert(e.EncodeString(payloads...), IsNil) + buf.Write(packfileContent) + + s.testDecodeOkRaw(c, expected, buf.Bytes()) } func (s *UpdReqDecodeSuite) testDecoderErrorMatches(c *C, input io.Reader, pattern string) { @@ -251,3 +277,32 @@ func (s *UpdReqDecodeSuite) testDecodeOK(c *C, payloads []string) *ReferenceUpda return r } + +func (s *UpdReqDecodeSuite) testDecodeOkRaw(c *C, expected *ReferenceUpdateRequest, raw []byte) { + req := NewReferenceUpdateRequest() + c.Assert(req.Decode(bytes.NewBuffer(raw)), IsNil) + c.Assert(req.Packfile, NotNil) + s.compareReaders(c, req.Packfile, expected.Packfile) + req.Packfile = nil + expected.Packfile = nil + c.Assert(req, DeepEquals, expected) +} + +func (s *UpdReqDecodeSuite) testDecodeOkExpected(c *C, expected *ReferenceUpdateRequest, payloads []string) { + req := s.testDecodeOK(c, payloads) + c.Assert(req.Packfile, NotNil) + s.compareReaders(c, req.Packfile, expected.Packfile) + req.Packfile = nil + expected.Packfile = nil + c.Assert(req, DeepEquals, expected) +} + +func (s *UpdReqDecodeSuite) compareReaders(c *C, a io.ReadCloser, b io.ReadCloser) { + pba, err := ioutil.ReadAll(a) + c.Assert(err, IsNil) + c.Assert(a.Close(), IsNil) + pbb, err := ioutil.ReadAll(b) + c.Assert(err, IsNil) + c.Assert(b.Close(), IsNil) + c.Assert(pba, DeepEquals, pbb) +} diff --git a/plumbing/protocol/packp/updreq_encode.go b/plumbing/protocol/packp/updreq_encode.go index b2b7944..44c0573 100644 --- a/plumbing/protocol/packp/updreq_encode.go +++ b/plumbing/protocol/packp/updreq_encode.go @@ -29,6 +29,14 @@ func (r *ReferenceUpdateRequest) Encode(w io.Writer) error { return err } + if r.Packfile != nil { + if _, err := io.Copy(w, r.Packfile); err != nil { + return err + } + + return r.Packfile.Close() + } + return nil } diff --git a/plumbing/protocol/packp/updreq_encode_test.go b/plumbing/protocol/packp/updreq_encode_test.go index 47958fd..14f9975 100644 --- a/plumbing/protocol/packp/updreq_encode_test.go +++ b/plumbing/protocol/packp/updreq_encode_test.go @@ -7,6 +7,7 @@ import ( "gopkg.in/src-d/go-git.v4/plumbing/format/pktline" . "gopkg.in/check.v1" + "io/ioutil" ) type UpdReqEncodeSuite struct{} @@ -117,3 +118,27 @@ func (s *UpdReqEncodeSuite) TestMultipleCommandsAndCapabilitiesShallow(c *C) { s.testEncode(c, r, expected) } + +func (s *UpdReqEncodeSuite) TestWithPackfile(c *C) { + hash1 := plumbing.NewHash("1ecf0ef2c2dffb796033e5a02219af86ec6584e5") + hash2 := plumbing.NewHash("2ecf0ef2c2dffb796033e5a02219af86ec6584e5") + name := "myref" + + packfileContent := []byte("PACKabc") + packfileReader := bytes.NewReader(packfileContent) + packfileReadCloser := ioutil.NopCloser(packfileReader) + + r := NewReferenceUpdateRequest() + r.Commands = []*Command{ + {Name: name, Old: hash1, New: hash2}, + } + r.Packfile = packfileReadCloser + + expected := pktlines(c, + "1ecf0ef2c2dffb796033e5a02219af86ec6584e5 2ecf0ef2c2dffb796033e5a02219af86ec6584e5 myref\x00", + pktline.FlushString, + ) + expected = append(expected, packfileContent...) + + s.testEncode(c, r, expected) +} diff --git a/plumbing/protocol/packp/updreq_test.go b/plumbing/protocol/packp/updreq_test.go new file mode 100644 index 0000000..2412fbf --- /dev/null +++ b/plumbing/protocol/packp/updreq_test.go @@ -0,0 +1,39 @@ +package packp + +import ( + "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/capability" + + . "gopkg.in/check.v1" +) + +type UpdReqSuite struct{} + +var _ = Suite(&UpdReqSuite{}) + +func (s *UpdReqSuite) TestNewReferenceUpdateRequestFromCapabilities(c *C) { + cap := capability.NewList() + cap.Set(capability.Sideband) + cap.Set(capability.Sideband64k) + cap.Set(capability.Quiet) + cap.Set(capability.ReportStatus) + cap.Set(capability.DeleteRefs) + cap.Set(capability.PushCert, "foo") + cap.Set(capability.Atomic) + cap.Set(capability.Agent, "foo") + + r := NewReferenceUpdateRequestFromCapabilities(cap) + c.Assert(r.Capabilities.String(), Equals, + "agent=go-git/4.x report-status", + ) + + cap = capability.NewList() + cap.Set(capability.Agent, "foo") + + r = NewReferenceUpdateRequestFromCapabilities(cap) + c.Assert(r.Capabilities.String(), Equals, "agent=go-git/4.x") + + cap = capability.NewList() + + r = NewReferenceUpdateRequestFromCapabilities(cap) + c.Assert(r.Capabilities.String(), Equals, "") +} |