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

i8c-beta changed/i8c-beta/dnf-plugins-core-4.0.21-25.el8
MSVSphere Packaging Team 11 months ago
commit d4275d8700

@ -0,0 +1 @@
40f26a50a6605eacb1e9c4a443f01655fa461767 SOURCES/dnf-plugins-core-4.0.21.tar.gz

1
.gitignore vendored

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

@ -0,0 +1,38 @@
From a3b9e17628994b43080b8c03b9f665a0e6514cd6 Mon Sep 17 00:00:00 2001
From: Marek Blaha <mblaha@redhat.com>
Date: Tue, 11 May 2021 08:29:31 +0200
Subject: [PATCH] versionlock: Do not exclude locked obsoleters (RhBug:1957280)
The versionlock plugin excludes all obsoleters of locked packages. If
both versions (obsoleted package and its obsoleter) are locked, this
leads to the inability to install the obsoleter package. The patch
protects all locked packages from being excluded as obsoleters.
= changelog =
msg: versionlock: Locking obsoleted package does not make the obsoleter unavailable
type: bugfix
resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1957280
---
plugins/versionlock.py | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/plugins/versionlock.py b/plugins/versionlock.py
index d997130..c89a75d 100644
--- a/plugins/versionlock.py
+++ b/plugins/versionlock.py
@@ -113,8 +113,10 @@ class VersionLock(dnf.Plugin):
other_versions = all_versions.difference(locked_query)
excludes_query = excludes_query.union(other_versions)
# exclude also anything that obsoletes the locked versions of packages
- excludes_query = excludes_query.union(
- self.base.sack.query().filterm(obsoletes=locked_query))
+ obsoletes_query = self.base.sack.query().filterm(obsoletes=locked_query)
+ # leave out obsoleters that are also part of locked versions (otherwise the obsoleter package
+ # would not be installable at all)
+ excludes_query = excludes_query.union(obsoletes_query.difference(locked_query))
excludes_query.filterm(reponame__neq=hawkey.SYSTEM_REPO_NAME)
if excludes_query:
--
libgit2 1.0.1

@ -0,0 +1,49 @@
From 716c5978a8036df22d6f5b430ba38c35d034f3ea Mon Sep 17 00:00:00 2001
From: Aleš Matěj <amatej@redhat.com>
Date: Tue, 8 Jun 2021 10:25:55 +0200
Subject: [PATCH] [repomanage] Allow running only with metadata
Requiring some packages to be present even if there are repodata was
arbitrary because they are never used.
---
plugins/repomanage.py | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/plugins/repomanage.py b/plugins/repomanage.py
index 445006d..989bd78 100644
--- a/plugins/repomanage.py
+++ b/plugins/repomanage.py
@@ -58,18 +58,13 @@ class RepoManageCommand(dnf.cli.Command):
if self.opts.new and self.opts.old:
raise dnf.exceptions.Error(_("Pass either --old or --new, not both!"))
- rpm_list = []
- rpm_list = self._get_file_list(self.opts.path, ".rpm")
verfile = {}
pkgdict = {}
module_dict = {} # {NameStream: {Version: [modules]}}
all_modular_artifacts = set()
keepnum = int(self.opts.keep) # the number of items to keep
- if len(rpm_list) == 0:
- raise dnf.exceptions.Error(_("No files to process"))
-
try:
repo_conf = self.base.repos.add_new_repo("repomanage_repo", self.base.conf, baseurl=[self.opts.path])
# Always expire the repo, otherwise repomanage could use cached metadata and give identical results
@@ -88,6 +83,11 @@ class RepoManageCommand(dnf.cli.Command):
module_package.getVersionNum(), []).append(module_package)
except dnf.exceptions.RepoError:
+ rpm_list = []
+ rpm_list = self._get_file_list(self.opts.path, ".rpm")
+ if len(rpm_list) == 0:
+ raise dnf.exceptions.Error(_("No files to process"))
+
self.base.reset(sack=True, repos=True)
self.base.fill_sack(load_system_repo=False, load_available_repos=False)
try:
--
libgit2 1.0.1

@ -0,0 +1,42 @@
From 1b432bada5a3627f729cb42b99b7a93f808e3a80 Mon Sep 17 00:00:00 2001
From: Aleš Matěj <amatej@redhat.com>
Date: Tue, 8 Jun 2021 11:48:07 +0200
Subject: [PATCH] [repomanage] Enhance repomanage documentation (RhBug:1898293)
= changelog =
msg: Enhance repomanage documentation
type: enhancement
resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1898293
---
doc/repomanage.rst | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/doc/repomanage.rst b/doc/repomanage.rst
index e4da441..e3171ef 100644
--- a/doc/repomanage.rst
+++ b/doc/repomanage.rst
@@ -31,9 +31,10 @@ Synopsis
Description
-----------
-`repomanage` prints newest or oldest packages in a repository specified by <path> for easy piping to xargs or similar programs. In case <path> doesn't contain a valid repository it is searched for rpm packages which are then used instead.
+`repomanage` prints newest or older packages in a repository specified by <path> for easy piping to xargs or similar programs. In case <path> doesn't contain a valid repodata, it is searched for rpm packages which are then used instead.
+If the repodata are present, `repomanage` uses them as the source of truth, it doesn't verify that they match the present rpm packages. In fact, `repomanage` can run with just the repodata, no rpm packages are needed.
-In order to work correctly with modular packages <path> has to contain repodata with modular metadata. If modular content is present `repomanage` prints packages from newest or oldest versions of each stream in addition to newest or oldest non-modular packages.
+In order to work correctly with modular packages, <path> has to contain repodata with modular metadata. If modular content is present, `repomanage` prints packages from newest or older stream versions in addition to newest or older non-modular packages.
Options
@@ -44,7 +45,7 @@ All general DNF options are accepted, see `Options` in :manpage:`dnf(8)` for det
The following options set what packages are displayed. These options are mutually exclusive, i.e. only one can be specified. If no option is specified, the newest packages are shown.
``--old``
- Show older packages.
+ Show older packages (for a package or a stream show all versions except the newest one).
``--new``
Show newest packages.
--
libgit2 1.0.1

@ -0,0 +1,33 @@
From ebacba86979d16cdb92ace9d7dc601a85c97b5db Mon Sep 17 00:00:00 2001
From: Jakub Kadlcik <frostyx@email.cz>
Date: Tue, 12 Oct 2021 18:30:47 +0200
Subject: [PATCH] copr: don't traceback on empty lines in /etc/os-release
Fix RHBZ 1994944
---
plugins/copr.py | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/plugins/copr.py b/plugins/copr.py
index 4644495..8841f03 100644
--- a/plugins/copr.py
+++ b/plugins/copr.py
@@ -50,8 +50,13 @@ except ImportError:
with open('/etc/os-release') as os_release_file:
os_release_data = {}
for line in os_release_file:
- os_release_key, os_release_value = line.rstrip().split('=')
- os_release_data[os_release_key] = os_release_value.strip('"')
+ try:
+ os_release_key, os_release_value = line.rstrip().split('=')
+ os_release_data[os_release_key] = os_release_value.strip('"')
+ except ValueError:
+ # Skip empty lines and everything that is not a simple
+ # variable assignment
+ pass
return (os_release_data['NAME'], os_release_data['VERSION_ID'], None)
PLUGIN_CONF = 'copr'
--
libgit2 1.0.1

@ -0,0 +1,40 @@
From b60f27006cdbdd14fb480aa22610fcd32bfe41e5 Mon Sep 17 00:00:00 2001
From: Marek Blaha <mblaha@redhat.com>
Date: Wed, 6 Oct 2021 13:40:55 +0200
Subject: [PATCH] reposync: Use fail_fast=False when downloading packages (RhBug:2009894)
= changelog =
msg: Reposync does not stop downloading packages on the first error
type: bugfix
resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2009894
---
dnf-plugins-core.spec | 2 +-
plugins/reposync.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/dnf-plugins-core.spec b/dnf-plugins-core.spec
index 83ae6ae..cef836f 100644
--- a/dnf-plugins-core.spec
+++ b/dnf-plugins-core.spec
@@ -1,4 +1,4 @@
-%{?!dnf_lowest_compatible: %global dnf_lowest_compatible 4.2.22}
+%{?!dnf_lowest_compatible: %global dnf_lowest_compatible 4.9.2}
%global dnf_plugins_extra 2.0.0
%global hawkey_version 0.46.1
%global yum_utils_subpackage_name dnf-utils
diff --git a/plugins/reposync.py b/plugins/reposync.py
index 66c76a7..0ff936f 100644
--- a/plugins/reposync.py
+++ b/plugins/reposync.py
@@ -303,7 +303,7 @@ class RepoSyncCommand(dnf.cli.Command):
progress, 0)
payloads = [RPMPayloadLocation(pkg, progress, self.pkg_download_path(pkg))
for pkg in pkglist]
- base._download_remote_payloads(payloads, drpm, progress, None)
+ base._download_remote_payloads(payloads, drpm, progress, None, False)
def print_urls(self, pkglist):
for pkg in pkglist:
--
libgit2 1.0.1

@ -0,0 +1,101 @@
From 54b7c5f91b4ad1db1f716f25cc7973ec7542f0d4 Mon Sep 17 00:00:00 2001
From: Jakub Kadlcik <frostyx@email.cz>
Date: Tue, 12 Oct 2021 12:54:05 +0200
Subject: [PATCH] copr: migrate all calls to APIv3
In the latest Copr release we dropped all APIv1 code from frontend.
https://docs.pagure.org/copr.copr/release-notes/2021-10-01.html
Unfortunatelly we frogot to migrate DNF copr plugin to APIv3 and
therefore the following commands started failing with 404.
dnf copr search tests
dnf copr list --available-by-user frostyx
---
plugins/copr.py | 40 +++++++++++++++++-----------------------
1 file changed, 17 insertions(+), 23 deletions(-)
diff --git a/plugins/copr.py b/plugins/copr.py
index 8841f03..7fc6c6f 100644
--- a/plugins/copr.py
+++ b/plugins/copr.py
@@ -355,51 +355,45 @@ Bugzilla. In case of problems, contact the owner of this repository.
"Re-enable the project to fix this."))
def _list_user_projects(self, user_name):
- # http://copr.fedorainfracloud.org/api/coprs/ignatenkobrain/
- api_path = "/api/coprs/{}/".format(user_name)
- res = self.base.urlopen(self.copr_url + api_path, mode='w+')
+ # https://copr.fedorainfracloud.org/api_3/project/list?ownername=ignatenkobrain
+ api_path = "/api_3/project/list?ownername={0}".format(user_name)
+ url = self.copr_url + api_path
+ res = self.base.urlopen(url, mode='w+')
try:
json_parse = json.loads(res.read())
except ValueError:
raise dnf.exceptions.Error(
_("Can't parse repositories for username '{}'.")
.format(user_name))
self._check_json_output(json_parse)
section_text = _("List of {} coprs").format(user_name)
self._print_match_section(section_text)
- i = 0
- while i < len(json_parse["repos"]):
- msg = "{0}/{1} : ".format(user_name,
- json_parse["repos"][i]["name"])
- desc = json_parse["repos"][i]["description"]
- if not desc:
- desc = _("No description given")
+
+ for item in json_parse["items"]:
+ msg = "{0}/{1} : ".format(user_name, item["name"])
+ desc = item["description"] or _("No description given")
msg = self.base.output.fmtKeyValFill(ucd(msg), desc)
print(msg)
- i += 1
def _search(self, query):
- # http://copr.fedorainfracloud.org/api/coprs/search/tests/
- api_path = "/api/coprs/search/{}/".format(query)
- res = self.base.urlopen(self.copr_url + api_path, mode='w+')
+ # https://copr.fedorainfracloud.org/api_3/project/search?query=tests
+ api_path = "/api_3/project/search?query={}".format(query)
+ url = self.copr_url + api_path
+ res = self.base.urlopen(url, mode='w+')
try:
json_parse = json.loads(res.read())
except ValueError:
raise dnf.exceptions.Error(_("Can't parse search for '{}'."
).format(query))
self._check_json_output(json_parse)
section_text = _("Matched: {}").format(query)
self._print_match_section(section_text)
- i = 0
- while i < len(json_parse["repos"]):
- msg = "{0}/{1} : ".format(json_parse["repos"][i]["username"],
- json_parse["repos"][i]["coprname"])
- desc = json_parse["repos"][i]["description"]
- if not desc:
- desc = _("No description given.")
+
+ for item in json_parse["items"]:
+ msg = "{0} : ".format(item["full_name"])
+ desc = item["description"] or _("No description given.")
msg = self.base.output.fmtKeyValFill(ucd(msg), desc)
print(msg)
- i += 1
def _print_match_section(self, text):
formatted = self.base.output.fmtSection(text)
@@ -624,7 +618,7 @@ Bugzilla. In case of problems, contact the owner of this repository.
@classmethod
def _check_json_output(cls, json_obj):
- if json_obj["output"] != "ok":
+ if "error" in json_obj:
raise dnf.exceptions.Error("{}".format(json_obj["error"]))
@classmethod
--
libgit2 1.0.1

@ -0,0 +1,31 @@
From 5c8f753503be87e5d6237be12eec2330236d78ed Mon Sep 17 00:00:00 2001
From: Marek Blaha <mblaha@redhat.com>
Date: Mon, 8 Nov 2021 16:51:56 +0100
Subject: [PATCH] groups-manager: More benevolent resolving of packages (RhBug:2013633)
= changelog =
msg: groups-manager uses for matching packages full NEVRA and not only name.
type: enhancement
resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2013633
---
plugins/groups_manager.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/plugins/groups_manager.py b/plugins/groups_manager.py
index 382df37..12da183 100644
--- a/plugins/groups_manager.py
+++ b/plugins/groups_manager.py
@@ -254,7 +254,9 @@ class GroupsManagerCommand(dnf.cli.Command):
# 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()
+ subj = dnf.subject.Subject(pkg_spec)
+ q = subj.get_best_query(self.base.sack, with_nevra=True,
+ with_provides=False, with_filenames=False).latest()
if not q:
logger.warning(_("No match for argument: {}").format(pkg_spec))
continue
--
libgit2 1.1.0

@ -0,0 +1,95 @@
From 0030ea94dd261b66cac6f08c9dfa99e3d8ee3648 Mon Sep 17 00:00:00 2001
From: Nicola Sella <nsella@redhat.com>
Date: Mon, 1 Nov 2021 18:29:40 +0100
Subject: [PATCH] [versionlock] fix multi pkg lock (RhBug:2013324)
= changelog =
msg: [versionlock] Fix: Multiple package-name-spec arguments don't lock
correctly (RhBug:2001039)
type: bugfix
resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2013324
---
plugins/versionlock.py | 57 +++++++++++++++++++++++++++++++++------------------------
1 file changed, 33 insertions(+), 24 deletions(-)
diff --git a/plugins/versionlock.py b/plugins/versionlock.py
index c89a75d..77b7f91 100644
--- a/plugins/versionlock.py
+++ b/plugins/versionlock.py
@@ -167,25 +167,27 @@ class VersionLockCommand(dnf.cli.Command):
cmd = self.opts.subcommand
if cmd == 'add':
- (entry, entry_cmd) = _search_locklist(self.opts.package)
- if entry == '':
- _write_locklist(self.base, self.opts.package, self.opts.raw, True,
- "\n# Added lock on %s\n" % time.ctime(),
- ADDING_SPEC, '')
- elif cmd != entry_cmd:
- raise dnf.exceptions.Error(ALREADY_EXCLUDED.format(entry))
- else:
- logger.info("%s %s", EXISTING_SPEC, entry)
+ results = _search_locklist(self.opts.package)
+ for entry, entry_cmd in results:
+ if entry_cmd == '':
+ _write_locklist(self.base, [entry], self.opts.raw, True,
+ "\n# Added lock on %s\n" % time.ctime(),
+ ADDING_SPEC, '')
+ elif cmd != entry_cmd:
+ raise dnf.exceptions.Error(ALREADY_EXCLUDED.format(entry))
+ else:
+ logger.info("%s %s", EXISTING_SPEC, entry)
elif cmd == 'exclude':
- (entry, entry_cmd) = _search_locklist(self.opts.package)
- if entry == '':
- _write_locklist(self.base, self.opts.package, self.opts.raw, False,
- "\n# Added exclude on %s\n" % time.ctime(),
- EXCLUDING_SPEC, '!')
- elif cmd != entry_cmd:
- raise dnf.exceptions.Error(ALREADY_LOCKED.format(entry))
- else:
- logger.info("%s %s", EXISTING_SPEC, entry)
+ results = _search_locklist(self.opts.package)
+ for entry, entry_cmd in results:
+ if entry_cmd == '':
+ _write_locklist(self.base, [entry], self.opts.raw, False,
+ "\n# Added exclude on %s\n" % time.ctime(),
+ EXCLUDING_SPEC, '!')
+ elif cmd != entry_cmd:
+ raise dnf.exceptions.Error(ALREADY_LOCKED.format(entry))
+ else:
+ logger.info("%s %s", EXISTING_SPEC, entry)
elif cmd == 'list':
for pat in _read_locklist():
print(pat)
@@ -233,14 +235,21 @@ def _read_locklist():
def _search_locklist(package):
+ results = []
found = action = ''
locked_specs = _read_locklist()
- for ent in locked_specs:
- if _match(ent, package):
- found = ent
- action = 'exclude' if ent.startswith('!') else 'add'
- break
- return (found, action)
+ for pkg in package:
+ match = False
+ for ent in locked_specs:
+ found = action = ''
+ if _match(ent, [pkg]):
+ found = ent
+ action = 'exclude' if ent.startswith('!') else 'add'
+ results.append((found, action))
+ match = True
+ if not match:
+ results.append((pkg, action))
+ return results
def _write_locklist(base, args, raw, try_installed, comment, info, prefix):
--
libgit2 1.1.0

@ -0,0 +1,31 @@
From ed05ce74cfb9151ea5218da0f8b9eccb70c00f70 Mon Sep 17 00:00:00 2001
From: Nicola Sella <nsella@redhat.com>
Date: Thu, 11 Nov 2021 13:48:39 +0100
Subject: [PATCH] Update documentation for adding specific version (RhBug:2013332)
=changelog=
msg: [versionlock] update documentation for adding specifi version
type: bugfix
resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2013332
---
doc/versionlock.rst | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/doc/versionlock.rst b/doc/versionlock.rst
index 061ce80..1ac7196 100644
--- a/doc/versionlock.rst
+++ b/doc/versionlock.rst
@@ -97,6 +97,10 @@ Subcommands
Adding versionlock on: mutt-5:1.11.4-1.fc30.*
Adding versionlock on: mutt-5:1.12.1-3.fc30.*
+ .. note:: Be careful when adding specific versions
+
+ If you add a package specifying a version with ``dnf versionlock mutt-5:1.11.4-1.fc30.x86_64`` then, if you run ``dnf versionlock add mutt``
+ versionlock will not add ``mutt-5:1.12.1-3.fc30.x86_64``.
``dnf versionlock exclude <package-name-spec>``
Add an exclude (within versionlock) for the available packages matching the spec. It means that
--
libgit2 1.1.0

@ -0,0 +1,25 @@
From dc13ed6bab62a38ef74b00376e2ba05c82115e47 Mon Sep 17 00:00:00 2001
From: Nicola Sella <nsella@redhat.com>
Date: Thu, 8 Jul 2021 15:54:21 +0200
Subject: [PATCH] [needs-restarting] Fix wrong boot time (RhBug:1960437)
---
plugins/needs_restarting.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/plugins/needs_restarting.py b/plugins/needs_restarting.py
index 1fedb73..91dbe66 100644
--- a/plugins/needs_restarting.py
+++ b/plugins/needs_restarting.py
@@ -199,7 +199,7 @@ class ProcessStart(object):
@staticmethod
def get_boot_time():
- return int(os.stat('/proc/1/cmdline').st_mtime)
+ return int(os.stat('/proc/1').st_mtime)
@staticmethod
def get_sc_clk_tck():
--
libgit2 1.1.0

@ -0,0 +1,439 @@
From 6ea94d9c768eb45975f314e11ab9dd88284fa380 Mon Sep 17 00:00:00 2001
From: Jaroslav Mracek <jmracek@redhat.com>
Date: Mon, 27 Sep 2021 11:29:01 +0200
Subject: [PATCH] Add new command modulesync (RhBug:1868047)
It will download module metadata from all enabled repositories,
module artifacts and profiles of matching modules. Then it creates
a repository.
= changelog =
msg: Add a new subpackage with modulesync command. The command
downloads packages from modules and/or creates a repository with modular
data.
type: enhancement
resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1868047
---
dnf-plugins-core.spec | 20 ++++++++++++++++++++
doc/CMakeLists.txt | 1 +
doc/conf.py | 1 +
doc/index.rst | 1 +
doc/modulesync.rst | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
plugins/CMakeLists.txt | 1 +
plugins/modulesync.py | 208 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 335 insertions(+)
create mode 100644 doc/modulesync.rst
create mode 100644 plugins/modulesync.py
diff --git a/dnf-plugins-core.spec b/dnf-plugins-core.spec
index cef836f..afdbcbb 100644
--- a/dnf-plugins-core.spec
+++ b/dnf-plugins-core.spec
@@ -402,6 +402,19 @@ versions of those packages. This allows you to e.g. protect packages from being
updated by newer versions.
%endif
+%if %{with python3}
+%package -n python3-dnf-plugin-modulesync
+Summary: Download module metadata and packages and create repository
+Requires: python3-%{name} = %{version}-%{release}
+Requires: createrepo_c >= 0.17.4
+Provides: dnf-plugin-modulesync = %{version}-%{release}
+Provides: dnf-command(modulesync)
+
+%description -n python3-dnf-plugin-modulesync
+Download module metadata from all enabled repositories, module artifacts and profiles of matching modules and create
+repository.
+%endif
+
%prep
%autosetup
%if %{with python2}
@@ -762,6 +775,13 @@ ln -sf %{_mandir}/man1/%{yum_utils_subpackage_name}.1.gz %{buildroot}%{_mandir}/
%endif
%endif
+%if %{with python3}
+%files -n python3-dnf-plugin-modulesync
+%{python3_sitelib}/dnf-plugins/modulesync.*
+%{python3_sitelib}/dnf-plugins/__pycache__/modulesync.*
+%{_mandir}/man8/dnf-modulesync.*
+%endif
+
%changelog
* Mon Apr 12 2021 Nicola Sella <nsella@redhat.com> - 4.0.21-1
- Add missing command line option to documentation
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt
index 3fb665d..ff84cf8 100644
--- a/doc/CMakeLists.txt
+++ b/doc/CMakeLists.txt
@@ -28,6 +28,7 @@ INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/dnf-builddep.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-modulesync.8
${CMAKE_CURRENT_BINARY_DIR}/dnf-needs-restarting.8
${CMAKE_CURRENT_BINARY_DIR}/dnf-repoclosure.8
${CMAKE_CURRENT_BINARY_DIR}/dnf-repodiff.8
diff --git a/doc/conf.py b/doc/conf.py
index 645185a..41d6936 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -254,6 +254,7 @@ man_pages = [
('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),
+ ('modulesync', 'dnf-modulesync', u'DNF modulesync Plugin', AUTHORS, 8),
('needs_restarting', 'dnf-needs-restarting', u'DNF needs_restarting Plugin', AUTHORS, 8),
('repoclosure', 'dnf-repoclosure', u'DNF repoclosure Plugin', AUTHORS, 8),
('repodiff', 'dnf-repodiff', u'DNF repodiff Plugin', AUTHORS, 8),
diff --git a/doc/index.rst b/doc/index.rst
index 7213253..07f6052 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -37,6 +37,7 @@ This documents core plugins of DNF:
leaves
local
migrate
+ modulesync
needs_restarting
post-transaction-actions
repoclosure
diff --git a/doc/modulesync.rst b/doc/modulesync.rst
new file mode 100644
index 0000000..2837287
--- /dev/null
+++ b/doc/modulesync.rst
@@ -0,0 +1,103 @@
+..
+ Copyright (C) 2015 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 modulesync Plugin
+====================
+
+Download packages from modules and/or create a repository with modular data.
+
+--------
+Synopsis
+--------
+
+``dnf modulesync [options] [<module-spec>...]``
+
+-----------
+Description
+-----------
+
+`modulesync` downloads packages from modules according to provided arguments and creates a repository with modular data
+in working directory. In environment with modules it is recommend to use the command for redistribution of packages,
+because DNF does not allow installation of modular packages without modular metadata on the system (Fail-safe
+mechanism). The command without an argument creates a repository like `createrepo_c` but with modular metadata collected
+from all available repositories.
+
+See examples.
+
+---------
+Arguments
+---------
+
+``<module-spec>``
+ Module specification for the package to download. The argument is an optional.
+
+-------
+Options
+-------
+
+All general DNF options are accepted. Namely, the ``--destdir`` option can be used to specify directory where packages
+will be downloaded and the new repository created. See `Options` in :manpage:`dnf(8)` for details.
+
+
+``-n, --newest-only``
+ Download only packages from the newest modules.
+
+``--enable_source_repos``
+ Enable repositories with source packages
+
+``--enable_debug_repos``
+ Enable repositories with debug-info and debug-source packages
+
+``--resolve``
+ Resolve and download needed dependencies
+
+--------
+Examples
+--------
+
+``dnf modulesync nodejs``
+ Download packages from `nodejs` module and crete a repository with modular metadata in working directory
+
+``dnf download nodejs``
+
+``dnf modulesync``
+ The first `download` command downloads nodejs package into working directory. In environment with modules `nodejs`
+ package can be a modular package therefore when I create a repository I have to insert also modular metadata
+ from available repositories to ensure 100% functionality. Instead of `createrepo_c` use `dnf modulesync`
+ to create a repository in working directory with nodejs package and modular metadata.
+
+``dnf --destdir=/tmp/my-temp modulesync nodejs:14/minimal --resolve``
+ Download package required for installation of `minimal` profile from module `nodejs` and stream `14` into directory
+ `/tmp/my-temp` and all required dependencies. Then it will create a repository in `/tmp/my-temp` directory with
+ previously downloaded packages and modular metadata from all available repositories.
+
+``dnf module install nodejs:14/minimal --downloadonly --destdir=/tmp/my-temp``
+
+``dnf modulesync --destdir=/tmp/my-temp``
+ The first `dnf module install` command downloads package from required for installation of `minimal` profile from module
+ `nodejs` and stream `14` into directory `/tmp/my-temp`. The second command `dnf modulesync` will create
+ a repository in `/tmp/my-temp` directory with previously downloaded packages and modular metadata from all
+ available repositories. In comparison to `dnf --destdir=/tmp/my-temp modulesync nodejs:14/minimal --resolve` it will
+ only download packages required for installation on current system.
+
+
+--------
+See Also
+--------
+
+* :manpage:`dnf(8)`, DNF Command Reference
diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt
index f66d3df..59f148f 100644
--- a/plugins/CMakeLists.txt
+++ b/plugins/CMakeLists.txt
@@ -22,6 +22,7 @@ INSTALL (FILES repograph.py DESTINATION ${PYTHON_INSTALL_DIR}/dnf-plugins)
INSTALL (FILES repomanage.py DESTINATION ${PYTHON_INSTALL_DIR}/dnf-plugins)
INSTALL (FILES reposync.py DESTINATION ${PYTHON_INSTALL_DIR}/dnf-plugins)
INSTALL (FILES show_leaves.py DESTINATION ${PYTHON_INSTALL_DIR}/dnf-plugins)
+INSTALL (FILES modulesync.py DESTINATION ${PYTHON_INSTALL_DIR}/dnf-plugins)
INSTALL (FILES versionlock.py DESTINATION ${PYTHON_INSTALL_DIR}/dnf-plugins)
ADD_SUBDIRECTORY (dnfpluginscore)
diff --git a/plugins/modulesync.py b/plugins/modulesync.py
new file mode 100644
index 0000000..c1c33e4
--- /dev/null
+++ b/plugins/modulesync.py
@@ -0,0 +1,208 @@
+# Copyright (C) 2021 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
+from dnfpluginscore import _, P_, logger
+from dnf.cli.option_parser import OptionParser
+
+import os
+import shutil
+import subprocess
+
+import dnf
+import dnf.cli
+import dnf.i18n
+import hawkey
+
+
+@dnf.plugin.register_command
+class SyncToolCommand(dnf.cli.Command):
+
+ aliases = ['modulesync']
+ summary = _('Download packages from modules and/or create a repository with modular data')
+
+ def __init__(self, cli):
+ super(SyncToolCommand, self).__init__(cli)
+
+ @staticmethod
+ def set_argparser(parser):
+ parser.add_argument('module', nargs='*', metavar=_('MODULE'),
+ help=_('modules to download'))
+ parser.add_argument("--enable_source_repos", action='store_true',
+ help=_('enable repositories with source packages'))
+ parser.add_argument("--enable_debug_repos", action='store_true',
+ help=_('enable repositories with debug-info and debug-source packages'))
+ parser.add_argument('--resolve', action='store_true',
+ help=_('resolve and download needed dependencies'))
+ parser.add_argument('-n', '--newest-only', default=False, action='store_true',
+ help=_('download only packages from newest modules'))
+
+ def configure(self):
+ # setup sack and populate it with enabled repos
+ demands = self.cli.demands
+ demands.sack_activation = True
+ demands.available_repos = True
+
+ demands.load_system_repo = False
+
+ if self.opts.enable_source_repos:
+ self.base.repos.enable_source_repos()
+
+ if self.opts.enable_debug_repos:
+ self.base.repos.enable_debug_repos()
+
+ if self.opts.destdir:
+ self.base.conf.destdir = self.opts.destdir
+ else:
+ self.base.conf.destdir = dnf.i18n.ucd(os.getcwd())
+
+ def run(self):
+ """Execute the util action here."""
+
+ pkgs = self.base.sack.query().filterm(empty=True)
+ no_matched_spec = []
+ for module_spec in self.opts.module:
+ try:
+ pkgs = pkgs.union(self._get_packages_from_modules(module_spec))
+ except dnf.exceptions.Error:
+ no_matched_spec.append(module_spec)
+ if no_matched_spec:
+ msg = P_("Unable to find a match for argument: '{}'", "Unable to find a match for arguments: '{}'",
+ len(no_matched_spec)).format("' '".join(no_matched_spec))
+ raise dnf.exceptions.Error(msg)
+
+ if self.opts.resolve:
+ pkgs = pkgs.union(self._get_providers_of_requires(pkgs))
+
+ # download rpms
+ self._do_downloads(pkgs)
+
+ # Create a repository at destdir with modular data
+ remove_tmp_moduleyamls_files = []
+ for repo in self.base.repos.iter_enabled():
+ module_md_path = repo.get_metadata_path('modules')
+ if module_md_path:
+ filename = "".join([repo.id, "-", os.path.basename(module_md_path)])
+ dest_path = os.path.join(self.base.conf.destdir, filename)
+ shutil.copy(module_md_path, dest_path)
+ remove_tmp_moduleyamls_files.append(dest_path)
+ args = ["createrepo_c", "--update", "--unique-md-filenames", self.base.conf.destdir]
+ p = subprocess.run(args)
+ if p.returncode:
+ msg = _("Creation of repository failed with return code {}. All downloaded content was kept on the system")
+ msg = msg.format(p.returncode)
+ raise dnf.exceptions.Error(msg)
+ for file_path in remove_tmp_moduleyamls_files:
+ os.remove(file_path)
+
+ def _do_downloads(self, pkgs):
+ """
+ Perform the download for a list of packages
+ """
+ pkg_dict = {}
+ for pkg in pkgs:
+ pkg_dict.setdefault(str(pkg), []).append(pkg)
+
+ to_download = []
+
+ for pkg_list in pkg_dict.values():
+ pkg_list.sort(key=lambda x: (x.repo.priority, x.repo.cost))
+ to_download.append(pkg_list[0])
+ if to_download:
+ self.base.download_packages(to_download, self.base.output.progress)
+
+ def _get_packages_from_modules(self, module_spec):
+ """Gets packages from modules matching module spec
+ 1. From module artifacts
+ 2. From module profiles"""
+ result_query = self.base.sack.query().filterm(empty=True)
+ module_base = dnf.module.module_base.ModuleBase(self.base)
+ module_list, nsvcap = module_base.get_modules(module_spec)
+ if self.opts.newest_only:
+ module_list = self.base._moduleContainer.getLatestModules(module_list, False)
+ for module in module_list:
+ for artifact in module.getArtifacts():
+ query = self.base.sack.query(flags=hawkey.IGNORE_EXCLUDES).filterm(nevra_strict=artifact)
+ if query:
+ result_query = result_query.union(query)
+ else:
+ msg = _("No match for artifact '{0}' from module '{1}'").format(
+ artifact, module.getFullIdentifier())
+ logger.warning(msg)
+ if nsvcap.profile:
+ profiles_set = module.getProfiles(nsvcap.profile)
+ else:
+ profiles_set = module.getProfiles()
+ if profiles_set:
+ for profile in profiles_set:
+ for pkg_name in profile.getContent():
+ query = self.base.sack.query(flags=hawkey.IGNORE_EXCLUDES).filterm(name=pkg_name)
+ # Prefer to add modular providers selected by argument
+ if result_query.intersection(query):
+ continue
+ # Add all packages with the same name as profile described
+ elif query:
+ result_query = result_query.union(query)
+ else:
+ msg = _("No match for package name '{0}' in profile {1} from module {2}")\
+ .format(pkg_name, profile.getName(), module.getFullIdentifier())
+ logger.warning(msg)
+ if not module_list:
+ msg = _("No mach for argument '{}'").format(module_spec)
+ raise dnf.exceptions.Error(msg)
+
+ return result_query
+
+ def _get_providers_of_requires(self, to_test, done=None, req_dict=None):
+ done = done if done else to_test
+ # req_dict = {} {req : set(pkgs)}
+ if req_dict is None:
+ req_dict = {}
+ test_requires = []
+ for pkg in to_test:
+ for require in pkg.requires:
+ if require not in req_dict:
+ test_requires.append(require)
+ req_dict.setdefault(require, set()).add(pkg)
+
+ if self.opts.newest_only:
+ # Prepare cache with all packages related affected by modular filtering
+ names = set()
+ for module in self.base._moduleContainer.getModulePackages():
+ for artifact in module.getArtifacts():
+ name, __, __ = artifact.rsplit("-", 2)
+ names.add(name)
+ modular_related = self.base.sack.query(flags=hawkey.IGNORE_EXCLUDES).filterm(provides=names)
+
+ requires = self.base.sack.query().filterm(empty=True)
+ for require in test_requires:
+ q = self.base.sack.query(flags=hawkey.IGNORE_EXCLUDES).filterm(provides=require)
+
+ if not q:
+ # TODO(jmracek) Shell we end with an error or with RC 1?
+ logger.warning((_("Unable to satisfy require {}").format(require)))
+ else:
+ if self.opts.newest_only:
+ if not modular_related.intersection(q):
+ q.filterm(latest_per_arch_by_priority=1)
+ requires = requires.union(q.difference(done))
+ done = done.union(requires)
+ if requires:
+ done = self._get_providers_of_requires(requires, done=done, req_dict=req_dict)
+
+ return done
--
libgit2 1.1.0

File diff suppressed because it is too large Load Diff

@ -0,0 +1,48 @@
From e80f79b2f5e17a20065617c0b614b272dd53c57c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ale=C5=A1=20Mat=C4=9Bj?= <amatej@redhat.com>
Date: Thu, 26 May 2022 07:21:45 +0200
Subject: [PATCH] repomanage: Use modules only from repo they are handling
(RhBug:2072441)
= changelog =
msg: [repomanage] Modules are used only when they belong to target repo
type: bugfix
resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2072441
---
plugins/repomanage.py | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/plugins/repomanage.py b/plugins/repomanage.py
index 989bd78..67a6fc7 100644
--- a/plugins/repomanage.py
+++ b/plugins/repomanage.py
@@ -66,7 +66,8 @@ class RepoManageCommand(dnf.cli.Command):
keepnum = int(self.opts.keep) # the number of items to keep
try:
- repo_conf = self.base.repos.add_new_repo("repomanage_repo", self.base.conf, baseurl=[self.opts.path])
+ REPOMANAGE_REPOID = "repomanage_repo"
+ repo_conf = self.base.repos.add_new_repo(REPOMANAGE_REPOID, self.base.conf, baseurl=[self.opts.path])
# Always expire the repo, otherwise repomanage could use cached metadata and give identical results
# for multiple runs even if the actual repo changed in the meantime
repo_conf._repo.expire()
@@ -78,9 +79,13 @@ class RepoManageCommand(dnf.cli.Command):
module_packages = self.base._moduleContainer.getModulePackages()
for module_package in module_packages:
- all_modular_artifacts.update(module_package.getArtifacts())
- module_dict.setdefault(module_package.getNameStream(), {}).setdefault(
- module_package.getVersionNum(), []).append(module_package)
+ # Even though we load only REPOMANAGE_REPOID other modules can be loaded from system
+ # failsafe data automatically, we don't want them affecting repomanage results so ONLY
+ # use modules from REPOMANAGE_REPOID.
+ if module_package.getRepoID() == REPOMANAGE_REPOID:
+ all_modular_artifacts.update(module_package.getArtifacts())
+ module_dict.setdefault(module_package.getNameStream(), {}).setdefault(
+ module_package.getVersionNum(), []).append(module_package)
except dnf.exceptions.RepoError:
rpm_list = []
--
2.36.1

@ -0,0 +1,117 @@
From eb1d6edf55c167d575ce3d16bd6349e382d05600 Mon Sep 17 00:00:00 2001
From: Masahiro Matsuya <mmatsuya@redhat.com>
Date: Wed, 13 Apr 2022 18:42:03 +0900
Subject: [PATCH] feat(repomanage): Add new option --oldonly
= changelog =
msg: repomanage: Add new option --oldonly
type: enhancement
resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2034736
resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2058676
---
doc/repomanage.rst | 3 +++
plugins/repomanage.py | 46 ++++++++++++++++++++++++++++++++++++++++---
2 files changed, 46 insertions(+), 3 deletions(-)
diff --git a/doc/repomanage.rst b/doc/repomanage.rst
index e3171ef..3c01289 100644
--- a/doc/repomanage.rst
+++ b/doc/repomanage.rst
@@ -47,6 +47,9 @@ The following options set what packages are displayed. These options are mutuall
``--old``
Show older packages (for a package or a stream show all versions except the newest one).
+``--oldonly``
+ Show older packages (same as --old, but exclude the newest packages even when it's included in the older stream versions).
+
``--new``
Show newest packages.
diff --git a/plugins/repomanage.py b/plugins/repomanage.py
index 67a6fc7..d23497a 100644
--- a/plugins/repomanage.py
+++ b/plugins/repomanage.py
@@ -57,6 +57,12 @@ class RepoManageCommand(dnf.cli.Command):
def run(self):
if self.opts.new and self.opts.old:
raise dnf.exceptions.Error(_("Pass either --old or --new, not both!"))
+ if self.opts.new and self.opts.oldonly:
+ raise dnf.exceptions.Error(_("Pass either --oldonly or --new, not both!"))
+ if self.opts.old and self.opts.oldonly:
+ raise dnf.exceptions.Error(_("Pass either --old or --oldonly, not both!"))
+ if not self.opts.old and not self.opts.oldonly:
+ self.opts.new = True
verfile = {}
pkgdict = {}
@@ -123,8 +129,7 @@ class RepoManageCommand(dnf.cli.Command):
# modular packages
keepnum_latest_stream_artifacts = set()
- # if new
- if not self.opts.old:
+ if self.opts.new:
# regular packages
for (n, a) in pkgdict.keys():
evrlist = pkgdict[(n, a)]
@@ -146,7 +151,6 @@ class RepoManageCommand(dnf.cli.Command):
for stream in streams_by_version[i]:
keepnum_latest_stream_artifacts.update(set(stream.getArtifacts()))
-
if self.opts.old:
# regular packages
for (n, a) in pkgdict.keys():
@@ -169,6 +173,40 @@ class RepoManageCommand(dnf.cli.Command):
for stream in streams_by_version[i]:
keepnum_latest_stream_artifacts.update(set(stream.getArtifacts()))
+ if self.opts.oldonly:
+ # regular packages
+ for (n, a) in pkgdict.keys():
+ evrlist = pkgdict[(n, a)]
+
+ oldevrs = evrlist[:-keepnum]
+
+ for package in oldevrs:
+ nevra = self._package_to_nevra(package)
+ for fpkg in verfile[nevra]:
+ outputpackages.append(fpkg)
+
+ # modular packages
+ keepnum_newer_stream_artifacts = set()
+
+ for streams_by_version in module_dict.values():
+ sorted_stream_versions = sorted(streams_by_version.keys())
+
+ new_sorted_stream_versions = sorted_stream_versions[-keepnum:]
+
+ for i in new_sorted_stream_versions:
+ for stream in streams_by_version[i]:
+ keepnum_newer_stream_artifacts.update(set(stream.getArtifacts()))
+
+ for streams_by_version in module_dict.values():
+ sorted_stream_versions = sorted(streams_by_version.keys())
+
+ old_sorted_stream_versions = sorted_stream_versions[:-keepnum]
+
+ for i in old_sorted_stream_versions:
+ for stream in streams_by_version[i]:
+ for artifact in stream.getArtifacts():
+ if artifact not in keepnum_newer_stream_artifacts:
+ keepnum_latest_stream_artifacts.add(artifact)
modular_packages = [self._package_to_path(x) for x in query.filter(pkg__eq=query.filter(nevra_strict=keepnum_latest_stream_artifacts)).available()]
outputpackages = outputpackages + modular_packages
@@ -183,6 +221,8 @@ class RepoManageCommand(dnf.cli.Command):
def set_argparser(parser):
parser.add_argument("-o", "--old", action="store_true",
help=_("Print the older packages"))
+ parser.add_argument("-O", "--oldonly", action="store_true",
+ help=_("Print the older packages. Exclude the newest packages."))
parser.add_argument("-n", "--new", action="store_true",
help=_("Print the newest packages"))
parser.add_argument("-s", "--space", action="store_true",
--
2.36.1

@ -0,0 +1,28 @@
From b4e0cafe70680db24ab3611e0fd4dd95c8311ccc Mon Sep 17 00:00:00 2001
From: Jaroslav Mracek <jmracek@redhat.com>
Date: Tue, 26 Apr 2022 11:23:41 +0200
Subject: [PATCH] Skip all non rpm tsi for transaction_action plugins
(rhbug:2023652)
It prevent traceback in output when reason change is in transaction
---
plugins/post-transaction-actions.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/plugins/post-transaction-actions.py b/plugins/post-transaction-actions.py
index 05a7841..1520c26 100644
--- a/plugins/post-transaction-actions.py
+++ b/plugins/post-transaction-actions.py
@@ -115,6 +115,9 @@ class PostTransactionActions(dnf.Plugin):
in_ts_items.append(ts_item)
elif ts_item.action in dnf.transaction.BACKWARD_ACTIONS:
out_ts_items.append(ts_item)
+ else:
+ # The action is not rpm change. It can be a reason change, therefore we can skip that item
+ continue
all_ts_items.append(ts_item)
commands_to_run = []
--
2.36.1

@ -0,0 +1,28 @@
From 76d7c9e2d2fa052cc6d9fab08af51c603d7e20e5 Mon Sep 17 00:00:00 2001
From: Pavel Raiskup <praiskup@redhat.com>
Date: Fri, 16 Jul 2021 12:52:03 +0200
Subject: [PATCH] Fix 'dnf copr enable' on Fedora 35
The output from linux_distribution() changed so it returns:
>>> distro.linux_distribution()
('Fedora Linux', '35', '')
---
plugins/copr.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/plugins/copr.py b/plugins/copr.py
index 7fc6c6f..235989b 100644
--- a/plugins/copr.py
+++ b/plugins/copr.py
@@ -430,7 +430,7 @@ Bugzilla. In case of problems, contact the owner of this repository.
dist = linux_distribution()
# Get distribution architecture
distarch = self.base.conf.substitutions['basearch']
- if "Fedora" in dist:
+ if any([name in dist for name in ["Fedora", "Fedora Linux"]]):
if "Rawhide" in dist:
chroot = ("fedora-rawhide-" + distarch)
# workaround for enabling repos in Rawhide when VERSION in os-release
--
2.36.1

@ -0,0 +1,37 @@
From 517f0093218e3c23097d7e7e3f3d65930059ef82 Mon Sep 17 00:00:00 2001
From: Silvie Chlupova <sisi.chlupova@gmail.com>
Date: Thu, 12 Aug 2021 16:24:56 +0200
Subject: [PATCH] Disable dnf playground command
= changelog =
msg: playground command doesn't work
type: bugfix
related: https://bugzilla.redhat.com/show_bug.cgi?id=1955907
---
plugins/copr.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/plugins/copr.py b/plugins/copr.py
index 235989b..e1e7018 100644
--- a/plugins/copr.py
+++ b/plugins/copr.py
@@ -122,6 +122,8 @@ class CoprCommand(dnf.cli.Command):
parser.add_argument('arg', nargs='*')
def configure(self):
+ if self.cli.command.opts.command != "copr":
+ return
copr_hub = None
copr_plugin_config = ConfigParser()
config_files = []
@@ -680,6 +682,7 @@ class PlaygroundCommand(CoprCommand):
choices=['enable', 'disable', 'upgrade'])
def run(self):
+ raise dnf.exceptions.Error("Playground is temporarily unsupported")
subcommand = self.opts.subcommand[0]
chroot = self._guess_chroot()
if subcommand == "enable":
--
2.36.1

@ -0,0 +1,29 @@
From 7f9d6809f7cb9ac48f11ef02a4e7c0cadeef9594 Mon Sep 17 00:00:00 2001
From: Silvie Chlupova <sisi.chlupova@gmail.com>
Date: Wed, 22 Sep 2021 22:35:21 +0200
Subject: [PATCH] Fix baseurl for centos stream chroot
= changelog =
msg: dnf copr enable on CentOS Stream should enable centos stream chroot, not epel 8
type: bugfix
resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1994154
---
plugins/copr.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/plugins/copr.py b/plugins/copr.py
index e1e7018..c216408 100644
--- a/plugins/copr.py
+++ b/plugins/copr.py
@@ -457,6 +457,8 @@ Bugzilla. In case of problems, contact the owner of this repository.
chroot = ("opensuse-tumbleweed-{}".format(distarch))
else:
chroot = ("opensuse-leap-{0}-{1}".format(dist[1], distarch))
+ elif "CentOS Stream" in dist:
+ chroot = ("centos-stream-{0}-{1}".format(dist[1], distarch))
else:
chroot = ("epel-%s-x86_64" % dist[1].split(".", 1)[0])
return chroot
--
2.36.1

@ -0,0 +1,42 @@
From a07db6dcd669eecb27b7ddbf1b85cd842bdcc35b Mon Sep 17 00:00:00 2001
From: Otto Urpelainen <oturpe@iki.fi>
Date: Wed, 6 Oct 2021 22:08:54 +0300
Subject: [PATCH] Silence a deprecation warning in plugins/copr.py
In version 1.6.0, the 'distro' package deprecated linux_distribution().
This causes a deprecation warning to printed to stdout
every time the user calls the copr plugin.
In order to avoid the printout
and to protect against possible removal in the future,
the function is reimplemented
using still supported functions from 'distro'.
= changelog =
msg: [copr] Avoid using deprecated function distro.linux_distribution()
type: bugfix
resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2011550
---
plugins/copr.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/plugins/copr.py b/plugins/copr.py
index c216408..9f597dd 100644
--- a/plugins/copr.py
+++ b/plugins/copr.py
@@ -38,7 +38,11 @@ import rpm
# If that fails, attempt to import the deprecated implementation
# from the platform module.
try:
- from distro import linux_distribution, os_release_attr
+ from distro import name, version, codename, os_release_attr
+
+ # Re-implement distro.linux_distribution() to avoid a deprecation warning
+ def linux_distribution():
+ return (name(), version(), codename())
except ImportError:
def os_release_attr(_):
return ""
--
2.36.1

@ -0,0 +1,49 @@
From bf230d570763acc6ccd4f4b3951f4b8325a8e4b8 Mon Sep 17 00:00:00 2001
From: Silvie Chlupova <sisi.chlupova@gmail.com>
Date: Fri, 3 Sep 2021 15:45:43 +0200
Subject: [PATCH] Shorter verification that the project exists
---
plugins/copr.py | 16 ++++++----------
1 file changed, 6 insertions(+), 10 deletions(-)
diff --git a/plugins/copr.py b/plugins/copr.py
index 9f597dd..1539c0d 100644
--- a/plugins/copr.py
+++ b/plugins/copr.py
@@ -70,8 +70,10 @@ NO = set([_('no'), _('n'), ''])
if PY3:
from configparser import ConfigParser, NoOptionError, NoSectionError
+ from urllib.request import urlopen, HTTPError
else:
from ConfigParser import ConfigParser, NoOptionError, NoSectionError
+ from urllib2 import urlopen, HTTPError
@dnf.plugin.register_command
class CoprCommand(dnf.cli.Command):
@@ -478,17 +480,11 @@ Bugzilla. In case of problems, contact the owner of this repository.
if os.path.exists(repo_filename):
os.remove(repo_filename)
if '404' in str(e):
- if PY3:
- import urllib.request
- try:
- res = urllib.request.urlopen(self.copr_url + "/coprs/" + project_name)
- status_code = res.getcode()
- except urllib.error.HTTPError as e:
- status_code = e.getcode()
- else:
- import urllib
- res = urllib.urlopen(self.copr_url + "/coprs/" + project_name)
+ try:
+ res = urlopen(self.copr_url + "/coprs/" + project_name)
status_code = res.getcode()
+ except HTTPError as e:
+ status_code = e.getcode()
if str(status_code) != '404':
raise dnf.exceptions.Error(_("This repository does not have"
" any builds yet so you cannot enable it now."))
--
2.36.1

@ -0,0 +1,114 @@
From 1d097d0e4ecfef78aec5d760278b44d5f3192cdc Mon Sep 17 00:00:00 2001
From: Silvie Chlupova <sisi.chlupova@gmail.com>
Date: Mon, 2 Aug 2021 15:04:17 +0200
Subject: [PATCH] Better error message for dnf copr enable
= changelog =
msg: show better error message if the command dnf copr enable fails
type: enhancement
---
plugins/copr.py | 63 +++++++++++++++++++++++++++++++------------------
1 file changed, 40 insertions(+), 23 deletions(-)
diff --git a/plugins/copr.py b/plugins/copr.py
index 1539c0d..721c010 100644
--- a/plugins/copr.py
+++ b/plugins/copr.py
@@ -27,6 +27,8 @@ import re
import shutil
import stat
import sys
+import base64
+import json
from dnfpluginscore import _, logger
import dnf
@@ -70,10 +72,10 @@ NO = set([_('no'), _('n'), ''])
if PY3:
from configparser import ConfigParser, NoOptionError, NoSectionError
- from urllib.request import urlopen, HTTPError
+ from urllib.request import urlopen, HTTPError, URLError
else:
from ConfigParser import ConfigParser, NoOptionError, NoSectionError
- from urllib2 import urlopen, HTTPError
+ from urllib2 import urlopen, HTTPError, URLError
@dnf.plugin.register_command
class CoprCommand(dnf.cli.Command):
@@ -475,28 +477,40 @@ Bugzilla. In case of problems, contact the owner of this repository.
api_path = "/coprs/{0}/repo/{1}/dnf.repo?arch={2}".format(project_name, short_chroot, arch)
try:
- f = self.base.urlopen(self.copr_url + api_path, mode='w+')
- except IOError as e:
+ response = urlopen(self.copr_url + api_path)
if os.path.exists(repo_filename):
os.remove(repo_filename)
- if '404' in str(e):
- try:
- res = urlopen(self.copr_url + "/coprs/" + project_name)
- status_code = res.getcode()
- except HTTPError as e:
- status_code = e.getcode()
- if str(status_code) != '404':
- raise dnf.exceptions.Error(_("This repository does not have"
- " any builds yet so you cannot enable it now."))
- else:
- raise dnf.exceptions.Error(_("Such repository does not exist."))
- raise
-
- for line in f:
- if re.match(r"\[copr:", line):
- repo_filename = os.path.join(self.base.conf.get_reposdir,
- "_" + line[1:-2] + ".repo")
- break
+ except HTTPError as e:
+ if e.code != 404:
+ error_msg = _("Request to {0} failed: {1} - {2}").format(self.copr_url + api_path, e.code, str(e))
+ raise dnf.exceptions.Error(error_msg)
+ error_msg = _("It wasn't possible to enable this project.\n")
+ error_data = e.headers.get("Copr-Error-Data")
+ if error_data:
+ error_data_decoded = base64.b64decode(error_data).decode('utf-8')
+ error_data_decoded = json.loads(error_data_decoded)
+ error_msg += _("Repository '{0}' does not exist in project '{1}'.").format(
+ '-'.join(self.chroot_parts), project_name)
+ if error_data_decoded.get("available chroots"):
+ error_msg += _("\nAvailable repositories: ") + ', '.join(
+ "'{}'".format(x) for x in error_data_decoded["available chroots"])
+ error_msg += _("\n\nIf you want to enable a non-default repository, use the following command:\n"
+ " 'dnf copr enable {0} <repository>'\n"
+ "But note that the installed repo file will likely need a manual "
+ "modification.").format(project_name)
+ raise dnf.exceptions.Error(error_msg)
+ else:
+ error_msg += _("Project {0} does not exist.").format(project_name)
+ raise dnf.exceptions.Error(error_msg)
+ except URLError as e:
+ error_msg = _("Failed to connect to {0}: {1}").format(self.copr_url + api_path, e.reason.strerror)
+ raise dnf.exceptions.Error(error_msg)
+
+ # Try to read the first line, and detect the repo_filename from that (override the repo_filename value).
+ first_line = response.readline()
+ line = first_line.decode("utf-8")
+ if re.match(r"\[copr:", line):
+ repo_filename = os.path.join(self.base.conf.get_reposdir, "_" + line[1:-2] + ".repo")
# if using default hub, remove possible old repofile
if self.copr_url == self.default_url:
@@ -507,7 +521,10 @@ Bugzilla. In case of problems, contact the owner of this repository.
if os.path.exists(old_repo_filename):
os.remove(old_repo_filename)
- shutil.copy2(f.name, repo_filename)
+ with open(repo_filename, 'wb') as f:
+ f.write(first_line)
+ for line in response.readlines():
+ f.write(line)
os.chmod(repo_filename, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH)
def _runtime_deps_warning(self, copr_username, copr_projectname):
--
2.36.1

@ -0,0 +1,33 @@
From b2d019658ebb40606e1a9efcb2233a8e38834410 Mon Sep 17 00:00:00 2001
From: Alexander Sosedkin <asosedkin@redhat.com>
Date: Thu, 7 Oct 2021 19:08:47 +0200
Subject: [PATCH] copr: allow specifying protocol as part of --hub
This way it doesn't try to connect to
https://http//url if --hub started with http://.
---
plugins/copr.py | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/plugins/copr.py b/plugins/copr.py
index 721c010..297210b 100644
--- a/plugins/copr.py
+++ b/plugins/copr.py
@@ -198,8 +198,12 @@ class CoprCommand(dnf.cli.Command):
self.copr_hostname += ":" + port
if not self.copr_url:
- self.copr_hostname = copr_hub
- self.copr_url = self.default_protocol + "://" + copr_hub
+ if '://' not in copr_hub:
+ self.copr_hostname = copr_hub
+ self.copr_url = self.default_protocol + "://" + copr_hub
+ else:
+ self.copr_hostname = copr_hub.split('://', 1)[1]
+ self.copr_url = copr_hub
def _read_config_item(self, config, hub, section, default):
try:
--
2.36.1

@ -0,0 +1,37 @@
From 4b0001d0f13598369ec2e6a800af519e8c3a334c Mon Sep 17 00:00:00 2001
From: Carl George <carl@george.computer>
Date: Mon, 27 Jun 2022 23:12:05 -0500
Subject: [PATCH] copr: Guess EPEL chroots for CentOS Stream (RhBug:2058471)
Packages built in epel-9 chroots are almost always compatible with
CentOS Stream 9. Not having the copr plugin guess this chroot is
causing user friction. Users are creating epel-9 chroots expecting them
to work for both CentOS Stream 9 and RHEL 9. When they get reports
about `dnf copr enable` not working, they try to add a centos-stream-9
chroot, only to discover the dependencies they need from EPEL are not
available.
Instead of making the majority of CentOS Stream users include an
explicit chroot argument, let's reserve that workaround only for the
people that don't want their CentOS Stream systems picking the EPEL
chroot.
---
plugins/copr.py | 2 --
1 file changed, 2 deletions(-)
diff --git a/plugins/copr.py b/plugins/copr.py
index 297210b..16946b7 100644
--- a/plugins/copr.py
+++ b/plugins/copr.py
@@ -469,8 +469,6 @@ Bugzilla. In case of problems, contact the owner of this repository.
chroot = ("opensuse-tumbleweed-{}".format(distarch))
else:
chroot = ("opensuse-leap-{0}-{1}".format(dist[1], distarch))
- elif "CentOS Stream" in dist:
- chroot = ("centos-stream-{0}-{1}".format(dist[1], distarch))
else:
chroot = ("epel-%s-x86_64" % dist[1].split(".", 1)[0])
return chroot
--
2.36.1

@ -0,0 +1,45 @@
From 0afd47edc60fb7fe5c72fa64bca413bdce82d900 Mon Sep 17 00:00:00 2001
From: Jan Kolarik <jkolarik@redhat.com>
Date: Thu, 11 Aug 2022 14:12:06 +0200
Subject: [PATCH] builddep: Warning when using macros with source rpms
(RhBug:2077820)
= changelog =
type: bugfix
resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2077820
---
doc/builddep.rst | 2 +-
plugins/builddep.py | 4 ++++
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/doc/builddep.rst b/doc/builddep.rst
index 6e9bde6..97eb823 100644
--- a/doc/builddep.rst
+++ b/doc/builddep.rst
@@ -31,7 +31,7 @@ All general DNF options are accepted, see `Options` in :manpage:`dnf(8)` for det
Show this help.
``-D <macro expr>, --define <macro expr>``
- Define the RPM macro named `macro` to the value `expr` when parsing spec files.
+ Define the RPM macro named `macro` to the value `expr` when parsing spec files. Does not apply for source rpm files.
``--spec``
Treat arguments as .spec files.
diff --git a/plugins/builddep.py b/plugins/builddep.py
index e3da012..e7dac43 100644
--- a/plugins/builddep.py
+++ b/plugins/builddep.py
@@ -204,6 +204,10 @@ class BuildDepCommand(dnf.cli.Command):
err = _("Not all dependencies satisfied")
raise dnf.exceptions.Error(err)
+ if self.opts.define:
+ logger.warning(_("Warning: -D or --define arguments have no meaning "
+ "for source rpm packages."))
+
def _spec_deps(self, spec_fn):
try:
spec = rpm.spec(spec_fn)
--
2.37.1

@ -0,0 +1,78 @@
From e52655aa9c7c9ad334639990d612da574b57736b Mon Sep 17 00:00:00 2001
From: Jan Kolarik <jkolarik@redhat.com>
Date: Fri, 30 Sep 2022 11:36:26 +0000
Subject: [PATCH 1/3] Add a warning when using `system-upgrade` on RHEL
---
dnf-plugins-core.spec | 3 +--
doc/system-upgrade.rst | 6 ++++--
plugins/system_upgrade.py | 4 ++++
3 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/dnf-plugins-core.spec b/dnf-plugins-core.spec
index 0e1c9e3..a5ec165 100644
--- a/dnf-plugins-core.spec
+++ b/dnf-plugins-core.spec
@@ -148,14 +148,13 @@ Summary: Core Plugins for DNF
%{?python_provide:%python_provide python3-%{name}}
BuildRequires: python3-dbus
BuildRequires: python3-devel
+BuildRequires: python3-distro
BuildRequires: python3-dnf >= %{dnf_lowest_compatible}
BuildRequires: python3-systemd
BuildRequires: pkgconfig(systemd)
BuildRequires: systemd
%{?systemd_ordering}
-%if 0%{?fedora}
Requires: python3-distro
-%endif
Requires: python3-dbus
Requires: python3-dnf >= %{dnf_lowest_compatible}
Requires: python3-hawkey >= %{hawkey_version}
diff --git a/doc/system-upgrade.rst b/doc/system-upgrade.rst
index 3110460..87b7319 100644
--- a/doc/system-upgrade.rst
+++ b/doc/system-upgrade.rst
@@ -27,13 +27,15 @@ DNF system-upgrades plugin provides three commands: ``system-upgrade``, ``offlin
``offline-distrosync``. Only ``system-upgrade`` command requires increase of distribution major
version (``--releasever``) compared to installed version.
-``dnf system-upgrade`` can be used to upgrade a Fedora system to a new major
-release. It replaces fedup (the old Fedora Upgrade tool). Before you proceed ensure that your system
+``dnf system-upgrade`` is a recommended way to upgrade a system to a new major release.
+It replaces fedup (the old Fedora Upgrade tool). Before you proceed ensure that your system
is fully upgraded (``dnf --refresh upgrade``).
The ``system-upgrade`` command also performes additional actions necessary for the upgrade of the
system, for example an upgrade of groups and environments.
+.. WARNING:: The ``system-upgrade`` command is not supported on the RHEL distribution.
+
--------
Synopsis
--------
diff --git a/plugins/system_upgrade.py b/plugins/system_upgrade.py
index fee6762..0baf978 100644
--- a/plugins/system_upgrade.py
+++ b/plugins/system_upgrade.py
@@ -20,6 +20,7 @@
"""system_upgrade.py - DNF plugin to handle major-version system upgrades."""
from subprocess import call, Popen, check_output, CalledProcessError
+import distro
import json
import os
import os.path
@@ -451,6 +452,9 @@ class SystemUpgradeCommand(dnf.cli.Command):
def configure_download(self):
if 'system-upgrade' == self.opts.command or 'fedup' == self.opts.command:
+ if distro.id() == 'rhel':
+ logger.warning(_('WARNING: this operation is not supported on the RHEL distribution. '
+ 'Proceed at your own risk.'))
help_url = get_url_from_os_release()
if help_url:
msg = _('Additional information for System Upgrade: {}')
--
2.38.1

@ -0,0 +1,61 @@
From 3a18b7241708a3c5fd1b4b92a2f9908a826e815d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tarc=C3=ADsio=20Ladeia=20de=20Oliveira?=
<wyrquill@gmail.com>
Date: Thu, 20 Oct 2022 22:16:59 -0300
Subject: [PATCH 1/2] [offline-upgrade] Add security filters (RhBug:1939975)
Add support for security filter options that are available in the main
`dnf` commands, that is, `--advisory`, `--bugfix`, `--security`, and
`--enhancement`.
= changelog =
msg: [offline-upgrade] Add support for security filters
type: bugfix
resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1939975
---
plugins/system_upgrade.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/plugins/system_upgrade.py b/plugins/system_upgrade.py
index 0baf978..ef1de73 100644
--- a/plugins/system_upgrade.py
+++ b/plugins/system_upgrade.py
@@ -467,6 +467,9 @@ class SystemUpgradeCommand(dnf.cli.Command):
logger.error(_("Operation aborted."))
sys.exit(1)
check_release_ver(self.base.conf, target=self.opts.releasever)
+ elif 'offline-upgrade' == self.opts.command:
+ self.cli._populate_update_security_filter(self.opts)
+
self.cli.demands.root_user = True
self.cli.demands.resolving = True
self.cli.demands.available_repos = True
--
2.38.1
From dad20a478e100bd0ac3a8d7d51dad75baca90c7f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tarc=C3=ADsio=20Ladeia=20de=20Oliveira?=
<wyrquill@gmail.com>
Date: Thu, 20 Oct 2022 22:27:22 -0300
Subject: [PATCH 2/2] Add myself as contributor in AUTHORS
---
AUTHORS | 1 +
1 file changed, 1 insertion(+)
diff --git a/AUTHORS b/AUTHORS
index 33512fd..cd4b5be 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -32,6 +32,7 @@ DNF-PLUGINS-CORE CONTRIBUTORS
Neal Gompa <ngompa13@gmail.com>
Paul Howarth <paul@city-fan.org>
Rickard Dybeck <r.dybeck@gmail.com>
+ Tarcísio Ladeia de Oliveira <wyrquill@gmail.com>
Tomas Babej <tomasbabej@gmail.com>
Vladan Kudlac <vladankudlac@gmail.com>
Wieland Hoffmann <themineo@gmail.com>
--
2.38.1

@ -0,0 +1,62 @@
From dfbda502c5c46daf84e00179478de01e452f9dae Mon Sep 17 00:00:00 2001
From: Jan Kolarik <jkolarik@redhat.com>
Date: Fri, 16 Dec 2022 05:55:19 +0000
Subject: [PATCH] system-upgrade: Show warning always for a downstream
As the distro package is not available in the BaseOS, the warning implementation will be shown always, but only in related downstreams.
= changelog =
type: bugfix
resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2152846
---
dnf-plugins-core.spec | 3 ++-
plugins/system_upgrade.py | 6 ++----
2 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/dnf-plugins-core.spec b/dnf-plugins-core.spec
index a5ec165..0e1c9e3 100644
--- a/dnf-plugins-core.spec
+++ b/dnf-plugins-core.spec
@@ -148,13 +148,14 @@ Summary: Core Plugins for DNF
%{?python_provide:%python_provide python3-%{name}}
BuildRequires: python3-dbus
BuildRequires: python3-devel
-BuildRequires: python3-distro
BuildRequires: python3-dnf >= %{dnf_lowest_compatible}
BuildRequires: python3-systemd
BuildRequires: pkgconfig(systemd)
BuildRequires: systemd
%{?systemd_ordering}
+%if 0%{?fedora}
Requires: python3-distro
+%endif
Requires: python3-dbus
Requires: python3-dnf >= %{dnf_lowest_compatible}
Requires: python3-hawkey >= %{hawkey_version}
diff --git a/plugins/system_upgrade.py b/plugins/system_upgrade.py
index ef1de73..4f7620f 100644
--- a/plugins/system_upgrade.py
+++ b/plugins/system_upgrade.py
@@ -20,7 +20,6 @@
"""system_upgrade.py - DNF plugin to handle major-version system upgrades."""
from subprocess import call, Popen, check_output, CalledProcessError
-import distro
import json
import os
import os.path
@@ -452,9 +451,8 @@ class SystemUpgradeCommand(dnf.cli.Command):
def configure_download(self):
if 'system-upgrade' == self.opts.command or 'fedup' == self.opts.command:
- if distro.id() == 'rhel':
- logger.warning(_('WARNING: this operation is not supported on the RHEL distribution. '
- 'Proceed at your own risk.'))
+ logger.warning(_('WARNING: this operation is not supported on the RHEL distribution. '
+ 'Proceed at your own risk.'))
help_url = get_url_from_os_release()
if help_url:
msg = _('Additional information for System Upgrade: {}')
--
2.39.0

File diff suppressed because it is too large Load Diff

@ -0,0 +1,88 @@
From ee0e1ca0751d29adcc4788334ce8fd74b4d772c9 Mon Sep 17 00:00:00 2001
From: Marek Blaha <mblaha@redhat.com>
Date: Wed, 19 May 2021 16:52:57 +0200
Subject: [PATCH] versionlock: Store full NEVRA
---
plugins/versionlock.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/plugins/versionlock.py b/plugins/versionlock.py
index 77b7f91..8a3994e 100644
--- a/plugins/versionlock.py
+++ b/plugins/versionlock.py
@@ -312,5 +312,4 @@ def _match(ent, patterns):
def pkgtup2spec(name, arch, epoch, version, release):
# we ignore arch
- e = "" if epoch in (None, "") else "%s:" % epoch
- return "%s-%s%s-%s.*" % (name, e, version, release)
+ return "%s-%s:%s-%s.*" % (name, epoch or "0", version, release)
--
2.40.1
From da25d50a8753b0a648a2653e2fb9e33eb372f73f Mon Sep 17 00:00:00 2001
From: Marek Blaha <mblaha@redhat.com>
Date: Wed, 19 May 2021 16:53:37 +0200
Subject: [PATCH] versionlock: Use only the most specific NEVRA (RhBug:1961217)
When matching patterns from versionlock.list file accept only the most
specific possible NEVRA.
The problem with current implementation (using of all possible variants)
is following (also see the referenced bug):
$ dnf repoquery procps-ng
procps-ng-0:3.3.17-1.fc34.1.x86_64
procps-ng-0:3.3.17-1.fc34.x86_64 <-- this one is installed
See the `.1` minorbump part of the release after %{dist} in
`procps-ng-0:3.3.17-1.fc34.1.x86_64`
$ dnf versionlock procps-ng
Adding versionlock on: procps-ng-0:3.3.17-1.fc34.*
Now both of the available procps-ng version could be matched by this
pattern:
- procps-ng-0:3.3.17-1.fc34.x86_64 (when `*` is considered arch)
- procps-ng-0:3.3.17-1.fc34.1.x86_64 (when `*` is matched against
release part, and arch is considered not present)
That results in versionlock allowing upgrade to a newer version than the
locked one.
= changelog =
msg: Versionlock works correctly with packages with minorbump part of release
type: bugfix
resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1961217
---
plugins/versionlock.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/plugins/versionlock.py b/plugins/versionlock.py
index 8a3994e..32c51da 100644
--- a/plugins/versionlock.py
+++ b/plugins/versionlock.py
@@ -89,7 +89,9 @@ class VersionLock(dnf.Plugin):
pat = pat[1:]
excl = 1
- possible_nevras = dnf.subject.Subject(pat).get_nevra_possibilities()
+ possible_nevras = dnf.subject.Subject(pat).get_nevra_possibilities(
+ forms=[hawkey.FORM_NEVRA, hawkey.FORM_NEVR, hawkey.FORM_NEV,
+ hawkey.FORM_NA, hawkey.FORM_NAME])
if possible_nevras:
count[excl] += 1
else:
@@ -102,6 +104,8 @@ class VersionLock(dnf.Plugin):
else:
locked_names.add(nevra.name)
locked_query = locked_query.union(pat_query)
+ if pat_query:
+ break
if count[1]:
logger.debug(APPLY_EXCLUDE.format(locklist_fn, count[1]))
--
2.40.1

@ -0,0 +1,55 @@
From 23a6123348f0a387768ebdfdaaded900a083039e Mon Sep 17 00:00:00 2001
From: Todd Lewis <todd_lewis@unc.edu>
Date: Wed, 16 Nov 2022 10:45:39 -0500
Subject: [PATCH] Fix boot time derivation for systems with no rtc
That addresses https://bugzilla.redhat.com/show_bug.cgi?id=2137935
---
plugins/needs_restarting.py | 24 +++++++++++++++++++++++-
1 file changed, 23 insertions(+), 1 deletion(-)
diff --git a/plugins/needs_restarting.py b/plugins/needs_restarting.py
index 91dbe66..03831fa 100644
--- a/plugins/needs_restarting.py
+++ b/plugins/needs_restarting.py
@@ -34,6 +34,7 @@ import functools
import os
import re
import stat
+import time
# For which package updates we should recommend a reboot
@@ -199,7 +200,28 @@ class ProcessStart(object):
@staticmethod
def get_boot_time():
- return int(os.stat('/proc/1').st_mtime)
+ """
+ We have two sources from which to derive the boot time. These values vary
+ depending on containerization, existence of a Real Time Clock, etc.
+ For our purposes we want the latest derived value.
+ - st_mtime of /proc/1
+ Reflects the time the first process was run after booting
+ This works for all known cases except machines without
+ a RTC - they awake at the start of the epoch.
+ - /proc/uptime
+ Seconds field of /proc/uptime subtracted from the current time
+ Works for machines without RTC iff the current time is reasonably correct.
+ Does not work on containers which share their kernel with the
+ host - there the host kernel uptime is returned
+ """
+
+ proc_1_boot_time = int(os.stat('/proc/1').st_mtime)
+ if os.path.isfile('/proc/uptime'):
+ with open('/proc/uptime', 'rb') as f:
+ uptime = f.readline().strip().split()[0].strip()
+ proc_uptime_boot_time = int(time.time() - float(uptime))
+ return max(proc_1_boot_time, proc_uptime_boot_time)
+ return proc_1_boot_time
@staticmethod
def get_sc_clk_tck():
--
libgit2 1.3.2

@ -0,0 +1,34 @@
From a83af3db9f1aaf698be5455a01814849e39307d8 Mon Sep 17 00:00:00 2001
From: Jaroslav Mracek <jmracek@redhat.com>
Date: Mon, 27 Mar 2023 10:24:59 +0200
Subject: [PATCH] Documentation update for reposync (RhBug:2132383,2182004)
The update describe the behavior when `-n` and `--download-metadata`
is used.
https://bugzilla.redhat.com/show_bug.cgi?id=2132383
https://bugzilla.redhat.com/show_bug.cgi?id=2182004
---
doc/reposync.rst | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/doc/reposync.rst b/doc/reposync.rst
index 0df00b9..bbf714c 100644
--- a/doc/reposync.rst
+++ b/doc/reposync.rst
@@ -46,7 +46,11 @@ All general DNF options are accepted. Namely, the ``--repoid`` option can be use
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.
+ Download all repository metadata. Downloaded copy is instantly usable as a repository, no need to run createrepo_c
+ on it. When the option is used with `--newest-only`, only latest packages will be downloaded, but metadata will
+ still contain older packages. It might be useful to update metadata using `createrepo_c --update` to remove
+ the packages with missing RPM files from metadata. Otherwise, DNF ends with an error due to the missing files
+ whenever it tries to download older packages.
``-g, --gpgcheck``
Remove packages that fail GPG signature checking after downloading. Exit code is ``1`` if at least one package was removed.
--
libgit2 1.3.2

@ -0,0 +1,88 @@
From b086bfe09cf0eec67ea830e0e0f3482c6b6b2aa9 Mon Sep 17 00:00:00 2001
From: Andy Baugh <andy@troglodyne.net>
Date: Fri, 28 Apr 2023 10:52:16 -0500
Subject: [PATCH] Add fix and test assertion for "no systemd unit exists for
pid"
= changelog =
msg: Catch exception in needs-restarting.py when no systemd unit exists for pid
type: bugfix
resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2122587
related: None
---
plugins/needs_restarting.py | 18 ++++++++++++++----
tests/test_needs_restarting.py | 15 +++++++++++++--
2 files changed, 27 insertions(+), 6 deletions(-)
diff --git a/plugins/needs_restarting.py b/plugins/needs_restarting.py
index 03831fa..8dbc965 100644
--- a/plugins/needs_restarting.py
+++ b/plugins/needs_restarting.py
@@ -138,10 +138,20 @@ def get_service_dbus(pid):
systemd_manager_object,
'org.freedesktop.systemd1.Manager'
)
- service_proxy = bus.get_object(
- 'org.freedesktop.systemd1',
- systemd_manager_interface.GetUnitByPID(pid)
- )
+ service_proxy = None
+ try:
+ service_proxy = bus.get_object(
+ 'org.freedesktop.systemd1',
+ systemd_manager_interface.GetUnitByPID(pid)
+ )
+ except dbus.DBusException as e:
+ # There is no unit for the pid. Usually error is 'NoUnitForPid'.
+ # Considering what we do at the bottom (just return if not service)
+ # Then there's really no reason to exit here on that exception.
+ # Log what's happened then move on.
+ msg = str(e)
+ logger.warning("Failed to get systemd unit for PID {}: {}".format(pid, msg))
+ return
service_properties = dbus.Interface(
service_proxy, dbus_interface="org.freedesktop.DBus.Properties")
name = service_properties.Get(
diff --git a/tests/test_needs_restarting.py b/tests/test_needs_restarting.py
index 0ad70a5..7b629b4 100644
--- a/tests/test_needs_restarting.py
+++ b/tests/test_needs_restarting.py
@@ -20,6 +20,8 @@ from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals
+from unittest.mock import patch, Mock
+import dbus
import needs_restarting
import tests.support
@@ -29,8 +31,6 @@ MM_FILE = '7fc4e1168000-7fc4e1169000 rw-s 1096dd000 00:05 7749' \
' /dev/dri/card0'
SO_FILE = '30efe06000-30efe07000 r--p 00006000 08:02 139936' \
' /usr/lib64/libSM.so.6.0.1'
-
-
class NeedsRestartingTest(tests.support.TestCase):
def test_smap2opened_file(self):
func = needs_restarting.smap2opened_file
@@ -46,6 +46,17 @@ class NeedsRestartingTest(tests.support.TestCase):
self.assertTrue(ofile.deleted)
self.assertEqual(ofile.name, '/usr/lib64/libXfont.so.1.4.1;5408628d')
+ def test_get_service_dbus_nounitforpid(self):
+ func = needs_restarting.get_service_dbus
+ # So, This is gonna look kinda screwy unless you are aware of what
+ # this proxies interface is actually doing. The GetUnitByPid function
+ # is normally "dynamically" defined by the get_dbus_method at runtime.
+ # As such there's no actual way to mock it out in any meaningful way
+ # without create=True.
+ with patch( "dbus.proxies.Interface.GetUnitByPID", create=True, side_effect=dbus.DBusException('org.freedesktop.systemd1.NoUnitForPID: PID 1234 does not belong to any loaded unit.') ), \
+ patch( "dbus.SystemBus", return_value=Mock(spec=dbus.Bus) ), \
+ patch( "dbus.bus.BusConnection.__new__", side_effect=dbus.DBusException("Never should hit this exception if mock above works")):
+ self.assertIsNone(func(1234))
class OpenedFileTest(tests.support.TestCase):
def test_presumed_name(self):
--
2.40.1

@ -0,0 +1,51 @@
From b5e6219b12773b76f634641752fa6f194608e1ff Mon Sep 17 00:00:00 2001
From: Nicola Sella <nsella@redhat.com>
Date: Wed, 21 Jun 2023 15:21:57 +0200
Subject: [PATCH] Fix zlib reboot requirement (RhBug:2092033)
---
plugins/needs_restarting.py | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/plugins/needs_restarting.py b/plugins/needs_restarting.py
index 8dbc965..3197fe1 100644
--- a/plugins/needs_restarting.py
+++ b/plugins/needs_restarting.py
@@ -42,6 +42,8 @@ import time
NEED_REBOOT = ['kernel', 'kernel-rt', 'glibc', 'linux-firmware',
'systemd', 'dbus', 'dbus-broker', 'dbus-daemon']
+NEED_REBOOT_DEPENDS_ON_DBUS = ['zlib']
+
def get_options_from_dir(filepath, base):
"""
Provide filepath as string if single dir or list of strings
@@ -277,15 +279,24 @@ class NeedsRestartingCommand(dnf.cli.Command):
NEED_REBOOT.extend(opt)
if self.opts.reboothint:
need_reboot = set()
+ need_reboot_depends_on_dbus = set()
installed = self.base.sack.query().installed()
for pkg in installed.filter(name=NEED_REBOOT):
if pkg.installtime > process_start.boot_time:
need_reboot.add(pkg.name)
- if need_reboot:
+
+ dbus_installed = installed.filter(name=['dbus', 'dbus-daemon', 'dbus-broker'])
+ if len(dbus_installed) != 0:
+ for pkg in installed.filter(name=NEED_REBOOT_DEPENDS_ON_DBUS):
+ if pkg.installtime > process_start.boot_time:
+ need_reboot_depends_on_dbus.add(pkg.name)
+ if need_reboot or need_reboot_depends_on_dbus:
print(_('Core libraries or services have been updated '
'since boot-up:'))
for name in sorted(need_reboot):
print(' * %s' % name)
+ for name in sorted(need_reboot_depends_on_dbus):
+ print(' * %s (dependency of dbus. Recommending reboot of dbus)' % name)
print()
print(_('Reboot is required to fully utilize these updates.'))
print(_('More information:'),
--
2.40.1

@ -0,0 +1,75 @@
From 1a29f3ab2f4719f40510dc08f12f4795ad358e93 Mon Sep 17 00:00:00 2001
From: Andy Baugh <thomas.baugh@cpanel.net>
Date: Tue, 6 Jun 2023 16:37:42 +0000
Subject: [PATCH] Fix for strange issue with binary garbage in smaps files
= changelog =
msg: Avoid issue with garbage smaps chars in needs-restarting.py
type: bugfix
resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2212953
related: None
---
plugins/needs_restarting.py | 2 +-
tests/test_needs_restarting.py | 14 +++++++++++++-
2 files changed, 14 insertions(+), 2 deletions(-)
diff --git a/plugins/needs_restarting.py b/plugins/needs_restarting.py
index 3197fe1..64d4d0f 100644
--- a/plugins/needs_restarting.py
+++ b/plugins/needs_restarting.py
@@ -76,7 +76,7 @@ def list_opened_files(uid):
try:
if uid is not None and uid != owner_uid(smaps):
continue
- with open(smaps, 'r') as smaps_file:
+ with open(smaps, 'r', errors='replace') as smaps_file:
lines = smaps_file.readlines()
except EnvironmentError:
logger.warning("Failed to read PID %d's smaps.", pid)
diff --git a/tests/test_needs_restarting.py b/tests/test_needs_restarting.py
index 7b629b4..d7dd6d5 100644
--- a/tests/test_needs_restarting.py
+++ b/tests/test_needs_restarting.py
@@ -1,3 +1,4 @@
+# coding: utf-8
# Copyright (C) 2014 Red Hat, Inc.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -15,15 +16,15 @@
# Red Hat, Inc.
#
-
from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals
from unittest.mock import patch, Mock
import dbus
import needs_restarting
import tests.support
+import tempfile
DEL_FILE = '3dcf000000-3dcf032000 r-xp 00000000 08:02 140759 ' \
' /usr/lib64/libXfont.so.1.4.1;5408628d (deleted)'
@@ -58,6 +59,17 @@ class NeedsRestartingTest(tests.support.TestCase):
patch( "dbus.bus.BusConnection.__new__", side_effect=dbus.DBusException("Never should hit this exception if mock above works")):
self.assertIsNone(func(1234))
+ def test_list_opened_files_garbage_filename(self):
+ tempObj = tempfile.NamedTemporaryFile()
+ tempFile = tempObj.name
+ with open(tempFile, 'wb') as bogusFile:
+ bogusFile.write(b'151e7f7b7000-151e7f7b8000 r--p 00006000 fd:01 14744 /usr/lib64/lib\xe5Evil-13.37.so')
+ smaps = [[1234,tempObj.name]]
+ with patch("needs_restarting.list_smaps", return_value=smaps):
+ ofiles = list(needs_restarting.list_opened_files(None));
+ self.assertEqual(ofiles[0].presumed_name, '/usr/lib64/lib<69>Evil-13.37.so')
+
+
class OpenedFileTest(tests.support.TestCase):
def test_presumed_name(self):
ofile = needs_restarting.OpenedFile(
--
libgit2 1.6.4

@ -0,0 +1,40 @@
From e1af3642a7811229567284f6901d393a6ce28b62 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= <ppisar@redhat.com>
Date: Thu, 23 Nov 2023 16:26:06 +0100
Subject: [PATCH] needs-restarting: Add microcode_ctl to a reboot list
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
commit 9f46488c6b1ac553989a3fd8a9ea18271451c5e8 upstream.
To fully update CPU microcode, a reboot is needed because the
microcode update should be applied before starting a kernel and other
process.
Therefore recommend a reboot after installing or updating
microcode_ctl package.
https://issues.redhat.com/browse/RHEL-17356
Signed-off-by: Petr Písař <ppisar@redhat.com>
---
plugins/needs_restarting.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/plugins/needs_restarting.py b/plugins/needs_restarting.py
index 64d4d0f..92cde0a 100644
--- a/plugins/needs_restarting.py
+++ b/plugins/needs_restarting.py
@@ -40,7 +40,8 @@ import time
# For which package updates we should recommend a reboot
# Mostly taken from https://access.redhat.com/solutions/27943
NEED_REBOOT = ['kernel', 'kernel-rt', 'glibc', 'linux-firmware',
- 'systemd', 'dbus', 'dbus-broker', 'dbus-daemon']
+ 'systemd', 'dbus', 'dbus-broker', 'dbus-daemon',
+ 'microcode_ctl']
NEED_REBOOT_DEPENDS_ON_DBUS = ['zlib']
--
2.43.0

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save