Patchwork [4,of,4,RFC] hook: add a generic hook right before we commit a transaction

login
register
mail settings
Submitter Pierre-Yves David
Date March 10, 2015, 8:07 a.m.
Message ID <4ad191c38fbc3ba7f021.1425974836@marginatus.alto.octopoid.net>
Download mbox | patch
Permalink /patch/7963/
State Superseded
Commit ff14b26fe5f4269c41c1b70372ca2485cefaec25
Headers show

Comments

Pierre-Yves David - March 10, 2015, 8:07 a.m.
# HG changeset patch
# User Pierre-Yves David <pierre-yves.david@fb.com>
# Date 1425966649 25200
#      Mon Mar 09 22:50:49 2015 -0700
# Node ID 4ad191c38fbc3ba7f0218c4fdd035ec10ef69082
# Parent  d3bb13fe8ffe090f13b6f66cf437333c468c8b0a
hook: add a generic hook right before we commit a transaction

We are adding a 'txnclosing' hook that will be run right before a transaction is
close. Hooks running at that time will have access to the full transaction
content through both 'hookargs' content and on disk reading. They will be able
to abort the transaction.

Patch

diff --git a/mercurial/help/config.txt b/mercurial/help/config.txt
--- a/mercurial/help/config.txt
+++ b/mercurial/help/config.txt
@@ -810,19 +810,27 @@  variables it is passed are listed with n
 
 ``txnopen``
   Run before any new repository transaction is open. Reason for the transaction
   opening will be in ``$HG_TXNNAME``. This hook can abort transaction opening.
 
-``txnclosed``
-  Run after any transaction have been commited. The transaction cannot be
-  aborted at this point. The hook will run after the lock is released. Reason
+``txnclosing``
+  Run right before that transaction is actually commited for good. Any
+  repository change will be visible to the hook program. This lets you validate
+  the transaction content or changes it. Exit status 0 allows the commit to
+  proceed. Non-zero status will cause the transaction to be rolled back. Reason
   for the transaction opening will be in ``$HG_TXNNAME``. The rest of the
   available data will vary according the event who append during the
   transaction. New changesets will add ``$HG_NODE`` (id of the first added
   changesets, ``$HG_URL`` and ``$HG_SOURCE`` variables, bookmark and phases
   changes will set ``HG_BOOKMARK_MOVED`` and ``HG_PHASES_MOVED`` to ``1``, etc
 
+``txnclosed``
+  Run after any transaction have been commited. The transaction cannot be
+  aborted at this point. The hook will run after the lock is released. Reason
+  for the transaction opening will be in ``$HG_TXNNAME``, see ``txnclosing``
+  docs for details on other variables.
+
 ``pretxnchangegroup``
   Run after a changegroup has been added via push, pull or unbundle,
   but before the transaction has been committed. Changegroup is
   visible to hook program. This lets you validate incoming changes
   before accepting them. Passed the ID of the first new changeset in
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -912,21 +912,28 @@  class localrepository(object):
 
         self._writejournal(desc)
         renames = [(vfs, x, undoname(x)) for vfs, x in self._journalfiles()]
         rp = report and report or self.ui.warn
         vfsmap = {'plain': self.vfs} # root of .hg/
-        tr = transaction.transaction(rp, self.svfs, vfsmap,
+        # we must avoid cyclic reference between repo and transaction.
+        reporef = weakref.ref(self)
+        def validate(tr):
+            """will run pre-closing hooks"""
+            pending = lambda: tr.writepending() and self.root or ""
+            reporef().hook('txnclosing', throw=True, pending=pending,
+                           xnname=desc)
+
+        tr = transaction.transaction(rp, self.sopener, vfsmap,
                                      "journal",
                                      "undo",
                                      aftertrans(renames),
-                                     self.store.createmode)
+                                     self.store.createmode,
+                                     validator=validate)
         # note: writing the fncache only during finalize mean that the file is
         # outdated when running hooks. As fncache is used for streaming clone,
         # this is not expected to break anything that happen during the hooks.
         tr.addfinalize('flush-fncache', self.store.write)
-        # we must avoid cyclic reference between repo and transaction.
-        reporef = weakref.ref(self)
         def txnclosedhook(tr2):
             """To be run if transaction is successful, will schedule a hook run
             """
             def hook():
                 reporef().hook('txnclosed', throw=False, txnname=desc,
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
@@ -23,56 +23,70 @@  enable obsolescence
   > push_ssl = false
   > allow_push = *
   > [phases]
   > publish=False
   > [hooks]
-  > changegroup = sh -c  "HG_LOCAL= python \"$TESTDIR/printenv.py\" changegroup"
-  > b2x-pretransactionclose.tip = hg log -r tip -T "pre-close-tip:{node|short} {phase} {bookmarks}\n"
-  > b2x-transactionclose.tip = hg log -r tip -T "postclose-tip:{node|short} {phase} {bookmarks}\n"
-  > b2x-transactionclose.env = sh -c  "HG_LOCAL= python \"$TESTDIR/printenv.py\" b2x-transactionclose"
+  > txnclosing.tip = hg log -r tip -T "pre-close-tip:{node|short} {phase} {bookmarks}\n"
+  > txnclosed.tip = hg log -r tip -T "postclose-tip:{node|short} {phase} {bookmarks}\n"
+  > txnclosed.env = sh -c  "HG_LOCAL= python \"$TESTDIR/printenv.py\" txnclosed"
   > pushkey= sh "$TESTTMP/bundle2-pushkey-hook.sh"
   > EOF
 
 The extension requires a repo (currently unused)
 
   $ hg init main
   $ cd main
   $ touch a
   $ hg add a
   $ hg commit -m 'a'
+  pre-close-tip:3903775176ed draft 
+  postclose-tip:3903775176ed draft 
+  txnclosed hook: HG_PHASES_MOVED=1 HG_TXNNAME=commit
 
   $ hg unbundle $TESTDIR/bundles/rebase.hg
   adding changesets
   adding manifests
   adding file changes
   added 8 changesets with 7 changes to 7 files (+3 heads)
-  changegroup hook: HG_NODE=cd010b8cd998f3981a5a8115f94f8da4ab506089 HG_SOURCE=unbundle HG_URL=bundle:*/rebase.hg (glob)
+  pre-close-tip:02de42196ebe draft 
+  postclose-tip:02de42196ebe draft 
+  txnclosed hook: HG_NODE=cd010b8cd998f3981a5a8115f94f8da4ab506089 HG_PHASES_MOVED=1 HG_SOURCE=unbundle HG_TXNNAME=unbundle
+  bundle:*/tests/bundles/rebase.hg HG_URL=bundle:*/tests/bundles/rebase.hg (glob)
   (run 'hg heads' to see heads, 'hg merge' to merge)
 
   $ cd ..
 
 Real world exchange
 =====================
 
 Add more obsolescence information
 
   $ hg -R main debugobsolete -d '0 0' 1111111111111111111111111111111111111111 `getmainid 9520eea781bc`
+  pre-close-tip:02de42196ebe draft 
+  postclose-tip:02de42196ebe draft 
+  txnclosed hook: HG_NEW_OBSMARKERS=1 HG_TXNNAME=debugobsolete
   $ hg -R main debugobsolete -d '0 0' 2222222222222222222222222222222222222222 `getmainid 24b6387c8c8c`
+  pre-close-tip:02de42196ebe draft 
+  postclose-tip:02de42196ebe draft 
+  txnclosed hook: HG_NEW_OBSMARKERS=1 HG_TXNNAME=debugobsolete
 
 clone --pull
 
   $ hg -R main phase --public cd010b8cd998
+  pre-close-tip:000000000000 public 
+  postclose-tip:02de42196ebe draft 
+  txnclosed hook: HG_PHASES_MOVED=1 HG_TXNNAME=phase
   $ hg clone main other --pull --rev 9520eea781bc
   adding changesets
   adding manifests
   adding file changes
   added 2 changesets with 2 changes to 2 files
   1 new obsolescence markers
   pre-close-tip:9520eea781bc draft 
   postclose-tip:9520eea781bc draft 
-  b2x-transactionclose hook: HG_NEW_OBSMARKERS=1 HG_NODE=cd010b8cd998f3981a5a8115f94f8da4ab506089 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_URL=file:$TESTTMP/main
-  changegroup hook: HG_NODE=cd010b8cd998f3981a5a8115f94f8da4ab506089 HG_SOURCE=pull HG_URL=file:$TESTTMP/main
+  txnclosed hook: HG_NEW_OBSMARKERS=1 HG_NODE=cd010b8cd998f3981a5a8115f94f8da4ab506089 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNNAME=pull
+  file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
   updating to branch default
   2 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg -R other log -G
   @  1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com>  E
   |
@@ -82,22 +96,25 @@  clone --pull
   1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
 
 pull
 
   $ hg -R main phase --public 9520eea781bc
+  pre-close-tip:000000000000 public 
+  postclose-tip:02de42196ebe draft 
+  txnclosed hook: HG_PHASES_MOVED=1 HG_TXNNAME=phase
   $ hg -R other pull -r 24b6387c8c8c
   pulling from $TESTTMP/main (glob)
   searching for changes
   adding changesets
   adding manifests
   adding file changes
   added 1 changesets with 1 changes to 1 files (+1 heads)
   1 new obsolescence markers
   pre-close-tip:24b6387c8c8c draft 
   postclose-tip:24b6387c8c8c draft 
-  b2x-transactionclose hook: HG_NEW_OBSMARKERS=1 HG_NODE=24b6387c8c8cae37178880f3fa95ded3cb1cf785 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_URL=file:$TESTTMP/main
-  changegroup hook: HG_NODE=24b6387c8c8cae37178880f3fa95ded3cb1cf785 HG_SOURCE=pull HG_URL=file:$TESTTMP/main
+  txnclosed hook: HG_NEW_OBSMARKERS=1 HG_NODE=24b6387c8c8cae37178880f3fa95ded3cb1cf785 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNNAME=pull
+  file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
   (run 'hg heads' to see heads, 'hg merge' to merge)
   $ hg -R other log -G
   o  2:24b6387c8c8c draft Nicolas Dumazet <nicdumz.commits@gmail.com>  F
   |
   | @  1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com>  E
@@ -109,16 +126,20 @@  pull
   2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
 
 pull empty (with phase movement)
 
   $ hg -R main phase --public 24b6387c8c8c
+  pre-close-tip:000000000000 public 
+  postclose-tip:02de42196ebe draft 
+  txnclosed hook: HG_PHASES_MOVED=1 HG_TXNNAME=phase
   $ hg -R other pull -r 24b6387c8c8c
   pulling from $TESTTMP/main (glob)
   no changes found
   pre-close-tip:000000000000 public 
   postclose-tip:24b6387c8c8c public 
-  b2x-transactionclose hook: HG_NEW_OBSMARKERS=0 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_URL=file:$TESTTMP/main
+  txnclosed hook: HG_NEW_OBSMARKERS=0 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNNAME=pull
+  file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
   $ hg -R other log -G
   o  2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com>  F
   |
   | @  1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com>  E
   |/
@@ -133,11 +154,12 @@  pull empty
   $ hg -R other pull -r 24b6387c8c8c
   pulling from $TESTTMP/main (glob)
   no changes found
   pre-close-tip:24b6387c8c8c public 
   postclose-tip:24b6387c8c8c public 
-  b2x-transactionclose hook: HG_NEW_OBSMARKERS=0 HG_SOURCE=pull HG_URL=file:$TESTTMP/main
+  txnclosed hook: HG_NEW_OBSMARKERS=0 HG_SOURCE=pull HG_TXNNAME=pull
+  file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
   $ hg -R other log -G
   o  2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com>  F
   |
   | @  1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com>  E
   |/
@@ -149,26 +171,44 @@  pull empty
 
 add extra data to test their exchange during push
 
   $ hg -R main bookmark --rev eea13746799a book_eea1
   $ hg -R main debugobsolete -d '0 0' 3333333333333333333333333333333333333333 `getmainid eea13746799a`
+  pre-close-tip:02de42196ebe draft 
+  postclose-tip:02de42196ebe draft 
+  txnclosed hook: HG_NEW_OBSMARKERS=1 HG_TXNNAME=debugobsolete
   $ hg -R main bookmark --rev 02de42196ebe book_02de
   $ hg -R main debugobsolete -d '0 0' 4444444444444444444444444444444444444444 `getmainid 02de42196ebe`
+  pre-close-tip:02de42196ebe draft book_02de
+  postclose-tip:02de42196ebe draft book_02de
+  txnclosed hook: HG_NEW_OBSMARKERS=1 HG_TXNNAME=debugobsolete
   $ hg -R main bookmark --rev 42ccdea3bb16 book_42cc
   $ hg -R main debugobsolete -d '0 0' 5555555555555555555555555555555555555555 `getmainid 42ccdea3bb16`
+  pre-close-tip:02de42196ebe draft book_02de
+  postclose-tip:02de42196ebe draft book_02de
+  txnclosed hook: HG_NEW_OBSMARKERS=1 HG_TXNNAME=debugobsolete
   $ hg -R main bookmark --rev 5fddd98957c8 book_5fdd
   $ hg -R main debugobsolete -d '0 0' 6666666666666666666666666666666666666666 `getmainid 5fddd98957c8`
+  pre-close-tip:02de42196ebe draft book_02de
+  postclose-tip:02de42196ebe draft book_02de
+  txnclosed hook: HG_NEW_OBSMARKERS=1 HG_TXNNAME=debugobsolete
   $ hg -R main bookmark --rev 32af7686d403 book_32af
   $ hg -R main debugobsolete -d '0 0' 7777777777777777777777777777777777777777 `getmainid 32af7686d403`
+  pre-close-tip:02de42196ebe draft book_02de
+  postclose-tip:02de42196ebe draft book_02de
+  txnclosed hook: HG_NEW_OBSMARKERS=1 HG_TXNNAME=debugobsolete
 
   $ hg -R other bookmark --rev cd010b8cd998 book_eea1
   $ hg -R other bookmark --rev cd010b8cd998 book_02de
   $ hg -R other bookmark --rev cd010b8cd998 book_42cc
   $ hg -R other bookmark --rev cd010b8cd998 book_5fdd
   $ hg -R other bookmark --rev cd010b8cd998 book_32af
 
   $ hg -R main phase --public eea13746799a
+  pre-close-tip:000000000000 public 
+  postclose-tip:02de42196ebe draft book_02de
+  txnclosed hook: HG_PHASES_MOVED=1 HG_TXNNAME=phase
 
 push
   $ hg -R main push other --rev eea13746799a --bookmark book_eea1
   pushing to other
   searching for changes
@@ -178,21 +218,21 @@  push
   wlock: free
   pushkey: lock state after "bookmarks"
   lock:  free
   wlock: free
   postclose-tip:eea13746799a public book_eea1
-  b2x-transactionclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2-EXP=1 HG_NEW_OBSMARKERS=1 HG_NODE=eea13746799a9e0bfd88f29d3c2e9dc9389f524f HG_PHASES_MOVED=1 HG_SOURCE=push HG_URL=push
-  changegroup hook: HG_BUNDLE2-EXP=1 HG_NODE=eea13746799a9e0bfd88f29d3c2e9dc9389f524f HG_SOURCE=push HG_URL=push
+  txnclosed hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2-EXP=1 HG_NEW_OBSMARKERS=1 HG_NODE=eea13746799a9e0bfd88f29d3c2e9dc9389f524f HG_PHASES_MOVED=1 HG_SOURCE=push HG_TXNNAME=unbundle HG_URL=push
   remote: adding changesets
   remote: adding manifests
   remote: adding file changes
   remote: added 1 changesets with 0 changes to 0 files (-1 heads)
   remote: 1 new obsolescence markers
   updating bookmark book_eea1
   pre-close-tip:02de42196ebe draft book_02de
   postclose-tip:02de42196ebe draft book_02de
-  b2x-transactionclose hook: HG_SOURCE=push-response HG_URL=file:$TESTTMP/other
+  txnclosed hook: HG_SOURCE=push-response HG_TXNNAME=push-response
+  file:/*/$TESTTMP/other HG_URL=file:$TESTTMP/other (glob)
   $ hg -R other log -G
   o    3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
   |\
   | o  2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com>  F
   | |
@@ -216,12 +256,12 @@  pull over ssh
   added 1 changesets with 1 changes to 1 files (+1 heads)
   1 new obsolescence markers
   updating bookmark book_02de
   pre-close-tip:02de42196ebe draft book_02de
   postclose-tip:02de42196ebe draft book_02de
-  b2x-transactionclose hook: HG_BOOKMARK_MOVED=1 HG_NEW_OBSMARKERS=1 HG_NODE=02de42196ebee42ef284b6780a87cdc96e8eaab6 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_URL=ssh://user@dummy/main
-  changegroup hook: HG_NODE=02de42196ebee42ef284b6780a87cdc96e8eaab6 HG_SOURCE=pull HG_URL=ssh://user@dummy/main
+  txnclosed hook: HG_BOOKMARK_MOVED=1 HG_NEW_OBSMARKERS=1 HG_NODE=02de42196ebee42ef284b6780a87cdc96e8eaab6 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNNAME=pull
+  ssh://user@dummy/main HG_URL=ssh://user@dummy/main
   (run 'hg heads' to see heads, 'hg merge' to merge)
   $ hg -R other debugobsolete
   1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
   2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
   3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
@@ -241,12 +281,12 @@  pull over http
   added 1 changesets with 1 changes to 1 files (+1 heads)
   1 new obsolescence markers
   updating bookmark book_42cc
   pre-close-tip:42ccdea3bb16 draft book_42cc
   postclose-tip:42ccdea3bb16 draft book_42cc
-  b2x-transactionclose hook: HG_BOOKMARK_MOVED=1 HG_NEW_OBSMARKERS=1 HG_NODE=42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_URL=http://localhost:$HGPORT/
-  changegroup hook: HG_NODE=42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 HG_SOURCE=pull HG_URL=http://localhost:$HGPORT/
+  txnclosed hook: HG_BOOKMARK_MOVED=1 HG_NEW_OBSMARKERS=1 HG_NODE=42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNNAME=pull
+  http://localhost:$HGPORT/ HG_URL=http://localhost:$HGPORT/
   (run 'hg heads .' to see heads, 'hg merge' to merge)
   $ cat main-error.log
   $ hg -R other debugobsolete
   1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
   2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
@@ -268,15 +308,15 @@  push over ssh
   remote: pre-close-tip:5fddd98957c8 draft book_5fdd
   remote: pushkey: lock state after "bookmarks"
   remote: lock:  free
   remote: wlock: free
   remote: postclose-tip:5fddd98957c8 draft book_5fdd
-  remote: b2x-transactionclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2-EXP=1 HG_NEW_OBSMARKERS=1 HG_NODE=5fddd98957c8a54a4d436dfe1da9d87f21a1b97b HG_SOURCE=serve HG_URL=remote:ssh:127.0.0.1
-  remote: changegroup hook: HG_BUNDLE2-EXP=1 HG_NODE=5fddd98957c8a54a4d436dfe1da9d87f21a1b97b HG_SOURCE=serve HG_URL=remote:ssh:127.0.0.1
+  remote: txnclosed hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2-EXP=1 HG_NEW_OBSMARKERS=1 HG_NODE=5fddd98957c8a54a4d436dfe1da9d87f21a1b97b HG_SOURCE=serve HG_TXNNAME=unbundle HG_URL=remote:ssh:127.0.0.1
   pre-close-tip:02de42196ebe draft book_02de
   postclose-tip:02de42196ebe draft book_02de
-  b2x-transactionclose hook: HG_SOURCE=push-response HG_URL=ssh://user@dummy/other
+  txnclosed hook: HG_SOURCE=push-response HG_TXNNAME=push-response
+  ssh://user@dummy/other HG_URL=ssh://user@dummy/other
   $ hg -R other log -G
   o  6:5fddd98957c8 draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_5fdd C
   |
   o  5:42ccdea3bb16 draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_42cc B
   |
@@ -302,10 +342,13 @@  push over http
 
   $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
   $ cat other.pid >> $DAEMON_PIDS
 
   $ hg -R main phase --public 32af7686d403
+  pre-close-tip:000000000000 public 
+  postclose-tip:02de42196ebe draft book_02de
+  txnclosed hook: HG_PHASES_MOVED=1 HG_TXNNAME=phase
   $ hg -R main push http://localhost:$HGPORT2/ -r 32af7686d403 --bookmark book_32af
   pushing to http://localhost:$HGPORT2/
   searching for changes
   remote: adding changesets
   remote: adding manifests
@@ -313,11 +356,12 @@  push over http
   remote: added 1 changesets with 1 changes to 1 files
   remote: 1 new obsolescence markers
   updating bookmark book_32af
   pre-close-tip:02de42196ebe draft book_02de
   postclose-tip:02de42196ebe draft book_02de
-  b2x-transactionclose hook: HG_SOURCE=push-response HG_URL=http://localhost:$HGPORT2/
+  txnclosed hook: HG_SOURCE=push-response HG_TXNNAME=push-response
+  http://localhost:$HGPORT2/ HG_URL=http://localhost:$HGPORT2/
   $ cat other-error.log
 
 Check final content.
 
   $ hg -R other log -G
@@ -398,10 +442,13 @@  Setting up
   $ hg up tip
   3 files updated, 0 files merged, 1 files removed, 0 files unresolved
   $ echo 'I' > I
   $ hg add I
   $ hg ci -m 'I'
+  pre-close-tip:e7ec4e813ba6 draft 
+  postclose-tip:e7ec4e813ba6 draft 
+  txnclosed hook: HG_TXNNAME=commit
   $ hg id
   e7ec4e813ba6 tip
   $ cd ..
 
   $ cat << EOF >> $HGRCPATH
@@ -499,11 +546,11 @@  Doing the actual push: hook abort
 
   $ cat << EOF >> $HGRCPATH
   > [failpush]
   > reason =
   > [hooks]
-  > b2x-pretransactionclose.failpush = false
+  > txnclosing.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
@@ -512,26 +559,26 @@  Doing the actual push: hook abort
   pushing to other
   searching for changes
   pre-close-tip:e7ec4e813ba6 draft 
   transaction abort!
   rollback completed
-  abort: b2x-pretransactionclose.failpush hook exited with status 1
+  abort: txnclosing.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
+  abort: txnclosing.failpush hook exited with status 1
   remote: pre-close-tip:e7ec4e813ba6 draft 
   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
+  abort: txnclosing.failpush hook exited with status 1
   [255]
 
 (check that no 'pending' files remain)
 
   $ ls -1 other/.hg/bookmarks*
diff --git a/tests/test-hook.t b/tests/test-hook.t
--- a/tests/test-hook.t
+++ b/tests/test-hook.t
@@ -11,19 +11,21 @@  commit hooks can see env vars
   > pretxncommit.tip = hg -q tip
   > pre-identify = python "$TESTDIR/printenv.py" pre-identify 1
   > pre-cat = python "$TESTDIR/printenv.py" pre-cat
   > post-cat = python "$TESTDIR/printenv.py" post-cat
   > txnopen = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" txnopen"
+  > txnclosing = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" txnclosing"
   > txnclosed = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" txnclosed"
   > EOF
   $ echo a > a
   $ hg add a
   $ hg commit -m a
   precommit hook: HG_PARENT1=0000000000000000000000000000000000000000
   txnopen hook: HG_TXNNAME=commit
   pretxncommit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000 HG_PENDING=$TESTTMP/a
   0:cb9a9f314b8b
+  txnclosing hook: HG_PENDING=$TESTTMP/a HG_XNNAME=commit
   txnclosed hook: HG_PHASES_MOVED=1 HG_TXNNAME=commit
   commit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
   commit.b hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
 
   $ hg clone . ../b
@@ -47,10 +49,11 @@  pretxncommit and commit hooks can see bo
   $ hg commit -m a1 -d "1 0"
   precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
   txnopen hook: HG_TXNNAME=commit
   pretxncommit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
   1:ab228980c14d
+  txnclosing hook: HG_PENDING=$TESTTMP/a HG_XNNAME=commit
   txnclosed hook: HG_TXNNAME=commit
   commit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
   commit.b hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
   $ hg update -C 0
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
@@ -59,10 +62,11 @@  pretxncommit and commit hooks can see bo
   $ hg commit -m b -d '1 0'
   precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
   txnopen hook: HG_TXNNAME=commit
   pretxncommit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
   2:ee9deb46ab31
+  txnclosing hook: HG_PENDING=$TESTTMP/a HG_XNNAME=commit
   txnclosed hook: HG_TXNNAME=commit
   commit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
   commit.b hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
   created new head
   $ hg merge 1
@@ -71,10 +75,11 @@  pretxncommit and commit hooks can see bo
   $ hg commit -m merge -d '2 0'
   precommit hook: HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
   txnopen hook: HG_TXNNAME=commit
   pretxncommit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd HG_PENDING=$TESTTMP/a
   3:07f3376c1e65
+  txnclosing hook: HG_PENDING=$TESTTMP/a HG_XNNAME=commit
   txnclosed hook: HG_TXNNAME=commit
   commit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
   commit.b hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
 
 test generic hooks
@@ -114,10 +119,11 @@  tag hooks can see env vars
   pretag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
   precommit hook: HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
   txnopen hook: HG_TXNNAME=commit
   pretxncommit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PENDING=$TESTTMP/a
   4:539e4b31b6dc
+  txnclosing hook: HG_PENDING=$TESTTMP/a HG_XNNAME=commit
   tag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
   txnclosed hook: HG_TXNNAME=commit
   commit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
   commit.b hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
   $ hg tag -l la
@@ -210,10 +216,11 @@  pushkey hook
   $ hg push -B foo ../a
   pushing to ../a
   searching for changes
   no changes found
   txnopen hook: HG_TXNNAME=bookmarks
+  txnclosing hook: HG_PENDING=$TESTTMP/a HG_XNNAME=bookmarks
   txnclosed hook: HG_BOOKMARK_MOVED=1 HG_TXNNAME=bookmarks
   pushkey hook: HG_KEY=foo HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_RET=1
   exporting bookmark foo
   [1]
   $ cd ../a