feat: use split packages (#135)

* move argument parsers to handlers themselves

* use hatchling instead of flit

* Revert "use hatchling instead of flit"

This reverts commit d18d146d79.

* add package-splitt script

* replace simplify walk method

* split packages

* explicitly install packages

* separate support triggers from main package

* add docs examples

* sort actions

* docs update

* add metapackage

* review fixes
This commit is contained in:
2024-11-01 16:07:04 +02:00
committed by GitHub
parent 6fe77eb465
commit 93ce7f9a51
105 changed files with 1982 additions and 1631 deletions

View File

@ -0,0 +1,51 @@
Writing own handler
===================
It is possible to extend the application by adding own custom commands. To do so it is required to implement class, which derives from ``ahriman.application.handlers.handler.Handler`` and put it to the ``ahriman.application.handlers`` package. The class later will be loaded automatically and included to each command run.
Let's imagine, that the new class implements ``help-web``, which prints server information to the stdout. To do so, we need to implement base ``ahriman.application.handlers.handler.Handler.run`` method which is entry point for all subcommands:
.. code-block:: python
from ahriman.application.application import Application
from ahriman.application.handlers.handler import Handler
class HelpWeb(Handler):
@classmethod
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
report: bool) -> None:
# load application instance
# report is set to True to make sure that web client is loaded
application = Application(repository_id, configuration, report=True)
# extract web client
client = application.repository.reporter
# send request to the server
response = client.make_request("GET", f"{client.address}/api/v1/info")
result = response.json()
print(result)
The main functionality of the class is already described, but command is still not available yet. To do so, it is required to set ``arguments`` property, which is the list of the functions, each of them which takes argument parser object, creates new subcommand and returns the modified parser, e.g.:
.. code-block:: python
import argparse
from ahriman.application.handlers.handler import SubParserAction
...
@staticmethod
def set_parser(root: SubParserAction) -> argparse.ArgumentParser:
parser = root.add_parser("help-web", help="get web server status",
description="request server info and print it to stdout")
arguments = set_parser
In addition, ``ahriman.application.handlers.handler.Handler.ALLOW_MULTI_ARCHITECTURE_RUN`` can be set to ``False`` in order to disable multiprocess run (e.g. in case if there are conflicting operations, like writting to stdout).
Save the file above as ``/usr/lib/python3.12/site-packages/ahriman/application/handlers/help_web.py`` (replace ``python3.12`` with actual python version) and you are set.
For more examples and details, please check builtin handlers and classes documentations.

View File

@ -0,0 +1,51 @@
Advanced usage
==============
.. toctree::
:maxdepth: 2
handlers
views
Depending on the goal the package can be used in different ways. Nevertheless, in the most cases you will need some basic classes
.. code-block:: python
from pathlib import Path
from ahriman.core.configuration import Configuration
from ahriman.core.database import SQLite
from ahriman.models.repository_id import RepositoryId
repository_id = RepositoryId("x86_64", "aur")
configuration = Configuration.from_path(Path("/etc/ahriman.ini"), repository_id)
database = SQLite.load(configuration)
At this point there are ``configuration`` and ``database`` instances which can be used later at any time anywhere, e.g.
.. code-block:: python
# instance of ``RepositoryPaths`` class
paths = configuration.repository_paths
Almost all actions are wrapped by ``ahriman.core.repository.Repository`` class
.. code-block:: python
from ahriman.core.repository import Repository
from ahriman.models.pacman_synchronization import PacmanSynchronization
repository = Repository(repository_id, configuration, database,
report=True, refresh_pacman_database=PacmanSynchronization.Disabled)
And the ``repository`` instance can be used to perform repository maintenance
.. code-block:: python
build_result = repository.process_build(known_packages)
built_packages = repository.packages_built()
update_result = repository.process_update(built_packages)
repository.triggers.on_result(update_result, repository.packages())
For the more info please refer to the classes documentation.

View File

@ -0,0 +1,41 @@
Writing own API endpoint
========================
The web service loads views dynamically, thus it is possible to add custom API endpoint or even web page. The view must be derived from ``ahriman.web.views.base.BaseView`` and should implement desired HTTP methods. The API specification will be also loaded automatically if available, but optional. The implementation must be saved into the ``ahriman.web.views`` package
Let's consider example of API endpoint which always returns 204 with no response:
.. code-block:: python
from aiohttp.web import Response, HTTPNoContent
from ahriman.web.views.base import BaseView
class PingView(BaseView):
async def get(self) -> Response:
# do nothing, just raise 204 response
# check public methods of the BaseView class for all available controls
raise HTTPNoContent
The ``get()`` method can be decorated by ``aiohttp_apispec`` methods, but we will leave it for a self-study, please, consider to check examples of usages in the main package.
In order to view to be added to the route list correctly, few more properties are required to be set. First of all, it is required to specify ``ROUTES`` (list of strings), which contains list of all available routes, e.g.:
.. code-block:: python
...
ROUTES = ["/api/v1/ping"]
In addition, it is also recommended to specify permission level for using this endpoint. Since this endpoint neither does anything nor returns sensitive information, it can be set to ``UserAccess.Unauthorized``:
.. code-block:: python
...
GET_PERMISSION = UserAccess.Unauthorized
That's all. Just save the file as ``/usr/lib/python3.12/site-packages/ahriman/web/views/ping.py`` (replace ``python3.12`` with actual python version) and restart web server.
For more examples and details, please check builtin handlers and classes documentations.