Reporter.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. """Methods for reporting bugs."""
  4. import subprocess, sys, os
  5. __all__ = ['ReportFailure', 'BugReport', 'getReporters']
  6. #
  7. class ReportFailure(Exception):
  8. """Generic exception for failures in bug reporting."""
  9. def __init__(self, value):
  10. self.value = value
  11. # Collect information about a bug.
  12. class BugReport(object):
  13. def __init__(self, title, description, files):
  14. self.title = title
  15. self.description = description
  16. self.files = files
  17. # Reporter interfaces.
  18. import os
  19. import email, mimetypes, smtplib
  20. from email import encoders
  21. from email.message import Message
  22. from email.mime.base import MIMEBase
  23. from email.mime.multipart import MIMEMultipart
  24. from email.mime.text import MIMEText
  25. #===------------------------------------------------------------------------===#
  26. # ReporterParameter
  27. #===------------------------------------------------------------------------===#
  28. class ReporterParameter(object):
  29. def __init__(self, n):
  30. self.name = n
  31. def getName(self):
  32. return self.name
  33. def getValue(self,r,bugtype,getConfigOption):
  34. return getConfigOption(r.getName(),self.getName())
  35. def saveConfigValue(self):
  36. return True
  37. class TextParameter (ReporterParameter):
  38. def getHTML(self,r,bugtype,getConfigOption):
  39. return """\
  40. <tr>
  41. <td class="form_clabel">%s:</td>
  42. <td class="form_value"><input type="text" name="%s_%s" value="%s"></td>
  43. </tr>"""%(self.getName(),r.getName(),self.getName(),self.getValue(r,bugtype,getConfigOption))
  44. class SelectionParameter (ReporterParameter):
  45. def __init__(self, n, values):
  46. ReporterParameter.__init__(self,n)
  47. self.values = values
  48. def getHTML(self,r,bugtype,getConfigOption):
  49. default = self.getValue(r,bugtype,getConfigOption)
  50. return """\
  51. <tr>
  52. <td class="form_clabel">%s:</td><td class="form_value"><select name="%s_%s">
  53. %s
  54. </select></td>"""%(self.getName(),r.getName(),self.getName(),'\n'.join(["""\
  55. <option value="%s"%s>%s</option>"""%(o[0],
  56. o[0] == default and ' selected="selected"' or '',
  57. o[1]) for o in self.values]))
  58. #===------------------------------------------------------------------------===#
  59. # Reporters
  60. #===------------------------------------------------------------------------===#
  61. class EmailReporter(object):
  62. def getName(self):
  63. return 'Email'
  64. def getParameters(self):
  65. return [TextParameter(x) for x in ['To', 'From', 'SMTP Server', 'SMTP Port']]
  66. # Lifted from python email module examples.
  67. def attachFile(self, outer, path):
  68. # Guess the content type based on the file's extension. Encoding
  69. # will be ignored, although we should check for simple things like
  70. # gzip'd or compressed files.
  71. ctype, encoding = mimetypes.guess_type(path)
  72. if ctype is None or encoding is not None:
  73. # No guess could be made, or the file is encoded (compressed), so
  74. # use a generic bag-of-bits type.
  75. ctype = 'application/octet-stream'
  76. maintype, subtype = ctype.split('/', 1)
  77. if maintype == 'text':
  78. fp = open(path)
  79. # Note: we should handle calculating the charset
  80. msg = MIMEText(fp.read(), _subtype=subtype)
  81. fp.close()
  82. else:
  83. fp = open(path, 'rb')
  84. msg = MIMEBase(maintype, subtype)
  85. msg.set_payload(fp.read())
  86. fp.close()
  87. # Encode the payload using Base64
  88. encoders.encode_base64(msg)
  89. # Set the filename parameter
  90. msg.add_header('Content-Disposition', 'attachment', filename=os.path.basename(path))
  91. outer.attach(msg)
  92. def fileReport(self, report, parameters):
  93. mainMsg = """\
  94. BUG REPORT
  95. ---
  96. Title: %s
  97. Description: %s
  98. """%(report.title, report.description)
  99. if not parameters.get('To'):
  100. raise ReportFailure('No "To" address specified.')
  101. if not parameters.get('From'):
  102. raise ReportFailure('No "From" address specified.')
  103. msg = MIMEMultipart()
  104. msg['Subject'] = 'BUG REPORT: %s'%(report.title)
  105. # FIXME: Get config parameters
  106. msg['To'] = parameters.get('To')
  107. msg['From'] = parameters.get('From')
  108. msg.preamble = mainMsg
  109. msg.attach(MIMEText(mainMsg, _subtype='text/plain'))
  110. for file in report.files:
  111. self.attachFile(msg, file)
  112. try:
  113. s = smtplib.SMTP(host=parameters.get('SMTP Server'),
  114. port=parameters.get('SMTP Port'))
  115. s.sendmail(msg['From'], msg['To'], msg.as_string())
  116. s.close()
  117. except:
  118. raise ReportFailure('Unable to send message via SMTP.')
  119. return "Message sent!"
  120. class BugzillaReporter(object):
  121. def getName(self):
  122. return 'Bugzilla'
  123. def getParameters(self):
  124. return [TextParameter(x) for x in ['URL','Product']]
  125. def fileReport(self, report, parameters):
  126. raise NotImplementedError
  127. class RadarClassificationParameter(SelectionParameter):
  128. def __init__(self):
  129. SelectionParameter.__init__(self,"Classification",
  130. [['1', 'Security'], ['2', 'Crash/Hang/Data Loss'],
  131. ['3', 'Performance'], ['4', 'UI/Usability'],
  132. ['6', 'Serious Bug'], ['7', 'Other']])
  133. def saveConfigValue(self):
  134. return False
  135. def getValue(self,r,bugtype,getConfigOption):
  136. if bugtype.find("leak") != -1:
  137. return '3'
  138. elif bugtype.find("dereference") != -1:
  139. return '2'
  140. elif bugtype.find("missing ivar release") != -1:
  141. return '3'
  142. else:
  143. return '7'
  144. ###
  145. def getReporters():
  146. reporters = []
  147. reporters.append(EmailReporter())
  148. return reporters