Generalized handling of cumulative attributes in target overrides

In tools/config.py, Config now aggregates all cumulative attributes in
target overrides.

{
  "target_overrides": {
    "K64F": {
      "target.features_add": ["UVISOR"],
      "target.extra_labels_add": ["UVISOR_SUPPORTED"],
      "target.macros_add": ["UVISOR_MACRO"],
      "target.device_has_add": ["UVISOR_HAS"]
    }
  }
}

Note: no action is performed on overrides yet
pull/2215/head
Christopher Haster 2016-07-21 13:53:02 -05:00
parent 48c1d2eb7a
commit 0fcb20e8c1
1 changed files with 60 additions and 37 deletions

View File

@ -137,6 +137,40 @@ class ConfigMacro:
self.macro_name = name
self.macro_value = None
# Representation of overrides for cumulative attributes
class ConfigCumulativeOverride:
def __init__(self, name, additions=set(), removals=set(), strict=False):
self.name = name
self.additions = set(additions)
self.removals = set(removals)
self.strict = strict
# Add attr to the cumulative override
def remove_cumulative_override(self, overrides):
for override in overrides:
if override in self.additions:
raise ConfigException("Configuration conflict. The %s %s both added and removed." % (self.name, override))
self.removals |= set(overrides)
# Remove attr from the cumulative overrides
def add_cumulative_overrides(self, overrides):
for override in overrides:
if (override in self.removals or (self.strict and override not in self.additions)):
raise ConfigException("Configuration conflict. The %s %s both added and removed." % (self.name, override))
self.additions |= set(overrides)
# Enable strict set of cumulative overrides for the specified attr
def strict_cumulative_overrides(self, overrides):
self.remove_cumulative_override(self.additions - set(overrides))
self.add_cumulative_override(overrides)
self.strict = True
def get_cumulative_overrides(self, target):
return set(getattr(target, self.name)) | self.additions - self.removals
# 'Config' implements the mbed configuration mechanism
class Config:
# Libraries and applications have different names for their configuration files
@ -184,9 +218,9 @@ class Config:
self.processed_configs = {}
self.target = target if isinstance(target, basestring) else target.name
self.target_labels = Target.get_target(self.target).get_labels()
self.added_features = set()
self.removed_features = set()
self.removed_unecessary_features = False
self.cumulative_overrides = { key: ConfigCumulativeOverride(key)
for key in Target._Target__cumulative_attributes }
# Add one or more configuration files
def add_config_files(self, flist):
@ -222,23 +256,6 @@ class Config:
params[full_name] = ConfigParameter(name, v if isinstance(v, dict) else {"value": v}, unit_name, unit_kind)
return params
# Add features to the available features
def remove_features(self, features):
for feature in features:
if feature in self.added_features:
raise ConfigException("Configuration conflict. Feature %s both added and removed." % feature)
self.removed_features |= set(features)
# Remove features from the available features
def add_features(self, features):
for feature in features:
if (feature in self.removed_features
or (self.removed_unecessary_features and feature not in self.added_features)):
raise ConfigException("Configuration conflict. Feature %s both added and removed." % feature)
self.added_features |= set(features)
# Helper function: process "config_parameters" and "target_config_overrides" in a given dictionary
# data: the configuration data of the library/appliation
# params: storage for the discovered configuration parameters
@ -250,21 +267,19 @@ class Config:
for label, overrides in data.get("target_overrides", {}).items():
# If the label is defined by the target or it has the special value "*", process the overrides
if (label == '*') or (label in self.target_labels):
# Parse out features
if 'target.features' in overrides:
features = overrides['target.features']
self.remove_features(self.added_features - set(features))
self.add_features(features)
self.removed_unecessary_features = True
del overrides['target.features']
# Parse out cumulative overrides
for attr, cumulatives in self.cumulative_overrides.iteritems():
if 'target.'+attr in overrides:
cumulatives.strict_cumulative_overrides(overrides['target.'+attr])
del overrides['target.'+attr]
if 'target.features_add' in overrides:
self.add_features(overrides['target.features_add'])
del overrides['target.features_add']
if 'target.'+attr+'_add' in overrides:
cumulatives.add_cumulative_overrides(overrides['target.'+attr+'_add'])
del overrides['target.'+attr+'_add']
if 'target.features_remove' in overrides:
self.remove_features(overrides['target.features_remove'])
del overrides['target.features_remove']
if 'target.'+attr+'_remove' in overrides:
cumulatives.remove_cumulative_overrides(overrides['target.'+attr+'_remove'])
del overrides['target.'+attr+'_remove']
# Consider the others as overrides
for name, v in overrides.items():
@ -385,12 +400,20 @@ class Config:
def get_config_data_macros(self):
return self.config_to_macros(self.get_config_data())
# Returns any features in the configuration data
def get_features(self):
# Returns any cumulative overrides in the configuration data
def get_cumulative_overrides(self, attr):
if attr not in self.cumulative_overrides:
return None
params, _ = self.get_config_data()
self._check_required_parameters(params)
features = ((set(Target.get_target(self.target).features)
| self.added_features) - self.removed_features)
return self.cumulative_overrides[attr].get_cumulative_overrides(
Target.get_target(self.target))
# Returns any features in the configuration data
def get_features(self):
features = self.get_cumulative_overrides('features')
for feature in features:
if feature not in self.__allowed_features: