# HG changeset patch
# User Pierre-Yves David <pierre-yves.david@fb.com>
# Date 1398121995 25200
#      Mon Apr 21 16:13:15 2014 -0700
# Branch stable
# Node ID bcfd44abad933390b1b21d7ffcd107fca0023dd2
# Parent  9f3652e851f8c53f75358777ae89e0906bd835f3
bundle2: gracefully handle hook abort

We make sure any exceptions raised during the whole span of handling bundle2
processing are decorated. This let us catch exceptions raised by hooks prior to
transaction commit.

diff --git a/mercurial/exchange.py b/mercurial/exchange.py
--- a/mercurial/exchange.py
+++ b/mercurial/exchange.py
@@ -738,16 +738,20 @@
         check_heads(repo, heads, 'uploading changes')
         # push can proceed
         if util.safehasattr(cg, 'params'):
-            tr = repo.transaction('unbundle')
-            tr.hookargs['bundle2-exp'] = '1'
-            r = bundle2.processbundle(repo, cg, lambda: tr).reply
-            cl = repo.unfiltered().changelog
-            p = cl.writepending() and repo.root or ""
-            repo.hook('b2x-pretransactionclose', throw=True, source=source,
-                      url=url, pending=p, **tr.hookargs)
-            tr.close()
-            repo.hook('b2x-transactionclose', source=source, url=url,
-                      **tr.hookargs)
+            try:
+                tr = repo.transaction('unbundle')
+                tr.hookargs['bundle2-exp'] = '1'
+                r = bundle2.processbundle(repo, cg, lambda: tr).reply
+                cl = repo.unfiltered().changelog
+                p = cl.writepending() and repo.root or ""
+                repo.hook('b2x-pretransactionclose', throw=True, source=source,
+                          url=url, pending=p, **tr.hookargs)
+                tr.close()
+                repo.hook('b2x-transactionclose', source=source, url=url,
+                          **tr.hookargs)
+            except Exception, exc:
+                exc.duringunbundle2 = True
+                raise
         else:
             r = changegroup.addchangegroup(repo, cg, source, url)
     finally:
diff --git a/tests/test-bundle2.t b/tests/test-bundle2.t
--- a/tests/test-bundle2.t
+++ b/tests/test-bundle2.t
@@ -1043,3 +1043,40 @@
   abort: push failed:
   'repository changed while pushing - please try again'
   [255]
+
+Doing the actual push: hook abort
+
+  $ cat << EOF >> $HGRCPATH
+  > [failpush]
+  > reason =
+  > [hooks]
+  > b2x-pretransactionclose.failpush = false
+  > EOF
+
+  $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+  $ 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
+  transaction abort!
+  rollback completed
+  abort: b2x-pretransactionclose.failpush 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
+  abort: b2x-pretransactionclose.failpush hook exited with status 1
+  remote: transaction abort!
+  remote: rollback completed
+  [255]
+
+  $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
+  pushing to http://localhost:$HGPORT2/
+  searching for changes
+  abort: b2x-pretransactionclose.failpush hook exited with status 1
+  [255]
+
+