import dnf-plugins-core-4.0.21-1.el8

This commit is contained in:
CentOS Sources 2021-06-24 04:21:29 +00:00 committed by Andrew Lukoshko
parent 8887ff32ff
commit 0bb2bbe60d
7 changed files with 21 additions and 3743 deletions

View File

@ -1 +1 @@
3b8638dec2cb91a13241106b9a57114ed037d2ca SOURCES/dnf-plugins-core-4.0.18.tar.gz 40f26a50a6605eacb1e9c4a443f01655fa461767 SOURCES/dnf-plugins-core-4.0.21.tar.gz

2
.gitignore vendored
View File

@ -1 +1 @@
SOURCES/dnf-plugins-core-4.0.18.tar.gz SOURCES/dnf-plugins-core-4.0.21.tar.gz

View File

@ -1,653 +0,0 @@
From 40f08d7a22907e6292c314462c01de94584c0854 Mon Sep 17 00:00:00 2001
From: Marek Blaha <mblaha@redhat.com>
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-name-spec>``
+ 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=<path_to_comps.xml>``
+ 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=<path_to_comps.xml>``
+ 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=<path_to_comps.xml>``
+ 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=<id>``
+ The id to lookup/use for the group. If you don't specify an ``<id>``, 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>, --name=<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=<description>``
+ The description to use for the group.
+
+``--display-order=<display_order>``
+ Change the integer which controls the order groups are presented in, for example in ``dnf grouplist``.
+
+``--translated-name=<lang:text>``
+ A translation of the group name in the given language. The syntax is ``lang:text``. Eg. ``en:my-group-name-in-english``
+
+``--translated-description=<lang:text>``
+ 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

View File

@ -1,138 +0,0 @@
From b2a912724d737ca7ac4350885b54117f5e043046 Mon Sep 17 00:00:00 2001
From: Nicola Sella <nsella@redhat.com>
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

View File

@ -1,194 +0,0 @@
From a4f21266a6dab9e77913d56c04aba1e579f0e0c1 Mon Sep 17 00:00:00 2001
From: Marek Blaha <mblaha@redhat.com>
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>, --download-path=<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 <architecture>, --arch=<architecture>``
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>, --download-path=<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 <mblaha@redhat.com>
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,

File diff suppressed because it is too large Load Diff

View File

@ -6,6 +6,8 @@
%global yum_utils_subpackage_name yum-utils %global yum_utils_subpackage_name yum-utils
%endif %endif
%define __cmake_in_source_build 1
%if 0%{?rhel} && 0%{?rhel} <= 7 %if 0%{?rhel} && 0%{?rhel} <= 7
%bcond_with python3 %bcond_with python3
%else %else
@ -31,16 +33,13 @@
%endif %endif
Name: dnf-plugins-core Name: dnf-plugins-core
Version: 4.0.18 Version: 4.0.21
Release: 4%{?dist} Release: 1%{?dist}
Summary: Core Plugins for DNF Summary: Core Plugins for DNF
License: GPLv2+ License: GPLv2+
URL: https://github.com/rpm-software-management/dnf-plugins-core URL: https://github.com/rpm-software-management/dnf-plugins-core
Source0: %{url}/archive/%{version}/%{name}-%{version}.tar.gz 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
Patch4: 0004-Update-translations.patch
BuildArch: noarch BuildArch: noarch
BuildRequires: cmake BuildRequires: cmake
BuildRequires: gettext BuildRequires: gettext
@ -102,10 +101,8 @@ Summary: Core Plugins for DNF
BuildRequires: python2-dnf >= %{dnf_lowest_compatible} BuildRequires: python2-dnf >= %{dnf_lowest_compatible}
%if 0%{?rhel} && 0%{?rhel} <= 7 %if 0%{?rhel} && 0%{?rhel} <= 7
BuildRequires: dbus-python BuildRequires: dbus-python
BuildRequires: python-nose
%else %else
BuildRequires: python2-dbus BuildRequires: python2-dbus
BuildRequires: python2-nose
%endif %endif
BuildRequires: python2-devel BuildRequires: python2-devel
%if 0%{?fedora} %if 0%{?fedora}
@ -148,7 +145,6 @@ Summary: Core Plugins for DNF
BuildRequires: python3-dbus BuildRequires: python3-dbus
BuildRequires: python3-devel BuildRequires: python3-devel
BuildRequires: python3-dnf >= %{dnf_lowest_compatible} BuildRequires: python3-dnf >= %{dnf_lowest_compatible}
BuildRequires: python3-nose
%if 0%{?fedora} %if 0%{?fedora}
Requires: python3-distro Requires: python3-distro
%endif %endif
@ -479,10 +475,14 @@ ln -sf %{_mandir}/man1/%{yum_utils_subpackage_name}.1.gz %{buildroot}%{_mandir}/
%check %check
%if %{with python2} %if %{with python2}
PYTHONPATH=./plugins nosetests-%{python2_version} -s tests/ pushd build-py2
ctest -VV
popd
%endif %endif
%if %{with python3} %if %{with python3}
PYTHONPATH=./plugins nosetests-%{python3_version} -s tests/ pushd build-py3
ctest -VV
popd
%endif %endif
%files %files
@ -762,8 +762,14 @@ PYTHONPATH=./plugins nosetests-%{python3_version} -s tests/
%endif %endif
%changelog %changelog
* Mon Mar 8 2021 Marek Blaha <mblaha@redhat.com> - 4.0.18-4 * Wed May 19 2021 Pavla Kratochvilova <pkratoch@redhat.com> - 4.0.21-1
- Update translations (RhBug:1899687) - 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 <nsella@redhat.com> - 4.0.18-3 * Fri Jan 15 2021 Nicola Sella <nsella@redhat.com> - 4.0.18-3
- [reposync] Check GPG signatures of downloaded packages (RhBug:1856818) - [reposync] Check GPG signatures of downloaded packages (RhBug:1856818)