2010-04-28 Eric Seidel <eric@webkit.org>
[WebKit-https.git] / WebKitTools / Scripts / webkitpy / layout_tests / port / http_server.py
index 99e2ea1..fbe47e3 100755 (executable)
@@ -29,7 +29,9 @@
 
 """A class to help start/stop the lighttpd server used by layout tests."""
 
+from __future__ import with_statement
 
+import codecs
 import logging
 import optparse
 import os
@@ -40,53 +42,25 @@ import tempfile
 import time
 import urllib
 
+import factory
 import http_server_base
-import path_utils
 
-class HttpdNotStarted(Exception): pass
+_log = logging.getLogger("webkitpy.layout_tests.port.http_server")
 
-def remove_log_files(folder, starts_with):
-    files = os.listdir(folder)
-    for file in files:
-        if file.startswith(starts_with):
-            full_path = os.path.join(folder, file)
-            os.remove(full_path)
+
+class HttpdNotStarted(Exception):
+    pass
 
 
 class Lighttpd(http_server_base.HttpServerBase):
-    # Webkit tests
-    try:
-        _webkit_tests = path_utils.path_from_base('third_party', 'WebKit',
-                                                  'LayoutTests', 'http',
-                                                  'tests')
-        _js_test_resource = path_utils.path_from_base('third_party', 'WebKit',
-                                                      'LayoutTests', 'fast',
-                                                      'js', 'resources')
-    except path_utils.PathNotFound:
-        _webkit_tests = None
-        _js_test_resource = None
-
-    # Path where we can access all of the tests
-    _all_tests = path_utils.path_from_base('webkit', 'data', 'layout_tests')
-    # Self generated certificate for SSL server (for client cert get
-    # <base-path>\chrome\test\data\ssl\certs\root_ca_cert.crt)
-    _pem_file = path_utils.path_from_base(
-        os.path.dirname(os.path.abspath(__file__)), 'httpd2.pem')
-    # One mapping where we can get to everything
-    VIRTUALCONFIG = [{'port': 8081, 'docroot': _all_tests}]
-
-    if _webkit_tests:
-        VIRTUALCONFIG.extend(
-          # Three mappings (one with SSL enabled) for LayoutTests http tests
-          [{'port': 8000, 'docroot': _webkit_tests},
-           {'port': 8080, 'docroot': _webkit_tests},
-           {'port': 8443, 'docroot': _webkit_tests, 'sslcert': _pem_file}])
-
-    def __init__(self, output_dir, background=False, port=None,
+
+    def __init__(self, port_obj, output_dir, background=False, port=None,
                  root=None, register_cygwin=None, run_background=None):
         """Args:
           output_dir: the absolute path to the layout test result directory
         """
+        # Webkit tests
+        http_server_base.HttpServerBase.__init__(self, port_obj)
         self._output_dir = output_dir
         self._process = None
         self._port = port
@@ -96,6 +70,31 @@ class Lighttpd(http_server_base.HttpServerBase):
         if self._port:
             self._port = int(self._port)
 
+        try:
+            self._webkit_tests = os.path.join(
+                self._port_obj.layout_tests_dir(), 'http', 'tests')
+            self._js_test_resource = os.path.join(
+                self._port_obj.layout_tests_dir(), 'fast', 'js', 'resources')
+        except:
+            self._webkit_tests = None
+            self._js_test_resource = None
+
+        # Self generated certificate for SSL server (for client cert get
+        # <base-path>\chrome\test\data\ssl\certs\root_ca_cert.crt)
+        self._pem_file = os.path.join(
+            os.path.dirname(os.path.abspath(__file__)), 'httpd2.pem')
+
+        # One mapping where we can get to everything
+        self.VIRTUALCONFIG = []
+
+        if self._webkit_tests:
+            self.VIRTUALCONFIG.extend(
+               # Three mappings (one with SSL) for LayoutTests http tests
+               [{'port': 8000, 'docroot': self._webkit_tests},
+                {'port': 8080, 'docroot': self._webkit_tests},
+                {'port': 8443, 'docroot': self._webkit_tests,
+                 'sslcert': self._pem_file}])
+
     def is_running(self):
         return self._process != None
 
@@ -103,9 +102,8 @@ class Lighttpd(http_server_base.HttpServerBase):
         if self.is_running():
             raise 'Lighttpd already running'
 
-        base_conf_file = path_utils.path_from_base('third_party',
-            'WebKitTools', 'Scripts', 'webkitpy', 'layout_tests',
-            'layout_package', 'lighttpd.conf')
+        base_conf_file = self._port_obj.path_from_webkit_base('WebKitTools',
+            'Scripts', 'webkitpy', 'layout_tests', 'port', 'lighttpd.conf')
         out_conf_file = os.path.join(self._output_dir, 'lighttpd.conf')
         time_str = time.strftime("%d%b%Y-%H%M%S")
         access_file_name = "access.log-" + time_str + ".txt"
@@ -114,15 +112,18 @@ class Lighttpd(http_server_base.HttpServerBase):
         error_log = os.path.join(self._output_dir, log_file_name)
 
         # Remove old log files. We only need to keep the last ones.
-        remove_log_files(self._output_dir, "access.log-")
-        remove_log_files(self._output_dir, "error.log-")
+        self.remove_log_files(self._output_dir, "access.log-")
+        self.remove_log_files(self._output_dir, "error.log-")
 
         # Write out the config
-        f = file(base_conf_file, 'rb')
-        base_conf = f.read()
-        f.close()
-
-        f = file(out_conf_file, 'wb')
+        with codecs.open(base_conf_file, "r", "utf-8") as file:
+            base_conf = file.read()
+
+        # FIXME: This should be re-worked so that this block can
+        # use with open() instead of a manual file.close() call.
+        # lighttpd.conf files seem to be UTF-8 without BOM:
+        # http://redmine.lighttpd.net/issues/992
+        f = codecs.open(out_conf_file, "w", "utf-8")
         f.write(base_conf)
 
         # Write out our cgi handlers.  Run perl through env so that it
@@ -132,7 +133,7 @@ class Lighttpd(http_server_base.HttpServerBase):
                  '               ".pl"   => "/usr/bin/env",\n'
                  '               ".asis" => "/bin/cat",\n'
                  '               ".php"  => "%s" )\n\n') %
-                                     path_utils.lighttpd_php_path())
+                                     self._port_obj._path_to_lighttpd_php())
 
         # Setup log files
         f.write(('server.errorlog = "%s"\n'
@@ -161,7 +162,7 @@ class Lighttpd(http_server_base.HttpServerBase):
                 mappings = [{'port': 8000, 'docroot': self._root},
                             {'port': 8080, 'docroot': self._root},
                             {'port': 8443, 'docroot': self._root,
-                             'sslcert': Lighttpd._pem_file}]
+                             'sslcert': self._pem_file}]
         else:
             mappings = self.VIRTUALCONFIG
         for mapping in mappings:
@@ -176,12 +177,11 @@ class Lighttpd(http_server_base.HttpServerBase):
                      '}\n\n') % (mapping['port'], mapping['docroot']))
         f.close()
 
-        executable = path_utils.lighttpd_executable_path()
-        module_path = path_utils.lighttpd_module_path()
+        executable = self._port_obj._path_to_lighttpd()
+        module_path = self._port_obj._path_to_lighttpd_modules()
         start_cmd = [executable,
                      # Newly written config file
-                     '-f', path_utils.path_from_base(self._output_dir,
-                                                     'lighttpd.conf'),
+                     '-f', os.path.join(self._output_dir, 'lighttpd.conf'),
                      # Where it can find its module dynamic libraries
                      '-m', module_path]
 
@@ -203,15 +203,18 @@ class Lighttpd(http_server_base.HttpServerBase):
         env = os.environ
         if sys.platform in ('cygwin', 'win32'):
             env['PATH'] = '%s;%s' % (
-                path_utils.path_from_base('third_party', 'cygwin', 'bin'),
+                self._port_obj.path_from_chromium_base('third_party',
+                                                       'cygwin', 'bin'),
                 env['PATH'])
 
         if sys.platform == 'win32' and self._register_cygwin:
-            setup_mount = path_utils.path_from_base('third_party', 'cygwin',
-                                                    'setup_mount.bat')
+            setup_mount = self._port_obj.path_from_chromium_base('third_party',
+                'cygwin', 'setup_mount.bat')
+            # FIXME: Should use Executive.run_command
             subprocess.Popen(setup_mount).wait()
 
-        logging.debug('Starting http server')
+        _log.debug('Starting http server')
+        # FIXME: Should use Executive.run_command
         self._process = subprocess.Popen(start_cmd, env=env)
 
         # Wait for server to start.
@@ -223,7 +226,7 @@ class Lighttpd(http_server_base.HttpServerBase):
         if not server_started or self._process.returncode != None:
             raise google.httpd_utils.HttpdNotStarted('Failed to start httpd.')
 
-        logging.debug("Server successfully started")
+        _log.debug("Server successfully started")
 
     # TODO(deanm): Find a nicer way to shutdown cleanly.  Our log files are
     # probably not being flushed, etc... why doesn't our python have os.kill ?
@@ -235,45 +238,10 @@ class Lighttpd(http_server_base.HttpServerBase):
         httpd_pid = None
         if self._process:
             httpd_pid = self._process.pid
-        path_utils.shut_down_http_server(httpd_pid)
+        self._port_obj._shut_down_http_server(httpd_pid)
 
         if self._process:
+            # wait() is not threadsafe and can throw OSError due to:
+            # http://bugs.python.org/issue1731717
             self._process.wait()
             self._process = None
-
-if '__main__' == __name__:
-    # Provide some command line params for starting/stopping the http server
-    # manually. Also used in ui_tests to run http layout tests in a browser.
-    option_parser = optparse.OptionParser()
-    option_parser.add_option('-k', '--server',
-        help='Server action (start|stop)')
-    option_parser.add_option('-p', '--port',
-        help='Port to listen on (overrides layout test ports)')
-    option_parser.add_option('-r', '--root',
-        help='Absolute path to DocumentRoot (overrides layout test roots)')
-    option_parser.add_option('--register_cygwin', action="store_true",
-        dest="register_cygwin", help='Register Cygwin paths (on Win try bots)')
-    option_parser.add_option('--run_background', action="store_true",
-        dest="run_background",
-        help='Run on background (for running as UI test)')
-    options, args = option_parser.parse_args()
-
-    if not options.server:
-        print ('Usage: %s --server {start|stop} [--root=root_dir]'
-               ' [--port=port_number]' % sys.argv[0])
-    else:
-        if (options.root is None) and (options.port is not None):
-            # specifying root but not port means we want httpd on default
-            # set of ports that LayoutTest use, but pointing to a different
-            # source of tests. Specifying port but no root does not seem
-            # meaningful.
-            raise 'Specifying port requires also a root.'
-        httpd = Lighttpd(tempfile.gettempdir(),
-                         port=options.port,
-                         root=options.root,
-                         register_cygwin=options.register_cygwin,
-                         run_background=options.run_background)
-        if 'start' == options.server:
-            httpd.start()
-        else:
-            httpd.stop(force=True)