##// END OF EJS Templates
eol: look up partial nodeid as partial nodeid...
Martin von Zweigbergk -
r37525:9b16a67c default
parent child Browse files
Show More
@@ -1,419 +1,421 b''
1 1 """automatically manage newlines in repository files
2 2
3 3 This extension allows you to manage the type of line endings (CRLF or
4 4 LF) that are used in the repository and in the local working
5 5 directory. That way you can get CRLF line endings on Windows and LF on
6 6 Unix/Mac, thereby letting everybody use their OS native line endings.
7 7
8 8 The extension reads its configuration from a versioned ``.hgeol``
9 9 configuration file found in the root of the working directory. The
10 10 ``.hgeol`` file use the same syntax as all other Mercurial
11 11 configuration files. It uses two sections, ``[patterns]`` and
12 12 ``[repository]``.
13 13
14 14 The ``[patterns]`` section specifies how line endings should be
15 15 converted between the working directory and the repository. The format is
16 16 specified by a file pattern. The first match is used, so put more
17 17 specific patterns first. The available line endings are ``LF``,
18 18 ``CRLF``, and ``BIN``.
19 19
20 20 Files with the declared format of ``CRLF`` or ``LF`` are always
21 21 checked out and stored in the repository in that format and files
22 22 declared to be binary (``BIN``) are left unchanged. Additionally,
23 23 ``native`` is an alias for checking out in the platform's default line
24 24 ending: ``LF`` on Unix (including Mac OS X) and ``CRLF`` on
25 25 Windows. Note that ``BIN`` (do nothing to line endings) is Mercurial's
26 26 default behavior; it is only needed if you need to override a later,
27 27 more general pattern.
28 28
29 29 The optional ``[repository]`` section specifies the line endings to
30 30 use for files stored in the repository. It has a single setting,
31 31 ``native``, which determines the storage line endings for files
32 32 declared as ``native`` in the ``[patterns]`` section. It can be set to
33 33 ``LF`` or ``CRLF``. The default is ``LF``. For example, this means
34 34 that on Windows, files configured as ``native`` (``CRLF`` by default)
35 35 will be converted to ``LF`` when stored in the repository. Files
36 36 declared as ``LF``, ``CRLF``, or ``BIN`` in the ``[patterns]`` section
37 37 are always stored as-is in the repository.
38 38
39 39 Example versioned ``.hgeol`` file::
40 40
41 41 [patterns]
42 42 **.py = native
43 43 **.vcproj = CRLF
44 44 **.txt = native
45 45 Makefile = LF
46 46 **.jpg = BIN
47 47
48 48 [repository]
49 49 native = LF
50 50
51 51 .. note::
52 52
53 53 The rules will first apply when files are touched in the working
54 54 directory, e.g. by updating to null and back to tip to touch all files.
55 55
56 56 The extension uses an optional ``[eol]`` section read from both the
57 57 normal Mercurial configuration files and the ``.hgeol`` file, with the
58 58 latter overriding the former. You can use that section to control the
59 59 overall behavior. There are three settings:
60 60
61 61 - ``eol.native`` (default ``os.linesep``) can be set to ``LF`` or
62 62 ``CRLF`` to override the default interpretation of ``native`` for
63 63 checkout. This can be used with :hg:`archive` on Unix, say, to
64 64 generate an archive where files have line endings for Windows.
65 65
66 66 - ``eol.only-consistent`` (default True) can be set to False to make
67 67 the extension convert files with inconsistent EOLs. Inconsistent
68 68 means that there is both ``CRLF`` and ``LF`` present in the file.
69 69 Such files are normally not touched under the assumption that they
70 70 have mixed EOLs on purpose.
71 71
72 72 - ``eol.fix-trailing-newline`` (default False) can be set to True to
73 73 ensure that converted files end with a EOL character (either ``\\n``
74 74 or ``\\r\\n`` as per the configured patterns).
75 75
76 76 The extension provides ``cleverencode:`` and ``cleverdecode:`` filters
77 77 like the deprecated win32text extension does. This means that you can
78 78 disable win32text and enable eol and your filters will still work. You
79 79 only need to these filters until you have prepared a ``.hgeol`` file.
80 80
81 81 The ``win32text.forbid*`` hooks provided by the win32text extension
82 82 have been unified into a single hook named ``eol.checkheadshook``. The
83 83 hook will lookup the expected line endings from the ``.hgeol`` file,
84 84 which means you must migrate to a ``.hgeol`` file first before using
85 85 the hook. ``eol.checkheadshook`` only checks heads, intermediate
86 86 invalid revisions will be pushed. To forbid them completely, use the
87 87 ``eol.checkallhook`` hook. These hooks are best used as
88 88 ``pretxnchangegroup`` hooks.
89 89
90 90 See :hg:`help patterns` for more information about the glob patterns
91 91 used.
92 92 """
93 93
94 94 from __future__ import absolute_import
95 95
96 96 import os
97 97 import re
98 98 from mercurial.i18n import _
99 99 from mercurial import (
100 100 config,
101 101 error as errormod,
102 102 extensions,
103 103 match,
104 104 pycompat,
105 105 registrar,
106 scmutil,
106 107 util,
107 108 )
108 109 from mercurial.utils import (
109 110 stringutil,
110 111 )
111 112
112 113 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
113 114 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
114 115 # be specifying the version(s) of Mercurial they are tested with, or
115 116 # leave the attribute unspecified.
116 117 testedwith = 'ships-with-hg-core'
117 118
118 119 configtable = {}
119 120 configitem = registrar.configitem(configtable)
120 121
121 122 configitem('eol', 'fix-trailing-newline',
122 123 default=False,
123 124 )
124 125 configitem('eol', 'native',
125 126 default=pycompat.oslinesep,
126 127 )
127 128 configitem('eol', 'only-consistent',
128 129 default=True,
129 130 )
130 131
131 132 # Matches a lone LF, i.e., one that is not part of CRLF.
132 133 singlelf = re.compile('(^|[^\r])\n')
133 134
134 135 def inconsistenteol(data):
135 136 return '\r\n' in data and singlelf.search(data)
136 137
137 138 def tolf(s, params, ui, **kwargs):
138 139 """Filter to convert to LF EOLs."""
139 140 if stringutil.binary(s):
140 141 return s
141 142 if ui.configbool('eol', 'only-consistent') and inconsistenteol(s):
142 143 return s
143 144 if (ui.configbool('eol', 'fix-trailing-newline')
144 145 and s and s[-1] != '\n'):
145 146 s = s + '\n'
146 147 return util.tolf(s)
147 148
148 149 def tocrlf(s, params, ui, **kwargs):
149 150 """Filter to convert to CRLF EOLs."""
150 151 if stringutil.binary(s):
151 152 return s
152 153 if ui.configbool('eol', 'only-consistent') and inconsistenteol(s):
153 154 return s
154 155 if (ui.configbool('eol', 'fix-trailing-newline')
155 156 and s and s[-1] != '\n'):
156 157 s = s + '\n'
157 158 return util.tocrlf(s)
158 159
159 160 def isbinary(s, params):
160 161 """Filter to do nothing with the file."""
161 162 return s
162 163
163 164 filters = {
164 165 'to-lf': tolf,
165 166 'to-crlf': tocrlf,
166 167 'is-binary': isbinary,
167 168 # The following provide backwards compatibility with win32text
168 169 'cleverencode:': tolf,
169 170 'cleverdecode:': tocrlf
170 171 }
171 172
172 173 class eolfile(object):
173 174 def __init__(self, ui, root, data):
174 175 self._decode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'}
175 176 self._encode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'}
176 177
177 178 self.cfg = config.config()
178 179 # Our files should not be touched. The pattern must be
179 180 # inserted first override a '** = native' pattern.
180 181 self.cfg.set('patterns', '.hg*', 'BIN', 'eol')
181 182 # We can then parse the user's patterns.
182 183 self.cfg.parse('.hgeol', data)
183 184
184 185 isrepolf = self.cfg.get('repository', 'native') != 'CRLF'
185 186 self._encode['NATIVE'] = isrepolf and 'to-lf' or 'to-crlf'
186 187 iswdlf = ui.config('eol', 'native') in ('LF', '\n')
187 188 self._decode['NATIVE'] = iswdlf and 'to-lf' or 'to-crlf'
188 189
189 190 include = []
190 191 exclude = []
191 192 self.patterns = []
192 193 for pattern, style in self.cfg.items('patterns'):
193 194 key = style.upper()
194 195 if key == 'BIN':
195 196 exclude.append(pattern)
196 197 else:
197 198 include.append(pattern)
198 199 m = match.match(root, '', [pattern])
199 200 self.patterns.append((pattern, key, m))
200 201 # This will match the files for which we need to care
201 202 # about inconsistent newlines.
202 203 self.match = match.match(root, '', [], include, exclude)
203 204
204 205 def copytoui(self, ui):
205 206 for pattern, key, m in self.patterns:
206 207 try:
207 208 ui.setconfig('decode', pattern, self._decode[key], 'eol')
208 209 ui.setconfig('encode', pattern, self._encode[key], 'eol')
209 210 except KeyError:
210 211 ui.warn(_("ignoring unknown EOL style '%s' from %s\n")
211 212 % (key, self.cfg.source('patterns', pattern)))
212 213 # eol.only-consistent can be specified in ~/.hgrc or .hgeol
213 214 for k, v in self.cfg.items('eol'):
214 215 ui.setconfig('eol', k, v, 'eol')
215 216
216 217 def checkrev(self, repo, ctx, files):
217 218 failed = []
218 219 for f in (files or ctx.files()):
219 220 if f not in ctx:
220 221 continue
221 222 for pattern, key, m in self.patterns:
222 223 if not m(f):
223 224 continue
224 225 target = self._encode[key]
225 226 data = ctx[f].data()
226 227 if (target == "to-lf" and "\r\n" in data
227 228 or target == "to-crlf" and singlelf.search(data)):
228 229 failed.append((f, target, bytes(ctx)))
229 230 break
230 231 return failed
231 232
232 233 def parseeol(ui, repo, nodes):
233 234 try:
234 235 for node in nodes:
235 236 try:
236 237 if node is None:
237 238 # Cannot use workingctx.data() since it would load
238 239 # and cache the filters before we configure them.
239 240 data = repo.wvfs('.hgeol').read()
240 241 else:
241 242 data = repo[node]['.hgeol'].data()
242 243 return eolfile(ui, repo.root, data)
243 244 except (IOError, LookupError):
244 245 pass
245 246 except errormod.ParseError as inst:
246 247 ui.warn(_("warning: ignoring .hgeol file due to parse error "
247 248 "at %s: %s\n") % (inst.args[1], inst.args[0]))
248 249 return None
249 250
250 251 def ensureenabled(ui):
251 252 """make sure the extension is enabled when used as hook
252 253
253 254 When eol is used through hooks, the extension is never formally loaded and
254 255 enabled. This has some side effect, for example the config declaration is
255 256 never loaded. This function ensure the extension is enabled when running
256 257 hooks.
257 258 """
258 259 if 'eol' in ui._knownconfig:
259 260 return
260 261 ui.setconfig('extensions', 'eol', '', source='internal')
261 262 extensions.loadall(ui, ['eol'])
262 263
263 264 def _checkhook(ui, repo, node, headsonly):
264 265 # Get revisions to check and touched files at the same time
265 266 ensureenabled(ui)
266 267 files = set()
267 268 revs = set()
268 269 for rev in xrange(repo[node].rev(), len(repo)):
269 270 revs.add(rev)
270 271 if headsonly:
271 272 ctx = repo[rev]
272 273 files.update(ctx.files())
273 274 for pctx in ctx.parents():
274 275 revs.discard(pctx.rev())
275 276 failed = []
276 277 for rev in revs:
277 278 ctx = repo[rev]
278 279 eol = parseeol(ui, repo, [ctx.node()])
279 280 if eol:
280 281 failed.extend(eol.checkrev(repo, ctx, files))
281 282
282 283 if failed:
283 284 eols = {'to-lf': 'CRLF', 'to-crlf': 'LF'}
284 285 msgs = []
285 286 for f, target, node in sorted(failed):
286 287 msgs.append(_(" %s in %s should not have %s line endings") %
287 288 (f, node, eols[target]))
288 289 raise errormod.Abort(_("end-of-line check failed:\n") + "\n".join(msgs))
289 290
290 291 def checkallhook(ui, repo, node, hooktype, **kwargs):
291 292 """verify that files have expected EOLs"""
292 293 _checkhook(ui, repo, node, False)
293 294
294 295 def checkheadshook(ui, repo, node, hooktype, **kwargs):
295 296 """verify that files have expected EOLs"""
296 297 _checkhook(ui, repo, node, True)
297 298
298 299 # "checkheadshook" used to be called "hook"
299 300 hook = checkheadshook
300 301
301 302 def preupdate(ui, repo, hooktype, parent1, parent2):
302 repo.loadeol([parent1])
303 p1node = scmutil.resolvepartialhexnodeid(repo, parent1)
304 repo.loadeol([p1node])
303 305 return False
304 306
305 307 def uisetup(ui):
306 308 ui.setconfig('hooks', 'preupdate.eol', preupdate, 'eol')
307 309
308 310 def extsetup(ui):
309 311 try:
310 312 extensions.find('win32text')
311 313 ui.warn(_("the eol extension is incompatible with the "
312 314 "win32text extension\n"))
313 315 except KeyError:
314 316 pass
315 317
316 318
317 319 def reposetup(ui, repo):
318 320 uisetup(repo.ui)
319 321
320 322 if not repo.local():
321 323 return
322 324 for name, fn in filters.iteritems():
323 325 repo.adddatafilter(name, fn)
324 326
325 327 ui.setconfig('patch', 'eol', 'auto', 'eol')
326 328
327 329 class eolrepo(repo.__class__):
328 330
329 331 def loadeol(self, nodes):
330 332 eol = parseeol(self.ui, self, nodes)
331 333 if eol is None:
332 334 return None
333 335 eol.copytoui(self.ui)
334 336 return eol.match
335 337
336 338 def _hgcleardirstate(self):
337 339 self._eolmatch = self.loadeol([None, 'tip'])
338 340 if not self._eolmatch:
339 341 self._eolmatch = util.never
340 342 return
341 343
342 344 oldeol = None
343 345 try:
344 346 cachemtime = os.path.getmtime(self.vfs.join("eol.cache"))
345 347 except OSError:
346 348 cachemtime = 0
347 349 else:
348 350 olddata = self.vfs.read("eol.cache")
349 351 if olddata:
350 352 oldeol = eolfile(self.ui, self.root, olddata)
351 353
352 354 try:
353 355 eolmtime = os.path.getmtime(self.wjoin(".hgeol"))
354 356 except OSError:
355 357 eolmtime = 0
356 358
357 359 if eolmtime > cachemtime:
358 360 self.ui.debug("eol: detected change in .hgeol\n")
359 361
360 362 hgeoldata = self.wvfs.read('.hgeol')
361 363 neweol = eolfile(self.ui, self.root, hgeoldata)
362 364
363 365 wlock = None
364 366 try:
365 367 wlock = self.wlock()
366 368 for f in self.dirstate:
367 369 if self.dirstate[f] != 'n':
368 370 continue
369 371 if oldeol is not None:
370 372 if not oldeol.match(f) and not neweol.match(f):
371 373 continue
372 374 oldkey = None
373 375 for pattern, key, m in oldeol.patterns:
374 376 if m(f):
375 377 oldkey = key
376 378 break
377 379 newkey = None
378 380 for pattern, key, m in neweol.patterns:
379 381 if m(f):
380 382 newkey = key
381 383 break
382 384 if oldkey == newkey:
383 385 continue
384 386 # all normal files need to be looked at again since
385 387 # the new .hgeol file specify a different filter
386 388 self.dirstate.normallookup(f)
387 389 # Write the cache to update mtime and cache .hgeol
388 390 with self.vfs("eol.cache", "w") as f:
389 391 f.write(hgeoldata)
390 392 except errormod.LockUnavailable:
391 393 # If we cannot lock the repository and clear the
392 394 # dirstate, then a commit might not see all files
393 395 # as modified. But if we cannot lock the
394 396 # repository, then we can also not make a commit,
395 397 # so ignore the error.
396 398 pass
397 399 finally:
398 400 if wlock is not None:
399 401 wlock.release()
400 402
401 403 def commitctx(self, ctx, error=False):
402 404 for f in sorted(ctx.added() + ctx.modified()):
403 405 if not self._eolmatch(f):
404 406 continue
405 407 fctx = ctx[f]
406 408 if fctx is None:
407 409 continue
408 410 data = fctx.data()
409 411 if stringutil.binary(data):
410 412 # We should not abort here, since the user should
411 413 # be able to say "** = native" to automatically
412 414 # have all non-binary files taken care of.
413 415 continue
414 416 if inconsistenteol(data):
415 417 raise errormod.Abort(_("inconsistent newline style "
416 418 "in %s\n") % f)
417 419 return super(eolrepo, self).commitctx(ctx, error)
418 420 repo.__class__ = eolrepo
419 421 repo._hgcleardirstate()
@@ -1,376 +1,375 b''
1 1 setup
2 2 $ cat >> $HGRCPATH <<EOF
3 3 > [extensions]
4 4 > blackbox=
5 5 > mock=$TESTDIR/mockblackbox.py
6 6 > mq=
7 7 > [alias]
8 8 > confuse = log --limit 3
9 9 > so-confusing = confuse --style compact
10 10 > EOF
11 11 $ hg init blackboxtest
12 12 $ cd blackboxtest
13 13
14 14 command, exit codes, and duration
15 15
16 16 $ echo a > a
17 17 $ hg add a
18 18 $ hg blackbox --config blackbox.dirty=True
19 19 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> init blackboxtest exited 0 after * seconds (glob)
20 20 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> add a
21 21 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> add a exited 0 after * seconds (glob)
22 22 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000+ (5000)> blackbox --config *blackbox.dirty=True* (glob)
23 23
24 24 alias expansion is logged
25 25 $ rm ./.hg/blackbox.log
26 26 $ hg confuse
27 27 $ hg blackbox
28 28 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> confuse
29 29 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> alias 'confuse' expands to 'log --limit 3'
30 30 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> confuse exited 0 after * seconds (glob)
31 31 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> blackbox
32 32
33 33 recursive aliases work correctly
34 34 $ rm ./.hg/blackbox.log
35 35 $ hg so-confusing
36 36 $ hg blackbox
37 37 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> so-confusing
38 38 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> alias 'so-confusing' expands to 'confuse --style compact'
39 39 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> alias 'confuse' expands to 'log --limit 3'
40 40 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> so-confusing exited 0 after * seconds (glob)
41 41 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> blackbox
42 42
43 43 incoming change tracking
44 44
45 45 create two heads to verify that we only see one change in the log later
46 46 $ hg commit -ma
47 47 $ hg up null
48 48 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
49 49 $ echo b > b
50 50 $ hg commit -Amb
51 51 adding b
52 52 created new head
53 53
54 54 clone, commit, pull
55 55 $ hg clone . ../blackboxtest2
56 56 updating to branch default
57 57 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
58 58 $ echo c > c
59 59 $ hg commit -Amc
60 60 adding c
61 61 $ cd ../blackboxtest2
62 62 $ hg pull
63 63 pulling from $TESTTMP/blackboxtest
64 64 searching for changes
65 65 adding changesets
66 66 adding manifests
67 67 adding file changes
68 68 added 1 changesets with 1 changes to 1 files
69 69 new changesets d02f48003e62
70 70 (run 'hg update' to get a working copy)
71 71 $ hg blackbox -l 6
72 72 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> pull
73 73 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> updated served branch cache in * seconds (glob)
74 74 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> wrote served branch cache with 1 labels and 2 nodes
75 75 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> 1 incoming changes - new heads: d02f48003e62
76 76 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> pull exited 0 after * seconds (glob)
77 77 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> blackbox -l 6
78 78
79 79 we must not cause a failure if we cannot write to the log
80 80
81 81 $ hg rollback
82 82 repository tip rolled back to revision 1 (undo pull)
83 83
84 84 $ mv .hg/blackbox.log .hg/blackbox.log-
85 85 $ mkdir .hg/blackbox.log
86 86 $ hg --debug incoming
87 87 warning: cannot write to blackbox.log: * (glob)
88 88 comparing with $TESTTMP/blackboxtest
89 89 query 1; heads
90 90 searching for changes
91 91 all local heads known remotely
92 92 changeset: 2:d02f48003e62c24e2659d97d30f2a83abe5d5d51
93 93 tag: tip
94 94 phase: draft
95 95 parent: 1:6563da9dcf87b1949716e38ff3e3dfaa3198eb06
96 96 parent: -1:0000000000000000000000000000000000000000
97 97 manifest: 2:ab9d46b053ebf45b7996f2922b9893ff4b63d892
98 98 user: test
99 99 date: Thu Jan 01 00:00:00 1970 +0000
100 100 files+: c
101 101 extra: branch=default
102 102 description:
103 103 c
104 104
105 105
106 106 $ hg pull
107 107 pulling from $TESTTMP/blackboxtest
108 108 searching for changes
109 109 adding changesets
110 110 adding manifests
111 111 adding file changes
112 112 added 1 changesets with 1 changes to 1 files
113 113 new changesets d02f48003e62
114 114 (run 'hg update' to get a working copy)
115 115
116 116 a failure reading from the log is fatal
117 117
118 118 $ hg blackbox -l 3
119 119 abort: *$TESTTMP/blackboxtest2/.hg/blackbox.log* (glob)
120 120 [255]
121 121
122 122 $ rmdir .hg/blackbox.log
123 123 $ mv .hg/blackbox.log- .hg/blackbox.log
124 124
125 125 backup bundles get logged
126 126
127 127 $ touch d
128 128 $ hg commit -Amd
129 129 adding d
130 130 created new head
131 131 $ hg strip tip
132 132 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
133 133 saved backup bundle to $TESTTMP/blackboxtest2/.hg/strip-backup/*-backup.hg (glob)
134 134 $ hg blackbox -l 6
135 135 1970/01/01 00:00:00 bob @73f6ee326b27d820b0472f1a825e3a50f3dc489b (5000)> strip tip
136 136 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> saved backup bundle to $TESTTMP/blackboxtest2/.hg/strip-backup/73f6ee326b27-7612e004-backup.hg
137 137 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> updated base branch cache in * seconds (glob)
138 138 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> wrote base branch cache with 1 labels and 2 nodes
139 139 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> strip tip exited 0 after * seconds (glob)
140 140 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> blackbox -l 6
141 141
142 142 extension and python hooks - use the eol extension for a pythonhook
143 143
144 144 $ echo '[extensions]' >> .hg/hgrc
145 145 $ echo 'eol=' >> .hg/hgrc
146 146 $ echo '[hooks]' >> .hg/hgrc
147 147 $ echo 'update = echo hooked' >> .hg/hgrc
148 148 $ hg update
149 149 The fsmonitor extension is incompatible with the eol extension and has been disabled. (fsmonitor !)
150 150 hooked
151 151 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
152 152 updated to "d02f48003e62: c"
153 153 1 other heads for branch "default"
154 154 $ cat >> .hg/hgrc <<EOF
155 155 > [extensions]
156 156 > # disable eol, because it is not needed for subsequent tests
157 157 > # (in addition, keeping it requires extra care for fsmonitor)
158 158 > eol=!
159 159 > EOF
160 $ hg blackbox -l 6
160 $ hg blackbox -l 5
161 161 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> update (no-chg !)
162 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> writing .hg/cache/tags2-visible with 0 tags
163 162 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> pythonhook-preupdate: hgext.eol.preupdate finished in * seconds (glob)
164 163 1970/01/01 00:00:00 bob @d02f48003e62c24e2659d97d30f2a83abe5d5d51 (5000)> exthook-update: echo hooked finished in * seconds (glob)
165 164 1970/01/01 00:00:00 bob @d02f48003e62c24e2659d97d30f2a83abe5d5d51 (5000)> update exited 0 after * seconds (glob)
166 165 1970/01/01 00:00:00 bob @d02f48003e62c24e2659d97d30f2a83abe5d5d51 (5000)> serve --cmdserver chgunix --address $TESTTMP.chgsock/server.* --daemon-postexec 'chdir:/' (glob) (chg !)
167 1970/01/01 00:00:00 bob @d02f48003e62c24e2659d97d30f2a83abe5d5d51 (5000)> blackbox -l 6
166 1970/01/01 00:00:00 bob @d02f48003e62c24e2659d97d30f2a83abe5d5d51 (5000)> blackbox -l 5
168 167
169 168 log rotation
170 169
171 170 $ echo '[blackbox]' >> .hg/hgrc
172 171 $ echo 'maxsize = 20 b' >> .hg/hgrc
173 172 $ echo 'maxfiles = 3' >> .hg/hgrc
174 173 $ hg status
175 174 $ hg status
176 175 $ hg status
177 176 $ hg tip -q
178 177 2:d02f48003e62
179 178 $ ls .hg/blackbox.log*
180 179 .hg/blackbox.log
181 180 .hg/blackbox.log.1
182 181 .hg/blackbox.log.2
183 182 $ cd ..
184 183
185 184 $ hg init blackboxtest3
186 185 $ cd blackboxtest3
187 186 $ hg blackbox
188 187 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> init blackboxtest3 exited 0 after * seconds (glob)
189 188 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> blackbox
190 189 $ mv .hg/blackbox.log .hg/blackbox.log-
191 190 $ mkdir .hg/blackbox.log
192 191 $ sed -e 's/\(.*test1.*\)/#\1/; s#\(.*commit2.*\)#os.rmdir(".hg/blackbox.log")\
193 192 > os.rename(".hg/blackbox.log-", ".hg/blackbox.log")\
194 193 > \1#' $TESTDIR/test-dispatch.py > ../test-dispatch.py
195 194 $ $PYTHON $TESTDIR/blackbox-readonly-dispatch.py
196 195 running: --debug add foo
197 196 warning: cannot write to blackbox.log: Is a directory (no-windows !)
198 197 warning: cannot write to blackbox.log: $TESTTMP/blackboxtest3/.hg/blackbox.log: Access is denied (windows !)
199 198 adding foo
200 199 result: 0
201 200 running: --debug commit -m commit1 -d 2000-01-01 foo
202 201 warning: cannot write to blackbox.log: Is a directory (no-windows !)
203 202 warning: cannot write to blackbox.log: $TESTTMP/blackboxtest3/.hg/blackbox.log: Access is denied (windows !)
204 203 committing files:
205 204 foo
206 205 committing manifest
207 206 committing changelog
208 207 updating the branch cache
209 208 committed changeset 0:0e46349438790c460c5c9f7546bfcd39b267bbd2
210 209 result: None
211 210 running: --debug commit -m commit2 -d 2000-01-02 foo
212 211 committing files:
213 212 foo
214 213 committing manifest
215 214 committing changelog
216 215 updating the branch cache
217 216 committed changeset 1:45589e459b2edfbf3dbde7e01f611d2c1e7453d7
218 217 result: None
219 218 running: --debug log -r 0
220 219 changeset: 0:0e46349438790c460c5c9f7546bfcd39b267bbd2
221 220 phase: draft
222 221 parent: -1:0000000000000000000000000000000000000000
223 222 parent: -1:0000000000000000000000000000000000000000
224 223 manifest: 0:9091aa5df980aea60860a2e39c95182e68d1ddec
225 224 user: test
226 225 date: Sat Jan 01 00:00:00 2000 +0000
227 226 files+: foo
228 227 extra: branch=default
229 228 description:
230 229 commit1
231 230
232 231
233 232 result: None
234 233 running: --debug log -r tip
235 234 changeset: 1:45589e459b2edfbf3dbde7e01f611d2c1e7453d7
236 235 tag: tip
237 236 phase: draft
238 237 parent: 0:0e46349438790c460c5c9f7546bfcd39b267bbd2
239 238 parent: -1:0000000000000000000000000000000000000000
240 239 manifest: 1:895aa9b7886f89dd017a6d62524e1f9180b04df9
241 240 user: test
242 241 date: Sun Jan 02 00:00:00 2000 +0000
243 242 files: foo
244 243 extra: branch=default
245 244 description:
246 245 commit2
247 246
248 247
249 248 result: None
250 249 $ hg blackbox
251 250 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> updating the branch cache
252 251 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> updated served branch cache in * seconds (glob)
253 252 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> wrote served branch cache with 1 labels and 1 nodes
254 253 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> --debug commit -m commit2 -d 2000-01-02 foo exited 0 after *.?? seconds (glob)
255 254 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> --debug log -r 0
256 255 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> writing .hg/cache/tags2-visible with 0 tags
257 256 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> --debug log -r 0 exited 0 after *.?? seconds (glob)
258 257 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> --debug log -r tip
259 258 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> --debug log -r tip exited 0 after *.?? seconds (glob)
260 259 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> blackbox
261 260
262 261 Test log recursion from dirty status check
263 262
264 263 $ cat > ../r.py <<EOF
265 264 > from mercurial import context, error, extensions
266 265 > x=[False]
267 266 > def status(orig, *args, **opts):
268 267 > args[0].repo().ui.log(b"broken", b"recursion?")
269 268 > return orig(*args, **opts)
270 269 > def reposetup(ui, repo):
271 270 > extensions.wrapfunction(context.basectx, 'status', status)
272 271 > EOF
273 272 $ hg id --config extensions.x=../r.py --config blackbox.dirty=True
274 273 45589e459b2e tip
275 274
276 275 cleanup
277 276 $ cd ..
278 277
279 278 #if chg
280 279
281 280 when using chg, blackbox.log should get rotated correctly
282 281
283 282 $ cat > $TESTTMP/noop.py << EOF
284 283 > from __future__ import absolute_import
285 284 > import time
286 285 > from mercurial import registrar, scmutil
287 286 > cmdtable = {}
288 287 > command = registrar.command(cmdtable)
289 288 > @command('noop')
290 289 > def noop(ui, repo):
291 290 > pass
292 291 > EOF
293 292
294 293 $ hg init blackbox-chg
295 294 $ cd blackbox-chg
296 295
297 296 $ cat > .hg/hgrc << EOF
298 297 > [blackbox]
299 298 > maxsize = 500B
300 299 > [extensions]
301 300 > # extension change forces chg to restart
302 301 > noop=$TESTTMP/noop.py
303 302 > EOF
304 303
305 304 $ $PYTHON -c 'print("a" * 400)' > .hg/blackbox.log
306 305 $ chg noop
307 306 $ chg noop
308 307 $ chg noop
309 308 $ chg noop
310 309 $ chg noop
311 310
312 311 $ cat > showsize.py << 'EOF'
313 312 > import os, sys
314 313 > limit = 500
315 314 > for p in sys.argv[1:]:
316 315 > size = os.stat(p).st_size
317 316 > if size >= limit:
318 317 > desc = '>='
319 318 > else:
320 319 > desc = '<'
321 320 > print('%s: %s %d' % (p, desc, limit))
322 321 > EOF
323 322
324 323 $ $PYTHON showsize.py .hg/blackbox*
325 324 .hg/blackbox.log: < 500
326 325 .hg/blackbox.log.1: >= 500
327 326 .hg/blackbox.log.2: >= 500
328 327
329 328 $ cd ..
330 329
331 330 With chg, blackbox should not create the log file if the repo is gone
332 331
333 332 $ hg init repo1
334 333 $ hg --config extensions.a=! -R repo1 log
335 334 $ rm -rf $TESTTMP/repo1
336 335 $ hg --config extensions.a=! init repo1
337 336
338 337 #endif
339 338
340 339 blackbox should work if repo.ui.log is not called (issue5518)
341 340
342 341 $ cat > $TESTTMP/raise.py << EOF
343 342 > from __future__ import absolute_import
344 343 > from mercurial import registrar, scmutil
345 344 > cmdtable = {}
346 345 > command = registrar.command(cmdtable)
347 346 > @command(b'raise')
348 347 > def raisecmd(*args):
349 348 > raise RuntimeError('raise')
350 349 > EOF
351 350
352 351 $ cat >> $HGRCPATH << EOF
353 352 > [blackbox]
354 353 > track = commandexception
355 354 > [extensions]
356 355 > raise=$TESTTMP/raise.py
357 356 > EOF
358 357
359 358 $ hg init $TESTTMP/blackbox-exception-only
360 359 $ cd $TESTTMP/blackbox-exception-only
361 360
362 361 #if chg
363 362 (chg exits 255 because it fails to receive an exit code)
364 363 $ hg raise 2>/dev/null
365 364 [255]
366 365 #else
367 366 (hg exits 1 because Python default exit code for uncaught exception is 1)
368 367 $ hg raise 2>/dev/null
369 368 [1]
370 369 #endif
371 370
372 371 $ head -1 .hg/blackbox.log
373 372 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> ** Unknown exception encountered with possibly-broken third-party extension mock
374 373 $ tail -2 .hg/blackbox.log
375 374 RuntimeError: raise
376 375
General Comments 0
You need to be logged in to leave comments. Login now