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 272f54b716SRichard Lowe# Copyright 2010, Richard Lowe 28*93be19b9SAndy Fiddaman# Copyright 2018 OmniOS Community Edition (OmniOSce) Association. 292f54b716SRichard Lowe 30cdf0c1d5Smjnelson# 31cdf0c1d5Smjnelson# Various database lookup classes/methods, i.e.: 32cdf0c1d5Smjnelson# * monaco 33cdf0c1d5Smjnelson# * bugs.opensolaris.org (b.o.o.) 342f54b716SRichard Lowe# * redmine (illumos.org) 35cdf0c1d5Smjnelson# 36cdf0c1d5Smjnelson 37cdf0c1d5Smjnelsonimport re 38*93be19b9SAndy Fiddamantry: 39*93be19b9SAndy Fiddaman from urllib.request import urlopen, Request 40*93be19b9SAndy Fiddaman from urllib.error import HTTPError 41*93be19b9SAndy Fiddamanexcept ImportError: 42*93be19b9SAndy Fiddaman # Python 2 43*93be19b9SAndy Fiddaman from urllib2 import Request, urlopen, HTTPError 44cdf0c1d5Smjnelson 452f54b716SRichard Lowetry: # Python >= 2.5 462f54b716SRichard Lowe from xml.etree import ElementTree 472f54b716SRichard Loweexcept ImportError: 482f54b716SRichard Lowe from elementtree import ElementTree 49cdf0c1d5Smjnelson 5041a5f560SMark J. Nelsonclass NonExistentBug(Exception): 51cdf0c1d5Smjnelson def __str__(self): 5241a5f560SMark J. Nelson return "Bug %s does not exist" % (Exception.__str__(self)) 53cdf0c1d5Smjnelson 54c08a253cSJohn Sonnenscheinclass BugDBException(Exception): 55c08a253cSJohn Sonnenschein def __str__(self): 5641a5f560SMark J. Nelson return "Unknown bug database: %s" % (Exception.__str__(self)) 57cdf0c1d5Smjnelson 58cdf0c1d5Smjnelsonclass BugDB(object): 59cdf0c1d5Smjnelson """Lookup change requests. 60cdf0c1d5Smjnelson 61cdf0c1d5Smjnelson Usage: 62cdf0c1d5Smjnelson bdb = BugDB() 63cdf0c1d5Smjnelson r = bdb.lookup("6455550") 64cdf0c1d5Smjnelson print r["6455550"]["synopsis"] 65cdf0c1d5Smjnelson r = bdb.lookup(["6455550", "6505625"]) 66cdf0c1d5Smjnelson print r["6505625"]["synopsis"] 67cdf0c1d5Smjnelson """ 68cdf0c1d5Smjnelson 6937cc68d4SJoshua M. Clulow VALID_DBS = ["illumos"] 702f54b716SRichard Lowe 7137cc68d4SJoshua M. Clulow def __init__(self, priority = ["illumos"]): 72cdf0c1d5Smjnelson """Create a BugDB object. 73cdf0c1d5Smjnelson 74cdf0c1d5Smjnelson Keyword argument: 75c08a253cSJohn Sonnenschein priority: use bug databases in this order 76cdf0c1d5Smjnelson """ 77c08a253cSJohn Sonnenschein for database in priority: 782f54b716SRichard Lowe if database not in self.VALID_DBS: 79*93be19b9SAndy Fiddaman raise BugDBException(database) 80c08a253cSJohn Sonnenschein self.__priority = priority 81c08a253cSJohn Sonnenschein 82c08a253cSJohn Sonnenschein 832f54b716SRichard Lowe def __illbug(self, cr): 842f54b716SRichard Lowe url = "http://illumos.org/issues/%s.xml" % cr 85*93be19b9SAndy Fiddaman req = Request(url) 862f54b716SRichard Lowe 872f54b716SRichard Lowe try: 88*93be19b9SAndy Fiddaman data = urlopen(req) 89*93be19b9SAndy Fiddaman except HTTPError as e: 902f54b716SRichard Lowe if e.code == 404: 912f54b716SRichard Lowe raise NonExistentBug(cr) 922f54b716SRichard Lowe else: 932f54b716SRichard Lowe raise 942f54b716SRichard Lowe 952f54b716SRichard Lowe bug = ElementTree.parse(data) 962f54b716SRichard Lowe 972f54b716SRichard Lowe return {'cr_number': bug.find('id').text, 982f54b716SRichard Lowe 'synopsis': bug.find('subject').text, 992f54b716SRichard Lowe 'status': bug.find('status').attrib['name'] 1002f54b716SRichard Lowe } 1012f54b716SRichard Lowe 1022f54b716SRichard Lowe 103cdf0c1d5Smjnelson def lookup(self, crs): 104cdf0c1d5Smjnelson """Return all info for requested change reports. 105cdf0c1d5Smjnelson 106cdf0c1d5Smjnelson Argument: 107cdf0c1d5Smjnelson crs: one change request id (may be integer, string, or list), 108cdf0c1d5Smjnelson or multiple change request ids (must be a list) 109cdf0c1d5Smjnelson 110cdf0c1d5Smjnelson Returns: 111cdf0c1d5Smjnelson Dictionary, mapping CR=>dictionary, where the nested dictionary 112cdf0c1d5Smjnelson is a mapping of field=>value 113cdf0c1d5Smjnelson """ 114c08a253cSJohn Sonnenschein results = {} 115cdf0c1d5Smjnelson if not isinstance(crs, list): 116cdf0c1d5Smjnelson crs = [str(crs)] 117c08a253cSJohn Sonnenschein for database in self.__priority: 11837cc68d4SJoshua M. Clulow if database == "illumos": 1192f54b716SRichard Lowe for cr in crs: 1202f54b716SRichard Lowe try: 1212f54b716SRichard Lowe results[str(cr)] = self.__illbug(cr) 1222f54b716SRichard Lowe except NonExistentBug: 1232f54b716SRichard Lowe continue 124cdf0c1d5Smjnelson 125c08a253cSJohn Sonnenschein # the CR has already been found by one bug database 126c08a253cSJohn Sonnenschein # so don't bother looking it up in the others 127c08a253cSJohn Sonnenschein for cr in crs: 128c08a253cSJohn Sonnenschein if cr in results: 129c08a253cSJohn Sonnenschein crs.remove(cr) 130cdf0c1d5Smjnelson 131cdf0c1d5Smjnelson return results 132