blob: a28d0945ac3e8a9f1548e460a426c3ac0e6fcfa1 [file] [log] [blame]
Daniel Dunbar2b0662c2008-09-19 23:32:11 +00001"""Methods for reporting bugs."""
2
3import subprocess, sys, os
4
5__all__ = ['BugReport', 'getReporters']
6
7# Collect information about a bug.
8
9class BugReport:
10 def __init__(self, title, description, files):
11 self.title = title
12 self.description = description
13 self.files = files
14
15# Reporter interfaces.
16
17import os
18
19import email, mimetypes, smtplib
20from email import encoders
21from email.message import Message
22from email.mime.base import MIMEBase
23from email.mime.multipart import MIMEMultipart
24from email.mime.text import MIMEText
25
26class EmailReporter:
27 def getName(self):
28 return 'Email'
29
30 def getParameterNames(self):
31 return ['To', 'From', 'SMTP Server', 'SMTP Port']
32
33 # Lifted from python email module examples.
34 def attachFile(self, outer, path):
35 # Guess the content type based on the file's extension. Encoding
36 # will be ignored, although we should check for simple things like
37 # gzip'd or compressed files.
38 ctype, encoding = mimetypes.guess_type(path)
39 if ctype is None or encoding is not None:
40 # No guess could be made, or the file is encoded (compressed), so
41 # use a generic bag-of-bits type.
42 ctype = 'application/octet-stream'
43 maintype, subtype = ctype.split('/', 1)
44 if maintype == 'text':
45 fp = open(path)
46 # Note: we should handle calculating the charset
47 msg = MIMEText(fp.read(), _subtype=subtype)
48 fp.close()
49 else:
50 fp = open(path, 'rb')
51 msg = MIMEBase(maintype, subtype)
52 msg.set_payload(fp.read())
53 fp.close()
54 # Encode the payload using Base64
55 encoders.encode_base64(msg)
56 # Set the filename parameter
57 msg.add_header('Content-Disposition', 'attachment', filename=os.path.basename(path))
58 outer.attach(msg)
59
60 def fileReport(self, report, parameters):
61 mainMsg = """\
62BUG REPORT
63---
64Title: %s
65Description: %s
66"""%(report.title, report.description)
67
68 if not parameters.get('To') or not parameters.get('From'):
69 raise ValueError,'Invalid email parameters.'
70
71 msg = MIMEMultipart()
72 msg['Subject'] = 'BUG REPORT: %s'%(report.title)
73 # FIXME: Get config parameters
74 msg['To'] = parameters.get('To')
75 msg['From'] = parameters.get('From')
76 msg.preamble = mainMsg
77
78 msg.attach(MIMEText(mainMsg, _subtype='text/plain'))
79 for file in report.files:
80 self.attachFile(msg, file)
81
82 s = smtplib.SMTP(host=parameters.get('SMTP Server'),
83 port=parameters.get('SMTP Port'))
84 s.sendmail(msg['From'], msg['To'], msg.as_string())
85 s.close()
86
87class BugzillaReporter:
88 def getName(self):
89 return 'Bugzilla'
90
91 def getParameterNames(self):
92 return ['URL', 'Product']
93
94 def fileReport(self, report, parameters):
95 raise NotImplementedError
96
97class RadarReporter:
98 @staticmethod
99 def isAvailable():
100 # FIXME: Find this .scpt better
101 path = os.path.join(os.path.dirname(__file__),'Resources/GetRadarVersion.scpt')
102 try:
103 p = subprocess.Popen(['osascript',path],
104 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
105 except:
106 return False
107 data,err = p.communicate()
108 res = p.wait()
109 # FIXME: Check version? Check for no errors?
110 return res == 0
111
112 def getName(self):
113 return 'Radar'
114
115 def getParameterNames(self):
116 return ['Component', 'Component Version']
117
118 def fileReport(self, report, parameters):
119 component = parameters.get('Component', '')
120 componentVersion = parameters.get('Component Version', '')
121 personID = ""
122 diagnosis = ""
123 config = ""
124
125 if not component.strip():
126 component = 'Bugs found by clang Analyzer'
127 if not componentVersion.strip():
128 componentVersion = 'X'
129
130 script = os.path.join(os.path.dirname(__file__),'Resources/FileRadar.scpt')
131 args = ['osascript', script, component, componentVersion, personID, report.title,
132 report.description, diagnosis, config] + map(os.path.abspath, report.files)
133# print >>sys.stderr, args
134 try:
135 p = subprocess.Popen(args,
136 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
137 except:
138 print >>sys.stderr, '%s: SERVER: radar failed'%(sys.argv[0],)
139 sys.print_exc()
140 raise
141 data, err = p.communicate()
142# print >>sys.stderr, '%s: SERVER: radar report: "%s" "%s"'%(sys.argv[0],data, err)
143 res = p.wait()
144# print >>sys.stderr, '%s: SERVER: radar report res: %d'%(sys.argv[0],res,)
145
146 if res:
147 raise RuntimeError,'Radar submission failed.'
148
149 return data.replace('\n','\n<br>')
150
151###
152
153def getReporters():
154 reporters = []
155 if RadarReporter.isAvailable():
156 reporters.append(RadarReporter())
157 reporters.extend([EmailReporter(), BugzillaReporter()])
158 return reporters
159