1#!/usr/bin/env python 2# 3# Copyright (C) 2017 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the 'License'); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an 'AS IS' BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16# 17 18import os 19import re 20 21from utils.const import Constant 22from vts_spec_parser import VtsSpecParser 23import build_rule_gen_utils as utils 24 25 26class BuildRuleGen(object): 27 """Build rule generator for test/vts-testcase/hal.""" 28 _ANDROID_BUILD_TOP = os.environ.get('ANDROID_BUILD_TOP') 29 if not _ANDROID_BUILD_TOP: 30 print 'Run "lunch" command first.' 31 sys.exit(1) 32 _PROJECT_PATH = os.path.join(_ANDROID_BUILD_TOP, 'test', 'vts-testcase', 33 'hal') 34 _VTS_BUILD_TEMPLATE = os.path.join(_PROJECT_PATH, 'script', 'build', 35 'template', 'vts_build_template.bp') 36 37 def __init__(self, warning_header, package_root, path_root): 38 """BuildRuleGen constructor. 39 40 Args: 41 warning_header: string, warning header for every generated file. 42 package_root: string, prefix of the hal package. 43 path_root: string, root path that stores the hal definition. 44 """ 45 self._warning_header = warning_header 46 self._vts_spec_parser = VtsSpecParser(package_root, path_root) 47 self._package_root = package_root 48 self._path_root = path_root 49 50 def UpdateBuildRule(self, test_config_dir): 51 """Updates build rules under the configuration directory. 52 53 Args: 54 test_config_dir: string, directory storing the configurations. 55 56 Returns: 57 a list of strings where each string contains the path of a checked 58 or updated build file. 59 True if any file is updated, False otherwise 60 """ 61 hal_list = self._vts_spec_parser.HalNamesAndVersions() 62 gen_file_paths, updated_file_paths, updated = self.UpdateHalDirBuildRule( 63 hal_list, test_config_dir) 64 updated |= utils.RemoveFilesInDirIf( 65 os.path.join(self._ANDROID_BUILD_TOP, test_config_dir), 66 lambda x: self._IsAutoGenerated(x) and (x not in gen_file_paths)) 67 return updated_file_paths, updated 68 69 def UpdateHalDirBuildRule(self, hal_list, test_config_dir): 70 """Updates build rules for vts drivers/profilers. 71 72 Updates vts drivers/profilers for each pair of (hal_name, hal_version) 73 in hal_list. 74 75 Args: 76 hal_list: list of tuple of strings. For example, 77 [('vibrator', '1.3'), ('sensors', '1.7')] 78 test_config_dir: string, directory storing the configurations. 79 80 Returns: 81 a list of strings where each string contains the path of a checked 82 build file, 83 a list of strings where each string contains the path of an updated 84 build file, 85 boolean, True if any file is updated, False otherwise 86 """ 87 checked_file_paths = [] 88 updated_file_paths = [] 89 ever_updated = False 90 for target in hal_list: 91 hal_name = target[0] 92 hal_version = target[1] 93 94 hal_dir = os.path.join( 95 self._ANDROID_BUILD_TOP, test_config_dir, 96 utils.HalNameDir(hal_name), utils.HalVerDir(hal_version)) 97 98 file_path = os.path.join(hal_dir, 'build', 'Android.bp') 99 updated = utils.WriteBuildRule(file_path, self._VtsBuildRuleFromTemplate( 100 self._VTS_BUILD_TEMPLATE, hal_name, hal_version)) 101 checked_file_paths.append(file_path) 102 if updated: 103 updated_file_paths.append(file_path) 104 ever_updated = True 105 return checked_file_paths, updated_file_paths, ever_updated 106 107 def _VtsBuildRuleFromTemplate(self, template_path, hal_name, hal_version): 108 """Returns build rules in string form by filling out a template. 109 110 Reads template from given path and fills it out. 111 112 Args: 113 template_path: string, path to build rule template file. 114 hal_name: string, name of the hal, e.g. 'vibrator'. 115 hal_version: string, version of the hal, e.g '7.4' 116 117 Returns: 118 string, complete build rules in string form 119 """ 120 with open(template_path) as template_file: 121 build_template = str(template_file.read()) 122 return self._FillOutBuildRuleTemplate(hal_name, hal_version, 123 build_template) 124 125 def _FillOutBuildRuleTemplate(self, hal_name, hal_version, template): 126 """Returns build rules in string form by filling out given template. 127 128 Args: 129 hal_name: string, name of the hal, e.g. 'vibrator'. 130 hal_version: string, version of the hal, e.g '7.4' 131 template: string, build rule template to fill out. 132 133 Returns: 134 string, complete build rule in string form. 135 """ 136 package_root_dir = self._package_root.replace(".", "/") 137 138 def GeneratedOutput(hal_name, hal_version, extension): 139 """Formats list of vts spec names into a string. 140 141 Formats list of vts spec name for given hal_name, hal_version 142 into a string that can be inserted into build template. 143 144 Args: 145 hal_name: string, name of the hal, e.g. 'vibrator'. 146 hal_version: string, version of the hal, e.g '7.4' 147 extension: string, extension of files e.g. '.cpp'. 148 149 Returns: 150 string, to be inserted into build template. 151 """ 152 result = [] 153 vts_spec_names = self._vts_spec_parser.VtsSpecNames(hal_name, 154 hal_version) 155 for vts_spec in vts_spec_names: 156 result.append('%s/%s/%s/%s%s' % 157 (package_root_dir, utils.HalNameDir(hal_name), 158 hal_version, vts_spec, extension)) 159 return ListToBuildString(result, 2) 160 161 def ImportedPackages(vts_pkg_type, imported_packages): 162 """Formats list of imported packages into a string. 163 164 Formats list of imported packages for given hal_name, hal_version 165 into a string that can be inserted into build template. 166 167 Args: 168 vts_pkg_type: string 'driver' or 'profiler' 169 imported_packages: list of imported packages 170 171 Returns: 172 string, to be inserted into build template. 173 """ 174 result = [] 175 for package in imported_packages: 176 if re.match(Constant.HAL_PACKAGE_NAME_PATTERN, package): 177 vts_pkg_name = package + '-vts.' + vts_pkg_type 178 result.append(vts_pkg_name) 179 else: 180 result.append(package) 181 return ListToBuildString(result, 2) 182 183 build_rule = self._warning_header + template 184 build_rule = build_rule.replace('{HAL_NAME}', hal_name) 185 build_rule = build_rule.replace('{HAL_NAME_DIR}', 186 utils.HalNameDir(hal_name)) 187 build_rule = build_rule.replace('{HAL_VERSION}', hal_version) 188 build_rule = build_rule.replace('{PACKAGE_ROOT}', self._package_root) 189 build_rule = build_rule.replace('{PACKAGE_ROOT_DIR}', package_root_dir) 190 build_rule = build_rule.replace( 191 '{HIDL_GEN_ARGS}', 192 "-r %s:%s" % (self._package_root, self._path_root)) 193 build_rule = build_rule.replace( 194 '{GENERATED_VTS_SPECS}', 195 GeneratedOutput(hal_name, hal_version, '')) 196 build_rule = build_rule.replace( 197 '{GENERATED_SOURCES}', 198 GeneratedOutput(hal_name, hal_version, '.cpp')) 199 build_rule = build_rule.replace( 200 '{GENERATED_HEADERS}', GeneratedOutput(hal_name, hal_version, '.h')) 201 202 imported_packages = self._vts_spec_parser.ImportedPackagesList( 203 hal_name, hal_version) 204 build_rule = build_rule.replace( 205 '{IMPORTED_DRIVER_PACKAGES}', 206 ImportedPackages('driver', imported_packages)) 207 build_rule = build_rule.replace( 208 '{IMPORTED_PROFILER_PACKAGES}', 209 ImportedPackages('profiler', imported_packages)) 210 211 this_package = '%s.%s@%s' % (self._package_root, hal_name, hal_version) 212 imported_packages.append(this_package) 213 hal_libs = sorted(imported_packages) 214 215 build_rule = build_rule.replace( 216 '{HAL_LIBS}', ListToBuildString(hal_libs, 2)) 217 218 return build_rule 219 220 def _IsAutoGenerated(self, abs_file_path): 221 """Checks if file was auto-generated. 222 223 Args: 224 abs_file_path: string, absolute file path. 225 226 Returns: 227 True iff file was auto-generated by BuildRuleGen. 228 """ 229 [dir_name, file_name] = os.path.split(abs_file_path) 230 if file_name != 'Android.bp': 231 return False 232 with open(abs_file_path) as myfile: 233 return self._warning_header in myfile.read() 234 235def ListToBuildString(lst, indent_lvl): 236 """Formats a list of item into a string to be inserted into build rule. 237 238 Args: 239 lst: string list, e.g. [a, b, c]. 240 indent_lvl: int, indentation level of the output list. 241 242 Returns: 243 string to be inserted into build rule. 244 """ 245 single_indent = ' ' 246 indent = single_indent * indent_lvl 247 result = ''.join(map(lambda x: '\n%s"%s",' % (indent, x), sorted(lst))) 248 if result: 249 result += '\n' + single_indent * (indent_lvl - 1) 250 return result 251