1
0
mirror of https://github.com/ARM-software/workload-automation.git synced 2025-02-28 07:48:51 +00:00

Added merge_using_priority_specificity

This complex function handles merging of config with two priorities in mind.
The specificity of the config (`device_config` vs `nexus10`) and the priorty
of the source.
This commit is contained in:
Sebastian Goscik 2016-08-12 15:26:46 +01:00
parent 22888b502f
commit 57cd5a93fe

View File

@ -14,12 +14,13 @@
import os import os
from copy import copy from copy import copy
from collections import OrderedDict from collections import OrderedDict, defaultdict
from wlauto.exceptions import ConfigError from wlauto.exceptions import ConfigError
from wlauto.utils.misc import (get_article, merge_config_values) from wlauto.utils.misc import (get_article, merge_config_values)
from wlauto.utils.types import (identifier, integer, boolean, from wlauto.utils.types import (identifier, integer, boolean,
list_of_strings, toggle_set) list_of_strings, toggle_set,
obj_dict)
from wlauto.core.configuration.tree import SectionNode from wlauto.core.configuration.tree import SectionNode
########################## ##########################
@ -306,6 +307,88 @@ class ConfigurationPoint(object):
### Configuration ### ### Configuration ###
##################### #####################
# pylint: disable=too-many-nested-blocks, too-many-branches
def merge_using_priority_specificity(generic_name, specific_name, plugin_cache):
"""
WA configuration can come from various sources of increasing priority, as well
as being specified in a generic and specific manner (e.g. ``device_config``
and ``nexus10`` respectivly). WA has two rules for the priority of configuration:
- Configuration from higher priority sources overrides configuration from
lower priority sources.
- More specific configuration overrides less specific configuration.
There is a situation where these two rules come into conflict. When a generic
configuration is given in config source of high priority and a specific
configuration is given in a config source of lower priority. In this situation
it is not possible to know the end users intention and WA will error.
:param generic_name: The name of the generic configuration e.g ``device_config``
:param specific_name: The name of the specific configuration used, e.g ``nexus10``
:param cfg_point: A dict of ``ConfigurationPoint``s to be used when merging configuration.
keys=config point name, values=config point
:rtype: A fully merged and validated configuration in the form of a obj_dict.
"""
generic_config = plugin_cache.get_plugin_config(generic_name)
specific_config = plugin_cache.get_plugin_config(specific_name)
cfg_points = plugin_cache.get_plugin_config_points(specific_name)
sources = plugin_cache.sources
final_config = obj_dict(not_in_dict=['name'])
seen_specific_config = defaultdict(list)
# set_value uses the 'name' attribute of the passed object in it error
# messages, to ensure these messages make sense the name will have to be
# changed several times during this function.
final_config.name = specific_name
# Load default config
for cfg_point in cfg_points.itervalues():
cfg_point.set_value(final_config, check_mandatory=False)
# pylint: disable=too-many-nested-blocks
for source in sources:
try:
if source in generic_config:
for name, cfg_point in cfg_points.iteritems():
final_config.name = generic_name
if name in generic_config[source]:
if name in seen_specific_config:
msg = ('"{generic_name}" configuration "{config_name}" has already been '
'specified more specifically for {specific_name} in:\n\t\t{sources}')
msg = msg.format(generic_name=generic_name,
config_name=name,
specific_name=specific_name,
sources="\n\t\t".join(seen_specific_config[name]))
raise ConfigError(msg)
value = generic_config[source].pop(name)
cfg_point.set_value(final_config, value, check_mandatory=False)
if generic_config[source]:
msg = 'Invalid entry(ies) for "{}" in "{}": "{}"'
msg = msg.format(specific_name, generic_name, '", "'.join(generic_config[source]))
raise ConfigError(msg)
if source in specific_config:
final_config.name = specific_name
for name, cfg_point in cfg_points.iteritems():
if name in specific_config[source]:
seen_specific_config[name].append(source)
value = specific_config[source].pop(name)
cfg_point.set_value(final_config, value, check_mandatory=False)
if specific_config[source]:
msg = 'Invalid entry(ies) for "{}": "{}"'
raise ConfigError(msg.format(specific_name, '", "'.join(specific_config[source])))
except ConfigError as e:
raise ConfigError('Error in "{}":\n\t{}'.format(source, str(e)))
# Validate final configuration
final_config.name = specific_name
for cfg_point in cfg_points.itervalues():
cfg_point.validate(final_config)
return final_config
class Configuration(object): class Configuration(object):