##// END OF EJS Templates
hook: restore use of callable() since it was readded in Python 3.2
Augie Fackler -
r21797:b009dd13 default
parent child Browse files
Show More
@@ -1,211 +1,211 b''
1 # hook.py - hook support for mercurial
1 # hook.py - hook support for mercurial
2 #
2 #
3 # Copyright 2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from i18n import _
8 from i18n import _
9 import os, sys, time
9 import os, sys, time
10 import extensions, util, demandimport
10 import extensions, util, demandimport
11
11
12 def _pythonhook(ui, repo, name, hname, funcname, args, throw):
12 def _pythonhook(ui, repo, name, hname, funcname, args, throw):
13 '''call python hook. hook is callable object, looked up as
13 '''call python hook. hook is callable object, looked up as
14 name in python module. if callable returns "true", hook
14 name in python module. if callable returns "true", hook
15 fails, else passes. if hook raises exception, treated as
15 fails, else passes. if hook raises exception, treated as
16 hook failure. exception propagates if throw is "true".
16 hook failure. exception propagates if throw is "true".
17
17
18 reason for "true" meaning "hook failed" is so that
18 reason for "true" meaning "hook failed" is so that
19 unmodified commands (e.g. mercurial.commands.update) can
19 unmodified commands (e.g. mercurial.commands.update) can
20 be run as hooks without wrappers to convert return values.'''
20 be run as hooks without wrappers to convert return values.'''
21
21
22 if util.safehasattr(funcname, '__call__'):
22 if callable(funcname):
23 obj = funcname
23 obj = funcname
24 funcname = obj.__module__ + "." + obj.__name__
24 funcname = obj.__module__ + "." + obj.__name__
25 else:
25 else:
26 d = funcname.rfind('.')
26 d = funcname.rfind('.')
27 if d == -1:
27 if d == -1:
28 raise util.Abort(_('%s hook is invalid ("%s" not in '
28 raise util.Abort(_('%s hook is invalid ("%s" not in '
29 'a module)') % (hname, funcname))
29 'a module)') % (hname, funcname))
30 modname = funcname[:d]
30 modname = funcname[:d]
31 oldpaths = sys.path
31 oldpaths = sys.path
32 if util.mainfrozen():
32 if util.mainfrozen():
33 # binary installs require sys.path manipulation
33 # binary installs require sys.path manipulation
34 modpath, modfile = os.path.split(modname)
34 modpath, modfile = os.path.split(modname)
35 if modpath and modfile:
35 if modpath and modfile:
36 sys.path = sys.path[:] + [modpath]
36 sys.path = sys.path[:] + [modpath]
37 modname = modfile
37 modname = modfile
38 demandimportenabled = demandimport.isenabled()
38 demandimportenabled = demandimport.isenabled()
39 if demandimportenabled:
39 if demandimportenabled:
40 demandimport.disable()
40 demandimport.disable()
41 try:
41 try:
42 try:
42 try:
43 obj = __import__(modname)
43 obj = __import__(modname)
44 except ImportError:
44 except ImportError:
45 e1 = sys.exc_type, sys.exc_value, sys.exc_traceback
45 e1 = sys.exc_type, sys.exc_value, sys.exc_traceback
46 try:
46 try:
47 # extensions are loaded with hgext_ prefix
47 # extensions are loaded with hgext_ prefix
48 obj = __import__("hgext_%s" % modname)
48 obj = __import__("hgext_%s" % modname)
49 except ImportError:
49 except ImportError:
50 e2 = sys.exc_type, sys.exc_value, sys.exc_traceback
50 e2 = sys.exc_type, sys.exc_value, sys.exc_traceback
51 if ui.tracebackflag:
51 if ui.tracebackflag:
52 ui.warn(_('exception from first failed import '
52 ui.warn(_('exception from first failed import '
53 'attempt:\n'))
53 'attempt:\n'))
54 ui.traceback(e1)
54 ui.traceback(e1)
55 if ui.tracebackflag:
55 if ui.tracebackflag:
56 ui.warn(_('exception from second failed import '
56 ui.warn(_('exception from second failed import '
57 'attempt:\n'))
57 'attempt:\n'))
58 ui.traceback(e2)
58 ui.traceback(e2)
59 raise util.Abort(_('%s hook is invalid '
59 raise util.Abort(_('%s hook is invalid '
60 '(import of "%s" failed)') %
60 '(import of "%s" failed)') %
61 (hname, modname))
61 (hname, modname))
62 finally:
62 finally:
63 if demandimportenabled:
63 if demandimportenabled:
64 demandimport.enable()
64 demandimport.enable()
65 sys.path = oldpaths
65 sys.path = oldpaths
66 try:
66 try:
67 for p in funcname.split('.')[1:]:
67 for p in funcname.split('.')[1:]:
68 obj = getattr(obj, p)
68 obj = getattr(obj, p)
69 except AttributeError:
69 except AttributeError:
70 raise util.Abort(_('%s hook is invalid '
70 raise util.Abort(_('%s hook is invalid '
71 '("%s" is not defined)') %
71 '("%s" is not defined)') %
72 (hname, funcname))
72 (hname, funcname))
73 if not util.safehasattr(obj, '__call__'):
73 if not callable(obj):
74 raise util.Abort(_('%s hook is invalid '
74 raise util.Abort(_('%s hook is invalid '
75 '("%s" is not callable)') %
75 '("%s" is not callable)') %
76 (hname, funcname))
76 (hname, funcname))
77
77
78 ui.note(_("calling hook %s: %s\n") % (hname, funcname))
78 ui.note(_("calling hook %s: %s\n") % (hname, funcname))
79 starttime = time.time()
79 starttime = time.time()
80
80
81 try:
81 try:
82 try:
82 try:
83 # redirect IO descriptors to the ui descriptors so hooks
83 # redirect IO descriptors to the ui descriptors so hooks
84 # that write directly to these don't mess up the command
84 # that write directly to these don't mess up the command
85 # protocol when running through the command server
85 # protocol when running through the command server
86 old = sys.stdout, sys.stderr, sys.stdin
86 old = sys.stdout, sys.stderr, sys.stdin
87 sys.stdout, sys.stderr, sys.stdin = ui.fout, ui.ferr, ui.fin
87 sys.stdout, sys.stderr, sys.stdin = ui.fout, ui.ferr, ui.fin
88
88
89 r = obj(ui=ui, repo=repo, hooktype=name, **args)
89 r = obj(ui=ui, repo=repo, hooktype=name, **args)
90 except KeyboardInterrupt:
90 except KeyboardInterrupt:
91 raise
91 raise
92 except Exception, exc:
92 except Exception, exc:
93 if isinstance(exc, util.Abort):
93 if isinstance(exc, util.Abort):
94 ui.warn(_('error: %s hook failed: %s\n') %
94 ui.warn(_('error: %s hook failed: %s\n') %
95 (hname, exc.args[0]))
95 (hname, exc.args[0]))
96 else:
96 else:
97 ui.warn(_('error: %s hook raised an exception: '
97 ui.warn(_('error: %s hook raised an exception: '
98 '%s\n') % (hname, exc))
98 '%s\n') % (hname, exc))
99 if throw:
99 if throw:
100 raise
100 raise
101 ui.traceback()
101 ui.traceback()
102 return True
102 return True
103 finally:
103 finally:
104 sys.stdout, sys.stderr, sys.stdin = old
104 sys.stdout, sys.stderr, sys.stdin = old
105 duration = time.time() - starttime
105 duration = time.time() - starttime
106 ui.log('pythonhook', 'pythonhook-%s: %s finished in %0.2f seconds\n',
106 ui.log('pythonhook', 'pythonhook-%s: %s finished in %0.2f seconds\n',
107 name, funcname, duration)
107 name, funcname, duration)
108 if r:
108 if r:
109 if throw:
109 if throw:
110 raise util.Abort(_('%s hook failed') % hname)
110 raise util.Abort(_('%s hook failed') % hname)
111 ui.warn(_('warning: %s hook failed\n') % hname)
111 ui.warn(_('warning: %s hook failed\n') % hname)
112 return r
112 return r
113
113
114 def _exthook(ui, repo, name, cmd, args, throw):
114 def _exthook(ui, repo, name, cmd, args, throw):
115 ui.note(_("running hook %s: %s\n") % (name, cmd))
115 ui.note(_("running hook %s: %s\n") % (name, cmd))
116
116
117 starttime = time.time()
117 starttime = time.time()
118 env = {}
118 env = {}
119 for k, v in args.iteritems():
119 for k, v in args.iteritems():
120 if util.safehasattr(v, '__call__'):
120 if callable(v):
121 v = v()
121 v = v()
122 if isinstance(v, dict):
122 if isinstance(v, dict):
123 # make the dictionary element order stable across Python
123 # make the dictionary element order stable across Python
124 # implementations
124 # implementations
125 v = ('{' +
125 v = ('{' +
126 ', '.join('%r: %r' % i for i in sorted(v.iteritems())) +
126 ', '.join('%r: %r' % i for i in sorted(v.iteritems())) +
127 '}')
127 '}')
128 env['HG_' + k.upper()] = v
128 env['HG_' + k.upper()] = v
129
129
130 if repo:
130 if repo:
131 cwd = repo.root
131 cwd = repo.root
132 else:
132 else:
133 cwd = os.getcwd()
133 cwd = os.getcwd()
134 if 'HG_URL' in env and env['HG_URL'].startswith('remote:http'):
134 if 'HG_URL' in env and env['HG_URL'].startswith('remote:http'):
135 r = util.system(cmd, environ=env, cwd=cwd, out=ui)
135 r = util.system(cmd, environ=env, cwd=cwd, out=ui)
136 else:
136 else:
137 r = util.system(cmd, environ=env, cwd=cwd, out=ui.fout)
137 r = util.system(cmd, environ=env, cwd=cwd, out=ui.fout)
138
138
139 duration = time.time() - starttime
139 duration = time.time() - starttime
140 ui.log('exthook', 'exthook-%s: %s finished in %0.2f seconds\n',
140 ui.log('exthook', 'exthook-%s: %s finished in %0.2f seconds\n',
141 name, cmd, duration)
141 name, cmd, duration)
142 if r:
142 if r:
143 desc, r = util.explainexit(r)
143 desc, r = util.explainexit(r)
144 if throw:
144 if throw:
145 raise util.Abort(_('%s hook %s') % (name, desc))
145 raise util.Abort(_('%s hook %s') % (name, desc))
146 ui.warn(_('warning: %s hook %s\n') % (name, desc))
146 ui.warn(_('warning: %s hook %s\n') % (name, desc))
147 return r
147 return r
148
148
149 def _allhooks(ui):
149 def _allhooks(ui):
150 hooks = []
150 hooks = []
151 for name, cmd in ui.configitems('hooks'):
151 for name, cmd in ui.configitems('hooks'):
152 if not name.startswith('priority'):
152 if not name.startswith('priority'):
153 priority = ui.configint('hooks', 'priority.%s' % name, 0)
153 priority = ui.configint('hooks', 'priority.%s' % name, 0)
154 hooks.append((-priority, len(hooks), name, cmd))
154 hooks.append((-priority, len(hooks), name, cmd))
155 return [(k, v) for p, o, k, v in sorted(hooks)]
155 return [(k, v) for p, o, k, v in sorted(hooks)]
156
156
157 _redirect = False
157 _redirect = False
158 def redirect(state):
158 def redirect(state):
159 global _redirect
159 global _redirect
160 _redirect = state
160 _redirect = state
161
161
162 def hook(ui, repo, name, throw=False, **args):
162 def hook(ui, repo, name, throw=False, **args):
163 if not ui.callhooks:
163 if not ui.callhooks:
164 return False
164 return False
165
165
166 r = False
166 r = False
167 oldstdout = -1
167 oldstdout = -1
168
168
169 try:
169 try:
170 for hname, cmd in _allhooks(ui):
170 for hname, cmd in _allhooks(ui):
171 if hname.split('.')[0] != name or not cmd:
171 if hname.split('.')[0] != name or not cmd:
172 continue
172 continue
173
173
174 if oldstdout == -1 and _redirect:
174 if oldstdout == -1 and _redirect:
175 try:
175 try:
176 stdoutno = sys.__stdout__.fileno()
176 stdoutno = sys.__stdout__.fileno()
177 stderrno = sys.__stderr__.fileno()
177 stderrno = sys.__stderr__.fileno()
178 # temporarily redirect stdout to stderr, if possible
178 # temporarily redirect stdout to stderr, if possible
179 if stdoutno >= 0 and stderrno >= 0:
179 if stdoutno >= 0 and stderrno >= 0:
180 sys.__stdout__.flush()
180 sys.__stdout__.flush()
181 oldstdout = os.dup(stdoutno)
181 oldstdout = os.dup(stdoutno)
182 os.dup2(stderrno, stdoutno)
182 os.dup2(stderrno, stdoutno)
183 except (OSError, AttributeError):
183 except (OSError, AttributeError):
184 # files seem to be bogus, give up on redirecting (WSGI, etc)
184 # files seem to be bogus, give up on redirecting (WSGI, etc)
185 pass
185 pass
186
186
187 if util.safehasattr(cmd, '__call__'):
187 if callable(cmd):
188 r = _pythonhook(ui, repo, name, hname, cmd, args, throw) or r
188 r = _pythonhook(ui, repo, name, hname, cmd, args, throw) or r
189 elif cmd.startswith('python:'):
189 elif cmd.startswith('python:'):
190 if cmd.count(':') >= 2:
190 if cmd.count(':') >= 2:
191 path, cmd = cmd[7:].rsplit(':', 1)
191 path, cmd = cmd[7:].rsplit(':', 1)
192 path = util.expandpath(path)
192 path = util.expandpath(path)
193 if repo:
193 if repo:
194 path = os.path.join(repo.root, path)
194 path = os.path.join(repo.root, path)
195 try:
195 try:
196 mod = extensions.loadpath(path, 'hghook.%s' % hname)
196 mod = extensions.loadpath(path, 'hghook.%s' % hname)
197 except Exception:
197 except Exception:
198 ui.write(_("loading %s hook failed:\n") % hname)
198 ui.write(_("loading %s hook failed:\n") % hname)
199 raise
199 raise
200 hookfn = getattr(mod, cmd)
200 hookfn = getattr(mod, cmd)
201 else:
201 else:
202 hookfn = cmd[7:].strip()
202 hookfn = cmd[7:].strip()
203 r = _pythonhook(ui, repo, name, hname, hookfn, args, throw) or r
203 r = _pythonhook(ui, repo, name, hname, hookfn, args, throw) or r
204 else:
204 else:
205 r = _exthook(ui, repo, hname, cmd, args, throw) or r
205 r = _exthook(ui, repo, hname, cmd, args, throw) or r
206 finally:
206 finally:
207 if _redirect and oldstdout >= 0:
207 if _redirect and oldstdout >= 0:
208 os.dup2(oldstdout, stdoutno)
208 os.dup2(oldstdout, stdoutno)
209 os.close(oldstdout)
209 os.close(oldstdout)
210
210
211 return r
211 return r
General Comments 0
You need to be logged in to leave comments. Login now