Skip to content
This repository was archived by the owner on Sep 11, 2020. It is now read-only.

Commit 22fe81f

Browse files
authored
protocol/packp: UploadPackResponse implementation (#161)
* plumbing/protocol: paktp avoid duplication of haves, wants and shallow * protocol/pakp: UploadPackResponse implementation * changes * changes * changes * debug * changes
1 parent 4b5849d commit 22fe81f

17 files changed

+580
-67
lines changed

fixtures/fixtures.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package fixtures
33
import (
44
"fmt"
55
"go/build"
6+
"io/ioutil"
67
"os"
78
"path/filepath"
89

@@ -195,6 +196,25 @@ func (f *Fixture) DotGit() fs.Filesystem {
195196
return osfs.New(path)
196197
}
197198

199+
func (f *Fixture) Worktree() fs.Filesystem {
200+
fn := filepath.Join(RootFolder, DataFolder, fmt.Sprintf("git-%s.tgz", f.DotGitHash))
201+
git, err := tgz.Extract(fn)
202+
if err != nil {
203+
panic(err)
204+
}
205+
206+
worktree, err := ioutil.TempDir("", "worktree")
207+
if err != nil {
208+
panic(err)
209+
}
210+
211+
if err := os.Rename(git, filepath.Join(worktree, ".git")); err != nil {
212+
panic(err)
213+
}
214+
215+
return osfs.New(worktree)
216+
}
217+
198218
type Fixtures []*Fixture
199219

200220
func (g Fixtures) Test(c *check.C, test func(*Fixture)) {

plumbing/protocol/packp/common.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,26 @@ var (
1717
eol = []byte("\n")
1818
eq = []byte{'='}
1919

20-
// advrefs
20+
// advertised-refs
2121
null = []byte("\x00")
2222
peeled = []byte("^{}")
2323
noHeadMark = []byte(" capabilities^{}\x00")
2424

25-
// ulreq
25+
// upload-request
2626
want = []byte("want ")
2727
shallow = []byte("shallow ")
2828
deepen = []byte("deepen")
2929
deepenCommits = []byte("deepen ")
3030
deepenSince = []byte("deepen-since ")
3131
deepenReference = []byte("deepen-not ")
3232

33+
// shallow-update
34+
unshallow = []byte("unshallow ")
35+
36+
// server-response
37+
ack = []byte("ACK")
38+
nak = []byte("NAK")
39+
3340
// updreq
3441
shallowNoSp = []byte("shallow")
3542
)

plumbing/protocol/packp/shallowupd.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package packp
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
"io"
7+
8+
"gopkg.in/src-d/go-git.v4/plumbing"
9+
"gopkg.in/src-d/go-git.v4/plumbing/format/pktline"
10+
)
11+
12+
const (
13+
shallowLineLen = 48
14+
unshallowLineLen = 50
15+
)
16+
17+
type ShallowUpdate struct {
18+
Shallows []plumbing.Hash
19+
Unshallows []plumbing.Hash
20+
}
21+
22+
func (r *ShallowUpdate) Decode(reader io.Reader) error {
23+
s := pktline.NewScanner(reader)
24+
25+
for s.Scan() {
26+
line := s.Bytes()
27+
28+
var err error
29+
switch {
30+
case bytes.HasPrefix(line, shallow):
31+
err = r.decodeShallowLine(line)
32+
case bytes.HasPrefix(line, unshallow):
33+
err = r.decodeUnshallowLine(line)
34+
case bytes.Compare(line, pktline.Flush) == 0:
35+
return nil
36+
}
37+
38+
if err != nil {
39+
return err
40+
}
41+
}
42+
43+
return s.Err()
44+
}
45+
46+
func (r *ShallowUpdate) decodeShallowLine(line []byte) error {
47+
hash, err := r.decodeLine(line, shallow, shallowLineLen)
48+
if err != nil {
49+
return err
50+
}
51+
52+
r.Shallows = append(r.Shallows, hash)
53+
return nil
54+
}
55+
56+
func (r *ShallowUpdate) decodeUnshallowLine(line []byte) error {
57+
hash, err := r.decodeLine(line, unshallow, unshallowLineLen)
58+
if err != nil {
59+
return err
60+
}
61+
62+
r.Unshallows = append(r.Unshallows, hash)
63+
return nil
64+
}
65+
66+
func (r *ShallowUpdate) decodeLine(line, prefix []byte, expLen int) (plumbing.Hash, error) {
67+
if len(line) != expLen {
68+
return plumbing.ZeroHash, fmt.Errorf("malformed %s%q", prefix, line)
69+
}
70+
71+
raw := string(line[expLen-40 : expLen])
72+
return plumbing.NewHash(raw), nil
73+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package packp
2+
3+
import (
4+
"bytes"
5+
6+
"gopkg.in/src-d/go-git.v4/plumbing"
7+
8+
. "gopkg.in/check.v1"
9+
)
10+
11+
type ShallowUpdateSuite struct{}
12+
13+
var _ = Suite(&ShallowUpdateSuite{})
14+
15+
func (s *ShallowUpdateSuite) TestDecode(c *C) {
16+
raw := "" +
17+
"0034shallow aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
18+
"0034shallow bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" +
19+
"0000"
20+
21+
su := &ShallowUpdate{}
22+
err := su.Decode(bytes.NewBufferString(raw))
23+
c.Assert(err, IsNil)
24+
25+
plumbing.HashesSort(su.Shallows)
26+
27+
c.Assert(su.Unshallows, HasLen, 0)
28+
c.Assert(su.Shallows, HasLen, 2)
29+
c.Assert(su.Shallows, DeepEquals, []plumbing.Hash{
30+
plumbing.NewHash("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
31+
plumbing.NewHash("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"),
32+
})
33+
}
34+
35+
func (s *ShallowUpdateSuite) TestDecodeUnshallow(c *C) {
36+
raw := "" +
37+
"0036unshallow aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
38+
"0036unshallow bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" +
39+
"0000"
40+
41+
su := &ShallowUpdate{}
42+
err := su.Decode(bytes.NewBufferString(raw))
43+
c.Assert(err, IsNil)
44+
45+
plumbing.HashesSort(su.Unshallows)
46+
47+
c.Assert(su.Shallows, HasLen, 0)
48+
c.Assert(su.Unshallows, HasLen, 2)
49+
c.Assert(su.Unshallows, DeepEquals, []plumbing.Hash{
50+
plumbing.NewHash("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
51+
plumbing.NewHash("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"),
52+
})
53+
}
54+
55+
func (s *ShallowUpdateSuite) TestDecodeMalformed(c *C) {
56+
raw := "" +
57+
"0035unshallow aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
58+
"0000"
59+
60+
su := &ShallowUpdate{}
61+
err := su.Decode(bytes.NewBufferString(raw))
62+
c.Assert(err, NotNil)
63+
}

plumbing/protocol/packp/srvresp.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package packp
2+
3+
import (
4+
"bytes"
5+
"errors"
6+
"fmt"
7+
"io"
8+
9+
"gopkg.in/src-d/go-git.v4/plumbing"
10+
"gopkg.in/src-d/go-git.v4/plumbing/format/pktline"
11+
)
12+
13+
const ackLineLen = 44
14+
15+
// ServerResponse object acknowledgement from upload-pack service
16+
// TODO: implement support for multi_ack or multi_ack_detailed responses
17+
type ServerResponse struct {
18+
ACKs []plumbing.Hash
19+
}
20+
21+
// Decode decodes the response into the struct, isMultiACK should be true, if
22+
// the request was done with multi_ack or multi_ack_detailed capabilities
23+
func (r *ServerResponse) Decode(reader io.Reader, isMultiACK bool) error {
24+
if isMultiACK {
25+
return errors.New("multi_ack and multi_ack_detailed are not supported")
26+
}
27+
28+
s := pktline.NewScanner(reader)
29+
30+
for s.Scan() {
31+
line := s.Bytes()
32+
33+
if err := r.decodeLine(line); err != nil {
34+
return err
35+
}
36+
37+
if !isMultiACK {
38+
break
39+
}
40+
}
41+
42+
return s.Err()
43+
}
44+
45+
func (r *ServerResponse) decodeLine(line []byte) error {
46+
if len(line) == 0 {
47+
return fmt.Errorf("unexpected flush")
48+
}
49+
50+
if bytes.Compare(line[0:3], ack) == 0 {
51+
return r.decodeACKLine(line)
52+
}
53+
54+
if bytes.Compare(line[0:3], nak) == 0 {
55+
return nil
56+
}
57+
58+
return fmt.Errorf("unexpected content %q", string(line))
59+
}
60+
61+
func (r *ServerResponse) decodeACKLine(line []byte) error {
62+
if len(line) < ackLineLen {
63+
return fmt.Errorf("malformed ACK %q", line)
64+
}
65+
66+
sp := bytes.Index(line, []byte(" "))
67+
h := plumbing.NewHash(string(line[sp+1 : sp+41]))
68+
r.ACKs = append(r.ACKs, h)
69+
return nil
70+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package packp
2+
3+
import (
4+
"bytes"
5+
6+
"gopkg.in/src-d/go-git.v4/plumbing"
7+
8+
. "gopkg.in/check.v1"
9+
)
10+
11+
type ServerResponseSuite struct{}
12+
13+
var _ = Suite(&ServerResponseSuite{})
14+
15+
func (s *ServerResponseSuite) TestDecodeNAK(c *C) {
16+
raw := "0008NAK\n"
17+
18+
sr := &ServerResponse{}
19+
err := sr.Decode(bytes.NewBufferString(raw), false)
20+
c.Assert(err, IsNil)
21+
22+
c.Assert(sr.ACKs, HasLen, 0)
23+
}
24+
25+
func (s *ServerResponseSuite) TestDecodeACK(c *C) {
26+
raw := "0031ACK 6ecf0ef2c2dffb796033e5a02219af86ec6584e5\n"
27+
28+
sr := &ServerResponse{}
29+
err := sr.Decode(bytes.NewBufferString(raw), false)
30+
c.Assert(err, IsNil)
31+
32+
c.Assert(sr.ACKs, HasLen, 1)
33+
c.Assert(sr.ACKs[0], Equals, plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"))
34+
}
35+
36+
func (s *ServerResponseSuite) TestDecodeMalformed(c *C) {
37+
raw := "0029ACK 6ecf0ef2c2dffb796033e5a02219af86ec6584e\n"
38+
39+
sr := &ServerResponse{}
40+
err := sr.Decode(bytes.NewBufferString(raw), false)
41+
c.Assert(err, NotNil)
42+
}
43+
44+
func (s *ServerResponseSuite) TestDecodeMultiACK(c *C) {
45+
sr := &ServerResponse{}
46+
err := sr.Decode(bytes.NewBuffer(nil), true)
47+
c.Assert(err, NotNil)
48+
}

plumbing/protocol/packp/ulreq.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ type UploadRequest struct {
2525
// DepthCommit, DepthSince and DepthReference.
2626
type Depth interface {
2727
isDepth()
28+
IsZero() bool
2829
}
2930

3031
// DepthCommits values stores the maximum number of requested commits in
@@ -34,16 +35,28 @@ type DepthCommits int
3435

3536
func (d DepthCommits) isDepth() {}
3637

38+
func (d DepthCommits) IsZero() bool {
39+
return d == 0
40+
}
41+
3742
// DepthSince values requests only commits newer than the specified time.
3843
type DepthSince time.Time
3944

4045
func (d DepthSince) isDepth() {}
4146

47+
func (d DepthSince) IsZero() bool {
48+
return time.Time(d).IsZero()
49+
}
50+
4251
// DepthReference requests only commits not to found in the specified reference.
4352
type DepthReference string
4453

4554
func (d DepthReference) isDepth() {}
4655

56+
func (d DepthReference) IsZero() bool {
57+
return string(d) == ""
58+
}
59+
4760
// NewUploadRequest returns a pointer to a new UploadRequest value, ready to be
4861
// used. It has no capabilities, wants or shallows and an infinite depth. Please
4962
// note that to encode an upload-request it has to have at least one wanted hash.

plumbing/protocol/packp/ulreq_encode_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ import (
66

77
"gopkg.in/src-d/go-git.v4/plumbing"
88
"gopkg.in/src-d/go-git.v4/plumbing/format/pktline"
9+
"gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/capability"
910

1011
. "gopkg.in/check.v1"
11-
"gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/capability"
1212
)
1313

1414
type UlReqEncodeSuite struct{}

0 commit comments

Comments
 (0)