##// END OF EJS Templates
hooks: restore io correctly on exception
Jesse Long -
r7416:196b05a5 default
parent child Browse files
Show More
@@ -1,114 +1,115
1 1 # hook.py - hook support for mercurial
2 2 #
3 3 # Copyright 2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 8 from i18n import _
9 9 import util, os, sys
10 10
11 11 def _pythonhook(ui, repo, name, hname, funcname, args, throw):
12 12 '''call python hook. hook is callable object, looked up as
13 13 name in python module. if callable returns "true", hook
14 14 fails, else passes. if hook raises exception, treated as
15 15 hook failure. exception propagates if throw is "true".
16 16
17 17 reason for "true" meaning "hook failed" is so that
18 18 unmodified commands (e.g. mercurial.commands.update) can
19 19 be run as hooks without wrappers to convert return values.'''
20 20
21 21 ui.note(_("calling hook %s: %s\n") % (hname, funcname))
22 22 obj = funcname
23 23 if not callable(obj):
24 24 d = funcname.rfind('.')
25 25 if d == -1:
26 26 raise util.Abort(_('%s hook is invalid ("%s" not in '
27 27 'a module)') % (hname, funcname))
28 28 modname = funcname[:d]
29 29 try:
30 30 obj = __import__(modname)
31 31 except ImportError:
32 32 try:
33 33 # extensions are loaded with hgext_ prefix
34 34 obj = __import__("hgext_%s" % modname)
35 35 except ImportError:
36 36 raise util.Abort(_('%s hook is invalid '
37 37 '(import of "%s" failed)') %
38 38 (hname, modname))
39 39 try:
40 40 for p in funcname.split('.')[1:]:
41 41 obj = getattr(obj, p)
42 42 except AttributeError:
43 43 raise util.Abort(_('%s hook is invalid '
44 44 '("%s" is not defined)') %
45 45 (hname, funcname))
46 46 if not callable(obj):
47 47 raise util.Abort(_('%s hook is invalid '
48 48 '("%s" is not callable)') %
49 49 (hname, funcname))
50 50 try:
51 51 r = obj(ui=ui, repo=repo, hooktype=name, **args)
52 52 except (KeyboardInterrupt, util.SignalInterrupt):
53 53 raise
54 54 except Exception, exc:
55 55 if isinstance(exc, util.Abort):
56 56 ui.warn(_('error: %s hook failed: %s\n') %
57 57 (hname, exc.args[0]))
58 58 else:
59 59 ui.warn(_('error: %s hook raised an exception: '
60 60 '%s\n') % (hname, exc))
61 61 if throw:
62 62 raise
63 63 ui.print_exc()
64 64 return True
65 65 if r:
66 66 if throw:
67 67 raise util.Abort(_('%s hook failed') % hname)
68 68 ui.warn(_('warning: %s hook failed\n') % hname)
69 69 return r
70 70
71 71 def _exthook(ui, repo, name, cmd, args, throw):
72 72 ui.note(_("running hook %s: %s\n") % (name, cmd))
73 73 env = dict([('HG_' + k.upper(), v) for k, v in args.iteritems()])
74 74 if repo:
75 75 cwd = repo.root
76 76 else:
77 77 cwd = os.getcwd()
78 78 r = util.system(cmd, environ=env, cwd=cwd)
79 79 if r:
80 80 desc, r = util.explain_exit(r)
81 81 if throw:
82 82 raise util.Abort(_('%s hook %s') % (name, desc))
83 83 ui.warn(_('warning: %s hook %s\n') % (name, desc))
84 84 return r
85 85
86 86 _redirect = False
87 87 def redirect(state):
88 88 global _redirect
89 89 _redirect = state
90 90
91 91 def hook(ui, repo, name, throw=False, **args):
92 92 r = False
93 93
94 94 if _redirect:
95 95 # temporarily redirect stdout to stderr
96 96 oldstdout = os.dup(sys.__stdout__.fileno())
97 97 os.dup2(sys.__stderr__.fileno(), sys.__stdout__.fileno())
98 98
99 for hname, cmd in util.sort(ui.configitems('hooks')):
100 if hname.split('.')[0] != name or not cmd:
101 continue
102 if callable(cmd):
103 r = _pythonhook(ui, repo, name, hname, cmd, args, throw) or r
104 elif cmd.startswith('python:'):
105 r = _pythonhook(ui, repo, name, hname, cmd[7:].strip(),
106 args, throw) or r
107 else:
108 r = _exthook(ui, repo, hname, cmd, args, throw) or r
109
110 if _redirect:
111 os.dup2(oldstdout, sys.__stdout__.fileno())
112 os.close(oldstdout)
99 try:
100 for hname, cmd in util.sort(ui.configitems('hooks')):
101 if hname.split('.')[0] != name or not cmd:
102 continue
103 if callable(cmd):
104 r = _pythonhook(ui, repo, name, hname, cmd, args, throw) or r
105 elif cmd.startswith('python:'):
106 r = _pythonhook(ui, repo, name, hname, cmd[7:].strip(),
107 args, throw) or r
108 else:
109 r = _exthook(ui, repo, hname, cmd, args, throw) or r
110 finally:
111 if _redirect:
112 os.dup2(oldstdout, sys.__stdout__.fileno())
113 os.close(oldstdout)
113 114
114 115 return r
General Comments 0
You need to be logged in to leave comments. Login now