mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-04-24 15:27:17 +00:00
feat: allow to use one application for multiple repositories (#111)
* allow to use one application for multiple repositories * update tests * handle None append argument everywhere * rewrite repository definition logic * drop optional flags from docs * support of new schema in systemd units * add migration docs and ability to migrate tree automatically * use repostory id instead * verbose multiarchitectureerror * object path support for s3 sync * fix tests after rebase
This commit is contained in:
parent
c915d68c97
commit
efde0b2e86
14
.github/workflows/setup.sh
vendored
14
.github/workflows/setup.sh
vendored
@ -36,21 +36,21 @@ systemd-machine-id-setup
|
||||
|
||||
# initial setup command as root
|
||||
[[ -z $MINIMAL_INSTALL ]] && WEB_ARGS=("--web-port" "8080")
|
||||
ahriman -a x86_64 service-setup --packager "ahriman bot <ahriman@example.com>" --repository "github" "${WEB_ARGS[@]}"
|
||||
ahriman -a x86_64 -r "github" service-setup --packager "ahriman bot <ahriman@example.com>" "${WEB_ARGS[@]}"
|
||||
# validate configuration
|
||||
ahriman -a x86_64 service-config-validate --exit-code
|
||||
ahriman service-config-validate --exit-code
|
||||
# enable services
|
||||
systemctl enable ahriman-web@x86_64
|
||||
systemctl enable ahriman@x86_64.timer
|
||||
systemctl enable ahriman-web@x86_64-github
|
||||
systemctl enable ahriman@x86_64-github.timer
|
||||
if [[ -z $MINIMAL_INSTALL ]]; then
|
||||
# run web service (detached)
|
||||
sudo -u ahriman -- ahriman -a x86_64 web &
|
||||
sudo -u ahriman -- ahriman web &
|
||||
WEB_PID=$!
|
||||
fi
|
||||
# add the first package
|
||||
sudo -u ahriman -- ahriman package-add --now yay
|
||||
sudo -u ahriman -- ahriman package-add --now ahriman
|
||||
# check if package was actually installed
|
||||
test -n "$(find "/var/lib/ahriman/repository/x86_64" -name "yay*pkg*")"
|
||||
test -n "$(find "/var/lib/ahriman/repository/github/x86_64" -name "ahriman*pkg*")"
|
||||
# run package check
|
||||
sudo -u ahriman -- ahriman repo-update
|
||||
# stop web service lol
|
||||
|
@ -17,6 +17,7 @@ host = $AHRIMAN_HOST
|
||||
EOF
|
||||
|
||||
AHRIMAN_DEFAULT_ARGS=("--architecture" "$AHRIMAN_ARCHITECTURE")
|
||||
AHRIMAN_DEFAULT_ARGS+=("--repository" "$AHRIMAN_REPOSITORY")
|
||||
if [ -n "$AHRIMAN_OUTPUT" ]; then
|
||||
AHRIMAN_DEFAULT_ARGS+=("--log-handler" "$AHRIMAN_OUTPUT")
|
||||
fi
|
||||
@ -33,19 +34,18 @@ chown "$AHRIMAN_USER":"$AHRIMAN_USER" "$AHRIMAN_GNUPG_HOME"
|
||||
# run built-in setup command
|
||||
AHRIMAN_SETUP_ARGS=("--build-as-user" "$AHRIMAN_USER")
|
||||
AHRIMAN_SETUP_ARGS+=("--packager" "$AHRIMAN_PACKAGER")
|
||||
AHRIMAN_SETUP_ARGS+=("--repository" "$AHRIMAN_REPOSITORY")
|
||||
if [ -z "$AHRIMAN_MULTILIB" ]; then
|
||||
AHRIMAN_SETUP_ARGS+=("--no-multilib")
|
||||
fi
|
||||
if [ -n "$AHRIMAN_PACMAN_MIRROR" ]; then
|
||||
AHRIMAN_SETUP_ARGS+=("--mirror" "$AHRIMAN_PACMAN_MIRROR")
|
||||
fi
|
||||
if [ -n "$AHRIMAN_PORT" ]; then
|
||||
AHRIMAN_SETUP_ARGS+=("--web-port" "$AHRIMAN_PORT")
|
||||
fi
|
||||
if [ -n "$AHRIMAN_REPOSITORY_SERVER" ]; then
|
||||
AHRIMAN_SETUP_ARGS+=("--server" "$AHRIMAN_REPOSITORY_SERVER")
|
||||
fi
|
||||
if [ -n "$AHRIMAN_PORT" ]; then
|
||||
AHRIMAN_SETUP_ARGS+=("--web-port" "$AHRIMAN_PORT")
|
||||
fi
|
||||
if [ -n "$AHRIMAN_UNIX_SOCKET" ]; then
|
||||
AHRIMAN_SETUP_ARGS+=("--web-unix-socket" "$AHRIMAN_UNIX_SOCKET")
|
||||
fi
|
||||
|
@ -172,6 +172,14 @@ ahriman.application.handlers.structure module
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
ahriman.application.handlers.tree\_migrate module
|
||||
-------------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.application.handlers.tree_migrate
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
ahriman.application.handlers.triggers module
|
||||
--------------------------------------------
|
||||
|
||||
|
@ -92,6 +92,14 @@ ahriman.core.database.migrations.m010\_version\_based\_logs\_removal module
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
ahriman.core.database.migrations.m011\_repository\_name module
|
||||
--------------------------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.database.migrations.m011_repository_name
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
|
@ -36,10 +36,10 @@ ahriman.core.log.lazy\_logging module
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
ahriman.core.log.log module
|
||||
---------------------------
|
||||
ahriman.core.log.log\_loader module
|
||||
-----------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.log.log
|
||||
.. automodule:: ahriman.core.log.log_loader
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
|
@ -164,6 +164,14 @@ ahriman.models.report\_settings module
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
ahriman.models.repository\_id module
|
||||
------------------------------------
|
||||
|
||||
.. automodule:: ahriman.models.repository_id
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
ahriman.models.repository\_paths module
|
||||
---------------------------------------
|
||||
|
||||
|
@ -102,6 +102,53 @@ All subcommands are divided into several groups depending on the role they are d
|
||||
|
||||
For historical reasons and in order to keep backward compatibility some subcommands have aliases to their shorter forms or even other groups, but the service doesn't guarantee that they will remain unchanged.
|
||||
|
||||
Filesystem tree
|
||||
---------------
|
||||
|
||||
The application supports two types of trees, one is for legacy configuration (when there were no repository name explicit configuration available) and another one is for new-style tree. This document describes only new-style tree in order to avoid deprecated structure.
|
||||
|
||||
Having default root as ``/var/lib/ahriman`` (differs from container though), the directory structure is the following:
|
||||
|
||||
.. code-block::
|
||||
|
||||
/var/lib/ahriman/
|
||||
├── ahriman.db
|
||||
├── cache
|
||||
├── chroot
|
||||
│ └── aur-clone
|
||||
├── packages
|
||||
│ └── aur-clone
|
||||
│ └── x86_64
|
||||
├── pacman
|
||||
│ └── aur-clone
|
||||
│ └── x86_64
|
||||
│ ├── local
|
||||
│ │ └── ALPM_DB_VERSION
|
||||
│ └── sync
|
||||
│ ├── core.db
|
||||
│ ├── extra.db
|
||||
│ └── multilib.db
|
||||
│
|
||||
└── repository
|
||||
└── aur-clone
|
||||
└── x86_64
|
||||
├── aur-clone.db -> aur-clone.db.tar.gz
|
||||
├── aur-clone.db.tar.gz
|
||||
├── aur-clone.files -> aur-clone.files.tar.gz
|
||||
└── aur-clone.files.tar.gz
|
||||
|
||||
There are multiple subdirectories, some of them are commons for any repository, but some of them are not.
|
||||
|
||||
* ``cache`` is a directory with locally stored PKGBUILD's and VCS packages. It is common for all repositories and architectures.
|
||||
* ``chroot/{repository}`` is a chroot directory for ``devtools``. It is specific for each repository, but shared for different architectures inside (the ``devtools`` handles architectures automatically).
|
||||
* ``packages/{repository}/{architecture}`` is a directory with prebuilt packages. When package is built, first it will be uploaded to this directory and later will be handled by update process. It is architecture and repository specific.
|
||||
* ``pacman/{repository}/{architecture}`` is repository and architecture specific caches for pacman's databases.
|
||||
* ``repository/{repository}/{architecture}`` is a repository packages directory.
|
||||
|
||||
Normally you should avoid direct interaction with the application tree.
|
||||
|
||||
For tree migration process refer to the :doc:`migration notes <migration>`.
|
||||
|
||||
Database
|
||||
--------
|
||||
|
||||
@ -274,7 +321,7 @@ There are several supported synchronization providers, currently they are ``rsyn
|
||||
|
||||
``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/aur-clone/x86_64`` for the ``aur-clone`` repository ``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.
|
||||
|
||||
|
@ -1,7 +1,12 @@
|
||||
Configuration
|
||||
=============
|
||||
|
||||
Some groups can be specified for each architecture separately. E.g. if there are ``build`` and ``build:x86_64`` groups it will use an option from ``build:x86_64`` for the ``x86_64`` architecture and ``build`` for any other (architecture specific group has higher priority). In case if both groups are presented, architecture specific options will be merged into global ones overriding them.
|
||||
Some groups can be specified for each architecture and/or repository separately. E.g. if there are ``build`` and ``build:x86_64`` groups it will use an option from ``build:x86_64`` for the ``x86_64`` architecture and ``build`` for any other (architecture specific group has higher priority). In case if both groups are presented, architecture specific options will be merged into global ones overriding them. The order which will be used for option resolution is the following:
|
||||
|
||||
#. Repository and architecture specific, e.g. ``build:aur-clone:x86_64``.
|
||||
#. Repository specific, e.g. ``build:aur-clone``.
|
||||
#. Architecture specific, e.g. ``build:x86_64``.
|
||||
#. Default section, e.g. ``build``.
|
||||
|
||||
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:
|
||||
|
||||
@ -25,7 +30,7 @@ There is also additional subcommand which will allow to validate configuration a
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
ahriman -a x86_64 service-config-validate
|
||||
ahriman service-config-validate
|
||||
|
||||
It will check current settings on common errors and compare configuration with known schema.
|
||||
|
||||
@ -87,7 +92,6 @@ Build related configuration. Group name can refer to architecture, e.g. ``build:
|
||||
|
||||
Base repository settings.
|
||||
|
||||
* ``name`` - repository name, string, required.
|
||||
* ``root`` - root path for application, string, required.
|
||||
|
||||
``sign:*`` groups
|
||||
@ -292,20 +296,21 @@ Type will be read from several sources:
|
||||
``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.
|
||||
* ``password`` - created Github API key. In order to create it do the following:
|
||||
* ``owner`` - GitHub repository owner, string, required.
|
||||
* ``password`` - created GitHub API key. In order to create it do the following:
|
||||
|
||||
#. Go to `settings page <https://github.com/settings/profile>`_.
|
||||
#. Switch to `developers settings <https://github.com/settings/apps>`_.
|
||||
#. Switch to `personal access tokens <https://github.com/settings/tokens>`_.
|
||||
#. Generate new token. Required scope is ``public_repo`` (or ``repo`` for private repository support).
|
||||
|
||||
* ``repository`` - Github repository name, string, required. Repository must be created before any action and must have active branch (e.g. with readme).
|
||||
* ``repository`` - GitHub repository name, string, required. Repository must be created before any action and must have active branch (e.g. with readme).
|
||||
* ``timeout`` - HTTP request timeout in seconds, int, optional, default is ``30``.
|
||||
* ``username`` - Github authorization user, string, required. Basically the same as ``owner``.
|
||||
* ``use_full_release_name`` - if set to ``yes``, the release will contain both repository name and architecture, and only architecture otherwise, boolean, optional, default ``no`` (legacy behavior).
|
||||
* ``username`` - GitHub authorization user, string, required. Basically the same as ``owner``.
|
||||
|
||||
``remote-service`` type
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -329,9 +334,10 @@ Requires ``rsync`` package to be installed. Do not forget to configure ssh for u
|
||||
|
||||
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.
|
||||
* ``type`` - type of the upload, string, optional, must be set to ``s3`` if exists.
|
||||
* ``access_key`` - AWS access key ID, string, required.
|
||||
* ``bucket`` - bucket name (e.g. ``bucket``), string, required.
|
||||
* ``chunk_size`` - chunk size for calculating entity tags, int, optional, default 8 * 1024 * 1024.
|
||||
* ``object_path`` - path prefix for stored objects, string, optional. If none set, the prefix as in repository tree will be used.
|
||||
* ``region`` - bucket region (e.g. ``eu-central-1``), string, required.
|
||||
* ``secret_key`` - AWS secret access key, string, required.
|
99
docs/faq.rst
99
docs/faq.rst
@ -17,8 +17,8 @@ TL;DR
|
||||
.. code-block:: shell
|
||||
|
||||
yay -S ahriman
|
||||
ahriman -a x86_64 service-setup --packager "ahriman bot <ahriman@example.com>" --repository "repository"
|
||||
systemctl enable --now ahriman@x86_64.timer
|
||||
ahriman -a x86_64 -r aur-clone service-setup --packager "ahriman bot <ahriman@example.com>"
|
||||
systemctl enable --now ahriman@x86_64-aur-clone.timer
|
||||
|
||||
Long answer
|
||||
"""""""""""
|
||||
@ -32,7 +32,7 @@ There is special command which can be used in order to validate current configur
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
ahriman -a x86_64 service-config-validate --exit-code
|
||||
ahriman service-config-validate --exit-code
|
||||
|
||||
This command will print found errors, based on `cerberus <https://docs.python-cerberus.org/>`_, e.g.:
|
||||
|
||||
@ -71,7 +71,7 @@ states that default build command is ``extra-x86_64-build``. But if there is sec
|
||||
[build:i686]
|
||||
build_command = extra-i686-build
|
||||
|
||||
the ``extra-i686-build`` command will be used for ``i686`` architecture.
|
||||
the ``extra-i686-build`` command will be used for ``i686`` architecture. You can also override settings for different repositories and architectures; in this case section names will be ``build:aur-clone`` (repository name only) and ``build:aur-clone:i686`` (both repository name and architecture).
|
||||
|
||||
How to generate build reports
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -121,7 +121,7 @@ How do I add new package
|
||||
|
||||
sudo -u ahriman ahriman package-add ahriman --now
|
||||
|
||||
``--now`` flag is totally optional and just run ``repo-update`` subcommand after the registering the new package, Thus the extended flow is the following:
|
||||
``--now`` flag is totally optional and just run ``repo-update`` subcommand after the registering the new package. Thus the extended flow is the following:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
@ -209,7 +209,7 @@ So it is the same as adding any other package, but due to restrictions you must
|
||||
|
||||
sudo -u ahriman ahriman package-add pacman -s repository
|
||||
|
||||
This feature is heavily depends on local pacman cache. In order to use this feature it is recommended to either run ``pacman -Sy`` before the interaction or configure timer for this.
|
||||
This feature is heavily depends on local pacman cache. In order to use this feature it is recommended to either run ``pacman -Sy`` before the interaction or use internal application cache with ``--refresh`` flag.
|
||||
|
||||
Package build fails because it cannot validate PGP signature of source files
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -317,7 +317,7 @@ Add the following lines to your ``pacman.conf``:
|
||||
.. code-block:: ini
|
||||
|
||||
[repository]
|
||||
Server = file:///var/lib/ahriman/repository/x86_64
|
||||
Server = file:///var/lib/ahriman/repository/$repo/$arch
|
||||
|
||||
(You might need to add ``SigLevel`` option according to the pacman documentation.)
|
||||
|
||||
@ -359,7 +359,14 @@ Example of the status page configuration is the following (status service is usi
|
||||
Docker image
|
||||
------------
|
||||
|
||||
We provide official images which can be found under ``arcan1s/ahriman`` repository. Docker image is being updated on each commit to master as well as on each version. If you would like to use last (probably unstable) build you can use ``edge`` tag or ``latest`` for any tagged versions; otherwise you can use any version tag available.
|
||||
We provide official images which can be found under:
|
||||
|
||||
* docker registry ``arcan1s/ahriman``;
|
||||
* ghcr.io registry ``ghcr.io/arcan1s/ahriman``;
|
||||
|
||||
These images are totally identical.
|
||||
|
||||
Docker image is being updated on each commit to master as well as on each version. If you would like to use last (probably unstable) build you can use ``edge`` tag or ``latest`` for any tagged versions; otherwise you can use any version tag available.
|
||||
|
||||
The default action (in case if no arguments provided) is ``repo-update``. Basically the idea is to run container, e.g.:
|
||||
|
||||
@ -456,22 +463,22 @@ Physical server setup
|
||||
In this example we are going to use files and packages which are provided by official repositories of the used architecture. Note, that versions might be different, thus you need to find correct versions on the distribution web site, e.g. `archlinux32 packages <https://www.archlinux32.org/packages/>`_.
|
||||
|
||||
#.
|
||||
First, considering having base Arch Linux system, we need to install keyring for the specified repositories:
|
||||
First, considering having base Arch Linux system, we need to install keyring for the specified repositories, e.g.:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
wget http://pool.mirror.archlinux32.org/i686/core/archlinux32-keyring-20220927-1.0-any.pkg.tar.zst
|
||||
pacman -U archlinux32-keyring-20220927-1.0-any.pkg.tar.zst
|
||||
wget http://pool.mirror.archlinux32.org/i686/core/archlinux32-keyring-20230705-1.0-any.pkg.tar.zst
|
||||
pacman -U archlinux32-keyring-20230705-1.0-any.pkg.tar.zst
|
||||
|
||||
#.
|
||||
In order to run ``devtools`` scripts for custom architecture they also need specific ``makepkg`` configuration, it can be retrieved by installing the ``devtools`` package of the distribution:
|
||||
In order to run ``devtools`` scripts for custom architecture they also need specific ``makepkg`` configuration, it can be retrieved by installing the ``devtools`` package of the distribution, e.g.:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
wget http://pool.mirror.archlinux32.org/i686/extra/devtools-20221208-1.0-any.pkg.tar.zst
|
||||
pacman -U devtools-20221208-1.0-any.pkg.tar.zst
|
||||
wget http://pool.mirror.archlinux32.org/i686/extra/devtools-20221208-1.2-any.pkg.tar.zst
|
||||
pacman -U devtools-20221208-1.2-any.pkg.tar.zst
|
||||
|
||||
Alternatively, you can create your own ``makepkg`` configuration and save it as ``/usr/share/devtools/makepkg-i686.conf``.
|
||||
Alternatively, you can create your own ``makepkg`` configuration and save it as ``/usr/share/devtools/makepkg.conf.d/i686.conf``.
|
||||
|
||||
#.
|
||||
Setup repository as usual:
|
||||
@ -485,6 +492,9 @@ In this example we are going to use files and packages which are provided by off
|
||||
* ``--mirror`` - link to the mirrors which will be used instead of official repositories.
|
||||
* ``--no-multilib`` - in the example we are using i686 architecture for which multilib repository doesn't exist.
|
||||
|
||||
#.
|
||||
That's all Folks!
|
||||
|
||||
Docker container setup
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@ -510,8 +520,8 @@ There are two possible ways to achieve same setup, by using docker container. Th
|
||||
.. code-block:: dockerfile
|
||||
|
||||
RUN pacman --noconfirm -Sy wget
|
||||
RUN wget http://pool.mirror.archlinux32.org/i686/extra/devtools-20221208-1.0-any.pkg.tar.zst && pacman --noconfirm -U devtools-20221208-1.0-any.pkg.tar.zst
|
||||
RUN wget http://pool.mirror.archlinux32.org/i686/core/archlinux32-keyring-20220927-1.0-any.pkg.tar.zst && pacman --noconfirm -U archlinux32-keyring-20220927-1.0-any.pkg.tar.zst
|
||||
RUN wget http://pool.mirror.archlinux32.org/i686/extra/devtools-20221208-1.2-any.pkg.tar.zst && pacman --noconfirm -U devtools-20221208-1.2-any.pkg.tar.zst
|
||||
RUN wget http://pool.mirror.archlinux32.org/i686/core/archlinux32-keyring-20230705-1.0-any.pkg.tar.zst && pacman --noconfirm -U archlinux32-keyring-20230705-1.0-any.pkg.tar.zst
|
||||
|
||||
#.
|
||||
At that point you should have full ``Dockerfile`` like:
|
||||
@ -523,8 +533,8 @@ There are two possible ways to achieve same setup, by using docker container. Th
|
||||
RUN pacman-key --init
|
||||
|
||||
RUN pacman --noconfirm -Sy wget
|
||||
RUN wget http://pool.mirror.archlinux32.org/i686/extra/devtools-20221208-1.0-any.pkg.tar.zst && pacman --noconfirm -U devtools-20221208-1.0-any.pkg.tar.zst
|
||||
RUN wget http://pool.mirror.archlinux32.org/i686/core/archlinux32-keyring-20220927-1.0-any.pkg.tar.zst && pacman --noconfirm -U archlinux32-keyring-20220927-1.0-any.pkg.tar.zst
|
||||
RUN wget http://pool.mirror.archlinux32.org/i686/extra/devtools-20221208-1.2-any.pkg.tar.zst && pacman --noconfirm -U devtools-20221208-1.2-any.pkg.tar.zst
|
||||
RUN wget http://pool.mirror.archlinux32.org/i686/core/archlinux32-keyring-20230705-1.0-any.pkg.tar.zst && pacman --noconfirm -U archlinux32-keyring-20230705-1.0-any.pkg.tar.zst
|
||||
|
||||
#.
|
||||
After that you can build you own container, e.g.:
|
||||
@ -554,8 +564,8 @@ There are several choices:
|
||||
.. code-block::
|
||||
|
||||
server {
|
||||
location /x86_64 {
|
||||
root /var/lib/ahriman/repository/x86_64;
|
||||
location / {
|
||||
root /var/lib/ahriman/repository/;
|
||||
autoindex on;
|
||||
}
|
||||
}
|
||||
@ -571,7 +581,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 (``Server = https://s3.eu-central-1.amazonaws.com/repository/aur-clone/x86_64``) or to Github (``Server = https://github.com/ahriman/repository/releases/download/aur-clone-x86_64``).
|
||||
|
||||
How to sync to S3
|
||||
^^^^^^^^^^^^^^^^^
|
||||
@ -632,6 +642,23 @@ How to sync to S3
|
||||
region = eu-central-1
|
||||
secret_key = ...
|
||||
|
||||
S3 with SSL
|
||||
"""""""""""
|
||||
|
||||
In order to configure S3 on custom domain with SSL (and some other features, like redirects), the CloudFront should be used.
|
||||
|
||||
#. Configure S3 as described above.
|
||||
#. In bucket properties, enable static website hosting with hosting type "Host a static website".
|
||||
#. Go to AWS Certificate Manager and create public ceritificate on your domain. Validate domain as suggested.
|
||||
#. Go to CloudFront and create distribution. The following settings are required:
|
||||
|
||||
* Origin domain choose S3 bucket.
|
||||
* Tick use website endpoint.
|
||||
* Disable caching.
|
||||
* Select issued certificate.
|
||||
|
||||
#. Point DNS record to CloudFront address.
|
||||
|
||||
How to sync to Github releases
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@ -676,7 +703,7 @@ How to report by email
|
||||
|
||||
[email]
|
||||
host = smtp.example.com
|
||||
link_path = http://example.com/x86_64
|
||||
link_path = http://example.com/aur-clone/x86_64
|
||||
password = ...
|
||||
port = 465
|
||||
receivers = me@example.com
|
||||
@ -702,10 +729,10 @@ How to generate index page for S3
|
||||
target = html
|
||||
|
||||
[html]
|
||||
path = /var/lib/ahriman/repository/x86_64/index.html
|
||||
link_path = http://example.com/x86_64
|
||||
path = /var/lib/ahriman/repository/aur-clone/x86_64/index.html
|
||||
link_path = http://example.com/aur-clone/x86_64
|
||||
|
||||
After these steps ``index.html`` file will be automatically synced to S3
|
||||
After these steps ``index.html`` file will be automatically synced to S3.
|
||||
|
||||
How to post build report to telegram
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -741,7 +768,7 @@ How to post build report to telegram
|
||||
[telegram]
|
||||
api_key = aaAAbbBBccCC
|
||||
chat_id = @ahriman
|
||||
link_path = http://example.com/x86_64
|
||||
link_path = http://example.com/aur-clone/x86_64
|
||||
|
||||
``api_key`` is the one sent by `@BotFather <https://t.me/botfather>`_, ``chat_id`` is the value retrieved from previous step.
|
||||
|
||||
@ -756,7 +783,7 @@ If you did everything fine you should receive the message with the next update.
|
||||
Distributed builds
|
||||
------------------
|
||||
|
||||
The service allows to run build on multiple machines and collect packages on main node. There are multiple ways to achieve it, this section describes officially supported methods.
|
||||
The service allows to run build on multiple machines and collect packages on main node. There are several ways to achieve it, this section describes officially supported methods.
|
||||
|
||||
Remote synchronization and remote server call
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -933,7 +960,7 @@ Command to run worker node:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
docker run --privileged -v worker.ini:/etc/ahriman.ini.d/overrides.ini -it arcan1s/ahriman:latest package-add arhiman --now
|
||||
docker run --privileged -v worker.ini:/etc/ahriman.ini.d/overrides.ini -it arcan1s/ahriman:latest package-add ahriman --now
|
||||
|
||||
The command above will successfully build ``ahriman`` package, upload it on master node and, finally, will update master node repository.
|
||||
|
||||
@ -1046,7 +1073,7 @@ How to setup web service
|
||||
port = 8080
|
||||
|
||||
#.
|
||||
Start the web service ``systemctl enable --now ahriman-web@x86_64``.
|
||||
Start the web service ``systemctl enable --now ahriman-web@x86_64-aur-clone``.
|
||||
|
||||
How to enable basic authorization
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -1059,7 +1086,7 @@ How to enable basic authorization
|
||||
yay -S --asdeps python-aiohttp-security python-aiohttp-session python-cryptography
|
||||
|
||||
#.
|
||||
Configure the service to enable authorization (``salt`` can be generated as any random string):
|
||||
Configure the service to enable authorization (``salt`` can be generated as any random string and optional):
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
@ -1087,7 +1114,7 @@ How to enable basic authorization
|
||||
|
||||
sudo -u ahriman ahriman user-add -r full api
|
||||
|
||||
This command will ask for the password, just type it in stdin; *do not* leave the field blank, user will not be able to authorize, and finally configure the application:
|
||||
This command will ask for the password, just type it in stdin; **do not** leave the field blank, user will not be able to authorize, and finally configure the application:
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
@ -1103,7 +1130,7 @@ How to enable basic authorization
|
||||
sudo -u ahriman ahriman user-add -r full my-first-user
|
||||
|
||||
#.
|
||||
Restart web service ``systemctl restart ahriman-web@x86_64``.
|
||||
Restart web service ``systemctl restart ahriman-web@x86_64-aur-clone``.
|
||||
|
||||
How to enable OAuth authorization
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -1149,7 +1176,7 @@ How to enable OAuth authorization
|
||||
When it will ask for the password leave it blank.
|
||||
|
||||
#.
|
||||
Restart web service ``systemctl restart ahriman-web@x86_64``.
|
||||
Restart web service ``systemctl restart ahriman-web@x86_64-aur-clone``.
|
||||
|
||||
How to implement own interface
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -1265,7 +1292,9 @@ You can also ask to forward logs to ``stderr``, just set ``--log-handler`` flag,
|
||||
|
||||
ahriman --log-handler console ...
|
||||
|
||||
You can even configure logging as you wish, but kindly refer to python ``logging`` module `configuration <https://docs.python.org/3/library/logging.config.html>`_. The application uses java concept to log messages, e.g. class ``Application`` imported from ``ahriman.application.application`` package will have logger called ``ahriman.application.application.Application``. In order to e.g. change logger name for whole application package it is possible to change values for ``ahriman.application`` package; thus editing ``ahriman`` logger configuration will change logging for whole application (unless there are overrides for another logger).
|
||||
You can even configure logging as you wish, but kindly refer to python ``logging`` module `configuration <https://docs.python.org/3/library/logging.config.html>`_.
|
||||
|
||||
The application uses java concept to log messages, e.g. class ``Application`` imported from ``ahriman.application.application`` package will have logger called ``ahriman.application.application.Application``. In order to e.g. change logger name for whole application package it is possible to change values for ``ahriman.application`` package; thus editing ``ahriman`` logger configuration will change logging for whole application (unless there are overrides for another logger).
|
||||
|
||||
Html customization
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
@ -34,6 +34,7 @@ Contents
|
||||
configuration
|
||||
command-line
|
||||
faq
|
||||
migration
|
||||
architecture
|
||||
advanced-usage
|
||||
triggers
|
||||
|
55
docs/migration.rst
Normal file
55
docs/migration.rst
Normal file
@ -0,0 +1,55 @@
|
||||
Manual migrations
|
||||
=================
|
||||
|
||||
Normally most of migrations are handled automatically after application start. However, some upgrades require manual interventions; this document describes them.
|
||||
|
||||
Upgrades to breakpoints
|
||||
-----------------------
|
||||
|
||||
To 2.9.0
|
||||
^^^^^^^^
|
||||
|
||||
This release includes major upgrade for the newest devtools and archlinux repository structure. In order to upgrade package need to:
|
||||
|
||||
#. Upgrade to the latest major release of python (3.11) (required by other changes).
|
||||
#. Upgrade devtools to the latest release.
|
||||
#. Backup your settings, ``/etc/ahriman.ini.d/00-setup-overrides.ini`` by default.
|
||||
#. Run setup command (i.e. ``ahriman service-setup``) again with the same arguments as you used before. This step can be done manually by moving ``devtools`` configuration (something like ``/usr/share/devtools/pacman-ahriman*.conf``) to new location ``/usr/share/devtools/pacman.conf.d/`` under name ``ahriman.conf``. After that make sure to remove any ``community`` mentions from configurations (e.g. ``/usr/share/devtools/pacman.conf.d/ahriman.conf``, ``/etc/ahriman.ini``) if there were any. The only thing which will change is ``devtools`` configuration.
|
||||
#. Remove build chroot as it is incompatible, e.g. ``sudo ahriman service-clean --chroot``.
|
||||
#. Run ``sudo -u ahriman ahriman update --no-aur --no-local --no-manual -yy`` in order to update local databases.
|
||||
|
||||
To 2.12.0
|
||||
^^^^^^^^^
|
||||
|
||||
This release includes paths migration. Unlike usual case, no automatic migration is performed because it might break user configuration. The following noticeable changes have been made:
|
||||
|
||||
* Path to pre-built packages now includes repository name, i.e. it has been changed from ``/var/lib/ahriman/packages/x86_64`` to ``/var/lib/ahriman/packages/aur-clone/x86_64``.
|
||||
* Path to pacman databases now includes repository name too, it has been changed from ``/var/lib/ahriman/pacman/x86_64`` to ``/var/lib/ahriman/pacman/aur-clone/x86_64``.
|
||||
* Path to repository itself also includes repository name, from ``/var/lib/ahriman/repository/x86_64`` to ``/var/lib/ahriman/repository/aur-clone/x86_64``.
|
||||
|
||||
In order to migrate to new filesystem tree the following actions are required:
|
||||
|
||||
#.
|
||||
Stop and disable all services, e.g. timer and web service:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
sudo systemctl disable --now ahriman@x86_64.timer
|
||||
sudo systemctl disable --now ahriman-web@x86_64
|
||||
|
||||
#.
|
||||
Create directory tree. It can be done by running ``ahriman service-tree-migrate`` subcommand. It performs copying between the old repository tree and the new one. Alternatively you can copy directories by hands.
|
||||
|
||||
#.
|
||||
Edit configuration in case if anything is pointing to the old path, e.g. HTML report generation, in the way in which it will be pointed to directory inside repository specific one, e.g. ``/var/lib/ahriman/repository/x86_64`` to ``/var/lib/ahriman/repository/aur-clone/x86_64``.
|
||||
|
||||
#.
|
||||
Make sure to update remote synchronization services if any. Almost all of them rely on current repository tree by default, so you need to setup either redirects or configure to synchronize to the old locations (e.g. ``object_path`` option for S3 synchronization).
|
||||
|
||||
#.
|
||||
Enable and start services again. Unit template parameter should include both repository architecture and name, dash separated, e.g. ``x86_64-aur-clone``:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
sudo systemctl enable --now ahriman@x86_64-aur-clone.timer
|
||||
sudo systemctl enable --now ahriman-web@x86_64-aur-clone
|
@ -10,7 +10,7 @@ Initial setup
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
sudo ahriman -a x86_64 service-setup ...
|
||||
sudo ahriman -a x86_64 -r aur-clone service-setup ...
|
||||
|
||||
``service-setup`` literally does the following steps:
|
||||
|
||||
@ -29,26 +29,26 @@ Initial setup
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
ln -s /usr/bin/archbuild /usr/local/bin/ahriman-x86_64-build
|
||||
ln -s /usr/bin/archbuild /usr/local/bin/aur-clone-x86_64-build
|
||||
|
||||
#.
|
||||
Create configuration file (same as previous ``{name}.conf``):
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
cp /usr/share/devtools/pacman.conf.d/{extra,ahriman}.conf
|
||||
cp /usr/share/devtools/pacman.conf.d/{extra,aur-clone}.conf
|
||||
|
||||
#.
|
||||
Change configuration file, add your own repository, add multilib repository etc:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
echo '[multilib]' | tee -a /usr/share/devtools/pacman-ahriman.conf
|
||||
echo 'Include = /etc/pacman.d/mirrorlist' | tee -a /usr/share/devtools/pacman.conf.d/ahriman.conf
|
||||
echo '[multilib]' | tee -a /usr/share/devtools/pacman.conf.d/aur-clone-x86_64.conf
|
||||
echo 'Include = /etc/pacman.d/mirrorlist' | tee -a /usr/share/devtools/pacman.conf.d/aur-clone-x86_64.conf
|
||||
|
||||
echo '[aur-clone]' | tee -a /usr/share/devtools/pacman-ahriman.conf
|
||||
echo 'SigLevel = Optional TrustAll' | tee -a /usr/share/devtools/pacman.conf.d/ahriman.conf
|
||||
echo 'Server = file:///var/lib/ahriman/repository/$arch' | tee -a /usr/share/devtools/pacman.conf.d/ahriman.conf
|
||||
echo '[aur-clone]' | tee -a /usr/share/devtools/pacman.conf.d/aur-clone-x86_64.conf
|
||||
echo 'SigLevel = Optional TrustAll' | tee -a /usr/share/devtools/pacman.conf.d/aur-clone-x86_64.conf
|
||||
echo 'Server = file:///var/lib/ahriman/repository/$repo/$arch' | tee -a /usr/share/devtools/pacman.conf.d/aur-clone-x86_64.conf
|
||||
|
||||
#.
|
||||
Set ``build_command`` option to point to your command:
|
||||
@ -56,14 +56,14 @@ Initial setup
|
||||
.. code-block:: shell
|
||||
|
||||
echo '[build]' | tee -a /etc/ahriman.ini.d/build.ini
|
||||
echo 'build_command = ahriman-x86_64-build' | tee -a /etc/ahriman.ini.d/build.ini
|
||||
echo 'build_command = aur-clone-x86_64-build' | tee -a /etc/ahriman.ini.d/build.ini
|
||||
|
||||
#.
|
||||
Configure ``/etc/sudoers.d/ahriman`` to allow running command without a password:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
echo 'Cmnd_Alias CARCHBUILD_CMD = /usr/local/bin/ahriman-x86_64-build *' | tee -a /etc/sudoers.d/ahriman
|
||||
echo 'Cmnd_Alias CARCHBUILD_CMD = /usr/local/bin/aur-clone-x86_64-build *' | tee -a /etc/sudoers.d/ahriman
|
||||
echo 'ahriman ALL=(ALL) NOPASSWD:SETENV: CARCHBUILD_CMD' | tee -a /etc/sudoers.d/ahriman
|
||||
chmod 400 /etc/sudoers.d/ahriman
|
||||
|
||||
@ -74,20 +74,20 @@ Initial setup
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
systemctl enable --now ahriman@x86_64.timer
|
||||
systemctl enable --now ahriman@x86_64-aur-clone.timer
|
||||
|
||||
#.
|
||||
Start and enable status page:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
systemctl enable --now ahriman-web@x86_64
|
||||
systemctl enable --now ahriman-web@x86_64-aur-clone
|
||||
|
||||
#.
|
||||
Add packages by using ``ahriman package-add {package}`` command:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
sudo -u ahriman ahriman -a x86_64 package-add ahriman --now --refresh
|
||||
sudo -u ahriman ahriman package-add ahriman --now --refresh
|
||||
|
||||
The ``--refresh`` flag is required in order to handle local database update.
|
||||
|
@ -1,6 +1,7 @@
|
||||
post_upgrade() {
|
||||
local breakpoints=(
|
||||
2.9.0-1
|
||||
2.12.0-1
|
||||
)
|
||||
|
||||
for v in "${breakpoints[@]}"; do
|
||||
@ -20,6 +21,21 @@ It was found that you were upgrading from old-devtools package to the new one, w
|
||||
* remove build chroot: sudo rm -r /var/lib/ahriman/chroot/ahriman-x86_64/;
|
||||
* update local databases: sudo -u ahriman ahriman update --no-aur --no-local --no-manual -yy;
|
||||
|
||||
For more information kindly refer to changelog https://github.com/arcan1s/ahriman/releases/tag/2.9.0
|
||||
For more information kindly refer to migration notes https://ahriman.readthedocs.io/en/stable/migration.html
|
||||
EOF
|
||||
}
|
||||
|
||||
_2_12_0_1_changes() {
|
||||
cat << EOF
|
||||
Whereas old tree is still supported it is highly recommended to migrate to the new one:
|
||||
|
||||
* stop and disable all services;
|
||||
* run service-tree-migrate as ahriman user;
|
||||
* edit configuration to avoid pointing to the old paths;
|
||||
* update synchronization services in order to support new paths (or setup redirects);
|
||||
* enable web and timer services again by using x86_64-aur-clone suffix, where x86_64 is your architecture and
|
||||
aur-clone is repository name;
|
||||
|
||||
For more information kindly refer to migration notes https://ahriman.readthedocs.io/en/stable/migration.html
|
||||
EOF
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
[Unit]
|
||||
Description=ArcH linux ReposItory MANager web server (%I architecture)
|
||||
Description=ArcH linux ReposItory MANager web server (%i)
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/bin/ahriman --architecture %i web
|
||||
ExecStart=/usr/bin/ahriman --repository-id "%I" web
|
||||
User=ahriman
|
||||
Group=ahriman
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
[Unit]
|
||||
Description=ArcH linux ReposItory MANager (%I architecture)
|
||||
Description=ArcH linux ReposItory MANager (%i)
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/ahriman --architecture %i repo-update --refresh
|
||||
ExecStart=/usr/bin/ahriman --repository-id "%I" repo-update --refresh
|
||||
User=ahriman
|
||||
Group=ahriman
|
@ -1,5 +1,5 @@
|
||||
[Unit]
|
||||
Description=ArcH linux ReposItory MANager timer (%I architecture)
|
||||
Description=ArcH linux ReposItory MANager timer (%i)
|
||||
|
||||
[Timer]
|
||||
OnCalendar=daily
|
||||
|
@ -21,7 +21,6 @@ allow_read_only = yes
|
||||
|
||||
[build]
|
||||
archbuild_flags =
|
||||
build_command = extra-x86_64-build
|
||||
ignore_packages =
|
||||
makechrootpkg_flags =
|
||||
makepkg_flags = --nocolor --ignorearch
|
||||
@ -30,7 +29,6 @@ triggers_known = ahriman.core.gitremote.RemotePullTrigger ahriman.core.gitremote
|
||||
vcs_allowed_age = 604800
|
||||
|
||||
[repository]
|
||||
name = aur-clone
|
||||
root = /var/lib/ahriman
|
||||
|
||||
[sign]
|
||||
|
@ -1,8 +1,8 @@
|
||||
# AUTOMATICALLY GENERATED by `shtab`
|
||||
|
||||
_shtab_ahriman_subparsers=('aur-search' 'search' 'help' 'help-commands-unsafe' 'help-updates' 'help-version' 'version' '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' 'patch-set-add' 'repo-backup' 'repo-check' 'check' 'repo-create-keyring' 'repo-create-mirrorlist' 'repo-daemon' 'daemon' 'repo-rebuild' 'rebuild' 'repo-remove-unknown' 'remove-unknown' 'repo-report' 'report' 'repo-restore' 'repo-sign' 'sign' 'repo-status-update' 'repo-sync' 'sync' 'repo-tree' 'repo-triggers' 'repo-update' 'update' 'service-clean' 'clean' 'repo-clean' 'service-config' 'config' 'repo-config' 'service-config-validate' 'config-validate' 'repo-config-validate' 'service-key-import' 'key-import' 'service-setup' 'init' 'repo-init' 'repo-setup' 'setup' 'service-shell' 'shell' 'user-add' 'user-list' 'user-remove' 'web')
|
||||
_shtab_ahriman_subparsers=('aur-search' 'search' 'help' 'help-commands-unsafe' 'help-updates' 'help-version' 'version' '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' 'patch-set-add' 'repo-backup' 'repo-check' 'check' 'repo-create-keyring' 'repo-create-mirrorlist' 'repo-daemon' 'daemon' 'repo-rebuild' 'rebuild' 'repo-remove-unknown' 'remove-unknown' 'repo-report' 'report' 'repo-restore' 'repo-sign' 'sign' 'repo-status-update' 'repo-sync' 'sync' 'repo-tree' 'repo-triggers' 'repo-update' 'update' 'service-clean' 'clean' 'repo-clean' 'service-config' 'config' 'repo-config' 'service-config-validate' 'config-validate' 'repo-config-validate' 'service-key-import' 'key-import' 'service-setup' 'init' 'repo-init' 'repo-setup' 'setup' 'service-shell' 'shell' 'service-tree-migrate' 'user-add' 'user-list' 'user-remove' 'web')
|
||||
|
||||
_shtab_ahriman_option_strings=('-h' '--help' '-a' '--architecture' '-c' '--configuration' '--force' '-l' '--lock' '--log-handler' '--report' '--no-report' '-q' '--quiet' '--unsafe' '--wait-timeout' '-V' '--version')
|
||||
_shtab_ahriman_option_strings=('-h' '--help' '-a' '--architecture' '-c' '--configuration' '--force' '-l' '--lock' '--log-handler' '-q' '--quiet' '--report' '--no-report' '-r' '--repository' '--unsafe' '--wait-timeout' '-V' '--version')
|
||||
_shtab_ahriman_aur_search_option_strings=('-h' '--help' '-e' '--exit-code' '--info' '--no-info' '--sort-by')
|
||||
_shtab_ahriman_search_option_strings=('-h' '--help' '-e' '--exit-code' '--info' '--no-info' '--sort-by')
|
||||
_shtab_ahriman_help_option_strings=('-h' '--help')
|
||||
@ -58,21 +58,22 @@ _shtab_ahriman_config_validate_option_strings=('-h' '--help' '-e' '--exit-code')
|
||||
_shtab_ahriman_repo_config_validate_option_strings=('-h' '--help' '-e' '--exit-code')
|
||||
_shtab_ahriman_service_key_import_option_strings=('-h' '--help' '--key-server')
|
||||
_shtab_ahriman_key_import_option_strings=('-h' '--help' '--key-server')
|
||||
_shtab_ahriman_service_setup_option_strings=('-h' '--help' '--build-as-user' '--build-command' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--repository' '--server' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket')
|
||||
_shtab_ahriman_init_option_strings=('-h' '--help' '--build-as-user' '--build-command' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--repository' '--server' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket')
|
||||
_shtab_ahriman_repo_init_option_strings=('-h' '--help' '--build-as-user' '--build-command' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--repository' '--server' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket')
|
||||
_shtab_ahriman_repo_setup_option_strings=('-h' '--help' '--build-as-user' '--build-command' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--repository' '--server' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket')
|
||||
_shtab_ahriman_setup_option_strings=('-h' '--help' '--build-as-user' '--build-command' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--repository' '--server' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket')
|
||||
_shtab_ahriman_service_setup_option_strings=('-h' '--help' '--build-as-user' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--server' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket')
|
||||
_shtab_ahriman_init_option_strings=('-h' '--help' '--build-as-user' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--server' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket')
|
||||
_shtab_ahriman_repo_init_option_strings=('-h' '--help' '--build-as-user' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--server' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket')
|
||||
_shtab_ahriman_repo_setup_option_strings=('-h' '--help' '--build-as-user' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--server' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket')
|
||||
_shtab_ahriman_setup_option_strings=('-h' '--help' '--build-as-user' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--server' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket')
|
||||
_shtab_ahriman_service_shell_option_strings=('-h' '--help')
|
||||
_shtab_ahriman_shell_option_strings=('-h' '--help')
|
||||
_shtab_ahriman_user_add_option_strings=('-h' '--help' '--key' '--packager' '-p' '--password' '-r' '--role')
|
||||
_shtab_ahriman_user_list_option_strings=('-h' '--help' '-e' '--exit-code' '-r' '--role')
|
||||
_shtab_ahriman_service_tree_migrate_option_strings=('-h' '--help')
|
||||
_shtab_ahriman_user_add_option_strings=('-h' '--help' '--key' '--packager' '-p' '--password' '-R' '--role')
|
||||
_shtab_ahriman_user_list_option_strings=('-h' '--help' '-e' '--exit-code' '-R' '--role')
|
||||
_shtab_ahriman_user_remove_option_strings=('-h' '--help')
|
||||
_shtab_ahriman_web_option_strings=('-h' '--help')
|
||||
|
||||
|
||||
|
||||
_shtab_ahriman_pos_0_choices=('aur-search' 'search' 'help' 'help-commands-unsafe' 'help-updates' 'help-version' 'version' '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' 'patch-set-add' 'repo-backup' 'repo-check' 'check' 'repo-create-keyring' 'repo-create-mirrorlist' 'repo-daemon' 'daemon' 'repo-rebuild' 'rebuild' 'repo-remove-unknown' 'remove-unknown' 'repo-report' 'report' 'repo-restore' 'repo-sign' 'sign' 'repo-status-update' 'repo-sync' 'sync' 'repo-tree' 'repo-triggers' 'repo-update' 'update' 'service-clean' 'clean' 'repo-clean' 'service-config' 'config' 'repo-config' 'service-config-validate' 'config-validate' 'repo-config-validate' 'service-key-import' 'key-import' 'service-setup' 'init' 'repo-init' 'repo-setup' 'setup' 'service-shell' 'shell' 'user-add' 'user-list' 'user-remove' 'web')
|
||||
_shtab_ahriman_pos_0_choices=('aur-search' 'search' 'help' 'help-commands-unsafe' 'help-updates' 'help-version' 'version' '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' 'patch-set-add' 'repo-backup' 'repo-check' 'check' 'repo-create-keyring' 'repo-create-mirrorlist' 'repo-daemon' 'daemon' 'repo-rebuild' 'rebuild' 'repo-remove-unknown' 'remove-unknown' 'repo-report' 'report' 'repo-restore' 'repo-sign' 'sign' 'repo-status-update' 'repo-sync' 'sync' 'repo-tree' 'repo-triggers' 'repo-update' 'update' 'service-clean' 'clean' 'repo-clean' 'service-config' 'config' 'repo-config' 'service-config-validate' 'config-validate' 'repo-config-validate' 'service-key-import' 'key-import' 'service-setup' 'init' 'repo-init' 'repo-setup' 'setup' 'service-shell' 'shell' 'service-tree-migrate' 'user-add' 'user-list' 'user-remove' 'web')
|
||||
_shtab_ahriman___log_handler_choices=('console' 'syslog' 'journald')
|
||||
_shtab_ahriman_aur_search___sort_by_choices=('description' 'first_submitted' 'id' 'last_modified' 'maintainer' 'name' 'num_votes' 'out_of_date' 'package_base' 'package_base_id' 'popularity' 'repository' 'submitter' 'url' 'url_path' 'version')
|
||||
_shtab_ahriman_search___sort_by_choices=('description' 'first_submitted' 'id' 'last_modified' 'maintainer' 'name' 'num_votes' 'out_of_date' 'package_base' 'package_base_id' 'popularity' 'repository' 'submitter' 'url' 'url_path' 'version')
|
||||
@ -101,19 +102,19 @@ _shtab_ahriman_init___sign_target_choices=('disabled' 'packages' 'repository')
|
||||
_shtab_ahriman_repo_init___sign_target_choices=('disabled' 'packages' 'repository')
|
||||
_shtab_ahriman_repo_setup___sign_target_choices=('disabled' 'packages' 'repository')
|
||||
_shtab_ahriman_setup___sign_target_choices=('disabled' 'packages' 'repository')
|
||||
_shtab_ahriman_user_add__r_choices=('unauthorized' 'read' 'reporter' 'full')
|
||||
_shtab_ahriman_user_add__R_choices=('unauthorized' 'read' 'reporter' 'full')
|
||||
_shtab_ahriman_user_add___role_choices=('unauthorized' 'read' 'reporter' 'full')
|
||||
_shtab_ahriman_user_list__r_choices=('unauthorized' 'read' 'reporter' 'full')
|
||||
_shtab_ahriman_user_list__R_choices=('unauthorized' 'read' 'reporter' 'full')
|
||||
_shtab_ahriman_user_list___role_choices=('unauthorized' 'read' 'reporter' 'full')
|
||||
|
||||
_shtab_ahriman_pos_0_nargs=A...
|
||||
_shtab_ahriman__h_nargs=0
|
||||
_shtab_ahriman___help_nargs=0
|
||||
_shtab_ahriman___force_nargs=0
|
||||
_shtab_ahriman___report_nargs=0
|
||||
_shtab_ahriman___no_report_nargs=0
|
||||
_shtab_ahriman__q_nargs=0
|
||||
_shtab_ahriman___quiet_nargs=0
|
||||
_shtab_ahriman___report_nargs=0
|
||||
_shtab_ahriman___no_report_nargs=0
|
||||
_shtab_ahriman___unsafe_nargs=0
|
||||
_shtab_ahriman__V_nargs=0
|
||||
_shtab_ahriman___version_nargs=0
|
||||
@ -473,6 +474,8 @@ _shtab_ahriman_shell__h_nargs=0
|
||||
_shtab_ahriman_shell___help_nargs=0
|
||||
_shtab_ahriman_shell__v_nargs=0
|
||||
_shtab_ahriman_shell___verbose_nargs=0
|
||||
_shtab_ahriman_service_tree_migrate__h_nargs=0
|
||||
_shtab_ahriman_service_tree_migrate___help_nargs=0
|
||||
_shtab_ahriman_user_add__h_nargs=0
|
||||
_shtab_ahriman_user_add___help_nargs=0
|
||||
_shtab_ahriman_user_list__h_nargs=0
|
||||
|
@ -1,9 +1,9 @@
|
||||
.TH AHRIMAN "1" "2023\-08\-26" "ahriman" "Generated Python Manual"
|
||||
.TH AHRIMAN "1" "2023\-09\-02" "ahriman" "Generated Python Manual"
|
||||
.SH NAME
|
||||
ahriman
|
||||
.SH SYNOPSIS
|
||||
.B ahriman
|
||||
[-h] [-a ARCHITECTURE] [-c CONFIGURATION] [--force] [-l LOCK] [--log-handler {console,syslog,journald}] [--report | --no-report] [-q] [--unsafe] [--wait-timeout WAIT_TIMEOUT] [-V] {aur-search,search,help,help-commands-unsafe,help-updates,help-version,version,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,patch-set-add,repo-backup,repo-check,check,repo-create-keyring,repo-create-mirrorlist,repo-daemon,daemon,repo-rebuild,rebuild,repo-remove-unknown,remove-unknown,repo-report,report,repo-restore,repo-sign,sign,repo-status-update,repo-sync,sync,repo-tree,repo-triggers,repo-update,update,service-clean,clean,repo-clean,service-config,config,repo-config,service-config-validate,config-validate,repo-config-validate,service-key-import,key-import,service-setup,init,repo-init,repo-setup,setup,service-shell,shell,user-add,user-list,user-remove,web} ...
|
||||
[-h] [-a ARCHITECTURE] [-c CONFIGURATION] [--force] [-l LOCK] [--log-handler {console,syslog,journald}] [-q] [--report | --no-report] [-r REPOSITORY] [--unsafe] [--wait-timeout WAIT_TIMEOUT] [-V] {aur-search,search,help,help-commands-unsafe,help-updates,help-version,version,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,patch-set-add,repo-backup,repo-check,check,repo-create-keyring,repo-create-mirrorlist,repo-daemon,daemon,repo-rebuild,rebuild,repo-remove-unknown,remove-unknown,repo-report,report,repo-restore,repo-sign,sign,repo-status-update,repo-sync,sync,repo-tree,repo-triggers,repo-update,update,service-clean,clean,repo-clean,service-config,config,repo-config,service-config-validate,config-validate,repo-config-validate,service-key-import,key-import,service-setup,init,repo-init,repo-setup,setup,service-shell,shell,service-tree-migrate,user-add,user-list,user-remove,web} ...
|
||||
.SH DESCRIPTION
|
||||
ArcH linux ReposItory MANager
|
||||
|
||||
@ -28,13 +28,17 @@ lock file
|
||||
\fB\-\-log\-handler\fR \fI\,{console,syslog,journald}\/\fR
|
||||
explicit log handler specification. If none set, the handler will be guessed from environment
|
||||
|
||||
.TP
|
||||
\fB\-q\fR, \fB\-\-quiet\fR
|
||||
force disable any logging
|
||||
|
||||
.TP
|
||||
\fB\-\-report\fR, \fB\-\-no\-report\fR
|
||||
force enable or disable reporting to web service
|
||||
|
||||
.TP
|
||||
\fB\-q\fR, \fB\-\-quiet\fR
|
||||
force disable any logging
|
||||
\fB\-r\fR \fI\,REPOSITORY\/\fR, \fB\-\-repository\fR \fI\,REPOSITORY\/\fR
|
||||
target repository. For several subcommands it can be used multiple times
|
||||
|
||||
.TP
|
||||
\fB\-\-unsafe\fR
|
||||
@ -157,6 +161,9 @@ initial service configuration
|
||||
\fBahriman\fR \fI\,service\-shell\/\fR
|
||||
invoke python shell
|
||||
.TP
|
||||
\fBahriman\fR \fI\,service\-tree\-migrate\/\fR
|
||||
migrate repository tree
|
||||
.TP
|
||||
\fBahriman\fR \fI\,user\-add\/\fR
|
||||
create or update user
|
||||
.TP
|
||||
@ -691,11 +698,10 @@ PGP key to import from public server
|
||||
key server for key import
|
||||
|
||||
.SH COMMAND \fI\,'ahriman service\-setup'\/\fR
|
||||
usage: ahriman service\-setup [\-h] [\-\-build\-as\-user BUILD_AS_USER] [\-\-build\-command BUILD_COMMAND]
|
||||
[\-\-from\-configuration FROM_CONFIGURATION] [\-\-generate\-salt | \-\-no\-generate\-salt]
|
||||
[\-\-makeflags\-jobs | \-\-no\-makeflags\-jobs] [\-\-mirror MIRROR] [\-\-multilib | \-\-no\-multilib]
|
||||
\-\-packager PACKAGER \-\-repository REPOSITORY [\-\-server SERVER] [\-\-sign\-key SIGN_KEY]
|
||||
[\-\-sign\-target {disabled,packages,repository}] [\-\-web\-port WEB_PORT]
|
||||
usage: ahriman service\-setup [\-h] [\-\-build\-as\-user BUILD_AS_USER] [\-\-from\-configuration FROM_CONFIGURATION]
|
||||
[\-\-generate\-salt | \-\-no\-generate\-salt] [\-\-makeflags\-jobs | \-\-no\-makeflags\-jobs]
|
||||
[\-\-mirror MIRROR] [\-\-multilib | \-\-no\-multilib] \-\-packager PACKAGER [\-\-server SERVER]
|
||||
[\-\-sign\-key SIGN_KEY] [\-\-sign\-target {disabled,packages,repository}] [\-\-web\-port WEB_PORT]
|
||||
[\-\-web\-unix\-socket WEB_UNIX_SOCKET]
|
||||
|
||||
create initial service configuration, requires root
|
||||
@ -705,10 +711,6 @@ create initial service configuration, requires root
|
||||
\fB\-\-build\-as\-user\fR \fI\,BUILD_AS_USER\/\fR
|
||||
force makepkg user to the specific one
|
||||
|
||||
.TP
|
||||
\fB\-\-build\-command\fR \fI\,BUILD_COMMAND\/\fR
|
||||
build command prefix
|
||||
|
||||
.TP
|
||||
\fB\-\-from\-configuration\fR \fI\,FROM_CONFIGURATION\/\fR
|
||||
path to default devtools pacman configuration
|
||||
@ -733,10 +735,6 @@ add or do not multilib repository
|
||||
\fB\-\-packager\fR \fI\,PACKAGER\/\fR
|
||||
packager name and email
|
||||
|
||||
.TP
|
||||
\fB\-\-repository\fR \fI\,REPOSITORY\/\fR
|
||||
repository name
|
||||
|
||||
.TP
|
||||
\fB\-\-server\fR \fI\,SERVER\/\fR
|
||||
server to be used for devtools. If none set, local files will be used
|
||||
@ -766,8 +764,13 @@ drop into python shell
|
||||
\fBcode\fR
|
||||
instead of dropping into shell, just execute the specified code
|
||||
|
||||
.SH COMMAND \fI\,'ahriman service\-tree\-migrate'\/\fR
|
||||
usage: ahriman service\-tree\-migrate [\-h]
|
||||
|
||||
migrate repository tree between versions
|
||||
|
||||
.SH COMMAND \fI\,'ahriman user\-add'\/\fR
|
||||
usage: ahriman user\-add [\-h] [\-\-key KEY] [\-\-packager PACKAGER] [\-p PASSWORD] [\-r {unauthorized,read,reporter,full}]
|
||||
usage: ahriman user\-add [\-h] [\-\-key KEY] [\-\-packager PACKAGER] [\-p PASSWORD] [\-R {unauthorized,read,reporter,full}]
|
||||
username
|
||||
|
||||
update user for web services with the given password and role. In case if password was not entered it will be asked interactively
|
||||
@ -791,11 +794,11 @@ user password. Blank password will be treated as empty password, which is in par
|
||||
authorization type.
|
||||
|
||||
.TP
|
||||
\fB\-r\fR \fI\,{unauthorized,read,reporter,full}\/\fR, \fB\-\-role\fR \fI\,{unauthorized,read,reporter,full}\/\fR
|
||||
\fB\-R\fR \fI\,{unauthorized,read,reporter,full}\/\fR, \fB\-\-role\fR \fI\,{unauthorized,read,reporter,full}\/\fR
|
||||
user access level
|
||||
|
||||
.SH COMMAND \fI\,'ahriman user\-list'\/\fR
|
||||
usage: ahriman user\-list [\-h] [\-e] [\-r {unauthorized,read,reporter,full}] [username]
|
||||
usage: ahriman user\-list [\-h] [\-e] [\-R {unauthorized,read,reporter,full}] [username]
|
||||
|
||||
list users from the user mapping and their roles
|
||||
|
||||
@ -809,7 +812,7 @@ filter users by username
|
||||
return non\-zero exit status if result is empty
|
||||
|
||||
.TP
|
||||
\fB\-r\fR \fI\,{unauthorized,read,reporter,full}\/\fR, \fB\-\-role\fR \fI\,{unauthorized,read,reporter,full}\/\fR
|
||||
\fB\-R\fR \fI\,{unauthorized,read,reporter,full}\/\fR, \fB\-\-role\fR \fI\,{unauthorized,read,reporter,full}\/\fR
|
||||
filter users by role
|
||||
|
||||
.SH COMMAND \fI\,'ahriman user\-remove'\/\fR
|
||||
|
@ -59,6 +59,7 @@ _shtab_ahriman_commands() {
|
||||
"service-key-import:import PGP key from public sources to the repository user"
|
||||
"service-setup:create initial service configuration, requires root"
|
||||
"service-shell:drop into python shell"
|
||||
"service-tree-migrate:migrate repository tree between versions"
|
||||
"setup:create initial service configuration, requires root"
|
||||
"shell:drop into python shell"
|
||||
"sign:(re-)sign packages and repository database according to current settings"
|
||||
@ -82,8 +83,9 @@ _shtab_ahriman_options=(
|
||||
"--force[force run, remove file lock (default\: False)]"
|
||||
{-l,--lock}"[lock file (default\: \/tmp\/ahriman.lock)]:lock:"
|
||||
"--log-handler[explicit log handler specification. If none set, the handler will be guessed from environment (default\: None)]:log_handler:(console syslog journald)"
|
||||
{--report,--no-report}"[force enable or disable reporting to web service (default\: True)]:report:"
|
||||
{-q,--quiet}"[force disable any logging (default\: False)]"
|
||||
{--report,--no-report}"[force enable or disable reporting to web service (default\: True)]:report:"
|
||||
"*"{-r,--repository}"[target repository. For several subcommands it can be used multiple times (default\: None)]:repository:"
|
||||
"--unsafe[allow to run ahriman as non-ahriman user. Some actions might be unavailable (default\: False)]"
|
||||
"--wait-timeout[wait for lock to be free. Negative value will lead to immediate application run even if there is lock file. In case of zero value, the application will wait infinitely (default\: -1)]:wait_timeout:"
|
||||
"(- : *)"{-V,--version}"[show program\'s version number and exit]"
|
||||
@ -169,14 +171,12 @@ _shtab_ahriman_help_version_options=(
|
||||
_shtab_ahriman_init_options=(
|
||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||
"--build-as-user[force makepkg user to the specific one (default\: None)]:build_as_user:"
|
||||
"--build-command[build command prefix (default\: ahriman)]:build_command:"
|
||||
"--from-configuration[path to default devtools pacman configuration (default\: \/usr\/share\/devtools\/pacman.conf.d\/extra.conf)]:from_configuration:"
|
||||
{--generate-salt,--no-generate-salt}"[generate salt for user passwords (default\: False)]:generate_salt:"
|
||||
{--makeflags-jobs,--no-makeflags-jobs}"[append MAKEFLAGS variable with parallelism set to number of cores (default\: True)]:makeflags_jobs:"
|
||||
"--mirror[use the specified explicitly mirror instead of including mirrorlist (default\: None)]:mirror:"
|
||||
{--multilib,--no-multilib}"[add or do not multilib repository (default\: True)]:multilib:"
|
||||
"--packager[packager name and email (default\: None)]:packager:"
|
||||
"--repository[repository name (default\: None)]:repository:"
|
||||
"--server[server to be used for devtools. If none set, local files will be used (default\: None)]:server:"
|
||||
"--sign-key[sign key id (default\: None)]:sign_key:"
|
||||
"*--sign-target[sign options (default\: None)]:sign_target:(disabled packages repository)"
|
||||
@ -340,14 +340,12 @@ _shtab_ahriman_repo_daemon_options=(
|
||||
_shtab_ahriman_repo_init_options=(
|
||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||
"--build-as-user[force makepkg user to the specific one (default\: None)]:build_as_user:"
|
||||
"--build-command[build command prefix (default\: ahriman)]:build_command:"
|
||||
"--from-configuration[path to default devtools pacman configuration (default\: \/usr\/share\/devtools\/pacman.conf.d\/extra.conf)]:from_configuration:"
|
||||
{--generate-salt,--no-generate-salt}"[generate salt for user passwords (default\: False)]:generate_salt:"
|
||||
{--makeflags-jobs,--no-makeflags-jobs}"[append MAKEFLAGS variable with parallelism set to number of cores (default\: True)]:makeflags_jobs:"
|
||||
"--mirror[use the specified explicitly mirror instead of including mirrorlist (default\: None)]:mirror:"
|
||||
{--multilib,--no-multilib}"[add or do not multilib repository (default\: True)]:multilib:"
|
||||
"--packager[packager name and email (default\: None)]:packager:"
|
||||
"--repository[repository name (default\: None)]:repository:"
|
||||
"--server[server to be used for devtools. If none set, local files will be used (default\: None)]:server:"
|
||||
"--sign-key[sign key id (default\: None)]:sign_key:"
|
||||
"*--sign-target[sign options (default\: None)]:sign_target:(disabled packages repository)"
|
||||
@ -384,14 +382,12 @@ _shtab_ahriman_repo_restore_options=(
|
||||
_shtab_ahriman_repo_setup_options=(
|
||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||
"--build-as-user[force makepkg user to the specific one (default\: None)]:build_as_user:"
|
||||
"--build-command[build command prefix (default\: ahriman)]:build_command:"
|
||||
"--from-configuration[path to default devtools pacman configuration (default\: \/usr\/share\/devtools\/pacman.conf.d\/extra.conf)]:from_configuration:"
|
||||
{--generate-salt,--no-generate-salt}"[generate salt for user passwords (default\: False)]:generate_salt:"
|
||||
{--makeflags-jobs,--no-makeflags-jobs}"[append MAKEFLAGS variable with parallelism set to number of cores (default\: True)]:makeflags_jobs:"
|
||||
"--mirror[use the specified explicitly mirror instead of including mirrorlist (default\: None)]:mirror:"
|
||||
{--multilib,--no-multilib}"[add or do not multilib repository (default\: True)]:multilib:"
|
||||
"--packager[packager name and email (default\: None)]:packager:"
|
||||
"--repository[repository name (default\: None)]:repository:"
|
||||
"--server[server to be used for devtools. If none set, local files will be used (default\: None)]:server:"
|
||||
"--sign-key[sign key id (default\: None)]:sign_key:"
|
||||
"*--sign-target[sign options (default\: None)]:sign_target:(disabled packages repository)"
|
||||
@ -478,14 +474,12 @@ _shtab_ahriman_service_key_import_options=(
|
||||
_shtab_ahriman_service_setup_options=(
|
||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||
"--build-as-user[force makepkg user to the specific one (default\: None)]:build_as_user:"
|
||||
"--build-command[build command prefix (default\: ahriman)]:build_command:"
|
||||
"--from-configuration[path to default devtools pacman configuration (default\: \/usr\/share\/devtools\/pacman.conf.d\/extra.conf)]:from_configuration:"
|
||||
{--generate-salt,--no-generate-salt}"[generate salt for user passwords (default\: False)]:generate_salt:"
|
||||
{--makeflags-jobs,--no-makeflags-jobs}"[append MAKEFLAGS variable with parallelism set to number of cores (default\: True)]:makeflags_jobs:"
|
||||
"--mirror[use the specified explicitly mirror instead of including mirrorlist (default\: None)]:mirror:"
|
||||
{--multilib,--no-multilib}"[add or do not multilib repository (default\: True)]:multilib:"
|
||||
"--packager[packager name and email (default\: None)]:packager:"
|
||||
"--repository[repository name (default\: None)]:repository:"
|
||||
"--server[server to be used for devtools. If none set, local files will be used (default\: None)]:server:"
|
||||
"--sign-key[sign key id (default\: None)]:sign_key:"
|
||||
"*--sign-target[sign options (default\: None)]:sign_target:(disabled packages repository)"
|
||||
@ -498,17 +492,19 @@ _shtab_ahriman_service_shell_options=(
|
||||
":instead of dropping into shell, just execute the specified code (default\: None):"
|
||||
)
|
||||
|
||||
_shtab_ahriman_service_tree_migrate_options=(
|
||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||
)
|
||||
|
||||
_shtab_ahriman_setup_options=(
|
||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||
"--build-as-user[force makepkg user to the specific one (default\: None)]:build_as_user:"
|
||||
"--build-command[build command prefix (default\: ahriman)]:build_command:"
|
||||
"--from-configuration[path to default devtools pacman configuration (default\: \/usr\/share\/devtools\/pacman.conf.d\/extra.conf)]:from_configuration:"
|
||||
{--generate-salt,--no-generate-salt}"[generate salt for user passwords (default\: False)]:generate_salt:"
|
||||
{--makeflags-jobs,--no-makeflags-jobs}"[append MAKEFLAGS variable with parallelism set to number of cores (default\: True)]:makeflags_jobs:"
|
||||
"--mirror[use the specified explicitly mirror instead of including mirrorlist (default\: None)]:mirror:"
|
||||
{--multilib,--no-multilib}"[add or do not multilib repository (default\: True)]:multilib:"
|
||||
"--packager[packager name and email (default\: None)]:packager:"
|
||||
"--repository[repository name (default\: None)]:repository:"
|
||||
"--server[server to be used for devtools. If none set, local files will be used (default\: None)]:server:"
|
||||
"--sign-key[sign key id (default\: None)]:sign_key:"
|
||||
"*--sign-target[sign options (default\: None)]:sign_target:(disabled packages repository)"
|
||||
@ -565,14 +561,14 @@ _shtab_ahriman_user_add_options=(
|
||||
"--key[optional PGP key used by this user. The private key must be imported (default\: None)]:key:"
|
||||
"--packager[optional packager id used for build process in form of \`Name Surname \<mail\@example.com\>\` (default\: None)]:packager:"
|
||||
{-p,--password}"[user password. Blank password will be treated as empty password, which is in particular must be used for OAuth2 authorization type. (default\: None)]:password:"
|
||||
{-r,--role}"[user access level (default\: UserAccess.Read)]:role:(unauthorized read reporter full)"
|
||||
{-R,--role}"[user access level (default\: UserAccess.Read)]:role:(unauthorized read reporter full)"
|
||||
":username for web service:"
|
||||
)
|
||||
|
||||
_shtab_ahriman_user_list_options=(
|
||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
|
||||
{-r,--role}"[filter users by role (default\: None)]:role:(unauthorized read reporter full)"
|
||||
{-R,--role}"[filter users by role (default\: None)]:role:(unauthorized read reporter full)"
|
||||
":filter users by username (default\: None):"
|
||||
)
|
||||
|
||||
@ -658,6 +654,7 @@ _shtab_ahriman() {
|
||||
service-key-import) _arguments -C -s $_shtab_ahriman_service_key_import_options ;;
|
||||
service-setup) _arguments -C -s $_shtab_ahriman_service_setup_options ;;
|
||||
service-shell) _arguments -C -s $_shtab_ahriman_service_shell_options ;;
|
||||
service-tree-migrate) _arguments -C -s $_shtab_ahriman_service_tree_migrate_options ;;
|
||||
setup) _arguments -C -s $_shtab_ahriman_setup_options ;;
|
||||
shell) _arguments -C -s $_shtab_ahriman_shell_options ;;
|
||||
sign) _arguments -C -s $_shtab_ahriman_sign_options ;;
|
||||
|
@ -79,9 +79,14 @@ def _parser() -> argparse.ArgumentParser:
|
||||
parser.add_argument("--log-handler", help="explicit log handler specification. If none set, the handler will be "
|
||||
"guessed from environment",
|
||||
type=LogHandler, choices=enum_values(LogHandler))
|
||||
parser.add_argument("-q", "--quiet", help="force disable any logging", action="store_true")
|
||||
parser.add_argument("--report", help="force enable or disable reporting to web service",
|
||||
action=argparse.BooleanOptionalAction, default=True)
|
||||
parser.add_argument("-q", "--quiet", help="force disable any logging", action="store_true")
|
||||
parser.add_argument("-r", "--repository", help="target repository. For several subcommands it can be used "
|
||||
"multiple times", action="append")
|
||||
# special secret argument for systemd unit. The issue is that systemd doesn't allow multiple arguments to template
|
||||
# name. This parameter accepts [[arch]-repo] in order to keep backward compatibility
|
||||
parser.add_argument("--repository-id", help=argparse.SUPPRESS)
|
||||
parser.add_argument("--unsafe", help="allow to run ahriman as non-ahriman user. Some actions might be unavailable",
|
||||
action="store_true")
|
||||
parser.add_argument("--wait-timeout", help="wait for lock to be free. Negative value will lead to "
|
||||
@ -127,6 +132,7 @@ def _parser() -> argparse.ArgumentParser:
|
||||
_set_service_key_import_parser(subparsers)
|
||||
_set_service_setup_parser(subparsers)
|
||||
_set_service_shell_parser(subparsers)
|
||||
_set_service_tree_migrate_parser(subparsers)
|
||||
_set_user_add_parser(subparsers)
|
||||
_set_user_list_parser(subparsers)
|
||||
_set_user_remove_parser(subparsers)
|
||||
@ -155,7 +161,8 @@ def _set_aur_search_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
parser.add_argument("--sort-by", help="sort field by this field. In case if two packages have the same value of "
|
||||
"the specified field, they will be always sorted by name",
|
||||
default="name", choices=sorted(handlers.Search.SORT_FIELDS))
|
||||
parser.set_defaults(handler=handlers.Search, architecture=[""], lock=None, report=False, quiet=True, unsafe=True)
|
||||
parser.set_defaults(handler=handlers.Search, architecture=[""], lock=None, quiet=True, report=False,
|
||||
repository=[""], unsafe=True)
|
||||
return parser
|
||||
|
||||
|
||||
@ -173,8 +180,8 @@ def _set_help_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
description="show help message for application or command and exit",
|
||||
formatter_class=_formatter)
|
||||
parser.add_argument("command", help="show help message for specific command", nargs="?")
|
||||
parser.set_defaults(handler=handlers.Help, architecture=[""], lock=None, report=False, quiet=True, unsafe=True,
|
||||
parser=_parser)
|
||||
parser.set_defaults(handler=handlers.Help, architecture=[""], lock=None, quiet=True, report=False, repository=[""],
|
||||
unsafe=True, parser=_parser)
|
||||
return parser
|
||||
|
||||
|
||||
@ -192,8 +199,8 @@ def _set_help_commands_unsafe_parser(root: SubParserAction) -> argparse.Argument
|
||||
description="list unsafe commands as defined in default args", formatter_class=_formatter)
|
||||
parser.add_argument("command", help="instead of showing commands, just test command line for unsafe subcommand "
|
||||
"and return 0 in case if command is safe and 1 otherwise", nargs="*")
|
||||
parser.set_defaults(handler=handlers.UnsafeCommands, architecture=[""], lock=None, report=False, quiet=True,
|
||||
unsafe=True, parser=_parser)
|
||||
parser.set_defaults(handler=handlers.UnsafeCommands, architecture=[""], lock=None, quiet=True, report=False,
|
||||
repository=[""], unsafe=True, parser=_parser)
|
||||
return parser
|
||||
|
||||
|
||||
@ -211,8 +218,8 @@ def _set_help_updates_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
description="request AUR for current version and compare with current service version",
|
||||
formatter_class=_formatter)
|
||||
parser.add_argument("-e", "--exit-code", help="return non-zero exit code if updates available", action="store_true")
|
||||
parser.set_defaults(handler=handlers.ServiceUpdates, architecture=[""], lock=None, report=False, quiet=True,
|
||||
unsafe=True)
|
||||
parser.set_defaults(handler=handlers.ServiceUpdates, architecture=[""], lock=None, quiet=True, report=False,
|
||||
repository=[""], unsafe=True)
|
||||
return parser
|
||||
|
||||
|
||||
@ -228,7 +235,8 @@ def _set_help_version_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
parser = root.add_parser("help-version", aliases=["version"], help="application version",
|
||||
description="print application and its dependencies versions", formatter_class=_formatter)
|
||||
parser.set_defaults(handler=handlers.Versions, architecture=[""], lock=None, report=False, quiet=True, unsafe=True)
|
||||
parser.set_defaults(handler=handlers.Versions, architecture=[""], lock=None, quiet=True, report=False,
|
||||
repository=[""], unsafe=True)
|
||||
return parser
|
||||
|
||||
|
||||
@ -310,7 +318,7 @@ def _set_package_status_parser(root: SubParserAction) -> argparse.ArgumentParser
|
||||
action=argparse.BooleanOptionalAction, default=False)
|
||||
parser.add_argument("-s", "--status", help="filter packages by status",
|
||||
type=BuildStatusEnum, choices=enum_values(BuildStatusEnum))
|
||||
parser.set_defaults(handler=handlers.Status, lock=None, report=False, quiet=True, unsafe=True)
|
||||
parser.set_defaults(handler=handlers.Status, lock=None, quiet=True, report=False, unsafe=True)
|
||||
return parser
|
||||
|
||||
|
||||
@ -330,7 +338,7 @@ def _set_package_status_remove_parser(root: SubParserAction) -> argparse.Argumen
|
||||
"clears the status page.",
|
||||
formatter_class=_formatter)
|
||||
parser.add_argument("package", help="remove specified packages from status page", nargs="+")
|
||||
parser.set_defaults(handler=handlers.StatusUpdate, action=Action.Remove, lock=None, report=False, quiet=True,
|
||||
parser.set_defaults(handler=handlers.StatusUpdate, action=Action.Remove, lock=None, quiet=True, report=False,
|
||||
unsafe=True)
|
||||
return parser
|
||||
|
||||
@ -352,7 +360,7 @@ def _set_package_status_update_parser(root: SubParserAction) -> argparse.Argumen
|
||||
nargs="*")
|
||||
parser.add_argument("-s", "--status", help="new package build status",
|
||||
type=BuildStatusEnum, choices=enum_values(BuildStatusEnum), default=BuildStatusEnum.Success)
|
||||
parser.set_defaults(handler=handlers.StatusUpdate, action=Action.Update, lock=None, report=False, quiet=True,
|
||||
parser.set_defaults(handler=handlers.StatusUpdate, action=Action.Update, lock=None, quiet=True, report=False,
|
||||
unsafe=True)
|
||||
return parser
|
||||
|
||||
@ -379,7 +387,8 @@ def _set_patch_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"it must end with ()")
|
||||
parser.add_argument("patch", help="path to file which contains function or variable value. If not set, "
|
||||
"the value will be read from stdin", type=Path, nargs="?")
|
||||
parser.set_defaults(handler=handlers.Patch, action=Action.Update, architecture=[""], lock=None, report=False)
|
||||
parser.set_defaults(handler=handlers.Patch, action=Action.Update, architecture=[""], lock=None, report=False,
|
||||
repository=[""])
|
||||
return parser
|
||||
|
||||
|
||||
@ -400,7 +409,7 @@ def _set_patch_list_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
parser.add_argument("-v", "--variable", help="if set, show only patches for specified PKGBUILD variables",
|
||||
action="append")
|
||||
parser.set_defaults(handler=handlers.Patch, action=Action.List, architecture=[""], lock=None, report=False,
|
||||
unsafe=True)
|
||||
repository=[""], unsafe=True)
|
||||
return parser
|
||||
|
||||
|
||||
@ -421,7 +430,8 @@ def _set_patch_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"to remove only specified PKGBUILD variables. In case if not set, "
|
||||
"it will remove all patches related to the package",
|
||||
action="append")
|
||||
parser.set_defaults(handler=handlers.Patch, action=Action.Remove, architecture=[""], lock=None, report=False)
|
||||
parser.set_defaults(handler=handlers.Patch, action=Action.Remove, architecture=[""], lock=None, report=False,
|
||||
repository=[""])
|
||||
return parser
|
||||
|
||||
|
||||
@ -446,7 +456,7 @@ def _set_patch_set_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
parser.add_argument("-t", "--track", help="files which has to be tracked", action="append",
|
||||
default=["*.diff", "*.patch"])
|
||||
parser.set_defaults(handler=handlers.Patch, action=Action.Update, architecture=[""], lock=None, report=False,
|
||||
variable=None)
|
||||
repository=[""], variable=None)
|
||||
return parser
|
||||
|
||||
|
||||
@ -463,7 +473,8 @@ def _set_repo_backup_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
parser = root.add_parser("repo-backup", help="backup repository data",
|
||||
description="backup repository settings and database", formatter_class=_formatter)
|
||||
parser.add_argument("path", help="path of the output archive", type=Path)
|
||||
parser.set_defaults(handler=handlers.Backup, architecture=[""], lock=None, report=False, unsafe=True)
|
||||
parser.set_defaults(handler=handlers.Backup, architecture=[""], lock=None, report=False, repository=[""],
|
||||
unsafe=True)
|
||||
return parser
|
||||
|
||||
|
||||
@ -642,7 +653,8 @@ def _set_repo_restore_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
description="restore settings and database", formatter_class=_formatter)
|
||||
parser.add_argument("path", help="path of the input archive", type=Path)
|
||||
parser.add_argument("-o", "--output", help="root path of the extracted files", type=Path, default=Path("/"))
|
||||
parser.set_defaults(handler=handlers.Restore, architecture=[""], lock=None, report=False, unsafe=True)
|
||||
parser.set_defaults(handler=handlers.Restore, architecture=[""], lock=None, report=False, repository=[""],
|
||||
unsafe=True)
|
||||
return parser
|
||||
|
||||
|
||||
@ -679,8 +691,8 @@ def _set_repo_status_update_parser(root: SubParserAction) -> argparse.ArgumentPa
|
||||
description="update repository status on the status page", formatter_class=_formatter)
|
||||
parser.add_argument("-s", "--status", help="new status",
|
||||
type=BuildStatusEnum, choices=enum_values(BuildStatusEnum), default=BuildStatusEnum.Success)
|
||||
parser.set_defaults(handler=handlers.StatusUpdate, action=Action.Update, lock=None, report=False, package=[],
|
||||
quiet=True, unsafe=True)
|
||||
parser.set_defaults(handler=handlers.StatusUpdate, action=Action.Update, lock=None, package=[], quiet=True,
|
||||
report=False, unsafe=True)
|
||||
return parser
|
||||
|
||||
|
||||
@ -717,7 +729,7 @@ def _set_repo_tree_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
formatter_class=_formatter)
|
||||
parser.add_argument("-p", "--partitions", help="also divide packages by independent partitions",
|
||||
type=int, default=1)
|
||||
parser.set_defaults(handler=handlers.Structure, lock=None, report=False, quiet=True, unsafe=True)
|
||||
parser.set_defaults(handler=handlers.Structure, lock=None, quiet=True, report=False, unsafe=True)
|
||||
return parser
|
||||
|
||||
|
||||
@ -820,7 +832,7 @@ def _set_service_config_parser(root: SubParserAction) -> argparse.ArgumentParser
|
||||
formatter_class=_formatter)
|
||||
parser.add_argument("--secure", help="hide passwords and secrets from output",
|
||||
action=argparse.BooleanOptionalAction, default=True)
|
||||
parser.set_defaults(handler=handlers.Dump, lock=None, report=False, quiet=True, unsafe=True)
|
||||
parser.set_defaults(handler=handlers.Dump, lock=None, quiet=True, report=False, unsafe=True)
|
||||
return parser
|
||||
|
||||
|
||||
@ -840,7 +852,7 @@ def _set_service_config_validate_parser(root: SubParserAction) -> argparse.Argum
|
||||
formatter_class=_formatter)
|
||||
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if configuration is invalid",
|
||||
action="store_true")
|
||||
parser.set_defaults(handler=handlers.Validate, lock=None, report=False, quiet=True, unsafe=True)
|
||||
parser.set_defaults(handler=handlers.Validate, lock=None, quiet=True, report=False, unsafe=True)
|
||||
return parser
|
||||
|
||||
|
||||
@ -863,7 +875,7 @@ def _set_service_key_import_parser(root: SubParserAction) -> argparse.ArgumentPa
|
||||
formatter_class=_formatter)
|
||||
parser.add_argument("--key-server", help="key server for key import", default="keyserver.ubuntu.com")
|
||||
parser.add_argument("key", help="PGP key to import from public server")
|
||||
parser.set_defaults(handler=handlers.KeyImport, architecture=[""], lock=None, report=False)
|
||||
parser.set_defaults(handler=handlers.KeyImport, architecture=[""], lock=None, report=False, repository=[""])
|
||||
return parser
|
||||
|
||||
|
||||
@ -883,7 +895,6 @@ def _set_service_setup_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
epilog="Create _minimal_ configuration for the service according to provided options.",
|
||||
formatter_class=_formatter)
|
||||
parser.add_argument("--build-as-user", help="force makepkg user to the specific one")
|
||||
parser.add_argument("--build-command", help="build command prefix", default="ahriman")
|
||||
parser.add_argument("--from-configuration", help="path to default devtools pacman configuration",
|
||||
type=Path, default=Path("/usr") / "share" / "devtools" / "pacman.conf.d" / "extra.conf")
|
||||
parser.add_argument("--generate-salt", help="generate salt for user passwords",
|
||||
@ -894,14 +905,13 @@ def _set_service_setup_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
parser.add_argument("--multilib", help="add or do not multilib repository",
|
||||
action=argparse.BooleanOptionalAction, default=True)
|
||||
parser.add_argument("--packager", help="packager name and email", required=True)
|
||||
parser.add_argument("--repository", help="repository name", required=True)
|
||||
parser.add_argument("--server", help="server to be used for devtools. If none set, local files will be used")
|
||||
parser.add_argument("--sign-key", help="sign key id")
|
||||
parser.add_argument("--sign-target", help="sign options", action="append",
|
||||
type=SignSettings.from_option, choices=enum_values(SignSettings))
|
||||
parser.add_argument("--web-port", help="port of the web service", type=int)
|
||||
parser.add_argument("--web-unix-socket", help="path to unix socket used for interprocess communications", type=Path)
|
||||
parser.set_defaults(handler=handlers.Setup, lock=None, report=False, quiet=True, unsafe=True)
|
||||
parser.set_defaults(handler=handlers.Setup, lock=None, quiet=True, report=False, unsafe=True)
|
||||
return parser
|
||||
|
||||
|
||||
@ -923,6 +933,22 @@ def _set_service_shell_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
return parser
|
||||
|
||||
|
||||
def _set_service_tree_migrate_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for tree migration subcommand
|
||||
|
||||
Args:
|
||||
root(SubParserAction): subparsers for the commands
|
||||
|
||||
Returns:
|
||||
argparse.ArgumentParser: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("service-tree-migrate", help="migrate repository tree",
|
||||
description="migrate repository tree between versions", formatter_class=_formatter)
|
||||
parser.set_defaults(handler=handlers.TreeMigrate, lock=None, quiet=True, report=False)
|
||||
return parser
|
||||
|
||||
|
||||
def _set_user_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for create user subcommand
|
||||
@ -943,10 +969,10 @@ def _set_user_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"`Name Surname <mail@example.com>`")
|
||||
parser.add_argument("-p", "--password", help="user password. Blank password will be treated as empty password, "
|
||||
"which is in particular must be used for OAuth2 authorization type.")
|
||||
parser.add_argument("-r", "--role", help="user access level",
|
||||
parser.add_argument("-R", "--role", help="user access level",
|
||||
type=UserAccess, choices=enum_values(UserAccess), default=UserAccess.Read)
|
||||
parser.set_defaults(handler=handlers.Users, action=Action.Update, architecture=[""], lock=None, report=False,
|
||||
quiet=True)
|
||||
parser.set_defaults(handler=handlers.Users, action=Action.Update, architecture=[""], lock=None, quiet=True,
|
||||
report=False, repository=[""])
|
||||
return parser
|
||||
|
||||
|
||||
@ -965,9 +991,9 @@ def _set_user_list_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
formatter_class=_formatter)
|
||||
parser.add_argument("username", help="filter users by username", nargs="?")
|
||||
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
|
||||
parser.add_argument("-r", "--role", help="filter users by role", type=UserAccess, choices=enum_values(UserAccess))
|
||||
parser.set_defaults(handler=handlers.Users, action=Action.List, architecture=[""], lock=None, report=False,
|
||||
quiet=True, unsafe=True)
|
||||
parser.add_argument("-R", "--role", help="filter users by role", type=UserAccess, choices=enum_values(UserAccess))
|
||||
parser.set_defaults(handler=handlers.Users, action=Action.List, architecture=[""], lock=None, quiet=True,
|
||||
report=False, repository=[""], unsafe=True)
|
||||
return parser
|
||||
|
||||
|
||||
@ -985,8 +1011,8 @@ def _set_user_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
description="remove user from the user mapping and update the configuration",
|
||||
formatter_class=_formatter)
|
||||
parser.add_argument("username", help="username for web service")
|
||||
parser.set_defaults(handler=handlers.Users, action=Action.Remove, architecture=[""], lock=None, report=False,
|
||||
quiet=True)
|
||||
parser.set_defaults(handler=handlers.Users, action=Action.Remove, architecture=[""], lock=None, quiet=True,
|
||||
report=False, repository=[""])
|
||||
return parser
|
||||
|
||||
|
||||
|
@ -37,9 +37,10 @@ class Application(ApplicationPackages, ApplicationRepository):
|
||||
|
||||
>>> from ahriman.core.configuration import Configuration
|
||||
>>> from ahriman.models.package_source import PackageSource
|
||||
>>> from ahriman.models.repository_id import RepositoryId
|
||||
>>>
|
||||
>>> configuration = Configuration()
|
||||
>>> application = Application("x86_64", configuration, report=True)
|
||||
>>> application = Application(RepositoryId("x86_64", "x86_64"), configuration, report=True)
|
||||
>>> # add packages to build queue
|
||||
>>> application.add(["ahriman"], PackageSource.AUR)
|
||||
>>>
|
||||
|
@ -22,6 +22,7 @@ from ahriman.core.database import SQLite
|
||||
from ahriman.core.log import LazyLogging
|
||||
from ahriman.core.repository import Repository
|
||||
from ahriman.models.pacman_synchronization import PacmanSynchronization
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class ApplicationProperties(LazyLogging):
|
||||
@ -29,26 +30,36 @@ class ApplicationProperties(LazyLogging):
|
||||
application base properties class
|
||||
|
||||
Attributes:
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
database(SQLite): database instance
|
||||
repository(Repository): repository instance
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
"""
|
||||
|
||||
def __init__(self, architecture: str, configuration: Configuration, *, report: bool,
|
||||
def __init__(self, repository_id: RepositoryId, configuration: Configuration, *, report: bool,
|
||||
refresh_pacman_database: PacmanSynchronization = PacmanSynchronization.Disabled) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
report(bool): force enable or disable reporting
|
||||
refresh_pacman_database(PacmanSynchronization, optional): pacman database synchronization level
|
||||
(Default value = PacmanSynchronization.Disabled)
|
||||
"""
|
||||
self.configuration = configuration
|
||||
self.architecture = architecture
|
||||
self.repository_id = repository_id
|
||||
self.database = SQLite.load(configuration)
|
||||
self.repository = Repository.load(architecture, configuration, self.database, report=report,
|
||||
self.repository = Repository.load(repository_id, configuration, self.database, report=report,
|
||||
refresh_pacman_database=refresh_pacman_database)
|
||||
|
||||
@property
|
||||
def architecture(self) -> str:
|
||||
"""
|
||||
repository architecture for backward compatibility
|
||||
|
||||
Returns:
|
||||
str: repository architecture
|
||||
"""
|
||||
return self.repository_id.architecture
|
||||
|
@ -39,6 +39,7 @@ 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.structure import Structure
|
||||
from ahriman.application.handlers.tree_migrate import TreeMigrate
|
||||
from ahriman.application.handlers.triggers import Triggers
|
||||
from ahriman.application.handlers.unsafe_commands import UnsafeCommands
|
||||
from ahriman.application.handlers.update import Update
|
||||
|
@ -23,6 +23,7 @@ from ahriman.application.application import Application
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.models.packagers import Packagers
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class Add(Handler):
|
||||
@ -31,17 +32,18 @@ class Add(Handler):
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
|
||||
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
|
||||
report: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
report(bool): force enable or disable reporting
|
||||
"""
|
||||
application = Application(architecture, configuration, report=report, refresh_pacman_database=args.refresh)
|
||||
application = Application(repository_id, configuration, report=report, refresh_pacman_database=args.refresh)
|
||||
application.on_start()
|
||||
application.add(args.package, args.source, args.username)
|
||||
if not args.now:
|
||||
|
@ -26,6 +26,7 @@ from tarfile import TarFile
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database import SQLite
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class Backup(Handler):
|
||||
@ -33,16 +34,17 @@ class Backup(Handler):
|
||||
backup packages handler
|
||||
"""
|
||||
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||
ALLOW_MULTI_ARCHITECTURE_RUN = False # system-wide action
|
||||
|
||||
@classmethod
|
||||
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
|
||||
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
|
||||
report: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
report(bool): force enable or disable reporting
|
||||
"""
|
||||
|
@ -22,6 +22,7 @@ import argparse
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class Clean(Handler):
|
||||
@ -30,17 +31,18 @@ class Clean(Handler):
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
|
||||
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
|
||||
report: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
report(bool): force enable or disable reporting
|
||||
"""
|
||||
application = Application(architecture, configuration, report=report)
|
||||
application = Application(repository_id, configuration, report=report)
|
||||
application.on_start()
|
||||
application.clean(cache=args.cache, chroot=args.chroot, manual=args.manual, packages=args.packages,
|
||||
pacman=args.pacman)
|
||||
|
@ -22,6 +22,7 @@ import threading
|
||||
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class Daemon(Handler):
|
||||
@ -30,19 +31,20 @@ class Daemon(Handler):
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
|
||||
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
|
||||
report: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
report(bool): force enable or disable reporting
|
||||
"""
|
||||
from ahriman.application.handlers import Update
|
||||
Update.run(args, architecture, configuration, report=report)
|
||||
timer = threading.Timer(args.interval, Daemon.run, args=[args, architecture, configuration],
|
||||
Update.run(args, repository_id, configuration, report=report)
|
||||
timer = threading.Timer(args.interval, Daemon.run, args=[args, repository_id, configuration],
|
||||
kwargs={"report": report})
|
||||
timer.start()
|
||||
timer.join()
|
||||
|
@ -22,6 +22,7 @@ import argparse
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.formatters import ConfigurationPathsPrinter, ConfigurationPrinter, StringPrinter
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class Dump(Handler):
|
||||
@ -29,16 +30,17 @@ class Dump(Handler):
|
||||
dump configuration handler
|
||||
"""
|
||||
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False
|
||||
ALLOW_MULTI_ARCHITECTURE_RUN = False # conflicting io
|
||||
|
||||
@classmethod
|
||||
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
|
||||
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
|
||||
report: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
report(bool): force enable or disable reporting
|
||||
"""
|
||||
|
@ -25,7 +25,8 @@ from multiprocessing import Pool
|
||||
from ahriman.application.lock import Lock
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.exceptions import ExitCode, MissingArchitectureError, MultipleArchitecturesError
|
||||
from ahriman.core.log import Log
|
||||
from ahriman.core.log.log_loader import LogLoader
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
from ahriman.models.repository_paths import RepositoryPaths
|
||||
|
||||
|
||||
@ -34,7 +35,6 @@ class Handler:
|
||||
base handler class for command callbacks
|
||||
|
||||
Attributes:
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN(bool): (class attribute) allow defining architecture from existing repositories
|
||||
ALLOW_MULTI_ARCHITECTURE_RUN(bool): (class attribute) allow running with multiple architectures
|
||||
|
||||
Examples:
|
||||
@ -46,60 +46,28 @@ class Handler:
|
||||
>>> Add.execute(args)
|
||||
"""
|
||||
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = True
|
||||
ALLOW_MULTI_ARCHITECTURE_RUN = True
|
||||
|
||||
@classmethod
|
||||
def architectures_extract(cls, args: argparse.Namespace) -> list[str]:
|
||||
"""
|
||||
get known architectures
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
|
||||
Returns:
|
||||
list[str]: list of architectures for which tree is created
|
||||
|
||||
Raises:
|
||||
MissingArchitectureError: if no architecture set and automatic detection is not allowed or failed
|
||||
"""
|
||||
if not cls.ALLOW_AUTO_ARCHITECTURE_RUN and args.architecture is None:
|
||||
# for some parsers (e.g. config) we need to run with specific architecture
|
||||
# for those cases architecture must be set explicitly
|
||||
raise MissingArchitectureError(args.command)
|
||||
if args.architecture: # architecture is specified explicitly
|
||||
return sorted(set(args.architecture))
|
||||
|
||||
configuration = Configuration()
|
||||
configuration.load(args.configuration)
|
||||
# wtf???
|
||||
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
|
||||
raise MissingArchitectureError(args.command)
|
||||
return sorted(architectures)
|
||||
|
||||
@classmethod
|
||||
def call(cls, args: argparse.Namespace, architecture: str) -> bool:
|
||||
def call(cls, args: argparse.Namespace, repository_id: RepositoryId) -> bool:
|
||||
"""
|
||||
additional function to wrap all calls for multiprocessing library
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
|
||||
Returns:
|
||||
bool: True on success, False otherwise
|
||||
"""
|
||||
try:
|
||||
configuration = Configuration.from_path(args.configuration, architecture)
|
||||
configuration = Configuration.from_path(args.configuration, repository_id)
|
||||
|
||||
log_handler = Log.handler(args.log_handler)
|
||||
Log.load(configuration, log_handler, quiet=args.quiet, report=args.report)
|
||||
log_handler = LogLoader.handler(args.log_handler)
|
||||
LogLoader.load(configuration, log_handler, quiet=args.quiet, report=args.report)
|
||||
|
||||
with Lock(args, architecture, configuration):
|
||||
cls.run(args, architecture, configuration, report=args.report)
|
||||
with Lock(args, repository_id, configuration):
|
||||
cls.run(args, repository_id, configuration, report=args.report)
|
||||
|
||||
return True
|
||||
except ExitCode:
|
||||
@ -123,28 +91,82 @@ class Handler:
|
||||
Raises:
|
||||
MultipleArchitecturesError: if more than one architecture supplied and no multi architecture supported
|
||||
"""
|
||||
architectures = cls.architectures_extract(args)
|
||||
repositories = cls.repositories_extract(args)
|
||||
|
||||
# actually we do not have to spawn another process if it is single-process application, do we?
|
||||
if len(architectures) > 1:
|
||||
if len(repositories) > 1:
|
||||
if not cls.ALLOW_MULTI_ARCHITECTURE_RUN:
|
||||
raise MultipleArchitecturesError(args.command)
|
||||
raise MultipleArchitecturesError(args.command, repositories)
|
||||
|
||||
with Pool(len(architectures)) as pool:
|
||||
result = pool.starmap(cls.call, [(args, architecture) for architecture in architectures])
|
||||
with Pool(len(repositories)) as pool:
|
||||
result = pool.starmap(cls.call, [(args, repository_id) for repository_id in repositories])
|
||||
else:
|
||||
result = [cls.call(args, architectures.pop())]
|
||||
result = [cls.call(args, repositories.pop())]
|
||||
|
||||
return 0 if all(result) else 1
|
||||
|
||||
@classmethod
|
||||
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
|
||||
def repositories_extract(cls, args: argparse.Namespace) -> list[RepositoryId]:
|
||||
"""
|
||||
get known architectures
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
|
||||
Returns:
|
||||
list[RepositoryId]: list of repository names and architectures for which tree is created
|
||||
|
||||
Raises:
|
||||
MissingArchitectureError: if no architecture set and automatic detection is not allowed or failed
|
||||
"""
|
||||
configuration = Configuration()
|
||||
configuration.load(args.configuration)
|
||||
# pylint, wtf???
|
||||
root = configuration.getpath("repository", "root") # pylint: disable=assignment-from-no-return
|
||||
|
||||
# preparse systemd repository-id argument
|
||||
# we are using unescaped values, so / is not allowed here, because it is impossible to separate if from dashes
|
||||
if args.repository_id is not None:
|
||||
# repository parts is optional for backward compatibility
|
||||
architecture, *repository_parts = args.repository_id.split("/")
|
||||
args.architecture = [architecture]
|
||||
if repository_parts:
|
||||
args.repository = ["-".join(repository_parts)] # replace slash with dash
|
||||
|
||||
# extract repository names first
|
||||
names = args.repository
|
||||
if names is None: # try to read file system first
|
||||
names = RepositoryPaths.known_repositories(root)
|
||||
if not names: # try to read configuration now
|
||||
names = [configuration.get("repository", "name")]
|
||||
|
||||
# extract architecture names
|
||||
if (architectures := args.architecture) is not None:
|
||||
repositories = set(
|
||||
RepositoryId(architecture, name)
|
||||
for name in names
|
||||
for architecture in architectures
|
||||
)
|
||||
else: # try to read from file system
|
||||
repositories = set(
|
||||
RepositoryId(architecture, name)
|
||||
for name in names
|
||||
for architecture in RepositoryPaths.known_architectures(root, name)
|
||||
)
|
||||
|
||||
if not repositories:
|
||||
raise MissingArchitectureError(args.command)
|
||||
return sorted(repositories)
|
||||
|
||||
@classmethod
|
||||
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
|
||||
report: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
report(bool): force enable or disable reporting
|
||||
|
||||
|
@ -21,6 +21,7 @@ import argparse
|
||||
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class Help(Handler):
|
||||
@ -28,16 +29,17 @@ class Help(Handler):
|
||||
help handler
|
||||
"""
|
||||
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||
ALLOW_MULTI_ARCHITECTURE_RUN = False # system-wide action
|
||||
|
||||
@classmethod
|
||||
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
|
||||
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
|
||||
report: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
report(bool): force enable or disable reporting
|
||||
"""
|
||||
|
@ -22,6 +22,7 @@ import argparse
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class KeyImport(Handler):
|
||||
@ -29,18 +30,19 @@ class KeyImport(Handler):
|
||||
key import packages handler
|
||||
"""
|
||||
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||
ALLOW_MULTI_ARCHITECTURE_RUN = False # system-wide action
|
||||
|
||||
@classmethod
|
||||
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
|
||||
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
|
||||
report: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
report(bool): force enable or disable reporting
|
||||
"""
|
||||
application = Application(architecture, configuration, report=report)
|
||||
application = Application(repository_id, configuration, report=report)
|
||||
application.repository.sign.key_import(args.key_server, args.key)
|
||||
|
@ -30,6 +30,7 @@ from ahriman.core.formatters import PatchPrinter
|
||||
from ahriman.models.action import Action
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class Patch(Handler):
|
||||
@ -37,18 +38,21 @@ class Patch(Handler):
|
||||
patch control handler
|
||||
"""
|
||||
|
||||
ALLOW_MULTI_ARCHITECTURE_RUN = False # system-wide action
|
||||
|
||||
@classmethod
|
||||
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
|
||||
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
|
||||
report: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
report(bool): force enable or disable reporting
|
||||
"""
|
||||
application = Application(architecture, configuration, report=report)
|
||||
application = Application(repository_id, configuration, report=report)
|
||||
application.on_start()
|
||||
|
||||
match args.action:
|
||||
@ -56,7 +60,7 @@ class Patch(Handler):
|
||||
patch = Patch.patch_create_from_function(args.variable, args.patch)
|
||||
Patch.patch_set_create(application, args.package, patch)
|
||||
case Action.Update:
|
||||
package_base, patch = Patch.patch_create_from_diff(args.package, architecture, args.track)
|
||||
package_base, patch = Patch.patch_create_from_diff(args.package, repository_id.architecture, args.track)
|
||||
Patch.patch_set_create(application, package_base, patch)
|
||||
case Action.List:
|
||||
Patch.patch_set_list(application, args.package, args.variable, args.exit_code)
|
||||
@ -114,7 +118,7 @@ class Patch(Handler):
|
||||
application.database.patches_insert(package_base, patch)
|
||||
|
||||
@staticmethod
|
||||
def patch_set_list(application: Application, package_base: str | None, variables: list[str],
|
||||
def patch_set_list(application: Application, package_base: str | None, variables: list[str] | None,
|
||||
exit_code: bool) -> None:
|
||||
"""
|
||||
list patches available for the package base
|
||||
@ -122,7 +126,7 @@ class Patch(Handler):
|
||||
Args:
|
||||
application(Application): application instance
|
||||
package_base(str | None): package base
|
||||
variables(list[str]): extract patches only for specified PKGBUILD variables
|
||||
variables(list[str] | None): extract patches only for specified PKGBUILD variables
|
||||
exit_code(bool): exit with error on empty search result
|
||||
"""
|
||||
patches = application.database.patches_list(package_base, variables)
|
||||
@ -132,13 +136,13 @@ class Patch(Handler):
|
||||
PatchPrinter(base, patch).print(verbose=True, separator=" = ")
|
||||
|
||||
@staticmethod
|
||||
def patch_set_remove(application: Application, package_base: str, variables: list[str]) -> None:
|
||||
def patch_set_remove(application: Application, package_base: str, variables: list[str] | None) -> None:
|
||||
"""
|
||||
remove patch set for the package base
|
||||
|
||||
Args:
|
||||
application(Application): application instance
|
||||
package_base(str): package base
|
||||
variables(list[str]): remove patches only for specified PKGBUILD variables
|
||||
variables(list[str] | None): remove patches only for specified PKGBUILD variables
|
||||
"""
|
||||
application.database.patches_remove(package_base, variables)
|
||||
|
@ -24,6 +24,7 @@ from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.models.build_status import BuildStatusEnum
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class Rebuild(Handler):
|
||||
@ -32,21 +33,22 @@ class Rebuild(Handler):
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
|
||||
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
|
||||
report: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
report(bool): force enable or disable reporting
|
||||
"""
|
||||
application = Application(architecture, configuration, report=report)
|
||||
application = Application(repository_id, configuration, report=report)
|
||||
application.on_start()
|
||||
|
||||
packages = Rebuild.extract_packages(application, args.status, from_database=args.from_database)
|
||||
updates = application.repository.packages_depend_on(packages, args.depends_on or None)
|
||||
updates = application.repository.packages_depend_on(packages, args.depends_on)
|
||||
|
||||
Rebuild.check_if_empty(args.exit_code, not updates)
|
||||
if args.dry_run:
|
||||
|
@ -22,6 +22,7 @@ import argparse
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class Remove(Handler):
|
||||
@ -30,16 +31,17 @@ class Remove(Handler):
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
|
||||
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
|
||||
report: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
report(bool): force enable or disable reporting
|
||||
"""
|
||||
application = Application(architecture, configuration, report=report)
|
||||
application = Application(repository_id, configuration, report=report)
|
||||
application.on_start()
|
||||
application.remove(args.package)
|
||||
|
@ -23,6 +23,7 @@ from ahriman.application.application import Application
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.formatters import StringPrinter
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class RemoveUnknown(Handler):
|
||||
@ -31,17 +32,18 @@ class RemoveUnknown(Handler):
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
|
||||
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
|
||||
report: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
report(bool): force enable or disable reporting
|
||||
"""
|
||||
application = Application(architecture, configuration, report=report)
|
||||
application = Application(repository_id, configuration, report=report)
|
||||
application.on_start()
|
||||
unknown_packages = application.unknown()
|
||||
|
||||
|
@ -23,6 +23,7 @@ from tarfile import TarFile
|
||||
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class Restore(Handler):
|
||||
@ -30,16 +31,17 @@ class Restore(Handler):
|
||||
restore packages handler
|
||||
"""
|
||||
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||
ALLOW_MULTI_ARCHITECTURE_RUN = False # system-wide action
|
||||
|
||||
@classmethod
|
||||
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
|
||||
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
|
||||
report: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
report(bool): force enable or disable reporting
|
||||
"""
|
||||
|
@ -29,6 +29,7 @@ from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.exceptions import OptionError
|
||||
from ahriman.core.formatters import AurPrinter
|
||||
from ahriman.models.aur_package import AURPackage
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class Search(Handler):
|
||||
@ -39,7 +40,7 @@ class Search(Handler):
|
||||
SORT_FIELDS(set[str]): (class attribute) allowed fields to sort the package list
|
||||
"""
|
||||
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||
ALLOW_MULTI_ARCHITECTURE_RUN = False # system-wide action
|
||||
SORT_FIELDS = {
|
||||
field.name
|
||||
for field in fields(AURPackage)
|
||||
@ -47,17 +48,18 @@ class Search(Handler):
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
|
||||
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
|
||||
report: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
report(bool): force enable or disable reporting
|
||||
"""
|
||||
application = Application(architecture, configuration, report=report)
|
||||
application = Application(repository_id, configuration, report=report)
|
||||
|
||||
official_packages_list = Official.multisearch(*args.search, pacman=application.repository.pacman)
|
||||
aur_packages_list = AUR.multisearch(*args.search, pacman=application.repository.pacman)
|
||||
|
@ -25,6 +25,7 @@ from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.formatters import UpdatePrinter
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class ServiceUpdates(Handler):
|
||||
@ -32,20 +33,21 @@ class ServiceUpdates(Handler):
|
||||
service updates handler
|
||||
"""
|
||||
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||
ALLOW_MULTI_ARCHITECTURE_RUN = False # system-wide action
|
||||
|
||||
@classmethod
|
||||
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
|
||||
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
|
||||
report: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
report(bool): force enable or disable reporting
|
||||
"""
|
||||
application = Application(architecture, configuration, report=report)
|
||||
application = Application(repository_id, configuration, report=report)
|
||||
|
||||
remote = Package.from_aur("ahriman", application.repository.pacman, None)
|
||||
_, release = remote.version.rsplit("-", 1) # we don't store pkgrel locally, so we just append it
|
||||
|
@ -25,6 +25,8 @@ from pwd import getpwuid
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.exceptions import MissingArchitectureError
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
from ahriman.models.repository_paths import RepositoryPaths
|
||||
from ahriman.models.user import User
|
||||
|
||||
@ -39,88 +41,92 @@ class Setup(Handler):
|
||||
SUDOERS_DIR_PATH(Path): (class attribute) path to sudoers.d includes directory
|
||||
"""
|
||||
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False
|
||||
ALLOW_MULTI_ARCHITECTURE_RUN = False # conflicting io
|
||||
|
||||
ARCHBUILD_COMMAND_PATH = Path("/usr") / "bin" / "archbuild"
|
||||
MIRRORLIST_PATH = Path("/etc") / "pacman.d" / "mirrorlist"
|
||||
SUDOERS_DIR_PATH = Path("/etc") / "sudoers.d"
|
||||
|
||||
@classmethod
|
||||
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
|
||||
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
|
||||
report: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
report(bool): force enable or disable reporting
|
||||
"""
|
||||
Setup.configuration_create_ahriman(args, architecture, args.repository, configuration)
|
||||
# special check for args to avoid auto definition for setup command
|
||||
if args.architecture is None or args.repository is None:
|
||||
raise MissingArchitectureError(args.command)
|
||||
|
||||
Setup.configuration_create_ahriman(args, repository_id, configuration)
|
||||
configuration.reload()
|
||||
|
||||
application = Application(architecture, configuration, report=report)
|
||||
application = Application(repository_id, configuration, report=report)
|
||||
|
||||
Setup.configuration_create_makepkg(args.packager, args.makeflags_jobs, application.repository.paths)
|
||||
Setup.executable_create(application.repository.paths, args.build_command, architecture)
|
||||
Setup.executable_create(application.repository.paths, repository_id)
|
||||
repository_server = f"file://{application.repository.paths.repository}" if args.server is None else args.server
|
||||
Setup.configuration_create_devtools(args.build_command, architecture, args.from_configuration, args.mirror,
|
||||
args.multilib, args.repository, repository_server)
|
||||
Setup.configuration_create_sudo(application.repository.paths, args.build_command, architecture)
|
||||
Setup.configuration_create_devtools(
|
||||
repository_id, args.from_configuration, args.mirror, args.multilib, repository_server)
|
||||
Setup.configuration_create_sudo(application.repository.paths, repository_id)
|
||||
|
||||
application.repository.repo.init()
|
||||
# lazy database sync
|
||||
application.repository.pacman.handle # pylint: disable=pointless-statement
|
||||
|
||||
@staticmethod
|
||||
def build_command(root: Path, prefix: str, architecture: str) -> Path:
|
||||
def build_command(root: Path, repository_id: RepositoryId) -> Path:
|
||||
"""
|
||||
generate build command name
|
||||
|
||||
Args:
|
||||
root(Path): root directory for the build command (must be root of the repository)
|
||||
prefix(str): command prefix in {prefix}-{architecture}-build
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
|
||||
Returns:
|
||||
Path: valid devtools command name
|
||||
"""
|
||||
return root / f"{prefix}-{architecture}-build"
|
||||
return root / f"{repository_id.name}-{repository_id.architecture}-build"
|
||||
|
||||
@staticmethod
|
||||
def configuration_create_ahriman(args: argparse.Namespace, architecture: str, repository: str,
|
||||
def configuration_create_ahriman(args: argparse.Namespace, repository_id: RepositoryId,
|
||||
root: Configuration) -> None:
|
||||
"""
|
||||
create service specific configuration
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
repository(str): repository name
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
root(Configuration): root configuration instance
|
||||
"""
|
||||
configuration = Configuration()
|
||||
|
||||
section = Configuration.section_name("build", architecture)
|
||||
build_command = Setup.build_command(root.repository_paths.root, args.build_command, architecture)
|
||||
section = Configuration.section_name("build", repository_id.name, repository_id.architecture)
|
||||
build_command = Setup.build_command(root.repository_paths.root, repository_id)
|
||||
configuration.set_option(section, "build_command", str(build_command))
|
||||
configuration.set_option("repository", "name", repository)
|
||||
configuration.set_option("repository", "name", repository_id.name) # backward compatibility for docker
|
||||
if args.build_as_user is not None:
|
||||
configuration.set_option(section, "makechrootpkg_flags", f"-U {args.build_as_user}")
|
||||
|
||||
section = Configuration.section_name("alpm", architecture)
|
||||
section = Configuration.section_name("alpm", repository_id.name, repository_id.architecture)
|
||||
if args.mirror is not None:
|
||||
configuration.set_option(section, "mirror", args.mirror)
|
||||
if not args.multilib:
|
||||
repositories = filter(lambda r: r != "multilib", root.getlist("alpm", "repositories"))
|
||||
configuration.set_option(section, "repositories", " ".join(repositories))
|
||||
|
||||
section = Configuration.section_name("sign", architecture)
|
||||
section = Configuration.section_name("sign", repository_id.name, repository_id.architecture)
|
||||
if args.sign_key is not None:
|
||||
configuration.set_option(section, "target", " ".join([target.name.lower() for target in args.sign_target]))
|
||||
sign_targets = args.sign_target or []
|
||||
configuration.set_option(section, "target", " ".join([target.name.lower() for target in sign_targets]))
|
||||
configuration.set_option(section, "key", args.sign_key)
|
||||
|
||||
section = Configuration.section_name("web", architecture)
|
||||
section = Configuration.section_name("web", repository_id.name, repository_id.architecture)
|
||||
if args.web_port is not None:
|
||||
configuration.set_option(section, "port", str(args.web_port))
|
||||
if args.web_unix_socket is not None:
|
||||
@ -134,8 +140,8 @@ class Setup(Handler):
|
||||
configuration.write(ahriman_configuration)
|
||||
|
||||
@staticmethod
|
||||
def configuration_create_devtools(prefix: str, architecture: str, source: Path, mirror: str | None,
|
||||
multilib: bool, repository: str, repository_server: str) -> None:
|
||||
def configuration_create_devtools(repository_id: RepositoryId, source: Path, mirror: str | None,
|
||||
multilib: bool, repository_server: str) -> None:
|
||||
"""
|
||||
create configuration for devtools based on ``source`` configuration
|
||||
|
||||
@ -143,12 +149,10 @@ class Setup(Handler):
|
||||
devtools does not allow to specify the pacman configuration, thus we still have to use configuration in /usr
|
||||
|
||||
Args:
|
||||
prefix(str): command prefix in {prefix}-{architecture}-build
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
source(Path): path to source configuration file
|
||||
mirror(str | None): link to package server mirror
|
||||
multilib(bool): add or do not multilib repository to the configuration
|
||||
repository(str): repository name
|
||||
repository_server(str): url of the repository
|
||||
"""
|
||||
# allow_no_value=True is required because pacman uses boolean configuration in which just keys present
|
||||
@ -163,7 +167,7 @@ class Setup(Handler):
|
||||
configuration.read(source)
|
||||
|
||||
# set our architecture now
|
||||
configuration.set_option("options", "Architecture", architecture)
|
||||
configuration.set_option("options", "Architecture", repository_id.architecture)
|
||||
|
||||
# add multilib
|
||||
if multilib:
|
||||
@ -178,10 +182,10 @@ class Setup(Handler):
|
||||
configuration.set_option(section, "Server", mirror)
|
||||
|
||||
# add repository itself
|
||||
configuration.set_option(repository, "SigLevel", "Never") # we don't care
|
||||
configuration.set_option(repository, "Server", repository_server)
|
||||
configuration.set_option(repository_id.name, "SigLevel", "Never") # we don't care
|
||||
configuration.set_option(repository_id.name, "Server", repository_server)
|
||||
|
||||
target = source.parent / f"{prefix}-{architecture}.conf"
|
||||
target = source.parent / f"{repository_id.name}-{repository_id.architecture}.conf"
|
||||
with target.open("w") as devtools_configuration:
|
||||
configuration.write(devtools_configuration)
|
||||
|
||||
@ -205,31 +209,29 @@ class Setup(Handler):
|
||||
(home_dir / ".makepkg.conf").write_text(content, encoding="utf8")
|
||||
|
||||
@staticmethod
|
||||
def configuration_create_sudo(paths: RepositoryPaths, prefix: str, architecture: str) -> None:
|
||||
def configuration_create_sudo(paths: RepositoryPaths, repository_id: RepositoryId) -> None:
|
||||
"""
|
||||
create configuration to run build command with sudo without password
|
||||
|
||||
Args:
|
||||
paths(RepositoryPaths): repository paths instance
|
||||
prefix(str): command prefix in {prefix}-{architecture}-build
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
"""
|
||||
command = Setup.build_command(paths.root, prefix, architecture)
|
||||
sudoers_file = Setup.build_command(Setup.SUDOERS_DIR_PATH, prefix, architecture)
|
||||
command = Setup.build_command(paths.root, repository_id)
|
||||
sudoers_file = Setup.build_command(Setup.SUDOERS_DIR_PATH, repository_id)
|
||||
sudoers_file.write_text(f"ahriman ALL=(ALL) NOPASSWD:SETENV: {command} *\n", encoding="utf8")
|
||||
sudoers_file.chmod(0o400) # security!
|
||||
|
||||
@staticmethod
|
||||
def executable_create(paths: RepositoryPaths, prefix: str, architecture: str) -> None:
|
||||
def executable_create(paths: RepositoryPaths, repository_id: RepositoryId) -> None:
|
||||
"""
|
||||
create executable for the service
|
||||
|
||||
Args:
|
||||
paths(RepositoryPaths): repository paths instance
|
||||
prefix(str): command prefix in {prefix}-{architecture}-build
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
"""
|
||||
command = Setup.build_command(paths.root, prefix, architecture)
|
||||
command = Setup.build_command(paths.root, repository_id)
|
||||
command.unlink(missing_ok=True)
|
||||
command.symlink_to(Setup.ARCHBUILD_COMMAND_PATH)
|
||||
paths.chown(command) # we would like to keep owner inside ahriman's home
|
||||
|
@ -26,6 +26,7 @@ from pathlib import Path
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.formatters import StringPrinter
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class Shell(Handler):
|
||||
@ -33,16 +34,17 @@ class Shell(Handler):
|
||||
python shell handler
|
||||
"""
|
||||
|
||||
ALLOW_MULTI_ARCHITECTURE_RUN = False
|
||||
ALLOW_MULTI_ARCHITECTURE_RUN = False # conflicting io
|
||||
|
||||
@classmethod
|
||||
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
|
||||
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
|
||||
report: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
report(bool): force enable or disable reporting
|
||||
"""
|
||||
@ -50,7 +52,13 @@ class Shell(Handler):
|
||||
# licensed by https://creativecommons.org/licenses/by-sa/3.0
|
||||
path = Path(sys.prefix) / "share" / "ahriman" / "templates" / "shell"
|
||||
StringPrinter(path.read_text(encoding="utf8")).print(verbose=False)
|
||||
local_variables = {"architecture": architecture, "configuration": configuration}
|
||||
|
||||
local_variables = {
|
||||
"architecture": repository_id.architecture,
|
||||
"configuration": configuration,
|
||||
"repository_id": repository_id,
|
||||
}
|
||||
|
||||
if args.code is None:
|
||||
code.interact(local=local_variables)
|
||||
else:
|
||||
|
@ -22,6 +22,7 @@ import argparse
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class Sign(Handler):
|
||||
@ -30,14 +31,15 @@ class Sign(Handler):
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
|
||||
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
|
||||
report: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
report(bool): force enable or disable reporting
|
||||
"""
|
||||
Application(architecture, configuration, report=report).sign(args.package)
|
||||
Application(repository_id, configuration, report=report).sign(args.package)
|
||||
|
@ -27,6 +27,7 @@ from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.formatters import PackagePrinter, StatusPrinter
|
||||
from ahriman.models.build_status import BuildStatus
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class Status(Handler):
|
||||
@ -34,21 +35,22 @@ class Status(Handler):
|
||||
package status handler
|
||||
"""
|
||||
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False
|
||||
ALLOW_MULTI_ARCHITECTURE_RUN = False # conflicting io
|
||||
|
||||
@classmethod
|
||||
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
|
||||
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
|
||||
report: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
report(bool): force enable or disable reporting
|
||||
"""
|
||||
# we are using reporter here
|
||||
client = Application(architecture, configuration, report=True).repository.reporter
|
||||
client = Application(repository_id, configuration, report=True).repository.reporter
|
||||
if args.ahriman:
|
||||
service_status = client.status_get()
|
||||
StatusPrinter(service_status.status).print(verbose=args.info)
|
||||
|
@ -23,6 +23,7 @@ from ahriman.application.application import Application
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.models.action import Action
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class StatusUpdate(Handler):
|
||||
@ -30,21 +31,22 @@ class StatusUpdate(Handler):
|
||||
status update handler
|
||||
"""
|
||||
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False
|
||||
ALLOW_MULTI_ARCHITECTURE_RUN = False # conflicting io
|
||||
|
||||
@classmethod
|
||||
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
|
||||
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
|
||||
report: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
report(bool): force enable or disable reporting
|
||||
"""
|
||||
# we are using reporter here
|
||||
client = Application(architecture, configuration, report=True).repository.reporter
|
||||
client = Application(repository_id, configuration, report=True).repository.reporter
|
||||
|
||||
match args.action:
|
||||
case Action.Update if args.package:
|
||||
|
@ -24,6 +24,7 @@ from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.formatters import StringPrinter, TreePrinter
|
||||
from ahriman.core.tree import Tree
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class Structure(Handler):
|
||||
@ -31,20 +32,21 @@ class Structure(Handler):
|
||||
dump repository structure handler
|
||||
"""
|
||||
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False
|
||||
ALLOW_MULTI_ARCHITECTURE_RUN = False # conflicting io
|
||||
|
||||
@classmethod
|
||||
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
|
||||
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
|
||||
report: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
report(bool): force enable or disable reporting
|
||||
"""
|
||||
application = Application(architecture, configuration, report=report)
|
||||
application = Application(repository_id, configuration, report=report)
|
||||
partitions = Tree.partition(application.repository.packages(), count=args.partitions)
|
||||
|
||||
for partition_id, partition in enumerate(partitions):
|
||||
|
68
src/ahriman/application/handlers/tree_migrate.py
Normal file
68
src/ahriman/application/handlers/tree_migrate.py
Normal file
@ -0,0 +1,68 @@
|
||||
#
|
||||
# Copyright (c) 2021-2023 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 argparse
|
||||
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
from ahriman.models.repository_paths import RepositoryPaths
|
||||
|
||||
|
||||
class TreeMigrate(Handler):
|
||||
"""
|
||||
tree migration handler
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
|
||||
report: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
report(bool): force enable or disable reporting
|
||||
"""
|
||||
current_tree = configuration.repository_paths
|
||||
target_tree = RepositoryPaths(current_tree.root, current_tree.repository_id, _force_current_tree=True)
|
||||
|
||||
# create repository tree
|
||||
target_tree.tree_create()
|
||||
# perform migration
|
||||
TreeMigrate.tree_move(current_tree, target_tree)
|
||||
|
||||
@staticmethod
|
||||
def tree_move(from_tree: RepositoryPaths, to_tree: RepositoryPaths) -> None:
|
||||
"""
|
||||
move files between trees. Trees must be created in advance
|
||||
|
||||
Args:
|
||||
from_tree(RepositoryPaths): old repository tree
|
||||
to_tree(RepositoryPaths): new repository tree
|
||||
"""
|
||||
# we don't care about devtools chroot
|
||||
for attribute in (
|
||||
RepositoryPaths.packages,
|
||||
RepositoryPaths.pacman,
|
||||
RepositoryPaths.repository,
|
||||
):
|
||||
attribute.fget(from_tree).rename(attribute.fget(to_tree)) # type: ignore[attr-defined]
|
@ -22,6 +22,7 @@ import argparse
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
from ahriman.models.result import Result
|
||||
|
||||
|
||||
@ -31,19 +32,20 @@ class Triggers(Handler):
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
|
||||
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
|
||||
report: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
report(bool): force enable or disable reporting
|
||||
"""
|
||||
application = Application(architecture, configuration, report=report)
|
||||
application = Application(repository_id, configuration, report=report)
|
||||
if args.trigger:
|
||||
loader = application.repository.triggers
|
||||
loader.triggers = [loader.load_trigger(trigger, architecture, configuration) for trigger in args.trigger]
|
||||
loader.triggers = [loader.load_trigger(trigger, repository_id, configuration) for trigger in args.trigger]
|
||||
application.on_start()
|
||||
application.on_result(Result())
|
||||
|
@ -22,6 +22,7 @@ import argparse
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.formatters import StringPrinter
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class UnsafeCommands(Handler):
|
||||
@ -29,16 +30,17 @@ class UnsafeCommands(Handler):
|
||||
unsafe command help parser
|
||||
"""
|
||||
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||
ALLOW_MULTI_ARCHITECTURE_RUN = False # system-wide action
|
||||
|
||||
@classmethod
|
||||
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
|
||||
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
|
||||
report: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
report(bool): force enable or disable reporting
|
||||
"""
|
||||
|
@ -25,6 +25,7 @@ from ahriman.application.application import Application
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.models.packagers import Packagers
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class Update(Handler):
|
||||
@ -33,17 +34,18 @@ class Update(Handler):
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
|
||||
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
|
||||
report: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
report(bool): force enable or disable reporting
|
||||
"""
|
||||
application = Application(architecture, configuration, report=report, refresh_pacman_database=args.refresh)
|
||||
application = Application(repository_id, configuration, report=report, refresh_pacman_database=args.refresh)
|
||||
application.on_start()
|
||||
packages = application.updates(args.package, aur=args.aur, local=args.local, manual=args.manual, vcs=args.vcs)
|
||||
Update.check_if_empty(args.exit_code, not packages)
|
||||
|
@ -26,6 +26,7 @@ from ahriman.core.database import SQLite
|
||||
from ahriman.core.exceptions import PasswordError
|
||||
from ahriman.core.formatters import UserPrinter
|
||||
from ahriman.models.action import Action
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
from ahriman.models.user import User
|
||||
|
||||
|
||||
@ -34,16 +35,17 @@ class Users(Handler):
|
||||
user management handler
|
||||
"""
|
||||
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||
ALLOW_MULTI_ARCHITECTURE_RUN = False # system-wide action
|
||||
|
||||
@classmethod
|
||||
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
|
||||
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
|
||||
report: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
report(bool): force enable or disable reporting
|
||||
"""
|
||||
|
@ -29,6 +29,7 @@ from ahriman.core.configuration.validator import Validator
|
||||
from ahriman.core.exceptions import ExtensionError
|
||||
from ahriman.core.formatters import ValidationPrinter
|
||||
from ahriman.core.triggers import TriggerLoader
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class Validate(Handler):
|
||||
@ -36,20 +37,21 @@ class Validate(Handler):
|
||||
configuration validator handler
|
||||
"""
|
||||
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False
|
||||
ALLOW_MULTI_ARCHITECTURE_RUN = False # conflicting io
|
||||
|
||||
@classmethod
|
||||
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
|
||||
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
|
||||
report: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
report(bool): force enable or disable reporting
|
||||
"""
|
||||
schema = Validate.schema(architecture, configuration)
|
||||
schema = Validate.schema(repository_id, configuration)
|
||||
validator = Validator(configuration=configuration, schema=schema)
|
||||
|
||||
if validator.validate(configuration.dump()):
|
||||
@ -61,12 +63,12 @@ class Validate(Handler):
|
||||
Validate.check_if_empty(args.exit_code, True)
|
||||
|
||||
@staticmethod
|
||||
def schema(architecture: str, configuration: Configuration) -> ConfigurationSchema:
|
||||
def schema(repository_id: RepositoryId, configuration: Configuration) -> ConfigurationSchema:
|
||||
"""
|
||||
get schema with triggers
|
||||
|
||||
Args:
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
|
||||
Returns:
|
||||
@ -85,12 +87,12 @@ class Validate(Handler):
|
||||
continue
|
||||
|
||||
# default settings if any
|
||||
for schema_name, schema in trigger_class.configuration_schema(architecture, None).items():
|
||||
for schema_name, schema in trigger_class.configuration_schema(repository_id, None).items():
|
||||
erased = Validate.schema_erase_required(copy.deepcopy(schema))
|
||||
root[schema_name] = Validate.schema_merge(root.get(schema_name, {}), erased)
|
||||
|
||||
# settings according to enabled triggers
|
||||
for schema_name, schema in trigger_class.configuration_schema(architecture, configuration).items():
|
||||
for schema_name, schema in trigger_class.configuration_schema(repository_id, configuration).items():
|
||||
root[schema_name] = Validate.schema_merge(root.get(schema_name, {}), copy.deepcopy(schema))
|
||||
|
||||
return root
|
||||
|
@ -28,6 +28,7 @@ from ahriman import __version__
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.formatters import VersionPrinter
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class Versions(Handler):
|
||||
@ -38,17 +39,18 @@ class Versions(Handler):
|
||||
PEP423_PACKAGE_NAME(str): (class attribute) special regex for valid PEP423 package name
|
||||
"""
|
||||
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||
ALLOW_MULTI_ARCHITECTURE_RUN = False # system-wide action
|
||||
PEP423_PACKAGE_NAME = re.compile(r"^[A-Za-z0-9._-]+")
|
||||
|
||||
@classmethod
|
||||
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
|
||||
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
|
||||
report: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
report(bool): force enable or disable reporting
|
||||
"""
|
||||
|
@ -24,6 +24,7 @@ from collections.abc import Generator
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.spawn import Spawn
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class Web(Handler):
|
||||
@ -31,28 +32,28 @@ class Web(Handler):
|
||||
web server handler
|
||||
"""
|
||||
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False
|
||||
ALLOW_MULTI_ARCHITECTURE_RUN = False # required to be able to spawn external processes
|
||||
|
||||
@classmethod
|
||||
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
|
||||
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
|
||||
report: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
report(bool): force enable or disable reporting
|
||||
"""
|
||||
# we are using local import for optional dependencies
|
||||
from ahriman.web.web import run_server, setup_service
|
||||
|
||||
spawner_args = Web.extract_arguments(args, architecture, configuration)
|
||||
spawner = Spawn(args.parser(), architecture, list(spawner_args))
|
||||
spawner_args = Web.extract_arguments(args, repository_id, configuration)
|
||||
spawner = Spawn(args.parser(), repository_id, list(spawner_args))
|
||||
spawner.start()
|
||||
|
||||
application = setup_service(architecture, configuration, spawner)
|
||||
application = setup_service(repository_id, configuration, spawner)
|
||||
run_server(application)
|
||||
|
||||
# terminate spawn process at the last
|
||||
@ -60,21 +61,22 @@ class Web(Handler):
|
||||
spawner.join()
|
||||
|
||||
@staticmethod
|
||||
def extract_arguments(args: argparse.Namespace, architecture: str,
|
||||
def extract_arguments(args: argparse.Namespace, repository_id: RepositoryId,
|
||||
configuration: Configuration) -> Generator[str, None, None]:
|
||||
"""
|
||||
extract list of arguments used for current command, except for command specific ones
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
|
||||
Returns:
|
||||
Generator[str, None, None]: command line arguments which were used for this specific command
|
||||
"""
|
||||
# read architecture from the same argument list
|
||||
yield from ["--architecture", architecture]
|
||||
yield from ["--architecture", repository_id.architecture]
|
||||
yield from ["--repository", repository_id.name]
|
||||
# read configuration path from current settings
|
||||
if (configuration_path := configuration.path) is not None:
|
||||
yield from ["--configuration", str(configuration_path)]
|
||||
|
@ -30,6 +30,7 @@ from ahriman.core.log import LazyLogging
|
||||
from ahriman.core.status.client import Client
|
||||
from ahriman.core.util import check_user
|
||||
from ahriman.models.build_status import BuildStatusEnum
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
from ahriman.models.waiter import Waiter
|
||||
|
||||
|
||||
@ -50,26 +51,29 @@ class Lock(LazyLogging):
|
||||
The common flow is to create instance in ``with`` block and handle exceptions after all::
|
||||
|
||||
>>> from ahriman.core.configuration import Configuration
|
||||
>>> from ahriman.models.repository_id import RepositoryId
|
||||
>>>
|
||||
>>> configuration = Configuration()
|
||||
>>> try:
|
||||
>>> with Lock(args, "x86_64", configuration):
|
||||
>>> with Lock(args, RepositoryId("x86_64", "aur-clone"), configuration):
|
||||
>>> perform_actions()
|
||||
>>> except Exception as exception:
|
||||
>>> handle_exceptions(exception)
|
||||
"""
|
||||
|
||||
def __init__(self, args: argparse.Namespace, architecture: str, configuration: Configuration) -> None:
|
||||
def __init__(self, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
"""
|
||||
lock_suffix = f"{repository_id.name}_{repository_id.architecture}"
|
||||
self.path: Path | None = \
|
||||
args.lock.with_stem(f"{args.lock.stem}_{architecture}") if args.lock is not None else None
|
||||
args.lock.with_stem(f"{args.lock.stem}_{lock_suffix}") if args.lock is not None else None
|
||||
|
||||
self.force: bool = args.force
|
||||
self.unsafe: bool = args.unsafe
|
||||
self.wait_timeout: int = args.wait_timeout
|
||||
|
@ -23,11 +23,13 @@ from collections.abc import Callable, Generator
|
||||
from functools import cached_property
|
||||
from pathlib import Path
|
||||
from pyalpm import DB, Handle, Package, SIG_PACKAGE, error as PyalpmError # type: ignore[import]
|
||||
from string import Template
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.log import LazyLogging
|
||||
from ahriman.core.util import trim_package
|
||||
from ahriman.models.pacman_synchronization import PacmanSynchronization
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
from ahriman.models.repository_paths import RepositoryPaths
|
||||
|
||||
|
||||
@ -36,18 +38,18 @@ class Pacman(LazyLogging):
|
||||
alpm wrapper
|
||||
"""
|
||||
|
||||
def __init__(self, architecture: str, configuration: Configuration, *,
|
||||
def __init__(self, repository_id: RepositoryId, configuration: Configuration, *,
|
||||
refresh_database: PacmanSynchronization) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
refresh_database(PacmanSynchronization): synchronize local cache to remote
|
||||
"""
|
||||
self.__create_handle_fn: Callable[[], Handle] = lambda: self.__create_handle(
|
||||
architecture, configuration, refresh_database=refresh_database)
|
||||
repository_id, configuration, refresh_database=refresh_database)
|
||||
|
||||
@cached_property
|
||||
def handle(self) -> Handle:
|
||||
@ -59,13 +61,13 @@ class Pacman(LazyLogging):
|
||||
"""
|
||||
return self.__create_handle_fn()
|
||||
|
||||
def __create_handle(self, architecture: str, configuration: Configuration, *,
|
||||
def __create_handle(self, repository_id: RepositoryId, configuration: Configuration, *,
|
||||
refresh_database: PacmanSynchronization) -> Handle:
|
||||
"""
|
||||
create lazy handle function
|
||||
|
||||
Args:
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
refresh_database(PacmanSynchronization): synchronize local cache to remote
|
||||
|
||||
@ -81,7 +83,7 @@ class Pacman(LazyLogging):
|
||||
|
||||
handle = Handle(str(root), str(database_path))
|
||||
for repository in configuration.getlist("alpm", "repositories"):
|
||||
database = self.database_init(handle, repository, mirror, architecture)
|
||||
database = self.database_init(handle, repository, mirror, repository_id.architecture)
|
||||
self.database_copy(handle, database, pacman_root, paths, use_ahriman_cache=use_ahriman_cache)
|
||||
|
||||
if use_ahriman_cache and refresh_database:
|
||||
@ -113,6 +115,7 @@ class Pacman(LazyLogging):
|
||||
dst = repository_database(pacman_db_path)
|
||||
if dst.is_file():
|
||||
return # file already exists, do not copy
|
||||
dst.parent.mkdir(mode=0o755, exist_ok=True) # create sync directory if it doesn't exist
|
||||
src = repository_database(pacman_root)
|
||||
if not src.is_file():
|
||||
self.logger.warning("repository %s is set to be used, however, no working copy was found", database.name)
|
||||
@ -136,8 +139,14 @@ class Pacman(LazyLogging):
|
||||
"""
|
||||
self.logger.info("loading pacman database %s", repository)
|
||||
database: DB = handle.register_syncdb(repository, SIG_PACKAGE)
|
||||
|
||||
# replace variables in mirror address
|
||||
database.servers = [mirror.replace("$repo", repository).replace("$arch", architecture)]
|
||||
variables = {
|
||||
"arch": architecture,
|
||||
"repo": repository,
|
||||
}
|
||||
database.servers = [Template(mirror).safe_substitute(variables)]
|
||||
|
||||
return database
|
||||
|
||||
def database_sync(self, handle: Handle, *, force: bool) -> None:
|
||||
|
@ -154,7 +154,7 @@ class Sources(LazyLogging):
|
||||
shutil.copytree(cache_dir, sources_dir, dirs_exist_ok=True)
|
||||
instance.fetch(sources_dir, package.remote)
|
||||
|
||||
patches.extend(instance.extend_architectures(sources_dir, paths.architecture))
|
||||
patches.extend(instance.extend_architectures(sources_dir, paths.repository_id.architecture))
|
||||
for patch in patches:
|
||||
instance.patch_apply(sources_dir, patch)
|
||||
|
||||
|
@ -27,6 +27,7 @@ from typing import Any, Self
|
||||
|
||||
from ahriman.core.configuration.shell_interpolator import ShellInterpolator
|
||||
from ahriman.core.exceptions import InitializeError
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
from ahriman.models.repository_paths import RepositoryPaths
|
||||
|
||||
|
||||
@ -38,9 +39,9 @@ class Configuration(configparser.RawConfigParser):
|
||||
ARCHITECTURE_SPECIFIC_SECTIONS(list[str]): (class attribute) known sections which can be architecture specific.
|
||||
Required by dump and merging functions
|
||||
SYSTEM_CONFIGURATION_PATH(Path): (class attribute) default system configuration path distributed by package
|
||||
architecture(str | None): repository architecture
|
||||
includes(list[Path]): list of includes which were read
|
||||
path(Path | None): path to root configuration file
|
||||
repository_id(RepositoryId | None): repository unique identifier
|
||||
|
||||
Examples:
|
||||
Configuration class provides additional method in order to handle application configuration. Since this class is
|
||||
@ -49,7 +50,7 @@ class Configuration(configparser.RawConfigParser):
|
||||
|
||||
>>> from pathlib import Path
|
||||
>>>
|
||||
>>> configuration = Configuration.from_path(Path("/etc/ahriman.ini"), "x86_64")
|
||||
>>> configuration = Configuration.from_path(Path("/etc/ahriman.ini"), RepositoryId("x86_64", "aur-clone"))
|
||||
>>> repository_name = configuration.get("repository", "name")
|
||||
>>> makepkg_flags = configuration.getlist("build", "makepkg_flags")
|
||||
|
||||
@ -59,7 +60,7 @@ class Configuration(configparser.RawConfigParser):
|
||||
In order to get current settings, the ``check_loaded`` method can be used. This method will raise an
|
||||
``InitializeError`` in case if configuration was not yet loaded::
|
||||
|
||||
>>> path, architecture = configuration.check_loaded()
|
||||
>>> path, repository_id = configuration.check_loaded()
|
||||
"""
|
||||
|
||||
ARCHITECTURE_SPECIFIC_SECTIONS = ["alpm", "build", "sign", "web"]
|
||||
@ -84,10 +85,21 @@ class Configuration(configparser.RawConfigParser):
|
||||
}
|
||||
)
|
||||
|
||||
self.architecture: str | None = None
|
||||
self.repository_id: RepositoryId | None = None
|
||||
self.path: Path | None = None
|
||||
self.includes: list[Path] = []
|
||||
|
||||
@property
|
||||
def architecture(self) -> str:
|
||||
"""
|
||||
repository architecture for backward compatibility
|
||||
|
||||
Returns:
|
||||
str: repository architecture
|
||||
"""
|
||||
_, repository_id = self.check_loaded()
|
||||
return repository_id.architecture
|
||||
|
||||
@property
|
||||
def include(self) -> Path:
|
||||
"""
|
||||
@ -111,12 +123,13 @@ class Configuration(configparser.RawConfigParser):
|
||||
@property
|
||||
def repository_name(self) -> str:
|
||||
"""
|
||||
repository name as defined by configuration
|
||||
repository name for backward compatibility
|
||||
|
||||
Returns:
|
||||
str: repository name from configuration
|
||||
str: repository name
|
||||
"""
|
||||
return self.get("repository", "name")
|
||||
_, repository_id = self.check_loaded()
|
||||
return repository_id.name
|
||||
|
||||
@property
|
||||
def repository_paths(self) -> RepositoryPaths:
|
||||
@ -126,39 +139,60 @@ class Configuration(configparser.RawConfigParser):
|
||||
Returns:
|
||||
RepositoryPaths: repository paths instance
|
||||
"""
|
||||
_, architecture = self.check_loaded()
|
||||
return RepositoryPaths(self.getpath("repository", "root"), architecture)
|
||||
_, repository_id = self.check_loaded()
|
||||
return RepositoryPaths(self.getpath("repository", "root"), repository_id)
|
||||
|
||||
@classmethod
|
||||
def from_path(cls, path: Path, architecture: str) -> Self:
|
||||
def from_path(cls, path: Path, repository_id: RepositoryId) -> Self:
|
||||
"""
|
||||
constructor with full object initialization
|
||||
|
||||
Args:
|
||||
path(Path): path to root configuration file
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
|
||||
Returns:
|
||||
Self: configuration instance
|
||||
"""
|
||||
configuration = cls()
|
||||
configuration.load(path)
|
||||
configuration.merge_sections(architecture)
|
||||
configuration.merge_sections(repository_id)
|
||||
return configuration
|
||||
|
||||
@staticmethod
|
||||
def section_name(section: str, suffix: str) -> str:
|
||||
def override_sections(section: str, repository_id: RepositoryId) -> list[str]:
|
||||
"""
|
||||
extract override sections
|
||||
|
||||
Args:
|
||||
section(str): section name
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
|
||||
Returns:
|
||||
list[str]: architecture and repository specific sections in correct order
|
||||
"""
|
||||
# the valid order is global < per architecture < per repository < per repository and architecture
|
||||
return [
|
||||
Configuration.section_name(section, repository_id.architecture), # architecture specific override
|
||||
Configuration.section_name(section, repository_id.name), # override with repository name
|
||||
Configuration.section_name(section, repository_id.name, repository_id.architecture), # both
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def section_name(section: str, *suffixes: str | None) -> str:
|
||||
"""
|
||||
generate section name for sections which depends on context
|
||||
|
||||
Args:
|
||||
section(str): section name
|
||||
suffix(str): session suffix, e.g. repository architecture
|
||||
*suffixes(str | None): session suffix, e.g. repository architecture
|
||||
|
||||
Returns:
|
||||
str: correct section name for repository specific section
|
||||
"""
|
||||
return f"{section}:{suffix}"
|
||||
for suffix in filter(bool, suffixes):
|
||||
section = f"{section}:{suffix}"
|
||||
return section
|
||||
|
||||
def _convert_path(self, value: str) -> Path:
|
||||
"""
|
||||
@ -175,19 +209,19 @@ class Configuration(configparser.RawConfigParser):
|
||||
return path
|
||||
return self.path.parent / path
|
||||
|
||||
def check_loaded(self) -> tuple[Path, str]:
|
||||
def check_loaded(self) -> tuple[Path, RepositoryId]:
|
||||
"""
|
||||
check if service was actually loaded
|
||||
|
||||
Returns:
|
||||
tuple[Path, str]: configuration root path and architecture if loaded
|
||||
tuple[Path, RepositoryId]: configuration root path and architecture if loaded
|
||||
|
||||
Raises:
|
||||
InitializeError: in case if architecture and/or path are not set
|
||||
"""
|
||||
if self.path is None or self.architecture is None:
|
||||
raise InitializeError("Configuration path and/or architecture are not set")
|
||||
return self.path, self.architecture
|
||||
if self.path is None or self.repository_id is None:
|
||||
raise InitializeError("Configuration path and/or repository id are not set")
|
||||
return self.path, self.repository_id
|
||||
|
||||
def dump(self) -> dict[str, dict[str, str]]:
|
||||
"""
|
||||
@ -207,14 +241,14 @@ class Configuration(configparser.RawConfigParser):
|
||||
|
||||
def getpath(self, *args: Any, **kwargs: Any) -> Path: ... # type: ignore[empty-body]
|
||||
|
||||
def gettype(self, section: str, architecture: str, *, fallback: str | None = None) -> tuple[str, str]:
|
||||
def gettype(self, section: str, repository_id: RepositoryId, *, fallback: str | None = None) -> tuple[str, str]:
|
||||
"""
|
||||
get type variable with fallback to old logic. Despite the fact that it has same semantics as other get* methods,
|
||||
but it has different argument list
|
||||
|
||||
Args:
|
||||
section(str): section name
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
fallback(str | None, optional): optional fallback type if any. If set, second element of the tuple will
|
||||
be always set to this value (Default value = None)
|
||||
|
||||
@ -227,9 +261,9 @@ class Configuration(configparser.RawConfigParser):
|
||||
if (group_type := self.get(section, "type", fallback=fallback)) is not None:
|
||||
return section, group_type # new-style logic
|
||||
# okay lets check for the section with architecture name
|
||||
full_section = self.section_name(section, architecture)
|
||||
if self.has_section(full_section):
|
||||
return full_section, section
|
||||
for specific in self.override_sections(section, repository_id):
|
||||
if self.has_section(specific):
|
||||
return specific, section
|
||||
# okay lets just use section as type
|
||||
if self.has_section(section):
|
||||
return section, section
|
||||
@ -262,23 +296,24 @@ class Configuration(configparser.RawConfigParser):
|
||||
except (FileNotFoundError, configparser.NoOptionError, configparser.NoSectionError):
|
||||
pass
|
||||
|
||||
def merge_sections(self, architecture: str) -> None:
|
||||
def merge_sections(self, repository_id: RepositoryId) -> None:
|
||||
"""
|
||||
merge architecture specific sections into main configuration
|
||||
merge architecture and repository specific sections into main configuration
|
||||
|
||||
Args:
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
"""
|
||||
self.architecture = architecture
|
||||
self.repository_id = repository_id
|
||||
|
||||
for section in self.ARCHITECTURE_SPECIFIC_SECTIONS:
|
||||
# get overrides
|
||||
specific = self.section_name(section, architecture)
|
||||
if self.has_section(specific):
|
||||
# if there is no such section it means that there is no overrides for this arch,
|
||||
# but we anyway will have to delete sections for others architectures
|
||||
for key, value in self[specific].items():
|
||||
self.set_option(section, key, value)
|
||||
# remove any arch specific section
|
||||
for specific in self.override_sections(section, repository_id):
|
||||
if self.has_section(specific):
|
||||
# if there is no such section it means that there is no overrides for this arch,
|
||||
# but we anyway will have to delete sections for others architectures
|
||||
for key, value in self[specific].items():
|
||||
self.set_option(section, key, value)
|
||||
|
||||
# remove any arch/repo specific section
|
||||
for foreign in self.sections():
|
||||
# we would like to use lambda filter here, but pylint is too dumb
|
||||
if not foreign.startswith(f"{section}:"):
|
||||
@ -289,11 +324,11 @@ class Configuration(configparser.RawConfigParser):
|
||||
"""
|
||||
reload configuration if possible or raise exception otherwise
|
||||
"""
|
||||
path, architecture = self.check_loaded()
|
||||
path, repository_id = self.check_loaded()
|
||||
for section in self.sections(): # clear current content
|
||||
self.remove_section(section)
|
||||
self.load(path)
|
||||
self.merge_sections(architecture)
|
||||
self.merge_sections(repository_id)
|
||||
|
||||
def set_option(self, section: str, option: str, value: str) -> None:
|
||||
"""
|
||||
|
@ -187,7 +187,6 @@ CONFIGURATION_SCHEMA: ConfigurationSchema = {
|
||||
"schema": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"required": True,
|
||||
},
|
||||
"root": {
|
||||
"type": "string",
|
||||
|
@ -71,7 +71,18 @@ def migrate_package_remotes(connection: Connection, paths: RepositoryPaths) -> N
|
||||
paths(RepositoryPaths): repository paths instance
|
||||
"""
|
||||
from ahriman.core.alpm.remote import AUR
|
||||
from ahriman.core.database.operations import PackageOperations
|
||||
from ahriman.models.package import Package
|
||||
|
||||
def get_packages() -> dict[str, Package]:
|
||||
return {
|
||||
row["package_base"]: Package(
|
||||
base=row["package_base"],
|
||||
version=row["version"],
|
||||
remote=RemoteSource.from_json(row),
|
||||
packages={},
|
||||
packager=row.get("packager") or None,
|
||||
) for row in connection.execute("""select * from package_bases""")
|
||||
}
|
||||
|
||||
def insert_remote(base: str, remote: RemoteSource) -> None:
|
||||
connection.execute(
|
||||
@ -88,8 +99,7 @@ def migrate_package_remotes(connection: Connection, paths: RepositoryPaths) -> N
|
||||
}
|
||||
)
|
||||
|
||||
packages = PackageOperations._packages_get_select_package_bases(connection)
|
||||
for package_base, package in packages.items():
|
||||
for package_base, package in get_packages().items():
|
||||
local_cache = paths.cache_for(package_base)
|
||||
if local_cache.exists() and not package.is_vcs:
|
||||
continue # skip packages which are not VCS and with local cache
|
||||
|
@ -61,8 +61,8 @@ def migrate_package_depends(connection: Connection, configuration: Configuration
|
||||
if not configuration.repository_paths.repository.is_dir():
|
||||
return
|
||||
|
||||
_, architecture = configuration.check_loaded()
|
||||
pacman = Pacman(architecture, configuration, refresh_database=PacmanSynchronization.Disabled)
|
||||
_, repository_id = configuration.check_loaded()
|
||||
pacman = Pacman(repository_id, configuration, refresh_database=PacmanSynchronization.Disabled)
|
||||
|
||||
package_list = []
|
||||
for full_path in filter(package_like, configuration.repository_paths.repository.iterdir()):
|
||||
|
@ -45,9 +45,9 @@ steps = [
|
||||
)
|
||||
""",
|
||||
"""
|
||||
insert into packages select * from packages_ where architecture is not null;
|
||||
insert into packages select * from packages_ where architecture is not null
|
||||
""",
|
||||
"""
|
||||
drop table packages_;
|
||||
drop table packages_
|
||||
""",
|
||||
]
|
||||
|
@ -58,8 +58,8 @@ def migrate_package_check_depends(connection: Connection, configuration: Configu
|
||||
if not configuration.repository_paths.repository.is_dir():
|
||||
return
|
||||
|
||||
_, architecture = configuration.check_loaded()
|
||||
pacman = Pacman(architecture, configuration, refresh_database=PacmanSynchronization.Disabled)
|
||||
_, repository_id = configuration.check_loaded()
|
||||
pacman = Pacman(repository_id, configuration, refresh_database=PacmanSynchronization.Disabled)
|
||||
|
||||
package_list = []
|
||||
for full_path in filter(package_like, configuration.repository_paths.repository.iterdir()):
|
||||
|
@ -64,8 +64,8 @@ def migrate_package_base_packager(connection: Connection, configuration: Configu
|
||||
if not configuration.repository_paths.repository.is_dir():
|
||||
return
|
||||
|
||||
_, architecture = configuration.check_loaded()
|
||||
pacman = Pacman(architecture, configuration, refresh_database=PacmanSynchronization.Disabled)
|
||||
_, repository_id = configuration.check_loaded()
|
||||
pacman = Pacman(repository_id, configuration, refresh_database=PacmanSynchronization.Disabled)
|
||||
|
||||
package_list = []
|
||||
for full_path in filter(package_like, configuration.repository_paths.repository.iterdir()):
|
||||
|
211
src/ahriman/core/database/migrations/m011_repository_name.py
Normal file
211
src/ahriman/core/database/migrations/m011_repository_name.py
Normal file
@ -0,0 +1,211 @@
|
||||
#
|
||||
# Copyright (c) 2021-2023 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 sqlite3 import Connection
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
|
||||
|
||||
__all__ = ["migrate_data", "steps"]
|
||||
|
||||
|
||||
steps = [
|
||||
# set correct types for schema
|
||||
"""
|
||||
alter table users rename to users_
|
||||
""",
|
||||
"""
|
||||
create table users (
|
||||
username text not null unique,
|
||||
access text not null,
|
||||
password text,
|
||||
packager_id text,
|
||||
key_id text
|
||||
)
|
||||
""",
|
||||
"""
|
||||
insert into users select * from users_
|
||||
""",
|
||||
"""
|
||||
drop table users_
|
||||
""",
|
||||
# update base tables
|
||||
# build_queue
|
||||
"""
|
||||
alter table build_queue add column repository text not null default ''
|
||||
""",
|
||||
"""
|
||||
alter table build_queue rename to build_queue_
|
||||
""",
|
||||
"""
|
||||
create table build_queue (
|
||||
package_base text not null,
|
||||
properties json not null,
|
||||
repository text not null,
|
||||
unique (package_base, repository)
|
||||
)
|
||||
""",
|
||||
"""
|
||||
insert into build_queue select * from build_queue_
|
||||
""",
|
||||
"""
|
||||
drop table build_queue_
|
||||
""",
|
||||
# package_bases
|
||||
"""
|
||||
alter table package_bases add column repository text not null default ''
|
||||
""",
|
||||
"""
|
||||
alter table package_bases rename to package_bases_
|
||||
""",
|
||||
"""
|
||||
create table package_bases (
|
||||
package_base text not null,
|
||||
version text not null,
|
||||
branch text,
|
||||
git_url text,
|
||||
path text,
|
||||
web_url text,
|
||||
source text,
|
||||
packager text,
|
||||
repository text not null,
|
||||
unique (package_base, repository)
|
||||
)
|
||||
""",
|
||||
"""
|
||||
insert into package_bases select * from package_bases_
|
||||
""",
|
||||
"""
|
||||
drop table package_bases_
|
||||
""",
|
||||
# package_statuses
|
||||
"""
|
||||
alter table package_statuses add column repository text not null default ''
|
||||
""",
|
||||
"""
|
||||
alter table package_statuses rename to package_statuses_
|
||||
""",
|
||||
"""
|
||||
create table package_statuses (
|
||||
package_base text not null,
|
||||
status text not null,
|
||||
last_updated integer,
|
||||
repository text not null,
|
||||
unique (package_base, repository)
|
||||
)
|
||||
""",
|
||||
"""
|
||||
insert into package_statuses select * from package_statuses_
|
||||
""",
|
||||
"""
|
||||
drop table package_statuses_
|
||||
""",
|
||||
# packages
|
||||
"""
|
||||
alter table packages add column repository text not null default ''
|
||||
""",
|
||||
"""
|
||||
alter table packages rename to packages_
|
||||
""",
|
||||
"""
|
||||
create table packages (
|
||||
package text not null,
|
||||
package_base text not null,
|
||||
architecture text not null,
|
||||
archive_size integer,
|
||||
build_date integer,
|
||||
depends json,
|
||||
description text,
|
||||
filename text,
|
||||
"groups" json,
|
||||
installed_size integer,
|
||||
licenses json,
|
||||
provides json,
|
||||
url text,
|
||||
make_depends json,
|
||||
opt_depends json,
|
||||
check_depends json,
|
||||
repository text not null,
|
||||
unique (package, architecture, repository)
|
||||
)
|
||||
""",
|
||||
"""
|
||||
insert into packages select * from packages_
|
||||
""",
|
||||
"""
|
||||
drop table packages_
|
||||
""",
|
||||
# logs
|
||||
"""
|
||||
alter table logs add column repository text not null default ''
|
||||
""",
|
||||
"""
|
||||
drop index logs_package_base_version
|
||||
""",
|
||||
"""
|
||||
alter table logs rename to logs_
|
||||
""",
|
||||
"""
|
||||
create table logs (
|
||||
package_base text not null,
|
||||
created real not null,
|
||||
record text,
|
||||
version text not null,
|
||||
repository text not null
|
||||
)
|
||||
""",
|
||||
"""
|
||||
insert into logs select * from logs_
|
||||
""",
|
||||
"""
|
||||
create index logs_package_base_version_repository
|
||||
on logs (package_base, version, repository)
|
||||
""",
|
||||
"""
|
||||
drop table logs_
|
||||
""",
|
||||
]
|
||||
|
||||
|
||||
def migrate_data(connection: Connection, configuration: Configuration) -> None:
|
||||
"""
|
||||
perform data migration
|
||||
|
||||
Args:
|
||||
connection(Connection): database connection
|
||||
configuration(Configuration): configuration instance
|
||||
"""
|
||||
migrate_package_repository(connection, configuration)
|
||||
|
||||
|
||||
def migrate_package_repository(connection: Connection, configuration: Configuration) -> None:
|
||||
"""
|
||||
update repository name from current settings
|
||||
|
||||
Args:
|
||||
connection(Connection): database connection
|
||||
configuration(Configuration): configuration instance
|
||||
"""
|
||||
_, repository_id = configuration.check_loaded()
|
||||
|
||||
connection.execute("""update build_queue set repository = :repository""", {"repository": repository_id.id})
|
||||
connection.execute("""update package_bases set repository = :repository""", {"repository": repository_id.id})
|
||||
connection.execute("""update package_statuses set repository = :repository""", {"repository": repository_id.id})
|
||||
connection.execute("""update packages set repository = :repository""", {"repository": repository_id.id})
|
||||
connection.execute("""update logs set repository = :repository""", {"repository": repository_id.id})
|
@ -39,9 +39,12 @@ class BuildOperations(Operations):
|
||||
connection.execute(
|
||||
"""
|
||||
delete from build_queue
|
||||
where :package_base is null or package_base = :package_base
|
||||
where (:package_base is null or package_base = :package_base) and repository = :repository
|
||||
""",
|
||||
{"package_base": package_base})
|
||||
{
|
||||
"package_base": package_base,
|
||||
"repository": self.repository_id.id,
|
||||
})
|
||||
|
||||
return self.with_connection(run, commit=True)
|
||||
|
||||
@ -55,7 +58,10 @@ class BuildOperations(Operations):
|
||||
def run(connection: Connection) -> list[Package]:
|
||||
return [
|
||||
Package.from_json(row["properties"])
|
||||
for row in connection.execute("""select * from build_queue""")
|
||||
for row in connection.execute(
|
||||
"""select properties from build_queue where repository = :repository""",
|
||||
{"repository": self.repository_id.id}
|
||||
)
|
||||
]
|
||||
|
||||
return self.with_connection(run)
|
||||
@ -71,12 +77,16 @@ class BuildOperations(Operations):
|
||||
connection.execute(
|
||||
"""
|
||||
insert into build_queue
|
||||
(package_base, properties)
|
||||
(package_base, properties, repository)
|
||||
values
|
||||
(:package_base, :properties)
|
||||
on conflict (package_base) do update set
|
||||
(:package_base, :properties, :repository)
|
||||
on conflict (package_base, repository) do update set
|
||||
properties = :properties
|
||||
""",
|
||||
{"package_base": package.base, "properties": package.view()})
|
||||
{
|
||||
"package_base": package.base,
|
||||
"properties": package.view(),
|
||||
"repository": self.repository_id.id,
|
||||
})
|
||||
|
||||
return self.with_connection(run, commit=True)
|
||||
|
@ -45,11 +45,13 @@ class LogsOperations(Operations):
|
||||
(row["created"], row["record"])
|
||||
for row in connection.execute(
|
||||
"""
|
||||
select created, record from logs where package_base = :package_base
|
||||
select created, record from logs
|
||||
where package_base = :package_base and repository = :repository
|
||||
order by created limit :limit offset :offset
|
||||
""",
|
||||
{
|
||||
"package_base": package_base,
|
||||
"repository": self.repository_id.id,
|
||||
"limit": limit,
|
||||
"offset": offset,
|
||||
})
|
||||
@ -70,15 +72,16 @@ class LogsOperations(Operations):
|
||||
connection.execute(
|
||||
"""
|
||||
insert into logs
|
||||
(package_base, version, created, record)
|
||||
(package_base, version, created, record, repository)
|
||||
values
|
||||
(:package_base, :version, :created, :record)
|
||||
(:package_base, :version, :created, :record, :repository)
|
||||
""",
|
||||
{
|
||||
"package_base": log_record_id.package_base,
|
||||
"version": log_record_id.version,
|
||||
"created": created,
|
||||
"record": record,
|
||||
"repository": self.repository_id.id,
|
||||
}
|
||||
)
|
||||
|
||||
@ -97,9 +100,15 @@ class LogsOperations(Operations):
|
||||
connection.execute(
|
||||
"""
|
||||
delete from logs
|
||||
where package_base = :package_base and (:version is null or version <> :version)
|
||||
where package_base = :package_base
|
||||
and repository = :repository
|
||||
and (:version is null or version <> :version)
|
||||
""",
|
||||
{"package_base": package_base, "version": version}
|
||||
{
|
||||
"package_base": package_base,
|
||||
"version": version,
|
||||
"repository": self.repository_id.id,
|
||||
}
|
||||
)
|
||||
|
||||
return self.with_connection(run, commit=True)
|
||||
|
@ -24,6 +24,7 @@ from pathlib import Path
|
||||
from typing import Any, TypeVar
|
||||
|
||||
from ahriman.core.log import LazyLogging
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
T = TypeVar("T")
|
||||
@ -35,16 +36,19 @@ class Operations(LazyLogging):
|
||||
|
||||
Attributes:
|
||||
path(Path): path to the database file
|
||||
repository_id(RepositoryId): repository unique identifier to perform implicit filtering
|
||||
"""
|
||||
|
||||
def __init__(self, path: Path) -> None:
|
||||
def __init__(self, path: Path, repository_id: RepositoryId) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
path(Path): path to the database file
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
"""
|
||||
self.path = path
|
||||
self.repository_id = repository_id
|
||||
|
||||
@staticmethod
|
||||
def factory(cursor: sqlite3.Cursor, row: tuple[Any, ...]) -> dict[str, Any]:
|
||||
|
@ -32,8 +32,7 @@ class PackageOperations(Operations):
|
||||
package operations
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def _package_remove_package_base(connection: Connection, package_base: str) -> None:
|
||||
def _package_remove_package_base(self, connection: Connection, package_base: str) -> None:
|
||||
"""
|
||||
remove package base information
|
||||
|
||||
@ -41,13 +40,15 @@ class PackageOperations(Operations):
|
||||
connection(Connection): database connection
|
||||
package_base(str): package base name
|
||||
"""
|
||||
connection.execute("""delete from package_statuses where package_base = :package_base""",
|
||||
{"package_base": package_base})
|
||||
connection.execute("""delete from package_bases where package_base = :package_base""",
|
||||
{"package_base": package_base})
|
||||
connection.execute(
|
||||
"""delete from package_statuses where package_base = :package_base and repository = :repository""",
|
||||
{"package_base": package_base, "repository": self.repository_id.id})
|
||||
connection.execute(
|
||||
"""delete from package_bases where package_base = :package_base and repository = :repository""",
|
||||
{"package_base": package_base, "repository": self.repository_id.id})
|
||||
|
||||
@staticmethod
|
||||
def _package_remove_packages(connection: Connection, package_base: str, current_packages: Iterable[str]) -> None:
|
||||
def _package_remove_packages(self, connection: Connection, package_base: str,
|
||||
current_packages: Iterable[str]) -> None:
|
||||
"""
|
||||
remove packages belong to the package base
|
||||
|
||||
@ -59,13 +60,17 @@ class PackageOperations(Operations):
|
||||
packages = [
|
||||
package
|
||||
for package in connection.execute(
|
||||
"""select package from packages where package_base = :package_base""", {"package_base": package_base})
|
||||
"""
|
||||
select package, repository from packages
|
||||
where package_base = :package_base and repository = :repository""",
|
||||
{"package_base": package_base, "repository": self.repository_id.id})
|
||||
if package["package"] not in current_packages
|
||||
]
|
||||
connection.executemany("""delete from packages where package = :package""", packages)
|
||||
connection.executemany(
|
||||
"""delete from packages where package = :package and repository = :repository""",
|
||||
packages)
|
||||
|
||||
@staticmethod
|
||||
def _package_update_insert_base(connection: Connection, package: Package) -> None:
|
||||
def _package_update_insert_base(self, connection: Connection, package: Package) -> None:
|
||||
"""
|
||||
insert base package into table
|
||||
|
||||
@ -76,10 +81,10 @@ class PackageOperations(Operations):
|
||||
connection.execute(
|
||||
"""
|
||||
insert into package_bases
|
||||
(package_base, version, source, branch, git_url, path, web_url, packager)
|
||||
(package_base, version, source, branch, git_url, path, web_url, packager, repository)
|
||||
values
|
||||
(:package_base, :version, :source, :branch, :git_url, :path, :web_url, :packager)
|
||||
on conflict (package_base) do update set
|
||||
(:package_base, :version, :source, :branch, :git_url, :path, :web_url, :packager, :repository)
|
||||
on conflict (package_base, repository) do update set
|
||||
version = :version, branch = :branch, git_url = :git_url, path = :path, web_url = :web_url,
|
||||
source = :source, packager = :packager
|
||||
""",
|
||||
@ -92,11 +97,11 @@ class PackageOperations(Operations):
|
||||
"web_url": package.remote.web_url,
|
||||
"source": package.remote.source.value,
|
||||
"packager": package.packager,
|
||||
"repository": self.repository_id.id,
|
||||
}
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _package_update_insert_packages(connection: Connection, package: Package) -> None:
|
||||
def _package_update_insert_packages(self, connection: Connection, package: Package) -> None:
|
||||
"""
|
||||
insert packages into table
|
||||
|
||||
@ -108,20 +113,27 @@ class PackageOperations(Operations):
|
||||
for name, description in package.packages.items():
|
||||
if description.architecture is None:
|
||||
continue # architecture is required
|
||||
package_list.append({"package": name, "package_base": package.base, **description.view()})
|
||||
package_list.append({
|
||||
"package": name,
|
||||
"package_base": package.base,
|
||||
"repository": self.repository_id.id,
|
||||
**description.view(),
|
||||
})
|
||||
connection.executemany(
|
||||
"""
|
||||
insert into packages
|
||||
(package, package_base, architecture, archive_size,
|
||||
build_date, depends, description, filename,
|
||||
"groups", installed_size, licenses, provides,
|
||||
url, make_depends, opt_depends, check_depends)
|
||||
url, make_depends, opt_depends, check_depends,
|
||||
repository)
|
||||
values
|
||||
(:package, :package_base, :architecture, :archive_size,
|
||||
:build_date, :depends, :description, :filename,
|
||||
:groups, :installed_size, :licenses, :provides,
|
||||
:url, :make_depends, :opt_depends, :check_depends)
|
||||
on conflict (package, architecture) do update set
|
||||
:url, :make_depends, :opt_depends, :check_depends,
|
||||
:repository)
|
||||
on conflict (package, architecture, repository) do update set
|
||||
package_base = :package_base, archive_size = :archive_size,
|
||||
build_date = :build_date, depends = :depends, description = :description, filename = :filename,
|
||||
"groups" = :groups, installed_size = :installed_size, licenses = :licenses, provides = :provides,
|
||||
@ -129,8 +141,7 @@ class PackageOperations(Operations):
|
||||
""",
|
||||
package_list)
|
||||
|
||||
@staticmethod
|
||||
def _package_update_insert_status(connection: Connection, package_base: str, status: BuildStatus) -> None:
|
||||
def _package_update_insert_status(self, connection: Connection, package_base: str, status: BuildStatus) -> None:
|
||||
"""
|
||||
insert base package status into table
|
||||
|
||||
@ -141,16 +152,21 @@ class PackageOperations(Operations):
|
||||
"""
|
||||
connection.execute(
|
||||
"""
|
||||
insert into package_statuses (package_base, status, last_updated)
|
||||
insert into package_statuses
|
||||
(package_base, status, last_updated, repository)
|
||||
values
|
||||
(:package_base, :status, :last_updated)
|
||||
on conflict (package_base) do update set
|
||||
(:package_base, :status, :last_updated, :repository)
|
||||
on conflict (package_base, repository) do update set
|
||||
status = :status, last_updated = :last_updated
|
||||
""",
|
||||
{"package_base": package_base, "status": status.status.value, "last_updated": status.timestamp})
|
||||
{
|
||||
"package_base": package_base,
|
||||
"status": status.status.value,
|
||||
"last_updated": status.timestamp,
|
||||
"repository": self.repository_id.id,
|
||||
})
|
||||
|
||||
@staticmethod
|
||||
def _packages_get_select_package_bases(connection: Connection) -> dict[str, Package]:
|
||||
def _packages_get_select_package_bases(self, connection: Connection) -> dict[str, Package]:
|
||||
"""
|
||||
select package bases from the table
|
||||
|
||||
@ -167,11 +183,13 @@ class PackageOperations(Operations):
|
||||
remote=RemoteSource.from_json(row),
|
||||
packages={},
|
||||
packager=row["packager"] or None,
|
||||
) for row in connection.execute("""select * from package_bases""")
|
||||
) for row in connection.execute(
|
||||
"""select * from package_bases where repository = :repository""",
|
||||
{"repository": self.repository_id.id}
|
||||
)
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _packages_get_select_packages(connection: Connection, packages: dict[str, Package]) -> dict[str, Package]:
|
||||
def _packages_get_select_packages(self, connection: Connection, packages: dict[str, Package]) -> dict[str, Package]:
|
||||
"""
|
||||
select packages from the table
|
||||
|
||||
@ -182,14 +200,16 @@ class PackageOperations(Operations):
|
||||
Returns:
|
||||
dict[str, Package]: map of the package base to its descriptor including individual packages
|
||||
"""
|
||||
for row in connection.execute("""select * from packages"""):
|
||||
for row in connection.execute(
|
||||
"""select * from packages where repository = :repository""",
|
||||
{"repository": self.repository_id.id}
|
||||
):
|
||||
if row["package_base"] not in packages:
|
||||
continue # normally must never happen though
|
||||
packages[row["package_base"]].packages[row["package"]] = PackageDescription.from_json(row)
|
||||
return packages
|
||||
|
||||
@staticmethod
|
||||
def _packages_get_select_statuses(connection: Connection) -> dict[str, BuildStatus]:
|
||||
def _packages_get_select_statuses(self, connection: Connection) -> dict[str, BuildStatus]:
|
||||
"""
|
||||
select package build statuses from the table
|
||||
|
||||
@ -201,7 +221,10 @@ class PackageOperations(Operations):
|
||||
"""
|
||||
return {
|
||||
row["package_base"]: BuildStatus.from_json({"status": row["status"], "timestamp": row["last_updated"]})
|
||||
for row in connection.execute("""select * from package_statuses""")
|
||||
for row in connection.execute(
|
||||
"""select * from package_statuses where repository = :repository""",
|
||||
{"repository": self.repository_id.id}
|
||||
)
|
||||
}
|
||||
|
||||
def package_remove(self, package_base: str) -> None:
|
||||
|
@ -40,7 +40,7 @@ class PatchOperations(Operations):
|
||||
Returns:
|
||||
list[PkgbuildPatch]: plain text patch for the package
|
||||
"""
|
||||
return self.patches_list(package_base, []).get(package_base, [])
|
||||
return self.patches_list(package_base, None).get(package_base, [])
|
||||
|
||||
def patches_insert(self, package_base: str, patch: PkgbuildPatch) -> None:
|
||||
"""
|
||||
@ -64,13 +64,13 @@ class PatchOperations(Operations):
|
||||
|
||||
return self.with_connection(run, commit=True)
|
||||
|
||||
def patches_list(self, package_base: str | None, variables: list[str]) -> dict[str, list[PkgbuildPatch]]:
|
||||
def patches_list(self, package_base: str | None, variables: list[str] | None) -> dict[str, list[PkgbuildPatch]]:
|
||||
"""
|
||||
extract all patches
|
||||
|
||||
Args:
|
||||
package_base(str | None): optional filter by package base
|
||||
variables(list[str]): extract patches only for specified PKGBUILD variables
|
||||
variables(list[str] | None): extract patches only for specified PKGBUILD variables
|
||||
|
||||
Returns:
|
||||
dict[str, list[PkgbuildPatch]]: map of package base to patch content
|
||||
@ -86,29 +86,30 @@ class PatchOperations(Operations):
|
||||
# we could use itertools & operator but why?
|
||||
patches: dict[str, list[PkgbuildPatch]] = defaultdict(list)
|
||||
for package, patch in self.with_connection(run):
|
||||
if variables and patch.key not in variables:
|
||||
if variables is not None and patch.key not in variables:
|
||||
continue
|
||||
patches[package].append(patch)
|
||||
return dict(patches)
|
||||
|
||||
def patches_remove(self, package_base: str, variables: list[str]) -> None:
|
||||
def patches_remove(self, package_base: str, variables: list[str] | None) -> None:
|
||||
"""
|
||||
remove patch set
|
||||
|
||||
Args:
|
||||
package_base(str): package base to clear patches
|
||||
variables(list[str]): remove patches only for specified PKGBUILD variables
|
||||
variables(list[str] | None): remove patches only for specified PKGBUILD variables
|
||||
"""
|
||||
def run_many(connection: Connection) -> None:
|
||||
patches = variables or [] # suppress mypy warning
|
||||
connection.executemany(
|
||||
"""delete from patches where package_base = :package_base and variable = :variable""",
|
||||
[{"package_base": package_base, "variable": variable} for variable in variables])
|
||||
[{"package_base": package_base, "variable": variable} for variable in patches])
|
||||
|
||||
def run(connection: Connection) -> None:
|
||||
connection.execute(
|
||||
"""delete from patches where package_base = :package_base""",
|
||||
{"package_base": package_base})
|
||||
|
||||
if variables:
|
||||
if variables is not None:
|
||||
return self.with_connection(run_many, commit=True)
|
||||
return self.with_connection(run, commit=True)
|
||||
|
@ -56,8 +56,11 @@ class SQLite(AuthOperations, BuildOperations, LogsOperations, PackageOperations,
|
||||
Self: fully initialized instance of the database
|
||||
"""
|
||||
path = cls.database_path(configuration)
|
||||
database = cls(path)
|
||||
_, repository_id = configuration.check_loaded()
|
||||
|
||||
database = cls(path, repository_id)
|
||||
database.init(configuration)
|
||||
|
||||
return database
|
||||
|
||||
@staticmethod
|
||||
|
@ -23,6 +23,8 @@ from collections.abc import Callable
|
||||
from pathlib import Path
|
||||
from typing import Any, Self
|
||||
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class BuildError(RuntimeError):
|
||||
"""
|
||||
@ -165,7 +167,7 @@ class MissingArchitectureError(ValueError):
|
||||
Args:
|
||||
command(str): command name which throws exception
|
||||
"""
|
||||
ValueError.__init__(self, f"Architecture required for subcommand {command}, but missing")
|
||||
ValueError.__init__(self, f"Architecture/repository required for subcommand {command}, but missing")
|
||||
|
||||
|
||||
class MultipleArchitecturesError(ValueError):
|
||||
@ -173,14 +175,18 @@ class MultipleArchitecturesError(ValueError):
|
||||
exception which will be raised if multiple architectures are not supported by the handler
|
||||
"""
|
||||
|
||||
def __init__(self, command: str) -> None:
|
||||
def __init__(self, command: str, repositories: list[RepositoryId] | None = None) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
command(str): command name which throws exception
|
||||
repositories(list[RepositoryId] | None, optional): found repository list (Default value = None)
|
||||
"""
|
||||
ValueError.__init__(self, f"Multiple architectures are not supported by subcommand {command}")
|
||||
message = f"Multiple architectures/repositories are not supported by subcommand {command}"
|
||||
if repositories is not None:
|
||||
message += f", got {repositories}"
|
||||
ValueError.__init__(self, message)
|
||||
|
||||
|
||||
class OptionError(ValueError):
|
||||
|
@ -30,6 +30,7 @@ from ahriman.core.util import walk
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.package_source import PackageSource
|
||||
from ahriman.models.remote_source import RemoteSource
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class RemotePull(LazyLogging):
|
||||
@ -42,13 +43,13 @@ class RemotePull(LazyLogging):
|
||||
repository_paths(RepositoryPaths): repository paths instance
|
||||
"""
|
||||
|
||||
def __init__(self, configuration: Configuration, architecture: str, section: str) -> None:
|
||||
def __init__(self, repository_id: RepositoryId, configuration: Configuration, section: str) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
architecture(str): repository architecture
|
||||
section(str): settings section name
|
||||
"""
|
||||
self.remote_source = RemoteSource(
|
||||
@ -58,7 +59,7 @@ class RemotePull(LazyLogging):
|
||||
branch=configuration.get(section, "pull_branch", fallback="master"),
|
||||
source=PackageSource.Local,
|
||||
)
|
||||
self.architecture = architecture
|
||||
self.architecture = repository_id.architecture
|
||||
self.repository_paths = configuration.repository_paths
|
||||
|
||||
def package_copy(self, pkgbuild_path: Path) -> None:
|
||||
|
@ -20,6 +20,7 @@
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.gitremote.remote_pull import RemotePull
|
||||
from ahriman.core.triggers import Trigger
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class RemotePullTrigger(Trigger):
|
||||
@ -56,15 +57,15 @@ class RemotePullTrigger(Trigger):
|
||||
}
|
||||
CONFIGURATION_SCHEMA_FALLBACK = "gitremote"
|
||||
|
||||
def __init__(self, architecture: str, configuration: Configuration) -> None:
|
||||
def __init__(self, repository_id: RepositoryId, configuration: Configuration) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
"""
|
||||
Trigger.__init__(self, architecture, configuration)
|
||||
Trigger.__init__(self, repository_id, configuration)
|
||||
self.targets = self.configuration_sections(configuration)
|
||||
|
||||
@classmethod
|
||||
@ -86,6 +87,6 @@ class RemotePullTrigger(Trigger):
|
||||
"""
|
||||
for target in self.targets:
|
||||
section, _ = self.configuration.gettype(
|
||||
target, self.architecture, fallback=self.CONFIGURATION_SCHEMA_FALLBACK)
|
||||
runner = RemotePull(self.configuration, self.architecture, section)
|
||||
target, self.repository_id, fallback=self.CONFIGURATION_SCHEMA_FALLBACK)
|
||||
runner = RemotePull(self.repository_id, self.configuration, section)
|
||||
runner.run()
|
||||
|
@ -24,6 +24,7 @@ from ahriman.core.gitremote.remote_push import RemotePush
|
||||
from ahriman.core.triggers import Trigger
|
||||
from ahriman.models.context_key import ContextKey
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
from ahriman.models.result import Result
|
||||
|
||||
|
||||
@ -67,15 +68,15 @@ class RemotePushTrigger(Trigger):
|
||||
}
|
||||
CONFIGURATION_SCHEMA_FALLBACK = "gitremote"
|
||||
|
||||
def __init__(self, architecture: str, configuration: Configuration) -> None:
|
||||
def __init__(self, repository_id: RepositoryId, configuration: Configuration) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
"""
|
||||
Trigger.__init__(self, architecture, configuration)
|
||||
Trigger.__init__(self, repository_id, configuration)
|
||||
self.targets = self.configuration_sections(configuration)
|
||||
|
||||
@classmethod
|
||||
@ -107,6 +108,6 @@ class RemotePushTrigger(Trigger):
|
||||
|
||||
for target in self.targets:
|
||||
section, _ = self.configuration.gettype(
|
||||
target, self.architecture, fallback=self.CONFIGURATION_SCHEMA_FALLBACK)
|
||||
target, self.repository_id, fallback=self.CONFIGURATION_SCHEMA_FALLBACK)
|
||||
runner = RemotePush(database, self.configuration, section)
|
||||
runner.run(result)
|
||||
|
@ -41,14 +41,14 @@ class SyncHttpClient(LazyLogging):
|
||||
timeout(int): HTTP request timeout in seconds
|
||||
"""
|
||||
|
||||
def __init__(self, section: str | None = None, configuration: Configuration | None = None, *,
|
||||
def __init__(self, configuration: Configuration | None = None, section: str | None = None, *,
|
||||
suppress_errors: bool = False) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
section(str, optional): settings section name (Default value = None)
|
||||
configuration(Configuration | None): configuration instance (Default value = None)
|
||||
section(str, optional): settings section name (Default value = None)
|
||||
suppress_errors(bool, optional): suppress logging of request errors (Default value = False)
|
||||
"""
|
||||
if configuration is None:
|
||||
|
@ -18,4 +18,3 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from ahriman.core.log.lazy_logging import LazyLogging
|
||||
from ahriman.core.log.log import Log
|
||||
|
@ -27,7 +27,7 @@ from ahriman.core.log.http_log_handler import HttpLogHandler
|
||||
from ahriman.models.log_handler import LogHandler
|
||||
|
||||
|
||||
class Log:
|
||||
class LogLoader:
|
||||
"""
|
||||
simple static method class which setups application loggers
|
||||
|
||||
@ -63,7 +63,7 @@ class Log:
|
||||
del JournalHandler
|
||||
return LogHandler.Journald # journald import was found
|
||||
except ImportError:
|
||||
if Log.DEFAULT_SYSLOG_DEVICE.exists():
|
||||
if LogLoader.DEFAULT_SYSLOG_DEVICE.exists():
|
||||
return LogHandler.Syslog
|
||||
return LogHandler.Console
|
||||
|
||||
@ -94,8 +94,7 @@ class Log:
|
||||
fileConfig(log_configuration, disable_existing_loggers=True)
|
||||
logging.debug("using %s logger", default_handler)
|
||||
except Exception:
|
||||
logging.basicConfig(filename=None, format=Log.DEFAULT_LOG_FORMAT,
|
||||
level=Log.DEFAULT_LOG_LEVEL)
|
||||
logging.basicConfig(filename=None, format=LogLoader.DEFAULT_LOG_FORMAT, level=LogLoader.DEFAULT_LOG_LEVEL)
|
||||
logging.exception("could not load logging from configuration, fallback to stderr")
|
||||
|
||||
HttpLogHandler.load(configuration, report=report)
|
@ -21,6 +21,7 @@ from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.formatters import BuildPrinter
|
||||
from ahriman.core.report.report import Report
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
from ahriman.models.result import Result
|
||||
|
||||
|
||||
@ -32,16 +33,16 @@ class Console(Report):
|
||||
use_utf(bool): print utf8 symbols instead of ASCII
|
||||
"""
|
||||
|
||||
def __init__(self, architecture: str, configuration: Configuration, section: str) -> None:
|
||||
def __init__(self, repository_id: RepositoryId, configuration: Configuration, section: str) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
section(str): settings section name
|
||||
"""
|
||||
Report.__init__(self, architecture, configuration)
|
||||
Report.__init__(self, repository_id, configuration)
|
||||
self.use_utf = configuration.getboolean(section, "use_utf", fallback=True)
|
||||
|
||||
def generate(self, packages: list[Package], result: Result) -> None:
|
||||
|
@ -27,6 +27,7 @@ from ahriman.core.report.jinja_template import JinjaTemplate
|
||||
from ahriman.core.report.report import Report
|
||||
from ahriman.core.util import pretty_datetime, utcnow
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
from ahriman.models.result import Result
|
||||
from ahriman.models.smtp_ssl_settings import SmtpSSLSettings
|
||||
|
||||
@ -48,17 +49,17 @@ class Email(Report, JinjaTemplate):
|
||||
user(str | None): username to authenticate via SMTP
|
||||
"""
|
||||
|
||||
def __init__(self, architecture: str, configuration: Configuration, section: str) -> None:
|
||||
def __init__(self, repository_id: RepositoryId, configuration: Configuration, section: str) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
section(str): settings section name
|
||||
"""
|
||||
Report.__init__(self, architecture, configuration)
|
||||
JinjaTemplate.__init__(self, section, configuration)
|
||||
Report.__init__(self, repository_id, configuration)
|
||||
JinjaTemplate.__init__(self, repository_id, configuration, section)
|
||||
|
||||
self.full_template_path = configuration.getpath(section, "full_template_path", fallback=None)
|
||||
self.template_path = configuration.getpath(section, "template_path")
|
||||
|
@ -21,6 +21,7 @@ from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.report.jinja_template import JinjaTemplate
|
||||
from ahriman.core.report.report import Report
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
from ahriman.models.result import Result
|
||||
|
||||
|
||||
@ -33,17 +34,17 @@ class HTML(Report, JinjaTemplate):
|
||||
template_path(Path): path to template for full package list
|
||||
"""
|
||||
|
||||
def __init__(self, architecture: str, configuration: Configuration, section: str) -> None:
|
||||
def __init__(self, repository_id: RepositoryId, configuration: Configuration, section: str) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
section(str): settings section name
|
||||
"""
|
||||
Report.__init__(self, architecture, configuration)
|
||||
JinjaTemplate.__init__(self, section, configuration)
|
||||
Report.__init__(self, repository_id, configuration)
|
||||
JinjaTemplate.__init__(self, repository_id, configuration, section)
|
||||
|
||||
self.report_path = configuration.getpath(section, "path")
|
||||
self.template_path = configuration.getpath(section, "template_path")
|
||||
|
@ -25,6 +25,7 @@ from pathlib import Path
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.sign.gpg import GPG
|
||||
from ahriman.core.util import pretty_datetime, pretty_size
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
from ahriman.models.result import Result
|
||||
from ahriman.models.sign_settings import SignSettings
|
||||
|
||||
@ -63,19 +64,20 @@ class JinjaTemplate:
|
||||
sign_targets(set[SignSettings]): targets to sign enabled in configuration
|
||||
"""
|
||||
|
||||
def __init__(self, section: str, configuration: Configuration) -> None:
|
||||
def __init__(self, repository_id: RepositoryId, configuration: Configuration, section: str) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
section(str): settings section name
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
section(str): settings section name
|
||||
"""
|
||||
self.link_path = configuration.get(section, "link_path")
|
||||
|
||||
# base template vars
|
||||
self.homepage = configuration.get(section, "homepage", fallback=None)
|
||||
self.name = configuration.repository_name
|
||||
self.name = repository_id.name
|
||||
|
||||
self.sign_targets, self.default_pgp_key = GPG.sign_options(configuration)
|
||||
|
||||
|
@ -23,6 +23,7 @@ from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.report.report import Report
|
||||
from ahriman.core.status.web_client import WebClient
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
from ahriman.models.result import Result
|
||||
from ahriman.models.waiter import Waiter
|
||||
|
||||
@ -39,16 +40,16 @@ class RemoteCall(Report):
|
||||
wait_timeout(int): timeout to wait external process
|
||||
"""
|
||||
|
||||
def __init__(self, architecture: str, configuration: Configuration, section: str) -> None:
|
||||
def __init__(self, repository_id: RepositoryId, configuration: Configuration, section: str) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
section(str): settings section name
|
||||
"""
|
||||
Report.__init__(self, architecture, configuration)
|
||||
Report.__init__(self, repository_id, configuration)
|
||||
|
||||
self.client = WebClient(configuration)
|
||||
|
||||
|
@ -24,6 +24,7 @@ from ahriman.core.exceptions import ReportError
|
||||
from ahriman.core.log import LazyLogging
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.report_settings import ReportSettings
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
from ahriman.models.result import Result
|
||||
|
||||
|
||||
@ -32,17 +33,15 @@ class Report(LazyLogging):
|
||||
base report generator
|
||||
|
||||
Attributes:
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
|
||||
Examples:
|
||||
``Report`` classes provide several method in order to operate with the report generation and additional class
|
||||
method ``load`` which can be used in order to determine right report instance::
|
||||
|
||||
>>> from ahriman.core.configuration import Configuration
|
||||
>>>
|
||||
>>> configuration = Configuration()
|
||||
>>> report = Report.load("x86_64", configuration, "email")
|
||||
>>> report = Report.load(RepositoryId("x86_64", "aur-clone"), configuration, "email")
|
||||
|
||||
The ``generate`` method can be used in order to perform the report itself, whereas ``run`` method handles
|
||||
exception and raises ``ReportFailed`` instead::
|
||||
@ -55,49 +54,49 @@ class Report(LazyLogging):
|
||||
>>> report.run(Result(), [])
|
||||
"""
|
||||
|
||||
def __init__(self, architecture: str, configuration: Configuration) -> None:
|
||||
def __init__(self, repository_id: RepositoryId, configuration: Configuration) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
"""
|
||||
self.architecture = architecture
|
||||
self.repository_id = repository_id
|
||||
self.configuration = configuration
|
||||
|
||||
@staticmethod
|
||||
def load(architecture: str, configuration: Configuration, target: str) -> Report:
|
||||
def load(repository_id: RepositoryId, configuration: Configuration, target: str) -> Report:
|
||||
"""
|
||||
load client from settings
|
||||
|
||||
Args:
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
target(str): target to generate report aka section name (e.g. html)
|
||||
|
||||
Returns:
|
||||
Report: client according to current settings
|
||||
"""
|
||||
section, provider_name = configuration.gettype(target, architecture)
|
||||
section, provider_name = configuration.gettype(target, repository_id)
|
||||
match ReportSettings.from_option(provider_name):
|
||||
case ReportSettings.HTML:
|
||||
from ahriman.core.report.html import HTML
|
||||
return HTML(architecture, configuration, section)
|
||||
return HTML(repository_id, configuration, section)
|
||||
case ReportSettings.Email:
|
||||
from ahriman.core.report.email import Email
|
||||
return Email(architecture, configuration, section)
|
||||
return Email(repository_id, configuration, section)
|
||||
case ReportSettings.Console:
|
||||
from ahriman.core.report.console import Console
|
||||
return Console(architecture, configuration, section)
|
||||
return Console(repository_id, configuration, section)
|
||||
case ReportSettings.Telegram:
|
||||
from ahriman.core.report.telegram import Telegram
|
||||
return Telegram(architecture, configuration, section)
|
||||
return Telegram(repository_id, configuration, section)
|
||||
case ReportSettings.RemoteCall:
|
||||
from ahriman.core.report.remote_call import RemoteCall
|
||||
return RemoteCall(architecture, configuration, section)
|
||||
return RemoteCall(repository_id, configuration, section)
|
||||
case _:
|
||||
return Report(architecture, configuration) # should never happen
|
||||
return Report(repository_id, configuration) # should never happen
|
||||
|
||||
def generate(self, packages: list[Package], result: Result) -> None:
|
||||
"""
|
||||
|
@ -21,6 +21,7 @@ from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.triggers import Trigger
|
||||
from ahriman.core.report.report import Report
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
from ahriman.models.result import Result
|
||||
|
||||
|
||||
@ -218,15 +219,15 @@ class ReportTrigger(Trigger):
|
||||
}
|
||||
}
|
||||
|
||||
def __init__(self, architecture: str, configuration: Configuration) -> None:
|
||||
def __init__(self, repository_id: RepositoryId, configuration: Configuration) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
"""
|
||||
Trigger.__init__(self, architecture, configuration)
|
||||
Trigger.__init__(self, repository_id, configuration)
|
||||
self.targets = self.configuration_sections(configuration)
|
||||
|
||||
@classmethod
|
||||
@ -251,5 +252,5 @@ class ReportTrigger(Trigger):
|
||||
packages(list[Package]): list of all available packages
|
||||
"""
|
||||
for target in self.targets:
|
||||
runner = Report.load(self.architecture, self.configuration, target)
|
||||
runner = Report.load(self.repository_id, self.configuration, target)
|
||||
runner.run(result, packages)
|
||||
|
@ -22,6 +22,7 @@ from ahriman.core.http import SyncHttpClient
|
||||
from ahriman.core.report.jinja_template import JinjaTemplate
|
||||
from ahriman.core.report.report import Report
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
from ahriman.models.result import Result
|
||||
|
||||
|
||||
@ -41,18 +42,18 @@ class Telegram(Report, JinjaTemplate, SyncHttpClient):
|
||||
TELEGRAM_API_URL = "https://api.telegram.org"
|
||||
TELEGRAM_MAX_CONTENT_LENGTH = 4096
|
||||
|
||||
def __init__(self, architecture: str, configuration: Configuration, section: str) -> None:
|
||||
def __init__(self, repository_id: RepositoryId, configuration: Configuration, section: str) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
section(str): settings section name
|
||||
"""
|
||||
Report.__init__(self, architecture, configuration)
|
||||
JinjaTemplate.__init__(self, section, configuration)
|
||||
SyncHttpClient.__init__(self, section, configuration)
|
||||
Report.__init__(self, repository_id, configuration)
|
||||
JinjaTemplate.__init__(self, repository_id, configuration, section)
|
||||
SyncHttpClient.__init__(self, configuration, section)
|
||||
|
||||
self.api_key = configuration.get(section, "api_key")
|
||||
self.chat_id = configuration.get(section, "chat_id")
|
||||
|
@ -32,6 +32,7 @@ from ahriman.core.util import package_like
|
||||
from ahriman.models.context_key import ContextKey
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.pacman_synchronization import PacmanSynchronization
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class Repository(Executor, UpdateHandler):
|
||||
@ -47,7 +48,7 @@ class Repository(Executor, UpdateHandler):
|
||||
>>>
|
||||
>>> configuration = Configuration()
|
||||
>>> database = SQLite.load(configuration)
|
||||
>>> repository = Repository.load("x86_64", configuration, database, report=True)
|
||||
>>> repository = Repository.load(RepositoryId("x86_64", "x86_64"), configuration, database, report=True)
|
||||
>>> known_packages = repository.packages()
|
||||
>>>
|
||||
>>> build_result = repository.process_build(known_packages)
|
||||
@ -58,13 +59,13 @@ class Repository(Executor, UpdateHandler):
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def load(cls, architecture: str, configuration: Configuration, database: SQLite, *, report: bool,
|
||||
def load(cls, repository_id: RepositoryId, configuration: Configuration, database: SQLite, *, report: bool,
|
||||
refresh_pacman_database: PacmanSynchronization = PacmanSynchronization.Disabled) -> Self:
|
||||
"""
|
||||
load instance from argument list
|
||||
|
||||
Args:
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
database(SQLite): database instance
|
||||
report(bool): force enable or disable reporting
|
||||
@ -74,7 +75,7 @@ class Repository(Executor, UpdateHandler):
|
||||
Returns:
|
||||
Self: fully loaded repository class instance
|
||||
"""
|
||||
instance = cls(architecture, configuration, database,
|
||||
instance = cls(repository_id, configuration, database,
|
||||
report=report, refresh_pacman_database=refresh_pacman_database)
|
||||
instance._set_context()
|
||||
return instance
|
||||
|
@ -27,6 +27,7 @@ from ahriman.core.status.client import Client
|
||||
from ahriman.core.triggers import TriggerLoader
|
||||
from ahriman.models.packagers import Packagers
|
||||
from ahriman.models.pacman_synchronization import PacmanSynchronization
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
from ahriman.models.repository_paths import RepositoryPaths
|
||||
from ahriman.models.user import User
|
||||
from ahriman.models.user_access import UserAccess
|
||||
@ -37,47 +38,65 @@ class RepositoryProperties(LazyLogging):
|
||||
repository internal objects holder
|
||||
|
||||
Attributes:
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
database(SQLite): database instance
|
||||
ignore_list(list[str]): package bases which will be ignored during auto updates
|
||||
name(str): repository name
|
||||
pacman(Pacman): alpm wrapper instance
|
||||
paths(RepositoryPaths): repository paths instance
|
||||
repo(Repo): repo commands wrapper instance
|
||||
reporter(Client): build status reporter instance
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
sign(GPG): GPG wrapper instance
|
||||
triggers(TriggerLoader): triggers holder
|
||||
vcs_allowed_age(int): maximal age of the VCS packages before they will be checked
|
||||
"""
|
||||
|
||||
def __init__(self, architecture: str, configuration: Configuration, database: SQLite, *, report: bool,
|
||||
def __init__(self, repository_id: RepositoryId, configuration: Configuration, database: SQLite, *, report: bool,
|
||||
refresh_pacman_database: PacmanSynchronization) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
database(SQLite): database instance
|
||||
report(bool): force enable or disable reporting
|
||||
refresh_pacman_database(PacmanSynchronization): pacman database synchronization level
|
||||
"""
|
||||
self.architecture = architecture
|
||||
self.repository_id = repository_id
|
||||
self.configuration = configuration
|
||||
self.database = database
|
||||
|
||||
self.name = configuration.repository_name
|
||||
self.vcs_allowed_age = configuration.getint("build", "vcs_allowed_age", fallback=0)
|
||||
|
||||
self.paths: RepositoryPaths = configuration.repository_paths # additional workaround for pycharm typing
|
||||
|
||||
self.ignore_list = configuration.getlist("build", "ignore_packages", fallback=[])
|
||||
self.pacman = Pacman(architecture, configuration, refresh_database=refresh_pacman_database)
|
||||
self.pacman = Pacman(repository_id, configuration, refresh_database=refresh_pacman_database)
|
||||
self.sign = GPG(configuration)
|
||||
self.repo = Repo(self.name, self.paths, self.sign.repository_sign_args)
|
||||
self.reporter = Client.load(configuration, report=report)
|
||||
self.triggers = TriggerLoader.load(architecture, configuration)
|
||||
self.triggers = TriggerLoader.load(repository_id, configuration)
|
||||
|
||||
@property
|
||||
def architecture(self) -> str:
|
||||
"""
|
||||
repository architecture for backward compatibility
|
||||
|
||||
Returns:
|
||||
str: repository architecture
|
||||
"""
|
||||
return self.repository_id.architecture
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""
|
||||
repository name for backward compatibility
|
||||
|
||||
Returns:
|
||||
str: repository name
|
||||
"""
|
||||
return self.repository_id.name
|
||||
|
||||
def packager(self, packagers: Packagers, package_base: str) -> User:
|
||||
"""
|
||||
|
@ -28,6 +28,7 @@ from multiprocessing import Process, Queue
|
||||
from threading import Lock, Thread
|
||||
|
||||
from ahriman.core.log import LazyLogging
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class Spawn(Thread, LazyLogging):
|
||||
@ -37,22 +38,23 @@ class Spawn(Thread, LazyLogging):
|
||||
|
||||
Attributes:
|
||||
active(dict[str, Process]): map of active child processes required to avoid zombies
|
||||
architecture(str): repository architecture
|
||||
command_arguments(list[str]): base command line arguments
|
||||
queue(Queue[tuple[str, bool, int]]): multiprocessing queue to read updates from processes
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
"""
|
||||
|
||||
def __init__(self, args_parser: argparse.ArgumentParser, architecture: str, command_arguments: list[str]) -> None:
|
||||
def __init__(self, args_parser: argparse.ArgumentParser, repository_id: RepositoryId,
|
||||
command_arguments: list[str]) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
args_parser(argparse.ArgumentParser): command line parser for the application
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
command_arguments(list[str]): base command line arguments
|
||||
"""
|
||||
Thread.__init__(self, name="spawn")
|
||||
self.architecture = architecture
|
||||
self.repository_id = repository_id
|
||||
|
||||
self.args_parser = args_parser
|
||||
self.command_arguments = command_arguments
|
||||
@ -77,20 +79,20 @@ class Spawn(Thread, LazyLogging):
|
||||
return name if value else f"no-{name}"
|
||||
|
||||
@staticmethod
|
||||
def process(callback: Callable[[argparse.Namespace, str], bool], args: argparse.Namespace, architecture: str,
|
||||
process_id: str, queue: Queue[tuple[str, bool, int]]) -> None: # pylint: disable=unsubscriptable-object
|
||||
def process(callback: Callable[[argparse.Namespace, RepositoryId], bool], args: argparse.Namespace,
|
||||
repository_id: RepositoryId, process_id: str, queue: Queue[tuple[str, bool, int]]) -> None: # pylint: disable=unsubscriptable-object
|
||||
"""
|
||||
helper to run external process
|
||||
|
||||
Args:
|
||||
callback(Callable[[argparse.Namespace, str], bool]): application run function (i.e. Handler.run method)
|
||||
args(argparse.Namespace): command line arguments
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
process_id(str): process unique identifier
|
||||
queue(Queue[tuple[str, bool, int]]): output queue
|
||||
"""
|
||||
start_time = time.monotonic()
|
||||
result = callback(args, architecture)
|
||||
result = callback(args, repository_id)
|
||||
stop_time = time.monotonic()
|
||||
|
||||
consumed_time = int(1000 * (stop_time - start_time))
|
||||
@ -128,7 +130,7 @@ class Spawn(Thread, LazyLogging):
|
||||
|
||||
callback = parsed.handler.call
|
||||
process = Process(target=self.process,
|
||||
args=(callback, parsed, self.architecture, process_id, self.queue),
|
||||
args=(callback, parsed, self.repository_id, process_id, self.queue),
|
||||
daemon=True)
|
||||
process.start()
|
||||
|
||||
|
@ -25,6 +25,7 @@ from ahriman.core.repository import Repository
|
||||
from ahriman.models.build_status import BuildStatus, BuildStatusEnum
|
||||
from ahriman.models.log_record_id import LogRecordId
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class Watcher(LazyLogging):
|
||||
@ -32,26 +33,26 @@ class Watcher(LazyLogging):
|
||||
package status watcher
|
||||
|
||||
Attributes:
|
||||
architecture(str): repository architecture
|
||||
database(SQLite): database instance
|
||||
known(dict[str, tuple[Package, BuildStatus]]): list of known packages. For the most cases ``packages`` should
|
||||
be used instead
|
||||
repository(Repository): repository object
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
status(BuildStatus): daemon status
|
||||
"""
|
||||
|
||||
def __init__(self, architecture: str, configuration: Configuration, database: SQLite) -> None:
|
||||
def __init__(self, repository_id: RepositoryId, configuration: Configuration, database: SQLite) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
database(SQLite): database instance
|
||||
"""
|
||||
self.architecture = architecture
|
||||
self.repository_id = repository_id
|
||||
self.database = database
|
||||
self.repository = Repository.load(architecture, configuration, database, report=False)
|
||||
self.repository = Repository.load(repository_id, configuration, database, report=False)
|
||||
|
||||
self.known: dict[str, tuple[Package, BuildStatus]] = {}
|
||||
self.status = BuildStatus()
|
||||
|
@ -51,7 +51,7 @@ class WebClient(Client, SyncHttpClient):
|
||||
configuration(Configuration): configuration instance
|
||||
"""
|
||||
suppress_errors = configuration.getboolean("settings", "suppress_http_log_errors", fallback=False)
|
||||
SyncHttpClient.__init__(self, "web", configuration, suppress_errors=suppress_errors)
|
||||
SyncHttpClient.__init__(self, configuration, "web", suppress_errors=suppress_errors)
|
||||
|
||||
self.address, self.use_unix_socket = self.parse_address(configuration)
|
||||
|
||||
|
@ -25,6 +25,7 @@ from ahriman.core.support.package_creator import PackageCreator
|
||||
from ahriman.core.support.pkgbuild.keyring_generator import KeyringGenerator
|
||||
from ahriman.core.triggers import Trigger
|
||||
from ahriman.models.context_key import ContextKey
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class KeyringTrigger(Trigger):
|
||||
@ -82,15 +83,15 @@ class KeyringTrigger(Trigger):
|
||||
},
|
||||
}
|
||||
|
||||
def __init__(self, architecture: str, configuration: Configuration) -> None:
|
||||
def __init__(self, repository_id: RepositoryId, configuration: Configuration) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
"""
|
||||
Trigger.__init__(self, architecture, configuration)
|
||||
Trigger.__init__(self, repository_id, configuration)
|
||||
self.targets = self.configuration_sections(configuration)
|
||||
|
||||
@classmethod
|
||||
@ -115,6 +116,6 @@ class KeyringTrigger(Trigger):
|
||||
database = ctx.get(ContextKey("database", SQLite))
|
||||
|
||||
for target in self.targets:
|
||||
generator = KeyringGenerator(database, sign, self.configuration, target)
|
||||
generator = KeyringGenerator(database, sign, self.repository_id, self.configuration, target)
|
||||
runner = PackageCreator(self.configuration, generator)
|
||||
runner.run()
|
||||
|
@ -21,6 +21,7 @@ from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.support.package_creator import PackageCreator
|
||||
from ahriman.core.support.pkgbuild.mirrorlist_generator import MirrorlistGenerator
|
||||
from ahriman.core.triggers import Trigger
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class MirrorlistTrigger(Trigger):
|
||||
@ -75,15 +76,15 @@ class MirrorlistTrigger(Trigger):
|
||||
},
|
||||
}
|
||||
|
||||
def __init__(self, architecture: str, configuration: Configuration) -> None:
|
||||
def __init__(self, repository_id: RepositoryId, configuration: Configuration) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
"""
|
||||
Trigger.__init__(self, architecture, configuration)
|
||||
Trigger.__init__(self, repository_id, configuration)
|
||||
self.targets = self.configuration_sections(configuration)
|
||||
|
||||
@classmethod
|
||||
@ -104,6 +105,6 @@ class MirrorlistTrigger(Trigger):
|
||||
trigger action which will be called at the start of the application
|
||||
"""
|
||||
for target in self.targets:
|
||||
generator = MirrorlistGenerator(self.configuration, target)
|
||||
generator = MirrorlistGenerator(self.repository_id, self.configuration, target)
|
||||
runner = PackageCreator(self.configuration, generator)
|
||||
runner.run()
|
||||
|
@ -66,6 +66,6 @@ class PackageCreator:
|
||||
# register package
|
||||
ctx = context.get()
|
||||
database: SQLite = ctx.get(ContextKey("database", SQLite))
|
||||
_, architecture = self.configuration.check_loaded()
|
||||
package = Package.from_build(local_path, architecture, None)
|
||||
_, repository_id = self.configuration.check_loaded()
|
||||
package = Package.from_build(local_path, repository_id.architecture, None)
|
||||
database.package_update(package, BuildStatus())
|
||||
|
@ -25,6 +25,7 @@ from ahriman.core.database import SQLite
|
||||
from ahriman.core.exceptions import PkgbuildGeneratorError
|
||||
from ahriman.core.sign.gpg import GPG
|
||||
from ahriman.core.support.pkgbuild.pkgbuild_generator import PkgbuildGenerator
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class KeyringGenerator(PkgbuildGenerator):
|
||||
@ -43,18 +44,20 @@ class KeyringGenerator(PkgbuildGenerator):
|
||||
trusted(list[str]): lif of trusted PGP keys
|
||||
"""
|
||||
|
||||
def __init__(self, database: SQLite, sign: GPG, configuration: Configuration, section: str) -> None:
|
||||
def __init__(self, database: SQLite, sign: GPG, repository_id: RepositoryId,
|
||||
configuration: Configuration, section: str) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
database(SQLite): database instance
|
||||
sign(GPG): GPG wrapper instance
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
section(str): settings section name
|
||||
"""
|
||||
self.sign = sign
|
||||
self.name = configuration.repository_name
|
||||
self.name = repository_id.name
|
||||
|
||||
# configuration fields
|
||||
packager_keys = [packager.key for packager in database.user_list(None, None) if packager.key is not None]
|
||||
|
@ -23,6 +23,7 @@ from pathlib import Path
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.support.pkgbuild.pkgbuild_generator import PkgbuildGenerator
|
||||
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class MirrorlistGenerator(PkgbuildGenerator):
|
||||
@ -38,24 +39,24 @@ class MirrorlistGenerator(PkgbuildGenerator):
|
||||
servers(list[str]): list of mirror servers
|
||||
"""
|
||||
|
||||
def __init__(self, configuration: Configuration, section: str) -> None:
|
||||
def __init__(self, repository_id: RepositoryId, configuration: Configuration, section: str) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
section(str): settings section name
|
||||
"""
|
||||
name = configuration.repository_name
|
||||
|
||||
# configuration fields
|
||||
self.servers = configuration.getlist(section, "servers")
|
||||
self.path = configuration.getpath(section, "path", fallback=Path("/etc") / "pacman.d" / f"{name}-mirrorlist")
|
||||
self.path = configuration.getpath(
|
||||
section, "path", fallback=Path("/etc") / "pacman.d" / f"{repository_id.name}-mirrorlist")
|
||||
self.path = self.path.relative_to("/") # in pkgbuild we are always operating with relative to / path
|
||||
# pkgbuild description fields
|
||||
self.pkgbuild_pkgname = configuration.get(section, "package", fallback=f"{name}-mirrorlist")
|
||||
self.pkgbuild_pkgname = configuration.get(section, "package", fallback=f"{repository_id.name}-mirrorlist")
|
||||
self.pkgbuild_pkgdesc = configuration.get(
|
||||
section, "description", fallback=f"{name} mirror list for use by pacman")
|
||||
section, "description", fallback=f"{repository_id.name} mirror list for use by pacman")
|
||||
self.pkgbuild_license = configuration.getlist(section, "license", fallback=["Unlicense"])
|
||||
self.pkgbuild_url = configuration.get(section, "homepage", fallback="")
|
||||
|
||||
|
@ -19,9 +19,8 @@
|
||||
#
|
||||
from __future__ import annotations
|
||||
|
||||
import functools
|
||||
|
||||
from collections.abc import Iterable
|
||||
from functools import partial
|
||||
|
||||
from ahriman.core.exceptions import PartitionError
|
||||
from ahriman.core.util import minmax, partition
|
||||
@ -102,10 +101,11 @@ class Tree:
|
||||
>>> from ahriman.core.configuration import Configuration
|
||||
>>> from ahriman.core.database import SQLite
|
||||
>>> from ahriman.core.repository import Repository
|
||||
>>> from ahriman.models.repository_id import RepositoryId
|
||||
>>>
|
||||
>>> configuration = Configuration()
|
||||
>>> database = SQLite.load(configuration)
|
||||
>>> repository = Repository.load("x86_64", configuration, database, report=True)
|
||||
>>> repository = Repository.load(RepositoryId("x86_64", "aur-clone"), configuration, database, report=True)
|
||||
>>> packages = repository.packages()
|
||||
>>>
|
||||
>>> tree = Tree.resolve(packages)
|
||||
@ -242,7 +242,7 @@ class Tree:
|
||||
unprocessed = self.leaves[:]
|
||||
while unprocessed:
|
||||
# additional workaround with partial in order to hide cell-var-from-loop pylint warning
|
||||
predicate = functools.partial(Leaf.is_root, packages=unprocessed)
|
||||
predicate = partial(Leaf.is_root, packages=unprocessed)
|
||||
new_level, unprocessed = partition(unprocessed, predicate)
|
||||
unsorted.append(new_level)
|
||||
|
||||
@ -252,7 +252,7 @@ class Tree:
|
||||
next_level = unsorted[next_num]
|
||||
|
||||
# change lists inside the collection
|
||||
predicate = functools.partial(Leaf.is_dependency, packages=next_level)
|
||||
predicate = partial(Leaf.is_dependency, packages=next_level)
|
||||
unsorted[current_num], to_be_moved = partition(current_level, predicate)
|
||||
unsorted[next_num].extend(to_be_moved)
|
||||
|
||||
@ -279,12 +279,12 @@ class Tree:
|
||||
|
||||
while True: # python doesn't allow to use walrus operator to unpack tuples
|
||||
# get packages which depend on packages in chunk
|
||||
predicate = functools.partial(Leaf.is_root, packages=chunk)
|
||||
predicate = partial(Leaf.is_root, packages=chunk)
|
||||
unprocessed, new_dependent = partition(unprocessed, predicate)
|
||||
chunk.extend(new_dependent)
|
||||
|
||||
# get packages which are dependency of packages in chunk
|
||||
predicate = functools.partial(Leaf.is_dependency, packages=chunk)
|
||||
predicate = partial(Leaf.is_dependency, packages=chunk)
|
||||
new_dependencies, unprocessed = partition(unprocessed, predicate)
|
||||
chunk.extend(new_dependencies)
|
||||
|
||||
|
@ -23,6 +23,7 @@ from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.configuration.schema import ConfigurationSchema
|
||||
from ahriman.core.log import LazyLogging
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
from ahriman.models.result import Result
|
||||
|
||||
|
||||
@ -34,8 +35,8 @@ class Trigger(LazyLogging):
|
||||
CONFIGURATION_SCHEMA(ConfigurationSchema): (class attribute) configuration schema template
|
||||
CONFIGURATION_SCHEMA_FALLBACK(str | None): (class attribute) optional fallback option for defining
|
||||
configuration schema type used
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
|
||||
Examples:
|
||||
This class must be used in order to create own extension. Basically idea is the following::
|
||||
@ -51,26 +52,37 @@ class Trigger(LazyLogging):
|
||||
>>> configuration = Configuration()
|
||||
>>> configuration.set_option("build", "triggers", "my.awesome.package.CustomTrigger")
|
||||
>>>
|
||||
>>> loader = TriggerLoader.load("x86_64", configuration)
|
||||
>>> loader = TriggerLoader.load(RepositoryId("x86_64", "aur-clone"), configuration)
|
||||
>>> loader.on_result(Result(), [])
|
||||
"""
|
||||
|
||||
CONFIGURATION_SCHEMA: ConfigurationSchema = {}
|
||||
CONFIGURATION_SCHEMA_FALLBACK: str | None = None
|
||||
|
||||
def __init__(self, architecture: str, configuration: Configuration) -> None:
|
||||
def __init__(self, repository_id: RepositoryId, configuration: Configuration) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
"""
|
||||
self.architecture = architecture
|
||||
self.repository_id = repository_id
|
||||
self.configuration = configuration
|
||||
|
||||
@property
|
||||
def architecture(self) -> str:
|
||||
"""
|
||||
repository architecture for backward compatibility
|
||||
|
||||
Returns:
|
||||
str: repository architecture
|
||||
"""
|
||||
return self.repository_id.architecture
|
||||
|
||||
@classmethod
|
||||
def configuration_schema(cls, architecture: str, configuration: Configuration | None) -> ConfigurationSchema:
|
||||
def configuration_schema(cls, repository_id: RepositoryId,
|
||||
configuration: Configuration | None) -> ConfigurationSchema:
|
||||
"""
|
||||
configuration schema based on supplied service configuration
|
||||
|
||||
@ -78,7 +90,7 @@ class Trigger(LazyLogging):
|
||||
Schema must be in cerberus format, for details and examples you can check built-in triggers.
|
||||
|
||||
Args:
|
||||
architecture(str): repository architecture
|
||||
repository_id(str): repository unique identifier
|
||||
configuration(Configuration | None): configuration instance. If set to None, the default schema
|
||||
should be returned
|
||||
|
||||
@ -93,7 +105,7 @@ class Trigger(LazyLogging):
|
||||
if not configuration.has_section(target):
|
||||
continue
|
||||
section, schema_name = configuration.gettype(
|
||||
target, architecture, fallback=cls.CONFIGURATION_SCHEMA_FALLBACK)
|
||||
target, repository_id, fallback=cls.CONFIGURATION_SCHEMA_FALLBACK)
|
||||
if schema_name not in cls.CONFIGURATION_SCHEMA:
|
||||
continue
|
||||
result[section] = cls.CONFIGURATION_SCHEMA[schema_name]
|
||||
|
@ -31,6 +31,7 @@ from ahriman.core.exceptions import ExtensionError
|
||||
from ahriman.core.log import LazyLogging
|
||||
from ahriman.core.triggers import Trigger
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
from ahriman.models.result import Result
|
||||
|
||||
|
||||
@ -49,7 +50,7 @@ class TriggerLoader(LazyLogging):
|
||||
|
||||
Having such configuration you can create instance of the loader::
|
||||
|
||||
>>> loader = TriggerLoader.load("x86_64", configuration)
|
||||
>>> loader = TriggerLoader.load(RepositoryId("x86_64", "aur-clone"), configuration)
|
||||
>>> print(loader.triggers)
|
||||
|
||||
After that you are free to run triggers::
|
||||
@ -65,12 +66,12 @@ class TriggerLoader(LazyLogging):
|
||||
self.triggers: list[Trigger] = []
|
||||
|
||||
@classmethod
|
||||
def load(cls, architecture: str, configuration: Configuration) -> Self:
|
||||
def load(cls, repository_id: RepositoryId, configuration: Configuration) -> Self:
|
||||
"""
|
||||
create instance from configuration
|
||||
|
||||
Args:
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
|
||||
Returns:
|
||||
@ -78,7 +79,7 @@ class TriggerLoader(LazyLogging):
|
||||
"""
|
||||
instance = cls()
|
||||
instance.triggers = [
|
||||
instance.load_trigger(trigger, architecture, configuration)
|
||||
instance.load_trigger(trigger, repository_id, configuration)
|
||||
for trigger in instance.selected_triggers(configuration)
|
||||
]
|
||||
|
||||
@ -166,13 +167,13 @@ class TriggerLoader(LazyLogging):
|
||||
except ModuleNotFoundError:
|
||||
raise ExtensionError(f"Module {package} not found") from None
|
||||
|
||||
def load_trigger(self, module_path: str, architecture: str, configuration: Configuration) -> Trigger:
|
||||
def load_trigger(self, module_path: str, repository_id: RepositoryId, configuration: Configuration) -> Trigger:
|
||||
"""
|
||||
load trigger by module path
|
||||
|
||||
Args:
|
||||
module_path(str): module import path to load
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
|
||||
Returns:
|
||||
@ -183,7 +184,7 @@ class TriggerLoader(LazyLogging):
|
||||
"""
|
||||
trigger_type = self.load_trigger_class(module_path)
|
||||
try:
|
||||
trigger = trigger_type(architecture, configuration)
|
||||
trigger = trigger_type(repository_id, configuration)
|
||||
except Exception:
|
||||
raise ExtensionError(f"Could not load instance of trigger from {trigger_type} loaded from {module_path}")
|
||||
|
||||
|
@ -25,32 +25,44 @@ from typing import Any
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.upload.http_upload import HttpUpload
|
||||
from ahriman.core.upload.upload import Upload
|
||||
from ahriman.core.util import walk
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
|
||||
|
||||
class Github(HttpUpload):
|
||||
class GitHub(Upload, HttpUpload):
|
||||
"""
|
||||
upload files to GitHub releases
|
||||
|
||||
Attributes:
|
||||
github_owner(str): GitHub repository owner
|
||||
github_release_tag(str): GitHub release tag
|
||||
github_release_tag_name(str): GitHub release tag name
|
||||
github_repository(str): GitHub repository name
|
||||
"""
|
||||
|
||||
def __init__(self, architecture: str, configuration: Configuration, section: str) -> None:
|
||||
def __init__(self, repository_id: RepositoryId, configuration: Configuration, section: str) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
architecture(str): repository architecture
|
||||
repository_id(RepositoryId): repository unique identifier
|
||||
configuration(Configuration): configuration instance
|
||||
section(str): settings section name
|
||||
"""
|
||||
HttpUpload.__init__(self, architecture, configuration, section)
|
||||
Upload.__init__(self, repository_id, configuration)
|
||||
HttpUpload.__init__(self, configuration, section)
|
||||
|
||||
self.github_owner = configuration.get(section, "owner")
|
||||
self.github_repository = configuration.get(section, "repository")
|
||||
|
||||
if configuration.getboolean(section, "use_full_release_name", fallback=False):
|
||||
self.github_release_tag = f"{repository_id.name}-{repository_id.architecture}"
|
||||
self.github_release_tag_name = f"{repository_id.name} {repository_id.architecture}"
|
||||
else:
|
||||
self.github_release_tag_name = self.github_release_tag = repository_id.architecture
|
||||
|
||||
def asset_remove(self, release: dict[str, Any], name: str) -> None:
|
||||
"""
|
||||
remove asset from the release by name
|
||||
@ -136,7 +148,10 @@ class Github(HttpUpload):
|
||||
dict[str, Any]: GitHub API release object for the new release
|
||||
"""
|
||||
url = f"https://api.github.com/repos/{self.github_owner}/{self.github_repository}/releases"
|
||||
response = self.make_request("POST", url, json={"tag_name": self.architecture, "name": self.architecture})
|
||||
response = self.make_request("POST", url, json={
|
||||
"tag_name": self.github_release_tag,
|
||||
"name": self.github_release_tag_name,
|
||||
})
|
||||
release: dict[str, Any] = response.json()
|
||||
return release
|
||||
|
||||
@ -147,7 +162,7 @@ class Github(HttpUpload):
|
||||
Returns:
|
||||
dict[str, Any] | None: GitHub API release object if release found and None otherwise
|
||||
"""
|
||||
url = f"https://api.github.com/repos/{self.github_owner}/{self.github_repository}/releases/tags/{self.architecture}"
|
||||
url = f"https://api.github.com/repos/{self.github_owner}/{self.github_repository}/releases/tags/{self.github_release_tag}"
|
||||
try:
|
||||
response = self.make_request("GET", url)
|
||||
release: dict[str, Any] = response.json()
|
||||
|
@ -21,28 +21,14 @@ import hashlib
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.http import SyncHttpClient
|
||||
from ahriman.core.upload.upload import Upload
|
||||
|
||||
|
||||
class HttpUpload(Upload, SyncHttpClient):
|
||||
class HttpUpload(SyncHttpClient):
|
||||
"""
|
||||
helper for the http based uploads
|
||||
"""
|
||||
|
||||
def __init__(self, architecture: str, configuration: Configuration, section: str) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
section(str): configuration section name
|
||||
"""
|
||||
Upload.__init__(self, architecture, configuration)
|
||||
SyncHttpClient.__init__(self, section, configuration)
|
||||
|
||||
@staticmethod
|
||||
def calculate_hash(path: Path) -> str:
|
||||
"""
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user