xref: /llvm-project/clang/tools/scan-view/share/Reporter.py (revision dd3c26a045c081620375a878159f536758baba6e)
1e3cd3a3cSTom Stellard#!/usr/bin/env python
2e3cd3a3cSTom Stellard# -*- coding: utf-8 -*-
3e3cd3a3cSTom Stellard
4e3cd3a3cSTom Stellard"""Methods for reporting bugs."""
5e3cd3a3cSTom Stellard
6e3cd3a3cSTom Stellardimport subprocess, sys, os
7e3cd3a3cSTom Stellard
8*dd3c26a0STobias Hieta__all__ = ["ReportFailure", "BugReport", "getReporters"]
9e3cd3a3cSTom Stellard
10e3cd3a3cSTom Stellard#
11e3cd3a3cSTom Stellard
12*dd3c26a0STobias Hieta
13e3cd3a3cSTom Stellardclass ReportFailure(Exception):
14e3cd3a3cSTom Stellard    """Generic exception for failures in bug reporting."""
15*dd3c26a0STobias Hieta
16e3cd3a3cSTom Stellard    def __init__(self, value):
17e3cd3a3cSTom Stellard        self.value = value
18e3cd3a3cSTom Stellard
19*dd3c26a0STobias Hieta
20e3cd3a3cSTom Stellard# Collect information about a bug.
21e3cd3a3cSTom Stellard
22*dd3c26a0STobias Hieta
23e3cd3a3cSTom Stellardclass BugReport(object):
24e3cd3a3cSTom Stellard    def __init__(self, title, description, files):
25e3cd3a3cSTom Stellard        self.title = title
26e3cd3a3cSTom Stellard        self.description = description
27e3cd3a3cSTom Stellard        self.files = files
28e3cd3a3cSTom Stellard
29*dd3c26a0STobias Hieta
30e3cd3a3cSTom Stellard# Reporter interfaces.
31e3cd3a3cSTom Stellard
32e3cd3a3cSTom Stellardimport os
33e3cd3a3cSTom Stellard
34e3cd3a3cSTom Stellardimport email, mimetypes, smtplib
35e3cd3a3cSTom Stellardfrom email import encoders
36e3cd3a3cSTom Stellardfrom email.message import Message
37e3cd3a3cSTom Stellardfrom email.mime.base import MIMEBase
38e3cd3a3cSTom Stellardfrom email.mime.multipart import MIMEMultipart
39e3cd3a3cSTom Stellardfrom email.mime.text import MIMEText
40e3cd3a3cSTom Stellard
41e3cd3a3cSTom Stellard# ===------------------------------------------------------------------------===#
42e3cd3a3cSTom Stellard# ReporterParameter
43e3cd3a3cSTom Stellard# ===------------------------------------------------------------------------===#
44e3cd3a3cSTom Stellard
45*dd3c26a0STobias Hieta
46e3cd3a3cSTom Stellardclass ReporterParameter(object):
47e3cd3a3cSTom Stellard    def __init__(self, n):
48e3cd3a3cSTom Stellard        self.name = n
49*dd3c26a0STobias Hieta
50e3cd3a3cSTom Stellard    def getName(self):
51e3cd3a3cSTom Stellard        return self.name
52*dd3c26a0STobias Hieta
53e3cd3a3cSTom Stellard    def getValue(self, r, bugtype, getConfigOption):
54e3cd3a3cSTom Stellard        return getConfigOption(r.getName(), self.getName())
55*dd3c26a0STobias Hieta
56e3cd3a3cSTom Stellard    def saveConfigValue(self):
57e3cd3a3cSTom Stellard        return True
58e3cd3a3cSTom Stellard
59*dd3c26a0STobias Hieta
60e3cd3a3cSTom Stellardclass TextParameter(ReporterParameter):
61e3cd3a3cSTom Stellard    def getHTML(self, r, bugtype, getConfigOption):
62e3cd3a3cSTom Stellard        return """\
63e3cd3a3cSTom Stellard<tr>
64e3cd3a3cSTom Stellard<td class="form_clabel">%s:</td>
65e3cd3a3cSTom Stellard<td class="form_value"><input type="text" name="%s_%s" value="%s"></td>
66*dd3c26a0STobias Hieta</tr>""" % (
67*dd3c26a0STobias Hieta            self.getName(),
68*dd3c26a0STobias Hieta            r.getName(),
69*dd3c26a0STobias Hieta            self.getName(),
70*dd3c26a0STobias Hieta            self.getValue(r, bugtype, getConfigOption),
71*dd3c26a0STobias Hieta        )
72*dd3c26a0STobias Hieta
73e3cd3a3cSTom Stellard
74e3cd3a3cSTom Stellardclass SelectionParameter(ReporterParameter):
75e3cd3a3cSTom Stellard    def __init__(self, n, values):
76e3cd3a3cSTom Stellard        ReporterParameter.__init__(self, n)
77e3cd3a3cSTom Stellard        self.values = values
78e3cd3a3cSTom Stellard
79e3cd3a3cSTom Stellard    def getHTML(self, r, bugtype, getConfigOption):
80e3cd3a3cSTom Stellard        default = self.getValue(r, bugtype, getConfigOption)
81e3cd3a3cSTom Stellard        return """\
82e3cd3a3cSTom Stellard<tr>
83e3cd3a3cSTom Stellard<td class="form_clabel">%s:</td><td class="form_value"><select name="%s_%s">
84e3cd3a3cSTom Stellard%s
85*dd3c26a0STobias Hieta</select></td>""" % (
86*dd3c26a0STobias Hieta            self.getName(),
87*dd3c26a0STobias Hieta            r.getName(),
88*dd3c26a0STobias Hieta            self.getName(),
89*dd3c26a0STobias Hieta            "\n".join(
90*dd3c26a0STobias Hieta                [
91*dd3c26a0STobias Hieta                    """\
92*dd3c26a0STobias Hieta<option value="%s"%s>%s</option>"""
93*dd3c26a0STobias Hieta                    % (o[0], o[0] == default and ' selected="selected"' or "", o[1])
94*dd3c26a0STobias Hieta                    for o in self.values
95*dd3c26a0STobias Hieta                ]
96*dd3c26a0STobias Hieta            ),
97*dd3c26a0STobias Hieta        )
98*dd3c26a0STobias Hieta
99e3cd3a3cSTom Stellard
100e3cd3a3cSTom Stellard# ===------------------------------------------------------------------------===#
101e3cd3a3cSTom Stellard# Reporters
102e3cd3a3cSTom Stellard# ===------------------------------------------------------------------------===#
103e3cd3a3cSTom Stellard
104*dd3c26a0STobias Hieta
105e3cd3a3cSTom Stellardclass EmailReporter(object):
106e3cd3a3cSTom Stellard    def getName(self):
107*dd3c26a0STobias Hieta        return "Email"
108e3cd3a3cSTom Stellard
109e3cd3a3cSTom Stellard    def getParameters(self):
110*dd3c26a0STobias Hieta        return [TextParameter(x) for x in ["To", "From", "SMTP Server", "SMTP Port"]]
111e3cd3a3cSTom Stellard
112e3cd3a3cSTom Stellard    # Lifted from python email module examples.
113e3cd3a3cSTom Stellard    def attachFile(self, outer, path):
114e3cd3a3cSTom Stellard        # Guess the content type based on the file's extension.  Encoding
115e3cd3a3cSTom Stellard        # will be ignored, although we should check for simple things like
116e3cd3a3cSTom Stellard        # gzip'd or compressed files.
117e3cd3a3cSTom Stellard        ctype, encoding = mimetypes.guess_type(path)
118e3cd3a3cSTom Stellard        if ctype is None or encoding is not None:
119e3cd3a3cSTom Stellard            # No guess could be made, or the file is encoded (compressed), so
120e3cd3a3cSTom Stellard            # use a generic bag-of-bits type.
121*dd3c26a0STobias Hieta            ctype = "application/octet-stream"
122*dd3c26a0STobias Hieta        maintype, subtype = ctype.split("/", 1)
123*dd3c26a0STobias Hieta        if maintype == "text":
124e3cd3a3cSTom Stellard            fp = open(path)
125e3cd3a3cSTom Stellard            # Note: we should handle calculating the charset
126e3cd3a3cSTom Stellard            msg = MIMEText(fp.read(), _subtype=subtype)
127e3cd3a3cSTom Stellard            fp.close()
128e3cd3a3cSTom Stellard        else:
129*dd3c26a0STobias Hieta            fp = open(path, "rb")
130e3cd3a3cSTom Stellard            msg = MIMEBase(maintype, subtype)
131e3cd3a3cSTom Stellard            msg.set_payload(fp.read())
132e3cd3a3cSTom Stellard            fp.close()
133e3cd3a3cSTom Stellard            # Encode the payload using Base64
134e3cd3a3cSTom Stellard            encoders.encode_base64(msg)
135e3cd3a3cSTom Stellard        # Set the filename parameter
136*dd3c26a0STobias Hieta        msg.add_header(
137*dd3c26a0STobias Hieta            "Content-Disposition", "attachment", filename=os.path.basename(path)
138*dd3c26a0STobias Hieta        )
139e3cd3a3cSTom Stellard        outer.attach(msg)
140e3cd3a3cSTom Stellard
141e3cd3a3cSTom Stellard    def fileReport(self, report, parameters):
142e3cd3a3cSTom Stellard        mainMsg = """\
143e3cd3a3cSTom StellardBUG REPORT
144e3cd3a3cSTom Stellard---
145e3cd3a3cSTom StellardTitle: %s
146e3cd3a3cSTom StellardDescription: %s
147*dd3c26a0STobias Hieta""" % (
148*dd3c26a0STobias Hieta            report.title,
149*dd3c26a0STobias Hieta            report.description,
150*dd3c26a0STobias Hieta        )
151e3cd3a3cSTom Stellard
152*dd3c26a0STobias Hieta        if not parameters.get("To"):
153e3cd3a3cSTom Stellard            raise ReportFailure('No "To" address specified.')
154*dd3c26a0STobias Hieta        if not parameters.get("From"):
155e3cd3a3cSTom Stellard            raise ReportFailure('No "From" address specified.')
156e3cd3a3cSTom Stellard
157e3cd3a3cSTom Stellard        msg = MIMEMultipart()
158*dd3c26a0STobias Hieta        msg["Subject"] = "BUG REPORT: %s" % (report.title)
159e3cd3a3cSTom Stellard        # FIXME: Get config parameters
160*dd3c26a0STobias Hieta        msg["To"] = parameters.get("To")
161*dd3c26a0STobias Hieta        msg["From"] = parameters.get("From")
162e3cd3a3cSTom Stellard        msg.preamble = mainMsg
163e3cd3a3cSTom Stellard
164*dd3c26a0STobias Hieta        msg.attach(MIMEText(mainMsg, _subtype="text/plain"))
165e3cd3a3cSTom Stellard        for file in report.files:
166e3cd3a3cSTom Stellard            self.attachFile(msg, file)
167e3cd3a3cSTom Stellard
168e3cd3a3cSTom Stellard        try:
169*dd3c26a0STobias Hieta            s = smtplib.SMTP(
170*dd3c26a0STobias Hieta                host=parameters.get("SMTP Server"), port=parameters.get("SMTP Port")
171*dd3c26a0STobias Hieta            )
172*dd3c26a0STobias Hieta            s.sendmail(msg["From"], msg["To"], msg.as_string())
173e3cd3a3cSTom Stellard            s.close()
174e3cd3a3cSTom Stellard        except:
175*dd3c26a0STobias Hieta            raise ReportFailure("Unable to send message via SMTP.")
176e3cd3a3cSTom Stellard
177e3cd3a3cSTom Stellard        return "Message sent!"
178e3cd3a3cSTom Stellard
179*dd3c26a0STobias Hieta
180e3cd3a3cSTom Stellardclass BugzillaReporter(object):
181e3cd3a3cSTom Stellard    def getName(self):
182*dd3c26a0STobias Hieta        return "Bugzilla"
183e3cd3a3cSTom Stellard
184e3cd3a3cSTom Stellard    def getParameters(self):
185*dd3c26a0STobias Hieta        return [TextParameter(x) for x in ["URL", "Product"]]
186e3cd3a3cSTom Stellard
187e3cd3a3cSTom Stellard    def fileReport(self, report, parameters):
188e3cd3a3cSTom Stellard        raise NotImplementedError
189e3cd3a3cSTom Stellard
190e3cd3a3cSTom Stellard
191e3cd3a3cSTom Stellardclass RadarClassificationParameter(SelectionParameter):
192e3cd3a3cSTom Stellard    def __init__(self):
193*dd3c26a0STobias Hieta        SelectionParameter.__init__(
194*dd3c26a0STobias Hieta            self,
195*dd3c26a0STobias Hieta            "Classification",
196*dd3c26a0STobias Hieta            [
197*dd3c26a0STobias Hieta                ["1", "Security"],
198*dd3c26a0STobias Hieta                ["2", "Crash/Hang/Data Loss"],
199*dd3c26a0STobias Hieta                ["3", "Performance"],
200*dd3c26a0STobias Hieta                ["4", "UI/Usability"],
201*dd3c26a0STobias Hieta                ["6", "Serious Bug"],
202*dd3c26a0STobias Hieta                ["7", "Other"],
203*dd3c26a0STobias Hieta            ],
204*dd3c26a0STobias Hieta        )
205e3cd3a3cSTom Stellard
206e3cd3a3cSTom Stellard    def saveConfigValue(self):
207e3cd3a3cSTom Stellard        return False
208e3cd3a3cSTom Stellard
209e3cd3a3cSTom Stellard    def getValue(self, r, bugtype, getConfigOption):
210e3cd3a3cSTom Stellard        if bugtype.find("leak") != -1:
211*dd3c26a0STobias Hieta            return "3"
212e3cd3a3cSTom Stellard        elif bugtype.find("dereference") != -1:
213*dd3c26a0STobias Hieta            return "2"
214e3cd3a3cSTom Stellard        elif bugtype.find("missing ivar release") != -1:
215*dd3c26a0STobias Hieta            return "3"
216e3cd3a3cSTom Stellard        else:
217*dd3c26a0STobias Hieta            return "7"
218*dd3c26a0STobias Hieta
219e3cd3a3cSTom Stellard
220e3cd3a3cSTom Stellard###
221e3cd3a3cSTom Stellard
222*dd3c26a0STobias Hieta
223e3cd3a3cSTom Stellarddef getReporters():
224e3cd3a3cSTom Stellard    reporters = []
225e3cd3a3cSTom Stellard    reporters.append(EmailReporter())
226e3cd3a3cSTom Stellard    return reporters
227