comparison mercurial/hook.py @ 43076:2372284d9457

formatting: blacken the codebase This is using my patch to black (https://github.com/psf/black/pull/826) so we don't un-wrap collection literals. Done with: hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S # skip-blame mass-reformatting only # no-check-commit reformats foo_bar functions Differential Revision: https://phab.mercurial-scm.org/D6971
author Augie Fackler <augie@google.com>
date Sun, 06 Oct 2019 09:45:02 -0400
parents 8c8fcb385c46
children 687b865b95ad
comparison
equal deleted inserted replaced
43075:57875cf423c9 43076:2372284d9457
22 from .utils import ( 22 from .utils import (
23 procutil, 23 procutil,
24 stringutil, 24 stringutil,
25 ) 25 )
26 26
27
27 def pythonhook(ui, repo, htype, hname, funcname, args, throw): 28 def pythonhook(ui, repo, htype, hname, funcname, args, throw):
28 '''call python hook. hook is callable object, looked up as 29 '''call python hook. hook is callable object, looked up as
29 name in python module. if callable returns "true", hook 30 name in python module. if callable returns "true", hook
30 fails, else passes. if hook raises exception, treated as 31 fails, else passes. if hook raises exception, treated as
31 hook failure. exception propagates if throw is "true". 32 hook failure. exception propagates if throw is "true".
40 else: 41 else:
41 d = funcname.rfind('.') 42 d = funcname.rfind('.')
42 if d == -1: 43 if d == -1:
43 raise error.HookLoadError( 44 raise error.HookLoadError(
44 _('%s hook is invalid: "%s" not in a module') 45 _('%s hook is invalid: "%s" not in a module')
45 % (hname, funcname)) 46 % (hname, funcname)
47 )
46 modname = funcname[:d] 48 modname = funcname[:d]
47 oldpaths = sys.path 49 oldpaths = sys.path
48 if procutil.mainfrozen(): 50 if procutil.mainfrozen():
49 # binary installs require sys.path manipulation 51 # binary installs require sys.path manipulation
50 modpath, modfile = os.path.split(modname) 52 modpath, modfile = os.path.split(modname)
60 # extensions are loaded with hgext_ prefix 62 # extensions are loaded with hgext_ prefix
61 obj = __import__(r"hgext_%s" % pycompat.sysstr(modname)) 63 obj = __import__(r"hgext_%s" % pycompat.sysstr(modname))
62 except (ImportError, SyntaxError): 64 except (ImportError, SyntaxError):
63 e2 = sys.exc_info() 65 e2 = sys.exc_info()
64 if ui.tracebackflag: 66 if ui.tracebackflag:
65 ui.warn(_('exception from first failed import ' 67 ui.warn(
66 'attempt:\n')) 68 _(
69 'exception from first failed import '
70 'attempt:\n'
71 )
72 )
67 ui.traceback(e1) 73 ui.traceback(e1)
68 if ui.tracebackflag: 74 if ui.tracebackflag:
69 ui.warn(_('exception from second failed import ' 75 ui.warn(
70 'attempt:\n')) 76 _(
77 'exception from second failed import '
78 'attempt:\n'
79 )
80 )
71 ui.traceback(e2) 81 ui.traceback(e2)
72 82
73 if not ui.tracebackflag: 83 if not ui.tracebackflag:
74 tracebackhint = _( 84 tracebackhint = _(
75 'run with --traceback for stack trace') 85 'run with --traceback for stack trace'
86 )
76 else: 87 else:
77 tracebackhint = None 88 tracebackhint = None
78 raise error.HookLoadError( 89 raise error.HookLoadError(
79 _('%s hook is invalid: import of "%s" failed') % 90 _('%s hook is invalid: import of "%s" failed')
80 (hname, modname), hint=tracebackhint) 91 % (hname, modname),
92 hint=tracebackhint,
93 )
81 sys.path = oldpaths 94 sys.path = oldpaths
82 try: 95 try:
83 for p in funcname.split('.')[1:]: 96 for p in funcname.split('.')[1:]:
84 obj = getattr(obj, p) 97 obj = getattr(obj, p)
85 except AttributeError: 98 except AttributeError:
86 raise error.HookLoadError( 99 raise error.HookLoadError(
87 _('%s hook is invalid: "%s" is not defined') 100 _('%s hook is invalid: "%s" is not defined') % (hname, funcname)
88 % (hname, funcname)) 101 )
89 if not callable(obj): 102 if not callable(obj):
90 raise error.HookLoadError( 103 raise error.HookLoadError(
91 _('%s hook is invalid: "%s" is not callable') 104 _('%s hook is invalid: "%s" is not callable')
92 % (hname, funcname)) 105 % (hname, funcname)
106 )
93 107
94 ui.note(_("calling hook %s: %s\n") % (hname, funcname)) 108 ui.note(_("calling hook %s: %s\n") % (hname, funcname))
95 starttime = util.timer() 109 starttime = util.timer()
96 110
97 try: 111 try:
98 r = obj(ui=ui, repo=repo, hooktype=htype, **pycompat.strkwargs(args)) 112 r = obj(ui=ui, repo=repo, hooktype=htype, **pycompat.strkwargs(args))
99 except Exception as exc: 113 except Exception as exc:
100 if isinstance(exc, error.Abort): 114 if isinstance(exc, error.Abort):
101 ui.warn(_('error: %s hook failed: %s\n') % 115 ui.warn(_('error: %s hook failed: %s\n') % (hname, exc.args[0]))
102 (hname, exc.args[0]))
103 else: 116 else:
104 ui.warn(_('error: %s hook raised an exception: ' 117 ui.warn(
105 '%s\n') % (hname, stringutil.forcebytestr(exc))) 118 _('error: %s hook raised an exception: ' '%s\n')
119 % (hname, stringutil.forcebytestr(exc))
120 )
106 if throw: 121 if throw:
107 raise 122 raise
108 if not ui.tracebackflag: 123 if not ui.tracebackflag:
109 ui.warn(_('(run with --traceback for stack trace)\n')) 124 ui.warn(_('(run with --traceback for stack trace)\n'))
110 ui.traceback() 125 ui.traceback()
111 return True, True 126 return True, True
112 finally: 127 finally:
113 duration = util.timer() - starttime 128 duration = util.timer() - starttime
114 ui.log('pythonhook', 'pythonhook-%s: %s finished in %0.2f seconds\n', 129 ui.log(
115 htype, funcname, duration) 130 'pythonhook',
131 'pythonhook-%s: %s finished in %0.2f seconds\n',
132 htype,
133 funcname,
134 duration,
135 )
116 if r: 136 if r:
117 if throw: 137 if throw:
118 raise error.HookAbort(_('%s hook failed') % hname) 138 raise error.HookAbort(_('%s hook failed') % hname)
119 ui.warn(_('warning: %s hook failed\n') % hname) 139 ui.warn(_('warning: %s hook failed\n') % hname)
120 return r, False 140 return r, False
141
121 142
122 def _exthook(ui, repo, htype, name, cmd, args, throw): 143 def _exthook(ui, repo, htype, name, cmd, args, throw):
123 starttime = util.timer() 144 starttime = util.timer()
124 env = {} 145 env = {}
125 146
152 else: 173 else:
153 cwd = encoding.getcwd() 174 cwd = encoding.getcwd()
154 r = ui.system(cmd, environ=env, cwd=cwd, blockedtag='exthook-%s' % (name,)) 175 r = ui.system(cmd, environ=env, cwd=cwd, blockedtag='exthook-%s' % (name,))
155 176
156 duration = util.timer() - starttime 177 duration = util.timer() - starttime
157 ui.log('exthook', 'exthook-%s: %s finished in %0.2f seconds\n', 178 ui.log(
158 name, cmd, duration) 179 'exthook',
180 'exthook-%s: %s finished in %0.2f seconds\n',
181 name,
182 cmd,
183 duration,
184 )
159 if r: 185 if r:
160 desc = procutil.explainexit(r) 186 desc = procutil.explainexit(r)
161 if throw: 187 if throw:
162 raise error.HookAbort(_('%s hook %s') % (name, desc)) 188 raise error.HookAbort(_('%s hook %s') % (name, desc))
163 ui.warn(_('warning: %s hook %s\n') % (name, desc)) 189 ui.warn(_('warning: %s hook %s\n') % (name, desc))
164 return r 190 return r
165 191
192
166 # represent an untrusted hook command 193 # represent an untrusted hook command
167 _fromuntrusted = object() 194 _fromuntrusted = object()
195
168 196
169 def _allhooks(ui): 197 def _allhooks(ui):
170 """return a list of (hook-id, cmd) pairs sorted by priority""" 198 """return a list of (hook-id, cmd) pairs sorted by priority"""
171 hooks = _hookitems(ui) 199 hooks = _hookitems(ui)
172 # Be careful in this section, propagating the real commands from untrusted 200 # Be careful in this section, propagating the real commands from untrusted
179 (lp, lo, lk, lv) = trustedvalue 207 (lp, lo, lk, lv) = trustedvalue
180 hooks[name] = (lp, lo, lk, _fromuntrusted) 208 hooks[name] = (lp, lo, lk, _fromuntrusted)
181 # (end of the security sensitive section) 209 # (end of the security sensitive section)
182 return [(k, v) for p, o, k, v in sorted(hooks.values())] 210 return [(k, v) for p, o, k, v in sorted(hooks.values())]
183 211
212
184 def _hookitems(ui, _untrusted=False): 213 def _hookitems(ui, _untrusted=False):
185 """return all hooks items ready to be sorted""" 214 """return all hooks items ready to be sorted"""
186 hooks = {} 215 hooks = {}
187 for name, cmd in ui.configitems('hooks', untrusted=_untrusted): 216 for name, cmd in ui.configitems('hooks', untrusted=_untrusted):
188 if name.startswith('priority.') or name.startswith('tonative.'): 217 if name.startswith('priority.') or name.startswith('tonative.'):
190 219
191 priority = ui.configint('hooks', 'priority.%s' % name, 0) 220 priority = ui.configint('hooks', 'priority.%s' % name, 0)
192 hooks[name] = (-priority, len(hooks), name, cmd) 221 hooks[name] = (-priority, len(hooks), name, cmd)
193 return hooks 222 return hooks
194 223
224
195 _redirect = False 225 _redirect = False
226
227
196 def redirect(state): 228 def redirect(state):
197 global _redirect 229 global _redirect
198 _redirect = state 230 _redirect = state
231
199 232
200 def hashook(ui, htype): 233 def hashook(ui, htype):
201 """return True if a hook is configured for 'htype'""" 234 """return True if a hook is configured for 'htype'"""
202 if not ui.callhooks: 235 if not ui.callhooks:
203 return False 236 return False
204 for hname, cmd in _allhooks(ui): 237 for hname, cmd in _allhooks(ui):
205 if hname.split('.')[0] == htype and cmd: 238 if hname.split('.')[0] == htype and cmd:
206 return True 239 return True
207 return False 240 return False
208 241
242
209 def hook(ui, repo, htype, throw=False, **args): 243 def hook(ui, repo, htype, throw=False, **args):
210 if not ui.callhooks: 244 if not ui.callhooks:
211 return False 245 return False
212 246
213 hooks = [] 247 hooks = []
218 res = runhooks(ui, repo, htype, hooks, throw=throw, **args) 252 res = runhooks(ui, repo, htype, hooks, throw=throw, **args)
219 r = False 253 r = False
220 for hname, cmd in hooks: 254 for hname, cmd in hooks:
221 r = res[hname][0] or r 255 r = res[hname][0] or r
222 return r 256 return r
257
223 258
224 def runhooks(ui, repo, htype, hooks, throw=False, **args): 259 def runhooks(ui, repo, htype, hooks, throw=False, **args):
225 args = pycompat.byteskwargs(args) 260 args = pycompat.byteskwargs(args)
226 res = {} 261 res = {}
227 oldstdout = -1 262 oldstdout = -1
243 278
244 if cmd is _fromuntrusted: 279 if cmd is _fromuntrusted:
245 if throw: 280 if throw:
246 raise error.HookAbort( 281 raise error.HookAbort(
247 _('untrusted hook %s not executed') % hname, 282 _('untrusted hook %s not executed') % hname,
248 hint = _("see 'hg help config.trusted'")) 283 hint=_("see 'hg help config.trusted'"),
284 )
249 ui.warn(_('warning: untrusted hook %s not executed\n') % hname) 285 ui.warn(_('warning: untrusted hook %s not executed\n') % hname)
250 r = 1 286 r = 1
251 raised = False 287 raised = False
252 elif callable(cmd): 288 elif callable(cmd):
253 r, raised = pythonhook(ui, repo, htype, hname, cmd, args, 289 r, raised = pythonhook(ui, repo, htype, hname, cmd, args, throw)
254 throw)
255 elif cmd.startswith('python:'): 290 elif cmd.startswith('python:'):
256 if cmd.count(':') >= 2: 291 if cmd.count(':') >= 2:
257 path, cmd = cmd[7:].rsplit(':', 1) 292 path, cmd = cmd[7:].rsplit(':', 1)
258 path = util.expandpath(path) 293 path = util.expandpath(path)
259 if repo: 294 if repo:
264 ui.write(_("loading %s hook failed:\n") % hname) 299 ui.write(_("loading %s hook failed:\n") % hname)
265 raise 300 raise
266 hookfn = getattr(mod, cmd) 301 hookfn = getattr(mod, cmd)
267 else: 302 else:
268 hookfn = cmd[7:].strip() 303 hookfn = cmd[7:].strip()
269 r, raised = pythonhook(ui, repo, htype, hname, hookfn, args, 304 r, raised = pythonhook(
270 throw) 305 ui, repo, htype, hname, hookfn, args, throw
306 )
271 else: 307 else:
272 r = _exthook(ui, repo, htype, hname, cmd, args, throw) 308 r = _exthook(ui, repo, htype, hname, cmd, args, throw)
273 raised = False 309 raised = False
274 310
275 res[hname] = r, raised 311 res[hname] = r, raised