Files
2025-12-28 17:47:56 +03:00

138 lines
4.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import json
import traceback
from abc import ABC, abstractmethod
from pathlib import Path
from typing import Any, Dict, Literal
from pydantic import BaseModel, ConfigDict, Field, PrivateAttr, field_validator
from rich.console import Console
from utils.tools import CONFIGS
class ToolsConfig(BaseModel):
apktool_jar_url: str
apktool_wrapper_url: str
@field_validator("apktool_jar_url", "apktool_wrapper_url")
@classmethod
def validate_url(cls, v: str) -> str:
if not v.startswith(("http://", "https://")):
raise ValueError("URL должен начинаться с http:// или https://")
return v
class SigningConfig(BaseModel):
keystore: Path = Field(default=Path("keystore.jks"))
keystore_pass_file: Path = Field(default=Path("keystore.pass"))
v1_signing: bool = False
v2_signing: bool = True
v3_signing: bool = True
class BuildConfig(BaseModel):
verbose: bool = False
force: bool = False
clean_after_build: bool = True
class Config(BaseModel):
tools: ToolsConfig
signing: SigningConfig = Field(default_factory=SigningConfig)
build: BuildConfig = Field(default_factory=BuildConfig)
base: Dict[str, Any] = Field(default_factory=dict)
def load_config(console: Console) -> Config:
"""Загружает и валидирует конфигурацию"""
config_path = Path("config.json")
if not config_path.exists():
console.print("[red]Файл config.json не найден")
raise typer.Exit(1)
try:
return Config.model_validate_json(config_path.read_text())
except ValidationError as e:
console.print(f"[red]Ошибка валидации config.json:\n{e}")
raise typer.Exit(1)
class PatchTemplate(BaseModel, ABC):
model_config = ConfigDict(arbitrary_types_allowed=True, validate_default=True)
enabled: bool = Field(default=True, description="Включить или отключить патч")
priority: int = Field(default=0, description="Приоритет применения патча")
_name: str = PrivateAttr()
_applied: bool = PrivateAttr(default=False)
_console: Console | None = PrivateAttr(default=None)
def __init__(self, name: str, console: Console, **data):
loaded_data = self._load_config_static(name, console)
merged_data = {**loaded_data, **data}
valid_fields = set(self.model_fields.keys())
filtered_data = {k: v for k, v in merged_data.items() if k in valid_fields}
super().__init__(**filtered_data)
self._name = name
self._console = console
self._applied = False
@staticmethod
def _load_config_static(name: str, console: Console | None) -> Dict[str, Any]:
"""Загружает конфигурацию из файла (статический метод)"""
config_path = CONFIGS / f"{name}.json"
try:
if config_path.exists():
return json.loads(config_path.read_text())
except Exception as e:
if console:
console.print(
f"[red]Ошибка при загрузке конфигурации патча {name}: {e}"
)
console.print(f"[yellow]Используются значения по умолчанию")
return {}
def save_config(self) -> None:
"""Сохраняет конфигурацию в файл"""
config_path = CONFIGS / f"{self._name}.json"
config_path.parent.mkdir(parents=True, exist_ok=True)
config_path.write_text(self.model_dump_json(indent=2))
@property
def name(self) -> str:
return self._name
@property
def applied(self) -> bool:
return self._applied
@applied.setter
def applied(self, value: bool) -> None:
self._applied = value
@property
def console(self) -> Console | None:
return self._console
@abstractmethod
def apply(self, base: Dict[str, Any]) -> Any:
raise NotImplementedError(
"Попытка применения шаблона патча, а не его реализации"
)
def safe_apply(self, base: Dict[str, Any]) -> bool:
"""Безопасно применяет патч с обработкой ошибок"""
try:
self._applied = self.apply(base)
return self._applied
except Exception as e:
if self._console:
self._console.print(f"[red]Ошибка в патче {self._name}: {e}")
if base.get("verbose"):
self._console.print_exception()
return False