| 1 | #!/usr/bin/python |
|---|
| 2 | # -*- coding: utf-8 -*- |
|---|
| 3 | |
|---|
| 4 | import gtk, gobject |
|---|
| 5 | import urllib, re, xml.dom.minidom, csv, urlparse |
|---|
| 6 | import bug |
|---|
| 7 | import BeautifulSoup |
|---|
| 8 | |
|---|
| 9 | Bug = bug.bug |
|---|
| 10 | Comment = bug.comment |
|---|
| 11 | |
|---|
| 12 | class protocol: |
|---|
| 13 | @staticmethod |
|---|
| 14 | def Name(): |
|---|
| 15 | return "Bugzilla" |
|---|
| 16 | |
|---|
| 17 | def __init__(self, account): |
|---|
| 18 | self.account = account |
|---|
| 19 | |
|---|
| 20 | def getBugUrl(self,nbr): |
|---|
| 21 | return self.__url('show_bug.cgi', id=nbr) |
|---|
| 22 | |
|---|
| 23 | def btsName(self): |
|---|
| 24 | return urlparse.urlsplit(self.account.url)[1] |
|---|
| 25 | |
|---|
| 26 | def retrieveBug(self,nbr): |
|---|
| 27 | """ Get bug #nbr """ |
|---|
| 28 | def tagval(parent,tag): |
|---|
| 29 | return parent.getElementsByTagName(tag)[0].firstChild.nodeValue |
|---|
| 30 | |
|---|
| 31 | fd = urllib.urlopen(self.__url('show_bug.cgi', id=nbr, ctype='xml')) |
|---|
| 32 | xbug = xml.dom.minidom.parse(fd).getElementsByTagName('bug')[0] |
|---|
| 33 | if xbug.getAttribute('error'): |
|---|
| 34 | return Bug(-1) |
|---|
| 35 | bug = Bug(nbr) |
|---|
| 36 | |
|---|
| 37 | comments = xbug.getElementsByTagName('long_desc') |
|---|
| 38 | bug.setPackage(tagval(xbug, 'product')) |
|---|
| 39 | bug.setTitle(tagval(xbug, 'short_desc')) |
|---|
| 40 | bug.setDescription(tagval(comments[0], 'thetext')) |
|---|
| 41 | bug.setStatus(tagval(xbug, 'bug_status')) |
|---|
| 42 | bug.setImportance(tagval(xbug, 'bug_severity')) |
|---|
| 43 | bug.setAssignee(tagval(xbug, 'assigned_to')) |
|---|
| 44 | bug.setCommentable(False) # fixme ! |
|---|
| 45 | |
|---|
| 46 | for i, comment in enumerate(comments[1:]): |
|---|
| 47 | c_content = tagval(comment, 'thetext') |
|---|
| 48 | c_number = i+1 |
|---|
| 49 | c_author = tagval(comment, 'who') |
|---|
| 50 | c_date = tagval(comment, 'bug_when') |
|---|
| 51 | |
|---|
| 52 | bug.addComment(Comment(c_number, c_content, c_author, "", c_date)) |
|---|
| 53 | |
|---|
| 54 | return bug |
|---|
| 55 | |
|---|
| 56 | def genericSearch(self, string): |
|---|
| 57 | """ Search for a string """ |
|---|
| 58 | return self.__searchResults(query=string, quicksearch=string) |
|---|
| 59 | |
|---|
| 60 | def packageSearch(self, pkg, string): |
|---|
| 61 | """ Search for a string, but only for bug of package "pkg" |
|---|
| 62 | Well, sin't meaningful for Gentoo BTS ;) """ |
|---|
| 63 | return self.__searchResults(product=pkg, content=string, bug_status='__open__') |
|---|
| 64 | |
|---|
| 65 | def packageExist(self, pkg): |
|---|
| 66 | return False |
|---|
| 67 | #fixme! |
|---|
| 68 | potage = BeautifulSoup.BeautifulSoup(urllib.urlopen(self.__url('query.cgi', format="specific"))) |
|---|
| 69 | products = potage.find('select', id='product').findAll('option') |
|---|
| 70 | print [p.string.strip() for p in products] |
|---|
| 71 | return pkg in products |
|---|
| 72 | |
|---|
| 73 | def advancedSearch(self, pkg): |
|---|
| 74 | # fixme ! |
|---|
| 75 | pass |
|---|
| 76 | |
|---|
| 77 | def __searchResults(self, **kwargs): |
|---|
| 78 | url = self.__url('buglist.cgi', ctype='csv', **kwargs) |
|---|
| 79 | data = urllib.urlopen(url) |
|---|
| 80 | fmt = [x.replace('"', '').strip() for x in data.readline().split(',')] |
|---|
| 81 | indexes = (fmt.index('bug_id'), fmt.index('short_short_desc'), fmt.index('bug_severity'), fmt.index('bug_status')) |
|---|
| 82 | bugs = self.__newResult() |
|---|
| 83 | for bug in csv.reader(data, quoting=csv.QUOTE_NONNUMERIC): |
|---|
| 84 | bugs.append((int(bug[indexes[0]]), '', bug[indexes[1]], bug[indexes[2]], bug[indexes[3]])) |
|---|
| 85 | return bugs |
|---|
| 86 | |
|---|
| 87 | def __newResult(self) : |
|---|
| 88 | #private function to create a new result gtk.ListStore |
|---|
| 89 | # Bug id, package, title, importance, status |
|---|
| 90 | return gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING) |
|---|
| 91 | |
|---|
| 92 | def __url(self, base, **qs): |
|---|
| 93 | root = self.account.url |
|---|
| 94 | if not root.startswith('http://') and not root.startswith('https://'): |
|---|
| 95 | root = 'http://' + root |
|---|
| 96 | if not root.endswith('/'): |
|---|
| 97 | root += '/' |
|---|
| 98 | s_qs = urllib.urlencode(qs) |
|---|
| 99 | if s_qs: |
|---|
| 100 | s_qs = '?' + s_qs |
|---|
| 101 | return root + base + s_qs |
|---|
| 102 | |
|---|
| 103 | def availableStatus(self): |
|---|
| 104 | return ('UNCONFIRMED', 'NEW', 'ASSIGNED', 'REOPENED', 'RESOLVED', 'VERIFIED', 'CLOSED') |
|---|
| 105 | |
|---|
| 106 | def availableImportance(self): |
|---|
| 107 | return ('Blocker', 'Critical', 'Major', 'Minor', 'Trivial', 'Enhancement') |
|---|