OLD | NEW |
1 # Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 #!/usr/bin/python |
| 2 # Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 |
4 """Platform-specific utility methods shared by several scripts.""" | 6 """Platform-specific utility methods shared by several scripts.""" |
5 | 7 |
6 import os | 8 import os |
7 import re | |
8 import subprocess | 9 import subprocess |
9 import sys | |
10 | 10 |
11 import google.path_utils | 11 import google.path_utils |
12 | 12 |
13 # Cache a single cygpath process for use throughout, even across instances of | |
14 # the PlatformUtility class. | |
15 _cygpath_proc = None | |
16 | 13 |
17 class PlatformUtility(object): | 14 class PlatformUtility(object): |
18 def __init__(self, base_dir): | 15 def __init__(self, base_dir): |
19 """Args: | 16 """Args: |
20 base_dir: a directory above which third_party/cygwin can be found, | 17 base_dir: the base dir for running tests. |
21 used to locate the cygpath executable for path conversions. | |
22 """ | 18 """ |
23 self._cygwin_root = None | |
24 self._base_dir = base_dir | 19 self._base_dir = base_dir |
| 20 self._httpd_cmd_string = None # used for starting/stopping httpd |
| 21 self._bash = "/bin/bash" |
25 | 22 |
26 def _CygwinRoot(self): | 23 def _UnixRoot(self): |
27 """Returns the full path to third_party/cygwin/.""" | 24 """Returns the path to root.""" |
28 if not self._cygwin_root: | 25 return "/" |
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 | 26 |
56 def GetFilesystemRoot(self): | 27 def GetFilesystemRoot(self): |
57 """Returns the root directory of the file system.""" | 28 """Returns the root directory of the file system.""" |
58 return os.environ['SYSTEMDRIVE'] + '\\' | 29 return self._UnixRoot() |
59 | 30 |
60 def GetTempDirectory(self): | 31 def GetTempDirectory(self): |
61 """Returns the file system's base temp directory, or the filesystem root | 32 """Returns the file system temp directory |
62 if the standard temp directory can't be determined. | |
63 | 33 |
64 Note that this does not use a random subdirectory, so it's not | 34 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 | 35 intrinsically secure. If you need a secure subdir, use the tempfile |
66 package. | 36 package. |
67 """ | 37 """ |
68 return os.environ.get('TEMP', self.GetFilesystemRoot()) | 38 return os.getenv("TMPDIR", "/tmp") |
69 | 39 |
70 def FilenameToUri(self, path, use_http=False, use_ssl=False, port=8000): | 40 def FilenameToUri(self, path, use_http=False, use_ssl=False, port=8000): |
71 """Convert a Windows style path to a URI. | 41 """Convert a filesystem path to a URI. |
72 | 42 |
73 Args: | 43 Args: |
74 path: For an http URI, the path relative to the httpd server's | 44 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. | 45 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/. | 46 use_http: if True, returns a URI of the form http://127.0.0.1:8000/. |
77 If False, returns a file:/// URI. | 47 If False, returns a file:/// URI. |
78 use_ssl: if True, returns HTTPS URL (https://127.0.0.1:8000/). | 48 use_ssl: if True, returns HTTPS URL (https://127.0.0.1:8000/). |
79 This parameter is ignored if use_http=False. | 49 This parameter is ignored if use_http=False. |
80 port: The port number to append when returning an HTTP URI | 50 port: The port number to append when returning an HTTP URI |
81 """ | 51 """ |
82 if use_http: | 52 if use_http: |
83 protocol = 'http' | 53 protocol = 'http' |
84 if use_ssl: | 54 if use_ssl: |
85 protocol = 'https' | 55 protocol = 'https' |
86 path = path.replace("\\", "/") | 56 return "%s://127.0.0.1:%d/%s" % (protocol, port, path) |
87 return "%s://127.0.0.1:%s/%s" % (protocol, str(port), path) | 57 return "file://" + path |
88 return "file:///" + self.GetAbsolutePath(path) | |
89 | 58 |
90 def GetStartHttpdCommand(self, output_dir, | 59 def GetStartHttpdCommand(self, output_dir, |
91 httpd_conf_path, mime_types_path, | 60 httpd_conf_path, mime_types_path, |
92 document_root=None, apache2=False): | 61 document_root=None, apache2=False): |
93 """Prepares the config file and output directory to start an httpd server. | 62 """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. | 63 Returns a list of strings containing the server's command line+args. |
95 | 64 |
96 Args: | 65 Args: |
97 output_dir: the path to the server's output directory, for log files. | 66 output_dir: the path to the server's output directory, for log files. |
98 It will be created if necessary. | 67 It will be created if necessary. |
99 httpd_conf_path: full path to the httpd.conf file to be used. | 68 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. | 69 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 | 70 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 | 71 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 | 72 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. | 73 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 | 74 apache2: boolean if true will cause this function to return start |
106 command for Apache 2.x as opposed to Apache 1.3.x | 75 command for Apache 2.x as opposed to Apache 1.3.x. This flag |
| 76 is ignored on Mac (but preserved here for compatibility in |
| 77 function signature with win), where httpd2 is used always |
107 """ | 78 """ |
108 | 79 |
109 if document_root: | |
110 document_root = GetCygwinPath(document_root) | |
111 exe_name = "httpd" | 80 exe_name = "httpd" |
112 cert_file = "" | 81 cert_file = google.path_utils.FindUpward(self._base_dir, 'tools', |
113 if apache2: | 82 'python', 'google', |
114 exe_name = "httpd2" | 83 'httpd_config', 'httpd2.pem') |
115 cert_file = google.path_utils.FindUpward(self._base_dir, 'tools', | |
116 'python', 'google', | |
117 'httpd_config', 'httpd2.pem') | |
118 httpd_vars = { | 84 httpd_vars = { |
119 "httpd_executable_path": GetCygwinPath( | 85 "httpd_executable_path": |
120 os.path.join(self._CygwinRoot(), "usr", "sbin", exe_name)), | 86 os.path.join(self._UnixRoot(), "usr", "sbin", exe_name), |
121 "httpd_conf_path": GetCygwinPath(httpd_conf_path), | 87 "httpd_conf_path": httpd_conf_path, |
122 "ssl_certificate_file": GetCygwinPath(cert_file), | 88 "ssl_certificate_file": cert_file, |
123 "document_root" : document_root, | 89 "document_root" : document_root, |
124 "server_root": GetCygwinPath(os.path.join(self._CygwinRoot(), "usr")), | 90 "server_root": os.path.join(self._UnixRoot(), "usr"), |
125 "mime_types_path": GetCygwinPath(mime_types_path), | 91 "mime_types_path": mime_types_path, |
126 "output_dir": GetCygwinPath(output_dir), | 92 "output_dir": output_dir, |
127 "bindir": GetCygwinPath(os.path.join(self._CygwinRoot(), "bin")), | 93 "user": os.environ.get("USER", "#%d" % os.geteuid()), |
128 "user": os.environ.get("USERNAME", os.environ.get("USER", "")), | 94 "lock_file": os.path.join(output_dir, "accept.lock"), |
129 } | 95 } |
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 | 96 |
140 google.path_utils.MaybeMakeDirectory(output_dir) | 97 google.path_utils.MaybeMakeDirectory(output_dir) |
141 | 98 |
142 # We have to wrap the command in bash because the cygwin environment | 99 # We have to wrap the command in bash |
143 # is required for httpd to run. | |
144 # -C: process directive before reading config files | 100 # -C: process directive before reading config files |
145 # -c: process directive after reading config files | 101 # -c: process directive after reading config files |
146 # Apache wouldn't run CGIs with permissions==700 unless we add | 102 # Apache wouldn't run CGIs with permissions==700 unless we add |
147 # -c User "<username>" | 103 # -c User "<username>" |
148 bash = self._PathToExecutable("bash.exe") | |
149 httpd_cmd_string = ( | 104 httpd_cmd_string = ( |
150 ' PATH=%(bindir)s %(httpd_executable_path)s' | 105 '%(httpd_executable_path)s' |
151 ' -f %(httpd_conf_path)s' | 106 ' -f %(httpd_conf_path)s' |
152 ' -c \'TypesConfig "%(mime_types_path)s"\'' | 107 ' -c \'TypesConfig "%(mime_types_path)s"\'' |
153 ' -c \'CustomLog "%(output_dir)s/access_log.txt" common\'' | 108 ' -c \'CustomLog "%(output_dir)s/access_log.txt" common\'' |
154 ' -c \'ErrorLog "%(output_dir)s/error_log.txt"\'' | 109 ' -c \'ErrorLog "%(output_dir)s/error_log.txt"\'' |
155 ' -c \'PidFile "%(output_dir)s/httpd.pid"\'' | 110 ' -c \'PidFile "%(output_dir)s/httpd.pid"\'' |
156 ' -C \'User "%(user)s"\'' | 111 ' -C \'User "%(user)s"\'' |
157 ' -C \'ServerRoot "%(server_root)s"\'' | 112 ' -C \'ServerRoot "%(server_root)s"\'' |
| 113 ' -c \'LockFile "%(lock_file)s"\'' |
| 114 ' -c \'SSLCertificateFile "%(ssl_certificate_file)s"\'' |
158 ) | 115 ) |
159 if apache2: | 116 |
160 httpd_cmd_string = ('export CYGWIN=server;' + httpd_cmd_string + | |
161 ' -c \'SSLCertificateFile "%(ssl_certificate_file)s"\'') | |
162 if document_root: | 117 if document_root: |
163 httpd_cmd_string += ' -C \'DocumentRoot "%(document_root)s"\'' | 118 httpd_cmd_string += ' -C \'DocumentRoot "%(document_root)s"\'' |
| 119 # Save a copy of httpd_cmd_string to use for stopping httpd |
| 120 self._httpd_cmd_string = httpd_cmd_string % httpd_vars |
164 | 121 |
165 httpd_cmd = [bash, "-c", httpd_cmd_string % httpd_vars] | 122 httpd_cmd = [self._bash, "-c", self._httpd_cmd_string] |
166 return httpd_cmd | 123 return httpd_cmd |
167 | 124 |
168 def GetStopHttpdCommand(self): | 125 def GetStopHttpdCommand(self): |
169 """Returns a list of strings that contains the command line+args needed to | 126 """Returns a list of strings that contains the command line+args needed to |
170 stop the http server used in the http tests. | 127 stop the http server used in the http tests. |
| 128 |
| 129 This tries to fetch the pid of httpd (if available) and returns the |
| 130 command to kill it. If pid is not available, kill all httpd processes |
171 """ | 131 """ |
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 | 132 |
176 ########################################################################### | 133 if not self._httpd_cmd_string: |
177 # This method is specific to windows, expected to be used only by *_win.py | 134 return ["true"] # Haven't been asked for the start cmd yet. Just pass. |
178 # files. | 135 return [self._bash, "-c", self._httpd_cmd_string + ' -k stop'] |
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('\\', '/') | |
195 | |
OLD | NEW |