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

tvb pushed a commit to branch tristan/source-info-fatal-warning
in repository https://gitbox.apache.org/repos/asf/buildstream.git

commit 6273a2e7dca5550c39468f6fe3707d206d0304b7
Author: Tristan van Berkom <[email protected]>
AuthorDate: Mon Jun 2 17:37:03 2025 +0900

    source.py: Issue a configurable warning when collect_source_info() is 
unimplemented
    
    This allows the project to have a policy of only allowing usage of sources
    which implement Source.collect_source_info() (or 
SourceFetcher.get_source_info()).
---
 src/buildstream/__init__.py         |  1 -
 src/buildstream/_frontend/widget.py | 22 +++++++----------
 src/buildstream/source.py           | 49 ++++++++++++++-----------------------
 3 files changed, 28 insertions(+), 44 deletions(-)

diff --git a/src/buildstream/__init__.py b/src/buildstream/__init__.py
index 01d1d6535..54d509494 100644
--- a/src/buildstream/__init__.py
+++ b/src/buildstream/__init__.py
@@ -34,7 +34,6 @@ if "_BST_COMPLETION" not in os.environ:
     from .source import (
         Source,
         SourceError,
-        SourceImplError,
         SourceFetcher,
         SourceInfo,
         SourceInfoMedium,
diff --git a/src/buildstream/_frontend/widget.py 
b/src/buildstream/_frontend/widget.py
index 6c15f7263..09b824ff3 100644
--- a/src/buildstream/_frontend/widget.py
+++ b/src/buildstream/_frontend/widget.py
@@ -23,7 +23,6 @@ import click
 
 from .profile import Profile
 from ..types import _Scope
-from ..source import SourceImplError
 from .. import _yaml
 from .. import __version__ as bst_version
 from .. import FileType
@@ -445,18 +444,15 @@ class LogLine(Widget):
                 #
                 all_source_infos = []
                 for source in element.sources():
-                    try:
-                        source_infos = source.collect_source_info()
-                    except SourceImplError as e:
-                        source.warn(str(e))
-                        continue
-
-                    serialized_sources = []
-                    for s in source_infos:
-                        serialized = s.serialize()
-                        serialized_sources.append(serialized)
-
-                    all_source_infos += serialized_sources
+                    source_infos = source.collect_source_info()
+
+                    if source_infos is not None:
+                        serialized_sources = []
+                        for s in source_infos:
+                            serialized = s.serialize()
+                            serialized_sources.append(serialized)
+
+                        all_source_infos += serialized_sources
 
                 # Dump the SourceInfo provenance objects in yaml format
                 line = p.fmt_subst(line, "source-info", 
_yaml.roundtrip_dump_string(all_source_infos))
diff --git a/src/buildstream/source.py b/src/buildstream/source.py
index 21d060a86..5646cce7b 100644
--- a/src/buildstream/source.py
+++ b/src/buildstream/source.py
@@ -395,19 +395,6 @@ class SourceError(BstError):
         super().__init__(message, detail=detail, domain=ErrorDomain.SOURCE, 
reason=reason, temporary=temporary)
 
 
-class SourceImplError(BstError):
-    """This exception is expected to be raised from some unimplemented 
abstract methods.
-
-    There is no need to raise this exception, however some public abstract 
methods which
-    are intended to be called by plugins may advertize the raising of this 
exception
-    in the case of a source plugin which does not implement the said method, 
in which case
-    it must be handled by the calling plugin.
-    """
-
-    def __init__(self, message, reason=None):
-        super().__init__(message, domain=ErrorDomain.IMPL, reason=reason)
-
-
 @dataclass
 class AliasSubstitution:
     """AliasSubstitution()
@@ -669,7 +656,7 @@ class SourceFetcher:
         """
         raise ImplError("SourceFetcher '{}' does not implement 
fetch()".format(type(self)))
 
-    def get_source_info(self) -> SourceInfo:
+    def get_source_info(self) -> Optional[SourceInfo]:
         """Get the :class:`.SourceInfo` object describing this source
 
         This method should only be called whenever
@@ -679,14 +666,12 @@ class SourceFetcher:
         SourceInfo objects created by implementors should be created with
         :func:`Source.create_source_info() 
<buildstream.source.Source.create_source_info>`.
 
-        Returns: the :class:`.SourceInfo` objects describing this source
-
-        Raises:
-           :class:`.SourceImplError`: if this method is unimplemented
+        Returns: the :class:`.SourceInfo` object describing this source, or 
``None`` if the
+                 SourceFetcher does not implement this method.
 
         *Since: 2.5*
         """
-        raise SourceImplError("SourceFetcher '{}' does not implement 
get_source_info()".format(type(self)))
+        return None
 
     #############################################################
     #                       Public Methods                      #
@@ -1068,7 +1053,7 @@ class Source(Plugin):
         """
         raise ImplError("Source plugin '{}' does not implement 
is_cached()".format(self.get_kind()))
 
-    def collect_source_info(self) -> Iterable[SourceInfo]:
+    def collect_source_info(self) -> Optional[Iterable[SourceInfo]]:
         """Get the :class:`.SourceInfo` objects describing this source
 
         This method should only be called whenever
@@ -1078,11 +1063,8 @@ class Source(Plugin):
         SourceInfo objects created by implementors should be created with
         :func:`Source.create_source_info() 
<buildstream.source.Source.create_source_info>`.
 
-        Returns: the :class:`.SourceInfo` objects describing this source
-
-        Raises:
-           :class:`.SourceImplError`: if the source class does not implement 
this method and does not implement
-                                      :func:`SourceFether.get_source_info() 
<buildstream.source.SourceFetcher.get_source_info>`
+        Returns: the :class:`.SourceInfo` objects describing this source, or 
``None`` if the
+                 SourceFetcher does not implement this method.
 
         .. note::
 
@@ -1093,15 +1075,22 @@ class Source(Plugin):
         """
         source_info = []
         for fetcher in self.get_source_fetchers():
-            source_info.append(fetcher.get_source_info())
+            info = fetcher.get_source_info()
+            if info is not None:
+                source_info.append(info)
 
         # If there are source fetchers, they can either have returned
-        # SourceInfo objects, OR they may have raised SourceImplError, we need
-        # to raise ImplError here in the case there were no source fetchers.
+        # SourceInfo objects, or None.
+        #
+        # We need to issue the warning here and return None in the case that 
no source info
+        # was reported.
+        #
         if not source_info:
-            raise SourceImplError(
-                "Source plugin '{}' does not implement 
collect_source_info()".format(self.get_kind())
+            self.warn(
+                "{}: Source.collect_source_info() is not implemented in this 
plugin".format(self),
+                warning_token=CoreWarnings.UNAVAILABLE_SOURCE_INFO,
             )
+            return None
 
         return source_info
 

Reply via email to