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_spec_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
|
||||
|
||||
def _log(self, message: str, level: str = "INFO") -> None:
|
||||
@ -79,10 +79,128 @@ class ProjectManager:
|
||||
except TypeError:
|
||||
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:
|
||||
"""
|
||||
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.
|
||||
If the expected source folder is not found, searches for alternatives and asks the user.
|
||||
"""
|
||||
self._log(
|
||||
"=" * 20 + " PROJECT DIRECTORY SELECTION STARTED " + "=" * 20, level="INFO"
|
||||
@ -101,19 +219,61 @@ class ProjectManager:
|
||||
self.project_root_name = project_root.name
|
||||
project_name_lower = self.project_root_name.lower()
|
||||
|
||||
# Derived paths as strings for direct assignment to Tkinter variables/attributes
|
||||
self.derived_source_dir_path = project_root / project_name_lower
|
||||
# Try to find the source directory - first check the expected location
|
||||
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_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 = f"{project_name_lower}.ico"
|
||||
default_icon_filename = f"{source_folder_name}.ico"
|
||||
if sys.platform == "darwin":
|
||||
default_icon_filename = f"{project_name_lower}.icns"
|
||||
default_icon_filename = f"{source_folder_name}.icns"
|
||||
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._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)
|
||||
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():
|
||||
self.derived_script_label_val.config(
|
||||
text=str(main_script_path_obj), foreground="black"
|
||||
)
|
||||
self._log(f"Main script confirmed: {main_script_path_obj}", level="INFO")
|
||||
else:
|
||||
# This shouldn't happen anymore, but keep as safeguard
|
||||
self.derived_script_label_val.config(text="NOT FOUND!", foreground="red")
|
||||
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",
|
||||
)
|
||||
messagebox.showerror(
|
||||
"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,
|
||||
)
|
||||
return
|
||||
|
||||
if spec_path_obj.is_file():
|
||||
self.derived_spec_label_val.config(
|
||||
@ -172,18 +336,18 @@ class ProjectManager:
|
||||
)
|
||||
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 (
|
||||
isinstance(self.derived_source_dir_path, pathlib.Path)
|
||||
and not self.derived_source_dir_path.is_dir()
|
||||
):
|
||||
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",
|
||||
)
|
||||
|
||||
# Call the callback if project selection and initial path derivation are successful
|
||||
if main_script_path_obj.is_file() and self.on_project_selected_callback:
|
||||
# Call the callback - main script existence is guaranteed at this point
|
||||
if self.on_project_selected_callback:
|
||||
# Prepare a dictionary of derived paths to pass to the callback
|
||||
derived_paths_info: Dict[str, Any] = {
|
||||
"project_root_path": dir_path,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user