mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-07-16 15:29:56 +00:00
Compare commits
8 Commits
33e9fea47c
...
2.0.0rc11
Author | SHA1 | Date | |
---|---|---|---|
a11fd188a2 | |||
2431d5de0e | |||
88f71b240d | |||
99874845b5 | |||
d98cfa3732 | |||
b6db2a8035 | |||
47c578ea08 | |||
98910240dd |
@ -14,7 +14,7 @@ Wrapper for managing custom repository inspired by [repo-scripts](https://github
|
||||
* Multi-architecture support.
|
||||
* VCS packages support.
|
||||
* Sign support with gpg (repository, package, per package settings).
|
||||
* Synchronization to remote services (rsync, s3 and github) and report generation (email, html, telegram).
|
||||
* Synchronization to remote services (rsync, s3 and github) and report generation (email, html, telegram) and even ability to write own extensions.
|
||||
* Dependency manager.
|
||||
* Ability to patch AUR packages and even create package from local PKGBUILDs.
|
||||
* Repository status interface with optional authorization and control options:
|
||||
|
@ -8,7 +8,7 @@ Depending on the goal the package can be used in different ways. Nevertheless, i
|
||||
from pathlib import Path
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database.sqlite import SQLite
|
||||
from ahriman.core.database import SQLite
|
||||
|
||||
architecture = "x86_64"
|
||||
configuration = Configuration.from_path(Path("/etc/ahriman.ini"), architecture, quiet=False)
|
||||
|
File diff suppressed because it is too large
Load Diff
Before Width: | Height: | Size: 570 KiB After Width: | Height: | Size: 517 KiB |
@ -3,7 +3,7 @@
|
||||
ahriman
|
||||
.SH SYNOPSIS
|
||||
.B ahriman
|
||||
[-h] [-a ARCHITECTURE] [-c CONFIGURATION] [--force] [-l LOCK] [--no-report] [-q] [--unsafe] [-v] {aur-search,search,help,help-commands-unsafe,key-import,package-add,add,package-update,package-remove,remove,package-status,status,package-status-remove,package-status-update,status-update,patch-add,patch-list,patch-remove,repo-backup,repo-check,check,repo-clean,clean,repo-config,config,repo-rebuild,rebuild,repo-remove-unknown,remove-unknown,repo-report,report,repo-restore,repo-setup,init,repo-init,setup,repo-sign,sign,repo-status-update,repo-sync,sync,repo-update,update,user-add,user-list,user-remove,web} ...
|
||||
[-h] [-a ARCHITECTURE] [-c CONFIGURATION] [--force] [-l LOCK] [--no-report] [-q] [--unsafe] [-v] {aur-search,search,help,help-commands-unsafe,key-import,package-add,add,package-update,package-remove,remove,package-status,status,package-status-remove,package-status-update,status-update,patch-add,patch-list,patch-remove,repo-backup,repo-check,check,repo-clean,clean,repo-config,config,repo-rebuild,rebuild,repo-remove-unknown,remove-unknown,repo-restore,repo-setup,init,repo-init,setup,repo-sign,sign,repo-status-update,repo-triggers,repo-update,update,user-add,user-list,user-remove,web} ...
|
||||
.SH DESCRIPTION
|
||||
ArcH Linux ReposItory MANager
|
||||
|
||||
@ -97,9 +97,6 @@ rebuild repository
|
||||
\fBahriman\fR \fI\,repo-remove-unknown\/\fR
|
||||
remove unknown packages
|
||||
.TP
|
||||
\fBahriman\fR \fI\,repo-report\/\fR
|
||||
generate report
|
||||
.TP
|
||||
\fBahriman\fR \fI\,repo-restore\/\fR
|
||||
restore repository data
|
||||
.TP
|
||||
@ -112,8 +109,8 @@ sign packages
|
||||
\fBahriman\fR \fI\,repo-status-update\/\fR
|
||||
update repository status
|
||||
.TP
|
||||
\fBahriman\fR \fI\,repo-sync\/\fR
|
||||
sync repository
|
||||
\fBahriman\fR \fI\,repo-triggers\/\fR
|
||||
run triggers
|
||||
.TP
|
||||
\fBahriman\fR \fI\,repo-update\/\fR
|
||||
update packages
|
||||
@ -408,15 +405,6 @@ just perform check for packages without removal
|
||||
\fB\-i\fR, \fB\-\-info\fR
|
||||
show additional package information
|
||||
|
||||
.SH COMMAND \fI\,'ahriman repo-report'\/\fR
|
||||
usage: ahriman repo-report [-h] [target ...]
|
||||
|
||||
generate repository report according to current settings
|
||||
|
||||
.TP
|
||||
\fBtarget\fR
|
||||
target to generate report
|
||||
|
||||
.SH COMMAND \fI\,'ahriman repo-restore'\/\fR
|
||||
usage: ahriman repo-restore [-h] [-o OUTPUT] path
|
||||
|
||||
@ -497,14 +485,10 @@ update repository status on the status page
|
||||
\fB\-s\fR \fI\,{BuildStatusEnum.Unknown,BuildStatusEnum.Pending,BuildStatusEnum.Building,BuildStatusEnum.Failed,BuildStatusEnum.Success}\/\fR, \fB\-\-status\fR \fI\,{BuildStatusEnum.Unknown,BuildStatusEnum.Pending,BuildStatusEnum.Building,BuildStatusEnum.Failed,BuildStatusEnum.Success}\/\fR
|
||||
new status
|
||||
|
||||
.SH COMMAND \fI\,'ahriman repo-sync'\/\fR
|
||||
usage: ahriman repo-sync [-h] [target ...]
|
||||
.SH COMMAND \fI\,'ahriman repo-triggers'\/\fR
|
||||
usage: ahriman repo-triggers [-h]
|
||||
|
||||
sync repository files to remote server according to current settings
|
||||
|
||||
.TP
|
||||
\fBtarget\fR
|
||||
target to sync
|
||||
run triggers on empty build result as configured by settings
|
||||
|
||||
.SH COMMAND \fI\,'ahriman repo-update'\/\fR
|
||||
usage: ahriman repo-update [-h] [--dry-run] [-e] [--no-aur] [--no-local] [--no-manual] [--no-vcs] [package ...]
|
||||
|
@ -92,14 +92,6 @@ ahriman.application.handlers.remove\_unknown module
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
ahriman.application.handlers.report module
|
||||
------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.application.handlers.report
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
ahriman.application.handlers.restore module
|
||||
-------------------------------------------
|
||||
|
||||
@ -148,10 +140,10 @@ ahriman.application.handlers.status\_update module
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
ahriman.application.handlers.sync module
|
||||
----------------------------------------
|
||||
ahriman.application.handlers.triggers module
|
||||
--------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.application.handlers.sync
|
||||
.. automodule:: ahriman.application.handlers.triggers
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
|
@ -44,6 +44,14 @@ ahriman.core.report.report module
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
ahriman.core.report.report\_trigger module
|
||||
------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.report.report_trigger
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
ahriman.core.report.telegram module
|
||||
-----------------------------------
|
||||
|
||||
|
@ -16,6 +16,7 @@ Subpackages
|
||||
ahriman.core.repository
|
||||
ahriman.core.sign
|
||||
ahriman.core.status
|
||||
ahriman.core.triggers
|
||||
ahriman.core.upload
|
||||
|
||||
Submodules
|
||||
|
29
docs/ahriman.core.triggers.rst
Normal file
29
docs/ahriman.core.triggers.rst
Normal file
@ -0,0 +1,29 @@
|
||||
ahriman.core.triggers package
|
||||
=============================
|
||||
|
||||
Submodules
|
||||
----------
|
||||
|
||||
ahriman.core.triggers.trigger module
|
||||
------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.triggers.trigger
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
ahriman.core.triggers.trigger\_loader module
|
||||
--------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.triggers.trigger_loader
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
.. automodule:: ahriman.core.triggers
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
@ -44,6 +44,14 @@ ahriman.core.upload.upload module
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
ahriman.core.upload.upload\_trigger module
|
||||
------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.upload.upload_trigger
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
|
@ -7,7 +7,7 @@ Package structure
|
||||
Packages have strict rules of importing:
|
||||
|
||||
* ``ahriman.application`` package must not be used anywhere except for itself.
|
||||
* ``ahriman.core`` and ``ahriman.models`` packages don't have any import restriction. Actually we would like to totally restrict importing of ``core`` package from ``models``\ , but it is impossible at the moment.
|
||||
* ``ahriman.core`` and ``ahriman.models`` packages don't have any import restriction. Actually we would like to totally restrict importing of ``core`` package from ``models``, but it is impossible at the moment.
|
||||
* ``ahriman.web`` package is allowed to be imported from ``ahriman.application`` (web handler only, only ``ahriman.web.web`` methods). It also must not be imported globally, only local import is allowed.
|
||||
|
||||
Full dependency diagram:
|
||||
@ -30,13 +30,13 @@ This package contains application (aka executable) related classes and everythin
|
||||
|
||||
This package contains everything which is required for any time of application run and separated to several packages:
|
||||
|
||||
* ``ahriman.core.alpm`` package controls pacman related functions. It provides wrappers for ``pyalpm`` library and safe calls for repository tools (\ ``repo-add`` and ``repo-remove``\ ). Also this package contains ``ahriman.core.alpm.remote`` package which provides wrapper for remote sources (e.g. AUR RPC and official repositories RPC).
|
||||
* ``ahriman.core.alpm`` package controls pacman related functions. It provides wrappers for ``pyalpm`` library and safe calls for repository tools (``repo-add`` and ``repo-remove``). Also this package contains ``ahriman.core.alpm.remote`` package which provides wrapper for remote sources (e.g. AUR RPC and official repositories RPC).
|
||||
* ``ahriman.core.auth`` package provides classes for authorization methods used by web mostly. Base class is ``ahriman.core.auth.auth.Auth`` which must be called by ``load`` method.
|
||||
* ``ahriman.core.build_tools`` is a package which provides wrapper for ``devtools`` commands.
|
||||
* ``ahriman.core.database`` is everything including data and schema migrations for database.
|
||||
* ``ahriman.core.formatters`` package provides ``Printer`` sub-classes for printing data (e.g. package properties) to stdout which are used by some handlers.
|
||||
* ``ahriman.core.report`` is a package with reporting classes. Usually it must be called by ``ahriman.core.report.report.Report.load`` method.
|
||||
* ``ahriman.core.repository`` contains several traits and base repository (\ ``ahriman.core.repository.repository.Repository`` class) implementation.
|
||||
* ``ahriman.core.repository`` contains several traits and base repository (``ahriman.core.repository.repository.Repository`` class) implementation.
|
||||
* ``ahriman.core.sign`` package provides sign feature (only gpg calls are available).
|
||||
* ``ahriman.core.status`` contains helpers and watcher class which are required for web application. Reporter must be initialized by using ``ahriman.core.status.client.Client.load`` method.
|
||||
* ``ahriman.core.upload`` package provides sync feature, must be called by ``ahriman.core.upload.upload.Upload.load`` method.
|
||||
@ -68,7 +68,7 @@ Application run
|
||||
|
||||
* Parse command line arguments, find command and related handler which is set by parser.
|
||||
* Call ``Handler.execute`` method.
|
||||
* Define list of architectures to run. In case if there is more than one architecture specified run several subprocesses or process in current process otherwise. Class attribute ``ALLOW_MULTI_ARCHITECTURE_RUN`` controls whether application can be run in multiple processes or not - this feature is required for some handlers (e.g. ``Web``\ ) which should be able to spawn child process in daemon mode (it is impossible to do for daemonic processes).
|
||||
* Define list of architectures to run. In case if there is more than one architecture specified run several subprocesses or process in current process otherwise. Class attribute ``ALLOW_MULTI_ARCHITECTURE_RUN`` controls whether application can be run in multiple processes or not - this feature is required for some handlers (e.g. ``Web``) which should be able to spawn child process in daemon mode (it is impossible to do for daemonic processes).
|
||||
* In each child process call lock functions.
|
||||
* After success checks pass control to ``Handler.run`` method defined by specific handler class.
|
||||
* Return result (success or failure) of each subprocess and exit from application.
|
||||
@ -102,7 +102,7 @@ Type conversions
|
||||
|
||||
By default, it parses rows into python dictionary. In addition, the following pseudo-types are supported:
|
||||
|
||||
* ``Dict[str, Any]``\ , ``List[Any]`` - for storing JSON data structures in database (technically there is no restriction on types for dictionary keys and values, but it is recommended to use only string keys). The type is stored as ``json`` datatype and ``json.loads`` and ``json.dumps`` methods are used in order to read and write from/to database respectively.
|
||||
* ``Dict[str, Any]``, ``List[Any]`` - for storing JSON data structures in database (technically there is no restriction on types for dictionary keys and values, but it is recommended to use only string keys). The type is stored as ``json`` datatype and ``json.loads`` and ``json.dumps`` methods are used in order to read and write from/to database respectively.
|
||||
|
||||
Basic flows
|
||||
-----------
|
||||
@ -113,7 +113,7 @@ Add new packages or rebuild existing
|
||||
Idea is to copy package to the directory from which it will be handled at the next update run. Different variants are supported:
|
||||
|
||||
* If supplied argument is file then application moves the file to the directory with built packages. Same rule applies for directory, but in this case it copies every package-like file from the specified directory.
|
||||
* If supplied argument is directory and there is ``PKGBUILD`` file there it will be treated as local package. In this case it will queue this package to build and copy source files (\ ``PKGBUILD`` and ``.SRCINFO``\ ) to caches.
|
||||
* If supplied argument is directory and there is ``PKGBUILD`` file there it will be treated as local package. In this case it will queue this package to build and copy source files (``PKGBUILD`` and ``.SRCINFO``) to caches.
|
||||
* If supplied argument iis not file then application tries to lookup for the specified name in AUR and clones it into the directory with manual updates. This scenario can also handle package dependencies which are missing in repositories.
|
||||
|
||||
This logic can be overwritten by specifying the ``source`` parameter, which is partially useful if you would like to add package from AUR, but there is local directory cloned from AUR.
|
||||
@ -142,7 +142,7 @@ This feature is divided into to stages: check AUR for updates and run rebuild fo
|
||||
#. Build every package in clean chroot.
|
||||
#. Sign packages if required.
|
||||
#. Add packages to database and sign database if required.
|
||||
#. Process sync and report methods.
|
||||
#. Process triggers.
|
||||
|
||||
After any step any package data is being removed.
|
||||
|
||||
@ -152,7 +152,7 @@ Core functions reference
|
||||
Configuration
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
``ahriman.core.configuration.Configuration`` class provides some additional methods (e.g. ``getpath`` and ``getlist``\ ) and also combines multiple files into single configuration dictionary using architecture overrides. It is the recommended way to deal with settings.
|
||||
``ahriman.core.configuration.Configuration`` class provides some additional methods (e.g. ``getpath`` and ``getlist``) and also combines multiple files into single configuration dictionary using architecture overrides. It is the recommended way to deal with settings.
|
||||
|
||||
Utils
|
||||
^^^^^
|
||||
@ -176,7 +176,7 @@ Mapping (aka configuration) provider uses hashed passwords with salt from the da
|
||||
* ``check_credentials`` - user password validation (authentication).
|
||||
* ``verify_access`` - user permission validation (authorization).
|
||||
|
||||
Passwords must be stored in database as ``hash(password + salt)``\ , where ``password`` is user defined password (taken from user input), ``salt`` is random string (any length) defined globally in configuration and ``hash`` is secure hash function. Thus, the following configuration
|
||||
Passwords must be stored in database as ``hash(password + salt)``, where ``password`` is user defined password (taken from user input), ``salt`` is random string (any length) defined globally in configuration and ``hash`` is secure hash function. Thus, the following configuration
|
||||
|
||||
.. code-block::
|
||||
|
||||
@ -185,20 +185,31 @@ Passwords must be stored in database as ``hash(password + salt)``\ , where ``pas
|
||||
|
||||
means that there is user ``username`` with ``read`` access and password ``password`` hashed by ``sha512`` with salt ``salt``.
|
||||
|
||||
OAuth provider uses library definitions (\ ``aioauth-client``\ ) in order *authenticate* users. It still requires user permission to be set in database, thus it inherits mapping provider without any changes. Whereas we could override ``check_credentials`` (authentication method) by something custom, OAuth flow is a bit more complex than just forward request, thus we have to implement the flow in login form.
|
||||
OAuth provider uses library definitions (``aioauth-client``) in order *authenticate* users. It still requires user permission to be set in database, thus it inherits mapping provider without any changes. Whereas we could override ``check_credentials`` (authentication method) by something custom, OAuth flow is a bit more complex than just forward request, thus we have to implement the flow in login form.
|
||||
|
||||
OAuth's implementation also allows authenticating users via username + password (in the same way as mapping does) though it is not recommended for end-users and password must be left blank. In particular this feature is used by service reporting (aka robots).
|
||||
|
||||
In order to configure users there are special commands.
|
||||
|
||||
Triggers
|
||||
^^^^^^^^
|
||||
|
||||
Triggers are extensions which can be used in order to perform any actions after the update process. The package provides two default extensions - one is report generation and another one is remote upload feature.
|
||||
|
||||
The main idea is to load classes by their full path (e.g. ``ahriman.core.upload.UploadTrigger``) by using ``importlib``: get the last part of the import and treat it as class name, join remain part by ``.`` and interpret as module path, import module and extract attribute from it.
|
||||
|
||||
The loaded triggers will be called with ``ahriman.models.result.Result`` and ``List[Packages]`` arguments, which describes the process result and current repository packages respectively. Any exception raised will be suppressed and will generate an exception message in logs.
|
||||
|
||||
For more details how to deal with the triggers, refer to :doc:`documentation <triggers>` and modules descriptions.
|
||||
|
||||
Remote synchronization
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
There are several supported synchronization providers, currently they are ``rsync``\ , ``s3``\ , ``github``.
|
||||
There are several supported synchronization providers, currently they are ``rsync``, ``s3``, ``github``.
|
||||
|
||||
``rsync`` provider does not have any specific logic except for running external rsync application with configured arguments. The service does not handle SSH configuration, thus it has to be configured before running application manually.
|
||||
|
||||
``s3`` provider uses ``boto3`` package and implements sync feature. The files are stored in architecture directory (e.g. if bucket is ``repository``\ , packages will be stored in ``repository/x86_64`` for the ``x86_64`` architecture), bucket must be created before any action and API key must have permissions to write to the bucket. No external configuration required. In order to upload only changed files the service compares calculated hashes with the Amazon ETags, used realization is described `here <https://teppen.io/2018/10/23/aws_s3_verify_etags/>`_.
|
||||
``s3`` provider uses ``boto3`` package and implements sync feature. The files are stored in architecture directory (e.g. if bucket is ``repository``, packages will be stored in ``repository/x86_64`` for the ``x86_64`` architecture), bucket must be created before any action and API key must have permissions to write to the bucket. No external configuration required. In order to upload only changed files the service compares calculated hashes with the Amazon ETags, used realization is described `here <https://teppen.io/2018/10/23/aws_s3_verify_etags/>`_.
|
||||
|
||||
``github`` provider authenticates through basic auth, API key with repository write permissions is required. There will be created a release with the name of the architecture in case if it does not exist; files will be uploaded to the release assets. It also stores array of files and their MD5 checksums in release body in order to upload only changed ones. According to the Github API in case if there is already uploaded asset with the same name (e.g. database files), asset will be removed first.
|
||||
|
||||
@ -207,7 +218,7 @@ Additional features
|
||||
|
||||
Some features require optional dependencies to be installed:
|
||||
|
||||
* Version control executables (e.g. ``git``\ , ``svn``\ ) for VCS packages.
|
||||
* Version control executables (e.g. ``git``, ``svn``) for VCS packages.
|
||||
* ``gnupg`` application for package and repository sign feature.
|
||||
* ``rsync`` application for rsync based repository sync.
|
||||
* ``boto3`` python package for ``S3`` sync.
|
||||
@ -220,7 +231,7 @@ Web application requires the following python packages to be installed:
|
||||
|
||||
* Core part requires ``aiohttp`` (application itself), ``aiohttp_jinja2`` and ``Jinja2`` (HTML generation from templates).
|
||||
* In addition, ``aiohttp_debugtoolbar`` is required for debug panel. Please note that this option does not work together with authorization and basically must not be used in production.
|
||||
* In addition, authorization feature requires ``aiohttp_security``\ , ``aiohttp_session`` and ``cryptography``.
|
||||
* In addition, authorization feature requires ``aiohttp_security``, ``aiohttp_session`` and ``cryptography``.
|
||||
* In addition to base authorization dependencies, OAuth2 also requires ``aioauth-client`` library.
|
||||
|
||||
Middlewares
|
||||
|
@ -1,5 +1,5 @@
|
||||
Commands help
|
||||
=============
|
||||
Commands reference
|
||||
==================
|
||||
|
||||
ahriman
|
||||
-------
|
||||
|
@ -6,11 +6,11 @@ Some groups can be specified for each architecture separately. E.g. if there are
|
||||
There are two variable types which have been added to default ones, they are paths and lists. List values will be read in the same way as shell does:
|
||||
|
||||
* By default, it splits value by spaces excluding empty elements.
|
||||
* In case if quotation mark (\ ``"`` or ``'``\ ) will be found, any spaces inside will be ignored.
|
||||
* In case if quotation mark (``"`` or ``'``) will be found, any spaces inside will be ignored.
|
||||
* In order to use quotation mark inside value it is required to put it to another quotation mark, e.g. ``wor"'"d "with quote"`` will be parsed as ``["wor'd", "with quote"]`` and vice versa.
|
||||
* Unclosed quotation mark is not allowed and will rise an exception.
|
||||
|
||||
Path values, except for casting to ``pathlib.Path`` type, will be also expanded to absolute paths relative to the configuration path. E.g. if path is set to ``ahriman.ini.d/logging.ini`` and root configuration path is ``/etc/ahriman.ini``\ , the value will be expanded to ``/etc/ahriman.ini.d/logging.ini``. In order to disable path expand, use the full path, e.g. ``/etc/ahriman.ini.d/logging.ini``.
|
||||
Path values, except for casting to ``pathlib.Path`` type, will be also expanded to absolute paths relative to the configuration path. E.g. if path is set to ``ahriman.ini.d/logging.ini`` and root configuration path is ``/etc/ahriman.ini``, the value will be expanded to ``/etc/ahriman.ini.d/logging.ini``. In order to disable path expand, use the full path, e.g. ``/etc/ahriman.ini.d/logging.ini``.
|
||||
|
||||
``settings`` group
|
||||
------------------
|
||||
@ -35,12 +35,12 @@ libalpm and AUR related configuration.
|
||||
|
||||
Base authorization settings. ``OAuth`` provider requires ``aioauth-client`` library to be installed.
|
||||
|
||||
* ``target`` - specifies authorization provider, string, optional, default ``disabled``. Allowed values are ``disabled``\ , ``configuration``\ , ``oauth``.
|
||||
* ``target`` - specifies authorization provider, string, optional, default ``disabled``. Allowed values are ``disabled``, ``configuration``, ``oauth``.
|
||||
* ``client_id`` - OAuth2 application client ID, string, required in case if ``oauth`` is used.
|
||||
* ``client_secret`` - OAuth2 application client secret key, string, required in case if ``oauth`` is used.
|
||||
* ``max_age`` - parameter which controls both cookie expiration and token expiration inside the service, integer, optional, default is 7 days.
|
||||
* ``oauth_provider`` - OAuth2 provider class name as is in ``aioauth-client`` (e.g. ``GoogleClient``\ , ``GithubClient`` etc), string, required in case if ``oauth`` is used.
|
||||
* ``oauth_scopes`` - scopes list for OAuth2 provider, which will allow retrieving user email (which is used for checking user permissions), e.g. ``https://www.googleapis.com/auth/userinfo.email`` for ``GoogleClient`` or ``user:email`` for ``GithubClient``\ , space separated list of strings, required in case if ``oauth`` is used.
|
||||
* ``oauth_provider`` - OAuth2 provider class name as is in ``aioauth-client`` (e.g. ``GoogleClient``, ``GithubClient`` etc), string, required in case if ``oauth`` is used.
|
||||
* ``oauth_scopes`` - scopes list for OAuth2 provider, which will allow retrieving user email (which is used for checking user permissions), e.g. ``https://www.googleapis.com/auth/userinfo.email`` for ``GoogleClient`` or ``user:email`` for ``GithubClient``, space separated list of strings, required in case if ``oauth`` is used.
|
||||
* ``safe_build_status`` - allow requesting status page without authorization, boolean, required.
|
||||
* ``salt`` - password hash salt, string, required in case if authorization enabled (automatically generated by ``create-user`` subcommand).
|
||||
|
||||
@ -56,6 +56,7 @@ Build related configuration. Group name can refer to architecture, e.g. ``build:
|
||||
* ``ignore_packages`` - list packages to ignore during a regular update (manual update will still work), space separated list of strings, optional.
|
||||
* ``makepkg_flags`` - additional flags passed to ``makepkg`` command, space separated list of strings, optional.
|
||||
* ``makechrootpkg_flags`` - additional flags passed to ``makechrootpkg`` command, space separated list of strings, optional.
|
||||
* ``triggers`` - list of trigger classes (e.g. ``ahriman.core.report.ReportTrigger ahriman.core.upload.UploadTrigger``) which will be loaded and run at the end of processing, space separated list of strings, optional. You can also specify triggers by their paths, e.g. ``/usr/lib/python3.10/site-packages/ahriman/core/report/report.py.ReportTrigger``. Triggers are run in the order of mention.
|
||||
|
||||
``repository`` group
|
||||
--------------------
|
||||
@ -90,14 +91,14 @@ Type will be read from several ways:
|
||||
``console`` type
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
Section name must be either ``console`` (plus optional architecture name, e.g. ``console:x86_64``\ ) or random name with ``type`` set.
|
||||
Section name must be either ``console`` (plus optional architecture name, e.g. ``console:x86_64``) or random name with ``type`` set.
|
||||
|
||||
* ``use_utf`` - use utf8 symbols in output if set and ascii otherwise, boolean, optional, default ``yes``.
|
||||
|
||||
``email`` type
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
Section name must be either ``email`` (plus optional architecture name, e.g. ``email:x86_64``\ ) or random name with ``type`` set.
|
||||
Section name must be either ``email`` (plus optional architecture name, e.g. ``email:x86_64``) or random name with ``type`` set.
|
||||
|
||||
* ``type`` - type of the report, string, optional, must be set to ``email`` if exists.
|
||||
* ``full_template_path`` - path to Jinja2 template for full package description index, string, optional.
|
||||
@ -109,14 +110,14 @@ Section name must be either ``email`` (plus optional architecture name, e.g. ``e
|
||||
* ``port`` - SMTP port for sending emails, int, required.
|
||||
* ``receivers`` - SMTP receiver addresses, space separated list of strings, required.
|
||||
* ``sender`` - SMTP sender address, string, required.
|
||||
* ``ssl`` - SSL mode for SMTP connection, one of ``ssl``\ , ``starttls``\ , ``disabled``\ , optional, default ``disabled``.
|
||||
* ``ssl`` - SSL mode for SMTP connection, one of ``ssl``, ``starttls``, ``disabled``, optional, default ``disabled``.
|
||||
* ``template_path`` - path to Jinja2 template, string, required.
|
||||
* ``user`` - SMTP user to authenticate, string, optional.
|
||||
|
||||
``html`` type
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
Section name must be either ``html`` (plus optional architecture name, e.g. ``html:x86_64``\ ) or random name with ``type`` set.
|
||||
Section name must be either ``html`` (plus optional architecture name, e.g. ``html:x86_64``) or random name with ``type`` set.
|
||||
|
||||
* ``type`` - type of the report, string, optional, must be set to ``html`` if exists.
|
||||
* ``path`` - path to html report file, string, required.
|
||||
@ -127,7 +128,7 @@ Section name must be either ``html`` (plus optional architecture name, e.g. ``ht
|
||||
``telegram`` type
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
Section name must be either ``telegram`` (plus optional architecture name, e.g. ``telegram:x86_64``\ ) or random name with ``type`` set.
|
||||
Section name must be either ``telegram`` (plus optional architecture name, e.g. ``telegram:x86_64``) or random name with ``type`` set.
|
||||
|
||||
* ``type`` - type of the report, string, optional, must be set to ``telegram`` if exists.
|
||||
* ``api_key`` - telegram bot API key, string, required. Please refer FAQ about how to create chat and bot
|
||||
@ -135,7 +136,7 @@ Section name must be either ``telegram`` (plus optional architecture name, e.g.
|
||||
* ``homepage`` - link to homepage, string, optional.
|
||||
* ``link_path`` - prefix for HTML links, string, required.
|
||||
* ``template_path`` - path to Jinja2 template, string, required.
|
||||
* ``template_type`` - ``parse_mode`` to be passed to telegram API, one of ``MarkdownV2``\ , ``HTML``\ , ``Markdown``\ , string, optional, default ``HTML``.
|
||||
* ``template_type`` - ``parse_mode`` to be passed to telegram API, one of ``MarkdownV2``, ``HTML``, ``Markdown``, string, optional, default ``HTML``.
|
||||
|
||||
``upload`` group
|
||||
----------------
|
||||
@ -153,7 +154,7 @@ Type will be read from several ways:
|
||||
``github`` type
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
This feature requires Github key creation (see below). Section name must be either ``github`` (plus optional architecture name, e.g. ``github:x86_64``\ ) or random name with ``type`` set.
|
||||
This feature requires Github key creation (see below). Section name must be either ``github`` (plus optional architecture name, e.g. ``github:x86_64``) or random name with ``type`` set.
|
||||
|
||||
* ``type`` - type of the upload, string, optional, must be set to ``github`` if exists.
|
||||
* ``owner`` - Github repository owner, string, required.
|
||||
@ -170,30 +171,30 @@ This feature requires Github key creation (see below). Section name must be eith
|
||||
``rsync`` type
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
Requires ``rsync`` package to be installed. Do not forget to configure ssh for user ``ahriman``. Section name must be either ``rsync`` (plus optional architecture name, e.g. ``rsync:x86_64``\ ) or random name with ``type`` set.
|
||||
Requires ``rsync`` package to be installed. Do not forget to configure ssh for user ``ahriman``. Section name must be either ``rsync`` (plus optional architecture name, e.g. ``rsync:x86_64``) or random name with ``type`` set.
|
||||
|
||||
* ``type`` - type of the upload, string, optional, must be set to ``rsync`` if exists.
|
||||
* ``command`` - rsync command to run, space separated list of string, required.
|
||||
* ``remote`` - remote server to rsync (e.g. ``1.2.3.4:path/to/sync``\ ), string, required.
|
||||
* ``remote`` - remote server to rsync (e.g. ``1.2.3.4:path/to/sync``), string, required.
|
||||
|
||||
``s3`` type
|
||||
^^^^^^^^^^^
|
||||
|
||||
Requires ``boto3`` library to be installed. Section name must be either ``s3`` (plus optional architecture name, e.g. ``s3:x86_64``\ ) or random name with ``type`` set.
|
||||
Requires ``boto3`` library to be installed. Section name must be either ``s3`` (plus optional architecture name, e.g. ``s3:x86_64``) or random name with ``type`` set.
|
||||
|
||||
* ``type`` - type of the upload, string, optional, must be set to ``github`` if exists.
|
||||
* ``access_key`` - AWS access key ID, string, required.
|
||||
* ``bucket`` - bucket name (e.g. ``bucket``\ ), string, required.
|
||||
* ``bucket`` - bucket name (e.g. ``bucket``), string, required.
|
||||
* ``chunk_size`` - chunk size for calculating entity tags, int, optional, default 8 * 1024 * 1024.
|
||||
* ``region`` - bucket region (e.g. ``eu-central-1``\ ), string, required.
|
||||
* ``region`` - bucket region (e.g. ``eu-central-1``), string, required.
|
||||
* ``secret_key`` - AWS secret access key, string, required.
|
||||
|
||||
``web:*`` groups
|
||||
----------------
|
||||
|
||||
Web server settings. If any of ``host``\ /\ ``port`` is not set, web integration will be disabled. Group name can refer to architecture, e.g. ``web:x86_64`` can be used for x86_64 architecture specific settings. This feature requires ``aiohttp`` libraries to be installed.
|
||||
Web server settings. If any of ``host``/``port`` is not set, web integration will be disabled. Group name can refer to architecture, e.g. ``web:x86_64`` can be used for x86_64 architecture specific settings. This feature requires ``aiohttp`` libraries to be installed.
|
||||
|
||||
* ``address`` - optional address in form ``proto://host:port`` (\ ``port`` can be omitted in case of default ``proto`` ports), will be used instead of ``http://{host}:{port}`` in case if set, string, optional. This option is required in case if ``OAuth`` provider is used.
|
||||
* ``address`` - optional address in form ``proto://host:port`` (``port`` can be omitted in case of default ``proto`` ports), will be used instead of ``http://{host}:{port}`` in case if set, string, optional. This option is required in case if ``OAuth`` provider is used.
|
||||
* ``debug`` - enable debug toolbar, boolean, optional, default ``no``.
|
||||
* ``debug_check_host`` - check hosts to access debug toolbar, boolean, optional, default ``no``.
|
||||
* ``debug_allowed_hosts`` - allowed hosts to get access to debug toolbar, space separated list of string, optional.
|
||||
|
24
docs/faq.rst
24
docs/faq.rst
@ -118,7 +118,7 @@ But I just wanted to change PKGBUILD from AUR a bit!
|
||||
Well it is supported also.
|
||||
|
||||
#. Clone sources from AUR.
|
||||
#. Make changes you would like to (e.g. edit ``PKGBUILD``\ , add external patches).
|
||||
#. Make changes you would like to (e.g. edit ``PKGBUILD``, add external patches).
|
||||
#. Run ``sudo -u ahriman ahriman patch-add /path/to/local/directory/with/PKGBUILD``.
|
||||
|
||||
The last command will calculate diff from current tree to the ``HEAD`` and will store it locally. Patches will be applied on any package actions (e.g. it can be used for dependency management).
|
||||
@ -177,7 +177,7 @@ However, note that you do not need to rebuild repository in case if you just cha
|
||||
Hmm, I have packages built, but how can I use it?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Add the following lines to your ``pacman.conf``\ :
|
||||
Add the following lines to your ``pacman.conf``:
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
@ -238,7 +238,7 @@ The default action (in case if no arguments provided) is ``repo-update``. Basica
|
||||
|
||||
docker run -v /path/to/local/repo:/var/lib/ahriman -v /etc/ahriman.ini:/etc/ahriman.ini.d/10-overrides.ini arcan1s/ahriman:latest
|
||||
|
||||
By default, it runs ``repo-update``\ , but it can be overwritten to any other command you would like to, e.g.:
|
||||
By default, it runs ``repo-update``, but it can be overwritten to any other command you would like to, e.g.:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
@ -255,7 +255,7 @@ The following environment variables are supported:
|
||||
* ``AHRIMAN_DEBUG`` - if set all commands will be logged to console.
|
||||
* ``AHRIMAN_FORCE_ROOT`` - force run ahriman as root instead of guessing by subcommand.
|
||||
* ``AHRIMAN_HOST`` - host for the web interface, default is ``0.0.0.0``.
|
||||
* ``AHRIMAN_OUTPUT`` - controls logging handler, e.g. ``syslog``\ , ``console``. The name must be found in logging configuration. Note that if ``syslog`` (the default) handler is used you will need to mount ``/dev/log`` inside container because it is not available there.
|
||||
* ``AHRIMAN_OUTPUT`` - controls logging handler, e.g. ``syslog``, ``console``. The name must be found in logging configuration. Note that if ``syslog`` (the default) handler is used you will need to mount ``/dev/log`` inside container because it is not available there.
|
||||
* ``AHRIMAN_PACKAGER`` - packager name from which packages will be built, default is ``ahriman bot <ahriman@example.com>``.
|
||||
* ``AHRIMAN_PORT`` - HTTP server port if any, default is empty.
|
||||
* ``AHRIMAN_REPOSITORY`` - repository name, default is ``aur-clone``.
|
||||
@ -279,7 +279,7 @@ Well for that you would need to have web container instance running forever; it
|
||||
|
||||
Note about ``AHRIMAN_PORT`` environment variable which is required in order to enable web service. An additional port bind by ``-p 8080:8080`` is required to pass docker port outside of container.
|
||||
|
||||
For every next container run use arguments ``-e AHRIMAN_PORT=8080 --net=host``\ , e.g.:
|
||||
For every next container run use arguments ``-e AHRIMAN_PORT=8080 --net=host``, e.g.:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
@ -294,7 +294,7 @@ Wait I would like to use the repository from another server
|
||||
There are several choices:
|
||||
|
||||
#.
|
||||
Easy and cheap, just share your local files through the internet, e.g. for ``nginx``\ :
|
||||
Easy and cheap, just share your local files through the internet, e.g. for ``nginx``:
|
||||
|
||||
.. code-block::
|
||||
|
||||
@ -316,7 +316,7 @@ There are several choices:
|
||||
[rsync]
|
||||
remote = 192.168.0.1:/srv/repo
|
||||
|
||||
After that just add ``/srv/repo`` to the ``pacman.conf`` as usual. You can also upload to S3 (e.g. ``Server = https://s3.eu-central-1.amazonaws.com/repository/x86_64``\ ) or to Github (e.g. ``Server = https://github.com/ahriman/repository/releases/download/x86_64``\ ).
|
||||
After that just add ``/srv/repo`` to the ``pacman.conf`` as usual. You can also upload to S3 (e.g. ``Server = https://s3.eu-central-1.amazonaws.com/repository/x86_64``) or to Github (e.g. ``Server = https://github.com/ahriman/repository/releases/download/x86_64``).
|
||||
|
||||
How do I configure S3?
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -474,7 +474,7 @@ I would like to get messages to my telegram account/channel
|
||||
#. Make your channel public
|
||||
|
||||
#.
|
||||
Get chat id if you want to use by numerical id or just use id prefixed with ``@`` (e.g. ``@ahriman``\ ). If you are not using chat the chat id is your user id. If you don't want to make channel public you can use `this guide <https://stackoverflow.com/a/33862907>`_.
|
||||
Get chat id if you want to use by numerical id or just use id prefixed with ``@`` (e.g. ``@ahriman``). If you are not using chat the chat id is your user id. If you don't want to make channel public you can use `this guide <https://stackoverflow.com/a/33862907>`_.
|
||||
|
||||
#.
|
||||
Configure the service:
|
||||
@ -489,7 +489,7 @@ I would like to get messages to my telegram account/channel
|
||||
chat_id = @ahriman
|
||||
link_path = http://example.com/x86_64
|
||||
|
||||
``api_key`` is the one sent by `@BotFather <https://t.me/botfather>`_\ , ``chat_id`` is the value retrieved from previous step.
|
||||
``api_key`` is the one sent by `@BotFather <https://t.me/botfather>`_, ``chat_id`` is the value retrieved from previous step.
|
||||
|
||||
If you did everything fine you should receive the message with the next update. Quick credentials check can be done by using the following command:
|
||||
|
||||
@ -606,7 +606,7 @@ The service provides several commands aim to do easy repository backup and resto
|
||||
|
||||
sudo ahriman repo-backup /tmp/repo.tar.gz
|
||||
|
||||
This command will pack all configuration files together with database file into the archive specified as command line argument (i.e. ``/tmp/repo.tar.gz``\ ). In addition it will also archive ``cache`` directory (the one which contains local clones used by e.g. local packages) and ``.gnupg`` of the ``ahriman`` user.
|
||||
This command will pack all configuration files together with database file into the archive specified as command line argument (i.e. ``/tmp/repo.tar.gz``). In addition it will also archive ``cache`` directory (the one which contains local clones used by e.g. local packages) and ``.gnupg`` of the ``ahriman`` user.
|
||||
|
||||
#.
|
||||
Copy created archive from source server ``server1.example.com`` to target ``server2.example.com``.
|
||||
@ -621,7 +621,7 @@ The service provides several commands aim to do easy repository backup and resto
|
||||
|
||||
sudo ahriman repo-restore /tmp/repo.tar.gz
|
||||
|
||||
An additional argument ``-o``\ /\ ``--output`` can be used to specify extraction root (\ ``/`` by default).
|
||||
An additional argument ``-o``/``--output`` can be used to specify extraction root (``/`` by default).
|
||||
|
||||
#.
|
||||
Rebuild repository:
|
||||
@ -684,7 +684,7 @@ I would like to check service logs
|
||||
|
||||
By default, the service writes logs to ``/dev/log`` which can be accessed by using ``journalctl`` command (logs are written to the journal of the user under which command is run).
|
||||
|
||||
You can also edit configuration and forward logs to ``stderr``\ , just change ``handlers`` value, e.g.:
|
||||
You can also edit configuration and forward logs to ``stderr``, just change ``handlers`` value, e.g.:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
|
@ -10,7 +10,7 @@ Features
|
||||
* Multi-architecture support.
|
||||
* VCS packages support.
|
||||
* Sign support with gpg (repository, package, per package settings).
|
||||
* Synchronization to remote services (rsync, s3 and github) and report generation (email, html, telegram).
|
||||
* Synchronization to remote services (rsync, s3 and github) and report generation (email, html, telegram) and even ability to write own extensions.
|
||||
* Dependency manager.
|
||||
* Ability to patch AUR packages and even create package from local PKGBUILDs.
|
||||
* Repository status interface with optional authorization and control options.
|
||||
@ -27,6 +27,7 @@ Contents
|
||||
faq
|
||||
architecture
|
||||
advanced-usage
|
||||
triggers
|
||||
modules
|
||||
|
||||
Indices and tables
|
||||
|
@ -15,7 +15,7 @@ Initial setup
|
||||
``repo-setup`` literally does the following steps:
|
||||
|
||||
#.
|
||||
Create ``/var/lib/ahriman/.makepkg.conf`` with ``makepkg.conf`` overrides if required (at least you might want to set ``PACKAGER``\ ):
|
||||
Create ``/var/lib/ahriman/.makepkg.conf`` with ``makepkg.conf`` overrides if required (at least you might want to set ``PACKAGER``):
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
@ -25,9 +25,9 @@ Initial setup
|
||||
Configure build tools (it is required for correct dependency management system):
|
||||
|
||||
#.
|
||||
Create build command, e.g. ``ln -s /usr/bin/archbuild /usr/local/bin/ahriman-x86_64-build`` (you can choose any name for command, basically it should be ``{name}-{arch}-build``\ ).
|
||||
Create build command, e.g. ``ln -s /usr/bin/archbuild /usr/local/bin/ahriman-x86_64-build`` (you can choose any name for command, basically it should be ``{name}-{arch}-build``).
|
||||
#.
|
||||
Create configuration file, e.g. ``cp /usr/share/devtools/pacman-{extra,ahriman}.conf`` (same as previous ``pacman-{name}.conf``\ ).
|
||||
Create configuration file, e.g. ``cp /usr/share/devtools/pacman-{extra,ahriman}.conf`` (same as previous ``pacman-{name}.conf``).
|
||||
#.
|
||||
Change configuration file, add your own repository, add multilib repository etc;
|
||||
#.
|
||||
@ -55,7 +55,7 @@ Initial setup
|
||||
chmod 400 /etc/sudoers.d/ahriman
|
||||
|
||||
#.
|
||||
Start and enable ``ahriman@.timer`` via ``systemctl``\ :
|
||||
Start and enable ``ahriman@.timer`` via ``systemctl``:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
|
62
docs/triggers.rst
Normal file
62
docs/triggers.rst
Normal file
@ -0,0 +1,62 @@
|
||||
Triggers
|
||||
========
|
||||
|
||||
The package provides ability to write custom extensions which will be run on (the most) actions, e.g. after updates. By default ahriman provides two types of extensions - reporting and files uploading. Each extension must derive from the ``Trigger`` class and implement ``run`` method
|
||||
|
||||
Trigger example
|
||||
---------------
|
||||
|
||||
Lets consider example of reporting trigger (e.g. `slack <https://slack.com/>`_, which provides easy HTTP API for triggers for integrations).
|
||||
|
||||
In order to post message to slack we will need a specific trigger url (something like ``https://hooks.slack.com/services/company_id/trigger_id``), channel (e.g. ``#archrepo``) and username (``repo-bot``). It can be retrieved from the same application instance.
|
||||
|
||||
As it has been mentioned, our trigger must derive from specific class
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from ahriman.core.triggers import Trigger
|
||||
|
||||
class SlackReporter(Trigger):
|
||||
|
||||
def __init__(self, architecture, configuration):
|
||||
Trigger.__init__(self, architecture, configuration)
|
||||
self.slack_url = configuration.get("slack", "url")
|
||||
self.channel = configuration.get("slack", "channel")
|
||||
self.username = configuration.get("slack", "username")
|
||||
|
||||
By now we have class with all required variables.
|
||||
|
||||
Lets implement run method. Slack API requires positing data with specific payload by HTTP, thus
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import json
|
||||
import requests
|
||||
|
||||
def notify(result, slack_url, channel, username):
|
||||
text = f"""Build has been completed with packages: {", ".join([package.name for package in result.success])}"""
|
||||
payload = {"channel": channel, "username": username, "text": text}
|
||||
response = requests.post(slack_url, data={"payload": json.dumps(payload)})
|
||||
response.raise_for_status()
|
||||
|
||||
Obviously you can implement the specified method in class, but for guide purpose it has been done as separated method. Now we can merge this method into the class
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class SlackReporter(Trigger):
|
||||
|
||||
def __init__(self, architecture, configuration):
|
||||
Trigger.__init__(self, architecture, configuration)
|
||||
self.slack_url = configuration.get("slack", "url")
|
||||
self.channel = configuration.get("slack", "channel")
|
||||
self.username = configuration.get("slack", "username")
|
||||
|
||||
def run(self, result, packages):
|
||||
notify(result, self.slack_url, channel, username)
|
||||
|
||||
Setup the trigger
|
||||
-----------------
|
||||
|
||||
First, put the trigger in any path it can be exported, e.g. by packing the resource into python package (which will lead to import path as ``package.slack_reporter.SlackReporter``) or just put file somewhere it can be accessed by application (e.g. ``/usr/local/lib/slack_reporter.py.SlackReporter``.
|
||||
|
||||
After that run application as usual and receive notification in your slack channel.
|
@ -1,7 +1,7 @@
|
||||
# Maintainer: Evgeniy Alekseev
|
||||
|
||||
pkgname='ahriman'
|
||||
pkgver=2.0.0rc7
|
||||
pkgver=2.0.0rc11
|
||||
pkgrel=1
|
||||
pkgdesc="ArcH Linux ReposItory MANager"
|
||||
arch=('any')
|
||||
|
@ -21,6 +21,7 @@ build_command = extra-x86_64-build
|
||||
ignore_packages =
|
||||
makechrootpkg_flags =
|
||||
makepkg_flags = --nocolor
|
||||
triggers = ahriman.core.report.ReportTrigger ahriman.core.upload.UploadTrigger
|
||||
|
||||
[repository]
|
||||
name = aur-clone
|
||||
|
@ -98,12 +98,11 @@ def _parser() -> argparse.ArgumentParser:
|
||||
_set_repo_config_parser(subparsers)
|
||||
_set_repo_rebuild_parser(subparsers)
|
||||
_set_repo_remove_unknown_parser(subparsers)
|
||||
_set_repo_report_parser(subparsers)
|
||||
_set_repo_restore_parser(subparsers)
|
||||
_set_repo_setup_parser(subparsers)
|
||||
_set_repo_sign_parser(subparsers)
|
||||
_set_repo_status_update_parser(subparsers)
|
||||
_set_repo_sync_parser(subparsers)
|
||||
_set_repo_triggers_parser(subparsers)
|
||||
_set_repo_update_parser(subparsers)
|
||||
_set_user_add_parser(subparsers)
|
||||
_set_user_list_parser(subparsers)
|
||||
@ -496,25 +495,6 @@ def _set_repo_remove_unknown_parser(root: SubParserAction) -> argparse.ArgumentP
|
||||
return parser
|
||||
|
||||
|
||||
def _set_repo_report_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for report subcommand
|
||||
|
||||
Args:
|
||||
root(SubParserAction): subparsers for the commands
|
||||
|
||||
Returns:
|
||||
argparse.ArgumentParser: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("repo-report", aliases=["report"], help="generate report",
|
||||
description="generate repository report according to current settings",
|
||||
epilog="Create and/or update repository report as configured.",
|
||||
formatter_class=_formatter)
|
||||
parser.add_argument("target", help="target to generate report", nargs="*")
|
||||
parser.set_defaults(handler=handlers.Report)
|
||||
return parser
|
||||
|
||||
|
||||
def _set_repo_restore_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for repository restore subcommand
|
||||
@ -600,7 +580,7 @@ def _set_repo_status_update_parser(root: SubParserAction) -> argparse.ArgumentPa
|
||||
return parser
|
||||
|
||||
|
||||
def _set_repo_sync_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
def _set_repo_triggers_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for repository sync subcommand
|
||||
|
||||
@ -610,12 +590,10 @@ def _set_repo_sync_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
Returns:
|
||||
argparse.ArgumentParser: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("repo-sync", aliases=["sync"], help="sync repository",
|
||||
description="sync repository files to remote server according to current settings",
|
||||
epilog="Synchronize the repository to remote services as configured.",
|
||||
parser = root.add_parser("repo-triggers", help="run triggers",
|
||||
description="run triggers on empty build result as configured by settings",
|
||||
formatter_class=_formatter)
|
||||
parser.add_argument("target", help="target to sync", nargs="*")
|
||||
parser.set_defaults(handler=handlers.Sync)
|
||||
parser.set_defaults(handler=handlers.Triggers)
|
||||
return parser
|
||||
|
||||
|
||||
|
@ -56,8 +56,7 @@ class Application(ApplicationPackages, ApplicationRepository):
|
||||
Args:
|
||||
result(Result): build result
|
||||
"""
|
||||
self.report([], result)
|
||||
self.sync([], result.success)
|
||||
self.repository.process_triggers(result)
|
||||
|
||||
def _known_packages(self) -> Set[str]:
|
||||
"""
|
||||
|
@ -85,9 +85,9 @@ class ApplicationPackages(ApplicationProperties):
|
||||
self.database.build_queue_insert(package)
|
||||
self.database.remote_update(package)
|
||||
|
||||
with tmpdir() as local_path:
|
||||
Sources.load(local_path, package.remote, self.database.patches_get(package.base))
|
||||
self._process_dependencies(local_path, known_packages, without_dependencies)
|
||||
with tmpdir() as local_dir:
|
||||
Sources.load(local_dir, package, self.database.patches_get(package.base), self.repository.paths)
|
||||
self._process_dependencies(local_dir, known_packages, without_dependencies)
|
||||
|
||||
def _add_directory(self, source: str, *_: Any) -> None:
|
||||
"""
|
||||
@ -96,8 +96,8 @@ class ApplicationPackages(ApplicationProperties):
|
||||
Args:
|
||||
source(str): path to local directory
|
||||
"""
|
||||
local_path = Path(source)
|
||||
for full_path in filter(package_like, local_path.iterdir()):
|
||||
local_dir = Path(source)
|
||||
for full_path in filter(package_like, local_dir.iterdir()):
|
||||
self._add_archive(str(full_path))
|
||||
|
||||
def _add_local(self, source: str, known_packages: Set[str], without_dependencies: bool) -> None:
|
||||
@ -146,19 +146,19 @@ class ApplicationPackages(ApplicationProperties):
|
||||
self.database.remote_update(package)
|
||||
# repository packages must not depend on unknown packages, thus we are not going to process dependencies
|
||||
|
||||
def _process_dependencies(self, local_path: Path, known_packages: Set[str], without_dependencies: bool) -> None:
|
||||
def _process_dependencies(self, local_dir: Path, known_packages: Set[str], without_dependencies: bool) -> None:
|
||||
"""
|
||||
process package dependencies
|
||||
|
||||
Args:
|
||||
local_path(Path): path to local package sources (i.e. cloned AUR repository)
|
||||
local_dir(Path): path to local package sources (i.e. cloned AUR repository)
|
||||
known_packages(Set[str]): list of packages which are known by the service
|
||||
without_dependencies(bool): if set, dependency check will be disabled
|
||||
"""
|
||||
if without_dependencies:
|
||||
return
|
||||
|
||||
dependencies = Package.dependencies(local_path)
|
||||
dependencies = Package.dependencies(local_dir)
|
||||
self.add(dependencies.difference(known_packages), PackageSource.AUR, without_dependencies)
|
||||
|
||||
def add(self, names: Iterable[str], source: PackageSource, without_dependencies: bool) -> None:
|
||||
|
@ -20,7 +20,7 @@
|
||||
import logging
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database.sqlite import SQLite
|
||||
from ahriman.core.database import SQLite
|
||||
from ahriman.core.repository import Repository
|
||||
|
||||
|
||||
|
@ -24,7 +24,7 @@ from typing import Callable, Iterable, List
|
||||
|
||||
from ahriman.application.application.application_properties import ApplicationProperties
|
||||
from ahriman.core.build_tools.sources import Sources
|
||||
from ahriman.core.formatters.update_printer import UpdatePrinter
|
||||
from ahriman.core.formatters import UpdatePrinter
|
||||
from ahriman.core.tree import Tree
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.result import Result
|
||||
@ -66,17 +66,6 @@ class ApplicationRepository(ApplicationProperties):
|
||||
if packages:
|
||||
self.repository.clear_packages()
|
||||
|
||||
def report(self, target: Iterable[str], result: Result) -> None:
|
||||
"""
|
||||
generate report
|
||||
|
||||
Args:
|
||||
target(Iterable[str]): list of targets to run (e.g. html)
|
||||
result(Result): build result
|
||||
"""
|
||||
targets = target or None
|
||||
self.repository.process_report(targets, result)
|
||||
|
||||
def sign(self, packages: Iterable[str]) -> None:
|
||||
"""
|
||||
sign packages and repository
|
||||
@ -102,17 +91,6 @@ class ApplicationRepository(ApplicationProperties):
|
||||
self.repository.sign.process_sign_repository(self.repository.repo.repo_path)
|
||||
self._finalize(Result())
|
||||
|
||||
def sync(self, target: Iterable[str], built_packages: Iterable[Package]) -> None:
|
||||
"""
|
||||
sync to remote server
|
||||
|
||||
Args:
|
||||
target(Iterable[str]): list of targets to run (e.g. s3)
|
||||
built_packages(Iterable[Package]): list of packages which has just been built
|
||||
"""
|
||||
targets = target or None
|
||||
self.repository.process_sync(targets, built_packages)
|
||||
|
||||
def unknown(self) -> List[str]:
|
||||
"""
|
||||
get packages which were not found in AUR
|
||||
@ -169,7 +147,7 @@ class ApplicationRepository(ApplicationProperties):
|
||||
process_update(packages, build_result)
|
||||
|
||||
# process manual packages
|
||||
tree = Tree.load(updates, self.database)
|
||||
tree = Tree.load(updates, self.repository.paths, self.database)
|
||||
for num, level in enumerate(tree.levels()):
|
||||
self.logger.info("processing level #%i %s", num, [package.base for package in level])
|
||||
build_result = self.repository.process_build(level)
|
||||
|
@ -29,14 +29,13 @@ from ahriman.application.handlers.patch import Patch
|
||||
from ahriman.application.handlers.rebuild import Rebuild
|
||||
from ahriman.application.handlers.remove import Remove
|
||||
from ahriman.application.handlers.remove_unknown import RemoveUnknown
|
||||
from ahriman.application.handlers.report import Report
|
||||
from ahriman.application.handlers.restore import Restore
|
||||
from ahriman.application.handlers.search import Search
|
||||
from ahriman.application.handlers.setup import Setup
|
||||
from ahriman.application.handlers.sign import Sign
|
||||
from ahriman.application.handlers.status import Status
|
||||
from ahriman.application.handlers.status_update import StatusUpdate
|
||||
from ahriman.application.handlers.sync import Sync
|
||||
from ahriman.application.handlers.triggers import Triggers
|
||||
from ahriman.application.handlers.unsafe_commands import UnsafeCommands
|
||||
from ahriman.application.handlers.update import Update
|
||||
from ahriman.application.handlers.users import Users
|
||||
|
@ -22,7 +22,7 @@ import argparse
|
||||
from typing import Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
|
||||
|
||||
|
@ -24,9 +24,9 @@ from pathlib import Path
|
||||
from tarfile import TarFile
|
||||
from typing import Set, Type
|
||||
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database.sqlite import SQLite
|
||||
from ahriman.core.database import SQLite
|
||||
|
||||
|
||||
class Backup(Handler):
|
||||
|
@ -22,7 +22,7 @@ import argparse
|
||||
from typing import Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
|
||||
|
||||
|
@ -21,9 +21,9 @@ import argparse
|
||||
|
||||
from typing import Type
|
||||
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.formatters.configuration_printer import ConfigurationPrinter
|
||||
from ahriman.core.formatters import ConfigurationPrinter
|
||||
|
||||
|
||||
class Dump(Handler):
|
||||
|
@ -71,10 +71,10 @@ class Handler:
|
||||
if args.architecture: # architecture is specified explicitly
|
||||
return sorted(set(args.architecture))
|
||||
|
||||
config = Configuration()
|
||||
config.load(args.configuration)
|
||||
configuration = Configuration()
|
||||
configuration.load(args.configuration)
|
||||
# wtf???
|
||||
root = config.getpath("repository", "root") # pylint: disable=assignment-from-no-return
|
||||
root = configuration.getpath("repository", "root") # pylint: disable=assignment-from-no-return
|
||||
architectures = RepositoryPaths.known_architectures(root)
|
||||
|
||||
if not architectures: # well we did not find anything
|
||||
|
@ -21,7 +21,7 @@ import argparse
|
||||
|
||||
from typing import Type
|
||||
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
|
||||
|
||||
|
@ -22,7 +22,7 @@ import argparse
|
||||
from typing import Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
|
||||
|
||||
|
@ -23,10 +23,10 @@ from pathlib import Path
|
||||
from typing import List, Optional, Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.build_tools.sources import Sources
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.formatters.string_printer import StringPrinter
|
||||
from ahriman.core.formatters import StringPrinter
|
||||
from ahriman.models.action import Action
|
||||
from ahriman.models.package import Package
|
||||
|
||||
|
@ -22,9 +22,9 @@ import argparse
|
||||
from typing import List, Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.formatters.update_printer import UpdatePrinter
|
||||
from ahriman.core.formatters import UpdatePrinter
|
||||
from ahriman.models.package import Package
|
||||
|
||||
|
||||
|
@ -22,7 +22,7 @@ import argparse
|
||||
from typing import Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
|
||||
|
||||
|
@ -22,9 +22,9 @@ import argparse
|
||||
from typing import Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.formatters.string_printer import StringPrinter
|
||||
from ahriman.core.formatters import StringPrinter
|
||||
|
||||
|
||||
class RemoveUnknown(Handler):
|
||||
|
@ -22,7 +22,7 @@ import argparse
|
||||
from typing import Type
|
||||
from tarfile import TarFile
|
||||
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
|
||||
|
||||
|
@ -23,12 +23,11 @@ from dataclasses import fields
|
||||
from typing import Callable, Iterable, List, Tuple, Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.core.alpm.remote.aur import AUR
|
||||
from ahriman.core.alpm.remote.official import Official
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.alpm.remote import AUR, Official
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.exceptions import InvalidOption
|
||||
from ahriman.core.formatters.aur_printer import AurPrinter
|
||||
from ahriman.core.formatters import AurPrinter
|
||||
from ahriman.models.aur_package import AURPackage
|
||||
|
||||
|
||||
|
@ -23,7 +23,7 @@ from pathlib import Path
|
||||
from typing import Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.models.repository_paths import RepositoryPaths
|
||||
|
||||
|
@ -22,7 +22,7 @@ import argparse
|
||||
from typing import Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
|
||||
|
||||
|
@ -22,10 +22,9 @@ import argparse
|
||||
from typing import Callable, Iterable, Tuple, Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.formatters.package_printer import PackagePrinter
|
||||
from ahriman.core.formatters.status_printer import StatusPrinter
|
||||
from ahriman.core.formatters import PackagePrinter, StatusPrinter
|
||||
from ahriman.models.build_status import BuildStatus
|
||||
from ahriman.models.package import Package
|
||||
|
||||
|
@ -22,7 +22,7 @@ import argparse
|
||||
from typing import Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.models.action import Action
|
||||
|
||||
|
@ -22,14 +22,14 @@ import argparse
|
||||
from typing import Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.models.result import Result
|
||||
|
||||
|
||||
class Report(Handler):
|
||||
class Triggers(Handler):
|
||||
"""
|
||||
generate report handler
|
||||
triggers handlers
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
@ -45,4 +45,4 @@ class Report(Handler):
|
||||
no_report(bool): force disable reporting
|
||||
unsafe(bool): if set no user check will be performed before path creation
|
||||
"""
|
||||
Application(architecture, configuration, no_report, unsafe).report(args.target, Result())
|
||||
Application(architecture, configuration, no_report, unsafe).repository.process_triggers(Result())
|
@ -22,9 +22,9 @@ import shlex
|
||||
|
||||
from typing import List, Type
|
||||
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.formatters.string_printer import StringPrinter
|
||||
from ahriman.core.formatters import StringPrinter
|
||||
|
||||
|
||||
class UnsafeCommands(Handler):
|
||||
|
@ -22,7 +22,7 @@ import argparse
|
||||
from typing import Callable, Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
|
||||
|
||||
|
@ -23,10 +23,10 @@ import getpass
|
||||
from pathlib import Path
|
||||
from typing import Type
|
||||
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database.sqlite import SQLite
|
||||
from ahriman.core.formatters.user_printer import UserPrinter
|
||||
from ahriman.core.database import SQLite
|
||||
from ahriman.core.formatters import UserPrinter
|
||||
from ahriman.models.action import Action
|
||||
from ahriman.models.user import User
|
||||
|
||||
|
@ -21,7 +21,7 @@ import argparse
|
||||
|
||||
from typing import Type
|
||||
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.spawn import Spawn
|
||||
|
||||
|
@ -17,3 +17,8 @@
|
||||
# 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.alpm.remote.remote import Remote
|
||||
|
||||
from ahriman.core.alpm.remote.aur import AUR
|
||||
from ahriman.core.alpm.remote.official import Official
|
||||
from ahriman.core.alpm.remote.official_syncdb import OfficialSyncdb
|
||||
|
@ -22,7 +22,7 @@ import requests
|
||||
from typing import Any, Dict, List, Type
|
||||
|
||||
from ahriman.core.alpm.pacman import Pacman
|
||||
from ahriman.core.alpm.remote.remote import Remote
|
||||
from ahriman.core.alpm.remote import Remote
|
||||
from ahriman.core.exceptions import InvalidPackageInfo
|
||||
from ahriman.core.util import exception_response_text
|
||||
from ahriman.models.aur_package import AURPackage
|
||||
|
@ -22,7 +22,7 @@ import requests
|
||||
from typing import Any, Dict, List, Type
|
||||
|
||||
from ahriman.core.alpm.pacman import Pacman
|
||||
from ahriman.core.alpm.remote.remote import Remote
|
||||
from ahriman.core.alpm.remote import Remote
|
||||
from ahriman.core.exceptions import InvalidPackageInfo
|
||||
from ahriman.core.util import exception_response_text
|
||||
from ahriman.models.aur_package import AURPackage
|
||||
|
@ -18,7 +18,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from ahriman.core.alpm.pacman import Pacman
|
||||
from ahriman.core.alpm.remote.official import Official
|
||||
from ahriman.core.alpm.remote import Official
|
||||
from ahriman.models.aur_package import AURPackage
|
||||
|
||||
|
||||
|
@ -38,8 +38,7 @@ class Remote:
|
||||
These classes are designed to be used without instancing. In order to achieve it several class methods are
|
||||
provided: ``info``, ``multisearch`` and ``search``. Thus, the basic flow is the following::
|
||||
|
||||
>>> from ahriman.core.alpm.remote.aur import AUR
|
||||
>>> from ahriman.core.alpm.remote.official import Official
|
||||
>>> from ahriman.core.alpm.remote import AUR, Official
|
||||
>>>
|
||||
>>> package = AUR.info("ahriman", pacman=pacman)
|
||||
>>> search_result = Official.multisearch("pacman", "manager", pacman=pacman)
|
||||
|
@ -17,3 +17,7 @@
|
||||
# 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.auth.auth import Auth
|
||||
|
||||
from ahriman.core.auth.mapping import Mapping
|
||||
from ahriman.core.auth.oauth import OAuth
|
||||
|
@ -24,7 +24,7 @@ import logging
|
||||
from typing import Optional, Type
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database.sqlite import SQLite
|
||||
from ahriman.core.database import SQLite
|
||||
from ahriman.models.auth_settings import AuthSettings
|
||||
from ahriman.models.user_access import UserAccess
|
||||
|
||||
@ -82,10 +82,10 @@ class Auth:
|
||||
"""
|
||||
provider = AuthSettings.from_option(configuration.get("auth", "target", fallback="disabled"))
|
||||
if provider == AuthSettings.Configuration:
|
||||
from ahriman.core.auth.mapping import Mapping
|
||||
from ahriman.core.auth import Mapping
|
||||
return Mapping(configuration, database)
|
||||
if provider == AuthSettings.OAuth:
|
||||
from ahriman.core.auth.oauth import OAuth
|
||||
from ahriman.core.auth import OAuth
|
||||
return OAuth(configuration, database)
|
||||
return cls(configuration)
|
||||
|
||||
|
@ -19,10 +19,9 @@
|
||||
#
|
||||
from typing import Optional
|
||||
|
||||
from ahriman.core.auth.auth import Auth
|
||||
|
||||
from ahriman.core.auth import Auth
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database.sqlite import SQLite
|
||||
from ahriman.core.database import SQLite
|
||||
from ahriman.models.auth_settings import AuthSettings
|
||||
from ahriman.models.user import User
|
||||
from ahriman.models.user_access import UserAccess
|
||||
|
@ -21,9 +21,9 @@ import aioauth_client
|
||||
|
||||
from typing import Optional, Type
|
||||
|
||||
from ahriman.core.auth.mapping import Mapping
|
||||
from ahriman.core.auth import Mapping
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database.sqlite import SQLite
|
||||
from ahriman.core.database import SQLite
|
||||
from ahriman.core.exceptions import InvalidOption
|
||||
from ahriman.models.auth_settings import AuthSettings
|
||||
|
||||
|
@ -24,7 +24,9 @@ from pathlib import Path
|
||||
from typing import List, Optional
|
||||
|
||||
from ahriman.core.util import check_output, walk
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.remote_source import RemoteSource
|
||||
from ahriman.models.repository_paths import RepositoryPaths
|
||||
|
||||
|
||||
class Sources:
|
||||
@ -43,7 +45,7 @@ class Sources:
|
||||
_check_output = check_output
|
||||
|
||||
@staticmethod
|
||||
def add(sources_dir: Path, *pattern: str) -> None:
|
||||
def _add(sources_dir: Path, *pattern: str) -> None:
|
||||
"""
|
||||
track found files via git
|
||||
|
||||
@ -64,7 +66,7 @@ class Sources:
|
||||
exception=None, cwd=sources_dir, logger=Sources.logger)
|
||||
|
||||
@staticmethod
|
||||
def diff(sources_dir: Path) -> str:
|
||||
def _diff(sources_dir: Path) -> str:
|
||||
"""
|
||||
generate diff from the current version and write it to the output file
|
||||
|
||||
@ -76,6 +78,21 @@ class Sources:
|
||||
"""
|
||||
return Sources._check_output("git", "diff", exception=None, cwd=sources_dir, logger=Sources.logger)
|
||||
|
||||
@staticmethod
|
||||
def _move(pkgbuild_dir: Path, sources_dir: Path) -> None:
|
||||
"""
|
||||
move content from pkgbuild_dir to sources_dir
|
||||
|
||||
Args:
|
||||
pkgbuild_dir(Path): path to directory with pkgbuild from which need to move
|
||||
sources_dir(Path): path to target directory
|
||||
"""
|
||||
if pkgbuild_dir == sources_dir:
|
||||
return # directories are the same, no need to move
|
||||
for src in walk(pkgbuild_dir):
|
||||
dst = sources_dir / src.relative_to(pkgbuild_dir)
|
||||
shutil.move(src, dst)
|
||||
|
||||
@staticmethod
|
||||
def fetch(sources_dir: Path, remote: Optional[RemoteSource]) -> None:
|
||||
"""
|
||||
@ -103,7 +120,8 @@ class Sources:
|
||||
remote.git_url, str(sources_dir),
|
||||
exception=None, cwd=sources_dir, logger=Sources.logger)
|
||||
else:
|
||||
Sources.logger.warning("%s is not initialized, but no remote provided", sources_dir)
|
||||
# it will cause an exception later
|
||||
Sources.logger.error("%s is not initialized, but no remote provided", sources_dir)
|
||||
|
||||
# and now force reset to our branch
|
||||
Sources._check_output("git", "checkout", "--force", branch,
|
||||
@ -114,7 +132,7 @@ class Sources:
|
||||
# move content if required
|
||||
# we are using full path to source directory in order to make append possible
|
||||
pkgbuild_dir = remote.pkgbuild_dir if remote is not None else sources_dir.resolve()
|
||||
Sources.move((sources_dir / pkgbuild_dir).resolve(), sources_dir)
|
||||
Sources._move((sources_dir / pkgbuild_dir).resolve(), sources_dir)
|
||||
|
||||
@staticmethod
|
||||
def has_remotes(sources_dir: Path) -> bool:
|
||||
@ -142,36 +160,26 @@ class Sources:
|
||||
exception=None, cwd=sources_dir, logger=Sources.logger)
|
||||
|
||||
@staticmethod
|
||||
def load(sources_dir: Path, remote: Optional[RemoteSource], patch: Optional[str]) -> None:
|
||||
def load(sources_dir: Path, package: Package, patch: Optional[str], paths: RepositoryPaths) -> None:
|
||||
"""
|
||||
fetch sources from remote and apply patches
|
||||
|
||||
Args:
|
||||
sources_dir(Path): local path to fetch
|
||||
remote(Optional[RemoteSource]): remote target (from where to fetch)
|
||||
package(Package): package definitions
|
||||
patch(Optional[str]): optional patch to be applied
|
||||
paths(RepositoryPaths): repository paths instance
|
||||
"""
|
||||
Sources.fetch(sources_dir, remote)
|
||||
if (cache_dir := paths.cache_for(package.base)).is_dir() and cache_dir != sources_dir:
|
||||
# no need to clone whole repository, just copy from cache first
|
||||
shutil.copytree(cache_dir, sources_dir, dirs_exist_ok=True)
|
||||
Sources.fetch(sources_dir, package.remote)
|
||||
|
||||
if patch is None:
|
||||
Sources.logger.info("no patches found")
|
||||
return
|
||||
Sources.patch_apply(sources_dir, patch)
|
||||
|
||||
@staticmethod
|
||||
def move(pkgbuild_dir: Path, sources_dir: Path) -> None:
|
||||
"""
|
||||
move content from pkgbuild_dir to sources_dir
|
||||
|
||||
Args:
|
||||
pkgbuild_dir(Path): path to directory with pkgbuild from which need to move
|
||||
sources_dir(Path): path to target directory
|
||||
"""
|
||||
if pkgbuild_dir == sources_dir:
|
||||
return # directories are the same, no need to move
|
||||
for src in walk(pkgbuild_dir):
|
||||
dst = sources_dir / src.relative_to(pkgbuild_dir)
|
||||
shutil.move(src, dst)
|
||||
|
||||
@staticmethod
|
||||
def patch_apply(sources_dir: Path, patch: str) -> None:
|
||||
"""
|
||||
@ -198,6 +206,6 @@ class Sources:
|
||||
Returns:
|
||||
str: patch as plain text
|
||||
"""
|
||||
Sources.add(sources_dir, *pattern)
|
||||
diff = Sources.diff(sources_dir)
|
||||
Sources._add(sources_dir, *pattern)
|
||||
diff = Sources._diff(sources_dir)
|
||||
return f"{diff}\n" # otherwise, patch will be broken
|
||||
|
@ -18,14 +18,13 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
import logging
|
||||
import shutil
|
||||
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
|
||||
from ahriman.core.build_tools.sources import Sources
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database.sqlite import SQLite
|
||||
from ahriman.core.database import SQLite
|
||||
from ahriman.core.exceptions import BuildFailed
|
||||
from ahriman.core.util import check_output
|
||||
from ahriman.models.package import Package
|
||||
@ -66,12 +65,12 @@ class Task:
|
||||
self.makepkg_flags = configuration.getlist("build", "makepkg_flags", fallback=[])
|
||||
self.makechrootpkg_flags = configuration.getlist("build", "makechrootpkg_flags", fallback=[])
|
||||
|
||||
def build(self, sources_path: Path) -> List[Path]:
|
||||
def build(self, sources_dir: Path) -> List[Path]:
|
||||
"""
|
||||
run package build
|
||||
|
||||
Args:
|
||||
sources_path(Path): path to where sources are
|
||||
sources_dir(Path): path to where sources are
|
||||
|
||||
Returns:
|
||||
List[Path]: paths of produced packages
|
||||
@ -85,26 +84,23 @@ class Task:
|
||||
Task._check_output(
|
||||
*command,
|
||||
exception=BuildFailed(self.package.base),
|
||||
cwd=sources_path,
|
||||
cwd=sources_dir,
|
||||
logger=self.build_logger,
|
||||
user=self.uid)
|
||||
|
||||
# well it is not actually correct, but we can deal with it
|
||||
packages = Task._check_output("makepkg", "--packagelist",
|
||||
exception=BuildFailed(self.package.base),
|
||||
cwd=sources_path,
|
||||
cwd=sources_dir,
|
||||
logger=self.build_logger).splitlines()
|
||||
return [Path(package) for package in packages]
|
||||
|
||||
def init(self, path: Path, database: SQLite) -> None:
|
||||
def init(self, sources_dir: Path, database: SQLite) -> None:
|
||||
"""
|
||||
fetch package from git
|
||||
|
||||
Args:
|
||||
path(Path): local path to fetch
|
||||
sources_dir(Path): local path to fetch
|
||||
database(SQLite): database instance
|
||||
"""
|
||||
if self.paths.cache_for(self.package.base).is_dir():
|
||||
# no need to clone whole repository, just copy from cache first
|
||||
shutil.copytree(self.paths.cache_for(self.package.base), path, dirs_exist_ok=True)
|
||||
Sources.load(path, self.package.remote, database.patches_get(self.package.base))
|
||||
Sources.load(sources_dir, self.package, database.patches_get(self.package.base), self.paths)
|
||||
|
@ -125,11 +125,11 @@ class Configuration(configparser.RawConfigParser):
|
||||
Returns:
|
||||
Configuration: configuration instance
|
||||
"""
|
||||
config = cls()
|
||||
config.load(path)
|
||||
config.merge_sections(architecture)
|
||||
config.load_logging(quiet)
|
||||
return config
|
||||
configuration = cls()
|
||||
configuration.load(path)
|
||||
configuration.merge_sections(architecture)
|
||||
configuration.load_logging(quiet)
|
||||
return configuration
|
||||
|
||||
@staticmethod
|
||||
def __convert_list(value: str) -> List[str]:
|
||||
|
@ -17,3 +17,4 @@
|
||||
# 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.database.sqlite import SQLite
|
||||
|
@ -27,8 +27,7 @@ from ahriman.core.database.data.users import migrate_users_data
|
||||
from ahriman.models.migration_result import MigrationResult
|
||||
|
||||
|
||||
def migrate_data(
|
||||
result: MigrationResult, connection: Connection, configuration: Configuration) -> None:
|
||||
def migrate_data(result: MigrationResult, connection: Connection, configuration: Configuration) -> None:
|
||||
"""
|
||||
perform data migration
|
||||
|
||||
|
@ -70,6 +70,12 @@ class InitializeException(RuntimeError):
|
||||
RuntimeError.__init__(self, f"Could not load service: {details}")
|
||||
|
||||
|
||||
class InvalidExtension(RuntimeError):
|
||||
"""
|
||||
exception being raised by trigger load in case of errors
|
||||
"""
|
||||
|
||||
|
||||
class InvalidOption(ValueError):
|
||||
"""
|
||||
exception which will be raised on configuration errors
|
||||
|
@ -1,19 +1,29 @@
|
||||
#
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
# copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# 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
|
||||
# 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.
|
||||
# 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/>.
|
||||
# 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.printer import Printer
|
||||
from ahriman.core.formatters.string_printer import StringPrinter
|
||||
|
||||
from ahriman.core.formatters.aur_printer import AurPrinter
|
||||
from ahriman.core.formatters.build_printer import BuildPrinter
|
||||
from ahriman.core.formatters.configuration_printer import ConfigurationPrinter
|
||||
from ahriman.core.formatters.package_printer import PackagePrinter
|
||||
from ahriman.core.formatters.status_printer import StatusPrinter
|
||||
from ahriman.core.formatters.update_printer import UpdatePrinter
|
||||
from ahriman.core.formatters.user_printer import UserPrinter
|
||||
|
@ -19,7 +19,7 @@
|
||||
#
|
||||
from typing import List
|
||||
|
||||
from ahriman.core.formatters.string_printer import StringPrinter
|
||||
from ahriman.core.formatters import StringPrinter
|
||||
from ahriman.core.util import pretty_datetime
|
||||
from ahriman.models.aur_package import AURPackage
|
||||
from ahriman.models.property import Property
|
||||
|
@ -17,7 +17,7 @@
|
||||
# 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.formatters import StringPrinter
|
||||
from ahriman.models.package import Package
|
||||
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
#
|
||||
from typing import Dict, List
|
||||
|
||||
from ahriman.core.formatters.string_printer import StringPrinter
|
||||
from ahriman.core.formatters import StringPrinter
|
||||
from ahriman.models.property import Property
|
||||
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
#
|
||||
from typing import List
|
||||
|
||||
from ahriman.core.formatters.string_printer import StringPrinter
|
||||
from ahriman.core.formatters import StringPrinter
|
||||
from ahriman.models.build_status import BuildStatus
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.property import Property
|
||||
|
@ -17,7 +17,7 @@
|
||||
# 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.formatters import StringPrinter
|
||||
from ahriman.models.build_status import BuildStatus
|
||||
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
#
|
||||
from typing import Optional
|
||||
|
||||
from ahriman.core.formatters.printer import Printer
|
||||
from ahriman.core.formatters import Printer
|
||||
|
||||
|
||||
class StringPrinter(Printer):
|
||||
|
@ -19,7 +19,7 @@
|
||||
#
|
||||
from typing import List, Optional
|
||||
|
||||
from ahriman.core.formatters.string_printer import StringPrinter
|
||||
from ahriman.core.formatters import StringPrinter
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.property import Property
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
#
|
||||
from typing import List
|
||||
|
||||
from ahriman.core.formatters.string_printer import StringPrinter
|
||||
from ahriman.core.formatters import StringPrinter
|
||||
from ahriman.models.property import Property
|
||||
from ahriman.models.user import User
|
||||
|
||||
|
@ -17,3 +17,12 @@
|
||||
# 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.report.report import Report
|
||||
from ahriman.core.report.jinja_template import JinjaTemplate
|
||||
|
||||
from ahriman.core.report.console import Console
|
||||
from ahriman.core.report.email import Email
|
||||
from ahriman.core.report.html import HTML
|
||||
from ahriman.core.report.telegram import Telegram
|
||||
|
||||
from ahriman.core.report.report_trigger import ReportTrigger
|
||||
|
@ -20,8 +20,8 @@
|
||||
from typing import Iterable
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.formatters.build_printer import BuildPrinter
|
||||
from ahriman.core.report.report import Report
|
||||
from ahriman.core.formatters import BuildPrinter
|
||||
from ahriman.core.report import Report
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.result import Result
|
||||
|
||||
|
@ -25,8 +25,7 @@ from email.mime.text import MIMEText
|
||||
from typing import Dict, Iterable
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.report.jinja_template import JinjaTemplate
|
||||
from ahriman.core.report.report import Report
|
||||
from ahriman.core.report import JinjaTemplate, Report
|
||||
from ahriman.core.util import pretty_datetime
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.result import Result
|
||||
|
@ -20,8 +20,7 @@
|
||||
from typing import Iterable
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.report.jinja_template import JinjaTemplate
|
||||
from ahriman.core.report.report import Report
|
||||
from ahriman.core.report import JinjaTemplate, Report
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.result import Result
|
||||
|
||||
|
@ -87,16 +87,16 @@ class Report:
|
||||
section, provider_name = configuration.gettype(target, architecture)
|
||||
provider = ReportSettings.from_option(provider_name)
|
||||
if provider == ReportSettings.HTML:
|
||||
from ahriman.core.report.html import HTML
|
||||
from ahriman.core.report import HTML
|
||||
return HTML(architecture, configuration, section)
|
||||
if provider == ReportSettings.Email:
|
||||
from ahriman.core.report.email import Email
|
||||
from ahriman.core.report import Email
|
||||
return Email(architecture, configuration, section)
|
||||
if provider == ReportSettings.Console:
|
||||
from ahriman.core.report.console import Console
|
||||
from ahriman.core.report import Console
|
||||
return Console(architecture, configuration, section)
|
||||
if provider == ReportSettings.Telegram:
|
||||
from ahriman.core.report.telegram import Telegram
|
||||
from ahriman.core.report import Telegram
|
||||
return Telegram(architecture, configuration, section)
|
||||
return cls(architecture, configuration) # should never happen
|
||||
|
||||
@ -109,13 +109,13 @@ class Report:
|
||||
result(Result): build result
|
||||
"""
|
||||
|
||||
def run(self, packages: Iterable[Package], result: Result) -> None:
|
||||
def run(self, result: Result, packages: Iterable[Package]) -> None:
|
||||
"""
|
||||
run report generation
|
||||
|
||||
Args:
|
||||
packages(Iterable[Package]): list of packages to generate report
|
||||
result(Result): build result
|
||||
packages(Iterable[Package]): list of packages to generate report
|
||||
|
||||
Raises:
|
||||
ReportFailed: in case of any report unmatched exception
|
||||
|
@ -17,31 +17,42 @@
|
||||
# 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 argparse
|
||||
from typing import Iterable
|
||||
|
||||
from typing import Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.triggers import Trigger
|
||||
from ahriman.core.report import Report
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.result import Result
|
||||
|
||||
|
||||
class Sync(Handler):
|
||||
class ReportTrigger(Trigger):
|
||||
"""
|
||||
remote sync handler
|
||||
report trigger
|
||||
|
||||
Attributes:
|
||||
targets(List[str]): report target list
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||
def __init__(self, architecture: str, configuration: Configuration) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
no_report(bool): force disable reporting
|
||||
unsafe(bool): if set no user check will be performed before path creation
|
||||
"""
|
||||
Application(architecture, configuration, no_report, unsafe).sync(args.target, [])
|
||||
Trigger.__init__(self, architecture, configuration)
|
||||
self.targets = configuration.getlist("report", "target")
|
||||
|
||||
def run(self, result: Result, packages: Iterable[Package]) -> None:
|
||||
"""
|
||||
run trigger
|
||||
|
||||
Args:
|
||||
result(Result): build result
|
||||
packages(Iterable[Package]): list of all available packages
|
||||
"""
|
||||
for target in self.targets:
|
||||
runner = Report.load(self.architecture, self.configuration, target)
|
||||
runner.run(result, packages)
|
@ -23,8 +23,7 @@ import requests
|
||||
from typing import Iterable
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.report.jinja_template import JinjaTemplate
|
||||
from ahriman.core.report.report import Report
|
||||
from ahriman.core.report import JinjaTemplate, Report
|
||||
from ahriman.core.util import exception_response_text
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.result import Result
|
||||
|
@ -23,9 +23,7 @@ from pathlib import Path
|
||||
from typing import Iterable, List, Optional, Set
|
||||
|
||||
from ahriman.core.build_tools.task import Task
|
||||
from ahriman.core.report.report import Report
|
||||
from ahriman.core.repository.cleaner import Cleaner
|
||||
from ahriman.core.upload.upload import Upload
|
||||
from ahriman.core.util import tmpdir
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.result import Result
|
||||
@ -143,35 +141,14 @@ class Executor(Cleaner):
|
||||
|
||||
return self.repo.repo_path
|
||||
|
||||
def process_report(self, targets: Optional[Iterable[str]], result: Result) -> None:
|
||||
def process_triggers(self, result: Result) -> None:
|
||||
"""
|
||||
generate reports
|
||||
process triggers setup by settings
|
||||
|
||||
Args:
|
||||
targets(Optional[Iterable[str]]): list of targets to generate reports. Configuration option will be used
|
||||
if it is not set
|
||||
result(Result): build result
|
||||
"""
|
||||
if targets is None:
|
||||
targets = self.configuration.getlist("report", "target")
|
||||
for target in targets:
|
||||
runner = Report.load(self.architecture, self.configuration, target)
|
||||
runner.run(self.packages(), result)
|
||||
|
||||
def process_sync(self, targets: Optional[Iterable[str]], built_packages: Iterable[Package]) -> None:
|
||||
"""
|
||||
process synchronization to remote servers
|
||||
|
||||
Args:
|
||||
targets(Optional[Iterable[str]]): list of targets to sync. Configuration option will be used
|
||||
if it is not set
|
||||
built_packages(Iterable[Package]): list of packages which has just been built
|
||||
"""
|
||||
if targets is None:
|
||||
targets = self.configuration.getlist("upload", "target")
|
||||
for target in targets:
|
||||
runner = Upload.load(self.architecture, self.configuration, target)
|
||||
runner.run(self.paths.repository, built_packages)
|
||||
self.triggers.process(result, self.packages())
|
||||
|
||||
def process_update(self, packages: Iterable[Path]) -> Result:
|
||||
"""
|
||||
|
@ -35,7 +35,7 @@ class Repository(Executor, UpdateHandler):
|
||||
sync local repository to remote, generate report, etc::
|
||||
|
||||
>>> from ahriman.core.configuration import Configuration
|
||||
>>> from ahriman.core.database.sqlite import SQLite
|
||||
>>> from ahriman.core.database import SQLite
|
||||
>>>
|
||||
>>> configuration = Configuration()
|
||||
>>> database = SQLite.load(configuration)
|
||||
|
@ -22,10 +22,11 @@ import logging
|
||||
from ahriman.core.alpm.pacman import Pacman
|
||||
from ahriman.core.alpm.repo import Repo
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database.sqlite import SQLite
|
||||
from ahriman.core.database import SQLite
|
||||
from ahriman.core.exceptions import UnsafeRun
|
||||
from ahriman.core.sign.gpg import GPG
|
||||
from ahriman.core.status.client import Client
|
||||
from ahriman.core.triggers import TriggerLoader
|
||||
from ahriman.core.util import check_user
|
||||
|
||||
|
||||
@ -45,6 +46,7 @@ class RepositoryProperties:
|
||||
repo(Repo): repo commands wrapper instance
|
||||
reporter(Client): build status reporter instance
|
||||
sign(GPG): GPG wrapper instance
|
||||
triggers(TriggerLoader): triggers holder
|
||||
"""
|
||||
|
||||
def __init__(self, architecture: str, configuration: Configuration, database: SQLite,
|
||||
@ -78,3 +80,4 @@ class RepositoryProperties:
|
||||
self.sign = GPG(architecture, configuration)
|
||||
self.repo = Repo(self.name, self.paths, self.sign.repository_sign_args)
|
||||
self.reporter = Client() if no_report else Client.load(configuration)
|
||||
self.triggers = TriggerLoader(architecture, configuration)
|
||||
|
@ -22,7 +22,7 @@ import logging
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database.sqlite import SQLite
|
||||
from ahriman.core.database import SQLite
|
||||
from ahriman.core.exceptions import UnknownPackage
|
||||
from ahriman.core.repository import Repository
|
||||
from ahriman.models.build_status import BuildStatus, BuildStatusEnum
|
||||
|
@ -22,9 +22,10 @@ from __future__ import annotations
|
||||
from typing import Iterable, List, Set, Type
|
||||
|
||||
from ahriman.core.build_tools.sources import Sources
|
||||
from ahriman.core.database.sqlite import SQLite
|
||||
from ahriman.core.database import SQLite
|
||||
from ahriman.core.util import tmpdir
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.repository_paths import RepositoryPaths
|
||||
|
||||
|
||||
class Leaf:
|
||||
@ -58,19 +59,20 @@ class Leaf:
|
||||
return self.package.packages.keys()
|
||||
|
||||
@classmethod
|
||||
def load(cls: Type[Leaf], package: Package, database: SQLite) -> Leaf:
|
||||
def load(cls: Type[Leaf], package: Package, paths: RepositoryPaths, database: SQLite) -> Leaf:
|
||||
"""
|
||||
load leaf from package with dependencies
|
||||
|
||||
Args:
|
||||
package(Package): package properties
|
||||
paths(RepositoryPaths): repository paths instance
|
||||
database(SQLite): database instance
|
||||
|
||||
Returns:
|
||||
Leaf: loaded class
|
||||
"""
|
||||
with tmpdir() as clone_dir:
|
||||
Sources.load(clone_dir, package.remote, database.patches_get(package.base))
|
||||
Sources.load(clone_dir, package, database.patches_get(package.base), paths)
|
||||
dependencies = Package.dependencies(clone_dir)
|
||||
return cls(package, dependencies)
|
||||
|
||||
@ -102,7 +104,7 @@ class Tree:
|
||||
method::
|
||||
|
||||
>>> from ahriman.core.configuration import Configuration
|
||||
>>> from ahriman.core.database.sqlite import SQLite
|
||||
>>> from ahriman.core.database import SQLite
|
||||
>>> from ahriman.core.repository import Repository
|
||||
>>>
|
||||
>>> configuration = Configuration()
|
||||
@ -110,7 +112,7 @@ class Tree:
|
||||
>>> repository = Repository("x86_64", configuration, database, no_report=False, unsafe=False)
|
||||
>>> packages = repository.packages()
|
||||
>>>
|
||||
>>> tree = Tree.load(packages, database)
|
||||
>>> tree = Tree.load(packages, configuration.repository_paths, database)
|
||||
>>> for tree_level in tree.levels():
|
||||
>>> for package in tree_level:
|
||||
>>> print(package.base)
|
||||
@ -138,18 +140,19 @@ class Tree:
|
||||
self.leaves = leaves
|
||||
|
||||
@classmethod
|
||||
def load(cls: Type[Tree], packages: Iterable[Package], database: SQLite) -> Tree:
|
||||
def load(cls: Type[Tree], packages: Iterable[Package], paths: RepositoryPaths, database: SQLite) -> Tree:
|
||||
"""
|
||||
load tree from packages
|
||||
|
||||
Args:
|
||||
packages(Iterable[Package]): packages list
|
||||
paths(RepositoryPaths): repository paths instance
|
||||
database(SQLite): database instance
|
||||
|
||||
Returns:
|
||||
Tree: loaded class
|
||||
"""
|
||||
return cls([Leaf.load(package, database) for package in packages])
|
||||
return cls([Leaf.load(package, paths, database) for package in packages])
|
||||
|
||||
def levels(self) -> List[List[Package]]:
|
||||
"""
|
||||
|
21
src/ahriman/core/triggers/__init__.py
Normal file
21
src/ahriman/core/triggers/__init__.py
Normal file
@ -0,0 +1,21 @@
|
||||
#
|
||||
# Copyright (c) 2021-2022 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.triggers.trigger import Trigger
|
||||
from ahriman.core.triggers.trigger_loader import TriggerLoader
|
79
src/ahriman/core/triggers/trigger.py
Normal file
79
src/ahriman/core/triggers/trigger.py
Normal file
@ -0,0 +1,79 @@
|
||||
#
|
||||
# Copyright (c) 2021-2022 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/>.
|
||||
#
|
||||
import logging
|
||||
|
||||
from typing import Iterable
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.result import Result
|
||||
|
||||
|
||||
class Trigger:
|
||||
"""
|
||||
trigger base class
|
||||
|
||||
Attributes:
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
logger(logging.Logger): application logger
|
||||
|
||||
Examples:
|
||||
This class must be used in order to create own extension. Basically idea is the following::
|
||||
|
||||
>>> class CustomTrigger(Trigger):
|
||||
>>> def run(self, result: Result, packages: Iterable[Package]) -> None:
|
||||
>>> perform_some_action()
|
||||
|
||||
Having this class you can pass it to ``configuration`` and it will be run on action::
|
||||
|
||||
>>> from ahriman.core.triggers import TriggerLoader
|
||||
>>>
|
||||
>>> configuration = Configuration()
|
||||
>>> configuration.set_option("build", "triggers", "my.awesome.package.CustomTrigger")
|
||||
>>>
|
||||
>>> loader = TriggerLoader("x86_64", configuration)
|
||||
>>> loader.process(Result(), [])
|
||||
"""
|
||||
|
||||
def __init__(self, architecture: str, configuration: Configuration) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
"""
|
||||
self.logger = logging.getLogger("root")
|
||||
self.architecture = architecture
|
||||
self.configuration = configuration
|
||||
|
||||
def run(self, result: Result, packages: Iterable[Package]) -> None:
|
||||
"""
|
||||
run trigger
|
||||
|
||||
Args:
|
||||
result(Result): build result
|
||||
packages(Iterable[Package]): list of all available packages
|
||||
|
||||
Raises:
|
||||
NotImplementedError: not implemented method
|
||||
"""
|
||||
raise NotImplementedError
|
161
src/ahriman/core/triggers/trigger_loader.py
Normal file
161
src/ahriman/core/triggers/trigger_loader.py
Normal file
@ -0,0 +1,161 @@
|
||||
#
|
||||
# Copyright (c) 2021-2022 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/>.
|
||||
#
|
||||
import importlib
|
||||
import logging
|
||||
import os
|
||||
|
||||
from pathlib import Path
|
||||
from types import ModuleType
|
||||
from typing import Iterable
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.exceptions import InvalidExtension
|
||||
from ahriman.core.triggers import Trigger
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.result import Result
|
||||
|
||||
|
||||
class TriggerLoader:
|
||||
"""
|
||||
trigger loader class
|
||||
|
||||
Attributes:
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
logger(logging.Logger): application logger
|
||||
triggers(List[Trigger]): list of loaded triggers according to the configuration
|
||||
|
||||
Examples:
|
||||
This class more likely must not be used directly, but the usual workflow is the following::
|
||||
|
||||
>>> configuration = Configuration() # create configuration
|
||||
>>> configuration.set_option("build", "triggers", "ahriman.core.report.ReportTrigger") # set class for load
|
||||
|
||||
Having such configuration you can create instance of the loader::
|
||||
|
||||
>>> loader = TriggerLoader("x86_64", configuration)
|
||||
>>> print(loader.triggers)
|
||||
|
||||
After that you are free to run triggers::
|
||||
|
||||
>>> loader.process(Result(), [])
|
||||
"""
|
||||
|
||||
def __init__(self, architecture: str, configuration: Configuration) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
"""
|
||||
self.logger = logging.getLogger("root")
|
||||
self.architecture = architecture
|
||||
self.configuration = configuration
|
||||
|
||||
self.triggers = [
|
||||
self._load_trigger(trigger)
|
||||
for trigger in configuration.getlist("build", "triggers")
|
||||
]
|
||||
|
||||
def _load_module_from_file(self, module_path: str, implementation: str) -> ModuleType:
|
||||
"""
|
||||
load module by given file path
|
||||
|
||||
Args:
|
||||
module_path(str): import package
|
||||
implementation(str): specific trigger implementation, class name, required by import
|
||||
|
||||
Returns:
|
||||
ModuleType: module loaded from the imported file
|
||||
"""
|
||||
self.logger.info("load module %s from path %s", implementation, module_path)
|
||||
# basically this method is called only if ``module_path`` exists and is file.
|
||||
# Thus, this method should never throw ``FileNotFoundError`` exception
|
||||
loader = importlib.machinery.SourceFileLoader(implementation, module_path)
|
||||
module = ModuleType(loader.name)
|
||||
loader.exec_module(module)
|
||||
|
||||
return module
|
||||
|
||||
def _load_module_from_package(self, package: str) -> ModuleType:
|
||||
"""
|
||||
load module by given package name
|
||||
|
||||
Args:
|
||||
package(str): package name to import
|
||||
|
||||
Returns:
|
||||
ModuleType: module loaded from the imported module
|
||||
"""
|
||||
self.logger.info("load module from package %s", package)
|
||||
try:
|
||||
return importlib.import_module(package)
|
||||
except ModuleNotFoundError:
|
||||
raise InvalidExtension(f"Module {package} not found")
|
||||
|
||||
def _load_trigger(self, module_path: str) -> Trigger:
|
||||
"""
|
||||
load trigger by module path
|
||||
|
||||
Args:
|
||||
module_path(str): module import path to load
|
||||
|
||||
Returns:
|
||||
Trigger: loaded trigger based on settings
|
||||
"""
|
||||
*package_path_parts, class_name = module_path.split(".")
|
||||
package_or_path = ".".join(package_path_parts)
|
||||
|
||||
# it works for both missing permission and file does not exist
|
||||
if os.access(Path(package_or_path), os.R_OK):
|
||||
module = self._load_module_from_file(package_or_path, class_name)
|
||||
else:
|
||||
module = self._load_module_from_package(package_or_path)
|
||||
|
||||
trigger_type = getattr(module, class_name, None)
|
||||
if not isinstance(trigger_type, type):
|
||||
raise InvalidExtension(f"{class_name} of {package_or_path} is not a type")
|
||||
self.logger.info("loaded type %s of package %s", class_name, package_or_path)
|
||||
|
||||
try:
|
||||
trigger = trigger_type(self.architecture, self.configuration)
|
||||
except Exception:
|
||||
raise InvalidExtension(f"Could not load instance of trigger from {class_name} of {package_or_path}")
|
||||
if not isinstance(trigger, Trigger):
|
||||
raise InvalidExtension(f"Class {class_name} of {package_or_path} is not a Trigger")
|
||||
|
||||
return trigger
|
||||
|
||||
def process(self, result: Result, packages: Iterable[Package]) -> None:
|
||||
"""
|
||||
run remote sync
|
||||
|
||||
Args:
|
||||
result(Result): build result
|
||||
packages(Iterable[Package]): list of all available packages
|
||||
"""
|
||||
for trigger in self.triggers:
|
||||
trigger_name = type(trigger).__name__
|
||||
try:
|
||||
self.logger.info("executing extension %s", trigger_name)
|
||||
trigger.run(result, packages)
|
||||
except Exception:
|
||||
self.logger.exception("got exception while run trigger %s", trigger_name)
|
@ -17,3 +17,11 @@
|
||||
# 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.upload.upload import Upload
|
||||
from ahriman.core.upload.http_upload import HttpUpload
|
||||
|
||||
from ahriman.core.upload.github import Github
|
||||
from ahriman.core.upload.rsync import Rsync
|
||||
from ahriman.core.upload.s3 import S3
|
||||
|
||||
from ahriman.core.upload.upload_trigger import UploadTrigger
|
||||
|
@ -24,7 +24,7 @@ from pathlib import Path
|
||||
from typing import Any, Dict, Iterable, Optional
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.upload.http_upload import HttpUpload
|
||||
from ahriman.core.upload import HttpUpload
|
||||
from ahriman.core.util import walk
|
||||
from ahriman.models.package import Package
|
||||
|
||||
|
@ -24,7 +24,7 @@ from pathlib import Path
|
||||
from typing import Any, Dict
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.upload.upload import Upload
|
||||
from ahriman.core.upload import Upload
|
||||
from ahriman.core.util import exception_response_text
|
||||
|
||||
|
||||
|
@ -21,7 +21,7 @@ from pathlib import Path
|
||||
from typing import Iterable
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.upload.upload import Upload
|
||||
from ahriman.core.upload import Upload
|
||||
from ahriman.core.util import check_output
|
||||
from ahriman.models.package import Package
|
||||
|
||||
|
@ -25,7 +25,7 @@ from pathlib import Path
|
||||
from typing import Any, Dict, Iterable
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.upload.upload import Upload
|
||||
from ahriman.core.upload import Upload
|
||||
from ahriman.core.util import walk
|
||||
from ahriman.models.package import Package
|
||||
|
||||
|
@ -68,7 +68,7 @@ class Upload:
|
||||
"""
|
||||
self.logger = logging.getLogger("root")
|
||||
self.architecture = architecture
|
||||
self.config = configuration
|
||||
self.configuration = configuration
|
||||
|
||||
@classmethod
|
||||
def load(cls: Type[Upload], architecture: str, configuration: Configuration, target: str) -> Upload:
|
||||
@ -86,13 +86,13 @@ class Upload:
|
||||
section, provider_name = configuration.gettype(target, architecture)
|
||||
provider = UploadSettings.from_option(provider_name)
|
||||
if provider == UploadSettings.Rsync:
|
||||
from ahriman.core.upload.rsync import Rsync
|
||||
from ahriman.core.upload import Rsync
|
||||
return Rsync(architecture, configuration, section)
|
||||
if provider == UploadSettings.S3:
|
||||
from ahriman.core.upload.s3 import S3
|
||||
from ahriman.core.upload import S3
|
||||
return S3(architecture, configuration, section)
|
||||
if provider == UploadSettings.Github:
|
||||
from ahriman.core.upload.github import Github
|
||||
from ahriman.core.upload import Github
|
||||
return Github(architecture, configuration, section)
|
||||
return cls(architecture, configuration) # should never happen
|
||||
|
||||
|
58
src/ahriman/core/upload/upload_trigger.py
Normal file
58
src/ahriman/core/upload/upload_trigger.py
Normal file
@ -0,0 +1,58 @@
|
||||
#
|
||||
# Copyright (c) 2021-2022 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 typing import Iterable
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.triggers import Trigger
|
||||
from ahriman.core.upload import Upload
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.result import Result
|
||||
|
||||
|
||||
class UploadTrigger(Trigger):
|
||||
"""
|
||||
synchronization trigger
|
||||
|
||||
Attributes:
|
||||
targets(List[str]): upload target list
|
||||
"""
|
||||
|
||||
def __init__(self, architecture: str, configuration: Configuration) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
"""
|
||||
Trigger.__init__(self, architecture, configuration)
|
||||
self.targets = configuration.getlist("upload", "target")
|
||||
|
||||
def run(self, result: Result, packages: Iterable[Package]) -> None:
|
||||
"""
|
||||
run trigger
|
||||
|
||||
Args:
|
||||
result(Result): build result
|
||||
packages(Iterable[Package]): list of all available packages
|
||||
"""
|
||||
for target in self.targets:
|
||||
runner = Upload.load(self.architecture, self.configuration, target)
|
||||
runner.run(self.configuration.repository_paths.repository, result.success)
|
@ -29,9 +29,7 @@ from srcinfo.parse import parse_srcinfo # type: ignore
|
||||
from typing import Any, Dict, Iterable, List, Optional, Set, Type
|
||||
|
||||
from ahriman.core.alpm.pacman import Pacman
|
||||
from ahriman.core.alpm.remote.aur import AUR
|
||||
from ahriman.core.alpm.remote.official import Official
|
||||
from ahriman.core.alpm.remote.official_syncdb import OfficialSyncdb
|
||||
from ahriman.core.alpm.remote import AUR, Official, OfficialSyncdb
|
||||
from ahriman.core.exceptions import InvalidPackageInfo
|
||||
from ahriman.core.util import check_output, full_version
|
||||
from ahriman.models.package_description import PackageDescription
|
||||
@ -284,7 +282,7 @@ class Package:
|
||||
from ahriman.core.build_tools.sources import Sources
|
||||
|
||||
logger = logging.getLogger("build_details")
|
||||
Sources.load(paths.cache_for(self.base), self.remote, None)
|
||||
Sources.load(paths.cache_for(self.base), self, None, paths)
|
||||
|
||||
try:
|
||||
# update pkgver first
|
||||
|
@ -95,7 +95,7 @@ class RemoteSource:
|
||||
Optional[RemoteSource]: generated remote source if any, None otherwise
|
||||
"""
|
||||
if source == PackageSource.AUR:
|
||||
from ahriman.core.alpm.remote.aur import AUR
|
||||
from ahriman.core.alpm.remote import AUR
|
||||
return RemoteSource(
|
||||
git_url=AUR.remote_git_url(package_base, repository),
|
||||
web_url=AUR.remote_web_url(package_base),
|
||||
@ -104,7 +104,7 @@ class RemoteSource:
|
||||
source=source,
|
||||
)
|
||||
if source == PackageSource.Repository:
|
||||
from ahriman.core.alpm.remote.official import Official
|
||||
from ahriman.core.alpm.remote import Official
|
||||
return RemoteSource(
|
||||
git_url=Official.remote_git_url(package_base, repository),
|
||||
web_url=Official.remote_web_url(package_base),
|
||||
|
@ -17,4 +17,4 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
__version__ = "2.0.0rc7"
|
||||
__version__ = "2.0.0rc11"
|
||||
|
@ -30,7 +30,7 @@ from aiohttp_session.cookie_storage import EncryptedCookieStorage
|
||||
from cryptography import fernet
|
||||
from typing import Optional
|
||||
|
||||
from ahriman.core.auth.auth import Auth
|
||||
from ahriman.core.auth import Auth
|
||||
from ahriman.models.user_access import UserAccess
|
||||
from ahriman.models.user_identity import UserIdentity
|
||||
from ahriman.web.middlewares import HandlerType, MiddlewareType
|
||||
|
@ -22,9 +22,9 @@ from __future__ import annotations
|
||||
from aiohttp.web import Request, View
|
||||
from typing import Any, Dict, List, Optional, Type
|
||||
|
||||
from ahriman.core.auth.auth import Auth
|
||||
from ahriman.core.auth import Auth
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database.sqlite import SQLite
|
||||
from ahriman.core.database import SQLite
|
||||
from ahriman.core.spawn import Spawn
|
||||
from ahriman.core.status.watcher import Watcher
|
||||
from ahriman.models.user_access import UserAccess
|
||||
|
@ -20,7 +20,7 @@
|
||||
from aiohttp.web import HTTPNotFound, Response, json_response
|
||||
from typing import Callable, List
|
||||
|
||||
from ahriman.core.alpm.remote.aur import AUR
|
||||
from ahriman.core.alpm.remote import AUR
|
||||
from ahriman.models.aur_package import AURPackage
|
||||
from ahriman.models.user_access import UserAccess
|
||||
from ahriman.web.views.base import BaseView
|
||||
|
@ -48,7 +48,7 @@ class LoginView(BaseView):
|
||||
HTTPMethodNotAllowed: in case if method is used, but OAuth is disabled
|
||||
HTTPUnauthorized: if case of authorization error
|
||||
"""
|
||||
from ahriman.core.auth.oauth import OAuth
|
||||
from ahriman.core.auth import OAuth
|
||||
|
||||
oauth_provider = self.validator
|
||||
if not isinstance(oauth_provider, OAuth): # there is actually property, but mypy does not like it anyway
|
||||
|
@ -23,9 +23,9 @@ import logging
|
||||
|
||||
from aiohttp import web
|
||||
|
||||
from ahriman.core.auth.auth import Auth
|
||||
from ahriman.core.auth import Auth
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database.sqlite import SQLite
|
||||
from ahriman.core.database import SQLite
|
||||
from ahriman.core.exceptions import InitializeException
|
||||
from ahriman.core.spawn import Spawn
|
||||
from ahriman.core.status.watcher import Watcher
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user