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 from dataclasses import dataclass 10 import re 10 import re 11 from typing import Any, Dict, Iterable, List, !! 11 from typing import Dict, Iterable, List, Set, Tuple 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 @dataclass(frozen=True) 17 class KconfigEntry: 17 class KconfigEntry: 18 name: str 18 name: str 19 value: str 19 value: str 20 20 21 def __str__(self) -> str: 21 def __str__(self) -> str: 22 if self.value == 'n': 22 if self.value == 'n': 23 return f'# CONFIG_{sel 23 return f'# CONFIG_{self.name} is not set' 24 return f'CONFIG_{self.name}={s 24 return f'CONFIG_{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: 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: Dict[str, str] 36 36 37 def __eq__(self, other: Any) -> bool: !! 37 def __eq__(self, other) -> bool: 38 if not isinstance(other, self. 38 if not isinstance(other, self.__class__): 39 return False 39 return False 40 return self._entries == other. 40 return self._entries == other._entries 41 41 42 def __repr__(self) -> str: 42 def __repr__(self) -> str: 43 return ','.join(str(e) for e i 43 return ','.join(str(e) for e in self.as_entries()) 44 44 45 def as_entries(self) -> Iterable[Kconf 45 def as_entries(self) -> Iterable[KconfigEntry]: 46 for name, value in self._entri 46 for name, value in self._entries.items(): 47 yield KconfigEntry(nam 47 yield KconfigEntry(name, value) 48 48 49 def add_entry(self, name: str, value: 49 def add_entry(self, name: str, value: str) -> None: 50 self._entries[name] = value 50 self._entries[name] = value 51 51 52 def is_subset_of(self, other: 'Kconfig 52 def is_subset_of(self, other: 'Kconfig') -> bool: 53 for name, value in self._entri 53 for name, value in self._entries.items(): 54 b = other._entries.get 54 b = other._entries.get(name) 55 if b is None: 55 if b is None: 56 if value == 'n 56 if value == 'n': 57 contin 57 continue 58 return False 58 return False 59 if value != b: 59 if value != b: 60 return False 60 return False 61 return True 61 return True 62 62 63 def conflicting_options(self, other: ' 63 def conflicting_options(self, other: 'Kconfig') -> List[Tuple[KconfigEntry, KconfigEntry]]: 64 diff = [] # type: List[Tuple[ 64 diff = [] # type: List[Tuple[KconfigEntry, KconfigEntry]] 65 for name, value in self._entri 65 for name, value in self._entries.items(): 66 b = other._entries.get 66 b = other._entries.get(name) 67 if b and value != b: 67 if b and value != b: 68 pair = (Kconfi 68 pair = (KconfigEntry(name, value), KconfigEntry(name, b)) 69 diff.append(pa 69 diff.append(pair) 70 return diff 70 return diff 71 71 72 def merge_in_entries(self, other: 'Kco 72 def merge_in_entries(self, other: 'Kconfig') -> None: 73 for name, value in other._entr 73 for name, value in other._entries.items(): 74 self._entries[name] = 74 self._entries[name] = value 75 75 76 def write_to_file(self, path: str) -> 76 def write_to_file(self, path: str) -> None: 77 with open(path, 'a+') as f: 77 with open(path, 'a+') as f: 78 for e in self.as_entri 78 for e in self.as_entries(): 79 f.write(str(e) 79 f.write(str(e) + '\n') 80 80 81 def parse_file(path: str) -> Kconfig: 81 def parse_file(path: str) -> Kconfig: 82 with open(path, 'r') as f: 82 with open(path, 'r') as f: 83 return parse_from_string(f.rea 83 return parse_from_string(f.read()) 84 84 85 def parse_from_string(blob: str) -> Kconfig: 85 def parse_from_string(blob: str) -> Kconfig: 86 """Parses a string containing Kconfig 86 """Parses a string containing Kconfig entries.""" 87 kconfig = Kconfig() 87 kconfig = Kconfig() 88 is_not_set_matcher = re.compile(CONFIG 88 is_not_set_matcher = re.compile(CONFIG_IS_NOT_SET_PATTERN) 89 config_matcher = re.compile(CONFIG_PAT 89 config_matcher = re.compile(CONFIG_PATTERN) 90 for line in blob.split('\n'): 90 for line in blob.split('\n'): 91 line = line.strip() 91 line = line.strip() 92 if not line: 92 if not line: 93 continue 93 continue 94 94 95 match = config_matcher.match(l 95 match = config_matcher.match(line) 96 if match: 96 if match: 97 kconfig.add_entry(matc 97 kconfig.add_entry(match.group(1), match.group(2)) 98 continue 98 continue 99 99 100 empty_match = is_not_set_match 100 empty_match = is_not_set_matcher.match(line) 101 if empty_match: 101 if empty_match: 102 kconfig.add_entry(empt 102 kconfig.add_entry(empty_match.group(1), 'n') 103 continue 103 continue 104 104 105 if line[0] == '#': 105 if line[0] == '#': 106 continue 106 continue 107 raise KconfigParseError('Faile 107 raise KconfigParseError('Failed to parse: ' + line) 108 return kconfig 108 return kconfig
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.