Phil Dawson pushed to branch phil/848-plugin-deprecation-warnings at BuildStream / buildstream
Commits:
- 
ed422b3e
by Phil Dawson at 2019-02-19T15:49:26Z
7 changed files:
- buildstream/_project.py
- buildstream/plugin.py
- + tests/plugins/deprecationwarnings/deprecationwarnings.py
- + tests/plugins/deprecationwarnings/project/elements/deprecated.bst
- + tests/plugins/deprecationwarnings/project/plugins/elements/deprecated_plugin.py
- + tests/plugins/deprecationwarnings/project/plugins/elements/deprecated_plugin.yaml
- + tests/plugins/deprecationwarnings/project/project.conf
Changes:
| ... | ... | @@ -483,6 +483,10 @@ class Project(): | 
| 483 | 483 |  | 
| 484 | 484 |          self._validate_node(pre_config_node)
 | 
| 485 | 485 |  | 
| 486 | +        # Load plugin deprecation warning supression config
 | |
| 487 | +        self.supressed_deprecation_warnings = _yaml.node_get(
 | |
| 488 | +            pre_config_node, list, 'supress-deprecation-warnings', default_value=[])
 | |
| 489 | + | |
| 486 | 490 |          # FIXME:
 | 
| 487 | 491 |          #
 | 
| 488 | 492 |          #   Performing this check manually in the absense
 | 
| ... | ... | @@ -164,6 +164,25 @@ class Plugin(): | 
| 164 | 164 |         core format version :ref:`core format version <project_format_version>`.
 | 
| 165 | 165 |      """
 | 
| 166 | 166 |  | 
| 167 | +    BST_PLUGIN_DEPRECATED = False
 | |
| 168 | +    """True if this element plugin has been deprecated.
 | |
| 169 | + | |
| 170 | +    If this is set to true, BuildStream will emmit a deprecation
 | |
| 171 | +    warning when this plugin is loaded. This deprecation warning may
 | |
| 172 | +    be supressed on a plugin by plugin basis by setting
 | |
| 173 | +    ``supress-deprecation-warnings: true`` in the relevent section of
 | |
| 174 | +    the project's :ref:`plugin configuration overrides <project_overrides>`.
 | |
| 175 | + | |
| 176 | +    """
 | |
| 177 | + | |
| 178 | +    BST_PLUGIN_DEPRECATION_MESSAGE = ""
 | |
| 179 | +    """ The message printed when this element shows a deprecation warning.
 | |
| 180 | + | |
| 181 | +    This should be set if BST_PLUGIN_DEPRECATED is True and should direct the user
 | |
| 182 | +    to the deprecated plug-in's replacement.
 | |
| 183 | + | |
| 184 | +    """
 | |
| 185 | + | |
| 167 | 186 |      def __init__(self, name, context, project, provenance, type_tag):
 | 
| 168 | 187 |  | 
| 169 | 188 |          self.name = name
 | 
| ... | ... | @@ -188,6 +207,12 @@ class Plugin(): | 
| 188 | 207 |          self.__kind = modulename.split('.')[-1]
 | 
| 189 | 208 |          self.debug("Created: {}".format(self))
 | 
| 190 | 209 |  | 
| 210 | +        # If this plugin has been deprecated, emit a warning.
 | |
| 211 | +        if self.BST_PLUGIN_DEPRECATED and not self.__deprecation_warning_silcenced():
 | |
| 212 | +            detail = "Using deprecated plugin {}: {}".format(self.__kind,
 | |
| 213 | +                                                                self.BST_PLUGIN_DEPRECATION_MESSAGE)
 | |
| 214 | +            self.__message(MessageType.WARN, detail)
 | |
| 215 | + | |
| 191 | 216 |      def __del__(self):
 | 
| 192 | 217 |          # Dont send anything through the Message() pipeline at destruction time,
 | 
| 193 | 218 |          # any subsequent lookup of plugin by unique id would raise KeyError.
 | 
| ... | ... | @@ -767,6 +792,19 @@ class Plugin(): | 
| 767 | 792 |          else:
 | 
| 768 | 793 |              return self.name
 | 
| 769 | 794 |  | 
| 795 | +    def __deprecation_warning_silcenced(self):
 | |
| 796 | +        if not self.BST_PLUGIN_DEPRECATED:
 | |
| 797 | +            return False
 | |
| 798 | +        else:
 | |
| 799 | +            silenced_warnings = set()
 | |
| 800 | +            project= self.__project
 | |
| 801 | +            plugin_overrides = {**project.element_overrides, **project.source_overrides}
 | |
| 802 | + | |
| 803 | +            for key, value in self.node_items(plugin_overrides):
 | |
| 804 | +                if value.get('supress-deprecation-warnings', False):
 | |
| 805 | +                    silenced_warnings.add(key)
 | |
| 806 | + | |
| 807 | +            return self.get_kind() in silenced_warnings
 | |
| 770 | 808 |  | 
| 771 | 809 |  # Hold on to a lookup table by counter of all instantiated plugins.
 | 
| 772 | 810 |  # We use this to send the id back from child processes so we can lookup
 | 
| 1 | +import pytest
 | |
| 2 | +import tempfile
 | |
| 3 | +import os
 | |
| 4 | +from buildstream.plugintestutils import cli
 | |
| 5 | +from buildstream import _yaml
 | |
| 6 | +import buildstream.plugins.elements.manual
 | |
| 7 | + | |
| 8 | + | |
| 9 | +DATA_DIR = os.path.join(
 | |
| 10 | +    os.path.dirname(os.path.realpath(__file__)),
 | |
| 11 | +    "project"
 | |
| 12 | +)
 | |
| 13 | + | |
| 14 | +_DEPRECATION_MESSAGE = "Here is some detail."
 | |
| 15 | +_DEPRECATION_WARNING = "Using deprecated plugin deprecated_plugin: {}".format(_DEPRECATION_MESSAGE)
 | |
| 16 | + | |
| 17 | + | |
| 18 | +@pytest.mark.datafiles(DATA_DIR)
 | |
| 19 | +def test_deprecation_warning_present(cli, datafiles):
 | |
| 20 | +    project = os.path.join(datafiles.dirname, datafiles.basename)
 | |
| 21 | +    result = cli.run(project=project, args=['show', 'deprecated.bst'])
 | |
| 22 | +    result.assert_success()
 | |
| 23 | +    assert _DEPRECATION_WARNING in result.stderr
 | |
| 24 | + | |
| 25 | +@pytest.mark.datafiles(DATA_DIR)
 | |
| 26 | +def test_supress_deprecation_warning(cli, datafiles):
 | |
| 27 | +    project = os.path.join(datafiles.dirname, datafiles.basename)
 | |
| 28 | +    result = cli.run(project=project, args=['show', 'manual.bst'])
 | |
| 29 | + | |
| 30 | +    element_overrides = "elements:\n" \
 | |
| 31 | +                        "  deprecated_plugin:\n" \
 | |
| 32 | +                        "    supress-deprecation-warnings : True\n"
 | |
| 33 | + | |
| 34 | +    project_conf = os.path.join(project, 'project.conf')
 | |
| 35 | +    with open(project_conf, 'a') as f:
 | |
| 36 | +        f.write(element_overrides)
 | |
| 37 | + | |
| 38 | +    result = cli.run(project=project, args=['show', 'deprecated.bst'])
 | |
| 39 | +    result.assert_success()
 | |
| 40 | +    assert _DEPRECATION_WARNING not in result.stderr | 
| 1 | +kind: deprecated_plugin | |
| \ No newline at end of file | 
| 1 | +from buildstream import BuildElement, SandboxFlags
 | |
| 2 | + | |
| 3 | + | |
| 4 | +class DeprecatedPlugin(BuildElement):
 | |
| 5 | +    BST_PLUGIN_DEPRECATED = True
 | |
| 6 | +    BST_PLUGIN_DEPRECATION_MESSAGE = "Here is some detail."
 | |
| 7 | + | |
| 8 | + | |
| 9 | +# Plugin entry point
 | |
| 10 | +def setup():
 | |
| 11 | +    return DeprecatedPlugin | 
| 1 | +# Deprecated-plugin build element does not provide any default
 | |
| 2 | +# build commands
 | |
| 3 | +config:
 | |
| 4 | + | |
| 5 | +  # Commands for configuring the software
 | |
| 6 | +  #
 | |
| 7 | +  configure-commands: []
 | |
| 8 | + | |
| 9 | +  # Commands for building the software
 | |
| 10 | +  #
 | |
| 11 | +  build-commands: []
 | |
| 12 | + | |
| 13 | +  # Commands for installing the software into a
 | |
| 14 | +  # destination folder
 | |
| 15 | +  #
 | |
| 16 | +  install-commands: []
 | |
| 17 | + | |
| 18 | +  # Commands for stripping installed binaries
 | |
| 19 | +  #
 | |
| 20 | +  strip-commands:
 | |
| 21 | +  - |
 | |
| 22 | +    %{strip-binaries} | |
| \ No newline at end of file | 
| 1 | +# Unique project name
 | |
| 2 | +name: deprecation-warnings
 | |
| 3 | + | |
| 4 | +# Required BuildStream format version
 | |
| 5 | +format-version: 20
 | |
| 6 | + | |
| 7 | +# Subdirectory where elements are stored
 | |
| 8 | +element-path: elements
 | |
| 9 | + | |
| 10 | +plugins:
 | |
| 11 | + | |
| 12 | +- origin: local
 | |
| 13 | +  path: plugins/elements
 | |
| 14 | +  elements:
 | |
| 15 | +    deprecated_plugin: 0 | 
