diff --git a/package/share/ahriman/repo-index.jinja2 b/package/share/ahriman/repo-index.jinja2 index e4be967d..3edbb86f 100644 --- a/package/share/ahriman/repo-index.jinja2 +++ b/package/share/ahriman/repo-index.jinja2 @@ -33,14 +33,18 @@ package version + archive size installed size + build date {% for package in packages %} {{ package.name|e }} {{ package.version|e }} + {{ package.archive_size|e }} {{ package.installed_size|e }} + {{ package.build_date|e }} {% endfor %} diff --git a/src/ahriman/application/application.py b/src/ahriman/application/application.py index 12aa8995..edfdada9 100644 --- a/src/ahriman/application/application.py +++ b/src/ahriman/application/application.py @@ -17,13 +17,11 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . # -from __future__ import annotations - import logging import os import shutil -from typing import Callable, Iterable, List, Optional, Set, Type +from typing import Callable, Iterable, List, Optional, Set from ahriman.core.build_tools.task import Task from ahriman.core.configuration import Configuration diff --git a/src/ahriman/core/report/html.py b/src/ahriman/core/report/html.py index 6ea46a52..35416146 100644 --- a/src/ahriman/core/report/html.py +++ b/src/ahriman/core/report/html.py @@ -24,8 +24,8 @@ 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.models.package import Package -from ahriman.models.package_desciption import PackageDescription from ahriman.models.sign_settings import SignSettings @@ -39,7 +39,7 @@ 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: filename, installed_size, name, version. Required + packages - sorted list of packages properties: archive_size, build_date, filename, installed_size, name, version. Required pgp_key - default PGP key ID, string, optional repository - repository name, string, required @@ -85,8 +85,10 @@ class HTML(Report): content = [ { + 'archive_size': pretty_size(properties.archive_size), + 'build_date': pretty_datetime(properties.build_date), 'filename': properties.filename, - 'installed_size': PackageDescription.size_to_str(properties.installed_size), + 'installed_size': pretty_size(properties.installed_size), 'name': package, 'version': base.version } for base in packages for package, properties in base.packages.items() diff --git a/src/ahriman/core/util.py b/src/ahriman/core/util.py index 2a0f810e..1ebf505d 100644 --- a/src/ahriman/core/util.py +++ b/src/ahriman/core/util.py @@ -17,11 +17,14 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . # +import datetime import subprocess from logging import Logger from typing import Optional +from ahriman.core.exceptions import InvalidOption + def check_output(*args: str, exception: Optional[Exception], cwd: Optional[str] = None, stderr: int = subprocess.STDOUT, @@ -55,3 +58,37 @@ def package_like(filename: str) -> bool: :return: True in case if name contains `.pkg.` and not signature, False otherwise ''' return '.pkg.' in filename and not filename.endswith('.sig') + + +def pretty_datetime(timestamp: Optional[datetime.datetime]) -> str: + ''' + convert datetime object to string + :param timestamp: datetime to convert + :return: pretty printable datetime as string + ''' + return '' if timestamp is None else timestamp.strftime('%Y-%m-%d %H:%M:%S') + + +def pretty_size(size: Optional[float], level: int = 0) -> str: + ''' + convert size to string + :param size: size to convert + :param level: represents current units, 0 is B, 1 is KiB etc + :return: pretty printable size as string + ''' + def str_level() -> str: + if level == 0: + return 'B' + elif level == 1: + return 'KiB' + elif level == 2: + return 'MiB' + elif level == 3: + return 'GiB' + raise InvalidOption(level) # I hope it will not be more than 1024 GiB + + if size is None: + return '' + elif size < 1024: + return f'{round(size, 2)} {str_level()}' + return pretty_size(size / 1024, level + 1) diff --git a/src/ahriman/models/build_status.py b/src/ahriman/models/build_status.py index 0535cfe7..5b417793 100644 --- a/src/ahriman/models/build_status.py +++ b/src/ahriman/models/build_status.py @@ -70,11 +70,4 @@ class BuildStatus: :param timestamp: build status timestamp. Current timestamp will be used if not set ''' self.status = BuildStatusEnum(status) if status else BuildStatusEnum.Unknown - self._timestamp = timestamp or datetime.datetime.utcnow() - - @property - def timestamp(self) -> str: - ''' - :return: string representation of build status timestamp - ''' - return self._timestamp.strftime('%Y-%m-%d %H:%M:%S') + self.timestamp = timestamp or datetime.datetime.utcnow() diff --git a/src/ahriman/models/package.py b/src/ahriman/models/package.py index a83dd2f2..bdfbe98d 100644 --- a/src/ahriman/models/package.py +++ b/src/ahriman/models/package.py @@ -20,6 +20,7 @@ from __future__ import annotations import aur # type: ignore +import datetime import os from dataclasses import dataclass @@ -108,7 +109,8 @@ class Package: :return: package properties ''' package = pacman.handle.load_pkg(path) - properties = PackageDescription(os.path.basename(path), package.isize) + build_date = datetime.datetime.fromtimestamp(package.builddate) + properties = PackageDescription(package.size, build_date, os.path.basename(path), package.isize) return cls(package.base, package.version, aur_url, {package.name: properties}) @classmethod diff --git a/src/ahriman/models/package_desciption.py b/src/ahriman/models/package_desciption.py index 4ad0b299..53f4daa1 100644 --- a/src/ahriman/models/package_desciption.py +++ b/src/ahriman/models/package_desciption.py @@ -17,41 +17,23 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . # +import datetime + from dataclasses import dataclass from typing import Optional -from ahriman.core.exceptions import InvalidOption - @dataclass class PackageDescription: ''' package specific properties + :ivar archive_size: package archive size + :ivar build_date: package build date + :ivar filename: package archive name + :ivar installed_size: package installed size ''' + + archive_size: Optional[int] = None + build_date: Optional[datetime.datetime] = None filename: Optional[str] = None installed_size: Optional[int] = None - - @staticmethod - def size_to_str(size: Optional[float], level: int = 0) -> str: - ''' - convert size to string - :param size: size to convert - :param level: represents current units, 0 is B, 1 is KiB etc - :return: pretty printable size as string - ''' - def str_level() -> str: - if level == 0: - return 'B' - elif level == 1: - return 'KiB' - elif level == 2: - return 'MiB' - elif level == 3: - return 'GiB' - raise InvalidOption(level) - - if size is None: - return '' - elif size < 1024: - return f'{round(size, 2)} {str_level()}' - return PackageDescription.size_to_str(size / 1024, level + 1) diff --git a/src/ahriman/models/report_settings.py b/src/ahriman/models/report_settings.py index 6695ab34..51e30305 100644 --- a/src/ahriman/models/report_settings.py +++ b/src/ahriman/models/report_settings.py @@ -27,7 +27,7 @@ from ahriman.core.exceptions import InvalidOption class ReportSettings(Enum): ''' report targets enumeration - :ivar HTML: html report generation + :cvar HTML: html report generation ''' HTML = auto() diff --git a/src/ahriman/models/sign_settings.py b/src/ahriman/models/sign_settings.py index 9b3d4609..ad9e37ac 100644 --- a/src/ahriman/models/sign_settings.py +++ b/src/ahriman/models/sign_settings.py @@ -27,8 +27,8 @@ from ahriman.core.exceptions import InvalidOption class SignSettings(Enum): ''' sign targets enumeration - :ivar SignPackages: sign each package - :ivar SignRepository: sign repository database file + :cvar SignPackages: sign each package + :cvar SignRepository: sign repository database file ''' SignPackages = auto() diff --git a/src/ahriman/models/upload_settings.py b/src/ahriman/models/upload_settings.py index 87bdf473..6fc6a9b4 100644 --- a/src/ahriman/models/upload_settings.py +++ b/src/ahriman/models/upload_settings.py @@ -27,8 +27,8 @@ from ahriman.core.exceptions import InvalidOption class UploadSettings(Enum): ''' remote synchronization targets enumeration - :ivar Rsync: sync via rsync - :ivar S3: sync to Amazon S3 + :cvar Rsync: sync via rsync + :cvar S3: sync to Amazon S3 ''' Rsync = auto() diff --git a/src/ahriman/web/views/index.py b/src/ahriman/web/views/index.py index 89fd18e5..73d3062a 100644 --- a/src/ahriman/web/views/index.py +++ b/src/ahriman/web/views/index.py @@ -23,6 +23,7 @@ from typing import Any, Dict import ahriman.version as version +from ahriman.core.util import pretty_datetime from ahriman.web.views.base import BaseView @@ -52,7 +53,7 @@ class IndexView(BaseView): 'base': package.base, 'packages': [p for p in sorted(package.packages)], 'status': status.status.value, - 'timestamp': status.timestamp, + 'timestamp': pretty_datetime(status.timestamp), 'version': package.version, 'web_url': package.web_url } for package, status in sorted(self.service.packages, key=lambda item: item[0].base) @@ -60,7 +61,7 @@ class IndexView(BaseView): service = { 'status': self.service.status.status.value, 'status_color': self.service.status.status.badges_color(), - 'timestamp': self.service.status.timestamp + 'timestamp': pretty_datetime(self.service.status.timestamp) } return {