Clone of official tools

Revision:
24:25bff2709c20
Parent:
13:ab47a20b66f0
Child:
29:1210849dba19
--- a/config.py	Sat Jul 16 22:51:17 2016 +0100
+++ b/config.py	Mon Aug 01 09:10:17 2016 +0100
@@ -137,6 +137,42 @@
             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_overrides(self, overrides):
+        for override in overrides:
+            if override in self.additions:
+                raise ConfigException("Configuration conflict. The %s %s both added and removed." % (self.name[:-1], 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[:-1], override))
+
+        self.additions |= set(overrides)
+
+    # Enable strict set of cumulative overrides for the specified attr
+    def strict_cumulative_overrides(self, overrides):
+        self.remove_cumulative_overrides(self.additions - set(overrides))
+        self.add_cumulative_overrides(overrides)
+        self.strict = True
+
+    def update_target(self, target):
+        setattr(target, self.name, list(
+                (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
@@ -152,7 +188,7 @@
 
     # Allowed features in configurations
     __allowed_features = [
-        "UVISOR", "BLE", "CLIENT", "IPV4", "IPV6"
+        "UVISOR", "BLE", "CLIENT", "IPV4", "IPV6", "COMMON_PAL", "STORAGE"
     ]
 
     # The initialization arguments for Config are:
@@ -184,9 +220,12 @@
         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 }
+
+        self._process_config_and_overrides(self.app_config_data, {}, "app", "application")
+        self.target_labels = Target.get_target(self.target).get_labels()
 
     # Add one or more configuration files
     def add_config_files(self, flist):
@@ -222,23 +261,6 @@
             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 +272,25 @@
         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']
+                # Check for invalid cumulative overrides in libraries
+                if (unit_kind == 'library' and 
+                    any(attr.startswith('target.extra_labels') for attr in overrides.iterkeys())):
+                    raise ConfigException("Target override '%s' in '%s' is only allowed at the application level"
+                        % ("target.extra_labels", ConfigParameter.get_display_name(unit_name, unit_kind, label)))
 
-                if 'target.features_add' in overrides:
-                    self.add_features(overrides['target.features_add'])
-                    del overrides['target.features_add']
+                # 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_remove' in overrides:
-                    self.remove_features(overrides['target.features_remove'])
-                    del overrides['target.features_remove']
+                    if 'target.'+attr+'_add' in overrides:
+                        cumulatives.add_cumulative_overrides(overrides['target.'+attr+'_add'])
+                        del overrides['target.'+attr+'_add']
+
+                    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():
@@ -275,6 +301,10 @@
                     else:
                         self.config_errors.append(ConfigException("Attempt to override undefined parameter '%s' in '%s'"
                             % (full_name, ConfigParameter.get_display_name(unit_name, unit_kind, label))))
+
+        for cumulatives in self.cumulative_overrides.itervalues():
+            cumulatives.update_target(Target.get_target(self.target))
+
         return params
 
     # Read and interpret configuration data defined by targets
@@ -389,8 +419,8 @@
     def get_features(self):
         params, _ = self.get_config_data()
         self._check_required_parameters(params)
-        features = ((set(Target.get_target(self.target).features)
-            | self.added_features) - self.removed_features)
+        self.cumulative_overrides['features'].update_target(Target.get_target(self.target))
+        features = Target.get_target(self.target).features
 
         for feature in features:
             if feature not in self.__allowed_features: