From 0fcb20e8c1fe0fa8f7715368172c5a9a0a06b73e Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Thu, 21 Jul 2016 13:53:02 -0500 Subject: [PATCH] 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 --- tools/config.py | 97 ++++++++++++++++++++++++++++++------------------- 1 file changed, 60 insertions(+), 37 deletions(-) diff --git a/tools/config.py b/tools/config.py index 3971e7f5d5..7898a77062 100644 --- a/tools/config.py +++ b/tools/config.py @@ -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: