1# Copyright 2013 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5"""Generic utilities for all python scripts.""" 6 7import atexit 8import httplib 9import os 10import signal 11import stat 12import subprocess 13import sys 14import tempfile 15import urlparse 16 17 18def GetPlatformName(): 19 """Return a string to be used in paths for the platform.""" 20 if IsWindows(): 21 return 'win' 22 if IsMac(): 23 return 'mac' 24 if IsLinux(): 25 return 'linux' 26 raise NotImplementedError('Unknown platform "%s".' % sys.platform) 27 28 29def IsWindows(): 30 return sys.platform == 'cygwin' or sys.platform.startswith('win') 31 32 33def IsLinux(): 34 return sys.platform.startswith('linux') 35 36 37def IsMac(): 38 return sys.platform.startswith('darwin') 39 40 41def _DeleteDir(path): 42 """Deletes a directory recursively, which must exist.""" 43 # Don't use shutil.rmtree because it can't delete read-only files on Win. 44 for root, dirs, files in os.walk(path, topdown=False): 45 for name in files: 46 filename = os.path.join(root, name) 47 os.chmod(filename, stat.S_IWRITE) 48 os.remove(filename) 49 for name in dirs: 50 os.rmdir(os.path.join(root, name)) 51 os.rmdir(path) 52 53 54def Delete(path): 55 """Deletes the given file or directory (recursively), which must exist.""" 56 if os.path.isdir(path): 57 _DeleteDir(path) 58 else: 59 os.remove(path) 60 61 62def MaybeDelete(path): 63 """Deletes the given file or directory (recurisvely), if it exists.""" 64 if os.path.exists(path): 65 Delete(path) 66 67 68def MakeTempDir(parent_dir=None): 69 """Creates a temporary directory and returns an absolute path to it. 70 71 The temporary directory is automatically deleted when the python interpreter 72 exits normally. 73 74 Args: 75 parent_dir: the directory to create the temp dir in. If None, the system 76 temp dir is used. 77 78 Returns: 79 The absolute path to the temporary directory. 80 """ 81 path = tempfile.mkdtemp(dir=parent_dir) 82 atexit.register(MaybeDelete, path) 83 return path 84 85 86def Unzip(zip_path, output_dir): 87 """Unzips the given zip file using a system installed unzip tool. 88 89 Args: 90 zip_path: zip file to unzip. 91 output_dir: directory to unzip the contents of the zip file. The directory 92 must exist. 93 94 Raises: 95 RuntimeError if the unzip operation fails. 96 """ 97 if IsWindows(): 98 unzip_cmd = ['C:\\Program Files\\7-Zip\\7z.exe', 'x', '-y'] 99 else: 100 unzip_cmd = ['unzip', '-o'] 101 unzip_cmd += [zip_path] 102 if RunCommand(unzip_cmd, output_dir) != 0: 103 raise RuntimeError('Unable to unzip %s to %s' % (zip_path, output_dir)) 104 105 106def Kill(pid): 107 """Terminate the given pid.""" 108 if IsWindows(): 109 subprocess.call(['taskkill.exe', '/T', '/F', '/PID', str(pid)]) 110 else: 111 os.kill(pid, signal.SIGTERM) 112 113 114def RunCommand(cmd, cwd=None): 115 """Runs the given command and returns the exit code. 116 117 Args: 118 cmd: list of command arguments. 119 cwd: working directory to execute the command, or None if the current 120 working directory should be used. 121 122 Returns: 123 The exit code of the command. 124 """ 125 process = subprocess.Popen(cmd, cwd=cwd) 126 process.wait() 127 return process.returncode 128 129 130def DoesUrlExist(url): 131 """Determines whether a resource exists at the given URL. 132 133 Args: 134 url: URL to be verified. 135 136 Returns: 137 True if url exists, otherwise False. 138 """ 139 parsed = urlparse.urlparse(url) 140 try: 141 conn = httplib.HTTPConnection(parsed.netloc) 142 conn.request('HEAD', parsed.path) 143 response = conn.getresponse() 144 except (socket.gaierror, socket.error): 145 return False 146 finally: 147 conn.close() 148 # Follow both permanent (301) and temporary (302) redirects. 149 if response.status == 302 or response.status == 301: 150 return DoesUrlExist(response.getheader('location')) 151 return response.status == 200 152