commit:     6c1e1f997b0a99954f0eadd7898a368076fb0ea5
Author:     Brian Harring <ferringb <AT> gmail <DOT> com>
AuthorDate: Tue Jan 16 04:50:04 2024 +0000
Commit:     Arthur Zamarin <arthurzam <AT> gentoo <DOT> org>
CommitDate: Tue Jan 23 08:52:08 2024 +0000
URL:        
https://gitweb.gentoo.org/proj/pkgcore/pkgcore.git/commit/?id=6c1e1f99

fix filtered.tree.{categories,packages,versions} .

The implementation wasn't properly aliasing _get_* to
the underlying raw_repo, and it should've been filtering
packages and versions according to the filter.  This adds that.

This isn't a huge issue, but it breaks API guarantees
for code tring to efficienctly access this sort of info
for a repository stack.

Signed-off-by: Brian Harring <ferringb <AT> gmail.com>

 src/pkgcore/repository/filtered.py | 22 +++++++++++++++++++++-
 tests/repository/test_filtered.py  | 22 ++++++++++++++++++++++
 2 files changed, 43 insertions(+), 1 deletion(-)

diff --git a/src/pkgcore/repository/filtered.py 
b/src/pkgcore/repository/filtered.py
index 2e700d7e4..81f5b7e7f 100644
--- a/src/pkgcore/repository/filtered.py
+++ b/src/pkgcore/repository/filtered.py
@@ -5,12 +5,15 @@ filtering repository
 __all__ = ("tree",)
 
 from itertools import filterfalse
+import typing
 
-from snakeoil.klass import DirProxy, GetAttrProxy
+from snakeoil.klass import DirProxy, GetAttrProxy, alias_method
 
 from ..operations.repo import operations_proxy
 from ..restrictions import restriction
 from . import errors, prototype
+from pkgcore.ebuild.restricts import CategoryDep
+from pkgcore.ebuild.atom import atom
 
 
 class tree(prototype.tree):
@@ -33,6 +36,7 @@ class tree(prototype.tree):
             self._filterfunc = filter
         else:
             self._filterfunc = filterfalse
+        super().__init__()
 
     def itermatch(self, restrict, **kwds):
         # note that this lets the repo do the initial filtering.
@@ -54,6 +58,22 @@ class tree(prototype.tree):
             count += 1
         return count
 
+    # note: for the _get_* methods they use itermatch which would typically
+    # be a cycle; this class's itermatch is fully reliant on the raw repo
+    # thus no cycle.
+
+    # TODO: add support for .{category,package,version}.force_regen via custom 
class.  No code relies upon this,
+    # but that functionality missing means the implementation has a known 
potential for developing a stale cache.
+    _get_categories = alias_method("raw_repo.categories.__iter__")
+
+    def _get_packages(self, category: str) -> typing.Iterable[str]:
+        for package in self.raw_repo.packages[category]:
+            if any(self.itermatch(atom(f"{category}/{package}"))):
+                yield package
+
+    def _get_versions(self, catpkg: tuple[str, str]) -> typing.Iterable[str]:
+        return (pkg.fullver for pkg in 
self.itermatch(atom(f"{catpkg[0]}/{catpkg[1]}")))
+
     __getattr__ = GetAttrProxy("raw_repo")
     __dir__ = DirProxy("raw_repo")
 

diff --git a/tests/repository/test_filtered.py 
b/tests/repository/test_filtered.py
index 312e2528b..7a04c21b9 100644
--- a/tests/repository/test_filtered.py
+++ b/tests/repository/test_filtered.py
@@ -1,4 +1,5 @@
 from pkgcore.ebuild.atom import atom
+from pkgcore.ebuild.restricts import CategoryDep
 from pkgcore.ebuild.cpv import VersionedCPV
 from pkgcore.repository import filtered
 from pkgcore.repository.util import SimpleTree
@@ -57,3 +58,24 @@ class TestVisibility:
             )
         )
         assert sorted(vrepo) == sorted(repo.itermatch(atom("dev-util/bsdiff")))
+
+    def test_categories_api(self):
+        # filter to just dev-util/diffball; this confirms that empty 
categories are filter,
+        # and that filtering of a package (leaving one in a category still) 
doesn't filter the category.
+        _, vrepo = self.setup_repos(
+            packages.OrRestriction(CategoryDep("dev-lib"), 
atom("dev-util/bsdiff"))
+        )
+        assert sorted(vrepo.categories) == sorted(
+            [
+                "dev-lib",
+                "dev-util",
+            ]
+        ), "category filtering must not filter dev-lib even if there are no 
packages left post filtering"
+
+    def test_packages_api(self):
+        _, vrepo = self.setup_repos(atom("dev-util/diffball"))
+        assert sorted(vrepo.packages["dev-util"]) == ["bsdiff"]
+
+    def test_versions_api(self):
+        _, vrepo = self.setup_repos(atom("=dev-util/diffball-1.0"))
+        assert sorted(vrepo.versions[("dev-util", "diffball")]) == ["0.7"]

Reply via email to