1 # SPDX-License-Identifier: GPL-2.0 1 # SPDX-License-Identifier: GPL-2.0 2 # 2 # 3 # Builds a .config from a kunitconfig. 3 # Builds a .config from a kunitconfig. 4 # 4 # 5 # Copyright (C) 2019, Google LLC. 5 # Copyright (C) 2019, Google LLC. 6 # Author: Felix Guo <felixguoxiuping@gmail.com> 6 # Author: Felix Guo <felixguoxiuping@gmail.com> 7 # Author: Brendan Higgins <brendanhiggins@googl 7 # Author: Brendan Higgins <brendanhiggins@google.com> 8 8 9 from dataclasses import dataclass !! 9 import collections 10 import re 10 import re 11 from typing import Any, Dict, Iterable, List, !! 11 from typing import List, Set 12 12 13 CONFIG_IS_NOT_SET_PATTERN = r'^# CONFIG_(\w+) 13 CONFIG_IS_NOT_SET_PATTERN = r'^# CONFIG_(\w+) is not set$' 14 CONFIG_PATTERN = r'^CONFIG_(\w+)=(\S+|".*")$' 14 CONFIG_PATTERN = r'^CONFIG_(\w+)=(\S+|".*")$' 15 15 16 @dataclass(frozen=True) !! 16 KconfigEntryBase = collections.namedtuple('KconfigEntryBase', ['name', 'value']) 17 class KconfigEntry: !! 17 18 name: str !! 18 class KconfigEntry(KconfigEntryBase): 19 value: str << 20 19 21 def __str__(self) -> str: 20 def __str__(self) -> str: 22 if self.value == 'n': 21 if self.value == 'n': 23 return f'# CONFIG_{sel !! 22 return r'# CONFIG_%s is not set' % (self.name) 24 return f'CONFIG_{self.name}={s !! 23 else: >> 24 return r'CONFIG_%s=%s' % (self.name, self.value) 25 25 26 26 27 class KconfigParseError(Exception): 27 class KconfigParseError(Exception): 28 """Error parsing Kconfig defconfig or 28 """Error parsing Kconfig defconfig or .config.""" 29 29 30 30 31 class Kconfig: !! 31 class Kconfig(object): 32 """Represents defconfig or .config spe 32 """Represents defconfig or .config specified using the Kconfig language.""" 33 33 34 def __init__(self) -> None: 34 def __init__(self) -> None: 35 self._entries = {} # type: Di !! 35 self._entries = [] # type: List[KconfigEntry] 36 36 37 def __eq__(self, other: Any) -> bool: !! 37 def entries(self) -> Set[KconfigEntry]: 38 if not isinstance(other, self. !! 38 return set(self._entries) 39 return False << 40 return self._entries == other. << 41 << 42 def __repr__(self) -> str: << 43 return ','.join(str(e) for e i << 44 << 45 def as_entries(self) -> Iterable[Kconf << 46 for name, value in self._entri << 47 yield KconfigEntry(nam << 48 39 49 def add_entry(self, name: str, value: !! 40 def add_entry(self, entry: KconfigEntry) -> None: 50 self._entries[name] = value !! 41 self._entries.append(entry) 51 42 52 def is_subset_of(self, other: 'Kconfig 43 def is_subset_of(self, other: 'Kconfig') -> bool: 53 for name, value in self._entri !! 44 other_dict = {e.name: e.value for e in other.entries()} 54 b = other._entries.get !! 45 for a in self.entries(): >> 46 b = other_dict.get(a.name) 55 if b is None: 47 if b is None: 56 if value == 'n !! 48 if a.value == 'n': 57 contin 49 continue 58 return False 50 return False 59 if value != b: !! 51 elif a.value != b: 60 return False 52 return False 61 return True 53 return True 62 54 63 def conflicting_options(self, other: ' << 64 diff = [] # type: List[Tuple[ << 65 for name, value in self._entri << 66 b = other._entries.get << 67 if b and value != b: << 68 pair = (Kconfi << 69 diff.append(pa << 70 return diff << 71 << 72 def merge_in_entries(self, other: 'Kco << 73 for name, value in other._entr << 74 self._entries[name] = << 75 << 76 def write_to_file(self, path: str) -> 55 def write_to_file(self, path: str) -> None: 77 with open(path, 'a+') as f: !! 56 with open(path, 'w') as f: 78 for e in self.as_entri !! 57 for entry in self.entries(): 79 f.write(str(e) !! 58 f.write(str(entry) + '\n') 80 !! 59 81 def parse_file(path: str) -> Kconfig: !! 60 def parse_from_string(self, blob: str) -> None: 82 with open(path, 'r') as f: !! 61 """Parses a string containing KconfigEntrys and populates this Kconfig.""" 83 return parse_from_string(f.rea !! 62 self._entries = [] 84 !! 63 is_not_set_matcher = re.compile(CONFIG_IS_NOT_SET_PATTERN) 85 def parse_from_string(blob: str) -> Kconfig: !! 64 config_matcher = re.compile(CONFIG_PATTERN) 86 """Parses a string containing Kconfig !! 65 for line in blob.split('\n'): 87 kconfig = Kconfig() !! 66 line = line.strip() 88 is_not_set_matcher = re.compile(CONFIG !! 67 if not line: 89 config_matcher = re.compile(CONFIG_PAT !! 68 continue 90 for line in blob.split('\n'): !! 69 91 line = line.strip() !! 70 match = config_matcher.match(line) 92 if not line: !! 71 if match: 93 continue !! 72 entry = KconfigEntry(match.group(1), match.group(2)) 94 !! 73 self.add_entry(entry) 95 match = config_matcher.match(l !! 74 continue 96 if match: !! 75 97 kconfig.add_entry(matc !! 76 empty_match = is_not_set_matcher.match(line) 98 continue !! 77 if empty_match: 99 !! 78 entry = KconfigEntry(empty_match.group(1), 'n') 100 empty_match = is_not_set_match !! 79 self.add_entry(entry) 101 if empty_match: !! 80 continue 102 kconfig.add_entry(empt !! 81 103 continue !! 82 if line[0] == '#': 104 !! 83 continue 105 if line[0] == '#': !! 84 else: 106 continue !! 85 raise KconfigParseError('Failed to parse: ' + line) 107 raise KconfigParseError('Faile !! 86 108 return kconfig !! 87 def read_from_file(self, path: str) -> None: >> 88 with open(path, 'r') as f: >> 89 self.parse_from_string(f.read())
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.