DbLookups.py revision 2f54b716e4d3cb0dc99066638fed631e3cbec97c
#! /usr/bin/python
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
#
# Copyright 2010, Richard Lowe
#
# Various database lookup classes/methods, i.e.:
# * monaco
# * bugs.opensolaris.org (b.o.o.)
# * redmine (illumos.org)
#
import htmllib
import re
import urllib
import urllib2
try: # Python >= 2.5
from xml.etree import ElementTree
except ImportError:
from elementtree import ElementTree
class NonExistentBug(Exception):
def __str__(self):
return "Bug %s does not exist" % (Exception.__str__(self))
class BugDBException(Exception):
def __str__(self):
return "Unknown bug database: %s" % (Exception.__str__(self))
class BugDB(object):
"""Lookup change requests.
Usage:
bdb = BugDB()
r = bdb.lookup("6455550")
print r["6455550"]["synopsis"]
r = bdb.lookup(["6455550", "6505625"])
print r["6505625"]["synopsis"]
"""
VALID_DBS = ["bugster", "illumos"]
def __init__(self, priority = ("illumos", "bugster")):
"""Create a BugDB object.
Keyword argument:
priority: use bug databases in this order
"""
for database in priority:
if database not in self.VALID_DBS:
raise BugDBException, database
self.__priority = priority
def __illbug(self, cr):
url = "http://illumos.org/issues/%s.xml" % cr
req = urllib2.Request(url)
try:
data = urllib2.urlopen(req)
except urllib2.HTTPError, e:
if e.code == 404:
raise NonExistentBug(cr)
else:
raise
bug = ElementTree.parse(data)
return {'cr_number': bug.find('id').text,
'synopsis': bug.find('subject').text,
'status': bug.find('status').attrib['name']
}
def __boobug(self, cr):
cr = str(cr)
url = "http://bugs.opensolaris.org/view_bug.do"
req = urllib2.Request(url, urllib.urlencode({"bug_id": cr}))
results = {}
try:
data = urllib2.urlopen(req).readlines()
except urllib2.HTTPError, e:
if e.code != 404:
print "ERROR: HTTP error at " + \
req.get_full_url() + \
" got error: " + str(e.code)
raise e
else:
raise NonExistentBug(cr)
except urllib2.URLError, e:
print "ERROR: could not connect to " + \
req.get_full_url() + \
' got error: "' + e.reason[1] + '"'
raise e
htmlParser = htmllib.HTMLParser(None)
metaHtmlRe = re.compile(r'^<meta name="([^"]+)" content="([^"]*)">$')
for line in data:
m = metaHtmlRe.search(line)
if not m:
continue
val = urllib.unquote(m.group(2))
htmlParser.save_bgn()
htmlParser.feed(val)
results[m.group(1)] = htmlParser.save_end()
htmlParser.close()
if "synopsis" not in results:
raise NonExistentBug(cr)
results["cr_number"] = cr
results["sub_category"] = results.pop("subcategory")
results["status"] = results.pop("state")
results["date_submitted"] = results.pop("submit_date")
return results
def lookup(self, crs):
"""Return all info for requested change reports.
Argument:
crs: one change request id (may be integer, string, or list),
or multiple change request ids (must be a list)
Returns:
Dictionary, mapping CR=>dictionary, where the nested dictionary
is a mapping of field=>value
"""
results = {}
if not isinstance(crs, list):
crs = [str(crs)]
for database in self.__priority:
if database == "bugster":
for cr in crs:
cr = str(cr)
try:
results[cr] = self.__boobug(cr)
except NonExistentBug:
continue
elif database == "illumos":
for cr in crs:
try:
results[str(cr)] = self.__illbug(cr)
except NonExistentBug:
continue
# the CR has already been found by one bug database
# so don't bother looking it up in the others
for cr in crs:
if cr in results:
crs.remove(cr)
return results