aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common_test.go23
-rw-r--r--plumbing/protocol/packp/advrefs.go69
-rw-r--r--plumbing/protocol/packp/advrefs_decode.go51
-rw-r--r--plumbing/protocol/packp/advrefs_decode_test.go (renamed from plumbing/protocol/packp/advrefs_decoder_test.go)16
-rw-r--r--plumbing/protocol/packp/advrefs_encode.go (renamed from plumbing/protocol/packp/advrefs_encoder.go)37
-rw-r--r--plumbing/protocol/packp/advrefs_encode_test.go (renamed from plumbing/protocol/packp/advrefs_encoder_test.go)4
-rw-r--r--plumbing/protocol/packp/advrefs_test.go16
-rw-r--r--plumbing/protocol/packp/ulreq.go16
-rw-r--r--plumbing/protocol/packp/ulreq_decode.go (renamed from plumbing/protocol/packp/ulreq_decoder.go)47
-rw-r--r--plumbing/protocol/packp/ulreq_decode_test.go (renamed from plumbing/protocol/packp/ulreq_decoder_test.go)14
-rw-r--r--plumbing/protocol/packp/ulreq_encode.go (renamed from plumbing/protocol/packp/ulreq_encoder.go)37
-rw-r--r--plumbing/protocol/packp/ulreq_encode_test.go (renamed from plumbing/protocol/packp/ulreq_encoder_test.go)32
-rw-r--r--plumbing/protocol/packp/ulreq_test.go8
-rw-r--r--plumbing/protocol/packp/upload_pack_request.go75
-rw-r--r--plumbing/protocol/packp/upload_pack_request_test.go33
-rw-r--r--plumbing/transport/common.go7
-rw-r--r--plumbing/transport/fetch_pack.go177
-rw-r--r--plumbing/transport/fetch_pack_test.go119
-rw-r--r--plumbing/transport/http/fetch_pack.go49
-rw-r--r--plumbing/transport/http/fetch_pack_test.go21
-rw-r--r--plumbing/transport/http/send_pack.go6
-rw-r--r--plumbing/transport/ssh/fetch_pack.go44
-rw-r--r--plumbing/transport/ssh/send_pack.go4
-rw-r--r--plumbing/transport/test/common.go13
-rw-r--r--remote.go56
-rw-r--r--remote_test.go12
-rw-r--r--repository.go11
27 files changed, 465 insertions, 532 deletions
diff --git a/common_test.go b/common_test.go
index 62896a1..be86b4e 100644
--- a/common_test.go
+++ b/common_test.go
@@ -93,8 +93,7 @@ func (c *MockFetchPackSession) SetAuth(auth transport.AuthMethod) error {
return nil
}
-func (c *MockFetchPackSession) AdvertisedReferences() (
- *transport.UploadPackInfo, error) {
+func (c *MockFetchPackSession) AdvertisedReferences() (*packp.AdvRefs, error) {
h := fixtures.ByURL(c.endpoint.String()).One().Head
@@ -105,19 +104,19 @@ func (c *MockFetchPackSession) AdvertisedReferences() (
branch := plumbing.ReferenceName("refs/heads/branch")
tag := plumbing.ReferenceName("refs/tags/v1.0.0")
- return &transport.UploadPackInfo{
- Capabilities: cap,
- Refs: map[plumbing.ReferenceName]*plumbing.Reference{
- plumbing.HEAD: plumbing.NewSymbolicReference(plumbing.HEAD, ref),
- ref: plumbing.NewHashReference(ref, h),
- tag: plumbing.NewHashReference(tag, h),
- branch: plumbing.NewHashReference(branch, plumbing.NewHash("e8d3ffab552895c19b9fcf7aa264d277cde33881")),
- },
- }, nil
+ a := packp.NewAdvRefs()
+ a.Capabilities = cap
+ a.Head = &h
+ a.AddReference(plumbing.NewSymbolicReference(plumbing.HEAD, ref))
+ a.AddReference(plumbing.NewHashReference(ref, h))
+ a.AddReference(plumbing.NewHashReference(tag, h))
+ a.AddReference(plumbing.NewHashReference(branch, plumbing.NewHash("e8d3ffab552895c19b9fcf7aa264d277cde33881")))
+
+ return a, nil
}
func (c *MockFetchPackSession) FetchPack(
- r *transport.UploadPackRequest) (io.ReadCloser, error) {
+ r *packp.UploadPackRequest) (io.ReadCloser, error) {
f := fixtures.ByURL(c.endpoint.String())
diff --git a/plumbing/protocol/packp/advrefs.go b/plumbing/protocol/packp/advrefs.go
index c54f9d8..b36b180 100644
--- a/plumbing/protocol/packp/advrefs.go
+++ b/plumbing/protocol/packp/advrefs.go
@@ -1,7 +1,16 @@
package packp
import (
+ "fmt"
+ "strings"
+
"gopkg.in/src-d/go-git.v4/plumbing"
+ "gopkg.in/src-d/go-git.v4/plumbing/storer"
+ "gopkg.in/src-d/go-git.v4/storage/memory"
+)
+
+const (
+ symref = "symref"
)
// AdvRefs values represent the information transmitted on an
@@ -38,3 +47,63 @@ func NewAdvRefs() *AdvRefs {
Shallows: []plumbing.Hash{},
}
}
+
+func (a *AdvRefs) AddReference(r *plumbing.Reference) error {
+ switch r.Type() {
+ case plumbing.SymbolicReference:
+ v := fmt.Sprintf("%s:%s", r.Name().String(), r.Target().String())
+ a.Capabilities.Add(symref, v)
+ case plumbing.HashReference:
+ a.References[r.Name().String()] = r.Hash()
+ default:
+ return plumbing.ErrInvalidType
+ }
+
+ return nil
+}
+
+func (a *AdvRefs) AllReferences() (memory.ReferenceStorage, error) {
+ s := memory.ReferenceStorage{}
+ if err := addRefs(s, a); err != nil {
+ return s, plumbing.NewUnexpectedError(err)
+ }
+
+ return s, nil
+}
+
+func addRefs(s storer.ReferenceStorer, ar *AdvRefs) error {
+ for name, hash := range ar.References {
+ ref := plumbing.NewReferenceFromStrings(name, hash.String())
+ if err := s.SetReference(ref); err != nil {
+ return err
+ }
+ }
+
+ return addSymbolicRefs(s, ar)
+}
+
+func addSymbolicRefs(s storer.ReferenceStorer, ar *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)
+ if err := s.SetReference(ref); err != nil {
+ return nil
+ }
+ }
+
+ return nil
+}
+
+func hasSymrefs(ar *AdvRefs) bool {
+ return ar.Capabilities.Supports(symref)
+}
diff --git a/plumbing/protocol/packp/advrefs_decode.go b/plumbing/protocol/packp/advrefs_decode.go
index df824a9..8d37066 100644
--- a/plumbing/protocol/packp/advrefs_decode.go
+++ b/plumbing/protocol/packp/advrefs_decode.go
@@ -11,8 +11,14 @@ import (
"gopkg.in/src-d/go-git.v4/plumbing/format/pktline"
)
-// A AdvRefsDecoder reads and decodes AdvRef values from an input stream.
-type AdvRefsDecoder struct {
+// Decode reads the next advertised-refs message form its input and
+// stores it in the AdvRefs.
+func (a *AdvRefs) Decode(r io.Reader) error {
+ d := newAdvRefsDecoder(r)
+ return d.Decode(a)
+}
+
+type advRefsDecoder struct {
s *pktline.Scanner // a pkt-line scanner from the input stream
line []byte // current pkt-line contents, use parser.nextLine() to make it advance
nLine int // current pkt-line number for debugging, begins at 1
@@ -21,21 +27,16 @@ type AdvRefsDecoder struct {
data *AdvRefs // parsed data is stored here
}
-// ErrEmpty is returned by Decode when there was no advertised-message at all
-var ErrEmpty = errors.New("empty advertised-ref message")
+// ErrEmptyAdvRefs is returned by Decode when there was no advertised-message at all
+var ErrEmptyAdvRefs = errors.New("empty advertised-ref message")
-// NewAdvRefsDecoder returns a new decoder that reads from r.
-//
-// Will not read more data from r than necessary.
-func NewAdvRefsDecoder(r io.Reader) *AdvRefsDecoder {
- return &AdvRefsDecoder{
+func newAdvRefsDecoder(r io.Reader) *advRefsDecoder {
+ return &advRefsDecoder{
s: pktline.NewScanner(r),
}
}
-// Decode reads the next advertised-refs message form its input and
-// stores it in the value pointed to by v.
-func (d *AdvRefsDecoder) Decode(v *AdvRefs) error {
+func (d *advRefsDecoder) Decode(v *AdvRefs) error {
d.data = v
for state := decodePrefix; state != nil; {
@@ -45,10 +46,10 @@ func (d *AdvRefsDecoder) Decode(v *AdvRefs) error {
return d.err
}
-type decoderStateFn func(*AdvRefsDecoder) decoderStateFn
+type decoderStateFn func(*advRefsDecoder) decoderStateFn
// fills out the parser stiky error
-func (d *AdvRefsDecoder) error(format string, a ...interface{}) {
+func (d *advRefsDecoder) error(format string, a ...interface{}) {
d.err = fmt.Errorf("pkt-line %d: %s", d.nLine,
fmt.Sprintf(format, a...))
}
@@ -57,7 +58,7 @@ func (d *AdvRefsDecoder) error(format string, a ...interface{}) {
// p.line and increments p.nLine. A successful invocation returns true,
// otherwise, false is returned and the sticky error is filled out
// accordingly. Trims eols at the end of the payloads.
-func (d *AdvRefsDecoder) nextLine() bool {
+func (d *advRefsDecoder) nextLine() bool {
d.nLine++
if !d.s.Scan() {
@@ -66,7 +67,7 @@ func (d *AdvRefsDecoder) nextLine() bool {
}
if d.nLine == 1 {
- d.err = ErrEmpty
+ d.err = ErrEmptyAdvRefs
return false
}
@@ -81,14 +82,14 @@ func (d *AdvRefsDecoder) nextLine() bool {
}
// The HTTP smart prefix is often followed by a flush-pkt.
-func decodePrefix(d *AdvRefsDecoder) decoderStateFn {
+func decodePrefix(d *advRefsDecoder) decoderStateFn {
if ok := d.nextLine(); !ok {
return nil
}
// If the repository is empty, we receive a flush here (SSH).
if isFlush(d.line) {
- d.err = ErrEmpty
+ d.err = ErrEmptyAdvRefs
return nil
}
@@ -122,10 +123,10 @@ func isFlush(payload []byte) bool {
// If the first hash is zero, then a no-refs is comming. Otherwise, a
// list-of-refs is comming, and the hash will be followed by the first
// advertised ref.
-func decodeFirstHash(p *AdvRefsDecoder) decoderStateFn {
+func decodeFirstHash(p *advRefsDecoder) decoderStateFn {
// If the repository is empty, we receive a flush here (HTTP).
if isFlush(p.line) {
- p.err = ErrEmpty
+ p.err = ErrEmptyAdvRefs
return nil
}
@@ -149,7 +150,7 @@ func decodeFirstHash(p *AdvRefsDecoder) decoderStateFn {
}
// Skips SP "capabilities^{}" NUL
-func decodeSkipNoRefs(p *AdvRefsDecoder) decoderStateFn {
+func decodeSkipNoRefs(p *advRefsDecoder) decoderStateFn {
if len(p.line) < len(noHeadMark) {
p.error("too short zero-id ref")
return nil
@@ -166,7 +167,7 @@ func decodeSkipNoRefs(p *AdvRefsDecoder) decoderStateFn {
}
// decode the refname, expectes SP refname NULL
-func decodeFirstRef(l *AdvRefsDecoder) decoderStateFn {
+func decodeFirstRef(l *advRefsDecoder) decoderStateFn {
if len(l.line) < 3 {
l.error("line too short after hash")
return nil
@@ -195,7 +196,7 @@ func decodeFirstRef(l *AdvRefsDecoder) decoderStateFn {
return decodeCaps
}
-func decodeCaps(p *AdvRefsDecoder) decoderStateFn {
+func decodeCaps(p *advRefsDecoder) decoderStateFn {
if len(p.line) == 0 {
return decodeOtherRefs
}
@@ -210,7 +211,7 @@ func decodeCaps(p *AdvRefsDecoder) decoderStateFn {
// The refs are either tips (obj-id SP refname) or a peeled (obj-id SP refname^{}).
// If there are no refs, then there might be a shallow or flush-ptk.
-func decodeOtherRefs(p *AdvRefsDecoder) decoderStateFn {
+func decodeOtherRefs(p *advRefsDecoder) decoderStateFn {
if ok := p.nextLine(); !ok {
return nil
}
@@ -253,7 +254,7 @@ func readRef(data []byte) (string, plumbing.Hash, error) {
}
// Keeps reading shallows until a flush-pkt is found
-func decodeShallow(p *AdvRefsDecoder) decoderStateFn {
+func decodeShallow(p *advRefsDecoder) decoderStateFn {
if !bytes.HasPrefix(p.line, shallow) {
p.error("malformed shallow prefix, found %q... instead", p.line[:len(shallow)])
return nil
diff --git a/plumbing/protocol/packp/advrefs_decoder_test.go b/plumbing/protocol/packp/advrefs_decode_test.go
index ee72d56..2b3da72 100644
--- a/plumbing/protocol/packp/advrefs_decoder_test.go
+++ b/plumbing/protocol/packp/advrefs_decode_test.go
@@ -18,10 +18,10 @@ var _ = Suite(&AdvRefsDecodeSuite{})
func (s *AdvRefsDecodeSuite) TestEmpty(c *C) {
ar := NewAdvRefs()
var buf bytes.Buffer
- d := NewAdvRefsDecoder(&buf)
+ d := newAdvRefsDecoder(&buf)
err := d.Decode(ar)
- c.Assert(err, Equals, ErrEmpty)
+ c.Assert(err, Equals, ErrEmptyAdvRefs)
}
func (s *AdvRefsDecodeSuite) TestEmptyFlush(c *C) {
@@ -30,10 +30,10 @@ func (s *AdvRefsDecodeSuite) TestEmptyFlush(c *C) {
e := pktline.NewEncoder(&buf)
e.Flush()
- d := NewAdvRefsDecoder(&buf)
+ d := newAdvRefsDecoder(&buf)
err := d.Decode(ar)
- c.Assert(err, Equals, ErrEmpty)
+ c.Assert(err, Equals, ErrEmptyAdvRefs)
}
func (s *AdvRefsDecodeSuite) TestEmptyPrefixFlush(c *C) {
@@ -44,10 +44,10 @@ func (s *AdvRefsDecodeSuite) TestEmptyPrefixFlush(c *C) {
e.Flush()
e.Flush()
- d := NewAdvRefsDecoder(&buf)
+ d := newAdvRefsDecoder(&buf)
err := d.Decode(ar)
- c.Assert(err, Equals, ErrEmpty)
+ c.Assert(err, Equals, ErrEmptyAdvRefs)
}
func (s *AdvRefsDecodeSuite) TestShortForHash(c *C) {
@@ -61,7 +61,7 @@ func (s *AdvRefsDecodeSuite) TestShortForHash(c *C) {
func (s *AdvRefsDecodeSuite) testDecoderErrorMatches(c *C, input io.Reader, pattern string) {
ar := NewAdvRefs()
- d := NewAdvRefsDecoder(input)
+ d := newAdvRefsDecoder(input)
err := d.Decode(ar)
c.Assert(err, ErrorMatches, pattern)
@@ -92,7 +92,7 @@ func (s *AdvRefsDecodeSuite) testDecodeOK(c *C, payloads []string) *AdvRefs {
c.Assert(err, IsNil)
ar := NewAdvRefs()
- d := NewAdvRefsDecoder(&buf)
+ d := newAdvRefsDecoder(&buf)
err = d.Decode(ar)
c.Assert(err, IsNil)
diff --git a/plumbing/protocol/packp/advrefs_encoder.go b/plumbing/protocol/packp/advrefs_encode.go
index cdba188..3c5df19 100644
--- a/plumbing/protocol/packp/advrefs_encoder.go
+++ b/plumbing/protocol/packp/advrefs_encode.go
@@ -9,26 +9,29 @@ import (
"gopkg.in/src-d/go-git.v4/plumbing/format/pktline"
)
-// An AdvRefsEncoder writes AdvRefs values to an output stream.
-type AdvRefsEncoder struct {
+// Encode writes the AdvRefs encoding to a writer.
+//
+// All the payloads will end with a newline character. Capabilities,
+// references and shallows are writen in alphabetical order, except for
+// peeled references that always follow their corresponding references.
+func (a *AdvRefs) Encode(w io.Writer) error {
+ e := newAdvRefsEncoder(w)
+ return e.Encode(a)
+}
+
+type advRefsEncoder struct {
data *AdvRefs // data to encode
pe *pktline.Encoder // where to write the encoded data
err error // sticky error
}
-// NewAdvRefsEncoder returns a new encoder that writes to w.
-func NewAdvRefsEncoder(w io.Writer) *AdvRefsEncoder {
- return &AdvRefsEncoder{
+func newAdvRefsEncoder(w io.Writer) *advRefsEncoder {
+ return &advRefsEncoder{
pe: pktline.NewEncoder(w),
}
}
-// Encode writes the AdvRefs encoding of v to the stream.
-//
-// All the payloads will end with a newline character. Capabilities,
-// references and shallows are writen in alphabetical order, except for
-// peeled references that always follow their corresponding references.
-func (e *AdvRefsEncoder) Encode(v *AdvRefs) error {
+func (e *advRefsEncoder) Encode(v *AdvRefs) error {
e.data = v
for state := encodePrefix; state != nil; {
@@ -38,9 +41,9 @@ func (e *AdvRefsEncoder) Encode(v *AdvRefs) error {
return e.err
}
-type encoderStateFn func(*AdvRefsEncoder) encoderStateFn
+type encoderStateFn func(*advRefsEncoder) encoderStateFn
-func encodePrefix(e *AdvRefsEncoder) encoderStateFn {
+func encodePrefix(e *advRefsEncoder) encoderStateFn {
for _, p := range e.data.Prefix {
if bytes.Equal(p, pktline.Flush) {
if e.err = e.pe.Flush(); e.err != nil {
@@ -58,7 +61,7 @@ func encodePrefix(e *AdvRefsEncoder) encoderStateFn {
// Adds the first pkt-line payload: head hash, head ref and capabilities.
// Also handle the special case when no HEAD ref is found.
-func encodeFirstLine(e *AdvRefsEncoder) encoderStateFn {
+func encodeFirstLine(e *advRefsEncoder) encoderStateFn {
head := formatHead(e.data.Head)
separator := formatSeparator(e.data.Head)
capabilities := formatCaps(e.data.Capabilities)
@@ -98,7 +101,7 @@ func formatCaps(c *Capabilities) string {
// Adds the (sorted) refs: hash SP refname EOL
// and their peeled refs if any.
-func encodeRefs(e *AdvRefsEncoder) encoderStateFn {
+func encodeRefs(e *advRefsEncoder) encoderStateFn {
refs := sortRefs(e.data.References)
for _, r := range refs {
hash, _ := e.data.References[r]
@@ -127,7 +130,7 @@ func sortRefs(m map[string]plumbing.Hash) []string {
}
// Adds the (sorted) shallows: "shallow" SP hash EOL
-func encodeShallow(e *AdvRefsEncoder) encoderStateFn {
+func encodeShallow(e *advRefsEncoder) encoderStateFn {
sorted := sortShallows(e.data.Shallows)
for _, hash := range sorted {
if e.err = e.pe.Encodef("shallow %s\n", hash); e.err != nil {
@@ -148,7 +151,7 @@ func sortShallows(c []plumbing.Hash) []string {
return ret
}
-func encodeFlush(e *AdvRefsEncoder) encoderStateFn {
+func encodeFlush(e *advRefsEncoder) encoderStateFn {
e.err = e.pe.Flush()
return nil
}
diff --git a/plumbing/protocol/packp/advrefs_encoder_test.go b/plumbing/protocol/packp/advrefs_encode_test.go
index 222a267..207ce58 100644
--- a/plumbing/protocol/packp/advrefs_encoder_test.go
+++ b/plumbing/protocol/packp/advrefs_encode_test.go
@@ -16,7 +16,7 @@ var _ = Suite(&AdvRefsEncodeSuite{})
func testEncode(c *C, input *AdvRefs, expected []byte) {
var buf bytes.Buffer
- e := NewAdvRefsEncoder(&buf)
+ e := newAdvRefsEncoder(&buf)
err := e.Encode(input)
c.Assert(err, IsNil)
obtained := buf.Bytes()
@@ -231,7 +231,7 @@ func (s *AdvRefsEncodeSuite) TestErrorTooLong(c *C) {
}
var buf bytes.Buffer
- e := NewAdvRefsEncoder(&buf)
+ e := newAdvRefsEncoder(&buf)
err := e.Encode(ar)
c.Assert(err, ErrorMatches, ".*payload is too long.*")
}
diff --git a/plumbing/protocol/packp/advrefs_test.go b/plumbing/protocol/packp/advrefs_test.go
index 1a696d4..6d9f488 100644
--- a/plumbing/protocol/packp/advrefs_test.go
+++ b/plumbing/protocol/packp/advrefs_test.go
@@ -44,14 +44,10 @@ func (s *SuiteDecodeEncode) test(c *C, in []string, exp []string) {
var obtained []byte
{
ar := packp.NewAdvRefs()
- d := packp.NewAdvRefsDecoder(input)
- err = d.Decode(ar)
- c.Assert(err, IsNil)
+ c.Assert(ar.Decode(input), IsNil)
var buf bytes.Buffer
- e := packp.NewAdvRefsEncoder(&buf)
- err := e.Encode(ar)
- c.Assert(err, IsNil)
+ c.Assert(ar.Encode(&buf), IsNil)
obtained = buf.Bytes()
}
@@ -258,12 +254,9 @@ func ExampleDecoder_Decode() {
// Use the raw message as our input.
input := strings.NewReader(raw)
- // Create a Decoder reading from our input.
- d := packp.NewAdvRefsDecoder(input)
-
// Decode the input into a newly allocated AdvRefs value.
ar := packp.NewAdvRefs()
- _ = d.Decode(ar) // error check ignored for brevity
+ _ = ar.Decode(input) // error check ignored for brevity
// Do something interesting with the AdvRefs, e.g. print its contents.
fmt.Println("head =", ar.Head)
@@ -303,8 +296,7 @@ func ExampleEncoder_Encode() {
// You can encode into stdout too, but you will not be able
// see the '\x00' after "HEAD".
var buf bytes.Buffer
- e := packp.NewAdvRefsEncoder(&buf)
- _ = e.Encode(ar) // error checks ignored for brevity
+ _ = ar.Encode(&buf) // error checks ignored for brevity
// Print the contents of the buffer as a quoted string.
// Printing is as a non-quoted string will be prettier but you
diff --git a/plumbing/protocol/packp/ulreq.go b/plumbing/protocol/packp/ulreq.go
index 5870001..6ec5b96 100644
--- a/plumbing/protocol/packp/ulreq.go
+++ b/plumbing/protocol/packp/ulreq.go
@@ -6,10 +6,11 @@ import (
"gopkg.in/src-d/go-git.v4/plumbing"
)
-// UlReq values represent the information transmitted on a
+// 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.
-type UlReq struct {
+// This is a low level type, use UploadPackRequest instead.
+type UploadRequest struct {
Capabilities *Capabilities
Wants []plumbing.Hash
Shallows []plumbing.Hash
@@ -39,15 +40,20 @@ type DepthReference string
func (d DepthReference) isDepth() {}
-// NewUlReq returns a pointer to a new UlReq value, ready to be used. It has
+// NewUploadRequest returns a pointer to a new UlReq value, ready to be used. It has
// no capabilities, wants or shallows and an infinite depth. Please
// note that to encode an upload-request it has to have at least one
// wanted hash.
-func NewUlReq() *UlReq {
- return &UlReq{
+func NewUploadRequest() *UploadRequest {
+ return &UploadRequest{
Capabilities: NewCapabilities(),
Wants: []plumbing.Hash{},
Shallows: []plumbing.Hash{},
Depth: DepthCommits(0),
}
}
+
+// Want adds a hash reference to the 'wants' list.
+func (r *UploadRequest) Want(h ...plumbing.Hash) {
+ r.Wants = append(r.Wants, h...)
+}
diff --git a/plumbing/protocol/packp/ulreq_decoder.go b/plumbing/protocol/packp/ulreq_decode.go
index 67ba479..0124cd0 100644
--- a/plumbing/protocol/packp/ulreq_decoder.go
+++ b/plumbing/protocol/packp/ulreq_decode.go
@@ -12,27 +12,28 @@ import (
"gopkg.in/src-d/go-git.v4/plumbing/format/pktline"
)
-// A UlReqDecoder reads and decodes AdvRef values from an input stream.
-type UlReqDecoder struct {
+// Decode reads the next upload-request form its input and
+// stores it in the UploadRequest.
+func (u *UploadRequest) Decode(r io.Reader) error {
+ d := newUlReqDecoder(r)
+ return d.Decode(u)
+}
+
+type ulReqDecoder struct {
s *pktline.Scanner // a pkt-line scanner from the input stream
line []byte // current pkt-line contents, use parser.nextLine() to make it advance
nLine int // current pkt-line number for debugging, begins at 1
err error // sticky error, use the parser.error() method to fill this out
- data *UlReq // parsed data is stored here
+ data *UploadRequest // parsed data is stored here
}
-// NewUlReqDecoder returns a new decoder that reads from r.
-//
-// Will not read more data from r than necessary.
-func NewUlReqDecoder(r io.Reader) *UlReqDecoder {
- return &UlReqDecoder{
+func newUlReqDecoder(r io.Reader) *ulReqDecoder {
+ return &ulReqDecoder{
s: pktline.NewScanner(r),
}
}
-// Decode reads the next upload-request form its input and
-// stores it in the value pointed to by v.
-func (d *UlReqDecoder) Decode(v *UlReq) error {
+func (d *ulReqDecoder) Decode(v *UploadRequest) error {
d.data = v
for state := d.decodeFirstWant; state != nil; {
@@ -43,7 +44,7 @@ func (d *UlReqDecoder) Decode(v *UlReq) error {
}
// fills out the parser stiky error
-func (d *UlReqDecoder) error(format string, a ...interface{}) {
+func (d *ulReqDecoder) error(format string, a ...interface{}) {
d.err = fmt.Errorf("pkt-line %d: %s", d.nLine,
fmt.Sprintf(format, a...))
}
@@ -52,7 +53,7 @@ func (d *UlReqDecoder) error(format string, a ...interface{}) {
// p.line and increments p.nLine. A successful invocation returns true,
// otherwise, false is returned and the sticky error is filled out
// accordingly. Trims eols at the end of the payloads.
-func (d *UlReqDecoder) nextLine() bool {
+func (d *ulReqDecoder) nextLine() bool {
d.nLine++
if !d.s.Scan() {
@@ -71,7 +72,7 @@ func (d *UlReqDecoder) nextLine() bool {
}
// Expected format: want <hash>[ capabilities]
-func (d *UlReqDecoder) decodeFirstWant() stateFn {
+func (d *ulReqDecoder) decodeFirstWant() stateFn {
if ok := d.nextLine(); !ok {
return nil
}
@@ -91,7 +92,7 @@ func (d *UlReqDecoder) decodeFirstWant() stateFn {
return d.decodeCaps
}
-func (d *UlReqDecoder) readHash() (plumbing.Hash, bool) {
+func (d *ulReqDecoder) readHash() (plumbing.Hash, bool) {
if len(d.line) < hashSize {
d.err = fmt.Errorf("malformed hash: %v", d.line)
return plumbing.ZeroHash, false
@@ -108,7 +109,7 @@ func (d *UlReqDecoder) readHash() (plumbing.Hash, bool) {
}
// Expected format: sp cap1 sp cap2 sp cap3...
-func (d *UlReqDecoder) decodeCaps() stateFn {
+func (d *ulReqDecoder) decodeCaps() stateFn {
if len(d.line) == 0 {
return d.decodeOtherWants
}
@@ -124,7 +125,7 @@ func (d *UlReqDecoder) decodeCaps() stateFn {
}
// Expected format: want <hash>
-func (d *UlReqDecoder) decodeOtherWants() stateFn {
+func (d *ulReqDecoder) decodeOtherWants() stateFn {
if ok := d.nextLine(); !ok {
return nil
}
@@ -157,7 +158,7 @@ func (d *UlReqDecoder) decodeOtherWants() stateFn {
}
// Expected format: shallow <hash>
-func (d *UlReqDecoder) decodeShallow() stateFn {
+func (d *ulReqDecoder) decodeShallow() stateFn {
if bytes.HasPrefix(d.line, deepen) {
return d.decodeDeepen
}
@@ -186,7 +187,7 @@ func (d *UlReqDecoder) decodeShallow() stateFn {
}
// Expected format: deepen <n> / deepen-since <ul> / deepen-not <ref>
-func (d *UlReqDecoder) decodeDeepen() stateFn {
+func (d *ulReqDecoder) decodeDeepen() stateFn {
if bytes.HasPrefix(d.line, deepenCommits) {
return d.decodeDeepenCommits
}
@@ -207,7 +208,7 @@ func (d *UlReqDecoder) decodeDeepen() stateFn {
return nil
}
-func (d *UlReqDecoder) decodeDeepenCommits() stateFn {
+func (d *ulReqDecoder) decodeDeepenCommits() stateFn {
d.line = bytes.TrimPrefix(d.line, deepenCommits)
var n int
@@ -223,7 +224,7 @@ func (d *UlReqDecoder) decodeDeepenCommits() stateFn {
return d.decodeFlush
}
-func (d *UlReqDecoder) decodeDeepenSince() stateFn {
+func (d *ulReqDecoder) decodeDeepenSince() stateFn {
d.line = bytes.TrimPrefix(d.line, deepenSince)
var secs int64
@@ -237,7 +238,7 @@ func (d *UlReqDecoder) decodeDeepenSince() stateFn {
return d.decodeFlush
}
-func (d *UlReqDecoder) decodeDeepenReference() stateFn {
+func (d *ulReqDecoder) decodeDeepenReference() stateFn {
d.line = bytes.TrimPrefix(d.line, deepenReference)
d.data.Depth = DepthReference(string(d.line))
@@ -245,7 +246,7 @@ func (d *UlReqDecoder) decodeDeepenReference() stateFn {
return d.decodeFlush
}
-func (d *UlReqDecoder) decodeFlush() stateFn {
+func (d *ulReqDecoder) decodeFlush() stateFn {
if ok := d.nextLine(); !ok {
return nil
}
diff --git a/plumbing/protocol/packp/ulreq_decoder_test.go b/plumbing/protocol/packp/ulreq_decode_test.go
index e90962a..eb12c90 100644
--- a/plumbing/protocol/packp/ulreq_decoder_test.go
+++ b/plumbing/protocol/packp/ulreq_decode_test.go
@@ -17,9 +17,9 @@ type UlReqDecodeSuite struct{}
var _ = Suite(&UlReqDecodeSuite{})
func (s *UlReqDecodeSuite) TestEmpty(c *C) {
- ur := NewUlReq()
+ ur := NewUploadRequest()
var buf bytes.Buffer
- d := NewUlReqDecoder(&buf)
+ d := newUlReqDecoder(&buf)
err := d.Decode(ur)
c.Assert(err, ErrorMatches, "pkt-line 1: EOF")
@@ -35,8 +35,8 @@ func (s *UlReqDecodeSuite) TestNoWant(c *C) {
}
func (s *UlReqDecodeSuite) testDecoderErrorMatches(c *C, input io.Reader, pattern string) {
- ur := NewUlReq()
- d := NewUlReqDecoder(input)
+ ur := NewUploadRequest()
+ d := newUlReqDecoder(input)
err := d.Decode(ur)
c.Assert(err, ErrorMatches, pattern)
@@ -63,14 +63,14 @@ func (s *UlReqDecodeSuite) TestWantOK(c *C) {
})
}
-func (s *UlReqDecodeSuite) testDecodeOK(c *C, payloads []string) *UlReq {
+func (s *UlReqDecodeSuite) testDecodeOK(c *C, payloads []string) *UploadRequest {
var buf bytes.Buffer
e := pktline.NewEncoder(&buf)
err := e.EncodeString(payloads...)
c.Assert(err, IsNil)
- ur := NewUlReq()
- d := NewUlReqDecoder(&buf)
+ ur := NewUploadRequest()
+ d := newUlReqDecoder(&buf)
err = d.Decode(ur)
c.Assert(err, IsNil)
diff --git a/plumbing/protocol/packp/ulreq_encoder.go b/plumbing/protocol/packp/ulreq_encode.go
index 9ebc4b5..b422a5f 100644
--- a/plumbing/protocol/packp/ulreq_encoder.go
+++ b/plumbing/protocol/packp/ulreq_encode.go
@@ -10,27 +10,30 @@ import (
"gopkg.in/src-d/go-git.v4/plumbing/format/pktline"
)
-// An UlReqEncoder writes UlReq values to an output stream.
-type UlReqEncoder struct {
+// Encode writes the UlReq encoding of u to the stream.
+//
+// All the payloads will end with a newline character. Wants and
+// shallows are sorted alphabetically. A depth of 0 means no depth
+// request is sent.
+func (u *UploadRequest) Encode(w io.Writer) error {
+ e := newUlReqEncoder(w)
+ return e.Encode(u)
+}
+
+type ulReqEncoder struct {
pe *pktline.Encoder // where to write the encoded data
- data *UlReq // the data to encode
+ data *UploadRequest // the data to encode
sortedWants []string
err error // sticky error
}
-// NewUlReqEncoder returns a new encoder that writes to w.
-func NewUlReqEncoder(w io.Writer) *UlReqEncoder {
- return &UlReqEncoder{
+func newUlReqEncoder(w io.Writer) *ulReqEncoder {
+ return &ulReqEncoder{
pe: pktline.NewEncoder(w),
}
}
-// Encode writes the UlReq encoding of v to the stream.
-//
-// All the payloads will end with a newline character. Wants and
-// shallows are sorted alphabetically. A depth of 0 means no depth
-// request is sent.
-func (e *UlReqEncoder) Encode(v *UlReq) error {
+func (e *ulReqEncoder) Encode(v *UploadRequest) error {
if len(v.Wants) == 0 {
return fmt.Errorf("empty wants provided")
}
@@ -55,7 +58,7 @@ func sortHashes(list []plumbing.Hash) []string {
return sorted
}
-func (e *UlReqEncoder) encodeFirstWant() stateFn {
+func (e *ulReqEncoder) encodeFirstWant() stateFn {
var err error
if e.data.Capabilities.IsEmpty() {
err = e.pe.Encodef("want %s\n", e.sortedWants[0])
@@ -75,7 +78,7 @@ func (e *UlReqEncoder) encodeFirstWant() stateFn {
return e.encodeAditionalWants
}
-func (e *UlReqEncoder) encodeAditionalWants() stateFn {
+func (e *ulReqEncoder) encodeAditionalWants() stateFn {
for _, w := range e.sortedWants[1:] {
if err := e.pe.Encodef("want %s\n", w); err != nil {
e.err = fmt.Errorf("encoding want %q: %s", w, err)
@@ -86,7 +89,7 @@ func (e *UlReqEncoder) encodeAditionalWants() stateFn {
return e.encodeShallows
}
-func (e *UlReqEncoder) encodeShallows() stateFn {
+func (e *ulReqEncoder) encodeShallows() stateFn {
sorted := sortHashes(e.data.Shallows)
for _, s := range sorted {
if err := e.pe.Encodef("shallow %s\n", s); err != nil {
@@ -98,7 +101,7 @@ func (e *UlReqEncoder) encodeShallows() stateFn {
return e.encodeDepth
}
-func (e *UlReqEncoder) encodeDepth() stateFn {
+func (e *ulReqEncoder) encodeDepth() stateFn {
switch depth := e.data.Depth.(type) {
case DepthCommits:
if depth != 0 {
@@ -128,7 +131,7 @@ func (e *UlReqEncoder) encodeDepth() stateFn {
return e.encodeFlush
}
-func (e *UlReqEncoder) encodeFlush() stateFn {
+func (e *ulReqEncoder) encodeFlush() stateFn {
if err := e.pe.Flush(); err != nil {
e.err = fmt.Errorf("encoding flush-pkt: %s", err)
return nil
diff --git a/plumbing/protocol/packp/ulreq_encoder_test.go b/plumbing/protocol/packp/ulreq_encode_test.go
index fb83653..1eb3175 100644
--- a/plumbing/protocol/packp/ulreq_encoder_test.go
+++ b/plumbing/protocol/packp/ulreq_encode_test.go
@@ -14,9 +14,9 @@ type UlReqEncodeSuite struct{}
var _ = Suite(&UlReqEncodeSuite{})
-func testUlReqEncode(c *C, ur *UlReq, expectedPayloads []string) {
+func testUlReqEncode(c *C, ur *UploadRequest, expectedPayloads []string) {
var buf bytes.Buffer
- e := NewUlReqEncoder(&buf)
+ e := newUlReqEncoder(&buf)
err := e.Encode(ur)
c.Assert(err, IsNil)
@@ -29,23 +29,23 @@ func testUlReqEncode(c *C, ur *UlReq, expectedPayloads []string) {
c.Assert(obtained, DeepEquals, expected, comment)
}
-func testUlReqEncodeError(c *C, ur *UlReq, expectedErrorRegEx string) {
+func testUlReqEncodeError(c *C, ur *UploadRequest, expectedErrorRegEx string) {
var buf bytes.Buffer
- e := NewUlReqEncoder(&buf)
+ e := newUlReqEncoder(&buf)
err := e.Encode(ur)
c.Assert(err, ErrorMatches, expectedErrorRegEx)
}
func (s *UlReqEncodeSuite) TestZeroValue(c *C) {
- ur := NewUlReq()
+ ur := NewUploadRequest()
expectedErrorRegEx := ".*empty wants.*"
testUlReqEncodeError(c, ur, expectedErrorRegEx)
}
func (s *UlReqEncodeSuite) TestOneWant(c *C) {
- ur := NewUlReq()
+ ur := NewUploadRequest()
ur.Wants = append(ur.Wants, plumbing.NewHash("1111111111111111111111111111111111111111"))
expected := []string{
@@ -57,7 +57,7 @@ func (s *UlReqEncodeSuite) TestOneWant(c *C) {
}
func (s *UlReqEncodeSuite) TestOneWantWithCapabilities(c *C) {
- ur := NewUlReq()
+ ur := NewUploadRequest()
ur.Wants = append(ur.Wants, plumbing.NewHash("1111111111111111111111111111111111111111"))
ur.Capabilities.Add("sysref", "HEAD:/refs/heads/master")
ur.Capabilities.Add("multi_ack")
@@ -74,7 +74,7 @@ func (s *UlReqEncodeSuite) TestOneWantWithCapabilities(c *C) {
}
func (s *UlReqEncodeSuite) TestWants(c *C) {
- ur := NewUlReq()
+ ur := NewUploadRequest()
ur.Wants = append(ur.Wants, plumbing.NewHash("4444444444444444444444444444444444444444"))
ur.Wants = append(ur.Wants, plumbing.NewHash("1111111111111111111111111111111111111111"))
ur.Wants = append(ur.Wants, plumbing.NewHash("3333333333333333333333333333333333333333"))
@@ -94,7 +94,7 @@ func (s *UlReqEncodeSuite) TestWants(c *C) {
}
func (s *UlReqEncodeSuite) TestWantsWithCapabilities(c *C) {
- ur := NewUlReq()
+ ur := NewUploadRequest()
ur.Wants = append(ur.Wants, plumbing.NewHash("4444444444444444444444444444444444444444"))
ur.Wants = append(ur.Wants, plumbing.NewHash("1111111111111111111111111111111111111111"))
ur.Wants = append(ur.Wants, plumbing.NewHash("3333333333333333333333333333333333333333"))
@@ -120,7 +120,7 @@ func (s *UlReqEncodeSuite) TestWantsWithCapabilities(c *C) {
}
func (s *UlReqEncodeSuite) TestShallow(c *C) {
- ur := NewUlReq()
+ ur := NewUploadRequest()
ur.Wants = append(ur.Wants, plumbing.NewHash("1111111111111111111111111111111111111111"))
ur.Capabilities.Add("multi_ack")
ur.Shallows = append(ur.Shallows, plumbing.NewHash("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
@@ -135,7 +135,7 @@ func (s *UlReqEncodeSuite) TestShallow(c *C) {
}
func (s *UlReqEncodeSuite) TestManyShallows(c *C) {
- ur := NewUlReq()
+ ur := NewUploadRequest()
ur.Wants = append(ur.Wants, plumbing.NewHash("1111111111111111111111111111111111111111"))
ur.Capabilities.Add("multi_ack")
ur.Shallows = append(ur.Shallows, plumbing.NewHash("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"))
@@ -156,7 +156,7 @@ func (s *UlReqEncodeSuite) TestManyShallows(c *C) {
}
func (s *UlReqEncodeSuite) TestDepthCommits(c *C) {
- ur := NewUlReq()
+ ur := NewUploadRequest()
ur.Wants = append(ur.Wants, plumbing.NewHash("1111111111111111111111111111111111111111"))
ur.Depth = DepthCommits(1234)
@@ -170,7 +170,7 @@ func (s *UlReqEncodeSuite) TestDepthCommits(c *C) {
}
func (s *UlReqEncodeSuite) TestDepthSinceUTC(c *C) {
- ur := NewUlReq()
+ ur := NewUploadRequest()
ur.Wants = append(ur.Wants, plumbing.NewHash("1111111111111111111111111111111111111111"))
since := time.Date(2015, time.January, 2, 3, 4, 5, 0, time.UTC)
ur.Depth = DepthSince(since)
@@ -185,7 +185,7 @@ func (s *UlReqEncodeSuite) TestDepthSinceUTC(c *C) {
}
func (s *UlReqEncodeSuite) TestDepthSinceNonUTC(c *C) {
- ur := NewUlReq()
+ ur := NewUploadRequest()
ur.Wants = append(ur.Wants, plumbing.NewHash("1111111111111111111111111111111111111111"))
berlin, err := time.LoadLocation("Europe/Berlin")
c.Assert(err, IsNil)
@@ -204,7 +204,7 @@ func (s *UlReqEncodeSuite) TestDepthSinceNonUTC(c *C) {
}
func (s *UlReqEncodeSuite) TestDepthReference(c *C) {
- ur := NewUlReq()
+ ur := NewUploadRequest()
ur.Wants = append(ur.Wants, plumbing.NewHash("1111111111111111111111111111111111111111"))
ur.Depth = DepthReference("refs/heads/feature-foo")
@@ -218,7 +218,7 @@ func (s *UlReqEncodeSuite) TestDepthReference(c *C) {
}
func (s *UlReqEncodeSuite) TestAll(c *C) {
- ur := NewUlReq()
+ ur := NewUploadRequest()
ur.Wants = append(ur.Wants, plumbing.NewHash("4444444444444444444444444444444444444444"))
ur.Wants = append(ur.Wants, plumbing.NewHash("1111111111111111111111111111111111111111"))
ur.Wants = append(ur.Wants, plumbing.NewHash("3333333333333333333333333333333333333333"))
diff --git a/plumbing/protocol/packp/ulreq_test.go b/plumbing/protocol/packp/ulreq_test.go
index 19b6dd0..be02f9d 100644
--- a/plumbing/protocol/packp/ulreq_test.go
+++ b/plumbing/protocol/packp/ulreq_test.go
@@ -12,7 +12,7 @@ import (
func ExampleUlReqEncoder_Encode() {
// Create an empty UlReq with the contents you want...
- ur := NewUlReq()
+ ur := NewUploadRequest()
// Add a couple of wants
ur.Wants = append(ur.Wants, plumbing.NewHash("3333333333333333333333333333333333333333"))
@@ -32,7 +32,7 @@ func ExampleUlReqEncoder_Encode() {
ur.Depth = DepthSince(since)
// Create a new Encode for the stdout...
- e := NewUlReqEncoder(os.Stdout)
+ e := newUlReqEncoder(os.Stdout)
// ...and encode the upload-request to it.
_ = e.Encode(ur) // ignoring errors for brevity
// Output:
@@ -60,10 +60,10 @@ func ExampleUlReqDecoder_Decode() {
input := strings.NewReader(raw)
// Create the Decoder reading from our input.
- d := NewUlReqDecoder(input)
+ d := newUlReqDecoder(input)
// Decode the input into a newly allocated UlReq value.
- ur := NewUlReq()
+ ur := NewUploadRequest()
_ = d.Decode(ur) // error check ignored for brevity
// Do something interesting with the UlReq, e.g. print its contents.
diff --git a/plumbing/protocol/packp/upload_pack_request.go b/plumbing/protocol/packp/upload_pack_request.go
new file mode 100644
index 0000000..42033b1
--- /dev/null
+++ b/plumbing/protocol/packp/upload_pack_request.go
@@ -0,0 +1,75 @@
+package packp
+
+import (
+ "fmt"
+ "io"
+
+ "gopkg.in/src-d/go-git.v4/plumbing"
+ "gopkg.in/src-d/go-git.v4/plumbing/format/pktline"
+)
+
+// UploadHaves is a message to signal the references that a client has in a
+// upload-pack. Do not use this directly. Use UploadPackRequest request instead.
+type UploadHaves struct {
+ Haves []plumbing.Hash
+}
+
+// Encode encodes the UploadHaves into the Writer.
+func (u *UploadHaves) Encode(w io.Writer) error {
+ e := pktline.NewEncoder(w)
+ for _, have := range u.Haves {
+ if err := e.Encodef("have %s\n", have); err != nil {
+ return fmt.Errorf("sending haves for %q: %s", have, err)
+ }
+ }
+
+ if len(u.Haves) != 0 {
+ if err := e.Flush(); err != nil {
+ return fmt.Errorf("sending flush-pkt after haves: %s", err)
+ }
+ }
+
+ return nil
+}
+
+// Have adds a hash reference to the 'haves' list.
+func (r *UploadHaves) Have(h ...plumbing.Hash) {
+ r.Haves = append(r.Haves, h...)
+}
+
+// UploadPackRequest represents a upload-pack request.
+// Zero-value is not safe, use NewUploadPackRequest instead.
+type UploadPackRequest struct {
+ *UploadRequest
+ *UploadHaves
+}
+
+// NewUploadPackRequest creates a new UploadPackRequest and returns a pointer.
+func NewUploadPackRequest() *UploadPackRequest {
+ return &UploadPackRequest{
+ UploadHaves: &UploadHaves{},
+ UploadRequest: NewUploadRequest(),
+ }
+}
+
+func (r *UploadPackRequest) IsEmpty() bool {
+ return isSubset(r.Wants, r.Haves)
+}
+
+func isSubset(needle []plumbing.Hash, haystack []plumbing.Hash) bool {
+ for _, h := range needle {
+ found := false
+ for _, oh := range haystack {
+ if h == oh {
+ found = true
+ break
+ }
+ }
+
+ if !found {
+ return false
+ }
+ }
+
+ return true
+}
diff --git a/plumbing/protocol/packp/upload_pack_request_test.go b/plumbing/protocol/packp/upload_pack_request_test.go
new file mode 100644
index 0000000..f321736
--- /dev/null
+++ b/plumbing/protocol/packp/upload_pack_request_test.go
@@ -0,0 +1,33 @@
+package packp
+
+import (
+ "gopkg.in/src-d/go-git.v4/plumbing"
+
+ . "gopkg.in/check.v1"
+)
+
+type UploadPackRequestSuite struct{}
+
+var _ = Suite(&UploadPackRequestSuite{})
+
+func (s *UploadPackRequestSuite) TestUploadPackRequest_IsEmpty(c *C) {
+ r := NewUploadPackRequest()
+ r.Want(plumbing.NewHash("d82f291cde9987322c8a0c81a325e1ba6159684c"))
+ r.Want(plumbing.NewHash("2b41ef280fdb67a9b250678686a0c3e03b0a9989"))
+ r.Have(plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"))
+
+ c.Assert(r.IsEmpty(), Equals, false)
+
+ r = NewUploadPackRequest()
+ r.Want(plumbing.NewHash("d82f291cde9987322c8a0c81a325e1ba6159684c"))
+ r.Want(plumbing.NewHash("2b41ef280fdb67a9b250678686a0c3e03b0a9989"))
+ r.Have(plumbing.NewHash("d82f291cde9987322c8a0c81a325e1ba6159684c"))
+
+ c.Assert(r.IsEmpty(), Equals, false)
+
+ r = NewUploadPackRequest()
+ r.Want(plumbing.NewHash("d82f291cde9987322c8a0c81a325e1ba6159684c"))
+ r.Have(plumbing.NewHash("d82f291cde9987322c8a0c81a325e1ba6159684c"))
+
+ c.Assert(r.IsEmpty(), Equals, true)
+}
diff --git a/plumbing/transport/common.go b/plumbing/transport/common.go
index 8329069..2f6fcee 100644
--- a/plumbing/transport/common.go
+++ b/plumbing/transport/common.go
@@ -20,6 +20,7 @@ import (
"regexp"
"gopkg.in/src-d/go-git.v4/plumbing"
+ "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp"
)
var (
@@ -63,10 +64,10 @@ type FetchPackSession interface {
// AdvertisedReferences retrieves the advertised references for a
// repository. It should be called before FetchPack, and it cannot be
// called after FetchPack.
- AdvertisedReferences() (*UploadPackInfo, error)
+ AdvertisedReferences() (*packp.AdvRefs, error)
// FetchPack takes a request and returns a reader for the packfile
// received from the server.
- FetchPack(req *UploadPackRequest) (io.ReadCloser, error)
+ FetchPack(req *packp.UploadPackRequest) (io.ReadCloser, error)
}
// FetchPackSession represents a git-send-pack session.
@@ -78,7 +79,7 @@ type SendPackSession interface {
// AdvertisedReferences retrieves the advertised references for a
// repository. It should be called before FetchPack, and it cannot be
// called after FetchPack.
- AdvertisedReferences() (*UploadPackInfo, error)
+ AdvertisedReferences() (*packp.AdvRefs, error)
// UpdateReferences sends an update references request and returns a
// writer to be used for packfile writing.
//TODO: Complete signature.
diff --git a/plumbing/transport/fetch_pack.go b/plumbing/transport/fetch_pack.go
deleted file mode 100644
index 14d3e19..0000000
--- a/plumbing/transport/fetch_pack.go
+++ /dev/null
@@ -1,177 +0,0 @@
-package transport
-
-import (
- "bytes"
- "fmt"
- "io"
- "io/ioutil"
- "strings"
-
- "gopkg.in/src-d/go-git.v4/plumbing"
- "gopkg.in/src-d/go-git.v4/plumbing/format/pktline"
- "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp"
- "gopkg.in/src-d/go-git.v4/plumbing/storer"
- "gopkg.in/src-d/go-git.v4/storage/memory"
-)
-
-//TODO: Replace this by packpAdvRefs.
-type UploadPackInfo struct {
- Capabilities *packp.Capabilities
- Refs memory.ReferenceStorage
-}
-
-func NewUploadPackInfo() *UploadPackInfo {
- return &UploadPackInfo{
- Capabilities: packp.NewCapabilities(),
- Refs: make(memory.ReferenceStorage, 0),
- }
-}
-
-func (i *UploadPackInfo) Decode(r io.Reader) error {
- d := packp.NewAdvRefsDecoder(r)
- ar := packp.NewAdvRefs()
- if err := d.Decode(ar); err != nil {
- if err == packp.ErrEmpty {
- return err
- }
- return plumbing.NewUnexpectedError(err)
- }
-
- i.Capabilities = ar.Capabilities
-
- if err := i.addRefs(ar); err != nil {
- return plumbing.NewUnexpectedError(err)
- }
-
- return nil
-}
-
-func (i *UploadPackInfo) addRefs(ar *packp.AdvRefs) error {
- for name, hash := range ar.References {
- ref := plumbing.NewReferenceFromStrings(name, hash.String())
- i.Refs.SetReference(ref)
- }
-
- return i.addSymbolicRefs(ar)
-}
-
-func (i *UploadPackInfo) addSymbolicRefs(ar *packp.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 *packp.AdvRefs) bool {
- return ar.Capabilities.Supports("symref")
-}
-
-func (i *UploadPackInfo) Head() *plumbing.Reference {
- ref, _ := storer.ResolveReference(i.Refs, plumbing.HEAD)
- return ref
-}
-
-func (i *UploadPackInfo) String() string {
- return string(i.Bytes())
-}
-
-func (i *UploadPackInfo) 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 UploadPackRequest struct {
- Wants []plumbing.Hash
- Haves []plumbing.Hash
- Depth int
-}
-
-func (r *UploadPackRequest) Want(h ...plumbing.Hash) {
- r.Wants = append(r.Wants, h...)
-}
-
-func (r *UploadPackRequest) Have(h ...plumbing.Hash) {
- r.Haves = append(r.Haves, h...)
-}
-
-func (r *UploadPackRequest) IsEmpty() bool {
- return isSubset(r.Wants, r.Haves)
-}
-
-func isSubset(needle []plumbing.Hash, haystack []plumbing.Hash) bool {
- for _, h := range needle {
- found := false
- for _, oh := range haystack {
- if h == oh {
- found = true
- break
- }
- }
-
- if !found {
- return false
- }
- }
-
- return true
-}
-
-func (r *UploadPackRequest) String() string {
- b, _ := ioutil.ReadAll(r.Reader())
- return string(b)
-}
-
-func (r *UploadPackRequest) 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/transport/fetch_pack_test.go b/plumbing/transport/fetch_pack_test.go
deleted file mode 100644
index fc77fe2..0000000
--- a/plumbing/transport/fetch_pack_test.go
+++ /dev/null
@@ -1,119 +0,0 @@
-package transport
-
-import (
- "bytes"
- "encoding/base64"
-
- "gopkg.in/src-d/go-git.v4/plumbing"
- "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp"
-
- . "gopkg.in/check.v1"
-)
-
-type UploadPackSuite struct{}
-
-var _ = Suite(&UploadPackSuite{})
-
-const UploadPackInfoFixture = "MDAxZSMgc2VydmljZT1naXQtdXBsb2FkLXBhY2sKMDAwMDAxMGM2ZWNmMGVmMmMyZGZmYjc5NjAzM2U1YTAyMjE5YWY4NmVjNjU4NGU1IEhFQUQAbXVsdGlfYWNrIHRoaW4tcGFjayBzaWRlLWJhbmQgc2lkZS1iYW5kLTY0ayBvZnMtZGVsdGEgc2hhbGxvdyBuby1wcm9ncmVzcyBpbmNsdWRlLXRhZyBtdWx0aV9hY2tfZGV0YWlsZWQgbm8tZG9uZSBzeW1yZWY9SEVBRDpyZWZzL2hlYWRzL21hc3RlciBhZ2VudD1naXQvMjoyLjQuOH5kYnVzc2luay1maXgtZW50ZXJwcmlzZS10b2tlbnMtY29tcGlsYXRpb24tMTE2Ny1nYzcwMDZjZgowMDNmZThkM2ZmYWI1NTI4OTVjMTliOWZjZjdhYTI2NGQyNzdjZGUzMzg4MSByZWZzL2hlYWRzL2JyYW5jaAowMDNmNmVjZjBlZjJjMmRmZmI3OTYwMzNlNWEwMjIxOWFmODZlYzY1ODRlNSByZWZzL2hlYWRzL21hc3RlcgowMDNlYjhlNDcxZjU4YmNiY2E2M2IwN2JkYTIwZTQyODE5MDQwOWMyZGI0NyByZWZzL3B1bGwvMS9oZWFkCjAwMDA="
-
-func (s *UploadPackSuite) TestUploadPackInfo(c *C) {
- b, _ := base64.StdEncoding.DecodeString(UploadPackInfoFixture)
-
- i := NewUploadPackInfo()
- 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 UploadPackInfoNoHEADFixture = "MDAxZSMgc2VydmljZT1naXQtdXBsb2FkLXBhY2sKMDAwMDAwYmNkN2UxZmVlMjYxMjM0YmIzYTQzYzA5NmY1NTg3NDhhNTY5ZDc5ZWZmIHJlZnMvaGVhZHMvdjQAbXVsdGlfYWNrIHRoaW4tcGFjayBzaWRlLWJhbmQgc2lkZS1iYW5kLTY0ayBvZnMtZGVsdGEgc2hhbGxvdyBuby1wcm9ncmVzcyBpbmNsdWRlLXRhZyBtdWx0aV9hY2tfZGV0YWlsZWQgbm8tZG9uZSBhZ2VudD1naXQvMS45LjEKMDAwMA=="
-
-func (s *UploadPackSuite) TestUploadPackInfoNoHEAD(c *C) {
- b, _ := base64.StdEncoding.DecodeString(UploadPackInfoNoHEADFixture)
-
- i := NewUploadPackInfo()
- 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 *UploadPackSuite) TestUploadPackInfoEmpty(c *C) {
- b := bytes.NewBuffer(nil)
-
- i := NewUploadPackInfo()
- err := i.Decode(b)
- c.Assert(err, Equals, packp.ErrEmpty)
-}
-
-func (s *UploadPackSuite) TestUploadPackEncode(c *C) {
- info := NewUploadPackInfo()
- 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 *UploadPackSuite) TestUploadPackRequest(c *C) {
- r := &UploadPackRequest{}
- 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",
- )
-}
-
-func (s *UploadPackSuite) TestUploadPackRequest_IsEmpty(c *C) {
- r := &UploadPackRequest{}
- r.Want(plumbing.NewHash("d82f291cde9987322c8a0c81a325e1ba6159684c"))
- r.Want(plumbing.NewHash("2b41ef280fdb67a9b250678686a0c3e03b0a9989"))
- r.Have(plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"))
-
- c.Assert(r.IsEmpty(), Equals, false)
-
- r = &UploadPackRequest{}
- r.Want(plumbing.NewHash("d82f291cde9987322c8a0c81a325e1ba6159684c"))
- r.Want(plumbing.NewHash("2b41ef280fdb67a9b250678686a0c3e03b0a9989"))
- r.Have(plumbing.NewHash("d82f291cde9987322c8a0c81a325e1ba6159684c"))
-
- c.Assert(r.IsEmpty(), Equals, false)
-
- r = &UploadPackRequest{}
- r.Want(plumbing.NewHash("d82f291cde9987322c8a0c81a325e1ba6159684c"))
- r.Have(plumbing.NewHash("d82f291cde9987322c8a0c81a325e1ba6159684c"))
-
- c.Assert(r.IsEmpty(), Equals, true)
-}
diff --git a/plumbing/transport/http/fetch_pack.go b/plumbing/transport/http/fetch_pack.go
index 29e385b..40c3a7f 100644
--- a/plumbing/transport/http/fetch_pack.go
+++ b/plumbing/transport/http/fetch_pack.go
@@ -31,8 +31,7 @@ func newFetchPackSession(c *http.Client,
}
}
-func (s *fetchPackSession) AdvertisedReferences() (*transport.UploadPackInfo,
- error) {
+func (s *fetchPackSession) AdvertisedReferences() (*packp.AdvRefs, error) {
if s.advRefsRun {
return nil, transport.ErrAdvertistedReferencesAlreadyCalled
}
@@ -62,19 +61,19 @@ func (s *fetchPackSession) AdvertisedReferences() (*transport.UploadPackInfo,
return nil, transport.ErrAuthorizationRequired
}
- i := transport.NewUploadPackInfo()
- if err := i.Decode(res.Body); err != nil {
- if err == packp.ErrEmpty {
+ ar := packp.NewAdvRefs()
+ if err := ar.Decode(res.Body); err != nil {
+ if err == packp.ErrEmptyAdvRefs {
err = transport.ErrEmptyRemoteRepository
}
return nil, err
}
- return i, nil
+ return ar, nil
}
-func (s *fetchPackSession) FetchPack(r *transport.UploadPackRequest) (io.ReadCloser, error) {
+func (s *fetchPackSession) FetchPack(r *packp.UploadPackRequest) (io.ReadCloser, error) {
if r.IsEmpty() {
return nil, transport.ErrEmptyUploadPackRequest
}
@@ -84,7 +83,12 @@ func (s *fetchPackSession) FetchPack(r *transport.UploadPackRequest) (io.ReadClo
s.endpoint.String(), transport.UploadPackServiceName,
)
- res, err := s.doRequest("POST", url, r.Reader())
+ content, err := uploadPackRequestToReader(r)
+ if err != nil {
+ return nil, err
+ }
+
+ res, err := s.doRequest("POST", url, content)
if err != nil {
return nil, err
}
@@ -161,3 +165,32 @@ func (s *fetchPackSession) applyHeadersToRequest(req *http.Request, content *str
req.Header.Add("Content-Length", string(content.Len()))
}
}
+
+func uploadPackRequestToReader(r *packp.UploadPackRequest) (*strings.Reader, error) {
+ 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 != nil {
+ depth, ok := r.Depth.(packp.DepthCommits)
+ if !ok {
+ return nil, fmt.Errorf("only commit depth is supported")
+ }
+
+ if depth != 0 {
+ _ = e.Encodef("deepen %d\n", depth)
+ }
+ }
+
+ _ = e.Flush()
+ _ = e.EncodeString("done\n")
+
+ return strings.NewReader(buf.String()), nil
+}
diff --git a/plumbing/transport/http/fetch_pack_test.go b/plumbing/transport/http/fetch_pack_test.go
index c7666c8..7471208 100644
--- a/plumbing/transport/http/fetch_pack_test.go
+++ b/plumbing/transport/http/fetch_pack_test.go
@@ -1,6 +1,10 @@
package http
import (
+ "io/ioutil"
+
+ "gopkg.in/src-d/go-git.v4/plumbing"
+ "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp"
"gopkg.in/src-d/go-git.v4/plumbing/transport"
"gopkg.in/src-d/go-git.v4/plumbing/transport/test"
@@ -36,3 +40,20 @@ func (s *FetchPackSuite) TestInfoNotExists(c *C) {
c.Assert(err, Equals, transport.ErrAuthorizationRequired)
c.Assert(info, IsNil)
}
+
+func (s *FetchPackSuite) TestuploadPackRequestToReader(c *C) {
+ r := packp.NewUploadPackRequest()
+ r.Want(plumbing.NewHash("d82f291cde9987322c8a0c81a325e1ba6159684c"))
+ r.Want(plumbing.NewHash("2b41ef280fdb67a9b250678686a0c3e03b0a9989"))
+ r.Have(plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"))
+
+ sr, err := uploadPackRequestToReader(r)
+ c.Assert(err, IsNil)
+ b, _ := ioutil.ReadAll(sr)
+ c.Assert(string(b), Equals,
+ "0032want d82f291cde9987322c8a0c81a325e1ba6159684c\n"+
+ "0032want 2b41ef280fdb67a9b250678686a0c3e03b0a9989\n"+
+ "0032have 6ecf0ef2c2dffb796033e5a02219af86ec6584e5\n0000"+
+ "0009done\n",
+ )
+}
diff --git a/plumbing/transport/http/send_pack.go b/plumbing/transport/http/send_pack.go
index 39be95c..5e3b2bb 100644
--- a/plumbing/transport/http/send_pack.go
+++ b/plumbing/transport/http/send_pack.go
@@ -5,12 +5,13 @@ import (
"io"
"net/http"
+ "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp"
"gopkg.in/src-d/go-git.v4/plumbing/transport"
)
var errSendPackNotSupported = errors.New("send-pack not supported yet")
-type sendPackSession struct{
+type sendPackSession struct {
*session
}
@@ -18,8 +19,7 @@ func newSendPackSession(c *http.Client, ep transport.Endpoint) transport.SendPac
return &sendPackSession{&session{}}
}
-func (s *sendPackSession) AdvertisedReferences() (*transport.UploadPackInfo,
- error) {
+func (s *sendPackSession) AdvertisedReferences() (*packp.AdvRefs, error) {
return nil, errSendPackNotSupported
}
diff --git a/plumbing/transport/ssh/fetch_pack.go b/plumbing/transport/ssh/fetch_pack.go
index decd9c4..a0f52f1 100644
--- a/plumbing/transport/ssh/fetch_pack.go
+++ b/plumbing/transport/ssh/fetch_pack.go
@@ -35,7 +35,7 @@ func newFetchPackSession(ep transport.Endpoint) (*fetchPackSession, error) {
return s, nil
}
-func (s *fetchPackSession) AdvertisedReferences() (*transport.UploadPackInfo, error) {
+func (s *fetchPackSession) AdvertisedReferences() (*packp.AdvRefs, error) {
if s.advRefsRun {
return nil, transport.ErrAdvertistedReferencesAlreadyCalled
}
@@ -46,9 +46,9 @@ func (s *fetchPackSession) AdvertisedReferences() (*transport.UploadPackInfo, er
return nil, err
}
- i := transport.NewUploadPackInfo()
- if err := i.Decode(s.stdout); err != nil {
- if err != packp.ErrEmpty {
+ ar := packp.NewAdvRefs()
+ if err := ar.Decode(s.stdout); err != nil {
+ if err != packp.ErrEmptyAdvRefs {
return nil, err
}
@@ -65,12 +65,12 @@ func (s *fetchPackSession) AdvertisedReferences() (*transport.UploadPackInfo, er
return nil, err
}
- return i, nil
+ return ar, nil
}
// FetchPack returns a packfile for a given upload request.
// Closing the returned reader will close the SSH session.
-func (s *fetchPackSession) FetchPack(req *transport.UploadPackRequest) (
+func (s *fetchPackSession) FetchPack(req *packp.UploadPackRequest) (
io.ReadCloser, error) {
if req.IsEmpty() {
@@ -161,13 +161,13 @@ var (
// TODO support acks for common objects
// TODO build a proper state machine for all these processing options
func fetchPack(w io.WriteCloser, r io.Reader,
- req *transport.UploadPackRequest) error {
+ req *packp.UploadPackRequest) error {
- if err := sendUlReq(w, req); err != nil {
+ if err := req.UploadRequest.Encode(w); err != nil {
return fmt.Errorf("sending upload-req message: %s", err)
}
- if err := sendHaves(w, req); err != nil {
+ if err := req.UploadHaves.Encode(w); err != nil {
return fmt.Errorf("sending haves message: %s", err)
}
@@ -186,32 +186,6 @@ func fetchPack(w io.WriteCloser, r io.Reader,
return nil
}
-func sendUlReq(w io.Writer, req *transport.UploadPackRequest) error {
- ur := packp.NewUlReq()
- ur.Wants = req.Wants
- ur.Depth = packp.DepthCommits(req.Depth)
- e := packp.NewUlReqEncoder(w)
-
- return e.Encode(ur)
-}
-
-func sendHaves(w io.Writer, req *transport.UploadPackRequest) 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)
diff --git a/plumbing/transport/ssh/send_pack.go b/plumbing/transport/ssh/send_pack.go
index afe7510..adf67bb 100644
--- a/plumbing/transport/ssh/send_pack.go
+++ b/plumbing/transport/ssh/send_pack.go
@@ -4,6 +4,7 @@ import (
"errors"
"io"
+ "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp"
"gopkg.in/src-d/go-git.v4/plumbing/transport"
)
@@ -19,8 +20,7 @@ func newSendPackSession(ep transport.Endpoint) (transport.SendPackSession,
return &sendPackSession{&session{}}, nil
}
-func (s *sendPackSession) AdvertisedReferences() (*transport.UploadPackInfo,
- error) {
+func (s *sendPackSession) AdvertisedReferences() (*packp.AdvRefs, error) {
return nil, errSendPackNotSupported
}
diff --git a/plumbing/transport/test/common.go b/plumbing/transport/test/common.go
index 059c0c9..7818fbb 100644
--- a/plumbing/transport/test/common.go
+++ b/plumbing/transport/test/common.go
@@ -10,6 +10,7 @@ import (
"gopkg.in/src-d/go-git.v4/plumbing"
"gopkg.in/src-d/go-git.v4/plumbing/format/packfile"
+ "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp"
"gopkg.in/src-d/go-git.v4/plumbing/transport"
"gopkg.in/src-d/go-git.v4/storage/memory"
@@ -40,7 +41,7 @@ func (s *FetchPackSuite) TestInfoNotExists(c *C) {
r, err = s.Client.NewFetchPackSession(s.NonExistentEndpoint)
c.Assert(err, IsNil)
- req := &transport.UploadPackRequest{}
+ req := packp.NewUploadPackRequest()
req.Want(plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"))
reader, err := r.FetchPack(req)
c.Assert(err, Equals, transport.ErrRepositoryNotFound)
@@ -85,7 +86,7 @@ func (s *FetchPackSuite) TestFullFetchPack(c *C) {
c.Assert(err, IsNil)
c.Assert(info, NotNil)
- req := &transport.UploadPackRequest{}
+ req := packp.NewUploadPackRequest()
req.Want(plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"))
reader, err := r.FetchPack(req)
@@ -99,7 +100,7 @@ func (s *FetchPackSuite) TestFetchPack(c *C) {
c.Assert(err, IsNil)
defer func() { c.Assert(r.Close(), IsNil) }()
- req := &transport.UploadPackRequest{}
+ req := packp.NewUploadPackRequest()
req.Want(plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"))
reader, err := r.FetchPack(req)
@@ -113,7 +114,7 @@ func (s *FetchPackSuite) TestFetchPackNoChanges(c *C) {
c.Assert(err, IsNil)
defer func() { c.Assert(r.Close(), IsNil) }()
- req := &transport.UploadPackRequest{}
+ req := packp.NewUploadPackRequest()
req.Want(plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"))
req.Have(plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"))
@@ -127,7 +128,7 @@ func (s *FetchPackSuite) TestFetchPackMulti(c *C) {
c.Assert(err, IsNil)
defer func() { c.Assert(r.Close(), IsNil) }()
- req := &transport.UploadPackRequest{}
+ req := packp.NewUploadPackRequest()
req.Want(plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"))
req.Want(plumbing.NewHash("e8d3ffab552895c19b9fcf7aa264d277cde33881"))
@@ -141,7 +142,7 @@ func (s *FetchPackSuite) TestFetchError(c *C) {
r, err := s.Client.NewFetchPackSession(s.Endpoint)
c.Assert(err, IsNil)
- req := &transport.UploadPackRequest{}
+ req := packp.NewUploadPackRequest()
req.Want(plumbing.NewHash("1111111111111111111111111111111111111111"))
reader, err := r.FetchPack(req)
diff --git a/remote.go b/remote.go
index 5b6411d..feab72a 100644
--- a/remote.go
+++ b/remote.go
@@ -12,6 +12,7 @@ import (
"gopkg.in/src-d/go-git.v4/plumbing/storer"
"gopkg.in/src-d/go-git.v4/plumbing/transport"
"gopkg.in/src-d/go-git.v4/plumbing/transport/client"
+ "gopkg.in/src-d/go-git.v4/storage/memory"
)
var NoErrAlreadyUpToDate = errors.New("already up-to-date")
@@ -25,7 +26,8 @@ type Remote struct {
endpoint transport.Endpoint
client transport.Client
fetchSession transport.FetchPackSession
- upInfo *transport.UploadPackInfo
+ advRefs *packp.AdvRefs
+ refs memory.ReferenceStorage
}
func newRemote(s Storer, c *config.RemoteConfig) *Remote {
@@ -49,7 +51,7 @@ func (r *Remote) Connect() error {
return nil
}
- return r.retrieveUpInfo()
+ return r.retrieveAdvertisedReferences()
}
func (r *Remote) initClient() error {
@@ -71,20 +73,25 @@ func (r *Remote) initClient() error {
return nil
}
-func (r *Remote) retrieveUpInfo() error {
+func (r *Remote) retrieveAdvertisedReferences() error {
var err error
- r.upInfo, err = r.fetchSession.AdvertisedReferences()
+ r.advRefs, err = r.fetchSession.AdvertisedReferences()
+ if err != nil {
+ return err
+ }
+
+ r.refs, err = r.advRefs.AllReferences()
return err
}
-// Info returns the git-upload-pack info
-func (r *Remote) Info() *transport.UploadPackInfo {
- return r.upInfo
+// AdvertisedReferences returns the git-upload-pack advertised references.
+func (r *Remote) AdvertisedReferences() *packp.AdvRefs {
+ return r.advRefs
}
// Capabilities returns the remote capabilities
func (r *Remote) Capabilities() *packp.Capabilities {
- return r.upInfo.Capabilities
+ return r.advRefs.Capabilities
}
// Fetch returns a reader using the request
@@ -126,7 +133,7 @@ func (r *Remote) Fetch(o *FetchOptions) (err error) {
func (r *Remote) getWantedReferences(spec []config.RefSpec) ([]*plumbing.Reference, error) {
var refs []*plumbing.Reference
- iter, err := r.Refs()
+ iter, err := r.References()
if err != nil {
return refs, err
}
@@ -162,9 +169,9 @@ func (r *Remote) getWantedReferences(spec []config.RefSpec) ([]*plumbing.Referen
func (r *Remote) buildRequest(
s storer.ReferenceStorer, o *FetchOptions, refs []*plumbing.Reference,
-) (*transport.UploadPackRequest, error) {
- req := &transport.UploadPackRequest{}
- req.Depth = o.Depth
+) (*packp.UploadPackRequest, error) {
+ req := packp.NewUploadPackRequest()
+ req.Depth = packp.DepthCommits(o.Depth)
for _, ref := range refs {
req.Want(ref.Hash())
@@ -232,7 +239,7 @@ func (r *Remote) updateLocalReferenceStorage(specs []config.RefSpec, refs []*plu
}
func (r *Remote) buildFetchedTags() error {
- iter, err := r.Refs()
+ iter, err := r.References()
if err != nil {
return err
}
@@ -257,26 +264,31 @@ func (r *Remote) buildFetchedTags() error {
// Head returns the Reference of the HEAD
func (r *Remote) Head() *plumbing.Reference {
- return r.upInfo.Head()
+ ref, err := storer.ResolveReference(r.refs, plumbing.HEAD)
+ if err != nil {
+ return nil
+ }
+
+ return ref
}
-// Ref returns the Hash pointing the given refName
-func (r *Remote) Ref(name plumbing.ReferenceName, resolved bool) (*plumbing.Reference, error) {
+// Reference returns a Reference for a ReferenceName.
+func (r *Remote) Reference(name plumbing.ReferenceName, resolved bool) (*plumbing.Reference, error) {
if resolved {
- return storer.ResolveReference(r.upInfo.Refs, name)
+ return storer.ResolveReference(r.refs, name)
}
- return r.upInfo.Refs.Reference(name)
+ return r.refs.Reference(name)
}
-// Refs returns a map with all the References
-func (r *Remote) Refs() (storer.ReferenceIter, error) {
- return r.upInfo.Refs.IterReferences()
+// References returns an iterator for all references.
+func (r *Remote) References() (storer.ReferenceIter, error) {
+ return r.refs.IterReferences()
}
// Disconnect from the remote and save the config
func (r *Remote) Disconnect() error {
- r.upInfo = nil
+ r.advRefs = nil
return r.fetchSession.Close()
}
diff --git a/remote_test.go b/remote_test.go
index 4df8767..ff543f2 100644
--- a/remote_test.go
+++ b/remote_test.go
@@ -54,10 +54,10 @@ func (s *RemoteSuite) TestInfo(c *C) {
r := newRemote(nil, &config.RemoteConfig{Name: "foo", URL: RepositoryFixture})
r.client = &MockClient{}
- c.Assert(r.Info(), IsNil)
+ c.Assert(r.AdvertisedReferences(), IsNil)
c.Assert(r.Connect(), IsNil)
- c.Assert(r.Info(), NotNil)
- c.Assert(r.Info().Capabilities.Get("ofs-delta"), NotNil)
+ c.Assert(r.AdvertisedReferences(), NotNil)
+ c.Assert(r.AdvertisedReferences().Capabilities.Get("ofs-delta"), NotNil)
}
func (s *RemoteSuite) TestDefaultBranch(c *C) {
@@ -180,11 +180,11 @@ func (s *RemoteSuite) TestRef(c *C) {
err := r.Connect()
c.Assert(err, IsNil)
- ref, err := r.Ref(plumbing.HEAD, false)
+ ref, err := r.Reference(plumbing.HEAD, false)
c.Assert(err, IsNil)
c.Assert(ref.Name(), Equals, plumbing.HEAD)
- ref, err = r.Ref(plumbing.HEAD, true)
+ ref, err = r.Reference(plumbing.HEAD, true)
c.Assert(err, IsNil)
c.Assert(ref.Name(), Equals, plumbing.ReferenceName("refs/heads/master"))
}
@@ -196,7 +196,7 @@ func (s *RemoteSuite) TestRefs(c *C) {
err := r.Connect()
c.Assert(err, IsNil)
- iter, err := r.Refs()
+ iter, err := r.References()
c.Assert(err, IsNil)
c.Assert(iter, NotNil)
}
diff --git a/repository.go b/repository.go
index ec3a1f9..a1a5cae 100644
--- a/repository.go
+++ b/repository.go
@@ -160,7 +160,7 @@ func (r *Repository) Clone(o *CloneOptions) error {
return err
}
- head, err := remote.Ref(o.ReferenceName, true)
+ head, err := remote.Reference(o.ReferenceName, true)
if err != nil {
return err
}
@@ -177,7 +177,12 @@ func (r *Repository) updateRemoteConfig(
return nil
}
- head, err := storer.ResolveReference(remote.Info().Refs, o.ReferenceName)
+ refs, err := remote.AdvertisedReferences().AllReferences()
+ if err != nil {
+ return err
+ }
+
+ head, err := storer.ResolveReference(refs, o.ReferenceName)
if err != nil {
return err
}
@@ -242,7 +247,7 @@ func (r *Repository) Pull(o *PullOptions) error {
defer remote.Disconnect()
- head, err := remote.Ref(o.ReferenceName, true)
+ head, err := remote.Reference(o.ReferenceName, true)
if err != nil {
return err
}