Spaces:
Sleeping
Sleeping
File size: 7,744 Bytes
feac656 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 | """
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) |