1#!/usr/bin/env python 2 3from __future__ import print_function 4 5"""The clang static analyzer results viewer. 6""" 7 8import sys 9import os 10import posixpath 11import threading 12import time 13try: 14 from urllib.request import urlopen 15except ImportError: 16 from urllib2 import urlopen 17import webbrowser 18 19# How long to wait for server to start. 20kSleepTimeout = .05 21kMaxSleeps = int(60 / kSleepTimeout) 22 23# Default server parameters 24 25kDefaultHost = '127.0.0.1' 26kDefaultPort = 8181 27kMaxPortsToTry = 100 28 29### 30 31 32def url_is_up(url): 33 try: 34 o = urlopen(url) 35 except IOError: 36 return False 37 o.close() 38 return True 39 40 41def start_browser(port, options): 42 import webbrowser 43 44 url = 'http://%s:%d' % (options.host, port) 45 46 # Wait for server to start... 47 if options.debug: 48 sys.stderr.write('%s: Waiting for server.' % sys.argv[0]) 49 sys.stderr.flush() 50 for i in range(kMaxSleeps): 51 if url_is_up(url): 52 break 53 if options.debug: 54 sys.stderr.write('.') 55 sys.stderr.flush() 56 time.sleep(kSleepTimeout) 57 else: 58 print('WARNING: Unable to detect that server started.', file=sys.stderr) 59 60 if options.debug: 61 print('%s: Starting webbrowser...' % sys.argv[0], file=sys.stderr) 62 webbrowser.open(url) 63 64 65def run(port, options, root): 66 # Prefer to look relative to the installed binary 67 share = os.path.dirname(__file__) + "/../share/scan-view" 68 if not os.path.isdir(share): 69 # Otherwise look relative to the source 70 share = os.path.dirname(__file__) + "/../../scan-view/share" 71 sys.path.append(share) 72 73 import ScanView 74 try: 75 print('Starting scan-view at: http://%s:%d' % (options.host, 76 port)) 77 print(' Use Ctrl-C to exit.') 78 httpd = ScanView.create_server((options.host, port), 79 options, root) 80 httpd.serve_forever() 81 except KeyboardInterrupt: 82 pass 83 84 85def port_is_open(port): 86 try: 87 import socketserver 88 except ImportError: 89 import SocketServer as socketserver 90 try: 91 t = socketserver.TCPServer((kDefaultHost, port), None) 92 except: 93 return False 94 t.server_close() 95 return True 96 97 98def main(): 99 import argparse 100 parser = argparse.ArgumentParser(description="The clang static analyzer " 101 "results viewer.") 102 parser.add_argument("root", metavar="<results directory>", type=str) 103 parser.add_argument( 104 '--host', dest="host", default=kDefaultHost, type=str, 105 help="Host interface to listen on. (default=%s)" % kDefaultHost) 106 parser.add_argument('--port', dest="port", default=None, type=int, 107 help="Port to listen on. (default=%s)" % kDefaultPort) 108 parser.add_argument("--debug", dest="debug", default=0, 109 action="count", 110 help="Print additional debugging information.") 111 parser.add_argument("--auto-reload", dest="autoReload", default=False, 112 action="store_true", 113 help="Automatically update module for each request.") 114 parser.add_argument("--no-browser", dest="startBrowser", default=True, 115 action="store_false", 116 help="Don't open a webbrowser on startup.") 117 parser.add_argument("--allow-all-hosts", dest="onlyServeLocal", 118 default=True, action="store_false", 119 help='Allow connections from any host (access ' 120 'restricted to "127.0.0.1" by default)') 121 args = parser.parse_args() 122 123 # Make sure this directory is in a reasonable state to view. 124 if not posixpath.exists(posixpath.join(args.root, 'index.html')): 125 parser.error('Invalid directory, analysis results not found!') 126 127 # Find an open port. We aren't particularly worried about race 128 # conditions here. Note that if the user specified a port we only 129 # use that one. 130 if args.port is not None: 131 port = args.port 132 else: 133 for i in range(kMaxPortsToTry): 134 if port_is_open(kDefaultPort + i): 135 port = kDefaultPort + i 136 break 137 else: 138 parser.error('Unable to find usable port in [%d,%d)' % 139 (kDefaultPort, kDefaultPort+kMaxPortsToTry)) 140 141 # Kick off thread to wait for server and start web browser, if 142 # requested. 143 if args.startBrowser: 144 threading.Thread(target=start_browser, args=(port, args)).start() 145 146 run(port, args, args.root) 147 148if __name__ == '__main__': 149 main() 150