1#!/usr/bin/env python 2# 3# Copyright 2016 Google Inc. 4# 5# Use of this source code is governed by a BSD-style license that can be 6# found in the LICENSE file. 7 8 9"""Default flavor utils class, used for desktop bots.""" 10 11 12import os 13import shutil 14import sys 15 16 17class DeviceDirs(object): 18 def __init__(self, 19 dm_dir, 20 perf_data_dir, 21 resource_dir, 22 images_dir, 23 skp_dir, 24 tmp_dir): 25 self._dm_dir = dm_dir 26 self._perf_data_dir = perf_data_dir 27 self._resource_dir = resource_dir 28 self._images_dir = images_dir 29 self._skp_dir = skp_dir 30 self._tmp_dir = tmp_dir 31 32 @property 33 def dm_dir(self): 34 """Where DM writes.""" 35 return self._dm_dir 36 37 @property 38 def perf_data_dir(self): 39 return self._perf_data_dir 40 41 @property 42 def resource_dir(self): 43 return self._resource_dir 44 45 @property 46 def images_dir(self): 47 return self._images_dir 48 49 @property 50 def skp_dir(self): 51 return self._skp_dir 52 53 @property 54 def tmp_dir(self): 55 return self._tmp_dir 56 57 58class DefaultFlavorUtils(object): 59 """Utilities to be used by build steps. 60 61 The methods in this class define how certain high-level functions should 62 work. Each build step flavor should correspond to a subclass of 63 DefaultFlavorUtils which may override any of these functions as appropriate 64 for that flavor. 65 66 For example, the AndroidFlavorUtils will override the functions for 67 copying files between the host and Android device, as well as the 68 'step' function, so that commands may be run through ADB. 69 """ 70 def __init__(self, bot_info, *args, **kwargs): 71 self._bot_info = bot_info 72 self.chrome_path = os.path.join(os.path.expanduser('~'), 'src') 73 74 def step(self, cmd, **kwargs): 75 """Runs a step as appropriate for this flavor.""" 76 path_to_app = self._bot_info.out_dir.join( 77 self._bot_info.configuration, cmd[0]) 78 if (sys.platform == 'linux' and 79 'x86_64' in self._bot_info.bot_name and 80 not 'TSAN' in self._bot_info.bot_name): 81 new_cmd = ['catchsegv', path_to_app] 82 else: 83 new_cmd = [path_to_app] 84 new_cmd.extend(cmd[1:]) 85 return self._bot_info.run(new_cmd, **kwargs) 86 87 88 def compile(self, target): 89 """Build the given target.""" 90 # The CHROME_PATH environment variable is needed for bots that use 91 # toolchains downloaded by Chrome. 92 env = {'CHROME_PATH': self.chrome_path} 93 if sys.platform == 'win32': 94 make_cmd = ['python', 'make.py'] 95 else: 96 make_cmd = ['make'] 97 cmd = make_cmd + [target] 98 self._bot_info.run(cmd, env=env) 99 100 def device_path_join(self, *args): 101 """Like os.path.join(), but for paths on a connected device.""" 102 return os.path.join(*args) 103 104 def device_path_exists(self, path): 105 """Like os.path.exists(), but for paths on a connected device.""" 106 return os.path.exists(path, infra_step=True) # pragma: no cover 107 108 def copy_directory_contents_to_device(self, host_dir, device_dir): 109 """Like shutil.copytree(), but for copying to a connected device.""" 110 # For "normal" bots who don't have an attached device, we expect 111 # host_dir and device_dir to be the same. 112 if str(host_dir) != str(device_dir): 113 raise ValueError('For bots who do not have attached devices, copying ' 114 'from host to device is undefined and only allowed if ' 115 'host_path and device_path are the same (%s vs %s).' % ( 116 str(host_dir), str(device_dir))) # pragma: no cover 117 118 def copy_directory_contents_to_host(self, device_dir, host_dir): 119 """Like shutil.copytree(), but for copying from a connected device.""" 120 # For "normal" bots who don't have an attached device, we expect 121 # host_dir and device_dir to be the same. 122 if str(host_dir) != str(device_dir): 123 raise ValueError('For bots who do not have attached devices, copying ' 124 'from device to host is undefined and only allowed if ' 125 'host_path and device_path are the same (%s vs %s).' % ( 126 str(host_dir), str(device_dir))) # pragma: no cover 127 128 def copy_file_to_device(self, host_path, device_path): 129 """Like shutil.copyfile, but for copying to a connected device.""" 130 # For "normal" bots who don't have an attached device, we expect 131 # host_dir and device_dir to be the same. 132 if str(host_path) != str(device_path): # pragma: no cover 133 raise ValueError('For bots who do not have attached devices, copying ' 134 'from host to device is undefined and only allowed if ' 135 'host_path and device_path are the same (%s vs %s).' % ( 136 str(host_path), str(device_path))) 137 138 def create_clean_device_dir(self, path): 139 """Like shutil.rmtree() + os.makedirs(), but on a connected device.""" 140 self.create_clean_host_dir(path) 141 142 def create_clean_host_dir(self, path): 143 """Convenience function for creating a clean directory.""" 144 shutil.rmtree(path) 145 os.makedirs(path) 146 147 def install(self): 148 """Run device-specific installation steps.""" 149 pass 150 151 def cleanup_steps(self): 152 """Run any device-specific cleanup steps.""" 153 pass 154 155 def get_device_dirs(self): 156 """ Set the directories which will be used by the build steps. 157 158 These refer to paths on the same device where the test executables will 159 run, for example, for Android bots these are paths on the Android device 160 itself. For desktop bots, these are just local paths. 161 """ 162 join = lambda p: os.path.join(self._bot_info.build_dir, p) 163 return DeviceDirs( 164 dm_dir=join('dm'), 165 perf_data_dir=self._bot_info.perf_data_dir, 166 resource_dir=self._bot_info.resource_dir, 167 images_dir=join('images'), 168 skp_dir=self._bot_info.local_skp_dir, 169 tmp_dir=join('tmp')) 170 171 def __repr__(self): 172 return '<%s object>' % self.__class__.__name__ # pragma: no cover 173