# --- FILE: gitsync_tool/logic/submodule_handler.py --- import os import re from typing import TYPE_CHECKING, Optional, Tuple, List, Dict, Callable from gitutility.async_tasks import async_workers from gitutility.gui.dialogs import AddSubmoduleDialog 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 SubmoduleLogicHandler: """ Handles the application logic for submodule-related actions, acting as an intermediary between the GUI callbacks and the asynchronous workers. """ def __init__(self, app: "GitSvnSyncApp"): """ Initializes the SubmoduleLogicHandler. Args: app: The main application instance. """ self.app = app self.main_frame = app.main_frame self.git_commands = app.git_commands self.submodule_handler = app.submodule_handler # The core handler def refresh_submodules(self, on_complete: Optional[Callable[[List[Dict[str, str]]], None]] = None): """ Starts an async operation to refresh the list of submodules. Args: on_complete (Optional[Callable]): A callback function to execute after the refresh is successful, passing the list of submodule data as an argument. """ func_name = "refresh_submodules" svn_path = self.app._get_and_validate_svn_path("Refresh Submodules") if not svn_path or not self.app._is_repo_ready(svn_path): log_handler.log_debug("Refresh Submodules skipped: Repo not ready.", func_name=func_name) # Ensure the list is cleared if the repo is not ready if hasattr(self.main_frame, "submodules_tab"): self.main_frame.submodules_tab.update_submodules_list([]) return args = (self.git_commands, svn_path) self.app._start_async_operation( worker_func=async_workers.run_refresh_submodules_async, args_tuple=args, context_dict={ "context": "refresh_submodules", "status_msg": "Refreshing submodules...", "on_complete": on_complete # Pass the callback to the context }, ) def check_for_updates(self): # Rimuoviamo l'argomento """ Starts the two-step process: first refresh the submodule list, then check each one for remote updates. """ # La funzione che verrĂ  chiamata DOPO che il refresh ha avuto successo def on_refresh_complete(submodules_list: List[Dict[str, str]]): repo_path = self.app._get_and_validate_svn_path("Check Updates") if not repo_path: return if not submodules_list: self.main_frame.update_status_bar("No submodules found to check for updates.") return args = (self.git_commands, repo_path, submodules_list) self.app._start_async_operation( async_workers.run_check_submodule_updates_async, args, {"context": "check_submodule_updates", "status_msg": "Checking submodules for updates..."} ) # Avvia il primo passo: il refresh. Passagli il nostro callback `on_complete`. self.refresh_submodules(on_complete=on_refresh_complete) def view_submodule_changes(self, submodule_path: str): """Opens a diff summary for a submodule with local changes.""" func_name = "view_submodule_changes" repo_path = self.app._get_and_validate_svn_path("View Submodule Changes") if not repo_path: return full_submodule_path = os.path.join(repo_path, submodule_path) if not os.path.isdir(full_submodule_path): self.main_frame.show_error("Error", f"Submodule directory not found:\n{full_submodule_path}") return try: # Compare HEAD with the Working Directory in the submodule changed_files = self.git_commands.get_diff_files(full_submodule_path, "HEAD", None) if not changed_files: self.main_frame.show_info("No Changes", f"No local changes found in submodule '{submodule_path}'.") return # Use the existing window handler to show the summary self.app.window_handler.handle_show_comparison_summary( ref1="HEAD (Committed)", ref2="Working Directory", repo_path=full_submodule_path, changed_files=changed_files ) except GitCommandError as e: self.main_frame.show_error("Diff Error", f"Could not get submodule changes:\n{e}") def add_submodule(self): """Handles adding a new submodule via a dialog.""" func_name = "add_submodule" svn_path = self.app._get_and_validate_svn_path("Add Submodule") if not svn_path or not self.app._is_repo_ready(svn_path): self.main_frame.show_error("Action Failed", "Repository is not ready.") return dialog = AddSubmoduleDialog(self.app.master) details = dialog.result if not details: self.main_frame.update_status_bar("Add submodule cancelled.") return submodule_url, submodule_path = details log_handler.log_info(f"Attempting to add submodule '{submodule_url}' at path '{submodule_path}'", func_name=func_name) args = (self.app.submodule_handler, svn_path, submodule_url, submodule_path) self.app._start_async_operation( worker_func=async_workers.run_add_submodule_async, args_tuple=args, context_dict={"context": "add_submodule", "status_msg": f"Adding submodule '{submodule_path}'..."}, ) def sync_all_submodules(self): """Starts an async operation to sync all submodules.""" func_name = "sync_all_submodules" svn_path = self.app._get_and_validate_svn_path("Sync Submodules") if not svn_path or not self.app._is_repo_ready(svn_path): self.main_frame.show_error("Action Failed", "Repository is not ready.") return if not self.main_frame.ask_yes_no( "Confirm Sync", "This will fetch the latest changes for all submodules and commit the updates to your main repository.\n\nProceed?" ): self.main_frame.update_status_bar("Sync cancelled.") return args = (self.app.submodule_handler, svn_path) self.app._start_async_operation( worker_func=async_workers.run_sync_all_submodules_async, args_tuple=args, context_dict={"context": "sync_submodules", "status_msg": "Syncing all submodules..."}, ) def remove_submodule(self, submodule_path: str): """Handles removing a selected submodule after confirmation.""" func_name = "remove_submodule" svn_path = self.app._get_and_validate_svn_path("Remove Submodule") if not svn_path or not self.app._is_repo_ready(svn_path): self.main_frame.show_error("Action Failed", "Repository is not ready.") return if not self.main_frame.ask_yes_no( "Confirm Removal", f"Are you sure you want to permanently remove the submodule at '{submodule_path}'?\n\n" "This will de-initialize the submodule, remove it from the index, and create a commit." ): self.main_frame.update_status_bar("Removal cancelled.") return args = (self.app.submodule_handler, svn_path, submodule_path) self.app._start_async_operation( worker_func=async_workers.run_remove_submodule_async, args_tuple=args, context_dict={"context": "remove_submodule", "status_msg": f"Removing submodule '{submodule_path}'..."}, ) def init_missing_submodules(self): """Starts an async operation to initialize all missing submodules.""" func_name = "init_missing_submodules" svn_path = self.app._get_and_validate_svn_path("Initialize Submodules") if not svn_path or not self.app._is_repo_ready(svn_path): self.main_frame.show_error("Action Failed", "Repository is not ready.") return args = (self.app.submodule_handler, svn_path) self.app._start_async_operation( worker_func=async_workers.run_init_submodules_async, args_tuple=args, context_dict={"context": "init_submodules", "status_msg": "Initializing missing submodules..."}, )