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