Mercurial > hg
comparison mercurial/match.py @ 14675:cfc89398f710
match: introduce basic fileset support
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Sat, 18 Jun 2011 16:53:44 -0500 |
parents | 1c151b963254 |
children | b6dc362b051c |
comparison
equal
deleted
inserted
replaced
14674:1c151b963254 | 14675:cfc89398f710 |
---|---|
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 import re | 8 import re |
9 import scmutil, util | 9 import scmutil, util, fileset |
10 from i18n import _ | 10 from i18n import _ |
11 | |
12 def _expandsets(pats, ctx): | |
13 '''convert set: patterns into a list of files in the given context''' | |
14 fset = set() | |
15 other = [] | |
16 | |
17 for kind, expr in pats: | |
18 if kind == 'set': | |
19 if not ctx: | |
20 raise util.Abort("fileset expression with no context") | |
21 s = fileset.getfileset(ctx, expr) | |
22 fset.update(s) | |
23 continue | |
24 other.append((kind, expr)) | |
25 return fset, other | |
11 | 26 |
12 class match(object): | 27 class match(object): |
13 def __init__(self, root, cwd, patterns, include=[], exclude=[], | 28 def __init__(self, root, cwd, patterns, include=[], exclude=[], |
14 default='glob', exact=False, auditor=None, ctx=None): | 29 default='glob', exact=False, auditor=None, ctx=None): |
15 """build an object to match a set of file patterns | 30 """build an object to match a set of file patterns |
28 're:<regexp>' - a regular expression | 43 're:<regexp>' - a regular expression |
29 'path:<path>' - a path relative to canonroot | 44 'path:<path>' - a path relative to canonroot |
30 'relglob:<glob>' - an unrooted glob (*.c matches C files in all dirs) | 45 'relglob:<glob>' - an unrooted glob (*.c matches C files in all dirs) |
31 'relpath:<path>' - a path relative to cwd | 46 'relpath:<path>' - a path relative to cwd |
32 'relre:<regexp>' - a regexp that needn't match the start of a name | 47 'relre:<regexp>' - a regexp that needn't match the start of a name |
48 'set:<fileset>' - a fileset expression | |
33 '<something>' - a pattern of the specified default type | 49 '<something>' - a pattern of the specified default type |
34 """ | 50 """ |
35 | 51 |
52 self._ctx = None | |
36 self._root = root | 53 self._root = root |
37 self._cwd = cwd | 54 self._cwd = cwd |
38 self._files = [] | 55 self._files = [] |
39 self._anypats = bool(include or exclude) | 56 self._anypats = bool(include or exclude) |
40 self._ctx = ctx | 57 self._ctx = ctx |
41 | 58 |
42 if include: | 59 if include: |
43 pats = _normalize(include, 'glob', root, cwd, auditor) | 60 pats = _normalize(include, 'glob', root, cwd, auditor) |
44 self.includepat, im = _buildmatch(pats, '(?:/|$)') | 61 self.includepat, im = _buildmatch(ctx, pats, '(?:/|$)') |
45 if exclude: | 62 if exclude: |
46 pats = _normalize(exclude, 'glob', root, cwd, auditor) | 63 pats = _normalize(exclude, 'glob', root, cwd, auditor) |
47 self.excludepat, em = _buildmatch(pats, '(?:/|$)') | 64 self.excludepat, em = _buildmatch(ctx, pats, '(?:/|$)') |
48 if exact: | 65 if exact: |
49 self._files = patterns | 66 self._files = patterns |
50 pm = self.exact | 67 pm = self.exact |
51 elif patterns: | 68 elif patterns: |
52 pats = _normalize(patterns, default, root, cwd, auditor) | 69 pats = _normalize(patterns, default, root, cwd, auditor) |
53 self._files = _roots(pats) | 70 self._files = _roots(pats) |
54 self._anypats = self._anypats or _anypats(pats) | 71 self._anypats = self._anypats or _anypats(pats) |
55 self.patternspat, pm = _buildmatch(pats, '$') | 72 self.patternspat, pm = _buildmatch(ctx, pats, '$') |
56 | 73 |
57 if patterns or exact: | 74 if patterns or exact: |
58 if include: | 75 if include: |
59 if exclude: | 76 if exclude: |
60 m = lambda f: im(f) and not em(f) and pm(f) | 77 m = lambda f: im(f) and not em(f) and pm(f) |
161 """Split a string into an optional pattern kind prefix and the | 178 """Split a string into an optional pattern kind prefix and the |
162 actual pattern.""" | 179 actual pattern.""" |
163 if ':' in pat: | 180 if ':' in pat: |
164 kind, val = pat.split(':', 1) | 181 kind, val = pat.split(':', 1) |
165 if kind in ('re', 'glob', 'path', 'relglob', 'relpath', 'relre', | 182 if kind in ('re', 'glob', 'path', 'relglob', 'relpath', 'relre', |
166 'listfile', 'listfile0'): | 183 'listfile', 'listfile0', 'set'): |
167 return kind, val | 184 return kind, val |
168 return default, pat | 185 return default, pat |
169 | 186 |
170 def _globre(pat): | 187 def _globre(pat): |
171 "convert a glob pattern into a regexp" | 188 "convert a glob pattern into a regexp" |
239 if name.startswith('^'): | 256 if name.startswith('^'): |
240 return name | 257 return name |
241 return '.*' + name | 258 return '.*' + name |
242 return _globre(name) + tail | 259 return _globre(name) + tail |
243 | 260 |
244 def _buildmatch(pats, tail): | 261 def _buildmatch(ctx, pats, tail): |
262 fset, pats = _expandsets(pats, ctx) | |
263 if not pats: | |
264 return "", fset.__contains__ | |
265 | |
266 pat, mf = _buildregexmatch(pats, tail) | |
267 if fset: | |
268 return pat, lambda f: f in fset or mf(f) | |
269 return pat, mf | |
270 | |
271 def _buildregexmatch(pats, tail): | |
245 """build a matching function from a set of patterns""" | 272 """build a matching function from a set of patterns""" |
246 try: | 273 try: |
247 pat = '(?:%s)' % '|'.join([_regex(k, p, tail) for (k, p) in pats]) | 274 pat = '(?:%s)' % '|'.join([_regex(k, p, tail) for (k, p) in pats]) |
248 if len(pat) > 20000: | 275 if len(pat) > 20000: |
249 raise OverflowError() | 276 raise OverflowError() |