@@ -66,6 +66,7 @@ class RebuildContext:
6666 missing_packages : dict = field (default_factory = lambda : collections .defaultdict (set ))
6767 unresolvable_components : set = field (default_factory = set )
6868 prerel_abi_blocked_components : set = field (default_factory = set )
69+ component_availability : dict = field (default_factory = dict )
6970
7071
7172def _query_packages_by_deps (sack_getter , deps , excluded_components ):
@@ -489,28 +490,40 @@ def check_bcond_build(component, bcond_config, number_of_resolved, ctx):
489490def check_bcond_builds (component , number_of_resolved , ctx ):
490491 """
491492 Check all bcond builds for a component that isn't ready for regular build.
492-
493+
493494 Args:
494495 component: Name of the component to check
495496 number_of_resolved: Number of packages in regular build (for comparison)
496497 ctx: RebuildContext with shared data and state
497-
498+
498499 Prints any bcond build identifiers that are ready to rebuild.
500+
501+ Returns:
502+ tuple: (ready_bcond_id, all_bcond_ids) where:
503+ - ready_bcond_id: str if a bcond build is ready, None otherwise
504+ - all_bcond_ids: list of all bcond identifiers for this component
499505 """
500506 from bconds import bcond_cache_identifier
501-
507+
502508 if component not in CONFIG ['bconds' ]:
503- return
504-
509+ return None , []
510+
511+ all_bcond_ids = []
512+ ready_bcond_id = None
513+
505514 for bcond_config in CONFIG ['bconds' ][component ]:
506515 bcond_config ['id' ] = bcond_cache_identifier (component , bcond_config )
516+ all_bcond_ids .append (bcond_config ['id' ])
507517 log (f'• { component } not ready and { bcond_config ["id" ]} bcond found, will check that one' )
508-
518+
509519 ready_to_rebuild = check_bcond_build (component , bcond_config , number_of_resolved , ctx )
510-
511- if ready_to_rebuild :
520+
521+ if ready_to_rebuild and ready_bcond_id is None :
512522 if should_print_component (component , ctx .components_done ):
513523 print (bcond_config ['id' ])
524+ ready_bcond_id = bcond_config ['id' ]
525+
526+ return ready_bcond_id , all_bcond_ids
514527
515528
516529def should_print_component (component , components_done ):
@@ -526,20 +539,35 @@ def should_print_component(component, components_done):
526539def process_component (component , ctx ):
527540 """
528541 Process a single component: check regular build and bcond builds if needed.
529-
542+ Stores availability data in ctx.component_availability.
543+
530544 Args:
531545 component: Name of the component to process
532546 ctx: RebuildContext with shared data and state
533-
547+
534548 Prints the component or bcond identifier if ready to rebuild.
535549 """
536550 ready_to_rebuild , number_of_resolved = check_regular_build (component , ctx )
537-
551+ availability = {
552+ 'can_build_regular' : ready_to_rebuild ,
553+ 'can_build_bcond' : None ,
554+ 'bcond_ids' : []
555+ }
556+
538557 if ready_to_rebuild :
539558 if should_print_component (component , ctx .components_done ):
540559 print (component )
541560 else :
542- check_bcond_builds (component , number_of_resolved , ctx )
561+ ready_bcond_id , all_bcond_ids = check_bcond_builds (component , number_of_resolved , ctx )
562+ availability ['bcond_ids' ] = all_bcond_ids
563+
564+ if ready_bcond_id :
565+ availability ['can_build_bcond' ] = True
566+ elif all_bcond_ids :
567+ # Bconds exist but none are ready
568+ availability ['can_build_bcond' ] = False
569+
570+ ctx .component_availability [component ] = availability
543571
544572
545573def assemble_component_info (component , count , ctx ):
@@ -597,7 +625,6 @@ def generate_reports(ctx):
597625 log ('\n The 20 most commonly last-blocking small combinations of components are:' )
598626 for components_tuple , count in ctx .blocker_counter ['combinations' ].most_common (20 ):
599627 log (f'{ count :>5} { ", " .join (components_tuple )} ' )
600-
601628 report_data ['most_commonly_last_blocking_combinations' ].append ({
602629 'components' : list (components_tuple ),
603630 'count' : count
@@ -612,6 +639,38 @@ def generate_reports(ctx):
612639 log ('\n Report saved to commonly-needed-report.json' )
613640
614641
642+ def generate_component_availability_report (ctx ):
643+ """
644+ Generate and save full component availability report.
645+ Creates component-availability-report.json with per-component data.
646+
647+ Args:
648+ ctx: RebuildContext with component availability data
649+ """
650+
651+ report_data = {}
652+ for component in ctx .components :
653+ availability = ctx .component_availability .get (component , {})
654+ bcond_ids = availability .get ('bcond_ids' , [])
655+
656+ report_data [component ] = {
657+ 'was_already_built' : component in ctx .components_done ,
658+ 'is_resolvable' : component not in ctx .unresolvable_components ,
659+ 'prerel_abi_blocked' : component in ctx .prerel_abi_blocked_components ,
660+ 'can_build_regular' : availability .get ('can_build_regular' , False ),
661+ 'can_build_bcond' : availability .get ('can_build_bcond' ),
662+ 'blocked_by' : sorted (ctx .loop_detector .get (component , [])),
663+ 'blocks_count' : ctx .blocker_counter ['general' ].get (component , 0 )
664+ }
665+
666+ if bcond_ids :
667+ report_data [component ]['bcond_ids' ] = bcond_ids
668+
669+ with open ('component-availability-report.json' , 'w' ) as f :
670+ json .dump (report_data , f , indent = 2 , sort_keys = True )
671+ log ('Full component availability report saved to component-availability-report.json' )
672+
673+
615674def main ():
616675 """
617676 Main entry point for rebuild analysis.
@@ -640,8 +699,9 @@ def main():
640699
641700 for component in components_to_process :
642701 process_component (component , ctx )
643-
702+
644703 generate_reports (ctx )
704+ generate_component_availability_report (ctx )
645705
646706
647707if __name__ == '__main__' :
0 commit comments