local_host.py revision 497780908dd4b33d966566f24830194a557eed4e
1# Copyright 2009 Google Inc. Released under the GPL v2 2 3""" 4This file contains the implementation of a host object for the local machine. 5""" 6 7import distutils.core, glob, os, platform, shutil 8from autotest_lib.client.common_lib import hosts, error 9from autotest_lib.client.bin import utils 10 11class LocalHost(hosts.Host): 12 """This class represents a host running locally on the host.""" 13 14 15 def _initialize(self, hostname=None, bootloader=None, *args, **dargs): 16 super(LocalHost, self)._initialize(*args, **dargs) 17 18 # hostname will be an actual hostname when this client was created 19 # by an autoserv process 20 if not hostname: 21 hostname = platform.node() 22 self.hostname = hostname 23 self.bootloader = bootloader 24 self.tmp_dirs = [] 25 26 27 def close(self): 28 """Cleanup after we're done.""" 29 for tmp_dir in self.tmp_dirs: 30 self.run('rm -rf "%s"' % (utils.sh_escape(tmp_dir)), 31 ignore_status=True) 32 33 34 def wait_up(self, timeout=None): 35 # a local host is always up 36 return True 37 38 39 def run(self, command, timeout=3600, ignore_status=False, 40 ignore_timeout=False, 41 stdout_tee=utils.TEE_TO_LOGS, stderr_tee=utils.TEE_TO_LOGS, 42 stdin=None, args=(), **kwargs): 43 """ 44 @see common_lib.hosts.Host.run() 45 """ 46 try: 47 result = utils.run( 48 command, timeout=timeout, ignore_status=True, 49 ignore_timeout=ignore_timeout, 50 stdout_tee=stdout_tee, stderr_tee=stderr_tee, stdin=stdin, 51 args=args) 52 except error.CmdError, e: 53 # this indicates a timeout exception 54 raise error.AutotestHostRunError('command timed out', e.result_obj) 55 56 if ignore_timeout and result is None: 57 # We have timed out, there is no result to report. 58 return None 59 60 if not ignore_status and result.exit_status > 0: 61 raise error.AutotestHostRunError('command execution error', result) 62 63 return result 64 65 66 def list_files_glob(self, path_glob): 67 """ 68 Get a list of files on a remote host given a glob pattern path. 69 """ 70 return glob.glob(path_glob) 71 72 73 def symlink_closure(self, paths): 74 """ 75 Given a sequence of path strings, return the set of all paths that 76 can be reached from the initial set by following symlinks. 77 78 @param paths: sequence of path strings. 79 @return: a sequence of path strings that are all the unique paths that 80 can be reached from the given ones after following symlinks. 81 """ 82 paths = set(paths) 83 closure = set() 84 85 while paths: 86 path = paths.pop() 87 if not os.path.exists(path): 88 continue 89 closure.add(path) 90 if os.path.islink(path): 91 link_to = os.path.join(os.path.dirname(path), 92 os.readlink(path)) 93 if link_to not in closure: 94 paths.add(link_to) 95 96 return closure 97 98 99 def _copy_file(self, source, dest, delete_dest=False, preserve_perm=False, 100 preserve_symlinks=False): 101 """Copy files from source to dest, will be the base for {get,send}_file. 102 103 @param source: The file/directory on localhost to copy. 104 @param dest: The destination path on localhost to copy to. 105 @param delete_dest: A flag set to choose whether or not to delete 106 dest if it exists. 107 @param preserve_perm: Tells get_file() to try to preserve the sources 108 permissions on files and dirs. 109 @param preserve_symlinks: Try to preserve symlinks instead of 110 transforming them into files/dirs on copy. 111 """ 112 if delete_dest and os.path.exists(dest): 113 # Check if it's a file or a dir and use proper remove method. 114 if os.path.isdir(dest): 115 shutil.rmtree(dest) 116 else: 117 os.remove(dest) 118 119 if preserve_symlinks and os.path.islink(source): 120 os.symlink(os.readlink(source), dest) 121 # If source is a dir, use distutils.dir_util.copytree since 122 # shutil.copy_tree has weird limitations. 123 elif os.path.isdir(source): 124 distutils.dir_util.copy_tree(source, dest, 125 preserve_symlinks=preserve_symlinks, 126 preserve_mode=preserve_perm, 127 update=1) 128 else: 129 shutil.copyfile(source, dest) 130 131 if preserve_perm: 132 shutil.copymode(source, dest) 133 134 135 def get_file(self, source, dest, delete_dest=False, preserve_perm=True, 136 preserve_symlinks=False): 137 """Copy files from source to dest. 138 139 @param source: The file/directory on localhost to copy. 140 @param dest: The destination path on localhost to copy to. 141 @param delete_dest: A flag set to choose whether or not to delete 142 dest if it exists. 143 @param preserve_perm: Tells get_file() to try to preserve the sources 144 permissions on files and dirs. 145 @param preserve_symlinks: Try to preserve symlinks instead of 146 transforming them into files/dirs on copy. 147 """ 148 self._copy_file(source, dest, delete_dest=delete_dest, 149 preserve_perm=preserve_perm, 150 preserve_symlinks=preserve_symlinks) 151 152 153 def send_file(self, source, dest, delete_dest=False, 154 preserve_symlinks=False): 155 """Copy files from source to dest. 156 157 @param source: The file/directory on the drone to send to the device. 158 @param dest: The destination path on the device to copy to. 159 @param delete_dest: A flag set to choose whether or not to delete 160 dest on the device if it exists. 161 @param preserve_symlinks: Controls if symlinks on the source will be 162 copied as such on the destination or 163 transformed into the referenced 164 file/directory. 165 """ 166 self._copy_file(source, dest, delete_dest=delete_dest, 167 preserve_symlinks=preserve_symlinks) 168 169 170 def get_tmp_dir(self, parent='/tmp'): 171 """ 172 Return the pathname of a directory on the host suitable 173 for temporary file storage. 174 175 The directory and its content will be deleted automatically 176 on the destruction of the Host object that was used to obtain 177 it. 178 179 @param parent: The leading path to make the tmp dir. 180 """ 181 self.run('mkdir -p "%s"' % parent) 182 tmp_dir = self.run('mktemp -d -p "%s"' % parent).stdout.rstrip() 183 self.tmp_dirs.append(tmp_dir) 184 return tmp_dir 185