@@ -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+
591660def _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