annotate mercurial/hook.py @ 6858:8f256bf98219

Add support for multiple possible bisect results (issue1228, issue1182) The real reason for both issue is that bisect can not handle cases where there are multiple possibilities for the result. Example (from issue1228): rev 0 -> good rev 1 -> skipped rev 2 -> skipped rev 3 -> skipped rev 4 -> bad Note that this patch does not only fix the reported Assertion Error but also the problem of a non converging bisect: hg init for i in `seq 3`; do echo $i > $i; hg add $i; hg ci -m$i; done hg bisect -b 2 hg bisect -g 0 hg bisect -s From this state on, you can: a) mark as bad forever (non converging!) b) mark as good to get an inconsistent state c) skip for the Assertion Error Minor description and code edits by pmezard.
author Bernhard Leiner <bleiner@gmail.com>
date Sat, 02 Aug 2008 22:10:10 +0200
parents 9f76df0edb7d
children f67d1468ac50
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 #
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
5 # This software may be used and distributed according to the terms
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
6 # of the GNU General Public License, incorporated herein by reference.
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 _
5833
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
9 import util, os, sys
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
10
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
11 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
12 '''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
13 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
14 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
15 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
16
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
17 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
18 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
19 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
20
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
21 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
22 obj = funcname
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
23 if not callable(obj):
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
24 d = funcname.rfind('.')
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
25 if d == -1:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
26 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
27 'a module)') % (hname, funcname))
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
28 modname = funcname[:d]
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
29 try:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
30 obj = __import__(modname)
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
31 except ImportError:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
32 try:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
33 # extensions are loaded with hgext_ prefix
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
34 obj = __import__("hgext_%s" % modname)
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
35 except ImportError:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
36 raise util.Abort(_('%s hook is invalid '
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
37 '(import of "%s" failed)') %
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
38 (hname, modname))
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
39 try:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
40 for p in funcname.split('.')[1:]:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
41 obj = getattr(obj, p)
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
42 except AttributeError, err:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
43 raise util.Abort(_('%s hook is invalid '
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
44 '("%s" is not defined)') %
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
45 (hname, funcname))
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
46 if not callable(obj):
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
47 raise util.Abort(_('%s hook is invalid '
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
48 '("%s" is not callable)') %
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
49 (hname, funcname))
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
50 try:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
51 r = obj(ui=ui, repo=repo, hooktype=name, **args)
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
52 except (KeyboardInterrupt, util.SignalInterrupt):
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
53 raise
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
54 except Exception, exc:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
55 if isinstance(exc, util.Abort):
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
56 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
57 (hname, exc.args[0]))
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
58 else:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
59 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
60 '%s\n') % (hname, exc))
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
61 if throw:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
62 raise
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
63 ui.print_exc()
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
64 return True
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
65 if r:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
66 if throw:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
67 raise util.Abort(_('%s hook failed') % hname)
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
68 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
69 return r
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
70
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
71 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
72 ui.note(_("running hook %s: %s\n") % (name, cmd))
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
73 env = dict([('HG_' + k.upper(), v) for k, v in args.iteritems()])
5869
2c565b9598b8 hooks: fix pre- and post- hooks specified in .hg/hgrc
Matt Mackall <mpm@selenic.com>
parents: 5833
diff changeset
74 if repo:
2c565b9598b8 hooks: fix pre- and post- hooks specified in .hg/hgrc
Matt Mackall <mpm@selenic.com>
parents: 5833
diff changeset
75 cwd = repo.root
2c565b9598b8 hooks: fix pre- and post- hooks specified in .hg/hgrc
Matt Mackall <mpm@selenic.com>
parents: 5833
diff changeset
76 else:
2c565b9598b8 hooks: fix pre- and post- hooks specified in .hg/hgrc
Matt Mackall <mpm@selenic.com>
parents: 5833
diff changeset
77 cwd = os.getcwd()
2c565b9598b8 hooks: fix pre- and post- hooks specified in .hg/hgrc
Matt Mackall <mpm@selenic.com>
parents: 5833
diff changeset
78 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
79 if r:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
80 desc, r = util.explain_exit(r)
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
81 if throw:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
82 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
83 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
84 return r
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
85
5833
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
86 _redirect = False
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
87 def redirect(state):
6266
9f76df0edb7d hook.py: fix redirections introduced by 323b9c55b328
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5869
diff changeset
88 global _redirect
5833
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
89 _redirect = state
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
90
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
91 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
92 r = False
5833
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
93
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
94 if _redirect:
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
95 # 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
96 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
97 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
98
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
99 hooks = [(hname, cmd) for hname, cmd in ui.configitems("hooks")
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
100 if hname.split(".", 1)[0] == name and cmd]
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
101 hooks.sort()
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
102 for hname, cmd in hooks:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
103 if callable(cmd):
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
104 r = _pythonhook(ui, repo, name, hname, cmd, args, throw) or r
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
105 elif cmd.startswith('python:'):
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
106 r = _pythonhook(ui, repo, name, hname, cmd[7:].strip(),
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
107 args, throw) or r
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
108 else:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
109 r = _exthook(ui, repo, hname, cmd, args, throw) or r
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
110
5833
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
111 if _redirect:
6266
9f76df0edb7d hook.py: fix redirections introduced by 323b9c55b328
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5869
diff changeset
112 os.dup2(oldstdout, sys.__stdout__.fileno())
5833
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
113 os.close(oldstdout)
6266
9f76df0edb7d hook.py: fix redirections introduced by 323b9c55b328
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5869
diff changeset
114
9f76df0edb7d hook.py: fix redirections introduced by 323b9c55b328
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5869
diff changeset
115 return r