Home | History | Annotate | Download | only in bin
      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