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 os 12import re 13from string import Template 14 15import hdf_utils 16from .hdf_dot_config_file import HdfDotConfigFile 17 18 19class HdfModuleKconfigFile(object): 20 def __init__(self, root, module, k_path): 21 self.root = root 22 self.module = module 23 self.k_path = k_path 24 self.module_models = { 25 'self': {}, 26 'children': [] 27 } 28 self.lines = [] 29 self.dot_config = None 30 self.config_re = re.compile(r'\s*config\s+([a-zA-Z0-9_\-]+)') 31 self.depends_on_re = re.compile(r'depends\s+on\s+([a-zA-Z0-9_\-]+)') 32 self.choice_re = re.compile(r'^\s*choice\s*$') 33 self.endchoice_re = re.compile(r'^\s*endchoice\s*$') 34 self.config_splitter = 'DRIVERS_HDF_' 35 self.top_res = [ 36 (self.config_re, self._parse_config), 37 (self.choice_re, self._parse_choice), 38 (self.endchoice_re, None) 39 ] 40 41 def _add_model(self, name_, config_item_, depends_on_item_, enabled_): 42 model = {'name': name_, 43 'config_item': config_item_, 44 'depends_on_item': depends_on_item_, 45 'enabled': enabled_} 46 if name_ == self.module: 47 self.module_models['self'] = model 48 else: 49 self.module_models.get('children').append(model) 50 51 def _is_any_top_res_match(self, line): 52 for re_pair in self.top_res: 53 if re_pair[0].search(line): 54 return True 55 return False 56 57 def _block_top_match(self, current_index, parent_item): 58 line = self.lines[current_index] 59 for re_pair in self.top_res: 60 match_obj = re_pair[0].search(line) 61 if match_obj: 62 func_obj = re_pair[1] 63 if func_obj is not None: 64 return func_obj(match_obj, current_index, parent_item) 65 return 0 66 67 def _parse_config(self, match_obj, start, parent_item): 68 config_item = match_obj.group(1) 69 parts = config_item.split(self.config_splitter) 70 valid_parts = [part for part in parts if part] 71 if not valid_parts: 72 return 73 config_name = valid_parts[-1].lower() 74 depends_on_item = '' 75 end = start + 1 76 while end < len(self.lines): 77 line = self.lines[end] 78 match_obj = self.depends_on_re.search(line) 79 if match_obj: 80 depends_on_item = match_obj.group(1) 81 break 82 if self._is_any_top_res_match(line): 83 break 84 end += 1 85 if not depends_on_item: 86 depends_on_item = parent_item 87 block_lines = end - start 88 else: 89 block_lines = end - start + 1 90 enabled = self.dot_config.is_enabled(config_item, depends_on_item) 91 self._add_model(config_name, config_item, depends_on_item, enabled) 92 return block_lines 93 94 def _parse_choice(self, _match_obj, start, _parent_item): 95 end = start + 1 96 common_depends_on_item = '' 97 depends_on_obj = None 98 while end < len(self.lines): 99 line = self.lines[end] 100 match_obj = self.depends_on_re.search(line) 101 if match_obj: 102 if not depends_on_obj: 103 depends_on_obj = match_obj 104 common_depends_on_item = match_obj.group(1) 105 end += 1 106 continue 107 if self.endchoice_re.search(line): 108 end += 1 109 return end - start + 1 110 consumed = self._block_top_match(end, common_depends_on_item) 111 if consumed: 112 end += consumed 113 else: 114 end += 1 115 116 def get_models(self): 117 if not os.path.exists(self.k_path): 118 return 119 self.lines = hdf_utils.read_file_lines(self.k_path) 120 dot_config_path = hdf_utils.get_liteos_a_dot_config_path(self.root) 121 self.dot_config = HdfDotConfigFile(dot_config_path) 122 index = 0 123 while index < len(self.lines): 124 consume = self._block_top_match(index, '') 125 if consume: 126 index += consume 127 else: 128 index += 1 129 return self.module_models 130 131 def _get_driver_kconfig_item(self, driver): 132 templates_dir = hdf_utils.get_templates_lite_dir() 133 template = os.path.join(templates_dir, 'hdf_driver_kconfig.template') 134 template_str = hdf_utils.read_file(template) 135 mod_converter = hdf_utils.WordsConverter(self.module) 136 drv_converter = hdf_utils.WordsConverter(driver) 137 data_model = { 138 'driver_upper_case': drv_converter.upper_case(), 139 'driver_lower_case': drv_converter.lower_case(), 140 'module_upper_case': mod_converter.upper_case() 141 } 142 config_item = 'DRIVERS_HDF_%s' % drv_converter.upper_case() 143 depends_on_item = 'DRIVERS_HDF_%s' % mod_converter.upper_case() 144 config_option = {'name': drv_converter.lower_case(), 145 'config_item': config_item, 146 'depends_on_item': depends_on_item, 147 'enabled': False} 148 config = Template(template_str).safe_substitute(data_model) 149 return config_option, config 150 151 def _get_begin_end_flag(self, driver): 152 id_ = hdf_utils.get_id(self.module, driver) 153 begin_flag = '\n# <begin %s\n' % id_ 154 end_flag = '\n# %s end>\n' % id_ 155 return begin_flag, end_flag 156 157 def add_driver(self, driver): 158 file_content = hdf_utils.read_file(self.k_path) 159 begin_flag, end_flag = self._get_begin_end_flag(driver) 160 k_option, k_item = self._get_driver_kconfig_item(driver) 161 new_content = hdf_utils.SectionContent(begin_flag, k_item, end_flag) 162 old_content = hdf_utils.SectionContent(begin_flag, '', end_flag) 163 old_range = hdf_utils.find_section(file_content, old_content) 164 if old_range: 165 hdf_utils.replace_and_save(file_content, self.k_path, 166 old_range, new_content) 167 else: 168 hdf_utils.append_and_save(file_content, self.k_path, new_content) 169 return k_option 170 171 def delete_driver(self, driver): 172 if not os.path.exists(self.k_path): 173 return 174 file_content = hdf_utils.read_file(self.k_path) 175 begin_flag, end_flag = self._get_begin_end_flag(driver) 176 old_content = hdf_utils.SectionContent(begin_flag, '', end_flag) 177 old_range = hdf_utils.find_section(file_content, old_content) 178 if not old_range: 179 return 180 hdf_utils.delete_and_save(file_content, self.k_path, old_range) 181