179
179
so are matched first, then the basename patterns, then the fullpath
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" ]
190
"translator" : _sub_extension,
191
"prefix" : r'(?:.*/)?(?!.*/)(?:.*\.)'
194
"translator" : _sub_basename,
195
"prefix" : r'(?:.*/)?(?!.*/)'
198
"translator" : _sub_fullpath,
182
203
def __init__(self, patterns):
183
204
self._regex_patterns = []
187
210
for pat in patterns:
188
211
pat = normalize_pattern(pat)
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)
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)
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"],
201
218
def _add_patterns(self, patterns, translator, prefix=''):
221
238
# the combined pattern we sent to regex. Instead we indicate to
222
239
# the user that an ignore file needs fixing.
223
240
mutter('Invalid pattern found in regex: %s.', e.msg)
224
e.msg = "File ~/.bazaar/ignore or .bzrignore contains errors."
241
e.msg = "File ~/.bazaar/ignore or .bzrignore contains error(s)."
243
for _, patterns in self._regex_patterns:
245
if not Globster.is_pattern_valid(p):
246
bad_patterns += ('\n %s' % p)
247
e.msg += bad_patterns
252
def identify(pattern):
253
"""Returns pattern category.
255
:param pattern: normalized pattern.
256
Identify if a pattern is fullpath, basename or extension
257
and returns the appropriate type.
259
if pattern.startswith(u'RE:') or u'/' in pattern:
261
elif pattern.startswith(u'*.'):
267
def is_pattern_valid(pattern):
268
"""Returns True if pattern is valid.
270
:param pattern: Normalized pattern.
271
is_pattern_valid() assumes pattern to be normalized.
272
see: globbing.normalize_pattern
275
translator = Globster.pattern_info[Globster.identify(pattern)]["translator"]
276
tpattern = '(%s)' % translator(pattern)
278
re_obj = re.compile(tpattern, re.UNICODE)
279
re_obj.search("") # force compile
280
except errors.InvalidPattern, e:
228
285
class ExceptionGlobster(object):
229
286
"""A Globster that supports exception patterns.
272
329
self._regex_patterns = []
273
330
for pat in patterns:
274
331
pat = normalize_pattern(pat)
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'(?:.*/)?(?!.*/)(?:.*\.)')
281
self._add_patterns([pat], _sub_basename,
282
prefix=r'(?:.*/)?(?!.*/)')
332
t = Globster.identify(pat)
333
self._add_patterns([pat], Globster.pattern_info[t]["translator"],
334
Globster.pattern_info[t]["prefix"])
285
337
_slashes = re.compile(r'[\\/]+')