Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to comment out or uncomment a macro definition #298

Merged
merged 1 commit into from
Nov 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 51 additions & 15 deletions specfile/macro_definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import collections
import copy
import re
from enum import Enum, auto
from typing import TYPE_CHECKING, List, Optional, Tuple, Union, overload

from specfile.conditions import process_conditions
Expand All @@ -14,20 +15,31 @@
from specfile.specfile import Specfile


class CommentOutStyle(Enum):
DNL = auto()
HASH = auto()


class MacroDefinition:
def __init__(
self,
name: str,
body: str,
is_global: bool,
commented_out: bool,
comment_out_style: CommentOutStyle,
whitespace: Tuple[str, str, str, str],
dnl_whitespace: str = "",
valid: bool = True,
preceding_lines: Optional[List[str]] = None,
) -> None:
self.name = name
self.body = body
self.is_global = is_global
self.commented_out = commented_out
self.comment_out_style = comment_out_style
self._whitespace = whitespace
self._dnl_whitespace = dnl_whitespace
self.valid = valid
self._preceding_lines = (
preceding_lines.copy() if preceding_lines is not None else []
Expand All @@ -40,21 +52,32 @@ def __eq__(self, other: object) -> bool:
self.name == other.name
and self.body == other.body
and self.is_global == other.is_global
and self.commented_out == other.commented_out
and self.comment_out_style == other.comment_out_style
and self._whitespace == other._whitespace
and self._dnl_whitespace == other._dnl_whitespace
and self._preceding_lines == other._preceding_lines
)

@formatted
def __repr__(self) -> str:
return (
f"MacroDefinition({self.name!r}, {self.body!r}, {self.is_global!r}, "
f"{self._whitespace!r}, {self.valid!r}, {self._preceding_lines!r})"
f"{self.commented_out!r}, {self.comment_out_style!r}, {self._whitespace!r}, "
f"{self.valid!r}, {self._preceding_lines!r})"
)

def __str__(self) -> str:
ws = self._whitespace
macro = "%global" if self.is_global else "%define"
return f"{ws[0]}{macro}{ws[1]}{self.name}{ws[2]}{self.body}{ws[3]}"
dnl = ""
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.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]}"

def get_position(self, container: "MacroDefinitions") -> int:
"""
Expand All @@ -73,13 +96,20 @@ def get_position(self, container: "MacroDefinitions") -> int:
def get_raw_data(self) -> List[str]:
result = self._preceding_lines.copy()
ws = self._whitespace
macro = "%global" if self.is_global else "%define"
dnl = ""
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.HASH:
sc = "#"
macro = "global" if self.is_global else "define"
body = self.body.splitlines()
if body:
body[-1] += ws[3]
else:
body = [ws[3]]
result.append(f"{ws[0]}{macro}{ws[1]}{self.name}{ws[2]}{body[0]}")
result.append(f"{ws[0]}{dnl}{sc}{macro}{ws[1]}{self.name}{ws[2]}{body[0]}")
result.extend(body[1:])
return result

Expand Down Expand Up @@ -249,7 +279,9 @@ def count_brackets(s):
r"""
^
(\s*) # optional preceding whitespace
(%(?:global|define)) # scope-defining macro definition
(%dnl\s+)? # optional DNL prefix
((?(2)%|(?:%|\#))) # starting character
(global|define) # scope-defining macro definition
(\s+)
(\w+(?:\(.*?\))?) # macro name with optional arguments in parentheses
(\s+)
Expand All @@ -267,15 +299,16 @@ def count_brackets(s):
line, valid = pop(lines)
m = md_regex.match(line)
if m:
ws0, macro, ws1, name, ws2, body, ws3 = m.groups()
if ws3 == "\\":
body += ws3
ws3 = ""
bc, pc = count_brackets(body)
while (bc > 0 or pc > 0 or body.endswith("\\")) and lines:
line, _ = pop(lines)
body += "\n" + line
ws0, dnl, sc, macro, ws1, name, ws2, body, ws3 = m.groups()
if not dnl and sc == "%":
if ws3 == "\\":
body += ws3
ws3 = ""
bc, pc = count_brackets(body)
while (bc > 0 or pc > 0 or body.endswith("\\")) and lines:
line, _ = pop(lines)
body += "\n" + line
bc, pc = count_brackets(body)
tokens = re.split(r"(\s+)$", body, maxsplit=1)
if len(tokens) == 1:
body = tokens[0]
Expand All @@ -286,8 +319,11 @@ def count_brackets(s):
MacroDefinition(
name,
body,
macro == "%global",
macro == "global",
bool(dnl or sc == "#"),
CommentOutStyle.HASH if sc == "#" else CommentOutStyle.DNL,
(ws0, ws1, ws2, ws3),
dnl[4:] if dnl else "",
valid,
buffer,
)
Expand Down
1 change: 1 addition & 0 deletions specfile/specfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -730,6 +730,7 @@ class Entity:
)
for md in macro_definitions
if md.valid
and not md.commented_out
and not protected_regex.match(md.name)
and not md.name.endswith(")") # skip macro definitions with options
]
Expand Down
103 changes: 94 additions & 9 deletions tests/unit/test_macro_definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,39 @@

import pytest

from specfile.macro_definitions import MacroDefinition, MacroDefinitions
from specfile.macro_definitions import (
CommentOutStyle,
MacroDefinition,
MacroDefinitions,
)


def test_find():
macro_definitions = MacroDefinitions(
[
MacroDefinition("gitdate", "20160901", True, ("", " ", " ", "")),
MacroDefinition(
"gitdate",
"20160901",
True,
False,
CommentOutStyle.DNL,
("", " ", " ", ""),
),
MacroDefinition(
"commit",
"9ab9717cf7d1be1a85b165a8eacb71b9e5831113",
True,
False,
CommentOutStyle.DNL,
("", " ", " ", ""),
),
MacroDefinition(
"shortcommit", "%(c=%{commit}; echo ${c:0:7})", True, ("", " ", " ", "")
"shortcommit",
"%(c=%{commit}; echo ${c:0:7})",
True,
False,
CommentOutStyle.DNL,
("", " ", " ", ""),
),
]
)
Expand All @@ -32,15 +50,29 @@ def test_find():
def test_get():
macro_definitions = MacroDefinitions(
[
MacroDefinition("gitdate", "20160901", True, ("", " ", " ", "")),
MacroDefinition(
"gitdate",
"20160901",
True,
False,
CommentOutStyle.DNL,
("", " ", " ", ""),
),
MacroDefinition(
"commit",
"9ab9717cf7d1be1a85b165a8eacb71b9e5831113",
True,
False,
CommentOutStyle.DNL,
("", " ", " ", ""),
),
MacroDefinition(
"shortcommit", "%(c=%{commit}; echo ${c:0:7})", True, ("", " ", " ", "")
"shortcommit",
"%(c=%{commit}; echo ${c:0:7})",
True,
False,
CommentOutStyle.DNL,
("", " ", " ", ""),
),
]
)
Expand All @@ -59,6 +91,9 @@ def test_parse():
"%global commit 9ab9717cf7d1be1a85b165a8eacb71b9e5831113",
"%global shortcommit %(c=%{commit}; echo ${c:0:7})",
"",
"%dnl %global pre a1",
"#global prerel beta2",
"",
"Name: test",
"Version: 0.1.0",
"",
Expand All @@ -74,8 +109,14 @@ def test_parse():
assert macro_definitions[1].name == "commit"
assert macro_definitions.commit.body == "9ab9717cf7d1be1a85b165a8eacb71b9e5831113"
assert macro_definitions[2].name == "shortcommit"
assert macro_definitions[3].name == "desc(x)"
assert macro_definitions[3].body == (
assert macro_definitions[3].name == "pre"
assert macro_definitions[3].commented_out
assert macro_definitions[3].comment_out_style is CommentOutStyle.DNL
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 == (
"Test spec file containing several \\\n"
"macro definitions in various formats (%?1)"
)
Expand All @@ -90,21 +131,57 @@ def test_parse():
def test_get_raw_data():
macro_definitions = MacroDefinitions(
[
MacroDefinition("gitdate", "20160901", True, ("", " ", " ", "")),
MacroDefinition(
"gitdate",
"20160901",
True,
False,
CommentOutStyle.DNL,
("", " ", " ", ""),
),
MacroDefinition(
"commit",
"9ab9717cf7d1be1a85b165a8eacb71b9e5831113",
True,
False,
CommentOutStyle.DNL,
("", " ", " ", ""),
),
MacroDefinition(
"shortcommit", "%(c=%{commit}; echo ${c:0:7})", True, ("", " ", " ", "")
"shortcommit",
"%(c=%{commit}; echo ${c:0:7})",
True,
False,
CommentOutStyle.DNL,
("", " ", " ", ""),
),
MacroDefinition(
"pre",
"a1",
True,
True,
CommentOutStyle.DNL,
("", " ", " ", ""),
" ",
True,
[""],
),
MacroDefinition(
"prerel",
"beta2",
True,
True,
CommentOutStyle.HASH,
("", " ", " ", ""),
),
MacroDefinition(
"desc(x)",
"Test spec file containing several \\\nmacro definitions in various formats (%?1)",
False,
False,
CommentOutStyle.DNL,
("", " ", " ", ""),
"",
True,
[
"",
Expand All @@ -119,7 +196,10 @@ def test_get_raw_data():
"This an example of a macro definition with body \n"
"spawning across mutiple lines}",
False,
False,
CommentOutStyle.DNL,
("", " ", " ", ""),
"",
True,
[""],
),
Expand All @@ -130,6 +210,9 @@ def test_get_raw_data():
"%global commit 9ab9717cf7d1be1a85b165a8eacb71b9e5831113",
"%global shortcommit %(c=%{commit}; echo ${c:0:7})",
"",
"%dnl %global pre a1",
"#global prerel beta2",
"",
"Name: test",
"Version: 0.1.0",
"",
Expand All @@ -149,6 +232,8 @@ def test_copy_macro_definitions():
"commit",
"9ab9717cf7d1be1a85b165a8eacb71b9e5831113",
True,
False,
CommentOutStyle.DNL,
("", " ", " ", ""),
),
],
Expand Down