79 lines
2.8 KiB
Python
79 lines
2.8 KiB
Python
import enum
|
||
from dataclasses import dataclass
|
||
from typing import Optional, Set, Dict
|
||
|
||
from pythonapp.Instance.ABS import Instance
|
||
from pythonapp.Libs.pip_api import pip_api
|
||
from pythonapp.Decider.Loader import Loader
|
||
from .misc import *
|
||
|
||
|
||
class ConflictSeverity(enum.Enum):
|
||
FATAL = "Fatal"
|
||
ERROR = "Error"
|
||
WARNING = "Warning"
|
||
|
||
|
||
|
||
@dataclass
|
||
class ConflictError:
|
||
"""Класс для хранения информации о конфликте зависимостей."""
|
||
conflicting_packages: Set[str]
|
||
sources: Dict[str, str] # package -> source (installed/requested)
|
||
severity: ConflictSeverity
|
||
error_message: str
|
||
resolution_action: str = ""
|
||
|
||
def __post_init__(self):
|
||
# Автоматически определяем источники, если не предоставлены
|
||
if not self.sources:
|
||
self.sources = {pkg: "unknown" for pkg in self.conflicting_packages}
|
||
|
||
|
||
|
||
class DeciderState(enum.Enum):
|
||
SUCCESS = 0
|
||
WARN = 30
|
||
ERROR = 50
|
||
FATAL = 100
|
||
|
||
|
||
|
||
class Decider:
|
||
@classmethod
|
||
def decide(cls, instance: Instance,
|
||
packages: list[RequirementInfo] | Path,
|
||
pip_path: str,
|
||
index_url: Optional[str] = None,
|
||
extra_index_urls: Optional[list[str]] = None
|
||
) -> tuple[list[RequirementInfo], list[ConflictError], DeciderState]:
|
||
raise NotImplemented
|
||
|
||
@classmethod
|
||
def load(cls, instance: Instance, packages: list[RequirementInfo] | Path, manual=False):
|
||
if isinstance(packages, Path):
|
||
opt, req = requirements_separator(packages)
|
||
packages = requirements_converter(opt, req)
|
||
p = instance.path
|
||
c = instance.config
|
||
installed = Loader.load_existent_requirements(
|
||
str(p / c.manual_requirements_path), str(p / c.requirements_dir),
|
||
str(p / c.pinned_packages_path), str(p / c.excluded_packages_path))
|
||
if not manual:
|
||
packages = Loader.filter_reqs(packages, str(p / c.pinned_packages_path), str(p / c.excluded_packages_path))
|
||
installed.extend(packages)
|
||
return installed, packages
|
||
|
||
class SimpleDecider(Decider):
|
||
@classmethod
|
||
def decide(cls, instance: Instance,
|
||
packages: list[RequirementInfo] | Path,
|
||
pip_path: str,
|
||
index_url: Optional[str] = None,
|
||
extra_index_urls: Optional[list[str]] = None,
|
||
manual=False) -> tuple[list[RequirementInfo] | None, list[ConflictError], DeciderState]:
|
||
all_packages, packages = cls.load(instance, packages, manual)
|
||
result = pip_api.run_pip_install(pip_path, [p.requirement_str for p in all_packages], index_url, extra_index_urls, dry_run=True)
|
||
if result.exit_code != 0: return None, [], DeciderState.FATAL
|
||
return packages, [], DeciderState.SUCCESS
|