1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3 4# Copyright (c) 2020-2021 Huawei Device Co., Ltd. 5# 6# HDF is dual licensed: you can use it either under the terms of 7# the GPL, or the BSD license, at your option. 8# See the LICENSE file in the root of this repository for complete details. 9 10 11import json 12import os 13import re 14import ast 15import platform 16from string import Template 17 18import hdf_utils 19from hdf_tool_exception import HdfToolException 20from .hdf_command_error_code import CommandErrorCode 21 22 23class HdfLiteScan(object): 24 def __init__(self, root, vendor, board): 25 self.root = root 26 self.vendor = vendor 27 self.board = board 28 29 self.build_path = hdf_utils.get_vendor_gn_path(self.root) 30 if not os.path.exists(self.build_path): 31 raise HdfToolException('file: %s not exist' % self.build_path, 32 CommandErrorCode.TARGET_NOT_EXIST) 33 34 self.framework_dir = hdf_utils.get_module_dir(self.root) 35 if not os.path.exists(self.framework_dir): 36 raise HdfToolException('file: %s not exist' % self.framework_dir, 37 CommandErrorCode.TARGET_NOT_EXIST) 38 39 self.hcs_path = hdf_utils.get_hcs_file_path(self.root, vendor, board) 40 if not os.path.exists(self.hcs_path): 41 raise HdfToolException('file: %s not exist' % self.hcs_path, 42 CommandErrorCode.TARGET_NOT_EXIST) 43 44 dot_file_list = hdf_utils.get_dot_configs_path(root, vendor, board) 45 self.dot_file = list(filter( 46 lambda x: x.endswith("debug_tee.config"), dot_file_list)) 47 self.contents = hdf_utils.read_file_lines(self.build_path) 48 self.contents_config_enable = hdf_utils.read_file_lines( 49 self.dot_file[0]) 50 self.re_temp = r"^modules" 51 self.re_temp_model = r'"[a-z 0-9]+' 52 self.re_temp_module_switch = r"^module_switch" 53 self.re_temp_loscfg = r"LOSCFG[_ A-Z 0-9]+" 54 self.re_temp_sources = "^sources" 55 self.re_source_file1 = r"\$[A-Z _ / a-z 0-9 .]+\.c" 56 self.re_source_file2 = r"[_ / a-z 0-9]+\.c" 57 self.re_temp_header = r"^hdf_driver\(module_name\)" 58 self.re_temp_if = r"^if" 59 self.re_left_macro = r'^[A-Z _ 0-9]+' 60 self.re_right_macro = r'\$[A-Z _ 0-9]+' 61 62 def scan_build(self): 63 start_index = 0 64 end_index = 0 65 state = 0 66 for index, line in enumerate(self.contents): 67 if re.compile(self.re_temp).match(line.strip()): 68 start_index = index 69 state += 1 70 elif line.strip() == "[" and start_index > 0: 71 state += 1 72 elif line.strip() == "]" and start_index > 0: 73 state -= 1 74 if state == 0: 75 end_index = index + 1 76 77 model_list = [] 78 for i in self.contents[start_index + 1: end_index - 1]: 79 model_name = re.compile(self.re_temp_model).match(i.strip()) 80 if model_name: 81 model_list.append(i.strip()) 82 return list(set(model_list)) 83 84 def _get_model_file_dict(self, liteos_model): 85 parent_path_model = os.path.sep.join( 86 self.build_path.split(os.path.sep)[:-1]) 87 model_path_dict = {} 88 for model_path in liteos_model: 89 model_file_path = os.path.join(parent_path_model, model_path[1:-2]) 90 model_name = model_path[1:-2].split("/")[0] 91 if model_path_dict.get(model_name, None): 92 model_path_dict.get(model_name).append(model_file_path) 93 else: 94 model_path_dict[model_name] = [model_file_path] 95 return model_path_dict 96 97 def model_able_scan(self, model_path_dict): 98 for model_name, value in model_path_dict.items(): 99 for path in value: 100 model_build = os.path.join(path, "BUILD.gn") 101 if not os.path.exists(model_build): 102 continue 103 model_build_lines = hdf_utils.read_file_lines(model_build) 104 model_path_dict = self.model_build_file_able( 105 model_build_lines, model_path_dict, model_name, path) 106 return model_path_dict 107 108 def model_build_file_able(self, model_build_lines, model_path_dict, 109 model_name, path): 110 status = True 111 for line in model_build_lines: 112 if re.search(self.re_temp_module_switch, line) and status: 113 enable_key = '%s=y\n' % re.search( 114 self.re_temp_loscfg, line.strip()).group() 115 if enable_key not in self.contents_config_enable: 116 model_path_dict[model_name].remove(path) 117 else: 118 status = False 119 return model_path_dict 120 121 def get_need_result_only(self, model_path_dict, name, 122 import_gni_path, return_dict, need_replace): 123 parent = model_path_dict[name][0] 124 model_build = os.path.join(parent, "BUILD.gn") 125 if os.path.exists(model_build): 126 model_build_lines = hdf_utils.read_file_lines(model_build) 127 key_index = self.get_index(model_config_lines=model_build_lines) 128 enable_path_dict = self.enable_dict( 129 index_list=key_index, 130 enable_lines=model_build_lines, 131 path=parent) 132 replace_path = {} 133 import_gni_path, replace_path, temp_name = self.build_able_analyze( 134 model_build_lines, replace_path, import_gni_path) 135 enable_path_dict[temp_name] = enable_path_dict.pop("temp") 136 return_dict[name] = enable_path_dict 137 need_replace[name] = replace_path 138 return need_replace, return_dict, enable_path_dict, import_gni_path 139 140 def build_able_analyze(self, model_build_lines, replace_path, import_gni_path): 141 for index, line in enumerate(model_build_lines): 142 if re.search(self.re_temp_module_switch, line.strip()): 143 temp_name = re.search(self.re_temp_loscfg, 144 line.strip()).group() 145 elif re.search(self.re_left_macro, line.strip()): 146 if line.strip().endswith("="): 147 temp_str = line.strip() + \ 148 model_build_lines[index + 1].strip() 149 replace_path = self.build_line_analyze(temp_str, replace_path) 150 else: 151 temp_str = line.strip() 152 replace_path = self.build_line_analyze(temp_str, replace_path) 153 elif re.search(r"^import", line.strip()): 154 import_gni_path.append(line.strip()) 155 return import_gni_path, replace_path, temp_name 156 157 def build_line_analyze(self, temp_str, replace_path): 158 if re.search(self.re_right_macro, temp_str): 159 temp = re.search( 160 self.re_right_macro, temp_str).group() 161 temp_re_list = re.sub( 162 self.re_right_macro, 163 '${' + temp[1:] + "}", 164 temp_str).split("=") 165 replace_path[temp_re_list[0].strip()] = \ 166 temp_re_list[-1].strip().strip("\"") 167 else: 168 temp_split_list = temp_str.split("=") 169 replace_path[temp_split_list[0].strip()] = \ 170 temp_split_list[-1].strip().strip("\"") 171 return replace_path 172 173 def get_need_result_list(self, model_path_dict, name, import_replace_name, 174 import_gni_path, return_dict, need_replace): 175 multiple_path = {} 176 for path in model_path_dict[name]: 177 model_build = os.path.join(path, "BUILD.gn") 178 if not os.path.exists(model_build): 179 continue 180 model_build_lines = hdf_utils.read_file_lines(model_build) 181 key_index = self.get_index( 182 model_config_lines=model_build_lines) 183 replace_path = {} 184 enable_path_dict = self.enable_dict( 185 index_list=key_index, 186 enable_lines=model_build_lines, 187 path=path 188 ) 189 for index, line in enumerate(model_build_lines): 190 if re.search(self.re_temp_module_switch, line.strip()): 191 temp_name = re.search(self.re_temp_loscfg, 192 line.strip()).group() 193 elif re.search(self.re_left_macro, line.strip()): 194 replace_path = self.get_macro_replace_path( 195 line, model_build_lines, 196 index, replace_path, import_replace_name) 197 elif re.search(r"^import", line.strip()): 198 import_gni_path.append(line.strip()) 199 enable_path_dict[temp_name] = enable_path_dict.pop("temp") 200 multiple_path.update(enable_path_dict) 201 if need_replace.get(name): 202 need_replace[name].update(replace_path) 203 else: 204 need_replace[name] = replace_path 205 return_dict[name] = multiple_path 206 return need_replace, return_dict, enable_path_dict, import_gni_path 207 208 def get_macro_replace_path(self, line, model_build_lines, 209 index, replace_path, import_replace_name): 210 if line.strip().endswith("="): 211 temp_str = line.strip() + \ 212 model_build_lines[index + 1].strip() 213 replace_path = self.build_line_analyze( 214 temp_str, replace_path) 215 else: 216 temp_str = line.strip() 217 if re.search(self.re_right_macro, temp_str): 218 temp = re.search(self.re_right_macro, 219 temp_str).group() 220 temp_re_list = re.sub(self.re_right_macro, 221 '${' + temp[1:] + "}", 222 temp_str).split("=") 223 import_replace_name.add(temp[1:]) 224 replace_path[temp_re_list[0].strip()] = \ 225 temp_re_list[-1].strip().strip("\"") 226 return replace_path 227 228 def get_need_result(self, model_path_dict): 229 return_dict_temp = {} 230 need_replace_temp = {} 231 import_gni_path = [] 232 import_replace_name = set([]) 233 for name in list(model_path_dict.keys()): 234 if len(model_path_dict[name]) == 0: 235 pass 236 else: 237 if len(model_path_dict[name]) == 1: 238 need_replace, return_dict, \ 239 enable_path_dict, import_gni_path = \ 240 self.get_need_result_only( 241 model_path_dict, name, 242 import_gni_path, return_dict_temp, need_replace_temp) 243 else: 244 need_replace, return_dict, \ 245 enable_path_dict, import_gni_path = \ 246 self.get_need_result_list( 247 model_path_dict, name, import_replace_name, 248 import_gni_path, return_dict_temp, need_replace_temp) 249 250 for k_name in list(return_dict.keys()): 251 for model_detail in list(return_dict.get(k_name).keys()): 252 enable_key = '%s=y\n' % model_detail 253 if enable_key not in self.contents_config_enable: 254 del return_dict.get(k_name)[model_detail] 255 continue 256 if not return_dict.get(k_name).get(model_detail): 257 del return_dict.get(k_name)[model_detail] 258 else: 259 return_dict = self.format_replace_string( 260 return_dict, model_name=k_name, 261 model_detail=model_detail) 262 return return_dict, need_replace, \ 263 import_gni_path, import_replace_name 264 265 def format_replace_string(self, return_dict, model_name, model_detail): 266 temp_list = [] 267 for info in return_dict[model_name][model_detail]['drivers_sources']: 268 if re.search(self.re_right_macro, info): 269 temp = re.search(self.re_right_macro, info).group() 270 temp_re_str = re.sub(self.re_right_macro, 271 '${' + temp[1:] + "}", info) 272 temp_list.append(temp_re_str.strip().strip("\"")) 273 else: 274 temp_list.append(info.strip()) 275 return_dict[model_name][model_detail]['drivers_sources'] = temp_list 276 return return_dict 277 278 def get_index(self, model_config_lines): 279 index_list = [] 280 count = 0 281 for index, line in enumerate(model_config_lines): 282 if re.search(self.re_temp_header, line.strip())\ 283 or re.search(self.re_temp_if, line.strip()): 284 count += 1 285 index_list.append(index) 286 elif line.strip() == "}": 287 count -= 1 288 if count == 0: 289 index_list.append(index) 290 return index_list 291 292 def enable_dict(self, index_list, enable_lines, path): 293 config_name = ['BUILD.gn', 'Kconfig', 'Makefile'] 294 driver_configs = [] 295 result_dict = {} 296 for file_name in os.listdir(path): 297 if file_name in config_name: 298 driver_configs.append(os.path.join(path, file_name)) 299 for index_num in range(len(index_list) - 1): 300 temp_dict = {} 301 header_name, temp_list = self.get_header_list( 302 enable_lines, index_list, index_num) 303 if header_name is not None: 304 if header_name.find("if") != -1: 305 enable_name = re.search( 306 self.re_temp_loscfg, header_name).group() 307 else: 308 enable_name = "temp" 309 else: 310 enable_name = "temp" 311 temp_res_list = self.eval_source_str_path(temp_list) 312 replace_finish = [] 313 for temp_path in temp_res_list: 314 if temp_path.startswith('$'): 315 replace_finish.append(temp_path) 316 else: 317 replace_finish.append(os.path.join(path, temp_path)) 318 temp_dict["driver_configs"] = driver_configs 319 temp_dict["drivers_sources"] = replace_finish 320 result_dict[enable_name] = temp_dict 321 return result_dict 322 323 def eval_source_str_path(self, temp_list): 324 temp_res_list = [] 325 for temp_info in temp_list: 326 source_file_path1 = re.search( 327 self.re_source_file1, temp_info.strip()) 328 source_file_path2 = re.search( 329 self.re_source_file2, temp_info.strip()) 330 if source_file_path1: 331 temp_res_list.append(source_file_path1.group()) 332 elif source_file_path2: 333 list1 = temp_info.strip().split("=") 334 try: 335 str1 = ast.literal_eval(list1[-1].strip())[0] 336 except NameError: 337 continue 338 finally: 339 pass 340 temp_res_list.append(re.search( 341 self.re_source_file2, str1.strip()).group()) 342 return temp_res_list 343 344 def get_header_list(self, enable_lines, index_list, index_num): 345 count = 0 346 temp_list = [] 347 header_name = None 348 for line in enable_lines[index_list[index_num]: index_list[index_num + 1]]: 349 if re.search(self.re_temp_sources, line.strip()): 350 if line.strip().find("+=") > 0 and \ 351 line.strip().endswith("]"): 352 header_name = enable_lines[index_list[index_num]].strip() 353 temp_list.append(line) 354 continue 355 if line.strip().find("+=") > 0: 356 count += 1 357 header_name = enable_lines[index_list[index_num]].strip() 358 else: 359 count += 1 360 elif line.strip() == "]": 361 count -= 1 362 if count == 0: 363 break 364 if count > 0: 365 temp_list.append(line) 366 return header_name, temp_list 367 368 def replace_file_path(self, return_dict, import_gni_path, 369 import_replace_name, need_replace): 370 test_re = r'\([/ a-z . - " _]+\)' 371 import_path = [] 372 template_replace_dict = {} 373 for i in list(set(import_gni_path)): 374 temp_path = re.search(test_re, i).group()[2:-2] 375 if os.path.exists(self.root + temp_path): 376 self.found_import_file_path( 377 temp_path, import_path, 378 import_replace_name, template_replace_dict) 379 temp_template = Template(json.dumps(need_replace)) 380 replace_result_dict = json.loads(temp_template.substitute( 381 template_replace_dict)) 382 for key_model in list(return_dict.keys()): 383 replace_result_dict[key_model].update(template_replace_dict) 384 replace_dict = json.loads(json.dumps( 385 replace_result_dict[key_model]).replace("//", '/')) 386 temp_template1 = Template( 387 json.dumps(return_dict[key_model])) 388 temp_key_model = json.loads(temp_template1. 389 substitute(replace_dict)) 390 temp_res_key_model = self.driver_source_filter(temp_key_model) 391 return_dict[key_model] = temp_res_key_model 392 return_dict["deconfig"] = self.dot_file[0] 393 return_dict["build"] = self.build_path 394 return_dict["hcs_path"] = self.hcs_path 395 return json.dumps(return_dict, indent=4) 396 397 def driver_source_filter(self, temp_key_model): 398 for enable_name_lower in list(temp_key_model.keys()): 399 if enable_name_lower.find("HDF") != -1: 400 key_name = ''.join(["HDF", enable_name_lower. 401 split("HDF")[-1]]).lower() 402 else: 403 key_name = enable_name_lower.lower() 404 temp_key_model[key_name] = temp_key_model.pop(enable_name_lower) 405 for file_path in temp_key_model[key_name]["drivers_sources"]: 406 if not os.path.exists(file_path): 407 temp_key_model[key_name]["drivers_sources"].remove(file_path) 408 return temp_key_model 409 410 def get_model_scan(self): 411 liteos_model = self.scan_build() 412 model_path_dict = self._get_model_file_dict(liteos_model=liteos_model) 413 model_path_dict = self.model_able_scan(model_path_dict) 414 return_dict, need_replace, import_gni_path, import_replace_name =\ 415 self.get_need_result(model_path_dict) 416 return self.replace_file_path(return_dict, import_gni_path, 417 import_replace_name, need_replace) 418 419 def found_import_file_path(self, temp_path, import_path, 420 import_replace_name, template_replace_dict): 421 import_info = hdf_utils.read_file_lines(self.root + temp_path) 422 for temp_import in import_info: 423 if re.search(r"^import", temp_import.strip()): 424 import_path.append(temp_import.strip("import")[2:-3]) 425 for import_element in import_path: 426 import_info.extend(hdf_utils. 427 read_file_lines(self.root + import_element[1:])) 428 for name in import_replace_name: 429 for temp_import in import_info: 430 re_replace = "^%s" % name 431 if re.search(re_replace, temp_import.strip()): 432 replace_line = temp_import.strip().split("=") 433 template_replace_dict[replace_line[0].strip()] =\ 434 self.root + replace_line[-1]\ 435 .strip().strip('"') 436 break 437