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