configurationengine/source/cone/action/configroot2flat.py
changeset 3 e7e0ae78773e
child 4 0951727b8815
equal deleted inserted replaced
2:87cfa131b535 3:e7e0ae78773e
       
     1 #
       
     2 # Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 # All rights reserved.
       
     4 # This component and the accompanying materials are made available
       
     5 # under the terms of "Eclipse Public License v1.0"
       
     6 # which accompanies this distribution, and is available
       
     7 # at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 #
       
     9 # Initial Contributors:
       
    10 # Nokia Corporation - initial contribution.
       
    11 #
       
    12 # Contributors:
       
    13 #
       
    14 # Description:
       
    15 #
       
    16 #!/usr/bin/env python
       
    17 ## 
       
    18 # @author Teemu Rytkonen
       
    19 
       
    20 import os, re, fnmatch, logging
       
    21 from cone.public import api, utils, exceptions
       
    22 from cone.confml import model as confml_model
       
    23 
       
    24 logger = logging.getLogger('cone')
       
    25 
       
    26 def get_config_list_from_project(project, configs, config_wildcards, config_regexes):
       
    27     """
       
    28     Return a list of configuration root names based on the given parameters.
       
    29     @param project: The project from which to get the configuration list.
       
    30     @param configs: List of configuration names to add. All of these should exist
       
    31         in the project, or a ConfigurationNotFoundError is raised.
       
    32     @param config_wildcards: List of wildcard patterns for including configurations.
       
    33     @param config_regexs: List of regular expression patters for including configurations.
       
    34     @return: A distinct list of configuration names matched by the given parameters. The
       
    35         list contains matched configurations in the following order:
       
    36             1. Configurations specified in configs
       
    37             2. Configurations matched by wildcard patterns
       
    38             3. Configurations matched by regular expressions
       
    39         If a configuration is matched by more than one of these, the first match determines
       
    40         its placement in the list.
       
    41     @raise Exception: A configuration specified in configs is not
       
    42         actually found in the project.
       
    43     """
       
    44     config_list = []
       
    45     
       
    46     # Handle configurations specified with --configuration first
       
    47     for config in configs:
       
    48         if not project.get_storage().is_resource(utils.resourceref.norm(config)):
       
    49             raise Exception("No such configuration: %s" % config)
       
    50         if config not in config_list:
       
    51             config_list.append(config)
       
    52     
       
    53     # Then handle wildcards
       
    54     #print "wilds %s" % config_wildcards
       
    55     if config_wildcards:
       
    56         for path in project.get_storage().list_resources('.', recurse=True):
       
    57             for wildcard in config_wildcards:
       
    58                 if fnmatch.fnmatch(path, wildcard):
       
    59                     if path not in config_list:
       
    60                         config_list.append(path)
       
    61     
       
    62     # Lastly handle regexes
       
    63     #print "regexes %s" % config_regexes
       
    64     if config_regexes:
       
    65         for path in project.get_storage().list_resources('.', recurse=True):
       
    66             for pattern in config_regexes:
       
    67                 if re.search(pattern, path) is not None:
       
    68                     if path not in config_list:
       
    69                         config_list.append(path)
       
    70     
       
    71     return config_list
       
    72 
       
    73 def get_flat_includes(config):
       
    74     """
       
    75     get a flat list of configuration in which each include of configuration root is expanded.
       
    76     The mechanism assumes all includes that end with /root.confml to be layer includes that 
       
    77     are layers that are not expanded
       
    78     @param config: the configuration object to process. 
       
    79     """
       
    80     includes = []
       
    81     for include in config.list_configurations():
       
    82         if include.endswith('/root.confml'):
       
    83             includes.append(utils.resourceref.remove_begin_slash(include))
       
    84         else:
       
    85             subconfig = config.get_configuration(include)
       
    86             includes += get_flat_includes(subconfig)
       
    87     return includes
       
    88 
       
    89 def get_nested_meta(config, recursion_depth=-1):
       
    90     """
       
    91     Get the nested meta data for the given configuration constructed from metadata of all sub configuration meta.
       
    92     @param config: the configuration object to fetch the metadata for
       
    93     @param recursion_depth: the depth of the recursive nested metadata calls. default value -1 will go through 
       
    94     all configurations.
       
    95     @return: a ConfmlMeta object 
       
    96     """
       
    97     
       
    98     meta = confml_model.ConfmlMeta()
       
    99     if recursion_depth != 0:
       
   100         # First recurse through all subconfigurations to get their meta     
       
   101         for subconfig_name in config.list_configurations():
       
   102             subconfig = config.get_configuration(subconfig_name)
       
   103             submeta = get_nested_meta(subconfig, recursion_depth-1)
       
   104             
       
   105             meta.update( submeta )
       
   106     
       
   107     # lastly, update the meta data of the root configuration
       
   108     if config.meta:
       
   109         meta.update(config.meta)
       
   110     return meta
       
   111 
       
   112 
       
   113 class Configroot2FlatFailed(exceptions.ConeException):
       
   114     pass
       
   115 
       
   116 class ConeConfigroot2FlatAction(object):
       
   117     def __init__(self, **kwargs):
       
   118         self.project = kwargs.get('project')
       
   119         self.configs = kwargs.get('configs')
       
   120         self.config_wildcards = kwargs.get('config_wildcards')
       
   121         self.config_regexes = kwargs.get('config_regexes')
       
   122         self._project = None
       
   123         
       
   124     def run(self):
       
   125         self._project = api.Project(api.Storage.open(self.project, 'a'))
       
   126         prj = self._project
       
   127         
       
   128         configs = []
       
   129         if self.configs or self.config_wildcards or self.config_regexes:
       
   130             configs = get_config_list_from_project(
       
   131                 project          = prj,
       
   132                 configs          = self.configs,
       
   133                 config_wildcards = self.config_wildcards,
       
   134                 config_regexes   = self.config_regexes)
       
   135     
       
   136         if not configs:
       
   137             raise Configroot2FlatFailed("At least one configuration must be given!")
       
   138         
       
   139         print "Processing configurations %s" % configs
       
   140         for source_config in configs:
       
   141             target_config= os.path.basename(source_config)
       
   142             if source_config == target_config:
       
   143                 print "Cannot flatten configuration because the source path is the same as target!"
       
   144             config = prj.get_configuration(source_config)
       
   145             
       
   146             print "opened %s for flattening" % source_config
       
   147             
       
   148             print "Creating a new configuration root '%s' for flattening" % target_config
       
   149             tconf = prj.create_configuration(target_config, True)
       
   150             # add the includes
       
   151             for config_include in get_flat_includes(config):
       
   152                 tconf.include_configuration(config_include)
       
   153             # add the metadata with hardcoded recursion depth count
       
   154             newmeta = get_nested_meta(config, 2)
       
   155             tconf.meta = newmeta
       
   156             tconf.name = config.name
       
   157             tconf.save()
       
   158         
       
   159         return True
       
   160 
       
   161     def save(self):
       
   162         if self._project: self._project.save()
       
   163         
       
   164     def close(self):
       
   165         if self._project: self._project.close()
       
   166 
       
   167 
       
   168 def get_class():
       
   169     return ConeConfigroot2FlatAction