добавила автоматическое разрешение зависимостей
This commit is contained in:
45
mypkg/core/dependency_resolver.py
Normal file
45
mypkg/core/dependency_resolver.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# mypkg/core/dependency_resolver.py
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
from typing import List, Set, Dict
|
||||||
|
from ..models.package import Package
|
||||||
|
|
||||||
|
|
||||||
|
class DependencyResolver:
|
||||||
|
def __init__(self, repo_path: str, installed: Dict[str, Package]):
|
||||||
|
self.repo_path = repo_path
|
||||||
|
self.installed = installed
|
||||||
|
self.visited = set()
|
||||||
|
|
||||||
|
def resolve(self, target_name: str) -> List[Package]:
|
||||||
|
"""Возвращает список пакетов для установки в правильном порядке"""
|
||||||
|
self.visited.clear()
|
||||||
|
to_install = [] # используем список вместо множества
|
||||||
|
self._resolve_recursive(target_name, to_install)
|
||||||
|
return to_install
|
||||||
|
|
||||||
|
def _resolve_recursive(self, pkg_name: str, to_install: List[Package]):
|
||||||
|
if pkg_name in self.visited:
|
||||||
|
return
|
||||||
|
self.visited.add(pkg_name)
|
||||||
|
|
||||||
|
if pkg_name in self.installed:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Читаем meta.json пакета
|
||||||
|
meta_path = os.path.join(self.repo_path, "packages", pkg_name, "meta.json")
|
||||||
|
if not os.path.exists(meta_path):
|
||||||
|
raise Exception(f"Зависимость '{pkg_name}' не найдена в репозитории")
|
||||||
|
|
||||||
|
with open(meta_path, 'r') as f:
|
||||||
|
pkg_data = json.load(f)
|
||||||
|
|
||||||
|
pkg = Package(**pkg_data)
|
||||||
|
|
||||||
|
# Сначала обрабатываем зависимости
|
||||||
|
for dep in pkg.depends:
|
||||||
|
self._resolve_recursive(dep, to_install)
|
||||||
|
|
||||||
|
# Добавляем текущий пакет (если ещё не добавлен)
|
||||||
|
if pkg not in to_install:
|
||||||
|
to_install.append(pkg)
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
# mypkg/core/package_manager.py
|
# mypkg/core/package_manager.py
|
||||||
|
from .dependency_resolver import DependencyResolver
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
@@ -24,62 +25,63 @@ class PackageManager:
|
|||||||
self.sandbox_mode = False
|
self.sandbox_mode = False
|
||||||
|
|
||||||
self.db = DatabaseManager(self.root)
|
self.db = DatabaseManager(self.root)
|
||||||
|
self.resolver = DependencyResolver(repo_path, self.db.installed)
|
||||||
|
|
||||||
def install(self, package_name: str, dry_run: bool = False) -> bool:
|
def install(self, package_name: str, dry_run: bool = False) -> bool:
|
||||||
print_step(f"Поиск пакета {package_name}...")
|
# DRY-RUN: показываем, что будет
|
||||||
|
|
||||||
meta_path = os.path.join(self.repo_path, "packages", package_name, "meta.json")
|
|
||||||
|
|
||||||
if not os.path.exists(meta_path):
|
|
||||||
print_error(f"Пакет {package_name} не найден")
|
|
||||||
return False
|
|
||||||
|
|
||||||
with open(meta_path, 'r') as f:
|
|
||||||
pkg_data = json.load(f)
|
|
||||||
|
|
||||||
pkg = Package(**pkg_data)
|
|
||||||
|
|
||||||
if self.db.is_installed(package_name):
|
|
||||||
print_warning(f"Пакет {package_name} уже установлен")
|
|
||||||
return True
|
|
||||||
|
|
||||||
# DRY-RUN: только показываем, ничего не делаем
|
|
||||||
if dry_run:
|
if dry_run:
|
||||||
print("🔍 РЕЖИМ DRY-RUN (ничего не устанавливается)")
|
print("🔍 РЕЖИМ DRY-RUN (ничего не устанавливается)")
|
||||||
print(f"\n📦 Будет установлен: {pkg.full_name()}")
|
try:
|
||||||
if pkg.depends:
|
to_install = self.resolver.resolve(package_name)
|
||||||
print(f" Зависимости: {', '.join(pkg.depends)}")
|
except Exception as e:
|
||||||
else:
|
print_error(f"Ошибка: {e}")
|
||||||
print(f" Зависимости: нет")
|
return False
|
||||||
print(f" Файлы ({len(pkg.files)}):")
|
|
||||||
for f in pkg.files:
|
print(f"\n📦 Будет установлено:")
|
||||||
print(f" {f['destination']}")
|
for pkg in to_install:
|
||||||
if self.sandbox_mode:
|
print(f" {pkg.full_name()}")
|
||||||
print(f"\n🏖️ Установка будет выполнена в песочницу: {self.root}")
|
if pkg.depends:
|
||||||
|
print(f" Зависимости: {', '.join(pkg.depends)}")
|
||||||
print(f"\n✅ Установка не произведена (dry-run)")
|
print(f"\n✅ Установка не произведена (dry-run)")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# РЕАЛЬНАЯ УСТАНОВКА
|
# РЕАЛЬНАЯ УСТАНОВКА
|
||||||
print_package(f"Установка {pkg.full_name()}...")
|
print_step(f"Поиск пакета {package_name}...")
|
||||||
|
|
||||||
source_dir = os.path.join(self.repo_path, "packages", package_name, "files")
|
# 1. Разрешаем зависимости
|
||||||
|
try:
|
||||||
|
to_install = self.resolver.resolve(package_name)
|
||||||
|
except Exception as e:
|
||||||
|
print_error(f"Ошибка разрешения зависимостей: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
for file_info in pkg.files:
|
# 2. Устанавливаем всё по порядку
|
||||||
src = os.path.join(source_dir, file_info["source"])
|
for pkg in to_install:
|
||||||
dst = os.path.join(self.root, file_info["destination"].lstrip("/"))
|
if self.db.is_installed(pkg.name):
|
||||||
|
print_info(f"{pkg.name} уже установлен")
|
||||||
|
continue
|
||||||
|
|
||||||
os.makedirs(os.path.dirname(dst), exist_ok=True)
|
print_step(f"Установка {pkg.full_name()}...")
|
||||||
shutil.copy2(src, dst)
|
|
||||||
|
|
||||||
if "permissions" in file_info:
|
source_dir = os.path.join(self.repo_path, "packages", pkg.name, "files")
|
||||||
os.chmod(dst, file_info["permissions"])
|
|
||||||
|
|
||||||
self.db.add_package(pkg)
|
for file_info in pkg.files:
|
||||||
print_success(f"Пакет {package_name} установлен")
|
src = os.path.join(source_dir, file_info["source"])
|
||||||
|
dst = os.path.join(self.root, file_info["destination"].lstrip("/"))
|
||||||
|
|
||||||
|
os.makedirs(os.path.dirname(dst), exist_ok=True)
|
||||||
|
shutil.copy2(src, dst)
|
||||||
|
|
||||||
|
if "permissions" in file_info:
|
||||||
|
os.chmod(dst, file_info["permissions"])
|
||||||
|
|
||||||
|
self.db.add_package(pkg)
|
||||||
|
print_success(f"{pkg.name} установлен")
|
||||||
|
|
||||||
if self.sandbox_mode:
|
if self.sandbox_mode:
|
||||||
print_info(f"Файлы в: {self.root}")
|
print_info(f"Файлы в: {self.root}")
|
||||||
|
|
||||||
|
print_success(f"Пакет {package_name} и его зависимости установлены")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def remove(self, package_name: str, force: bool = False, dry_run: bool = False) -> bool:
|
def remove(self, package_name: str, force: bool = False, dry_run: bool = False) -> bool:
|
||||||
|
|||||||
13
repo/packages/libncurses/meta.json
Normal file
13
repo/packages/libncurses/meta.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"name": "libncurses",
|
||||||
|
"version": "6.2",
|
||||||
|
"description": "Библиотека для работы с терминалом",
|
||||||
|
"depends": [],
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"source": "usr/lib/libncurses.so.6",
|
||||||
|
"destination": "/usr/lib/libncurses.so.6",
|
||||||
|
"permissions": 644
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user