From 16e14104f71ed415940aa65ea8a35d97a5ecc010 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 16 Apr 2020 13:59:16 +1000 Subject: [PATCH 1/2] kconfig: Fix generation of hex outputs for Make & CMake And add tests for hex output formatting in all output formats. Previously, Make & CMake outputs only formatted hex values with the 0x prefix if they had the 0x prefix in the sdkconfig file. Now this prefix is always applied. Closes https://github.com/espressif/vscode-esp-idf-extension/issues/83 --- tools/kconfig_new/confgen.py | 25 +++++++--- .../kconfig_new/test/confgen/test_confgen.py | 50 +++++++++++++++++-- 2 files changed, 63 insertions(+), 12 deletions(-) diff --git a/tools/kconfig_new/confgen.py b/tools/kconfig_new/confgen.py index 605104db85..e757d1d4f1 100755 --- a/tools/kconfig_new/confgen.py +++ b/tools/kconfig_new/confgen.py @@ -355,14 +355,24 @@ def write_makefile(deprecated_options, config, filename): def get_makefile_config_string(name, value, orig_type): if orig_type in (kconfiglib.BOOL, kconfiglib.TRISTATE): - return "{}{}={}\n".format(config.config_prefix, name, '' if value == 'n' else value) - elif orig_type in (kconfiglib.INT, kconfiglib.HEX): - return "{}{}={}\n".format(config.config_prefix, name, value) + value = '' if value == 'n' else value + elif orig_type == kconfiglib.INT: + try: + value = int(value) + except ValueError: + value = "" + elif orig_type == kconfiglib.HEX: + try: + value = hex(int(value, 16)) # ensure 0x prefix + except ValueError: + value = "" elif orig_type == kconfiglib.STRING: - return '{}{}="{}"\n'.format(config.config_prefix, name, kconfiglib.escape(value)) + value = '"{}"'.format(kconfiglib.escape(value)) else: raise RuntimeError('{}{}: unknown type {}'.format(config.config_prefix, name, orig_type)) + return '{}{}={}\n'.format(config.config_prefix, name, value) + def write_makefile_node(node): item = node.item if isinstance(item, kconfiglib.Symbol) and item.env_var is None: @@ -419,13 +429,14 @@ def write_cmake(deprecated_options, config, filename): val = "" # write unset values as empty variables elif sym.orig_type == kconfiglib.STRING: val = kconfiglib.escape(val) - write("set({}{} \"{}\")\n".format( - prefix, sym.name, val)) + elif sym.orig_type == kconfiglib.HEX: + val = hex(int(val, 16)) # ensure 0x prefix + write('set({}{} "{}")\n'.format(prefix, sym.name, val)) configs_list.append(prefix + sym.name) dep_opt = deprecated_options.get_deprecated_option(sym.name) if dep_opt: - tmp_dep_list.append("set({}{} \"{}\")\n".format(prefix, dep_opt, val)) + tmp_dep_list.append('set({}{} "{}")\n'.format(prefix, dep_opt, val)) configs_list.append(prefix + dep_opt) for n in config.node_iter(): diff --git a/tools/kconfig_new/test/confgen/test_confgen.py b/tools/kconfig_new/test/confgen/test_confgen.py index 75ab30ca38..8bc24c28fd 100755 --- a/tools/kconfig_new/test/confgen/test_confgen.py +++ b/tools/kconfig_new/test/confgen/test_confgen.py @@ -25,7 +25,7 @@ class ConfgenBaseTestCase(unittest.TestCase): # Python 2 fallback regex_func = self.assertRegexpMatches finally: - self.functions['regex'] = regex_func + self.functions['regex'] = lambda instance, s, expr: regex_func(instance, expr, s) # reverse args order def setUp(self): with tempfile.NamedTemporaryFile(prefix='test_confgen_', delete=False) as f: @@ -47,6 +47,16 @@ class ConfgenBaseTestCase(unittest.TestCase): subprocess.check_call(call_args) def invoke_and_test(self, in_text, out_text, test='in'): + """ + Main utility function for testing confgen: + + - Runs confgen via invoke_confgen(), using output method pre-set in test class setup + - in_text is the Kconfig file input content + - out_text is some expected output from confgen + - 'test' can be any function key from self.functions dict (see above). Default is 'in' to test if + out_text is a substring of the full confgen output. + """ + with tempfile.NamedTemporaryFile(mode='w+', prefix='test_confgen_', delete=False) as f: self.addCleanup(os.remove, f.name) f.write(textwrap.dedent(in_text)) @@ -58,10 +68,12 @@ class ConfgenBaseTestCase(unittest.TestCase): with open(self.output_file) as f_result: result = f_result.read() - if test == 'regex': # need to reverse the argument order - self.functions[test](self, result, out_text) - else: - self.functions[test](self, textwrap.dedent(out_text), result) + try: + out_text = textwrap.dedent(out_text) + except TypeError: + pass # probably a regex + + self.functions[test](self, out_text, result) class CmakeTestCase(ConfgenBaseTestCase): @@ -77,6 +89,10 @@ class CmakeTestCase(ConfgenBaseTestCase): default "\\\\~!@#$%^&*()\\\"" """, 'set(CONFIG_PASSWORD "\\\\~!@#$%^&*()\\\"")') + def testHexPrefix(self): + self.invoke_and_test(HEXPREFIX_KCONFIG, 'set(CONFIG_HEX_NOPREFIX "0x33")') + self.invoke_and_test(HEXPREFIX_KCONFIG, 'set(CONFIG_HEX_PREFIX "0x77")') + class JsonTestCase(ConfgenBaseTestCase): @classmethod @@ -91,6 +107,11 @@ class JsonTestCase(ConfgenBaseTestCase): default "\\\\~!@#$%^&*()\\\"" """, '"PASSWORD": "\\\\~!@#$%^&*()\\\""') + def testHexPrefix(self): + # hex values come out as integers in JSON, due to no hex type + self.invoke_and_test(HEXPREFIX_KCONFIG, '"HEX_NOPREFIX": %d' % 0x33) + self.invoke_and_test(HEXPREFIX_KCONFIG, '"HEX_PREFIX": %d' % 0x77) + class JsonMenuTestCase(ConfgenBaseTestCase): @classmethod @@ -168,6 +189,10 @@ class MakefileTestCase(ConfgenBaseTestCase): with open(os.path.join(os.environ['IDF_PATH'], 'Kconfig')) as f: self.invoke_and_test(f.read(), 'CONFIG_IDF_TARGET="esp32"') + def testHexPrefix(self): + self.invoke_and_test(HEXPREFIX_KCONFIG, 'CONFIG_HEX_NOPREFIX=0x33') + self.invoke_and_test(HEXPREFIX_KCONFIG, 'CONFIG_HEX_PREFIX=0x77') + class HeaderTestCase(ConfgenBaseTestCase): @classmethod @@ -182,6 +207,10 @@ class HeaderTestCase(ConfgenBaseTestCase): default "\\\\~!@#$%^&*()\\\"" """, '#define CONFIG_PASSWORD "\\\\~!@#$%^&*()\\\""') + def testHexPrefix(self): + self.invoke_and_test(HEXPREFIX_KCONFIG, '#define CONFIG_HEX_NOPREFIX 0x33') + self.invoke_and_test(HEXPREFIX_KCONFIG, '#define CONFIG_HEX_PREFIX 0x77') + class DocsTestCase(ConfgenBaseTestCase): @classmethod @@ -230,5 +259,16 @@ class DocsTestCase(ConfgenBaseTestCase): """) # this is more readable than regex +# Used by multiple testHexPrefix() test cases to verify correct hex output for each format +HEXPREFIX_KCONFIG = """ +config HEX_NOPREFIX +hex "Hex Item default no prefix" +default 33 + +config HEX_PREFIX +hex "Hex Item default prefix" +default 0x77 +""" + if __name__ == "__main__": unittest.main() From 9b5f25ae2c5cafd83c61fa6ebf1d0d57b01a958f Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 16 Apr 2020 14:04:54 +1000 Subject: [PATCH 2/2] confserver: Always store hex values in sdkconfig with 0x prefix This is not necessary for correct behaviour or to have valid sdkconfig files (previous commit adds tests for this), but it's useful for consistency with sdkconfig files generated by menuconfig. As reported in https://github.com/espressif/vscode-esp-idf-extension/issues/83 --- tools/kconfig_new/confserver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/kconfig_new/confserver.py b/tools/kconfig_new/confserver.py index 536f43ed52..f8694a9338 100755 --- a/tools/kconfig_new/confserver.py +++ b/tools/kconfig_new/confserver.py @@ -228,7 +228,7 @@ def handle_set(config, error, to_set): try: if not isinstance(val, int): val = int(val, 16) # input can be a decimal JSON value or a string of hex digits - sym.set_value("%x" % val) + sym.set_value(hex(val)) except ValueError: error.append("Hex symbol %s can accept a decimal integer or a string of hex digits, only") else: