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