Patchwork [3,of,4,V2] phase: add a dedicated txnclose-phase hook

login
register
mail settings
Submitter Boris Feld
Date Oct. 14, 2017, 3:46 p.m.
Message ID <06eeae1828afe149886e.1507995983@FB>
Download mbox | patch
Permalink /patch/24903/
State Accepted
Headers show

Comments

Boris Feld - Oct. 14, 2017, 3:46 p.m.
# HG changeset patch
# User Boris Feld <boris.feld@octobus.net>
# Date 1507477846 -7200
#      Sun Oct 08 17:50:46 2017 +0200
# Node ID 06eeae1828afe149886e18e6b4fc8180a3803fdb
# Parent  e1aa5834b2423fd04b32965075e5dee2204768c2
# EXP-Topic b2.phases.hooks
# Available At https://bitbucket.org/octobus/mercurial-devel/
#              hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 06eeae1828af
phase: add a dedicated txnclose-phase hook

The new 'txnclose-phase' hook expose the phase movement information stored in
'tr.changes['phases]'. To provide a simple and straightforward hook API to the
users, we introduce a new hook called for each revision affected.  Since a
transaction can affect the phase of multiple changesets, updating the existing
'txnclose' hook to expose that information would be more complex. The data for
all moves will not fit in environment variables and iterations over each move
would be cumbersome. So the introduction of a new dedicated hook is
preferred in this changesets.

This does not exclude the addition of the full phase movement information to
the existing 'txnclose' in the future to help write more complex hooks.

Patch

diff --git a/mercurial/help/config.txt b/mercurial/help/config.txt
--- a/mercurial/help/config.txt
+++ b/mercurial/help/config.txt
@@ -1002,6 +1002,16 @@ 
   is released. See :hg:`help config.hooks.pretxnclose-bookmark` for details
   about available variables.
 
+``txnclose-phase``
+  Run after any phase change has been committed. At this point, the
+  transaction can no longer be rolled back. The hook will run after the lock
+  is released.
+  The affected node is available in ``$HG_NODE``, the new phase will be
+  available in ``$HG_PHASE`` while the previous phase will be available in
+  ``$HG_OLDPHASE``. In case of new node, ``$HG_OLDPHASE`` will be empty.  In
+  addition, the reason for the transaction opening will be in ``$HG_TXNNAME``,
+  and a unique identifier for the transaction will be in ``HG_TXNID``.
+
 ``txnabort``
   Run when a transaction is aborted. See :hg:`help config.hooks.pretxnclose`
   for details about available variables.
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -1299,6 +1299,16 @@ 
                         repo.hook('txnclose-bookmark', throw=False,
                                   txnname=desc, **pycompat.strkwargs(args))
 
+                if hook.hashook(repo.ui, 'txnclose-phase'):
+                    cl = repo.unfiltered().changelog
+                    phasemv = sorted(tr.changes['phases'].items())
+                    for rev, (old, new) in phasemv:
+                        args = tr.hookargs.copy()
+                        node = hex(cl.node(rev))
+                        args.update(phases.preparehookargs(node, old, new))
+                        repo.hook('txnclose-phase', throw=False, txnname=desc,
+                                  **pycompat.strkwargs(args))
+
                 repo.hook('txnclose', throw=False, txnname=desc,
                           **pycompat.strkwargs(hookargs))
             reporef()._afterlock(hookfunc)
diff --git a/mercurial/phases.py b/mercurial/phases.py
--- a/mercurial/phases.py
+++ b/mercurial/phases.py
@@ -632,3 +632,12 @@ 
 def hassecret(repo):
     """utility function that check if a repo have any secret changeset."""
     return bool(repo._phasecache.phaseroots[2])
+
+def preparehookargs(node, old, new):
+    if old is None:
+        old = ''
+    else:
+        old = '%s' % old
+    return {'node': node,
+            'oldphase': old,
+            'phase': '%s' % new}
diff --git a/tests/test-phases.t b/tests/test-phases.t
--- a/tests/test-phases.t
+++ b/tests/test-phases.t
@@ -2,6 +2,8 @@ 
   $ cat >> $HGRCPATH << EOF
   > [extensions]
   > phasereport=$TESTDIR/testlib/ext-phase-report.py
+  > [hooks]
+  > txnclose-phase.test = echo "test-hook-close-phase: \$HG_NODE:  \$HG_OLDPHASE -> \$HG_PHASE"
   > EOF
 
   $ hglog() { hg log --template "{rev} {phaseidx} {desc}\n" $*; }
@@ -26,6 +28,7 @@ 
 
   $ mkcommit A
   test-debug-phase: new rev 0:  x -> 1
+  test-hook-close-phase: 4a2df7238c3b48766b5e22fafbb8a2f506ec8256:   -> 1
 
 New commit are draft by default
 
@@ -36,6 +39,7 @@ 
 
   $ mkcommit B
   test-debug-phase: new rev 1:  x -> 1
+  test-hook-close-phase: 27547f69f25460a52fff66ad004e58da7ad3fb56:   -> 1
 
   $ hglog
   1 1 B
@@ -46,6 +50,8 @@ 
   $ hg phase --public .
   test-debug-phase: move rev 0: 1 -> 0
   test-debug-phase: move rev 1: 1 -> 0
+  test-hook-close-phase: 4a2df7238c3b48766b5e22fafbb8a2f506ec8256:  1 -> 0
+  test-hook-close-phase: 27547f69f25460a52fff66ad004e58da7ad3fb56:  1 -> 0
   $ hg phase
   1: public
   $ hglog
@@ -54,8 +60,10 @@ 
 
   $ mkcommit C
   test-debug-phase: new rev 2:  x -> 1
+  test-hook-close-phase: f838bfaca5c7226600ebcfd84f3c3c13a28d3757:   -> 1
   $ mkcommit D
   test-debug-phase: new rev 3:  x -> 1
+  test-hook-close-phase: b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e:   -> 1
 
   $ hglog
   3 1 D
@@ -67,6 +75,7 @@ 
 
   $ mkcommit E --config phases.new-commit='secret'
   test-debug-phase: new rev 4:  x -> 2
+  test-hook-close-phase: a603bfb5a83e312131cebcd05353c217d4d21dde:   -> 2
   $ hglog
   4 2 E
   3 1 D
@@ -78,6 +87,7 @@ 
 
   $ mkcommit H
   test-debug-phase: new rev 5:  x -> 2
+  test-hook-close-phase: a030c6be5127abc010fcbff1851536552e6951a8:   -> 2
   $ hglog
   5 2 H
   4 2 E
@@ -92,6 +102,7 @@ 
   $ mkcommit "B'"
   test-debug-phase: new rev 6:  x -> 1
   created new head
+  test-hook-close-phase: cf9fe039dfd67e829edf6522a45de057b5c86519:   -> 1
   $ hglog
   6 1 B'
   5 2 H
@@ -108,6 +119,7 @@ 
   4: secret
   $ hg ci -m "merge B' and E"
   test-debug-phase: new rev 7:  x -> 2
+  test-hook-close-phase: 17a481b3bccb796c0521ae97903d81c52bfee4af:   -> 2
 
   $ hglog
   7 2 merge B' and E
@@ -155,6 +167,11 @@ 
   test-debug-phase: new rev 2:  x -> 1
   test-debug-phase: new rev 3:  x -> 1
   test-debug-phase: new rev 4:  x -> 1
+  test-hook-close-phase: 4a2df7238c3b48766b5e22fafbb8a2f506ec8256:   -> 0
+  test-hook-close-phase: 27547f69f25460a52fff66ad004e58da7ad3fb56:   -> 0
+  test-hook-close-phase: f838bfaca5c7226600ebcfd84f3c3c13a28d3757:   -> 1
+  test-hook-close-phase: b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e:   -> 1
+  test-hook-close-phase: cf9fe039dfd67e829edf6522a45de057b5c86519:   -> 1
   $ hglog
   7 2 merge B' and E
   6 1 B'
@@ -181,6 +198,7 @@ 
   $ hg up -q 4 # B'
   $ mkcommit Z --config phases.new-commit=secret
   test-debug-phase: new rev 5:  x -> 2
+  test-hook-close-phase: 2713879da13d6eea1ff22b442a5a87cb31a7ce6a:   -> 2
   $ hg phase .
   5: secret
 
@@ -192,6 +210,7 @@ 
   $ mkcommit I
   test-debug-phase: new rev 8:  x -> 1
   created new head
+  test-hook-close-phase: 6d6770faffce199f1fddd1cf87f6f026138cf061:   -> 1
   $ hg push ../push-dest
   pushing to ../push-dest
   searching for changes
@@ -200,6 +219,7 @@ 
   adding file changes
   added 1 changesets with 1 changes to 1 files (+1 heads)
   test-debug-phase: new rev 6:  x -> 1
+  test-hook-close-phase: 6d6770faffce199f1fddd1cf87f6f026138cf061:   -> 1
 
 :note: The "(+1 heads)" is wrong as we do not had any visible head
 
@@ -253,6 +273,11 @@ 
   test-debug-phase: new rev 2:  x -> 0
   test-debug-phase: new rev 3:  x -> 0
   test-debug-phase: new rev 4:  x -> 0
+  test-hook-close-phase: 4a2df7238c3b48766b5e22fafbb8a2f506ec8256:   -> 0
+  test-hook-close-phase: 27547f69f25460a52fff66ad004e58da7ad3fb56:   -> 0
+  test-hook-close-phase: f838bfaca5c7226600ebcfd84f3c3c13a28d3757:   -> 0
+  test-hook-close-phase: b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e:   -> 0
+  test-hook-close-phase: cf9fe039dfd67e829edf6522a45de057b5c86519:   -> 0
   (run 'hg heads' to see heads, 'hg merge' to merge)
   $ hglog
   4 0 B'
@@ -278,6 +303,11 @@ 
   test-debug-phase: new rev 2:  x -> 0
   test-debug-phase: new rev 3:  x -> 0
   test-debug-phase: new rev 4:  x -> 0
+  test-hook-close-phase: 4a2df7238c3b48766b5e22fafbb8a2f506ec8256:   -> 0
+  test-hook-close-phase: 27547f69f25460a52fff66ad004e58da7ad3fb56:   -> 0
+  test-hook-close-phase: f838bfaca5c7226600ebcfd84f3c3c13a28d3757:   -> 0
+  test-hook-close-phase: b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e:   -> 0
+  test-hook-close-phase: cf9fe039dfd67e829edf6522a45de057b5c86519:   -> 0
   $ hglog -R clone-dest
   4 0 B'
   3 0 D
@@ -477,6 +507,7 @@ 
 
   $ hg phase --public -r 2
   test-debug-phase: move rev 2: 1 -> 0
+  test-hook-close-phase: f838bfaca5c7226600ebcfd84f3c3c13a28d3757:  1 -> 0
   $ hg log -G --template "{rev} {phase} {desc}\n"
   @    7 secret merge B' and E
   |\
@@ -501,6 +532,7 @@ 
 
   $ hg phase --draft --force 2
   test-debug-phase: move rev 2: 0 -> 1
+  test-hook-close-phase: f838bfaca5c7226600ebcfd84f3c3c13a28d3757:  0 -> 1
   $ hg log -G --template "{rev} {phase} {desc}\n"
   @    7 secret merge B' and E
   |\
@@ -524,6 +556,8 @@ 
   $ hg phase --draft --force 1::4
   test-debug-phase: move rev 1: 0 -> 1
   test-debug-phase: move rev 4: 2 -> 1
+  test-hook-close-phase: 27547f69f25460a52fff66ad004e58da7ad3fb56:  0 -> 1
+  test-hook-close-phase: a603bfb5a83e312131cebcd05353c217d4d21dde:  2 -> 1
   $ hg log -G --template "{rev} {phase} {desc}\n"
   @    7 secret merge B' and E
   |\
@@ -550,8 +584,15 @@ 
   test-debug-phase: move rev 4: 1 -> 0
   test-debug-phase: move rev 6: 1 -> 0
   test-debug-phase: move rev 7: 2 -> 0
+  test-hook-close-phase: 27547f69f25460a52fff66ad004e58da7ad3fb56:  1 -> 0
+  test-hook-close-phase: f838bfaca5c7226600ebcfd84f3c3c13a28d3757:  1 -> 0
+  test-hook-close-phase: b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e:  1 -> 0
+  test-hook-close-phase: a603bfb5a83e312131cebcd05353c217d4d21dde:  1 -> 0
+  test-hook-close-phase: cf9fe039dfd67e829edf6522a45de057b5c86519:  1 -> 0
+  test-hook-close-phase: 17a481b3bccb796c0521ae97903d81c52bfee4af:  2 -> 0
   $ hg phase --draft '5 or 7'
   test-debug-phase: move rev 5: 2 -> 1
+  test-hook-close-phase: a030c6be5127abc010fcbff1851536552e6951a8:  2 -> 1
   cannot move 1 changesets to a higher phase, use --force
   phase changed for 1 changesets
   [1]
@@ -611,6 +652,13 @@ 
   test-debug-phase: new rev 4:  x -> 0
   test-debug-phase: new rev 5:  x -> 0
   test-debug-phase: new rev 6:  x -> 0
+  test-hook-close-phase: 4a2df7238c3b48766b5e22fafbb8a2f506ec8256:   -> 0
+  test-hook-close-phase: 27547f69f25460a52fff66ad004e58da7ad3fb56:   -> 0
+  test-hook-close-phase: f838bfaca5c7226600ebcfd84f3c3c13a28d3757:   -> 0
+  test-hook-close-phase: b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e:   -> 0
+  test-hook-close-phase: a603bfb5a83e312131cebcd05353c217d4d21dde:   -> 0
+  test-hook-close-phase: cf9fe039dfd67e829edf6522a45de057b5c86519:   -> 0
+  test-hook-close-phase: 17a481b3bccb796c0521ae97903d81c52bfee4af:   -> 0
   updating to branch default
   6 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ cd clonewithobs
diff --git a/tests/test-push-http.t b/tests/test-push-http.t
--- a/tests/test-push-http.t
+++ b/tests/test-push-http.t
@@ -61,6 +61,7 @@ 
   > [hooks]
   > changegroup = sh -c "printenv.py changegroup 0"
   > pushkey = sh -c "printenv.py pushkey 0"
+  > txnclose-phase.test = echo "phase-move: \$HG_NODE:  \$HG_OLDPHASE -> \$HG_PHASE"
   > EOF
   $ req
   pushing to http://localhost:$HGPORT/
@@ -70,6 +71,8 @@ 
   remote: adding file changes
   remote: added 1 changesets with 1 changes to 1 files
   remote: pushkey hook: HG_HOOKNAME=pushkey HG_HOOKTYPE=pushkey HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_OLD=1 HG_RET=1
+  remote: phase-move: cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b:  1 -> 0
+  remote: phase-move: ba677d0156c1196c1a699fa53f390dcfc3ce3872:   -> 0
   remote: changegroup hook: HG_BUNDLE2=1 HG_HOOKNAME=changegroup HG_HOOKTYPE=changegroup HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:http:$LOCALIP: (glob)
   % serve errors
   $ hg rollback
@@ -87,6 +90,8 @@ 
   remote: adding file changes
   remote: added 1 changesets with 1 changes to 1 files
   remote: pushkey hook: HG_HOOKNAME=pushkey HG_HOOKTYPE=pushkey HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_OLD=1 HG_RET=1
+  remote: phase-move: cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b:  1 -> 0
+  remote: phase-move: ba677d0156c1196c1a699fa53f390dcfc3ce3872:   -> 0
   remote: changegroup hook: HG_BUNDLE2=1 HG_HOOKNAME=changegroup HG_HOOKTYPE=changegroup HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:http:$LOCALIP: (glob)
   % serve errors
   $ hg rollback
@@ -104,6 +109,8 @@ 
   remote: adding file changes
   remote: added 1 changesets with 1 changes to 1 files
   remote: pushkey hook: HG_HOOKNAME=pushkey HG_HOOKTYPE=pushkey HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_OLD=1 HG_RET=1
+  remote: phase-move: cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b:  1 -> 0
+  remote: phase-move: ba677d0156c1196c1a699fa53f390dcfc3ce3872:   -> 0
   remote: changegroup hook: HG_BUNDLE2=1 HG_HOOKNAME=changegroup HG_HOOKTYPE=changegroup HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:http:$LOCALIP: (glob)
   % serve errors
   $ hg rollback