#!/usr/bin/env python # -*- coding: utf-8 -*- """Methods for reporting bugs.""" import subprocess, sys, os __all__ = ["ReportFailure", "BugReport", "getReporters"] # class ReportFailure(Exception): """Generic exception for failures in bug reporting.""" def __init__(self, value): self.value = value # Collect information about a bug. class BugReport(object): def __init__(self, title, description, files): self.title = title self.description = description self.files = files # Reporter interfaces. import os import email, mimetypes, smtplib from email import encoders from email.message import Message from email.mime.base import MIMEBase from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText # ===------------------------------------------------------------------------===# # ReporterParameter # ===------------------------------------------------------------------------===# class ReporterParameter(object): def __init__(self, n): self.name = n def getName(self): return self.name def getValue(self, r, bugtype, getConfigOption): return getConfigOption(r.getName(), self.getName()) def saveConfigValue(self): return True class TextParameter(ReporterParameter): def getHTML(self, r, bugtype, getConfigOption): return """\ %s: """ % ( self.getName(), r.getName(), self.getName(), self.getValue(r, bugtype, getConfigOption), ) class SelectionParameter(ReporterParameter): def __init__(self, n, values): ReporterParameter.__init__(self, n) self.values = values def getHTML(self, r, bugtype, getConfigOption): default = self.getValue(r, bugtype, getConfigOption) return """\ %s:""" % ( self.getName(), r.getName(), self.getName(), "\n".join( [ """\ """ % (o[0], o[0] == default and ' selected="selected"' or "", o[1]) for o in self.values ] ), ) # ===------------------------------------------------------------------------===# # Reporters # ===------------------------------------------------------------------------===# class EmailReporter(object): def getName(self): return "Email" def getParameters(self): return [TextParameter(x) for x in ["To", "From", "SMTP Server", "SMTP Port"]] # Lifted from python email module examples. def attachFile(self, outer, path): # Guess the content type based on the file's extension. Encoding # will be ignored, although we should check for simple things like # gzip'd or compressed files. ctype, encoding = mimetypes.guess_type(path) if ctype is None or encoding is not None: # No guess could be made, or the file is encoded (compressed), so # use a generic bag-of-bits type. ctype = "application/octet-stream" maintype, subtype = ctype.split("/", 1) if maintype == "text": fp = open(path) # Note: we should handle calculating the charset msg = MIMEText(fp.read(), _subtype=subtype) fp.close() else: fp = open(path, "rb") msg = MIMEBase(maintype, subtype) msg.set_payload(fp.read()) fp.close() # Encode the payload using Base64 encoders.encode_base64(msg) # Set the filename parameter msg.add_header( "Content-Disposition", "attachment", filename=os.path.basename(path) ) outer.attach(msg) def fileReport(self, report, parameters): mainMsg = """\ BUG REPORT --- Title: %s Description: %s """ % ( report.title, report.description, ) if not parameters.get("To"): raise ReportFailure('No "To" address specified.') if not parameters.get("From"): raise ReportFailure('No "From" address specified.') msg = MIMEMultipart() msg["Subject"] = "BUG REPORT: %s" % (report.title) # FIXME: Get config parameters msg["To"] = parameters.get("To") msg["From"] = parameters.get("From") msg.preamble = mainMsg msg.attach(MIMEText(mainMsg, _subtype="text/plain")) for file in report.files: self.attachFile(msg, file) try: s = smtplib.SMTP( host=parameters.get("SMTP Server"), port=parameters.get("SMTP Port") ) s.sendmail(msg["From"], msg["To"], msg.as_string()) s.close() except: raise ReportFailure("Unable to send message via SMTP.") return "Message sent!" class BugzillaReporter(object): def getName(self): return "Bugzilla" def getParameters(self): return [TextParameter(x) for x in ["URL", "Product"]] def fileReport(self, report, parameters): raise NotImplementedError class RadarClassificationParameter(SelectionParameter): def __init__(self): SelectionParameter.__init__( self, "Classification", [ ["1", "Security"], ["2", "Crash/Hang/Data Loss"], ["3", "Performance"], ["4", "UI/Usability"], ["6", "Serious Bug"], ["7", "Other"], ], ) def saveConfigValue(self): return False def getValue(self, r, bugtype, getConfigOption): if bugtype.find("leak") != -1: return "3" elif bugtype.find("dereference") != -1: return "2" elif bugtype.find("missing ivar release") != -1: return "3" else: return "7" ### def getReporters(): reporters = [] reporters.append(EmailReporter()) return reporters