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# Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
29
30#
31# Various database lookup classes/methods, i.e.:
32#     * monaco
33#     * bugs.opensolaris.org (b.o.o.)
34#     * redmine (illumos.org)
35#
36
37import re
38try:
39	from urllib.request import urlopen, Request
40	from urllib.error import HTTPError
41except ImportError:
42	# Python 2
43	from urllib2 import Request, urlopen, HTTPError
44
45try:				# Python >= 2.5
46	from xml.etree import ElementTree
47except ImportError:
48	from elementtree import ElementTree
49
50class NonExistentBug(Exception):
51	def __str__(self):
52		return "Bug %s does not exist" % (Exception.__str__(self))
53
54class BugDBException(Exception):
55	def __str__(self):
56		return "Unknown bug database: %s" % (Exception.__str__(self))
57
58class BugDB(object):
59	"""Lookup change requests.
60
61	Usage:
62	bdb = BugDB()
63	r = bdb.lookup("6455550")
64	print r["6455550"]["synopsis"]
65	r = bdb.lookup(["6455550", "6505625"])
66	print r["6505625"]["synopsis"]
67	"""
68
69	VALID_DBS = ["illumos"]
70
71	def __init__(self, priority = ["illumos"]):
72		"""Create a BugDB object.
73
74		Keyword argument:
75		priority: use bug databases in this order
76		"""
77		for database in priority:
78			if database not in self.VALID_DBS:
79				raise BugDBException(database)
80		self.__priority = priority
81
82
83	def __illbug(self, cr):
84		url = "http://illumos.org/issues/%s.xml" % cr
85		req = Request(url)
86
87		try:
88			data = urlopen(req)
89		except HTTPError as e:
90			if e.code == 401 or e.code == 404:
91				raise NonExistentBug(cr)
92			else:
93				raise
94
95		bug = ElementTree.parse(data)
96
97		return {'cr_number': bug.find('id').text,
98			'synopsis': bug.find('subject').text,
99			'status': bug.find('status').attrib['name']
100		}
101
102
103	def lookup(self, crs):
104		"""Return all info for requested change reports.
105
106		Argument:
107		crs: one change request id (may be integer, string, or list),
108		     or multiple change request ids (must be a list)
109
110		Returns:
111		Dictionary, mapping CR=>dictionary, where the nested dictionary
112		is a mapping of field=>value
113		"""
114		results = {}
115		if not isinstance(crs, list):
116			crs = [str(crs)]
117		for database in self.__priority:
118			if database == "illumos":
119				for cr in crs:
120					try:
121						results[str(cr)] = self.__illbug(cr)
122					except NonExistentBug:
123						continue
124
125			# the CR has already been found by one bug database
126			# so don't bother looking it up in the others
127			for cr in crs:
128				if cr in results:
129					crs.remove(cr)
130
131		return results
132