79
80
def __call__(self, text):
81
82
self._pat = lazy_regex.lazy_compile(
82
u'|'.join([u'(%s)' % p for p in self._pats]),
83
u'|'.join([u'(%s)' % p for p in self._pats]),
84
85
return self._pat.sub(self._do_sub, text)
86
87
def _do_sub(self, m):
138
139
_sub_fullpath = Replacer()
139
_sub_fullpath.add(r'^RE:.*', _sub_re) # RE:<anything> is a regex
140
_sub_fullpath.add(r'\[\^?\]?(?:[^][]|\[:[^]]+:\])+\]',
141
_sub_group) # char group
142
_sub_fullpath.add(r'(?:(?<=/)|^)(?:\.?/)+', u'') # canonicalize path
143
_sub_fullpath.add(r'\\.', r'\&') # keep anything backslashed
144
_sub_fullpath.add(r'[(){}|^$+.]', r'\\&') # escape specials
145
_sub_fullpath.add(r'(?:(?<=/)|^)\*\*+/', r'(?:.*/)?') # **/ after ^ or /
146
_sub_fullpath.add(r'\*+', r'[^/]*') # * elsewhere
147
_sub_fullpath.add(r'\?', r'[^/]') # ? everywhere
140
_sub_fullpath.add(r'^RE:.*', _sub_re) # RE:<anything> is a regex
141
_sub_fullpath.add(r'\[\^?\]?(?:[^][]|\[:[^]]+:\])+\]', _sub_group) # char group
142
_sub_fullpath.add(r'(?:(?<=/)|^)(?:\.?/)+', u'') # canonicalize path
143
_sub_fullpath.add(r'\\.', r'\&') # keep anything backslashed
144
_sub_fullpath.add(r'[(){}|^$+.]', r'\\&') # escape specials
145
_sub_fullpath.add(r'(?:(?<=/)|^)\*\*+/', r'(?:.*/)?') # **/ after ^ or /
146
_sub_fullpath.add(r'\*+', r'[^/]*') # * elsewhere
147
_sub_fullpath.add(r'\?', r'[^/]') # ? everywhere
150
150
_sub_basename = Replacer()
151
_sub_basename.add(r'\[\^?\]?(?:[^][]|\[:[^]]+:\])+\]',
152
_sub_group) # char group
153
_sub_basename.add(r'\\.', r'\&') # keep anything backslashed
154
_sub_basename.add(r'[(){}|^$+.]', r'\\&') # escape specials
155
_sub_basename.add(r'\*+', r'.*') # * everywhere
156
_sub_basename.add(r'\?', r'.') # ? everywhere
151
_sub_basename.add(r'\[\^?\]?(?:[^][]|\[:[^]]+:\])+\]', _sub_group) # char group
152
_sub_basename.add(r'\\.', r'\&') # keep anything backslashed
153
_sub_basename.add(r'[(){}|^$+.]', r'\\&') # escape specials
154
_sub_basename.add(r'\*+', r'.*') # * everywhere
155
_sub_basename.add(r'\?', r'.') # ? everywhere
159
158
def _sub_extension(pattern):
189
188
# starting with the shortest and going to the longest.
190
189
# As some Python version don't support ordered dicts the list below is
191
190
# used to select inputs for _add_pattern in a specific order.
192
pattern_types = ["extension", "basename", "fullpath"]
191
pattern_types = [ "extension", "basename", "fullpath" ]
196
"translator": _sub_extension,
197
"prefix": r'(?:.*/)?(?!.*/)(?:.*\.)'
195
"translator" : _sub_extension,
196
"prefix" : r'(?:.*/)?(?!.*/)(?:.*\.)'
200
"translator": _sub_basename,
201
"prefix": r'(?:.*/)?(?!.*/)'
199
"translator" : _sub_basename,
200
"prefix" : r'(?:.*/)?(?!.*/)'
204
"translator": _sub_fullpath,
203
"translator" : _sub_fullpath,
219
218
pi = Globster.pattern_info
220
219
for t in Globster.pattern_types:
221
220
self._add_patterns(pattern_lists[t], pi[t]["translator"],
224
223
def _add_patterns(self, patterns, translator, prefix=''):
242
241
for regex, patterns in self._regex_patterns:
243
242
match = regex.match(filename)
245
return patterns[match.lastindex - 1]
244
return patterns[match.lastindex -1]
246
245
except lazy_regex.InvalidPattern as e:
247
246
# We can't show the default e.msg to the user as thats for
248
247
# the combined pattern we sent to regex. Instead we indicate to
249
248
# the user that an ignore file needs fixing.
250
249
mutter('Invalid pattern found in regex: %s.', e.msg)
252
"File ~/.config/breezy/ignore or "
253
".bzrignore contains error(s).")
250
e.msg = "File ~/.bazaar/ignore or .bzrignore contains error(s)."
254
251
bad_patterns = ''
255
252
for _, patterns in self._regex_patterns:
256
253
for p in patterns:
284
281
see: globbing.normalize_pattern
287
translator = Globster.pattern_info[Globster.identify(
288
pattern)]["translator"]
284
translator = Globster.pattern_info[Globster.identify(pattern)]["translator"]
289
285
tpattern = '(%s)' % translator(pattern)
291
287
re_obj = lazy_regex.lazy_compile(tpattern, re.UNICODE)
292
re_obj.search("") # force compile
293
except lazy_regex.InvalidPattern:
288
re_obj.search("") # force compile
289
except lazy_regex.InvalidPattern as e:
298
294
class ExceptionGlobster(object):
299
295
"""A Globster that supports exception patterns.
301
297
Exceptions are ignore patterns prefixed with '!'. Exception
302
patterns take precedence over regular patterns and cause a
303
matching filename to return None from the match() function.
304
Patterns using a '!!' prefix are highest precedence, and act
298
patterns take precedence over regular patterns and cause a
299
matching filename to return None from the match() function.
300
Patterns using a '!!' prefix are highest precedence, and act
305
301
as regular ignores. '!!' patterns are useful to establish ignores
306
302
that apply under paths specified by '!' exception patterns.
309
305
def __init__(self, patterns):
310
306
ignores = [[], [], []]
311
307
for p in patterns:
345
340
pat = normalize_pattern(pat)
346
341
t = Globster.identify(pat)
347
342
self._add_patterns([pat], Globster.pattern_info[t]["translator"],
348
Globster.pattern_info[t]["prefix"])
343
Globster.pattern_info[t]["prefix"])
351
346
_slashes = lazy_regex.lazy_compile(r'[\\/]+')
354
347
def normalize_pattern(pattern):
355
348
"""Converts backslashes in path patterns to forward slashes.