| #!/usr/bin/env python |
| |
| import logging |
| import os |
| import re |
| import socket |
| import subprocess |
| import sys |
| import time |
| |
| from webkitpy.benchmark_runner.http_server_driver.http_server_driver import HTTPServerDriver |
| |
| |
| _log = logging.getLogger(__name__) |
| |
| |
| class SimpleHTTPServerDriver(HTTPServerDriver): |
| |
| """This class depends on unix environment, need to be modified to achieve crossplatform compability |
| """ |
| |
| platforms = ['osx', 'linux'] |
| |
| def __init__(self): |
| self._server_process = None |
| self._server_port = 0 |
| self._ip = '127.0.0.1' |
| self._ensure_http_server_dependencies() |
| |
| def serve(self, web_root): |
| _log.info('Launching an http server') |
| http_server_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "http_server/twisted_http_server.py") |
| interface_args = [] |
| if self._ip: |
| interface_args.extend(['--interface', self._ip]) |
| self._server_process = subprocess.Popen(["python", http_server_path, web_root] + interface_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
| |
| max_attempt = 5 |
| interval = 0.5 |
| _log.info('Start to fetching the port number of the http server') |
| try: |
| import psutil |
| for attempt in xrange(max_attempt): |
| connections = psutil.Process(self._server_process.pid).connections() |
| if connections and connections[0].laddr and connections[0].laddr[1] and connections[0].status == 'LISTEN': |
| self._server_port = connections[0].laddr[1] |
| _log.info('HTTP Server is serving at port: %d', self._server_port) |
| break |
| _log.info('Server port is not found this time, retry after %f seconds' % interval) |
| time.sleep(interval) |
| interval *= 2 |
| else: |
| raise Exception("Server is not listening on port, max tries exceeded. HTTP server may be installing dependent modules.") |
| except ImportError: |
| for attempt in xrange(max_attempt): |
| try: |
| output = subprocess.check_output(['/usr/sbin/lsof', '-a', '-P', '-iTCP', '-sTCP:LISTEN', '-p', str(self._server_process.pid)]) |
| self._server_port = int(re.search('TCP .*:(\d+) \(LISTEN\)', output).group(1)) |
| if self._server_port: |
| _log.info('HTTP Server is serving at port: %d', self._server_port) |
| break |
| except Exception as error: |
| _log.info('Error: %s' % error) |
| _log.info('Server port is not found this time, retry after %f seconds' % interval) |
| time.sleep(interval) |
| interval *= 2 |
| else: |
| raise Exception("Cannot listen to server, max tries exceeded") |
| self._wait_for_http_server() |
| |
| def _wait_for_http_server(self): |
| max_attempt = 5 |
| # Wait for server to be up completely before exiting |
| for attempt in xrange(max_attempt): |
| try: |
| subprocess.check_call(["curl", "--silent", "--head", "--fail", "--output", "/dev/null", self.base_url()]) |
| return |
| except Exception as error: |
| _log.info('Server not running yet: %s' % error) |
| time.sleep(1) |
| raise Exception('Server not running, max tries exceeded: %s' % error) |
| |
| def base_url(self): |
| return "http://%s:%d" % (self._ip, self._server_port) |
| |
| def fetch_result(self): |
| (stdout, stderr) = self._server_process.communicate() |
| print(stderr) |
| return stdout |
| |
| def kill_server(self): |
| try: |
| if not self._server_process: |
| return |
| if self._server_process.poll() is None: |
| self._server_process.terminate() |
| except OSError as error: |
| _log.info('Error terminating server process: %s' % (error)) |
| |
| def get_return_code(self): |
| return self._server_process.returncode |
| |
| def set_device_id(self, device_id): |
| pass |
| |
| def _ensure_http_server_dependencies(self): |
| _log.info('Ensure dependencies of http server is satisfied') |
| from pkg_resources import require, VersionConflict, DistributionNotFound |
| try: |
| require("Twisted>=15.5.0") |
| import twisted |
| except (ImportError, VersionConflict, DistributionNotFound): |
| _log.info("Will install twisted in webkitpy, and twisted will be used by webkitpy only") |
| sys.path.append(os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '../../../..'))) |
| from webkitpy.thirdparty.autoinstalled.twisted_15_5_0 import twisted |