This is an automated email from the ASF dual-hosted git repository.

juergbi pushed a commit to branch jbilleter/junction-provenance
in repository https://gitbox.apache.org/repos/asf/buildstream.git

commit d07808b2f76234445616132ee798da8a9f45af3f
Author: Jürg Billeter <[email protected]>
AuthorDate: Fri May 1 11:39:51 2026 +0200

    Defer source provenance check until the project is fully loaded
    
    Junctions may be loaded before a project is fully loaded, which means
    that the source provenance attribute project configuration may not be
    available yet.
    
    This adds a callback mechanism to defer the source provenance attribute
    check if the project is not fully loaded when a junction element with a
    provenance node is loaded.
    
          File "src/buildstream/element.py", line 1075, in 
_new_from_load_element
            element.__load_sources(load_element)
            ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^
          File "src/buildstream/element.py", line 2642, in __load_sources
            
provenance_node.validate_keys(project.source_provenance_attributes.keys())
                                          
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        AttributeError: 'NoneType' object has no attribute 'keys'
    
    Fixes #2116.
---
 src/buildstream/_project.py | 19 ++++++++++++++++++-
 src/buildstream/element.py  | 22 +++++++++++++++-------
 2 files changed, 33 insertions(+), 8 deletions(-)

diff --git a/src/buildstream/_project.py b/src/buildstream/_project.py
index dd46442c2..252616220 100644
--- a/src/buildstream/_project.py
+++ b/src/buildstream/_project.py
@@ -15,7 +15,7 @@
 #        Tristan Van Berkom <[email protected]>
 #        Tiago Gomes <[email protected]>
 
-from typing import TYPE_CHECKING, Optional, Dict, Union, List, Sequence
+from typing import TYPE_CHECKING, Optional, Dict, Union, List, Sequence, 
Callable
 
 import os
 import urllib.parse
@@ -158,6 +158,8 @@ class Project:
         self._fully_loaded: bool = False
         self._project_includes: Optional[Includes] = None
 
+        self._fully_loaded_callbacks: List[Callable[[], None]] = []
+
         #
         # Initialization body
         #
@@ -692,6 +694,17 @@ class Project:
     def loaded_projects(self):
         yield from self.load_context.loaded_projects()
 
+    # register_fully_loaded_callback()
+    #
+    # Call the specified function once the project is fully loaded.
+    #
+    # Args:
+    #    callback (Callable[[], None]): A function to call once fully loaded
+    #
+    def register_fully_loaded_callback(self, callback: Callable[[], None]):
+        assert not self._fully_loaded
+        self._fully_loaded_callbacks.append(callback)
+
     ########################################################
     #                    Private Methods                   #
     ########################################################
@@ -1017,6 +1030,10 @@ class Project:
             "source-provenance-attributes", None
         ) or config.get_mapping("source-provenance-attributes")
 
+        for callback in self._fully_loaded_callbacks:
+            callback()
+        self._fully_loaded_callbacks = None
+
     # _load_pass():
     #
     # Loads parts of the project configuration that are different
diff --git a/src/buildstream/element.py b/src/buildstream/element.py
index 32666af46..891ee7152 100644
--- a/src/buildstream/element.py
+++ b/src/buildstream/element.py
@@ -2638,13 +2638,21 @@ class Element(Plugin):
                 provenance_node: MappingNode = 
source.get_mapping(Symbol.PROVENANCE, default=None)
                 if provenance_node:
                     del source[Symbol.PROVENANCE]
-                    try:
-                        
provenance_node.validate_keys(project.source_provenance_attributes.keys())
-                    except LoadError as E:
-                        raise LoadError(
-                            f"Specified source provenance attribute not 
defined in project config\n {E}",
-                            
LoadErrorReason.UNDEFINED_SOURCE_PROVENANCE_ATTRIBUTE,
-                        )
+
+                    def 
source_provenance_attribute_check(provenance_node=provenance_node):
+                        try:
+                            
provenance_node.validate_keys(project.source_provenance_attributes.keys())
+                        except LoadError as E:
+                            raise LoadError(
+                                f"Specified source provenance attribute not 
defined in project config\n {E}",
+                                
LoadErrorReason.UNDEFINED_SOURCE_PROVENANCE_ATTRIBUTE,
+                            )
+
+                    # Source provenance attributes are available only after 
the project is fully loaded
+                    if project.source_provenance_attributes is None:
+                        
project.register_fully_loaded_callback(source_provenance_attribute_check)
+                    else:
+                        source_provenance_attribute_check()
 
                     # make sure everything is a string
                     for key, value in provenance_node.items():

Reply via email to