Skip to content
Snippets Groups Projects
Commit 76efca13 authored by Ori Rawlings's avatar Ori Rawlings
Browse files

Add sideband support for push

parent 3ca37027
No related branches found
No related tags found
No related merge requests found
......@@ -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.
......
......@@ -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.
......
......@@ -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()
......
......@@ -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
}
......
......@@ -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,
......
......@@ -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{
......
// +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))
}
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))
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment