Blame SOURCES/0013-Package-add-a-get-header--method.patch

31f77b
From 38cc67385fb1b36aa0881bc5982bc58d75dac464 Mon Sep 17 00:00:00 2001
31f77b
From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hr=C3=A1zk=C3=BD?= <lhrazky@redhat.com>
31f77b
Date: Wed, 11 Nov 2020 18:45:11 +0100
31f77b
Subject: [PATCH] Package: add a get_header() method (RhBug:1876606)
31f77b
31f77b
Adds get_header() method to the Package class, which returns the rpm
31f77b
header of an installed package.
31f77b
31f77b
= changelog =
31f77b
msg: Add get_header() method to the Package class
31f77b
type: enhancement
31f77b
resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1876606
31f77b
---
31f77b
 dnf/package.py        | 24 ++++++++++++++++++++++++
31f77b
 tests/test_package.py | 12 ++++++++++++
31f77b
 2 files changed, 36 insertions(+)
31f77b
31f77b
diff --git a/dnf/package.py b/dnf/package.py
31f77b
index baef04fa5b..836e0e4989 100644
31f77b
--- a/dnf/package.py
31f77b
+++ b/dnf/package.py
31f77b
@@ -26,11 +26,13 @@
31f77b
 from dnf.i18n import _
31f77b
 
31f77b
 import binascii
31f77b
+import dnf.exceptions
31f77b
 import dnf.rpm
31f77b
 import dnf.yum.misc
31f77b
 import hawkey
31f77b
 import logging
31f77b
 import os
31f77b
+import rpm
31f77b
 
31f77b
 logger = logging.getLogger("dnf")
31f77b
 
31f77b
@@ -95,6 +97,11 @@ def from_repo(self):
31f77b
 
31f77b
     @property
31f77b
     def _header(self):
31f77b
+        """
31f77b
+        Returns the header of a locally present rpm package file. As opposed to
31f77b
+        self.get_header(), which retrieves the header of an installed package
31f77b
+        from rpmdb.
31f77b
+        """
31f77b
         return dnf.rpm._header(self.localPkg())
31f77b
 
31f77b
     @property
31f77b
@@ -164,6 +171,23 @@ def debugsource_name(self):
31f77b
         src_name = self.source_name if self.source_name is not None else self.name
31f77b
         return src_name + self.DEBUGSOURCE_SUFFIX
31f77b
 
31f77b
+    def get_header(self):
31f77b
+        """
31f77b
+        Returns the rpm header of the package if it is installed. If not
31f77b
+        installed, returns None. The header is not cached, it is retrieved from
31f77b
+        rpmdb on every call. In case of a failure (e.g. when the rpmdb changes
31f77b
+        between loading the data and calling this method), raises an instance
31f77b
+        of PackageNotFoundError.
31f77b
+        """
31f77b
+        if not self._from_system:
31f77b
+            return None
31f77b
+
31f77b
+        try:
31f77b
+            # RPMDBI_PACKAGES stands for the header of the package
31f77b
+            return next(self.base._ts.dbMatch(rpm.RPMDBI_PACKAGES, self.rpmdbid))
31f77b
+        except StopIteration:
31f77b
+            raise dnf.exceptions.PackageNotFoundError("Package not found when attempting to retrieve header", str(self))
31f77b
+
31f77b
     @property
31f77b
     def source_debug_name(self):
31f77b
         # :api
31f77b
diff --git a/tests/test_package.py b/tests/test_package.py
31f77b
index cd4872e631..514e5bf099 100644
31f77b
--- a/tests/test_package.py
31f77b
+++ b/tests/test_package.py
31f77b
@@ -68,6 +68,18 @@ def fn_getter():
31f77b
             with self.assertRaises(IOError):
31f77b
                 pkg._header
31f77b
 
31f77b
+    # rpm.hdr() is not easy to construct with custom data, we just return a string
31f77b
+    # instead, as we don't actually need an instance of rpm.hdr for the test
31f77b
+    @mock.patch("rpm.TransactionSet.dbMatch", lambda self, a, b: iter(["package_header_test_data"]))
31f77b
+    def test_get_header(self):
31f77b
+        pkg = self.sack.query().installed().filter(name="pepper")[0]
31f77b
+        header = pkg.get_header()
31f77b
+        self.assertEqual(header, "package_header_test_data")
31f77b
+
31f77b
+        pkg = self.sack.query().available().filter(name="pepper")[0]
31f77b
+        header = pkg.get_header()
31f77b
+        self.assertEqual(header, None)
31f77b
+
31f77b
     @mock.patch("dnf.package.Package.rpmdbid", long(3))
31f77b
     def test_idx(self):
31f77b
         """ pkg.idx is an int. """