xref: /illumos-gate/usr/src/tools/onbld/Checks/DbLookups.py (revision e0731422366620894c16c1ee6515551c5f00733d)
1#! /usr/bin/python
2#
3# CDDL HEADER START
4#
5# The contents of this file are subject to the terms of the
6# Common Development and Distribution License (the "License").
7# You may not use this file except in compliance with the License.
8#
9# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10# or http://www.opensolaris.org/os/licensing.
11# See the License for the specific language governing permissions
12# and limitations under the License.
13#
14# When distributing Covered Code, include this CDDL HEADER in each
15# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16# If applicable, add the following below this CDDL HEADER, with the
17# fields enclosed by brackets "[]" replaced with your own identifying
18# information: Portions Copyright [yyyy] [name of copyright owner]
19#
20# CDDL HEADER END
21#
22
23#
24# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
25#
26
27# Copyright 2010, Richard Lowe
28
29#
30# Various database lookup classes/methods, i.e.:
31#     * monaco
32#     * bugs.opensolaris.org (b.o.o.)
33#     * redmine (illumos.org)
34#
35
36import htmllib
37import re
38import urllib
39import urllib2
40
41try:				# Python >= 2.5
42	from xml.etree import ElementTree
43except ImportError:
44	from elementtree import ElementTree
45
46class NonExistentBug(Exception):
47	def __str__(self):
48		return "Bug %s does not exist" % (Exception.__str__(self))
49
50class BugDBException(Exception):
51	def __str__(self):
52		return "Unknown bug database: %s" % (Exception.__str__(self))
53
54class BugDB(object):
55	"""Lookup change requests.
56
57	Usage:
58	bdb = BugDB()
59	r = bdb.lookup("6455550")
60	print r["6455550"]["synopsis"]
61	r = bdb.lookup(["6455550", "6505625"])
62	print r["6505625"]["synopsis"]
63	"""
64
65 	VALID_DBS = ["bugster", "illumos"]
66
67	def __init__(self, priority = ("illumos", "bugster")):
68		"""Create a BugDB object.
69
70		Keyword argument:
71		priority: use bug databases in this order
72		"""
73		for database in priority:
74			if database not in self.VALID_DBS:
75				raise BugDBException, database
76		self.__priority = priority
77
78
79	def __illbug(self, cr):
80		url = "http://illumos.org/issues/%s.xml" % cr
81		req = urllib2.Request(url)
82
83		try:
84			data = urllib2.urlopen(req)
85		except urllib2.HTTPError, e:
86			if e.code == 404:
87				raise NonExistentBug(cr)
88			else:
89				raise
90
91		bug = ElementTree.parse(data)
92
93		return {'cr_number': bug.find('id').text,
94			'synopsis': bug.find('subject').text,
95			'status': bug.find('status').attrib['name']
96		}
97
98
99	def __boobug(self, cr):
100		cr = str(cr)
101		url = "http://bugs.opensolaris.org/view_bug.do"
102   		req = urllib2.Request(url, urllib.urlencode({"bug_id": cr}))
103		results = {}
104		try:
105			data = urllib2.urlopen(req).readlines()
106		except urllib2.HTTPError, e:
107			if e.code != 404:
108				print "ERROR: HTTP error at " + \
109					req.get_full_url() + \
110					" got error: " + str(e.code)
111				raise e
112			else:
113				raise NonExistentBug(cr)
114		except urllib2.URLError, e:
115			print "ERROR: could not connect to " + \
116				req.get_full_url() + \
117				' got error: "' + e.reason[1] + '"'
118			raise e
119		htmlParser = htmllib.HTMLParser(None)
120		metaHtmlRe = re.compile(r'^<meta name="([^"]+)" content="([^"]*)">$')
121		for line in data:
122			m = metaHtmlRe.search(line)
123			if not m:
124				continue
125			val = urllib.unquote(m.group(2))
126			htmlParser.save_bgn()
127			htmlParser.feed(val)
128			results[m.group(1)] = htmlParser.save_end()
129		htmlParser.close()
130
131		if "synopsis" not in results:
132			raise NonExistentBug(cr)
133
134		results["cr_number"] = cr
135		results["sub_category"] = results.pop("subcategory")
136		results["status"] = results.pop("state")
137		results["date_submitted"] = results.pop("submit_date")
138
139		return results
140
141	def lookup(self, crs):
142		"""Return all info for requested change reports.
143
144		Argument:
145		crs: one change request id (may be integer, string, or list),
146		     or multiple change request ids (must be a list)
147
148		Returns:
149		Dictionary, mapping CR=>dictionary, where the nested dictionary
150		is a mapping of field=>value
151		"""
152		results = {}
153		if not isinstance(crs, list):
154			crs = [str(crs)]
155		for database in self.__priority:
156			if database == "bugster":
157				for cr in crs:
158					cr = str(cr)
159					try:
160						results[cr] = self.__boobug(cr)
161					except NonExistentBug:
162						continue
163			elif database == "illumos":
164				for cr in crs:
165					try:
166						results[str(cr)] = self.__illbug(cr)
167					except NonExistentBug:
168						continue
169
170			# the CR has already been found by one bug database
171			# so don't bother looking it up in the others
172			for cr in crs:
173				if cr in results:
174					crs.remove(cr)
175
176		return results
177