configurationengine/source/cone/action/configroot2flat.py
changeset 3 e7e0ae78773e
child 4 0951727b8815
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/configurationengine/source/cone/action/configroot2flat.py	Tue Aug 10 14:29:28 2010 +0300
@@ -0,0 +1,169 @@
+#
+# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+# All rights reserved.
+# This component and the accompanying materials are made available
+# under the terms of "Eclipse Public License v1.0"
+# which accompanies this distribution, and is available
+# at the URL "http://www.eclipse.org/legal/epl-v10.html".
+#
+# Initial Contributors:
+# Nokia Corporation - initial contribution.
+#
+# Contributors:
+#
+# Description:
+#
+#!/usr/bin/env python
+## 
+# @author Teemu Rytkonen
+
+import os, re, fnmatch, logging
+from cone.public import api, utils, exceptions
+from cone.confml import model as confml_model
+
+logger = logging.getLogger('cone')
+
+def get_config_list_from_project(project, configs, config_wildcards, config_regexes):
+    """
+    Return a list of configuration root names based on the given parameters.
+    @param project: The project from which to get the configuration list.
+    @param configs: List of configuration names to add. All of these should exist
+        in the project, or a ConfigurationNotFoundError is raised.
+    @param config_wildcards: List of wildcard patterns for including configurations.
+    @param config_regexs: List of regular expression patters for including configurations.
+    @return: A distinct list of configuration names matched by the given parameters. The
+        list contains matched configurations in the following order:
+            1. Configurations specified in configs
+            2. Configurations matched by wildcard patterns
+            3. Configurations matched by regular expressions
+        If a configuration is matched by more than one of these, the first match determines
+        its placement in the list.
+    @raise Exception: A configuration specified in configs is not
+        actually found in the project.
+    """
+    config_list = []
+    
+    # Handle configurations specified with --configuration first
+    for config in configs:
+        if not project.get_storage().is_resource(utils.resourceref.norm(config)):
+            raise Exception("No such configuration: %s" % config)
+        if config not in config_list:
+            config_list.append(config)
+    
+    # Then handle wildcards
+    #print "wilds %s" % config_wildcards
+    if config_wildcards:
+        for path in project.get_storage().list_resources('.', recurse=True):
+            for wildcard in config_wildcards:
+                if fnmatch.fnmatch(path, wildcard):
+                    if path not in config_list:
+                        config_list.append(path)
+    
+    # Lastly handle regexes
+    #print "regexes %s" % config_regexes
+    if config_regexes:
+        for path in project.get_storage().list_resources('.', recurse=True):
+            for pattern in config_regexes:
+                if re.search(pattern, path) is not None:
+                    if path not in config_list:
+                        config_list.append(path)
+    
+    return config_list
+
+def get_flat_includes(config):
+    """
+    get a flat list of configuration in which each include of configuration root is expanded.
+    The mechanism assumes all includes that end with /root.confml to be layer includes that 
+    are layers that are not expanded
+    @param config: the configuration object to process. 
+    """
+    includes = []
+    for include in config.list_configurations():
+        if include.endswith('/root.confml'):
+            includes.append(utils.resourceref.remove_begin_slash(include))
+        else:
+            subconfig = config.get_configuration(include)
+            includes += get_flat_includes(subconfig)
+    return includes
+
+def get_nested_meta(config, recursion_depth=-1):
+    """
+    Get the nested meta data for the given configuration constructed from metadata of all sub configuration meta.
+    @param config: the configuration object to fetch the metadata for
+    @param recursion_depth: the depth of the recursive nested metadata calls. default value -1 will go through 
+    all configurations.
+    @return: a ConfmlMeta object 
+    """
+    
+    meta = confml_model.ConfmlMeta()
+    if recursion_depth != 0:
+        # First recurse through all subconfigurations to get their meta     
+        for subconfig_name in config.list_configurations():
+            subconfig = config.get_configuration(subconfig_name)
+            submeta = get_nested_meta(subconfig, recursion_depth-1)
+            
+            meta.update( submeta )
+    
+    # lastly, update the meta data of the root configuration
+    if config.meta:
+        meta.update(config.meta)
+    return meta
+
+
+class Configroot2FlatFailed(exceptions.ConeException):
+    pass
+
+class ConeConfigroot2FlatAction(object):
+    def __init__(self, **kwargs):
+        self.project = kwargs.get('project')
+        self.configs = kwargs.get('configs')
+        self.config_wildcards = kwargs.get('config_wildcards')
+        self.config_regexes = kwargs.get('config_regexes')
+        self._project = None
+        
+    def run(self):
+        self._project = api.Project(api.Storage.open(self.project, 'a'))
+        prj = self._project
+        
+        configs = []
+        if self.configs or self.config_wildcards or self.config_regexes:
+            configs = get_config_list_from_project(
+                project          = prj,
+                configs          = self.configs,
+                config_wildcards = self.config_wildcards,
+                config_regexes   = self.config_regexes)
+    
+        if not configs:
+            raise Configroot2FlatFailed("At least one configuration must be given!")
+        
+        print "Processing configurations %s" % configs
+        for source_config in configs:
+            target_config= os.path.basename(source_config)
+            if source_config == target_config:
+                print "Cannot flatten configuration because the source path is the same as target!"
+            config = prj.get_configuration(source_config)
+            
+            print "opened %s for flattening" % source_config
+            
+            print "Creating a new configuration root '%s' for flattening" % target_config
+            tconf = prj.create_configuration(target_config, True)
+            # add the includes
+            for config_include in get_flat_includes(config):
+                tconf.include_configuration(config_include)
+            # add the metadata with hardcoded recursion depth count
+            newmeta = get_nested_meta(config, 2)
+            tconf.meta = newmeta
+            tconf.name = config.name
+            tconf.save()
+        
+        return True
+
+    def save(self):
+        if self._project: self._project.save()
+        
+    def close(self):
+        if self._project: self._project.close()
+
+
+def get_class():
+    return ConeConfigroot2FlatAction