##// END OF EJS Templates
match: remove support for includes from patternmatcher...
Martin von Zweigbergk -
r32504:2ba4d3b7 default
parent child Browse files
Show More
@@ -1,1004 +1,973 b''
1 # match.py - filename matching
1 # match.py - filename matching
2 #
2 #
3 # Copyright 2008, 2009 Matt Mackall <mpm@selenic.com> and others
3 # Copyright 2008, 2009 Matt Mackall <mpm@selenic.com> and others
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import copy
10 import copy
11 import os
11 import os
12 import re
12 import re
13
13
14 from .i18n import _
14 from .i18n import _
15 from . import (
15 from . import (
16 error,
16 error,
17 pathutil,
17 pathutil,
18 util,
18 util,
19 )
19 )
20
20
21 propertycache = util.propertycache
21 propertycache = util.propertycache
22
22
23 def _rematcher(regex):
23 def _rematcher(regex):
24 '''compile the regexp with the best available regexp engine and return a
24 '''compile the regexp with the best available regexp engine and return a
25 matcher function'''
25 matcher function'''
26 m = util.re.compile(regex)
26 m = util.re.compile(regex)
27 try:
27 try:
28 # slightly faster, provided by facebook's re2 bindings
28 # slightly faster, provided by facebook's re2 bindings
29 return m.test_match
29 return m.test_match
30 except AttributeError:
30 except AttributeError:
31 return m.match
31 return m.match
32
32
33 def _expandsets(kindpats, ctx, listsubrepos):
33 def _expandsets(kindpats, ctx, listsubrepos):
34 '''Returns the kindpats list with the 'set' patterns expanded.'''
34 '''Returns the kindpats list with the 'set' patterns expanded.'''
35 fset = set()
35 fset = set()
36 other = []
36 other = []
37
37
38 for kind, pat, source in kindpats:
38 for kind, pat, source in kindpats:
39 if kind == 'set':
39 if kind == 'set':
40 if not ctx:
40 if not ctx:
41 raise error.ProgrammingError("fileset expression with no "
41 raise error.ProgrammingError("fileset expression with no "
42 "context")
42 "context")
43 s = ctx.getfileset(pat)
43 s = ctx.getfileset(pat)
44 fset.update(s)
44 fset.update(s)
45
45
46 if listsubrepos:
46 if listsubrepos:
47 for subpath in ctx.substate:
47 for subpath in ctx.substate:
48 s = ctx.sub(subpath).getfileset(pat)
48 s = ctx.sub(subpath).getfileset(pat)
49 fset.update(subpath + '/' + f for f in s)
49 fset.update(subpath + '/' + f for f in s)
50
50
51 continue
51 continue
52 other.append((kind, pat, source))
52 other.append((kind, pat, source))
53 return fset, other
53 return fset, other
54
54
55 def _expandsubinclude(kindpats, root):
55 def _expandsubinclude(kindpats, root):
56 '''Returns the list of subinclude matcher args and the kindpats without the
56 '''Returns the list of subinclude matcher args and the kindpats without the
57 subincludes in it.'''
57 subincludes in it.'''
58 relmatchers = []
58 relmatchers = []
59 other = []
59 other = []
60
60
61 for kind, pat, source in kindpats:
61 for kind, pat, source in kindpats:
62 if kind == 'subinclude':
62 if kind == 'subinclude':
63 sourceroot = pathutil.dirname(util.normpath(source))
63 sourceroot = pathutil.dirname(util.normpath(source))
64 pat = util.pconvert(pat)
64 pat = util.pconvert(pat)
65 path = pathutil.join(sourceroot, pat)
65 path = pathutil.join(sourceroot, pat)
66
66
67 newroot = pathutil.dirname(path)
67 newroot = pathutil.dirname(path)
68 matcherargs = (newroot, '', [], ['include:%s' % path])
68 matcherargs = (newroot, '', [], ['include:%s' % path])
69
69
70 prefix = pathutil.canonpath(root, root, newroot)
70 prefix = pathutil.canonpath(root, root, newroot)
71 if prefix:
71 if prefix:
72 prefix += '/'
72 prefix += '/'
73 relmatchers.append((prefix, matcherargs))
73 relmatchers.append((prefix, matcherargs))
74 else:
74 else:
75 other.append((kind, pat, source))
75 other.append((kind, pat, source))
76
76
77 return relmatchers, other
77 return relmatchers, other
78
78
79 def _kindpatsalwaysmatch(kindpats):
79 def _kindpatsalwaysmatch(kindpats):
80 """"Checks whether the kindspats match everything, as e.g.
80 """"Checks whether the kindspats match everything, as e.g.
81 'relpath:.' does.
81 'relpath:.' does.
82 """
82 """
83 for kind, pat, source in kindpats:
83 for kind, pat, source in kindpats:
84 if pat != '' or kind not in ['relpath', 'glob']:
84 if pat != '' or kind not in ['relpath', 'glob']:
85 return False
85 return False
86 return True
86 return True
87
87
88 def match(root, cwd, patterns, include=None, exclude=None, default='glob',
88 def match(root, cwd, patterns, include=None, exclude=None, default='glob',
89 exact=False, auditor=None, ctx=None, listsubrepos=False, warn=None,
89 exact=False, auditor=None, ctx=None, listsubrepos=False, warn=None,
90 badfn=None, icasefs=False):
90 badfn=None, icasefs=False):
91 """build an object to match a set of file patterns
91 """build an object to match a set of file patterns
92
92
93 arguments:
93 arguments:
94 root - the canonical root of the tree you're matching against
94 root - the canonical root of the tree you're matching against
95 cwd - the current working directory, if relevant
95 cwd - the current working directory, if relevant
96 patterns - patterns to find
96 patterns - patterns to find
97 include - patterns to include (unless they are excluded)
97 include - patterns to include (unless they are excluded)
98 exclude - patterns to exclude (even if they are included)
98 exclude - patterns to exclude (even if they are included)
99 default - if a pattern in patterns has no explicit type, assume this one
99 default - if a pattern in patterns has no explicit type, assume this one
100 exact - patterns are actually filenames (include/exclude still apply)
100 exact - patterns are actually filenames (include/exclude still apply)
101 warn - optional function used for printing warnings
101 warn - optional function used for printing warnings
102 badfn - optional bad() callback for this matcher instead of the default
102 badfn - optional bad() callback for this matcher instead of the default
103 icasefs - make a matcher for wdir on case insensitive filesystems, which
103 icasefs - make a matcher for wdir on case insensitive filesystems, which
104 normalizes the given patterns to the case in the filesystem
104 normalizes the given patterns to the case in the filesystem
105
105
106 a pattern is one of:
106 a pattern is one of:
107 'glob:<glob>' - a glob relative to cwd
107 'glob:<glob>' - a glob relative to cwd
108 're:<regexp>' - a regular expression
108 're:<regexp>' - a regular expression
109 'path:<path>' - a path relative to repository root, which is matched
109 'path:<path>' - a path relative to repository root, which is matched
110 recursively
110 recursively
111 'rootfilesin:<path>' - a path relative to repository root, which is
111 'rootfilesin:<path>' - a path relative to repository root, which is
112 matched non-recursively (will not match subdirectories)
112 matched non-recursively (will not match subdirectories)
113 'relglob:<glob>' - an unrooted glob (*.c matches C files in all dirs)
113 'relglob:<glob>' - an unrooted glob (*.c matches C files in all dirs)
114 'relpath:<path>' - a path relative to cwd
114 'relpath:<path>' - a path relative to cwd
115 'relre:<regexp>' - a regexp that needn't match the start of a name
115 'relre:<regexp>' - a regexp that needn't match the start of a name
116 'set:<fileset>' - a fileset expression
116 'set:<fileset>' - a fileset expression
117 'include:<path>' - a file of patterns to read and include
117 'include:<path>' - a file of patterns to read and include
118 'subinclude:<path>' - a file of patterns to match against files under
118 'subinclude:<path>' - a file of patterns to match against files under
119 the same directory
119 the same directory
120 '<something>' - a pattern of the specified default type
120 '<something>' - a pattern of the specified default type
121 """
121 """
122 normalize = _donormalize
122 normalize = _donormalize
123 if icasefs:
123 if icasefs:
124 if exact:
124 if exact:
125 raise error.ProgrammingError("a case-insensitive exact matcher "
125 raise error.ProgrammingError("a case-insensitive exact matcher "
126 "doesn't make sense")
126 "doesn't make sense")
127 dirstate = ctx.repo().dirstate
127 dirstate = ctx.repo().dirstate
128 dsnormalize = dirstate.normalize
128 dsnormalize = dirstate.normalize
129
129
130 def normalize(patterns, default, root, cwd, auditor, warn):
130 def normalize(patterns, default, root, cwd, auditor, warn):
131 kp = _donormalize(patterns, default, root, cwd, auditor, warn)
131 kp = _donormalize(patterns, default, root, cwd, auditor, warn)
132 kindpats = []
132 kindpats = []
133 for kind, pats, source in kp:
133 for kind, pats, source in kp:
134 if kind not in ('re', 'relre'): # regex can't be normalized
134 if kind not in ('re', 'relre'): # regex can't be normalized
135 p = pats
135 p = pats
136 pats = dsnormalize(pats)
136 pats = dsnormalize(pats)
137
137
138 # Preserve the original to handle a case only rename.
138 # Preserve the original to handle a case only rename.
139 if p != pats and p in dirstate:
139 if p != pats and p in dirstate:
140 kindpats.append((kind, p, source))
140 kindpats.append((kind, p, source))
141
141
142 kindpats.append((kind, pats, source))
142 kindpats.append((kind, pats, source))
143 return kindpats
143 return kindpats
144
144
145 if exact:
145 if exact:
146 m = exactmatcher(root, cwd, patterns, badfn)
146 m = exactmatcher(root, cwd, patterns, badfn)
147 else:
147 else:
148 m = patternmatcher(root, cwd, normalize, patterns, include=None,
148 m = patternmatcher(root, cwd, normalize, patterns, default=default,
149 default=default, auditor=auditor, ctx=ctx,
149 auditor=auditor, ctx=ctx, listsubrepos=listsubrepos,
150 listsubrepos=listsubrepos, warn=warn, badfn=badfn)
150 warn=warn, badfn=badfn)
151 if include:
151 if include:
152 im = includematcher(root, cwd, normalize, include, auditor=auditor,
152 im = includematcher(root, cwd, normalize, include, auditor=auditor,
153 ctx=ctx, listsubrepos=listsubrepos, warn=warn,
153 ctx=ctx, listsubrepos=listsubrepos, warn=warn,
154 badfn=None)
154 badfn=None)
155 m = intersectmatchers(m, im)
155 m = intersectmatchers(m, im)
156 if exclude:
156 if exclude:
157 em = includematcher(root, cwd, normalize, exclude, auditor=auditor,
157 em = includematcher(root, cwd, normalize, exclude, auditor=auditor,
158 ctx=ctx, listsubrepos=listsubrepos, warn=warn,
158 ctx=ctx, listsubrepos=listsubrepos, warn=warn,
159 badfn=None)
159 badfn=None)
160 m = differencematcher(m, em)
160 m = differencematcher(m, em)
161 return m
161 return m
162
162
163 def exact(root, cwd, files, badfn=None):
163 def exact(root, cwd, files, badfn=None):
164 return exactmatcher(root, cwd, files, badfn=badfn)
164 return exactmatcher(root, cwd, files, badfn=badfn)
165
165
166 def always(root, cwd):
166 def always(root, cwd):
167 return match(root, cwd, [])
167 return match(root, cwd, [])
168
168
169 def badmatch(match, badfn):
169 def badmatch(match, badfn):
170 """Make a copy of the given matcher, replacing its bad method with the given
170 """Make a copy of the given matcher, replacing its bad method with the given
171 one.
171 one.
172 """
172 """
173 m = copy.copy(match)
173 m = copy.copy(match)
174 m.bad = badfn
174 m.bad = badfn
175 return m
175 return m
176
176
177 def _donormalize(patterns, default, root, cwd, auditor, warn):
177 def _donormalize(patterns, default, root, cwd, auditor, warn):
178 '''Convert 'kind:pat' from the patterns list to tuples with kind and
178 '''Convert 'kind:pat' from the patterns list to tuples with kind and
179 normalized and rooted patterns and with listfiles expanded.'''
179 normalized and rooted patterns and with listfiles expanded.'''
180 kindpats = []
180 kindpats = []
181 for kind, pat in [_patsplit(p, default) for p in patterns]:
181 for kind, pat in [_patsplit(p, default) for p in patterns]:
182 if kind in ('glob', 'relpath'):
182 if kind in ('glob', 'relpath'):
183 pat = pathutil.canonpath(root, cwd, pat, auditor)
183 pat = pathutil.canonpath(root, cwd, pat, auditor)
184 elif kind in ('relglob', 'path', 'rootfilesin'):
184 elif kind in ('relglob', 'path', 'rootfilesin'):
185 pat = util.normpath(pat)
185 pat = util.normpath(pat)
186 elif kind in ('listfile', 'listfile0'):
186 elif kind in ('listfile', 'listfile0'):
187 try:
187 try:
188 files = util.readfile(pat)
188 files = util.readfile(pat)
189 if kind == 'listfile0':
189 if kind == 'listfile0':
190 files = files.split('\0')
190 files = files.split('\0')
191 else:
191 else:
192 files = files.splitlines()
192 files = files.splitlines()
193 files = [f for f in files if f]
193 files = [f for f in files if f]
194 except EnvironmentError:
194 except EnvironmentError:
195 raise error.Abort(_("unable to read file list (%s)") % pat)
195 raise error.Abort(_("unable to read file list (%s)") % pat)
196 for k, p, source in _donormalize(files, default, root, cwd,
196 for k, p, source in _donormalize(files, default, root, cwd,
197 auditor, warn):
197 auditor, warn):
198 kindpats.append((k, p, pat))
198 kindpats.append((k, p, pat))
199 continue
199 continue
200 elif kind == 'include':
200 elif kind == 'include':
201 try:
201 try:
202 fullpath = os.path.join(root, util.localpath(pat))
202 fullpath = os.path.join(root, util.localpath(pat))
203 includepats = readpatternfile(fullpath, warn)
203 includepats = readpatternfile(fullpath, warn)
204 for k, p, source in _donormalize(includepats, default,
204 for k, p, source in _donormalize(includepats, default,
205 root, cwd, auditor, warn):
205 root, cwd, auditor, warn):
206 kindpats.append((k, p, source or pat))
206 kindpats.append((k, p, source or pat))
207 except error.Abort as inst:
207 except error.Abort as inst:
208 raise error.Abort('%s: %s' % (pat, inst[0]))
208 raise error.Abort('%s: %s' % (pat, inst[0]))
209 except IOError as inst:
209 except IOError as inst:
210 if warn:
210 if warn:
211 warn(_("skipping unreadable pattern file '%s': %s\n") %
211 warn(_("skipping unreadable pattern file '%s': %s\n") %
212 (pat, inst.strerror))
212 (pat, inst.strerror))
213 continue
213 continue
214 # else: re or relre - which cannot be normalized
214 # else: re or relre - which cannot be normalized
215 kindpats.append((kind, pat, ''))
215 kindpats.append((kind, pat, ''))
216 return kindpats
216 return kindpats
217
217
218 class basematcher(object):
218 class basematcher(object):
219
219
220 def __init__(self, root, cwd, badfn=None, relativeuipath=True):
220 def __init__(self, root, cwd, badfn=None, relativeuipath=True):
221 self._root = root
221 self._root = root
222 self._cwd = cwd
222 self._cwd = cwd
223 if badfn is not None:
223 if badfn is not None:
224 self.bad = badfn
224 self.bad = badfn
225 self._relativeuipath = relativeuipath
225 self._relativeuipath = relativeuipath
226
226
227 def __call__(self, fn):
227 def __call__(self, fn):
228 return self.matchfn(fn)
228 return self.matchfn(fn)
229 def __iter__(self):
229 def __iter__(self):
230 for f in self._files:
230 for f in self._files:
231 yield f
231 yield f
232 # Callbacks related to how the matcher is used by dirstate.walk.
232 # Callbacks related to how the matcher is used by dirstate.walk.
233 # Subscribers to these events must monkeypatch the matcher object.
233 # Subscribers to these events must monkeypatch the matcher object.
234 def bad(self, f, msg):
234 def bad(self, f, msg):
235 '''Callback from dirstate.walk for each explicit file that can't be
235 '''Callback from dirstate.walk for each explicit file that can't be
236 found/accessed, with an error message.'''
236 found/accessed, with an error message.'''
237 pass
237 pass
238
238
239 # If an explicitdir is set, it will be called when an explicitly listed
239 # If an explicitdir is set, it will be called when an explicitly listed
240 # directory is visited.
240 # directory is visited.
241 explicitdir = None
241 explicitdir = None
242
242
243 # If an traversedir is set, it will be called when a directory discovered
243 # If an traversedir is set, it will be called when a directory discovered
244 # by recursive traversal is visited.
244 # by recursive traversal is visited.
245 traversedir = None
245 traversedir = None
246
246
247 def abs(self, f):
247 def abs(self, f):
248 '''Convert a repo path back to path that is relative to the root of the
248 '''Convert a repo path back to path that is relative to the root of the
249 matcher.'''
249 matcher.'''
250 return f
250 return f
251
251
252 def rel(self, f):
252 def rel(self, f):
253 '''Convert repo path back to path that is relative to cwd of matcher.'''
253 '''Convert repo path back to path that is relative to cwd of matcher.'''
254 return util.pathto(self._root, self._cwd, f)
254 return util.pathto(self._root, self._cwd, f)
255
255
256 def uipath(self, f):
256 def uipath(self, f):
257 '''Convert repo path to a display path. If patterns or -I/-X were used
257 '''Convert repo path to a display path. If patterns or -I/-X were used
258 to create this matcher, the display path will be relative to cwd.
258 to create this matcher, the display path will be relative to cwd.
259 Otherwise it is relative to the root of the repo.'''
259 Otherwise it is relative to the root of the repo.'''
260 return (self._relativeuipath and self.rel(f)) or self.abs(f)
260 return (self._relativeuipath and self.rel(f)) or self.abs(f)
261
261
262 @propertycache
262 @propertycache
263 def _files(self):
263 def _files(self):
264 return []
264 return []
265
265
266 def files(self):
266 def files(self):
267 '''Explicitly listed files or patterns or roots:
267 '''Explicitly listed files or patterns or roots:
268 if no patterns or .always(): empty list,
268 if no patterns or .always(): empty list,
269 if exact: list exact files,
269 if exact: list exact files,
270 if not .anypats(): list all files and dirs,
270 if not .anypats(): list all files and dirs,
271 else: optimal roots'''
271 else: optimal roots'''
272 return self._files
272 return self._files
273
273
274 @propertycache
274 @propertycache
275 def _fileset(self):
275 def _fileset(self):
276 return set(self._files)
276 return set(self._files)
277
277
278 def exact(self, f):
278 def exact(self, f):
279 '''Returns True if f is in .files().'''
279 '''Returns True if f is in .files().'''
280 return f in self._fileset
280 return f in self._fileset
281
281
282 def matchfn(self, f):
282 def matchfn(self, f):
283 return False
283 return False
284
284
285 def visitdir(self, dir):
285 def visitdir(self, dir):
286 '''Decides whether a directory should be visited based on whether it
286 '''Decides whether a directory should be visited based on whether it
287 has potential matches in it or one of its subdirectories. This is
287 has potential matches in it or one of its subdirectories. This is
288 based on the match's primary, included, and excluded patterns.
288 based on the match's primary, included, and excluded patterns.
289
289
290 Returns the string 'all' if the given directory and all subdirectories
290 Returns the string 'all' if the given directory and all subdirectories
291 should be visited. Otherwise returns True or False indicating whether
291 should be visited. Otherwise returns True or False indicating whether
292 the given directory should be visited.
292 the given directory should be visited.
293
293
294 This function's behavior is undefined if it has returned False for
294 This function's behavior is undefined if it has returned False for
295 one of the dir's parent directories.
295 one of the dir's parent directories.
296 '''
296 '''
297 return False
297 return False
298
298
299 def anypats(self):
299 def anypats(self):
300 '''Matcher uses patterns or include/exclude.'''
300 '''Matcher uses patterns or include/exclude.'''
301 return False
301 return False
302
302
303 def always(self):
303 def always(self):
304 '''Matcher will match everything and .files() will be empty
304 '''Matcher will match everything and .files() will be empty
305 - optimization might be possible and necessary.'''
305 - optimization might be possible and necessary.'''
306 return False
306 return False
307
307
308 def isexact(self):
308 def isexact(self):
309 return False
309 return False
310
310
311 def prefix(self):
311 def prefix(self):
312 return not self.always() and not self.isexact() and not self.anypats()
312 return not self.always() and not self.isexact() and not self.anypats()
313
313
314 class patternmatcher(basematcher):
314 class patternmatcher(basematcher):
315
315
316 def __init__(self, root, cwd, normalize, patterns, include=None,
316 def __init__(self, root, cwd, normalize, patterns, default='glob',
317 default='glob', auditor=None, ctx=None,
317 auditor=None, ctx=None, listsubrepos=False, warn=None,
318 listsubrepos=False, warn=None, badfn=None):
318 badfn=None):
319 super(patternmatcher, self).__init__(root, cwd, badfn,
319 super(patternmatcher, self).__init__(root, cwd, badfn,
320 relativeuipath=bool(include or
320 relativeuipath=bool(patterns))
321 patterns))
322 if include is None:
323 include = []
324
321
325 self._anypats = bool(include)
322 self._anypats = False
326 self._anyincludepats = False
327 self._always = False
323 self._always = False
328 self.patternspat = None
324 self.patternspat = None
329 self.includepat = None
330
331 # roots are directories which are recursively included.
332 self._includeroots = set()
333 # dirs are directories which are non-recursively included.
334 self._includedirs = set()
335
325
336 matchfns = []
326 matchfns = []
337 if include:
338 kindpats = normalize(include, 'glob', root, cwd, auditor, warn)
339 self.includepat, im = _buildmatch(ctx, kindpats, '(?:/|$)',
340 listsubrepos, root)
341 self._anyincludepats = _anypats(kindpats)
342 roots, dirs = _rootsanddirs(kindpats)
343 self._includeroots.update(roots)
344 self._includedirs.update(dirs)
345 matchfns.append(im)
346 if patterns:
327 if patterns:
347 kindpats = normalize(patterns, default, root, cwd, auditor, warn)
328 kindpats = normalize(patterns, default, root, cwd, auditor, warn)
348 if not _kindpatsalwaysmatch(kindpats):
329 if not _kindpatsalwaysmatch(kindpats):
349 self._files = _explicitfiles(kindpats)
330 self._files = _explicitfiles(kindpats)
350 self._anypats = self._anypats or _anypats(kindpats)
331 self._anypats = self._anypats or _anypats(kindpats)
351 self.patternspat, pm = _buildmatch(ctx, kindpats, '$',
332 self.patternspat, pm = _buildmatch(ctx, kindpats, '$',
352 listsubrepos, root)
333 listsubrepos, root)
353 matchfns.append(pm)
334 matchfns.append(pm)
354
335
355 if not matchfns:
336 if not matchfns:
356 m = util.always
337 m = util.always
357 self._always = True
338 self._always = True
358 elif len(matchfns) == 1:
339 elif len(matchfns) == 1:
359 m = matchfns[0]
340 m = matchfns[0]
360 else:
341 else:
361 def m(f):
342 def m(f):
362 for matchfn in matchfns:
343 for matchfn in matchfns:
363 if not matchfn(f):
344 if not matchfn(f):
364 return False
345 return False
365 return True
346 return True
366
347
367 self.matchfn = m
348 self.matchfn = m
368
349
369 @propertycache
350 @propertycache
370 def _dirs(self):
351 def _dirs(self):
371 return set(util.dirs(self._fileset)) | {'.'}
352 return set(util.dirs(self._fileset)) | {'.'}
372
353
373 def visitdir(self, dir):
354 def visitdir(self, dir):
374 if self.prefix() and dir in self._fileset:
355 if self.prefix() and dir in self._fileset:
375 return 'all'
356 return 'all'
376 if self._includeroots or self._includedirs:
377 if (not self._anyincludepats and
378 dir in self._includeroots):
379 # The condition above is essentially self.prefix() for includes
380 return 'all'
381 if ('.' not in self._includeroots and
382 dir not in self._includeroots and
383 dir not in self._includedirs and
384 not any(parent in self._includeroots
385 for parent in util.finddirs(dir))):
386 return False
387 return (not self._fileset or
357 return (not self._fileset or
388 '.' in self._fileset or
358 '.' in self._fileset or
389 dir in self._fileset or
359 dir in self._fileset or
390 dir in self._dirs or
360 dir in self._dirs or
391 any(parentdir in self._fileset
361 any(parentdir in self._fileset
392 for parentdir in util.finddirs(dir)))
362 for parentdir in util.finddirs(dir)))
393
363
394 def anypats(self):
364 def anypats(self):
395 return self._anypats
365 return self._anypats
396
366
397 def always(self):
367 def always(self):
398 return self._always
368 return self._always
399
369
400 def __repr__(self):
370 def __repr__(self):
401 return ('<patternmatcher patterns=%r, includes=%r>' %
371 return ('<patternmatcher patterns=%r>' % self.patternspat)
402 (self.patternspat, self.includepat))
403
372
404 class includematcher(basematcher):
373 class includematcher(basematcher):
405
374
406 def __init__(self, root, cwd, normalize, include, auditor=None, ctx=None,
375 def __init__(self, root, cwd, normalize, include, auditor=None, ctx=None,
407 listsubrepos=False, warn=None, badfn=None):
376 listsubrepos=False, warn=None, badfn=None):
408 super(includematcher, self).__init__(root, cwd, badfn)
377 super(includematcher, self).__init__(root, cwd, badfn)
409
378
410 kindpats = normalize(include, 'glob', root, cwd, auditor, warn)
379 kindpats = normalize(include, 'glob', root, cwd, auditor, warn)
411 self.includepat, im = _buildmatch(ctx, kindpats, '(?:/|$)',
380 self.includepat, im = _buildmatch(ctx, kindpats, '(?:/|$)',
412 listsubrepos, root)
381 listsubrepos, root)
413 self._anypats = _anypats(kindpats)
382 self._anypats = _anypats(kindpats)
414 roots, dirs = _rootsanddirs(kindpats)
383 roots, dirs = _rootsanddirs(kindpats)
415 # roots are directories which are recursively included.
384 # roots are directories which are recursively included.
416 self._roots = set(roots)
385 self._roots = set(roots)
417 # dirs are directories which are non-recursively included.
386 # dirs are directories which are non-recursively included.
418 self._dirs = set(dirs)
387 self._dirs = set(dirs)
419 self.matchfn = im
388 self.matchfn = im
420
389
421 def visitdir(self, dir):
390 def visitdir(self, dir):
422 if not self._anypats and dir in self._roots:
391 if not self._anypats and dir in self._roots:
423 # The condition above is essentially self.prefix() for includes
392 # The condition above is essentially self.prefix() for includes
424 return 'all'
393 return 'all'
425 return ('.' in self._roots or
394 return ('.' in self._roots or
426 dir in self._roots or
395 dir in self._roots or
427 dir in self._dirs or
396 dir in self._dirs or
428 any(parentdir in self._roots
397 any(parentdir in self._roots
429 for parentdir in util.finddirs(dir)))
398 for parentdir in util.finddirs(dir)))
430
399
431 def anypats(self):
400 def anypats(self):
432 return True
401 return True
433
402
434 def __repr__(self):
403 def __repr__(self):
435 return ('<includematcher includes=%r>' % self.includepat)
404 return ('<includematcher includes=%r>' % self.includepat)
436
405
437 class exactmatcher(basematcher):
406 class exactmatcher(basematcher):
438 '''Matches the input files exactly. They are interpreted as paths, not
407 '''Matches the input files exactly. They are interpreted as paths, not
439 patterns (so no kind-prefixes).
408 patterns (so no kind-prefixes).
440 '''
409 '''
441
410
442 def __init__(self, root, cwd, files, badfn=None):
411 def __init__(self, root, cwd, files, badfn=None):
443 super(exactmatcher, self).__init__(root, cwd, badfn)
412 super(exactmatcher, self).__init__(root, cwd, badfn)
444
413
445 if isinstance(files, list):
414 if isinstance(files, list):
446 self._files = files
415 self._files = files
447 else:
416 else:
448 self._files = list(files)
417 self._files = list(files)
449 self.matchfn = self.exact
418 self.matchfn = self.exact
450
419
451 @propertycache
420 @propertycache
452 def _dirs(self):
421 def _dirs(self):
453 return set(util.dirs(self._fileset)) | {'.'}
422 return set(util.dirs(self._fileset)) | {'.'}
454
423
455 def visitdir(self, dir):
424 def visitdir(self, dir):
456 return dir in self._dirs
425 return dir in self._dirs
457
426
458 def isexact(self):
427 def isexact(self):
459 return True
428 return True
460
429
461 def __repr__(self):
430 def __repr__(self):
462 return ('<exactmatcher files=%r>' % self._files)
431 return ('<exactmatcher files=%r>' % self._files)
463
432
464 class differencematcher(basematcher):
433 class differencematcher(basematcher):
465 '''Composes two matchers by matching if the first matches and the second
434 '''Composes two matchers by matching if the first matches and the second
466 does not. Well, almost... If the user provides a pattern like "-X foo foo",
435 does not. Well, almost... If the user provides a pattern like "-X foo foo",
467 Mercurial actually does match "foo" against that. That's because exact
436 Mercurial actually does match "foo" against that. That's because exact
468 matches are treated specially. So, since this differencematcher is used for
437 matches are treated specially. So, since this differencematcher is used for
469 excludes, it needs to special-case exact matching.
438 excludes, it needs to special-case exact matching.
470
439
471 The second matcher's non-matching-attributes (root, cwd, bad, explicitdir,
440 The second matcher's non-matching-attributes (root, cwd, bad, explicitdir,
472 traversedir) are ignored.
441 traversedir) are ignored.
473
442
474 TODO: If we want to keep the behavior described above for exact matches, we
443 TODO: If we want to keep the behavior described above for exact matches, we
475 should consider instead treating the above case something like this:
444 should consider instead treating the above case something like this:
476 union(exact(foo), difference(pattern(foo), include(foo)))
445 union(exact(foo), difference(pattern(foo), include(foo)))
477 '''
446 '''
478 def __init__(self, m1, m2):
447 def __init__(self, m1, m2):
479 super(differencematcher, self).__init__(m1._root, m1._cwd)
448 super(differencematcher, self).__init__(m1._root, m1._cwd)
480 self._m1 = m1
449 self._m1 = m1
481 self._m2 = m2
450 self._m2 = m2
482 self.bad = m1.bad
451 self.bad = m1.bad
483 self.explicitdir = m1.explicitdir
452 self.explicitdir = m1.explicitdir
484 self.traversedir = m1.traversedir
453 self.traversedir = m1.traversedir
485
454
486 def matchfn(self, f):
455 def matchfn(self, f):
487 return self._m1(f) and (not self._m2(f) or self._m1.exact(f))
456 return self._m1(f) and (not self._m2(f) or self._m1.exact(f))
488
457
489 @propertycache
458 @propertycache
490 def _files(self):
459 def _files(self):
491 if self.isexact():
460 if self.isexact():
492 return [f for f in self._m1.files() if self(f)]
461 return [f for f in self._m1.files() if self(f)]
493 # If m1 is not an exact matcher, we can't easily figure out the set of
462 # If m1 is not an exact matcher, we can't easily figure out the set of
494 # files, because its files() are not always files. For example, if
463 # files, because its files() are not always files. For example, if
495 # m1 is "path:dir" and m2 is "rootfileins:.", we don't
464 # m1 is "path:dir" and m2 is "rootfileins:.", we don't
496 # want to remove "dir" from the set even though it would match m2,
465 # want to remove "dir" from the set even though it would match m2,
497 # because the "dir" in m1 may not be a file.
466 # because the "dir" in m1 may not be a file.
498 return self._m1.files()
467 return self._m1.files()
499
468
500 def visitdir(self, dir):
469 def visitdir(self, dir):
501 if self._m2.visitdir(dir) == 'all':
470 if self._m2.visitdir(dir) == 'all':
502 # There's a bug here: If m1 matches file 'dir/file' and m2 excludes
471 # There's a bug here: If m1 matches file 'dir/file' and m2 excludes
503 # 'dir' (recursively), we should still visit 'dir' due to the
472 # 'dir' (recursively), we should still visit 'dir' due to the
504 # exception we have for exact matches.
473 # exception we have for exact matches.
505 return False
474 return False
506 return bool(self._m1.visitdir(dir))
475 return bool(self._m1.visitdir(dir))
507
476
508 def isexact(self):
477 def isexact(self):
509 return self._m1.isexact()
478 return self._m1.isexact()
510
479
511 def anypats(self):
480 def anypats(self):
512 return self._m1.anypats() or self._m2.anypats()
481 return self._m1.anypats() or self._m2.anypats()
513
482
514 def prefix(self):
483 def prefix(self):
515 return not self.always() and not self.isexact() and not self.anypats()
484 return not self.always() and not self.isexact() and not self.anypats()
516
485
517 def __repr__(self):
486 def __repr__(self):
518 return ('<differencematcher m1=%r, m2=%r>' % (self._m1, self._m2))
487 return ('<differencematcher m1=%r, m2=%r>' % (self._m1, self._m2))
519
488
520 def intersectmatchers(m1, m2):
489 def intersectmatchers(m1, m2):
521 '''Composes two matchers by matching if both of them match.
490 '''Composes two matchers by matching if both of them match.
522
491
523 The second matcher's non-matching-attributes (root, cwd, bad, explicitdir,
492 The second matcher's non-matching-attributes (root, cwd, bad, explicitdir,
524 traversedir) are ignored.
493 traversedir) are ignored.
525 '''
494 '''
526 if m1 is None or m2 is None:
495 if m1 is None or m2 is None:
527 return m1 or m2
496 return m1 or m2
528 if m1.always():
497 if m1.always():
529 m = copy.copy(m2)
498 m = copy.copy(m2)
530 # TODO: Consider encapsulating these things in a class so there's only
499 # TODO: Consider encapsulating these things in a class so there's only
531 # one thing to copy from m1.
500 # one thing to copy from m1.
532 m.bad = m1.bad
501 m.bad = m1.bad
533 m.explicitdir = m1.explicitdir
502 m.explicitdir = m1.explicitdir
534 m.traversedir = m1.traversedir
503 m.traversedir = m1.traversedir
535 m.abs = m1.abs
504 m.abs = m1.abs
536 m.rel = m1.rel
505 m.rel = m1.rel
537 m._relativeuipath |= m1._relativeuipath
506 m._relativeuipath |= m1._relativeuipath
538 return m
507 return m
539 if m2.always():
508 if m2.always():
540 m = copy.copy(m1)
509 m = copy.copy(m1)
541 m._relativeuipath |= m2._relativeuipath
510 m._relativeuipath |= m2._relativeuipath
542 return m
511 return m
543 return intersectionmatcher(m1, m2)
512 return intersectionmatcher(m1, m2)
544
513
545 class intersectionmatcher(basematcher):
514 class intersectionmatcher(basematcher):
546 def __init__(self, m1, m2):
515 def __init__(self, m1, m2):
547 super(intersectionmatcher, self).__init__(m1._root, m1._cwd)
516 super(intersectionmatcher, self).__init__(m1._root, m1._cwd)
548 self._m1 = m1
517 self._m1 = m1
549 self._m2 = m2
518 self._m2 = m2
550 self.bad = m1.bad
519 self.bad = m1.bad
551 self.explicitdir = m1.explicitdir
520 self.explicitdir = m1.explicitdir
552 self.traversedir = m1.traversedir
521 self.traversedir = m1.traversedir
553
522
554 @propertycache
523 @propertycache
555 def _files(self):
524 def _files(self):
556 if self.isexact():
525 if self.isexact():
557 m1, m2 = self._m1, self._m2
526 m1, m2 = self._m1, self._m2
558 if not m1.isexact():
527 if not m1.isexact():
559 m1, m2 = m2, m1
528 m1, m2 = m2, m1
560 return [f for f in m1.files() if m2(f)]
529 return [f for f in m1.files() if m2(f)]
561 # It neither m1 nor m2 is an exact matcher, we can't easily intersect
530 # It neither m1 nor m2 is an exact matcher, we can't easily intersect
562 # the set of files, because their files() are not always files. For
531 # the set of files, because their files() are not always files. For
563 # example, if intersecting a matcher "-I glob:foo.txt" with matcher of
532 # example, if intersecting a matcher "-I glob:foo.txt" with matcher of
564 # "path:dir2", we don't want to remove "dir2" from the set.
533 # "path:dir2", we don't want to remove "dir2" from the set.
565 return self._m1.files() + self._m2.files()
534 return self._m1.files() + self._m2.files()
566
535
567 def matchfn(self, f):
536 def matchfn(self, f):
568 return self._m1(f) and self._m2(f)
537 return self._m1(f) and self._m2(f)
569
538
570 def visitdir(self, dir):
539 def visitdir(self, dir):
571 visit1 = self._m1.visitdir(dir)
540 visit1 = self._m1.visitdir(dir)
572 if visit1 == 'all':
541 if visit1 == 'all':
573 return self._m2.visitdir(dir)
542 return self._m2.visitdir(dir)
574 # bool() because visit1=True + visit2='all' should not be 'all'
543 # bool() because visit1=True + visit2='all' should not be 'all'
575 return bool(visit1 and self._m2.visitdir(dir))
544 return bool(visit1 and self._m2.visitdir(dir))
576
545
577 def always(self):
546 def always(self):
578 return self._m1.always() and self._m2.always()
547 return self._m1.always() and self._m2.always()
579
548
580 def isexact(self):
549 def isexact(self):
581 return self._m1.isexact() or self._m2.isexact()
550 return self._m1.isexact() or self._m2.isexact()
582
551
583 def anypats(self):
552 def anypats(self):
584 return self._m1.anypats() or self._m2.anypats()
553 return self._m1.anypats() or self._m2.anypats()
585
554
586 def __repr__(self):
555 def __repr__(self):
587 return ('<intersectionmatcher m1=%r, m2=%r>' % (self._m1, self._m2))
556 return ('<intersectionmatcher m1=%r, m2=%r>' % (self._m1, self._m2))
588
557
589 class subdirmatcher(basematcher):
558 class subdirmatcher(basematcher):
590 """Adapt a matcher to work on a subdirectory only.
559 """Adapt a matcher to work on a subdirectory only.
591
560
592 The paths are remapped to remove/insert the path as needed:
561 The paths are remapped to remove/insert the path as needed:
593
562
594 >>> m1 = match('root', '', ['a.txt', 'sub/b.txt'])
563 >>> m1 = match('root', '', ['a.txt', 'sub/b.txt'])
595 >>> m2 = subdirmatcher('sub', m1)
564 >>> m2 = subdirmatcher('sub', m1)
596 >>> bool(m2('a.txt'))
565 >>> bool(m2('a.txt'))
597 False
566 False
598 >>> bool(m2('b.txt'))
567 >>> bool(m2('b.txt'))
599 True
568 True
600 >>> bool(m2.matchfn('a.txt'))
569 >>> bool(m2.matchfn('a.txt'))
601 False
570 False
602 >>> bool(m2.matchfn('b.txt'))
571 >>> bool(m2.matchfn('b.txt'))
603 True
572 True
604 >>> m2.files()
573 >>> m2.files()
605 ['b.txt']
574 ['b.txt']
606 >>> m2.exact('b.txt')
575 >>> m2.exact('b.txt')
607 True
576 True
608 >>> util.pconvert(m2.rel('b.txt'))
577 >>> util.pconvert(m2.rel('b.txt'))
609 'sub/b.txt'
578 'sub/b.txt'
610 >>> def bad(f, msg):
579 >>> def bad(f, msg):
611 ... print "%s: %s" % (f, msg)
580 ... print "%s: %s" % (f, msg)
612 >>> m1.bad = bad
581 >>> m1.bad = bad
613 >>> m2.bad('x.txt', 'No such file')
582 >>> m2.bad('x.txt', 'No such file')
614 sub/x.txt: No such file
583 sub/x.txt: No such file
615 >>> m2.abs('c.txt')
584 >>> m2.abs('c.txt')
616 'sub/c.txt'
585 'sub/c.txt'
617 """
586 """
618
587
619 def __init__(self, path, matcher):
588 def __init__(self, path, matcher):
620 super(subdirmatcher, self).__init__(matcher._root, matcher._cwd)
589 super(subdirmatcher, self).__init__(matcher._root, matcher._cwd)
621 self._path = path
590 self._path = path
622 self._matcher = matcher
591 self._matcher = matcher
623 self._always = matcher.always()
592 self._always = matcher.always()
624
593
625 self._files = [f[len(path) + 1:] for f in matcher._files
594 self._files = [f[len(path) + 1:] for f in matcher._files
626 if f.startswith(path + "/")]
595 if f.startswith(path + "/")]
627
596
628 # If the parent repo had a path to this subrepo and the matcher is
597 # If the parent repo had a path to this subrepo and the matcher is
629 # a prefix matcher, this submatcher always matches.
598 # a prefix matcher, this submatcher always matches.
630 if matcher.prefix():
599 if matcher.prefix():
631 self._always = any(f == path for f in matcher._files)
600 self._always = any(f == path for f in matcher._files)
632
601
633 def bad(self, f, msg):
602 def bad(self, f, msg):
634 self._matcher.bad(self._path + "/" + f, msg)
603 self._matcher.bad(self._path + "/" + f, msg)
635
604
636 def abs(self, f):
605 def abs(self, f):
637 return self._matcher.abs(self._path + "/" + f)
606 return self._matcher.abs(self._path + "/" + f)
638
607
639 def rel(self, f):
608 def rel(self, f):
640 return self._matcher.rel(self._path + "/" + f)
609 return self._matcher.rel(self._path + "/" + f)
641
610
642 def uipath(self, f):
611 def uipath(self, f):
643 return self._matcher.uipath(self._path + "/" + f)
612 return self._matcher.uipath(self._path + "/" + f)
644
613
645 def matchfn(self, f):
614 def matchfn(self, f):
646 # Some information is lost in the superclass's constructor, so we
615 # Some information is lost in the superclass's constructor, so we
647 # can not accurately create the matching function for the subdirectory
616 # can not accurately create the matching function for the subdirectory
648 # from the inputs. Instead, we override matchfn() and visitdir() to
617 # from the inputs. Instead, we override matchfn() and visitdir() to
649 # call the original matcher with the subdirectory path prepended.
618 # call the original matcher with the subdirectory path prepended.
650 return self._matcher.matchfn(self._path + "/" + f)
619 return self._matcher.matchfn(self._path + "/" + f)
651
620
652 def visitdir(self, dir):
621 def visitdir(self, dir):
653 if dir == '.':
622 if dir == '.':
654 dir = self._path
623 dir = self._path
655 else:
624 else:
656 dir = self._path + "/" + dir
625 dir = self._path + "/" + dir
657 return self._matcher.visitdir(dir)
626 return self._matcher.visitdir(dir)
658
627
659 def always(self):
628 def always(self):
660 return self._always
629 return self._always
661
630
662 def anypats(self):
631 def anypats(self):
663 return self._matcher.anypats()
632 return self._matcher.anypats()
664
633
665 def patkind(pattern, default=None):
634 def patkind(pattern, default=None):
666 '''If pattern is 'kind:pat' with a known kind, return kind.'''
635 '''If pattern is 'kind:pat' with a known kind, return kind.'''
667 return _patsplit(pattern, default)[0]
636 return _patsplit(pattern, default)[0]
668
637
669 def _patsplit(pattern, default):
638 def _patsplit(pattern, default):
670 """Split a string into the optional pattern kind prefix and the actual
639 """Split a string into the optional pattern kind prefix and the actual
671 pattern."""
640 pattern."""
672 if ':' in pattern:
641 if ':' in pattern:
673 kind, pat = pattern.split(':', 1)
642 kind, pat = pattern.split(':', 1)
674 if kind in ('re', 'glob', 'path', 'relglob', 'relpath', 'relre',
643 if kind in ('re', 'glob', 'path', 'relglob', 'relpath', 'relre',
675 'listfile', 'listfile0', 'set', 'include', 'subinclude',
644 'listfile', 'listfile0', 'set', 'include', 'subinclude',
676 'rootfilesin'):
645 'rootfilesin'):
677 return kind, pat
646 return kind, pat
678 return default, pattern
647 return default, pattern
679
648
680 def _globre(pat):
649 def _globre(pat):
681 r'''Convert an extended glob string to a regexp string.
650 r'''Convert an extended glob string to a regexp string.
682
651
683 >>> print _globre(r'?')
652 >>> print _globre(r'?')
684 .
653 .
685 >>> print _globre(r'*')
654 >>> print _globre(r'*')
686 [^/]*
655 [^/]*
687 >>> print _globre(r'**')
656 >>> print _globre(r'**')
688 .*
657 .*
689 >>> print _globre(r'**/a')
658 >>> print _globre(r'**/a')
690 (?:.*/)?a
659 (?:.*/)?a
691 >>> print _globre(r'a/**/b')
660 >>> print _globre(r'a/**/b')
692 a\/(?:.*/)?b
661 a\/(?:.*/)?b
693 >>> print _globre(r'[a*?!^][^b][!c]')
662 >>> print _globre(r'[a*?!^][^b][!c]')
694 [a*?!^][\^b][^c]
663 [a*?!^][\^b][^c]
695 >>> print _globre(r'{a,b}')
664 >>> print _globre(r'{a,b}')
696 (?:a|b)
665 (?:a|b)
697 >>> print _globre(r'.\*\?')
666 >>> print _globre(r'.\*\?')
698 \.\*\?
667 \.\*\?
699 '''
668 '''
700 i, n = 0, len(pat)
669 i, n = 0, len(pat)
701 res = ''
670 res = ''
702 group = 0
671 group = 0
703 escape = util.re.escape
672 escape = util.re.escape
704 def peek():
673 def peek():
705 return i < n and pat[i:i + 1]
674 return i < n and pat[i:i + 1]
706 while i < n:
675 while i < n:
707 c = pat[i:i + 1]
676 c = pat[i:i + 1]
708 i += 1
677 i += 1
709 if c not in '*?[{},\\':
678 if c not in '*?[{},\\':
710 res += escape(c)
679 res += escape(c)
711 elif c == '*':
680 elif c == '*':
712 if peek() == '*':
681 if peek() == '*':
713 i += 1
682 i += 1
714 if peek() == '/':
683 if peek() == '/':
715 i += 1
684 i += 1
716 res += '(?:.*/)?'
685 res += '(?:.*/)?'
717 else:
686 else:
718 res += '.*'
687 res += '.*'
719 else:
688 else:
720 res += '[^/]*'
689 res += '[^/]*'
721 elif c == '?':
690 elif c == '?':
722 res += '.'
691 res += '.'
723 elif c == '[':
692 elif c == '[':
724 j = i
693 j = i
725 if j < n and pat[j:j + 1] in '!]':
694 if j < n and pat[j:j + 1] in '!]':
726 j += 1
695 j += 1
727 while j < n and pat[j:j + 1] != ']':
696 while j < n and pat[j:j + 1] != ']':
728 j += 1
697 j += 1
729 if j >= n:
698 if j >= n:
730 res += '\\['
699 res += '\\['
731 else:
700 else:
732 stuff = pat[i:j].replace('\\','\\\\')
701 stuff = pat[i:j].replace('\\','\\\\')
733 i = j + 1
702 i = j + 1
734 if stuff[0:1] == '!':
703 if stuff[0:1] == '!':
735 stuff = '^' + stuff[1:]
704 stuff = '^' + stuff[1:]
736 elif stuff[0:1] == '^':
705 elif stuff[0:1] == '^':
737 stuff = '\\' + stuff
706 stuff = '\\' + stuff
738 res = '%s[%s]' % (res, stuff)
707 res = '%s[%s]' % (res, stuff)
739 elif c == '{':
708 elif c == '{':
740 group += 1
709 group += 1
741 res += '(?:'
710 res += '(?:'
742 elif c == '}' and group:
711 elif c == '}' and group:
743 res += ')'
712 res += ')'
744 group -= 1
713 group -= 1
745 elif c == ',' and group:
714 elif c == ',' and group:
746 res += '|'
715 res += '|'
747 elif c == '\\':
716 elif c == '\\':
748 p = peek()
717 p = peek()
749 if p:
718 if p:
750 i += 1
719 i += 1
751 res += escape(p)
720 res += escape(p)
752 else:
721 else:
753 res += escape(c)
722 res += escape(c)
754 else:
723 else:
755 res += escape(c)
724 res += escape(c)
756 return res
725 return res
757
726
758 def _regex(kind, pat, globsuffix):
727 def _regex(kind, pat, globsuffix):
759 '''Convert a (normalized) pattern of any kind into a regular expression.
728 '''Convert a (normalized) pattern of any kind into a regular expression.
760 globsuffix is appended to the regexp of globs.'''
729 globsuffix is appended to the regexp of globs.'''
761 if not pat:
730 if not pat:
762 return ''
731 return ''
763 if kind == 're':
732 if kind == 're':
764 return pat
733 return pat
765 if kind == 'path':
734 if kind == 'path':
766 if pat == '.':
735 if pat == '.':
767 return ''
736 return ''
768 return '^' + util.re.escape(pat) + '(?:/|$)'
737 return '^' + util.re.escape(pat) + '(?:/|$)'
769 if kind == 'rootfilesin':
738 if kind == 'rootfilesin':
770 if pat == '.':
739 if pat == '.':
771 escaped = ''
740 escaped = ''
772 else:
741 else:
773 # Pattern is a directory name.
742 # Pattern is a directory name.
774 escaped = util.re.escape(pat) + '/'
743 escaped = util.re.escape(pat) + '/'
775 # Anything after the pattern must be a non-directory.
744 # Anything after the pattern must be a non-directory.
776 return '^' + escaped + '[^/]+$'
745 return '^' + escaped + '[^/]+$'
777 if kind == 'relglob':
746 if kind == 'relglob':
778 return '(?:|.*/)' + _globre(pat) + globsuffix
747 return '(?:|.*/)' + _globre(pat) + globsuffix
779 if kind == 'relpath':
748 if kind == 'relpath':
780 return util.re.escape(pat) + '(?:/|$)'
749 return util.re.escape(pat) + '(?:/|$)'
781 if kind == 'relre':
750 if kind == 'relre':
782 if pat.startswith('^'):
751 if pat.startswith('^'):
783 return pat
752 return pat
784 return '.*' + pat
753 return '.*' + pat
785 return _globre(pat) + globsuffix
754 return _globre(pat) + globsuffix
786
755
787 def _buildmatch(ctx, kindpats, globsuffix, listsubrepos, root):
756 def _buildmatch(ctx, kindpats, globsuffix, listsubrepos, root):
788 '''Return regexp string and a matcher function for kindpats.
757 '''Return regexp string and a matcher function for kindpats.
789 globsuffix is appended to the regexp of globs.'''
758 globsuffix is appended to the regexp of globs.'''
790 matchfuncs = []
759 matchfuncs = []
791
760
792 subincludes, kindpats = _expandsubinclude(kindpats, root)
761 subincludes, kindpats = _expandsubinclude(kindpats, root)
793 if subincludes:
762 if subincludes:
794 submatchers = {}
763 submatchers = {}
795 def matchsubinclude(f):
764 def matchsubinclude(f):
796 for prefix, matcherargs in subincludes:
765 for prefix, matcherargs in subincludes:
797 if f.startswith(prefix):
766 if f.startswith(prefix):
798 mf = submatchers.get(prefix)
767 mf = submatchers.get(prefix)
799 if mf is None:
768 if mf is None:
800 mf = match(*matcherargs)
769 mf = match(*matcherargs)
801 submatchers[prefix] = mf
770 submatchers[prefix] = mf
802
771
803 if mf(f[len(prefix):]):
772 if mf(f[len(prefix):]):
804 return True
773 return True
805 return False
774 return False
806 matchfuncs.append(matchsubinclude)
775 matchfuncs.append(matchsubinclude)
807
776
808 fset, kindpats = _expandsets(kindpats, ctx, listsubrepos)
777 fset, kindpats = _expandsets(kindpats, ctx, listsubrepos)
809 if fset:
778 if fset:
810 matchfuncs.append(fset.__contains__)
779 matchfuncs.append(fset.__contains__)
811
780
812 regex = ''
781 regex = ''
813 if kindpats:
782 if kindpats:
814 regex, mf = _buildregexmatch(kindpats, globsuffix)
783 regex, mf = _buildregexmatch(kindpats, globsuffix)
815 matchfuncs.append(mf)
784 matchfuncs.append(mf)
816
785
817 if len(matchfuncs) == 1:
786 if len(matchfuncs) == 1:
818 return regex, matchfuncs[0]
787 return regex, matchfuncs[0]
819 else:
788 else:
820 return regex, lambda f: any(mf(f) for mf in matchfuncs)
789 return regex, lambda f: any(mf(f) for mf in matchfuncs)
821
790
822 def _buildregexmatch(kindpats, globsuffix):
791 def _buildregexmatch(kindpats, globsuffix):
823 """Build a match function from a list of kinds and kindpats,
792 """Build a match function from a list of kinds and kindpats,
824 return regexp string and a matcher function."""
793 return regexp string and a matcher function."""
825 try:
794 try:
826 regex = '(?:%s)' % '|'.join([_regex(k, p, globsuffix)
795 regex = '(?:%s)' % '|'.join([_regex(k, p, globsuffix)
827 for (k, p, s) in kindpats])
796 for (k, p, s) in kindpats])
828 if len(regex) > 20000:
797 if len(regex) > 20000:
829 raise OverflowError
798 raise OverflowError
830 return regex, _rematcher(regex)
799 return regex, _rematcher(regex)
831 except OverflowError:
800 except OverflowError:
832 # We're using a Python with a tiny regex engine and we
801 # We're using a Python with a tiny regex engine and we
833 # made it explode, so we'll divide the pattern list in two
802 # made it explode, so we'll divide the pattern list in two
834 # until it works
803 # until it works
835 l = len(kindpats)
804 l = len(kindpats)
836 if l < 2:
805 if l < 2:
837 raise
806 raise
838 regexa, a = _buildregexmatch(kindpats[:l//2], globsuffix)
807 regexa, a = _buildregexmatch(kindpats[:l//2], globsuffix)
839 regexb, b = _buildregexmatch(kindpats[l//2:], globsuffix)
808 regexb, b = _buildregexmatch(kindpats[l//2:], globsuffix)
840 return regex, lambda s: a(s) or b(s)
809 return regex, lambda s: a(s) or b(s)
841 except re.error:
810 except re.error:
842 for k, p, s in kindpats:
811 for k, p, s in kindpats:
843 try:
812 try:
844 _rematcher('(?:%s)' % _regex(k, p, globsuffix))
813 _rematcher('(?:%s)' % _regex(k, p, globsuffix))
845 except re.error:
814 except re.error:
846 if s:
815 if s:
847 raise error.Abort(_("%s: invalid pattern (%s): %s") %
816 raise error.Abort(_("%s: invalid pattern (%s): %s") %
848 (s, k, p))
817 (s, k, p))
849 else:
818 else:
850 raise error.Abort(_("invalid pattern (%s): %s") % (k, p))
819 raise error.Abort(_("invalid pattern (%s): %s") % (k, p))
851 raise error.Abort(_("invalid pattern"))
820 raise error.Abort(_("invalid pattern"))
852
821
853 def _patternrootsanddirs(kindpats):
822 def _patternrootsanddirs(kindpats):
854 '''Returns roots and directories corresponding to each pattern.
823 '''Returns roots and directories corresponding to each pattern.
855
824
856 This calculates the roots and directories exactly matching the patterns and
825 This calculates the roots and directories exactly matching the patterns and
857 returns a tuple of (roots, dirs) for each. It does not return other
826 returns a tuple of (roots, dirs) for each. It does not return other
858 directories which may also need to be considered, like the parent
827 directories which may also need to be considered, like the parent
859 directories.
828 directories.
860 '''
829 '''
861 r = []
830 r = []
862 d = []
831 d = []
863 for kind, pat, source in kindpats:
832 for kind, pat, source in kindpats:
864 if kind == 'glob': # find the non-glob prefix
833 if kind == 'glob': # find the non-glob prefix
865 root = []
834 root = []
866 for p in pat.split('/'):
835 for p in pat.split('/'):
867 if '[' in p or '{' in p or '*' in p or '?' in p:
836 if '[' in p or '{' in p or '*' in p or '?' in p:
868 break
837 break
869 root.append(p)
838 root.append(p)
870 r.append('/'.join(root) or '.')
839 r.append('/'.join(root) or '.')
871 elif kind in ('relpath', 'path'):
840 elif kind in ('relpath', 'path'):
872 r.append(pat or '.')
841 r.append(pat or '.')
873 elif kind in ('rootfilesin',):
842 elif kind in ('rootfilesin',):
874 d.append(pat or '.')
843 d.append(pat or '.')
875 else: # relglob, re, relre
844 else: # relglob, re, relre
876 r.append('.')
845 r.append('.')
877 return r, d
846 return r, d
878
847
879 def _roots(kindpats):
848 def _roots(kindpats):
880 '''Returns root directories to match recursively from the given patterns.'''
849 '''Returns root directories to match recursively from the given patterns.'''
881 roots, dirs = _patternrootsanddirs(kindpats)
850 roots, dirs = _patternrootsanddirs(kindpats)
882 return roots
851 return roots
883
852
884 def _rootsanddirs(kindpats):
853 def _rootsanddirs(kindpats):
885 '''Returns roots and exact directories from patterns.
854 '''Returns roots and exact directories from patterns.
886
855
887 roots are directories to match recursively, whereas exact directories should
856 roots are directories to match recursively, whereas exact directories should
888 be matched non-recursively. The returned (roots, dirs) tuple will also
857 be matched non-recursively. The returned (roots, dirs) tuple will also
889 include directories that need to be implicitly considered as either, such as
858 include directories that need to be implicitly considered as either, such as
890 parent directories.
859 parent directories.
891
860
892 >>> _rootsanddirs(\
861 >>> _rootsanddirs(\
893 [('glob', 'g/h/*', ''), ('glob', 'g/h', ''), ('glob', 'g*', '')])
862 [('glob', 'g/h/*', ''), ('glob', 'g/h', ''), ('glob', 'g*', '')])
894 (['g/h', 'g/h', '.'], ['g', '.'])
863 (['g/h', 'g/h', '.'], ['g', '.'])
895 >>> _rootsanddirs(\
864 >>> _rootsanddirs(\
896 [('rootfilesin', 'g/h', ''), ('rootfilesin', '', '')])
865 [('rootfilesin', 'g/h', ''), ('rootfilesin', '', '')])
897 ([], ['g/h', '.', 'g', '.'])
866 ([], ['g/h', '.', 'g', '.'])
898 >>> _rootsanddirs(\
867 >>> _rootsanddirs(\
899 [('relpath', 'r', ''), ('path', 'p/p', ''), ('path', '', '')])
868 [('relpath', 'r', ''), ('path', 'p/p', ''), ('path', '', '')])
900 (['r', 'p/p', '.'], ['p', '.'])
869 (['r', 'p/p', '.'], ['p', '.'])
901 >>> _rootsanddirs(\
870 >>> _rootsanddirs(\
902 [('relglob', 'rg*', ''), ('re', 're/', ''), ('relre', 'rr', '')])
871 [('relglob', 'rg*', ''), ('re', 're/', ''), ('relre', 'rr', '')])
903 (['.', '.', '.'], ['.'])
872 (['.', '.', '.'], ['.'])
904 '''
873 '''
905 r, d = _patternrootsanddirs(kindpats)
874 r, d = _patternrootsanddirs(kindpats)
906
875
907 # Append the parents as non-recursive/exact directories, since they must be
876 # Append the parents as non-recursive/exact directories, since they must be
908 # scanned to get to either the roots or the other exact directories.
877 # scanned to get to either the roots or the other exact directories.
909 d.extend(util.dirs(d))
878 d.extend(util.dirs(d))
910 d.extend(util.dirs(r))
879 d.extend(util.dirs(r))
911 # util.dirs() does not include the root directory, so add it manually
880 # util.dirs() does not include the root directory, so add it manually
912 d.append('.')
881 d.append('.')
913
882
914 return r, d
883 return r, d
915
884
916 def _explicitfiles(kindpats):
885 def _explicitfiles(kindpats):
917 '''Returns the potential explicit filenames from the patterns.
886 '''Returns the potential explicit filenames from the patterns.
918
887
919 >>> _explicitfiles([('path', 'foo/bar', '')])
888 >>> _explicitfiles([('path', 'foo/bar', '')])
920 ['foo/bar']
889 ['foo/bar']
921 >>> _explicitfiles([('rootfilesin', 'foo/bar', '')])
890 >>> _explicitfiles([('rootfilesin', 'foo/bar', '')])
922 []
891 []
923 '''
892 '''
924 # Keep only the pattern kinds where one can specify filenames (vs only
893 # Keep only the pattern kinds where one can specify filenames (vs only
925 # directory names).
894 # directory names).
926 filable = [kp for kp in kindpats if kp[0] not in ('rootfilesin',)]
895 filable = [kp for kp in kindpats if kp[0] not in ('rootfilesin',)]
927 return _roots(filable)
896 return _roots(filable)
928
897
929 def _anypats(kindpats):
898 def _anypats(kindpats):
930 for kind, pat, source in kindpats:
899 for kind, pat, source in kindpats:
931 if kind in ('glob', 're', 'relglob', 'relre', 'set', 'rootfilesin'):
900 if kind in ('glob', 're', 'relglob', 'relre', 'set', 'rootfilesin'):
932 return True
901 return True
933
902
934 _commentre = None
903 _commentre = None
935
904
936 def readpatternfile(filepath, warn, sourceinfo=False):
905 def readpatternfile(filepath, warn, sourceinfo=False):
937 '''parse a pattern file, returning a list of
906 '''parse a pattern file, returning a list of
938 patterns. These patterns should be given to compile()
907 patterns. These patterns should be given to compile()
939 to be validated and converted into a match function.
908 to be validated and converted into a match function.
940
909
941 trailing white space is dropped.
910 trailing white space is dropped.
942 the escape character is backslash.
911 the escape character is backslash.
943 comments start with #.
912 comments start with #.
944 empty lines are skipped.
913 empty lines are skipped.
945
914
946 lines can be of the following formats:
915 lines can be of the following formats:
947
916
948 syntax: regexp # defaults following lines to non-rooted regexps
917 syntax: regexp # defaults following lines to non-rooted regexps
949 syntax: glob # defaults following lines to non-rooted globs
918 syntax: glob # defaults following lines to non-rooted globs
950 re:pattern # non-rooted regular expression
919 re:pattern # non-rooted regular expression
951 glob:pattern # non-rooted glob
920 glob:pattern # non-rooted glob
952 pattern # pattern of the current default type
921 pattern # pattern of the current default type
953
922
954 if sourceinfo is set, returns a list of tuples:
923 if sourceinfo is set, returns a list of tuples:
955 (pattern, lineno, originalline). This is useful to debug ignore patterns.
924 (pattern, lineno, originalline). This is useful to debug ignore patterns.
956 '''
925 '''
957
926
958 syntaxes = {'re': 'relre:', 'regexp': 'relre:', 'glob': 'relglob:',
927 syntaxes = {'re': 'relre:', 'regexp': 'relre:', 'glob': 'relglob:',
959 'include': 'include', 'subinclude': 'subinclude'}
928 'include': 'include', 'subinclude': 'subinclude'}
960 syntax = 'relre:'
929 syntax = 'relre:'
961 patterns = []
930 patterns = []
962
931
963 fp = open(filepath, 'rb')
932 fp = open(filepath, 'rb')
964 for lineno, line in enumerate(util.iterfile(fp), start=1):
933 for lineno, line in enumerate(util.iterfile(fp), start=1):
965 if "#" in line:
934 if "#" in line:
966 global _commentre
935 global _commentre
967 if not _commentre:
936 if not _commentre:
968 _commentre = util.re.compile(br'((?:^|[^\\])(?:\\\\)*)#.*')
937 _commentre = util.re.compile(br'((?:^|[^\\])(?:\\\\)*)#.*')
969 # remove comments prefixed by an even number of escapes
938 # remove comments prefixed by an even number of escapes
970 m = _commentre.search(line)
939 m = _commentre.search(line)
971 if m:
940 if m:
972 line = line[:m.end(1)]
941 line = line[:m.end(1)]
973 # fixup properly escaped comments that survived the above
942 # fixup properly escaped comments that survived the above
974 line = line.replace("\\#", "#")
943 line = line.replace("\\#", "#")
975 line = line.rstrip()
944 line = line.rstrip()
976 if not line:
945 if not line:
977 continue
946 continue
978
947
979 if line.startswith('syntax:'):
948 if line.startswith('syntax:'):
980 s = line[7:].strip()
949 s = line[7:].strip()
981 try:
950 try:
982 syntax = syntaxes[s]
951 syntax = syntaxes[s]
983 except KeyError:
952 except KeyError:
984 if warn:
953 if warn:
985 warn(_("%s: ignoring invalid syntax '%s'\n") %
954 warn(_("%s: ignoring invalid syntax '%s'\n") %
986 (filepath, s))
955 (filepath, s))
987 continue
956 continue
988
957
989 linesyntax = syntax
958 linesyntax = syntax
990 for s, rels in syntaxes.iteritems():
959 for s, rels in syntaxes.iteritems():
991 if line.startswith(rels):
960 if line.startswith(rels):
992 linesyntax = rels
961 linesyntax = rels
993 line = line[len(rels):]
962 line = line[len(rels):]
994 break
963 break
995 elif line.startswith(s+':'):
964 elif line.startswith(s+':'):
996 linesyntax = rels
965 linesyntax = rels
997 line = line[len(s) + 1:]
966 line = line[len(s) + 1:]
998 break
967 break
999 if sourceinfo:
968 if sourceinfo:
1000 patterns.append((linesyntax + line, lineno, line))
969 patterns.append((linesyntax + line, lineno, line))
1001 else:
970 else:
1002 patterns.append(linesyntax + line)
971 patterns.append(linesyntax + line)
1003 fp.close()
972 fp.close()
1004 return patterns
973 return patterns
@@ -1,79 +1,79 b''
1 #require eol-in-paths
1 #require eol-in-paths
2
2
3 https://bz.mercurial-scm.org/352
3 https://bz.mercurial-scm.org/352
4
4
5 test issue352
5 test issue352
6
6
7 $ hg init foo
7 $ hg init foo
8 $ cd foo
8 $ cd foo
9 $ A=`printf 'he\rllo'`
9 $ A=`printf 'he\rllo'`
10 $ echo foo > "$A"
10 $ echo foo > "$A"
11 $ hg add
11 $ hg add
12 adding he\r (no-eol) (esc)
12 adding he\r (no-eol) (esc)
13 llo
13 llo
14 abort: '\n' and '\r' disallowed in filenames: 'he\rllo'
14 abort: '\n' and '\r' disallowed in filenames: 'he\rllo'
15 [255]
15 [255]
16 $ hg ci -A -m m
16 $ hg ci -A -m m
17 adding he\r (no-eol) (esc)
17 adding he\r (no-eol) (esc)
18 llo
18 llo
19 abort: '\n' and '\r' disallowed in filenames: 'he\rllo'
19 abort: '\n' and '\r' disallowed in filenames: 'he\rllo'
20 [255]
20 [255]
21 $ rm "$A"
21 $ rm "$A"
22 $ echo foo > "hell
22 $ echo foo > "hell
23 > o"
23 > o"
24 $ hg add
24 $ hg add
25 adding hell
25 adding hell
26 o
26 o
27 abort: '\n' and '\r' disallowed in filenames: 'hell\no'
27 abort: '\n' and '\r' disallowed in filenames: 'hell\no'
28 [255]
28 [255]
29 $ hg ci -A -m m
29 $ hg ci -A -m m
30 adding hell
30 adding hell
31 o
31 o
32 abort: '\n' and '\r' disallowed in filenames: 'hell\no'
32 abort: '\n' and '\r' disallowed in filenames: 'hell\no'
33 [255]
33 [255]
34 $ echo foo > "$A"
34 $ echo foo > "$A"
35 $ hg debugwalk
35 $ hg debugwalk
36 matcher: <patternmatcher patterns=None, includes=None>
36 matcher: <patternmatcher patterns=None>
37 f he\r (no-eol) (esc)
37 f he\r (no-eol) (esc)
38 llo he\r (no-eol) (esc)
38 llo he\r (no-eol) (esc)
39 llo
39 llo
40 f hell
40 f hell
41 o hell
41 o hell
42 o
42 o
43
43
44 $ echo bla > quickfox
44 $ echo bla > quickfox
45 $ hg add quickfox
45 $ hg add quickfox
46 $ hg ci -m 2
46 $ hg ci -m 2
47 $ A=`printf 'quick\rfox'`
47 $ A=`printf 'quick\rfox'`
48 $ hg cp quickfox "$A"
48 $ hg cp quickfox "$A"
49 abort: '\n' and '\r' disallowed in filenames: 'quick\rfox'
49 abort: '\n' and '\r' disallowed in filenames: 'quick\rfox'
50 [255]
50 [255]
51 $ hg mv quickfox "$A"
51 $ hg mv quickfox "$A"
52 abort: '\n' and '\r' disallowed in filenames: 'quick\rfox'
52 abort: '\n' and '\r' disallowed in filenames: 'quick\rfox'
53 [255]
53 [255]
54
54
55 https://bz.mercurial-scm.org/2036
55 https://bz.mercurial-scm.org/2036
56
56
57 $ cd ..
57 $ cd ..
58
58
59 test issue2039
59 test issue2039
60
60
61 $ hg init bar
61 $ hg init bar
62 $ cd bar
62 $ cd bar
63 $ cat <<EOF >> $HGRCPATH
63 $ cat <<EOF >> $HGRCPATH
64 > [extensions]
64 > [extensions]
65 > color =
65 > color =
66 > [color]
66 > [color]
67 > mode = ansi
67 > mode = ansi
68 > EOF
68 > EOF
69 $ A=`printf 'foo\nbar'`
69 $ A=`printf 'foo\nbar'`
70 $ B=`printf 'foo\nbar.baz'`
70 $ B=`printf 'foo\nbar.baz'`
71 $ touch "$A"
71 $ touch "$A"
72 $ touch "$B"
72 $ touch "$B"
73 $ hg status --color=always
73 $ hg status --color=always
74 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mfoo\x1b[0m (esc)
74 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mfoo\x1b[0m (esc)
75 \x1b[0;35;1;4mbar\x1b[0m (esc)
75 \x1b[0;35;1;4mbar\x1b[0m (esc)
76 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mfoo\x1b[0m (esc)
76 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mfoo\x1b[0m (esc)
77 \x1b[0;35;1;4mbar.baz\x1b[0m (esc)
77 \x1b[0;35;1;4mbar.baz\x1b[0m (esc)
78
78
79 $ cd ..
79 $ cd ..
@@ -1,518 +1,518 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
31 $ hg debugwalk
32 matcher: <patternmatcher patterns=None, includes=None>
32 matcher: <patternmatcher patterns=None>
33 f beans/black beans/black
33 f beans/black beans/black
34 f beans/borlotti beans/borlotti
34 f beans/borlotti beans/borlotti
35 f beans/kidney beans/kidney
35 f beans/kidney beans/kidney
36 f beans/navy beans/navy
36 f beans/navy beans/navy
37 f beans/pinto beans/pinto
37 f beans/pinto beans/pinto
38 f beans/turtle beans/turtle
38 f beans/turtle beans/turtle
39 f fennel fennel
39 f fennel fennel
40 f fenugreek fenugreek
40 f fenugreek fenugreek
41 f fiddlehead fiddlehead
41 f fiddlehead fiddlehead
42 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
42 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
43 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
43 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
44 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
44 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
45 f mammals/skunk mammals/skunk
45 f mammals/skunk mammals/skunk
46 $ hg debugwalk -I.
46 $ hg debugwalk -I.
47 matcher: <includematcher includes='(?:)'>
47 matcher: <includematcher includes='(?:)'>
48 f beans/black beans/black
48 f beans/black beans/black
49 f beans/borlotti beans/borlotti
49 f beans/borlotti beans/borlotti
50 f beans/kidney beans/kidney
50 f beans/kidney beans/kidney
51 f beans/navy beans/navy
51 f beans/navy beans/navy
52 f beans/pinto beans/pinto
52 f beans/pinto beans/pinto
53 f beans/turtle beans/turtle
53 f beans/turtle beans/turtle
54 f fennel fennel
54 f fennel fennel
55 f fenugreek fenugreek
55 f fenugreek fenugreek
56 f fiddlehead fiddlehead
56 f fiddlehead fiddlehead
57 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
57 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
58 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
58 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
59 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
59 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
60 f mammals/skunk mammals/skunk
60 f mammals/skunk mammals/skunk
61
61
62 $ cd mammals
62 $ cd mammals
63 $ hg debugwalk
63 $ hg debugwalk
64 matcher: <patternmatcher patterns=None, includes=None>
64 matcher: <patternmatcher patterns=None>
65 f beans/black ../beans/black
65 f beans/black ../beans/black
66 f beans/borlotti ../beans/borlotti
66 f beans/borlotti ../beans/borlotti
67 f beans/kidney ../beans/kidney
67 f beans/kidney ../beans/kidney
68 f beans/navy ../beans/navy
68 f beans/navy ../beans/navy
69 f beans/pinto ../beans/pinto
69 f beans/pinto ../beans/pinto
70 f beans/turtle ../beans/turtle
70 f beans/turtle ../beans/turtle
71 f fennel ../fennel
71 f fennel ../fennel
72 f fenugreek ../fenugreek
72 f fenugreek ../fenugreek
73 f fiddlehead ../fiddlehead
73 f fiddlehead ../fiddlehead
74 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
74 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
75 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
75 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
76 f mammals/Procyonidae/raccoon Procyonidae/raccoon
76 f mammals/Procyonidae/raccoon Procyonidae/raccoon
77 f mammals/skunk skunk
77 f mammals/skunk skunk
78 $ hg debugwalk -X ../beans
78 $ hg debugwalk -X ../beans
79 matcher: <differencematcher m1=<patternmatcher patterns=None, includes=None>, m2=<includematcher includes='(?:beans(?:/|$))'>>
79 matcher: <differencematcher m1=<patternmatcher patterns=None>, m2=<includematcher includes='(?:beans(?:/|$))'>>
80 f fennel ../fennel
80 f fennel ../fennel
81 f fenugreek ../fenugreek
81 f fenugreek ../fenugreek
82 f fiddlehead ../fiddlehead
82 f fiddlehead ../fiddlehead
83 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
83 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
84 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
84 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
85 f mammals/Procyonidae/raccoon Procyonidae/raccoon
85 f mammals/Procyonidae/raccoon Procyonidae/raccoon
86 f mammals/skunk skunk
86 f mammals/skunk skunk
87 $ hg debugwalk -I '*k'
87 $ hg debugwalk -I '*k'
88 matcher: <includematcher includes='(?:mammals\\/[^/]*k(?:/|$))'>
88 matcher: <includematcher includes='(?:mammals\\/[^/]*k(?:/|$))'>
89 f mammals/skunk skunk
89 f mammals/skunk skunk
90 $ hg debugwalk -I 'glob:*k'
90 $ hg debugwalk -I 'glob:*k'
91 matcher: <includematcher includes='(?:mammals\\/[^/]*k(?:/|$))'>
91 matcher: <includematcher includes='(?:mammals\\/[^/]*k(?:/|$))'>
92 f mammals/skunk skunk
92 f mammals/skunk skunk
93 $ hg debugwalk -I 'relglob:*k'
93 $ hg debugwalk -I 'relglob:*k'
94 matcher: <includematcher includes='(?:(?:|.*/)[^/]*k(?:/|$))'>
94 matcher: <includematcher includes='(?:(?:|.*/)[^/]*k(?:/|$))'>
95 f beans/black ../beans/black
95 f beans/black ../beans/black
96 f fenugreek ../fenugreek
96 f fenugreek ../fenugreek
97 f mammals/skunk skunk
97 f mammals/skunk skunk
98 $ hg debugwalk -I 'relglob:*k' .
98 $ hg debugwalk -I 'relglob:*k' .
99 matcher: <intersectionmatcher m1=<patternmatcher patterns='(?:mammals(?:/|$))', includes=None>, m2=<includematcher includes='(?:(?:|.*/)[^/]*k(?:/|$))'>>
99 matcher: <intersectionmatcher m1=<patternmatcher patterns='(?:mammals(?:/|$))'>, m2=<includematcher includes='(?:(?:|.*/)[^/]*k(?:/|$))'>>
100 f mammals/skunk skunk
100 f mammals/skunk skunk
101 $ hg debugwalk -I 're:.*k$'
101 $ hg debugwalk -I 're:.*k$'
102 matcher: <includematcher includes='(?:.*k$)'>
102 matcher: <includematcher includes='(?:.*k$)'>
103 f beans/black ../beans/black
103 f beans/black ../beans/black
104 f fenugreek ../fenugreek
104 f fenugreek ../fenugreek
105 f mammals/skunk skunk
105 f mammals/skunk skunk
106 $ hg debugwalk -I 'relre:.*k$'
106 $ hg debugwalk -I 'relre:.*k$'
107 matcher: <includematcher includes='(?:.*.*k$)'>
107 matcher: <includematcher includes='(?:.*.*k$)'>
108 f beans/black ../beans/black
108 f beans/black ../beans/black
109 f fenugreek ../fenugreek
109 f fenugreek ../fenugreek
110 f mammals/skunk skunk
110 f mammals/skunk skunk
111 $ hg debugwalk -I 'path:beans'
111 $ hg debugwalk -I 'path:beans'
112 matcher: <includematcher includes='(?:^beans(?:/|$))'>
112 matcher: <includematcher includes='(?:^beans(?:/|$))'>
113 f beans/black ../beans/black
113 f beans/black ../beans/black
114 f beans/borlotti ../beans/borlotti
114 f beans/borlotti ../beans/borlotti
115 f beans/kidney ../beans/kidney
115 f beans/kidney ../beans/kidney
116 f beans/navy ../beans/navy
116 f beans/navy ../beans/navy
117 f beans/pinto ../beans/pinto
117 f beans/pinto ../beans/pinto
118 f beans/turtle ../beans/turtle
118 f beans/turtle ../beans/turtle
119 $ hg debugwalk -I 'relpath:detour/../../beans'
119 $ hg debugwalk -I 'relpath:detour/../../beans'
120 matcher: <includematcher includes='(?:beans(?:/|$))'>
120 matcher: <includematcher includes='(?:beans(?:/|$))'>
121 f beans/black ../beans/black
121 f beans/black ../beans/black
122 f beans/borlotti ../beans/borlotti
122 f beans/borlotti ../beans/borlotti
123 f beans/kidney ../beans/kidney
123 f beans/kidney ../beans/kidney
124 f beans/navy ../beans/navy
124 f beans/navy ../beans/navy
125 f beans/pinto ../beans/pinto
125 f beans/pinto ../beans/pinto
126 f beans/turtle ../beans/turtle
126 f beans/turtle ../beans/turtle
127
127
128 $ hg debugwalk 'rootfilesin:'
128 $ hg debugwalk 'rootfilesin:'
129 matcher: <patternmatcher patterns='(?:^[^/]+$)', includes=None>
129 matcher: <patternmatcher patterns='(?:^[^/]+$)'>
130 f fennel ../fennel
130 f fennel ../fennel
131 f fenugreek ../fenugreek
131 f fenugreek ../fenugreek
132 f fiddlehead ../fiddlehead
132 f fiddlehead ../fiddlehead
133 $ hg debugwalk -I 'rootfilesin:'
133 $ hg debugwalk -I 'rootfilesin:'
134 matcher: <includematcher includes='(?:^[^/]+$)'>
134 matcher: <includematcher includes='(?:^[^/]+$)'>
135 f fennel ../fennel
135 f fennel ../fennel
136 f fenugreek ../fenugreek
136 f fenugreek ../fenugreek
137 f fiddlehead ../fiddlehead
137 f fiddlehead ../fiddlehead
138 $ hg debugwalk 'rootfilesin:.'
138 $ hg debugwalk 'rootfilesin:.'
139 matcher: <patternmatcher patterns='(?:^[^/]+$)', includes=None>
139 matcher: <patternmatcher patterns='(?:^[^/]+$)'>
140 f fennel ../fennel
140 f fennel ../fennel
141 f fenugreek ../fenugreek
141 f fenugreek ../fenugreek
142 f fiddlehead ../fiddlehead
142 f fiddlehead ../fiddlehead
143 $ hg debugwalk -I 'rootfilesin:.'
143 $ hg debugwalk -I 'rootfilesin:.'
144 matcher: <includematcher includes='(?:^[^/]+$)'>
144 matcher: <includematcher includes='(?:^[^/]+$)'>
145 f fennel ../fennel
145 f fennel ../fennel
146 f fenugreek ../fenugreek
146 f fenugreek ../fenugreek
147 f fiddlehead ../fiddlehead
147 f fiddlehead ../fiddlehead
148 $ hg debugwalk -X 'rootfilesin:'
148 $ hg debugwalk -X 'rootfilesin:'
149 matcher: <differencematcher m1=<patternmatcher patterns=None, includes=None>, m2=<includematcher includes='(?:^[^/]+$)'>>
149 matcher: <differencematcher m1=<patternmatcher patterns=None>, m2=<includematcher includes='(?:^[^/]+$)'>>
150 f beans/black ../beans/black
150 f beans/black ../beans/black
151 f beans/borlotti ../beans/borlotti
151 f beans/borlotti ../beans/borlotti
152 f beans/kidney ../beans/kidney
152 f beans/kidney ../beans/kidney
153 f beans/navy ../beans/navy
153 f beans/navy ../beans/navy
154 f beans/pinto ../beans/pinto
154 f beans/pinto ../beans/pinto
155 f beans/turtle ../beans/turtle
155 f beans/turtle ../beans/turtle
156 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
156 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
157 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
157 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
158 f mammals/Procyonidae/raccoon Procyonidae/raccoon
158 f mammals/Procyonidae/raccoon Procyonidae/raccoon
159 f mammals/skunk skunk
159 f mammals/skunk skunk
160 $ hg debugwalk 'rootfilesin:fennel'
160 $ hg debugwalk 'rootfilesin:fennel'
161 matcher: <patternmatcher patterns='(?:^fennel/[^/]+$)', includes=None>
161 matcher: <patternmatcher patterns='(?:^fennel/[^/]+$)'>
162 $ hg debugwalk -I 'rootfilesin:fennel'
162 $ hg debugwalk -I 'rootfilesin:fennel'
163 matcher: <includematcher includes='(?:^fennel/[^/]+$)'>
163 matcher: <includematcher includes='(?:^fennel/[^/]+$)'>
164 $ hg debugwalk 'rootfilesin:skunk'
164 $ hg debugwalk 'rootfilesin:skunk'
165 matcher: <patternmatcher patterns='(?:^skunk/[^/]+$)', includes=None>
165 matcher: <patternmatcher patterns='(?:^skunk/[^/]+$)'>
166 $ hg debugwalk -I 'rootfilesin:skunk'
166 $ hg debugwalk -I 'rootfilesin:skunk'
167 matcher: <includematcher includes='(?:^skunk/[^/]+$)'>
167 matcher: <includematcher includes='(?:^skunk/[^/]+$)'>
168 $ hg debugwalk 'rootfilesin:beans'
168 $ hg debugwalk 'rootfilesin:beans'
169 matcher: <patternmatcher patterns='(?:^beans/[^/]+$)', includes=None>
169 matcher: <patternmatcher patterns='(?:^beans/[^/]+$)'>
170 f beans/black ../beans/black
170 f beans/black ../beans/black
171 f beans/borlotti ../beans/borlotti
171 f beans/borlotti ../beans/borlotti
172 f beans/kidney ../beans/kidney
172 f beans/kidney ../beans/kidney
173 f beans/navy ../beans/navy
173 f beans/navy ../beans/navy
174 f beans/pinto ../beans/pinto
174 f beans/pinto ../beans/pinto
175 f beans/turtle ../beans/turtle
175 f beans/turtle ../beans/turtle
176 $ hg debugwalk -I 'rootfilesin:beans'
176 $ hg debugwalk -I 'rootfilesin:beans'
177 matcher: <includematcher includes='(?:^beans/[^/]+$)'>
177 matcher: <includematcher includes='(?:^beans/[^/]+$)'>
178 f beans/black ../beans/black
178 f beans/black ../beans/black
179 f beans/borlotti ../beans/borlotti
179 f beans/borlotti ../beans/borlotti
180 f beans/kidney ../beans/kidney
180 f beans/kidney ../beans/kidney
181 f beans/navy ../beans/navy
181 f beans/navy ../beans/navy
182 f beans/pinto ../beans/pinto
182 f beans/pinto ../beans/pinto
183 f beans/turtle ../beans/turtle
183 f beans/turtle ../beans/turtle
184 $ hg debugwalk 'rootfilesin:mammals'
184 $ hg debugwalk 'rootfilesin:mammals'
185 matcher: <patternmatcher patterns='(?:^mammals/[^/]+$)', includes=None>
185 matcher: <patternmatcher patterns='(?:^mammals/[^/]+$)'>
186 f mammals/skunk skunk
186 f mammals/skunk skunk
187 $ hg debugwalk -I 'rootfilesin:mammals'
187 $ hg debugwalk -I 'rootfilesin:mammals'
188 matcher: <includematcher includes='(?:^mammals/[^/]+$)'>
188 matcher: <includematcher includes='(?:^mammals/[^/]+$)'>
189 f mammals/skunk skunk
189 f mammals/skunk skunk
190 $ hg debugwalk 'rootfilesin:mammals/'
190 $ hg debugwalk 'rootfilesin:mammals/'
191 matcher: <patternmatcher patterns='(?:^mammals/[^/]+$)', includes=None>
191 matcher: <patternmatcher patterns='(?:^mammals/[^/]+$)'>
192 f mammals/skunk skunk
192 f mammals/skunk skunk
193 $ hg debugwalk -I 'rootfilesin:mammals/'
193 $ hg debugwalk -I 'rootfilesin:mammals/'
194 matcher: <includematcher includes='(?:^mammals/[^/]+$)'>
194 matcher: <includematcher includes='(?:^mammals/[^/]+$)'>
195 f mammals/skunk skunk
195 f mammals/skunk skunk
196 $ hg debugwalk -X 'rootfilesin:mammals'
196 $ hg debugwalk -X 'rootfilesin:mammals'
197 matcher: <differencematcher m1=<patternmatcher patterns=None, includes=None>, m2=<includematcher includes='(?:^mammals/[^/]+$)'>>
197 matcher: <differencematcher m1=<patternmatcher patterns=None>, m2=<includematcher includes='(?:^mammals/[^/]+$)'>>
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 f fennel ../fennel
204 f fennel ../fennel
205 f fenugreek ../fenugreek
205 f fenugreek ../fenugreek
206 f fiddlehead ../fiddlehead
206 f fiddlehead ../fiddlehead
207 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
207 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
208 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
208 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
209 f mammals/Procyonidae/raccoon Procyonidae/raccoon
209 f mammals/Procyonidae/raccoon Procyonidae/raccoon
210
210
211 $ hg debugwalk .
211 $ hg debugwalk .
212 matcher: <patternmatcher patterns='(?:mammals(?:/|$))', includes=None>
212 matcher: <patternmatcher patterns='(?:mammals(?:/|$))'>
213 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
213 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
214 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
214 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
215 f mammals/Procyonidae/raccoon Procyonidae/raccoon
215 f mammals/Procyonidae/raccoon Procyonidae/raccoon
216 f mammals/skunk skunk
216 f mammals/skunk skunk
217 $ hg debugwalk -I.
217 $ hg debugwalk -I.
218 matcher: <includematcher includes='(?:mammals(?:/|$))'>
218 matcher: <includematcher includes='(?:mammals(?:/|$))'>
219 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
219 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
220 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
220 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
221 f mammals/Procyonidae/raccoon Procyonidae/raccoon
221 f mammals/Procyonidae/raccoon Procyonidae/raccoon
222 f mammals/skunk skunk
222 f mammals/skunk skunk
223 $ hg debugwalk Procyonidae
223 $ hg debugwalk Procyonidae
224 matcher: <patternmatcher patterns='(?:mammals\\/Procyonidae(?:/|$))', includes=None>
224 matcher: <patternmatcher patterns='(?:mammals\\/Procyonidae(?:/|$))'>
225 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
225 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
226 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
226 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
227 f mammals/Procyonidae/raccoon Procyonidae/raccoon
227 f mammals/Procyonidae/raccoon Procyonidae/raccoon
228
228
229 $ cd Procyonidae
229 $ cd Procyonidae
230 $ hg debugwalk .
230 $ hg debugwalk .
231 matcher: <patternmatcher patterns='(?:mammals\\/Procyonidae(?:/|$))', includes=None>
231 matcher: <patternmatcher patterns='(?:mammals\\/Procyonidae(?:/|$))'>
232 f mammals/Procyonidae/cacomistle cacomistle
232 f mammals/Procyonidae/cacomistle cacomistle
233 f mammals/Procyonidae/coatimundi coatimundi
233 f mammals/Procyonidae/coatimundi coatimundi
234 f mammals/Procyonidae/raccoon raccoon
234 f mammals/Procyonidae/raccoon raccoon
235 $ hg debugwalk ..
235 $ hg debugwalk ..
236 matcher: <patternmatcher patterns='(?:mammals(?:/|$))', includes=None>
236 matcher: <patternmatcher patterns='(?:mammals(?:/|$))'>
237 f mammals/Procyonidae/cacomistle cacomistle
237 f mammals/Procyonidae/cacomistle cacomistle
238 f mammals/Procyonidae/coatimundi coatimundi
238 f mammals/Procyonidae/coatimundi coatimundi
239 f mammals/Procyonidae/raccoon raccoon
239 f mammals/Procyonidae/raccoon raccoon
240 f mammals/skunk ../skunk
240 f mammals/skunk ../skunk
241 $ cd ..
241 $ cd ..
242
242
243 $ hg debugwalk ../beans
243 $ hg debugwalk ../beans
244 matcher: <patternmatcher patterns='(?:beans(?:/|$))', includes=None>
244 matcher: <patternmatcher patterns='(?:beans(?:/|$))'>
245 f beans/black ../beans/black
245 f beans/black ../beans/black
246 f beans/borlotti ../beans/borlotti
246 f beans/borlotti ../beans/borlotti
247 f beans/kidney ../beans/kidney
247 f beans/kidney ../beans/kidney
248 f beans/navy ../beans/navy
248 f beans/navy ../beans/navy
249 f beans/pinto ../beans/pinto
249 f beans/pinto ../beans/pinto
250 f beans/turtle ../beans/turtle
250 f beans/turtle ../beans/turtle
251 $ hg debugwalk .
251 $ hg debugwalk .
252 matcher: <patternmatcher patterns='(?:mammals(?:/|$))', includes=None>
252 matcher: <patternmatcher patterns='(?:mammals(?:/|$))'>
253 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
253 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
254 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
254 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
255 f mammals/Procyonidae/raccoon Procyonidae/raccoon
255 f mammals/Procyonidae/raccoon Procyonidae/raccoon
256 f mammals/skunk skunk
256 f mammals/skunk skunk
257 $ hg debugwalk .hg
257 $ hg debugwalk .hg
258 abort: path 'mammals/.hg' is inside nested repo 'mammals' (glob)
258 abort: path 'mammals/.hg' is inside nested repo 'mammals' (glob)
259 [255]
259 [255]
260 $ hg debugwalk ../.hg
260 $ hg debugwalk ../.hg
261 abort: path contains illegal component: .hg
261 abort: path contains illegal component: .hg
262 [255]
262 [255]
263 $ cd ..
263 $ cd ..
264
264
265 $ hg debugwalk -Ibeans
265 $ hg debugwalk -Ibeans
266 matcher: <includematcher includes='(?:beans(?:/|$))'>
266 matcher: <includematcher includes='(?:beans(?:/|$))'>
267 f beans/black beans/black
267 f beans/black beans/black
268 f beans/borlotti beans/borlotti
268 f beans/borlotti beans/borlotti
269 f beans/kidney beans/kidney
269 f beans/kidney beans/kidney
270 f beans/navy beans/navy
270 f beans/navy beans/navy
271 f beans/pinto beans/pinto
271 f beans/pinto beans/pinto
272 f beans/turtle beans/turtle
272 f beans/turtle beans/turtle
273 $ hg debugwalk -I '{*,{b,m}*/*}k'
273 $ hg debugwalk -I '{*,{b,m}*/*}k'
274 matcher: <includematcher includes='(?:(?:[^/]*|(?:b|m)[^/]*\\/[^/]*)k(?:/|$))'>
274 matcher: <includematcher includes='(?:(?:[^/]*|(?:b|m)[^/]*\\/[^/]*)k(?:/|$))'>
275 f beans/black beans/black
275 f beans/black beans/black
276 f fenugreek fenugreek
276 f fenugreek fenugreek
277 f mammals/skunk mammals/skunk
277 f mammals/skunk mammals/skunk
278 $ hg debugwalk -Ibeans mammals
278 $ hg debugwalk -Ibeans mammals
279 matcher: <intersectionmatcher m1=<patternmatcher patterns='(?:mammals(?:/|$))', includes=None>, m2=<includematcher includes='(?:beans(?:/|$))'>>
279 matcher: <intersectionmatcher m1=<patternmatcher patterns='(?:mammals(?:/|$))'>, m2=<includematcher includes='(?:beans(?:/|$))'>>
280 $ hg debugwalk -Inon-existent
280 $ hg debugwalk -Inon-existent
281 matcher: <includematcher includes='(?:non\\-existent(?:/|$))'>
281 matcher: <includematcher includes='(?:non\\-existent(?:/|$))'>
282 $ hg debugwalk -Inon-existent -Ibeans/black
282 $ hg debugwalk -Inon-existent -Ibeans/black
283 matcher: <includematcher includes='(?:non\\-existent(?:/|$)|beans\\/black(?:/|$))'>
283 matcher: <includematcher includes='(?:non\\-existent(?:/|$)|beans\\/black(?:/|$))'>
284 f beans/black beans/black
284 f beans/black beans/black
285 $ hg debugwalk -Ibeans beans/black
285 $ hg debugwalk -Ibeans beans/black
286 matcher: <intersectionmatcher m1=<patternmatcher patterns='(?:beans\\/black(?:/|$))', includes=None>, m2=<includematcher includes='(?:beans(?:/|$))'>>
286 matcher: <intersectionmatcher m1=<patternmatcher patterns='(?:beans\\/black(?:/|$))'>, m2=<includematcher includes='(?:beans(?:/|$))'>>
287 f beans/black beans/black exact
287 f beans/black beans/black exact
288 $ hg debugwalk -Ibeans/black beans
288 $ hg debugwalk -Ibeans/black beans
289 matcher: <intersectionmatcher m1=<patternmatcher patterns='(?:beans(?:/|$))', includes=None>, m2=<includematcher includes='(?:beans\\/black(?:/|$))'>>
289 matcher: <intersectionmatcher m1=<patternmatcher patterns='(?:beans(?:/|$))'>, m2=<includematcher includes='(?:beans\\/black(?:/|$))'>>
290 f beans/black beans/black
290 f beans/black beans/black
291 $ hg debugwalk -Xbeans/black beans
291 $ hg debugwalk -Xbeans/black beans
292 matcher: <differencematcher m1=<patternmatcher patterns='(?:beans(?:/|$))', includes=None>, m2=<includematcher includes='(?:beans\\/black(?:/|$))'>>
292 matcher: <differencematcher m1=<patternmatcher patterns='(?:beans(?:/|$))'>, m2=<includematcher includes='(?:beans\\/black(?:/|$))'>>
293 f beans/borlotti beans/borlotti
293 f beans/borlotti beans/borlotti
294 f beans/kidney beans/kidney
294 f beans/kidney beans/kidney
295 f beans/navy beans/navy
295 f beans/navy beans/navy
296 f beans/pinto beans/pinto
296 f beans/pinto beans/pinto
297 f beans/turtle beans/turtle
297 f beans/turtle beans/turtle
298 $ hg debugwalk -Xbeans/black -Ibeans
298 $ hg debugwalk -Xbeans/black -Ibeans
299 matcher: <differencematcher m1=<includematcher includes='(?:beans(?:/|$))'>, m2=<includematcher includes='(?:beans\\/black(?:/|$))'>>
299 matcher: <differencematcher m1=<includematcher includes='(?:beans(?:/|$))'>, m2=<includematcher includes='(?:beans\\/black(?:/|$))'>>
300 f beans/borlotti beans/borlotti
300 f beans/borlotti beans/borlotti
301 f beans/kidney beans/kidney
301 f beans/kidney beans/kidney
302 f beans/navy beans/navy
302 f beans/navy beans/navy
303 f beans/pinto beans/pinto
303 f beans/pinto beans/pinto
304 f beans/turtle beans/turtle
304 f beans/turtle beans/turtle
305 $ hg debugwalk -Xbeans/black beans/black
305 $ hg debugwalk -Xbeans/black beans/black
306 matcher: <differencematcher m1=<patternmatcher patterns='(?:beans\\/black(?:/|$))', includes=None>, m2=<includematcher includes='(?:beans\\/black(?:/|$))'>>
306 matcher: <differencematcher m1=<patternmatcher patterns='(?:beans\\/black(?:/|$))'>, m2=<includematcher includes='(?:beans\\/black(?:/|$))'>>
307 f beans/black beans/black exact
307 f beans/black beans/black exact
308 $ hg debugwalk -Xbeans/black -Ibeans/black
308 $ hg debugwalk -Xbeans/black -Ibeans/black
309 matcher: <differencematcher m1=<includematcher includes='(?:beans\\/black(?:/|$))'>, m2=<includematcher includes='(?:beans\\/black(?:/|$))'>>
309 matcher: <differencematcher m1=<includematcher includes='(?:beans\\/black(?:/|$))'>, m2=<includematcher includes='(?:beans\\/black(?:/|$))'>>
310 $ hg debugwalk -Xbeans beans/black
310 $ hg debugwalk -Xbeans beans/black
311 matcher: <differencematcher m1=<patternmatcher patterns='(?:beans\\/black(?:/|$))', includes=None>, m2=<includematcher includes='(?:beans(?:/|$))'>>
311 matcher: <differencematcher m1=<patternmatcher patterns='(?:beans\\/black(?:/|$))'>, m2=<includematcher includes='(?:beans(?:/|$))'>>
312 f beans/black beans/black exact
312 f beans/black beans/black exact
313 $ hg debugwalk -Xbeans -Ibeans/black
313 $ hg debugwalk -Xbeans -Ibeans/black
314 matcher: <differencematcher m1=<includematcher includes='(?:beans\\/black(?:/|$))'>, m2=<includematcher includes='(?:beans(?:/|$))'>>
314 matcher: <differencematcher m1=<includematcher includes='(?:beans\\/black(?:/|$))'>, m2=<includematcher includes='(?:beans(?:/|$))'>>
315 $ hg debugwalk 'glob:mammals/../beans/b*'
315 $ hg debugwalk 'glob:mammals/../beans/b*'
316 matcher: <patternmatcher patterns='(?:beans\\/b[^/]*$)', includes=None>
316 matcher: <patternmatcher patterns='(?:beans\\/b[^/]*$)'>
317 f beans/black beans/black
317 f beans/black beans/black
318 f beans/borlotti beans/borlotti
318 f beans/borlotti beans/borlotti
319 $ hg debugwalk '-X*/Procyonidae' mammals
319 $ hg debugwalk '-X*/Procyonidae' mammals
320 matcher: <differencematcher m1=<patternmatcher patterns='(?:mammals(?:/|$))', includes=None>, m2=<includematcher includes='(?:[^/]*\\/Procyonidae(?:/|$))'>>
320 matcher: <differencematcher m1=<patternmatcher patterns='(?:mammals(?:/|$))'>, m2=<includematcher includes='(?:[^/]*\\/Procyonidae(?:/|$))'>>
321 f mammals/skunk mammals/skunk
321 f mammals/skunk mammals/skunk
322 $ hg debugwalk path:mammals
322 $ hg debugwalk path:mammals
323 matcher: <patternmatcher patterns='(?:^mammals(?:/|$))', includes=None>
323 matcher: <patternmatcher patterns='(?:^mammals(?:/|$))'>
324 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
324 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
325 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
325 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
326 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
326 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
327 f mammals/skunk mammals/skunk
327 f mammals/skunk mammals/skunk
328 $ hg debugwalk ..
328 $ hg debugwalk ..
329 abort: .. not under root '$TESTTMP/t' (glob)
329 abort: .. not under root '$TESTTMP/t' (glob)
330 [255]
330 [255]
331 $ hg debugwalk beans/../..
331 $ hg debugwalk beans/../..
332 abort: beans/../.. not under root '$TESTTMP/t' (glob)
332 abort: beans/../.. not under root '$TESTTMP/t' (glob)
333 [255]
333 [255]
334 $ hg debugwalk .hg
334 $ hg debugwalk .hg
335 abort: path contains illegal component: .hg
335 abort: path contains illegal component: .hg
336 [255]
336 [255]
337 $ hg debugwalk beans/../.hg
337 $ hg debugwalk beans/../.hg
338 abort: path contains illegal component: .hg
338 abort: path contains illegal component: .hg
339 [255]
339 [255]
340 $ hg debugwalk beans/../.hg/data
340 $ hg debugwalk beans/../.hg/data
341 abort: path contains illegal component: .hg/data (glob)
341 abort: path contains illegal component: .hg/data (glob)
342 [255]
342 [255]
343 $ hg debugwalk beans/.hg
343 $ hg debugwalk beans/.hg
344 abort: path 'beans/.hg' is inside nested repo 'beans' (glob)
344 abort: path 'beans/.hg' is inside nested repo 'beans' (glob)
345 [255]
345 [255]
346
346
347 Test absolute paths:
347 Test absolute paths:
348
348
349 $ hg debugwalk `pwd`/beans
349 $ hg debugwalk `pwd`/beans
350 matcher: <patternmatcher patterns='(?:beans(?:/|$))', includes=None>
350 matcher: <patternmatcher patterns='(?:beans(?:/|$))'>
351 f beans/black beans/black
351 f beans/black 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 `pwd`/..
357 $ hg debugwalk `pwd`/..
358 abort: $TESTTMP/t/.. not under root '$TESTTMP/t' (glob)
358 abort: $TESTTMP/t/.. not under root '$TESTTMP/t' (glob)
359 [255]
359 [255]
360
360
361 Test patterns:
361 Test patterns:
362
362
363 $ hg debugwalk glob:\*
363 $ hg debugwalk glob:\*
364 matcher: <patternmatcher patterns='(?:[^/]*$)', includes=None>
364 matcher: <patternmatcher patterns='(?:[^/]*$)'>
365 f fennel fennel
365 f fennel fennel
366 f fenugreek fenugreek
366 f fenugreek fenugreek
367 f fiddlehead fiddlehead
367 f fiddlehead fiddlehead
368 #if eol-in-paths
368 #if eol-in-paths
369 $ echo glob:glob > glob:glob
369 $ echo glob:glob > glob:glob
370 $ hg addremove
370 $ hg addremove
371 adding glob:glob
371 adding glob:glob
372 warning: filename contains ':', which is reserved on Windows: 'glob:glob'
372 warning: filename contains ':', which is reserved on Windows: 'glob:glob'
373 $ hg debugwalk glob:\*
373 $ hg debugwalk glob:\*
374 matcher: <patternmatcher patterns='(?:[^/]*$)', includes=None>
374 matcher: <patternmatcher patterns='(?:[^/]*$)'>
375 f fennel fennel
375 f fennel fennel
376 f fenugreek fenugreek
376 f fenugreek fenugreek
377 f fiddlehead fiddlehead
377 f fiddlehead fiddlehead
378 f glob:glob glob:glob
378 f glob:glob glob:glob
379 $ hg debugwalk glob:glob
379 $ hg debugwalk glob:glob
380 matcher: <patternmatcher patterns='(?:glob$)', includes=None>
380 matcher: <patternmatcher patterns='(?:glob$)'>
381 glob: No such file or directory
381 glob: No such file or directory
382 $ hg debugwalk glob:glob:glob
382 $ hg debugwalk glob:glob:glob
383 matcher: <patternmatcher patterns='(?:glob\\:glob$)', includes=None>
383 matcher: <patternmatcher patterns='(?:glob\\:glob$)'>
384 f glob:glob glob:glob exact
384 f glob:glob glob:glob exact
385 $ hg debugwalk path:glob:glob
385 $ hg debugwalk path:glob:glob
386 matcher: <patternmatcher patterns='(?:^glob\\:glob(?:/|$))', includes=None>
386 matcher: <patternmatcher patterns='(?:^glob\\:glob(?:/|$))'>
387 f glob:glob glob:glob exact
387 f glob:glob glob:glob exact
388 $ rm glob:glob
388 $ rm glob:glob
389 $ hg addremove
389 $ hg addremove
390 removing glob:glob
390 removing glob:glob
391 #endif
391 #endif
392
392
393 $ hg debugwalk 'glob:**e'
393 $ hg debugwalk 'glob:**e'
394 matcher: <patternmatcher patterns='(?:.*e$)', includes=None>
394 matcher: <patternmatcher patterns='(?:.*e$)'>
395 f beans/turtle beans/turtle
395 f beans/turtle beans/turtle
396 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
396 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
397
397
398 $ hg debugwalk 're:.*[kb]$'
398 $ hg debugwalk 're:.*[kb]$'
399 matcher: <patternmatcher patterns='(?:.*[kb]$)', includes=None>
399 matcher: <patternmatcher patterns='(?:.*[kb]$)'>
400 f beans/black beans/black
400 f beans/black beans/black
401 f fenugreek fenugreek
401 f fenugreek fenugreek
402 f mammals/skunk mammals/skunk
402 f mammals/skunk mammals/skunk
403
403
404 $ hg debugwalk path:beans/black
404 $ hg debugwalk path:beans/black
405 matcher: <patternmatcher patterns='(?:^beans\\/black(?:/|$))', includes=None>
405 matcher: <patternmatcher patterns='(?:^beans\\/black(?:/|$))'>
406 f beans/black beans/black exact
406 f beans/black beans/black exact
407 $ hg debugwalk path:beans//black
407 $ hg debugwalk path:beans//black
408 matcher: <patternmatcher patterns='(?:^beans\\/black(?:/|$))', includes=None>
408 matcher: <patternmatcher patterns='(?:^beans\\/black(?:/|$))'>
409 f beans/black beans/black exact
409 f beans/black beans/black exact
410
410
411 $ hg debugwalk relglob:Procyonidae
411 $ hg debugwalk relglob:Procyonidae
412 matcher: <patternmatcher patterns='(?:(?:|.*/)Procyonidae$)', includes=None>
412 matcher: <patternmatcher patterns='(?:(?:|.*/)Procyonidae$)'>
413 $ hg debugwalk 'relglob:Procyonidae/**'
413 $ hg debugwalk 'relglob:Procyonidae/**'
414 matcher: <patternmatcher patterns='(?:(?:|.*/)Procyonidae\\/.*$)', includes=None>
414 matcher: <patternmatcher patterns='(?:(?:|.*/)Procyonidae\\/.*$)'>
415 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
415 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
416 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
416 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
417 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
417 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
418 $ hg debugwalk 'relglob:Procyonidae/**' fennel
418 $ hg debugwalk 'relglob:Procyonidae/**' fennel
419 matcher: <patternmatcher patterns='(?:(?:|.*/)Procyonidae\\/.*$|fennel(?:/|$))', includes=None>
419 matcher: <patternmatcher patterns='(?:(?:|.*/)Procyonidae\\/.*$|fennel(?:/|$))'>
420 f fennel fennel exact
420 f fennel fennel exact
421 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
421 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
422 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
422 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
423 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
423 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
424 $ hg debugwalk beans 'glob:beans/*'
424 $ hg debugwalk beans 'glob:beans/*'
425 matcher: <patternmatcher patterns='(?:beans(?:/|$)|beans\\/[^/]*$)', includes=None>
425 matcher: <patternmatcher patterns='(?:beans(?:/|$)|beans\\/[^/]*$)'>
426 f beans/black beans/black
426 f beans/black beans/black
427 f beans/borlotti beans/borlotti
427 f beans/borlotti beans/borlotti
428 f beans/kidney beans/kidney
428 f beans/kidney beans/kidney
429 f beans/navy beans/navy
429 f beans/navy beans/navy
430 f beans/pinto beans/pinto
430 f beans/pinto beans/pinto
431 f beans/turtle beans/turtle
431 f beans/turtle beans/turtle
432 $ hg debugwalk 'glob:mamm**'
432 $ hg debugwalk 'glob:mamm**'
433 matcher: <patternmatcher patterns='(?:mamm.*$)', includes=None>
433 matcher: <patternmatcher patterns='(?:mamm.*$)'>
434 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
434 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
435 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
435 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
436 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
436 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
437 f mammals/skunk mammals/skunk
437 f mammals/skunk mammals/skunk
438 $ hg debugwalk 'glob:mamm**' fennel
438 $ hg debugwalk 'glob:mamm**' fennel
439 matcher: <patternmatcher patterns='(?:mamm.*$|fennel(?:/|$))', includes=None>
439 matcher: <patternmatcher patterns='(?:mamm.*$|fennel(?:/|$))'>
440 f fennel fennel exact
440 f fennel fennel exact
441 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
441 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
442 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
442 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
443 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
443 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
444 f mammals/skunk mammals/skunk
444 f mammals/skunk mammals/skunk
445 $ hg debugwalk 'glob:j*'
445 $ hg debugwalk 'glob:j*'
446 matcher: <patternmatcher patterns='(?:j[^/]*$)', includes=None>
446 matcher: <patternmatcher patterns='(?:j[^/]*$)'>
447 $ hg debugwalk NOEXIST
447 $ hg debugwalk NOEXIST
448 matcher: <patternmatcher patterns='(?:NOEXIST(?:/|$))', includes=None>
448 matcher: <patternmatcher patterns='(?:NOEXIST(?:/|$))'>
449 NOEXIST: * (glob)
449 NOEXIST: * (glob)
450
450
451 #if fifo
451 #if fifo
452 $ mkfifo fifo
452 $ mkfifo fifo
453 $ hg debugwalk fifo
453 $ hg debugwalk fifo
454 matcher: <patternmatcher patterns='(?:fifo(?:/|$))', includes=None>
454 matcher: <patternmatcher patterns='(?:fifo(?:/|$))'>
455 fifo: unsupported file type (type is fifo)
455 fifo: unsupported file type (type is fifo)
456 #endif
456 #endif
457
457
458 $ rm fenugreek
458 $ rm fenugreek
459 $ hg debugwalk fenugreek
459 $ hg debugwalk fenugreek
460 matcher: <patternmatcher patterns='(?:fenugreek(?:/|$))', includes=None>
460 matcher: <patternmatcher patterns='(?:fenugreek(?:/|$))'>
461 f fenugreek fenugreek exact
461 f fenugreek fenugreek exact
462 $ hg rm fenugreek
462 $ hg rm fenugreek
463 $ hg debugwalk fenugreek
463 $ hg debugwalk fenugreek
464 matcher: <patternmatcher patterns='(?:fenugreek(?:/|$))', includes=None>
464 matcher: <patternmatcher patterns='(?:fenugreek(?:/|$))'>
465 f fenugreek fenugreek exact
465 f fenugreek fenugreek exact
466 $ touch new
466 $ touch new
467 $ hg debugwalk new
467 $ hg debugwalk new
468 matcher: <patternmatcher patterns='(?:new(?:/|$))', includes=None>
468 matcher: <patternmatcher patterns='(?:new(?:/|$))'>
469 f new new exact
469 f new new exact
470
470
471 $ mkdir ignored
471 $ mkdir ignored
472 $ touch ignored/file
472 $ touch ignored/file
473 $ echo '^ignored$' > .hgignore
473 $ echo '^ignored$' > .hgignore
474 $ hg debugwalk ignored
474 $ hg debugwalk ignored
475 matcher: <patternmatcher patterns='(?:ignored(?:/|$))', includes=None>
475 matcher: <patternmatcher patterns='(?:ignored(?:/|$))'>
476 $ hg debugwalk ignored/file
476 $ hg debugwalk ignored/file
477 matcher: <patternmatcher patterns='(?:ignored\\/file(?:/|$))', includes=None>
477 matcher: <patternmatcher patterns='(?:ignored\\/file(?:/|$))'>
478 f ignored/file ignored/file exact
478 f ignored/file ignored/file exact
479
479
480 Test listfile and listfile0
480 Test listfile and listfile0
481
481
482 $ $PYTHON -c "file('listfile0', 'wb').write('fenugreek\0new\0')"
482 $ $PYTHON -c "file('listfile0', 'wb').write('fenugreek\0new\0')"
483 $ hg debugwalk -I 'listfile0:listfile0'
483 $ hg debugwalk -I 'listfile0:listfile0'
484 matcher: <includematcher includes='(?:fenugreek(?:/|$)|new(?:/|$))'>
484 matcher: <includematcher includes='(?:fenugreek(?:/|$)|new(?:/|$))'>
485 f fenugreek fenugreek
485 f fenugreek fenugreek
486 f new new
486 f new new
487 $ $PYTHON -c "file('listfile', 'wb').write('fenugreek\nnew\r\nmammals/skunk\n')"
487 $ $PYTHON -c "file('listfile', 'wb').write('fenugreek\nnew\r\nmammals/skunk\n')"
488 $ hg debugwalk -I 'listfile:listfile'
488 $ hg debugwalk -I 'listfile:listfile'
489 matcher: <includematcher includes='(?:fenugreek(?:/|$)|new(?:/|$)|mammals\\/skunk(?:/|$))'>
489 matcher: <includematcher includes='(?:fenugreek(?:/|$)|new(?:/|$)|mammals\\/skunk(?:/|$))'>
490 f fenugreek fenugreek
490 f fenugreek fenugreek
491 f mammals/skunk mammals/skunk
491 f mammals/skunk mammals/skunk
492 f new new
492 f new new
493
493
494 $ cd ..
494 $ cd ..
495 $ hg debugwalk -R t t/mammals/skunk
495 $ hg debugwalk -R t t/mammals/skunk
496 matcher: <patternmatcher patterns='(?:mammals\\/skunk(?:/|$))', includes=None>
496 matcher: <patternmatcher patterns='(?:mammals\\/skunk(?:/|$))'>
497 f mammals/skunk t/mammals/skunk exact
497 f mammals/skunk t/mammals/skunk exact
498 $ mkdir t2
498 $ mkdir t2
499 $ cd t2
499 $ cd t2
500 $ hg debugwalk -R ../t ../t/mammals/skunk
500 $ hg debugwalk -R ../t ../t/mammals/skunk
501 matcher: <patternmatcher patterns='(?:mammals\\/skunk(?:/|$))', includes=None>
501 matcher: <patternmatcher patterns='(?:mammals\\/skunk(?:/|$))'>
502 f mammals/skunk ../t/mammals/skunk exact
502 f mammals/skunk ../t/mammals/skunk exact
503 $ hg debugwalk --cwd ../t mammals/skunk
503 $ hg debugwalk --cwd ../t mammals/skunk
504 matcher: <patternmatcher patterns='(?:mammals\\/skunk(?:/|$))', includes=None>
504 matcher: <patternmatcher patterns='(?:mammals\\/skunk(?:/|$))'>
505 f mammals/skunk mammals/skunk exact
505 f mammals/skunk mammals/skunk exact
506
506
507 $ cd ..
507 $ cd ..
508
508
509 Test split patterns on overflow
509 Test split patterns on overflow
510
510
511 $ cd t
511 $ cd t
512 $ echo fennel > overflow.list
512 $ echo fennel > overflow.list
513 $ $PYTHON -c "for i in xrange(20000 / 100): print 'x' * 100" >> overflow.list
513 $ $PYTHON -c "for i in xrange(20000 / 100): print 'x' * 100" >> overflow.list
514 $ echo fenugreek >> overflow.list
514 $ echo fenugreek >> overflow.list
515 $ hg debugwalk 'listfile:overflow.list' 2>&1 | egrep -v '(^matcher: |^xxx)'
515 $ hg debugwalk 'listfile:overflow.list' 2>&1 | egrep -v '(^matcher: |^xxx)'
516 f fennel fennel exact
516 f fennel fennel exact
517 f fenugreek fenugreek exact
517 f fenugreek fenugreek exact
518 $ cd ..
518 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now