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