##// END OF EJS Templates
match: handle excludes using new differencematcher...
Martin von Zweigbergk -
r32465:a83a7d27 default
parent child Browse files
Show More
@@ -1,836 +1,897 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 return matcher(root, cwd, normalize, patterns, include=include,
145 m = matcher(root, cwd, normalize, patterns, include=include, exclude=None,
146 exclude=exclude, default=default, exact=exact,
146 default=default, exact=exact, auditor=auditor, ctx=ctx,
147 auditor=auditor, ctx=ctx, listsubrepos=listsubrepos,
147 listsubrepos=listsubrepos, warn=warn, badfn=badfn)
148 warn=warn, badfn=badfn)
148 if exclude:
149 em = matcher(root, cwd, normalize, [], include=exclude, exclude=None,
150 default=default, exact=False, auditor=auditor, ctx=ctx,
151 listsubrepos=listsubrepos, warn=warn, badfn=None)
152 m = differencematcher(m, em)
153 return m
149
154
150 def exact(root, cwd, files, badfn=None):
155 def exact(root, cwd, files, badfn=None):
151 return match(root, cwd, files, exact=True, badfn=badfn)
156 return match(root, cwd, files, exact=True, badfn=badfn)
152
157
153 def always(root, cwd):
158 def always(root, cwd):
154 return match(root, cwd, [])
159 return match(root, cwd, [])
155
160
156 def badmatch(match, badfn):
161 def badmatch(match, badfn):
157 """Make a copy of the given matcher, replacing its bad method with the given
162 """Make a copy of the given matcher, replacing its bad method with the given
158 one.
163 one.
159 """
164 """
160 m = copy.copy(match)
165 m = copy.copy(match)
161 m.bad = badfn
166 m.bad = badfn
162 return m
167 return m
163
168
164 def _donormalize(patterns, default, root, cwd, auditor, warn):
169 def _donormalize(patterns, default, root, cwd, auditor, warn):
165 '''Convert 'kind:pat' from the patterns list to tuples with kind and
170 '''Convert 'kind:pat' from the patterns list to tuples with kind and
166 normalized and rooted patterns and with listfiles expanded.'''
171 normalized and rooted patterns and with listfiles expanded.'''
167 kindpats = []
172 kindpats = []
168 for kind, pat in [_patsplit(p, default) for p in patterns]:
173 for kind, pat in [_patsplit(p, default) for p in patterns]:
169 if kind in ('glob', 'relpath'):
174 if kind in ('glob', 'relpath'):
170 pat = pathutil.canonpath(root, cwd, pat, auditor)
175 pat = pathutil.canonpath(root, cwd, pat, auditor)
171 elif kind in ('relglob', 'path', 'rootfilesin'):
176 elif kind in ('relglob', 'path', 'rootfilesin'):
172 pat = util.normpath(pat)
177 pat = util.normpath(pat)
173 elif kind in ('listfile', 'listfile0'):
178 elif kind in ('listfile', 'listfile0'):
174 try:
179 try:
175 files = util.readfile(pat)
180 files = util.readfile(pat)
176 if kind == 'listfile0':
181 if kind == 'listfile0':
177 files = files.split('\0')
182 files = files.split('\0')
178 else:
183 else:
179 files = files.splitlines()
184 files = files.splitlines()
180 files = [f for f in files if f]
185 files = [f for f in files if f]
181 except EnvironmentError:
186 except EnvironmentError:
182 raise error.Abort(_("unable to read file list (%s)") % pat)
187 raise error.Abort(_("unable to read file list (%s)") % pat)
183 for k, p, source in _donormalize(files, default, root, cwd,
188 for k, p, source in _donormalize(files, default, root, cwd,
184 auditor, warn):
189 auditor, warn):
185 kindpats.append((k, p, pat))
190 kindpats.append((k, p, pat))
186 continue
191 continue
187 elif kind == 'include':
192 elif kind == 'include':
188 try:
193 try:
189 fullpath = os.path.join(root, util.localpath(pat))
194 fullpath = os.path.join(root, util.localpath(pat))
190 includepats = readpatternfile(fullpath, warn)
195 includepats = readpatternfile(fullpath, warn)
191 for k, p, source in _donormalize(includepats, default,
196 for k, p, source in _donormalize(includepats, default,
192 root, cwd, auditor, warn):
197 root, cwd, auditor, warn):
193 kindpats.append((k, p, source or pat))
198 kindpats.append((k, p, source or pat))
194 except error.Abort as inst:
199 except error.Abort as inst:
195 raise error.Abort('%s: %s' % (pat, inst[0]))
200 raise error.Abort('%s: %s' % (pat, inst[0]))
196 except IOError as inst:
201 except IOError as inst:
197 if warn:
202 if warn:
198 warn(_("skipping unreadable pattern file '%s': %s\n") %
203 warn(_("skipping unreadable pattern file '%s': %s\n") %
199 (pat, inst.strerror))
204 (pat, inst.strerror))
200 continue
205 continue
201 # else: re or relre - which cannot be normalized
206 # else: re or relre - which cannot be normalized
202 kindpats.append((kind, pat, ''))
207 kindpats.append((kind, pat, ''))
203 return kindpats
208 return kindpats
204
209
205 class basematcher(object):
210 class basematcher(object):
206
211
207 def __init__(self, root, cwd, badfn=None):
212 def __init__(self, root, cwd, badfn=None):
208 self._root = root
213 self._root = root
209 self._cwd = cwd
214 self._cwd = cwd
210 if badfn is not None:
215 if badfn is not None:
211 self.bad = badfn
216 self.bad = badfn
212
217
213 def __call__(self, fn):
218 def __call__(self, fn):
214 return self.matchfn(fn)
219 return self.matchfn(fn)
215 def __iter__(self):
220 def __iter__(self):
216 for f in self._files:
221 for f in self._files:
217 yield f
222 yield f
218 # Callbacks related to how the matcher is used by dirstate.walk.
223 # Callbacks related to how the matcher is used by dirstate.walk.
219 # Subscribers to these events must monkeypatch the matcher object.
224 # Subscribers to these events must monkeypatch the matcher object.
220 def bad(self, f, msg):
225 def bad(self, f, msg):
221 '''Callback from dirstate.walk for each explicit file that can't be
226 '''Callback from dirstate.walk for each explicit file that can't be
222 found/accessed, with an error message.'''
227 found/accessed, with an error message.'''
223 pass
228 pass
224
229
225 # If an explicitdir is set, it will be called when an explicitly listed
230 # If an explicitdir is set, it will be called when an explicitly listed
226 # directory is visited.
231 # directory is visited.
227 explicitdir = None
232 explicitdir = None
228
233
229 # If an traversedir is set, it will be called when a directory discovered
234 # If an traversedir is set, it will be called when a directory discovered
230 # by recursive traversal is visited.
235 # by recursive traversal is visited.
231 traversedir = None
236 traversedir = None
232
237
233 def abs(self, f):
238 def abs(self, f):
234 '''Convert a repo path back to path that is relative to the root of the
239 '''Convert a repo path back to path that is relative to the root of the
235 matcher.'''
240 matcher.'''
236 return f
241 return f
237
242
238 def rel(self, f):
243 def rel(self, f):
239 '''Convert repo path back to path that is relative to cwd of matcher.'''
244 '''Convert repo path back to path that is relative to cwd of matcher.'''
240 return util.pathto(self._root, self._cwd, f)
245 return util.pathto(self._root, self._cwd, f)
241
246
242 def uipath(self, f):
247 def uipath(self, f):
243 '''Convert repo path to a display path. If patterns or -I/-X were used
248 '''Convert repo path to a display path. If patterns or -I/-X were used
244 to create this matcher, the display path will be relative to cwd.
249 to create this matcher, the display path will be relative to cwd.
245 Otherwise it is relative to the root of the repo.'''
250 Otherwise it is relative to the root of the repo.'''
246 return self.rel(f)
251 return self.rel(f)
247
252
248 @propertycache
253 @propertycache
249 def _files(self):
254 def _files(self):
250 return []
255 return []
251
256
252 def files(self):
257 def files(self):
253 '''Explicitly listed files or patterns or roots:
258 '''Explicitly listed files or patterns or roots:
254 if no patterns or .always(): empty list,
259 if no patterns or .always(): empty list,
255 if exact: list exact files,
260 if exact: list exact files,
256 if not .anypats(): list all files and dirs,
261 if not .anypats(): list all files and dirs,
257 else: optimal roots'''
262 else: optimal roots'''
258 return self._files
263 return self._files
259
264
260 @propertycache
265 @propertycache
261 def _fileset(self):
266 def _fileset(self):
262 return set(self._files)
267 return set(self._files)
263
268
264 def exact(self, f):
269 def exact(self, f):
265 '''Returns True if f is in .files().'''
270 '''Returns True if f is in .files().'''
266 return f in self._fileset
271 return f in self._fileset
267
272
268 def matchfn(self, f):
273 def matchfn(self, f):
269 return False
274 return False
270
275
271 def visitdir(self, dir):
276 def visitdir(self, dir):
272 '''Decides whether a directory should be visited based on whether it
277 '''Decides whether a directory should be visited based on whether it
273 has potential matches in it or one of its subdirectories. This is
278 has potential matches in it or one of its subdirectories. This is
274 based on the match's primary, included, and excluded patterns.
279 based on the match's primary, included, and excluded patterns.
275
280
276 Returns the string 'all' if the given directory and all subdirectories
281 Returns the string 'all' if the given directory and all subdirectories
277 should be visited. Otherwise returns True or False indicating whether
282 should be visited. Otherwise returns True or False indicating whether
278 the given directory should be visited.
283 the given directory should be visited.
279
284
280 This function's behavior is undefined if it has returned False for
285 This function's behavior is undefined if it has returned False for
281 one of the dir's parent directories.
286 one of the dir's parent directories.
282 '''
287 '''
283 return False
288 return False
284
289
285 def anypats(self):
290 def anypats(self):
286 '''Matcher uses patterns or include/exclude.'''
291 '''Matcher uses patterns or include/exclude.'''
287 return False
292 return False
288
293
289 def always(self):
294 def always(self):
290 '''Matcher will match everything and .files() will be empty
295 '''Matcher will match everything and .files() will be empty
291 - optimization might be possible and necessary.'''
296 - optimization might be possible and necessary.'''
292 return False
297 return False
293
298
294 def isexact(self):
299 def isexact(self):
295 return False
300 return False
296
301
297 def prefix(self):
302 def prefix(self):
298 return not self.always() and not self.isexact() and not self.anypats()
303 return not self.always() and not self.isexact() and not self.anypats()
299
304
300 class matcher(basematcher):
305 class matcher(basematcher):
301
306
302 def __init__(self, root, cwd, normalize, patterns, include=None,
307 def __init__(self, root, cwd, normalize, patterns, include=None,
303 exclude=None, default='glob', exact=False, auditor=None,
308 exclude=None, default='glob', exact=False, auditor=None,
304 ctx=None, listsubrepos=False, warn=None, badfn=None):
309 ctx=None, listsubrepos=False, warn=None, badfn=None):
305 super(matcher, self).__init__(root, cwd, badfn)
310 super(matcher, self).__init__(root, cwd, badfn)
306 if include is None:
311 if include is None:
307 include = []
312 include = []
308 if exclude is None:
313 if exclude is None:
309 exclude = []
314 exclude = []
310
315
311 self._anypats = bool(include or exclude)
316 self._anypats = bool(include or exclude)
312 self._anyincludepats = False
317 self._anyincludepats = False
313 self._always = False
318 self._always = False
314 self._pathrestricted = bool(include or exclude or patterns)
319 self._pathrestricted = bool(include or exclude or patterns)
315 self.patternspat = None
320 self.patternspat = None
316 self.includepat = None
321 self.includepat = None
317 self.excludepat = None
322 self.excludepat = None
318
323
319 # roots are directories which are recursively included/excluded.
324 # roots are directories which are recursively included/excluded.
320 self._includeroots = set()
325 self._includeroots = set()
321 self._excluderoots = set()
326 self._excluderoots = set()
322 # dirs are directories which are non-recursively included.
327 # dirs are directories which are non-recursively included.
323 self._includedirs = set()
328 self._includedirs = set()
324
329
325 matchfns = []
330 matchfns = []
326 if include:
331 if include:
327 kindpats = normalize(include, 'glob', root, cwd, auditor, warn)
332 kindpats = normalize(include, 'glob', root, cwd, auditor, warn)
328 self.includepat, im = _buildmatch(ctx, kindpats, '(?:/|$)',
333 self.includepat, im = _buildmatch(ctx, kindpats, '(?:/|$)',
329 listsubrepos, root)
334 listsubrepos, root)
330 self._anyincludepats = _anypats(kindpats)
335 self._anyincludepats = _anypats(kindpats)
331 roots, dirs = _rootsanddirs(kindpats)
336 roots, dirs = _rootsanddirs(kindpats)
332 self._includeroots.update(roots)
337 self._includeroots.update(roots)
333 self._includedirs.update(dirs)
338 self._includedirs.update(dirs)
334 matchfns.append(im)
339 matchfns.append(im)
335 if exclude:
340 if exclude:
336 kindpats = normalize(exclude, 'glob', root, cwd, auditor, warn)
341 kindpats = normalize(exclude, 'glob', root, cwd, auditor, warn)
337 self.excludepat, em = _buildmatch(ctx, kindpats, '(?:/|$)',
342 self.excludepat, em = _buildmatch(ctx, kindpats, '(?:/|$)',
338 listsubrepos, root)
343 listsubrepos, root)
339 if not _anypats(kindpats):
344 if not _anypats(kindpats):
340 # Only consider recursive excludes as such - if a non-recursive
345 # Only consider recursive excludes as such - if a non-recursive
341 # exclude is used, we must still recurse into the excluded
346 # exclude is used, we must still recurse into the excluded
342 # directory, at least to find subdirectories. In such a case,
347 # directory, at least to find subdirectories. In such a case,
343 # the regex still won't match the non-recursively-excluded
348 # the regex still won't match the non-recursively-excluded
344 # files.
349 # files.
345 self._excluderoots.update(_roots(kindpats))
350 self._excluderoots.update(_roots(kindpats))
346 matchfns.append(lambda f: not em(f))
351 matchfns.append(lambda f: not em(f))
347 if exact:
352 if exact:
348 if isinstance(patterns, list):
353 if isinstance(patterns, list):
349 self._files = patterns
354 self._files = patterns
350 else:
355 else:
351 self._files = list(patterns)
356 self._files = list(patterns)
352 matchfns.append(self.exact)
357 matchfns.append(self.exact)
353 elif patterns:
358 elif patterns:
354 kindpats = normalize(patterns, default, root, cwd, auditor, warn)
359 kindpats = normalize(patterns, default, root, cwd, auditor, warn)
355 if not _kindpatsalwaysmatch(kindpats):
360 if not _kindpatsalwaysmatch(kindpats):
356 self._files = _explicitfiles(kindpats)
361 self._files = _explicitfiles(kindpats)
357 self._anypats = self._anypats or _anypats(kindpats)
362 self._anypats = self._anypats or _anypats(kindpats)
358 self.patternspat, pm = _buildmatch(ctx, kindpats, '$',
363 self.patternspat, pm = _buildmatch(ctx, kindpats, '$',
359 listsubrepos, root)
364 listsubrepos, root)
360 matchfns.append(pm)
365 matchfns.append(pm)
361
366
362 if not matchfns:
367 if not matchfns:
363 m = util.always
368 m = util.always
364 self._always = True
369 self._always = True
365 elif len(matchfns) == 1:
370 elif len(matchfns) == 1:
366 m = matchfns[0]
371 m = matchfns[0]
367 else:
372 else:
368 def m(f):
373 def m(f):
369 for matchfn in matchfns:
374 for matchfn in matchfns:
370 if not matchfn(f):
375 if not matchfn(f):
371 return False
376 return False
372 return True
377 return True
373
378
374 self.matchfn = m
379 self.matchfn = m
375
380
376 def uipath(self, f):
381 def uipath(self, f):
377 return (self._pathrestricted and self.rel(f)) or self.abs(f)
382 return (self._pathrestricted and self.rel(f)) or self.abs(f)
378
383
379 @propertycache
384 @propertycache
380 def _dirs(self):
385 def _dirs(self):
381 return set(util.dirs(self._fileset)) | {'.'}
386 return set(util.dirs(self._fileset)) | {'.'}
382
387
383 def visitdir(self, dir):
388 def visitdir(self, dir):
384 if self.prefix() and dir in self._fileset:
389 if self.prefix() and dir in self._fileset:
385 return 'all'
390 return 'all'
386 if dir in self._excluderoots:
391 if dir in self._excluderoots:
387 return False
392 return False
388 if self._includeroots or self._includedirs:
393 if self._includeroots or self._includedirs:
389 if (not self._anyincludepats and
394 if (not self._anyincludepats and
390 not self._excluderoots and
395 not self._excluderoots and
391 dir in self._includeroots):
396 dir in self._includeroots):
392 # The condition above is essentially self.prefix() for includes
397 # The condition above is essentially self.prefix() for includes
393 return 'all'
398 return 'all'
394 if ('.' not in self._includeroots and
399 if ('.' not in self._includeroots and
395 dir not in self._includeroots and
400 dir not in self._includeroots and
396 dir not in self._includedirs and
401 dir not in self._includedirs and
397 not any(parent in self._includeroots
402 not any(parent in self._includeroots
398 for parent in util.finddirs(dir))):
403 for parent in util.finddirs(dir))):
399 return False
404 return False
400 return (not self._fileset or
405 return (not self._fileset or
401 '.' in self._fileset or
406 '.' in self._fileset or
402 dir in self._fileset or
407 dir in self._fileset or
403 dir in self._dirs or
408 dir in self._dirs or
404 any(parentdir in self._fileset
409 any(parentdir in self._fileset
405 for parentdir in util.finddirs(dir)))
410 for parentdir in util.finddirs(dir)))
406
411
407 def anypats(self):
412 def anypats(self):
408 return self._anypats
413 return self._anypats
409
414
410 def always(self):
415 def always(self):
411 return self._always
416 return self._always
412
417
413 def isexact(self):
418 def isexact(self):
414 return self.matchfn == self.exact
419 return self.matchfn == self.exact
415
420
416 def __repr__(self):
421 def __repr__(self):
417 return ('<matcher files=%r, patterns=%r, includes=%r, excludes=%r>' %
422 return ('<matcher files=%r, patterns=%r, includes=%r, excludes=%r>' %
418 (self._files, self.patternspat, self.includepat,
423 (self._files, self.patternspat, self.includepat,
419 self.excludepat))
424 self.excludepat))
420
425
426 class differencematcher(basematcher):
427 '''Composes two matchers by matching if the first matches and the second
428 does not. Well, almost... If the user provides a pattern like "-X foo foo",
429 Mercurial actually does match "foo" against that. That's because exact
430 matches are treated specially. So, since this differencematcher is used for
431 excludes, it needs to special-case exact matching.
432
433 The second matcher's non-matching-attributes (root, cwd, bad, explicitdir,
434 traversedir) are ignored.
435
436 TODO: If we want to keep the behavior described above for exact matches, we
437 should consider instead treating the above case something like this:
438 union(exact(foo), difference(pattern(foo), include(foo)))
439 '''
440 def __init__(self, m1, m2):
441 super(differencematcher, self).__init__(m1._root, m1._cwd)
442 self._m1 = m1
443 self._m2 = m2
444 self.bad = m1.bad
445 self.explicitdir = m1.explicitdir
446 self.traversedir = m1.traversedir
447
448 def matchfn(self, f):
449 return self._m1(f) and (not self._m2(f) or self._m1.exact(f))
450
451 @propertycache
452 def _files(self):
453 if self.isexact():
454 return [f for f in self._m1.files() if self(f)]
455 # If m1 is not an exact matcher, we can't easily figure out the set of
456 # files, because its files() are not always files. For example, if
457 # m1 is "path:dir" and m2 is "rootfileins:.", we don't
458 # want to remove "dir" from the set even though it would match m2,
459 # because the "dir" in m1 may not be a file.
460 return self._m1.files()
461
462 def visitdir(self, dir):
463 if self._m2.visitdir(dir) == 'all':
464 # There's a bug here: If m1 matches file 'dir/file' and m2 excludes
465 # 'dir' (recursively), we should still visit 'dir' due to the
466 # exception we have for exact matches.
467 return False
468 return bool(self._m1.visitdir(dir))
469
470 def isexact(self):
471 return self._m1.isexact()
472
473 def anypats(self):
474 return self._m1.anypats() or self._m2.anypats()
475
476 def prefix(self):
477 return not self.always() and not self.isexact() and not self.anypats()
478
479 def __repr__(self):
480 return ('<differencematcher m1=%r, m2=%r>' % (self._m1, self._m2))
481
421 class subdirmatcher(basematcher):
482 class subdirmatcher(basematcher):
422 """Adapt a matcher to work on a subdirectory only.
483 """Adapt a matcher to work on a subdirectory only.
423
484
424 The paths are remapped to remove/insert the path as needed:
485 The paths are remapped to remove/insert the path as needed:
425
486
426 >>> m1 = match('root', '', ['a.txt', 'sub/b.txt'])
487 >>> m1 = match('root', '', ['a.txt', 'sub/b.txt'])
427 >>> m2 = subdirmatcher('sub', m1)
488 >>> m2 = subdirmatcher('sub', m1)
428 >>> bool(m2('a.txt'))
489 >>> bool(m2('a.txt'))
429 False
490 False
430 >>> bool(m2('b.txt'))
491 >>> bool(m2('b.txt'))
431 True
492 True
432 >>> bool(m2.matchfn('a.txt'))
493 >>> bool(m2.matchfn('a.txt'))
433 False
494 False
434 >>> bool(m2.matchfn('b.txt'))
495 >>> bool(m2.matchfn('b.txt'))
435 True
496 True
436 >>> m2.files()
497 >>> m2.files()
437 ['b.txt']
498 ['b.txt']
438 >>> m2.exact('b.txt')
499 >>> m2.exact('b.txt')
439 True
500 True
440 >>> util.pconvert(m2.rel('b.txt'))
501 >>> util.pconvert(m2.rel('b.txt'))
441 'sub/b.txt'
502 'sub/b.txt'
442 >>> def bad(f, msg):
503 >>> def bad(f, msg):
443 ... print "%s: %s" % (f, msg)
504 ... print "%s: %s" % (f, msg)
444 >>> m1.bad = bad
505 >>> m1.bad = bad
445 >>> m2.bad('x.txt', 'No such file')
506 >>> m2.bad('x.txt', 'No such file')
446 sub/x.txt: No such file
507 sub/x.txt: No such file
447 >>> m2.abs('c.txt')
508 >>> m2.abs('c.txt')
448 'sub/c.txt'
509 'sub/c.txt'
449 """
510 """
450
511
451 def __init__(self, path, matcher):
512 def __init__(self, path, matcher):
452 super(subdirmatcher, self).__init__(matcher._root, matcher._cwd)
513 super(subdirmatcher, self).__init__(matcher._root, matcher._cwd)
453 self._path = path
514 self._path = path
454 self._matcher = matcher
515 self._matcher = matcher
455 self._always = matcher.always()
516 self._always = matcher.always()
456
517
457 self._files = [f[len(path) + 1:] for f in matcher._files
518 self._files = [f[len(path) + 1:] for f in matcher._files
458 if f.startswith(path + "/")]
519 if f.startswith(path + "/")]
459
520
460 # If the parent repo had a path to this subrepo and the matcher is
521 # If the parent repo had a path to this subrepo and the matcher is
461 # a prefix matcher, this submatcher always matches.
522 # a prefix matcher, this submatcher always matches.
462 if matcher.prefix():
523 if matcher.prefix():
463 self._always = any(f == path for f in matcher._files)
524 self._always = any(f == path for f in matcher._files)
464
525
465 def bad(self, f, msg):
526 def bad(self, f, msg):
466 self._matcher.bad(self._path + "/" + f, msg)
527 self._matcher.bad(self._path + "/" + f, msg)
467
528
468 def abs(self, f):
529 def abs(self, f):
469 return self._matcher.abs(self._path + "/" + f)
530 return self._matcher.abs(self._path + "/" + f)
470
531
471 def rel(self, f):
532 def rel(self, f):
472 return self._matcher.rel(self._path + "/" + f)
533 return self._matcher.rel(self._path + "/" + f)
473
534
474 def uipath(self, f):
535 def uipath(self, f):
475 return self._matcher.uipath(self._path + "/" + f)
536 return self._matcher.uipath(self._path + "/" + f)
476
537
477 def matchfn(self, f):
538 def matchfn(self, f):
478 # Some information is lost in the superclass's constructor, so we
539 # Some information is lost in the superclass's constructor, so we
479 # can not accurately create the matching function for the subdirectory
540 # can not accurately create the matching function for the subdirectory
480 # from the inputs. Instead, we override matchfn() and visitdir() to
541 # from the inputs. Instead, we override matchfn() and visitdir() to
481 # call the original matcher with the subdirectory path prepended.
542 # call the original matcher with the subdirectory path prepended.
482 return self._matcher.matchfn(self._path + "/" + f)
543 return self._matcher.matchfn(self._path + "/" + f)
483
544
484 def visitdir(self, dir):
545 def visitdir(self, dir):
485 if dir == '.':
546 if dir == '.':
486 dir = self._path
547 dir = self._path
487 else:
548 else:
488 dir = self._path + "/" + dir
549 dir = self._path + "/" + dir
489 return self._matcher.visitdir(dir)
550 return self._matcher.visitdir(dir)
490
551
491 def always(self):
552 def always(self):
492 return self._always
553 return self._always
493
554
494 def anypats(self):
555 def anypats(self):
495 return self._matcher.anypats()
556 return self._matcher.anypats()
496
557
497 def patkind(pattern, default=None):
558 def patkind(pattern, default=None):
498 '''If pattern is 'kind:pat' with a known kind, return kind.'''
559 '''If pattern is 'kind:pat' with a known kind, return kind.'''
499 return _patsplit(pattern, default)[0]
560 return _patsplit(pattern, default)[0]
500
561
501 def _patsplit(pattern, default):
562 def _patsplit(pattern, default):
502 """Split a string into the optional pattern kind prefix and the actual
563 """Split a string into the optional pattern kind prefix and the actual
503 pattern."""
564 pattern."""
504 if ':' in pattern:
565 if ':' in pattern:
505 kind, pat = pattern.split(':', 1)
566 kind, pat = pattern.split(':', 1)
506 if kind in ('re', 'glob', 'path', 'relglob', 'relpath', 'relre',
567 if kind in ('re', 'glob', 'path', 'relglob', 'relpath', 'relre',
507 'listfile', 'listfile0', 'set', 'include', 'subinclude',
568 'listfile', 'listfile0', 'set', 'include', 'subinclude',
508 'rootfilesin'):
569 'rootfilesin'):
509 return kind, pat
570 return kind, pat
510 return default, pattern
571 return default, pattern
511
572
512 def _globre(pat):
573 def _globre(pat):
513 r'''Convert an extended glob string to a regexp string.
574 r'''Convert an extended glob string to a regexp string.
514
575
515 >>> print _globre(r'?')
576 >>> print _globre(r'?')
516 .
577 .
517 >>> print _globre(r'*')
578 >>> print _globre(r'*')
518 [^/]*
579 [^/]*
519 >>> print _globre(r'**')
580 >>> print _globre(r'**')
520 .*
581 .*
521 >>> print _globre(r'**/a')
582 >>> print _globre(r'**/a')
522 (?:.*/)?a
583 (?:.*/)?a
523 >>> print _globre(r'a/**/b')
584 >>> print _globre(r'a/**/b')
524 a\/(?:.*/)?b
585 a\/(?:.*/)?b
525 >>> print _globre(r'[a*?!^][^b][!c]')
586 >>> print _globre(r'[a*?!^][^b][!c]')
526 [a*?!^][\^b][^c]
587 [a*?!^][\^b][^c]
527 >>> print _globre(r'{a,b}')
588 >>> print _globre(r'{a,b}')
528 (?:a|b)
589 (?:a|b)
529 >>> print _globre(r'.\*\?')
590 >>> print _globre(r'.\*\?')
530 \.\*\?
591 \.\*\?
531 '''
592 '''
532 i, n = 0, len(pat)
593 i, n = 0, len(pat)
533 res = ''
594 res = ''
534 group = 0
595 group = 0
535 escape = util.re.escape
596 escape = util.re.escape
536 def peek():
597 def peek():
537 return i < n and pat[i:i + 1]
598 return i < n and pat[i:i + 1]
538 while i < n:
599 while i < n:
539 c = pat[i:i + 1]
600 c = pat[i:i + 1]
540 i += 1
601 i += 1
541 if c not in '*?[{},\\':
602 if c not in '*?[{},\\':
542 res += escape(c)
603 res += escape(c)
543 elif c == '*':
604 elif c == '*':
544 if peek() == '*':
605 if peek() == '*':
545 i += 1
606 i += 1
546 if peek() == '/':
607 if peek() == '/':
547 i += 1
608 i += 1
548 res += '(?:.*/)?'
609 res += '(?:.*/)?'
549 else:
610 else:
550 res += '.*'
611 res += '.*'
551 else:
612 else:
552 res += '[^/]*'
613 res += '[^/]*'
553 elif c == '?':
614 elif c == '?':
554 res += '.'
615 res += '.'
555 elif c == '[':
616 elif c == '[':
556 j = i
617 j = i
557 if j < n and pat[j:j + 1] in '!]':
618 if j < n and pat[j:j + 1] in '!]':
558 j += 1
619 j += 1
559 while j < n and pat[j:j + 1] != ']':
620 while j < n and pat[j:j + 1] != ']':
560 j += 1
621 j += 1
561 if j >= n:
622 if j >= n:
562 res += '\\['
623 res += '\\['
563 else:
624 else:
564 stuff = pat[i:j].replace('\\','\\\\')
625 stuff = pat[i:j].replace('\\','\\\\')
565 i = j + 1
626 i = j + 1
566 if stuff[0:1] == '!':
627 if stuff[0:1] == '!':
567 stuff = '^' + stuff[1:]
628 stuff = '^' + stuff[1:]
568 elif stuff[0:1] == '^':
629 elif stuff[0:1] == '^':
569 stuff = '\\' + stuff
630 stuff = '\\' + stuff
570 res = '%s[%s]' % (res, stuff)
631 res = '%s[%s]' % (res, stuff)
571 elif c == '{':
632 elif c == '{':
572 group += 1
633 group += 1
573 res += '(?:'
634 res += '(?:'
574 elif c == '}' and group:
635 elif c == '}' and group:
575 res += ')'
636 res += ')'
576 group -= 1
637 group -= 1
577 elif c == ',' and group:
638 elif c == ',' and group:
578 res += '|'
639 res += '|'
579 elif c == '\\':
640 elif c == '\\':
580 p = peek()
641 p = peek()
581 if p:
642 if p:
582 i += 1
643 i += 1
583 res += escape(p)
644 res += escape(p)
584 else:
645 else:
585 res += escape(c)
646 res += escape(c)
586 else:
647 else:
587 res += escape(c)
648 res += escape(c)
588 return res
649 return res
589
650
590 def _regex(kind, pat, globsuffix):
651 def _regex(kind, pat, globsuffix):
591 '''Convert a (normalized) pattern of any kind into a regular expression.
652 '''Convert a (normalized) pattern of any kind into a regular expression.
592 globsuffix is appended to the regexp of globs.'''
653 globsuffix is appended to the regexp of globs.'''
593 if not pat:
654 if not pat:
594 return ''
655 return ''
595 if kind == 're':
656 if kind == 're':
596 return pat
657 return pat
597 if kind == 'path':
658 if kind == 'path':
598 if pat == '.':
659 if pat == '.':
599 return ''
660 return ''
600 return '^' + util.re.escape(pat) + '(?:/|$)'
661 return '^' + util.re.escape(pat) + '(?:/|$)'
601 if kind == 'rootfilesin':
662 if kind == 'rootfilesin':
602 if pat == '.':
663 if pat == '.':
603 escaped = ''
664 escaped = ''
604 else:
665 else:
605 # Pattern is a directory name.
666 # Pattern is a directory name.
606 escaped = util.re.escape(pat) + '/'
667 escaped = util.re.escape(pat) + '/'
607 # Anything after the pattern must be a non-directory.
668 # Anything after the pattern must be a non-directory.
608 return '^' + escaped + '[^/]+$'
669 return '^' + escaped + '[^/]+$'
609 if kind == 'relglob':
670 if kind == 'relglob':
610 return '(?:|.*/)' + _globre(pat) + globsuffix
671 return '(?:|.*/)' + _globre(pat) + globsuffix
611 if kind == 'relpath':
672 if kind == 'relpath':
612 return util.re.escape(pat) + '(?:/|$)'
673 return util.re.escape(pat) + '(?:/|$)'
613 if kind == 'relre':
674 if kind == 'relre':
614 if pat.startswith('^'):
675 if pat.startswith('^'):
615 return pat
676 return pat
616 return '.*' + pat
677 return '.*' + pat
617 return _globre(pat) + globsuffix
678 return _globre(pat) + globsuffix
618
679
619 def _buildmatch(ctx, kindpats, globsuffix, listsubrepos, root):
680 def _buildmatch(ctx, kindpats, globsuffix, listsubrepos, root):
620 '''Return regexp string and a matcher function for kindpats.
681 '''Return regexp string and a matcher function for kindpats.
621 globsuffix is appended to the regexp of globs.'''
682 globsuffix is appended to the regexp of globs.'''
622 matchfuncs = []
683 matchfuncs = []
623
684
624 subincludes, kindpats = _expandsubinclude(kindpats, root)
685 subincludes, kindpats = _expandsubinclude(kindpats, root)
625 if subincludes:
686 if subincludes:
626 submatchers = {}
687 submatchers = {}
627 def matchsubinclude(f):
688 def matchsubinclude(f):
628 for prefix, matcherargs in subincludes:
689 for prefix, matcherargs in subincludes:
629 if f.startswith(prefix):
690 if f.startswith(prefix):
630 mf = submatchers.get(prefix)
691 mf = submatchers.get(prefix)
631 if mf is None:
692 if mf is None:
632 mf = match(*matcherargs)
693 mf = match(*matcherargs)
633 submatchers[prefix] = mf
694 submatchers[prefix] = mf
634
695
635 if mf(f[len(prefix):]):
696 if mf(f[len(prefix):]):
636 return True
697 return True
637 return False
698 return False
638 matchfuncs.append(matchsubinclude)
699 matchfuncs.append(matchsubinclude)
639
700
640 fset, kindpats = _expandsets(kindpats, ctx, listsubrepos)
701 fset, kindpats = _expandsets(kindpats, ctx, listsubrepos)
641 if fset:
702 if fset:
642 matchfuncs.append(fset.__contains__)
703 matchfuncs.append(fset.__contains__)
643
704
644 regex = ''
705 regex = ''
645 if kindpats:
706 if kindpats:
646 regex, mf = _buildregexmatch(kindpats, globsuffix)
707 regex, mf = _buildregexmatch(kindpats, globsuffix)
647 matchfuncs.append(mf)
708 matchfuncs.append(mf)
648
709
649 if len(matchfuncs) == 1:
710 if len(matchfuncs) == 1:
650 return regex, matchfuncs[0]
711 return regex, matchfuncs[0]
651 else:
712 else:
652 return regex, lambda f: any(mf(f) for mf in matchfuncs)
713 return regex, lambda f: any(mf(f) for mf in matchfuncs)
653
714
654 def _buildregexmatch(kindpats, globsuffix):
715 def _buildregexmatch(kindpats, globsuffix):
655 """Build a match function from a list of kinds and kindpats,
716 """Build a match function from a list of kinds and kindpats,
656 return regexp string and a matcher function."""
717 return regexp string and a matcher function."""
657 try:
718 try:
658 regex = '(?:%s)' % '|'.join([_regex(k, p, globsuffix)
719 regex = '(?:%s)' % '|'.join([_regex(k, p, globsuffix)
659 for (k, p, s) in kindpats])
720 for (k, p, s) in kindpats])
660 if len(regex) > 20000:
721 if len(regex) > 20000:
661 raise OverflowError
722 raise OverflowError
662 return regex, _rematcher(regex)
723 return regex, _rematcher(regex)
663 except OverflowError:
724 except OverflowError:
664 # We're using a Python with a tiny regex engine and we
725 # We're using a Python with a tiny regex engine and we
665 # made it explode, so we'll divide the pattern list in two
726 # made it explode, so we'll divide the pattern list in two
666 # until it works
727 # until it works
667 l = len(kindpats)
728 l = len(kindpats)
668 if l < 2:
729 if l < 2:
669 raise
730 raise
670 regexa, a = _buildregexmatch(kindpats[:l//2], globsuffix)
731 regexa, a = _buildregexmatch(kindpats[:l//2], globsuffix)
671 regexb, b = _buildregexmatch(kindpats[l//2:], globsuffix)
732 regexb, b = _buildregexmatch(kindpats[l//2:], globsuffix)
672 return regex, lambda s: a(s) or b(s)
733 return regex, lambda s: a(s) or b(s)
673 except re.error:
734 except re.error:
674 for k, p, s in kindpats:
735 for k, p, s in kindpats:
675 try:
736 try:
676 _rematcher('(?:%s)' % _regex(k, p, globsuffix))
737 _rematcher('(?:%s)' % _regex(k, p, globsuffix))
677 except re.error:
738 except re.error:
678 if s:
739 if s:
679 raise error.Abort(_("%s: invalid pattern (%s): %s") %
740 raise error.Abort(_("%s: invalid pattern (%s): %s") %
680 (s, k, p))
741 (s, k, p))
681 else:
742 else:
682 raise error.Abort(_("invalid pattern (%s): %s") % (k, p))
743 raise error.Abort(_("invalid pattern (%s): %s") % (k, p))
683 raise error.Abort(_("invalid pattern"))
744 raise error.Abort(_("invalid pattern"))
684
745
685 def _patternrootsanddirs(kindpats):
746 def _patternrootsanddirs(kindpats):
686 '''Returns roots and directories corresponding to each pattern.
747 '''Returns roots and directories corresponding to each pattern.
687
748
688 This calculates the roots and directories exactly matching the patterns and
749 This calculates the roots and directories exactly matching the patterns and
689 returns a tuple of (roots, dirs) for each. It does not return other
750 returns a tuple of (roots, dirs) for each. It does not return other
690 directories which may also need to be considered, like the parent
751 directories which may also need to be considered, like the parent
691 directories.
752 directories.
692 '''
753 '''
693 r = []
754 r = []
694 d = []
755 d = []
695 for kind, pat, source in kindpats:
756 for kind, pat, source in kindpats:
696 if kind == 'glob': # find the non-glob prefix
757 if kind == 'glob': # find the non-glob prefix
697 root = []
758 root = []
698 for p in pat.split('/'):
759 for p in pat.split('/'):
699 if '[' in p or '{' in p or '*' in p or '?' in p:
760 if '[' in p or '{' in p or '*' in p or '?' in p:
700 break
761 break
701 root.append(p)
762 root.append(p)
702 r.append('/'.join(root) or '.')
763 r.append('/'.join(root) or '.')
703 elif kind in ('relpath', 'path'):
764 elif kind in ('relpath', 'path'):
704 r.append(pat or '.')
765 r.append(pat or '.')
705 elif kind in ('rootfilesin',):
766 elif kind in ('rootfilesin',):
706 d.append(pat or '.')
767 d.append(pat or '.')
707 else: # relglob, re, relre
768 else: # relglob, re, relre
708 r.append('.')
769 r.append('.')
709 return r, d
770 return r, d
710
771
711 def _roots(kindpats):
772 def _roots(kindpats):
712 '''Returns root directories to match recursively from the given patterns.'''
773 '''Returns root directories to match recursively from the given patterns.'''
713 roots, dirs = _patternrootsanddirs(kindpats)
774 roots, dirs = _patternrootsanddirs(kindpats)
714 return roots
775 return roots
715
776
716 def _rootsanddirs(kindpats):
777 def _rootsanddirs(kindpats):
717 '''Returns roots and exact directories from patterns.
778 '''Returns roots and exact directories from patterns.
718
779
719 roots are directories to match recursively, whereas exact directories should
780 roots are directories to match recursively, whereas exact directories should
720 be matched non-recursively. The returned (roots, dirs) tuple will also
781 be matched non-recursively. The returned (roots, dirs) tuple will also
721 include directories that need to be implicitly considered as either, such as
782 include directories that need to be implicitly considered as either, such as
722 parent directories.
783 parent directories.
723
784
724 >>> _rootsanddirs(\
785 >>> _rootsanddirs(\
725 [('glob', 'g/h/*', ''), ('glob', 'g/h', ''), ('glob', 'g*', '')])
786 [('glob', 'g/h/*', ''), ('glob', 'g/h', ''), ('glob', 'g*', '')])
726 (['g/h', 'g/h', '.'], ['g', '.'])
787 (['g/h', 'g/h', '.'], ['g', '.'])
727 >>> _rootsanddirs(\
788 >>> _rootsanddirs(\
728 [('rootfilesin', 'g/h', ''), ('rootfilesin', '', '')])
789 [('rootfilesin', 'g/h', ''), ('rootfilesin', '', '')])
729 ([], ['g/h', '.', 'g', '.'])
790 ([], ['g/h', '.', 'g', '.'])
730 >>> _rootsanddirs(\
791 >>> _rootsanddirs(\
731 [('relpath', 'r', ''), ('path', 'p/p', ''), ('path', '', '')])
792 [('relpath', 'r', ''), ('path', 'p/p', ''), ('path', '', '')])
732 (['r', 'p/p', '.'], ['p', '.'])
793 (['r', 'p/p', '.'], ['p', '.'])
733 >>> _rootsanddirs(\
794 >>> _rootsanddirs(\
734 [('relglob', 'rg*', ''), ('re', 're/', ''), ('relre', 'rr', '')])
795 [('relglob', 'rg*', ''), ('re', 're/', ''), ('relre', 'rr', '')])
735 (['.', '.', '.'], ['.'])
796 (['.', '.', '.'], ['.'])
736 '''
797 '''
737 r, d = _patternrootsanddirs(kindpats)
798 r, d = _patternrootsanddirs(kindpats)
738
799
739 # Append the parents as non-recursive/exact directories, since they must be
800 # Append the parents as non-recursive/exact directories, since they must be
740 # scanned to get to either the roots or the other exact directories.
801 # scanned to get to either the roots or the other exact directories.
741 d.extend(util.dirs(d))
802 d.extend(util.dirs(d))
742 d.extend(util.dirs(r))
803 d.extend(util.dirs(r))
743 # util.dirs() does not include the root directory, so add it manually
804 # util.dirs() does not include the root directory, so add it manually
744 d.append('.')
805 d.append('.')
745
806
746 return r, d
807 return r, d
747
808
748 def _explicitfiles(kindpats):
809 def _explicitfiles(kindpats):
749 '''Returns the potential explicit filenames from the patterns.
810 '''Returns the potential explicit filenames from the patterns.
750
811
751 >>> _explicitfiles([('path', 'foo/bar', '')])
812 >>> _explicitfiles([('path', 'foo/bar', '')])
752 ['foo/bar']
813 ['foo/bar']
753 >>> _explicitfiles([('rootfilesin', 'foo/bar', '')])
814 >>> _explicitfiles([('rootfilesin', 'foo/bar', '')])
754 []
815 []
755 '''
816 '''
756 # Keep only the pattern kinds where one can specify filenames (vs only
817 # Keep only the pattern kinds where one can specify filenames (vs only
757 # directory names).
818 # directory names).
758 filable = [kp for kp in kindpats if kp[0] not in ('rootfilesin',)]
819 filable = [kp for kp in kindpats if kp[0] not in ('rootfilesin',)]
759 return _roots(filable)
820 return _roots(filable)
760
821
761 def _anypats(kindpats):
822 def _anypats(kindpats):
762 for kind, pat, source in kindpats:
823 for kind, pat, source in kindpats:
763 if kind in ('glob', 're', 'relglob', 'relre', 'set', 'rootfilesin'):
824 if kind in ('glob', 're', 'relglob', 'relre', 'set', 'rootfilesin'):
764 return True
825 return True
765
826
766 _commentre = None
827 _commentre = None
767
828
768 def readpatternfile(filepath, warn, sourceinfo=False):
829 def readpatternfile(filepath, warn, sourceinfo=False):
769 '''parse a pattern file, returning a list of
830 '''parse a pattern file, returning a list of
770 patterns. These patterns should be given to compile()
831 patterns. These patterns should be given to compile()
771 to be validated and converted into a match function.
832 to be validated and converted into a match function.
772
833
773 trailing white space is dropped.
834 trailing white space is dropped.
774 the escape character is backslash.
835 the escape character is backslash.
775 comments start with #.
836 comments start with #.
776 empty lines are skipped.
837 empty lines are skipped.
777
838
778 lines can be of the following formats:
839 lines can be of the following formats:
779
840
780 syntax: regexp # defaults following lines to non-rooted regexps
841 syntax: regexp # defaults following lines to non-rooted regexps
781 syntax: glob # defaults following lines to non-rooted globs
842 syntax: glob # defaults following lines to non-rooted globs
782 re:pattern # non-rooted regular expression
843 re:pattern # non-rooted regular expression
783 glob:pattern # non-rooted glob
844 glob:pattern # non-rooted glob
784 pattern # pattern of the current default type
845 pattern # pattern of the current default type
785
846
786 if sourceinfo is set, returns a list of tuples:
847 if sourceinfo is set, returns a list of tuples:
787 (pattern, lineno, originalline). This is useful to debug ignore patterns.
848 (pattern, lineno, originalline). This is useful to debug ignore patterns.
788 '''
849 '''
789
850
790 syntaxes = {'re': 'relre:', 'regexp': 'relre:', 'glob': 'relglob:',
851 syntaxes = {'re': 'relre:', 'regexp': 'relre:', 'glob': 'relglob:',
791 'include': 'include', 'subinclude': 'subinclude'}
852 'include': 'include', 'subinclude': 'subinclude'}
792 syntax = 'relre:'
853 syntax = 'relre:'
793 patterns = []
854 patterns = []
794
855
795 fp = open(filepath, 'rb')
856 fp = open(filepath, 'rb')
796 for lineno, line in enumerate(util.iterfile(fp), start=1):
857 for lineno, line in enumerate(util.iterfile(fp), start=1):
797 if "#" in line:
858 if "#" in line:
798 global _commentre
859 global _commentre
799 if not _commentre:
860 if not _commentre:
800 _commentre = util.re.compile(br'((?:^|[^\\])(?:\\\\)*)#.*')
861 _commentre = util.re.compile(br'((?:^|[^\\])(?:\\\\)*)#.*')
801 # remove comments prefixed by an even number of escapes
862 # remove comments prefixed by an even number of escapes
802 m = _commentre.search(line)
863 m = _commentre.search(line)
803 if m:
864 if m:
804 line = line[:m.end(1)]
865 line = line[:m.end(1)]
805 # fixup properly escaped comments that survived the above
866 # fixup properly escaped comments that survived the above
806 line = line.replace("\\#", "#")
867 line = line.replace("\\#", "#")
807 line = line.rstrip()
868 line = line.rstrip()
808 if not line:
869 if not line:
809 continue
870 continue
810
871
811 if line.startswith('syntax:'):
872 if line.startswith('syntax:'):
812 s = line[7:].strip()
873 s = line[7:].strip()
813 try:
874 try:
814 syntax = syntaxes[s]
875 syntax = syntaxes[s]
815 except KeyError:
876 except KeyError:
816 if warn:
877 if warn:
817 warn(_("%s: ignoring invalid syntax '%s'\n") %
878 warn(_("%s: ignoring invalid syntax '%s'\n") %
818 (filepath, s))
879 (filepath, s))
819 continue
880 continue
820
881
821 linesyntax = syntax
882 linesyntax = syntax
822 for s, rels in syntaxes.iteritems():
883 for s, rels in syntaxes.iteritems():
823 if line.startswith(rels):
884 if line.startswith(rels):
824 linesyntax = rels
885 linesyntax = rels
825 line = line[len(rels):]
886 line = line[len(rels):]
826 break
887 break
827 elif line.startswith(s+':'):
888 elif line.startswith(s+':'):
828 linesyntax = rels
889 linesyntax = rels
829 line = line[len(s) + 1:]
890 line = line[len(s) + 1:]
830 break
891 break
831 if sourceinfo:
892 if sourceinfo:
832 patterns.append((linesyntax + line, lineno, line))
893 patterns.append((linesyntax + line, lineno, line))
833 else:
894 else:
834 patterns.append(linesyntax + line)
895 patterns.append(linesyntax + line)
835 fp.close()
896 fp.close()
836 return patterns
897 return patterns
@@ -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: <matcher files=[], patterns=None, includes=None, excludes=None>
32 matcher: <matcher files=[], patterns=None, includes=None, excludes=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: <matcher files=[], patterns=None, includes='(?:)', excludes=None>
47 matcher: <matcher files=[], patterns=None, includes='(?:)', excludes=None>
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: <matcher files=[], patterns=None, includes=None, excludes=None>
64 matcher: <matcher files=[], patterns=None, includes=None, excludes=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: <matcher files=[], patterns=None, includes=None, excludes='(?:beans(?:/|$))'>
79 matcher: <differencematcher m1=<matcher files=[], patterns=None, includes=None, excludes=None>, m2=<matcher files=[], patterns=None, includes='(?:beans(?:/|$))', excludes=None>>
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: <matcher files=[], patterns=None, includes='(?:mammals\\/[^/]*k(?:/|$))', excludes=None>
88 matcher: <matcher files=[], patterns=None, includes='(?:mammals\\/[^/]*k(?:/|$))', excludes=None>
89 f mammals/skunk skunk
89 f mammals/skunk skunk
90 $ hg debugwalk -I 'glob:*k'
90 $ hg debugwalk -I 'glob:*k'
91 matcher: <matcher files=[], patterns=None, includes='(?:mammals\\/[^/]*k(?:/|$))', excludes=None>
91 matcher: <matcher files=[], patterns=None, includes='(?:mammals\\/[^/]*k(?:/|$))', excludes=None>
92 f mammals/skunk skunk
92 f mammals/skunk skunk
93 $ hg debugwalk -I 'relglob:*k'
93 $ hg debugwalk -I 'relglob:*k'
94 matcher: <matcher files=[], patterns=None, includes='(?:(?:|.*/)[^/]*k(?:/|$))', excludes=None>
94 matcher: <matcher files=[], patterns=None, includes='(?:(?:|.*/)[^/]*k(?:/|$))', excludes=None>
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: <matcher files=['mammals'], patterns='(?:mammals(?:/|$))', includes='(?:(?:|.*/)[^/]*k(?:/|$))', excludes=None>
99 matcher: <matcher files=['mammals'], patterns='(?:mammals(?:/|$))', includes='(?:(?:|.*/)[^/]*k(?:/|$))', excludes=None>
100 f mammals/skunk skunk
100 f mammals/skunk skunk
101 $ hg debugwalk -I 're:.*k$'
101 $ hg debugwalk -I 're:.*k$'
102 matcher: <matcher files=[], patterns=None, includes='(?:.*k$)', excludes=None>
102 matcher: <matcher files=[], patterns=None, includes='(?:.*k$)', excludes=None>
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: <matcher files=[], patterns=None, includes='(?:.*.*k$)', excludes=None>
107 matcher: <matcher files=[], patterns=None, includes='(?:.*.*k$)', excludes=None>
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: <matcher files=[], patterns=None, includes='(?:^beans(?:/|$))', excludes=None>
112 matcher: <matcher files=[], patterns=None, includes='(?:^beans(?:/|$))', excludes=None>
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: <matcher files=[], patterns=None, includes='(?:beans(?:/|$))', excludes=None>
120 matcher: <matcher files=[], patterns=None, includes='(?:beans(?:/|$))', excludes=None>
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: <matcher files=[], patterns='(?:^[^/]+$)', includes=None, excludes=None>
129 matcher: <matcher files=[], patterns='(?:^[^/]+$)', includes=None, excludes=None>
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: <matcher files=[], patterns=None, includes='(?:^[^/]+$)', excludes=None>
134 matcher: <matcher files=[], patterns=None, includes='(?:^[^/]+$)', excludes=None>
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: <matcher files=[], patterns='(?:^[^/]+$)', includes=None, excludes=None>
139 matcher: <matcher files=[], patterns='(?:^[^/]+$)', includes=None, excludes=None>
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: <matcher files=[], patterns=None, includes='(?:^[^/]+$)', excludes=None>
144 matcher: <matcher files=[], patterns=None, includes='(?:^[^/]+$)', excludes=None>
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: <matcher files=[], patterns=None, includes=None, excludes='(?:^[^/]+$)'>
149 matcher: <differencematcher m1=<matcher files=[], patterns=None, includes=None, excludes=None>, m2=<matcher files=[], patterns=None, includes='(?:^[^/]+$)', excludes=None>>
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: <matcher files=[], patterns='(?:^fennel/[^/]+$)', includes=None, excludes=None>
161 matcher: <matcher files=[], patterns='(?:^fennel/[^/]+$)', includes=None, excludes=None>
162 $ hg debugwalk -I 'rootfilesin:fennel'
162 $ hg debugwalk -I 'rootfilesin:fennel'
163 matcher: <matcher files=[], patterns=None, includes='(?:^fennel/[^/]+$)', excludes=None>
163 matcher: <matcher files=[], patterns=None, includes='(?:^fennel/[^/]+$)', excludes=None>
164 $ hg debugwalk 'rootfilesin:skunk'
164 $ hg debugwalk 'rootfilesin:skunk'
165 matcher: <matcher files=[], patterns='(?:^skunk/[^/]+$)', includes=None, excludes=None>
165 matcher: <matcher files=[], patterns='(?:^skunk/[^/]+$)', includes=None, excludes=None>
166 $ hg debugwalk -I 'rootfilesin:skunk'
166 $ hg debugwalk -I 'rootfilesin:skunk'
167 matcher: <matcher files=[], patterns=None, includes='(?:^skunk/[^/]+$)', excludes=None>
167 matcher: <matcher files=[], patterns=None, includes='(?:^skunk/[^/]+$)', excludes=None>
168 $ hg debugwalk 'rootfilesin:beans'
168 $ hg debugwalk 'rootfilesin:beans'
169 matcher: <matcher files=[], patterns='(?:^beans/[^/]+$)', includes=None, excludes=None>
169 matcher: <matcher files=[], patterns='(?:^beans/[^/]+$)', includes=None, excludes=None>
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: <matcher files=[], patterns=None, includes='(?:^beans/[^/]+$)', excludes=None>
177 matcher: <matcher files=[], patterns=None, includes='(?:^beans/[^/]+$)', excludes=None>
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: <matcher files=[], patterns='(?:^mammals/[^/]+$)', includes=None, excludes=None>
185 matcher: <matcher files=[], patterns='(?:^mammals/[^/]+$)', includes=None, excludes=None>
186 f mammals/skunk skunk
186 f mammals/skunk skunk
187 $ hg debugwalk -I 'rootfilesin:mammals'
187 $ hg debugwalk -I 'rootfilesin:mammals'
188 matcher: <matcher files=[], patterns=None, includes='(?:^mammals/[^/]+$)', excludes=None>
188 matcher: <matcher files=[], patterns=None, includes='(?:^mammals/[^/]+$)', excludes=None>
189 f mammals/skunk skunk
189 f mammals/skunk skunk
190 $ hg debugwalk 'rootfilesin:mammals/'
190 $ hg debugwalk 'rootfilesin:mammals/'
191 matcher: <matcher files=[], patterns='(?:^mammals/[^/]+$)', includes=None, excludes=None>
191 matcher: <matcher files=[], patterns='(?:^mammals/[^/]+$)', includes=None, excludes=None>
192 f mammals/skunk skunk
192 f mammals/skunk skunk
193 $ hg debugwalk -I 'rootfilesin:mammals/'
193 $ hg debugwalk -I 'rootfilesin:mammals/'
194 matcher: <matcher files=[], patterns=None, includes='(?:^mammals/[^/]+$)', excludes=None>
194 matcher: <matcher files=[], patterns=None, includes='(?:^mammals/[^/]+$)', excludes=None>
195 f mammals/skunk skunk
195 f mammals/skunk skunk
196 $ hg debugwalk -X 'rootfilesin:mammals'
196 $ hg debugwalk -X 'rootfilesin:mammals'
197 matcher: <matcher files=[], patterns=None, includes=None, excludes='(?:^mammals/[^/]+$)'>
197 matcher: <differencematcher m1=<matcher files=[], patterns=None, includes=None, excludes=None>, m2=<matcher files=[], patterns=None, includes='(?:^mammals/[^/]+$)', excludes=None>>
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: <matcher files=['mammals'], patterns='(?:mammals(?:/|$))', includes=None, excludes=None>
212 matcher: <matcher files=['mammals'], patterns='(?:mammals(?:/|$))', includes=None, excludes=None>
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: <matcher files=[], patterns=None, includes='(?:mammals(?:/|$))', excludes=None>
218 matcher: <matcher files=[], patterns=None, includes='(?:mammals(?:/|$))', excludes=None>
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: <matcher files=['mammals/Procyonidae'], patterns='(?:mammals\\/Procyonidae(?:/|$))', includes=None, excludes=None>
224 matcher: <matcher files=['mammals/Procyonidae'], patterns='(?:mammals\\/Procyonidae(?:/|$))', includes=None, excludes=None>
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: <matcher files=['mammals/Procyonidae'], patterns='(?:mammals\\/Procyonidae(?:/|$))', includes=None, excludes=None>
231 matcher: <matcher files=['mammals/Procyonidae'], patterns='(?:mammals\\/Procyonidae(?:/|$))', includes=None, excludes=None>
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: <matcher files=['mammals'], patterns='(?:mammals(?:/|$))', includes=None, excludes=None>
236 matcher: <matcher files=['mammals'], patterns='(?:mammals(?:/|$))', includes=None, excludes=None>
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: <matcher files=['beans'], patterns='(?:beans(?:/|$))', includes=None, excludes=None>
244 matcher: <matcher files=['beans'], patterns='(?:beans(?:/|$))', includes=None, excludes=None>
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: <matcher files=['mammals'], patterns='(?:mammals(?:/|$))', includes=None, excludes=None>
252 matcher: <matcher files=['mammals'], patterns='(?:mammals(?:/|$))', includes=None, excludes=None>
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: <matcher files=[], patterns=None, includes='(?:beans(?:/|$))', excludes=None>
266 matcher: <matcher files=[], patterns=None, includes='(?:beans(?:/|$))', excludes=None>
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: <matcher files=[], patterns=None, includes='(?:(?:[^/]*|(?:b|m)[^/]*\\/[^/]*)k(?:/|$))', excludes=None>
274 matcher: <matcher files=[], patterns=None, includes='(?:(?:[^/]*|(?:b|m)[^/]*\\/[^/]*)k(?:/|$))', excludes=None>
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: <matcher files=['mammals'], patterns='(?:mammals(?:/|$))', includes='(?:beans(?:/|$))', excludes=None>
279 matcher: <matcher files=['mammals'], patterns='(?:mammals(?:/|$))', includes='(?:beans(?:/|$))', excludes=None>
280 $ hg debugwalk -Inon-existent
280 $ hg debugwalk -Inon-existent
281 matcher: <matcher files=[], patterns=None, includes='(?:non\\-existent(?:/|$))', excludes=None>
281 matcher: <matcher files=[], patterns=None, includes='(?:non\\-existent(?:/|$))', excludes=None>
282 $ hg debugwalk -Inon-existent -Ibeans/black
282 $ hg debugwalk -Inon-existent -Ibeans/black
283 matcher: <matcher files=[], patterns=None, includes='(?:non\\-existent(?:/|$)|beans\\/black(?:/|$))', excludes=None>
283 matcher: <matcher files=[], patterns=None, includes='(?:non\\-existent(?:/|$)|beans\\/black(?:/|$))', excludes=None>
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: <matcher files=['beans/black'], patterns='(?:beans\\/black(?:/|$))', includes='(?:beans(?:/|$))', excludes=None>
286 matcher: <matcher files=['beans/black'], patterns='(?:beans\\/black(?:/|$))', includes='(?:beans(?:/|$))', excludes=None>
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: <matcher files=['beans'], patterns='(?:beans(?:/|$))', includes='(?:beans\\/black(?:/|$))', excludes=None>
289 matcher: <matcher files=['beans'], patterns='(?:beans(?:/|$))', includes='(?:beans\\/black(?:/|$))', excludes=None>
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: <matcher files=['beans'], patterns='(?:beans(?:/|$))', includes=None, excludes='(?:beans\\/black(?:/|$))'>
292 matcher: <differencematcher m1=<matcher files=['beans'], patterns='(?:beans(?:/|$))', includes=None, excludes=None>, m2=<matcher files=[], patterns=None, includes='(?:beans\\/black(?:/|$))', excludes=None>>
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: <matcher files=[], patterns=None, includes='(?:beans(?:/|$))', excludes='(?:beans\\/black(?:/|$))'>
299 matcher: <differencematcher m1=<matcher files=[], patterns=None, includes='(?:beans(?:/|$))', excludes=None>, m2=<matcher files=[], patterns=None, includes='(?:beans\\/black(?:/|$))', excludes=None>>
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: <matcher files=['beans/black'], patterns='(?:beans\\/black(?:/|$))', includes=None, excludes='(?:beans\\/black(?:/|$))'>
306 matcher: <differencematcher m1=<matcher files=['beans/black'], patterns='(?:beans\\/black(?:/|$))', includes=None, excludes=None>, m2=<matcher files=[], patterns=None, includes='(?:beans\\/black(?:/|$))', excludes=None>>
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: <matcher files=[], patterns=None, includes='(?:beans\\/black(?:/|$))', excludes='(?:beans\\/black(?:/|$))'>
309 matcher: <differencematcher m1=<matcher files=[], patterns=None, includes='(?:beans\\/black(?:/|$))', excludes=None>, m2=<matcher files=[], patterns=None, includes='(?:beans\\/black(?:/|$))', excludes=None>>
310 $ hg debugwalk -Xbeans beans/black
310 $ hg debugwalk -Xbeans beans/black
311 matcher: <matcher files=['beans/black'], patterns='(?:beans\\/black(?:/|$))', includes=None, excludes='(?:beans(?:/|$))'>
311 matcher: <differencematcher m1=<matcher files=['beans/black'], patterns='(?:beans\\/black(?:/|$))', includes=None, excludes=None>, m2=<matcher files=[], patterns=None, includes='(?:beans(?:/|$))', excludes=None>>
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: <matcher files=[], patterns=None, includes='(?:beans\\/black(?:/|$))', excludes='(?:beans(?:/|$))'>
314 matcher: <differencematcher m1=<matcher files=[], patterns=None, includes='(?:beans\\/black(?:/|$))', excludes=None>, m2=<matcher files=[], patterns=None, includes='(?:beans(?:/|$))', excludes=None>>
315 $ hg debugwalk 'glob:mammals/../beans/b*'
315 $ hg debugwalk 'glob:mammals/../beans/b*'
316 matcher: <matcher files=['beans'], patterns='(?:beans\\/b[^/]*$)', includes=None, excludes=None>
316 matcher: <matcher files=['beans'], patterns='(?:beans\\/b[^/]*$)', includes=None, excludes=None>
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: <matcher files=['mammals'], patterns='(?:mammals(?:/|$))', includes=None, excludes='(?:[^/]*\\/Procyonidae(?:/|$))'>
320 matcher: <differencematcher m1=<matcher files=['mammals'], patterns='(?:mammals(?:/|$))', includes=None, excludes=None>, m2=<matcher files=[], patterns=None, includes='(?:[^/]*\\/Procyonidae(?:/|$))', excludes=None>>
321 f mammals/skunk mammals/skunk
321 f mammals/skunk mammals/skunk
322 $ hg debugwalk path:mammals
322 $ hg debugwalk path:mammals
323 matcher: <matcher files=['mammals'], patterns='(?:^mammals(?:/|$))', includes=None, excludes=None>
323 matcher: <matcher files=['mammals'], patterns='(?:^mammals(?:/|$))', includes=None, excludes=None>
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: <matcher files=['beans'], patterns='(?:beans(?:/|$))', includes=None, excludes=None>
350 matcher: <matcher files=['beans'], patterns='(?:beans(?:/|$))', includes=None, excludes=None>
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: <matcher files=['.'], patterns='(?:[^/]*$)', includes=None, excludes=None>
364 matcher: <matcher files=['.'], patterns='(?:[^/]*$)', includes=None, excludes=None>
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: <matcher files=['.'], patterns='(?:[^/]*$)', includes=None, excludes=None>
374 matcher: <matcher files=['.'], patterns='(?:[^/]*$)', includes=None, excludes=None>
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: <matcher files=['glob'], patterns='(?:glob$)', includes=None, excludes=None>
380 matcher: <matcher files=['glob'], patterns='(?:glob$)', includes=None, excludes=None>
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: <matcher files=['glob:glob'], patterns='(?:glob\\:glob$)', includes=None, excludes=None>
383 matcher: <matcher files=['glob:glob'], patterns='(?:glob\\:glob$)', includes=None, excludes=None>
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: <matcher files=['glob:glob'], patterns='(?:^glob\\:glob(?:/|$))', includes=None, excludes=None>
386 matcher: <matcher files=['glob:glob'], patterns='(?:^glob\\:glob(?:/|$))', includes=None, excludes=None>
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: <matcher files=['.'], patterns='(?:.*e$)', includes=None, excludes=None>
394 matcher: <matcher files=['.'], patterns='(?:.*e$)', includes=None, excludes=None>
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: <matcher files=['.'], patterns='(?:.*[kb]$)', includes=None, excludes=None>
399 matcher: <matcher files=['.'], patterns='(?:.*[kb]$)', includes=None, excludes=None>
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: <matcher files=['beans/black'], patterns='(?:^beans\\/black(?:/|$))', includes=None, excludes=None>
405 matcher: <matcher files=['beans/black'], patterns='(?:^beans\\/black(?:/|$))', includes=None, excludes=None>
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: <matcher files=['beans/black'], patterns='(?:^beans\\/black(?:/|$))', includes=None, excludes=None>
408 matcher: <matcher files=['beans/black'], patterns='(?:^beans\\/black(?:/|$))', includes=None, excludes=None>
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: <matcher files=['.'], patterns='(?:(?:|.*/)Procyonidae$)', includes=None, excludes=None>
412 matcher: <matcher files=['.'], patterns='(?:(?:|.*/)Procyonidae$)', includes=None, excludes=None>
413 $ hg debugwalk 'relglob:Procyonidae/**'
413 $ hg debugwalk 'relglob:Procyonidae/**'
414 matcher: <matcher files=['.'], patterns='(?:(?:|.*/)Procyonidae\\/.*$)', includes=None, excludes=None>
414 matcher: <matcher files=['.'], patterns='(?:(?:|.*/)Procyonidae\\/.*$)', includes=None, excludes=None>
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: <matcher files=['.', 'fennel'], patterns='(?:(?:|.*/)Procyonidae\\/.*$|fennel(?:/|$))', includes=None, excludes=None>
419 matcher: <matcher files=['.', 'fennel'], patterns='(?:(?:|.*/)Procyonidae\\/.*$|fennel(?:/|$))', includes=None, excludes=None>
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: <matcher files=['beans', 'beans'], patterns='(?:beans(?:/|$)|beans\\/[^/]*$)', includes=None, excludes=None>
425 matcher: <matcher files=['beans', 'beans'], patterns='(?:beans(?:/|$)|beans\\/[^/]*$)', includes=None, excludes=None>
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: <matcher files=['.'], patterns='(?:mamm.*$)', includes=None, excludes=None>
433 matcher: <matcher files=['.'], patterns='(?:mamm.*$)', includes=None, excludes=None>
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: <matcher files=['.', 'fennel'], patterns='(?:mamm.*$|fennel(?:/|$))', includes=None, excludes=None>
439 matcher: <matcher files=['.', 'fennel'], patterns='(?:mamm.*$|fennel(?:/|$))', includes=None, excludes=None>
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: <matcher files=['.'], patterns='(?:j[^/]*$)', includes=None, excludes=None>
446 matcher: <matcher files=['.'], patterns='(?:j[^/]*$)', includes=None, excludes=None>
447 $ hg debugwalk NOEXIST
447 $ hg debugwalk NOEXIST
448 matcher: <matcher files=['NOEXIST'], patterns='(?:NOEXIST(?:/|$))', includes=None, excludes=None>
448 matcher: <matcher files=['NOEXIST'], patterns='(?:NOEXIST(?:/|$))', includes=None, excludes=None>
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: <matcher files=['fifo'], patterns='(?:fifo(?:/|$))', includes=None, excludes=None>
454 matcher: <matcher files=['fifo'], patterns='(?:fifo(?:/|$))', includes=None, excludes=None>
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: <matcher files=['fenugreek'], patterns='(?:fenugreek(?:/|$))', includes=None, excludes=None>
460 matcher: <matcher files=['fenugreek'], patterns='(?:fenugreek(?:/|$))', includes=None, excludes=None>
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: <matcher files=['fenugreek'], patterns='(?:fenugreek(?:/|$))', includes=None, excludes=None>
464 matcher: <matcher files=['fenugreek'], patterns='(?:fenugreek(?:/|$))', includes=None, excludes=None>
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: <matcher files=['new'], patterns='(?:new(?:/|$))', includes=None, excludes=None>
468 matcher: <matcher files=['new'], patterns='(?:new(?:/|$))', includes=None, excludes=None>
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: <matcher files=['ignored'], patterns='(?:ignored(?:/|$))', includes=None, excludes=None>
475 matcher: <matcher files=['ignored'], patterns='(?:ignored(?:/|$))', includes=None, excludes=None>
476 $ hg debugwalk ignored/file
476 $ hg debugwalk ignored/file
477 matcher: <matcher files=['ignored/file'], patterns='(?:ignored\\/file(?:/|$))', includes=None, excludes=None>
477 matcher: <matcher files=['ignored/file'], patterns='(?:ignored\\/file(?:/|$))', includes=None, excludes=None>
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: <matcher files=[], patterns=None, includes='(?:fenugreek(?:/|$)|new(?:/|$))', excludes=None>
484 matcher: <matcher files=[], patterns=None, includes='(?:fenugreek(?:/|$)|new(?:/|$))', excludes=None>
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: <matcher files=[], patterns=None, includes='(?:fenugreek(?:/|$)|new(?:/|$)|mammals\\/skunk(?:/|$))', excludes=None>
489 matcher: <matcher files=[], patterns=None, includes='(?:fenugreek(?:/|$)|new(?:/|$)|mammals\\/skunk(?:/|$))', excludes=None>
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: <matcher files=['mammals/skunk'], patterns='(?:mammals\\/skunk(?:/|$))', includes=None, excludes=None>
496 matcher: <matcher files=['mammals/skunk'], patterns='(?:mammals\\/skunk(?:/|$))', includes=None, excludes=None>
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: <matcher files=['mammals/skunk'], patterns='(?:mammals\\/skunk(?:/|$))', includes=None, excludes=None>
501 matcher: <matcher files=['mammals/skunk'], patterns='(?:mammals\\/skunk(?:/|$))', includes=None, excludes=None>
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: <matcher files=['mammals/skunk'], patterns='(?:mammals\\/skunk(?:/|$))', includes=None, excludes=None>
504 matcher: <matcher files=['mammals/skunk'], patterns='(?:mammals\\/skunk(?:/|$))', includes=None, excludes=None>
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