Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-specfile for openSUSE:Factory checked in at 2023-03-14 18:16:13 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-specfile (Old) and /work/SRC/openSUSE:Factory/.python-specfile.new.31432 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-specfile" Tue Mar 14 18:16:13 2023 rev:9 rq:1071125 version:0.15.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-specfile/python-specfile.changes 2023-02-27 12:55:33.651493671 +0100 +++ /work/SRC/openSUSE:Factory/.python-specfile.new.31432/python-specfile.changes 2023-03-14 18:16:16.667614136 +0100 @@ -1,0 +2,9 @@ +Mon Mar 13 12:34:39 UTC 2023 - David Anes <david.a...@suse.com> + +- Update to version 0.15.0: + * Parsing the spec file by RPM is now performed only if really + necessary, greatly improving performance in certain scenarios. + (#212) + * Checked that license is a valid SPDX license. + +------------------------------------------------------------------- Old: ---- specfile-0.14.0.tar.gz New: ---- specfile-0.15.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-specfile.spec ++++++ --- /var/tmp/diff_new_pack.MYtslW/_old 2023-03-14 18:16:17.343617749 +0100 +++ /var/tmp/diff_new_pack.MYtslW/_new 2023-03-14 18:16:17.363617856 +0100 @@ -18,7 +18,7 @@ %define skip_python38 1 Name: python-specfile -Version: 0.14.0 +Version: 0.15.0 Release: 0 Summary: A library for parsing and manipulating RPM spec files License: MIT ++++++ specfile-0.14.0.tar.gz -> specfile-0.15.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/specfile-0.14.0/CHANGELOG.md new/specfile-0.15.0/CHANGELOG.md --- old/specfile-0.14.0/CHANGELOG.md 2023-02-23 17:10:09.000000000 +0100 +++ new/specfile-0.15.0/CHANGELOG.md 2023-03-10 12:16:50.000000000 +0100 @@ -1,3 +1,8 @@ +# 0.15.0 + +- Parsing the spec file by RPM is now performed only if really necessary, greatly improving performance in certain scenarios. (#212) +- Checked that license is a valid SPDX license. + # 0.14.0 - Fixed a bug that broke parsing in case spec file contained conditionalized macro definitions or similar constructs. (#209) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/specfile-0.14.0/PKG-INFO new/specfile-0.15.0/PKG-INFO --- old/specfile-0.14.0/PKG-INFO 2023-02-23 17:10:24.365865700 +0100 +++ new/specfile-0.15.0/PKG-INFO 2023-03-10 12:17:02.947491000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: specfile -Version: 0.14.0 +Version: 0.15.0 Summary: A library for parsing and manipulating RPM spec files. Home-page: https://github.com/packit/specfile Author: Red Hat diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/specfile-0.14.0/fedora/python-specfile.spec new/specfile-0.15.0/fedora/python-specfile.spec --- old/specfile-0.14.0/fedora/python-specfile.spec 2023-02-23 17:10:09.000000000 +0100 +++ new/specfile-0.15.0/fedora/python-specfile.spec 2023-03-10 12:16:50.000000000 +0100 @@ -13,7 +13,7 @@ Name: python-specfile -Version: 0.14.0 +Version: 0.15.0 Release: 1%{?dist} Summary: A library for parsing and manipulating RPM spec files @@ -67,6 +67,9 @@ %changelog +* Fri Mar 10 2023 Packit Team <he...@packit.dev> - 0.15.0-1 +- New upstream release 0.15.0 + * Thu Feb 23 2023 Packit Team <he...@packit.dev> - 0.14.0-1 - New upstream release 0.14.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/specfile-0.14.0/plans/packit-integration.fmf new/specfile-0.15.0/plans/packit-integration.fmf --- old/specfile-0.14.0/plans/packit-integration.fmf 2023-02-23 17:10:09.000000000 +0100 +++ new/specfile-0.15.0/plans/packit-integration.fmf 2023-03-10 12:16:50.000000000 +0100 @@ -3,6 +3,13 @@ url: https://github.com/packit/packit filter: tier:0 | tier:1 +prepare: + - how: install + copr: packit/packit-dev + # make sure the Copr repo has higher priority than TF Tag Repository + - how: shell + script: dnf -y config-manager --save --setopt="*:packit:packit-dev.priority=5" + adjust: - when: "how == integration" because: "provide latest python-specfile rpm when running locally" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/specfile-0.14.0/specfile/context_management.py new/specfile-0.15.0/specfile/context_management.py --- old/specfile-0.14.0/specfile/context_management.py 2023-02-23 17:10:09.000000000 +0100 +++ new/specfile-0.15.0/specfile/context_management.py 2023-03-10 12:16:50.000000000 +0100 @@ -39,7 +39,7 @@ class GeneratorContextManager(contextlib._GeneratorContextManager): """ - Extended contextlib._GeneratorContextManager that provides get() method. + Extended contextlib._GeneratorContextManager that provides content property. """ def __init__(self, function: Callable) -> None: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/specfile-0.14.0/specfile/sections.py new/specfile-0.15.0/specfile/sections.py --- old/specfile-0.14.0/specfile/sections.py 2023-02-23 17:10:09.000000000 +0100 +++ new/specfile-0.15.0/specfile/sections.py 2023-03-10 12:16:50.000000000 +0100 @@ -231,12 +231,7 @@ def expand(s): if context: - result = context.expand( - s, skip_parsing=getattr(expand, "skip_parsing", False) - ) - # parse only once - expand.skip_parsing = True - return result + return context.expand(s) return Macros.expand(s) def split_id(line): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/specfile-0.14.0/specfile/sources.py new/specfile-0.15.0/specfile/sources.py --- old/specfile-0.14.0/specfile/sources.py 2023-02-23 17:10:09.000000000 +0100 +++ new/specfile-0.15.0/specfile/sources.py 2023-03-10 12:16:50.000000000 +0100 @@ -5,7 +5,7 @@ import re import urllib.parse from abc import ABC, abstractmethod -from typing import Iterable, List, Optional, Tuple, Union, cast, overload +from typing import TYPE_CHECKING, Iterable, List, Optional, Tuple, Union, cast, overload from specfile.exceptions import DuplicateSourceException from specfile.formatter import formatted @@ -13,6 +13,9 @@ from specfile.tags import Comments, Tag, Tags from specfile.utils import get_filename_from_location +if TYPE_CHECKING: + from specfile.specfile import Specfile + class Source(ABC): """Class that represents a source.""" @@ -236,6 +239,7 @@ allow_duplicates: bool = False, default_to_implicit_numbering: bool = False, default_source_number_digits: int = 1, + context: Optional["Specfile"] = None, ) -> None: """ Constructs a `Sources` object. @@ -256,6 +260,7 @@ self._allow_duplicates = allow_duplicates self._default_to_implicit_numbering = default_to_implicit_numbering self._default_source_number_digits = default_source_number_digits + self._context = context def __eq__(self, other: object) -> bool: if not isinstance(other, Sources): @@ -277,7 +282,7 @@ return ( f"{self.__class__.__name__}({self._tags!r}, {self._sourcelists!r}, " f"{self._allow_duplicates!r}, {self._default_to_implicit_numbering!r}, " - f"{self._default_source_number_digits!r})" + f"{self._default_source_number_digits!r}, {self._context!r})" ) def __contains__(self, location: object) -> bool: @@ -502,21 +507,25 @@ name, separator = self._get_tag_format(cast(TagSource, source), number) container.insert( index, - Tag(name, location, separator, Comments()), + Tag(name, location, separator, Comments(), context=self._context), ) self._deduplicate_tag_names(i) else: container.insert( index, - SourcelistEntry(location, Comments()), # type: ignore[arg-type] + SourcelistEntry( # type: ignore[arg-type] + location, Comments(), context=self._context + ), ) elif self._sourcelists: - self._sourcelists[-1].append(SourcelistEntry(location, Comments())) + self._sourcelists[-1].append( + SourcelistEntry(location, Comments(), context=self._context) + ) else: index, name, separator = self._get_initial_tag_setup() self._tags.insert( index, - Tag(name, location, separator, Comments()), + Tag(name, location, separator, Comments(), context=self._context), ) def insert_numbered(self, number: int, location: str) -> int: @@ -549,7 +558,9 @@ else: i = 0 index, name, separator = self._get_initial_tag_setup(number) - self._tags.insert(index, Tag(name, location, separator, Comments())) + self._tags.insert( + index, Tag(name, location, separator, Comments(), context=self._context) + ) self._deduplicate_tag_names(i) return i diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/specfile-0.14.0/specfile/spec_parser.py new/specfile-0.15.0/specfile/spec_parser.py --- old/specfile-0.14.0/specfile/spec_parser.py 2023-02-23 17:10:09.000000000 +0100 +++ new/specfile-0.15.0/specfile/spec_parser.py 2023-03-10 12:16:50.000000000 +0100 @@ -3,8 +3,10 @@ import contextlib import copy +import hashlib import logging import os +import pickle import re import tempfile from pathlib import Path @@ -41,6 +43,9 @@ and were replaced with dummy files. """ + # hash of input parameters to the last parse performed + _last_parse_hash = None + def __init__( self, sourcedir: Path, @@ -325,11 +330,32 @@ Raises: RPMException, if parsing error occurs. """ + # calculate hash of all input parameters + payload = ( + id(self), + self.sourcedir, + self.macros, + self.force_parse, + content, + extra_macros, + ) + parse_hash = hashlib.sha256( + pickle.dumps(payload, protocol=pickle.HIGHEST_PROTOCOL) + ).digest() + if parse_hash == SpecParser._last_parse_hash: + # none of the input parameters has changed, no need to parse again + return if self.spec: # workaround RPM lua tables feature/bug, see above for details del self.spec try: - self.spec, self.tainted = self._do_parse(content, extra_macros) + try: + self.spec, self.tainted = self._do_parse(content, extra_macros) + except Exception: + SpecParser._last_parse_hash = None + raise + else: + SpecParser._last_parse_hash = parse_hash except RPMException: self.spec = None self.tainted = False diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/specfile-0.14.0/specfile/specfile.py new/specfile-0.15.0/specfile/specfile.py --- old/specfile-0.14.0/specfile/specfile.py 2023-02-23 17:10:09.000000000 +0100 +++ new/specfile-0.15.0/specfile/specfile.py 2023-03-10 12:16:50.000000000 +0100 @@ -64,7 +64,6 @@ self._parser = SpecParser( Path(sourcedir or self.path.parent), macros, force_parse ) - # parse here to fail early on parsing errors self._parser.parse(str(self)) def __eq__(self, other: object) -> bool: @@ -161,7 +160,6 @@ self, expression: str, extra_macros: Optional[List[Tuple[str, str]]] = None, - skip_parsing: bool = False, ) -> str: """ Expands an expression in the context of the spec file. @@ -169,15 +167,11 @@ Args: expression: Expression to expand. extra_macros: Extra macros to be defined before expansion is performed. - skip_parsing: Do not parse the spec file before expansion is performed. - Defaults to False. Mutually exclusive with extra_macros. Set this to True - only if you are certain that the global macro context is up-to-date. Returns: Expanded expression. """ - if not skip_parsing: - self._parser.parse(str(self), extra_macros) + self._parser.parse(str(self), extra_macros) return Macros.expand(expression) def get_active_macros(self) -> List[Macro]: @@ -336,6 +330,7 @@ allow_duplicates, default_to_implicit_numbering, default_source_number_digits, + context=self, ) finally: for section, sourcelist in sourcelists: @@ -372,6 +367,7 @@ allow_duplicates, default_to_implicit_numbering, default_source_number_digits, + context=self, ) finally: for section, patchlist in patchlists: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/specfile-0.14.0/specfile/value_parser.py new/specfile-0.15.0/specfile/value_parser.py --- old/specfile-0.14.0/specfile/value_parser.py 2023-02-23 17:10:09.000000000 +0100 +++ new/specfile-0.15.0/specfile/value_parser.py 2023-03-10 12:16:50.000000000 +0100 @@ -312,12 +312,7 @@ def expand(s): if context: - result = context.expand( - s, skip_parsing=getattr(expand, "skip_parsing", False) - ) - # parse only once - expand.skip_parsing = True - return result + return context.expand(s) return Macros.expand(s) def flatten(nodes): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/specfile-0.14.0/specfile.egg-info/PKG-INFO new/specfile-0.15.0/specfile.egg-info/PKG-INFO --- old/specfile-0.14.0/specfile.egg-info/PKG-INFO 2023-02-23 17:10:24.000000000 +0100 +++ new/specfile-0.15.0/specfile.egg-info/PKG-INFO 2023-03-10 12:17:02.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: specfile -Version: 0.14.0 +Version: 0.15.0 Summary: A library for parsing and manipulating RPM spec files. Home-page: https://github.com/packit/specfile Author: Red Hat diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/specfile-0.14.0/tests/integration/test_specfile.py new/specfile-0.15.0/tests/integration/test_specfile.py --- old/specfile-0.14.0/tests/integration/test_specfile.py 2023-02-23 17:10:09.000000000 +0100 +++ new/specfile-0.15.0/tests/integration/test_specfile.py 2023-03-10 12:16:50.000000000 +0100 @@ -12,7 +12,7 @@ from specfile.exceptions import RPMException, SpecfileException from specfile.prep import AutopatchMacro, AutosetupMacro, PatchMacro, SetupMacro from specfile.sections import Section -from specfile.specfile import Specfile +from specfile.specfile import Specfile, SpecParser def test_parse(spec_multiple_sources): @@ -481,3 +481,21 @@ assert deep_copy is not spec assert deep_copy._lines is not spec._lines assert deep_copy._parser is not spec._parser + + +def test_parse_if_necessary(spec_macros): + flexmock(SpecParser).should_call("_do_parse").once() + spec1 = Specfile(spec_macros) + spec2 = copy.deepcopy(spec1) + flexmock(SpecParser).should_call("_do_parse").never() + assert spec1.expanded_name == "test" + flexmock(SpecParser).should_call("_do_parse").once() + assert spec2.expanded_name == "test" + assert spec2.expanded_version == "0.1.2~rc2" + flexmock(SpecParser).should_call("_do_parse").once() + assert spec1.expanded_version == "0.1.2~rc2" + with spec1.macro_definitions() as md: + md[0].body = "28" + flexmock(SpecParser).should_call("_do_parse").once() + assert spec1.expanded_name == "test" + assert spec1.expanded_version == "28.1.2~rc2"