add add file into commit function
This commit is contained in:
parent
b5dbd75999
commit
688e779494
@ -114,6 +114,7 @@ class GitSvnSyncApp:
|
|||||||
# Passa istanza config manager e profili iniziali
|
# Passa istanza config manager e profili iniziali
|
||||||
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(),
|
||||||
|
add_selected_file_cb=self.add_selected_file,
|
||||||
)
|
)
|
||||||
|
|
||||||
# --- Collega widget GUI specifici (che non passano dal costruttore di MainFrame) ---
|
# --- Collega widget GUI specifici (che non passano dal costruttore di MainFrame) ---
|
||||||
@ -1826,6 +1827,70 @@ class GitSvnSyncApp:
|
|||||||
self.master.destroy()
|
self.master.destroy()
|
||||||
except: pass # Ignora errori durante la distruzione
|
except: pass # Ignora errori durante la distruzione
|
||||||
|
|
||||||
|
def add_selected_file(self, file_status_line):
|
||||||
|
"""Handles the 'Add to Staging Area' action from the context menu."""
|
||||||
|
self.logger.info(f"--- Action Triggered: Add File for '{file_status_line}' ---")
|
||||||
|
if hasattr(self, 'main_frame'):
|
||||||
|
self.main_frame.update_status_bar("Processing: Adding file to staging...")
|
||||||
|
|
||||||
|
# Ottieni percorso repo
|
||||||
|
svn_path = self._get_and_validate_svn_path("Add File")
|
||||||
|
if not svn_path:
|
||||||
|
if hasattr(self, 'main_frame'): self.main_frame.update_status_bar("Add failed: Invalid path.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Estrai percorso relativo pulito
|
||||||
|
# Usa la stessa logica di open_diff_viewer o il metodo da diff_viewer
|
||||||
|
relative_path = ""
|
||||||
|
try:
|
||||||
|
# Assumi che _clean_relative_path sia in DiffViewerWindow, potremmo duplicarlo
|
||||||
|
# o creare un helper comune se diventa troppo ripetitivo.
|
||||||
|
# Per ora usiamo una logica simile a quella in open_diff_viewer
|
||||||
|
line = file_status_line.strip('\x00').strip()
|
||||||
|
if line.startswith("??") and len(line) > 3:
|
||||||
|
relative_path = line[3:].strip()
|
||||||
|
if relative_path.startswith('"') and relative_path.endswith('"'):
|
||||||
|
relative_path = relative_path[1:-1]
|
||||||
|
else:
|
||||||
|
# Se non inizia con '??', l'opzione non doveva essere attiva. Logga errore.
|
||||||
|
self.logger.error(f"Add action triggered for non-untracked file: '{file_status_line}'")
|
||||||
|
if hasattr(self, 'main_frame'):
|
||||||
|
self.main_frame.show_error("Error", "Cannot add non-untracked file.")
|
||||||
|
self.main_frame.update_status_bar("Add failed: File not untracked.")
|
||||||
|
return
|
||||||
|
|
||||||
|
if not relative_path:
|
||||||
|
raise ValueError("Could not extract file path.")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"Error parsing file path for add: {e}")
|
||||||
|
if hasattr(self, 'main_frame'):
|
||||||
|
self.main_frame.show_error("Error", f"Could not determine file to add from:\n{file_status_line}")
|
||||||
|
self.main_frame.update_status_bar("Add failed: Parse error.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Esegui il comando git add
|
||||||
|
status_final = "Ready."
|
||||||
|
try:
|
||||||
|
success = self.git_commands.add_file(svn_path, relative_path)
|
||||||
|
if success:
|
||||||
|
status_final = f"File '{os.path.basename(relative_path)}' added to staging."
|
||||||
|
self.logger.info(status_final)
|
||||||
|
# Aggiorna la lista dei file modificati per mostrare il nuovo stato
|
||||||
|
self.refresh_changed_files_list()
|
||||||
|
# else: add_file solleverà eccezione in caso di fallimento
|
||||||
|
|
||||||
|
except (GitCommandError, ValueError) as e:
|
||||||
|
self.logger.error(f"Failed to add file '{relative_path}': {e}", exc_info=True)
|
||||||
|
status_final = f"Error adding file: {type(e).__name__}"
|
||||||
|
if hasattr(self, 'main_frame'): self.main_frame.show_error("Add Error", f"Failed to add file:\n{e}")
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.exception(f"Unexpected error adding file '{relative_path}': {e}")
|
||||||
|
status_final = "Error: Unexpected add failure."
|
||||||
|
if hasattr(self, 'main_frame'): self.main_frame.show_error("Error", f"Unexpected error:\n{e}")
|
||||||
|
finally:
|
||||||
|
if hasattr(self, 'main_frame'): self.main_frame.update_status_bar(status_final)
|
||||||
|
|
||||||
|
|
||||||
# --- Application Entry Point ---
|
# --- Application Entry Point ---
|
||||||
def main():
|
def main():
|
||||||
|
|||||||
@ -1178,3 +1178,48 @@ class GitCommands:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.exception(f"Unexpected error in get_file_content_from_ref for '{ref_path_arg}': {e}")
|
self.logger.exception(f"Unexpected error in get_file_content_from_ref for '{ref_path_arg}': {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def add_file(self, working_directory, file_path):
|
||||||
|
"""
|
||||||
|
Adds a specific file to the Git staging area (index).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
working_directory (str): Path to the Git repository.
|
||||||
|
file_path (str): Relative path to the file within the repo to add.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if the command executed successfully.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
GitCommandError: If git add fails (e.g., file doesn't exist, permissions).
|
||||||
|
ValueError: If file_path is empty.
|
||||||
|
"""
|
||||||
|
if not file_path:
|
||||||
|
raise ValueError("File path cannot be empty for git add.")
|
||||||
|
|
||||||
|
# Normalizza il percorso per sicurezza, anche se git add è flessibile
|
||||||
|
# git_style_path = file_path.replace(os.path.sep, '/') # Non strettamente necessario per add
|
||||||
|
self.logger.info(f"Adding file to staging area: '{file_path}' in '{working_directory}'")
|
||||||
|
|
||||||
|
# Costruisci comando semplice
|
||||||
|
command = ["git", "add", "--", file_path] # "--" per sicurezza con nomi file strani
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Esegui il comando. L'output non è molto informativo di solito.
|
||||||
|
# Logghiamolo a DEBUG. check=True solleva eccezione su errore.
|
||||||
|
self.log_and_execute(command, working_directory, check=True, log_output_level=logging.DEBUG)
|
||||||
|
self.logger.info(f"File '{file_path}' added to staging area successfully.")
|
||||||
|
return True
|
||||||
|
except GitCommandError as add_error:
|
||||||
|
# Logga e rilancia l'errore specifico di git add
|
||||||
|
self.logger.error(f"Failed to add file '{file_path}': {add_error}", exc_info=True)
|
||||||
|
# Rendi l'errore un po' più specifico se possibile
|
||||||
|
stderr = add_error.stderr.lower() if add_error.stderr else ""
|
||||||
|
if "did not match any files" in stderr:
|
||||||
|
raise GitCommandError(f"File not found or invalid: '{file_path}'", command=command, stderr=add_error.stderr) from add_error
|
||||||
|
else:
|
||||||
|
raise add_error # Rilancia errore generico git
|
||||||
|
except Exception as e:
|
||||||
|
# Errore imprevisto
|
||||||
|
self.logger.exception(f"Unexpected error adding file '{file_path}': {e}")
|
||||||
|
raise GitCommandError(f"Unexpected add error: {e}", command=command) from e
|
||||||
62
gui.py
62
gui.py
@ -381,8 +381,11 @@ class MainFrame(ttk.Frame):
|
|||||||
refresh_branches_cb,
|
refresh_branches_cb,
|
||||||
checkout_branch_cb,
|
checkout_branch_cb,
|
||||||
create_branch_cb,
|
create_branch_cb,
|
||||||
refresh_changed_files_cb, # <-- NUOVO PARAMETRO
|
refresh_changed_files_cb,
|
||||||
open_diff_viewer_cb,
|
open_diff_viewer_cb,
|
||||||
|
add_selected_file_cb
|
||||||
|
|
||||||
|
|
||||||
):
|
):
|
||||||
"""Initializes the MainFrame with tabs."""
|
"""Initializes the MainFrame with tabs."""
|
||||||
super().__init__(master)
|
super().__init__(master)
|
||||||
@ -408,6 +411,7 @@ class MainFrame(ttk.Frame):
|
|||||||
self.checkout_branch_callback = checkout_branch_cb
|
self.checkout_branch_callback = checkout_branch_cb
|
||||||
self.create_branch_callback = create_branch_cb
|
self.create_branch_callback = create_branch_cb
|
||||||
self.open_diff_viewer_callback = open_diff_viewer_cb
|
self.open_diff_viewer_callback = open_diff_viewer_cb
|
||||||
|
self.add_selected_file_callback = add_selected_file_cb
|
||||||
|
|
||||||
|
|
||||||
# Store instances and initial data
|
# Store instances and initial data
|
||||||
@ -847,6 +851,9 @@ class MainFrame(ttk.Frame):
|
|||||||
self.changed_files_listbox.grid(row=0, column=0, sticky="nsew")
|
self.changed_files_listbox.grid(row=0, column=0, sticky="nsew")
|
||||||
# Associa doppio click all'apertura del diff viewer (verrà collegato in GitUtility)
|
# Associa doppio click all'apertura del diff viewer (verrà collegato in GitUtility)
|
||||||
self.changed_files_listbox.bind("<Double-Button-1>", self._on_changed_file_double_click)
|
self.changed_files_listbox.bind("<Double-Button-1>", self._on_changed_file_double_click)
|
||||||
|
# Usa <Button-3> per Windows/Linux, <Button-2> o <Control-Button-1> per macOS?
|
||||||
|
# <Button-3> è spesso il più compatibile per il tasto destro standard.
|
||||||
|
self.changed_files_listbox.bind("<Button-3>", self._show_changed_files_context_menu)
|
||||||
|
|
||||||
scrollbar_list = ttk.Scrollbar(
|
scrollbar_list = ttk.Scrollbar(
|
||||||
list_sub_frame, orient=tk.VERTICAL, command=self.changed_files_listbox.yview
|
list_sub_frame, orient=tk.VERTICAL, command=self.changed_files_listbox.yview
|
||||||
@ -865,10 +872,8 @@ class MainFrame(ttk.Frame):
|
|||||||
)
|
)
|
||||||
self.refresh_changes_button.grid(row=1, column=0, sticky="w", padx=(0, 5), pady=(5, 0))
|
self.refresh_changes_button.grid(row=1, column=0, sticky="w", padx=(0, 5), pady=(5, 0))
|
||||||
self.create_tooltip(self.refresh_changes_button, "Refresh the list of changed files.")
|
self.create_tooltip(self.refresh_changes_button, "Refresh the list of changed files.")
|
||||||
# --- FINE MODIFICA ---
|
self.changed_files_context_menu = tk.Menu(self.changed_files_listbox, tearoff=0)
|
||||||
|
|
||||||
|
|
||||||
# --- Pulsante Commit Manuale --- (Spostato sotto)
|
|
||||||
self.commit_button = ttk.Button(
|
self.commit_button = ttk.Button(
|
||||||
frame, # Ora nel frame principale
|
frame, # Ora nel frame principale
|
||||||
text="Commit All Changes Manually",
|
text="Commit All Changes Manually",
|
||||||
@ -1366,3 +1371,52 @@ class MainFrame(ttk.Frame):
|
|||||||
# Chiama il metodo del controller (verrà impostato in __init__ di MainFrame)
|
# Chiama il metodo del controller (verrà impostato in __init__ di MainFrame)
|
||||||
if hasattr(self, 'open_diff_viewer_callback') and callable(self.open_diff_viewer_callback):
|
if hasattr(self, 'open_diff_viewer_callback') and callable(self.open_diff_viewer_callback):
|
||||||
self.open_diff_viewer_callback(file_status_line)
|
self.open_diff_viewer_callback(file_status_line)
|
||||||
|
|
||||||
|
def _show_changed_files_context_menu(self, event):
|
||||||
|
"""Shows the context menu for the changed files listbox."""
|
||||||
|
# Seleziona l'elemento sotto il cursore
|
||||||
|
try:
|
||||||
|
# Identifica l'indice dell'elemento su cui si è cliccato
|
||||||
|
index = self.changed_files_listbox.nearest(event.y)
|
||||||
|
# Se l'indice è valido, selezionalo visivamente (opzionale ma carino)
|
||||||
|
# Cancella selezioni precedenti e seleziona quella nuova
|
||||||
|
self.changed_files_listbox.selection_clear(0, tk.END)
|
||||||
|
self.changed_files_listbox.selection_set(index)
|
||||||
|
self.changed_files_listbox.activate(index) # Evidenzia riga
|
||||||
|
except tk.TclError:
|
||||||
|
# Errore se si clicca su area vuota, non fare nulla
|
||||||
|
return
|
||||||
|
|
||||||
|
# Ottieni la riga di stato selezionata
|
||||||
|
selection_indices = self.changed_files_listbox.curselection()
|
||||||
|
if not selection_indices: return # Nessuna selezione valida
|
||||||
|
selected_line = self.changed_files_listbox.get(selection_indices[0])
|
||||||
|
|
||||||
|
# Pulisci il menu precedente
|
||||||
|
self.changed_files_context_menu.delete(0, tk.END)
|
||||||
|
|
||||||
|
# Controlla se il file è Untracked ('??')
|
||||||
|
is_untracked = selected_line.strip().startswith('??')
|
||||||
|
|
||||||
|
# Aggiungi l'opzione "Add" solo se è untracked e abbiamo la callback
|
||||||
|
if is_untracked and hasattr(self, 'add_selected_file_callback') and callable(self.add_selected_file_callback):
|
||||||
|
self.changed_files_context_menu.add_command(
|
||||||
|
label="Add to Staging Area",
|
||||||
|
# Chiama la callback del controller passando la linea selezionata
|
||||||
|
command=lambda line=selected_line: self.add_selected_file_callback(line)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# Opzionalmente, aggiungi una voce disabilitata o nessun'azione
|
||||||
|
self.changed_files_context_menu.add_command(label="Add to Staging Area", state=tk.DISABLED)
|
||||||
|
pass # Nessuna azione applicabile per ora
|
||||||
|
|
||||||
|
# Aggiungi altre eventuali azioni qui (es. "View Changes", "Discard Changes" - future)
|
||||||
|
# self.changed_files_context_menu.add_separator()
|
||||||
|
# self.changed_files_context_menu.add_command(label="View Changes (Diff)", ...)
|
||||||
|
|
||||||
|
# Mostra il menu alla posizione del mouse
|
||||||
|
try:
|
||||||
|
self.changed_files_context_menu.tk_popup(event.x_root, event.y_root)
|
||||||
|
finally:
|
||||||
|
# Assicura che il grab venga rilasciato
|
||||||
|
self.changed_files_context_menu.grab_release()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user