archinstall/archinstall/lib/models/packages.py

191 lines
3.9 KiB
Python

from dataclasses import dataclass, field
from enum import Enum
from functools import cached_property
from typing import Any, Self, override
from pydantic import BaseModel
from archinstall.lib.translationhandler import tr
class Repository(Enum):
Core = 'core'
Extra = 'extra'
Multilib = 'multilib'
Testing = 'testing'
MultilibTesting = 'multilib-testing'
CoreTesting = 'core-testing'
ExtraTesting = 'extra-testing'
@dataclass
class PackageSearchResult:
pkgname: str
pkgbase: str
repo: str
arch: str
pkgver: str
pkgrel: str
epoch: int
pkgdesc: str
url: str
filename: str
compressed_size: int
installed_size: int
build_date: str
last_update: str
flag_date: str | None
maintainers: list[str]
packager: str
groups: list[str]
licenses: list[str]
conflicts: list[str]
provides: list[str]
replaces: list[str]
depends: list[str]
optdepends: list[str]
makedepends: list[str]
checkdepends: list[str]
@classmethod
def from_json(cls, data: dict[str, Any]) -> Self:
return cls(**data)
@property
def pkg_version(self) -> str:
return self.pkgver
@override
def __eq__(self, other: object) -> bool:
if not isinstance(other, PackageSearchResult):
return NotImplemented
return self.pkg_version == other.pkg_version
def __lt__(self, other: Self) -> bool:
return self.pkg_version < other.pkg_version
@dataclass
class PackageSearch:
version: int
limit: int
valid: bool
num_pages: int
page: int
results: list[PackageSearchResult]
@classmethod
def from_json(cls, data: dict[str, Any]) -> Self:
results = [PackageSearchResult.from_json(r) for r in data['results']]
return cls(
version=data['version'],
limit=data['limit'],
valid=data['valid'],
num_pages=data['num_pages'],
page=data['page'],
results=results,
)
class LocalPackage(BaseModel):
name: str
version: str
description: str
architecture: str
url: str
licenses: str
groups: str
@override
def __eq__(self, other: object) -> bool:
if not isinstance(other, LocalPackage):
return NotImplemented
return self.version == other.version
def __lt__(self, other: Self) -> bool:
return self.version < other.version
class AvailablePackage(BaseModel):
name: str
architecture: str
build_date: str
depends_on: str
description: str
download_size: str
groups: str
installed_size: str
licenses: str
optional_deps: str
packager: str
provides: str
replaces: str
repository: str
url: str
validated_by: str
version: str
@cached_property
def longest_key(self) -> int:
return max(len(key) for key in self.model_dump().keys())
def info(self) -> str:
output = ''
for key, value in self.model_dump().items():
key = key.replace('_', ' ').capitalize()
key = key.ljust(self.longest_key)
output += f'{key} : {value}\n'
return output
@cached_property
def get_depends_on(self) -> list[str]:
return [entry.strip() for entry in self.depends_on.split(' ') if entry.strip()]
@cached_property
def get_optional_deps(self) -> list[str]:
return [entry.strip() for entry in self.optional_deps.split(' ') if entry.strip()]
@dataclass
class PackageGroup:
name: str
packages: list[str] = field(default_factory=list)
@classmethod
def from_package_group_output(cls, data: list[str]) -> Self:
name = data[0].split()[0].strip()
packages = [line.split()[1].strip() for line in data if line.strip()]
return cls(name, packages)
@classmethod
def from_available_packages(
cls,
packages: dict[str, AvailablePackage],
) -> dict[str, Self]:
pkg_groups: dict[str, Self] = {}
for pkg in packages.values():
if 'None' in pkg.groups:
continue
groups = pkg.groups.split(' ')
for group in groups:
# same group names have multiple spaces in between
if len(group) == 0:
continue
pkg_groups.setdefault(group, cls(group))
pkg_groups[group].packages.append(pkg.name)
return pkg_groups
def info(self) -> str:
output = tr('Package group:') + '\n - '
output += '\n - '.join(self.packages)
return output