|  | # 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('\\', '/') |