[PATCH 5 of 5] bundle2: also save output when error happens during part processing

Pierre-Yves David pierre-yves.david at ens-lyon.org
Thu Apr 23 18:56:25 CDT 2015


# HG changeset patch
# User Pierre-Yves David <pierre-yves.david at fb.com>
# Date 1429803378 -3600
#      Thu Apr 23 16:36:18 2015 +0100
# Branch stable
# Node ID 5f39c4343d9d3bf58dcd98f923784f9f0e9dac73
# Parent  09f08e0203066707963b3ed25c4b0da0c5a71622
bundle2: also save output when error happens during part processing

Until this changesets, we were only able to save output if an error happened
during the 'transaction.close()' phases. If the 'processbundle' call raised an
exception, the 'bundleoperation' object was never returned, so the reply bundle
was never accessible and no output could be salvaged. We introduce a quick (but
not very elegant) fix to gain access to any reply created during the processing.

This conclude this output related series. We should hopefully be able client-side to see the
whole server output, in a proper order.

The code is now complex enough that a refactoring of it would make sense on
default.

diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
--- a/mercurial/bundle2.py
+++ b/mercurial/bundle2.py
@@ -283,24 +283,30 @@ def _notransaction():
 
     Raise an exception to highlight the fact that no transaction was expected
     to be created"""
     raise TransactionUnavailable()
 
-def processbundle(repo, unbundler, transactiongetter=None):
+def processbundle(repo, unbundler, transactiongetter=None, op=None):
     """This function process a bundle, apply effect to/from a repo
 
     It iterates over each part then searches for and uses the proper handling
     code to process the part. Parts are processed in order.
 
     This is very early version of this function that will be strongly reworked
     before final usage.
 
     Unknown Mandatory part will abort the process.
+
+    It is temporarily possible to provide a prebuilt bundleoperation to the
+    function. This is used to ensure output is properly propagated in case of
+    error during the unbundling. This output capturing part will likely be
+    reworked and this ability with probably goes away in the process.
     """
-    if transactiongetter is None:
-        transactiongetter = _notransaction
-    op = bundleoperation(repo, transactiongetter)
+    if op is None:
+        if transactiongetter is None:
+            transactiongetter = _notransaction
+        op = bundleoperation(repo, transactiongetter)
     # todo:
     # - replace this is a init function soon.
     # - exception catching
     unbundler.params
     iterparts = unbundler.iterparts()
diff --git a/mercurial/exchange.py b/mercurial/exchange.py
--- a/mercurial/exchange.py
+++ b/mercurial/exchange.py
@@ -1295,15 +1295,19 @@ def unbundle(repo, cg, heads, source, ur
                 lock = repo.lock()
                 tr = repo.transaction(source)
                 tr.hookargs['source'] = source
                 tr.hookargs['url'] = url
                 tr.hookargs['bundle2'] = '1'
-                r = bundle2.processbundle(repo, cg, lambda: tr).reply
-                if r is not None:
-                    repo.ui.pushbuffer(error=True, subproc=True)
-                    def recordout(output):
-                        r.newpart('output', data=output, mandatory=False)
+                op = bundle2.bundleoperation(repo, lambda: tr)
+                try:
+                    r = bundle2.processbundle(repo, cg, op=op)
+                finally:
+                    r = op.reply
+                    if r is not None:
+                        repo.ui.pushbuffer(error=True, subproc=True)
+                        def recordout(output):
+                            r.newpart('output', data=output, mandatory=False)
                 tr.close()
             except Exception, exc:
                 exc.duringunbundle2 = True
                 if r is not None:
                     parts = exc._bundle2salvagedoutput = r.salvageoutput()
diff --git a/tests/test-bundle2-exchange.t b/tests/test-bundle2-exchange.t
--- a/tests/test-bundle2-exchange.t
+++ b/tests/test-bundle2-exchange.t
@@ -617,5 +617,53 @@ Doing the actual push: hook abort
   $ ls -1 other/.hg/store/phaseroots*
   other/.hg/store/phaseroots
   $ ls -1 other/.hg/store/00changelog.i*
   other/.hg/store/00changelog.i
 
+Check error from hook during the unbundling process itself
+
+  $ cat << EOF >> $HGRCPATH
+  > pretxnchangegroup = echo "Fail early!"; false
+  > EOF
+  $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS # reload http config
+  $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
+  $ cat other.pid >> $DAEMON_PIDS
+
+  $ hg -R main push other -r e7ec4e813ba6
+  pushing to other
+  searching for changes
+  remote: adding changesets
+  remote: adding manifests
+  remote: adding file changes
+  remote: added 1 changesets with 1 changes to 1 files
+  remote: Fail early!
+  remote: transaction abort!
+  remote: Cleaning up the mess...
+  remote: rollback completed
+  abort: pretxnchangegroup hook exited with status 1
+  [255]
+  $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
+  pushing to ssh://user@dummy/other
+  searching for changes
+  remote: adding changesets
+  remote: adding manifests
+  remote: adding file changes
+  remote: added 1 changesets with 1 changes to 1 files
+  remote: Fail early!
+  remote: transaction abort!
+  remote: Cleaning up the mess...
+  remote: rollback completed
+  abort: pretxnchangegroup hook exited with status 1
+  [255]
+  $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
+  pushing to http://localhost:$HGPORT2/
+  searching for changes
+  remote: adding changesets
+  remote: adding manifests
+  remote: adding file changes
+  remote: added 1 changesets with 1 changes to 1 files
+  remote: Fail early!
+  remote: transaction abort!
+  remote: Cleaning up the mess...
+  remote: rollback completed
+  abort: pretxnchangegroup hook exited with status 1
+  [255]


More information about the Mercurial-devel mailing list