changeset 15896:30c34fde40cc

hooks: prioritize run order of hooks As of Mercurial 1.3, hooks are sorted in the order they are read into Mercurial. There are many instances when someone may want the hooks sorted in a specific order; this patch allows prioritizing hooks, while maintaining the existing enumeration for hooks without a priority.
author Matt Zuba <matt.zuba@goodwillaz.org>
date Sun, 15 Jan 2012 13:50:12 -0700
parents 933b9ff73750
children cc021114fc98
files mercurial/help/config.txt mercurial/hook.py tests/test-hook.t
diffstat 3 files changed, 31 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/help/config.txt	Sun Jan 15 18:00:01 2012 -0600
+++ b/mercurial/help/config.txt	Sun Jan 15 13:50:12 2012 -0700
@@ -655,7 +655,10 @@
 various actions such as starting or finishing a commit. Multiple
 hooks can be run for the same action by appending a suffix to the
 action. Overriding a site-wide hook can be done by changing its
-value or setting it to an empty string.
+value or setting it to an empty string.  Hooks can be prioritized
+by adding a prefix of ``priority`` to the hook name on a new line
+and setting the priority.  The default priority is 0 if
+not specified.
 
 Example ``.hg/hgrc``::
 
@@ -666,6 +669,8 @@
   incoming =
   incoming.email = /my/email/hook
   incoming.autobuild = /my/build/hook
+  # force autobuild hook to run before other incoming hooks
+  priority.incoming.autobuild = 1
 
 Most hooks are run with environment variables set that give useful
 additional information. For each hook below, the environment
--- a/mercurial/hook.py	Sun Jan 15 18:00:01 2012 -0600
+++ b/mercurial/hook.py	Sun Jan 15 13:50:12 2012 -0700
@@ -124,6 +124,14 @@
         ui.warn(_('warning: %s hook %s\n') % (name, desc))
     return r
 
+def _allhooks(ui):
+    hooks = []
+    for name, cmd in ui.configitems('hooks'):
+        if not name.startswith('priority'):
+            priority = ui.configint('hooks', 'priority.%s' % name, 0)
+            hooks.append((-priority, len(hooks), name, cmd))
+    return [(k, v) for p, o, k, v in sorted(hooks)]
+
 _redirect = False
 def redirect(state):
     global _redirect
@@ -147,7 +155,7 @@
             pass
 
     try:
-        for hname, cmd in ui.configitems('hooks'):
+        for hname, cmd in _allhooks(ui):
             if hname.split('.')[0] != name or not cmd:
                 continue
             if util.safehasattr(cmd, '__call__'):
--- a/tests/test-hook.t	Sun Jan 15 18:00:01 2012 -0600
+++ b/tests/test-hook.t	Sun Jan 15 13:50:12 2012 -0700
@@ -553,3 +553,19 @@
   calling hook pre-identify: hooktests.verbosehook
   verbose output from hook
   cb9a9f314b8b
+
+Ensure hooks can be prioritized
+
+  $ echo '[hooks]' > .hg/hgrc
+  $ echo 'pre-identify.a = python:hooktests.verbosehook' >> .hg/hgrc
+  $ echo 'pre-identify.b = python:hooktests.verbosehook' >> .hg/hgrc
+  $ echo 'priority.pre-identify.b = 1' >> .hg/hgrc
+  $ echo 'pre-identify.c = python:hooktests.verbosehook' >> .hg/hgrc
+  $ hg id --verbose
+  calling hook pre-identify.b: hooktests.verbosehook
+  verbose output from hook
+  calling hook pre-identify.a: hooktests.verbosehook
+  verbose output from hook
+  calling hook pre-identify.c: hooktests.verbosehook
+  verbose output from hook
+  cb9a9f314b8b