2019-09-23 02:02:43 -07:00
# SPDX-License-Identifier: GPL-2.0
#
# Builds a .config from a kunitconfig.
#
# Copyright (C) 2019, Google LLC.
# Author: Felix Guo <felixguoxiuping@gmail.com>
# Author: Brendan Higgins <brendanhiggins@google.com>
import collections
import re
2021-01-14 16:39:11 -08:00
from typing import List , Set
2019-09-23 02:02:43 -07:00
2020-03-23 19:43:33 -07:00
CONFIG_IS_NOT_SET_PATTERN = r ' ^# CONFIG_( \ w+) is not set$ '
2020-06-07 23:57:15 +02:00
CONFIG_PATTERN = r ' ^CONFIG_( \ w+)=( \ S+| " .* " )$ '
2019-09-23 02:02:43 -07:00
2021-02-22 21:49:30 -08:00
KconfigEntryBase = collections . namedtuple ( ' KconfigEntryBase ' , [ ' name ' , ' value ' ] )
2019-09-23 02:02:43 -07:00
class KconfigEntry ( KconfigEntryBase ) :
def __str__ ( self ) - > str :
2020-03-23 19:43:33 -07:00
if self . value == ' n ' :
return r ' # CONFIG_ %s is not set ' % ( self . name )
else :
return r ' CONFIG_ %s = %s ' % ( self . name , self . value )
2019-09-23 02:02:43 -07:00
class KconfigParseError ( Exception ) :
""" Error parsing Kconfig defconfig or .config. """
class Kconfig ( object ) :
""" Represents defconfig or .config specified using the Kconfig language. """
2021-01-14 16:39:11 -08:00
def __init__ ( self ) - > None :
self . _entries = [ ] # type: List[KconfigEntry]
2019-09-23 02:02:43 -07:00
2021-01-14 16:39:11 -08:00
def entries ( self ) - > Set [ KconfigEntry ] :
2019-09-23 02:02:43 -07:00
return set ( self . _entries )
def add_entry ( self , entry : KconfigEntry ) - > None :
self . _entries . append ( entry )
def is_subset_of ( self , other : ' Kconfig ' ) - > bool :
2020-12-08 15:21:02 -08:00
other_dict = { e . name : e . value for e in other . entries ( ) }
2020-03-23 19:43:33 -07:00
for a in self . entries ( ) :
2020-12-08 15:21:02 -08:00
b = other_dict . get ( a . name )
if b is None :
if a . value == ' n ' :
2020-03-23 19:43:33 -07:00
continue
2020-12-08 15:21:02 -08:00
return False
elif a . value != b :
2020-03-23 19:43:33 -07:00
return False
return True
2019-09-23 02:02:43 -07:00
2021-05-26 14:24:06 -07:00
def merge_in_entries ( self , other : ' Kconfig ' ) - > None :
if other . is_subset_of ( self ) :
return
self . _entries = list ( self . entries ( ) . union ( other . entries ( ) ) )
2019-09-23 02:02:43 -07:00
def write_to_file ( self , path : str ) - > None :
2021-05-26 14:24:06 -07:00
with open ( path , ' a+ ' ) as f :
2019-09-23 02:02:43 -07:00
for entry in self . entries ( ) :
f . write ( str ( entry ) + ' \n ' )
2021-11-05 18:30:57 -07:00
def parse_file ( path : str ) - > Kconfig :
with open ( path , ' r ' ) as f :
return parse_from_string ( f . read ( ) )
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 :
continue
match = config_matcher . match ( line )
if match :
entry = KconfigEntry ( match . group ( 1 ) , match . group ( 2 ) )
kconfig . add_entry ( entry )
continue
empty_match = is_not_set_matcher . match ( line )
if empty_match :
entry = KconfigEntry ( empty_match . group ( 1 ) , ' n ' )
kconfig . add_entry ( entry )
continue
if line [ 0 ] == ' # ' :
continue
else :
raise KconfigParseError ( ' Failed to parse: ' + line )
return kconfig