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
|
||||
config_manager_instance=self.config_manager,
|
||||
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) ---
|
||||
@ -1826,6 +1827,70 @@ class GitSvnSyncApp:
|
||||
self.master.destroy()
|
||||
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 ---
|
||||
def main():
|
||||
|
||||
@ -1178,3 +1178,48 @@ class GitCommands:
|
||||
except Exception as e:
|
||||
self.logger.exception(f"Unexpected error in get_file_content_from_ref for '{ref_path_arg}': {e}")
|
||||
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,
|
||||
checkout_branch_cb,
|
||||
create_branch_cb,
|
||||
refresh_changed_files_cb, # <-- NUOVO PARAMETRO
|
||||
refresh_changed_files_cb,
|
||||
open_diff_viewer_cb,
|
||||
add_selected_file_cb
|
||||
|
||||
|
||||
):
|
||||
"""Initializes the MainFrame with tabs."""
|
||||
super().__init__(master)
|
||||
@ -408,6 +411,7 @@ class MainFrame(ttk.Frame):
|
||||
self.checkout_branch_callback = checkout_branch_cb
|
||||
self.create_branch_callback = create_branch_cb
|
||||
self.open_diff_viewer_callback = open_diff_viewer_cb
|
||||
self.add_selected_file_callback = add_selected_file_cb
|
||||
|
||||
|
||||
# Store instances and initial data
|
||||
@ -847,6 +851,9 @@ class MainFrame(ttk.Frame):
|
||||
self.changed_files_listbox.grid(row=0, column=0, sticky="nsew")
|
||||
# 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)
|
||||
# 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(
|
||||
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.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(
|
||||
frame, # Ora nel frame principale
|
||||
text="Commit All Changes Manually",
|
||||
@ -1366,3 +1371,52 @@ class MainFrame(ttk.Frame):
|
||||
# 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):
|
||||
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