|  | # Copyright 2013 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. | 
|  |  | 
|  | """Generic utilities for all python scripts.""" | 
|  |  | 
|  | import atexit | 
|  | import httplib | 
|  | import os | 
|  | import signal | 
|  | import stat | 
|  | import subprocess | 
|  | import sys | 
|  | import tempfile | 
|  | import urlparse | 
|  |  | 
|  |  | 
|  | def GetPlatformName(): | 
|  | """Return a string to be used in paths for the platform.""" | 
|  | if IsWindows(): | 
|  | return 'win' | 
|  | if IsMac(): | 
|  | return 'mac' | 
|  | if IsLinux(): | 
|  | return 'linux' | 
|  | raise NotImplementedError('Unknown platform "%s".' % sys.platform) | 
|  |  | 
|  |  | 
|  | def IsWindows(): | 
|  | return sys.platform == 'cygwin' or sys.platform.startswith('win') | 
|  |  | 
|  |  | 
|  | def IsLinux(): | 
|  | return sys.platform.startswith('linux') | 
|  |  | 
|  |  | 
|  | def IsMac(): | 
|  | return sys.platform.startswith('darwin') | 
|  |  | 
|  |  | 
|  | def _DeleteDir(path): | 
|  | """Deletes a directory recursively, which must exist.""" | 
|  | # Don't use shutil.rmtree because it can't delete read-only files on Win. | 
|  | for root, dirs, files in os.walk(path, topdown=False): | 
|  | for name in files: | 
|  | filename = os.path.join(root, name) | 
|  | os.chmod(filename, stat.S_IWRITE) | 
|  | os.remove(filename) | 
|  | for name in dirs: | 
|  | os.rmdir(os.path.join(root, name)) | 
|  | os.rmdir(path) | 
|  |  | 
|  |  | 
|  | def Delete(path): | 
|  | """Deletes the given file or directory (recursively), which must exist.""" | 
|  | if os.path.isdir(path): | 
|  | _DeleteDir(path) | 
|  | else: | 
|  | os.remove(path) | 
|  |  | 
|  |  | 
|  | def MaybeDelete(path): | 
|  | """Deletes the given file or directory (recurisvely), if it exists.""" | 
|  | if os.path.exists(path): | 
|  | Delete(path) | 
|  |  | 
|  |  | 
|  | def MakeTempDir(parent_dir=None): | 
|  | """Creates a temporary directory and returns an absolute path to it. | 
|  |  | 
|  | The temporary directory is automatically deleted when the python interpreter | 
|  | exits normally. | 
|  |  | 
|  | Args: | 
|  | parent_dir: the directory to create the temp dir in. If None, the system | 
|  | temp dir is used. | 
|  |  | 
|  | Returns: | 
|  | The absolute path to the temporary directory. | 
|  | """ | 
|  | path = tempfile.mkdtemp(dir=parent_dir) | 
|  | atexit.register(MaybeDelete, path) | 
|  | return path | 
|  |  | 
|  |  | 
|  | def Unzip(zip_path, output_dir): | 
|  | """Unzips the given zip file using a system installed unzip tool. | 
|  |  | 
|  | Args: | 
|  | zip_path: zip file to unzip. | 
|  | output_dir: directory to unzip the contents of the zip file. The directory | 
|  | must exist. | 
|  |  | 
|  | Raises: | 
|  | RuntimeError if the unzip operation fails. | 
|  | """ | 
|  | if IsWindows(): | 
|  | unzip_cmd = ['C:\\Program Files\\7-Zip\\7z.exe', 'x', '-y'] | 
|  | else: | 
|  | unzip_cmd = ['unzip', '-o'] | 
|  | unzip_cmd += [zip_path] | 
|  | if RunCommand(unzip_cmd, output_dir) != 0: | 
|  | raise RuntimeError('Unable to unzip %s to %s' % (zip_path, output_dir)) | 
|  |  | 
|  |  | 
|  | def Kill(pid): | 
|  | """Terminate the given pid.""" | 
|  | if IsWindows(): | 
|  | subprocess.call(['taskkill.exe', '/T', '/F', '/PID', str(pid)]) | 
|  | else: | 
|  | os.kill(pid, signal.SIGTERM) | 
|  |  | 
|  |  | 
|  | def RunCommand(cmd, cwd=None): | 
|  | """Runs the given command and returns the exit code. | 
|  |  | 
|  | Args: | 
|  | cmd: list of command arguments. | 
|  | cwd: working directory to execute the command, or None if the current | 
|  | working directory should be used. | 
|  |  | 
|  | Returns: | 
|  | The exit code of the command. | 
|  | """ | 
|  | process = subprocess.Popen(cmd, cwd=cwd) | 
|  | process.wait() | 
|  | return process.returncode | 
|  |  | 
|  |  | 
|  | def DoesUrlExist(url): | 
|  | """Determines whether a resource exists at the given URL. | 
|  |  | 
|  | Args: | 
|  | url: URL to be verified. | 
|  |  | 
|  | Returns: | 
|  | True if url exists, otherwise False. | 
|  | """ | 
|  | parsed = urlparse.urlparse(url) | 
|  | try: | 
|  | conn = httplib.HTTPConnection(parsed.netloc) | 
|  | conn.request('HEAD', parsed.path) | 
|  | response = conn.getresponse() | 
|  | except (socket.gaierror, socket.error): | 
|  | return False | 
|  | finally: | 
|  | conn.close() | 
|  | # Follow both permanent (301) and temporary (302) redirects. | 
|  | if response.status == 302 or response.status == 301: | 
|  | return DoesUrlExist(response.getheader('location')) | 
|  | return response.status == 200 |