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 2022-11-12 17:40:56
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-specfile (Old)
and /work/SRC/openSUSE:Factory/.python-specfile.new.1597 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-specfile"
Sat Nov 12 17:40:56 2022 rev:2 rq:1035243 version:0.9.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-specfile/python-specfile.changes
2022-10-26 12:31:31.432278077 +0200
+++
/work/SRC/openSUSE:Factory/.python-specfile.new.1597/python-specfile.changes
2022-11-12 17:41:13.062185332 +0100
@@ -1,0 +2,7 @@
+Wed Nov 9 19:02:12 UTC 2022 - Yogalakshmi Arunachalam <[email protected]>
+
+- Update to version 0.9.0
+ * Added utility classes for working with (N)EVR. (#113)
+ * Fixed an issue with multiple instances of Specfile not expanding macros in
the right context. (#117)
+
+-------------------------------------------------------------------
Old:
----
specfile-0.8.0.tar.gz
New:
----
specfile-0.9.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-specfile.spec ++++++
--- /var/tmp/diff_new_pack.iQkmU7/_old 2022-11-12 17:41:13.858190071 +0100
+++ /var/tmp/diff_new_pack.iQkmU7/_new 2022-11-12 17:41:13.866190119 +0100
@@ -15,23 +15,24 @@
# Please submit bugfixes or comments via https://bugs.opensuse.org/
#
+
%define skip_python38 1
Name: python-specfile
-Version: 0.8.0
+Version: 0.9.0
Release: 0
Summary: A library for parsing and manipulating RPM spec files
License: MIT
URL: https://github.com/packit/specfile
Source:
https://files.pythonhosted.org/packages/source/s/specfile/specfile-%{version}.tar.gz
-BuildRequires: python-rpm-macros
-BuildRequires: %{python_module setuptools}
-BuildRequires: %{python_module setuptools_scm}
BuildRequires: %{python_module setuptools_scm_git_archive}
+BuildRequires: %{python_module setuptools_scm}
+BuildRequires: %{python_module setuptools}
+BuildRequires: python-rpm-macros
# SECTION test requirements
BuildRequires: %{python_module rpm}
-BuildRequires: %{python_module typing-extensions}
-BuildRequires: %{python_module pytest}
BuildRequires: %{python_module flexmock}
+BuildRequires: %{python_module pytest}
+BuildRequires: %{python_module typing-extensions}
# /SECTION
BuildRequires: fdupes
Requires: python-rpm
++++++ specfile-0.8.0.tar.gz -> specfile-0.9.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/specfile-0.8.0/.packit.yaml
new/specfile-0.9.0/.packit.yaml
--- old/specfile-0.8.0/.packit.yaml 2022-10-14 13:31:08.000000000 +0200
+++ new/specfile-0.9.0/.packit.yaml 2022-10-25 19:06:38.000000000 +0200
@@ -54,6 +54,12 @@
- fedora-all
- epel-9
+ - job: tests
+ trigger: pull_request
+ targets:
+ - fedora-all
+ - epel-9
+
- job: copr_build
trigger: commit
branch: main
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/specfile-0.8.0/.pre-commit-config.yaml
new/specfile-0.9.0/.pre-commit-config.yaml
--- old/specfile-0.8.0/.pre-commit-config.yaml 2022-10-14 13:31:08.000000000
+0200
+++ new/specfile-0.9.0/.pre-commit-config.yaml 2022-10-25 19:06:38.000000000
+0200
@@ -12,7 +12,7 @@
hooks:
- id: black
- repo: https://github.com/pre-commit/mirrors-prettier
- rev: v3.0.0-alpha.1
+ rev: v3.0.0-alpha.3
hooks:
- id: prettier
- repo: https://github.com/pre-commit/pre-commit-hooks
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/specfile-0.8.0/CHANGELOG.md
new/specfile-0.9.0/CHANGELOG.md
--- old/specfile-0.8.0/CHANGELOG.md 2022-10-14 13:31:08.000000000 +0200
+++ new/specfile-0.9.0/CHANGELOG.md 2022-10-25 19:06:38.000000000 +0200
@@ -1,3 +1,8 @@
+# 0.9.0
+
+- Added utility classes for working with (N)EVR. (#113)
+- Fixed an issue with multiple instances of `Specfile` not expanding macros in
the right context. (#117)
+
# 0.8.0
- Added `Specfile.update_tag()` method that allows updating tag values while
trying to preserve macro expansions. You can watch a demo on
[YouTube](https://youtu.be/yzMfBPdFXZY). (#101)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/specfile-0.8.0/PKG-INFO new/specfile-0.9.0/PKG-INFO
--- old/specfile-0.8.0/PKG-INFO 2022-10-14 13:31:18.927929400 +0200
+++ new/specfile-0.9.0/PKG-INFO 2022-10-25 19:06:48.976166000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: specfile
-Version: 0.8.0
+Version: 0.9.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.8.0/fedora/python-specfile.spec
new/specfile-0.9.0/fedora/python-specfile.spec
--- old/specfile-0.8.0/fedora/python-specfile.spec 2022-10-14
13:31:08.000000000 +0200
+++ new/specfile-0.9.0/fedora/python-specfile.spec 2022-10-25
19:06:38.000000000 +0200
@@ -13,7 +13,7 @@
Name: python-specfile
-Version: 0.8.0
+Version: 0.9.0
Release: 1%{?dist}
Summary: A library for parsing and manipulating RPM spec files
@@ -69,6 +69,9 @@
%changelog
+* Tue Oct 25 2022 Packit Team <[email protected]> - 0.9.0-1
+- New upstream release 0.9.0
+
* Fri Oct 14 2022 Packit Team <[email protected]> - 0.8.0-1
- New upstream release 0.8.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/specfile-0.8.0/specfile/changelog.py
new/specfile-0.9.0/specfile/changelog.py
--- old/specfile-0.8.0/specfile/changelog.py 2022-10-14 13:31:08.000000000
+0200
+++ new/specfile-0.9.0/specfile/changelog.py 2022-10-25 19:06:38.000000000
+0200
@@ -8,7 +8,9 @@
import rpm
+from specfile.exceptions import SpecfileException
from specfile.sections import Section
+from specfile.utils import EVR
WEEKDAYS = ("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")
MONTHS = (
@@ -137,8 +139,9 @@
return ""
return m.group("wsp") + (m.group("zp") or "")
- @staticmethod
+ @classmethod
def assemble(
+ cls,
timestamp: Union[datetime.date, datetime.datetime],
author: str,
content: List[str],
@@ -176,7 +179,7 @@
header += f" {timestamp:%Y} {author}"
if evr is not None:
header += f" - {evr}"
- return ChangelogEntry(header, content, [""] if append_newline else
None)
+ return cls(header, content, [""] if append_newline else None)
class Changelog(collections.UserList):
@@ -262,12 +265,11 @@
"""
def parse_evr(s):
- if not s:
+ try:
+ evr = EVR.from_string(s)
+ except SpecfileException:
return "0", "0", ""
- m = re.match(r"^(?:(\d+):)?(.*?)(?:-([^-]*))?$", s)
- if not m:
- return "0", "0", ""
- return m.group(1) or "0", m.group(2), m.group(3) or ""
+ return str(evr.epoch), evr.version or "0", evr.release
if since is None:
start_index = 0
@@ -293,8 +295,8 @@
)
return self[start_index:end_index]
- @staticmethod
- def parse(section: Section) -> "Changelog":
+ @classmethod
+ def parse(cls, section: Section) -> "Changelog":
"""
Parses a %changelog section.
@@ -325,7 +327,7 @@
predecessor.append(line)
if header:
data.insert(0, ChangelogEntry(header, content, following_lines))
- return Changelog(data, predecessor)
+ return cls(data, predecessor)
def get_raw_section_data(self) -> List[str]:
"""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/specfile-0.8.0/specfile/macro_definitions.py
new/specfile-0.9.0/specfile/macro_definitions.py
--- old/specfile-0.8.0/specfile/macro_definitions.py 2022-10-14
13:31:08.000000000 +0200
+++ new/specfile-0.9.0/specfile/macro_definitions.py 2022-10-25
19:06:38.000000000 +0200
@@ -162,8 +162,8 @@
return i
raise ValueError
- @staticmethod
- def parse(lines: List[str]) -> "MacroDefinitions":
+ @classmethod
+ def parse(cls, lines: List[str]) -> "MacroDefinitions":
"""
Parses given lines into macro defintions.
@@ -213,7 +213,7 @@
buffer = []
else:
buffer.append(line)
- return MacroDefinitions(data, buffer)
+ return cls(data, buffer)
def get_raw_data(self) -> List[str]:
result = []
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/specfile-0.8.0/specfile/prep.py
new/specfile-0.9.0/specfile/prep.py
--- old/specfile-0.8.0/specfile/prep.py 2022-10-14 13:31:08.000000000 +0200
+++ new/specfile-0.9.0/specfile/prep.py 2022-10-25 19:06:38.000000000 +0200
@@ -319,8 +319,8 @@
if index:
del self.macros[index]
- @staticmethod
- def parse(section: Section) -> "Prep":
+ @classmethod
+ def parse(cls, section: Section) -> "Prep":
"""
Parses a section into a `Prep` object.
@@ -350,25 +350,27 @@
m.group("o"),
)
prefix, suffix = line[: m.start("m")], line[m.end("o") :]
- cls = next(
+ klass = next(
(
- cls
- for cls in PrepMacro.__subclasses__()
- if name.startswith(cls.CANONICAL_NAME)
+ klass
+ for klass in PrepMacro.__subclasses__()
+ if name.startswith(klass.CANONICAL_NAME)
),
None,
)
- if not cls:
+ if not klass:
buffer.append(line)
continue
options = MacroOptions(
- MacroOptions.tokenize(option_string), cls.OPTSTRING,
cls.DEFAULTS
+ MacroOptions.tokenize(option_string),
+ klass.OPTSTRING,
+ klass.DEFAULTS,
)
- data.append(cls(name, options, delimiter, prefix, suffix,
buffer))
+ data.append(klass(name, options, delimiter, prefix, suffix,
buffer))
buffer = []
else:
buffer.append(line)
- return Prep(PrepMacros(data, buffer))
+ return cls(PrepMacros(data, buffer))
def get_raw_section_data(self) -> List[str]:
"""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/specfile-0.8.0/specfile/sections.py
new/specfile-0.9.0/specfile/sections.py
--- old/specfile-0.8.0/specfile/sections.py 2022-10-14 13:31:08.000000000
+0200
+++ new/specfile-0.9.0/specfile/sections.py 2022-10-25 19:06:38.000000000
+0200
@@ -172,8 +172,8 @@
return i
raise ValueError
- @staticmethod
- def parse(lines: List[str]) -> "Sections":
+ @classmethod
+ def parse(cls, lines: List[str]) -> "Sections":
"""
Parses given lines into sections.
@@ -197,7 +197,7 @@
data = [Section(PREAMBLE, lines[: section_starts[0]])]
for start, end in zip(section_starts, section_starts[1:]):
data.append(Section(lines[start][1:], lines[start + 1 : end]))
- return Sections(data)
+ return cls(data)
def get_raw_data(self) -> List[str]:
result = []
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/specfile-0.8.0/specfile/sourcelist.py
new/specfile-0.9.0/specfile/sourcelist.py
--- old/specfile-0.8.0/specfile/sourcelist.py 2022-10-14 13:31:08.000000000
+0200
+++ new/specfile-0.9.0/specfile/sourcelist.py 2022-10-25 19:06:38.000000000
+0200
@@ -2,12 +2,15 @@
# SPDX-License-Identifier: MIT
import collections
-from typing import List, Optional, SupportsIndex, overload
+from typing import TYPE_CHECKING, List, Optional, SupportsIndex, overload
from specfile.rpm import Macros
from specfile.sections import Section
from specfile.tags import Comments
+if TYPE_CHECKING:
+ from specfile.specfile import Specfile
+
class SourcelistEntry:
"""
@@ -18,9 +21,23 @@
comments: List of comments associated with the source/patch.
"""
- def __init__(self, location: str, comments: Comments) -> None:
+ def __init__(
+ self, location: str, comments: Comments, context: Optional["Specfile"]
= None
+ ) -> None:
+ """
+ Constructs a `SourceListEntry` object.
+
+ Args:
+ location: Literal location of the source/patch as stored in the
spec file.
+ comments: List of comments associated with the source/patch.
+ context: `Specfile` instance that defines the context for macro
expansions.
+
+ Returns:
+ Constructed instance of `SourceListEntry` class.
+ """
self.location = location
self.comments = comments.copy()
+ self._context = context
def __eq__(self, other: object) -> bool:
if not isinstance(other, SourcelistEntry):
@@ -34,6 +51,8 @@
@property
def expanded_location(self) -> str:
"""URL of the source/patch after expanding macros."""
+ if self._context:
+ return self._context.expand(self.location)
return Macros.expand(self.location)
@@ -87,13 +106,16 @@
def copy(self) -> "Sourcelist":
return Sourcelist(self.data, self._remainder)
- @staticmethod
- def parse(section: Section) -> "Sourcelist":
+ @classmethod
+ def parse(
+ cls, section: Section, context: Optional["Specfile"] = None
+ ) -> "Sourcelist":
"""
Parses a section into sources/patches.
Args:
section: %sourcelist/%patchlist section.
+ context: `Specfile` instance that defines the context for macro
expansions.
Returns:
Constructed instance of `Sourcelist` class.
@@ -102,11 +124,11 @@
buffer: List[str] = []
for line in section:
if line and not line.lstrip().startswith("#"):
- data.append(SourcelistEntry(line, Comments.parse(buffer)))
+ data.append(SourcelistEntry(line, Comments.parse(buffer),
context))
buffer = []
else:
buffer.append(line)
- return Sourcelist(data, buffer)
+ return cls(data, buffer)
def get_raw_section_data(self) -> List[str]:
"""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/specfile-0.8.0/specfile/sources.py
new/specfile-0.9.0/specfile/sources.py
--- old/specfile-0.8.0/specfile/sources.py 2022-10-14 13:31:08.000000000
+0200
+++ new/specfile-0.9.0/specfile/sources.py 2022-10-25 19:06:38.000000000
+0200
@@ -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.rpm import Macros
@@ -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."""
@@ -218,6 +221,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.
@@ -228,6 +232,7 @@
allow_duplicates: Whether to allow duplicate entries when adding
new sources.
default_to_implicit_numbering: Use implicit numbering (no source
numbers) by default.
default_source_number_digits: Default number of digits in a source
number.
+ context: `Specfile` instance that defines the context for macro
expansions.
Returns:
Constructed instance of `Sources` class.
@@ -237,6 +242,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 __repr__(self) -> str:
tags = repr(self._tags)
@@ -306,6 +312,11 @@
_, container, index = items[i]
del container[index]
+ def _expand(self, s: str) -> str:
+ if self._context:
+ return self._context.expand(s)
+ return Macros.expand(s)
+
def _get_tags(self) -> List[Tuple[TagSource, Tags, int]]:
"""
Gets all tag sources.
@@ -474,7 +485,7 @@
name, separator = self._get_tag_format(source, number)
container.insert(
index,
- Tag(name, location, Macros.expand(location), separator,
Comments()),
+ Tag(name, location, self._expand(location), separator,
Comments()),
)
self._deduplicate_tag_names(i)
else:
@@ -488,7 +499,7 @@
index, name, separator = self._get_initial_tag_setup()
self._tags.insert(
index,
- Tag(name, location, Macros.expand(location), separator,
Comments()),
+ Tag(name, location, self._expand(location), separator,
Comments()),
)
def insert_numbered(self, number: int, location: str) -> int:
@@ -522,7 +533,7 @@
i = 0
index, name, separator = self._get_initial_tag_setup(number)
self._tags.insert(
- index, Tag(name, location, Macros.expand(location), separator,
Comments())
+ index, Tag(name, location, self._expand(location), separator,
Comments())
)
self._deduplicate_tag_names(i)
return i
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/specfile-0.8.0/specfile/specfile.py
new/specfile-0.9.0/specfile/specfile.py
--- old/specfile-0.8.0/specfile/specfile.py 2022-10-14 13:31:08.000000000
+0200
+++ new/specfile-0.9.0/specfile/specfile.py 2022-10-25 19:06:38.000000000
+0200
@@ -233,7 +233,9 @@
"""
with self.sections() as sections, self.tags(sections.package) as tags:
sourcelists = [
- (s, Sourcelist.parse(s)) for s in sections if s.name ==
"sourcelist"
+ (s, Sourcelist.parse(s, context=self))
+ for s in sections
+ if s.name == "sourcelist"
]
try:
yield Sources(
@@ -242,6 +244,7 @@
allow_duplicates,
default_to_implicit_numbering,
default_source_number_digits,
+ context=self,
)
finally:
for section, sourcelist in sourcelists:
@@ -267,7 +270,9 @@
"""
with self.sections() as sections, self.tags(sections.package) as tags:
patchlists = [
- (s, Sourcelist.parse(s)) for s in sections if s.name ==
"patchlist"
+ (s, Sourcelist.parse(s, context=self))
+ for s in sections
+ if s.name == "patchlist"
]
try:
yield Patches(
@@ -276,6 +281,7 @@
allow_duplicates,
default_to_implicit_numbering,
default_source_number_digits,
+ context=self,
)
finally:
for section, patchlist in patchlists:
@@ -572,7 +578,9 @@
entities.update({k.upper(): v for k, v in entities.items() if v.type
== Tag})
def update(value, requested_value):
- regex, template = ValueParser.construct_regex(value,
entities.keys())
+ regex, template = ValueParser.construct_regex(
+ value, entities.keys(), context=self
+ )
m = regex.match(requested_value)
if m:
d = m.groupdict()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/specfile-0.8.0/specfile/tags.py
new/specfile-0.9.0/specfile/tags.py
--- old/specfile-0.8.0/specfile/tags.py 2022-10-14 13:31:08.000000000 +0200
+++ new/specfile-0.9.0/specfile/tags.py 2022-10-25 19:06:38.000000000 +0200
@@ -190,8 +190,8 @@
item = Comment(item)
self.data.append(item)
- @staticmethod
- def parse(lines: List[str]) -> "Comments":
+ @classmethod
+ def parse(cls, lines: List[str]) -> "Comments":
"""
Parses list of lines into comments.
@@ -210,7 +210,7 @@
preceding_lines.insert(0, line)
continue
comments.insert(0, Comment(*reversed(m.groups())))
- return Comments(comments, preceding_lines)
+ return cls(comments, preceding_lines)
def get_raw_data(self) -> List[str]:
return self._preceding_lines + [str(i) for i in self.data]
@@ -427,8 +427,10 @@
item.comments._preceding_lines[0:0] = lines[: index + 1]
del lines[: index + 1]
- @staticmethod
- def parse(raw_section: Section, parsed_section: Optional[Section] = None)
-> "Tags":
+ @classmethod
+ def parse(
+ cls, raw_section: Section, parsed_section: Optional[Section] = None
+ ) -> "Tags":
"""
Parses a section into tags.
@@ -475,7 +477,7 @@
buffer = []
else:
buffer.append(line)
- return Tags(data, buffer)
+ return cls(data, buffer)
def get_raw_section_data(self) -> List[str]:
"""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/specfile-0.8.0/specfile/utils.py
new/specfile-0.9.0/specfile/utils.py
--- old/specfile-0.8.0/specfile/utils.py 2022-10-14 13:31:08.000000000
+0200
+++ new/specfile-0.9.0/specfile/utils.py 2022-10-25 19:06:38.000000000
+0200
@@ -1,9 +1,79 @@
# Copyright Contributors to the Packit project.
# SPDX-License-Identifier: MIT
+import collections
+import re
import urllib.parse
from pathlib import Path
+from specfile.exceptions import SpecfileException
+
+
+class EVR(collections.abc.Hashable):
+ """Class representing Epoch-Version-Release combination."""
+
+ def __init__(self, *, version: str, release: str = "", epoch: int = 0) ->
None:
+ self.epoch = epoch
+ self.version = version
+ self.release = release
+
+ def _key(self) -> tuple:
+ return self.epoch, self.version, self.release
+
+ def __hash__(self) -> int:
+ return hash(self._key())
+
+ def __eq__(self, other: object) -> bool:
+ if type(other) != self.__class__:
+ return NotImplemented
+ return self._key() == other._key()
+
+ def __repr__(self) -> str:
+ return f"EVR(epoch={self.epoch}, version='{self.version}',
release='{self.release}')"
+
+ def __str__(self) -> str:
+ epoch = f"{self.epoch}:" if self.epoch > 0 else ""
+ release = f"-{self.release}" if self.release else ""
+ return f"{epoch}{self.version}{release}"
+
+ @classmethod
+ def from_string(cls, evr: str) -> "EVR":
+ m = re.match(r"^(?:(\d+):)?([^-]+?)(?:-([^-]+))?$", evr)
+ if not m:
+ raise SpecfileException("Invalid EVR string.")
+ e, v, r = m.groups()
+ return cls(epoch=int(e) if e else 0, version=v, release=r or "")
+
+
+class NEVR(EVR):
+ """Class representing Name-Epoch-Version-Release combination."""
+
+ def __init__(
+ self, *, name: str, version: str, release: str = "", epoch: int = 0
+ ) -> None:
+ self.name = name
+ super().__init__(epoch=epoch, version=version, release=release)
+
+ def _key(self) -> tuple:
+ return self.name, self.epoch, self.version, self.release
+
+ def __repr__(self) -> str:
+ return (
+ f"NEVR(name='{self.name}', epoch={self.epoch}, "
+ f"version='{self.version}', release='{self.release}')"
+ )
+
+ def __str__(self) -> str:
+ return f"{self.name}-" + super().__str__()
+
+ @classmethod
+ def from_string(cls, nevr: str) -> "NEVR":
+ m = re.match(r"^(.+?)-(?:(\d+):)?([^-]+?)(?:-([^-]+))?$", nevr)
+ if not m:
+ raise SpecfileException("Invalid NEVR string.")
+ n, e, v, r = m.groups()
+ return cls(name=n, epoch=int(e) if e else 0, version=v, release=r or
"")
+
def get_filename_from_location(location: str) -> str:
"""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/specfile-0.8.0/specfile/value_parser.py
new/specfile-0.9.0/specfile/value_parser.py
--- old/specfile-0.8.0/specfile/value_parser.py 2022-10-14 13:31:08.000000000
+0200
+++ new/specfile-0.9.0/specfile/value_parser.py 2022-10-25 19:06:38.000000000
+0200
@@ -5,12 +5,15 @@
import re
from abc import ABC
from string import Template
-from typing import List, Tuple
+from typing import TYPE_CHECKING, List, Optional, Tuple
from typing.re import Pattern
from specfile.exceptions import UnterminatedMacroException
from specfile.rpm import Macros
+if TYPE_CHECKING:
+ from specfile.specfile import Specfile
+
SUBSTITUTION_GROUP_PREFIX = "sub_"
@@ -227,7 +230,10 @@
@classmethod
def construct_regex(
- cls, value: str, modifiable_entities: List[str]
+ cls,
+ value: str,
+ modifiable_entities: List[str],
+ context: Optional["Specfile"] = None,
) -> Tuple[Pattern, Template]:
"""
Parses the given value and constructs a regex that allows matching
@@ -250,18 +256,24 @@
value: Value string to parse.
modifiable_entities: Names of modifiable entities, i.e. local
macro definitions
and tags.
+ context: `Specfile` instance that defines the context for macro
expansions.
Returns:
Tuple in the form of (constructed regex, corresponding template).
"""
+ def expand(s):
+ if context:
+ return context.expand(s)
+ return Macros.expand(s)
+
def flatten(nodes):
# get rid of conditional macro expansions
result = []
for node in nodes:
if isinstance(node, ConditionalMacroExpansion):
# evaluate the condition
- if Macros.expand(f"%{node.prefix}{node.name}"):
+ if expand(f"%{node.prefix}{node.name}"):
result.append(f"%{{{node.prefix}{node.name}:")
result.extend(flatten(node.body))
result.append("}")
@@ -281,13 +293,13 @@
elif isinstance(node, StringLiteral):
tokens.append(("v", node.value, ""))
elif isinstance(node, (ShellExpansion, ExpressionExpansion)):
- const = Macros.expand(str(node))
+ const = expand(str(node))
tokens.append(("c", const, str(node)))
elif isinstance(node, MacroSubstitution):
if node.prefix.count("!") % 2 == 0 and node.name in
modifiable_entities:
tokens.append(("g", node.name, str(node)))
else:
- const = Macros.expand(str(node))
+ const = expand(str(node))
tokens.append(("c", const, str(node)))
elif isinstance(node, EnclosedMacroSubstitution):
if (
@@ -297,7 +309,7 @@
):
tokens.append(("g", node.name, str(node)))
else:
- const = Macros.expand(str(node))
+ const = expand(str(node))
tokens.append(("c", const, str(node)))
def escape(s):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/specfile-0.8.0/specfile.egg-info/PKG-INFO
new/specfile-0.9.0/specfile.egg-info/PKG-INFO
--- old/specfile-0.8.0/specfile.egg-info/PKG-INFO 2022-10-14
13:31:18.000000000 +0200
+++ new/specfile-0.9.0/specfile.egg-info/PKG-INFO 2022-10-25
19:06:48.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: specfile
-Version: 0.8.0
+Version: 0.9.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.8.0/tests/integration/test_specfile.py
new/specfile-0.9.0/tests/integration/test_specfile.py
--- old/specfile-0.8.0/tests/integration/test_specfile.py 2022-10-14
13:31:08.000000000 +0200
+++ new/specfile-0.9.0/tests/integration/test_specfile.py 2022-10-25
19:06:38.000000000 +0200
@@ -333,3 +333,14 @@
assert md.minorver.body == "2"
with spec.sources() as sources:
assert sources[1].location == "tests-86.tar.xz"
+
+
+def test_multiple_instances(spec_minimal, spec_autosetup):
+ spec1 = Specfile(spec_minimal)
+ spec2 = Specfile(spec_autosetup)
+ spec1.version = "14.2"
+ assert spec2.expanded_version == "0.1"
+ with spec2.sources() as sources:
+ assert sources[0].expanded_location == "test-0.1.tar.xz"
+ sources.append("tests-%{version}.tar.xz")
+ assert sources[1].expanded_location == "tests-0.1.tar.xz"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/specfile-0.8.0/tests/unit/test_utils.py
new/specfile-0.9.0/tests/unit/test_utils.py
--- old/specfile-0.8.0/tests/unit/test_utils.py 2022-10-14 13:31:08.000000000
+0200
+++ new/specfile-0.9.0/tests/unit/test_utils.py 2022-10-25 19:06:38.000000000
+0200
@@ -3,7 +3,7 @@
import pytest
-from specfile.utils import get_filename_from_location
+from specfile.utils import EVR, NEVR, get_filename_from_location
@pytest.mark.parametrize(
@@ -29,3 +29,55 @@
)
def test_get_filename_from_location(location, filename):
assert get_filename_from_location(location) == filename
+
+
[email protected](
+ "evr, result",
+ [
+ ("0", EVR(version="0")),
+ ("12.0-1", EVR(version="12.0", release="1")),
+ ("2:56.8-5", EVR(epoch=2, version="56.8", release="5")),
+ ("0.8.0-1.fc37", EVR(version="0.8.0", release="1.fc37")),
+ ("0.5.0~rc2-1.el9", EVR(version="0.5.0~rc2", release="1.el9")),
+ ("7.3-0.2.rc1.fc38", EVR(version="7.3", release="0.2.rc1.fc38")),
+ (
+ "7.3~rc1^20200701gdeadf00f-12.fc38",
+ EVR(version="7.3~rc1^20200701gdeadf00f", release="12.fc38"),
+ ),
+ ],
+)
+def test_EVR_from_string(evr, result):
+ assert EVR.from_string(evr) == result
+
+
[email protected](
+ "nevr, result",
+ [
+ ("package-0", NEVR(name="package", version="0")),
+ ("package-12.0-1", NEVR(name="package", version="12.0", release="1")),
+ (
+ "package-2:56.8-5",
+ NEVR(name="package", epoch=2, version="56.8", release="5"),
+ ),
+ (
+ "package-0.8.0-1.fc37",
+ NEVR(name="package", version="0.8.0", release="1.fc37"),
+ ),
+ (
+ "package-0.5.0~rc2-1.el9",
+ NEVR(name="package", version="0.5.0~rc2", release="1.el9"),
+ ),
+ (
+ "package-devel-7.3-0.2.rc1.fc38",
+ NEVR(name="package-devel", version="7.3", release="0.2.rc1.fc38"),
+ ),
+ (
+ "package-7.3~rc1^20200701gdeadf00f-12.fc38",
+ NEVR(
+ name="package", version="7.3~rc1^20200701gdeadf00f",
release="12.fc38"
+ ),
+ ),
+ ],
+)
+def test_NEVR_from_string(nevr, result):
+ assert NEVR.from_string(nevr) == result