diff options
Diffstat (limited to 'clang/tools/scan-view/ScanView.py')
-rw-r--r-- | clang/tools/scan-view/ScanView.py | 767 |
1 files changed, 0 insertions, 767 deletions
diff --git a/clang/tools/scan-view/ScanView.py b/clang/tools/scan-view/ScanView.py deleted file mode 100644 index 7dc0351ebe7..00000000000 --- a/clang/tools/scan-view/ScanView.py +++ /dev/null @@ -1,767 +0,0 @@ -import BaseHTTPServer -import SimpleHTTPServer -import os -import sys -import urllib, urlparse -import posixpath -import StringIO -import re -import shutil -import threading -import time -import socket -import itertools - -import Reporter -import ConfigParser - -### -# Various patterns matched or replaced by server. - -kReportFileRE = re.compile('(.*/)?report-(.*)\\.html') - -kBugKeyValueRE = re.compile('<!-- BUG([^ ]*) (.*) -->') - -# <!-- REPORTPROBLEM file="crashes/clang_crash_ndSGF9.mi" stderr="crashes/clang_crash_ndSGF9.mi.stderr.txt" info="crashes/clang_crash_ndSGF9.mi.info" --> - -kReportCrashEntryRE = re.compile('<!-- REPORTPROBLEM (.*?)-->') -kReportCrashEntryKeyValueRE = re.compile(' ?([^=]+)="(.*?)"') - -kReportReplacements = [] - -# Add custom javascript. -kReportReplacements.append((re.compile('<!-- SUMMARYENDHEAD -->'), """\ -<script language="javascript" type="text/javascript"> -function load(url) { - if (window.XMLHttpRequest) { - req = new XMLHttpRequest(); - } else if (window.ActiveXObject) { - req = new ActiveXObject("Microsoft.XMLHTTP"); - } - if (req != undefined) { - req.open("GET", url, true); - req.send(""); - } -} -</script>""")) - -# Insert additional columns. -kReportReplacements.append((re.compile('<!-- REPORTBUGCOL -->'), - '<td></td><td></td>')) - -# Insert report bug and open file links. -kReportReplacements.append((re.compile('<!-- REPORTBUG id="report-(.*)\\.html" -->'), - ('<td class="Button"><a href="report/\\1">Report Bug</a></td>' + - '<td class="Button"><a href="javascript:load(\'open/\\1\')">Open File</a></td>'))) - -kReportReplacements.append((re.compile('<!-- REPORTHEADER -->'), - '<h3><a href="/">Summary</a> > Report %(report)s</h3>')) - -kReportReplacements.append((re.compile('<!-- REPORTSUMMARYEXTRA -->'), - '<td class="Button"><a href="report/%(report)s">Report Bug</a></td>')) - -# Insert report crashes link. - -# Disabled for the time being until we decide exactly when this should -# be enabled. Also the radar reporter needs to be fixed to report -# multiple files. - -#kReportReplacements.append((re.compile('<!-- REPORTCRASHES -->'), -# '<br>These files will automatically be attached to ' + -# 'reports filed here: <a href="report_crashes">Report Crashes</a>.')) - -### -# Other simple parameters - -kShare = posixpath.join(posixpath.dirname(__file__), '../share/scan-view') -kConfigPath = os.path.expanduser('~/.scanview.cfg') - -### - -__version__ = "0.1" - -__all__ = ["create_server"] - -class ReporterThread(threading.Thread): - def __init__(self, report, reporter, parameters, server): - threading.Thread.__init__(self) - self.report = report - self.server = server - self.reporter = reporter - self.parameters = parameters - self.success = False - self.status = None - - def run(self): - result = None - try: - if self.server.options.debug: - print >>sys.stderr, "%s: SERVER: submitting bug."%(sys.argv[0],) - self.status = self.reporter.fileReport(self.report, self.parameters) - self.success = True - time.sleep(3) - if self.server.options.debug: - print >>sys.stderr, "%s: SERVER: submission complete."%(sys.argv[0],) - except Reporter.ReportFailure,e: - self.status = e.value - except Exception,e: - s = StringIO.StringIO() - import traceback - print >>s,'<b>Unhandled Exception</b><br><pre>' - traceback.print_exc(e,file=s) - print >>s,'</pre>' - self.status = s.getvalue() - -class ScanViewServer(BaseHTTPServer.HTTPServer): - def __init__(self, address, handler, root, reporters, options): - BaseHTTPServer.HTTPServer.__init__(self, address, handler) - self.root = root - self.reporters = reporters - self.options = options - self.halted = False - self.config = None - self.load_config() - - def load_config(self): - self.config = ConfigParser.RawConfigParser() - - # Add defaults - self.config.add_section('ScanView') - for r in self.reporters: - self.config.add_section(r.getName()) - for p in r.getParameters(): - if p.saveConfigValue(): - self.config.set(r.getName(), p.getName(), '') - - # Ignore parse errors - try: - self.config.read([kConfigPath]) - except: - pass - - # Save on exit - import atexit - atexit.register(lambda: self.save_config()) - - def save_config(self): - # Ignore errors (only called on exit). - try: - f = open(kConfigPath,'w') - self.config.write(f) - f.close() - except: - pass - - def halt(self): - self.halted = True - if self.options.debug: - print >>sys.stderr, "%s: SERVER: halting." % (sys.argv[0],) - - def serve_forever(self): - while not self.halted: - if self.options.debug > 1: - print >>sys.stderr, "%s: SERVER: waiting..." % (sys.argv[0],) - try: - self.handle_request() - except OSError,e: - print 'OSError',e.errno - - def finish_request(self, request, client_address): - if self.options.autoReload: - import ScanView - self.RequestHandlerClass = reload(ScanView).ScanViewRequestHandler - BaseHTTPServer.HTTPServer.finish_request(self, request, client_address) - - def handle_error(self, request, client_address): - # Ignore socket errors - info = sys.exc_info() - if info and isinstance(info[1], socket.error): - if self.options.debug > 1: - print >>sys.stderr, "%s: SERVER: ignored socket error." % (sys.argv[0],) - return - BaseHTTPServer.HTTPServer.handle_error(self, request, client_address) - -# Borrowed from Quixote, with simplifications. -def parse_query(qs, fields=None): - if fields is None: - fields = {} - for chunk in filter(None, qs.split('&')): - if '=' not in chunk: - name = chunk - value = '' - else: - name, value = chunk.split('=', 1) - name = urllib.unquote(name.replace('+', ' ')) - value = urllib.unquote(value.replace('+', ' ')) - item = fields.get(name) - if item is None: - fields[name] = [value] - else: - item.append(value) - return fields - -class ScanViewRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): - server_version = "ScanViewServer/" + __version__ - dynamic_mtime = time.time() - - def do_HEAD(self): - try: - SimpleHTTPServer.SimpleHTTPRequestHandler.do_HEAD(self) - except Exception,e: - self.handle_exception(e) - - def do_GET(self): - try: - SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self) - except Exception,e: - self.handle_exception(e) - - def do_POST(self): - """Serve a POST request.""" - try: - length = self.headers.getheader('content-length') or "0" - try: - length = int(length) - except: - length = 0 - content = self.rfile.read(length) - fields = parse_query(content) - f = self.send_head(fields) - if f: - self.copyfile(f, self.wfile) - f.close() - except Exception,e: - self.handle_exception(e) - - def log_message(self, format, *args): - if self.server.options.debug: - sys.stderr.write("%s: SERVER: %s - - [%s] %s\n" % - (sys.argv[0], - self.address_string(), - self.log_date_time_string(), - format%args)) - - def load_report(self, report): - path = os.path.join(self.server.root, 'report-%s.html'%report) - data = open(path).read() - keys = {} - for item in kBugKeyValueRE.finditer(data): - k,v = item.groups() - keys[k] = v - return keys - - def load_crashes(self): - path = posixpath.join(self.server.root, 'index.html') - data = open(path).read() - problems = [] - for item in kReportCrashEntryRE.finditer(data): - fieldData = item.group(1) - fields = dict([i.groups() for i in - kReportCrashEntryKeyValueRE.finditer(fieldData)]) - problems.append(fields) - return problems - - def handle_exception(self, exc): - import traceback - s = StringIO.StringIO() - print >>s, "INTERNAL ERROR\n" - traceback.print_exc(exc, s) - f = self.send_string(s.getvalue(), 'text/plain') - if f: - self.copyfile(f, self.wfile) - f.close() - - def get_scalar_field(self, name): - if name in self.fields: - return self.fields[name][0] - else: - return None - - def submit_bug(self, c): - title = self.get_scalar_field('title') - description = self.get_scalar_field('description') - report = self.get_scalar_field('report') - reporterIndex = self.get_scalar_field('reporter') - files = [] - for fileID in self.fields.get('files',[]): - try: - i = int(fileID) - except: - i = None - if i is None or i<0 or i>=len(c.files): - return (False, 'Invalid file ID') - files.append(c.files[i]) - - if not title: - return (False, "Missing title.") - if not description: - return (False, "Missing description.") - try: - reporterIndex = int(reporterIndex) - except: - return (False, "Invalid report method.") - - # Get the reporter and parameters. - reporter = self.server.reporters[reporterIndex] - parameters = {} - for o in reporter.getParameters(): - name = '%s_%s'%(reporter.getName(),o.getName()) - if name not in self.fields: - return (False, - 'Missing field "%s" for %s report method.'%(name, - reporter.getName())) - parameters[o.getName()] = self.get_scalar_field(name) - - # Update config defaults. - if report != 'None': - self.server.config.set('ScanView', 'reporter', reporterIndex) - for o in reporter.getParameters(): - if o.saveConfigValue(): - name = o.getName() - self.server.config.set(reporter.getName(), name, parameters[name]) - - # Create the report. - bug = Reporter.BugReport(title, description, files) - - # Kick off a reporting thread. - t = ReporterThread(bug, reporter, parameters, self.server) - t.start() - - # Wait for thread to die... - while t.isAlive(): - time.sleep(.25) - submitStatus = t.status - - return (t.success, t.status) - - def send_report_submit(self): - report = self.get_scalar_field('report') - c = self.get_report_context(report) - if c.reportSource is None: - reportingFor = "Report Crashes > " - fileBug = """\ -<a href="/report_crashes">File Bug</a> > """%locals() - else: - reportingFor = '<a href="/%s">Report %s</a> > ' % (c.reportSource, - report) - fileBug = '<a href="/report/%s">File Bug</a> > ' % report - title = self.get_scalar_field('title') - description = self.get_scalar_field('description') - - res,message = self.submit_bug(c) - - if res: - statusClass = 'SubmitOk' - statusName = 'Succeeded' - else: - statusClass = 'SubmitFail' - statusName = 'Failed' - - result = """ -<head> - <title>Bug Submission</title> - <link rel="stylesheet" type="text/css" href="/scanview.css" /> -</head> -<body> -<h3> -<a href="/">Summary</a> > -%(reportingFor)s -%(fileBug)s -Submit</h3> -<form name="form" action=""> -<table class="form"> -<tr><td> -<table class="form_group"> -<tr> - <td class="form_clabel">Title:</td> - <td class="form_value"> - <input type="text" name="title" size="50" value="%(title)s" disabled> - </td> -</tr> -<tr> - <td class="form_label">Description:</td> - <td class="form_value"> -<textarea rows="10" cols="80" name="description" disabled> -%(description)s -</textarea> - </td> -</table> -</td></tr> -</table> -</form> -<h1 class="%(statusClass)s">Submission %(statusName)s</h1> -%(message)s -<p> -<hr> -<a href="/">Return to Summary</a> -</body> -</html>"""%locals() - return self.send_string(result) - - def send_open_report(self, report): - try: - keys = self.load_report(report) - except IOError: - return self.send_error(400, 'Invalid report.') - - file = keys.get('FILE') - if not file or not posixpath.exists(file): - return self.send_error(400, 'File does not exist: "%s"' % file) - - import startfile - if self.server.options.debug: - print >>sys.stderr, '%s: SERVER: opening "%s"'%(sys.argv[0], - file) - - status = startfile.open(file) - if status: - res = 'Opened: "%s"' % file - else: - res = 'Open failed: "%s"' % file - - return self.send_string(res, 'text/plain') - - def get_report_context(self, report): - class Context: - pass - if report is None or report == 'None': - data = self.load_crashes() - # Don't allow empty reports. - if not data: - raise ValueError, 'No crashes detected!' - c = Context() - c.title = 'clang static analyzer failures' - - stderrSummary = "" - for item in data: - if 'stderr' in item: - path = posixpath.join(self.server.root, item['stderr']) - if os.path.exists(path): - lns = itertools.islice(open(path), 0, 10) - stderrSummary += '%s\n--\n%s' % (item.get('src', - '<unknown>'), - ''.join(lns)) - - c.description = """\ -The clang static analyzer failed on these inputs: -%s - -STDERR Summary --------------- -%s -""" % ('\n'.join([item.get('src','<unknown>') for item in data]), - stderrSummary) - c.reportSource = None - c.navMarkup = "Report Crashes > " - c.files = [] - for item in data: - c.files.append(item.get('src','')) - c.files.append(posixpath.join(self.server.root, - item.get('file',''))) - c.files.append(posixpath.join(self.server.root, - item.get('clangfile',''))) - c.files.append(posixpath.join(self.server.root, - item.get('stderr',''))) - c.files.append(posixpath.join(self.server.root, - item.get('info',''))) - # Just in case something failed, ignore files which don't - # exist. - c.files = [f for f in c.files - if os.path.exists(f) and os.path.isfile(f)] - else: - # Check that this is a valid report. - path = posixpath.join(self.server.root, 'report-%s.html' % report) - if not posixpath.exists(path): - raise ValueError, 'Invalid report ID' - keys = self.load_report(report) - c = Context() - c.title = keys.get('DESC','clang error (unrecognized') - c.description = """\ -Bug reported by the clang static analyzer. - -Description: %s -File: %s -Line: %s -"""%(c.title, keys.get('FILE','<unknown>'), keys.get('LINE', '<unknown>')) - c.reportSource = 'report-%s.html' % report - c.navMarkup = """<a href="/%s">Report %s</a> > """ % (c.reportSource, - report) - - c.files = [path] - return c - - def send_report(self, report, configOverrides=None): - def getConfigOption(section, field): - if (configOverrides is not None and - section in configOverrides and - field in configOverrides[section]): - return configOverrides[section][field] - return self.server.config.get(section, field) - - # report is None is used for crashes - try: - c = self.get_report_context(report) - except ValueError, e: - return self.send_error(400, e.message) - - title = c.title - description= c.description - reportingFor = c.navMarkup - if c.reportSource is None: - extraIFrame = "" - else: - extraIFrame = """\ -<iframe src="/%s" width="100%%" height="40%%" - scrolling="auto" frameborder="1"> - <a href="/%s">View Bug Report</a> -</iframe>""" % (c.reportSource, c.reportSource) - - reporterSelections = [] - reporterOptions = [] - - try: - active = int(getConfigOption('ScanView','reporter')) - except: - active = 0 - for i,r in enumerate(self.server.reporters): - selected = (i == active) - if selected: - selectedStr = ' selected' - else: - selectedStr = '' - reporterSelections.append('<option value="%d"%s>%s</option>'%(i,selectedStr,r.getName())) - options = '\n'.join([ o.getHTML(r,title,getConfigOption) for o in r.getParameters()]) - display = ('none','')[selected] - reporterOptions.append("""\ -<tr id="%sReporterOptions" style="display:%s"> - <td class="form_label">%s Options</td> - <td class="form_value"> - <table class="form_inner_group"> -%s - </table> - </td> -</tr> -"""%(r.getName(),display,r.getName(),options)) - reporterSelections = '\n'.join(reporterSelections) - reporterOptionsDivs = '\n'.join(reporterOptions) - reportersArray = '[%s]'%(','.join([`r.getName()` for r in self.server.reporters])) - - if c.files: - fieldSize = min(5, len(c.files)) - attachFileOptions = '\n'.join(["""\ -<option value="%d" selected>%s</option>""" % (i,v) for i,v in enumerate(c.files)]) - attachFileRow = """\ -<tr> - <td class="form_label">Attach:</td> - <td class="form_value"> -<select style="width:100%%" name="files" multiple size=%d> -%s -</select> - </td> -</tr> -""" % (min(5, len(c.files)), attachFileOptions) - else: - attachFileRow = "" - - result = """<html> -<head> - <title>File Bug</title> - <link rel="stylesheet" type="text/css" href="/scanview.css" /> -</head> -<script language="javascript" type="text/javascript"> -var reporters = %(reportersArray)s; -function updateReporterOptions() { - index = document.getElementById('reporter').selectedIndex; - for (var i=0; i < reporters.length; ++i) { - o = document.getElementById(reporters[i] + "ReporterOptions"); - if (i == index) { - o.style.display = ""; - } else { - o.style.display = "none"; - } - } -} -</script> -<body onLoad="updateReporterOptions()"> -<h3> -<a href="/">Summary</a> > -%(reportingFor)s -File Bug</h3> -<form name="form" action="/report_submit" method="post"> -<input type="hidden" name="report" value="%(report)s"> - -<table class="form"> -<tr><td> -<table class="form_group"> -<tr> - <td class="form_clabel">Title:</td> - <td class="form_value"> - <input type="text" name="title" size="50" value="%(title)s"> - </td> -</tr> -<tr> - <td class="form_label">Description:</td> - <td class="form_value"> -<textarea rows="10" cols="80" name="description"> -%(description)s -</textarea> - </td> -</tr> - -%(attachFileRow)s - -</table> -<br> -<table class="form_group"> -<tr> - <td class="form_clabel">Method:</td> - <td class="form_value"> - <select id="reporter" name="reporter" onChange="updateReporterOptions()"> - %(reporterSelections)s - </select> - </td> -</tr> -%(reporterOptionsDivs)s -</table> -<br> -</td></tr> -<tr><td class="form_submit"> - <input align="right" type="submit" name="Submit" value="Submit"> -</td></tr> -</table> -</form> - -%(extraIFrame)s - -</body> -</html>"""%locals() - - return self.send_string(result) - - def send_head(self, fields=None): - if (self.server.options.onlyServeLocal and - self.client_address[0] != '127.0.0.1'): - return self.send_error(401, 'Unauthorized host.') - - if fields is None: - fields = {} - self.fields = fields - - o = urlparse.urlparse(self.path) - self.fields = parse_query(o.query, fields) - path = posixpath.normpath(urllib.unquote(o.path)) - - # Split the components and strip the root prefix. - components = path.split('/')[1:] - - # Special case some top-level entries. - if components: - name = components[0] - if len(components)==2: - if name=='report': - return self.send_report(components[1]) - elif name=='open': - return self.send_open_report(components[1]) - elif len(components)==1: - if name=='quit': - self.server.halt() - return self.send_string('Goodbye.', 'text/plain') - elif name=='report_submit': - return self.send_report_submit() - elif name=='report_crashes': - overrides = { 'ScanView' : {}, - 'Radar' : {}, - 'Email' : {} } - for i,r in enumerate(self.server.reporters): - if r.getName() == 'Radar': - overrides['ScanView']['reporter'] = i - break - overrides['Radar']['Component'] = 'llvm - checker' - overrides['Radar']['Component Version'] = 'X' - return self.send_report(None, overrides) - elif name=='favicon.ico': - return self.send_path(posixpath.join(kShare,'bugcatcher.ico')) - - # Match directory entries. - if components[-1] == '': - components[-1] = 'index.html' - - relpath = '/'.join(components) - path = posixpath.join(self.server.root, relpath) - - if self.server.options.debug > 1: - print >>sys.stderr, '%s: SERVER: sending path "%s"'%(sys.argv[0], - path) - return self.send_path(path) - - def send_404(self): - self.send_error(404, "File not found") - return None - - def send_path(self, path): - # If the requested path is outside the root directory, do not open it - rel = os.path.abspath(path) - if not rel.startswith(os.path.abspath(self.server.root)): - return self.send_404() - - ctype = self.guess_type(path) - if ctype.startswith('text/'): - # Patch file instead - return self.send_patched_file(path, ctype) - else: - mode = 'rb' - try: - f = open(path, mode) - except IOError: - return self.send_404() - return self.send_file(f, ctype) - - def send_file(self, f, ctype): - # Patch files to add links, but skip binary files. - self.send_response(200) - self.send_header("Content-type", ctype) - fs = os.fstat(f.fileno()) - self.send_header("Content-Length", str(fs[6])) - self.send_header("Last-Modified", self.date_time_string(fs.st_mtime)) - self.end_headers() - return f - - def send_string(self, s, ctype='text/html', headers=True, mtime=None): - if headers: - self.send_response(200) - self.send_header("Content-type", ctype) - self.send_header("Content-Length", str(len(s))) - if mtime is None: - mtime = self.dynamic_mtime - self.send_header("Last-Modified", self.date_time_string(mtime)) - self.end_headers() - return StringIO.StringIO(s) - - def send_patched_file(self, path, ctype): - # Allow a very limited set of variables. This is pretty gross. - variables = {} - variables['report'] = '' - m = kReportFileRE.match(path) - if m: - variables['report'] = m.group(2) - - try: - f = open(path,'r') - except IOError: - return self.send_404() - fs = os.fstat(f.fileno()) - data = f.read() - for a,b in kReportReplacements: - data = a.sub(b % variables, data) - return self.send_string(data, ctype, mtime=fs.st_mtime) - - -def create_server(address, options, root): - import Reporter - - reporters = Reporter.getReporters() - - return ScanViewServer(address, ScanViewRequestHandler, - root, - reporters, - options) |