##// END OF EJS Templates
hook: for python hook exceptions, add note to run with --traceback...
Siddharth Agarwal -
r28108:2a71d948 default
parent child Browse files
Show More
@@ -1,242 +1,244
1 # hook.py - hook support for mercurial
1 # hook.py - hook support for mercurial
2 #
2 #
3 # Copyright 2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import os
10 import os
11 import sys
11 import sys
12 import time
12 import time
13
13
14 from .i18n import _
14 from .i18n import _
15 from . import (
15 from . import (
16 demandimport,
16 demandimport,
17 error,
17 error,
18 extensions,
18 extensions,
19 util,
19 util,
20 )
20 )
21
21
22 def _pythonhook(ui, repo, name, hname, funcname, args, throw):
22 def _pythonhook(ui, repo, name, hname, funcname, args, throw):
23 '''call python hook. hook is callable object, looked up as
23 '''call python hook. hook is callable object, looked up as
24 name in python module. if callable returns "true", hook
24 name in python module. if callable returns "true", hook
25 fails, else passes. if hook raises exception, treated as
25 fails, else passes. if hook raises exception, treated as
26 hook failure. exception propagates if throw is "true".
26 hook failure. exception propagates if throw is "true".
27
27
28 reason for "true" meaning "hook failed" is so that
28 reason for "true" meaning "hook failed" is so that
29 unmodified commands (e.g. mercurial.commands.update) can
29 unmodified commands (e.g. mercurial.commands.update) can
30 be run as hooks without wrappers to convert return values.'''
30 be run as hooks without wrappers to convert return values.'''
31
31
32 if callable(funcname):
32 if callable(funcname):
33 obj = funcname
33 obj = funcname
34 funcname = obj.__module__ + "." + obj.__name__
34 funcname = obj.__module__ + "." + obj.__name__
35 else:
35 else:
36 d = funcname.rfind('.')
36 d = funcname.rfind('.')
37 if d == -1:
37 if d == -1:
38 raise error.HookLoadError(
38 raise error.HookLoadError(
39 _('%s hook is invalid: "%s" not in a module')
39 _('%s hook is invalid: "%s" not in a module')
40 % (hname, funcname))
40 % (hname, funcname))
41 modname = funcname[:d]
41 modname = funcname[:d]
42 oldpaths = sys.path
42 oldpaths = sys.path
43 if util.mainfrozen():
43 if util.mainfrozen():
44 # binary installs require sys.path manipulation
44 # binary installs require sys.path manipulation
45 modpath, modfile = os.path.split(modname)
45 modpath, modfile = os.path.split(modname)
46 if modpath and modfile:
46 if modpath and modfile:
47 sys.path = sys.path[:] + [modpath]
47 sys.path = sys.path[:] + [modpath]
48 modname = modfile
48 modname = modfile
49 with demandimport.deactivated():
49 with demandimport.deactivated():
50 try:
50 try:
51 obj = __import__(modname)
51 obj = __import__(modname)
52 except ImportError:
52 except ImportError:
53 e1 = sys.exc_info()
53 e1 = sys.exc_info()
54 try:
54 try:
55 # extensions are loaded with hgext_ prefix
55 # extensions are loaded with hgext_ prefix
56 obj = __import__("hgext_%s" % modname)
56 obj = __import__("hgext_%s" % modname)
57 except ImportError:
57 except ImportError:
58 e2 = sys.exc_info()
58 e2 = sys.exc_info()
59 if ui.tracebackflag:
59 if ui.tracebackflag:
60 ui.warn(_('exception from first failed import '
60 ui.warn(_('exception from first failed import '
61 'attempt:\n'))
61 'attempt:\n'))
62 ui.traceback(e1)
62 ui.traceback(e1)
63 if ui.tracebackflag:
63 if ui.tracebackflag:
64 ui.warn(_('exception from second failed import '
64 ui.warn(_('exception from second failed import '
65 'attempt:\n'))
65 'attempt:\n'))
66 ui.traceback(e2)
66 ui.traceback(e2)
67
67
68 if not ui.tracebackflag:
68 if not ui.tracebackflag:
69 tracebackhint = _(
69 tracebackhint = _(
70 'run with --traceback for stack trace')
70 'run with --traceback for stack trace')
71 else:
71 else:
72 tracebackhint = None
72 tracebackhint = None
73 raise error.HookLoadError(
73 raise error.HookLoadError(
74 _('%s hook is invalid: import of "%s" failed') %
74 _('%s hook is invalid: import of "%s" failed') %
75 (hname, modname), hint=tracebackhint)
75 (hname, modname), hint=tracebackhint)
76 sys.path = oldpaths
76 sys.path = oldpaths
77 try:
77 try:
78 for p in funcname.split('.')[1:]:
78 for p in funcname.split('.')[1:]:
79 obj = getattr(obj, p)
79 obj = getattr(obj, p)
80 except AttributeError:
80 except AttributeError:
81 raise error.HookLoadError(
81 raise error.HookLoadError(
82 _('%s hook is invalid: "%s" is not defined')
82 _('%s hook is invalid: "%s" is not defined')
83 % (hname, funcname))
83 % (hname, funcname))
84 if not callable(obj):
84 if not callable(obj):
85 raise error.HookLoadError(
85 raise error.HookLoadError(
86 _('%s hook is invalid: "%s" is not callable')
86 _('%s hook is invalid: "%s" is not callable')
87 % (hname, funcname))
87 % (hname, funcname))
88
88
89 ui.note(_("calling hook %s: %s\n") % (hname, funcname))
89 ui.note(_("calling hook %s: %s\n") % (hname, funcname))
90 starttime = time.time()
90 starttime = time.time()
91
91
92 try:
92 try:
93 # redirect IO descriptors to the ui descriptors so hooks
93 # redirect IO descriptors to the ui descriptors so hooks
94 # that write directly to these don't mess up the command
94 # that write directly to these don't mess up the command
95 # protocol when running through the command server
95 # protocol when running through the command server
96 old = sys.stdout, sys.stderr, sys.stdin
96 old = sys.stdout, sys.stderr, sys.stdin
97 sys.stdout, sys.stderr, sys.stdin = ui.fout, ui.ferr, ui.fin
97 sys.stdout, sys.stderr, sys.stdin = ui.fout, ui.ferr, ui.fin
98
98
99 r = obj(ui=ui, repo=repo, hooktype=name, **args)
99 r = obj(ui=ui, repo=repo, hooktype=name, **args)
100 except Exception as exc:
100 except Exception as exc:
101 if isinstance(exc, error.Abort):
101 if isinstance(exc, error.Abort):
102 ui.warn(_('error: %s hook failed: %s\n') %
102 ui.warn(_('error: %s hook failed: %s\n') %
103 (hname, exc.args[0]))
103 (hname, exc.args[0]))
104 else:
104 else:
105 ui.warn(_('error: %s hook raised an exception: '
105 ui.warn(_('error: %s hook raised an exception: '
106 '%s\n') % (hname, exc))
106 '%s\n') % (hname, exc))
107 if throw:
107 if throw:
108 raise
108 raise
109 if not ui.tracebackflag:
110 ui.warn(_('(run with --traceback for stack trace)\n'))
109 ui.traceback()
111 ui.traceback()
110 return True, True
112 return True, True
111 finally:
113 finally:
112 sys.stdout, sys.stderr, sys.stdin = old
114 sys.stdout, sys.stderr, sys.stdin = old
113 duration = time.time() - starttime
115 duration = time.time() - starttime
114 ui.log('pythonhook', 'pythonhook-%s: %s finished in %0.2f seconds\n',
116 ui.log('pythonhook', 'pythonhook-%s: %s finished in %0.2f seconds\n',
115 name, funcname, duration)
117 name, funcname, duration)
116 if r:
118 if r:
117 if throw:
119 if throw:
118 raise error.HookAbort(_('%s hook failed') % hname)
120 raise error.HookAbort(_('%s hook failed') % hname)
119 ui.warn(_('warning: %s hook failed\n') % hname)
121 ui.warn(_('warning: %s hook failed\n') % hname)
120 return r, False
122 return r, False
121
123
122 def _exthook(ui, repo, name, cmd, args, throw):
124 def _exthook(ui, repo, name, cmd, args, throw):
123 ui.note(_("running hook %s: %s\n") % (name, cmd))
125 ui.note(_("running hook %s: %s\n") % (name, cmd))
124
126
125 starttime = time.time()
127 starttime = time.time()
126 env = {}
128 env = {}
127
129
128 # make in-memory changes visible to external process
130 # make in-memory changes visible to external process
129 if repo is not None:
131 if repo is not None:
130 tr = repo.currenttransaction()
132 tr = repo.currenttransaction()
131 repo.dirstate.write(tr)
133 repo.dirstate.write(tr)
132 if tr and tr.writepending():
134 if tr and tr.writepending():
133 env['HG_PENDING'] = repo.root
135 env['HG_PENDING'] = repo.root
134
136
135 for k, v in args.iteritems():
137 for k, v in args.iteritems():
136 if callable(v):
138 if callable(v):
137 v = v()
139 v = v()
138 if isinstance(v, dict):
140 if isinstance(v, dict):
139 # make the dictionary element order stable across Python
141 # make the dictionary element order stable across Python
140 # implementations
142 # implementations
141 v = ('{' +
143 v = ('{' +
142 ', '.join('%r: %r' % i for i in sorted(v.iteritems())) +
144 ', '.join('%r: %r' % i for i in sorted(v.iteritems())) +
143 '}')
145 '}')
144 env['HG_' + k.upper()] = v
146 env['HG_' + k.upper()] = v
145
147
146 if repo:
148 if repo:
147 cwd = repo.root
149 cwd = repo.root
148 else:
150 else:
149 cwd = os.getcwd()
151 cwd = os.getcwd()
150 r = ui.system(cmd, environ=env, cwd=cwd)
152 r = ui.system(cmd, environ=env, cwd=cwd)
151
153
152 duration = time.time() - starttime
154 duration = time.time() - starttime
153 ui.log('exthook', 'exthook-%s: %s finished in %0.2f seconds\n',
155 ui.log('exthook', 'exthook-%s: %s finished in %0.2f seconds\n',
154 name, cmd, duration)
156 name, cmd, duration)
155 if r:
157 if r:
156 desc, r = util.explainexit(r)
158 desc, r = util.explainexit(r)
157 if throw:
159 if throw:
158 raise error.HookAbort(_('%s hook %s') % (name, desc))
160 raise error.HookAbort(_('%s hook %s') % (name, desc))
159 ui.warn(_('warning: %s hook %s\n') % (name, desc))
161 ui.warn(_('warning: %s hook %s\n') % (name, desc))
160 return r
162 return r
161
163
162 def _allhooks(ui):
164 def _allhooks(ui):
163 hooks = []
165 hooks = []
164 for name, cmd in ui.configitems('hooks'):
166 for name, cmd in ui.configitems('hooks'):
165 if not name.startswith('priority'):
167 if not name.startswith('priority'):
166 priority = ui.configint('hooks', 'priority.%s' % name, 0)
168 priority = ui.configint('hooks', 'priority.%s' % name, 0)
167 hooks.append((-priority, len(hooks), name, cmd))
169 hooks.append((-priority, len(hooks), name, cmd))
168 return [(k, v) for p, o, k, v in sorted(hooks)]
170 return [(k, v) for p, o, k, v in sorted(hooks)]
169
171
170 _redirect = False
172 _redirect = False
171 def redirect(state):
173 def redirect(state):
172 global _redirect
174 global _redirect
173 _redirect = state
175 _redirect = state
174
176
175 def hook(ui, repo, name, throw=False, **args):
177 def hook(ui, repo, name, throw=False, **args):
176 if not ui.callhooks:
178 if not ui.callhooks:
177 return False
179 return False
178
180
179 hooks = []
181 hooks = []
180 for hname, cmd in _allhooks(ui):
182 for hname, cmd in _allhooks(ui):
181 if hname.split('.')[0] == name and cmd:
183 if hname.split('.')[0] == name and cmd:
182 hooks.append((hname, cmd))
184 hooks.append((hname, cmd))
183
185
184 res = runhooks(ui, repo, name, hooks, throw=throw, **args)
186 res = runhooks(ui, repo, name, hooks, throw=throw, **args)
185 r = False
187 r = False
186 for hname, cmd in hooks:
188 for hname, cmd in hooks:
187 r = res[hname][0] or r
189 r = res[hname][0] or r
188 return r
190 return r
189
191
190 def runhooks(ui, repo, name, hooks, throw=False, **args):
192 def runhooks(ui, repo, name, hooks, throw=False, **args):
191 res = {}
193 res = {}
192 oldstdout = -1
194 oldstdout = -1
193
195
194 try:
196 try:
195 for hname, cmd in hooks:
197 for hname, cmd in hooks:
196 if oldstdout == -1 and _redirect:
198 if oldstdout == -1 and _redirect:
197 try:
199 try:
198 stdoutno = sys.__stdout__.fileno()
200 stdoutno = sys.__stdout__.fileno()
199 stderrno = sys.__stderr__.fileno()
201 stderrno = sys.__stderr__.fileno()
200 # temporarily redirect stdout to stderr, if possible
202 # temporarily redirect stdout to stderr, if possible
201 if stdoutno >= 0 and stderrno >= 0:
203 if stdoutno >= 0 and stderrno >= 0:
202 sys.__stdout__.flush()
204 sys.__stdout__.flush()
203 oldstdout = os.dup(stdoutno)
205 oldstdout = os.dup(stdoutno)
204 os.dup2(stderrno, stdoutno)
206 os.dup2(stderrno, stdoutno)
205 except (OSError, AttributeError):
207 except (OSError, AttributeError):
206 # files seem to be bogus, give up on redirecting (WSGI, etc)
208 # files seem to be bogus, give up on redirecting (WSGI, etc)
207 pass
209 pass
208
210
209 if callable(cmd):
211 if callable(cmd):
210 r, raised = _pythonhook(ui, repo, name, hname, cmd, args, throw)
212 r, raised = _pythonhook(ui, repo, name, hname, cmd, args, throw)
211 elif cmd.startswith('python:'):
213 elif cmd.startswith('python:'):
212 if cmd.count(':') >= 2:
214 if cmd.count(':') >= 2:
213 path, cmd = cmd[7:].rsplit(':', 1)
215 path, cmd = cmd[7:].rsplit(':', 1)
214 path = util.expandpath(path)
216 path = util.expandpath(path)
215 if repo:
217 if repo:
216 path = os.path.join(repo.root, path)
218 path = os.path.join(repo.root, path)
217 try:
219 try:
218 mod = extensions.loadpath(path, 'hghook.%s' % hname)
220 mod = extensions.loadpath(path, 'hghook.%s' % hname)
219 except Exception:
221 except Exception:
220 ui.write(_("loading %s hook failed:\n") % hname)
222 ui.write(_("loading %s hook failed:\n") % hname)
221 raise
223 raise
222 hookfn = getattr(mod, cmd)
224 hookfn = getattr(mod, cmd)
223 else:
225 else:
224 hookfn = cmd[7:].strip()
226 hookfn = cmd[7:].strip()
225 r, raised = _pythonhook(ui, repo, name, hname, hookfn, args,
227 r, raised = _pythonhook(ui, repo, name, hname, hookfn, args,
226 throw)
228 throw)
227 else:
229 else:
228 r = _exthook(ui, repo, hname, cmd, args, throw)
230 r = _exthook(ui, repo, hname, cmd, args, throw)
229 raised = False
231 raised = False
230
232
231 res[hname] = r, raised
233 res[hname] = r, raised
232
234
233 # The stderr is fully buffered on Windows when connected to a pipe.
235 # The stderr is fully buffered on Windows when connected to a pipe.
234 # A forcible flush is required to make small stderr data in the
236 # A forcible flush is required to make small stderr data in the
235 # remote side available to the client immediately.
237 # remote side available to the client immediately.
236 sys.stderr.flush()
238 sys.stderr.flush()
237 finally:
239 finally:
238 if _redirect and oldstdout >= 0:
240 if _redirect and oldstdout >= 0:
239 os.dup2(oldstdout, stdoutno)
241 os.dup2(oldstdout, stdoutno)
240 os.close(oldstdout)
242 os.close(oldstdout)
241
243
242 return res
244 return res
@@ -1,789 +1,790
1 commit hooks can see env vars
1 commit hooks can see env vars
2 (and post-transaction one are run unlocked)
2 (and post-transaction one are run unlocked)
3
3
4 $ cat << EOF >> $HGRCPATH
4 $ cat << EOF >> $HGRCPATH
5 > [experimental]
5 > [experimental]
6 > # drop me once bundle2 is the default,
6 > # drop me once bundle2 is the default,
7 > # added to get test change early.
7 > # added to get test change early.
8 > bundle2-exp = True
8 > bundle2-exp = True
9 > EOF
9 > EOF
10
10
11 $ cat > $TESTTMP/txnabort.checkargs.py <<EOF
11 $ cat > $TESTTMP/txnabort.checkargs.py <<EOF
12 > def showargs(ui, repo, hooktype, **kwargs):
12 > def showargs(ui, repo, hooktype, **kwargs):
13 > ui.write('%s python hook: %s\n' % (hooktype, ','.join(sorted(kwargs))))
13 > ui.write('%s python hook: %s\n' % (hooktype, ','.join(sorted(kwargs))))
14 > EOF
14 > EOF
15
15
16 $ hg init a
16 $ hg init a
17 $ cd a
17 $ cd a
18 $ cat > .hg/hgrc <<EOF
18 $ cat > .hg/hgrc <<EOF
19 > [hooks]
19 > [hooks]
20 > commit = sh -c "HG_LOCAL= HG_TAG= printenv.py commit"
20 > commit = sh -c "HG_LOCAL= HG_TAG= printenv.py commit"
21 > commit.b = sh -c "HG_LOCAL= HG_TAG= printenv.py commit.b"
21 > commit.b = sh -c "HG_LOCAL= HG_TAG= printenv.py commit.b"
22 > precommit = sh -c "HG_LOCAL= HG_NODE= HG_TAG= printenv.py precommit"
22 > precommit = sh -c "HG_LOCAL= HG_NODE= HG_TAG= printenv.py precommit"
23 > pretxncommit = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxncommit"
23 > pretxncommit = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxncommit"
24 > pretxncommit.tip = hg -q tip
24 > pretxncommit.tip = hg -q tip
25 > pre-identify = printenv.py pre-identify 1
25 > pre-identify = printenv.py pre-identify 1
26 > pre-cat = printenv.py pre-cat
26 > pre-cat = printenv.py pre-cat
27 > post-cat = printenv.py post-cat
27 > post-cat = printenv.py post-cat
28 > pretxnopen = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxnopen"
28 > pretxnopen = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxnopen"
29 > pretxnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxnclose"
29 > pretxnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxnclose"
30 > txnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py txnclose"
30 > txnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py txnclose"
31 > txnabort.0 = python:$TESTTMP/txnabort.checkargs.py:showargs
31 > txnabort.0 = python:$TESTTMP/txnabort.checkargs.py:showargs
32 > txnabort.1 = sh -c "HG_LOCAL= HG_TAG= printenv.py txnabort"
32 > txnabort.1 = sh -c "HG_LOCAL= HG_TAG= printenv.py txnabort"
33 > txnclose.checklock = sh -c "hg debuglock > /dev/null"
33 > txnclose.checklock = sh -c "hg debuglock > /dev/null"
34 > EOF
34 > EOF
35 $ echo a > a
35 $ echo a > a
36 $ hg add a
36 $ hg add a
37 $ hg commit -m a
37 $ hg commit -m a
38 precommit hook: HG_PARENT1=0000000000000000000000000000000000000000
38 precommit hook: HG_PARENT1=0000000000000000000000000000000000000000
39 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
39 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
40 pretxncommit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000 HG_PENDING=$TESTTMP/a
40 pretxncommit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000 HG_PENDING=$TESTTMP/a
41 0:cb9a9f314b8b
41 0:cb9a9f314b8b
42 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
42 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
43 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
43 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
44 commit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
44 commit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
45 commit.b hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
45 commit.b hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
46
46
47 $ hg clone . ../b
47 $ hg clone . ../b
48 updating to branch default
48 updating to branch default
49 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
49 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
50 $ cd ../b
50 $ cd ../b
51
51
52 changegroup hooks can see env vars
52 changegroup hooks can see env vars
53
53
54 $ cat > .hg/hgrc <<EOF
54 $ cat > .hg/hgrc <<EOF
55 > [hooks]
55 > [hooks]
56 > prechangegroup = printenv.py prechangegroup
56 > prechangegroup = printenv.py prechangegroup
57 > changegroup = printenv.py changegroup
57 > changegroup = printenv.py changegroup
58 > incoming = printenv.py incoming
58 > incoming = printenv.py incoming
59 > EOF
59 > EOF
60
60
61 pretxncommit and commit hooks can see both parents of merge
61 pretxncommit and commit hooks can see both parents of merge
62
62
63 $ cd ../a
63 $ cd ../a
64 $ echo b >> a
64 $ echo b >> a
65 $ hg commit -m a1 -d "1 0"
65 $ hg commit -m a1 -d "1 0"
66 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
66 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
67 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
67 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
68 pretxncommit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
68 pretxncommit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
69 1:ab228980c14d
69 1:ab228980c14d
70 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
70 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
71 txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
71 txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
72 commit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
72 commit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
73 commit.b hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
73 commit.b hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
74 $ hg update -C 0
74 $ hg update -C 0
75 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
75 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
76 $ echo b > b
76 $ echo b > b
77 $ hg add b
77 $ hg add b
78 $ hg commit -m b -d '1 0'
78 $ hg commit -m b -d '1 0'
79 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
79 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
80 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
80 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
81 pretxncommit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
81 pretxncommit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
82 2:ee9deb46ab31
82 2:ee9deb46ab31
83 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
83 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
84 created new head
84 created new head
85 txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
85 txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
86 commit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
86 commit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
87 commit.b hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
87 commit.b hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
88 $ hg merge 1
88 $ hg merge 1
89 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
89 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
90 (branch merge, don't forget to commit)
90 (branch merge, don't forget to commit)
91 $ hg commit -m merge -d '2 0'
91 $ hg commit -m merge -d '2 0'
92 precommit hook: HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
92 precommit hook: HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
93 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
93 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
94 pretxncommit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd HG_PENDING=$TESTTMP/a
94 pretxncommit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd HG_PENDING=$TESTTMP/a
95 3:07f3376c1e65
95 3:07f3376c1e65
96 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
96 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
97 txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
97 txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
98 commit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
98 commit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
99 commit.b hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
99 commit.b hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
100
100
101 test generic hooks
101 test generic hooks
102
102
103 $ hg id
103 $ hg id
104 pre-identify hook: HG_ARGS=id HG_OPTS={'bookmarks': None, 'branch': None, 'id': None, 'insecure': None, 'num': None, 'remotecmd': '', 'rev': '', 'ssh': '', 'tags': None} HG_PATS=[]
104 pre-identify hook: HG_ARGS=id HG_OPTS={'bookmarks': None, 'branch': None, 'id': None, 'insecure': None, 'num': None, 'remotecmd': '', 'rev': '', 'ssh': '', 'tags': None} HG_PATS=[]
105 abort: pre-identify hook exited with status 1
105 abort: pre-identify hook exited with status 1
106 [255]
106 [255]
107 $ hg cat b
107 $ hg cat b
108 pre-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b']
108 pre-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b']
109 b
109 b
110 post-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b'] HG_RESULT=0
110 post-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b'] HG_RESULT=0
111
111
112 $ cd ../b
112 $ cd ../b
113 $ hg pull ../a
113 $ hg pull ../a
114 pulling from ../a
114 pulling from ../a
115 searching for changes
115 searching for changes
116 prechangegroup hook: HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
116 prechangegroup hook: HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
117 adding changesets
117 adding changesets
118 adding manifests
118 adding manifests
119 adding file changes
119 adding file changes
120 added 3 changesets with 2 changes to 2 files
120 added 3 changesets with 2 changes to 2 files
121 changegroup hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_NODE_LAST=07f3376c1e655977439df2a814e3cc14b27abac2 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
121 changegroup hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_NODE_LAST=07f3376c1e655977439df2a814e3cc14b27abac2 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
122 incoming hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
122 incoming hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
123 incoming hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
123 incoming hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
124 incoming hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
124 incoming hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
125 (run 'hg update' to get a working copy)
125 (run 'hg update' to get a working copy)
126
126
127 tag hooks can see env vars
127 tag hooks can see env vars
128
128
129 $ cd ../a
129 $ cd ../a
130 $ cat >> .hg/hgrc <<EOF
130 $ cat >> .hg/hgrc <<EOF
131 > pretag = printenv.py pretag
131 > pretag = printenv.py pretag
132 > tag = sh -c "HG_PARENT1= HG_PARENT2= printenv.py tag"
132 > tag = sh -c "HG_PARENT1= HG_PARENT2= printenv.py tag"
133 > EOF
133 > EOF
134 $ hg tag -d '3 0' a
134 $ hg tag -d '3 0' a
135 pretag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
135 pretag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
136 precommit hook: HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
136 precommit hook: HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
137 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
137 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
138 pretxncommit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PENDING=$TESTTMP/a
138 pretxncommit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PENDING=$TESTTMP/a
139 4:539e4b31b6dc
139 4:539e4b31b6dc
140 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
140 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
141 tag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
141 tag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
142 txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
142 txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
143 commit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
143 commit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
144 commit.b hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
144 commit.b hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
145 $ hg tag -l la
145 $ hg tag -l la
146 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
146 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
147 tag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
147 tag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
148
148
149 pretag hook can forbid tagging
149 pretag hook can forbid tagging
150
150
151 $ echo "pretag.forbid = printenv.py pretag.forbid 1" >> .hg/hgrc
151 $ echo "pretag.forbid = printenv.py pretag.forbid 1" >> .hg/hgrc
152 $ hg tag -d '4 0' fa
152 $ hg tag -d '4 0' fa
153 pretag hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
153 pretag hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
154 pretag.forbid hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
154 pretag.forbid hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
155 abort: pretag.forbid hook exited with status 1
155 abort: pretag.forbid hook exited with status 1
156 [255]
156 [255]
157 $ hg tag -l fla
157 $ hg tag -l fla
158 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
158 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
159 pretag.forbid hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
159 pretag.forbid hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
160 abort: pretag.forbid hook exited with status 1
160 abort: pretag.forbid hook exited with status 1
161 [255]
161 [255]
162
162
163 pretxncommit hook can see changeset, can roll back txn, changeset no
163 pretxncommit hook can see changeset, can roll back txn, changeset no
164 more there after
164 more there after
165
165
166 $ echo "pretxncommit.forbid0 = hg tip -q" >> .hg/hgrc
166 $ echo "pretxncommit.forbid0 = hg tip -q" >> .hg/hgrc
167 $ echo "pretxncommit.forbid1 = printenv.py pretxncommit.forbid 1" >> .hg/hgrc
167 $ echo "pretxncommit.forbid1 = printenv.py pretxncommit.forbid 1" >> .hg/hgrc
168 $ echo z > z
168 $ echo z > z
169 $ hg add z
169 $ hg add z
170 $ hg -q tip
170 $ hg -q tip
171 4:539e4b31b6dc
171 4:539e4b31b6dc
172 $ hg commit -m 'fail' -d '4 0'
172 $ hg commit -m 'fail' -d '4 0'
173 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
173 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
174 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
174 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
175 pretxncommit hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
175 pretxncommit hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
176 5:6f611f8018c1
176 5:6f611f8018c1
177 5:6f611f8018c1
177 5:6f611f8018c1
178 pretxncommit.forbid hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
178 pretxncommit.forbid hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
179 transaction abort!
179 transaction abort!
180 txnabort python hook: txnid,txnname
180 txnabort python hook: txnid,txnname
181 txnabort hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
181 txnabort hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
182 rollback completed
182 rollback completed
183 abort: pretxncommit.forbid1 hook exited with status 1
183 abort: pretxncommit.forbid1 hook exited with status 1
184 [255]
184 [255]
185 $ hg -q tip
185 $ hg -q tip
186 4:539e4b31b6dc
186 4:539e4b31b6dc
187
187
188 (Check that no 'changelog.i.a' file were left behind)
188 (Check that no 'changelog.i.a' file were left behind)
189
189
190 $ ls -1 .hg/store/
190 $ ls -1 .hg/store/
191 00changelog.i
191 00changelog.i
192 00manifest.i
192 00manifest.i
193 data
193 data
194 fncache
194 fncache
195 journal.phaseroots
195 journal.phaseroots
196 phaseroots
196 phaseroots
197 undo
197 undo
198 undo.backup.fncache
198 undo.backup.fncache
199 undo.backupfiles
199 undo.backupfiles
200 undo.phaseroots
200 undo.phaseroots
201
201
202
202
203 precommit hook can prevent commit
203 precommit hook can prevent commit
204
204
205 $ echo "precommit.forbid = printenv.py precommit.forbid 1" >> .hg/hgrc
205 $ echo "precommit.forbid = printenv.py precommit.forbid 1" >> .hg/hgrc
206 $ hg commit -m 'fail' -d '4 0'
206 $ hg commit -m 'fail' -d '4 0'
207 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
207 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
208 precommit.forbid hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
208 precommit.forbid hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
209 abort: precommit.forbid hook exited with status 1
209 abort: precommit.forbid hook exited with status 1
210 [255]
210 [255]
211 $ hg -q tip
211 $ hg -q tip
212 4:539e4b31b6dc
212 4:539e4b31b6dc
213
213
214 preupdate hook can prevent update
214 preupdate hook can prevent update
215
215
216 $ echo "preupdate = printenv.py preupdate" >> .hg/hgrc
216 $ echo "preupdate = printenv.py preupdate" >> .hg/hgrc
217 $ hg update 1
217 $ hg update 1
218 preupdate hook: HG_PARENT1=ab228980c14d
218 preupdate hook: HG_PARENT1=ab228980c14d
219 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
219 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
220
220
221 update hook
221 update hook
222
222
223 $ echo "update = printenv.py update" >> .hg/hgrc
223 $ echo "update = printenv.py update" >> .hg/hgrc
224 $ hg update
224 $ hg update
225 preupdate hook: HG_PARENT1=539e4b31b6dc
225 preupdate hook: HG_PARENT1=539e4b31b6dc
226 update hook: HG_ERROR=0 HG_PARENT1=539e4b31b6dc
226 update hook: HG_ERROR=0 HG_PARENT1=539e4b31b6dc
227 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
227 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
228
228
229 pushkey hook
229 pushkey hook
230
230
231 $ echo "pushkey = printenv.py pushkey" >> .hg/hgrc
231 $ echo "pushkey = printenv.py pushkey" >> .hg/hgrc
232 $ cd ../b
232 $ cd ../b
233 $ hg bookmark -r null foo
233 $ hg bookmark -r null foo
234 $ hg push -B foo ../a
234 $ hg push -B foo ../a
235 pushing to ../a
235 pushing to ../a
236 searching for changes
236 searching for changes
237 no changes found
237 no changes found
238 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=push (glob)
238 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=push (glob)
239 pretxnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_PENDING=$TESTTMP/a HG_SOURCE=push HG_TXNID=TXN:* HG_TXNNAME=push HG_URL=push (glob)
239 pretxnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_PENDING=$TESTTMP/a HG_SOURCE=push HG_TXNID=TXN:* HG_TXNNAME=push HG_URL=push (glob)
240 pushkey hook: HG_KEY=foo HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_RET=1
240 pushkey hook: HG_KEY=foo HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_RET=1
241 txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_SOURCE=push HG_TXNID=TXN:* HG_TXNNAME=push HG_URL=push (glob)
241 txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_SOURCE=push HG_TXNID=TXN:* HG_TXNNAME=push HG_URL=push (glob)
242 exporting bookmark foo
242 exporting bookmark foo
243 [1]
243 [1]
244 $ cd ../a
244 $ cd ../a
245
245
246 listkeys hook
246 listkeys hook
247
247
248 $ echo "listkeys = printenv.py listkeys" >> .hg/hgrc
248 $ echo "listkeys = printenv.py listkeys" >> .hg/hgrc
249 $ hg bookmark -r null bar
249 $ hg bookmark -r null bar
250 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
250 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
251 pretxnclose hook: HG_BOOKMARK_MOVED=1 HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
251 pretxnclose hook: HG_BOOKMARK_MOVED=1 HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
252 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
252 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
253 $ cd ../b
253 $ cd ../b
254 $ hg pull -B bar ../a
254 $ hg pull -B bar ../a
255 pulling from ../a
255 pulling from ../a
256 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
256 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
257 no changes found
257 no changes found
258 listkeys hook: HG_NAMESPACE=phase HG_VALUES={}
258 listkeys hook: HG_NAMESPACE=phase HG_VALUES={}
259 adding remote bookmark bar
259 adding remote bookmark bar
260 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
260 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
261 $ cd ../a
261 $ cd ../a
262
262
263 test that prepushkey can prevent incoming keys
263 test that prepushkey can prevent incoming keys
264
264
265 $ echo "prepushkey = printenv.py prepushkey.forbid 1" >> .hg/hgrc
265 $ echo "prepushkey = printenv.py prepushkey.forbid 1" >> .hg/hgrc
266 $ cd ../b
266 $ cd ../b
267 $ hg bookmark -r null baz
267 $ hg bookmark -r null baz
268 $ hg push -B baz ../a
268 $ hg push -B baz ../a
269 pushing to ../a
269 pushing to ../a
270 searching for changes
270 searching for changes
271 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
271 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
272 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
272 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
273 no changes found
273 no changes found
274 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=push (glob)
274 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=push (glob)
275 prepushkey.forbid hook: HG_BUNDLE2=1 HG_KEY=baz HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_SOURCE=push HG_TXNID=TXN:* HG_URL=push (glob)
275 prepushkey.forbid hook: HG_BUNDLE2=1 HG_KEY=baz HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_SOURCE=push HG_TXNID=TXN:* HG_URL=push (glob)
276 pushkey-abort: prepushkey hook exited with status 1
276 pushkey-abort: prepushkey hook exited with status 1
277 abort: exporting bookmark baz failed!
277 abort: exporting bookmark baz failed!
278 [255]
278 [255]
279 $ cd ../a
279 $ cd ../a
280
280
281 test that prelistkeys can prevent listing keys
281 test that prelistkeys can prevent listing keys
282
282
283 $ echo "prelistkeys = printenv.py prelistkeys.forbid 1" >> .hg/hgrc
283 $ echo "prelistkeys = printenv.py prelistkeys.forbid 1" >> .hg/hgrc
284 $ hg bookmark -r null quux
284 $ hg bookmark -r null quux
285 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
285 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
286 pretxnclose hook: HG_BOOKMARK_MOVED=1 HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
286 pretxnclose hook: HG_BOOKMARK_MOVED=1 HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
287 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
287 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
288 $ cd ../b
288 $ cd ../b
289 $ hg pull -B quux ../a
289 $ hg pull -B quux ../a
290 pulling from ../a
290 pulling from ../a
291 prelistkeys.forbid hook: HG_NAMESPACE=bookmarks
291 prelistkeys.forbid hook: HG_NAMESPACE=bookmarks
292 abort: prelistkeys hook exited with status 1
292 abort: prelistkeys hook exited with status 1
293 [255]
293 [255]
294 $ cd ../a
294 $ cd ../a
295 $ rm .hg/hgrc
295 $ rm .hg/hgrc
296
296
297 prechangegroup hook can prevent incoming changes
297 prechangegroup hook can prevent incoming changes
298
298
299 $ cd ../b
299 $ cd ../b
300 $ hg -q tip
300 $ hg -q tip
301 3:07f3376c1e65
301 3:07f3376c1e65
302 $ cat > .hg/hgrc <<EOF
302 $ cat > .hg/hgrc <<EOF
303 > [hooks]
303 > [hooks]
304 > prechangegroup.forbid = printenv.py prechangegroup.forbid 1
304 > prechangegroup.forbid = printenv.py prechangegroup.forbid 1
305 > EOF
305 > EOF
306 $ hg pull ../a
306 $ hg pull ../a
307 pulling from ../a
307 pulling from ../a
308 searching for changes
308 searching for changes
309 prechangegroup.forbid hook: HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
309 prechangegroup.forbid hook: HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
310 abort: prechangegroup.forbid hook exited with status 1
310 abort: prechangegroup.forbid hook exited with status 1
311 [255]
311 [255]
312
312
313 pretxnchangegroup hook can see incoming changes, can roll back txn,
313 pretxnchangegroup hook can see incoming changes, can roll back txn,
314 incoming changes no longer there after
314 incoming changes no longer there after
315
315
316 $ cat > .hg/hgrc <<EOF
316 $ cat > .hg/hgrc <<EOF
317 > [hooks]
317 > [hooks]
318 > pretxnchangegroup.forbid0 = hg tip -q
318 > pretxnchangegroup.forbid0 = hg tip -q
319 > pretxnchangegroup.forbid1 = printenv.py pretxnchangegroup.forbid 1
319 > pretxnchangegroup.forbid1 = printenv.py pretxnchangegroup.forbid 1
320 > EOF
320 > EOF
321 $ hg pull ../a
321 $ hg pull ../a
322 pulling from ../a
322 pulling from ../a
323 searching for changes
323 searching for changes
324 adding changesets
324 adding changesets
325 adding manifests
325 adding manifests
326 adding file changes
326 adding file changes
327 added 1 changesets with 1 changes to 1 files
327 added 1 changesets with 1 changes to 1 files
328 4:539e4b31b6dc
328 4:539e4b31b6dc
329 pretxnchangegroup.forbid hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_NODE_LAST=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/b HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
329 pretxnchangegroup.forbid hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_NODE_LAST=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/b HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
330 transaction abort!
330 transaction abort!
331 rollback completed
331 rollback completed
332 abort: pretxnchangegroup.forbid1 hook exited with status 1
332 abort: pretxnchangegroup.forbid1 hook exited with status 1
333 [255]
333 [255]
334 $ hg -q tip
334 $ hg -q tip
335 3:07f3376c1e65
335 3:07f3376c1e65
336
336
337 outgoing hooks can see env vars
337 outgoing hooks can see env vars
338
338
339 $ rm .hg/hgrc
339 $ rm .hg/hgrc
340 $ cat > ../a/.hg/hgrc <<EOF
340 $ cat > ../a/.hg/hgrc <<EOF
341 > [hooks]
341 > [hooks]
342 > preoutgoing = printenv.py preoutgoing
342 > preoutgoing = printenv.py preoutgoing
343 > outgoing = printenv.py outgoing
343 > outgoing = printenv.py outgoing
344 > EOF
344 > EOF
345 $ hg pull ../a
345 $ hg pull ../a
346 pulling from ../a
346 pulling from ../a
347 searching for changes
347 searching for changes
348 preoutgoing hook: HG_SOURCE=pull
348 preoutgoing hook: HG_SOURCE=pull
349 outgoing hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_SOURCE=pull
349 outgoing hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_SOURCE=pull
350 adding changesets
350 adding changesets
351 adding manifests
351 adding manifests
352 adding file changes
352 adding file changes
353 added 1 changesets with 1 changes to 1 files
353 added 1 changesets with 1 changes to 1 files
354 adding remote bookmark quux
354 adding remote bookmark quux
355 (run 'hg update' to get a working copy)
355 (run 'hg update' to get a working copy)
356 $ hg rollback
356 $ hg rollback
357 repository tip rolled back to revision 3 (undo pull)
357 repository tip rolled back to revision 3 (undo pull)
358
358
359 preoutgoing hook can prevent outgoing changes
359 preoutgoing hook can prevent outgoing changes
360
360
361 $ echo "preoutgoing.forbid = printenv.py preoutgoing.forbid 1" >> ../a/.hg/hgrc
361 $ echo "preoutgoing.forbid = printenv.py preoutgoing.forbid 1" >> ../a/.hg/hgrc
362 $ hg pull ../a
362 $ hg pull ../a
363 pulling from ../a
363 pulling from ../a
364 searching for changes
364 searching for changes
365 preoutgoing hook: HG_SOURCE=pull
365 preoutgoing hook: HG_SOURCE=pull
366 preoutgoing.forbid hook: HG_SOURCE=pull
366 preoutgoing.forbid hook: HG_SOURCE=pull
367 abort: preoutgoing.forbid hook exited with status 1
367 abort: preoutgoing.forbid hook exited with status 1
368 [255]
368 [255]
369
369
370 outgoing hooks work for local clones
370 outgoing hooks work for local clones
371
371
372 $ cd ..
372 $ cd ..
373 $ cat > a/.hg/hgrc <<EOF
373 $ cat > a/.hg/hgrc <<EOF
374 > [hooks]
374 > [hooks]
375 > preoutgoing = printenv.py preoutgoing
375 > preoutgoing = printenv.py preoutgoing
376 > outgoing = printenv.py outgoing
376 > outgoing = printenv.py outgoing
377 > EOF
377 > EOF
378 $ hg clone a c
378 $ hg clone a c
379 preoutgoing hook: HG_SOURCE=clone
379 preoutgoing hook: HG_SOURCE=clone
380 outgoing hook: HG_NODE=0000000000000000000000000000000000000000 HG_SOURCE=clone
380 outgoing hook: HG_NODE=0000000000000000000000000000000000000000 HG_SOURCE=clone
381 updating to branch default
381 updating to branch default
382 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
382 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
383 $ rm -rf c
383 $ rm -rf c
384
384
385 preoutgoing hook can prevent outgoing changes for local clones
385 preoutgoing hook can prevent outgoing changes for local clones
386
386
387 $ echo "preoutgoing.forbid = printenv.py preoutgoing.forbid 1" >> a/.hg/hgrc
387 $ echo "preoutgoing.forbid = printenv.py preoutgoing.forbid 1" >> a/.hg/hgrc
388 $ hg clone a zzz
388 $ hg clone a zzz
389 preoutgoing hook: HG_SOURCE=clone
389 preoutgoing hook: HG_SOURCE=clone
390 preoutgoing.forbid hook: HG_SOURCE=clone
390 preoutgoing.forbid hook: HG_SOURCE=clone
391 abort: preoutgoing.forbid hook exited with status 1
391 abort: preoutgoing.forbid hook exited with status 1
392 [255]
392 [255]
393
393
394 $ cd "$TESTTMP/b"
394 $ cd "$TESTTMP/b"
395
395
396 $ cat > hooktests.py <<EOF
396 $ cat > hooktests.py <<EOF
397 > from mercurial import error
397 > from mercurial import error
398 >
398 >
399 > uncallable = 0
399 > uncallable = 0
400 >
400 >
401 > def printargs(args):
401 > def printargs(args):
402 > args.pop('ui', None)
402 > args.pop('ui', None)
403 > args.pop('repo', None)
403 > args.pop('repo', None)
404 > a = list(args.items())
404 > a = list(args.items())
405 > a.sort()
405 > a.sort()
406 > print 'hook args:'
406 > print 'hook args:'
407 > for k, v in a:
407 > for k, v in a:
408 > print ' ', k, v
408 > print ' ', k, v
409 >
409 >
410 > def passhook(**args):
410 > def passhook(**args):
411 > printargs(args)
411 > printargs(args)
412 >
412 >
413 > def failhook(**args):
413 > def failhook(**args):
414 > printargs(args)
414 > printargs(args)
415 > return True
415 > return True
416 >
416 >
417 > class LocalException(Exception):
417 > class LocalException(Exception):
418 > pass
418 > pass
419 >
419 >
420 > def raisehook(**args):
420 > def raisehook(**args):
421 > raise LocalException('exception from hook')
421 > raise LocalException('exception from hook')
422 >
422 >
423 > def aborthook(**args):
423 > def aborthook(**args):
424 > raise error.Abort('raise abort from hook')
424 > raise error.Abort('raise abort from hook')
425 >
425 >
426 > def brokenhook(**args):
426 > def brokenhook(**args):
427 > return 1 + {}
427 > return 1 + {}
428 >
428 >
429 > def verbosehook(ui, **args):
429 > def verbosehook(ui, **args):
430 > ui.note('verbose output from hook\n')
430 > ui.note('verbose output from hook\n')
431 >
431 >
432 > def printtags(ui, repo, **args):
432 > def printtags(ui, repo, **args):
433 > print sorted(repo.tags())
433 > print sorted(repo.tags())
434 >
434 >
435 > class container:
435 > class container:
436 > unreachable = 1
436 > unreachable = 1
437 > EOF
437 > EOF
438
438
439 test python hooks
439 test python hooks
440
440
441 #if windows
441 #if windows
442 $ PYTHONPATH="$TESTTMP/b;$PYTHONPATH"
442 $ PYTHONPATH="$TESTTMP/b;$PYTHONPATH"
443 #else
443 #else
444 $ PYTHONPATH="$TESTTMP/b:$PYTHONPATH"
444 $ PYTHONPATH="$TESTTMP/b:$PYTHONPATH"
445 #endif
445 #endif
446 $ export PYTHONPATH
446 $ export PYTHONPATH
447
447
448 $ echo '[hooks]' > ../a/.hg/hgrc
448 $ echo '[hooks]' > ../a/.hg/hgrc
449 $ echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
449 $ echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
450 $ hg pull ../a 2>&1 | grep 'raised an exception'
450 $ hg pull ../a 2>&1 | grep 'raised an exception'
451 error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
451 error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
452
452
453 $ echo '[hooks]' > ../a/.hg/hgrc
453 $ echo '[hooks]' > ../a/.hg/hgrc
454 $ echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
454 $ echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
455 $ hg pull ../a 2>&1 | grep 'raised an exception'
455 $ hg pull ../a 2>&1 | grep 'raised an exception'
456 error: preoutgoing.raise hook raised an exception: exception from hook
456 error: preoutgoing.raise hook raised an exception: exception from hook
457
457
458 $ echo '[hooks]' > ../a/.hg/hgrc
458 $ echo '[hooks]' > ../a/.hg/hgrc
459 $ echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
459 $ echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
460 $ hg pull ../a
460 $ hg pull ../a
461 pulling from ../a
461 pulling from ../a
462 searching for changes
462 searching for changes
463 error: preoutgoing.abort hook failed: raise abort from hook
463 error: preoutgoing.abort hook failed: raise abort from hook
464 abort: raise abort from hook
464 abort: raise abort from hook
465 [255]
465 [255]
466
466
467 $ echo '[hooks]' > ../a/.hg/hgrc
467 $ echo '[hooks]' > ../a/.hg/hgrc
468 $ echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
468 $ echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
469 $ hg pull ../a
469 $ hg pull ../a
470 pulling from ../a
470 pulling from ../a
471 searching for changes
471 searching for changes
472 hook args:
472 hook args:
473 hooktype preoutgoing
473 hooktype preoutgoing
474 source pull
474 source pull
475 abort: preoutgoing.fail hook failed
475 abort: preoutgoing.fail hook failed
476 [255]
476 [255]
477
477
478 $ echo '[hooks]' > ../a/.hg/hgrc
478 $ echo '[hooks]' > ../a/.hg/hgrc
479 $ echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
479 $ echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
480 $ hg pull ../a
480 $ hg pull ../a
481 pulling from ../a
481 pulling from ../a
482 searching for changes
482 searching for changes
483 abort: preoutgoing.uncallable hook is invalid: "hooktests.uncallable" is not callable
483 abort: preoutgoing.uncallable hook is invalid: "hooktests.uncallable" is not callable
484 [255]
484 [255]
485
485
486 $ echo '[hooks]' > ../a/.hg/hgrc
486 $ echo '[hooks]' > ../a/.hg/hgrc
487 $ echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
487 $ echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
488 $ hg pull ../a
488 $ hg pull ../a
489 pulling from ../a
489 pulling from ../a
490 searching for changes
490 searching for changes
491 abort: preoutgoing.nohook hook is invalid: "hooktests.nohook" is not defined
491 abort: preoutgoing.nohook hook is invalid: "hooktests.nohook" is not defined
492 [255]
492 [255]
493
493
494 $ echo '[hooks]' > ../a/.hg/hgrc
494 $ echo '[hooks]' > ../a/.hg/hgrc
495 $ echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
495 $ echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
496 $ hg pull ../a
496 $ hg pull ../a
497 pulling from ../a
497 pulling from ../a
498 searching for changes
498 searching for changes
499 abort: preoutgoing.nomodule hook is invalid: "nomodule" not in a module
499 abort: preoutgoing.nomodule hook is invalid: "nomodule" not in a module
500 [255]
500 [255]
501
501
502 $ echo '[hooks]' > ../a/.hg/hgrc
502 $ echo '[hooks]' > ../a/.hg/hgrc
503 $ echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
503 $ echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
504 $ hg pull ../a
504 $ hg pull ../a
505 pulling from ../a
505 pulling from ../a
506 searching for changes
506 searching for changes
507 abort: preoutgoing.badmodule hook is invalid: import of "nomodule" failed
507 abort: preoutgoing.badmodule hook is invalid: import of "nomodule" failed
508 (run with --traceback for stack trace)
508 (run with --traceback for stack trace)
509 [255]
509 [255]
510
510
511 $ echo '[hooks]' > ../a/.hg/hgrc
511 $ echo '[hooks]' > ../a/.hg/hgrc
512 $ echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
512 $ echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
513 $ hg pull ../a
513 $ hg pull ../a
514 pulling from ../a
514 pulling from ../a
515 searching for changes
515 searching for changes
516 abort: preoutgoing.unreachable hook is invalid: import of "hooktests.container" failed
516 abort: preoutgoing.unreachable hook is invalid: import of "hooktests.container" failed
517 (run with --traceback for stack trace)
517 (run with --traceback for stack trace)
518 [255]
518 [255]
519
519
520 $ echo '[hooks]' > ../a/.hg/hgrc
520 $ echo '[hooks]' > ../a/.hg/hgrc
521 $ echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
521 $ echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
522 $ hg pull ../a
522 $ hg pull ../a
523 pulling from ../a
523 pulling from ../a
524 searching for changes
524 searching for changes
525 hook args:
525 hook args:
526 hooktype preoutgoing
526 hooktype preoutgoing
527 source pull
527 source pull
528 adding changesets
528 adding changesets
529 adding manifests
529 adding manifests
530 adding file changes
530 adding file changes
531 added 1 changesets with 1 changes to 1 files
531 added 1 changesets with 1 changes to 1 files
532 adding remote bookmark quux
532 adding remote bookmark quux
533 (run 'hg update' to get a working copy)
533 (run 'hg update' to get a working copy)
534
534
535 post- python hooks that fail to *run* don't cause an abort
535 post- python hooks that fail to *run* don't cause an abort
536 $ rm ../a/.hg/hgrc
536 $ rm ../a/.hg/hgrc
537 $ echo '[hooks]' > .hg/hgrc
537 $ echo '[hooks]' > .hg/hgrc
538 $ echo 'post-pull.broken = python:hooktests.brokenhook' >> .hg/hgrc
538 $ echo 'post-pull.broken = python:hooktests.brokenhook' >> .hg/hgrc
539 $ hg pull ../a
539 $ hg pull ../a
540 pulling from ../a
540 pulling from ../a
541 searching for changes
541 searching for changes
542 no changes found
542 no changes found
543 error: post-pull.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
543 error: post-pull.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
544 (run with --traceback for stack trace)
544
545
545 but post- python hooks that fail to *load* do
546 but post- python hooks that fail to *load* do
546 $ echo '[hooks]' > .hg/hgrc
547 $ echo '[hooks]' > .hg/hgrc
547 $ echo 'post-pull.nomodule = python:nomodule' >> .hg/hgrc
548 $ echo 'post-pull.nomodule = python:nomodule' >> .hg/hgrc
548 $ hg pull ../a
549 $ hg pull ../a
549 pulling from ../a
550 pulling from ../a
550 searching for changes
551 searching for changes
551 no changes found
552 no changes found
552 abort: post-pull.nomodule hook is invalid: "nomodule" not in a module
553 abort: post-pull.nomodule hook is invalid: "nomodule" not in a module
553 [255]
554 [255]
554
555
555 $ echo '[hooks]' > .hg/hgrc
556 $ echo '[hooks]' > .hg/hgrc
556 $ echo 'post-pull.badmodule = python:nomodule.nowhere' >> .hg/hgrc
557 $ echo 'post-pull.badmodule = python:nomodule.nowhere' >> .hg/hgrc
557 $ hg pull ../a
558 $ hg pull ../a
558 pulling from ../a
559 pulling from ../a
559 searching for changes
560 searching for changes
560 no changes found
561 no changes found
561 abort: post-pull.badmodule hook is invalid: import of "nomodule" failed
562 abort: post-pull.badmodule hook is invalid: import of "nomodule" failed
562 (run with --traceback for stack trace)
563 (run with --traceback for stack trace)
563 [255]
564 [255]
564
565
565 $ echo '[hooks]' > .hg/hgrc
566 $ echo '[hooks]' > .hg/hgrc
566 $ echo 'post-pull.nohook = python:hooktests.nohook' >> .hg/hgrc
567 $ echo 'post-pull.nohook = python:hooktests.nohook' >> .hg/hgrc
567 $ hg pull ../a
568 $ hg pull ../a
568 pulling from ../a
569 pulling from ../a
569 searching for changes
570 searching for changes
570 no changes found
571 no changes found
571 abort: post-pull.nohook hook is invalid: "hooktests.nohook" is not defined
572 abort: post-pull.nohook hook is invalid: "hooktests.nohook" is not defined
572 [255]
573 [255]
573
574
574 make sure --traceback works
575 make sure --traceback works
575
576
576 $ echo '[hooks]' > .hg/hgrc
577 $ echo '[hooks]' > .hg/hgrc
577 $ echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
578 $ echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
578
579
579 $ echo aa > a
580 $ echo aa > a
580 $ hg --traceback commit -d '0 0' -ma 2>&1 | grep '^Traceback'
581 $ hg --traceback commit -d '0 0' -ma 2>&1 | grep '^Traceback'
581 Traceback (most recent call last):
582 Traceback (most recent call last):
582
583
583 $ cd ..
584 $ cd ..
584 $ hg init c
585 $ hg init c
585 $ cd c
586 $ cd c
586
587
587 $ cat > hookext.py <<EOF
588 $ cat > hookext.py <<EOF
588 > def autohook(**args):
589 > def autohook(**args):
589 > print "Automatically installed hook"
590 > print "Automatically installed hook"
590 >
591 >
591 > def reposetup(ui, repo):
592 > def reposetup(ui, repo):
592 > repo.ui.setconfig("hooks", "commit.auto", autohook)
593 > repo.ui.setconfig("hooks", "commit.auto", autohook)
593 > EOF
594 > EOF
594 $ echo '[extensions]' >> .hg/hgrc
595 $ echo '[extensions]' >> .hg/hgrc
595 $ echo 'hookext = hookext.py' >> .hg/hgrc
596 $ echo 'hookext = hookext.py' >> .hg/hgrc
596
597
597 $ touch foo
598 $ touch foo
598 $ hg add foo
599 $ hg add foo
599 $ hg ci -d '0 0' -m 'add foo'
600 $ hg ci -d '0 0' -m 'add foo'
600 Automatically installed hook
601 Automatically installed hook
601 $ echo >> foo
602 $ echo >> foo
602 $ hg ci --debug -d '0 0' -m 'change foo'
603 $ hg ci --debug -d '0 0' -m 'change foo'
603 committing files:
604 committing files:
604 foo
605 foo
605 committing manifest
606 committing manifest
606 committing changelog
607 committing changelog
607 committed changeset 1:52998019f6252a2b893452765fcb0a47351a5708
608 committed changeset 1:52998019f6252a2b893452765fcb0a47351a5708
608 calling hook commit.auto: hgext_hookext.autohook
609 calling hook commit.auto: hgext_hookext.autohook
609 Automatically installed hook
610 Automatically installed hook
610
611
611 $ hg showconfig hooks
612 $ hg showconfig hooks
612 hooks.commit.auto=<function autohook at *> (glob)
613 hooks.commit.auto=<function autohook at *> (glob)
613
614
614 test python hook configured with python:[file]:[hook] syntax
615 test python hook configured with python:[file]:[hook] syntax
615
616
616 $ cd ..
617 $ cd ..
617 $ mkdir d
618 $ mkdir d
618 $ cd d
619 $ cd d
619 $ hg init repo
620 $ hg init repo
620 $ mkdir hooks
621 $ mkdir hooks
621
622
622 $ cd hooks
623 $ cd hooks
623 $ cat > testhooks.py <<EOF
624 $ cat > testhooks.py <<EOF
624 > def testhook(**args):
625 > def testhook(**args):
625 > print 'hook works'
626 > print 'hook works'
626 > EOF
627 > EOF
627 $ echo '[hooks]' > ../repo/.hg/hgrc
628 $ echo '[hooks]' > ../repo/.hg/hgrc
628 $ echo "pre-commit.test = python:`pwd`/testhooks.py:testhook" >> ../repo/.hg/hgrc
629 $ echo "pre-commit.test = python:`pwd`/testhooks.py:testhook" >> ../repo/.hg/hgrc
629
630
630 $ cd ../repo
631 $ cd ../repo
631 $ hg commit -d '0 0'
632 $ hg commit -d '0 0'
632 hook works
633 hook works
633 nothing changed
634 nothing changed
634 [1]
635 [1]
635
636
636 $ echo '[hooks]' > .hg/hgrc
637 $ echo '[hooks]' > .hg/hgrc
637 $ echo "update.ne = python:`pwd`/nonexistent.py:testhook" >> .hg/hgrc
638 $ echo "update.ne = python:`pwd`/nonexistent.py:testhook" >> .hg/hgrc
638 $ echo "pre-identify.npmd = python:`pwd`/:no_python_module_dir" >> .hg/hgrc
639 $ echo "pre-identify.npmd = python:`pwd`/:no_python_module_dir" >> .hg/hgrc
639
640
640 $ hg up null
641 $ hg up null
641 loading update.ne hook failed:
642 loading update.ne hook failed:
642 abort: No such file or directory: $TESTTMP/d/repo/nonexistent.py
643 abort: No such file or directory: $TESTTMP/d/repo/nonexistent.py
643 [255]
644 [255]
644
645
645 $ hg id
646 $ hg id
646 loading pre-identify.npmd hook failed:
647 loading pre-identify.npmd hook failed:
647 abort: No module named repo!
648 abort: No module named repo!
648 [255]
649 [255]
649
650
650 $ cd ../../b
651 $ cd ../../b
651
652
652 make sure --traceback works on hook import failure
653 make sure --traceback works on hook import failure
653
654
654 $ cat > importfail.py <<EOF
655 $ cat > importfail.py <<EOF
655 > import somebogusmodule
656 > import somebogusmodule
656 > # dereference something in the module to force demandimport to load it
657 > # dereference something in the module to force demandimport to load it
657 > somebogusmodule.whatever
658 > somebogusmodule.whatever
658 > EOF
659 > EOF
659
660
660 $ echo '[hooks]' > .hg/hgrc
661 $ echo '[hooks]' > .hg/hgrc
661 $ echo 'precommit.importfail = python:importfail.whatever' >> .hg/hgrc
662 $ echo 'precommit.importfail = python:importfail.whatever' >> .hg/hgrc
662
663
663 $ echo a >> a
664 $ echo a >> a
664 $ hg --traceback commit -ma 2>&1 | egrep -v '^( +File| [a-zA-Z(])'
665 $ hg --traceback commit -ma 2>&1 | egrep -v '^( +File| [a-zA-Z(])'
665 exception from first failed import attempt:
666 exception from first failed import attempt:
666 Traceback (most recent call last):
667 Traceback (most recent call last):
667 ImportError: No module named somebogusmodule
668 ImportError: No module named somebogusmodule
668 exception from second failed import attempt:
669 exception from second failed import attempt:
669 Traceback (most recent call last):
670 Traceback (most recent call last):
670 ImportError: No module named hgext_importfail
671 ImportError: No module named hgext_importfail
671 Traceback (most recent call last):
672 Traceback (most recent call last):
672 HookLoadError: precommit.importfail hook is invalid: import of "importfail" failed
673 HookLoadError: precommit.importfail hook is invalid: import of "importfail" failed
673 abort: precommit.importfail hook is invalid: import of "importfail" failed
674 abort: precommit.importfail hook is invalid: import of "importfail" failed
674
675
675 Issue1827: Hooks Update & Commit not completely post operation
676 Issue1827: Hooks Update & Commit not completely post operation
676
677
677 commit and update hooks should run after command completion. The largefiles
678 commit and update hooks should run after command completion. The largefiles
678 use demonstrates a recursive wlock, showing the hook doesn't run until the
679 use demonstrates a recursive wlock, showing the hook doesn't run until the
679 final release (and dirstate flush).
680 final release (and dirstate flush).
680
681
681 $ echo '[hooks]' > .hg/hgrc
682 $ echo '[hooks]' > .hg/hgrc
682 $ echo 'commit = hg id' >> .hg/hgrc
683 $ echo 'commit = hg id' >> .hg/hgrc
683 $ echo 'update = hg id' >> .hg/hgrc
684 $ echo 'update = hg id' >> .hg/hgrc
684 $ echo bb > a
685 $ echo bb > a
685 $ hg ci -ma
686 $ hg ci -ma
686 223eafe2750c tip
687 223eafe2750c tip
687 $ hg up 0 --config extensions.largefiles=
688 $ hg up 0 --config extensions.largefiles=
688 cb9a9f314b8b
689 cb9a9f314b8b
689 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
690 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
690
691
691 make sure --verbose (and --quiet/--debug etc.) are propagated to the local ui
692 make sure --verbose (and --quiet/--debug etc.) are propagated to the local ui
692 that is passed to pre/post hooks
693 that is passed to pre/post hooks
693
694
694 $ echo '[hooks]' > .hg/hgrc
695 $ echo '[hooks]' > .hg/hgrc
695 $ echo 'pre-identify = python:hooktests.verbosehook' >> .hg/hgrc
696 $ echo 'pre-identify = python:hooktests.verbosehook' >> .hg/hgrc
696 $ hg id
697 $ hg id
697 cb9a9f314b8b
698 cb9a9f314b8b
698 $ hg id --verbose
699 $ hg id --verbose
699 calling hook pre-identify: hooktests.verbosehook
700 calling hook pre-identify: hooktests.verbosehook
700 verbose output from hook
701 verbose output from hook
701 cb9a9f314b8b
702 cb9a9f314b8b
702
703
703 Ensure hooks can be prioritized
704 Ensure hooks can be prioritized
704
705
705 $ echo '[hooks]' > .hg/hgrc
706 $ echo '[hooks]' > .hg/hgrc
706 $ echo 'pre-identify.a = python:hooktests.verbosehook' >> .hg/hgrc
707 $ echo 'pre-identify.a = python:hooktests.verbosehook' >> .hg/hgrc
707 $ echo 'pre-identify.b = python:hooktests.verbosehook' >> .hg/hgrc
708 $ echo 'pre-identify.b = python:hooktests.verbosehook' >> .hg/hgrc
708 $ echo 'priority.pre-identify.b = 1' >> .hg/hgrc
709 $ echo 'priority.pre-identify.b = 1' >> .hg/hgrc
709 $ echo 'pre-identify.c = python:hooktests.verbosehook' >> .hg/hgrc
710 $ echo 'pre-identify.c = python:hooktests.verbosehook' >> .hg/hgrc
710 $ hg id --verbose
711 $ hg id --verbose
711 calling hook pre-identify.b: hooktests.verbosehook
712 calling hook pre-identify.b: hooktests.verbosehook
712 verbose output from hook
713 verbose output from hook
713 calling hook pre-identify.a: hooktests.verbosehook
714 calling hook pre-identify.a: hooktests.verbosehook
714 verbose output from hook
715 verbose output from hook
715 calling hook pre-identify.c: hooktests.verbosehook
716 calling hook pre-identify.c: hooktests.verbosehook
716 verbose output from hook
717 verbose output from hook
717 cb9a9f314b8b
718 cb9a9f314b8b
718
719
719 new tags must be visible in pretxncommit (issue3210)
720 new tags must be visible in pretxncommit (issue3210)
720
721
721 $ echo 'pretxncommit.printtags = python:hooktests.printtags' >> .hg/hgrc
722 $ echo 'pretxncommit.printtags = python:hooktests.printtags' >> .hg/hgrc
722 $ hg tag -f foo
723 $ hg tag -f foo
723 ['a', 'foo', 'tip']
724 ['a', 'foo', 'tip']
724
725
725 post-init hooks must not crash (issue4983)
726 post-init hooks must not crash (issue4983)
726 This also creates the `to` repo for the next test block.
727 This also creates the `to` repo for the next test block.
727
728
728 $ cd ..
729 $ cd ..
729 $ cat << EOF >> hgrc-with-post-init-hook
730 $ cat << EOF >> hgrc-with-post-init-hook
730 > [hooks]
731 > [hooks]
731 > post-init = printenv.py post-init
732 > post-init = printenv.py post-init
732 > EOF
733 > EOF
733 $ HGRCPATH=hgrc-with-post-init-hook hg init to
734 $ HGRCPATH=hgrc-with-post-init-hook hg init to
734 post-init hook: HG_ARGS=init to HG_OPTS={'insecure': None, 'remotecmd': '', 'ssh': ''} HG_PATS=['to'] HG_RESULT=0
735 post-init hook: HG_ARGS=init to HG_OPTS={'insecure': None, 'remotecmd': '', 'ssh': ''} HG_PATS=['to'] HG_RESULT=0
735
736
736 new commits must be visible in pretxnchangegroup (issue3428)
737 new commits must be visible in pretxnchangegroup (issue3428)
737
738
738 $ echo '[hooks]' >> to/.hg/hgrc
739 $ echo '[hooks]' >> to/.hg/hgrc
739 $ echo 'prechangegroup = hg --traceback tip' >> to/.hg/hgrc
740 $ echo 'prechangegroup = hg --traceback tip' >> to/.hg/hgrc
740 $ echo 'pretxnchangegroup = hg --traceback tip' >> to/.hg/hgrc
741 $ echo 'pretxnchangegroup = hg --traceback tip' >> to/.hg/hgrc
741 $ echo a >> to/a
742 $ echo a >> to/a
742 $ hg --cwd to ci -Ama
743 $ hg --cwd to ci -Ama
743 adding a
744 adding a
744 $ hg clone to from
745 $ hg clone to from
745 updating to branch default
746 updating to branch default
746 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
747 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
747 $ echo aa >> from/a
748 $ echo aa >> from/a
748 $ hg --cwd from ci -mb
749 $ hg --cwd from ci -mb
749 $ hg --cwd from push
750 $ hg --cwd from push
750 pushing to $TESTTMP/to (glob)
751 pushing to $TESTTMP/to (glob)
751 searching for changes
752 searching for changes
752 changeset: 0:cb9a9f314b8b
753 changeset: 0:cb9a9f314b8b
753 tag: tip
754 tag: tip
754 user: test
755 user: test
755 date: Thu Jan 01 00:00:00 1970 +0000
756 date: Thu Jan 01 00:00:00 1970 +0000
756 summary: a
757 summary: a
757
758
758 adding changesets
759 adding changesets
759 adding manifests
760 adding manifests
760 adding file changes
761 adding file changes
761 added 1 changesets with 1 changes to 1 files
762 added 1 changesets with 1 changes to 1 files
762 changeset: 1:9836a07b9b9d
763 changeset: 1:9836a07b9b9d
763 tag: tip
764 tag: tip
764 user: test
765 user: test
765 date: Thu Jan 01 00:00:00 1970 +0000
766 date: Thu Jan 01 00:00:00 1970 +0000
766 summary: b
767 summary: b
767
768
768 $ cd ..
769 $ cd ..
769
770
770 pretxnclose hook failure should abort the transaction
771 pretxnclose hook failure should abort the transaction
771
772
772 $ hg init txnfailure
773 $ hg init txnfailure
773 $ cd txnfailure
774 $ cd txnfailure
774 $ touch a && hg commit -Aqm a
775 $ touch a && hg commit -Aqm a
775 $ cat >> .hg/hgrc <<EOF
776 $ cat >> .hg/hgrc <<EOF
776 > [hooks]
777 > [hooks]
777 > pretxnclose.error = exit 1
778 > pretxnclose.error = exit 1
778 > EOF
779 > EOF
779 $ hg strip -r 0 --config extensions.strip=
780 $ hg strip -r 0 --config extensions.strip=
780 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
781 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
781 saved backup bundle to * (glob)
782 saved backup bundle to * (glob)
782 transaction abort!
783 transaction abort!
783 rollback completed
784 rollback completed
784 strip failed, full bundle stored in * (glob)
785 strip failed, full bundle stored in * (glob)
785 abort: pretxnclose.error hook exited with status 1
786 abort: pretxnclose.error hook exited with status 1
786 [255]
787 [255]
787 $ hg recover
788 $ hg recover
788 no interrupted transaction available
789 no interrupted transaction available
789 [1]
790 [1]
General Comments 0
You need to be logged in to leave comments. Login now