приведение кода к PEP 8, добавление комментариев, финальные правки

This commit is contained in:
2026-05-26 09:58:26 +03:00
parent 70c5e441ae
commit df8049e4a3
17 changed files with 647 additions and 170 deletions

View File

@@ -1,9 +1,19 @@
# mypkg/core/package_manager.py
from .dependency_resolver import DependencyResolver
"""
Главный модуль менеджера пакетов.
Содержит класс PackageManager, который управляет:
- установкой пакетов (с зависимостями)
- удалением пакетов
- получением информации о пакетах
- поиском пакетов в репозитории
"""
import json
import os
import shutil
from typing import List
from .dependency_resolver import DependencyResolver
from ..models.package import Package
from ..database.db_manager import DatabaseManager
from ..utils.colors import (
@@ -13,22 +23,52 @@ from ..utils.colors import (
class PackageManager:
"""
Главный класс менеджера пакетов.
Координирует работу всех компонентов:
- DatabaseManager — для хранения установленных пакетов
- DependencyResolver — для разрешения зависимостей
Позволяет устанавливать, удалять, искать пакеты и получать о них информацию.
"""
def __init__(self, repo_path: str = "repo", sandbox: str = None):
"""
Инициализация менеджера пакетов.
Args:
repo_path: путь к папке с репозиторием (по умолчанию "repo")
sandbox: путь к песочнице (если указан — установка в эту папку,
иначе в реальную систему "/")
"""
self.repo_path = repo_path
# Настройка режима песочницы
if sandbox:
self.root = sandbox
self.root = sandbox # корень для установки
self.sandbox_mode = True
print_sandbox_mode(self.root)
else:
self.root = "/"
self.root = "/" # реальная файловая система
self.sandbox_mode = False
# Создаём компоненты менеджера
self.db = DatabaseManager(self.root)
self.resolver = DependencyResolver(repo_path, self.db.installed)
def install(self, package_name: str, dry_run: bool = False) -> bool:
# DRY-RUN: показываем, что будет
"""
Устанавливает пакет и все его зависимости.
Аргументы:
package_name: имя пакета для установки (например, "nano")
dry_run: если True — только показать, что будет сделано
Возвращает:
True — установка успешна, False — ошибка
"""
# === РЕЖИМ DRY-RUN (только показать) ===
if dry_run:
print("🔍 РЕЖИМ DRY-RUN (ничего не устанавливается)")
try:
@@ -36,7 +76,7 @@ class PackageManager:
except Exception as e:
print_error(f"Ошибка: {e}")
return False
print(f"\n📦 Будет установлено:")
for pkg in to_install:
print(f" {pkg.full_name()}")
@@ -44,56 +84,82 @@ class PackageManager:
print(f" Зависимости: {', '.join(pkg.depends)}")
print(f"\n✅ Установка не произведена (dry-run)")
return True
# РЕАЛЬНАЯ УСТАНОВКА
# === РЕАЛЬНАЯ УСТАНОВКА ===
print_step(f"Поиск пакета {package_name}...")
# 1. Разрешаем зависимости
# 1. Разрешаем зависимости (получаем список пакетов в нужном порядке)
try:
to_install = self.resolver.resolve(package_name)
except Exception as e:
print_error(f"Ошибка разрешения зависимостей: {e}")
return False
# 2. Устанавливаем всё по порядку
# 2. Устанавливаем каждый пакет из списка (сначала зависимости)
for pkg in to_install:
# Если пакет уже установлен — пропускаем
if self.db.is_installed(pkg.name):
print_info(f"{pkg.name} уже установлен")
continue
print_step(f"Установка {pkg.full_name()}...")
source_dir = os.path.join(self.repo_path, "packages", pkg.name, "files")
# Путь к папке с файлами пакета
source_dir = os.path.join(
self.repo_path, "packages", pkg.name, "files"
)
# Копируем все файлы пакета в целевую систему
for file_info in pkg.files:
src = os.path.join(source_dir, file_info["source"])
dst = os.path.join(self.root, file_info["destination"].lstrip("/"))
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:
print_info(f"Файлы в: {self.root}")
print_success(f"Пакет {package_name} и его зависимости установлены")
return True
def remove(self, package_name: str, force: bool = False, dry_run: bool = False) -> bool:
"""
Удаляет установленный пакет.
Аргументы:
package_name: имя пакета для удаления
force: принудительное удаление (игнорировать зависимости)
dry_run: если True — только показать, что будет удалено
Возвращает:
True — удаление успешно, False — ошибка
"""
print_step(f"Поиск пакета {package_name}...")
# Проверяем, установлен ли пакет
if not self.db.is_installed(package_name):
print_error(f"Пакет {package_name} не установлен")
return False
pkg = self.db.get_package(package_name)
# DRY-RUN: только показываем, ничего не делаем
# === РЕЖИМ DRY-RUN (только показать) ===
if dry_run:
print("🔍 РЕЖИМ DRY-RUN (ничего не удаляется)")
print(f"\n🗑️ Будет удалён: {pkg.full_name()}")
@@ -106,34 +172,50 @@ class PackageManager:
print(f" {dst} (не найден)")
print(f"\n✅ Удаление не произведено (dry-run)")
return True
# РЕАЛЬНОЕ УДАЛЕНИЕ
# === РЕАЛЬНОЕ УДАЛЕНИЕ ===
print_step(f"Удаление {pkg.full_name()}...")
# Удаляем все файлы пакета
for file_info in pkg.files:
dst = os.path.join(self.root, file_info["destination"].lstrip("/"))
if os.path.exists(dst):
os.remove(dst)
print_step(f" Удалён: {dst}")
# Удаляем запись о пакете из базы данных
self.db.remove_package(package_name)
print_success(f"Пакет {package_name} удалён")
return True
def info(self, package_name: str):
"""
Возвращает информацию о пакете (из репозитория или из установленных).
Аргументы:
package_name: имя пакета
Возвращает:
словарь с информацией о пакете (name, version, description,
depends, files, installed, install_date) или None, если не найден
"""
from ..utils.colors import print_error
# Сначала ищем среди установленных пакетов
pkg = self.db.get_package(package_name)
# Если не установлен — ищем в репозитории
if not pkg:
meta_path = os.path.join(self.repo_path, "packages", package_name, "meta.json")
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 None
with open(meta_path, 'r') as f:
pkg_data = json.load(f)
pkg = Package(**pkg_data)
return {
'name': pkg.name,
'version': pkg.version,
@@ -143,28 +225,44 @@ class PackageManager:
'installed': pkg.installed,
'install_date': pkg.install_date
}
def search(self, keyword: str):
"""Ищет пакеты в репозитории по ключевому слову"""
def search(self, keyword: str) -> List[Package]:
"""
Ищет пакеты в репозитории по ключевому слову.
Аргументы:
keyword: ключевое слово для поиска (ищет в имени и описании)
Возвращает:
список объектов Package, подходящих под критерий поиска
"""
results = []
packages_dir = os.path.join(self.repo_path, "packages")
if not os.path.exists(packages_dir):
return results
# Перебираем все папки пакетов в репозитории
for pkg_name in os.listdir(packages_dir):
meta_path = os.path.join(packages_dir, pkg_name, "meta.json")
if os.path.exists(meta_path):
with open(meta_path, 'r') as f:
pkg_data = json.load(f)
# Проверяем, содержится ли ключевое слово в имени или описании
keyword_lower = keyword.lower()
if (keyword_lower in pkg_data.get('name', '').lower() or
keyword_lower in pkg_data.get('description', '').lower()):
keyword_lower in pkg_data.get('description', '').lower()):
pkg = Package(**pkg_data)
results.append(pkg)
return results
def list_installed(self) -> List[Package]:
"""
Возвращает список всех установленных пакетов.
Возвращает:
список объектов Package
"""
return list(self.db.installed.values())