commit:     d31f0fee089eb0883c7b48faabee4c47d80cbdf8
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Sun Dec 24 18:40:57 2023 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Sun Dec 24 18:57:49 2023 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=d31f0fee

bindbapi: Update state for package remove in aux_update

When removing a signed gpkg in aux_update, update internal
state including $PKGDIR/Packages (important especially for
FEATURES=pkgdir-index-trusted).

Bug: https://bugs.gentoo.org/920095
Fixes: a7bbb4fc4d38 ("Fix move_ent with signed binpkg")
Signed-off-by: Zac Medico <zmedico <AT> gentoo.org>

 lib/portage/dbapi/bintree.py                    | 61 +++++++++++++++++++++----
 lib/portage/tests/update/test_move_slot_ent.py  | 19 +++++---
 lib/portage/tests/update/test_update_dbentry.py | 13 ++++--
 3 files changed, 73 insertions(+), 20 deletions(-)

diff --git a/lib/portage/dbapi/bintree.py b/lib/portage/dbapi/bintree.py
index 9c9ac66334..b9f8d6795e 100644
--- a/lib/portage/dbapi/bintree.py
+++ b/lib/portage/dbapi/bintree.py
@@ -302,15 +302,7 @@ class bindbapi(fakedbapi):
                         "the file will be removed.",
                     )
                 )
-                try:
-                    os.remove(binpkg_path)
-                except OSError as err:
-                    writemsg(
-                        colorize(
-                            "WARN",
-                            f"Failed to remove moved signed package: 
{binpkg_path} {str(err)}",
-                        )
-                    )
+                self.bintree.remove(cpv)
                 return
             encoding_key = False
         else:
@@ -1789,6 +1781,57 @@ class binarytree:
 
         return cpv
 
+    def remove(self, cpv: portage.versions._pkg_str) -> None:
+        """
+        Remove a package instance and update internal state including
+        the package index. This will raise a KeyError if cpv is not
+        found in the internal state. It will display a warning message
+        if the package file was not found on disk, since it could have
+        been removed by another process before this method could
+        acquire a lock.
+
+        @param cpv: The cpv of the existing package to remove
+        @type cpv: portage.versions._pkg_str
+        @rtype: None
+        @return: None
+        @raise KeyError: If cpv does not exist in the internal state
+        """
+        if not self.populated:
+            self.populate()
+        os.makedirs(self.pkgdir, exist_ok=True)
+        pkgindex_lock = lockfile(self._pkgindex_file, wantnewlockfile=1)
+        try:
+            # Will raise KeyError if the package is not found.
+            instance_key = self.dbapi._instance_key(cpv)
+            pkg_path = self.getname(cpv)
+            self.dbapi.cpv_remove(cpv)
+            self._pkg_paths.pop(instance_key, None)
+            if self._remotepkgs is not None:
+                self._remotepkgs.pop(instance_key, None)
+            pkgindex = self._load_pkgindex()
+            if not self._pkgindex_version_supported(pkgindex):
+                pkgindex = self._new_pkgindex()
+
+            path = pkg_path[len(self.pkgdir) + 1 :]
+            for i in range(len(pkgindex.packages) - 1, -1, -1):
+                d = pkgindex.packages[i]
+                if cpv == d.get("CPV"):
+                    if path == d.get("PATH", ""):
+                        del pkgindex.packages[i]
+
+            self._pkgindex_write(pkgindex)
+            try:
+                os.remove(pkg_path)
+            except OSError as err:
+                writemsg(
+                    colorize(
+                        "WARN",
+                        f"Failed to remove package: {binpkg_path} {str(err)}",
+                    )
+                )
+        finally:
+            unlockfile(pkgindex_lock)
+
     def _read_metadata(self, filename, st, keys=None, binpkg_format=None):
         """
         Read metadata from a binary package. The returned metadata

diff --git a/lib/portage/tests/update/test_move_slot_ent.py 
b/lib/portage/tests/update/test_move_slot_ent.py
index caefdb4c9c..62b5c35446 100644
--- a/lib/portage/tests/update/test_move_slot_ent.py
+++ b/lib/portage/tests/update/test_move_slot_ent.py
@@ -1,4 +1,4 @@
-# Copyright 2012-2019 Gentoo Authors
+# Copyright 2012-2023 Gentoo Authors
 # Distributed under the terms of the GNU General Public License v2
 
 import sys
@@ -277,17 +277,24 @@ class MoveSlotEntTestCase(TestCase):
                     self.assertEqual(
                         "2/2.30", vardb.aux_get("dev-libs/A-1", ["SLOT"])[0]
                     )
-                    self.assertEqual(
-                        "0/2.30", bindb.aux_get("dev-libs/A-1", ["SLOT"])[0]
-                    )
+
+                    # Stale signed packages removed since a7bbb4fc4d38.
+                    self.assertRaises(KeyError, bindb.aux_get, "dev-libs/A-1", 
["SLOT"])
+                    # self.assertEqual(
+                    #    "0/2.30", bindb.aux_get("dev-libs/A-1", ["SLOT"])[0]
+                    # )
 
                     # 0 -> 1
                     self.assertEqual("1", vardb.aux_get("dev-libs/B-1", 
["SLOT"])[0])
-                    self.assertEqual("0", bindb.aux_get("dev-libs/B-1", 
["SLOT"])[0])
+                    # Stale signed packages removed since a7bbb4fc4d38.
+                    self.assertRaises(KeyError, bindb.aux_get, "dev-libs/B-1", 
["SLOT"])
+                    # self.assertEqual("0", bindb.aux_get("dev-libs/B-1", 
["SLOT"])[0])
 
                     # 0/1 -> 1 (equivalent to 1/1)
                     self.assertEqual("1", vardb.aux_get("dev-libs/C-1", 
["SLOT"])[0])
-                    self.assertEqual("0/1", bindb.aux_get("dev-libs/C-1", 
["SLOT"])[0])
+                    # Stale signed packages removed since a7bbb4fc4d38.
+                    self.assertRaises(KeyError, bindb.aux_get, "dev-libs/C-1", 
["SLOT"])
+                    # self.assertEqual("0/1", bindb.aux_get("dev-libs/C-1", 
["SLOT"])[0])
 
                     # dont_apply_updates
                     self.assertEqual(

diff --git a/lib/portage/tests/update/test_update_dbentry.py 
b/lib/portage/tests/update/test_update_dbentry.py
index 4e6554496d..a3c9a37e8c 100644
--- a/lib/portage/tests/update/test_update_dbentry.py
+++ b/lib/portage/tests/update/test_update_dbentry.py
@@ -1,4 +1,4 @@
-# Copyright 2012-2013 Gentoo Foundation
+# Copyright 2012-2023 Gentoo Authors
 # Distributed under the terms of the GNU General Public License v2
 
 import sys
@@ -432,10 +432,13 @@ class UpdateDbentryTestCase(TestCase):
                     rdepend = vardb.aux_get("dev-libs/A-1", ["RDEPEND"])[0]
                     self.assertTrue(old_pattern.search(rdepend) is None)
                     self.assertTrue("dev-libs/M-moved" in rdepend)
-                    rdepend = bindb.aux_get("dev-libs/A-1", ["RDEPEND"])[0]
-                    print(old_pattern.search(rdepend) is None)
-                    self.assertFalse(old_pattern.search(rdepend) is None)
-                    self.assertFalse("dev-libs/M-moved" in rdepend)
+                    # Stale signed packages removed since a7bbb4fc4d38.
+                    self.assertRaises(
+                        KeyError, bindb.aux_get, "dev-libs/A-1", ["RDEPEND"]
+                    )
+                    # rdepend = bindb.aux_get("dev-libs/A-1", ["RDEPEND"])[0]
+                    # self.assertFalse(old_pattern.search(rdepend) is None)
+                    # self.assertFalse("dev-libs/M-moved" in rdepend)
                     rdepend = vardb.aux_get("dev-libs/B-1", ["RDEPEND"])[0]
                     self.assertTrue(old_pattern.search(rdepend) is None)
                     self.assertTrue("dev-libs/M-moved" in rdepend)

Reply via email to