195 lines
7.9 KiB
Python
195 lines
7.9 KiB
Python
|
# Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||
|
# Use of this source code is governed by a BSD-style license that can be
|
||
|
# found in the LICENSE file.
|
||
|
"""Platform-specific utility methods shared by several scripts."""
|
||
|
|
||
|
import os
|
||
|
import re
|
||
|
import subprocess
|
||
|
import sys
|
||
|
|
||
|
import google.path_utils
|
||
|
|
||
|
# Cache a single cygpath process for use throughout, even across instances of
|
||
|
# the PlatformUtility class.
|
||
|
_cygpath_proc = None
|
||
|
|
||
|
class PlatformUtility(object):
|
||
|
def __init__(self, base_dir):
|
||
|
"""Args:
|
||
|
base_dir: a directory above which third_party/cygwin can be found,
|
||
|
used to locate the cygpath executable for path conversions.
|
||
|
"""
|
||
|
self._cygwin_root = None
|
||
|
self._base_dir = base_dir
|
||
|
|
||
|
def _CygwinRoot(self):
|
||
|
"""Returns the full path to third_party/cygwin/."""
|
||
|
if not self._cygwin_root:
|
||
|
self._cygwin_root = google.path_utils.FindUpward(self._base_dir,
|
||
|
'third_party', 'cygwin')
|
||
|
return self._cygwin_root
|
||
|
|
||
|
def _PathToExecutable(self, executable):
|
||
|
"""Returns the full path to an executable in Cygwin's bin dir."""
|
||
|
return os.path.join(self._CygwinRoot(), 'bin', executable)
|
||
|
|
||
|
def GetAbsolutePath(self, path, force=False):
|
||
|
"""Returns an absolute windows path. If platform is cygwin, converts it to
|
||
|
windows style using cygpath.
|
||
|
|
||
|
For performance reasons, we use a single cygpath process, shared among all
|
||
|
instances of this class. Otherwise Python can run out of file handles.
|
||
|
"""
|
||
|
if not force and sys.platform != "cygwin":
|
||
|
return os.path.abspath(path)
|
||
|
global _cygpath_proc
|
||
|
if not _cygpath_proc:
|
||
|
cygpath_command = [self._PathToExecutable("cygpath.exe"),
|
||
|
"-a", "-m", "-f", "-"]
|
||
|
_cygpath_proc = subprocess.Popen(cygpath_command,
|
||
|
stdin=subprocess.PIPE,
|
||
|
stdout=subprocess.PIPE)
|
||
|
_cygpath_proc.stdin.write(path + "\n")
|
||
|
return _cygpath_proc.stdout.readline().rstrip()
|
||
|
|
||
|
def GetFilesystemRoot(self):
|
||
|
"""Returns the root directory of the file system."""
|
||
|
return os.environ['SYSTEMDRIVE'] + '\\'
|
||
|
|
||
|
def GetTempDirectory(self):
|
||
|
"""Returns the file system's base temp directory, or the filesystem root
|
||
|
if the standard temp directory can't be determined.
|
||
|
|
||
|
Note that this does not use a random subdirectory, so it's not
|
||
|
intrinsically secure. If you need a secure subdir, use the tempfile
|
||
|
package.
|
||
|
"""
|
||
|
return os.environ.get('TEMP', self.GetFilesystemRoot())
|
||
|
|
||
|
def FilenameToUri(self, path, use_http=False, use_ssl=False, port=8000):
|
||
|
"""Convert a Windows style path to a URI.
|
||
|
|
||
|
Args:
|
||
|
path: For an http URI, the path relative to the httpd server's
|
||
|
DocumentRoot; for a file URI, the full path to the file.
|
||
|
use_http: if True, returns a URI of the form http://127.0.0.1:8000/.
|
||
|
If False, returns a file:/// URI.
|
||
|
use_ssl: if True, returns HTTPS URL (https://127.0.0.1:8000/).
|
||
|
This parameter is ignored if use_http=False.
|
||
|
port: The port number to append when returning an HTTP URI
|
||
|
"""
|
||
|
if use_http:
|
||
|
protocol = 'http'
|
||
|
if use_ssl:
|
||
|
protocol = 'https'
|
||
|
path = path.replace("\\", "/")
|
||
|
return "%s://127.0.0.1:%s/%s" % (protocol, str(port), path)
|
||
|
return "file:///" + self.GetAbsolutePath(path)
|
||
|
|
||
|
def GetStartHttpdCommand(self, output_dir,
|
||
|
httpd_conf_path, mime_types_path,
|
||
|
document_root=None, apache2=False):
|
||
|
"""Prepares the config file and output directory to start an httpd server.
|
||
|
Returns a list of strings containing the server's command line+args.
|
||
|
|
||
|
Args:
|
||
|
output_dir: the path to the server's output directory, for log files.
|
||
|
It will be created if necessary.
|
||
|
httpd_conf_path: full path to the httpd.conf file to be used.
|
||
|
mime_types_path: full path to the mime.types file to be used.
|
||
|
document_root: full path to the DocumentRoot. If None, the DocumentRoot
|
||
|
from the httpd.conf file will be used. Note that the httpd.conf
|
||
|
file alongside this script does not specify any DocumentRoot, so if
|
||
|
you're using that one, be sure to specify a document_root here.
|
||
|
apache2: boolean if true will cause this function to return start
|
||
|
command for Apache 2.x as opposed to Apache 1.3.x
|
||
|
"""
|
||
|
|
||
|
if document_root:
|
||
|
document_root = GetCygwinPath(document_root)
|
||
|
exe_name = "httpd"
|
||
|
cert_file = ""
|
||
|
if apache2:
|
||
|
exe_name = "httpd2"
|
||
|
cert_file = google.path_utils.FindUpward(self._base_dir, 'tools',
|
||
|
'python', 'google',
|
||
|
'httpd_config', 'httpd2.pem')
|
||
|
httpd_vars = {
|
||
|
"httpd_executable_path": GetCygwinPath(
|
||
|
os.path.join(self._CygwinRoot(), "usr", "sbin", exe_name)),
|
||
|
"httpd_conf_path": GetCygwinPath(httpd_conf_path),
|
||
|
"ssl_certificate_file": GetCygwinPath(cert_file),
|
||
|
"document_root" : document_root,
|
||
|
"server_root": GetCygwinPath(os.path.join(self._CygwinRoot(), "usr")),
|
||
|
"mime_types_path": GetCygwinPath(mime_types_path),
|
||
|
"output_dir": GetCygwinPath(output_dir),
|
||
|
"bindir": GetCygwinPath(os.path.join(self._CygwinRoot(), "bin")),
|
||
|
"user": os.environ.get("USERNAME", os.environ.get("USER", "")),
|
||
|
}
|
||
|
if not httpd_vars["user"]:
|
||
|
# Failed to get the username from the environment; use whoami.exe
|
||
|
# instead.
|
||
|
proc = subprocess.Popen(self._PathToExecutable("whoami.exe"),
|
||
|
stdout=subprocess.PIPE)
|
||
|
httpd_vars["user"] = proc.stdout.read().strip()
|
||
|
|
||
|
if not httpd_vars["user"]:
|
||
|
raise Exception("Failed to get username.")
|
||
|
|
||
|
google.path_utils.MaybeMakeDirectory(output_dir)
|
||
|
|
||
|
# We have to wrap the command in bash because the cygwin environment
|
||
|
# is required for httpd to run.
|
||
|
# -C: process directive before reading config files
|
||
|
# -c: process directive after reading config files
|
||
|
# Apache wouldn't run CGIs with permissions==700 unless we add
|
||
|
# -c User "<username>"
|
||
|
bash = self._PathToExecutable("bash.exe")
|
||
|
httpd_cmd_string = (
|
||
|
' PATH=%(bindir)s %(httpd_executable_path)s'
|
||
|
' -f %(httpd_conf_path)s'
|
||
|
' -c \'TypesConfig "%(mime_types_path)s"\''
|
||
|
' -c \'CustomLog "%(output_dir)s/access_log.txt" common\''
|
||
|
' -c \'ErrorLog "%(output_dir)s/error_log.txt"\''
|
||
|
' -c \'PidFile "%(output_dir)s/httpd.pid"\''
|
||
|
' -C \'User "%(user)s"\''
|
||
|
' -C \'ServerRoot "%(server_root)s"\''
|
||
|
)
|
||
|
if apache2:
|
||
|
httpd_cmd_string = ('export CYGWIN=server;' + httpd_cmd_string +
|
||
|
' -c \'SSLCertificateFile "%(ssl_certificate_file)s"\'')
|
||
|
if document_root:
|
||
|
httpd_cmd_string += ' -C \'DocumentRoot "%(document_root)s"\''
|
||
|
|
||
|
httpd_cmd = [bash, "-c", httpd_cmd_string % httpd_vars]
|
||
|
return httpd_cmd
|
||
|
|
||
|
def GetStopHttpdCommand(self):
|
||
|
"""Returns a list of strings that contains the command line+args needed to
|
||
|
stop the http server used in the http tests.
|
||
|
"""
|
||
|
# Force kill (/f) *all* httpd processes. This has the side effect of
|
||
|
# killing httpd processes that we didn't start.
|
||
|
return ["taskkill.exe", "/f", "/im", "httpd*"]
|
||
|
|
||
|
###########################################################################
|
||
|
# This method is specific to windows, expected to be used only by *_win.py
|
||
|
# files.
|
||
|
|
||
|
def GetCygwinPath(path):
|
||
|
"""Convert a Windows path to a cygwin path.
|
||
|
|
||
|
The cygpath utility insists on converting paths that it thinks are Cygwin
|
||
|
root paths to what it thinks the correct roots are. So paths such as
|
||
|
"C:\b\slave\webkit-release-kjs\build\third_party\cygwin\bin" are converted to
|
||
|
plain "/usr/bin". To avoid this, we do the conversion manually.
|
||
|
|
||
|
The path is expected to be an absolute path, on any drive.
|
||
|
"""
|
||
|
drive_regexp = re.compile(r'([a-z]):[/\\]', re.IGNORECASE)
|
||
|
def LowerDrive(matchobj):
|
||
|
return '/cygdrive/%s/' % matchobj.group(1).lower()
|
||
|
path = drive_regexp.sub(LowerDrive, path)
|
||
|
return path.replace('\\', '/')
|