[email protected] | cb155a8 | 2011-11-29 17:25:34 | [diff] [blame] | 1 | # Copyright (c) 2011 The Chromium Authors. All rights reserved. |
license.bot | bf09a50 | 2008-08-24 00:55:55 | [diff] [blame] | 2 | # Use of this source code is governed by a BSD-style license that can be |
| 3 | # found in the LICENSE file. |
initial.commit | 920c091 | 2008-07-27 00:12:16 | [diff] [blame] | 4 | """Platform-specific utility methods shared by several scripts.""" |
| 5 | |
| 6 | import os |
| 7 | import re |
| 8 | import subprocess |
| 9 | import sys |
| 10 | |
| 11 | import google.path_utils |
| 12 | |
| 13 | # Cache a single cygpath process for use throughout, even across instances of |
| 14 | # the PlatformUtility class. |
| 15 | _cygpath_proc = None |
| 16 | |
| 17 | class PlatformUtility(object): |
| 18 | def __init__(self, base_dir): |
| 19 | """Args: |
| 20 | base_dir: a directory above which third_party/cygwin can be found, |
| 21 | used to locate the cygpath executable for path conversions. |
| 22 | """ |
| 23 | self._cygwin_root = None |
| 24 | self._base_dir = base_dir |
| 25 | |
| 26 | def _CygwinRoot(self): |
| 27 | """Returns the full path to third_party/cygwin/.""" |
| 28 | if not self._cygwin_root: |
| 29 | self._cygwin_root = google.path_utils.FindUpward(self._base_dir, |
| 30 | 'third_party', 'cygwin') |
| 31 | return self._cygwin_root |
| 32 | |
| 33 | def _PathToExecutable(self, executable): |
| 34 | """Returns the full path to an executable in Cygwin's bin dir.""" |
| 35 | return os.path.join(self._CygwinRoot(), 'bin', executable) |
| 36 | |
| 37 | def GetAbsolutePath(self, path, force=False): |
| 38 | """Returns an absolute windows path. If platform is cygwin, converts it to |
| 39 | windows style using cygpath. |
| 40 | |
| 41 | For performance reasons, we use a single cygpath process, shared among all |
| 42 | instances of this class. Otherwise Python can run out of file handles. |
| 43 | """ |
| 44 | if not force and sys.platform != "cygwin": |
| 45 | return os.path.abspath(path) |
| 46 | global _cygpath_proc |
| 47 | if not _cygpath_proc: |
| 48 | cygpath_command = [self._PathToExecutable("cygpath.exe"), |
| 49 | "-a", "-m", "-f", "-"] |
| 50 | _cygpath_proc = subprocess.Popen(cygpath_command, |
| 51 | stdin=subprocess.PIPE, |
| 52 | stdout=subprocess.PIPE) |
| 53 | _cygpath_proc.stdin.write(path + "\n") |
| 54 | return _cygpath_proc.stdout.readline().rstrip() |
| 55 | |
| 56 | def GetFilesystemRoot(self): |
| 57 | """Returns the root directory of the file system.""" |
| 58 | return os.environ['SYSTEMDRIVE'] + '\\' |
| 59 | |
| 60 | def GetTempDirectory(self): |
| 61 | """Returns the file system's base temp directory, or the filesystem root |
| 62 | if the standard temp directory can't be determined. |
| 63 | |
| 64 | Note that this does not use a random subdirectory, so it's not |
| 65 | intrinsically secure. If you need a secure subdir, use the tempfile |
| 66 | package. |
| 67 | """ |
| 68 | return os.environ.get('TEMP', self.GetFilesystemRoot()) |
| 69 | |
| 70 | def FilenameToUri(self, path, use_http=False, use_ssl=False, port=8000): |
| 71 | """Convert a Windows style path to a URI. |
| 72 | |
| 73 | Args: |
| 74 | path: For an http URI, the path relative to the httpd server's |
| 75 | DocumentRoot; for a file URI, the full path to the file. |
| 76 | use_http: if True, returns a URI of the form http://127.0.0.1:8000/. |
| 77 | If False, returns a file:/// URI. |
| 78 | use_ssl: if True, returns HTTPS URL (https://127.0.0.1:8000/). |
| 79 | This parameter is ignored if use_http=False. |
| 80 | port: The port number to append when returning an HTTP URI |
| 81 | """ |
| 82 | if use_http: |
| 83 | protocol = 'http' |
| 84 | if use_ssl: |
| 85 | protocol = 'https' |
| 86 | path = path.replace("\\", "/") |
| 87 | return "%s://127.0.0.1:%s/%s" % (protocol, str(port), path) |
| 88 | return "file:///" + self.GetAbsolutePath(path) |
| 89 | |
| 90 | def GetStartHttpdCommand(self, output_dir, |
| 91 | httpd_conf_path, mime_types_path, |
| 92 | document_root=None, apache2=False): |
| 93 | """Prepares the config file and output directory to start an httpd server. |
| 94 | Returns a list of strings containing the server's command line+args. |
| 95 | |
| 96 | Args: |
| 97 | output_dir: the path to the server's output directory, for log files. |
| 98 | It will be created if necessary. |
| 99 | httpd_conf_path: full path to the httpd.conf file to be used. |
| 100 | mime_types_path: full path to the mime.types file to be used. |
| 101 | document_root: full path to the DocumentRoot. If None, the DocumentRoot |
| 102 | from the httpd.conf file will be used. Note that the httpd.conf |
| 103 | file alongside this script does not specify any DocumentRoot, so if |
| 104 | you're using that one, be sure to specify a document_root here. |
| 105 | apache2: boolean if true will cause this function to return start |
| 106 | command for Apache 2.x as opposed to Apache 1.3.x |
| 107 | """ |
| 108 | |
| 109 | if document_root: |
| 110 | document_root = GetCygwinPath(document_root) |
| 111 | exe_name = "httpd" |
| 112 | cert_file = "" |
| 113 | if apache2: |
| 114 | exe_name = "httpd2" |
| 115 | cert_file = google.path_utils.FindUpward(self._base_dir, 'tools', |
| 116 | 'python', 'google', |
| 117 | 'httpd_config', 'httpd2.pem') |
| 118 | httpd_vars = { |
| 119 | "httpd_executable_path": GetCygwinPath( |
| 120 | os.path.join(self._CygwinRoot(), "usr", "sbin", exe_name)), |
| 121 | "httpd_conf_path": GetCygwinPath(httpd_conf_path), |
| 122 | "ssl_certificate_file": GetCygwinPath(cert_file), |
| 123 | "document_root" : document_root, |
| 124 | "server_root": GetCygwinPath(os.path.join(self._CygwinRoot(), "usr")), |
| 125 | "mime_types_path": GetCygwinPath(mime_types_path), |
| 126 | "output_dir": GetCygwinPath(output_dir), |
| 127 | "bindir": GetCygwinPath(os.path.join(self._CygwinRoot(), "bin")), |
| 128 | "user": os.environ.get("USERNAME", os.environ.get("USER", "")), |
| 129 | } |
| 130 | if not httpd_vars["user"]: |
| 131 | # Failed to get the username from the environment; use whoami.exe |
| 132 | # instead. |
| 133 | proc = subprocess.Popen(self._PathToExecutable("whoami.exe"), |
| 134 | stdout=subprocess.PIPE) |
| 135 | httpd_vars["user"] = proc.stdout.read().strip() |
| 136 | |
| 137 | if not httpd_vars["user"]: |
| 138 | raise Exception("Failed to get username.") |
| 139 | |
| 140 | google.path_utils.MaybeMakeDirectory(output_dir) |
| 141 | |
| 142 | # We have to wrap the command in bash because the cygwin environment |
| 143 | # is required for httpd to run. |
| 144 | # -C: process directive before reading config files |
| 145 | # -c: process directive after reading config files |
| 146 | # Apache wouldn't run CGIs with permissions==700 unless we add |
| 147 | # -c User "<username>" |
| 148 | bash = self._PathToExecutable("bash.exe") |
| 149 | httpd_cmd_string = ( |
| 150 | ' PATH=%(bindir)s %(httpd_executable_path)s' |
| 151 | ' -f %(httpd_conf_path)s' |
| 152 | ' -c \'TypesConfig "%(mime_types_path)s"\'' |
| 153 | ' -c \'CustomLog "%(output_dir)s/access_log.txt" common\'' |
| 154 | ' -c \'ErrorLog "%(output_dir)s/error_log.txt"\'' |
| 155 | ' -c \'PidFile "%(output_dir)s/httpd.pid"\'' |
| 156 | ' -C \'User "%(user)s"\'' |
| 157 | ' -C \'ServerRoot "%(server_root)s"\'' |
| 158 | ) |
| 159 | if apache2: |
[email protected] | f0a51fb5 | 2009-03-05 12:46:38 | [diff] [blame] | 160 | httpd_cmd_string = ('export CYGWIN=server;' + httpd_cmd_string + |
initial.commit | 920c091 | 2008-07-27 00:12:16 | [diff] [blame] | 161 | ' -c \'SSLCertificateFile "%(ssl_certificate_file)s"\'') |
| 162 | if document_root: |
| 163 | httpd_cmd_string += ' -C \'DocumentRoot "%(document_root)s"\'' |
| 164 | |
| 165 | httpd_cmd = [bash, "-c", httpd_cmd_string % httpd_vars] |
| 166 | return httpd_cmd |
| 167 | |
| 168 | def GetStopHttpdCommand(self): |
| 169 | """Returns a list of strings that contains the command line+args needed to |
| 170 | stop the http server used in the http tests. |
| 171 | """ |
| 172 | # Force kill (/f) *all* httpd processes. This has the side effect of |
| 173 | # killing httpd processes that we didn't start. |
| 174 | return ["taskkill.exe", "/f", "/im", "httpd*"] |
| 175 | |
| 176 | ########################################################################### |
| 177 | # This method is specific to windows, expected to be used only by *_win.py |
| 178 | # files. |
| 179 | |
| 180 | def GetCygwinPath(path): |
| 181 | """Convert a Windows path to a cygwin path. |
| 182 | |
| 183 | The cygpath utility insists on converting paths that it thinks are Cygwin |
| 184 | root paths to what it thinks the correct roots are. So paths such as |
| 185 | "C:\b\slave\webkit-release-kjs\build\third_party\cygwin\bin" are converted to |
| 186 | plain "/usr/bin". To avoid this, we do the conversion manually. |
| 187 | |
| 188 | The path is expected to be an absolute path, on any drive. |
| 189 | """ |
| 190 | drive_regexp = re.compile(r'([a-z]):[/\\]', re.IGNORECASE) |
| 191 | def LowerDrive(matchobj): |
| 192 | return '/cygdrive/%s/' % matchobj.group(1).lower() |
| 193 | path = drive_regexp.sub(LowerDrive, path) |
| 194 | return path.replace('\\', '/') |