From 62b8877483461a18bd99de1122f8373a23223602 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Oct 06 2021 16:43:09 +0000 Subject: import dnf-plugins-core-4.0.21-2.el8 --- diff --git a/.dnf-plugins-core.metadata b/.dnf-plugins-core.metadata index fc3009b..40ecba9 100644 --- a/.dnf-plugins-core.metadata +++ b/.dnf-plugins-core.metadata @@ -1 +1 @@ -3b8638dec2cb91a13241106b9a57114ed037d2ca SOURCES/dnf-plugins-core-4.0.18.tar.gz +40f26a50a6605eacb1e9c4a443f01655fa461767 SOURCES/dnf-plugins-core-4.0.21.tar.gz diff --git a/.gitignore b/.gitignore index dae8243..ae4a8af 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/dnf-plugins-core-4.0.18.tar.gz +SOURCES/dnf-plugins-core-4.0.21.tar.gz diff --git a/SOURCES/0001-groups-manager-Re-introduce-yum-groups-manager-funct.patch b/SOURCES/0001-groups-manager-Re-introduce-yum-groups-manager-funct.patch deleted file mode 100644 index ddebf40..0000000 --- a/SOURCES/0001-groups-manager-Re-introduce-yum-groups-manager-funct.patch +++ /dev/null @@ -1,653 +0,0 @@ -From 40f08d7a22907e6292c314462c01de94584c0854 Mon Sep 17 00:00:00 2001 -From: Marek Blaha -Date: Tue, 27 Oct 2020 15:46:03 +0100 -Subject: [PATCH 1/2] [groups-manager] Re-introduce yum-groups-manager - functionality (RhBug:1826016) - -Implements 'dnf groups-manager' command with features: -- read, merge, print and write groups metadata files -- edit group attributes name (with translated variants), - description (with translated variants), uservisible, displayorder -- add packgages to group -- remove packages from group - -= changelog = -msg: Re-introduce yum-groups-manager functionality -type: enhancement -resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1826016 ---- - dnf-plugins-core.spec | 22 ++- - doc/CMakeLists.txt | 2 + - doc/conf.py | 2 + - doc/groups-manager.rst | 94 ++++++++++++ - doc/index.rst | 1 + - libexec/dnf-utils.in | 1 + - plugins/CMakeLists.txt | 1 + - plugins/groups_manager.py | 314 ++++++++++++++++++++++++++++++++++++++ - 8 files changed, 432 insertions(+), 5 deletions(-) - create mode 100644 doc/groups-manager.rst - create mode 100644 plugins/groups_manager.py - -diff --git a/dnf-plugins-core.spec b/dnf-plugins-core.spec -index d13a996..42d0884 100644 ---- a/dnf-plugins-core.spec -+++ b/dnf-plugins-core.spec -@@ -58,6 +58,7 @@ Provides: dnf-command(debug-dump) - Provides: dnf-command(debug-restore) - Provides: dnf-command(debuginfo-install) - Provides: dnf-command(download) -+Provides: dnf-command(groups-manager) - Provides: dnf-command(repoclosure) - Provides: dnf-command(repograph) - Provides: dnf-command(repomanage) -@@ -73,6 +74,7 @@ Provides: dnf-plugin-debuginfo-install = %{version}-%{release} - Provides: dnf-plugin-download = %{version}-%{release} - Provides: dnf-plugin-generate_completion_cache = %{version}-%{release} - Provides: dnf-plugin-needs_restarting = %{version}-%{release} -+Provides: dnf-plugin-groups-manager = %{version}-%{release} - Provides: dnf-plugin-repoclosure = %{version}-%{release} - Provides: dnf-plugin-repodiff = %{version}-%{release} - Provides: dnf-plugin-repograph = %{version}-%{release} -@@ -87,7 +89,7 @@ Conflicts: dnf-plugins-extras-common-data < %{dnf_plugins_extra} - - %description - Core Plugins for DNF. This package enhances DNF with builddep, config-manager, --copr, debug, debuginfo-install, download, needs-restarting, repoclosure, -+copr, debug, debuginfo-install, download, needs-restarting, groups-manager, repoclosure, - repograph, repomanage, reposync, changelog and repodiff commands. Additionally - provides generate_completion_cache passive plugin. - -@@ -129,7 +131,8 @@ Conflicts: python-%{name} < %{version}-%{release} - %description -n python2-%{name} - Core Plugins for DNF, Python 2 interface. This package enhances DNF with builddep, - config-manager, copr, degug, debuginfo-install, download, needs-restarting, --repoclosure, repograph, repomanage, reposync, changelog and repodiff commands. -+groups-manager, repoclosure, repograph, repomanage, reposync, changelog -+and repodiff commands. - Additionally provides generate_completion_cache passive plugin. - %endif - -@@ -163,7 +166,8 @@ Conflicts: python-%{name} < %{version}-%{release} - %description -n python3-%{name} - Core Plugins for DNF, Python 3 interface. This package enhances DNF with builddep, - config-manager, copr, debug, debuginfo-install, download, needs-restarting, --repoclosure, repograph, repomanage, reposync, changelog and repodiff commands. -+groups-manager, repoclosure, repograph, repomanage, reposync, changelog -+and repodiff commands. - Additionally provides generate_completion_cache passive plugin. - %endif - -@@ -190,8 +194,8 @@ Summary: Yum-utils CLI compatibility layer - %description -n %{yum_utils_subpackage_name} - As a Yum-utils CLI compatibility layer, supplies in CLI shims for - debuginfo-install, repograph, package-cleanup, repoclosure, repomanage, --repoquery, reposync, repotrack, repodiff, builddep, config-manager, debug --and download that use new implementations using DNF. -+repoquery, reposync, repotrack, repodiff, builddep, config-manager, debug, -+download and yum-groups-manager that use new implementations using DNF. - %endif - - %if 0%{?rhel} == 0 && %{with python2} -@@ -458,6 +462,7 @@ ln -sf %{_libexecdir}/dnf-utils %{buildroot}%{_bindir}/yum-builddep - ln -sf %{_libexecdir}/dnf-utils %{buildroot}%{_bindir}/yum-config-manager - ln -sf %{_libexecdir}/dnf-utils %{buildroot}%{_bindir}/yum-debug-dump - ln -sf %{_libexecdir}/dnf-utils %{buildroot}%{_bindir}/yum-debug-restore -+ln -sf %{_libexecdir}/dnf-utils %{buildroot}%{_bindir}/yum-groups-manager - ln -sf %{_libexecdir}/dnf-utils %{buildroot}%{_bindir}/yumdownloader - # These commands don't have a dedicated man page, so let's just point them - # to the utils page which contains their descriptions. -@@ -483,6 +488,7 @@ PYTHONPATH=./plugins nosetests-%{python3_version} -s tests/ - %{_mandir}/man8/dnf-debuginfo-install.* - %{_mandir}/man8/dnf-download.* - %{_mandir}/man8/dnf-generate_completion_cache.* -+%{_mandir}/man8/dnf-groups-manager.* - %{_mandir}/man8/dnf-needs-restarting.* - %{_mandir}/man8/dnf-repoclosure.* - %{_mandir}/man8/dnf-repodiff.* -@@ -513,6 +519,7 @@ PYTHONPATH=./plugins nosetests-%{python3_version} -s tests/ - %{python2_sitelib}/dnf-plugins/debuginfo-install.* - %{python2_sitelib}/dnf-plugins/download.* - %{python2_sitelib}/dnf-plugins/generate_completion_cache.* -+%{python2_sitelib}/dnf-plugins/groups_manager.* - %{python2_sitelib}/dnf-plugins/needs_restarting.* - %{python2_sitelib}/dnf-plugins/repoclosure.* - %{python2_sitelib}/dnf-plugins/repodiff.* -@@ -538,6 +545,7 @@ PYTHONPATH=./plugins nosetests-%{python3_version} -s tests/ - %{python3_sitelib}/dnf-plugins/debuginfo-install.py - %{python3_sitelib}/dnf-plugins/download.py - %{python3_sitelib}/dnf-plugins/generate_completion_cache.py -+%{python3_sitelib}/dnf-plugins/groups_manager.py - %{python3_sitelib}/dnf-plugins/needs_restarting.py - %{python3_sitelib}/dnf-plugins/repoclosure.py - %{python3_sitelib}/dnf-plugins/repodiff.py -@@ -552,6 +560,7 @@ PYTHONPATH=./plugins nosetests-%{python3_version} -s tests/ - %{python3_sitelib}/dnf-plugins/__pycache__/debuginfo-install.* - %{python3_sitelib}/dnf-plugins/__pycache__/download.* - %{python3_sitelib}/dnf-plugins/__pycache__/generate_completion_cache.* -+%{python3_sitelib}/dnf-plugins/__pycache__/groups_manager.* - %{python3_sitelib}/dnf-plugins/__pycache__/needs_restarting.* - %{python3_sitelib}/dnf-plugins/__pycache__/repoclosure.* - %{python3_sitelib}/dnf-plugins/__pycache__/repodiff.* -@@ -579,6 +588,7 @@ PYTHONPATH=./plugins nosetests-%{python3_version} -s tests/ - %{_bindir}/yum-config-manager - %{_bindir}/yum-debug-dump - %{_bindir}/yum-debug-restore -+%{_bindir}/yum-groups-manager - %{_bindir}/yumdownloader - %{_mandir}/man1/debuginfo-install.* - %{_mandir}/man1/needs-restarting.* -@@ -591,6 +601,7 @@ PYTHONPATH=./plugins nosetests-%{python3_version} -s tests/ - %{_mandir}/man1/yum-config-manager.* - %{_mandir}/man1/yum-debug-dump.* - %{_mandir}/man1/yum-debug-restore.* -+%{_mandir}/man1/yum-groups-manager.* - %{_mandir}/man1/yumdownloader.* - %{_mandir}/man1/package-cleanup.* - %{_mandir}/man1/dnf-utils.* -@@ -612,6 +623,7 @@ PYTHONPATH=./plugins nosetests-%{python3_version} -s tests/ - %exclude %{_mandir}/man1/yum-config-manager.* - %exclude %{_mandir}/man1/yum-debug-dump.* - %exclude %{_mandir}/man1/yum-debug-restore.* -+%exclude %{_mandir}/man1/yum-groups-manager.* - %exclude %{_mandir}/man1/yumdownloader.* - %exclude %{_mandir}/man1/package-cleanup.* - %exclude %{_mandir}/man1/dnf-utils.* -diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt -index dd97eb2..3fb665d 100644 ---- a/doc/CMakeLists.txt -+++ b/doc/CMakeLists.txt -@@ -26,6 +26,7 @@ INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/dnf-builddep.8 - ${CMAKE_CURRENT_BINARY_DIR}/dnf-debuginfo-install.8 - ${CMAKE_CURRENT_BINARY_DIR}/dnf-download.8 - ${CMAKE_CURRENT_BINARY_DIR}/dnf-generate_completion_cache.8 -+ ${CMAKE_CURRENT_BINARY_DIR}/dnf-groups-manager.8 - ${CMAKE_CURRENT_BINARY_DIR}/dnf-leaves.8 - ${CMAKE_CURRENT_BINARY_DIR}/dnf-needs-restarting.8 - ${CMAKE_CURRENT_BINARY_DIR}/dnf-repoclosure.8 -@@ -61,6 +62,7 @@ INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/debuginfo-install.1 - ${CMAKE_CURRENT_BINARY_DIR}/yum-config-manager.1 - ${CMAKE_CURRENT_BINARY_DIR}/yum-debug-dump.1 - ${CMAKE_CURRENT_BINARY_DIR}/yum-debug-restore.1 -+ ${CMAKE_CURRENT_BINARY_DIR}/yum-groups-manager.1 - ${CMAKE_CURRENT_BINARY_DIR}/yumdownloader.1 - ${CMAKE_CURRENT_BINARY_DIR}/package-cleanup.1 - ${CMAKE_CURRENT_BINARY_DIR}/dnf-utils.1 -diff --git a/doc/conf.py b/doc/conf.py -index d760ef3..645185a 100644 ---- a/doc/conf.py -+++ b/doc/conf.py -@@ -251,6 +251,7 @@ man_pages = [ - ('download', 'dnf-download', u'DNF download Plugin', AUTHORS, 8), - ('generate_completion_cache', 'dnf-generate_completion_cache', - u'DNF generate_completion_cache Plugin', AUTHORS, 8), -+ ('groups-manager', 'dnf-groups-manager', u'DNF groups-manager Plugin', AUTHORS, 8), - ('leaves', 'dnf-leaves', u'DNF leaves Plugin', AUTHORS, 8), - ('local', 'dnf-local', u'DNF local Plugin', AUTHORS, 8), - ('needs_restarting', 'dnf-needs-restarting', u'DNF needs_restarting Plugin', AUTHORS, 8), -@@ -268,6 +269,7 @@ man_pages = [ - ('copr', 'yum-copr', u'redirecting to DNF copr Plugin', AUTHORS, 8), - ('debuginfo-install', 'debuginfo-install', u'redirecting to DNF debuginfo-install Plugin', - AUTHORS, 1), -+ ('groups-manager', 'yum-groups-manager', u'redirecting to DNF groups-manager Plugin', AUTHORS, 1), - ('needs_restarting', 'needs-restarting', u'redirecting to DNF needs-restarting Plugin', - AUTHORS, 1), - ('repoclosure', 'repoclosure', u'redirecting to DNF repoclosure Plugin', AUTHORS, 1), -diff --git a/doc/groups-manager.rst b/doc/groups-manager.rst -new file mode 100644 -index 0000000..f8f76a1 ---- /dev/null -+++ b/doc/groups-manager.rst -@@ -0,0 +1,94 @@ -+.. -+ Copyright (C) 2020 Red Hat, Inc. -+ -+ This copyrighted material is made available to anyone wishing to use, -+ modify, copy, or redistribute it subject to the terms and conditions of -+ the GNU General Public License v.2, or (at your option) any later version. -+ This program is distributed in the hope that it will be useful, but WITHOUT -+ ANY WARRANTY expressed or implied, including the implied warranties 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., 51 Franklin Street, Fifth Floor, Boston, MA -+ 02110-1301, USA. Any Red Hat trademarks that are incorporated in the -+ source code or documentation are not subject to the GNU General Public -+ License and may only be used or replicated with the express permission of -+ Red Hat, Inc. -+ -+========================= -+DNF groups-manager Plugin -+========================= -+ -+Create and edit groups repository metadata files. -+ -+-------- -+Synopsis -+-------- -+ -+``dnf groups-manager [options] [package-name-spec [package-name-spec ...]]`` -+ -+----------- -+Description -+----------- -+groups-manager plugin is used to create or edit a group metadata file for a repository. This is often much easier than writing/editing the XML by hand. The groups-manager can load an entire file of groups metadata and either create a new group or edit an existing group and then write all of the groups metadata back out. -+ -+--------- -+Arguments -+--------- -+ -+```` -+ Package to add to a group or remove from a group. -+ -+------- -+Options -+------- -+ -+All general DNF options are accepted, see `Options` in :manpage:`dnf(8)` for details. -+ -+``--load=`` -+ Load the groups metadata information from the specified file before performing any operations. Metadata from all files are merged together if the option is specified multiple times. -+ -+``--save=`` -+ Save the result to this file. You can specify the name of a file you are loading from as the data will only be saved when all the operations have been performed. This option can also be specified multiple times. -+ -+``--merge=`` -+ This is the same as loading and saving a file, however the "merge" file is loaded before any others and saved last. -+ -+``--print`` -+ Also print the result to stdout. -+ -+``--id=`` -+ The id to lookup/use for the group. If you don't specify an ````, but do specify a name that doesn't refer to an existing group, then an id for the group is generated based on the name. -+ -+``-n , --name=`` -+ The name to lookup/use for the group. If you specify an existing group id, then the group with that id will have it's name changed to this value. -+ -+``--description=`` -+ The description to use for the group. -+ -+``--display-order=`` -+ Change the integer which controls the order groups are presented in, for example in ``dnf grouplist``. -+ -+``--translated-name=`` -+ A translation of the group name in the given language. The syntax is ``lang:text``. Eg. ``en:my-group-name-in-english`` -+ -+``--translated-description=`` -+ A translation of the group description in the given language. The syntax is ``lang:text``. Eg. ``en:my-group-description-in-english``. -+ -+``--user-visible`` -+ Make the group visible in ``dnf grouplist`` (this is the default). -+ -+``--not-user-visible`` -+ Make the group not visible in ``dnf grouplist``. -+ -+``--mandatory`` -+ Store the package names specified within the mandatory section of the specified group, the default is to use the default section. -+ -+``--optional`` -+ Store the package names specified within the optional section of the specified group, the default is to use the default section. -+ -+``--remove`` -+ Instead of adding packages remove them. Note that the packages are removed from all sections (default, mandatory and optional). -+ -+``--dependencies`` -+ Also include the names of the direct dependencies for each package specified. -diff --git a/doc/index.rst b/doc/index.rst -index 91bb36e..7213253 100644 ---- a/doc/index.rst -+++ b/doc/index.rst -@@ -33,6 +33,7 @@ This documents core plugins of DNF: - debuginfo-install - download - generate_completion_cache -+ groups-manager - leaves - local - migrate -diff --git a/libexec/dnf-utils.in b/libexec/dnf-utils.in -index 667ce13..af1e893 100644 ---- a/libexec/dnf-utils.in -+++ b/libexec/dnf-utils.in -@@ -37,6 +37,7 @@ MAPPING = {'debuginfo-install': ['debuginfo-install'], - 'yum-config-manager': ['config-manager'], - 'yum-debug-dump': ['debug-dump'], - 'yum-debug-restore': ['debug-restore'], -+ 'yum-groups-manager': ['groups-manager'], - 'yumdownloader': ['download'] - } - -diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt -index 7465e53..f66d3df 100644 ---- a/plugins/CMakeLists.txt -+++ b/plugins/CMakeLists.txt -@@ -6,6 +6,7 @@ INSTALL (FILES config_manager.py DESTINATION ${PYTHON_INSTALL_DIR}/dnf-plugins) - INSTALL (FILES copr.py DESTINATION ${PYTHON_INSTALL_DIR}/dnf-plugins) - INSTALL (FILES download.py DESTINATION ${PYTHON_INSTALL_DIR}/dnf-plugins) - INSTALL (FILES generate_completion_cache.py DESTINATION ${PYTHON_INSTALL_DIR}/dnf-plugins) -+INSTALL (FILES groups_manager.py DESTINATION ${PYTHON_INSTALL_DIR}/dnf-plugins) - INSTALL (FILES leaves.py DESTINATION ${PYTHON_INSTALL_DIR}/dnf-plugins) - if (${WITHOUT_LOCAL} STREQUAL "0") - INSTALL (FILES local.py DESTINATION ${PYTHON_INSTALL_DIR}/dnf-plugins) -diff --git a/plugins/groups_manager.py b/plugins/groups_manager.py -new file mode 100644 -index 0000000..382df37 ---- /dev/null -+++ b/plugins/groups_manager.py -@@ -0,0 +1,314 @@ -+# groups_manager.py -+# DNF plugin for managing comps groups metadata files -+# -+# Copyright (C) 2020 Red Hat, Inc. -+# -+# This copyrighted material is made available to anyone wishing to use, -+# modify, copy, or redistribute it subject to the terms and conditions of -+# the GNU General Public License v.2, or (at your option) any later version. -+# This program is distributed in the hope that it will be useful, but WITHOUT -+# ANY WARRANTY expressed or implied, including the implied warranties 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., 51 Franklin Street, Fifth Floor, Boston, MA -+# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the -+# source code or documentation are not subject to the GNU General Public -+# License and may only be used or replicated with the express permission of -+# Red Hat, Inc. -+# -+ -+from __future__ import absolute_import -+from __future__ import unicode_literals -+ -+import argparse -+import gzip -+import libcomps -+import os -+import re -+import shutil -+import tempfile -+ -+from dnfpluginscore import _, logger -+import dnf -+import dnf.cli -+ -+ -+RE_GROUP_ID_VALID = '-a-z0-9_.:' -+RE_GROUP_ID = re.compile(r'^[{}]+$'.format(RE_GROUP_ID_VALID)) -+RE_LANG = re.compile(r'^[-a-zA-Z0-9_.@]+$') -+COMPS_XML_OPTIONS = { -+ 'default_explicit': True, -+ 'uservisible_explicit': True, -+ 'empty_groups': True} -+ -+ -+def group_id_type(value): -+ '''group id validator''' -+ if not RE_GROUP_ID.match(value): -+ raise argparse.ArgumentTypeError(_('Invalid group id')) -+ return value -+ -+ -+def translation_type(value): -+ '''translated texts validator''' -+ data = value.split(':', 2) -+ if len(data) != 2: -+ raise argparse.ArgumentTypeError( -+ _("Invalid translated data, should be in form 'lang:text'")) -+ lang, text = data -+ if not RE_LANG.match(lang): -+ raise argparse.ArgumentTypeError(_('Invalid/empty language for translated data')) -+ return lang, text -+ -+ -+def text_to_id(text): -+ '''generate group id based on its name''' -+ group_id = text.lower() -+ group_id = re.sub('[^{}]'.format(RE_GROUP_ID_VALID), '', group_id) -+ if not group_id: -+ raise dnf.cli.CliError( -+ _("Can't generate group id from '{}'. Please specify group id using --id.").format( -+ text)) -+ return group_id -+ -+ -+@dnf.plugin.register_command -+class GroupsManagerCommand(dnf.cli.Command): -+ aliases = ('groups-manager',) -+ summary = _('create and edit groups metadata file') -+ -+ def __init__(self, cli): -+ super(GroupsManagerCommand, self).__init__(cli) -+ self.comps = libcomps.Comps() -+ -+ @staticmethod -+ def set_argparser(parser): -+ # input / output options -+ parser.add_argument('--load', action='append', default=[], -+ metavar='COMPS.XML', -+ help=_('load groups metadata from file')) -+ parser.add_argument('--save', action='append', default=[], -+ metavar='COMPS.XML', -+ help=_('save groups metadata to file')) -+ parser.add_argument('--merge', metavar='COMPS.XML', -+ help=_('load and save groups metadata to file')) -+ parser.add_argument('--print', action='store_true', default=False, -+ help=_('print the result metadata to stdout')) -+ # group options -+ parser.add_argument('--id', type=group_id_type, -+ help=_('group id')) -+ parser.add_argument('-n', '--name', help=_('group name')) -+ parser.add_argument('--description', -+ help=_('group description')) -+ parser.add_argument('--display-order', type=int, -+ help=_('group display order')) -+ parser.add_argument('--translated-name', action='append', default=[], -+ metavar='LANG:TEXT', type=translation_type, -+ help=_('translated name for the group')) -+ parser.add_argument('--translated-description', action='append', default=[], -+ metavar='LANG:TEXT', type=translation_type, -+ help=_('translated description for the group')) -+ visible = parser.add_mutually_exclusive_group() -+ visible.add_argument('--user-visible', dest='user_visible', action='store_true', -+ default=None, -+ help=_('make the group user visible (default)')) -+ visible.add_argument('--not-user-visible', dest='user_visible', action='store_false', -+ default=None, -+ help=_('make the group user invisible')) -+ -+ # package list options -+ section = parser.add_mutually_exclusive_group() -+ section.add_argument('--mandatory', action='store_true', -+ help=_('add packages to the mandatory section')) -+ section.add_argument('--optional', action='store_true', -+ help=_('add packages to the optional section')) -+ section.add_argument('--remove', action='store_true', default=False, -+ help=_('remove packages from the group instead of adding them')) -+ parser.add_argument('--dependencies', action='store_true', -+ help=_('include also direct dependencies for packages')) -+ -+ parser.add_argument("packages", nargs='*', metavar='PACKAGE', -+ help=_('package specification')) -+ -+ def configure(self): -+ demands = self.cli.demands -+ -+ if self.opts.packages: -+ demands.sack_activation = True -+ demands.available_repos = True -+ demands.load_system_repo = False -+ -+ # handle --merge option (shortcut to --load and --save the same file) -+ if self.opts.merge: -+ self.opts.load.insert(0, self.opts.merge) -+ self.opts.save.append(self.opts.merge) -+ -+ # check that group is specified when editing is attempted -+ if (self.opts.description -+ or self.opts.display_order -+ or self.opts.translated_name -+ or self.opts.translated_description -+ or self.opts.user_visible is not None -+ or self.opts.packages): -+ if not self.opts.id and not self.opts.name: -+ raise dnf.cli.CliError( -+ _("Can't edit group without specifying it (use --id or --name)")) -+ -+ def load_input_files(self): -+ """ -+ Loads all input xml files. -+ Returns True if at least one file was successfuly loaded -+ """ -+ for file_name in self.opts.load: -+ file_comps = libcomps.Comps() -+ try: -+ if file_name.endswith('.gz'): -+ # libcomps does not support gzipped files - decompress to temporary -+ # location -+ with gzip.open(file_name) as gz_file: -+ temp_file = tempfile.NamedTemporaryFile(delete=False) -+ try: -+ shutil.copyfileobj(gz_file, temp_file) -+ # close temp_file to ensure the content is flushed to disk -+ temp_file.close() -+ file_comps.fromxml_f(temp_file.name) -+ finally: -+ os.unlink(temp_file.name) -+ else: -+ file_comps.fromxml_f(file_name) -+ except (IOError, OSError, libcomps.ParserError) as err: -+ # gzip module raises OSError on reading from malformed gz file -+ # get_last_errors() output often contains duplicit lines, remove them -+ seen = set() -+ for error in file_comps.get_last_errors(): -+ if error in seen: -+ continue -+ logger.error(error.strip()) -+ seen.add(error) -+ raise dnf.exceptions.Error( -+ _("Can't load file \"{}\": {}").format(file_name, err)) -+ else: -+ self.comps += file_comps -+ -+ def save_output_files(self): -+ for file_name in self.opts.save: -+ try: -+ # xml_f returns a list of errors / log entries -+ errors = self.comps.xml_f(file_name, xml_options=COMPS_XML_OPTIONS) -+ except libcomps.XMLGenError as err: -+ errors = [err] -+ if errors: -+ # xml_f() method could return more than one error. In this case -+ # raise the latest of them and log the others. -+ for err in errors[:-1]: -+ logger.error(err.strip()) -+ raise dnf.exceptions.Error(_("Can't save file \"{}\": {}").format( -+ file_name, errors[-1].strip())) -+ -+ -+ def find_group(self, group_id, name): -+ ''' -+ Try to find group according to command line parameters - first by id -+ then by name. -+ ''' -+ group = None -+ if group_id: -+ for grp in self.comps.groups: -+ if grp.id == group_id: -+ group = grp -+ break -+ if group is None and name: -+ for grp in self.comps.groups: -+ if grp.name == name: -+ group = grp -+ break -+ return group -+ -+ def edit_group(self, group): -+ ''' -+ Set attributes and package lists for selected group -+ ''' -+ def langlist_to_strdict(lst): -+ str_dict = libcomps.StrDict() -+ for lang, text in lst: -+ str_dict[lang] = text -+ return str_dict -+ -+ # set group attributes -+ if self.opts.name: -+ group.name = self.opts.name -+ if self.opts.description: -+ group.desc = self.opts.description -+ if self.opts.display_order: -+ group.display_order = self.opts.display_order -+ if self.opts.user_visible is not None: -+ group.uservisible = self.opts.user_visible -+ if self.opts.translated_name: -+ group.name_by_lang = langlist_to_strdict(self.opts.translated_name) -+ if self.opts.translated_description: -+ group.desc_by_lang = langlist_to_strdict(self.opts.translated_description) -+ -+ # edit packages list -+ if self.opts.packages: -+ # find packages according to specifications from command line -+ packages = set() -+ for pkg_spec in self.opts.packages: -+ q = self.base.sack.query().filterm(name__glob=pkg_spec).latest() -+ if not q: -+ logger.warning(_("No match for argument: {}").format(pkg_spec)) -+ continue -+ packages.update(q) -+ if self.opts.dependencies: -+ # add packages that provide requirements -+ requirements = set() -+ for pkg in packages: -+ requirements.update(pkg.requires) -+ packages.update(self.base.sack.query().filterm(provides=requirements)) -+ -+ pkg_names = {pkg.name for pkg in packages} -+ -+ if self.opts.remove: -+ for pkg_name in pkg_names: -+ for pkg in group.packages_match(name=pkg_name, -+ type=libcomps.PACKAGE_TYPE_UNKNOWN): -+ group.packages.remove(pkg) -+ else: -+ if self.opts.mandatory: -+ pkg_type = libcomps.PACKAGE_TYPE_MANDATORY -+ elif self.opts.optional: -+ pkg_type = libcomps.PACKAGE_TYPE_OPTIONAL -+ else: -+ pkg_type = libcomps.PACKAGE_TYPE_DEFAULT -+ for pkg_name in sorted(pkg_names): -+ if not group.packages_match(name=pkg_name, type=pkg_type): -+ group.packages.append(libcomps.Package(name=pkg_name, type=pkg_type)) -+ -+ def run(self): -+ self.load_input_files() -+ -+ if self.opts.id or self.opts.name: -+ # we are adding / editing a group -+ group = self.find_group(group_id=self.opts.id, name=self.opts.name) -+ if group is None: -+ # create a new group -+ if self.opts.remove: -+ raise dnf.exceptions.Error(_("Can't remove packages from non-existent group")) -+ group = libcomps.Group() -+ if self.opts.id: -+ group.id = self.opts.id -+ group.name = self.opts.id -+ elif self.opts.name: -+ group_id = text_to_id(self.opts.name) -+ if self.find_group(group_id=group_id, name=None): -+ raise dnf.cli.CliError( -+ _("Group id '{}' generated from '{}' is duplicit. " -+ "Please specify group id using --id.").format( -+ group_id, self.opts.name)) -+ group.id = group_id -+ self.comps.groups.append(group) -+ self.edit_group(group) -+ -+ self.save_output_files() -+ if self.opts.print or (not self.opts.save): -+ print(self.comps.xml_str(xml_options=COMPS_XML_OPTIONS)) --- -2.26.2 - diff --git a/SOURCES/0001-versionlock-Do-not-exclude-locked-obsoleters-RhBug1957280.patch b/SOURCES/0001-versionlock-Do-not-exclude-locked-obsoleters-RhBug1957280.patch new file mode 100644 index 0000000..133ea78 --- /dev/null +++ b/SOURCES/0001-versionlock-Do-not-exclude-locked-obsoleters-RhBug1957280.patch @@ -0,0 +1,38 @@ +From a3b9e17628994b43080b8c03b9f665a0e6514cd6 Mon Sep 17 00:00:00 2001 +From: Marek Blaha +Date: Tue, 11 May 2021 08:29:31 +0200 +Subject: [PATCH] versionlock: Do not exclude locked obsoleters (RhBug:1957280) + +The versionlock plugin excludes all obsoleters of locked packages. If +both versions (obsoleted package and its obsoleter) are locked, this +leads to the inability to install the obsoleter package. The patch +protects all locked packages from being excluded as obsoleters. + += changelog = +msg: versionlock: Locking obsoleted package does not make the obsoleter unavailable +type: bugfix +resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1957280 +--- + plugins/versionlock.py | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/plugins/versionlock.py b/plugins/versionlock.py +index d997130..c89a75d 100644 +--- a/plugins/versionlock.py ++++ b/plugins/versionlock.py +@@ -113,8 +113,10 @@ class VersionLock(dnf.Plugin): + other_versions = all_versions.difference(locked_query) + excludes_query = excludes_query.union(other_versions) + # exclude also anything that obsoletes the locked versions of packages +- excludes_query = excludes_query.union( +- self.base.sack.query().filterm(obsoletes=locked_query)) ++ obsoletes_query = self.base.sack.query().filterm(obsoletes=locked_query) ++ # leave out obsoleters that are also part of locked versions (otherwise the obsoleter package ++ # would not be installable at all) ++ excludes_query = excludes_query.union(obsoletes_query.difference(locked_query)) + + excludes_query.filterm(reponame__neq=hawkey.SYSTEM_REPO_NAME) + if excludes_query: +-- +libgit2 1.0.1 + diff --git a/SOURCES/0002-needs-restarting-add-s-to-list-services-RhBug-177293.patch b/SOURCES/0002-needs-restarting-add-s-to-list-services-RhBug-177293.patch deleted file mode 100644 index b832730..0000000 --- a/SOURCES/0002-needs-restarting-add-s-to-list-services-RhBug-177293.patch +++ /dev/null @@ -1,138 +0,0 @@ -From b2a912724d737ca7ac4350885b54117f5e043046 Mon Sep 17 00:00:00 2001 -From: Nicola Sella -Date: Thu, 5 Mar 2020 12:45:39 +0100 -Subject: [PATCH 2/2] [needs-restarting] add -s to list services - (RhBug:1772939) - -= changelog = -msg: [needs-restarting] add -s to list services (RhBug:1772939) -type: bugfix -resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1772939 - -Closes: #395 -Approved by: kontura ---- - dnf-plugins-core.spec | 6 ++++++ - doc/needs_restarting.rst | 3 +++ - plugins/needs_restarting.py | 33 +++++++++++++++++++++++++++++++++ - 3 files changed, 42 insertions(+) - -diff --git a/dnf-plugins-core.spec b/dnf-plugins-core.spec -index 42d0884..012dde8 100644 ---- a/dnf-plugins-core.spec -+++ b/dnf-plugins-core.spec -@@ -99,8 +99,10 @@ Summary: Core Plugins for DNF - %{?python_provide:%python_provide python2-%{name}} - BuildRequires: python2-dnf >= %{dnf_lowest_compatible} - %if 0%{?rhel} && 0%{?rhel} <= 7 -+BuildRequires: dbus-python - BuildRequires: python-nose - %else -+BuildRequires: python2-dbus - BuildRequires: python2-nose - %endif - BuildRequires: python2-devel -@@ -110,8 +112,10 @@ Requires: python2-distro - Requires: python2-dnf >= %{dnf_lowest_compatible} - Requires: python2-hawkey >= %{hawkey_version} - %if 0%{?rhel} && 0%{?rhel} <= 7 -+Requires: dbus-python - Requires: python-dateutil - %else -+Requires: python2-dbus - Requires: python2-dateutil - %endif - Provides: python2-dnf-plugins-extras-debug = %{version}-%{release} -@@ -140,12 +144,14 @@ Additionally provides generate_completion_cache passive plugin. - %package -n python3-%{name} - Summary: Core Plugins for DNF - %{?python_provide:%python_provide python3-%{name}} -+BuildRequires: python3-dbus - BuildRequires: python3-devel - BuildRequires: python3-dnf >= %{dnf_lowest_compatible} - BuildRequires: python3-nose - %if 0%{?fedora} - Requires: python3-distro - %endif -+Requires: python3-dbus - Requires: python3-dnf >= %{dnf_lowest_compatible} - Requires: python3-hawkey >= %{hawkey_version} - Requires: python3-dateutil -diff --git a/doc/needs_restarting.rst b/doc/needs_restarting.rst -index e79b43f..1a3fbbe 100644 ---- a/doc/needs_restarting.rst -+++ b/doc/needs_restarting.rst -@@ -48,3 +48,6 @@ All general DNF options are accepted, see `Options` in :manpage:`dnf(8)` for det - ``-r, --reboothint`` - - Only report whether a reboot is required (exit code 1) or not (exit code 0). -+ -+``-s, --services`` -+ Only list the affected systemd services. -diff --git a/plugins/needs_restarting.py b/plugins/needs_restarting.py -index 69203f4..f6bf525 100644 ---- a/plugins/needs_restarting.py -+++ b/plugins/needs_restarting.py -@@ -29,6 +29,7 @@ from dnfpluginscore import logger, _ - - import dnf - import dnf.cli -+import dbus - import functools - import os - import re -@@ -126,6 +127,30 @@ def print_cmd(pid): - print('%d : %s' % (pid, command)) - - -+def get_service_dbus(pid): -+ bus = dbus.SystemBus() -+ systemd_manager_object = bus.get_object( -+ 'org.freedesktop.systemd1', -+ '/org/freedesktop/systemd1' -+ ) -+ systemd_manager_interface = dbus.Interface( -+ systemd_manager_object, -+ 'org.freedesktop.systemd1.Manager' -+ ) -+ service_proxy = bus.get_object( -+ 'org.freedesktop.systemd1', -+ systemd_manager_interface.GetUnitByPID(pid) -+ ) -+ service_properties = dbus.Interface( -+ service_proxy, dbus_interface="org.freedesktop.DBus.Properties") -+ name = service_properties.Get( -+ "org.freedesktop.systemd1.Unit", -+ 'Id' -+ ) -+ if name.endswith(".service"): -+ return name -+ return -+ - def smap2opened_file(pid, line): - slash = line.find('/') - if slash < 0: -@@ -205,6 +230,8 @@ class NeedsRestartingCommand(dnf.cli.Command): - parser.add_argument('-r', '--reboothint', action='store_true', - help=_("only report whether a reboot is required " - "(exit code 1) or not (exit code 0)")) -+ parser.add_argument('-s', '--services', action='store_true', -+ help=_("only report affected systemd services")) - - def configure(self): - demands = self.cli.demands -@@ -251,5 +278,11 @@ class NeedsRestartingCommand(dnf.cli.Command): - if pkg.installtime > process_start(ofile.pid): - stale_pids.add(ofile.pid) - -+ if self.opts.services: -+ names = set([get_service_dbus(pid) for pid in sorted(stale_pids)]) -+ for name in names: -+ if name is not None: -+ print(name) -+ return 0 - for pid in sorted(stale_pids): - print_cmd(pid) --- -2.26.2 - diff --git a/SOURCES/0002-repomanage-Allow-running-only-with-metadata.patch b/SOURCES/0002-repomanage-Allow-running-only-with-metadata.patch new file mode 100644 index 0000000..2067f00 --- /dev/null +++ b/SOURCES/0002-repomanage-Allow-running-only-with-metadata.patch @@ -0,0 +1,49 @@ +From 716c5978a8036df22d6f5b430ba38c35d034f3ea Mon Sep 17 00:00:00 2001 +From: Aleš Matěj +Date: Tue, 8 Jun 2021 10:25:55 +0200 +Subject: [PATCH] [repomanage] Allow running only with metadata + +Requiring some packages to be present even if there are repodata was +arbitrary because they are never used. +--- + plugins/repomanage.py | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/plugins/repomanage.py b/plugins/repomanage.py +index 445006d..989bd78 100644 +--- a/plugins/repomanage.py ++++ b/plugins/repomanage.py +@@ -58,18 +58,13 @@ class RepoManageCommand(dnf.cli.Command): + if self.opts.new and self.opts.old: + raise dnf.exceptions.Error(_("Pass either --old or --new, not both!")) + +- rpm_list = [] +- rpm_list = self._get_file_list(self.opts.path, ".rpm") + verfile = {} + pkgdict = {} + module_dict = {} # {NameStream: {Version: [modules]}} + all_modular_artifacts = set() + + keepnum = int(self.opts.keep) # the number of items to keep + +- if len(rpm_list) == 0: +- raise dnf.exceptions.Error(_("No files to process")) +- + try: + repo_conf = self.base.repos.add_new_repo("repomanage_repo", self.base.conf, baseurl=[self.opts.path]) + # Always expire the repo, otherwise repomanage could use cached metadata and give identical results +@@ -88,6 +83,11 @@ class RepoManageCommand(dnf.cli.Command): + module_package.getVersionNum(), []).append(module_package) + + except dnf.exceptions.RepoError: ++ rpm_list = [] ++ rpm_list = self._get_file_list(self.opts.path, ".rpm") ++ if len(rpm_list) == 0: ++ raise dnf.exceptions.Error(_("No files to process")) ++ + self.base.reset(sack=True, repos=True) + self.base.fill_sack(load_system_repo=False, load_available_repos=False) + try: +-- +libgit2 1.0.1 + diff --git a/SOURCES/0003-repomanage-Enhance-repomanage-documentation-RhBug1898293.patch b/SOURCES/0003-repomanage-Enhance-repomanage-documentation-RhBug1898293.patch new file mode 100644 index 0000000..7563d02 --- /dev/null +++ b/SOURCES/0003-repomanage-Enhance-repomanage-documentation-RhBug1898293.patch @@ -0,0 +1,42 @@ +From 1b432bada5a3627f729cb42b99b7a93f808e3a80 Mon Sep 17 00:00:00 2001 +From: Aleš Matěj +Date: Tue, 8 Jun 2021 11:48:07 +0200 +Subject: [PATCH] [repomanage] Enhance repomanage documentation (RhBug:1898293) + += changelog = +msg: Enhance repomanage documentation +type: enhancement +resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1898293 +--- + doc/repomanage.rst | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/doc/repomanage.rst b/doc/repomanage.rst +index e4da441..e3171ef 100644 +--- a/doc/repomanage.rst ++++ b/doc/repomanage.rst +@@ -31,9 +31,10 @@ Synopsis + Description + ----------- + +-`repomanage` prints newest or oldest packages in a repository specified by for easy piping to xargs or similar programs. In case doesn't contain a valid repository it is searched for rpm packages which are then used instead. ++`repomanage` prints newest or older packages in a repository specified by for easy piping to xargs or similar programs. In case doesn't contain a valid repodata, it is searched for rpm packages which are then used instead. ++If the repodata are present, `repomanage` uses them as the source of truth, it doesn't verify that they match the present rpm packages. In fact, `repomanage` can run with just the repodata, no rpm packages are needed. + +-In order to work correctly with modular packages has to contain repodata with modular metadata. If modular content is present `repomanage` prints packages from newest or oldest versions of each stream in addition to newest or oldest non-modular packages. ++In order to work correctly with modular packages, has to contain repodata with modular metadata. If modular content is present, `repomanage` prints packages from newest or older stream versions in addition to newest or older non-modular packages. + + + Options +@@ -44,7 +45,7 @@ All general DNF options are accepted, see `Options` in :manpage:`dnf(8)` for det + The following options set what packages are displayed. These options are mutually exclusive, i.e. only one can be specified. If no option is specified, the newest packages are shown. + + ``--old`` +- Show older packages. ++ Show older packages (for a package or a stream show all versions except the newest one). + + ``--new`` + Show newest packages. +-- +libgit2 1.0.1 + diff --git a/SOURCES/0003-reposync-Check-GPG-signatures-of-downloaded-packages-RhBug-1856818.patch b/SOURCES/0003-reposync-Check-GPG-signatures-of-downloaded-packages-RhBug-1856818.patch deleted file mode 100644 index 45cc285..0000000 --- a/SOURCES/0003-reposync-Check-GPG-signatures-of-downloaded-packages-RhBug-1856818.patch +++ /dev/null @@ -1,194 +0,0 @@ -From a4f21266a6dab9e77913d56c04aba1e579f0e0c1 Mon Sep 17 00:00:00 2001 -From: Marek Blaha -Date: Fri, 23 Oct 2020 09:06:35 +0200 -Subject: [PATCH 1/2] [reposync] Reorder options alphabetically - ---- - doc/reposync.rst | 30 +++++++++++++++--------------- - plugins/reposync.py | 18 +++++++++--------- - 2 files changed, 24 insertions(+), 24 deletions(-) - -diff --git a/doc/reposync.rst b/doc/reposync.rst -index 71a435dc..3b820f33 100644 ---- a/doc/reposync.rst -+++ b/doc/reposync.rst -@@ -39,36 +39,36 @@ Options - - All general DNF options are accepted. Namely, the ``--repoid`` option can be used to specify the repositories to synchronize. See `Options` in :manpage:`dnf(8)` for details. - --``-p , --download-path=`` -- Root path under which the downloaded repositories are stored, relative to the current working directory. Defaults to the current working directory. Every downloaded repository has a subdirectory named after its ID under this path. -- --``--norepopath`` -- Don't add the reponame to the download path. Can only be used when syncing a single repository (default is to add the reponame). -- --``--download-metadata`` -- Download all repository metadata. Downloaded copy is instantly usable as a repository, no need to run createrepo_c on it. -- - ``-a , --arch=`` - Download only packages of given architectures (default is all architectures). Can be used multiple times. - --``--source`` -- Operate on source packages. -+``--delete`` -+ Delete local packages no longer present in repository. -+ -+``--download-metadata`` -+ Download all repository metadata. Downloaded copy is instantly usable as a repository, no need to run createrepo_c on it. - - ``-m, --downloadcomps`` - Also download and uncompress comps.xml. Consider using ``--download-metadata`` option which will download all available repository metadata. - -+``--metadata-path`` -+ Root path under which the downloaded metadata are stored. It defaults to ``--download-path`` value if not given. -+ - ``-n, --newest-only`` - Download only newest packages per-repo. - --``--delete`` -- Delete local packages no longer present in repository. -+``--norepopath`` -+ Don't add the reponame to the download path. Can only be used when syncing a single repository (default is to add the reponame). - --``--metadata-path`` -- Root path under which the downloaded metadata are stored. It defaults to ``--download-path`` value if not given. -+``-p , --download-path=`` -+ Root path under which the downloaded repositories are stored, relative to the current working directory. Defaults to the current working directory. Every downloaded repository has a subdirectory named after its ID under this path. - - ``--remote-time`` - Try to set the timestamps of the downloaded files to those on the remote side. - -+``--source`` -+ Operate on source packages. -+ - ``-u, --urls`` - Just print urls of what would be downloaded, don't download. - -diff --git a/plugins/reposync.py b/plugins/reposync.py -index 7556e7eb..6f572cac 100644 ---- a/plugins/reposync.py -+++ b/plugins/reposync.py -@@ -63,24 +63,24 @@ def set_argparser(parser): - help=_('download only packages for this ARCH')) - parser.add_argument('--delete', default=False, action='store_true', - help=_('delete local packages no longer present in repository')) -- parser.add_argument('-m', '--downloadcomps', default=False, action='store_true', -- help=_('also download and uncompress comps.xml')) - parser.add_argument('--download-metadata', default=False, action='store_true', - help=_('download all the metadata.')) -+ parser.add_argument('-m', '--downloadcomps', default=False, action='store_true', -+ help=_('also download and uncompress comps.xml')) -+ parser.add_argument('--metadata-path', -+ help=_('where to store downloaded repository metadata. ' -+ 'Defaults to the value of --download-path.')) - parser.add_argument('-n', '--newest-only', default=False, action='store_true', - help=_('download only newest packages per-repo')) -- parser.add_argument('-p', '--download-path', default='./', -- help=_('where to store downloaded repositories')) - parser.add_argument('--norepopath', default=False, action='store_true', - help=_("Don't add the reponame to the download path.")) -- parser.add_argument('--metadata-path', -- help=_('where to store downloaded repository metadata. ' -- 'Defaults to the value of --download-path.')) -- parser.add_argument('--source', default=False, action='store_true', -- help=_('operate on source packages')) -+ parser.add_argument('-p', '--download-path', default='./', -+ help=_('where to store downloaded repositories')) - parser.add_argument('--remote-time', default=False, action='store_true', - help=_('try to set local timestamps of local files by ' - 'the one on the server')) -+ parser.add_argument('--source', default=False, action='store_true', -+ help=_('operate on source packages')) - parser.add_argument('-u', '--urls', default=False, action='store_true', - help=_("Just list urls of what would be downloaded, " - "don't download")) - -From 978b7f2b1c654fed7b1b4cf45cb607143226804c Mon Sep 17 00:00:00 2001 -From: Marek Blaha -Date: Fri, 23 Oct 2020 09:14:02 +0200 -Subject: [PATCH 2/2] [reposync] Check GPG signatures of downloaded packages - (RhBug:1856818) - -YUMv3 reposync used to have --gpgcheck option to remove packages that fail GPG -signature checking after downloading. -This patch implements the option for DNF. - -= changelog = -msg: Add --gpgcheck option to reposync (RhBug:1856818) -type: enhancement -resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1856818 ---- - doc/reposync.rst | 4 ++++ - plugins/reposync.py | 21 +++++++++++++++++++++ - 2 files changed, 25 insertions(+) - -diff --git a/doc/reposync.rst b/doc/reposync.rst -index 3b820f33..de40957f 100644 ---- a/doc/reposync.rst -+++ b/doc/reposync.rst -@@ -48,6 +48,10 @@ All general DNF options are accepted. Namely, the ``--repoid`` option can be use - ``--download-metadata`` - Download all repository metadata. Downloaded copy is instantly usable as a repository, no need to run createrepo_c on it. - -+``-g, --gpgcheck`` -+ Remove packages that fail GPG signature checking after downloading. Exit code is ``1`` if at least one package was removed. -+ Note that for repositories with ``gpgcheck=0`` set in their configuration the GPG signature is not checked even with this option used. -+ - ``-m, --downloadcomps`` - Also download and uncompress comps.xml. Consider using ``--download-metadata`` option which will download all available repository metadata. - -diff --git a/plugins/reposync.py b/plugins/reposync.py -index 6f572cac..c891bfa2 100644 ---- a/plugins/reposync.py -+++ b/plugins/reposync.py -@@ -24,6 +24,7 @@ - import hawkey - import os - import shutil -+import types - - from dnfpluginscore import _, logger - from dnf.cli.option_parser import OptionParser -@@ -65,6 +66,9 @@ def set_argparser(parser): - help=_('delete local packages no longer present in repository')) - parser.add_argument('--download-metadata', default=False, action='store_true', - help=_('download all the metadata.')) -+ parser.add_argument('-g', '--gpgcheck', default=False, action='store_true', -+ help=_('Remove packages that fail GPG signature checking ' -+ 'after downloading')) - parser.add_argument('-m', '--downloadcomps', default=False, action='store_true', - help=_('also download and uncompress comps.xml')) - parser.add_argument('--metadata-path', -@@ -114,6 +118,7 @@ def configure(self): - - def run(self): - self.base.conf.keepcache = True -+ gpgcheck_ok = True - for repo in self.base.repos.iter_enabled(): - if self.opts.remote_time: - repo._repo.setPreserveRemoteTime(True) -@@ -150,8 +155,24 @@ def run(self): - self.print_urls(pkglist) - else: - self.download_packages(pkglist) -+ if self.opts.gpgcheck: -+ for pkg in pkglist: -+ local_path = self.pkg_download_path(pkg) -+ # base.package_signature_check uses pkg.localPkg() to determine -+ # the location of the package rpm file on the disk. -+ # Set it to the correct download path. -+ pkg.localPkg = types.MethodType( -+ lambda s, local_path=local_path: local_path, pkg) -+ result, error = self.base.package_signature_check(pkg) -+ if result != 0: -+ logger.warning(_("Removing {}: {}").format( -+ os.path.basename(local_path), error)) -+ os.unlink(local_path) -+ gpgcheck_ok = False - if self.opts.delete: - self.delete_old_local_packages(repo, pkglist) -+ if not gpgcheck_ok: -+ raise dnf.exceptions.Error(_("GPG signature check failed.")) - - def repo_target(self, repo): - return _pkgdir(self.opts.destdir or self.opts.download_path, diff --git a/SPECS/dnf-plugins-core.spec b/SPECS/dnf-plugins-core.spec index 09b3283..4fda121 100644 --- a/SPECS/dnf-plugins-core.spec +++ b/SPECS/dnf-plugins-core.spec @@ -6,6 +6,8 @@ %global yum_utils_subpackage_name yum-utils %endif +%define __cmake_in_source_build 1 + %if 0%{?rhel} && 0%{?rhel} <= 7 %bcond_with python3 %else @@ -31,15 +33,16 @@ %endif Name: dnf-plugins-core -Version: 4.0.18 -Release: 3%{?dist} +Version: 4.0.21 +Release: 2%{?dist} Summary: Core Plugins for DNF License: GPLv2+ URL: https://github.com/rpm-software-management/dnf-plugins-core Source0: %{url}/archive/%{version}/%{name}-%{version}.tar.gz -Patch1: 0001-groups-manager-Re-introduce-yum-groups-manager-funct.patch -Patch2: 0002-needs-restarting-add-s-to-list-services-RhBug-177293.patch -Patch3: 0003-reposync-Check-GPG-signatures-of-downloaded-packages-RhBug-1856818.patch +Patch1: 0001-versionlock-Do-not-exclude-locked-obsoleters-RhBug1957280.patch +Patch2: 0002-repomanage-Allow-running-only-with-metadata.patch +Patch3: 0003-repomanage-Enhance-repomanage-documentation-RhBug1898293.patch + BuildArch: noarch BuildRequires: cmake BuildRequires: gettext @@ -101,10 +104,8 @@ Summary: Core Plugins for DNF BuildRequires: python2-dnf >= %{dnf_lowest_compatible} %if 0%{?rhel} && 0%{?rhel} <= 7 BuildRequires: dbus-python -BuildRequires: python-nose %else BuildRequires: python2-dbus -BuildRequires: python2-nose %endif BuildRequires: python2-devel %if 0%{?fedora} @@ -147,7 +148,6 @@ Summary: Core Plugins for DNF BuildRequires: python3-dbus BuildRequires: python3-devel BuildRequires: python3-dnf >= %{dnf_lowest_compatible} -BuildRequires: python3-nose %if 0%{?fedora} Requires: python3-distro %endif @@ -478,10 +478,14 @@ ln -sf %{_mandir}/man1/%{yum_utils_subpackage_name}.1.gz %{buildroot}%{_mandir}/ %check %if %{with python2} -PYTHONPATH=./plugins nosetests-%{python2_version} -s tests/ + pushd build-py2 + ctest -VV + popd %endif %if %{with python3} -PYTHONPATH=./plugins nosetests-%{python3_version} -s tests/ + pushd build-py3 + ctest -VV + popd %endif %files @@ -761,6 +765,20 @@ PYTHONPATH=./plugins nosetests-%{python3_version} -s tests/ %endif %changelog +* Tue Jul 27 2021 Pavla Kratochvilova - 4.0.21-2 +- [versionlock] Locking obsoleted package does not make the obsoleter unavailable (RhBug:1957280) +- [repomanage] Allow running with metadata only +- [repomanage] Enhance repomanage documentation (RhBug:1898293) + +* Wed May 19 2021 Pavla Kratochvilova - 4.0.21-1 +- Update to 4.0.21 +- [repomanage] Don't use cached metadata (RhBug:1899852) +- [needs-restarting] fix -r in nspawn containers (RhBug:1913962,1914251) +- doc: add packages to needs-restarting conf +- Set blacklist subcommand as deprecated +- Removed dependency on dnf.yum.misc.Checksum class (RhBug:1935465) +- Bugs fixed (RhBug:1914827,1916782) + * Fri Jan 15 2021 Nicola Sella - 4.0.18-3 - [reposync] Check GPG signatures of downloaded packages (RhBug:1856818)