comparison mercurial/hook.py @ 4623:fff50306e6dd

hooks: separate hook code into a separate module
author Matt Mackall <mpm@selenic.com>
date Mon, 18 Jun 2007 13:24:34 -0500
parents
children
comparison
equal deleted inserted replaced
4622:6fc26982f203 4623:fff50306e6dd
1 # hook.py - hook support for mercurial
2 #
3 # Copyright 2007 Matt Mackall <mpm@selenic.com>
4 #
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
7
8 from i18n import _
9 import util
10
11 def _pythonhook(ui, repo, name, hname, funcname, args, throw):
12 '''call python hook. hook is callable object, looked up as
13 name in python module. if callable returns "true", hook
14 fails, else passes. if hook raises exception, treated as
15 hook failure. exception propagates if throw is "true".
16
17 reason for "true" meaning "hook failed" is so that
18 unmodified commands (e.g. mercurial.commands.update) can
19 be run as hooks without wrappers to convert return values.'''
20
21 ui.note(_("calling hook %s: %s\n") % (hname, funcname))
22 obj = funcname
23 if not callable(obj):
24 d = funcname.rfind('.')
25 if d == -1:
26 raise util.Abort(_('%s hook is invalid ("%s" not in '
27 'a module)') % (hname, funcname))
28 modname = funcname[:d]
29 try:
30 obj = __import__(modname)
31 except ImportError:
32 try:
33 # extensions are loaded with hgext_ prefix
34 obj = __import__("hgext_%s" % modname)
35 except ImportError:
36 raise util.Abort(_('%s hook is invalid '
37 '(import of "%s" failed)') %
38 (hname, modname))
39 try:
40 for p in funcname.split('.')[1:]:
41 obj = getattr(obj, p)
42 except AttributeError, err:
43 raise util.Abort(_('%s hook is invalid '
44 '("%s" is not defined)') %
45 (hname, funcname))
46 if not callable(obj):
47 raise util.Abort(_('%s hook is invalid '
48 '("%s" is not callable)') %
49 (hname, funcname))
50 try:
51 r = obj(ui=ui, repo=repo, hooktype=name, **args)
52 except (KeyboardInterrupt, util.SignalInterrupt):
53 raise
54 except Exception, exc:
55 if isinstance(exc, util.Abort):
56 ui.warn(_('error: %s hook failed: %s\n') %
57 (hname, exc.args[0]))
58 else:
59 ui.warn(_('error: %s hook raised an exception: '
60 '%s\n') % (hname, exc))
61 if throw:
62 raise
63 ui.print_exc()
64 return True
65 if r:
66 if throw:
67 raise util.Abort(_('%s hook failed') % hname)
68 ui.warn(_('warning: %s hook failed\n') % hname)
69 return r
70
71 def _exthook(ui, repo, name, cmd, args, throw):
72 ui.note(_("running hook %s: %s\n") % (name, cmd))
73 env = dict([('HG_' + k.upper(), v) for k, v in args.iteritems()])
74 r = util.system(cmd, environ=env, cwd=repo.root)
75 if r:
76 desc, r = util.explain_exit(r)
77 if throw:
78 raise util.Abort(_('%s hook %s') % (name, desc))
79 ui.warn(_('warning: %s hook %s\n') % (name, desc))
80 return r
81
82 def hook(ui, repo, name, throw=False, **args):
83 r = False
84 hooks = [(hname, cmd) for hname, cmd in ui.configitems("hooks")
85 if hname.split(".", 1)[0] == name and cmd]
86 hooks.sort()
87 for hname, cmd in hooks:
88 if callable(cmd):
89 r = _pythonhook(ui, repo, name, hname, cmd, args, throw) or r
90 elif cmd.startswith('python:'):
91 r = _pythonhook(ui, repo, name, hname, cmd[7:].strip(),
92 args, throw) or r
93 else:
94 r = _exthook(ui, repo, hname, cmd, args, throw) or r
95 return r
96