Dependency merging in APT

Julian Andres Klode <[email protected]>
Newsgroups gmane.linux.debian.apt.devel,gmane.linux.debian.devel.general
Message-ID <[email protected]>
Hi all,

yesterday I enabled a new feature in APT's new solver, where
it takes overlapping dependencies from a package and merges
them to their intersection.

In particular this addresses the problem with version ranges and
versioned provides such as:

gnupg Depends: gpg (>= 2.4.7-19) overlaps Depends: gpg (<< 2.4.7-19.1~)
 -  solutions: ['gpg=2.4.7-19']
 -  eliminated: [] ['gpg-from-sq=0.13.1-3']

Where gpg-from-sq would be considered a valid solution for the
<< depends as it provides 2.2.something, but not the greater
depends and apt may decide to upgrade gnupg by installing gpg-from-sq.


Some bits just eliminate funny redundancies such as:

dpkg-dev Recommends: sqv | sqopv | rsopv | sopv | gosop | pgpainless-cli | gpgv-sq | gpgv overlaps Recommends: sq | sqop | rsop | gosop | pgpainless-cli | gpg-sq | gnupg
 -  solutions: ['sqop=0.37.1-1+b1', 'rsop=0.6.4-1', 'gosop=1.1.0-3', 'gosop=1.1.0-3', 'pgpainless-cli=1.6.9-1']
 -  eliminated: ['sqv=1.3.0-2', 'sqopv=0.37.1-1+b1', 'rsopv=0.6.4-1', 'sopv-gpgv=0.1.4-1', 'sqopv=0.37.1-1+b1', 'rsopv=0.6.4-1', 'gpgv-sq=0.13.1-3+b1', 'gpgv=2.4.7-19', 'gpgv-from-sq=0.13.1-3'] ['sq=1.3.1-2+b1', 'gpg-sq=0.13.1-3+b1', 'gnupg=2.4.7-19']

Or modules merged into greater packages such as perl:

razor Depends: libtest-simple-perl overlaps Depends: libmime-base64-perl
 -  solutions: ['perl=5.40.1-3']
 -  eliminated: ['libtest-simple-perl=1.302210-1'] []

A complete list of mergeable dependencies is attached.

Please note that we also merge Depends into Recommends, such as

ddclient Recommends: libdigest-sha-perl overlaps Depends: perl:any
 -  solutions: ['perl=5.40.1-3']
 -  eliminated: ['libdigest-sha-perl=6.04-1+b3'] []

That is, the Recommends is restricted to the bits that intersect
with the overlapping dependency, here the

    Recommends: libdigest-sha-perl

effectively becomes

    Recommends: perl

There may be some unexpected issues that need some refinement.
-- 
debian developer - deb.li/jak | jak-linux.org - free software dev
ubuntu core developer                              i speak de, en
find-dependency-merges.py (text/x-python, 2.1 KB)
import apt_pkg

apt_pkg.init()


def render(group: list[apt_pkg.Dependency]) -> str:
    def render1(dep: apt_pkg.Dependency) -> str:
        if dep.comp_type_deb:
            return f"{dep.target_pkg.name} ({dep.comp_type_deb} {dep.target_ver})"
        return dep.target_pkg.name

    return f"{group[0].dep_type_untranslated}: " + " | ".join(
        render1(dep) for dep in group
    )


def check_overlap(v: apt_pkg.Version) -> None:
    deps: list[tuple[list[apt_pkg.Version], list[apt_pkg.Dependency]]] = []
    for kind_name, kind in v.depends_list.items():
        if kind_name in ["Conflicts", "Breaks", "Replaces", "Suggests", "Enhances"]:
            continue
        for group in kind:
            targets: list[apt_pkg.Version] = []
            for dep in group:
                targets.extend(dep.all_targets())
            deps.append((targets, group))

    for i in range(len(deps)):
        for j in range(i):
            lhs = set(v.id for v in deps[i][0])
            rhs = set(v.id for v in deps[j][0])
            overlap = lhs & rhs
            if overlap and lhs != rhs:
                print(
                    v.parent_pkg.name,
                    render(deps[i][1]),
                    "overlaps",
                    render(deps[j][1]),
                )
                print(
                    " -  solutions:",
                    [
                        v.parent_pkg.name + "=" + v.ver_str
                        for v in deps[i][0]
                        if v.id in overlap
                    ],
                )
                print(
                    " -  eliminated:",
                    [
                        v.parent_pkg.name + "=" + v.ver_str
                        for v in deps[i][0]
                        if v.id not in overlap
                    ],
                    [
                        v.parent_pkg.name + "=" + v.ver_str
                        for v in deps[j][0]
                        if v.id not in overlap
                    ],
                )
                print()


cache = apt_pkg.Cache(None)

for pkg in cache.packages:
    if pkg.version_list:
        check_overlap(pkg.version_list[0])
dependency-merges.unstable.txt.gz (application/gzip, 33.4 KB) - not displayed
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.