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 platform 14import re 15from string import Template 16 17import hdf_utils 18from hdf_tool_exception import HdfToolException 19from .hdf_command_error_code import CommandErrorCode 20 21 22class HdfLinuxScan(object): 23 def __init__(self, root, vendor, board): 24 self.root = root 25 self.vendor = vendor 26 self.board = board 27 self.kernel = "linux" 28 29 self.makefile_path = hdf_utils.get_vendor_makefile_path( 30 root, kernel="linux") 31 if not os.path.exists(self.makefile_path): 32 raise HdfToolException( 33 'Makefile: %s not exist' % self.makefile_path, 34 CommandErrorCode.TARGET_NOT_EXIST) 35 36 self.framework_dir = hdf_utils.get_module_dir(self.root) 37 if not os.path.exists(self.framework_dir): 38 raise HdfToolException( 39 'file: %s not exist' % self.framework_dir, 40 CommandErrorCode.TARGET_NOT_EXIST) 41 42 self.hcs_path = hdf_utils.get_hcs_file_path( 43 self.root, self.vendor, self.board) 44 if not os.path.exists(self.hcs_path): 45 raise HdfToolException('file: %s not exist' % self.hcs_path, 46 CommandErrorCode.TARGET_NOT_EXIST) 47 self.contents = hdf_utils.read_file_lines(self.makefile_path) 48 self.driver_configs_list = ['Kconfig', 'Makefile'] 49 self.re_temp1_model = r'model/[a-z _ 0-9]+' 50 self.re_temp2_obj = r"^obj-" 51 self.re_temp3_enable = r"CONFIG_DRIVERS_[A-Z _ 0-9]+" 52 self.re_temp4_include = r"^include" 53 self.re_temp_prefix0 = r"^../[. /]+" 54 self.re_temp_prefix1 = r"\$\(HDF_DIR_PREFIX\)" 55 self.re_temp_prefix2 = r"\$\(KHDF_AUDIO_BASE_ROOT_DIR\)" 56 self.re_temp_current = r"^\.\/" 57 self.te_temp5 = r"^[a-z]" 58 if platform.system().lower() == 'windows': 59 self.platform = "windows" 60 elif platform.system().lower() == 'linux': 61 self.platform = "linux" 62 63 def scan_makefile(self): 64 model_enable_dict = {} 65 for index, lines in enumerate(self.contents): 66 temp_list = [] 67 obj_result = re.search(self.re_temp2_obj, lines.strip()) 68 if obj_result: 69 enable_name_result = re.search( 70 self.re_temp3_enable, lines.strip()) 71 model_path = lines.split("+=")[-1].strip() 72 model_name_result = re.search( 73 self.re_temp1_model, model_path) 74 if model_name_result: 75 model_name = enable_name_result.group() 76 if self.platform == "windows": 77 model_path =\ 78 os.path.join('\\'.join(self.makefile_path. 79 split('\\')[:-1]), model_path) 80 elif self.platform == "linux": 81 model_path = \ 82 os.path.join('/'.join( 83 self.makefile_path.split('/')[:-1]), model_path) 84 temp_list.append(model_path) 85 if os.path.exists(model_path): 86 if model_enable_dict.get(model_name, None): 87 model_enable_dict[model_name] =\ 88 temp_list + model_enable_dict.get(model_name) 89 else: 90 model_enable_dict[model_name] = temp_list 91 return model_enable_dict 92 93 def get_config_path(self): 94 model_defconfig_list = [] 95 config_path = hdf_utils.\ 96 get_config_config_path(root=self.root, kernel=self.kernel) 97 for roots, dirs, files in os.walk(config_path): 98 for file_name in files: 99 if file_name.strip() == "hi3516dv300_small_defconfig": 100 model_defconfig_list.append(os.path.join(roots, file_name)) 101 return model_defconfig_list 102 103 def enable_scan(self): 104 enable_list = [] 105 judge_enable_dict = self.scan_makefile() 106 defconfig_path = self.get_config_path()[0] 107 config_enable_lines = hdf_utils.read_file_lines(defconfig_path) 108 for enable_name, model_path in judge_enable_dict.items(): 109 # 先去判断使能文件中是否使能(获取使能配置文件路径) 110 if ('%s=y\n' % enable_name) in config_enable_lines: 111 if "Makefile" in os.listdir(model_path[0]): 112 if os.path.join(model_path[0], 113 'Makefile') not in enable_list: 114 enable_list.append( 115 os.path.join(model_path[0], 'Makefile')) 116 return enable_list 117 118 def _get_model_file_dict(self): 119 model_file_dict = {} 120 for model_name in self.scan_makefile(): 121 model_file_dict[model_name] = [] 122 path = os.path.join(self.framework_dir, model_name) 123 for root_path, dirs, files in os.walk(path): 124 for file_name in files: 125 model_file_dict.get(model_name).append( 126 os.path.join(root_path, file_name)) 127 return model_file_dict 128 129 def _get_model_name(self, model_makefile_path): 130 parent_path = "/".join(model_makefile_path.split("/")[:-1]) 131 config_file_path = [] 132 for i in os.listdir(parent_path): 133 if i in self.driver_configs_list: 134 config_file_path.append(os.path.join(parent_path, i)) 135 model_name = re.search( 136 self.re_temp1_model, model_makefile_path).group().split("/")[-1] 137 return model_name 138 139 def scan_enable_dict(self, lines, test_dict, names): 140 re_temp3 = "CONFIG_[A-Z _ 0-9]+" 141 142 list1_12 = [] 143 for index, line in enumerate(lines): 144 if re.search("^ifeq", line): 145 list1_12.append(index) 146 elif re.search("^endif", line): 147 list1_12.append(index + 1) 148 obj_list = self.get_obj(lines) 149 150 if list1_12: 151 obj_list.extend(list1_12) 152 obj_list.sort() 153 obj_list = list(filter( 154 lambda x: x >= list1_12[1] or x <= list1_12[0], obj_list)) 155 if obj_list == list1_12: 156 obj_list.clear() 157 158 obj_list = self.split_list(obj_list) 159 if list1_12 in obj_list: 160 obj_list.remove(list1_12) 161 162 if list1_12: 163 names = re.search(re_temp3, lines[list1_12[0]].strip()).group() 164 test2_dict = {} 165 test_dict[names] = self.scan_enable_dict\ 166 (lines[list1_12[0] + 1:list1_12[1] - 1], test2_dict, names) 167 temp_lines = lines 168 else: 169 temp_lines = lines 170 temp_list00 = [] 171 for i in obj_list: 172 if i[0] == i[1]: 173 continue 174 temp_result = re.search(re_temp3, temp_lines[i[0]].strip()) 175 temp_list2 = [] 176 if temp_result is not None: 177 key_name = temp_result.group() 178 temp_list00.append(key_name) 179 else: 180 key_name = names 181 for j in temp_lines[i[0]: i[1]]: 182 if j.strip().strip("\\").strip().split(".")[-1] == "o": 183 temp_list2.append(j.strip().strip("\\").strip()) 184 if key_name is None: 185 key_name = temp_list00[-1] 186 187 if test_dict.get(key_name, None): 188 if isinstance((test_dict[key_name]), list): 189 test_dict[key_name] = test_dict[key_name] + temp_list2 190 else: 191 test_dict[key_name] = test_dict[key_name][key_name] + temp_list2 192 else: 193 test_dict[key_name] = temp_list2 194 195 return test_dict 196 197 def get_obj(self, lines): 198 # 查找所有 obj 的开头和结尾 199 re_temp2 = "^obj-" 200 re_temp1 = "^ccflags" 201 status = 0 202 list1 = [] 203 for index, line in enumerate(lines): 204 temp_result_obj = re.search(re_temp2, line.strip()) 205 if temp_result_obj: 206 status = 1 207 list1.append(index) 208 temp_result_flag = re.search(re_temp1, line.strip()) 209 if temp_result_flag and status == 1: 210 status = 2 211 list1.append(index) 212 break 213 # 如果status 为1时说明没有找到结尾,将整个长度的结尾 214 if status == 1: 215 list1.append(len(lines)) 216 return list1 217 218 def split_list(self, src_list): 219 test_list1 = [] 220 for i in range(len(src_list) - 1): 221 test_list1.append([src_list[i], src_list[i + 1]]) 222 return test_list1 223 224 def get_model_scan(self): 225 enable_model_path_list = self.enable_scan() 226 result_dict00 = {} 227 for model_makefile_path in enable_model_path_list: 228 model_name = self._get_model_name(model_makefile_path) 229 model_makefile_lines = hdf_utils.\ 230 read_file_lines(model_makefile_path) 231 enable_dict = {} 232 config_enable_lines = hdf_utils.\ 233 read_file_lines(self.get_config_path()[0]) 234 result = self.scan_enable_dict( 235 model_makefile_lines, enable_dict, names=None) 236 name_split_dict, enable_list = \ 237 self.name_split_func(result, config_enable_lines) 238 enable_dict = self.path_replace( 239 lines=model_makefile_lines, 240 enable_list=enable_list, 241 makefile_path=model_makefile_path) 242 result = self._prefix_template_replace( 243 name_split_dict, enable_dict, 244 makefile_path=model_makefile_path) 245 if result_dict00.get(model_name, None): 246 result_dict00.get(model_name).update(result) 247 else: 248 result_dict00[model_name] = result 249 result_dict00["deconfig"] = self.get_config_path()[0] 250 result_dict00["makefile_path"] = self.makefile_path 251 result_dict00["hcs_path"] = self.hcs_path 252 return json.dumps(result_dict00, indent=4) 253 254 def scann_driver_configs(self, makefile_path): 255 driver_configs_list = ['Kconfig', 'Makefile'] 256 parent_path = "/".join(makefile_path.split("/")[:-1]) 257 config_file_path = [] 258 for i in os.listdir(parent_path): 259 if i in driver_configs_list: 260 if self.platform == "windows": 261 config_file_path.append( 262 os.path.join(parent_path, i).replace("/", "\\")) 263 elif self.platform == "linux": 264 config_file_path.append(os.path.join(parent_path, i)) 265 return config_file_path 266 267 def _prefix_template_replace(self, 268 name_split_dict, enable_dict, 269 makefile_path): 270 config_file_path = self.scann_driver_configs(makefile_path) 271 return_dict = {} 272 temp_template = Template(json.dumps(name_split_dict)) 273 dict000 = json.loads(temp_template.substitute(enable_dict)) 274 for k0, v0 in dict000.items(): 275 if isinstance(v0, dict): 276 return_dict[k0] = {} 277 for k01, v01 in v0.items(): 278 drivers_sources = [] 279 for i in v01: 280 i = i.replace(".o", ".c") 281 prefix4_field = re.search(self.re_temp_current, i) 282 prefix5_field = re.search(self.te_temp5, i) 283 284 if prefix4_field or prefix5_field: 285 replace_field = "/".join( 286 makefile_path.replace("\\", '/'). 287 split("/")[:-1] 288 ) + "/" 289 if prefix4_field: 290 i = i.replace(prefix4_field.group(), 291 replace_field).strip() 292 elif prefix5_field: 293 i = os.path.join(replace_field, i) 294 if os.path.exists(i): 295 drivers_sources.append(i) 296 return_dict.get(k0)[k01] = { 297 "driver_configs": config_file_path, 298 "drivers_sources": drivers_sources, 299 } 300 else: 301 return_dict[k0] = {} 302 drivers_sources = [] 303 for i in v0: 304 i = i.replace(".o", ".c") 305 prefix5_field = re.search(self.te_temp5, i) 306 prefix4_field = re.search(self.re_temp_current, i) 307 if prefix4_field or prefix5_field: 308 replace_field = "/".join( 309 makefile_path.replace("\\", '/'). 310 split("/")[:-1] 311 ) + "/" 312 if prefix4_field: 313 i = i.replace(prefix4_field.group(), 314 replace_field).strip() 315 elif prefix5_field: 316 i = os.path.join(replace_field, i) 317 if i.find("=") != -1: 318 i = i.split("=")[-1].strip() 319 if os.path.exists(i): 320 drivers_sources.append(i) 321 return_dict[k0] = { 322 "driver_configs": config_file_path, 323 "drivers_sources": drivers_sources, 324 } 325 return return_dict 326 327 def path_replace(self, lines, enable_list, makefile_path): 328 enable_dict = {} 329 include_list = [] 330 for line in lines: 331 if re.search(self.re_temp4_include, line): 332 include_list.append( 333 os.path.join(makefile_path.strip("Makefile"), 334 line.strip().split("/")[-1])) 335 include_lines = [] 336 for include_file in include_list: 337 if os.path.exists(include_file): 338 with open(include_file, "r") as f: 339 include_lines = f.readlines() 340 if include_lines: 341 lines.extend(include_lines) 342 343 for key_enable in list(set(enable_list)): 344 re_enable = '^%s' % key_enable 345 for line in lines: 346 result = re.search(re_enable, line) 347 if result: 348 line = line.strip().split("=")[-1].strip() 349 result_replace_field = re.search( 350 self.re_temp_prefix0, line) 351 prefix1_field = re.search(self.re_temp_prefix1, line) 352 prefix2_field = re.search(self.re_temp_prefix2, line) 353 prefix3_field = re.search(self.re_temp_current, line) 354 if result_replace_field or \ 355 prefix1_field or \ 356 prefix2_field or \ 357 prefix3_field: 358 if result_replace_field: 359 enable_dict[key_enable] = \ 360 "/".join( 361 [self.root, 362 line.replace(result_replace_field.group(), 363 "drivers/").strip()]) 364 if prefix1_field: 365 enable_dict[key_enable] = \ 366 "/".join( 367 [self.root, 368 line.replace(prefix1_field.group(), 369 "drivers").strip()] 370 ) 371 if prefix2_field: 372 enable_dict[key_enable] = \ 373 "/".join( 374 [self.root, 375 line.strip(prefix2_field.group() + "/"). 376 strip()] 377 ) 378 if prefix3_field: 379 replace_field = \ 380 "/".join( 381 makefile_path.replace("\\", '/'). 382 split("/")[:-1] 383 ) 384 enable_dict[key_enable] = \ 385 line.replace(prefix3_field.group(), 386 replace_field).strip() 387 else: 388 enable_dict[key_enable] = line.split("=")[-1].strip() 389 return enable_dict 390 391 def name_split_func(self, result, config_enable_lines): 392 enable_list = [] 393 name_split_dict = {} 394 for enable_key, enable_value in result.items(): 395 key = "%s=y\n" % enable_key 396 if key in config_enable_lines: 397 if isinstance(enable_value, dict): 398 # 先判断第一级的使能(没有使能的话直接下一个文件) 399 if enable_key.find("HDF") != -1: 400 child_enable_key = ''.join( 401 ["HDF", enable_key.split("HDF")[-1]] 402 ).lower() 403 else: 404 child_enable_key = enable_key.lower() 405 name_split_dict[child_enable_key] = {} 406 for k1, v1 in enable_value.items(): 407 if k1.find("HDF") != -1: 408 grand_enable_key = ''.join( 409 ["HDF", k1.split("HDF")[-1]] 410 ).lower() 411 else: 412 grand_enable_key = k1.lower() 413 # 先判断第二级的使能(没有使能的话直接下一个文件) 414 key1 = "%s=y\n" % k1 415 if key1 in config_enable_lines: 416 name_split_dict.get(child_enable_key)[grand_enable_key] = [] 417 for name in v1: 418 # 分为 几种情况 419 if name.find("+=") != -1: 420 child_enable_list, str1 = \ 421 self.get_name( 422 str1=name.split("+=")[-1].strip() 423 ) 424 else: 425 child_enable_list, str1 = \ 426 self.get_name(str1=name.strip()) 427 enable_list.extend(child_enable_list) 428 name_split_dict.get(child_enable_key).get(grand_enable_key).append(str1) 429 else: 430 continue 431 elif isinstance(enable_value, list): 432 if enable_key.find("HDF") != -1: 433 k2 = ''.join( 434 ["HDF", enable_key.split("HDF")[-1]] 435 ).lower() 436 else: 437 k2 = enable_key.lower() 438 name_split_dict[k2] = [] 439 for name in enable_value: 440 if name.find("+=") != -1: 441 child_enable_list, str1 = \ 442 self.get_name( 443 str1=name.split("+=")[-1].strip()) 444 else: 445 child_enable_list, str1 = \ 446 self.get_name(str1=name.strip()) 447 enable_list.extend(child_enable_list) 448 name_split_dict.get(k2).append(str1) 449 else: 450 continue 451 return name_split_dict, enable_list 452 453 def get_name(self, str1): 454 temp_re = "[A-Z _ 0-9]+" 455 list1 = str1.split("/") 456 list2 = [] 457 for i in list1: 458 if i.find('$(') != -1: 459 temp_name = re.search(temp_re, i) 460 if temp_name: 461 list2.append(temp_name.group()) 462 dict1 = {"$(": "${", ")": "}"} 463 for k, v in dict1.items(): 464 str1 = str1.replace(k, v) 465 return list2, str1 466