Patchwork [2,of,2] bundle2: allow to use bundle2 for push

login
register
mail settings
Submitter Pierre-Yves David
Date April 13, 2014, 6:58 p.m.
Message ID <d705fbcf41e61d3dff6b.1397415491@marginatus.alto.octopoid.net>
Download mbox | patch
Permalink /patch/4336/
State Accepted
Headers show

Comments

Pierre-Yves David - April 13, 2014, 6:58 p.m.
# HG changeset patch
# User Pierre-Yves David <pierre-yves.david@fb.com>
# Date 1397152423 25200
#      Thu Apr 10 10:53:43 2014 -0700
# Node ID d705fbcf41e61d3dff6bdaff4df3044f25ec9f1e
# Parent  66d9aab7e6895fae7e723d5122c9301e3d2d90ec
bundle2: allow to use bundle2 for push

We now support bundle2 for local push. The unbundle function have to detect
which version of the bundle to use since the return type is different.

Note that push error handling is currently inexistent. This is one of the reason
why bundle is still disabled by default.
Pierre-Yves David - April 16, 2014, 9:49 p.m.
On 04/13/2014 02:58 PM, pierre-yves.david@ens-lyon.org wrote:
> # HG changeset patch
> # User Pierre-Yves David <pierre-yves.david@fb.com>
> # Date 1397152423 25200
> #      Thu Apr 10 10:53:43 2014 -0700
> # Node ID d705fbcf41e61d3dff6bdaff4df3044f25ec9f1e
> # Parent  66d9aab7e6895fae7e723d5122c9301e3d2d90ec
> bundle2: allow to use bundle2 for push

Those two, and 18 other patches have been reviewed by Matt in real life.

They have been queued in the clown copter.

Patch

diff --git a/mercurial/exchange.py b/mercurial/exchange.py
--- a/mercurial/exchange.py
+++ b/mercurial/exchange.py
@@ -101,11 +101,14 @@  def push(repo, remote, force=False, revs
         if not unbundle:
             lock = pushop.remote.lock()
         try:
             _pushdiscovery(pushop)
             if _pushcheckoutgoing(pushop):
-                _pushchangeset(pushop)
+                if pushop.remote.capable('bundle2'):
+                    _pushbundle2(pushop)
+                else:
+                    _pushchangeset(pushop)
             _pushcomputecommonheads(pushop)
             _pushsyncphase(pushop)
             _pushobsolete(pushop)
         finally:
             if lock is not None:
@@ -167,10 +170,35 @@  def _pushcheckoutgoing(pushop):
                              pushop.newbranch,
                              bool(pushop.incoming),
                              newbm)
     return True
 
+def _pushbundle2(pushop):
+    """push data to the remote using bundle2
+
+    The only currently supported type of data is changegroup but this will
+    evolve in the future."""
+    # Send known head to the server for race detection.
+    bundler = bundle2.bundle20(pushop.ui)
+    if not pushop.force:
+        part = bundle2.bundlepart('CHECK:HEADS', data=iter(pushop.remoteheads))
+        bundler.addpart(part)
+    # add the changegroup bundle
+    cg = changegroup.getlocalbundle(pushop.repo, 'push', pushop.outgoing)
+    cgpart = bundle2.bundlepart('CHANGEGROUP', data=cg.getchunks())
+    bundler.addpart(cgpart)
+    stream = util.chunkbuffer(bundler.getchunks())
+    sent = bundle2.unbundle20(pushop.repo.ui, stream)
+    reply = pushop.remote.unbundle(sent, ['force'], 'push')
+    try:
+        op = bundle2.processbundle(pushop.repo, reply)
+    except KeyError, exc:
+        raise util.Abort('missing support for %s' % exc)
+    cgreplies = op.records.getreplies(cgpart.id)
+    assert len(cgreplies['changegroup']) == 1
+    pushop.ret = cgreplies['changegroup'][0]['return']
+
 def _pushchangeset(pushop):
     """Make the actual push of changeset bundle to remote repo"""
     outgoing = pushop.outgoing
     unbundle = pushop.remote.capable('unbundle')
     # TODO: get bundlecaps from remote
@@ -632,13 +660,25 @@  def unbundle(repo, cg, heads, source, ur
     mechanism to check that no push race occured between the creation of the
     bundle and its application.
 
     If the push was raced as PushRaced exception is raised."""
     r = 0
+    # need a transaction when processing a bundle2 stream
+    tr = None
     lock = repo.lock()
     try:
         check_heads(repo, heads, 'uploading changes')
         # push can proceed
-        r = changegroup.addchangegroup(repo, cg, source, url)
+        if util.safehasattr(cg, 'params'):
+            tr = repo.transaction('unbundle')
+
+            ret = bundle2.processbundle(repo, cg, lambda:tr)
+            tr.close()
+            stream = util.chunkbuffer(ret.reply.getchunks())
+            r = bundle2.unbundle20(repo.ui, stream)
+        else:
+            r = changegroup.addchangegroup(repo, cg, source, url)
     finally:
+        if tr is not None:
+            tr.release()
         lock.release()
     return r
diff --git a/tests/test-bundle2.t b/tests/test-bundle2.t
--- a/tests/test-bundle2.t
+++ b/tests/test-bundle2.t
@@ -666,13 +666,23 @@  clone --pull
      summary:     A
   
 
 pull
 
-  $ hg -R other pull
+  $ hg -R other pull -r 24b6387c8c8c
   pulling from $TESTTMP/main (glob)
   searching for changes
   adding changesets
   adding manifests
   adding file changes
-  added 7 changesets with 6 changes to 6 files (+3 heads)
+  added 1 changesets with 1 changes to 1 files (+1 heads)
   (run 'hg heads' to see heads, 'hg merge' to merge)
+
+push
+
+  $ hg -R main push other --rev eea13746799a
+  pushing to other
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 0 changes to 0 files (-1 heads)