dispatch: add generic pre- and post-command hooks
authorMatt Mackall <mpm@selenic.com>
Mon, 18 Jun 2007 17:49:56 -0500
changeset 4630 e6d105a51ec7
parent 4629 a04b5f37eda7
child 4631 e3afa670e484
dispatch: add generic pre- and post-command hooks
doc/hgrc.5.txt
mercurial/cmdutil.py
tests/test-hook
tests/test-hook.out
--- a/doc/hgrc.5.txt	Mon Jun 18 15:21:02 2007 -0700
+++ b/doc/hgrc.5.txt	Mon Jun 18 17:49:56 2007 -0500
@@ -312,10 +312,20 @@
     new parent is in $HG_PARENT1.  If merge, ID of second new parent
     is in $HG_PARENT2.  If update succeeded, $HG_ERROR=0.  If update
     failed (e.g. because conflicts not resolved), $HG_ERROR=1.
+  pre-<command>;;
+    Run before executing the associated command. The contents of the
+    command line are passed as $HG_ARGS. If the hook returns failure,
+    the command doesn't execute and Mercurial returns the failure code.
+  post-<command>;;
+    Run after successful invocations of the associated command. The
+    contents of the command line are passed as $HG_ARGS and the result
+    code in $HG_RESULT. Hook failure is ignored.
 
-  Note: In earlier releases, the names of hook environment variables
-  did not have a "HG_" prefix.  The old unprefixed names are no longer
-  provided in the environment.
+  Note: it is generally better to use standard hooks rather than the
+  generic pre- and post- command hooks as they are guaranteed to be
+  called in the appropriate contexts for influencing transactions.
+  Also, hooks like "commit" will be called in all contexts that
+  generate a commit (eg. tag) and not just the commit command.
 
   The syntax for Python hooks is as follows:
 
--- a/mercurial/cmdutil.py	Mon Jun 18 15:21:02 2007 -0700
+++ b/mercurial/cmdutil.py	Mon Jun 18 17:49:56 2007 -0500
@@ -9,7 +9,7 @@
 from i18n import _
 import os, sys, atexit, signal, pdb, traceback, socket, errno, shlex
 import mdiff, bdiff, util, templater, patch, commands, hg, lock, time
-import fancyopts, revlog, version, extensions
+import fancyopts, revlog, version, extensions, hook
 
 revrangesep = ':'
 
@@ -272,6 +272,7 @@
     if fallback:
         util._fallbackencoding = fallback
 
+    fullargs = args
     cmd, func, args, options, cmdoptions = parse(ui, args)
 
     if options["encoding"]:
@@ -302,8 +303,8 @@
     elif not cmd:
         return commands.help_(ui, 'shortlist')
 
+    repo = None
     if cmd not in commands.norepo.split():
-        repo = None
         try:
             repo = hg.repository(ui, path=path)
             ui = repo.ui
@@ -316,7 +317,15 @@
     else:
         d = lambda: func(ui, *args, **cmdoptions)
 
-    return runcommand(ui, options, cmd, d)
+    # run pre-hook, and abort if it fails
+    ret = hook.hook(ui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs))
+    if ret:
+        return ret
+    ret = runcommand(ui, options, cmd, d)
+    # run post-hook, passing command result
+    hook.hook(ui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
+                    result = ret)
+    return ret
 
 def runcommand(ui, options, cmd, cmdfunc):
     def checkargs():
--- a/tests/test-hook	Mon Jun 18 15:21:02 2007 -0700
+++ b/tests/test-hook	Mon Jun 18 17:49:56 2007 -0500
@@ -11,6 +11,9 @@
 echo 'precommit = unset HG_LOCAL HG_NODE HG_TAG; python ../printenv.py precommit' >> .hg/hgrc
 echo 'pretxncommit = unset HG_LOCAL HG_TAG; python ../printenv.py pretxncommit' >> .hg/hgrc
 echo 'pretxncommit.tip = hg -q tip' >> .hg/hgrc
+echo 'pre-identify = false' >> .hg/hgrc
+echo 'pre-cat = echo "meow $HG_ARGS"' >> .hg/hgrc
+echo 'post-cat = echo "purr $HG_RESULT"' >> .hg/hgrc
 echo a > a
 hg add a
 hg commit -m a -d "1000000 0"
@@ -35,6 +38,10 @@
 hg merge 1
 hg commit -m merge -d '2 0'
 
+# test generic hooks
+hg id
+hg cat b 
+
 cd ../b
 hg pull ../a
 
--- a/tests/test-hook.out	Mon Jun 18 15:21:02 2007 -0700
+++ b/tests/test-hook.out	Mon Jun 18 17:49:56 2007 -0500
@@ -22,6 +22,10 @@
 3:4c52fb2e4022
 commit hook: HG_NODE=4c52fb2e402287dd5dc052090682536c8406c321 HG_PARENT1=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT2=b702efe9688826e3a91283852b328b84dbf37bc2 
 commit.b hook: HG_NODE=4c52fb2e402287dd5dc052090682536c8406c321 HG_PARENT1=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT2=b702efe9688826e3a91283852b328b84dbf37bc2 
+warning: pre-identify hook exited with status 1
+meow cat b
+purr 0
+b
 prechangegroup hook: HG_SOURCE=pull HG_URL=file: 
 changegroup hook: HG_NODE=b702efe9688826e3a91283852b328b84dbf37bc2 HG_SOURCE=pull HG_URL=file: 
 incoming hook: HG_NODE=b702efe9688826e3a91283852b328b84dbf37bc2 HG_SOURCE=pull HG_URL=file: