mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-05-09 02:28:18 +02:00
contrib/bzutil: add filter FilterId and allow negation of filters
There is already the command line option --bz to add additional bugs to the output. The option --no-bz is to black list bugs. The new filter 'bz' allows you something similar, but contrary to --no-bz which acts at an earlier stage, this filters bugs after they are parsed from refs. Also, allow every filter to be negated by prepending it with ~ or !. Signed-off-by: Thomas Haller <thaller@redhat.com>
This commit is contained in:
parent
d4be2c2da7
commit
25a57149aa
1 changed files with 110 additions and 59 deletions
|
|
@ -430,6 +430,37 @@ class BzInfo:
|
||||||
def clearBZData(self):
|
def clearBZData(self):
|
||||||
if hasattr(self, '_bzdata'):
|
if hasattr(self, '_bzdata'):
|
||||||
del self._bzdata
|
del self._bzdata
|
||||||
|
@staticmethod
|
||||||
|
def parse_bz(obz, no_bz=None):
|
||||||
|
bz_tuples = [bz for bz in re.split('[,; ]', obz) if bz]
|
||||||
|
result_man2 = []
|
||||||
|
no_bz_skipped = []
|
||||||
|
has_any = False
|
||||||
|
for bzii in bz_tuples:
|
||||||
|
bzi = bzii.partition(':')
|
||||||
|
if not bzi[1] and not bzi[2]:
|
||||||
|
bzi = bzii.partition('#')
|
||||||
|
if not bzi[1] and not bzi[2]:
|
||||||
|
bzi = ['rh',bzi[0]]
|
||||||
|
else:
|
||||||
|
bzi = bzi[::2]
|
||||||
|
if not bzi[0] or not bzi[1] or not re.match('^[0-9]{4,7}$', bzi[1]):
|
||||||
|
raise Exception('invalid bug specifier \"%s\" (%s)' % (obz, bzii))
|
||||||
|
bz = None
|
||||||
|
if bzi[0] == 'rhbz' or bzi[0] == 'rh':
|
||||||
|
bz = BzInfoRhbz(bzi[1])
|
||||||
|
elif bzi[0] == 'bgo' or bzi[0] == 'bg':
|
||||||
|
bz = BzInfoBgo(bzi[1])
|
||||||
|
else:
|
||||||
|
raise Exception('invalid bug specifier \"%s\"' % obz)
|
||||||
|
if no_bz is None or bz not in no_bz:
|
||||||
|
result_man2.append(bz)
|
||||||
|
else:
|
||||||
|
no_bz_skipped.append(bz)
|
||||||
|
has_any = True
|
||||||
|
if not has_any:
|
||||||
|
raise Exception('invalid bug specifier \"%s\": contains no bugs' % obz)
|
||||||
|
return result_man2, no_bz_skipped
|
||||||
|
|
||||||
|
|
||||||
class BzInfoBgo(BzInfo):
|
class BzInfoBgo(BzInfo):
|
||||||
|
|
@ -696,6 +727,8 @@ class FilterBase():
|
||||||
s = s.replace("\n", "\\n")
|
s = s.replace("\n", "\\n")
|
||||||
s = s.replace("\\", "\\\\")
|
s = s.replace("\\", "\\\\")
|
||||||
return "'" + s + "'"
|
return "'" + s + "'"
|
||||||
|
_regex_neg = '^([!~]*)'
|
||||||
|
_regex_neg = re.compile(_regex_neg)
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create_filter(args):
|
def create_filter(args):
|
||||||
if isinstance(args, basestring):
|
if isinstance(args, basestring):
|
||||||
|
|
@ -704,10 +737,16 @@ class FilterBase():
|
||||||
raise Exception("Cannot parse empty filter")
|
raise Exception("Cannot parse empty filter")
|
||||||
name = args[0]
|
name = args[0]
|
||||||
|
|
||||||
|
neg = FilterBase._regex_neg.match(name)
|
||||||
|
neg = neg.group(0)
|
||||||
|
if neg:
|
||||||
|
name = name[len(neg):]
|
||||||
|
neg = len(neg) % 2 == 1
|
||||||
|
|
||||||
if name.lower() in FilterBase._mapping:
|
if name.lower() in FilterBase._mapping:
|
||||||
filter_type = FilterBase._mapping[name.lower()]
|
filter_type = FilterBase._mapping[name.lower()]
|
||||||
elif name.lower() in BzClient.DEFAULT_FIELDS:
|
elif name.lower() in BzClient.DEFAULT_FIELDS:
|
||||||
args = tuple(['match'] + list(args))
|
args = tuple(['match', name] + list(args[1:]))
|
||||||
filter_type = FilterBase._mapping['match']
|
filter_type = FilterBase._mapping['match']
|
||||||
else:
|
else:
|
||||||
raise Exception("Invalid filter name \"%s\"" % name)
|
raise Exception("Invalid filter name \"%s\"" % name)
|
||||||
|
|
@ -716,18 +755,30 @@ class FilterBase():
|
||||||
f = filter_type.factory(args[1:])
|
f = filter_type.factory(args[1:])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise Exception("Cannot create filter of type %s with arguments \"%r\": (%s)" % (filter_type.__name__, args[1:], str(e)))
|
raise Exception("Cannot create filter of type %s with arguments \"%r\": (%s)" % (filter_type.__name__, args[1:], str(e)))
|
||||||
|
if neg:
|
||||||
|
f = FilterNot.create(f)
|
||||||
return f
|
return f
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def parse(s):
|
def parse(s):
|
||||||
if s.lower() in FilterBase._mapping:
|
if not isinstance(s, basestring):
|
||||||
filter_type = FilterBase._mapping[s.lower()]
|
return FilterBase.create_filter(s)
|
||||||
if not filter_type.allow_simple:
|
sl = s.lower()
|
||||||
raise Exception("Cannot create filter '%s' because it needs some arguments. Use full python syntax" % (s))
|
if sl in FilterBase._mapping:
|
||||||
try:
|
filter_type = FilterBase._mapping[sl]
|
||||||
f = filter_type.factory([])
|
if filter_type.allow_simple:
|
||||||
except Exception as e:
|
try:
|
||||||
raise Exception("Cannot create filter of type %s with arguments \"%r\": (%s)" % (filter_type.factory.__name__, args[1:], str(e)))
|
f = filter_type.factory([])
|
||||||
return f
|
except Exception as e:
|
||||||
|
raise Exception("Cannot create filter of type %s with arguments \"%r\": (%s)" % (filter_type.factory.__name__, args[1:], str(e)))
|
||||||
|
return f
|
||||||
|
if sl.startswith("bz "):
|
||||||
|
return FilterBz(s[3:].split())
|
||||||
|
if sl.startswith("nobz "):
|
||||||
|
return FilterBz.exclude(s[5:].split())
|
||||||
|
if sl.startswith("not "):
|
||||||
|
return FilterNot.create(filter=FilterBase.parse(s[4:]))
|
||||||
|
if sl.startswith("!") or sl.startswith("~"):
|
||||||
|
return FilterNot.create(filter=FilterBase.parse(s[1:]))
|
||||||
try:
|
try:
|
||||||
expr = ast.literal_eval(s)
|
expr = ast.literal_eval(s)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
@ -771,7 +822,7 @@ class FilterNot(FilterBase):
|
||||||
return
|
return
|
||||||
if len(args) != 1:
|
if len(args) != 1:
|
||||||
raise Exception("Filter of type FilterNot expects exactly one arguement (instead got \"%r\")" % (args))
|
raise Exception("Filter of type FilterNot expects exactly one arguement (instead got \"%r\")" % (args))
|
||||||
self._filter = FilterBase.create_filter(args[0])
|
self._filter = FilterBase.parse(args[0])
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '(not %s)' % self._filter
|
return '(not %s)' % self._filter
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
|
@ -784,17 +835,21 @@ class FilterAnd(FilterBase):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def join(*args):
|
def join(*args):
|
||||||
if len(args) >= 2:
|
if len(args) >= 2:
|
||||||
return FilterAnd(None, filters=args)
|
return FilterAnd(filters=args)
|
||||||
return args[0]
|
return args[0]
|
||||||
def __init__(self, args, filters=None):
|
@staticmethod
|
||||||
|
def create(args=None,filters=None):
|
||||||
|
filter = FilterAnd(args=args, filters=filters)
|
||||||
|
if len(filter._filters) == 0:
|
||||||
|
return FilterTrue()
|
||||||
|
if len(filter._filters) == 1:
|
||||||
|
return filters[0]
|
||||||
|
return filter
|
||||||
|
def __init__(self, args=None, filters=None):
|
||||||
if filters is None:
|
if filters is None:
|
||||||
if not args:
|
if not args:
|
||||||
raise Exception("Filter of type FilterAnd expects one or more filters (instead got \"%r\")" % (args))
|
raise Exception("Filter of type FilterAnd expects one or more filters (instead got \"%r\")" % (args))
|
||||||
filters = [FilterBase.create_filter(f) for f in args]
|
filters = [FilterBase.parse(f) for f in args]
|
||||||
if len(filters) == 0:
|
|
||||||
return FilterTrue()
|
|
||||||
if len(filters) == 1:
|
|
||||||
return filters[0]
|
|
||||||
f = []
|
f = []
|
||||||
for filter in filters:
|
for filter in filters:
|
||||||
if isinstance(filter, FilterAnd):
|
if isinstance(filter, FilterAnd):
|
||||||
|
|
@ -818,17 +873,21 @@ class FilterOr(FilterBase):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def join(*args):
|
def join(*args):
|
||||||
if len(args) >= 2:
|
if len(args) >= 2:
|
||||||
return FilterOr(None, filters=args)
|
return FilterOr(filters=args)
|
||||||
return args[0]
|
return args[0]
|
||||||
def __init__(self, args, filters=None):
|
@staticmethod
|
||||||
|
def create(args=None,filters=None):
|
||||||
|
filter = FilterOr(args=args, filters=filters)
|
||||||
|
if len(filter._filters) == 0:
|
||||||
|
return FilterTrue()
|
||||||
|
if len(filter._filters) == 1:
|
||||||
|
return filters[0]
|
||||||
|
return filter
|
||||||
|
def __init__(self, args=None, filters=None):
|
||||||
if filters is None:
|
if filters is None:
|
||||||
if not args:
|
if not args:
|
||||||
raise Exception("Filter of type FilterOr expects one or more filters (instead got \"%r\")" % (args))
|
raise Exception("Filter of type FilterOr expects one or more filters (instead got \"%r\")" % (args))
|
||||||
filters = [FilterBase.create_filter(f) for f in args]
|
filters = [FilterBase.parse(f) for f in args]
|
||||||
if len(filters) == 0:
|
|
||||||
return FilterFalse()
|
|
||||||
if len(filters) == 1:
|
|
||||||
return filters[0]
|
|
||||||
f = []
|
f = []
|
||||||
for filter in filters:
|
for filter in filters:
|
||||||
if isinstance(filter, FilterOr):
|
if isinstance(filter, FilterOr):
|
||||||
|
|
@ -872,6 +931,27 @@ class FilterBgo(FilterBase):
|
||||||
return isinstance(bz, BzInfoBgo)
|
return isinstance(bz, BzInfoBgo)
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
return isinstance(other, FilterBgo)
|
return isinstance(other, FilterBgo)
|
||||||
|
class FilterBz(FilterBase):
|
||||||
|
def __init__(self, args=None, bz=None):
|
||||||
|
if bz is not None:
|
||||||
|
self._bz = set(bz)
|
||||||
|
else:
|
||||||
|
self._bz = set([bz for arg in args for bz in BzInfo.parse_bz(arg)[0]])
|
||||||
|
if not self._bz:
|
||||||
|
raise Exception("Missing bz arguments for FilterBz")
|
||||||
|
def __str__(self):
|
||||||
|
return "(bz %s)" % (" ".join([FilterBase.escape(str(bz)) for bz in self._bz]))
|
||||||
|
def __repr__(self):
|
||||||
|
return "('bz' %s)" % (",".join([FilterBase.escape(str(bz)) for bz in self._bz]))
|
||||||
|
def eval(self, bz):
|
||||||
|
for bz2 in self._bz:
|
||||||
|
if bz == bz2:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
def __eq__(self, other):
|
||||||
|
if isinstance(other, FilterBz):
|
||||||
|
return other._bz == self._bz
|
||||||
|
return False
|
||||||
class FilterMatch(FilterBase):
|
class FilterMatch(FilterBase):
|
||||||
def __init__(self, args):
|
def __init__(self, args):
|
||||||
if len(args) != 2 or not isinstance(args[0], basestring) or not isinstance(args[1], basestring):
|
if len(args) != 2 or not isinstance(args[0], basestring) or not isinstance(args[1], basestring):
|
||||||
|
|
@ -881,7 +961,7 @@ class FilterMatch(FilterBase):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '(match %s %s)' % (FilterBase.escape(self._name), FilterBase.escape(self._value))
|
return '(match %s %s)' % (FilterBase.escape(self._name), FilterBase.escape(self._value))
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "('match' %s %s)" % (FilterBase.escape(self._name), FilterBase.escape(self._value))
|
return "('match', %s, %s)" % (FilterBase.escape(self._name), FilterBase.escape(self._value))
|
||||||
def eval(self, bz):
|
def eval(self, bz):
|
||||||
bzdata = bz.getBZData()
|
bzdata = bz.getBZData()
|
||||||
if not bzdata or self._name not in bzdata:
|
if not bzdata or self._name not in bzdata:
|
||||||
|
|
@ -946,6 +1026,7 @@ FilterBase._mapping = {
|
||||||
'not': FilterMapping(FilterNot, False),
|
'not': FilterMapping(FilterNot, False),
|
||||||
'and': FilterMapping(FilterAnd, False),
|
'and': FilterMapping(FilterAnd, False),
|
||||||
'or': FilterMapping(FilterOr, False),
|
'or': FilterMapping(FilterOr, False),
|
||||||
|
'bz': FilterMapping(FilterBz, False),
|
||||||
'rhbz': FilterMapping(FilterRhbz),
|
'rhbz': FilterMapping(FilterRhbz),
|
||||||
'bgo': FilterMapping(FilterBgo),
|
'bgo': FilterMapping(FilterBgo),
|
||||||
'match': FilterMapping(FilterMatch, False),
|
'match': FilterMapping(FilterMatch, False),
|
||||||
|
|
@ -1001,42 +1082,12 @@ class CmdParseCommitMessage(CmdBase):
|
||||||
def _order_keys(keys, ordered):
|
def _order_keys(keys, ordered):
|
||||||
return [o for o in ordered if o in keys]
|
return [o for o in ordered if o in keys]
|
||||||
|
|
||||||
def _parse_bz(self, obz, no_bz):
|
|
||||||
bz_tuples = [bz for bz in re.split('[,; ]', obz) if bz]
|
|
||||||
result_man2 = []
|
|
||||||
no_bz_skipped = []
|
|
||||||
has_any = False
|
|
||||||
for bzii in bz_tuples:
|
|
||||||
bzi = bzii.partition(':')
|
|
||||||
if not bzi[1] and not bzi[2]:
|
|
||||||
bzi = bzii.partition('#')
|
|
||||||
if not bzi[1] and not bzi[2]:
|
|
||||||
bzi = ['rh',bzi[0]]
|
|
||||||
else:
|
|
||||||
bzi = bzi[::2]
|
|
||||||
if not bzi[0] or not bzi[1] or not re.match('^[0-9]{4,7}$', bzi[1]):
|
|
||||||
raise Exception('invalid bug specifier \"%s\" (%s)' % (obz, bzii))
|
|
||||||
bz = None
|
|
||||||
if bzi[0] == 'rhbz' or bzi[0] == 'rh':
|
|
||||||
bz = BzInfoRhbz(bzi[1])
|
|
||||||
elif bzi[0] == 'bgo' or bzi[0] == 'bg':
|
|
||||||
bz = BzInfoBgo(bzi[1])
|
|
||||||
else:
|
|
||||||
raise Exception('invalid bug specifier \"%s\"' % obz)
|
|
||||||
if no_bz is None or bz not in no_bz:
|
|
||||||
result_man2.append(bz)
|
|
||||||
else:
|
|
||||||
no_bz_skipped.append(bz)
|
|
||||||
has_any = True
|
|
||||||
if not has_any:
|
|
||||||
raise Exception('invalid bug specifier \"%s\": contains no bugs' % obz)
|
|
||||||
return result_man2, no_bz_skipped
|
|
||||||
def _parse_bzlist(self, bzlist, no_bz=None):
|
def _parse_bzlist(self, bzlist, no_bz=None):
|
||||||
i = 0
|
i = 0
|
||||||
result_man = []
|
result_man = []
|
||||||
no_bz_skipped = []
|
no_bz_skipped = []
|
||||||
for obz in (bzlist if bzlist else []):
|
for obz in (bzlist if bzlist else []):
|
||||||
result_man2, no_bz_skipped2 = self._parse_bz(obz, no_bz)
|
result_man2, no_bz_skipped2 = BzInfo.parse_bz(obz, no_bz)
|
||||||
result_man.append(UtilParseCommitMessage('bz:\"%s\"' % obz, result_man2, git_backend=False, commit_date=-1000+i))
|
result_man.append(UtilParseCommitMessage('bz:\"%s\"' % obz, result_man2, git_backend=False, commit_date=-1000+i))
|
||||||
no_bz_skipped.extend(no_bz_skipped2)
|
no_bz_skipped.extend(no_bz_skipped2)
|
||||||
i = i + 1
|
i = i + 1
|
||||||
|
|
@ -1161,7 +1212,7 @@ class CmdParseCommitMessage(CmdBase):
|
||||||
excluded = excluded + commit_data.filter_out(filter)
|
excluded = excluded + commit_data.filter_out(filter)
|
||||||
|
|
||||||
if excluded:
|
if excluded:
|
||||||
print(" --no-bz '%s'" % ",".join([str(result) for result in excluded]))
|
print(" ~bz %s" % ",".join([str(result) for result in excluded]))
|
||||||
excluded =sorted(list(set(excluded)))
|
excluded =sorted(list(set(excluded)))
|
||||||
for result in excluded:
|
for result in excluded:
|
||||||
print(result.to_string(" ", 0, self.options.color))
|
print(result.to_string(" ", 0, self.options.color))
|
||||||
|
|
@ -1245,7 +1296,7 @@ class CmdParseCommitMessage(CmdBase):
|
||||||
printed_something = True
|
printed_something = True
|
||||||
print('=== List by BZ (%s) ===' % (len(result_bz_keys)))
|
print('=== List by BZ (%s) ===' % (len(result_bz_keys)))
|
||||||
if result_bz_keys:
|
if result_bz_keys:
|
||||||
print(" --bz '%s'" % ",".join([str(result) for result in result_bz_keys]))
|
print(" bz %s" % ",".join([str(result) for result in result_bz_keys]))
|
||||||
for result in result_bz_keys:
|
for result in result_bz_keys:
|
||||||
print(result.to_string(" ", self.options.verbose, self.options.color))
|
print(result.to_string(" ", self.options.verbose, self.options.color))
|
||||||
for commit_data in sorted(result_bz[result], key=lambda commit_data: commit_data.get_commit_date(), reverse=True):
|
for commit_data in sorted(result_bz[result], key=lambda commit_data: commit_data.get_commit_date(), reverse=True):
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue