1 # SPDX-License-Identifier: GPL-2.0
3 # Builds a .config from a kunitconfig.
5 # Copyright (C) 2019, Google LLC.
6 # Author: Felix Guo <felixguoxiuping@gmail.com>
7 # Author: Brendan Higgins <brendanhiggins@google.com>
9 from dataclasses
import dataclass
11 from typing
import Any
, Dict
, Iterable
, List
, Tuple
13 CONFIG_IS_NOT_SET_PATTERN
= r
'^# CONFIG_(\w+) is not set$'
14 CONFIG_PATTERN
= r
'^CONFIG_(\w+)=(\S+|".*")$'
16 @dataclass(frozen
=True)
21 def __str__(self
) -> str:
23 return f
'# CONFIG_{self.name} is not set'
24 return f
'CONFIG_{self.name}={self.value}'
27 class KconfigParseError(Exception):
28 """Error parsing Kconfig defconfig or .config."""
32 """Represents defconfig or .config specified using the Kconfig language."""
34 def __init__(self
) -> None:
35 self
._entries
= {} # type: Dict[str, str]
37 def __eq__(self
, other
: Any
) -> bool:
38 if not isinstance(other
, self
.__class
__):
40 return self
._entries
== other
._entries
42 def __repr__(self
) -> str:
43 return ','.join(str(e
) for e
in self
.as_entries())
45 def as_entries(self
) -> Iterable
[KconfigEntry
]:
46 for name
, value
in self
._entries
.items():
47 yield KconfigEntry(name
, value
)
49 def add_entry(self
, name
: str, value
: str) -> None:
50 self
._entries
[name
] = value
52 def is_subset_of(self
, other
: 'Kconfig') -> bool:
53 for name
, value
in self
._entries
.items():
54 b
= other
._entries
.get(name
)
63 def conflicting_options(self
, other
: 'Kconfig') -> List
[Tuple
[KconfigEntry
, KconfigEntry
]]:
64 diff
= [] # type: List[Tuple[KconfigEntry, KconfigEntry]]
65 for name
, value
in self
._entries
.items():
66 b
= other
._entries
.get(name
)
68 pair
= (KconfigEntry(name
, value
), KconfigEntry(name
, b
))
72 def merge_in_entries(self
, other
: 'Kconfig') -> None:
73 for name
, value
in other
._entries
.items():
74 self
._entries
[name
] = value
76 def write_to_file(self
, path
: str) -> None:
77 with
open(path
, 'a+') as f
:
78 for e
in self
.as_entries():
79 f
.write(str(e
) + '\n')
81 def parse_file(path
: str) -> Kconfig
:
82 with
open(path
, 'r') as f
:
83 return parse_from_string(f
.read())
85 def parse_from_string(blob
: str) -> Kconfig
:
86 """Parses a string containing Kconfig entries."""
88 is_not_set_matcher
= re
.compile(CONFIG_IS_NOT_SET_PATTERN
)
89 config_matcher
= re
.compile(CONFIG_PATTERN
)
90 for line
in blob
.split('\n'):
95 match
= config_matcher
.match(line
)
97 kconfig
.add_entry(match
.group(1), match
.group(2))
100 empty_match
= is_not_set_matcher
.match(line
)
102 kconfig
.add_entry(empty_match
.group(1), 'n')
107 raise KconfigParseError('Failed to parse: ' + line
)