Auto sync2gitlab import of dnf-plugins-core-4.0.21-11.el8.src.rpm

This commit is contained in:
James Antill 2022-05-26 01:20:39 -04:00
parent c0bddb589e
commit 28e5761fa2
16 changed files with 9564 additions and 1 deletions

1
.gitignore vendored Normal file
View File

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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

1
EMPTY
View File

@ -1 +0,0 @@

1614
dnf-plugins-core.spec Normal file

File diff suppressed because it is too large Load Diff

1
sources Normal file
View File

@ -0,0 +1 @@
SHA512 (dnf-plugins-core-4.0.21.tar.gz) = e114d6ad3243b53a903714ac524adf73962d12a1ae75f8a65b7318babaa7aa4dccb6e506b219b374de8d8cde139ef460318fb7104bed77f0ee7ee87e885c10b1