aggiunta la possibilità di gestire repository che hanno nomi diversi rispetto la cartella del sorgente
This commit is contained in:
parent
07423ab4d0
commit
42aa62a1b2
@ -69,7 +69,7 @@ class ProjectManager:
|
|||||||
self.derived_main_script_path: Optional[str] = None
|
self.derived_main_script_path: Optional[str] = None
|
||||||
self.derived_spec_path: Optional[str] = None
|
self.derived_spec_path: Optional[str] = None
|
||||||
self.derived_icon_path: Optional[str] = None
|
self.derived_icon_path: Optional[str] = None
|
||||||
self.derived_source_dir_path: Optional[path.Path] = None # pathlib.Path object
|
self.derived_source_dir_path: Optional[pathlib.Path] = None # pathlib.Path object
|
||||||
self.project_root_name: Optional[str] = None
|
self.project_root_name: Optional[str] = None
|
||||||
|
|
||||||
def _log(self, message: str, level: str = "INFO") -> None:
|
def _log(self, message: str, level: str = "INFO") -> None:
|
||||||
@ -79,10 +79,128 @@ class ProjectManager:
|
|||||||
except TypeError:
|
except TypeError:
|
||||||
self.logger(f"[{level}][ProjectManager] {message}")
|
self.logger(f"[{level}][ProjectManager] {message}")
|
||||||
|
|
||||||
|
def _find_source_folders_with_main(self, project_root: pathlib.Path) -> list[pathlib.Path]:
|
||||||
|
"""
|
||||||
|
Finds all direct subdirectories of the project root that contain a __main__.py file.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
project_root: The root directory of the project.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A list of Path objects representing subdirectories containing __main__.py.
|
||||||
|
"""
|
||||||
|
candidates = []
|
||||||
|
try:
|
||||||
|
for item in project_root.iterdir():
|
||||||
|
if item.is_dir() and not item.name.startswith('.') and not item.name.startswith('_'):
|
||||||
|
main_script = item / "__main__.py"
|
||||||
|
if main_script.is_file():
|
||||||
|
candidates.append(item)
|
||||||
|
self._log(f"Found candidate source folder: {item.name}", level="DEBUG")
|
||||||
|
except Exception as e:
|
||||||
|
self._log(f"Error scanning directory: {e}", level="ERROR")
|
||||||
|
|
||||||
|
return candidates
|
||||||
|
|
||||||
|
def _ask_user_for_source_folder(self, project_root: pathlib.Path, candidates: list[pathlib.Path]) -> Optional[pathlib.Path]:
|
||||||
|
"""
|
||||||
|
Asks the user to select the correct source folder either from candidates or by manual selection.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
project_root: The root directory of the project.
|
||||||
|
candidates: List of candidate folders found automatically.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The selected source folder Path, or None if cancelled.
|
||||||
|
"""
|
||||||
|
dialog = tk.Toplevel(self.parent_gui)
|
||||||
|
dialog.title("Select Source Folder")
|
||||||
|
dialog.geometry("600x400")
|
||||||
|
dialog.transient(self.parent_gui)
|
||||||
|
dialog.grab_set()
|
||||||
|
|
||||||
|
selected_folder = None
|
||||||
|
|
||||||
|
def on_select():
|
||||||
|
nonlocal selected_folder
|
||||||
|
selection = listbox.curselection()
|
||||||
|
if selection:
|
||||||
|
idx = selection[0]
|
||||||
|
if idx < len(candidates):
|
||||||
|
selected_folder = candidates[idx]
|
||||||
|
dialog.destroy()
|
||||||
|
|
||||||
|
def on_browse():
|
||||||
|
nonlocal selected_folder
|
||||||
|
folder = filedialog.askdirectory(
|
||||||
|
title="Select the source folder containing __main__.py",
|
||||||
|
initialdir=str(project_root),
|
||||||
|
parent=dialog
|
||||||
|
)
|
||||||
|
if folder:
|
||||||
|
folder_path = pathlib.Path(folder)
|
||||||
|
# Verify it contains __main__.py
|
||||||
|
if (folder_path / "__main__.py").is_file():
|
||||||
|
selected_folder = folder_path
|
||||||
|
dialog.destroy()
|
||||||
|
else:
|
||||||
|
messagebox.showerror(
|
||||||
|
"Invalid Selection",
|
||||||
|
f"The selected folder does not contain a __main__.py file.",
|
||||||
|
parent=dialog
|
||||||
|
)
|
||||||
|
|
||||||
|
def on_cancel():
|
||||||
|
dialog.destroy()
|
||||||
|
|
||||||
|
# Message label
|
||||||
|
msg_frame = ttk.Frame(dialog, padding=10)
|
||||||
|
msg_frame.pack(fill=tk.X)
|
||||||
|
|
||||||
|
if candidates:
|
||||||
|
msg_text = "Multiple source folders found. Please select the correct one:"
|
||||||
|
else:
|
||||||
|
msg_text = "No source folder found automatically. Please browse to select the folder containing __main__.py:"
|
||||||
|
|
||||||
|
ttk.Label(msg_frame, text=msg_text, wraplength=560).pack()
|
||||||
|
|
||||||
|
# Listbox with candidates
|
||||||
|
if candidates:
|
||||||
|
list_frame = ttk.Frame(dialog, padding=10)
|
||||||
|
list_frame.pack(fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
|
scrollbar = ttk.Scrollbar(list_frame)
|
||||||
|
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
|
||||||
|
|
||||||
|
listbox = tk.Listbox(list_frame, yscrollcommand=scrollbar.set)
|
||||||
|
listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
||||||
|
scrollbar.config(command=listbox.yview)
|
||||||
|
|
||||||
|
for candidate in candidates:
|
||||||
|
listbox.insert(tk.END, candidate.name)
|
||||||
|
|
||||||
|
listbox.bind('<Double-Button-1>', lambda e: on_select())
|
||||||
|
else:
|
||||||
|
listbox = None
|
||||||
|
|
||||||
|
# Buttons
|
||||||
|
btn_frame = ttk.Frame(dialog, padding=10)
|
||||||
|
btn_frame.pack(fill=tk.X)
|
||||||
|
|
||||||
|
if candidates:
|
||||||
|
ttk.Button(btn_frame, text="Select", command=on_select).pack(side=tk.LEFT, padx=5)
|
||||||
|
|
||||||
|
ttk.Button(btn_frame, text="Browse...", command=on_browse).pack(side=tk.LEFT, padx=5)
|
||||||
|
ttk.Button(btn_frame, text="Cancel", command=on_cancel).pack(side=tk.RIGHT, padx=5)
|
||||||
|
|
||||||
|
dialog.wait_window()
|
||||||
|
return selected_folder
|
||||||
|
|
||||||
def select_project_directory(self) -> None:
|
def select_project_directory(self) -> None:
|
||||||
"""
|
"""
|
||||||
Opens a file dialog for the user to select the main project directory.
|
Opens a file dialog for the user to select the main project directory.
|
||||||
Derives and updates paths for the main script, .spec file, and icon.
|
Derives and updates paths for the main script, .spec file, and icon.
|
||||||
|
If the expected source folder is not found, searches for alternatives and asks the user.
|
||||||
"""
|
"""
|
||||||
self._log(
|
self._log(
|
||||||
"=" * 20 + " PROJECT DIRECTORY SELECTION STARTED " + "=" * 20, level="INFO"
|
"=" * 20 + " PROJECT DIRECTORY SELECTION STARTED " + "=" * 20, level="INFO"
|
||||||
@ -101,19 +219,61 @@ class ProjectManager:
|
|||||||
self.project_root_name = project_root.name
|
self.project_root_name = project_root.name
|
||||||
project_name_lower = self.project_root_name.lower()
|
project_name_lower = self.project_root_name.lower()
|
||||||
|
|
||||||
# Derived paths as strings for direct assignment to Tkinter variables/attributes
|
# Try to find the source directory - first check the expected location
|
||||||
self.derived_source_dir_path = project_root / project_name_lower
|
expected_source_dir = project_root / project_name_lower
|
||||||
|
source_folder_name = project_name_lower # Default to expected name
|
||||||
|
|
||||||
|
if (expected_source_dir / "__main__.py").is_file():
|
||||||
|
# Expected location found - use it
|
||||||
|
self.derived_source_dir_path = expected_source_dir
|
||||||
|
self._log(f"Using expected source folder: {source_folder_name}", level="INFO")
|
||||||
|
else:
|
||||||
|
# Expected location not found - search for alternatives
|
||||||
|
self._log(f"Expected source folder '{project_name_lower}' not found or does not contain __main__.py", level="WARNING")
|
||||||
|
self._log("Searching for alternative source folders...", level="INFO")
|
||||||
|
|
||||||
|
candidates = self._find_source_folders_with_main(project_root)
|
||||||
|
|
||||||
|
if len(candidates) == 1:
|
||||||
|
# Only one candidate found - use it automatically
|
||||||
|
self.derived_source_dir_path = candidates[0]
|
||||||
|
source_folder_name = candidates[0].name
|
||||||
|
self._log(f"Automatically selected single candidate: {source_folder_name}", level="INFO")
|
||||||
|
elif len(candidates) > 1:
|
||||||
|
# Multiple candidates - ask user to choose
|
||||||
|
self._log(f"Found {len(candidates)} candidate folders, asking user to select...", level="INFO")
|
||||||
|
selected = self._ask_user_for_source_folder(project_root, candidates)
|
||||||
|
if selected:
|
||||||
|
self.derived_source_dir_path = selected
|
||||||
|
source_folder_name = selected.name
|
||||||
|
self._log(f"User selected source folder: {source_folder_name}", level="INFO")
|
||||||
|
else:
|
||||||
|
self._log("User cancelled source folder selection.", level="INFO")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
# No candidates found - ask user to browse
|
||||||
|
self._log("No source folders with __main__.py found, asking user to browse...", level="WARNING")
|
||||||
|
selected = self._ask_user_for_source_folder(project_root, [])
|
||||||
|
if selected:
|
||||||
|
self.derived_source_dir_path = selected
|
||||||
|
source_folder_name = selected.name
|
||||||
|
self._log(f"User selected source folder: {source_folder_name}", level="INFO")
|
||||||
|
else:
|
||||||
|
self._log("User cancelled source folder selection.", level="INFO")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Now derive paths using the determined source folder name
|
||||||
self.derived_main_script_path = str(
|
self.derived_main_script_path = str(
|
||||||
self.derived_source_dir_path / "__main__.py"
|
self.derived_source_dir_path / "__main__.py"
|
||||||
)
|
)
|
||||||
self.derived_spec_path = str(project_root / f"{project_name_lower}.spec")
|
self.derived_spec_path = str(project_root / f"{source_folder_name}.spec")
|
||||||
|
|
||||||
# Default icon filename based on platform
|
# Default icon filename based on platform
|
||||||
default_icon_filename = f"{project_name_lower}.ico"
|
default_icon_filename = f"{source_folder_name}.ico"
|
||||||
if sys.platform == "darwin":
|
if sys.platform == "darwin":
|
||||||
default_icon_filename = f"{project_name_lower}.icns"
|
default_icon_filename = f"{source_folder_name}.icns"
|
||||||
elif sys.platform != "win32":
|
elif sys.platform != "win32":
|
||||||
default_icon_filename = f"{project_name_lower}.png"
|
default_icon_filename = f"{source_folder_name}.png"
|
||||||
self.derived_icon_path = str(project_root / default_icon_filename)
|
self.derived_icon_path = str(project_root / default_icon_filename)
|
||||||
|
|
||||||
self._log(f"Derived project name: {self.project_root_name}", level="DEBUG")
|
self._log(f"Derived project name: {self.project_root_name}", level="DEBUG")
|
||||||
@ -134,21 +294,25 @@ class ProjectManager:
|
|||||||
spec_path_obj = pathlib.Path(self.derived_spec_path)
|
spec_path_obj = pathlib.Path(self.derived_spec_path)
|
||||||
icon_path_obj = pathlib.Path(self.derived_icon_path)
|
icon_path_obj = pathlib.Path(self.derived_icon_path)
|
||||||
|
|
||||||
|
# At this point, main script should always exist since we verified it during folder selection
|
||||||
if main_script_path_obj.is_file():
|
if main_script_path_obj.is_file():
|
||||||
self.derived_script_label_val.config(
|
self.derived_script_label_val.config(
|
||||||
text=str(main_script_path_obj), foreground="black"
|
text=str(main_script_path_obj), foreground="black"
|
||||||
)
|
)
|
||||||
|
self._log(f"Main script confirmed: {main_script_path_obj}", level="INFO")
|
||||||
else:
|
else:
|
||||||
|
# This shouldn't happen anymore, but keep as safeguard
|
||||||
self.derived_script_label_val.config(text="NOT FOUND!", foreground="red")
|
self.derived_script_label_val.config(text="NOT FOUND!", foreground="red")
|
||||||
self._log(
|
self._log(
|
||||||
f"Error: Main script not found in the expected location: {main_script_path_obj}",
|
f"Error: Main script not found: {main_script_path_obj}",
|
||||||
level="ERROR",
|
level="ERROR",
|
||||||
)
|
)
|
||||||
messagebox.showerror(
|
messagebox.showerror(
|
||||||
"Invalid Project Structure",
|
"Invalid Project Structure",
|
||||||
f"Main script not found in expected location:\n{main_script_path_obj}",
|
f"Main script not found:\n{main_script_path_obj}",
|
||||||
parent=self.parent_gui,
|
parent=self.parent_gui,
|
||||||
)
|
)
|
||||||
|
return
|
||||||
|
|
||||||
if spec_path_obj.is_file():
|
if spec_path_obj.is_file():
|
||||||
self.derived_spec_label_val.config(
|
self.derived_spec_label_val.config(
|
||||||
@ -172,18 +336,18 @@ class ProjectManager:
|
|||||||
)
|
)
|
||||||
self.icon_path_var.set("") # Clear icon path if default not found
|
self.icon_path_var.set("") # Clear icon path if default not found
|
||||||
|
|
||||||
# Check if derived source directory actually exists
|
# Source directory should always exist at this point
|
||||||
if (
|
if (
|
||||||
isinstance(self.derived_source_dir_path, pathlib.Path)
|
isinstance(self.derived_source_dir_path, pathlib.Path)
|
||||||
and not self.derived_source_dir_path.is_dir()
|
and not self.derived_source_dir_path.is_dir()
|
||||||
):
|
):
|
||||||
self._log(
|
self._log(
|
||||||
f"Warning: Expected source directory '{self.derived_source_dir_path.name}' does not exist. This might be an issue if it's essential for the project structure.",
|
f"Warning: Source directory '{self.derived_source_dir_path.name}' does not exist.",
|
||||||
level="WARNING",
|
level="WARNING",
|
||||||
)
|
)
|
||||||
|
|
||||||
# Call the callback if project selection and initial path derivation are successful
|
# Call the callback - main script existence is guaranteed at this point
|
||||||
if main_script_path_obj.is_file() and self.on_project_selected_callback:
|
if self.on_project_selected_callback:
|
||||||
# Prepare a dictionary of derived paths to pass to the callback
|
# Prepare a dictionary of derived paths to pass to the callback
|
||||||
derived_paths_info: Dict[str, Any] = {
|
derived_paths_info: Dict[str, Any] = {
|
||||||
"project_root_path": dir_path,
|
"project_root_path": dir_path,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user