diff options
30 files changed, 376 insertions, 193 deletions
@@ -8,6 +8,14 @@ CLI o `bst shell --build` will now automatically fetch missing sources. +Format +------ + + o BREAKING CHANGE: Now deprecation warnings are suppressed using the `allow-deprecated` + configuration with the plugin origins in project.conf, instead of on the + source/element overrides section (See issue #1291) + + ================== buildstream 1.93.3 ================== diff --git a/doc/source/format_project.rst b/doc/source/format_project.rst index 65ca6c14d..211fc4dd0 100644 --- a/doc/source/format_project.rst +++ b/doc/source/format_project.rst @@ -404,7 +404,7 @@ plugin. # We want to use the `mysource` source plugin located in our # project's `plugins/sources` subdirectory. sources: - mysource: 0 + - mysource Pip plugins @@ -425,11 +425,60 @@ system. # package-name: potato - # We again must specify a minimal format version for the - # external plugin, it is allowed to be `0`. + # We again must specify specifically which plugins we + # want loaded from this origin. # elements: - starch: 0 + - starch + + +.. _project_plugins_deprecation: + +Suppressing deprecation warnings +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Plugins can be deprecated over time, and using deprecated plugins will +trigger a warning when loading elements and sources which use +deprecated plugin kinds. + +These deprecation warnings can be suppressed for the entire plugin +origin or on a per plugin kind basis. + +To suppress all deprecation warnings from the origin, set the +``allow-deprecated`` flag for the origin as follows: + +.. code:: yaml + + plugins: + + - origin: local + path: plugins/sources + + # Suppress deprecation warnings for any plugins loaded here + allow-deprecated: True + + sources: + - mysource + + +In order to suppress deprecation warnings for a single element or +source kind within an origin, you will have to use a dictionary +to declare the specific plugin kind and set the ``allow-deprecated`` flag +on that dictionary as follows: + +.. code:: yaml + + plugins: + + - origin: pip + package-name: potato + + # Here we use a dictionary to declare the "starch" + # element kind, and specify that it is allowed to + # be deprecated. + # + elements: + - kind: starch + allow-deprecated: True .. _project_options: diff --git a/src/buildstream/_loader/metasource.py b/src/buildstream/_loader/metasource.py index 5466d3aa5..ddaa538f5 100644 --- a/src/buildstream/_loader/metasource.py +++ b/src/buildstream/_loader/metasource.py @@ -40,3 +40,4 @@ class MetaSource: self.config = config self.directory = directory self.first_pass = False + self.provenance = config.get_provenance() diff --git a/src/buildstream/_pluginfactory/elementfactory.py b/src/buildstream/_pluginfactory/elementfactory.py index 8879a4173..da6e8ac56 100644 --- a/src/buildstream/_pluginfactory/elementfactory.py +++ b/src/buildstream/_pluginfactory/elementfactory.py @@ -53,6 +53,6 @@ class ElementFactory(PluginFactory): # LoadError (if the element itself took issue with the config) # def create(self, context, project, meta): - element_type, default_config = self.lookup(meta.kind) + element_type, default_config = self.lookup(context.messenger, meta.kind, meta.provenance) element = element_type(context, project, meta, default_config) return element diff --git a/src/buildstream/_pluginfactory/pluginfactory.py b/src/buildstream/_pluginfactory/pluginfactory.py index 27321c62f..2de110ed4 100644 --- a/src/buildstream/_pluginfactory/pluginfactory.py +++ b/src/buildstream/_pluginfactory/pluginfactory.py @@ -19,10 +19,15 @@ import os import inspect +from typing import Tuple, Type from .. import utils +from ..plugin import Plugin +from ..node import ProvenanceInformation from ..utils import UtilError from .._exceptions import PluginError +from .._messenger import Messenger +from .._message import Message, MessageType from .pluginorigin import PluginOrigin, PluginOriginType @@ -61,6 +66,7 @@ class PluginFactory: self._base_type = base_type # The base class plugins derive from self._types = {} # Plugin type lookup table by kind self._origins = {} # PluginOrigin lookup table by kind + self._allow_deprecated = {} # Lookup table to check if a plugin is allowed to be deprecated # The PluginSource object self._plugin_base = plugin_base @@ -115,14 +121,42 @@ class PluginFactory: # Fetches a type loaded from a plugin in this plugin context # # Args: + # messenger (Messenger): The messenger # kind (str): The kind of Plugin to create + # provenance (ProvenanceInformation): The provenance from where + # the plugin was referenced # - # Returns: the type associated with the given kind + # Returns: + # (type): The type associated with the given kind + # (str): A path to the YAML file holding the plugin's defaults, or None # # Raises: PluginError # - def lookup(self, kind): - return self._ensure_plugin(kind) + def lookup(self, messenger: Messenger, kind: str, provenance: ProvenanceInformation) -> Tuple[Type[Plugin], str]: + plugin_type, defaults = self._ensure_plugin(kind, provenance) + + # We can be called with None for the messenger here in the + # case that we've been pickled through the scheduler (see jobpickler.py), + # + # In this case we know that we've already initialized and do not need + # to warn about deprecated plugins a second time. + if messenger is None: + return plugin_type, defaults + + # After looking up the type, issue a warning if it's deprecated + # + # We do this here because we want to issue one warning for each time the + # plugin is used. + # + if plugin_type.BST_PLUGIN_DEPRECATED and not self._allow_deprecated[kind]: + message = Message( + MessageType.WARN, + "{}: Using deprecated plugin '{}'".format(provenance, kind), + detail=plugin_type.BST_PLUGIN_DEPRECATION_MESSAGE, + ) + messenger.message(message) + + return plugin_type, defaults # register_plugin_origin(): # @@ -131,8 +165,9 @@ class PluginFactory: # Args: # kind (str): The kind identifier of the Plugin # origin (PluginOrigin): The PluginOrigin providing the plugin + # allow_deprecated (bool): Whether this plugin kind is allowed to be used in a deprecated state # - def register_plugin_origin(self, kind: str, origin: PluginOrigin): + def register_plugin_origin(self, kind: str, origin: PluginOrigin, allow_deprecated: bool): if kind in self._origins: raise PluginError( "More than one {} plugin registered as kind '{}'".format(self._base_type.__name__, kind), @@ -140,6 +175,7 @@ class PluginFactory: ) self._origins[kind] = origin + self._allow_deprecated[kind] = allow_deprecated # all_loaded_plugins(): # @@ -197,7 +233,7 @@ class PluginFactory: return source, defaults - def _ensure_plugin(self, kind): + def _ensure_plugin(self, kind: str, provenance: ProvenanceInformation) -> Tuple[Type[Plugin], str]: if kind not in self._types: source = None @@ -215,7 +251,10 @@ class PluginFactory: else: # Try getting it from the core plugins if kind not in self._site_source.list_plugins(): - raise PluginError("No {} type registered for kind '{}'".format(self._base_type.__name__, kind)) + raise PluginError( + "{}: No {} type registered for kind '{}'".format(provenance, self._base_type.__name__, kind), + reason="plugin-not-found", + ) source = self._site_source diff --git a/src/buildstream/_pluginfactory/pluginorigin.py b/src/buildstream/_pluginfactory/pluginorigin.py index 50852711b..14d7a76bf 100644 --- a/src/buildstream/_pluginfactory/pluginorigin.py +++ b/src/buildstream/_pluginfactory/pluginorigin.py @@ -18,6 +18,9 @@ import os from ..types import FastEnum +from ..node import ScalarNode, MappingNode +from .._exceptions import LoadError +from ..exceptions import LoadErrorReason # PluginOriginType: @@ -29,6 +32,17 @@ class PluginOriginType(FastEnum): PIP = "pip" +# PluginConfiguration: +# +# An object representing the configuration of a single +# plugin in the origin. +# +class PluginConfiguration: + def __init__(self, kind, allow_deprecated): + self.kind = kind + self.allow_deprecated = allow_deprecated + + # PluginOrigin # # Base class holding common properties of all origins. @@ -36,18 +50,19 @@ class PluginOriginType(FastEnum): class PluginOrigin: # Common fields valid for all plugin origins - _COMMON_CONFIG_KEYS = ["origin", "sources", "elements"] + _COMMON_CONFIG_KEYS = ["origin", "sources", "elements", "allow-deprecated"] def __init__(self, origin_type): # Public - self.origin_type = origin_type - self.elements = [] - self.sources = [] + self.origin_type = origin_type # The PluginOriginType + self.elements = {} # A dictionary of PluginConfiguration + self.sources = {} # A dictionary of PluginConfiguration objects # Private self._project = None self._kinds = {} + self._allow_deprecated = False # new_from_node() # @@ -73,8 +88,14 @@ class PluginOrigin: origin._project = project origin._load(origin_node) - origin.elements = origin_node.get_str_list("elements", []) - origin.sources = origin_node.get_str_list("sources", []) + # Parse commonly defined aspects of PluginOrigins + origin._allow_deprecated = origin_node.get_bool("allow-deprecated", False) + + element_sequence = origin_node.get_sequence("elements", []) + origin._load_plugin_configurations(element_sequence, origin.elements) + + source_sequence = origin_node.get_sequence("sources", []) + origin._load_plugin_configurations(source_sequence, origin.sources) return origin @@ -89,6 +110,38 @@ class PluginOrigin: def _load(self, origin_node): pass + # _load_plugin_configurations() + # + # Helper function to load the list of source or element + # PluginConfigurations + # + # Args: + # sequence_node (SequenceNode): The list of configurations + # dictionary (dict): The location to store the results + # + def _load_plugin_configurations(self, sequence_node, dictionary): + + for node in sequence_node: + + # Parse as a simple string + if type(node) is ScalarNode: # pylint: disable=unidiomatic-typecheck + kind = node.as_str() + conf = PluginConfiguration(kind, self._allow_deprecated) + + # Parse as a dictionary + elif type(node) is MappingNode: # pylint: disable=unidiomatic-typecheck + node.validate_keys(["kind", "allow-deprecated"]) + kind = node.get_str("kind") + allow_deprecated = node.get_bool("allow-deprecated", self._allow_deprecated) + conf = PluginConfiguration(kind, allow_deprecated) + else: + p = node.get_provenance() + raise LoadError( + "{}: Plugin is not specified as a string or a dictionary".format(p), LoadErrorReason.INVALID_DATA + ) + + dictionary[kind] = conf + # PluginOriginLocal # diff --git a/src/buildstream/_pluginfactory/sourcefactory.py b/src/buildstream/_pluginfactory/sourcefactory.py index 9f6a09784..5277577d4 100644 --- a/src/buildstream/_pluginfactory/sourcefactory.py +++ b/src/buildstream/_pluginfactory/sourcefactory.py @@ -54,6 +54,6 @@ class SourceFactory(PluginFactory): # LoadError (if the source itself took issue with the config) # def create(self, context, project, meta): - source_type, _ = self.lookup(meta.kind) + source_type, _ = self.lookup(context.messenger, meta.kind, meta.provenance) source = source_type(context, project, meta) return source diff --git a/src/buildstream/_project.py b/src/buildstream/_project.py index 40524d7ad..45f3b4d34 100644 --- a/src/buildstream/_project.py +++ b/src/buildstream/_project.py @@ -951,10 +951,10 @@ class Project: origins = config.get_sequence("plugins", default=[]) for origin_node in origins: origin = PluginOrigin.new_from_node(self, origin_node) - for kind in origin.elements: - output.element_factory.register_plugin_origin(kind, origin) - for kind in origin.sources: - output.source_factory.register_plugin_origin(kind, origin) + for kind, conf in origin.elements.items(): + output.element_factory.register_plugin_origin(kind, origin, conf.allow_deprecated) + for kind, conf in origin.sources.items(): + output.source_factory.register_plugin_origin(kind, origin, conf.allow_deprecated) # _warning_is_fatal(): # diff --git a/src/buildstream/_scheduler/jobs/jobpickler.py b/src/buildstream/_scheduler/jobs/jobpickler.py index 1d47f67db..066e518c8 100644 --- a/src/buildstream/_scheduler/jobs/jobpickler.py +++ b/src/buildstream/_scheduler/jobs/jobpickler.py @@ -192,7 +192,7 @@ def _reduce_plugin_with_factory_dict(plugin, plugin_class_to_factory): def _new_plugin_from_reduction_args(factory, meta_kind): - cls, _ = factory.lookup(meta_kind) + cls, _ = factory.lookup(None, meta_kind, None) plugin = cls.__new__(cls) # Note that we rely on the `__project` member of the Plugin to keep diff --git a/src/buildstream/plugin.py b/src/buildstream/plugin.py index 935db6523..ff0604811 100644 --- a/src/buildstream/plugin.py +++ b/src/buildstream/plugin.py @@ -177,20 +177,18 @@ class Plugin: BST_PLUGIN_DEPRECATED = False """True if this element plugin has been deprecated. - If this is set to true, BuildStream will emmit a deprecation - warning when this plugin is loaded. This deprecation warning may - be suppressed on a plugin by plugin basis by setting - ``suppress-deprecation-warnings: true`` in the relevent section of - the project's :ref:`plugin configuration overrides <project_overrides>`. + If this is set to true, BuildStream will emit a deprecation warning + in any place where this plugin is used. + The deprecation warnings can be suppressed when defining the + :ref:`plugin origins in your project configuration <project_plugins_deprecation>` """ - BST_PLUGIN_DEPRECATION_MESSAGE = "" - """ The message printed when this element shows a deprecation warning. - - This should be set if BST_PLUGIN_DEPRECATED is True and should direct the user - to the deprecated plug-in's replacement. + BST_PLUGIN_DEPRECATION_MESSAGE = None + """An additional message to report when a plugin is deprecated + This can be used to refer the user to a suitable replacement or + alternative approach when the plugin is deprecated. """ # Unique id generator for Plugins @@ -272,11 +270,6 @@ class Plugin: self.__kind = modulename.split(".")[-1] self.debug("Created: {}".format(self)) - # If this plugin has been deprecated, emit a warning. - if self.BST_PLUGIN_DEPRECATED and not self.__deprecation_warning_silenced(): - detail = "Using deprecated plugin {}: {}".format(self.__kind, self.BST_PLUGIN_DEPRECATION_MESSAGE) - self.__message(MessageType.WARN, detail) - def __del__(self): # Dont send anything through the Message() pipeline at destruction time, # any subsequent lookup of plugin by unique id would raise KeyError. @@ -762,22 +755,6 @@ class Plugin: output.flush() self.status("Running host command", detail=command) - def __deprecation_warning_silenced(self): - if not self.BST_PLUGIN_DEPRECATED: - return False - else: - silenced_warnings = set() - project = self.__project - - for key, value in project.element_overrides.items(): - if value.get_bool("suppress-deprecation-warnings", default=False): - silenced_warnings.add(key) - for key, value in project.source_overrides.items(): - if value.get_bool("suppress-deprecation-warnings", default=False): - silenced_warnings.add(key) - - return self.get_kind() in silenced_warnings - def __get_full_name(self): project = self.__project # Set the name, depending on element or source plugin type diff --git a/tests/format/project.py b/tests/format/project.py index c4b2a480a..d3de67222 100644 --- a/tests/format/project.py +++ b/tests/format/project.py @@ -153,20 +153,6 @@ def test_local_plugin_not_directory(cli, datafiles): @pytest.mark.datafiles(DATA_DIR) -def test_plugin_load_allowed(cli, datafiles): - project = os.path.join(datafiles.dirname, datafiles.basename, "plugin-allowed") - result = cli.run(project=project, silent=True, args=["show", "element.bst"]) - result.assert_success() - - -@pytest.mark.datafiles(DATA_DIR) -def test_plugin_load_forbidden(cli, datafiles): - project = os.path.join(datafiles.dirname, datafiles.basename, "plugin-forbidden") - result = cli.run(project=project, silent=True, args=["show", "element.bst"]) - result.assert_main_error(ErrorDomain.PLUGIN, None) - - -@pytest.mark.datafiles(DATA_DIR) @pytest.mark.parametrize("ref_storage", [("inline"), ("project.refs")]) def test_plugin_no_load_ref(cli, datafiles, ref_storage): project = os.path.join(datafiles.dirname, datafiles.basename, "plugin-no-load-ref") diff --git a/tests/format/project/plugin-allowed/__init__.py b/tests/format/project/plugin-allowed/__init__.py deleted file mode 100644 index e69de29bb..000000000 --- a/tests/format/project/plugin-allowed/__init__.py +++ /dev/null diff --git a/tests/format/project/plugin-allowed/element.bst b/tests/format/project/plugin-allowed/element.bst deleted file mode 100644 index 675938bec..000000000 --- a/tests/format/project/plugin-allowed/element.bst +++ /dev/null @@ -1 +0,0 @@ -kind: foo diff --git a/tests/format/project/plugin-allowed/plugins/__init__.py b/tests/format/project/plugin-allowed/plugins/__init__.py deleted file mode 100644 index e69de29bb..000000000 --- a/tests/format/project/plugin-allowed/plugins/__init__.py +++ /dev/null diff --git a/tests/format/project/plugin-allowed/plugins/foo.py b/tests/format/project/plugin-allowed/plugins/foo.py deleted file mode 100644 index 76d9bfd3c..000000000 --- a/tests/format/project/plugin-allowed/plugins/foo.py +++ /dev/null @@ -1,19 +0,0 @@ -from buildstream import Element - - -class FooElement(Element): - - BST_MIN_VERSION = "2.0" - - def configure(self, config): - pass - - def preflight(self): - pass - - def get_unique_key(self): - return "foo" - - -def setup(): - return FooElement diff --git a/tests/format/project/plugin-allowed/project.conf b/tests/format/project/plugin-allowed/project.conf deleted file mode 100644 index 97107edf6..000000000 --- a/tests/format/project/plugin-allowed/project.conf +++ /dev/null @@ -1,8 +0,0 @@ -name: test -min-version: 2.0 - -plugins: -- origin: local - path: plugins - elements: - - foo diff --git a/tests/format/project/plugin-forbidden/__init__.py b/tests/format/project/plugin-forbidden/__init__.py deleted file mode 100644 index e69de29bb..000000000 --- a/tests/format/project/plugin-forbidden/__init__.py +++ /dev/null diff --git a/tests/format/project/plugin-forbidden/element.bst b/tests/format/project/plugin-forbidden/element.bst deleted file mode 100644 index c8d51318c..000000000 --- a/tests/format/project/plugin-forbidden/element.bst +++ /dev/null @@ -1 +0,0 @@ -kind: bar diff --git a/tests/format/project/plugin-forbidden/forbidden-plugins/__init__.py b/tests/format/project/plugin-forbidden/forbidden-plugins/__init__.py deleted file mode 100644 index e69de29bb..000000000 --- a/tests/format/project/plugin-forbidden/forbidden-plugins/__init__.py +++ /dev/null diff --git a/tests/format/project/plugin-forbidden/project.conf b/tests/format/project/plugin-forbidden/project.conf deleted file mode 100644 index 0211b2061..000000000 --- a/tests/format/project/plugin-forbidden/project.conf +++ /dev/null @@ -1,3 +0,0 @@ -name: test -min-version: 2.0 - diff --git a/tests/plugins/deprecationwarnings.py b/tests/plugins/deprecationwarnings.py deleted file mode 100644 index a4da3ea72..000000000 --- a/tests/plugins/deprecationwarnings.py +++ /dev/null @@ -1,38 +0,0 @@ -# Pylint doesn't play well with fixtures and dependency injection from pytest -# pylint: disable=redefined-outer-name - -import os - -import pytest - -from buildstream.testing import cli # pylint: disable=unused-import - - -DATA_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "deprecationwarnings") - -_DEPRECATION_MESSAGE = "Here is some detail." -_DEPRECATION_WARNING = "Using deprecated plugin deprecated_plugin: {}".format(_DEPRECATION_MESSAGE) - - -@pytest.mark.datafiles(DATA_DIR) -def test_deprecation_warning_present(cli, datafiles): - project = str(datafiles) - result = cli.run(project=project, args=["show", "deprecated.bst"]) - result.assert_success() - assert _DEPRECATION_WARNING in result.stderr - - -@pytest.mark.datafiles(DATA_DIR) -def test_suppress_deprecation_warning(cli, datafiles): - project = str(datafiles) - cli.run(project=project, args=["show", "manual.bst"]) - - element_overrides = "elements:\n" " deprecated_plugin:\n" " suppress-deprecation-warnings : True\n" - - project_conf = os.path.join(project, "project.conf") - with open(project_conf, "a") as f: - f.write(element_overrides) - - result = cli.run(project=project, args=["show", "deprecated.bst"]) - result.assert_success() - assert _DEPRECATION_WARNING not in result.stderr diff --git a/tests/plugins/deprecationwarnings/elements/deprecated.bst b/tests/plugins/deprecationwarnings/elements/deprecated.bst deleted file mode 100644 index e80bd91cd..000000000 --- a/tests/plugins/deprecationwarnings/elements/deprecated.bst +++ /dev/null @@ -1 +0,0 @@ -kind: deprecated_plugin
\ No newline at end of file diff --git a/tests/plugins/deprecationwarnings/plugins/elements/deprecated_plugin.py b/tests/plugins/deprecationwarnings/plugins/elements/deprecated_plugin.py deleted file mode 100644 index 244009764..000000000 --- a/tests/plugins/deprecationwarnings/plugins/elements/deprecated_plugin.py +++ /dev/null @@ -1,12 +0,0 @@ -from buildstream import BuildElement - - -class DeprecatedPlugin(BuildElement): - BST_MIN_VERSION = "2.0" - BST_PLUGIN_DEPRECATED = True - BST_PLUGIN_DEPRECATION_MESSAGE = "Here is some detail." - - -# Plugin entry point -def setup(): - return DeprecatedPlugin diff --git a/tests/plugins/deprecationwarnings/plugins/elements/deprecated_plugin.yaml b/tests/plugins/deprecationwarnings/plugins/elements/deprecated_plugin.yaml deleted file mode 100644 index 1c07cd8b2..000000000 --- a/tests/plugins/deprecationwarnings/plugins/elements/deprecated_plugin.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# Deprecated-plugin build element does not provide any default -# build commands -config: - - # Commands for configuring the software - # - configure-commands: [] - - # Commands for building the software - # - build-commands: [] - - # Commands for installing the software into a - # destination folder - # - install-commands: [] - - # Commands for stripping installed binaries - # - strip-commands: - - | - %{strip-binaries}
\ No newline at end of file diff --git a/tests/plugins/deprecationwarnings/project.conf b/tests/plugins/deprecationwarnings/project.conf deleted file mode 100644 index 9e03afe0a..000000000 --- a/tests/plugins/deprecationwarnings/project.conf +++ /dev/null @@ -1,15 +0,0 @@ -# Unique project name -name: deprecation-warnings - -# Required BuildStream version -min-version: 2.0 - -# Subdirectory where elements are stored -element-path: elements - -plugins: - -- origin: local - path: plugins/elements - elements: - - deprecated_plugin diff --git a/tests/plugins/loading.py b/tests/plugins/loading.py index a368e9952..152f4080b 100644 --- a/tests/plugins/loading.py +++ b/tests/plugins/loading.py @@ -200,3 +200,106 @@ def test_incompatible_minor_version(cli, datafiles, plugin_type): result = cli.run(project=project, args=["show", "element.bst"]) result.assert_main_error(ErrorDomain.PLUGIN, "incompatible-minor-version") + + +@pytest.mark.datafiles(DATA_DIR) +@pytest.mark.parametrize("plugin_type", [("elements"), ("sources")]) +def test_plugin_not_found(cli, datafiles, plugin_type): + project = str(datafiles) + + setup_element(project, plugin_type, "notfound") + + result = cli.run(project=project, args=["show", "element.bst"]) + result.assert_main_error(ErrorDomain.PLUGIN, "plugin-not-found") + + +@pytest.mark.datafiles(DATA_DIR) +@pytest.mark.parametrize("plugin_type", [("elements"), ("sources")]) +def test_plugin_found(cli, datafiles, plugin_type): + project = str(datafiles) + + update_project( + project, + { + "plugins": [ + {"origin": "local", "path": os.path.join("plugins", plugin_type, "found"), plugin_type: ["found"],} + ] + }, + ) + setup_element(project, plugin_type, "found") + + result = cli.run(project=project, args=["show", "element.bst"]) + result.assert_success() + + +@pytest.mark.datafiles(DATA_DIR) +@pytest.mark.parametrize("plugin_type", [("elements"), ("sources")]) +def test_deprecation_warnings(cli, datafiles, plugin_type): + project = str(datafiles) + + update_project( + project, + { + "plugins": [ + { + "origin": "local", + "path": os.path.join("plugins", plugin_type, "deprecated"), + plugin_type: ["deprecated"], + } + ] + }, + ) + setup_element(project, plugin_type, "deprecated") + + result = cli.run(project=project, args=["show", "element.bst"]) + result.assert_success() + assert "Here is some detail." in result.stderr + + +@pytest.mark.datafiles(DATA_DIR) +@pytest.mark.parametrize("plugin_type", [("elements"), ("sources")]) +def test_deprecation_warning_suppressed_by_origin(cli, datafiles, plugin_type): + project = str(datafiles) + + update_project( + project, + { + "plugins": [ + { + "origin": "local", + "path": os.path.join("plugins", plugin_type, "deprecated"), + "allow-deprecated": True, + plugin_type: ["deprecated"], + } + ] + }, + ) + setup_element(project, plugin_type, "deprecated") + + result = cli.run(project=project, args=["show", "element.bst"]) + result.assert_success() + assert "Here is some detail." not in result.stderr + + +@pytest.mark.datafiles(DATA_DIR) +@pytest.mark.parametrize("plugin_type", [("elements"), ("sources")]) +def test_deprecation_warning_suppressed_specifically(cli, datafiles, plugin_type): + project = str(datafiles) + + update_project( + project, + { + "plugins": [ + { + "origin": "local", + "path": os.path.join("plugins", plugin_type, "deprecated"), + plugin_type: [{"kind": "deprecated", "allow-deprecated": True}], + } + ] + }, + ) + setup_element(project, plugin_type, "deprecated") + + result = cli.run(project=project, args=["show", "element.bst"]) + result.assert_success() + assert "Here is some detail." not in result.stderr diff --git a/tests/plugins/loading/plugins/elements/deprecated/deprecated.py b/tests/plugins/loading/plugins/elements/deprecated/deprecated.py new file mode 100644 index 000000000..7184710bc --- /dev/null +++ b/tests/plugins/loading/plugins/elements/deprecated/deprecated.py @@ -0,0 +1,21 @@ +from buildstream import Element + + +class Deprecated(Element): + BST_MIN_VERSION = "2.0" + BST_PLUGIN_DEPRECATED = True + BST_PLUGIN_DEPRECATION_MESSAGE = "Here is some detail." + + def configure(self, node): + pass + + def preflight(self): + pass + + def get_unique_key(self): + return {} + + +# Plugin entry point +def setup(): + return Deprecated diff --git a/tests/format/project/plugin-forbidden/forbidden-plugins/forbidden-plugin.py b/tests/plugins/loading/plugins/elements/found/found.py index 76d9bfd3c..34a7e4398 100644 --- a/tests/format/project/plugin-forbidden/forbidden-plugins/forbidden-plugin.py +++ b/tests/plugins/loading/plugins/elements/found/found.py @@ -1,19 +1,19 @@ from buildstream import Element -class FooElement(Element): - +class Found(Element): BST_MIN_VERSION = "2.0" - def configure(self, config): + def configure(self, node): pass def preflight(self): pass def get_unique_key(self): - return "foo" + return {} +# Plugin entry point def setup(): - return FooElement + return Found diff --git a/tests/plugins/loading/plugins/sources/deprecated/deprecated.py b/tests/plugins/loading/plugins/sources/deprecated/deprecated.py new file mode 100644 index 000000000..6203eb2fa --- /dev/null +++ b/tests/plugins/loading/plugins/sources/deprecated/deprecated.py @@ -0,0 +1,34 @@ +from buildstream import Source + + +class Deprecated(Source): + BST_MIN_VERSION = "2.0" + BST_PLUGIN_DEPRECATED = True + BST_PLUGIN_DEPRECATION_MESSAGE = "Here is some detail." + + def configure(self, node): + pass + + def preflight(self): + pass + + def get_unique_key(self): + return {} + + def load_ref(self, node): + pass + + def get_ref(self): + return {} + + def set_ref(self, ref, node): + pass + + def is_cached(self): + return False + + +# Plugin entry point +def setup(): + + return Deprecated diff --git a/tests/plugins/loading/plugins/sources/found/found.py b/tests/plugins/loading/plugins/sources/found/found.py new file mode 100644 index 000000000..4ab40f005 --- /dev/null +++ b/tests/plugins/loading/plugins/sources/found/found.py @@ -0,0 +1,32 @@ +from buildstream import Source + + +class Found(Source): + BST_MIN_VERSION = "2.0" + + def configure(self, node): + pass + + def preflight(self): + pass + + def get_unique_key(self): + return {} + + def load_ref(self, node): + pass + + def get_ref(self): + return {} + + def set_ref(self, ref, node): + pass + + def is_cached(self): + return False + + +# Plugin entry point +def setup(): + + return Found |