Hardcoded python path is not compatible with virtual environment.
[WebKit-https.git] / Tools / Scripts / webkitpy / benchmark_runner / http_server_driver / simple_http_server_driver.py
1 #!/usr/bin/env python
2
3 import logging
4 import os
5 import re
6 import socket
7 import subprocess
8 import sys
9 import time
10
11 from http_server_driver import HTTPServerDriver
12
13
14 _log = logging.getLogger(__name__)
15
16
17 class SimpleHTTPServerDriver(HTTPServerDriver):
18
19     """This class depends on unix environment, need to be modified to achieve crossplatform compability
20     """
21
22     platforms = ['osx', 'linux']
23
24     def __init__(self):
25         self._server_process = None
26         self._server_port = 0
27         self._ip = '127.0.0.1'
28         self._ensure_http_server_dependencies()
29
30     def serve(self, web_root):
31         _log.info('Launching an http server')
32         http_server_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "http_server/twisted_http_server.py")
33         self._server_process = subprocess.Popen(["python", http_server_path, web_root], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
34
35         max_attempt = 5
36         interval = 0.5
37         _log.info('Start to fetching the port number of the http server')
38         try:
39             import psutil
40             for attempt in xrange(max_attempt):
41                 connections = psutil.Process(self._server_process.pid).connections()
42                 if connections and connections[0].laddr and connections[0].laddr[1] and connections[0].status == 'LISTEN':
43                     self._server_port = connections[0].laddr[1]
44                     _log.info('HTTP Server is serving at port: %d', self._server_port)
45                     break
46                 _log.info('Server port is not found this time, retry after %f seconds' % interval)
47                 time.sleep(interval)
48                 interval *= 2
49             else:
50                 raise Exception("Server is not listening on port, max tries exceeded. HTTP server may be installing dependent modules.")
51         except ImportError:
52             for attempt in xrange(max_attempt):
53                 try:
54                     output = subprocess.check_output(['/usr/sbin/lsof', '-a', '-iTCP', '-sTCP:LISTEN', '-p', str(self._server_process.pid)])
55                     self._server_port = int(re.search('TCP \*:(\d+) \(LISTEN\)', output).group(1))
56                     if self._server_port:
57                         _log.info('HTTP Server is serving at port: %d', self._server_port)
58                         break
59                 except Exception as error:
60                     _log.info('Error: %s' % error)
61                 _log.info('Server port is not found this time, retry after %f seconds' % interval)
62                 time.sleep(interval)
63                 interval *= 2
64             else:
65                 raise Exception("Cannot listen to server, max tries exceeded")
66
67         # Wait for server to be up completely before exiting
68         for attempt in xrange(max_attempt):
69             try:
70                 subprocess.check_call(["curl", "--silent", "--head", "--fail", "--output", "/dev/null", self.base_url()])
71                 return
72             except Exception as error:
73                 _log.info('Server not running yet: %s' % error)
74                 time.sleep(interval)
75         raise Exception('Server not running, max tries exceeded: %s' % error)
76
77     def base_url(self):
78         return "http://%s:%d" % (self._ip, self._server_port)
79
80     def fetch_result(self):
81         (stdout, stderr) = self._server_process.communicate()
82         print stderr
83         return stdout
84
85     def kill_server(self):
86         try:
87             if self._server_process.poll() is None:
88                 self._server_process.terminate()
89         except OSError as error:
90             _log.info('Error terminating server process: %s' % (error))
91
92     def get_return_code(self):
93         return self._server_process.returncode
94
95     def set_device_id(self, device_id):
96         pass
97
98     def _ensure_http_server_dependencies(self):
99         _log.info('Ensure dependencies of http server is satisfied')
100         from pkg_resources import require, VersionConflict, DistributionNotFound
101         try:
102             require("Twisted>=15.5.0")
103             import twisted
104         except (ImportError, VersionConflict, DistributionNotFound):
105             _log.info("Will install twisted in webkitpy, and twisted will be used by webkitpy only")
106             sys.path.append(os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '../../../..')))
107             from webkitpy.thirdparty.autoinstalled.twisted_15_5_0 import twisted