##// END OF EJS Templates
changelog: ensure that nodecache is valid (issue3428)...
Bryan O'Sullivan -
r16619:bc84a1ae stable
parent child Browse files
Show More
@@ -1,255 +1,256 b''
1 # changelog.py - changelog class for mercurial
1 # changelog.py - changelog class for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-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 node import bin, hex, nullid
8 from node import bin, hex, nullid
9 from i18n import _
9 from i18n import _
10 import util, error, revlog, encoding
10 import util, error, revlog, encoding
11
11
12 _defaultextra = {'branch': 'default'}
12 _defaultextra = {'branch': 'default'}
13
13
14 def _string_escape(text):
14 def _string_escape(text):
15 """
15 """
16 >>> d = {'nl': chr(10), 'bs': chr(92), 'cr': chr(13), 'nul': chr(0)}
16 >>> d = {'nl': chr(10), 'bs': chr(92), 'cr': chr(13), 'nul': chr(0)}
17 >>> s = "ab%(nl)scd%(bs)s%(bs)sn%(nul)sab%(cr)scd%(bs)s%(nl)s" % d
17 >>> s = "ab%(nl)scd%(bs)s%(bs)sn%(nul)sab%(cr)scd%(bs)s%(nl)s" % d
18 >>> s
18 >>> s
19 'ab\\ncd\\\\\\\\n\\x00ab\\rcd\\\\\\n'
19 'ab\\ncd\\\\\\\\n\\x00ab\\rcd\\\\\\n'
20 >>> res = _string_escape(s)
20 >>> res = _string_escape(s)
21 >>> s == res.decode('string_escape')
21 >>> s == res.decode('string_escape')
22 True
22 True
23 """
23 """
24 # subset of the string_escape codec
24 # subset of the string_escape codec
25 text = text.replace('\\', '\\\\').replace('\n', '\\n').replace('\r', '\\r')
25 text = text.replace('\\', '\\\\').replace('\n', '\\n').replace('\r', '\\r')
26 return text.replace('\0', '\\0')
26 return text.replace('\0', '\\0')
27
27
28 def decodeextra(text):
28 def decodeextra(text):
29 """
29 """
30 >>> decodeextra(encodeextra({'foo': 'bar', 'baz': chr(0) + '2'}))
30 >>> decodeextra(encodeextra({'foo': 'bar', 'baz': chr(0) + '2'}))
31 {'foo': 'bar', 'baz': '\\x002', 'branch': 'default'}
31 {'foo': 'bar', 'baz': '\\x002', 'branch': 'default'}
32 >>> decodeextra(encodeextra({'foo': 'bar', 'baz': chr(92) + chr(0) + '2'}))
32 >>> decodeextra(encodeextra({'foo': 'bar', 'baz': chr(92) + chr(0) + '2'}))
33 {'foo': 'bar', 'baz': '\\\\\\x002', 'branch': 'default'}
33 {'foo': 'bar', 'baz': '\\\\\\x002', 'branch': 'default'}
34 """
34 """
35 extra = _defaultextra.copy()
35 extra = _defaultextra.copy()
36 for l in text.split('\0'):
36 for l in text.split('\0'):
37 if l:
37 if l:
38 if '\\0' in l:
38 if '\\0' in l:
39 # fix up \0 without getting into trouble with \\0
39 # fix up \0 without getting into trouble with \\0
40 l = l.replace('\\\\', '\\\\\n')
40 l = l.replace('\\\\', '\\\\\n')
41 l = l.replace('\\0', '\0')
41 l = l.replace('\\0', '\0')
42 l = l.replace('\n', '')
42 l = l.replace('\n', '')
43 k, v = l.decode('string_escape').split(':', 1)
43 k, v = l.decode('string_escape').split(':', 1)
44 extra[k] = v
44 extra[k] = v
45 return extra
45 return extra
46
46
47 def encodeextra(d):
47 def encodeextra(d):
48 # keys must be sorted to produce a deterministic changelog entry
48 # keys must be sorted to produce a deterministic changelog entry
49 items = [_string_escape('%s:%s' % (k, d[k])) for k in sorted(d)]
49 items = [_string_escape('%s:%s' % (k, d[k])) for k in sorted(d)]
50 return "\0".join(items)
50 return "\0".join(items)
51
51
52 class appender(object):
52 class appender(object):
53 '''the changelog index must be updated last on disk, so we use this class
53 '''the changelog index must be updated last on disk, so we use this class
54 to delay writes to it'''
54 to delay writes to it'''
55 def __init__(self, fp, buf):
55 def __init__(self, fp, buf):
56 self.data = buf
56 self.data = buf
57 self.fp = fp
57 self.fp = fp
58 self.offset = fp.tell()
58 self.offset = fp.tell()
59 self.size = util.fstat(fp).st_size
59 self.size = util.fstat(fp).st_size
60
60
61 def end(self):
61 def end(self):
62 return self.size + len("".join(self.data))
62 return self.size + len("".join(self.data))
63 def tell(self):
63 def tell(self):
64 return self.offset
64 return self.offset
65 def flush(self):
65 def flush(self):
66 pass
66 pass
67 def close(self):
67 def close(self):
68 self.fp.close()
68 self.fp.close()
69
69
70 def seek(self, offset, whence=0):
70 def seek(self, offset, whence=0):
71 '''virtual file offset spans real file and data'''
71 '''virtual file offset spans real file and data'''
72 if whence == 0:
72 if whence == 0:
73 self.offset = offset
73 self.offset = offset
74 elif whence == 1:
74 elif whence == 1:
75 self.offset += offset
75 self.offset += offset
76 elif whence == 2:
76 elif whence == 2:
77 self.offset = self.end() + offset
77 self.offset = self.end() + offset
78 if self.offset < self.size:
78 if self.offset < self.size:
79 self.fp.seek(self.offset)
79 self.fp.seek(self.offset)
80
80
81 def read(self, count=-1):
81 def read(self, count=-1):
82 '''only trick here is reads that span real file and data'''
82 '''only trick here is reads that span real file and data'''
83 ret = ""
83 ret = ""
84 if self.offset < self.size:
84 if self.offset < self.size:
85 s = self.fp.read(count)
85 s = self.fp.read(count)
86 ret = s
86 ret = s
87 self.offset += len(s)
87 self.offset += len(s)
88 if count > 0:
88 if count > 0:
89 count -= len(s)
89 count -= len(s)
90 if count != 0:
90 if count != 0:
91 doff = self.offset - self.size
91 doff = self.offset - self.size
92 self.data.insert(0, "".join(self.data))
92 self.data.insert(0, "".join(self.data))
93 del self.data[1:]
93 del self.data[1:]
94 s = self.data[0][doff:doff + count]
94 s = self.data[0][doff:doff + count]
95 self.offset += len(s)
95 self.offset += len(s)
96 ret += s
96 ret += s
97 return ret
97 return ret
98
98
99 def write(self, s):
99 def write(self, s):
100 self.data.append(str(s))
100 self.data.append(str(s))
101 self.offset += len(s)
101 self.offset += len(s)
102
102
103 def delayopener(opener, target, divert, buf):
103 def delayopener(opener, target, divert, buf):
104 def o(name, mode='r'):
104 def o(name, mode='r'):
105 if name != target:
105 if name != target:
106 return opener(name, mode)
106 return opener(name, mode)
107 if divert:
107 if divert:
108 return opener(name + ".a", mode.replace('a', 'w'))
108 return opener(name + ".a", mode.replace('a', 'w'))
109 # otherwise, divert to memory
109 # otherwise, divert to memory
110 return appender(opener(name, mode), buf)
110 return appender(opener(name, mode), buf)
111 return o
111 return o
112
112
113 class changelog(revlog.revlog):
113 class changelog(revlog.revlog):
114 def __init__(self, opener):
114 def __init__(self, opener):
115 revlog.revlog.__init__(self, opener, "00changelog.i")
115 revlog.revlog.__init__(self, opener, "00changelog.i")
116 if self._initempty:
116 if self._initempty:
117 # changelogs don't benefit from generaldelta
117 # changelogs don't benefit from generaldelta
118 self.version &= ~revlog.REVLOGGENERALDELTA
118 self.version &= ~revlog.REVLOGGENERALDELTA
119 self._generaldelta = False
119 self._generaldelta = False
120 self._realopener = opener
120 self._realopener = opener
121 self._delayed = False
121 self._delayed = False
122 self._divert = False
122 self._divert = False
123 # hiddenrevs: revs that should be hidden by command and tools
123 # hiddenrevs: revs that should be hidden by command and tools
124 self.hiddenrevs = set()
124 self.hiddenrevs = set()
125
125
126 def delayupdate(self):
126 def delayupdate(self):
127 "delay visibility of index updates to other readers"
127 "delay visibility of index updates to other readers"
128 self._delayed = True
128 self._delayed = True
129 self._divert = (len(self) == 0)
129 self._divert = (len(self) == 0)
130 self._delaybuf = []
130 self._delaybuf = []
131 self.opener = delayopener(self._realopener, self.indexfile,
131 self.opener = delayopener(self._realopener, self.indexfile,
132 self._divert, self._delaybuf)
132 self._divert, self._delaybuf)
133
133
134 def finalize(self, tr):
134 def finalize(self, tr):
135 "finalize index updates"
135 "finalize index updates"
136 self._delayed = False
136 self._delayed = False
137 self.opener = self._realopener
137 self.opener = self._realopener
138 # move redirected index data back into place
138 # move redirected index data back into place
139 if self._divert:
139 if self._divert:
140 nfile = self.opener(self.indexfile + ".a")
140 nfile = self.opener(self.indexfile + ".a")
141 n = nfile.name
141 n = nfile.name
142 nfile.close()
142 nfile.close()
143 util.rename(n, n[:-2])
143 util.rename(n, n[:-2])
144 elif self._delaybuf:
144 elif self._delaybuf:
145 fp = self.opener(self.indexfile, 'a')
145 fp = self.opener(self.indexfile, 'a')
146 fp.write("".join(self._delaybuf))
146 fp.write("".join(self._delaybuf))
147 fp.close()
147 fp.close()
148 self._delaybuf = []
148 self._delaybuf = []
149 # split when we're done
149 # split when we're done
150 self.checkinlinesize(tr)
150 self.checkinlinesize(tr)
151
151
152 def readpending(self, file):
152 def readpending(self, file):
153 r = revlog.revlog(self.opener, file)
153 r = revlog.revlog(self.opener, file)
154 self.index = r.index
154 self.index = r.index
155 self.nodemap = r.nodemap
155 self.nodemap = r.nodemap
156 self._nodecache = r._nodecache
156 self._chunkcache = r._chunkcache
157 self._chunkcache = r._chunkcache
157
158
158 def writepending(self):
159 def writepending(self):
159 "create a file containing the unfinalized state for pretxnchangegroup"
160 "create a file containing the unfinalized state for pretxnchangegroup"
160 if self._delaybuf:
161 if self._delaybuf:
161 # make a temporary copy of the index
162 # make a temporary copy of the index
162 fp1 = self._realopener(self.indexfile)
163 fp1 = self._realopener(self.indexfile)
163 fp2 = self._realopener(self.indexfile + ".a", "w")
164 fp2 = self._realopener(self.indexfile + ".a", "w")
164 fp2.write(fp1.read())
165 fp2.write(fp1.read())
165 # add pending data
166 # add pending data
166 fp2.write("".join(self._delaybuf))
167 fp2.write("".join(self._delaybuf))
167 fp2.close()
168 fp2.close()
168 # switch modes so finalize can simply rename
169 # switch modes so finalize can simply rename
169 self._delaybuf = []
170 self._delaybuf = []
170 self._divert = True
171 self._divert = True
171
172
172 if self._divert:
173 if self._divert:
173 return True
174 return True
174
175
175 return False
176 return False
176
177
177 def checkinlinesize(self, tr, fp=None):
178 def checkinlinesize(self, tr, fp=None):
178 if not self._delayed:
179 if not self._delayed:
179 revlog.revlog.checkinlinesize(self, tr, fp)
180 revlog.revlog.checkinlinesize(self, tr, fp)
180
181
181 def read(self, node):
182 def read(self, node):
182 """
183 """
183 format used:
184 format used:
184 nodeid\n : manifest node in ascii
185 nodeid\n : manifest node in ascii
185 user\n : user, no \n or \r allowed
186 user\n : user, no \n or \r allowed
186 time tz extra\n : date (time is int or float, timezone is int)
187 time tz extra\n : date (time is int or float, timezone is int)
187 : extra is metadatas, encoded and separated by '\0'
188 : extra is metadatas, encoded and separated by '\0'
188 : older versions ignore it
189 : older versions ignore it
189 files\n\n : files modified by the cset, no \n or \r allowed
190 files\n\n : files modified by the cset, no \n or \r allowed
190 (.*) : comment (free text, ideally utf-8)
191 (.*) : comment (free text, ideally utf-8)
191
192
192 changelog v0 doesn't use extra
193 changelog v0 doesn't use extra
193 """
194 """
194 text = self.revision(node)
195 text = self.revision(node)
195 if not text:
196 if not text:
196 return (nullid, "", (0, 0), [], "", _defaultextra)
197 return (nullid, "", (0, 0), [], "", _defaultextra)
197 last = text.index("\n\n")
198 last = text.index("\n\n")
198 desc = encoding.tolocal(text[last + 2:])
199 desc = encoding.tolocal(text[last + 2:])
199 l = text[:last].split('\n')
200 l = text[:last].split('\n')
200 manifest = bin(l[0])
201 manifest = bin(l[0])
201 user = encoding.tolocal(l[1])
202 user = encoding.tolocal(l[1])
202
203
203 tdata = l[2].split(' ', 2)
204 tdata = l[2].split(' ', 2)
204 if len(tdata) != 3:
205 if len(tdata) != 3:
205 time = float(tdata[0])
206 time = float(tdata[0])
206 try:
207 try:
207 # various tools did silly things with the time zone field.
208 # various tools did silly things with the time zone field.
208 timezone = int(tdata[1])
209 timezone = int(tdata[1])
209 except ValueError:
210 except ValueError:
210 timezone = 0
211 timezone = 0
211 extra = _defaultextra
212 extra = _defaultextra
212 else:
213 else:
213 time, timezone = float(tdata[0]), int(tdata[1])
214 time, timezone = float(tdata[0]), int(tdata[1])
214 extra = decodeextra(tdata[2])
215 extra = decodeextra(tdata[2])
215
216
216 files = l[3:]
217 files = l[3:]
217 return (manifest, user, (time, timezone), files, desc, extra)
218 return (manifest, user, (time, timezone), files, desc, extra)
218
219
219 def add(self, manifest, files, desc, transaction, p1, p2,
220 def add(self, manifest, files, desc, transaction, p1, p2,
220 user, date=None, extra=None):
221 user, date=None, extra=None):
221 # Convert to UTF-8 encoded bytestrings as the very first
222 # Convert to UTF-8 encoded bytestrings as the very first
222 # thing: calling any method on a localstr object will turn it
223 # thing: calling any method on a localstr object will turn it
223 # into a str object and the cached UTF-8 string is thus lost.
224 # into a str object and the cached UTF-8 string is thus lost.
224 user, desc = encoding.fromlocal(user), encoding.fromlocal(desc)
225 user, desc = encoding.fromlocal(user), encoding.fromlocal(desc)
225
226
226 user = user.strip()
227 user = user.strip()
227 # An empty username or a username with a "\n" will make the
228 # An empty username or a username with a "\n" will make the
228 # revision text contain two "\n\n" sequences -> corrupt
229 # revision text contain two "\n\n" sequences -> corrupt
229 # repository since read cannot unpack the revision.
230 # repository since read cannot unpack the revision.
230 if not user:
231 if not user:
231 raise error.RevlogError(_("empty username"))
232 raise error.RevlogError(_("empty username"))
232 if "\n" in user:
233 if "\n" in user:
233 raise error.RevlogError(_("username %s contains a newline")
234 raise error.RevlogError(_("username %s contains a newline")
234 % repr(user))
235 % repr(user))
235
236
236 # strip trailing whitespace and leading and trailing empty lines
237 # strip trailing whitespace and leading and trailing empty lines
237 desc = '\n'.join([l.rstrip() for l in desc.splitlines()]).strip('\n')
238 desc = '\n'.join([l.rstrip() for l in desc.splitlines()]).strip('\n')
238
239
239 if date:
240 if date:
240 parseddate = "%d %d" % util.parsedate(date)
241 parseddate = "%d %d" % util.parsedate(date)
241 else:
242 else:
242 parseddate = "%d %d" % util.makedate()
243 parseddate = "%d %d" % util.makedate()
243 if extra:
244 if extra:
244 branch = extra.get("branch")
245 branch = extra.get("branch")
245 if branch in ("default", ""):
246 if branch in ("default", ""):
246 del extra["branch"]
247 del extra["branch"]
247 elif branch in (".", "null", "tip"):
248 elif branch in (".", "null", "tip"):
248 raise error.RevlogError(_('the name \'%s\' is reserved')
249 raise error.RevlogError(_('the name \'%s\' is reserved')
249 % branch)
250 % branch)
250 if extra:
251 if extra:
251 extra = encodeextra(extra)
252 extra = encodeextra(extra)
252 parseddate = "%s %s" % (parseddate, extra)
253 parseddate = "%s %s" % (parseddate, extra)
253 l = [hex(manifest), user, parseddate] + sorted(files) + ["", desc]
254 l = [hex(manifest), user, parseddate] + sorted(files) + ["", desc]
254 text = "\n".join(l)
255 text = "\n".join(l)
255 return self.addrevision(text, transaction, len(self), p1, p2)
256 return self.addrevision(text, transaction, len(self), p1, p2)
@@ -1,581 +1,608 b''
1 $ "$TESTDIR/hghave" system-sh || exit 80
1 $ "$TESTDIR/hghave" system-sh || exit 80
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 "$TESTDIR"/printenv.py commit' >> .hg/hgrc
8 $ echo 'commit = unset HG_LOCAL HG_TAG; python "$TESTDIR"/printenv.py commit' >> .hg/hgrc
9 $ echo 'commit.b = unset HG_LOCAL HG_TAG; python "$TESTDIR"/printenv.py commit.b' >> .hg/hgrc
9 $ echo 'commit.b = unset HG_LOCAL HG_TAG; python "$TESTDIR"/printenv.py commit.b' >> .hg/hgrc
10 $ echo 'precommit = unset HG_LOCAL HG_NODE HG_TAG; python "$TESTDIR"/printenv.py precommit' >> .hg/hgrc
10 $ echo 'precommit = unset HG_LOCAL HG_NODE HG_TAG; python "$TESTDIR"/printenv.py precommit' >> .hg/hgrc
11 $ echo 'pretxncommit = unset HG_LOCAL HG_TAG; python "$TESTDIR"/printenv.py pretxncommit' >> .hg/hgrc
11 $ echo 'pretxncommit = unset HG_LOCAL HG_TAG; python "$TESTDIR"/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 "$TESTDIR"/printenv.py pre-identify 1' >> .hg/hgrc
13 $ echo 'pre-identify = python "$TESTDIR"/printenv.py pre-identify 1' >> .hg/hgrc
14 $ echo 'pre-cat = python "$TESTDIR"/printenv.py pre-cat' >> .hg/hgrc
14 $ echo 'pre-cat = python "$TESTDIR"/printenv.py pre-cat' >> .hg/hgrc
15 $ echo 'post-cat = python "$TESTDIR"/printenv.py post-cat' >> .hg/hgrc
15 $ echo 'post-cat = python "$TESTDIR"/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 "$TESTDIR"/printenv.py prechangegroup' >> .hg/hgrc
33 $ echo 'prechangegroup = python "$TESTDIR"/printenv.py prechangegroup' >> .hg/hgrc
34 $ echo 'changegroup = python "$TESTDIR"/printenv.py changegroup' >> .hg/hgrc
34 $ echo 'changegroup = python "$TESTDIR"/printenv.py changegroup' >> .hg/hgrc
35 $ echo 'incoming = python "$TESTDIR"/printenv.py incoming' >> .hg/hgrc
35 $ echo 'incoming = python "$TESTDIR"/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={'bookmarks': None, 'branch': None, 'id': None, 'insecure': None, 'num': None, 'remotecmd': '', 'rev': '', 'ssh': '', 'tags': None} HG_PATS=[]
71 pre-identify hook: HG_ARGS=id HG_OPTS={'bookmarks': None, 'branch': None, 'id': None, 'insecure': None, 'num': None, 'remotecmd': '', 'rev': '', 'ssh': '', 'tags': None} HG_PATS=[]
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={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} 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={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} 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 pulling from ../a
81 pulling from ../a
82 searching for changes
82 searching for changes
83 prechangegroup hook: HG_SOURCE=pull HG_URL=file:$TESTTMP/a
83 prechangegroup hook: HG_SOURCE=pull HG_URL=file:$TESTTMP/a
84 adding changesets
84 adding changesets
85 adding manifests
85 adding manifests
86 adding file changes
86 adding file changes
87 added 3 changesets with 2 changes to 2 files
87 added 3 changesets with 2 changes to 2 files
88 changegroup hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:$TESTTMP/a
88 changegroup hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:$TESTTMP/a
89 incoming hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:$TESTTMP/a
89 incoming hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:$TESTTMP/a
90 incoming hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_SOURCE=pull HG_URL=file:$TESTTMP/a
90 incoming hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_SOURCE=pull HG_URL=file:$TESTTMP/a
91 incoming hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_SOURCE=pull HG_URL=file:$TESTTMP/a
91 incoming hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_SOURCE=pull HG_URL=file:$TESTTMP/a
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 "$TESTDIR"/printenv.py pretag' >> .hg/hgrc
97 $ echo 'pretag = python "$TESTDIR"/printenv.py pretag' >> .hg/hgrc
98 $ echo 'tag = unset HG_PARENT1 HG_PARENT2; python "$TESTDIR"/printenv.py tag' >> .hg/hgrc
98 $ echo 'tag = unset HG_PARENT1 HG_PARENT2; python "$TESTDIR"/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 "$TESTDIR"/printenv.py pretag.forbid 1' >> .hg/hgrc
113 $ echo 'pretag.forbid = python "$TESTDIR"/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 "$TESTDIR"/printenv.py pretxncommit.forbid 1' >> .hg/hgrc
129 $ echo 'pretxncommit.forbid1 = python "$TESTDIR"/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 "$TESTDIR"/printenv.py precommit.forbid 1' >> .hg/hgrc
149 $ echo 'precommit.forbid = python "$TESTDIR"/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 "$TESTDIR"/printenv.py preupdate' >> .hg/hgrc
160 $ echo 'preupdate = python "$TESTDIR"/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 "$TESTDIR"/printenv.py update' >> .hg/hgrc
167 $ echo 'update = python "$TESTDIR"/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 pushkey hook
173 pushkey hook
174
174
175 $ echo 'pushkey = python "$TESTDIR"/printenv.py pushkey' >> .hg/hgrc
175 $ echo 'pushkey = python "$TESTDIR"/printenv.py pushkey' >> .hg/hgrc
176 $ cd ../b
176 $ cd ../b
177 $ hg bookmark -r null foo
177 $ hg bookmark -r null foo
178 $ hg push -B foo ../a
178 $ hg push -B foo ../a
179 pushing to ../a
179 pushing to ../a
180 searching for changes
180 searching for changes
181 no changes found
181 no changes found
182 exporting bookmark foo
182 exporting bookmark foo
183 pushkey hook: HG_KEY=foo HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_RET=1
183 pushkey hook: HG_KEY=foo HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_RET=1
184 [1]
184 [1]
185 $ cd ../a
185 $ cd ../a
186
186
187 listkeys hook
187 listkeys hook
188
188
189 $ echo 'listkeys = python "$TESTDIR"/printenv.py listkeys' >> .hg/hgrc
189 $ echo 'listkeys = python "$TESTDIR"/printenv.py listkeys' >> .hg/hgrc
190 $ hg bookmark -r null bar
190 $ hg bookmark -r null bar
191 $ cd ../b
191 $ cd ../b
192 $ hg pull -B bar ../a
192 $ hg pull -B bar ../a
193 pulling from ../a
193 pulling from ../a
194 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
194 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
195 no changes found
195 no changes found
196 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
196 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
197 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
197 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
198 importing bookmark bar
198 importing bookmark bar
199 $ cd ../a
199 $ cd ../a
200
200
201 test that prepushkey can prevent incoming keys
201 test that prepushkey can prevent incoming keys
202
202
203 $ echo 'prepushkey = python "$TESTDIR"/printenv.py prepushkey.forbid 1' >> .hg/hgrc
203 $ echo 'prepushkey = python "$TESTDIR"/printenv.py prepushkey.forbid 1' >> .hg/hgrc
204 $ cd ../b
204 $ cd ../b
205 $ hg bookmark -r null baz
205 $ hg bookmark -r null baz
206 $ hg push -B baz ../a
206 $ hg push -B baz ../a
207 pushing to ../a
207 pushing to ../a
208 searching for changes
208 searching for changes
209 no changes found
209 no changes found
210 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
210 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
211 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
211 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
212 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
212 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
213 exporting bookmark baz
213 exporting bookmark baz
214 prepushkey.forbid hook: HG_KEY=baz HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000
214 prepushkey.forbid hook: HG_KEY=baz HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000
215 abort: prepushkey hook exited with status 1
215 abort: prepushkey hook exited with status 1
216 [255]
216 [255]
217 $ cd ../a
217 $ cd ../a
218
218
219 test that prelistkeys can prevent listing keys
219 test that prelistkeys can prevent listing keys
220
220
221 $ echo 'prelistkeys = python "$TESTDIR"/printenv.py prelistkeys.forbid 1' >> .hg/hgrc
221 $ echo 'prelistkeys = python "$TESTDIR"/printenv.py prelistkeys.forbid 1' >> .hg/hgrc
222 $ hg bookmark -r null quux
222 $ hg bookmark -r null quux
223 $ cd ../b
223 $ cd ../b
224 $ hg pull -B quux ../a
224 $ hg pull -B quux ../a
225 pulling from ../a
225 pulling from ../a
226 prelistkeys.forbid hook: HG_NAMESPACE=bookmarks
226 prelistkeys.forbid hook: HG_NAMESPACE=bookmarks
227 abort: prelistkeys hook exited with status 1
227 abort: prelistkeys hook exited with status 1
228 [255]
228 [255]
229 $ cd ../a
229 $ cd ../a
230
230
231 prechangegroup hook can prevent incoming changes
231 prechangegroup hook can prevent incoming changes
232
232
233 $ cd ../b
233 $ cd ../b
234 $ hg -q tip
234 $ hg -q tip
235 3:07f3376c1e65
235 3:07f3376c1e65
236 $ echo '[hooks]' > .hg/hgrc
236 $ echo '[hooks]' > .hg/hgrc
237 $ echo 'prechangegroup.forbid = python "$TESTDIR"/printenv.py prechangegroup.forbid 1' >> .hg/hgrc
237 $ echo 'prechangegroup.forbid = python "$TESTDIR"/printenv.py prechangegroup.forbid 1' >> .hg/hgrc
238 $ hg pull ../a
238 $ hg pull ../a
239 pulling from ../a
239 pulling from ../a
240 searching for changes
240 searching for changes
241 prechangegroup.forbid hook: HG_SOURCE=pull HG_URL=file:$TESTTMP/a
241 prechangegroup.forbid hook: HG_SOURCE=pull HG_URL=file:$TESTTMP/a
242 abort: prechangegroup.forbid hook exited with status 1
242 abort: prechangegroup.forbid hook exited with status 1
243 [255]
243 [255]
244
244
245 pretxnchangegroup hook can see incoming changes, can roll back txn,
245 pretxnchangegroup hook can see incoming changes, can roll back txn,
246 incoming changes no longer there after
246 incoming changes no longer there after
247
247
248 $ echo '[hooks]' > .hg/hgrc
248 $ echo '[hooks]' > .hg/hgrc
249 $ echo 'pretxnchangegroup.forbid0 = hg tip -q' >> .hg/hgrc
249 $ echo 'pretxnchangegroup.forbid0 = hg tip -q' >> .hg/hgrc
250 $ echo 'pretxnchangegroup.forbid1 = python "$TESTDIR"/printenv.py pretxnchangegroup.forbid 1' >> .hg/hgrc
250 $ echo 'pretxnchangegroup.forbid1 = python "$TESTDIR"/printenv.py pretxnchangegroup.forbid 1' >> .hg/hgrc
251 $ hg pull ../a
251 $ hg pull ../a
252 pulling from ../a
252 pulling from ../a
253 searching for changes
253 searching for changes
254 adding changesets
254 adding changesets
255 adding manifests
255 adding manifests
256 adding file changes
256 adding file changes
257 added 1 changesets with 1 changes to 1 files
257 added 1 changesets with 1 changes to 1 files
258 4:539e4b31b6dc
258 4:539e4b31b6dc
259 pretxnchangegroup.forbid hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/b HG_SOURCE=pull HG_URL=file:$TESTTMP/a
259 pretxnchangegroup.forbid hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/b HG_SOURCE=pull HG_URL=file:$TESTTMP/a
260 transaction abort!
260 transaction abort!
261 rollback completed
261 rollback completed
262 abort: pretxnchangegroup.forbid1 hook exited with status 1
262 abort: pretxnchangegroup.forbid1 hook exited with status 1
263 [255]
263 [255]
264 $ hg -q tip
264 $ hg -q tip
265 3:07f3376c1e65
265 3:07f3376c1e65
266
266
267 outgoing hooks can see env vars
267 outgoing hooks can see env vars
268
268
269 $ rm .hg/hgrc
269 $ rm .hg/hgrc
270 $ echo '[hooks]' > ../a/.hg/hgrc
270 $ echo '[hooks]' > ../a/.hg/hgrc
271 $ echo 'preoutgoing = python "$TESTDIR"/printenv.py preoutgoing' >> ../a/.hg/hgrc
271 $ echo 'preoutgoing = python "$TESTDIR"/printenv.py preoutgoing' >> ../a/.hg/hgrc
272 $ echo 'outgoing = python "$TESTDIR"/printenv.py outgoing' >> ../a/.hg/hgrc
272 $ echo 'outgoing = python "$TESTDIR"/printenv.py outgoing' >> ../a/.hg/hgrc
273 $ hg pull ../a
273 $ hg pull ../a
274 pulling from ../a
274 pulling from ../a
275 searching for changes
275 searching for changes
276 preoutgoing hook: HG_SOURCE=pull
276 preoutgoing hook: HG_SOURCE=pull
277 adding changesets
277 adding changesets
278 outgoing hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_SOURCE=pull
278 outgoing hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_SOURCE=pull
279 adding manifests
279 adding manifests
280 adding file changes
280 adding file changes
281 added 1 changesets with 1 changes to 1 files
281 added 1 changesets with 1 changes to 1 files
282 (run 'hg update' to get a working copy)
282 (run 'hg update' to get a working copy)
283 $ hg rollback
283 $ hg rollback
284 repository tip rolled back to revision 3 (undo pull)
284 repository tip rolled back to revision 3 (undo pull)
285
285
286 preoutgoing hook can prevent outgoing changes
286 preoutgoing hook can prevent outgoing changes
287
287
288 $ echo 'preoutgoing.forbid = python "$TESTDIR"/printenv.py preoutgoing.forbid 1' >> ../a/.hg/hgrc
288 $ echo 'preoutgoing.forbid = python "$TESTDIR"/printenv.py preoutgoing.forbid 1' >> ../a/.hg/hgrc
289 $ hg pull ../a
289 $ hg pull ../a
290 pulling from ../a
290 pulling from ../a
291 searching for changes
291 searching for changes
292 preoutgoing hook: HG_SOURCE=pull
292 preoutgoing hook: HG_SOURCE=pull
293 preoutgoing.forbid hook: HG_SOURCE=pull
293 preoutgoing.forbid hook: HG_SOURCE=pull
294 abort: preoutgoing.forbid hook exited with status 1
294 abort: preoutgoing.forbid hook exited with status 1
295 [255]
295 [255]
296
296
297 outgoing hooks work for local clones
297 outgoing hooks work for local clones
298
298
299 $ cd ..
299 $ cd ..
300 $ echo '[hooks]' > a/.hg/hgrc
300 $ echo '[hooks]' > a/.hg/hgrc
301 $ echo 'preoutgoing = python "$TESTDIR"/printenv.py preoutgoing' >> a/.hg/hgrc
301 $ echo 'preoutgoing = python "$TESTDIR"/printenv.py preoutgoing' >> a/.hg/hgrc
302 $ echo 'outgoing = python "$TESTDIR"/printenv.py outgoing' >> a/.hg/hgrc
302 $ echo 'outgoing = python "$TESTDIR"/printenv.py outgoing' >> a/.hg/hgrc
303 $ hg clone a c
303 $ hg clone a c
304 preoutgoing hook: HG_SOURCE=clone
304 preoutgoing hook: HG_SOURCE=clone
305 outgoing hook: HG_NODE=0000000000000000000000000000000000000000 HG_SOURCE=clone
305 outgoing hook: HG_NODE=0000000000000000000000000000000000000000 HG_SOURCE=clone
306 updating to branch default
306 updating to branch default
307 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
307 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
308 $ rm -rf c
308 $ rm -rf c
309
309
310 preoutgoing hook can prevent outgoing changes for local clones
310 preoutgoing hook can prevent outgoing changes for local clones
311
311
312 $ echo 'preoutgoing.forbid = python "$TESTDIR"/printenv.py preoutgoing.forbid 1' >> a/.hg/hgrc
312 $ echo 'preoutgoing.forbid = python "$TESTDIR"/printenv.py preoutgoing.forbid 1' >> a/.hg/hgrc
313 $ hg clone a zzz
313 $ hg clone a zzz
314 preoutgoing hook: HG_SOURCE=clone
314 preoutgoing hook: HG_SOURCE=clone
315 preoutgoing.forbid hook: HG_SOURCE=clone
315 preoutgoing.forbid hook: HG_SOURCE=clone
316 abort: preoutgoing.forbid hook exited with status 1
316 abort: preoutgoing.forbid hook exited with status 1
317 [255]
317 [255]
318 $ cd b
318 $ cd b
319
319
320 $ cat > hooktests.py <<EOF
320 $ cat > hooktests.py <<EOF
321 > from mercurial import util
321 > from mercurial import util
322 >
322 >
323 > uncallable = 0
323 > uncallable = 0
324 >
324 >
325 > def printargs(args):
325 > def printargs(args):
326 > args.pop('ui', None)
326 > args.pop('ui', None)
327 > args.pop('repo', None)
327 > args.pop('repo', None)
328 > a = list(args.items())
328 > a = list(args.items())
329 > a.sort()
329 > a.sort()
330 > print 'hook args:'
330 > print 'hook args:'
331 > for k, v in a:
331 > for k, v in a:
332 > print ' ', k, v
332 > print ' ', k, v
333 >
333 >
334 > def passhook(**args):
334 > def passhook(**args):
335 > printargs(args)
335 > printargs(args)
336 >
336 >
337 > def failhook(**args):
337 > def failhook(**args):
338 > printargs(args)
338 > printargs(args)
339 > return True
339 > return True
340 >
340 >
341 > class LocalException(Exception):
341 > class LocalException(Exception):
342 > pass
342 > pass
343 >
343 >
344 > def raisehook(**args):
344 > def raisehook(**args):
345 > raise LocalException('exception from hook')
345 > raise LocalException('exception from hook')
346 >
346 >
347 > def aborthook(**args):
347 > def aborthook(**args):
348 > raise util.Abort('raise abort from hook')
348 > raise util.Abort('raise abort from hook')
349 >
349 >
350 > def brokenhook(**args):
350 > def brokenhook(**args):
351 > return 1 + {}
351 > return 1 + {}
352 >
352 >
353 > def verbosehook(ui, **args):
353 > def verbosehook(ui, **args):
354 > ui.note('verbose output from hook\n')
354 > ui.note('verbose output from hook\n')
355 >
355 >
356 > def printtags(ui, repo, **args):
356 > def printtags(ui, repo, **args):
357 > print repo.tags().keys()
357 > print repo.tags().keys()
358 >
358 >
359 > class container:
359 > class container:
360 > unreachable = 1
360 > unreachable = 1
361 > EOF
361 > EOF
362
362
363 test python hooks
363 test python hooks
364
364
365 $ PYTHONPATH="`pwd`:$PYTHONPATH"
365 $ PYTHONPATH="`pwd`:$PYTHONPATH"
366 $ export PYTHONPATH
366 $ export PYTHONPATH
367
367
368 $ echo '[hooks]' > ../a/.hg/hgrc
368 $ echo '[hooks]' > ../a/.hg/hgrc
369 $ echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
369 $ echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
370 $ hg pull ../a 2>&1 | grep 'raised an exception'
370 $ hg pull ../a 2>&1 | grep 'raised an exception'
371 error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
371 error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
372
372
373 $ echo '[hooks]' > ../a/.hg/hgrc
373 $ echo '[hooks]' > ../a/.hg/hgrc
374 $ echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
374 $ echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
375 $ hg pull ../a 2>&1 | grep 'raised an exception'
375 $ hg pull ../a 2>&1 | grep 'raised an exception'
376 error: preoutgoing.raise hook raised an exception: exception from hook
376 error: preoutgoing.raise hook raised an exception: exception from hook
377
377
378 $ echo '[hooks]' > ../a/.hg/hgrc
378 $ echo '[hooks]' > ../a/.hg/hgrc
379 $ echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
379 $ echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
380 $ hg pull ../a
380 $ hg pull ../a
381 pulling from ../a
381 pulling from ../a
382 searching for changes
382 searching for changes
383 error: preoutgoing.abort hook failed: raise abort from hook
383 error: preoutgoing.abort hook failed: raise abort from hook
384 abort: raise abort from hook
384 abort: raise abort from hook
385 [255]
385 [255]
386
386
387 $ echo '[hooks]' > ../a/.hg/hgrc
387 $ echo '[hooks]' > ../a/.hg/hgrc
388 $ echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
388 $ echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
389 $ hg pull ../a
389 $ hg pull ../a
390 pulling from ../a
390 pulling from ../a
391 searching for changes
391 searching for changes
392 hook args:
392 hook args:
393 hooktype preoutgoing
393 hooktype preoutgoing
394 source pull
394 source pull
395 abort: preoutgoing.fail hook failed
395 abort: preoutgoing.fail hook failed
396 [255]
396 [255]
397
397
398 $ echo '[hooks]' > ../a/.hg/hgrc
398 $ echo '[hooks]' > ../a/.hg/hgrc
399 $ echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
399 $ echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
400 $ hg pull ../a
400 $ hg pull ../a
401 pulling from ../a
401 pulling from ../a
402 searching for changes
402 searching for changes
403 abort: preoutgoing.uncallable hook is invalid ("hooktests.uncallable" is not callable)
403 abort: preoutgoing.uncallable hook is invalid ("hooktests.uncallable" is not callable)
404 [255]
404 [255]
405
405
406 $ echo '[hooks]' > ../a/.hg/hgrc
406 $ echo '[hooks]' > ../a/.hg/hgrc
407 $ echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
407 $ echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
408 $ hg pull ../a
408 $ hg pull ../a
409 pulling from ../a
409 pulling from ../a
410 searching for changes
410 searching for changes
411 abort: preoutgoing.nohook hook is invalid ("hooktests.nohook" is not defined)
411 abort: preoutgoing.nohook hook is invalid ("hooktests.nohook" is not defined)
412 [255]
412 [255]
413
413
414 $ echo '[hooks]' > ../a/.hg/hgrc
414 $ echo '[hooks]' > ../a/.hg/hgrc
415 $ echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
415 $ echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
416 $ hg pull ../a
416 $ hg pull ../a
417 pulling from ../a
417 pulling from ../a
418 searching for changes
418 searching for changes
419 abort: preoutgoing.nomodule hook is invalid ("nomodule" not in a module)
419 abort: preoutgoing.nomodule hook is invalid ("nomodule" not in a module)
420 [255]
420 [255]
421
421
422 $ echo '[hooks]' > ../a/.hg/hgrc
422 $ echo '[hooks]' > ../a/.hg/hgrc
423 $ echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
423 $ echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
424 $ hg pull ../a
424 $ hg pull ../a
425 pulling from ../a
425 pulling from ../a
426 searching for changes
426 searching for changes
427 abort: preoutgoing.badmodule hook is invalid (import of "nomodule" failed)
427 abort: preoutgoing.badmodule hook is invalid (import of "nomodule" failed)
428 [255]
428 [255]
429
429
430 $ echo '[hooks]' > ../a/.hg/hgrc
430 $ echo '[hooks]' > ../a/.hg/hgrc
431 $ echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
431 $ echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
432 $ hg pull ../a
432 $ hg pull ../a
433 pulling from ../a
433 pulling from ../a
434 searching for changes
434 searching for changes
435 abort: preoutgoing.unreachable hook is invalid (import of "hooktests.container" failed)
435 abort: preoutgoing.unreachable hook is invalid (import of "hooktests.container" failed)
436 [255]
436 [255]
437
437
438 $ echo '[hooks]' > ../a/.hg/hgrc
438 $ echo '[hooks]' > ../a/.hg/hgrc
439 $ echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
439 $ echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
440 $ hg pull ../a
440 $ hg pull ../a
441 pulling from ../a
441 pulling from ../a
442 searching for changes
442 searching for changes
443 hook args:
443 hook args:
444 hooktype preoutgoing
444 hooktype preoutgoing
445 source pull
445 source pull
446 adding changesets
446 adding changesets
447 adding manifests
447 adding manifests
448 adding file changes
448 adding file changes
449 added 1 changesets with 1 changes to 1 files
449 added 1 changesets with 1 changes to 1 files
450 (run 'hg update' to get a working copy)
450 (run 'hg update' to get a working copy)
451
451
452 make sure --traceback works
452 make sure --traceback works
453
453
454 $ echo '[hooks]' > .hg/hgrc
454 $ echo '[hooks]' > .hg/hgrc
455 $ echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
455 $ echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
456
456
457 $ echo aa > a
457 $ echo aa > a
458 $ hg --traceback commit -d '0 0' -ma 2>&1 | grep '^Traceback'
458 $ hg --traceback commit -d '0 0' -ma 2>&1 | grep '^Traceback'
459 Traceback (most recent call last):
459 Traceback (most recent call last):
460
460
461 $ cd ..
461 $ cd ..
462 $ hg init c
462 $ hg init c
463 $ cd c
463 $ cd c
464
464
465 $ cat > hookext.py <<EOF
465 $ cat > hookext.py <<EOF
466 > def autohook(**args):
466 > def autohook(**args):
467 > print "Automatically installed hook"
467 > print "Automatically installed hook"
468 >
468 >
469 > def reposetup(ui, repo):
469 > def reposetup(ui, repo):
470 > repo.ui.setconfig("hooks", "commit.auto", autohook)
470 > repo.ui.setconfig("hooks", "commit.auto", autohook)
471 > EOF
471 > EOF
472 $ echo '[extensions]' >> .hg/hgrc
472 $ echo '[extensions]' >> .hg/hgrc
473 $ echo 'hookext = hookext.py' >> .hg/hgrc
473 $ echo 'hookext = hookext.py' >> .hg/hgrc
474
474
475 $ touch foo
475 $ touch foo
476 $ hg add foo
476 $ hg add foo
477 $ hg ci -d '0 0' -m 'add foo'
477 $ hg ci -d '0 0' -m 'add foo'
478 Automatically installed hook
478 Automatically installed hook
479 $ echo >> foo
479 $ echo >> foo
480 $ hg ci --debug -d '0 0' -m 'change foo'
480 $ hg ci --debug -d '0 0' -m 'change foo'
481 foo
481 foo
482 calling hook commit.auto: <function autohook at *> (glob)
482 calling hook commit.auto: <function autohook at *> (glob)
483 Automatically installed hook
483 Automatically installed hook
484 committed changeset 1:52998019f6252a2b893452765fcb0a47351a5708
484 committed changeset 1:52998019f6252a2b893452765fcb0a47351a5708
485
485
486 $ hg showconfig hooks
486 $ hg showconfig hooks
487 hooks.commit.auto=<function autohook at *> (glob)
487 hooks.commit.auto=<function autohook at *> (glob)
488
488
489 test python hook configured with python:[file]:[hook] syntax
489 test python hook configured with python:[file]:[hook] syntax
490
490
491 $ cd ..
491 $ cd ..
492 $ mkdir d
492 $ mkdir d
493 $ cd d
493 $ cd d
494 $ hg init repo
494 $ hg init repo
495 $ mkdir hooks
495 $ mkdir hooks
496
496
497 $ cd hooks
497 $ cd hooks
498 $ cat > testhooks.py <<EOF
498 $ cat > testhooks.py <<EOF
499 > def testhook(**args):
499 > def testhook(**args):
500 > print 'hook works'
500 > print 'hook works'
501 > EOF
501 > EOF
502 $ echo '[hooks]' > ../repo/.hg/hgrc
502 $ echo '[hooks]' > ../repo/.hg/hgrc
503 $ echo "pre-commit.test = python:`pwd`/testhooks.py:testhook" >> ../repo/.hg/hgrc
503 $ echo "pre-commit.test = python:`pwd`/testhooks.py:testhook" >> ../repo/.hg/hgrc
504
504
505 $ cd ../repo
505 $ cd ../repo
506 $ hg commit -d '0 0'
506 $ hg commit -d '0 0'
507 hook works
507 hook works
508 nothing changed
508 nothing changed
509 [1]
509 [1]
510
510
511 $ cd ../../b
511 $ cd ../../b
512
512
513 make sure --traceback works on hook import failure
513 make sure --traceback works on hook import failure
514
514
515 $ cat > importfail.py <<EOF
515 $ cat > importfail.py <<EOF
516 > import somebogusmodule
516 > import somebogusmodule
517 > # dereference something in the module to force demandimport to load it
517 > # dereference something in the module to force demandimport to load it
518 > somebogusmodule.whatever
518 > somebogusmodule.whatever
519 > EOF
519 > EOF
520
520
521 $ echo '[hooks]' > .hg/hgrc
521 $ echo '[hooks]' > .hg/hgrc
522 $ echo 'precommit.importfail = python:importfail.whatever' >> .hg/hgrc
522 $ echo 'precommit.importfail = python:importfail.whatever' >> .hg/hgrc
523
523
524 $ echo a >> a
524 $ echo a >> a
525 $ hg --traceback commit -ma 2>&1 | egrep '^(exception|Traceback|ImportError)'
525 $ hg --traceback commit -ma 2>&1 | egrep '^(exception|Traceback|ImportError)'
526 exception from first failed import attempt:
526 exception from first failed import attempt:
527 Traceback (most recent call last):
527 Traceback (most recent call last):
528 ImportError: No module named somebogusmodule
528 ImportError: No module named somebogusmodule
529 exception from second failed import attempt:
529 exception from second failed import attempt:
530 Traceback (most recent call last):
530 Traceback (most recent call last):
531 ImportError: No module named hgext_importfail
531 ImportError: No module named hgext_importfail
532 Traceback (most recent call last):
532 Traceback (most recent call last):
533
533
534 Issue1827: Hooks Update & Commit not completely post operation
534 Issue1827: Hooks Update & Commit not completely post operation
535
535
536 commit and update hooks should run after command completion
536 commit and update hooks should run after command completion
537
537
538 $ echo '[hooks]' > .hg/hgrc
538 $ echo '[hooks]' > .hg/hgrc
539 $ echo 'commit = hg id' >> .hg/hgrc
539 $ echo 'commit = hg id' >> .hg/hgrc
540 $ echo 'update = hg id' >> .hg/hgrc
540 $ echo 'update = hg id' >> .hg/hgrc
541 $ echo bb > a
541 $ echo bb > a
542 $ hg ci -ma
542 $ hg ci -ma
543 223eafe2750c tip
543 223eafe2750c tip
544 $ hg up 0
544 $ hg up 0
545 cb9a9f314b8b
545 cb9a9f314b8b
546 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
546 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
547
547
548 make sure --verbose (and --quiet/--debug etc.) are propogated to the local ui
548 make sure --verbose (and --quiet/--debug etc.) are propogated to the local ui
549 that is passed to pre/post hooks
549 that is passed to pre/post hooks
550
550
551 $ echo '[hooks]' > .hg/hgrc
551 $ echo '[hooks]' > .hg/hgrc
552 $ echo 'pre-identify = python:hooktests.verbosehook' >> .hg/hgrc
552 $ echo 'pre-identify = python:hooktests.verbosehook' >> .hg/hgrc
553 $ hg id
553 $ hg id
554 cb9a9f314b8b
554 cb9a9f314b8b
555 $ hg id --verbose
555 $ hg id --verbose
556 calling hook pre-identify: hooktests.verbosehook
556 calling hook pre-identify: hooktests.verbosehook
557 verbose output from hook
557 verbose output from hook
558 cb9a9f314b8b
558 cb9a9f314b8b
559
559
560 Ensure hooks can be prioritized
560 Ensure hooks can be prioritized
561
561
562 $ echo '[hooks]' > .hg/hgrc
562 $ echo '[hooks]' > .hg/hgrc
563 $ echo 'pre-identify.a = python:hooktests.verbosehook' >> .hg/hgrc
563 $ echo 'pre-identify.a = python:hooktests.verbosehook' >> .hg/hgrc
564 $ echo 'pre-identify.b = python:hooktests.verbosehook' >> .hg/hgrc
564 $ echo 'pre-identify.b = python:hooktests.verbosehook' >> .hg/hgrc
565 $ echo 'priority.pre-identify.b = 1' >> .hg/hgrc
565 $ echo 'priority.pre-identify.b = 1' >> .hg/hgrc
566 $ echo 'pre-identify.c = python:hooktests.verbosehook' >> .hg/hgrc
566 $ echo 'pre-identify.c = python:hooktests.verbosehook' >> .hg/hgrc
567 $ hg id --verbose
567 $ hg id --verbose
568 calling hook pre-identify.b: hooktests.verbosehook
568 calling hook pre-identify.b: hooktests.verbosehook
569 verbose output from hook
569 verbose output from hook
570 calling hook pre-identify.a: hooktests.verbosehook
570 calling hook pre-identify.a: hooktests.verbosehook
571 verbose output from hook
571 verbose output from hook
572 calling hook pre-identify.c: hooktests.verbosehook
572 calling hook pre-identify.c: hooktests.verbosehook
573 verbose output from hook
573 verbose output from hook
574 cb9a9f314b8b
574 cb9a9f314b8b
575
575
576 new tags must be visible in pretxncommit (issue3210)
576 new tags must be visible in pretxncommit (issue3210)
577
577
578 $ echo 'pretxncommit.printtags = python:hooktests.printtags' >> .hg/hgrc
578 $ echo 'pretxncommit.printtags = python:hooktests.printtags' >> .hg/hgrc
579 $ hg tag -f foo
579 $ hg tag -f foo
580 ['a', 'foo', 'tip']
580 ['a', 'foo', 'tip']
581
581
582 new commits must be visible in pretxnchangegroup (issue3428)
583
584 $ cd ..
585 $ hg init to
586 $ echo '[hooks]' >> to/.hg/hgrc
587 $ echo 'pretxnchangegroup = hg --traceback tip' >> to/.hg/hgrc
588 $ echo a >> to/a
589 $ hg --cwd to ci -Ama
590 adding a
591 $ hg clone to from
592 updating to branch default
593 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
594 $ echo aa >> from/a
595 $ hg --cwd from ci -mb
596 $ hg --cwd from push
597 pushing to $TESTTMP/to
598 searching for changes
599 adding changesets
600 adding manifests
601 adding file changes
602 added 1 changesets with 1 changes to 1 files
603 changeset: 1:9836a07b9b9d
604 tag: tip
605 user: test
606 date: Thu Jan 01 00:00:00 1970 +0000
607 summary: b
608
General Comments 0
You need to be logged in to leave comments. Login now