Home | History | Annotate | Line # | Download | only in bin
      1 #!/usr/bin/env python
      2 
      3 from __future__ import print_function
      4 
      5 """The clang static analyzer results viewer.
      6 """
      7 
      8 import sys
      9 import imp
     10 import os
     11 import posixpath
     12 import threading
     13 import time
     14 try:
     15     from urllib.request import urlopen
     16 except ImportError:
     17     from urllib2 import urlopen
     18 import webbrowser
     19 
     20 # How long to wait for server to start.
     21 kSleepTimeout = .05
     22 kMaxSleeps = int(60 / kSleepTimeout)
     23 
     24 # Default server parameters
     25 
     26 kDefaultHost = '127.0.0.1'
     27 kDefaultPort = 8181
     28 kMaxPortsToTry = 100
     29 
     30 ###
     31 
     32 
     33 def url_is_up(url):
     34     try:
     35         o = urlopen(url)
     36     except IOError:
     37         return False
     38     o.close()
     39     return True
     40 
     41 
     42 def 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 
     66 def 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 
     86 def 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 
     99 def 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 
    149 if __name__ == '__main__':
    150     main()
    151