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)

Co-Authored-By: Maxwell G <maxwell@gtmx.me>
This commit is contained in:
Miro Hrončok 2023-09-27 14:37:15 +02:00
parent 0ce790d763
commit f39261901c
28 changed files with 75 additions and 43 deletions

View File

@ -288,6 +288,12 @@ However, in Fedora packages, always list executables explicitly to avoid uninten
and language (`*.mo`) files with `%lang` macro and appropriate language code.
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.
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/).
If you wish to rename, remove or otherwise change the installed files of a package

View File

@ -108,7 +108,7 @@ fi
# 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() %{expand:\\\
%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 \\
--output-files "%{pyproject_files}" \\
@ -119,7 +119,7 @@ fi
--python-version "%{python3_version}" \\
--pyproject-record "%{_pyproject_record}" \\
--prefix "%{_prefix}" \\
%{*}
%{**}
}
# -t - Process only top-level modules

View File

@ -13,7 +13,7 @@ License: MIT
# Increment Y and reset Z when new macros or features are added
# Increment Z when this is a bugfix or a cosmetic change
# Dropping support for EOL Fedoras is *not* considered a breaking change
Version: 1.10.0
Version: 1.11.0
Release: 1%{?dist}
# Macro files
@ -171,6 +171,11 @@ export HOSTNAME="rpmbuild" # to speedup tox in network-less mock, see rhbz#1856
%changelog
* 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)
* 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

View File

@ -693,12 +693,15 @@ def dist_metadata(buildroot, record_path):
return dist.metadata
def pyproject_save_files_and_modules(buildroot, sitelib, sitearch, python_version, pyproject_record, prefix, varargs):
def pyproject_save_files_and_modules(buildroot, sitelib, sitearch, python_version, pyproject_record, prefix, assert_license, varargs):
"""
Takes arguments from the %{pyproject_save_files} macro
Returns tuple: list of paths for the %files section and list of module names
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
# This saves us browsing one directory twice
@ -710,11 +713,15 @@ def pyproject_save_files_and_modules(buildroot, sitelib, sitearch, python_versio
final_file_list = []
final_module_list = []
# we assume OK when not asserting
license_ok = not assert_license
for record_path, files in parsed_records.items():
metadata = dist_metadata(buildroot, record_path)
paths_dict = classify_paths(
record_path, files, metadata, sitedirs, python_version, prefix
)
license_ok = license_ok or bool(paths_dict["metadata"]["licenses"])
final_file_list.extend(
generate_file_list(paths_dict, globs, include_auto)
@ -723,6 +730,15 @@ def pyproject_save_files_and_modules(buildroot, sitelib, sitearch, python_versio
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
@ -734,6 +750,7 @@ def main(cli_args):
cli_args.python_version,
cli_args.pyproject_record,
cli_args.prefix,
cli_args.assert_license,
cli_args.varargs,
)
@ -747,7 +764,7 @@ def argparser():
prog="%pyproject_save_files",
add_help=False,
# custom usage to add +auto
usage="%(prog)s MODULE_GLOB [MODULE_GLOB ...] [+auto]",
usage="%(prog)s [-l|-L] MODULE_GLOB [MODULE_GLOB ...] [+auto]",
)
parser.add_argument(
'--help', action='help',
@ -763,6 +780,14 @@ def argparser():
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("--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(
"varargs", nargs="+", metavar="MODULE_GLOB",
help="Shell-like glob matching top-level module names to save into %%{pyproject_files}",

View File

@ -48,7 +48,7 @@ touch 'escape_percentages/one%%version'
%install
%pyproject_install
%pyproject_save_files escape_percentages
%pyproject_save_files -L escape_percentages
touch '%{buildroot}/two%%version'

View File

@ -33,7 +33,7 @@ Building this tests that lang files are marked with %%lang in filelist.
%install
%pyproject_install
%pyproject_save_files printrun +auto
%pyproject_save_files -l printrun +auto
%check
@ -52,4 +52,3 @@ grep -E '/printrun/__pycache__$' %{pyproject_files}
%files -f %{pyproject_files}
%doc README*
%license COPYING

View File

@ -42,7 +42,7 @@ sed -Ei "s/(, )?'pytest-runner'//" setup.py
%install
%pyproject_install
%pyproject_save_files distroinfo
%pyproject_save_files -l distroinfo
%check
@ -52,4 +52,3 @@ sed -Ei "s/(, )?'pytest-runner'//" setup.py
%files -n python3-distroinfo -f %{pyproject_files}
%doc README.rst AUTHORS
%license LICENSE

View File

@ -40,7 +40,7 @@ find -name "*.po" | xargs rm -f
%install
%pyproject_install
%pyproject_save_files django
%pyproject_save_files -l django
%check
@ -56,6 +56,5 @@ diff tested.lang expected.lang
%files -n python3-django -f %{pyproject_files}
%doc README.rst
%license LICENSE
%{_bindir}/django-admin
%{_bindir}/django-admin.py

View File

@ -55,7 +55,8 @@ sed -i \
%install
%pyproject_install
%pyproject_save_files lexicon
# the license is not marked as License-File by poetry-core, hence -L
%pyproject_save_files -L lexicon
%check

View File

@ -38,7 +38,8 @@ Summary: %{summary}
%install
%pyproject_install
%pyproject_save_files entrypoints
# the license is not marked as License-File, hence -L
%pyproject_save_files entrypoints -L
%check

View File

@ -42,7 +42,13 @@ cd ..
%install
%pyproject_install
# there is no license file marked as License-File, hence not using -l
%pyproject_save_files flit_core
%check
# internal check for our macros, we assume there is no license
grep -F %%license %{pyproject_files} && exit 1 || true
%files -n python3-flit-core -f %{pyproject_files}

View File

@ -40,7 +40,7 @@ Summary: %{summary}
%install
%pyproject_install
%pyproject_save_files '*' +auto
%pyproject_save_files -l '*' +auto
%check

View File

@ -56,7 +56,7 @@ sed -Ei 's/\bdef (test_(relative_)?redirect_(to_post|n_(equals_to|higher_than)_1
%install
%pyproject_install
%pyproject_save_files httpbin
%pyproject_save_files -l httpbin
%if %{with tests}
@ -72,4 +72,3 @@ sed -Ei 's/\bdef (test_(relative_)?redirect_(to_post|n_(equals_to|higher_than)_1
%files -n python3-httpbin -f %{pyproject_files}
%doc README*
%license LICENSE*

View File

@ -46,12 +46,11 @@ sed -i '/"debugpy/d' pyproject.toml setup.py
%install
%pyproject_install
%pyproject_save_files 'ipykernel*' +auto
%pyproject_save_files -l 'ipykernel*' +auto
%check
%pyproject_check_import -e '*.test*' -e 'ipykernel.gui*' -e 'ipykernel.pylab.*' -e 'ipykernel.trio*'
%files -n python3-ipykernel -f %{pyproject_files}
%license COPYING.md
%doc README.md

View File

@ -41,7 +41,7 @@ Summary: %{summary}
%install
%pyproject_install
%pyproject_save_files isort
%pyproject_save_files -l isort
%check
@ -55,5 +55,4 @@ grep -F %{_bindir}/%{modname} %{pyproject_files} && exit 1 || true
%files -n python%{python3_pkgversion}-%{modname} -f %{pyproject_files}
%doc README.rst *.md
%license LICENSE
%{_bindir}/%{modname}

View File

@ -61,7 +61,7 @@ PYTHONPATH=%{pyproject_build_lib} %{python3} -c 'import _ldap'
%install
%pyproject_install
# We can pass multiple globs
%pyproject_save_files 'ldap*' '*ldap'
%pyproject_save_files -l 'ldap*' '*ldap'
%check
@ -104,7 +104,6 @@ test "%{pyproject_build_lib}" == "%{_builddir}/%{buildsubdir}/build/lib.%{python
%files -n python3-ldap -f %{pyproject_files}
%license LICENCE
%doc CHANGES README TODO Demo
# Explicitly listed files can be combined with automation
%pycached %{python3_sitearch}/ldif.py

View File

@ -26,7 +26,6 @@ Summary: %{summary}
# In this spec, we put %%files early to test it still works
%files -n python3-markupsafe -f %{pyproject_files}
%license LICENSE.rst
%doc CHANGES.rst README.rst
@ -54,7 +53,7 @@ sed -Ei 's/sphinx\.git@([0-9a-f]+)/sphinx.git@\1#egg=sphinx/' requirements/docs.
%install
%pyproject_install
%pyproject_save_files markupsafe
%pyproject_save_files -l markupsafe
%check

View File

@ -46,7 +46,7 @@ Summary: %summary
%install
%pyproject_install
%pyproject_save_files mistune
%pyproject_save_files -l mistune
%check
@ -61,4 +61,3 @@ test -f %{buildroot}%{python3_sitearch}/mistune.cpython-*.so
%files -n python%{python3_pkgversion}-mistune -f %{pyproject_files}
%doc README.rst
%license LICENSE

View File

@ -45,7 +45,7 @@ sed -i '/mock/d' tests.requires
%install
%pyproject_install
%pyproject_save_files %{pypi_name}
%pyproject_save_files -l %{pypi_name}
%check
@ -54,4 +54,3 @@ sed -i '/mock/d' tests.requires
%files -n python3-%{pypi_name} -f %{pyproject_files}
%doc README.*
%license COPYING

View File

@ -43,7 +43,7 @@ Summary: %{summary}
%install
%pyproject_install
# There are no executables, but we are allowed to pass +auto anyway
%pyproject_save_files pluggy +auto
%pyproject_save_files pluggy +auto -l
%check
@ -52,4 +52,3 @@ Summary: %{summary}
%files -n python3-%{pypi_name} -f %{pyproject_files}
%doc README.rst
%license LICENSE

View File

@ -37,8 +37,11 @@ Summary: %{summary}
%install
%pyproject_install
%pyproject_save_files poetry
# the license is not marked as License-File by poetry-core, hence -L
%pyproject_save_files -L poetry
# internal check for our macros, -l must fail:
%pyproject_save_files -l poetry && exit 1 || true
%files -n python3-poetry-core -f %{pyproject_files}
%doc README.md

View File

@ -54,7 +54,7 @@ sed -i 's/setuptools-scm\[toml\]>=6.2.3/setuptools-scm[toml]>=5/' pyproject.toml
%install
%pyproject_install
%pyproject_save_files '*pytest' +auto
%pyproject_save_files -l '*pytest' +auto
%check
@ -70,4 +70,3 @@ sed -i 's/setuptools-scm\[toml\]>=6.2.3/setuptools-scm[toml]>=5/' pyproject.toml
%files -n python3-%{pypi_name} -f %{pyproject_files}
%doc README.rst
%doc CHANGELOG.rst
%license LICENSE

View File

@ -76,7 +76,7 @@ sed -i pytest.ini -e 's/ --flake8//' \
%install
%pyproject_install
%pyproject_save_files setuptools pkg_resources _distutils_hack
%pyproject_save_files setuptools pkg_resources _distutils_hack -l
# https://github.com/pypa/setuptools/issues/2709
rm -rf %{buildroot}%{python3_sitelib}/pkg_resources/tests/

View File

@ -52,7 +52,7 @@ Summary: %{summary}
%install
%pyproject_install
%pyproject_save_files setuptools_scm
%pyproject_save_files -l setuptools_scm
%check
@ -73,4 +73,3 @@ test "$(cat %{_pyproject_ghost_distinfo})" == "%ghost %{python3_sitelib}/setupto
%files -n python3-setuptools_scm -f %{pyproject_files}
%doc README.rst
%doc CHANGELOG.rst
%license LICENSE

View File

@ -43,7 +43,7 @@ sed -Ei '/^(coverage)$/d' requirements-dev.txt
%install
%pyproject_install
%pyproject_save_files userpath
%pyproject_save_files -l userpath
%check

View File

@ -52,7 +52,7 @@ sed -i 's/_nonwrappers/_hookimpls/' tests/conftest.py
%install
%pyproject_install
%pyproject_save_files virtualenv
%pyproject_save_files -l virtualenv
%{?el9:
# old version of setuptools_scm produces files incompatible with
# assumptions in virtualenv code, we append the expected attributes:

View File

@ -32,7 +32,7 @@ Summary: %{summary}
%install
%pyproject_install
%pyproject_save_files zope +auto
%pyproject_save_files -l zope +auto
%check
# Internal check that the RECORD and REQUESTED files are
@ -42,5 +42,4 @@ test ! $(find %{buildroot}%{python3_sitelib}/ | grep -E "\.dist-info/REQUESTED$"
%files -n python3-zope-event -f %{pyproject_files}
%doc README.rst
%license LICENSE.txt

View File

@ -36,7 +36,7 @@ Building this tests:
%install
%pyproject_install
%pyproject_save_files tldr +auto
%pyproject_save_files -l tldr +auto
%check
# Internal check for our macros: tests we don't ship __pycache__ in bindir
@ -62,5 +62,4 @@ grep '^/app' %{pyproject_files}
%endif
%files -f %pyproject_files
%license LICENSE
%doc README.md