##// END OF EJS Templates
hooks: separate hook code into a separate module
Matt Mackall -
r4622:fff50306 default
parent child Browse files
Show More
@@ -0,0 +1,96 b''
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
@@ -10,7 +10,7 b' from i18n import _'
10 import repo, changegroup
10 import repo, changegroup
11 import changelog, dirstate, filelog, manifest, context
11 import changelog, dirstate, filelog, manifest, context
12 import re, lock, transaction, tempfile, stat, mdiff, errno, ui
12 import re, lock, transaction, tempfile, stat, mdiff, errno, ui
13 import os, revlog, time, util, extensions
13 import os, revlog, time, util, extensions, hook
14
14
15 class localrepository(repo.repository):
15 class localrepository(repo.repository):
16 capabilities = ('lookup', 'changegroupsubset')
16 capabilities = ('lookup', 'changegroupsubset')
@@ -105,89 +105,7 b' class localrepository(repo.repository):'
105 return 'file:' + self.root
105 return 'file:' + self.root
106
106
107 def hook(self, name, throw=False, **args):
107 def hook(self, name, throw=False, **args):
108 def callhook(hname, funcname):
108 return hook.hook(self.ui, self, name, throw, **args)
109 '''call python hook. hook is callable object, looked up as
110 name in python module. if callable returns "true", hook
111 fails, else passes. if hook raises exception, treated as
112 hook failure. exception propagates if throw is "true".
113
114 reason for "true" meaning "hook failed" is so that
115 unmodified commands (e.g. mercurial.commands.update) can
116 be run as hooks without wrappers to convert return values.'''
117
118 self.ui.note(_("calling hook %s: %s\n") % (hname, funcname))
119 obj = funcname
120 if not callable(obj):
121 d = funcname.rfind('.')
122 if d == -1:
123 raise util.Abort(_('%s hook is invalid ("%s" not in '
124 'a module)') % (hname, funcname))
125 modname = funcname[:d]
126 try:
127 obj = __import__(modname)
128 except ImportError:
129 try:
130 # extensions are loaded with hgext_ prefix
131 obj = __import__("hgext_%s" % modname)
132 except ImportError:
133 raise util.Abort(_('%s hook is invalid '
134 '(import of "%s" failed)') %
135 (hname, modname))
136 try:
137 for p in funcname.split('.')[1:]:
138 obj = getattr(obj, p)
139 except AttributeError, err:
140 raise util.Abort(_('%s hook is invalid '
141 '("%s" is not defined)') %
142 (hname, funcname))
143 if not callable(obj):
144 raise util.Abort(_('%s hook is invalid '
145 '("%s" is not callable)') %
146 (hname, funcname))
147 try:
148 r = obj(ui=self.ui, repo=self, hooktype=name, **args)
149 except (KeyboardInterrupt, util.SignalInterrupt):
150 raise
151 except Exception, exc:
152 if isinstance(exc, util.Abort):
153 self.ui.warn(_('error: %s hook failed: %s\n') %
154 (hname, exc.args[0]))
155 else:
156 self.ui.warn(_('error: %s hook raised an exception: '
157 '%s\n') % (hname, exc))
158 if throw:
159 raise
160 self.ui.print_exc()
161 return True
162 if r:
163 if throw:
164 raise util.Abort(_('%s hook failed') % hname)
165 self.ui.warn(_('warning: %s hook failed\n') % hname)
166 return r
167
168 def runhook(name, cmd):
169 self.ui.note(_("running hook %s: %s\n") % (name, cmd))
170 env = dict([('HG_' + k.upper(), v) for k, v in args.iteritems()])
171 r = util.system(cmd, environ=env, cwd=self.root)
172 if r:
173 desc, r = util.explain_exit(r)
174 if throw:
175 raise util.Abort(_('%s hook %s') % (name, desc))
176 self.ui.warn(_('warning: %s hook %s\n') % (name, desc))
177 return r
178
179 r = False
180 hooks = [(hname, cmd) for hname, cmd in self.ui.configitems("hooks")
181 if hname.split(".", 1)[0] == name and cmd]
182 hooks.sort()
183 for hname, cmd in hooks:
184 if callable(cmd):
185 r = callhook(hname, cmd) or r
186 elif cmd.startswith('python:'):
187 r = callhook(hname, cmd[7:].strip()) or r
188 else:
189 r = runhook(hname, cmd) or r
190 return r
191
109
192 tag_disallowed = ':\r\n'
110 tag_disallowed = ':\r\n'
193
111
General Comments 0
You need to be logged in to leave comments. Login now