Skip to content

Commit 66e4bb8

Browse files
committed
eclean: Add --changed-subslot option to delete binpkgs with stale subslot deps
When a binpkg has a := slot operator dependency resolved to a specific subslot (e.g., sys-libs/bar:0/1=), but no version of that dependency in the ebuild repo still has that subslot, the binpkg is stale and would need a rebuild. The new --changed-subslot option detects and removes such binpkgs. Signed-off-by: Matt Turner <mattst88@gentoo.org>
1 parent 5a2d0ae commit 66e4bb8

2 files changed

Lines changed: 109 additions & 13 deletions

File tree

pym/gentoolkit/eclean/cli.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,11 @@ def printUsage(_error=None, help=None, unresolved_invalids=None):
261261
+ " - delete packages for which ebuild dependencies have changed",
262262
file=out,
263263
)
264+
print(
265+
yellow(" --changed-subslot")
266+
+ " - delete packages with := deps on subslots no longer in tree",
267+
file=out,
268+
)
264269
print(
265270
yellow(" --no-clean-invalid")
266271
+ " - Skip cleaning invalid binpkgs",
@@ -418,6 +423,8 @@ def optionSwitch(option, opts, action=None):
418423
options["verbose"] = True
419424
elif o in ("--changed-deps"):
420425
options["changed-deps"] = True
426+
elif o in ("--changed-subslot"):
427+
options["changed-subslot"] = True
421428
elif o in ("-i", "--ignore-failure"):
422429
options["ignore-failure"] = True
423430
elif o in ("-u", "--unique-use"):
@@ -472,6 +479,7 @@ def optionSwitch(option, opts, action=None):
472479
getopt_options["long"]["packages"] = [
473480
"ignore-failure",
474481
"changed-deps",
482+
"changed-subslot",
475483
"unique-use",
476484
"no-clean-invalid",
477485
]
@@ -488,6 +496,7 @@ def optionSwitch(option, opts, action=None):
488496
options["size-limit"] = 0
489497
options["verbose"] = False
490498
options["changed-deps"] = False
499+
options["changed-subslot"] = False
491500
options["ignore-failure"] = False
492501
options["no-clean-invalid"] = False
493502
options["unique-use"] = False

pym/gentoolkit/eclean/search.py

Lines changed: 100 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,75 @@ def _deps_equal(deps_a, eapi_a, deps_b, eapi_b, libc_deps, uselist=None, cpv=Non
588588
return deps_a == deps_b
589589

590590

591+
def _check_subslot_deps(deps, eapi, port_dbapi, uselist=None, cpv=None, verbose=False):
592+
"""Check if any := dep has a subslot no longer available in the tree.
593+
594+
Returns True if a stale subslot dep is found (binpkg should be removed).
595+
"""
596+
try:
597+
dep_list = use_reduce(deps, uselist=uselist, eapi=eapi, token_class=Atom)
598+
except InvalidDependString:
599+
print(
600+
pp.warn(
601+
"Warning: Invalid binpkg DEPEND string found for: %s"
602+
" | tagging for removal" % cpv
603+
),
604+
file=sys.stderr,
605+
)
606+
return True
607+
608+
queue = list(dep_list)
609+
while queue:
610+
token = queue.pop()
611+
if isinstance(token, list):
612+
queue.extend(token)
613+
continue
614+
if not isinstance(token, Atom):
615+
continue
616+
if not token.slot_operator_built:
617+
continue
618+
matches = port_dbapi.cp_list(token.cp)
619+
if not matches:
620+
continue
621+
found = False
622+
available_subslots = set()
623+
for match_cpv in matches:
624+
try:
625+
slot_str = port_dbapi.aux_get(match_cpv, ["SLOT"])[0]
626+
except KeyError:
627+
continue
628+
slot_parts = slot_str.split("/")
629+
match_slot = slot_parts[0]
630+
match_subslot = slot_parts[1] if len(slot_parts) > 1 else slot_parts[0]
631+
if match_slot == token.slot:
632+
if match_subslot == token.sub_slot:
633+
found = True
634+
break
635+
available_subslots.add(match_subslot)
636+
if not found:
637+
if verbose:
638+
print(
639+
pp.warn(
640+
" %s: stale subslot dep on %s:%s/%s=,"
641+
" available subslot(s): %s"
642+
% (
643+
cpv,
644+
token.cp,
645+
token.slot,
646+
token.sub_slot,
647+
(
648+
", ".join(sorted(available_subslots))
649+
if available_subslots
650+
else "(none)"
651+
),
652+
)
653+
),
654+
file=sys.stderr,
655+
)
656+
return True
657+
return False
658+
659+
591660
def _find_debuginfo_tarball(cpv: portage.versions._pkg_str, cp: str):
592661
"""
593662
From a CPV, identify and check for a matching debuginfo tarball.
@@ -737,25 +806,43 @@ def mk_binpkg_key(cpv):
737806

738807
# Exclude if binpkg exists in the porttree and not --deep
739808
if not destructive and port_dbapi.cpv_exists(cpv):
740-
if not options["changed-deps"]:
809+
if not options["changed-deps"] and not options["changed-subslot"]:
741810
continue
742811

743812
dep_keys = ("RDEPEND", "PDEPEND")
744813
keys = ("EAPI", "USE") + dep_keys
745814
binpkg_metadata = dict(zip(keys, bin_dbapi.aux_get(cpv, keys)))
746-
ebuild_metadata = dict(zip(keys, port_dbapi.aux_get(cpv, keys)))
747-
748815
deps_binpkg = " ".join(binpkg_metadata[key] for key in dep_keys)
749-
deps_ebuild = " ".join(ebuild_metadata[key] for key in dep_keys)
750-
if _deps_equal(
751-
deps_binpkg,
752-
binpkg_metadata["EAPI"],
753-
deps_ebuild,
754-
ebuild_metadata["EAPI"],
755-
libc_deps,
756-
frozenset(binpkg_metadata["USE"].split()),
757-
cpv,
758-
):
816+
uselist = frozenset(binpkg_metadata["USE"].split())
817+
818+
should_remove = False
819+
820+
if options["changed-deps"]:
821+
ebuild_metadata = dict(zip(keys, port_dbapi.aux_get(cpv, keys)))
822+
deps_ebuild = " ".join(ebuild_metadata[key] for key in dep_keys)
823+
if not _deps_equal(
824+
deps_binpkg,
825+
binpkg_metadata["EAPI"],
826+
deps_ebuild,
827+
ebuild_metadata["EAPI"],
828+
libc_deps,
829+
uselist,
830+
cpv,
831+
):
832+
should_remove = True
833+
834+
if not should_remove and options["changed-subslot"]:
835+
if _check_subslot_deps(
836+
deps_binpkg,
837+
binpkg_metadata["EAPI"],
838+
port_dbapi,
839+
uselist,
840+
cpv,
841+
verbose=options["verbose"],
842+
):
843+
should_remove = True
844+
845+
if not should_remove:
759846
continue
760847

761848
if destructive and var_dbapi.cpv_exists(cpv):

0 commit comments

Comments
 (0)