summaryrefslogtreecommitdiffstats
path: root/tools/scan-view/bin/scan-view
blob: 6e384ec2171db868e2a3b1fcf7c91473c538ea79 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#!/usr/bin/env python

"""The clang static analyzer results viewer.
"""

import sys
import imp
import os
import posixpath
import threading
import time
import urllib
import webbrowser

# How long to wait for server to start.
kSleepTimeout = .05
kMaxSleeps = int(60 / kSleepTimeout)

# Default server parameters

kDefaultHost = '127.0.0.1'
kDefaultPort = 8181
kMaxPortsToTry = 100

###


def url_is_up(url):
    try:
        o = urllib.urlopen(url)
    except IOError:
        return False
    o.close()
    return True


def start_browser(port, options):
    import urllib
    import webbrowser

    url = 'http://%s:%d' % (options.host, port)

    # Wait for server to start...
    if options.debug:
        sys.stderr.write('%s: Waiting for server.' % sys.argv[0])
        sys.stderr.flush()
    for i in range(kMaxSleeps):
        if url_is_up(url):
            break
        if options.debug:
            sys.stderr.write('.')
            sys.stderr.flush()
        time.sleep(kSleepTimeout)
    else:
        print >> sys.stderr, 'WARNING: Unable to detect that server started.'

    if options.debug:
        print >> sys.stderr, '%s: Starting webbrowser...' % sys.argv[0]
    webbrowser.open(url)


def run(port, options, root):
    # Prefer to look relative to the installed binary
    share = os.path.dirname(__file__) + "/../share/scan-view"
    if not os.path.isdir(share):
        # Otherwise look relative to the source
        share = os.path.dirname(__file__) + "/../../scan-view/share"
    sys.path.append(share)

    import ScanView
    try:
        print 'Starting scan-view at: http://%s:%d' % (options.host,
                                                       port)
        print '  Use Ctrl-C to exit.'
        httpd = ScanView.create_server((options.host, port),
                                       options, root)
        httpd.serve_forever()
    except KeyboardInterrupt:
        pass


def port_is_open(port):
    try:
        import socketserver
    except ImportError:
        import SocketServer as socketserver
    try:
        t = socketserver.TCPServer((kDefaultHost, port), None)
    except:
        return False
    t.server_close()
    return True


def main():
    import argparse
    parser = argparse.ArgumentParser(description="The clang static analyzer "
                                                 "results viewer.")
    parser.add_argument("root", metavar="<results directory>", type=str)
    parser.add_argument(
        '--host', dest="host", default=kDefaultHost, type=str,
        help="Host interface to listen on. (default=%s)" % kDefaultHost)
    parser.add_argument('--port', dest="port", default=None, type=int,
                        help="Port to listen on. (default=%s)" % kDefaultPort)
    parser.add_argument("--debug", dest="debug", default=0,
                        action="count",
                        help="Print additional debugging information.")
    parser.add_argument("--auto-reload", dest="autoReload", default=False,
                        action="store_true",
                        help="Automatically update module for each request.")
    parser.add_argument("--no-browser", dest="startBrowser", default=True,
                        action="store_false",
                        help="Don't open a webbrowser on startup.")
    parser.add_argument("--allow-all-hosts", dest="onlyServeLocal",
                        default=True, action="store_false",
                        help='Allow connections from any host (access '
                             'restricted to "127.0.0.1" by default)')
    args = parser.parse_args()

    # Make sure this directory is in a reasonable state to view.
    if not posixpath.exists(posixpath.join(args.root, 'index.html')):
        parser.error('Invalid directory, analysis results not found!')

    # Find an open port. We aren't particularly worried about race
    # conditions here. Note that if the user specified a port we only
    # use that one.
    if args.port is not None:
        port = args.port
    else:
        for i in range(kMaxPortsToTry):
            if port_is_open(kDefaultPort + i):
                port = kDefaultPort + i
                break
        else:
            parser.error('Unable to find usable port in [%d,%d)' %
                         (kDefaultPort, kDefaultPort+kMaxPortsToTry))

    # Kick off thread to wait for server and start web browser, if
    # requested.
    if args.startBrowser:
        threading.Thread(target=start_browser, args=(port, args)).start()

    run(port, args, args.root)

if __name__ == '__main__':
    main()