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