Compare commits

..

10 Commits

Author SHA1 Message Date
5cc4cb47dd Release 2.20.0rc1 2026-02-18 10:40:00 +02:00
431b1a7150 feat: implement CSRF protection 2026-02-17 03:41:45 +02:00
3b43861bcf feat: handle only unknownpackageerror on aur load 2026-02-17 03:41:45 +02:00
c1e9534bc3 bug: filter logs by repository (twice) before rotation 2026-02-17 01:43:17 +02:00
cdd0ffbbd2 bug: do not clear queue on queue fetch failures 2026-02-17 01:34:54 +02:00
9fb93e4697 docs: correct docstring for list_flatmap method 2026-02-17 01:27:59 +02:00
953048422c bug: correct vcs definition for cvs packages 2026-02-17 01:18:36 +02:00
2cc486eb59 bug: load gitremote triggers configuration schema from non-standard
paths
2026-02-16 22:58:11 +02:00
93c36fb429 docs: update documentation for the lasts archive feature 2026-02-16 22:07:34 +02:00
2d6d42f969 feat: archive package tree implementation (#153)
* store built packages in archive tree instead of repository

* write tests to support new changes

* implement atomic_move method, move files only with lock

* use generic packages tree for all repos

* lookup through archive packages before build

* add archive trigger

* add archive trigger

* regenerate docs

* gpg loader fix

* support requires repostory flag

* drop excess REQUIRES_REPOSITORY

* simplify symlionk creation

* remove generators

* fix sttyle

* add separate function for symlinks creation

* fix rebase

* add note about slicing

* smol refactoring of archive_tree class

* remove duplicate code

* fix typos

* few review fixes

* monor fixes and typos

* clean empty directories

* remove side effect from getter

* drop recursive remove

* ensure_exists now accepts only argument

* add package like guard to symlinks fix

* speedup archive_lookup processing by iterrupting cycle

* remove custom filelock

* fix naming

* remove remove flag from repo

* review fixes

* restore wrapper around filelock

* extract repository explorer to separate class

* docs update

* fix ide findings
2026-02-16 00:12:51 +02:00
44 changed files with 2258 additions and 1684 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -28,6 +28,14 @@ ahriman.core.repository.executor module
:no-undoc-members: :no-undoc-members:
:show-inheritance: :show-inheritance:
ahriman.core.repository.explorer module
---------------------------------------
.. automodule:: ahriman.core.repository.explorer
:members:
:no-undoc-members:
:show-inheritance:
ahriman.core.repository.package\_info module ahriman.core.repository.package\_info module
-------------------------------------------- --------------------------------------------

View File

@@ -120,6 +120,20 @@ Having default root as ``/var/lib/ahriman`` (differs from container though), the
/var/lib/ahriman/ /var/lib/ahriman/
├── ahriman.db ├── ahriman.db
├── archive
│ ├── packages
│ │ └── a
│ │ └── ahriman
│ │ └── ahriman-2.0.0-1-any.pkg.tar.zst
│ └── repos
│ └── 2026
│ └── 01
│ └── 01
│ └── aur
│ └── x86_64
│ ├── ahriman-2.0.0-1-any.pkg.tar.zst -> ../../../../../../packages/a/ahriman/ahriman-2.0.0-1-any.pkg.tar.zst
│ ├── aur.db -> aur.db.tar.gz
│ └── aur.db.tar.gz
├── cache ├── cache
├── chroot ├── chroot
│ └── aur │ └── aur
@@ -139,6 +153,7 @@ Having default root as ``/var/lib/ahriman`` (differs from container though), the
└── repository └── repository
└── aur └── aur
└── x86_64 └── x86_64
├── ahriman-2.0.0-1-any.pkg.tar.zst -> ../../../archive/packages/a/ahriman/ahriman-2.0.0-1-any.pkg.tar.zst
├── aur.db -> aur.db.tar.gz ├── aur.db -> aur.db.tar.gz
├── aur.db.tar.gz ├── aur.db.tar.gz
├── aur.files -> aur.files.tar.gz ├── aur.files -> aur.files.tar.gz
@@ -146,11 +161,18 @@ Having default root as ``/var/lib/ahriman`` (differs from container though), the
There are multiple subdirectories, some of them are commons for any repository, but some of them are not. There are multiple subdirectories, some of them are commons for any repository, but some of them are not.
* ``archive`` is the package archive directory. It is common for all repositories and architectures and contains two subdirectories:
* ``archive/packages/{first_letter}/{package_base}`` stores the actual built package files and their signatures.
* ``archive/repos/{YYYY}/{MM}/{DD}/{repository}/{architecture}`` contains daily repository snapshots. Each snapshot is a repository database with symlinks pointing to the corresponding packages in the ``archive/packages`` tree.
The archive also allows the build process to skip rebuilding a package if a matching version already exists.
* ``cache`` is a directory with locally stored PKGBUILD's and VCS packages. It is common for all repositories and architectures. * ``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). * ``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 a 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. * ``packages/{repository}/{architecture}`` is a directory with prebuilt packages. When a 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 the repository and architecture specific caches for pacman's databases. * ``pacman/{repository}/{architecture}`` is the repository and architecture specific caches for pacman's databases.
* ``repository/{repository}/{architecture}`` is a repository packages directory. * ``repository/{repository}/{architecture}`` is a repository packages directory. Package files in this directory are symlinks to the archive.
Normally you should avoid direct interaction with the application tree. For tree migration process refer to the :doc:`migration notes <migrations/index>`. Normally you should avoid direct interaction with the application tree. For tree migration process refer to the :doc:`migration notes <migrations/index>`.

View File

@@ -97,13 +97,6 @@ libalpm and AUR related configuration. Group name can refer to architecture, e.g
* ``sync_files_database`` - download files database from mirror, boolean, required. * ``sync_files_database`` - download files database from mirror, boolean, required.
* ``use_ahriman_cache`` - use local pacman package cache instead of system one, boolean, required. With this option enabled you might want to refresh database periodically (available as additional flag for some subcommands). If set to ``no``, databases must be synchronized manually. * ``use_ahriman_cache`` - use local pacman package cache instead of system one, boolean, required. With this option enabled you might want to refresh database periodically (available as additional flag for some subcommands). If set to ``no``, databases must be synchronized manually.
``archive`` group
-----------------
Describes settings for packages archives management extensions.
* ``keep_built_packages`` - keep this amount of built packages with different versions, integer, required. ``0`` (or negative number) will effectively disable archives removal.
``auth`` group ``auth`` group
-------------- --------------
@@ -189,6 +182,13 @@ Web server settings. This feature requires ``aiohttp`` libraries to be installed
* ``unix_socket_unsafe`` - set unsafe (o+w) permissions to unix socket, boolean, optional, default ``yes``. This option is enabled by default, because it is supposed that unix socket is created in safe environment (only web service is supposed to be used in unsafe), but it can be disabled by configuration. * ``unix_socket_unsafe`` - set unsafe (o+w) permissions to unix socket, boolean, optional, default ``yes``. This option is enabled by default, because it is supposed that unix socket is created in safe environment (only web service is supposed to be used in unsafe), but it can be disabled by configuration.
* ``wait_timeout`` - wait timeout in seconds, maximum amount of time to be waited before lock will be free, integer, optional. * ``wait_timeout`` - wait timeout in seconds, maximum amount of time to be waited before lock will be free, integer, optional.
``archive`` group
-----------------
Describes settings for packages archives management extensions.
* ``keep_built_packages`` - keep this amount of built packages with different versions, integer, required. ``0`` will effectively disable archives removal.
``keyring`` group ``keyring`` group
----------------- -----------------
@@ -208,12 +208,12 @@ Keyring generator plugin
* ``revoked`` - list of revoked packagers keys, space separated list of strings, optional. * ``revoked`` - list of revoked packagers keys, space separated list of strings, optional.
* ``trusted`` - list of master keys, space separated list of strings, optional, if not set, the ``key`` option from ``sign`` group will be used. * ``trusted`` - list of master keys, space separated list of strings, optional, if not set, the ``key`` option from ``sign`` group will be used.
``housekeeping`` group ``logs-rotation`` group
---------------------- -----------------------
This section describes settings for the ``ahriman.core.housekeeping.LogsRotationTrigger`` plugin. This section describes settings for the ``ahriman.core.housekeeping.LogsRotationTrigger`` plugin.
* ``keep_last_logs`` - amount of build logs to be kept for each package, integer, optional ,default ``0``. Logs will be cleared at the end of each process. * ``keep_last_logs`` - amount of build logs to be kept for each package, integer, required. Logs will be cleared at the end of each process.
``mirrorlist`` group ``mirrorlist`` group
-------------------- --------------------
@@ -250,6 +250,7 @@ Available options are:
Remote pull trigger Remote pull trigger
^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
* ``type`` - type of the pull, string, optional, must be set to ``gitremote`` if exists.
* ``pull_url`` - URL of the remote repository from which PKGBUILDs can be pulled before build process, string, required. * ``pull_url`` - URL of the remote repository from which PKGBUILDs can be pulled before build process, string, required.
* ``pull_branch`` - branch of the remote repository from which PKGBUILDs can be pulled before build process, string, optional, default is ``master``. * ``pull_branch`` - branch of the remote repository from which PKGBUILDs can be pulled before build process, string, optional, default is ``master``.
@@ -270,6 +271,7 @@ Available options are:
Remote push trigger Remote push trigger
^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
* ``type`` - type of the push, string, optional, must be set to ``gitremote`` if exists.
* ``commit_email`` - git commit email, string, optional, default is ``ahriman@localhost``. * ``commit_email`` - git commit email, string, optional, default is ``ahriman@localhost``.
* ``commit_user`` - git commit user, string, optional, default is ``ahriman``. * ``commit_user`` - git commit user, string, optional, default is ``ahriman``.
* ``push_url`` - URL of the remote repository to which PKGBUILDs should be pushed after build process, string, required. * ``push_url`` - URL of the remote repository to which PKGBUILDs should be pushed after build process, string, required.

View File

@@ -40,6 +40,8 @@ docutils==0.21.2
# sphinx # sphinx
# sphinx-argparse # sphinx-argparse
# sphinx-rtd-theme # sphinx-rtd-theme
filelock==3.24.0
# via ahriman (pyproject.toml)
frozenlist==1.6.0 frozenlist==1.6.0
# via # via
# aiohttp # aiohttp

View File

@@ -1,7 +1,7 @@
Triggers Triggers
======== ========
The package provides ability to write custom extensions which will be run on (the most) actions, e.g. after updates. By default ahriman provides three types of extensions - reporting, files uploading and PKGBUILD synchronization. Each extension must derive from the ``ahriman.core.triggers.Trigger`` class and should implement at least one of the abstract methods: The package provides ability to write custom extensions which will be run on (the most) actions, e.g. after updates. By default ahriman provides several types of extensions - reporting, files uploading, PKGBUILD synchronization, repository archiving, housekeeping and distributed builds support. Each extension must derive from the ``ahriman.core.triggers.Trigger`` class and should implement at least one of the abstract methods:
* ``on_result`` - trigger action which will be called after build process, the build result and the list of repository packages will be supplied as arguments. * ``on_result`` - trigger action which will be called after build process, the build result and the list of repository packages will be supplied as arguments.
* ``on_start`` - trigger action which will be called right before the start of the application process. * ``on_start`` - trigger action which will be called right before the start of the application process.
@@ -14,6 +14,11 @@ Built-in triggers
For the configuration details and settings explanation kindly refer to the :doc:`documentation <configuration>`. For the configuration details and settings explanation kindly refer to the :doc:`documentation <configuration>`.
``ahriman.core.archive.ArchiveTrigger``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This trigger provides date-based snapshots of the repository. It organizes packages into a daily directory tree (``repos/YYYY/MM/DD``) with its own pacman database. On each run it creates symlinks from the daily snapshot to the actual package archives and maintains the database accordingly. It also takes care of cleaning up broken symlinks and empty directories for packages which have been removed.
``ahriman.core.distributed.WorkerLoaderTrigger`` ``ahriman.core.distributed.WorkerLoaderTrigger``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -36,6 +41,16 @@ In order to update those packages you would need to clone your repository separa
This trigger will be called right after build process (``on_result``). It will pick PKGBUILDs for the updated packages, pull them (together with any other files) and commit and push changes to remote repository. No real use cases, but the most of user repositories do it. This trigger will be called right after build process (``on_result``). It will pick PKGBUILDs for the updated packages, pull them (together with any other files) and commit and push changes to remote repository. No real use cases, but the most of user repositories do it.
``ahriman.core.housekeeping.ArchiveRotationTrigger``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This trigger removes old package versions from the archive directory. It implements ``on_result`` and, after each build, compares available versions for updated packages and removes the older ones, keeping only the last N versions as configured by ``keep_built_packages`` option.
``ahriman.core.housekeeping.LogsRotationTrigger``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Simple trigger to rotate build logs. It implements ``on_result`` and removes old log records after each build process, keeping only the last N records as configured by ``keep_last_logs`` option.
``ahriman.core.report.ReportTrigger`` ``ahriman.core.report.ReportTrigger``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@@ -2,7 +2,7 @@
pkgbase='ahriman' pkgbase='ahriman'
pkgname=('ahriman' 'ahriman-core' 'ahriman-triggers' 'ahriman-web') pkgname=('ahriman' 'ahriman-core' 'ahriman-triggers' 'ahriman-web')
pkgver=2.19.0 pkgver=2.20.0rc1
pkgrel=1 pkgrel=1
pkgdesc="ArcH linux ReposItory MANager" pkgdesc="ArcH linux ReposItory MANager"
arch=('any') arch=('any')

View File

@@ -1,6 +1,6 @@
# AUTOMATICALLY GENERATED by `shtab` # AUTOMATICALLY GENERATED by `shtab`
_shtab_ahriman_subparsers=('add' 'aur-search' 'check' 'clean' 'config' 'config-validate' 'copy' 'daemon' 'help' 'help-commands-unsafe' 'help-updates' 'help-version' 'init' 'key-import' 'package-add' 'package-changes' 'package-changes-remove' 'package-copy' 'package-remove' 'package-status' 'package-status-remove' 'package-status-update' 'package-update' 'patch-add' 'patch-list' 'patch-remove' 'patch-set-add' 'rebuild' 'remove' 'remove-unknown' 'repo-backup' 'repo-check' 'repo-clean' 'repo-config' 'repo-config-validate' 'repo-create-keyring' 'repo-create-mirrorlist' 'repo-daemon' 'repo-init' 'repo-rebuild' 'repo-remove-unknown' 'repo-report' 'repo-restore' 'repo-setup' 'repo-sign' 'repo-statistics' 'repo-status-update' 'repo-sync' 'repo-tree' 'repo-triggers' 'repo-update' 'report' 'run' 'search' 'service-clean' 'service-config' 'service-config-validate' 'service-key-import' 'service-repositories' 'service-run' 'service-setup' 'service-shell' 'service-tree-migrate' 'setup' 'shell' 'sign' 'status' 'status-update' 'sync' 'update' 'user-add' 'user-list' 'user-remove' 'version' 'web') _shtab_ahriman_subparsers=('add' 'aur-search' 'check' 'clean' 'config' 'config-validate' 'copy' 'daemon' 'help' 'help-commands-unsafe' 'help-updates' 'help-version' 'init' 'key-import' 'package-add' 'package-changes' 'package-changes-remove' 'package-copy' 'package-remove' 'package-status' 'package-status-remove' 'package-status-update' 'package-update' 'patch-add' 'patch-list' 'patch-remove' 'patch-set-add' 'rebuild' 'remove' 'remove-unknown' 'repo-backup' 'repo-check' 'repo-clean' 'repo-config' 'repo-config-validate' 'repo-create-keyring' 'repo-create-mirrorlist' 'repo-daemon' 'repo-init' 'repo-rebuild' 'repo-remove-unknown' 'repo-report' 'repo-restore' 'repo-setup' 'repo-sign' 'repo-statistics' 'repo-status-update' 'repo-sync' 'repo-tree' 'repo-triggers' 'repo-update' 'report' 'run' 'search' 'service-clean' 'service-config' 'service-config-validate' 'service-key-import' 'service-repositories' 'service-run' 'service-setup' 'service-shell' 'service-tree-migrate' 'setup' 'shell' 'sign' 'status' 'status-update' 'sync' 'update' 'user-add' 'user-list' 'user-remove' 'version' 'web' 'web-reload')
_shtab_ahriman_option_strings=('-h' '--help' '-a' '--architecture' '-c' '--configuration' '--force' '-l' '--lock' '--log-handler' '-q' '--quiet' '--report' '--no-report' '-r' '--repository' '--unsafe' '-V' '--version' '--wait-timeout') _shtab_ahriman_option_strings=('-h' '--help' '-a' '--architecture' '-c' '--configuration' '--force' '-l' '--lock' '--log-handler' '-q' '--quiet' '--report' '--no-report' '-r' '--repository' '--unsafe' '-V' '--version' '--wait-timeout')
_shtab_ahriman_add_option_strings=('-h' '--help' '--changes' '--no-changes' '--dependencies' '--no-dependencies' '-e' '--exit-code' '--increment' '--no-increment' '-n' '--now' '-y' '--refresh' '-s' '--source' '-u' '--username' '-v' '--variable') _shtab_ahriman_add_option_strings=('-h' '--help' '--changes' '--no-changes' '--dependencies' '--no-dependencies' '-e' '--exit-code' '--increment' '--no-increment' '-n' '--now' '-y' '--refresh' '-s' '--source' '-u' '--username' '-v' '--variable')
@@ -78,10 +78,11 @@ _shtab_ahriman_user_list_option_strings=('-h' '--help' '-e' '--exit-code' '-R' '
_shtab_ahriman_user_remove_option_strings=('-h' '--help') _shtab_ahriman_user_remove_option_strings=('-h' '--help')
_shtab_ahriman_version_option_strings=('-h' '--help') _shtab_ahriman_version_option_strings=('-h' '--help')
_shtab_ahriman_web_option_strings=('-h' '--help') _shtab_ahriman_web_option_strings=('-h' '--help')
_shtab_ahriman_web_reload_option_strings=('-h' '--help')
_shtab_ahriman_pos_0_choices=('add' 'aur-search' 'check' 'clean' 'config' 'config-validate' 'copy' 'daemon' 'help' 'help-commands-unsafe' 'help-updates' 'help-version' 'init' 'key-import' 'package-add' 'package-changes' 'package-changes-remove' 'package-copy' 'package-remove' 'package-status' 'package-status-remove' 'package-status-update' 'package-update' 'patch-add' 'patch-list' 'patch-remove' 'patch-set-add' 'rebuild' 'remove' 'remove-unknown' 'repo-backup' 'repo-check' 'repo-clean' 'repo-config' 'repo-config-validate' 'repo-create-keyring' 'repo-create-mirrorlist' 'repo-daemon' 'repo-init' 'repo-rebuild' 'repo-remove-unknown' 'repo-report' 'repo-restore' 'repo-setup' 'repo-sign' 'repo-statistics' 'repo-status-update' 'repo-sync' 'repo-tree' 'repo-triggers' 'repo-update' 'report' 'run' 'search' 'service-clean' 'service-config' 'service-config-validate' 'service-key-import' 'service-repositories' 'service-run' 'service-setup' 'service-shell' 'service-tree-migrate' 'setup' 'shell' 'sign' 'status' 'status-update' 'sync' 'update' 'user-add' 'user-list' 'user-remove' 'version' 'web') _shtab_ahriman_pos_0_choices=('add' 'aur-search' 'check' 'clean' 'config' 'config-validate' 'copy' 'daemon' 'help' 'help-commands-unsafe' 'help-updates' 'help-version' 'init' 'key-import' 'package-add' 'package-changes' 'package-changes-remove' 'package-copy' 'package-remove' 'package-status' 'package-status-remove' 'package-status-update' 'package-update' 'patch-add' 'patch-list' 'patch-remove' 'patch-set-add' 'rebuild' 'remove' 'remove-unknown' 'repo-backup' 'repo-check' 'repo-clean' 'repo-config' 'repo-config-validate' 'repo-create-keyring' 'repo-create-mirrorlist' 'repo-daemon' 'repo-init' 'repo-rebuild' 'repo-remove-unknown' 'repo-report' 'repo-restore' 'repo-setup' 'repo-sign' 'repo-statistics' 'repo-status-update' 'repo-sync' 'repo-tree' 'repo-triggers' 'repo-update' 'report' 'run' 'search' 'service-clean' 'service-config' 'service-config-validate' 'service-key-import' 'service-repositories' 'service-run' 'service-setup' 'service-shell' 'service-tree-migrate' 'setup' 'shell' 'sign' 'status' 'status-update' 'sync' 'update' 'user-add' 'user-list' 'user-remove' 'version' 'web' 'web-reload')
_shtab_ahriman___log_handler_choices=('console' 'syslog' 'journald') _shtab_ahriman___log_handler_choices=('console' 'syslog' 'journald')
_shtab_ahriman_add__s_choices=('auto' 'archive' 'aur' 'directory' 'local' 'remote' 'repository') _shtab_ahriman_add__s_choices=('auto' 'archive' 'aur' 'directory' 'local' 'remote' 'repository')
_shtab_ahriman_add___source_choices=('auto' 'archive' 'aur' 'directory' 'local' 'remote' 'repository') _shtab_ahriman_add___source_choices=('auto' 'archive' 'aur' 'directory' 'local' 'remote' 'repository')
@@ -572,6 +573,8 @@ _shtab_ahriman_version__h_nargs=0
_shtab_ahriman_version___help_nargs=0 _shtab_ahriman_version___help_nargs=0
_shtab_ahriman_web__h_nargs=0 _shtab_ahriman_web__h_nargs=0
_shtab_ahriman_web___help_nargs=0 _shtab_ahriman_web___help_nargs=0
_shtab_ahriman_web_reload__h_nargs=0
_shtab_ahriman_web_reload___help_nargs=0
# $1=COMP_WORDS[1] # $1=COMP_WORDS[1]
@@ -674,6 +677,7 @@ _shtab_ahriman() {
if [[ "$current_action_nargs" != "*" ]] && \ if [[ "$current_action_nargs" != "*" ]] && \
[[ "$current_action_nargs" != "+" ]] && \ [[ "$current_action_nargs" != "+" ]] && \
[[ "$current_action_nargs" != "?" ]] && \
[[ "$current_action_nargs" != *"..." ]] && \ [[ "$current_action_nargs" != *"..." ]] && \
(( $word_index + 1 - $current_action_args_start_index - $pos_only >= \ (( $word_index + 1 - $current_action_args_start_index - $pos_only >= \
$current_action_nargs )); then $current_action_nargs )); then

View File

@@ -1,9 +1,9 @@
.TH AHRIMAN "1" "2025\-06\-29" "ahriman 2.19.0" "ArcH linux ReposItory MANager" .TH AHRIMAN "1" "2026\-02\-18" "ahriman 2.20.0rc1" "ArcH linux ReposItory MANager"
.SH NAME .SH NAME
ahriman \- ArcH linux ReposItory MANager ahriman \- ArcH linux ReposItory MANager
.SH SYNOPSIS .SH SYNOPSIS
.B ahriman .B ahriman
[-h] [-a ARCHITECTURE] [-c CONFIGURATION] [--force] [-l LOCK] [--log-handler {console,syslog,journald}] [-q] [--report | --no-report] [-r REPOSITORY] [--unsafe] [-V] [--wait-timeout WAIT_TIMEOUT] {add,aur-search,check,clean,config,config-validate,copy,daemon,help,help-commands-unsafe,help-updates,help-version,init,key-import,package-add,package-changes,package-changes-remove,package-copy,package-remove,package-status,package-status-remove,package-status-update,package-update,patch-add,patch-list,patch-remove,patch-set-add,rebuild,remove,remove-unknown,repo-backup,repo-check,repo-clean,repo-config,repo-config-validate,repo-create-keyring,repo-create-mirrorlist,repo-daemon,repo-init,repo-rebuild,repo-remove-unknown,repo-report,repo-restore,repo-setup,repo-sign,repo-statistics,repo-status-update,repo-sync,repo-tree,repo-triggers,repo-update,report,run,search,service-clean,service-config,service-config-validate,service-key-import,service-repositories,service-run,service-setup,service-shell,service-tree-migrate,setup,shell,sign,status,status-update,sync,update,user-add,user-list,user-remove,version,web} ... [-h] [-a ARCHITECTURE] [-c CONFIGURATION] [--force] [-l LOCK] [--log-handler {console,syslog,journald}] [-q] [--report | --no-report] [-r REPOSITORY] [--unsafe] [-V] [--wait-timeout WAIT_TIMEOUT] {add,aur-search,check,clean,config,config-validate,copy,daemon,help,help-commands-unsafe,help-updates,help-version,init,key-import,package-add,package-changes,package-changes-remove,package-copy,package-remove,package-status,package-status-remove,package-status-update,package-update,patch-add,patch-list,patch-remove,patch-set-add,rebuild,remove,remove-unknown,repo-backup,repo-check,repo-clean,repo-config,repo-config-validate,repo-create-keyring,repo-create-mirrorlist,repo-daemon,repo-init,repo-rebuild,repo-remove-unknown,repo-report,repo-restore,repo-setup,repo-sign,repo-statistics,repo-status-update,repo-sync,repo-tree,repo-triggers,repo-update,report,run,search,service-clean,service-config,service-config-validate,service-key-import,service-repositories,service-run,service-setup,service-shell,service-tree-migrate,setup,shell,sign,status,status-update,sync,update,user-add,user-list,user-remove,version,web,web-reload} ...
.SH DESCRIPTION .SH DESCRIPTION
ArcH linux ReposItory MANager ArcH linux ReposItory MANager
@@ -193,11 +193,14 @@ remove user
.TP .TP
\fBahriman\fR \fI\,web\/\fR \fBahriman\fR \fI\,web\/\fR
web server web server
.TP
\fBahriman\fR \fI\,web\-reload\/\fR
reload configuration
.SH COMMAND \fI\,'ahriman aur\-search'\/\fR .SH COMMAND \fI\,'ahriman aur\-search'\/\fR
usage: ahriman aur\-search [\-h] [\-e] [\-\-info | \-\-no\-info] usage: ahriman aur\-search [\-h] [\-e] [\-\-info | \-\-no\-info]
[\-\-sort\-by {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}] [\-\-sort\-by {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}]
search [search ...] search [search ...]
search for package in AUR using API search for package in AUR using API
@@ -220,7 +223,7 @@ sort field by this field. In case if two packages have the same value of the spe
by name by name
.SH COMMAND \fI\,'ahriman help'\/\fR .SH COMMAND \fI\,'ahriman help'\/\fR
usage: ahriman help [\-h] [subcommand] usage: ahriman help [\-h] [subcommand]
show help message for application or command and exit show help message for application or command and exit
@@ -229,7 +232,7 @@ show help message for application or command and exit
show help message for specific command show help message for specific command
.SH COMMAND \fI\,'ahriman help\-commands\-unsafe'\/\fR .SH COMMAND \fI\,'ahriman help\-commands\-unsafe'\/\fR
usage: ahriman help\-commands\-unsafe [\-h] [subcommand ...] usage: ahriman help\-commands\-unsafe [\-h] [subcommand ...]
list unsafe commands as defined in default args list unsafe commands as defined in default args
@@ -239,7 +242,7 @@ instead of showing commands, just test command line for unsafe subcommand and re
otherwise otherwise
.SH COMMAND \fI\,'ahriman help\-updates'\/\fR .SH COMMAND \fI\,'ahriman help\-updates'\/\fR
usage: ahriman help\-updates [\-h] [\-e] usage: ahriman help\-updates [\-h] [\-e]
request AUR for current version and compare with current service version request AUR for current version and compare with current service version
@@ -249,15 +252,15 @@ request AUR for current version and compare with current service version
return non\-zero exit code if updates available return non\-zero exit code if updates available
.SH COMMAND \fI\,'ahriman help\-version'\/\fR .SH COMMAND \fI\,'ahriman help\-version'\/\fR
usage: ahriman help\-version [\-h] usage: ahriman help\-version [\-h]
print application and its dependencies versions print application and its dependencies versions
.SH COMMAND \fI\,'ahriman package\-add'\/\fR .SH COMMAND \fI\,'ahriman package\-add'\/\fR
usage: ahriman package\-add [\-h] [\-\-changes | \-\-no\-changes] [\-\-dependencies | \-\-no\-dependencies] [\-e] usage: ahriman package\-add [\-h] [\-\-changes | \-\-no\-changes] [\-\-dependencies | \-\-no\-dependencies] [\-e]
[\-\-increment | \-\-no\-increment] [\-n] [\-y] [\-\-increment | \-\-no\-increment] [\-n] [\-y]
[\-s {auto,archive,aur,directory,local,remote,repository}] [\-u USERNAME] [\-v VARIABLE] [\-s {auto,archive,aur,directory,local,remote,repository}] [\-u USERNAME] [\-v VARIABLE]
package [package ...] package [package ...]
add existing or new package to the build queue add existing or new package to the build queue
@@ -303,7 +306,7 @@ build as user
apply specified makepkg variables to the next build apply specified makepkg variables to the next build
.SH COMMAND \fI\,'ahriman package\-changes'\/\fR .SH COMMAND \fI\,'ahriman package\-changes'\/\fR
usage: ahriman package\-changes [\-h] [\-e] package usage: ahriman package\-changes [\-h] [\-e] package
retrieve package changes stored in database retrieve package changes stored in database
@@ -317,7 +320,7 @@ package base
return non\-zero exit status if result is empty return non\-zero exit status if result is empty
.SH COMMAND \fI\,'ahriman package\-changes\-remove'\/\fR .SH COMMAND \fI\,'ahriman package\-changes\-remove'\/\fR
usage: ahriman package\-changes\-remove [\-h] package usage: ahriman package\-changes\-remove [\-h] package
remove the package changes stored remotely remove the package changes stored remotely
@@ -326,7 +329,7 @@ remove the package changes stored remotely
package base package base
.SH COMMAND \fI\,'ahriman package\-copy'\/\fR .SH COMMAND \fI\,'ahriman package\-copy'\/\fR
usage: ahriman package\-copy [\-h] [\-e] [\-\-remove] source package [package ...] usage: ahriman package\-copy [\-h] [\-e] [\-\-remove] source package [package ...]
copy package and its metadata from another repository copy package and its metadata from another repository
@@ -348,7 +351,7 @@ return non\-zero exit status if result is empty
remove package from the source repository after remove package from the source repository after
.SH COMMAND \fI\,'ahriman package\-remove'\/\fR .SH COMMAND \fI\,'ahriman package\-remove'\/\fR
usage: ahriman package\-remove [\-h] package [package ...] usage: ahriman package\-remove [\-h] package [package ...]
remove package from the repository remove package from the repository
@@ -357,8 +360,8 @@ remove package from the repository
package name or base package name or base
.SH COMMAND \fI\,'ahriman package\-status'\/\fR .SH COMMAND \fI\,'ahriman package\-status'\/\fR
usage: ahriman package\-status [\-h] [\-\-ahriman] [\-e] [\-\-info | \-\-no\-info] [\-s {unknown,pending,building,failed,success}] usage: ahriman package\-status [\-h] [\-\-ahriman] [\-e] [\-\-info | \-\-no\-info] [\-s {unknown,pending,building,failed,success}]
[package ...] [package ...]
request status of the package request status of the package
@@ -384,7 +387,7 @@ show additional package information
filter packages by status filter packages by status
.SH COMMAND \fI\,'ahriman package\-status\-remove'\/\fR .SH COMMAND \fI\,'ahriman package\-status\-remove'\/\fR
usage: ahriman package\-status\-remove [\-h] package [package ...] usage: ahriman package\-status\-remove [\-h] package [package ...]
remove the package from the status page remove the package from the status page
@@ -393,7 +396,7 @@ remove the package from the status page
remove specified packages from status page remove specified packages from status page
.SH COMMAND \fI\,'ahriman package\-status\-update'\/\fR .SH COMMAND \fI\,'ahriman package\-status\-update'\/\fR
usage: ahriman package\-status\-update [\-h] [\-s {unknown,pending,building,failed,success}] [package ...] usage: ahriman package\-status\-update [\-h] [\-s {unknown,pending,building,failed,success}] [package ...]
update package status on the status page update package status on the status page
@@ -407,7 +410,7 @@ set status for specified packages. If no packages supplied, service status will
new package build status new package build status
.SH COMMAND \fI\,'ahriman patch\-add'\/\fR .SH COMMAND \fI\,'ahriman patch\-add'\/\fR
usage: ahriman patch\-add [\-h] package variable [patch] usage: ahriman patch\-add [\-h] package variable [patch]
create or update patched PKGBUILD function or variable create or update patched PKGBUILD function or variable
@@ -424,7 +427,7 @@ PKGBUILD variable or function name. If variable is a function, it must end with
path to file which contains function or variable value. If not set, the value will be read from stdin path to file which contains function or variable value. If not set, the value will be read from stdin
.SH COMMAND \fI\,'ahriman patch\-list'\/\fR .SH COMMAND \fI\,'ahriman patch\-list'\/\fR
usage: ahriman patch\-list [\-h] [\-e] [\-v VARIABLE] package usage: ahriman patch\-list [\-h] [\-e] [\-v VARIABLE] package
list available patches for the package list available patches for the package
@@ -442,7 +445,7 @@ return non\-zero exit status if result is empty
if set, show only patches for specified PKGBUILD variables if set, show only patches for specified PKGBUILD variables
.SH COMMAND \fI\,'ahriman patch\-remove'\/\fR .SH COMMAND \fI\,'ahriman patch\-remove'\/\fR
usage: ahriman patch\-remove [\-h] [\-v VARIABLE] package usage: ahriman patch\-remove [\-h] [\-v VARIABLE] package
remove patches for the package remove patches for the package
@@ -457,7 +460,7 @@ should be used for single\-function patches in case if you wold like to remove o
if not set, it will remove all patches related to the package if not set, it will remove all patches related to the package
.SH COMMAND \fI\,'ahriman patch\-set\-add'\/\fR .SH COMMAND \fI\,'ahriman patch\-set\-add'\/\fR
usage: ahriman patch\-set\-add [\-h] [\-t TRACK] package usage: ahriman patch\-set\-add [\-h] [\-t TRACK] package
create or update source patches create or update source patches
@@ -471,7 +474,7 @@ path to directory with changed files for patch addition/update
files which has to be tracked files which has to be tracked
.SH COMMAND \fI\,'ahriman repo\-backup'\/\fR .SH COMMAND \fI\,'ahriman repo\-backup'\/\fR
usage: ahriman repo\-backup [\-h] path usage: ahriman repo\-backup [\-h] path
backup repository settings and database backup repository settings and database
@@ -480,9 +483,9 @@ backup repository settings and database
path of the output archive path of the output archive
.SH COMMAND \fI\,'ahriman repo\-check'\/\fR .SH COMMAND \fI\,'ahriman repo\-check'\/\fR
usage: ahriman repo\-check [\-h] [\-\-changes | \-\-no\-changes] [\-\-check\-files | \-\-no\-check\-files] [\-e] [\-\-vcs | \-\-no\-vcs] usage: ahriman repo\-check [\-h] [\-\-changes | \-\-no\-changes] [\-\-check\-files | \-\-no\-check\-files] [\-e] [\-\-vcs | \-\-no\-vcs]
[\-y] [\-y]
[package ...] [package ...]
check for packages updates. Same as repo\-update \-\-dry\-run \-\-no\-manual check for packages updates. Same as repo\-update \-\-dry\-run \-\-no\-manual
@@ -512,20 +515,20 @@ fetch actual version of VCS packages
download fresh package databases from the mirror before actions, \-yy to force refresh even if up to date download fresh package databases from the mirror before actions, \-yy to force refresh even if up to date
.SH COMMAND \fI\,'ahriman repo\-create\-keyring'\/\fR .SH COMMAND \fI\,'ahriman repo\-create\-keyring'\/\fR
usage: ahriman repo\-create\-keyring [\-h] usage: ahriman repo\-create\-keyring [\-h]
create package which contains list of trusted keys as set by configuration. Note, that this action will only create package, the package itself has to be built manually create package which contains list of trusted keys as set by configuration. Note, that this action will only create package, the package itself has to be built manually
.SH COMMAND \fI\,'ahriman repo\-create\-mirrorlist'\/\fR .SH COMMAND \fI\,'ahriman repo\-create\-mirrorlist'\/\fR
usage: ahriman repo\-create\-mirrorlist [\-h] usage: ahriman repo\-create\-mirrorlist [\-h]
create package which contains list of available mirrors as set by configuration. Note, that this action will only create package, the package itself has to be built manually create package which contains list of available mirrors as set by configuration. Note, that this action will only create package, the package itself has to be built manually
.SH COMMAND \fI\,'ahriman repo\-daemon'\/\fR .SH COMMAND \fI\,'ahriman repo\-daemon'\/\fR
usage: ahriman repo\-daemon [\-h] [\-i INTERVAL] [\-\-aur | \-\-no\-aur] [\-\-changes | \-\-no\-changes] usage: ahriman repo\-daemon [\-h] [\-i INTERVAL] [\-\-aur | \-\-no\-aur] [\-\-changes | \-\-no\-changes]
[\-\-check\-files | \-\-no\-check\-files] [\-\-dependencies | \-\-no\-dependencies] [\-\-dry\-run] [\-\-check\-files | \-\-no\-check\-files] [\-\-dependencies | \-\-no\-dependencies] [\-\-dry\-run]
[\-\-increment | \-\-no\-increment] [\-\-local | \-\-no\-local] [\-\-manual | \-\-no\-manual] [\-\-increment | \-\-no\-increment] [\-\-local | \-\-no\-local] [\-\-manual | \-\-no\-manual]
[\-\-partitions | \-\-no\-partitions] [\-u USERNAME] [\-\-vcs | \-\-no\-vcs] [\-y] [\-\-partitions | \-\-no\-partitions] [\-u USERNAME] [\-\-vcs | \-\-no\-vcs] [\-y]
start process which periodically will run update process start process which periodically will run update process
@@ -583,8 +586,8 @@ fetch actual version of VCS packages
download fresh package databases from the mirror before actions, \-yy to force refresh even if up to date download fresh package databases from the mirror before actions, \-yy to force refresh even if up to date
.SH COMMAND \fI\,'ahriman repo\-rebuild'\/\fR .SH COMMAND \fI\,'ahriman repo\-rebuild'\/\fR
usage: ahriman repo\-rebuild [\-h] [\-\-depends\-on DEPENDS_ON] [\-\-dry\-run] [\-\-from\-database] [\-\-increment | \-\-no\-increment] usage: ahriman repo\-rebuild [\-h] [\-\-depends\-on DEPENDS_ON] [\-\-dry\-run] [\-\-from\-database] [\-\-increment | \-\-no\-increment]
[\-e] [\-s {unknown,pending,building,failed,success}] [\-u USERNAME] [\-e] [\-s {unknown,pending,building,failed,success}] [\-u USERNAME]
force rebuild whole repository force rebuild whole repository
@@ -620,7 +623,7 @@ filter packages by status. Requires \-\-from\-database to be set
build as user build as user
.SH COMMAND \fI\,'ahriman repo\-remove\-unknown'\/\fR .SH COMMAND \fI\,'ahriman repo\-remove\-unknown'\/\fR
usage: ahriman repo\-remove\-unknown [\-h] [\-\-dry\-run] usage: ahriman repo\-remove\-unknown [\-h] [\-\-dry\-run]
remove packages which are missing in AUR and do not have local PKGBUILDs remove packages which are missing in AUR and do not have local PKGBUILDs
@@ -630,12 +633,12 @@ remove packages which are missing in AUR and do not have local PKGBUILDs
just perform check for packages without removal just perform check for packages without removal
.SH COMMAND \fI\,'ahriman repo\-report'\/\fR .SH COMMAND \fI\,'ahriman repo\-report'\/\fR
usage: ahriman repo\-report [\-h] usage: ahriman repo\-report [\-h]
generate repository report according to current settings generate repository report according to current settings
.SH COMMAND \fI\,'ahriman repo\-restore'\/\fR .SH COMMAND \fI\,'ahriman repo\-restore'\/\fR
usage: ahriman repo\-restore [\-h] [\-o OUTPUT] path usage: ahriman repo\-restore [\-h] [\-o OUTPUT] path
restore settings and database restore settings and database
@@ -649,7 +652,7 @@ path of the input archive
root path of the extracted files root path of the extracted files
.SH COMMAND \fI\,'ahriman repo\-sign'\/\fR .SH COMMAND \fI\,'ahriman repo\-sign'\/\fR
usage: ahriman repo\-sign [\-h] [package ...] usage: ahriman repo\-sign [\-h] [package ...]
(re\-)sign packages and repository database according to current settings (re\-)sign packages and repository database according to current settings
@@ -658,10 +661,10 @@ usage: ahriman repo\-sign [\-h] [package ...]
sign only specified packages sign only specified packages
.SH COMMAND \fI\,'ahriman repo\-statistics'\/\fR .SH COMMAND \fI\,'ahriman repo\-statistics'\/\fR
usage: ahriman repo\-statistics [\-h] [\-\-chart CHART] usage: ahriman repo\-statistics [\-h] [\-\-chart CHART]
[\-e {package\-outdated,package\-removed,package\-update\-failed,package\-updated}] [\-e {package\-outdated,package\-removed,package\-update\-failed,package\-updated}]
[\-\-from\-date FROM_DATE] [\-\-limit LIMIT] [\-\-offset OFFSET] [\-\-to\-date TO_DATE] [\-\-from\-date FROM_DATE] [\-\-limit LIMIT] [\-\-offset OFFSET] [\-\-to\-date TO_DATE]
[package] [package]
fetch repository statistics fetch repository statistics
@@ -695,7 +698,7 @@ skip specified amount of events
only fetch events which are older than the date only fetch events which are older than the date
.SH COMMAND \fI\,'ahriman repo\-status\-update'\/\fR .SH COMMAND \fI\,'ahriman repo\-status\-update'\/\fR
usage: ahriman repo\-status\-update [\-h] [\-s {unknown,pending,building,failed,success}] usage: ahriman repo\-status\-update [\-h] [\-s {unknown,pending,building,failed,success}]
update repository status on the status page update repository status on the status page
@@ -705,12 +708,12 @@ update repository status on the status page
new status new status
.SH COMMAND \fI\,'ahriman repo\-sync'\/\fR .SH COMMAND \fI\,'ahriman repo\-sync'\/\fR
usage: ahriman repo\-sync [\-h] usage: ahriman repo\-sync [\-h]
sync repository files to remote server according to current settings sync repository files to remote server according to current settings
.SH COMMAND \fI\,'ahriman repo\-tree'\/\fR .SH COMMAND \fI\,'ahriman repo\-tree'\/\fR
usage: ahriman repo\-tree [\-h] [\-p PARTITIONS] usage: ahriman repo\-tree [\-h] [\-p PARTITIONS]
dump repository tree based on packages dependencies dump repository tree based on packages dependencies
@@ -720,7 +723,7 @@ dump repository tree based on packages dependencies
also divide packages by independent partitions also divide packages by independent partitions
.SH COMMAND \fI\,'ahriman repo\-triggers'\/\fR .SH COMMAND \fI\,'ahriman repo\-triggers'\/\fR
usage: ahriman repo\-triggers [\-h] [trigger ...] usage: ahriman repo\-triggers [\-h] [trigger ...]
run triggers on empty build result as configured by settings run triggers on empty build result as configured by settings
@@ -729,10 +732,10 @@ run triggers on empty build result as configured by settings
instead of running all triggers as set by configuration, just process specified ones in order of mention instead of running all triggers as set by configuration, just process specified ones in order of mention
.SH COMMAND \fI\,'ahriman repo\-update'\/\fR .SH COMMAND \fI\,'ahriman repo\-update'\/\fR
usage: ahriman repo\-update [\-h] [\-\-aur | \-\-no\-aur] [\-\-changes | \-\-no\-changes] [\-\-check\-files | \-\-no\-check\-files] usage: ahriman repo\-update [\-h] [\-\-aur | \-\-no\-aur] [\-\-changes | \-\-no\-changes] [\-\-check\-files | \-\-no\-check\-files]
[\-\-dependencies | \-\-no\-dependencies] [\-\-dry\-run] [\-e] [\-\-increment | \-\-no\-increment] [\-\-dependencies | \-\-no\-dependencies] [\-\-dry\-run] [\-e] [\-\-increment | \-\-no\-increment]
[\-\-local | \-\-no\-local] [\-\-manual | \-\-no\-manual] [\-u USERNAME] [\-\-vcs | \-\-no\-vcs] [\-y] [\-\-local | \-\-no\-local] [\-\-manual | \-\-no\-manual] [\-u USERNAME] [\-\-vcs | \-\-no\-vcs] [\-y]
[package ...] [package ...]
check for packages updates and run build process if requested check for packages updates and run build process if requested
@@ -790,8 +793,8 @@ fetch actual version of VCS packages
download fresh package databases from the mirror before actions, \-yy to force refresh even if up to date download fresh package databases from the mirror before actions, \-yy to force refresh even if up to date
.SH COMMAND \fI\,'ahriman service\-clean'\/\fR .SH COMMAND \fI\,'ahriman service\-clean'\/\fR
usage: ahriman service\-clean [\-h] [\-\-cache | \-\-no\-cache] [\-\-chroot | \-\-no\-chroot] [\-\-manual | \-\-no\-manual] usage: ahriman service\-clean [\-h] [\-\-cache | \-\-no\-cache] [\-\-chroot | \-\-no\-chroot] [\-\-manual | \-\-no\-manual]
[\-\-packages | \-\-no\-packages] [\-\-pacman | \-\-no\-pacman] [\-\-packages | \-\-no\-packages] [\-\-pacman | \-\-no\-pacman]
remove local caches remove local caches
@@ -817,7 +820,7 @@ clear directory with built packages
clear directory with pacman local database cache clear directory with pacman local database cache
.SH COMMAND \fI\,'ahriman service\-config'\/\fR .SH COMMAND \fI\,'ahriman service\-config'\/\fR
usage: ahriman service\-config [\-h] [\-\-info | \-\-no\-info] [\-\-secure | \-\-no\-secure] [section] [key] usage: ahriman service\-config [\-h] [\-\-info | \-\-no\-info] [\-\-secure | \-\-no\-secure] [section] [key]
dump configuration for the specified architecture dump configuration for the specified architecture
@@ -839,7 +842,7 @@ show additional information, e.g. configuration files
hide passwords and secrets from output hide passwords and secrets from output
.SH COMMAND \fI\,'ahriman service\-config\-validate'\/\fR .SH COMMAND \fI\,'ahriman service\-config\-validate'\/\fR
usage: ahriman service\-config\-validate [\-h] [\-e] usage: ahriman service\-config\-validate [\-h] [\-e]
validate configuration and print found errors validate configuration and print found errors
@@ -849,7 +852,7 @@ validate configuration and print found errors
return non\-zero exit status if configuration is invalid return non\-zero exit status if configuration is invalid
.SH COMMAND \fI\,'ahriman service\-key\-import'\/\fR .SH COMMAND \fI\,'ahriman service\-key\-import'\/\fR
usage: ahriman service\-key\-import [\-h] [\-\-key\-server KEY_SERVER] key usage: ahriman service\-key\-import [\-h] [\-\-key\-server KEY_SERVER] key
import PGP key from public sources to the repository user import PGP key from public sources to the repository user
@@ -863,7 +866,7 @@ PGP key to import from public server
key server for key import key server for key import
.SH COMMAND \fI\,'ahriman service\-repositories'\/\fR .SH COMMAND \fI\,'ahriman service\-repositories'\/\fR
usage: ahriman service\-repositories [\-h] [\-\-id\-only | \-\-no\-id\-only] usage: ahriman service\-repositories [\-h] [\-\-id\-only | \-\-no\-id\-only]
list all available repositories list all available repositories
@@ -873,7 +876,7 @@ list all available repositories
show machine readable identifier instead show machine readable identifier instead
.SH COMMAND \fI\,'ahriman service\-run'\/\fR .SH COMMAND \fI\,'ahriman service\-run'\/\fR
usage: ahriman service\-run [\-h] command [command ...] usage: ahriman service\-run [\-h] command [command ...]
run multiple commands on success run of the previous command run multiple commands on success run of the previous command
@@ -882,11 +885,11 @@ run multiple commands on success run of the previous command
command to be run (quoted) without ``ahriman`` command to be run (quoted) without ``ahriman``
.SH COMMAND \fI\,'ahriman service\-setup'\/\fR .SH COMMAND \fI\,'ahriman service\-setup'\/\fR
usage: ahriman service\-setup [\-h] [\-\-build\-as\-user BUILD_AS_USER] [\-\-from\-configuration FROM_CONFIGURATION] 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] [\-\-generate\-salt | \-\-no\-generate\-salt] [\-\-makeflags\-jobs | \-\-no\-makeflags\-jobs]
[\-\-mirror MIRROR] [\-\-multilib | \-\-no\-multilib] \-\-packager PACKAGER [\-\-server SERVER] [\-\-mirror MIRROR] [\-\-multilib | \-\-no\-multilib] \-\-packager PACKAGER [\-\-server SERVER]
[\-\-sign\-key SIGN_KEY] [\-\-sign\-target {disabled,packages,repository}] [\-\-web\-port WEB_PORT] [\-\-sign\-key SIGN_KEY] [\-\-sign\-target {disabled,packages,repository}] [\-\-web\-port WEB_PORT]
[\-\-web\-unix\-socket WEB_UNIX_SOCKET] [\-\-web\-unix\-socket WEB_UNIX_SOCKET]
create initial service configuration, requires root create initial service configuration, requires root
@@ -940,7 +943,7 @@ port of the web service
path to unix socket used for interprocess communications path to unix socket used for interprocess communications
.SH COMMAND \fI\,'ahriman service\-shell'\/\fR .SH COMMAND \fI\,'ahriman service\-shell'\/\fR
usage: ahriman service\-shell [\-h] [\-o OUTPUT] [code] usage: ahriman service\-shell [\-h] [\-o OUTPUT] [code]
drop into python shell drop into python shell
@@ -954,13 +957,13 @@ instead of dropping into shell, just execute the specified code
output commands and result to the file output commands and result to the file
.SH COMMAND \fI\,'ahriman service\-tree\-migrate'\/\fR .SH COMMAND \fI\,'ahriman service\-tree\-migrate'\/\fR
usage: ahriman service\-tree\-migrate [\-h] usage: ahriman service\-tree\-migrate [\-h]
migrate repository tree between versions migrate repository tree between versions
.SH COMMAND \fI\,'ahriman user\-add'\/\fR .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 username
update user for web services with the given password and role. In case if password was not entered it will be asked interactively update user for web services with the given password and role. In case if password was not entered it will be asked interactively
@@ -987,7 +990,7 @@ authorization type.
user access level user access level
.SH COMMAND \fI\,'ahriman user\-list'\/\fR .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 list users from the user mapping and their roles
@@ -1005,7 +1008,7 @@ return non\-zero exit status if result is empty
filter users by role filter users by role
.SH COMMAND \fI\,'ahriman user\-remove'\/\fR .SH COMMAND \fI\,'ahriman user\-remove'\/\fR
usage: ahriman user\-remove [\-h] username usage: ahriman user\-remove [\-h] username
remove user from the user mapping and update the configuration remove user from the user mapping and update the configuration
@@ -1014,10 +1017,15 @@ remove user from the user mapping and update the configuration
username for web service username for web service
.SH COMMAND \fI\,'ahriman web'\/\fR .SH COMMAND \fI\,'ahriman web'\/\fR
usage: ahriman web [\-h] usage: ahriman web [\-h]
start web server start web server
.SH COMMAND \fI\,'ahriman web\-reload'\/\fR
usage: ahriman web\-reload [\-h]
reload web server configuration
.SH COMMENTS .SH COMMENTS
Quick setup command (replace repository name, architecture and packager as needed): Quick setup command (replace repository name, architecture and packager as needed):

View File

@@ -80,6 +80,7 @@ _shtab_ahriman_commands() {
"user-remove:remove user from the user mapping and update the configuration" "user-remove:remove user from the user mapping and update the configuration"
"version:print application and its dependencies versions" "version:print application and its dependencies versions"
"web:start web server" "web:start web server"
"web-reload:reload web server configuration"
) )
_describe 'ahriman commands' _commands _describe 'ahriman commands' _commands
} }
@@ -99,6 +100,9 @@ _shtab_ahriman_options=(
"--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:" "--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:"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_defaults_added=0
_shtab_ahriman_add_options=( _shtab_ahriman_add_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{--changes,--no-changes}"[calculate changes from the latest known commit if available (default\: True)]:changes:" {--changes,--no-changes}"[calculate changes from the latest known commit if available (default\: True)]:changes:"
@@ -113,6 +117,9 @@ _shtab_ahriman_add_options=(
"(*):package source (base name, path to local files, remote URL):" "(*):package source (base name, path to local files, remote URL):"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_add_defaults_added=0
_shtab_ahriman_aur_search_options=( _shtab_ahriman_aur_search_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]" {-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
@@ -121,6 +128,9 @@ _shtab_ahriman_aur_search_options=(
"(*):search terms, can be specified multiple times, the result will match all terms:" "(*):search terms, can be specified multiple times, the result will match all terms:"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_aur_search_defaults_added=0
_shtab_ahriman_check_options=( _shtab_ahriman_check_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{--changes,--no-changes}"[calculate changes from the latest known commit if available (default\: True)]:changes:" {--changes,--no-changes}"[calculate changes from the latest known commit if available (default\: True)]:changes:"
@@ -131,6 +141,9 @@ _shtab_ahriman_check_options=(
"(*)::filter check by package base (default\: None):" "(*)::filter check by package base (default\: None):"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_check_defaults_added=0
_shtab_ahriman_clean_options=( _shtab_ahriman_clean_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{--cache,--no-cache}"[clear directory with package caches (default\: False)]:cache:" {--cache,--no-cache}"[clear directory with package caches (default\: False)]:cache:"
@@ -140,6 +153,9 @@ _shtab_ahriman_clean_options=(
{--pacman,--no-pacman}"[clear directory with pacman local database cache (default\: False)]:pacman:" {--pacman,--no-pacman}"[clear directory with pacman local database cache (default\: False)]:pacman:"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_clean_defaults_added=0
_shtab_ahriman_config_options=( _shtab_ahriman_config_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{--info,--no-info}"[show additional information, e.g. configuration files (default\: True)]:info:" {--info,--no-info}"[show additional information, e.g. configuration files (default\: True)]:info:"
@@ -148,11 +164,17 @@ _shtab_ahriman_config_options=(
":filter settings by key (default\: None):" ":filter settings by key (default\: None):"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_config_defaults_added=0
_shtab_ahriman_config_validate_options=( _shtab_ahriman_config_validate_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{-e,--exit-code}"[return non-zero exit status if configuration is invalid (default\: False)]" {-e,--exit-code}"[return non-zero exit status if configuration is invalid (default\: False)]"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_config_validate_defaults_added=0
_shtab_ahriman_copy_options=( _shtab_ahriman_copy_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]" {-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
@@ -161,6 +183,9 @@ _shtab_ahriman_copy_options=(
"(*):package base:" "(*):package base:"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_copy_defaults_added=0
_shtab_ahriman_daemon_options=( _shtab_ahriman_daemon_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{-i,--interval}"[interval between runs in seconds (default\: 43200)]:interval:" {-i,--interval}"[interval between runs in seconds (default\: 43200)]:interval:"
@@ -178,25 +203,40 @@ _shtab_ahriman_daemon_options=(
"*"{-y,--refresh}"[download fresh package databases from the mirror before actions, -yy to force refresh even if up to date (default\: False)]" "*"{-y,--refresh}"[download fresh package databases from the mirror before actions, -yy to force refresh even if up to date (default\: False)]"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_daemon_defaults_added=0
_shtab_ahriman_help_options=( _shtab_ahriman_help_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
":show help message for specific command (default\: None):" ":show help message for specific command (default\: None):"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_help_defaults_added=0
_shtab_ahriman_help_commands_unsafe_options=( _shtab_ahriman_help_commands_unsafe_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
"(*)::instead of showing commands, just test command line for unsafe subcommand and return 0 in case if command is safe and 1 otherwise (default\: None):" "(*)::instead of showing commands, just test command line for unsafe subcommand and return 0 in case if command is safe and 1 otherwise (default\: None):"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_help_commands_unsafe_defaults_added=0
_shtab_ahriman_help_updates_options=( _shtab_ahriman_help_updates_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{-e,--exit-code}"[return non-zero exit code if updates available (default\: False)]" {-e,--exit-code}"[return non-zero exit code if updates available (default\: False)]"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_help_updates_defaults_added=0
_shtab_ahriman_help_version_options=( _shtab_ahriman_help_version_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_help_version_defaults_added=0
_shtab_ahriman_init_options=( _shtab_ahriman_init_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
"--build-as-user[force makepkg user to the specific one (default\: None)]:build_as_user:" "--build-as-user[force makepkg user to the specific one (default\: None)]:build_as_user:"
@@ -213,12 +253,18 @@ _shtab_ahriman_init_options=(
"--web-unix-socket[path to unix socket used for interprocess communications (default\: None)]:web_unix_socket:" "--web-unix-socket[path to unix socket used for interprocess communications (default\: None)]:web_unix_socket:"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_init_defaults_added=0
_shtab_ahriman_key_import_options=( _shtab_ahriman_key_import_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
"--key-server[key server for key import (default\: keyserver.ubuntu.com)]:key_server:" "--key-server[key server for key import (default\: keyserver.ubuntu.com)]:key_server:"
":PGP key to import from public server:" ":PGP key to import from public server:"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_key_import_defaults_added=0
_shtab_ahriman_package_add_options=( _shtab_ahriman_package_add_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{--changes,--no-changes}"[calculate changes from the latest known commit if available (default\: True)]:changes:" {--changes,--no-changes}"[calculate changes from the latest known commit if available (default\: True)]:changes:"
@@ -233,17 +279,26 @@ _shtab_ahriman_package_add_options=(
"(*):package source (base name, path to local files, remote URL):" "(*):package source (base name, path to local files, remote URL):"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_package_add_defaults_added=0
_shtab_ahriman_package_changes_options=( _shtab_ahriman_package_changes_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]" {-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
":package base:" ":package base:"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_package_changes_defaults_added=0
_shtab_ahriman_package_changes_remove_options=( _shtab_ahriman_package_changes_remove_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
":package base:" ":package base:"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_package_changes_remove_defaults_added=0
_shtab_ahriman_package_copy_options=( _shtab_ahriman_package_copy_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]" {-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
@@ -252,11 +307,17 @@ _shtab_ahriman_package_copy_options=(
"(*):package base:" "(*):package base:"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_package_copy_defaults_added=0
_shtab_ahriman_package_remove_options=( _shtab_ahriman_package_remove_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
"(*):package name or base:" "(*):package name or base:"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_package_remove_defaults_added=0
_shtab_ahriman_package_status_options=( _shtab_ahriman_package_status_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
"--ahriman[get service status itself (default\: False)]" "--ahriman[get service status itself (default\: False)]"
@@ -266,17 +327,26 @@ _shtab_ahriman_package_status_options=(
"(*)::filter status by package base (default\: None):" "(*)::filter status by package base (default\: None):"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_package_status_defaults_added=0
_shtab_ahriman_package_status_remove_options=( _shtab_ahriman_package_status_remove_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
"(*):remove specified packages from status page:" "(*):remove specified packages from status page:"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_package_status_remove_defaults_added=0
_shtab_ahriman_package_status_update_options=( _shtab_ahriman_package_status_update_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{-s,--status}"[new package build status (default\: success)]:status:(unknown pending building failed success)" {-s,--status}"[new package build status (default\: success)]:status:(unknown pending building failed success)"
"(*)::set status for specified packages. If no packages supplied, service status will be updated (default\: None):" "(*)::set status for specified packages. If no packages supplied, service status will be updated (default\: None):"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_package_status_update_defaults_added=0
_shtab_ahriman_package_update_options=( _shtab_ahriman_package_update_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{--changes,--no-changes}"[calculate changes from the latest known commit if available (default\: True)]:changes:" {--changes,--no-changes}"[calculate changes from the latest known commit if available (default\: True)]:changes:"
@@ -291,6 +361,9 @@ _shtab_ahriman_package_update_options=(
"(*):package source (base name, path to local files, remote URL):" "(*):package source (base name, path to local files, remote URL):"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_package_update_defaults_added=0
_shtab_ahriman_patch_add_options=( _shtab_ahriman_patch_add_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
":package base:" ":package base:"
@@ -298,6 +371,9 @@ _shtab_ahriman_patch_add_options=(
":path to file which contains function or variable value. If not set, the value will be read from stdin (default\: None):" ":path to file which contains function or variable value. If not set, the value will be read from stdin (default\: None):"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_patch_add_defaults_added=0
_shtab_ahriman_patch_list_options=( _shtab_ahriman_patch_list_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]" {-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
@@ -305,18 +381,27 @@ _shtab_ahriman_patch_list_options=(
":package base:" ":package base:"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_patch_list_defaults_added=0
_shtab_ahriman_patch_remove_options=( _shtab_ahriman_patch_remove_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
"*"{-v,--variable}"[should be used for single-function patches in case if you wold like to remove only specified PKGBUILD variables. In case if not set, it will remove all patches related to the package (default\: None)]:variable:" "*"{-v,--variable}"[should be used for single-function patches in case if you wold like to remove only specified PKGBUILD variables. In case if not set, it will remove all patches related to the package (default\: None)]:variable:"
":package base:" ":package base:"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_patch_remove_defaults_added=0
_shtab_ahriman_patch_set_add_options=( _shtab_ahriman_patch_set_add_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
"*"{-t,--track}"[files which has to be tracked (default\: \[\'\*.diff\', \'\*.patch\'\])]:track:" "*"{-t,--track}"[files which has to be tracked (default\: \[\'\*.diff\', \'\*.patch\'\])]:track:"
":path to directory with changed files for patch addition\/update:" ":path to directory with changed files for patch addition\/update:"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_patch_set_add_defaults_added=0
_shtab_ahriman_rebuild_options=( _shtab_ahriman_rebuild_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
"*--depends-on[only rebuild packages that depend on specified packages (default\: None)]:depends_on:" "*--depends-on[only rebuild packages that depend on specified packages (default\: None)]:depends_on:"
@@ -328,21 +413,33 @@ _shtab_ahriman_rebuild_options=(
{-u,--username}"[build as user (default\: None)]:username:" {-u,--username}"[build as user (default\: None)]:username:"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_rebuild_defaults_added=0
_shtab_ahriman_remove_options=( _shtab_ahriman_remove_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
"(*):package name or base:" "(*):package name or base:"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_remove_defaults_added=0
_shtab_ahriman_remove_unknown_options=( _shtab_ahriman_remove_unknown_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
"--dry-run[just perform check for packages without removal (default\: False)]" "--dry-run[just perform check for packages without removal (default\: False)]"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_remove_unknown_defaults_added=0
_shtab_ahriman_repo_backup_options=( _shtab_ahriman_repo_backup_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
":path of the output archive:" ":path of the output archive:"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_repo_backup_defaults_added=0
_shtab_ahriman_repo_check_options=( _shtab_ahriman_repo_check_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{--changes,--no-changes}"[calculate changes from the latest known commit if available (default\: True)]:changes:" {--changes,--no-changes}"[calculate changes from the latest known commit if available (default\: True)]:changes:"
@@ -353,6 +450,9 @@ _shtab_ahriman_repo_check_options=(
"(*)::filter check by package base (default\: None):" "(*)::filter check by package base (default\: None):"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_repo_check_defaults_added=0
_shtab_ahriman_repo_clean_options=( _shtab_ahriman_repo_clean_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{--cache,--no-cache}"[clear directory with package caches (default\: False)]:cache:" {--cache,--no-cache}"[clear directory with package caches (default\: False)]:cache:"
@@ -362,6 +462,9 @@ _shtab_ahriman_repo_clean_options=(
{--pacman,--no-pacman}"[clear directory with pacman local database cache (default\: False)]:pacman:" {--pacman,--no-pacman}"[clear directory with pacman local database cache (default\: False)]:pacman:"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_repo_clean_defaults_added=0
_shtab_ahriman_repo_config_options=( _shtab_ahriman_repo_config_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{--info,--no-info}"[show additional information, e.g. configuration files (default\: True)]:info:" {--info,--no-info}"[show additional information, e.g. configuration files (default\: True)]:info:"
@@ -370,19 +473,31 @@ _shtab_ahriman_repo_config_options=(
":filter settings by key (default\: None):" ":filter settings by key (default\: None):"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_repo_config_defaults_added=0
_shtab_ahriman_repo_config_validate_options=( _shtab_ahriman_repo_config_validate_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{-e,--exit-code}"[return non-zero exit status if configuration is invalid (default\: False)]" {-e,--exit-code}"[return non-zero exit status if configuration is invalid (default\: False)]"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_repo_config_validate_defaults_added=0
_shtab_ahriman_repo_create_keyring_options=( _shtab_ahriman_repo_create_keyring_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_repo_create_keyring_defaults_added=0
_shtab_ahriman_repo_create_mirrorlist_options=( _shtab_ahriman_repo_create_mirrorlist_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_repo_create_mirrorlist_defaults_added=0
_shtab_ahriman_repo_daemon_options=( _shtab_ahriman_repo_daemon_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{-i,--interval}"[interval between runs in seconds (default\: 43200)]:interval:" {-i,--interval}"[interval between runs in seconds (default\: 43200)]:interval:"
@@ -400,6 +515,9 @@ _shtab_ahriman_repo_daemon_options=(
"*"{-y,--refresh}"[download fresh package databases from the mirror before actions, -yy to force refresh even if up to date (default\: False)]" "*"{-y,--refresh}"[download fresh package databases from the mirror before actions, -yy to force refresh even if up to date (default\: False)]"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_repo_daemon_defaults_added=0
_shtab_ahriman_repo_init_options=( _shtab_ahriman_repo_init_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
"--build-as-user[force makepkg user to the specific one (default\: None)]:build_as_user:" "--build-as-user[force makepkg user to the specific one (default\: None)]:build_as_user:"
@@ -416,6 +534,9 @@ _shtab_ahriman_repo_init_options=(
"--web-unix-socket[path to unix socket used for interprocess communications (default\: None)]:web_unix_socket:" "--web-unix-socket[path to unix socket used for interprocess communications (default\: None)]:web_unix_socket:"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_repo_init_defaults_added=0
_shtab_ahriman_repo_rebuild_options=( _shtab_ahriman_repo_rebuild_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
"*--depends-on[only rebuild packages that depend on specified packages (default\: None)]:depends_on:" "*--depends-on[only rebuild packages that depend on specified packages (default\: None)]:depends_on:"
@@ -427,21 +548,33 @@ _shtab_ahriman_repo_rebuild_options=(
{-u,--username}"[build as user (default\: None)]:username:" {-u,--username}"[build as user (default\: None)]:username:"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_repo_rebuild_defaults_added=0
_shtab_ahriman_repo_remove_unknown_options=( _shtab_ahriman_repo_remove_unknown_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
"--dry-run[just perform check for packages without removal (default\: False)]" "--dry-run[just perform check for packages without removal (default\: False)]"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_repo_remove_unknown_defaults_added=0
_shtab_ahriman_repo_report_options=( _shtab_ahriman_repo_report_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_repo_report_defaults_added=0
_shtab_ahriman_repo_restore_options=( _shtab_ahriman_repo_restore_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{-o,--output}"[root path of the extracted files (default\: \/)]:output:" {-o,--output}"[root path of the extracted files (default\: \/)]:output:"
":path of the input archive:" ":path of the input archive:"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_repo_restore_defaults_added=0
_shtab_ahriman_repo_setup_options=( _shtab_ahriman_repo_setup_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
"--build-as-user[force makepkg user to the specific one (default\: None)]:build_as_user:" "--build-as-user[force makepkg user to the specific one (default\: None)]:build_as_user:"
@@ -458,11 +591,17 @@ _shtab_ahriman_repo_setup_options=(
"--web-unix-socket[path to unix socket used for interprocess communications (default\: None)]:web_unix_socket:" "--web-unix-socket[path to unix socket used for interprocess communications (default\: None)]:web_unix_socket:"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_repo_setup_defaults_added=0
_shtab_ahriman_repo_sign_options=( _shtab_ahriman_repo_sign_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
"(*)::sign only specified packages (default\: None):" "(*)::sign only specified packages (default\: None):"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_repo_sign_defaults_added=0
_shtab_ahriman_repo_statistics_options=( _shtab_ahriman_repo_statistics_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
"--chart[create updates chart and save it to the specified path (default\: None)]:chart:" "--chart[create updates chart and save it to the specified path (default\: None)]:chart:"
@@ -474,25 +613,40 @@ _shtab_ahriman_repo_statistics_options=(
":fetch only events for the specified package (default\: None):" ":fetch only events for the specified package (default\: None):"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_repo_statistics_defaults_added=0
_shtab_ahriman_repo_status_update_options=( _shtab_ahriman_repo_status_update_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{-s,--status}"[new status (default\: success)]:status:(unknown pending building failed success)" {-s,--status}"[new status (default\: success)]:status:(unknown pending building failed success)"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_repo_status_update_defaults_added=0
_shtab_ahriman_repo_sync_options=( _shtab_ahriman_repo_sync_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_repo_sync_defaults_added=0
_shtab_ahriman_repo_tree_options=( _shtab_ahriman_repo_tree_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{-p,--partitions}"[also divide packages by independent partitions (default\: 1)]:partitions:" {-p,--partitions}"[also divide packages by independent partitions (default\: 1)]:partitions:"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_repo_tree_defaults_added=0
_shtab_ahriman_repo_triggers_options=( _shtab_ahriman_repo_triggers_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
"(*)::instead of running all triggers as set by configuration, just process specified ones in order of mention (default\: None):" "(*)::instead of running all triggers as set by configuration, just process specified ones in order of mention (default\: None):"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_repo_triggers_defaults_added=0
_shtab_ahriman_repo_update_options=( _shtab_ahriman_repo_update_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{--aur,--no-aur}"[enable or disable checking for AUR updates (default\: True)]:aur:" {--aur,--no-aur}"[enable or disable checking for AUR updates (default\: True)]:aur:"
@@ -510,15 +664,24 @@ _shtab_ahriman_repo_update_options=(
"(*)::filter check by package base (default\: None):" "(*)::filter check by package base (default\: None):"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_repo_update_defaults_added=0
_shtab_ahriman_report_options=( _shtab_ahriman_report_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_report_defaults_added=0
_shtab_ahriman_run_options=( _shtab_ahriman_run_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
"(*):command to be run (quoted) without \`\`ahriman\`\`:" "(*):command to be run (quoted) without \`\`ahriman\`\`:"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_run_defaults_added=0
_shtab_ahriman_search_options=( _shtab_ahriman_search_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]" {-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
@@ -527,6 +690,9 @@ _shtab_ahriman_search_options=(
"(*):search terms, can be specified multiple times, the result will match all terms:" "(*):search terms, can be specified multiple times, the result will match all terms:"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_search_defaults_added=0
_shtab_ahriman_service_clean_options=( _shtab_ahriman_service_clean_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{--cache,--no-cache}"[clear directory with package caches (default\: False)]:cache:" {--cache,--no-cache}"[clear directory with package caches (default\: False)]:cache:"
@@ -536,6 +702,9 @@ _shtab_ahriman_service_clean_options=(
{--pacman,--no-pacman}"[clear directory with pacman local database cache (default\: False)]:pacman:" {--pacman,--no-pacman}"[clear directory with pacman local database cache (default\: False)]:pacman:"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_service_clean_defaults_added=0
_shtab_ahriman_service_config_options=( _shtab_ahriman_service_config_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{--info,--no-info}"[show additional information, e.g. configuration files (default\: True)]:info:" {--info,--no-info}"[show additional information, e.g. configuration files (default\: True)]:info:"
@@ -544,27 +713,42 @@ _shtab_ahriman_service_config_options=(
":filter settings by key (default\: None):" ":filter settings by key (default\: None):"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_service_config_defaults_added=0
_shtab_ahriman_service_config_validate_options=( _shtab_ahriman_service_config_validate_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{-e,--exit-code}"[return non-zero exit status if configuration is invalid (default\: False)]" {-e,--exit-code}"[return non-zero exit status if configuration is invalid (default\: False)]"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_service_config_validate_defaults_added=0
_shtab_ahriman_service_key_import_options=( _shtab_ahriman_service_key_import_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
"--key-server[key server for key import (default\: keyserver.ubuntu.com)]:key_server:" "--key-server[key server for key import (default\: keyserver.ubuntu.com)]:key_server:"
":PGP key to import from public server:" ":PGP key to import from public server:"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_service_key_import_defaults_added=0
_shtab_ahriman_service_repositories_options=( _shtab_ahriman_service_repositories_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{--id-only,--no-id-only}"[show machine readable identifier instead (default\: False)]:id_only:" {--id-only,--no-id-only}"[show machine readable identifier instead (default\: False)]:id_only:"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_service_repositories_defaults_added=0
_shtab_ahriman_service_run_options=( _shtab_ahriman_service_run_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
"(*):command to be run (quoted) without \`\`ahriman\`\`:" "(*):command to be run (quoted) without \`\`ahriman\`\`:"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_service_run_defaults_added=0
_shtab_ahriman_service_setup_options=( _shtab_ahriman_service_setup_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
"--build-as-user[force makepkg user to the specific one (default\: None)]:build_as_user:" "--build-as-user[force makepkg user to the specific one (default\: None)]:build_as_user:"
@@ -581,16 +765,25 @@ _shtab_ahriman_service_setup_options=(
"--web-unix-socket[path to unix socket used for interprocess communications (default\: None)]:web_unix_socket:" "--web-unix-socket[path to unix socket used for interprocess communications (default\: None)]:web_unix_socket:"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_service_setup_defaults_added=0
_shtab_ahriman_service_shell_options=( _shtab_ahriman_service_shell_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{-o,--output}"[output commands and result to the file (default\: None)]:output:" {-o,--output}"[output commands and result to the file (default\: None)]:output:"
":instead of dropping into shell, just execute the specified code (default\: None):" ":instead of dropping into shell, just execute the specified code (default\: None):"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_service_shell_defaults_added=0
_shtab_ahriman_service_tree_migrate_options=( _shtab_ahriman_service_tree_migrate_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_service_tree_migrate_defaults_added=0
_shtab_ahriman_setup_options=( _shtab_ahriman_setup_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
"--build-as-user[force makepkg user to the specific one (default\: None)]:build_as_user:" "--build-as-user[force makepkg user to the specific one (default\: None)]:build_as_user:"
@@ -607,17 +800,26 @@ _shtab_ahriman_setup_options=(
"--web-unix-socket[path to unix socket used for interprocess communications (default\: None)]:web_unix_socket:" "--web-unix-socket[path to unix socket used for interprocess communications (default\: None)]:web_unix_socket:"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_setup_defaults_added=0
_shtab_ahriman_shell_options=( _shtab_ahriman_shell_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{-o,--output}"[output commands and result to the file (default\: None)]:output:" {-o,--output}"[output commands and result to the file (default\: None)]:output:"
":instead of dropping into shell, just execute the specified code (default\: None):" ":instead of dropping into shell, just execute the specified code (default\: None):"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_shell_defaults_added=0
_shtab_ahriman_sign_options=( _shtab_ahriman_sign_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
"(*)::sign only specified packages (default\: None):" "(*)::sign only specified packages (default\: None):"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_sign_defaults_added=0
_shtab_ahriman_status_options=( _shtab_ahriman_status_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
"--ahriman[get service status itself (default\: False)]" "--ahriman[get service status itself (default\: False)]"
@@ -627,16 +829,25 @@ _shtab_ahriman_status_options=(
"(*)::filter status by package base (default\: None):" "(*)::filter status by package base (default\: None):"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_status_defaults_added=0
_shtab_ahriman_status_update_options=( _shtab_ahriman_status_update_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{-s,--status}"[new package build status (default\: success)]:status:(unknown pending building failed success)" {-s,--status}"[new package build status (default\: success)]:status:(unknown pending building failed success)"
"(*)::set status for specified packages. If no packages supplied, service status will be updated (default\: None):" "(*)::set status for specified packages. If no packages supplied, service status will be updated (default\: None):"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_status_update_defaults_added=0
_shtab_ahriman_sync_options=( _shtab_ahriman_sync_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_sync_defaults_added=0
_shtab_ahriman_update_options=( _shtab_ahriman_update_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{--aur,--no-aur}"[enable or disable checking for AUR updates (default\: True)]:aur:" {--aur,--no-aur}"[enable or disable checking for AUR updates (default\: True)]:aur:"
@@ -654,6 +865,9 @@ _shtab_ahriman_update_options=(
"(*)::filter check by package base (default\: None):" "(*)::filter check by package base (default\: None):"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_update_defaults_added=0
_shtab_ahriman_user_add_options=( _shtab_ahriman_user_add_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
"--key[optional PGP key used by this user. The private key must be imported (default\: None)]:key:" "--key[optional PGP key used by this user. The private key must be imported (default\: None)]:key:"
@@ -663,6 +877,9 @@ _shtab_ahriman_user_add_options=(
":username for web service:" ":username for web service:"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_user_add_defaults_added=0
_shtab_ahriman_user_list_options=( _shtab_ahriman_user_list_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]" {-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
@@ -670,25 +887,48 @@ _shtab_ahriman_user_list_options=(
":filter users by username (default\: None):" ":filter users by username (default\: None):"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_user_list_defaults_added=0
_shtab_ahriman_user_remove_options=( _shtab_ahriman_user_remove_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
":username for web service:" ":username for web service:"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_user_remove_defaults_added=0
_shtab_ahriman_version_options=( _shtab_ahriman_version_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_version_defaults_added=0
_shtab_ahriman_web_options=( _shtab_ahriman_web_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
) )
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_web_defaults_added=0
_shtab_ahriman_web_reload_options=(
"(- : *)"{-h,--help}"[show this help message and exit]"
)
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_web_reload_defaults_added=0
_shtab_ahriman() { _shtab_ahriman() {
local context state line curcontext="$curcontext" one_or_more='(-)*' remainder='(*)' local context state line curcontext="$curcontext" one_or_more='(*)' remainder='(-)*' default='*::: :->ahriman'
if ((${_shtab_ahriman_options[(I)${(q)one_or_more}*]} + ${_shtab_ahriman_options[(I)${(q)remainder}*]} == 0)); then # noqa: E501 # Add default positional/remainder specs only if none exist, and only once per session
_shtab_ahriman_options+=(': :_shtab_ahriman_commands' '*::: :->ahriman') if (( ! _shtab_ahriman_defaults_added )); then
if (( ${_shtab_ahriman_options[(I)${(q)one_or_more}*]} + ${_shtab_ahriman_options[(I)${(q)remainder}*]} + ${_shtab_ahriman_options[(I)${(q)default}]} == 0 )); then
_shtab_ahriman_options+=(': :_shtab_ahriman_commands' '*::: :->ahriman')
fi
_shtab_ahriman_defaults_added=1
fi fi
_arguments -C -s $_shtab_ahriman_options _arguments -C -s $_shtab_ahriman_options
@@ -773,6 +1013,7 @@ _shtab_ahriman() {
user-remove) _arguments -C -s $_shtab_ahriman_user_remove_options ;; user-remove) _arguments -C -s $_shtab_ahriman_user_remove_options ;;
version) _arguments -C -s $_shtab_ahriman_version_options ;; version) _arguments -C -s $_shtab_ahriman_version_options ;;
web) _arguments -C -s $_shtab_ahriman_web_options ;; web) _arguments -C -s $_shtab_ahriman_web_options ;;
web-reload) _arguments -C -s $_shtab_ahriman_web_reload_options ;;
esac esac
esac esac
} }

View File

@@ -17,4 +17,4 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
__version__ = "2.19.0" __version__ = "2.20.0rc1"

View File

@@ -22,6 +22,7 @@ from collections.abc import Iterable
from ahriman.application.application.application_properties import ApplicationProperties from ahriman.application.application.application_properties import ApplicationProperties
from ahriman.application.application.workers import Updater from ahriman.application.application.workers import Updater
from ahriman.core.build_tools.sources import Sources from ahriman.core.build_tools.sources import Sources
from ahriman.core.exceptions import UnknownPackageError
from ahriman.models.package import Package from ahriman.models.package import Package
from ahriman.models.packagers import Packagers from ahriman.models.packagers import Packagers
from ahriman.models.result import Result from ahriman.models.result import Result
@@ -116,7 +117,7 @@ class ApplicationRepository(ApplicationProperties):
for single in probe.packages: for single in probe.packages:
try: try:
_ = Package.from_aur(single, None) _ = Package.from_aur(single, None)
except Exception: except UnknownPackageError:
packages.append(single) packages.append(single)
return packages return packages

View File

@@ -20,7 +20,7 @@
import argparse import argparse
import logging import logging
from collections.abc import Callable, Iterable from collections.abc import Callable
from multiprocessing import Pool from multiprocessing import Pool
from typing import ClassVar, TypeVar from typing import ClassVar, TypeVar
@@ -28,9 +28,9 @@ from ahriman.application.lock import Lock
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.exceptions import ExitCode, MissingArchitectureError, MultipleArchitecturesError from ahriman.core.exceptions import ExitCode, MissingArchitectureError, MultipleArchitecturesError
from ahriman.core.log.log_loader import LogLoader from ahriman.core.log.log_loader import LogLoader
from ahriman.core.repository import Explorer
from ahriman.core.types import ExplicitBool from ahriman.core.types import ExplicitBool
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
from ahriman.models.repository_paths import RepositoryPaths
# this workaround is for several things # this workaround is for several things
@@ -169,11 +169,6 @@ class Handler:
Raises: Raises:
MissingArchitectureError: if no architecture set and automatic detection is not allowed or failed 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 # preparse systemd repository-id argument
# we are using unescaped values, so / is not allowed here, because it is impossible to separate if from dashes # 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: if args.repository_id is not None:
@@ -184,27 +179,10 @@ class Handler:
if repository_parts: if repository_parts:
args.repository = "-".join(repository_parts) # replace slash with dash args.repository = "-".join(repository_parts) # replace slash with dash
# extract repository names first configuration = Configuration()
if (from_args := args.repository) is not None: configuration.load(args.configuration)
repositories: Iterable[str] = [from_args] repositories = Explorer.repositories_extract(configuration, args.repository, args.architecture)
elif from_filesystem := RepositoryPaths.known_repositories(root):
repositories = from_filesystem
else: # try to read configuration now
repositories = [configuration.get("repository", "name")]
# extract architecture names if not repositories:
if (architecture := args.architecture) is not None:
parsed = set(
RepositoryId(architecture, repository)
for repository in repositories
)
else: # try to read from file system
parsed = set(
RepositoryId(architecture, repository)
for repository in repositories
for architecture in RepositoryPaths.known_architectures(root, repository)
)
if not parsed:
raise MissingArchitectureError(args.command) raise MissingArchitectureError(args.command)
return sorted(parsed) return sorted(repositories)

View File

@@ -50,7 +50,8 @@ class ArchiveTree(LazyLogging):
self.repository_id = repository_path.repository_id self.repository_id = repository_path.repository_id
self.sign_args = sign_args self.sign_args = sign_args
def _package_symlinks_create(self, package_description: PackageDescription, root: Path, archive: Path) -> bool: @staticmethod
def _package_symlinks_create(package_description: PackageDescription, root: Path, archive: Path) -> bool:
""" """
process symlinks creation for single package process symlinks creation for single package

View File

@@ -22,6 +22,11 @@ try:
except ImportError: except ImportError:
aiohttp_security = None # type: ignore[assignment] aiohttp_security = None # type: ignore[assignment]
try:
import aiohttp_session
except ImportError:
aiohttp_session = None # type: ignore[assignment]
from typing import Any from typing import Any
@@ -50,7 +55,7 @@ async def check_authorized(*args: Any, **kwargs: Any) -> Any:
Args: Args:
*args(Any): argument list as provided by check_authorized function *args(Any): argument list as provided by check_authorized function
**kwargs(Any): named argument list as provided by authorized_userid function **kwargs(Any): named argument list as provided by check_authorized function
Returns: Returns:
Any: ``None`` in case if no aiohttp_security module found and function call otherwise Any: ``None`` in case if no aiohttp_security module found and function call otherwise
@@ -66,7 +71,7 @@ async def forget(*args: Any, **kwargs: Any) -> Any:
Args: Args:
*args(Any): argument list as provided by forget function *args(Any): argument list as provided by forget function
**kwargs(Any): named argument list as provided by authorized_userid function **kwargs(Any): named argument list as provided by forget function
Returns: Returns:
Any: ``None`` in case if no aiohttp_security module found and function call otherwise Any: ``None`` in case if no aiohttp_security module found and function call otherwise
@@ -76,13 +81,29 @@ async def forget(*args: Any, **kwargs: Any) -> Any:
return None return None
async def get_session(*args: Any, **kwargs: Any) -> Any:
"""
handle aiohttp session methods
Args:
*args(Any): argument list as provided by get_session function
**kwargs(Any): named argument list as provided by get_session function
Returns:
Any: empty dictionary in case if no aiohttp_session module found and function call otherwise
"""
if aiohttp_session is not None:
return await aiohttp_session.get_session(*args, **kwargs)
return {}
async def remember(*args: Any, **kwargs: Any) -> Any: async def remember(*args: Any, **kwargs: Any) -> Any:
""" """
handle disabled auth handle disabled auth
Args: Args:
*args(Any): argument list as provided by remember function *args(Any): argument list as provided by remember function
**kwargs(Any): named argument list as provided by authorized_userid function **kwargs(Any): named argument list as provided by remember function
Returns: Returns:
Any: ``None`` in case if no aiohttp_security module found and function call otherwise Any: ``None`` in case if no aiohttp_security module found and function call otherwise

View File

@@ -19,6 +19,8 @@
# #
import aioauth_client import aioauth_client
from typing import Any
from ahriman.core.auth.mapping import Mapping from ahriman.core.auth.mapping import Mapping
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.database import SQLite from ahriman.core.database import SQLite
@@ -53,7 +55,7 @@ class OAuth(Mapping):
self.client_secret = configuration.get("auth", "client_secret") self.client_secret = configuration.get("auth", "client_secret")
# in order to use OAuth feature the service must be publicity available # in order to use OAuth feature the service must be publicity available
# thus we expect that address is set # thus we expect that address is set
self.redirect_uri = f"""{configuration.get("web", "address")}/api/v1/login""" self.redirect_uri = f"{configuration.get("web", "address")}/api/v1/login"
self.provider = self.get_provider(configuration.get("auth", "oauth_provider")) self.provider = self.get_provider(configuration.get("auth", "oauth_provider"))
# it is list, but we will have to convert to string it anyway # it is list, but we will have to convert to string it anyway
self.scopes = configuration.get("auth", "oauth_scopes") self.scopes = configuration.get("auth", "oauth_scopes")
@@ -102,27 +104,35 @@ class OAuth(Mapping):
""" """
return self.provider(client_id=self.client_id, client_secret=self.client_secret) return self.provider(client_id=self.client_id, client_secret=self.client_secret)
def get_oauth_url(self) -> str: def get_oauth_url(self, state: str) -> str:
""" """
get authorization URI for the specified settings get authorization URI for the specified settings
Args:
state(str): CSRF token to pass to OAuth2 provider
Returns: Returns:
str: authorization URI as a string str: authorization URI as a string
""" """
client = self.get_client() client = self.get_client()
uri: str = client.get_authorize_url(scope=self.scopes, redirect_uri=self.redirect_uri) uri: str = client.get_authorize_url(scope=self.scopes, redirect_uri=self.redirect_uri, state=state)
return uri return uri
async def get_oauth_username(self, code: str) -> str | None: async def get_oauth_username(self, code: str, state: str | None, session: dict[str, Any]) -> str | None:
""" """
extract OAuth username from remote extract OAuth username from remote
Args: Args:
code(str): authorization code provided by external service code(str): authorization code provided by external service
state(str | None): CSRF token returned by external service
session(dict[str, Any]): current session instance
Returns: Returns:
str | None: username as is in OAuth provider str | None: username as is in OAuth provider
""" """
if state is None or state != session.get("state"):
return None
try: try:
client = self.get_client() client = self.get_client()
access_token, _ = await client.get_access_token(code, redirect_uri=self.redirect_uri) access_token, _ = await client.get_access_token(code, redirect_uri=self.redirect_uri)

View File

@@ -17,14 +17,12 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
import argparse
from dataclasses import replace from dataclasses import replace
from sqlite3 import Connection from sqlite3 import Connection
from ahriman.application.handlers.handler import Handler
from ahriman.core.alpm.pacman import Pacman from ahriman.core.alpm.pacman import Pacman
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.repository import Explorer
from ahriman.core.sign.gpg import GPG from ahriman.core.sign.gpg import GPG
from ahriman.core.utils import atomic_move, package_like, symlink_relative from ahriman.core.utils import atomic_move, package_like, symlink_relative
from ahriman.models.package import Package from ahriman.models.package import Package
@@ -45,10 +43,7 @@ def migrate_data(connection: Connection, configuration: Configuration) -> None:
""" """
del connection del connection
config_path, _ = configuration.check_loaded() for repository_id in Explorer.repositories_extract(configuration):
args = argparse.Namespace(configuration=config_path, architecture=None, repository=None, repository_id=None)
for repository_id in Handler.repositories_extract(args):
paths = replace(configuration.repository_paths, repository_id=repository_id) paths = replace(configuration.repository_paths, repository_id=repository_id)
pacman = Pacman(repository_id, configuration, refresh_database=PacmanSynchronization.Disabled) pacman = Pacman(repository_id, configuration, refresh_database=PacmanSynchronization.Disabled)

View File

@@ -141,14 +141,15 @@ class LogsOperations(Operations):
connection.execute( connection.execute(
""" """
delete from logs delete from logs
where (package_base, version, repository, process_id) not in ( where repository = :repository
select package_base, version, repository, process_id from logs and (package_base, version, repository, process_id) not in (
where (package_base, version, repository, created) in ( select package_base, version, repository, process_id from logs
select package_base, version, repository, max(created) from logs where (package_base, version, repository, created) in (
where repository = :repository select package_base, version, repository, max(created) from logs
group by package_base, version, repository where repository = :repository
group by package_base, version, repository
)
) )
)
""", """,
{ {
"repository": repository_id.id, "repository": repository_id.id,

View File

@@ -48,6 +48,10 @@ class RemotePullTrigger(Trigger):
"gitremote": { "gitremote": {
"type": "dict", "type": "dict",
"schema": { "schema": {
"type": {
"type": "string",
"allowed": ["gitremote"],
},
"pull_url": { "pull_url": {
"type": "string", "type": "string",
"required": True, "required": True,
@@ -60,7 +64,6 @@ class RemotePullTrigger(Trigger):
}, },
}, },
} }
CONFIGURATION_SCHEMA_FALLBACK = "gitremote"
def __init__(self, repository_id: RepositoryId, configuration: Configuration) -> None: def __init__(self, repository_id: RepositoryId, configuration: Configuration) -> None:
""" """
@@ -89,7 +92,6 @@ class RemotePullTrigger(Trigger):
trigger action which will be called at the start of the application trigger action which will be called at the start of the application
""" """
for target in self.targets: for target in self.targets:
section, _ = self.configuration.gettype( section, _ = self.configuration.gettype(target, self.repository_id, fallback="gitremote")
target, self.repository_id, fallback=self.CONFIGURATION_SCHEMA_FALLBACK)
runner = RemotePull(self.repository_id, self.configuration, section) runner = RemotePull(self.repository_id, self.configuration, section)
runner.run() runner.run()

View File

@@ -52,6 +52,10 @@ class RemotePushTrigger(Trigger):
"gitremote": { "gitremote": {
"type": "dict", "type": "dict",
"schema": { "schema": {
"type": {
"type": "string",
"allowed": ["gitremote"],
},
"commit_email": { "commit_email": {
"type": "string", "type": "string",
"empty": False, "empty": False,
@@ -72,7 +76,6 @@ class RemotePushTrigger(Trigger):
}, },
}, },
} }
CONFIGURATION_SCHEMA_FALLBACK = "gitremote"
def __init__(self, repository_id: RepositoryId, configuration: Configuration) -> None: def __init__(self, repository_id: RepositoryId, configuration: Configuration) -> None:
""" """
@@ -111,7 +114,6 @@ class RemotePushTrigger(Trigger):
reporter = ctx.get(Client) reporter = ctx.get(Client)
for target in self.targets: for target in self.targets:
section, _ = self.configuration.gettype( section, _ = self.configuration.gettype(target, self.repository_id, fallback="gitremote")
target, self.repository_id, fallback=self.CONFIGURATION_SCHEMA_FALLBACK)
runner = RemotePush(reporter, self.configuration, section) runner = RemotePush(reporter, self.configuration, section)
runner.run(result) runner.run(result)

View File

@@ -17,4 +17,5 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
from ahriman.core.repository.explorer import Explorer
from ahriman.core.repository.repository import Repository from ahriman.core.repository.repository import Repository

View File

@@ -20,7 +20,6 @@
import shutil import shutil
from collections.abc import Iterable from collections.abc import Iterable
from filelock import FileLock
from pathlib import Path from pathlib import Path
from tempfile import TemporaryDirectory from tempfile import TemporaryDirectory
@@ -28,7 +27,7 @@ from ahriman.core.build_tools.package_archive import PackageArchive
from ahriman.core.build_tools.task import Task from ahriman.core.build_tools.task import Task
from ahriman.core.repository.cleaner import Cleaner from ahriman.core.repository.cleaner import Cleaner
from ahriman.core.repository.package_info import PackageInfo from ahriman.core.repository.package_info import PackageInfo
from ahriman.core.utils import atomic_move, list_flatmap, package_like, safe_filename, symlink_relative from ahriman.core.utils import atomic_move, filelock, list_flatmap, package_like, safe_filename, symlink_relative
from ahriman.models.changes import Changes from ahriman.models.changes import Changes
from ahriman.models.event import EventType from ahriman.models.event import EventType
from ahriman.models.package import Package from ahriman.models.package import Package
@@ -112,7 +111,7 @@ class Executor(PackageInfo, Cleaner):
self.logger.info("using prebuilt packages for %s-%s", loaded_package.base, loaded_package.version) self.logger.info("using prebuilt packages for %s-%s", loaded_package.base, loaded_package.version)
built = [] built = []
for artifact in prebuilt: for artifact in prebuilt:
with FileLock(artifact.with_name(f".{artifact.name}.lock")): with filelock(artifact):
shutil.copy(artifact, path) shutil.copy(artifact, path)
built.append(path / artifact.name) built.append(path / artifact.name)
else: else:

View File

@@ -0,0 +1,70 @@
#
# Copyright (c) 2021-2026 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 collections.abc import Iterable
from ahriman.core.configuration import Configuration
from ahriman.models.repository_id import RepositoryId
from ahriman.models.repository_paths import RepositoryPaths
class Explorer:
"""
helper to read filesystem and find created repositories
"""
@staticmethod
def repositories_extract(configuration: Configuration, repository: str | None = None,
architecture: str | None = None) -> list[RepositoryId]:
"""
get known architectures
Args:
configuration(Configuration): configuration instance
repository(str | None, optional): predefined repository name if available (Default value = None)
architecture(str | None, optional): predefined repository architecture if available (Default value = None)
Returns:
list[RepositoryId]: list of repository names and architectures for which tree is created
"""
# pylint, wtf???
root = configuration.getpath("repository", "root") # pylint: disable=assignment-from-no-return
# extract repository names first
if repository is not None:
repositories: Iterable[str] = [repository]
elif from_filesystem := RepositoryPaths.known_repositories(root):
repositories = from_filesystem
else: # try to read configuration now
repositories = [configuration.get("repository", "name")]
# extract architecture names
if architecture is not None:
parsed = set(
RepositoryId(architecture, repository)
for repository in repositories
)
else: # try to read from file system
parsed = set(
RepositoryId(architecture, repository)
for repository in repositories
for architecture in RepositoryPaths.known_architectures(root, repository)
)
return sorted(parsed)

View File

@@ -185,8 +185,9 @@ class UpdateHandler(PackageInfo, Cleaner):
else: else:
self.reporter.set_pending(local.base) self.reporter.set_pending(local.base)
self.event(local.base, EventType.PackageOutdated, "Manual update is requested") self.event(local.base, EventType.PackageOutdated, "Manual update is requested")
self.clear_queue()
except Exception: except Exception:
self.logger.exception("could not load packages from database") self.logger.exception("could not load packages from database")
self.clear_queue()
return result return result

View File

@@ -34,8 +34,6 @@ class Trigger(LazyLogging):
Attributes: Attributes:
CONFIGURATION_SCHEMA(ConfigurationSchema): (class attribute) configuration schema template CONFIGURATION_SCHEMA(ConfigurationSchema): (class attribute) configuration schema template
CONFIGURATION_SCHEMA_FALLBACK(str | None): (class attribute) optional fallback option for defining
configuration schema type used
REQUIRES_REPOSITORY(bool): (class attribute) either trigger requires loaded repository or not REQUIRES_REPOSITORY(bool): (class attribute) either trigger requires loaded repository or not
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
repository_id(RepositoryId): repository unique identifier repository_id(RepositoryId): repository unique identifier
@@ -59,7 +57,6 @@ class Trigger(LazyLogging):
""" """
CONFIGURATION_SCHEMA: ClassVar[ConfigurationSchema] = {} CONFIGURATION_SCHEMA: ClassVar[ConfigurationSchema] = {}
CONFIGURATION_SCHEMA_FALLBACK: ClassVar[str | None] = None
REQUIRES_REPOSITORY: ClassVar[bool] = True REQUIRES_REPOSITORY: ClassVar[bool] = True
def __init__(self, repository_id: RepositoryId, configuration: Configuration) -> None: def __init__(self, repository_id: RepositoryId, configuration: Configuration) -> None:

View File

@@ -18,6 +18,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
# pylint: disable=too-many-lines # pylint: disable=too-many-lines
import contextlib
import datetime import datetime
import io import io
import itertools import itertools
@@ -47,6 +48,7 @@ __all__ = [
"dataclass_view", "dataclass_view",
"enum_values", "enum_values",
"extract_user", "extract_user",
"filelock",
"filter_json", "filter_json",
"full_version", "full_version",
"list_flatmap", "list_flatmap",
@@ -87,7 +89,7 @@ def atomic_move(src: Path, dst: Path) -> None:
>>> atomic_move(src, dst) >>> atomic_move(src, dst)
""" """
with FileLock(dst.with_name(f".{dst.name}.lock")): with filelock(dst):
shutil.move(src, dst) shutil.move(src, dst)
@@ -262,6 +264,25 @@ def extract_user() -> str | None:
return os.getenv("SUDO_USER") or os.getenv("DOAS_USER") or os.getenv("USER") return os.getenv("SUDO_USER") or os.getenv("DOAS_USER") or os.getenv("USER")
@contextlib.contextmanager
def filelock(path: Path) -> Iterator[FileLock]:
"""
wrapper around :class:`filelock.FileLock`, which also removes locks afterward
Args:
path(Path): path to lock on. The lock file will be created as ``.{path.name}.lock``
Yields:
FileLock: acquired file lock instance
"""
lock_path = path.with_name(f".{path.name}.lock")
try:
with FileLock(lock_path) as lock:
yield lock
finally:
lock_path.unlink(missing_ok=True)
def filter_json(source: dict[str, Any], known_fields: Iterable[str]) -> dict[str, Any]: def filter_json(source: dict[str, Any], known_fields: Iterable[str]) -> dict[str, Any]:
""" """
filter json object by fields used for json-to-object conversion filter json object by fields used for json-to-object conversion
@@ -308,10 +329,10 @@ def list_flatmap(source: Iterable[T], extractor: Callable[[T], Iterable[R]]) ->
Args: Args:
source(Iterable[T]): source list source(Iterable[T]): source list
extractor(Callable[[T], list[R]): property extractor extractor(Callable[[T], Iterable[R]]): property extractor
Returns: Returns:
list[T]: combined list of unique entries in properties list list[R]: combined list of unique entries in properties list
""" """
def generator() -> Iterator[R]: def generator() -> Iterator[R]:
for inner in source: for inner in source:

View File

@@ -155,7 +155,7 @@ class Package(LazyLogging):
bool: ``True`` in case if package base looks like VCS package and ``False`` otherwise bool: ``True`` in case if package base looks like VCS package and ``False`` otherwise
""" """
return self.base.endswith("-bzr") \ return self.base.endswith("-bzr") \
or self.base.endswith("-csv") \ or self.base.endswith("-cvs") \
or self.base.endswith("-darcs") \ or self.base.endswith("-darcs") \
or self.base.endswith("-git") \ or self.base.endswith("-git") \
or self.base.endswith("-hg") \ or self.base.endswith("-hg") \

View File

@@ -28,3 +28,6 @@ class OAuth2Schema(Schema):
code = fields.String(metadata={ code = fields.String(metadata={
"description": "OAuth2 authorization code. In case if not set, the redirect to provider will be initiated", "description": "OAuth2 authorization code. In case if not set, the redirect to provider will be initiated",
}) })
state = fields.String(metadata={
"description": "CSRF token returned by OAuth2 provider",
})

View File

@@ -18,9 +18,10 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
from aiohttp.web import HTTPBadRequest, HTTPFound, HTTPMethodNotAllowed, HTTPUnauthorized from aiohttp.web import HTTPBadRequest, HTTPFound, HTTPMethodNotAllowed, HTTPUnauthorized
from secrets import token_urlsafe
from typing import ClassVar from typing import ClassVar
from ahriman.core.auth.helpers import remember from ahriman.core.auth.helpers import get_session, remember
from ahriman.models.user_access import UserAccess from ahriman.models.user_access import UserAccess
from ahriman.web.apispec.decorators import apidocs from ahriman.web.apispec.decorators import apidocs
from ahriman.web.schemas import LoginSchema, OAuth2Schema from ahriman.web.schemas import LoginSchema, OAuth2Schema
@@ -68,15 +69,18 @@ class LoginView(BaseView):
raise HTTPMethodNotAllowed(self.request.method, ["POST"]) raise HTTPMethodNotAllowed(self.request.method, ["POST"])
oauth_provider = self.validator oauth_provider = self.validator
if not isinstance(oauth_provider, OAuth): # there is actually property, but mypy does not like it anyway if not isinstance(oauth_provider, OAuth):
raise HTTPMethodNotAllowed(self.request.method, ["POST"]) raise HTTPMethodNotAllowed(self.request.method, ["POST"])
session = await get_session(self.request)
code = self.request.query.get("code") code = self.request.query.get("code")
if not code: if not code:
raise HTTPFound(oauth_provider.get_oauth_url()) state = session["state"] = token_urlsafe()
raise HTTPFound(oauth_provider.get_oauth_url(state))
response = HTTPFound("/") response = HTTPFound("/")
identity = await oauth_provider.get_oauth_username(code) identity = await oauth_provider.get_oauth_username(code, self.request.query.get("state"), session)
if identity is not None and await self.validator.known_username(identity): if identity is not None and await self.validator.known_username(identity):
await remember(self.request, response, identity) await remember(self.request, response, identity)
raise response raise response

View File

@@ -5,6 +5,7 @@ from pytest_mock import MockerFixture
from unittest.mock import call as MockCall from unittest.mock import call as MockCall
from ahriman.application.application.application_repository import ApplicationRepository from ahriman.application.application.application_repository import ApplicationRepository
from ahriman.core.exceptions import UnknownPackageError
from ahriman.core.tree import Leaf, Tree from ahriman.core.tree import Leaf, Tree
from ahriman.models.changes import Changes from ahriman.models.changes import Changes
from ahriman.models.package import Package from ahriman.models.package import Package
@@ -135,7 +136,7 @@ def test_unknown_no_aur(application_repository: ApplicationRepository, package_a
must return empty list in case if there is locally stored PKGBUILD must return empty list in case if there is locally stored PKGBUILD
""" """
mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[package_ahriman]) mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[package_ahriman])
mocker.patch("ahriman.models.package.Package.from_aur", side_effect=Exception) mocker.patch("ahriman.models.package.Package.from_aur", side_effect=UnknownPackageError(package_ahriman.base))
mocker.patch("ahriman.models.package.Package.from_build", return_value=package_ahriman) mocker.patch("ahriman.models.package.Package.from_build", return_value=package_ahriman)
mocker.patch("pathlib.Path.is_dir", return_value=True) mocker.patch("pathlib.Path.is_dir", return_value=True)
mocker.patch("ahriman.core.build_tools.sources.Sources.has_remotes", return_value=False) mocker.patch("ahriman.core.build_tools.sources.Sources.has_remotes", return_value=False)
@@ -149,7 +150,7 @@ def test_unknown_no_aur_no_local(application_repository: ApplicationRepository,
must return list of packages missing in aur and in local storage must return list of packages missing in aur and in local storage
""" """
mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[package_ahriman]) mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[package_ahriman])
mocker.patch("ahriman.models.package.Package.from_aur", side_effect=Exception) mocker.patch("ahriman.models.package.Package.from_aur", side_effect=UnknownPackageError(package_ahriman.base))
mocker.patch("pathlib.Path.is_dir", return_value=False) mocker.patch("pathlib.Path.is_dir", return_value=False)
packages = application_repository.unknown() packages = application_repository.unknown()

View File

@@ -145,63 +145,11 @@ def test_repositories_extract(args: argparse.Namespace, configuration: Configura
args.configuration = configuration.path args.configuration = configuration.path
args.repository = "repo" args.repository = "repo"
mocker.patch("ahriman.core.configuration.Configuration.load", new=lambda self, _: self.copy_from(configuration)) mocker.patch("ahriman.core.configuration.Configuration.load", new=lambda self, _: self.copy_from(configuration))
known_architectures_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_architectures") extract_mock = mocker.patch("ahriman.core.repository.Explorer.repositories_extract",
known_repositories_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_repositories") return_value=[RepositoryId("arch", "repo")])
assert Handler.repositories_extract(args) == [RepositoryId("arch", "repo")] assert Handler.repositories_extract(args) == [RepositoryId("arch", "repo")]
known_architectures_mock.assert_not_called() extract_mock.assert_called_once_with(pytest.helpers.anyvar(Configuration, True), args.repository, args.architecture)
known_repositories_mock.assert_not_called()
def test_repositories_extract_repository(args: argparse.Namespace, configuration: Configuration,
mocker: MockerFixture) -> None:
"""
must generate list of available repositories based on flags and tree
"""
args.architecture = "arch"
args.configuration = configuration.path
mocker.patch("ahriman.core.configuration.Configuration.load", new=lambda self, _: self.copy_from(configuration))
known_architectures_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_architectures")
known_repositories_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_repositories",
return_value={"repo"})
assert Handler.repositories_extract(args) == [RepositoryId("arch", "repo")]
known_architectures_mock.assert_not_called()
known_repositories_mock.assert_called_once_with(configuration.repository_paths.root)
def test_repositories_extract_repository_legacy(args: argparse.Namespace, configuration: Configuration,
mocker: MockerFixture) -> None:
"""
must generate list of available repositories based on flags and tree (legacy mode)
"""
args.architecture = "arch"
args.configuration = configuration.path
mocker.patch("ahriman.core.configuration.Configuration.load", new=lambda self, _: self.copy_from(configuration))
known_architectures_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_architectures")
known_repositories_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_repositories",
return_value=set())
assert Handler.repositories_extract(args) == [RepositoryId("arch", "aur")]
known_architectures_mock.assert_not_called()
known_repositories_mock.assert_called_once_with(configuration.repository_paths.root)
def test_repositories_extract_architecture(args: argparse.Namespace, configuration: Configuration,
mocker: MockerFixture) -> None:
"""
must read repository name from config
"""
args.configuration = configuration.path
args.repository = "repo"
mocker.patch("ahriman.core.configuration.Configuration.load", new=lambda self, _: self.copy_from(configuration))
known_architectures_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_architectures",
return_value={"arch"})
known_repositories_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_repositories")
assert Handler.repositories_extract(args) == [RepositoryId("arch", "repo")]
known_architectures_mock.assert_called_once_with(configuration.repository_paths.root, "repo")
known_repositories_mock.assert_not_called()
def test_repositories_extract_empty(args: argparse.Namespace, configuration: Configuration, def test_repositories_extract_empty(args: argparse.Namespace, configuration: Configuration,
@@ -212,8 +160,7 @@ def test_repositories_extract_empty(args: argparse.Namespace, configuration: Con
args.command = "config" args.command = "config"
args.configuration = configuration.path args.configuration = configuration.path
mocker.patch("ahriman.core.configuration.Configuration.load", new=lambda self, _: self.copy_from(configuration)) mocker.patch("ahriman.core.configuration.Configuration.load", new=lambda self, _: self.copy_from(configuration))
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_architectures", return_value=set()) mocker.patch("ahriman.core.repository.Explorer.repositories_extract", return_value=[])
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_repositories", return_value=set())
with pytest.raises(MissingArchitectureError): with pytest.raises(MissingArchitectureError):
Handler.repositories_extract(args) Handler.repositories_extract(args)
@@ -227,12 +174,11 @@ def test_repositories_extract_systemd(args: argparse.Namespace, configuration: C
args.configuration = configuration.path args.configuration = configuration.path
args.repository_id = "i686/some/repo/name" args.repository_id = "i686/some/repo/name"
mocker.patch("ahriman.core.configuration.Configuration.load", new=lambda self, _: self.copy_from(configuration)) mocker.patch("ahriman.core.configuration.Configuration.load", new=lambda self, _: self.copy_from(configuration))
known_architectures_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_architectures") extract_mock = mocker.patch("ahriman.core.repository.Explorer.repositories_extract",
known_repositories_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_repositories") return_value=[RepositoryId("i686", "some-repo-name")])
assert Handler.repositories_extract(args) == [RepositoryId("i686", "some-repo-name")] assert Handler.repositories_extract(args) == [RepositoryId("i686", "some-repo-name")]
known_architectures_mock.assert_not_called() extract_mock.assert_called_once_with(pytest.helpers.anyvar(Configuration, True), "some-repo-name", "i686")
known_repositories_mock.assert_not_called()
def test_repositories_extract_systemd_with_dash(args: argparse.Namespace, configuration: Configuration, def test_repositories_extract_systemd_with_dash(args: argparse.Namespace, configuration: Configuration,
@@ -243,12 +189,11 @@ def test_repositories_extract_systemd_with_dash(args: argparse.Namespace, config
args.configuration = configuration.path args.configuration = configuration.path
args.repository_id = "i686-some-repo-name" args.repository_id = "i686-some-repo-name"
mocker.patch("ahriman.core.configuration.Configuration.load", new=lambda self, _: self.copy_from(configuration)) mocker.patch("ahriman.core.configuration.Configuration.load", new=lambda self, _: self.copy_from(configuration))
known_architectures_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_architectures") extract_mock = mocker.patch("ahriman.core.repository.Explorer.repositories_extract",
known_repositories_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_repositories") return_value=[RepositoryId("i686", "some-repo-name")])
assert Handler.repositories_extract(args) == [RepositoryId("i686", "some-repo-name")] assert Handler.repositories_extract(args) == [RepositoryId("i686", "some-repo-name")]
known_architectures_mock.assert_not_called() extract_mock.assert_called_once_with(pytest.helpers.anyvar(Configuration, True), "some-repo-name", "i686")
known_repositories_mock.assert_not_called()
def test_repositories_extract_systemd_legacy(args: argparse.Namespace, configuration: Configuration, def test_repositories_extract_systemd_legacy(args: argparse.Namespace, configuration: Configuration,
@@ -259,10 +204,8 @@ def test_repositories_extract_systemd_legacy(args: argparse.Namespace, configura
args.configuration = configuration.path args.configuration = configuration.path
args.repository_id = "i686" args.repository_id = "i686"
mocker.patch("ahriman.core.configuration.Configuration.load", new=lambda self, _: self.copy_from(configuration)) mocker.patch("ahriman.core.configuration.Configuration.load", new=lambda self, _: self.copy_from(configuration))
known_architectures_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_architectures") extract_mock = mocker.patch("ahriman.core.repository.Explorer.repositories_extract",
known_repositories_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_repositories", return_value=[RepositoryId("i686", "aur")])
return_value=set())
assert Handler.repositories_extract(args) == [RepositoryId("i686", "aur")] assert Handler.repositories_extract(args) == [RepositoryId("i686", "aur")]
known_architectures_mock.assert_not_called() extract_mock.assert_called_once_with(pytest.helpers.anyvar(Configuration, True), None, "i686")
known_repositories_mock.assert_called_once_with(configuration.repository_paths.root)

View File

@@ -13,6 +13,13 @@ def test_import_aiohttp_security() -> None:
assert helpers.aiohttp_security assert helpers.aiohttp_security
def test_import_aiohttp_session() -> None:
"""
must import aiohttp_session correctly
"""
assert helpers.aiohttp_session
async def test_authorized_userid_dummy(mocker: MockerFixture) -> None: async def test_authorized_userid_dummy(mocker: MockerFixture) -> None:
""" """
must not call authorized_userid from library if not enabled must not call authorized_userid from library if not enabled
@@ -55,6 +62,23 @@ async def test_forget_dummy(mocker: MockerFixture) -> None:
await helpers.forget() await helpers.forget()
async def test_get_session_dummy(mocker: MockerFixture) -> None:
"""
must return empty dict if no aiohttp_session module found
"""
mocker.patch.object(helpers, "aiohttp_session", None)
assert await helpers.get_session() == {}
async def test_get_session_library(mocker: MockerFixture) -> None:
"""
must call get_session from library if enabled
"""
get_session_mock = mocker.patch("aiohttp_session.get_session")
await helpers.get_session()
get_session_mock.assert_called_once_with()
async def test_forget_library(mocker: MockerFixture) -> None: async def test_forget_library(mocker: MockerFixture) -> None:
""" """
must call forget from library if enabled must call forget from library if enabled
@@ -88,3 +112,12 @@ def test_import_aiohttp_security_missing(mocker: MockerFixture) -> None:
mocker.patch.dict(sys.modules, {"aiohttp_security": None}) mocker.patch.dict(sys.modules, {"aiohttp_security": None})
importlib.reload(helpers) importlib.reload(helpers)
assert helpers.aiohttp_security is None assert helpers.aiohttp_security is None
def test_import_aiohttp_session_missing(mocker: MockerFixture) -> None:
"""
must set missing flag if no aiohttp_session module found
"""
mocker.patch.dict(sys.modules, {"aiohttp_session": None})
importlib.reload(helpers)
assert helpers.aiohttp_session is None

View File

@@ -57,8 +57,8 @@ def test_get_oauth_url(oauth: OAuth, mocker: MockerFixture) -> None:
must generate valid OAuth authorization URL must generate valid OAuth authorization URL
""" """
authorize_url_mock = mocker.patch("aioauth_client.GoogleClient.get_authorize_url") authorize_url_mock = mocker.patch("aioauth_client.GoogleClient.get_authorize_url")
oauth.get_oauth_url() oauth.get_oauth_url(state="state")
authorize_url_mock.assert_called_once_with(scope=oauth.scopes, redirect_uri=oauth.redirect_uri) authorize_url_mock.assert_called_once_with(scope=oauth.scopes, redirect_uri=oauth.redirect_uri, state="state")
async def test_get_oauth_username(oauth: OAuth, mocker: MockerFixture) -> None: async def test_get_oauth_username(oauth: OAuth, mocker: MockerFixture) -> None:
@@ -69,10 +69,9 @@ async def test_get_oauth_username(oauth: OAuth, mocker: MockerFixture) -> None:
user_info_mock = mocker.patch("aioauth_client.GoogleClient.user_info", user_info_mock = mocker.patch("aioauth_client.GoogleClient.user_info",
return_value=(aioauth_client.User(email="email"), "")) return_value=(aioauth_client.User(email="email"), ""))
email = await oauth.get_oauth_username("code") assert await oauth.get_oauth_username("code", state="state", session={"state": "state"}) == "email"
access_token_mock.assert_called_once_with("code", redirect_uri=oauth.redirect_uri) access_token_mock.assert_called_once_with("code", redirect_uri=oauth.redirect_uri)
user_info_mock.assert_called_once_with() user_info_mock.assert_called_once_with()
assert email == "email"
async def test_get_oauth_username_empty_email(oauth: OAuth, mocker: MockerFixture) -> None: async def test_get_oauth_username_empty_email(oauth: OAuth, mocker: MockerFixture) -> None:
@@ -82,8 +81,7 @@ async def test_get_oauth_username_empty_email(oauth: OAuth, mocker: MockerFixtur
mocker.patch("aioauth_client.GoogleClient.get_access_token", return_value=("token", "")) mocker.patch("aioauth_client.GoogleClient.get_access_token", return_value=("token", ""))
mocker.patch("aioauth_client.GoogleClient.user_info", return_value=(aioauth_client.User(username="username"), "")) mocker.patch("aioauth_client.GoogleClient.user_info", return_value=(aioauth_client.User(username="username"), ""))
username = await oauth.get_oauth_username("code") assert await oauth.get_oauth_username("code", state="state", session={"state": "state"}) == "username"
assert username == "username"
async def test_get_oauth_username_exception_1(oauth: OAuth, mocker: MockerFixture) -> None: async def test_get_oauth_username_exception_1(oauth: OAuth, mocker: MockerFixture) -> None:
@@ -93,8 +91,7 @@ async def test_get_oauth_username_exception_1(oauth: OAuth, mocker: MockerFixtur
mocker.patch("aioauth_client.GoogleClient.get_access_token", side_effect=Exception) mocker.patch("aioauth_client.GoogleClient.get_access_token", side_effect=Exception)
user_info_mock = mocker.patch("aioauth_client.GoogleClient.user_info") user_info_mock = mocker.patch("aioauth_client.GoogleClient.user_info")
email = await oauth.get_oauth_username("code") assert await oauth.get_oauth_username("code", state="state", session={"state": "state"}) is None
assert email is None
user_info_mock.assert_not_called() user_info_mock.assert_not_called()
@@ -105,5 +102,19 @@ async def test_get_oauth_username_exception_2(oauth: OAuth, mocker: MockerFixtur
mocker.patch("aioauth_client.GoogleClient.get_access_token", return_value=("token", "")) mocker.patch("aioauth_client.GoogleClient.get_access_token", return_value=("token", ""))
mocker.patch("aioauth_client.GoogleClient.user_info", side_effect=Exception) mocker.patch("aioauth_client.GoogleClient.user_info", side_effect=Exception)
email = await oauth.get_oauth_username("code") username = await oauth.get_oauth_username("code", state="state", session={"state": "state"})
assert email is None assert username is None
async def test_get_oauth_username_csrf_missing(oauth: OAuth) -> None:
"""
must return None if CSRF state is missing
"""
assert await oauth.get_oauth_username("code", state=None, session={"state": "state"}) is None
async def test_get_oauth_username_csrf_mismatch(oauth: OAuth) -> None:
"""
must return None if CSRF state does not match session
"""
assert await oauth.get_oauth_username("code", state="wrong", session={"state": "state"}) is None

View File

@@ -23,7 +23,7 @@ def test_migrate_data(connection: Connection, configuration: Configuration, mock
repository_id, repository_id,
replace(repository_id, architecture="i686"), replace(repository_id, architecture="i686"),
] ]
mocker.patch("ahriman.application.handlers.handler.Handler.repositories_extract", return_value=repositories) mocker.patch("ahriman.core.repository.Explorer.repositories_extract", return_value=repositories)
migration_mock = mocker.patch("ahriman.core.database.migrations.m016_archive.move_packages") migration_mock = mocker.patch("ahriman.core.database.migrations.m016_archive.move_packages")
migrate_data(connection, configuration) migrate_data(connection, configuration)

View File

@@ -16,7 +16,7 @@ def test_load(configuration: Configuration, mocker: MockerFixture) -> None:
init_mock.assert_called_once_with() init_mock.assert_called_once_with()
def test_init(database: SQLite, configuration: Configuration, mocker: MockerFixture) -> None: def test_init(database: SQLite, mocker: MockerFixture) -> None:
""" """
must run migrations on init must run migrations on init
""" """

View File

@@ -2,7 +2,6 @@ import logging
import pytest import pytest
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from unittest.mock import call as MockCall
from ahriman.core.alpm.repo import Repo from ahriman.core.alpm.repo import Repo
from ahriman.core.build_tools.task import Task from ahriman.core.build_tools.task import Task

View File

@@ -0,0 +1,56 @@
from pytest_mock import MockerFixture
from ahriman.core.configuration import Configuration
from ahriman.core.repository import Explorer
from ahriman.models.repository_id import RepositoryId
def test_repositories_extract(configuration: Configuration, mocker: MockerFixture) -> None:
"""
must generate list of available repositories based on arguments
"""
known_architectures_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_architectures")
known_repositories_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_repositories")
assert Explorer.repositories_extract(configuration, "repo", "arch") == [RepositoryId("arch", "repo")]
known_architectures_mock.assert_not_called()
known_repositories_mock.assert_not_called()
def test_repositories_extract_repository(configuration: Configuration, mocker: MockerFixture) -> None:
"""
must generate list of available repositories based on arguments and tree
"""
known_architectures_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_architectures")
known_repositories_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_repositories",
return_value={"repo"})
assert Explorer.repositories_extract(configuration, architecture="arch") == [RepositoryId("arch", "repo")]
known_architectures_mock.assert_not_called()
known_repositories_mock.assert_called_once_with(configuration.repository_paths.root)
def test_repositories_extract_repository_legacy(configuration: Configuration, mocker: MockerFixture) -> None:
"""
must generate list of available repositories based on arguments and tree (legacy mode)
"""
known_architectures_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_architectures")
known_repositories_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_repositories",
return_value=set())
assert Explorer.repositories_extract(configuration, architecture="arch") == [RepositoryId("arch", "aur")]
known_architectures_mock.assert_not_called()
known_repositories_mock.assert_called_once_with(configuration.repository_paths.root)
def test_repositories_extract_architecture(configuration: Configuration, mocker: MockerFixture) -> None:
"""
must read repository name from config
"""
known_architectures_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_architectures",
return_value={"arch"})
known_repositories_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_repositories")
assert Explorer.repositories_extract(configuration, repository="repo") == [RepositoryId("arch", "repo")]
known_architectures_mock.assert_called_once_with(configuration.repository_paths.root, "repo")
known_repositories_mock.assert_not_called()

View File

@@ -357,4 +357,8 @@ def test_updates_manual_with_failures(update_handler: UpdateHandler, package_ahr
""" """
mocker.patch("ahriman.core.database.SQLite.build_queue_get", side_effect=Exception) mocker.patch("ahriman.core.database.SQLite.build_queue_get", side_effect=Exception)
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman]) mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman])
assert update_handler.updates_manual() == [] assert update_handler.updates_manual() == []
from ahriman.core.repository.cleaner import Cleaner
Cleaner.clear_queue.assert_not_called()

View File

@@ -35,7 +35,7 @@ def test_event_get(local_client: LocalClient, package_ahriman: Package, mocker:
local_client.repository_id) local_client.repository_id)
def test_logs_rotate(local_client: LocalClient, package_ahriman: Package, mocker: MockerFixture) -> None: def test_logs_rotate(local_client: LocalClient, mocker: MockerFixture) -> None:
""" """
must rotate logs must rotate logs
""" """

View File

@@ -20,11 +20,11 @@ def test_atomic_move(mocker: MockerFixture) -> None:
""" """
must move file with locking must move file with locking
""" """
filelock_mock = mocker.patch("ahriman.core.utils.FileLock") filelock_mock = mocker.patch("ahriman.core.utils.filelock")
move_mock = mocker.patch("shutil.move") move_mock = mocker.patch("shutil.move")
atomic_move(Path("source"), Path("destination")) atomic_move(Path("source"), Path("destination"))
filelock_mock.assert_called_once_with(Path(".destination.lock")) filelock_mock.assert_called_once_with(Path("destination"))
move_mock.assert_called_once_with(Path("source"), Path("destination")) move_mock.assert_called_once_with(Path("source"), Path("destination"))
@@ -247,6 +247,30 @@ def test_extract_user() -> None:
assert extract_user() == "doas" assert extract_user() == "doas"
def test_filelock(tmp_path: Path) -> None:
"""
must acquire lock and remove lock file after
"""
local = tmp_path / "local"
lock = local.with_name(f".{local.name}.lock")
with filelock(local):
assert lock.exists()
assert not lock.exists()
def test_filelock_cleanup_on_missing(tmp_path: Path) -> None:
"""
must not fail if lock file is already removed
"""
local = tmp_path / "local"
lock = local.with_name(f".{local.name}.lock")
with filelock(local):
lock.unlink(missing_ok=True)
assert not lock.exists()
def test_filter_json(package_ahriman: Package) -> None: def test_filter_json(package_ahriman: Package) -> None:
""" """
must filter fields by known list must filter fields by known list

View File

@@ -58,7 +58,7 @@ def test_configuration_schema_no_schema(configuration: Configuration) -> None:
assert ReportTrigger.configuration_schema(configuration) == {} assert ReportTrigger.configuration_schema(configuration) == {}
def test_configuration_schema_empty(configuration: Configuration) -> None: def test_configuration_schema_empty() -> None:
""" """
must return default schema if no configuration set must return default schema if no configuration set
""" """
@@ -70,7 +70,6 @@ def test_configuration_schema_variables() -> None:
must return empty schema must return empty schema
""" """
assert Trigger.CONFIGURATION_SCHEMA == {} assert Trigger.CONFIGURATION_SCHEMA == {}
assert Trigger.CONFIGURATION_SCHEMA_FALLBACK is None
def test_configuration_sections(configuration: Configuration) -> None: def test_configuration_sections(configuration: Configuration) -> None:

View File

@@ -4,16 +4,12 @@ from pathlib import Path
from unittest.mock import MagicMock, PropertyMock from unittest.mock import MagicMock, PropertyMock
from ahriman import __version__ from ahriman import __version__
from ahriman.core.alpm.remote import AUR
from ahriman.models.build_status import BuildStatus, BuildStatusEnum from ahriman.models.build_status import BuildStatus, BuildStatusEnum
from ahriman.models.counters import Counters from ahriman.models.counters import Counters
from ahriman.models.filesystem_package import FilesystemPackage from ahriman.models.filesystem_package import FilesystemPackage
from ahriman.models.internal_status import InternalStatus from ahriman.models.internal_status import InternalStatus
from ahriman.models.package import Package
from ahriman.models.package_description import PackageDescription from ahriman.models.package_description import PackageDescription
from ahriman.models.package_source import PackageSource
from ahriman.models.pkgbuild import Pkgbuild from ahriman.models.pkgbuild import Pkgbuild
from ahriman.models.remote_source import RemoteSource
from ahriman.models.repository_stats import RepositoryStats from ahriman.models.repository_stats import RepositoryStats

View File

@@ -66,7 +66,7 @@ async def test_delete_partially(client: TestClient, package_ahriman: Package) ->
assert json assert json
async def test_delete_exception(client: TestClient, package_ahriman: Package) -> None: async def test_delete_exception(client: TestClient) -> None:
""" """
must raise exception on invalid payload must raise exception on invalid payload
""" """

View File

@@ -54,7 +54,7 @@ async def test_get_redirect_to_oauth(client_with_oauth_auth: TestClient) -> None
assert not request_schema.validate(payload) assert not request_schema.validate(payload)
response = await client_with_oauth_auth.get("/api/v1/login", params=payload, allow_redirects=False) response = await client_with_oauth_auth.get("/api/v1/login", params=payload, allow_redirects=False)
assert response.ok assert response.ok
oauth.get_oauth_url.assert_called_once_with() oauth.get_oauth_url.assert_called_once_with(pytest.helpers.anyvar(str))
async def test_get_redirect_to_oauth_empty_code(client_with_oauth_auth: TestClient) -> None: async def test_get_redirect_to_oauth_empty_code(client_with_oauth_auth: TestClient) -> None:
@@ -69,13 +69,15 @@ async def test_get_redirect_to_oauth_empty_code(client_with_oauth_auth: TestClie
assert not request_schema.validate(payload) assert not request_schema.validate(payload)
response = await client_with_oauth_auth.get("/api/v1/login", params=payload, allow_redirects=False) response = await client_with_oauth_auth.get("/api/v1/login", params=payload, allow_redirects=False)
assert response.ok assert response.ok
oauth.get_oauth_url.assert_called_once_with() oauth.get_oauth_url.assert_called_once_with(pytest.helpers.anyvar(str))
async def test_get(client_with_oauth_auth: TestClient, mocker: MockerFixture) -> None: async def test_get(client_with_oauth_auth: TestClient, mocker: MockerFixture) -> None:
""" """
must log in user correctly from OAuth must log in user correctly from OAuth
""" """
session = {"state": "state"}
mocker.patch("ahriman.web.views.v1.user.login.get_session", return_value=session)
oauth = client_with_oauth_auth.app[AuthKey] oauth = client_with_oauth_auth.app[AuthKey]
oauth.get_oauth_username.return_value = "user" oauth.get_oauth_username.return_value = "user"
oauth.known_username.return_value = True oauth.known_username.return_value = True
@@ -84,12 +86,12 @@ async def test_get(client_with_oauth_auth: TestClient, mocker: MockerFixture) ->
remember_mock = mocker.patch("ahriman.web.views.v1.user.login.remember") remember_mock = mocker.patch("ahriman.web.views.v1.user.login.remember")
request_schema = pytest.helpers.schema_request(LoginView.get, location="querystring") request_schema = pytest.helpers.schema_request(LoginView.get, location="querystring")
payload = {"code": "code"} payload = {"code": "code", "state": "state"}
assert not request_schema.validate(payload) assert not request_schema.validate(payload)
response = await client_with_oauth_auth.get("/api/v1/login", params=payload) response = await client_with_oauth_auth.get("/api/v1/login", params=payload)
assert response.ok assert response.ok
oauth.get_oauth_username.assert_called_once_with("code") oauth.get_oauth_username.assert_called_once_with("code", "state", session)
oauth.known_username.assert_called_once_with("user") oauth.known_username.assert_called_once_with("user")
remember_mock.assert_called_once_with( remember_mock.assert_called_once_with(
pytest.helpers.anyvar(int), pytest.helpers.anyvar(int), pytest.helpers.anyvar(int)) pytest.helpers.anyvar(int), pytest.helpers.anyvar(int), pytest.helpers.anyvar(int))