Skip to content

Commit

Permalink
feat: add counters to repository stats overview
Browse files Browse the repository at this point in the history
  • Loading branch information
arcan1s committed Jan 9, 2025
1 parent a07b20b commit 15ca143
Show file tree
Hide file tree
Showing 26 changed files with 519 additions and 28 deletions.
8 changes: 8 additions & 0 deletions docs/ahriman.core.formatters.rst
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,14 @@ ahriman.core.formatters.repository\_printer module
:no-undoc-members:
:show-inheritance:

ahriman.core.formatters.repository\_stats\_printer module
---------------------------------------------------------

.. automodule:: ahriman.core.formatters.repository_stats_printer
:members:
:no-undoc-members:
:show-inheritance:

ahriman.core.formatters.status\_printer module
----------------------------------------------

Expand Down
16 changes: 16 additions & 0 deletions docs/ahriman.models.rst
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,14 @@ ahriman.models.repository\_paths module
:no-undoc-members:
:show-inheritance:

ahriman.models.repository\_stats module
---------------------------------------

.. automodule:: ahriman.models.repository_stats
:members:
:no-undoc-members:
:show-inheritance:

ahriman.models.result module
----------------------------

Expand All @@ -252,6 +260,14 @@ ahriman.models.scan\_paths module
:no-undoc-members:
:show-inheritance:

ahriman.models.series\_statistics module
----------------------------------------

.. automodule:: ahriman.models.series_statistics
:members:
:no-undoc-members:
:show-inheritance:

ahriman.models.sign\_settings module
------------------------------------

Expand Down
8 changes: 8 additions & 0 deletions docs/ahriman.web.schemas.rst
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,14 @@ ahriman.web.schemas.repository\_id\_schema module
:no-undoc-members:
:show-inheritance:

ahriman.web.schemas.repository\_stats\_schema module
----------------------------------------------------

.. automodule:: ahriman.web.schemas.repository_stats_schema
:members:
:no-undoc-members:
:show-inheritance:

ahriman.web.schemas.search\_schema module
-----------------------------------------

Expand Down
3 changes: 2 additions & 1 deletion src/ahriman/application/handlers/statistics.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from ahriman.application.application import Application
from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration
from ahriman.core.formatters import EventStatsPrinter, PackageStatsPrinter
from ahriman.core.formatters import EventStatsPrinter, PackageStatsPrinter, RepositoryStatsPrinter
from ahriman.core.utils import enum_values, pretty_datetime
from ahriman.models.event import Event, EventType
from ahriman.models.repository_id import RepositoryId
Expand Down Expand Up @@ -64,6 +64,7 @@ def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuratio

match args.package:
case None:
RepositoryStatsPrinter(repository_id, application.reporter.statistics())(verbose=True)
Statistics.stats_per_package(args.event, events, args.chart)
case _:
Statistics.stats_for_package(args.event, events, args.chart)
Expand Down
1 change: 1 addition & 0 deletions src/ahriman/core/formatters/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
from ahriman.core.formatters.patch_printer import PatchPrinter
from ahriman.core.formatters.printer import Printer
from ahriman.core.formatters.repository_printer import RepositoryPrinter
from ahriman.core.formatters.repository_stats_printer import RepositoryStatsPrinter
from ahriman.core.formatters.status_printer import StatusPrinter
from ahriman.core.formatters.string_printer import StringPrinter
from ahriman.core.formatters.tree_printer import TreePrinter
Expand Down
27 changes: 9 additions & 18 deletions src/ahriman/core/formatters/event_stats_printer.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,17 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import statistics

from ahriman.core.formatters.string_printer import StringPrinter
from ahriman.core.utils import minmax
from ahriman.models.property import Property
from ahriman.models.series_statistics import SeriesStatistics


class EventStatsPrinter(StringPrinter):
"""
print event statistics
Attributes:
events(list[float | int]): event values to build statistics
statistics(SeriesStatistics): statistics object
"""

def __init__(self, event_type: str, events: list[float | int]) -> None:
Expand All @@ -39,7 +37,7 @@ def __init__(self, event_type: str, events: list[float | int]) -> None:
events(list[float | int]): event values to build statistics
"""
StringPrinter.__init__(self, event_type)
self.events = events
self.statistics = SeriesStatistics(events)

def properties(self) -> list[Property]:
"""
Expand All @@ -49,24 +47,17 @@ def properties(self) -> list[Property]:
list[Property]: list of content properties
"""
properties = [
Property("total", len(self.events)),
Property("total", self.statistics.total),
]

# time statistics
if self.events:
min_time, max_time = minmax(self.events)
mean = statistics.mean(self.events)

if len(self.events) > 1:
st_dev = statistics.stdev(self.events)
average = f"{mean:.3f} ± {st_dev:.3f}"
else:
average = f"{mean:.3f}"
if self.statistics:
mean = self.statistics.mean

properties.extend([
Property("min", min_time),
Property("average", average),
Property("max", max_time),
Property("min", self.statistics.min),
Property("average", f"{mean:.3f} ± {self.statistics.st_dev:.3f}"),
Property("max", self.statistics.max),
])

return properties
53 changes: 53 additions & 0 deletions src/ahriman/core/formatters/repository_stats_printer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#
# Copyright (c) 2021-2025 ahriman team.
#
# This file is part of ahriman
# (see https://github.com/arcan1s/ahriman).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from ahriman.core.formatters.string_printer import StringPrinter
from ahriman.core.utils import pretty_size
from ahriman.models.property import Property
from ahriman.models.repository_id import RepositoryId
from ahriman.models.repository_stats import RepositoryStats


class RepositoryStatsPrinter(StringPrinter):
"""
print repository statistics
Attributes:
statistics(RepositoryStats): repository statistics
"""

def __init__(self, repository_id: RepositoryId, statistics: RepositoryStats) -> None:
"""
Args:
statistics(RepositoryStats): repository statistics
"""
StringPrinter.__init__(self, str(repository_id))
self.statistics = statistics

def properties(self) -> list[Property]:
"""
convert content into printable data
Returns:
list[Property]: list of content properties
"""
return [
Property("Packages", self.statistics.bases),
Property("Repository size", pretty_size(self.statistics.archive_size)),
]
11 changes: 11 additions & 0 deletions src/ahriman/core/status/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
from ahriman.models.package import Package
from ahriman.models.pkgbuild_patch import PkgbuildPatch
from ahriman.models.repository_id import RepositoryId
from ahriman.models.repository_stats import RepositoryStats


class Client:
Expand Down Expand Up @@ -354,6 +355,16 @@ def set_unknown(self, package: Package) -> None:
return # skip update in case if package is already known
self.package_update(package, BuildStatusEnum.Unknown)

def statistics(self) -> RepositoryStats:
"""
get repository statistics
Returns:
RepositoryStats: repository statistics object
"""
packages = [package for package, _ in self.package_get(None)]
return RepositoryStats.from_packages(packages)

def status_get(self) -> InternalStatus:
"""
get internal service status
Expand Down
5 changes: 5 additions & 0 deletions src/ahriman/models/internal_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from ahriman.core.utils import dataclass_view
from ahriman.models.build_status import BuildStatus
from ahriman.models.counters import Counters
from ahriman.models.repository_stats import RepositoryStats


@dataclass(frozen=True, kw_only=True)
Expand All @@ -35,13 +36,15 @@ class InternalStatus:
architecture(str | None): repository architecture
packages(Counters): packages statuses counter object
repository(str | None): repository name
stats(RepositoryStats | None): repository stats
version(str | None): service version
"""

status: BuildStatus
architecture: str | None = None
packages: Counters = field(default=Counters(total=0))
repository: str | None = None
stats: RepositoryStats | None = None
version: str | None = None

@classmethod
Expand All @@ -56,11 +59,13 @@ def from_json(cls, dump: dict[str, Any]) -> Self:
Self: internal status
"""
counters = Counters.from_json(dump["packages"]) if "packages" in dump else Counters(total=0)
stats = RepositoryStats.from_json(dump["stats"]) if "stats" in dump else None
build_status = dump.get("status") or {}
return cls(status=BuildStatus.from_json(build_status),
architecture=dump.get("architecture"),
packages=counters,
repository=dump.get("repository"),
stats=stats,
version=dump.get("version"))

def view(self) -> dict[str, Any]:
Expand Down
9 changes: 9 additions & 0 deletions src/ahriman/models/repository_id.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,12 @@ def __lt__(self, other: Any) -> bool:
raise ValueError(f"'<' not supported between instances of '{type(self)}' and '{type(other)}'")

return (self.name, self.architecture) < (other.name, other.architecture)

def __str__(self) -> str:
"""
string representation of the repository identifier
Returns:
str: string view of the repository identifier
"""
return f"{self.name} ({self.architecture})"
77 changes: 77 additions & 0 deletions src/ahriman/models/repository_stats.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#
# Copyright (c) 2021-2025 ahriman team.
#
# This file is part of ahriman
# (see https://github.com/arcan1s/ahriman).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from dataclasses import dataclass, fields
from typing import Any, Self

from ahriman.core.utils import filter_json
from ahriman.models.package import Package


@dataclass(frozen=True, kw_only=True)
class RepositoryStats:
"""
repository stats representation
"""

bases: int
packages: int
archive_size: int
installed_size: int

@classmethod
def from_json(cls, dump: dict[str, Any]) -> Self:
"""
construct counters from json dump
Args:
dump(dict[str, Any]): json dump body
Returns:
Self: status counters
"""
# filter to only known fields
known_fields = [pair.name for pair in fields(cls)]
return cls(**filter_json(dump, known_fields))

@classmethod
def from_packages(cls, packages: list[Package]) -> Self:
"""
construct statistics from list of repository packages
Args:
packages(list[Packages]): list of repository packages
Returns:
Self: constructed statistics object
"""
return cls(
bases=len(packages),
packages=sum(len(package.packages) for package in packages),
archive_size=sum(
archive.archive_size or 0
for package in packages
for archive in package.packages.values()
),
installed_size=sum(
archive.installed_size or 0
for package in packages
for archive in package.packages.values()
),
)
Loading

0 comments on commit 15ca143

Please sign in to comment.