diff --git a/specfile/changelog.py b/specfile/changelog.py index 506a6f4..342d203 100644 --- a/specfile/changelog.py +++ b/specfile/changelog.py @@ -46,6 +46,23 @@ class ChangelogEntry: content: List of lines forming the content of the entry. """ + _EVR_RE = re.compile( + r""" + ^.* + \d{4} # year + \s+ # whitespace + .+ # author + \s+ # preceding whitespace + ((?P\[)|(?P\())? # optional opening bracket + (?P\S+?) # EVR + (?(sb)\]|(?(rb)\))) # matching closing bracket + :? # optional colon + \s* # optional following whitespace + $ + """, + re.VERBOSE, + ) + def __init__( self, header: str, @@ -83,25 +100,24 @@ def __repr__(self) -> str: return f"ChangelogEntry({self.header!r}, {self.content!r}, {self._following_lines!r})" @property - def evr(self) -> Optional[str]: + def evr(self) -> Optional[EVR]: """EVR (epoch, version, release) of the entry.""" - m = re.match( - r""" - ^.* - \s+ # preceding whitespace - ((?P\[)|(?P\())? # optional opening bracket - (?P(\d+:)?\S+-\S+?) # EVR - (?(sb)\]|(?(rb)\))) # matching closing bracket - :? # optional colon - \s* # optional following whitespace - $ - """, - self.header, - re.VERBOSE, - ) + m = self._EVR_RE.match(self.header) + if not m: return None - return m.group("evr") + + evr_s = m.group("evr") + try: + evr = EVR.from_string(evr_s) + except SpecfileException: + return None + + # looks like an email + if evr_s.startswith("<") and evr_s.endswith(">"): + return None + + return evr @property def extended_timestamp(self) -> bool: @@ -263,7 +279,9 @@ def copy(self) -> "Changelog": return copy.copy(self) def filter( - self, since: Optional[str] = None, until: Optional[str] = None + self, + since: Optional[Union[str, EVR]] = None, + until: Optional[Union[str, EVR]] = None, ) -> "Changelog": """ Filters changelog entries with EVR between since and until. @@ -278,9 +296,11 @@ def filter( Filtered changelog. """ - def parse_evr(s): + def parse_evr(str_or_evr: Union[str, EVR]) -> EVR: + if isinstance(str_or_evr, EVR): + return str_or_evr try: - return EVR.from_string(s) + return EVR.from_string(str_or_evr) except SpecfileException: return EVR(version="0") @@ -290,8 +310,8 @@ def parse_evr(s): start_index = next( ( i - for i, e in enumerate(self.data) - if parse_evr(e.evr) >= parse_evr(since) + for i, entry in enumerate(self.data) + if entry.evr >= parse_evr(since) ), len(self.data) + 1, ) @@ -301,8 +321,8 @@ def parse_evr(s): end_index = next( ( i + 1 - for i, e in reversed(list(enumerate(self.data))) - if parse_evr(e.evr) <= parse_evr(until) + for i, entry in reversed(list(enumerate(self.data))) + if entry.evr <= parse_evr(until) ), 0, ) diff --git a/tests/unit/test_changelog.py b/tests/unit/test_changelog.py index 1b31192..ace615e 100644 --- a/tests/unit/test_changelog.py +++ b/tests/unit/test_changelog.py @@ -3,44 +3,57 @@ import copy import datetime +from typing import Optional import pytest from specfile.changelog import Changelog, ChangelogEntry from specfile.sections import Section +from specfile.utils import EVR @pytest.mark.parametrize( "header, evr", [ ("* Thu Jan 04 2007 Michael Schwendt ", None), + ("* Thu Jan 04 2007 Michael Schwendt ", None), + ( + "* Fri Jul 26 2024 Miroslav Suchý - ss981107-67", + EVR(version="ss981107", release="67"), + ), ( "* Mon Jul 13 2020 Tom Stellard 4.0-0.4.pre2", - "4.0-0.4.pre2", + EVR(version="4.0", release="0.4.pre2"), + ), + ( + "* Fri Jul 20 2018 Gwyn Ciesla - 0.52-6", + EVR(version="0.52", release="6"), ), - ("* Fri Jul 20 2018 Gwyn Ciesla - 0.52-6", "0.52-6"), ( "* Mon Feb 23 2009 Fedora Release Engineering " "- 1.23-3.20081106gitbe42b4", - "1.23-3.20081106gitbe42b4", + EVR(version="1.23", release="3.20081106gitbe42b4"), ), ( "* Thu Feb 04 2016 Marcin Zajaczkowski - 1:0.9.10-6", - "1:0.9.10-6", + EVR(epoch=1, version="0.9.10", release="6"), ), ( "* Mon Jan 03 2022 Fedora Kernel Team [5.16-0.rc8.55]", - "5.16-0.rc8.55", + EVR(version="5.16", release="0.rc8.55"), + ), + ( + "* Wed Jan 23 2002 Karsten Hopp (4.6-1)", + EVR(version="4.6", release="1"), ), - ("* Wed Jan 23 2002 Karsten Hopp (4.6-1)", "4.6-1"), ( "* Thu Apr 9 2015 Jeffrey C. Ollie - 13.3.2-1:", - "13.3.2-1", + EVR(version="13.3.2", release="1"), ), ], ) -def test_entry_evr(header, evr): - assert ChangelogEntry(header, [""]).evr == evr +def test_entry_evr(header, evr: Optional[EVR]): + assert evr == ChangelogEntry(header, [""]).evr @pytest.mark.parametrize( @@ -133,7 +146,9 @@ def test_filter(since, until, evrs): ), ] ) - assert [e.evr for e in changelog.filter(since=since, until=until)] == evrs + assert [e.evr for e in changelog.filter(since=since, until=until)] == [ + EVR.from_string(evr) for evr in evrs + ] def test_parse():