Spaces:
Sleeping
Sleeping
File size: 9,945 Bytes
0d91ffe 65ea2c6 503a15e 65ea2c6 503a15e 65ea2c6 503a15e 65ea2c6 503a15e 65ea2c6 503a15e 65ea2c6 503a15e 0d91ffe 503a15e 0d91ffe 503a15e 0d91ffe 503a15e 0d91ffe 503a15e 0d91ffe 503a15e 0d91ffe 503a15e 0d91ffe 503a15e 0d91ffe 503a15e | 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 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 | """Project handling utilities for Ada files and archives."""
import tempfile
import uuid
import os
import zipfile
import glob
import shutil
from src.agents.code_analyzer import CodeAnalyzerAgent
from src.agents.ada_converter import AdaConverterAgent
from src.agents.unit_test_generator import UnitTestGeneratorAgent
class ProjectHandler:
"""Handles Ada project operations including extraction, analysis, conversion, and download."""
def __init__(self, model):
"""Initialize ProjectHandler with model and create agents."""
self.model = model
self.analyzer = CodeAnalyzerAgent(model)
self.converter = AdaConverterAgent(model)
self.test_generator = UnitTestGeneratorAgent(model)
@staticmethod
def cleanup_old_projects(target_dir: str | None = None) -> None:
"""
Clean up old ada_project_* directories in the temp directory.
Args:
target_dir: Directory to clean up (defaults to system temp directory)
"""
if target_dir is None:
target_dir = tempfile.gettempdir()
# Find all ada_project_* directories
pattern = os.path.join(target_dir, "ada_project_*")
old_projects = glob.glob(pattern)
# Remove each directory
for project_dir in old_projects:
if os.path.isdir(project_dir):
try:
shutil.rmtree(project_dir)
except OSError:
# Ignore errors if directory can't be removed
pass
def unzip_project(self, zip_file: str, target_dir: str | None = None) -> str:
"""
Extract a zip file containing Ada project files.
Args:
zip_file: Path to the zip file
target_dir: Directory to extract to (defaults to system temp directory)
Returns:
Path to the extracted directory (unique UUID-based name)
"""
if target_dir is None:
target_dir = tempfile.gettempdir()
# Clean up old ada_project_* directories
self.cleanup_old_projects(target_dir)
# Generate unique directory name using UUID
unique_dir_name = f"ada_project_{uuid.uuid4().hex}"
extract_path = os.path.join(target_dir, unique_dir_name)
# Create the extraction directory
os.makedirs(extract_path, exist_ok=True)
# Extract zip file to extract_path
with zipfile.ZipFile(zip_file, 'r') as zip_ref:
zip_ref.extractall(extract_path)
return extract_path
@staticmethod
def build_directory_tree(directory_path: str) -> str:
"""
Build a visual directory tree representation.
Args:
directory_path: Path to the directory to build tree for
Returns:
String representation of directory tree suitable for Gradio display
"""
def _build_tree(path: str, prefix: str = "") -> str:
"""Recursively build tree structure."""
items = []
if not os.path.exists(path):
return ""
try:
# Get all items in directory
entries = sorted(os.listdir(path))
for i, entry in enumerate(entries):
entry_path = os.path.join(path, entry)
is_last_item = i == len(entries) - 1
# Choose appropriate tree symbols
current_prefix = "βββ " if is_last_item else "βββ "
next_prefix = prefix + (" " if is_last_item else "β ")
if os.path.isdir(entry_path):
items.append(f"{prefix}{current_prefix}{entry}/")
# Recursively add subdirectory contents
subtree = _build_tree(entry_path, next_prefix)
if subtree:
items.append(subtree)
else:
items.append(f"{prefix}{current_prefix}{entry}")
except PermissionError:
items.append(f"{prefix}[Permission Denied]")
return "\n".join(items)
# Start with root directory name
root_name = os.path.basename(directory_path) or directory_path
tree = f"{root_name}/\n"
tree += _build_tree(directory_path)
return tree
@staticmethod
def find_ada_files(extracted_path: str) -> list[str]:
"""Find all Ada files (.ads and .adb) in the extracted project."""
ada_files = []
for root, _, files in os.walk(extracted_path):
for file in files:
if file.endswith(('.ads', '.adb')):
ada_files.append(os.path.join(root, file))
return ada_files
def analyze_business_logic(self, ada_code: str) -> str:
"""Analyze Ada code to extract business logic."""
return self.analyzer.extract_business_logic(ada_code)
def convert_to_python(self, ada_code: str) -> str:
"""Convert Ada code to Python."""
return self.converter.convert_to_python(ada_code)
def generate_unit_tests(self, python_code: str) -> str:
"""Generate unit tests for Python code."""
return self.test_generator.generate_unit_tests(python_code)
def process_ada_file(self, ada_code: str) -> tuple[str, str, str]:
"""Process Ada code: analyze, convert to Python, and generate unit tests.
Args:
ada_code: The Ada source code to process
Returns:
Tuple of (analysis_result, python_code, unit_tests)
"""
# Analyze the Ada code
analysis_result = self.analyze_business_logic(ada_code)
# Convert Ada code to Python
python_code = self.convert_to_python(ada_code)
# Generate unit tests for the converted Python code
unit_tests = self.generate_unit_tests(python_code)
return analysis_result, python_code, unit_tests
def convert_and_download_project(self, extracted_path: str) -> str | None:
"""Convert all Ada files to Python and create downloadable zip with tests"""
if not extracted_path:
return None
try:
# Create temporary directory for converted files
temp_dir = tempfile.mkdtemp()
converted_root = os.path.join(temp_dir, "converted_project")
tests_dir = os.path.join(converted_root, "tests")
os.makedirs(converted_root, exist_ok=True)
os.makedirs(tests_dir, exist_ok=True)
# Find all Ada files (.ads and .adb)
ada_files = self.find_ada_files(extracted_path)
converted_files = []
# Convert each Ada file to Python
for ada_file in ada_files:
try:
# Read Ada file content
with open(ada_file, 'r', encoding='utf-8') as f:
ada_code = f.read()
# Convert to Python
python_code = self.convert_to_python(ada_code)
# Calculate relative path to preserve directory structure
rel_path = os.path.relpath(ada_file, extracted_path)
python_filename = os.path.splitext(rel_path)[0] + '.py'
python_file_path = os.path.join(converted_root, python_filename)
# Create directories if needed
os.makedirs(os.path.dirname(python_file_path), exist_ok=True)
# Write Python file
with open(python_file_path, 'w', encoding='utf-8') as f:
f.write(python_code)
converted_files.append((python_file_path, python_filename, python_code))
except Exception as e:
print(f"Error converting {ada_file}: {str(e)}")
continue
# Generate unit tests for each converted Python file
for python_file_path, python_filename, python_code in converted_files:
try:
# Generate unit tests from Python code string
unit_tests = self.generate_unit_tests(python_code)
# Create test file name
test_filename = f"test_{os.path.basename(python_filename)}"
test_file_path = os.path.join(tests_dir, test_filename)
# Write test file
with open(test_file_path, 'w', encoding='utf-8') as f:
f.write(unit_tests)
except Exception as e:
print(f"Error generating tests for {python_filename}: {str(e)}")
continue
# Create zip file
zip_path = os.path.join(temp_dir, "converted_ada_project.zip")
with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
for root, _, files in os.walk(converted_root):
for file in files:
file_path = os.path.join(root, file)
arcname = os.path.relpath(file_path, converted_root)
zipf.write(file_path, arcname)
return zip_path
except Exception as e:
print(f"Error in convert_and_download_project: {str(e)}")
return None |