1*9e94795aSAndroid Build Coastguard Worker# 2*9e94795aSAndroid Build Coastguard Worker# Copyright 2024, The Android Open Source Project 3*9e94795aSAndroid Build Coastguard Worker# 4*9e94795aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 5*9e94795aSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 6*9e94795aSAndroid Build Coastguard Worker# You may obtain a copy of the License at 7*9e94795aSAndroid Build Coastguard Worker# 8*9e94795aSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 9*9e94795aSAndroid Build Coastguard Worker# 10*9e94795aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 11*9e94795aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 12*9e94795aSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*9e94795aSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 14*9e94795aSAndroid Build Coastguard Worker# limitations under the License. 15*9e94795aSAndroid Build Coastguard Worker 16*9e94795aSAndroid Build Coastguard Workerfrom abc import ABC 17*9e94795aSAndroid Build Coastguard Workerimport argparse 18*9e94795aSAndroid Build Coastguard Workerimport functools 19*9e94795aSAndroid Build Coastguard Workerimport json 20*9e94795aSAndroid Build Coastguard Workerimport logging 21*9e94795aSAndroid Build Coastguard Workerimport os 22*9e94795aSAndroid Build Coastguard Workerimport pathlib 23*9e94795aSAndroid Build Coastguard Workerimport subprocess 24*9e94795aSAndroid Build Coastguard Worker 25*9e94795aSAndroid Build Coastguard Workerfrom build_context import BuildContext 26*9e94795aSAndroid Build Coastguard Workerimport test_mapping_module_retriever 27*9e94795aSAndroid Build Coastguard Worker 28*9e94795aSAndroid Build Coastguard Worker 29*9e94795aSAndroid Build Coastguard Workerclass OptimizedBuildTarget(ABC): 30*9e94795aSAndroid Build Coastguard Worker """A representation of an optimized build target. 31*9e94795aSAndroid Build Coastguard Worker 32*9e94795aSAndroid Build Coastguard Worker This class will determine what targets to build given a given build_cotext and 33*9e94795aSAndroid Build Coastguard Worker will have a packaging function to generate any necessary output zips for the 34*9e94795aSAndroid Build Coastguard Worker build. 35*9e94795aSAndroid Build Coastguard Worker """ 36*9e94795aSAndroid Build Coastguard Worker 37*9e94795aSAndroid Build Coastguard Worker _SOONG_UI_BASH_PATH = 'build/soong/soong_ui.bash' 38*9e94795aSAndroid Build Coastguard Worker _PREBUILT_SOONG_ZIP_PATH = 'prebuilts/build-tools/linux-x86/bin/soong_zip' 39*9e94795aSAndroid Build Coastguard Worker 40*9e94795aSAndroid Build Coastguard Worker def __init__( 41*9e94795aSAndroid Build Coastguard Worker self, 42*9e94795aSAndroid Build Coastguard Worker target: str, 43*9e94795aSAndroid Build Coastguard Worker build_context: BuildContext, 44*9e94795aSAndroid Build Coastguard Worker args: argparse.Namespace, 45*9e94795aSAndroid Build Coastguard Worker ): 46*9e94795aSAndroid Build Coastguard Worker self.target = target 47*9e94795aSAndroid Build Coastguard Worker self.build_context = build_context 48*9e94795aSAndroid Build Coastguard Worker self.args = args 49*9e94795aSAndroid Build Coastguard Worker 50*9e94795aSAndroid Build Coastguard Worker def get_build_targets(self) -> set[str]: 51*9e94795aSAndroid Build Coastguard Worker features = self.build_context.enabled_build_features 52*9e94795aSAndroid Build Coastguard Worker if self.get_enabled_flag() in features: 53*9e94795aSAndroid Build Coastguard Worker self.modules_to_build = self.get_build_targets_impl() 54*9e94795aSAndroid Build Coastguard Worker return self.modules_to_build 55*9e94795aSAndroid Build Coastguard Worker 56*9e94795aSAndroid Build Coastguard Worker self.modules_to_build = {self.target} 57*9e94795aSAndroid Build Coastguard Worker return {self.target} 58*9e94795aSAndroid Build Coastguard Worker 59*9e94795aSAndroid Build Coastguard Worker def get_package_outputs_commands(self) -> list[list[str]]: 60*9e94795aSAndroid Build Coastguard Worker features = self.build_context.enabled_build_features 61*9e94795aSAndroid Build Coastguard Worker if self.get_enabled_flag() in features: 62*9e94795aSAndroid Build Coastguard Worker return self.get_package_outputs_commands_impl() 63*9e94795aSAndroid Build Coastguard Worker 64*9e94795aSAndroid Build Coastguard Worker return [] 65*9e94795aSAndroid Build Coastguard Worker 66*9e94795aSAndroid Build Coastguard Worker def get_package_outputs_commands_impl(self) -> list[list[str]]: 67*9e94795aSAndroid Build Coastguard Worker raise NotImplementedError( 68*9e94795aSAndroid Build Coastguard Worker 'get_package_outputs_commands_impl not implemented in' 69*9e94795aSAndroid Build Coastguard Worker f' {type(self).__name__}' 70*9e94795aSAndroid Build Coastguard Worker ) 71*9e94795aSAndroid Build Coastguard Worker 72*9e94795aSAndroid Build Coastguard Worker def get_enabled_flag(self): 73*9e94795aSAndroid Build Coastguard Worker raise NotImplementedError( 74*9e94795aSAndroid Build Coastguard Worker f'get_enabled_flag not implemented in {type(self).__name__}' 75*9e94795aSAndroid Build Coastguard Worker ) 76*9e94795aSAndroid Build Coastguard Worker 77*9e94795aSAndroid Build Coastguard Worker def get_build_targets_impl(self) -> set[str]: 78*9e94795aSAndroid Build Coastguard Worker raise NotImplementedError( 79*9e94795aSAndroid Build Coastguard Worker f'get_build_targets_impl not implemented in {type(self).__name__}' 80*9e94795aSAndroid Build Coastguard Worker ) 81*9e94795aSAndroid Build Coastguard Worker 82*9e94795aSAndroid Build Coastguard Worker def _generate_zip_options_for_items( 83*9e94795aSAndroid Build Coastguard Worker self, 84*9e94795aSAndroid Build Coastguard Worker prefix: str = '', 85*9e94795aSAndroid Build Coastguard Worker relative_root: str = '', 86*9e94795aSAndroid Build Coastguard Worker list_files: list[str] | None = None, 87*9e94795aSAndroid Build Coastguard Worker files: list[str] | None = None, 88*9e94795aSAndroid Build Coastguard Worker directories: list[str] | None = None, 89*9e94795aSAndroid Build Coastguard Worker ) -> list[str]: 90*9e94795aSAndroid Build Coastguard Worker if not list_files and not files and not directories: 91*9e94795aSAndroid Build Coastguard Worker raise RuntimeError( 92*9e94795aSAndroid Build Coastguard Worker f'No items specified to be added to zip! Prefix: {prefix}, Relative' 93*9e94795aSAndroid Build Coastguard Worker f' root: {relative_root}' 94*9e94795aSAndroid Build Coastguard Worker ) 95*9e94795aSAndroid Build Coastguard Worker command_segment = [] 96*9e94795aSAndroid Build Coastguard Worker # These are all soong_zip options so consult soong_zip --help for specifics. 97*9e94795aSAndroid Build Coastguard Worker if prefix: 98*9e94795aSAndroid Build Coastguard Worker command_segment.append('-P') 99*9e94795aSAndroid Build Coastguard Worker command_segment.append(prefix) 100*9e94795aSAndroid Build Coastguard Worker if relative_root: 101*9e94795aSAndroid Build Coastguard Worker command_segment.append('-C') 102*9e94795aSAndroid Build Coastguard Worker command_segment.append(relative_root) 103*9e94795aSAndroid Build Coastguard Worker if list_files: 104*9e94795aSAndroid Build Coastguard Worker for list_file in list_files: 105*9e94795aSAndroid Build Coastguard Worker command_segment.append('-l') 106*9e94795aSAndroid Build Coastguard Worker command_segment.append(list_file) 107*9e94795aSAndroid Build Coastguard Worker if files: 108*9e94795aSAndroid Build Coastguard Worker for file in files: 109*9e94795aSAndroid Build Coastguard Worker command_segment.append('-f') 110*9e94795aSAndroid Build Coastguard Worker command_segment.append(file) 111*9e94795aSAndroid Build Coastguard Worker if directories: 112*9e94795aSAndroid Build Coastguard Worker for directory in directories: 113*9e94795aSAndroid Build Coastguard Worker command_segment.append('-D') 114*9e94795aSAndroid Build Coastguard Worker command_segment.append(directory) 115*9e94795aSAndroid Build Coastguard Worker 116*9e94795aSAndroid Build Coastguard Worker return command_segment 117*9e94795aSAndroid Build Coastguard Worker 118*9e94795aSAndroid Build Coastguard Worker def _query_soong_vars( 119*9e94795aSAndroid Build Coastguard Worker self, src_top: pathlib.Path, soong_vars: list[str] 120*9e94795aSAndroid Build Coastguard Worker ) -> dict[str, str]: 121*9e94795aSAndroid Build Coastguard Worker process_result = subprocess.run( 122*9e94795aSAndroid Build Coastguard Worker args=[ 123*9e94795aSAndroid Build Coastguard Worker f'{src_top / self._SOONG_UI_BASH_PATH}', 124*9e94795aSAndroid Build Coastguard Worker '--dumpvars-mode', 125*9e94795aSAndroid Build Coastguard Worker f'--abs-vars={" ".join(soong_vars)}', 126*9e94795aSAndroid Build Coastguard Worker ], 127*9e94795aSAndroid Build Coastguard Worker env=os.environ, 128*9e94795aSAndroid Build Coastguard Worker check=False, 129*9e94795aSAndroid Build Coastguard Worker capture_output=True, 130*9e94795aSAndroid Build Coastguard Worker text=True, 131*9e94795aSAndroid Build Coastguard Worker ) 132*9e94795aSAndroid Build Coastguard Worker if not process_result.returncode == 0: 133*9e94795aSAndroid Build Coastguard Worker logging.error('soong dumpvars command failed! stderr:') 134*9e94795aSAndroid Build Coastguard Worker logging.error(process_result.stderr) 135*9e94795aSAndroid Build Coastguard Worker raise RuntimeError('Soong dumpvars failed! See log for stderr.') 136*9e94795aSAndroid Build Coastguard Worker 137*9e94795aSAndroid Build Coastguard Worker if not process_result.stdout: 138*9e94795aSAndroid Build Coastguard Worker raise RuntimeError( 139*9e94795aSAndroid Build Coastguard Worker 'Necessary soong variables ' + soong_vars + ' not found.' 140*9e94795aSAndroid Build Coastguard Worker ) 141*9e94795aSAndroid Build Coastguard Worker 142*9e94795aSAndroid Build Coastguard Worker try: 143*9e94795aSAndroid Build Coastguard Worker return { 144*9e94795aSAndroid Build Coastguard Worker line.split('=')[0]: line.split('=')[1].strip("'") 145*9e94795aSAndroid Build Coastguard Worker for line in process_result.stdout.strip().split('\n') 146*9e94795aSAndroid Build Coastguard Worker } 147*9e94795aSAndroid Build Coastguard Worker except IndexError as e: 148*9e94795aSAndroid Build Coastguard Worker raise RuntimeError( 149*9e94795aSAndroid Build Coastguard Worker 'Error parsing soong dumpvars output! See output here:' 150*9e94795aSAndroid Build Coastguard Worker f' {process_result.stdout}', 151*9e94795aSAndroid Build Coastguard Worker e, 152*9e94795aSAndroid Build Coastguard Worker ) 153*9e94795aSAndroid Build Coastguard Worker 154*9e94795aSAndroid Build Coastguard Worker def _base_zip_command( 155*9e94795aSAndroid Build Coastguard Worker self, src_top: pathlib.Path, dist_dir: pathlib.Path, name: str 156*9e94795aSAndroid Build Coastguard Worker ) -> list[str]: 157*9e94795aSAndroid Build Coastguard Worker return [ 158*9e94795aSAndroid Build Coastguard Worker f'{src_top / self._PREBUILT_SOONG_ZIP_PATH }', 159*9e94795aSAndroid Build Coastguard Worker '-d', 160*9e94795aSAndroid Build Coastguard Worker '-o', 161*9e94795aSAndroid Build Coastguard Worker f'{dist_dir / name}', 162*9e94795aSAndroid Build Coastguard Worker ] 163*9e94795aSAndroid Build Coastguard Worker 164*9e94795aSAndroid Build Coastguard Worker 165*9e94795aSAndroid Build Coastguard Workerclass NullOptimizer(OptimizedBuildTarget): 166*9e94795aSAndroid Build Coastguard Worker """No-op target optimizer. 167*9e94795aSAndroid Build Coastguard Worker 168*9e94795aSAndroid Build Coastguard Worker This will simply build the same target it was given and do nothing for the 169*9e94795aSAndroid Build Coastguard Worker packaging step. 170*9e94795aSAndroid Build Coastguard Worker """ 171*9e94795aSAndroid Build Coastguard Worker 172*9e94795aSAndroid Build Coastguard Worker def __init__(self, target): 173*9e94795aSAndroid Build Coastguard Worker self.target = target 174*9e94795aSAndroid Build Coastguard Worker 175*9e94795aSAndroid Build Coastguard Worker def get_build_targets(self): 176*9e94795aSAndroid Build Coastguard Worker return {self.target} 177*9e94795aSAndroid Build Coastguard Worker 178*9e94795aSAndroid Build Coastguard Worker def get_package_outputs_commands(self): 179*9e94795aSAndroid Build Coastguard Worker return [] 180*9e94795aSAndroid Build Coastguard Worker 181*9e94795aSAndroid Build Coastguard Worker 182*9e94795aSAndroid Build Coastguard Workerclass ChangeInfo: 183*9e94795aSAndroid Build Coastguard Worker 184*9e94795aSAndroid Build Coastguard Worker def __init__(self, change_info_file_path): 185*9e94795aSAndroid Build Coastguard Worker try: 186*9e94795aSAndroid Build Coastguard Worker with open(change_info_file_path) as change_info_file: 187*9e94795aSAndroid Build Coastguard Worker change_info_contents = json.load(change_info_file) 188*9e94795aSAndroid Build Coastguard Worker except json.decoder.JSONDecodeError: 189*9e94795aSAndroid Build Coastguard Worker logging.error(f'Failed to load CHANGE_INFO: {change_info_file_path}') 190*9e94795aSAndroid Build Coastguard Worker raise 191*9e94795aSAndroid Build Coastguard Worker 192*9e94795aSAndroid Build Coastguard Worker self._change_info_contents = change_info_contents 193*9e94795aSAndroid Build Coastguard Worker 194*9e94795aSAndroid Build Coastguard Worker def find_changed_files(self) -> set[str]: 195*9e94795aSAndroid Build Coastguard Worker changed_files = set() 196*9e94795aSAndroid Build Coastguard Worker 197*9e94795aSAndroid Build Coastguard Worker for change in self._change_info_contents['changes']: 198*9e94795aSAndroid Build Coastguard Worker project_path = change.get('projectPath') + '/' 199*9e94795aSAndroid Build Coastguard Worker 200*9e94795aSAndroid Build Coastguard Worker for revision in change.get('revisions'): 201*9e94795aSAndroid Build Coastguard Worker for file_info in revision.get('fileInfos'): 202*9e94795aSAndroid Build Coastguard Worker changed_files.add(project_path + file_info.get('path')) 203*9e94795aSAndroid Build Coastguard Worker 204*9e94795aSAndroid Build Coastguard Worker return changed_files 205*9e94795aSAndroid Build Coastguard Worker 206*9e94795aSAndroid Build Coastguard Worker 207*9e94795aSAndroid Build Coastguard Workerclass GeneralTestsOptimizer(OptimizedBuildTarget): 208*9e94795aSAndroid Build Coastguard Worker """general-tests optimizer 209*9e94795aSAndroid Build Coastguard Worker 210*9e94795aSAndroid Build Coastguard Worker This optimizer reads in the list of changed files from the file located in 211*9e94795aSAndroid Build Coastguard Worker env[CHANGE_INFO] and uses this list alongside the normal TEST MAPPING logic to 212*9e94795aSAndroid Build Coastguard Worker determine what test mapping modules will run for the given changes. It then 213*9e94795aSAndroid Build Coastguard Worker builds those modules and packages them in the same way general-tests.zip is 214*9e94795aSAndroid Build Coastguard Worker normally built. 215*9e94795aSAndroid Build Coastguard Worker """ 216*9e94795aSAndroid Build Coastguard Worker 217*9e94795aSAndroid Build Coastguard Worker # List of modules that are built alongside general-tests as dependencies. 218*9e94795aSAndroid Build Coastguard Worker _REQUIRED_MODULES = frozenset([ 219*9e94795aSAndroid Build Coastguard Worker 'cts-tradefed', 220*9e94795aSAndroid Build Coastguard Worker 'vts-tradefed', 221*9e94795aSAndroid Build Coastguard Worker 'compatibility-host-util', 222*9e94795aSAndroid Build Coastguard Worker 'general-tests-shared-libs', 223*9e94795aSAndroid Build Coastguard Worker ]) 224*9e94795aSAndroid Build Coastguard Worker 225*9e94795aSAndroid Build Coastguard Worker def get_build_targets_impl(self) -> set[str]: 226*9e94795aSAndroid Build Coastguard Worker change_info_file_path = os.environ.get('CHANGE_INFO') 227*9e94795aSAndroid Build Coastguard Worker if not change_info_file_path: 228*9e94795aSAndroid Build Coastguard Worker logging.info( 229*9e94795aSAndroid Build Coastguard Worker 'No CHANGE_INFO env var found, general-tests optimization disabled.' 230*9e94795aSAndroid Build Coastguard Worker ) 231*9e94795aSAndroid Build Coastguard Worker return {'general-tests'} 232*9e94795aSAndroid Build Coastguard Worker 233*9e94795aSAndroid Build Coastguard Worker test_infos = self.build_context.test_infos 234*9e94795aSAndroid Build Coastguard Worker test_mapping_test_groups = set() 235*9e94795aSAndroid Build Coastguard Worker for test_info in test_infos: 236*9e94795aSAndroid Build Coastguard Worker is_test_mapping = test_info.is_test_mapping 237*9e94795aSAndroid Build Coastguard Worker current_test_mapping_test_groups = test_info.test_mapping_test_groups 238*9e94795aSAndroid Build Coastguard Worker uses_general_tests = test_info.build_target_used('general-tests') 239*9e94795aSAndroid Build Coastguard Worker 240*9e94795aSAndroid Build Coastguard Worker if uses_general_tests and not is_test_mapping: 241*9e94795aSAndroid Build Coastguard Worker logging.info( 242*9e94795aSAndroid Build Coastguard Worker 'Test uses general-tests.zip but is not test-mapping, general-tests' 243*9e94795aSAndroid Build Coastguard Worker ' optimization disabled.' 244*9e94795aSAndroid Build Coastguard Worker ) 245*9e94795aSAndroid Build Coastguard Worker return {'general-tests'} 246*9e94795aSAndroid Build Coastguard Worker 247*9e94795aSAndroid Build Coastguard Worker if is_test_mapping: 248*9e94795aSAndroid Build Coastguard Worker test_mapping_test_groups.update(current_test_mapping_test_groups) 249*9e94795aSAndroid Build Coastguard Worker 250*9e94795aSAndroid Build Coastguard Worker change_info = ChangeInfo(change_info_file_path) 251*9e94795aSAndroid Build Coastguard Worker changed_files = change_info.find_changed_files() 252*9e94795aSAndroid Build Coastguard Worker 253*9e94795aSAndroid Build Coastguard Worker test_mappings = test_mapping_module_retriever.GetTestMappings( 254*9e94795aSAndroid Build Coastguard Worker changed_files, set() 255*9e94795aSAndroid Build Coastguard Worker ) 256*9e94795aSAndroid Build Coastguard Worker 257*9e94795aSAndroid Build Coastguard Worker modules_to_build = set(self._REQUIRED_MODULES) 258*9e94795aSAndroid Build Coastguard Worker 259*9e94795aSAndroid Build Coastguard Worker modules_to_build.update( 260*9e94795aSAndroid Build Coastguard Worker test_mapping_module_retriever.FindAffectedModules( 261*9e94795aSAndroid Build Coastguard Worker test_mappings, changed_files, test_mapping_test_groups 262*9e94795aSAndroid Build Coastguard Worker ) 263*9e94795aSAndroid Build Coastguard Worker ) 264*9e94795aSAndroid Build Coastguard Worker 265*9e94795aSAndroid Build Coastguard Worker return modules_to_build 266*9e94795aSAndroid Build Coastguard Worker 267*9e94795aSAndroid Build Coastguard Worker def get_package_outputs_commands_impl(self): 268*9e94795aSAndroid Build Coastguard Worker src_top = pathlib.Path(os.environ.get('TOP', os.getcwd())) 269*9e94795aSAndroid Build Coastguard Worker dist_dir = pathlib.Path(os.environ.get('DIST_DIR')) 270*9e94795aSAndroid Build Coastguard Worker 271*9e94795aSAndroid Build Coastguard Worker soong_vars = self._query_soong_vars( 272*9e94795aSAndroid Build Coastguard Worker src_top, 273*9e94795aSAndroid Build Coastguard Worker [ 274*9e94795aSAndroid Build Coastguard Worker 'HOST_OUT_TESTCASES', 275*9e94795aSAndroid Build Coastguard Worker 'TARGET_OUT_TESTCASES', 276*9e94795aSAndroid Build Coastguard Worker 'PRODUCT_OUT', 277*9e94795aSAndroid Build Coastguard Worker 'SOONG_HOST_OUT', 278*9e94795aSAndroid Build Coastguard Worker 'HOST_OUT', 279*9e94795aSAndroid Build Coastguard Worker ], 280*9e94795aSAndroid Build Coastguard Worker ) 281*9e94795aSAndroid Build Coastguard Worker host_out_testcases = pathlib.Path(soong_vars.get('HOST_OUT_TESTCASES')) 282*9e94795aSAndroid Build Coastguard Worker target_out_testcases = pathlib.Path(soong_vars.get('TARGET_OUT_TESTCASES')) 283*9e94795aSAndroid Build Coastguard Worker product_out = pathlib.Path(soong_vars.get('PRODUCT_OUT')) 284*9e94795aSAndroid Build Coastguard Worker soong_host_out = pathlib.Path(soong_vars.get('SOONG_HOST_OUT')) 285*9e94795aSAndroid Build Coastguard Worker host_out = pathlib.Path(soong_vars.get('HOST_OUT')) 286*9e94795aSAndroid Build Coastguard Worker 287*9e94795aSAndroid Build Coastguard Worker host_paths = [] 288*9e94795aSAndroid Build Coastguard Worker target_paths = [] 289*9e94795aSAndroid Build Coastguard Worker host_config_files = [] 290*9e94795aSAndroid Build Coastguard Worker target_config_files = [] 291*9e94795aSAndroid Build Coastguard Worker for module in self.modules_to_build: 292*9e94795aSAndroid Build Coastguard Worker # The required modules are handled separately, no need to package. 293*9e94795aSAndroid Build Coastguard Worker if module in self._REQUIRED_MODULES: 294*9e94795aSAndroid Build Coastguard Worker continue 295*9e94795aSAndroid Build Coastguard Worker 296*9e94795aSAndroid Build Coastguard Worker host_path = host_out_testcases / module 297*9e94795aSAndroid Build Coastguard Worker if os.path.exists(host_path): 298*9e94795aSAndroid Build Coastguard Worker host_paths.append(host_path) 299*9e94795aSAndroid Build Coastguard Worker self._collect_config_files(src_top, host_path, host_config_files) 300*9e94795aSAndroid Build Coastguard Worker 301*9e94795aSAndroid Build Coastguard Worker target_path = target_out_testcases / module 302*9e94795aSAndroid Build Coastguard Worker if os.path.exists(target_path): 303*9e94795aSAndroid Build Coastguard Worker target_paths.append(target_path) 304*9e94795aSAndroid Build Coastguard Worker self._collect_config_files(src_top, target_path, target_config_files) 305*9e94795aSAndroid Build Coastguard Worker 306*9e94795aSAndroid Build Coastguard Worker if not os.path.exists(host_path) and not os.path.exists(target_path): 307*9e94795aSAndroid Build Coastguard Worker logging.info(f'No host or target build outputs found for {module}.') 308*9e94795aSAndroid Build Coastguard Worker 309*9e94795aSAndroid Build Coastguard Worker zip_commands = [] 310*9e94795aSAndroid Build Coastguard Worker 311*9e94795aSAndroid Build Coastguard Worker zip_commands.extend( 312*9e94795aSAndroid Build Coastguard Worker self._get_zip_test_configs_zips_commands( 313*9e94795aSAndroid Build Coastguard Worker src_top, 314*9e94795aSAndroid Build Coastguard Worker dist_dir, 315*9e94795aSAndroid Build Coastguard Worker host_out, 316*9e94795aSAndroid Build Coastguard Worker product_out, 317*9e94795aSAndroid Build Coastguard Worker host_config_files, 318*9e94795aSAndroid Build Coastguard Worker target_config_files, 319*9e94795aSAndroid Build Coastguard Worker ) 320*9e94795aSAndroid Build Coastguard Worker ) 321*9e94795aSAndroid Build Coastguard Worker 322*9e94795aSAndroid Build Coastguard Worker zip_command = self._base_zip_command(src_top, dist_dir, 'general-tests.zip') 323*9e94795aSAndroid Build Coastguard Worker 324*9e94795aSAndroid Build Coastguard Worker # Add host testcases. 325*9e94795aSAndroid Build Coastguard Worker if host_paths: 326*9e94795aSAndroid Build Coastguard Worker zip_command.extend( 327*9e94795aSAndroid Build Coastguard Worker self._generate_zip_options_for_items( 328*9e94795aSAndroid Build Coastguard Worker prefix='host', 329*9e94795aSAndroid Build Coastguard Worker relative_root=f'{src_top / soong_host_out}', 330*9e94795aSAndroid Build Coastguard Worker directories=host_paths, 331*9e94795aSAndroid Build Coastguard Worker ) 332*9e94795aSAndroid Build Coastguard Worker ) 333*9e94795aSAndroid Build Coastguard Worker 334*9e94795aSAndroid Build Coastguard Worker # Add target testcases. 335*9e94795aSAndroid Build Coastguard Worker if target_paths: 336*9e94795aSAndroid Build Coastguard Worker zip_command.extend( 337*9e94795aSAndroid Build Coastguard Worker self._generate_zip_options_for_items( 338*9e94795aSAndroid Build Coastguard Worker prefix='target', 339*9e94795aSAndroid Build Coastguard Worker relative_root=f'{src_top / product_out}', 340*9e94795aSAndroid Build Coastguard Worker directories=target_paths, 341*9e94795aSAndroid Build Coastguard Worker ) 342*9e94795aSAndroid Build Coastguard Worker ) 343*9e94795aSAndroid Build Coastguard Worker 344*9e94795aSAndroid Build Coastguard Worker # TODO(lucafarsi): Push this logic into a general-tests-minimal build command 345*9e94795aSAndroid Build Coastguard Worker # Add necessary tools. These are also hardcoded in general-tests.mk. 346*9e94795aSAndroid Build Coastguard Worker framework_path = soong_host_out / 'framework' 347*9e94795aSAndroid Build Coastguard Worker 348*9e94795aSAndroid Build Coastguard Worker zip_command.extend( 349*9e94795aSAndroid Build Coastguard Worker self._generate_zip_options_for_items( 350*9e94795aSAndroid Build Coastguard Worker prefix='host/tools', 351*9e94795aSAndroid Build Coastguard Worker relative_root=str(framework_path), 352*9e94795aSAndroid Build Coastguard Worker files=[ 353*9e94795aSAndroid Build Coastguard Worker f"{framework_path / 'cts-tradefed.jar'}", 354*9e94795aSAndroid Build Coastguard Worker f"{framework_path / 'compatibility-host-util.jar'}", 355*9e94795aSAndroid Build Coastguard Worker f"{framework_path / 'vts-tradefed.jar'}", 356*9e94795aSAndroid Build Coastguard Worker ], 357*9e94795aSAndroid Build Coastguard Worker ) 358*9e94795aSAndroid Build Coastguard Worker ) 359*9e94795aSAndroid Build Coastguard Worker 360*9e94795aSAndroid Build Coastguard Worker zip_commands.append(zip_command) 361*9e94795aSAndroid Build Coastguard Worker return zip_commands 362*9e94795aSAndroid Build Coastguard Worker 363*9e94795aSAndroid Build Coastguard Worker def _collect_config_files( 364*9e94795aSAndroid Build Coastguard Worker self, 365*9e94795aSAndroid Build Coastguard Worker src_top: pathlib.Path, 366*9e94795aSAndroid Build Coastguard Worker root_dir: pathlib.Path, 367*9e94795aSAndroid Build Coastguard Worker config_files: list[str], 368*9e94795aSAndroid Build Coastguard Worker ): 369*9e94795aSAndroid Build Coastguard Worker for root, dirs, files in os.walk(src_top / root_dir): 370*9e94795aSAndroid Build Coastguard Worker for file in files: 371*9e94795aSAndroid Build Coastguard Worker if file.endswith('.config'): 372*9e94795aSAndroid Build Coastguard Worker config_files.append(root_dir / file) 373*9e94795aSAndroid Build Coastguard Worker 374*9e94795aSAndroid Build Coastguard Worker def _get_zip_test_configs_zips_commands( 375*9e94795aSAndroid Build Coastguard Worker self, 376*9e94795aSAndroid Build Coastguard Worker src_top: pathlib.Path, 377*9e94795aSAndroid Build Coastguard Worker dist_dir: pathlib.Path, 378*9e94795aSAndroid Build Coastguard Worker host_out: pathlib.Path, 379*9e94795aSAndroid Build Coastguard Worker product_out: pathlib.Path, 380*9e94795aSAndroid Build Coastguard Worker host_config_files: list[str], 381*9e94795aSAndroid Build Coastguard Worker target_config_files: list[str], 382*9e94795aSAndroid Build Coastguard Worker ) -> tuple[list[str], list[str]]: 383*9e94795aSAndroid Build Coastguard Worker """Generate general-tests_configs.zip and general-tests_list.zip. 384*9e94795aSAndroid Build Coastguard Worker 385*9e94795aSAndroid Build Coastguard Worker general-tests_configs.zip contains all of the .config files that were 386*9e94795aSAndroid Build Coastguard Worker built and general-tests_list.zip contains a text file which lists 387*9e94795aSAndroid Build Coastguard Worker all of the .config files that are in general-tests_configs.zip. 388*9e94795aSAndroid Build Coastguard Worker 389*9e94795aSAndroid Build Coastguard Worker general-tests_configs.zip is organized as follows: 390*9e94795aSAndroid Build Coastguard Worker / 391*9e94795aSAndroid Build Coastguard Worker host/ 392*9e94795aSAndroid Build Coastguard Worker testcases/ 393*9e94795aSAndroid Build Coastguard Worker test_1.config 394*9e94795aSAndroid Build Coastguard Worker test_2.config 395*9e94795aSAndroid Build Coastguard Worker ... 396*9e94795aSAndroid Build Coastguard Worker target/ 397*9e94795aSAndroid Build Coastguard Worker testcases/ 398*9e94795aSAndroid Build Coastguard Worker test_1.config 399*9e94795aSAndroid Build Coastguard Worker test_2.config 400*9e94795aSAndroid Build Coastguard Worker ... 401*9e94795aSAndroid Build Coastguard Worker 402*9e94795aSAndroid Build Coastguard Worker So the process is we write out the paths to all the host config files into 403*9e94795aSAndroid Build Coastguard Worker one 404*9e94795aSAndroid Build Coastguard Worker file and all the paths to the target config files in another. We also write 405*9e94795aSAndroid Build Coastguard Worker the paths to all the config files into a third file to use for 406*9e94795aSAndroid Build Coastguard Worker general-tests_list.zip. 407*9e94795aSAndroid Build Coastguard Worker 408*9e94795aSAndroid Build Coastguard Worker Args: 409*9e94795aSAndroid Build Coastguard Worker dist_dir: dist directory. 410*9e94795aSAndroid Build Coastguard Worker host_out: host out directory. 411*9e94795aSAndroid Build Coastguard Worker product_out: product out directory. 412*9e94795aSAndroid Build Coastguard Worker host_config_files: list of all host config files. 413*9e94795aSAndroid Build Coastguard Worker target_config_files: list of all target config files. 414*9e94795aSAndroid Build Coastguard Worker 415*9e94795aSAndroid Build Coastguard Worker Returns: 416*9e94795aSAndroid Build Coastguard Worker The commands to generate general-tests_configs.zip and 417*9e94795aSAndroid Build Coastguard Worker general-tests_list.zip 418*9e94795aSAndroid Build Coastguard Worker """ 419*9e94795aSAndroid Build Coastguard Worker with open( 420*9e94795aSAndroid Build Coastguard Worker f"{host_out / 'host_general-tests_list'}", 'w' 421*9e94795aSAndroid Build Coastguard Worker ) as host_list_file, open( 422*9e94795aSAndroid Build Coastguard Worker f"{product_out / 'target_general-tests_list'}", 'w' 423*9e94795aSAndroid Build Coastguard Worker ) as target_list_file, open( 424*9e94795aSAndroid Build Coastguard Worker f"{host_out / 'general-tests_list'}", 'w' 425*9e94795aSAndroid Build Coastguard Worker ) as list_file: 426*9e94795aSAndroid Build Coastguard Worker 427*9e94795aSAndroid Build Coastguard Worker for config_file in host_config_files: 428*9e94795aSAndroid Build Coastguard Worker host_list_file.write(f'{config_file}' + '\n') 429*9e94795aSAndroid Build Coastguard Worker list_file.write('host/' + os.path.relpath(config_file, host_out) + '\n') 430*9e94795aSAndroid Build Coastguard Worker 431*9e94795aSAndroid Build Coastguard Worker for config_file in target_config_files: 432*9e94795aSAndroid Build Coastguard Worker target_list_file.write(f'{config_file}' + '\n') 433*9e94795aSAndroid Build Coastguard Worker list_file.write( 434*9e94795aSAndroid Build Coastguard Worker 'target/' + os.path.relpath(config_file, product_out) + '\n' 435*9e94795aSAndroid Build Coastguard Worker ) 436*9e94795aSAndroid Build Coastguard Worker 437*9e94795aSAndroid Build Coastguard Worker zip_commands = [] 438*9e94795aSAndroid Build Coastguard Worker 439*9e94795aSAndroid Build Coastguard Worker tests_config_zip_command = self._base_zip_command( 440*9e94795aSAndroid Build Coastguard Worker src_top, dist_dir, 'general-tests_configs.zip' 441*9e94795aSAndroid Build Coastguard Worker ) 442*9e94795aSAndroid Build Coastguard Worker tests_config_zip_command.extend( 443*9e94795aSAndroid Build Coastguard Worker self._generate_zip_options_for_items( 444*9e94795aSAndroid Build Coastguard Worker prefix='host', 445*9e94795aSAndroid Build Coastguard Worker relative_root=str(host_out), 446*9e94795aSAndroid Build Coastguard Worker list_files=[f"{host_out / 'host_general-tests_list'}"], 447*9e94795aSAndroid Build Coastguard Worker ) 448*9e94795aSAndroid Build Coastguard Worker ) 449*9e94795aSAndroid Build Coastguard Worker 450*9e94795aSAndroid Build Coastguard Worker tests_config_zip_command.extend( 451*9e94795aSAndroid Build Coastguard Worker self._generate_zip_options_for_items( 452*9e94795aSAndroid Build Coastguard Worker prefix='target', 453*9e94795aSAndroid Build Coastguard Worker relative_root=str(product_out), 454*9e94795aSAndroid Build Coastguard Worker list_files=[f"{product_out / 'target_general-tests_list'}"], 455*9e94795aSAndroid Build Coastguard Worker ), 456*9e94795aSAndroid Build Coastguard Worker ) 457*9e94795aSAndroid Build Coastguard Worker 458*9e94795aSAndroid Build Coastguard Worker zip_commands.append(tests_config_zip_command) 459*9e94795aSAndroid Build Coastguard Worker 460*9e94795aSAndroid Build Coastguard Worker tests_list_zip_command = self._base_zip_command( 461*9e94795aSAndroid Build Coastguard Worker src_top, dist_dir, 'general-tests_list.zip' 462*9e94795aSAndroid Build Coastguard Worker ) 463*9e94795aSAndroid Build Coastguard Worker tests_list_zip_command.extend( 464*9e94795aSAndroid Build Coastguard Worker self._generate_zip_options_for_items( 465*9e94795aSAndroid Build Coastguard Worker relative_root=str(host_out), 466*9e94795aSAndroid Build Coastguard Worker files=[f"{host_out / 'general-tests_list'}"], 467*9e94795aSAndroid Build Coastguard Worker ) 468*9e94795aSAndroid Build Coastguard Worker ) 469*9e94795aSAndroid Build Coastguard Worker zip_commands.append(tests_list_zip_command) 470*9e94795aSAndroid Build Coastguard Worker 471*9e94795aSAndroid Build Coastguard Worker return zip_commands 472*9e94795aSAndroid Build Coastguard Worker 473*9e94795aSAndroid Build Coastguard Worker def get_enabled_flag(self): 474*9e94795aSAndroid Build Coastguard Worker return 'general_tests_optimized' 475*9e94795aSAndroid Build Coastguard Worker 476*9e94795aSAndroid Build Coastguard Worker @classmethod 477*9e94795aSAndroid Build Coastguard Worker def get_optimized_targets(cls) -> dict[str, OptimizedBuildTarget]: 478*9e94795aSAndroid Build Coastguard Worker return {'general-tests': functools.partial(cls)} 479*9e94795aSAndroid Build Coastguard Worker 480*9e94795aSAndroid Build Coastguard Worker 481*9e94795aSAndroid Build Coastguard WorkerOPTIMIZED_BUILD_TARGETS = {} 482*9e94795aSAndroid Build Coastguard WorkerOPTIMIZED_BUILD_TARGETS.update(GeneralTestsOptimizer.get_optimized_targets()) 483