import os import shutil from setuptools import setup, Extension from Cython.Build import cythonize def build_project(): # 1. Сначала определяем все абсолютные пути, пока мы в исходной директории build_dir = os.path.dirname(os.path.abspath(__file__)) # папка build/ project_root = os.path.abspath(os.path.join(build_dir, "..")) # корень проекта source_app = os.path.join(project_root, "app") dist_dir = os.path.join(project_root, "dist") dist_app = os.path.join(dist_dir, "app") build_main_file = os.path.join(build_dir, "main.py") dist_main_file = os.path.join(dist_dir, "main.py") print("🚀 Старт сборки проекта...") # 2. Пересоздаем чистую папку dist/ if os.path.exists(dist_dir): shutil.rmtree(dist_dir) os.makedirs(dist_dir) # 3. Копируем исходный код app/ в dist/app/ shutil.copytree(source_app, dist_app) # Сохраняем текущую директорию корня, чтобы вернуться в неё в конце original_cwd = os.getcwd() # СИСТЕМНЫЙ СДВИГ: Переносим рабочую директорию процесса внутрь dist/app/ # Теперь для компилятора корнем является именно dist/app/ os.chdir(dist_app) # 4. Собираем модули для компиляции (сканируем текущую папку, так как мы уже внутри dist/app) extensions = [] for root, _, files in os.walk("."): for file in files: if file.endswith('.py') and not file.startswith('__'): full_path = os.path.join(root, file) # Вычисляем путь относительно dist/app clean_path = os.path.relpath(full_path, ".") # Формируем имя модуля для Python (например, workflows.graph_manager) module_name = clean_path.replace(os.sep, '.').rstrip('.py') if module_name == "run": extensions.append(Extension("run", [clean_path])) else: extensions.append(Extension(module_name, [clean_path])) # 5. Запускаем компиляцию (теперь --inplace положит бинарники строго в dist/app/) setup( name="AppBinary", script_args=["build_ext", "--inplace"], ext_modules=cythonize( extensions, language_level="3", compiler_directives={ 'annotation_typing': False, # Отключаем строгую типизацию (фиксит max_tokens) 'binding': True, # Сохраняем Python-совместимость методов 'always_allow_keywords': True # Разрешаем передачу None в именованные аргументы } ), ) # 6. Очищаем dist/app/ от исходного кода print("\n🧹 Удаление исходного кода из папки dist/app/...") for root, _, files in os.walk("."): for file in files: if (file.endswith('.py') and not file.startswith('__')) or file.endswith('.c'): try: os.remove(os.path.join(root, file)) except OSError: pass # Удаляем временную папку сборки компилятора C++ if os.path.exists("build"): shutil.rmtree("build") # Возвращаем рабочую директорию обратно в корень проекта os.chdir(original_cwd) # 7. Копируем файл build/main.py в dist/main.py if os.path.exists(build_main_file): shutil.copy(build_main_file, dist_main_file) print("📄 Файл build/main.py успешно скопирован в dist/main.py") else: print("⚠️ Ошибка: Файл build/main.py не найден, нечего копировать!") print("\n✅ Сборка успешно завершена! Папка dist/ готова к деплою.") if __name__ == "__main__": build_project()