|
23 | 23 | """ |
24 | 24 | import sys |
25 | 25 | import os |
26 | | -from threading import Lock |
| 26 | +from threading import Thread, Lock |
| 27 | +from queue import Queue |
27 | 28 |
|
28 | 29 | import json |
29 | 30 | import yaml |
30 | 31 |
|
31 | 32 | from cli import options |
32 | 33 | from sonar import exceptions, errcodes, utilities |
| 34 | +from sonar.util import types |
33 | 35 | import sonar.logging as log |
34 | 36 | from sonar import platform, rules, qualityprofiles, qualitygates, users, groups |
35 | 37 | from sonar import projects, portfolios, applications |
@@ -219,44 +221,84 @@ def __export_config_sync(endpoint: platform.Platform, what: list[str], **kwargs) |
219 | 221 | log.info("Synchronous export of configuration from %s completed", kwargs["url"]) |
220 | 222 |
|
221 | 223 |
|
| 224 | +def write_objects(queue: Queue, fd, object_type: str, export_settings: types.ConfigSettings) -> None: |
| 225 | + """ |
| 226 | + Thread to write projects in the JSON file |
| 227 | + """ |
| 228 | + done = False |
| 229 | + prefix = "" |
| 230 | + log.info("Waiting %s to write...", object_type) |
| 231 | + print(f'"{object_type}": ' + "{", file=fd) |
| 232 | + while not done: |
| 233 | + obj_json = queue.get() |
| 234 | + done = obj_json is None |
| 235 | + if not done: |
| 236 | + if export_settings.get("INLINE_LISTS", True): |
| 237 | + obj_json = utilities.inline_lists(obj_json, exceptions=("conditions",)) |
| 238 | + if object_type in ("projects", "applications", "portfolios", "users"): |
| 239 | + if object_type == "users": |
| 240 | + key = obj_json.pop("login", None) |
| 241 | + else: |
| 242 | + key = obj_json.pop("key", None) |
| 243 | + log.debug("Writing %s key '%s'", object_type[:-1], key) |
| 244 | + print(f'{prefix}"{key}": {utilities.json_dump(obj_json)}', end="", file=fd) |
| 245 | + else: |
| 246 | + log.debug("Writing %s", object_type) |
| 247 | + print(f"{prefix}{utilities.json_dump(obj_json)[2:-1]}", end="", file=fd) |
| 248 | + prefix = ",\n" |
| 249 | + queue.task_done() |
| 250 | + print("\n}", file=fd, end="") |
| 251 | + log.info("Writing %s complete", object_type) |
| 252 | + |
| 253 | + |
222 | 254 | def __export_config_async(endpoint: platform.Platform, what: list[str], **kwargs) -> None: |
223 | 255 | """Exports a platform configuration in a JSON file""" |
| 256 | + file = kwargs[options.REPORT_FILE] |
224 | 257 | export_settings = { |
225 | 258 | "INLINE_LISTS": not kwargs["dontInlineLists"], |
226 | | - "EXPORT_DEFAULTS": kwargs["exportDefaults"], |
227 | | - "FULL_EXPORT": kwargs["fullExport"], |
| 259 | + "EXPORT_DEFAULTS": True, |
| 260 | + # "FULL_EXPORT": kwargs["fullExport"], |
| 261 | + "FULL_EXPORT": False, |
| 262 | + "MODE": "MIGRATION", |
228 | 263 | "THREADS": kwargs[options.NBR_THREADS], |
229 | | - options.REPORT_FILE: kwargs[options.REPORT_FILE], |
230 | | - "WRITE_CALLBACK": write_project, |
| 264 | + "SKIP_ISSUES": True, |
231 | 265 | } |
232 | | - log.info("Exporting configuration from %s (asynchronously)", kwargs[options.URL]) |
| 266 | + if "projects" in what and kwargs[options.KEYS]: |
| 267 | + non_existing_projects = [key for key in kwargs[options.KEYS] if not projects.exists(key, endpoint)] |
| 268 | + if len(non_existing_projects) > 0: |
| 269 | + utilities.exit_fatal(f"Project key(s) '{','.join(non_existing_projects)}' do(es) not exist", errcodes.NO_SUCH_KEY) |
| 270 | + |
| 271 | + log.info("Exporting configuration from %s", kwargs[options.URL]) |
233 | 272 | key_list = kwargs[options.KEYS] |
234 | 273 | sq_settings = {__JSON_KEY_PLATFORM: endpoint.basics()} |
235 | | - for what_item, call_data in _EXPORT_CALLS.items(): |
236 | | - if what_item not in what or what_item == options.WHAT_PROJECTS: |
237 | | - continue |
238 | | - ndx, func = call_data |
239 | | - try: |
240 | | - sq_settings[ndx] = utilities.remove_empties(func(endpoint, export_settings=export_settings, key_list=key_list)) |
241 | | - __write_export(sq_settings, kwargs[options.REPORT_FILE], kwargs[options.FORMAT]) |
242 | | - except exceptions.UnsupportedOperation as e: |
243 | | - log.warning(e.message) |
244 | | - except exceptions.ObjectNotFound as e: |
245 | | - log.error(e.message) |
246 | | - if not kwargs["dontInlineLists"]: |
247 | | - sq_settings = utilities.inline_lists(sq_settings, exceptions=("conditions",)) |
248 | | - __write_export(sq_settings, kwargs[options.REPORT_FILE], kwargs[options.FORMAT]) |
249 | | - |
250 | | - __remove_chars_at_end(kwargs[options.REPORT_FILE], 3) |
251 | | - __add_project_header(kwargs[options.REPORT_FILE]) |
252 | | - projects.export(endpoint, export_settings=export_settings, key_list=None) |
253 | | - __add_project_footer(kwargs[options.REPORT_FILE]) |
254 | | - log.info("Asynchronous export of configuration from %s completed", kwargs["url"]) |
| 274 | + is_first = True |
| 275 | + q = Queue(maxsize=0) |
| 276 | + with utilities.open_file(file, mode="w") as fd: |
| 277 | + print("{", file=fd) |
| 278 | + for what_item, call_data in _EXPORT_CALLS.items(): |
| 279 | + if what_item not in what: |
| 280 | + continue |
| 281 | + ndx, func = call_data |
| 282 | + try: |
| 283 | + if not is_first: |
| 284 | + print(",", file=fd) |
| 285 | + is_first = False |
| 286 | + worker = Thread(target=write_objects, args=(q, fd, ndx, export_settings)) |
| 287 | + worker.daemon = True |
| 288 | + worker.name = f"Write{ndx[:1].upper()}{ndx[1:10]}" |
| 289 | + worker.start() |
| 290 | + sq_settings[ndx] = func(endpoint, export_settings=export_settings, key_list=key_list, write_q=q) |
| 291 | + q.join() |
| 292 | + except exceptions.UnsupportedOperation as e: |
| 293 | + log.warning(e.message) |
| 294 | + sq_settings = utilities.remove_empties(sq_settings) |
| 295 | + print("\n}", file=fd) |
| 296 | + log.info("Exporting migration data from %s completed", kwargs["url"]) |
255 | 297 |
|
256 | 298 |
|
257 | 299 | def __export_config(endpoint: platform.Platform, what: list[str], **kwargs) -> None: |
258 | 300 | """Exports the configuration of the SonarQube platform""" |
259 | | - if kwargs[options.KEYS] or options.WHAT_PROJECTS not in what or kwargs[options.FORMAT] != "json" or not kwargs[options.REPORT_FILE]: |
| 301 | + if kwargs[options.KEYS] or options.WHAT_PROJECTS not in what or kwargs[options.FORMAT] != "json": |
260 | 302 | __export_config_sync(endpoint=endpoint, what=what, **kwargs) |
261 | 303 | else: |
262 | 304 | __export_config_async(endpoint=endpoint, what=what, **kwargs) |
|
0 commit comments