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