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 59 def scan_makefile(self): 60 model_enable_dict = {} 61 for index, lines in enumerate(self.contents): 62 temp_list = [] 63 obj_result = re.search(self.re_temp2_obj, lines.strip()) 64 if not obj_result: 65 continue 66 enable_name_result = re.search( 67 self.re_temp3_enable, lines.strip()) 68 model_path = lines.split("+=")[-1].strip() 69 model_name_result = re.search( 70 self.re_temp1_model, model_path) 71 if not model_name_result: 72 continue 73 model_name = enable_name_result.group() 74 model_path = os.path.join(os.path.sep.join( 75 self.makefile_path.split(os.path.sep)[:-1]), model_path) 76 temp_list.append(model_path) 77 if os.path.exists(model_path): 78 if model_enable_dict.get(model_name, None): 79 model_enable_dict[model_name] = \ 80 temp_list + model_enable_dict.get(model_name) 81 else: 82 model_enable_dict[model_name] = temp_list 83 return model_enable_dict 84 85 def get_config_path(self): 86 model_defconfig_list = [] 87 config_path = hdf_utils.\ 88 get_config_config_path(root=self.root, kernel=self.kernel) 89 for roots, dirs, files in os.walk(config_path): 90 for file_name in files: 91 if file_name.endswith("small_defconfig"): 92 model_defconfig_list.append(os.path.join(roots, file_name)) 93 return model_defconfig_list 94 95 def enable_scan(self): 96 enable_list = [] 97 judge_enable_dict = self.scan_makefile() 98 defconfig_path = self.get_config_path()[0] 99 config_enable_lines = hdf_utils.read_file_lines(defconfig_path) 100 for enable_name, model_path in judge_enable_dict.items(): 101 # First determine whether the enable file is enabled 102 # (get the enable configuration file path) 103 if ('%s=y\n' % enable_name) not in config_enable_lines: 104 continue 105 if "Makefile" in os.listdir(model_path[0]): 106 if os.path.join(model_path[0], 107 'Makefile') not in enable_list: 108 enable_list.append( 109 os.path.join(model_path[0], 'Makefile')) 110 return enable_list 111 112 def _get_model_file_dict(self): 113 model_file_dict = {} 114 for model_name in self.scan_makefile(): 115 model_file_dict[model_name] = [] 116 path = os.path.join(self.framework_dir, model_name) 117 for root_path, dirs, files in os.walk(path): 118 for file_name in files: 119 model_file_dict.get(model_name).append( 120 os.path.join(root_path, file_name)) 121 return model_file_dict 122 123 def _get_model_name(self, model_makefile_path): 124 parent_path = "/".join(model_makefile_path.split("/")[:-1]) 125 config_file_path = [] 126 for i in os.listdir(parent_path): 127 if i in self.driver_configs_list: 128 config_file_path.append(os.path.join(parent_path, i)) 129 model_name = re.search( 130 self.re_temp1_model, model_makefile_path).group().split("/")[-1] 131 return model_name 132 133 def scan_enable_dict(self, lines, test_dict, names): 134 re_temp3 = "CONFIG_[A-Z _ 0-9]+" 135 list1_12 = [] 136 for index, line in enumerate(lines): 137 if re.search("^ifeq", line): 138 list1_12.append(index) 139 elif re.search("^endif", line): 140 list1_12.append(index + 1) 141 obj_list = self.get_obj(lines) 142 143 if list1_12: 144 obj_list.extend(list1_12) 145 obj_list.sort() 146 obj_list = list(filter( 147 lambda x: x >= list1_12[1] or x <= list1_12[0], obj_list)) 148 if obj_list == list1_12: 149 obj_list.clear() 150 151 obj_list = self.split_list(obj_list) 152 if list1_12 in obj_list: 153 obj_list.remove(list1_12) 154 155 if list1_12: 156 names = re.search(re_temp3, lines[list1_12[0]].strip()).group() 157 test2_dict = {} 158 test_dict[names] = self.scan_enable_dict( 159 lines[list1_12[0] + 1:list1_12[1] - 1], test2_dict, names) 160 temp_lines = lines 161 else: 162 temp_lines = lines 163 temp_list00 = [] 164 for i in obj_list: 165 if i[0] == i[1]: 166 continue 167 temp_result = re.search(re_temp3, temp_lines[i[0]].strip()) 168 temp_list2 = [] 169 if temp_result is not None: 170 key_name = temp_result.group() 171 temp_list00.append(key_name) 172 else: 173 key_name = names 174 for j in temp_lines[i[0]: i[1]]: 175 if j.strip().strip("\\").strip().split(".")[-1] == "o": 176 temp_list2.append(j.strip().strip("\\").strip()) 177 if key_name is None: 178 key_name = temp_list00[-1] 179 180 if test_dict.get(key_name, None): 181 if isinstance((test_dict[key_name]), list): 182 test_dict[key_name] = test_dict[key_name] + temp_list2 183 else: 184 test_dict[key_name] = test_dict[key_name][key_name] + temp_list2 185 else: 186 test_dict[key_name] = temp_list2 187 188 return test_dict 189 190 def get_obj(self, lines): 191 # 查找所有 obj 的开头和结尾 192 re_temp2 = "^obj-" 193 re_temp1 = "^ccflags" 194 status = 0 195 list1 = [] 196 for index, line in enumerate(lines): 197 temp_result_obj = re.search(re_temp2, line.strip()) 198 if temp_result_obj: 199 status = 1 200 list1.append(index) 201 temp_result_flag = re.search(re_temp1, line.strip()) 202 if temp_result_flag and status == 1: 203 status = 2 204 list1.append(index) 205 break 206 # 如果status 为1时说明没有找到结尾,将整个长度的结尾 207 if status == 1: 208 list1.append(len(lines)) 209 return list1 210 211 def split_list(self, src_list): 212 test_list1 = [] 213 for i in range(len(src_list) - 1): 214 test_list1.append([src_list[i], src_list[i + 1]]) 215 return test_list1 216 217 def get_model_scan(self): 218 enable_model_path_list = self.enable_scan() 219 result_dict = {} 220 for model_makefile_path in enable_model_path_list: 221 model_name = self._get_model_name(model_makefile_path) 222 model_makefile_lines = hdf_utils.\ 223 read_file_lines(model_makefile_path) 224 enable_dict = {} 225 config_enable_lines = hdf_utils.\ 226 read_file_lines(self.get_config_path()[0]) 227 result = self.scan_enable_dict( 228 model_makefile_lines, enable_dict, names=None) 229 name_split_dict, enable_list = \ 230 self.name_split_func(result, config_enable_lines) 231 enable_dict = self.path_replace( 232 lines=model_makefile_lines, 233 enable_list=enable_list, 234 makefile_path=model_makefile_path) 235 result = self._prefix_template_replace( 236 name_split_dict, enable_dict, 237 makefile_path=model_makefile_path) 238 if result_dict.get(model_name, None): 239 result_dict.get(model_name).update(result) 240 else: 241 result_dict[model_name] = result 242 result_dict["deconfig"] = self.get_config_path()[0] 243 result_dict["makefile_path"] = self.makefile_path 244 result_dict["hcs_path"] = self.hcs_path 245 return json.dumps(result_dict, indent=4) 246 247 def scann_driver_configs(self, makefile_path): 248 driver_configs_list = ['Kconfig', 'Makefile'] 249 parent_path = "/".join(makefile_path.split("/")[:-1]) 250 config_file_path = [] 251 for i in os.listdir(parent_path): 252 if i in driver_configs_list: 253 config_file_path.append(os.path.join( 254 parent_path, i).replace("/", os.path.sep)) 255 return config_file_path 256 257 def _prefix_template_replace(self, 258 name_split_dict, enable_dict, 259 makefile_path): 260 config_file_path = self.scann_driver_configs(makefile_path) 261 return_dict = {} 262 temp_template = Template(json.dumps(name_split_dict)) 263 replace_result_dict = json.loads(temp_template.substitute(enable_dict)) 264 for result_k, result_v in replace_result_dict.items(): 265 if not isinstance(result_v, dict): 266 return_dict[result_k] = {} 267 drivers_sources = [] 268 drivers_sources_list = self.drivers_file_find( 269 result_v, makefile_path, drivers_sources) 270 return_dict[result_k] = { 271 "driver_configs": config_file_path, 272 "drivers_sources": drivers_sources_list, 273 } 274 else: 275 return_dict[result_k] = {} 276 for result_assistant_k, result_assistant_v in result_v.items(): 277 drivers_sources = [] 278 drivers_sources_list = self.drivers_file_find( 279 result_assistant_v, makefile_path, drivers_sources) 280 return_dict.get(result_k)[result_assistant_k] = { 281 "driver_configs": config_file_path, 282 "drivers_sources": drivers_sources_list, 283 } 284 return return_dict 285 286 def drivers_file_find(self, args_list, makefile_path, drivers_sources): 287 for info in args_list: 288 info = info.replace(".o", ".c") 289 prefix4_field = re.search(self.re_temp_current, info) 290 prefix5_field = re.search(self.te_temp5, info) 291 if prefix4_field or prefix5_field: 292 replace_field = "/".join( 293 makefile_path.replace("\\", '/'). 294 split("/")[:-1] 295 ) + "/" 296 if prefix4_field: 297 info = info.replace(prefix4_field.group(), 298 replace_field).strip() 299 elif prefix5_field: 300 info = os.path.join(replace_field, info) 301 if info.find("=") != -1: 302 info = info.split("=")[-1].strip() 303 if os.path.exists(info): 304 drivers_sources.append(info) 305 return drivers_sources 306 307 def path_replace(self, lines, enable_list, makefile_path): 308 enable_dict = {} 309 include_list = [] 310 for line in lines: 311 if re.search(self.re_temp4_include, line): 312 include_list.append( 313 os.path.join(makefile_path.strip("Makefile"), 314 line.strip().split("/")[-1])) 315 include_lines = [] 316 for include_file in include_list: 317 if os.path.exists(include_file): 318 with open(include_file, "r") as f: 319 include_lines = f.readlines() 320 if include_lines: 321 lines.extend(include_lines) 322 323 for key_enable in list(set(enable_list)): 324 re_enable = '^%s' % key_enable 325 for line in lines: 326 result = re.search(re_enable, line) 327 if not result: 328 continue 329 line = line.strip().split("=")[-1].strip() 330 enable_dict = self.parent_path_regular( 331 line, enable_dict, key_enable, makefile_path) 332 return enable_dict 333 334 def parent_path_regular(self, line, enable_dict, key_enable, makefile_path): 335 result_replace_field = re.search( 336 self.re_temp_prefix0, line) 337 prefix1_field = re.search(self.re_temp_prefix1, line) 338 prefix2_field = re.search(self.re_temp_prefix2, line) 339 prefix3_field = re.search(self.re_temp_current, line) 340 if result_replace_field or prefix1_field \ 341 or prefix2_field or prefix3_field: 342 if result_replace_field: 343 enable_dict[key_enable] = self.parent_path_splice( 344 self.re_temp_prefix0, line) 345 if prefix1_field: 346 enable_dict[key_enable] = self.parent_path_splice( 347 self.re_temp_prefix1, line) 348 if prefix2_field: 349 enable_dict[key_enable] = "/".join( 350 [self.root, line.strip( 351 prefix2_field.group() + "/").strip()]) 352 if prefix3_field: 353 replace_field = "/".join( 354 makefile_path.replace("\\", '/').split("/")[:-1]) 355 enable_dict[key_enable] = line.replace( 356 prefix3_field.group(), replace_field).strip() 357 else: 358 enable_dict[key_enable] = line.split("=")[-1].strip() 359 return enable_dict 360 361 def parent_path_splice(self, re_prefix, line): 362 re_split_list = re.split(re_prefix, line) 363 if re_split_list[-1].startswith("hdf_core"): 364 return "/".join([self.root, "drivers", 365 re_split_list[-1].strip()]) 366 else: 367 if re_split_list[-1].startswith("framework"): 368 return "/".join([self.root, "drivers/hdf_core", 369 re_split_list[-1].strip()]) 370 else: 371 return "/".join([self.root, "drivers", 372 re_split_list[-1].strip()]) 373 374 def name_split_func(self, result, config_enable_lines): 375 enable_list = [] 376 name_split_dict = {} 377 for enable_key, enable_value in result.items(): 378 key = "%s=y\n" % enable_key 379 if key not in config_enable_lines: 380 continue 381 if isinstance(enable_value, list): 382 if enable_key.find("HDF") != -1: 383 k2 = ''.join( 384 ["HDF", enable_key.split("HDF")[-1]] 385 ).lower() 386 else: 387 k2 = enable_key.lower() 388 name_split_dict[k2] = [] 389 for name in enable_value: 390 child_enable_list, str1 = self.get_driver(name) 391 enable_list.extend(child_enable_list) 392 name_split_dict.get(k2).append(str1) 393 return name_split_dict, enable_list 394 395 def get_driver(self, name): 396 if name.find("+=") != -1: 397 return self.get_name(str1=name.split("+=")[-1].strip()) 398 else: 399 return self.get_name(str1=name.strip()) 400 401 def operate_dict(self, enable_key, name_split_dict, enable_value, 402 config_enable_lines, enable_list): 403 if enable_key.find("HDF") != -1: 404 child_enable_key = ''.join( 405 ["HDF", enable_key.split("HDF")[-1]] 406 ).lower() 407 else: 408 child_enable_key = enable_key.lower() 409 name_split_dict[child_enable_key] = {} 410 for k1, v1 in enable_value.items(): 411 if k1.find("HDF") != -1: 412 grand_enable_key = ''.join( 413 ["HDF", k1.split("HDF")[-1]] 414 ).lower() 415 else: 416 grand_enable_key = k1.lower() 417 # First judge the enables of the second level 418 # (if there is no enable, the next file is directly) 419 key1 = "%s=y\n" % k1 420 if key1 in config_enable_lines: 421 name_split_dict.get(child_enable_key)[grand_enable_key] = [] 422 for name in v1: 423 # Divided into several cases 424 child_enable_list, str1 = self.get_driver(name) 425 enable_list.extend(child_enable_list) 426 name_split_dict.get(child_enable_key).get( 427 grand_enable_key).append(str1) 428 else: 429 continue 430 return enable_list, name_split_dict 431 432 def get_name(self, str1): 433 temp_re = "[A-Z _ 0-9]+" 434 list1 = str1.split("/") 435 list2 = [] 436 for i in list1: 437 if i.find('$(') != -1: 438 temp_name = re.search(temp_re, i) 439 if temp_name: 440 list2.append(temp_name.group()) 441 dict1 = {"$(": "${", ")": "}"} 442 for k, v in dict1.items(): 443 str1 = str1.replace(k, v) 444 return list2, str1 445