diff options
Diffstat (limited to 'plumbing/protocol')
-rw-r--r-- | plumbing/protocol/packp/advrefs_encode.go | 88 | ||||
-rw-r--r-- | plumbing/protocol/packp/advrefs_encode_test.go | 6 | ||||
-rw-r--r-- | plumbing/protocol/packp/capability/capability.go | 2 | ||||
-rw-r--r-- | plumbing/protocol/packp/capability/list.go | 23 | ||||
-rw-r--r-- | plumbing/protocol/packp/capability/list_test.go | 22 | ||||
-rw-r--r-- | plumbing/protocol/packp/updreq.go | 4 |
6 files changed, 96 insertions, 49 deletions
diff --git a/plumbing/protocol/packp/advrefs_encode.go b/plumbing/protocol/packp/advrefs_encode.go index e981120..cb93d46 100644 --- a/plumbing/protocol/packp/advrefs_encode.go +++ b/plumbing/protocol/packp/advrefs_encode.go @@ -2,6 +2,7 @@ package packp import ( "bytes" + "fmt" "io" "sort" @@ -21,9 +22,13 @@ func (a *AdvRefs) Encode(w io.Writer) error { } type advRefsEncoder struct { - data *AdvRefs // data to encode - pe *pktline.Encoder // where to write the encoded data - err error // sticky error + data *AdvRefs // data to encode + pe *pktline.Encoder // where to write the encoded data + firstRefName string // reference name to encode in the first pkt-line (HEAD if present) + firstRefHash plumbing.Hash // hash referenced to encode in the first pkt-line (HEAD if present) + sortedRefs []string // hash references to encode ordered by increasing order + err error // sticky error + } func newAdvRefsEncoder(w io.Writer) *advRefsEncoder { @@ -34,6 +39,8 @@ func newAdvRefsEncoder(w io.Writer) *advRefsEncoder { func (e *advRefsEncoder) Encode(v *AdvRefs) error { e.data = v + e.sortRefs() + e.setFirstRef() for state := encodePrefix; state != nil; { state = state(e) @@ -42,6 +49,32 @@ func (e *advRefsEncoder) Encode(v *AdvRefs) error { return e.err } +func (e *advRefsEncoder) sortRefs() { + if len(e.data.References) > 0 { + refs := make([]string, 0, len(e.data.References)) + for refName := range e.data.References { + refs = append(refs, refName) + } + + sort.Strings(refs) + e.sortedRefs = refs + } +} + +func (e *advRefsEncoder) setFirstRef() { + if e.data.Head != nil { + e.firstRefName = head + e.firstRefHash = *e.data.Head + return + } + + if len(e.sortedRefs) > 0 { + refName := e.sortedRefs[0] + e.firstRefName = refName + e.firstRefHash = e.data.References[refName] + } +} + type encoderStateFn func(*advRefsEncoder) encoderStateFn func encodePrefix(e *advRefsEncoder) encoderStateFn { @@ -61,33 +94,27 @@ 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. +// If HEAD ref is not found, the first reference ordered in increasing order will be used. +// If there aren't HEAD neither refs, the first line will be "PKT-LINE(zero-id SP "capabilities^{}" NUL capability-list)". +// See: https://github.com/git/git/blob/master/Documentation/technical/pack-protocol.txt +// See: https://github.com/git/git/blob/master/Documentation/technical/protocol-common.txt func encodeFirstLine(e *advRefsEncoder) encoderStateFn { - head := formatHead(e.data.Head) - separator := formatSeparator(e.data.Head) + const formatFirstLine = "%s %s\x00%s\n" + var firstLine string capabilities := formatCaps(e.data.Capabilities) - if e.err = e.pe.Encodef("%s %s\x00%s\n", head, separator, capabilities); e.err != nil { - return nil - } + if e.firstRefName == "" { + firstLine = fmt.Sprintf(formatFirstLine, plumbing.ZeroHash.String(), "capabilities^{}", capabilities) + } else { + firstLine = fmt.Sprintf(formatFirstLine, e.firstRefHash.String(), e.firstRefName, capabilities) - return encodeRefs -} - -func formatHead(h *plumbing.Hash) string { - if h == nil { - return plumbing.ZeroHash.String() } - return h.String() -} - -func formatSeparator(h *plumbing.Hash) string { - if h == nil { - return noHead + if e.err = e.pe.EncodeString(firstLine); e.err != nil { + return nil } - return head + return encodeRefs } func formatCaps(c *capability.List) string { @@ -101,8 +128,11 @@ func formatCaps(c *capability.List) string { // Adds the (sorted) refs: hash SP refname EOL // and their peeled refs if any. func encodeRefs(e *advRefsEncoder) encoderStateFn { - refs := sortRefs(e.data.References) - for _, r := range refs { + for _, r := range e.sortedRefs { + if r == e.firstRefName { + continue + } + hash, _ := e.data.References[r] if e.err = e.pe.Encodef("%s %s\n", hash.String(), r); e.err != nil { return nil @@ -118,16 +148,6 @@ func encodeRefs(e *advRefsEncoder) encoderStateFn { return encodeShallow } -func sortRefs(m map[string]plumbing.Hash) []string { - ret := make([]string, 0, len(m)) - for k := range m { - ret = append(ret, k) - } - sort.Strings(ret) - - return ret -} - // Adds the (sorted) shallows: "shallow" SP hash EOL func encodeShallow(e *advRefsEncoder) encoderStateFn { sorted := sortShallows(e.data.Shallows) diff --git a/plumbing/protocol/packp/advrefs_encode_test.go b/plumbing/protocol/packp/advrefs_encode_test.go index f901440..3ae84a7 100644 --- a/plumbing/protocol/packp/advrefs_encode_test.go +++ b/plumbing/protocol/packp/advrefs_encode_test.go @@ -99,8 +99,7 @@ func (s *AdvRefsEncodeSuite) TestRefs(c *C) { } expected := pktlines(c, - "0000000000000000000000000000000000000000 capabilities^{}\x00\n", - "a6930aaee06755d1bdcfd943fbf614e4d92bb0c7 refs/heads/master\n", + "a6930aaee06755d1bdcfd943fbf614e4d92bb0c7 refs/heads/master\x00\n", "5dc01c595e6c6ec9ccda4f6f69c131c0dd945f8c refs/tags/v2.6.11-tree\n", "1111111111111111111111111111111111111111 refs/tags/v2.6.12-tree\n", "2222222222222222222222222222222222222222 refs/tags/v2.6.13-tree\n", @@ -129,8 +128,7 @@ func (s *AdvRefsEncodeSuite) TestPeeled(c *C) { } expected := pktlines(c, - "0000000000000000000000000000000000000000 capabilities^{}\x00\n", - "a6930aaee06755d1bdcfd943fbf614e4d92bb0c7 refs/heads/master\n", + "a6930aaee06755d1bdcfd943fbf614e4d92bb0c7 refs/heads/master\x00\n", "5dc01c595e6c6ec9ccda4f6f69c131c0dd945f8c refs/tags/v2.6.11-tree\n", "1111111111111111111111111111111111111111 refs/tags/v2.6.12-tree\n", "5555555555555555555555555555555555555555 refs/tags/v2.6.12-tree^{}\n", diff --git a/plumbing/protocol/packp/capability/capability.go b/plumbing/protocol/packp/capability/capability.go index 96d93f6..a129781 100644 --- a/plumbing/protocol/packp/capability/capability.go +++ b/plumbing/protocol/packp/capability/capability.go @@ -234,7 +234,7 @@ const ( const DefaultAgent = "go-git/4.x" -var valid = map[Capability]bool{ +var known = map[Capability]bool{ MultiACK: true, MultiACKDetailed: true, NoDone: true, ThinPack: true, Sideband: true, Sideband64k: true, OFSDelta: true, Agent: true, Shallow: true, DeepenSince: true, DeepenNot: true, DeepenRelative: true, diff --git a/plumbing/protocol/packp/capability/list.go b/plumbing/protocol/packp/capability/list.go index 3904a4e..26a79b6 100644 --- a/plumbing/protocol/packp/capability/list.go +++ b/plumbing/protocol/packp/capability/list.go @@ -108,7 +108,7 @@ func (l *List) Add(c Capability, values ...string) error { return nil } - if !multipleArgument[c] && len(l.m[c].Values) > 0 { + if known[c] && !multipleArgument[c] && len(l.m[c].Values) > 0 { return ErrMultipleArguments } @@ -116,7 +116,19 @@ func (l *List) Add(c Capability, values ...string) error { return nil } +func (l *List) validateNoEmptyArgs(values []string) error { + for _, v := range values { + if v == "" { + return ErrEmtpyArgument + } + } + return nil +} + func (l *List) validate(c Capability, values []string) error { + if !known[c] { + return l.validateNoEmptyArgs(values) + } if requiresArgument[c] && len(values) == 0 { return ErrArgumentsRequired } @@ -128,14 +140,7 @@ func (l *List) validate(c Capability, values []string) error { if !multipleArgument[c] && len(values) > 1 { return ErrMultipleArguments } - - for _, v := range values { - if v == "" { - return ErrEmtpyArgument - } - } - - return nil + return l.validateNoEmptyArgs(values) } // Supports returns true if capability is present diff --git a/plumbing/protocol/packp/capability/list_test.go b/plumbing/protocol/packp/capability/list_test.go index 9665e89..82dd63f 100644 --- a/plumbing/protocol/packp/capability/list_test.go +++ b/plumbing/protocol/packp/capability/list_test.go @@ -65,6 +65,26 @@ func (s *SuiteCapabilities) TestDecodeWithUnknownCapability(c *check.C) { c.Assert(cap.Supports(Capability("foo")), check.Equals, true) } +func (s *SuiteCapabilities) TestDecodeWithUnknownCapabilityWithArgument(c *check.C) { + cap := NewList() + err := cap.Decode([]byte("oldref=HEAD:refs/heads/v2 thin-pack")) + c.Assert(err, check.IsNil) + + c.Assert(cap.m, check.HasLen, 2) + c.Assert(cap.Get("oldref"), check.DeepEquals, []string{"HEAD:refs/heads/v2"}) + c.Assert(cap.Get(ThinPack), check.IsNil) +} + +func (s *SuiteCapabilities) TestDecodeWithUnknownCapabilityWithMultipleArgument(c *check.C) { + cap := NewList() + err := cap.Decode([]byte("foo=HEAD:refs/heads/v2 foo=HEAD:refs/heads/v1 thin-pack")) + c.Assert(err, check.IsNil) + + c.Assert(cap.m, check.HasLen, 2) + c.Assert(cap.Get("foo"), check.DeepEquals, []string{"HEAD:refs/heads/v2", "HEAD:refs/heads/v1"}) + c.Assert(cap.Get(ThinPack), check.IsNil) +} + func (s *SuiteCapabilities) TestString(c *check.C) { cap := NewList() cap.Set(Agent, "bar") @@ -153,7 +173,7 @@ func (s *SuiteCapabilities) TestAddErrArgumentsNotAllowed(c *check.C) { c.Assert(err, check.Equals, ErrArguments) } -func (s *SuiteCapabilities) TestAddErrArgumendts(c *check.C) { +func (s *SuiteCapabilities) TestAddErrArguments(c *check.C) { cap := NewList() err := cap.Add(SymRef, "") c.Assert(err, check.Equals, ErrEmtpyArgument) diff --git a/plumbing/protocol/packp/updreq.go b/plumbing/protocol/packp/updreq.go index b246613..73be117 100644 --- a/plumbing/protocol/packp/updreq.go +++ b/plumbing/protocol/packp/updreq.go @@ -6,6 +6,7 @@ import ( "gopkg.in/src-d/go-git.v4/plumbing" "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/capability" + "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/sideband" ) var ( @@ -21,6 +22,9 @@ type ReferenceUpdateRequest struct { Shallow *plumbing.Hash // Packfile contains an optional packfile reader. Packfile io.ReadCloser + + // Progress receives sideband progress messages from the server + Progress sideband.Progress } // New returns a pointer to a new ReferenceUpdateRequest value. |