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