annotate mercurial/hook.py @ 8847:7951f385fcb7

url: support client certificate files over HTTPS (issue643) This extends the httpshandler with the means to utilise the auth section to provide it with a PEM encoded certificate key file and certificate chain file. This works also with sites that both require client certificate authentication and basic or digest password authentication, although the latter situation may require the user to enter the PEM password multiple times.
author Henrik Stuart <hg@hstuart.dk>
date Sat, 20 Jun 2009 10:58:57 +0200
parents 0bf0045000b5
children 872d49dd577a
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
1 # hook.py - hook support for mercurial
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
2 #
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
3 # Copyright 2007 Matt Mackall <mpm@selenic.com>
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
4 #
8225
46293a0c7e9f updated license to be explicit about GPL version 2
Martin Geisler <mg@lazybytes.net>
parents: 8209
diff changeset
5 # This software may be used and distributed according to the terms of the
46293a0c7e9f updated license to be explicit about GPL version 2
Martin Geisler <mg@lazybytes.net>
parents: 8209
diff changeset
6 # GNU General Public License version 2, incorporated herein by reference.
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
7
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
8 from i18n import _
8312
b87a50b7125c separate import lines from mercurial and general python modules
Simon Heimberg <simohe@besonet.ch>
parents: 8225
diff changeset
9 import os, sys
b87a50b7125c separate import lines from mercurial and general python modules
Simon Heimberg <simohe@besonet.ch>
parents: 8225
diff changeset
10 import extensions, util
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
11
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
12 def _pythonhook(ui, repo, name, hname, funcname, args, throw):
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
13 '''call python hook. hook is callable object, looked up as
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
14 name in python module. if callable returns "true", hook
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
15 fails, else passes. if hook raises exception, treated as
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
16 hook failure. exception propagates if throw is "true".
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
17
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
18 reason for "true" meaning "hook failed" is so that
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
19 unmodified commands (e.g. mercurial.commands.update) can
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
20 be run as hooks without wrappers to convert return values.'''
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
21
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
22 ui.note(_("calling hook %s: %s\n") % (hname, funcname))
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
23 obj = funcname
8366
0bf0045000b5 some modernization cleanups, forward compatibility
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8312
diff changeset
24 if not hasattr(obj, '__call__'):
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
25 d = funcname.rfind('.')
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
26 if d == -1:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
27 raise util.Abort(_('%s hook is invalid ("%s" not in '
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
28 'a module)') % (hname, funcname))
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
29 modname = funcname[:d]
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
30 try:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
31 obj = __import__(modname)
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
32 except ImportError:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
33 try:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
34 # extensions are loaded with hgext_ prefix
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
35 obj = __import__("hgext_%s" % modname)
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
36 except ImportError:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
37 raise util.Abort(_('%s hook is invalid '
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
38 '(import of "%s" failed)') %
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
39 (hname, modname))
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
40 try:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
41 for p in funcname.split('.')[1:]:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
42 obj = getattr(obj, p)
7280
810ca383da9c remove unused variables
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 6762
diff changeset
43 except AttributeError:
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
44 raise util.Abort(_('%s hook is invalid '
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
45 '("%s" is not defined)') %
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
46 (hname, funcname))
8366
0bf0045000b5 some modernization cleanups, forward compatibility
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8312
diff changeset
47 if not hasattr(obj, '__call__'):
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
48 raise util.Abort(_('%s hook is invalid '
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
49 '("%s" is not callable)') %
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
50 (hname, funcname))
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
51 try:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
52 r = obj(ui=ui, repo=repo, hooktype=name, **args)
7644
182b7114d35a error: move SignalInterrupt
Matt Mackall <mpm@selenic.com>
parents: 7416
diff changeset
53 except KeyboardInterrupt:
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
54 raise
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
55 except Exception, exc:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
56 if isinstance(exc, util.Abort):
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
57 ui.warn(_('error: %s hook failed: %s\n') %
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
58 (hname, exc.args[0]))
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
59 else:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
60 ui.warn(_('error: %s hook raised an exception: '
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
61 '%s\n') % (hname, exc))
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
62 if throw:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
63 raise
8206
cce63ef1045b ui: print_exc() -> traceback()
Matt Mackall <mpm@selenic.com>
parents: 7916
diff changeset
64 ui.traceback()
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
65 return True
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
66 if r:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
67 if throw:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
68 raise util.Abort(_('%s hook failed') % hname)
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
69 ui.warn(_('warning: %s hook failed\n') % hname)
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
70 return r
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
71
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
72 def _exthook(ui, repo, name, cmd, args, throw):
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
73 ui.note(_("running hook %s: %s\n") % (name, cmd))
7787
b8d750daadde Introduce HG_PREPEND to solve pretxn races
Matt Mackall <mpm@selenic.com>
parents: 7644
diff changeset
74
b8d750daadde Introduce HG_PREPEND to solve pretxn races
Matt Mackall <mpm@selenic.com>
parents: 7644
diff changeset
75 env = {}
b8d750daadde Introduce HG_PREPEND to solve pretxn races
Matt Mackall <mpm@selenic.com>
parents: 7644
diff changeset
76 for k, v in args.iteritems():
8366
0bf0045000b5 some modernization cleanups, forward compatibility
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8312
diff changeset
77 if hasattr(v, '__call__'):
7787
b8d750daadde Introduce HG_PREPEND to solve pretxn races
Matt Mackall <mpm@selenic.com>
parents: 7644
diff changeset
78 v = v()
b8d750daadde Introduce HG_PREPEND to solve pretxn races
Matt Mackall <mpm@selenic.com>
parents: 7644
diff changeset
79 env['HG_' + k.upper()] = v
b8d750daadde Introduce HG_PREPEND to solve pretxn races
Matt Mackall <mpm@selenic.com>
parents: 7644
diff changeset
80
5869
2c565b9598b8 hooks: fix pre- and post- hooks specified in .hg/hgrc
Matt Mackall <mpm@selenic.com>
parents: 5833
diff changeset
81 if repo:
2c565b9598b8 hooks: fix pre- and post- hooks specified in .hg/hgrc
Matt Mackall <mpm@selenic.com>
parents: 5833
diff changeset
82 cwd = repo.root
2c565b9598b8 hooks: fix pre- and post- hooks specified in .hg/hgrc
Matt Mackall <mpm@selenic.com>
parents: 5833
diff changeset
83 else:
2c565b9598b8 hooks: fix pre- and post- hooks specified in .hg/hgrc
Matt Mackall <mpm@selenic.com>
parents: 5833
diff changeset
84 cwd = os.getcwd()
2c565b9598b8 hooks: fix pre- and post- hooks specified in .hg/hgrc
Matt Mackall <mpm@selenic.com>
parents: 5833
diff changeset
85 r = util.system(cmd, environ=env, cwd=cwd)
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
86 if r:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
87 desc, r = util.explain_exit(r)
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
88 if throw:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
89 raise util.Abort(_('%s hook %s') % (name, desc))
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
90 ui.warn(_('warning: %s hook %s\n') % (name, desc))
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
91 return r
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
92
5833
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
93 _redirect = False
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
94 def redirect(state):
6266
9f76df0edb7d hook.py: fix redirections introduced by 323b9c55b328
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5869
diff changeset
95 global _redirect
5833
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
96 _redirect = state
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
97
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
98 def hook(ui, repo, name, throw=False, **args):
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
99 r = False
5833
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
100
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
101 if _redirect:
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
102 # temporarily redirect stdout to stderr
6266
9f76df0edb7d hook.py: fix redirections introduced by 323b9c55b328
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5869
diff changeset
103 oldstdout = os.dup(sys.__stdout__.fileno())
9f76df0edb7d hook.py: fix redirections introduced by 323b9c55b328
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5869
diff changeset
104 os.dup2(sys.__stderr__.fileno(), sys.__stdout__.fileno())
5833
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
105
7416
196b05a548d0 hooks: restore io correctly on exception
Jesse Long <jesse@virtualpostman.co.za>
parents: 7280
diff changeset
106 try:
8209
a1a5a57efe90 replace util.sort with sorted built-in
Matt Mackall <mpm@selenic.com>
parents: 8206
diff changeset
107 for hname, cmd in ui.configitems('hooks'):
7416
196b05a548d0 hooks: restore io correctly on exception
Jesse Long <jesse@virtualpostman.co.za>
parents: 7280
diff changeset
108 if hname.split('.')[0] != name or not cmd:
196b05a548d0 hooks: restore io correctly on exception
Jesse Long <jesse@virtualpostman.co.za>
parents: 7280
diff changeset
109 continue
8366
0bf0045000b5 some modernization cleanups, forward compatibility
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8312
diff changeset
110 if hasattr(cmd, '__call__'):
7416
196b05a548d0 hooks: restore io correctly on exception
Jesse Long <jesse@virtualpostman.co.za>
parents: 7280
diff changeset
111 r = _pythonhook(ui, repo, name, hname, cmd, args, throw) or r
196b05a548d0 hooks: restore io correctly on exception
Jesse Long <jesse@virtualpostman.co.za>
parents: 7280
diff changeset
112 elif cmd.startswith('python:'):
7916
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7787
diff changeset
113 if cmd.count(':') == 2:
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7787
diff changeset
114 path, cmd = cmd[7:].split(':')
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7787
diff changeset
115 mod = extensions.loadpath(path, 'hgkook.%s' % hname)
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7787
diff changeset
116 hookfn = getattr(mod, cmd)
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7787
diff changeset
117 else:
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7787
diff changeset
118 hookfn = cmd[7:].strip()
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7787
diff changeset
119 r = _pythonhook(ui, repo, name, hname, hookfn, args, throw) or r
7416
196b05a548d0 hooks: restore io correctly on exception
Jesse Long <jesse@virtualpostman.co.za>
parents: 7280
diff changeset
120 else:
196b05a548d0 hooks: restore io correctly on exception
Jesse Long <jesse@virtualpostman.co.za>
parents: 7280
diff changeset
121 r = _exthook(ui, repo, hname, cmd, args, throw) or r
196b05a548d0 hooks: restore io correctly on exception
Jesse Long <jesse@virtualpostman.co.za>
parents: 7280
diff changeset
122 finally:
196b05a548d0 hooks: restore io correctly on exception
Jesse Long <jesse@virtualpostman.co.za>
parents: 7280
diff changeset
123 if _redirect:
196b05a548d0 hooks: restore io correctly on exception
Jesse Long <jesse@virtualpostman.co.za>
parents: 7280
diff changeset
124 os.dup2(oldstdout, sys.__stdout__.fileno())
196b05a548d0 hooks: restore io correctly on exception
Jesse Long <jesse@virtualpostman.co.za>
parents: 7280
diff changeset
125 os.close(oldstdout)
6266
9f76df0edb7d hook.py: fix redirections introduced by 323b9c55b328
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5869
diff changeset
126
9f76df0edb7d hook.py: fix redirections introduced by 323b9c55b328
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5869
diff changeset
127 return r