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
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])
Attachment:
dependency-merges.unstable.txt.gz
Description: application/gzip