@@ -51,6 +51,7 @@ class RebuildContext:
5151 loop_detector: Map of components to their blocking components
5252 missing_packages: Map of components to their missing package names
5353 unresolvable_components: Set of components whose dependencies cannot be resolved
54+ prerel_abi_blocked_components: Set of components blocked by unsatisfied prerel-abi dependencies
5455 """
5556 components : ReverseLookupDict
5657 components_done : ReverseLookupDict
@@ -63,6 +64,7 @@ class RebuildContext:
6364 loop_detector : dict = field (default_factory = dict )
6465 missing_packages : dict = field (default_factory = lambda : collections .defaultdict (set ))
6566 unresolvable_components : set = field (default_factory = set )
67+ prerel_abi_blocked_components : set = field (default_factory = set )
6668
6769
6870def _query_packages_by_deps (sack_getter , deps , excluded_components ):
@@ -291,9 +293,11 @@ def report_blocking_components(loop_detector):
291293 log (' • ' + ' → ' .join (loop ))
292294
293295
294- def get_component_status_info (component , missing_packages , components , unresolvable_components ):
296+ def get_component_status_info (component , missing_packages , components , unresolvable_components , prerel_abi_blocked_components = None ):
295297 """Generate status information for a component explaining why it's blocked."""
296- if component in unresolvable_components :
298+ if prerel_abi_blocked_components and component in prerel_abi_blocked_components :
299+ return " (unsatisfied prerel-abi dependency)"
300+ elif component in unresolvable_components :
297301 return " (can't resolve dependencies)"
298302 elif component in components :
299303 if component in missing_packages :
@@ -311,6 +315,67 @@ def get_component_status_info(component, missing_packages, components, unresolva
311315 return f" (build failed)"
312316
313317
318+ def _filter_components_with_unsatisfied_prerel_abi (components_done ):
319+ """
320+ Filter out components that have unsatisfied python(prerel-abi) dependencies.
321+
322+ Some packages require python(prerel-abi) = X.Y.Z~alphaN which should match
323+ the current_version defined in config.toml [prerel] section.
324+
325+ Args:
326+ components_done: ReverseLookupDict of components that have been built
327+
328+ Returns:
329+ Tuple of (filtered_components, blocked_components) where:
330+ - filtered_components: ReverseLookupDict with components that have matching prerel-abi removed
331+ - blocked_components: set of component names that were filtered (should not be rebuilt)
332+ """
333+ import re
334+
335+ # Get the expected prerel-abi version from config
336+ expected_version = CONFIG .get ('prerel' , {}).get ('current_version' )
337+ if not expected_version :
338+ log (' • Warning: No prerel.current_version found in config.toml, skipping prerel-abi filtering' )
339+ return components_done , set ()
340+
341+ filtered = ReverseLookupDict ()
342+ blocked_components = set ()
343+
344+ for component , packages in components_done .items ():
345+ component_has_unsatisfied_prerel = False
346+
347+ for pkg in packages :
348+ for req in pkg .requires :
349+ req_str = str (req )
350+ if 'python(prerel-abi)' in req_str :
351+ # Extract version from requirement string
352+ # Format: python(prerel-abi) = X.Y.Z~alphaN
353+ match = re .search (r'python\(prerel-abi\)\s*=\s*([^\s]+)' , req_str )
354+ if match :
355+ required_version = match .group (1 )
356+ if required_version != expected_version :
357+ log (f' • Filtering { component } : required { req_str } , expected python(prerel-abi) = { expected_version } ' )
358+ component_has_unsatisfied_prerel = True
359+ blocked_components .add (component )
360+ break
361+ else :
362+ log (f' • Warning: Could not parse prerel-abi requirement: { req_str } ' )
363+
364+ if component_has_unsatisfied_prerel :
365+ break
366+
367+ # Only include this component if it doesn't have unsatisfied prerel-abi deps
368+ if not component_has_unsatisfied_prerel :
369+ filtered [component ] = packages
370+
371+ filtered .default_factory = None
372+
373+ if blocked_components :
374+ log (f'• Filtered out { len (blocked_components )} components with unsatisfied prerel-abi dependencies.' )
375+
376+ return filtered , blocked_components
377+
378+
314379def initialize_component_data ():
315380 """
316381 Load and prepare all component data needed for rebuild analysis.
@@ -330,12 +395,16 @@ def initialize_component_data():
330395 excluded_components = tuple (CONFIG ['components' ]['excluded' ])
331396 )
332397
398+ # Filter out components with unsatisfied prerel-abi dependencies
399+ components_done , prerel_abi_blocked = _filter_components_with_unsatisfied_prerel_abi (components_done )
400+
333401 binary_rpms = components .all_values ()
334402
335403 return RebuildContext (
336404 components = components ,
337405 components_done = components_done ,
338- binary_rpms = binary_rpms
406+ binary_rpms = binary_rpms ,
407+ prerel_abi_blocked_components = prerel_abi_blocked
339408 )
340409
341410
@@ -480,12 +549,18 @@ def generate_reports(ctx):
480549 """
481550 log ('\n The 50 most commonly needed components are:' )
482551 for component , count in ctx .blocker_counter ['general' ].most_common (50 ):
483- status_info = get_component_status_info (component , ctx .missing_packages , ctx .components , ctx .unresolvable_components )
552+ status_info = get_component_status_info (
553+ component , ctx .missing_packages , ctx .components ,
554+ ctx .unresolvable_components , ctx .prerel_abi_blocked_components
555+ )
484556 log (f'{ count :>5} { component :<35} { status_info } ' )
485557
486558 log ('\n The 20 most commonly last-blocking components are:' )
487559 for component , count in ctx .blocker_counter ['single' ].most_common (20 ):
488- status_info = get_component_status_info (component , ctx .missing_packages , ctx .components , ctx .unresolvable_components )
560+ status_info = get_component_status_info (
561+ component , ctx .missing_packages , ctx .components ,
562+ ctx .unresolvable_components , ctx .prerel_abi_blocked_components
563+ )
489564 log (f'{ count :>5} { component :<35} { status_info } ' )
490565
491566 log ('\n The 20 most commonly last-blocking small combinations of components are:' )
0 commit comments