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 06497df23038dd9727071e45c2e794af6d5e666e 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 | 17 +++++++++++++++++ src/buildstream/element.py | 22 +++++++++++++++------- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/buildstream/_project.py b/src/buildstream/_project.py index dd46442c2..7a7e2b847 100644 --- a/src/buildstream/_project.py +++ b/src/buildstream/_project.py @@ -158,6 +158,8 @@ class Project: self._fully_loaded: bool = False self._project_includes: Optional[Includes] = None + self._fully_loaded_callbacks = [] + # # Initialization body # @@ -692,6 +694,17 @@ class Project: def loaded_projects(self): yield from self.load_context.loaded_projects() + # add_fully_loaded_callback() + # + # Call the specified function once the project is fully loaded. + # + # Args: + # callback (callable): A function to call once fully loaded + # + def add_fully_loaded_callback(self, callback): + 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..d6cbed234 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.add_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():
