diff --git a/tools/check_kconfigs.py b/tools/check_kconfigs.py index 23a46e149c..bdc3953e46 100755 --- a/tools/check_kconfigs.py +++ b/tools/check_kconfigs.py @@ -84,6 +84,23 @@ class BaseChecker(object): pass +class SourceChecker(BaseChecker): + # allow to source only files which will be also checked by the script + # Note: The rules are complex and the LineRuleChecker cannot be used + def process_line(self, line, line_number): + m = re.search(r'^\s*source(\s*)"([^"]+)"', line) + if m: + if len(m.group(1)) == 0: + raise InputError(self.path_in_idf, line_number, '"source" has to been followed by space', + line.replace('source', 'source ')) + path = m.group(2) + if path in ['$COMPONENT_KCONFIGS_PROJBUILD', '$COMPONENT_KCONFIGS']: + pass + elif not path.endswith('/Kconfig.in') and path != 'Kconfig.in': + raise InputError(self.path_in_idf, line_number, "only Kconfig.in can be sourced", + line.replace(path, os.path.join(os.path.dirname(path), 'Kconfig.in'))) + + class LineRuleChecker(BaseChecker): """ checks LINE_ERROR_RULES for each line @@ -134,6 +151,7 @@ class IndentAndNameChecker(BaseChecker): |(menuconfig) |(help) |(if) + |(source) ) ''', re.X) @@ -193,7 +211,7 @@ class IndentAndNameChecker(BaseChecker): print('level+', new_item, ': ', self.level_stack, end=' -> ') # "config" and "menuconfig" don't have a closing pair. So if new_item is an item which need to be indented # outside the last "config" or "menuconfig" then we need to find to a parent where it belongs - if new_item in ['config', 'menuconfig', 'menu', 'choice', 'if']: + if new_item in ['config', 'menuconfig', 'menu', 'choice', 'if', 'source']: # item is not belonging to a previous "config" or "menuconfig" so need to indent to parent for i, item in enumerate(reversed(self.level_stack)): if item in ['menu', 'mainmenu', 'choice', 'if']: @@ -328,7 +346,7 @@ class IndentAndNameChecker(BaseChecker): new_item = m.group(1) current_level = self.update_level_for_dec_pattern(new_item) if new_item not in ['endif']: - # endif doesn't require to check the prefix because the items in inside if/endif belong to the + # endif doesn't require to check the prefix because the items inside if/endif belong to the # same prefix level self.check_common_prefix(line, line_number) @@ -384,11 +402,12 @@ def main(): with open(full_path, 'r', encoding='utf-8') as f, \ open(suggestions_full_path, 'w', encoding='utf-8', newline='\n') as f_o, \ LineRuleChecker(path_in_idf) as line_checker, \ + SourceChecker(path_in_idf) as source_checker, \ IndentAndNameChecker(path_in_idf, debug=args.verbose) as indent_and_name_checker: try: for line_number, line in enumerate(f, start=1): try: - for checker in [line_checker, indent_and_name_checker]: + for checker in [line_checker, indent_and_name_checker, source_checker]: checker.process_line(line, line_number) # The line is correct therefore we echo it to the output file f_o.write(line) diff --git a/tools/test_check_kconfigs.py b/tools/test_check_kconfigs.py index 737ae46570..a38f16ab91 100755 --- a/tools/test_check_kconfigs.py +++ b/tools/test_check_kconfigs.py @@ -16,6 +16,7 @@ import unittest from check_kconfigs import LineRuleChecker +from check_kconfigs import SourceChecker from check_kconfigs import InputError from check_kconfigs import IndentAndNameChecker from check_kconfigs import CONFIG_NAME_MAX_LENGTH @@ -71,6 +72,23 @@ class TestLineRuleChecker(unittest.TestCase, ApplyLine): self.expect_error('test \\', expect=None) +class TestSourceChecker(unittest.TestCase, ApplyLine): + def setUp(self): + self.checker = SourceChecker('Kconfig') + + def tearDown(self): + pass + + def test_source_file_name(self): + self.expect_error('source "Kconfig.test"', expect='source "Kconfig.in"') + self.expect_error('source "/tmp/Kconfig.test"', expect='source "/tmp/Kconfig.in"') + self.expect_error('source "Kconfig"', expect='source "Kconfig.in"') + self.expt_success('source "Kconfig.in"') + self.expt_success('source "/tmp/Kconfig.in"') + self.expect_error('source"Kconfig.in"', expect='source "Kconfig.in"') + self.expt_success('source "/tmp/Kconfig.in" # comment') + + class TestIndentAndNameChecker(unittest.TestCase, ApplyLine): def setUp(self): self.checker = IndentAndNameChecker('Kconfig') @@ -156,6 +174,21 @@ class TestIndent(TestIndentAndNameChecker): self.expt_success('config') self.expt_success(' help') + def test_source_after_config(self): + self.expt_success('menuconfig') + self.expt_success(' help') + self.expt_success(' text') + self.expect_error(' source', expect='source') + self.expt_success('source "Kconfig.in"') + + def test_comment_after_config(self): + self.expt_success('menuconfig') + self.expt_success(' # comment') + self.expt_success(' help') + self.expt_success(' text') + self.expect_error('# comment', expect=' # comment') + self.expt_success(' # second not realcomment"') + class TestName(TestIndentAndNameChecker): def setUp(self):