2 # -*- coding: utf-8 -*-
4 """Methods for reporting bugs."""
6 import subprocess
, sys
, os
8 __all__
= ["ReportFailure", "BugReport", "getReporters"]
13 class ReportFailure(Exception):
14 """Generic exception for failures in bug reporting."""
16 def __init__(self
, value
):
20 # Collect information about a bug.
23 class BugReport(object):
24 def __init__(self
, title
, description
, files
):
26 self
.description
= description
30 # Reporter interfaces.
34 import email
, mimetypes
, smtplib
35 from email
import encoders
36 from email
.message
import Message
37 from email
.mime
.base
import MIMEBase
38 from email
.mime
.multipart
import MIMEMultipart
39 from email
.mime
.text
import MIMEText
41 # ===------------------------------------------------------------------------===#
43 # ===------------------------------------------------------------------------===#
46 class ReporterParameter(object):
47 def __init__(self
, n
):
53 def getValue(self
, r
, bugtype
, getConfigOption
):
54 return getConfigOption(r
.getName(), self
.getName())
56 def saveConfigValue(self
):
60 class TextParameter(ReporterParameter
):
61 def getHTML(self
, r
, bugtype
, getConfigOption
):
64 <td class="form_clabel">%s:</td>
65 <td class="form_value"><input type="text" name="%s_%s" value="%s"></td>
70 self
.getValue(r
, bugtype
, getConfigOption
),
74 class SelectionParameter(ReporterParameter
):
75 def __init__(self
, n
, values
):
76 ReporterParameter
.__init
__(self
, n
)
79 def getHTML(self
, r
, bugtype
, getConfigOption
):
80 default
= self
.getValue(r
, bugtype
, getConfigOption
)
83 <td class="form_clabel">%s:</td><td class="form_value"><select name="%s_%s">
92 <option value="%s"%s>%s</option>"""
93 % (o
[0], o
[0] == default
and ' selected="selected"' or "", o
[1])
100 # ===------------------------------------------------------------------------===#
102 # ===------------------------------------------------------------------------===#
105 class EmailReporter(object):
109 def getParameters(self
):
110 return [TextParameter(x
) for x
in ["To", "From", "SMTP Server", "SMTP Port"]]
112 # Lifted from python email module examples.
113 def attachFile(self
, outer
, path
):
114 # Guess the content type based on the file's extension. Encoding
115 # will be ignored, although we should check for simple things like
116 # gzip'd or compressed files.
117 ctype
, encoding
= mimetypes
.guess_type(path
)
118 if ctype
is None or encoding
is not None:
119 # No guess could be made, or the file is encoded (compressed), so
120 # use a generic bag-of-bits type.
121 ctype
= "application/octet-stream"
122 maintype
, subtype
= ctype
.split("/", 1)
123 if maintype
== "text":
125 # Note: we should handle calculating the charset
126 msg
= MIMEText(fp
.read(), _subtype
=subtype
)
129 fp
= open(path
, "rb")
130 msg
= MIMEBase(maintype
, subtype
)
131 msg
.set_payload(fp
.read())
133 # Encode the payload using Base64
134 encoders
.encode_base64(msg
)
135 # Set the filename parameter
137 "Content-Disposition", "attachment", filename
=os
.path
.basename(path
)
141 def fileReport(self
, report
, parameters
):
152 if not parameters
.get("To"):
153 raise ReportFailure('No "To" address specified.')
154 if not parameters
.get("From"):
155 raise ReportFailure('No "From" address specified.')
157 msg
= MIMEMultipart()
158 msg
["Subject"] = "BUG REPORT: %s" % (report
.title
)
159 # FIXME: Get config parameters
160 msg
["To"] = parameters
.get("To")
161 msg
["From"] = parameters
.get("From")
162 msg
.preamble
= mainMsg
164 msg
.attach(MIMEText(mainMsg
, _subtype
="text/plain"))
165 for file in report
.files
:
166 self
.attachFile(msg
, file)
170 host
=parameters
.get("SMTP Server"), port
=parameters
.get("SMTP Port")
172 s
.sendmail(msg
["From"], msg
["To"], msg
.as_string())
175 raise ReportFailure("Unable to send message via SMTP.")
177 return "Message sent!"
180 class BugzillaReporter(object):
184 def getParameters(self
):
185 return [TextParameter(x
) for x
in ["URL", "Product"]]
187 def fileReport(self
, report
, parameters
):
188 raise NotImplementedError
191 class RadarClassificationParameter(SelectionParameter
):
193 SelectionParameter
.__init
__(
198 ["2", "Crash/Hang/Data Loss"],
199 ["3", "Performance"],
200 ["4", "UI/Usability"],
201 ["6", "Serious Bug"],
206 def saveConfigValue(self
):
209 def getValue(self
, r
, bugtype
, getConfigOption
):
210 if bugtype
.find("leak") != -1:
212 elif bugtype
.find("dereference") != -1:
214 elif bugtype
.find("missing ivar release") != -1:
225 reporters
.append(EmailReporter())