|
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 |