mirror of https://github.com/ARMmbed/mbed-os.git
				
				
				
			Glorify config.py (passes pylint)
							parent
							
								
									b2156ceef5
								
							
						
					
					
						commit
						acf5c40af4
					
				
							
								
								
									
										653
									
								
								tools/config.py
								
								
								
								
							
							
						
						
									
										653
									
								
								tools/config.py
								
								
								
								
							| 
						 | 
				
			
			@ -16,40 +16,52 @@ limitations under the License.
 | 
			
		|||
"""
 | 
			
		||||
 | 
			
		||||
# Implementation of mbed configuration mechanism
 | 
			
		||||
from copy import deepcopy
 | 
			
		||||
from collections import OrderedDict
 | 
			
		||||
from tools.utils import json_file_to_dict, ToolException
 | 
			
		||||
from tools.utils import json_file_to_dict
 | 
			
		||||
from tools.targets import Target
 | 
			
		||||
import os
 | 
			
		||||
 | 
			
		||||
# Base class for all configuration exceptions
 | 
			
		||||
class ConfigException(Exception):
 | 
			
		||||
    """Config system only exception. Makes it easier to distinguish config
 | 
			
		||||
    errors"""
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
# This class keeps information about a single configuration parameter
 | 
			
		||||
class ConfigParameter:
 | 
			
		||||
    # name: the name of the configuration parameter
 | 
			
		||||
    # data: the data associated with the configuration parameter
 | 
			
		||||
    # unit_name: the unit (target/library/application) that defines this parameter
 | 
			
		||||
    # unit_ kind: the kind of the unit ("target", "library" or "application")
 | 
			
		||||
class ConfigParameter(object):
 | 
			
		||||
    """This class keeps information about a single configuration parameter"""
 | 
			
		||||
 | 
			
		||||
    def __init__(self, name, data, unit_name, unit_kind):
 | 
			
		||||
        self.name = self.get_full_name(name, unit_name, unit_kind, allow_prefix = False)
 | 
			
		||||
        """
 | 
			
		||||
        name: the name of the configuration parameter
 | 
			
		||||
        data: the data associated with the configuration parameter
 | 
			
		||||
        unit_name: the unit (target/library/application) that defines this
 | 
			
		||||
                   parameter
 | 
			
		||||
        unit_ kind: the kind of the unit ("target", "library" or "application")
 | 
			
		||||
        """
 | 
			
		||||
        self.name = self.get_full_name(name, unit_name, unit_kind,
 | 
			
		||||
                                       allow_prefix=False)
 | 
			
		||||
        self.defined_by = self.get_display_name(unit_name, unit_kind)
 | 
			
		||||
        self.set_value(data.get("value", None), unit_name, unit_kind)
 | 
			
		||||
        self.help_text = data.get("help", None)
 | 
			
		||||
        self.required = data.get("required", False)
 | 
			
		||||
        self.macro_name = data.get("macro_name", "MBED_CONF_%s" % self.sanitize(self.name.upper()))
 | 
			
		||||
        self.macro_name = data.get("macro_name", "MBED_CONF_%s" %
 | 
			
		||||
                                   self.sanitize(self.name.upper()))
 | 
			
		||||
        self.config_errors = []
 | 
			
		||||
 | 
			
		||||
    # Return the full (prefixed) name of a parameter.
 | 
			
		||||
    # If the parameter already has a prefix, check if it is valid
 | 
			
		||||
    # name: the simple (unqualified) name of the parameter
 | 
			
		||||
    # unit_name: the unit (target/library/application) that defines this parameter
 | 
			
		||||
    # unit_kind: the kind of the unit ("target", "library" or "application")
 | 
			
		||||
    # label: the name of the label in the 'target_config_overrides' section (optional)
 | 
			
		||||
    # allow_prefix: True to allo the original name to have a prefix, False otherwise
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def get_full_name(name, unit_name, unit_kind, label = None, allow_prefix = True):
 | 
			
		||||
    def get_full_name(name, unit_name, unit_kind, label=None,
 | 
			
		||||
                      allow_prefix=True):
 | 
			
		||||
        """Return the full (prefixed) name of a parameter. If the parameter
 | 
			
		||||
        already has a prefix, check if it is valid
 | 
			
		||||
 | 
			
		||||
        name: the simple (unqualified) name of the parameter
 | 
			
		||||
        unit_name: the unit (target/library/application) that defines this
 | 
			
		||||
                   parameter
 | 
			
		||||
        unit_kind: the kind of the unit ("target", "library" or "application")
 | 
			
		||||
        label: the name of the label in the 'target_config_overrides' section
 | 
			
		||||
               (optional)
 | 
			
		||||
        allow_prefix: True to allow the original name to have a prefix, False
 | 
			
		||||
                      otherwise
 | 
			
		||||
        """
 | 
			
		||||
        if name.find('.') == -1: # the name is not prefixed
 | 
			
		||||
            if unit_kind == "target":
 | 
			
		||||
                prefix = "target."
 | 
			
		||||
| 
						 | 
				
			
			@ -60,24 +72,37 @@ class ConfigParameter:
 | 
			
		|||
            return prefix + name
 | 
			
		||||
        # The name has a prefix, so check if it is valid
 | 
			
		||||
        if not allow_prefix:
 | 
			
		||||
            raise ConfigException("Invalid parameter name '%s' in '%s'" % (name, ConfigParameter.get_display_name(unit_name, unit_kind, label)))
 | 
			
		||||
            raise ConfigException("Invalid parameter name '%s' in '%s'" %
 | 
			
		||||
                                  (name, ConfigParameter.get_display_name(
 | 
			
		||||
                                      unit_name, unit_kind, label)))
 | 
			
		||||
        temp = name.split(".")
 | 
			
		||||
        # Check if the parameter syntax is correct (must be unit_name.parameter_name)
 | 
			
		||||
        # Check if the parameter syntax is correct (must be
 | 
			
		||||
        # unit_name.parameter_name)
 | 
			
		||||
        if len(temp) != 2:
 | 
			
		||||
            raise ConfigException("Invalid parameter name '%s' in '%s'" % (name, ConfigParameter.get_display_name(unit_name, unit_kind, label)))
 | 
			
		||||
            raise ConfigException("Invalid parameter name '%s' in '%s'" %
 | 
			
		||||
                                  (name, ConfigParameter.get_display_name(
 | 
			
		||||
                                      unit_name, unit_kind, label)))
 | 
			
		||||
        prefix = temp[0]
 | 
			
		||||
        # Check if the given parameter prefix matches the expected prefix
 | 
			
		||||
        if (unit_kind == "library" and prefix != unit_name) or (unit_kind == "target" and prefix != "target"):
 | 
			
		||||
            raise ConfigException("Invalid prefix '%s' for parameter name '%s' in '%s'" % (prefix, name, ConfigParameter.get_display_name(unit_name, unit_kind, label)))
 | 
			
		||||
        if (unit_kind == "library" and prefix != unit_name) or \
 | 
			
		||||
           (unit_kind == "target" and prefix != "target"):
 | 
			
		||||
            raise ConfigException(
 | 
			
		||||
                "Invalid prefix '%s' for parameter name '%s' in '%s'" %
 | 
			
		||||
                (prefix, name, ConfigParameter.get_display_name(
 | 
			
		||||
                    unit_name, unit_kind, label)))
 | 
			
		||||
        return name
 | 
			
		||||
 | 
			
		||||
    # Return the name displayed for a unit when interogating the origin
 | 
			
		||||
    # and the last set place of a parameter
 | 
			
		||||
    # unit_name: the unit (target/library/application) that defines this parameter
 | 
			
		||||
    # unit_kind: the kind of the unit ("target", "library" or "application")
 | 
			
		||||
    # label: the name of the label in the 'target_config_overrides' section (optional)
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def get_display_name(unit_name, unit_kind, label = None):
 | 
			
		||||
    def get_display_name(unit_name, unit_kind, label=None):
 | 
			
		||||
        """Return the name displayed for a unit when interrogating the origin
 | 
			
		||||
        and the last set place of a parameter
 | 
			
		||||
 | 
			
		||||
        unit_name: the unit (target/library/application) that defines this
 | 
			
		||||
                   parameter
 | 
			
		||||
        unit_kind: the kind of the unit ("target", "library" or "application")
 | 
			
		||||
        label: the name of the label in the 'target_config_overrides' section
 | 
			
		||||
               (optional)
 | 
			
		||||
        """
 | 
			
		||||
        if unit_kind == "target":
 | 
			
		||||
            return "target:" + unit_name
 | 
			
		||||
        elif unit_kind == "application":
 | 
			
		||||
| 
						 | 
				
			
			@ -85,33 +110,42 @@ class ConfigParameter:
 | 
			
		|||
        else: # library
 | 
			
		||||
            return "library:%s%s" % (unit_name, "[%s]" % label if label else "")
 | 
			
		||||
 | 
			
		||||
    # "Sanitize" a name so that it is a valid C macro name
 | 
			
		||||
    # Currently it simply replaces '.' and '-' with '_'
 | 
			
		||||
    # name: the un-sanitized name.
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def sanitize(name):
 | 
			
		||||
        """ "Sanitize" a name so that it is a valid C macro name Currently it
 | 
			
		||||
        simply replaces '.' and '-' with '_' name: the un-sanitized name.
 | 
			
		||||
        """
 | 
			
		||||
        return name.replace('.', '_').replace('-', '_')
 | 
			
		||||
 | 
			
		||||
    # Sets a value for this parameter, remember the place where it was set.
 | 
			
		||||
    # If the value is a boolean, it is converted to 1 (for True) or to 0 (for False).
 | 
			
		||||
    # value: the value of the parameter
 | 
			
		||||
    # unit_name: the unit (target/library/application) that defines this parameter
 | 
			
		||||
    # unit_ kind: the kind of the unit ("target", "library" or "application")
 | 
			
		||||
    # label: the name of the label in the 'target_config_overrides' section (optional)
 | 
			
		||||
    def set_value(self, value, unit_name, unit_kind, label = None):
 | 
			
		||||
    def set_value(self, value, unit_name, unit_kind, label=None):
 | 
			
		||||
        """ Sets a value for this parameter, remember the place where it was
 | 
			
		||||
        set.  If the value is a boolean, it is converted to 1 (for True) or
 | 
			
		||||
        to 0 (for False).
 | 
			
		||||
 | 
			
		||||
        value: the value of the parameter
 | 
			
		||||
        unit_name: the unit (target/library/application) that defines this
 | 
			
		||||
                   parameter
 | 
			
		||||
        unit_ kind: the kind of the unit ("target", "library" or "application")
 | 
			
		||||
        label: the name of the label in the 'target_config_overrides' section
 | 
			
		||||
               (optional)
 | 
			
		||||
        """
 | 
			
		||||
        self.value = int(value) if isinstance(value, bool) else value
 | 
			
		||||
        self.set_by = self.get_display_name(unit_name, unit_kind, label)
 | 
			
		||||
 | 
			
		||||
    # Return the string representation of this configuration parameter
 | 
			
		||||
    def __str__(self):
 | 
			
		||||
        """Return the string representation of this configuration parameter"""
 | 
			
		||||
        if self.value is not None:
 | 
			
		||||
            return '%s = %s (macro name: "%s")' % (self.name, self.value, self.macro_name)
 | 
			
		||||
            return '%s = %s (macro name: "%s")' % \
 | 
			
		||||
                (self.name, self.value, self.macro_name)
 | 
			
		||||
        else:
 | 
			
		||||
            return '%s has no value' % self.name
 | 
			
		||||
 | 
			
		||||
    # Return a verbose description of this configuration paramater as a string
 | 
			
		||||
    def get_verbose_description(self):
 | 
			
		||||
        desc = "Name: %s%s\n" % (self.name, " (required parameter)" if self.required else "")
 | 
			
		||||
        """Return a verbose description of this configuration paramater as a
 | 
			
		||||
        string
 | 
			
		||||
        """
 | 
			
		||||
        desc = "Name: %s%s\n" % \
 | 
			
		||||
               (self.name, " (required parameter)" if self.required else "")
 | 
			
		||||
        if self.help_text:
 | 
			
		||||
            desc += "    Description: %s\n" % self.help_text
 | 
			
		||||
        desc += "    Defined by: %s\n" % self.defined_by
 | 
			
		||||
| 
						 | 
				
			
			@ -121,69 +155,139 @@ class ConfigParameter:
 | 
			
		|||
        desc += "    Value: %s (set by %s)" % (self.value, self.set_by)
 | 
			
		||||
        return desc
 | 
			
		||||
 | 
			
		||||
# A representation of a configuration macro. It handles both macros without a value (MACRO)
 | 
			
		||||
# and with a value (MACRO=VALUE)
 | 
			
		||||
class ConfigMacro:
 | 
			
		||||
class ConfigMacro(object):
 | 
			
		||||
    """ A representation of a configuration macro. It handles both macros
 | 
			
		||||
    without a value (MACRO) and with a value (MACRO=VALUE)
 | 
			
		||||
    """
 | 
			
		||||
    def __init__(self, name, unit_name, unit_kind):
 | 
			
		||||
        self.name = name
 | 
			
		||||
        self.defined_by = ConfigParameter.get_display_name(unit_name, unit_kind)
 | 
			
		||||
        if name.find("=") != -1:
 | 
			
		||||
            tmp = name.split("=")
 | 
			
		||||
            if len(tmp) != 2:
 | 
			
		||||
                raise ValueError("Invalid macro definition '%s' in '%s'" % (name, self.defined_by))
 | 
			
		||||
                raise ValueError("Invalid macro definition '%s' in '%s'" %
 | 
			
		||||
                                 (name, self.defined_by))
 | 
			
		||||
            self.macro_name = tmp[0]
 | 
			
		||||
            self.macro_value = tmp[1]
 | 
			
		||||
        else:
 | 
			
		||||
            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):
 | 
			
		||||
class ConfigCumulativeOverride(object):
 | 
			
		||||
    """Representation of overrides for cumulative attributes"""
 | 
			
		||||
    def __init__(self, name, additions=None, removals=None, strict=False):
 | 
			
		||||
        self.name = name
 | 
			
		||||
        self.additions = set(additions)
 | 
			
		||||
        self.removals = set(removals)
 | 
			
		||||
        if additions:
 | 
			
		||||
            self.additions = set(additions)
 | 
			
		||||
        else:
 | 
			
		||||
            self.additions = set()
 | 
			
		||||
        if removals:
 | 
			
		||||
            self.removals = set(removals)
 | 
			
		||||
        else:
 | 
			
		||||
            self.removals = set()
 | 
			
		||||
        self.strict = strict
 | 
			
		||||
 | 
			
		||||
    # Add attr to the cumulative override
 | 
			
		||||
    def remove_cumulative_overrides(self, overrides):
 | 
			
		||||
        """Add attr to the cumulative override"""
 | 
			
		||||
        for override in overrides:
 | 
			
		||||
            if override in self.additions:
 | 
			
		||||
                raise ConfigException("Configuration conflict. The %s %s both added and removed." % (self.name[:-1], override))
 | 
			
		||||
                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):
 | 
			
		||||
        """Remove attr from the cumulative 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))
 | 
			
		||||
            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):
 | 
			
		||||
        """Enable strict set of cumulative overrides for the specified attr"""
 | 
			
		||||
        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))
 | 
			
		||||
        """Update the attributes of a target based on this override"""
 | 
			
		||||
        setattr(target, self.name,
 | 
			
		||||
                list((set(getattr(target, self.name, []))
 | 
			
		||||
                      | self.additions) - self.removals))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _process_config_parameters(data, params, unit_name, unit_kind):
 | 
			
		||||
    """Process a "config_parameters" section in either a target, a library
 | 
			
		||||
    or the application
 | 
			
		||||
 | 
			
		||||
# 'Config' implements the mbed configuration mechanism
 | 
			
		||||
class Config:
 | 
			
		||||
    # Libraries and applications have different names for their configuration files
 | 
			
		||||
    data: a dictionary with the configuration parameters
 | 
			
		||||
    params: storage for the discovered configuration parameters
 | 
			
		||||
    unit_name: the unit (target/library/application) that defines this parameter
 | 
			
		||||
    unit_kind: the kind of the unit ("target", "library" or "application")
 | 
			
		||||
    """
 | 
			
		||||
    for name, val in data.items():
 | 
			
		||||
        full_name = ConfigParameter.get_full_name(name, unit_name, unit_kind)
 | 
			
		||||
        # If the parameter was already defined, raise an error
 | 
			
		||||
        if full_name in params:
 | 
			
		||||
            raise ConfigException(
 | 
			
		||||
                "Parameter name '%s' defined in both '%s' and '%s'" %
 | 
			
		||||
                (name, ConfigParameter.get_display_name(unit_name, unit_kind),
 | 
			
		||||
                 params[full_name].defined_by))
 | 
			
		||||
        # Otherwise add it to the list of known parameters
 | 
			
		||||
        # If "val" is not a dictionary, this is a shortcut definition,
 | 
			
		||||
        # otherwise it is a full definition
 | 
			
		||||
        params[full_name] = ConfigParameter(name, val if isinstance(val, dict)
 | 
			
		||||
                                            else {"value": val}, unit_name,
 | 
			
		||||
                                            unit_kind)
 | 
			
		||||
    return params
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _process_macros(mlist, macros, unit_name, unit_kind):
 | 
			
		||||
    """Process a macro definition, checking for incompatible duplicate
 | 
			
		||||
    definitions
 | 
			
		||||
 | 
			
		||||
    mlist: list of macro names to process
 | 
			
		||||
    macros: dictionary with currently discovered macros
 | 
			
		||||
    unit_name: the unit (library/application) that defines this macro
 | 
			
		||||
    unit_kind: the kind of the unit ("library" or "application")
 | 
			
		||||
    """
 | 
			
		||||
    for mname in mlist:
 | 
			
		||||
        macro = ConfigMacro(mname, unit_name, unit_kind)
 | 
			
		||||
        if (macro.macro_name in macros) and \
 | 
			
		||||
           (macros[macro.macro_name].name != mname):
 | 
			
		||||
            # Found an incompatible definition of the macro in another module,
 | 
			
		||||
            # so raise an error
 | 
			
		||||
            full_unit_name = ConfigParameter.get_display_name(unit_name,
 | 
			
		||||
                                                              unit_kind)
 | 
			
		||||
            raise ConfigException(
 | 
			
		||||
                ("Macro '%s' defined in both '%s' and '%s'"
 | 
			
		||||
                 % (macro.macro_name, macros[macro.macro_name].defined_by,
 | 
			
		||||
                    full_unit_name)) +
 | 
			
		||||
                " with incompatible values")
 | 
			
		||||
        macros[macro.macro_name] = macro
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Config(object):
 | 
			
		||||
    """'Config' implements the mbed configuration mechanism"""
 | 
			
		||||
 | 
			
		||||
    # Libraries and applications have different names for their configuration
 | 
			
		||||
    # files
 | 
			
		||||
    __mbed_app_config_name = "mbed_app.json"
 | 
			
		||||
    __mbed_lib_config_name = "mbed_lib.json"
 | 
			
		||||
 | 
			
		||||
    # Allowed keys in configuration dictionaries
 | 
			
		||||
    # (targets can have any kind of keys, so this validation is not applicable to them)
 | 
			
		||||
    # (targets can have any kind of keys, so this validation is not applicable
 | 
			
		||||
    # to them)
 | 
			
		||||
    __allowed_keys = {
 | 
			
		||||
        "library": set(["name", "config", "target_overrides", "macros", "__config_path"]),
 | 
			
		||||
        "application": set(["config", "custom_targets", "target_overrides", "macros", "__config_path"])
 | 
			
		||||
        "library": set(["name", "config", "target_overrides", "macros",
 | 
			
		||||
                        "__config_path"]),
 | 
			
		||||
        "application": set(["config", "custom_targets", "target_overrides",
 | 
			
		||||
                            "macros", "__config_path"])
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    # Allowed features in configurations
 | 
			
		||||
| 
						 | 
				
			
			@ -191,29 +295,43 @@ class Config:
 | 
			
		|||
        "UVISOR", "BLE", "CLIENT", "IPV4", "IPV6", "COMMON_PAL", "STORAGE"
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    # The initialization arguments for Config are:
 | 
			
		||||
    #     target: the name of the mbed target used for this configuration instance
 | 
			
		||||
    #     top_level_dirs: a list of top level source directories (where mbed_abb_config.json could be found)
 | 
			
		||||
    # __init__ will look for the application configuration file in top_level_dirs.
 | 
			
		||||
    # If found once, it'll parse it and check if it has a custom_targets function.
 | 
			
		||||
    # If it does, it'll update the list of targets if need.
 | 
			
		||||
    # If found more than once, an exception is raised
 | 
			
		||||
    # top_level_dirs can be None (in this case, mbed_app_config.json will not be searched)
 | 
			
		||||
    def __init__(self, target, top_level_dirs = []):
 | 
			
		||||
    def __init__(self, target, top_level_dirs=None):
 | 
			
		||||
        """
 | 
			
		||||
        The initialization arguments for Config are:
 | 
			
		||||
            target: the name of the mbed target used for this configuration
 | 
			
		||||
                    instance
 | 
			
		||||
            top_level_dirs: a list of top level source directories (where
 | 
			
		||||
                            mbed_abb_config.json could be found)
 | 
			
		||||
        __init__ will look for the application configuration file in
 | 
			
		||||
        top_level_dirs.
 | 
			
		||||
        If found once, it'll parse it and check if it has a custom_targets
 | 
			
		||||
        function.
 | 
			
		||||
        If it does, it'll update the list of targets if need.
 | 
			
		||||
        If found more than once, an exception is raised
 | 
			
		||||
        top_level_dirs can be None (in this case, mbed_app_config.json will not
 | 
			
		||||
        be searched)
 | 
			
		||||
        """
 | 
			
		||||
        app_config_location = None
 | 
			
		||||
        for s in (top_level_dirs or []):
 | 
			
		||||
            full_path = os.path.join(s, self.__mbed_app_config_name)
 | 
			
		||||
        for directory in top_level_dirs or []:
 | 
			
		||||
            full_path = os.path.join(directory, self.__mbed_app_config_name)
 | 
			
		||||
            if os.path.isfile(full_path):
 | 
			
		||||
                if app_config_location is not None:
 | 
			
		||||
                    raise ConfigException("Duplicate '%s' file in '%s' and '%s'" % (self.__mbed_app_config_name, app_config_location, full_path))
 | 
			
		||||
                    raise ConfigException("Duplicate '%s' file in '%s' and '%s'"
 | 
			
		||||
                                          % (self.__mbed_app_config_name,
 | 
			
		||||
                                             app_config_location, full_path))
 | 
			
		||||
                else:
 | 
			
		||||
                    app_config_location = full_path
 | 
			
		||||
        self.app_config_data = json_file_to_dict(app_config_location) if app_config_location else {}
 | 
			
		||||
        self.app_config_data = json_file_to_dict(app_config_location) \
 | 
			
		||||
                               if app_config_location else {}
 | 
			
		||||
        # Check the keys in the application configuration data
 | 
			
		||||
        unknown_keys = set(self.app_config_data.keys()) - self.__allowed_keys["application"]
 | 
			
		||||
        unknown_keys = set(self.app_config_data.keys()) - \
 | 
			
		||||
                       self.__allowed_keys["application"]
 | 
			
		||||
        if unknown_keys:
 | 
			
		||||
            raise ConfigException("Unknown key(s) '%s' in %s" % (",".join(unknown_keys), self.__mbed_app_config_name))
 | 
			
		||||
        # Update the list of targets with the ones defined in the application config, if applicable
 | 
			
		||||
            raise ConfigException("Unknown key(s) '%s' in %s" %
 | 
			
		||||
                                  (",".join(unknown_keys),
 | 
			
		||||
                                   self.__mbed_app_config_name))
 | 
			
		||||
        # Update the list of targets with the ones defined in the application
 | 
			
		||||
        # config, if applicable
 | 
			
		||||
        Target.add_py_targets(self.app_config_data.get("custom_targets", {}))
 | 
			
		||||
        self.lib_config_data = {}
 | 
			
		||||
        # Make sure that each config is processed only once
 | 
			
		||||
| 
						 | 
				
			
			@ -221,229 +339,281 @@ class Config:
 | 
			
		|||
        self.target = target if isinstance(target, basestring) else target.name
 | 
			
		||||
        self.target_labels = Target.get_target(self.target).get_labels()
 | 
			
		||||
 | 
			
		||||
        self.cumulative_overrides = { key: ConfigCumulativeOverride(key) 
 | 
			
		||||
                                      for key in Target._Target__cumulative_attributes }
 | 
			
		||||
        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._process_config_and_overrides(self.app_config_data, {}, "app",
 | 
			
		||||
                                           "application")
 | 
			
		||||
        self.target_labels = Target.get_target(self.target).get_labels()
 | 
			
		||||
        self.config_errors = None
 | 
			
		||||
 | 
			
		||||
    # Add one or more configuration files
 | 
			
		||||
    def add_config_files(self, flist):
 | 
			
		||||
        for f in flist:
 | 
			
		||||
            if not f.endswith(self.__mbed_lib_config_name):
 | 
			
		||||
        """Add one or more configuration files"""
 | 
			
		||||
        for config_file in flist:
 | 
			
		||||
            if not config_file.endswith(self.__mbed_lib_config_name):
 | 
			
		||||
                continue
 | 
			
		||||
            full_path = os.path.normpath(os.path.abspath(f))
 | 
			
		||||
            full_path = os.path.normpath(os.path.abspath(config_file))
 | 
			
		||||
            # Check that we didn't already process this file
 | 
			
		||||
            if self.processed_configs.has_key(full_path):
 | 
			
		||||
                continue
 | 
			
		||||
            self.processed_configs[full_path] = True
 | 
			
		||||
            # Read the library configuration and add a "__full_config_path" attribute to it
 | 
			
		||||
            cfg = json_file_to_dict(f)
 | 
			
		||||
            # Read the library configuration and add a "__full_config_path"
 | 
			
		||||
            # attribute to it
 | 
			
		||||
            cfg = json_file_to_dict(config_file)
 | 
			
		||||
            cfg["__config_path"] = full_path
 | 
			
		||||
 | 
			
		||||
            if "name" not in cfg:
 | 
			
		||||
                raise ConfigException("Library configured at %s has no name field." % full_path)
 | 
			
		||||
            # If there's already a configuration for a module with the same name, exit with error
 | 
			
		||||
                raise ConfigException(
 | 
			
		||||
                    "Library configured at %s has no name field." % full_path)
 | 
			
		||||
            # If there's already a configuration for a module with the same
 | 
			
		||||
            # name, exit with error
 | 
			
		||||
            if self.lib_config_data.has_key(cfg["name"]):
 | 
			
		||||
                raise ConfigException("Library name '%s' is not unique (defined in '%s' and '%s')" % (cfg["name"], full_path, self.lib_config_data[cfg["name"]]["__config_path"]))
 | 
			
		||||
                raise ConfigException(
 | 
			
		||||
                    "Library name '%s' is not unique (defined in '%s' and '%s')"
 | 
			
		||||
                    % (cfg["name"], full_path,
 | 
			
		||||
                       self.lib_config_data[cfg["name"]]["__config_path"]))
 | 
			
		||||
            self.lib_config_data[cfg["name"]] = cfg
 | 
			
		||||
 | 
			
		||||
    # Helper function: process a "config_parameters" section in either a target, a library or the application
 | 
			
		||||
    # data: a dictionary with the configuration parameters
 | 
			
		||||
    # params: storage for the discovered configuration parameters
 | 
			
		||||
    # unit_name: the unit (target/library/application) that defines this parameter
 | 
			
		||||
    # unit_kind: the kind of the unit ("target", "library" or "application")
 | 
			
		||||
    def _process_config_parameters(self, data, params, unit_name, unit_kind):
 | 
			
		||||
        for name, v in data.items():
 | 
			
		||||
            full_name = ConfigParameter.get_full_name(name, unit_name, unit_kind)
 | 
			
		||||
            # If the parameter was already defined, raise an error
 | 
			
		||||
            if full_name in params:
 | 
			
		||||
                raise ConfigException("Parameter name '%s' defined in both '%s' and '%s'" % (name, ConfigParameter.get_display_name(unit_name, unit_kind), params[full_name].defined_by))
 | 
			
		||||
            # Otherwise add it to the list of known parameters
 | 
			
		||||
            # If "v" is not a dictionary, this is a shortcut definition, otherwise it is a full definition
 | 
			
		||||
            params[full_name] = ConfigParameter(name, v if isinstance(v, dict) else {"value": v}, unit_name, unit_kind)
 | 
			
		||||
        return params
 | 
			
		||||
 | 
			
		||||
    # 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
 | 
			
		||||
    # unit_name: the unit (library/application) that defines this parameter
 | 
			
		||||
    # unit_kind: the kind of the unit ("library" or "application")
 | 
			
		||||
    def _process_config_and_overrides(self, data, params, unit_name, unit_kind):
 | 
			
		||||
        """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
 | 
			
		||||
        unit_name: the unit (library/application) that defines this parameter
 | 
			
		||||
        unit_kind: the kind of the unit ("library" or "application")
 | 
			
		||||
        """
 | 
			
		||||
        self.config_errors = []
 | 
			
		||||
        self._process_config_parameters(data.get("config", {}), params, unit_name, unit_kind)
 | 
			
		||||
        _process_config_parameters(data.get("config", {}), params, unit_name,
 | 
			
		||||
                                   unit_kind)
 | 
			
		||||
        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 the label is defined by the target or it has the special value
 | 
			
		||||
            # "*", process the overrides
 | 
			
		||||
            if (label == '*') or (label in self.target_labels):
 | 
			
		||||
                # 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 (unit_kind == 'library' and
 | 
			
		||||
                    any(attr.startswith('target.extra_labels') for attr
 | 
			
		||||
                        in overrides.iterkeys())):
 | 
			
		||||
                    raise ConfigException(
 | 
			
		||||
                        "Target override 'target.extra_labels' in " +
 | 
			
		||||
                        ConfigParameter.get_display_name(unit_name, unit_kind,
 | 
			
		||||
                                                         label) +
 | 
			
		||||
                        " is only allowed at the application level")
 | 
			
		||||
 | 
			
		||||
                # Parse out cumulative overrides
 | 
			
		||||
                for attr, cumulatives in self.cumulative_overrides.iteritems():
 | 
			
		||||
                    if 'target.'+attr in overrides:
 | 
			
		||||
                        cumulatives.strict_cumulative_overrides(overrides['target.'+attr])
 | 
			
		||||
                        cumulatives.strict_cumulative_overrides(
 | 
			
		||||
                            overrides['target.'+attr])
 | 
			
		||||
                        del overrides['target.'+attr]
 | 
			
		||||
 | 
			
		||||
                    if 'target.'+attr+'_add' in overrides:
 | 
			
		||||
                        cumulatives.add_cumulative_overrides(overrides['target.'+attr+'_add'])
 | 
			
		||||
                        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'])
 | 
			
		||||
                        cumulatives.remove_cumulative_overrides(
 | 
			
		||||
                            overrides['target.'+attr+'_remove'])
 | 
			
		||||
                        del overrides['target.'+attr+'_remove']
 | 
			
		||||
 | 
			
		||||
                # Consider the others as overrides
 | 
			
		||||
                for name, v in overrides.items():
 | 
			
		||||
                for name, val in overrides.items():
 | 
			
		||||
                    # Get the full name of the parameter
 | 
			
		||||
                    full_name = ConfigParameter.get_full_name(name, unit_name, unit_kind, label)
 | 
			
		||||
                    full_name = ConfigParameter.get_full_name(name, unit_name,
 | 
			
		||||
                                                              unit_kind, label)
 | 
			
		||||
                    if full_name in params:
 | 
			
		||||
                        params[full_name].set_value(v, unit_name, unit_kind, label)
 | 
			
		||||
                        params[full_name].set_value(val, unit_name, unit_kind,
 | 
			
		||||
                                                    label)
 | 
			
		||||
                    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))))
 | 
			
		||||
                        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
 | 
			
		||||
    def get_target_config_data(self):
 | 
			
		||||
        # We consider the resolution order for our target and sort it by level reversed,
 | 
			
		||||
        # so that we first look at the top level target (the parent), then its direct children,
 | 
			
		||||
        # then the children's children and so on, until we reach self.target
 | 
			
		||||
        # TODO: this might not work so well in some multiple inheritance scenarios
 | 
			
		||||
        # At each step, look at two keys of the target data:
 | 
			
		||||
        #   - config_parameters: used to define new configuration parameters
 | 
			
		||||
        #   - config_overrides: used to override already defined configuration parameters
 | 
			
		||||
        """Read and interpret configuration data defined by targets.
 | 
			
		||||
 | 
			
		||||
        We consider the resolution order for our target and sort it by level
 | 
			
		||||
        reversed, so that we first look at the top level target (the parent),
 | 
			
		||||
        then its direct children, then the children's children and so on,
 | 
			
		||||
        until we reach self.target
 | 
			
		||||
        TODO: this might not work so well in some multiple inheritance scenarios
 | 
			
		||||
        At each step, look at two keys of the target data:
 | 
			
		||||
          - config_parameters: used to define new configuration parameters
 | 
			
		||||
          - config_overrides: used to override already defined configuration
 | 
			
		||||
                              parameters
 | 
			
		||||
        """
 | 
			
		||||
        params, json_data = {}, Target.get_json_target_data()
 | 
			
		||||
        resolution_order = [e[0] for e in sorted(Target.get_target(self.target).resolution_order, key = lambda e: e[1], reverse = True)]
 | 
			
		||||
        resolution_order = [e[0] for e
 | 
			
		||||
                            in sorted(
 | 
			
		||||
                                Target.get_target(self.target).resolution_order,
 | 
			
		||||
                                key=lambda e: e[1], reverse=True)]
 | 
			
		||||
        for tname in resolution_order:
 | 
			
		||||
            # Read the target data directly from its description
 | 
			
		||||
            t = json_data[tname]
 | 
			
		||||
            target_data = json_data[tname]
 | 
			
		||||
            # Process definitions first
 | 
			
		||||
            self._process_config_parameters(t.get("config", {}), params, tname, "target")
 | 
			
		||||
            _process_config_parameters(target_data.get("config", {}), params,
 | 
			
		||||
                                       tname, "target")
 | 
			
		||||
            # Then process overrides
 | 
			
		||||
            for name, v in t.get("overrides", {}).items():
 | 
			
		||||
            for name, val in target_data.get("overrides", {}).items():
 | 
			
		||||
                full_name = ConfigParameter.get_full_name(name, tname, "target")
 | 
			
		||||
                # If the parameter name is not defined or if there isn't a path from this target to the target where the
 | 
			
		||||
                # parameter was defined in the target inheritance tree, raise an error
 | 
			
		||||
                # We need to use 'defined_by[7:]' to remove the "target:" prefix from defined_by
 | 
			
		||||
                if (not full_name in params) or (not params[full_name].defined_by[7:] in Target.get_target(tname).resolution_order_names):
 | 
			
		||||
                    raise ConfigException("Attempt to override undefined parameter '%s' in '%s'" % (name, ConfigParameter.get_display_name(tname, "target")))
 | 
			
		||||
                # If the parameter name is not defined or if there isn't a path
 | 
			
		||||
                # from this target to the target where the parameter was defined
 | 
			
		||||
                # in the target inheritance tree, raise an error We need to use
 | 
			
		||||
                # 'defined_by[7:]' to remove the "target:" prefix from
 | 
			
		||||
                # defined_by
 | 
			
		||||
                if (full_name not in params) or \
 | 
			
		||||
                   (params[full_name].defined_by[7:] not in
 | 
			
		||||
                    Target.get_target(tname).resolution_order_names):
 | 
			
		||||
                    raise ConfigException(
 | 
			
		||||
                        "Attempt to override undefined parameter '%s' in '%s'"
 | 
			
		||||
                        % (name,
 | 
			
		||||
                           ConfigParameter.get_display_name(tname, "target")))
 | 
			
		||||
                # Otherwise update the value of the parameter
 | 
			
		||||
                params[full_name].set_value(v, tname, "target")
 | 
			
		||||
                params[full_name].set_value(val, tname, "target")
 | 
			
		||||
        return params
 | 
			
		||||
 | 
			
		||||
    # Helper function: process a macro definition, checking for incompatible duplicate definitions
 | 
			
		||||
    # mlist: list of macro names to process
 | 
			
		||||
    # macros: dictionary with currently discovered macros
 | 
			
		||||
    # unit_name: the unit (library/application) that defines this macro
 | 
			
		||||
    # unit_kind: the kind of the unit ("library" or "application")
 | 
			
		||||
    def _process_macros(self, mlist, macros, unit_name, unit_kind):
 | 
			
		||||
        for mname in mlist:
 | 
			
		||||
            m = ConfigMacro(mname, unit_name, unit_kind)
 | 
			
		||||
            if (m.macro_name in macros) and (macros[m.macro_name].name != mname):
 | 
			
		||||
                # Found an incompatible definition of the macro in another module, so raise an error
 | 
			
		||||
                full_unit_name = ConfigParameter.get_display_name(unit_name, unit_kind)
 | 
			
		||||
                raise ConfigException("Macro '%s' defined in both '%s' and '%s' with incompatible values" % (m.macro_name, macros[m.macro_name].defined_by, full_unit_name))
 | 
			
		||||
            macros[m.macro_name] = m
 | 
			
		||||
 | 
			
		||||
    # Read and interpret configuration data defined by libs
 | 
			
		||||
    # It is assumed that "add_config_files" above was already called and the library configuration data
 | 
			
		||||
    # exists in self.lib_config_data
 | 
			
		||||
    def get_lib_config_data(self):
 | 
			
		||||
        """ Read and interpret configuration data defined by libs It is assumed
 | 
			
		||||
        that "add_config_files" above was already called and the library
 | 
			
		||||
        configuration data exists in self.lib_config_data
 | 
			
		||||
        """
 | 
			
		||||
        all_params, macros = {}, {}
 | 
			
		||||
        for lib_name, lib_data in self.lib_config_data.items():
 | 
			
		||||
            unknown_keys = set(lib_data.keys()) - self.__allowed_keys["library"]
 | 
			
		||||
            if unknown_keys:
 | 
			
		||||
                raise ConfigException("Unknown key(s) '%s' in %s" % (",".join(unknown_keys), lib_name))
 | 
			
		||||
            all_params.update(self._process_config_and_overrides(lib_data, {}, lib_name, "library"))
 | 
			
		||||
            self._process_macros(lib_data.get("macros", []), macros, lib_name, "library")
 | 
			
		||||
                raise ConfigException("Unknown key(s) '%s' in %s" %
 | 
			
		||||
                                      (",".join(unknown_keys), lib_name))
 | 
			
		||||
            all_params.update(self._process_config_and_overrides(lib_data, {},
 | 
			
		||||
                                                                 lib_name,
 | 
			
		||||
                                                                 "library"))
 | 
			
		||||
            _process_macros(lib_data.get("macros", []), macros, lib_name,
 | 
			
		||||
                            "library")
 | 
			
		||||
        return all_params, macros
 | 
			
		||||
 | 
			
		||||
    # Read and interpret the configuration data defined by the target
 | 
			
		||||
    # The target can override any configuration parameter, as well as define its own configuration data
 | 
			
		||||
    # params: the dictionary with configuration parameters found so far (in the target and in libraries)
 | 
			
		||||
    # macros: the list of macros defined in the configuration
 | 
			
		||||
    def get_app_config_data(self, params, macros):
 | 
			
		||||
        app_cfg = self.app_config_data
 | 
			
		||||
        # The application can have a "config_parameters" and a "target_config_overrides" section just like a library
 | 
			
		||||
        self._process_config_and_overrides(app_cfg, params, "app", "application")
 | 
			
		||||
        # The application can also defined macros
 | 
			
		||||
        self._process_macros(app_cfg.get("macros", []), macros, "app", "application")
 | 
			
		||||
        """ Read and interpret the configuration data defined by the target The
 | 
			
		||||
        target can override any configuration parameter, as well as define its
 | 
			
		||||
        own configuration data
 | 
			
		||||
 | 
			
		||||
        params: the dictionary with configuration parameters found so far (in
 | 
			
		||||
                the target and in libraries)
 | 
			
		||||
        macros: the list of macros defined in the configuration
 | 
			
		||||
        """
 | 
			
		||||
        app_cfg = self.app_config_data
 | 
			
		||||
        # The application can have a "config_parameters" and a
 | 
			
		||||
        # "target_config_overrides" section just like a library
 | 
			
		||||
        self._process_config_and_overrides(app_cfg, params, "app",
 | 
			
		||||
                                           "application")
 | 
			
		||||
        # The application can also defined macros
 | 
			
		||||
        _process_macros(app_cfg.get("macros", []), macros, "app",
 | 
			
		||||
                        "application")
 | 
			
		||||
 | 
			
		||||
    # Return the configuration data in two parts:
 | 
			
		||||
    #   - params: a dictionary with (name, ConfigParam) entries
 | 
			
		||||
    #   - macros: the list of macros defined with "macros" in libraries and in the application (as ConfigMacro instances)
 | 
			
		||||
    def get_config_data(self):
 | 
			
		||||
        """ Return the configuration data in two parts:
 | 
			
		||||
          - params: a dictionary with (name, ConfigParam) entries
 | 
			
		||||
          - macros: the list of macros defined with "macros" in libraries and
 | 
			
		||||
                    in the application (as ConfigMacro instances)
 | 
			
		||||
        """
 | 
			
		||||
        all_params = self.get_target_config_data()
 | 
			
		||||
        lib_params, macros = self.get_lib_config_data()
 | 
			
		||||
        all_params.update(lib_params)
 | 
			
		||||
        self.get_app_config_data(all_params, macros)
 | 
			
		||||
        return all_params, macros
 | 
			
		||||
 | 
			
		||||
    # Helper: verify if there are any required parameters without a value in 'params'
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def _check_required_parameters(params):
 | 
			
		||||
        for p in params.values():
 | 
			
		||||
            if p.required and (p.value is None):
 | 
			
		||||
                raise ConfigException("Required parameter '%s' defined by '%s' doesn't have a value" % (p.name, p.defined_by))
 | 
			
		||||
        """verify if there are any required parameters without a value in
 | 
			
		||||
        'params'
 | 
			
		||||
        """
 | 
			
		||||
        for param in params.values():
 | 
			
		||||
            if param.required and (param.value is None):
 | 
			
		||||
                raise ConfigException("Required parameter '" + param.name +
 | 
			
		||||
                                      "' defined by '" + param.defined_by +
 | 
			
		||||
                                      "' doesn't have a value")
 | 
			
		||||
 | 
			
		||||
    # Return the macro definitions generated for a dictionary of configuration parameters
 | 
			
		||||
    # params: a dictionary of (name, ConfigParameters instance) mappings
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def parameters_to_macros(params):
 | 
			
		||||
        return ['%s=%s' % (m.macro_name, m.value) for m in params.values() if m.value is not None]
 | 
			
		||||
        """ Return the macro definitions generated for a dictionary of
 | 
			
		||||
        configuration parameters
 | 
			
		||||
 | 
			
		||||
        params: a dictionary of (name, ConfigParameters instance) mappings
 | 
			
		||||
        """
 | 
			
		||||
        return ['%s=%s' % (m.macro_name, m.value) for m in params.values()
 | 
			
		||||
                if m.value is not None]
 | 
			
		||||
 | 
			
		||||
    # Return the macro definitions generated for a dictionary of ConfigMacros (as returned by get_config_data)
 | 
			
		||||
    # params: a dictionary of (name, ConfigMacro instance) mappings
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def config_macros_to_macros(macros):
 | 
			
		||||
        """ Return the macro definitions generated for a dictionary of
 | 
			
		||||
        ConfigMacros (as returned by get_config_data)
 | 
			
		||||
 | 
			
		||||
        params: a dictionary of (name, ConfigMacro instance) mappings
 | 
			
		||||
        """
 | 
			
		||||
        return [m.name for m in macros.values()]
 | 
			
		||||
 | 
			
		||||
    # Return the configuration data converted to a list of C macros
 | 
			
		||||
    # config - configuration data as (ConfigParam instances, ConfigMacro instances) tuple
 | 
			
		||||
    #          (as returned by get_config_data())
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def config_to_macros(config):
 | 
			
		||||
        """ Return the configuration data converted to a list of C macros
 | 
			
		||||
 | 
			
		||||
        config - configuration data as (ConfigParam instances, ConfigMacro
 | 
			
		||||
                 instances) tuple (as returned by get_config_data())
 | 
			
		||||
        """
 | 
			
		||||
        params, macros = config[0], config[1]
 | 
			
		||||
        Config._check_required_parameters(params)
 | 
			
		||||
        return Config.config_macros_to_macros(macros) + Config.parameters_to_macros(params)
 | 
			
		||||
        return Config.config_macros_to_macros(macros) + \
 | 
			
		||||
            Config.parameters_to_macros(params)
 | 
			
		||||
 | 
			
		||||
    # Return the configuration data converted to a list of C macros
 | 
			
		||||
    def get_config_data_macros(self):
 | 
			
		||||
        """ Return the configuration data converted to a list of C macros
 | 
			
		||||
        """
 | 
			
		||||
        return self.config_to_macros(self.get_config_data())
 | 
			
		||||
 | 
			
		||||
    # Returns any features in the configuration data
 | 
			
		||||
    def get_features(self):
 | 
			
		||||
        """ Returns any features in the configuration data
 | 
			
		||||
        """
 | 
			
		||||
        params, _ = self.get_config_data()
 | 
			
		||||
        self._check_required_parameters(params)
 | 
			
		||||
        self.cumulative_overrides['features'].update_target(Target.get_target(self.target))
 | 
			
		||||
        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:
 | 
			
		||||
                raise ConfigException("Feature '%s' is not a supported features" % feature)
 | 
			
		||||
                raise ConfigException(
 | 
			
		||||
                    "Feature '%s' is not a supported features" % feature)
 | 
			
		||||
 | 
			
		||||
        return features
 | 
			
		||||
 | 
			
		||||
    # Validate configuration settings. This either returns True or raises an exception
 | 
			
		||||
    def validate_config(self):
 | 
			
		||||
        """ Validate configuration settings. This either returns True or
 | 
			
		||||
        raises an exception
 | 
			
		||||
        """
 | 
			
		||||
        if self.config_errors:
 | 
			
		||||
            raise self.config_errors[0]
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    # Loads configuration data from resources. Also expands resources based on defined features settings
 | 
			
		||||
    def load_resources(self, resources):
 | 
			
		||||
        """ Loads configuration data from resources. Also expands resources
 | 
			
		||||
        based on defined features settings
 | 
			
		||||
        """
 | 
			
		||||
        # Update configuration files until added features creates no changes
 | 
			
		||||
        prev_features = set()
 | 
			
		||||
        while True:
 | 
			
		||||
            # Add/update the configuration with any .json files found while scanning
 | 
			
		||||
            # Add/update the configuration with any .json files found while
 | 
			
		||||
            # scanning
 | 
			
		||||
            self.add_config_files(resources.json_files)
 | 
			
		||||
 | 
			
		||||
            # Add features while we find new ones
 | 
			
		||||
| 
						 | 
				
			
			@ -460,52 +630,81 @@ class Config:
 | 
			
		|||
 | 
			
		||||
        return resources
 | 
			
		||||
 | 
			
		||||
    # Return the configuration data converted to the content of a C header file,
 | 
			
		||||
    # meant to be included to a C/C++ file. The content is returned as a string.
 | 
			
		||||
    # If 'fname' is given, the content is also written to the file called "fname".
 | 
			
		||||
    # WARNING: if 'fname' names an existing file, that file will be overwritten!
 | 
			
		||||
    # config - configuration data as (ConfigParam instances, ConfigMacro instances) tuple
 | 
			
		||||
    #          (as returned by get_config_data())
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def config_to_header(config, fname = None):
 | 
			
		||||
    def config_to_header(config, fname=None):
 | 
			
		||||
        """ Return the configuration data converted to the content of a C header
 | 
			
		||||
        file, meant to be included to a C/C++ file. The content is returned as a
 | 
			
		||||
        string. If 'fname' is given, the content is also written to the file
 | 
			
		||||
        called "fname".
 | 
			
		||||
        WARNING: if 'fname' names an existing file, that file will be
 | 
			
		||||
        overwritten!
 | 
			
		||||
 | 
			
		||||
        config - configuration data as (ConfigParam instances, ConfigMacro
 | 
			
		||||
                 instances) tuple (as returned by get_config_data())
 | 
			
		||||
        """
 | 
			
		||||
        params, macros = config[0], config[1]
 | 
			
		||||
        Config._check_required_parameters(params)
 | 
			
		||||
        header_data =  "// Automatically generated configuration file.\n"
 | 
			
		||||
        header_data = "// Automatically generated configuration file.\n"
 | 
			
		||||
        header_data += "// DO NOT EDIT, content will be overwritten.\n\n"
 | 
			
		||||
        header_data += "#ifndef __MBED_CONFIG_DATA__\n"
 | 
			
		||||
        header_data += "#define __MBED_CONFIG_DATA__\n\n"
 | 
			
		||||
        # Compute maximum length of macro names for proper alignment
 | 
			
		||||
        max_param_macro_name_len = max([len(m.macro_name) for m in params.values() if m.value is not None]) if params else 0
 | 
			
		||||
        max_direct_macro_name_len = max([len(m.macro_name) for m in macros.values()]) if macros else 0
 | 
			
		||||
        max_macro_name_len = max(max_param_macro_name_len, max_direct_macro_name_len)
 | 
			
		||||
        max_param_macro_name_len = (max([len(m.macro_name) for m
 | 
			
		||||
                                         in params.values()
 | 
			
		||||
                                         if m.value is not None])
 | 
			
		||||
                                    if params else 0)
 | 
			
		||||
        max_direct_macro_name_len = (max([len(m.macro_name) for m
 | 
			
		||||
                                         in macros.values()])
 | 
			
		||||
                                     if macros else 0)
 | 
			
		||||
        max_macro_name_len = max(max_param_macro_name_len,
 | 
			
		||||
                                 max_direct_macro_name_len)
 | 
			
		||||
        # Compute maximum length of macro values for proper alignment
 | 
			
		||||
        max_param_macro_val_len = max([len(str(m.value)) for m in params.values() if m.value is not None]) if params else 0
 | 
			
		||||
        max_direct_macro_val_len = max([len(m.macro_value or "") for m in macros.values()]) if macros else 0
 | 
			
		||||
        max_macro_val_len = max(max_param_macro_val_len, max_direct_macro_val_len)
 | 
			
		||||
        max_param_macro_val_len = (max([len(str(m.value)) for m
 | 
			
		||||
                                       in params.values()
 | 
			
		||||
                                       if m.value is not None])
 | 
			
		||||
                                   if params else 0)
 | 
			
		||||
        max_direct_macro_val_len = max([len(m.macro_value or "") for m
 | 
			
		||||
                                        in macros.values()]) if macros else 0
 | 
			
		||||
        max_macro_val_len = max(max_param_macro_val_len,
 | 
			
		||||
                                max_direct_macro_val_len)
 | 
			
		||||
        # Generate config parameters first
 | 
			
		||||
        if params:
 | 
			
		||||
            header_data += "// Configuration parameters\n"
 | 
			
		||||
            for m in params.values():
 | 
			
		||||
                if m.value is not None:
 | 
			
		||||
                    header_data += "#define {0:<{1}} {2!s:<{3}} // set by {4}\n".format(m.macro_name, max_macro_name_len, m.value, max_macro_val_len, m.set_by)
 | 
			
		||||
            for macro in params.values():
 | 
			
		||||
                if macro.value is not None:
 | 
			
		||||
                    header_data += ("#define {0:<{1}} {2!s:<{3}} " +
 | 
			
		||||
                                    "// set by {4}\n")\
 | 
			
		||||
                        .format(macro.macro_name, max_macro_name_len,
 | 
			
		||||
                                macro.value, max_macro_val_len, macro.set_by)
 | 
			
		||||
        # Then macros
 | 
			
		||||
        if macros:
 | 
			
		||||
            header_data += "// Macros\n"
 | 
			
		||||
            for m in macros.values():
 | 
			
		||||
                if m.macro_value:
 | 
			
		||||
                    header_data += "#define {0:<{1}} {2!s:<{3}} // defined by {4}\n".format(m.macro_name, max_macro_name_len, m.macro_value, max_macro_val_len, m.defined_by)
 | 
			
		||||
            for macro in macros.values():
 | 
			
		||||
                if macro.macro_value:
 | 
			
		||||
                    header_data += ("#define {0:<{1}} {2!s:<{3}}" +
 | 
			
		||||
                                    " // defined by {4}\n")\
 | 
			
		||||
                        .format(m.macro_name, max_macro_name_len, m.macro_value,
 | 
			
		||||
                                max_macro_val_len, m.defined_by)
 | 
			
		||||
                else:
 | 
			
		||||
                    header_data += "#define {0:<{1}} // defined by {2}\n".format(m.macro_name, max_macro_name_len + max_macro_val_len + 1, m.defined_by)
 | 
			
		||||
                    header_data += ("#define {0:<{1}}" +
 | 
			
		||||
                                    " // defined by {2}\n")\
 | 
			
		||||
                        .format(m.macro_name,
 | 
			
		||||
                                max_macro_name_len + max_macro_val_len + 1,
 | 
			
		||||
                                m.defined_by)
 | 
			
		||||
        header_data += "\n#endif\n"
 | 
			
		||||
        # If fname is given, write "header_data" to it
 | 
			
		||||
        if fname:
 | 
			
		||||
            with open(fname, "wt") as f:
 | 
			
		||||
                f.write(header_data)
 | 
			
		||||
            with open(fname, "w+") as file_desc:
 | 
			
		||||
                file_desc.write(header_data)
 | 
			
		||||
        return header_data
 | 
			
		||||
 | 
			
		||||
    # Return the configuration data converted to the content of a C header file,
 | 
			
		||||
    # meant to be included to a C/C++ file. The content is returned as a string.
 | 
			
		||||
    # If 'fname' is given, the content is also written to the file called "fname".
 | 
			
		||||
    # WARNING: if 'fname' names an existing file, that file will be overwritten!
 | 
			
		||||
    def get_config_data_header(self, fname = None):
 | 
			
		||||
    def get_config_data_header(self, fname=None):
 | 
			
		||||
        """ Return the configuration data converted to the content of a C
 | 
			
		||||
        header file, meant to be included to a C/C++ file. The content is
 | 
			
		||||
        returned as a string. If 'fname' is given, the content is also written
 | 
			
		||||
        to the file called "fname".
 | 
			
		||||
 | 
			
		||||
        WARNING: if 'fname' names an existing file, that file will be
 | 
			
		||||
                 overwritten!
 | 
			
		||||
        """
 | 
			
		||||
        return self.config_to_header(self.get_config_data(), fname)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue