diff options
author | Josh Smith <joshsmith@codethink.co.uk> | 2018-08-03 11:32:29 +0100 |
---|---|---|
committer | Josh Smith <qinusty@gmail.com> | 2018-08-15 12:15:58 +0100 |
commit | f3d58233793cf0249cbac51f72d5c459eb256d44 (patch) | |
tree | 1ac54367e79ac7ac3e53f5e66484d05e916b7237 /buildstream | |
parent | 9f675c640d47e844712cb8917018fda163d5e070 (diff) | |
download | buildstream-f3d58233793cf0249cbac51f72d5c459eb256d44.tar.gz |
_project.py: Add fatal-warnings configuration item
This allows for users to configure fatal-warnings to be either a list of
warnings.
This commit deprecates the use of fail-on-overlap within project.conf,
this will now use the fatal-warnings configuration item.
element.py: Cache key calculation now takes into account all of the
fatal-warnings
tests: This modifys the tests/frontend/overlaps.py tests to support the
new fatal-warnings configuration. Backwards compatibility is also
tested for `fail-on-overlap`
_versions.py: BST_FORMAT_VERSION bumped to 15 for fatal-warnings
BST_CORE_ARTIFACT_VERSION bumpted to 5 for fatal-warnings
Fixes: #526
Diffstat (limited to 'buildstream')
-rw-r--r-- | buildstream/_project.py | 42 | ||||
-rw-r--r-- | buildstream/_versions.py | 4 | ||||
-rw-r--r-- | buildstream/data/projectconfig.yaml | 4 | ||||
-rw-r--r-- | buildstream/element.py | 26 | ||||
-rw-r--r-- | buildstream/plugin.py | 64 |
5 files changed, 108 insertions, 32 deletions
diff --git a/buildstream/_project.py b/buildstream/_project.py index 951662e2b..702fd81f4 100644 --- a/buildstream/_project.py +++ b/buildstream/_project.py @@ -31,6 +31,7 @@ from ._options import OptionPool from ._artifactcache import ArtifactCache from ._elementfactory import ElementFactory from ._sourcefactory import SourceFactory +from .plugin import CoreWarnings from ._projectrefs import ProjectRefs, ProjectRefStorage from ._versions import BST_FORMAT_VERSION from ._loader import Loader @@ -105,7 +106,7 @@ class Project(): self.first_pass_config = ProjectConfig() self.junction = junction # The junction Element object, if this is a subproject - self.fail_on_overlap = False # Whether overlaps are treated as errors + self.ref_storage = None # ProjectRefStorage setting self.base_environment = {} # The base set of environment variables self.base_env_nocache = None # The base nocache mask (list) for the environment @@ -120,6 +121,8 @@ class Project(): self._cli_options = cli_options self._cache_key = None + self._fatal_warnings = [] # A list of warnings which should trigger an error + self._shell_command = [] # The default interactive shell command self._shell_environment = {} # Statically set environment vars self._shell_host_files = [] # A list of HostMount objects @@ -456,7 +459,7 @@ class Project(): 'split-rules', 'elements', 'plugins', 'aliases', 'name', 'artifacts', 'options', - 'fail-on-overlap', 'shell', + 'fail-on-overlap', 'shell', 'fatal-warnings', 'ref-storage', 'sandbox', 'mirrors' ]) @@ -478,8 +481,25 @@ class Project(): # Load project split rules self._splits = _yaml.node_get(config, Mapping, 'split-rules') - # Fail on overlap - self.fail_on_overlap = _yaml.node_get(config, bool, 'fail-on-overlap') + # Fatal warnings + self._fatal_warnings = _yaml.node_get(config, list, 'fatal-warnings', default_value=[]) + + # Support backwards compatibility for fail-on-overlap + fail_on_overlap = _yaml.node_get(config, bool, 'fail-on-overlap', default_value=None) + + if (CoreWarnings.OVERLAPS not in self._fatal_warnings) and fail_on_overlap: + self._fatal_warnings.append(CoreWarnings.OVERLAPS) + + # Deprecation check + if fail_on_overlap is not None: + self._context.message( + Message( + None, + MessageType.WARN, + "Use of fail-on-overlap within project.conf " + + "is deprecated. Consider using fatal-warnings instead." + ) + ) # Load project.refs if it exists, this may be ignored. if self.ref_storage == ProjectRefStorage.PROJECT_REFS: @@ -712,3 +732,17 @@ class Project(): # paths are passed in relative to the project, but must be absolute origin_dict['path'] = os.path.join(self.directory, path) destination.append(origin_dict) + + # _warning_is_fatal(): + # + # Returns true if the warning in question should be considered fatal based on + # the project configuration. + # + # Args: + # warning_str (str): The warning configuration string to check against + # + # Returns: + # (bool): True if the warning should be considered fatal and cause an error. + # + def _warning_is_fatal(self, warning_str): + return warning_str in self._fatal_warnings diff --git a/buildstream/_versions.py b/buildstream/_versions.py index 3f32847ae..a722e11a5 100644 --- a/buildstream/_versions.py +++ b/buildstream/_versions.py @@ -23,7 +23,7 @@ # This version is bumped whenever enhancements are made # to the `project.conf` format or the core element format. # -BST_FORMAT_VERSION = 14 +BST_FORMAT_VERSION = 15 # The base BuildStream artifact version @@ -33,4 +33,4 @@ BST_FORMAT_VERSION = 14 # or if buildstream was changed in a way which can cause # the same cache key to produce something that is no longer # the same. -BST_CORE_ARTIFACT_VERSION = 4 +BST_CORE_ARTIFACT_VERSION = 5 diff --git a/buildstream/data/projectconfig.yaml b/buildstream/data/projectconfig.yaml index b4ad2dcb9..686040ee0 100644 --- a/buildstream/data/projectconfig.yaml +++ b/buildstream/data/projectconfig.yaml @@ -13,10 +13,6 @@ element-path: . # Store source references in element files ref-storage: inline -# Overlaps are just warnings -fail-on-overlap: False - - # Variable Configuration # variables: diff --git a/buildstream/element.py b/buildstream/element.py index a099e934b..bb205c777 100644 --- a/buildstream/element.py +++ b/buildstream/element.py @@ -94,6 +94,7 @@ from . import _cachekey from . import _signals from . import _site from ._platform import Platform +from .plugin import CoreWarnings from .sandbox._config import SandboxConfig from .storage.directory import Directory @@ -746,32 +747,23 @@ class Element(Plugin): ignored[dep.name] = result.ignored if overlaps: - overlap_error = overlap_warning = False - error_detail = warning_detail = "Staged files overwrite existing files in staging area:\n" + overlap_warning = False + warning_detail = "Staged files overwrite existing files in staging area:\n" for f, elements in overlaps.items(): - overlap_error_elements = [] overlap_warning_elements = [] # The bottom item overlaps nothing overlapping_elements = elements[1:] for elm in overlapping_elements: element = self.search(scope, elm) - element_project = element._get_project() if not element.__file_is_whitelisted(f): - if element_project.fail_on_overlap: - overlap_error_elements.append(elm) - overlap_error = True - else: - overlap_warning_elements.append(elm) - overlap_warning = True + overlap_warning_elements.append(elm) + overlap_warning = True warning_detail += _overlap_error_detail(f, overlap_warning_elements, elements) - error_detail += _overlap_error_detail(f, overlap_error_elements, elements) if overlap_warning: - self.warn("Non-whitelisted overlaps detected", detail=warning_detail) - if overlap_error: - raise ElementError("Non-whitelisted overlaps detected and fail-on-overlaps is set", - detail=error_detail, reason="overlap-error") + self.warn("Non-whitelisted overlaps detected", detail=warning_detail, + warning_token=CoreWarnings.OVERLAPS) if ignored: detail = "Not staging files which would replace non-empty directories:\n" @@ -2054,9 +2046,7 @@ class Element(Plugin): 'cache': type(self.__artifacts).__name__ } - # fail-on-overlap setting cannot affect elements without dependencies - if project.fail_on_overlap and dependencies: - self.__cache_key_dict['fail-on-overlap'] = True + self.__cache_key_dict['fatal-warnings'] = sorted(project._fatal_warnings) cache_key_dict = self.__cache_key_dict.copy() cache_key_dict['dependencies'] = dependencies diff --git a/buildstream/plugin.py b/buildstream/plugin.py index 836b60834..64b38ff99 100644 --- a/buildstream/plugin.py +++ b/buildstream/plugin.py @@ -166,7 +166,6 @@ class Plugin(): # Infer the kind identifier modulename = type(self).__module__ self.__kind = modulename.split('.')[-1] - self.debug("Created: {}".format(self)) def __del__(self): @@ -473,14 +472,28 @@ class Plugin(): """ self.__message(MessageType.INFO, brief, detail=detail) - def warn(self, brief, *, detail=None): - """Print a warning message + def warn(self, brief, *, detail=None, warning_token=None): + """Print a warning message, checks warning_token against project configuration Args: brief (str): The brief message detail (str): An optional detailed message, can be multiline output + warning_token (str): An optional configurable warning assosciated with this warning, + this will cause PluginError to be raised if this warning is configured as fatal. + (*Since 1.4*) + + Raises: + (:class:`.PluginError`): When warning_token is considered fatal by the project configuration """ - self.__message(MessageType.WARN, brief, detail=detail) + if warning_token: + warning_token = _prefix_warning(self, warning_token) + brief = "[{}]: {}".format(warning_token, brief) + project = self._get_project() + + if project._warning_is_fatal(warning_token): + raise PluginError(message="{}\n{}".format(brief, detail), reason=warning_token) + + self.__message(MessageType.WARN, brief=brief, detail=detail) def log(self, brief, *, detail=None): """Log a message into the plugin's log file @@ -709,6 +722,32 @@ class Plugin(): return self.name +class CoreWarnings(): + """CoreWarnings() + + Some common warnings which are raised by core functionalities within BuildStream are found in this class. + """ + + OVERLAPS = "overlaps" + """ + This warning will be produced when buildstream detects an overlap on an element + which is not whitelisted. + """ + + REF_NOT_IN_TRACK = "ref-not-in-track" + """ + This warning will be produced when a source is configured with a reference + which is found to be invalid based on the configured track + """ + + +__CORE_WARNINGS = [ + value + for name, value in CoreWarnings.__dict__.items() + if not name.startswith("__") +] + + # Hold on to a lookup table by counter of all instantiated plugins. # We use this to send the id back from child processes so we can lookup # corresponding element/source in the master process. @@ -739,6 +778,23 @@ def _plugin_lookup(unique_id): return __PLUGINS_TABLE[unique_id] +# _prefix_warning(): +# +# Prefix a warning with the plugin kind. CoreWarnings are not prefixed. +# +# Args: +# plugin (Plugin): The plugin which raised the warning +# warning (str): The warning to prefix +# +# Returns: +# (str): A prefixed warning +# +def _prefix_warning(plugin, warning): + if any((warning is core_warning for core_warning in __CORE_WARNINGS)): + return warning + return "{}:{}".format(plugin.get_kind(), warning) + + # No need for unregister, WeakValueDictionary() will remove entries # in itself when the referenced plugins are garbage collected. def _plugin_register(plugin): |