775 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			775 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			Python
		
	
	
	
from __future__ import print_function
 | 
						|
try:
 | 
						|
    from http.server import HTTPServer, SimpleHTTPRequestHandler
 | 
						|
except ImportError:
 | 
						|
    from BaseHTTPServer import HTTPServer
 | 
						|
    from SimpleHTTPServer import SimpleHTTPRequestHandler
 | 
						|
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
 | 
						|
try:
 | 
						|
    import configparser
 | 
						|
except ImportError:
 | 
						|
    import ConfigParser as 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("%s: SERVER: submitting bug."%(sys.argv[0],), file=sys.stderr)
 | 
						|
            self.status = self.reporter.fileReport(self.report, self.parameters)
 | 
						|
            self.success = True
 | 
						|
            time.sleep(3)
 | 
						|
            if self.server.options.debug:
 | 
						|
                print("%s: SERVER: submission complete."%(sys.argv[0],), file=sys.stderr)
 | 
						|
        except Reporter.ReportFailure as e:
 | 
						|
            self.status = e.value
 | 
						|
        except Exception as e:
 | 
						|
            s = StringIO.StringIO()
 | 
						|
            import traceback
 | 
						|
            print('<b>Unhandled Exception</b><br><pre>', file=s)
 | 
						|
            traceback.print_exc(file=s)
 | 
						|
            print('</pre>', file=s)
 | 
						|
            self.status = s.getvalue()
 | 
						|
 | 
						|
class ScanViewServer(HTTPServer):
 | 
						|
    def __init__(self, address, handler, root, reporters, options):
 | 
						|
        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("%s: SERVER: halting." % (sys.argv[0],), file=sys.stderr)
 | 
						|
 | 
						|
    def serve_forever(self):
 | 
						|
        while not self.halted:
 | 
						|
            if self.options.debug > 1:
 | 
						|
                print("%s: SERVER: waiting..." % (sys.argv[0],), file=sys.stderr)
 | 
						|
            try:
 | 
						|
                self.handle_request()
 | 
						|
            except OSError as e:
 | 
						|
                print('OSError',e.errno)
 | 
						|
 | 
						|
    def finish_request(self, request, client_address):
 | 
						|
        if self.options.autoReload:
 | 
						|
            import ScanView
 | 
						|
            self.RequestHandlerClass = reload(ScanView).ScanViewRequestHandler
 | 
						|
        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("%s: SERVER: ignored socket error." % (sys.argv[0],), file=sys.stderr)
 | 
						|
            return
 | 
						|
        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(SimpleHTTPRequestHandler):
 | 
						|
    server_version = "ScanViewServer/" + __version__
 | 
						|
    dynamic_mtime = time.time()
 | 
						|
 | 
						|
    def do_HEAD(self):
 | 
						|
        try:
 | 
						|
            SimpleHTTPRequestHandler.do_HEAD(self)
 | 
						|
        except Exception as e:
 | 
						|
            self.handle_exception(e)
 | 
						|
            
 | 
						|
    def do_GET(self):
 | 
						|
        try:
 | 
						|
            SimpleHTTPRequestHandler.do_GET(self)
 | 
						|
        except Exception as 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 as 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("INTERNAL ERROR\n", file=s)
 | 
						|
        traceback.print_exc(file=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('%s: SERVER: opening "%s"'%(sys.argv[0],
 | 
						|
                                                            file), file=sys.stderr)
 | 
						|
 | 
						|
        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(object):
 | 
						|
            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 as 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([repr(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('%s: SERVER: sending path "%s"'%(sys.argv[0],
 | 
						|
                                                                 path), file=sys.stderr)
 | 
						|
        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)
 |