Spaces:
Sleeping
Sleeping
| """ | |
| ZIP utilities for handling Ada project ZIP files and creating Python project ZIP files. | |
| """ | |
| import os | |
| import tempfile | |
| import zipfile | |
| import shutil | |
| from pathlib import Path | |
| from typing import Tuple, Optional | |
| from loguru import logger | |
| class ZipHandler: | |
| """Handles ZIP file operations for Ada to Python conversion.""" | |
| def __init__(self): | |
| self.temp_base_dir = Path(tempfile.gettempdir()) / "ada-conversion" | |
| # Clean up any existing sessions from previous runs | |
| self._cleanup_previous_sessions() | |
| self.temp_base_dir.mkdir(exist_ok=True) | |
| logger.debug("ZIP handler initialized", temp_dir=str(self.temp_base_dir)) | |
| def _cleanup_previous_sessions(self) -> None: | |
| """Clean up any existing session directories from previous runs.""" | |
| if self.temp_base_dir.exists(): | |
| logger.debug("Cleaning up previous sessions", temp_base=str(self.temp_base_dir)) | |
| shutil.rmtree(self.temp_base_dir) | |
| def is_zip_file(self, file_path: str) -> bool: | |
| """ | |
| Check if the given file path is a ZIP file. | |
| Args: | |
| file_path: Path to the file to check | |
| Returns: | |
| True if the file is a ZIP file, False otherwise | |
| """ | |
| try: | |
| path = Path(file_path) | |
| if not path.exists() or not path.is_file(): | |
| return False | |
| # Check file extension | |
| if path.suffix.lower() != '.zip': | |
| return False | |
| # Verify it's actually a ZIP file by trying to open it | |
| with zipfile.ZipFile(path, 'r') as zip_file: | |
| # Try to read the file list | |
| zip_file.namelist() | |
| return True | |
| except (zipfile.BadZipFile, Exception): | |
| return False | |
| def extract_ada_project(self, zip_path: str, session_id: Optional[str] = None) -> Tuple[str, str]: | |
| """ | |
| Extract Ada project ZIP file to temporary directory. | |
| Args: | |
| zip_path: Path to the ZIP file containing Ada project | |
| session_id: Optional session ID for unique directory naming | |
| Returns: | |
| Tuple of (extracted_project_path, temp_session_dir) | |
| Raises: | |
| FileNotFoundError: If ZIP file doesn't exist | |
| zipfile.BadZipFile: If file is not a valid ZIP | |
| ValueError: If no Ada files found in ZIP | |
| """ | |
| zip_path = Path(zip_path) | |
| if not zip_path.exists(): | |
| raise FileNotFoundError(f"ZIP file does not exist: {zip_path}") | |
| if not self.is_zip_file(str(zip_path)): | |
| raise zipfile.BadZipFile(f"Not a valid ZIP file: {zip_path}") | |
| # Create unique session directory | |
| if session_id is None: | |
| session_id = f"session_{os.getpid()}_{zip_path.stem}" | |
| session_dir = self.temp_base_dir / session_id | |
| session_dir.mkdir(parents=True, exist_ok=True) | |
| logger.info("Extracting Ada project ZIP", | |
| zip_file=str(zip_path), | |
| extract_to=str(session_dir)) | |
| # Extract ZIP file | |
| with zipfile.ZipFile(zip_path, 'r') as zip_file: | |
| zip_file.extractall(session_dir) | |
| # Find the Ada project directory within the extracted content | |
| ada_project_path = self._find_ada_project_root(session_dir) | |
| if ada_project_path is None: | |
| raise ValueError(f"No Ada files found in ZIP: {zip_path}") | |
| logger.success("Ada project extracted successfully", | |
| ada_project=str(ada_project_path), | |
| ada_files_found=len(list(ada_project_path.rglob("*.ad[s|b]"))) + len(list(ada_project_path.rglob("*.ada"))), | |
| session_dir=str(session_dir)) | |
| return str(ada_project_path), str(session_dir) | |
| def _find_ada_project_root(self, extracted_dir: Path) -> Optional[Path]: | |
| """ | |
| Find the root directory containing Ada files within extracted content. | |
| Args: | |
| extracted_dir: Directory where ZIP was extracted | |
| Returns: | |
| Path to Ada project root, or None if no Ada files found | |
| """ | |
| ada_extensions = {'.ads', '.adb', '.ada'} | |
| # Check if extracted_dir itself contains Ada files | |
| ada_files = [] | |
| for ext in ada_extensions: | |
| ada_files.extend(list(extracted_dir.rglob(f"*{ext}"))) | |
| if not ada_files: | |
| return None | |
| # Find the common parent directory of all Ada files | |
| if len(ada_files) == 1: | |
| # If only one file, its parent is the project root | |
| return ada_files[0].parent | |
| # Find common parent of all Ada files | |
| common_parent = Path(ada_files[0]).parent | |
| for ada_file in ada_files[1:]: | |
| # Find common path between current common_parent and this file's parent | |
| try: | |
| # Get relative path from common_parent to this file's parent | |
| ada_file.parent.relative_to(common_parent) | |
| except ValueError: | |
| # Files are in different branches, need to go up | |
| while True: | |
| try: | |
| ada_file.parent.relative_to(common_parent) | |
| break | |
| except ValueError: | |
| common_parent = common_parent.parent | |
| if common_parent == extracted_dir.parent: | |
| # Gone too far up | |
| common_parent = extracted_dir | |
| break | |
| return common_parent | |
| def create_python_project_zip(self, python_project_path: str, output_zip_path: Optional[str] = None) -> str: | |
| """ | |
| Create a ZIP file from the generated Python project. | |
| Args: | |
| python_project_path: Path to the Python project directory | |
| output_zip_path: Optional output ZIP path (defaults to project_name.zip) | |
| Returns: | |
| Path to the created ZIP file | |
| Raises: | |
| FileNotFoundError: If Python project directory doesn't exist | |
| """ | |
| project_path = Path(python_project_path) | |
| if not project_path.exists(): | |
| raise FileNotFoundError(f"Python project directory does not exist: {python_project_path}") | |
| if not project_path.is_dir(): | |
| raise ValueError(f"Path is not a directory: {python_project_path}") | |
| # Determine output ZIP path | |
| if output_zip_path is None: | |
| output_zip_path = str(project_path.parent / f"{project_path.name}.zip") | |
| output_zip_path = Path(output_zip_path) | |
| logger.info("Creating Python project ZIP", | |
| python_project=str(project_path), | |
| output_zip=str(output_zip_path)) | |
| # Create ZIP file | |
| with zipfile.ZipFile(output_zip_path, 'w', zipfile.ZIP_DEFLATED) as zip_file: | |
| for file_path in project_path.rglob('*'): | |
| if file_path.is_file(): | |
| # Get relative path within the project | |
| relative_path = file_path.relative_to(project_path) | |
| zip_file.write(file_path, relative_path) | |
| logger.success("Python project ZIP created", | |
| zip_file=str(output_zip_path), | |
| zip_size=f"{output_zip_path.stat().st_size / (1024*1024):.1f} MB") | |
| return str(output_zip_path) |