diff --git a/src/ahriman/core/report/html.py b/src/ahriman/core/report/html.py index 3bff8567..3d5dab1f 100644 --- a/src/ahriman/core/report/html.py +++ b/src/ahriman/core/report/html.py @@ -23,7 +23,7 @@ from typing import Callable, Dict, Iterable from ahriman.core.configuration import Configuration from ahriman.core.report.report import Report -from ahriman.core.util import pretty_size, pretty_datetime +from ahriman.core.util import pretty_datetime, pretty_size from ahriman.models.package import Package from ahriman.models.sign_settings import SignSettings @@ -38,7 +38,18 @@ class HTML(Report): link_path - prefix fo packages to download, string, required has_package_signed - True in case if package sign enabled, False otherwise, required has_repo_signed - True in case if repository database sign enabled, False otherwise, required - packages - sorted list of packages properties: archive_size, build_date, filename, installed_size, name, version. Required + packages - sorted list of packages properties, required + * architecture, string + * archive_size, pretty printed size, string + * build_date, pretty printed datetime, string + * description, string + * filename, string, + * groups, sorted list of strings + * installed_size, pretty printed datetime, string + * licenses, sorted list of strings + * name, string + * url, string + * version, string pgp_key - default PGP key ID, string, optional repository - repository name, string, required @@ -48,7 +59,7 @@ class HTML(Report): :ivar pgp_key: default PGP key :ivar report_path: output path to html report :ivar sign_targets: targets to sign enabled in configuration - :ivar tempate_path: path to directory with jinja templates + :ivar template_path: path to directory with jinja templates """ def __init__(self, architecture: str, config: Configuration) -> None: @@ -83,11 +94,16 @@ class HTML(Report): content = [ { + "architecture": properties.architecture or "", "archive_size": pretty_size(properties.archive_size), "build_date": pretty_datetime(properties.build_date), + "description": properties.description or "", "filename": properties.filename, + "groups": properties.groups, "installed_size": pretty_size(properties.installed_size), + "licenses": properties.licenses, "name": package, + "url": properties.url or "", "version": base.version } for base in packages for package, properties in base.packages.items() ] diff --git a/src/ahriman/models/package.py b/src/ahriman/models/package.py index f028efed..3692dd55 100644 --- a/src/ahriman/models/package.py +++ b/src/ahriman/models/package.py @@ -59,6 +59,13 @@ class Package: """ return f"{self.aur_url}/{self.base}.git" + @property + def groups(self) -> List[str]: + """ + :return: sum of groups per each package + """ + return sorted(set(sum([package.groups for package in self.packages.values()], start=[]))) + @property def is_single_package(self) -> bool: """ @@ -78,6 +85,13 @@ class Package: or self.base.endswith("-hg")\ or self.base.endswith("-svn") + @property + def licenses(self) -> List[str]: + """ + :return: sum of licenses per each package + """ + return sorted(set(sum([package.licenses for package in self.packages.values()], start=[]))) + @property def web_url(self) -> str: """ @@ -95,8 +109,8 @@ class Package: :return: package properties """ package = pacman.handle.load_pkg(str(path)) - properties = PackageDescription(package.size, package.builddate, path.name, package.isize) - return cls(package.base, package.version, aur_url, {package.name: properties}) + return cls(package.base, package.version, aur_url, + {package.name: PackageDescription.from_package(package, path)}) @classmethod def from_aur(cls: Type[Package], name: str, aur_url: str) -> Package: diff --git a/src/ahriman/models/package_desciption.py b/src/ahriman/models/package_desciption.py index 4e98adf0..e71a2e50 100644 --- a/src/ahriman/models/package_desciption.py +++ b/src/ahriman/models/package_desciption.py @@ -17,25 +17,38 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . # -from dataclasses import dataclass +from __future__ import annotations + +from dataclasses import dataclass, field from pathlib import Path -from typing import Optional +from pyalpm import Package # type: ignore +from typing import List, Optional, Type @dataclass class PackageDescription: """ package specific properties + :ivar architecture: package architecture :ivar archive_size: package archive size :ivar build_date: package build date + :ivar description: package description :ivar filename: package archive name + :ivar groups: package groups :ivar installed_size: package installed size + :ivar licenses: package licenses list + :ivar url: package url """ + architecture: Optional[str] = None archive_size: Optional[int] = None build_date: Optional[int] = None + description: Optional[str] = None filename: Optional[str] = None + groups: List[str] = field(default_factory=list) installed_size: Optional[int] = None + licenses: List[str] = field(default_factory=list) + url: Optional[str] = None @property def filepath(self) -> Optional[Path]: @@ -43,3 +56,22 @@ class PackageDescription: :return: path object for current filename """ return Path(self.filename) if self.filename is not None else None + + @classmethod + def from_package(cls: Type[PackageDescription], package: Package, path: Path) -> PackageDescription: + """ + construct class from alpm package class + :param package: alpm generated object + :param path: path to package archive + :return: package properties based on tarball + """ + return PackageDescription( + architecture=package.arch, + archive_size=package.size, + build_date=package.builddate, + description=package.desc, + filename=path.name, + groups=package.groups, + installed_size=package.isize, + licenses=package.licenses, + url=package.url) diff --git a/src/ahriman/web/views/index.py b/src/ahriman/web/views/index.py index 270a983d..e0ebac3d 100644 --- a/src/ahriman/web/views/index.py +++ b/src/ahriman/web/views/index.py @@ -34,10 +34,20 @@ class IndexView(BaseView): It uses jinja2 templates for report generation, the following variables are allowed: architecture - repository architecture, string, required - packages - sorted list of packages properties: base, packages (sorted list), status, - timestamp, version, web_url. Required + packages - sorted list of packages properties, required + * base, string + * groups, sorted list of strings + * licenses, sorted list of strings + * packages, sorted list of strings + * status, string based on enum value + * timestamp, pretty printed datetime, string + * version, string + * web_url, string repository - repository name, string, required - service - service status properties: status, status_color, timestamp. Required + service - service status properties, required + * status, string based on enum value + * status_color, string based on enum value + * timestamp, pretty printed datetime, string version - ahriman version, string, required """ @@ -51,6 +61,8 @@ class IndexView(BaseView): packages = [ { "base": package.base, + "groups": package.groups, + "licenses": package.licenses, "packages": list(sorted(package.packages)), "status": status.status.value, "timestamp": pretty_datetime(status.timestamp), diff --git a/tests/ahriman/conftest.py b/tests/ahriman/conftest.py index ee5aa2d2..cd99799b 100644 --- a/tests/ahriman/conftest.py +++ b/tests/ahriman/conftest.py @@ -58,28 +58,43 @@ def package_python_schedule( @pytest.fixture def package_description_ahriman() -> PackageDescription: return PackageDescription( + architecture="x86_64", archive_size=4200, build_date=42, + description="ArcHlinux ReposItory MANager", filename="ahriman-0.12.1-1-any.pkg.tar.zst", - installed_size=4200000) + groups=[], + installed_size=4200000, + licenses=["GPL3"], + url="https://github.com/arcan1s/ahriman") @pytest.fixture def package_description_python_schedule() -> PackageDescription: return PackageDescription( + architecture="x86_64", archive_size=4201, build_date=421, + description="Python job scheduling for humans.", filename="python-schedule-1.0.0-2-any.pkg.tar.zst", - installed_size=4200001) + groups=[], + installed_size=4200001, + licenses=["MIT"], + url="https://github.com/dbader/schedule") @pytest.fixture def package_description_python2_schedule() -> PackageDescription: return PackageDescription( + architecture="x86_64", archive_size=4202, build_date=422, + description="Python job scheduling for humans.", filename="python2-schedule-1.0.0-2-any.pkg.tar.zst", - installed_size=4200002) + groups=[], + installed_size=4200002, + licenses=["MIT"], + url="https://github.com/dbader/schedule") @pytest.fixture diff --git a/tests/ahriman/models/test_package.py b/tests/ahriman/models/test_package.py index cb3b9640..c8201f4a 100644 --- a/tests/ahriman/models/test_package.py +++ b/tests/ahriman/models/test_package.py @@ -14,6 +14,17 @@ def test_git_url(package_ahriman: Package) -> None: assert package_ahriman.base in package_ahriman.git_url +def test_groups(package_ahriman: Package) -> None: + """ + must return list of groups for each package + """ + assert all( + all(group in package_ahriman.groups for group in package.groups) + for package in package_ahriman.packages.values() + ) + assert sorted(package_ahriman.groups) == package_ahriman.groups + + def test_is_single_package_false(package_python_schedule: Package) -> None: """ python-schedule must not be single package @@ -42,6 +53,17 @@ def test_is_vcs_true(package_tpacpi_bat_git: Package) -> None: assert package_tpacpi_bat_git.is_vcs +def test_licenses(package_ahriman: Package) -> None: + """ + must return list of licenses for each package + """ + assert all( + all(lic in package_ahriman.licenses for lic in package.licenses) + for package in package_ahriman.packages.values() + ) + assert sorted(package_ahriman.licenses) == package_ahriman.licenses + + def test_web_url(package_ahriman: Package) -> None: """ must generate valid web url