~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/globbing.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-07-16 14:02:58 UTC
  • mfrom: (5346.2.3 doc)
  • Revision ID: pqm@pqm.ubuntu.com-20100716140258-js1p8i24w8nodz6t
(mbp) developer docs about transports and symlinks (Martin Pool)

Show diffs side-by-side

added added

removed removed

Lines of Context:
179
179
    so are matched first, then the basename patterns, then the fullpath
180
180
    patterns.
181
181
    """
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
182
    def __init__(self, patterns):
204
183
        self._regex_patterns = []
205
 
        pattern_lists = {
206
 
            "extension" : [],
207
 
            "basename" : [],
208
 
            "fullpath" : [],
209
 
        }
 
184
        path_patterns = []
 
185
        base_patterns = []
 
186
        ext_patterns = []
210
187
        for pat in patterns:
211
188
            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"])
 
189
            if pat.startswith(u'RE:') or u'/' in pat:
 
190
                path_patterns.append(pat)
 
191
            elif pat.startswith(u'*.'):
 
192
                ext_patterns.append(pat)
 
193
            else:
 
194
                base_patterns.append(pat)
 
195
        self._add_patterns(ext_patterns,_sub_extension,
 
196
            prefix=r'(?:.*/)?(?!.*/)(?:.*\.)')
 
197
        self._add_patterns(base_patterns,_sub_basename,
 
198
            prefix=r'(?:.*/)?(?!.*/)')
 
199
        self._add_patterns(path_patterns,_sub_fullpath)
217
200
 
218
201
    def _add_patterns(self, patterns, translator, prefix=''):
219
202
        while patterns:
238
221
            # the combined pattern we sent to regex. Instead we indicate to
239
222
            # the user that an ignore file needs fixing.
240
223
            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
 
224
            e.msg = "File ~/.bazaar/ignore or .bzrignore contains errors."
248
225
            raise e
249
226
        return None
250
227
 
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
228
class ExceptionGlobster(object):
286
229
    """A Globster that supports exception patterns.
287
230
    
329
272
        self._regex_patterns = []
330
273
        for pat in patterns:
331
274
            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"])
 
275
            if pat.startswith(u'RE:') or u'/' in pat:
 
276
                self._add_patterns([pat], _sub_fullpath)
 
277
            elif pat.startswith(u'*.'):
 
278
                self._add_patterns([pat], _sub_extension,
 
279
                    prefix=r'(?:.*/)?(?!.*/)(?:.*\.)')
 
280
            else:
 
281
                self._add_patterns([pat], _sub_basename,
 
282
                    prefix=r'(?:.*/)?(?!.*/)')
335
283
 
336
284
 
337
285
_slashes = re.compile(r'[\\/]+')