##// END OF EJS Templates
hooks: sort any dictionaries set in the environment...
Dan Villiom Podlaski Christiansen -
r13207:1775382f default
parent child Browse files
Show More
@@ -1,153 +1,159
1 # hook.py - hook support for mercurial
1 # hook.py - hook support for mercurial
2 #
2 #
3 # Copyright 2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from i18n import _
8 from i18n import _
9 import os, sys
9 import os, sys
10 import extensions, util
10 import extensions, util
11
11
12 def _pythonhook(ui, repo, name, hname, funcname, args, throw):
12 def _pythonhook(ui, repo, name, hname, funcname, args, throw):
13 '''call python hook. hook is callable object, looked up as
13 '''call python hook. hook is callable object, looked up as
14 name in python module. if callable returns "true", hook
14 name in python module. if callable returns "true", hook
15 fails, else passes. if hook raises exception, treated as
15 fails, else passes. if hook raises exception, treated as
16 hook failure. exception propagates if throw is "true".
16 hook failure. exception propagates if throw is "true".
17
17
18 reason for "true" meaning "hook failed" is so that
18 reason for "true" meaning "hook failed" is so that
19 unmodified commands (e.g. mercurial.commands.update) can
19 unmodified commands (e.g. mercurial.commands.update) can
20 be run as hooks without wrappers to convert return values.'''
20 be run as hooks without wrappers to convert return values.'''
21
21
22 ui.note(_("calling hook %s: %s\n") % (hname, funcname))
22 ui.note(_("calling hook %s: %s\n") % (hname, funcname))
23 obj = funcname
23 obj = funcname
24 if not hasattr(obj, '__call__'):
24 if not hasattr(obj, '__call__'):
25 d = funcname.rfind('.')
25 d = funcname.rfind('.')
26 if d == -1:
26 if d == -1:
27 raise util.Abort(_('%s hook is invalid ("%s" not in '
27 raise util.Abort(_('%s hook is invalid ("%s" not in '
28 'a module)') % (hname, funcname))
28 'a module)') % (hname, funcname))
29 modname = funcname[:d]
29 modname = funcname[:d]
30 oldpaths = sys.path
30 oldpaths = sys.path
31 if hasattr(sys, "frozen"):
31 if hasattr(sys, "frozen"):
32 # binary installs require sys.path manipulation
32 # binary installs require sys.path manipulation
33 modpath, modfile = os.path.split(modname)
33 modpath, modfile = os.path.split(modname)
34 if modpath and modfile:
34 if modpath and modfile:
35 sys.path = sys.path[:] + [modpath]
35 sys.path = sys.path[:] + [modpath]
36 modname = modfile
36 modname = modfile
37 try:
37 try:
38 obj = __import__(modname)
38 obj = __import__(modname)
39 except ImportError:
39 except ImportError:
40 e1 = sys.exc_type, sys.exc_value, sys.exc_traceback
40 e1 = sys.exc_type, sys.exc_value, sys.exc_traceback
41 try:
41 try:
42 # extensions are loaded with hgext_ prefix
42 # extensions are loaded with hgext_ prefix
43 obj = __import__("hgext_%s" % modname)
43 obj = __import__("hgext_%s" % modname)
44 except ImportError:
44 except ImportError:
45 e2 = sys.exc_type, sys.exc_value, sys.exc_traceback
45 e2 = sys.exc_type, sys.exc_value, sys.exc_traceback
46 if ui.tracebackflag:
46 if ui.tracebackflag:
47 ui.warn(_('exception from first failed import attempt:\n'))
47 ui.warn(_('exception from first failed import attempt:\n'))
48 ui.traceback(e1)
48 ui.traceback(e1)
49 if ui.tracebackflag:
49 if ui.tracebackflag:
50 ui.warn(_('exception from second failed import attempt:\n'))
50 ui.warn(_('exception from second failed import attempt:\n'))
51 ui.traceback(e2)
51 ui.traceback(e2)
52 raise util.Abort(_('%s hook is invalid '
52 raise util.Abort(_('%s hook is invalid '
53 '(import of "%s" failed)') %
53 '(import of "%s" failed)') %
54 (hname, modname))
54 (hname, modname))
55 sys.path = oldpaths
55 sys.path = oldpaths
56 try:
56 try:
57 for p in funcname.split('.')[1:]:
57 for p in funcname.split('.')[1:]:
58 obj = getattr(obj, p)
58 obj = getattr(obj, p)
59 except AttributeError:
59 except AttributeError:
60 raise util.Abort(_('%s hook is invalid '
60 raise util.Abort(_('%s hook is invalid '
61 '("%s" is not defined)') %
61 '("%s" is not defined)') %
62 (hname, funcname))
62 (hname, funcname))
63 if not hasattr(obj, '__call__'):
63 if not hasattr(obj, '__call__'):
64 raise util.Abort(_('%s hook is invalid '
64 raise util.Abort(_('%s hook is invalid '
65 '("%s" is not callable)') %
65 '("%s" is not callable)') %
66 (hname, funcname))
66 (hname, funcname))
67 try:
67 try:
68 r = obj(ui=ui, repo=repo, hooktype=name, **args)
68 r = obj(ui=ui, repo=repo, hooktype=name, **args)
69 except KeyboardInterrupt:
69 except KeyboardInterrupt:
70 raise
70 raise
71 except Exception, exc:
71 except Exception, exc:
72 if isinstance(exc, util.Abort):
72 if isinstance(exc, util.Abort):
73 ui.warn(_('error: %s hook failed: %s\n') %
73 ui.warn(_('error: %s hook failed: %s\n') %
74 (hname, exc.args[0]))
74 (hname, exc.args[0]))
75 else:
75 else:
76 ui.warn(_('error: %s hook raised an exception: '
76 ui.warn(_('error: %s hook raised an exception: '
77 '%s\n') % (hname, exc))
77 '%s\n') % (hname, exc))
78 if throw:
78 if throw:
79 raise
79 raise
80 ui.traceback()
80 ui.traceback()
81 return True
81 return True
82 if r:
82 if r:
83 if throw:
83 if throw:
84 raise util.Abort(_('%s hook failed') % hname)
84 raise util.Abort(_('%s hook failed') % hname)
85 ui.warn(_('warning: %s hook failed\n') % hname)
85 ui.warn(_('warning: %s hook failed\n') % hname)
86 return r
86 return r
87
87
88 def _exthook(ui, repo, name, cmd, args, throw):
88 def _exthook(ui, repo, name, cmd, args, throw):
89 ui.note(_("running hook %s: %s\n") % (name, cmd))
89 ui.note(_("running hook %s: %s\n") % (name, cmd))
90
90
91 env = {}
91 env = {}
92 for k, v in args.iteritems():
92 for k, v in args.iteritems():
93 if hasattr(v, '__call__'):
93 if hasattr(v, '__call__'):
94 v = v()
94 v = v()
95 if isinstance(v, dict):
96 # make the dictionary element order stable across Python
97 # implementations
98 v = ('{' +
99 ', '.join('%r: %r' % i for i in sorted(v.iteritems())) +
100 '}')
95 env['HG_' + k.upper()] = v
101 env['HG_' + k.upper()] = v
96
102
97 if repo:
103 if repo:
98 cwd = repo.root
104 cwd = repo.root
99 else:
105 else:
100 cwd = os.getcwd()
106 cwd = os.getcwd()
101 if 'HG_URL' in env and env['HG_URL'].startswith('remote:http'):
107 if 'HG_URL' in env and env['HG_URL'].startswith('remote:http'):
102 r = util.system(cmd, environ=env, cwd=cwd, out=ui)
108 r = util.system(cmd, environ=env, cwd=cwd, out=ui)
103 else:
109 else:
104 r = util.system(cmd, environ=env, cwd=cwd)
110 r = util.system(cmd, environ=env, cwd=cwd)
105 if r:
111 if r:
106 desc, r = util.explain_exit(r)
112 desc, r = util.explain_exit(r)
107 if throw:
113 if throw:
108 raise util.Abort(_('%s hook %s') % (name, desc))
114 raise util.Abort(_('%s hook %s') % (name, desc))
109 ui.warn(_('warning: %s hook %s\n') % (name, desc))
115 ui.warn(_('warning: %s hook %s\n') % (name, desc))
110 return r
116 return r
111
117
112 _redirect = False
118 _redirect = False
113 def redirect(state):
119 def redirect(state):
114 global _redirect
120 global _redirect
115 _redirect = state
121 _redirect = state
116
122
117 def hook(ui, repo, name, throw=False, **args):
123 def hook(ui, repo, name, throw=False, **args):
118 r = False
124 r = False
119
125
120 oldstdout = -1
126 oldstdout = -1
121 if _redirect:
127 if _redirect:
122 stdoutno = sys.__stdout__.fileno()
128 stdoutno = sys.__stdout__.fileno()
123 stderrno = sys.__stderr__.fileno()
129 stderrno = sys.__stderr__.fileno()
124 # temporarily redirect stdout to stderr, if possible
130 # temporarily redirect stdout to stderr, if possible
125 if stdoutno >= 0 and stderrno >= 0:
131 if stdoutno >= 0 and stderrno >= 0:
126 oldstdout = os.dup(stdoutno)
132 oldstdout = os.dup(stdoutno)
127 os.dup2(stderrno, stdoutno)
133 os.dup2(stderrno, stdoutno)
128
134
129 try:
135 try:
130 for hname, cmd in ui.configitems('hooks'):
136 for hname, cmd in ui.configitems('hooks'):
131 if hname.split('.')[0] != name or not cmd:
137 if hname.split('.')[0] != name or not cmd:
132 continue
138 continue
133 if hasattr(cmd, '__call__'):
139 if hasattr(cmd, '__call__'):
134 r = _pythonhook(ui, repo, name, hname, cmd, args, throw) or r
140 r = _pythonhook(ui, repo, name, hname, cmd, args, throw) or r
135 elif cmd.startswith('python:'):
141 elif cmd.startswith('python:'):
136 if cmd.count(':') >= 2:
142 if cmd.count(':') >= 2:
137 path, cmd = cmd[7:].rsplit(':', 1)
143 path, cmd = cmd[7:].rsplit(':', 1)
138 path = util.expandpath(path)
144 path = util.expandpath(path)
139 if repo:
145 if repo:
140 path = os.path.join(repo.root, path)
146 path = os.path.join(repo.root, path)
141 mod = extensions.loadpath(path, 'hghook.%s' % hname)
147 mod = extensions.loadpath(path, 'hghook.%s' % hname)
142 hookfn = getattr(mod, cmd)
148 hookfn = getattr(mod, cmd)
143 else:
149 else:
144 hookfn = cmd[7:].strip()
150 hookfn = cmd[7:].strip()
145 r = _pythonhook(ui, repo, name, hname, hookfn, args, throw) or r
151 r = _pythonhook(ui, repo, name, hname, hookfn, args, throw) or r
146 else:
152 else:
147 r = _exthook(ui, repo, hname, cmd, args, throw) or r
153 r = _exthook(ui, repo, hname, cmd, args, throw) or r
148 finally:
154 finally:
149 if _redirect and oldstdout >= 0:
155 if _redirect and oldstdout >= 0:
150 os.dup2(oldstdout, stdoutno)
156 os.dup2(oldstdout, stdoutno)
151 os.close(oldstdout)
157 os.close(oldstdout)
152
158
153 return r
159 return r
@@ -1,483 +1,483
1 $ cp "$TESTDIR"/printenv.py .
1 $ cp "$TESTDIR"/printenv.py .
2
2
3 commit hooks can see env vars
3 commit hooks can see env vars
4
4
5 $ hg init a
5 $ hg init a
6 $ cd a
6 $ cd a
7 $ echo "[hooks]" > .hg/hgrc
7 $ echo "[hooks]" > .hg/hgrc
8 $ echo 'commit = unset HG_LOCAL HG_TAG; python ../printenv.py commit' >> .hg/hgrc
8 $ echo 'commit = unset HG_LOCAL HG_TAG; python ../printenv.py commit' >> .hg/hgrc
9 $ echo 'commit.b = unset HG_LOCAL HG_TAG; python ../printenv.py commit.b' >> .hg/hgrc
9 $ echo 'commit.b = unset HG_LOCAL HG_TAG; python ../printenv.py commit.b' >> .hg/hgrc
10 $ echo 'precommit = unset HG_LOCAL HG_NODE HG_TAG; python ../printenv.py precommit' >> .hg/hgrc
10 $ echo 'precommit = unset HG_LOCAL HG_NODE HG_TAG; python ../printenv.py precommit' >> .hg/hgrc
11 $ echo 'pretxncommit = unset HG_LOCAL HG_TAG; python ../printenv.py pretxncommit' >> .hg/hgrc
11 $ echo 'pretxncommit = unset HG_LOCAL HG_TAG; python ../printenv.py pretxncommit' >> .hg/hgrc
12 $ echo 'pretxncommit.tip = hg -q tip' >> .hg/hgrc
12 $ echo 'pretxncommit.tip = hg -q tip' >> .hg/hgrc
13 $ echo 'pre-identify = python ../printenv.py pre-identify 1' >> .hg/hgrc
13 $ echo 'pre-identify = python ../printenv.py pre-identify 1' >> .hg/hgrc
14 $ echo 'pre-cat = python ../printenv.py pre-cat' >> .hg/hgrc
14 $ echo 'pre-cat = python ../printenv.py pre-cat' >> .hg/hgrc
15 $ echo 'post-cat = python ../printenv.py post-cat' >> .hg/hgrc
15 $ echo 'post-cat = python ../printenv.py post-cat' >> .hg/hgrc
16 $ echo a > a
16 $ echo a > a
17 $ hg add a
17 $ hg add a
18 $ hg commit -m a
18 $ hg commit -m a
19 precommit hook: HG_PARENT1=0000000000000000000000000000000000000000
19 precommit hook: HG_PARENT1=0000000000000000000000000000000000000000
20 pretxncommit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000 HG_PENDING=$TESTTMP/a
20 pretxncommit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000 HG_PENDING=$TESTTMP/a
21 0:cb9a9f314b8b
21 0:cb9a9f314b8b
22 commit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
22 commit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
23 commit.b hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
23 commit.b hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
24
24
25 $ hg clone . ../b
25 $ hg clone . ../b
26 updating to branch default
26 updating to branch default
27 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
27 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
28 $ cd ../b
28 $ cd ../b
29
29
30 changegroup hooks can see env vars
30 changegroup hooks can see env vars
31
31
32 $ echo '[hooks]' > .hg/hgrc
32 $ echo '[hooks]' > .hg/hgrc
33 $ echo 'prechangegroup = python ../printenv.py prechangegroup' >> .hg/hgrc
33 $ echo 'prechangegroup = python ../printenv.py prechangegroup' >> .hg/hgrc
34 $ echo 'changegroup = python ../printenv.py changegroup' >> .hg/hgrc
34 $ echo 'changegroup = python ../printenv.py changegroup' >> .hg/hgrc
35 $ echo 'incoming = python ../printenv.py incoming' >> .hg/hgrc
35 $ echo 'incoming = python ../printenv.py incoming' >> .hg/hgrc
36
36
37 pretxncommit and commit hooks can see both parents of merge
37 pretxncommit and commit hooks can see both parents of merge
38
38
39 $ cd ../a
39 $ cd ../a
40 $ echo b >> a
40 $ echo b >> a
41 $ hg commit -m a1 -d "1 0"
41 $ hg commit -m a1 -d "1 0"
42 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
42 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
43 pretxncommit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
43 pretxncommit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
44 1:ab228980c14d
44 1:ab228980c14d
45 commit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
45 commit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
46 commit.b hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
46 commit.b hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
47 $ hg update -C 0
47 $ hg update -C 0
48 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
48 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
49 $ echo b > b
49 $ echo b > b
50 $ hg add b
50 $ hg add b
51 $ hg commit -m b -d '1 0'
51 $ hg commit -m b -d '1 0'
52 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
52 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
53 pretxncommit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
53 pretxncommit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
54 2:ee9deb46ab31
54 2:ee9deb46ab31
55 commit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
55 commit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
56 commit.b hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
56 commit.b hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
57 created new head
57 created new head
58 $ hg merge 1
58 $ hg merge 1
59 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
59 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
60 (branch merge, don't forget to commit)
60 (branch merge, don't forget to commit)
61 $ hg commit -m merge -d '2 0'
61 $ hg commit -m merge -d '2 0'
62 precommit hook: HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
62 precommit hook: HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
63 pretxncommit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd HG_PENDING=$TESTTMP/a
63 pretxncommit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd HG_PENDING=$TESTTMP/a
64 3:07f3376c1e65
64 3:07f3376c1e65
65 commit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
65 commit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
66 commit.b hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
66 commit.b hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
67
67
68 test generic hooks
68 test generic hooks
69
69
70 $ hg id
70 $ hg id
71 pre-identify hook: HG_ARGS=id HG_OPTS={'tags': None, 'rev': '', 'num': None, 'branch': None, 'id': None} HG_PATS=[]
71 pre-identify hook: HG_ARGS=id HG_OPTS={'branch': None, 'id': None, 'num': None, 'rev': '', 'tags': None} HG_PATS=[]
72 warning: pre-identify hook exited with status 1
72 warning: pre-identify hook exited with status 1
73 [1]
73 [1]
74 $ hg cat b
74 $ hg cat b
75 pre-cat hook: HG_ARGS=cat b HG_OPTS={'rev': '', 'decode': None, 'exclude': [], 'output': '', 'include': []} HG_PATS=['b']
75 pre-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b']
76 b
76 b
77 post-cat hook: HG_ARGS=cat b HG_OPTS={'rev': '', 'decode': None, 'exclude': [], 'output': '', 'include': []} HG_PATS=['b'] HG_RESULT=0
77 post-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b'] HG_RESULT=0
78
78
79 $ cd ../b
79 $ cd ../b
80 $ hg pull ../a
80 $ hg pull ../a
81 prechangegroup hook: HG_SOURCE=pull HG_URL=file:
81 prechangegroup hook: HG_SOURCE=pull HG_URL=file:
82 changegroup hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:
82 changegroup hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:
83 incoming hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:
83 incoming hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:
84 incoming hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_SOURCE=pull HG_URL=file:
84 incoming hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_SOURCE=pull HG_URL=file:
85 incoming hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_SOURCE=pull HG_URL=file:
85 incoming hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_SOURCE=pull HG_URL=file:
86 pulling from ../a
86 pulling from ../a
87 searching for changes
87 searching for changes
88 adding changesets
88 adding changesets
89 adding manifests
89 adding manifests
90 adding file changes
90 adding file changes
91 added 3 changesets with 2 changes to 2 files
91 added 3 changesets with 2 changes to 2 files
92 (run 'hg update' to get a working copy)
92 (run 'hg update' to get a working copy)
93
93
94 tag hooks can see env vars
94 tag hooks can see env vars
95
95
96 $ cd ../a
96 $ cd ../a
97 $ echo 'pretag = python ../printenv.py pretag' >> .hg/hgrc
97 $ echo 'pretag = python ../printenv.py pretag' >> .hg/hgrc
98 $ echo 'tag = unset HG_PARENT1 HG_PARENT2; python ../printenv.py tag' >> .hg/hgrc
98 $ echo 'tag = unset HG_PARENT1 HG_PARENT2; python ../printenv.py tag' >> .hg/hgrc
99 $ hg tag -d '3 0' a
99 $ hg tag -d '3 0' a
100 pretag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
100 pretag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
101 precommit hook: HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
101 precommit hook: HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
102 pretxncommit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PENDING=$TESTTMP/a
102 pretxncommit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PENDING=$TESTTMP/a
103 4:539e4b31b6dc
103 4:539e4b31b6dc
104 commit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
104 commit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
105 commit.b hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
105 commit.b hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
106 tag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
106 tag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
107 $ hg tag -l la
107 $ hg tag -l la
108 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
108 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
109 tag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
109 tag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
110
110
111 pretag hook can forbid tagging
111 pretag hook can forbid tagging
112
112
113 $ echo 'pretag.forbid = python ../printenv.py pretag.forbid 1' >> .hg/hgrc
113 $ echo 'pretag.forbid = python ../printenv.py pretag.forbid 1' >> .hg/hgrc
114 $ hg tag -d '4 0' fa
114 $ hg tag -d '4 0' fa
115 pretag hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
115 pretag hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
116 pretag.forbid hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
116 pretag.forbid hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
117 abort: pretag.forbid hook exited with status 1
117 abort: pretag.forbid hook exited with status 1
118 [255]
118 [255]
119 $ hg tag -l fla
119 $ hg tag -l fla
120 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
120 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
121 pretag.forbid hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
121 pretag.forbid hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
122 abort: pretag.forbid hook exited with status 1
122 abort: pretag.forbid hook exited with status 1
123 [255]
123 [255]
124
124
125 pretxncommit hook can see changeset, can roll back txn, changeset no
125 pretxncommit hook can see changeset, can roll back txn, changeset no
126 more there after
126 more there after
127
127
128 $ echo 'pretxncommit.forbid0 = hg tip -q' >> .hg/hgrc
128 $ echo 'pretxncommit.forbid0 = hg tip -q' >> .hg/hgrc
129 $ echo 'pretxncommit.forbid1 = python ../printenv.py pretxncommit.forbid 1' >> .hg/hgrc
129 $ echo 'pretxncommit.forbid1 = python ../printenv.py pretxncommit.forbid 1' >> .hg/hgrc
130 $ echo z > z
130 $ echo z > z
131 $ hg add z
131 $ hg add z
132 $ hg -q tip
132 $ hg -q tip
133 4:539e4b31b6dc
133 4:539e4b31b6dc
134 $ hg commit -m 'fail' -d '4 0'
134 $ hg commit -m 'fail' -d '4 0'
135 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
135 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
136 pretxncommit hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
136 pretxncommit hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
137 5:6f611f8018c1
137 5:6f611f8018c1
138 5:6f611f8018c1
138 5:6f611f8018c1
139 pretxncommit.forbid hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
139 pretxncommit.forbid hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
140 transaction abort!
140 transaction abort!
141 rollback completed
141 rollback completed
142 abort: pretxncommit.forbid1 hook exited with status 1
142 abort: pretxncommit.forbid1 hook exited with status 1
143 [255]
143 [255]
144 $ hg -q tip
144 $ hg -q tip
145 4:539e4b31b6dc
145 4:539e4b31b6dc
146
146
147 precommit hook can prevent commit
147 precommit hook can prevent commit
148
148
149 $ echo 'precommit.forbid = python ../printenv.py precommit.forbid 1' >> .hg/hgrc
149 $ echo 'precommit.forbid = python ../printenv.py precommit.forbid 1' >> .hg/hgrc
150 $ hg commit -m 'fail' -d '4 0'
150 $ hg commit -m 'fail' -d '4 0'
151 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
151 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
152 precommit.forbid hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
152 precommit.forbid hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
153 abort: precommit.forbid hook exited with status 1
153 abort: precommit.forbid hook exited with status 1
154 [255]
154 [255]
155 $ hg -q tip
155 $ hg -q tip
156 4:539e4b31b6dc
156 4:539e4b31b6dc
157
157
158 preupdate hook can prevent update
158 preupdate hook can prevent update
159
159
160 $ echo 'preupdate = python ../printenv.py preupdate' >> .hg/hgrc
160 $ echo 'preupdate = python ../printenv.py preupdate' >> .hg/hgrc
161 $ hg update 1
161 $ hg update 1
162 preupdate hook: HG_PARENT1=ab228980c14d
162 preupdate hook: HG_PARENT1=ab228980c14d
163 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
163 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
164
164
165 update hook
165 update hook
166
166
167 $ echo 'update = python ../printenv.py update' >> .hg/hgrc
167 $ echo 'update = python ../printenv.py update' >> .hg/hgrc
168 $ hg update
168 $ hg update
169 preupdate hook: HG_PARENT1=539e4b31b6dc
169 preupdate hook: HG_PARENT1=539e4b31b6dc
170 update hook: HG_ERROR=0 HG_PARENT1=539e4b31b6dc
170 update hook: HG_ERROR=0 HG_PARENT1=539e4b31b6dc
171 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
171 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
172
172
173 prechangegroup hook can prevent incoming changes
173 prechangegroup hook can prevent incoming changes
174
174
175 $ cd ../b
175 $ cd ../b
176 $ hg -q tip
176 $ hg -q tip
177 3:07f3376c1e65
177 3:07f3376c1e65
178 $ echo '[hooks]' > .hg/hgrc
178 $ echo '[hooks]' > .hg/hgrc
179 $ echo 'prechangegroup.forbid = python ../printenv.py prechangegroup.forbid 1' >> .hg/hgrc
179 $ echo 'prechangegroup.forbid = python ../printenv.py prechangegroup.forbid 1' >> .hg/hgrc
180 $ hg pull ../a
180 $ hg pull ../a
181 prechangegroup.forbid hook: HG_SOURCE=pull HG_URL=file:
181 prechangegroup.forbid hook: HG_SOURCE=pull HG_URL=file:
182 pulling from ../a
182 pulling from ../a
183 searching for changes
183 searching for changes
184 abort: prechangegroup.forbid hook exited with status 1
184 abort: prechangegroup.forbid hook exited with status 1
185 [255]
185 [255]
186
186
187 pretxnchangegroup hook can see incoming changes, can roll back txn,
187 pretxnchangegroup hook can see incoming changes, can roll back txn,
188 incoming changes no longer there after
188 incoming changes no longer there after
189
189
190 $ echo '[hooks]' > .hg/hgrc
190 $ echo '[hooks]' > .hg/hgrc
191 $ echo 'pretxnchangegroup.forbid0 = hg tip -q' >> .hg/hgrc
191 $ echo 'pretxnchangegroup.forbid0 = hg tip -q' >> .hg/hgrc
192 $ echo 'pretxnchangegroup.forbid1 = python ../printenv.py pretxnchangegroup.forbid 1' >> .hg/hgrc
192 $ echo 'pretxnchangegroup.forbid1 = python ../printenv.py pretxnchangegroup.forbid 1' >> .hg/hgrc
193 $ hg pull ../a
193 $ hg pull ../a
194 4:539e4b31b6dc
194 4:539e4b31b6dc
195 pretxnchangegroup.forbid hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/b HG_SOURCE=pull HG_URL=file:
195 pretxnchangegroup.forbid hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/b HG_SOURCE=pull HG_URL=file:
196 pulling from ../a
196 pulling from ../a
197 searching for changes
197 searching for changes
198 adding changesets
198 adding changesets
199 adding manifests
199 adding manifests
200 adding file changes
200 adding file changes
201 added 1 changesets with 1 changes to 1 files
201 added 1 changesets with 1 changes to 1 files
202 transaction abort!
202 transaction abort!
203 rollback completed
203 rollback completed
204 abort: pretxnchangegroup.forbid1 hook exited with status 1
204 abort: pretxnchangegroup.forbid1 hook exited with status 1
205 [255]
205 [255]
206 $ hg -q tip
206 $ hg -q tip
207 3:07f3376c1e65
207 3:07f3376c1e65
208
208
209 outgoing hooks can see env vars
209 outgoing hooks can see env vars
210
210
211 $ rm .hg/hgrc
211 $ rm .hg/hgrc
212 $ echo '[hooks]' > ../a/.hg/hgrc
212 $ echo '[hooks]' > ../a/.hg/hgrc
213 $ echo 'preoutgoing = python ../printenv.py preoutgoing' >> ../a/.hg/hgrc
213 $ echo 'preoutgoing = python ../printenv.py preoutgoing' >> ../a/.hg/hgrc
214 $ echo 'outgoing = python ../printenv.py outgoing' >> ../a/.hg/hgrc
214 $ echo 'outgoing = python ../printenv.py outgoing' >> ../a/.hg/hgrc
215 $ hg pull ../a
215 $ hg pull ../a
216 preoutgoing hook: HG_SOURCE=pull
216 preoutgoing hook: HG_SOURCE=pull
217 outgoing hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_SOURCE=pull
217 outgoing hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_SOURCE=pull
218 pulling from ../a
218 pulling from ../a
219 searching for changes
219 searching for changes
220 adding changesets
220 adding changesets
221 adding manifests
221 adding manifests
222 adding file changes
222 adding file changes
223 added 1 changesets with 1 changes to 1 files
223 added 1 changesets with 1 changes to 1 files
224 (run 'hg update' to get a working copy)
224 (run 'hg update' to get a working copy)
225 $ hg rollback
225 $ hg rollback
226 rolling back to revision 3 (undo pull)
226 rolling back to revision 3 (undo pull)
227
227
228 preoutgoing hook can prevent outgoing changes
228 preoutgoing hook can prevent outgoing changes
229
229
230 $ echo 'preoutgoing.forbid = python ../printenv.py preoutgoing.forbid 1' >> ../a/.hg/hgrc
230 $ echo 'preoutgoing.forbid = python ../printenv.py preoutgoing.forbid 1' >> ../a/.hg/hgrc
231 $ hg pull ../a
231 $ hg pull ../a
232 preoutgoing hook: HG_SOURCE=pull
232 preoutgoing hook: HG_SOURCE=pull
233 preoutgoing.forbid hook: HG_SOURCE=pull
233 preoutgoing.forbid hook: HG_SOURCE=pull
234 pulling from ../a
234 pulling from ../a
235 searching for changes
235 searching for changes
236 abort: preoutgoing.forbid hook exited with status 1
236 abort: preoutgoing.forbid hook exited with status 1
237 [255]
237 [255]
238
238
239 outgoing hooks work for local clones
239 outgoing hooks work for local clones
240
240
241 $ cd ..
241 $ cd ..
242 $ echo '[hooks]' > a/.hg/hgrc
242 $ echo '[hooks]' > a/.hg/hgrc
243 $ echo 'preoutgoing = python ../printenv.py preoutgoing' >> a/.hg/hgrc
243 $ echo 'preoutgoing = python ../printenv.py preoutgoing' >> a/.hg/hgrc
244 $ echo 'outgoing = python ../printenv.py outgoing' >> a/.hg/hgrc
244 $ echo 'outgoing = python ../printenv.py outgoing' >> a/.hg/hgrc
245 $ hg clone a c
245 $ hg clone a c
246 preoutgoing hook: HG_SOURCE=clone
246 preoutgoing hook: HG_SOURCE=clone
247 outgoing hook: HG_NODE=0000000000000000000000000000000000000000 HG_SOURCE=clone
247 outgoing hook: HG_NODE=0000000000000000000000000000000000000000 HG_SOURCE=clone
248 updating to branch default
248 updating to branch default
249 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
249 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
250 $ rm -rf c
250 $ rm -rf c
251
251
252 preoutgoing hook can prevent outgoing changes for local clones
252 preoutgoing hook can prevent outgoing changes for local clones
253
253
254 $ echo 'preoutgoing.forbid = python ../printenv.py preoutgoing.forbid 1' >> a/.hg/hgrc
254 $ echo 'preoutgoing.forbid = python ../printenv.py preoutgoing.forbid 1' >> a/.hg/hgrc
255 $ hg clone a zzz
255 $ hg clone a zzz
256 preoutgoing hook: HG_SOURCE=clone
256 preoutgoing hook: HG_SOURCE=clone
257 preoutgoing.forbid hook: HG_SOURCE=clone
257 preoutgoing.forbid hook: HG_SOURCE=clone
258 abort: preoutgoing.forbid hook exited with status 1
258 abort: preoutgoing.forbid hook exited with status 1
259 [255]
259 [255]
260 $ cd b
260 $ cd b
261
261
262 $ cat > hooktests.py <<EOF
262 $ cat > hooktests.py <<EOF
263 > from mercurial import util
263 > from mercurial import util
264 >
264 >
265 > uncallable = 0
265 > uncallable = 0
266 >
266 >
267 > def printargs(args):
267 > def printargs(args):
268 > args.pop('ui', None)
268 > args.pop('ui', None)
269 > args.pop('repo', None)
269 > args.pop('repo', None)
270 > a = list(args.items())
270 > a = list(args.items())
271 > a.sort()
271 > a.sort()
272 > print 'hook args:'
272 > print 'hook args:'
273 > for k, v in a:
273 > for k, v in a:
274 > print ' ', k, v
274 > print ' ', k, v
275 >
275 >
276 > def passhook(**args):
276 > def passhook(**args):
277 > printargs(args)
277 > printargs(args)
278 >
278 >
279 > def failhook(**args):
279 > def failhook(**args):
280 > printargs(args)
280 > printargs(args)
281 > return True
281 > return True
282 >
282 >
283 > class LocalException(Exception):
283 > class LocalException(Exception):
284 > pass
284 > pass
285 >
285 >
286 > def raisehook(**args):
286 > def raisehook(**args):
287 > raise LocalException('exception from hook')
287 > raise LocalException('exception from hook')
288 >
288 >
289 > def aborthook(**args):
289 > def aborthook(**args):
290 > raise util.Abort('raise abort from hook')
290 > raise util.Abort('raise abort from hook')
291 >
291 >
292 > def brokenhook(**args):
292 > def brokenhook(**args):
293 > return 1 + {}
293 > return 1 + {}
294 >
294 >
295 > class container:
295 > class container:
296 > unreachable = 1
296 > unreachable = 1
297 > EOF
297 > EOF
298
298
299 test python hooks
299 test python hooks
300
300
301 $ PYTHONPATH="`pwd`:$PYTHONPATH"
301 $ PYTHONPATH="`pwd`:$PYTHONPATH"
302 $ export PYTHONPATH
302 $ export PYTHONPATH
303
303
304 $ echo '[hooks]' > ../a/.hg/hgrc
304 $ echo '[hooks]' > ../a/.hg/hgrc
305 $ echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
305 $ echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
306 $ hg pull ../a 2>&1 | grep 'raised an exception'
306 $ hg pull ../a 2>&1 | grep 'raised an exception'
307 error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
307 error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
308
308
309 $ echo '[hooks]' > ../a/.hg/hgrc
309 $ echo '[hooks]' > ../a/.hg/hgrc
310 $ echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
310 $ echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
311 $ hg pull ../a 2>&1 | grep 'raised an exception'
311 $ hg pull ../a 2>&1 | grep 'raised an exception'
312 error: preoutgoing.raise hook raised an exception: exception from hook
312 error: preoutgoing.raise hook raised an exception: exception from hook
313
313
314 $ echo '[hooks]' > ../a/.hg/hgrc
314 $ echo '[hooks]' > ../a/.hg/hgrc
315 $ echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
315 $ echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
316 $ hg pull ../a
316 $ hg pull ../a
317 pulling from ../a
317 pulling from ../a
318 searching for changes
318 searching for changes
319 error: preoutgoing.abort hook failed: raise abort from hook
319 error: preoutgoing.abort hook failed: raise abort from hook
320 abort: raise abort from hook
320 abort: raise abort from hook
321 [255]
321 [255]
322
322
323 $ echo '[hooks]' > ../a/.hg/hgrc
323 $ echo '[hooks]' > ../a/.hg/hgrc
324 $ echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
324 $ echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
325 $ hg pull ../a
325 $ hg pull ../a
326 pulling from ../a
326 pulling from ../a
327 searching for changes
327 searching for changes
328 hook args:
328 hook args:
329 hooktype preoutgoing
329 hooktype preoutgoing
330 source pull
330 source pull
331 abort: preoutgoing.fail hook failed
331 abort: preoutgoing.fail hook failed
332 [255]
332 [255]
333
333
334 $ echo '[hooks]' > ../a/.hg/hgrc
334 $ echo '[hooks]' > ../a/.hg/hgrc
335 $ echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
335 $ echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
336 $ hg pull ../a
336 $ hg pull ../a
337 pulling from ../a
337 pulling from ../a
338 searching for changes
338 searching for changes
339 abort: preoutgoing.uncallable hook is invalid ("hooktests.uncallable" is not callable)
339 abort: preoutgoing.uncallable hook is invalid ("hooktests.uncallable" is not callable)
340 [255]
340 [255]
341
341
342 $ echo '[hooks]' > ../a/.hg/hgrc
342 $ echo '[hooks]' > ../a/.hg/hgrc
343 $ echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
343 $ echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
344 $ hg pull ../a
344 $ hg pull ../a
345 pulling from ../a
345 pulling from ../a
346 searching for changes
346 searching for changes
347 abort: preoutgoing.nohook hook is invalid ("hooktests.nohook" is not defined)
347 abort: preoutgoing.nohook hook is invalid ("hooktests.nohook" is not defined)
348 [255]
348 [255]
349
349
350 $ echo '[hooks]' > ../a/.hg/hgrc
350 $ echo '[hooks]' > ../a/.hg/hgrc
351 $ echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
351 $ echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
352 $ hg pull ../a
352 $ hg pull ../a
353 pulling from ../a
353 pulling from ../a
354 searching for changes
354 searching for changes
355 abort: preoutgoing.nomodule hook is invalid ("nomodule" not in a module)
355 abort: preoutgoing.nomodule hook is invalid ("nomodule" not in a module)
356 [255]
356 [255]
357
357
358 $ echo '[hooks]' > ../a/.hg/hgrc
358 $ echo '[hooks]' > ../a/.hg/hgrc
359 $ echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
359 $ echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
360 $ hg pull ../a
360 $ hg pull ../a
361 pulling from ../a
361 pulling from ../a
362 searching for changes
362 searching for changes
363 abort: preoutgoing.badmodule hook is invalid (import of "nomodule" failed)
363 abort: preoutgoing.badmodule hook is invalid (import of "nomodule" failed)
364 [255]
364 [255]
365
365
366 $ echo '[hooks]' > ../a/.hg/hgrc
366 $ echo '[hooks]' > ../a/.hg/hgrc
367 $ echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
367 $ echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
368 $ hg pull ../a
368 $ hg pull ../a
369 pulling from ../a
369 pulling from ../a
370 searching for changes
370 searching for changes
371 abort: preoutgoing.unreachable hook is invalid (import of "hooktests.container" failed)
371 abort: preoutgoing.unreachable hook is invalid (import of "hooktests.container" failed)
372 [255]
372 [255]
373
373
374 $ echo '[hooks]' > ../a/.hg/hgrc
374 $ echo '[hooks]' > ../a/.hg/hgrc
375 $ echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
375 $ echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
376 $ hg pull ../a
376 $ hg pull ../a
377 pulling from ../a
377 pulling from ../a
378 searching for changes
378 searching for changes
379 hook args:
379 hook args:
380 hooktype preoutgoing
380 hooktype preoutgoing
381 source pull
381 source pull
382 adding changesets
382 adding changesets
383 adding manifests
383 adding manifests
384 adding file changes
384 adding file changes
385 added 1 changesets with 1 changes to 1 files
385 added 1 changesets with 1 changes to 1 files
386 (run 'hg update' to get a working copy)
386 (run 'hg update' to get a working copy)
387
387
388 make sure --traceback works
388 make sure --traceback works
389
389
390 $ echo '[hooks]' > .hg/hgrc
390 $ echo '[hooks]' > .hg/hgrc
391 $ echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
391 $ echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
392
392
393 $ echo aa > a
393 $ echo aa > a
394 $ hg --traceback commit -d '0 0' -ma 2>&1 | grep '^Traceback'
394 $ hg --traceback commit -d '0 0' -ma 2>&1 | grep '^Traceback'
395 Traceback (most recent call last):
395 Traceback (most recent call last):
396
396
397 $ cd ..
397 $ cd ..
398 $ hg init c
398 $ hg init c
399 $ cd c
399 $ cd c
400
400
401 $ cat > hookext.py <<EOF
401 $ cat > hookext.py <<EOF
402 > def autohook(**args):
402 > def autohook(**args):
403 > print "Automatically installed hook"
403 > print "Automatically installed hook"
404 >
404 >
405 > def reposetup(ui, repo):
405 > def reposetup(ui, repo):
406 > repo.ui.setconfig("hooks", "commit.auto", autohook)
406 > repo.ui.setconfig("hooks", "commit.auto", autohook)
407 > EOF
407 > EOF
408 $ echo '[extensions]' >> .hg/hgrc
408 $ echo '[extensions]' >> .hg/hgrc
409 $ echo 'hookext = hookext.py' >> .hg/hgrc
409 $ echo 'hookext = hookext.py' >> .hg/hgrc
410
410
411 $ touch foo
411 $ touch foo
412 $ hg add foo
412 $ hg add foo
413 $ hg ci -d '0 0' -m 'add foo'
413 $ hg ci -d '0 0' -m 'add foo'
414 Automatically installed hook
414 Automatically installed hook
415 $ echo >> foo
415 $ echo >> foo
416 $ hg ci --debug -d '0 0' -m 'change foo'
416 $ hg ci --debug -d '0 0' -m 'change foo'
417 foo
417 foo
418 calling hook commit.auto: <function autohook at *> (glob)
418 calling hook commit.auto: <function autohook at *> (glob)
419 Automatically installed hook
419 Automatically installed hook
420 committed changeset 1:52998019f6252a2b893452765fcb0a47351a5708
420 committed changeset 1:52998019f6252a2b893452765fcb0a47351a5708
421
421
422 $ hg showconfig hooks
422 $ hg showconfig hooks
423 hooks.commit.auto=<function autohook at *> (glob)
423 hooks.commit.auto=<function autohook at *> (glob)
424
424
425 test python hook configured with python:[file]:[hook] syntax
425 test python hook configured with python:[file]:[hook] syntax
426
426
427 $ cd ..
427 $ cd ..
428 $ mkdir d
428 $ mkdir d
429 $ cd d
429 $ cd d
430 $ hg init repo
430 $ hg init repo
431 $ mkdir hooks
431 $ mkdir hooks
432
432
433 $ cd hooks
433 $ cd hooks
434 $ cat > testhooks.py <<EOF
434 $ cat > testhooks.py <<EOF
435 > def testhook(**args):
435 > def testhook(**args):
436 > print 'hook works'
436 > print 'hook works'
437 > EOF
437 > EOF
438 $ echo '[hooks]' > ../repo/.hg/hgrc
438 $ echo '[hooks]' > ../repo/.hg/hgrc
439 $ echo "pre-commit.test = python:`pwd`/testhooks.py:testhook" >> ../repo/.hg/hgrc
439 $ echo "pre-commit.test = python:`pwd`/testhooks.py:testhook" >> ../repo/.hg/hgrc
440
440
441 $ cd ../repo
441 $ cd ../repo
442 $ hg commit -d '0 0'
442 $ hg commit -d '0 0'
443 hook works
443 hook works
444 nothing changed
444 nothing changed
445 [1]
445 [1]
446
446
447 $ cd ../../b
447 $ cd ../../b
448
448
449 make sure --traceback works on hook import failure
449 make sure --traceback works on hook import failure
450
450
451 $ cat > importfail.py <<EOF
451 $ cat > importfail.py <<EOF
452 > import somebogusmodule
452 > import somebogusmodule
453 > # dereference something in the module to force demandimport to load it
453 > # dereference something in the module to force demandimport to load it
454 > somebogusmodule.whatever
454 > somebogusmodule.whatever
455 > EOF
455 > EOF
456
456
457 $ echo '[hooks]' > .hg/hgrc
457 $ echo '[hooks]' > .hg/hgrc
458 $ echo 'precommit.importfail = python:importfail.whatever' >> .hg/hgrc
458 $ echo 'precommit.importfail = python:importfail.whatever' >> .hg/hgrc
459
459
460 $ echo a >> a
460 $ echo a >> a
461 $ hg --traceback commit -ma 2>&1 | egrep '^(exception|Traceback|ImportError)'
461 $ hg --traceback commit -ma 2>&1 | egrep '^(exception|Traceback|ImportError)'
462 exception from first failed import attempt:
462 exception from first failed import attempt:
463 Traceback (most recent call last):
463 Traceback (most recent call last):
464 ImportError: No module named somebogusmodule
464 ImportError: No module named somebogusmodule
465 exception from second failed import attempt:
465 exception from second failed import attempt:
466 Traceback (most recent call last):
466 Traceback (most recent call last):
467 ImportError: No module named hgext_importfail
467 ImportError: No module named hgext_importfail
468 Traceback (most recent call last):
468 Traceback (most recent call last):
469
469
470 Issue1827: Hooks Update & Commit not completely post operation
470 Issue1827: Hooks Update & Commit not completely post operation
471
471
472 commit and update hooks should run after command completion
472 commit and update hooks should run after command completion
473
473
474 $ echo '[hooks]' > .hg/hgrc
474 $ echo '[hooks]' > .hg/hgrc
475 $ echo 'commit = hg id' >> .hg/hgrc
475 $ echo 'commit = hg id' >> .hg/hgrc
476 $ echo 'update = hg id' >> .hg/hgrc
476 $ echo 'update = hg id' >> .hg/hgrc
477 $ echo bb > a
477 $ echo bb > a
478 $ hg ci -ma
478 $ hg ci -ma
479 223eafe2750c tip
479 223eafe2750c tip
480 $ hg up 0
480 $ hg up 0
481 cb9a9f314b8b
481 cb9a9f314b8b
482 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
482 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
483
483
General Comments 0
You need to be logged in to leave comments. Login now