##// END OF EJS Templates
Add (pre)outgoing hooks for local clones.
Fred Wulff -
r8907:e9ef409e default
parent child Browse files
Show More
@@ -1,362 +1,363
1 # hg.py - repository classes for mercurial
1 # hg.py - repository classes for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2, incorporated herein by reference.
7 # GNU General Public License version 2, incorporated herein by reference.
8
8
9 from i18n import _
9 from i18n import _
10 from lock import release
10 from lock import release
11 import localrepo, bundlerepo, httprepo, sshrepo, statichttprepo
11 import localrepo, bundlerepo, httprepo, sshrepo, statichttprepo
12 import lock, util, extensions, error
12 import lock, util, extensions, error
13 import merge as _merge
13 import merge as _merge
14 import verify as _verify
14 import verify as _verify
15 import errno, os, shutil
15 import errno, os, shutil
16
16
17 def _local(path):
17 def _local(path):
18 return (os.path.isfile(util.drop_scheme('file', path)) and
18 return (os.path.isfile(util.drop_scheme('file', path)) and
19 bundlerepo or localrepo)
19 bundlerepo or localrepo)
20
20
21 def parseurl(url, revs=[]):
21 def parseurl(url, revs=[]):
22 '''parse url#branch, returning url, branch + revs'''
22 '''parse url#branch, returning url, branch + revs'''
23
23
24 if '#' not in url:
24 if '#' not in url:
25 return url, (revs or None), revs and revs[-1] or None
25 return url, (revs or None), revs and revs[-1] or None
26
26
27 url, branch = url.split('#', 1)
27 url, branch = url.split('#', 1)
28 checkout = revs and revs[-1] or branch
28 checkout = revs and revs[-1] or branch
29 return url, (revs or []) + [branch], checkout
29 return url, (revs or []) + [branch], checkout
30
30
31 schemes = {
31 schemes = {
32 'bundle': bundlerepo,
32 'bundle': bundlerepo,
33 'file': _local,
33 'file': _local,
34 'http': httprepo,
34 'http': httprepo,
35 'https': httprepo,
35 'https': httprepo,
36 'ssh': sshrepo,
36 'ssh': sshrepo,
37 'static-http': statichttprepo,
37 'static-http': statichttprepo,
38 }
38 }
39
39
40 def _lookup(path):
40 def _lookup(path):
41 scheme = 'file'
41 scheme = 'file'
42 if path:
42 if path:
43 c = path.find(':')
43 c = path.find(':')
44 if c > 0:
44 if c > 0:
45 scheme = path[:c]
45 scheme = path[:c]
46 thing = schemes.get(scheme) or schemes['file']
46 thing = schemes.get(scheme) or schemes['file']
47 try:
47 try:
48 return thing(path)
48 return thing(path)
49 except TypeError:
49 except TypeError:
50 return thing
50 return thing
51
51
52 def islocal(repo):
52 def islocal(repo):
53 '''return true if repo or path is local'''
53 '''return true if repo or path is local'''
54 if isinstance(repo, str):
54 if isinstance(repo, str):
55 try:
55 try:
56 return _lookup(repo).islocal(repo)
56 return _lookup(repo).islocal(repo)
57 except AttributeError:
57 except AttributeError:
58 return False
58 return False
59 return repo.local()
59 return repo.local()
60
60
61 def repository(ui, path='', create=False):
61 def repository(ui, path='', create=False):
62 """return a repository object for the specified path"""
62 """return a repository object for the specified path"""
63 repo = _lookup(path).instance(ui, path, create)
63 repo = _lookup(path).instance(ui, path, create)
64 ui = getattr(repo, "ui", ui)
64 ui = getattr(repo, "ui", ui)
65 for name, module in extensions.extensions():
65 for name, module in extensions.extensions():
66 hook = getattr(module, 'reposetup', None)
66 hook = getattr(module, 'reposetup', None)
67 if hook:
67 if hook:
68 hook(ui, repo)
68 hook(ui, repo)
69 return repo
69 return repo
70
70
71 def defaultdest(source):
71 def defaultdest(source):
72 '''return default destination of clone if none is given'''
72 '''return default destination of clone if none is given'''
73 return os.path.basename(os.path.normpath(source))
73 return os.path.basename(os.path.normpath(source))
74
74
75 def localpath(path):
75 def localpath(path):
76 if path.startswith('file://localhost/'):
76 if path.startswith('file://localhost/'):
77 return path[16:]
77 return path[16:]
78 if path.startswith('file://'):
78 if path.startswith('file://'):
79 return path[7:]
79 return path[7:]
80 if path.startswith('file:'):
80 if path.startswith('file:'):
81 return path[5:]
81 return path[5:]
82 return path
82 return path
83
83
84 def share(ui, source, dest=None, update=True):
84 def share(ui, source, dest=None, update=True):
85 '''create a shared repository'''
85 '''create a shared repository'''
86
86
87 if not islocal(source):
87 if not islocal(source):
88 raise util.Abort(_('can only share local repositories'))
88 raise util.Abort(_('can only share local repositories'))
89
89
90 if not dest:
90 if not dest:
91 dest = os.path.basename(source)
91 dest = os.path.basename(source)
92
92
93 if isinstance(source, str):
93 if isinstance(source, str):
94 origsource = ui.expandpath(source)
94 origsource = ui.expandpath(source)
95 source, rev, checkout = parseurl(origsource, '')
95 source, rev, checkout = parseurl(origsource, '')
96 srcrepo = repository(ui, source)
96 srcrepo = repository(ui, source)
97 else:
97 else:
98 srcrepo = source
98 srcrepo = source
99 origsource = source = srcrepo.url()
99 origsource = source = srcrepo.url()
100 checkout = None
100 checkout = None
101
101
102 sharedpath = srcrepo.sharedpath # if our source is already sharing
102 sharedpath = srcrepo.sharedpath # if our source is already sharing
103
103
104 root = os.path.realpath(dest)
104 root = os.path.realpath(dest)
105 roothg = os.path.join(root, '.hg')
105 roothg = os.path.join(root, '.hg')
106
106
107 if os.path.exists(roothg):
107 if os.path.exists(roothg):
108 raise util.Abort(_('destination already exists'))
108 raise util.Abort(_('destination already exists'))
109
109
110 if not os.path.isdir(root):
110 if not os.path.isdir(root):
111 os.mkdir(root)
111 os.mkdir(root)
112 os.mkdir(roothg)
112 os.mkdir(roothg)
113
113
114 requirements = ''
114 requirements = ''
115 try:
115 try:
116 requirements = srcrepo.opener('requires').read()
116 requirements = srcrepo.opener('requires').read()
117 except IOError, inst:
117 except IOError, inst:
118 if inst.errno != errno.ENOENT:
118 if inst.errno != errno.ENOENT:
119 raise
119 raise
120
120
121 requirements += 'shared\n'
121 requirements += 'shared\n'
122 file(os.path.join(roothg, 'requires'), 'w').write(requirements)
122 file(os.path.join(roothg, 'requires'), 'w').write(requirements)
123 file(os.path.join(roothg, 'sharedpath'), 'w').write(sharedpath)
123 file(os.path.join(roothg, 'sharedpath'), 'w').write(sharedpath)
124
124
125 default = srcrepo.ui.config('paths', 'default')
125 default = srcrepo.ui.config('paths', 'default')
126 if default:
126 if default:
127 f = file(os.path.join(roothg, 'hgrc'), 'w')
127 f = file(os.path.join(roothg, 'hgrc'), 'w')
128 f.write('[paths]\ndefault = %s\n' % default)
128 f.write('[paths]\ndefault = %s\n' % default)
129 f.close()
129 f.close()
130
130
131 r = repository(ui, root)
131 r = repository(ui, root)
132
132
133 if update:
133 if update:
134 r.ui.status(_("updating working directory\n"))
134 r.ui.status(_("updating working directory\n"))
135 if update is not True:
135 if update is not True:
136 checkout = update
136 checkout = update
137 for test in (checkout, 'default', 'tip'):
137 for test in (checkout, 'default', 'tip'):
138 try:
138 try:
139 uprev = r.lookup(test)
139 uprev = r.lookup(test)
140 break
140 break
141 except:
141 except:
142 continue
142 continue
143 _update(r, uprev)
143 _update(r, uprev)
144
144
145 def clone(ui, source, dest=None, pull=False, rev=None, update=True,
145 def clone(ui, source, dest=None, pull=False, rev=None, update=True,
146 stream=False):
146 stream=False):
147 """Make a copy of an existing repository.
147 """Make a copy of an existing repository.
148
148
149 Create a copy of an existing repository in a new directory. The
149 Create a copy of an existing repository in a new directory. The
150 source and destination are URLs, as passed to the repository
150 source and destination are URLs, as passed to the repository
151 function. Returns a pair of repository objects, the source and
151 function. Returns a pair of repository objects, the source and
152 newly created destination.
152 newly created destination.
153
153
154 The location of the source is added to the new repository's
154 The location of the source is added to the new repository's
155 .hg/hgrc file, as the default to be used for future pulls and
155 .hg/hgrc file, as the default to be used for future pulls and
156 pushes.
156 pushes.
157
157
158 If an exception is raised, the partly cloned/updated destination
158 If an exception is raised, the partly cloned/updated destination
159 repository will be deleted.
159 repository will be deleted.
160
160
161 Arguments:
161 Arguments:
162
162
163 source: repository object or URL
163 source: repository object or URL
164
164
165 dest: URL of destination repository to create (defaults to base
165 dest: URL of destination repository to create (defaults to base
166 name of source repository)
166 name of source repository)
167
167
168 pull: always pull from source repository, even in local case
168 pull: always pull from source repository, even in local case
169
169
170 stream: stream raw data uncompressed from repository (fast over
170 stream: stream raw data uncompressed from repository (fast over
171 LAN, slow over WAN)
171 LAN, slow over WAN)
172
172
173 rev: revision to clone up to (implies pull=True)
173 rev: revision to clone up to (implies pull=True)
174
174
175 update: update working directory after clone completes, if
175 update: update working directory after clone completes, if
176 destination is local repository (True means update to default rev,
176 destination is local repository (True means update to default rev,
177 anything else is treated as a revision)
177 anything else is treated as a revision)
178 """
178 """
179
179
180 if isinstance(source, str):
180 if isinstance(source, str):
181 origsource = ui.expandpath(source)
181 origsource = ui.expandpath(source)
182 source, rev, checkout = parseurl(origsource, rev)
182 source, rev, checkout = parseurl(origsource, rev)
183 src_repo = repository(ui, source)
183 src_repo = repository(ui, source)
184 else:
184 else:
185 src_repo = source
185 src_repo = source
186 origsource = source = src_repo.url()
186 origsource = source = src_repo.url()
187 checkout = rev and rev[-1] or None
187 checkout = rev and rev[-1] or None
188
188
189 if dest is None:
189 if dest is None:
190 dest = defaultdest(source)
190 dest = defaultdest(source)
191 ui.status(_("destination directory: %s\n") % dest)
191 ui.status(_("destination directory: %s\n") % dest)
192
192
193 dest = localpath(dest)
193 dest = localpath(dest)
194 source = localpath(source)
194 source = localpath(source)
195
195
196 if os.path.exists(dest):
196 if os.path.exists(dest):
197 if not os.path.isdir(dest):
197 if not os.path.isdir(dest):
198 raise util.Abort(_("destination '%s' already exists") % dest)
198 raise util.Abort(_("destination '%s' already exists") % dest)
199 elif os.listdir(dest):
199 elif os.listdir(dest):
200 raise util.Abort(_("destination '%s' is not empty") % dest)
200 raise util.Abort(_("destination '%s' is not empty") % dest)
201
201
202 class DirCleanup(object):
202 class DirCleanup(object):
203 def __init__(self, dir_):
203 def __init__(self, dir_):
204 self.rmtree = shutil.rmtree
204 self.rmtree = shutil.rmtree
205 self.dir_ = dir_
205 self.dir_ = dir_
206 def close(self):
206 def close(self):
207 self.dir_ = None
207 self.dir_ = None
208 def cleanup(self):
208 def cleanup(self):
209 if self.dir_:
209 if self.dir_:
210 self.rmtree(self.dir_, True)
210 self.rmtree(self.dir_, True)
211
211
212 src_lock = dest_lock = dir_cleanup = None
212 src_lock = dest_lock = dir_cleanup = None
213 try:
213 try:
214 if islocal(dest):
214 if islocal(dest):
215 dir_cleanup = DirCleanup(dest)
215 dir_cleanup = DirCleanup(dest)
216
216
217 abspath = origsource
217 abspath = origsource
218 copy = False
218 copy = False
219 if src_repo.cancopy() and islocal(dest):
219 if src_repo.cancopy() and islocal(dest):
220 abspath = os.path.abspath(util.drop_scheme('file', origsource))
220 abspath = os.path.abspath(util.drop_scheme('file', origsource))
221 copy = not pull and not rev
221 copy = not pull and not rev
222
222
223 if copy:
223 if copy:
224 try:
224 try:
225 # we use a lock here because if we race with commit, we
225 # we use a lock here because if we race with commit, we
226 # can end up with extra data in the cloned revlogs that's
226 # can end up with extra data in the cloned revlogs that's
227 # not pointed to by changesets, thus causing verify to
227 # not pointed to by changesets, thus causing verify to
228 # fail
228 # fail
229 src_lock = src_repo.lock(wait=False)
229 src_lock = src_repo.lock(wait=False)
230 except error.LockError:
230 except error.LockError:
231 copy = False
231 copy = False
232
232
233 if copy:
233 if copy:
234 src_repo.hook('preoutgoing', throw=True, source='clone')
234 hgdir = os.path.realpath(os.path.join(dest, ".hg"))
235 hgdir = os.path.realpath(os.path.join(dest, ".hg"))
235 if not os.path.exists(dest):
236 if not os.path.exists(dest):
236 os.mkdir(dest)
237 os.mkdir(dest)
237 else:
238 else:
238 # only clean up directories we create ourselves
239 # only clean up directories we create ourselves
239 dir_cleanup.dir_ = hgdir
240 dir_cleanup.dir_ = hgdir
240 try:
241 try:
241 dest_path = hgdir
242 dest_path = hgdir
242 os.mkdir(dest_path)
243 os.mkdir(dest_path)
243 except OSError, inst:
244 except OSError, inst:
244 if inst.errno == errno.EEXIST:
245 if inst.errno == errno.EEXIST:
245 dir_cleanup.close()
246 dir_cleanup.close()
246 raise util.Abort(_("destination '%s' already exists")
247 raise util.Abort(_("destination '%s' already exists")
247 % dest)
248 % dest)
248 raise
249 raise
249
250
250 for f in src_repo.store.copylist():
251 for f in src_repo.store.copylist():
251 src = os.path.join(src_repo.path, f)
252 src = os.path.join(src_repo.path, f)
252 dst = os.path.join(dest_path, f)
253 dst = os.path.join(dest_path, f)
253 dstbase = os.path.dirname(dst)
254 dstbase = os.path.dirname(dst)
254 if dstbase and not os.path.exists(dstbase):
255 if dstbase and not os.path.exists(dstbase):
255 os.mkdir(dstbase)
256 os.mkdir(dstbase)
256 if os.path.exists(src):
257 if os.path.exists(src):
257 if dst.endswith('data'):
258 if dst.endswith('data'):
258 # lock to avoid premature writing to the target
259 # lock to avoid premature writing to the target
259 dest_lock = lock.lock(os.path.join(dstbase, "lock"))
260 dest_lock = lock.lock(os.path.join(dstbase, "lock"))
260 util.copyfiles(src, dst)
261 util.copyfiles(src, dst)
261
262
262 # we need to re-init the repo after manually copying the data
263 # we need to re-init the repo after manually copying the data
263 # into it
264 # into it
264 dest_repo = repository(ui, dest)
265 dest_repo = repository(ui, dest)
265
266 src_repo.hook('outgoing', source='clone', node='0'*40)
266 else:
267 else:
267 try:
268 try:
268 dest_repo = repository(ui, dest, create=True)
269 dest_repo = repository(ui, dest, create=True)
269 except OSError, inst:
270 except OSError, inst:
270 if inst.errno == errno.EEXIST:
271 if inst.errno == errno.EEXIST:
271 dir_cleanup.close()
272 dir_cleanup.close()
272 raise util.Abort(_("destination '%s' already exists")
273 raise util.Abort(_("destination '%s' already exists")
273 % dest)
274 % dest)
274 raise
275 raise
275
276
276 revs = None
277 revs = None
277 if rev:
278 if rev:
278 if 'lookup' not in src_repo.capabilities:
279 if 'lookup' not in src_repo.capabilities:
279 raise util.Abort(_("src repository does not support revision "
280 raise util.Abort(_("src repository does not support revision "
280 "lookup and so doesn't support clone by "
281 "lookup and so doesn't support clone by "
281 "revision"))
282 "revision"))
282 revs = [src_repo.lookup(r) for r in rev]
283 revs = [src_repo.lookup(r) for r in rev]
283 checkout = revs[0]
284 checkout = revs[0]
284 if dest_repo.local():
285 if dest_repo.local():
285 dest_repo.clone(src_repo, heads=revs, stream=stream)
286 dest_repo.clone(src_repo, heads=revs, stream=stream)
286 elif src_repo.local():
287 elif src_repo.local():
287 src_repo.push(dest_repo, revs=revs)
288 src_repo.push(dest_repo, revs=revs)
288 else:
289 else:
289 raise util.Abort(_("clone from remote to remote not supported"))
290 raise util.Abort(_("clone from remote to remote not supported"))
290
291
291 if dir_cleanup:
292 if dir_cleanup:
292 dir_cleanup.close()
293 dir_cleanup.close()
293
294
294 if dest_repo.local():
295 if dest_repo.local():
295 fp = dest_repo.opener("hgrc", "w", text=True)
296 fp = dest_repo.opener("hgrc", "w", text=True)
296 fp.write("[paths]\n")
297 fp.write("[paths]\n")
297 fp.write("default = %s\n" % abspath)
298 fp.write("default = %s\n" % abspath)
298 fp.close()
299 fp.close()
299
300
300 dest_repo.ui.setconfig('paths', 'default', abspath)
301 dest_repo.ui.setconfig('paths', 'default', abspath)
301
302
302 if update:
303 if update:
303 dest_repo.ui.status(_("updating working directory\n"))
304 dest_repo.ui.status(_("updating working directory\n"))
304 if update is not True:
305 if update is not True:
305 checkout = update
306 checkout = update
306 for test in (checkout, 'default', 'tip'):
307 for test in (checkout, 'default', 'tip'):
307 try:
308 try:
308 uprev = dest_repo.lookup(test)
309 uprev = dest_repo.lookup(test)
309 break
310 break
310 except:
311 except:
311 continue
312 continue
312 _update(dest_repo, uprev)
313 _update(dest_repo, uprev)
313
314
314 return src_repo, dest_repo
315 return src_repo, dest_repo
315 finally:
316 finally:
316 release(src_lock, dest_lock)
317 release(src_lock, dest_lock)
317 if dir_cleanup is not None:
318 if dir_cleanup is not None:
318 dir_cleanup.cleanup()
319 dir_cleanup.cleanup()
319
320
320 def _showstats(repo, stats):
321 def _showstats(repo, stats):
321 stats = ((stats[0], _("updated")),
322 stats = ((stats[0], _("updated")),
322 (stats[1], _("merged")),
323 (stats[1], _("merged")),
323 (stats[2], _("removed")),
324 (stats[2], _("removed")),
324 (stats[3], _("unresolved")))
325 (stats[3], _("unresolved")))
325 note = ", ".join([_("%d files %s") % s for s in stats])
326 note = ", ".join([_("%d files %s") % s for s in stats])
326 repo.ui.status("%s\n" % note)
327 repo.ui.status("%s\n" % note)
327
328
328 def update(repo, node):
329 def update(repo, node):
329 """update the working directory to node, merging linear changes"""
330 """update the working directory to node, merging linear changes"""
330 stats = _merge.update(repo, node, False, False, None)
331 stats = _merge.update(repo, node, False, False, None)
331 _showstats(repo, stats)
332 _showstats(repo, stats)
332 if stats[3]:
333 if stats[3]:
333 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n"))
334 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n"))
334 return stats[3] > 0
335 return stats[3] > 0
335
336
336 # naming conflict in clone()
337 # naming conflict in clone()
337 _update = update
338 _update = update
338
339
339 def clean(repo, node, show_stats=True):
340 def clean(repo, node, show_stats=True):
340 """forcibly switch the working directory to node, clobbering changes"""
341 """forcibly switch the working directory to node, clobbering changes"""
341 stats = _merge.update(repo, node, False, True, None)
342 stats = _merge.update(repo, node, False, True, None)
342 if show_stats: _showstats(repo, stats)
343 if show_stats: _showstats(repo, stats)
343 return stats[3] > 0
344 return stats[3] > 0
344
345
345 def merge(repo, node, force=None, remind=True):
346 def merge(repo, node, force=None, remind=True):
346 """branch merge with node, resolving changes"""
347 """branch merge with node, resolving changes"""
347 stats = _merge.update(repo, node, True, force, False)
348 stats = _merge.update(repo, node, True, force, False)
348 _showstats(repo, stats)
349 _showstats(repo, stats)
349 if stats[3]:
350 if stats[3]:
350 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
351 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
351 "or 'hg up --clean' to abandon\n"))
352 "or 'hg up --clean' to abandon\n"))
352 elif remind:
353 elif remind:
353 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
354 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
354 return stats[3] > 0
355 return stats[3] > 0
355
356
356 def revert(repo, node, choose):
357 def revert(repo, node, choose):
357 """revert changes to revision in node without updating dirstate"""
358 """revert changes to revision in node without updating dirstate"""
358 return _merge.update(repo, node, False, True, choose)[3] > 0
359 return _merge.update(repo, node, False, True, choose)[3] > 0
359
360
360 def verify(repo):
361 def verify(repo):
361 """verify the consistency of a repository"""
362 """verify the consistency of a repository"""
362 return _verify.verify(repo)
363 return _verify.verify(repo)
@@ -1,220 +1,233
1 #!/bin/sh
1 #!/bin/sh
2
2
3 cp "$TESTDIR"/printenv.py .
3 cp "$TESTDIR"/printenv.py .
4
4
5 # commit hooks can see env vars
5 # commit hooks can see env vars
6 hg init a
6 hg init a
7 cd a
7 cd a
8 echo "[hooks]" > .hg/hgrc
8 echo "[hooks]" > .hg/hgrc
9 echo 'commit = unset HG_LOCAL HG_TAG; python ../printenv.py commit' >> .hg/hgrc
9 echo 'commit = unset HG_LOCAL HG_TAG; python ../printenv.py commit' >> .hg/hgrc
10 echo 'commit.b = unset HG_LOCAL HG_TAG; python ../printenv.py commit.b' >> .hg/hgrc
10 echo 'commit.b = unset HG_LOCAL HG_TAG; python ../printenv.py commit.b' >> .hg/hgrc
11 echo 'precommit = unset HG_LOCAL HG_NODE HG_TAG; python ../printenv.py precommit' >> .hg/hgrc
11 echo 'precommit = unset HG_LOCAL HG_NODE HG_TAG; python ../printenv.py precommit' >> .hg/hgrc
12 echo 'pretxncommit = unset HG_LOCAL HG_TAG; python ../printenv.py pretxncommit' >> .hg/hgrc
12 echo 'pretxncommit = unset HG_LOCAL HG_TAG; python ../printenv.py pretxncommit' >> .hg/hgrc
13 echo 'pretxncommit.tip = hg -q tip' >> .hg/hgrc
13 echo 'pretxncommit.tip = hg -q tip' >> .hg/hgrc
14 echo 'pre-identify = python ../printenv.py pre-identify 1' >> .hg/hgrc
14 echo 'pre-identify = python ../printenv.py pre-identify 1' >> .hg/hgrc
15 echo 'pre-cat = python ../printenv.py pre-cat' >> .hg/hgrc
15 echo 'pre-cat = python ../printenv.py pre-cat' >> .hg/hgrc
16 echo 'post-cat = python ../printenv.py post-cat' >> .hg/hgrc
16 echo 'post-cat = python ../printenv.py post-cat' >> .hg/hgrc
17 echo a > a
17 echo a > a
18 hg add a
18 hg add a
19 hg commit -m a -d "1000000 0"
19 hg commit -m a -d "1000000 0"
20
20
21 hg clone . ../b
21 hg clone . ../b
22 cd ../b
22 cd ../b
23
23
24 # changegroup hooks can see env vars
24 # changegroup hooks can see env vars
25 echo '[hooks]' > .hg/hgrc
25 echo '[hooks]' > .hg/hgrc
26 echo 'prechangegroup = python ../printenv.py prechangegroup' >> .hg/hgrc
26 echo 'prechangegroup = python ../printenv.py prechangegroup' >> .hg/hgrc
27 echo 'changegroup = python ../printenv.py changegroup' >> .hg/hgrc
27 echo 'changegroup = python ../printenv.py changegroup' >> .hg/hgrc
28 echo 'incoming = python ../printenv.py incoming' >> .hg/hgrc
28 echo 'incoming = python ../printenv.py incoming' >> .hg/hgrc
29
29
30 # pretxncommit and commit hooks can see both parents of merge
30 # pretxncommit and commit hooks can see both parents of merge
31 cd ../a
31 cd ../a
32 echo b >> a
32 echo b >> a
33 hg commit -m a1 -d "1 0"
33 hg commit -m a1 -d "1 0"
34 hg update -C 0
34 hg update -C 0
35 echo b > b
35 echo b > b
36 hg add b
36 hg add b
37 hg commit -m b -d '1 0'
37 hg commit -m b -d '1 0'
38 hg merge 1
38 hg merge 1
39 hg commit -m merge -d '2 0'
39 hg commit -m merge -d '2 0'
40
40
41 # test generic hooks
41 # test generic hooks
42 hg id
42 hg id
43 hg cat b
43 hg cat b
44
44
45 cd ../b
45 cd ../b
46 hg pull ../a
46 hg pull ../a
47
47
48 # tag hooks can see env vars
48 # tag hooks can see env vars
49 cd ../a
49 cd ../a
50 echo 'pretag = python ../printenv.py pretag' >> .hg/hgrc
50 echo 'pretag = python ../printenv.py pretag' >> .hg/hgrc
51 echo 'tag = unset HG_PARENT1 HG_PARENT2; python ../printenv.py tag' >> .hg/hgrc
51 echo 'tag = unset HG_PARENT1 HG_PARENT2; python ../printenv.py tag' >> .hg/hgrc
52 hg tag -d '3 0' a
52 hg tag -d '3 0' a
53 hg tag -l la
53 hg tag -l la
54
54
55 # pretag hook can forbid tagging
55 # pretag hook can forbid tagging
56 echo 'pretag.forbid = python ../printenv.py pretag.forbid 1' >> .hg/hgrc
56 echo 'pretag.forbid = python ../printenv.py pretag.forbid 1' >> .hg/hgrc
57 hg tag -d '4 0' fa
57 hg tag -d '4 0' fa
58 hg tag -l fla
58 hg tag -l fla
59
59
60 # pretxncommit hook can see changeset, can roll back txn, changeset
60 # pretxncommit hook can see changeset, can roll back txn, changeset
61 # no more there after
61 # no more there after
62 echo 'pretxncommit.forbid0 = hg tip -q' >> .hg/hgrc
62 echo 'pretxncommit.forbid0 = hg tip -q' >> .hg/hgrc
63 echo 'pretxncommit.forbid1 = python ../printenv.py pretxncommit.forbid 1' >> .hg/hgrc
63 echo 'pretxncommit.forbid1 = python ../printenv.py pretxncommit.forbid 1' >> .hg/hgrc
64 echo z > z
64 echo z > z
65 hg add z
65 hg add z
66 hg -q tip
66 hg -q tip
67 hg commit -m 'fail' -d '4 0'
67 hg commit -m 'fail' -d '4 0'
68 hg -q tip
68 hg -q tip
69
69
70 # precommit hook can prevent commit
70 # precommit hook can prevent commit
71 echo 'precommit.forbid = python ../printenv.py precommit.forbid 1' >> .hg/hgrc
71 echo 'precommit.forbid = python ../printenv.py precommit.forbid 1' >> .hg/hgrc
72 hg commit -m 'fail' -d '4 0'
72 hg commit -m 'fail' -d '4 0'
73 hg -q tip
73 hg -q tip
74
74
75 # preupdate hook can prevent update
75 # preupdate hook can prevent update
76 echo 'preupdate = python ../printenv.py preupdate' >> .hg/hgrc
76 echo 'preupdate = python ../printenv.py preupdate' >> .hg/hgrc
77 hg update 1
77 hg update 1
78
78
79 # update hook
79 # update hook
80 echo 'update = python ../printenv.py update' >> .hg/hgrc
80 echo 'update = python ../printenv.py update' >> .hg/hgrc
81 hg update
81 hg update
82
82
83 # prechangegroup hook can prevent incoming changes
83 # prechangegroup hook can prevent incoming changes
84 cd ../b
84 cd ../b
85 hg -q tip
85 hg -q tip
86 echo '[hooks]' > .hg/hgrc
86 echo '[hooks]' > .hg/hgrc
87 echo 'prechangegroup.forbid = python ../printenv.py prechangegroup.forbid 1' >> .hg/hgrc
87 echo 'prechangegroup.forbid = python ../printenv.py prechangegroup.forbid 1' >> .hg/hgrc
88 hg pull ../a
88 hg pull ../a
89
89
90 # pretxnchangegroup hook can see incoming changes, can roll back txn,
90 # pretxnchangegroup hook can see incoming changes, can roll back txn,
91 # incoming changes no longer there after
91 # incoming changes no longer there after
92 echo '[hooks]' > .hg/hgrc
92 echo '[hooks]' > .hg/hgrc
93 echo 'pretxnchangegroup.forbid0 = hg tip -q' >> .hg/hgrc
93 echo 'pretxnchangegroup.forbid0 = hg tip -q' >> .hg/hgrc
94 echo 'pretxnchangegroup.forbid1 = python ../printenv.py pretxnchangegroup.forbid 1' >> .hg/hgrc
94 echo 'pretxnchangegroup.forbid1 = python ../printenv.py pretxnchangegroup.forbid 1' >> .hg/hgrc
95 hg pull ../a
95 hg pull ../a
96 hg -q tip
96 hg -q tip
97
97
98 # outgoing hooks can see env vars
98 # outgoing hooks can see env vars
99 rm .hg/hgrc
99 rm .hg/hgrc
100 echo '[hooks]' > ../a/.hg/hgrc
100 echo '[hooks]' > ../a/.hg/hgrc
101 echo 'preoutgoing = python ../printenv.py preoutgoing' >> ../a/.hg/hgrc
101 echo 'preoutgoing = python ../printenv.py preoutgoing' >> ../a/.hg/hgrc
102 echo 'outgoing = python ../printenv.py outgoing' >> ../a/.hg/hgrc
102 echo 'outgoing = python ../printenv.py outgoing' >> ../a/.hg/hgrc
103 hg pull ../a
103 hg pull ../a
104 hg rollback
104 hg rollback
105
105
106 # preoutgoing hook can prevent outgoing changes
106 # preoutgoing hook can prevent outgoing changes
107 echo 'preoutgoing.forbid = python ../printenv.py preoutgoing.forbid 1' >> ../a/.hg/hgrc
107 echo 'preoutgoing.forbid = python ../printenv.py preoutgoing.forbid 1' >> ../a/.hg/hgrc
108 hg pull ../a
108 hg pull ../a
109
109
110 # outgoing hooks work for local clones
111 cd ..
112 echo '[hooks]' > a/.hg/hgrc
113 echo 'preoutgoing = python ../printenv.py preoutgoing' >> a/.hg/hgrc
114 echo 'outgoing = python ../printenv.py outgoing' >> a/.hg/hgrc
115 hg clone a c
116 rm -rf c
117
118 # preoutgoing hook can prevent outgoing changes for local clones
119 echo 'preoutgoing.forbid = python ../printenv.py preoutgoing.forbid 1' >> a/.hg/hgrc
120 hg clone a zzz
121 cd b
122
110 cat > hooktests.py <<EOF
123 cat > hooktests.py <<EOF
111 from mercurial import util
124 from mercurial import util
112
125
113 uncallable = 0
126 uncallable = 0
114
127
115 def printargs(args):
128 def printargs(args):
116 args.pop('ui', None)
129 args.pop('ui', None)
117 args.pop('repo', None)
130 args.pop('repo', None)
118 a = list(args.items())
131 a = list(args.items())
119 a.sort()
132 a.sort()
120 print 'hook args:'
133 print 'hook args:'
121 for k, v in a:
134 for k, v in a:
122 print ' ', k, v
135 print ' ', k, v
123
136
124 def passhook(**args):
137 def passhook(**args):
125 printargs(args)
138 printargs(args)
126
139
127 def failhook(**args):
140 def failhook(**args):
128 printargs(args)
141 printargs(args)
129 return True
142 return True
130
143
131 class LocalException(Exception):
144 class LocalException(Exception):
132 pass
145 pass
133
146
134 def raisehook(**args):
147 def raisehook(**args):
135 raise LocalException('exception from hook')
148 raise LocalException('exception from hook')
136
149
137 def aborthook(**args):
150 def aborthook(**args):
138 raise util.Abort('raise abort from hook')
151 raise util.Abort('raise abort from hook')
139
152
140 def brokenhook(**args):
153 def brokenhook(**args):
141 return 1 + {}
154 return 1 + {}
142
155
143 class container:
156 class container:
144 unreachable = 1
157 unreachable = 1
145 EOF
158 EOF
146
159
147 echo '# test python hooks'
160 echo '# test python hooks'
148 PYTHONPATH="`pwd`:$PYTHONPATH"
161 PYTHONPATH="`pwd`:$PYTHONPATH"
149 export PYTHONPATH
162 export PYTHONPATH
150
163
151 echo '[hooks]' > ../a/.hg/hgrc
164 echo '[hooks]' > ../a/.hg/hgrc
152 echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
165 echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
153 hg pull ../a 2>&1 | grep 'raised an exception'
166 hg pull ../a 2>&1 | grep 'raised an exception'
154
167
155 echo '[hooks]' > ../a/.hg/hgrc
168 echo '[hooks]' > ../a/.hg/hgrc
156 echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
169 echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
157 hg pull ../a 2>&1 | grep 'raised an exception'
170 hg pull ../a 2>&1 | grep 'raised an exception'
158
171
159 echo '[hooks]' > ../a/.hg/hgrc
172 echo '[hooks]' > ../a/.hg/hgrc
160 echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
173 echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
161 hg pull ../a
174 hg pull ../a
162
175
163 echo '[hooks]' > ../a/.hg/hgrc
176 echo '[hooks]' > ../a/.hg/hgrc
164 echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
177 echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
165 hg pull ../a
178 hg pull ../a
166
179
167 echo '[hooks]' > ../a/.hg/hgrc
180 echo '[hooks]' > ../a/.hg/hgrc
168 echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
181 echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
169 hg pull ../a
182 hg pull ../a
170
183
171 echo '[hooks]' > ../a/.hg/hgrc
184 echo '[hooks]' > ../a/.hg/hgrc
172 echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
185 echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
173 hg pull ../a
186 hg pull ../a
174
187
175 echo '[hooks]' > ../a/.hg/hgrc
188 echo '[hooks]' > ../a/.hg/hgrc
176 echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
189 echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
177 hg pull ../a
190 hg pull ../a
178
191
179 echo '[hooks]' > ../a/.hg/hgrc
192 echo '[hooks]' > ../a/.hg/hgrc
180 echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
193 echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
181 hg pull ../a
194 hg pull ../a
182
195
183 echo '[hooks]' > ../a/.hg/hgrc
196 echo '[hooks]' > ../a/.hg/hgrc
184 echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
197 echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
185 hg pull ../a
198 hg pull ../a
186
199
187 echo '[hooks]' > ../a/.hg/hgrc
200 echo '[hooks]' > ../a/.hg/hgrc
188 echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
201 echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
189 hg pull ../a
202 hg pull ../a
190
203
191 echo '# make sure --traceback works'
204 echo '# make sure --traceback works'
192 echo '[hooks]' > .hg/hgrc
205 echo '[hooks]' > .hg/hgrc
193 echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
206 echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
194
207
195 echo a >> a
208 echo a >> a
196 hg --traceback commit -A -m a 2>&1 | grep '^Traceback'
209 hg --traceback commit -A -m a 2>&1 | grep '^Traceback'
197
210
198 cd ..
211 cd ..
199 hg init c
212 hg init c
200 cd c
213 cd c
201
214
202 cat > hookext.py <<EOF
215 cat > hookext.py <<EOF
203 def autohook(**args):
216 def autohook(**args):
204 print "Automatically installed hook"
217 print "Automatically installed hook"
205
218
206 def reposetup(ui, repo):
219 def reposetup(ui, repo):
207 repo.ui.setconfig("hooks", "commit.auto", autohook)
220 repo.ui.setconfig("hooks", "commit.auto", autohook)
208 EOF
221 EOF
209 echo '[extensions]' >> .hg/hgrc
222 echo '[extensions]' >> .hg/hgrc
210 echo 'hookext = hookext.py' >> .hg/hgrc
223 echo 'hookext = hookext.py' >> .hg/hgrc
211
224
212 touch foo
225 touch foo
213 hg add foo
226 hg add foo
214 hg ci -m 'add foo'
227 hg ci -m 'add foo'
215 echo >> foo
228 echo >> foo
216 hg ci --debug -m 'change foo' | sed -e 's/ at .*>/>/'
229 hg ci --debug -m 'change foo' | sed -e 's/ at .*>/>/'
217
230
218 hg showconfig hooks | sed -e 's/ at .*>/>/'
231 hg showconfig hooks | sed -e 's/ at .*>/>/'
219
232
220 exit 0
233 exit 0
@@ -1,155 +1,162
1 precommit hook: HG_PARENT1=0000000000000000000000000000000000000000
1 precommit hook: HG_PARENT1=0000000000000000000000000000000000000000
2 pretxncommit hook: HG_NODE=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PARENT1=0000000000000000000000000000000000000000 HG_PENDING=true
2 pretxncommit hook: HG_NODE=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PARENT1=0000000000000000000000000000000000000000 HG_PENDING=true
3 0:29b62aeb769f
3 0:29b62aeb769f
4 commit hook: HG_NODE=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PARENT1=0000000000000000000000000000000000000000
4 commit hook: HG_NODE=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PARENT1=0000000000000000000000000000000000000000
5 commit.b hook: HG_NODE=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PARENT1=0000000000000000000000000000000000000000
5 commit.b hook: HG_NODE=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PARENT1=0000000000000000000000000000000000000000
6 updating working directory
6 updating working directory
7 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
7 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
8 precommit hook: HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b
8 precommit hook: HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b
9 pretxncommit hook: HG_NODE=b702efe9688826e3a91283852b328b84dbf37bc2 HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PENDING=true
9 pretxncommit hook: HG_NODE=b702efe9688826e3a91283852b328b84dbf37bc2 HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PENDING=true
10 1:b702efe96888
10 1:b702efe96888
11 commit hook: HG_NODE=b702efe9688826e3a91283852b328b84dbf37bc2 HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b
11 commit hook: HG_NODE=b702efe9688826e3a91283852b328b84dbf37bc2 HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b
12 commit.b hook: HG_NODE=b702efe9688826e3a91283852b328b84dbf37bc2 HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b
12 commit.b hook: HG_NODE=b702efe9688826e3a91283852b328b84dbf37bc2 HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b
13 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
13 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
14 precommit hook: HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b
14 precommit hook: HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b
15 pretxncommit hook: HG_NODE=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PENDING=true
15 pretxncommit hook: HG_NODE=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PENDING=true
16 2:1324a5531bac
16 2:1324a5531bac
17 commit hook: HG_NODE=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b
17 commit hook: HG_NODE=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b
18 commit.b hook: HG_NODE=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b
18 commit.b hook: HG_NODE=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b
19 created new head
19 created new head
20 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
20 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
21 (branch merge, don't forget to commit)
21 (branch merge, don't forget to commit)
22 precommit hook: HG_PARENT1=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT2=b702efe9688826e3a91283852b328b84dbf37bc2
22 precommit hook: HG_PARENT1=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT2=b702efe9688826e3a91283852b328b84dbf37bc2
23 pretxncommit hook: HG_NODE=4c52fb2e402287dd5dc052090682536c8406c321 HG_PARENT1=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT2=b702efe9688826e3a91283852b328b84dbf37bc2 HG_PENDING=true
23 pretxncommit hook: HG_NODE=4c52fb2e402287dd5dc052090682536c8406c321 HG_PARENT1=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT2=b702efe9688826e3a91283852b328b84dbf37bc2 HG_PENDING=true
24 3:4c52fb2e4022
24 3:4c52fb2e4022
25 commit hook: HG_NODE=4c52fb2e402287dd5dc052090682536c8406c321 HG_PARENT1=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT2=b702efe9688826e3a91283852b328b84dbf37bc2
25 commit hook: HG_NODE=4c52fb2e402287dd5dc052090682536c8406c321 HG_PARENT1=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT2=b702efe9688826e3a91283852b328b84dbf37bc2
26 commit.b hook: HG_NODE=4c52fb2e402287dd5dc052090682536c8406c321 HG_PARENT1=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT2=b702efe9688826e3a91283852b328b84dbf37bc2
26 commit.b hook: HG_NODE=4c52fb2e402287dd5dc052090682536c8406c321 HG_PARENT1=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT2=b702efe9688826e3a91283852b328b84dbf37bc2
27 pre-identify hook: HG_ARGS=id
27 pre-identify hook: HG_ARGS=id
28 warning: pre-identify hook exited with status 1
28 warning: pre-identify hook exited with status 1
29 pre-cat hook: HG_ARGS=cat b
29 pre-cat hook: HG_ARGS=cat b
30 post-cat hook: HG_ARGS=cat b HG_RESULT=0
30 post-cat hook: HG_ARGS=cat b HG_RESULT=0
31 b
31 b
32 prechangegroup hook: HG_SOURCE=pull HG_URL=file:
32 prechangegroup hook: HG_SOURCE=pull HG_URL=file:
33 changegroup hook: HG_NODE=b702efe9688826e3a91283852b328b84dbf37bc2 HG_SOURCE=pull HG_URL=file:
33 changegroup hook: HG_NODE=b702efe9688826e3a91283852b328b84dbf37bc2 HG_SOURCE=pull HG_URL=file:
34 incoming hook: HG_NODE=b702efe9688826e3a91283852b328b84dbf37bc2 HG_SOURCE=pull HG_URL=file:
34 incoming hook: HG_NODE=b702efe9688826e3a91283852b328b84dbf37bc2 HG_SOURCE=pull HG_URL=file:
35 incoming hook: HG_NODE=1324a5531bac09b329c3845d35ae6a7526874edb HG_SOURCE=pull HG_URL=file:
35 incoming hook: HG_NODE=1324a5531bac09b329c3845d35ae6a7526874edb HG_SOURCE=pull HG_URL=file:
36 incoming hook: HG_NODE=4c52fb2e402287dd5dc052090682536c8406c321 HG_SOURCE=pull HG_URL=file:
36 incoming hook: HG_NODE=4c52fb2e402287dd5dc052090682536c8406c321 HG_SOURCE=pull HG_URL=file:
37 pulling from ../a
37 pulling from ../a
38 searching for changes
38 searching for changes
39 adding changesets
39 adding changesets
40 adding manifests
40 adding manifests
41 adding file changes
41 adding file changes
42 added 3 changesets with 2 changes to 2 files
42 added 3 changesets with 2 changes to 2 files
43 (run 'hg update' to get a working copy)
43 (run 'hg update' to get a working copy)
44 pretag hook: HG_LOCAL=0 HG_NODE=4c52fb2e402287dd5dc052090682536c8406c321 HG_TAG=a
44 pretag hook: HG_LOCAL=0 HG_NODE=4c52fb2e402287dd5dc052090682536c8406c321 HG_TAG=a
45 precommit hook: HG_PARENT1=4c52fb2e402287dd5dc052090682536c8406c321
45 precommit hook: HG_PARENT1=4c52fb2e402287dd5dc052090682536c8406c321
46 pretxncommit hook: HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PARENT1=4c52fb2e402287dd5dc052090682536c8406c321 HG_PENDING=true
46 pretxncommit hook: HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PARENT1=4c52fb2e402287dd5dc052090682536c8406c321 HG_PENDING=true
47 4:8ea2ef7ad3e8
47 4:8ea2ef7ad3e8
48 commit hook: HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PARENT1=4c52fb2e402287dd5dc052090682536c8406c321
48 commit hook: HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PARENT1=4c52fb2e402287dd5dc052090682536c8406c321
49 commit.b hook: HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PARENT1=4c52fb2e402287dd5dc052090682536c8406c321
49 commit.b hook: HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PARENT1=4c52fb2e402287dd5dc052090682536c8406c321
50 tag hook: HG_LOCAL=0 HG_NODE=4c52fb2e402287dd5dc052090682536c8406c321 HG_TAG=a
50 tag hook: HG_LOCAL=0 HG_NODE=4c52fb2e402287dd5dc052090682536c8406c321 HG_TAG=a
51 pretag hook: HG_LOCAL=1 HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_TAG=la
51 pretag hook: HG_LOCAL=1 HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_TAG=la
52 tag hook: HG_LOCAL=1 HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_TAG=la
52 tag hook: HG_LOCAL=1 HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_TAG=la
53 pretag hook: HG_LOCAL=0 HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_TAG=fa
53 pretag hook: HG_LOCAL=0 HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_TAG=fa
54 pretag.forbid hook: HG_LOCAL=0 HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_TAG=fa
54 pretag.forbid hook: HG_LOCAL=0 HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_TAG=fa
55 abort: pretag.forbid hook exited with status 1
55 abort: pretag.forbid hook exited with status 1
56 pretag hook: HG_LOCAL=1 HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_TAG=fla
56 pretag hook: HG_LOCAL=1 HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_TAG=fla
57 pretag.forbid hook: HG_LOCAL=1 HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_TAG=fla
57 pretag.forbid hook: HG_LOCAL=1 HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_TAG=fla
58 abort: pretag.forbid hook exited with status 1
58 abort: pretag.forbid hook exited with status 1
59 4:8ea2ef7ad3e8
59 4:8ea2ef7ad3e8
60 precommit hook: HG_PARENT1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198
60 precommit hook: HG_PARENT1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198
61 pretxncommit hook: HG_NODE=fad284daf8c032148abaffcd745dafeceefceb61 HG_PARENT1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PENDING=true
61 pretxncommit hook: HG_NODE=fad284daf8c032148abaffcd745dafeceefceb61 HG_PARENT1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PENDING=true
62 5:fad284daf8c0
62 5:fad284daf8c0
63 5:fad284daf8c0
63 5:fad284daf8c0
64 pretxncommit.forbid hook: HG_NODE=fad284daf8c032148abaffcd745dafeceefceb61 HG_PARENT1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PENDING=true
64 pretxncommit.forbid hook: HG_NODE=fad284daf8c032148abaffcd745dafeceefceb61 HG_PARENT1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PENDING=true
65 transaction abort!
65 transaction abort!
66 rollback completed
66 rollback completed
67 abort: pretxncommit.forbid1 hook exited with status 1
67 abort: pretxncommit.forbid1 hook exited with status 1
68 4:8ea2ef7ad3e8
68 4:8ea2ef7ad3e8
69 precommit hook: HG_PARENT1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198
69 precommit hook: HG_PARENT1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198
70 precommit.forbid hook: HG_PARENT1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198
70 precommit.forbid hook: HG_PARENT1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198
71 abort: precommit.forbid hook exited with status 1
71 abort: precommit.forbid hook exited with status 1
72 4:8ea2ef7ad3e8
72 4:8ea2ef7ad3e8
73 preupdate hook: HG_PARENT1=b702efe96888
73 preupdate hook: HG_PARENT1=b702efe96888
74 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
74 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
75 preupdate hook: HG_PARENT1=8ea2ef7ad3e8
75 preupdate hook: HG_PARENT1=8ea2ef7ad3e8
76 update hook: HG_ERROR=0 HG_PARENT1=8ea2ef7ad3e8
76 update hook: HG_ERROR=0 HG_PARENT1=8ea2ef7ad3e8
77 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
77 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
78 3:4c52fb2e4022
78 3:4c52fb2e4022
79 prechangegroup.forbid hook: HG_SOURCE=pull HG_URL=file:
79 prechangegroup.forbid hook: HG_SOURCE=pull HG_URL=file:
80 pulling from ../a
80 pulling from ../a
81 searching for changes
81 searching for changes
82 abort: prechangegroup.forbid hook exited with status 1
82 abort: prechangegroup.forbid hook exited with status 1
83 4:8ea2ef7ad3e8
83 4:8ea2ef7ad3e8
84 pretxnchangegroup.forbid hook: HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PENDING=true HG_SOURCE=pull HG_URL=file:
84 pretxnchangegroup.forbid hook: HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PENDING=true HG_SOURCE=pull HG_URL=file:
85 pulling from ../a
85 pulling from ../a
86 searching for changes
86 searching for changes
87 adding changesets
87 adding changesets
88 adding manifests
88 adding manifests
89 adding file changes
89 adding file changes
90 added 1 changesets with 1 changes to 1 files
90 added 1 changesets with 1 changes to 1 files
91 transaction abort!
91 transaction abort!
92 rollback completed
92 rollback completed
93 abort: pretxnchangegroup.forbid1 hook exited with status 1
93 abort: pretxnchangegroup.forbid1 hook exited with status 1
94 3:4c52fb2e4022
94 3:4c52fb2e4022
95 preoutgoing hook: HG_SOURCE=pull
95 preoutgoing hook: HG_SOURCE=pull
96 outgoing hook: HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_SOURCE=pull
96 outgoing hook: HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_SOURCE=pull
97 pulling from ../a
97 pulling from ../a
98 searching for changes
98 searching for changes
99 adding changesets
99 adding changesets
100 adding manifests
100 adding manifests
101 adding file changes
101 adding file changes
102 added 1 changesets with 1 changes to 1 files
102 added 1 changesets with 1 changes to 1 files
103 (run 'hg update' to get a working copy)
103 (run 'hg update' to get a working copy)
104 rolling back last transaction
104 rolling back last transaction
105 preoutgoing hook: HG_SOURCE=pull
105 preoutgoing hook: HG_SOURCE=pull
106 preoutgoing.forbid hook: HG_SOURCE=pull
106 preoutgoing.forbid hook: HG_SOURCE=pull
107 pulling from ../a
107 pulling from ../a
108 searching for changes
108 searching for changes
109 abort: preoutgoing.forbid hook exited with status 1
109 abort: preoutgoing.forbid hook exited with status 1
110 preoutgoing hook: HG_SOURCE=clone
111 outgoing hook: HG_NODE=0000000000000000000000000000000000000000 HG_SOURCE=clone
112 updating working directory
113 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
114 preoutgoing hook: HG_SOURCE=clone
115 preoutgoing.forbid hook: HG_SOURCE=clone
116 abort: preoutgoing.forbid hook exited with status 1
110 # test python hooks
117 # test python hooks
111 error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
118 error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
112 error: preoutgoing.raise hook raised an exception: exception from hook
119 error: preoutgoing.raise hook raised an exception: exception from hook
113 pulling from ../a
120 pulling from ../a
114 searching for changes
121 searching for changes
115 error: preoutgoing.abort hook failed: raise abort from hook
122 error: preoutgoing.abort hook failed: raise abort from hook
116 abort: raise abort from hook
123 abort: raise abort from hook
117 pulling from ../a
124 pulling from ../a
118 searching for changes
125 searching for changes
119 hook args:
126 hook args:
120 hooktype preoutgoing
127 hooktype preoutgoing
121 source pull
128 source pull
122 abort: preoutgoing.fail hook failed
129 abort: preoutgoing.fail hook failed
123 pulling from ../a
130 pulling from ../a
124 searching for changes
131 searching for changes
125 abort: preoutgoing.uncallable hook is invalid ("hooktests.uncallable" is not callable)
132 abort: preoutgoing.uncallable hook is invalid ("hooktests.uncallable" is not callable)
126 pulling from ../a
133 pulling from ../a
127 searching for changes
134 searching for changes
128 abort: preoutgoing.nohook hook is invalid ("hooktests.nohook" is not defined)
135 abort: preoutgoing.nohook hook is invalid ("hooktests.nohook" is not defined)
129 pulling from ../a
136 pulling from ../a
130 searching for changes
137 searching for changes
131 abort: preoutgoing.nomodule hook is invalid ("nomodule" not in a module)
138 abort: preoutgoing.nomodule hook is invalid ("nomodule" not in a module)
132 pulling from ../a
139 pulling from ../a
133 searching for changes
140 searching for changes
134 abort: preoutgoing.badmodule hook is invalid (import of "nomodule" failed)
141 abort: preoutgoing.badmodule hook is invalid (import of "nomodule" failed)
135 pulling from ../a
142 pulling from ../a
136 searching for changes
143 searching for changes
137 abort: preoutgoing.unreachable hook is invalid (import of "hooktests.container" failed)
144 abort: preoutgoing.unreachable hook is invalid (import of "hooktests.container" failed)
138 pulling from ../a
145 pulling from ../a
139 searching for changes
146 searching for changes
140 hook args:
147 hook args:
141 hooktype preoutgoing
148 hooktype preoutgoing
142 source pull
149 source pull
143 adding changesets
150 adding changesets
144 adding manifests
151 adding manifests
145 adding file changes
152 adding file changes
146 added 1 changesets with 1 changes to 1 files
153 added 1 changesets with 1 changes to 1 files
147 (run 'hg update' to get a working copy)
154 (run 'hg update' to get a working copy)
148 # make sure --traceback works
155 # make sure --traceback works
149 Traceback (most recent call last):
156 Traceback (most recent call last):
150 Automatically installed hook
157 Automatically installed hook
151 foo
158 foo
152 calling hook commit.auto: <function autohook>
159 calling hook commit.auto: <function autohook>
153 Automatically installed hook
160 Automatically installed hook
154 committed changeset 1:52998019f6252a2b893452765fcb0a47351a5708
161 committed changeset 1:52998019f6252a2b893452765fcb0a47351a5708
155 hooks.commit.auto=<function autohook>
162 hooks.commit.auto=<function autohook>
General Comments 0
You need to be logged in to leave comments. Login now