blob: 75a8dc1683d4295a375f12829e36650ebe1c8d9d [file] [log] [blame]
# SPDX-License-Identifier: GPL-2.0
# Builds a .config from a kunitconfig.
# Copyright (C) 2019, Google LLC.
# Author: Felix Guo <>
# Author: Brendan Higgins <>
from dataclasses import dataclass
import re
from typing import List, Set
CONFIG_IS_NOT_SET_PATTERN = r'^# CONFIG_(\w+) is not set$'
CONFIG_PATTERN = r'^CONFIG_(\w+)=(\S+|".*")$'
class KconfigEntry:
name: str
value: str
def __str__(self) -> str:
if self.value == 'n':
return f'# CONFIG_{} is not set'
return f'CONFIG_{}={self.value}'
class KconfigParseError(Exception):
"""Error parsing Kconfig defconfig or .config."""
class Kconfig:
"""Represents defconfig or .config specified using the Kconfig language."""
def __init__(self) -> None:
self._entries = [] # type: List[KconfigEntry]
def entries(self) -> Set[KconfigEntry]:
return set(self._entries)
def add_entry(self, entry: KconfigEntry) -> None:
def is_subset_of(self, other: 'Kconfig') -> bool:
other_dict = { e.value for e in other.entries()}
for a in self.entries():
b = other_dict.get(
if b is None:
if a.value == 'n':
return False
if a.value != b:
return False
return True
def merge_in_entries(self, other: 'Kconfig') -> None:
if other.is_subset_of(self):
self._entries = list(self.entries().union(other.entries()))
def write_to_file(self, path: str) -> None:
with open(path, 'a+') as f:
for entry in self.entries():
f.write(str(entry) + '\n')
def parse_file(path: str) -> Kconfig:
with open(path, 'r') as f:
return parse_from_string(
def parse_from_string(blob: str) -> Kconfig:
"""Parses a string containing Kconfig entries."""
kconfig = Kconfig()
is_not_set_matcher = re.compile(CONFIG_IS_NOT_SET_PATTERN)
config_matcher = re.compile(CONFIG_PATTERN)
for line in blob.split('\n'):
line = line.strip()
if not line:
match = config_matcher.match(line)
if match:
entry = KconfigEntry(,
empty_match = is_not_set_matcher.match(line)
if empty_match:
entry = KconfigEntry(, 'n')
if line[0] == '#':
raise KconfigParseError('Failed to parse: ' + line)
return kconfig