add reset to commit from history tab
This commit is contained in:
parent
8d1d712785
commit
ad4fe4cf44
@ -137,6 +137,7 @@ class GitSvnSyncApp:
|
|||||||
merge_local_branch_cb=self.merge_local_branch,
|
merge_local_branch_cb=self.merge_local_branch,
|
||||||
compare_branch_with_current_cb=self.compare_branch_with_current,
|
compare_branch_with_current_cb=self.compare_branch_with_current,
|
||||||
view_commit_details_cb=self.view_commit_details,
|
view_commit_details_cb=self.view_commit_details,
|
||||||
|
reset_to_commit_cb=self.repository_handler.handle_reset_to_commit if self.repository_handler else None,
|
||||||
config_manager_instance=self.config_manager,
|
config_manager_instance=self.config_manager,
|
||||||
profile_sections_list=self.config_manager.get_profile_sections(),
|
profile_sections_list=self.config_manager.get_profile_sections(),
|
||||||
)
|
)
|
||||||
@ -179,6 +180,8 @@ class GitSvnSyncApp:
|
|||||||
self.main_frame.tags_tab.checkout_tag_callback = self.repository_handler.checkout_tag
|
self.main_frame.tags_tab.checkout_tag_callback = self.repository_handler.checkout_tag
|
||||||
self.main_frame.tags_tab.revert_to_tag_callback = self.repository_handler.revert_to_tag
|
self.main_frame.tags_tab.revert_to_tag_callback = self.repository_handler.revert_to_tag
|
||||||
|
|
||||||
|
self.main_frame.history_tab.reset_to_commit_callback = self.repository_handler.handle_reset_to_commit
|
||||||
|
|
||||||
self.main_frame.branch_tab.create_branch_callback = self.repository_handler.create_branch
|
self.main_frame.branch_tab.create_branch_callback = self.repository_handler.create_branch
|
||||||
self.main_frame.branch_tab.checkout_branch_callback = self.repository_handler.checkout_branch
|
self.main_frame.branch_tab.checkout_branch_callback = self.repository_handler.checkout_branch
|
||||||
self.main_frame.branch_tab.merge_local_branch_callback = self.repository_handler.handle_merge_local_branch
|
self.main_frame.branch_tab.merge_local_branch_callback = self.repository_handler.handle_merge_local_branch
|
||||||
|
|||||||
@ -20,7 +20,7 @@ import re
|
|||||||
from gitutility.logging_setup import log_handler
|
from gitutility.logging_setup import log_handler
|
||||||
from gitutility.commands.git_commands import GitCommandError
|
from gitutility.commands.git_commands import GitCommandError
|
||||||
from gitutility.async_tasks import async_workers
|
from gitutility.async_tasks import async_workers
|
||||||
from gitutility.config.config_manager import DEFAULT_REMOTE_NAME
|
from ..core.wiki_updater import WikiUpdateStatus
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from ..app import GitSvnSyncApp
|
from ..app import GitSvnSyncApp
|
||||||
@ -80,7 +80,7 @@ class AsyncResultHandler:
|
|||||||
"clone_remote": self._handle_clone_remote_result,
|
"clone_remote": self._handle_clone_remote_result,
|
||||||
"checkout_tracking_branch": self._handle_checkout_tracking_branch_result,
|
"checkout_tracking_branch": self._handle_checkout_tracking_branch_result,
|
||||||
"get_commit_details": self._handle_get_commit_details_result,
|
"get_commit_details": self._handle_get_commit_details_result,
|
||||||
"update_wiki": self._handle_generic_result,
|
"update_wiki": self._handle_update_wiki_result,
|
||||||
"revert_to_tag": self._handle_revert_to_tag_result,
|
"revert_to_tag": self._handle_revert_to_tag_result,
|
||||||
"analyze_history": self._handle_analyze_history_result,
|
"analyze_history": self._handle_analyze_history_result,
|
||||||
"purge_history": self._handle_purge_history_result,
|
"purge_history": self._handle_purge_history_result,
|
||||||
@ -92,6 +92,7 @@ class AsyncResultHandler:
|
|||||||
"init_submodules": self._handle_init_submodules_result,
|
"init_submodules": self._handle_init_submodules_result,
|
||||||
"force_clean_submodule": self._handle_force_clean_submodule_result,
|
"force_clean_submodule": self._handle_force_clean_submodule_result,
|
||||||
"clean_submodule": self._handle_clean_submodule_result,
|
"clean_submodule": self._handle_clean_submodule_result,
|
||||||
|
"reset_to_commit": self._handle_reset_to_commit_result,
|
||||||
}
|
}
|
||||||
|
|
||||||
handler_method = handler_map.get(task_context)
|
handler_method = handler_map.get(task_context)
|
||||||
@ -107,6 +108,14 @@ class AsyncResultHandler:
|
|||||||
if should_trigger_refreshes:
|
if should_trigger_refreshes:
|
||||||
self.app._trigger_post_action_refreshes(post_action_sync_refresh_needed)
|
self.app._trigger_post_action_refreshes(post_action_sync_refresh_needed)
|
||||||
|
|
||||||
|
def _handle_reset_to_commit_result(self, result_data: Dict[str, Any], context: Dict[str, Any]) -> Tuple[bool, bool]:
|
||||||
|
if result_data.get("status") == "success":
|
||||||
|
self.main_frame.show_info("Operation Successful", result_data.get("message"))
|
||||||
|
return True, True
|
||||||
|
else:
|
||||||
|
self.main_frame.show_error("Reset to Commit Error", f"Failed:\n{result_data.get('message')}")
|
||||||
|
return False, False
|
||||||
|
|
||||||
def _handle_refresh_tags_result(self, result_data: Dict[str, Any], context: Dict[str, Any]) -> Tuple[bool, bool]:
|
def _handle_refresh_tags_result(self, result_data: Dict[str, Any], context: Dict[str, Any]) -> Tuple[bool, bool]:
|
||||||
if result_data.get("status") == "success":
|
if result_data.get("status") == "success":
|
||||||
self.main_frame.tags_tab.update_tag_list(result_data.get("result", []))
|
self.main_frame.tags_tab.update_tag_list(result_data.get("result", []))
|
||||||
@ -600,3 +609,23 @@ class AsyncResultHandler:
|
|||||||
self.main_frame.submodules_tab.update_remote_statuses(statuses)
|
self.main_frame.submodules_tab.update_remote_statuses(statuses)
|
||||||
|
|
||||||
return False, False
|
return False, False
|
||||||
|
|
||||||
|
def _handle_update_wiki_result(self, result_data: Dict[str, Any], context: Dict[str, Any]) -> Tuple[bool, bool]:
|
||||||
|
"""Handles the result of the update_wiki_from_docs async task."""
|
||||||
|
status = result_data.get("status")
|
||||||
|
message = result_data.get("message", "Wiki operation finished.")
|
||||||
|
|
||||||
|
if status == "success":
|
||||||
|
# In our new implementation, 'success' is for both actual updates and no-changes scenarios
|
||||||
|
self.main_frame.show_info("Wiki Update", message)
|
||||||
|
# We only need to trigger a full refresh if something actually changed.
|
||||||
|
# The result object from the worker now contains the detailed status.
|
||||||
|
update_result = result_data.get("result")
|
||||||
|
if update_result and update_result.status == WikiUpdateStatus.SUCCESS:
|
||||||
|
return True, True
|
||||||
|
elif status == "warning":
|
||||||
|
self.main_frame.show_warning("Wiki Update Info", message)
|
||||||
|
elif status == "error":
|
||||||
|
self.main_frame.show_error("Wiki Update Error", f"Failed:\n{message}")
|
||||||
|
|
||||||
|
return False, False
|
||||||
@ -13,7 +13,7 @@ from ..commands.git_commands import GitCommands, GitCommandError
|
|||||||
from ..core.action_handler import ActionHandler
|
from ..core.action_handler import ActionHandler
|
||||||
from ..core.backup_handler import BackupHandler
|
from ..core.backup_handler import BackupHandler
|
||||||
from ..core.remote_actions import RemoteActionHandler
|
from ..core.remote_actions import RemoteActionHandler
|
||||||
from ..core.wiki_updater import WikiUpdater
|
from ..core.wiki_updater import WikiUpdater, WikiUpdateStatus
|
||||||
from ..core.history_cleaner import HistoryCleaner
|
from ..core.history_cleaner import HistoryCleaner
|
||||||
from ..core.submodule_handler import SubmoduleHandler
|
from ..core.submodule_handler import SubmoduleHandler
|
||||||
|
|
||||||
@ -1040,17 +1040,27 @@ def run_update_wiki_async(
|
|||||||
"status": "error",
|
"status": "error",
|
||||||
"message": "Wiki update failed.",
|
"message": "Wiki update failed.",
|
||||||
"exception": None,
|
"exception": None,
|
||||||
"result": False,
|
"result": None,
|
||||||
}
|
}
|
||||||
try:
|
try:
|
||||||
success, message = wiki_updater.update_wiki_from_docs(
|
update_result = wiki_updater.update_wiki_from_docs(
|
||||||
main_repo_path=main_repo_path,
|
main_repo_path=main_repo_path,
|
||||||
main_repo_remote_url=main_repo_remote_url,
|
main_repo_remote_url=main_repo_remote_url,
|
||||||
)
|
)
|
||||||
result_payload["status"] = "success" if success else "error"
|
|
||||||
result_payload["message"] = message
|
# The status for the queue can be 'success', 'warning', or 'error'
|
||||||
result_payload["result"] = success
|
# We map our detailed status to one of these
|
||||||
log_handler.log_info(f"[Worker] Wiki update result: {message}", func_name=func_name)
|
if update_result.status in [WikiUpdateStatus.SUCCESS, WikiUpdateStatus.NO_CHANGES]:
|
||||||
|
queue_status = "success"
|
||||||
|
elif update_result.status in [WikiUpdateStatus.DOC_NOT_FOUND]:
|
||||||
|
queue_status = "warning"
|
||||||
|
else:
|
||||||
|
queue_status = "error"
|
||||||
|
|
||||||
|
result_payload["status"] = queue_status
|
||||||
|
result_payload["message"] = update_result.message
|
||||||
|
result_payload["result"] = update_result # Pass the whole result object
|
||||||
|
log_handler.log_info(f"[Worker] Wiki update result: {update_result.message}", func_name=func_name)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log_handler.log_exception(f"[Worker] UNEXPECTED EXCEPTION during wiki update: {e}", func_name=func_name)
|
log_handler.log_exception(f"[Worker] UNEXPECTED EXCEPTION during wiki update: {e}", func_name=func_name)
|
||||||
@ -1093,6 +1103,36 @@ def run_revert_to_tag_async(
|
|||||||
log_handler.log_error(f"[Worker] Failed to put result in queue for {func_name}: {qe}", func_name=func_name)
|
log_handler.log_error(f"[Worker] Failed to put result in queue for {func_name}: {qe}", func_name=func_name)
|
||||||
log_handler.log_debug(f"[Worker] Finished: Revert to Tag '{tag_name}'", func_name=func_name)
|
log_handler.log_debug(f"[Worker] Finished: Revert to Tag '{tag_name}'", func_name=func_name)
|
||||||
|
|
||||||
|
def run_reset_to_commit_async(
|
||||||
|
action_handler: ActionHandler,
|
||||||
|
repo_path: str,
|
||||||
|
commit_hash: str,
|
||||||
|
results_queue: queue.Queue[Dict[str, Any]],
|
||||||
|
) -> None:
|
||||||
|
"""Worker to perform a hard reset to a specific commit asynchronously."""
|
||||||
|
func_name = "run_reset_to_commit_async"
|
||||||
|
log_handler.log_debug(f"[Worker] Started: Reset to Commit '{commit_hash}' in '{repo_path}'", func_name=func_name)
|
||||||
|
result_payload: Dict[str, Any] = {
|
||||||
|
"status": "error", "result": False, "message": f"Failed to reset to commit '{commit_hash[:7]}'.", "exception": None,
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
# Directly call the git_reset_hard from action_handler's git_commands
|
||||||
|
action_handler.git_commands.git_reset_hard(repo_path, commit_hash)
|
||||||
|
result_payload["status"] = "success"
|
||||||
|
result_payload["result"] = True
|
||||||
|
result_payload["message"] = f"Repository successfully reset to commit '{commit_hash[:7]}'."
|
||||||
|
log_handler.log_info(f"[Worker] {result_payload['message']}", func_name=func_name)
|
||||||
|
except (GitCommandError, ValueError, Exception) as e:
|
||||||
|
log_handler.log_exception(f"[Worker] EXCEPTION resetting to commit: {e}", func_name=func_name)
|
||||||
|
result_payload["exception"] = e
|
||||||
|
result_payload["message"] = f"Error resetting to commit '{commit_hash[:7]}': {e}"
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
results_queue.put(result_payload)
|
||||||
|
except Exception as qe:
|
||||||
|
log_handler.log_error(f"[Worker] Failed to put result in queue for {func_name}: {qe}", func_name=func_name)
|
||||||
|
log_handler.log_debug(f"[Worker] Finished: Reset to Commit '{commit_hash}'", func_name=func_name)
|
||||||
|
|
||||||
def run_analyze_repo_for_purge_async(
|
def run_analyze_repo_for_purge_async(
|
||||||
history_cleaner: HistoryCleaner,
|
history_cleaner: HistoryCleaner,
|
||||||
repo_path: str,
|
repo_path: str,
|
||||||
|
|||||||
@ -905,6 +905,32 @@ class GitCommands:
|
|||||||
raise e
|
raise e
|
||||||
|
|
||||||
# --- History / Log ---
|
# --- History / Log ---
|
||||||
|
def reset_hard(self, working_directory: str, commit_hash: str) -> None:
|
||||||
|
"""
|
||||||
|
Performs a git reset --hard to the specified commit hash.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
working_directory (str): Path to the repository.
|
||||||
|
commit_hash (str): The commit hash to reset to.
|
||||||
|
"""
|
||||||
|
func_name = "reset_hard"
|
||||||
|
log_handler.log_warning(
|
||||||
|
f"Performing a destructive 'git reset --hard' to '{commit_hash}' in '{working_directory}'",
|
||||||
|
func_name=func_name
|
||||||
|
)
|
||||||
|
if not commit_hash or commit_hash.isspace():
|
||||||
|
raise ValueError("Commit hash cannot be empty.")
|
||||||
|
|
||||||
|
cmd = ["git", "reset", "--hard", commit_hash]
|
||||||
|
try:
|
||||||
|
self.log_and_execute(cmd, working_directory, check=True)
|
||||||
|
log_handler.log_info(
|
||||||
|
f"Successfully reset to commit '{commit_hash}'.", func_name=func_name
|
||||||
|
)
|
||||||
|
except GitCommandError as e:
|
||||||
|
log_handler.log_error(f"Failed to 'git reset --hard': {e}", func_name=func_name)
|
||||||
|
raise
|
||||||
|
|
||||||
def get_commit_log(
|
def get_commit_log(
|
||||||
self, working_directory: str, max_count: int = 200, branch: Optional[str] = None
|
self, working_directory: str, max_count: int = 200, branch: Optional[str] = None
|
||||||
) -> List[str]:
|
) -> List[str]:
|
||||||
@ -2048,11 +2074,11 @@ class GitCommands:
|
|||||||
raise e
|
raise e
|
||||||
|
|
||||||
log_handler.log_warning(
|
log_handler.log_warning(
|
||||||
"Performing DESTRUCTIVE operation: git clean -fdx", func_name=func_name
|
"Performing DESTRUCTIVE operation: git clean -fd", func_name=func_name
|
||||||
)
|
)
|
||||||
|
|
||||||
# 2. Esegui git clean -fdx per rimuovere file non tracciati
|
# 2. Esegui git clean -fd per rimuovere file non tracciati
|
||||||
clean_cmd: List[str] = ["git", "clean", "-fdx"]
|
clean_cmd: List[str] = ["git", "clean", "-fd"]
|
||||||
try:
|
try:
|
||||||
self.log_and_execute(
|
self.log_and_execute(
|
||||||
clean_cmd, working_directory, check=True, log_output_level=logging.INFO
|
clean_cmd, working_directory, check=True, log_output_level=logging.INFO
|
||||||
|
|||||||
@ -5,14 +5,33 @@ import shutil
|
|||||||
import tempfile
|
import tempfile
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
from typing import Optional, Tuple
|
from typing import Optional
|
||||||
from urllib.parse import urlparse, urlunparse
|
from urllib.parse import urlparse, urlunparse
|
||||||
|
from enum import Enum, auto
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
from ..commands.git_commands import GitCommands, GitCommandError
|
from ..commands.git_commands import GitCommands, GitCommandError
|
||||||
from ..logging_setup import log_handler
|
from ..logging_setup import log_handler
|
||||||
|
|
||||||
|
class WikiUpdateStatus(Enum):
|
||||||
|
"""Represents the result of the wiki update operation."""
|
||||||
|
SUCCESS = auto()
|
||||||
|
NO_CHANGES = auto()
|
||||||
|
URL_DERIVATION_FAILED = auto()
|
||||||
|
CLONE_FAILED = auto()
|
||||||
|
PUSH_FAILED = auto()
|
||||||
|
COMMIT_FAILED = auto()
|
||||||
|
DOC_NOT_FOUND = auto()
|
||||||
|
BRANCH_NOT_FOUND = auto()
|
||||||
|
GENERIC_ERROR = auto()
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class WikiUpdateResult:
|
||||||
|
"""Holds the result of the wiki update operation."""
|
||||||
|
status: WikiUpdateStatus
|
||||||
|
message: str
|
||||||
|
|
||||||
class WikiUpdater:
|
class WikiUpdater:
|
||||||
# ... (il resto della classe è invariato fino a update_wiki_from_docs)
|
|
||||||
DEFAULT_WIKI_EN_FILENAME = "English-Manual.md"
|
DEFAULT_WIKI_EN_FILENAME = "English-Manual.md"
|
||||||
DEFAULT_WIKI_IT_FILENAME = "Italian-Manual.md"
|
DEFAULT_WIKI_IT_FILENAME = "Italian-Manual.md"
|
||||||
|
|
||||||
@ -23,7 +42,6 @@ class WikiUpdater:
|
|||||||
log_handler.log_debug("WikiUpdater initialized.", func_name="__init__")
|
log_handler.log_debug("WikiUpdater initialized.", func_name="__init__")
|
||||||
|
|
||||||
def _get_wiki_repo_url(self, main_repo_url: str) -> Optional[str]:
|
def _get_wiki_repo_url(self, main_repo_url: str) -> Optional[str]:
|
||||||
# ... (codice invariato)
|
|
||||||
if not main_repo_url:
|
if not main_repo_url:
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
@ -52,7 +70,7 @@ class WikiUpdater:
|
|||||||
wiki_en_target_filename: Optional[str] = None,
|
wiki_en_target_filename: Optional[str] = None,
|
||||||
wiki_it_target_filename: Optional[str] = None,
|
wiki_it_target_filename: Optional[str] = None,
|
||||||
commit_message: str = "Update Wiki documentation from local files"
|
commit_message: str = "Update Wiki documentation from local files"
|
||||||
) -> Tuple[bool, str]:
|
) -> WikiUpdateResult:
|
||||||
"""
|
"""
|
||||||
Clones the Gitea wiki repo, updates pages from local doc files, and pushes.
|
Clones the Gitea wiki repo, updates pages from local doc files, and pushes.
|
||||||
"""
|
"""
|
||||||
@ -63,7 +81,7 @@ class WikiUpdater:
|
|||||||
if not wiki_url:
|
if not wiki_url:
|
||||||
msg = "Could not derive Wiki repository URL from main remote URL."
|
msg = "Could not derive Wiki repository URL from main remote URL."
|
||||||
log_handler.log_error(msg, func_name=func_name)
|
log_handler.log_error(msg, func_name=func_name)
|
||||||
return False, msg
|
return WikiUpdateResult(status=WikiUpdateStatus.URL_DERIVATION_FAILED, message=msg)
|
||||||
|
|
||||||
log_handler.log_debug(f"Derived wiki URL: {wiki_url}", func_name=func_name)
|
log_handler.log_debug(f"Derived wiki URL: {wiki_url}", func_name=func_name)
|
||||||
|
|
||||||
@ -78,7 +96,7 @@ class WikiUpdater:
|
|||||||
if not en_exists and not it_exists:
|
if not en_exists and not it_exists:
|
||||||
msg = f"Neither '{en_manual_filename}' nor '{it_manual_filename}' found in '{doc_path}'. Cannot update Wiki."
|
msg = f"Neither '{en_manual_filename}' nor '{it_manual_filename}' found in '{doc_path}'. Cannot update Wiki."
|
||||||
log_handler.log_warning(msg, func_name=func_name)
|
log_handler.log_warning(msg, func_name=func_name)
|
||||||
return False, msg
|
return WikiUpdateResult(status=WikiUpdateStatus.DOC_NOT_FOUND, message=msg)
|
||||||
|
|
||||||
temp_dir: Optional[str] = None
|
temp_dir: Optional[str] = None
|
||||||
try:
|
try:
|
||||||
@ -93,7 +111,7 @@ class WikiUpdater:
|
|||||||
else:
|
else:
|
||||||
msg = f"Failed to clone Wiki repository '{wiki_url}'. Error: {stderr_msg.strip()}"
|
msg = f"Failed to clone Wiki repository '{wiki_url}'. Error: {stderr_msg.strip()}"
|
||||||
log_handler.log_error(msg, func_name=func_name)
|
log_handler.log_error(msg, func_name=func_name)
|
||||||
return False, f"{msg} (Check authentication?)"
|
return WikiUpdateResult(status=WikiUpdateStatus.CLONE_FAILED, message=f"{msg} (Check authentication?)")
|
||||||
|
|
||||||
log_handler.log_info("Wiki repository cloned successfully.", func_name=func_name)
|
log_handler.log_info("Wiki repository cloned successfully.", func_name=func_name)
|
||||||
|
|
||||||
@ -108,26 +126,24 @@ class WikiUpdater:
|
|||||||
if not self.git_commands.git_status_has_changes(temp_dir):
|
if not self.git_commands.git_status_has_changes(temp_dir):
|
||||||
msg = "Wiki content is already up-to-date with local doc files."
|
msg = "Wiki content is already up-to-date with local doc files."
|
||||||
log_handler.log_info(msg, func_name=func_name)
|
log_handler.log_info(msg, func_name=func_name)
|
||||||
return True, msg
|
return WikiUpdateResult(status=WikiUpdateStatus.NO_CHANGES, message=msg)
|
||||||
|
|
||||||
# --- MODIFICA PER PROBLEMA COMMIT ---
|
|
||||||
log_handler.log_info("Changes detected. Staging with --renormalize to handle line endings.", func_name=func_name)
|
log_handler.log_info("Changes detected. Staging with --renormalize to handle line endings.", func_name=func_name)
|
||||||
# Questo comando forza Git a ri-processare i file, risolvendo problemi di CRLF/LF
|
|
||||||
self.git_commands.add_file(temp_dir, ".", renormalize=True)
|
self.git_commands.add_file(temp_dir, ".", renormalize=True)
|
||||||
# Ora eseguiamo il commit, ma senza fare un altro 'add'
|
|
||||||
commit_success = self.git_commands.git_commit(temp_dir, commit_message, stage_all_first=False)
|
|
||||||
# --- FINE MODIFICA ---
|
|
||||||
|
|
||||||
|
commit_success = self.git_commands.git_commit(temp_dir, commit_message, stage_all_first=False)
|
||||||
if not commit_success:
|
if not commit_success:
|
||||||
msg = "Staged changes, but commit reported no changes to commit. Push will be skipped."
|
msg = "Staged changes, but commit reported no changes to commit. Push will be skipped."
|
||||||
log_handler.log_warning(msg, func_name=func_name)
|
log_handler.log_warning(msg, func_name=func_name)
|
||||||
return True, msg # Consideriamo un "successo" perché non c'era nulla di sostanziale da pushare
|
return WikiUpdateResult(status=WikiUpdateStatus.NO_CHANGES, message=msg)
|
||||||
|
|
||||||
log_handler.log_info("Wiki changes committed locally.", func_name=func_name)
|
log_handler.log_info("Wiki changes committed locally.", func_name=func_name)
|
||||||
|
|
||||||
current_wiki_branch = self.git_commands.get_current_branch_name(temp_dir)
|
current_wiki_branch = self.git_commands.get_current_branch_name(temp_dir)
|
||||||
if not current_wiki_branch:
|
if not current_wiki_branch:
|
||||||
return False, "Could not determine the current branch in the cloned wiki repository."
|
msg = "Could not determine the current branch in the cloned wiki repository."
|
||||||
|
log_handler.log_error(msg, func_name=func_name)
|
||||||
|
return WikiUpdateResult(status=WikiUpdateStatus.BRANCH_NOT_FOUND, message=msg)
|
||||||
|
|
||||||
log_handler.log_info("Pushing wiki changes to remote...", func_name=func_name)
|
log_handler.log_info("Pushing wiki changes to remote...", func_name=func_name)
|
||||||
push_result = self.git_commands.git_push(
|
push_result = self.git_commands.git_push(
|
||||||
@ -140,30 +156,28 @@ class WikiUpdater:
|
|||||||
if push_result.returncode == 0:
|
if push_result.returncode == 0:
|
||||||
msg = "Wiki update pushed successfully to Gitea."
|
msg = "Wiki update pushed successfully to Gitea."
|
||||||
log_handler.log_info(msg, func_name=func_name)
|
log_handler.log_info(msg, func_name=func_name)
|
||||||
return True, msg
|
return WikiUpdateResult(status=WikiUpdateStatus.SUCCESS, message=msg)
|
||||||
else:
|
else:
|
||||||
stderr_msg = push_result.stderr or "Unknown push error"
|
stderr_msg = push_result.stderr or "Unknown push error"
|
||||||
msg = f"Failed to push Wiki updates. Error: {stderr_msg.strip()}"
|
msg = f"Failed to push Wiki updates. Error: {stderr_msg.strip()}"
|
||||||
log_handler.log_error(msg, func_name=func_name)
|
log_handler.log_error(msg, func_name=func_name)
|
||||||
return False, msg
|
return WikiUpdateResult(status=WikiUpdateStatus.PUSH_FAILED, message=msg)
|
||||||
|
|
||||||
except (GitCommandError, ValueError, IOError, Exception) as e:
|
except (GitCommandError, ValueError, IOError, Exception) as e:
|
||||||
log_handler.log_exception(f"Error during wiki update process: {e}", func_name=func_name)
|
log_handler.log_exception(f"Error during wiki update process: {e}", func_name=func_name)
|
||||||
return False, f"Wiki update failed: {e}"
|
return WikiUpdateResult(status=WikiUpdateStatus.GENERIC_ERROR, message=f"Wiki update failed: {e}")
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
# --- MODIFICA PER PROBLEMA PULIZIA ---
|
|
||||||
if temp_dir and os.path.isdir(temp_dir):
|
if temp_dir and os.path.isdir(temp_dir):
|
||||||
log_handler.log_debug(f"Attempting to clean up temporary directory: {temp_dir}", func_name=func_name)
|
log_handler.log_debug(f"Attempting to clean up temporary directory: {temp_dir}", func_name=func_name)
|
||||||
for attempt in range(3): # Prova fino a 3 volte
|
for attempt in range(3):
|
||||||
try:
|
try:
|
||||||
shutil.rmtree(temp_dir)
|
shutil.rmtree(temp_dir)
|
||||||
log_handler.log_info(f"Cleanup of temporary directory successful.", func_name=func_name)
|
log_handler.log_info(f"Cleanup of temporary directory successful.", func_name=func_name)
|
||||||
break # Esci dal ciclo se la pulizia ha successo
|
break
|
||||||
except Exception as clean_e:
|
except Exception as clean_e:
|
||||||
log_handler.log_warning(f"Cleanup attempt {attempt + 1} failed for '{temp_dir}': {clean_e}", func_name=func_name)
|
log_handler.log_warning(f"Cleanup attempt {attempt + 1} failed for '{temp_dir}': {clean_e}", func_name=func_name)
|
||||||
if attempt < 2:
|
if attempt < 2:
|
||||||
time.sleep(0.5) # Aspetta 500ms prima di riprovare
|
time.sleep(0.5)
|
||||||
else:
|
else:
|
||||||
log_handler.log_error(f"Final cleanup attempt failed for '{temp_dir}'.", func_name=func_name)
|
log_handler.log_error(f"Final cleanup attempt failed for '{temp_dir}'.", func_name=func_name)
|
||||||
# --- FINE MODIFICA ---
|
|
||||||
@ -27,6 +27,7 @@ class HistoryTab(ttk.Frame):
|
|||||||
# Store callbacks
|
# Store callbacks
|
||||||
self.refresh_history_callback = kwargs.get('refresh_history_cb')
|
self.refresh_history_callback = kwargs.get('refresh_history_cb')
|
||||||
self.view_commit_details_callback = kwargs.get('view_commit_details_cb')
|
self.view_commit_details_callback = kwargs.get('view_commit_details_cb')
|
||||||
|
self.reset_to_commit_callback = kwargs.get('reset_to_commit_cb')
|
||||||
|
|
||||||
# --- Get a reference to the main frame for shared components ---
|
# --- Get a reference to the main frame for shared components ---
|
||||||
self.main_frame = self.master.master
|
self.main_frame = self.master.master
|
||||||
@ -97,7 +98,8 @@ class HistoryTab(ttk.Frame):
|
|||||||
tree_scrollbar_x.grid(row=1, column=0, columnspan=2, sticky="ew")
|
tree_scrollbar_x.grid(row=1, column=0, columnspan=2, sticky="ew")
|
||||||
|
|
||||||
self.history_tree.bind("<Double-Button-1>", self._on_history_double_click)
|
self.history_tree.bind("<Double-Button-1>", self._on_history_double_click)
|
||||||
Tooltip(self.history_tree, "Double-click a commit line to view details.")
|
self.history_tree.bind("<Button-3>", self._show_context_menu)
|
||||||
|
Tooltip(self.history_tree, "Double-click a commit line to view details.\nRight-click for more options.")
|
||||||
|
|
||||||
def set_action_widgets_state(self, state: str) -> None:
|
def set_action_widgets_state(self, state: str) -> None:
|
||||||
"""Sets the state of all action widgets in this tab."""
|
"""Sets the state of all action widgets in this tab."""
|
||||||
@ -115,8 +117,10 @@ class HistoryTab(ttk.Frame):
|
|||||||
if self.history_tree and self.history_tree.winfo_exists():
|
if self.history_tree and self.history_tree.winfo_exists():
|
||||||
if state == tk.DISABLED:
|
if state == tk.DISABLED:
|
||||||
self.history_tree.unbind("<Double-Button-1>")
|
self.history_tree.unbind("<Double-Button-1>")
|
||||||
|
self.history_tree.unbind("<Button-3>")
|
||||||
else:
|
else:
|
||||||
self.history_tree.bind("<Double-Button-1>", self._on_history_double_click)
|
self.history_tree.bind("<Double-Button-1>", self._on_history_double_click)
|
||||||
|
self.history_tree.bind("<Button-3>", self._show_context_menu)
|
||||||
|
|
||||||
def update_history_display(self, log_lines: List[str]) -> None:
|
def update_history_display(self, log_lines: List[str]) -> None:
|
||||||
"""Populates the history treeview with parsed log data."""
|
"""Populates the history treeview with parsed log data."""
|
||||||
@ -186,3 +190,58 @@ class HistoryTab(ttk.Frame):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
log_handler.log_exception(f"Error handling history double-click: {e}", func_name=func_name)
|
log_handler.log_exception(f"Error handling history double-click: {e}", func_name=func_name)
|
||||||
messagebox.showerror("Error", f"Could not process history selection:\n{e}", parent=self)
|
messagebox.showerror("Error", f"Could not process history selection:\n{e}", parent=self)
|
||||||
|
|
||||||
|
def _show_context_menu(self, event: tk.Event) -> None:
|
||||||
|
"""Displays a context menu on right-click."""
|
||||||
|
# Select the item under the cursor
|
||||||
|
iid = self.history_tree.identify_row(event.y)
|
||||||
|
if not iid: # Clicked outside of any item
|
||||||
|
return
|
||||||
|
|
||||||
|
self.history_tree.selection_set(iid)
|
||||||
|
self.history_tree.focus(iid)
|
||||||
|
|
||||||
|
item_data = self.history_tree.item(iid)
|
||||||
|
item_values = item_data.get("values")
|
||||||
|
if not item_values or not str(item_values[0]).strip():
|
||||||
|
return
|
||||||
|
|
||||||
|
commit_hash = str(item_values[0]).strip()
|
||||||
|
|
||||||
|
context_menu = tk.Menu(self, tearoff=0)
|
||||||
|
context_menu.add_command(
|
||||||
|
label=f"View Details for {commit_hash[:7]}...",
|
||||||
|
command=lambda: self.view_commit_details_callback(commit_hash)
|
||||||
|
)
|
||||||
|
context_menu.add_separator()
|
||||||
|
context_menu.add_command(
|
||||||
|
label=f"Reset branch to this commit ({commit_hash[:7]}) ...",
|
||||||
|
command=lambda: self._on_reset_to_commit(commit_hash)
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
context_menu.tk_popup(event.x_root, event.y_root)
|
||||||
|
finally:
|
||||||
|
context_menu.grab_release()
|
||||||
|
|
||||||
|
def _on_reset_to_commit(self, commit_hash: str) -> None:
|
||||||
|
"""Handles the 'Reset to commit' action from the context menu."""
|
||||||
|
func_name = "_on_reset_to_commit"
|
||||||
|
if not callable(self.reset_to_commit_callback):
|
||||||
|
log_handler.log_warning("reset_to_commit_callback is not available.", func_name)
|
||||||
|
return
|
||||||
|
|
||||||
|
title = "Confirm Destructive Action"
|
||||||
|
message = (
|
||||||
|
f"Are you sure you want to reset your current branch to commit {commit_hash[:7]}?"
|
||||||
|
f"WARNING: This is a destructive operation!"
|
||||||
|
f"- All commits made after this one will be permanently lost."
|
||||||
|
f"- All uncommitted changes in your working directory will be permanently lost."
|
||||||
|
f"This action cannot be undone. Proceed with caution."
|
||||||
|
)
|
||||||
|
|
||||||
|
if messagebox.askokcancel(title, message, icon=messagebox.WARNING, parent=self):
|
||||||
|
log_handler.log_warning(f"User confirmed reset to commit: '{commit_hash}'", func_name)
|
||||||
|
self.reset_to_commit_callback(commit_hash)
|
||||||
|
else:
|
||||||
|
log_handler.log_info("User cancelled reset operation.", func_name)
|
||||||
@ -408,3 +408,18 @@ class RepositoryHandler:
|
|||||||
args_tuple=args,
|
args_tuple=args,
|
||||||
context_dict={"context": "get_commit_details", "status_msg": f"Loading details for commit {commit_hash_short}"}
|
context_dict={"context": "get_commit_details", "status_msg": f"Loading details for commit {commit_hash_short}"}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def handle_reset_to_commit(self, commit_hash: str):
|
||||||
|
"""Handles the destructive 'Reset to Commit' action."""
|
||||||
|
func_name = "handle_reset_to_commit"
|
||||||
|
svn_path = self.app._get_and_validate_svn_path("Reset to Commit")
|
||||||
|
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.action_handler, svn_path, commit_hash)
|
||||||
|
self.app._start_async_operation(
|
||||||
|
worker_func=async_workers.run_reset_to_commit_async,
|
||||||
|
args_tuple=args,
|
||||||
|
context_dict={"context": "reset_to_commit", "status_msg": f"Resetting to commit '{commit_hash[:7]}'"},
|
||||||
|
)
|
||||||
Loading…
Reference in New Issue
Block a user