From 0fb362073aac1ef8395b6ac72d5d03b31f4cec61 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Sat, 14 Jul 2018 01:58:03 +0000 Subject: [PATCH 001/110] - Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild Signed-off-by: Fedora Release Engineering --- python-rpm-generators.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 33196c7..2ecf76c 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -5,7 +5,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 5 -Release: 1%{?dist} +Release: 2%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -45,6 +45,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} pythondeps.sh pythondistdeps.py %{_rpmconfigdir}/pythondistdeps.py %changelog +* Sat Jul 14 2018 Fedora Release Engineering - 5-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild + * Sun Feb 11 2018 Igor Gnatenko - 5-1 - Fork upstream generators - "Fix" support of environment markers From dc64d7b4365db52364123b89e11e9850b2c563cf Mon Sep 17 00:00:00 2001 From: Igor Gnatenko Date: Sat, 28 Jul 2018 14:19:20 +0200 Subject: [PATCH 002/110] Split python to pythondist generator Running this python script on all possible files is way too expensive. Some of the packages timeout due to that. Signed-off-by: Igor Gnatenko --- python-rpm-generators.spec | 14 ++++++++++---- python.attr | 4 ++-- pythondist.attr | 3 +++ 3 files changed, 15 insertions(+), 6 deletions(-) create mode 100644 pythondist.attr diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 2ecf76c..dc544a6 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -5,7 +5,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 5 -Release: 2%{?dist} +Release: 3%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -13,8 +13,9 @@ Url: https://src.fedoraproject.org/python-rpm-generators # Commit is the last change in following files Source0: https://raw.githubusercontent.com/rpm-software-management/rpm/102eab50b3d0d6546dfe082eac0ade21e6b3dbf1/COPYING Source1: python.attr -Source2: pythondeps.sh -Source3: pythondistdeps.py +Source2: pythondist.attr +Source3: pythondeps.sh +Source4: pythondistdeps.py BuildArch: noarch @@ -26,6 +27,8 @@ Summary: %{summary} Requires: python3-setuptools # The point of split Conflicts: rpm-build < 4.13.0.1-2 +# Breaking change, change a way how depgen is enabled +Conflicts: python-rpm-macros < 3-36 %description -n python3-rpm-generators %{summary}. @@ -35,7 +38,7 @@ Conflicts: rpm-build < 4.13.0.1-2 cp -a %{sources} . %install -install -Dpm0644 -t %{buildroot}%{_fileattrsdir} python.attr +install -Dpm0644 -t %{buildroot}%{_fileattrsdir} python.attr pythondist.attr install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} pythondeps.sh pythondistdeps.py %files -n python3-rpm-generators @@ -45,6 +48,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} pythondeps.sh pythondistdeps.py %{_rpmconfigdir}/pythondistdeps.py %changelog +* Sat Jul 28 2018 Igor Gnatenko - 5-3 +- Add pythondist generator + * Sat Jul 14 2018 Fedora Release Engineering - 5-2 - Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild diff --git a/python.attr b/python.attr index a7381d6..0f3c2cc 100644 --- a/python.attr +++ b/python.attr @@ -1,4 +1,4 @@ -%__python_provides %{_rpmconfigdir}/pythondistdeps.py --provides --majorver-provides +%__python_provides %{_rpmconfigdir}/pythondeps.sh --provides %__python_requires %{_rpmconfigdir}/pythondeps.sh --requires -%__python_path ^((/usr/lib(64)?/python[[:digit:]]\\.[[:digit:]]/.*))|(%{_bindir}/python[[:digit:]]\\.[[:digit:]]))$ +%__python_path ^((/usr/lib(64)?/python[[:digit:]]\\.[[:digit:]]/.*\\.(py[oc]?|so))|(%{_bindir}/python[[:digit:]]\\.[[:digit:]]))$ %__python_magic [Pp]ython.*(executable|byte-compiled) diff --git a/pythondist.attr b/pythondist.attr new file mode 100644 index 0000000..641d701 --- /dev/null +++ b/pythondist.attr @@ -0,0 +1,3 @@ +%__pythondist_provides %{_rpmconfigdir}/pythondistdeps.py --provides --majorver-provides +#%__pythondist_requires %{_rpmconfigdir}/pythondistdeps.py --requires +%__pythondist_path ^((/usr/lib(64)?/python[[:digit:]]\\.[[:digit:]]/.*\\.(dist.*|egg.*))$ From 1d1b5f8e22cc344c9fc86f60166cb58398c86368 Mon Sep 17 00:00:00 2001 From: Igor Gnatenko Date: Sat, 28 Jul 2018 14:30:57 +0200 Subject: [PATCH 003/110] reference new attr file in %files Signed-off-by: Igor Gnatenko --- python-rpm-generators.spec | 1 + 1 file changed, 1 insertion(+) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index dc544a6..9bc4382 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -44,6 +44,7 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} pythondeps.sh pythondistdeps.py %files -n python3-rpm-generators %license COPYING %{_fileattrsdir}/python.attr +%{_fileattrsdir}/pythondist.attr %{_rpmconfigdir}/pythondeps.sh %{_rpmconfigdir}/pythondistdeps.py From a51b52a5e4753c25845f341c3ef22bd52735cfcb Mon Sep 17 00:00:00 2001 From: Igor Gnatenko Date: Sat, 28 Jul 2018 14:31:43 +0200 Subject: [PATCH 004/110] remove gitingore/sources We don't use that anymore. Signed-off-by: Igor Gnatenko --- .gitignore | 3 --- sources | 1 - 2 files changed, 4 deletions(-) delete mode 100644 .gitignore delete mode 100644 sources diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 54a81e0..0000000 --- a/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/rpm-4.13.0.1.tar.bz2 -/rpm-4.14.0-rc1.tar.bz2 -/rpm-4.14.0.tar.bz2 diff --git a/sources b/sources deleted file mode 100644 index 88d74ab..0000000 --- a/sources +++ /dev/null @@ -1 +0,0 @@ -SHA512 (rpm-4.14.0.tar.bz2) = 938a46bfaf480741b72e11ad93fa1d2a5bce51f1e8ee206983a64e1cda0d7a0cf517f7658c98c93605d4ae9bede2d7305cf5754c7905820f3da64d8a860a0756 From 40740c1747ebca5e6023101c4d2045fb9ec533ec Mon Sep 17 00:00:00 2001 From: Igor Gnatenko Date: Sat, 28 Jul 2018 14:32:50 +0200 Subject: [PATCH 005/110] fix the conflicting version Signed-off-by: Igor Gnatenko --- python-rpm-generators.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 9bc4382..4474357 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -28,7 +28,7 @@ Requires: python3-setuptools # The point of split Conflicts: rpm-build < 4.13.0.1-2 # Breaking change, change a way how depgen is enabled -Conflicts: python-rpm-macros < 3-36 +Conflicts: python-rpm-macros < 3-35 %description -n python3-rpm-generators %{summary}. From fdad4ede040be5b734a5bf7110b4ce43068c3937 Mon Sep 17 00:00:00 2001 From: Igor Gnatenko Date: Sat, 28 Jul 2018 14:39:01 +0200 Subject: [PATCH 006/110] fix wrong regex in dist attr Signed-off-by: Igor Gnatenko --- pythondist.attr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pythondist.attr b/pythondist.attr index 641d701..c9af54c 100644 --- a/pythondist.attr +++ b/pythondist.attr @@ -1,3 +1,3 @@ %__pythondist_provides %{_rpmconfigdir}/pythondistdeps.py --provides --majorver-provides #%__pythondist_requires %{_rpmconfigdir}/pythondistdeps.py --requires -%__pythondist_path ^((/usr/lib(64)?/python[[:digit:]]\\.[[:digit:]]/.*\\.(dist.*|egg.*))$ +%__pythondist_path ^/usr/lib(64)?/python[[:digit:]]\\.[[:digit:]]/.*\\.(dist.*|egg.*)$ From 1879d8a0e231b74286c8ae113c401dbbb4b04734 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Sat, 28 Jul 2018 22:15:16 +0200 Subject: [PATCH 007/110] Use nonstandardlib for purelib definition (#1609492) The purelib and platlib were both defined to /usr/lib64/python on 64bits systems. This is because: >>> get_python_lib(standard_lib=1, plat_specific=0) '/usr/lib64/python3.7' >>> get_python_lib(standard_lib=1, plat_specific=1) '/usr/lib64/python3.7' >>> get_python_lib(standard_lib=0, plat_specific=0) '/usr/lib/python3.7/site-packages' >>> get_python_lib(standard_lib=0, plat_specific=1) '/usr/lib64/python3.7/site-packages' So now we use standard_lib=0 to get the site-packages base path from /usr/lib and not /usr/lib64. Fixes https://bugzilla.redhat.com/show_bug.cgi?id=1609492 --- python-rpm-generators.spec | 5 ++++- pythondistdeps.py | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 4474357..352adb4 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -5,7 +5,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 5 -Release: 3%{?dist} +Release: 4%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -49,6 +49,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} pythondeps.sh pythondistdeps.py %{_rpmconfigdir}/pythondistdeps.py %changelog +* Sat Jul 28 2018 Miro Hrončok - 5-4 +- Use nonstandardlib for purelib definition (#1609492) + * Sat Jul 28 2018 Igor Gnatenko - 5-3 - Add pythondist generator diff --git a/pythondistdeps.py b/pythondistdeps.py index a15ccba..2f3dd71 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -82,8 +82,8 @@ for f in files: if py_abi and (lower.endswith('.py') or lower.endswith('.pyc') or lower.endswith('.pyo')): if name not in py_deps: py_deps[name] = [] - purelib = get_python_lib(standard_lib=1, plat_specific=0).split(version[:3])[0] - platlib = get_python_lib(standard_lib=1, plat_specific=1).split(version[:3])[0] + purelib = get_python_lib(standard_lib=0, plat_specific=0).split(version[:3])[0] + platlib = get_python_lib(standard_lib=0, plat_specific=1).split(version[:3])[0] for lib in (purelib, platlib): if lib in f: spec = ('==', f.split(lib)[1].split(sep)[0]) From 9f6f709036af34a75839e43e1f21d6519231e339 Mon Sep 17 00:00:00 2001 From: Igor Gnatenko Date: Wed, 3 Oct 2018 14:21:26 +0200 Subject: [PATCH 008/110] Tighten regex for depgen Signed-off-by: Igor Gnatenko --- python-rpm-generators.spec | 7 +++++-- python.attr | 2 +- pythondist.attr | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 352adb4..984ed7d 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -4,8 +4,8 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs -Version: 5 -Release: 4%{?dist} +Version: 6 +Release: 1%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -49,6 +49,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} pythondeps.sh pythondistdeps.py %{_rpmconfigdir}/pythondistdeps.py %changelog +* Wed Oct 03 2018 Igor Gnatenko - 6-1 +- Tighten regex for depgen + * Sat Jul 28 2018 Miro Hrončok - 5-4 - Use nonstandardlib for purelib definition (#1609492) diff --git a/python.attr b/python.attr index 0f3c2cc..f5d2dff 100644 --- a/python.attr +++ b/python.attr @@ -1,4 +1,4 @@ %__python_provides %{_rpmconfigdir}/pythondeps.sh --provides %__python_requires %{_rpmconfigdir}/pythondeps.sh --requires -%__python_path ^((/usr/lib(64)?/python[[:digit:]]\\.[[:digit:]]/.*\\.(py[oc]?|so))|(%{_bindir}/python[[:digit:]]\\.[[:digit:]]))$ +%__python_path ^((/usr/lib(64)?/python[[:digit:]]\\.[[:digit:]]+/.*\\.(py[oc]?|so))|(^%{_bindir}/python[[:digit:]]\\.[[:digit:]]+))$ %__python_magic [Pp]ython.*(executable|byte-compiled) diff --git a/pythondist.attr b/pythondist.attr index c9af54c..28535b5 100644 --- a/pythondist.attr +++ b/pythondist.attr @@ -1,3 +1,3 @@ %__pythondist_provides %{_rpmconfigdir}/pythondistdeps.py --provides --majorver-provides #%__pythondist_requires %{_rpmconfigdir}/pythondistdeps.py --requires -%__pythondist_path ^/usr/lib(64)?/python[[:digit:]]\\.[[:digit:]]/.*\\.(dist.*|egg.*)$ +%__pythondist_path ^/usr/lib(64)?/python[[:digit:]]\\.[[:digit:]]+/site-packages/[^/]+\\.(dist-info|egg-info|egg-link)$ From e745e149a6c877ae9b7fc26027d35fa6aeaaf902 Mon Sep 17 00:00:00 2001 From: Igor Gnatenko Date: Thu, 20 Dec 2018 14:21:14 +0100 Subject: [PATCH 009/110] Enable requires generator References: https://fedoraproject.org/wiki/Changes/EnablingPythonGeneratorsByDefault References: https://pagure.io/fesco/issue/2026 Signed-off-by: Igor Gnatenko --- python-rpm-generators.spec | 5 ++++- pythondist.attr | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 984ed7d..cd1ab69 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -4,7 +4,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs -Version: 6 +Version: 7 Release: 1%{?dist} # Originally all those files were part of RPM, so license is kept here @@ -49,6 +49,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} pythondeps.sh pythondistdeps.py %{_rpmconfigdir}/pythondistdeps.py %changelog +* Thu Dec 20 2018 Igor Gnatenko - 7-1 +- Enable requires generator + * Wed Oct 03 2018 Igor Gnatenko - 6-1 - Tighten regex for depgen diff --git a/pythondist.attr b/pythondist.attr index 28535b5..2bf737a 100644 --- a/pythondist.attr +++ b/pythondist.attr @@ -1,3 +1,3 @@ %__pythondist_provides %{_rpmconfigdir}/pythondistdeps.py --provides --majorver-provides -#%__pythondist_requires %{_rpmconfigdir}/pythondistdeps.py --requires +%__pythondist_requires %{_rpmconfigdir}/pythondistdeps.py --requires %__pythondist_path ^/usr/lib(64)?/python[[:digit:]]\\.[[:digit:]]+/site-packages/[^/]+\\.(dist-info|egg-info|egg-link)$ From 67cc59dd224deda3399b79504fdfe06338373767 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Sat, 2 Feb 2019 09:09:35 +0000 Subject: [PATCH 010/110] - Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild Signed-off-by: Fedora Release Engineering --- python-rpm-generators.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index cd1ab69..1fe1fdc 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -5,7 +5,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 7 -Release: 1%{?dist} +Release: 2%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -49,6 +49,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} pythondeps.sh pythondistdeps.py %{_rpmconfigdir}/pythondistdeps.py %changelog +* Sat Feb 02 2019 Fedora Release Engineering - 7-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild + * Thu Dec 20 2018 Igor Gnatenko - 7-1 - Enable requires generator From 70b3ebc993c45c82c5f84868a10634e4dd156280 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Wed, 17 Apr 2019 14:35:46 +0200 Subject: [PATCH 011/110] console_scripts entry points to require setuptools https://github.com/rpm-software-management/rpm/pull/666 --- python-rpm-generators.spec | 8 ++++++-- pythondistdeps.py | 8 +++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 1fe1fdc..f17486b 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -4,8 +4,8 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs -Version: 7 -Release: 2%{?dist} +Version: 8 +Release: 1%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -49,6 +49,10 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} pythondeps.sh pythondistdeps.py %{_rpmconfigdir}/pythondistdeps.py %changelog +* Wed Apr 17 2019 Miro Hrončok - 8-1 +- console_scripts entry points to require setuptools + https://github.com/rpm-software-management/rpm/pull/666 + * Sat Feb 02 2019 Fedora Release Engineering - 7-2 - Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild diff --git a/pythondistdeps.py b/pythondistdeps.py index 2f3dd71..d81cd4b 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -102,7 +102,7 @@ for f in files: lower.endswith('.egg-info') or \ lower.endswith('.dist-info'): # This import is very slow, so only do it if needed - from pkg_resources import Distribution, FileMetadata, PathMetadata + from pkg_resources import Distribution, FileMetadata, PathMetadata, Requirement dist_name = basename(f) if isdir(f): path_item = dirname(f) @@ -127,6 +127,7 @@ for f in files: import platform platform.python_version = lambda: dist.py_version + if Provides_PyMajorVer_Variant or PyMajorVer_Deps or legacy_Provides or legacy: # Get the Python major version pyver_major = dist.py_version.split('.')[0] @@ -179,6 +180,11 @@ for f in files: if dep in deps: depsextras.remove(dep) deps = depsextras + # console_scripts/gui_scripts entry points need pkg_resources from setuptools + if (dist.get_entry_map('console_scripts') or + dist.get_entry_map('gui_scripts')): + # stick them first so any more specific requirement overrides it + deps.insert(0, Requirement.parse('setuptools')) # add requires/recommends based on egg/dist metadata for dep in deps: if legacy: From ff085a044d19dd40aaeb236a11fe024c064ef16a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Thu, 20 Jun 2019 11:03:40 +0200 Subject: [PATCH 012/110] Canonicalize Python versions and properly handle != spec Fixes https://github.com/rpm-software-management/rpm/issues/639 From upstream PR: https://github.com/rpm-software-management/rpm/pull/757 --- python-rpm-generators.spec | 5 ++++- pythondistdeps.py | 21 ++++++++++++++------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index f17486b..4955850 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -4,7 +4,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs -Version: 8 +Version: 9 Release: 1%{?dist} # Originally all those files were part of RPM, so license is kept here @@ -49,6 +49,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} pythondeps.sh pythondistdeps.py %{_rpmconfigdir}/pythondistdeps.py %changelog +* Mon Jun 24 2019 Tomas Orsava - 9-1 +- Canonicalize Python versions and properly handle != spec + * Wed Apr 17 2019 Miro Hrončok - 8-1 - console_scripts entry points to require setuptools https://github.com/rpm-software-management/rpm/pull/666 diff --git a/pythondistdeps.py b/pythondistdeps.py index d81cd4b..1d3535b 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -151,7 +151,10 @@ for f in files: if legacy_name not in py_deps: py_deps[legacy_name] = [] if dist.version: - spec = ('==', dist.version) + version = dist.version + while version.endswith('.0'): + version = version[:-2] + spec = ('==', version) if spec not in py_deps[name]: if not legacy: py_deps[name].append(spec) @@ -195,11 +198,12 @@ for f in files: else: name = 'python{}dist({})'.format(dist.py_version, dep.key) for spec in dep.specs: - if spec[0] != '!=': - if name not in py_deps: - py_deps[name] = [] - if spec not in py_deps[name]: - py_deps[name].append(spec) + while spec[1].endswith('.0'): + spec = (spec[0], spec[1][:-2]) + if name not in py_deps: + py_deps[name] = [] + if spec not in py_deps[name]: + py_deps[name].append(spec) if not dep.specs: py_deps[name] = [] # Unused, for automatic sub-package generation based on 'extras' from egg/dist metadata @@ -245,7 +249,10 @@ for name in names: if py_deps[name]: # Print out versioned provides, requires, recommends, conflicts for spec in py_deps[name]: - print('{} {} {}'.format(name, spec[0], spec[1])) + if spec[0] == '!=': + print('({n} < {v} or {n} >= {v}.0)'.format(n=name, v=spec[1])) + else: + print('{} {} {}'.format(name, spec[0], spec[1])) else: # Print out unversioned provides, requires, recommends, conflicts print(name) From b9fe0e71822e12f4998f0dea45aa4b9f76b19ce3 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Fri, 26 Jul 2019 16:06:05 +0000 Subject: [PATCH 013/110] - Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild Signed-off-by: Fedora Release Engineering --- python-rpm-generators.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 4955850..eaeda0f 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -5,7 +5,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 9 -Release: 1%{?dist} +Release: 2%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -49,6 +49,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} pythondeps.sh pythondistdeps.py %{_rpmconfigdir}/pythondistdeps.py %changelog +* Fri Jul 26 2019 Fedora Release Engineering - 9-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild + * Mon Jun 24 2019 Tomas Orsava - 9-1 - Canonicalize Python versions and properly handle != spec From ca811dbf35c1447694253a6c462efe9542d90056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Wed, 1 Jan 2020 23:17:07 +0100 Subject: [PATCH 014/110] Sync with upstream RPM - Handle version ending with ".*" - Handle compatible-release operator "~=" - Use rich deps for semantically versioned dependencies - Match Python version if minor has multiple digits (e.g. 3.10) - Only add setuptools requirement for egg-info packages https://github.com/rpm-software-management/rpm/pull/951 https://github.com/rpm-software-management/rpm/pull/973 https://github.com/rpm-software-management/rpm/pull/982 Fixes https://bugzilla.redhat.com/show_bug.cgi?id=1758141 Fixes https://bugzilla.redhat.com/show_bug.cgi?id=1777382 --- python-rpm-generators.spec | 11 +++++++++-- pythondistdeps.py | 38 ++++++++++++++++++++++++++++++++------ 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index eaeda0f..acc9d06 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -4,8 +4,8 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs -Version: 9 -Release: 2%{?dist} +Version: 10 +Release: 1%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -49,6 +49,13 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} pythondeps.sh pythondistdeps.py %{_rpmconfigdir}/pythondistdeps.py %changelog +* Wed Jan 01 2020 Miro Hrončok - 10-1 +- Handle version ending with ".*" (#1758141) +- Handle compatible-release operator "~=" (#1758141) +- Use rich deps for semantically versioned dependencies +- Match Python version if minor has multiple digits (e.g. 3.10, #1777382) +- Only add setuptools requirement for egg-info packages + * Fri Jul 26 2019 Fedora Release Engineering - 9-2 - Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild diff --git a/pythondistdeps.py b/pythondistdeps.py index 1d3535b..2572ac2 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -102,7 +102,7 @@ for f in files: lower.endswith('.egg-info') or \ lower.endswith('.dist-info'): # This import is very slow, so only do it if needed - from pkg_resources import Distribution, FileMetadata, PathMetadata, Requirement + from pkg_resources import Distribution, FileMetadata, PathMetadata, Requirement, parse_version dist_name = basename(f) if isdir(f): path_item = dirname(f) @@ -116,7 +116,7 @@ for f in files: # Try to parse the Python version from the path the metadata # resides at (e.g. /usr/lib/pythonX.Y/site-packages/...) import re - res = re.search(r"/python(?P\d+\.\d)/", path_item) + res = re.search(r"/python(?P\d+\.\d+)/", path_item) if res: dist.py_version = res.group('pyver') else: @@ -184,8 +184,10 @@ for f in files: depsextras.remove(dep) deps = depsextras # console_scripts/gui_scripts entry points need pkg_resources from setuptools - if (dist.get_entry_map('console_scripts') or - dist.get_entry_map('gui_scripts')): + if ((dist.get_entry_map('console_scripts') or + dist.get_entry_map('gui_scripts')) and + (lower.endswith('.egg') or + lower.endswith('.egg-info'))): # stick them first so any more specific requirement overrides it deps.insert(0, Requirement.parse('setuptools')) # add requires/recommends based on egg/dist metadata @@ -248,11 +250,35 @@ names.sort() for name in names: if py_deps[name]: # Print out versioned provides, requires, recommends, conflicts + spec_list = [] for spec in py_deps[name]: if spec[0] == '!=': - print('({n} < {v} or {n} >= {v}.0)'.format(n=name, v=spec[1])) + spec_list.append('{n} < {v} or {n} >= {v}.0'.format(n=name, v=spec[1])) + elif spec[0] == '~=': + # Parse the current version + next_ver = parse_version(spec[1]).base_version.split('.') + # Drop the micro version + next_ver = next_ver[0:-1] + # Increment the minor version + next_ver[-1] = str(int(next_ver[-1]) + 1) + next_ver = '.'.join(next_ver) + spec_list.append('{n} >= {v} with {n} < {vnext}'.format(n=name, v=spec[1], vnext=next_ver)) + elif spec[0] == '==' and spec[1].endswith('.*'): + # Parse the current version + next_ver = parse_version(spec[1]).base_version.split('.') + # Drop the micro version from both the version in spec and next_ver + next_ver = next_ver[0:-1] + spec = (spec[0], '.'.join(next_ver)) + # Increment the minor version + next_ver[-1] = str(int(next_ver[-1]) + 1) + next_ver = '.'.join(next_ver) + spec_list.append('{n} >= {v} with {n} < {vnext}'.format(n=name, v=spec[1], vnext=next_ver)) else: - print('{} {} {}'.format(name, spec[0], spec[1])) + spec_list.append('{} {} {}'.format(name, spec[0], spec[1])) + if len(spec_list) == 1: + print(spec_list[0]) + else: + print('({})'.format(' with '.join(spec_list))) else: # Print out unversioned provides, requires, recommends, conflicts print(name) From 724a52a5f219ce006a1c525f8df816e3050a3af7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Fri, 3 Jan 2020 11:00:19 +0100 Subject: [PATCH 015/110] Fix more complicated requirement expressions by adding parenthesis Puts bounded requirements into parenthesis Fixes: https://github.com/rpm-software-management/rpm/issues/995 Upstream: https://github.com/rpm-software-management/rpm/pull/996 For this input: pyparsing>=2.0.1,!=2.0.4,!=2.1.2,!=2.1.6 Instead of (invalid): (python3.8dist(pyparsing) >= 2.0.1 with python3.8dist(pyparsing) < 2.1.2 or python3.8dist(pyparsing) >= 2.1.2.0 with python3.8dist(pyparsing) < 2.1.6 or python3.8dist(pyparsing) >= 2.1.6.0 with python3.8dist(pyparsing) < 2.0.4 or python3.8dist(pyparsing) >= 2.0.4.0) Produces (valid): (python3.8dist(pyparsing) >= 2.0.1 with (python3.8dist(pyparsing) < 2.1.2 or python3.8dist(pyparsing) >= 2.1.2.0) with (python3.8dist(pyparsing) < 2.0.4 or python3.8dist(pyparsing) >= 2.0.4.0) with (python3.8dist(pyparsing) < 2.1.6 or python3.8dist(pyparsing) >= 2.1.6.0)) For this input: babel>=1.3,!=2.0 Instead of (invalid): (python3.8dist(babel) >= 1.3 with python3.8dist(babel) < 2 or python3.8dist(babel) >= 2.0) Produces (valid): (python3.8dist(babel) >= 1.3 with (python3.8dist(babel) < 2 or python3.8dist(babel) >= 2.0)) For this input: pbr!=2.1.0,>=2.0.0 Instead of (invalid): (python3.8dist(pbr) >= 2 with python3.8dist(pbr) < 2.1 or python3.8dist(pbr) >= 2.1.0) Produces (valid): (python3.8dist(pbr) >= 2 with (python3.8dist(pbr) < 2.1 or python3.8dist(pbr) >= 2.1.0)) --- python-rpm-generators.spec | 5 ++++- pythondistdeps.py | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index acc9d06..2af6e6d 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -5,7 +5,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 10 -Release: 1%{?dist} +Release: 2%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -49,6 +49,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} pythondeps.sh pythondistdeps.py %{_rpmconfigdir}/pythondistdeps.py %changelog +* Fri Jan 03 2020 Miro Hrončok - 10-2 +- Fix more complicated requirement expressions by adding parenthesis + * Wed Jan 01 2020 Miro Hrončok - 10-1 - Handle version ending with ".*" (#1758141) - Handle compatible-release operator "~=" (#1758141) diff --git a/pythondistdeps.py b/pythondistdeps.py index 2572ac2..da5f1a0 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -253,7 +253,7 @@ for name in names: spec_list = [] for spec in py_deps[name]: if spec[0] == '!=': - spec_list.append('{n} < {v} or {n} >= {v}.0'.format(n=name, v=spec[1])) + spec_list.append('({n} < {v} or {n} >= {v}.0)'.format(n=name, v=spec[1])) elif spec[0] == '~=': # Parse the current version next_ver = parse_version(spec[1]).base_version.split('.') @@ -262,7 +262,7 @@ for name in names: # Increment the minor version next_ver[-1] = str(int(next_ver[-1]) + 1) next_ver = '.'.join(next_ver) - spec_list.append('{n} >= {v} with {n} < {vnext}'.format(n=name, v=spec[1], vnext=next_ver)) + spec_list.append('({n} >= {v} with {n} < {vnext})'.format(n=name, v=spec[1], vnext=next_ver)) elif spec[0] == '==' and spec[1].endswith('.*'): # Parse the current version next_ver = parse_version(spec[1]).base_version.split('.') @@ -272,7 +272,7 @@ for name in names: # Increment the minor version next_ver[-1] = str(int(next_ver[-1]) + 1) next_ver = '.'.join(next_ver) - spec_list.append('{n} >= {v} with {n} < {vnext}'.format(n=name, v=spec[1], vnext=next_ver)) + spec_list.append('({n} >= {v} with {n} < {vnext})'.format(n=name, v=spec[1], vnext=next_ver)) else: spec_list.append('{} {} {}'.format(name, spec[0], spec[1])) if len(spec_list) == 1: From 7d819e0000e77820f5705406660b6e86b56a50e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Fri, 17 Jan 2020 17:27:09 +0100 Subject: [PATCH 016/110] Also provide pythonXdist() with PEP 503 normalized names (#1791530) That is, we add new provides that replace dots with a dash. Package that used to provide python3dist(zope.component) and python3.8dist(zope.component) now also provides python3dist(zope-component) and python3.8dist(zope-component). Package that used to provide python3dist(a.-.-.-.a) now provides python3dist(a-a) as well. This is consistent with pip behavior, `pip install zope-component` installs zope.component. Historically, we have always used dist.key (safe_name) from setuptools, but that is a non-standardized convention -- whether or not it replaces dots with dashes is not even documented. We say we use "canonical name" or "normalized name" everywhere, yet we didn't. We really need to follow the standard (PEP 503): https://www.python.org/dev/peps/pep-0503/#normalized-names The proper function here would be packaging.utils.canonicalize_name https://packaging.pypa.io/en/latest/utils/#packaging.utils.canonicalize_name -- we reimplement it here to avoid an external dependency. This is the first required step needed if we want to change our requirements later. If we decide we don't, for whatever reason, this doesn't break anything. --- python-rpm-generators.spec | 5 ++++- pythondistdeps.py | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 2af6e6d..ea6fb97 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -5,7 +5,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 10 -Release: 2%{?dist} +Release: 3%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -49,6 +49,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} pythondeps.sh pythondistdeps.py %{_rpmconfigdir}/pythondistdeps.py %changelog +* Fri Jan 17 2020 Miro Hrončok - 10-3 +- Also provide pythonXdist() with PEP 503 normalized names (#1791530) + * Fri Jan 03 2020 Miro Hrončok - 10-2 - Fix more complicated requirement expressions by adding parenthesis diff --git a/pythondistdeps.py b/pythondistdeps.py index da5f1a0..8756fdf 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -32,6 +32,11 @@ PyMajorVer_Deps = False legacy_Provides = False legacy = False +def normalize_name(name): + """https://www.python.org/dev/peps/pep-0503/#normalized-names""" + import re + return re.sub(r'[-_.]+', '-', name).lower() + for o, a in opts: if o in ('-h', '--help'): print('-h, --help\tPrint help') @@ -127,6 +132,12 @@ for f in files: import platform platform.python_version = lambda: dist.py_version + # This is the PEP 503 normalized name. + # It does also convert dots to dashes, unlike dist.key. + # In the current code, we only add additional provides with this. + # Later, we can start requiring them. + # See https://bugzilla.redhat.com/show_bug.cgi?id=1791530 + normalized_name = normalize_name(dist.project_name) if Provides_PyMajorVer_Variant or PyMajorVer_Deps or legacy_Provides or legacy: # Get the Python major version @@ -142,10 +153,16 @@ for f in files: name = 'python{}dist({})'.format(dist.py_version, dist.key) if name not in py_deps: py_deps[name] = [] + name_ = 'python{}dist({})'.format(dist.py_version, normalized_name) + if name_ not in py_deps: + py_deps[name_] = [] if Provides_PyMajorVer_Variant or PyMajorVer_Deps: pymajor_name = 'python{}dist({})'.format(pyver_major, dist.key) if pymajor_name not in py_deps: py_deps[pymajor_name] = [] + pymajor_name_ = 'python{}dist({})'.format(pyver_major, normalized_name) + if pymajor_name_ not in py_deps: + py_deps[pymajor_name_] = [] if legacy or legacy_Provides: legacy_name = 'pythonegg({})({})'.format(pyver_major, dist.key) if legacy_name not in py_deps: @@ -158,8 +175,12 @@ for f in files: if spec not in py_deps[name]: if not legacy: py_deps[name].append(spec) + if name != name_: + py_deps[name_].append(spec) if Provides_PyMajorVer_Variant: py_deps[pymajor_name].append(spec) + if pymajor_name != pymajor_name_: + py_deps[pymajor_name_].append(spec) if legacy or legacy_Provides: py_deps[legacy_name].append(spec) if Requires or (Recommends and dist.extras): From caccd3e498844d693f1604be6e4c65b7322c8e79 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Thu, 30 Jan 2020 15:05:48 +0000 Subject: [PATCH 017/110] - Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild Signed-off-by: Fedora Release Engineering --- python-rpm-generators.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index ea6fb97..8511c94 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -5,7 +5,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 10 -Release: 3%{?dist} +Release: 4%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -49,6 +49,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} pythondeps.sh pythondistdeps.py %{_rpmconfigdir}/pythondistdeps.py %changelog +* Thu Jan 30 2020 Fedora Release Engineering - 10-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild + * Fri Jan 17 2020 Miro Hrončok - 10-3 - Also provide pythonXdist() with PEP 503 normalized names (#1791530) From ff7b9b1ae0b81b07c6eb181cf8c58f321fae9d7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Wed, 1 Apr 2020 13:54:32 +0200 Subject: [PATCH 018/110] Reimplement pythondeps.sh as parametric macro generators pythondeps.sh was written in shell and unlike the Python dist generators, it uses no Python, it plainly determines the provide / requires from the path. As the script was run for every Python file, we were potentially doing hundreds of shelling outs to execute a script that calls grep and sed. In Lua, this is much more efficient. Some timings: https://github.com/rpm-software-management/rpm/pull/1153#issuecomment-607146356 Parametric macro generators require RPM 4.16+: https://fedoraproject.org/wiki/Changes/RPM-4.16 Fixes https://github.com/rpm-software-management/rpm/issues/1152 Upstream PR: https://github.com/rpm-software-management/rpm/pull/1153 Since this is intended for Fedora 33+ only, clean some old cruft. --- python-rpm-generators.spec | 24 ++++++++++-------------- python.attr | 28 ++++++++++++++++++++++++++-- pythondeps.sh | 32 -------------------------------- 3 files changed, 36 insertions(+), 48 deletions(-) delete mode 100755 pythondeps.sh diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 8511c94..3553018 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,11 +1,7 @@ -# Disable automatic bytecompilation. We install only one script and we will -# never "import" it. -%undefine py_auto_byte_compile - Name: python-rpm-generators Summary: Dependency generators for Python RPMs -Version: 10 -Release: 4%{?dist} +Version: 11 +Release: 1%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -14,8 +10,7 @@ Url: https://src.fedoraproject.org/python-rpm-generators Source0: https://raw.githubusercontent.com/rpm-software-management/rpm/102eab50b3d0d6546dfe082eac0ade21e6b3dbf1/COPYING Source1: python.attr Source2: pythondist.attr -Source3: pythondeps.sh -Source4: pythondistdeps.py +Source3: pythondistdeps.py BuildArch: noarch @@ -25,10 +20,8 @@ BuildArch: noarch %package -n python3-rpm-generators Summary: %{summary} Requires: python3-setuptools -# The point of split -Conflicts: rpm-build < 4.13.0.1-2 -# Breaking change, change a way how depgen is enabled -Conflicts: python-rpm-macros < 3-35 +# We have parametric macro generators, we need RPM 4.16 (4.15.90+ is 4.16 alpha) +Requires: rpm > 4.15.90-0 %description -n python3-rpm-generators %{summary}. @@ -39,16 +32,19 @@ cp -a %{sources} . %install install -Dpm0644 -t %{buildroot}%{_fileattrsdir} python.attr pythondist.attr -install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} pythondeps.sh pythondistdeps.py +install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} pythondistdeps.py %files -n python3-rpm-generators %license COPYING %{_fileattrsdir}/python.attr %{_fileattrsdir}/pythondist.attr -%{_rpmconfigdir}/pythondeps.sh %{_rpmconfigdir}/pythondistdeps.py %changelog +* Wed Apr 01 2020 Miro Hrončok - 11-1 +- Rewrite python(abi) generators to Lua to make them faster +- RPM 4.16+ is needed + * Thu Jan 30 2020 Fedora Release Engineering - 10-4 - Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild diff --git a/python.attr b/python.attr index f5d2dff..fc19439 100644 --- a/python.attr +++ b/python.attr @@ -1,4 +1,28 @@ -%__python_provides %{_rpmconfigdir}/pythondeps.sh --provides -%__python_requires %{_rpmconfigdir}/pythondeps.sh --requires +%__python_provides() %{lua: + -- Match buildroot/payload paths of the form + -- /PATH/OF/BUILDROOT/usr/bin/pythonMAJOR.MINOR + -- generating a line of the form + -- python(abi) = MAJOR.MINOR + -- (Don't match against -config tools e.g. /usr/bin/python2.6-config) + local path = rpm.expand('%1') + if path:match('/usr/bin/python%d+%.%d+$') then + provides = path:gsub('.*/usr/bin/python(%d+%.%d+)', 'python(abi) = %1') + print(provides) + end +} + +%__python_requires() %{lua: + -- Match buildroot paths of the form + -- /PATH/OF/BUILDROOT/usr/lib/pythonMAJOR.MINOR/ and + -- /PATH/OF/BUILDROOT/usr/lib64/pythonMAJOR.MINOR/ + -- generating a line of the form: + -- python(abi) = MAJOR.MINOR + local path = rpm.expand('%1') + if path:match('/usr/lib%d*/python%d+%.%d+/.*') then + requires = path:gsub('.*/usr/lib%d*/python(%d+%.%d+)/.*', 'python(abi) = %1') + print(requires) + end +} + %__python_path ^((/usr/lib(64)?/python[[:digit:]]\\.[[:digit:]]+/.*\\.(py[oc]?|so))|(^%{_bindir}/python[[:digit:]]\\.[[:digit:]]+))$ %__python_magic [Pp]ython.*(executable|byte-compiled) diff --git a/pythondeps.sh b/pythondeps.sh deleted file mode 100755 index 10a060a..0000000 --- a/pythondeps.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash - -[ $# -ge 1 ] || { - cat > /dev/null - exit 0 -} - -case $1 in --P|--provides) - shift - # Match buildroot/payload paths of the form - # /PATH/OF/BUILDROOT/usr/bin/pythonMAJOR.MINOR - # generating a line of the form - # python(abi) = MAJOR.MINOR - # (Don't match against -config tools e.g. /usr/bin/python2.6-config) - grep "/usr/bin/python.\..$" \ - | sed -e "s|.*/usr/bin/python\(.\..\)|python(abi) = \1|" - ;; --R|--requires) - shift - # Match buildroot paths of the form - # /PATH/OF/BUILDROOT/usr/lib/pythonMAJOR.MINOR/ and - # /PATH/OF/BUILDROOT/usr/lib64/pythonMAJOR.MINOR/ - # generating (uniqely) lines of the form: - # python(abi) = MAJOR.MINOR - grep "/usr/lib[^/]*/python.\../.*" \ - | sed -e "s|.*/usr/lib[^/]*/python\(.\..\)/.*|python(abi) = \1|g" \ - | sort | uniq - ;; -esac - -exit 0 From 486ca7e54086be114e88c326215d835c7791c731 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Wed, 1 Apr 2020 15:57:00 +0200 Subject: [PATCH 019/110] Drop tabs from python.attr --- python.attr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python.attr b/python.attr index fc19439..f4442b7 100644 --- a/python.attr +++ b/python.attr @@ -24,5 +24,5 @@ end } -%__python_path ^((/usr/lib(64)?/python[[:digit:]]\\.[[:digit:]]+/.*\\.(py[oc]?|so))|(^%{_bindir}/python[[:digit:]]\\.[[:digit:]]+))$ -%__python_magic [Pp]ython.*(executable|byte-compiled) +%__python_path ^((/usr/lib(64)?/python[[:digit:]]\\.[[:digit:]]+/.*\\.(py[oc]?|so))|(^%{_bindir}/python[[:digit:]]\\.[[:digit:]]+))$ +%__python_magic [Pp]ython.*(executable|byte-compiled) From eae8dd0f572003a7bf0555a552ed7be3ad5fbfdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Fri, 3 Apr 2020 14:00:49 +0200 Subject: [PATCH 020/110] Add CI tests for python(abi) provides --- tests/pythonabi.sh | 16 ++++++++++++++++ tests/pythonabi.spec | 43 +++++++++++++++++++++++++++++++++++++++++++ tests/tests.yml | 21 +++++++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100755 tests/pythonabi.sh create mode 100644 tests/pythonabi.spec create mode 100644 tests/tests.yml diff --git a/tests/pythonabi.sh b/tests/pythonabi.sh new file mode 100755 index 0000000..ba7a87d --- /dev/null +++ b/tests/pythonabi.sh @@ -0,0 +1,16 @@ +#!/usr/bin/bash -eux +rpmbuild -ba pythonabi.spec + +PYVER=$(rpm --eval '%python3_version') +RPMDIR=$(rpm --eval '%_topdir')/RPMS +ARCH=$(rpm --eval '%_arch') +ABI='^python(abi) = '${PYVER}'$' + +rpm -qp --provides ${RPMDIR}/${ARCH}/python-interpreter-0-0.${ARCH}.rpm | grep "${ABI}" +rpm -qp --requires ${RPMDIR}/${ARCH}/python-interpreter-0-0.${ARCH}.rpm | grep -v "${ABI}" + +rpm -qp --requires ${RPMDIR}/${ARCH}/python-arched-0-0.${ARCH}.rpm | grep "${ABI}" +rpm -qp --provides ${RPMDIR}/${ARCH}/python-arched-0-0.${ARCH}.rpm | grep -v "${ABI}" + +rpm -qp --requires ${RPMDIR}/noarch/python-noarch-0-0.noarch.rpm | grep "${ABI}" +rpm -qp --provides ${RPMDIR}/noarch/python-noarch-0-0.noarch.rpm | grep -v "${ABI}" diff --git a/tests/pythonabi.spec b/tests/pythonabi.spec new file mode 100644 index 0000000..88b312d --- /dev/null +++ b/tests/pythonabi.spec @@ -0,0 +1,43 @@ +Name: pythonabi +Version: 0 +Release: 0 +Summary: ... +License: MIT +BuildRequires: python3-devel + +%description +... + +%install +mkdir -p %{buildroot}%{python3_sitelib} +mkdir -p %{buildroot}%{python3_sitearch} +mkdir -p %{buildroot}%{_bindir} +echo "print()" > %{buildroot}%{python3_sitelib}/file.py +cp %{python3_sitearch}/../lib-dynload/cmath.*.so %{buildroot}%{python3_sitearch}/file.so +cp %{_bindir}/python%{python3_version} %{buildroot}%{_bindir}/python%{python3_version} + + +%package -n python-noarch +Summary: ... +BuildArch: noarch +%description -n python-noarch +... +%files -n python-noarch +%pycached %{python3_sitelib}/file.py + + +%package -n python-arched +Summary: ... +%description -n python-arched +... +%files -n python-arched +%{python3_sitearch}/file.so + + +%package -n python-interpreter +Summary: ... +%description -n python-interpreter +... +%files -n python-interpreter +%{_bindir}/python%{python3_version} + diff --git a/tests/tests.yml b/tests/tests.yml new file mode 100644 index 0000000..5649fa2 --- /dev/null +++ b/tests/tests.yml @@ -0,0 +1,21 @@ +--- +- hosts: localhost + tags: + - classic + tasks: + - dnf: + name: "*" + state: latest + +- hosts: localhost + roles: + - role: standard-test-basic + tags: + - classic + tests: + - pythonabi: + dir: . + run: ./pythonabi.sh + required_packages: + - rpm-build + - python3-devel From bbfe4930d9af5bf55847c51be645779bbb9c92a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Thu, 5 Mar 2020 23:40:17 +0100 Subject: [PATCH 021/110] Automatically call %python_provide This allows us to drop the %python_provide macro from most spec files, except where we want to use it for virtual provides or empty packages. --- python-rpm-generators.spec | 9 ++++-- pythonname.attr | 20 ++++++++++++ tests/pythonname.sh | 28 +++++++++++++++++ tests/pythonname.spec | 62 ++++++++++++++++++++++++++++++++++++++ tests/tests.yml | 3 ++ 5 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 pythonname.attr create mode 100755 tests/pythonname.sh create mode 100644 tests/pythonname.spec diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 3553018..292a014 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -10,7 +10,8 @@ Url: https://src.fedoraproject.org/python-rpm-generators Source0: https://raw.githubusercontent.com/rpm-software-management/rpm/102eab50b3d0d6546dfe082eac0ade21e6b3dbf1/COPYING Source1: python.attr Source2: pythondist.attr -Source3: pythondistdeps.py +Source3: pythonname.attr +Source4: pythondistdeps.py BuildArch: noarch @@ -22,6 +23,8 @@ Summary: %{summary} Requires: python3-setuptools # We have parametric macro generators, we need RPM 4.16 (4.15.90+ is 4.16 alpha) Requires: rpm > 4.15.90-0 +# We use %%python_provide +Requires: python-rpm-macros %description -n python3-rpm-generators %{summary}. @@ -31,19 +34,21 @@ Requires: rpm > 4.15.90-0 cp -a %{sources} . %install -install -Dpm0644 -t %{buildroot}%{_fileattrsdir} python.attr pythondist.attr +install -Dpm0644 -t %{buildroot}%{_fileattrsdir} *.attr install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} pythondistdeps.py %files -n python3-rpm-generators %license COPYING %{_fileattrsdir}/python.attr %{_fileattrsdir}/pythondist.attr +%{_fileattrsdir}/pythonname.attr %{_rpmconfigdir}/pythondistdeps.py %changelog * Wed Apr 01 2020 Miro Hrončok - 11-1 - Rewrite python(abi) generators to Lua to make them faster - RPM 4.16+ is needed +- Automatically call %%python_provide * Thu Jan 30 2020 Fedora Release Engineering - 10-4 - Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild diff --git a/pythonname.attr b/pythonname.attr new file mode 100644 index 0000000..b086549 --- /dev/null +++ b/pythonname.attr @@ -0,0 +1,20 @@ +%__pythonname_provides() %{lua: + -- this macro is called for each file in a package, the path being in %1 + -- but we don't need to know the path, so we would get for each file: Macro %1 defined but not used within scope + -- in here, we expand %name conditionally on %1 to suppress the warning + local name = rpm.expand('%{?1:%{name}}') + -- a structure that knows what names were already processed, so we can end early + if __pythonname_beenthere == nil then + __pythonname_beenthere = {} + end + -- we save ourselves a trip to %python_provide if we have already been there + if __pythonname_beenthere[name] == nil then + local python_provide = rpm.expand('%{?python_provide:%python_provide %{name}}') + for provides in python_provide:gmatch('Provides:[ \\t]+([^\\n]+)') do + print(provides .. " ") + end + __pythonname_beenthere[name] = true + end +} + +%__pythonname_path ^/ diff --git a/tests/pythonname.sh b/tests/pythonname.sh new file mode 100755 index 0000000..272016e --- /dev/null +++ b/tests/pythonname.sh @@ -0,0 +1,28 @@ +#!/usr/bin/bash -eux +rpmbuild -ba pythonname.spec + +XY=$(rpm --eval '%python3_version_nodots') +RPMDIR=$(rpm --eval '%_topdir')/RPMS/noarch + +echo "Provides for python${XY}-foo" +rpm -qp --provides ${RPMDIR}/python${XY}-foo-0-0.noarch.rpm +rpm -qp --provides ${RPMDIR}/python${XY}-foo-0-0.noarch.rpm | grep -q '^python-foo = 0-0$' +rpm -qp --provides ${RPMDIR}/python${XY}-foo-0-0.noarch.rpm | grep -q '^python3-foo = 0-0$' + +echo "Provides for python3-foo" +rpm -qp --provides ${RPMDIR}/python3-foo-0-0.noarch.rpm +rpm -qp --provides ${RPMDIR}/python3-foo-0-0.noarch.rpm | grep -q '^python-foo = 0-0$' +rpm -qp --provides ${RPMDIR}/python3-foo-0-0.noarch.rpm | grep -q '^python'${XY}'-foo = 0-0$' + +echo "Provides for python2-foo" +rpm -qp --provides ${RPMDIR}/python2-foo-0-0.noarch.rpm +rpm -qp --provides ${RPMDIR}/python2-foo-0-0.noarch.rpm | grep -vq '^python-foo = 0-0$' + +echo "Provides for python-foo" +rpm -qp --provides ${RPMDIR}/python-foo-0-0.noarch.rpm +rpm -qp --provides ${RPMDIR}/python-foo-0-0.noarch.rpm | grep -vq '^python2-foo = 0-0$' + +echo "Provides for python35-foo" +rpm -qp --provides ${RPMDIR}/python35-foo-0-0.noarch.rpm +rpm -qp --provides ${RPMDIR}/python35-foo-0-0.noarch.rpm | grep -vq '^python-foo = 0-0$' +rpm -qp --provides ${RPMDIR}/python35-foo-0-0.noarch.rpm | grep -vq '^python3-foo = 0-0$' diff --git a/tests/pythonname.spec b/tests/pythonname.spec new file mode 100644 index 0000000..b4a3f6d --- /dev/null +++ b/tests/pythonname.spec @@ -0,0 +1,62 @@ +Name: pythonname +Version: 0 +Release: 0 +Summary: ... +License: MIT +BuildArch: noarch + +%description +... + +%install +touch %{buildroot}/something +touch %{buildroot}/something_else +touch %{buildroot}/something_completely_different + + +%package -n python-foo +Summary: ... +%description -n python-foo +... +%files -n python-foo +/* + + +%package -n python2-foo +Summary: ... +%description -n python2-foo +... +%files -n python2-foo +/* + + +%package -n python3-foo +Summary: ... +%description -n python3-foo +... +%files -n python3-foo +/* + + +%package -n python%{python3_version_nodots}-foo +Summary: ... +%description -n python%{python3_version_nodots}-foo +... +%files -n python%{python3_version_nodots}-foo +/* + + +%package -n python35-foo +Summary: ... +%description -n python35-foo +... +%files -n python35-foo +/* + + +%package -n ruby-foo +Summary: ... +%description -n ruby-foo +... +%files -n ruby-foo +/* diff --git a/tests/tests.yml b/tests/tests.yml index 5649fa2..cceb9b4 100644 --- a/tests/tests.yml +++ b/tests/tests.yml @@ -16,6 +16,9 @@ - pythonabi: dir: . run: ./pythonabi.sh + - pythonname: + dir: . + run: ./pythonname.sh required_packages: - rpm-build - python3-devel From 8eef42cbaa6ff0e5c006959fc06ec115ed5ca37b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Tue, 7 Apr 2020 14:41:51 +0200 Subject: [PATCH 022/110] Use dynamic %_prefix value when matching files for python(abi) provides See https://lists.fedoraproject.org/archives/list/packaging@lists.fedoraproject.org/thread/UFKUM5UKCTNGIT3KJVYEI5VXPI23QMBN/ Flatpak builds redefine %_prefix and the dependencies should remain present. Also get rid of one useless ^ and prep the pattern for two digit Python major versions. Add a test that tests that we match our default %_prefix (was the case even before this commit). --- python-rpm-generators.spec | 5 ++++- python.attr | 2 +- tests/pythonabi.sh | 3 +++ tests/pythonabi.spec | 23 +++++++++++++++++++++++ 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 292a014..2388507 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 11 -Release: 1%{?dist} +Release: 2%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -45,6 +45,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} pythondistdeps.py %{_rpmconfigdir}/pythondistdeps.py %changelog +* Tue Apr 07 2020 Miro Hrončok - 11-2 +- Use dynamic %%_prefix value when matching files for python(abi) provides + * Wed Apr 01 2020 Miro Hrončok - 11-1 - Rewrite python(abi) generators to Lua to make them faster - RPM 4.16+ is needed diff --git a/python.attr b/python.attr index f4442b7..5a6be24 100644 --- a/python.attr +++ b/python.attr @@ -24,5 +24,5 @@ end } -%__python_path ^((/usr/lib(64)?/python[[:digit:]]\\.[[:digit:]]+/.*\\.(py[oc]?|so))|(^%{_bindir}/python[[:digit:]]\\.[[:digit:]]+))$ +%__python_path ^((%{_prefix}/lib(64)?/python[[:digit:]]+\\.[[:digit:]]+/.*\\.(py[oc]?|so))|(%{_bindir}/python[[:digit:]]+\\.[[:digit:]]+))$ %__python_magic [Pp]ython.*(executable|byte-compiled) diff --git a/tests/pythonabi.sh b/tests/pythonabi.sh index ba7a87d..28eff53 100755 --- a/tests/pythonabi.sh +++ b/tests/pythonabi.sh @@ -14,3 +14,6 @@ rpm -qp --provides ${RPMDIR}/${ARCH}/python-arched-0-0.${ARCH}.rpm | grep -v "${ rpm -qp --requires ${RPMDIR}/noarch/python-noarch-0-0.noarch.rpm | grep "${ABI}" rpm -qp --provides ${RPMDIR}/noarch/python-noarch-0-0.noarch.rpm | grep -v "${ABI}" + +rpm -qp --provides ${RPMDIR}/${ARCH}/python-misplaced-interpreter-0-0.${ARCH}.rpm | grep -v "${ABI}" +rpm -qp --requires ${RPMDIR}/noarch/python-misplaced-library-0-0.noarch.rpm | grep -v "${ABI}" diff --git a/tests/pythonabi.spec b/tests/pythonabi.spec index 88b312d..4f5e477 100644 --- a/tests/pythonabi.spec +++ b/tests/pythonabi.spec @@ -10,11 +10,18 @@ BuildRequires: python3-devel %install mkdir -p %{buildroot}%{python3_sitelib} +mkdir -p %{buildroot}/opt%{python3_sitelib} mkdir -p %{buildroot}%{python3_sitearch} mkdir -p %{buildroot}%{_bindir} +mkdir -p %{buildroot}/opt%{_bindir} + echo "print()" > %{buildroot}%{python3_sitelib}/file.py +echo "print()" > %{buildroot}/opt%{python3_sitelib}/file.py + cp %{python3_sitearch}/../lib-dynload/cmath.*.so %{buildroot}%{python3_sitearch}/file.so + cp %{_bindir}/python%{python3_version} %{buildroot}%{_bindir}/python%{python3_version} +cp %{_bindir}/python%{python3_version} %{buildroot}/opt%{_bindir}/python%{python3_version} %package -n python-noarch @@ -41,3 +48,19 @@ Summary: ... %files -n python-interpreter %{_bindir}/python%{python3_version} + +%package -n python-misplaced-library +Summary: ... +BuildArch: noarch +%description -n python-misplaced-library +... +%files -n python-misplaced-library +%pycached /opt%{python3_sitelib}/file.py + + +%package -n python-misplaced-interpreter +Summary: ... +%description -n python-misplaced-interpreter +... +%files -n python-misplaced-interpreter +/opt%{_bindir}/python%{python3_version} From 783dcc71471c6544e4cb89cef35b78be735f0a20 Mon Sep 17 00:00:00 2001 From: Igor Raits Date: Fri, 10 Apr 2020 07:41:01 +0200 Subject: [PATCH 023/110] Sync with upstream RPM dist generator --- python-rpm-generators.spec | 1 + pythondistdeps.py | 135 +++++++++++++++++++++++++++++-------- 2 files changed, 109 insertions(+), 27 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 2388507..d5c8969 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -47,6 +47,7 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} pythondistdeps.py %changelog * Tue Apr 07 2020 Miro Hrončok - 11-2 - Use dynamic %%_prefix value when matching files for python(abi) provides +- Sync with upstream RPM dist generator * Wed Apr 01 2020 Miro Hrončok - 11-1 - Rewrite python(abi) generators to Lua to make them faster diff --git a/pythondistdeps.py b/pythondistdeps.py index 8756fdf..28e2d27 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -18,6 +18,113 @@ from distutils.sysconfig import get_python_lib from warnings import warn +class RpmVersion(): + def __init__(self, version_id): + version = parse_version(version_id) + if isinstance(version._version, str): + self.version = version._version + else: + self.epoch = version._version.epoch + self.version = list(version._version.release) + self.pre = version._version.pre + self.dev = version._version.dev + self.post = version._version.post + + def increment(self): + self.version[-1] += 1 + self.pre = None + self.dev = None + self.post = None + return self + + def __str__(self): + if isinstance(self.version, str): + return self.version + if self.epoch: + rpm_epoch = str(self.epoch) + ':' + else: + rpm_epoch = '' + while self.version[-1] == 0: + self.version.pop() + rpm_version = '.'.join(str(x) for x in self.version) + if self.pre: + rpm_suffix = '~{}'.format(''.join(str(x) for x in self.pre)) + elif self.dev: + rpm_suffix = '~{}'.format(''.join(str(x) for x in self.dev)) + elif self.post: + rpm_suffix = '^post{}'.format(self.post[1]) + else: + rpm_suffix = '' + return '{}{}{}'.format(rpm_epoch, rpm_version, rpm_suffix) + +def convert_compatible(name, operator, version_id): + if version_id.endswith('.*'): + print('Invalid requirement: {} {} {}'.format(name, operator, version_id)) + exit(65) # os.EX_DATAERR + version = RpmVersion(version_id) + if len(version.version) == 1: + print('Invalid requirement: {} {} {}'.format(name, operator, version_id)) + exit(65) # os.EX_DATAERR + upper_version = RpmVersion(version_id) + upper_version.version.pop() + upper_version.increment() + return '({} >= {} with {} < {})'.format( + name, version, name, upper_version) + +def convert_equal(name, operator, version_id): + if version_id.endswith('.*'): + version_id = version_id[:-2] + '.0' + return convert_compatible(name, '~=', version_id) + version = RpmVersion(version_id) + return '{} = {}'.format(name, version) + +def convert_arbitrary_equal(name, operator, version_id): + if version_id.endswith('.*'): + print('Invalid requirement: {} {} {}'.format(name, operator, version_id)) + exit(65) # os.EX_DATAERR + version = RpmVersion(version_id) + return '{} = {}'.format(name, version) + +def convert_not_equal(name, operator, version_id): + if version_id.endswith('.*'): + version_id = version_id[:-2] + version = RpmVersion(version_id) + lower_version = RpmVersion(version_id).increment() + else: + version = RpmVersion(version_id) + lower_version = version + return '({} < {} or {} > {})'.format( + name, version, name, lower_version) + +def convert_ordered(name, operator, version_id): + if version_id.endswith('.*'): + # PEP 440 does not define semantics for prefix matching + # with ordered comparisons + version_id = version_id[:-2] + version = RpmVersion(version_id) + if '>' == operator: + # distutils does not behave this way, but this is + # their recommendation + # https://mail.python.org/archives/list/distutils-sig@python.org/thread/NWEQVTCX5CR2RKW2LT4H77PJTEINSX7P/ + operator = '>=' + version.increment() + else: + version = RpmVersion(version_id) + return '{} {} {}'.format(name, operator, version) + +OPERATORS = {'~=': convert_compatible, + '==': convert_equal, + '===': convert_arbitrary_equal, + '!=': convert_not_equal, + '<=': convert_ordered, + '<': convert_ordered, + '>=': convert_ordered, + '>': convert_ordered} + +def convert(name, operator, version_id): + return OPERATORS[operator](name, operator, version_id) + + opts, args = getopt( argv[1:], 'hPRrCEMmLl:', ['help', 'provides', 'requires', 'recommends', 'conflicts', 'extras', 'majorver-provides', 'majorver-only', 'legacy-provides' , 'legacy']) @@ -169,8 +276,6 @@ for f in files: py_deps[legacy_name] = [] if dist.version: version = dist.version - while version.endswith('.0'): - version = version[:-2] spec = ('==', version) if spec not in py_deps[name]: if not legacy: @@ -221,8 +326,6 @@ for f in files: else: name = 'python{}dist({})'.format(dist.py_version, dep.key) for spec in dep.specs: - while spec[1].endswith('.0'): - spec = (spec[0], spec[1][:-2]) if name not in py_deps: py_deps[name] = [] if spec not in py_deps[name]: @@ -273,29 +376,7 @@ for name in names: # Print out versioned provides, requires, recommends, conflicts spec_list = [] for spec in py_deps[name]: - if spec[0] == '!=': - spec_list.append('({n} < {v} or {n} >= {v}.0)'.format(n=name, v=spec[1])) - elif spec[0] == '~=': - # Parse the current version - next_ver = parse_version(spec[1]).base_version.split('.') - # Drop the micro version - next_ver = next_ver[0:-1] - # Increment the minor version - next_ver[-1] = str(int(next_ver[-1]) + 1) - next_ver = '.'.join(next_ver) - spec_list.append('({n} >= {v} with {n} < {vnext})'.format(n=name, v=spec[1], vnext=next_ver)) - elif spec[0] == '==' and spec[1].endswith('.*'): - # Parse the current version - next_ver = parse_version(spec[1]).base_version.split('.') - # Drop the micro version from both the version in spec and next_ver - next_ver = next_ver[0:-1] - spec = (spec[0], '.'.join(next_ver)) - # Increment the minor version - next_ver[-1] = str(int(next_ver[-1]) + 1) - next_ver = '.'.join(next_ver) - spec_list.append('({n} >= {v} with {n} < {vnext})'.format(n=name, v=spec[1], vnext=next_ver)) - else: - spec_list.append('{} {} {}'.format(name, spec[0], spec[1])) + spec_list.append(convert(name, spec[0], spec[1])) if len(spec_list) == 1: print(spec_list[0]) else: From 0ec858103701d4ba4e67612ea49316458494306b Mon Sep 17 00:00:00 2001 From: Gordon Messmer Date: Sun, 19 Apr 2020 14:24:00 -0700 Subject: [PATCH 024/110] Handle all-zero versions without crashing From https://github.com/rpm-software-management/rpm/pull/1184 --- python-rpm-generators.spec | 5 ++++- pythondistdeps.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index d5c8969..159176c 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 11 -Release: 2%{?dist} +Release: 3%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -45,6 +45,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} pythondistdeps.py %{_rpmconfigdir}/pythondistdeps.py %changelog +* Mon Apr 20 2020 Gordon Messmer - 11-3 +- Handle all-zero versions without crashing + * Tue Apr 07 2020 Miro Hrončok - 11-2 - Use dynamic %%_prefix value when matching files for python(abi) provides - Sync with upstream RPM dist generator diff --git a/pythondistdeps.py b/pythondistdeps.py index 28e2d27..47a40b3 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -44,7 +44,7 @@ class RpmVersion(): rpm_epoch = str(self.epoch) + ':' else: rpm_epoch = '' - while self.version[-1] == 0: + while len(self.version) > 1 and self.version[-1] == 0: self.version.pop() rpm_version = '.'.join(str(x) for x in self.version) if self.pre: From c8249102ec0100654f5a9cdcbc9e25923df04659 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Tue, 28 Apr 2020 14:47:32 +0200 Subject: [PATCH 025/110] Don't define global Lua variables from Python generator --- python-rpm-generators.spec | 5 ++++- python.attr | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 159176c..e446519 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 11 -Release: 3%{?dist} +Release: 4%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -45,6 +45,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} pythondistdeps.py %{_rpmconfigdir}/pythondistdeps.py %changelog +* Tue Apr 28 2020 Miro Hrončok - 11-4 +- Don't define global Lua variables from Python generator + * Mon Apr 20 2020 Gordon Messmer - 11-3 - Handle all-zero versions without crashing diff --git a/python.attr b/python.attr index 5a6be24..4000019 100644 --- a/python.attr +++ b/python.attr @@ -6,7 +6,7 @@ -- (Don't match against -config tools e.g. /usr/bin/python2.6-config) local path = rpm.expand('%1') if path:match('/usr/bin/python%d+%.%d+$') then - provides = path:gsub('.*/usr/bin/python(%d+%.%d+)', 'python(abi) = %1') + local provides = path:gsub('.*/usr/bin/python(%d+%.%d+)', 'python(abi) = %1') print(provides) end } @@ -19,7 +19,7 @@ -- python(abi) = MAJOR.MINOR local path = rpm.expand('%1') if path:match('/usr/lib%d*/python%d+%.%d+/.*') then - requires = path:gsub('.*/usr/lib%d*/python(%d+%.%d+)/.*', 'python(abi) = %1') + local requires = path:gsub('.*/usr/lib%d*/python(%d+%.%d+)/.*', 'python(abi) = %1') print(requires) end } From 1639424a5116e4a83c1d520678759b602dad4e30 Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Thu, 30 Apr 2020 15:57:15 +0200 Subject: [PATCH 026/110] Sync with upstream RPM dist generator --- pythondistdeps.py | 138 ++++++++++++++++++++-------------------------- 1 file changed, 59 insertions(+), 79 deletions(-) diff --git a/pythondistdeps.py b/pythondistdeps.py index 47a40b3..31b4737 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -3,6 +3,7 @@ # # Copyright 2010 Per Øyvind Karlsen # Copyright 2015 Neal Gompa +# Copyright 2020 SUSE LLC # # This program is free software. It may be redistributed and/or modified under # the terms of the LGPL version 2.1 (or later). @@ -11,7 +12,7 @@ # from __future__ import print_function -from getopt import getopt +import argparse from os.path import basename, dirname, isdir, sep from sys import argv, stdin, version from distutils.sysconfig import get_python_lib @@ -57,20 +58,22 @@ class RpmVersion(): rpm_suffix = '' return '{}{}{}'.format(rpm_epoch, rpm_version, rpm_suffix) + def convert_compatible(name, operator, version_id): if version_id.endswith('.*'): print('Invalid requirement: {} {} {}'.format(name, operator, version_id)) - exit(65) # os.EX_DATAERR + exit(65) # os.EX_DATAERR version = RpmVersion(version_id) if len(version.version) == 1: print('Invalid requirement: {} {} {}'.format(name, operator, version_id)) - exit(65) # os.EX_DATAERR + exit(65) # os.EX_DATAERR upper_version = RpmVersion(version_id) upper_version.version.pop() upper_version.increment() return '({} >= {} with {} < {})'.format( name, version, name, upper_version) + def convert_equal(name, operator, version_id): if version_id.endswith('.*'): version_id = version_id[:-2] + '.0' @@ -78,13 +81,15 @@ def convert_equal(name, operator, version_id): version = RpmVersion(version_id) return '{} = {}'.format(name, version) + def convert_arbitrary_equal(name, operator, version_id): if version_id.endswith('.*'): print('Invalid requirement: {} {} {}'.format(name, operator, version_id)) - exit(65) # os.EX_DATAERR + exit(65) # os.EX_DATAERR version = RpmVersion(version_id) return '{} = {}'.format(name, version) + def convert_not_equal(name, operator, version_id): if version_id.endswith('.*'): version_id = version_id[:-2] @@ -96,6 +101,7 @@ def convert_not_equal(name, operator, version_id): return '({} < {} or {} > {})'.format( name, version, name, lower_version) + def convert_ordered(name, operator, version_id): if version_id.endswith('.*'): # PEP 440 does not define semantics for prefix matching @@ -112,81 +118,46 @@ def convert_ordered(name, operator, version_id): version = RpmVersion(version_id) return '{} {} {}'.format(name, operator, version) + OPERATORS = {'~=': convert_compatible, '==': convert_equal, '===': convert_arbitrary_equal, '!=': convert_not_equal, '<=': convert_ordered, - '<': convert_ordered, + '<': convert_ordered, '>=': convert_ordered, - '>': convert_ordered} + '>': convert_ordered} + def convert(name, operator, version_id): return OPERATORS[operator](name, operator, version_id) -opts, args = getopt( - argv[1:], 'hPRrCEMmLl:', - ['help', 'provides', 'requires', 'recommends', 'conflicts', 'extras', 'majorver-provides', 'majorver-only', 'legacy-provides' , 'legacy']) - -Provides = False -Requires = False -Recommends = False -Conflicts = False -Extras = False -Provides_PyMajorVer_Variant = False -PyMajorVer_Deps = False -legacy_Provides = False -legacy = False - def normalize_name(name): """https://www.python.org/dev/peps/pep-0503/#normalized-names""" import re return re.sub(r'[-_.]+', '-', name).lower() -for o, a in opts: - if o in ('-h', '--help'): - print('-h, --help\tPrint help') - print('-P, --provides\tPrint Provides') - print('-R, --requires\tPrint Requires') - print('-r, --recommends\tPrint Recommends') - print('-C, --conflicts\tPrint Conflicts') - print('-E, --extras\tPrint Extras ') - print('-M, --majorver-provides\tPrint extra Provides with Python major version only') - print('-m, --majorver-only\tPrint Provides/Requires with Python major version only') - print('-L, --legacy-provides\tPrint extra legacy pythonegg Provides') - print('-l, --legacy\tPrint legacy pythonegg Provides/Requires instead') - exit(1) - elif o in ('-P', '--provides'): - Provides = True - elif o in ('-R', '--requires'): - Requires = True - elif o in ('-r', '--recommends'): - Recommends = True - elif o in ('-C', '--conflicts'): - Conflicts = True - elif o in ('-E', '--extras'): - Extras = True - elif o in ('-M', '--majorver-provides'): - Provides_PyMajorVer_Variant = True - elif o in ('-m', '--majorver-only'): - PyMajorVer_Deps = True - elif o in ('-L', '--legacy-provides'): - legacy_Provides = True - elif o in ('-l', '--legacy'): - legacy = True -if Requires: - py_abi = True -else: - py_abi = False +parser = argparse.ArgumentParser(prog=argv[0]) +group = parser.add_mutually_exclusive_group(required=True) +group.add_argument('-P', '--provides', action='store_true', help='Print Provides') +group.add_argument('-R', '--requires', action='store_true', help='Print Requires') +group.add_argument('-r', '--recommends', action='store_true', help='Print Recommends') +group.add_argument('-C', '--conflicts', action='store_true', help='Print Conflicts') +group.add_argument('-E', '--extras', action='store_true', help='Print Extras') +parser.add_argument('-M', '--majorver-provides', action='store_true', help='Print extra Provides with Python major version only') +parser.add_argument('-m', '--majorver-only', action='store_true', help='Print Provides/Requires with Python major version only') +parser.add_argument('-L', '--legacy-provides', action='store_true', help='Print extra legacy pythonegg Provides') +parser.add_argument('-l', '--legacy', action='store_true', help='Print legacy pythonegg Provides/Requires instead') +parser.add_argument('files', nargs=argparse.REMAINDER) +args = parser.parse_args() + +py_abi = args.requires py_deps = {} -if args: - files = args -else: - files = stdin.readlines() -for f in files: + +for f in (args.files or stdin.readlines()): f = f.strip() lower = f.lower() name = 'python(abi)' @@ -235,7 +206,16 @@ for f in files: warn("Version for {!r} has not been found".format(dist), RuntimeWarning) continue - # XXX: https://github.com/pypa/setuptools/pull/1275 + # pkg_resources use platform.python_version to evaluate if a + # dependency is relevant based on environment markers [1], + # e.g. requirement `argparse;python_version<"2.7"` + # + # Since we're running this script on one Python version while + # possibly evaluating packages for different versions, we mock the + # platform.python_version function. Discussed upstream [2]. + # + # [1] https://www.python.org/dev/peps/pep-0508/#environment-markers + # [2] https://github.com/pypa/setuptools/pull/1275 import platform platform.python_version = lambda: dist.py_version @@ -246,31 +226,31 @@ for f in files: # See https://bugzilla.redhat.com/show_bug.cgi?id=1791530 normalized_name = normalize_name(dist.project_name) - if Provides_PyMajorVer_Variant or PyMajorVer_Deps or legacy_Provides or legacy: + if args.majorver_provides or args.majorver_only or args.legacy_provides or args.legacy: # Get the Python major version pyver_major = dist.py_version.split('.')[0] - if Provides: + if args.provides: # If egg/dist metadata says package name is python, we provide python(abi) if dist.key == 'python': name = 'python(abi)' if name not in py_deps: py_deps[name] = [] py_deps[name].append(('==', dist.py_version)) - if not legacy or not PyMajorVer_Deps: + if not args.legacy or not args.majorver_only: name = 'python{}dist({})'.format(dist.py_version, dist.key) if name not in py_deps: py_deps[name] = [] name_ = 'python{}dist({})'.format(dist.py_version, normalized_name) if name_ not in py_deps: py_deps[name_] = [] - if Provides_PyMajorVer_Variant or PyMajorVer_Deps: + if args.majorver_provides or args.majorver_only: pymajor_name = 'python{}dist({})'.format(pyver_major, dist.key) if pymajor_name not in py_deps: py_deps[pymajor_name] = [] pymajor_name_ = 'python{}dist({})'.format(pyver_major, normalized_name) if pymajor_name_ not in py_deps: py_deps[pymajor_name_] = [] - if legacy or legacy_Provides: + if args.legacy or args.legacy_provides: legacy_name = 'pythonegg({})({})'.format(pyver_major, dist.key) if legacy_name not in py_deps: py_deps[legacy_name] = [] @@ -278,17 +258,17 @@ for f in files: version = dist.version spec = ('==', version) if spec not in py_deps[name]: - if not legacy: + if not args.legacy: py_deps[name].append(spec) if name != name_: py_deps[name_].append(spec) - if Provides_PyMajorVer_Variant: + if args.majorver_provides: py_deps[pymajor_name].append(spec) if pymajor_name != pymajor_name_: py_deps[pymajor_name_].append(spec) - if legacy or legacy_Provides: + if args.legacy or args.legacy_provides: py_deps[legacy_name].append(spec) - if Requires or (Recommends and dist.extras): + if args.requires or (args.recommends and dist.extras): name = 'python(abi)' # If egg/dist metadata says package name is python, we don't add dependency on python(abi) if dist.key == 'python': @@ -302,26 +282,26 @@ for f in files: if spec not in py_deps[name]: py_deps[name].append(spec) deps = dist.requires() - if Recommends: + if args.recommends: depsextras = dist.requires(extras=dist.extras) - if not Requires: + if not args.requires: for dep in reversed(depsextras): if dep in deps: depsextras.remove(dep) deps = depsextras # console_scripts/gui_scripts entry points need pkg_resources from setuptools if ((dist.get_entry_map('console_scripts') or - dist.get_entry_map('gui_scripts')) and - (lower.endswith('.egg') or - lower.endswith('.egg-info'))): + dist.get_entry_map('gui_scripts')) and + (lower.endswith('.egg') or + lower.endswith('.egg-info'))): # stick them first so any more specific requirement overrides it deps.insert(0, Requirement.parse('setuptools')) # add requires/recommends based on egg/dist metadata for dep in deps: - if legacy: + if args.legacy: name = 'pythonegg({})({})'.format(pyver_major, dep.key) else: - if PyMajorVer_Deps: + if args.majorver_only: name = 'python{}dist({})'.format(pyver_major, dep.key) else: name = 'python{}dist({})'.format(dist.py_version, dep.key) @@ -334,7 +314,7 @@ for f in files: py_deps[name] = [] # Unused, for automatic sub-package generation based on 'extras' from egg/dist metadata # TODO: implement in rpm later, or...? - if Extras: + if args.extras: deps = dist.requires() extras = dist.extras print(extras) @@ -356,7 +336,7 @@ for f in files: print('%%description\t{}'.format(extra)) print('{} extra for {} python package'.format(extra, dist.key)) print('%%files\t\textras-{}\n'.format(extra)) - if Conflicts: + if args.conflicts: # Should we really add conflicts for extras? # Creating a meta package per extra with recommends on, which has # the requires/conflicts in stead might be a better solution... From 1634914c2e1e79bc61be9bf111ccc03f69f890ba Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Wed, 8 Apr 2020 18:12:09 +0200 Subject: [PATCH 027/110] scripts/pythondistdeps: Notes from an attempted rewrite to importlib.metadata Notes from an attempted rewrite from pkg_resources to importlib.metadata in 2020: 1. While pkg_resources can open a metadata on a specified path (Distribution.from_location()), importlib provides access only to "installed package metadata", i.e. the the dist-info or egg-info directory must be "discoverable", i.e. on the sys.path. - Thankfully only the dist/egg-info directory must exist, the corresponding Python module does not have to be present. - The problems this causes: (a) You have to manipulate the sys.path to add the specific location of the site-packages directory inside the buildroot (b) If you have package "foo" in this newly added directory on sys.path and there is some problem and its dist/egg-info metadata are not found, importlib.metadata continues searching the sys.path and may discover a package with the same name (possibly same version) outside the buildroot. To get around this, you can manipulate the sys.path to remove all other "site-packages" directories. But you have to leave the standard library there, because importlib may import other modules (in my testing: base64, quopri, random, socket, calendar, uu) (c) I have not tested how well it works if you're ispecting metadata of different Python versions than the one you run the script with (especially Python 2 vs Python 3). This might also cause problems with dependency specifiers (i.e. python_version != "3.4") 2. Handling of dependencies (requires) is problematic in importlib.metadata - pkg_resources provides a way to separately list standard requires and a requires for each "extras" category. importlib does not provide this, it only spits out a list of strings, each string in the format: - 'packaging>=14', - 'towncrier>=18.5.0; extra == "docs"', or - 'psutil<6,>=5.6.1; (python_version != "3.4") and extra == "testing" you can either parse these with a regex (fragile) or use the external `packaging` Python module. `packaging`, however, also doesn't have a great support for figuring out extra dependencies, it provides the marker api: - you can use Marker api to evaluate the condition, but not to parse. For parsing you can access the private api Marker._markers: - marker._markers=[[(, , \ )], 'and', (, , \ )] which beyond the problem of being private is also not very useful for parsing due to its structure. - pkg_resources also provides version parsing, which importlib does not and `packaging` needs to be used - importlib is part of the standard library, but packaging and its 2 runtime dependencies (pyparsing and six) are not, and therefore we would go from 1 dependency to 3 3. A few minor issues, more in the next section about equivalents. importlib.metadata.distribution equivalents of pkg_resources.Distribution attributes: - pkg_resources: dist.py_version importlib: # not implemented (but can be guessed from the /usr/lib/pythonXX.YY/ path) - pkg_resources: dist.project_name importlib: dist.metadata['name'] - pkg_resources: dist.key importlib: # not implemented - pkg_resources: dist.version importlib: dist.version - pkg_resources: dist.requires() importlib: dist.requires # but returns strings with almost no parsing done, and also lists extras - pkg_resources: dist.requires(extras=dist.extras) importlib: # not implemented, has to be parsed from dist.requires - pkg_resources: dist.get_entry_map('console_scripts') importlib: [ep for ep in importlib.metadata.entry_points()['console_scripts'] if ep.name == pkg][0] # I have not found a better way to get the console_scripts - pkg_resources: dist.get_entry_map('gui_scripts') importlib: # Presumably same as console_scripts, but untested --- pythondistdeps.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pythondistdeps.py b/pythondistdeps.py index 31b4737..f5cdeaf 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -11,6 +11,10 @@ # RPM python dependency generator, using .egg-info/.egg-link/.dist-info data # +# Please know: +# - Notes from an attempted rewrite from pkg_resources to importlib.metadata in +# 2020 can be found in the message of the commit that added this line. + from __future__ import print_function import argparse from os.path import basename, dirname, isdir, sep @@ -185,6 +189,9 @@ for f in (args.files or stdin.readlines()): lower.endswith('.egg-info') or \ lower.endswith('.dist-info'): # This import is very slow, so only do it if needed + # - Notes from an attempted rewrite from pkg_resources to + # importlib.metadata in 2020 can be found in the message of + # the commit that added this line. from pkg_resources import Distribution, FileMetadata, PathMetadata, Requirement, parse_version dist_name = basename(f) if isdir(f): From 89e1676ceeebb50886aae6ee9801c6b4843a6a15 Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Tue, 7 Apr 2020 01:16:34 +0200 Subject: [PATCH 028/110] scripts/pythondistdeps: Add tests The test data download themselves using pip if not present --- .gitignore | 1 + pythondistdeps.py | 3 +- .../PKG-INFO | 21 + .../requires.txt | 95 ++++ .../scripts_pythondistdeps/test-data.yaml | 480 ++++++++++++++++++ .../scripts_pythondistdeps/test-requires.yaml | 94 ++++ tests/test_scripts_pythondistdeps.py | 242 +++++++++ 7 files changed, 935 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/PKG-INFO create mode 100644 tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/requires.txt create mode 100644 tests/data/scripts_pythondistdeps/test-data.yaml create mode 100644 tests/data/scripts_pythondistdeps/test-requires.yaml create mode 100644 tests/test_scripts_pythondistdeps.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..999cc12 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/tests/data/scripts_pythondistdeps/usr/ diff --git a/pythondistdeps.py b/pythondistdeps.py index f5cdeaf..344334b 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -367,7 +367,8 @@ for name in names: if len(spec_list) == 1: print(spec_list[0]) else: - print('({})'.format(' with '.join(spec_list))) + # Sort spec_list so that the results can be tested easily + print('({})'.format(' with '.join(sorted(spec_list)))) else: # Print out unversioned provides, requires, recommends, conflicts print(name) diff --git a/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/PKG-INFO b/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/PKG-INFO new file mode 100644 index 0000000..a99b21c --- /dev/null +++ b/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/PKG-INFO @@ -0,0 +1,21 @@ +Metadata-Version: 2.1 +Name: pyreq2rpm.tests +Version: 2020.04.07.024dab0 +Summary: Test package to verify conversion of dependencies from pip/python to rpm format, data taken from pyreq2rpm +Author: Tomas Orsava (author of this metapackage) +Home-page: https://github.com/gordonmessmer/pyreq2rpm +License: MIT +Description: This dist-info is mock metadata for a fictional package pyreq2rpm.tests + The important part of its contents is the requires.txt that contains + different formats of Python requirements taken from + https://github.com/gordonmessmer/pyreq2rpm, that are numbered as to be + unique. The metadata is then processed through + scripts/pythondistdeps.py and the resulting RPM requires compared to + expected results. + + The version of the package contains the date when I converted the test + data from upstream to this metapackage, as well as the short hash of + the last git commit. + + From the requirements I have omitted those that are incorrect, as they + crash the pythondistdeps.py script. diff --git a/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/requires.txt b/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/requires.txt new file mode 100644 index 0000000..ec10bc6 --- /dev/null +++ b/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/requires.txt @@ -0,0 +1,95 @@ +# Taken from pyreq2rpm, removed tests that are expected to fail +foobar0~=2.4.8 +foobar1~=2.4.8.0 +foobar2~=2.4.8.1 + +foobar4~=2.0 + + +foobar7~=2.4.8b5 +foobar8~=2.0.0b5 +foobar9~=2.4.8.post1 +foobar10~=2.0.post1 +foobar11==2.4.8 +foobar12==2.4.8.0 +foobar13==2.4.8.1 +foobar14==2.4.8.* +foobar15==2.0 +foobar16==2 +foobar17==2.* +foobar18==2.4.8b5 +foobar19==2.0.0b5 +foobar20==2.4.8.post1 +foobar21==2.0.post1 +foobar22===2.4.8 +foobar23===2.4.8.0 +foobar24===2.4.8.1 + +foobar26===2.0 +foobar27===2 + +foobar29===2.4.8b5 +foobar30===2.0.0b5 +foobar31===2.4.8.post1 +foobar32===2.0.post1 +foobar33!=2.4.8 +foobar34!=2.4.8.0 +foobar35!=2.4.8.1 +foobar36!=2.4.8.* +foobar37!=2.0 +foobar38!=2 +foobar39!=2.* +foobar40!=2.4.8b5 +foobar41!=2.0.0b5 +foobar42!=2.4.8.post1 +foobar43!=2.0.post1 +foobar44<=2.4.8 +foobar45<=2.4.8.0 +foobar46<=2.4.8.1 +foobar47<=2.4.8.* +foobar48<=2.0 +foobar49<=2 +foobar50<=2.* +foobar51<=2.4.8b5 +foobar52<=2.0.0b5 +foobar53<=2.4.8.post1 +foobar54<=2.0.post1 +foobar55<2.4.8 +foobar56<2.4.8.0 +foobar57<2.4.8.1 +foobar58<2.4.8.* +foobar59<2.0 +foobar60<2 +foobar61<2.* +foobar62<2.4.8b5 +foobar63<2.0.0b5 +foobar64<2.4.8.post1 +foobar65<2.0.post1 +foobar66>=2.4.8 +foobar67>=2.4.8.0 +foobar68>=2.4.8.1 +foobar69>=2.4.8.* +foobar70>=2.0 +foobar71>=2 +foobar72>=2.* +foobar73>=2.4.8b5 +foobar74>=2.0.0b5 +foobar75>=2.4.8.post1 +foobar76>=2.0.post1 +foobar77>2.4.8 +foobar78>2.4.8.0 +foobar79>2.4.8.1 +foobar80>2.4.8.* +foobar81>2.0 +foobar82>2 +foobar83>2.* +foobar84>2.4.8b5 +foobar85>2.0.0b5 +foobar86>2.4.8.post1 +foobar87>2.0.post1 +pyparsing0 +pyparsing1>=2.0.1,!=2.0.4,!=2.1.2,!=2.1.6 +babel>=1.3,!=2.0 + +# Tests for breakages in Fedora +fedora-python-nb2plots==0+unknown diff --git a/tests/data/scripts_pythondistdeps/test-data.yaml b/tests/data/scripts_pythondistdeps/test-data.yaml new file mode 100644 index 0000000..ae4295a --- /dev/null +++ b/tests/data/scripts_pythondistdeps/test-data.yaml @@ -0,0 +1,480 @@ +--requires: + --provides: + pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info: + provides: python3.9dist(pyreq2rpm.tests) = 2020.04.07.024dab0 + requires: |- + python(abi) = 3.9 + ((python3.9dist(babel) < 2 or python3.9dist(babel) > 2) with python3.9dist(babel) >= 1.3) + python3.9dist(fedora-python-nb2plots) = 0 + (python3.9dist(foobar0) >= 2.4.8 with python3.9dist(foobar0) < 2.5) + (python3.9dist(foobar1) >= 2.4.8 with python3.9dist(foobar1) < 2.4.9) + (python3.9dist(foobar10) >= 2^post1 with python3.9dist(foobar10) < 3) + python3.9dist(foobar11) = 2.4.8 + python3.9dist(foobar12) = 2.4.8 + python3.9dist(foobar13) = 2.4.8.1 + (python3.9dist(foobar14) >= 2.4.8 with python3.9dist(foobar14) < 2.4.9) + python3.9dist(foobar15) = 2 + python3.9dist(foobar16) = 2 + (python3.9dist(foobar17) >= 2 with python3.9dist(foobar17) < 3) + python3.9dist(foobar18) = 2.4.8~b5 + python3.9dist(foobar19) = 2~b5 + (python3.9dist(foobar2) >= 2.4.8.1 with python3.9dist(foobar2) < 2.4.9) + python3.9dist(foobar20) = 2.4.8^post1 + python3.9dist(foobar21) = 2^post1 + python3.9dist(foobar22) = 2.4.8 + python3.9dist(foobar23) = 2.4.8 + python3.9dist(foobar24) = 2.4.8.1 + python3.9dist(foobar26) = 2 + python3.9dist(foobar27) = 2 + python3.9dist(foobar29) = 2.4.8~b5 + python3.9dist(foobar30) = 2~b5 + python3.9dist(foobar31) = 2.4.8^post1 + python3.9dist(foobar32) = 2^post1 + (python3.9dist(foobar33) < 2.4.8 or python3.9dist(foobar33) > 2.4.8) + (python3.9dist(foobar34) < 2.4.8 or python3.9dist(foobar34) > 2.4.8) + (python3.9dist(foobar35) < 2.4.8.1 or python3.9dist(foobar35) > 2.4.8.1) + (python3.9dist(foobar36) < 2.4.8 or python3.9dist(foobar36) > 2.4.9) + (python3.9dist(foobar37) < 2 or python3.9dist(foobar37) > 2) + (python3.9dist(foobar38) < 2 or python3.9dist(foobar38) > 2) + (python3.9dist(foobar39) < 2 or python3.9dist(foobar39) > 3) + (python3.9dist(foobar4) >= 2 with python3.9dist(foobar4) < 3) + (python3.9dist(foobar40) < 2.4.8~b5 or python3.9dist(foobar40) > 2.4.8~b5) + (python3.9dist(foobar41) < 2~b5 or python3.9dist(foobar41) > 2~b5) + (python3.9dist(foobar42) < 2.4.8^post1 or python3.9dist(foobar42) > 2.4.8^post1) + (python3.9dist(foobar43) < 2^post1 or python3.9dist(foobar43) > 2^post1) + python3.9dist(foobar44) <= 2.4.8 + python3.9dist(foobar45) <= 2.4.8 + python3.9dist(foobar46) <= 2.4.8.1 + python3.9dist(foobar47) <= 2.4.8 + python3.9dist(foobar48) <= 2 + python3.9dist(foobar49) <= 2 + python3.9dist(foobar50) <= 2 + python3.9dist(foobar51) <= 2.4.8~b5 + python3.9dist(foobar52) <= 2~b5 + python3.9dist(foobar53) <= 2.4.8^post1 + python3.9dist(foobar54) <= 2^post1 + python3.9dist(foobar55) < 2.4.8 + python3.9dist(foobar56) < 2.4.8 + python3.9dist(foobar57) < 2.4.8.1 + python3.9dist(foobar58) < 2.4.8 + python3.9dist(foobar59) < 2 + python3.9dist(foobar60) < 2 + python3.9dist(foobar61) < 2 + python3.9dist(foobar62) < 2.4.8~b5 + python3.9dist(foobar63) < 2~b5 + python3.9dist(foobar64) < 2.4.8^post1 + python3.9dist(foobar65) < 2^post1 + python3.9dist(foobar66) >= 2.4.8 + python3.9dist(foobar67) >= 2.4.8 + python3.9dist(foobar68) >= 2.4.8.1 + python3.9dist(foobar69) >= 2.4.8 + (python3.9dist(foobar7) >= 2.4.8~b5 with python3.9dist(foobar7) < 2.5) + python3.9dist(foobar70) >= 2 + python3.9dist(foobar71) >= 2 + python3.9dist(foobar72) >= 2 + python3.9dist(foobar73) >= 2.4.8~b5 + python3.9dist(foobar74) >= 2~b5 + python3.9dist(foobar75) >= 2.4.8^post1 + python3.9dist(foobar76) >= 2^post1 + python3.9dist(foobar77) > 2.4.8 + python3.9dist(foobar78) > 2.4.8 + python3.9dist(foobar79) > 2.4.8.1 + (python3.9dist(foobar8) >= 2~b5 with python3.9dist(foobar8) < 2.1) + python3.9dist(foobar80) >= 2.4.9 + python3.9dist(foobar81) > 2 + python3.9dist(foobar82) > 2 + python3.9dist(foobar83) >= 3 + python3.9dist(foobar84) > 2.4.8~b5 + python3.9dist(foobar85) > 2~b5 + python3.9dist(foobar86) > 2.4.8^post1 + python3.9dist(foobar87) > 2^post1 + (python3.9dist(foobar9) >= 2.4.8^post1 with python3.9dist(foobar9) < 2.5) + python3.9dist(pyparsing0) + ((python3.9dist(pyparsing1) < 2.0.4 or python3.9dist(pyparsing1) > 2.0.4) with (python3.9dist(pyparsing1) < 2.1.2 or python3.9dist(pyparsing1) > 2.1.2) with (python3.9dist(pyparsing1) < 2.1.6 or python3.9dist(pyparsing1) > 2.1.6) with python3.9dist(pyparsing1) >= 2.0.1) + --provides --majorver-provides: + usr/lib/python2.7/site-packages/attrs-19.1.0-py2.7.egg-info: + provides: |- + python2.7dist(attrs) = 19.1 + python2dist(attrs) = 19.1 + requires: python(abi) = 2.7 + usr/lib/python2.7/site-packages/kubernetes-11.0.0b2.dist-info: + provides: |- + python2.7dist(kubernetes) = 11~b2 + python2dist(kubernetes) = 11~b2 + requires: |- + python(abi) = 2.7 + python2.7dist(certifi) >= 14.5.14 + python2.7dist(google-auth) >= 1.0.1 + python2.7dist(ipaddress) >= 1.0.17 + python2.7dist(python-dateutil) >= 2.5.3 + python2.7dist(pyyaml) >= 3.12 + python2.7dist(requests) + python2.7dist(requests-oauthlib) + python2.7dist(setuptools) >= 21 + python2.7dist(six) >= 1.9 + python2.7dist(urllib3) >= 1.24.2 + ((python2.7dist(websocket-client) < 0.40 or python2.7dist(websocket-client) > 0.40) with (python2.7dist(websocket-client) < 0.41 or python2.7dist(websocket-client) > 0.42) with (python2.7dist(websocket-client) < 0.42 or python2.7dist(websocket-client) > 0.43) with python2.7dist(websocket-client) >= 0.32) + usr/lib/python2.7/site-packages/mistune-0.8.4-py2.7.egg-info: + provides: |- + python2.7dist(mistune) = 0.8.4 + python2dist(mistune) = 0.8.4 + requires: python(abi) = 2.7 + usr/lib/python2.7/site-packages/packaging-19.0.dist-info: + provides: |- + python2.7dist(packaging) = 19 + python2dist(packaging) = 19 + requires: |- + python(abi) = 2.7 + python2.7dist(pyparsing) >= 2.0.2 + python2.7dist(six) + usr/lib/python2.7/site-packages/pip-19.1.1.dist-info: + provides: |- + python2.7dist(pip) = 19.1.1 + python2dist(pip) = 19.1.1 + requires: python(abi) = 2.7 + usr/lib/python2.7/site-packages/pyparsing-2.4.0.dist-info: + provides: |- + python2.7dist(pyparsing) = 2.4 + python2dist(pyparsing) = 2.4 + requires: python(abi) = 2.7 + usr/lib/python2.7/site-packages/setuptools-41.6.0-py2.7.egg-info: + provides: |- + python2.7dist(setuptools) = 41.6 + python2dist(setuptools) = 41.6 + requires: |- + python(abi) = 2.7 + python2.7dist(setuptools) + usr/lib/python2.7/site-packages/setuptools-41.6.0.dist-info: + provides: |- + python2.7dist(setuptools) = 41.6 + python2dist(setuptools) = 41.6 + requires: python(abi) = 2.7 + usr/lib/python2.7/site-packages/six-1.12.0.dist-info: + provides: |- + python2.7dist(six) = 1.12 + python2dist(six) = 1.12 + requires: python(abi) = 2.7 + usr/lib/python2.7/site-packages/tox-3.14.0.dist-info: + provides: |- + python2.7dist(tox) = 3.14 + python2dist(tox) = 3.14 + requires: |- + python(abi) = 2.7 + (python2.7dist(filelock) < 4 with python2.7dist(filelock) >= 3) + (python2.7dist(importlib-metadata) < 1 with python2.7dist(importlib-metadata) >= 0.12) + python2.7dist(packaging) >= 14 + (python2.7dist(pluggy) < 1 with python2.7dist(pluggy) >= 0.12) + (python2.7dist(py) < 2 with python2.7dist(py) >= 1.4.17) + (python2.7dist(six) < 2 with python2.7dist(six) >= 1) + python2.7dist(toml) >= 0.9.4 + python2.7dist(virtualenv) >= 14 + usr/lib/python2.7/site-packages/urllib3-1.25.7-py2.7.egg-info: + provides: |- + python2.7dist(urllib3) = 1.25.7 + python2dist(urllib3) = 1.25.7 + requires: python(abi) = 2.7 + usr/lib/python2.7/site-packages/zope.component-4.3.0-py2.7.egg-info: + provides: |- + python2.7dist(zope.component) = 4.3 + python2dist(zope.component) = 4.3 + requires: |- + python(abi) = 2.7 + python2.7dist(setuptools) + python2.7dist(zope.event) + python2.7dist(zope.interface) >= 4.1 + usr/lib/python3.7/site-packages/astroid-2.3.3.dist-info: + provides: |- + python3.7dist(astroid) = 2.3.3 + python3dist(astroid) = 2.3.3 + requires: |- + python(abi) = 3.7 + (python3.7dist(lazy-object-proxy) >= 1.4 with python3.7dist(lazy-object-proxy) < 1.5) + (python3.7dist(six) >= 1.12 with python3.7dist(six) < 2) + (python3.7dist(typed-ast) < 1.5 with python3.7dist(typed-ast) >= 1.4) + (python3.7dist(wrapt) >= 1.11 with python3.7dist(wrapt) < 1.12) + usr/lib/python3.7/site-packages/packaging-19.0.dist-info: + provides: |- + python3.7dist(packaging) = 19 + python3dist(packaging) = 19 + requires: |- + python(abi) = 3.7 + python3.7dist(pyparsing) >= 2.0.2 + python3.7dist(six) + usr/lib/python3.7/site-packages/pip-19.1.1.dist-info: + provides: |- + python3.7dist(pip) = 19.1.1 + python3dist(pip) = 19.1.1 + requires: python(abi) = 3.7 + usr/lib/python3.7/site-packages/pyparsing-2.4.0.dist-info: + provides: |- + python3.7dist(pyparsing) = 2.4 + python3dist(pyparsing) = 2.4 + requires: python(abi) = 3.7 + usr/lib/python3.7/site-packages/setuptools-41.6.0-py3.7.egg-info: + provides: |- + python3.7dist(setuptools) = 41.6 + python3dist(setuptools) = 41.6 + requires: |- + python(abi) = 3.7 + python3.7dist(setuptools) + usr/lib/python3.7/site-packages/setuptools-41.6.0.dist-info: + provides: |- + python3.7dist(setuptools) = 41.6 + python3dist(setuptools) = 41.6 + requires: python(abi) = 3.7 + usr/lib/python3.7/site-packages/six-1.12.0.dist-info: + provides: |- + python3.7dist(six) = 1.12 + python3dist(six) = 1.12 + requires: python(abi) = 3.7 + usr/lib/python3.7/site-packages/tox-3.14.0.dist-info: + provides: |- + python3.7dist(tox) = 3.14 + python3dist(tox) = 3.14 + requires: |- + python(abi) = 3.7 + (python3.7dist(filelock) < 4 with python3.7dist(filelock) >= 3) + (python3.7dist(importlib-metadata) < 1 with python3.7dist(importlib-metadata) >= 0.12) + python3.7dist(packaging) >= 14 + (python3.7dist(pluggy) < 1 with python3.7dist(pluggy) >= 0.12) + (python3.7dist(py) < 2 with python3.7dist(py) >= 1.4.17) + (python3.7dist(six) < 2 with python3.7dist(six) >= 1) + python3.7dist(toml) >= 0.9.4 + python3.7dist(virtualenv) >= 14 + usr/lib/python3.9/site-packages/astroid-2.3.3.dist-info: + provides: |- + python3.9dist(astroid) = 2.3.3 + python3dist(astroid) = 2.3.3 + requires: |- + python(abi) = 3.9 + (python3.9dist(lazy-object-proxy) >= 1.4 with python3.9dist(lazy-object-proxy) < 1.5) + (python3.9dist(six) >= 1.12 with python3.9dist(six) < 2) + (python3.9dist(wrapt) >= 1.11 with python3.9dist(wrapt) < 1.12) + usr/lib/python3.9/site-packages/attrs-19.1.0-py3.9.egg-info: + provides: |- + python3.9dist(attrs) = 19.1 + python3dist(attrs) = 19.1 + requires: python(abi) = 3.9 + usr/lib/python3.9/site-packages/fsleyes-0.32.3.dist-info: + provides: |- + python3.9dist(fsleyes) = 0.32.3 + python3dist(fsleyes) = 0.32.3 + requires: |- + python(abi) = 3.9 + python3.9dist(fsleyes-props) >= 1.6.7 + python3.9dist(fsleyes-widgets) >= 0.8.4 + python3.9dist(fslpy) >= 2.8.4 + (python3.9dist(jinja2) >= 2 with python3.9dist(jinja2) < 3) + python3.9dist(matplotlib) >= 1.5.1 + python3.9dist(nibabel) >= 2.3 + python3.9dist(numpy) >= 1.14 + python3.9dist(pillow) >= 3.2 + python3.9dist(pyopengl) >= 3.1 + (python3.9dist(pyparsing) >= 2 with python3.9dist(pyparsing) < 3) + python3.9dist(scipy) >= 0.18 + python3.9dist(setuptools) + (python3.9dist(six) >= 1 with python3.9dist(six) < 2) + python3.9dist(wxpython) >= 3.0.2 + usr/lib/python3.9/site-packages/kubernetes-11.0.0.dist-info: + provides: |- + python3.9dist(kubernetes) = 11 + python3dist(kubernetes) = 11 + requires: |- + python(abi) = 3.9 + python3.9dist(certifi) >= 14.5.14 + python3.9dist(google-auth) >= 1.0.1 + python3.9dist(python-dateutil) >= 2.5.3 + python3.9dist(pyyaml) >= 3.12 + python3.9dist(requests) + python3.9dist(requests-oauthlib) + python3.9dist(setuptools) >= 21 + python3.9dist(six) >= 1.9 + python3.9dist(urllib3) >= 1.24.2 + ((python3.9dist(websocket-client) < 0.40 or python3.9dist(websocket-client) > 0.40) with (python3.9dist(websocket-client) < 0.41 or python3.9dist(websocket-client) > 0.42) with (python3.9dist(websocket-client) < 0.42 or python3.9dist(websocket-client) > 0.43) with python3.9dist(websocket-client) >= 0.32) + usr/lib/python3.9/site-packages/mistune-0.8.4-py3.9.egg-info: + provides: |- + python3.9dist(mistune) = 0.8.4 + python3dist(mistune) = 0.8.4 + requires: python(abi) = 3.9 + usr/lib/python3.9/site-packages/packaging-20.1.dist-info: + provides: |- + python3.9dist(packaging) = 20.1 + python3dist(packaging) = 20.1 + requires: |- + python(abi) = 3.9 + python3.9dist(pyparsing) >= 2.0.2 + python3.9dist(six) + usr/lib/python3.9/site-packages/pip-20.0.2.dist-info: + provides: |- + python3.9dist(pip) = 20.0.2 + python3dist(pip) = 20.0.2 + requires: python(abi) = 3.9 + usr/lib/python3.9/site-packages/pyparsing-2.4.0.dist-info: + provides: |- + python3.9dist(pyparsing) = 2.4 + python3dist(pyparsing) = 2.4 + requires: python(abi) = 3.9 + usr/lib/python3.9/site-packages/setuptools-41.6.0-py3.9.egg-info: + provides: |- + python3.9dist(setuptools) = 41.6 + python3dist(setuptools) = 41.6 + requires: |- + python(abi) = 3.9 + python3.9dist(setuptools) + usr/lib/python3.9/site-packages/setuptools-41.6.0.dist-info: + provides: |- + python3.9dist(setuptools) = 41.6 + python3dist(setuptools) = 41.6 + requires: python(abi) = 3.9 + usr/lib/python3.9/site-packages/six-1.12.0.dist-info: + provides: |- + python3.9dist(six) = 1.12 + python3dist(six) = 1.12 + requires: python(abi) = 3.9 + usr/lib/python3.9/site-packages/tox-3.14.0.dist-info: + provides: |- + python3.9dist(tox) = 3.14 + python3dist(tox) = 3.14 + requires: |- + python(abi) = 3.9 + (python3.9dist(filelock) < 4 with python3.9dist(filelock) >= 3) + python3.9dist(packaging) >= 14 + (python3.9dist(pluggy) < 1 with python3.9dist(pluggy) >= 0.12) + (python3.9dist(py) < 2 with python3.9dist(py) >= 1.4.17) + (python3.9dist(six) < 2 with python3.9dist(six) >= 1) + python3.9dist(toml) >= 0.9.4 + python3.9dist(virtualenv) >= 14 + usr/lib/python3.9/site-packages/urllib3-1.25.7-py3.9.egg-info: + provides: |- + python3.9dist(urllib3) = 1.25.7 + python3dist(urllib3) = 1.25.7 + requires: python(abi) = 3.9 + usr/lib/python3.9/site-packages/zope.schema-4.4.2-py3.9.egg-info: + provides: |- + python3.9dist(zope.schema) = 4.4.2 + python3dist(zope.schema) = 4.4.2 + requires: |- + python(abi) = 3.9 + python3.9dist(setuptools) + python3.9dist(zope.event) + python3.9dist(zope.interface) >= 3.6 + usr/lib64/python2.7/site-packages/MarkupSafe-1.1.1.dist-info: + provides: |- + python2.7dist(markupsafe) = 1.1.1 + python2dist(markupsafe) = 1.1.1 + requires: python(abi) = 2.7 + usr/lib64/python2.7/site-packages/backports.range-3.7.2-py2.7.egg-info: + provides: |- + python2.7dist(backports.range) = 3.7.2 + python2dist(backports.range) = 3.7.2 + requires: python(abi) = 2.7 + usr/lib64/python2.7/site-packages/lxml-4.4.0.dist-info: + provides: |- + python2.7dist(lxml) = 4.4 + python2dist(lxml) = 4.4 + requires: python(abi) = 2.7 + usr/lib64/python2.7/site-packages/numpy-1.16.4.dist-info: + provides: |- + python2.7dist(numpy) = 1.16.4 + python2dist(numpy) = 1.16.4 + requires: python(abi) = 2.7 + usr/lib64/python2.7/site-packages/numpy_stl-2.11.2-py2.7.egg-info: + provides: |- + python2.7dist(numpy-stl) = 2.11.2 + python2dist(numpy-stl) = 2.11.2 + requires: |- + python(abi) = 2.7 + python2.7dist(numpy) + python2.7dist(python-utils) >= 1.6.2 + python2.7dist(setuptools) + usr/lib64/python2.7/site-packages/scipy-1.2.1.dist-info: + provides: |- + python2.7dist(scipy) = 1.2.1 + python2dist(scipy) = 1.2.1 + requires: |- + python(abi) = 2.7 + python2.7dist(numpy) >= 1.8.2 + usr/lib64/python2.7/site-packages/simplejson-3.16.0-py2.7.egg-info: + provides: |- + python2.7dist(simplejson) = 3.16 + python2dist(simplejson) = 3.16 + requires: python(abi) = 2.7 + usr/lib64/python3.7/site-packages/MarkupSafe-1.1.1.dist-info: + provides: |- + python3.7dist(markupsafe) = 1.1.1 + python3dist(markupsafe) = 1.1.1 + requires: python(abi) = 3.7 + usr/lib64/python3.7/site-packages/PyQt5_sip-4.19.19.dist-info: + provides: |- + python3.7dist(pyqt5-sip) = 4.19.19 + python3dist(pyqt5-sip) = 4.19.19 + requires: python(abi) = 3.7 + usr/lib64/python3.7/site-packages/PyQtWebEngine-5.12.1.dist-info: + provides: |- + python3.7dist(pyqtwebengine) = 5.12.1 + python3dist(pyqtwebengine) = 5.12.1 + requires: |- + python(abi) = 3.7 + python3.7dist(pyqt5) >= 5.12 + usr/lib64/python3.7/site-packages/backports.range-3.7.2-py3.7.egg-info: + provides: |- + python3.7dist(backports.range) = 3.7.2 + python3dist(backports.range) = 3.7.2 + requires: python(abi) = 3.7 + usr/lib64/python3.7/site-packages/lxml-4.4.0.dist-info: + provides: |- + python3.7dist(lxml) = 4.4 + python3dist(lxml) = 4.4 + requires: python(abi) = 3.7 + usr/lib64/python3.7/site-packages/numpy-1.17.4.dist-info: + provides: |- + python3.7dist(numpy) = 1.17.4 + python3dist(numpy) = 1.17.4 + requires: python(abi) = 3.7 + usr/lib64/python3.7/site-packages/numpy_stl-2.11.2-py3.7.egg-info: + provides: |- + python3.7dist(numpy-stl) = 2.11.2 + python3dist(numpy-stl) = 2.11.2 + requires: |- + python(abi) = 3.7 + python3.7dist(numpy) + python3.7dist(python-utils) >= 1.6.2 + python3.7dist(setuptools) + usr/lib64/python3.7/site-packages/scipy-1.2.1.dist-info: + provides: |- + python3.7dist(scipy) = 1.2.1 + python3dist(scipy) = 1.2.1 + requires: |- + python(abi) = 3.7 + python3.7dist(numpy) >= 1.8.2 + usr/lib64/python3.7/site-packages/simplejson-3.16.0-py3.7.egg-info: + provides: |- + python3.7dist(simplejson) = 3.16 + python3dist(simplejson) = 3.16 + requires: python(abi) = 3.7 + usr/lib64/python3.9/site-packages/PyQtWebEngine-5.12.1.dist-info: + provides: |- + python3.9dist(pyqtwebengine) = 5.12.1 + python3dist(pyqtwebengine) = 5.12.1 + requires: |- + python(abi) = 3.9 + python3.9dist(pyqt5) >= 5.12 + usr/lib64/python3.9/site-packages/backports.range-3.7.2-py3.9.egg-info: + provides: |- + python3.9dist(backports.range) = 3.7.2 + python3dist(backports.range) = 3.7.2 + requires: python(abi) = 3.9 + usr/lib64/python3.9/site-packages/numpy_stl-2.11.2-py3.9.egg-info: + provides: |- + python3.9dist(numpy-stl) = 2.11.2 + python3dist(numpy-stl) = 2.11.2 + requires: |- + python(abi) = 3.9 + python3.9dist(numpy) + python3.9dist(python-utils) >= 1.6.2 + python3.9dist(setuptools) + usr/lib64/python3.9/site-packages/simplejson-3.16.0-py3.9.egg-info: + provides: |- + python3.9dist(simplejson) = 3.16 + python3dist(simplejson) = 3.16 + requires: python(abi) = 3.9 diff --git a/tests/data/scripts_pythondistdeps/test-requires.yaml b/tests/data/scripts_pythondistdeps/test-requires.yaml new file mode 100644 index 0000000..af79a28 --- /dev/null +++ b/tests/data/scripts_pythondistdeps/test-requires.yaml @@ -0,0 +1,94 @@ +setuptools: + wheel: + '41.6.0': ['2.7', '3.7', '3.9'] + sdist: + '41.6.0': ['2.7', '3.7', '3.9', '3.10'] +pip: + wheel: + '19.1.1': ['2.7', '3.7'] + '20.0.2': ['3.9'] + sdist: + '20.0.2': ['3.11'] +packaging: + wheel: + '19.0': ['2.7', '3.7'] + '20.1': ['3.9'] +attrs: + sdist: + '19.1.0': ['2.7', '3.9'] +pyparsing: + wheel: + '2.4.0': ['2.7', '3.7', '3.9'] +six: + wheel: + '1.12.0': ['2.7', '3.7', '3.9'] +tox: + wheel: + '3.14.0': ['2.7', '3.7', '3.9'] +urllib3: + sdist: + '1.25.7': ['2.7', '3.9'] +zope.component: + sdist: + '4.3.0': ['2.7', '3.9'] +zope.event: + wheel: + '4.2.0': ['2.7', '3.9'] +zope.schema: + sdist: + '4.4.2': ['2.7', '3.9'] +zope.interface: + sdist: + '5.1.0': ['3.9'] + wheel: + '4.6.0': ['2.7'] +lxml: + lib: lib64 + wheel: + '4.4.0': ['2.7', '3.7'] +scipy: + lib: lib64 + wheel: + '1.2.1': ['2.7', '3.7'] +numpy: + lib: lib64 + wheel: + '1.16.4': ['2.7'] + '1.17.4': ['3.7'] +numpy-stl: + lib: lib64 + sdist: + '2.11.2': ['2.7', '3.7', '3.9'] +PyQt5_sip: + lib: lib64 + wheel: + '4.19.19': ['3.7'] +PyQtWebEngine: + lib: lib64 + wheel: + '5.12.1': ['3.7', '3.9'] +MarkupSafe: + lib: lib64 + wheel: + '1.1.1': ['2.7', '3.7'] +simplejson: + lib: lib64 + sdist: + '3.16.0': ['2.7', '3.7', '3.9'] +backports.range: + lib: lib64 + sdist: + '3.7.2': ['2.7', '3.7', '3.9'] +mistune: + sdist: + '0.8.4': ['2.7', '3.9'] +astroid: + wheel: + '2.3.3': ['3.7', '3.9'] +kubernetes: + wheel: + '11.0.0b2': ['2.7'] + '11.0.0': ['3.9'] +fsleyes: + wheel: + '0.32.3': ['3.9'] diff --git a/tests/test_scripts_pythondistdeps.py b/tests/test_scripts_pythondistdeps.py new file mode 100644 index 0000000..5bbf357 --- /dev/null +++ b/tests/test_scripts_pythondistdeps.py @@ -0,0 +1,242 @@ +# Run tests using pytest, e.g. from the root directory +# $ python3 -m pytest --ignore tests/testing/ -vvv +# +# If there are any breakags, the best way to see differences is using a diff: +# $ diff tests/data/scripts_pythondistdeps/test-data.yaml <(python3 tests/test_scripts_pythondistdeps.py) +# +# - Test cases and expected results are saved in test-data.yaml inside +# TEST_DATA_PATH (currently ./data/scripts_pythondistdeps/) +# - To regenerate test-data.yaml file with the current results of +# pythondistdeps.py for each test configuration, execute this test file +# directly and results will be on stdout +# $ python3 test_scripts_pythondistdeps.py +# +# To add new test-data, add them to the test-requires.yaml: they will be +# downloaded automatically. And then add the resulting dist-info/egg-info paths +# into test-data.yaml under whichever requires/provides configurations you want +# to test +# - To find all dist-info/egg-info directories in the test-data directory, +# run inside test-data: +# $ find . -type d -regex ".*\(dist-info\|egg-info\)" | sort +# +# Requirements for this script: +# - Python >= 3.6 +# - pip >= 20.0.1 +# - setuptools +# - pytest +# - pyyaml +# - wheel + + +from pathlib import Path +import pytest +import shlex +import shutil +import subprocess +import sys +import tempfile +import yaml + +PYTHONDISTDEPS_PATH = Path(__file__).parent / '..' / 'scripts' / 'pythondistdeps.py' +TEST_DATA_PATH = Path(__file__).parent / 'data' / 'scripts_pythondistdeps' + + +def run_pythondistdeps(provides_params, requires_params, dist_egg_info_path): + """Runs pythondistdeps.py on `dits_egg_info_path` with given + provides and requires parameters and returns a dict with generated provides and requires""" + info_path = TEST_DATA_PATH / dist_egg_info_path + files = '\n'.join(map(str, info_path.iterdir())) + + provides = subprocess.check_output((sys.executable, PYTHONDISTDEPS_PATH, *shlex.split(provides_params)), + input=files, encoding="utf-8") + requires = subprocess.check_output((sys.executable, PYTHONDISTDEPS_PATH, *shlex.split(requires_params)), + input=files, encoding="utf-8") + + return {"provides": provides.strip(), "requires": requires.strip()} + + +def load_test_data(): + """Reads the test-data.yaml and loads the test data into a dict.""" + with TEST_DATA_PATH.joinpath('test-data.yaml').open() as file: + return yaml.safe_load(file) + + +def generate_test_cases(test_data): + """Goes through the test data dict and yields test cases. + Test case is a tuple of 4 elements: + - provides parameters + - requires parameters + - path to the dist-info/egg-info directory inside test-data + - dict with expected results ("requires" and "provides")""" + for requires_params in test_data: + for provides_params in test_data[requires_params]: + for dist_egg_info_path in test_data[requires_params][provides_params]: + expected = test_data[requires_params][provides_params][dist_egg_info_path] + yield (provides_params, requires_params, dist_egg_info_path, expected) + + +def check_and_install_test_data(): + """Checks if the appropriate metadata are present in TEST_DATA_PATH, and if + not, downloads them through pip from PyPI.""" + with TEST_DATA_PATH.joinpath('test-requires.yaml').open() as file: + test_requires = yaml.safe_load(file) + downloaded_anything = False + + for package in test_requires: + # To be as close to the real environment, we want some packages saved in /usr/lib64 instead of /usr/lib, + # for these we explicitly set lib64 as a parameter, and by default we use /usr/lib. + lib = test_requires[package].pop("lib", "lib") + + # type is either `wheel` or `sdist` + for type in test_requires[package]: + for pkg_version in test_requires[package][type]: + for py_version in test_requires[package][type][pkg_version]: + py_version_nodots = py_version.replace(".", "") + package_underscores = package.replace("-", "_") + + suffix = ".egg-info" if type == "sdist" else ".dist-info" + pre_suffix = f"-py{py_version}" if type == "sdist" else "" + + install_path = TEST_DATA_PATH / "usr" / lib / f"python{py_version}" \ + / "site-packages" / f"{package_underscores}-{pkg_version}{pre_suffix}{suffix}" + + if install_path.exists(): + continue + + # If this is the first package we're downloading, + # display what's happening + if not downloaded_anything: + print("=====================") + print("Downloading test data") + print("=====================\n") + downloaded_anything = True + + # We use a temporary directory to unpack/install the + # package to, and then we move only the metadata to the + # final location + with tempfile.TemporaryDirectory() as temp_dir: + import runpy + backup_argv = sys.argv[:] + + if type == "wheel": + from pkg_resources import parse_version + abi = f"cp{py_version_nodots}" + # The "m" was removed from the abi flag in Python version 3.8 + if parse_version(py_version) < parse_version('3.8'): + abi += "m" + + # Install = download and unpack wheel into our + # temporary directory + sys.argv[1:] = ["install", "--no-deps", + "--only-binary", ":all:", + "--platform", "manylinux1_x86_64", + "--python-version", py_version, + "--implementation", "cp", + "--abi", abi, + "--target", temp_dir, + "--no-build-isolation", + f"{package}=={pkg_version}"] + else: + # Download sdist that we'll unpack later + sys.argv[1:] = ["download", "--no-deps", + "--no-binary", ":all:", + "--dest", temp_dir, + "--no-build-isolation", + f"{package}=={pkg_version}"] + + try: + # run_module() alters sys.modules and sys.argv, but restores them at exit + runpy.run_module("pip", run_name="__main__", alter_sys=True) + except SystemExit as exc: + pass + finally: + sys.argv[:] = backup_argv + + temp_path = Path(temp_dir) + if type == "sdist": + # Wheel were already unpacked by pip, sdists we + # have to unpack ourselves + sdist_path = next(temp_path.glob(f"{package}-{pkg_version}.*")) + + if sdist_path.suffix == ".zip": + import zipfile + archive = zipfile.ZipFile(sdist_path) + else: + import tarfile + archive = tarfile.open(sdist_path) + + archive.extractall(temp_path) + try: + info_path = next(temp_path.glob(f"**/*{suffix}")) + + # Let's check the wheel metadata has the + # expected directory name. We don't check for + # egg-info metadata, because we're pulling them + # from sdists where they don't have the proper + # directory name + if type == "wheel": + if info_path.name != install_path.name: + print("\nWarning: wheel metadata have unexpected directory name.\n" + f"Expected: {install_path.name}\n" + f"Actual: {info_path.name}\n" + f"Info: package '{package}', version '{pkg_version}'" + f" for Python {py_version}\n" + f"Possible resolution: Specify the package version with" + f" trailing zeros in test-requires.yaml", file=sys.stderr) + + shutil.move(info_path, install_path) + + relative_path = install_path.relative_to(TEST_DATA_PATH) + print(f"\nDownloaded metadata to '{relative_path}'" \ + f" inside test-data directory.\n") + except StopIteration: + # temp_path.glob() did not find any file and + # thus there's been some problem + sys.exit(f"Problem occured while getting dist-info/egg-info" + f" for package '{package}', version '{pkg_version}'" + f" for Python {py_version}") + if downloaded_anything: + print("\n==============================") + print("Finished downloading test data") + print("==============================") + + +@pytest.fixture(scope="session", autouse=True) +def fixture_check_and_install_test_data(): + """Wrapper fixture, because a fixture can't be called as a function.""" + check_and_install_test_data() + + +@pytest.mark.parametrize("provides_params, requires_params, dist_egg_info_path, expected", + generate_test_cases(load_test_data())) +def test_pythondistdeps(provides_params, requires_params, dist_egg_info_path, expected): + """Runs pythondistdeps with the given parameters and dist-info/egg-info + path, compares the results with the expected results""" + assert expected == run_pythondistdeps(provides_params, requires_params, dist_egg_info_path) + + +if __name__ == "__main__": + """If the script is called directly, we check and install test data if needed, + we look up all the test configurations in test-data.yaml, run + pythondistdeps for each, save the results and print the resulting YAML file + with the updated results.""" + + check_and_install_test_data() + + # Set YAML dump style to block style + def str_presenter(dumper, data): + if len(data.splitlines()) > 1: # check for multiline string + return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='|') + return dumper.represent_scalar('tag:yaml.org,2002:str', data) + yaml.add_representer(str, str_presenter) + + # Run pythondistdeps for each test configuration + test_data = load_test_data() + for provides_params, requires_params, dist_egg_info_path, expected in generate_test_cases(test_data): + # Print a dot to stderr for each test run to keep user informed about progress + print(".", end="", flush=True, file=sys.stderr) + test_data[requires_params][provides_params][dist_egg_info_path] = \ + run_pythondistdeps(provides_params, requires_params, dist_egg_info_path) + + print(yaml.dump(test_data, indent=4)) + From e33d4e94c86a813bc66b8efa6e01b74045e5324a Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Wed, 27 Nov 2019 18:16:43 +0100 Subject: [PATCH 029/110] scripts/pythondistdeps: Add option to generate major-version provides only for specified Python versions --- pythondistdeps.py | 22 +- .../scripts_pythondistdeps/test-data.yaml | 362 ++++++++++++++++++ 2 files changed, 380 insertions(+), 4 deletions(-) diff --git a/pythondistdeps.py b/pythondistdeps.py index 344334b..8d7bf2d 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -150,7 +150,11 @@ group.add_argument('-R', '--requires', action='store_true', help='Print Requires group.add_argument('-r', '--recommends', action='store_true', help='Print Recommends') group.add_argument('-C', '--conflicts', action='store_true', help='Print Conflicts') group.add_argument('-E', '--extras', action='store_true', help='Print Extras') -parser.add_argument('-M', '--majorver-provides', action='store_true', help='Print extra Provides with Python major version only') +group_majorver = parser.add_mutually_exclusive_group() +group_majorver.add_argument('-M', '--majorver-provides', action='store_true', help='Print extra Provides with Python major version only') +group_majorver.add_argument('--majorver-provides-versions', action='append', + help='Print extra Provides with Python major version only for listed ' + 'Python VERSIONS (appended or comma separated without spaces, e.g. 2.7,3.9)') parser.add_argument('-m', '--majorver-only', action='store_true', help='Print Provides/Requires with Python major version only') parser.add_argument('-L', '--legacy-provides', action='store_true', help='Print extra legacy pythonegg Provides') parser.add_argument('-l', '--legacy', action='store_true', help='Print legacy pythonegg Provides/Requires instead') @@ -160,6 +164,11 @@ args = parser.parse_args() py_abi = args.requires py_deps = {} +if args.majorver_provides_versions: + # Go through the arguments (can be specified multiple times), + # and parse individual versions (can be comma-separated) + args.majorver_provides_versions = [v for vstring in args.majorver_provides_versions + for v in vstring.split(",")] for f in (args.files or stdin.readlines()): f = f.strip() @@ -233,7 +242,8 @@ for f in (args.files or stdin.readlines()): # See https://bugzilla.redhat.com/show_bug.cgi?id=1791530 normalized_name = normalize_name(dist.project_name) - if args.majorver_provides or args.majorver_only or args.legacy_provides or args.legacy: + if args.majorver_provides or args.majorver_provides_versions or \ + args.majorver_only or args.legacy_provides or args.legacy: # Get the Python major version pyver_major = dist.py_version.split('.')[0] if args.provides: @@ -250,7 +260,9 @@ for f in (args.files or stdin.readlines()): name_ = 'python{}dist({})'.format(dist.py_version, normalized_name) if name_ not in py_deps: py_deps[name_] = [] - if args.majorver_provides or args.majorver_only: + if args.majorver_provides or args.majorver_only or \ + (args.majorver_provides_versions and + dist.py_version in args.majorver_provides_versions): pymajor_name = 'python{}dist({})'.format(pyver_major, dist.key) if pymajor_name not in py_deps: py_deps[pymajor_name] = [] @@ -269,7 +281,9 @@ for f in (args.files or stdin.readlines()): py_deps[name].append(spec) if name != name_: py_deps[name_].append(spec) - if args.majorver_provides: + if args.majorver_provides or \ + (args.majorver_provides_versions and + dist.py_version in args.majorver_provides_versions): py_deps[pymajor_name].append(spec) if pymajor_name != pymajor_name_: py_deps[pymajor_name_].append(spec) diff --git a/tests/data/scripts_pythondistdeps/test-data.yaml b/tests/data/scripts_pythondistdeps/test-data.yaml index ae4295a..dcfa080 100644 --- a/tests/data/scripts_pythondistdeps/test-data.yaml +++ b/tests/data/scripts_pythondistdeps/test-data.yaml @@ -478,3 +478,365 @@ python3.9dist(simplejson) = 3.16 python3dist(simplejson) = 3.16 requires: python(abi) = 3.9 + --provides --majorver-provides-versions 3.9 --majorver-provides-versions 2.7: + usr/lib/python2.7/site-packages/attrs-19.1.0-py2.7.egg-info: + provides: |- + python2.7dist(attrs) = 19.1 + python2dist(attrs) = 19.1 + requires: python(abi) = 2.7 + usr/lib/python2.7/site-packages/kubernetes-11.0.0b2.dist-info: + provides: |- + python2.7dist(kubernetes) = 11~b2 + python2dist(kubernetes) = 11~b2 + requires: |- + python(abi) = 2.7 + python2.7dist(certifi) >= 14.5.14 + python2.7dist(google-auth) >= 1.0.1 + python2.7dist(ipaddress) >= 1.0.17 + python2.7dist(python-dateutil) >= 2.5.3 + python2.7dist(pyyaml) >= 3.12 + python2.7dist(requests) + python2.7dist(requests-oauthlib) + python2.7dist(setuptools) >= 21 + python2.7dist(six) >= 1.9 + python2.7dist(urllib3) >= 1.24.2 + ((python2.7dist(websocket-client) < 0.40 or python2.7dist(websocket-client) > 0.40) with (python2.7dist(websocket-client) < 0.41 or python2.7dist(websocket-client) > 0.42) with (python2.7dist(websocket-client) < 0.42 or python2.7dist(websocket-client) > 0.43) with python2.7dist(websocket-client) >= 0.32) + usr/lib/python2.7/site-packages/mistune-0.8.4-py2.7.egg-info: + provides: |- + python2.7dist(mistune) = 0.8.4 + python2dist(mistune) = 0.8.4 + requires: python(abi) = 2.7 + usr/lib/python2.7/site-packages/packaging-19.0.dist-info: + provides: |- + python2.7dist(packaging) = 19 + python2dist(packaging) = 19 + requires: |- + python(abi) = 2.7 + python2.7dist(pyparsing) >= 2.0.2 + python2.7dist(six) + usr/lib/python2.7/site-packages/pip-19.1.1.dist-info: + provides: |- + python2.7dist(pip) = 19.1.1 + python2dist(pip) = 19.1.1 + requires: python(abi) = 2.7 + usr/lib/python2.7/site-packages/pyparsing-2.4.0.dist-info: + provides: |- + python2.7dist(pyparsing) = 2.4 + python2dist(pyparsing) = 2.4 + requires: python(abi) = 2.7 + usr/lib/python2.7/site-packages/setuptools-41.6.0-py2.7.egg-info: + provides: |- + python2.7dist(setuptools) = 41.6 + python2dist(setuptools) = 41.6 + requires: |- + python(abi) = 2.7 + python2.7dist(setuptools) + usr/lib/python2.7/site-packages/setuptools-41.6.0.dist-info: + provides: |- + python2.7dist(setuptools) = 41.6 + python2dist(setuptools) = 41.6 + requires: python(abi) = 2.7 + usr/lib/python2.7/site-packages/six-1.12.0.dist-info: + provides: |- + python2.7dist(six) = 1.12 + python2dist(six) = 1.12 + requires: python(abi) = 2.7 + usr/lib/python3.11/site-packages/pip-20.0.2-py3.11.egg-info: + provides: python3.11dist(pip) = 20.0.2 + requires: |- + python(abi) = 3.11 + python3.11dist(setuptools) + usr/lib/python3.7/site-packages/astroid-2.3.3.dist-info: + provides: python3.7dist(astroid) = 2.3.3 + requires: |- + python(abi) = 3.7 + (python3.7dist(lazy-object-proxy) >= 1.4 with python3.7dist(lazy-object-proxy) < 1.5) + (python3.7dist(six) >= 1.12 with python3.7dist(six) < 2) + (python3.7dist(typed-ast) < 1.5 with python3.7dist(typed-ast) >= 1.4) + (python3.7dist(wrapt) >= 1.11 with python3.7dist(wrapt) < 1.12) + usr/lib/python3.7/site-packages/packaging-19.0.dist-info: + provides: python3.7dist(packaging) = 19 + requires: |- + python(abi) = 3.7 + python3.7dist(pyparsing) >= 2.0.2 + python3.7dist(six) + usr/lib/python3.7/site-packages/pip-19.1.1.dist-info: + provides: python3.7dist(pip) = 19.1.1 + requires: python(abi) = 3.7 + usr/lib/python3.7/site-packages/pyparsing-2.4.0.dist-info: + provides: python3.7dist(pyparsing) = 2.4 + requires: python(abi) = 3.7 + usr/lib/python3.9/site-packages/attrs-19.1.0-py3.9.egg-info: + provides: |- + python3.9dist(attrs) = 19.1 + python3dist(attrs) = 19.1 + requires: python(abi) = 3.9 + usr/lib/python3.9/site-packages/mistune-0.8.4-py3.9.egg-info: + provides: |- + python3.9dist(mistune) = 0.8.4 + python3dist(mistune) = 0.8.4 + requires: python(abi) = 3.9 + usr/lib/python3.9/site-packages/packaging-20.1.dist-info: + provides: |- + python3.9dist(packaging) = 20.1 + python3dist(packaging) = 20.1 + requires: |- + python(abi) = 3.9 + python3.9dist(pyparsing) >= 2.0.2 + python3.9dist(six) + usr/lib/python3.9/site-packages/pip-20.0.2.dist-info: + provides: |- + python3.9dist(pip) = 20.0.2 + python3dist(pip) = 20.0.2 + requires: python(abi) = 3.9 + usr/lib/python3.9/site-packages/pyparsing-2.4.0.dist-info: + provides: |- + python3.9dist(pyparsing) = 2.4 + python3dist(pyparsing) = 2.4 + requires: python(abi) = 3.9 + usr/lib/python3.9/site-packages/setuptools-41.6.0-py3.9.egg-info: + provides: |- + python3.9dist(setuptools) = 41.6 + python3dist(setuptools) = 41.6 + requires: |- + python(abi) = 3.9 + python3.9dist(setuptools) + usr/lib/python3.9/site-packages/setuptools-41.6.0.dist-info: + provides: |- + python3.9dist(setuptools) = 41.6 + python3dist(setuptools) = 41.6 + requires: python(abi) = 3.9 + usr/lib/python3.9/site-packages/six-1.12.0.dist-info: + provides: |- + python3.9dist(six) = 1.12 + python3dist(six) = 1.12 + requires: python(abi) = 3.9 + usr/lib/python3.9/site-packages/tox-3.14.0.dist-info: + provides: |- + python3.9dist(tox) = 3.14 + python3dist(tox) = 3.14 + requires: |- + python(abi) = 3.9 + (python3.9dist(filelock) < 4 with python3.9dist(filelock) >= 3) + python3.9dist(packaging) >= 14 + (python3.9dist(pluggy) < 1 with python3.9dist(pluggy) >= 0.12) + (python3.9dist(py) < 2 with python3.9dist(py) >= 1.4.17) + (python3.9dist(six) < 2 with python3.9dist(six) >= 1) + python3.9dist(toml) >= 0.9.4 + python3.9dist(virtualenv) >= 14 + usr/lib/python3.9/site-packages/urllib3-1.25.7-py3.9.egg-info: + provides: |- + python3.9dist(urllib3) = 1.25.7 + python3dist(urllib3) = 1.25.7 + requires: python(abi) = 3.9 + usr/lib/python3.9/site-packages/zope.schema-4.4.2-py3.9.egg-info: + provides: |- + python3.9dist(zope.schema) = 4.4.2 + python3dist(zope.schema) = 4.4.2 + requires: |- + python(abi) = 3.9 + python3.9dist(setuptools) + python3.9dist(zope.event) + python3.9dist(zope.interface) >= 3.6 + usr/lib64/python2.7/site-packages/MarkupSafe-1.1.1.dist-info: + provides: |- + python2.7dist(markupsafe) = 1.1.1 + python2dist(markupsafe) = 1.1.1 + requires: python(abi) = 2.7 + usr/lib64/python2.7/site-packages/backports.range-3.7.2-py2.7.egg-info: + provides: |- + python2.7dist(backports.range) = 3.7.2 + python2dist(backports.range) = 3.7.2 + requires: python(abi) = 2.7 + usr/lib64/python2.7/site-packages/lxml-4.4.0.dist-info: + provides: |- + python2.7dist(lxml) = 4.4 + python2dist(lxml) = 4.4 + requires: python(abi) = 2.7 + usr/lib64/python2.7/site-packages/numpy-1.16.4.dist-info: + provides: |- + python2.7dist(numpy) = 1.16.4 + python2dist(numpy) = 1.16.4 + requires: python(abi) = 2.7 + usr/lib64/python2.7/site-packages/numpy_stl-2.11.2-py2.7.egg-info: + provides: |- + python2.7dist(numpy-stl) = 2.11.2 + python2dist(numpy-stl) = 2.11.2 + requires: |- + python(abi) = 2.7 + python2.7dist(numpy) + python2.7dist(python-utils) >= 1.6.2 + python2.7dist(setuptools) + --provides --majorver-provides-versions 3.9,2.7: + usr/lib/python2.7/site-packages/tox-3.14.0.dist-info: + provides: |- + python2.7dist(tox) = 3.14 + python2dist(tox) = 3.14 + requires: |- + python(abi) = 2.7 + (python2.7dist(filelock) < 4 with python2.7dist(filelock) >= 3) + (python2.7dist(importlib-metadata) < 1 with python2.7dist(importlib-metadata) >= 0.12) + python2.7dist(packaging) >= 14 + (python2.7dist(pluggy) < 1 with python2.7dist(pluggy) >= 0.12) + (python2.7dist(py) < 2 with python2.7dist(py) >= 1.4.17) + (python2.7dist(six) < 2 with python2.7dist(six) >= 1) + python2.7dist(toml) >= 0.9.4 + python2.7dist(virtualenv) >= 14 + usr/lib/python2.7/site-packages/urllib3-1.25.7-py2.7.egg-info: + provides: |- + python2.7dist(urllib3) = 1.25.7 + python2dist(urllib3) = 1.25.7 + requires: python(abi) = 2.7 + usr/lib/python2.7/site-packages/zope.component-4.3.0-py2.7.egg-info: + provides: |- + python2.7dist(zope.component) = 4.3 + python2dist(zope.component) = 4.3 + requires: |- + python(abi) = 2.7 + python2.7dist(setuptools) + python2.7dist(zope.event) + python2.7dist(zope.interface) >= 4.1 + usr/lib/python3.10/site-packages/setuptools-41.6.0-py3.10.egg-info: + provides: python3.10dist(setuptools) = 41.6 + requires: |- + python(abi) = 3.10 + python3.10dist(setuptools) + usr/lib/python3.7/site-packages/setuptools-41.6.0-py3.7.egg-info: + provides: python3.7dist(setuptools) = 41.6 + requires: |- + python(abi) = 3.7 + python3.7dist(setuptools) + usr/lib/python3.7/site-packages/setuptools-41.6.0.dist-info: + provides: python3.7dist(setuptools) = 41.6 + requires: python(abi) = 3.7 + usr/lib/python3.7/site-packages/six-1.12.0.dist-info: + provides: python3.7dist(six) = 1.12 + requires: python(abi) = 3.7 + usr/lib/python3.7/site-packages/tox-3.14.0.dist-info: + provides: python3.7dist(tox) = 3.14 + requires: |- + python(abi) = 3.7 + (python3.7dist(filelock) < 4 with python3.7dist(filelock) >= 3) + (python3.7dist(importlib-metadata) < 1 with python3.7dist(importlib-metadata) >= 0.12) + python3.7dist(packaging) >= 14 + (python3.7dist(pluggy) < 1 with python3.7dist(pluggy) >= 0.12) + (python3.7dist(py) < 2 with python3.7dist(py) >= 1.4.17) + (python3.7dist(six) < 2 with python3.7dist(six) >= 1) + python3.7dist(toml) >= 0.9.4 + python3.7dist(virtualenv) >= 14 + usr/lib64/python2.7/site-packages/scipy-1.2.1.dist-info: + provides: |- + python2.7dist(scipy) = 1.2.1 + python2dist(scipy) = 1.2.1 + requires: |- + python(abi) = 2.7 + python2.7dist(numpy) >= 1.8.2 + usr/lib64/python2.7/site-packages/simplejson-3.16.0-py2.7.egg-info: + provides: |- + python2.7dist(simplejson) = 3.16 + python2dist(simplejson) = 3.16 + requires: python(abi) = 2.7 + usr/lib64/python3.7/site-packages/MarkupSafe-1.1.1.dist-info: + provides: python3.7dist(markupsafe) = 1.1.1 + requires: python(abi) = 3.7 + usr/lib64/python3.7/site-packages/PyQt5_sip-4.19.19.dist-info: + provides: python3.7dist(pyqt5-sip) = 4.19.19 + requires: python(abi) = 3.7 + usr/lib64/python3.7/site-packages/PyQtWebEngine-5.12.1.dist-info: + provides: python3.7dist(pyqtwebengine) = 5.12.1 + requires: |- + python(abi) = 3.7 + python3.7dist(pyqt5) >= 5.12 + usr/lib64/python3.7/site-packages/backports.range-3.7.2-py3.7.egg-info: + provides: python3.7dist(backports.range) = 3.7.2 + requires: python(abi) = 3.7 + usr/lib64/python3.7/site-packages/lxml-4.4.0.dist-info: + provides: python3.7dist(lxml) = 4.4 + requires: python(abi) = 3.7 + usr/lib64/python3.7/site-packages/numpy-1.17.4.dist-info: + provides: python3.7dist(numpy) = 1.17.4 + requires: python(abi) = 3.7 + usr/lib64/python3.7/site-packages/numpy_stl-2.11.2-py3.7.egg-info: + provides: python3.7dist(numpy-stl) = 2.11.2 + requires: |- + python(abi) = 3.7 + python3.7dist(numpy) + python3.7dist(python-utils) >= 1.6.2 + python3.7dist(setuptools) + usr/lib64/python3.7/site-packages/scipy-1.2.1.dist-info: + provides: python3.7dist(scipy) = 1.2.1 + requires: |- + python(abi) = 3.7 + python3.7dist(numpy) >= 1.8.2 + usr/lib64/python3.7/site-packages/simplejson-3.16.0-py3.7.egg-info: + provides: python3.7dist(simplejson) = 3.16 + requires: python(abi) = 3.7 + usr/lib64/python3.9/site-packages/PyQtWebEngine-5.12.1.dist-info: + provides: |- + python3.9dist(pyqtwebengine) = 5.12.1 + python3dist(pyqtwebengine) = 5.12.1 + requires: |- + python(abi) = 3.9 + python3.9dist(pyqt5) >= 5.12 + usr/lib64/python3.9/site-packages/backports.range-3.7.2-py3.9.egg-info: + provides: |- + python3.9dist(backports.range) = 3.7.2 + python3dist(backports.range) = 3.7.2 + requires: python(abi) = 3.9 + usr/lib64/python3.9/site-packages/numpy_stl-2.11.2-py3.9.egg-info: + provides: |- + python3.9dist(numpy-stl) = 2.11.2 + python3dist(numpy-stl) = 2.11.2 + requires: |- + python(abi) = 3.9 + python3.9dist(numpy) + python3.9dist(python-utils) >= 1.6.2 + python3.9dist(setuptools) + usr/lib64/python3.9/site-packages/simplejson-3.16.0-py3.9.egg-info: + provides: |- + python3.9dist(simplejson) = 3.16 + python3dist(simplejson) = 3.16 + requires: python(abi) = 3.9 + --provides --majorver-provides-versions 3.9,2.7 --majorver-provides-versions 3.10: + usr/lib/python2.7/site-packages/zope.interface-4.6.0.dist-info: + provides: |- + python2.7dist(zope.interface) = 4.6 + python2dist(zope.interface) = 4.6 + requires: |- + python(abi) = 2.7 + python2.7dist(setuptools) + usr/lib/python3.10/site-packages/setuptools-41.6.0-py3.10.egg-info: + provides: |- + python3.10dist(setuptools) = 41.6 + python3dist(setuptools) = 41.6 + requires: |- + python(abi) = 3.10 + python3.10dist(setuptools) + usr/lib/python3.11/site-packages/pip-20.0.2-py3.11.egg-info: + provides: python3.11dist(pip) = 20.0.2 + requires: |- + python(abi) = 3.11 + python3.11dist(setuptools) + usr/lib64/python3.7/site-packages/lxml-4.4.0.dist-info: + provides: python3.7dist(lxml) = 4.4 + requires: python(abi) = 3.7 + usr/lib64/python3.9/site-packages/simplejson-3.16.0-py3.9.egg-info: + provides: |- + python3.9dist(simplejson) = 3.16 + python3dist(simplejson) = 3.16 + requires: python(abi) = 3.9 + --provides --majorver-provides-versions 3.9: + usr/lib/python2.7/site-packages/zope.interface-4.6.0.dist-info: + provides: |- + python2.7dist(zope.interface) = 4.6 + requires: |- + python(abi) = 2.7 + python2.7dist(setuptools) + usr/lib64/python3.7/site-packages/lxml-4.4.0.dist-info: + provides: python3.7dist(lxml) = 4.4 + requires: python(abi) = 3.7 + usr/lib64/python3.9/site-packages/simplejson-3.16.0-py3.9.egg-info: + provides: |- + python3.9dist(simplejson) = 3.16 + python3dist(simplejson) = 3.16 + requires: python(abi) = 3.9 From 1523def34e1098262fc1c8327a5905d32a28c902 Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Tue, 7 Apr 2020 01:10:42 +0200 Subject: [PATCH 030/110] scripts/pythondistdeps: Implement --normalized-name-* options --normalized-names-format FORMAT FORMAT of normalized names can be `pep503` [default] or `legacy-dots` (dots allowed) --normalized-names-provide-both Provede both `pep503` and `legacy-dots` format of normalized names (useful for a transition period) --- pythondistdeps.py | 86 +++-- .../scripts_pythondistdeps/test-data.yaml | 356 ++++++++++++++++++ 2 files changed, 414 insertions(+), 28 deletions(-) diff --git a/pythondistdeps.py b/pythondistdeps.py index 8d7bf2d..09467f5 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -156,11 +156,17 @@ group_majorver.add_argument('--majorver-provides-versions', action='append', help='Print extra Provides with Python major version only for listed ' 'Python VERSIONS (appended or comma separated without spaces, e.g. 2.7,3.9)') parser.add_argument('-m', '--majorver-only', action='store_true', help='Print Provides/Requires with Python major version only') +parser.add_argument('-n', '--normalized-names-format', action='store', + default="legacy-dots", choices=["pep503", "legacy-dots"], + help='Format of normalized names according to pep503 or legacy format that allows dots [default]') +parser.add_argument('--normalized-names-provide-both', action='store_true', + help='Provide both `pep503` and `legacy-dots` format of normalized names (useful for a transition period)') parser.add_argument('-L', '--legacy-provides', action='store_true', help='Print extra legacy pythonegg Provides') parser.add_argument('-l', '--legacy', action='store_true', help='Print legacy pythonegg Provides/Requires instead') parser.add_argument('files', nargs=argparse.REMAINDER) args = parser.parse_args() + py_abi = args.requires py_deps = {} @@ -170,6 +176,20 @@ if args.majorver_provides_versions: args.majorver_provides_versions = [v for vstring in args.majorver_provides_versions for v in vstring.split(",")] +# If normalized_names_require_pep503 is True we require the pep503 +# normalized name, if it is False we provide the legacy normalized name +normalized_names_require_pep503 = args.normalized_names_format == "pep503" + +# If normalized_names_provide_pep503/legacy is True we provide the +# pep503/legacy normalized name, if it is False we don't +normalized_names_provide_pep503 = \ + args.normalized_names_format == "pep503" or args.normalized_names_provide_both +normalized_names_provide_legacy = \ + args.normalized_names_format == "legacy-dots" or args.normalized_names_provide_both + +# At least one type of normalization must be provided +assert normalized_names_provide_pep503 or normalized_names_provide_legacy + for f in (args.files or stdin.readlines()): f = f.strip() lower = f.lower() @@ -237,8 +257,6 @@ for f in (args.files or stdin.readlines()): # This is the PEP 503 normalized name. # It does also convert dots to dashes, unlike dist.key. - # In the current code, we only add additional provides with this. - # Later, we can start requiring them. # See https://bugzilla.redhat.com/show_bug.cgi?id=1791530 normalized_name = normalize_name(dist.project_name) @@ -254,21 +272,24 @@ for f in (args.files or stdin.readlines()): py_deps[name] = [] py_deps[name].append(('==', dist.py_version)) if not args.legacy or not args.majorver_only: - name = 'python{}dist({})'.format(dist.py_version, dist.key) - if name not in py_deps: - py_deps[name] = [] - name_ = 'python{}dist({})'.format(dist.py_version, normalized_name) - if name_ not in py_deps: - py_deps[name_] = [] + if normalized_names_provide_legacy: + name = 'python{}dist({})'.format(dist.py_version, dist.key) + if name not in py_deps: + py_deps[name] = [] + if normalized_names_provide_pep503: + name_ = 'python{}dist({})'.format(dist.py_version, normalized_name) + if name_ not in py_deps: + py_deps[name_] = [] if args.majorver_provides or args.majorver_only or \ - (args.majorver_provides_versions and - dist.py_version in args.majorver_provides_versions): - pymajor_name = 'python{}dist({})'.format(pyver_major, dist.key) - if pymajor_name not in py_deps: - py_deps[pymajor_name] = [] - pymajor_name_ = 'python{}dist({})'.format(pyver_major, normalized_name) - if pymajor_name_ not in py_deps: - py_deps[pymajor_name_] = [] + (args.majorver_provides_versions and dist.py_version in args.majorver_provides_versions): + if normalized_names_provide_legacy: + pymajor_name = 'python{}dist({})'.format(pyver_major, dist.key) + if pymajor_name not in py_deps: + py_deps[pymajor_name] = [] + if normalized_names_provide_pep503: + pymajor_name_ = 'python{}dist({})'.format(pyver_major, normalized_name) + if pymajor_name_ not in py_deps: + py_deps[pymajor_name_] = [] if args.legacy or args.legacy_provides: legacy_name = 'pythonegg({})({})'.format(pyver_major, dist.key) if legacy_name not in py_deps: @@ -276,18 +297,21 @@ for f in (args.files or stdin.readlines()): if dist.version: version = dist.version spec = ('==', version) - if spec not in py_deps[name]: - if not args.legacy: + + if normalized_names_provide_legacy: + if spec not in py_deps[name]: py_deps[name].append(spec) - if name != name_: - py_deps[name_].append(spec) - if args.majorver_provides or \ - (args.majorver_provides_versions and - dist.py_version in args.majorver_provides_versions): - py_deps[pymajor_name].append(spec) - if pymajor_name != pymajor_name_: + if args.majorver_provides or \ + (args.majorver_provides_versions and dist.py_version in args.majorver_provides_versions): + py_deps[pymajor_name].append(spec) + if normalized_names_provide_pep503: + if spec not in py_deps[name_]: + py_deps[name_].append(spec) + if args.majorver_provides or \ + (args.majorver_provides_versions and dist.py_version in args.majorver_provides_versions): py_deps[pymajor_name_].append(spec) - if args.legacy or args.legacy_provides: + if args.legacy or args.legacy_provides: + if spec not in py_deps[legacy_name]: py_deps[legacy_name].append(spec) if args.requires or (args.recommends and dist.extras): name = 'python(abi)' @@ -319,13 +343,18 @@ for f in (args.files or stdin.readlines()): deps.insert(0, Requirement.parse('setuptools')) # add requires/recommends based on egg/dist metadata for dep in deps: + if normalized_names_require_pep503: + dep_normalized_name = normalize_name(dep.project_name) + else: + dep_normalized_name = dep.key + if args.legacy: name = 'pythonegg({})({})'.format(pyver_major, dep.key) else: if args.majorver_only: - name = 'python{}dist({})'.format(pyver_major, dep.key) + name = 'python{}dist({})'.format(pyver_major, dep_normalized_name) else: - name = 'python{}dist({})'.format(dist.py_version, dep.key) + name = 'python{}dist({})'.format(dist.py_version, dep_normalized_name) for spec in dep.specs: if name not in py_deps: py_deps[name] = [] @@ -370,6 +399,7 @@ for f in (args.files or stdin.readlines()): spec = ('==', spec[1]) if spec not in py_deps[name]: py_deps[name].append(spec) + names = list(py_deps.keys()) names.sort() for name in names: diff --git a/tests/data/scripts_pythondistdeps/test-data.yaml b/tests/data/scripts_pythondistdeps/test-data.yaml index dcfa080..d396254 100644 --- a/tests/data/scripts_pythondistdeps/test-data.yaml +++ b/tests/data/scripts_pythondistdeps/test-data.yaml @@ -840,3 +840,359 @@ python3.9dist(simplejson) = 3.16 python3dist(simplejson) = 3.16 requires: python(abi) = 3.9 +--requires --normalized-names-format legacy-dots: + --provides --majorver-provides --normalized-names-format legacy-dots: + usr/lib/python2.7/site-packages/zope.component-4.3.0-py2.7.egg-info: + provides: |- + python2.7dist(zope.component) = 4.3 + python2dist(zope.component) = 4.3 + requires: |- + python(abi) = 2.7 + python2.7dist(setuptools) + python2.7dist(zope.event) + python2.7dist(zope.interface) >= 4.1 + usr/lib/python2.7/site-packages/zope.event-4.2.0.dist-info: + provides: |- + python2.7dist(zope.event) = 4.2 + python2dist(zope.event) = 4.2 + requires: |- + python(abi) = 2.7 + python2.7dist(setuptools) + usr/lib/python2.7/site-packages/zope.interface-4.6.0.dist-info: + provides: |- + python2.7dist(zope.interface) = 4.6 + python2dist(zope.interface) = 4.6 + requires: |- + python(abi) = 2.7 + python2.7dist(setuptools) + usr/lib/python2.7/site-packages/zope.schema-4.4.2-py2.7.egg-info: + provides: |- + python2.7dist(zope.schema) = 4.4.2 + python2dist(zope.schema) = 4.4.2 + requires: |- + python(abi) = 2.7 + python2.7dist(setuptools) + python2.7dist(zope.event) + python2.7dist(zope.interface) >= 3.6 + usr/lib/python3.10/site-packages/setuptools-41.6.0-py3.10.egg-info: + provides: |- + python3.10dist(setuptools) = 41.6 + python3dist(setuptools) = 41.6 + requires: |- + python(abi) = 3.10 + python3.10dist(setuptools) + usr/lib/python3.11/site-packages/pip-20.0.2-py3.11.egg-info: + provides: |- + python3.11dist(pip) = 20.0.2 + python3dist(pip) = 20.0.2 + requires: |- + python(abi) = 3.11 + python3.11dist(setuptools) + usr/lib/python3.9/site-packages/zope.component-4.3.0-py3.9.egg-info: + provides: |- + python3.9dist(zope.component) = 4.3 + python3dist(zope.component) = 4.3 + requires: |- + python(abi) = 3.9 + python3.9dist(setuptools) + python3.9dist(zope.event) + python3.9dist(zope.interface) >= 4.1 + usr/lib/python3.9/site-packages/zope.event-4.2.0.dist-info: + provides: |- + python3.9dist(zope.event) = 4.2 + python3dist(zope.event) = 4.2 + requires: |- + python(abi) = 3.9 + python3.9dist(setuptools) + usr/lib/python3.9/site-packages/zope.interface-5.1.0-py3.9.egg-info: + provides: |- + python3.9dist(zope.interface) = 5.1 + python3dist(zope.interface) = 5.1 + requires: |- + python(abi) = 3.9 + python3.9dist(setuptools) + usr/lib/python3.9/site-packages/zope.schema-4.4.2-py3.9.egg-info: + provides: |- + python3.9dist(zope.schema) = 4.4.2 + python3dist(zope.schema) = 4.4.2 + requires: |- + python(abi) = 3.9 + python3.9dist(setuptools) + python3.9dist(zope.event) + python3.9dist(zope.interface) >= 3.6 + usr/lib64/python2.7/site-packages/backports.range-3.7.2-py2.7.egg-info: + provides: |- + python2.7dist(backports.range) = 3.7.2 + python2dist(backports.range) = 3.7.2 + requires: python(abi) = 2.7 + usr/lib64/python3.7/site-packages/backports.range-3.7.2-py3.7.egg-info: + provides: |- + python3.7dist(backports.range) = 3.7.2 + python3dist(backports.range) = 3.7.2 + requires: python(abi) = 3.7 + --provides --majorver-provides --normalized-names-format legacy-dots --normalized-names-provide-both: + usr/lib/python2.7/site-packages/zope.component-4.3.0-py2.7.egg-info: + provides: |- + python2.7dist(zope-component) = 4.3 + python2.7dist(zope.component) = 4.3 + python2dist(zope-component) = 4.3 + python2dist(zope.component) = 4.3 + requires: |- + python(abi) = 2.7 + python2.7dist(setuptools) + python2.7dist(zope.event) + python2.7dist(zope.interface) >= 4.1 + usr/lib/python2.7/site-packages/zope.event-4.2.0.dist-info: + provides: |- + python2.7dist(zope-event) = 4.2 + python2.7dist(zope.event) = 4.2 + python2dist(zope-event) = 4.2 + python2dist(zope.event) = 4.2 + requires: |- + python(abi) = 2.7 + python2.7dist(setuptools) + usr/lib/python2.7/site-packages/zope.interface-4.6.0.dist-info: + provides: |- + python2.7dist(zope-interface) = 4.6 + python2.7dist(zope.interface) = 4.6 + python2dist(zope-interface) = 4.6 + python2dist(zope.interface) = 4.6 + requires: |- + python(abi) = 2.7 + python2.7dist(setuptools) + usr/lib/python2.7/site-packages/zope.schema-4.4.2-py2.7.egg-info: + provides: |- + python2.7dist(zope-schema) = 4.4.2 + python2.7dist(zope.schema) = 4.4.2 + python2dist(zope-schema) = 4.4.2 + python2dist(zope.schema) = 4.4.2 + requires: |- + python(abi) = 2.7 + python2.7dist(setuptools) + python2.7dist(zope.event) + python2.7dist(zope.interface) >= 3.6 + usr/lib/python3.9/site-packages/zope.component-4.3.0-py3.9.egg-info: + provides: |- + python3.9dist(zope-component) = 4.3 + python3.9dist(zope.component) = 4.3 + python3dist(zope-component) = 4.3 + python3dist(zope.component) = 4.3 + requires: |- + python(abi) = 3.9 + python3.9dist(setuptools) + python3.9dist(zope.event) + python3.9dist(zope.interface) >= 4.1 + usr/lib/python3.9/site-packages/zope.event-4.2.0.dist-info: + provides: |- + python3.9dist(zope-event) = 4.2 + python3.9dist(zope.event) = 4.2 + python3dist(zope-event) = 4.2 + python3dist(zope.event) = 4.2 + requires: |- + python(abi) = 3.9 + python3.9dist(setuptools) + usr/lib/python3.9/site-packages/zope.interface-5.1.0-py3.9.egg-info: + provides: |- + python3.9dist(zope-interface) = 5.1 + python3.9dist(zope.interface) = 5.1 + python3dist(zope-interface) = 5.1 + python3dist(zope.interface) = 5.1 + requires: |- + python(abi) = 3.9 + python3.9dist(setuptools) + usr/lib/python3.9/site-packages/zope.schema-4.4.2-py3.9.egg-info: + provides: |- + python3.9dist(zope-schema) = 4.4.2 + python3.9dist(zope.schema) = 4.4.2 + python3dist(zope-schema) = 4.4.2 + python3dist(zope.schema) = 4.4.2 + requires: |- + python(abi) = 3.9 + python3.9dist(setuptools) + python3.9dist(zope.event) + python3.9dist(zope.interface) >= 3.6 + usr/lib64/python2.7/site-packages/backports.range-3.7.2-py2.7.egg-info: + provides: |- + python2.7dist(backports-range) = 3.7.2 + python2.7dist(backports.range) = 3.7.2 + python2dist(backports-range) = 3.7.2 + python2dist(backports.range) = 3.7.2 + requires: python(abi) = 2.7 + usr/lib64/python3.7/site-packages/backports.range-3.7.2-py3.7.egg-info: + provides: |- + python3.7dist(backports-range) = 3.7.2 + python3.7dist(backports.range) = 3.7.2 + python3dist(backports-range) = 3.7.2 + python3dist(backports.range) = 3.7.2 + requires: python(abi) = 3.7 +--requires --normalized-names-format pep503: + --provides --majorver-provides --normalized-names-format pep503: + usr/lib/python2.7/site-packages/zope.component-4.3.0-py2.7.egg-info: + provides: |- + python2.7dist(zope-component) = 4.3 + python2dist(zope-component) = 4.3 + requires: |- + python(abi) = 2.7 + python2.7dist(setuptools) + python2.7dist(zope-event) + python2.7dist(zope-interface) >= 4.1 + usr/lib/python2.7/site-packages/zope.event-4.2.0.dist-info: + provides: |- + python2.7dist(zope-event) = 4.2 + python2dist(zope-event) = 4.2 + requires: |- + python(abi) = 2.7 + python2.7dist(setuptools) + usr/lib/python2.7/site-packages/zope.interface-4.6.0.dist-info: + provides: |- + python2.7dist(zope-interface) = 4.6 + python2dist(zope-interface) = 4.6 + requires: |- + python(abi) = 2.7 + python2.7dist(setuptools) + usr/lib/python2.7/site-packages/zope.schema-4.4.2-py2.7.egg-info: + provides: |- + python2.7dist(zope-schema) = 4.4.2 + python2dist(zope-schema) = 4.4.2 + requires: |- + python(abi) = 2.7 + python2.7dist(setuptools) + python2.7dist(zope-event) + python2.7dist(zope-interface) >= 3.6 + usr/lib/python3.9/site-packages/zope.component-4.3.0-py3.9.egg-info: + provides: |- + python3.9dist(zope-component) = 4.3 + python3dist(zope-component) = 4.3 + requires: |- + python(abi) = 3.9 + python3.9dist(setuptools) + python3.9dist(zope-event) + python3.9dist(zope-interface) >= 4.1 + usr/lib/python3.9/site-packages/zope.event-4.2.0.dist-info: + provides: |- + python3.9dist(zope-event) = 4.2 + python3dist(zope-event) = 4.2 + requires: |- + python(abi) = 3.9 + python3.9dist(setuptools) + usr/lib/python3.9/site-packages/zope.interface-5.1.0-py3.9.egg-info: + provides: |- + python3.9dist(zope-interface) = 5.1 + python3dist(zope-interface) = 5.1 + requires: |- + python(abi) = 3.9 + python3.9dist(setuptools) + usr/lib/python3.9/site-packages/zope.schema-4.4.2-py3.9.egg-info: + provides: |- + python3.9dist(zope-schema) = 4.4.2 + python3dist(zope-schema) = 4.4.2 + requires: |- + python(abi) = 3.9 + python3.9dist(setuptools) + python3.9dist(zope-event) + python3.9dist(zope-interface) >= 3.6 + usr/lib64/python2.7/site-packages/backports.range-3.7.2-py2.7.egg-info: + provides: |- + python2.7dist(backports-range) = 3.7.2 + python2dist(backports-range) = 3.7.2 + requires: python(abi) = 2.7 + usr/lib64/python3.7/site-packages/backports.range-3.7.2-py3.7.egg-info: + provides: |- + python3.7dist(backports-range) = 3.7.2 + python3dist(backports-range) = 3.7.2 + requires: python(abi) = 3.7 + --provides --majorver-provides --normalized-names-format pep503 --normalized-names-provide-both: + usr/lib/python2.7/site-packages/zope.component-4.3.0-py2.7.egg-info: + provides: |- + python2.7dist(zope-component) = 4.3 + python2.7dist(zope.component) = 4.3 + python2dist(zope-component) = 4.3 + python2dist(zope.component) = 4.3 + requires: |- + python(abi) = 2.7 + python2.7dist(setuptools) + python2.7dist(zope-event) + python2.7dist(zope-interface) >= 4.1 + usr/lib/python2.7/site-packages/zope.event-4.2.0.dist-info: + provides: |- + python2.7dist(zope-event) = 4.2 + python2.7dist(zope.event) = 4.2 + python2dist(zope-event) = 4.2 + python2dist(zope.event) = 4.2 + requires: |- + python(abi) = 2.7 + python2.7dist(setuptools) + usr/lib/python2.7/site-packages/zope.interface-4.6.0.dist-info: + provides: |- + python2.7dist(zope-interface) = 4.6 + python2.7dist(zope.interface) = 4.6 + python2dist(zope-interface) = 4.6 + python2dist(zope.interface) = 4.6 + requires: |- + python(abi) = 2.7 + python2.7dist(setuptools) + usr/lib/python2.7/site-packages/zope.schema-4.4.2-py2.7.egg-info: + provides: |- + python2.7dist(zope-schema) = 4.4.2 + python2.7dist(zope.schema) = 4.4.2 + python2dist(zope-schema) = 4.4.2 + python2dist(zope.schema) = 4.4.2 + requires: |- + python(abi) = 2.7 + python2.7dist(setuptools) + python2.7dist(zope-event) + python2.7dist(zope-interface) >= 3.6 + usr/lib/python3.9/site-packages/zope.component-4.3.0-py3.9.egg-info: + provides: |- + python3.9dist(zope-component) = 4.3 + python3.9dist(zope.component) = 4.3 + python3dist(zope-component) = 4.3 + python3dist(zope.component) = 4.3 + requires: |- + python(abi) = 3.9 + python3.9dist(setuptools) + python3.9dist(zope-event) + python3.9dist(zope-interface) >= 4.1 + usr/lib/python3.9/site-packages/zope.event-4.2.0.dist-info: + provides: |- + python3.9dist(zope-event) = 4.2 + python3.9dist(zope.event) = 4.2 + python3dist(zope-event) = 4.2 + python3dist(zope.event) = 4.2 + requires: |- + python(abi) = 3.9 + python3.9dist(setuptools) + usr/lib/python3.9/site-packages/zope.interface-5.1.0-py3.9.egg-info: + provides: |- + python3.9dist(zope-interface) = 5.1 + python3.9dist(zope.interface) = 5.1 + python3dist(zope-interface) = 5.1 + python3dist(zope.interface) = 5.1 + requires: |- + python(abi) = 3.9 + python3.9dist(setuptools) + usr/lib/python3.9/site-packages/zope.schema-4.4.2-py3.9.egg-info: + provides: |- + python3.9dist(zope-schema) = 4.4.2 + python3.9dist(zope.schema) = 4.4.2 + python3dist(zope-schema) = 4.4.2 + python3dist(zope.schema) = 4.4.2 + requires: |- + python(abi) = 3.9 + python3.9dist(setuptools) + python3.9dist(zope-event) + python3.9dist(zope-interface) >= 3.6 + usr/lib64/python2.7/site-packages/backports.range-3.7.2-py2.7.egg-info: + provides: |- + python2.7dist(backports-range) = 3.7.2 + python2.7dist(backports.range) = 3.7.2 + python2dist(backports-range) = 3.7.2 + python2dist(backports.range) = 3.7.2 + requires: python(abi) = 2.7 + usr/lib64/python3.7/site-packages/backports.range-3.7.2-py3.7.egg-info: + provides: |- + python3.7dist(backports-range) = 3.7.2 + python3.7dist(backports.range) = 3.7.2 + python3dist(backports-range) = 3.7.2 + python3dist(backports.range) = 3.7.2 + requires: python(abi) = 3.7 From d48f3500d802e30c6ae6a6bf922e4d2f0c28ec53 Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Mon, 20 Apr 2020 16:37:29 +0200 Subject: [PATCH 031/110] scripts/pythondistdeps: Do anything only when called as a main script Note that the code is completely unchanged except for the indentation under the new if __name__ == "__main__": Note that this change is necessary, but not sufficient to use the RpmVersion class. The init of the RpmVersion class will fail when called from an outside script, because the `parse_version()` function is lazily imported from the code outside the class. However, adding the import of parse_version() to RpmVersion class is not done right now, because while we would import it from `pkg_resources`, other scripts might want to rely instead of the lightweight `packaging` module for the import. Thus I'm leaving this conondrum to be addressed in the future. --- pythondistdeps.py | 515 +++++++++++++++++++++++----------------------- 1 file changed, 259 insertions(+), 256 deletions(-) diff --git a/pythondistdeps.py b/pythondistdeps.py index 09467f5..9787dc8 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -143,276 +143,279 @@ def normalize_name(name): return re.sub(r'[-_.]+', '-', name).lower() -parser = argparse.ArgumentParser(prog=argv[0]) -group = parser.add_mutually_exclusive_group(required=True) -group.add_argument('-P', '--provides', action='store_true', help='Print Provides') -group.add_argument('-R', '--requires', action='store_true', help='Print Requires') -group.add_argument('-r', '--recommends', action='store_true', help='Print Recommends') -group.add_argument('-C', '--conflicts', action='store_true', help='Print Conflicts') -group.add_argument('-E', '--extras', action='store_true', help='Print Extras') -group_majorver = parser.add_mutually_exclusive_group() -group_majorver.add_argument('-M', '--majorver-provides', action='store_true', help='Print extra Provides with Python major version only') -group_majorver.add_argument('--majorver-provides-versions', action='append', - help='Print extra Provides with Python major version only for listed ' - 'Python VERSIONS (appended or comma separated without spaces, e.g. 2.7,3.9)') -parser.add_argument('-m', '--majorver-only', action='store_true', help='Print Provides/Requires with Python major version only') -parser.add_argument('-n', '--normalized-names-format', action='store', - default="legacy-dots", choices=["pep503", "legacy-dots"], - help='Format of normalized names according to pep503 or legacy format that allows dots [default]') -parser.add_argument('--normalized-names-provide-both', action='store_true', - help='Provide both `pep503` and `legacy-dots` format of normalized names (useful for a transition period)') -parser.add_argument('-L', '--legacy-provides', action='store_true', help='Print extra legacy pythonegg Provides') -parser.add_argument('-l', '--legacy', action='store_true', help='Print legacy pythonegg Provides/Requires instead') -parser.add_argument('files', nargs=argparse.REMAINDER) -args = parser.parse_args() +if __name__ == "__main__": + """To allow this script to be importable (and its classes/functions + reused), actions are performed only when run as a main script.""" + parser = argparse.ArgumentParser(prog=argv[0]) + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument('-P', '--provides', action='store_true', help='Print Provides') + group.add_argument('-R', '--requires', action='store_true', help='Print Requires') + group.add_argument('-r', '--recommends', action='store_true', help='Print Recommends') + group.add_argument('-C', '--conflicts', action='store_true', help='Print Conflicts') + group.add_argument('-E', '--extras', action='store_true', help='Print Extras') + group_majorver = parser.add_mutually_exclusive_group() + group_majorver.add_argument('-M', '--majorver-provides', action='store_true', help='Print extra Provides with Python major version only') + group_majorver.add_argument('--majorver-provides-versions', action='append', + help='Print extra Provides with Python major version only for listed ' + 'Python VERSIONS (appended or comma separated without spaces, e.g. 2.7,3.9)') + parser.add_argument('-m', '--majorver-only', action='store_true', help='Print Provides/Requires with Python major version only') + parser.add_argument('-n', '--normalized-names-format', action='store', + default="legacy-dots", choices=["pep503", "legacy-dots"], + help='Format of normalized names according to pep503 or legacy format that allows dots [default]') + parser.add_argument('--normalized-names-provide-both', action='store_true', + help='Provide both `pep503` and `legacy-dots` format of normalized names (useful for a transition period)') + parser.add_argument('-L', '--legacy-provides', action='store_true', help='Print extra legacy pythonegg Provides') + parser.add_argument('-l', '--legacy', action='store_true', help='Print legacy pythonegg Provides/Requires instead') + parser.add_argument('files', nargs=argparse.REMAINDER) + args = parser.parse_args() -py_abi = args.requires -py_deps = {} + py_abi = args.requires + py_deps = {} -if args.majorver_provides_versions: - # Go through the arguments (can be specified multiple times), - # and parse individual versions (can be comma-separated) - args.majorver_provides_versions = [v for vstring in args.majorver_provides_versions - for v in vstring.split(",")] + if args.majorver_provides_versions: + # Go through the arguments (can be specified multiple times), + # and parse individual versions (can be comma-separated) + args.majorver_provides_versions = [v for vstring in args.majorver_provides_versions + for v in vstring.split(",")] -# If normalized_names_require_pep503 is True we require the pep503 -# normalized name, if it is False we provide the legacy normalized name -normalized_names_require_pep503 = args.normalized_names_format == "pep503" + # If normalized_names_require_pep503 is True we require the pep503 + # normalized name, if it is False we provide the legacy normalized name + normalized_names_require_pep503 = args.normalized_names_format == "pep503" -# If normalized_names_provide_pep503/legacy is True we provide the -# pep503/legacy normalized name, if it is False we don't -normalized_names_provide_pep503 = \ - args.normalized_names_format == "pep503" or args.normalized_names_provide_both -normalized_names_provide_legacy = \ - args.normalized_names_format == "legacy-dots" or args.normalized_names_provide_both + # If normalized_names_provide_pep503/legacy is True we provide the + # pep503/legacy normalized name, if it is False we don't + normalized_names_provide_pep503 = \ + args.normalized_names_format == "pep503" or args.normalized_names_provide_both + normalized_names_provide_legacy = \ + args.normalized_names_format == "legacy-dots" or args.normalized_names_provide_both -# At least one type of normalization must be provided -assert normalized_names_provide_pep503 or normalized_names_provide_legacy + # At least one type of normalization must be provided + assert normalized_names_provide_pep503 or normalized_names_provide_legacy -for f in (args.files or stdin.readlines()): - f = f.strip() - lower = f.lower() - name = 'python(abi)' - # add dependency based on path, versioned if within versioned python directory - if py_abi and (lower.endswith('.py') or lower.endswith('.pyc') or lower.endswith('.pyo')): - if name not in py_deps: - py_deps[name] = [] - purelib = get_python_lib(standard_lib=0, plat_specific=0).split(version[:3])[0] - platlib = get_python_lib(standard_lib=0, plat_specific=1).split(version[:3])[0] - for lib in (purelib, platlib): - if lib in f: - spec = ('==', f.split(lib)[1].split(sep)[0]) - if spec not in py_deps[name]: - py_deps[name].append(spec) - - # XXX: hack to workaround RPM internal dependency generator not passing directories - lower_dir = dirname(lower) - if lower_dir.endswith('.egg') or \ - lower_dir.endswith('.egg-info') or \ - lower_dir.endswith('.dist-info'): - lower = lower_dir - f = dirname(f) - # Determine provide, requires, conflicts & recommends based on egg/dist metadata - if lower.endswith('.egg') or \ - lower.endswith('.egg-info') or \ - lower.endswith('.dist-info'): - # This import is very slow, so only do it if needed - # - Notes from an attempted rewrite from pkg_resources to - # importlib.metadata in 2020 can be found in the message of - # the commit that added this line. - from pkg_resources import Distribution, FileMetadata, PathMetadata, Requirement, parse_version - dist_name = basename(f) - if isdir(f): - path_item = dirname(f) - metadata = PathMetadata(path_item, f) - else: - path_item = f - metadata = FileMetadata(f) - dist = Distribution.from_location(path_item, dist_name, metadata) - # Check if py_version is defined in the metadata file/directory name - if not dist.py_version: - # Try to parse the Python version from the path the metadata - # resides at (e.g. /usr/lib/pythonX.Y/site-packages/...) - import re - res = re.search(r"/python(?P\d+\.\d+)/", path_item) - if res: - dist.py_version = res.group('pyver') - else: - warn("Version for {!r} has not been found".format(dist), RuntimeWarning) - continue - - # pkg_resources use platform.python_version to evaluate if a - # dependency is relevant based on environment markers [1], - # e.g. requirement `argparse;python_version<"2.7"` - # - # Since we're running this script on one Python version while - # possibly evaluating packages for different versions, we mock the - # platform.python_version function. Discussed upstream [2]. - # - # [1] https://www.python.org/dev/peps/pep-0508/#environment-markers - # [2] https://github.com/pypa/setuptools/pull/1275 - import platform - platform.python_version = lambda: dist.py_version - - # This is the PEP 503 normalized name. - # It does also convert dots to dashes, unlike dist.key. - # See https://bugzilla.redhat.com/show_bug.cgi?id=1791530 - normalized_name = normalize_name(dist.project_name) - - if args.majorver_provides or args.majorver_provides_versions or \ - args.majorver_only or args.legacy_provides or args.legacy: - # Get the Python major version - pyver_major = dist.py_version.split('.')[0] - if args.provides: - # If egg/dist metadata says package name is python, we provide python(abi) - if dist.key == 'python': - name = 'python(abi)' - if name not in py_deps: - py_deps[name] = [] - py_deps[name].append(('==', dist.py_version)) - if not args.legacy or not args.majorver_only: - if normalized_names_provide_legacy: - name = 'python{}dist({})'.format(dist.py_version, dist.key) - if name not in py_deps: - py_deps[name] = [] - if normalized_names_provide_pep503: - name_ = 'python{}dist({})'.format(dist.py_version, normalized_name) - if name_ not in py_deps: - py_deps[name_] = [] - if args.majorver_provides or args.majorver_only or \ - (args.majorver_provides_versions and dist.py_version in args.majorver_provides_versions): - if normalized_names_provide_legacy: - pymajor_name = 'python{}dist({})'.format(pyver_major, dist.key) - if pymajor_name not in py_deps: - py_deps[pymajor_name] = [] - if normalized_names_provide_pep503: - pymajor_name_ = 'python{}dist({})'.format(pyver_major, normalized_name) - if pymajor_name_ not in py_deps: - py_deps[pymajor_name_] = [] - if args.legacy or args.legacy_provides: - legacy_name = 'pythonegg({})({})'.format(pyver_major, dist.key) - if legacy_name not in py_deps: - py_deps[legacy_name] = [] - if dist.version: - version = dist.version - spec = ('==', version) - - if normalized_names_provide_legacy: + for f in (args.files or stdin.readlines()): + f = f.strip() + lower = f.lower() + name = 'python(abi)' + # add dependency based on path, versioned if within versioned python directory + if py_abi and (lower.endswith('.py') or lower.endswith('.pyc') or lower.endswith('.pyo')): + if name not in py_deps: + py_deps[name] = [] + purelib = get_python_lib(standard_lib=0, plat_specific=0).split(version[:3])[0] + platlib = get_python_lib(standard_lib=0, plat_specific=1).split(version[:3])[0] + for lib in (purelib, platlib): + if lib in f: + spec = ('==', f.split(lib)[1].split(sep)[0]) if spec not in py_deps[name]: py_deps[name].append(spec) - if args.majorver_provides or \ - (args.majorver_provides_versions and dist.py_version in args.majorver_provides_versions): - py_deps[pymajor_name].append(spec) - if normalized_names_provide_pep503: - if spec not in py_deps[name_]: - py_deps[name_].append(spec) - if args.majorver_provides or \ - (args.majorver_provides_versions and dist.py_version in args.majorver_provides_versions): - py_deps[pymajor_name_].append(spec) + + # XXX: hack to workaround RPM internal dependency generator not passing directories + lower_dir = dirname(lower) + if lower_dir.endswith('.egg') or \ + lower_dir.endswith('.egg-info') or \ + lower_dir.endswith('.dist-info'): + lower = lower_dir + f = dirname(f) + # Determine provide, requires, conflicts & recommends based on egg/dist metadata + if lower.endswith('.egg') or \ + lower.endswith('.egg-info') or \ + lower.endswith('.dist-info'): + # This import is very slow, so only do it if needed + # - Notes from an attempted rewrite from pkg_resources to + # importlib.metadata in 2020 can be found in the message of + # the commit that added this line. + from pkg_resources import Distribution, FileMetadata, PathMetadata, Requirement, parse_version + dist_name = basename(f) + if isdir(f): + path_item = dirname(f) + metadata = PathMetadata(path_item, f) + else: + path_item = f + metadata = FileMetadata(f) + dist = Distribution.from_location(path_item, dist_name, metadata) + # Check if py_version is defined in the metadata file/directory name + if not dist.py_version: + # Try to parse the Python version from the path the metadata + # resides at (e.g. /usr/lib/pythonX.Y/site-packages/...) + import re + res = re.search(r"/python(?P\d+\.\d+)/", path_item) + if res: + dist.py_version = res.group('pyver') + else: + warn("Version for {!r} has not been found".format(dist), RuntimeWarning) + continue + + # pkg_resources use platform.python_version to evaluate if a + # dependency is relevant based on environment markers [1], + # e.g. requirement `argparse;python_version<"2.7"` + # + # Since we're running this script on one Python version while + # possibly evaluating packages for different versions, we mock the + # platform.python_version function. Discussed upstream [2]. + # + # [1] https://www.python.org/dev/peps/pep-0508/#environment-markers + # [2] https://github.com/pypa/setuptools/pull/1275 + import platform + platform.python_version = lambda: dist.py_version + + # This is the PEP 503 normalized name. + # It does also convert dots to dashes, unlike dist.key. + # See https://bugzilla.redhat.com/show_bug.cgi?id=1791530 + normalized_name = normalize_name(dist.project_name) + + if args.majorver_provides or args.majorver_provides_versions or \ + args.majorver_only or args.legacy_provides or args.legacy: + # Get the Python major version + pyver_major = dist.py_version.split('.')[0] + if args.provides: + # If egg/dist metadata says package name is python, we provide python(abi) + if dist.key == 'python': + name = 'python(abi)' + if name not in py_deps: + py_deps[name] = [] + py_deps[name].append(('==', dist.py_version)) + if not args.legacy or not args.majorver_only: + if normalized_names_provide_legacy: + name = 'python{}dist({})'.format(dist.py_version, dist.key) + if name not in py_deps: + py_deps[name] = [] + if normalized_names_provide_pep503: + name_ = 'python{}dist({})'.format(dist.py_version, normalized_name) + if name_ not in py_deps: + py_deps[name_] = [] + if args.majorver_provides or args.majorver_only or \ + (args.majorver_provides_versions and dist.py_version in args.majorver_provides_versions): + if normalized_names_provide_legacy: + pymajor_name = 'python{}dist({})'.format(pyver_major, dist.key) + if pymajor_name not in py_deps: + py_deps[pymajor_name] = [] + if normalized_names_provide_pep503: + pymajor_name_ = 'python{}dist({})'.format(pyver_major, normalized_name) + if pymajor_name_ not in py_deps: + py_deps[pymajor_name_] = [] if args.legacy or args.legacy_provides: - if spec not in py_deps[legacy_name]: - py_deps[legacy_name].append(spec) - if args.requires or (args.recommends and dist.extras): - name = 'python(abi)' - # If egg/dist metadata says package name is python, we don't add dependency on python(abi) - if dist.key == 'python': - py_abi = False - if name in py_deps: - py_deps.pop(name) - elif py_abi and dist.py_version: - if name not in py_deps: - py_deps[name] = [] - spec = ('==', dist.py_version) - if spec not in py_deps[name]: - py_deps[name].append(spec) - deps = dist.requires() - if args.recommends: - depsextras = dist.requires(extras=dist.extras) - if not args.requires: + legacy_name = 'pythonegg({})({})'.format(pyver_major, dist.key) + if legacy_name not in py_deps: + py_deps[legacy_name] = [] + if dist.version: + version = dist.version + spec = ('==', version) + + if normalized_names_provide_legacy: + if spec not in py_deps[name]: + py_deps[name].append(spec) + if args.majorver_provides or \ + (args.majorver_provides_versions and dist.py_version in args.majorver_provides_versions): + py_deps[pymajor_name].append(spec) + if normalized_names_provide_pep503: + if spec not in py_deps[name_]: + py_deps[name_].append(spec) + if args.majorver_provides or \ + (args.majorver_provides_versions and dist.py_version in args.majorver_provides_versions): + py_deps[pymajor_name_].append(spec) + if args.legacy or args.legacy_provides: + if spec not in py_deps[legacy_name]: + py_deps[legacy_name].append(spec) + if args.requires or (args.recommends and dist.extras): + name = 'python(abi)' + # If egg/dist metadata says package name is python, we don't add dependency on python(abi) + if dist.key == 'python': + py_abi = False + if name in py_deps: + py_deps.pop(name) + elif py_abi and dist.py_version: + if name not in py_deps: + py_deps[name] = [] + spec = ('==', dist.py_version) + if spec not in py_deps[name]: + py_deps[name].append(spec) + deps = dist.requires() + if args.recommends: + depsextras = dist.requires(extras=dist.extras) + if not args.requires: + for dep in reversed(depsextras): + if dep in deps: + depsextras.remove(dep) + deps = depsextras + # console_scripts/gui_scripts entry points need pkg_resources from setuptools + if ((dist.get_entry_map('console_scripts') or + dist.get_entry_map('gui_scripts')) and + (lower.endswith('.egg') or + lower.endswith('.egg-info'))): + # stick them first so any more specific requirement overrides it + deps.insert(0, Requirement.parse('setuptools')) + # add requires/recommends based on egg/dist metadata + for dep in deps: + if normalized_names_require_pep503: + dep_normalized_name = normalize_name(dep.project_name) + else: + dep_normalized_name = dep.key + + if args.legacy: + name = 'pythonegg({})({})'.format(pyver_major, dep.key) + else: + if args.majorver_only: + name = 'python{}dist({})'.format(pyver_major, dep_normalized_name) + else: + name = 'python{}dist({})'.format(dist.py_version, dep_normalized_name) + for spec in dep.specs: + if name not in py_deps: + py_deps[name] = [] + if spec not in py_deps[name]: + py_deps[name].append(spec) + if not dep.specs: + py_deps[name] = [] + # Unused, for automatic sub-package generation based on 'extras' from egg/dist metadata + # TODO: implement in rpm later, or...? + if args.extras: + deps = dist.requires() + extras = dist.extras + print(extras) + for extra in extras: + print('%%package\textras-{}'.format(extra)) + print('Summary:\t{} extra for {} python package'.format(extra, dist.key)) + print('Group:\t\tDevelopment/Python') + depsextras = dist.requires(extras=[extra]) for dep in reversed(depsextras): if dep in deps: depsextras.remove(dep) - deps = depsextras - # console_scripts/gui_scripts entry points need pkg_resources from setuptools - if ((dist.get_entry_map('console_scripts') or - dist.get_entry_map('gui_scripts')) and - (lower.endswith('.egg') or - lower.endswith('.egg-info'))): - # stick them first so any more specific requirement overrides it - deps.insert(0, Requirement.parse('setuptools')) - # add requires/recommends based on egg/dist metadata - for dep in deps: - if normalized_names_require_pep503: - dep_normalized_name = normalize_name(dep.project_name) - else: - dep_normalized_name = dep.key - - if args.legacy: - name = 'pythonegg({})({})'.format(pyver_major, dep.key) - else: - if args.majorver_only: - name = 'python{}dist({})'.format(pyver_major, dep_normalized_name) - else: - name = 'python{}dist({})'.format(dist.py_version, dep_normalized_name) - for spec in dep.specs: - if name not in py_deps: - py_deps[name] = [] - if spec not in py_deps[name]: - py_deps[name].append(spec) - if not dep.specs: - py_deps[name] = [] - # Unused, for automatic sub-package generation based on 'extras' from egg/dist metadata - # TODO: implement in rpm later, or...? - if args.extras: - deps = dist.requires() - extras = dist.extras - print(extras) - for extra in extras: - print('%%package\textras-{}'.format(extra)) - print('Summary:\t{} extra for {} python package'.format(extra, dist.key)) - print('Group:\t\tDevelopment/Python') - depsextras = dist.requires(extras=[extra]) - for dep in reversed(depsextras): - if dep in deps: - depsextras.remove(dep) - deps = depsextras - for dep in deps: + deps = depsextras + for dep in deps: + for spec in dep.specs: + if spec[0] == '!=': + print('Conflicts:\t{} {} {}'.format(dep.key, '==', spec[1])) + else: + print('Requires:\t{} {} {}'.format(dep.key, spec[0], spec[1])) + print('%%description\t{}'.format(extra)) + print('{} extra for {} python package'.format(extra, dist.key)) + print('%%files\t\textras-{}\n'.format(extra)) + if args.conflicts: + # Should we really add conflicts for extras? + # Creating a meta package per extra with recommends on, which has + # the requires/conflicts in stead might be a better solution... + for dep in dist.requires(extras=dist.extras): + name = dep.key for spec in dep.specs: if spec[0] == '!=': - print('Conflicts:\t{} {} {}'.format(dep.key, '==', spec[1])) - else: - print('Requires:\t{} {} {}'.format(dep.key, spec[0], spec[1])) - print('%%description\t{}'.format(extra)) - print('{} extra for {} python package'.format(extra, dist.key)) - print('%%files\t\textras-{}\n'.format(extra)) - if args.conflicts: - # Should we really add conflicts for extras? - # Creating a meta package per extra with recommends on, which has - # the requires/conflicts in stead might be a better solution... - for dep in dist.requires(extras=dist.extras): - name = dep.key - for spec in dep.specs: - if spec[0] == '!=': - if name not in py_deps: - py_deps[name] = [] - spec = ('==', spec[1]) - if spec not in py_deps[name]: - py_deps[name].append(spec) + if name not in py_deps: + py_deps[name] = [] + spec = ('==', spec[1]) + if spec not in py_deps[name]: + py_deps[name].append(spec) -names = list(py_deps.keys()) -names.sort() -for name in names: - if py_deps[name]: - # Print out versioned provides, requires, recommends, conflicts - spec_list = [] - for spec in py_deps[name]: - spec_list.append(convert(name, spec[0], spec[1])) - if len(spec_list) == 1: - print(spec_list[0]) + names = list(py_deps.keys()) + names.sort() + for name in names: + if py_deps[name]: + # Print out versioned provides, requires, recommends, conflicts + spec_list = [] + for spec in py_deps[name]: + spec_list.append(convert(name, spec[0], spec[1])) + if len(spec_list) == 1: + print(spec_list[0]) + else: + # Sort spec_list so that the results can be tested easily + print('({})'.format(' with '.join(sorted(spec_list)))) else: - # Sort spec_list so that the results can be tested easily - print('({})'.format(' with '.join(sorted(spec_list)))) - else: - # Print out unversioned provides, requires, recommends, conflicts - print(name) + # Print out unversioned provides, requires, recommends, conflicts + print(name) From 972beac29ab676c8244ece680a7eba2ca8108a55 Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Mon, 20 Apr 2020 16:39:28 +0200 Subject: [PATCH 032/110] scripts/pythondistdeps: Version handling exception with better information --- pythondistdeps.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pythondistdeps.py b/pythondistdeps.py index 9787dc8..76ae93b 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -134,7 +134,11 @@ OPERATORS = {'~=': convert_compatible, def convert(name, operator, version_id): - return OPERATORS[operator](name, operator, version_id) + try: + return OPERATORS[operator](name, operator, version_id) + except Exception as exc: + raise RuntimeError("Cannot process Python package version `{}` for name `{}`". + format(version_id, name)) from exc def normalize_name(name): From 79790d12af902a39ab354c7ac806a91d598dbe38 Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Thu, 23 Apr 2020 20:41:13 +0200 Subject: [PATCH 033/110] scripts/pythondistdeps: Modify handling of dev versions --- pythondistdeps.py | 2 +- .../requires.txt | 7 +++++++ .../scripts_pythondistdeps/test-data.yaml | 19 +++++++++++++++++++ .../scripts_pythondistdeps/test-requires.yaml | 3 +++ 4 files changed, 30 insertions(+), 1 deletion(-) diff --git a/pythondistdeps.py b/pythondistdeps.py index 76ae93b..ee67e6f 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -55,7 +55,7 @@ class RpmVersion(): if self.pre: rpm_suffix = '~{}'.format(''.join(str(x) for x in self.pre)) elif self.dev: - rpm_suffix = '~{}'.format(''.join(str(x) for x in self.dev)) + rpm_suffix = '~~{}'.format(''.join(str(x) for x in self.dev)) elif self.post: rpm_suffix = '^post{}'.format(self.post[1]) else: diff --git a/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/requires.txt b/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/requires.txt index ec10bc6..09279fb 100644 --- a/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/requires.txt +++ b/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/requires.txt @@ -93,3 +93,10 @@ babel>=1.3,!=2.0 # Tests for breakages in Fedora fedora-python-nb2plots==0+unknown + +# Other tests +hugo1==1.0.0.dev7 +hugo2<=8a4 +hugo3!=11.1.1b14 +hugo4>11rc0 +hugo5===11.1.0.post3 diff --git a/tests/data/scripts_pythondistdeps/test-data.yaml b/tests/data/scripts_pythondistdeps/test-data.yaml index d396254..9722688 100644 --- a/tests/data/scripts_pythondistdeps/test-data.yaml +++ b/tests/data/scripts_pythondistdeps/test-data.yaml @@ -89,8 +89,19 @@ python3.9dist(foobar86) > 2.4.8^post1 python3.9dist(foobar87) > 2^post1 (python3.9dist(foobar9) >= 2.4.8^post1 with python3.9dist(foobar9) < 2.5) + python3.9dist(hugo1) = 1~~dev7 + python3.9dist(hugo2) <= 8~a4 + (python3.9dist(hugo3) < 11.1.1~b14 or python3.9dist(hugo3) > 11.1.1~b14) + python3.9dist(hugo4) > 11~rc0 + python3.9dist(hugo5) = 11.1^post3 python3.9dist(pyparsing0) ((python3.9dist(pyparsing1) < 2.0.4 or python3.9dist(pyparsing1) > 2.0.4) with (python3.9dist(pyparsing1) < 2.1.2 or python3.9dist(pyparsing1) > 2.1.2) with (python3.9dist(pyparsing1) < 2.1.6 or python3.9dist(pyparsing1) > 2.1.6) with python3.9dist(pyparsing1) >= 2.0.1) + usr/lib/python3.9/site-packages/taskotron_python_versions-0.1.dev6.dist-info: + provides: python3.9dist(taskotron-python-versions) = 0.1~~dev6 + requires: |- + python(abi) = 3.9 + python3.9dist(libarchive-c) + python3.9dist(python-bugzilla) --provides --majorver-provides: usr/lib/python2.7/site-packages/attrs-19.1.0-py2.7.egg-info: provides: |- @@ -331,6 +342,14 @@ python3.9dist(six) = 1.12 python3dist(six) = 1.12 requires: python(abi) = 3.9 + usr/lib/python3.9/site-packages/taskotron_python_versions-0.1.dev6.dist-info: + provides: |- + python3.9dist(taskotron-python-versions) = 0.1~~dev6 + python3dist(taskotron-python-versions) = 0.1~~dev6 + requires: |- + python(abi) = 3.9 + python3.9dist(libarchive-c) + python3.9dist(python-bugzilla) usr/lib/python3.9/site-packages/tox-3.14.0.dist-info: provides: |- python3.9dist(tox) = 3.14 diff --git a/tests/data/scripts_pythondistdeps/test-requires.yaml b/tests/data/scripts_pythondistdeps/test-requires.yaml index af79a28..c06d6c0 100644 --- a/tests/data/scripts_pythondistdeps/test-requires.yaml +++ b/tests/data/scripts_pythondistdeps/test-requires.yaml @@ -92,3 +92,6 @@ kubernetes: fsleyes: wheel: '0.32.3': ['3.9'] +taskotron-python-versions: + wheel: + '0.1.dev6': ['3.9'] From 54e4aa751b52216d70d60dca4964f93e866c3d0a Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Thu, 30 Apr 2020 16:24:11 +0200 Subject: [PATCH 034/110] Bump version, enable new features, add test suite to Fedora CI --- .gitignore | 2 ++ python-rpm-generators.spec | 11 +++++++++- pythondist.attr | 4 ++-- sources | 1 + .../update-test-sources.sh | 1 + tests/test_scripts_pythondistdeps.py | 2 +- tests/tests.yml | 21 +++++++++++++++++-- update-test-sources.sh | 19 +++++++++++++++++ 8 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 sources create mode 120000 tests/data/scripts_pythondistdeps/update-test-sources.sh create mode 100755 update-test-sources.sh diff --git a/.gitignore b/.gitignore index 999cc12..71b8b4c 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ +/test-sources-2020-04-29.tar.gz +/tests/__pycache__/ /tests/data/scripts_pythondistdeps/usr/ diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index e446519..6687b81 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 11 -Release: 4%{?dist} +Release: 5%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -45,6 +45,15 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} pythondistdeps.py %{_rpmconfigdir}/pythondistdeps.py %changelog +* Wed Apr 29 2020 Tomas Orsava - 11-5 +- Backporting proposed upstream changes + https://github.com/rpm-software-management/rpm/pull/1195 + - Only provide python3dist(..) for the main Python versions (BZ#1812083) + - Preparation for the proper handling of normalized names (BZ#1791530) + - Add a test suite (and enable it in Fedora CI) + - Better error messages for unsupported package versions + - Fix sorting of dev versions + * Tue Apr 28 2020 Miro Hrončok - 11-4 - Don't define global Lua variables from Python generator diff --git a/pythondist.attr b/pythondist.attr index 2bf737a..be23e16 100644 --- a/pythondist.attr +++ b/pythondist.attr @@ -1,3 +1,3 @@ -%__pythondist_provides %{_rpmconfigdir}/pythondistdeps.py --provides --majorver-provides -%__pythondist_requires %{_rpmconfigdir}/pythondistdeps.py --requires +%__pythondist_provides %{_rpmconfigdir}/pythondistdeps.py --provides --normalized-names-format legacy-dots --normalized-names-provide-both --majorver-provides-versions 2.7,%{__default_python3_version} +%__pythondist_requires %{_rpmconfigdir}/pythondistdeps.py --requires --normalized-names-format legacy-dots %__pythondist_path ^/usr/lib(64)?/python[[:digit:]]\\.[[:digit:]]+/site-packages/[^/]+\\.(dist-info|egg-info|egg-link)$ diff --git a/sources b/sources new file mode 100644 index 0000000..1d7f97a --- /dev/null +++ b/sources @@ -0,0 +1 @@ +SHA512 (test-sources-2020-04-29.tar.gz) = a5539fbe05a4f7128b4f82e960c3f1392a55ad53086dfd7fbc436d2743feaf64784e08667237baed3a32f149db25bc63e4ab3efc2b0270f969c59550b75102b1 diff --git a/tests/data/scripts_pythondistdeps/update-test-sources.sh b/tests/data/scripts_pythondistdeps/update-test-sources.sh new file mode 120000 index 0000000..7fc1a5a --- /dev/null +++ b/tests/data/scripts_pythondistdeps/update-test-sources.sh @@ -0,0 +1 @@ +../../../update-test-sources.sh \ No newline at end of file diff --git a/tests/test_scripts_pythondistdeps.py b/tests/test_scripts_pythondistdeps.py index 5bbf357..2dc9a30 100644 --- a/tests/test_scripts_pythondistdeps.py +++ b/tests/test_scripts_pythondistdeps.py @@ -37,7 +37,7 @@ import sys import tempfile import yaml -PYTHONDISTDEPS_PATH = Path(__file__).parent / '..' / 'scripts' / 'pythondistdeps.py' +PYTHONDISTDEPS_PATH = Path(__file__).parent / '..' / 'pythondistdeps.py' TEST_DATA_PATH = Path(__file__).parent / 'data' / 'scripts_pythondistdeps' diff --git a/tests/tests.yml b/tests/tests.yml index cceb9b4..676d22c 100644 --- a/tests/tests.yml +++ b/tests/tests.yml @@ -8,10 +8,15 @@ state: latest - hosts: localhost + tags: + - classic + pre_tasks: + - import_role: + name: standard-test-source + vars: + fetch_only: True roles: - role: standard-test-basic - tags: - - classic tests: - pythonabi: dir: . @@ -19,6 +24,18 @@ - pythonname: dir: . run: ./pythonname.sh + - prepare-test-data: + dir: . + run: tar -xvf test-sources-*.tar.gz -C ./tests/data/scripts_pythondistdeps/ + - pythondistdeps: + dir: ./tests + # Use update-test-sources.sh to update the test data + run: python3 -m pytest --capture=no -vvv required_packages: - rpm-build - python3-devel + - python3-pip + - python3-pytest + - python3-pyyaml + - python3-setuptools + - python3-wheel diff --git a/update-test-sources.sh b/update-test-sources.sh new file mode 100755 index 0000000..b7fa68b --- /dev/null +++ b/update-test-sources.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +# +# Requirements: +# - pip >= 20.0.1 +# + +# First prune old test data +rm -rf ./tests/data/scripts_pythondistdeps/usr + +# First run the test suite, it will download the test-data again +python3 -m pytest --capture=no -vvv + +# Archive the test data into a file with today's date +archive=test-sources-$(date +%Y-%m-%d).tar.gz +tar -zcvf ${archive} -C ./tests/data/scripts_pythondistdeps/ usr + +# Now manually run: +# $ fedpkg new-sources ${archive} From 6beec97e9ee93d2b32cc2aa7ebc469736fe09390 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Fri, 1 May 2020 10:10:46 +0200 Subject: [PATCH 035/110] Add integartion test for the dist generator --- tests/pythondist.sh | 35 +++++++++++++++++++++++++ tests/pythondist.spec | 59 +++++++++++++++++++++++++++++++++++++++++++ tests/tests.yml | 4 +++ 3 files changed, 98 insertions(+) create mode 100755 tests/pythondist.sh create mode 100644 tests/pythondist.spec diff --git a/tests/pythondist.sh b/tests/pythondist.sh new file mode 100755 index 0000000..a8ec77f --- /dev/null +++ b/tests/pythondist.sh @@ -0,0 +1,35 @@ +#!/usr/bin/bash -eux +X_Y=$(rpm --eval '%python3_version') +RPMDIR=$(rpm --eval '%_topdir')/RPMS/noarch + +mkdir -p $(rpm --eval '%_topdir')/SOURCES/ + +spectool -g -R pythondist.spec +rpmbuild -ba pythondist.spec + + +rpm -qp --provides ${RPMDIR}/python3-zope-component-4.3.0-0.noarch.rpm | grep '^python3dist(zope\.component)' +rpm -qp --provides ${RPMDIR}/python3-zope-component-4.3.0-0.noarch.rpm | grep '^python3dist(zope-component)' +rpm -qp --provides ${RPMDIR}/python3-zope-component-4.3.0-0.noarch.rpm | grep '^python'$X_Y'dist(zope\.component)' +rpm -qp --provides ${RPMDIR}/python3-zope-component-4.3.0-0.noarch.rpm | grep '^python'$X_Y'dist(zope-component)' + +rpm -qp --requires ${RPMDIR}/python3-zope-component-4.3.0-0.noarch.rpm | grep '^python'$X_Y'dist(zope\.event)' +rpm -qp --requires ${RPMDIR}/python3-zope-component-4.3.0-0.noarch.rpm | grep '^python'$X_Y'dist(zope\.interface)' + + +rpm -qp --provides ${RPMDIR}/python37-zope-component-4.3.0-0.noarch.rpm | grep '^python3dist(zope\.component)' && exit 1 || true +rpm -qp --provides ${RPMDIR}/python37-zope-component-4.3.0-0.noarch.rpm | grep '^python3dist(zope-component)' && exit 1 || true +rpm -qp --provides ${RPMDIR}/python37-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.7dist(zope\.component)' +rpm -qp --provides ${RPMDIR}/python37-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.7dist(zope-component)' + +rpm -qp --requires ${RPMDIR}/python37-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.7dist(zope\.event)' +rpm -qp --requires ${RPMDIR}/python37-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.7dist(zope\.interface)' + + +rpm -qp --provides ${RPMDIR}/python310-zope-component-4.3.0-0.noarch.rpm | grep '^python3dist(zope\.component)' && exit 1 || true +rpm -qp --provides ${RPMDIR}/python310-zope-component-4.3.0-0.noarch.rpm | grep '^python3dist(zope-component)' && exit 1 || true +rpm -qp --provides ${RPMDIR}/python310-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.10dist(zope\.component)' +rpm -qp --provides ${RPMDIR}/python310-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.10dist(zope-component)' + +rpm -qp --requires ${RPMDIR}/python310-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.10dist(zope\.event)' +rpm -qp --requires ${RPMDIR}/python310-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.10dist(zope\.interface)' diff --git a/tests/pythondist.spec b/tests/pythondist.spec new file mode 100644 index 0000000..5ce9075 --- /dev/null +++ b/tests/pythondist.spec @@ -0,0 +1,59 @@ +Name: pythondist +Version: 4.3.0 +Release: 0 +Summary: ... +License: ZPLv2.1 +Source0: %{pypi_source zope.component} +BuildArch: noarch +BuildRequires: python3-devel +BuildRequires: python3-setuptools + +# Turn off Python bytecode compilation because the build would fail without Python 3.7/3.10 +%define __brp_python_bytecompile %{nil} + +%description +... + +%package -n python3-zope-component +Summary: ... +%description -n python3-zope-component +... + +%package -n python37-zope-component +Summary: ... +%description -n python37-zope-component +... + +%package -n python310-zope-component +Summary: ... +%description -n python310-zope-component +... + +%prep +%autosetup -n zope.component-%{version} + +%build +%py3_build + +%install +%py3_install + +mkdir -p %{buildroot}/usr/lib/python3.7/site-packages +cp -a %{buildroot}%{python3_sitelib}/zope.component-%{version}-py%{python3_version}.egg-info \ + %{buildroot}/usr/lib/python3.7/site-packages/zope.component-%{version}-py3.7.egg-info + +mkdir -p %{buildroot}/usr/lib/python3.10/site-packages +cp -a %{buildroot}%{python3_sitelib}/zope.component-%{version}-py%{python3_version}.egg-info \ + %{buildroot}/usr/lib/python3.10/site-packages/zope.component-%{version}-py3.10.egg-info + +%files -n python3-zope-component +%license LICENSE.txt +%{python3_sitelib}/* + +%files -n python37-zope-component +%license LICENSE.txt +/usr/lib/python3.7/site-packages/zope.component-%{version}-py3.7.egg-info/ + +%files -n python310-zope-component +%license LICENSE.txt +/usr/lib/python3.10/site-packages/zope.component-%{version}-py3.10.egg-info/ diff --git a/tests/tests.yml b/tests/tests.yml index 676d22c..d07e24f 100644 --- a/tests/tests.yml +++ b/tests/tests.yml @@ -24,6 +24,9 @@ - pythonname: dir: . run: ./pythonname.sh + - pythondist: + dir: . + run: ./pythondist.sh - prepare-test-data: dir: . run: tar -xvf test-sources-*.tar.gz -C ./tests/data/scripts_pythondistdeps/ @@ -33,6 +36,7 @@ run: python3 -m pytest --capture=no -vvv required_packages: - rpm-build + - rpmdevtools - python3-devel - python3-pip - python3-pytest From c3f90ed2e86607bc3f4d50c6a5749bf80671fada Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Fri, 1 May 2020 10:13:08 +0200 Subject: [PATCH 036/110] Fix reversed grep exit codes in integration tests grep -v only fails if there are no unmatched lines, but that's not what we want to test. --- tests/pythonabi.sh | 10 +++++----- tests/pythonname.sh | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/pythonabi.sh b/tests/pythonabi.sh index 28eff53..36b6060 100755 --- a/tests/pythonabi.sh +++ b/tests/pythonabi.sh @@ -7,13 +7,13 @@ ARCH=$(rpm --eval '%_arch') ABI='^python(abi) = '${PYVER}'$' rpm -qp --provides ${RPMDIR}/${ARCH}/python-interpreter-0-0.${ARCH}.rpm | grep "${ABI}" -rpm -qp --requires ${RPMDIR}/${ARCH}/python-interpreter-0-0.${ARCH}.rpm | grep -v "${ABI}" +rpm -qp --requires ${RPMDIR}/${ARCH}/python-interpreter-0-0.${ARCH}.rpm | grep "${ABI}" && exit 1 || true rpm -qp --requires ${RPMDIR}/${ARCH}/python-arched-0-0.${ARCH}.rpm | grep "${ABI}" -rpm -qp --provides ${RPMDIR}/${ARCH}/python-arched-0-0.${ARCH}.rpm | grep -v "${ABI}" +rpm -qp --provides ${RPMDIR}/${ARCH}/python-arched-0-0.${ARCH}.rpm | grep "${ABI}" && exit 1 || true rpm -qp --requires ${RPMDIR}/noarch/python-noarch-0-0.noarch.rpm | grep "${ABI}" -rpm -qp --provides ${RPMDIR}/noarch/python-noarch-0-0.noarch.rpm | grep -v "${ABI}" +rpm -qp --provides ${RPMDIR}/noarch/python-noarch-0-0.noarch.rpm | grep "${ABI}" && exit 1 || true -rpm -qp --provides ${RPMDIR}/${ARCH}/python-misplaced-interpreter-0-0.${ARCH}.rpm | grep -v "${ABI}" -rpm -qp --requires ${RPMDIR}/noarch/python-misplaced-library-0-0.noarch.rpm | grep -v "${ABI}" +rpm -qp --provides ${RPMDIR}/${ARCH}/python-misplaced-interpreter-0-0.${ARCH}.rpm | grep "${ABI}" && exit 1 || true +rpm -qp --requires ${RPMDIR}/noarch/python-misplaced-library-0-0.noarch.rpm | grep "${ABI}" && exit 1 || true diff --git a/tests/pythonname.sh b/tests/pythonname.sh index 272016e..8bedc03 100755 --- a/tests/pythonname.sh +++ b/tests/pythonname.sh @@ -16,13 +16,13 @@ rpm -qp --provides ${RPMDIR}/python3-foo-0-0.noarch.rpm | grep -q '^python'$ echo "Provides for python2-foo" rpm -qp --provides ${RPMDIR}/python2-foo-0-0.noarch.rpm -rpm -qp --provides ${RPMDIR}/python2-foo-0-0.noarch.rpm | grep -vq '^python-foo = 0-0$' +rpm -qp --provides ${RPMDIR}/python2-foo-0-0.noarch.rpm | grep -q '^python-foo = 0-0$' && exit 1 || true echo "Provides for python-foo" rpm -qp --provides ${RPMDIR}/python-foo-0-0.noarch.rpm -rpm -qp --provides ${RPMDIR}/python-foo-0-0.noarch.rpm | grep -vq '^python2-foo = 0-0$' +rpm -qp --provides ${RPMDIR}/python-foo-0-0.noarch.rpm | grep -q '^python2-foo = 0-0$' && exit 1 || true echo "Provides for python35-foo" rpm -qp --provides ${RPMDIR}/python35-foo-0-0.noarch.rpm -rpm -qp --provides ${RPMDIR}/python35-foo-0-0.noarch.rpm | grep -vq '^python-foo = 0-0$' -rpm -qp --provides ${RPMDIR}/python35-foo-0-0.noarch.rpm | grep -vq '^python3-foo = 0-0$' +rpm -qp --provides ${RPMDIR}/python35-foo-0-0.noarch.rpm | grep -q '^python-foo = 0-0$' && exit 1 || true +rpm -qp --provides ${RPMDIR}/python35-foo-0-0.noarch.rpm | grep -q '^python3-foo = 0-0$' && exit 1 || true From 33358b9a65b84d73a64fe7b5f00ff2a7fe83f72c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Tue, 5 May 2020 13:26:30 +0200 Subject: [PATCH 037/110] Deduplicate automatically provided names trough Python RPM Lua macros --- python-rpm-generators.spec | 9 ++++++--- pythonname.attr | 19 +++++++++---------- tests/pythonname.sh | 8 ++++++++ tests/pythonname.spec | 20 ++++++++++++++++++++ 4 files changed, 43 insertions(+), 13 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 6687b81..5c61cd9 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 11 -Release: 5%{?dist} +Release: 6%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -23,8 +23,8 @@ Summary: %{summary} Requires: python3-setuptools # We have parametric macro generators, we need RPM 4.16 (4.15.90+ is 4.16 alpha) Requires: rpm > 4.15.90-0 -# We use %%python_provide -Requires: python-rpm-macros +# This contains the Lua functions we use: +Requires: python-srpm-macros >= 3.8-5 %description -n python3-rpm-generators %{summary}. @@ -45,6 +45,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} pythondistdeps.py %{_rpmconfigdir}/pythondistdeps.py %changelog +* Tue May 05 2020 Miro Hrončok - 11-6 +- Deduplicate automatically provided names trough Python RPM Lua macros + * Wed Apr 29 2020 Tomas Orsava - 11-5 - Backporting proposed upstream changes https://github.com/rpm-software-management/rpm/pull/1195 diff --git a/pythonname.attr b/pythonname.attr index b086549..85969d7 100644 --- a/pythonname.attr +++ b/pythonname.attr @@ -1,19 +1,18 @@ %__pythonname_provides() %{lua: + local python = require 'fedora.srpm.python' -- this macro is called for each file in a package, the path being in %1 -- but we don't need to know the path, so we would get for each file: Macro %1 defined but not used within scope -- in here, we expand %name conditionally on %1 to suppress the warning local name = rpm.expand('%{?1:%{name}}') - -- a structure that knows what names were already processed, so we can end early - if __pythonname_beenthere == nil then - __pythonname_beenthere = {} - end - -- we save ourselves a trip to %python_provide if we have already been there - if __pythonname_beenthere[name] == nil then - local python_provide = rpm.expand('%{?python_provide:%python_provide %{name}}') - for provides in python_provide:gmatch('Provides:[ \\t]+([^\\n]+)') do - print(provides .. " ") + local evr = rpm.expand('%{?epoch:%{epoch}:}%{version}-%{release}') + local provides = python.python_altprovides_once(name, evr) + -- provides is either an array/table or nil + -- nil means the function was already called with the same arguments: + -- either with another file in %1 or manually via %py_provide + if provides then + for i, provide in ipairs(provides) do + print(provide .. ' ') end - __pythonname_beenthere[name] = true end } diff --git a/tests/pythonname.sh b/tests/pythonname.sh index 8bedc03..d5c8f3c 100755 --- a/tests/pythonname.sh +++ b/tests/pythonname.sh @@ -26,3 +26,11 @@ echo "Provides for python35-foo" rpm -qp --provides ${RPMDIR}/python35-foo-0-0.noarch.rpm rpm -qp --provides ${RPMDIR}/python35-foo-0-0.noarch.rpm | grep -q '^python-foo = 0-0$' && exit 1 || true rpm -qp --provides ${RPMDIR}/python35-foo-0-0.noarch.rpm | grep -q '^python3-foo = 0-0$' && exit 1 || true + +echo "Provides for python3-python_provide" +rpm -qp --provides ${RPMDIR}/python3-python_provide-0-0.noarch.rpm +test $(rpm -qp --provides ${RPMDIR}/python3-python_provide-0-0.noarch.rpm | grep python-python_provide | wc -l) -eq 1 + +echo "Provides for python3-py_provides" +rpm -qp --provides ${RPMDIR}/python3-py_provides-0-0.noarch.rpm +test $(rpm -qp --provides ${RPMDIR}/python3-py_provides-0-0.noarch.rpm | grep python-py_provides | wc -l) -eq 1 diff --git a/tests/pythonname.spec b/tests/pythonname.spec index b4a3f6d..01222ef 100644 --- a/tests/pythonname.spec +++ b/tests/pythonname.spec @@ -60,3 +60,23 @@ Summary: ... ... %files -n ruby-foo /* + + +%package -n python3-python_provide +Summary: ... +%{?python_provide:%python_provide python3-python_provide} + +%description -n python3-python_provide +... +%files -n python3-python_provide +/* + + +%package -n python3-py_provides +Summary: ... +%py_provides python3-py_provides + +%description -n python3-py_provides +... +%files -n python3-py_provides +/* From 39315a6aa41524fcb6e56a0174c5609d22f0cdfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Thu, 7 May 2020 17:37:30 +0200 Subject: [PATCH 038/110] Adapt tests for the pythonXY -> pythonX.Y renaming See https://lists.fedoraproject.org/archives/list/python-devel@lists.fedoraproject.org/message/VIUS7WMQMDX6H2WEIH7TVTMBB6SUHY7E/ --- tests/pythondist.sh | 24 ++++++++++++------------ tests/pythondist.spec | 12 ++++++------ tests/pythonname.sh | 20 ++++++++++---------- tests/pythonname.spec | 12 ++++++------ 4 files changed, 34 insertions(+), 34 deletions(-) diff --git a/tests/pythondist.sh b/tests/pythondist.sh index a8ec77f..c34c599 100755 --- a/tests/pythondist.sh +++ b/tests/pythondist.sh @@ -17,19 +17,19 @@ rpm -qp --requires ${RPMDIR}/python3-zope-component-4.3.0-0.noarch.rpm | grep '^ rpm -qp --requires ${RPMDIR}/python3-zope-component-4.3.0-0.noarch.rpm | grep '^python'$X_Y'dist(zope\.interface)' -rpm -qp --provides ${RPMDIR}/python37-zope-component-4.3.0-0.noarch.rpm | grep '^python3dist(zope\.component)' && exit 1 || true -rpm -qp --provides ${RPMDIR}/python37-zope-component-4.3.0-0.noarch.rpm | grep '^python3dist(zope-component)' && exit 1 || true -rpm -qp --provides ${RPMDIR}/python37-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.7dist(zope\.component)' -rpm -qp --provides ${RPMDIR}/python37-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.7dist(zope-component)' +rpm -qp --provides ${RPMDIR}/python3.7-zope-component-4.3.0-0.noarch.rpm | grep '^python3dist(zope\.component)' && exit 1 || true +rpm -qp --provides ${RPMDIR}/python3.7-zope-component-4.3.0-0.noarch.rpm | grep '^python3dist(zope-component)' && exit 1 || true +rpm -qp --provides ${RPMDIR}/python3.7-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.7dist(zope\.component)' +rpm -qp --provides ${RPMDIR}/python3.7-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.7dist(zope-component)' -rpm -qp --requires ${RPMDIR}/python37-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.7dist(zope\.event)' -rpm -qp --requires ${RPMDIR}/python37-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.7dist(zope\.interface)' +rpm -qp --requires ${RPMDIR}/python3.7-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.7dist(zope\.event)' +rpm -qp --requires ${RPMDIR}/python3.7-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.7dist(zope\.interface)' -rpm -qp --provides ${RPMDIR}/python310-zope-component-4.3.0-0.noarch.rpm | grep '^python3dist(zope\.component)' && exit 1 || true -rpm -qp --provides ${RPMDIR}/python310-zope-component-4.3.0-0.noarch.rpm | grep '^python3dist(zope-component)' && exit 1 || true -rpm -qp --provides ${RPMDIR}/python310-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.10dist(zope\.component)' -rpm -qp --provides ${RPMDIR}/python310-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.10dist(zope-component)' +rpm -qp --provides ${RPMDIR}/python3.10-zope-component-4.3.0-0.noarch.rpm | grep '^python3dist(zope\.component)' && exit 1 || true +rpm -qp --provides ${RPMDIR}/python3.10-zope-component-4.3.0-0.noarch.rpm | grep '^python3dist(zope-component)' && exit 1 || true +rpm -qp --provides ${RPMDIR}/python3.10-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.10dist(zope\.component)' +rpm -qp --provides ${RPMDIR}/python3.10-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.10dist(zope-component)' -rpm -qp --requires ${RPMDIR}/python310-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.10dist(zope\.event)' -rpm -qp --requires ${RPMDIR}/python310-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.10dist(zope\.interface)' +rpm -qp --requires ${RPMDIR}/python3.10-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.10dist(zope\.event)' +rpm -qp --requires ${RPMDIR}/python3.10-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.10dist(zope\.interface)' diff --git a/tests/pythondist.spec b/tests/pythondist.spec index 5ce9075..672e04a 100644 --- a/tests/pythondist.spec +++ b/tests/pythondist.spec @@ -19,14 +19,14 @@ Summary: ... %description -n python3-zope-component ... -%package -n python37-zope-component +%package -n python3.7-zope-component Summary: ... -%description -n python37-zope-component +%description -n python3.7-zope-component ... -%package -n python310-zope-component +%package -n python3.10-zope-component Summary: ... -%description -n python310-zope-component +%description -n python3.10-zope-component ... %prep @@ -50,10 +50,10 @@ cp -a %{buildroot}%{python3_sitelib}/zope.component-%{version}-py%{python3_versi %license LICENSE.txt %{python3_sitelib}/* -%files -n python37-zope-component +%files -n python3.7-zope-component %license LICENSE.txt /usr/lib/python3.7/site-packages/zope.component-%{version}-py3.7.egg-info/ -%files -n python310-zope-component +%files -n python3.10-zope-component %license LICENSE.txt /usr/lib/python3.10/site-packages/zope.component-%{version}-py3.10.egg-info/ diff --git a/tests/pythonname.sh b/tests/pythonname.sh index d5c8f3c..ab2024a 100755 --- a/tests/pythonname.sh +++ b/tests/pythonname.sh @@ -1,18 +1,18 @@ #!/usr/bin/bash -eux rpmbuild -ba pythonname.spec -XY=$(rpm --eval '%python3_version_nodots') +X_Y=$(rpm --eval '%python3_version') RPMDIR=$(rpm --eval '%_topdir')/RPMS/noarch -echo "Provides for python${XY}-foo" -rpm -qp --provides ${RPMDIR}/python${XY}-foo-0-0.noarch.rpm -rpm -qp --provides ${RPMDIR}/python${XY}-foo-0-0.noarch.rpm | grep -q '^python-foo = 0-0$' -rpm -qp --provides ${RPMDIR}/python${XY}-foo-0-0.noarch.rpm | grep -q '^python3-foo = 0-0$' +echo "Provides for python${X_Y}-foo" +rpm -qp --provides ${RPMDIR}/python${X_Y}-foo-0-0.noarch.rpm +rpm -qp --provides ${RPMDIR}/python${X_Y}-foo-0-0.noarch.rpm | grep -q '^python-foo = 0-0$' +rpm -qp --provides ${RPMDIR}/python${X_Y}-foo-0-0.noarch.rpm | grep -q '^python3-foo = 0-0$' echo "Provides for python3-foo" rpm -qp --provides ${RPMDIR}/python3-foo-0-0.noarch.rpm rpm -qp --provides ${RPMDIR}/python3-foo-0-0.noarch.rpm | grep -q '^python-foo = 0-0$' -rpm -qp --provides ${RPMDIR}/python3-foo-0-0.noarch.rpm | grep -q '^python'${XY}'-foo = 0-0$' +rpm -qp --provides ${RPMDIR}/python3-foo-0-0.noarch.rpm | grep -q '^python'${X_Y}'-foo = 0-0$' echo "Provides for python2-foo" rpm -qp --provides ${RPMDIR}/python2-foo-0-0.noarch.rpm @@ -22,10 +22,10 @@ echo "Provides for python-foo" rpm -qp --provides ${RPMDIR}/python-foo-0-0.noarch.rpm rpm -qp --provides ${RPMDIR}/python-foo-0-0.noarch.rpm | grep -q '^python2-foo = 0-0$' && exit 1 || true -echo "Provides for python35-foo" -rpm -qp --provides ${RPMDIR}/python35-foo-0-0.noarch.rpm -rpm -qp --provides ${RPMDIR}/python35-foo-0-0.noarch.rpm | grep -q '^python-foo = 0-0$' && exit 1 || true -rpm -qp --provides ${RPMDIR}/python35-foo-0-0.noarch.rpm | grep -q '^python3-foo = 0-0$' && exit 1 || true +echo "Provides for python3.5-foo" +rpm -qp --provides ${RPMDIR}/python3.5-foo-0-0.noarch.rpm +rpm -qp --provides ${RPMDIR}/python3.5-foo-0-0.noarch.rpm | grep -q '^python-foo = 0-0$' && exit 1 || true +rpm -qp --provides ${RPMDIR}/python3.5-foo-0-0.noarch.rpm | grep -q '^python3-foo = 0-0$' && exit 1 || true echo "Provides for python3-python_provide" rpm -qp --provides ${RPMDIR}/python3-python_provide-0-0.noarch.rpm diff --git a/tests/pythonname.spec b/tests/pythonname.spec index 01222ef..8755dc6 100644 --- a/tests/pythonname.spec +++ b/tests/pythonname.spec @@ -38,19 +38,19 @@ Summary: ... /* -%package -n python%{python3_version_nodots}-foo +%package -n python%{python3_version}-foo Summary: ... -%description -n python%{python3_version_nodots}-foo +%description -n python%{python3_version}-foo ... -%files -n python%{python3_version_nodots}-foo +%files -n python%{python3_version}-foo /* -%package -n python35-foo +%package -n python3.5-foo Summary: ... -%description -n python35-foo +%description -n python3.5-foo ... -%files -n python35-foo +%files -n python3.5-foo /* From 3a396fbf9638e2658790badb8b2c2f33c944f21d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Thu, 21 May 2020 17:43:19 +0200 Subject: [PATCH 039/110] Use PEP 503 names for requires --- python-rpm-generators.spec | 5 ++++- pythondist.attr | 4 ++-- tests/pythondist.sh | 12 ++++++------ 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 5c61cd9..6ea0960 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 11 -Release: 6%{?dist} +Release: 7%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -45,6 +45,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} pythondistdeps.py %{_rpmconfigdir}/pythondistdeps.py %changelog +* Thu May 21 2020 Miro Hrončok - 11-7 +- Use PEP 503 names for requires + * Tue May 05 2020 Miro Hrončok - 11-6 - Deduplicate automatically provided names trough Python RPM Lua macros diff --git a/pythondist.attr b/pythondist.attr index be23e16..7aefb3c 100644 --- a/pythondist.attr +++ b/pythondist.attr @@ -1,3 +1,3 @@ -%__pythondist_provides %{_rpmconfigdir}/pythondistdeps.py --provides --normalized-names-format legacy-dots --normalized-names-provide-both --majorver-provides-versions 2.7,%{__default_python3_version} -%__pythondist_requires %{_rpmconfigdir}/pythondistdeps.py --requires --normalized-names-format legacy-dots +%__pythondist_provides %{_rpmconfigdir}/pythondistdeps.py --provides --normalized-names-format pep503 --normalized-names-provide-both --majorver-provides-versions 2.7,%{__default_python3_version} +%__pythondist_requires %{_rpmconfigdir}/pythondistdeps.py --requires --normalized-names-format pep503 %__pythondist_path ^/usr/lib(64)?/python[[:digit:]]\\.[[:digit:]]+/site-packages/[^/]+\\.(dist-info|egg-info|egg-link)$ diff --git a/tests/pythondist.sh b/tests/pythondist.sh index c34c599..556f5e8 100755 --- a/tests/pythondist.sh +++ b/tests/pythondist.sh @@ -13,8 +13,8 @@ rpm -qp --provides ${RPMDIR}/python3-zope-component-4.3.0-0.noarch.rpm | grep '^ rpm -qp --provides ${RPMDIR}/python3-zope-component-4.3.0-0.noarch.rpm | grep '^python'$X_Y'dist(zope\.component)' rpm -qp --provides ${RPMDIR}/python3-zope-component-4.3.0-0.noarch.rpm | grep '^python'$X_Y'dist(zope-component)' -rpm -qp --requires ${RPMDIR}/python3-zope-component-4.3.0-0.noarch.rpm | grep '^python'$X_Y'dist(zope\.event)' -rpm -qp --requires ${RPMDIR}/python3-zope-component-4.3.0-0.noarch.rpm | grep '^python'$X_Y'dist(zope\.interface)' +rpm -qp --requires ${RPMDIR}/python3-zope-component-4.3.0-0.noarch.rpm | grep '^python'$X_Y'dist(zope-event)' +rpm -qp --requires ${RPMDIR}/python3-zope-component-4.3.0-0.noarch.rpm | grep '^python'$X_Y'dist(zope-interface)' rpm -qp --provides ${RPMDIR}/python3.7-zope-component-4.3.0-0.noarch.rpm | grep '^python3dist(zope\.component)' && exit 1 || true @@ -22,8 +22,8 @@ rpm -qp --provides ${RPMDIR}/python3.7-zope-component-4.3.0-0.noarch.rpm | grep rpm -qp --provides ${RPMDIR}/python3.7-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.7dist(zope\.component)' rpm -qp --provides ${RPMDIR}/python3.7-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.7dist(zope-component)' -rpm -qp --requires ${RPMDIR}/python3.7-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.7dist(zope\.event)' -rpm -qp --requires ${RPMDIR}/python3.7-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.7dist(zope\.interface)' +rpm -qp --requires ${RPMDIR}/python3.7-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.7dist(zope-event)' +rpm -qp --requires ${RPMDIR}/python3.7-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.7dist(zope-interface)' rpm -qp --provides ${RPMDIR}/python3.10-zope-component-4.3.0-0.noarch.rpm | grep '^python3dist(zope\.component)' && exit 1 || true @@ -31,5 +31,5 @@ rpm -qp --provides ${RPMDIR}/python3.10-zope-component-4.3.0-0.noarch.rpm | grep rpm -qp --provides ${RPMDIR}/python3.10-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.10dist(zope\.component)' rpm -qp --provides ${RPMDIR}/python3.10-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.10dist(zope-component)' -rpm -qp --requires ${RPMDIR}/python3.10-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.10dist(zope\.event)' -rpm -qp --requires ${RPMDIR}/python3.10-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.10dist(zope\.interface)' +rpm -qp --requires ${RPMDIR}/python3.10-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.10dist(zope-event)' +rpm -qp --requires ${RPMDIR}/python3.10-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.10dist(zope-interface)' From e78c420523fb1199361b3fe690b7dedc23fec65c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Wed, 17 Jun 2020 15:55:57 +0200 Subject: [PATCH 040/110] Fix python(abi) requires generator, it picked files from almost good directories The %__python_magic filter suddenly got actually working with file 5.39: Before: file.cpython-38.opt-1.pyc: data After: file.cpython-38.opt-1.pyc: python 3.8 byte-compiled Hence, the filter started to pick all Python files regardless of their location. Later, in the actual generator, paths like this were considered: /opt/usr/lib/python3.X/... And generated requirements on python(abi). We don't actually need to filter the files by file magic, so we drop it to get the previously accidentally working behavior. We could choose if the path and magic filters are applied as OR or AND. However, we don't want either. We actually want to mach any files in Python directories regardless of their magic. We *could* filter by file type (and executable bit) for provides, but that would require us to split the attr files into two. --- python-rpm-generators.spec | 5 ++++- python.attr | 1 - 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 6ea0960..5e371ae 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 11 -Release: 7%{?dist} +Release: 8%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -45,6 +45,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} pythondistdeps.py %{_rpmconfigdir}/pythondistdeps.py %changelog +* Wed Jun 17 2020 Miro Hrončok - 11-8 +- Fix python(abi) requires generator, it picked files from almost good directories + * Thu May 21 2020 Miro Hrončok - 11-7 - Use PEP 503 names for requires diff --git a/python.attr b/python.attr index 4000019..1793d3c 100644 --- a/python.attr +++ b/python.attr @@ -25,4 +25,3 @@ } %__python_path ^((%{_prefix}/lib(64)?/python[[:digit:]]+\\.[[:digit:]]+/.*\\.(py[oc]?|so))|(%{_bindir}/python[[:digit:]]+\\.[[:digit:]]+))$ -%__python_magic [Pp]ython.*(executable|byte-compiled) From 48c0de39d9adfd239da80164da62bbdc995e41b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Fri, 26 Jun 2020 12:57:41 +0200 Subject: [PATCH 041/110] Add a script to generate Python bundled provides See https://src.fedoraproject.org/rpms/python-setuptools/pull-request/40 Strictly speaking, this is not an RPM generator, but: - it generates provides - it is tighly coupled with pythondistdeps.py Usage: 1. Run `$ /usr/lib/rpm/pythonbundles.py .../vendored.txt` 2. Copy the output into the spec as a macro definition: %global bundled %{expand: Provides: bundled(python3dist(appdirs)) = 1.4.3 Provides: bundled(python3dist(packaging)) = 16.8 Provides: bundled(python3dist(pyparsing)) = 2.2.1 Provides: bundled(python3dist(six)) = 1.15 } 3. Use the macro to expand the provides 4. Verify the macro contents in %check: %check ... %{_rpmconfigdir}/pythonbundles.py src/_vendor/vendored.txt --compare-with '%{bundled}' --- python-rpm-generators.spec | 7 +- pythonbundles.py | 90 +++++++++++++++++ tests/data/scripts_pythonbundles/pip.in | 24 +++++ tests/data/scripts_pythonbundles/pip.out | 24 +++++ tests/data/scripts_pythonbundles/pipenv.in | 59 +++++++++++ tests/data/scripts_pythonbundles/pipenv.out | 58 +++++++++++ .../scripts_pythonbundles/pkg_resources.in | 4 + .../scripts_pythonbundles/pkg_resources.out | 4 + tests/test_scripts_pythonbundles.py | 99 +++++++++++++++++++ tests/tests.yml | 2 +- 10 files changed, 368 insertions(+), 3 deletions(-) create mode 100644 pythonbundles.py create mode 100644 tests/data/scripts_pythonbundles/pip.in create mode 100644 tests/data/scripts_pythonbundles/pip.out create mode 100644 tests/data/scripts_pythonbundles/pipenv.in create mode 100644 tests/data/scripts_pythonbundles/pipenv.out create mode 100644 tests/data/scripts_pythonbundles/pkg_resources.in create mode 100644 tests/data/scripts_pythonbundles/pkg_resources.out create mode 100644 tests/test_scripts_pythonbundles.py diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 5e371ae..500aa80 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -12,6 +12,7 @@ Source1: python.attr Source2: pythondist.attr Source3: pythonname.attr Source4: pythondistdeps.py +Source5: pythonbundles.py BuildArch: noarch @@ -35,7 +36,7 @@ cp -a %{sources} . %install install -Dpm0644 -t %{buildroot}%{_fileattrsdir} *.attr -install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} pythondistdeps.py +install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %files -n python3-rpm-generators %license COPYING @@ -43,10 +44,12 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} pythondistdeps.py %{_fileattrsdir}/pythondist.attr %{_fileattrsdir}/pythonname.attr %{_rpmconfigdir}/pythondistdeps.py +%{_rpmconfigdir}/pythonbundles.py %changelog -* Wed Jun 17 2020 Miro Hrončok - 11-8 +* Fri Jun 26 2020 Miro Hrončok - 11-8 - Fix python(abi) requires generator, it picked files from almost good directories +- Add a script to generate Python bundled provides * Thu May 21 2020 Miro Hrončok - 11-7 - Use PEP 503 names for requires diff --git a/pythonbundles.py b/pythonbundles.py new file mode 100644 index 0000000..5093dff --- /dev/null +++ b/pythonbundles.py @@ -0,0 +1,90 @@ +#!/usr/bin/python3 -B +# (imports pythondistdeps from /usr/lib/rpm, hence -B) +# +# This program is free software. +# +# It is placed in the public domain or under the CC0-1.0-Universal license, +# whichever is more permissive. +# +# Alternatively, it may be redistributed and/or modified under the terms of +# the LGPL version 2.1 (or later) or GPL version 2 (or later). +# +# Use this script to generate bundled provides, e.g.: +# ./pythonbundles.py setuptools-47.1.1/pkg_resources/_vendor/vendored.txt + +import pathlib +import sys + +# inject parse_version import to pythondistdeps +# not the nicest API, but :/ +from pkg_resources import parse_version +import pythondistdeps +pythondistdeps.parse_version = parse_version + + +def generate_bundled_provides(path, namespace): + provides = set() + + for line in path.read_text().splitlines(): + line, _, comment = line.partition('#') + if comment.startswith('egg='): + # not a real comment + # e.g. git+https://github.com/monty/spam.git@master#egg=spam&... + egg, *_ = comment.strip().partition(' ') + egg, *_ = egg.strip().partition('&') + name = pythondistdeps.normalize_name(egg[4:]) + provides.add(f'Provides: bundled({namespace}({name}))') + continue + line = line.strip() + if line: + name, _, version = line.partition('==') + name = pythondistdeps.normalize_name(name) + bundled_name = f"bundled({namespace}({name}))" + python_provide = pythondistdeps.convert(bundled_name, '==', version) + provides.add(f'Provides: {python_provide}') + + return provides + + +def compare(expected, given): + stripped = (l.strip() for l in given) + no_comments = set(l for l in stripped if not l.startswith('#')) + no_comments.discard('') + if expected == no_comments: + return True + extra_expected = expected - no_comments + extra_given = no_comments - expected + if extra_expected: + print('Missing expected provides:', file=sys.stderr) + for provide in sorted(extra_expected): + print(f' - {provide}', file=sys.stderr) + if extra_given: + print('Redundant unexpected provides:', file=sys.stderr) + for provide in sorted(extra_given): + print(f' + {provide}', file=sys.stderr) + return False + + +if __name__ == '__main__': + import argparse + + parser = argparse.ArgumentParser(prog=sys.argv[0], + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser.add_argument('vendored', metavar='VENDORED.TXT', + help='Upstream information about vendored libraries') + parser.add_argument('-c', '--compare-with', action='store', + help='A string value to compare with and verify') + parser.add_argument('-n', '--namespace', action='store', + help='What namespace of provides will used', default='python3dist') + args = parser.parse_args() + + provides = generate_bundled_provides(pathlib.Path(args.vendored), args.namespace) + + if args.compare_with: + given = args.compare_with.splitlines() + same = compare(provides, given) + if not same: + sys.exit(1) + else: + for provide in sorted(provides): + print(provide) diff --git a/tests/data/scripts_pythonbundles/pip.in b/tests/data/scripts_pythonbundles/pip.in new file mode 100644 index 0000000..74ecca4 --- /dev/null +++ b/tests/data/scripts_pythonbundles/pip.in @@ -0,0 +1,24 @@ +appdirs==1.4.3 +CacheControl==0.12.6 +colorama==0.4.3 +contextlib2==0.6.0.post1 +distlib==0.3.0 +distro==1.5.0 +html5lib==1.0.1 +ipaddress==1.0.23 # Only needed on 2.6 and 2.7 +msgpack==1.0.0 +packaging==20.3 +pep517==0.8.2 +progress==1.5 +pyparsing==2.4.7 +requests==2.23.0 + certifi==2020.04.05.1 + chardet==3.0.4 + idna==2.9 + urllib3==1.25.8 +resolvelib==0.3.0 +retrying==1.3.3 +setuptools==44.0.0 +six==1.14.0 +toml==0.10.0 +webencodings==0.5.1 diff --git a/tests/data/scripts_pythonbundles/pip.out b/tests/data/scripts_pythonbundles/pip.out new file mode 100644 index 0000000..0be59de --- /dev/null +++ b/tests/data/scripts_pythonbundles/pip.out @@ -0,0 +1,24 @@ +Provides: bundled(python3dist(appdirs)) = 1.4.3 +Provides: bundled(python3dist(cachecontrol)) = 0.12.6 +Provides: bundled(python3dist(certifi)) = 2020.4.5.1 +Provides: bundled(python3dist(chardet)) = 3.0.4 +Provides: bundled(python3dist(colorama)) = 0.4.3 +Provides: bundled(python3dist(contextlib2)) = 0.6^post1 +Provides: bundled(python3dist(distlib)) = 0.3 +Provides: bundled(python3dist(distro)) = 1.5 +Provides: bundled(python3dist(html5lib)) = 1.0.1 +Provides: bundled(python3dist(idna)) = 2.9 +Provides: bundled(python3dist(ipaddress)) = 1.0.23 +Provides: bundled(python3dist(msgpack)) = 1 +Provides: bundled(python3dist(packaging)) = 20.3 +Provides: bundled(python3dist(pep517)) = 0.8.2 +Provides: bundled(python3dist(progress)) = 1.5 +Provides: bundled(python3dist(pyparsing)) = 2.4.7 +Provides: bundled(python3dist(requests)) = 2.23 +Provides: bundled(python3dist(resolvelib)) = 0.3 +Provides: bundled(python3dist(retrying)) = 1.3.3 +Provides: bundled(python3dist(setuptools)) = 44 +Provides: bundled(python3dist(six)) = 1.14 +Provides: bundled(python3dist(toml)) = 0.10 +Provides: bundled(python3dist(urllib3)) = 1.25.8 +Provides: bundled(python3dist(webencodings)) = 0.5.1 diff --git a/tests/data/scripts_pythonbundles/pipenv.in b/tests/data/scripts_pythonbundles/pipenv.in new file mode 100644 index 0000000..de5797a --- /dev/null +++ b/tests/data/scripts_pythonbundles/pipenv.in @@ -0,0 +1,59 @@ +appdirs==1.4.4 +backports.shutil_get_terminal_size==1.0.0 +backports.weakref==1.0.post1 +click==7.1.2 +click-completion==0.5.2 +click-didyoumean==0.0.3 +colorama==0.4.3 +delegator.py==0.1.1 + pexpect==4.8.0 + ptyprocess==0.6.0 +python-dotenv==0.10.3 +first==2.0.1 +iso8601==0.1.12 +jinja2==2.11.2 +markupsafe==1.1.1 +parse==1.15.0 +pathlib2==2.3.5 + scandir==1.10 +pipdeptree==0.13.2 +pipreqs==0.4.10 + docopt==0.6.2 + yarg==0.1.9 +pythonfinder==1.2.4 +requests==2.23.0 + chardet==3.0.4 + idna==2.9 + urllib3==1.25.9 + certifi==2020.4.5.1 +requirementslib==1.5.11 + attrs==19.3.0 + distlib==0.3.0 + packaging==20.3 + pyparsing==2.4.7 + plette==0.2.3 + tomlkit==0.5.11 +shellingham==1.3.2 +six==1.14.0 +semver==2.9.0 +toml==0.10.1 +cached-property==1.5.1 +vistir==0.5.2 +pip-shims==0.5.2 + contextlib2==0.6.0.post1 + funcsigs==1.0.2 +enum34==1.1.10 +# yaspin==0.15.0 +yaspin==0.14.3 +cerberus==1.3.2 +resolvelib==0.3.0 +backports.functools_lru_cache==1.6.1 +pep517==0.8.2 + zipp==0.6.0 + importlib_metadata==1.6.0 + importlib-resources==1.5.0 + more-itertools==5.0.0 +git+https://github.com/sarugaku/passa.git@master#egg=passa +orderedmultidict==1.0.1 +dparse==0.5.0 +python-dateutil==2.8.1 diff --git a/tests/data/scripts_pythonbundles/pipenv.out b/tests/data/scripts_pythonbundles/pipenv.out new file mode 100644 index 0000000..524ef72 --- /dev/null +++ b/tests/data/scripts_pythonbundles/pipenv.out @@ -0,0 +1,58 @@ +Provides: bundled(python3dist(appdirs)) = 1.4.4 +Provides: bundled(python3dist(attrs)) = 19.3 +Provides: bundled(python3dist(backports-functools-lru-cache)) = 1.6.1 +Provides: bundled(python3dist(backports-shutil-get-terminal-size)) = 1 +Provides: bundled(python3dist(backports-weakref)) = 1^post1 +Provides: bundled(python3dist(cached-property)) = 1.5.1 +Provides: bundled(python3dist(cerberus)) = 1.3.2 +Provides: bundled(python3dist(certifi)) = 2020.4.5.1 +Provides: bundled(python3dist(chardet)) = 3.0.4 +Provides: bundled(python3dist(click)) = 7.1.2 +Provides: bundled(python3dist(click-completion)) = 0.5.2 +Provides: bundled(python3dist(click-didyoumean)) = 0.0.3 +Provides: bundled(python3dist(colorama)) = 0.4.3 +Provides: bundled(python3dist(contextlib2)) = 0.6^post1 +Provides: bundled(python3dist(delegator-py)) = 0.1.1 +Provides: bundled(python3dist(distlib)) = 0.3 +Provides: bundled(python3dist(docopt)) = 0.6.2 +Provides: bundled(python3dist(dparse)) = 0.5 +Provides: bundled(python3dist(enum34)) = 1.1.10 +Provides: bundled(python3dist(first)) = 2.0.1 +Provides: bundled(python3dist(funcsigs)) = 1.0.2 +Provides: bundled(python3dist(idna)) = 2.9 +Provides: bundled(python3dist(importlib-metadata)) = 1.6 +Provides: bundled(python3dist(importlib-resources)) = 1.5 +Provides: bundled(python3dist(iso8601)) = 0.1.12 +Provides: bundled(python3dist(jinja2)) = 2.11.2 +Provides: bundled(python3dist(markupsafe)) = 1.1.1 +Provides: bundled(python3dist(more-itertools)) = 5 +Provides: bundled(python3dist(orderedmultidict)) = 1.0.1 +Provides: bundled(python3dist(packaging)) = 20.3 +Provides: bundled(python3dist(parse)) = 1.15 +Provides: bundled(python3dist(passa)) +Provides: bundled(python3dist(pathlib2)) = 2.3.5 +Provides: bundled(python3dist(pep517)) = 0.8.2 +Provides: bundled(python3dist(pexpect)) = 4.8 +Provides: bundled(python3dist(pip-shims)) = 0.5.2 +Provides: bundled(python3dist(pipdeptree)) = 0.13.2 +Provides: bundled(python3dist(pipreqs)) = 0.4.10 +Provides: bundled(python3dist(plette)) = 0.2.3 +Provides: bundled(python3dist(ptyprocess)) = 0.6 +Provides: bundled(python3dist(pyparsing)) = 2.4.7 +Provides: bundled(python3dist(python-dateutil)) = 2.8.1 +Provides: bundled(python3dist(python-dotenv)) = 0.10.3 +Provides: bundled(python3dist(pythonfinder)) = 1.2.4 +Provides: bundled(python3dist(requests)) = 2.23 +Provides: bundled(python3dist(requirementslib)) = 1.5.11 +Provides: bundled(python3dist(resolvelib)) = 0.3 +Provides: bundled(python3dist(scandir)) = 1.10 +Provides: bundled(python3dist(semver)) = 2.9 +Provides: bundled(python3dist(shellingham)) = 1.3.2 +Provides: bundled(python3dist(six)) = 1.14 +Provides: bundled(python3dist(toml)) = 0.10.1 +Provides: bundled(python3dist(tomlkit)) = 0.5.11 +Provides: bundled(python3dist(urllib3)) = 1.25.9 +Provides: bundled(python3dist(vistir)) = 0.5.2 +Provides: bundled(python3dist(yarg)) = 0.1.9 +Provides: bundled(python3dist(yaspin)) = 0.14.3 +Provides: bundled(python3dist(zipp)) = 0.6 diff --git a/tests/data/scripts_pythonbundles/pkg_resources.in b/tests/data/scripts_pythonbundles/pkg_resources.in new file mode 100644 index 0000000..7f4f408 --- /dev/null +++ b/tests/data/scripts_pythonbundles/pkg_resources.in @@ -0,0 +1,4 @@ +packaging==16.8 +pyparsing==2.2.1 +six==1.10.0 +appdirs==1.4.3 diff --git a/tests/data/scripts_pythonbundles/pkg_resources.out b/tests/data/scripts_pythonbundles/pkg_resources.out new file mode 100644 index 0000000..294ad86 --- /dev/null +++ b/tests/data/scripts_pythonbundles/pkg_resources.out @@ -0,0 +1,4 @@ +Provides: bundled(python3dist(appdirs)) = 1.4.3 +Provides: bundled(python3dist(packaging)) = 16.8 +Provides: bundled(python3dist(pyparsing)) = 2.2.1 +Provides: bundled(python3dist(six)) = 1.10 diff --git a/tests/test_scripts_pythonbundles.py b/tests/test_scripts_pythonbundles.py new file mode 100644 index 0000000..c04230e --- /dev/null +++ b/tests/test_scripts_pythonbundles.py @@ -0,0 +1,99 @@ +# Run tests using pytest, e.g. from the root directory +# $ python3 -m pytest --ignore tests/testing/ -vvv +# +# Requirements for this script: +# - Python >= 3.6 +# - pytest +import pathlib +import pytest +import random +import sys +import subprocess + +PYTHONBUNDLES = pathlib.Path(__file__).parent / '..' / 'pythonbundles.py' +TEST_DATA = pathlib.Path(__file__).parent / 'data' / 'scripts_pythonbundles' + + +def run_pythonbundles(*args, success=True): + """ + Runs pythonbundles.py with given command line arguments + + Arguments: + *args: Shell arguments passed to the script + success: + - true-ish: assert return code is 0 (default) + - false-ish (excluding None): assert return code is not 0 + - None: don't assert return code value + """ + cp = subprocess.run((sys.executable, PYTHONBUNDLES, *args), encoding='utf-8', + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + if success: + assert cp.returncode == 0, cp.stderr + elif success is not None: + assert cp.returncode != 0, cp.stdout + return cp + + +projects = pytest.mark.parametrize('project', ('pkg_resources', 'pip', 'pipenv')) + + +@projects +def test_output_consistency(project): + cp = run_pythonbundles(TEST_DATA / f'{project}.in') + expected = (TEST_DATA / f'{project}.out').read_text() + assert cp.stdout == expected, cp.stdout + assert cp.stderr == '', cp.stderr + + +@pytest.mark.parametrize('namespace', ('python2dist', 'python3.11dist', 'pypy2.7dist')) +@projects +def test_namespace(project, namespace): + cp = run_pythonbundles(TEST_DATA / f'{project}.in', f'--namespace={namespace}') + expected = (TEST_DATA / f'{project}.out').read_text().replace('python3dist', namespace) + assert cp.stdout == expected, cp.stdout + assert cp.stderr == '', cp.stderr + + +@projects +def test_compare_with_identical(project): + expected = (TEST_DATA / f'{project}.out').read_text() + cp = run_pythonbundles(TEST_DATA / f'{project}.in', '--compare-with', expected) + assert cp.stdout == '', cp.stdout + assert cp.stderr == '', cp.stderr + + +@projects +def test_compare_with_shuffled(project): + expected = (TEST_DATA / f'{project}.out').read_text() + lines = expected.splitlines() + # some extra whitespace and comments + lines[0] = f' {lines[0]} ' + lines.extend([''] * 3) + lines.append('# this is a comment on a single line') + random.shuffle(lines) + shuffled = '\n'.join(lines) + cp = run_pythonbundles(TEST_DATA / f'{project}.in', '--compare-with', shuffled) + assert cp.stdout == '', cp.stdout + assert cp.stderr == '', cp.stderr + + +@projects +def test_compare_with_missing(project): + expected = (TEST_DATA / f'{project}.out').read_text() + lines = expected.splitlines() + missing = lines[0] + del lines[0] + shorter = '\n'.join(lines) + cp = run_pythonbundles(TEST_DATA / f'{project}.in', '--compare-with', shorter, success=False) + assert cp.stdout == '', cp.stdout + assert cp.stderr == f'Missing expected provides:\n - {missing}\n', cp.stderr + + +@projects +def test_compare_with_unexpected(project): + expected = (TEST_DATA / f'{project}.out').read_text() + unexpected = 'Provides: bundled(python3dist(brainfuck)) = 6.6.6' + longer = f'{expected}{unexpected}\n' + cp = run_pythonbundles(TEST_DATA / f'{project}.in', '--compare-with', longer, success=False) + assert cp.stdout == '', cp.stdout + assert cp.stderr == f'Redundant unexpected provides:\n + {unexpected}\n', cp.stderr diff --git a/tests/tests.yml b/tests/tests.yml index d07e24f..a79a5f1 100644 --- a/tests/tests.yml +++ b/tests/tests.yml @@ -30,7 +30,7 @@ - prepare-test-data: dir: . run: tar -xvf test-sources-*.tar.gz -C ./tests/data/scripts_pythondistdeps/ - - pythondistdeps: + - pytest: dir: ./tests # Use update-test-sources.sh to update the test data run: python3 -m pytest --capture=no -vvv From 3b1100ba1f5cbf1b1ebde65adec82d13d6cc62a6 Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Wed, 22 Apr 2020 14:22:16 +0200 Subject: [PATCH 042/110] scripts/pythondistdeps: Add parameter --package-name --- pythondistdeps.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pythondistdeps.py b/pythondistdeps.py index ee67e6f..93a9fd3 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -171,7 +171,8 @@ if __name__ == "__main__": help='Provide both `pep503` and `legacy-dots` format of normalized names (useful for a transition period)') parser.add_argument('-L', '--legacy-provides', action='store_true', help='Print extra legacy pythonegg Provides') parser.add_argument('-l', '--legacy', action='store_true', help='Print legacy pythonegg Provides/Requires instead') - parser.add_argument('files', nargs=argparse.REMAINDER) + parser.add_argument('--package-name', action='store', help="Name of the RPM package that's being inspected") + parser.add_argument('files', nargs=argparse.REMAINDER, help="Files from the RPM package that are to be inspected, can also be supplied on stdin") args = parser.parse_args() py_abi = args.requires From 0c9665427c3dd51ee94a5757f1a49db77a8e53b5 Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Tue, 2 Jun 2020 21:12:11 +0200 Subject: [PATCH 043/110] scripts/pythondistdeps: Implement provides/requires for extras packages --- pythondist.attr | 4 +-- pythondistdeps.py | 73 ++++++++++++++++++++++++++++++++--------------- 2 files changed, 52 insertions(+), 25 deletions(-) diff --git a/pythondist.attr b/pythondist.attr index 7aefb3c..a94ab70 100644 --- a/pythondist.attr +++ b/pythondist.attr @@ -1,3 +1,3 @@ -%__pythondist_provides %{_rpmconfigdir}/pythondistdeps.py --provides --normalized-names-format pep503 --normalized-names-provide-both --majorver-provides-versions 2.7,%{__default_python3_version} -%__pythondist_requires %{_rpmconfigdir}/pythondistdeps.py --requires --normalized-names-format pep503 +%__pythondist_provides %{_rpmconfigdir}/pythondistdeps.py --provides --normalized-names-format pep503 --package-name %{name} --normalized-names-provide-both --majorver-provides-versions 2.7,%{__default_python3_version} +%__pythondist_requires %{_rpmconfigdir}/pythondistdeps.py --requires --normalized-names-format pep503 --package-name %{name} %__pythondist_path ^/usr/lib(64)?/python[[:digit:]]\\.[[:digit:]]+/site-packages/[^/]+\\.(dist-info|egg-info|egg-link)$ diff --git a/pythondistdeps.py b/pythondistdeps.py index 93a9fd3..e9fe7da 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -157,7 +157,7 @@ if __name__ == "__main__": group.add_argument('-R', '--requires', action='store_true', help='Print Requires') group.add_argument('-r', '--recommends', action='store_true', help='Print Recommends') group.add_argument('-C', '--conflicts', action='store_true', help='Print Conflicts') - group.add_argument('-E', '--extras', action='store_true', help='Print Extras') + group.add_argument('-E', '--extras', action='store_true', help='[Unused] Generate spec file snippets for extras subpackages') group_majorver = parser.add_mutually_exclusive_group() group_majorver.add_argument('-M', '--majorver-provides', action='store_true', help='Print extra Provides with Python major version only') group_majorver.add_argument('--majorver-provides-versions', action='append', @@ -171,7 +171,9 @@ if __name__ == "__main__": help='Provide both `pep503` and `legacy-dots` format of normalized names (useful for a transition period)') parser.add_argument('-L', '--legacy-provides', action='store_true', help='Print extra legacy pythonegg Provides') parser.add_argument('-l', '--legacy', action='store_true', help='Print legacy pythonegg Provides/Requires instead') - parser.add_argument('--package-name', action='store', help="Name of the RPM package that's being inspected") + parser.add_argument('--require-extras-subpackages', action='store_true', + help="If there is a dependency on a package with extras functionality, require the extras subpackage") + parser.add_argument('--package-name', action='store', help="Name of the RPM package that's being inspected. Required for extras requires/provides to work.") parser.add_argument('files', nargs=argparse.REMAINDER, help="Files from the RPM package that are to be inspected, can also be supplied on stdin") args = parser.parse_args() @@ -198,6 +200,12 @@ if __name__ == "__main__": # At least one type of normalization must be provided assert normalized_names_provide_pep503 or normalized_names_provide_legacy + # Is this script being run for an extras subpackage? + extras_subpackage = None + if args.package_name: + package_name_parts = args.package_name.partition('+') + extras_subpackage = package_name_parts[2] or None + for f in (args.files or stdin.readlines()): f = f.strip() lower = f.lower() @@ -268,11 +276,18 @@ if __name__ == "__main__": # See https://bugzilla.redhat.com/show_bug.cgi?id=1791530 normalized_name = normalize_name(dist.project_name) + # If we're processing an extras subpackage, check that the extras exists + if extras_subpackage and extras_subpackage not in dist.extras: + print(f"\nError: The package name contains an extras name `{extras_subpackage}` that was not found in the metadata.\n" + "Check if the extras were removed from the project. If so, consider removing the subpackage and obsoleting it from another.") + exit(65) # os.EX_DATAERR + if args.majorver_provides or args.majorver_provides_versions or \ args.majorver_only or args.legacy_provides or args.legacy: # Get the Python major version pyver_major = dist.py_version.split('.')[0] if args.provides: + extras_suffix = f"[{extras_subpackage}]" if extras_subpackage else "" # If egg/dist metadata says package name is python, we provide python(abi) if dist.key == 'python': name = 'python(abi)' @@ -281,21 +296,21 @@ if __name__ == "__main__": py_deps[name].append(('==', dist.py_version)) if not args.legacy or not args.majorver_only: if normalized_names_provide_legacy: - name = 'python{}dist({})'.format(dist.py_version, dist.key) + name = 'python{}dist({}{})'.format(dist.py_version, dist.key, extras_suffix) if name not in py_deps: py_deps[name] = [] if normalized_names_provide_pep503: - name_ = 'python{}dist({})'.format(dist.py_version, normalized_name) + name_ = 'python{}dist({}{})'.format(dist.py_version, normalized_name, extras_suffix) if name_ not in py_deps: py_deps[name_] = [] if args.majorver_provides or args.majorver_only or \ (args.majorver_provides_versions and dist.py_version in args.majorver_provides_versions): if normalized_names_provide_legacy: - pymajor_name = 'python{}dist({})'.format(pyver_major, dist.key) + pymajor_name = 'python{}dist({}{})'.format(pyver_major, dist.key, extras_suffix) if pymajor_name not in py_deps: py_deps[pymajor_name] = [] if normalized_names_provide_pep503: - pymajor_name_ = 'python{}dist({})'.format(pyver_major, normalized_name) + pymajor_name_ = 'python{}dist({}{})'.format(pyver_major, normalized_name, extras_suffix) if pymajor_name_ not in py_deps: py_deps[pymajor_name_] = [] if args.legacy or args.legacy_provides: @@ -342,6 +357,9 @@ if __name__ == "__main__": if dep in deps: depsextras.remove(dep) deps = depsextras + elif extras_subpackage: + # Extras requires also contain the base requires included + deps = [d for d in dist.requires(extras=[extras_subpackage]) if d not in dist.requires()] # console_scripts/gui_scripts entry points need pkg_resources from setuptools if ((dist.get_entry_map('console_scripts') or dist.get_entry_map('gui_scripts')) and @@ -351,25 +369,34 @@ if __name__ == "__main__": deps.insert(0, Requirement.parse('setuptools')) # add requires/recommends based on egg/dist metadata for dep in deps: - if normalized_names_require_pep503: - dep_normalized_name = normalize_name(dep.project_name) - else: - dep_normalized_name = dep.key - - if args.legacy: - name = 'pythonegg({})({})'.format(pyver_major, dep.key) - else: - if args.majorver_only: - name = 'python{}dist({})'.format(pyver_major, dep_normalized_name) + # Even if we're requiring `foo[bar]`, also require `foo` + # to be safe, and to make it discoverable through + # `repoquery --whatrequires` + extras_suffixes = [""] + if args.require_extras_subpackages and dep.extras: + # A dependency can have more than one extras, + # i.e. foo[bar,baz], so let's go through all of them + extras_suffixes += [f"[{e}]" for e in dep.extras] + for extras_suffix in extras_suffixes: + if normalized_names_require_pep503: + dep_normalized_name = normalize_name(dep.project_name) else: - name = 'python{}dist({})'.format(dist.py_version, dep_normalized_name) - for spec in dep.specs: - if name not in py_deps: + dep_normalized_name = dep.key + + if args.legacy: + name = 'pythonegg({})({})'.format(pyver_major, dep.key) + else: + if args.majorver_only: + name = 'python{}dist({}{})'.format(pyver_major, dep_normalized_name, extras_suffix) + else: + name = 'python{}dist({}{})'.format(dist.py_version, dep_normalized_name, extras_suffix) + for spec in dep.specs: + if name not in py_deps: + py_deps[name] = [] + if spec not in py_deps[name]: + py_deps[name].append(spec) + if not dep.specs: py_deps[name] = [] - if spec not in py_deps[name]: - py_deps[name].append(spec) - if not dep.specs: - py_deps[name] = [] # Unused, for automatic sub-package generation based on 'extras' from egg/dist metadata # TODO: implement in rpm later, or...? if args.extras: From 9df3e5bcb513bbd305e58b8aeeb03e094db41aeb Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Tue, 2 Jun 2020 21:13:10 +0200 Subject: [PATCH 044/110] scripts/pythondistdeps: Add tests for: Implement provides/requires for extras packages --- .../scripts_pythondistdeps/test-data.yaml | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/tests/data/scripts_pythondistdeps/test-data.yaml b/tests/data/scripts_pythondistdeps/test-data.yaml index 9722688..3287eb5 100644 --- a/tests/data/scripts_pythondistdeps/test-data.yaml +++ b/tests/data/scripts_pythondistdeps/test-data.yaml @@ -1215,3 +1215,52 @@ python3dist(backports-range) = 3.7.2 python3dist(backports.range) = 3.7.2 requires: python(abi) = 3.7 +--requires --normalized-names-format pep503 --package-name python3-zope-component+testing: + --provides --majorver-provides --normalized-names-format pep503 --package-name python3-zope-component+testing: + usr/lib/python3.9/site-packages/zope.component-4.3.0-py3.9.egg-info: + provides: |- + python3.9dist(zope-component[testing]) = 4.3 + python3dist(zope-component[testing]) = 4.3 + requires: |- + python(abi) = 3.9 + python3.9dist(coverage) + python3.9dist(nose) + python3.9dist(zope-component) + python3.9dist(zope-testing) +--requires --normalized-names-format pep503 --package-name python3-zope-schema+docs: + --provides --majorver-provides --normalized-names-format pep503 --package-name python3-zope-schema+docs: + usr/lib/python3.9/site-packages/zope.schema-4.4.2-py3.9.egg-info: + provides: |- + python3.9dist(zope-schema[docs]) = 4.4.2 + python3dist(zope-schema[docs]) = 4.4.2 + requires: |- + python(abi) = 3.9 + python3.9dist(sphinx) +--requires --normalized-names-format pep503 --package-name python3-zope-schema+testing: + --provides --majorver-provides --normalized-names-format pep503 --package-name python3-zope-schema+testing: + usr/lib/python3.9/site-packages/zope.schema-4.4.2-py3.9.egg-info: + provides: |- + python3.9dist(zope-schema[testing]) = 4.4.2 + python3dist(zope-schema[testing]) = 4.4.2 + requires: |- + python(abi) = 3.9 + python3.9dist(coverage) + python3.9dist(nose) + python3.9dist(zope-testing) +--requires --normalized-names-format pep503 --require-extras-subpackages --package-name python3-zope-component+testing: + --provides --majorver-provides --normalized-names-format pep503 --package-name python3-zope-component+testing: + usr/lib/python3.9/site-packages/zope.component-4.3.0-py3.9.egg-info: + provides: |- + python3.9dist(zope-component[testing]) = 4.3 + python3dist(zope-component[testing]) = 4.3 + requires: |- + python(abi) = 3.9 + python3.9dist(coverage) + python3.9dist(nose) + python3.9dist(zope-component) + python3.9dist(zope-component[hook]) + python3.9dist(zope-component[persistentregistry]) + python3.9dist(zope-component[security]) + python3.9dist(zope-component[zcml]) + python3.9dist(zope-testing) + From b6e0638f7c9cf84f8beb30f7bb03c4eccfcd5cce Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Wed, 17 Jun 2020 14:36:33 +0200 Subject: [PATCH 045/110] Enable --require-extras-subpackages and bump release --- python-rpm-generators.spec | 6 +++++- pythondist.attr | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 500aa80..695f3b8 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 11 -Release: 8%{?dist} +Release: 9%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -47,6 +47,10 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Wed Jun 17 2020 Tomas Orsava - 11-9 +- pythondistdeps: Implement provides/requires for extras packages +- Enable --require-extras-subpackages + * Fri Jun 26 2020 Miro Hrončok - 11-8 - Fix python(abi) requires generator, it picked files from almost good directories - Add a script to generate Python bundled provides diff --git a/pythondist.attr b/pythondist.attr index a94ab70..b0d4fc5 100644 --- a/pythondist.attr +++ b/pythondist.attr @@ -1,3 +1,3 @@ %__pythondist_provides %{_rpmconfigdir}/pythondistdeps.py --provides --normalized-names-format pep503 --package-name %{name} --normalized-names-provide-both --majorver-provides-versions 2.7,%{__default_python3_version} -%__pythondist_requires %{_rpmconfigdir}/pythondistdeps.py --requires --normalized-names-format pep503 --package-name %{name} +%__pythondist_requires %{_rpmconfigdir}/pythondistdeps.py --requires --normalized-names-format pep503 --package-name %{name} %{?!_python_no_extras_requires:--require-extras-subpackages} %__pythondist_path ^/usr/lib(64)?/python[[:digit:]]\\.[[:digit:]]+/site-packages/[^/]+\\.(dist-info|egg-info|egg-link)$ From 098c48d46d7f9eceb4b41eddd0b20b31611c8e41 Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Fri, 10 Jul 2020 13:08:20 +0200 Subject: [PATCH 046/110] scripts/pythondistdeps: Rework error messages --- python-rpm-generators.spec | 2 +- pythondistdeps.py | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 695f3b8..c7d8c46 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -47,7 +47,7 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog -* Wed Jun 17 2020 Tomas Orsava - 11-9 +* Fri Jul 10 2020 Tomas Orsava - 11-9 - pythondistdeps: Implement provides/requires for extras packages - Enable --require-extras-subpackages diff --git a/pythondistdeps.py b/pythondistdeps.py index e9fe7da..5563769 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -18,7 +18,7 @@ from __future__ import print_function import argparse from os.path import basename, dirname, isdir, sep -from sys import argv, stdin, version +from sys import argv, stdin, stderr, version from distutils.sysconfig import get_python_lib from warnings import warn @@ -65,11 +65,13 @@ class RpmVersion(): def convert_compatible(name, operator, version_id): if version_id.endswith('.*'): - print('Invalid requirement: {} {} {}'.format(name, operator, version_id)) + print("*** INVALID_REQUIREMENT_ERROR___SEE_STDERR ***") + print('Invalid requirement: {} {} {}'.format(name, operator, version_id), file=stderr) exit(65) # os.EX_DATAERR version = RpmVersion(version_id) if len(version.version) == 1: - print('Invalid requirement: {} {} {}'.format(name, operator, version_id)) + print("*** INVALID_REQUIREMENT_ERROR___SEE_STDERR ***") + print('Invalid requirement: {} {} {}'.format(name, operator, version_id), file=stderr) exit(65) # os.EX_DATAERR upper_version = RpmVersion(version_id) upper_version.version.pop() @@ -88,7 +90,8 @@ def convert_equal(name, operator, version_id): def convert_arbitrary_equal(name, operator, version_id): if version_id.endswith('.*'): - print('Invalid requirement: {} {} {}'.format(name, operator, version_id)) + print("*** INVALID_REQUIREMENT_ERROR___SEE_STDERR ***") + print('Invalid requirement: {} {} {}'.format(name, operator, version_id), file=stderr) exit(65) # os.EX_DATAERR version = RpmVersion(version_id) return '{} = {}'.format(name, version) @@ -278,8 +281,9 @@ if __name__ == "__main__": # If we're processing an extras subpackage, check that the extras exists if extras_subpackage and extras_subpackage not in dist.extras: + print("*** PYTHON_EXTRAS_NOT_FOUND_ERROR___SEE_STDERR ***") print(f"\nError: The package name contains an extras name `{extras_subpackage}` that was not found in the metadata.\n" - "Check if the extras were removed from the project. If so, consider removing the subpackage and obsoleting it from another.") + "Check if the extras were removed from the project. If so, consider removing the subpackage and obsoleting it from another.\n", file=stderr) exit(65) # os.EX_DATAERR if args.majorver_provides or args.majorver_provides_versions or \ From c2e0f3356546e447dc970866bfa6bc37095acdbc Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Fri, 10 Jul 2020 14:09:25 +0200 Subject: [PATCH 047/110] scripts/pythondistdeps: Add tests for: Rework error messages --- .../scripts_pythondistdeps/test-data.yaml | 13 ++++++++ tests/test_scripts_pythondistdeps.py | 31 ++++++++++++++----- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/tests/data/scripts_pythondistdeps/test-data.yaml b/tests/data/scripts_pythondistdeps/test-data.yaml index 3287eb5..a1fd05d 100644 --- a/tests/data/scripts_pythondistdeps/test-data.yaml +++ b/tests/data/scripts_pythondistdeps/test-data.yaml @@ -1247,6 +1247,19 @@ python3.9dist(coverage) python3.9dist(nose) python3.9dist(zope-testing) +--requires --normalized-names-format pep503 --require-extras-subpackages --package-name python3-zope-component+missing: + --provides --majorver-provides --normalized-names-format pep503 --package-name python3-zope-component+missing: + usr/lib/python3.9/site-packages/zope.component-4.3.0-py3.9.egg-info: + stderr: + provides: |- + Error: The package name contains an extras name `missing` that was not found in the metadata. + Check if the extras were removed from the project. If so, consider removing the subpackage and obsoleting it from another. + requires: |- + Error: The package name contains an extras name `missing` that was not found in the metadata. + Check if the extras were removed from the project. If so, consider removing the subpackage and obsoleting it from another. + stdout: + provides: '*** PYTHON_EXTRAS_NOT_FOUND_ERROR___SEE_STDERR ***' + requires: '*** PYTHON_EXTRAS_NOT_FOUND_ERROR___SEE_STDERR ***' --requires --normalized-names-format pep503 --require-extras-subpackages --package-name python3-zope-component+testing: --provides --majorver-provides --normalized-names-format pep503 --package-name python3-zope-component+testing: usr/lib/python3.9/site-packages/zope.component-4.3.0-py3.9.egg-info: diff --git a/tests/test_scripts_pythondistdeps.py b/tests/test_scripts_pythondistdeps.py index 2dc9a30..bbe1511 100644 --- a/tests/test_scripts_pythondistdeps.py +++ b/tests/test_scripts_pythondistdeps.py @@ -41,18 +41,30 @@ PYTHONDISTDEPS_PATH = Path(__file__).parent / '..' / 'pythondistdeps.py' TEST_DATA_PATH = Path(__file__).parent / 'data' / 'scripts_pythondistdeps' -def run_pythondistdeps(provides_params, requires_params, dist_egg_info_path): +def run_pythondistdeps(provides_params, requires_params, dist_egg_info_path, expect_failure=False): """Runs pythondistdeps.py on `dits_egg_info_path` with given provides and requires parameters and returns a dict with generated provides and requires""" info_path = TEST_DATA_PATH / dist_egg_info_path files = '\n'.join(map(str, info_path.iterdir())) - provides = subprocess.check_output((sys.executable, PYTHONDISTDEPS_PATH, *shlex.split(provides_params)), - input=files, encoding="utf-8") - requires = subprocess.check_output((sys.executable, PYTHONDISTDEPS_PATH, *shlex.split(requires_params)), - input=files, encoding="utf-8") + provides = subprocess.run((sys.executable, PYTHONDISTDEPS_PATH, *shlex.split(provides_params)), + input=files, capture_output=True, check=False, encoding="utf-8") + requires = subprocess.run((sys.executable, PYTHONDISTDEPS_PATH, *shlex.split(requires_params)), + input=files, capture_output=True, check=False, encoding="utf-8") - return {"provides": provides.strip(), "requires": requires.strip()} + if expect_failure: + if provides.returncode == 0 or requires.returncode == 0: + raise RuntimeError(f"pythondistdeps.py did not exit with a non-zero code as expected.\n" + f"Used parameters: ({provides_params}, {requires_params}, {dist_egg_info_path})") + stdout = {"provides": provides.stdout.strip(), "requires": requires.stdout.strip()} + stderr = {"provides": provides.stderr.strip(), "requires": requires.stderr.strip()} + return {"stderr": stderr, "stdout": stdout} + + else: + if provides.returncode != 0 or requires.returncode != 0: + raise RuntimeError(f"pythondistdeps.py unexpectedly exited with a non-zero code.\n" + f"Used parameters: ({provides_params}, {requires_params}, {dist_egg_info_path})") + return {"provides": provides.stdout.strip(), "requires": requires.stdout.strip()} def load_test_data(): @@ -212,7 +224,8 @@ def fixture_check_and_install_test_data(): def test_pythondistdeps(provides_params, requires_params, dist_egg_info_path, expected): """Runs pythondistdeps with the given parameters and dist-info/egg-info path, compares the results with the expected results""" - assert expected == run_pythondistdeps(provides_params, requires_params, dist_egg_info_path) + expect_failure = "stderr" in expected + assert expected == run_pythondistdeps(provides_params, requires_params, dist_egg_info_path, expect_failure) if __name__ == "__main__": @@ -235,8 +248,10 @@ if __name__ == "__main__": for provides_params, requires_params, dist_egg_info_path, expected in generate_test_cases(test_data): # Print a dot to stderr for each test run to keep user informed about progress print(".", end="", flush=True, file=sys.stderr) + + expect_failure = "stderr" in test_data[requires_params][provides_params][dist_egg_info_path] test_data[requires_params][provides_params][dist_egg_info_path] = \ - run_pythondistdeps(provides_params, requires_params, dist_egg_info_path) + run_pythondistdeps(provides_params, requires_params, dist_egg_info_path, expect_failure) print(yaml.dump(test_data, indent=4)) From 32a1b47f5be25e6b17a13ff35bcaa177d36b8fe1 Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Fri, 10 Jul 2020 15:46:19 +0200 Subject: [PATCH 048/110] scripts/pythondistdeps: Tests: small tweaks --- .../scripts_pythondistdeps/test-data.yaml | 29 +++++++++---------- tests/test_scripts_pythondistdeps.py | 2 +- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/tests/data/scripts_pythondistdeps/test-data.yaml b/tests/data/scripts_pythondistdeps/test-data.yaml index a1fd05d..27a7963 100644 --- a/tests/data/scripts_pythondistdeps/test-data.yaml +++ b/tests/data/scripts_pythondistdeps/test-data.yaml @@ -497,6 +497,20 @@ python3.9dist(simplejson) = 3.16 python3dist(simplejson) = 3.16 requires: python(abi) = 3.9 + --provides --majorver-provides-versions 3.9: + usr/lib/python2.7/site-packages/zope.interface-4.6.0.dist-info: + provides: python2.7dist(zope.interface) = 4.6 + requires: |- + python(abi) = 2.7 + python2.7dist(setuptools) + usr/lib64/python3.7/site-packages/lxml-4.4.0.dist-info: + provides: python3.7dist(lxml) = 4.4 + requires: python(abi) = 3.7 + usr/lib64/python3.9/site-packages/simplejson-3.16.0-py3.9.egg-info: + provides: |- + python3.9dist(simplejson) = 3.16 + python3dist(simplejson) = 3.16 + requires: python(abi) = 3.9 --provides --majorver-provides-versions 3.9 --majorver-provides-versions 2.7: usr/lib/python2.7/site-packages/attrs-19.1.0-py2.7.egg-info: provides: |- @@ -844,21 +858,6 @@ python3.9dist(simplejson) = 3.16 python3dist(simplejson) = 3.16 requires: python(abi) = 3.9 - --provides --majorver-provides-versions 3.9: - usr/lib/python2.7/site-packages/zope.interface-4.6.0.dist-info: - provides: |- - python2.7dist(zope.interface) = 4.6 - requires: |- - python(abi) = 2.7 - python2.7dist(setuptools) - usr/lib64/python3.7/site-packages/lxml-4.4.0.dist-info: - provides: python3.7dist(lxml) = 4.4 - requires: python(abi) = 3.7 - usr/lib64/python3.9/site-packages/simplejson-3.16.0-py3.9.egg-info: - provides: |- - python3.9dist(simplejson) = 3.16 - python3dist(simplejson) = 3.16 - requires: python(abi) = 3.9 --requires --normalized-names-format legacy-dots: --provides --majorver-provides --normalized-names-format legacy-dots: usr/lib/python2.7/site-packages/zope.component-4.3.0-py2.7.egg-info: diff --git a/tests/test_scripts_pythondistdeps.py b/tests/test_scripts_pythondistdeps.py index bbe1511..3636f1c 100644 --- a/tests/test_scripts_pythondistdeps.py +++ b/tests/test_scripts_pythondistdeps.py @@ -1,5 +1,5 @@ # Run tests using pytest, e.g. from the root directory -# $ python3 -m pytest --ignore tests/testing/ -vvv +# $ python3 -m pytest --ignore tests/testing/ -s -vvv # # If there are any breakags, the best way to see differences is using a diff: # $ diff tests/data/scripts_pythondistdeps/test-data.yaml <(python3 tests/test_scripts_pythondistdeps.py) From d1a02fdda78743c796fe5c01cbb5287a8f3c873b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Fri, 10 Jul 2020 15:08:30 +0200 Subject: [PATCH 049/110] pythondistdeps.py: Adapt Python version marker workaround for setuptools 42+ See https://bugzilla.redhat.com/show_bug.cgi?id=1853597#c11 pkg_resources from setuptools 42+ no longer only use platform.python_version(), but also platform.python_version_tuple() -- this was updated in packaging 19.1+. This fix makes it work again with both new and old setuptools, hopefully for some while. https://github.com/pypa/setuptools/commit/bf069fe9ddcadaa2c029067601d06a07d037d4f7 https://github.com/pypa/packaging/commit/86a443f3185024edd0b826afdd91d8f9a4917022 --- python-rpm-generators.spec | 1 + pythondistdeps.py | 1 + 2 files changed, 2 insertions(+) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index c7d8c46..a4646df 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -50,6 +50,7 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py * Fri Jul 10 2020 Tomas Orsava - 11-9 - pythondistdeps: Implement provides/requires for extras packages - Enable --require-extras-subpackages +- Adapt Python version marker workaround for setuptools 42+ * Fri Jun 26 2020 Miro Hrončok - 11-8 - Fix python(abi) requires generator, it picked files from almost good directories diff --git a/pythondistdeps.py b/pythondistdeps.py index 5563769..39e53bc 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -273,6 +273,7 @@ if __name__ == "__main__": # [2] https://github.com/pypa/setuptools/pull/1275 import platform platform.python_version = lambda: dist.py_version + platform.python_version_tuple = lambda: tuple(dist.py_version.split('.')) # This is the PEP 503 normalized name. # It does also convert dots to dashes, unlike dist.key. From 7398b71fbceeabd090c8d768edbf75e9ecaa60af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Tue, 21 Jul 2020 22:11:16 +0200 Subject: [PATCH 050/110] pythondistdeps.py: When parsing extras name, take the rightmost + --- python-rpm-generators.spec | 5 ++++- pythondistdeps.py | 11 +++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index a4646df..ec09342 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 11 -Release: 9%{?dist} +Release: 10%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -47,6 +47,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Tue Jul 21 2020 Miro Hrončok - 11-10 +- pythondistdeps: Split Python Extras names after the rightmost plus sign + * Fri Jul 10 2020 Tomas Orsava - 11-9 - pythondistdeps: Implement provides/requires for extras packages - Enable --require-extras-subpackages diff --git a/pythondistdeps.py b/pythondistdeps.py index 39e53bc..7b5a0c2 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -205,8 +205,15 @@ if __name__ == "__main__": # Is this script being run for an extras subpackage? extras_subpackage = None - if args.package_name: - package_name_parts = args.package_name.partition('+') + if args.package_name and '+' in args.package_name: + # The extras names are encoded in the package names after the + sign. + # We take the part after the rightmost +, ignoring when empty, + # this allows packages like nicotine+ or c++ to work fine. + # While packages with names like +spam or foo+bar would break, + # names started with the plus sign are not very common + # and pluses in the middle can be easily replaced with dashes. + # Python extras names don't contain pluses according to PEP 508. + package_name_parts = args.package_name.rpartition('+') extras_subpackage = package_name_parts[2] or None for f in (args.files or stdin.readlines()): From fbe1c77166e93051e01983b9525bb99fbf31312f Mon Sep 17 00:00:00 2001 From: Gordon Messmer Date: Fri, 3 Jul 2020 22:38:41 -0700 Subject: [PATCH 051/110] Sync python dependency conversion with pyreq2rpm. --- python-rpm-generators.spec | 3 +++ pythondistdeps.py | 10 +++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index ec09342..80d64d5 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -49,6 +49,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %changelog * Tue Jul 21 2020 Miro Hrončok - 11-10 - pythondistdeps: Split Python Extras names after the rightmost plus sign +- pythondistdeps: Handle edge cases of version comparisons more closely to + upstream, despite irrationality + See: https://github.com/pypa/packaging/issues/320 * Fri Jul 10 2020 Tomas Orsava - 11-9 - pythondistdeps: Implement provides/requires for extras packages diff --git a/pythondistdeps.py b/pythondistdeps.py index 7b5a0c2..1ca576b 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -115,12 +115,12 @@ def convert_ordered(name, operator, version_id): # with ordered comparisons version_id = version_id[:-2] version = RpmVersion(version_id) - if '>' == operator: - # distutils does not behave this way, but this is - # their recommendation - # https://mail.python.org/archives/list/distutils-sig@python.org/thread/NWEQVTCX5CR2RKW2LT4H77PJTEINSX7P/ + if operator == '>': + # distutils will allow a prefix match with '>' operator = '>=' - version.increment() + if operator == '<=': + # distutils will not allow a prefix match with '<=' + operator = '<' else: version = RpmVersion(version_id) return '{} {} {}'.format(name, operator, version) From 64e5d7567a7c6cae86026d8dfd91c4912d05d07e Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Wed, 22 Jul 2020 17:15:20 +0200 Subject: [PATCH 052/110] Sync tests for python dependency conversion with pyreq2rpm --- tests/data/scripts_pythondistdeps/test-data.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/data/scripts_pythondistdeps/test-data.yaml b/tests/data/scripts_pythondistdeps/test-data.yaml index 27a7963..0f2f041 100644 --- a/tests/data/scripts_pythondistdeps/test-data.yaml +++ b/tests/data/scripts_pythondistdeps/test-data.yaml @@ -45,10 +45,10 @@ python3.9dist(foobar44) <= 2.4.8 python3.9dist(foobar45) <= 2.4.8 python3.9dist(foobar46) <= 2.4.8.1 - python3.9dist(foobar47) <= 2.4.8 + python3.9dist(foobar47) < 2.4.8 python3.9dist(foobar48) <= 2 python3.9dist(foobar49) <= 2 - python3.9dist(foobar50) <= 2 + python3.9dist(foobar50) < 2 python3.9dist(foobar51) <= 2.4.8~b5 python3.9dist(foobar52) <= 2~b5 python3.9dist(foobar53) <= 2.4.8^post1 @@ -80,10 +80,10 @@ python3.9dist(foobar78) > 2.4.8 python3.9dist(foobar79) > 2.4.8.1 (python3.9dist(foobar8) >= 2~b5 with python3.9dist(foobar8) < 2.1) - python3.9dist(foobar80) >= 2.4.9 + python3.9dist(foobar80) >= 2.4.8 python3.9dist(foobar81) > 2 python3.9dist(foobar82) > 2 - python3.9dist(foobar83) >= 3 + python3.9dist(foobar83) >= 2 python3.9dist(foobar84) > 2.4.8~b5 python3.9dist(foobar85) > 2~b5 python3.9dist(foobar86) > 2.4.8^post1 From df7ed92279b1ee7104cc713de7d9c67dd5fa9629 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Wed, 29 Jul 2020 03:42:44 +0000 Subject: [PATCH 053/110] - Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild Signed-off-by: Fedora Release Engineering --- python-rpm-generators.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 80d64d5..5da4f46 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 11 -Release: 10%{?dist} +Release: 11%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -47,6 +47,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Wed Jul 29 2020 Fedora Release Engineering - 11-11 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild + * Tue Jul 21 2020 Miro Hrončok - 11-10 - pythondistdeps: Split Python Extras names after the rightmost plus sign - pythondistdeps: Handle edge cases of version comparisons more closely to From cb3aaf6d26e8a2fd1830395899b937e28766b3df Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Wed, 23 Sep 2020 11:39:53 +0200 Subject: [PATCH 054/110] Add a test for a requires with an underscore We already have PyQt5_sip as a test of a provides with an underscore --- .../requires.txt | 2 ++ tests/data/scripts_pythondistdeps/test-data.yaml | 1 + 2 files changed, 3 insertions(+) diff --git a/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/requires.txt b/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/requires.txt index 09279fb..51ac189 100644 --- a/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/requires.txt +++ b/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/requires.txt @@ -100,3 +100,5 @@ hugo2<=8a4 hugo3!=11.1.1b14 hugo4>11rc0 hugo5===11.1.0.post3 + +test_underscores==1 diff --git a/tests/data/scripts_pythondistdeps/test-data.yaml b/tests/data/scripts_pythondistdeps/test-data.yaml index 0f2f041..168eb4f 100644 --- a/tests/data/scripts_pythondistdeps/test-data.yaml +++ b/tests/data/scripts_pythondistdeps/test-data.yaml @@ -96,6 +96,7 @@ python3.9dist(hugo5) = 11.1^post3 python3.9dist(pyparsing0) ((python3.9dist(pyparsing1) < 2.0.4 or python3.9dist(pyparsing1) > 2.0.4) with (python3.9dist(pyparsing1) < 2.1.2 or python3.9dist(pyparsing1) > 2.1.2) with (python3.9dist(pyparsing1) < 2.1.6 or python3.9dist(pyparsing1) > 2.1.6) with python3.9dist(pyparsing1) >= 2.0.1) + python3.9dist(test-underscores) = 1 usr/lib/python3.9/site-packages/taskotron_python_versions-0.1.dev6.dist-info: provides: python3.9dist(taskotron-python-versions) = 0.1~~dev6 requires: |- From bfb7f70b994d667b703a6b16c2b35d5056572800 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Thu, 24 Sep 2020 13:50:04 +0200 Subject: [PATCH 055/110] Add a test for a requires with multiple underscores --- .../requires.txt | 1 + tests/data/scripts_pythondistdeps/test-data.yaml | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/requires.txt b/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/requires.txt index 51ac189..22ef4d9 100644 --- a/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/requires.txt +++ b/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/requires.txt @@ -101,4 +101,5 @@ hugo3!=11.1.1b14 hugo4>11rc0 hugo5===11.1.0.post3 +test___multiple__underscores==1 test_underscores==1 diff --git a/tests/data/scripts_pythondistdeps/test-data.yaml b/tests/data/scripts_pythondistdeps/test-data.yaml index 168eb4f..6467c6c 100644 --- a/tests/data/scripts_pythondistdeps/test-data.yaml +++ b/tests/data/scripts_pythondistdeps/test-data.yaml @@ -96,6 +96,7 @@ python3.9dist(hugo5) = 11.1^post3 python3.9dist(pyparsing0) ((python3.9dist(pyparsing1) < 2.0.4 or python3.9dist(pyparsing1) > 2.0.4) with (python3.9dist(pyparsing1) < 2.1.2 or python3.9dist(pyparsing1) > 2.1.2) with (python3.9dist(pyparsing1) < 2.1.6 or python3.9dist(pyparsing1) > 2.1.6) with python3.9dist(pyparsing1) >= 2.0.1) + python3.9dist(test-multiple-underscores) = 1 python3.9dist(test-underscores) = 1 usr/lib/python3.9/site-packages/taskotron_python_versions-0.1.dev6.dist-info: provides: python3.9dist(taskotron-python-versions) = 0.1~~dev6 From d77d134c100194027d6b1f7bbc996043679e5fda Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Mon, 19 Oct 2020 12:50:23 +0200 Subject: [PATCH 056/110] Run scripts in an isolated environment (#1889080) --- python-rpm-generators.spec | 5 ++++- pythonbundles.py | 2 +- pythondistdeps.py | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 5da4f46..60811e5 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 11 -Release: 11%{?dist} +Release: 12%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -47,6 +47,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Mon Oct 19 2020 Tomas Orsava - 11-12 +- Run scripts in an isolated Python environment (#1889080) + * Wed Jul 29 2020 Fedora Release Engineering - 11-11 - Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild diff --git a/pythonbundles.py b/pythonbundles.py index 5093dff..96e817e 100644 --- a/pythonbundles.py +++ b/pythonbundles.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 -B +#!/usr/bin/python3 -sB # (imports pythondistdeps from /usr/lib/rpm, hence -B) # # This program is free software. diff --git a/pythondistdeps.py b/pythondistdeps.py index 1ca576b..70e08b8 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/python3 -s # -*- coding: utf-8 -*- # # Copyright 2010 Per Øyvind Karlsen From f328c9dd189053d0ceea722e28176261cf64fd15 Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Mon, 19 Oct 2020 12:51:06 +0200 Subject: [PATCH 057/110] Add executable bit to pythonbundles.py pythondistdeps.py is executable already --- pythonbundles.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 pythonbundles.py diff --git a/pythonbundles.py b/pythonbundles.py old mode 100644 new mode 100755 From b65cf8549a205716a8b60a82da5aed41c4c0254f Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Wed, 27 Jan 2021 13:13:21 +0000 Subject: [PATCH 058/110] - Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild Signed-off-by: Fedora Release Engineering --- python-rpm-generators.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 60811e5..c3a05e1 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 11 -Release: 12%{?dist} +Release: 13%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -47,6 +47,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Wed Jan 27 2021 Fedora Release Engineering - 11-13 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild + * Mon Oct 19 2020 Tomas Orsava - 11-12 - Run scripts in an isolated Python environment (#1889080) From 8c2a1c0ac980a4e0c831901694f73c68d5b707c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Wed, 3 Feb 2021 14:07:07 +0100 Subject: [PATCH 059/110] Disable the dist generators for Python 2 https://fedoraproject.org/wiki/Changes/Disable_Python_2_Dist_RPM_Generators_and_Freeze_Python_2_Macros The regex previously matched any Python version in a form of .. Now it matches anything from 3.0 above: . It still does not match ., e.g. 11.0. This is a breaking change, hence the version bump. --- python-rpm-generators.spec | 8 ++++++-- pythondist.attr | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index c3a05e1..1e01d79 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs -Version: 11 -Release: 13%{?dist} +Version: 12 +Release: 1%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -47,6 +47,10 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Wed Feb 03 2021 Miro Hrončok - 12-1 +- Disable the dist generators for Python 2 +- https://fedoraproject.org/wiki/Changes/Disable_Python_2_Dist_RPM_Generators_and_Freeze_Python_2_Macros + * Wed Jan 27 2021 Fedora Release Engineering - 11-13 - Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild diff --git a/pythondist.attr b/pythondist.attr index b0d4fc5..e3b1eed 100644 --- a/pythondist.attr +++ b/pythondist.attr @@ -1,3 +1,3 @@ %__pythondist_provides %{_rpmconfigdir}/pythondistdeps.py --provides --normalized-names-format pep503 --package-name %{name} --normalized-names-provide-both --majorver-provides-versions 2.7,%{__default_python3_version} %__pythondist_requires %{_rpmconfigdir}/pythondistdeps.py --requires --normalized-names-format pep503 --package-name %{name} %{?!_python_no_extras_requires:--require-extras-subpackages} -%__pythondist_path ^/usr/lib(64)?/python[[:digit:]]\\.[[:digit:]]+/site-packages/[^/]+\\.(dist-info|egg-info|egg-link)$ +%__pythondist_path ^/usr/lib(64)?/python[3-9]\\.[[:digit:]]+/site-packages/[^/]+\\.(dist-info|egg-info|egg-link)$ From 2d631762c556c4495ac6599075f896b372b4bbbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Mon, 8 Feb 2021 10:53:40 +0100 Subject: [PATCH 060/110] Remove unused 2.7 from --majorver-provides-versions Fixup for 8c2a1c0ac980a4e0c831901694f73c68d5b707c8. This makes no real difference, just a cleanup, hence not bumping. --- pythondist.attr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pythondist.attr b/pythondist.attr index e3b1eed..f849ba1 100644 --- a/pythondist.attr +++ b/pythondist.attr @@ -1,3 +1,3 @@ -%__pythondist_provides %{_rpmconfigdir}/pythondistdeps.py --provides --normalized-names-format pep503 --package-name %{name} --normalized-names-provide-both --majorver-provides-versions 2.7,%{__default_python3_version} +%__pythondist_provides %{_rpmconfigdir}/pythondistdeps.py --provides --normalized-names-format pep503 --package-name %{name} --normalized-names-provide-both --majorver-provides-versions %{__default_python3_version} %__pythondist_requires %{_rpmconfigdir}/pythondistdeps.py --requires --normalized-names-format pep503 --package-name %{name} %{?!_python_no_extras_requires:--require-extras-subpackages} %__pythondist_path ^/usr/lib(64)?/python[3-9]\\.[[:digit:]]+/site-packages/[^/]+\\.(dist-info|egg-info|egg-link)$ From 438d8d3b705e88b62d4d36347338fd5357a71687 Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Wed, 17 Feb 2021 12:18:26 +0100 Subject: [PATCH 061/110] scripts/pythondistdeps: Backport switch to importlib.metadata from upstream Upstream change to importlib.metadata: https://github.com/rpm-software-management/rpm/pull/1317 Due to extras packages being hadled slightly differently by importlib, one test case for this was added. And due to changes in handling requires.txt files, comments were removed from the pyreq2rpm.tests testing package. Also because of the switch, we removed the dependency on setuptools and added a dependency on packaging. Note: Some packages with egg-info files might provide a different name due to this change if there is a conflict between the filename and the name in the metadata. Previously, the filename was sometimes used to parse the name, now it is always the content of that file, which is what packaging does, and thus also pip and other Python tooling. Currently, this is known to affect only 1 package in Fedora (ntpsec). The resulting script is different from upstream because of not yet upstreamed changes in Fedora: - scripts/pythondistdeps: Rework error messages - scripts/pythondistdeps: Add parameter --package-name - scripts/pythondistdeps: Implement provides/requires for extras packages - pythondistdeps.py: When parsing extras name, take the rightmost + These changes are proposed in this upstream PR: https://github.com/rpm-software-management/rpm/pull/1546 --- python-rpm-generators.spec | 9 +- pythondistdeps.py | 263 ++++++++++-------- .../requires.txt | 3 - .../scripts_pythondistdeps/test-data.yaml | 9 + 4 files changed, 165 insertions(+), 119 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 1e01d79..1992873 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 12 -Release: 1%{?dist} +Release: 2%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -21,7 +21,7 @@ BuildArch: noarch %package -n python3-rpm-generators Summary: %{summary} -Requires: python3-setuptools +Requires: python3-packaging # We have parametric macro generators, we need RPM 4.16 (4.15.90+ is 4.16 alpha) Requires: rpm > 4.15.90-0 # This contains the Lua functions we use: @@ -47,6 +47,11 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Wed Feb 17 2021 Tomas Orsava - 12-2 +- scripts/pythondistdeps: Switch from using pkg_resources to importlib.metadata + for reading the egg/dist-info metadata +- The script no longer requires setuptools but instead requires packaging + * Wed Feb 03 2021 Miro Hrončok - 12-1 - Disable the dist generators for Python 2 - https://fedoraproject.org/wiki/Changes/Disable_Python_2_Dist_RPM_Generators_and_Freeze_Python_2_Macros diff --git a/pythondistdeps.py b/pythondistdeps.py index 70e08b8..dcc0a2a 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -11,21 +11,85 @@ # RPM python dependency generator, using .egg-info/.egg-link/.dist-info data # -# Please know: -# - Notes from an attempted rewrite from pkg_resources to importlib.metadata in -# 2020 can be found in the message of the commit that added this line. - from __future__ import print_function import argparse -from os.path import basename, dirname, isdir, sep -from sys import argv, stdin, stderr, version from distutils.sysconfig import get_python_lib +from os.path import dirname, sep +import re +from sys import argv, stdin, stderr from warnings import warn +from packaging.requirements import Requirement as Requirement_ +from packaging.version import parse + +try: + from importlib.metadata import PathDistribution +except ImportError: + from importlib_metadata import PathDistribution + +try: + from pathlib import Path +except ImportError: + from pathlib2 import Path + + +def normalize_name(name): + """https://www.python.org/dev/peps/pep-0503/#normalized-names""" + return re.sub(r'[-_.]+', '-', name).lower() + + +def legacy_normalize_name(name): + """Like pkg_resources Distribution.key property""" + return re.sub(r'[-_]+', '-', name).lower() + + +class Requirement(Requirement_): + def __init__(self, requirement_string): + super(Requirement, self).__init__(requirement_string) + self.normalized_name = normalize_name(self.name) + self.legacy_normalized_name = legacy_normalize_name(self.name) + + +class Distribution(PathDistribution): + def __init__(self, path): + super(Distribution, self).__init__(Path(path)) + self.name = self.metadata['Name'] + self.normalized_name = normalize_name(self.name) + self.legacy_normalized_name = legacy_normalize_name(self.name) + self.requirements = [Requirement(r) for r in self.requires or []] + self.extras = [ + v for k, v in self.metadata.items() if k == 'Provides-Extra'] + self.py_version = self._parse_py_version(path) + + def _parse_py_version(self, path): + # Try to parse the Python version from the path the metadata + # resides at (e.g. /usr/lib/pythonX.Y/site-packages/...) + res = re.search(r"/python(?P\d+\.\d+)/", path) + if res: + return res.group('pyver') + # If that hasn't worked, attempt to parse it from the metadata + # directory name + res = re.search(r"-py(?P\d+.\d+)[.-]egg-info$", path) + if res: + return res.group('pyver') + return None + + def requirements_for_extra(self, extra): + extra_deps = [] + for req in self.requirements: + if not req.marker: + continue + if req.marker.evaluate(get_marker_env(self, extra)): + extra_deps.append(req) + return extra_deps + + def __repr__(self): + return '{} from {}'.format(self.name, self._path) + class RpmVersion(): def __init__(self, version_id): - version = parse_version(version_id) + version = parse(version_id) if isinstance(version._version, str): self.version = version._version else: @@ -144,10 +208,20 @@ def convert(name, operator, version_id): format(version_id, name)) from exc -def normalize_name(name): - """https://www.python.org/dev/peps/pep-0503/#normalized-names""" - import re - return re.sub(r'[-_.]+', '-', name).lower() +def get_marker_env(dist, extra): + # packaging uses a default environment using + # platform.python_version to evaluate if a dependency is relevant + # based on environment markers [1], + # e.g. requirement `argparse;python_version<"2.7"` + # + # Since we're running this script on one Python version while + # possibly evaluating packages for different versions, we + # set up an environment with the version we want to evaluate. + # + # [1] https://www.python.org/dev/peps/pep-0508/#environment-markers + return {"python_full_version": dist.py_version, + "python_version": dist.py_version, + "extra": extra} if __name__ == "__main__": @@ -243,52 +317,21 @@ if __name__ == "__main__": if lower.endswith('.egg') or \ lower.endswith('.egg-info') or \ lower.endswith('.dist-info'): - # This import is very slow, so only do it if needed - # - Notes from an attempted rewrite from pkg_resources to - # importlib.metadata in 2020 can be found in the message of - # the commit that added this line. - from pkg_resources import Distribution, FileMetadata, PathMetadata, Requirement, parse_version - dist_name = basename(f) - if isdir(f): - path_item = dirname(f) - metadata = PathMetadata(path_item, f) - else: - path_item = f - metadata = FileMetadata(f) - dist = Distribution.from_location(path_item, dist_name, metadata) - # Check if py_version is defined in the metadata file/directory name + dist = Distribution(f) if not dist.py_version: - # Try to parse the Python version from the path the metadata - # resides at (e.g. /usr/lib/pythonX.Y/site-packages/...) - import re - res = re.search(r"/python(?P\d+\.\d+)/", path_item) - if res: - dist.py_version = res.group('pyver') - else: - warn("Version for {!r} has not been found".format(dist), RuntimeWarning) - continue + warn("Version for {!r} has not been found".format(dist), RuntimeWarning) + continue - # pkg_resources use platform.python_version to evaluate if a - # dependency is relevant based on environment markers [1], - # e.g. requirement `argparse;python_version<"2.7"` - # - # Since we're running this script on one Python version while - # possibly evaluating packages for different versions, we mock the - # platform.python_version function. Discussed upstream [2]. - # - # [1] https://www.python.org/dev/peps/pep-0508/#environment-markers - # [2] https://github.com/pypa/setuptools/pull/1275 - import platform - platform.python_version = lambda: dist.py_version - platform.python_version_tuple = lambda: tuple(dist.py_version.split('.')) - - # This is the PEP 503 normalized name. - # It does also convert dots to dashes, unlike dist.key. - # See https://bugzilla.redhat.com/show_bug.cgi?id=1791530 - normalized_name = normalize_name(dist.project_name) - - # If we're processing an extras subpackage, check that the extras exists - if extras_subpackage and extras_subpackage not in dist.extras: + # If processing an extras subpackage: + # Check that the extras name is declared in the metadata, or + # that there are some dependencies associated with the extras + # name in the requires.txt (this is an outdated way to declare + # extras packages). + # - If there is an extras package declared only in requires.txt + # without any dependencies, this check will fail. In that case + # make sure to use updated metadata and declare the extras + # package there. + if extras_subpackage and extras_subpackage not in dist.extras and not dist.requirements_for_extra(extras_subpackage): print("*** PYTHON_EXTRAS_NOT_FOUND_ERROR___SEE_STDERR ***") print(f"\nError: The package name contains an extras name `{extras_subpackage}` that was not found in the metadata.\n" "Check if the extras were removed from the project. If so, consider removing the subpackage and obsoleting it from another.\n", file=stderr) @@ -301,32 +344,32 @@ if __name__ == "__main__": if args.provides: extras_suffix = f"[{extras_subpackage}]" if extras_subpackage else "" # If egg/dist metadata says package name is python, we provide python(abi) - if dist.key == 'python': + if dist.normalized_name == 'python': name = 'python(abi)' if name not in py_deps: py_deps[name] = [] py_deps[name].append(('==', dist.py_version)) if not args.legacy or not args.majorver_only: if normalized_names_provide_legacy: - name = 'python{}dist({}{})'.format(dist.py_version, dist.key, extras_suffix) + name = 'python{}dist({}{})'.format(dist.py_version, dist.legacy_normalized_name, extras_suffix) if name not in py_deps: py_deps[name] = [] if normalized_names_provide_pep503: - name_ = 'python{}dist({}{})'.format(dist.py_version, normalized_name, extras_suffix) + name_ = 'python{}dist({}{})'.format(dist.py_version, dist.normalized_name, extras_suffix) if name_ not in py_deps: py_deps[name_] = [] if args.majorver_provides or args.majorver_only or \ (args.majorver_provides_versions and dist.py_version in args.majorver_provides_versions): if normalized_names_provide_legacy: - pymajor_name = 'python{}dist({}{})'.format(pyver_major, dist.key, extras_suffix) + pymajor_name = 'python{}dist({}{})'.format(pyver_major, dist.legacy_normalized_name, extras_suffix) if pymajor_name not in py_deps: py_deps[pymajor_name] = [] if normalized_names_provide_pep503: - pymajor_name_ = 'python{}dist({}{})'.format(pyver_major, normalized_name, extras_suffix) + pymajor_name_ = 'python{}dist({}{})'.format(pyver_major, dist.normalized_name, extras_suffix) if pymajor_name_ not in py_deps: py_deps[pymajor_name_] = [] if args.legacy or args.legacy_provides: - legacy_name = 'pythonegg({})({})'.format(pyver_major, dist.key) + legacy_name = 'pythonegg({})({})'.format(pyver_major, dist.legacy_normalized_name) if legacy_name not in py_deps: py_deps[legacy_name] = [] if dist.version: @@ -351,7 +394,7 @@ if __name__ == "__main__": if args.requires or (args.recommends and dist.extras): name = 'python(abi)' # If egg/dist metadata says package name is python, we don't add dependency on python(abi) - if dist.key == 'python': + if dist.normalized_name == 'python': py_abi = False if name in py_deps: py_deps.pop(name) @@ -361,24 +404,21 @@ if __name__ == "__main__": spec = ('==', dist.py_version) if spec not in py_deps[name]: py_deps[name].append(spec) - deps = dist.requires() - if args.recommends: - depsextras = dist.requires(extras=dist.extras) - if not args.requires: - for dep in reversed(depsextras): - if dep in deps: - depsextras.remove(dep) - deps = depsextras - elif extras_subpackage: - # Extras requires also contain the base requires included - deps = [d for d in dist.requires(extras=[extras_subpackage]) if d not in dist.requires()] + + if extras_subpackage: + deps = [d for d in dist.requirements_for_extra(extras_subpackage)] + else: + deps = dist.requirements + # console_scripts/gui_scripts entry points need pkg_resources from setuptools - if ((dist.get_entry_map('console_scripts') or - dist.get_entry_map('gui_scripts')) and + if (dist.entry_points and (lower.endswith('.egg') or lower.endswith('.egg-info'))): - # stick them first so any more specific requirement overrides it - deps.insert(0, Requirement.parse('setuptools')) + groups = {ep.group for ep in dist.entry_points} + if {"console_scripts", "gui_scripts"} & groups: + # stick them first so any more specific requirement + # overrides it + deps.insert(0, Requirement('setuptools')) # add requires/recommends based on egg/dist metadata for dep in deps: # Even if we're requiring `foo[bar]`, also require `foo` @@ -389,67 +429,62 @@ if __name__ == "__main__": # A dependency can have more than one extras, # i.e. foo[bar,baz], so let's go through all of them extras_suffixes += [f"[{e}]" for e in dep.extras] + for extras_suffix in extras_suffixes: if normalized_names_require_pep503: - dep_normalized_name = normalize_name(dep.project_name) + dep_normalized_name = dep.normalized_name else: - dep_normalized_name = dep.key + dep_normalized_name = dep.legacy_normalized_name if args.legacy: - name = 'pythonegg({})({})'.format(pyver_major, dep.key) + name = 'pythonegg({})({})'.format(pyver_major, dep.legacy_normalized_name) else: if args.majorver_only: name = 'python{}dist({}{})'.format(pyver_major, dep_normalized_name, extras_suffix) else: name = 'python{}dist({}{})'.format(dist.py_version, dep_normalized_name, extras_suffix) - for spec in dep.specs: - if name not in py_deps: - py_deps[name] = [] - if spec not in py_deps[name]: - py_deps[name].append(spec) - if not dep.specs: + + if dep.marker and not args.recommends and not extras_subpackage: + if not dep.marker.evaluate(get_marker_env(dist, '')): + continue + + if name not in py_deps: py_deps[name] = [] + for spec in dep.specifier: + if (spec.operator, spec.version) not in py_deps[name]: + py_deps[name].append((spec.operator, spec.version)) + # Unused, for automatic sub-package generation based on 'extras' from egg/dist metadata # TODO: implement in rpm later, or...? if args.extras: - deps = dist.requires() - extras = dist.extras - print(extras) - for extra in extras: + print(dist.extras) + for extra in dist.extras: print('%%package\textras-{}'.format(extra)) - print('Summary:\t{} extra for {} python package'.format(extra, dist.key)) + print('Summary:\t{} extra for {} python package'.format(extra, dist.legacy_normalized_name)) print('Group:\t\tDevelopment/Python') - depsextras = dist.requires(extras=[extra]) - for dep in reversed(depsextras): - if dep in deps: - depsextras.remove(dep) - deps = depsextras - for dep in deps: - for spec in dep.specs: - if spec[0] == '!=': - print('Conflicts:\t{} {} {}'.format(dep.key, '==', spec[1])) + for dep in dist.requirements_for_extra(extra): + for spec in dep.specifier: + if spec.operator == '!=': + print('Conflicts:\t{} {} {}'.format(dep.legacy_normalized_name, '==', spec.version)) else: - print('Requires:\t{} {} {}'.format(dep.key, spec[0], spec[1])) + print('Requires:\t{} {} {}'.format(dep.legacy_normalized_name, spec.operator, spec.version)) print('%%description\t{}'.format(extra)) - print('{} extra for {} python package'.format(extra, dist.key)) + print('{} extra for {} python package'.format(extra, dist.legacy_normalized_name)) print('%%files\t\textras-{}\n'.format(extra)) if args.conflicts: # Should we really add conflicts for extras? # Creating a meta package per extra with recommends on, which has # the requires/conflicts in stead might be a better solution... - for dep in dist.requires(extras=dist.extras): - name = dep.key - for spec in dep.specs: - if spec[0] == '!=': - if name not in py_deps: - py_deps[name] = [] - spec = ('==', spec[1]) - if spec not in py_deps[name]: - py_deps[name].append(spec) + for dep in dist.requirements: + for spec in dep.specifier: + if spec.operator == '!=': + if dep.legacy_normalized_name not in py_deps: + py_deps[dep.legacy_normalized_name] = [] + spec = ('==', spec.version) + if spec not in py_deps[dep.legacy_normalized_name]: + py_deps[dep.legacy_normalized_name].append(spec) - names = list(py_deps.keys()) - names.sort() - for name in names: + for name in sorted(py_deps): if py_deps[name]: # Print out versioned provides, requires, recommends, conflicts spec_list = [] diff --git a/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/requires.txt b/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/requires.txt index 22ef4d9..1436266 100644 --- a/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/requires.txt +++ b/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/requires.txt @@ -1,4 +1,3 @@ -# Taken from pyreq2rpm, removed tests that are expected to fail foobar0~=2.4.8 foobar1~=2.4.8.0 foobar2~=2.4.8.1 @@ -91,10 +90,8 @@ pyparsing0 pyparsing1>=2.0.1,!=2.0.4,!=2.1.2,!=2.1.6 babel>=1.3,!=2.0 -# Tests for breakages in Fedora fedora-python-nb2plots==0+unknown -# Other tests hugo1==1.0.0.dev7 hugo2<=8a4 hugo3!=11.1.1b14 diff --git a/tests/data/scripts_pythondistdeps/test-data.yaml b/tests/data/scripts_pythondistdeps/test-data.yaml index 6467c6c..9b97be8 100644 --- a/tests/data/scripts_pythondistdeps/test-data.yaml +++ b/tests/data/scripts_pythondistdeps/test-data.yaml @@ -1216,6 +1216,15 @@ python3dist(backports-range) = 3.7.2 python3dist(backports.range) = 3.7.2 requires: python(abi) = 3.7 +--requires --normalized-names-format pep503 --package-name python3-setuptools+certs: + --provides --majorver-provides --normalized-names-format pep503 --package-name python3-setuptools+certs: + usr/lib/python3.9/site-packages/setuptools-41.6.0.dist-info: + provides: |- + python3.9dist(setuptools[certs]) = 41.6 + python3dist(setuptools[certs]) = 41.6 + requires: |- + python(abi) = 3.9 + python3.9dist(certifi) = 2016.9.26 --requires --normalized-names-format pep503 --package-name python3-zope-component+testing: --provides --majorver-provides --normalized-names-format pep503 --package-name python3-zope-component+testing: usr/lib/python3.9/site-packages/zope.component-4.3.0-py3.9.egg-info: From 48510eebaebd2620d6b6a74f51e8478bbb2b7ad9 Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Mon, 22 Feb 2021 13:16:24 +0100 Subject: [PATCH 062/110] scripts/pythondistdeps: Fix for Python 3.10 self.name in PathDistribution is a property in Python 3.10+ and thus we can't redefine it as an instance variable. Instead we explicitly define it as a property, which works on all supported Python versions. --- python-rpm-generators.spec | 5 ++++- pythondistdeps.py | 10 +++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 1992873..7550178 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 12 -Release: 2%{?dist} +Release: 3%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -47,6 +47,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Mon Feb 22 2021 Tomas Orsava - 12-3 +- scripts/pythondistdeps: Fix for Python 3.10 + * Wed Feb 17 2021 Tomas Orsava - 12-2 - scripts/pythondistdeps: Switch from using pkg_resources to importlib.metadata for reading the egg/dist-info metadata diff --git a/pythondistdeps.py b/pythondistdeps.py index dcc0a2a..9ba0590 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -53,7 +53,6 @@ class Requirement(Requirement_): class Distribution(PathDistribution): def __init__(self, path): super(Distribution, self).__init__(Path(path)) - self.name = self.metadata['Name'] self.normalized_name = normalize_name(self.name) self.legacy_normalized_name = legacy_normalize_name(self.name) self.requirements = [Requirement(r) for r in self.requires or []] @@ -61,6 +60,15 @@ class Distribution(PathDistribution): v for k, v in self.metadata.items() if k == 'Provides-Extra'] self.py_version = self._parse_py_version(path) + # `name` is defined as a property exactly like this in Python 3.10 in the + # PathDistribution class. Due to that we can't redefine `name` as a normal + # attribute. So we copied the Python 3.10 definition here into the code so + # that it works also on previous Python/importlib_metadata versions. + @property + def name(self): + """Return the 'Name' metadata for the distribution package.""" + return self.metadata['Name'] + def _parse_py_version(self, path): # Try to parse the Python version from the path the metadata # resides at (e.g. /usr/lib/pythonX.Y/site-packages/...) From 103464475f0f30dc5f988fcc8080dc4452a60815 Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Thu, 11 Mar 2021 12:39:56 +0100 Subject: [PATCH 063/110] pythondistdeps.py: Changing order in test-data --- .../scripts_pythondistdeps/test-data.yaml | 198 +++++++++--------- 1 file changed, 100 insertions(+), 98 deletions(-) diff --git a/tests/data/scripts_pythondistdeps/test-data.yaml b/tests/data/scripts_pythondistdeps/test-data.yaml index 9b97be8..4a611c3 100644 --- a/tests/data/scripts_pythondistdeps/test-data.yaml +++ b/tests/data/scripts_pythondistdeps/test-data.yaml @@ -1,103 +1,5 @@ --requires: --provides: - pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info: - provides: python3.9dist(pyreq2rpm.tests) = 2020.04.07.024dab0 - requires: |- - python(abi) = 3.9 - ((python3.9dist(babel) < 2 or python3.9dist(babel) > 2) with python3.9dist(babel) >= 1.3) - python3.9dist(fedora-python-nb2plots) = 0 - (python3.9dist(foobar0) >= 2.4.8 with python3.9dist(foobar0) < 2.5) - (python3.9dist(foobar1) >= 2.4.8 with python3.9dist(foobar1) < 2.4.9) - (python3.9dist(foobar10) >= 2^post1 with python3.9dist(foobar10) < 3) - python3.9dist(foobar11) = 2.4.8 - python3.9dist(foobar12) = 2.4.8 - python3.9dist(foobar13) = 2.4.8.1 - (python3.9dist(foobar14) >= 2.4.8 with python3.9dist(foobar14) < 2.4.9) - python3.9dist(foobar15) = 2 - python3.9dist(foobar16) = 2 - (python3.9dist(foobar17) >= 2 with python3.9dist(foobar17) < 3) - python3.9dist(foobar18) = 2.4.8~b5 - python3.9dist(foobar19) = 2~b5 - (python3.9dist(foobar2) >= 2.4.8.1 with python3.9dist(foobar2) < 2.4.9) - python3.9dist(foobar20) = 2.4.8^post1 - python3.9dist(foobar21) = 2^post1 - python3.9dist(foobar22) = 2.4.8 - python3.9dist(foobar23) = 2.4.8 - python3.9dist(foobar24) = 2.4.8.1 - python3.9dist(foobar26) = 2 - python3.9dist(foobar27) = 2 - python3.9dist(foobar29) = 2.4.8~b5 - python3.9dist(foobar30) = 2~b5 - python3.9dist(foobar31) = 2.4.8^post1 - python3.9dist(foobar32) = 2^post1 - (python3.9dist(foobar33) < 2.4.8 or python3.9dist(foobar33) > 2.4.8) - (python3.9dist(foobar34) < 2.4.8 or python3.9dist(foobar34) > 2.4.8) - (python3.9dist(foobar35) < 2.4.8.1 or python3.9dist(foobar35) > 2.4.8.1) - (python3.9dist(foobar36) < 2.4.8 or python3.9dist(foobar36) > 2.4.9) - (python3.9dist(foobar37) < 2 or python3.9dist(foobar37) > 2) - (python3.9dist(foobar38) < 2 or python3.9dist(foobar38) > 2) - (python3.9dist(foobar39) < 2 or python3.9dist(foobar39) > 3) - (python3.9dist(foobar4) >= 2 with python3.9dist(foobar4) < 3) - (python3.9dist(foobar40) < 2.4.8~b5 or python3.9dist(foobar40) > 2.4.8~b5) - (python3.9dist(foobar41) < 2~b5 or python3.9dist(foobar41) > 2~b5) - (python3.9dist(foobar42) < 2.4.8^post1 or python3.9dist(foobar42) > 2.4.8^post1) - (python3.9dist(foobar43) < 2^post1 or python3.9dist(foobar43) > 2^post1) - python3.9dist(foobar44) <= 2.4.8 - python3.9dist(foobar45) <= 2.4.8 - python3.9dist(foobar46) <= 2.4.8.1 - python3.9dist(foobar47) < 2.4.8 - python3.9dist(foobar48) <= 2 - python3.9dist(foobar49) <= 2 - python3.9dist(foobar50) < 2 - python3.9dist(foobar51) <= 2.4.8~b5 - python3.9dist(foobar52) <= 2~b5 - python3.9dist(foobar53) <= 2.4.8^post1 - python3.9dist(foobar54) <= 2^post1 - python3.9dist(foobar55) < 2.4.8 - python3.9dist(foobar56) < 2.4.8 - python3.9dist(foobar57) < 2.4.8.1 - python3.9dist(foobar58) < 2.4.8 - python3.9dist(foobar59) < 2 - python3.9dist(foobar60) < 2 - python3.9dist(foobar61) < 2 - python3.9dist(foobar62) < 2.4.8~b5 - python3.9dist(foobar63) < 2~b5 - python3.9dist(foobar64) < 2.4.8^post1 - python3.9dist(foobar65) < 2^post1 - python3.9dist(foobar66) >= 2.4.8 - python3.9dist(foobar67) >= 2.4.8 - python3.9dist(foobar68) >= 2.4.8.1 - python3.9dist(foobar69) >= 2.4.8 - (python3.9dist(foobar7) >= 2.4.8~b5 with python3.9dist(foobar7) < 2.5) - python3.9dist(foobar70) >= 2 - python3.9dist(foobar71) >= 2 - python3.9dist(foobar72) >= 2 - python3.9dist(foobar73) >= 2.4.8~b5 - python3.9dist(foobar74) >= 2~b5 - python3.9dist(foobar75) >= 2.4.8^post1 - python3.9dist(foobar76) >= 2^post1 - python3.9dist(foobar77) > 2.4.8 - python3.9dist(foobar78) > 2.4.8 - python3.9dist(foobar79) > 2.4.8.1 - (python3.9dist(foobar8) >= 2~b5 with python3.9dist(foobar8) < 2.1) - python3.9dist(foobar80) >= 2.4.8 - python3.9dist(foobar81) > 2 - python3.9dist(foobar82) > 2 - python3.9dist(foobar83) >= 2 - python3.9dist(foobar84) > 2.4.8~b5 - python3.9dist(foobar85) > 2~b5 - python3.9dist(foobar86) > 2.4.8^post1 - python3.9dist(foobar87) > 2^post1 - (python3.9dist(foobar9) >= 2.4.8^post1 with python3.9dist(foobar9) < 2.5) - python3.9dist(hugo1) = 1~~dev7 - python3.9dist(hugo2) <= 8~a4 - (python3.9dist(hugo3) < 11.1.1~b14 or python3.9dist(hugo3) > 11.1.1~b14) - python3.9dist(hugo4) > 11~rc0 - python3.9dist(hugo5) = 11.1^post3 - python3.9dist(pyparsing0) - ((python3.9dist(pyparsing1) < 2.0.4 or python3.9dist(pyparsing1) > 2.0.4) with (python3.9dist(pyparsing1) < 2.1.2 or python3.9dist(pyparsing1) > 2.1.2) with (python3.9dist(pyparsing1) < 2.1.6 or python3.9dist(pyparsing1) > 2.1.6) with python3.9dist(pyparsing1) >= 2.0.1) - python3.9dist(test-multiple-underscores) = 1 - python3.9dist(test-underscores) = 1 usr/lib/python3.9/site-packages/taskotron_python_versions-0.1.dev6.dist-info: provides: python3.9dist(taskotron-python-versions) = 0.1~~dev6 requires: |- @@ -1257,6 +1159,106 @@ python3.9dist(coverage) python3.9dist(nose) python3.9dist(zope-testing) +--requires: + --provides: + pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info: + provides: python3.9dist(pyreq2rpm.tests) = 2020.04.07.024dab0 + requires: |- + python(abi) = 3.9 + ((python3.9dist(babel) < 2 or python3.9dist(babel) > 2) with python3.9dist(babel) >= 1.3) + python3.9dist(fedora-python-nb2plots) = 0 + (python3.9dist(foobar0) >= 2.4.8 with python3.9dist(foobar0) < 2.5) + (python3.9dist(foobar1) >= 2.4.8 with python3.9dist(foobar1) < 2.4.9) + (python3.9dist(foobar10) >= 2^post1 with python3.9dist(foobar10) < 3) + python3.9dist(foobar11) = 2.4.8 + python3.9dist(foobar12) = 2.4.8 + python3.9dist(foobar13) = 2.4.8.1 + (python3.9dist(foobar14) >= 2.4.8 with python3.9dist(foobar14) < 2.4.9) + python3.9dist(foobar15) = 2 + python3.9dist(foobar16) = 2 + (python3.9dist(foobar17) >= 2 with python3.9dist(foobar17) < 3) + python3.9dist(foobar18) = 2.4.8~b5 + python3.9dist(foobar19) = 2~b5 + (python3.9dist(foobar2) >= 2.4.8.1 with python3.9dist(foobar2) < 2.4.9) + python3.9dist(foobar20) = 2.4.8^post1 + python3.9dist(foobar21) = 2^post1 + python3.9dist(foobar22) = 2.4.8 + python3.9dist(foobar23) = 2.4.8 + python3.9dist(foobar24) = 2.4.8.1 + python3.9dist(foobar26) = 2 + python3.9dist(foobar27) = 2 + python3.9dist(foobar29) = 2.4.8~b5 + python3.9dist(foobar30) = 2~b5 + python3.9dist(foobar31) = 2.4.8^post1 + python3.9dist(foobar32) = 2^post1 + (python3.9dist(foobar33) < 2.4.8 or python3.9dist(foobar33) > 2.4.8) + (python3.9dist(foobar34) < 2.4.8 or python3.9dist(foobar34) > 2.4.8) + (python3.9dist(foobar35) < 2.4.8.1 or python3.9dist(foobar35) > 2.4.8.1) + (python3.9dist(foobar36) < 2.4.8 or python3.9dist(foobar36) > 2.4.9) + (python3.9dist(foobar37) < 2 or python3.9dist(foobar37) > 2) + (python3.9dist(foobar38) < 2 or python3.9dist(foobar38) > 2) + (python3.9dist(foobar39) < 2 or python3.9dist(foobar39) > 3) + (python3.9dist(foobar4) >= 2 with python3.9dist(foobar4) < 3) + (python3.9dist(foobar40) < 2.4.8~b5 or python3.9dist(foobar40) > 2.4.8~b5) + (python3.9dist(foobar41) < 2~b5 or python3.9dist(foobar41) > 2~b5) + (python3.9dist(foobar42) < 2.4.8^post1 or python3.9dist(foobar42) > 2.4.8^post1) + (python3.9dist(foobar43) < 2^post1 or python3.9dist(foobar43) > 2^post1) + python3.9dist(foobar44) <= 2.4.8 + python3.9dist(foobar45) <= 2.4.8 + python3.9dist(foobar46) <= 2.4.8.1 + python3.9dist(foobar47) < 2.4.8 + python3.9dist(foobar48) <= 2 + python3.9dist(foobar49) <= 2 + python3.9dist(foobar50) < 2 + python3.9dist(foobar51) <= 2.4.8~b5 + python3.9dist(foobar52) <= 2~b5 + python3.9dist(foobar53) <= 2.4.8^post1 + python3.9dist(foobar54) <= 2^post1 + python3.9dist(foobar55) < 2.4.8 + python3.9dist(foobar56) < 2.4.8 + python3.9dist(foobar57) < 2.4.8.1 + python3.9dist(foobar58) < 2.4.8 + python3.9dist(foobar59) < 2 + python3.9dist(foobar60) < 2 + python3.9dist(foobar61) < 2 + python3.9dist(foobar62) < 2.4.8~b5 + python3.9dist(foobar63) < 2~b5 + python3.9dist(foobar64) < 2.4.8^post1 + python3.9dist(foobar65) < 2^post1 + python3.9dist(foobar66) >= 2.4.8 + python3.9dist(foobar67) >= 2.4.8 + python3.9dist(foobar68) >= 2.4.8.1 + python3.9dist(foobar69) >= 2.4.8 + (python3.9dist(foobar7) >= 2.4.8~b5 with python3.9dist(foobar7) < 2.5) + python3.9dist(foobar70) >= 2 + python3.9dist(foobar71) >= 2 + python3.9dist(foobar72) >= 2 + python3.9dist(foobar73) >= 2.4.8~b5 + python3.9dist(foobar74) >= 2~b5 + python3.9dist(foobar75) >= 2.4.8^post1 + python3.9dist(foobar76) >= 2^post1 + python3.9dist(foobar77) > 2.4.8 + python3.9dist(foobar78) > 2.4.8 + python3.9dist(foobar79) > 2.4.8.1 + (python3.9dist(foobar8) >= 2~b5 with python3.9dist(foobar8) < 2.1) + python3.9dist(foobar80) >= 2.4.8 + python3.9dist(foobar81) > 2 + python3.9dist(foobar82) > 2 + python3.9dist(foobar83) >= 2 + python3.9dist(foobar84) > 2.4.8~b5 + python3.9dist(foobar85) > 2~b5 + python3.9dist(foobar86) > 2.4.8^post1 + python3.9dist(foobar87) > 2^post1 + (python3.9dist(foobar9) >= 2.4.8^post1 with python3.9dist(foobar9) < 2.5) + python3.9dist(hugo1) = 1~~dev7 + python3.9dist(hugo2) <= 8~a4 + (python3.9dist(hugo3) < 11.1.1~b14 or python3.9dist(hugo3) > 11.1.1~b14) + python3.9dist(hugo4) > 11~rc0 + python3.9dist(hugo5) = 11.1^post3 + python3.9dist(pyparsing0) + ((python3.9dist(pyparsing1) < 2.0.4 or python3.9dist(pyparsing1) > 2.0.4) with (python3.9dist(pyparsing1) < 2.1.2 or python3.9dist(pyparsing1) > 2.1.2) with (python3.9dist(pyparsing1) < 2.1.6 or python3.9dist(pyparsing1) > 2.1.6) with python3.9dist(pyparsing1) >= 2.0.1) + python3.9dist(test-multiple-underscores) = 1 + python3.9dist(test-underscores) = 1 --requires --normalized-names-format pep503 --require-extras-subpackages --package-name python3-zope-component+missing: --provides --majorver-provides --normalized-names-format pep503 --package-name python3-zope-component+missing: usr/lib/python3.9/site-packages/zope.component-4.3.0-py3.9.egg-info: From b44c80835888f29962c70ad5665f4b1427cdf1d4 Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Wed, 10 Mar 2021 19:51:55 +0100 Subject: [PATCH 064/110] pythondistdeps.py: Compare extras as lowercase - New test sources tarball with added test data --- .gitignore | 1 + pythondistdeps.py | 20 +++++++++++ sources | 2 +- .../scripts_pythondistdeps/test-data.yaml | 34 +++++++++++++++++++ .../scripts_pythondistdeps/test-requires.yaml | 5 +++ update-test-sources.sh | 1 + 6 files changed, 62 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 71b8b4c..e525b8a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /test-sources-2020-04-29.tar.gz /tests/__pycache__/ /tests/data/scripts_pythondistdeps/usr/ +/test-sources-2021-03-11.tar.gz diff --git a/pythondistdeps.py b/pythondistdeps.py index 9ba0590..b097228 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -21,6 +21,26 @@ from warnings import warn from packaging.requirements import Requirement as Requirement_ from packaging.version import parse +import packaging.markers + +# Monkey patching packaging.markers to handle extras names in a +# case-insensitive manner: +# pip considers dnspython[DNSSEC] and dnspython[dnssec] to be equal, but +# packaging markers treat extras in a case-sensitive manner. To solve this +# issue, we introduce a comparison operator that compares case-insensitively +# if both sides of the comparison are strings. And then we inject this +# operator into packaging.markers to be used when comparing names of extras. +# Fedora BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1936875 +# Upstream issue: https://discuss.python.org/t/what-extras-names-are-treated-as-equal-and-why/7614 +# - After it's established upstream what is the canonical form of an extras +# name, we plan to open an issue with packaging to hopefully solve this +# there without having to resort to monkeypatching. +def str_lower_eq(a, b): + if isinstance(a, str) and isinstance(b, str): + return a.lower() == b.lower() + else: + return a == b +packaging.markers._operators["=="] = str_lower_eq try: from importlib.metadata import PathDistribution diff --git a/sources b/sources index 1d7f97a..d8fedb8 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (test-sources-2020-04-29.tar.gz) = a5539fbe05a4f7128b4f82e960c3f1392a55ad53086dfd7fbc436d2743feaf64784e08667237baed3a32f149db25bc63e4ab3efc2b0270f969c59550b75102b1 +SHA512 (test-sources-2021-03-11.tar.gz) = 6f34c8151625be489a6a4d56d1fd3d39b7908bd31402c9703cb65918385320dfad35f35a32920c816fb85a829f44aaf04dc1d0654ccf512e26e87e95dbf87430 diff --git a/tests/data/scripts_pythondistdeps/test-data.yaml b/tests/data/scripts_pythondistdeps/test-data.yaml index 4a611c3..6dc4612 100644 --- a/tests/data/scripts_pythondistdeps/test-data.yaml +++ b/tests/data/scripts_pythondistdeps/test-data.yaml @@ -1118,6 +1118,40 @@ python3dist(backports-range) = 3.7.2 python3dist(backports.range) = 3.7.2 requires: python(abi) = 3.7 +--requires --normalized-names-format pep503 --package-name python3-dns+DNSSEC: + --provides --majorver-provides --normalized-names-format pep503 --package-name python3-dns+DNSSEC: + usr/lib/python3.9/site-packages/dnspython-2.1.0-py3.9.egg-info: + provides: |- + python3.9dist(dnspython[dnssec]) = 2.1 + python3dist(dnspython[dnssec]) = 2.1 + requires: |- + python(abi) = 3.9 + python3.9dist(cryptography) >= 2.6 +--requires --normalized-names-format pep503 --package-name python3-dns+Dnssec: + --provides --majorver-provides --normalized-names-format pep503 --package-name python3-dns+Dnssec: + usr/lib/python3.9/site-packages/dnspython-2.1.0-py3.9.egg-info: + provides: |- + python3.9dist(dnspython[dnssec]) = 2.1 + python3dist(dnspython[dnssec]) = 2.1 + requires: |- + python(abi) = 3.9 + python3.9dist(cryptography) >= 2.6 +--requires --normalized-names-format pep503 --package-name python3-dns+dnssec: + --provides --majorver-provides --normalized-names-format pep503 --package-name python3-dns+dnssec: + usr/lib/python3.9/site-packages/dnspython-2.1.0-py3.9.egg-info: + provides: |- + python3.9dist(dnspython[dnssec]) = 2.1 + python3dist(dnspython[dnssec]) = 2.1 + requires: |- + python(abi) = 3.9 + python3.9dist(cryptography) >= 2.6 + usr/lib/python3.9/site-packages/dnspython-2.1.0.dist-info: + provides: |- + python3.9dist(dnspython[dnssec]) = 2.1 + python3dist(dnspython[dnssec]) = 2.1 + requires: |- + python(abi) = 3.9 + python3.9dist(cryptography) >= 2.6 --requires --normalized-names-format pep503 --package-name python3-setuptools+certs: --provides --majorver-provides --normalized-names-format pep503 --package-name python3-setuptools+certs: usr/lib/python3.9/site-packages/setuptools-41.6.0.dist-info: diff --git a/tests/data/scripts_pythondistdeps/test-requires.yaml b/tests/data/scripts_pythondistdeps/test-requires.yaml index c06d6c0..32d70f2 100644 --- a/tests/data/scripts_pythondistdeps/test-requires.yaml +++ b/tests/data/scripts_pythondistdeps/test-requires.yaml @@ -95,3 +95,8 @@ fsleyes: taskotron-python-versions: wheel: '0.1.dev6': ['3.9'] +dnspython: + sdist: + '2.1.0': ['3.9'] + wheel: + '2.1.0': ['3.9'] diff --git a/update-test-sources.sh b/update-test-sources.sh index b7fa68b..4d7963e 100755 --- a/update-test-sources.sh +++ b/update-test-sources.sh @@ -3,6 +3,7 @@ # # Requirements: # - pip >= 20.0.1 +# - poetry # Due to bug: https://github.com/pypa/pip/issues/9701 # # First prune old test data From 3a4efade985c95915cff2c95e7330fa2d573201c Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Thu, 11 Mar 2021 12:43:37 +0100 Subject: [PATCH 065/110] pythondistdeps.py: Always output extras names in lowercase --- python-rpm-generators.spec | 6 +++++- pythondistdeps.py | 6 +++--- .../requires.txt | 2 ++ tests/data/scripts_pythondistdeps/test-data.yaml | 8 +++++--- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 7550178..24994bf 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 12 -Release: 3%{?dist} +Release: 4%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -47,6 +47,10 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Thu Mar 11 2021 Tomas Orsava - 12-4 +- scripts/pythondistdeps: Treat extras names case-insensitively and always + output them in lower case (#1936875) + * Mon Feb 22 2021 Tomas Orsava - 12-3 - scripts/pythondistdeps: Fix for Python 3.10 diff --git a/pythondistdeps.py b/pythondistdeps.py index b097228..f38f726 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -77,7 +77,7 @@ class Distribution(PathDistribution): self.legacy_normalized_name = legacy_normalize_name(self.name) self.requirements = [Requirement(r) for r in self.requires or []] self.extras = [ - v for k, v in self.metadata.items() if k == 'Provides-Extra'] + v.lower() for k, v in self.metadata.items() if k == 'Provides-Extra'] self.py_version = self._parse_py_version(path) # `name` is defined as a property exactly like this in Python 3.10 in the @@ -316,7 +316,7 @@ if __name__ == "__main__": # and pluses in the middle can be easily replaced with dashes. # Python extras names don't contain pluses according to PEP 508. package_name_parts = args.package_name.rpartition('+') - extras_subpackage = package_name_parts[2] or None + extras_subpackage = package_name_parts[2].lower() or None for f in (args.files or stdin.readlines()): f = f.strip() @@ -456,7 +456,7 @@ if __name__ == "__main__": if args.require_extras_subpackages and dep.extras: # A dependency can have more than one extras, # i.e. foo[bar,baz], so let's go through all of them - extras_suffixes += [f"[{e}]" for e in dep.extras] + extras_suffixes += [f"[{e.lower()}]" for e in dep.extras] for extras_suffix in extras_suffixes: if normalized_names_require_pep503: diff --git a/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/requires.txt b/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/requires.txt index 1436266..338afcc 100644 --- a/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/requires.txt +++ b/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/requires.txt @@ -100,3 +100,5 @@ hugo5===11.1.0.post3 test___multiple__underscores==1 test_underscores==1 + +dnspython[DNSSEC] diff --git a/tests/data/scripts_pythondistdeps/test-data.yaml b/tests/data/scripts_pythondistdeps/test-data.yaml index 6dc4612..35c72a8 100644 --- a/tests/data/scripts_pythondistdeps/test-data.yaml +++ b/tests/data/scripts_pythondistdeps/test-data.yaml @@ -1193,13 +1193,15 @@ python3.9dist(coverage) python3.9dist(nose) python3.9dist(zope-testing) ---requires: - --provides: +--requires --normalized-names-format pep503 --require-extras-subpackages: + --provides --normalized-names-format pep503: pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info: - provides: python3.9dist(pyreq2rpm.tests) = 2020.04.07.024dab0 + provides: python3.9dist(pyreq2rpm-tests) = 2020.04.07.024dab0 requires: |- python(abi) = 3.9 ((python3.9dist(babel) < 2 or python3.9dist(babel) > 2) with python3.9dist(babel) >= 1.3) + python3.9dist(dnspython) + python3.9dist(dnspython[dnssec]) python3.9dist(fedora-python-nb2plots) = 0 (python3.9dist(foobar0) >= 2.4.8 with python3.9dist(foobar0) < 2.5) (python3.9dist(foobar1) >= 2.4.8 with python3.9dist(foobar1) < 2.4.9) From a295a5855988a761a2adf2e87a06c01fbcc6439b Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Thu, 11 Mar 2021 12:46:05 +0100 Subject: [PATCH 066/110] Add __pycache__ into .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index e525b8a..78062d7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /test-sources-2020-04-29.tar.gz +/__pycache__/ /tests/__pycache__/ /tests/data/scripts_pythondistdeps/usr/ /test-sources-2021-03-11.tar.gz From 0a12aa5a2f1cb1a1003e5098108a6c5aa2040ce7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Mon, 15 Mar 2021 18:59:40 +0100 Subject: [PATCH 067/110] Do not generate setuptools requirement for console_scripts on Python 3.10+ See https://fedoraproject.org/wiki/Changes/Reduce_dependencies_on_python3-setuptools --- python-rpm-generators.spec | 6 +++- pythondist.attr | 2 +- pythondistdeps.py | 35 +++++++++++++----- tests/console_script.sh | 17 +++++++++ .../scripts_pythondistdeps/test-data.yaml | 24 +++++++++---- .../scripts_pythondistdeps/test-requires.yaml | 2 +- tests/isort.spec | 36 +++++++++++++++++++ tests/tests.yml | 3 ++ 8 files changed, 107 insertions(+), 18 deletions(-) create mode 100755 tests/console_script.sh create mode 100644 tests/isort.spec diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 24994bf..16a48b8 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 12 -Release: 4%{?dist} +Release: 5%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -47,6 +47,10 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Wed Mar 31 2021 Miro Hrončok - 12-5 +- Do not generate setuptools requirement for console_scripts on Python 3.10+ +- See https://fedoraproject.org/wiki/Changes/Reduce_dependencies_on_python3-setuptools + * Thu Mar 11 2021 Tomas Orsava - 12-4 - scripts/pythondistdeps: Treat extras names case-insensitively and always output them in lower case (#1936875) diff --git a/pythondist.attr b/pythondist.attr index f849ba1..747cc32 100644 --- a/pythondist.attr +++ b/pythondist.attr @@ -1,3 +1,3 @@ %__pythondist_provides %{_rpmconfigdir}/pythondistdeps.py --provides --normalized-names-format pep503 --package-name %{name} --normalized-names-provide-both --majorver-provides-versions %{__default_python3_version} -%__pythondist_requires %{_rpmconfigdir}/pythondistdeps.py --requires --normalized-names-format pep503 --package-name %{name} %{?!_python_no_extras_requires:--require-extras-subpackages} +%__pythondist_requires %{_rpmconfigdir}/pythondistdeps.py --requires --normalized-names-format pep503 --package-name %{name} %{?!_python_no_extras_requires:--require-extras-subpackages} --console-scripts-nodep-setuptools-since 3.10 %__pythondist_path ^/usr/lib(64)?/python[3-9]\\.[[:digit:]]+/site-packages/[^/]+\\.(dist-info|egg-info|egg-link)$ diff --git a/pythondistdeps.py b/pythondistdeps.py index f38f726..17f49f3 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -276,6 +276,12 @@ if __name__ == "__main__": help='Provide both `pep503` and `legacy-dots` format of normalized names (useful for a transition period)') parser.add_argument('-L', '--legacy-provides', action='store_true', help='Print extra legacy pythonegg Provides') parser.add_argument('-l', '--legacy', action='store_true', help='Print legacy pythonegg Provides/Requires instead') + parser.add_argument('--console-scripts-nodep-setuptools-since', action='store', + help='An optional Python version (X.Y), at least 3.8. ' + 'For that version and any newer version, ' + 'a dependency on "setuptools" WILL NOT be generated for packages with console_scripts/gui_scripts entry points. ' + 'By setting this flag, you guarantee that setuptools >= 47.2.0 is used ' + 'during the build of packages for this and any newer Python version.') parser.add_argument('--require-extras-subpackages', action='store_true', help="If there is a dependency on a package with extras functionality, require the extras subpackage") parser.add_argument('--package-name', action='store', help="Name of the RPM package that's being inspected. Required for extras requires/provides to work.") @@ -305,6 +311,15 @@ if __name__ == "__main__": # At least one type of normalization must be provided assert normalized_names_provide_pep503 or normalized_names_provide_legacy + if args.console_scripts_nodep_setuptools_since: + nodep_setuptools_pyversion = parse(args.console_scripts_nodep_setuptools_since) + if nodep_setuptools_pyversion < parse("3.8"): + print("Only version 3.8+ is supported in --console-scripts-nodep-setuptools-since", file=stderr) + print("*** PYTHON_EXTRAS_ARGUMENT_ERROR___SEE_STDERR ***") + exit(65) # os.EX_DATAERR + else: + nodep_setuptools_pyversion = None + # Is this script being run for an extras subpackage? extras_subpackage = None if args.package_name and '+' in args.package_name: @@ -438,15 +453,17 @@ if __name__ == "__main__": else: deps = dist.requirements - # console_scripts/gui_scripts entry points need pkg_resources from setuptools - if (dist.entry_points and - (lower.endswith('.egg') or - lower.endswith('.egg-info'))): - groups = {ep.group for ep in dist.entry_points} - if {"console_scripts", "gui_scripts"} & groups: - # stick them first so any more specific requirement - # overrides it - deps.insert(0, Requirement('setuptools')) + # console_scripts/gui_scripts entry points needed pkg_resources from setuptools + # on new Python/setuptools versions, this is no longer required + if nodep_setuptools_pyversion is None or parse(dist.py_version) < nodep_setuptools_pyversion: + if (dist.entry_points and + (lower.endswith('.egg') or + lower.endswith('.egg-info'))): + groups = {ep.group for ep in dist.entry_points} + if {"console_scripts", "gui_scripts"} & groups: + # stick them first so any more specific requirement + # overrides it + deps.insert(0, Requirement('setuptools')) # add requires/recommends based on egg/dist metadata for dep in deps: # Even if we're requiring `foo[bar]`, also require `foo` diff --git a/tests/console_script.sh b/tests/console_script.sh new file mode 100755 index 0000000..892fd4b --- /dev/null +++ b/tests/console_script.sh @@ -0,0 +1,17 @@ +#!/usr/bin/bash -eux +RPMDIR=$(rpm --eval '%_topdir')/RPMS/noarch +RPMPKG="${RPMDIR}/isort-5.7.0-0.noarch.rpm" + +mkdir -p $(rpm --eval '%_topdir')/SOURCES/ + +spectool -g -R isort.spec + +for py_version in 3.6 3.7 3.8 3.9; do + rpmbuild -ba --define "python3_test_version ${py_version}" isort.spec + rpm -qp --requires ${RPMPKG} | grep "python${py_version}dist(setuptools)" +done + +for py_version in 3.10 3.11; do + rpmbuild -ba --define "python3_test_version ${py_version}" isort.spec + rpm -qp --requires ${RPMPKG} | grep "python${py_version}dist(setuptools)" && exit 1 || true +done diff --git a/tests/data/scripts_pythondistdeps/test-data.yaml b/tests/data/scripts_pythondistdeps/test-data.yaml index 35c72a8..0a81eaa 100644 --- a/tests/data/scripts_pythondistdeps/test-data.yaml +++ b/tests/data/scripts_pythondistdeps/test-data.yaml @@ -762,7 +762,16 @@ python3.9dist(simplejson) = 3.16 python3dist(simplejson) = 3.16 requires: python(abi) = 3.9 ---requires --normalized-names-format legacy-dots: +--requires --console-scripts-nodep-setuptools-since 3.7: + --provides --console-scripts-nodep-setuptools-since 3.6: + usr/lib/python3.9/site-packages/zope.component-4.3.0-py3.9.egg-info: + stderr: + provides: Only version 3.8+ is supported in --console-scripts-nodep-setuptools-since + requires: Only version 3.8+ is supported in --console-scripts-nodep-setuptools-since + stdout: + provides: '*** PYTHON_EXTRAS_ARGUMENT_ERROR___SEE_STDERR ***' + requires: '*** PYTHON_EXTRAS_ARGUMENT_ERROR___SEE_STDERR ***' +--requires --normalized-names-format legacy-dots --console-scripts-nodep-setuptools-since 3.10: --provides --majorver-provides --normalized-names-format legacy-dots: usr/lib/python2.7/site-packages/zope.component-4.3.0-py2.7.egg-info: provides: |- @@ -800,16 +809,19 @@ provides: |- python3.10dist(setuptools) = 41.6 python3dist(setuptools) = 41.6 - requires: |- - python(abi) = 3.10 - python3.10dist(setuptools) + requires: python(abi) = 3.10 usr/lib/python3.11/site-packages/pip-20.0.2-py3.11.egg-info: provides: |- python3.11dist(pip) = 20.0.2 python3dist(pip) = 20.0.2 + requires: python(abi) = 3.11 + usr/lib/python3.8/site-packages/pip-20.0.2-py3.8.egg-info: + provides: |- + python3.8dist(pip) = 20.0.2 + python3dist(pip) = 20.0.2 requires: |- - python(abi) = 3.11 - python3.11dist(setuptools) + python(abi) = 3.8 + python3.8dist(setuptools) usr/lib/python3.9/site-packages/zope.component-4.3.0-py3.9.egg-info: provides: |- python3.9dist(zope.component) = 4.3 diff --git a/tests/data/scripts_pythondistdeps/test-requires.yaml b/tests/data/scripts_pythondistdeps/test-requires.yaml index 32d70f2..d876674 100644 --- a/tests/data/scripts_pythondistdeps/test-requires.yaml +++ b/tests/data/scripts_pythondistdeps/test-requires.yaml @@ -8,7 +8,7 @@ pip: '19.1.1': ['2.7', '3.7'] '20.0.2': ['3.9'] sdist: - '20.0.2': ['3.11'] + '20.0.2': ['3.8', '3.11'] packaging: wheel: '19.0': ['2.7', '3.7'] diff --git a/tests/isort.spec b/tests/isort.spec new file mode 100644 index 0000000..74514d4 --- /dev/null +++ b/tests/isort.spec @@ -0,0 +1,36 @@ +Name: isort +Version: 5.7.0 +Release: 0 +Summary: A Python package with a console_scripts entrypoint +License: MIT +Source0: %{pypi_source} +BuildArch: noarch +BuildRequires: python3-devel +BuildRequires: python3-setuptools + +# Turn off Python bytecode compilation because the build would fail without Python %%{python3_test_version} +%define __brp_python_bytecompile %{nil} + +%description +... + +%prep +%autosetup + +%build +%py3_build + +%install +%py3_install + +# A fake installation by a different Python version: +%if "%{python3_version}" != "%{python3_test_version}" +mv %{buildroot}%{_prefix}/lib/python%{python3_version} \ + %{buildroot}%{_prefix}/lib/python%{python3_test_version} +mv %{buildroot}%{_prefix}/lib/python%{python3_test_version}/site-packages/%{name}-%{version}-py%{python3_version}.egg-info \ + %{buildroot}%{_prefix}/lib/python%{python3_test_version}/site-packages/%{name}-%{version}-py%{python3_test_version}.egg-info +%endif + +%files +%{_bindir}/%{name}* +%{_prefix}/lib/python%{python3_test_version}/site-packages/%{name}* diff --git a/tests/tests.yml b/tests/tests.yml index a79a5f1..668ff36 100644 --- a/tests/tests.yml +++ b/tests/tests.yml @@ -27,6 +27,9 @@ - pythondist: dir: . run: ./pythondist.sh + - console_script: + dir: . + run: ./console_script.sh - prepare-test-data: dir: . run: tar -xvf test-sources-*.tar.gz -C ./tests/data/scripts_pythondistdeps/ From 20f8b2c7756e8086bda06227e9dcc8e2c755077b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Mon, 19 Apr 2021 22:56:25 +0200 Subject: [PATCH 068/110] Fix python(abi) generator (the one written in Python) There were three problems: - sys.version was not imported - sys.version[:3] is not reliable on Python 3.10+ - distutils is deprecated on Python 3.10+ We were not hit by the missing import in Fedora because we only run the script on .dist-info/.egg-info/.egg and not on .py files, so this if-branch never runs. But when the script was fed with a .py path, it errored: Traceback (most recent call last): File "/usr/lib/rpm/pythondistdeps.py", line 344, in purelib = get_python_lib(standard_lib=0, plat_specific=0).split(version[:3])[0] NameError: name 'version' is not defined The sys.version[:3] thing kinda works for Python 3.10+ because *in this particular case* splitting on '3.1' and taking the prefix yields the same results as splitting on '3.10', but I consider that mere coincidence. Finally, since the distutils import happened at module-level, we got the Deprecation warning in all Fedora's Python packages: /usr/lib/rpm/pythondistdeps.py:16: DeprecationWarning: The distutils package is deprecated and slated for removal in Python 3.12 Backported from https://github.com/rpm-software-management/python-rpm-packaging/commit/d12e039037 --- python-rpm-generators.spec | 7 ++++++- pythondistdeps.py | 9 +++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 16a48b8..072883b 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 12 -Release: 5%{?dist} +Release: 6%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -47,6 +47,11 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Mon Apr 19 2021 Miro Hrončok - 12-6 +- Get rid of distutils deprecation warning (by not using it) +- The distutils module is deprecated in Python 3.10+ +- https://www.python.org/dev/peps/pep-0632/ + * Wed Mar 31 2021 Miro Hrončok - 12-5 - Do not generate setuptools requirement for console_scripts on Python 3.10+ - See https://fedoraproject.org/wiki/Changes/Reduce_dependencies_on_python3-setuptools diff --git a/pythondistdeps.py b/pythondistdeps.py index 17f49f3..8be1a4d 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -13,10 +13,10 @@ from __future__ import print_function import argparse -from distutils.sysconfig import get_python_lib from os.path import dirname, sep import re -from sys import argv, stdin, stderr +from sys import argv, stdin, stderr, version_info +from sysconfig import get_path from warnings import warn from packaging.requirements import Requirement as Requirement_ @@ -341,8 +341,9 @@ if __name__ == "__main__": if py_abi and (lower.endswith('.py') or lower.endswith('.pyc') or lower.endswith('.pyo')): if name not in py_deps: py_deps[name] = [] - purelib = get_python_lib(standard_lib=0, plat_specific=0).split(version[:3])[0] - platlib = get_python_lib(standard_lib=0, plat_specific=1).split(version[:3])[0] + running_python_version = '{}.{}'.format(*version_info[:2]) + purelib = get_path('purelib').split(running_python_version)[0] + platlib = get_path('platlib').split(running_python_version)[0] for lib in (purelib, platlib): if lib in f: spec = ('==', f.split(lib)[1].split(sep)[0]) From 27d363833e8df0188df0cd6b9eb2bd79e61a2238 Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Tue, 25 May 2021 12:46:21 +0200 Subject: [PATCH 069/110] pythondistdeps.py: Detect and error when metadata is corrupted --- pythondistdeps.py | 8 ++++++++ .../corrupted.dist-info/corrupted | 1 + tests/data/scripts_pythondistdeps/test-data.yaml | 9 +++++++++ tests/test_scripts_pythondistdeps.py | 16 +++++++++++++++- 4 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 tests/data/scripts_pythondistdeps/corrupted.dist-info/corrupted diff --git a/pythondistdeps.py b/pythondistdeps.py index 8be1a4d..25ca6cb 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -73,6 +73,14 @@ class Requirement(Requirement_): class Distribution(PathDistribution): def __init__(self, path): super(Distribution, self).__init__(Path(path)) + + # Check that the initialization went well and metadata are not missing or corrupted + # name is the most important attribute, if it doesn't exist, import failed + if not self.name or not isinstance(self.name, str): + print("*** PYTHON_METADATA_FAILED_TO_PARSE_ERROR___SEE_STDERR ***") + print('Error: Python metadata at `{}` are missing or corrupted.'.format(path), file=stderr) + exit(65) # os.EX_DATAERR + self.normalized_name = normalize_name(self.name) self.legacy_normalized_name = legacy_normalize_name(self.name) self.requirements = [Requirement(r) for r in self.requires or []] diff --git a/tests/data/scripts_pythondistdeps/corrupted.dist-info/corrupted b/tests/data/scripts_pythondistdeps/corrupted.dist-info/corrupted new file mode 100644 index 0000000..b04b2ba --- /dev/null +++ b/tests/data/scripts_pythondistdeps/corrupted.dist-info/corrupted @@ -0,0 +1 @@ +Corrupted dist-info metadata diff --git a/tests/data/scripts_pythondistdeps/test-data.yaml b/tests/data/scripts_pythondistdeps/test-data.yaml index 0a81eaa..afd928e 100644 --- a/tests/data/scripts_pythondistdeps/test-data.yaml +++ b/tests/data/scripts_pythondistdeps/test-data.yaml @@ -1207,6 +1207,15 @@ python3.9dist(zope-testing) --requires --normalized-names-format pep503 --require-extras-subpackages: --provides --normalized-names-format pep503: + corrupted.dist-info: + stderr: + provides: |- + Error: Python metadata at `*/corrupted.dist-info` are missing or corrupted. + requires: |- + Error: Python metadata at `*/corrupted.dist-info` are missing or corrupted. + stdout: + provides: '*** PYTHON_METADATA_FAILED_TO_PARSE_ERROR___SEE_STDERR ***' + requires: '*** PYTHON_METADATA_FAILED_TO_PARSE_ERROR___SEE_STDERR ***' pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info: provides: python3.9dist(pyreq2rpm-tests) = 2020.04.07.024dab0 requires: |- diff --git a/tests/test_scripts_pythondistdeps.py b/tests/test_scripts_pythondistdeps.py index 3636f1c..79f0c6f 100644 --- a/tests/test_scripts_pythondistdeps.py +++ b/tests/test_scripts_pythondistdeps.py @@ -29,6 +29,7 @@ from pathlib import Path +from fnmatch import fnmatch import pytest import shlex import shutil @@ -224,8 +225,21 @@ def fixture_check_and_install_test_data(): def test_pythondistdeps(provides_params, requires_params, dist_egg_info_path, expected): """Runs pythondistdeps with the given parameters and dist-info/egg-info path, compares the results with the expected results""" + expect_failure = "stderr" in expected - assert expected == run_pythondistdeps(provides_params, requires_params, dist_egg_info_path, expect_failure) + tested = run_pythondistdeps(provides_params, requires_params, dist_egg_info_path, expect_failure) + + if expect_failure: + for k1, k2 in ((k1, k2) for k1 in expected.keys() for k2 in expected[k1].keys()): + if k1 == "stderr": + # Some stderr messages contain full file paths. To get around + # this, asterisk is used in the test-data and we compare with + # fnmatch that understands Unix-style wildcards. + assert fnmatch(tested[k1][k2], expected[k1][k2]) + else: + assert expected[k1][k2] == tested[k1][k2] + else: + assert expected == tested if __name__ == "__main__": From cc489bde7a3a06354aa4e5c1dad3e3f9dbdb6564 Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Tue, 25 May 2021 17:56:00 +0200 Subject: [PATCH 070/110] pythondistdeps.py: Catch all exceptions and terminate build if one is raised --- python-rpm-generators.spec | 6 +++++- pythondistdeps.py | 17 ++++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 072883b..6011515 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 12 -Release: 6%{?dist} +Release: 7%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -47,6 +47,10 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Tue May 25 2021 Tomas Orsava - 12-7 +- pythondistdeps.py: Detect missing or corrupted metadata +- pythondistdeps.py: Catch all exceptions and terminate the build if one is raised + * Mon Apr 19 2021 Miro Hrončok - 12-6 - Get rid of distutils deprecation warning (by not using it) - The distutils module is deprecated in Python 3.10+ diff --git a/pythondistdeps.py b/pythondistdeps.py index 25ca6cb..e8b5afd 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -260,10 +260,10 @@ def get_marker_env(dist, extra): "extra": extra} -if __name__ == "__main__": +def main(): """To allow this script to be importable (and its classes/functions - reused), actions are performed only when run as a main script.""" - + reused), actions are defined in the main function and are performed only + when run as a main script.""" parser = argparse.ArgumentParser(prog=argv[0]) group = parser.add_mutually_exclusive_group(required=True) group.add_argument('-P', '--provides', action='store_true', help='Print Provides') @@ -552,3 +552,14 @@ if __name__ == "__main__": else: # Print out unversioned provides, requires, recommends, conflicts print(name) + + +if __name__ == "__main__": + """To allow this script to be importable (and its classes/functions + reused), actions are performed only when run as a main script.""" + try: + main() + except Exception as exc: + print("*** PYTHONDISTDEPS_GENERATORS_FAILED ***", flush=True) + raise RuntimeError("Error: pythondistdeps.py generator encountered an unhandled exception and was terminated.") from exc + From 04ae9b96f2acb7c7c5adbaf4aca7a27745c45d20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Fri, 18 Jun 2021 18:49:37 +0200 Subject: [PATCH 071/110] CI: Adapt pythondist.spec for Python 3.10 being the main Python version Preserves comaptbility with Python 3.9. --- tests/pythondist.sh | 11 +++++++++++ tests/pythondist.spec | 25 +++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/tests/pythondist.sh b/tests/pythondist.sh index 556f5e8..4f2e15d 100755 --- a/tests/pythondist.sh +++ b/tests/pythondist.sh @@ -25,7 +25,17 @@ rpm -qp --provides ${RPMDIR}/python3.7-zope-component-4.3.0-0.noarch.rpm | grep rpm -qp --requires ${RPMDIR}/python3.7-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.7dist(zope-event)' rpm -qp --requires ${RPMDIR}/python3.7-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.7dist(zope-interface)' +if [ "$X_Y" != "3.9" ]; then +rpm -qp --provides ${RPMDIR}/python3.9-zope-component-4.3.0-0.noarch.rpm | grep '^python3dist(zope\.component)' && exit 1 || true +rpm -qp --provides ${RPMDIR}/python3.9-zope-component-4.3.0-0.noarch.rpm | grep '^python3dist(zope-component)' && exit 1 || true +rpm -qp --provides ${RPMDIR}/python3.9-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.9dist(zope\.component)' +rpm -qp --provides ${RPMDIR}/python3.9-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.9dist(zope-component)' +rpm -qp --requires ${RPMDIR}/python3.9-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.9dist(zope-event)' +rpm -qp --requires ${RPMDIR}/python3.9-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.9dist(zope-interface)' +fi + +if [ "$X_Y" != "3.10" ]; then rpm -qp --provides ${RPMDIR}/python3.10-zope-component-4.3.0-0.noarch.rpm | grep '^python3dist(zope\.component)' && exit 1 || true rpm -qp --provides ${RPMDIR}/python3.10-zope-component-4.3.0-0.noarch.rpm | grep '^python3dist(zope-component)' && exit 1 || true rpm -qp --provides ${RPMDIR}/python3.10-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.10dist(zope\.component)' @@ -33,3 +43,4 @@ rpm -qp --provides ${RPMDIR}/python3.10-zope-component-4.3.0-0.noarch.rpm | grep rpm -qp --requires ${RPMDIR}/python3.10-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.10dist(zope-event)' rpm -qp --requires ${RPMDIR}/python3.10-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.10dist(zope-interface)' +fi diff --git a/tests/pythondist.spec b/tests/pythondist.spec index 672e04a..960c716 100644 --- a/tests/pythondist.spec +++ b/tests/pythondist.spec @@ -24,10 +24,19 @@ Summary: ... %description -n python3.7-zope-component ... +%if v"%{python3_version}" != v"3.9" +%package -n python3.9-zope-component +Summary: ... +%description -n python3.9-zope-component +... +%endif + +%if v"%{python3_version}" != v"3.10" %package -n python3.10-zope-component Summary: ... %description -n python3.10-zope-component ... +%endif %prep %autosetup -n zope.component-%{version} @@ -42,9 +51,17 @@ mkdir -p %{buildroot}/usr/lib/python3.7/site-packages cp -a %{buildroot}%{python3_sitelib}/zope.component-%{version}-py%{python3_version}.egg-info \ %{buildroot}/usr/lib/python3.7/site-packages/zope.component-%{version}-py3.7.egg-info +%if v"%{python3_version}" != v"3.9" +mkdir -p %{buildroot}/usr/lib/python3.9/site-packages +cp -a %{buildroot}%{python3_sitelib}/zope.component-%{version}-py%{python3_version}.egg-info \ + %{buildroot}/usr/lib/python3.9/site-packages/zope.component-%{version}-py3.9.egg-info +%endif + +%if v"%{python3_version}" != v"3.10" mkdir -p %{buildroot}/usr/lib/python3.10/site-packages cp -a %{buildroot}%{python3_sitelib}/zope.component-%{version}-py%{python3_version}.egg-info \ %{buildroot}/usr/lib/python3.10/site-packages/zope.component-%{version}-py3.10.egg-info +%endif %files -n python3-zope-component %license LICENSE.txt @@ -54,6 +71,14 @@ cp -a %{buildroot}%{python3_sitelib}/zope.component-%{version}-py%{python3_versi %license LICENSE.txt /usr/lib/python3.7/site-packages/zope.component-%{version}-py3.7.egg-info/ +%if v"%{python3_version}" != v"3.9" +%files -n python3.9-zope-component +%license LICENSE.txt +/usr/lib/python3.9/site-packages/zope.component-%{version}-py3.9.egg-info/ +%endif + +%if v"%{python3_version}" != v"3.10" %files -n python3.10-zope-component %license LICENSE.txt /usr/lib/python3.10/site-packages/zope.component-%{version}-py3.10.egg-info/ +%endif From 9bd2a43a74fda68e75b85b26b6e71e51226c752f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Mon, 21 Jun 2021 11:35:48 +0200 Subject: [PATCH 072/110] Support multiple vendor files in pythonbundles.py Not bumping the release, will happily wait until it bubbles trough. --- pythonbundles.py | 41 ++++++++++--------- .../pkg_resources_setuptools.out | 5 +++ .../data/scripts_pythonbundles/setuptools.in | 3 ++ .../data/scripts_pythonbundles/setuptools.out | 3 ++ tests/test_scripts_pythonbundles.py | 22 +++++++++- 5 files changed, 53 insertions(+), 21 deletions(-) create mode 100644 tests/data/scripts_pythonbundles/pkg_resources_setuptools.out create mode 100644 tests/data/scripts_pythonbundles/setuptools.in create mode 100644 tests/data/scripts_pythonbundles/setuptools.out diff --git a/pythonbundles.py b/pythonbundles.py index 96e817e..6242e20 100755 --- a/pythonbundles.py +++ b/pythonbundles.py @@ -22,26 +22,27 @@ import pythondistdeps pythondistdeps.parse_version = parse_version -def generate_bundled_provides(path, namespace): +def generate_bundled_provides(paths, namespace): provides = set() - for line in path.read_text().splitlines(): - line, _, comment = line.partition('#') - if comment.startswith('egg='): - # not a real comment - # e.g. git+https://github.com/monty/spam.git@master#egg=spam&... - egg, *_ = comment.strip().partition(' ') - egg, *_ = egg.strip().partition('&') - name = pythondistdeps.normalize_name(egg[4:]) - provides.add(f'Provides: bundled({namespace}({name}))') - continue - line = line.strip() - if line: - name, _, version = line.partition('==') - name = pythondistdeps.normalize_name(name) - bundled_name = f"bundled({namespace}({name}))" - python_provide = pythondistdeps.convert(bundled_name, '==', version) - provides.add(f'Provides: {python_provide}') + for path in paths: + for line in path.read_text().splitlines(): + line, _, comment = line.partition('#') + if comment.startswith('egg='): + # not a real comment + # e.g. git+https://github.com/monty/spam.git@master#egg=spam&... + egg, *_ = comment.strip().partition(' ') + egg, *_ = egg.strip().partition('&') + name = pythondistdeps.normalize_name(egg[4:]) + provides.add(f'Provides: bundled({namespace}({name}))') + continue + line = line.strip() + if line: + name, _, version = line.partition('==') + name = pythondistdeps.normalize_name(name) + bundled_name = f"bundled({namespace}({name}))" + python_provide = pythondistdeps.convert(bundled_name, '==', version) + provides.add(f'Provides: {python_provide}') return provides @@ -70,7 +71,7 @@ if __name__ == '__main__': parser = argparse.ArgumentParser(prog=sys.argv[0], formatter_class=argparse.ArgumentDefaultsHelpFormatter) - parser.add_argument('vendored', metavar='VENDORED.TXT', + parser.add_argument('vendored', metavar='VENDORED.TXT', nargs='+', type=pathlib.Path, help='Upstream information about vendored libraries') parser.add_argument('-c', '--compare-with', action='store', help='A string value to compare with and verify') @@ -78,7 +79,7 @@ if __name__ == '__main__': help='What namespace of provides will used', default='python3dist') args = parser.parse_args() - provides = generate_bundled_provides(pathlib.Path(args.vendored), args.namespace) + provides = generate_bundled_provides(args.vendored, args.namespace) if args.compare_with: given = args.compare_with.splitlines() diff --git a/tests/data/scripts_pythonbundles/pkg_resources_setuptools.out b/tests/data/scripts_pythonbundles/pkg_resources_setuptools.out new file mode 100644 index 0000000..cc2d710 --- /dev/null +++ b/tests/data/scripts_pythonbundles/pkg_resources_setuptools.out @@ -0,0 +1,5 @@ +Provides: bundled(python3dist(appdirs)) = 1.4.3 +Provides: bundled(python3dist(ordered-set)) = 3.1.1 +Provides: bundled(python3dist(packaging)) = 16.8 +Provides: bundled(python3dist(pyparsing)) = 2.2.1 +Provides: bundled(python3dist(six)) = 1.10 diff --git a/tests/data/scripts_pythonbundles/setuptools.in b/tests/data/scripts_pythonbundles/setuptools.in new file mode 100644 index 0000000..d7d2beb --- /dev/null +++ b/tests/data/scripts_pythonbundles/setuptools.in @@ -0,0 +1,3 @@ +packaging==16.8 +pyparsing==2.2.1 +ordered-set==3.1.1 diff --git a/tests/data/scripts_pythonbundles/setuptools.out b/tests/data/scripts_pythonbundles/setuptools.out new file mode 100644 index 0000000..0acb887 --- /dev/null +++ b/tests/data/scripts_pythonbundles/setuptools.out @@ -0,0 +1,3 @@ +Provides: bundled(python3dist(ordered-set)) = 3.1.1 +Provides: bundled(python3dist(packaging)) = 16.8 +Provides: bundled(python3dist(pyparsing)) = 2.2.1 diff --git a/tests/test_scripts_pythonbundles.py b/tests/test_scripts_pythonbundles.py index c04230e..2926713 100644 --- a/tests/test_scripts_pythonbundles.py +++ b/tests/test_scripts_pythonbundles.py @@ -34,7 +34,7 @@ def run_pythonbundles(*args, success=True): return cp -projects = pytest.mark.parametrize('project', ('pkg_resources', 'pip', 'pipenv')) +projects = pytest.mark.parametrize('project', ('pkg_resources', 'pip', 'pipenv', 'setuptools')) @projects @@ -97,3 +97,23 @@ def test_compare_with_unexpected(project): cp = run_pythonbundles(TEST_DATA / f'{project}.in', '--compare-with', longer, success=False) assert cp.stdout == '', cp.stdout assert cp.stderr == f'Redundant unexpected provides:\n + {unexpected}\n', cp.stderr + + +combo_order = pytest.mark.parametrize('projects', ['pkg_resources-setuptools', 'setuptools-pkg_resources']) + + +@combo_order +def test_multiple_vendor_files_output(projects): + cp = run_pythonbundles(*(TEST_DATA / f'{p}.in' for p in projects.split('-'))) + expected = (TEST_DATA / 'pkg_resources_setuptools.out').read_text() + assert cp.stdout == expected, cp.stdout + assert cp.stderr == '', cp.stderr + + +@combo_order +def test_multiple_vendor_files_compare_with(projects): + expected = (TEST_DATA / 'pkg_resources_setuptools.out').read_text() + cp = run_pythonbundles(*(TEST_DATA / f'{p}.in' for p in projects.split('-')), + '--compare-with', expected) + assert cp.stdout == '', cp.stdout + assert cp.stderr == '', cp.stderr From 98fa009fc8f530b097d79e47bf1605774a6e9139 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Fri, 23 Jul 2021 09:18:27 +0000 Subject: [PATCH 073/110] - Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild Signed-off-by: Fedora Release Engineering --- python-rpm-generators.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 6011515..3a264b0 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 12 -Release: 7%{?dist} +Release: 8%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -47,6 +47,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Fri Jul 23 2021 Fedora Release Engineering - 12-8 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild + * Tue May 25 2021 Tomas Orsava - 12-7 - pythondistdeps.py: Detect missing or corrupted metadata - pythondistdeps.py: Catch all exceptions and terminate the build if one is raised From 27f9733f0b8d07a584eb59b75387d3ff1407bd93 Mon Sep 17 00:00:00 2001 From: Gordon Messmer Date: Fri, 22 Oct 2021 16:41:44 -0700 Subject: [PATCH 074/110] Sync dependency conversion with upstream pyreq2rpm. Improve handling of > operator, preventing post-release from satisfying most rpm requirements. Improve handling of < operator, preventing pre-release from satisfying rpm requirement. Improve handling of != operator with prefix matching, preventing pre-release from satisfying rpm requirements. --- python-rpm-generators.spec | 6 +- pythondistdeps.py | 26 ++++- .../scripts_pythondistdeps/test-data.yaml | 98 +++++++++---------- 3 files changed, 76 insertions(+), 54 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 3a264b0..c61d9c1 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 12 -Release: 8%{?dist} +Release: 9%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -47,6 +47,10 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Thu Oct 28 2021 Gordon Messmer - 12-9 +- Sync dependency conversion with upstream pyreq2rpm. +- Improve handling of > and < operators, and != operator with prefix matching + * Fri Jul 23 2021 Fedora Release Engineering - 12-8 - Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild diff --git a/pythondistdeps.py b/pythondistdeps.py index e8b5afd..eea2628 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -134,6 +134,9 @@ class RpmVersion(): self.pre = version._version.pre self.dev = version._version.dev self.post = version._version.post + # version.local is ignored as it is not expected to appear + # in public releases + # https://www.python.org/dev/peps/pep-0440/#local-version-identifiers def increment(self): self.version[-1] += 1 @@ -201,18 +204,27 @@ def convert_not_equal(name, operator, version_id): if version_id.endswith('.*'): version_id = version_id[:-2] version = RpmVersion(version_id) - lower_version = RpmVersion(version_id).increment() + version_gt = RpmVersion(version_id).increment() + version_gt_operator = '>=' + # Prevent pre-releases from satisfying a < requirement + version = '{}~'.format(version) else: version = RpmVersion(version_id) - lower_version = version - return '({} < {} or {} > {})'.format( - name, version, name, lower_version) + version_gt = version + version_gt_operator = '>' + return '({} < {} or {} {} {})'.format( + name, version, name, version_gt_operator, version_gt) def convert_ordered(name, operator, version_id): if version_id.endswith('.*'): # PEP 440 does not define semantics for prefix matching # with ordered comparisons + # see: https://github.com/pypa/packaging/issues/320 + # and: https://github.com/pypa/packaging/issues/321 + # This style of specifier is officially "unsupported", + # even though it is processed. Support may be removed + # in version 21.0. version_id = version_id[:-2] version = RpmVersion(version_id) if operator == '>': @@ -223,6 +235,12 @@ def convert_ordered(name, operator, version_id): operator = '<' else: version = RpmVersion(version_id) + # Prevent pre-releases from satisfying a < requirement + if operator == '<' and not version.pre and not version.dev and not version.post: + version = '{}~'.format(version) + # Prevent post-releases from satisfying a > requirement + if operator == '>' and not version.pre and not version.dev and not version.post: + version = '{}.0'.format(version) return '{} {} {}'.format(name, operator, version) diff --git a/tests/data/scripts_pythondistdeps/test-data.yaml b/tests/data/scripts_pythondistdeps/test-data.yaml index afd928e..baad647 100644 --- a/tests/data/scripts_pythondistdeps/test-data.yaml +++ b/tests/data/scripts_pythondistdeps/test-data.yaml @@ -28,7 +28,7 @@ python2.7dist(setuptools) >= 21 python2.7dist(six) >= 1.9 python2.7dist(urllib3) >= 1.24.2 - ((python2.7dist(websocket-client) < 0.40 or python2.7dist(websocket-client) > 0.40) with (python2.7dist(websocket-client) < 0.41 or python2.7dist(websocket-client) > 0.42) with (python2.7dist(websocket-client) < 0.42 or python2.7dist(websocket-client) > 0.43) with python2.7dist(websocket-client) >= 0.32) + ((python2.7dist(websocket-client) < 0.40 or python2.7dist(websocket-client) > 0.40) with (python2.7dist(websocket-client) < 0.41~ or python2.7dist(websocket-client) >= 0.42) with (python2.7dist(websocket-client) < 0.42~ or python2.7dist(websocket-client) >= 0.43) with python2.7dist(websocket-client) >= 0.32) usr/lib/python2.7/site-packages/mistune-0.8.4-py2.7.egg-info: provides: |- python2.7dist(mistune) = 0.8.4 @@ -75,12 +75,12 @@ python2dist(tox) = 3.14 requires: |- python(abi) = 2.7 - (python2.7dist(filelock) < 4 with python2.7dist(filelock) >= 3) - (python2.7dist(importlib-metadata) < 1 with python2.7dist(importlib-metadata) >= 0.12) + (python2.7dist(filelock) < 4~ with python2.7dist(filelock) >= 3) + (python2.7dist(importlib-metadata) < 1~ with python2.7dist(importlib-metadata) >= 0.12) python2.7dist(packaging) >= 14 - (python2.7dist(pluggy) < 1 with python2.7dist(pluggy) >= 0.12) - (python2.7dist(py) < 2 with python2.7dist(py) >= 1.4.17) - (python2.7dist(six) < 2 with python2.7dist(six) >= 1) + (python2.7dist(pluggy) < 1~ with python2.7dist(pluggy) >= 0.12) + (python2.7dist(py) < 2~ with python2.7dist(py) >= 1.4.17) + (python2.7dist(six) < 2~ with python2.7dist(six) >= 1) python2.7dist(toml) >= 0.9.4 python2.7dist(virtualenv) >= 14 usr/lib/python2.7/site-packages/urllib3-1.25.7-py2.7.egg-info: @@ -105,7 +105,7 @@ python(abi) = 3.7 (python3.7dist(lazy-object-proxy) >= 1.4 with python3.7dist(lazy-object-proxy) < 1.5) (python3.7dist(six) >= 1.12 with python3.7dist(six) < 2) - (python3.7dist(typed-ast) < 1.5 with python3.7dist(typed-ast) >= 1.4) + (python3.7dist(typed-ast) < 1.5~ with python3.7dist(typed-ast) >= 1.4) (python3.7dist(wrapt) >= 1.11 with python3.7dist(wrapt) < 1.12) usr/lib/python3.7/site-packages/packaging-19.0.dist-info: provides: |- @@ -148,12 +148,12 @@ python3dist(tox) = 3.14 requires: |- python(abi) = 3.7 - (python3.7dist(filelock) < 4 with python3.7dist(filelock) >= 3) - (python3.7dist(importlib-metadata) < 1 with python3.7dist(importlib-metadata) >= 0.12) + (python3.7dist(filelock) < 4~ with python3.7dist(filelock) >= 3) + (python3.7dist(importlib-metadata) < 1~ with python3.7dist(importlib-metadata) >= 0.12) python3.7dist(packaging) >= 14 - (python3.7dist(pluggy) < 1 with python3.7dist(pluggy) >= 0.12) - (python3.7dist(py) < 2 with python3.7dist(py) >= 1.4.17) - (python3.7dist(six) < 2 with python3.7dist(six) >= 1) + (python3.7dist(pluggy) < 1~ with python3.7dist(pluggy) >= 0.12) + (python3.7dist(py) < 2~ with python3.7dist(py) >= 1.4.17) + (python3.7dist(six) < 2~ with python3.7dist(six) >= 1) python3.7dist(toml) >= 0.9.4 python3.7dist(virtualenv) >= 14 usr/lib/python3.9/site-packages/astroid-2.3.3.dist-info: @@ -205,7 +205,7 @@ python3.9dist(setuptools) >= 21 python3.9dist(six) >= 1.9 python3.9dist(urllib3) >= 1.24.2 - ((python3.9dist(websocket-client) < 0.40 or python3.9dist(websocket-client) > 0.40) with (python3.9dist(websocket-client) < 0.41 or python3.9dist(websocket-client) > 0.42) with (python3.9dist(websocket-client) < 0.42 or python3.9dist(websocket-client) > 0.43) with python3.9dist(websocket-client) >= 0.32) + ((python3.9dist(websocket-client) < 0.40 or python3.9dist(websocket-client) > 0.40) with (python3.9dist(websocket-client) < 0.41~ or python3.9dist(websocket-client) >= 0.42) with (python3.9dist(websocket-client) < 0.42~ or python3.9dist(websocket-client) >= 0.43) with python3.9dist(websocket-client) >= 0.32) usr/lib/python3.9/site-packages/mistune-0.8.4-py3.9.egg-info: provides: |- python3.9dist(mistune) = 0.8.4 @@ -260,11 +260,11 @@ python3dist(tox) = 3.14 requires: |- python(abi) = 3.9 - (python3.9dist(filelock) < 4 with python3.9dist(filelock) >= 3) + (python3.9dist(filelock) < 4~ with python3.9dist(filelock) >= 3) python3.9dist(packaging) >= 14 - (python3.9dist(pluggy) < 1 with python3.9dist(pluggy) >= 0.12) - (python3.9dist(py) < 2 with python3.9dist(py) >= 1.4.17) - (python3.9dist(six) < 2 with python3.9dist(six) >= 1) + (python3.9dist(pluggy) < 1~ with python3.9dist(pluggy) >= 0.12) + (python3.9dist(py) < 2~ with python3.9dist(py) >= 1.4.17) + (python3.9dist(six) < 2~ with python3.9dist(six) >= 1) python3.9dist(toml) >= 0.9.4 python3.9dist(virtualenv) >= 14 usr/lib/python3.9/site-packages/urllib3-1.25.7-py3.9.egg-info: @@ -437,7 +437,7 @@ python2.7dist(setuptools) >= 21 python2.7dist(six) >= 1.9 python2.7dist(urllib3) >= 1.24.2 - ((python2.7dist(websocket-client) < 0.40 or python2.7dist(websocket-client) > 0.40) with (python2.7dist(websocket-client) < 0.41 or python2.7dist(websocket-client) > 0.42) with (python2.7dist(websocket-client) < 0.42 or python2.7dist(websocket-client) > 0.43) with python2.7dist(websocket-client) >= 0.32) + ((python2.7dist(websocket-client) < 0.40 or python2.7dist(websocket-client) > 0.40) with (python2.7dist(websocket-client) < 0.41~ or python2.7dist(websocket-client) >= 0.42) with (python2.7dist(websocket-client) < 0.42~ or python2.7dist(websocket-client) >= 0.43) with python2.7dist(websocket-client) >= 0.32) usr/lib/python2.7/site-packages/mistune-0.8.4-py2.7.egg-info: provides: |- python2.7dist(mistune) = 0.8.4 @@ -489,7 +489,7 @@ python(abi) = 3.7 (python3.7dist(lazy-object-proxy) >= 1.4 with python3.7dist(lazy-object-proxy) < 1.5) (python3.7dist(six) >= 1.12 with python3.7dist(six) < 2) - (python3.7dist(typed-ast) < 1.5 with python3.7dist(typed-ast) >= 1.4) + (python3.7dist(typed-ast) < 1.5~ with python3.7dist(typed-ast) >= 1.4) (python3.7dist(wrapt) >= 1.11 with python3.7dist(wrapt) < 1.12) usr/lib/python3.7/site-packages/packaging-19.0.dist-info: provides: python3.7dist(packaging) = 19 @@ -554,11 +554,11 @@ python3dist(tox) = 3.14 requires: |- python(abi) = 3.9 - (python3.9dist(filelock) < 4 with python3.9dist(filelock) >= 3) + (python3.9dist(filelock) < 4~ with python3.9dist(filelock) >= 3) python3.9dist(packaging) >= 14 - (python3.9dist(pluggy) < 1 with python3.9dist(pluggy) >= 0.12) - (python3.9dist(py) < 2 with python3.9dist(py) >= 1.4.17) - (python3.9dist(six) < 2 with python3.9dist(six) >= 1) + (python3.9dist(pluggy) < 1~ with python3.9dist(pluggy) >= 0.12) + (python3.9dist(py) < 2~ with python3.9dist(py) >= 1.4.17) + (python3.9dist(six) < 2~ with python3.9dist(six) >= 1) python3.9dist(toml) >= 0.9.4 python3.9dist(virtualenv) >= 14 usr/lib/python3.9/site-packages/urllib3-1.25.7-py3.9.egg-info: @@ -611,12 +611,12 @@ python2dist(tox) = 3.14 requires: |- python(abi) = 2.7 - (python2.7dist(filelock) < 4 with python2.7dist(filelock) >= 3) - (python2.7dist(importlib-metadata) < 1 with python2.7dist(importlib-metadata) >= 0.12) + (python2.7dist(filelock) < 4~ with python2.7dist(filelock) >= 3) + (python2.7dist(importlib-metadata) < 1~ with python2.7dist(importlib-metadata) >= 0.12) python2.7dist(packaging) >= 14 - (python2.7dist(pluggy) < 1 with python2.7dist(pluggy) >= 0.12) - (python2.7dist(py) < 2 with python2.7dist(py) >= 1.4.17) - (python2.7dist(six) < 2 with python2.7dist(six) >= 1) + (python2.7dist(pluggy) < 1~ with python2.7dist(pluggy) >= 0.12) + (python2.7dist(py) < 2~ with python2.7dist(py) >= 1.4.17) + (python2.7dist(six) < 2~ with python2.7dist(six) >= 1) python2.7dist(toml) >= 0.9.4 python2.7dist(virtualenv) >= 14 usr/lib/python2.7/site-packages/urllib3-1.25.7-py2.7.egg-info: @@ -653,12 +653,12 @@ provides: python3.7dist(tox) = 3.14 requires: |- python(abi) = 3.7 - (python3.7dist(filelock) < 4 with python3.7dist(filelock) >= 3) - (python3.7dist(importlib-metadata) < 1 with python3.7dist(importlib-metadata) >= 0.12) + (python3.7dist(filelock) < 4~ with python3.7dist(filelock) >= 3) + (python3.7dist(importlib-metadata) < 1~ with python3.7dist(importlib-metadata) >= 0.12) python3.7dist(packaging) >= 14 - (python3.7dist(pluggy) < 1 with python3.7dist(pluggy) >= 0.12) - (python3.7dist(py) < 2 with python3.7dist(py) >= 1.4.17) - (python3.7dist(six) < 2 with python3.7dist(six) >= 1) + (python3.7dist(pluggy) < 1~ with python3.7dist(pluggy) >= 0.12) + (python3.7dist(py) < 2~ with python3.7dist(py) >= 1.4.17) + (python3.7dist(six) < 2~ with python3.7dist(six) >= 1) python3.7dist(toml) >= 0.9.4 python3.7dist(virtualenv) >= 14 usr/lib64/python2.7/site-packages/scipy-1.2.1.dist-info: @@ -1251,10 +1251,10 @@ (python3.9dist(foobar33) < 2.4.8 or python3.9dist(foobar33) > 2.4.8) (python3.9dist(foobar34) < 2.4.8 or python3.9dist(foobar34) > 2.4.8) (python3.9dist(foobar35) < 2.4.8.1 or python3.9dist(foobar35) > 2.4.8.1) - (python3.9dist(foobar36) < 2.4.8 or python3.9dist(foobar36) > 2.4.9) + (python3.9dist(foobar36) < 2.4.8~ or python3.9dist(foobar36) >= 2.4.9) (python3.9dist(foobar37) < 2 or python3.9dist(foobar37) > 2) (python3.9dist(foobar38) < 2 or python3.9dist(foobar38) > 2) - (python3.9dist(foobar39) < 2 or python3.9dist(foobar39) > 3) + (python3.9dist(foobar39) < 2~ or python3.9dist(foobar39) >= 3) (python3.9dist(foobar4) >= 2 with python3.9dist(foobar4) < 3) (python3.9dist(foobar40) < 2.4.8~b5 or python3.9dist(foobar40) > 2.4.8~b5) (python3.9dist(foobar41) < 2~b5 or python3.9dist(foobar41) > 2~b5) @@ -1263,21 +1263,21 @@ python3.9dist(foobar44) <= 2.4.8 python3.9dist(foobar45) <= 2.4.8 python3.9dist(foobar46) <= 2.4.8.1 - python3.9dist(foobar47) < 2.4.8 + python3.9dist(foobar47) < 2.4.8~ python3.9dist(foobar48) <= 2 python3.9dist(foobar49) <= 2 - python3.9dist(foobar50) < 2 + python3.9dist(foobar50) < 2~ python3.9dist(foobar51) <= 2.4.8~b5 python3.9dist(foobar52) <= 2~b5 python3.9dist(foobar53) <= 2.4.8^post1 python3.9dist(foobar54) <= 2^post1 - python3.9dist(foobar55) < 2.4.8 - python3.9dist(foobar56) < 2.4.8 - python3.9dist(foobar57) < 2.4.8.1 - python3.9dist(foobar58) < 2.4.8 - python3.9dist(foobar59) < 2 - python3.9dist(foobar60) < 2 - python3.9dist(foobar61) < 2 + python3.9dist(foobar55) < 2.4.8~ + python3.9dist(foobar56) < 2.4.8~ + python3.9dist(foobar57) < 2.4.8.1~ + python3.9dist(foobar58) < 2.4.8~ + python3.9dist(foobar59) < 2~ + python3.9dist(foobar60) < 2~ + python3.9dist(foobar61) < 2~ python3.9dist(foobar62) < 2.4.8~b5 python3.9dist(foobar63) < 2~b5 python3.9dist(foobar64) < 2.4.8^post1 @@ -1294,13 +1294,13 @@ python3.9dist(foobar74) >= 2~b5 python3.9dist(foobar75) >= 2.4.8^post1 python3.9dist(foobar76) >= 2^post1 - python3.9dist(foobar77) > 2.4.8 - python3.9dist(foobar78) > 2.4.8 - python3.9dist(foobar79) > 2.4.8.1 + python3.9dist(foobar77) > 2.4.8.0 + python3.9dist(foobar78) > 2.4.8.0 + python3.9dist(foobar79) > 2.4.8.1.0 (python3.9dist(foobar8) >= 2~b5 with python3.9dist(foobar8) < 2.1) python3.9dist(foobar80) >= 2.4.8 - python3.9dist(foobar81) > 2 - python3.9dist(foobar82) > 2 + python3.9dist(foobar81) > 2.0 + python3.9dist(foobar82) > 2.0 python3.9dist(foobar83) >= 2 python3.9dist(foobar84) > 2.4.8~b5 python3.9dist(foobar85) > 2~b5 From a3ad67b505f1fb8a6463cc7eabc10edd85c890cb Mon Sep 17 00:00:00 2001 From: Gordon Messmer Date: Fri, 29 Oct 2021 20:00:41 -0700 Subject: [PATCH 075/110] Additional fix for dev releases. --- python-rpm-generators.spec | 5 +- pythondistdeps.py | 8 +- .../scripts_pythondistdeps/test-data.yaml | 88 +++++++++---------- 3 files changed, 52 insertions(+), 49 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index c61d9c1..ef80ad4 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 12 -Release: 9%{?dist} +Release: 10%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -47,6 +47,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Fri Oct 29 2021 Gordon Messmer - 12-10 +- Additional fix for dev releases. + * Thu Oct 28 2021 Gordon Messmer - 12-9 - Sync dependency conversion with upstream pyreq2rpm. - Improve handling of > and < operators, and != operator with prefix matching diff --git a/pythondistdeps.py b/pythondistdeps.py index eea2628..2e4c9c3 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -206,8 +206,8 @@ def convert_not_equal(name, operator, version_id): version = RpmVersion(version_id) version_gt = RpmVersion(version_id).increment() version_gt_operator = '>=' - # Prevent pre-releases from satisfying a < requirement - version = '{}~'.format(version) + # Prevent dev and pre-releases from satisfying a < requirement + version = '{}~~'.format(version) else: version = RpmVersion(version_id) version_gt = version @@ -235,9 +235,9 @@ def convert_ordered(name, operator, version_id): operator = '<' else: version = RpmVersion(version_id) - # Prevent pre-releases from satisfying a < requirement + # Prevent dev and pre-releases from satisfying a < requirement if operator == '<' and not version.pre and not version.dev and not version.post: - version = '{}~'.format(version) + version = '{}~~'.format(version) # Prevent post-releases from satisfying a > requirement if operator == '>' and not version.pre and not version.dev and not version.post: version = '{}.0'.format(version) diff --git a/tests/data/scripts_pythondistdeps/test-data.yaml b/tests/data/scripts_pythondistdeps/test-data.yaml index baad647..7050e60 100644 --- a/tests/data/scripts_pythondistdeps/test-data.yaml +++ b/tests/data/scripts_pythondistdeps/test-data.yaml @@ -28,7 +28,7 @@ python2.7dist(setuptools) >= 21 python2.7dist(six) >= 1.9 python2.7dist(urllib3) >= 1.24.2 - ((python2.7dist(websocket-client) < 0.40 or python2.7dist(websocket-client) > 0.40) with (python2.7dist(websocket-client) < 0.41~ or python2.7dist(websocket-client) >= 0.42) with (python2.7dist(websocket-client) < 0.42~ or python2.7dist(websocket-client) >= 0.43) with python2.7dist(websocket-client) >= 0.32) + ((python2.7dist(websocket-client) < 0.40 or python2.7dist(websocket-client) > 0.40) with (python2.7dist(websocket-client) < 0.41~~ or python2.7dist(websocket-client) >= 0.42) with (python2.7dist(websocket-client) < 0.42~~ or python2.7dist(websocket-client) >= 0.43) with python2.7dist(websocket-client) >= 0.32) usr/lib/python2.7/site-packages/mistune-0.8.4-py2.7.egg-info: provides: |- python2.7dist(mistune) = 0.8.4 @@ -75,12 +75,12 @@ python2dist(tox) = 3.14 requires: |- python(abi) = 2.7 - (python2.7dist(filelock) < 4~ with python2.7dist(filelock) >= 3) - (python2.7dist(importlib-metadata) < 1~ with python2.7dist(importlib-metadata) >= 0.12) + (python2.7dist(filelock) < 4~~ with python2.7dist(filelock) >= 3) + (python2.7dist(importlib-metadata) < 1~~ with python2.7dist(importlib-metadata) >= 0.12) python2.7dist(packaging) >= 14 - (python2.7dist(pluggy) < 1~ with python2.7dist(pluggy) >= 0.12) - (python2.7dist(py) < 2~ with python2.7dist(py) >= 1.4.17) - (python2.7dist(six) < 2~ with python2.7dist(six) >= 1) + (python2.7dist(pluggy) < 1~~ with python2.7dist(pluggy) >= 0.12) + (python2.7dist(py) < 2~~ with python2.7dist(py) >= 1.4.17) + (python2.7dist(six) < 2~~ with python2.7dist(six) >= 1) python2.7dist(toml) >= 0.9.4 python2.7dist(virtualenv) >= 14 usr/lib/python2.7/site-packages/urllib3-1.25.7-py2.7.egg-info: @@ -105,7 +105,7 @@ python(abi) = 3.7 (python3.7dist(lazy-object-proxy) >= 1.4 with python3.7dist(lazy-object-proxy) < 1.5) (python3.7dist(six) >= 1.12 with python3.7dist(six) < 2) - (python3.7dist(typed-ast) < 1.5~ with python3.7dist(typed-ast) >= 1.4) + (python3.7dist(typed-ast) < 1.5~~ with python3.7dist(typed-ast) >= 1.4) (python3.7dist(wrapt) >= 1.11 with python3.7dist(wrapt) < 1.12) usr/lib/python3.7/site-packages/packaging-19.0.dist-info: provides: |- @@ -148,12 +148,12 @@ python3dist(tox) = 3.14 requires: |- python(abi) = 3.7 - (python3.7dist(filelock) < 4~ with python3.7dist(filelock) >= 3) - (python3.7dist(importlib-metadata) < 1~ with python3.7dist(importlib-metadata) >= 0.12) + (python3.7dist(filelock) < 4~~ with python3.7dist(filelock) >= 3) + (python3.7dist(importlib-metadata) < 1~~ with python3.7dist(importlib-metadata) >= 0.12) python3.7dist(packaging) >= 14 - (python3.7dist(pluggy) < 1~ with python3.7dist(pluggy) >= 0.12) - (python3.7dist(py) < 2~ with python3.7dist(py) >= 1.4.17) - (python3.7dist(six) < 2~ with python3.7dist(six) >= 1) + (python3.7dist(pluggy) < 1~~ with python3.7dist(pluggy) >= 0.12) + (python3.7dist(py) < 2~~ with python3.7dist(py) >= 1.4.17) + (python3.7dist(six) < 2~~ with python3.7dist(six) >= 1) python3.7dist(toml) >= 0.9.4 python3.7dist(virtualenv) >= 14 usr/lib/python3.9/site-packages/astroid-2.3.3.dist-info: @@ -205,7 +205,7 @@ python3.9dist(setuptools) >= 21 python3.9dist(six) >= 1.9 python3.9dist(urllib3) >= 1.24.2 - ((python3.9dist(websocket-client) < 0.40 or python3.9dist(websocket-client) > 0.40) with (python3.9dist(websocket-client) < 0.41~ or python3.9dist(websocket-client) >= 0.42) with (python3.9dist(websocket-client) < 0.42~ or python3.9dist(websocket-client) >= 0.43) with python3.9dist(websocket-client) >= 0.32) + ((python3.9dist(websocket-client) < 0.40 or python3.9dist(websocket-client) > 0.40) with (python3.9dist(websocket-client) < 0.41~~ or python3.9dist(websocket-client) >= 0.42) with (python3.9dist(websocket-client) < 0.42~~ or python3.9dist(websocket-client) >= 0.43) with python3.9dist(websocket-client) >= 0.32) usr/lib/python3.9/site-packages/mistune-0.8.4-py3.9.egg-info: provides: |- python3.9dist(mistune) = 0.8.4 @@ -260,11 +260,11 @@ python3dist(tox) = 3.14 requires: |- python(abi) = 3.9 - (python3.9dist(filelock) < 4~ with python3.9dist(filelock) >= 3) + (python3.9dist(filelock) < 4~~ with python3.9dist(filelock) >= 3) python3.9dist(packaging) >= 14 - (python3.9dist(pluggy) < 1~ with python3.9dist(pluggy) >= 0.12) - (python3.9dist(py) < 2~ with python3.9dist(py) >= 1.4.17) - (python3.9dist(six) < 2~ with python3.9dist(six) >= 1) + (python3.9dist(pluggy) < 1~~ with python3.9dist(pluggy) >= 0.12) + (python3.9dist(py) < 2~~ with python3.9dist(py) >= 1.4.17) + (python3.9dist(six) < 2~~ with python3.9dist(six) >= 1) python3.9dist(toml) >= 0.9.4 python3.9dist(virtualenv) >= 14 usr/lib/python3.9/site-packages/urllib3-1.25.7-py3.9.egg-info: @@ -437,7 +437,7 @@ python2.7dist(setuptools) >= 21 python2.7dist(six) >= 1.9 python2.7dist(urllib3) >= 1.24.2 - ((python2.7dist(websocket-client) < 0.40 or python2.7dist(websocket-client) > 0.40) with (python2.7dist(websocket-client) < 0.41~ or python2.7dist(websocket-client) >= 0.42) with (python2.7dist(websocket-client) < 0.42~ or python2.7dist(websocket-client) >= 0.43) with python2.7dist(websocket-client) >= 0.32) + ((python2.7dist(websocket-client) < 0.40 or python2.7dist(websocket-client) > 0.40) with (python2.7dist(websocket-client) < 0.41~~ or python2.7dist(websocket-client) >= 0.42) with (python2.7dist(websocket-client) < 0.42~~ or python2.7dist(websocket-client) >= 0.43) with python2.7dist(websocket-client) >= 0.32) usr/lib/python2.7/site-packages/mistune-0.8.4-py2.7.egg-info: provides: |- python2.7dist(mistune) = 0.8.4 @@ -489,7 +489,7 @@ python(abi) = 3.7 (python3.7dist(lazy-object-proxy) >= 1.4 with python3.7dist(lazy-object-proxy) < 1.5) (python3.7dist(six) >= 1.12 with python3.7dist(six) < 2) - (python3.7dist(typed-ast) < 1.5~ with python3.7dist(typed-ast) >= 1.4) + (python3.7dist(typed-ast) < 1.5~~ with python3.7dist(typed-ast) >= 1.4) (python3.7dist(wrapt) >= 1.11 with python3.7dist(wrapt) < 1.12) usr/lib/python3.7/site-packages/packaging-19.0.dist-info: provides: python3.7dist(packaging) = 19 @@ -554,11 +554,11 @@ python3dist(tox) = 3.14 requires: |- python(abi) = 3.9 - (python3.9dist(filelock) < 4~ with python3.9dist(filelock) >= 3) + (python3.9dist(filelock) < 4~~ with python3.9dist(filelock) >= 3) python3.9dist(packaging) >= 14 - (python3.9dist(pluggy) < 1~ with python3.9dist(pluggy) >= 0.12) - (python3.9dist(py) < 2~ with python3.9dist(py) >= 1.4.17) - (python3.9dist(six) < 2~ with python3.9dist(six) >= 1) + (python3.9dist(pluggy) < 1~~ with python3.9dist(pluggy) >= 0.12) + (python3.9dist(py) < 2~~ with python3.9dist(py) >= 1.4.17) + (python3.9dist(six) < 2~~ with python3.9dist(six) >= 1) python3.9dist(toml) >= 0.9.4 python3.9dist(virtualenv) >= 14 usr/lib/python3.9/site-packages/urllib3-1.25.7-py3.9.egg-info: @@ -611,12 +611,12 @@ python2dist(tox) = 3.14 requires: |- python(abi) = 2.7 - (python2.7dist(filelock) < 4~ with python2.7dist(filelock) >= 3) - (python2.7dist(importlib-metadata) < 1~ with python2.7dist(importlib-metadata) >= 0.12) + (python2.7dist(filelock) < 4~~ with python2.7dist(filelock) >= 3) + (python2.7dist(importlib-metadata) < 1~~ with python2.7dist(importlib-metadata) >= 0.12) python2.7dist(packaging) >= 14 - (python2.7dist(pluggy) < 1~ with python2.7dist(pluggy) >= 0.12) - (python2.7dist(py) < 2~ with python2.7dist(py) >= 1.4.17) - (python2.7dist(six) < 2~ with python2.7dist(six) >= 1) + (python2.7dist(pluggy) < 1~~ with python2.7dist(pluggy) >= 0.12) + (python2.7dist(py) < 2~~ with python2.7dist(py) >= 1.4.17) + (python2.7dist(six) < 2~~ with python2.7dist(six) >= 1) python2.7dist(toml) >= 0.9.4 python2.7dist(virtualenv) >= 14 usr/lib/python2.7/site-packages/urllib3-1.25.7-py2.7.egg-info: @@ -653,12 +653,12 @@ provides: python3.7dist(tox) = 3.14 requires: |- python(abi) = 3.7 - (python3.7dist(filelock) < 4~ with python3.7dist(filelock) >= 3) - (python3.7dist(importlib-metadata) < 1~ with python3.7dist(importlib-metadata) >= 0.12) + (python3.7dist(filelock) < 4~~ with python3.7dist(filelock) >= 3) + (python3.7dist(importlib-metadata) < 1~~ with python3.7dist(importlib-metadata) >= 0.12) python3.7dist(packaging) >= 14 - (python3.7dist(pluggy) < 1~ with python3.7dist(pluggy) >= 0.12) - (python3.7dist(py) < 2~ with python3.7dist(py) >= 1.4.17) - (python3.7dist(six) < 2~ with python3.7dist(six) >= 1) + (python3.7dist(pluggy) < 1~~ with python3.7dist(pluggy) >= 0.12) + (python3.7dist(py) < 2~~ with python3.7dist(py) >= 1.4.17) + (python3.7dist(six) < 2~~ with python3.7dist(six) >= 1) python3.7dist(toml) >= 0.9.4 python3.7dist(virtualenv) >= 14 usr/lib64/python2.7/site-packages/scipy-1.2.1.dist-info: @@ -1251,10 +1251,10 @@ (python3.9dist(foobar33) < 2.4.8 or python3.9dist(foobar33) > 2.4.8) (python3.9dist(foobar34) < 2.4.8 or python3.9dist(foobar34) > 2.4.8) (python3.9dist(foobar35) < 2.4.8.1 or python3.9dist(foobar35) > 2.4.8.1) - (python3.9dist(foobar36) < 2.4.8~ or python3.9dist(foobar36) >= 2.4.9) + (python3.9dist(foobar36) < 2.4.8~~ or python3.9dist(foobar36) >= 2.4.9) (python3.9dist(foobar37) < 2 or python3.9dist(foobar37) > 2) (python3.9dist(foobar38) < 2 or python3.9dist(foobar38) > 2) - (python3.9dist(foobar39) < 2~ or python3.9dist(foobar39) >= 3) + (python3.9dist(foobar39) < 2~~ or python3.9dist(foobar39) >= 3) (python3.9dist(foobar4) >= 2 with python3.9dist(foobar4) < 3) (python3.9dist(foobar40) < 2.4.8~b5 or python3.9dist(foobar40) > 2.4.8~b5) (python3.9dist(foobar41) < 2~b5 or python3.9dist(foobar41) > 2~b5) @@ -1263,21 +1263,21 @@ python3.9dist(foobar44) <= 2.4.8 python3.9dist(foobar45) <= 2.4.8 python3.9dist(foobar46) <= 2.4.8.1 - python3.9dist(foobar47) < 2.4.8~ + python3.9dist(foobar47) < 2.4.8~~ python3.9dist(foobar48) <= 2 python3.9dist(foobar49) <= 2 - python3.9dist(foobar50) < 2~ + python3.9dist(foobar50) < 2~~ python3.9dist(foobar51) <= 2.4.8~b5 python3.9dist(foobar52) <= 2~b5 python3.9dist(foobar53) <= 2.4.8^post1 python3.9dist(foobar54) <= 2^post1 - python3.9dist(foobar55) < 2.4.8~ - python3.9dist(foobar56) < 2.4.8~ - python3.9dist(foobar57) < 2.4.8.1~ - python3.9dist(foobar58) < 2.4.8~ - python3.9dist(foobar59) < 2~ - python3.9dist(foobar60) < 2~ - python3.9dist(foobar61) < 2~ + python3.9dist(foobar55) < 2.4.8~~ + python3.9dist(foobar56) < 2.4.8~~ + python3.9dist(foobar57) < 2.4.8.1~~ + python3.9dist(foobar58) < 2.4.8~~ + python3.9dist(foobar59) < 2~~ + python3.9dist(foobar60) < 2~~ + python3.9dist(foobar61) < 2~~ python3.9dist(foobar62) < 2.4.8~b5 python3.9dist(foobar63) < 2~b5 python3.9dist(foobar64) < 2.4.8^post1 From 2c2f8bd98495cabb0ecfbed9ea4747660f48bb37 Mon Sep 17 00:00:00 2001 From: Gordon Messmer Date: Sun, 19 Dec 2021 14:08:05 -0800 Subject: [PATCH 076/110] Handle legacy version specifiers that would previously raise exceptions. --- python-rpm-generators.spec | 5 ++++- pythondistdeps.py | 29 ++++++++++++++++++++++------- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index ef80ad4..64bc193 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 12 -Release: 10%{?dist} +Release: 11%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -47,6 +47,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Sun Dec 19 2021 Gordon Messmer - 12-11 +- Handle legacy version specifiers that would previously raise exceptions. + * Fri Oct 29 2021 Gordon Messmer - 12-10 - Additional fix for dev releases. diff --git a/pythondistdeps.py b/pythondistdeps.py index 2e4c9c3..8ae142d 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -138,6 +138,9 @@ class RpmVersion(): # in public releases # https://www.python.org/dev/peps/pep-0440/#local-version-identifiers + def is_legacy(self): + return isinstance(self.version, str) + def increment(self): self.version[-1] += 1 self.pre = None @@ -146,7 +149,7 @@ class RpmVersion(): return self def __str__(self): - if isinstance(self.version, str): + if self.is_legacy(): return self.version if self.epoch: rpm_epoch = str(self.epoch) + ':' @@ -172,6 +175,11 @@ def convert_compatible(name, operator, version_id): print('Invalid requirement: {} {} {}'.format(name, operator, version_id), file=stderr) exit(65) # os.EX_DATAERR version = RpmVersion(version_id) + if version.is_legacy(): + # LegacyVersions are not supported in this context + print("*** INVALID_REQUIREMENT_ERROR___SEE_STDERR ***") + print('Invalid requirement: {} {} {}'.format(name, operator, version_id), file=stderr) + exit(65) # os.EX_DATAERR if len(version.version) == 1: print("*** INVALID_REQUIREMENT_ERROR___SEE_STDERR ***") print('Invalid requirement: {} {} {}'.format(name, operator, version_id), file=stderr) @@ -204,6 +212,11 @@ def convert_not_equal(name, operator, version_id): if version_id.endswith('.*'): version_id = version_id[:-2] version = RpmVersion(version_id) + if version.is_legacy(): + # LegacyVersions are not supported in this context + print("*** INVALID_REQUIREMENT_ERROR___SEE_STDERR ***") + print('Invalid requirement: {} {} {}'.format(name, operator, version_id), file=stderr) + exit(65) # os.EX_DATAERR version_gt = RpmVersion(version_id).increment() version_gt_operator = '>=' # Prevent dev and pre-releases from satisfying a < requirement @@ -235,12 +248,14 @@ def convert_ordered(name, operator, version_id): operator = '<' else: version = RpmVersion(version_id) - # Prevent dev and pre-releases from satisfying a < requirement - if operator == '<' and not version.pre and not version.dev and not version.post: - version = '{}~~'.format(version) - # Prevent post-releases from satisfying a > requirement - if operator == '>' and not version.pre and not version.dev and not version.post: - version = '{}.0'.format(version) + # For backwards compatibility, fallback to previous behavior with LegacyVersions + if not version.is_legacy(): + # Prevent dev and pre-releases from satisfying a < requirement + if operator == '<' and not version.pre and not version.dev and not version.post: + version = '{}~~'.format(version) + # Prevent post-releases from satisfying a > requirement + if operator == '>' and not version.pre and not version.dev and not version.post: + version = '{}.0'.format(version) return '{} {} {}'.format(name, operator, version) From 2ff265d8fdb00b9b573662db9e8d487efdf52f5f Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Fri, 21 Jan 2022 15:19:07 +0000 Subject: [PATCH 077/110] - Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild Signed-off-by: Fedora Release Engineering --- python-rpm-generators.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 64bc193..7a6c39b 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 12 -Release: 11%{?dist} +Release: 12%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -47,6 +47,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Fri Jan 21 2022 Fedora Release Engineering - 12-12 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild + * Sun Dec 19 2021 Gordon Messmer - 12-11 - Handle legacy version specifiers that would previously raise exceptions. From fbd2f8726560b96106cda4748f665573c807cbe2 Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Thu, 20 Jan 2022 19:03:13 +0100 Subject: [PATCH 078/110] Fix typo in lua comment --- pythonname.attr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pythonname.attr b/pythonname.attr index 85969d7..9cd580a 100644 --- a/pythonname.attr +++ b/pythonname.attr @@ -8,7 +8,7 @@ local provides = python.python_altprovides_once(name, evr) -- provides is either an array/table or nil -- nil means the function was already called with the same arguments: - -- either with another file in %1 or manually via %py_provide + -- either with another file in %1 or manually via %py_provides if provides then for i, provide in ipairs(provides) do print(provide .. ' ') From b1fa63bf02b03b2120d32eb91ca2911d4ec77beb Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Mon, 29 Nov 2021 12:31:48 +0100 Subject: [PATCH 079/110] From `python3-foo` packages automatically generate `python3.X-foo` Obsoletes tags on CentOS/RHEL --- python-rpm-generators.spec | 8 ++++++-- pythonname.attr | 23 +++++++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 7a6c39b..fd88df1 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 12 -Release: 12%{?dist} +Release: 13%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -25,7 +25,7 @@ Requires: python3-packaging # We have parametric macro generators, we need RPM 4.16 (4.15.90+ is 4.16 alpha) Requires: rpm > 4.15.90-0 # This contains the Lua functions we use: -Requires: python-srpm-macros >= 3.8-5 +Requires: python-srpm-macros >= 3.10-15 %description -n python3-rpm-generators %{summary}. @@ -47,6 +47,10 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Wed Jan 26 2022 Tomas Orsava - 12-13 +- From `python3-foo` packages automatically generate `python3.X-foo` Obsoletes + tags on CentOS/RHEL + * Fri Jan 21 2022 Fedora Release Engineering - 12-12 - Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild diff --git a/pythonname.attr b/pythonname.attr index 9cd580a..07d8df5 100644 --- a/pythonname.attr +++ b/pythonname.attr @@ -16,4 +16,27 @@ end } +%__pythonname_obsoletes() %{?rhel:%{lua: + -- On CentOS/RHEL we automatically generate Obsoletes tags in the form: + -- package python3-foo -> Obsoletes: python3.XY-foo + -- This provides a clean upgrade path between major versions of CentOS/RHEL. + -- In Fedora this is not needed as we don't ship ecosystem packages + -- for alternative Python interpreters. + local python = require 'fedora.srpm.python' + -- this macro is called for each file in a package, the path being in %1 + -- but we don't need to know the path, so we would get for each file: Macro %1 defined but not used within scope + -- in here, we expand %name conditionally on %1 to suppress the warning + local name = rpm.expand('%{?1:%{name}}') + local evr = rpm.expand('%{?epoch:%{epoch}:}%{version}-%{release}') + local obsoletes = python.python_altobsoletes_once(name, evr) + -- obsoletes is either an array/table or nil + -- nil means the function was already called with the same arguments: + -- either with another file in %1 or manually via %py_provides + if obsoletes then + for i, obsolete in ipairs(obsoletes) do + print(obsolete .. ' ') + end + end +}} + %__pythonname_path ^/ From e18b8c952cc55b4808a952c9b731a54ac194c3f6 Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Wed, 2 Feb 2022 11:32:20 +0100 Subject: [PATCH 080/110] Add tests for automatically not generating Obsoletes tags on Fedora --- tests/pythonname.sh | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/pythonname.sh b/tests/pythonname.sh index ab2024a..b21058c 100755 --- a/tests/pythonname.sh +++ b/tests/pythonname.sh @@ -34,3 +34,43 @@ test $(rpm -qp --provides ${RPMDIR}/python3-python_provide-0-0.noarch.rpm | grep echo "Provides for python3-py_provides" rpm -qp --provides ${RPMDIR}/python3-py_provides-0-0.noarch.rpm test $(rpm -qp --provides ${RPMDIR}/python3-py_provides-0-0.noarch.rpm | grep python-py_provides | wc -l) -eq 1 + + +echo "Obsoletes for python${X_Y}-foo" +rpm -qp --obsoletes ${RPMDIR}/python${X_Y}-foo-0-0.noarch.rpm +test $(rpm -qp --obsoletes ${RPMDIR}/python${X_Y}-foo-0-0.noarch.rpm | wc -l) -eq 0 + +echo "Obsoletes for python3-foo" +rpm -qp --obsoletes ${RPMDIR}/python3-foo-0-0.noarch.rpm +# In ELN/RHEL the pythonX.Y-* Obsoletes is generated, but not in Fedora, so we check for it explicitly. +rpm -qp --obsoletes ${RPMDIR}/python3-foo-0-0.noarch.rpm | grep -q '^python'${X_Y}'-py_provides < 0-0$' && exit 1 || true +test $(rpm -qp --obsoletes ${RPMDIR}/python3-foo-0-0.noarch.rpm | wc -l) -eq 0 + +echo "Obsoletes for python2-foo" +rpm -qp --obsoletes ${RPMDIR}/python2-foo-0-0.noarch.rpm +test $(rpm -qp --obsoletes ${RPMDIR}/python2-foo-0-0.noarch.rpm | wc -l) -eq 0 + +echo "Obsoletes for python-foo" +rpm -qp --obsoletes ${RPMDIR}/python-foo-0-0.noarch.rpm +test $(rpm -qp --obsoletes ${RPMDIR}/python-foo-0-0.noarch.rpm | wc -l) -eq 0 + +echo "Obsoletes for python3.5-foo" +rpm -qp --obsoletes ${RPMDIR}/python3.5-foo-0-0.noarch.rpm +test $(rpm -qp --obsoletes ${RPMDIR}/python3.5-foo-0-0.noarch.rpm | wc -l) -eq 0 + +echo "Obsoletes for python3-python_provide" +rpm -qp --obsoletes ${RPMDIR}/python3-python_provide-0-0.noarch.rpm +# The deprecated %python_provide macro always obsoletes python-foo +rpm -qp --obsoletes ${RPMDIR}/python3-python_provide-0-0.noarch.rpm | grep -q '^python-python_provide < 0-0$' +# In ELN/RHEL the pythonX.Y-* Obsoletes is generated, but not in Fedora, so we check for it explicitly. +rpm -qp --obsoletes ${RPMDIR}/python3-python_provide-0-0.noarch.rpm | grep -q '^python'${X_Y}'-python_provide < 0-0$' && exit 1 || true +test $(rpm -qp --obsoletes ${RPMDIR}/python3-python_provide-0-0.noarch.rpm | grep python-python_provide | wc -l) -eq 1 +test $(rpm -qp --obsoletes ${RPMDIR}/python3-python_provide-0-0.noarch.rpm | wc -l) -eq 1 + +echo "Obsoletes for python3-py_provides" +rpm -qp --obsoletes ${RPMDIR}/python3-py_provides-0-0.noarch.rpm +rpm -qp --obsoletes ${RPMDIR}/python3-py_provides-0-0.noarch.rpm | grep -q '^python-py_provides < 0-0$' && exit 1 || true +# In ELN/RHEL the pythonX.Y-* Obsoletes is generated, but not in Fedora, so we check for it explicitly. +rpm -qp --obsoletes ${RPMDIR}/python3-py_provides-0-0.noarch.rpm | grep -q '^python'${X_Y}'-py_provides < 0-0$' && exit 1 || true +test $(rpm -qp --obsoletes ${RPMDIR}/python3-py_provides-0-0.noarch.rpm | wc -l) -eq 0 + From ecd2f8b3f858d5c6307042c4978577bfe2a9bb6a Mon Sep 17 00:00:00 2001 From: Charalampos Stratakis Date: Tue, 1 Feb 2022 21:22:28 +0100 Subject: [PATCH 081/110] Add rpminspect file --- rpminspect.yaml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 rpminspect.yaml diff --git a/rpminspect.yaml b/rpminspect.yaml new file mode 100644 index 0000000..4589e70 --- /dev/null +++ b/rpminspect.yaml @@ -0,0 +1,7 @@ +# completely disabled inspections: +inspections: + # there is no upstream and the files are changed from time to time + addedfiles: off + changedfiles: off + filesize: off + upstream: off From 76e71def2c27d6948167a31b9644a3678277e423 Mon Sep 17 00:00:00 2001 From: Sandro Mani Date: Mon, 24 Jan 2022 11:23:14 +0100 Subject: [PATCH 082/110] Add namespace option to pythodistdeps.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Miro Hrončok --- python-rpm-generators.spec | 5 +++- pythondistdeps.py | 23 +++++++++++-------- .../scripts_pythondistdeps/test-data.yaml | 8 +++++++ 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index fd88df1..fbaff88 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 12 -Release: 13%{?dist} +Release: 14%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -47,6 +47,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Thu Feb 10 2022 Sandro Mani - 12-14 +- Add namespace option to pythodistdeps.py to allow mingw-python generatros + * Wed Jan 26 2022 Tomas Orsava - 12-13 - From `python3-foo` packages automatically generate `python3.X-foo` Obsoletes tags on CentOS/RHEL diff --git a/pythondistdeps.py b/pythondistdeps.py index 8ae142d..92be3a5 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -326,6 +326,7 @@ def main(): parser.add_argument('--require-extras-subpackages', action='store_true', help="If there is a dependency on a package with extras functionality, require the extras subpackage") parser.add_argument('--package-name', action='store', help="Name of the RPM package that's being inspected. Required for extras requires/provides to work.") + parser.add_argument('--namespace', action='store', help="Namespace for the printed Requires, Provides, Recommends and Conflicts") parser.add_argument('files', nargs=argparse.REMAINDER, help="Files from the RPM package that are to be inspected, can also be supplied on stdin") args = parser.parse_args() @@ -374,6 +375,8 @@ def main(): package_name_parts = args.package_name.rpartition('+') extras_subpackage = package_name_parts[2].lower() or None + namespace = (args.namespace + "({})") if args.namespace else "{}" + for f in (args.files or stdin.readlines()): f = f.strip() lower = f.lower() @@ -430,31 +433,31 @@ def main(): extras_suffix = f"[{extras_subpackage}]" if extras_subpackage else "" # If egg/dist metadata says package name is python, we provide python(abi) if dist.normalized_name == 'python': - name = 'python(abi)' + name = namespace.format('python(abi)') if name not in py_deps: py_deps[name] = [] py_deps[name].append(('==', dist.py_version)) if not args.legacy or not args.majorver_only: if normalized_names_provide_legacy: - name = 'python{}dist({}{})'.format(dist.py_version, dist.legacy_normalized_name, extras_suffix) + name = namespace.format('python{}dist({}{})').format(dist.py_version, dist.legacy_normalized_name, extras_suffix) if name not in py_deps: py_deps[name] = [] if normalized_names_provide_pep503: - name_ = 'python{}dist({}{})'.format(dist.py_version, dist.normalized_name, extras_suffix) + name_ = namespace.format('python{}dist({}{})').format(dist.py_version, dist.normalized_name, extras_suffix) if name_ not in py_deps: py_deps[name_] = [] if args.majorver_provides or args.majorver_only or \ (args.majorver_provides_versions and dist.py_version in args.majorver_provides_versions): if normalized_names_provide_legacy: - pymajor_name = 'python{}dist({}{})'.format(pyver_major, dist.legacy_normalized_name, extras_suffix) + pymajor_name = namespace.format('python{}dist({}{})').format(pyver_major, dist.legacy_normalized_name, extras_suffix) if pymajor_name not in py_deps: py_deps[pymajor_name] = [] if normalized_names_provide_pep503: - pymajor_name_ = 'python{}dist({}{})'.format(pyver_major, dist.normalized_name, extras_suffix) + pymajor_name_ = namespace.format('python{}dist({}{})').format(pyver_major, dist.normalized_name, extras_suffix) if pymajor_name_ not in py_deps: py_deps[pymajor_name_] = [] if args.legacy or args.legacy_provides: - legacy_name = 'pythonegg({})({})'.format(pyver_major, dist.legacy_normalized_name) + legacy_name = namespace.format('pythonegg({})({})').format(pyver_major, dist.legacy_normalized_name) if legacy_name not in py_deps: py_deps[legacy_name] = [] if dist.version: @@ -477,7 +480,7 @@ def main(): if spec not in py_deps[legacy_name]: py_deps[legacy_name].append(spec) if args.requires or (args.recommends and dist.extras): - name = 'python(abi)' + name = namespace.format('python(abi)') # If egg/dist metadata says package name is python, we don't add dependency on python(abi) if dist.normalized_name == 'python': py_abi = False @@ -524,12 +527,12 @@ def main(): dep_normalized_name = dep.legacy_normalized_name if args.legacy: - name = 'pythonegg({})({})'.format(pyver_major, dep.legacy_normalized_name) + name = namespace.format('pythonegg({})({})').format(pyver_major, dep.legacy_normalized_name) else: if args.majorver_only: - name = 'python{}dist({}{})'.format(pyver_major, dep_normalized_name, extras_suffix) + name = namespace.format('python{}dist({}{})').format(pyver_major, dep_normalized_name, extras_suffix) else: - name = 'python{}dist({}{})'.format(dist.py_version, dep_normalized_name, extras_suffix) + name = namespace.format('python{}dist({}{})').format(dist.py_version, dep_normalized_name, extras_suffix) if dep.marker and not args.recommends and not extras_subpackage: if not dep.marker.evaluate(get_marker_env(dist, '')): diff --git a/tests/data/scripts_pythondistdeps/test-data.yaml b/tests/data/scripts_pythondistdeps/test-data.yaml index 7050e60..54e5b66 100644 --- a/tests/data/scripts_pythondistdeps/test-data.yaml +++ b/tests/data/scripts_pythondistdeps/test-data.yaml @@ -762,6 +762,14 @@ python3.9dist(simplejson) = 3.16 python3dist(simplejson) = 3.16 requires: python(abi) = 3.9 +--requires --namespace mingw64: + --provides --namespace mingw64: + usr/lib/python3.9/site-packages/taskotron_python_versions-0.1.dev6.dist-info: + provides: mingw64(python3.9dist(taskotron-python-versions)) = 0.1~~dev6 + requires: |- + mingw64(python(abi)) = 3.9 + mingw64(python3.9dist(libarchive-c)) + mingw64(python3.9dist(python-bugzilla)) --requires --console-scripts-nodep-setuptools-since 3.7: --provides --console-scripts-nodep-setuptools-since 3.6: usr/lib/python3.9/site-packages/zope.component-4.3.0-py3.9.egg-info: From 0bd051d51473d62519bc6e03cafdf323c5345e7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Fri, 27 May 2022 12:49:09 +0200 Subject: [PATCH 083/110] Don't include all requirements with True-evaluating markers in extras subpackages The idea is that the extra subpackage only has requirements specific to that extra. The logic however only excluded requirements without markers, but requirements with *a* marker that was correct leaked to all extras subpackages. E.g. with the following requirements: Requires-Dist: base-dependency Requires-Dist: base-dependency-with-matching-marker ; python_version < "3.15" Requires-Dist: base-dependency-with-unmatching-marker ; python_version < "3.8" Provides-Extra: an-extra Requires-Dist: extra-only-dependency-with-matching-marker ; extra == 'an-extra' and python_version < "3.15" Requires-Dist: extra-only-dependency-with-unmatching-marker ; extra == 'an-extra' and python_version < "3.8" On Python 3.10, the base package generated the following requirements: python3.10dist(base-dependency) python3.10dist(base-dependency-with-matching-marker) And for the [an-extra] extra: python3.10dist(base-dependency-with-matching-marker) <--- REDUNDANT, WRONG python3.10dist(extra-only-dependency-with-matching-marker) Now we no longer just check if the marker evaluates to True, but we also check that the same marker evaluates to False when the extra is not given. A real package with this issue is build[virtualenv] 0.8.0, which we use for tests. The package has: Requires-Dist: tomli (>=1.0.0) ; python_version < "3.11" And on Python 3.10, it generated the following dependency for python3-build+virtualenv-0.8.0-2.fc37.noarch.rpm: python3.10dist(tomli) >= 1 Now it no longer does. This is asserted in tests. Fixes https://bugzilla.redhat.com/show_bug.cgi?id=2090186 Upstream PR: https://github.com/rpm-software-management/python-rpm-packaging/pull/16 --- python-rpm-generators.spec | 6 +++++- pythondistdeps.py | 9 ++++++++- tests/data/scripts_pythondistdeps/test-data.yaml | 9 +++++++++ tests/data/scripts_pythondistdeps/test-requires.yaml | 3 +++ 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index fbaff88..933683f 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 12 -Release: 14%{?dist} +Release: 15%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -47,6 +47,10 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Fri May 27 2022 Miro Hrončok - 12-15 +- Don't include all requirements with True-evaluating markers in extras subpackages +- Fixes: rhbz#2090186 + * Thu Feb 10 2022 Sandro Mani - 12-14 - Add namespace option to pythodistdeps.py to allow mingw-python generatros diff --git a/pythondistdeps.py b/pythondistdeps.py index 92be3a5..b825c35 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -112,10 +112,17 @@ class Distribution(PathDistribution): def requirements_for_extra(self, extra): extra_deps = [] + # we are only interested in dependencies with extra == 'our_extra' marker for req in self.requirements: + # no marker at all, nothing to evaluate if not req.marker: continue - if req.marker.evaluate(get_marker_env(self, extra)): + # does the marker include extra == 'our_extra'? + # we can only evaluate the marker as a whole, + # so we evaluate it twice (using 2 different marker_envs) + # and see if it only evaluates to True with our extra + if (req.marker.evaluate(get_marker_env(self, extra)) and + not req.marker.evaluate(get_marker_env(self, None))): extra_deps.append(req) return extra_deps diff --git a/tests/data/scripts_pythondistdeps/test-data.yaml b/tests/data/scripts_pythondistdeps/test-data.yaml index 54e5b66..6a8152d 100644 --- a/tests/data/scripts_pythondistdeps/test-data.yaml +++ b/tests/data/scripts_pythondistdeps/test-data.yaml @@ -1353,4 +1353,13 @@ python3.9dist(zope-component[security]) python3.9dist(zope-component[zcml]) python3.9dist(zope-testing) +--requires --normalized-names-format pep503 --require-extras-subpackages --package-name python3-build+virtualenv: + --provides --majorver-provides --normalized-names-format pep503 --package-name python3-build+virtualenv: + usr/lib/python3.10/site-packages/build-0.8.0.dist-info: + provides: |- + python3.10dist(build[virtualenv]) = 0.8 + python3dist(build[virtualenv]) = 0.8 + requires: |- + python(abi) = 3.10 + python3.10dist(virtualenv) >= 20.0.35 diff --git a/tests/data/scripts_pythondistdeps/test-requires.yaml b/tests/data/scripts_pythondistdeps/test-requires.yaml index d876674..ade5043 100644 --- a/tests/data/scripts_pythondistdeps/test-requires.yaml +++ b/tests/data/scripts_pythondistdeps/test-requires.yaml @@ -100,3 +100,6 @@ dnspython: '2.1.0': ['3.9'] wheel: '2.1.0': ['3.9'] +build: + wheel: + '0.8.0': ['3.10'] From cf65060b7e8aabacd6e183518da3bf6a952395e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Wed, 20 Apr 2022 13:07:09 +0200 Subject: [PATCH 084/110] https://fedoraproject.org/wiki/Changes/PythonDistPEP503ProvidesOnly --- python-rpm-generators.spec | 7 +++++-- pythondist.attr | 2 +- tests/pythondist.sh | 10 +++++----- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 933683f..9a7c8ed 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs -Version: 12 -Release: 15%{?dist} +Version: 13 +Release: 1%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -47,6 +47,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Thu Jun 02 2022 Miro Hrončok - 13-1 +- https://fedoraproject.org/wiki/Changes/PythonDistPEP503ProvidesOnly + * Fri May 27 2022 Miro Hrončok - 12-15 - Don't include all requirements with True-evaluating markers in extras subpackages - Fixes: rhbz#2090186 diff --git a/pythondist.attr b/pythondist.attr index 747cc32..7170bdb 100644 --- a/pythondist.attr +++ b/pythondist.attr @@ -1,3 +1,3 @@ -%__pythondist_provides %{_rpmconfigdir}/pythondistdeps.py --provides --normalized-names-format pep503 --package-name %{name} --normalized-names-provide-both --majorver-provides-versions %{__default_python3_version} +%__pythondist_provides %{_rpmconfigdir}/pythondistdeps.py --provides --normalized-names-format pep503 --package-name %{name} --majorver-provides-versions %{__default_python3_version} %__pythondist_requires %{_rpmconfigdir}/pythondistdeps.py --requires --normalized-names-format pep503 --package-name %{name} %{?!_python_no_extras_requires:--require-extras-subpackages} --console-scripts-nodep-setuptools-since 3.10 %__pythondist_path ^/usr/lib(64)?/python[3-9]\\.[[:digit:]]+/site-packages/[^/]+\\.(dist-info|egg-info|egg-link)$ diff --git a/tests/pythondist.sh b/tests/pythondist.sh index 4f2e15d..51f5511 100755 --- a/tests/pythondist.sh +++ b/tests/pythondist.sh @@ -8,9 +8,9 @@ spectool -g -R pythondist.spec rpmbuild -ba pythondist.spec -rpm -qp --provides ${RPMDIR}/python3-zope-component-4.3.0-0.noarch.rpm | grep '^python3dist(zope\.component)' +rpm -qp --provides ${RPMDIR}/python3-zope-component-4.3.0-0.noarch.rpm | grep '^python3dist(zope\.component)' && exit 1 || true rpm -qp --provides ${RPMDIR}/python3-zope-component-4.3.0-0.noarch.rpm | grep '^python3dist(zope-component)' -rpm -qp --provides ${RPMDIR}/python3-zope-component-4.3.0-0.noarch.rpm | grep '^python'$X_Y'dist(zope\.component)' +rpm -qp --provides ${RPMDIR}/python3-zope-component-4.3.0-0.noarch.rpm | grep '^python'$X_Y'dist(zope\.component)' && exit 1 || true rpm -qp --provides ${RPMDIR}/python3-zope-component-4.3.0-0.noarch.rpm | grep '^python'$X_Y'dist(zope-component)' rpm -qp --requires ${RPMDIR}/python3-zope-component-4.3.0-0.noarch.rpm | grep '^python'$X_Y'dist(zope-event)' @@ -19,7 +19,7 @@ rpm -qp --requires ${RPMDIR}/python3-zope-component-4.3.0-0.noarch.rpm | grep '^ rpm -qp --provides ${RPMDIR}/python3.7-zope-component-4.3.0-0.noarch.rpm | grep '^python3dist(zope\.component)' && exit 1 || true rpm -qp --provides ${RPMDIR}/python3.7-zope-component-4.3.0-0.noarch.rpm | grep '^python3dist(zope-component)' && exit 1 || true -rpm -qp --provides ${RPMDIR}/python3.7-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.7dist(zope\.component)' +rpm -qp --provides ${RPMDIR}/python3.7-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.7dist(zope\.component)' && exit 1 || true rpm -qp --provides ${RPMDIR}/python3.7-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.7dist(zope-component)' rpm -qp --requires ${RPMDIR}/python3.7-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.7dist(zope-event)' @@ -28,7 +28,7 @@ rpm -qp --requires ${RPMDIR}/python3.7-zope-component-4.3.0-0.noarch.rpm | grep if [ "$X_Y" != "3.9" ]; then rpm -qp --provides ${RPMDIR}/python3.9-zope-component-4.3.0-0.noarch.rpm | grep '^python3dist(zope\.component)' && exit 1 || true rpm -qp --provides ${RPMDIR}/python3.9-zope-component-4.3.0-0.noarch.rpm | grep '^python3dist(zope-component)' && exit 1 || true -rpm -qp --provides ${RPMDIR}/python3.9-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.9dist(zope\.component)' +rpm -qp --provides ${RPMDIR}/python3.9-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.9dist(zope\.component)' && exit 1 || true rpm -qp --provides ${RPMDIR}/python3.9-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.9dist(zope-component)' rpm -qp --requires ${RPMDIR}/python3.9-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.9dist(zope-event)' @@ -38,7 +38,7 @@ fi if [ "$X_Y" != "3.10" ]; then rpm -qp --provides ${RPMDIR}/python3.10-zope-component-4.3.0-0.noarch.rpm | grep '^python3dist(zope\.component)' && exit 1 || true rpm -qp --provides ${RPMDIR}/python3.10-zope-component-4.3.0-0.noarch.rpm | grep '^python3dist(zope-component)' && exit 1 || true -rpm -qp --provides ${RPMDIR}/python3.10-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.10dist(zope\.component)' +rpm -qp --provides ${RPMDIR}/python3.10-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.10dist(zope\.component)' && exit 1 || true rpm -qp --provides ${RPMDIR}/python3.10-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.10dist(zope-component)' rpm -qp --requires ${RPMDIR}/python3.10-zope-component-4.3.0-0.noarch.rpm | grep '^python3\.10dist(zope-event)' From 7b3e3b30de218e4c33034b85781fd8e344ff113d Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Fri, 22 Jul 2022 22:07:02 +0000 Subject: [PATCH 085/110] Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild Signed-off-by: Fedora Release Engineering --- python-rpm-generators.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 9a7c8ed..e5dee70 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 13 -Release: 1%{?dist} +Release: 2%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -47,6 +47,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Fri Jul 22 2022 Fedora Release Engineering - 13-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild + * Thu Jun 02 2022 Miro Hrončok - 13-1 - https://fedoraproject.org/wiki/Changes/PythonDistPEP503ProvidesOnly From 197a88bf932fd7f552724a0bb1eecc31c906eb7d Mon Sep 17 00:00:00 2001 From: Karolina Surma Date: Thu, 22 Dec 2022 16:48:53 +0100 Subject: [PATCH 086/110] https://fedoraproject.org/wiki/Changes/Prevent-Providing-python3dist(pkg)=0 --- python-rpm-generators.spec | 7 +++- pythondist.attr | 2 +- pythondistdeps.py | 18 +++++++++ .../scripts_pythondistdeps/test-data.yaml | 37 ++++++++++++++++++- .../scripts_pythondistdeps/test-requires.yaml | 4 ++ 5 files changed, 64 insertions(+), 4 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index e5dee70..1f42b8e 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs -Version: 13 -Release: 2%{?dist} +Version: 14 +Release: 1%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -47,6 +47,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Thu Dec 22 2022 Karolina Surma - 14-1 +- https://fedoraproject.org/wiki/Changes/Prevent-Providing-python3dist(pkg)=0 + * Fri Jul 22 2022 Fedora Release Engineering - 13-2 - Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild diff --git a/pythondist.attr b/pythondist.attr index 7170bdb..42ae7ad 100644 --- a/pythondist.attr +++ b/pythondist.attr @@ -1,3 +1,3 @@ -%__pythondist_provides %{_rpmconfigdir}/pythondistdeps.py --provides --normalized-names-format pep503 --package-name %{name} --majorver-provides-versions %{__default_python3_version} +%__pythondist_provides %{_rpmconfigdir}/pythondistdeps.py --provides --normalized-names-format pep503 --package-name %{name} --majorver-provides-versions %{__default_python3_version} %{?!_python_dist_allow_version_zero:--fail-if-zero} %__pythondist_requires %{_rpmconfigdir}/pythondistdeps.py --requires --normalized-names-format pep503 --package-name %{name} %{?!_python_no_extras_requires:--require-extras-subpackages} --console-scripts-nodep-setuptools-since 3.10 %__pythondist_path ^/usr/lib(64)?/python[3-9]\\.[[:digit:]]+/site-packages/[^/]+\\.(dist-info|egg-info|egg-link)$ diff --git a/pythondistdeps.py b/pythondistdeps.py index b825c35..ec80125 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -155,6 +155,9 @@ class RpmVersion(): self.post = None return self + def is_zero(self): + return self.__str__() == '0' + def __str__(self): if self.is_legacy(): return self.version @@ -334,9 +337,13 @@ def main(): help="If there is a dependency on a package with extras functionality, require the extras subpackage") parser.add_argument('--package-name', action='store', help="Name of the RPM package that's being inspected. Required for extras requires/provides to work.") parser.add_argument('--namespace', action='store', help="Namespace for the printed Requires, Provides, Recommends and Conflicts") + parser.add_argument('--fail-if-zero', action='store_true', help='Fail the script if the automatically generated Provides version was 0, which usually indicates a packaging error.') parser.add_argument('files', nargs=argparse.REMAINDER, help="Files from the RPM package that are to be inspected, can also be supplied on stdin") args = parser.parse_args() + if args.fail_if_zero and not args.provides: + raise parser.error('--fail-if-zero only works with --provides') + py_abi = args.requires py_deps = {} @@ -470,6 +477,17 @@ def main(): if dist.version: version = dist.version spec = ('==', version) + if args.fail_if_zero: + if RpmVersion(version).is_zero(): + print('*** PYTHON_PROVIDED_VERSION_NORMALIZES_TO_ZERO___SEE_STDERR ***') + print(f'\nError: The version in the Python package metadata {version} normalizes to zero.\n' + 'It\'s likely a packaging error caused by missing version information\n' + '(e.g. when using a version control system snapshot as a source).\n' + 'Try providing the version information manually when building the Python package,\n' + 'for example by setting the SETUPTOOLS_SCM_PRETEND_VERSION environment variable if the package uses setuptools_scm.\n' + 'If you are confident that the version of the Python package is intentionally zero,\n' + 'you may %define the _python_dist_allow_version_zero macro in the spec file to disable this check.\n', file=stderr) + exit(65) # os.EX_DATAERR if normalized_names_provide_legacy: if spec not in py_deps[name]: diff --git a/tests/data/scripts_pythondistdeps/test-data.yaml b/tests/data/scripts_pythondistdeps/test-data.yaml index 6a8152d..f1116a5 100644 --- a/tests/data/scripts_pythondistdeps/test-data.yaml +++ b/tests/data/scripts_pythondistdeps/test-data.yaml @@ -1362,4 +1362,39 @@ requires: |- python(abi) = 3.10 python3.10dist(virtualenv) >= 20.0.35 - +--requires --fail-if-zero: + --provides --majorver-provides --fail-if-zero: + usr/lib/python3.11/site-packages/importlib_metadata-0.0-py3.11.egg-info: + stderr: + provides: |- + Error: The version in the Python package metadata 0.0 normalizes to zero. + It's likely a packaging error caused by missing version information + (e.g. when using a version control system snapshot as a source). + Try providing the version information manually when building the Python package, + for example by setting the SETUPTOOLS_SCM_PRETEND_VERSION environment variable if the package uses setuptools_scm. + If you are confident that the version of the Python package is intentionally zero, + you may %define the _python_dist_allow_version_zero macro in the spec file to disable this check. + requires: '*error: --fail-if-zero only works with --provides*' + stdout: + provides: '*** PYTHON_PROVIDED_VERSION_NORMALIZES_TO_ZERO___SEE_STDERR ***' + requires: '' +--requires: + --provides --majorver-provides: + usr/lib/python3.11/site-packages/importlib_metadata-0.0-py3.11.egg-info: + provides: |- + python3.11dist(importlib-metadata) = 0 + python3dist(importlib-metadata) = 0 + requires: |- + python(abi) = 3.11 + python3.11dist(setuptools) + python3.11dist(wheel) +--requires: + --provides --majorver-provides --fail-if-zero: + usr/lib/python3.11/site-packages/importlib_metadata-0.1-py3.11.egg-info: + provides: |- + python3.11dist(importlib-metadata) = 0.1 + python3dist(importlib-metadata) = 0.1 + requires: |- + python(abi) = 3.11 + python3.11dist(setuptools) + python3.11dist(wheel) diff --git a/tests/data/scripts_pythondistdeps/test-requires.yaml b/tests/data/scripts_pythondistdeps/test-requires.yaml index ade5043..35314a5 100644 --- a/tests/data/scripts_pythondistdeps/test-requires.yaml +++ b/tests/data/scripts_pythondistdeps/test-requires.yaml @@ -103,3 +103,7 @@ dnspython: build: wheel: '0.8.0': ['3.10'] +importlib_metadata: + sdist: + '0.0': ['3.11'] + '0.1': ['3.11'] From 78c739cfd1f8a93ea029f3a5e36d5838331914cd Mon Sep 17 00:00:00 2001 From: Karolina Surma Date: Wed, 4 Jan 2023 18:05:28 +0100 Subject: [PATCH 087/110] Update the test data sources --- .gitignore | 1 + sources | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 78062d7..1f380c9 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ /tests/__pycache__/ /tests/data/scripts_pythondistdeps/usr/ /test-sources-2021-03-11.tar.gz +/test-sources-2023-01-04.tar.gz diff --git a/sources b/sources index d8fedb8..7d51236 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (test-sources-2021-03-11.tar.gz) = 6f34c8151625be489a6a4d56d1fd3d39b7908bd31402c9703cb65918385320dfad35f35a32920c816fb85a829f44aaf04dc1d0654ccf512e26e87e95dbf87430 +SHA512 (test-sources-2023-01-04.tar.gz) = ca25c35970e91adeaed0873c045f4335c33b96a4ef4c56a36bfb2fd9e1d4799142cf0513abb066479fdb14d2d184b3b825c1d90119ac8e8d0e9aa1a4423701d1 From 9d7ca941e7b2f80fba83a0a923e682f4bf9b9603 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Fri, 20 Jan 2023 17:03:50 +0000 Subject: [PATCH 088/110] Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild Signed-off-by: Fedora Release Engineering --- python-rpm-generators.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 1f42b8e..5596407 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 14 -Release: 1%{?dist} +Release: 2%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -47,6 +47,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Fri Jan 20 2023 Fedora Release Engineering - 14-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild + * Thu Dec 22 2022 Karolina Surma - 14-1 - https://fedoraproject.org/wiki/Changes/Prevent-Providing-python3dist(pkg)=0 From 1bdd94dd1d9c6fa08999ea02eda850569d065c95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Thu, 19 Jan 2023 17:36:21 +0100 Subject: [PATCH 089/110] CI: Include stdout/stderr in test failures --- tests/test_scripts_pythondistdeps.py | 5 +++++ tests/tests.yml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/test_scripts_pythondistdeps.py b/tests/test_scripts_pythondistdeps.py index 79f0c6f..7a7f57a 100644 --- a/tests/test_scripts_pythondistdeps.py +++ b/tests/test_scripts_pythondistdeps.py @@ -53,6 +53,11 @@ def run_pythondistdeps(provides_params, requires_params, dist_egg_info_path, exp requires = subprocess.run((sys.executable, PYTHONDISTDEPS_PATH, *shlex.split(requires_params)), input=files, capture_output=True, check=False, encoding="utf-8") + print(provides_params, provides.stdout, sep=':\n', file=sys.stdout) + print(requires_params, requires.stdout, sep=':\n', file=sys.stdout) + print(provides_params, provides.stderr, sep=':\n', file=sys.stderr) + print(requires_params, requires.stderr, sep=':\n', file=sys.stderr) + if expect_failure: if provides.returncode == 0 or requires.returncode == 0: raise RuntimeError(f"pythondistdeps.py did not exit with a non-zero code as expected.\n" diff --git a/tests/tests.yml b/tests/tests.yml index 668ff36..54a0aaf 100644 --- a/tests/tests.yml +++ b/tests/tests.yml @@ -36,7 +36,7 @@ - pytest: dir: ./tests # Use update-test-sources.sh to update the test data - run: python3 -m pytest --capture=no -vvv + run: python3 -m pytest -vvv required_packages: - rpm-build - rpmdevtools From 500fda1e6db830271a34dcb63cd1b1a50fa322ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Thu, 19 Jan 2023 17:44:36 +0100 Subject: [PATCH 090/110] CI: Remove tests for non-PEP440 versions packaging 22+ no longer supports them, so neither can we. --- .../PKG-INFO | 2 +- .../requires.txt | 8 -------- tests/data/scripts_pythondistdeps/test-data.yaml | 12 ++---------- 3 files changed, 3 insertions(+), 19 deletions(-) rename tests/data/scripts_pythondistdeps/{pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info => pyreq2rpm.tests-2020.04.07.024-py3.9.egg-info}/PKG-INFO (97%) rename tests/data/scripts_pythondistdeps/{pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info => pyreq2rpm.tests-2020.04.07.024-py3.9.egg-info}/requires.txt (92%) diff --git a/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/PKG-INFO b/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024-py3.9.egg-info/PKG-INFO similarity index 97% rename from tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/PKG-INFO rename to tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024-py3.9.egg-info/PKG-INFO index a99b21c..cf262f7 100644 --- a/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/PKG-INFO +++ b/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024-py3.9.egg-info/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: pyreq2rpm.tests -Version: 2020.04.07.024dab0 +Version: 2020.04.07.024 Summary: Test package to verify conversion of dependencies from pip/python to rpm format, data taken from pyreq2rpm Author: Tomas Orsava (author of this metapackage) Home-page: https://github.com/gordonmessmer/pyreq2rpm diff --git a/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/requires.txt b/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024-py3.9.egg-info/requires.txt similarity index 92% rename from tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/requires.txt rename to tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024-py3.9.egg-info/requires.txt index 338afcc..1b5da2d 100644 --- a/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info/requires.txt +++ b/tests/data/scripts_pythondistdeps/pyreq2rpm.tests-2020.04.07.024-py3.9.egg-info/requires.txt @@ -45,10 +45,8 @@ foobar43!=2.0.post1 foobar44<=2.4.8 foobar45<=2.4.8.0 foobar46<=2.4.8.1 -foobar47<=2.4.8.* foobar48<=2.0 foobar49<=2 -foobar50<=2.* foobar51<=2.4.8b5 foobar52<=2.0.0b5 foobar53<=2.4.8.post1 @@ -56,10 +54,8 @@ foobar54<=2.0.post1 foobar55<2.4.8 foobar56<2.4.8.0 foobar57<2.4.8.1 -foobar58<2.4.8.* foobar59<2.0 foobar60<2 -foobar61<2.* foobar62<2.4.8b5 foobar63<2.0.0b5 foobar64<2.4.8.post1 @@ -67,10 +63,8 @@ foobar65<2.0.post1 foobar66>=2.4.8 foobar67>=2.4.8.0 foobar68>=2.4.8.1 -foobar69>=2.4.8.* foobar70>=2.0 foobar71>=2 -foobar72>=2.* foobar73>=2.4.8b5 foobar74>=2.0.0b5 foobar75>=2.4.8.post1 @@ -78,10 +72,8 @@ foobar76>=2.0.post1 foobar77>2.4.8 foobar78>2.4.8.0 foobar79>2.4.8.1 -foobar80>2.4.8.* foobar81>2.0 foobar82>2 -foobar83>2.* foobar84>2.4.8b5 foobar85>2.0.0b5 foobar86>2.4.8.post1 diff --git a/tests/data/scripts_pythondistdeps/test-data.yaml b/tests/data/scripts_pythondistdeps/test-data.yaml index f1116a5..aa0bcdc 100644 --- a/tests/data/scripts_pythondistdeps/test-data.yaml +++ b/tests/data/scripts_pythondistdeps/test-data.yaml @@ -1224,8 +1224,8 @@ stdout: provides: '*** PYTHON_METADATA_FAILED_TO_PARSE_ERROR___SEE_STDERR ***' requires: '*** PYTHON_METADATA_FAILED_TO_PARSE_ERROR___SEE_STDERR ***' - pyreq2rpm.tests-2020.04.07.024dab0-py3.9.egg-info: - provides: python3.9dist(pyreq2rpm-tests) = 2020.04.07.024dab0 + pyreq2rpm.tests-2020.04.07.024-py3.9.egg-info: + provides: python3.9dist(pyreq2rpm-tests) = 2020.4.7.24 requires: |- python(abi) = 3.9 ((python3.9dist(babel) < 2 or python3.9dist(babel) > 2) with python3.9dist(babel) >= 1.3) @@ -1271,10 +1271,8 @@ python3.9dist(foobar44) <= 2.4.8 python3.9dist(foobar45) <= 2.4.8 python3.9dist(foobar46) <= 2.4.8.1 - python3.9dist(foobar47) < 2.4.8~~ python3.9dist(foobar48) <= 2 python3.9dist(foobar49) <= 2 - python3.9dist(foobar50) < 2~~ python3.9dist(foobar51) <= 2.4.8~b5 python3.9dist(foobar52) <= 2~b5 python3.9dist(foobar53) <= 2.4.8^post1 @@ -1282,10 +1280,8 @@ python3.9dist(foobar55) < 2.4.8~~ python3.9dist(foobar56) < 2.4.8~~ python3.9dist(foobar57) < 2.4.8.1~~ - python3.9dist(foobar58) < 2.4.8~~ python3.9dist(foobar59) < 2~~ python3.9dist(foobar60) < 2~~ - python3.9dist(foobar61) < 2~~ python3.9dist(foobar62) < 2.4.8~b5 python3.9dist(foobar63) < 2~b5 python3.9dist(foobar64) < 2.4.8^post1 @@ -1293,11 +1289,9 @@ python3.9dist(foobar66) >= 2.4.8 python3.9dist(foobar67) >= 2.4.8 python3.9dist(foobar68) >= 2.4.8.1 - python3.9dist(foobar69) >= 2.4.8 (python3.9dist(foobar7) >= 2.4.8~b5 with python3.9dist(foobar7) < 2.5) python3.9dist(foobar70) >= 2 python3.9dist(foobar71) >= 2 - python3.9dist(foobar72) >= 2 python3.9dist(foobar73) >= 2.4.8~b5 python3.9dist(foobar74) >= 2~b5 python3.9dist(foobar75) >= 2.4.8^post1 @@ -1306,10 +1300,8 @@ python3.9dist(foobar78) > 2.4.8.0 python3.9dist(foobar79) > 2.4.8.1.0 (python3.9dist(foobar8) >= 2~b5 with python3.9dist(foobar8) < 2.1) - python3.9dist(foobar80) >= 2.4.8 python3.9dist(foobar81) > 2.0 python3.9dist(foobar82) > 2.0 - python3.9dist(foobar83) >= 2 python3.9dist(foobar84) > 2.4.8~b5 python3.9dist(foobar85) > 2~b5 python3.9dist(foobar86) > 2.4.8^post1 From 279638a969f7c9f142c7a969d6aafbe0215ede3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Tue, 7 Mar 2023 17:16:58 +0100 Subject: [PATCH 091/110] Avoid needless pkg_resources import in pythonbundles.py --- python-rpm-generators.spec | 5 ++++- pythonbundles.py | 5 ----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 5596407..fc8c7ee 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 14 -Release: 2%{?dist} +Release: 3%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -47,6 +47,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Tue Mar 07 2023 Miro Hrončok - 14-3 +- Avoid needless pkg_resources import in pythonbundles.py + * Fri Jan 20 2023 Fedora Release Engineering - 14-2 - Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild diff --git a/pythonbundles.py b/pythonbundles.py index 6242e20..9c58f6c 100755 --- a/pythonbundles.py +++ b/pythonbundles.py @@ -15,12 +15,7 @@ import pathlib import sys -# inject parse_version import to pythondistdeps -# not the nicest API, but :/ -from pkg_resources import parse_version import pythondistdeps -pythondistdeps.parse_version = parse_version - def generate_bundled_provides(paths, namespace): provides = set() From 079b71a567cf8d81314e18938b54f521d555cec9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Tue, 7 Mar 2023 17:35:06 +0100 Subject: [PATCH 092/110] Ignore environment markers in pythonbundles.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use packaging.requirements instead of a naïve split on ==. --- python-rpm-generators.spec | 1 + pythonbundles.py | 12 ++++++++++-- .../pkg_resources_setuptools.out | 1 + tests/data/scripts_pythonbundles/setuptools.in | 1 + tests/data/scripts_pythonbundles/setuptools.out | 1 + 5 files changed, 14 insertions(+), 2 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index fc8c7ee..580eb06 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -49,6 +49,7 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %changelog * Tue Mar 07 2023 Miro Hrončok - 14-3 - Avoid needless pkg_resources import in pythonbundles.py +- Ignore environment markers in pythonbundles.py * Fri Jan 20 2023 Fedora Release Engineering - 14-2 - Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild diff --git a/pythonbundles.py b/pythonbundles.py index 9c58f6c..8adc36f 100755 --- a/pythonbundles.py +++ b/pythonbundles.py @@ -15,6 +15,8 @@ import pathlib import sys +from packaging import requirements + import pythondistdeps def generate_bundled_provides(paths, namespace): @@ -33,8 +35,14 @@ def generate_bundled_provides(paths, namespace): continue line = line.strip() if line: - name, _, version = line.partition('==') - name = pythondistdeps.normalize_name(name) + requirement = requirements.Requirement(line) + for spec in requirement.specifier: + if spec.operator == '==': + version = spec.version + break + else: + raise ValueError('pythonbundles.py only handles exactly one == requirement') + name = pythondistdeps.normalize_name(requirement.name) bundled_name = f"bundled({namespace}({name}))" python_provide = pythondistdeps.convert(bundled_name, '==', version) provides.add(f'Provides: {python_provide}') diff --git a/tests/data/scripts_pythonbundles/pkg_resources_setuptools.out b/tests/data/scripts_pythonbundles/pkg_resources_setuptools.out index cc2d710..0d41629 100644 --- a/tests/data/scripts_pythonbundles/pkg_resources_setuptools.out +++ b/tests/data/scripts_pythonbundles/pkg_resources_setuptools.out @@ -3,3 +3,4 @@ Provides: bundled(python3dist(ordered-set)) = 3.1.1 Provides: bundled(python3dist(packaging)) = 16.8 Provides: bundled(python3dist(pyparsing)) = 2.2.1 Provides: bundled(python3dist(six)) = 1.10 +Provides: bundled(python3dist(tomli)) = 1.2.3 diff --git a/tests/data/scripts_pythonbundles/setuptools.in b/tests/data/scripts_pythonbundles/setuptools.in index d7d2beb..64ee9d3 100644 --- a/tests/data/scripts_pythonbundles/setuptools.in +++ b/tests/data/scripts_pythonbundles/setuptools.in @@ -1,3 +1,4 @@ packaging==16.8 pyparsing==2.2.1 ordered-set==3.1.1 +tomli==1.2.3;python_version<"3.11" diff --git a/tests/data/scripts_pythonbundles/setuptools.out b/tests/data/scripts_pythonbundles/setuptools.out index 0acb887..ec452db 100644 --- a/tests/data/scripts_pythonbundles/setuptools.out +++ b/tests/data/scripts_pythonbundles/setuptools.out @@ -1,3 +1,4 @@ Provides: bundled(python3dist(ordered-set)) = 3.1.1 Provides: bundled(python3dist(packaging)) = 16.8 Provides: bundled(python3dist(pyparsing)) = 2.2.1 +Provides: bundled(python3dist(tomli)) = 1.2.3 From 2b230d8b53a71b42052f7ef0e2f0f87c51b5b7f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Mon, 13 Mar 2023 15:49:45 +0100 Subject: [PATCH 093/110] CI: Assert pythonbundles also ignores [extras] See https://bugzilla.redhat.com/show_bug.cgi?id=2140230#c12 to #c14. --- tests/data/scripts_pythonbundles/pipenv.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/data/scripts_pythonbundles/pipenv.in b/tests/data/scripts_pythonbundles/pipenv.in index de5797a..7735210 100644 --- a/tests/data/scripts_pythonbundles/pipenv.in +++ b/tests/data/scripts_pythonbundles/pipenv.in @@ -31,7 +31,7 @@ requirementslib==1.5.11 distlib==0.3.0 packaging==20.3 pyparsing==2.4.7 - plette==0.2.3 + plette[validation]==0.2.3 tomlkit==0.5.11 shellingham==1.3.2 six==1.14.0 From 2b8d03b0b153b90e64e3206c2d28c4bf765defc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Tue, 18 Apr 2023 10:07:17 +0200 Subject: [PATCH 094/110] CI: Add `rpm -qa | sort` for easier inspectability --- tests/tests.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/tests.yml b/tests/tests.yml index 54a0aaf..bd27cda 100644 --- a/tests/tests.yml +++ b/tests/tests.yml @@ -18,6 +18,9 @@ roles: - role: standard-test-basic tests: + - rpm_qa: + dir: . + run: rpm -qa | sort - pythonabi: dir: . run: ./pythonabi.sh From d6993270c2a89e3d4b44da712f5f5fec630fb866 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Wed, 19 Apr 2023 14:34:31 +0200 Subject: [PATCH 095/110] CI: Run pytest via script to make it easier to reuse it in python-packaging --- tests/download_data_and_run_pytest.sh | 14 ++++++++++++++ tests/tests.yml | 9 +++------ 2 files changed, 17 insertions(+), 6 deletions(-) create mode 100755 tests/download_data_and_run_pytest.sh diff --git a/tests/download_data_and_run_pytest.sh b/tests/download_data_and_run_pytest.sh new file mode 100755 index 0000000..8dca398 --- /dev/null +++ b/tests/download_data_and_run_pytest.sh @@ -0,0 +1,14 @@ +#!/usr/bin/bash -eux +# Use update-test-sources.sh to update the test data + +# When the tests run in python-rpm-generators, +# the structure on disk does not match the dist-git repository. +# We apparently must use the standard-test-source role to grab the sources. +# OTOH in other packages, we must use fedpkg(-minimal). +# The --force flag is required in full-blown fedpkg (the source is unused in spec), +# and it is ignored in fedpkg-minimal (all sources are always downloaded). +test -f test-sources-*.tar.gz || fedpkg sources --force + +tar -xvf test-sources-*.tar.gz -C ./tests/data/scripts_pythondistdeps/ +cd tests/ +python3 -m pytest -vvv diff --git a/tests/tests.yml b/tests/tests.yml index bd27cda..22b2cb7 100644 --- a/tests/tests.yml +++ b/tests/tests.yml @@ -33,16 +33,13 @@ - console_script: dir: . run: ./console_script.sh - - prepare-test-data: - dir: . - run: tar -xvf test-sources-*.tar.gz -C ./tests/data/scripts_pythondistdeps/ - pytest: - dir: ./tests - # Use update-test-sources.sh to update the test data - run: python3 -m pytest -vvv + dir: . + run: ./download_data_and_run_pytest.sh required_packages: - rpm-build - rpmdevtools + - fedpkg-minimal - python3-devel - python3-pip - python3-pytest From 47a0b37ac072262826ce1481673067d675d0b885 Mon Sep 17 00:00:00 2001 From: Kalev Lember Date: Thu, 20 Apr 2023 04:10:35 +0200 Subject: [PATCH 096/110] Generate provides for /app-installed flatpak builds The generator deliberately does not use %{_prefix} in order to avoid generating provides for packages that set a custom prefix. This is done to ensure that provides are only generated for paths where the Python interpreter actually loads modules from. As we can't use %{_prefix} (which would make it all much simpler), this commit adds a conditional to look in /app only when the %flatpak macro is defined, and /usr otherwise. This should fix provides generation for /app-installed flatpak builds. --- python-rpm-generators.spec | 5 ++++- python.attr | 14 +++++++++----- pythondist.attr | 2 +- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 580eb06..8f0a75b 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 14 -Release: 3%{?dist} +Release: 4%{?dist} # Originally all those files were part of RPM, so license is kept here License: GPLv2+ @@ -47,6 +47,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Mon Apr 17 2023 Kalev Lember - 14-4 +- Generate provides for /app-installed flatpak builds + * Tue Mar 07 2023 Miro Hrončok - 14-3 - Avoid needless pkg_resources import in pythonbundles.py - Ignore environment markers in pythonbundles.py diff --git a/python.attr b/python.attr index 1793d3c..cf5ae39 100644 --- a/python.attr +++ b/python.attr @@ -5,8 +5,10 @@ -- python(abi) = MAJOR.MINOR -- (Don't match against -config tools e.g. /usr/bin/python2.6-config) local path = rpm.expand('%1') - if path:match('/usr/bin/python%d+%.%d+$') then - local provides = path:gsub('.*/usr/bin/python(%d+%.%d+)', 'python(abi) = %1') + -- Use /usr prefix by default, and /app for flatpak builds + local prefix = rpm.expand('%{?!flatpak:/usr}%{?flatpak:/app}') + if path:match(prefix .. '/bin/python%d+%.%d+$') then + local provides = path:gsub('.*' .. prefix .. '/bin/python(%d+%.%d+)', 'python(abi) = %1') print(provides) end } @@ -18,10 +20,12 @@ -- generating a line of the form: -- python(abi) = MAJOR.MINOR local path = rpm.expand('%1') - if path:match('/usr/lib%d*/python%d+%.%d+/.*') then - local requires = path:gsub('.*/usr/lib%d*/python(%d+%.%d+)/.*', 'python(abi) = %1') + -- Use /usr prefix by default, and /app for flatpak builds + local prefix = rpm.expand('%{?!flatpak:/usr}%{?flatpak:/app}') + if path:match(prefix .. '/lib%d*/python%d+%.%d+/.*') then + local requires = path:gsub('.*' .. prefix .. '/lib%d*/python(%d+%.%d+)/.*', 'python(abi) = %1') print(requires) end } -%__python_path ^((%{_prefix}/lib(64)?/python[[:digit:]]+\\.[[:digit:]]+/.*\\.(py[oc]?|so))|(%{_bindir}/python[[:digit:]]+\\.[[:digit:]]+))$ +%__python_path ^((%{?!flatpak:/usr}%{?flatpak:/app}/lib(64)?/python[[:digit:]]+\\.[[:digit:]]+/.*\\.(py[oc]?|so))|(%{_bindir}/python[[:digit:]]+\\.[[:digit:]]+))$ diff --git a/pythondist.attr b/pythondist.attr index 42ae7ad..ede3a51 100644 --- a/pythondist.attr +++ b/pythondist.attr @@ -1,3 +1,3 @@ %__pythondist_provides %{_rpmconfigdir}/pythondistdeps.py --provides --normalized-names-format pep503 --package-name %{name} --majorver-provides-versions %{__default_python3_version} %{?!_python_dist_allow_version_zero:--fail-if-zero} %__pythondist_requires %{_rpmconfigdir}/pythondistdeps.py --requires --normalized-names-format pep503 --package-name %{name} %{?!_python_no_extras_requires:--require-extras-subpackages} --console-scripts-nodep-setuptools-since 3.10 -%__pythondist_path ^/usr/lib(64)?/python[3-9]\\.[[:digit:]]+/site-packages/[^/]+\\.(dist-info|egg-info|egg-link)$ +%__pythondist_path ^%{?!flatpak:/usr}%{?flatpak:/app}/lib(64)?/python[3-9]\\.[[:digit:]]+/site-packages/[^/]+\\.(dist-info|egg-info|egg-link)$ From e348b87fd9899d9f5938b8f2b1b0223ecb47f778 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Fri, 5 May 2023 13:31:19 +0200 Subject: [PATCH 097/110] License: Clarify pythonbundles.py license MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See https://gitlab.com/fedora/legal/fedora-license-data/-/issues/214 The script was only ever contributed to by me and Tomas Orsava. $ git log --format='%aN <%aE>' pythonbundles.py | sort -u Miro Hrončok Tomas Orsava This license clarification is: Signed-off-by: Miro Hrončok Signed-off-by: Tomas Orsava --- pythonbundles.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pythonbundles.py b/pythonbundles.py index 8adc36f..b0e5ecf 100755 --- a/pythonbundles.py +++ b/pythonbundles.py @@ -4,7 +4,7 @@ # This program is free software. # # It is placed in the public domain or under the CC0-1.0-Universal license, -# whichever is more permissive. +# whichever you choose. # # Alternatively, it may be redistributed and/or modified under the terms of # the LGPL version 2.1 (or later) or GPL version 2 (or later). From 50768e7a3de34a2800aa3c24f9d8526316a0fab4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Fri, 5 May 2023 14:14:41 +0200 Subject: [PATCH 098/110] Declare the license via a complex SPDX expression rather than "effective license" --- python-rpm-generators.spec | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 8f0a75b..0324781 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,19 +1,28 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 14 -Release: 4%{?dist} +Release: 5%{?dist} -# Originally all those files were part of RPM, so license is kept here -License: GPLv2+ Url: https://src.fedoraproject.org/python-rpm-generators -# Commit is the last change in following files + +# Originally the following files were part of RPM, so the license is inherited: GPL-2.0-or-later +# The COPYING file is grabbed from the last commit that changed the files Source0: https://raw.githubusercontent.com/rpm-software-management/rpm/102eab50b3d0d6546dfe082eac0ade21e6b3dbf1/COPYING Source1: python.attr Source2: pythondist.attr +# This was crafted in-place as a fork of python.attr, hence also GPL-2.0-or-later Source3: pythonname.attr +# This one is also originally from RPM, but it has its own license declaration: LGPL-2.1-or-later Source4: pythondistdeps.py +# This was crafted in-place with the following license declaration: +# LicenseRef-Fedora-Public-Domain OR CC0-1.0 OR LGPL-2.1-or-later OR GPL-2.0-or-later +# Note that CC0-1.0 is not allowed for code in Fedora, so we skip it in the package License tag Source5: pythonbundles.py +# See individual licenses above Source declarations +# Originally, this was simplified to GPL-2.0-or-later, but "effective license" analysis is no longer allowed +License: GPL-2.0-or-later AND LGPL-2.1-or-later AND (LicenseRef-Fedora-Public-Domain OR LGPL-2.1-or-later OR GPL-2.0-or-later) + BuildArch: noarch %description @@ -47,6 +56,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Fri May 05 2023 Miro Hrončok - 14-5 +- Declare the license via a complex SPDX expression rather than "effective license" + * Mon Apr 17 2023 Kalev Lember - 14-4 - Generate provides for /app-installed flatpak builds From f9b21eca49ad6b273790ec145097b46cc2d06d92 Mon Sep 17 00:00:00 2001 From: Todd Zullinger Date: Wed, 24 May 2023 12:58:14 -0400 Subject: [PATCH 099/110] Fix URL tag The Pagure instance at src.fedoraproject.org requires namespaces. This project is in the rpms namespace. Update the URL tag accordingly. --- python-rpm-generators.spec | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 0324781..9410a67 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,9 +1,9 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 14 -Release: 5%{?dist} +Release: 6%{?dist} -Url: https://src.fedoraproject.org/python-rpm-generators +Url: https://src.fedoraproject.org/rpms/python-rpm-generators # Originally the following files were part of RPM, so the license is inherited: GPL-2.0-or-later # The COPYING file is grabbed from the last commit that changed the files @@ -56,6 +56,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Wed May 24 2023 Todd Zullinger - 14-6 +- Fix URL tag + * Fri May 05 2023 Miro Hrončok - 14-5 - Declare the license via a complex SPDX expression rather than "effective license" From 8fe27ad070c104baac7e523fe241001892c24b46 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Fri, 21 Jul 2023 13:45:10 +0000 Subject: [PATCH 100/110] Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild Signed-off-by: Fedora Release Engineering --- python-rpm-generators.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 9410a67..2e46270 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 14 -Release: 6%{?dist} +Release: 7%{?dist} Url: https://src.fedoraproject.org/rpms/python-rpm-generators @@ -56,6 +56,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Fri Jul 21 2023 Fedora Release Engineering - 14-7 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild + * Wed May 24 2023 Todd Zullinger - 14-6 - Fix URL tag From 52372a464c70ebb29a285410327520c44e707135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Tue, 3 Oct 2023 12:07:49 +0200 Subject: [PATCH 101/110] Avoid DeprecationWarning: Implicit None on return values is deprecated and will raise KeyErrors The warning only happened on corrupted metadata. The warning originates in https://github.com/python/importlib_metadata/commit/880a6219a16911817214827020f272b4b03b54b4 --- python-rpm-generators.spec | 5 ++++- pythondistdeps.py | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 2e46270..8e76f05 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 14 -Release: 7%{?dist} +Release: 8%{?dist} Url: https://src.fedoraproject.org/rpms/python-rpm-generators @@ -56,6 +56,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Tue Oct 03 2023 Miro Hrončok - 14-8 +- Avoid DeprecationWarning: Implicit None on return values is deprecated and will raise KeyErrors + * Fri Jul 21 2023 Fedora Release Engineering - 14-7 - Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild diff --git a/pythondistdeps.py b/pythondistdeps.py index ec80125..b43ed39 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -94,8 +94,8 @@ class Distribution(PathDistribution): # that it works also on previous Python/importlib_metadata versions. @property def name(self): - """Return the 'Name' metadata for the distribution package.""" - return self.metadata['Name'] + """Return the 'Name' metadata for the distribution package or None.""" + return self.metadata.get('Name') def _parse_py_version(self, path): # Try to parse the Python version from the path the metadata From 592400f58bd11940aaddac443847fcc560910f0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Fri, 6 Oct 2023 11:59:15 +0200 Subject: [PATCH 102/110] Remove a no longer needed workaround for RPM <= 4.16 warning This removes an ugly hack that was used to get rid of: warning: Macro %1 defined but not used within scope I've noticed the %_pythonname_obsoletes generator does not expand %1 on non-RHELs and yet the warning is not shown. When debugging the missing warning, I've noticed it is never shown at all. According to RPM upstream, the warning was an undesired artifact: https://github.com/rpm-software-management/rpm/discussions/2501 It was purposefully removed starting with RPM 4.17. --- pythonname.attr | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/pythonname.attr b/pythonname.attr index 07d8df5..205570a 100644 --- a/pythonname.attr +++ b/pythonname.attr @@ -1,9 +1,6 @@ %__pythonname_provides() %{lua: local python = require 'fedora.srpm.python' - -- this macro is called for each file in a package, the path being in %1 - -- but we don't need to know the path, so we would get for each file: Macro %1 defined but not used within scope - -- in here, we expand %name conditionally on %1 to suppress the warning - local name = rpm.expand('%{?1:%{name}}') + local name = rpm.expand('%{name}') local evr = rpm.expand('%{?epoch:%{epoch}:}%{version}-%{release}') local provides = python.python_altprovides_once(name, evr) -- provides is either an array/table or nil @@ -23,10 +20,7 @@ -- In Fedora this is not needed as we don't ship ecosystem packages -- for alternative Python interpreters. local python = require 'fedora.srpm.python' - -- this macro is called for each file in a package, the path being in %1 - -- but we don't need to know the path, so we would get for each file: Macro %1 defined but not used within scope - -- in here, we expand %name conditionally on %1 to suppress the warning - local name = rpm.expand('%{?1:%{name}}') + local name = rpm.expand('%{name}') local evr = rpm.expand('%{?epoch:%{epoch}:}%{version}-%{release}') local obsoletes = python.python_altobsoletes_once(name, evr) -- obsoletes is either an array/table or nil From f3d6832f4d970041fd2297d6f7eece18bbf7a374 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Mon, 22 Jan 2024 06:41:25 +0000 Subject: [PATCH 103/110] Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild --- python-rpm-generators.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 8e76f05..bed427f 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 14 -Release: 8%{?dist} +Release: 9%{?dist} Url: https://src.fedoraproject.org/rpms/python-rpm-generators @@ -56,6 +56,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Mon Jan 22 2024 Fedora Release Engineering - 14-9 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild + * Tue Oct 03 2023 Miro Hrončok - 14-8 - Avoid DeprecationWarning: Implicit None on return values is deprecated and will raise KeyErrors From 223b71bb5e6d767ecfb3757c61ed09a38b756e8c Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Fri, 26 Jan 2024 10:19:05 +0000 Subject: [PATCH 104/110] Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild --- python-rpm-generators.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index bed427f..492cb8a 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 14 -Release: 9%{?dist} +Release: 10%{?dist} Url: https://src.fedoraproject.org/rpms/python-rpm-generators @@ -56,6 +56,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Fri Jan 26 2024 Fedora Release Engineering - 14-10 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild + * Mon Jan 22 2024 Fedora Release Engineering - 14-9 - Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild From 02ef9fde40ad2db7d33bbfda9dc1aabc24b72de8 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Fri, 19 Jul 2024 15:32:13 +0000 Subject: [PATCH 105/110] Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild --- python-rpm-generators.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 492cb8a..d014a53 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 14 -Release: 10%{?dist} +Release: 11%{?dist} Url: https://src.fedoraproject.org/rpms/python-rpm-generators @@ -56,6 +56,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Fri Jul 19 2024 Fedora Release Engineering - 14-11 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild + * Fri Jan 26 2024 Fedora Release Engineering - 14-10 - Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild From 91729cf8a0ad0d4b96865c61521b149169771765 Mon Sep 17 00:00:00 2001 From: Karolina Surma Date: Mon, 19 Aug 2024 14:24:39 +0200 Subject: [PATCH 106/110] CI: Look for the correct obsolete name in tests --- tests/pythonname.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/pythonname.sh b/tests/pythonname.sh index b21058c..f737a1f 100755 --- a/tests/pythonname.sh +++ b/tests/pythonname.sh @@ -43,7 +43,7 @@ test $(rpm -qp --obsoletes ${RPMDIR}/python${X_Y}-foo-0-0.noarch.rpm | wc -l) -e echo "Obsoletes for python3-foo" rpm -qp --obsoletes ${RPMDIR}/python3-foo-0-0.noarch.rpm # In ELN/RHEL the pythonX.Y-* Obsoletes is generated, but not in Fedora, so we check for it explicitly. -rpm -qp --obsoletes ${RPMDIR}/python3-foo-0-0.noarch.rpm | grep -q '^python'${X_Y}'-py_provides < 0-0$' && exit 1 || true +rpm -qp --obsoletes ${RPMDIR}/python3-foo-0-0.noarch.rpm | grep -q '^python'${X_Y}'-foo < 0-0$' && exit 1 || true test $(rpm -qp --obsoletes ${RPMDIR}/python3-foo-0-0.noarch.rpm | wc -l) -eq 0 echo "Obsoletes for python2-foo" From 03fc0de4acadafa264c319159953cd05a1fcee97 Mon Sep 17 00:00:00 2001 From: Karolina Surma Date: Wed, 6 Nov 2024 12:31:33 +0100 Subject: [PATCH 107/110] Add centpkg to use in CentOS Stream If tests are run in this repository, they exist. Other packages in Fedora require fedpkg-minimal to download the sources. We also want to run this test in CentOS Stream where fedpkg-minimal is not available, hence adding centpkg invocation. The change will have no effect in this repository, but is essential for the smooth tests run of other components. --- tests/download_data_and_run_pytest.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/download_data_and_run_pytest.sh b/tests/download_data_and_run_pytest.sh index 8dca398..79d54b5 100755 --- a/tests/download_data_and_run_pytest.sh +++ b/tests/download_data_and_run_pytest.sh @@ -4,10 +4,11 @@ # When the tests run in python-rpm-generators, # the structure on disk does not match the dist-git repository. # We apparently must use the standard-test-source role to grab the sources. -# OTOH in other packages, we must use fedpkg(-minimal). -# The --force flag is required in full-blown fedpkg (the source is unused in spec), -# and it is ignored in fedpkg-minimal (all sources are always downloaded). -test -f test-sources-*.tar.gz || fedpkg sources --force +# OTOH in other packages, we must use fedpkg(-minimal) or centpkg(-minimal), +# depending on the destination OS. +# The --force flag is required in full-blown fedpkg/centpkg (the source is unused in spec), +# and it is ignored in fedpkg/centpkg-minimal (all sources are always downloaded). +test -f test-sources-*.tar.gz || fedpkg sources --force || centpkg sources --force tar -xvf test-sources-*.tar.gz -C ./tests/data/scripts_pythondistdeps/ cd tests/ From db95d6e73506cf68fe981d1e01058a809026bdd8 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Sat, 18 Jan 2025 18:59:56 +0000 Subject: [PATCH 108/110] Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild --- python-rpm-generators.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index d014a53..36e283c 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 14 -Release: 11%{?dist} +Release: 12%{?dist} Url: https://src.fedoraproject.org/rpms/python-rpm-generators @@ -56,6 +56,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Sat Jan 18 2025 Fedora Release Engineering - 14-12 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild + * Fri Jul 19 2024 Fedora Release Engineering - 14-11 - Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild From 0bb99dc9e9765a8c8b190f84976cd3b1ce8cbb6e Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Fri, 25 Jul 2025 10:14:53 +0000 Subject: [PATCH 109/110] Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild --- python-rpm-generators.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 36e283c..599eb0c 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,7 +1,7 @@ Name: python-rpm-generators Summary: Dependency generators for Python RPMs Version: 14 -Release: 12%{?dist} +Release: 13%{?dist} Url: https://src.fedoraproject.org/rpms/python-rpm-generators @@ -56,6 +56,9 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} *.py %{_rpmconfigdir}/pythonbundles.py %changelog +* Fri Jul 25 2025 Fedora Release Engineering - 14-13 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild + * Sat Jan 18 2025 Fedora Release Engineering - 14-12 - Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild From b284634b222306626f32861772984c4d4cb21479 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Zachar?= Date: Mon, 28 Jul 2025 17:46:02 +0200 Subject: [PATCH 110/110] Drop STI and use tmt instead Resolves: rhbz#2383043 --- .fmf/version | 1 + plan.fmf | 45 +++++++++++++++++++++++++++++++++++++++++++++ tests/tests.yml | 48 ------------------------------------------------ 3 files changed, 46 insertions(+), 48 deletions(-) create mode 100644 .fmf/version create mode 100644 plan.fmf delete mode 100644 tests/tests.yml diff --git a/.fmf/version b/.fmf/version new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/.fmf/version @@ -0,0 +1 @@ +1 diff --git a/plan.fmf b/plan.fmf new file mode 100644 index 0000000..d2c549f --- /dev/null +++ b/plan.fmf @@ -0,0 +1,45 @@ +execute: + how: tmt + +discover: + - name: same_repo + how: shell + dist-git-source: true + dist-git-download-only: true + tests: + - name: pythonabi + path: /tests + test: ./pythonabi.sh + - name: pythonname + path: /tests + test: ./pythonname.sh + - name: pythondist + path: /tests + test: ./pythondist.sh + - name: console_script + path: /tests + test: ./console_script.sh + - name: pytest + test: cd $TMT_SOURCE_DIR && ./tests/download_data_and_run_pytest.sh + +prepare: + - name: Install dependencies + how: install + package: + - rpm-build + - rpmdevtools + - fedpkg-minimal + - python3-devel + - python3-pip + - python3-pytest + - python3-pyyaml + - python3-setuptools + - python3-wheel + - dnf + - name: Update packages + how: shell + script: dnf upgrade -y + - name: rpm_qa + order: 100 + how: shell + script: rpm -qa | sort | tee $TMT_PLAN_DATA/rpmqa.txt diff --git a/tests/tests.yml b/tests/tests.yml deleted file mode 100644 index 22b2cb7..0000000 --- a/tests/tests.yml +++ /dev/null @@ -1,48 +0,0 @@ ---- -- hosts: localhost - tags: - - classic - tasks: - - dnf: - name: "*" - state: latest - -- hosts: localhost - tags: - - classic - pre_tasks: - - import_role: - name: standard-test-source - vars: - fetch_only: True - roles: - - role: standard-test-basic - tests: - - rpm_qa: - dir: . - run: rpm -qa | sort - - pythonabi: - dir: . - run: ./pythonabi.sh - - pythonname: - dir: . - run: ./pythonname.sh - - pythondist: - dir: . - run: ./pythondist.sh - - console_script: - dir: . - run: ./console_script.sh - - pytest: - dir: . - run: ./download_data_and_run_pytest.sh - required_packages: - - rpm-build - - rpmdevtools - - fedpkg-minimal - - python3-devel - - python3-pip - - python3-pytest - - python3-pyyaml - - python3-setuptools - - python3-wheel