~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/globbing.py

  • Committer: Martin Pool
  • Date: 2010-04-01 04:41:18 UTC
  • mto: This revision was merged to the branch mainline in revision 5128.
  • Revision ID: mbp@sourcefrog.net-20100401044118-shyctqc02ob08ngz
ignore .testrepository

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
 
23
23
import re
24
24
 
25
 
from bzrlib import errors
26
25
from bzrlib.trace import (
27
 
    mutter,
28
 
    warning,
 
26
    warning
29
27
    )
30
28
 
31
29
 
179
177
    so are matched first, then the basename patterns, then the fullpath
180
178
    patterns.
181
179
    """
182
 
    # We want to _add_patterns in a specific order (as per type_list below)
183
 
    # starting with the shortest and going to the longest.
184
 
    # As some Python version don't support ordered dicts the list below is
185
 
    # used to select inputs for _add_pattern in a specific order.
186
 
    pattern_types = [ "extension", "basename", "fullpath" ]
187
 
 
188
 
    pattern_info = {
189
 
        "extension" : {
190
 
            "translator" : _sub_extension,
191
 
            "prefix" : r'(?:.*/)?(?!.*/)(?:.*\.)'
192
 
        },
193
 
        "basename" : {
194
 
            "translator" : _sub_basename,
195
 
            "prefix" : r'(?:.*/)?(?!.*/)'
196
 
        },
197
 
        "fullpath" : {
198
 
            "translator" : _sub_fullpath,
199
 
            "prefix" : r''
200
 
        },
201
 
    }
202
 
 
203
180
    def __init__(self, patterns):
204
181
        self._regex_patterns = []
205
 
        pattern_lists = {
206
 
            "extension" : [],
207
 
            "basename" : [],
208
 
            "fullpath" : [],
209
 
        }
 
182
        path_patterns = []
 
183
        base_patterns = []
 
184
        ext_patterns = []
210
185
        for pat in patterns:
211
186
            pat = normalize_pattern(pat)
212
 
            pattern_lists[Globster.identify(pat)].append(pat)
213
 
        pi = Globster.pattern_info
214
 
        for t in Globster.pattern_types:
215
 
            self._add_patterns(pattern_lists[t], pi[t]["translator"],
216
 
                pi[t]["prefix"])
 
187
            if pat.startswith(u'RE:') or u'/' in pat:
 
188
                path_patterns.append(pat)
 
189
            elif pat.startswith(u'*.'):
 
190
                ext_patterns.append(pat)
 
191
            else:
 
192
                base_patterns.append(pat)
 
193
        self._add_patterns(ext_patterns,_sub_extension,
 
194
            prefix=r'(?:.*/)?(?!.*/)(?:.*\.)')
 
195
        self._add_patterns(base_patterns,_sub_basename,
 
196
            prefix=r'(?:.*/)?(?!.*/)')
 
197
        self._add_patterns(path_patterns,_sub_fullpath)
217
198
 
218
199
    def _add_patterns(self, patterns, translator, prefix=''):
219
200
        while patterns:
228
209
 
229
210
        :return A matching pattern or None if there is no matching pattern.
230
211
        """
231
 
        try:
232
 
            for regex, patterns in self._regex_patterns:
233
 
                match = regex.match(filename)
234
 
                if match:
235
 
                    return patterns[match.lastindex -1]
236
 
        except errors.InvalidPattern, e:
237
 
            # We can't show the default e.msg to the user as thats for
238
 
            # the combined pattern we sent to regex. Instead we indicate to
239
 
            # the user that an ignore file needs fixing.
240
 
            mutter('Invalid pattern found in regex: %s.', e.msg)
241
 
            e.msg = "File ~/.bazaar/ignore or .bzrignore contains error(s)."
242
 
            bad_patterns = ''
243
 
            for _, patterns in self._regex_patterns:
244
 
                for p in patterns:
245
 
                    if not Globster.is_pattern_valid(p):
246
 
                        bad_patterns += ('\n  %s' % p)
247
 
            e.msg += bad_patterns
248
 
            raise e
 
212
        for regex, patterns in self._regex_patterns:
 
213
            match = regex.match(filename)
 
214
            if match:
 
215
                return patterns[match.lastindex -1]
249
216
        return None
250
217
 
251
 
    @staticmethod
252
 
    def identify(pattern):
253
 
        """Returns pattern category.
254
 
 
255
 
        :param pattern: normalized pattern.
256
 
        Identify if a pattern is fullpath, basename or extension
257
 
        and returns the appropriate type.
258
 
        """
259
 
        if pattern.startswith(u'RE:') or u'/' in pattern:
260
 
            return "fullpath"
261
 
        elif pattern.startswith(u'*.'):
262
 
            return "extension"
263
 
        else:
264
 
            return "basename"
265
 
 
266
 
    @staticmethod
267
 
    def is_pattern_valid(pattern):
268
 
        """Returns True if pattern is valid.
269
 
 
270
 
        :param pattern: Normalized pattern.
271
 
        is_pattern_valid() assumes pattern to be normalized.
272
 
        see: globbing.normalize_pattern
273
 
        """
274
 
        result = True
275
 
        translator = Globster.pattern_info[Globster.identify(pattern)]["translator"]
276
 
        tpattern = '(%s)' % translator(pattern)
277
 
        try:
278
 
            re_obj = re.compile(tpattern, re.UNICODE)
279
 
            re_obj.search("") # force compile
280
 
        except errors.InvalidPattern, e:
281
 
            result = False
282
 
        return result
283
 
 
284
 
 
285
218
class ExceptionGlobster(object):
286
219
    """A Globster that supports exception patterns.
287
220
    
329
262
        self._regex_patterns = []
330
263
        for pat in patterns:
331
264
            pat = normalize_pattern(pat)
332
 
            t = Globster.identify(pat)
333
 
            self._add_patterns([pat], Globster.pattern_info[t]["translator"],
334
 
                Globster.pattern_info[t]["prefix"])
 
265
            if pat.startswith(u'RE:') or u'/' in pat:
 
266
                self._add_patterns([pat], _sub_fullpath)
 
267
            elif pat.startswith(u'*.'):
 
268
                self._add_patterns([pat], _sub_extension,
 
269
                    prefix=r'(?:.*/)?(?!.*/)(?:.*\.)')
 
270
            else:
 
271
                self._add_patterns([pat], _sub_basename,
 
272
                    prefix=r'(?:.*/)?(?!.*/)')
335
273
 
336
274
 
337
275
_slashes = re.compile(r'[\\/]+')