##// END OF EJS Templates
stringutil: fix prettyrepr() to not orphan foo=<...> line
Yuya Nishihara -
r38283:fbb2edde default
parent child Browse files
Show More
@@ -1,530 +1,541 b''
1 1 # stringutil.py - utility for generic string formatting, parsing, etc.
2 2 #
3 3 # Copyright 2005 K. Thananchayan <thananck@yahoo.com>
4 4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
5 5 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
6 6 #
7 7 # This software may be used and distributed according to the terms of the
8 8 # GNU General Public License version 2 or any later version.
9 9
10 10 from __future__ import absolute_import
11 11
12 12 import ast
13 13 import codecs
14 14 import re as remod
15 15 import textwrap
16 16
17 17 from ..i18n import _
18 18 from ..thirdparty import attr
19 19
20 20 from .. import (
21 21 encoding,
22 22 error,
23 23 pycompat,
24 24 )
25 25
26 26 def pprint(o, bprefix=False):
27 27 """Pretty print an object."""
28 28 if isinstance(o, bytes):
29 29 if bprefix:
30 30 return "b'%s'" % escapestr(o)
31 31 return "'%s'" % escapestr(o)
32 32 elif isinstance(o, bytearray):
33 33 # codecs.escape_encode() can't handle bytearray, so escapestr fails
34 34 # without coercion.
35 35 return "bytearray['%s']" % escapestr(bytes(o))
36 36 elif isinstance(o, list):
37 37 return '[%s]' % (b', '.join(pprint(a, bprefix=bprefix) for a in o))
38 38 elif isinstance(o, dict):
39 39 return '{%s}' % (b', '.join(
40 40 '%s: %s' % (pprint(k, bprefix=bprefix),
41 41 pprint(v, bprefix=bprefix))
42 42 for k, v in sorted(o.items())))
43 43 elif isinstance(o, tuple):
44 44 return '(%s)' % (b', '.join(pprint(a, bprefix=bprefix) for a in o))
45 45 else:
46 46 return pycompat.byterepr(o)
47 47
48 48 def prettyrepr(o):
49 49 """Pretty print a representation of a possibly-nested object"""
50 50 lines = []
51 51 rs = pycompat.byterepr(o)
52 p = 0
53 while p < len(rs):
54 q = rs.find('<', p + 1)
55 if q < 0:
56 q = len(rs)
57 l = rs.count('<', 0, p) - rs.count('>', 0, p)
52 p0 = p1 = 0
53 while p0 < len(rs):
54 # '... field=<type ... field=<type ...'
55 # ~~~~~~~~~~~~~~~~
56 # p0 p1 q0 q1
57 q0 = -1
58 q1 = rs.find('<', p1 + 1)
59 if q1 < 0:
60 q1 = len(rs)
61 elif q1 > p1 + 1 and rs.startswith('=', q1 - 1):
62 # backtrack for ' field=<'
63 q0 = rs.rfind(' ', p1 + 1, q1 - 1)
64 if q0 < 0:
65 q0 = q1
66 else:
67 q0 += 1 # skip ' '
68 l = rs.count('<', 0, p0) - rs.count('>', 0, p0)
58 69 assert l >= 0
59 lines.append((l, rs[p:q].rstrip()))
60 p = q
70 lines.append((l, rs[p0:q0].rstrip()))
71 p0, p1 = q0, q1
61 72 return '\n'.join(' ' * l + s for l, s in lines)
62 73
63 74 def binary(s):
64 75 """return true if a string is binary data"""
65 76 return bool(s and '\0' in s)
66 77
67 78 def stringmatcher(pattern, casesensitive=True):
68 79 """
69 80 accepts a string, possibly starting with 're:' or 'literal:' prefix.
70 81 returns the matcher name, pattern, and matcher function.
71 82 missing or unknown prefixes are treated as literal matches.
72 83
73 84 helper for tests:
74 85 >>> def test(pattern, *tests):
75 86 ... kind, pattern, matcher = stringmatcher(pattern)
76 87 ... return (kind, pattern, [bool(matcher(t)) for t in tests])
77 88 >>> def itest(pattern, *tests):
78 89 ... kind, pattern, matcher = stringmatcher(pattern, casesensitive=False)
79 90 ... return (kind, pattern, [bool(matcher(t)) for t in tests])
80 91
81 92 exact matching (no prefix):
82 93 >>> test(b'abcdefg', b'abc', b'def', b'abcdefg')
83 94 ('literal', 'abcdefg', [False, False, True])
84 95
85 96 regex matching ('re:' prefix)
86 97 >>> test(b're:a.+b', b'nomatch', b'fooadef', b'fooadefbar')
87 98 ('re', 'a.+b', [False, False, True])
88 99
89 100 force exact matches ('literal:' prefix)
90 101 >>> test(b'literal:re:foobar', b'foobar', b're:foobar')
91 102 ('literal', 're:foobar', [False, True])
92 103
93 104 unknown prefixes are ignored and treated as literals
94 105 >>> test(b'foo:bar', b'foo', b'bar', b'foo:bar')
95 106 ('literal', 'foo:bar', [False, False, True])
96 107
97 108 case insensitive regex matches
98 109 >>> itest(b're:A.+b', b'nomatch', b'fooadef', b'fooadefBar')
99 110 ('re', 'A.+b', [False, False, True])
100 111
101 112 case insensitive literal matches
102 113 >>> itest(b'ABCDEFG', b'abc', b'def', b'abcdefg')
103 114 ('literal', 'ABCDEFG', [False, False, True])
104 115 """
105 116 if pattern.startswith('re:'):
106 117 pattern = pattern[3:]
107 118 try:
108 119 flags = 0
109 120 if not casesensitive:
110 121 flags = remod.I
111 122 regex = remod.compile(pattern, flags)
112 123 except remod.error as e:
113 124 raise error.ParseError(_('invalid regular expression: %s')
114 125 % e)
115 126 return 're', pattern, regex.search
116 127 elif pattern.startswith('literal:'):
117 128 pattern = pattern[8:]
118 129
119 130 match = pattern.__eq__
120 131
121 132 if not casesensitive:
122 133 ipat = encoding.lower(pattern)
123 134 match = lambda s: ipat == encoding.lower(s)
124 135 return 'literal', pattern, match
125 136
126 137 def shortuser(user):
127 138 """Return a short representation of a user name or email address."""
128 139 f = user.find('@')
129 140 if f >= 0:
130 141 user = user[:f]
131 142 f = user.find('<')
132 143 if f >= 0:
133 144 user = user[f + 1:]
134 145 f = user.find(' ')
135 146 if f >= 0:
136 147 user = user[:f]
137 148 f = user.find('.')
138 149 if f >= 0:
139 150 user = user[:f]
140 151 return user
141 152
142 153 def emailuser(user):
143 154 """Return the user portion of an email address."""
144 155 f = user.find('@')
145 156 if f >= 0:
146 157 user = user[:f]
147 158 f = user.find('<')
148 159 if f >= 0:
149 160 user = user[f + 1:]
150 161 return user
151 162
152 163 def email(author):
153 164 '''get email of author.'''
154 165 r = author.find('>')
155 166 if r == -1:
156 167 r = None
157 168 return author[author.find('<') + 1:r]
158 169
159 170 def person(author):
160 171 """Returns the name before an email address,
161 172 interpreting it as per RFC 5322
162 173
163 174 >>> person(b'foo@bar')
164 175 'foo'
165 176 >>> person(b'Foo Bar <foo@bar>')
166 177 'Foo Bar'
167 178 >>> person(b'"Foo Bar" <foo@bar>')
168 179 'Foo Bar'
169 180 >>> person(b'"Foo \"buz\" Bar" <foo@bar>')
170 181 'Foo "buz" Bar'
171 182 >>> # The following are invalid, but do exist in real-life
172 183 ...
173 184 >>> person(b'Foo "buz" Bar <foo@bar>')
174 185 'Foo "buz" Bar'
175 186 >>> person(b'"Foo Bar <foo@bar>')
176 187 'Foo Bar'
177 188 """
178 189 if '@' not in author:
179 190 return author
180 191 f = author.find('<')
181 192 if f != -1:
182 193 return author[:f].strip(' "').replace('\\"', '"')
183 194 f = author.find('@')
184 195 return author[:f].replace('.', ' ')
185 196
186 197 @attr.s(hash=True)
187 198 class mailmapping(object):
188 199 '''Represents a username/email key or value in
189 200 a mailmap file'''
190 201 email = attr.ib()
191 202 name = attr.ib(default=None)
192 203
193 204 def _ismailmaplineinvalid(names, emails):
194 205 '''Returns True if the parsed names and emails
195 206 in a mailmap entry are invalid.
196 207
197 208 >>> # No names or emails fails
198 209 >>> names, emails = [], []
199 210 >>> _ismailmaplineinvalid(names, emails)
200 211 True
201 212 >>> # Only one email fails
202 213 >>> emails = [b'email@email.com']
203 214 >>> _ismailmaplineinvalid(names, emails)
204 215 True
205 216 >>> # One email and one name passes
206 217 >>> names = [b'Test Name']
207 218 >>> _ismailmaplineinvalid(names, emails)
208 219 False
209 220 >>> # No names but two emails passes
210 221 >>> names = []
211 222 >>> emails = [b'proper@email.com', b'commit@email.com']
212 223 >>> _ismailmaplineinvalid(names, emails)
213 224 False
214 225 '''
215 226 return not emails or not names and len(emails) < 2
216 227
217 228 def parsemailmap(mailmapcontent):
218 229 """Parses data in the .mailmap format
219 230
220 231 >>> mmdata = b"\\n".join([
221 232 ... b'# Comment',
222 233 ... b'Name <commit1@email.xx>',
223 234 ... b'<name@email.xx> <commit2@email.xx>',
224 235 ... b'Name <proper@email.xx> <commit3@email.xx>',
225 236 ... b'Name <proper@email.xx> Commit <commit4@email.xx>',
226 237 ... ])
227 238 >>> mm = parsemailmap(mmdata)
228 239 >>> for key in sorted(mm.keys()):
229 240 ... print(key)
230 241 mailmapping(email='commit1@email.xx', name=None)
231 242 mailmapping(email='commit2@email.xx', name=None)
232 243 mailmapping(email='commit3@email.xx', name=None)
233 244 mailmapping(email='commit4@email.xx', name='Commit')
234 245 >>> for val in sorted(mm.values()):
235 246 ... print(val)
236 247 mailmapping(email='commit1@email.xx', name='Name')
237 248 mailmapping(email='name@email.xx', name=None)
238 249 mailmapping(email='proper@email.xx', name='Name')
239 250 mailmapping(email='proper@email.xx', name='Name')
240 251 """
241 252 mailmap = {}
242 253
243 254 if mailmapcontent is None:
244 255 return mailmap
245 256
246 257 for line in mailmapcontent.splitlines():
247 258
248 259 # Don't bother checking the line if it is a comment or
249 260 # is an improperly formed author field
250 261 if line.lstrip().startswith('#'):
251 262 continue
252 263
253 264 # names, emails hold the parsed emails and names for each line
254 265 # name_builder holds the words in a persons name
255 266 names, emails = [], []
256 267 namebuilder = []
257 268
258 269 for element in line.split():
259 270 if element.startswith('#'):
260 271 # If we reach a comment in the mailmap file, move on
261 272 break
262 273
263 274 elif element.startswith('<') and element.endswith('>'):
264 275 # We have found an email.
265 276 # Parse it, and finalize any names from earlier
266 277 emails.append(element[1:-1]) # Slice off the "<>"
267 278
268 279 if namebuilder:
269 280 names.append(' '.join(namebuilder))
270 281 namebuilder = []
271 282
272 283 # Break if we have found a second email, any other
273 284 # data does not fit the spec for .mailmap
274 285 if len(emails) > 1:
275 286 break
276 287
277 288 else:
278 289 # We have found another word in the committers name
279 290 namebuilder.append(element)
280 291
281 292 # Check to see if we have parsed the line into a valid form
282 293 # We require at least one email, and either at least one
283 294 # name or a second email
284 295 if _ismailmaplineinvalid(names, emails):
285 296 continue
286 297
287 298 mailmapkey = mailmapping(
288 299 email=emails[-1],
289 300 name=names[-1] if len(names) == 2 else None,
290 301 )
291 302
292 303 mailmap[mailmapkey] = mailmapping(
293 304 email=emails[0],
294 305 name=names[0] if names else None,
295 306 )
296 307
297 308 return mailmap
298 309
299 310 def mapname(mailmap, author):
300 311 """Returns the author field according to the mailmap cache, or
301 312 the original author field.
302 313
303 314 >>> mmdata = b"\\n".join([
304 315 ... b'# Comment',
305 316 ... b'Name <commit1@email.xx>',
306 317 ... b'<name@email.xx> <commit2@email.xx>',
307 318 ... b'Name <proper@email.xx> <commit3@email.xx>',
308 319 ... b'Name <proper@email.xx> Commit <commit4@email.xx>',
309 320 ... ])
310 321 >>> m = parsemailmap(mmdata)
311 322 >>> mapname(m, b'Commit <commit1@email.xx>')
312 323 'Name <commit1@email.xx>'
313 324 >>> mapname(m, b'Name <commit2@email.xx>')
314 325 'Name <name@email.xx>'
315 326 >>> mapname(m, b'Commit <commit3@email.xx>')
316 327 'Name <proper@email.xx>'
317 328 >>> mapname(m, b'Commit <commit4@email.xx>')
318 329 'Name <proper@email.xx>'
319 330 >>> mapname(m, b'Unknown Name <unknown@email.com>')
320 331 'Unknown Name <unknown@email.com>'
321 332 """
322 333 # If the author field coming in isn't in the correct format,
323 334 # or the mailmap is empty just return the original author field
324 335 if not isauthorwellformed(author) or not mailmap:
325 336 return author
326 337
327 338 # Turn the user name into a mailmapping
328 339 commit = mailmapping(name=person(author), email=email(author))
329 340
330 341 try:
331 342 # Try and use both the commit email and name as the key
332 343 proper = mailmap[commit]
333 344
334 345 except KeyError:
335 346 # If the lookup fails, use just the email as the key instead
336 347 # We call this commit2 as not to erase original commit fields
337 348 commit2 = mailmapping(email=commit.email)
338 349 proper = mailmap.get(commit2, mailmapping(None, None))
339 350
340 351 # Return the author field with proper values filled in
341 352 return '%s <%s>' % (
342 353 proper.name if proper.name else commit.name,
343 354 proper.email if proper.email else commit.email,
344 355 )
345 356
346 357 _correctauthorformat = remod.compile(br'^[^<]+\s\<[^<>]+@[^<>]+\>$')
347 358
348 359 def isauthorwellformed(author):
349 360 '''Return True if the author field is well formed
350 361 (ie "Contributor Name <contrib@email.dom>")
351 362
352 363 >>> isauthorwellformed(b'Good Author <good@author.com>')
353 364 True
354 365 >>> isauthorwellformed(b'Author <good@author.com>')
355 366 True
356 367 >>> isauthorwellformed(b'Bad Author')
357 368 False
358 369 >>> isauthorwellformed(b'Bad Author <author@author.com')
359 370 False
360 371 >>> isauthorwellformed(b'Bad Author author@author.com')
361 372 False
362 373 >>> isauthorwellformed(b'<author@author.com>')
363 374 False
364 375 >>> isauthorwellformed(b'Bad Author <author>')
365 376 False
366 377 '''
367 378 return _correctauthorformat.match(author) is not None
368 379
369 380 def ellipsis(text, maxlength=400):
370 381 """Trim string to at most maxlength (default: 400) columns in display."""
371 382 return encoding.trim(text, maxlength, ellipsis='...')
372 383
373 384 def escapestr(s):
374 385 # call underlying function of s.encode('string_escape') directly for
375 386 # Python 3 compatibility
376 387 return codecs.escape_encode(s)[0]
377 388
378 389 def unescapestr(s):
379 390 return codecs.escape_decode(s)[0]
380 391
381 392 def forcebytestr(obj):
382 393 """Portably format an arbitrary object (e.g. exception) into a byte
383 394 string."""
384 395 try:
385 396 return pycompat.bytestr(obj)
386 397 except UnicodeEncodeError:
387 398 # non-ascii string, may be lossy
388 399 return pycompat.bytestr(encoding.strtolocal(str(obj)))
389 400
390 401 def uirepr(s):
391 402 # Avoid double backslash in Windows path repr()
392 403 return pycompat.byterepr(pycompat.bytestr(s)).replace(b'\\\\', b'\\')
393 404
394 405 # delay import of textwrap
395 406 def _MBTextWrapper(**kwargs):
396 407 class tw(textwrap.TextWrapper):
397 408 """
398 409 Extend TextWrapper for width-awareness.
399 410
400 411 Neither number of 'bytes' in any encoding nor 'characters' is
401 412 appropriate to calculate terminal columns for specified string.
402 413
403 414 Original TextWrapper implementation uses built-in 'len()' directly,
404 415 so overriding is needed to use width information of each characters.
405 416
406 417 In addition, characters classified into 'ambiguous' width are
407 418 treated as wide in East Asian area, but as narrow in other.
408 419
409 420 This requires use decision to determine width of such characters.
410 421 """
411 422 def _cutdown(self, ucstr, space_left):
412 423 l = 0
413 424 colwidth = encoding.ucolwidth
414 425 for i in xrange(len(ucstr)):
415 426 l += colwidth(ucstr[i])
416 427 if space_left < l:
417 428 return (ucstr[:i], ucstr[i:])
418 429 return ucstr, ''
419 430
420 431 # overriding of base class
421 432 def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width):
422 433 space_left = max(width - cur_len, 1)
423 434
424 435 if self.break_long_words:
425 436 cut, res = self._cutdown(reversed_chunks[-1], space_left)
426 437 cur_line.append(cut)
427 438 reversed_chunks[-1] = res
428 439 elif not cur_line:
429 440 cur_line.append(reversed_chunks.pop())
430 441
431 442 # this overriding code is imported from TextWrapper of Python 2.6
432 443 # to calculate columns of string by 'encoding.ucolwidth()'
433 444 def _wrap_chunks(self, chunks):
434 445 colwidth = encoding.ucolwidth
435 446
436 447 lines = []
437 448 if self.width <= 0:
438 449 raise ValueError("invalid width %r (must be > 0)" % self.width)
439 450
440 451 # Arrange in reverse order so items can be efficiently popped
441 452 # from a stack of chucks.
442 453 chunks.reverse()
443 454
444 455 while chunks:
445 456
446 457 # Start the list of chunks that will make up the current line.
447 458 # cur_len is just the length of all the chunks in cur_line.
448 459 cur_line = []
449 460 cur_len = 0
450 461
451 462 # Figure out which static string will prefix this line.
452 463 if lines:
453 464 indent = self.subsequent_indent
454 465 else:
455 466 indent = self.initial_indent
456 467
457 468 # Maximum width for this line.
458 469 width = self.width - len(indent)
459 470
460 471 # First chunk on line is whitespace -- drop it, unless this
461 472 # is the very beginning of the text (i.e. no lines started yet).
462 473 if self.drop_whitespace and chunks[-1].strip() == r'' and lines:
463 474 del chunks[-1]
464 475
465 476 while chunks:
466 477 l = colwidth(chunks[-1])
467 478
468 479 # Can at least squeeze this chunk onto the current line.
469 480 if cur_len + l <= width:
470 481 cur_line.append(chunks.pop())
471 482 cur_len += l
472 483
473 484 # Nope, this line is full.
474 485 else:
475 486 break
476 487
477 488 # The current line is full, and the next chunk is too big to
478 489 # fit on *any* line (not just this one).
479 490 if chunks and colwidth(chunks[-1]) > width:
480 491 self._handle_long_word(chunks, cur_line, cur_len, width)
481 492
482 493 # If the last chunk on this line is all whitespace, drop it.
483 494 if (self.drop_whitespace and
484 495 cur_line and cur_line[-1].strip() == r''):
485 496 del cur_line[-1]
486 497
487 498 # Convert current line back to a string and store it in list
488 499 # of all lines (return value).
489 500 if cur_line:
490 501 lines.append(indent + r''.join(cur_line))
491 502
492 503 return lines
493 504
494 505 global _MBTextWrapper
495 506 _MBTextWrapper = tw
496 507 return tw(**kwargs)
497 508
498 509 def wrap(line, width, initindent='', hangindent=''):
499 510 maxindent = max(len(hangindent), len(initindent))
500 511 if width <= maxindent:
501 512 # adjust for weird terminal size
502 513 width = max(78, maxindent + 1)
503 514 line = line.decode(pycompat.sysstr(encoding.encoding),
504 515 pycompat.sysstr(encoding.encodingmode))
505 516 initindent = initindent.decode(pycompat.sysstr(encoding.encoding),
506 517 pycompat.sysstr(encoding.encodingmode))
507 518 hangindent = hangindent.decode(pycompat.sysstr(encoding.encoding),
508 519 pycompat.sysstr(encoding.encodingmode))
509 520 wrapper = _MBTextWrapper(width=width,
510 521 initial_indent=initindent,
511 522 subsequent_indent=hangindent)
512 523 return wrapper.fill(line).encode(pycompat.sysstr(encoding.encoding))
513 524
514 525 _booleans = {'1': True, 'yes': True, 'true': True, 'on': True, 'always': True,
515 526 '0': False, 'no': False, 'false': False, 'off': False,
516 527 'never': False}
517 528
518 529 def parsebool(s):
519 530 """Parse s into a boolean.
520 531
521 532 If s is not a valid boolean, returns None.
522 533 """
523 534 return _booleans.get(s.lower(), None)
524 535
525 536 def evalpythonliteral(s):
526 537 """Evaluate a string containing a Python literal expression"""
527 538 # We could backport our tokenizer hack to rewrite '' to u'' if we want
528 539 if pycompat.ispy3:
529 540 return ast.literal_eval(s.decode('latin1'))
530 541 return ast.literal_eval(s)
@@ -1,652 +1,652 b''
1 1 $ hg init t
2 2 $ cd t
3 3 $ mkdir -p beans
4 4 $ for b in kidney navy turtle borlotti black pinto; do
5 5 > echo $b > beans/$b
6 6 > done
7 7 $ mkdir -p mammals/Procyonidae
8 8 $ for m in cacomistle coatimundi raccoon; do
9 9 > echo $m > mammals/Procyonidae/$m
10 10 > done
11 11 $ echo skunk > mammals/skunk
12 12 $ echo fennel > fennel
13 13 $ echo fenugreek > fenugreek
14 14 $ echo fiddlehead > fiddlehead
15 15 $ hg addremove
16 16 adding beans/black
17 17 adding beans/borlotti
18 18 adding beans/kidney
19 19 adding beans/navy
20 20 adding beans/pinto
21 21 adding beans/turtle
22 22 adding fennel
23 23 adding fenugreek
24 24 adding fiddlehead
25 25 adding mammals/Procyonidae/cacomistle
26 26 adding mammals/Procyonidae/coatimundi
27 27 adding mammals/Procyonidae/raccoon
28 28 adding mammals/skunk
29 29 $ hg commit -m "commit #0"
30 30
31 31 $ hg debugwalk -v
32 32 * matcher:
33 33 <alwaysmatcher>
34 34 f beans/black beans/black
35 35 f beans/borlotti beans/borlotti
36 36 f beans/kidney beans/kidney
37 37 f beans/navy beans/navy
38 38 f beans/pinto beans/pinto
39 39 f beans/turtle beans/turtle
40 40 f fennel fennel
41 41 f fenugreek fenugreek
42 42 f fiddlehead fiddlehead
43 43 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
44 44 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
45 45 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
46 46 f mammals/skunk mammals/skunk
47 47 $ hg debugwalk -v -I.
48 48 * matcher:
49 49 <includematcher includes='(?:)'>
50 50 f beans/black beans/black
51 51 f beans/borlotti beans/borlotti
52 52 f beans/kidney beans/kidney
53 53 f beans/navy beans/navy
54 54 f beans/pinto beans/pinto
55 55 f beans/turtle beans/turtle
56 56 f fennel fennel
57 57 f fenugreek fenugreek
58 58 f fiddlehead fiddlehead
59 59 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
60 60 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
61 61 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
62 62 f mammals/skunk mammals/skunk
63 63
64 64 $ cd mammals
65 65 $ hg debugwalk -v
66 66 * matcher:
67 67 <alwaysmatcher>
68 68 f beans/black ../beans/black
69 69 f beans/borlotti ../beans/borlotti
70 70 f beans/kidney ../beans/kidney
71 71 f beans/navy ../beans/navy
72 72 f beans/pinto ../beans/pinto
73 73 f beans/turtle ../beans/turtle
74 74 f fennel ../fennel
75 75 f fenugreek ../fenugreek
76 76 f fiddlehead ../fiddlehead
77 77 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
78 78 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
79 79 f mammals/Procyonidae/raccoon Procyonidae/raccoon
80 80 f mammals/skunk skunk
81 81 $ hg debugwalk -v -X ../beans
82 82 * matcher:
83 <differencematcher m1=
84 <alwaysmatcher>, m2=
85 <includematcher includes='(?:beans(?:/|$))'>>
83 <differencematcher
84 m1=<alwaysmatcher>,
85 m2=<includematcher includes='(?:beans(?:/|$))'>>
86 86 f fennel ../fennel
87 87 f fenugreek ../fenugreek
88 88 f fiddlehead ../fiddlehead
89 89 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
90 90 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
91 91 f mammals/Procyonidae/raccoon Procyonidae/raccoon
92 92 f mammals/skunk skunk
93 93 $ hg debugwalk -v -I '*k'
94 94 * matcher:
95 95 <includematcher includes='(?:mammals\\/[^/]*k(?:/|$))'>
96 96 f mammals/skunk skunk
97 97 $ hg debugwalk -v -I 'glob:*k'
98 98 * matcher:
99 99 <includematcher includes='(?:mammals\\/[^/]*k(?:/|$))'>
100 100 f mammals/skunk skunk
101 101 $ hg debugwalk -v -I 'relglob:*k'
102 102 * matcher:
103 103 <includematcher includes='(?:(?:|.*/)[^/]*k(?:/|$))'>
104 104 f beans/black ../beans/black
105 105 f fenugreek ../fenugreek
106 106 f mammals/skunk skunk
107 107 $ hg debugwalk -v -I 'relglob:*k' .
108 108 * matcher:
109 <intersectionmatcher m1=
110 <patternmatcher patterns='(?:mammals(?:/|$))'>, m2=
111 <includematcher includes='(?:(?:|.*/)[^/]*k(?:/|$))'>>
109 <intersectionmatcher
110 m1=<patternmatcher patterns='(?:mammals(?:/|$))'>,
111 m2=<includematcher includes='(?:(?:|.*/)[^/]*k(?:/|$))'>>
112 112 f mammals/skunk skunk
113 113 $ hg debugwalk -v -I 're:.*k$'
114 114 * matcher:
115 115 <includematcher includes='(?:.*k$)'>
116 116 f beans/black ../beans/black
117 117 f fenugreek ../fenugreek
118 118 f mammals/skunk skunk
119 119 $ hg debugwalk -v -I 'relre:.*k$'
120 120 * matcher:
121 121 <includematcher includes='(?:.*.*k$)'>
122 122 f beans/black ../beans/black
123 123 f fenugreek ../fenugreek
124 124 f mammals/skunk skunk
125 125 $ hg debugwalk -v -I 'path:beans'
126 126 * matcher:
127 127 <includematcher includes='(?:beans(?:/|$))'>
128 128 f beans/black ../beans/black
129 129 f beans/borlotti ../beans/borlotti
130 130 f beans/kidney ../beans/kidney
131 131 f beans/navy ../beans/navy
132 132 f beans/pinto ../beans/pinto
133 133 f beans/turtle ../beans/turtle
134 134 $ hg debugwalk -v -I 'relpath:detour/../../beans'
135 135 * matcher:
136 136 <includematcher includes='(?:beans(?:/|$))'>
137 137 f beans/black ../beans/black
138 138 f beans/borlotti ../beans/borlotti
139 139 f beans/kidney ../beans/kidney
140 140 f beans/navy ../beans/navy
141 141 f beans/pinto ../beans/pinto
142 142 f beans/turtle ../beans/turtle
143 143
144 144 $ hg debugwalk -v 'rootfilesin:'
145 145 * matcher:
146 146 <patternmatcher patterns='(?:[^/]+$)'>
147 147 f fennel ../fennel
148 148 f fenugreek ../fenugreek
149 149 f fiddlehead ../fiddlehead
150 150 $ hg debugwalk -v -I 'rootfilesin:'
151 151 * matcher:
152 152 <includematcher includes='(?:[^/]+$)'>
153 153 f fennel ../fennel
154 154 f fenugreek ../fenugreek
155 155 f fiddlehead ../fiddlehead
156 156 $ hg debugwalk -v 'rootfilesin:.'
157 157 * matcher:
158 158 <patternmatcher patterns='(?:[^/]+$)'>
159 159 f fennel ../fennel
160 160 f fenugreek ../fenugreek
161 161 f fiddlehead ../fiddlehead
162 162 $ hg debugwalk -v -I 'rootfilesin:.'
163 163 * matcher:
164 164 <includematcher includes='(?:[^/]+$)'>
165 165 f fennel ../fennel
166 166 f fenugreek ../fenugreek
167 167 f fiddlehead ../fiddlehead
168 168 $ hg debugwalk -v -X 'rootfilesin:'
169 169 * matcher:
170 <differencematcher m1=
171 <alwaysmatcher>, m2=
172 <includematcher includes='(?:[^/]+$)'>>
170 <differencematcher
171 m1=<alwaysmatcher>,
172 m2=<includematcher includes='(?:[^/]+$)'>>
173 173 f beans/black ../beans/black
174 174 f beans/borlotti ../beans/borlotti
175 175 f beans/kidney ../beans/kidney
176 176 f beans/navy ../beans/navy
177 177 f beans/pinto ../beans/pinto
178 178 f beans/turtle ../beans/turtle
179 179 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
180 180 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
181 181 f mammals/Procyonidae/raccoon Procyonidae/raccoon
182 182 f mammals/skunk skunk
183 183 $ hg debugwalk -v 'rootfilesin:fennel'
184 184 * matcher:
185 185 <patternmatcher patterns='(?:fennel/[^/]+$)'>
186 186 $ hg debugwalk -v -I 'rootfilesin:fennel'
187 187 * matcher:
188 188 <includematcher includes='(?:fennel/[^/]+$)'>
189 189 $ hg debugwalk -v 'rootfilesin:skunk'
190 190 * matcher:
191 191 <patternmatcher patterns='(?:skunk/[^/]+$)'>
192 192 $ hg debugwalk -v -I 'rootfilesin:skunk'
193 193 * matcher:
194 194 <includematcher includes='(?:skunk/[^/]+$)'>
195 195 $ hg debugwalk -v 'rootfilesin:beans'
196 196 * matcher:
197 197 <patternmatcher patterns='(?:beans/[^/]+$)'>
198 198 f beans/black ../beans/black
199 199 f beans/borlotti ../beans/borlotti
200 200 f beans/kidney ../beans/kidney
201 201 f beans/navy ../beans/navy
202 202 f beans/pinto ../beans/pinto
203 203 f beans/turtle ../beans/turtle
204 204 $ hg debugwalk -v -I 'rootfilesin:beans'
205 205 * matcher:
206 206 <includematcher includes='(?:beans/[^/]+$)'>
207 207 f beans/black ../beans/black
208 208 f beans/borlotti ../beans/borlotti
209 209 f beans/kidney ../beans/kidney
210 210 f beans/navy ../beans/navy
211 211 f beans/pinto ../beans/pinto
212 212 f beans/turtle ../beans/turtle
213 213 $ hg debugwalk -v 'rootfilesin:mammals'
214 214 * matcher:
215 215 <patternmatcher patterns='(?:mammals/[^/]+$)'>
216 216 f mammals/skunk skunk
217 217 $ hg debugwalk -v -I 'rootfilesin:mammals'
218 218 * matcher:
219 219 <includematcher includes='(?:mammals/[^/]+$)'>
220 220 f mammals/skunk skunk
221 221 $ hg debugwalk -v 'rootfilesin:mammals/'
222 222 * matcher:
223 223 <patternmatcher patterns='(?:mammals/[^/]+$)'>
224 224 f mammals/skunk skunk
225 225 $ hg debugwalk -v -I 'rootfilesin:mammals/'
226 226 * matcher:
227 227 <includematcher includes='(?:mammals/[^/]+$)'>
228 228 f mammals/skunk skunk
229 229 $ hg debugwalk -v -X 'rootfilesin:mammals'
230 230 * matcher:
231 <differencematcher m1=
232 <alwaysmatcher>, m2=
233 <includematcher includes='(?:mammals/[^/]+$)'>>
231 <differencematcher
232 m1=<alwaysmatcher>,
233 m2=<includematcher includes='(?:mammals/[^/]+$)'>>
234 234 f beans/black ../beans/black
235 235 f beans/borlotti ../beans/borlotti
236 236 f beans/kidney ../beans/kidney
237 237 f beans/navy ../beans/navy
238 238 f beans/pinto ../beans/pinto
239 239 f beans/turtle ../beans/turtle
240 240 f fennel ../fennel
241 241 f fenugreek ../fenugreek
242 242 f fiddlehead ../fiddlehead
243 243 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
244 244 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
245 245 f mammals/Procyonidae/raccoon Procyonidae/raccoon
246 246
247 247 $ hg debugwalk -v .
248 248 * matcher:
249 249 <patternmatcher patterns='(?:mammals(?:/|$))'>
250 250 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
251 251 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
252 252 f mammals/Procyonidae/raccoon Procyonidae/raccoon
253 253 f mammals/skunk skunk
254 254 $ hg debugwalk -v -I.
255 255 * matcher:
256 256 <includematcher includes='(?:mammals(?:/|$))'>
257 257 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
258 258 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
259 259 f mammals/Procyonidae/raccoon Procyonidae/raccoon
260 260 f mammals/skunk skunk
261 261 $ hg debugwalk -v Procyonidae
262 262 * matcher:
263 263 <patternmatcher patterns='(?:mammals\\/Procyonidae(?:/|$))'>
264 264 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
265 265 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
266 266 f mammals/Procyonidae/raccoon Procyonidae/raccoon
267 267
268 268 $ cd Procyonidae
269 269 $ hg debugwalk -v .
270 270 * matcher:
271 271 <patternmatcher patterns='(?:mammals\\/Procyonidae(?:/|$))'>
272 272 f mammals/Procyonidae/cacomistle cacomistle
273 273 f mammals/Procyonidae/coatimundi coatimundi
274 274 f mammals/Procyonidae/raccoon raccoon
275 275 $ hg debugwalk -v ..
276 276 * matcher:
277 277 <patternmatcher patterns='(?:mammals(?:/|$))'>
278 278 f mammals/Procyonidae/cacomistle cacomistle
279 279 f mammals/Procyonidae/coatimundi coatimundi
280 280 f mammals/Procyonidae/raccoon raccoon
281 281 f mammals/skunk ../skunk
282 282 $ cd ..
283 283
284 284 $ hg debugwalk -v ../beans
285 285 * matcher:
286 286 <patternmatcher patterns='(?:beans(?:/|$))'>
287 287 f beans/black ../beans/black
288 288 f beans/borlotti ../beans/borlotti
289 289 f beans/kidney ../beans/kidney
290 290 f beans/navy ../beans/navy
291 291 f beans/pinto ../beans/pinto
292 292 f beans/turtle ../beans/turtle
293 293 $ hg debugwalk -v .
294 294 * matcher:
295 295 <patternmatcher patterns='(?:mammals(?:/|$))'>
296 296 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
297 297 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
298 298 f mammals/Procyonidae/raccoon Procyonidae/raccoon
299 299 f mammals/skunk skunk
300 300 $ hg debugwalk -v .hg
301 301 abort: path 'mammals/.hg' is inside nested repo 'mammals'
302 302 [255]
303 303 $ hg debugwalk -v ../.hg
304 304 abort: path contains illegal component: .hg
305 305 [255]
306 306 $ cd ..
307 307
308 308 $ hg debugwalk -v -Ibeans
309 309 * matcher:
310 310 <includematcher includes='(?:beans(?:/|$))'>
311 311 f beans/black beans/black
312 312 f beans/borlotti beans/borlotti
313 313 f beans/kidney beans/kidney
314 314 f beans/navy beans/navy
315 315 f beans/pinto beans/pinto
316 316 f beans/turtle beans/turtle
317 317 $ hg debugwalk -v -I '{*,{b,m}*/*}k'
318 318 * matcher:
319 319 <includematcher includes='(?:(?:[^/]*|(?:b|m)[^/]*\\/[^/]*)k(?:/|$))'>
320 320 f beans/black beans/black
321 321 f fenugreek fenugreek
322 322 f mammals/skunk mammals/skunk
323 323 $ hg debugwalk -v -Ibeans mammals
324 324 * matcher:
325 <intersectionmatcher m1=
326 <patternmatcher patterns='(?:mammals(?:/|$))'>, m2=
327 <includematcher includes='(?:beans(?:/|$))'>>
325 <intersectionmatcher
326 m1=<patternmatcher patterns='(?:mammals(?:/|$))'>,
327 m2=<includematcher includes='(?:beans(?:/|$))'>>
328 328 $ hg debugwalk -v -Inon-existent
329 329 * matcher:
330 330 <includematcher includes='(?:non\\-existent(?:/|$))'>
331 331 $ hg debugwalk -v -Inon-existent -Ibeans/black
332 332 * matcher:
333 333 <includematcher includes='(?:non\\-existent(?:/|$)|beans\\/black(?:/|$))'>
334 334 f beans/black beans/black
335 335 $ hg debugwalk -v -Ibeans beans/black
336 336 * matcher:
337 <intersectionmatcher m1=
338 <patternmatcher patterns='(?:beans\\/black(?:/|$))'>, m2=
339 <includematcher includes='(?:beans(?:/|$))'>>
337 <intersectionmatcher
338 m1=<patternmatcher patterns='(?:beans\\/black(?:/|$))'>,
339 m2=<includematcher includes='(?:beans(?:/|$))'>>
340 340 f beans/black beans/black exact
341 341 $ hg debugwalk -v -Ibeans/black beans
342 342 * matcher:
343 <intersectionmatcher m1=
344 <patternmatcher patterns='(?:beans(?:/|$))'>, m2=
345 <includematcher includes='(?:beans\\/black(?:/|$))'>>
343 <intersectionmatcher
344 m1=<patternmatcher patterns='(?:beans(?:/|$))'>,
345 m2=<includematcher includes='(?:beans\\/black(?:/|$))'>>
346 346 f beans/black beans/black
347 347 $ hg debugwalk -v -Xbeans/black beans
348 348 * matcher:
349 <differencematcher m1=
350 <patternmatcher patterns='(?:beans(?:/|$))'>, m2=
351 <includematcher includes='(?:beans\\/black(?:/|$))'>>
349 <differencematcher
350 m1=<patternmatcher patterns='(?:beans(?:/|$))'>,
351 m2=<includematcher includes='(?:beans\\/black(?:/|$))'>>
352 352 f beans/borlotti beans/borlotti
353 353 f beans/kidney beans/kidney
354 354 f beans/navy beans/navy
355 355 f beans/pinto beans/pinto
356 356 f beans/turtle beans/turtle
357 357 $ hg debugwalk -v -Xbeans/black -Ibeans
358 358 * matcher:
359 <differencematcher m1=
360 <includematcher includes='(?:beans(?:/|$))'>, m2=
361 <includematcher includes='(?:beans\\/black(?:/|$))'>>
359 <differencematcher
360 m1=<includematcher includes='(?:beans(?:/|$))'>,
361 m2=<includematcher includes='(?:beans\\/black(?:/|$))'>>
362 362 f beans/borlotti beans/borlotti
363 363 f beans/kidney beans/kidney
364 364 f beans/navy beans/navy
365 365 f beans/pinto beans/pinto
366 366 f beans/turtle beans/turtle
367 367 $ hg debugwalk -v -Xbeans/black beans/black
368 368 * matcher:
369 <differencematcher m1=
370 <patternmatcher patterns='(?:beans\\/black(?:/|$))'>, m2=
371 <includematcher includes='(?:beans\\/black(?:/|$))'>>
369 <differencematcher
370 m1=<patternmatcher patterns='(?:beans\\/black(?:/|$))'>,
371 m2=<includematcher includes='(?:beans\\/black(?:/|$))'>>
372 372 $ hg debugwalk -v -Xbeans/black -Ibeans/black
373 373 * matcher:
374 <differencematcher m1=
375 <includematcher includes='(?:beans\\/black(?:/|$))'>, m2=
376 <includematcher includes='(?:beans\\/black(?:/|$))'>>
374 <differencematcher
375 m1=<includematcher includes='(?:beans\\/black(?:/|$))'>,
376 m2=<includematcher includes='(?:beans\\/black(?:/|$))'>>
377 377 $ hg debugwalk -v -Xbeans beans/black
378 378 * matcher:
379 <differencematcher m1=
380 <patternmatcher patterns='(?:beans\\/black(?:/|$))'>, m2=
381 <includematcher includes='(?:beans(?:/|$))'>>
379 <differencematcher
380 m1=<patternmatcher patterns='(?:beans\\/black(?:/|$))'>,
381 m2=<includematcher includes='(?:beans(?:/|$))'>>
382 382 $ hg debugwalk -v -Xbeans -Ibeans/black
383 383 * matcher:
384 <differencematcher m1=
385 <includematcher includes='(?:beans\\/black(?:/|$))'>, m2=
386 <includematcher includes='(?:beans(?:/|$))'>>
384 <differencematcher
385 m1=<includematcher includes='(?:beans\\/black(?:/|$))'>,
386 m2=<includematcher includes='(?:beans(?:/|$))'>>
387 387 $ hg debugwalk -v 'glob:mammals/../beans/b*'
388 388 * matcher:
389 389 <patternmatcher patterns='(?:beans\\/b[^/]*$)'>
390 390 f beans/black beans/black
391 391 f beans/borlotti beans/borlotti
392 392 $ hg debugwalk -v '-X*/Procyonidae' mammals
393 393 * matcher:
394 <differencematcher m1=
395 <patternmatcher patterns='(?:mammals(?:/|$))'>, m2=
396 <includematcher includes='(?:[^/]*\\/Procyonidae(?:/|$))'>>
394 <differencematcher
395 m1=<patternmatcher patterns='(?:mammals(?:/|$))'>,
396 m2=<includematcher includes='(?:[^/]*\\/Procyonidae(?:/|$))'>>
397 397 f mammals/skunk mammals/skunk
398 398 $ hg debugwalk -v path:mammals
399 399 * matcher:
400 400 <patternmatcher patterns='(?:mammals(?:/|$))'>
401 401 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
402 402 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
403 403 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
404 404 f mammals/skunk mammals/skunk
405 405 $ hg debugwalk -v ..
406 406 abort: .. not under root '$TESTTMP/t'
407 407 [255]
408 408 $ hg debugwalk -v beans/../..
409 409 abort: beans/../.. not under root '$TESTTMP/t'
410 410 [255]
411 411 $ hg debugwalk -v .hg
412 412 abort: path contains illegal component: .hg
413 413 [255]
414 414 $ hg debugwalk -v beans/../.hg
415 415 abort: path contains illegal component: .hg
416 416 [255]
417 417 $ hg debugwalk -v beans/../.hg/data
418 418 abort: path contains illegal component: .hg/data
419 419 [255]
420 420 $ hg debugwalk -v beans/.hg
421 421 abort: path 'beans/.hg' is inside nested repo 'beans'
422 422 [255]
423 423
424 424 Test explicit paths and excludes:
425 425
426 426 $ hg debugwalk -v fennel -X fennel
427 427 * matcher:
428 <differencematcher m1=
429 <patternmatcher patterns='(?:fennel(?:/|$))'>, m2=
430 <includematcher includes='(?:fennel(?:/|$))'>>
428 <differencematcher
429 m1=<patternmatcher patterns='(?:fennel(?:/|$))'>,
430 m2=<includematcher includes='(?:fennel(?:/|$))'>>
431 431 $ hg debugwalk -v fennel -X 'f*'
432 432 * matcher:
433 <differencematcher m1=
434 <patternmatcher patterns='(?:fennel(?:/|$))'>, m2=
435 <includematcher includes='(?:f[^/]*(?:/|$))'>>
433 <differencematcher
434 m1=<patternmatcher patterns='(?:fennel(?:/|$))'>,
435 m2=<includematcher includes='(?:f[^/]*(?:/|$))'>>
436 436 $ hg debugwalk -v beans/black -X 'path:beans'
437 437 * matcher:
438 <differencematcher m1=
439 <patternmatcher patterns='(?:beans\\/black(?:/|$))'>, m2=
440 <includematcher includes='(?:beans(?:/|$))'>>
438 <differencematcher
439 m1=<patternmatcher patterns='(?:beans\\/black(?:/|$))'>,
440 m2=<includematcher includes='(?:beans(?:/|$))'>>
441 441 $ hg debugwalk -v -I 'path:beans/black' -X 'path:beans'
442 442 * matcher:
443 <differencematcher m1=
444 <includematcher includes='(?:beans\\/black(?:/|$))'>, m2=
445 <includematcher includes='(?:beans(?:/|$))'>>
443 <differencematcher
444 m1=<includematcher includes='(?:beans\\/black(?:/|$))'>,
445 m2=<includematcher includes='(?:beans(?:/|$))'>>
446 446
447 447 Test absolute paths:
448 448
449 449 $ hg debugwalk -v `pwd`/beans
450 450 * matcher:
451 451 <patternmatcher patterns='(?:beans(?:/|$))'>
452 452 f beans/black beans/black
453 453 f beans/borlotti beans/borlotti
454 454 f beans/kidney beans/kidney
455 455 f beans/navy beans/navy
456 456 f beans/pinto beans/pinto
457 457 f beans/turtle beans/turtle
458 458 $ hg debugwalk -v `pwd`/..
459 459 abort: $TESTTMP/t/.. not under root '$TESTTMP/t'
460 460 [255]
461 461
462 462 Test patterns:
463 463
464 464 $ hg debugwalk -v glob:\*
465 465 * matcher:
466 466 <patternmatcher patterns='(?:[^/]*$)'>
467 467 f fennel fennel
468 468 f fenugreek fenugreek
469 469 f fiddlehead fiddlehead
470 470 #if eol-in-paths
471 471 $ echo glob:glob > glob:glob
472 472 $ hg addremove
473 473 adding glob:glob
474 474 warning: filename contains ':', which is reserved on Windows: 'glob:glob'
475 475 $ hg debugwalk -v glob:\*
476 476 * matcher:
477 477 <patternmatcher patterns='(?:[^/]*$)'>
478 478 f fennel fennel
479 479 f fenugreek fenugreek
480 480 f fiddlehead fiddlehead
481 481 f glob:glob glob:glob
482 482 $ hg debugwalk -v glob:glob
483 483 * matcher:
484 484 <patternmatcher patterns='(?:glob$)'>
485 485 glob: $ENOENT$
486 486 $ hg debugwalk -v glob:glob:glob
487 487 * matcher:
488 488 <patternmatcher patterns='(?:glob\\:glob$)'>
489 489 f glob:glob glob:glob exact
490 490 $ hg debugwalk -v path:glob:glob
491 491 * matcher:
492 492 <patternmatcher patterns='(?:glob\\:glob(?:/|$))'>
493 493 f glob:glob glob:glob exact
494 494 $ rm glob:glob
495 495 $ hg addremove
496 496 removing glob:glob
497 497 #endif
498 498
499 499 $ hg debugwalk -v 'glob:**e'
500 500 * matcher:
501 501 <patternmatcher patterns='(?:.*e$)'>
502 502 f beans/turtle beans/turtle
503 503 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
504 504
505 505 $ hg debugwalk -v 're:.*[kb]$'
506 506 * matcher:
507 507 <patternmatcher patterns='(?:.*[kb]$)'>
508 508 f beans/black beans/black
509 509 f fenugreek fenugreek
510 510 f mammals/skunk mammals/skunk
511 511
512 512 $ hg debugwalk -v path:beans/black
513 513 * matcher:
514 514 <patternmatcher patterns='(?:beans\\/black(?:/|$))'>
515 515 f beans/black beans/black exact
516 516 $ hg debugwalk -v path:beans//black
517 517 * matcher:
518 518 <patternmatcher patterns='(?:beans\\/black(?:/|$))'>
519 519 f beans/black beans/black exact
520 520
521 521 $ hg debugwalk -v relglob:Procyonidae
522 522 * matcher:
523 523 <patternmatcher patterns='(?:(?:|.*/)Procyonidae$)'>
524 524 $ hg debugwalk -v 'relglob:Procyonidae/**'
525 525 * matcher:
526 526 <patternmatcher patterns='(?:(?:|.*/)Procyonidae\\/.*$)'>
527 527 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
528 528 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
529 529 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
530 530 $ hg debugwalk -v 'relglob:Procyonidae/**' fennel
531 531 * matcher:
532 532 <patternmatcher patterns='(?:(?:|.*/)Procyonidae\\/.*$|fennel(?:/|$))'>
533 533 f fennel fennel exact
534 534 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
535 535 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
536 536 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
537 537 $ hg debugwalk -v beans 'glob:beans/*'
538 538 * matcher:
539 539 <patternmatcher patterns='(?:beans(?:/|$)|beans\\/[^/]*$)'>
540 540 f beans/black beans/black
541 541 f beans/borlotti beans/borlotti
542 542 f beans/kidney beans/kidney
543 543 f beans/navy beans/navy
544 544 f beans/pinto beans/pinto
545 545 f beans/turtle beans/turtle
546 546 $ hg debugwalk -v 'glob:mamm**'
547 547 * matcher:
548 548 <patternmatcher patterns='(?:mamm.*$)'>
549 549 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
550 550 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
551 551 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
552 552 f mammals/skunk mammals/skunk
553 553 $ hg debugwalk -v 'glob:mamm**' fennel
554 554 * matcher:
555 555 <patternmatcher patterns='(?:mamm.*$|fennel(?:/|$))'>
556 556 f fennel fennel exact
557 557 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
558 558 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
559 559 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
560 560 f mammals/skunk mammals/skunk
561 561 $ hg debugwalk -v 'glob:j*'
562 562 * matcher:
563 563 <patternmatcher patterns='(?:j[^/]*$)'>
564 564 $ hg debugwalk -v NOEXIST
565 565 * matcher:
566 566 <patternmatcher patterns='(?:NOEXIST(?:/|$))'>
567 567 NOEXIST: * (glob)
568 568
569 569 #if fifo
570 570 $ mkfifo fifo
571 571 $ hg debugwalk -v fifo
572 572 * matcher:
573 573 <patternmatcher patterns='(?:fifo(?:/|$))'>
574 574 fifo: unsupported file type (type is fifo)
575 575 #endif
576 576
577 577 $ rm fenugreek
578 578 $ hg debugwalk -v fenugreek
579 579 * matcher:
580 580 <patternmatcher patterns='(?:fenugreek(?:/|$))'>
581 581 f fenugreek fenugreek exact
582 582 $ hg rm fenugreek
583 583 $ hg debugwalk -v fenugreek
584 584 * matcher:
585 585 <patternmatcher patterns='(?:fenugreek(?:/|$))'>
586 586 f fenugreek fenugreek exact
587 587 $ touch new
588 588 $ hg debugwalk -v new
589 589 * matcher:
590 590 <patternmatcher patterns='(?:new(?:/|$))'>
591 591 f new new exact
592 592
593 593 $ mkdir ignored
594 594 $ touch ignored/file
595 595 $ echo '^ignored$' > .hgignore
596 596 $ hg debugwalk -v ignored
597 597 * matcher:
598 598 <patternmatcher patterns='(?:ignored(?:/|$))'>
599 599 $ hg debugwalk -v ignored/file
600 600 * matcher:
601 601 <patternmatcher patterns='(?:ignored\\/file(?:/|$))'>
602 602 f ignored/file ignored/file exact
603 603
604 604 Test listfile and listfile0
605 605
606 606 $ $PYTHON -c "open('listfile0', 'wb').write(b'fenugreek\0new\0')"
607 607 $ hg debugwalk -v -I 'listfile0:listfile0'
608 608 * matcher:
609 609 <includematcher includes='(?:fenugreek(?:/|$)|new(?:/|$))'>
610 610 f fenugreek fenugreek
611 611 f new new
612 612 $ $PYTHON -c "open('listfile', 'wb').write(b'fenugreek\nnew\r\nmammals/skunk\n')"
613 613 $ hg debugwalk -v -I 'listfile:listfile'
614 614 * matcher:
615 615 <includematcher includes='(?:fenugreek(?:/|$)|new(?:/|$)|mammals\\/skunk(?:/|$))'>
616 616 f fenugreek fenugreek
617 617 f mammals/skunk mammals/skunk
618 618 f new new
619 619
620 620 $ cd ..
621 621 $ hg debugwalk -v -R t t/mammals/skunk
622 622 * matcher:
623 623 <patternmatcher patterns='(?:mammals\\/skunk(?:/|$))'>
624 624 f mammals/skunk t/mammals/skunk exact
625 625 $ mkdir t2
626 626 $ cd t2
627 627 $ hg debugwalk -v -R ../t ../t/mammals/skunk
628 628 * matcher:
629 629 <patternmatcher patterns='(?:mammals\\/skunk(?:/|$))'>
630 630 f mammals/skunk ../t/mammals/skunk exact
631 631 $ hg debugwalk -v --cwd ../t mammals/skunk
632 632 * matcher:
633 633 <patternmatcher patterns='(?:mammals\\/skunk(?:/|$))'>
634 634 f mammals/skunk mammals/skunk exact
635 635
636 636 $ cd ..
637 637
638 638 Test split patterns on overflow
639 639
640 640 $ cd t
641 641 $ echo fennel > overflow.list
642 642 $ cat >> printnum.py <<EOF
643 643 > from __future__ import print_function
644 644 > for i in range(20000 // 100):
645 645 > print('x' * 100)
646 646 > EOF
647 647 $ $PYTHON printnum.py >> overflow.list
648 648 $ echo fenugreek >> overflow.list
649 649 $ hg debugwalk 'listfile:overflow.list' 2>&1 | egrep -v '^xxx'
650 650 f fennel fennel exact
651 651 f fenugreek fenugreek exact
652 652 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now