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:
parent
22888b502f
commit
57cd5a93fe
@ -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):
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user