bundle2: fix raising errors during heads checking stable
authorPierre-Yves David <pierre-yves.david@fb.com>
Mon, 21 Apr 2014 18:59:09 -0700
branchstable
changeset 21184 28d76afa1568
parent 21183 4345274adc4b
child 21185 5b3717e1a3ea
bundle2: fix raising errors during heads checking If the heads on the server differ from the ones reported seen by the client at bundle time, we raise a PushRaced exception. However, the part raising the exception was broken. To fix it, we move the PushRaced class in the error module so it can be accessible everywhere without an import cycle. A test is also added to prevent regression.
mercurial/bundle2.py
mercurial/error.py
mercurial/exchange.py
mercurial/localrepo.py
mercurial/wireproto.py
tests/test-bundle2.t
--- a/mercurial/bundle2.py	Mon Apr 21 16:02:03 2014 -0700
+++ b/mercurial/bundle2.py	Mon Apr 21 18:59:09 2014 -0700
@@ -145,7 +145,7 @@
 import urllib
 import string
 
-import changegroup
+import changegroup, error
 from i18n import _
 
 _pack = struct.pack
@@ -730,7 +730,7 @@
         h = inpart.read(20)
     assert not h
     if heads != op.repo.heads():
-        raise exchange.PushRaced()
+        raise error.PushRaced()
 
 @parthandler('b2x:output')
 def handleoutput(op, inpart):
--- a/mercurial/error.py	Mon Apr 21 16:02:03 2014 -0700
+++ b/mercurial/error.py	Mon Apr 21 18:59:09 2014 -0700
@@ -94,3 +94,7 @@
 
 class SignatureError(Exception):
     pass
+
+class PushRaced(RuntimeError):
+    """An exception raised during unbundling that indicate a push race"""
+
--- a/mercurial/exchange.py	Mon Apr 21 16:02:03 2014 -0700
+++ b/mercurial/exchange.py	Mon Apr 21 18:59:09 2014 -0700
@@ -8,7 +8,7 @@
 from i18n import _
 from node import hex, nullid
 import errno, urllib
-import util, scmutil, changegroup, base85
+import util, scmutil, changegroup, base85, error
 import discovery, phases, obsolete, bookmarks, bundle2
 
 def readbundle(ui, fh, fname, vfs=None):
@@ -708,9 +708,6 @@
     """hook function to let extensions add parts to the requested bundle"""
     pass
 
-class PushRaced(RuntimeError):
-    """An exception raised during unbundling that indicate a push race"""
-
 def check_heads(repo, their_heads, context):
     """check if the heads of a repo have been modified
 
@@ -722,8 +719,8 @@
             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)
+        raise error.PushRaced('repository changed while %s - '
+                              'please try again' % context)
 
 def unbundle(repo, cg, heads, source, url):
     """Apply a bundle to a repo.
--- a/mercurial/localrepo.py	Mon Apr 21 16:02:03 2014 -0700
+++ b/mercurial/localrepo.py	Mon Apr 21 18:59:09 2014 -0700
@@ -133,7 +133,7 @@
                 stream = util.chunkbuffer(ret.getchunks())
                 ret = bundle2.unbundle20(self.ui, stream)
             return ret
-        except exchange.PushRaced, exc:
+        except error.PushRaced, exc:
             raise error.ResponseError(_('push failed:'), exc.message)
 
     def lock(self):
--- a/mercurial/wireproto.py	Mon Apr 21 16:02:03 2014 -0700
+++ b/mercurial/wireproto.py	Mon Apr 21 18:59:09 2014 -0700
@@ -826,5 +826,5 @@
         else:
             sys.stderr.write("abort: %s\n" % inst)
             return pushres(0)
-    except exchange.PushRaced, exc:
+    except error.PushRaced, exc:
         return pusherr(str(exc))
--- a/tests/test-bundle2.t	Mon Apr 21 16:02:03 2014 -0700
+++ b/tests/test-bundle2.t	Mon Apr 21 18:59:09 2014 -0700
@@ -15,6 +15,7 @@
   > from mercurial import scmutil
   > from mercurial import discovery
   > from mercurial import changegroup
+  > from mercurial import error
   > cmdtable = {}
   > command = cmdutil.command(cmdtable)
   > 
@@ -59,6 +60,7 @@
   >           ('', 'unknown', False, 'include an unknown mandatory part in the bundle'),
   >           ('', 'parts', False, 'include some arbitrary parts to the bundle'),
   >           ('', 'reply', False, 'produce a reply bundle'),
+  >           ('', 'pushrace', False, 'includes a check:head part with unknown nodes'),
   >           ('r', 'rev', [], 'includes those changeset in the bundle'),],
   >          '[OUTPUTFILE]')
   > def cmdbundle2(ui, repo, path=None, **opts):
@@ -75,6 +77,10 @@
   >         capsstring = 'ping-pong\nelephants=babar,celeste\ncity%3D%21=celeste%2Cville'
   >         bundler.addpart(bundle2.bundlepart('b2x:replycaps', data=capsstring))
   > 
+  >     if opts['pushrace']:
+  >         dummynode = '01234567890123456789'
+  >         bundler.addpart(bundle2.bundlepart('b2x:check:heads', data=dummynode))
+  > 
   >     revs = opts['rev']
   >     if 'rev' in opts:
   >         revs = scmutil.revrange(repo, opts['rev'])
@@ -132,6 +138,8 @@
   >             tr.close()
   >         except KeyError, exc:
   >             raise util.Abort('missing support for %s' % exc)
+  >         except error.PushRaced, exc:
+  >             raise util.Abort('push race')
   >     finally:
   >         if tr is not None:
   >             tr.release()
@@ -601,6 +609,15 @@
   remote: replying to ping request (id 6)
   0 unread bytes
 
+Test push race detection
+
+  $ hg bundle2 --pushrace ../part-race.hg2
+
+  $ hg unbundle2 < ../part-race.hg2
+  0 unread bytes
+  abort: push race
+  [255]
+
 Support for changegroup
 ===================================