From d2ec6ae95be9dd3e6edae06821d4bb3201f20834 Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Thu, 21 Sep 2017 15:25:57 +0200 Subject: [PATCH 001/118] Switch bootsrapping macro to a bcond for modularity --- python-rpm-generators.spec | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 6909ee9..b2b07a2 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -14,7 +14,7 @@ # # More info on the Python 3 bootstrapping sequence in the `python3` spec file. # -%global bootstrapping_python 0 +%bcond_with bootstrap # Disable automatic (Python 2) bytecompilation in %%__os_install_post. @@ -43,7 +43,7 @@ Source0: http://ftp.rpm.org/releases/%{srcdir}/%{srcname}-%{srcver}.tar.b BuildArch: noarch -%if ! 0%{?bootstrapping_python} +%if %{without bootstrap} BuildRequires: python3-devel %endif @@ -85,7 +85,7 @@ and add appropriate Provides and Requires tags to them. %build -%if ! 0%{?bootstrapping_python} +%if %{without bootstrap} %{__python3} -m compileall scripts/ %endif @@ -96,7 +96,7 @@ install -Dm 755 scripts/pythondeps.sh \ scripts/pythondistdeps.py \ -t %{buildroot}/%{_rpmconfigdir} -%if ! 0%{?bootstrapping_python} +%if %{without bootstrap} install -Dm 755 scripts/__pycache__/* \ -t %{buildroot}/%{_rpmconfigdir}/__pycache__ %endif @@ -108,7 +108,7 @@ install -Dm 755 scripts/__pycache__/* \ %{_rpmconfigdir}/pythondeps.sh %{_rpmconfigdir}/pythondistdeps.py -%if ! 0%{?bootstrapping_python} +%if %{without bootstrap} %{_rpmconfigdir}/__pycache__ %endif From 17d4b252d8a209a31a35b3c41c1d8076d5fbf520 Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Thu, 21 Sep 2017 15:25:57 +0200 Subject: [PATCH 002/118] Bump the release, add a changelog entry --- 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 b2b07a2..281ab3a 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -28,7 +28,7 @@ # the two packages on the same upstream version. %global rpmver 4.14.0 #global snapver rc2 -%global rel 1 +%global rel 2 %global srcver %{version}%{?snapver:-%{snapver}} %global srcdir %{?snapver:testing}%{!?snapver:rpm-%(echo %{version} | cut -d'.' -f1-2).x} @@ -114,6 +114,9 @@ install -Dm 755 scripts/__pycache__/* \ %changelog +* Tue Nov 28 2017 Tomas Orsava - 4.14.0-2 +- Switch bootsrapping macro to a bcond for modularity + * Fri Oct 20 2017 Tomas Orsava - 4.14.0-1 - Rebase to rpm 4.14.0 final (http://rpm.org/wiki/Releases/4.14.0) - Re-synchronize version/release macros with the rpm Fedora package From f3aa2260196bc003868cf4a01a10be618c163322 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Fri, 9 Feb 2018 10:39:37 +0000 Subject: [PATCH 003/118] - Rebuilt for https://fedoraproject.org/wiki/Fedora_28_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 281ab3a..3f5ff6f 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -36,7 +36,7 @@ Name: python-rpm-generators Summary: Requires and Provides generators for Python RPMs Version: %{rpmver} -Release: %{?snapver:0.%{snapver}.}%{rel}%{?dist} +Release: %{?snapver:0.%{snapver}.}%{rel}%{?dist}.1 License: GPLv2+ Url: http://www.rpm.org/ Source0: http://ftp.rpm.org/releases/%{srcdir}/%{srcname}-%{srcver}.tar.bz2 @@ -114,6 +114,9 @@ install -Dm 755 scripts/__pycache__/* \ %changelog +* Fri Feb 09 2018 Fedora Release Engineering - 4.14.0-2.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + * Tue Nov 28 2017 Tomas Orsava - 4.14.0-2 - Switch bootsrapping macro to a bcond for modularity From ad70cabb97be9633470f50a50199f0a6b548f8cd Mon Sep 17 00:00:00 2001 From: Igor Gnatenko Date: Sun, 11 Feb 2018 00:00:36 +0100 Subject: [PATCH 004/118] Fork upstream generators This package is not being kept up to date, it's hard to maintain and we will need to tune it from time to time which is painful. Also removes whole layer of bootstrapping. Signed-off-by: Igor Gnatenko --- COPYING | 842 ++++++++++++++++++ python-rpm-generators.spec | 114 +-- python.attr | 4 + pythondeps.sh | 32 + pythondistdeps.py | 240 +++++ ....13.x-pythondeps-platform-python-abi.patch | 36 - rpm-4.13.x-pythondistdeps-Makefile.patch | 20 - rpm-4.13.x-pythondistdeps-fileattr.patch | 9 - rpm-4.13.x-pythondistdeps-python3.patch | 9 - rpm-4.13.x-pythondistdeps.patch | 229 ----- ...thondistdeps.py-add-forgotten-import.patch | 34 - ...hondistdeps.py-fix-processing-wheels.patch | 43 - ....x-pythondistdeps.py-platform-python.patch | 42 - ...y-show-warning-if-version-is-not-fou.patch | 29 - ...thondistdeps.py-skip-.egg-link-files.patch | 50 -- ...y-skip-distribution-metadata-if-ther.patch | 44 - 16 files changed, 1142 insertions(+), 635 deletions(-) create mode 100644 COPYING create mode 100644 python.attr create mode 100755 pythondeps.sh create mode 100755 pythondistdeps.py delete mode 100644 rpm-4.13.x-pythondeps-platform-python-abi.patch delete mode 100644 rpm-4.13.x-pythondistdeps-Makefile.patch delete mode 100644 rpm-4.13.x-pythondistdeps-fileattr.patch delete mode 100644 rpm-4.13.x-pythondistdeps-python3.patch delete mode 100644 rpm-4.13.x-pythondistdeps.patch delete mode 100644 rpm-4.13.x-pythondistdeps.py-add-forgotten-import.patch delete mode 100644 rpm-4.13.x-pythondistdeps.py-fix-processing-wheels.patch delete mode 100644 rpm-4.13.x-pythondistdeps.py-platform-python.patch delete mode 100644 rpm-4.13.x-pythondistdeps.py-show-warning-if-version-is-not-fou.patch delete mode 100644 rpm-4.13.x-pythondistdeps.py-skip-.egg-link-files.patch delete mode 100644 rpm-4.13.x-pythondistdeps.py-skip-distribution-metadata-if-ther.patch diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..3ffa0ab --- /dev/null +++ b/COPYING @@ -0,0 +1,842 @@ +RPM and it's source code are covered under two separate licenses. + +The entire code base may be distributed under the terms of the GNU General +Public License (GPL), which appears immediately below. Alternatively, +all of the source code in the lib subdirectory of the RPM source code +distribution as well as any code derived from that code may instead be +distributed under the GNU Library General Public License (LGPL), at the +choice of the distributor. The complete text of the LGPL appears +at the bottom of this file. + +This alternatively is allowed to enable applications to be linked against +the RPM library (commonly called librpm) without forcing such applications +to be distributed under the GPL. + +Any questions regarding the licensing of RPM should be addressed to +rpm-maint@lists.rpm.org + +--------------------------------------------------------------------------- + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + +--------------------------------------------------------------------------- + + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 3f5ff6f..0391177 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -1,106 +1,42 @@ -# This package is part of the Python 3 bootstrapping sequence. -# -# The python3-devel subpackage has a runtime dependency on this package. -# Therefore it needs to be built before Python 3 itself. To facilitate this, -# this package has a bootstrapping mode—triggered by the macro below—that skips -# bytecompilation and therefore no Python is actually needed for building of -# this package. After Python 3 is built, this package can be rebuilt in -# normal mode again. -# -# Note, however, that even the bootstrapping version of this package is fully -# functional as Python will simply bytecompile the Python files when they are -# run. There will be a warning that the bytecompiled file cannot be saved -# (unless Python is run with root privileges), but the script will work. -# -# More info on the Python 3 bootstrapping sequence in the `python3` spec file. -# -%bcond_with bootstrap - - -# Disable automatic (Python 2) bytecompilation in %%__os_install_post. -# When not in bootstrapping mode, the scripts are bytecompiled -# in the %%install section. +# Disable automatic bytecompilation. We install only one script and we will +# never "import" it. %undefine py_auto_byte_compile -%global srcname rpm - -# These macros are copied from the `rpm` package so it's trivial to keep -# the two packages on the same upstream version. -%global rpmver 4.14.0 -#global snapver rc2 -%global rel 2 - -%global srcver %{version}%{?snapver:-%{snapver}} -%global srcdir %{?snapver:testing}%{!?snapver:rpm-%(echo %{version} | cut -d'.' -f1-2).x} - Name: python-rpm-generators -Summary: Requires and Provides generators for Python RPMs -Version: %{rpmver} -Release: %{?snapver:0.%{snapver}.}%{rel}%{?dist}.1 +Summary: Dependency generators for Python RPMs +Version: 5 +Release: 1%{?dist} + +# Originally all those files were part of RPM, so license is kept here License: GPLv2+ -Url: http://www.rpm.org/ -Source0: http://ftp.rpm.org/releases/%{srcdir}/%{srcname}-%{srcver}.tar.bz2 +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 BuildArch: noarch -%if %{without bootstrap} -BuildRequires: python3-devel -%endif - -# Enable rich Provides generator (pythondistdeps.py instead of pythondeps.sh) -# Downstream only -Patch1: rpm-4.13.x-pythondistdeps-fileattr.patch -# Switch the shebang of pythondistdeps.py to Python 3 -# Downstream only: https://github.com/rpm-software-management/rpm/pull/212 -Patch2: rpm-4.13.x-pythondistdeps-python3.patch - -# Handle Platform-Python implemented as a separate Python stack -# https://fedoraproject.org/wiki/Changes/Platform_Python_Stack -Patch3: rpm-4.13.x-pythondeps-platform-python-abi.patch -Patch4: rpm-4.13.x-pythondistdeps.py-platform-python.patch - %description -This package provides scripts that analyse Python binary RPM packages -and add appropriate Provides and Requires tags to them. +%{summary}. - -%package -n python3-rpm-generators +%package -n python3-rpm-generators Summary: %{summary} Requires: python3-setuptools -# We're installing files into rpm's directories, therefore we're requiring it -# to be installed so the directories are created. -Requires: rpm -# Conflicts with older versions of `rpm-build` because it copies several files -# to the same locations which is ok only when they have the same contents. +# The point of split Conflicts: rpm-build < 4.13.0.1-2 -%{?python_provide:%python_provide python3-rpm-generators} %description -n python3-rpm-generators -This package provides scripts that analyse Python binary RPM packages -and add appropriate Provides and Requires tags to them. - +%{summary}. %prep -%autosetup -n %{srcname}-%{srcver} -p1 - - -%build -%if %{without bootstrap} -%{__python3} -m compileall scripts/ -%endif - +%autosetup -c -T +cp -a %{sources} . %install -install -Dm 644 fileattrs/python.attr -t %{buildroot}/%{_fileattrsdir} -install -Dm 755 scripts/pythondeps.sh \ - scripts/pythondistdeps.py \ - -t %{buildroot}/%{_rpmconfigdir} - -%if %{without bootstrap} -install -Dm 755 scripts/__pycache__/* \ - -t %{buildroot}/%{_rpmconfigdir}/__pycache__ -%endif - +install -Dpm0644 -t %{buildroot}%{_fileattrsdir} python.attr +install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} pythondeps.sh pythondistdeps.py %files -n python3-rpm-generators %license COPYING @@ -108,12 +44,10 @@ install -Dm 755 scripts/__pycache__/* \ %{_rpmconfigdir}/pythondeps.sh %{_rpmconfigdir}/pythondistdeps.py -%if %{without bootstrap} -%{_rpmconfigdir}/__pycache__ -%endif - - %changelog +* Sun Feb 11 2018 Igor Gnatenko - 5-1 +- Fork upstream generators + * Fri Feb 09 2018 Fedora Release Engineering - 4.14.0-2.1 - Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild diff --git a/python.attr b/python.attr new file mode 100644 index 0000000..0f3c2cc --- /dev/null +++ b/python.attr @@ -0,0 +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_magic [Pp]ython.*(executable|byte-compiled) diff --git a/pythondeps.sh b/pythondeps.sh new file mode 100755 index 0000000..10a060a --- /dev/null +++ b/pythondeps.sh @@ -0,0 +1,32 @@ +#!/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 diff --git a/pythondistdeps.py b/pythondistdeps.py new file mode 100755 index 0000000..2abb59f --- /dev/null +++ b/pythondistdeps.py @@ -0,0 +1,240 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright 2010 Per Øyvind Karlsen +# Copyright 2015 Neal Gompa +# +# This program is free software. It may be redistributed and/or modified under +# the terms of the LGPL version 2.1 (or later). +# +# RPM python dependency generator, using .egg-info/.egg-link/.dist-info data +# + +from __future__ import print_function +from getopt import getopt +from os.path import basename, dirname, isdir, sep +from sys import argv, stdin, version +from distutils.sysconfig import get_python_lib +from warnings import warn + + +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 + +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 +py_deps = {} +if args: + files = args +else: + files = stdin.readlines() + +for f in files: + 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=1, plat_specific=0).split(version[:3])[0] + platlib = get_python_lib(standard_lib=1, 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 + from pkg_resources import Distribution, FileMetadata, PathMetadata + 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 + if Provides_PyMajorVer_Variant or PyMajorVer_Deps or legacy_Provides or legacy: + # Get the Python major version + pyver_major = dist.py_version.split('.')[0] + if 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: + name = 'python{}dist({})'.format(dist.py_version, dist.key) + 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] = [] + if legacy or legacy_Provides: + legacy_name = 'pythonegg({})({})'.format(pyver_major, dist.key) + if legacy_name not in py_deps: + py_deps[legacy_name] = [] + if dist.version: + spec = ('==', dist.version) + if spec not in py_deps[name]: + if not legacy: + py_deps[name].append(spec) + if Provides_PyMajorVer_Variant: + py_deps[pymajor_name].append(spec) + if legacy or legacy_Provides: + py_deps[legacy_name].append(spec) + if Requires or (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 Recommends: + depsextras = dist.requires(extras=dist.extras) + if not Requires: + for dep in reversed(depsextras): + if dep in deps: + depsextras.remove(dep) + deps = depsextras + # add requires/recommends based on egg/dist metadata + for dep in deps: + if legacy: + name = 'pythonegg({})({})'.format(pyver_major, dep.key) + else: + if PyMajorVer_Deps: + name = 'python{}dist({})'.format(pyver_major, dep.key) + 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) + 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 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: + 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 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) +names = list(py_deps.keys()) +names.sort() +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])) + else: + # Print out unversioned provides, requires, recommends, conflicts + print(name) diff --git a/rpm-4.13.x-pythondeps-platform-python-abi.patch b/rpm-4.13.x-pythondeps-platform-python-abi.patch deleted file mode 100644 index b44e900..0000000 --- a/rpm-4.13.x-pythondeps-platform-python-abi.patch +++ /dev/null @@ -1,36 +0,0 @@ -From fef3b646f3facd26dc04cfccdc27c061cfe0ee37 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= -Date: Mon, 7 Aug 2017 16:28:59 +0200 -Subject: [PATCH] Generate requires and provides for platform-python(abi) - -See https://fedoraproject.org/wiki/Changes/Platform_Python_Stack ---- - scripts/pythondeps.sh | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/scripts/pythondeps.sh b/scripts/pythondeps.sh -index 10a060aac..a6d97ef4f 100755 ---- a/scripts/pythondeps.sh -+++ b/scripts/pythondeps.sh -@@ -13,8 +13,8 @@ case $1 in - # 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|" -+ egrep '/usr/(bin/|libexec/platform-)python.\..$' \ -+ | sed -r -e "s@.*/usr/(bin/|libexec/(platform-))python(.\..)@\2python(abi) = \3@" - ;; - -R|--requires) - shift -@@ -23,8 +23,8 @@ case $1 in - # /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" \ -+ egrep '/usr/lib[^/]*/(platform-|)python.\../.*' \ -+ | sed -r -e "s@.*/usr/lib[^/]*/(platform-|)python(.\..)/.*@\1python(abi) = \2@g" \ - | sort | uniq - ;; - esac diff --git a/rpm-4.13.x-pythondistdeps-Makefile.patch b/rpm-4.13.x-pythondistdeps-Makefile.patch deleted file mode 100644 index dfdaf00..0000000 --- a/rpm-4.13.x-pythondistdeps-Makefile.patch +++ /dev/null @@ -1,20 +0,0 @@ ---- rpm-4.13.0-rc1/scripts/Makefile.am.orig 2015-09-01 19:45:43.896822977 +0200 -+++ rpm-4.13.0-rc1/scripts/Makefile.am 2016-06-13 15:46:34.281390084 +0200 -@@ -11,7 +11,7 @@ - check-files check-prereqs \ - check-buildroot check-rpaths check-rpaths-worker \ - find-debuginfo.sh find-lang.sh \ -- perl.prov perl.req pythondeps.sh \ -+ perl.prov perl.req pythondeps.sh pythondistdeps.py \ - rpmdb_loadcvt rpm.daily rpm.log rpm.supp rpm2cpio.sh \ - tgpg vpkg-provides.sh \ - find-requires find-provides \ -@@ -30,7 +30,7 @@ - check-files check-prereqs \ - check-buildroot check-rpaths check-rpaths-worker \ - find-lang.sh find-requires find-provides \ -- perl.prov perl.req pythondeps.sh \ -+ perl.prov perl.req pythondeps.sh pythondistdeps.py \ - mono-find-requires mono-find-provides \ - pkgconfigdeps.sh libtooldeps.sh \ - ocaml-find-requires.sh ocaml-find-provides.sh \ diff --git a/rpm-4.13.x-pythondistdeps-fileattr.patch b/rpm-4.13.x-pythondistdeps-fileattr.patch deleted file mode 100644 index 72ab9e6..0000000 --- a/rpm-4.13.x-pythondistdeps-fileattr.patch +++ /dev/null @@ -1,9 +0,0 @@ ---- rpm-4.13.0-rc1/fileattrs/python.attr.orig 2016-06-13 15:49:10.072832164 +0200 -+++ rpm-4.13.0-rc1/fileattrs/python.attr 2016-06-13 15:50:46.687106846 +0200 -@@ -1,4 +1,4 @@ --%__python_provides %{_rpmconfigdir}/pythondeps.sh --provides -+%__python_provides %{_rpmconfigdir}/pythondistdeps.py --provides --majorver-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:]]/.*))|(%{_bindir}/python[[:digit:]]\\.[[:digit:]]))$ - %__python_magic [Pp]ython.*(executable|byte-compiled) diff --git a/rpm-4.13.x-pythondistdeps-python3.patch b/rpm-4.13.x-pythondistdeps-python3.patch deleted file mode 100644 index eb4c6ae..0000000 --- a/rpm-4.13.x-pythondistdeps-python3.patch +++ /dev/null @@ -1,9 +0,0 @@ -diff -uNr rpm-4.13.0.orig/scripts/pythondistdeps.py rpm-4.13.0/scripts/pythondistdeps.py ---- rpm-4.13.0.orig/scripts/pythondistdeps.py 2016-12-18 12:25:21.287632679 +0100 -+++ rpm-4.13.0/scripts/pythondistdeps.py 2016-12-18 12:25:48.857479226 +0100 -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # -*- coding: utf-8 -*- - # - # Copyright 2010 Per Øyvind Karlsen diff --git a/rpm-4.13.x-pythondistdeps.patch b/rpm-4.13.x-pythondistdeps.patch deleted file mode 100644 index 695393c..0000000 --- a/rpm-4.13.x-pythondistdeps.patch +++ /dev/null @@ -1,229 +0,0 @@ -diff --git a/scripts/pythondistdeps.py b/scripts/pythondistdeps.py -new file mode 100755 -index 0000000..8a2f43d ---- /dev/null -+++ b/scripts/pythondistdeps.py -@@ -0,0 +1,223 @@ -+#!/usr/bin/python -+# -*- coding: utf-8 -*- -+# -+# Copyright 2010 Per Øyvind Karlsen -+# Copyright 2015 Neal Gompa -+# -+# This program is free software. It may be redistributed and/or modified under -+# the terms of the LGPL version 2.1 (or later). -+# -+# RPM python dependency generator, using .egg-info/.egg-link/.dist-info data -+# -+ -+from __future__ import print_function -+from getopt import getopt -+from os.path import basename, dirname, isdir, sep -+from sys import argv, stdin, version -+from distutils.sysconfig import get_python_lib -+ -+ -+opts, args = getopt( -+ argv[1:], 'hPRrCEMLl:', -+ ['help', 'provides', 'requires', 'recommends', 'conflicts', 'extras', 'majorver-provides', 'legacy-provides' , 'legacy']) -+ -+Provides = False -+Requires = False -+Recommends = False -+Conflicts = False -+Extras = False -+Provides_PyMajorVer_Variant = False -+legacy_Provides = False -+legacy = False -+ -+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('-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 ('-L', '--legacy-provides'): -+ legacy_Provides = True -+ elif o in ('-l', '--legacy'): -+ legacy = True -+ -+if Requires: -+ py_abi = True -+else: -+ py_abi = False -+py_deps = {} -+if args: -+ files = args -+else: -+ files = stdin.readlines() -+ -+for f in files: -+ 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=1, plat_specific=0).split(version[:3])[0] -+ platlib = get_python_lib(standard_lib=1, 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('.egg-link') 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('.egg-link') or \ -+ lower.endswith('.dist-info'): -+ # This import is very slow, so only do it if needed -+ from pkg_resources import Distribution, FileMetadata, PathMetadata -+ 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) -+ if (Provides_PyMajorVer_Variant or legacy_Provides or legacy) and Provides: -+ # Get the Python major version -+ pyver_major = dist.py_version.split('.')[0] -+ if 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: -+ name = 'python{}dist({})'.format(dist.py_version, dist.key) -+ if name not in py_deps: -+ py_deps[name] = [] -+ if Provides_PyMajorVer_Variant: -+ pymajor_name = 'python{}dist({})'.format(pyver_major, dist.key) -+ 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: -+ py_deps[legacy_name] = [] -+ if dist.version: -+ spec = ('==', dist.version) -+ if spec not in py_deps[name]: -+ if not legacy: -+ py_deps[name].append(spec) -+ if Provides_PyMajorVer_Variant: -+ py_deps[pymajor_name].append(spec) -+ if legacy or legacy_Provides: -+ py_deps[legacy_name].append(spec) -+ if Requires or (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 Recommends: -+ depsextras = dist.requires(extras=dist.extras) -+ if not Requires: -+ for dep in reversed(depsextras): -+ if dep in deps: -+ depsextras.remove(dep) -+ deps = depsextras -+ # add requires/recommends based on egg/dist metadata -+ for dep in deps: -+ if legacy: -+ name = 'pythonegg({})({})'.format(pyver_major, dep.key) -+ 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) -+ 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 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: -+ 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 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) -+names = list(py_deps.keys()) -+names.sort() -+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])) -+ else: -+ # Print out unversioned provides, requires, recommends, conflicts -+ print(name) diff --git a/rpm-4.13.x-pythondistdeps.py-add-forgotten-import.patch b/rpm-4.13.x-pythondistdeps.py-add-forgotten-import.patch deleted file mode 100644 index 2a0b121..0000000 --- a/rpm-4.13.x-pythondistdeps.py-add-forgotten-import.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 30d472c8af086df077e6cf047a87fdaf93c9b21b Mon Sep 17 00:00:00 2001 -From: Igor Gnatenko -Date: Wed, 24 Aug 2016 15:37:16 +0200 -Subject: [PATCH] pythondistdeps.py: add forgotten import - -Signed-off-by: Igor Gnatenko ---- - scripts/pythondistdeps.py | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/scripts/pythondistdeps.py b/scripts/pythondistdeps.py -index 76017f3..e4b99e2 100755 ---- a/scripts/pythondistdeps.py -+++ b/scripts/pythondistdeps.py -@@ -15,6 +15,7 @@ from getopt import getopt - from os.path import basename, dirname, isdir, sep - from sys import argv, stdin, version - from distutils.sysconfig import get_python_lib -+from warnings import warn - - - opts, args = getopt( -@@ -108,7 +109,7 @@ for f in files: - dist = Distribution.from_location(path_item, dist_name, metadata) - # Check if py_version is defined in the file - if not dist.py_version: -- warnings.warn("Version for {!r} has not been found".format(dist), RuntimeWarning) -+ warn("Version for {!r} has not been found".format(dist), RuntimeWarning) - continue - if (Provides_PyMajorVer_Variant or legacy_Provides or legacy) and Provides: - # Get the Python major version --- -2.9.3 - diff --git a/rpm-4.13.x-pythondistdeps.py-fix-processing-wheels.patch b/rpm-4.13.x-pythondistdeps.py-fix-processing-wheels.patch deleted file mode 100644 index 7aa5eb3..0000000 --- a/rpm-4.13.x-pythondistdeps.py-fix-processing-wheels.patch +++ /dev/null @@ -1,43 +0,0 @@ -From ff395f4a820497a443baa6cd0198c49b06207c3f Mon Sep 17 00:00:00 2001 -From: Tomas Orsava -Date: Thu, 16 Feb 2017 11:36:29 +0100 -Subject: [PATCH] Fix pythondistdeps.py --provides for Python wheels - -As Python wheels do not contain targetted Python version in the directory/file -name of their metadata like Python eggs do, and since the Python version is not -contained in the metadata either, it is necessary to get it from elsewhere. - -Here it is parsed from the path the metadata resides at -(e.g. /usr/lib/pythonX.Y/site-packages/...) ---- - scripts/pythondistdeps.py | 13 ++++++++++--- - 1 file changed, 10 insertions(+), 3 deletions(-) - -diff --git a/scripts/pythondistdeps.py b/scripts/pythondistdeps.py -index e4b99e2..d44210c 100644 ---- a/scripts/pythondistdeps.py -+++ b/scripts/pythondistdeps.py -@@ -107,10 +107,17 @@ for f in files: - path_item = f - metadata = FileMetadata(f) - dist = Distribution.from_location(path_item, dist_name, metadata) -- # Check if py_version is defined in the file -+ # Check if py_version is defined in the metadata file/directory name - if not dist.py_version: -- warn("Version for {!r} has not been found".format(dist), RuntimeWarning) -- continue -+ # 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 - if (Provides_PyMajorVer_Variant or legacy_Provides or legacy) and Provides: - # Get the Python major version - pyver_major = dist.py_version.split('.')[0] --- -2.11.0 - diff --git a/rpm-4.13.x-pythondistdeps.py-platform-python.patch b/rpm-4.13.x-pythondistdeps.py-platform-python.patch deleted file mode 100644 index 8afbf3b..0000000 --- a/rpm-4.13.x-pythondistdeps.py-platform-python.patch +++ /dev/null @@ -1,42 +0,0 @@ -From eb48f08dd30324f960b8e404b80eb885b2bbb593 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= -Date: Thu, 24 Aug 2017 13:45:49 +0200 -Subject: [PATCH] Do not provide pythonXdist for platform-python packages - ---- - scripts/pythondistdeps.py | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/scripts/pythondistdeps.py b/scripts/pythondistdeps.py -index 2abb59f49..f624fdbb7 100755 ---- a/scripts/pythondistdeps.py -+++ b/scripts/pythondistdeps.py -@@ -16,6 +16,7 @@ from os.path import basename, dirname, isdir, sep - from sys import argv, stdin, version - from distutils.sysconfig import get_python_lib - from warnings import warn -+import re - - - opts, args = getopt( -@@ -78,6 +79,9 @@ for f in files: - f = f.strip() - lower = f.lower() - name = 'python(abi)' -+ if re.search(r'/usr/lib(64)?/platform-python\d\.\d', lower): -+ # https://bugzilla.redhat.com/show_bug.cgi?id=1484607 -+ continue - # 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: -@@ -115,7 +119,6 @@ for f in files: - 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') --- -2.13.5 - diff --git a/rpm-4.13.x-pythondistdeps.py-show-warning-if-version-is-not-fou.patch b/rpm-4.13.x-pythondistdeps.py-show-warning-if-version-is-not-fou.patch deleted file mode 100644 index 0db2977..0000000 --- a/rpm-4.13.x-pythondistdeps.py-show-warning-if-version-is-not-fou.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 2f51022e1586a9b3ac8036b23995074b00910475 Mon Sep 17 00:00:00 2001 -From: Igor Gnatenko -Date: Mon, 22 Aug 2016 12:55:50 +0200 -Subject: [PATCH 2/3] pythondistdeps.py: show warning if version is not found - in metadata - -In 49197c930bb6090d0fca4089ea75ec9d10e62f99 we introduced skipping -metadata which has no version, but it's better to show some warning. - -Signed-off-by: Igor Gnatenko ---- - scripts/pythondistdeps.py | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/scripts/pythondistdeps.py b/scripts/pythondistdeps.py -index 54905c3..d7226e0 100755 ---- a/scripts/pythondistdeps.py -+++ b/scripts/pythondistdeps.py -@@ -110,6 +110,7 @@ for f in files: - dist = Distribution.from_location(path_item, dist_name, metadata) - # Check if py_version is defined in the file - if not dist.py_version: -+ warnings.warn("Version for {!r} has not been found".format(dist), RuntimeWarning) - continue - if (Provides_PyMajorVer_Variant or legacy_Provides or legacy) and Provides: - # Get the Python major version --- -2.9.3 - diff --git a/rpm-4.13.x-pythondistdeps.py-skip-.egg-link-files.patch b/rpm-4.13.x-pythondistdeps.py-skip-.egg-link-files.patch deleted file mode 100644 index a555ed5..0000000 --- a/rpm-4.13.x-pythondistdeps.py-skip-.egg-link-files.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 83e4d44b802d39dfbd407488c0d9f629799b809c Mon Sep 17 00:00:00 2001 -From: Igor Gnatenko -Date: Mon, 22 Aug 2016 12:56:05 +0200 -Subject: [PATCH 3/3] pythondistdeps.py: skip .egg-link files - -From setuptools's documentation: -These files are not eggs, strictly speaking. They simply provide a way -to reference an egg that is not physically installed in the desired -location. They exist primarily as a cross-platform alternative to -symbolic links, to support "installing" code that is being developed in -a different location than the desired installation location. - -If we read .egg-link using pkg_resources.Distribution it will -never have version as it is just list of directories which should be -taken into account. - -We could change into that directories and add eggs from those locations -for parsing, but RPM's dependency generator already passing all files -from built RPM so it just does not make any sense to traverse those -directories. - -After all written above, let's just ignore .egg-link files. - -Signed-off-by: Igor Gnatenko ---- - scripts/pythondistdeps.py | 2 -- - 1 file changed, 2 deletions(-) - -diff --git a/scripts/pythondistdeps.py b/scripts/pythondistdeps.py -index d7226e0..76017f3 100755 ---- a/scripts/pythondistdeps.py -+++ b/scripts/pythondistdeps.py -@@ -89,14 +89,12 @@ for f in files: - lower_dir = dirname(lower) - if lower_dir.endswith('.egg') or \ - lower_dir.endswith('.egg-info') or \ -- lower_dir.endswith('.egg-link') 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('.egg-link') or \ - lower.endswith('.dist-info'): - # This import is very slow, so only do it if needed - from pkg_resources import Distribution, FileMetadata, PathMetadata --- -2.9.3 - diff --git a/rpm-4.13.x-pythondistdeps.py-skip-distribution-metadata-if-ther.patch b/rpm-4.13.x-pythondistdeps.py-skip-distribution-metadata-if-ther.patch deleted file mode 100644 index 4279f9c..0000000 --- a/rpm-4.13.x-pythondistdeps.py-skip-distribution-metadata-if-ther.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 49197c930bb6090d0fca4089ea75ec9d10e62f99 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Neal=20Gompa=20=28=E3=83=8B=E3=83=BC=E3=83=AB=E3=83=BB?= - =?UTF-8?q?=E3=82=B3=E3=82=99=E3=83=B3=E3=83=8F=E3=82=9A=29?= - -Date: Sat, 20 Aug 2016 11:01:06 -0400 -Subject: [PATCH 1/3] pythondistdeps.py: skip distribution metadata if there is - no version - -For example, reading .egg-link using pkg_resources.Distribution returns -actual metadata, but it does not contain version. It returns traceback like: - -File "/usr/lib/rpm/pythondistdeps.py", line 113, in - pyver_major = dist.py_version.split('.')[0] -AttributeError: 'NoneType' object has no attribute 'split' -Traceback (most recent call last): - File "/usr/lib/rpm/pythondistdeps.py", line 113, in - pyver_major = dist.py_version.split('.')[0] -AttributeError: 'NoneType' object has no attribute 'split' - -Let's just skip such errors as we can't do much about that. - -Reference: https://bugzilla.redhat.com/show_bug.cgi?id=1368673 -Reported-and-tested-by: Igor Gnatenko ---- - scripts/pythondistdeps.py | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/scripts/pythondistdeps.py b/scripts/pythondistdeps.py -index 8a2f43d..54905c3 100755 ---- a/scripts/pythondistdeps.py -+++ b/scripts/pythondistdeps.py -@@ -108,6 +108,9 @@ for f in files: - path_item = f - metadata = FileMetadata(f) - dist = Distribution.from_location(path_item, dist_name, metadata) -+ # Check if py_version is defined in the file -+ if not dist.py_version: -+ continue - if (Provides_PyMajorVer_Variant or legacy_Provides or legacy) and Provides: - # Get the Python major version - pyver_major = dist.py_version.split('.')[0] --- -2.9.3 - From 257dcc8865ec63d631e0b6f8f139000ca6b7e948 Mon Sep 17 00:00:00 2001 From: Igor Gnatenko Date: Sun, 11 Feb 2018 00:49:59 +0100 Subject: [PATCH 005/118] attr: print provides in modern format Signed-off-by: Igor Gnatenko --- python.attr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python.attr b/python.attr index 0f3c2cc..17856bf 100644 --- a/python.attr +++ b/python.attr @@ -1,4 +1,4 @@ -%__python_provides %{_rpmconfigdir}/pythondeps.sh --provides +%__python_provides %{_rpmconfigdir}/pythondistdeps.py --provides --majorver-provides %__python_requires %{_rpmconfigdir}/pythondeps.sh --requires %__python_path ^((/usr/lib(64)?/python[[:digit:]]\\.[[:digit:]]/.*\\.(py[oc]?|so))|(%{_bindir}/python[[:digit:]]\\.[[:digit:]]))$ %__python_magic [Pp]ython.*(executable|byte-compiled) From 6d7c3b291d59f98e8cd6f135dcdae7a6ae30a882 Mon Sep 17 00:00:00 2001 From: Igor Gnatenko Date: Sun, 11 Feb 2018 00:50:17 +0100 Subject: [PATCH 006/118] attr: match everything in python directories Signed-off-by: Igor Gnatenko --- python.attr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python.attr b/python.attr index 17856bf..a7381d6 100644 --- a/python.attr +++ b/python.attr @@ -1,4 +1,4 @@ %__python_provides %{_rpmconfigdir}/pythondistdeps.py --provides --majorver-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:]]/.*))|(%{_bindir}/python[[:digit:]]\\.[[:digit:]]))$ %__python_magic [Pp]ython.*(executable|byte-compiled) From b3ca5d86225bcff7764466dd90c6cc7b7b064dd9 Mon Sep 17 00:00:00 2001 From: Igor Gnatenko Date: Sun, 11 Feb 2018 00:49:22 +0100 Subject: [PATCH 007/118] pythondistdeps.py: change shebang to python3 Signed-off-by: Igor Gnatenko --- pythondistdeps.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pythondistdeps.py b/pythondistdeps.py index 2abb59f..36590ba 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/python3 # -*- coding: utf-8 -*- # # Copyright 2010 Per Øyvind Karlsen From 5aa670bb3967c0e12163722fd274549ca0187ba6 Mon Sep 17 00:00:00 2001 From: Igor Gnatenko Date: Sun, 11 Feb 2018 00:32:23 +0100 Subject: [PATCH 008/118] "Fix" support of environment markers Signed-off-by: Igor Gnatenko --- python-rpm-generators.spec | 1 + pythondistdeps.py | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/python-rpm-generators.spec b/python-rpm-generators.spec index 0391177..33196c7 100644 --- a/python-rpm-generators.spec +++ b/python-rpm-generators.spec @@ -47,6 +47,7 @@ install -Dpm0755 -t %{buildroot}%{_rpmconfigdir} pythondeps.sh pythondistdeps.py %changelog * Sun Feb 11 2018 Igor Gnatenko - 5-1 - Fork upstream generators +- "Fix" support of environment markers * Fri Feb 09 2018 Fedora Release Engineering - 4.14.0-2.1 - Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild diff --git a/pythondistdeps.py b/pythondistdeps.py index 36590ba..a15ccba 100755 --- a/pythondistdeps.py +++ b/pythondistdeps.py @@ -122,6 +122,11 @@ for f in files: else: warn("Version for {!r} has not been found".format(dist), RuntimeWarning) continue + + # XXX: https://github.com/pypa/setuptools/pull/1275 + 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] From 0fb362073aac1ef8395b6ac72d5d03b31f4cec61 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Sat, 14 Jul 2018 01:58:03 +0000 Subject: [PATCH 009/118] - 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 010/118] 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 011/118] 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 012/118] 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 013/118] 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 014/118] 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 015/118] 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 016/118] 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 017/118] 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 018/118] - 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 019/118] 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 020/118] 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 021/118] - 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 022/118] 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 023/118] 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 024/118] 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 025/118] - 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 026/118] 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 027/118] 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 028/118] 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 029/118] 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 030/118] 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 031/118] 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 032/118] 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 033/118] 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 034/118] 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 035/118] 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 036/118] 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 037/118] 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 038/118] 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 039/118] 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 040/118] 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 041/118] 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 042/118] 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 043/118] 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 044/118] 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 045/118] 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 046/118] 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 047/118] 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 048/118] 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 049/118] 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 050/118] 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 051/118] 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 052/118] 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 053/118] 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 054/118] 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 055/118] 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 056/118] 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 057/118] 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 058/118] 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 059/118] 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 060/118] 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 061/118] - 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 062/118] 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 063/118] 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 064/118] 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 065/118] 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 066/118] - 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 067/118] 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 068/118] 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 069/118] 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 070/118] 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 071/118] 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 072/118] 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 073/118] 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 074/118] 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 075/118] 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 076/118] 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 077/118] 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 078/118] 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 079/118] 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 080/118] 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 081/118] - 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 082/118] 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 083/118] 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 084/118] 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 085/118] - 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 086/118] 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 087/118] 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 088/118] 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 089/118] 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 090/118] 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 091/118] 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 092/118] 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 093/118] 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 094/118] 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 095/118] 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 096/118] 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 097/118] 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 098/118] 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 099/118] 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 100/118] 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 101/118] 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 102/118] 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 103/118] 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 104/118] 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 105/118] 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 106/118] 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 107/118] 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 108/118] 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 109/118] 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 110/118] 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 111/118] 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 112/118] 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 113/118] 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 114/118] 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 115/118] 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 116/118] 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 117/118] 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 118/118] 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