forked from rpms/dnf-plugins-core
		
	import dnf-plugins-core-4.0.18-3.el8
This commit is contained in:
		
							parent
							
								
									6286210933
								
							
						
					
					
						commit
						e1a3d6ce06
					
				| @ -1 +1 @@ | ||||
| f938708df18862c3e31e2b9d49e5c9b322d79897 SOURCES/dnf-plugins-core-4.0.17.tar.gz | ||||
| 3b8638dec2cb91a13241106b9a57114ed037d2ca SOURCES/dnf-plugins-core-4.0.18.tar.gz | ||||
|  | ||||
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1 +1 @@ | ||||
| SOURCES/dnf-plugins-core-4.0.17.tar.gz | ||||
| SOURCES/dnf-plugins-core-4.0.18.tar.gz | ||||
|  | ||||
| @ -0,0 +1,653 @@ | ||||
| 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 | ||||
| 
 | ||||
| @ -1,62 +0,0 @@ | ||||
| From aa1f12be109a2d997eeb1c1cce22beb09dd21d04 Mon Sep 17 00:00:00 2001 | ||||
| From: Nicola Sella <nsella@redhat.com> | ||||
| Date: Thu, 11 Jun 2020 09:32:17 +0200 | ||||
| Subject: [PATCH 1/2] [needs-restarting] Fix plugin fail if needs-restarting.d | ||||
|  does not exist | ||||
| 
 | ||||
| includes pep8 warning fix and string formatting space missing | ||||
| ---
 | ||||
|  plugins/needs_restarting.py | 6 ++++-- | ||||
|  1 file changed, 4 insertions(+), 2 deletions(-) | ||||
| 
 | ||||
| diff --git a/plugins/needs_restarting.py b/plugins/needs_restarting.py
 | ||||
| index 91f7e116..6b7dacb6 100644
 | ||||
| --- a/plugins/needs_restarting.py
 | ||||
| +++ b/plugins/needs_restarting.py
 | ||||
| @@ -46,6 +46,8 @@ def get_options_from_dir(filepath, base):
 | ||||
|      Return set of package names contained in files under filepath | ||||
|      """ | ||||
|   | ||||
| +    if not os.path.exists(filepath):
 | ||||
| +        return set()
 | ||||
|      options = set() | ||||
|      for file in os.listdir(filepath): | ||||
|          if os.path.isdir(file) or not file.endswith('.conf'): | ||||
| @@ -58,9 +60,9 @@ def get_options_from_dir(filepath, base):
 | ||||
|      packages = set() | ||||
|      for pkg in base.sack.query().installed().filter(name={x[0] for x in options}): | ||||
|          packages.add(pkg.name) | ||||
| -    for name, file in {x for x in options if x[0] not in packages }:
 | ||||
| +    for name, file in {x for x in options if x[0] not in packages}:
 | ||||
|          logger.warning( | ||||
| -            _('No installed package found for package name "{pkg}"'
 | ||||
| +            _('No installed package found for package name "{pkg}" '
 | ||||
|                  'specified in needs-restarting file "{file}".'.format(pkg=name, file=file))) | ||||
|      return packages | ||||
|   | ||||
| 
 | ||||
| From 57955d299f751cb9927fe501fa086d9153092532 Mon Sep 17 00:00:00 2001 | ||||
| From: Nicola Sella <nsella@redhat.com> | ||||
| Date: Thu, 11 Jun 2020 10:53:54 +0200 | ||||
| Subject: [PATCH 2/2] [needs-restarting] add kernel-rt to reboot list | ||||
| 
 | ||||
| BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1806060 | ||||
| ---
 | ||||
|  plugins/needs_restarting.py | 4 ++-- | ||||
|  1 file changed, 2 insertions(+), 2 deletions(-) | ||||
| 
 | ||||
| diff --git a/plugins/needs_restarting.py b/plugins/needs_restarting.py
 | ||||
| index 6b7dacb6..69203f4d 100644
 | ||||
| --- a/plugins/needs_restarting.py
 | ||||
| +++ b/plugins/needs_restarting.py
 | ||||
| @@ -37,8 +37,8 @@
 | ||||
|   | ||||
|  # For which package updates we should recommend a reboot | ||||
|  # Mostly taken from https://access.redhat.com/solutions/27943 | ||||
| -NEED_REBOOT = ['kernel', 'glibc', 'linux-firmware', 'systemd', 'dbus',
 | ||||
| -               'dbus-broker', 'dbus-daemon']
 | ||||
| +NEED_REBOOT = ['kernel', 'kernel-rt', 'glibc', 'linux-firmware',
 | ||||
| +               'systemd', 'dbus', 'dbus-broker', 'dbus-daemon']
 | ||||
|   | ||||
|  def get_options_from_dir(filepath, base): | ||||
|      """ | ||||
| @ -0,0 +1,138 @@ | ||||
| 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 | ||||
| 
 | ||||
| @ -0,0 +1,194 @@ | ||||
| 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, | ||||
| @ -31,13 +31,15 @@ | ||||
| %endif | ||||
| 
 | ||||
| Name:           dnf-plugins-core | ||||
| Version:        4.0.17 | ||||
| Release:        2%{?dist} | ||||
| Version:        4.0.18 | ||||
| Release:        3%{?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-test-plugin-crash-if-needs-restarting-d-does-not-exist.patch | ||||
| 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 | ||||
| BuildArch:      noarch | ||||
| BuildRequires:  cmake | ||||
| BuildRequires:  gettext | ||||
| @ -57,6 +59,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) | ||||
| @ -72,6 +75,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} | ||||
| @ -86,7 +90,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, groups-manager, needs-restarting, repoclosure, | ||||
| repograph, repomanage, reposync, changelog and repodiff commands. Additionally | ||||
| provides generate_completion_cache passive plugin. | ||||
| 
 | ||||
| @ -96,8 +100,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 | ||||
| @ -107,8 +113,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} | ||||
| @ -127,7 +135,7 @@ 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, | ||||
| config-manager, copr, degug, debuginfo-install, download, groups-manager, needs-restarting, | ||||
| repoclosure, repograph, repomanage, reposync, changelog and repodiff commands. | ||||
| Additionally provides generate_completion_cache passive plugin. | ||||
| %endif | ||||
| @ -136,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 | ||||
| @ -161,7 +171,7 @@ 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, | ||||
| config-manager, copr, debug, debuginfo-install, download, groups-manager, needs-restarting, | ||||
| repoclosure, repograph, repomanage, reposync, changelog and repodiff commands. | ||||
| Additionally provides generate_completion_cache passive plugin. | ||||
| %endif | ||||
| @ -189,8 +199,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} | ||||
| @ -457,6 +467,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. | ||||
| @ -482,6 +493,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.* | ||||
| @ -512,6 +524,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.* | ||||
| @ -537,6 +550,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 | ||||
| @ -551,6 +565,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.* | ||||
| @ -578,6 +593,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.* | ||||
| @ -590,6 +606,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.* | ||||
| @ -611,6 +628,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.* | ||||
| @ -743,6 +761,36 @@ PYTHONPATH=./plugins nosetests-%{python3_version} -s tests/ | ||||
| %endif | ||||
| 
 | ||||
| %changelog | ||||
| * Fri Jan 15 2021 Nicola Sella <nsella@redhat.com> - 4.0.18-3 | ||||
| - [reposync] Check GPG signatures of downloaded packages (RhBug:1856818) | ||||
| 
 | ||||
| * Tue Dec 8 2020 Marek Blaha <mblaha@redhat.com> - 4.0.18-2 | ||||
| - Introduce groups-manager plugin (RhBug:1826016) | ||||
| - [needs-restarting] add -s to list services (RhBug:1772939) | ||||
| 
 | ||||
| * Tue Nov 10 2020 Nicola Sella <nsella@redhat.com> - 4.0.18-1 | ||||
| - Update to 4.0.18 | ||||
| - [needs-restarting] Fix plugin fail if needs-restarting.d does not exist | ||||
| - [needs-restarting] add kernel-rt to reboot list | ||||
| - Fix debug-restore command | ||||
| - [config-manager] enable/disable comma separated pkgs (RhBug:1830530) | ||||
| - [debug] Use standard demands.resolving for transaction handling | ||||
| - [debug] Do not remove install-only packages (RhBug:1844533) | ||||
| - return error when dnf download failed | ||||
| - README: Reference Fedora Weblate instead of Zanata | ||||
| - [reposync] Add latest NEVRAs per stream to download (RhBug: 1833074) | ||||
| - copr: don't try to list runtime dependencies | ||||
| 
 | ||||
| * Wed Aug 05 2020 Nicola Sella <nsella@redhat.com> - 4.0.17-5 | ||||
| - [reposync] Add latest NEVRAs per stream to download (RhBug: 1833074) | ||||
| 
 | ||||
| * Tue Jul 28 2020 Marek Blaha <mblaha@redhat.com> - 4.0.17-4 | ||||
| - Debug-restore command do not remove installonly packages (RhBug:1844533) | ||||
| - Update translations (RhBug:1820546) | ||||
| 
 | ||||
| * Fri Jul 17 2020 Nicola Sella <nsella@redhat.com> - 4.0.17-3 | ||||
| - Fix debug-restore command (RhBug:1844533) | ||||
| 
 | ||||
| * Thu Jun 11 2020 Nicola Sella <nsella@redhat.com> - 4.0.17-2 | ||||
| - [needs-restarting] Fix plugin fail if needs-restarting.d does not exist | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user