# Copyright 2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 import cStringIO import datetime import getpass 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)) def get_input(prompt): return raw_input(prompt) def login(bugzilla): """Authenticate a session. """ # prompt for username user = get_input('Bugzilla Username: ') # prompt for password password = getpass.getpass() # perform login params = {} params['login'] = user params['password'] = password print 'Logging in' bugzilla.User.login(params) 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.__creation_timestamp = datetime.datetime.strptime(xml.find('creation_ts').text, '%Y-%m-%d %H:%M:%S +0000') 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 creation_timestamp(self): return self.__creation_timestamp def keywords(self): return self.__keywords def cpvs(self): assert(self.__cpvs_detected) return self.__cpvs