changeset 20967:984850270acb

unbundle: extract checkheads in its own function We are going to refactor the unbundle function to have it working on a local repository too. Having this function extracted will ease the process. In the case of non-matching heads, the function now directly raises an exception. The top level of the function is catching it.
author Pierre-Yves David <pierre-yves.david@fb.com>
date Fri, 04 Apr 2014 17:15:25 -0700
parents 63659b809021
children 33d5fdd9bd99
files mercurial/exchange.py mercurial/wireproto.py
diffstat 2 files changed, 46 insertions(+), 39 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/exchange.py	Mon Apr 07 18:10:50 2014 -0700
+++ b/mercurial/exchange.py	Fri Apr 04 17:15:25 2014 -0700
@@ -611,3 +611,20 @@
         temp.write(c)
     temp.seek(0)
     return bundle2.unbundle20(repo.ui, temp)
+
+class PushRaced(RuntimeError):
+    """An exception raised during unbunding that indicate a push race"""
+
+def check_heads(repo, their_heads, context):
+    """check if the heads of a repo have been modified
+
+    Used by peer for unbundling.
+    """
+    heads = repo.heads()
+    heads_hash = util.sha1(''.join(sorted(heads))).digest()
+    if not (their_heads == ['force'] or their_heads == heads or
+            their_heads == ['hashed', heads_hash]):
+        # someone else committed/pushed/unbundled while we
+        # were transferring data
+        raise PushRaced('repository changed while %s - '
+                        'please try again' % context)
--- a/mercurial/wireproto.py	Mon Apr 07 18:10:50 2014 -0700
+++ b/mercurial/wireproto.py	Fri Apr 04 17:15:25 2014 -0700
@@ -9,7 +9,7 @@
 from i18n import _
 from node import bin, hex
 import changegroup as changegroupmod
-import peer, error, encoding, util, store
+import peer, error, encoding, util, store, exchange
 
 
 class abstractserverproto(object):
@@ -754,46 +754,36 @@
 def unbundle(repo, proto, heads):
     their_heads = decodelist(heads)
 
-    def check_heads():
-        heads = repo.heads()
-        heads_hash = util.sha1(''.join(sorted(heads))).digest()
-        return (their_heads == ['force'] or their_heads == heads or
-                their_heads == ['hashed', heads_hash])
+    try:
+        proto.redirect()
 
-    proto.redirect()
+        exchange.check_heads(repo, their_heads, 'preparing changes')
 
-    # fail early if possible
-    if not check_heads():
-        return pusherr('repository changed while preparing changes - '
-                       'please try again')
-
-    # write bundle data to temporary file because it can be big
-    fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
-    fp = os.fdopen(fd, 'wb+')
-    r = 0
-    try:
-        proto.getfile(fp)
-        lock = repo.lock()
+        # write bundle data to temporary file because it can be big
+        fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
+        fp = os.fdopen(fd, 'wb+')
+        r = 0
         try:
-            if not check_heads():
-                # someone else committed/pushed/unbundled while we
-                # were transferring data
-                return pusherr('repository changed while uploading changes - '
-                               'please try again')
-
-            # push can proceed
-            fp.seek(0)
-            gen = changegroupmod.readbundle(fp, None)
-
+            proto.getfile(fp)
+            lock = repo.lock()
             try:
-                r = changegroupmod.addchangegroup(repo, gen, 'serve',
-                                                  proto._client())
-            except util.Abort, inst:
-                sys.stderr.write("abort: %s\n" % inst)
+                exchange.check_heads(repo, their_heads, 'uploading changes')
+
+                # push can proceed
+                fp.seek(0)
+                gen = changegroupmod.readbundle(fp, None)
+
+                try:
+                    r = changegroupmod.addchangegroup(repo, gen, 'serve',
+                                                      proto._client())
+                except util.Abort, inst:
+                    sys.stderr.write("abort: %s\n" % inst)
+            finally:
+                lock.release()
+            return pushres(r)
+
         finally:
-            lock.release()
-        return pushres(r)
-
-    finally:
-        fp.close()
-        os.unlink(tempname)
+            fp.close()
+            os.unlink(tempname)
+    except exchange.PushRaced, exc:
+        return pusherr(str(exc))