##// END OF EJS Templates
hook: for python hook ImportErrors, add note to run with --traceback...
Siddharth Agarwal -
r28080:37b818ca default
parent child Browse files
Show More
@@ -1,236 +1,242
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
68 if not ui.tracebackflag:
69 tracebackhint = _(
70 'run with --traceback for stack trace')
71 else:
72 tracebackhint = None
67 raise error.HookLoadError(
73 raise error.HookLoadError(
68 _('%s hook is invalid: import of "%s" failed') %
74 _('%s hook is invalid: import of "%s" failed') %
69 (hname, modname))
75 (hname, modname), hint=tracebackhint)
70 sys.path = oldpaths
76 sys.path = oldpaths
71 try:
77 try:
72 for p in funcname.split('.')[1:]:
78 for p in funcname.split('.')[1:]:
73 obj = getattr(obj, p)
79 obj = getattr(obj, p)
74 except AttributeError:
80 except AttributeError:
75 raise error.HookLoadError(
81 raise error.HookLoadError(
76 _('%s hook is invalid: "%s" is not defined')
82 _('%s hook is invalid: "%s" is not defined')
77 % (hname, funcname))
83 % (hname, funcname))
78 if not callable(obj):
84 if not callable(obj):
79 raise error.HookLoadError(
85 raise error.HookLoadError(
80 _('%s hook is invalid: "%s" is not callable')
86 _('%s hook is invalid: "%s" is not callable')
81 % (hname, funcname))
87 % (hname, funcname))
82
88
83 ui.note(_("calling hook %s: %s\n") % (hname, funcname))
89 ui.note(_("calling hook %s: %s\n") % (hname, funcname))
84 starttime = time.time()
90 starttime = time.time()
85
91
86 try:
92 try:
87 # redirect IO descriptors to the ui descriptors so hooks
93 # redirect IO descriptors to the ui descriptors so hooks
88 # that write directly to these don't mess up the command
94 # that write directly to these don't mess up the command
89 # protocol when running through the command server
95 # protocol when running through the command server
90 old = sys.stdout, sys.stderr, sys.stdin
96 old = sys.stdout, sys.stderr, sys.stdin
91 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
92
98
93 r = obj(ui=ui, repo=repo, hooktype=name, **args)
99 r = obj(ui=ui, repo=repo, hooktype=name, **args)
94 except Exception as exc:
100 except Exception as exc:
95 if isinstance(exc, error.Abort):
101 if isinstance(exc, error.Abort):
96 ui.warn(_('error: %s hook failed: %s\n') %
102 ui.warn(_('error: %s hook failed: %s\n') %
97 (hname, exc.args[0]))
103 (hname, exc.args[0]))
98 else:
104 else:
99 ui.warn(_('error: %s hook raised an exception: '
105 ui.warn(_('error: %s hook raised an exception: '
100 '%s\n') % (hname, exc))
106 '%s\n') % (hname, exc))
101 if throw:
107 if throw:
102 raise
108 raise
103 ui.traceback()
109 ui.traceback()
104 return True, True
110 return True, True
105 finally:
111 finally:
106 sys.stdout, sys.stderr, sys.stdin = old
112 sys.stdout, sys.stderr, sys.stdin = old
107 duration = time.time() - starttime
113 duration = time.time() - starttime
108 ui.log('pythonhook', 'pythonhook-%s: %s finished in %0.2f seconds\n',
114 ui.log('pythonhook', 'pythonhook-%s: %s finished in %0.2f seconds\n',
109 name, funcname, duration)
115 name, funcname, duration)
110 if r:
116 if r:
111 if throw:
117 if throw:
112 raise error.HookAbort(_('%s hook failed') % hname)
118 raise error.HookAbort(_('%s hook failed') % hname)
113 ui.warn(_('warning: %s hook failed\n') % hname)
119 ui.warn(_('warning: %s hook failed\n') % hname)
114 return r, False
120 return r, False
115
121
116 def _exthook(ui, repo, name, cmd, args, throw):
122 def _exthook(ui, repo, name, cmd, args, throw):
117 ui.note(_("running hook %s: %s\n") % (name, cmd))
123 ui.note(_("running hook %s: %s\n") % (name, cmd))
118
124
119 starttime = time.time()
125 starttime = time.time()
120 env = {}
126 env = {}
121
127
122 # make in-memory changes visible to external process
128 # make in-memory changes visible to external process
123 if repo is not None:
129 if repo is not None:
124 tr = repo.currenttransaction()
130 tr = repo.currenttransaction()
125 repo.dirstate.write(tr)
131 repo.dirstate.write(tr)
126 if tr and tr.writepending():
132 if tr and tr.writepending():
127 env['HG_PENDING'] = repo.root
133 env['HG_PENDING'] = repo.root
128
134
129 for k, v in args.iteritems():
135 for k, v in args.iteritems():
130 if callable(v):
136 if callable(v):
131 v = v()
137 v = v()
132 if isinstance(v, dict):
138 if isinstance(v, dict):
133 # make the dictionary element order stable across Python
139 # make the dictionary element order stable across Python
134 # implementations
140 # implementations
135 v = ('{' +
141 v = ('{' +
136 ', '.join('%r: %r' % i for i in sorted(v.iteritems())) +
142 ', '.join('%r: %r' % i for i in sorted(v.iteritems())) +
137 '}')
143 '}')
138 env['HG_' + k.upper()] = v
144 env['HG_' + k.upper()] = v
139
145
140 if repo:
146 if repo:
141 cwd = repo.root
147 cwd = repo.root
142 else:
148 else:
143 cwd = os.getcwd()
149 cwd = os.getcwd()
144 r = ui.system(cmd, environ=env, cwd=cwd)
150 r = ui.system(cmd, environ=env, cwd=cwd)
145
151
146 duration = time.time() - starttime
152 duration = time.time() - starttime
147 ui.log('exthook', 'exthook-%s: %s finished in %0.2f seconds\n',
153 ui.log('exthook', 'exthook-%s: %s finished in %0.2f seconds\n',
148 name, cmd, duration)
154 name, cmd, duration)
149 if r:
155 if r:
150 desc, r = util.explainexit(r)
156 desc, r = util.explainexit(r)
151 if throw:
157 if throw:
152 raise error.HookAbort(_('%s hook %s') % (name, desc))
158 raise error.HookAbort(_('%s hook %s') % (name, desc))
153 ui.warn(_('warning: %s hook %s\n') % (name, desc))
159 ui.warn(_('warning: %s hook %s\n') % (name, desc))
154 return r
160 return r
155
161
156 def _allhooks(ui):
162 def _allhooks(ui):
157 hooks = []
163 hooks = []
158 for name, cmd in ui.configitems('hooks'):
164 for name, cmd in ui.configitems('hooks'):
159 if not name.startswith('priority'):
165 if not name.startswith('priority'):
160 priority = ui.configint('hooks', 'priority.%s' % name, 0)
166 priority = ui.configint('hooks', 'priority.%s' % name, 0)
161 hooks.append((-priority, len(hooks), name, cmd))
167 hooks.append((-priority, len(hooks), name, cmd))
162 return [(k, v) for p, o, k, v in sorted(hooks)]
168 return [(k, v) for p, o, k, v in sorted(hooks)]
163
169
164 _redirect = False
170 _redirect = False
165 def redirect(state):
171 def redirect(state):
166 global _redirect
172 global _redirect
167 _redirect = state
173 _redirect = state
168
174
169 def hook(ui, repo, name, throw=False, **args):
175 def hook(ui, repo, name, throw=False, **args):
170 if not ui.callhooks:
176 if not ui.callhooks:
171 return False
177 return False
172
178
173 hooks = []
179 hooks = []
174 for hname, cmd in _allhooks(ui):
180 for hname, cmd in _allhooks(ui):
175 if hname.split('.')[0] == name and cmd:
181 if hname.split('.')[0] == name and cmd:
176 hooks.append((hname, cmd))
182 hooks.append((hname, cmd))
177
183
178 res = runhooks(ui, repo, name, hooks, throw=throw, **args)
184 res = runhooks(ui, repo, name, hooks, throw=throw, **args)
179 r = False
185 r = False
180 for hname, cmd in hooks:
186 for hname, cmd in hooks:
181 r = res[hname][0] or r
187 r = res[hname][0] or r
182 return r
188 return r
183
189
184 def runhooks(ui, repo, name, hooks, throw=False, **args):
190 def runhooks(ui, repo, name, hooks, throw=False, **args):
185 res = {}
191 res = {}
186 oldstdout = -1
192 oldstdout = -1
187
193
188 try:
194 try:
189 for hname, cmd in hooks:
195 for hname, cmd in hooks:
190 if oldstdout == -1 and _redirect:
196 if oldstdout == -1 and _redirect:
191 try:
197 try:
192 stdoutno = sys.__stdout__.fileno()
198 stdoutno = sys.__stdout__.fileno()
193 stderrno = sys.__stderr__.fileno()
199 stderrno = sys.__stderr__.fileno()
194 # temporarily redirect stdout to stderr, if possible
200 # temporarily redirect stdout to stderr, if possible
195 if stdoutno >= 0 and stderrno >= 0:
201 if stdoutno >= 0 and stderrno >= 0:
196 sys.__stdout__.flush()
202 sys.__stdout__.flush()
197 oldstdout = os.dup(stdoutno)
203 oldstdout = os.dup(stdoutno)
198 os.dup2(stderrno, stdoutno)
204 os.dup2(stderrno, stdoutno)
199 except (OSError, AttributeError):
205 except (OSError, AttributeError):
200 # files seem to be bogus, give up on redirecting (WSGI, etc)
206 # files seem to be bogus, give up on redirecting (WSGI, etc)
201 pass
207 pass
202
208
203 if callable(cmd):
209 if callable(cmd):
204 r, raised = _pythonhook(ui, repo, name, hname, cmd, args, throw)
210 r, raised = _pythonhook(ui, repo, name, hname, cmd, args, throw)
205 elif cmd.startswith('python:'):
211 elif cmd.startswith('python:'):
206 if cmd.count(':') >= 2:
212 if cmd.count(':') >= 2:
207 path, cmd = cmd[7:].rsplit(':', 1)
213 path, cmd = cmd[7:].rsplit(':', 1)
208 path = util.expandpath(path)
214 path = util.expandpath(path)
209 if repo:
215 if repo:
210 path = os.path.join(repo.root, path)
216 path = os.path.join(repo.root, path)
211 try:
217 try:
212 mod = extensions.loadpath(path, 'hghook.%s' % hname)
218 mod = extensions.loadpath(path, 'hghook.%s' % hname)
213 except Exception:
219 except Exception:
214 ui.write(_("loading %s hook failed:\n") % hname)
220 ui.write(_("loading %s hook failed:\n") % hname)
215 raise
221 raise
216 hookfn = getattr(mod, cmd)
222 hookfn = getattr(mod, cmd)
217 else:
223 else:
218 hookfn = cmd[7:].strip()
224 hookfn = cmd[7:].strip()
219 r, raised = _pythonhook(ui, repo, name, hname, hookfn, args,
225 r, raised = _pythonhook(ui, repo, name, hname, hookfn, args,
220 throw)
226 throw)
221 else:
227 else:
222 r = _exthook(ui, repo, hname, cmd, args, throw)
228 r = _exthook(ui, repo, hname, cmd, args, throw)
223 raised = False
229 raised = False
224
230
225 res[hname] = r, raised
231 res[hname] = r, raised
226
232
227 # The stderr is fully buffered on Windows when connected to a pipe.
233 # The stderr is fully buffered on Windows when connected to a pipe.
228 # A forcible flush is required to make small stderr data in the
234 # A forcible flush is required to make small stderr data in the
229 # remote side available to the client immediately.
235 # remote side available to the client immediately.
230 sys.stderr.flush()
236 sys.stderr.flush()
231 finally:
237 finally:
232 if _redirect and oldstdout >= 0:
238 if _redirect and oldstdout >= 0:
233 os.dup2(oldstdout, stdoutno)
239 os.dup2(oldstdout, stdoutno)
234 os.close(oldstdout)
240 os.close(oldstdout)
235
241
236 return res
242 return res
@@ -1,748 +1,750
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 [255]
509 [255]
509
510
510 $ echo '[hooks]' > ../a/.hg/hgrc
511 $ echo '[hooks]' > ../a/.hg/hgrc
511 $ echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
512 $ echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
512 $ hg pull ../a
513 $ hg pull ../a
513 pulling from ../a
514 pulling from ../a
514 searching for changes
515 searching for changes
515 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)
516 [255]
518 [255]
517
519
518 $ echo '[hooks]' > ../a/.hg/hgrc
520 $ echo '[hooks]' > ../a/.hg/hgrc
519 $ echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
521 $ echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
520 $ hg pull ../a
522 $ hg pull ../a
521 pulling from ../a
523 pulling from ../a
522 searching for changes
524 searching for changes
523 hook args:
525 hook args:
524 hooktype preoutgoing
526 hooktype preoutgoing
525 source pull
527 source pull
526 adding changesets
528 adding changesets
527 adding manifests
529 adding manifests
528 adding file changes
530 adding file changes
529 added 1 changesets with 1 changes to 1 files
531 added 1 changesets with 1 changes to 1 files
530 adding remote bookmark quux
532 adding remote bookmark quux
531 (run 'hg update' to get a working copy)
533 (run 'hg update' to get a working copy)
532
534
533 make sure --traceback works
535 make sure --traceback works
534
536
535 $ echo '[hooks]' > .hg/hgrc
537 $ echo '[hooks]' > .hg/hgrc
536 $ echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
538 $ echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
537
539
538 $ echo aa > a
540 $ echo aa > a
539 $ hg --traceback commit -d '0 0' -ma 2>&1 | grep '^Traceback'
541 $ hg --traceback commit -d '0 0' -ma 2>&1 | grep '^Traceback'
540 Traceback (most recent call last):
542 Traceback (most recent call last):
541
543
542 $ cd ..
544 $ cd ..
543 $ hg init c
545 $ hg init c
544 $ cd c
546 $ cd c
545
547
546 $ cat > hookext.py <<EOF
548 $ cat > hookext.py <<EOF
547 > def autohook(**args):
549 > def autohook(**args):
548 > print "Automatically installed hook"
550 > print "Automatically installed hook"
549 >
551 >
550 > def reposetup(ui, repo):
552 > def reposetup(ui, repo):
551 > repo.ui.setconfig("hooks", "commit.auto", autohook)
553 > repo.ui.setconfig("hooks", "commit.auto", autohook)
552 > EOF
554 > EOF
553 $ echo '[extensions]' >> .hg/hgrc
555 $ echo '[extensions]' >> .hg/hgrc
554 $ echo 'hookext = hookext.py' >> .hg/hgrc
556 $ echo 'hookext = hookext.py' >> .hg/hgrc
555
557
556 $ touch foo
558 $ touch foo
557 $ hg add foo
559 $ hg add foo
558 $ hg ci -d '0 0' -m 'add foo'
560 $ hg ci -d '0 0' -m 'add foo'
559 Automatically installed hook
561 Automatically installed hook
560 $ echo >> foo
562 $ echo >> foo
561 $ hg ci --debug -d '0 0' -m 'change foo'
563 $ hg ci --debug -d '0 0' -m 'change foo'
562 committing files:
564 committing files:
563 foo
565 foo
564 committing manifest
566 committing manifest
565 committing changelog
567 committing changelog
566 committed changeset 1:52998019f6252a2b893452765fcb0a47351a5708
568 committed changeset 1:52998019f6252a2b893452765fcb0a47351a5708
567 calling hook commit.auto: hgext_hookext.autohook
569 calling hook commit.auto: hgext_hookext.autohook
568 Automatically installed hook
570 Automatically installed hook
569
571
570 $ hg showconfig hooks
572 $ hg showconfig hooks
571 hooks.commit.auto=<function autohook at *> (glob)
573 hooks.commit.auto=<function autohook at *> (glob)
572
574
573 test python hook configured with python:[file]:[hook] syntax
575 test python hook configured with python:[file]:[hook] syntax
574
576
575 $ cd ..
577 $ cd ..
576 $ mkdir d
578 $ mkdir d
577 $ cd d
579 $ cd d
578 $ hg init repo
580 $ hg init repo
579 $ mkdir hooks
581 $ mkdir hooks
580
582
581 $ cd hooks
583 $ cd hooks
582 $ cat > testhooks.py <<EOF
584 $ cat > testhooks.py <<EOF
583 > def testhook(**args):
585 > def testhook(**args):
584 > print 'hook works'
586 > print 'hook works'
585 > EOF
587 > EOF
586 $ echo '[hooks]' > ../repo/.hg/hgrc
588 $ echo '[hooks]' > ../repo/.hg/hgrc
587 $ echo "pre-commit.test = python:`pwd`/testhooks.py:testhook" >> ../repo/.hg/hgrc
589 $ echo "pre-commit.test = python:`pwd`/testhooks.py:testhook" >> ../repo/.hg/hgrc
588
590
589 $ cd ../repo
591 $ cd ../repo
590 $ hg commit -d '0 0'
592 $ hg commit -d '0 0'
591 hook works
593 hook works
592 nothing changed
594 nothing changed
593 [1]
595 [1]
594
596
595 $ echo '[hooks]' > .hg/hgrc
597 $ echo '[hooks]' > .hg/hgrc
596 $ echo "update.ne = python:`pwd`/nonexistent.py:testhook" >> .hg/hgrc
598 $ echo "update.ne = python:`pwd`/nonexistent.py:testhook" >> .hg/hgrc
597 $ echo "pre-identify.npmd = python:`pwd`/:no_python_module_dir" >> .hg/hgrc
599 $ echo "pre-identify.npmd = python:`pwd`/:no_python_module_dir" >> .hg/hgrc
598
600
599 $ hg up null
601 $ hg up null
600 loading update.ne hook failed:
602 loading update.ne hook failed:
601 abort: No such file or directory: $TESTTMP/d/repo/nonexistent.py
603 abort: No such file or directory: $TESTTMP/d/repo/nonexistent.py
602 [255]
604 [255]
603
605
604 $ hg id
606 $ hg id
605 loading pre-identify.npmd hook failed:
607 loading pre-identify.npmd hook failed:
606 abort: No module named repo!
608 abort: No module named repo!
607 [255]
609 [255]
608
610
609 $ cd ../../b
611 $ cd ../../b
610
612
611 make sure --traceback works on hook import failure
613 make sure --traceback works on hook import failure
612
614
613 $ cat > importfail.py <<EOF
615 $ cat > importfail.py <<EOF
614 > import somebogusmodule
616 > import somebogusmodule
615 > # dereference something in the module to force demandimport to load it
617 > # dereference something in the module to force demandimport to load it
616 > somebogusmodule.whatever
618 > somebogusmodule.whatever
617 > EOF
619 > EOF
618
620
619 $ echo '[hooks]' > .hg/hgrc
621 $ echo '[hooks]' > .hg/hgrc
620 $ echo 'precommit.importfail = python:importfail.whatever' >> .hg/hgrc
622 $ echo 'precommit.importfail = python:importfail.whatever' >> .hg/hgrc
621
623
622 $ echo a >> a
624 $ echo a >> a
623 $ hg --traceback commit -ma 2>&1 | egrep -v '^( +File| [a-zA-Z(])'
625 $ hg --traceback commit -ma 2>&1 | egrep -v '^( +File| [a-zA-Z(])'
624 exception from first failed import attempt:
626 exception from first failed import attempt:
625 Traceback (most recent call last):
627 Traceback (most recent call last):
626 ImportError: No module named somebogusmodule
628 ImportError: No module named somebogusmodule
627 exception from second failed import attempt:
629 exception from second failed import attempt:
628 Traceback (most recent call last):
630 Traceback (most recent call last):
629 ImportError: No module named hgext_importfail
631 ImportError: No module named hgext_importfail
630 Traceback (most recent call last):
632 Traceback (most recent call last):
631 HookLoadError: precommit.importfail hook is invalid: import of "importfail" failed
633 HookLoadError: precommit.importfail hook is invalid: import of "importfail" failed
632 abort: precommit.importfail hook is invalid: import of "importfail" failed
634 abort: precommit.importfail hook is invalid: import of "importfail" failed
633
635
634 Issue1827: Hooks Update & Commit not completely post operation
636 Issue1827: Hooks Update & Commit not completely post operation
635
637
636 commit and update hooks should run after command completion. The largefiles
638 commit and update hooks should run after command completion. The largefiles
637 use demonstrates a recursive wlock, showing the hook doesn't run until the
639 use demonstrates a recursive wlock, showing the hook doesn't run until the
638 final release (and dirstate flush).
640 final release (and dirstate flush).
639
641
640 $ echo '[hooks]' > .hg/hgrc
642 $ echo '[hooks]' > .hg/hgrc
641 $ echo 'commit = hg id' >> .hg/hgrc
643 $ echo 'commit = hg id' >> .hg/hgrc
642 $ echo 'update = hg id' >> .hg/hgrc
644 $ echo 'update = hg id' >> .hg/hgrc
643 $ echo bb > a
645 $ echo bb > a
644 $ hg ci -ma
646 $ hg ci -ma
645 223eafe2750c tip
647 223eafe2750c tip
646 $ hg up 0 --config extensions.largefiles=
648 $ hg up 0 --config extensions.largefiles=
647 cb9a9f314b8b
649 cb9a9f314b8b
648 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
650 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
649
651
650 make sure --verbose (and --quiet/--debug etc.) are propagated to the local ui
652 make sure --verbose (and --quiet/--debug etc.) are propagated to the local ui
651 that is passed to pre/post hooks
653 that is passed to pre/post hooks
652
654
653 $ echo '[hooks]' > .hg/hgrc
655 $ echo '[hooks]' > .hg/hgrc
654 $ echo 'pre-identify = python:hooktests.verbosehook' >> .hg/hgrc
656 $ echo 'pre-identify = python:hooktests.verbosehook' >> .hg/hgrc
655 $ hg id
657 $ hg id
656 cb9a9f314b8b
658 cb9a9f314b8b
657 $ hg id --verbose
659 $ hg id --verbose
658 calling hook pre-identify: hooktests.verbosehook
660 calling hook pre-identify: hooktests.verbosehook
659 verbose output from hook
661 verbose output from hook
660 cb9a9f314b8b
662 cb9a9f314b8b
661
663
662 Ensure hooks can be prioritized
664 Ensure hooks can be prioritized
663
665
664 $ echo '[hooks]' > .hg/hgrc
666 $ echo '[hooks]' > .hg/hgrc
665 $ echo 'pre-identify.a = python:hooktests.verbosehook' >> .hg/hgrc
667 $ echo 'pre-identify.a = python:hooktests.verbosehook' >> .hg/hgrc
666 $ echo 'pre-identify.b = python:hooktests.verbosehook' >> .hg/hgrc
668 $ echo 'pre-identify.b = python:hooktests.verbosehook' >> .hg/hgrc
667 $ echo 'priority.pre-identify.b = 1' >> .hg/hgrc
669 $ echo 'priority.pre-identify.b = 1' >> .hg/hgrc
668 $ echo 'pre-identify.c = python:hooktests.verbosehook' >> .hg/hgrc
670 $ echo 'pre-identify.c = python:hooktests.verbosehook' >> .hg/hgrc
669 $ hg id --verbose
671 $ hg id --verbose
670 calling hook pre-identify.b: hooktests.verbosehook
672 calling hook pre-identify.b: hooktests.verbosehook
671 verbose output from hook
673 verbose output from hook
672 calling hook pre-identify.a: hooktests.verbosehook
674 calling hook pre-identify.a: hooktests.verbosehook
673 verbose output from hook
675 verbose output from hook
674 calling hook pre-identify.c: hooktests.verbosehook
676 calling hook pre-identify.c: hooktests.verbosehook
675 verbose output from hook
677 verbose output from hook
676 cb9a9f314b8b
678 cb9a9f314b8b
677
679
678 new tags must be visible in pretxncommit (issue3210)
680 new tags must be visible in pretxncommit (issue3210)
679
681
680 $ echo 'pretxncommit.printtags = python:hooktests.printtags' >> .hg/hgrc
682 $ echo 'pretxncommit.printtags = python:hooktests.printtags' >> .hg/hgrc
681 $ hg tag -f foo
683 $ hg tag -f foo
682 ['a', 'foo', 'tip']
684 ['a', 'foo', 'tip']
683
685
684 post-init hooks must not crash (issue4983)
686 post-init hooks must not crash (issue4983)
685 This also creates the `to` repo for the next test block.
687 This also creates the `to` repo for the next test block.
686
688
687 $ cd ..
689 $ cd ..
688 $ cat << EOF >> hgrc-with-post-init-hook
690 $ cat << EOF >> hgrc-with-post-init-hook
689 > [hooks]
691 > [hooks]
690 > post-init = printenv.py post-init
692 > post-init = printenv.py post-init
691 > EOF
693 > EOF
692 $ HGRCPATH=hgrc-with-post-init-hook hg init to
694 $ HGRCPATH=hgrc-with-post-init-hook hg init to
693 post-init hook: HG_ARGS=init to HG_OPTS={'insecure': None, 'remotecmd': '', 'ssh': ''} HG_PATS=['to'] HG_RESULT=0
695 post-init hook: HG_ARGS=init to HG_OPTS={'insecure': None, 'remotecmd': '', 'ssh': ''} HG_PATS=['to'] HG_RESULT=0
694
696
695 new commits must be visible in pretxnchangegroup (issue3428)
697 new commits must be visible in pretxnchangegroup (issue3428)
696
698
697 $ echo '[hooks]' >> to/.hg/hgrc
699 $ echo '[hooks]' >> to/.hg/hgrc
698 $ echo 'prechangegroup = hg --traceback tip' >> to/.hg/hgrc
700 $ echo 'prechangegroup = hg --traceback tip' >> to/.hg/hgrc
699 $ echo 'pretxnchangegroup = hg --traceback tip' >> to/.hg/hgrc
701 $ echo 'pretxnchangegroup = hg --traceback tip' >> to/.hg/hgrc
700 $ echo a >> to/a
702 $ echo a >> to/a
701 $ hg --cwd to ci -Ama
703 $ hg --cwd to ci -Ama
702 adding a
704 adding a
703 $ hg clone to from
705 $ hg clone to from
704 updating to branch default
706 updating to branch default
705 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
707 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
706 $ echo aa >> from/a
708 $ echo aa >> from/a
707 $ hg --cwd from ci -mb
709 $ hg --cwd from ci -mb
708 $ hg --cwd from push
710 $ hg --cwd from push
709 pushing to $TESTTMP/to (glob)
711 pushing to $TESTTMP/to (glob)
710 searching for changes
712 searching for changes
711 changeset: 0:cb9a9f314b8b
713 changeset: 0:cb9a9f314b8b
712 tag: tip
714 tag: tip
713 user: test
715 user: test
714 date: Thu Jan 01 00:00:00 1970 +0000
716 date: Thu Jan 01 00:00:00 1970 +0000
715 summary: a
717 summary: a
716
718
717 adding changesets
719 adding changesets
718 adding manifests
720 adding manifests
719 adding file changes
721 adding file changes
720 added 1 changesets with 1 changes to 1 files
722 added 1 changesets with 1 changes to 1 files
721 changeset: 1:9836a07b9b9d
723 changeset: 1:9836a07b9b9d
722 tag: tip
724 tag: tip
723 user: test
725 user: test
724 date: Thu Jan 01 00:00:00 1970 +0000
726 date: Thu Jan 01 00:00:00 1970 +0000
725 summary: b
727 summary: b
726
728
727 $ cd ..
729 $ cd ..
728
730
729 pretxnclose hook failure should abort the transaction
731 pretxnclose hook failure should abort the transaction
730
732
731 $ hg init txnfailure
733 $ hg init txnfailure
732 $ cd txnfailure
734 $ cd txnfailure
733 $ touch a && hg commit -Aqm a
735 $ touch a && hg commit -Aqm a
734 $ cat >> .hg/hgrc <<EOF
736 $ cat >> .hg/hgrc <<EOF
735 > [hooks]
737 > [hooks]
736 > pretxnclose.error = exit 1
738 > pretxnclose.error = exit 1
737 > EOF
739 > EOF
738 $ hg strip -r 0 --config extensions.strip=
740 $ hg strip -r 0 --config extensions.strip=
739 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
741 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
740 saved backup bundle to * (glob)
742 saved backup bundle to * (glob)
741 transaction abort!
743 transaction abort!
742 rollback completed
744 rollback completed
743 strip failed, full bundle stored in * (glob)
745 strip failed, full bundle stored in * (glob)
744 abort: pretxnclose.error hook exited with status 1
746 abort: pretxnclose.error hook exited with status 1
745 [255]
747 [255]
746 $ hg recover
748 $ hg recover
747 no interrupted transaction available
749 no interrupted transaction available
748 [1]
750 [1]
General Comments 0
You need to be logged in to leave comments. Login now