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