Merge fedora/rawhide into c10s

This commit is contained in:
Miro Hrončok 2024-09-09 09:39:40 +02:00
commit e4e198afe9
22 changed files with 447 additions and 124 deletions

View File

@ -148,6 +148,7 @@ or together with `-w`.
[tox]: https://tox.readthedocs.io/ [tox]: https://tox.readthedocs.io/
[tox-current-env]: https://github.com/fedora-python/tox-current-env/ [tox-current-env]: https://github.com/fedora-python/tox-current-env/
[prepare-metadata-for-build-wheel hook]: https://www.python.org/dev/peps/pep-0517/#prepare-metadata-for-build-wheel [prepare-metadata-for-build-wheel hook]: https://www.python.org/dev/peps/pep-0517/#prepare-metadata-for-build-wheel
[python-devel list]: https://lists.fedoraproject.org/archives/list/python-devel@lists.fedoraproject.org/
Additionally to generated requirements you can supply multiple file names to `%pyproject_buildrequires` macro. Additionally to generated requirements you can supply multiple file names to `%pyproject_buildrequires` macro.
Dependencies will be loaded from them: Dependencies will be loaded from them:
@ -385,6 +386,78 @@ These arguments are still required:
Multiple subpackages are generated when multiple names are provided. Multiple subpackages are generated when multiple names are provided.
Provisional: Declarative Buildsystem (RPM 4.20+)
------------------------------------------------
It is possible to reduce some of the spec boilerplate by using the provided
pyproject [declarative buildsystem].
This option is only available with RPM 4.20+ (e.g. in Fedora 41+).
The declarative buildsystem is **provisional** and the behavior might change.
Please subscribe to Fedora's [python-devel list] if you use the feature.
To enable the pyproject declarative buildsystem, use the following:
BuildSystem: pyproject
BuildOption(install): <options for %%pyproject_save_files>
That way, RPM will automatically fill-in the `%prep`, `%generate_buildrequires`,
`%build`, `%install`, and `%check` sections the following defaults:
%prep
%autosetup -p1 -C
%generate_buildrequires
%pyproject_buildrequires
%build
%pyproject_wheel
%install
%pyproject_install
%pyproject_save_files <options from BuildOption(install)>
%check
%pyproject_check_import
To pass options to the individual macros, use `BuildOption` (see the [documentation of declarative buildsystems][declarative buildsystem]).
# pass options for %%pyproject_save_files (mandatory when not overriding %%install)
BuildOption(install): -l _module +auto
# replace the default options for %%autosetup
BuildOption(prep): -S git_am -C
# pass options to %%pyproject_buildrequires
BuildOption(generate_buildrequires): docs-requirements.txt -t
# pass options to %%pyproject_wheel
BuildOption(build): -C--global-option=--no-cython-compile
# pass options to %%pyproject_check_import
BuildOption(check): -e '*.test*'
Alternatively, you can supply your own sections to override the automatic ones:
BuildOption(generate_buildrequires): -w
...
%build
# do nothing, the wheel was built in %%generate_buildrequires
You can append to end of the automatic sections:
%check -a
# run %%pytest after %%pyproject_check_import
%pytest
Or prepend to the beginning of them:
%prep -p
# run %%gpgverify before %%autosetup
%gpgverify -k2 -s1 -d0
[declarative buildsystem]: https://rpm-software-management.github.io/rpm/manual/buildsystem.html
Limitations Limitations
----------- -----------

View File

@ -5,3 +5,13 @@
# When macros.pyproject is installed, it overrides this macro. # When macros.pyproject is installed, it overrides this macro.
# Note: This needs to maintain the same set of options as the real macro. # Note: This needs to maintain the same set of options as the real macro.
%pyproject_buildrequires(rRxtNwe:C:) echo 'pyproject-rpm-macros' && exit 0 %pyproject_buildrequires(rRxtNwe:C:) echo 'pyproject-rpm-macros' && exit 0
# Declarative buildsystem, requires RPM 4.20+ to work
# https://rpm-software-management.github.io/rpm/manual/buildsystem.html
# This is the minimal implementation to be in the srpm package,
# as required even before the BuildRequires are installed
%buildsystem_pyproject_conf() %nil
%buildsystem_pyproject_generate_buildrequires() %pyproject_buildrequires %*
%buildsystem_pyproject_build() %nil
%buildsystem_pyproject_install() %nil

View File

@ -109,15 +109,15 @@ fi
# Note: the three times nested questionmarked -i -f -F pattern means: If none of those options was used -- in that case, we inject our own -f # Note: the three times nested questionmarked -i -f -F pattern means: If none of those options was used -- in that case, we inject our own -f
%pyproject_extras_subpkg(n:i:f:F) %{expand:%{?python_extras_subpkg:%{python_extras_subpkg%{?!-i:%{?!-f:%{?!-F: -f %{_pyproject_ghost_distinfo}}}} %**}}} %pyproject_extras_subpkg(n:i:f:FaA) %{expand:%{?python_extras_subpkg:%{python_extras_subpkg%{?!-i:%{?!-f:%{?!-F: -f %{_pyproject_ghost_distinfo}}}} %**}}}
# Escaping an actual percentage sign in path by 8 signs has been verified in RPM 4.16 and 4.17. # Escaping shell-globs, percentage signs and spaces was reworked in RPM 4.19+
# See this thread http://lists.rpm.org/pipermail/rpm-list/2021-June/002048.html # https://github.com/rpm-software-management/rpm/issues/1749#issuecomment-1020420616
# Since RPM 4.19, 2 signs are needed instead. 4.18.90+ is a pre-release of RPM 4.19. # Since we support both ways, we pass either 4.19 or 4.18 to the script, so it knows which one to use
# On the CI, we build tests/escape_percentages.spec to verify the assumptions. # Rather than passing the actual version, we let RPM compare the versions, as it is easier done here than in Python
%pyproject_save_files(lL) %{expand:\\\ %pyproject_save_files(lL) %{expand:\\\
%{expr:v"0%{?rpmversion}" >= v"4.18.90" ? "RPM_PERCENTAGES_COUNT=2" : "RPM_PERCENTAGES_COUNT=8" } \\ %{expr:v"0%{?rpmversion}" >= v"4.18.90" ? "RPM_FILES_ESCAPE=4.19" : "RPM_FILES_ESCAPE=4.18" } \\
%{__python3} %{_rpmconfigdir}/redhat/pyproject_save_files.py \\ %{__python3} %{_rpmconfigdir}/redhat/pyproject_save_files.py \\
--output-files "%{pyproject_files}" \\ --output-files "%{pyproject_files}" \\
--output-modules "%{_pyproject_modules}" \\ --output-modules "%{_pyproject_modules}" \\
@ -221,3 +221,13 @@ PYTHONPATH="${PYTHONPATH:-%{buildroot}%{python3_sitearch}:%{buildroot}%{python3_
HOSTNAME="rpmbuild" \\ HOSTNAME="rpmbuild" \\
%{__python3} -m tox --current-env -q --recreate -e "%{-e:%{-e*}}%{!-e:%{toxenv}}" %{?*} %{__python3} -m tox --current-env -q --recreate -e "%{-e:%{-e*}}%{!-e:%{toxenv}}" %{?*}
} }
# Declarative buildsystem, requires RPM 4.20+ to work
# https://rpm-software-management.github.io/rpm/manual/buildsystem.html
%buildsystem_pyproject_conf() %nil
%buildsystem_pyproject_generate_buildrequires() %pyproject_buildrequires %*
%buildsystem_pyproject_build() %pyproject_wheel %*
%buildsystem_pyproject_install() %["%{shrink:%*}" == "" ? "%{error:BuildOption(install) is mandatory with pyproject BuildSystem.}" : "%pyproject_install \
%pyproject_save_files %*"]
%buildsystem_pyproject_check() %pyproject_check_import %*

View File

@ -1,5 +1,11 @@
# RPM macros, this is expected # RPM macros, this is expected
addFilter(r'only-non-binary-in-usr-lib') addFilter(r'only-non-binary-in-usr-lib')
# we mention older macro names in the description, they are unexpanded on purpose # we mention macro names in the descriptions and summaries
addFilter(r'unexpanded-macro %description .+ %py3_') addFilter(r'[EW]: unexpanded-macro (%description|Summary).+ %(py3_|(generate|pyproject)_buildrequires)')
# terms, not spelling errors
addFilter(r"[EW]: spelling-error .+'(cfg|toml|setuptools|buildrequires)'")
# the documentation is in the other subpackage
addFilter(r'pyproject-srpm-macros.noarch: [EW]: no-documentation')

View File

@ -1,5 +1,6 @@
Name: pyproject-rpm-macros Name: pyproject-rpm-macros
Summary: RPM macros for PEP 517 Python packages Summary: RPM macros for PEP 517 Python packages
# SPDX
License: MIT License: MIT
%bcond tests 1 %bcond tests 1
@ -13,8 +14,8 @@ License: MIT
# Increment Y and reset Z when new macros or features are added # Increment Y and reset Z when new macros or features are added
# Increment Z when this is a bugfix or a cosmetic change # Increment Z when this is a bugfix or a cosmetic change
# Dropping support for EOL Fedoras is *not* considered a breaking change # Dropping support for EOL Fedoras is *not* considered a breaking change
Version: 1.12.0 Version: 1.14.0
Release: 2%{?dist} Release: 1%{?dist}
# Macro files # Macro files
Source001: macros.pyproject Source001: macros.pyproject
@ -80,7 +81,8 @@ Requires: /usr/bin/sed
# This package requires the %%generate_buildrequires functionality. # This package requires the %%generate_buildrequires functionality.
# It has been introduced in RPM 4.15 (4.14.90 is the alpha of 4.15). # It has been introduced in RPM 4.15 (4.14.90 is the alpha of 4.15).
# What we need is rpmlib(DynamicBuildRequires), but that is impossible to (Build)Require. # What we need is rpmlib(DynamicBuildRequires), but that is impossible to (Build)Require.
Requires: (rpm-build >= 4.14.90 if rpm-build) # Also, we need to avoid 4.19.90..4.19.91-7 due to rhbz#2284187
Requires: ((rpm-build >= 4.14.90 with (rpm-build < 4.19.90 or rpm-build >= 4.19.91-8)) if rpm-build)
BuildRequires: rpm-build >= 4.14.90 BuildRequires: rpm-build >= 4.14.90
%description %description
@ -171,8 +173,23 @@ export HOSTNAME="rpmbuild" # to speedup tox in network-less mock, see rhbz#1856
%changelog %changelog
* Mon Jun 24 2024 Troy Dawson <tdawson@redhat.com> - 1.12.0-2 * Tue Jul 23 2024 Miro Hrončok <mhroncok@redhat.com> - 1.14.0-1
- Bump release for June 2024 mass rebuild - Add a provisional RPM Declarative Buildsystem (RPM 4.20+)
* Fri Jul 19 2024 Fedora Release Engineering <releng@fedoraproject.org> - 1.13.0-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild
* Tue Jul 02 2024 Miro Hrončok <mhroncok@redhat.com> - 1.13.0-1
- Properly escape weird characters from paths in %%{pyproject_files} (RPM 4.19+ only)
- Revert the temporary workaround for RPM 4.20 alpha 2 leaking \x1f (unit separators)
- Fixes: rhbz#1990879
* Tue Jun 25 2024 Cristian Le <fedora@lecris.me> - 1.12.2-1
- %%pyproject_extras_subpkg: Allow passing -a or -A to %%python_extras_subpkg
* Tue Jun 04 2024 Miro Hrončok <mhroncok@redhat.com> - 1.12.1-1
- Add a temporary workaround for RPM 4.20 alpha 2 leaking \x1f (unit separators)
- Related: rhbz#2284187
* Fri Jan 26 2024 Miro Hrončok <miro@hroncok.cz> - 1.12.0-1 * Fri Jan 26 2024 Miro Hrončok <miro@hroncok.cz> - 1.12.0-1
- Namespace pyproject-rpm-macros generated text files with %%{python3_pkgversion} - Namespace pyproject-rpm-macros generated text files with %%{python3_pkgversion}

View File

@ -248,6 +248,14 @@ def get_backend(requirements):
# with pyproject.toml without a specified build backend. # with pyproject.toml without a specified build backend.
# If the default requirements change, also change them in the macro! # If the default requirements change, also change them in the macro!
requirements.add('setuptools >= 40.8', source='default build backend') requirements.add('setuptools >= 40.8', source='default build backend')
# PEP 517 doesn't mandate depending on wheel when the default backend is used.
# Historically, it used to be assumed as necessary, but later it turned out to be wrong.
# See the removal in pip and build:
# https://github.com/pypa/pip/pull/12449
# https://github.com/pypa/build/pull/716
# However, the requirement *will* be generated by setuptools anyway
# as part of get_requires_for_build_wheel().
# So we might as well keep it to skip one redundant step.
requirements.add('wheel', source='default build backend') requirements.add('wheel', source='default build backend')
requirements.check(source='build backend') requirements.check(source='build backend')

View File

@ -2,6 +2,7 @@ import argparse
import fnmatch import fnmatch
import json import json
import os import os
import re
from collections import defaultdict from collections import defaultdict
from keyword import iskeyword from keyword import iskeyword
@ -11,9 +12,15 @@ from importlib.metadata import Distribution
# From RPM's build/files.c strtokWithQuotes delim argument # From RPM's build/files.c strtokWithQuotes delim argument
RPM_FILES_DELIMETERS = ' \n\t' RPM_FILES_DELIMETERS = ' \n\t'
RPM_GLOB_SYMBOLS = '[]{}*?!'
# Combined for escape_rpm_path_4_19()
RPM_SPECIAL_SYMBOLS = RPM_FILES_DELIMETERS + RPM_GLOB_SYMBOLS + '"' + "\\"
RPM_ESCAPE_REGEX = re.compile(f"([{re.escape(RPM_SPECIAL_SYMBOLS)}])")
# See the comment in the macro that wraps this script # See the comment in the macro that wraps this script
RPM_PERCENTAGES_COUNT = int(os.getenv('RPM_PERCENTAGES_COUNT', '2')) RPM_FILES_ESCAPE = os.getenv('RPM_FILES_ESCAPE', '4.19')
PYCACHED_SUFFIX = '{,.opt-?}.pyc'
# RPM hardcodes the lists of manpage extensions and directories, # RPM hardcodes the lists of manpage extensions and directories,
# so we have to maintain separate ones :( # so we have to maintain separate ones :(
@ -118,8 +125,9 @@ def pycached(script, python_version):
""" """
assert script.suffix == ".py" assert script.suffix == ".py"
pyver = "".join(python_version.split(".")[:2]) pyver = "".join(python_version.split(".")[:2])
pycname = f"{script.stem}.cpython-{pyver}{{,.opt-?}}.pyc" pycname = f"{script.stem}.cpython-{pyver}{PYCACHED_SUFFIX}"
pyc = pycache_dir(script) / pycname pyc = pycache_dir(script) / pycname
pyc.glob_suffix_len = len(PYCACHED_SUFFIX)
return [script, pyc] return [script, pyc]
@ -212,10 +220,12 @@ def normalize_manpage_filename(prefix, path):
if fnmatch.fnmatch(str(path.parent), mandir) and path.name != "dir": if fnmatch.fnmatch(str(path.parent), mandir) and path.name != "dir":
# "abc.1.gz2" -> "abc.1*" # "abc.1.gz2" -> "abc.1*"
if path.suffix[1:] in MANPAGE_EXTENSIONS: if path.suffix[1:] in MANPAGE_EXTENSIONS:
return BuildrootPath(path.parent / (path.stem + "*")) path = BuildrootPath(path.parent / (path.stem + "*"))
# "abc.1 -> abc.1*" # "abc.1 -> abc.1*"
else: else:
return BuildrootPath(path.parent / (path.name + "*")) path = BuildrootPath(path.parent / (path.name + "*"))
path.glob_suffix_len = 1
return path
else: else:
return path return path
@ -424,60 +434,139 @@ def classify_paths(
return paths return paths
def escape_rpm_path(path): def escape_rpm_path_4_19(path):
r"""
Escape special characters in string-paths or BuildrootPaths, RPM >= 4.19
E.g. a space in path otherwise makes RPM think it's multiple paths,
unless we escape it.
Or a literal % symbol in path might be expanded as a macro if not escaped by %%.
See https://github.com/rpm-software-management/rpm/pull/2103
and https://github.com/rpm-software-management/rpm/pull/2206
If the path ends with a glob produced by our other functions,
we cannot escape that part.
The BuildrootPath.glob_suffix_len attribute is used to indicate such globs.
When such suffix exists, it is not escaped.
Examples:
>>> escape_rpm_path_4_19(BuildrootPath('/usr/lib/python3.9/site-packages/setuptools'))
'/usr/lib/python3.9/site-packages/setuptools'
>>> escape_rpm_path_4_19('/usr/lib/python3.9/site-packages/setuptools/script (dev).tmpl')
'/usr/lib/python3.9/site-packages/setuptools/script\\ (dev).tmpl'
>>> escape_rpm_path_4_19('/usr/share/data/100%valid.path')
'/usr/share/data/100%%valid.path'
>>> escape_rpm_path_4_19('/usr/share/data/100 % valid.path')
'/usr/share/data/100\\ %%\\ valid.path'
>>> escape_rpm_path_4_19('/usr/share/data/1000 %% valid.path')
'/usr/share/data/1000\\ %%%%\\ valid.path'
>>> escape_rpm_path_4_19('/usr/share/data/spaces and "quotes" and ?')
'/usr/share/data/spaces\\ and\\ \\"quotes\\"\\ and\\ \\?'
>>> escape_rpm_path_4_19('/usr/share/data/spaces and [square brackets]')
'/usr/share/data/spaces\\ and\\ \\[square\\ brackets\\]'
>>> path = BuildrootPath('/whatever/__pycache__/bar.cpython-38{,.opt-?}.pyc')
>>> path.glob_suffix_len = len('{,.opt-?}.pyc')
>>> escape_rpm_path_4_19(path)
'/whatever/__pycache__/bar.cpython-38{,.opt-?}.pyc'
>>> path = BuildrootPath('/spa ces/__pycache__/bar.cpython-38{,.opt-?}.pyc')
>>> path.glob_suffix_len = len('{,.opt-?}.pyc')
>>> escape_rpm_path_4_19(path)
'/spa\\ ces/__pycache__/bar.cpython-38{,.opt-?}.pyc'
>>> path = BuildrootPath('/usr/man/man5/ipykernel.5*')
>>> path.glob_suffix_len = 1
>>> escape_rpm_path_4_19(path)
'/usr/man/man5/ipykernel.5*'
""" """
Escape special characters in string-paths or BuildrootPaths glob_suffix_len = getattr(path, "glob_suffix_len", 0)
suffix = ""
path = str(path)
if glob_suffix_len:
suffix = path[-glob_suffix_len:]
path = path[:-glob_suffix_len]
if "%" in path:
path = path.replace("%", "%%")
# Prepend all matched/special characters (\1) with a backslash (escaped, hence \\):
return RPM_ESCAPE_REGEX.sub(r'\\\1', path) + suffix
def escape_rpm_path_4_18(path):
"""
Escape special characters in string-paths or BuildrootPaths, RPM < 4.19
E.g. a space in path otherwise makes RPM think it's multiple paths, E.g. a space in path otherwise makes RPM think it's multiple paths,
unless we put it in "quotes". unless we put it in "quotes".
Or a literal % symbol in path might be expanded as a macro if not escaped. Or a literal % symbol in path might be expanded as a macro if not escaped.
Due to limitations in RPM, Due to limitations in RPM < 4.19,
some paths with spaces and other special characters are not supported. some paths with spaces and other special characters are not supported.
See this thread http://lists.rpm.org/pipermail/rpm-list/2021-June/002048.html
Examples: Examples:
>>> escape_rpm_path(BuildrootPath('/usr/lib/python3.9/site-packages/setuptools')) >>> escape_rpm_path_4_18(BuildrootPath('/usr/lib/python3.9/site-packages/setuptools'))
'/usr/lib/python3.9/site-packages/setuptools' '/usr/lib/python3.9/site-packages/setuptools'
>>> escape_rpm_path('/usr/lib/python3.9/site-packages/setuptools/script (dev).tmpl') >>> escape_rpm_path_4_18('/usr/lib/python3.9/site-packages/setuptools/script (dev).tmpl')
'"/usr/lib/python3.9/site-packages/setuptools/script (dev).tmpl"' '"/usr/lib/python3.9/site-packages/setuptools/script (dev).tmpl"'
>>> escape_rpm_path('/usr/share/data/100%valid.path') >>> escape_rpm_path_4_18('/usr/share/data/100%valid.path')
'/usr/share/data/100%%valid.path' '/usr/share/data/100%%%%%%%%valid.path'
>>> escape_rpm_path('/usr/share/data/100 % valid.path') >>> escape_rpm_path_4_18('/usr/share/data/100 % valid.path')
'"/usr/share/data/100 %% valid.path"' '"/usr/share/data/100 %%%%%%%% valid.path"'
>>> escape_rpm_path('/usr/share/data/1000 %% valid.path') >>> escape_rpm_path_4_18('/usr/share/data/1000 %% valid.path')
'"/usr/share/data/1000 %%%% valid.path"' '"/usr/share/data/1000 %%%%%%%%%%%%%%%% valid.path"'
>>> escape_rpm_path('/usr/share/data/spaces and "quotes"') >>> escape_rpm_path_4_18('/usr/share/data/spaces and "quotes"')
Traceback (most recent call last): Traceback (most recent call last):
... ...
NotImplementedError: ... NotImplementedError: ...
>>> escape_rpm_path('/usr/share/data/spaces and [square brackets]') >>> escape_rpm_path_4_18('/usr/share/data/spaces and [square brackets]')
Traceback (most recent call last): Traceback (most recent call last):
... ...
NotImplementedError: ... NotImplementedError: ...
""" """
orig_path = path = str(path) orig_path = path = str(path)
if "%" in path: if "%" in path:
path = path.replace("%", "%" * RPM_PERCENTAGES_COUNT) # Escaping an actual percentage sign in path by 8 signs
# has been verified in RPM 4.16 and 4.17:
path = path.replace("%", "%" * 8)
if any(symbol in path for symbol in RPM_FILES_DELIMETERS): if any(symbol in path for symbol in RPM_FILES_DELIMETERS):
if '"' in path: if '"' in path:
# As far as we know, RPM cannot list such file individually # As far as we know, RPM < 4.19 cannot list such file individually
# See this thread http://lists.rpm.org/pipermail/rpm-list/2021-June/002048.html # See this thread http://lists.rpm.org/pipermail/rpm-list/2021-June/002048.html
raise NotImplementedError(f'" symbol in path with spaces is not supported by %pyproject_save_files: {orig_path!r}') raise NotImplementedError(f'" symbol in path with spaces is not supported by %pyproject_save_files on RPM < 4.19: {orig_path!r}')
if "[" in path or "]" in path: if "[" in path or "]" in path:
# See https://bugzilla.redhat.com/show_bug.cgi?id=1990879 # See https://bugzilla.redhat.com/show_bug.cgi?id=1990879
# and https://github.com/rpm-software-management/rpm/issues/1749 # and https://github.com/rpm-software-management/rpm/issues/1749
raise NotImplementedError(f'[ or ] symbol in path with spaces is not supported by %pyproject_save_files: {orig_path!r}') raise NotImplementedError(f'[ or ] symbol in path with spaces is not supported by %pyproject_save_files on RPM < 4.19: {orig_path!r}')
return f'"{path}"' return f'"{path}"'
return path return path
if RPM_FILES_ESCAPE == "4.19":
escape_rpm_path = escape_rpm_path_4_19
elif RPM_FILES_ESCAPE == "4.18":
escape_rpm_path = escape_rpm_path_4_18
else:
raise RuntimeError("RPM_FILES_ESCAPE must be 4.18 or 4.19")
def generate_file_list(paths_dict, module_globs, include_others=False): def generate_file_list(paths_dict, module_globs, include_others=False):
""" """
This function takes the classified paths_dict and turns it into lines This function takes the classified paths_dict and turns it into lines

View File

@ -457,7 +457,7 @@ classified:
- /usr/lib/python3.7/site-packages/comic2pdf-3.1.0.dist-info/top_level.txt - /usr/lib/python3.7/site-packages/comic2pdf-3.1.0.dist-info/top_level.txt
- /usr/lib/python3.7/site-packages/comic2pdf-3.1.0.dist-info/zip-safe - /usr/lib/python3.7/site-packages/comic2pdf-3.1.0.dist-info/zip-safe
licenses: [] licenses: []
modules: [] modules: {}
other: other:
files: files:
- /usr/bin/comic2pdf.py - /usr/bin/comic2pdf.py

View File

@ -25,6 +25,21 @@ TEST_RECORDS = yaml_data["records"]
TEST_METADATAS = yaml_data["metadata"] TEST_METADATAS = yaml_data["metadata"]
# insert glob_suffix_len for .pyc files and man pages globs
for paths_dict in EXPECTED_DICT.values():
for modules in paths_dict["modules"].values():
for module in modules:
for idx, file in enumerate(module["files"]):
if file.endswith(".pyc"):
module["files"][idx] = BuildrootPath(file)
module["files"][idx].glob_suffix_len = len("{,.opt-?}.pyc")
if "other" in paths_dict and "files" in paths_dict["other"]:
for idx, file in enumerate(paths_dict["other"]["files"]):
if file.endswith("*"):
paths_dict["other"]["files"][idx] = BuildrootPath(file)
paths_dict["other"]["files"][idx].glob_suffix_len = len("*")
@pytest.fixture @pytest.fixture
def tldr_root(tmp_path): def tldr_root(tmp_path):
prepare_pyproject_record(tmp_path, package="tldr") prepare_pyproject_record(tmp_path, package="tldr")

88
tests/escape_paths.spec Normal file
View File

@ -0,0 +1,88 @@
Name: escape_paths
Version: 0.1
Release: 0
Summary: ...
License: MIT
BuildArch: noarch
%description
This spec file verifies that escaping percentage signs in paths is possible via
exactly 8 (or 2) percentage signs in a filelist and directly in the %%files section.
It also verifies other path escaping assumptions on RPM 4.19+.
It serves as a regression test for pyproject_save_files:escape_rpm_path().
When this breaks, the function needs to be adapted.
%prep
cat > pyproject.toml << EOF
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
EOF
cat > setup.cfg << EOF
[metadata]
name = escape_paths
version = 0.1
[options]
packages =
escape_paths
[options.package_data]
escape_paths =
*
EOF
mkdir -p escape_paths
touch escape_paths/__init__.py
# the paths on disk will have 1 percentage sign if we type 2 in the spec
# we use the word 'version' after the sign, as that is a known existing macro
touch 'escape_paths/one%%version'
%if v"0%{?rpmversion}" >= v"4.18.90"
touch 'escape_paths/path with spaces'
touch 'escape_paths/path with spaces and "quotes'
touch 'escape_paths/path_with_?*[!globs]!'
touch 'escape_paths/path_with_\backslash'
touch 'escape_paths/path_with_{curly,brackets}'
touch 'escape_paths/path with spaces and ?*[!globs]! and \backslash'
%endif
%generate_buildrequires
%pyproject_buildrequires
%build
%pyproject_wheel
%install
%pyproject_install
%pyproject_save_files -L escape_paths
touch '%{buildroot}/two%%version'
%if v"0%{?rpmversion}" >= v"4.18.90"
touch '%{buildroot}/another_path with spaces'
touch '%{buildroot}/another_path with spaces and "quotes'
touch '%{buildroot}/another_path_with_?*[!globs]!'
touch '%{buildroot}/another_path_with_\backslash'
touch '%{buildroot}/another_path_with_{curly,brackets}'
touch '%{buildroot}/another_path with spaces and ?*[!globs]! and \backslash'
%endif
%check
grep '/escape_paths/one' %{pyproject_files}
%files -f %{pyproject_files}
%if v"0%{?rpmversion}" >= v"4.18.90"
/two%%version
/another_path\ with\ spaces
/another_path\ with\ spaces\ and\ \"quotes
/another_path_with_\?\*\[\!globs\]\!
/another_path_with_\\backslash
/another_path_with_\{curly,brackets\}
/another_path\ with\ spaces\ and\ \?\*\[\!globs\]\!\ and\ \\backslash
%else
/two%%%%%%%%version
%endif

View File

@ -1,65 +0,0 @@
Name: escape_percentages
Version: 0.1
Release: 0
Summary: ...
License: MIT
BuildArch: noarch
%description
This spec file verifies that escaping percentage signs in paths is possible via
exactly 2 (or 8) percentage signs in a filelist and directly in the %%files section.
It serves as a regression test for pyproject_save_files:escape_rpm_path().
When this breaks, the function needs to be adapted.
%prep
cat > pyproject.toml << EOF
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
EOF
cat > setup.cfg << EOF
[metadata]
name = escape_percentages
version = 0.1
[options]
packages =
escape_percentages
[options.package_data]
escape_percentages =
*
EOF
mkdir -p escape_percentages
touch escape_percentages/__init__.py
# the paths on disk will have 1 percentage sign if we type 2 in the spec
# we use the word 'version' after the sign, as that is a known existing macro
touch 'escape_percentages/one%%version'
%generate_buildrequires
%pyproject_buildrequires
%build
%pyproject_wheel
%install
%pyproject_install
%pyproject_save_files -L escape_percentages
touch '%{buildroot}/two%%version'
%check
grep '/escape_percentages/one' %{pyproject_files}
%files -f %{pyproject_files}
%if v"0%{?rpmversion}" >= v"4.18.90"
/two%%version
%else
/two%%%%%%%%version
%endif

View File

@ -14,7 +14,7 @@ Fake spec file to test %%pyproject_buildrequires -N works as expected
%prep %prep
cat > requirements.txt <<EOF cat > requirements.txt <<EOF
click!=5.0.0,>=4.1 # comment to increase test complexity click!=5.0.0,>=4.1 # comment to increase test complexity
toml>=0.10.0 tomli>=0.10.0
EOF EOF
%generate_buildrequires %generate_buildrequires
@ -22,7 +22,7 @@ EOF
%check %check
pip show toml click pip show tomli click
%if 0%{?fedora} || 0%{?rhel} > 9 %if 0%{?fedora} || 0%{?rhel} > 9
# On RHEL 9, python3-devel requires (python3-setuptools if rpm-build) # On RHEL 9, python3-devel requires (python3-setuptools if rpm-build)
pip show setuptools && exit 1 || true pip show setuptools && exit 1 || true

View File

@ -13,7 +13,14 @@ case $NAME in
;; ;;
"CentOS Stream"|"Red Hat Enterprise Linux") "CentOS Stream"|"Red Hat Enterprise Linux")
mock="centos-stream+epel-next-${version}-${arch}" case $version in
9)
mock="centos-stream+epel-next-${version}-${arch}"
;;
*)
mock="centos-stream+epel-${version}-${arch}"
;;
esac
repos="local,local-centos-stream" repos="local,local-centos-stream"
;; ;;
@ -36,10 +43,9 @@ if [ ! -f $config ]; then
cp $original $config cp $original $config
echo -e '\n\n' >> $config echo -e '\n\n' >> $config
echo -e 'config_opts["package_manager"] = "dnf"' >> $config
echo -e 'config_opts["package_manager_max_attempts"] = 10' >> $config echo -e 'config_opts["package_manager_max_attempts"] = 10' >> $config
echo -e 'config_opts["package_manager_attempt_delay"] = 60' >> $config echo -e 'config_opts["package_manager_attempt_delay"] = 60' >> $config
echo -e '\n\nconfig_opts[f"{config_opts.package_manager}.conf"] += """' >> $config echo -e '\n\nconfig_opts["dnf.conf"] += """' >> $config
# The zuul CI has zuul-build.repo # The zuul CI has zuul-build.repo
# The Jenkins CI has test-<pkgname>.repo # The Jenkins CI has test-<pkgname>.repo

View File

@ -13,7 +13,7 @@ BuildRequires: pyproject-rpm-macros
BuildRequires: python3-devel BuildRequires: python3-devel
%description %description
Tests building with the poetry build backend. Tests building with the poetry(-core) build backend.
%package -n python3-%{pypi_name} %package -n python3-%{pypi_name}
@ -25,6 +25,11 @@ Summary: %{summary}
%prep %prep
%autosetup -p1 -n %{pypi_name}-%{version} %autosetup -p1 -n %{pypi_name}-%{version}
%if 0%{?rhel}
# force the poetry-core build backend, as that is available rather than full poetry
sed -i 's/"poetry>=0.12"/"poetry-core"/' pyproject.toml
sed -i 's/"poetry.masonry.api"/"poetry.core.masonry.api"/' pyproject.toml
%endif
%generate_buildrequires %generate_buildrequires

View File

@ -11,7 +11,7 @@ BuildArch: noarch
%description %description
This package contains one .py module This package contains one .py module
Building this tests the flit build backend. Building this tests the flit(_core) build backend.
This package also has no explicit BuildRequires for python or the macros, This package also has no explicit BuildRequires for python or the macros,
testing the minimal implementation of %%pyproject_buildrequires testing the minimal implementation of %%pyproject_buildrequires
from pyproject-srpm-macros. from pyproject-srpm-macros.
@ -26,6 +26,10 @@ Summary: %{summary}
%prep %prep
%autosetup -p1 -n %{pypi_name}-%{version} %autosetup -p1 -n %{pypi_name}-%{version}
%if 0%{?rhel}
# force the flit-core build backend, as that is available rather than full flit
sed -i 's/"flit/"flit_core/' pyproject.toml
%endif
%generate_buildrequires %generate_buildrequires

View File

@ -11,9 +11,6 @@ BuildArch: noarch
BuildRequires: pyproject-rpm-macros BuildRequires: pyproject-rpm-macros
BuildRequires: python3-devel BuildRequires: python3-devel
# some of the nested modules import from this, but upstream does not declare the dependency
BuildRequires: python3-ipyparallel
%description %description
This package contains data files. This package contains data files.
Building this tests that data files are not listed when +auto is not used Building this tests that data files are not listed when +auto is not used
@ -49,7 +46,7 @@ sed -i '/"debugpy/d' pyproject.toml setup.py
%pyproject_save_files -l 'ipykernel*' +auto %pyproject_save_files -l 'ipykernel*' +auto
%check %check
%pyproject_check_import -e '*.test*' -e 'ipykernel.gui*' -e 'ipykernel.pylab.*' -e 'ipykernel.trio*' %pyproject_check_import -e '*.test*' -e 'ipykernel.gui*' -e 'ipykernel.pylab.*' -e 'ipykernel.trio*' -e 'ipykernel.datapub' -e 'ipykernel.pickleutil' -e 'ipykernel.serialize'
%files -n python3-ipykernel -f %{pyproject_files} %files -n python3-ipykernel -f %{pyproject_files}
%doc README.md %doc README.md

51
tests/python-pello.spec Normal file
View File

@ -0,0 +1,51 @@
Name: python-pello
Version: 1.0.4
Release: 0%{?dist}
Summary: Example Python library
License: MIT-0
URL: https://github.com/fedora-python/Pello
Source: %{url}/archive/v%{version}/Pello-%{version}.tar.gz
BuildArch: noarch
# we use this specfile for 2 different tests, this bcond controls it
# a build --with options tests custom BuildOptions(generate_buildrequires)
%bcond options 0
# unfortunately, the following is not even parsable on RPM < 4.20
%if v"0%{?rpmversion}" >= v"4.19.90"
BuildSystem: pyproject
BuildOption(install): -l pello
%if %{with options}
BuildOption(generate_buildrequires): -t
%endif
%endif
%description
We use this specfile to test the declarative buildsystem.
On older RPM version the build succeeds but builds nothing.
Note that due to the "automagic" it's a bit challenging to actually assert
anything here. Manually inspecting the logs and results when doing changes
to the declarative buildsystem is still advised.
%package -n python3-pello
Summary: %{summary}
%description -n python3-pello
...
%if %{with options} && v"0%{?rpmversion}" >= v"4.19.90"
%check -a
%tox
%endif
%if v"0%{?rpmversion}" >= v"4.19.90"
%files -n python3-pello -f %{pyproject_files}
%doc README.md
%{_bindir}/pello_greeting
%endif

View File

@ -30,6 +30,9 @@ Summary: %{summary}
%prep %prep
%autosetup -p1 -n %{pypi_name}-%{version} %autosetup -p1 -n %{pypi_name}-%{version}
# Avoid pytest 8 for now.
# Once the compat package is removed from Fedora, we will update pluggy.
sed -i 's/{env:_PYTEST_DEP:pytest}$/{env:_PYTEST_DEP:pytest<8}/' tox.ini
%generate_buildrequires %generate_buildrequires

View File

@ -1,6 +1,6 @@
%global pypi_name pytest %global pypi_name pytest
Name: python-%{pypi_name} Name: python-%{pypi_name}
Version: 7.1.3 Version: 7.2.0
Release: 0%{?dist} Release: 0%{?dist}
Summary: Simple powerful testing with Python Summary: Simple powerful testing with Python
License: MIT License: MIT
@ -11,7 +11,7 @@ BuildArch: noarch
BuildRequires: python3-devel BuildRequires: python3-devel
BuildRequires: pyproject-rpm-macros BuildRequires: pyproject-rpm-macros
# no xmlschema packaged for EPEL 9 yet, cannot run tests on EPEL # no xmlschema packaged for EPEL 10 yet, cannot run tests on EPEL
%if 0%{?fedora} %if 0%{?fedora}
%bcond_without tests %bcond_without tests
%else %else
@ -40,8 +40,6 @@ sed -E -i '/mock|nose/d' setup.cfg
# internal check for our macros: insert a subprocess echo to setup.py # internal check for our macros: insert a subprocess echo to setup.py
# to ensure it's not generated as BuildRequires # to ensure it's not generated as BuildRequires
echo 'import os; os.system("echo if-this-is-generated-the-build-will-fail")' >> setup.py echo 'import os; os.system("echo if-this-is-generated-the-build-will-fail")' >> setup.py
# make this build in EPEL 9
sed -i 's/setuptools-scm\[toml\]>=6.2.3/setuptools-scm[toml]>=5/' pyproject.toml
%generate_buildrequires %generate_buildrequires
@ -54,7 +52,7 @@ sed -i 's/setuptools-scm\[toml\]>=6.2.3/setuptools-scm[toml]>=5/' pyproject.toml
%install %install
%pyproject_install %pyproject_install
%pyproject_save_files -l '*pytest' +auto %pyproject_save_files -l '*pytest' py +auto
%check %check

View File

@ -1,5 +1,5 @@
Name: python-setuptools_scm Name: python-setuptools_scm
Version: 6.0.1 Version: 6.3.2
Release: 0%{?dist} Release: 0%{?dist}
Summary: The blessed package to manage your versions by SCM tags Summary: The blessed package to manage your versions by SCM tags
@ -12,7 +12,7 @@ BuildRequires: python3-devel
BuildRequires: pyproject-rpm-macros BuildRequires: pyproject-rpm-macros
BuildRequires: /usr/bin/git BuildRequires: /usr/bin/git
# flake8 is still missing tests deps in EPEL 9 # flake8 is still missing tests deps in EPEL 9/10
%if 0%{?fedora} %if 0%{?fedora}
%bcond_without flake8 %bcond_without flake8
%else %else
@ -58,7 +58,7 @@ Summary: %{summary}
%check %check
# This tox should run all the toxenvs specified via -e in %%pyproject_buildrequires # This tox should run all the toxenvs specified via -e in %%pyproject_buildrequires
# We only run some of the tests (running all of them requires network connection and is slow) # We only run some of the tests (running all of them requires network connection and is slow)
%tox -- -- -k test_version -Wdefault | tee toxlog %tox -- -- -k test_version -Wdefault --ignore testing/test_hg_git.py | tee toxlog
# Internal check for our macros: Assert both toxenvs were executed. # Internal check for our macros: Assert both toxenvs were executed.
grep -E 'py%{python3_version_nodots}-test: (OK|commands succeeded)' toxlog grep -E 'py%{python3_version_nodots}-test: (OK|commands succeeded)' toxlog

View File

@ -9,7 +9,6 @@ Source: %{pypi_source virtualenv}
BuildArch: noarch BuildArch: noarch
BuildRequires: python3-devel BuildRequires: python3-devel
BuildRequires: python3-flaky
BuildRequires: python3-pytest BuildRequires: python3-pytest
%description %description
@ -31,10 +30,12 @@ Summary: %{summary}
# Relax the upper bounds of some dependencies to their known available versions in EL 9 # Relax the upper bounds of some dependencies to their known available versions in EL 9
sed -i -e 's/distlib<1,>=0.3.6/distlib<1,>=0.3.2/' \ sed -i -e 's/distlib<1,>=0.3.6/distlib<1,>=0.3.2/' \
-e 's/filelock<4,>=3.4.1/filelock<4,>=3.3.1/' \ -e 's/filelock<4,>=3.4.1/filelock<4,>=3.3.1/' \
-e 's/platformdirs<4,>=2.4/platformdirs<4,>=2.3/' \ -e 's/platformdirs<4,>=2.4/platformdirs<5,>=2.3/' \
-e 's/hatchling>=1.12.2/hatchling>=0.25/' \ -e 's/hatchling>=1.12.2/hatchling>=0.25/' \
-e 's/hatch-vcs>=0.3/hatch-vcs>=0.2.1/' \ -e 's/hatch-vcs>=0.3/hatch-vcs>=0.2.1/' \
pyproject.toml pyproject.toml
# Drop the option for flaky
sed -i 's/--no-success-flaky-report//' pyproject.toml
# Hacky backport of https://src.fedoraproject.org/rpms/python-virtualenv/c/87b1f95664 # Hacky backport of https://src.fedoraproject.org/rpms/python-virtualenv/c/87b1f95664
%if 0%{?fedora} >= 39 || 0%{?rhel} >= 10 %if 0%{?fedora} >= 39 || 0%{?rhel} >= 10
sed -i 's/_nonwrappers/_hookimpls/' tests/conftest.py sed -i 's/_nonwrappers/_hookimpls/' tests/conftest.py
@ -62,8 +63,9 @@ echo '__version__, __version_tuple__ = version, version_tuple' >> %{buildroot}%{
%check %check
# test_main fails when .dist-info is not deleted at the end of %%pyproject_buildrequires # test_main fails when .dist-info is not deleted at the end of %%pyproject_buildrequires
# tests/integration/test_zipapp.py imports flaky
PIP_CERT=/etc/pki/tls/certs/ca-bundle.crt \ PIP_CERT=/etc/pki/tls/certs/ca-bundle.crt \
%pytest -v -k test_main %pytest -v -k test_main --ignore tests/integration/test_zipapp.py
%files -n python3-virtualenv -f %{pyproject_files} %files -n python3-virtualenv -f %{pyproject_files}

View File

@ -91,9 +91,15 @@
- virtualenv: - virtualenv:
dir: . dir: .
run: ./mocktest.sh python-virtualenv run: ./mocktest.sh python-virtualenv
- escape_percentages: - pello:
dir: . dir: .
run: ./mocktest.sh escape_percentages run: ./mocktest.sh python-pello
- pello_with_options:
dir: .
run: ./mocktest.sh python-pello --with options
- escape_paths:
dir: .
run: ./mocktest.sh escape_paths
- config-settings-test: - config-settings-test:
dir: . dir: .
run: ./mocktest.sh config-settings-test run: ./mocktest.sh config-settings-test