From 4c9d61b2315518151db21d784f9e10b8d8ce78d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nikola=20Forr=C3=B3?= Date: Wed, 13 Dec 2023 20:23:01 +0100 Subject: [PATCH] Recognize all macro definitions in hash-style comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Macro definitions can be commented out by replacing '%' with '#', for example `%global debug 1` with `#global debug 1`, to avoid `Macro expanded in comment` warning. However, the same can be achieved also by escaping the '%' in the comment, i.e. `#%%global debug 1`, and even if the '%' is not escaped, it is still parseable, so we should be able to parse it as well. Signed-off-by: Nikola Forró --- specfile/macro_definitions.py | 42 ++++++++++++++++++++-------- tests/unit/test_macro_definitions.py | 22 +++++++++++++-- 2 files changed, 50 insertions(+), 14 deletions(-) diff --git a/specfile/macro_definitions.py b/specfile/macro_definitions.py index d4d8a8e..1a0b70a 100644 --- a/specfile/macro_definitions.py +++ b/specfile/macro_definitions.py @@ -18,6 +18,7 @@ class CommentOutStyle(Enum): DNL = auto() HASH = auto() + OTHER = auto() class MacroDefinition: @@ -30,6 +31,7 @@ def __init__( comment_out_style: CommentOutStyle, whitespace: Tuple[str, str, str, str], dnl_whitespace: str = "", + comment_prefix: str = "", valid: bool = True, preceding_lines: Optional[List[str]] = None, ) -> None: @@ -40,6 +42,7 @@ def __init__( self.comment_out_style = comment_out_style self._whitespace = whitespace self._dnl_whitespace = dnl_whitespace + self._comment_prefix = comment_prefix self.valid = valid self._preceding_lines = ( preceding_lines.copy() if preceding_lines is not None else [] @@ -56,6 +59,7 @@ def __eq__(self, other: object) -> bool: and self.comment_out_style == other.comment_out_style and self._whitespace == other._whitespace and self._dnl_whitespace == other._dnl_whitespace + and self._comment_prefix == other._comment_prefix and self._preceding_lines == other._preceding_lines ) @@ -64,20 +68,26 @@ def __repr__(self) -> str: return ( f"MacroDefinition({self.name!r}, {self.body!r}, {self.is_global!r}, " f"{self.commented_out!r}, {self.comment_out_style!r}, {self._whitespace!r}, " + f"{self._dnl_whitespace!r}, {self._comment_prefix!r}, " f"{self.valid!r}, {self._preceding_lines!r})" ) def __str__(self) -> str: ws = self._whitespace dnl = "" + pre = "" sc = "%" if self.commented_out: if self.comment_out_style is CommentOutStyle.DNL: dnl = f"%dnl{self._dnl_whitespace}" + elif self.comment_out_style is CommentOutStyle.OTHER: + pre = self._comment_prefix elif self.comment_out_style is CommentOutStyle.HASH: sc = "#" macro = "global" if self.is_global else "define" - return f"{ws[0]}{dnl}{sc}{macro}{ws[1]}{self.name}{ws[2]}{self.body}{ws[3]}" + return ( + f"{ws[0]}{dnl}{pre}{sc}{macro}{ws[1]}{self.name}{ws[2]}{self.body}{ws[3]}" + ) def get_position(self, container: "MacroDefinitions") -> int: """ @@ -97,10 +107,13 @@ def get_raw_data(self) -> List[str]: result = self._preceding_lines.copy() ws = self._whitespace dnl = "" + pre = "" sc = "%" if self.commented_out: if self.comment_out_style is CommentOutStyle.DNL: dnl = f"%dnl{self._dnl_whitespace}" + elif self.comment_out_style is CommentOutStyle.OTHER: + pre = self._comment_prefix elif self.comment_out_style is CommentOutStyle.HASH: sc = "#" macro = "global" if self.is_global else "define" @@ -109,7 +122,7 @@ def get_raw_data(self) -> List[str]: body[-1] += ws[3] else: body = [ws[3]] - result.append(f"{ws[0]}{dnl}{sc}{macro}{ws[1]}{self.name}{ws[2]}{body[0]}") + result.append(f"{ws[0]}{dnl}{pre}{sc}{macro}{ws[1]}{self.name}{ws[2]}{body[0]}") result.extend(body[1:]) return result @@ -303,16 +316,16 @@ def count_brackets(s): md_regex = re.compile( r""" ^ - (\s*) # optional preceding whitespace - (%dnl\s+)? # optional DNL prefix - ((?(2)%|(?:%|\#))) # starting character - (global|define) # scope-defining macro definition + (\s*) # optional preceding whitespace + (%dnl\s+)? # optional DNL prefix + ((?(2)%|(?:%|\#(?:.*?%)?))) # starting character with optional comment prefix + (global|define) # scope-defining macro definition (\s+) - (\w+(?:\(.*?\))?) # macro name with optional arguments in parentheses + (\w+(?:\(.*?\))?) # macro name with optional arguments in parentheses (\s+) - (.*?) # macro body - (\s*|\\) # optional following whitespace or a backslash indicating - # that the macro body continues on the next line + (.*?) # macro body + (\s*|\\) # optional following whitespace or a backslash indicating + # that the macro body continues on the next line $ """, re.VERBOSE, @@ -345,10 +358,15 @@ def count_brackets(s): name, body, macro == "global", - bool(dnl or sc == "#"), - CommentOutStyle.HASH if sc == "#" else CommentOutStyle.DNL, + bool(dnl or sc.startswith("#")), + CommentOutStyle.HASH + if sc == "#" + else CommentOutStyle.OTHER + if sc.startswith("#") + else CommentOutStyle.DNL, (ws0, ws1, ws2, ws3), dnl[4:] if dnl else " ", + sc[:-1] if len(sc) > 1 else "", valid, buffer, ) diff --git a/tests/unit/test_macro_definitions.py b/tests/unit/test_macro_definitions.py index ce9da40..98976cd 100644 --- a/tests/unit/test_macro_definitions.py +++ b/tests/unit/test_macro_definitions.py @@ -93,6 +93,7 @@ def test_parse(): "", "%dnl %global pre a1", "#global prerel beta2", + "# %global prerelease pre3", "", "Name: test", "Version: 0.1.0", @@ -115,8 +116,11 @@ def test_parse(): assert macro_definitions[4].name == "prerel" assert macro_definitions[4].commented_out assert macro_definitions[4].comment_out_style is CommentOutStyle.HASH - assert macro_definitions[5].name == "desc(x)" - assert macro_definitions[5].body == ( + assert macro_definitions[5].name == "prerelease" + assert macro_definitions[5].commented_out + assert macro_definitions[5].comment_out_style is CommentOutStyle.OTHER + assert macro_definitions[6].name == "desc(x)" + assert macro_definitions[6].body == ( "Test spec file containing several \\\n" "macro definitions in various formats (%?1)" ) @@ -163,6 +167,7 @@ def test_get_raw_data(): CommentOutStyle.DNL, ("", " ", " ", ""), " ", + "", True, [""], ), @@ -174,6 +179,16 @@ def test_get_raw_data(): CommentOutStyle.HASH, ("", " ", " ", ""), ), + MacroDefinition( + "prerelease", + "pre3", + True, + True, + CommentOutStyle.OTHER, + ("", " ", " ", ""), + "", + "# ", + ), MacroDefinition( "desc(x)", "Test spec file containing several \\\nmacro definitions in various formats (%?1)", @@ -182,6 +197,7 @@ def test_get_raw_data(): CommentOutStyle.DNL, ("", " ", " ", ""), "", + "", True, [ "", @@ -200,6 +216,7 @@ def test_get_raw_data(): CommentOutStyle.DNL, ("", " ", " ", ""), "", + "", True, [""], ), @@ -212,6 +229,7 @@ def test_get_raw_data(): "", "%dnl %global pre a1", "#global prerel beta2", + "# %global prerelease pre3", "", "Name: test", "Version: 0.1.0",