From 8aff939c6831ac73eb6a6a4a07a6c475e15ed308 Mon Sep 17 00:00:00 2001 From: "Pawel Hajdan, Jr" Date: Fri, 27 Jan 2012 15:54:19 +0100 Subject: Begin work on maintainer-timeout script. Extract common parts to common.py Fix bug where only first 100 bug details were retrieved from Bugzilla. --- .gitignore | 1 + bugzilla-viewer.py | 77 ++-------------------------------- common.py | 100 ++++++++++++++++++++++++++++++++++++++++++++ maintainer-timeout.py | 51 ++++++++++++++++++++++ stabilization-candidates.py | 8 +++- 5 files changed, 162 insertions(+), 75 deletions(-) create mode 100644 .gitignore create mode 100644 common.py create mode 100755 maintainer-timeout.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0d20b64 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/bugzilla-viewer.py b/bugzilla-viewer.py index e3cbcac..8a1e131 100755 --- a/bugzilla-viewer.py +++ b/bugzilla-viewer.py @@ -15,32 +15,7 @@ import xml.etree import bugz.bugzilla import portage.versions -CPV_REGEX = re.compile("[A-Za-z0-9+_.-]+/[A-Za-z0-9+_-]+-[0-9]+(?:\.[0-9]+)*[a-z0-9_]*(?:-r[0-9]+)?") - -# Snippet from http://bugs.python.org/issue9584 -def expand_braces(orig): - r = r'.*(\{.+?[^\\]\})' - p = re.compile(r) - - s = orig[:] - res = list() - - m = p.search(s) - if m is not None: - sub = m.group(1) - open_brace = s.find(sub) - close_brace = open_brace + len(sub) - 1 - if ',' in sub: - for pat in sub.strip('{}').split(','): - res.extend(expand_braces(s[:open_brace] + pat + s[close_brace+1:])) - - else: - res.extend(expand_braces(s[:open_brace] + sub.replace('}', '\\}') + s[close_brace+1:])) - - else: - res.append(s.replace('\\}', '}')) - - return list(set(res)) +from common import Bug, chunks def unicode_sanitize(text): """Converts a possibly unicode text to a regular string.""" @@ -53,52 +28,6 @@ def unicode_sanitize(text): class TermTooSmall(Exception): pass -class Bug: - def __init__(self, xml=None, id_number=None, summary=None, status=None): - if xml is not None: - self.__id = int(xml.find("bug_id").text) - self.__summary = xml.find("short_desc").text - self.__status = xml.find("bug_status").text - self.__depends_on = [int(dep.text) for dep in xml.findall("dependson")] - self.__comments = [c.find("who").text + "\n" + c.find("thetext").text for c in xml.findall("long_desc")] - if id_number is not None: - self.__id = id_number - if summary is not None: - self.__summary = summary - if status is not None: - self.__status = status - self.__cpvs_detected = False - self.__cpvs = [] - - def detect_cpvs(self): - if self.__cpvs_detected: - return - for cpv_string in list(set([self.summary()] + expand_braces(self.summary()))): - for cpv_candidate in CPV_REGEX.findall(cpv_string): - if portage.db["/"]["porttree"].dbapi.cpv_exists(cpv_candidate): - self.__cpvs.append(cpv_candidate) - self.__cpvs = list(set(self.__cpvs)) - self.__cpvs_detected = True - - def id_number(self): - return self.__id - - def summary(self): - return self.__summary - - def status(self): - return self.__status - - def depends_on(self): - return self.__depends_on - - def comments(self): - return self.__comments - - def cpvs(self): - assert(self.__cpvs_detected) - return self.__cpvs - class BugQueue: def __init__(self): self.__bug_list = [] @@ -320,8 +249,10 @@ if __name__ == "__main__": } if options.security: criteria['assigned_to'] = 'security@gentoo.org' + bugs = [] raw_bugs = bugzilla.search("", **criteria) - bugs = [Bug(xml) for xml in bugzilla.get([bug['bugid'] for bug in raw_bugs]).findall("bug")] + for chunk in chunks(raw_bugs, 100): + bugs += [Bug(xml) for xml in bugzilla.get([bug['bugid'] for bug in chunk]).findall("bug")] if not bugs: print 'The bug list is empty. Exiting.' diff --git a/common.py b/common.py new file mode 100644 index 0000000..d6841fb --- /dev/null +++ b/common.py @@ -0,0 +1,100 @@ +# Copyright 2012 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 + +import cStringIO +import re + +import portage + + +CPV_REGEX = re.compile("[A-Za-z0-9+_.-]+/[A-Za-z0-9+_-]+-[0-9]+(?:\.[0-9]+)*[a-z0-9_]*(?:-r[0-9]+)?") + + +def chunks(iterable, length): + for i in range(0, len(iterable), length): + yield iterable[i:i + length] + + +# Snippet from http://bugs.python.org/issue9584 +def expand_braces(orig): + r = r'.*(\{.+?[^\\]\})' + p = re.compile(r) + + s = orig[:] + res = list() + + m = p.search(s) + if m is not None: + sub = m.group(1) + open_brace = s.find(sub) + close_brace = open_brace + len(sub) - 1 + if ',' in sub: + for pat in sub.strip('{}').split(','): + res.extend(expand_braces(s[:open_brace] + pat + s[close_brace+1:])) + + else: + res.extend(expand_braces(s[:open_brace] + sub.replace('}', '\\}') + s[close_brace+1:])) + + else: + res.append(s.replace('\\}', '}')) + + return list(set(res)) + + +class Bug: + def __init__(self, xml=None, id_number=None, summary=None, status=None): + if xml is not None: + self.__id = int(xml.find("bug_id").text) + self.__summary = xml.find("short_desc").text + self.__status = xml.find("bug_status").text + self.__depends_on = [int(dep.text) for dep in xml.findall("dependson")] + self.__comments = [c.find("who").text + "\n" + c.find("thetext").text for c in xml.findall("long_desc")] + self.__cc = [cc.text for cc in xml.findall("cc")] + + self.__keywords = [] + keywords_elem = xml.find("keywords") + if keywords_elem is not None and keywords_elem.text: + self.__keywords = [k.strip() for k in keywords_elem.text.split(",")] + if id_number is not None: + self.__id = id_number + if summary is not None: + self.__summary = summary + if status is not None: + self.__status = status + self.__cpvs_detected = False + self.__cpvs = [] + + def detect_cpvs(self): + if self.__cpvs_detected: + return + for cpv_string in list(set([self.summary()] + expand_braces(self.summary()))): + for cpv_candidate in CPV_REGEX.findall(cpv_string): + if portage.db["/"]["porttree"].dbapi.cpv_exists(cpv_candidate): + self.__cpvs.append(cpv_candidate) + self.__cpvs = list(set(self.__cpvs)) + self.__cpvs_detected = True + + def id_number(self): + return self.__id + + def summary(self): + return self.__summary + + def status(self): + return self.__status + + def depends_on(self): + return self.__depends_on + + def comments(self): + return self.__comments + + def cc(self): + return self.__cc + + def keywords(self): + return self.__keywords + + def cpvs(self): + assert(self.__cpvs_detected) + return self.__cpvs diff --git a/maintainer-timeout.py b/maintainer-timeout.py new file mode 100755 index 0000000..c75edd6 --- /dev/null +++ b/maintainer-timeout.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +# Copyright 2012 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 + +import optparse + +import bugz.bugzilla +import portage.versions + +from common import Bug, chunks + + +class MyBugz(bugz.bugzilla.Bugz): + def get_input(self, prompt): + return raw_input(prompt) + + +if __name__ == "__main__": + parser = optparse.OptionParser() + (options, args) = parser.parse_args() + if args: + parser.error("unrecognized command-line args") + + url = 'https://bugs.gentoo.org' + print 'You may be prompted for your Gentoo Bugzilla username and password (%s).' % url + bugzilla = MyBugz(url, forget=True) + bugzilla.auth() + + bugs = [] + raw_bugs = bugzilla.search('please stabilize', reporter=bugzilla.user, status=None) + for chunk in chunks(raw_bugs, 100): + bugs += [Bug(xml) for xml in bugzilla.get([bug['bugid'] for bug in chunk]).findall("bug")] + for bug in bugs: + if 'STABLEREQ' in bug.keywords(): + continue + arch_found = False + for arch in portage.archlist: + if '%s@gentoo.org' % arch in bug.cc(): + arch_found = True + break + if arch_found: + continue + if len(bug.comments()) > 1: + continue + bug.detect_cpvs() + if len(bug.cpvs()) != 1: + continue + cp = portage.versions.cpv_getkey(bug.cpvs()[0]) + for cpv in portage.portdb.cp_list(cp): + print portage.portdb.aux_get(cpv, ['KEYWORDS']) + print (bug.id_number(), bug.summary(), cp) diff --git a/stabilization-candidates.py b/stabilization-candidates.py index 62efa04..1a7211c 100755 --- a/stabilization-candidates.py +++ b/stabilization-candidates.py @@ -115,8 +115,12 @@ if __name__ == "__main__": ebuild_name = portage.versions.catsplit(best_candidate)[1] + ".ebuild" ebuild_path = os.path.join(cvs_path, ebuild_name) manifest_path = os.path.join(cvs_path, 'Manifest') - original_contents = open(ebuild_path).read() - manifest_contents = open(manifest_path).read() + try: + original_contents = open(ebuild_path).read() + manifest_contents = open(manifest_path).read() + except IOError, e: + print e + continue try: for arch in options.arch: subprocess.check_output(["ekeyword", arch, ebuild_name], cwd=cvs_path) -- cgit v1.2.3-65-gdbad