aboutsummaryrefslogtreecommitdiffstats
path: root/plumbing/protocol/packp
diff options
context:
space:
mode:
Diffstat (limited to 'plumbing/protocol/packp')
-rw-r--r--plumbing/protocol/packp/capability/capability.go15
-rw-r--r--plumbing/protocol/packp/capability/capability_test.go22
-rw-r--r--plumbing/protocol/packp/capability/list.go4
-rw-r--r--plumbing/protocol/packp/capability/list_test.go11
-rw-r--r--plumbing/protocol/packp/srvresp.go28
-rw-r--r--plumbing/protocol/packp/srvresp_test.go17
-rw-r--r--plumbing/protocol/packp/ulreq.go2
-rw-r--r--plumbing/protocol/packp/updreq.go2
-rw-r--r--plumbing/protocol/packp/uppackresp.go2
-rw-r--r--plumbing/protocol/packp/uppackresp_test.go6
10 files changed, 93 insertions, 16 deletions
diff --git a/plumbing/protocol/packp/capability/capability.go b/plumbing/protocol/packp/capability/capability.go
index 8714412..b52e8a4 100644
--- a/plumbing/protocol/packp/capability/capability.go
+++ b/plumbing/protocol/packp/capability/capability.go
@@ -1,6 +1,11 @@
// Package capability defines the server and client capabilities.
package capability
+import (
+ "fmt"
+ "os"
+)
+
// Capability describes a server or client capability.
type Capability string
@@ -238,7 +243,15 @@ const (
Filter Capability = "filter"
)
-const DefaultAgent = "go-git/5.x"
+const userAgent = "go-git/5.x"
+
+// DefaultAgent provides the user agent string.
+func DefaultAgent() string {
+ if envUserAgent, ok := os.LookupEnv("GO_GIT_USER_AGENT_EXTRA"); ok {
+ return fmt.Sprintf("%s %s", userAgent, envUserAgent)
+ }
+ return userAgent
+}
var known = map[Capability]bool{
MultiACK: true, MultiACKDetailed: true, NoDone: true, ThinPack: true,
diff --git a/plumbing/protocol/packp/capability/capability_test.go b/plumbing/protocol/packp/capability/capability_test.go
new file mode 100644
index 0000000..f1fd028
--- /dev/null
+++ b/plumbing/protocol/packp/capability/capability_test.go
@@ -0,0 +1,22 @@
+package capability
+
+import (
+ "fmt"
+ "os"
+
+ check "gopkg.in/check.v1"
+)
+
+var _ = check.Suite(&SuiteCapabilities{})
+
+func (s *SuiteCapabilities) TestDefaultAgent(c *check.C) {
+ os.Unsetenv("GO_GIT_USER_AGENT_EXTRA")
+ ua := DefaultAgent()
+ c.Assert(ua, check.Equals, userAgent)
+}
+
+func (s *SuiteCapabilities) TestEnvAgent(c *check.C) {
+ os.Setenv("GO_GIT_USER_AGENT_EXTRA", "abc xyz")
+ ua := DefaultAgent()
+ c.Assert(ua, check.Equals, fmt.Sprintf("%s %s", userAgent, "abc xyz"))
+}
diff --git a/plumbing/protocol/packp/capability/list.go b/plumbing/protocol/packp/capability/list.go
index f41ec79..553d81c 100644
--- a/plumbing/protocol/packp/capability/list.go
+++ b/plumbing/protocol/packp/capability/list.go
@@ -86,7 +86,9 @@ func (l *List) Get(capability Capability) []string {
// Set sets a capability removing the previous values
func (l *List) Set(capability Capability, values ...string) error {
- delete(l.m, capability)
+ if _, ok := l.m[capability]; ok {
+ l.m[capability].Values = l.m[capability].Values[:0]
+ }
return l.Add(capability, values...)
}
diff --git a/plumbing/protocol/packp/capability/list_test.go b/plumbing/protocol/packp/capability/list_test.go
index 61b0b13..71181cb 100644
--- a/plumbing/protocol/packp/capability/list_test.go
+++ b/plumbing/protocol/packp/capability/list_test.go
@@ -122,6 +122,17 @@ func (s *SuiteCapabilities) TestSetEmpty(c *check.C) {
c.Assert(cap.Get(Agent), check.HasLen, 1)
}
+func (s *SuiteCapabilities) TestSetDuplicate(c *check.C) {
+ cap := NewList()
+ err := cap.Set(Agent, "baz")
+ c.Assert(err, check.IsNil)
+
+ err = cap.Set(Agent, "bar")
+ c.Assert(err, check.IsNil)
+
+ c.Assert(cap.String(), check.Equals, "agent=bar")
+}
+
func (s *SuiteCapabilities) TestGetEmpty(c *check.C) {
cap := NewList()
c.Assert(cap.Get(Agent), check.HasLen, 0)
diff --git a/plumbing/protocol/packp/srvresp.go b/plumbing/protocol/packp/srvresp.go
index b3a7ee8..8cd0a72 100644
--- a/plumbing/protocol/packp/srvresp.go
+++ b/plumbing/protocol/packp/srvresp.go
@@ -21,11 +21,6 @@ type ServerResponse struct {
// Decode decodes the response into the struct, isMultiACK should be true, if
// the request was done with multi_ack or multi_ack_detailed capabilities.
func (r *ServerResponse) Decode(reader *bufio.Reader, isMultiACK bool) error {
- // TODO: implement support for multi_ack or multi_ack_detailed responses
- if isMultiACK {
- return errors.New("multi_ack and multi_ack_detailed are not supported")
- }
-
s := pktline.NewScanner(reader)
for s.Scan() {
@@ -48,7 +43,23 @@ func (r *ServerResponse) Decode(reader *bufio.Reader, isMultiACK bool) error {
}
}
- return s.Err()
+ // isMultiACK is true when the remote server advertises the related
+ // capabilities when they are not in transport.UnsupportedCapabilities.
+ //
+ // Users may decide to remove multi_ack and multi_ack_detailed from the
+ // unsupported capabilities list, which allows them to do initial clones
+ // from Azure DevOps.
+ //
+ // Follow-up fetches may error, therefore errors are wrapped with additional
+ // information highlighting that this capabilities are not supported by go-git.
+ //
+ // TODO: Implement support for multi_ack or multi_ack_detailed responses.
+ err := s.Err()
+ if err != nil && isMultiACK {
+ return fmt.Errorf("multi_ack and multi_ack_detailed are not supported: %w", err)
+ }
+
+ return err
}
// stopReading detects when a valid command such as ACK or NAK is found to be
@@ -113,8 +124,9 @@ func (r *ServerResponse) decodeACKLine(line []byte) error {
}
// Encode encodes the ServerResponse into a writer.
-func (r *ServerResponse) Encode(w io.Writer) error {
- if len(r.ACKs) > 1 {
+func (r *ServerResponse) Encode(w io.Writer, isMultiACK bool) error {
+ if len(r.ACKs) > 1 && !isMultiACK {
+ // For further information, refer to comments in the Decode func above.
return errors.New("multi_ack and multi_ack_detailed are not supported")
}
diff --git a/plumbing/protocol/packp/srvresp_test.go b/plumbing/protocol/packp/srvresp_test.go
index 02fab42..aa0af52 100644
--- a/plumbing/protocol/packp/srvresp_test.go
+++ b/plumbing/protocol/packp/srvresp_test.go
@@ -72,8 +72,21 @@ func (s *ServerResponseSuite) TestDecodeMalformed(c *C) {
c.Assert(err, NotNil)
}
+// multi_ack isn't fully implemented, this ensures that Decode ignores that fact,
+// as in some circumstances that's OK to assume so.
+//
+// TODO: Review as part of multi_ack implementation.
func (s *ServerResponseSuite) TestDecodeMultiACK(c *C) {
+ raw := "" +
+ "0031ACK 1111111111111111111111111111111111111111\n" +
+ "0031ACK 6ecf0ef2c2dffb796033e5a02219af86ec6584e5\n" +
+ "00080PACK\n"
+
sr := &ServerResponse{}
- err := sr.Decode(bufio.NewReader(bytes.NewBuffer(nil)), true)
- c.Assert(err, NotNil)
+ err := sr.Decode(bufio.NewReader(bytes.NewBufferString(raw)), true)
+ c.Assert(err, IsNil)
+
+ c.Assert(sr.ACKs, HasLen, 2)
+ c.Assert(sr.ACKs[0], Equals, plumbing.NewHash("1111111111111111111111111111111111111111"))
+ c.Assert(sr.ACKs[1], Equals, plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"))
}
diff --git a/plumbing/protocol/packp/ulreq.go b/plumbing/protocol/packp/ulreq.go
index ddec06e..344f8c7 100644
--- a/plumbing/protocol/packp/ulreq.go
+++ b/plumbing/protocol/packp/ulreq.go
@@ -95,7 +95,7 @@ func NewUploadRequestFromCapabilities(adv *capability.List) *UploadRequest {
}
if adv.Supports(capability.Agent) {
- r.Capabilities.Set(capability.Agent, capability.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 5dbd8ac..8f39b39 100644
--- a/plumbing/protocol/packp/updreq.go
+++ b/plumbing/protocol/packp/updreq.go
@@ -59,7 +59,7 @@ func NewReferenceUpdateRequestFromCapabilities(adv *capability.List) *ReferenceU
r := NewReferenceUpdateRequest()
if adv.Supports(capability.Agent) {
- r.Capabilities.Set(capability.Agent, capability.DefaultAgent)
+ r.Capabilities.Set(capability.Agent, capability.DefaultAgent())
}
if adv.Supports(capability.ReportStatus) {
diff --git a/plumbing/protocol/packp/uppackresp.go b/plumbing/protocol/packp/uppackresp.go
index 26ae61e..a485cb7 100644
--- a/plumbing/protocol/packp/uppackresp.go
+++ b/plumbing/protocol/packp/uppackresp.go
@@ -78,7 +78,7 @@ func (r *UploadPackResponse) Encode(w io.Writer) (err error) {
}
}
- if err := r.ServerResponse.Encode(w); err != nil {
+ if err := r.ServerResponse.Encode(w, r.isMultiACK); err != nil {
return err
}
diff --git a/plumbing/protocol/packp/uppackresp_test.go b/plumbing/protocol/packp/uppackresp_test.go
index 260dc57..3f87804 100644
--- a/plumbing/protocol/packp/uppackresp_test.go
+++ b/plumbing/protocol/packp/uppackresp_test.go
@@ -59,6 +59,10 @@ func (s *UploadPackResponseSuite) TestDecodeMalformed(c *C) {
c.Assert(err, NotNil)
}
+// multi_ack isn't fully implemented, this ensures that Decode ignores that fact,
+// as in some circumstances that's OK to assume so.
+//
+// TODO: Review as part of multi_ack implementation.
func (s *UploadPackResponseSuite) TestDecodeMultiACK(c *C) {
req := NewUploadPackRequest()
req.Capabilities.Set(capability.MultiACK)
@@ -67,7 +71,7 @@ func (s *UploadPackResponseSuite) TestDecodeMultiACK(c *C) {
defer res.Close()
err := res.Decode(ioutil.NopCloser(bytes.NewBuffer(nil)))
- c.Assert(err, NotNil)
+ c.Assert(err, IsNil)
}
func (s *UploadPackResponseSuite) TestReadNoDecode(c *C) {