--- /dev/null
+# vim:set encoding=utf-8:
+###############################################################################
+# Copyright:
+# © 2006 Sanghyeon Seo <sanxiyn@gmail.com>
+# © 2006 Pierre Habouzit <madcoder@debian.org>
+# © 2007 Bernd Zeimetz <bernd@bzed.de>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+###############################################################################
+
+import urllib, urlparse, cgi, re
+
+from BeautifulSoup import BeautifulSoup
+from __init__ import *
+from base import maketoken
+
+#the status page
+MAX_BERLIOS_ID_LEN = 6
+
+def parse_table(soup, key, count):
+ #I have no damn clue why they have Status twice on their pages
+ #while Resolution is only listed once. ARGH!
+ cell = soup.fetchText(key)[count].findParent('td')
+ return cell.contents[2]
+
+def parse_status_page(soup, id):
+ #propably a weird way to add 0 in front of the number
+ id = (MAX_BERLIOS_ID_LEN - len(id)) * '0' + id
+ cell = soup.firstText(id).findParent('tr')
+ try:
+ return cell.fetchChildren()[5].string
+ except IndexError:
+ return Null
+
+gid_re = re.compile(r'.*group_id=([0-9]+).*')
+class BerliosData:
+ def __init__(self, uri, id):
+
+ self.id = id or failwith(uri, "Berlios: no id")
+
+ bugtype = uri.split('/')[3]
+ soup = BeautifulSoup(urllib.urlopen(uri))
+ if not bugtype == 'bugs':
+ self.status = parse_table(soup, 'Status:', 1)
+ self.resolution = 'Unknown'
+ else:
+ self.resolution = parse_table(soup, 'Resolution:', 0)
+ gid = gid_re.findall(uri)[0]
+ offset = 0
+
+ #berlios does not list the status for bugs on the bug's page, MEH!
+ #even worse, not all bugs are listed on the overview page...
+ while True:
+ status_uri = 'http://developer.berlios.de/bugs/index.php?func=browse&group_id=%s&set=custom&_assigned_to=0&_status=100&_category=100&_bug_group=100&offset=%s&order=bug_id' % (gid, str(offset))
+ soup = BeautifulSoup(urllib.urlopen(status_uri))
+ self.status = parse_status_page(soup, str(id))
+ if self.status:
+ break
+ #we don't want to parse ALL pages with bugs... that could be long...
+ if (not soup.firstText('Next 50 -->')) or offset >= 200:
+ break
+ offset += 50
+
+ if self.resolution == 'Duplicate':
+ raise DupeExn(uri)
+
+class RemoteBerlios(RemoteBts):
+ def __init__(self, cnf):
+ bugre = '^%%(uri)s/\\?func=detail%(bugtype)s&%(bugtype)s_id=([0-9]+)$' % \
+ {'bugtype' : cnf['bugtype']}
+ urifmt = '%%(uri)s/?func=detail%(bugtype)s&%(bugtype)s_id=%%(id)s' % \
+ {'bugtype' : cnf['bugtype']}
+ RemoteBts.__init__(self, cnf, bugre, urifmt, BerliosData)
+
+ def isClosing(self, status, resolution):
+ return resolution == 'Fixed' or status == 'Closed'
+
+ def isWontfix(self, status, resolution):
+ return status == 'Wont Fix' or status == 'Deleted' or status == 'Rejected'
+
+RemoteBts.register('berlios', RemoteBerlios)
+