aboutsummaryrefslogtreecommitdiffstats
path: root/plumbing/protocol/packp/srvresp.go
diff options
context:
space:
mode:
Diffstat (limited to 'plumbing/protocol/packp/srvresp.go')
-rw-r--r--plumbing/protocol/packp/srvresp.go70
1 files changed, 70 insertions, 0 deletions
diff --git a/plumbing/protocol/packp/srvresp.go b/plumbing/protocol/packp/srvresp.go
new file mode 100644
index 0000000..3284fa2
--- /dev/null
+++ b/plumbing/protocol/packp/srvresp.go
@@ -0,0 +1,70 @@
+package packp
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+
+ "gopkg.in/src-d/go-git.v4/plumbing"
+ "gopkg.in/src-d/go-git.v4/plumbing/format/pktline"
+)
+
+const ackLineLen = 44
+
+// ServerResponse object acknowledgement from upload-pack service
+// TODO: implement support for multi_ack or multi_ack_detailed responses
+type ServerResponse struct {
+ ACKs []plumbing.Hash
+}
+
+// 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 io.Reader, isMultiACK bool) error {
+ if isMultiACK {
+ return errors.New("multi_ack and multi_ack_detailed are not supported")
+ }
+
+ s := pktline.NewScanner(reader)
+
+ for s.Scan() {
+ line := s.Bytes()
+
+ if err := r.decodeLine(line); err != nil {
+ return err
+ }
+
+ if !isMultiACK {
+ break
+ }
+ }
+
+ return s.Err()
+}
+
+func (r *ServerResponse) decodeLine(line []byte) error {
+ if len(line) == 0 {
+ return fmt.Errorf("unexpected flush")
+ }
+
+ if bytes.Compare(line[0:3], ack) == 0 {
+ return r.decodeACKLine(line)
+ }
+
+ if bytes.Compare(line[0:3], nak) == 0 {
+ return nil
+ }
+
+ return fmt.Errorf("unexpected content %q", string(line))
+}
+
+func (r *ServerResponse) decodeACKLine(line []byte) error {
+ if len(line) < ackLineLen {
+ return fmt.Errorf("malformed ACK %q", line)
+ }
+
+ sp := bytes.Index(line, []byte(" "))
+ h := plumbing.NewHash(string(line[sp+1 : sp+41]))
+ r.ACKs = append(r.ACKs, h)
+ return nil
+}