aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOri Rawlings <orirawlings@gmail.com>2017-08-23 21:37:49 -0500
committerOri Rawlings <orirawlings@gmail.com>2017-09-01 09:17:23 -0500
commit76efca13092ba245caf15f232f467e68fa1f73ed (patch)
treee94ed3536e5af8d9201e83de9a7011ab5ac37dad
parent3ca370277427c5d508f0dedacbd559523a305121 (diff)
downloadgo-git-76efca13092ba245caf15f232f467e68fa1f73ed.tar.gz
Add sideband support for push
-rw-r--r--options.go3
-rw-r--r--plumbing/protocol/packp/updreq.go4
-rw-r--r--plumbing/transport/http/receive_pack.go13
-rw-r--r--plumbing/transport/internal/common/common.go18
-rw-r--r--remote.go25
-rw-r--r--repository_test.go41
-rw-r--r--repository_unix_test.go11
-rw-r--r--repository_windows_test.go9
8 files changed, 118 insertions, 6 deletions
diff --git a/options.go b/options.go
index 0ec18d4..98b1194 100644
--- a/options.go
+++ b/options.go
@@ -160,6 +160,9 @@ type PushOptions struct {
RefSpecs []config.RefSpec
// Auth credentials, if required, to use with the remote repository.
Auth transport.AuthMethod
+ // Progress is where the human readable information sent by the server is
+ // stored, if nil nothing is stored.
+ Progress sideband.Progress
}
// Validate validates the fields and sets the default values.
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.
diff --git a/plumbing/transport/http/receive_pack.go b/plumbing/transport/http/receive_pack.go
index b54b70f..d2dfeb7 100644
--- a/plumbing/transport/http/receive_pack.go
+++ b/plumbing/transport/http/receive_pack.go
@@ -9,6 +9,8 @@ import (
"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/protocol/packp/capability"
+ "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/sideband"
"gopkg.in/src-d/go-git.v4/plumbing/transport"
"gopkg.in/src-d/go-git.v4/utils/ioutil"
)
@@ -52,6 +54,17 @@ func (s *rpSession) ReceivePack(ctx context.Context, req *packp.ReferenceUpdateR
return nil, err
}
+ var d *sideband.Demuxer
+ if req.Capabilities.Supports(capability.Sideband64k) {
+ d = sideband.NewDemuxer(sideband.Sideband64k, r)
+ } else if req.Capabilities.Supports(capability.Sideband) {
+ d = sideband.NewDemuxer(sideband.Sideband, r)
+ }
+ if d != nil {
+ d.Progress = req.Progress
+ r = d
+ }
+
rc := ioutil.NewReadCloser(r, res.Body)
report := packp.NewReportStatus()
diff --git a/plumbing/transport/internal/common/common.go b/plumbing/transport/internal/common/common.go
index 2db8d54..598c6b1 100644
--- a/plumbing/transport/internal/common/common.go
+++ b/plumbing/transport/internal/common/common.go
@@ -18,6 +18,7 @@ import (
"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/protocol/packp/capability"
+ "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/sideband"
"gopkg.in/src-d/go-git.v4/plumbing/transport"
"gopkg.in/src-d/go-git.v4/utils/ioutil"
)
@@ -298,13 +299,26 @@ func (s *session) ReceivePack(ctx context.Context, req *packp.ReferenceUpdateReq
}
if !req.Capabilities.Supports(capability.ReportStatus) {
- // If we have neither report-status or sideband, we can only
+ // If we don't have report-status, we can only
// check return value error.
return nil, s.Command.Close()
}
+ r := s.StdoutContext(ctx)
+
+ var d *sideband.Demuxer
+ if req.Capabilities.Supports(capability.Sideband64k) {
+ d = sideband.NewDemuxer(sideband.Sideband64k, r)
+ } else if req.Capabilities.Supports(capability.Sideband) {
+ d = sideband.NewDemuxer(sideband.Sideband, r)
+ }
+ if d != nil {
+ d.Progress = req.Progress
+ r = d
+ }
+
report := packp.NewReportStatus()
- if err := report.Decode(s.StdoutContext(ctx)); err != nil {
+ if err := report.Decode(r); err != nil {
return nil, err
}
diff --git a/remote.go b/remote.go
index c07c5af..1c9d1cd 100644
--- a/remote.go
+++ b/remote.go
@@ -65,7 +65,6 @@ func (r *Remote) Push(o *PushOptions) error {
// operation is complete, an error is returned. The context only affects to the
// transport operations.
func (r *Remote) PushContext(ctx context.Context, o *PushOptions) error {
- // TODO: Sideband support
if err := o.Validate(); err != nil {
return err
}
@@ -108,9 +107,8 @@ func (r *Remote) PushContext(ctx context.Context, o *PushOptions) error {
return ErrDeleteRefNotSupported
}
- req := packp.NewReferenceUpdateRequestFromCapabilities(ar.Capabilities)
- if err := r.addReferencesToUpdate(o.RefSpecs, remoteRefs, req); err != nil {
-
+ req, err := r.newReferenceUpdateRequest(o, remoteRefs, ar)
+ if err != nil {
return err
}
@@ -158,6 +156,25 @@ func (r *Remote) PushContext(ctx context.Context, o *PushOptions) error {
return r.updateRemoteReferenceStorage(req, rs)
}
+func (r *Remote) newReferenceUpdateRequest(o *PushOptions, remoteRefs storer.ReferenceStorer, ar *packp.AdvRefs) (*packp.ReferenceUpdateRequest, error) {
+ req := packp.NewReferenceUpdateRequestFromCapabilities(ar.Capabilities)
+
+ if o.Progress != nil {
+ req.Progress = o.Progress
+ if ar.Capabilities.Supports(capability.Sideband64k) {
+ req.Capabilities.Set(capability.Sideband64k)
+ } else if ar.Capabilities.Supports(capability.Sideband) {
+ req.Capabilities.Set(capability.Sideband)
+ }
+ }
+
+ if err := r.addReferencesToUpdate(o.RefSpecs, remoteRefs, req); err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
func (r *Remote) updateRemoteReferenceStorage(
req *packp.ReferenceUpdateRequest,
result *packp.ReportStatus,
diff --git a/repository_test.go b/repository_test.go
index e944251..6184949 100644
--- a/repository_test.go
+++ b/repository_test.go
@@ -719,6 +719,47 @@ func (s *RepositorySuite) TestPushContext(c *C) {
c.Assert(err, NotNil)
}
+// installPreReceiveHook installs a pre-receive hook in the .git
+// directory at path which prints message m before exiting
+// successfully.
+func installPreReceiveHook(c *C, path, m string) {
+ hooks := filepath.Join(path, "hooks")
+ err := os.MkdirAll(hooks, 0777)
+ c.Assert(err, IsNil)
+
+ err = ioutil.WriteFile(filepath.Join(hooks, "pre-receive"), preReceiveHook(m), 0777)
+ c.Assert(err, IsNil)
+}
+
+func (s *RepositorySuite) TestPushWithProgress(c *C) {
+ url := c.MkDir()
+ server, err := PlainInit(url, true)
+ c.Assert(err, IsNil)
+
+ m := "Receiving..."
+ installPreReceiveHook(c, url, m)
+
+ _, err = s.Repository.CreateRemote(&config.RemoteConfig{
+ Name: "bar",
+ URLs: []string{url},
+ })
+ c.Assert(err, IsNil)
+
+ var p bytes.Buffer
+ err = s.Repository.Push(&PushOptions{
+ RemoteName: "bar",
+ Progress: &p,
+ })
+ c.Assert(err, IsNil)
+
+ AssertReferences(c, server, map[string]string{
+ "refs/heads/master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
+ "refs/heads/branch": "e8d3ffab552895c19b9fcf7aa264d277cde33881",
+ })
+
+ c.Assert((&p).Bytes(), DeepEquals, []byte(m))
+}
+
func (s *RepositorySuite) TestPushDepth(c *C) {
url := c.MkDir()
server, err := PlainClone(url, true, &CloneOptions{
diff --git a/repository_unix_test.go b/repository_unix_test.go
new file mode 100644
index 0000000..75682ae
--- /dev/null
+++ b/repository_unix_test.go
@@ -0,0 +1,11 @@
+// +build !plan9,!windows
+
+package git
+
+import "fmt"
+
+// preReceiveHook returns the bytes of a pre-receive hook script
+// that prints m before exiting successfully
+func preReceiveHook(m string) []byte {
+ return []byte(fmt.Sprintf("#!/bin/sh\nprintf '%s'\n", m))
+}
diff --git a/repository_windows_test.go b/repository_windows_test.go
new file mode 100644
index 0000000..bec0acd
--- /dev/null
+++ b/repository_windows_test.go
@@ -0,0 +1,9 @@
+package git
+
+import "fmt"
+
+// preReceiveHook returns the bytes of a pre-receive hook script
+// that prints m before exiting successfully
+func preReceiveHook(m string) []byte {
+ return []byte(fmt.Sprintf("#!C:/Program\\ Files/Git/usr/bin/sh.exe\nprintf '%s'\n", m))
+}