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