Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

python: provide batch iteration / filters #32

Open
Jannik2099 opened this issue Jul 20, 2024 · 0 comments
Open

python: provide batch iteration / filters #32

Jannik2099 opened this issue Jul 20, 2024 · 0 comments

Comments

@Jannik2099
Copy link
Owner

Turns out iterating over ~ 30k packages with 5 depend exprs each is really slow as pybind has to bind each iterator object, and throw a C++ exception for each iteration end.

We need some kind of API akin to "find ebuilds where dependency expr contains ..."

A quick "revdep at home":

C++:

#include "pms-utils/atom/atom.hpp"
#include "pms-utils/depend/depend.hpp"
#include "pms-utils/repo/repo.hpp"

#include <boost/variant/static_visitor.hpp>
#include <format>
#include <iostream>

bool contains_expr(const pms_utils::depend::DependExpr &dependExpr,
                   const pms_utils::atom::PackageExpr &packageExpr) {
    for (const auto &expr : dependExpr) {
        class visitor : public boost::static_visitor<bool> {
        public:
            const pms_utils::atom::PackageExpr &packageExpr;
            visitor(const pms_utils::atom::PackageExpr &packageExpr) : packageExpr{packageExpr} {}
            bool operator()(const pms_utils::atom::PackageExpr &expr) const {
                return expr.category == packageExpr.category && expr.name == packageExpr.name;
            }
            bool operator()(const pms_utils::depend::DependExpr &expr) const {
                return contains_expr(expr, packageExpr);
            }
        };
        if (boost::apply_visitor(visitor(packageExpr), expr)) {
            return true;
        }
    }
    return false;
}

int main() {
    pms_utils::repo::Repository repo{"/var/db/repos/gentoo"};

    for (const auto &category : repo) {
        for (const auto &package : category) {
            for (const auto &ebuild : package) {
                bool found = false;
                for (const auto &depends :
                     {ebuild.metadata().BDEPEND, ebuild.metadata().DEPEND, ebuild.metadata().IDEPEND,
                      ebuild.metadata().PDEPEND, ebuild.metadata().RDEPEND}) {
                    if (contains_expr(depends, pms_utils::atom::PackageExpr{.category = {"net-dns"},
                                                                            .name = {"avahi"}})) {
                        found = true;
                    }
                }
                if (found) {
                    std::cout << std::format("found in ebuild {}\n", std::string{ebuild.name});
                }
            }
        }
    }
}

./revdep 0.68s user 0.40s system 99% cpu 1.081 total

image

Python:

import pms_utils
from pathlib import Path

repo = pms_utils.repo.Repository(Path("/var/db/repos/gentoo"))
profile = pms_utils.profile.Profile(Path("/etc/portage/make.profile"))


def contains_expr(
    depend_expr: pms_utils.depend.DependExpr, package_expr: pms_utils.atom.Atom
) -> bool:
    for expr in depend_expr:
        if (
            type(expr) == pms_utils.atom.Atom
            and expr.category == package_expr.category
            and expr.name == package_expr.name
        ):
            return True
        if type(expr) == pms_utils.depend.DependExpr:
            if contains_expr(expr, package_expr):
                return True
    return False


for category in repo:
    for package in category:
        for ebuild in package:
            found = False
            for depends in [
                ebuild.metadata.BDEPEND,
                ebuild.metadata.IDEPEND,
                ebuild.metadata.RDEPEND,
                ebuild.metadata.DEPEND,
                ebuild.metadata.PDEPEND,
            ]:
                if contains_expr(depends, pms_utils.atom.Atom("net-dns/avahi")):
                    found = True
            if found:
                print(f"found in ebuild {ebuild.name}")

python revdep.py 4.35s user 0.48s system 99% cpu 4.858 total

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant