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
