|
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 |
|
17 import os |
|
18 import fnmatch |
|
19 import logging |
|
20 from optparse import OptionParser, OptionGroup |
|
21 |
|
22 import cone_common |
|
23 from cone.public import api, plugin, utils, exceptions |
|
24 |
|
25 |
|
26 VERSION = '1.0' |
|
27 DEFAULT_EXT = '.cpf' |
|
28 |
|
29 logger = logging.getLogger('cone') |
|
30 DATA_NAME = 'confml/data.confml' |
|
31 |
|
32 def main(): |
|
33 parser = OptionParser(version="%%prog %s" % VERSION) |
|
34 |
|
35 parser.add_options(cone_common.COMMON_OPTIONS) |
|
36 |
|
37 parser.add_option("-c", "--configuration", |
|
38 dest="configs", |
|
39 action="append", |
|
40 help="Defines the name of the configuration for the action, can be "\ |
|
41 "specified multiple times to include multiple configurations.", |
|
42 metavar="CONFIG", |
|
43 default=[]) |
|
44 |
|
45 parser.add_option("--config-wildcard", |
|
46 action="append", |
|
47 dest="config_wildcards", |
|
48 help="Wildcard pattern for including configurations, e.g. "\ |
|
49 "product_langpack_*_root.confml", |
|
50 metavar="WILDCARD", |
|
51 default=[]) |
|
52 |
|
53 parser.add_option("--config-regex", |
|
54 action="append", |
|
55 dest="config_regexes", |
|
56 help="Regular expression for including configurations, e.g. "\ |
|
57 "product_langpack_\\d{2}_root.confml", |
|
58 metavar="REGEX", |
|
59 default=[]) |
|
60 |
|
61 parser.add_option("-p", "--project", |
|
62 dest="project", |
|
63 help="defines the location of current project. Default is the "\ |
|
64 "current working directory.",\ |
|
65 default=".", |
|
66 metavar="STORAGE") |
|
67 |
|
68 group = OptionGroup(parser, 'Export options', |
|
69 'The export action is intended for exporting configurations '\ |
|
70 'from one project (storage) to another. A project can be a '\ |
|
71 'folder, a CPF or ZIP file, or a Carbon web storage URL. '\ |
|
72 # An ugly way to make newlines, someone should look into |
|
73 # sub-classing optparse.HelpFormatter... |
|
74 ' '\ |
|
75 'Two different ways of exporting are supported: '\ |
|
76 ' '\ |
|
77 '1. Exporting multiple configurations into one new project using --remote '\ |
|
78 ' '\ |
|
79 '2. Exporting configurations into a number of new projects using --export-dir') |
|
80 |
|
81 group.add_option("-r", "--remote", |
|
82 dest="remote", |
|
83 help="Defines the location of remote storage. All configurations included using "\ |
|
84 "--configuration, --config-wildcard and --config-regex are exported into "\ |
|
85 "the storage. If the remote storage location is not given, the default "\ |
|
86 "location is determined based on the first included source configuration name. "\ |
|
87 "E.g. 'example.confml' would be exported into 'example.cpf'", |
|
88 metavar="STORAGE") |
|
89 |
|
90 group.add_option("--export-dir", |
|
91 help="Defines the directory where each included configuration is exported "\ |
|
92 "as a new project.", |
|
93 default=None) |
|
94 |
|
95 group.add_option("--export-format", |
|
96 help="Defines the format into which projects are exported when using "\ |
|
97 "--export-dir. Possible values are 'cpf' (the default) and 'dir'.", |
|
98 default=None) |
|
99 |
|
100 group.add_option("-a","--add", |
|
101 dest="added", |
|
102 action="append", |
|
103 type="string", |
|
104 help="Adds a configuration layer to the given configuration as last element. "\ |
|
105 "The add operation can be used several times in a single command and it "\ |
|
106 "can create even an empty layer. "\ |
|
107 "Example --add foo/root.confml --add bar/root-confml.", |
|
108 metavar="CONFIG", |
|
109 default=None) |
|
110 |
|
111 group.add_option("--exclude-folders", |
|
112 dest="exclude_empty_folders", |
|
113 action="store_true", |
|
114 help="Excludes empty folders from export", |
|
115 default=False) |
|
116 |
|
117 parser.add_option_group(group) |
|
118 (options, args) = parser.parse_args() |
|
119 |
|
120 cone_common.handle_common_options(options) |
|
121 |
|
122 # Check options |
|
123 if options.export_format and options.export_dir is None: |
|
124 parser.error("--export-format can only be used in conjunction with --export-dir") |
|
125 if options.export_dir and options.remote: |
|
126 parser.error("--export-dir and --remote cannot be used at the same time") |
|
127 if options.export_format and options.export_format.lower() not in ('dir', 'cpf'): |
|
128 parser.error("Invalid export format '%s'" % options.export_format) |
|
129 if options.export_dir and not (options.configs or options.config_wildcards or options.config_regexes): |
|
130 parser.error("Use of --export-dir requires at least one configuration to be specified") |
|
131 if options.export_dir and os.path.isfile(options.export_dir): |
|
132 parser.error("Given export directory '%s' is a file") |
|
133 |
|
134 # Open the project and find out the active configuration |
|
135 project = api.Project(api.Storage.open(options.project, "r")) |
|
136 try: |
|
137 active_root = project.get_storage().get_active_configuration() |
|
138 except AttributeError: |
|
139 active_root = None |
|
140 |
|
141 # Collect the list of configurations specified from the command line |
|
142 config_list = [] |
|
143 if options.configs or options.config_wildcards or options.config_regexes: |
|
144 try: |
|
145 config_list = cone_common.get_config_list_from_project( |
|
146 project = project, |
|
147 configs = options.configs, |
|
148 config_wildcards = options.config_wildcards, |
|
149 config_regexes = options.config_regexes) |
|
150 except cone_common.ConfigurationNotFoundError, e: |
|
151 parser.error(str(e)) |
|
152 |
|
153 # Use the active configuration if no configurations are specifically given |
|
154 if len(config_list) == 0: |
|
155 if active_root is None: |
|
156 parser.error("No configurations given and the project does not have an active root") |
|
157 else: |
|
158 logger.info('No configurations given! Using active root configuration %s' % active_root) |
|
159 config_list = [active_root] |
|
160 |
|
161 # Perform the export |
|
162 if options.export_dir: |
|
163 _export_to_dir(project = project, |
|
164 export_dir = options.export_dir, |
|
165 export_format = options.export_format or 'cpf', |
|
166 configs = config_list, |
|
167 added_layers = options.added, |
|
168 empty_folders = not options.exclude_empty_folders) |
|
169 else: |
|
170 _export_to_storage(project = project, |
|
171 remote_project_location = options.remote, |
|
172 configs = config_list, |
|
173 added_layers = options.added, |
|
174 empty_folders = not options.exclude_empty_folders) |
|
175 |
|
176 |
|
177 def _export_to_storage(project, remote_project_location, configs, added_layers, empty_folders): |
|
178 assert len(configs) > 0 |
|
179 |
|
180 # If the remote storage is not given, determine it automatically based |
|
181 # on the first specified configuration name |
|
182 if not remote_project_location: |
|
183 remotename, ext = os.path.splitext(os.path.basename(configs[0])) |
|
184 remotename += DEFAULT_EXT |
|
185 logger.info('No remote storage given! Using source configuration name %s' % remotename) |
|
186 remote_project_location = remotename |
|
187 |
|
188 remote_project = api.Project(api.Storage.open(remote_project_location, "w")) |
|
189 for config_path in configs: |
|
190 config = project.get_configuration(config_path) |
|
191 project.export_configuration(config, |
|
192 remote_project.storage, |
|
193 empty_folders = empty_folders) |
|
194 print "Export %s to %s done!" % (config_path, remote_project_location) |
|
195 |
|
196 # Setting first as active configuration if there are more than one configuration defined. |
|
197 configs = remote_project.list_configurations() |
|
198 if len(configs): |
|
199 try: |
|
200 remote_project.get_storage().set_active_configuration(configs[0]) |
|
201 except AttributeError: |
|
202 pass |
|
203 |
|
204 remote_project.save() |
|
205 remote_project.close() |
|
206 |
|
207 _add_layers(project, remote_project_location, added_layers, empty_folders) |
|
208 |
|
209 def _add_layers(source_project, remote_project_location, added_configs, empty_folders): |
|
210 """ |
|
211 Add new configuration layers from source_project into |
|
212 """ |
|
213 if not added_configs: |
|
214 return |
|
215 |
|
216 target_project = api.Project(api.Storage.open(remote_project_location, "a")) |
|
217 for target_config_name in target_project.list_configurations(): |
|
218 target_config = target_project.get_configuration(target_config_name) |
|
219 |
|
220 for added_config_name in added_configs: |
|
221 # Add layers only once |
|
222 if not target_project.storage.is_resource(added_config_name): |
|
223 logger.info('Adding configuration %s' % added_config_name) |
|
224 |
|
225 if source_project.storage.is_resource(added_config_name): |
|
226 # The configuration exists in the source project, export it from there |
|
227 existing_config = source_project.get_configuration(added_config_name) |
|
228 source_project.export_configuration(existing_config, |
|
229 target_project.storage, |
|
230 empty_folders = empty_folders) |
|
231 else: |
|
232 # The given configuration does not exist in the source project, |
|
233 # create a new empty layer |
|
234 logger.info("Creating new layer %s." % added_config_name) |
|
235 new_config = target_project.create_configuration(added_config_name) |
|
236 new_config.create_configuration(DATA_NAME) |
|
237 |
|
238 # Include the added configuration in the configuration root |
|
239 target_config.include_configuration(utils.resourceref.norm(added_config_name)) |
|
240 |
|
241 target_project.save() |
|
242 target_project.close() |
|
243 |
|
244 def _export_to_dir(project, export_dir, export_format, configs, added_layers, empty_folders): |
|
245 if not os.path.exists(export_dir): |
|
246 os.makedirs(export_dir) |
|
247 |
|
248 for config in configs: |
|
249 remote_name, _ = os.path.splitext(os.path.basename(config)) |
|
250 if export_format.lower() == 'cpf': |
|
251 remote_name += '.cpf' |
|
252 elif export_format.lower() == 'dir': |
|
253 remote_name += '/' |
|
254 |
|
255 remote_name = os.path.join(export_dir, remote_name) |
|
256 _export_to_storage(project, remote_name, [config], added_layers, empty_folders) |
|
257 |
|
258 if __name__ == "__main__": |
|
259 main() |