From afdb62d1e27bf7e30d2ed472eaedd436bdf75277 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Mon, 21 Oct 2024 18:29:14 +0200 Subject: [PATCH] dtlib: add lineno/filename to string representation of a DT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Output lineno/filename as comments in the string representation of a DT to help with debugging DT issues. Also, remove the added comments when comparing the string representation of a DT to a reference string in the DT testsuite. Signed-off-by: Benjamin Cabé Signed-off-by: Luca Burelli --- .../python-devicetree/src/devicetree/dtlib.py | 28 +++++++++++++++++-- .../dts/python-devicetree/tests/test_dtlib.py | 17 +++++++++-- 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/scripts/dts/python-devicetree/src/devicetree/dtlib.py b/scripts/dts/python-devicetree/src/devicetree/dtlib.py index 3fc4a9374d0..c2ffead0802 100644 --- a/scripts/dts/python-devicetree/src/devicetree/dtlib.py +++ b/scripts/dts/python-devicetree/src/devicetree/dtlib.py @@ -202,13 +202,37 @@ class Node: Returns a DTS representation of the node. Called automatically if the node is print()ed. """ - s = "".join(label + ": " for label in self.labels) + def safe_relpath(filename): + # Returns a relative path to the file, or the absolute path if + # a relative path cannot be established (on Windows with files + # in different drives, for example). + try: + return os.path.relpath(filename, start=os.getcwd()) + except ValueError: + return filename + + rel_filename = safe_relpath(self.filename) + s = f"\n/* node '{self.path}' defined in {rel_filename}:{self.lineno} */\n" + s += "".join(label + ": " for label in self.labels) s += f"{self.name} {{\n" + lines = [] + comments = {} for prop in self.props.values(): prop_str = textwrap.indent(str(prop), "\t") - s += prop_str + "\n" + lines.extend(prop_str.splitlines(True)) + + rel_filename = safe_relpath(prop.filename) + comment = f"/* in {rel_filename}:{prop.lineno} */" + comments[len(lines)-1] = comment + + if lines: + max_len = max([ len(line.rstrip()) for line in lines ]) + for i, line in enumerate(lines): + if i in comments: + line += " " * (max_len - len(line) + 1) + comments[i] + "\n" + s += line for child in self.nodes.values(): s += textwrap.indent(child.__str__(), "\t") + "\n" diff --git a/scripts/dts/python-devicetree/tests/test_dtlib.py b/scripts/dts/python-devicetree/tests/test_dtlib.py index 4e9b20aa631..1a4fcf6ffa8 100644 --- a/scripts/dts/python-devicetree/tests/test_dtlib.py +++ b/scripts/dts/python-devicetree/tests/test_dtlib.py @@ -26,6 +26,17 @@ from devicetree import dtlib # - to run a particular test function or functions, use # '-k test_function_pattern_goes_here' +def uncomment(dts): + '''Trim added comments from a DT string.''' + + # remove node comments, including leading empty line + dts = re.sub(r'\n\n[ \t]*/\*.*?\*/\n', '\n', dts, flags=re.DOTALL) + + # remove property comments + dts = re.sub(r'[ \t]*/\*.*?\*/\n', '\n', dts) + + return dts + def parse(dts, include_path=(), **kwargs): '''Parse a DTS string 'dts', using the given include path. @@ -48,7 +59,7 @@ def verify_parse(dts, expected, include_path=()): dt = parse(dts[1:], include_path) - actual = str(dt) + actual = uncomment(str(dt)) expected = expected[1:-1] assert actual == expected, f'unexpected round-trip on {dts}' @@ -1029,7 +1040,7 @@ def test_include_curdir(tmp_path): }; """) dt = dtlib.DT("test.dts") - assert str(dt) == """ + assert uncomment(str(dt)) == """ /dts-v1/; / { @@ -1086,7 +1097,7 @@ y /include/ "via-include-path-1" y = < 0x2 >; }; """[1:-1] - assert str(dt) == expected_dt + assert uncomment(str(dt)) == expected_dt def test_include_misc(tmp_path): '''Miscellaneous /include/ tests.'''