200 lines
8.6 KiB
Python
200 lines
8.6 KiB
Python
# --- 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..."},
|
|
) |