Compare commits
No commits in common. "c9-beta" and "a8" have entirely different histories.
0
.pyproject-rpm-macros.metadata
Normal file
0
.pyproject-rpm-macros.metadata
Normal file
@ -163,43 +163,6 @@ The `%pyproject_buildrequires` macro also accepts the `-r` flag for backward com
|
|||||||
it means "include runtime dependencies" which has been the default since version 0-53.
|
it means "include runtime dependencies" which has been the default since version 0-53.
|
||||||
|
|
||||||
|
|
||||||
Passing config settings to build backends
|
|
||||||
-----------------------------------------
|
|
||||||
|
|
||||||
The `%pyproject_buildrequires` and `%pyproject_wheel` macros accept a `-C` flag
|
|
||||||
to pass [configuration settings][config_settings] to the build backend.
|
|
||||||
Options take the form of `-C KEY`, `-C KEY=VALUE`, or `-C--option-with-dashes`.
|
|
||||||
Pass `-C` multiple times to specify multiple options.
|
|
||||||
This option is equivalent to pip's `--config-settings` flag.
|
|
||||||
These are passed on to PEP 517 hooks' `config_settings` argument as a Python
|
|
||||||
dictionary.
|
|
||||||
|
|
||||||
The `%pyproject_buildrequires` macro passes these options to the
|
|
||||||
`get_requires_for_build_wheel` and `prepare_metadata_for_build_wheel` hooks.
|
|
||||||
Passing `-C` to `%pyproject_buildrequires` is incompatible with `-N` which does
|
|
||||||
not call these hooks at all.
|
|
||||||
|
|
||||||
The `%pyproject_wheel` macro passes these options to the `build_wheel` hook.
|
|
||||||
|
|
||||||
Consult the project's upstream documentation and/or the corresponding build
|
|
||||||
backend's documentation for more information.
|
|
||||||
Note that some projects don't use config settings at all
|
|
||||||
and other projects may only accept config settings for one of the two steps.
|
|
||||||
|
|
||||||
Note that the current implementation of the macros uses `pip` to build wheels.
|
|
||||||
On some systems (notably on RHEL 9 with Python 3.9),
|
|
||||||
`pip` is too old to understand `--config-settings`.
|
|
||||||
Using the `-C` option for `%pyproject_wheel` (or `%pyproject_buildrequires -w`)
|
|
||||||
is not supported there and will result to an error like:
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
/usr/bin/python3 -m pip wheel [options] <requirement specifier> ...
|
|
||||||
...
|
|
||||||
no such option: --config-settings
|
|
||||||
|
|
||||||
[config_settings]: https://peps.python.org/pep-0517/#config-settings
|
|
||||||
|
|
||||||
|
|
||||||
Running tox based tests
|
Running tox based tests
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
@ -288,12 +251,6 @@ However, in Fedora packages, always list executables explicitly to avoid uninten
|
|||||||
and language (`*.mo`) files with `%lang` macro and appropriate language code.
|
and language (`*.mo`) files with `%lang` macro and appropriate language code.
|
||||||
Only license files declared via [PEP 639] `License-File` field are detected.
|
Only license files declared via [PEP 639] `License-File` field are detected.
|
||||||
[PEP 639] is still a draft and can be changed in the future.
|
[PEP 639] is still a draft and can be changed in the future.
|
||||||
It is possible to use the `-l` flag to declare that a missing license should
|
|
||||||
terminate the build or `-L` (the default) to explicitly disable this check.
|
|
||||||
Packagers are encouraged to use the `-l` flag when the `%license` file is not manually listed in `%files`
|
|
||||||
to avoid accidentally losing the file in a future version.
|
|
||||||
When the `%license` file is manually listed in `%files`,
|
|
||||||
packagers can use the `-L` flag to ensure future compatibility in case the `-l` behavior eventually becomes a default.
|
|
||||||
|
|
||||||
Note that `%pyproject_save_files` uses data from the [RECORD file](https://www.python.org/dev/peps/pep-0627/).
|
Note that `%pyproject_save_files` uses data from the [RECORD file](https://www.python.org/dev/peps/pep-0627/).
|
||||||
If you wish to rename, remove or otherwise change the installed files of a package
|
If you wish to rename, remove or otherwise change the installed files of a package
|
||||||
@ -348,12 +305,6 @@ The `%pyproject_check_import` macro also accepts positional arguments with
|
|||||||
additional qualified module names to check, useful for example if some modules are installed manually.
|
additional qualified module names to check, useful for example if some modules are installed manually.
|
||||||
Note that filtering by `-t`/`-e` also applies to the positional arguments.
|
Note that filtering by `-t`/`-e` also applies to the positional arguments.
|
||||||
|
|
||||||
Another macro, `%_pyproject_check_import_allow_no_modules` allows to pass the import check,
|
|
||||||
even if no Python modules are detected in the package.
|
|
||||||
This may be a valid case for packages containing e.g. typing stubs.
|
|
||||||
Don't use this macro in Fedora packages.
|
|
||||||
It's only intended to be used in automated build environments such as Copr.
|
|
||||||
|
|
||||||
|
|
||||||
Generating Extras subpackages
|
Generating Extras subpackages
|
||||||
-----------------------------
|
-----------------------------
|
||||||
@ -385,6 +336,91 @@ These arguments are still required:
|
|||||||
Multiple subpackages are generated when multiple names are provided.
|
Multiple subpackages are generated when multiple names are provided.
|
||||||
|
|
||||||
|
|
||||||
|
PROVISIONAL: Importing just-built (extension) modules in %build
|
||||||
|
---------------------------------------------------------------
|
||||||
|
|
||||||
|
Sometimes, it is desired to be able to import the *just-built* extension modules
|
||||||
|
in the `%build` section, e.g. to build the documentation with Sphinx.
|
||||||
|
|
||||||
|
%build
|
||||||
|
%pyproject_wheel
|
||||||
|
... build the docs here ...
|
||||||
|
|
||||||
|
With pure Python packages, it might be possible to set `PYTHONPATH=${PWD}` or `PYTHONPATH=${PWD}/src`.
|
||||||
|
However, it is a bit more complicated with extension modules.
|
||||||
|
|
||||||
|
The location of just-built modules might differ depending on Python version, architecture, pip version, etc.
|
||||||
|
Hence, the macro `%{pyproject_build_lib}` exists to be used like this:
|
||||||
|
|
||||||
|
%build
|
||||||
|
%pyproject_wheel
|
||||||
|
PYTHONPATH=%{pyproject_build_lib} ... build the docs here ...
|
||||||
|
|
||||||
|
This macro is currently **provisional** and the behavior might change.
|
||||||
|
Please subscribe to Fedora's [python-devel list] if you use the macro.
|
||||||
|
|
||||||
|
The `%{pyproject_build_lib}` macro expands to an Shell `$(...)` expression and does not work when put into single quotes (`'`).
|
||||||
|
|
||||||
|
Depending on the pip version, the expanded value will differ:
|
||||||
|
|
||||||
|
[python-devel list]: https://lists.fedoraproject.org/archives/list/python-devel@lists.fedoraproject.org/
|
||||||
|
|
||||||
|
### New pip 21.3+ with in-tree-build and setuptools 62.1+ (Fedora 37+)
|
||||||
|
|
||||||
|
Always use the macro from the same directory where you called `%pyproject_wheel` from.
|
||||||
|
The value will expand to something like:
|
||||||
|
|
||||||
|
* `/builddir/build/BUILD/%{name}-%{version}/build/lib.linux-x86_64-cpython-311` for wheels with extension modules
|
||||||
|
* `/builddir/build/BUILD/%{name}-%{version}/build/lib` for pure Python wheels
|
||||||
|
|
||||||
|
If multiple wheels were built from the same directory,
|
||||||
|
some pure Python and some with extension modules,
|
||||||
|
the expanded value will be combined with `:`:
|
||||||
|
|
||||||
|
* `/builddir/build/BUILD/%{name}-%{version}/build/lib.linux-x86_64-cypthon-311:/builddir/build/BUILD/%{name}-%{version}/build/lib`
|
||||||
|
|
||||||
|
If multiple wheels were built from different directories,
|
||||||
|
the value will differ depending on the current directory.
|
||||||
|
|
||||||
|
|
||||||
|
### New pip 21.3+ with in-tree-build and older setuptools (Fedora 36)
|
||||||
|
|
||||||
|
Always use the macro from the same directory where you called `%pyproject_wheel` from.
|
||||||
|
The value will expand to something like:
|
||||||
|
|
||||||
|
* `/builddir/build/BUILD/%{name}-%{version}/build/lib.linux-x86_64-3.10` for wheels with extension modules
|
||||||
|
* `/builddir/build/BUILD/%{name}-%{version}/build/lib` for pure Python wheels
|
||||||
|
|
||||||
|
If multiple wheels were built from the same directory,
|
||||||
|
some pure Python and some with extension modules,
|
||||||
|
the expanded value will be combined with `:`:
|
||||||
|
|
||||||
|
* `/builddir/build/BUILD/%{name}-%{version}/build/lib.linux-x86_64-3.10:/builddir/build/BUILD/%{name}-%{version}/build/lib`
|
||||||
|
|
||||||
|
If multiple wheels were built from different directories,
|
||||||
|
the value will differ depending on the current directory.
|
||||||
|
|
||||||
|
|
||||||
|
### Older pip with out-of-tree-build (Fedora 35 and EL 9)
|
||||||
|
|
||||||
|
The value will expand to something like:
|
||||||
|
|
||||||
|
* `/builddir/build/BUILD/%{name}-%{version}/.pyproject-builddir/pip-req-build-xxxxxxxx/build/lib.linux-x86_64-3.10` for wheels with extension modules
|
||||||
|
* `/builddir/build/BUILD/%{name}-%{version}/.pyproject-builddir/pip-req-build-xxxxxxxx/build/lib` for pure Python wheels
|
||||||
|
|
||||||
|
Note that the exact value is **not stable** between builds
|
||||||
|
(the `xxxxxxxx` part is randomly generated,
|
||||||
|
neither you should consider the `.pyproject-builddir` directory to remain stable).
|
||||||
|
|
||||||
|
If multiple wheels are built,
|
||||||
|
the expanded value will always be combined with `:` regardless of the current directory, e.g.:
|
||||||
|
|
||||||
|
* `/builddir/build/BUILD/%{name}-%{version}/.pyproject-builddir/pip-req-build-xxxxxxxx/build/lib.linux-x86_64-3.10:/builddir/build/BUILD/%{name}-%{version}/.pyproject-builddir/pip-req-build-yyyyyyyy/build/lib.linux-x86_64-3.10:/builddir/build/BUILD/%{name}-%{version}/.pyproject-builddir/pip-req-build-zzzzzzzz/build/lib`
|
||||||
|
|
||||||
|
**Note:** If you manage to build some wheels with in-tree-build and some with out-of-tree-build option,
|
||||||
|
the expanded value will contain all relevant directories.
|
||||||
|
|
||||||
|
|
||||||
Limitations
|
Limitations
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
@ -437,12 +473,6 @@ so be prepared for problems.
|
|||||||
[pip's documentation]: https://pip.pypa.io/en/stable/cli/pip_install/#vcs-support
|
[pip's documentation]: https://pip.pypa.io/en/stable/cli/pip_install/#vcs-support
|
||||||
|
|
||||||
|
|
||||||
Deprecated
|
|
||||||
----------
|
|
||||||
|
|
||||||
The `%{pyproject_build_lib}` macro is deprecated, don't use it.
|
|
||||||
|
|
||||||
|
|
||||||
Testing the macros
|
Testing the macros
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
@ -4,4 +4,4 @@
|
|||||||
# this macro will cause the package with the real macro to be installed.
|
# this macro will cause the package with the real macro to be installed.
|
||||||
# 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:) echo 'pyproject-rpm-macros' && exit 0
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
# This is a backward-compatible suffix used in all pyproject-rpm-macros directories
|
|
||||||
# For the main Python it's empty, for all others it's "-3.X"
|
|
||||||
%_pyproject_files_pkgversion %{expr:"%{python3_pkgversion}" != "3" ? "-%{python3_pkgversion}" : ""}
|
|
||||||
|
|
||||||
# This is a directory where wheels are stored and installed from, absolute
|
# This is a directory where wheels are stored and installed from, absolute
|
||||||
%_pyproject_wheeldir %{_builddir}%{?buildsubdir:/%{buildsubdir}}/pyproject-wheeldir%{_pyproject_files_pkgversion}
|
%_pyproject_wheeldir %{_builddir}%{?buildsubdir:/%{buildsubdir}}/pyproject-wheeldir
|
||||||
|
|
||||||
# This is a directory used as TMPDIR, where pip copies sources to and builds from, relative to PWD
|
# This is a directory used as TMPDIR, where pip copies sources to and builds from, relative to PWD
|
||||||
# For proper debugsource packages, we create TMPDIR within PWD
|
# For proper debugsource packages, we create TMPDIR within PWD
|
||||||
@ -12,40 +8,32 @@
|
|||||||
# This will be used in debugsource package paths (applies to extension modules only)
|
# This will be used in debugsource package paths (applies to extension modules only)
|
||||||
# NB: pytest collects tests from here if not hidden
|
# NB: pytest collects tests from here if not hidden
|
||||||
# https://docs.pytest.org/en/latest/reference.html#confval-norecursedirs
|
# https://docs.pytest.org/en/latest/reference.html#confval-norecursedirs
|
||||||
%_pyproject_builddir %{_builddir}%{?buildsubdir:/%{buildsubdir}}/.pyproject-builddir%{_pyproject_files_pkgversion}
|
%_pyproject_builddir %{_builddir}%{?buildsubdir:/%{buildsubdir}}/.pyproject-builddir
|
||||||
|
|
||||||
# We prefix all created files with this value to make them unique
|
# We prefix all created files with this value to make them unique
|
||||||
# Ideally, we would put them into %%{buildsubdir}, but that value changes during the spec
|
# Ideally, we would put them into %%{buildsubdir}, but that value changes during the spec
|
||||||
# The used value is similar to the one used to define the default %%buildroot
|
# The used value is similar to the one used to define the default %%buildroot
|
||||||
%_pyproject_files_prefix %{name}-%{version}-%{release}.%{_arch}%{_pyproject_files_pkgversion}
|
%_pyproject_files_prefix %{name}-%{version}-%{release}.%{_arch}
|
||||||
|
|
||||||
%pyproject_files %{_builddir}/%{_pyproject_files_prefix}-pyproject-files
|
%pyproject_files %{_builddir}/%{_pyproject_files_prefix}-pyproject-files
|
||||||
%_pyproject_modules %{_builddir}/%{_pyproject_files_prefix}-pyproject-modules
|
%_pyproject_modules %{_builddir}/%{_pyproject_files_prefix}-pyproject-modules
|
||||||
%_pyproject_ghost_distinfo %{_builddir}/%{_pyproject_files_prefix}-pyproject-ghost-distinfo
|
%_pyproject_ghost_distinfo %{_builddir}/%{_pyproject_files_prefix}-pyproject-ghost-distinfo
|
||||||
%_pyproject_record %{_builddir}/%{_pyproject_files_prefix}-pyproject-record
|
%_pyproject_record %{_builddir}/%{_pyproject_files_prefix}-pyproject-record
|
||||||
%_pyproject_buildrequires %{_builddir}/%{_pyproject_files_prefix}-pyproject-buildrequires
|
|
||||||
|
|
||||||
# Avoid leaking %%{_pyproject_builddir} to pytest collection
|
# Avoid leaking %%{_pyproject_builddir} to pytest collection
|
||||||
# https://bugzilla.redhat.com/show_bug.cgi?id=1935212
|
# https://bugzilla.redhat.com/show_bug.cgi?id=1935212
|
||||||
# The value is read and used by the %%pytest and %%tox macros:
|
# The value is read and used by the %%pytest and %%tox macros:
|
||||||
%_set_pytest_addopts %global __pytest_addopts --ignore=%{_pyproject_builddir}
|
%_set_pytest_addopts %global __pytest_addopts --ignore=%{_pyproject_builddir}
|
||||||
|
|
||||||
%pyproject_wheel(C:) %{expand:\\\
|
%pyproject_wheel() %{expand:\\\
|
||||||
%_set_pytest_addopts
|
%_set_pytest_addopts
|
||||||
mkdir -p "%{_pyproject_builddir}"
|
mkdir -p "%{_pyproject_builddir}"
|
||||||
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}" TMPDIR="%{_pyproject_builddir}" \\\
|
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}" TMPDIR="%{_pyproject_builddir}" \\\
|
||||||
%{__python3} -Bs %{_rpmconfigdir}/redhat/pyproject_wheel.py %{?**} %{_pyproject_wheeldir}
|
%{__python3} -Bs %{_rpmconfigdir}/redhat/pyproject_wheel.py %{_pyproject_wheeldir}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
%pyproject_build_lib %{!?__pyproject_build_lib_warned:%{warn:The %%{pyproject_build_lib} macro is deprecated.
|
%pyproject_build_lib %{expand:\\\
|
||||||
It only works with setuptools and is not build-backend-agnostic.
|
|
||||||
The macro is not scheduled for removal, but there is a possibility of incompatibilities with future versions of setuptools.
|
|
||||||
As a replacement for the macro for the setuptools backend on Fedora 37+, you can use $PWD/build/lib for pure Python packages,
|
|
||||||
or $PWD/build/lib.%%{python3_platform}-cpython-%%{python3_version_nodots} for packages with extension modules.
|
|
||||||
Other build backends and older distributions may need different paths.
|
|
||||||
See https://lists.fedoraproject.org/archives/list/python-devel@lists.fedoraproject.org/thread/HMLOPAU3RZLXD4BOJHTIPKI3I4U6U7OE/ for details.
|
|
||||||
}%global __pyproject_build_lib_warned 1}%{expand:\\\
|
|
||||||
$(
|
$(
|
||||||
pyproject_build_lib=()
|
pyproject_build_lib=()
|
||||||
if [ -d build/lib.%{python3_platform}-cpython-%{python3_version_nodots} ]; then
|
if [ -d build/lib.%{python3_platform}-cpython-%{python3_version_nodots} ]; then
|
||||||
@ -69,10 +57,6 @@ echo $(IFS=:; echo "${pyproject_build_lib[*]}")
|
|||||||
|
|
||||||
%pyproject_install() %{expand:\\\
|
%pyproject_install() %{expand:\\\
|
||||||
specifier=$(ls %{_pyproject_wheeldir}/*.whl | xargs basename --multiple | sed -E 's/([^-]+)-([^-]+)-.+\\\.whl/\\\1==\\\2/')
|
specifier=$(ls %{_pyproject_wheeldir}/*.whl | xargs basename --multiple | sed -E 's/([^-]+)-([^-]+)-.+\\\.whl/\\\1==\\\2/')
|
||||||
if [ -z $specifier ]; then
|
|
||||||
echo 'ERROR: %%%%pyproject_install found no wheel in %%%%{_pyproject_wheeldir} %{_pyproject_wheeldir}' >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
TMPDIR="%{_pyproject_builddir}" %{__python3} -m pip install --root %{buildroot} --prefix %{_prefix} --no-deps --disable-pip-version-check --progress-bar off --verbose --ignore-installed --no-warn-script-location --no-index --no-cache-dir --find-links %{_pyproject_wheeldir} $specifier
|
TMPDIR="%{_pyproject_builddir}" %{__python3} -m pip install --root %{buildroot} --prefix %{_prefix} --no-deps --disable-pip-version-check --progress-bar off --verbose --ignore-installed --no-warn-script-location --no-index --no-cache-dir --find-links %{_pyproject_wheeldir} $specifier
|
||||||
if [ -d %{buildroot}%{_bindir} ]; then
|
if [ -d %{buildroot}%{_bindir} ]; then
|
||||||
%py3_shebang_fix %{buildroot}%{_bindir}/*
|
%py3_shebang_fix %{buildroot}%{_bindir}/*
|
||||||
@ -112,12 +96,7 @@ fi
|
|||||||
%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:F) %{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.
|
%pyproject_save_files() %{expand:\\\
|
||||||
# See this thread http://lists.rpm.org/pipermail/rpm-list/2021-June/002048.html
|
|
||||||
# Since RPM 4.19, 2 signs are needed instead. 4.18.90+ is a pre-release of RPM 4.19.
|
|
||||||
# On the CI, we build tests/escape_percentages.spec to verify the assumptions.
|
|
||||||
%pyproject_save_files(lL) %{expand:\\\
|
|
||||||
%{expr:v"0%{?rpmversion}" >= v"4.18.90" ? "RPM_PERCENTAGES_COUNT=2" : "RPM_PERCENTAGES_COUNT=8" } \\
|
|
||||||
%{__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}" \\
|
||||||
@ -127,7 +106,7 @@ fi
|
|||||||
--python-version "%{python3_version}" \\
|
--python-version "%{python3_version}" \\
|
||||||
--pyproject-record "%{_pyproject_record}" \\
|
--pyproject-record "%{_pyproject_record}" \\
|
||||||
--prefix "%{_prefix}" \\
|
--prefix "%{_prefix}" \\
|
||||||
%{**}
|
%{*}
|
||||||
}
|
}
|
||||||
|
|
||||||
# -t - Process only top-level modules
|
# -t - Process only top-level modules
|
||||||
@ -141,20 +120,12 @@ fi
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
%_pyproject_check_import_allow_no_modules(e:t) \
|
|
||||||
if [ -z "$(cat %{_pyproject_modules})" ]; then\
|
|
||||||
echo "No modules to check found, exiting check"\
|
|
||||||
else\
|
|
||||||
%pyproject_check_import %{?**}\
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
%default_toxenv py%{python3_version_nodots}
|
%default_toxenv py%{python3_version_nodots}
|
||||||
%toxenv %{default_toxenv}
|
%toxenv %{default_toxenv}
|
||||||
|
|
||||||
|
|
||||||
# Note: Keep the options in sync with this macro from macros.aaa-pyproject-srpm
|
# Note: Keep the options in sync with this macro from macros.aaa-pyproject-srpm
|
||||||
%pyproject_buildrequires(rRxtNwe:C:) %{expand:\\\
|
%pyproject_buildrequires(rRxtNwe:) %{expand:\\\
|
||||||
%_set_pytest_addopts
|
%_set_pytest_addopts
|
||||||
# The _auto_set_build_flags feature does not do this in %%generate_buildrequires section,
|
# The _auto_set_build_flags feature does not do this in %%generate_buildrequires section,
|
||||||
# but we want to get an environment consistent with %%build:
|
# but we want to get an environment consistent with %%build:
|
||||||
@ -164,9 +135,6 @@ fi
|
|||||||
%{?_package_note_flags:%_generate_package_note_file}
|
%{?_package_note_flags:%_generate_package_note_file}
|
||||||
%{-R:
|
%{-R:
|
||||||
%{-r:%{error:The -R and -r options are mutually exclusive}}
|
%{-r:%{error:The -R and -r options are mutually exclusive}}
|
||||||
%{-x:%{error:The -R and -x options are mutually exclusive}}
|
|
||||||
%{-e:%{error:The -R and -e options are mutually exclusive}}
|
|
||||||
%{-t:%{error:The -R and -t options are mutually exclusive}}
|
|
||||||
%{-w:%{error:The -R and -w options are mutually exclusive}}
|
%{-w:%{error:The -R and -w options are mutually exclusive}}
|
||||||
}
|
}
|
||||||
%{-N:
|
%{-N:
|
||||||
@ -175,7 +143,6 @@ fi
|
|||||||
%{-e:%{error:The -N and -e options are mutually exclusive}}
|
%{-e:%{error:The -N and -e options are mutually exclusive}}
|
||||||
%{-t:%{error:The -N and -t options are mutually exclusive}}
|
%{-t:%{error:The -N and -t options are mutually exclusive}}
|
||||||
%{-w:%{error:The -N and -w options are mutually exclusive}}
|
%{-w:%{error:The -N and -w options are mutually exclusive}}
|
||||||
%{-C:%{error:The -N and -C options are mutually exclusive}}
|
|
||||||
}
|
}
|
||||||
%{-e:%{expand:%global toxenv %(%{__python3} -s %{_rpmconfigdir}/redhat/pyproject_construct_toxenv.py %{?**})}}
|
%{-e:%{expand:%global toxenv %(%{__python3} -s %{_rpmconfigdir}/redhat/pyproject_construct_toxenv.py %{?**})}}
|
||||||
echo 'pyproject-rpm-macros' # first stdout line matches the implementation in macros.aaa-pyproject-srpm
|
echo 'pyproject-rpm-macros' # first stdout line matches the implementation in macros.aaa-pyproject-srpm
|
||||||
@ -184,9 +151,9 @@ echo 'python%{python3_pkgversion}dist(pip) >= 19'
|
|||||||
echo 'python%{python3_pkgversion}dist(packaging)'
|
echo 'python%{python3_pkgversion}dist(packaging)'
|
||||||
%{!-N:if [ -f pyproject.toml ]; then
|
%{!-N:if [ -f pyproject.toml ]; then
|
||||||
%["%{python3_pkgversion}" == "3"
|
%["%{python3_pkgversion}" == "3"
|
||||||
? "echo '(python%{python3_pkgversion}dist(tomli) if python%{python3_pkgversion}-devel < 3.11)'"
|
? "echo '(python%{python3_pkgversion}dist(toml) if python%{python3_pkgversion}-devel < 3.11)'"
|
||||||
: "%[v"%{python3_pkgversion}" < v"3.11"
|
: "%[v"%{python3_pkgversion}" < v"3.11"
|
||||||
? "echo 'python%{python3_pkgversion}dist(tomli)'"
|
? "echo 'python%{python3_pkgversion}dist(toml)'"
|
||||||
: "true # will use tomllib, echo nothing"
|
: "true # will use tomllib, echo nothing"
|
||||||
]"
|
]"
|
||||||
]
|
]
|
||||||
@ -202,13 +169,9 @@ fi}
|
|||||||
rm -rfv *.dist-info/ >&2
|
rm -rfv *.dist-info/ >&2
|
||||||
if [ -f %{__python3} ]; then
|
if [ -f %{__python3} ]; then
|
||||||
mkdir -p "%{_pyproject_builddir}"
|
mkdir -p "%{_pyproject_builddir}"
|
||||||
echo -n > %{_pyproject_buildrequires}
|
|
||||||
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}" TMPDIR="%{_pyproject_builddir}" \\\
|
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}" TMPDIR="%{_pyproject_builddir}" \\\
|
||||||
RPM_TOXENV="%{toxenv}" HOSTNAME="rpmbuild" %{__python3} -Bs %{_rpmconfigdir}/redhat/pyproject_buildrequires.py %{?!_python_no_extras_requires:--generate-extras} --python3_pkgversion %{python3_pkgversion} --wheeldir %{_pyproject_wheeldir} --output %{_pyproject_buildrequires} %{?**} >&2
|
RPM_TOXENV="%{toxenv}" HOSTNAME="rpmbuild" %{__python3} -Bs %{_rpmconfigdir}/redhat/pyproject_buildrequires.py %{?!_python_no_extras_requires:--generate-extras} --python3_pkgversion %{python3_pkgversion} --wheeldir %{_pyproject_wheeldir} %{?**}
|
||||||
cat %{_pyproject_buildrequires}
|
|
||||||
fi
|
fi
|
||||||
# Incomplete .dist-info dir might confuse importlib.metadata
|
|
||||||
rm -rfv *.dist-info/ >&2
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,7 +4,9 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import importlib.metadata
|
import importlib.metadata
|
||||||
import argparse
|
import argparse
|
||||||
|
import tempfile
|
||||||
import traceback
|
import traceback
|
||||||
|
import contextlib
|
||||||
import json
|
import json
|
||||||
import subprocess
|
import subprocess
|
||||||
import re
|
import re
|
||||||
@ -14,7 +16,6 @@ import pathlib
|
|||||||
import zipfile
|
import zipfile
|
||||||
|
|
||||||
from pyproject_requirements_txt import convert_requirements_txt
|
from pyproject_requirements_txt import convert_requirements_txt
|
||||||
from pyproject_wheel import parse_config_settings_args
|
|
||||||
|
|
||||||
|
|
||||||
# Some valid Python version specifiers are not supported.
|
# Some valid Python version specifiers are not supported.
|
||||||
@ -45,6 +46,39 @@ except ImportError as e:
|
|||||||
from pyproject_convert import convert
|
from pyproject_convert import convert
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def hook_call():
|
||||||
|
"""Context manager that records all stdout content (on FD level)
|
||||||
|
and prints it to stderr at the end, with a 'HOOK STDOUT: ' prefix."""
|
||||||
|
tmpfile = io.TextIOWrapper(
|
||||||
|
tempfile.TemporaryFile(buffering=0),
|
||||||
|
encoding='utf-8',
|
||||||
|
errors='replace',
|
||||||
|
write_through=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
stdout_fd = 1
|
||||||
|
stdout_fd_dup = os.dup(stdout_fd)
|
||||||
|
stdout_orig = sys.stdout
|
||||||
|
|
||||||
|
# begin capture
|
||||||
|
sys.stdout = tmpfile
|
||||||
|
os.dup2(tmpfile.fileno(), stdout_fd)
|
||||||
|
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
finally:
|
||||||
|
# end capture
|
||||||
|
sys.stdout = stdout_orig
|
||||||
|
os.dup2(stdout_fd_dup, stdout_fd)
|
||||||
|
|
||||||
|
tmpfile.seek(0) # rewind
|
||||||
|
for line in tmpfile:
|
||||||
|
print_err('HOOK STDOUT:', line, end='')
|
||||||
|
|
||||||
|
tmpfile.close()
|
||||||
|
|
||||||
|
|
||||||
def guess_reason_for_invalid_requirement(requirement_str):
|
def guess_reason_for_invalid_requirement(requirement_str):
|
||||||
if ':' in requirement_str:
|
if ':' in requirement_str:
|
||||||
message = (
|
message = (
|
||||||
@ -66,11 +100,10 @@ def guess_reason_for_invalid_requirement(requirement_str):
|
|||||||
|
|
||||||
|
|
||||||
class Requirements:
|
class Requirements:
|
||||||
"""Requirement gatherer. The macro will eventually print out output_lines."""
|
"""Requirement printer"""
|
||||||
def __init__(self, get_installed_version, extras=None,
|
def __init__(self, get_installed_version, extras=None,
|
||||||
generate_extras=False, python3_pkgversion='3', config_settings=None):
|
generate_extras=False, python3_pkgversion='3'):
|
||||||
self.get_installed_version = get_installed_version
|
self.get_installed_version = get_installed_version
|
||||||
self.output_lines = []
|
|
||||||
self.extras = set()
|
self.extras = set()
|
||||||
|
|
||||||
if extras:
|
if extras:
|
||||||
@ -78,11 +111,9 @@ class Requirements:
|
|||||||
self.add_extras(*extra.split(','))
|
self.add_extras(*extra.split(','))
|
||||||
|
|
||||||
self.missing_requirements = False
|
self.missing_requirements = False
|
||||||
self.ignored_alien_requirements = []
|
|
||||||
|
|
||||||
self.generate_extras = generate_extras
|
self.generate_extras = generate_extras
|
||||||
self.python3_pkgversion = python3_pkgversion
|
self.python3_pkgversion = python3_pkgversion
|
||||||
self.config_settings = config_settings
|
|
||||||
|
|
||||||
def add_extras(self, *extras):
|
def add_extras(self, *extras):
|
||||||
self.extras |= set(e.strip() for e in extras)
|
self.extras |= set(e.strip() for e in extras)
|
||||||
@ -99,7 +130,7 @@ class Requirements:
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def add(self, requirement_str, *, package_name=None, source=None):
|
def add(self, requirement_str, *, source=None):
|
||||||
"""Output a Python-style requirement string as RPM dep"""
|
"""Output a Python-style requirement string as RPM dep"""
|
||||||
print_err(f'Handling {requirement_str} from {source}')
|
print_err(f'Handling {requirement_str} from {source}')
|
||||||
|
|
||||||
@ -121,21 +152,6 @@ class Requirements:
|
|||||||
if (requirement.marker is not None and
|
if (requirement.marker is not None and
|
||||||
not self.evaluate_all_environments(requirement)):
|
not self.evaluate_all_environments(requirement)):
|
||||||
print_err(f'Ignoring alien requirement:', requirement_str)
|
print_err(f'Ignoring alien requirement:', requirement_str)
|
||||||
self.ignored_alien_requirements.append(requirement_str)
|
|
||||||
return
|
|
||||||
|
|
||||||
# Handle self-referencing requirements
|
|
||||||
if package_name and canonicalize_name(package_name) == name:
|
|
||||||
# Self-referential extras need to be handled specially
|
|
||||||
if requirement.extras:
|
|
||||||
if not (requirement.extras <= self.extras): # only handle it if needed
|
|
||||||
# let all further requirements know we want those extras
|
|
||||||
self.add_extras(*requirement.extras)
|
|
||||||
# re-add all of the alien requirements ignored in the past
|
|
||||||
# they might no longer be alien now
|
|
||||||
self.readd_ignored_alien_requirements(package_name=package_name)
|
|
||||||
else:
|
|
||||||
print_err(f'Ignoring self-referential requirement without extras:', requirement_str)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# We need to always accept pre-releases as satisfying the requirement
|
# We need to always accept pre-releases as satisfying the requirement
|
||||||
@ -176,12 +192,12 @@ class Requirements:
|
|||||||
together.append(convert(python3dist(name, python3_pkgversion=self.python3_pkgversion),
|
together.append(convert(python3dist(name, python3_pkgversion=self.python3_pkgversion),
|
||||||
specifier.operator, specifier.version))
|
specifier.operator, specifier.version))
|
||||||
if len(together) == 0:
|
if len(together) == 0:
|
||||||
dep = python3dist(name, python3_pkgversion=self.python3_pkgversion)
|
print(python3dist(name,
|
||||||
self.output_lines.append(dep)
|
python3_pkgversion=self.python3_pkgversion))
|
||||||
elif len(together) == 1:
|
elif len(together) == 1:
|
||||||
self.output_lines.append(together[0])
|
print(together[0])
|
||||||
else:
|
else:
|
||||||
self.output_lines.append(f"({' with '.join(together)})")
|
print(f"({' with '.join(together)})")
|
||||||
|
|
||||||
def check(self, *, source=None):
|
def check(self, *, source=None):
|
||||||
"""End current pass if any unsatisfied dependencies were output"""
|
"""End current pass if any unsatisfied dependencies were output"""
|
||||||
@ -194,25 +210,23 @@ class Requirements:
|
|||||||
for req_str in requirement_strs:
|
for req_str in requirement_strs:
|
||||||
self.add(req_str, **kwargs)
|
self.add(req_str, **kwargs)
|
||||||
|
|
||||||
def readd_ignored_alien_requirements(self, **kwargs):
|
|
||||||
"""add() previously ignored alien requirements again."""
|
|
||||||
requirements, self.ignored_alien_requirements = self.ignored_alien_requirements, []
|
|
||||||
kwargs.setdefault('source', 'Previously ignored alien requirements')
|
|
||||||
self.extend(requirements, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def toml_load(opened_binary_file):
|
def toml_load(opened_binary_file):
|
||||||
try:
|
try:
|
||||||
# tomllib is in the standard library since 3.11.0b1
|
# tomllib is in the standard library since 3.11.0b1
|
||||||
import tomllib
|
import tomllib as toml_module
|
||||||
|
load_from = opened_binary_file
|
||||||
except ImportError:
|
except ImportError:
|
||||||
try:
|
try:
|
||||||
import tomli as tomllib
|
# note: we could use tomli here,
|
||||||
|
# but for backwards compatibility with RHEL 9, we use toml instead
|
||||||
|
import toml as toml_module
|
||||||
|
load_from = io.TextIOWrapper(opened_binary_file, encoding='utf-8')
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
print_err('Import error:', e)
|
print_err('Import error:', e)
|
||||||
# already echoed by the %pyproject_buildrequires macro
|
# already echoed by the %pyproject_buildrequires macro
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
return tomllib.load(opened_binary_file)
|
return toml_module.load(load_from)
|
||||||
|
|
||||||
|
|
||||||
def get_backend(requirements):
|
def get_backend(requirements):
|
||||||
@ -271,30 +285,17 @@ def get_backend(requirements):
|
|||||||
def generate_build_requirements(backend, requirements):
|
def generate_build_requirements(backend, requirements):
|
||||||
get_requires = getattr(backend, 'get_requires_for_build_wheel', None)
|
get_requires = getattr(backend, 'get_requires_for_build_wheel', None)
|
||||||
if get_requires:
|
if get_requires:
|
||||||
new_reqs = get_requires(config_settings=requirements.config_settings)
|
with hook_call():
|
||||||
|
new_reqs = get_requires()
|
||||||
requirements.extend(new_reqs, source='get_requires_for_build_wheel')
|
requirements.extend(new_reqs, source='get_requires_for_build_wheel')
|
||||||
requirements.check(source='get_requires_for_build_wheel')
|
requirements.check(source='get_requires_for_build_wheel')
|
||||||
|
|
||||||
|
|
||||||
def parse_metadata_file(metadata_file):
|
def requires_from_metadata_file(metadata_file):
|
||||||
return email.parser.Parser().parse(metadata_file, headersonly=True)
|
message = email.parser.Parser().parse(metadata_file, headersonly=True)
|
||||||
|
|
||||||
|
|
||||||
def requires_from_parsed_metadata_file(message):
|
|
||||||
return {k: message.get_all(k, ()) for k in ('Requires', 'Requires-Dist')}
|
return {k: message.get_all(k, ()) for k in ('Requires', 'Requires-Dist')}
|
||||||
|
|
||||||
|
|
||||||
def package_name_from_parsed_metadata_file(message):
|
|
||||||
return message.get('name')
|
|
||||||
|
|
||||||
|
|
||||||
def package_name_and_requires_from_metadata_file(metadata_file):
|
|
||||||
message = parse_metadata_file(metadata_file)
|
|
||||||
package_name = package_name_from_parsed_metadata_file(message)
|
|
||||||
requires = requires_from_parsed_metadata_file(message)
|
|
||||||
return package_name, requires
|
|
||||||
|
|
||||||
|
|
||||||
def generate_run_requirements_hook(backend, requirements):
|
def generate_run_requirements_hook(backend, requirements):
|
||||||
hook_name = 'prepare_metadata_for_build_wheel'
|
hook_name = 'prepare_metadata_for_build_wheel'
|
||||||
prepare_metadata = getattr(backend, hook_name, None)
|
prepare_metadata = getattr(backend, hook_name, None)
|
||||||
@ -305,13 +306,11 @@ def generate_run_requirements_hook(backend, requirements):
|
|||||||
'Use the provisional -w flag to build the wheel and parse the metadata from it, '
|
'Use the provisional -w flag to build the wheel and parse the metadata from it, '
|
||||||
'or use the -R flag not to generate runtime dependencies.'
|
'or use the -R flag not to generate runtime dependencies.'
|
||||||
)
|
)
|
||||||
dir_basename = prepare_metadata('.', config_settings=requirements.config_settings)
|
with hook_call():
|
||||||
|
dir_basename = prepare_metadata('.')
|
||||||
with open(dir_basename + '/METADATA') as metadata_file:
|
with open(dir_basename + '/METADATA') as metadata_file:
|
||||||
name, requires = package_name_and_requires_from_metadata_file(metadata_file)
|
for key, requires in requires_from_metadata_file(metadata_file).items():
|
||||||
for key, req in requires.items():
|
requirements.extend(requires, source=f'hook generated metadata: {key}')
|
||||||
requirements.extend(req,
|
|
||||||
package_name=name,
|
|
||||||
source=f'hook generated metadata: {key} ({name})')
|
|
||||||
|
|
||||||
|
|
||||||
def find_built_wheel(wheeldir):
|
def find_built_wheel(wheeldir):
|
||||||
@ -328,17 +327,8 @@ def generate_run_requirements_wheel(backend, requirements, wheeldir):
|
|||||||
# Reuse the wheel from the previous round of %pyproject_buildrequires (if it exists)
|
# Reuse the wheel from the previous round of %pyproject_buildrequires (if it exists)
|
||||||
wheel = find_built_wheel(wheeldir)
|
wheel = find_built_wheel(wheeldir)
|
||||||
if not wheel:
|
if not wheel:
|
||||||
# pip is already echoed from the macro
|
|
||||||
# but we need to explicitly restart if has not yet been installed
|
|
||||||
# see https://bugzilla.redhat.com/2169855
|
|
||||||
requirements.add('pip >= 19', source='%pyproject_buildrequires -w')
|
|
||||||
requirements.check(source='%pyproject_buildrequires -w')
|
|
||||||
import pyproject_wheel
|
import pyproject_wheel
|
||||||
returncode = pyproject_wheel.build_wheel(
|
returncode = pyproject_wheel.build_wheel(wheeldir=wheeldir, stdout=sys.stderr)
|
||||||
wheeldir=wheeldir,
|
|
||||||
stdout=sys.stderr,
|
|
||||||
config_settings=requirements.config_settings,
|
|
||||||
)
|
|
||||||
if returncode != 0:
|
if returncode != 0:
|
||||||
raise RuntimeError('Failed to build the wheel for %pyproject_buildrequires -w.')
|
raise RuntimeError('Failed to build the wheel for %pyproject_buildrequires -w.')
|
||||||
wheel = find_built_wheel(wheeldir)
|
wheel = find_built_wheel(wheeldir)
|
||||||
@ -350,11 +340,8 @@ def generate_run_requirements_wheel(backend, requirements, wheeldir):
|
|||||||
for name in wheelfile.namelist():
|
for name in wheelfile.namelist():
|
||||||
if name.count('/') == 1 and name.endswith('.dist-info/METADATA'):
|
if name.count('/') == 1 and name.endswith('.dist-info/METADATA'):
|
||||||
with io.TextIOWrapper(wheelfile.open(name), encoding='utf-8') as metadata_file:
|
with io.TextIOWrapper(wheelfile.open(name), encoding='utf-8') as metadata_file:
|
||||||
name, requires = package_name_and_requires_from_metadata_file(metadata_file)
|
for key, requires in requires_from_metadata_file(metadata_file).items():
|
||||||
for key, req in requires.items():
|
requirements.extend(requires, source=f'built wheel metadata: {key}')
|
||||||
requirements.extend(req,
|
|
||||||
package_name=name,
|
|
||||||
source=f'built wheel metadata: {key} ({name})')
|
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
raise RuntimeError('Could not find *.dist-info/METADATA in built wheel.')
|
raise RuntimeError('Could not find *.dist-info/METADATA in built wheel.')
|
||||||
@ -391,7 +378,7 @@ def generate_tox_requirements(toxenv, requirements):
|
|||||||
provision_content = provision.read()
|
provision_content = provision.read()
|
||||||
if provision_content and r.returncode != 0:
|
if provision_content and r.returncode != 0:
|
||||||
provision_requires = json.loads(provision_content)
|
provision_requires = json.loads(provision_content)
|
||||||
if provision_requires.get('minversion') is not None:
|
if 'minversion' in provision_requires:
|
||||||
requirements.add(f'tox >= {provision_requires["minversion"]}',
|
requirements.add(f'tox >= {provision_requires["minversion"]}',
|
||||||
source='tox provision (minversion)')
|
source='tox provision (minversion)')
|
||||||
if 'requires' in provision_requires:
|
if 'requires' in provision_requires:
|
||||||
@ -425,20 +412,16 @@ def python3dist(name, op=None, version=None, python3_pkgversion="3"):
|
|||||||
def generate_requires(
|
def generate_requires(
|
||||||
*, include_runtime=False, build_wheel=False, wheeldir=None, toxenv=None, extras=None,
|
*, include_runtime=False, build_wheel=False, wheeldir=None, toxenv=None, extras=None,
|
||||||
get_installed_version=importlib.metadata.version, # for dep injection
|
get_installed_version=importlib.metadata.version, # for dep injection
|
||||||
generate_extras=False, python3_pkgversion="3", requirement_files=None, use_build_system=True,
|
generate_extras=False, python3_pkgversion="3", requirement_files=None, use_build_system=True
|
||||||
output, config_settings=None,
|
|
||||||
):
|
):
|
||||||
"""Generate the BuildRequires for the project in the current directory
|
"""Generate the BuildRequires for the project in the current directory
|
||||||
|
|
||||||
The generated BuildRequires are written to the provided output.
|
|
||||||
|
|
||||||
This is the main Python entry point.
|
This is the main Python entry point.
|
||||||
"""
|
"""
|
||||||
requirements = Requirements(
|
requirements = Requirements(
|
||||||
get_installed_version, extras=extras or [],
|
get_installed_version, extras=extras or [],
|
||||||
generate_extras=generate_extras,
|
generate_extras=generate_extras,
|
||||||
python3_pkgversion=python3_pkgversion,
|
python3_pkgversion=python3_pkgversion
|
||||||
config_settings=config_settings,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -461,8 +444,6 @@ def generate_requires(
|
|||||||
generate_run_requirements(backend, requirements, build_wheel=build_wheel, wheeldir=wheeldir)
|
generate_run_requirements(backend, requirements, build_wheel=build_wheel, wheeldir=wheeldir)
|
||||||
except EndPass:
|
except EndPass:
|
||||||
return
|
return
|
||||||
finally:
|
|
||||||
output.write_text(os.linesep.join(requirements.output_lines) + os.linesep)
|
|
||||||
|
|
||||||
|
|
||||||
def main(argv):
|
def main(argv):
|
||||||
@ -488,9 +469,6 @@ def main(argv):
|
|||||||
'-p', '--python3_pkgversion', metavar='PYTHON3_PKGVERSION',
|
'-p', '--python3_pkgversion', metavar='PYTHON3_PKGVERSION',
|
||||||
default="3", help=argparse.SUPPRESS,
|
default="3", help=argparse.SUPPRESS,
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
|
||||||
'--output', type=pathlib.Path, required=True, help=argparse.SUPPRESS,
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--wheeldir', metavar='PATH', default=None,
|
'--wheeldir', metavar='PATH', default=None,
|
||||||
help=argparse.SUPPRESS,
|
help=argparse.SUPPRESS,
|
||||||
@ -528,12 +506,6 @@ def main(argv):
|
|||||||
metavar='REQUIREMENTS.TXT',
|
metavar='REQUIREMENTS.TXT',
|
||||||
help=('Add buildrequires from file'),
|
help=('Add buildrequires from file'),
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
|
||||||
'-C',
|
|
||||||
dest='config_settings',
|
|
||||||
action='append',
|
|
||||||
help='Configuration settings to pass to the PEP 517 backend',
|
|
||||||
)
|
|
||||||
|
|
||||||
args = parser.parse_args(argv)
|
args = parser.parse_args(argv)
|
||||||
|
|
||||||
@ -567,8 +539,6 @@ def main(argv):
|
|||||||
python3_pkgversion=args.python3_pkgversion,
|
python3_pkgversion=args.python3_pkgversion,
|
||||||
requirement_files=args.requirement_files,
|
requirement_files=args.requirement_files,
|
||||||
use_build_system=args.use_build_system,
|
use_build_system=args.use_build_system,
|
||||||
output=args.output,
|
|
||||||
config_settings=parse_config_settings_args(args.config_settings),
|
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
# Log the traceback explicitly (it's useful debug info)
|
# Log the traceback explicitly (it's useful debug info)
|
||||||
|
@ -17,7 +17,7 @@ Insufficient version of setuptools:
|
|||||||
installed:
|
installed:
|
||||||
setuptools: 5
|
setuptools: 5
|
||||||
wheel: 1
|
wheel: 1
|
||||||
tomli: 1
|
toml: 1
|
||||||
pyproject.toml: |
|
pyproject.toml: |
|
||||||
# empty
|
# empty
|
||||||
setup.py: |
|
setup.py: |
|
||||||
@ -42,7 +42,7 @@ Default build system, empty setup.py:
|
|||||||
installed:
|
installed:
|
||||||
setuptools: 50
|
setuptools: 50
|
||||||
wheel: 1
|
wheel: 1
|
||||||
tomli: 1
|
toml: 1
|
||||||
include_runtime: false
|
include_runtime: false
|
||||||
pyproject.toml: |
|
pyproject.toml: |
|
||||||
# empty
|
# empty
|
||||||
@ -58,7 +58,7 @@ pyproject.toml with build-backend and setup.py:
|
|||||||
installed:
|
installed:
|
||||||
setuptools: 50
|
setuptools: 50
|
||||||
wheel: 1
|
wheel: 1
|
||||||
tomli: 1
|
toml: 1
|
||||||
setup.py: |
|
setup.py: |
|
||||||
# empty
|
# empty
|
||||||
pyproject.toml: |
|
pyproject.toml: |
|
||||||
@ -81,7 +81,7 @@ Erroring setup.py:
|
|||||||
|
|
||||||
Bad character in version:
|
Bad character in version:
|
||||||
installed:
|
installed:
|
||||||
tomli: 1
|
toml: 1
|
||||||
pyproject.toml: |
|
pyproject.toml: |
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["pkg == 0.$.^.*"]
|
requires = ["pkg == 0.$.^.*"]
|
||||||
@ -89,7 +89,7 @@ Bad character in version:
|
|||||||
|
|
||||||
Single value version with unsupported compatible operator:
|
Single value version with unsupported compatible operator:
|
||||||
installed:
|
installed:
|
||||||
tomli: 1
|
toml: 1
|
||||||
pyproject.toml: |
|
pyproject.toml: |
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["pkg ~= 42", "foo"]
|
requires = ["pkg ~= 42", "foo"]
|
||||||
@ -98,7 +98,7 @@ Single value version with unsupported compatible operator:
|
|||||||
|
|
||||||
Asterisk in version with unsupported compatible operator:
|
Asterisk in version with unsupported compatible operator:
|
||||||
installed:
|
installed:
|
||||||
tomli: 1
|
toml: 1
|
||||||
pyproject.toml: |
|
pyproject.toml: |
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["pkg ~= 0.1.*", "foo"]
|
requires = ["pkg ~= 0.1.*", "foo"]
|
||||||
@ -107,7 +107,7 @@ Asterisk in version with unsupported compatible operator:
|
|||||||
|
|
||||||
Local path as requirement:
|
Local path as requirement:
|
||||||
installed:
|
installed:
|
||||||
tomli: 1
|
toml: 1
|
||||||
pyproject.toml: |
|
pyproject.toml: |
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["./pkg-1.2.3.tar.gz", "foo"]
|
requires = ["./pkg-1.2.3.tar.gz", "foo"]
|
||||||
@ -116,7 +116,7 @@ Local path as requirement:
|
|||||||
|
|
||||||
Pip's egg=pkgName requirement not in requirements file:
|
Pip's egg=pkgName requirement not in requirements file:
|
||||||
installed:
|
installed:
|
||||||
tomli: 1
|
toml: 1
|
||||||
pyproject.toml: |
|
pyproject.toml: |
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["git+https://github.com/monty/spam.git@master#egg=spam", "foo"]
|
requires = ["git+https://github.com/monty/spam.git@master#egg=spam", "foo"]
|
||||||
@ -125,7 +125,7 @@ Pip's egg=pkgName requirement not in requirements file:
|
|||||||
|
|
||||||
URL without egg fragment as requirement:
|
URL without egg fragment as requirement:
|
||||||
installed:
|
installed:
|
||||||
tomli: 1
|
toml: 1
|
||||||
pyproject.toml: |
|
pyproject.toml: |
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["git+https://github.com/pkg-dev/pkg.git@96dbe5e3", "foo"]
|
requires = ["git+https://github.com/pkg-dev/pkg.git@96dbe5e3", "foo"]
|
||||||
@ -137,7 +137,7 @@ Build system dependencies in pyproject.toml with extras:
|
|||||||
installed:
|
installed:
|
||||||
setuptools: 50
|
setuptools: 50
|
||||||
wheel: 1
|
wheel: 1
|
||||||
tomli: 1
|
toml: 1
|
||||||
pyproject.toml: |
|
pyproject.toml: |
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = [
|
requires = [
|
||||||
@ -186,7 +186,7 @@ Build system dependencies in pyproject.toml without extras:
|
|||||||
installed:
|
installed:
|
||||||
setuptools: 50
|
setuptools: 50
|
||||||
wheel: 1
|
wheel: 1
|
||||||
tomli: 1
|
toml: 1
|
||||||
pyproject.toml: |
|
pyproject.toml: |
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = [
|
requires = [
|
||||||
@ -365,7 +365,6 @@ Run dependencies with extras and build wheel option:
|
|||||||
setuptools: 50
|
setuptools: 50
|
||||||
wheel: 1
|
wheel: 1
|
||||||
pyyaml: 1
|
pyyaml: 1
|
||||||
pip: 20
|
|
||||||
include_runtime: true
|
include_runtime: true
|
||||||
build_wheel: true
|
build_wheel: true
|
||||||
extras:
|
extras:
|
||||||
@ -376,7 +375,6 @@ Run dependencies with extras and build wheel option:
|
|||||||
python3dist(wheel)
|
python3dist(wheel)
|
||||||
python3dist(wheel)
|
python3dist(wheel)
|
||||||
python3dist(setuptools) >= 40
|
python3dist(setuptools) >= 40
|
||||||
python3dist(pip) >= 19
|
|
||||||
python3dist(py) >= 1.5
|
python3dist(py) >= 1.5
|
||||||
python3dist(six) >= 1.10
|
python3dist(six) >= 1.10
|
||||||
python3dist(setuptools)
|
python3dist(setuptools)
|
||||||
@ -391,7 +389,7 @@ Run dependencies with extras and build wheel option:
|
|||||||
result: 0
|
result: 0
|
||||||
stderr_contains: "Reading metadata from {wheeldir}/pytest-6.6.6-py3-none-any.whl"
|
stderr_contains: "Reading metadata from {wheeldir}/pytest-6.6.6-py3-none-any.whl"
|
||||||
|
|
||||||
tox dependencies:
|
Tox dependencies:
|
||||||
installed:
|
installed:
|
||||||
setuptools: 50
|
setuptools: 50
|
||||||
wheel: 1
|
wheel: 1
|
||||||
@ -435,7 +433,7 @@ tox dependencies:
|
|||||||
python3dist(inst)
|
python3dist(inst)
|
||||||
result: 0
|
result: 0
|
||||||
|
|
||||||
tox extras:
|
Tox extras:
|
||||||
installed:
|
installed:
|
||||||
setuptools: 50
|
setuptools: 50
|
||||||
wheel: 1
|
wheel: 1
|
||||||
@ -499,7 +497,7 @@ tox extras:
|
|||||||
python3dist(extra-dep[extra_dep])
|
python3dist(extra-dep[extra_dep])
|
||||||
result: 0
|
result: 0
|
||||||
|
|
||||||
tox provision unsatisfied:
|
Tox provision unsatisfied:
|
||||||
installed:
|
installed:
|
||||||
setuptools: 50
|
setuptools: 50
|
||||||
wheel: 1
|
wheel: 1
|
||||||
@ -544,7 +542,7 @@ tox provision unsatisfied:
|
|||||||
python3dist(tox) >= 3.999
|
python3dist(tox) >= 3.999
|
||||||
result: 0
|
result: 0
|
||||||
|
|
||||||
tox provision satisfied:
|
Tox provision satisfied:
|
||||||
installed:
|
installed:
|
||||||
setuptools: 50
|
setuptools: 50
|
||||||
wheel: 1
|
wheel: 1
|
||||||
@ -591,43 +589,6 @@ tox provision satisfied:
|
|||||||
python3dist(inst)
|
python3dist(inst)
|
||||||
result: 0
|
result: 0
|
||||||
|
|
||||||
tox provision no minversion:
|
|
||||||
installed:
|
|
||||||
setuptools: 50
|
|
||||||
wheel: 1
|
|
||||||
tox: 3.5.3
|
|
||||||
tox-current-env: 0.0.6
|
|
||||||
toxenv:
|
|
||||||
- py3
|
|
||||||
setup.py: |
|
|
||||||
from setuptools import setup
|
|
||||||
setup(
|
|
||||||
name='test',
|
|
||||||
version='0.1',
|
|
||||||
)
|
|
||||||
tox.ini: |
|
|
||||||
[tox]
|
|
||||||
requires =
|
|
||||||
setuptools > 40
|
|
||||||
wheel > 2
|
|
||||||
expected:
|
|
||||||
- | # tox 3
|
|
||||||
python3dist(setuptools) >= 40.8
|
|
||||||
python3dist(wheel)
|
|
||||||
python3dist(wheel)
|
|
||||||
python3dist(tox-current-env) >= 0.0.6
|
|
||||||
python3dist(setuptools) > 40.0
|
|
||||||
python3dist(wheel) > 2.0
|
|
||||||
- | # tox 4
|
|
||||||
python3dist(setuptools) >= 40.8
|
|
||||||
python3dist(wheel)
|
|
||||||
python3dist(wheel)
|
|
||||||
python3dist(tox-current-env) >= 0.0.6
|
|
||||||
python3dist(setuptools) > 40.0
|
|
||||||
python3dist(wheel) > 2.0
|
|
||||||
python3dist(tox)
|
|
||||||
result: 0
|
|
||||||
|
|
||||||
Default build system, unmet deps in requirements file:
|
Default build system, unmet deps in requirements file:
|
||||||
installed:
|
installed:
|
||||||
setuptools: 50
|
setuptools: 50
|
||||||
@ -693,7 +654,7 @@ With pyproject.toml, requirements file and with -N option:
|
|||||||
installed:
|
installed:
|
||||||
setuptools: 50
|
setuptools: 50
|
||||||
wheel: 1
|
wheel: 1
|
||||||
tomli: 1
|
toml: 1
|
||||||
lxml: 3.9
|
lxml: 3.9
|
||||||
ncclient: 1
|
ncclient: 1
|
||||||
cryptography: 2
|
cryptography: 2
|
||||||
@ -729,7 +690,7 @@ With pyproject.toml, requirements file and without -N option:
|
|||||||
installed:
|
installed:
|
||||||
setuptools: 50
|
setuptools: 50
|
||||||
wheel: 1
|
wheel: 1
|
||||||
tomli: 1
|
toml: 1
|
||||||
lxml: 3.9
|
lxml: 3.9
|
||||||
ncclient: 1
|
ncclient: 1
|
||||||
cryptography: 2
|
cryptography: 2
|
||||||
@ -840,7 +801,7 @@ Pre-releases are accepted:
|
|||||||
installed:
|
installed:
|
||||||
setuptools: 50
|
setuptools: 50
|
||||||
wheel: 1
|
wheel: 1
|
||||||
tomli: 1
|
toml: 1
|
||||||
cffi: 1.15.0rc2
|
cffi: 1.15.0rc2
|
||||||
pyproject.toml: |
|
pyproject.toml: |
|
||||||
[build-system]
|
[build-system]
|
||||||
@ -859,7 +820,7 @@ Pre-releases are accepted:
|
|||||||
result: 0
|
result: 0
|
||||||
|
|
||||||
|
|
||||||
Stdout from wrapped subprocess does not appear in output:
|
Wrapped subprocess prints to stdout from setup.py:
|
||||||
installed:
|
installed:
|
||||||
setuptools: 50
|
setuptools: 50
|
||||||
wheel: 1
|
wheel: 1
|
||||||
@ -873,192 +834,5 @@ Stdout from wrapped subprocess does not appear in output:
|
|||||||
python3dist(setuptools) >= 40.8
|
python3dist(setuptools) >= 40.8
|
||||||
python3dist(wheel)
|
python3dist(wheel)
|
||||||
python3dist(wheel)
|
python3dist(wheel)
|
||||||
result: 0
|
stderr_contains: "HOOK STDOUT: LEAK?"
|
||||||
|
|
||||||
pyproject.toml with runtime dependencies:
|
|
||||||
skipif: not SETUPTOOLS_60
|
|
||||||
installed:
|
|
||||||
setuptools: 50
|
|
||||||
wheel: 1
|
|
||||||
tomli: 1
|
|
||||||
pyproject.toml: |
|
|
||||||
[build-system]
|
|
||||||
requires = ["setuptools"]
|
|
||||||
build-backend = "setuptools.build_meta"
|
|
||||||
[project]
|
|
||||||
name = "my_package"
|
|
||||||
version = "0.1"
|
|
||||||
dependencies = [
|
|
||||||
"foo",
|
|
||||||
'importlib-metadata; python_version<"3.8"',
|
|
||||||
]
|
|
||||||
expected: |
|
|
||||||
python3dist(setuptools)
|
|
||||||
python3dist(wheel)
|
|
||||||
python3dist(foo)
|
|
||||||
result: 0
|
|
||||||
|
|
||||||
pyproject.toml with runtime dependencies and partially selected extras:
|
|
||||||
skipif: not SETUPTOOLS_60
|
|
||||||
installed:
|
|
||||||
setuptools: 50
|
|
||||||
wheel: 1
|
|
||||||
tomli: 1
|
|
||||||
extras:
|
|
||||||
- tests
|
|
||||||
pyproject.toml: |
|
|
||||||
[build-system]
|
|
||||||
requires = ["setuptools"]
|
|
||||||
build-backend = "setuptools.build_meta"
|
|
||||||
[project]
|
|
||||||
name = "my_package"
|
|
||||||
version = "0.1"
|
|
||||||
dependencies = [
|
|
||||||
"foo",
|
|
||||||
'importlib-metadata; python_version<"3.8"',
|
|
||||||
]
|
|
||||||
[project.optional-dependencies]
|
|
||||||
tests = ["pytest>=5", "pytest-mock"]
|
|
||||||
docs = ["sphinx", "python-docs-theme"]
|
|
||||||
expected: |
|
|
||||||
python3dist(setuptools)
|
|
||||||
python3dist(wheel)
|
|
||||||
python3dist(foo)
|
|
||||||
python3dist(pytest) >= 5
|
|
||||||
python3dist(pytest-mock)
|
|
||||||
result: 0
|
|
||||||
|
|
||||||
Self-referencing extras (sooner):
|
|
||||||
installed:
|
|
||||||
setuptools: 50
|
|
||||||
wheel: 1
|
|
||||||
tomli: 1
|
|
||||||
extras:
|
|
||||||
- dev # this is deliberately sooner in the alphabet than the referenced ones
|
|
||||||
pyproject.toml: |
|
|
||||||
[build-system]
|
|
||||||
requires = ["setuptools"]
|
|
||||||
build-backend = "setuptools.build_meta"
|
|
||||||
setup.cfg: |
|
|
||||||
[metadata]
|
|
||||||
name = my_package
|
|
||||||
version = 0.1
|
|
||||||
[options]
|
|
||||||
install_requires =
|
|
||||||
foo
|
|
||||||
importlib-metadata; python_version<"3.8"
|
|
||||||
[options.extras_require]
|
|
||||||
tests = pytest>=5; pytest-mock
|
|
||||||
docs = sphinx; python-docs-theme
|
|
||||||
dev = my_package[docs,tests]
|
|
||||||
expected: |
|
|
||||||
python3dist(setuptools)
|
|
||||||
python3dist(wheel)
|
|
||||||
python3dist(foo)
|
|
||||||
python3dist(sphinx)
|
|
||||||
python3dist(python-docs-theme)
|
|
||||||
python3dist(pytest) >= 5
|
|
||||||
python3dist(pytest-mock)
|
|
||||||
result: 0
|
|
||||||
|
|
||||||
Self-referencing extras (later):
|
|
||||||
installed:
|
|
||||||
setuptools: 50
|
|
||||||
wheel: 1
|
|
||||||
tomli: 1
|
|
||||||
extras:
|
|
||||||
- xdev # this is deliberately later in the alphabet than the referenced ones
|
|
||||||
pyproject.toml: |
|
|
||||||
[build-system]
|
|
||||||
requires = ["setuptools"]
|
|
||||||
build-backend = "setuptools.build_meta"
|
|
||||||
setup.cfg: |
|
|
||||||
[metadata]
|
|
||||||
name = my_package
|
|
||||||
version = 0.1
|
|
||||||
[options]
|
|
||||||
install_requires =
|
|
||||||
foo
|
|
||||||
importlib-metadata; python_version<"3.8"
|
|
||||||
[options.extras_require]
|
|
||||||
tests = pytest>=5; pytest-mock
|
|
||||||
docs = sphinx; python-docs-theme
|
|
||||||
xdev = my_package[docs,tests]
|
|
||||||
expected: |
|
|
||||||
python3dist(setuptools)
|
|
||||||
python3dist(wheel)
|
|
||||||
python3dist(foo)
|
|
||||||
python3dist(sphinx)
|
|
||||||
python3dist(python-docs-theme)
|
|
||||||
python3dist(pytest) >= 5
|
|
||||||
python3dist(pytest-mock)
|
|
||||||
result: 0
|
|
||||||
|
|
||||||
Self-referencing extras (maze):
|
|
||||||
installed:
|
|
||||||
setuptools: 50
|
|
||||||
wheel: 1
|
|
||||||
tomli: 1
|
|
||||||
extras:
|
|
||||||
- start
|
|
||||||
pyproject.toml: |
|
|
||||||
[build-system]
|
|
||||||
requires = ["setuptools"]
|
|
||||||
build-backend = "setuptools.build_meta"
|
|
||||||
setup.cfg: |
|
|
||||||
[metadata]
|
|
||||||
name = my_package
|
|
||||||
version = 0.1
|
|
||||||
[options.extras_require]
|
|
||||||
start = my_package[left,right]; startdep
|
|
||||||
left = my_package[right,forward]; leftdep
|
|
||||||
right = my_package[left,forward]; rightdep
|
|
||||||
forward = my_package[backward]; forwarddep
|
|
||||||
backward = my_package[left,right]; backwarddep
|
|
||||||
never = my_package[forward]; neverdep
|
|
||||||
expected: |
|
|
||||||
python3dist(setuptools)
|
|
||||||
python3dist(wheel)
|
|
||||||
python3dist(backwarddep)
|
|
||||||
python3dist(forwarddep)
|
|
||||||
python3dist(leftdep)
|
|
||||||
python3dist(rightdep)
|
|
||||||
python3dist(startdep)
|
|
||||||
result: 0
|
|
||||||
|
|
||||||
config_settings_control:
|
|
||||||
include_runtime: false
|
|
||||||
config_settings:
|
|
||||||
pyproject.toml: |
|
|
||||||
[build-system]
|
|
||||||
build-backend = "test_backend"
|
|
||||||
backend-path = ["."]
|
|
||||||
test_backend.py: |
|
|
||||||
def get_requires_for_build_wheel(config_settings=None):
|
|
||||||
if not (config_settings is None or isinstance(config_settings, dict)):
|
|
||||||
raise TypeError
|
|
||||||
if config_settings and "test-config-setting" in config_settings:
|
|
||||||
return ["test-config-setting"]
|
|
||||||
return ["test-no-config-setting"]
|
|
||||||
expected: |
|
|
||||||
python3dist(test-no-config-setting)
|
|
||||||
result: 0
|
|
||||||
|
|
||||||
config_settings:
|
|
||||||
include_runtime: false
|
|
||||||
config_settings:
|
|
||||||
test-config-setting: ""
|
|
||||||
pyproject.toml: |
|
|
||||||
[build-system]
|
|
||||||
build-backend = "test_backend"
|
|
||||||
backend-path = ["."]
|
|
||||||
test_backend.py: |
|
|
||||||
def get_requires_for_build_wheel(config_settings=None):
|
|
||||||
if not (config_settings is None or isinstance(config_settings, dict)):
|
|
||||||
raise TypeError
|
|
||||||
if config_settings and "test-config-setting" in config_settings:
|
|
||||||
return ["test-config-setting"]
|
|
||||||
return ["test-no-config-setting"]
|
|
||||||
expected: |
|
|
||||||
python3dist(test-config-setting)
|
|
||||||
result: 0
|
result: 0
|
||||||
|
@ -12,9 +12,6 @@ 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'
|
||||||
|
|
||||||
# See the comment in the macro that wraps this script
|
|
||||||
RPM_PERCENTAGES_COUNT = int(os.getenv('RPM_PERCENTAGES_COUNT', '2'))
|
|
||||||
|
|
||||||
# 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 :(
|
||||||
# There is an issue for RPM to provide the lists as macros:
|
# There is an issue for RPM to provide the lists as macros:
|
||||||
@ -345,7 +342,7 @@ def classify_paths(
|
|||||||
}
|
}
|
||||||
|
|
||||||
license_files = metadata.get_all('License-File')
|
license_files = metadata.get_all('License-File')
|
||||||
license_directory = distinfo / 'licenses' # See PEP 639 "Root License Directory"
|
license_directory = distinfo / 'licenses' # See PEP 369 "Root License Directory"
|
||||||
# setuptools was the first known build backend to implement License-File.
|
# setuptools was the first known build backend to implement License-File.
|
||||||
# Unfortunately they don't put licenses to the license directory (yet):
|
# Unfortunately they don't put licenses to the license directory (yet):
|
||||||
# https://github.com/pypa/setuptools/issues/3596
|
# https://github.com/pypa/setuptools/issues/3596
|
||||||
@ -444,13 +441,13 @@ def escape_rpm_path(path):
|
|||||||
'"/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('/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('/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('/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('/usr/share/data/spaces and "quotes"')
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
@ -464,7 +461,10 @@ def escape_rpm_path(path):
|
|||||||
"""
|
"""
|
||||||
orig_path = path = str(path)
|
orig_path = path = str(path)
|
||||||
if "%" in path:
|
if "%" in path:
|
||||||
path = path.replace("%", "%" * RPM_PERCENTAGES_COUNT)
|
# Escaping by 8 %s has been verified in RPM 4.16 and 4.17, but probably not stable
|
||||||
|
# See this thread http://lists.rpm.org/pipermail/rpm-list/2021-June/002048.html
|
||||||
|
# On the CI, we build tests/escape_percentages.spec to verify this assumption
|
||||||
|
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 cannot list such file individually
|
||||||
@ -673,7 +673,7 @@ def load_parsed_record(pyproject_record):
|
|||||||
content = json.load(pyproject_record_file)
|
content = json.load(pyproject_record_file)
|
||||||
|
|
||||||
if len(content) > 1:
|
if len(content) > 1:
|
||||||
raise FileExistsError("%pyproject_install has found more than one *.dist-info/RECORD file. "
|
raise FileExistsError("%pyproject install has found more than one *.dist-info/RECORD file. "
|
||||||
"Currently, %pyproject_save_files supports only one wheel → one file list mapping. "
|
"Currently, %pyproject_save_files supports only one wheel → one file list mapping. "
|
||||||
"Feel free to open a bugzilla for pyproject-rpm-macros and describe your usecase.")
|
"Feel free to open a bugzilla for pyproject-rpm-macros and describe your usecase.")
|
||||||
|
|
||||||
@ -693,15 +693,12 @@ def dist_metadata(buildroot, record_path):
|
|||||||
return dist.metadata
|
return dist.metadata
|
||||||
|
|
||||||
|
|
||||||
def pyproject_save_files_and_modules(buildroot, sitelib, sitearch, python_version, pyproject_record, prefix, assert_license, varargs):
|
def pyproject_save_files_and_modules(buildroot, sitelib, sitearch, python_version, pyproject_record, prefix, varargs):
|
||||||
"""
|
"""
|
||||||
Takes arguments from the %{pyproject_save_files} macro
|
Takes arguments from the %{pyproject_save_files} macro
|
||||||
|
|
||||||
Returns tuple: list of paths for the %files section and list of module names
|
Returns tuple: list of paths for the %files section and list of module names
|
||||||
for the %check section
|
for the %check section
|
||||||
|
|
||||||
Raises ValueError when assert_license is true and no License-File (PEP 639)
|
|
||||||
is found.
|
|
||||||
"""
|
"""
|
||||||
# On 32 bit architectures, sitelib equals to sitearch
|
# On 32 bit architectures, sitelib equals to sitearch
|
||||||
# This saves us browsing one directory twice
|
# This saves us browsing one directory twice
|
||||||
@ -713,15 +710,11 @@ def pyproject_save_files_and_modules(buildroot, sitelib, sitearch, python_versio
|
|||||||
final_file_list = []
|
final_file_list = []
|
||||||
final_module_list = []
|
final_module_list = []
|
||||||
|
|
||||||
# we assume OK when not asserting
|
|
||||||
license_ok = not assert_license
|
|
||||||
|
|
||||||
for record_path, files in parsed_records.items():
|
for record_path, files in parsed_records.items():
|
||||||
metadata = dist_metadata(buildroot, record_path)
|
metadata = dist_metadata(buildroot, record_path)
|
||||||
paths_dict = classify_paths(
|
paths_dict = classify_paths(
|
||||||
record_path, files, metadata, sitedirs, python_version, prefix
|
record_path, files, metadata, sitedirs, python_version, prefix
|
||||||
)
|
)
|
||||||
license_ok = license_ok or bool(paths_dict["metadata"]["licenses"])
|
|
||||||
|
|
||||||
final_file_list.extend(
|
final_file_list.extend(
|
||||||
generate_file_list(paths_dict, globs, include_auto)
|
generate_file_list(paths_dict, globs, include_auto)
|
||||||
@ -730,15 +723,6 @@ def pyproject_save_files_and_modules(buildroot, sitelib, sitearch, python_versio
|
|||||||
generate_module_list(paths_dict, globs)
|
generate_module_list(paths_dict, globs)
|
||||||
)
|
)
|
||||||
|
|
||||||
if not license_ok:
|
|
||||||
raise ValueError(
|
|
||||||
"No License-File (PEP 639) in upstream metadata found. "
|
|
||||||
"Adjust the upstream metadata "
|
|
||||||
"if the project's build backend supports PEP 639 "
|
|
||||||
"or use `%pyproject_save_files -L` "
|
|
||||||
"and include the %license file in %files manually."
|
|
||||||
)
|
|
||||||
|
|
||||||
return final_file_list, final_module_list
|
return final_file_list, final_module_list
|
||||||
|
|
||||||
|
|
||||||
@ -750,7 +734,6 @@ def main(cli_args):
|
|||||||
cli_args.python_version,
|
cli_args.python_version,
|
||||||
cli_args.pyproject_record,
|
cli_args.pyproject_record,
|
||||||
cli_args.prefix,
|
cli_args.prefix,
|
||||||
cli_args.assert_license,
|
|
||||||
cli_args.varargs,
|
cli_args.varargs,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -764,7 +747,7 @@ def argparser():
|
|||||||
prog="%pyproject_save_files",
|
prog="%pyproject_save_files",
|
||||||
add_help=False,
|
add_help=False,
|
||||||
# custom usage to add +auto
|
# custom usage to add +auto
|
||||||
usage="%(prog)s [-l|-L] MODULE_GLOB [MODULE_GLOB ...] [+auto]",
|
usage="%(prog)s MODULE_GLOB [MODULE_GLOB ...] [+auto]",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--help', action='help',
|
'--help', action='help',
|
||||||
@ -780,14 +763,6 @@ def argparser():
|
|||||||
r.add_argument("--python-version", type=str, required=True, help=argparse.SUPPRESS)
|
r.add_argument("--python-version", type=str, required=True, help=argparse.SUPPRESS)
|
||||||
r.add_argument("--pyproject-record", type=PosixPath, required=True, help=argparse.SUPPRESS)
|
r.add_argument("--pyproject-record", type=PosixPath, required=True, help=argparse.SUPPRESS)
|
||||||
r.add_argument("--prefix", type=PosixPath, required=True, help=argparse.SUPPRESS)
|
r.add_argument("--prefix", type=PosixPath, required=True, help=argparse.SUPPRESS)
|
||||||
parser.add_argument(
|
|
||||||
"-l", "--assert-license", action="store_true", default=False,
|
|
||||||
help="Fail when no License-File (PEP 639) is found.",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"-L", "--no-assert-license", action="store_false", dest="assert_license",
|
|
||||||
help="Don't fail when no License-File (PEP 639) is found (the default).",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"varargs", nargs="+", metavar="MODULE_GLOB",
|
"varargs", nargs="+", metavar="MODULE_GLOB",
|
||||||
help="Shell-like glob matching top-level module names to save into %%{pyproject_files}",
|
help="Shell-like glob matching top-level module names to save into %%{pyproject_files}",
|
||||||
|
@ -1,46 +1,8 @@
|
|||||||
import argparse
|
|
||||||
import sys
|
import sys
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
def parse_config_settings_args(config_settings):
|
def build_wheel(*, wheeldir, stdout=None):
|
||||||
"""
|
|
||||||
Given a list of config `KEY=VALUE` formatted config settings,
|
|
||||||
return a dictionary that can be passed to PEP 517 hook functions.
|
|
||||||
"""
|
|
||||||
if not config_settings:
|
|
||||||
return config_settings
|
|
||||||
new_config_settings = {}
|
|
||||||
for arg in config_settings:
|
|
||||||
key, _, value = arg.partition('=')
|
|
||||||
if key in new_config_settings:
|
|
||||||
if not isinstance(new_config_settings[key], list):
|
|
||||||
# convert the existing value to a list
|
|
||||||
new_config_settings[key] = [new_config_settings[key]]
|
|
||||||
new_config_settings[key].append(value)
|
|
||||||
else:
|
|
||||||
new_config_settings[key] = value
|
|
||||||
return new_config_settings
|
|
||||||
|
|
||||||
|
|
||||||
def get_config_settings_args(config_settings):
|
|
||||||
"""
|
|
||||||
Given a dictionary of PEP 517 backend config_settings,
|
|
||||||
yield --config-settings args that can be passed to pip's CLI
|
|
||||||
"""
|
|
||||||
if not config_settings:
|
|
||||||
return
|
|
||||||
for key, values in config_settings.items():
|
|
||||||
if not isinstance(values, list):
|
|
||||||
values = [values]
|
|
||||||
for value in values:
|
|
||||||
if value == '':
|
|
||||||
yield f'--config-settings={key}'
|
|
||||||
else:
|
|
||||||
yield f'--config-settings={key}={value}'
|
|
||||||
|
|
||||||
|
|
||||||
def build_wheel(*, wheeldir, stdout=None, config_settings=None):
|
|
||||||
command = (
|
command = (
|
||||||
sys.executable,
|
sys.executable,
|
||||||
'-m', 'pip',
|
'-m', 'pip',
|
||||||
@ -53,26 +15,11 @@ def build_wheel(*, wheeldir, stdout=None, config_settings=None):
|
|||||||
'--no-clean',
|
'--no-clean',
|
||||||
'--progress-bar', 'off',
|
'--progress-bar', 'off',
|
||||||
'--verbose',
|
'--verbose',
|
||||||
*get_config_settings_args(config_settings),
|
|
||||||
'.',
|
'.',
|
||||||
)
|
)
|
||||||
cp = subprocess.run(command, stdout=stdout)
|
cp = subprocess.run(command, stdout=stdout)
|
||||||
return cp.returncode
|
return cp.returncode
|
||||||
|
|
||||||
|
|
||||||
def parse_args(argv=None):
|
|
||||||
parser = argparse.ArgumentParser(prog='%pyproject_wheel')
|
|
||||||
parser.add_argument('wheeldir', help=argparse.SUPPRESS)
|
|
||||||
parser.add_argument(
|
|
||||||
'-C',
|
|
||||||
dest='config_settings',
|
|
||||||
action='append',
|
|
||||||
help='Configuration settings to pass to the PEP 517 backend',
|
|
||||||
)
|
|
||||||
args = parser.parse_args(argv)
|
|
||||||
args.config_settings = parse_config_settings_args(args.config_settings)
|
|
||||||
return args
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
sys.exit(build_wheel(**vars(parse_args())))
|
sys.exit(build_wheel(wheeldir=sys.argv[1]))
|
||||||
|
@ -1,15 +1,11 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import importlib.metadata
|
import importlib.metadata
|
||||||
|
|
||||||
import packaging.version
|
|
||||||
import pytest
|
import pytest
|
||||||
import setuptools
|
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from pyproject_buildrequires import generate_requires
|
from pyproject_buildrequires import generate_requires
|
||||||
|
|
||||||
SETUPTOOLS_VERSION = packaging.version.parse(setuptools.__version__)
|
|
||||||
SETUPTOOLS_60 = SETUPTOOLS_VERSION >= packaging.version.parse('60')
|
|
||||||
|
|
||||||
testcases = {}
|
testcases = {}
|
||||||
with Path(__file__).parent.joinpath('pyproject_buildrequires_testcases.yaml').open() as f:
|
with Path(__file__).parent.joinpath('pyproject_buildrequires_testcases.yaml').open() as f:
|
||||||
@ -25,16 +21,12 @@ def test_data(case_name, capfd, tmp_path, monkeypatch):
|
|||||||
monkeypatch.chdir(cwd)
|
monkeypatch.chdir(cwd)
|
||||||
wheeldir = cwd.joinpath('wheeldir')
|
wheeldir = cwd.joinpath('wheeldir')
|
||||||
wheeldir.mkdir()
|
wheeldir.mkdir()
|
||||||
output = tmp_path.joinpath('output.txt')
|
|
||||||
|
|
||||||
if case.get('xfail'):
|
if case.get('xfail'):
|
||||||
pytest.xfail(case.get('xfail'))
|
pytest.xfail(case.get('xfail'))
|
||||||
|
|
||||||
if case.get('skipif') and eval(case.get('skipif')):
|
|
||||||
pytest.skip(case.get('skipif'))
|
|
||||||
|
|
||||||
for filename in case:
|
for filename in case:
|
||||||
file_types = ('.toml', '.py', '.in', '.ini', '.txt', '.cfg')
|
file_types = ('.toml', '.py', '.in', '.ini', '.txt')
|
||||||
if filename.endswith(file_types):
|
if filename.endswith(file_types):
|
||||||
cwd.joinpath(filename).write_text(case[filename])
|
cwd.joinpath(filename).write_text(case[filename])
|
||||||
|
|
||||||
@ -62,8 +54,6 @@ def test_data(case_name, capfd, tmp_path, monkeypatch):
|
|||||||
generate_extras=case.get('generate_extras', False),
|
generate_extras=case.get('generate_extras', False),
|
||||||
requirement_files=requirement_files,
|
requirement_files=requirement_files,
|
||||||
use_build_system=use_build_system,
|
use_build_system=use_build_system,
|
||||||
output=output,
|
|
||||||
config_settings=case.get('config_settings'),
|
|
||||||
)
|
)
|
||||||
except SystemExit as e:
|
except SystemExit as e:
|
||||||
assert e.code == case['result']
|
assert e.code == case['result']
|
||||||
@ -79,15 +69,14 @@ def test_data(case_name, capfd, tmp_path, monkeypatch):
|
|||||||
assert 'expected' in case or 'stderr_contains' in case
|
assert 'expected' in case or 'stderr_contains' in case
|
||||||
|
|
||||||
out, err = capfd.readouterr()
|
out, err = capfd.readouterr()
|
||||||
dependencies = output.read_text()
|
|
||||||
|
|
||||||
if 'expected' in case:
|
if 'expected' in case:
|
||||||
expected = case['expected']
|
expected = case['expected']
|
||||||
if isinstance(expected, list):
|
if isinstance(expected, list):
|
||||||
# at least one of them needs to match
|
# at least one of them needs to match
|
||||||
assert dependencies in expected
|
assert any(out == e for e in expected)
|
||||||
else:
|
else:
|
||||||
assert dependencies == expected
|
assert out == expected
|
||||||
|
|
||||||
# stderr_contains may be a string or list of strings
|
# stderr_contains may be a string or list of strings
|
||||||
stderr_contains = case.get('stderr_contains')
|
stderr_contains = case.get('stderr_contains')
|
||||||
|
@ -2,10 +2,9 @@ Name: pyproject-rpm-macros
|
|||||||
Summary: RPM macros for PEP 517 Python packages
|
Summary: RPM macros for PEP 517 Python packages
|
||||||
License: MIT
|
License: MIT
|
||||||
|
|
||||||
%bcond tests 1
|
# Disable tests on RHEL9 as to not pull in the test dependencies
|
||||||
# pytest-xdist and tox are not desired in RHEL
|
# Specify --with tests to run the tests e.g. on EPEL
|
||||||
%bcond pytest_xdist %{undefined rhel}
|
%bcond_with tests
|
||||||
%bcond tox_tests %{undefined rhel}
|
|
||||||
|
|
||||||
# The idea is to follow the spirit of semver
|
# The idea is to follow the spirit of semver
|
||||||
# Given version X.Y.Z:
|
# Given version X.Y.Z:
|
||||||
@ -13,7 +12,7 @@ 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.6.2
|
||||||
Release: 1%{?dist}
|
Release: 1%{?dist}
|
||||||
|
|
||||||
# Macro files
|
# Macro files
|
||||||
@ -50,33 +49,14 @@ BuildArch: noarch
|
|||||||
|
|
||||||
%if %{with tests}
|
%if %{with tests}
|
||||||
BuildRequires: python3dist(pytest)
|
BuildRequires: python3dist(pytest)
|
||||||
%if %{with pytest_xdist}
|
|
||||||
BuildRequires: python3dist(pytest-xdist)
|
BuildRequires: python3dist(pytest-xdist)
|
||||||
%endif
|
|
||||||
BuildRequires: python3dist(pyyaml)
|
BuildRequires: python3dist(pyyaml)
|
||||||
BuildRequires: python3dist(packaging)
|
BuildRequires: python3dist(packaging)
|
||||||
BuildRequires: python3dist(pip)
|
BuildRequires: python3dist(pip)
|
||||||
BuildRequires: python3dist(setuptools)
|
BuildRequires: python3dist(setuptools)
|
||||||
%if %{with tox_tests}
|
|
||||||
BuildRequires: python3dist(tox-current-env) >= 0.0.6
|
BuildRequires: python3dist(tox-current-env) >= 0.0.6
|
||||||
%endif
|
|
||||||
BuildRequires: python3dist(wheel)
|
BuildRequires: python3dist(wheel)
|
||||||
BuildRequires: (python3dist(tomli) if python3 < 3.11)
|
BuildRequires: (python3dist(toml) if python3-devel < 3.11)
|
||||||
|
|
||||||
# RHEL 9: We also run pytest with Python 3.11 and 3.12
|
|
||||||
BuildRequires: python3.11dist(pytest)
|
|
||||||
BuildRequires: python3.11dist(pyyaml)
|
|
||||||
BuildRequires: python3.11dist(packaging)
|
|
||||||
BuildRequires: python3.11dist(pip)
|
|
||||||
BuildRequires: python3.11dist(setuptools)
|
|
||||||
BuildRequires: python3.11dist(wheel)
|
|
||||||
|
|
||||||
BuildRequires: python3.12dist(pytest)
|
|
||||||
BuildRequires: python3.12dist(pyyaml)
|
|
||||||
BuildRequires: python3.12dist(packaging)
|
|
||||||
BuildRequires: python3.12dist(pip)
|
|
||||||
BuildRequires: python3.12dist(setuptools)
|
|
||||||
BuildRequires: python3.12dist(wheel)
|
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
# We build on top of those:
|
# We build on top of those:
|
||||||
@ -92,12 +72,6 @@ Requires: (pyproject-srpm-macros = %{?epoch:%{epoch}:}%{version}-%{release
|
|||||||
Requires: /usr/bin/find
|
Requires: /usr/bin/find
|
||||||
Requires: /usr/bin/sed
|
Requires: /usr/bin/sed
|
||||||
|
|
||||||
# This package requires the %%generate_buildrequires functionality.
|
|
||||||
# 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.
|
|
||||||
Requires: (rpm-build >= 4.14.90 if rpm-build)
|
|
||||||
BuildRequires: rpm-build >= 4.14.90
|
|
||||||
|
|
||||||
%description
|
%description
|
||||||
These macros allow projects that follow the Python packaging specifications
|
These macros allow projects that follow the Python packaging specifications
|
||||||
to be packaged as RPMs.
|
to be packaged as RPMs.
|
||||||
@ -116,7 +90,6 @@ which only work with setup.py.
|
|||||||
%package -n pyproject-srpm-macros
|
%package -n pyproject-srpm-macros
|
||||||
Summary: Minimal implementation of %%pyproject_buildrequires
|
Summary: Minimal implementation of %%pyproject_buildrequires
|
||||||
Requires: (pyproject-rpm-macros = %{?epoch:%{epoch}:}%{version}-%{release} if pyproject-rpm-macros)
|
Requires: (pyproject-rpm-macros = %{?epoch:%{epoch}:}%{version}-%{release} if pyproject-rpm-macros)
|
||||||
Requires: (rpm-build >= 4.14.90 if rpm-build)
|
|
||||||
|
|
||||||
%description -n pyproject-srpm-macros
|
%description -n pyproject-srpm-macros
|
||||||
This package contains a minimal implementation of %%pyproject_buildrequires.
|
This package contains a minimal implementation of %%pyproject_buildrequires.
|
||||||
@ -131,9 +104,6 @@ takes precedence.
|
|||||||
%setup -c -T
|
%setup -c -T
|
||||||
cp -p %{sources} .
|
cp -p %{sources} .
|
||||||
|
|
||||||
%generate_buildrequires
|
|
||||||
# nothing to do, this is here just to assert we have that functionality
|
|
||||||
|
|
||||||
%build
|
%build
|
||||||
# nothing to do, sources are not buildable
|
# nothing to do, sources are not buildable
|
||||||
|
|
||||||
@ -150,25 +120,10 @@ install -pm 644 pyproject_construct_toxenv.py %{buildroot}%{_rpmconfigdir}/redha
|
|||||||
install -pm 644 pyproject_requirements_txt.py %{buildroot}%{_rpmconfigdir}/redhat/
|
install -pm 644 pyproject_requirements_txt.py %{buildroot}%{_rpmconfigdir}/redhat/
|
||||||
install -pm 644 pyproject_wheel.py %{buildroot}%{_rpmconfigdir}/redhat/
|
install -pm 644 pyproject_wheel.py %{buildroot}%{_rpmconfigdir}/redhat/
|
||||||
|
|
||||||
%check
|
|
||||||
# assert the two signatures of %%pyproject_buildrequires match exactly
|
|
||||||
signature1="$(grep '^%%pyproject_buildrequires' macros.pyproject | cut -d' ' -f1)"
|
|
||||||
signature2="$(grep '^%%pyproject_buildrequires' macros.aaa-pyproject-srpm | cut -d' ' -f1)"
|
|
||||||
test "$signature1" == "$signature2"
|
|
||||||
# but also assert we are not comparing empty strings
|
|
||||||
test "$signature1" != ""
|
|
||||||
|
|
||||||
%if %{with tests}
|
%if %{with tests}
|
||||||
|
%check
|
||||||
export HOSTNAME="rpmbuild" # to speedup tox in network-less mock, see rhbz#1856356
|
export HOSTNAME="rpmbuild" # to speedup tox in network-less mock, see rhbz#1856356
|
||||||
%pytest -vv --doctest-modules %{?with_pytest_xdist:-n auto} %{!?with_tox_tests:-k "not tox"}
|
%pytest -vv --doctest-modules -n auto
|
||||||
|
|
||||||
# RHEL 9 only:
|
|
||||||
%global __pytest pytest-3.11
|
|
||||||
%pytest -vv --doctest-modules -k "not tox"
|
|
||||||
|
|
||||||
# RHEL 9 only:
|
|
||||||
%global __pytest pytest-3.12
|
|
||||||
%pytest -vv --doctest-modules -k "not tox"
|
|
||||||
|
|
||||||
# brp-compress is provided as an argument to get the right directory macro expansion
|
# brp-compress is provided as an argument to get the right directory macro expansion
|
||||||
%{python3} compare_mandata.py -f %{_rpmconfigdir}/brp-compress
|
%{python3} compare_mandata.py -f %{_rpmconfigdir}/brp-compress
|
||||||
@ -194,50 +149,6 @@ export HOSTNAME="rpmbuild" # to speedup tox in network-less mock, see rhbz#1856
|
|||||||
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
* Fri Jan 26 2024 Miro Hrončok <miro@hroncok.cz> - 1.12.0-1
|
|
||||||
- Namespace pyproject-rpm-macros generated text files with %%{python3_pkgversion}
|
|
||||||
- That way, a single-spec can be used to build packages for multiple Python versions
|
|
||||||
- Fixes: rhbz#2209055
|
|
||||||
|
|
||||||
* Wed Sep 27 2023 Miro Hrončok <mhroncok@redhat.com> - 1.11.0-1
|
|
||||||
- Add the -l/-L flag to %%pyproject_save_files
|
|
||||||
- The -l flag can be used to assert at least 1 License-File was detected
|
|
||||||
- The -L flag explicitly disables this check (which remains the default)
|
|
||||||
- Prevent incorrect usage of %%pyproject_buildrequires -R with -x/-e/-t
|
|
||||||
- Fixes: rhbz#2244282
|
|
||||||
- Show a better error message when %%pyproject_install finds no wheel
|
|
||||||
- Fixes: rhbz#2242452
|
|
||||||
- Fix %%pyproject_buildrequires -w when the build backend is already installed and pip isn't
|
|
||||||
- Fixes: rhbz#2169855
|
|
||||||
|
|
||||||
* Wed Sep 13 2023 Python Maint <python-maint@redhat.com> - 1.10.0-1
|
|
||||||
- Add %%_pyproject_check_import_allow_no_modules for automated environments
|
|
||||||
- Fix handling of tox 4 provision without an explicit tox minversion
|
|
||||||
- Fixes: rhbz#2240590
|
|
||||||
|
|
||||||
* Wed May 31 2023 Maxwell G <maxwell@gtmx.me> - 1.9.0-1
|
|
||||||
- Allow passing config_settings to the build backend.
|
|
||||||
|
|
||||||
* Wed May 31 2023 Miro Hrončok <mhroncok@redhat.com> - 1.8.1-1
|
|
||||||
- On Python older than 3.11, use tomli instead of deprecated toml
|
|
||||||
- Fix literal %% handling in %%{pyproject_files} on RPM 4.19
|
|
||||||
|
|
||||||
* Tue May 23 2023 Miro Hrončok <mhroncok@redhat.com> - 1.8.0-2
|
|
||||||
- Rebuilt for ELN dependency changes
|
|
||||||
|
|
||||||
* Thu Apr 27 2023 Miro Hrončok <mhroncok@redhat.com> - 1.8.0-1
|
|
||||||
- %%pyproject_buildrequires: Add support for self-referential extras requirements
|
|
||||||
- Deprecate the provisional %%{pyproject_build_lib} macro
|
|
||||||
See https://lists.fedoraproject.org/archives/list/python-devel@lists.fedoraproject.org/thread/HMLOPAU3RZLXD4BOJHTIPKI3I4U6U7OE/
|
|
||||||
|
|
||||||
* Fri Mar 31 2023 Miro Hrončok <mhroncok@redhat.com> - 1.7.0-1
|
|
||||||
- %%pyproject_buildrequires: Redirect stdout to stderr via Shell
|
|
||||||
- Dependencies are recorded to a text file that is catted at the end
|
|
||||||
|
|
||||||
* Mon Feb 13 2023 Lumír Balhar <lbalhar@redhat.com> - 1.6.3-1
|
|
||||||
- Remove .dist-info directory at the end of %%pyproject_buildrequires
|
|
||||||
- An incomplete .dist-info directory in $PWD can confuse tests in %%check
|
|
||||||
|
|
||||||
* Wed Feb 08 2023 Lumír Balhar <lbalhar@redhat.com> - 1.6.2-1
|
* Wed Feb 08 2023 Lumír Balhar <lbalhar@redhat.com> - 1.6.2-1
|
||||||
- Improve detection of lang files
|
- Improve detection of lang files
|
||||||
|
|
||||||
@ -254,8 +165,7 @@ export HOSTNAME="rpmbuild" # to speedup tox in network-less mock, see rhbz#1856
|
|||||||
- Use %%py3_test_envvars in %%tox when available
|
- Use %%py3_test_envvars in %%tox when available
|
||||||
|
|
||||||
* Mon Sep 19 2022 Python Maint <python-maint@redhat.com> - 1.4.0-1
|
* Mon Sep 19 2022 Python Maint <python-maint@redhat.com> - 1.4.0-1
|
||||||
- %%pyproject_save_files: Support License-Files installed into the *Root License Directory* from PEP 639
|
- %%pyproject_save_files: Support License-Files installed into the *Root License Directory* from PEP 369
|
||||||
|
|
||||||
- %%pyproject_check_import: Import only the modules whose top-level names
|
- %%pyproject_check_import: Import only the modules whose top-level names
|
||||||
match any of the globs provided to %%pyproject_save_files
|
match any of the globs provided to %%pyproject_save_files
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user