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