Skip to content

Commit 6085078

Browse files
Merge pull request #186 from packit/parsing
Avoid parsing the spec file over and over in loops This fixes performance regression introduced in 9e1762c. Before every macro expansion, the spec file is parsed to be sure the global macro context is up-to-date, however, parsing of sections now calls macro expansion in a loop, and that can cause a huge performance hit. Initially, I tried to implement caching, to parse only if the content of the spec file or some parsing parameters have changed, but then I realized sources affect parsing as well, and it's not even possible to get a list of sources without parsing. Reviewed-by: Jiri Popelka <None>
2 parents 61a0f95 + 14ed44d commit 6085078

File tree

4 files changed

+22
-5
lines changed

4 files changed

+22
-5
lines changed

specfile/sections.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,12 @@ def parse(
230230

231231
def expand(s):
232232
if context:
233-
return context.expand(s)
233+
result = context.expand(
234+
s, skip_parsing=getattr(expand, "skip_parsing", False)
235+
)
236+
# parse only once
237+
expand.skip_parsing = True
238+
return result
234239
return Macros.expand(s)
235240

236241
def split_id(line):

specfile/specfile.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,19 +158,26 @@ def save(self) -> None:
158158
self.path.write_text(str(self))
159159

160160
def expand(
161-
self, expression: str, extra_macros: Optional[List[Tuple[str, str]]] = None
161+
self,
162+
expression: str,
163+
extra_macros: Optional[List[Tuple[str, str]]] = None,
164+
skip_parsing: bool = False,
162165
) -> str:
163166
"""
164167
Expands an expression in the context of the spec file.
165168
166169
Args:
167170
expression: Expression to expand.
168171
extra_macros: Extra macros to be defined before expansion is performed.
172+
skip_parsing: Do not parse the spec file before expansion is performed.
173+
Defaults to False. Mutually exclusive with extra_macros. Set this to True
174+
only if you are certain that the global macro context is up-to-date.
169175
170176
Returns:
171177
Expanded expression.
172178
"""
173-
self._parser.parse(str(self), extra_macros)
179+
if not skip_parsing:
180+
self._parser.parse(str(self), extra_macros)
174181
return Macros.expand(expression)
175182

176183
def get_active_macros(self) -> List[Macro]:

specfile/value_parser.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,12 @@ def construct_regex(
312312

313313
def expand(s):
314314
if context:
315-
return context.expand(s)
315+
result = context.expand(
316+
s, skip_parsing=getattr(expand, "skip_parsing", False)
317+
)
318+
# parse only once
319+
expand.skip_parsing = True
320+
return result
316321
return Macros.expand(s)
317322

318323
def flatten(nodes):

tests/unit/test_sections.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ def test_parse():
6060
"0",
6161
"%changelog",
6262
],
63-
context=flexmock(expand=lambda s: "\n" if s == "%{desc}" else ""),
63+
context=flexmock(expand=lambda s, **_: "\n" if s == "%{desc}" else ""),
6464
)
6565
assert sections[0][0] == "0"
6666
assert sections[1].id == "description"

0 commit comments

Comments
 (0)