annotate mercurial/hook.py @ 5909:f45f7390c1c5

strip: calculate list of extra nodes to save and pass it to changegroupsubset When we remove revision N from the repository, all revisions >= N are affected: either it's a descendant from N and will also be removed, or it's not a descendant of N and will be renumbered. As a consequence, we have to (at least temporarily) remove all filelog and manifest revisions that have a linkrev >= N, readding some of them later. Unfortunately, it's possible to have a revlog with two revisions r1 and r2 such that r1 < r2, but linkrev(r1) > linkrev(r2). If we try to strip revision linkrev(r1) from the repository, we'll also lose revision r2 when we truncate this revlog. We already use changegroupsubset to create a temporary changegroup containing the revisions that have to be restored, but that function is unable to detect that we also wanted to save the r2 in the case above. So we manually calculate these extra nodes and pass it to changegroupsubset. This should fix issue764.
author Alexis S. L. Carvalho <alexis@cecm.usp.br>
date Sat, 19 Jan 2008 18:01:16 -0200
parents 2c565b9598b8
children 9f76df0edb7d
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):
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
88 _redirect = state
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
89
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
90 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
91 r = False
5833
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
92
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
93 if _redirect:
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
94 # temporarily redirect stdout to stderr
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
95 oldstdout = os.dup(sys.stdout.fileno())
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
96 os.dup2(sys.stderr.fileno(), sys.stdout.fileno())
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 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
99 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
100 hooks.sort()
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
101 for hname, cmd in hooks:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
102 if callable(cmd):
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
103 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
104 elif cmd.startswith('python:'):
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
105 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
106 args, throw) or r
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
107 else:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
108 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
109 return 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:
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
112 os.dup2(oldstdout, sys.stdout.fileno())
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
113 os.close(oldstdout)