# -*- coding: utf-8 -*- """ Handles the business logic for the repository transformation workflow. This handler validates user input, confirms destructive actions, and orchestrates the asynchronous execution of the transformation process, which includes history rewriting, repository renaming, and updating the local Gitea remote. """ from typing import TYPE_CHECKING, Dict, Any, Optional import os from gitutility.async_tasks import async_workers from gitutility.logging_setup import log_handler from gitutility.commands.git_commands import GitCommandError # Forward reference for type hinting to avoid circular import if TYPE_CHECKING: from ..app import GitSvnSyncApp class TransformationHandler: """ Manages the logic for the repository transformation feature. """ def __init__(self, app: "GitSvnSyncApp"): """ Initializes the TransformationHandler. Args: app: The main application instance. """ self.app = app self.main_frame = app.main_frame self.git_commands = app.git_commands self.config_manager = app.config_manager log_handler.log_debug("TransformationHandler initialized.", func_name="__init__") def start_transformation(self, target_details: Dict[str, str]) -> None: """ Validates inputs and starts the asynchronous repository transformation process. Args: target_details: A dictionary containing 'repo_name', 'author_name', and 'author_email' for the target identity. """ func_name = "start_transformation" log_handler.log_info(f"--- Action Triggered: Start Repository Transformation ---", func_name=func_name) # --- 1. Validazione degli Input e dello Stato del Sistema --- # Valida i dettagli forniti dall'utente target_repo_name = target_details.get("repo_name") target_author_name = target_details.get("author_name") target_author_email = target_details.get("author_email") if not all([target_repo_name, target_author_name, target_author_email]): self.main_frame.show_error("Input Error", "All target identity fields are required.") log_handler.log_error("Validation failed: Missing target identity details.", func_name=func_name) return # Valida il repository sorgente (quello del profilo corrente) source_repo_path = self.app._get_and_validate_svn_path("Repository Transformation") if not source_repo_path or not self.app._is_repo_ready(source_repo_path): self.main_frame.show_error("Repository Error", "The current profile's repository is not valid or not ready.") log_handler.log_error("Validation failed: Source repository not valid.", func_name=func_name) return source_repo_basename = os.path.basename(source_repo_path) # If the target name equals the source, allow the user to proceed with # an author-only transformation (no folder/profile rename) or cancel. rename_repo = True if source_repo_basename == target_repo_name: # Ask the user whether to continue with author-only rewrite proceed_msg = ( "The target repository name is the SAME as the source repository.\n\n" "You can either:\n" " - Cancel and change the target repository name, or\n" " - Proceed with an AUTHOR-ONLY transformation (this will rewrite commit authors/emails but WILL NOT rename the repository folder nor create a new profile).\n\n" "Do you want to proceed with AUTHOR-ONLY transformation?" ) if not self.main_frame.ask_yes_no("Same Repository Name", proceed_msg): self.main_frame.update_status_bar("Transformation cancelled.") log_handler.log_info("User cancelled the transformation due to same repository name.", func_name=func_name) return rename_repo = False # Controlla se il repository ha modifiche non committate try: if self.git_commands.git_status_has_changes(source_repo_path): self.main_frame.show_warning( "Action Blocked", "The repository has uncommitted changes. Please commit or stash them before starting a transformation." ) log_handler.log_warning("Validation failed: Repository is not clean.", func_name=func_name) return except GitCommandError as e: self.main_frame.show_error("Git Error", f"Failed to check repository status:\n{e}") log_handler.log_error(f"Validation failed: Could not get repo status. {e}", func_name=func_name) return # --- 2. Dialogo di Conferma Finale --- confirmation_message = ( f"You are about to perform a PERMANENT and DESTRUCTIVE transformation.\n\n" f"1. Source Repository: '{source_repo_basename}'\n" f" at path: '{source_repo_path}'\n\n" f"2. All commits will be rewritten with author:\n" f" '{target_author_name} <{target_author_email}>'\n\n" f"3. The local repository folder will be RENAMED to:\n" f" '{target_repo_name}'\n\n" f"4. A new profile '{target_repo_name}' will be created in this tool.\n\n" f"This action CANNOT be undone. It is strongly advised to have a backup.\n\n" f"Are you absolutely sure you want to proceed?" ) if not self.main_frame.ask_yes_no("Confirm Destructive Transformation", confirmation_message): self.main_frame.update_status_bar("Transformation cancelled.") log_handler.log_info("User cancelled the transformation.", func_name=func_name) return # --- 3. Avvio del Worker Asincrono --- log_handler.log_info("User confirmed. Starting asynchronous transformation worker.", func_name=func_name) # Prepara gli argomenti per il worker args = ( # Passeremo le istanze necessarie, non solo i valori, per dare flessibilità al worker self.git_commands, self.config_manager, source_repo_path, target_repo_name, target_author_name, target_author_email, rename_repo, ) self.app._start_async_operation( worker_func=async_workers.run_repository_transformation_async, # Creeremo questo worker tra poco args_tuple=args, context_dict={ "context": "repository_transformation", "status_msg": f"Transforming '{source_repo_basename}' to '{target_repo_name}'...", }, )