Compare commits

...

9 Commits

Author SHA1 Message Date
4d1c881827 Release 2.19.4 2026-02-02 22:50:38 +02:00
833978f8b4 fix: handle permissionerror during walking over tree
Previously it tried to look into 700 directories (e.g. .gnupg) which
breaks running as non-ahriman user
2026-02-02 22:43:48 +02:00
b2e9ba3877 type: replace generator return type with iterator 2026-02-02 22:37:59 +02:00
2c913afb7a Release 2.19.3 2026-01-25 10:46:24 +02:00
65bcf819b1 fix: fallback to package name for missing bases in archive
package zoom is being generated without base, leading to None there

Closes #155
2026-01-25 10:45:56 +02:00
f13a2fde85 type: use as keyword in case match 2026-01-25 10:39:15 +02:00
847c029c46 fix: correctly process trigger repo specific settings in validator (see #154) 2026-01-25 10:24:01 +02:00
a647783252 feat: expose repository name and architecure in configuration if available
In some cases there are reference to current repository settings. In
order to handle it correctly two ro options have been added

Related to #154
2026-01-25 10:23:30 +02:00
5cfcb5c3e8 fix: careful handling of file permissions during initialization
It has been found that during cold start (e.g. in docker container),
some permissions are invalid. In order to handle that, some operations
are not guarded with RepositoryPaths.preserve_root guard

In addition, it has been also found that in some cases (e.g. web server
start) migrations are performed on empty repository identifier which may
lead to wrong data (see also 435375721d),
as well as some unexpected results during database operations. In order
to handle that, now all watcher instances have their own databases (and
configurations)
2026-01-25 10:20:29 +02:00
58 changed files with 831 additions and 374 deletions

View File

@@ -215,6 +215,7 @@ Again, the most checks can be performed by `tox` command, though some additional
* It is allowed to change web API to add new fields or remove optional ones. However, in case of model changes, new API version must be introduced.
* On the other hand, it is allowed to change method signatures, however, it is recommended to add new parameters as optional if possible. Deprecated API can be dropped during major release.
* Enumerations (`Enum` classes) are allowed and recommended. However, it is recommended to use `StrEnum` class if there are from/to string conversions and `IntEnum` otherwise.
* `Generator` return type is not allowed. Generator functions must return generic `Iterator` object. Documentation should be described as `Yields`, however, because of pylint checks. Unfortunately, `Iterable` return type is not available for generators also, because of specific `contextlib.contextmanager` case.
### Other checks

View File

@@ -184,7 +184,7 @@ digraph G {
ahriman_core_upload_upload [fillcolor="blue",fontcolor="white",label="ahriman\.\ncore\.\nupload\.\nupload",shape="box"];
ahriman_core_upload_upload_trigger [fillcolor="blue",fontcolor="white",label="ahriman\.\ncore\.\nupload\.\nupload_trigger",shape="box"];
ahriman_core_util [fillcolor="#ac6349",fontcolor="#ffffff",label="ahriman\.\ncore\.\nutil"];
ahriman_core_utils [fillcolor="#db3d05",fontcolor="#ffffff",label="ahriman\.\ncore\.\nutils"];
ahriman_core_utils [fillcolor="#ef4306",fontcolor="#ffffff",label="ahriman\.\ncore\.\nutils"];
ahriman_models [fillcolor="#f94d10",fontcolor="#ffffff",label="ahriman.models"];
ahriman_models_action [fillcolor="#e75622",fontcolor="#ffffff",label="ahriman\.\nmodels\.\naction"];
ahriman_models_aur_package [fillcolor="#db3d05",fontcolor="#ffffff",label="ahriman\.\nmodels\.\naur_package"];
@@ -215,7 +215,7 @@ digraph G {
ahriman_models_remote_source [fillcolor="#d13a05",fontcolor="#ffffff",label="ahriman\.\nmodels\.\nremote_source"];
ahriman_models_report_settings [fillcolor="#c26747",fontcolor="#ffffff",label="ahriman\.\nmodels\.\nreport_settings"];
ahriman_models_repository_id [fillcolor="#f94d10",fontcolor="#ffffff",label="ahriman\.\nmodels\.\nrepository_id"];
ahriman_models_repository_paths [fillcolor="#d13a05",fontcolor="#ffffff",label="ahriman\.\nmodels\.\nrepository_paths"];
ahriman_models_repository_paths [fillcolor="#c73705",fontcolor="#ffffff",label="ahriman\.\nmodels\.\nrepository_paths"];
ahriman_models_repository_stats [fillcolor="#ca4516",fontcolor="#ffffff",label="ahriman\.\nmodels\.\nrepository_stats"];
ahriman_models_result [fillcolor="#ef4306",fontcolor="#ffffff",label="ahriman\.\nmodels\.\nresult"];
ahriman_models_scan_paths [fillcolor="#ce613b",fontcolor="#ffffff",label="ahriman\.\nmodels\.\nscan_paths"];
@@ -952,56 +952,57 @@ digraph G {
ahriman_core_upload_upload -> ahriman_core_upload_s3 [fillcolor="blue",weight="3"];
ahriman_core_upload_upload -> ahriman_core_upload_upload_trigger [fillcolor="blue",weight="3"];
ahriman_core_upload_upload_trigger -> ahriman_core_upload [fillcolor="blue",weight="3"];
ahriman_core_utils -> ahriman_application_ahriman [fillcolor="#db3d05",minlen="2"];
ahriman_core_utils -> ahriman_application_application_application_packages [fillcolor="#db3d05",minlen="3"];
ahriman_core_utils -> ahriman_application_handlers_add [fillcolor="#db3d05",minlen="3"];
ahriman_core_utils -> ahriman_application_handlers_daemon [fillcolor="#db3d05",minlen="3"];
ahriman_core_utils -> ahriman_application_handlers_rebuild [fillcolor="#db3d05",minlen="3"];
ahriman_core_utils -> ahriman_application_handlers_setup [fillcolor="#db3d05",minlen="3"];
ahriman_core_utils -> ahriman_application_handlers_statistics [fillcolor="#db3d05",minlen="3"];
ahriman_core_utils -> ahriman_application_handlers_status [fillcolor="#db3d05",minlen="3"];
ahriman_core_utils -> ahriman_application_handlers_status_update [fillcolor="#db3d05",minlen="3"];
ahriman_core_utils -> ahriman_application_handlers_update [fillcolor="#db3d05",minlen="3"];
ahriman_core_utils -> ahriman_application_handlers_users [fillcolor="#db3d05",minlen="3"];
ahriman_core_utils -> ahriman_application_lock [fillcolor="#db3d05",minlen="2"];
ahriman_core_utils -> ahriman_core_alpm_pacman [fillcolor="#db3d05",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_alpm_repo [fillcolor="#db3d05",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_auth_pam [fillcolor="#db3d05",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_build_tools_package_archive [fillcolor="#db3d05",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_build_tools_sources [fillcolor="#db3d05",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_build_tools_task [fillcolor="#db3d05",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_formatters_aur_printer [fillcolor="#db3d05",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_formatters_repository_stats_printer [fillcolor="#db3d05",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_formatters_update_printer [fillcolor="#db3d05",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_gitremote_remote_pull [fillcolor="#db3d05",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_report_email [fillcolor="#db3d05",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_report_jinja_template [fillcolor="#db3d05",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_repository_executor [fillcolor="#db3d05",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_repository_package_info [fillcolor="#db3d05",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_sign_gpg [fillcolor="#db3d05",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_support_pkgbuild_pkgbuild_generator [fillcolor="#db3d05",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_tree [fillcolor="#db3d05",weight="2"];
ahriman_core_utils -> ahriman_core_upload_github [fillcolor="#db3d05",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_upload_rsync [fillcolor="#db3d05",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_upload_s3 [fillcolor="#db3d05",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_util [fillcolor="#db3d05",weight="2"];
ahriman_core_utils -> ahriman_models_aur_package [fillcolor="#db3d05",minlen="2"];
ahriman_core_utils -> ahriman_models_build_status [fillcolor="#db3d05",minlen="2"];
ahriman_core_utils -> ahriman_models_changes [fillcolor="#db3d05",minlen="2"];
ahriman_core_utils -> ahriman_models_counters [fillcolor="#db3d05",minlen="2"];
ahriman_core_utils -> ahriman_models_dependencies [fillcolor="#db3d05",minlen="2"];
ahriman_core_utils -> ahriman_models_event [fillcolor="#db3d05",minlen="2"];
ahriman_core_utils -> ahriman_models_filesystem_package [fillcolor="#db3d05",minlen="2"];
ahriman_core_utils -> ahriman_models_internal_status [fillcolor="#db3d05",minlen="2"];
ahriman_core_utils -> ahriman_models_package [fillcolor="#db3d05",minlen="2"];
ahriman_core_utils -> ahriman_models_package_description [fillcolor="#db3d05",minlen="2"];
ahriman_core_utils -> ahriman_models_package_source [fillcolor="#db3d05",minlen="2"];
ahriman_core_utils -> ahriman_models_pkgbuild_patch [fillcolor="#db3d05",minlen="2"];
ahriman_core_utils -> ahriman_models_remote_source [fillcolor="#db3d05",minlen="2"];
ahriman_core_utils -> ahriman_models_repository_stats [fillcolor="#db3d05",minlen="2"];
ahriman_core_utils -> ahriman_models_worker [fillcolor="#db3d05",minlen="2"];
ahriman_core_utils -> ahriman_web_views_api_swagger [fillcolor="#db3d05",minlen="3"];
ahriman_core_utils -> ahriman_web_views_v1_packages_logs [fillcolor="#db3d05",minlen="3"];
ahriman_core_utils -> ahriman_application_ahriman [fillcolor="#ef4306",minlen="2"];
ahriman_core_utils -> ahriman_application_application_application_packages [fillcolor="#ef4306",minlen="3"];
ahriman_core_utils -> ahriman_application_handlers_add [fillcolor="#ef4306",minlen="3"];
ahriman_core_utils -> ahriman_application_handlers_daemon [fillcolor="#ef4306",minlen="3"];
ahriman_core_utils -> ahriman_application_handlers_rebuild [fillcolor="#ef4306",minlen="3"];
ahriman_core_utils -> ahriman_application_handlers_setup [fillcolor="#ef4306",minlen="3"];
ahriman_core_utils -> ahriman_application_handlers_statistics [fillcolor="#ef4306",minlen="3"];
ahriman_core_utils -> ahriman_application_handlers_status [fillcolor="#ef4306",minlen="3"];
ahriman_core_utils -> ahriman_application_handlers_status_update [fillcolor="#ef4306",minlen="3"];
ahriman_core_utils -> ahriman_application_handlers_update [fillcolor="#ef4306",minlen="3"];
ahriman_core_utils -> ahriman_application_handlers_users [fillcolor="#ef4306",minlen="3"];
ahriman_core_utils -> ahriman_application_lock [fillcolor="#ef4306",minlen="2"];
ahriman_core_utils -> ahriman_core_alpm_pacman [fillcolor="#ef4306",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_alpm_repo [fillcolor="#ef4306",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_auth_pam [fillcolor="#ef4306",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_build_tools_package_archive [fillcolor="#ef4306",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_build_tools_sources [fillcolor="#ef4306",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_build_tools_task [fillcolor="#ef4306",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_formatters_aur_printer [fillcolor="#ef4306",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_formatters_repository_stats_printer [fillcolor="#ef4306",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_formatters_update_printer [fillcolor="#ef4306",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_gitremote_remote_pull [fillcolor="#ef4306",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_report_email [fillcolor="#ef4306",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_report_jinja_template [fillcolor="#ef4306",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_repository_executor [fillcolor="#ef4306",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_repository_package_info [fillcolor="#ef4306",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_sign_gpg [fillcolor="#ef4306",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_support_pkgbuild_pkgbuild_generator [fillcolor="#ef4306",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_tree [fillcolor="#ef4306",weight="2"];
ahriman_core_utils -> ahriman_core_upload_github [fillcolor="#ef4306",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_upload_rsync [fillcolor="#ef4306",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_upload_s3 [fillcolor="#ef4306",minlen="2",weight="2"];
ahriman_core_utils -> ahriman_core_util [fillcolor="#ef4306",weight="2"];
ahriman_core_utils -> ahriman_models_aur_package [fillcolor="#ef4306",minlen="2"];
ahriman_core_utils -> ahriman_models_build_status [fillcolor="#ef4306",minlen="2"];
ahriman_core_utils -> ahriman_models_changes [fillcolor="#ef4306",minlen="2"];
ahriman_core_utils -> ahriman_models_counters [fillcolor="#ef4306",minlen="2"];
ahriman_core_utils -> ahriman_models_dependencies [fillcolor="#ef4306",minlen="2"];
ahriman_core_utils -> ahriman_models_event [fillcolor="#ef4306",minlen="2"];
ahriman_core_utils -> ahriman_models_filesystem_package [fillcolor="#ef4306",minlen="2"];
ahriman_core_utils -> ahriman_models_internal_status [fillcolor="#ef4306",minlen="2"];
ahriman_core_utils -> ahriman_models_package [fillcolor="#ef4306",minlen="2"];
ahriman_core_utils -> ahriman_models_package_description [fillcolor="#ef4306",minlen="2"];
ahriman_core_utils -> ahriman_models_package_source [fillcolor="#ef4306",minlen="2"];
ahriman_core_utils -> ahriman_models_pkgbuild_patch [fillcolor="#ef4306",minlen="2"];
ahriman_core_utils -> ahriman_models_remote_source [fillcolor="#ef4306",minlen="2"];
ahriman_core_utils -> ahriman_models_repository_paths [fillcolor="#ef4306",minlen="2"];
ahriman_core_utils -> ahriman_models_repository_stats [fillcolor="#ef4306",minlen="2"];
ahriman_core_utils -> ahriman_models_worker [fillcolor="#ef4306",minlen="2"];
ahriman_core_utils -> ahriman_web_views_api_swagger [fillcolor="#ef4306",minlen="3"];
ahriman_core_utils -> ahriman_web_views_v1_packages_logs [fillcolor="#ef4306",minlen="3"];
ahriman_models -> ahriman_application_ahriman [fillcolor="#f94d10",minlen="2"];
ahriman_models -> ahriman_application_application_application [fillcolor="#f94d10",minlen="3"];
ahriman_models -> ahriman_application_application_application_packages [fillcolor="#f94d10",minlen="3"];
@@ -1136,7 +1137,6 @@ digraph G {
ahriman_models -> ahriman_core_upload_s3 [fillcolor="#f94d10",minlen="3"];
ahriman_models -> ahriman_core_upload_upload [fillcolor="#f94d10",minlen="3"];
ahriman_models -> ahriman_core_upload_upload_trigger [fillcolor="#f94d10",minlen="3"];
ahriman_models -> ahriman_core_utils [fillcolor="#f94d10",minlen="2"];
ahriman_models -> ahriman_web_apispec_decorators [fillcolor="#f94d10",minlen="3"];
ahriman_models -> ahriman_web_keys [fillcolor="#f94d10",minlen="2"];
ahriman_models -> ahriman_web_middlewares_auth_handler [fillcolor="#f94d10",minlen="3"];
@@ -1475,17 +1475,16 @@ digraph G {
ahriman_models_repository_id -> ahriman_web_keys [fillcolor="#f94d10",minlen="2"];
ahriman_models_repository_id -> ahriman_web_views_base [fillcolor="#f94d10",minlen="3"];
ahriman_models_repository_id -> ahriman_web_web [fillcolor="#f94d10",minlen="2"];
ahriman_models_repository_paths -> ahriman_application_handlers_handler [fillcolor="#d13a05",minlen="3"];
ahriman_models_repository_paths -> ahriman_application_handlers_setup [fillcolor="#d13a05",minlen="3"];
ahriman_models_repository_paths -> ahriman_application_handlers_tree_migrate [fillcolor="#d13a05",minlen="3"];
ahriman_models_repository_paths -> ahriman_core_alpm_repo [fillcolor="#d13a05",minlen="3"];
ahriman_models_repository_paths -> ahriman_core_build_tools_sources [fillcolor="#d13a05",minlen="3"];
ahriman_models_repository_paths -> ahriman_core_build_tools_task [fillcolor="#d13a05",minlen="3"];
ahriman_models_repository_paths -> ahriman_core_configuration_configuration [fillcolor="#d13a05",minlen="3"];
ahriman_models_repository_paths -> ahriman_core_repository_repository_properties [fillcolor="#d13a05",minlen="3"];
ahriman_models_repository_paths -> ahriman_core_utils [fillcolor="#d13a05",minlen="2"];
ahriman_models_repository_paths -> ahriman_models_package_source [fillcolor="#d13a05",weight="2"];
ahriman_models_repository_paths -> ahriman_web_views_v1_service_upload [fillcolor="#d13a05",minlen="3"];
ahriman_models_repository_paths -> ahriman_application_handlers_handler [fillcolor="#c73705",minlen="3"];
ahriman_models_repository_paths -> ahriman_application_handlers_setup [fillcolor="#c73705",minlen="3"];
ahriman_models_repository_paths -> ahriman_application_handlers_tree_migrate [fillcolor="#c73705",minlen="3"];
ahriman_models_repository_paths -> ahriman_core_alpm_repo [fillcolor="#c73705",minlen="3"];
ahriman_models_repository_paths -> ahriman_core_build_tools_sources [fillcolor="#c73705",minlen="3"];
ahriman_models_repository_paths -> ahriman_core_build_tools_task [fillcolor="#c73705",minlen="3"];
ahriman_models_repository_paths -> ahriman_core_configuration_configuration [fillcolor="#c73705",minlen="3"];
ahriman_models_repository_paths -> ahriman_core_repository_repository_properties [fillcolor="#c73705",minlen="3"];
ahriman_models_repository_paths -> ahriman_models_package_source [fillcolor="#c73705",weight="2"];
ahriman_models_repository_paths -> ahriman_web_views_v1_service_upload [fillcolor="#c73705",minlen="3"];
ahriman_models_repository_stats -> ahriman_core_formatters_repository_stats_printer [fillcolor="#ca4516",minlen="3"];
ahriman_models_repository_stats -> ahriman_core_status_client [fillcolor="#ca4516",minlen="3"];
ahriman_models_repository_stats -> ahriman_models_internal_status [fillcolor="#ca4516",weight="2"];

View File

@@ -138,6 +138,8 @@ Build related configuration. Group name can refer to architecture, e.g. ``build:
Base repository settings.
* ``architecture`` - repository architecture, string. This field is read-only and generated automatically from run options if possible.
* ``name`` - repository name, string. This field is read-only and generated automatically from run options if possible.
* ``root`` - root path for application, string, required.
``sign:*`` groups

View File

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

View File

@@ -674,6 +674,7 @@ _shtab_ahriman() {
if [[ "$current_action_nargs" != "*" ]] && \
[[ "$current_action_nargs" != "+" ]] && \
[[ "$current_action_nargs" != "?" ]] && \
[[ "$current_action_nargs" != *"..." ]] && \
(( $word_index + 1 - $current_action_args_start_index - $pos_only >= \
$current_action_nargs )); then

View File

@@ -1,9 +1,9 @@
.TH AHRIMAN "1" "2025\-07\-14" "ahriman 2.19.1" "ArcH linux ReposItory MANager"
.TH AHRIMAN "1" "2026\-02\-02" "ahriman 2.19.4" "ArcH linux ReposItory MANager"
.SH NAME
ahriman \- ArcH linux ReposItory MANager
.SH SYNOPSIS
.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} ...
.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} ...
.SH DESCRIPTION
ArcH linux ReposItory MANager
@@ -195,9 +195,9 @@ remove user
web server
.SH COMMAND \fI\,'ahriman aur\-search'\/\fR
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}]
search [search ...]
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}]
search [search ...]
search for package in AUR using API
@@ -220,7 +220,7 @@ sort field by this field. In case if two packages have the same value of the spe
by name
.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
@@ -229,7 +229,7 @@ show help message for application or command and exit
show help message for specific command
.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
@@ -239,7 +239,7 @@ instead of showing commands, just test command line for unsafe subcommand and re
otherwise
.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
@@ -249,15 +249,15 @@ request AUR for current version and compare with current service version
return non\-zero exit code if updates available
.SH COMMAND \fI\,'ahriman help\-version'\/\fR
usage: ahriman help\-version [\-h]
usage: ahriman help\-version [\-h]
print application and its dependencies versions
.SH COMMAND \fI\,'ahriman package\-add'\/\fR
usage: ahriman package\-add [\-h] [\-\-changes | \-\-no\-changes] [\-\-dependencies | \-\-no\-dependencies] [\-e]
[\-\-increment | \-\-no\-increment] [\-n] [\-y]
[\-s {auto,archive,aur,directory,local,remote,repository}] [\-u USERNAME] [\-v VARIABLE]
package [package ...]
usage: ahriman package\-add [\-h] [\-\-changes | \-\-no\-changes] [\-\-dependencies | \-\-no\-dependencies] [\-e]
[\-\-increment | \-\-no\-increment] [\-n] [\-y]
[\-s {auto,archive,aur,directory,local,remote,repository}] [\-u USERNAME] [\-v VARIABLE]
package [package ...]
add existing or new package to the build queue
@@ -303,7 +303,7 @@ build as user
apply specified makepkg variables to the next build
.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
@@ -317,7 +317,7 @@ package base
return non\-zero exit status if result is empty
.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
@@ -326,7 +326,7 @@ remove the package changes stored remotely
package base
.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
@@ -348,7 +348,7 @@ return non\-zero exit status if result is empty
remove package from the source repository after
.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
@@ -357,8 +357,8 @@ remove package from the repository
package name or base
.SH COMMAND \fI\,'ahriman package\-status'\/\fR
usage: ahriman package\-status [\-h] [\-\-ahriman] [\-e] [\-\-info | \-\-no\-info] [\-s {unknown,pending,building,failed,success}]
[package ...]
usage: ahriman package\-status [\-h] [\-\-ahriman] [\-e] [\-\-info | \-\-no\-info] [\-s {unknown,pending,building,failed,success}]
[package ...]
request status of the package
@@ -384,7 +384,7 @@ show additional package information
filter packages by status
.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
@@ -393,7 +393,7 @@ remove the package from the status page
remove specified packages from status page
.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
@@ -407,7 +407,7 @@ set status for specified packages. If no packages supplied, service status will
new package build status
.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
@@ -424,7 +424,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
.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
@@ -442,7 +442,7 @@ return non\-zero exit status if result is empty
if set, show only patches for specified PKGBUILD variables
.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
@@ -457,7 +457,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
.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
@@ -471,7 +471,7 @@ path to directory with changed files for patch addition/update
files which has to be tracked
.SH COMMAND \fI\,'ahriman repo\-backup'\/\fR
usage: ahriman repo\-backup [\-h] path
usage: ahriman repo\-backup [\-h] path
backup repository settings and database
@@ -480,9 +480,9 @@ backup repository settings and database
path of the output archive
.SH COMMAND \fI\,'ahriman repo\-check'\/\fR
usage: ahriman repo\-check [\-h] [\-\-changes | \-\-no\-changes] [\-\-check\-files | \-\-no\-check\-files] [\-e] [\-\-vcs | \-\-no\-vcs]
[\-y]
[package ...]
usage: ahriman repo\-check [\-h] [\-\-changes | \-\-no\-changes] [\-\-check\-files | \-\-no\-check\-files] [\-e] [\-\-vcs | \-\-no\-vcs]
[\-y]
[package ...]
check for packages updates. Same as repo\-update \-\-dry\-run \-\-no\-manual
@@ -512,20 +512,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
.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
.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
.SH COMMAND \fI\,'ahriman repo\-daemon'\/\fR
usage: ahriman repo\-daemon [\-h] [\-i INTERVAL] [\-\-aur | \-\-no\-aur] [\-\-changes | \-\-no\-changes]
[\-\-check\-files | \-\-no\-check\-files] [\-\-dependencies | \-\-no\-dependencies] [\-\-dry\-run]
[\-\-increment | \-\-no\-increment] [\-\-local | \-\-no\-local] [\-\-manual | \-\-no\-manual]
[\-\-partitions | \-\-no\-partitions] [\-u USERNAME] [\-\-vcs | \-\-no\-vcs] [\-y]
usage: ahriman repo\-daemon [\-h] [\-i INTERVAL] [\-\-aur | \-\-no\-aur] [\-\-changes | \-\-no\-changes]
[\-\-check\-files | \-\-no\-check\-files] [\-\-dependencies | \-\-no\-dependencies] [\-\-dry\-run]
[\-\-increment | \-\-no\-increment] [\-\-local | \-\-no\-local] [\-\-manual | \-\-no\-manual]
[\-\-partitions | \-\-no\-partitions] [\-u USERNAME] [\-\-vcs | \-\-no\-vcs] [\-y]
start process which periodically will run update process
@@ -583,8 +583,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
.SH COMMAND \fI\,'ahriman repo\-rebuild'\/\fR
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]
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]
force rebuild whole repository
@@ -620,7 +620,7 @@ filter packages by status. Requires \-\-from\-database to be set
build as user
.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
@@ -630,12 +630,12 @@ remove packages which are missing in AUR and do not have local PKGBUILDs
just perform check for packages without removal
.SH COMMAND \fI\,'ahriman repo\-report'\/\fR
usage: ahriman repo\-report [\-h]
usage: ahriman repo\-report [\-h]
generate repository report according to current settings
.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
@@ -649,7 +649,7 @@ path of the input archive
root path of the extracted files
.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
@@ -658,10 +658,10 @@ usage: ahriman repo\-sign [\-h] [package ...]
sign only specified packages
.SH COMMAND \fI\,'ahriman repo\-statistics'\/\fR
usage: ahriman repo\-statistics [\-h] [\-\-chart CHART]
[\-e {package\-outdated,package\-removed,package\-update\-failed,package\-updated}]
[\-\-from\-date FROM_DATE] [\-\-limit LIMIT] [\-\-offset OFFSET] [\-\-to\-date TO_DATE]
[package]
usage: ahriman repo\-statistics [\-h] [\-\-chart CHART]
[\-e {package\-outdated,package\-removed,package\-update\-failed,package\-updated}]
[\-\-from\-date FROM_DATE] [\-\-limit LIMIT] [\-\-offset OFFSET] [\-\-to\-date TO_DATE]
[package]
fetch repository statistics
@@ -695,7 +695,7 @@ skip specified amount of events
only fetch events which are older than the date
.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
@@ -705,12 +705,12 @@ update repository status on the status page
new status
.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
.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
@@ -720,7 +720,7 @@ dump repository tree based on packages dependencies
also divide packages by independent partitions
.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
@@ -729,10 +729,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
.SH COMMAND \fI\,'ahriman repo\-update'\/\fR
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]
[\-\-local | \-\-no\-local] [\-\-manual | \-\-no\-manual] [\-u USERNAME] [\-\-vcs | \-\-no\-vcs] [\-y]
[package ...]
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]
[\-\-local | \-\-no\-local] [\-\-manual | \-\-no\-manual] [\-u USERNAME] [\-\-vcs | \-\-no\-vcs] [\-y]
[package ...]
check for packages updates and run build process if requested
@@ -790,8 +790,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
.SH COMMAND \fI\,'ahriman service\-clean'\/\fR
usage: ahriman service\-clean [\-h] [\-\-cache | \-\-no\-cache] [\-\-chroot | \-\-no\-chroot] [\-\-manual | \-\-no\-manual]
[\-\-packages | \-\-no\-packages] [\-\-pacman | \-\-no\-pacman]
usage: ahriman service\-clean [\-h] [\-\-cache | \-\-no\-cache] [\-\-chroot | \-\-no\-chroot] [\-\-manual | \-\-no\-manual]
[\-\-packages | \-\-no\-packages] [\-\-pacman | \-\-no\-pacman]
remove local caches
@@ -817,7 +817,7 @@ clear directory with built packages
clear directory with pacman local database cache
.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
@@ -839,7 +839,7 @@ show additional information, e.g. configuration files
hide passwords and secrets from output
.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
@@ -849,7 +849,7 @@ validate configuration and print found errors
return non\-zero exit status if configuration is invalid
.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
@@ -863,7 +863,7 @@ PGP key to import from public server
key server for key import
.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
@@ -873,7 +873,7 @@ list all available repositories
show machine readable identifier instead
.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
@@ -882,11 +882,11 @@ run multiple commands on success run of the previous command
command to be run (quoted) without ``ahriman``
.SH COMMAND \fI\,'ahriman service\-setup'\/\fR
usage: ahriman service\-setup [\-h] [\-\-build\-as\-user BUILD_AS_USER] [\-\-from\-configuration FROM_CONFIGURATION]
[\-\-generate\-salt | \-\-no\-generate\-salt] [\-\-makeflags\-jobs | \-\-no\-makeflags\-jobs]
[\-\-mirror MIRROR] [\-\-multilib | \-\-no\-multilib] \-\-packager PACKAGER [\-\-server SERVER]
[\-\-sign\-key SIGN_KEY] [\-\-sign\-target {disabled,packages,repository}] [\-\-web\-port WEB_PORT]
[\-\-web\-unix\-socket WEB_UNIX_SOCKET]
usage: ahriman service\-setup [\-h] [\-\-build\-as\-user BUILD_AS_USER] [\-\-from\-configuration FROM_CONFIGURATION]
[\-\-generate\-salt | \-\-no\-generate\-salt] [\-\-makeflags\-jobs | \-\-no\-makeflags\-jobs]
[\-\-mirror MIRROR] [\-\-multilib | \-\-no\-multilib] \-\-packager PACKAGER [\-\-server SERVER]
[\-\-sign\-key SIGN_KEY] [\-\-sign\-target {disabled,packages,repository}] [\-\-web\-port WEB_PORT]
[\-\-web\-unix\-socket WEB_UNIX_SOCKET]
create initial service configuration, requires root
@@ -940,7 +940,7 @@ port of the web service
path to unix socket used for interprocess communications
.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
@@ -954,13 +954,13 @@ instead of dropping into shell, just execute the specified code
output commands and result to the file
.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
.SH COMMAND \fI\,'ahriman user\-add'\/\fR
usage: ahriman user\-add [\-h] [\-\-key KEY] [\-\-packager PACKAGER] [\-p PASSWORD] [\-R {unauthorized,read,reporter,full}]
username
usage: ahriman user\-add [\-h] [\-\-key KEY] [\-\-packager PACKAGER] [\-p PASSWORD] [\-R {unauthorized,read,reporter,full}]
username
update user for web services with the given password and role. In case if password was not entered it will be asked interactively
@@ -987,7 +987,7 @@ authorization type.
user access level
.SH COMMAND \fI\,'ahriman user\-list'\/\fR
usage: ahriman user\-list [\-h] [\-e] [\-R {unauthorized,read,reporter,full}] [username]
usage: ahriman user\-list [\-h] [\-e] [\-R {unauthorized,read,reporter,full}] [username]
list users from the user mapping and their roles
@@ -1005,7 +1005,7 @@ return non\-zero exit status if result is empty
filter users by role
.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
@@ -1014,7 +1014,7 @@ remove user from the user mapping and update the configuration
username for web service
.SH COMMAND \fI\,'ahriman web'\/\fR
usage: ahriman web [\-h]
usage: ahriman web [\-h]
start web server

View File

@@ -99,6 +99,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:"
)
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_defaults_added=0
_shtab_ahriman_add_options=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{--changes,--no-changes}"[calculate changes from the latest known commit if available (default\: True)]:changes:"
@@ -113,6 +116,9 @@ _shtab_ahriman_add_options=(
"(*):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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
@@ -121,6 +127,9 @@ _shtab_ahriman_aur_search_options=(
"(*):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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{--changes,--no-changes}"[calculate changes from the latest known commit if available (default\: True)]:changes:"
@@ -131,6 +140,9 @@ _shtab_ahriman_check_options=(
"(*)::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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{--cache,--no-cache}"[clear directory with package caches (default\: False)]:cache:"
@@ -140,6 +152,9 @@ _shtab_ahriman_clean_options=(
{--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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{--info,--no-info}"[show additional information, e.g. configuration files (default\: True)]:info:"
@@ -148,11 +163,17 @@ _shtab_ahriman_config_options=(
":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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{-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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
@@ -161,6 +182,9 @@ _shtab_ahriman_copy_options=(
"(*):package base:"
)
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_copy_defaults_added=0
_shtab_ahriman_daemon_options=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{-i,--interval}"[interval between runs in seconds (default\: 43200)]:interval:"
@@ -178,25 +202,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)]"
)
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_daemon_defaults_added=0
_shtab_ahriman_help_options=(
"(- : *)"{-h,--help}"[show this help message and exit]"
":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=(
"(- : *)"{-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):"
)
# 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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{-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=(
"(- : *)"{-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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
"--build-as-user[force makepkg user to the specific one (default\: None)]:build_as_user:"
@@ -213,12 +252,18 @@ _shtab_ahriman_init_options=(
"--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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
"--key-server[key server for key import (default\: keyserver.ubuntu.com)]:key_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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{--changes,--no-changes}"[calculate changes from the latest known commit if available (default\: True)]:changes:"
@@ -233,17 +278,26 @@ _shtab_ahriman_package_add_options=(
"(*):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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
":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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
":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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
@@ -252,11 +306,17 @@ _shtab_ahriman_package_copy_options=(
"(*):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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
"(*):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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
"--ahriman[get service status itself (default\: False)]"
@@ -266,17 +326,26 @@ _shtab_ahriman_package_status_options=(
"(*)::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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
"(*):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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{-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):"
)
# 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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{--changes,--no-changes}"[calculate changes from the latest known commit if available (default\: True)]:changes:"
@@ -291,6 +360,9 @@ _shtab_ahriman_package_update_options=(
"(*):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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
":package base:"
@@ -298,6 +370,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):"
)
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_patch_add_defaults_added=0
_shtab_ahriman_patch_list_options=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
@@ -305,18 +380,27 @@ _shtab_ahriman_patch_list_options=(
":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=(
"(- : *)"{-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:"
":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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
"*"{-t,--track}"[files which has to be tracked (default\: \[\'\*.diff\', \'\*.patch\'\])]:track:"
":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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
"*--depends-on[only rebuild packages that depend on specified packages (default\: None)]:depends_on:"
@@ -328,21 +412,33 @@ _shtab_ahriman_rebuild_options=(
{-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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
"(*):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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
"--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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
":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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{--changes,--no-changes}"[calculate changes from the latest known commit if available (default\: True)]:changes:"
@@ -353,6 +449,9 @@ _shtab_ahriman_repo_check_options=(
"(*)::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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{--cache,--no-cache}"[clear directory with package caches (default\: False)]:cache:"
@@ -362,6 +461,9 @@ _shtab_ahriman_repo_clean_options=(
{--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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{--info,--no-info}"[show additional information, e.g. configuration files (default\: True)]:info:"
@@ -370,19 +472,31 @@ _shtab_ahriman_repo_config_options=(
":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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{-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=(
"(- : *)"{-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=(
"(- : *)"{-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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{-i,--interval}"[interval between runs in seconds (default\: 43200)]:interval:"
@@ -400,6 +514,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)]"
)
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_repo_daemon_defaults_added=0
_shtab_ahriman_repo_init_options=(
"(- : *)"{-h,--help}"[show this help message and exit]"
"--build-as-user[force makepkg user to the specific one (default\: None)]:build_as_user:"
@@ -416,6 +533,9 @@ _shtab_ahriman_repo_init_options=(
"--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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
"*--depends-on[only rebuild packages that depend on specified packages (default\: None)]:depends_on:"
@@ -427,21 +547,33 @@ _shtab_ahriman_repo_rebuild_options=(
{-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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
"--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=(
"(- : *)"{-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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{-o,--output}"[root path of the extracted files (default\: \/)]:output:"
":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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
"--build-as-user[force makepkg user to the specific one (default\: None)]:build_as_user:"
@@ -458,11 +590,17 @@ _shtab_ahriman_repo_setup_options=(
"--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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
"(*)::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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
"--chart[create updates chart and save it to the specified path (default\: None)]:chart:"
@@ -474,25 +612,40 @@ _shtab_ahriman_repo_statistics_options=(
":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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{-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=(
"(- : *)"{-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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{-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=(
"(- : *)"{-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):"
)
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_repo_triggers_defaults_added=0
_shtab_ahriman_repo_update_options=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{--aur,--no-aur}"[enable or disable checking for AUR updates (default\: True)]:aur:"
@@ -510,15 +663,24 @@ _shtab_ahriman_repo_update_options=(
"(*)::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=(
"(- : *)"{-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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
"(*):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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
@@ -527,6 +689,9 @@ _shtab_ahriman_search_options=(
"(*):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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{--cache,--no-cache}"[clear directory with package caches (default\: False)]:cache:"
@@ -536,6 +701,9 @@ _shtab_ahriman_service_clean_options=(
{--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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{--info,--no-info}"[show additional information, e.g. configuration files (default\: True)]:info:"
@@ -544,27 +712,42 @@ _shtab_ahriman_service_config_options=(
":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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{-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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
"--key-server[key server for key import (default\: keyserver.ubuntu.com)]:key_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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{--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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
"(*):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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
"--build-as-user[force makepkg user to the specific one (default\: None)]:build_as_user:"
@@ -581,16 +764,25 @@ _shtab_ahriman_service_setup_options=(
"--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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{-o,--output}"[output commands and result to the file (default\: None)]:output:"
":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=(
"(- : *)"{-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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
"--build-as-user[force makepkg user to the specific one (default\: None)]:build_as_user:"
@@ -607,17 +799,26 @@ _shtab_ahriman_setup_options=(
"--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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{-o,--output}"[output commands and result to the file (default\: None)]:output:"
":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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
"(*)::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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
"--ahriman[get service status itself (default\: False)]"
@@ -627,16 +828,25 @@ _shtab_ahriman_status_options=(
"(*)::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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{-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):"
)
# guard to ensure default positional specs are added only once per session
_shtab_ahriman_status_update_defaults_added=0
_shtab_ahriman_sync_options=(
"(- : *)"{-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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{--aur,--no-aur}"[enable or disable checking for AUR updates (default\: True)]:aur:"
@@ -654,6 +864,9 @@ _shtab_ahriman_update_options=(
"(*)::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=(
"(- : *)"{-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:"
@@ -663,6 +876,9 @@ _shtab_ahriman_user_add_options=(
":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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
@@ -670,25 +886,41 @@ _shtab_ahriman_user_list_options=(
":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=(
"(- : *)"{-h,--help}"[show this help message and exit]"
":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=(
"(- : *)"{-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=(
"(- : *)"{-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() {
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
_shtab_ahriman_options+=(': :_shtab_ahriman_commands' '*::: :->ahriman')
# Add default positional/remainder specs only if none exist, and only once per session
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
_arguments -C -s $_shtab_ahriman_options

View File

@@ -8,7 +8,7 @@ services:
AHRIMAN_OUTPUT: console
AHRIMAN_PASSWORD: ${AHRIMAN_PASSWORD}
AHRIMAN_PORT: 8080
AHRIMAN_PRESETUP_COMMAND: (cat /run/secrets/password; echo; cat /run/secrets/password) | sudo -u ahriman ahriman user-add demo -R full
AHRIMAN_POSTSETUP_COMMAND: (cat /run/secrets/password; echo; cat /run/secrets/password) | sudo -u ahriman ahriman user-add demo -R full
AHRIMAN_REPOSITORY: ahriman-demo
AHRIMAN_UNIX_SOCKET: /var/lib/ahriman/ahriman/ahriman.sock

View File

@@ -8,7 +8,7 @@ services:
AHRIMAN_OUTPUT: console
AHRIMAN_PASSWORD: ${AHRIMAN_PASSWORD}
AHRIMAN_PORT: 8080
AHRIMAN_PRESETUP_COMMAND: (cat /run/secrets/password; echo; cat /run/secrets/password) | sudo -u ahriman ahriman user-add demo -R full
AHRIMAN_POSTSETUP_COMMAND: (cat /run/secrets/password; echo; cat /run/secrets/password) | sudo -u ahriman ahriman user-add demo -R full
AHRIMAN_REPOSITORY: ahriman-demo
AHRIMAN_UNIX_SOCKET: /var/lib/ahriman/ahriman/ahriman.sock

View File

@@ -8,7 +8,7 @@ services:
AHRIMAN_OUTPUT: console
AHRIMAN_PASSWORD: ${AHRIMAN_PASSWORD}
AHRIMAN_PORT: 8080
AHRIMAN_PRESETUP_COMMAND: (cat /run/secrets/password; echo; cat /run/secrets/password) | sudo -u ahriman ahriman user-add demo -R full
AHRIMAN_POSTSETUP_COMMAND: (cat /run/secrets/password; echo; cat /run/secrets/password) | sudo -u ahriman ahriman user-add demo -R full
AHRIMAN_REPOSITORY: ahriman-demo
AHRIMAN_UNIX_SOCKET: /var/lib/ahriman/ahriman/ahriman.sock
@@ -62,7 +62,7 @@ services:
AHRIMAN_OUTPUT: console
AHRIMAN_PASSWORD: ${AHRIMAN_PASSWORD}
AHRIMAN_PORT: 8080
AHRIMAN_PRESETUP_COMMAND: (cat /run/secrets/password; echo; cat /run/secrets/password) | sudo -u ahriman ahriman user-add demo -R full
AHRIMAN_POSTSETUP_COMMAND: (cat /run/secrets/password; echo; cat /run/secrets/password) | sudo -u ahriman ahriman user-add demo -R full
AHRIMAN_REPOSITORY: ahriman-demo
AHRIMAN_REPOSITORY_SERVER: http://frontend/repo/$$repo/$$arch

View File

@@ -12,7 +12,7 @@ services:
AHRIMAN_PACMAN_MIRROR: https://de.mirror.archlinux32.org/$$arch/$$repo
AHRIMAN_PASSWORD: ${AHRIMAN_PASSWORD}
AHRIMAN_PORT: 8080
AHRIMAN_PRESETUP_COMMAND: (cat /run/secrets/password; echo; cat /run/secrets/password) | sudo -u ahriman ahriman user-add demo -R full
AHRIMAN_POSTSETUP_COMMAND: (cat /run/secrets/password; echo; cat /run/secrets/password) | sudo -u ahriman ahriman user-add demo -R full
AHRIMAN_REPOSITORY: ahriman-demo
AHRIMAN_UNIX_SOCKET: /var/lib/ahriman/ahriman/ahriman.sock

View File

@@ -8,8 +8,8 @@ services:
AHRIMAN_OUTPUT: console
AHRIMAN_PASSWORD: ${AHRIMAN_PASSWORD}
AHRIMAN_PORT: 8080
AHRIMAN_POSTSETUP_COMMAND: ahriman --architecture x86_64 --repository another-demo service-setup --build-as-user ahriman --packager 'ahriman bot <ahriman@example.com>'
AHRIMAN_PRESETUP_COMMAND: (cat /run/secrets/password; echo; cat /run/secrets/password) | sudo -u ahriman ahriman user-add demo -R full
AHRIMAN_POSTSETUP_COMMAND: (cat /run/secrets/password; echo; cat /run/secrets/password) | sudo -u ahriman ahriman user-add demo -R full
AHRIMAN_PRESETUP_COMMAND: ahriman --architecture x86_64 --repository another-demo service-setup --build-as-user ahriman --packager 'ahriman bot <ahriman@example.com>'
AHRIMAN_REPOSITORY: ahriman-demo
AHRIMAN_UNIX_SOCKET: /var/lib/ahriman/ahriman/ahriman.sock

View File

@@ -9,7 +9,7 @@ services:
AHRIMAN_OAUTH_CLIENT_SECRET: ${AHRIMAN_OAUTH_CLIENT_SECRET}
AHRIMAN_OUTPUT: console
AHRIMAN_PORT: 8080
AHRIMAN_PRESETUP_COMMAND: sudo -u ahriman ahriman user-add ${AHRIMAN_OAUTH_USER} -R full -p ""
AHRIMAN_POSTSETUP_COMMAND: sudo -u ahriman ahriman user-add ${AHRIMAN_OAUTH_USER} -R full -p ""
AHRIMAN_REPOSITORY: ahriman-demo
AHRIMAN_UNIX_SOCKET: /var/lib/ahriman/ahriman/ahriman.sock

View File

@@ -6,7 +6,7 @@ services:
environment:
AHRIMAN_DEBUG: yes
AHRIMAN_OUTPUT: console
AHRIMAN_PRESETUP_COMMAND: sudo -u ahriman gpg --import /run/secrets/key
AHRIMAN_POSTSETUP_COMMAND: sudo -u ahriman gpg --import /run/secrets/key
AHRIMAN_REPOSITORY: ahriman-demo
configs:

View File

@@ -8,7 +8,7 @@ services:
AHRIMAN_OUTPUT: console
AHRIMAN_PASSWORD: ${AHRIMAN_PASSWORD}
AHRIMAN_PORT: 8080
AHRIMAN_PRESETUP_COMMAND: (cat /run/secrets/password; echo; cat /run/secrets/password) | sudo -u ahriman ahriman user-add demo -R full
AHRIMAN_POSTSETUP_COMMAND: (cat /run/secrets/password; echo; cat /run/secrets/password) | sudo -u ahriman ahriman user-add demo -R full
AHRIMAN_REPOSITORY: ahriman-demo
AHRIMAN_UNIX_SOCKET: /var/lib/ahriman/ahriman/ahriman.sock

View File

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

View File

@@ -72,16 +72,17 @@ class Setup(Handler):
application = Application(repository_id, configuration, report=report)
Setup.configuration_create_makepkg(args.packager, args.makeflags_jobs, application.repository.paths)
Setup.executable_create(application.repository.paths, repository_id)
repository_server = f"file://{application.repository.paths.repository}" if args.server is None else args.server
Setup.configuration_create_devtools(
repository_id, args.from_configuration, args.mirror, args.multilib, repository_server)
Setup.configuration_create_sudo(application.repository.paths, repository_id)
with application.repository.paths.preserve_owner():
Setup.configuration_create_makepkg(args.packager, args.makeflags_jobs, application.repository.paths)
Setup.executable_create(application.repository.paths, repository_id)
repository_server = f"file://{application.repository.paths.repository}" if args.server is None else args.server
Setup.configuration_create_devtools(
repository_id, args.from_configuration, args.mirror, args.multilib, repository_server)
Setup.configuration_create_sudo(application.repository.paths, repository_id)
application.repository.repo.init()
# lazy database sync
application.repository.pacman.handle # pylint: disable=pointless-statement
application.repository.repo.init()
# lazy database sync
application.repository.pacman.handle # pylint: disable=pointless-statement
@staticmethod
def _set_service_setup_parser(root: SubParserAction) -> argparse.ArgumentParser:
@@ -280,6 +281,5 @@ class Setup(Handler):
command = Setup.build_command(paths.root, repository_id)
command.unlink(missing_ok=True)
command.symlink_to(Setup.ARCHBUILD_COMMAND_PATH)
paths.chown(command) # we would like to keep owner inside ahriman's home
arguments = [_set_service_setup_parser]

View File

@@ -52,7 +52,7 @@ class Validate(Handler):
"""
from ahriman.core.configuration.validator import Validator
schema = Validate.schema(repository_id, configuration)
schema = Validate.schema(configuration)
validator = Validator(configuration=configuration, schema=schema)
if validator.validate(configuration.dump()):
@@ -83,12 +83,11 @@ class Validate(Handler):
return parser
@staticmethod
def schema(repository_id: RepositoryId, configuration: Configuration) -> ConfigurationSchema:
def schema(configuration: Configuration) -> ConfigurationSchema:
"""
get schema with triggers
Args:
repository_id(RepositoryId): repository unique identifier
configuration(Configuration): configuration instance
Returns:
@@ -107,12 +106,12 @@ class Validate(Handler):
continue
# default settings if any
for schema_name, schema in trigger_class.configuration_schema(repository_id, None).items():
for schema_name, schema in trigger_class.configuration_schema(None).items():
erased = Validate.schema_erase_required(copy.deepcopy(schema))
root[schema_name] = Validate.schema_merge(root.get(schema_name, {}), erased)
# settings according to enabled triggers
for schema_name, schema in trigger_class.configuration_schema(repository_id, configuration).items():
for schema_name, schema in trigger_class.configuration_schema(configuration).items():
root[schema_name] = Validate.schema_merge(root.get(schema_name, {}), copy.deepcopy(schema))
return root

View File

@@ -21,7 +21,7 @@ import argparse
import re
import sys
from collections.abc import Generator
from collections.abc import Iterator
from importlib import metadata
from typing import ClassVar
@@ -77,7 +77,7 @@ class Versions(Handler):
return parser
@staticmethod
def package_dependencies(root: str) -> Generator[tuple[str, str], None, None]:
def package_dependencies(root: str) -> Iterator[tuple[str, str]]:
"""
extract list of ahriman package dependencies installed into system with their versions
@@ -87,7 +87,7 @@ class Versions(Handler):
Yields:
tuple[str, str]: map of installed dependency to its version
"""
def dependencies_by_key(key: str) -> Generator[str, None, None]:
def dependencies_by_key(key: str) -> Iterator[str]:
# in importlib it returns requires in the following format
# ["pytest (>=3.0.0) ; extra == 'test'", "pytest-cov ; extra == 'test'"]
try:

View File

@@ -19,7 +19,7 @@
#
import argparse
from collections.abc import Generator
from collections.abc import Iterator
from pathlib import Path
from ahriman.application.handlers.handler import Handler, SubParserAction
@@ -86,7 +86,7 @@ class Web(Handler):
return parser
@staticmethod
def extract_arguments(args: argparse.Namespace, configuration: Configuration) -> Generator[str, None, None]:
def extract_arguments(args: argparse.Namespace, configuration: Configuration) -> Iterator[str]:
"""
extract list of arguments used for current command, except for command specific ones

View File

@@ -158,7 +158,7 @@ class Lock(LazyLogging):
"""
check if current user is actually owner of ahriman root
"""
check_user(self.paths, unsafe=self.unsafe)
check_user(self.paths.root, unsafe=self.unsafe)
self.paths.tree_create()
def check_version(self) -> None:

View File

@@ -21,7 +21,7 @@ import itertools
import shutil
import tarfile
from collections.abc import Generator, Iterable
from collections.abc import Iterable, Iterator
from functools import cached_property
from pathlib import Path
from pyalpm import DB, Handle, Package, SIG_DATABASE_OPTIONAL, SIG_PACKAGE_OPTIONAL # type: ignore[import-not-found]
@@ -130,8 +130,8 @@ class Pacman(LazyLogging):
return # database for some reason deos not exist
self.logger.info("copy pacman database %s from operating system root to ahriman's home %s", src, dst)
shutil.copy(src, dst)
self.repository_paths.chown(dst)
with self.repository_paths.preserve_owner(dst.parent):
shutil.copy(src, dst)
def database_init(self, handle: Handle, repository: str, architecture: str) -> DB:
"""
@@ -188,7 +188,7 @@ class Pacman(LazyLogging):
Returns:
dict[str, set[str]]: map of package name to its list of files
"""
def extract(tar: tarfile.TarFile, versions: dict[str, str]) -> Generator[tuple[str, set[str]], None, None]:
def extract(tar: tarfile.TarFile, versions: dict[str, str]) -> Iterator[tuple[str, set[str]]]:
for package_name, version in versions.items():
path = Path(f"{package_name}-{version}") / "files"
try:
@@ -223,7 +223,7 @@ class Pacman(LazyLogging):
return result
def package(self, package_name: str) -> Generator[Package, None, None]:
def package(self, package_name: str) -> Iterator[Package]:
"""
retrieve list of the packages from the repository by name
@@ -256,7 +256,7 @@ class Pacman(LazyLogging):
return result
def provided_by(self, package_name: str) -> Generator[Package, None, None]:
def provided_by(self, package_name: str) -> Iterator[Package]:
"""
search through databases and emit packages which provides the ``package_name``

View File

@@ -21,7 +21,7 @@ import itertools
import re
import shlex
from collections.abc import Generator
from collections.abc import Iterator
from enum import StrEnum
from typing import IO
@@ -209,7 +209,7 @@ class PkgbuildParser(shlex.shlex):
Raises:
PkgbuildParserError: if array is not closed
"""
def extract() -> Generator[str, None, None]:
def extract() -> Iterator[str]:
while token := self.get_token():
match token:
case _ if self._is_escaped():
@@ -276,7 +276,7 @@ class PkgbuildParser(shlex.shlex):
return content
def _parse_token(self, token: str) -> Generator[PkgbuildPatch, None, None]:
def _parse_token(self, token: str) -> Iterator[PkgbuildPatch]:
"""
parse single token to the PKGBUILD field
@@ -360,7 +360,7 @@ class PkgbuildParser(shlex.shlex):
raise PkgbuildParserError("reached starting position, no valid symbols found")
def parse(self) -> Generator[PkgbuildPatch, None, None]:
def parse(self) -> Iterator[PkgbuildPatch]:
"""
parse source stream and yield parsed entries

View File

@@ -19,7 +19,7 @@
#
import shutil
from collections.abc import Generator
from collections.abc import Iterator
from pathlib import Path
from typing import ClassVar
@@ -347,7 +347,7 @@ class Sources(LazyLogging):
"""
gitconfig = gitconfig or {}
def configuration_flags() -> Generator[str, None, None]:
def configuration_flags() -> Iterator[str]:
for option, value in (self.GITCONFIG | gitconfig).items():
yield "-c"
yield f"{option}=\"{value}\""

View File

@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from collections.abc import Generator
from collections.abc import Iterator
from pathlib import Path
from ahriman.core.build_tools.sources import Sources
@@ -77,7 +77,7 @@ class Task(LazyLogging):
Returns:
list[Path]: list of file paths which looks like freshly generated archives
"""
def files() -> Generator[Path, None, None]:
def files() -> Iterator[Path]:
for filepath in sources_dir.iterdir():
if filepath in source_files:
continue # skip files which were already there

View File

@@ -41,7 +41,6 @@ class Configuration(configparser.RawConfigParser):
SYSTEM_CONFIGURATION_PATH(Path): (class attribute) default system configuration path distributed by package
includes(list[Path]): list of includes which were read
path(Path | None): path to root configuration file
repository_id(RepositoryId | None): repository unique identifier
Examples:
Configuration class provides additional method in order to handle application configuration. Since this class is
@@ -91,7 +90,7 @@ class Configuration(configparser.RawConfigParser):
},
)
self.repository_id: RepositoryId | None = None
self._repository_id: RepositoryId | None = None
self.path: Path | None = None
self.includes: list[Path] = []
@@ -126,6 +125,32 @@ class Configuration(configparser.RawConfigParser):
"""
return self.getpath("settings", "logging")
@property
def repository_id(self) -> RepositoryId | None:
"""
repository identifier
Returns:
RepositoryId: repository unique identifier
"""
return self._repository_id
@repository_id.setter
def repository_id(self, repository_id: RepositoryId | None) -> None:
"""
setter for repository identifier
Args:
repository_id(RepositoryId | None): repository unique identifier
"""
self._repository_id = repository_id
if repository_id is None or repository_id.is_empty:
self.remove_option("repository", "name")
self.remove_option("repository", "architecture")
else:
self.set_option("repository", "name", repository_id.name)
self.set_option("repository", "architecture", repository_id.architecture)
@property
def repository_name(self) -> str:
"""

View File

@@ -57,7 +57,7 @@ class ConfigurationMultiDict(dict[str, Any]):
OptionError: if the key already exists in the dictionary, but not a single value list or a string
"""
match self.get(key):
case [current_value] | str(current_value):
case [current_value] | (str() as current_value):
value = f"{current_value} {value}"
case None:
pass

View File

@@ -254,6 +254,10 @@ CONFIGURATION_SCHEMA: ConfigurationSchema = {
"repository": {
"type": "dict",
"schema": {
"architecture": {
"type": "string",
"empty": False,
},
"name": {
"type": "string",
"empty": False,

View File

@@ -21,7 +21,7 @@ import configparser
import os
import sys
from collections.abc import Generator, Mapping, MutableMapping
from collections.abc import Iterator, Mapping, MutableMapping
from string import Template
from typing import Any, ClassVar
@@ -37,7 +37,7 @@ class ShellInterpolator(configparser.Interpolation):
@staticmethod
def _extract_variables(parser: MutableMapping[str, Mapping[str, str]], value: str,
defaults: Mapping[str, str]) -> Generator[tuple[str, str], None, None]:
defaults: Mapping[str, str]) -> Iterator[tuple[str, str]]:
"""
extract keys and values (if available) from the configuration. In case if a key is not available, it will be
silently skipped from the result
@@ -50,7 +50,7 @@ class ShellInterpolator(configparser.Interpolation):
Yields:
tuple[str, str]: variable name used for substitution and its value
"""
def identifiers() -> Generator[tuple[str | None, str], None, None]:
def identifiers() -> Iterator[tuple[str | None, str]]:
# extract all found identifiers and parse them
for identifier in ShellTemplate(value).get_identifiers():
match identifier.rsplit(":", maxsplit=1):

View File

@@ -20,7 +20,7 @@
import fnmatch
import re
from collections.abc import Generator, Mapping
from collections.abc import Iterator, Mapping
from string import Template
@@ -132,7 +132,7 @@ class ShellTemplate(Template):
(self._REPLACE, self._replace, "/"),
)
def generator(variables: dict[str, str]) -> Generator[tuple[str, str], None, None]:
def generator(variables: dict[str, str]) -> Iterator[tuple[str, str]]:
for identifier in self.get_identifiers():
for regex, function, greediness in substitutions:
if m := regex.match(identifier):

View File

@@ -203,8 +203,6 @@ def migrate_package_repository(connection: Connection, configuration: Configurat
configuration(Configuration): configuration instance
"""
_, repository_id = configuration.check_loaded()
if repository_id.is_empty:
return # no repository available yet
connection.execute("""update build_queue set repository = :repository""", {"repository": repository_id.id})
connection.execute("""update package_bases set repository = :repository""", {"repository": repository_id.id})

View File

@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from collections.abc import Generator, Iterable
from collections.abc import Iterable, Iterator
from sqlite3 import Connection
from ahriman.core.database.operations.operations import Operations
@@ -263,7 +263,7 @@ class PackageOperations(Operations):
"""
repository_id = repository_id or self._repository_id
def run(connection: Connection) -> Generator[tuple[Package, BuildStatus], None, None]:
def run(connection: Connection) -> Iterator[tuple[Package, BuildStatus]]:
packages = self._packages_get_select_package_bases(connection, repository_id)
statuses = self._packages_get_select_statuses(connection, repository_id)
per_package_base = self._packages_get_select_packages(connection, packages, repository_id)

View File

@@ -94,9 +94,13 @@ class SQLite(
sqlite3.register_adapter(list, json.dumps)
sqlite3.register_converter("json", json.loads)
if self._configuration.getboolean("settings", "apply_migrations", fallback=True):
if not self._configuration.getboolean("settings", "apply_migrations", fallback=True):
return
if self._repository_id.is_empty:
return # do not perform migration on empty repository identifier (e.g. multirepo command)
with self._repository_paths.preserve_owner():
self.with_connection(lambda connection: Migrations.migrate(connection, self._configuration))
self._repository_paths.chown(self.path)
def package_clear(self, package_base: str, repository_id: RepositoryId | None = None) -> None:
"""

View File

@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from collections.abc import Generator
from collections.abc import Iterator
from typing import Any
from ahriman.core.formatters.string_printer import StringPrinter
@@ -44,8 +44,7 @@ class ValidationPrinter(StringPrinter):
self.errors = errors
@staticmethod
def get_error_messages(node: str, errors: list[str | dict[str, Any]],
current_level: int = 1) -> Generator[Property, None, None]:
def get_error_messages(node: str, errors: list[str | dict[str, Any]], current_level: int = 1) -> Iterator[Property]:
"""
extract default error message from cerberus class

View File

@@ -19,7 +19,7 @@
#
import shutil
from collections.abc import Generator
from collections.abc import Iterator
from pathlib import Path
from tempfile import TemporaryDirectory
@@ -96,7 +96,7 @@ class RemotePush(LazyLogging):
# ...and finally return path to the copied directory
return package.base
def packages_update(self, result: Result, target_dir: Path) -> Generator[str, None, None]:
def packages_update(self, result: Result, target_dir: Path) -> Iterator[str]:
"""
update all packages from the build result

View File

@@ -20,7 +20,7 @@
import contextlib
import logging
from collections.abc import Generator
from collections.abc import Iterator
from functools import cached_property
from typing import Any
@@ -80,7 +80,7 @@ class LazyLogging:
logging.setLogRecordFactory(package_record_factory)
@contextlib.contextmanager
def in_package_context(self, package_base: str, version: str | None) -> Generator[None, None, None]:
def in_package_context(self, package_base: str, version: str | None) -> Iterator[None]:
"""
execute function while setting package context

View File

@@ -19,7 +19,7 @@
#
import inspect
from collections.abc import Generator
from collections.abc import Iterator
from importlib import import_module
from pathlib import Path
from pkgutil import ModuleInfo, walk_packages
@@ -33,7 +33,7 @@ __all__ = ["implementations"]
T = TypeVar("T")
def _modules(module_root: Path, prefix: str) -> Generator[ModuleInfo, None, None]:
def _modules(module_root: Path, prefix: str) -> Iterator[ModuleInfo]:
"""
extract available modules from package
@@ -52,7 +52,7 @@ def _modules(module_root: Path, prefix: str) -> Generator[ModuleInfo, None, None
yield module_info
def implementations(root_module: ModuleType, base_class: type[T]) -> Generator[type[T], None, None]:
def implementations(root_module: ModuleType, base_class: type[T]) -> Iterator[type[T]]:
"""
extract implementations of the ``base_class`` from the module

View File

@@ -19,7 +19,7 @@
#
import contextlib
from typing import Generator
from collections.abc import Iterator
from ahriman.core.status import Client
from ahriman.models.event import Event, EventType
@@ -55,7 +55,7 @@ class EventLogger:
@contextlib.contextmanager
def in_event(self, package_base: str, event: EventType, message: str | None = None,
failure: EventType | None = None) -> Generator[None, None, None]:
failure: EventType | None = None) -> Iterator[None]:
"""
perform action in package context and log event with time elapsed

View File

@@ -20,7 +20,7 @@
import hashlib
import itertools
from collections.abc import Callable, Generator
from collections.abc import Callable, Iterator
from pathlib import Path
from typing import ClassVar
@@ -187,7 +187,7 @@ class PkgbuildGenerator:
Returns:
list[PkgbuildPatch]: list of patches to be applied to the PKGBUILD
"""
def sources_generator() -> Generator[tuple[str, str], None, None]:
def sources_generator() -> Iterator[tuple[str, str]]:
for source, generator in sorted(self.sources().items()):
source_path = source_dir / source
generator(source_path)

View File

@@ -80,8 +80,7 @@ class Trigger(LazyLogging):
return self.repository_id.architecture
@classmethod
def configuration_schema(cls, repository_id: RepositoryId,
configuration: Configuration | None) -> ConfigurationSchema:
def configuration_schema(cls, configuration: Configuration | None) -> ConfigurationSchema:
"""
configuration schema based on supplied service configuration
@@ -89,7 +88,6 @@ class Trigger(LazyLogging):
Schema must be in cerberus format, for details and examples you can check built-in triggers.
Args:
repository_id(str): repository unique identifier
configuration(Configuration | None): configuration instance. If set to None, the default schema
should be returned
@@ -101,13 +99,15 @@ class Trigger(LazyLogging):
result: ConfigurationSchema = {}
for target in cls.configuration_sections(configuration):
if not configuration.has_section(target):
continue
section, schema_name = configuration.gettype(
target, repository_id, fallback=cls.CONFIGURATION_SCHEMA_FALLBACK)
if schema_name not in cls.CONFIGURATION_SCHEMA:
continue
result[section] = cls.CONFIGURATION_SCHEMA[schema_name]
for section in configuration.sections():
if not (section == target or section.startswith(f"{target}:")):
# either repository specific or exact name
continue
schema_name = configuration.get(section, "type", fallback=section)
if schema_name not in cls.CONFIGURATION_SCHEMA:
continue
result[section] = cls.CONFIGURATION_SCHEMA[schema_name]
return result

View File

@@ -20,7 +20,7 @@
import contextlib
import os
from collections.abc import Generator
from collections.abc import Iterator
from importlib import import_module, machinery
from pathlib import Path
from types import ModuleType
@@ -119,7 +119,7 @@ class TriggerLoader(LazyLogging):
return configuration.getlist("build", "triggers", fallback=[])
@contextlib.contextmanager
def __execute_trigger(self, trigger: Trigger) -> Generator[None, None, None]:
def __execute_trigger(self, trigger: Trigger) -> Iterator[None]:
"""
decorator for calling triggers

View File

@@ -27,7 +27,7 @@ import re
import selectors
import subprocess
from collections.abc import Callable, Generator, Iterable, Mapping
from collections.abc import Callable, Iterable, Iterator, Mapping
from dataclasses import asdict
from enum import Enum
from pathlib import Path
@@ -35,7 +35,6 @@ from pwd import getpwuid
from typing import Any, IO, TypeVar
from ahriman.core.exceptions import CalledProcessError, OptionError, UnsafeRunError
from ahriman.models.repository_paths import RepositoryPaths
__all__ = [
@@ -47,12 +46,14 @@ __all__ = [
"filter_json",
"full_version",
"minmax",
"owner",
"package_like",
"parse_version",
"partition",
"pretty_datetime",
"pretty_size",
"safe_filename",
"safe_iterdir",
"srcinfo_property",
"srcinfo_property_list",
"trim_package",
@@ -112,7 +113,7 @@ def check_output(*args: str, exception: Exception | Callable[[int, list[str], st
return channel if channel is not None else io.StringIO()
# wrapper around selectors polling
def poll(sel: selectors.BaseSelector) -> Generator[tuple[str, str], None, None]:
def poll(sel: selectors.BaseSelector) -> Iterator[tuple[str, str]]:
for key, _ in sel.select(): # we don't need to check mask here because we have only subscribed on reading
line = key.fileobj.readline() # type: ignore[union-attr]
if not line: # in case of empty line we remove selector as there is no data here anymore
@@ -169,12 +170,13 @@ def check_output(*args: str, exception: Exception | Callable[[int, list[str], st
return stdout
def check_user(paths: RepositoryPaths, *, unsafe: bool) -> None:
def check_user(root: Path, *, unsafe: bool) -> None:
"""
check if current user is the owner of the root
Args:
paths(RepositoryPaths): repository paths object
root(Path): path to root directory (e.g. repository root
:attr:`ahriman.models.repository_paths.RepositoryPaths.root`)
unsafe(bool): if set no user check will be performed before path creation
Raises:
@@ -183,14 +185,16 @@ def check_user(paths: RepositoryPaths, *, unsafe: bool) -> None:
Examples:
Simply run function with arguments::
>>> check_user(paths, unsafe=False)
>>> check_user(root, unsafe=False)
"""
if not paths.root.exists():
if not root.exists():
return # no directory found, skip check
if unsafe:
return # unsafe flag is enabled, no check performed
current_uid = os.getuid()
root_uid, _ = paths.root_owner
root_uid, _ = owner(root)
if current_uid != root_uid:
raise UnsafeRunError(current_uid, root_uid)
@@ -288,6 +292,20 @@ def minmax(source: Iterable[T], *, key: Callable[[T], Any] | None = None) -> tup
return min(first_iter, key=key), max(second_iter, key=key) # type: ignore
def owner(path: Path) -> tuple[int, int]:
"""
retrieve owner information by path
Args:
path(Path): path for which extract ids
Returns:
tuple[int, int]: owner user and group ids of the directory
"""
stat = path.stat()
return stat.st_uid, stat.st_gid
def package_like(filename: Path) -> bool:
"""
check if file looks like package
@@ -408,6 +426,22 @@ def safe_filename(source: str) -> str:
return re.sub(r"[^A-Za-z\d\-._~:\[\]@]", "-", source)
def safe_iterdir(path: Path) -> Iterator[Path]:
"""
wrapper around :func:`pathlib.Path.iterdir`, which suppresses :exc:`PermissionError`
Args:
path(Path): path to iterate
Yields:
Path: content of the directory
"""
try:
yield from path.iterdir()
except PermissionError:
pass
def srcinfo_property(key: str, srcinfo: Mapping[str, Any], package_srcinfo: Mapping[str, Any], *,
default: Any = None) -> Any:
"""
@@ -476,7 +510,7 @@ def utcnow() -> datetime.datetime:
return datetime.datetime.now(datetime.UTC)
def walk(directory_path: Path) -> Generator[Path, None, None]:
def walk(directory_path: Path) -> Iterator[Path]:
"""
list all file paths in given directory

View File

@@ -22,7 +22,7 @@ from __future__ import annotations
import copy
from collections.abc import Callable, Generator, Iterable
from collections.abc import Callable, Iterable, Iterator
from dataclasses import dataclass
from pathlib import Path
from pyalpm import vercmp # type: ignore[import-not-found]
@@ -205,7 +205,7 @@ class Package(LazyLogging):
package = pacman.handle.load_pkg(str(path))
description = PackageDescription.from_package(package, path)
return cls(
base=package.base,
base=package.base or package.name,
version=package.version,
remote=RemoteSource(source=PackageSource.Archive),
packages={package.name: description},
@@ -346,7 +346,7 @@ class Package(LazyLogging):
)
@staticmethod
def local_files(path: Path) -> Generator[Path, None, None]:
def local_files(path: Path) -> Iterator[Path]:
"""
extract list of local files
@@ -407,7 +407,7 @@ class Package(LazyLogging):
Returns:
list[str]: combined list of unique entries in properties list
"""
def generator() -> Generator[str, None, None]:
def generator() -> Iterator[str]:
for package in self.packages.values():
yield from extractor(package)
@@ -570,7 +570,7 @@ class Package(LazyLogging):
"""
return dataclass_view(self)
def with_packages(self, packages: list[Path], pacman: Pacman) -> None:
def with_packages(self, packages: Iterable[Path], pacman: Pacman) -> None:
"""
replace packages descriptions with ones from archives

View File

@@ -22,7 +22,7 @@ import shlex
from dataclasses import dataclass, fields
from pathlib import Path
from typing import Any, Generator, Self
from typing import Any, Iterator, Self
from ahriman.core.configuration.shell_template import ShellTemplate
from ahriman.core.utils import dataclass_view, filter_json
@@ -166,7 +166,7 @@ class PkgbuildPatch:
ValueError: if no closing quotation
"""
def generator() -> Generator[str, None, None]:
def generator() -> Iterator[str]:
token = None
for char in source:
if token is not None:

View File

@@ -17,10 +17,11 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import contextlib
import os
import shutil
from collections.abc import Generator
from collections.abc import Iterator
from dataclasses import dataclass, field
from functools import cached_property
from pathlib import Path
@@ -28,6 +29,7 @@ from pwd import getpwuid
from ahriman.core.exceptions import PathError
from ahriman.core.log import LazyLogging
from ahriman.core.utils import owner, safe_iterdir
from ahriman.models.repository_id import RepositoryId
@@ -92,7 +94,7 @@ class RepositoryPaths(LazyLogging):
Returns:
Path: path to directory in which build process is run
"""
uid, _ = self.owner(self.root)
uid, _ = owner(self.root)
return self.chroot / f"{self.repository_id.name}-{self.repository_id.architecture}" / getpwuid(uid).pw_name
@property
@@ -154,7 +156,7 @@ class RepositoryPaths(LazyLogging):
Returns:
tuple[int, int]: owner user and group of the root directory
"""
return self.owner(self.root)
return owner(self.root)
# pylint: disable=protected-access
@classmethod
@@ -169,7 +171,7 @@ class RepositoryPaths(LazyLogging):
Returns:
set[str]: list of repository architectures for which there is created tree
"""
def walk(repository_dir: Path) -> Generator[str, None, None]:
def walk(repository_dir: Path) -> Iterator[str]:
for architecture in filter(lambda path: path.is_dir(), repository_dir.iterdir()):
yield architecture.name
@@ -196,7 +198,7 @@ class RepositoryPaths(LazyLogging):
is loaded in legacy mode
"""
# simply walk through the root. In case if there are subdirectories, emit the name
def walk(paths: RepositoryPaths) -> Generator[str, None, None]:
def walk(paths: RepositoryPaths) -> Iterator[str]:
for repository in filter(lambda path: path.is_dir(), paths._repository_root.iterdir()):
if any(path.is_dir() for path in repository.iterdir()):
yield repository.name
@@ -207,19 +209,32 @@ class RepositoryPaths(LazyLogging):
return set(walk(instance))
@staticmethod
def owner(path: Path) -> tuple[int, int]:
def _chown(self, path: Path) -> None:
"""
retrieve owner information by path
set owner of path recursively (from root) to root owner
Notes:
More likely you don't want to call this method explicitly, consider using :func:`preserve_owner`
as context manager instead
Args:
path(Path): path for which extract ids
path(Path): path to be chown
Returns:
tuple[int, int]: owner user and group ids of the directory
Raises:
PathError: if path does not belong to root
"""
stat = path.stat()
return stat.st_uid, stat.st_gid
def set_owner(current: Path) -> None:
uid, gid = owner(current)
if uid == root_uid and gid == root_gid:
return
os.chown(current, root_uid, root_gid, follow_symlinks=False)
if self.root not in path.parents:
raise PathError(path, self.root)
root_uid, root_gid = self.root_owner
while path != self.root:
set_owner(path)
path = path.parent
def cache_for(self, package_base: str) -> Path:
"""
@@ -233,28 +248,43 @@ class RepositoryPaths(LazyLogging):
"""
return self.cache / package_base
def chown(self, path: Path) -> None:
@contextlib.contextmanager
def preserve_owner(self, path: Path | None = None) -> Iterator[None]:
"""
set owner of path recursively (from root) to root owner
perform any action preserving owner for any newly created file or directory
Args:
path(Path): path to be chown
path(Path | None, optional): use this path as root instead of repository root (Default value = None)
Raises:
PathError: if path does not belong to root
Examples:
This method is designed to use as context manager when you are going to perform operations which might
change filesystem, especially if you are doing it under unsafe flag, e.g.::
>>> with paths.preserve_owner():
>>> paths.tree_create()
Note, however, that this method doesn't handle any exceptions and will eventually interrupt
if there will be any.
"""
def set_owner(current: Path) -> None:
uid, gid = self.owner(current)
if uid == root_uid and gid == root_gid:
return
os.chown(current, root_uid, root_gid, follow_symlinks=False)
path = path or self.root
if self.root not in path.parents:
raise PathError(path, self.root)
root_uid, root_gid = self.root_owner
while path != self.root:
set_owner(path)
path = path.parent
def walk(root: Path) -> Iterator[Path]:
# basically walk, but skipping some content
for child in safe_iterdir(root):
yield child
if child in (self.chroot.parent,):
yield from safe_iterdir(child) # we only yield top-level in chroot directory
elif child.is_dir():
yield from walk(child)
# get current filesystem and run action
previous_snapshot = set(walk(path))
yield
# get newly created files and directories and chown them
new_entries = set(walk(path)).difference(previous_snapshot)
for entry in new_entries:
self._chown(entry)
def tree_clear(self, package_base: str) -> None:
"""
@@ -274,12 +304,13 @@ class RepositoryPaths(LazyLogging):
"""
if self.repository_id.is_empty:
return # do not even try to create tree in case if no repository id set
for directory in (
self.cache,
self.chroot,
self.packages,
self.pacman,
self.repository,
):
directory.mkdir(mode=0o755, parents=True, exist_ok=True)
self.chown(directory)
with self.preserve_owner():
for directory in (
self.cache,
self.chroot,
self.packages,
self.pacman,
self.repository,
):
directory.mkdir(mode=0o755, parents=True, exist_ok=True)

View File

@@ -20,7 +20,7 @@
import re
from aiohttp.web import Application, View
from collections.abc import Generator
from collections.abc import Iterator
import ahriman.web.views
@@ -32,7 +32,7 @@ from ahriman.web.views.base import BaseView
__all__ = ["setup_routes"]
def _dynamic_routes(configuration: Configuration) -> Generator[tuple[str, type[View]], None, None]:
def _dynamic_routes(configuration: Configuration) -> Iterator[tuple[str, type[View]]]:
"""
extract dynamic routes based on views

View File

@@ -166,11 +166,16 @@ def setup_server(configuration: Configuration, spawner: Spawn, repositories: lis
# package cache
if not repositories:
raise InitializeError("No repositories configured, exiting")
database = SQLite.load(configuration)
watchers: dict[RepositoryId, Watcher] = {}
configuration_path, _ = configuration.check_loaded()
for repository_id in repositories:
application.logger.info("load repository %s", repository_id)
client = Client.load(repository_id, configuration, database, report=False) # explicitly load local client
# load settings explicitly for architecture if any
repository_configuration = Configuration.from_path(configuration_path, repository_id)
# load database instance, because it holds identifier
database = SQLite.load(repository_configuration)
# explicitly load local client
client = Client.load(repository_id, repository_configuration, database, report=False)
watchers[repository_id] = Watcher(client)
application[WatcherKey] = watchers
# workers cache
@@ -179,6 +184,7 @@ def setup_server(configuration: Configuration, spawner: Spawn, repositories: lis
application[SpawnKey] = spawner
application.logger.info("setup authorization")
database = SQLite.load(configuration)
validator = application[AuthKey] = Auth.load(configuration, database)
if validator.enabled:
from ahriman.web.middlewares.auth_handler import setup_auth

View File

@@ -58,9 +58,11 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
sudo_configuration_mock = mocker.patch("ahriman.application.handlers.setup.Setup.configuration_create_sudo")
executable_mock = mocker.patch("ahriman.application.handlers.setup.Setup.executable_create")
init_mock = mocker.patch("ahriman.core.alpm.repo.Repo.init")
owner_guard_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.preserve_owner")
_, repository_id = configuration.check_loaded()
Setup.run(args, repository_id, configuration, report=False)
owner_guard_mock.assert_called_once_with()
ahriman_configuration_mock.assert_called_once_with(args, repository_id, configuration)
devtools_configuration_mock.assert_called_once_with(
repository_id, args.from_configuration, args.mirror, args.multilib, f"file://{repository_paths.repository}")
@@ -268,13 +270,11 @@ def test_executable_create(configuration: Configuration, repository_paths: Repos
"""
must create executable
"""
chown_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.chown")
symlink_mock = mocker.patch("pathlib.Path.symlink_to")
unlink_mock = mocker.patch("pathlib.Path.unlink")
_, repository_id = configuration.check_loaded()
Setup.executable_create(repository_paths, repository_id)
chown_mock.assert_called_once_with(Setup.build_command(repository_paths.root, repository_id))
symlink_mock.assert_called_once_with(Setup.ARCHBUILD_COMMAND_PATH)
unlink_mock.assert_called_once_with(missing_ok=True)

View File

@@ -2,6 +2,7 @@ import argparse
import json
import pytest
from pathlib import Path
from pytest_mock import MockerFixture
from ahriman.application.handlers.validate import Validate
@@ -53,12 +54,50 @@ def test_run_skip(args: argparse.Namespace, configuration: Configuration, mocker
print_mock.assert_not_called()
def test_run_default(args: argparse.Namespace, configuration: Configuration) -> None:
"""
must run on default configuration without errors
"""
args.exit_code = True
_, repository_id = configuration.check_loaded()
default = Configuration.from_path(Configuration.SYSTEM_CONFIGURATION_PATH, repository_id)
# copy autogenerated values
for section, key in (("build", "build_command"), ("repository", "root")):
value = configuration.get(section, key)
default.set_option(section, key, value)
Validate.run(args, repository_id, default, report=False)
def test_run_repo_specific_triggers(args: argparse.Namespace, configuration: Configuration,
resource_path_root: Path) -> None:
"""
must correctly insert repo specific triggers
"""
args.exit_code = True
_, repository_id = configuration.check_loaded()
# remove unused sections
for section in ("customs3", "github:x86_64", "logs-rotation", "mirrorlist"):
configuration.remove_section(section)
configuration.set_option("report", "target", "test")
for section in ("test", "test:i686", "test:another-repo:x86_64"):
configuration.set_option(section, "type", "html")
configuration.set_option(section, "link_path", "http://link_path")
configuration.set_option(section, "path", "path")
configuration.set_option(section, "template", "template")
configuration.set_option(section, "templates", str(resource_path_root))
Validate.run(args, repository_id, configuration, report=False)
def test_schema(configuration: Configuration) -> None:
"""
must generate full schema correctly
"""
_, repository_id = configuration.check_loaded()
schema = Validate.schema(repository_id, configuration)
schema = Validate.schema(configuration)
# defaults
assert schema.pop("console")
@@ -91,9 +130,7 @@ def test_schema_invalid_trigger(configuration: Configuration) -> None:
"""
configuration.set_option("build", "triggers", "some.invalid.trigger.path.Trigger")
configuration.remove_option("build", "triggers_known")
_, repository_id = configuration.check_loaded()
assert Validate.schema(repository_id, configuration) == CONFIGURATION_SCHEMA
assert Validate.schema(configuration) == CONFIGURATION_SCHEMA
def test_schema_erase_required() -> None:

View File

@@ -142,7 +142,7 @@ def test_check_user(lock: Lock, mocker: MockerFixture) -> None:
tree_create = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
lock.check_user()
check_user_patch.assert_called_once_with(lock.paths, unsafe=False)
check_user_patch.assert_called_once_with(lock.paths.root, unsafe=False)
tree_create.assert_called_once_with()

View File

@@ -62,12 +62,12 @@ def test_database_copy(pacman: Pacman, mocker: MockerFixture) -> None:
mocker.patch("pathlib.Path.is_file", autospec=True, side_effect=lambda p: p.is_relative_to(path))
mkdir_mock = mocker.patch("pathlib.Path.mkdir")
copy_mock = mocker.patch("shutil.copy")
chown_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.chown")
owner_guard_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.preserve_owner")
pacman.database_copy(pacman.handle, database, path, use_ahriman_cache=True)
mkdir_mock.assert_called_once_with(mode=0o755, exist_ok=True)
copy_mock.assert_called_once_with(path / "sync" / "core.db", dst_path)
chown_mock.assert_called_once_with(dst_path)
owner_guard_mock.assert_called_once_with(dst_path.parent)
def test_database_copy_skip(pacman: Pacman, mocker: MockerFixture) -> None:

View File

@@ -20,6 +20,40 @@ def test_architecture(configuration: Configuration) -> None:
assert configuration.architecture == "x86_64"
def test_repository_id(configuration: Configuration, repository_id: RepositoryId) -> None:
"""
must return repository identifier
"""
assert configuration.repository_id == repository_id
assert configuration.get("repository", "name") == repository_id.name
assert configuration.get("repository", "architecture") == repository_id.architecture
def test_repository_id_erase(configuration: Configuration) -> None:
"""
must remove repository identifier properties if empty identifier supplied
"""
configuration.repository_id = None
assert configuration.get("repository", "name", fallback=None) is None
assert configuration.get("repository", "architecture", fallback=None) is None
configuration.repository_id = RepositoryId("", "")
assert configuration.get("repository", "name", fallback=None) is None
assert configuration.get("repository", "architecture", fallback=None) is None
def test_repository_id_update(configuration: Configuration, repository_id: RepositoryId) -> None:
"""
must update repository identifier and related configuration options
"""
repository_id = RepositoryId("i686", repository_id.name)
configuration.repository_id = repository_id
assert configuration.repository_id == repository_id
assert configuration.get("repository", "name") == repository_id.name
assert configuration.get("repository", "architecture") == repository_id.architecture
def test_repository_name(configuration: Configuration) -> None:
"""
must return valid repository name

View File

@@ -6,7 +6,6 @@ from unittest.mock import call as MockCall
from ahriman.core.configuration import Configuration
from ahriman.core.database.migrations.m011_repository_name import migrate_data, migrate_package_repository, steps
from ahriman.models.repository_id import RepositoryId
def test_migration_repository_name() -> None:
@@ -38,13 +37,3 @@ def test_migrate_package_repository(connection: Connection, configuration: Confi
MockCall(pytest.helpers.anyvar(str, strict=True), {"repository": configuration.repository_id.id}),
MockCall(pytest.helpers.anyvar(str, strict=True), {"repository": configuration.repository_id.id}),
])
def test_migrate_package_repository_empty_id(connection: Connection, configuration: Configuration,
mocker: MockerFixture) -> None:
"""
must do nothing on empty repository id
"""
mocker.patch("ahriman.core.configuration.Configuration.check_loaded", return_value=("", RepositoryId("", "")))
migrate_package_repository(connection, configuration)
connection.execute.assert_not_called()

View File

@@ -36,6 +36,17 @@ def test_init_skip_migration(database: SQLite, mocker: MockerFixture) -> None:
migrate_schema_mock.assert_not_called()
def test_init_skip_empty_repository(database: SQLite, mocker: MockerFixture) -> None:
"""
must skip migrations if repository identifier is not set
"""
database._repository_id = RepositoryId("", "")
migrate_schema_mock = mocker.patch("ahriman.core.database.migrations.Migrations.migrate")
database.init()
migrate_schema_mock.assert_not_called()
def test_package_clear(database: SQLite, repository_id: RepositoryId, mocker: MockerFixture) -> None:
"""
must clear package data

View File

@@ -6,12 +6,10 @@ import pytest
from pathlib import Path
from pytest_mock import MockerFixture
from typing import Any
from unittest.mock import call as MockCall
from unittest.mock import MagicMock, call as MockCall
from ahriman.core.exceptions import BuildError, CalledProcessError, OptionError, UnsafeRunError
from ahriman.core.utils import check_output, check_user, dataclass_view, enum_values, extract_user, filter_json, \
full_version, minmax, package_like, parse_version, partition, pretty_datetime, pretty_size, safe_filename, \
srcinfo_property, srcinfo_property_list, trim_package, utcnow, walk
from ahriman.core.utils import *
from ahriman.models.package import Package
from ahriman.models.package_source import PackageSource
from ahriman.models.repository_id import RepositoryId
@@ -163,7 +161,7 @@ def test_check_user(repository_id: RepositoryId, mocker: MockerFixture) -> None:
"""
paths = RepositoryPaths(Path.cwd(), repository_id)
mocker.patch("os.getuid", return_value=paths.root_owner[0])
check_user(paths, unsafe=False)
check_user(paths.root, unsafe=False)
def test_check_user_no_directory(repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
@@ -171,7 +169,7 @@ def test_check_user_no_directory(repository_paths: RepositoryPaths, mocker: Mock
must not fail in case if no directory found
"""
mocker.patch("pathlib.Path.exists", return_value=False)
check_user(repository_paths, unsafe=False)
check_user(repository_paths.root, unsafe=False)
def test_check_user_exception(repository_id: RepositoryId, mocker: MockerFixture) -> None:
@@ -182,7 +180,7 @@ def test_check_user_exception(repository_id: RepositoryId, mocker: MockerFixture
mocker.patch("os.getuid", return_value=paths.root_owner[0] + 1)
with pytest.raises(UnsafeRunError):
check_user(paths, unsafe=False)
check_user(paths.root, unsafe=False)
def test_check_user_unsafe(repository_id: RepositoryId, mocker: MockerFixture) -> None:
@@ -191,7 +189,7 @@ def test_check_user_unsafe(repository_id: RepositoryId, mocker: MockerFixture) -
"""
paths = RepositoryPaths(Path.cwd(), repository_id)
mocker.patch("os.getuid", return_value=paths.root_owner[0] + 1)
check_user(paths, unsafe=True)
check_user(paths.root, unsafe=True)
def test_dataclass_view(package_ahriman: Package) -> None:
@@ -275,6 +273,18 @@ def test_minmax() -> None:
assert minmax([[1, 2, 3], [4, 5], [6, 7, 8, 9]], key=len) == ([4, 5], [6, 7, 8, 9])
def test_owner(repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
"""
must correctly retrieve owner of the path
"""
stat_mock = MagicMock()
stat_mock.st_uid = 42
stat_mock.st_gid = 142
mocker.patch("pathlib.Path.stat", return_value=stat_mock)
assert owner(repository_paths.root) == (42, 142)
def test_package_like(package_ahriman: Package) -> None:
"""
package_like must return true for archives
@@ -414,6 +424,17 @@ def test_safe_filename() -> None:
assert safe_filename("tolua++-1.0.93-4-x86_64.pkg.tar.zst") == "tolua---1.0.93-4-x86_64.pkg.tar.zst"
def test_safe_iterdir(mocker: MockerFixture, resource_path_root: Path) -> None:
"""
must suppress PermissionError
"""
assert list(safe_iterdir(resource_path_root))
iterdir_mock = mocker.patch("pathlib.Path.iterdir", side_effect=PermissionError)
assert list(safe_iterdir(Path("root"))) == []
iterdir_mock.assert_called_once_with()
def test_srcinfo_property() -> None:
"""
must correctly extract properties

View File

@@ -19,10 +19,9 @@ def test_configuration_schema(configuration: Configuration) -> None:
"""
section = "console"
configuration.set_option("report", "target", section)
_, repository_id = configuration.check_loaded()
expected = {section: ReportTrigger.CONFIGURATION_SCHEMA[section]}
assert ReportTrigger.configuration_schema(repository_id, configuration) == expected
assert ReportTrigger.configuration_schema(configuration) == expected
def test_configuration_schema_no_section(configuration: Configuration) -> None:
@@ -31,9 +30,7 @@ def test_configuration_schema_no_section(configuration: Configuration) -> None:
"""
section = "abracadabra"
configuration.set_option("report", "target", section)
_, repository_id = configuration.check_loaded()
assert ReportTrigger.configuration_schema(repository_id, configuration) == {}
assert ReportTrigger.configuration_schema(configuration) == {}
def test_configuration_schema_no_schema(configuration: Configuration) -> None:
@@ -43,17 +40,15 @@ def test_configuration_schema_no_schema(configuration: Configuration) -> None:
section = "abracadabra"
configuration.set_option("report", "target", section)
configuration.set_option(section, "key", "value")
_, repository_id = configuration.check_loaded()
assert ReportTrigger.configuration_schema(repository_id, configuration) == {}
assert ReportTrigger.configuration_schema(configuration) == {}
def test_configuration_schema_empty(configuration: Configuration) -> None:
"""
must return default schema if no configuration set
"""
_, repository_id = configuration.check_loaded()
assert ReportTrigger.configuration_schema(repository_id, None) == ReportTrigger.CONFIGURATION_SCHEMA
assert ReportTrigger.configuration_schema(None) == ReportTrigger.CONFIGURATION_SCHEMA
def test_configuration_schema_variables() -> None:

View File

@@ -2,7 +2,7 @@ import copy
from pathlib import Path
from pytest_mock import MockerFixture
from unittest.mock import MagicMock, call as MockCall
from unittest.mock import MagicMock, PropertyMock, call as MockCall
from ahriman.core.alpm.pacman import Pacman
from ahriman.core.configuration import Configuration
@@ -163,6 +163,23 @@ def test_from_archive(package_ahriman: Package, pyalpm_handle: MagicMock, mocker
assert generated == package_ahriman
def test_from_archive_empty_base(package_ahriman: Package, pyalpm_package_ahriman: MagicMock,
mocker: MockerFixture) -> None:
"""
must construct package with empty base from alpm library
"""
pyalpm_handle = MagicMock()
type(pyalpm_package_ahriman).base = PropertyMock(return_value=None)
pyalpm_handle.handle.load_pkg.return_value = pyalpm_package_ahriman
mocker.patch("ahriman.models.package_description.PackageDescription.from_package",
return_value=package_ahriman.packages[package_ahriman.base])
generated = Package.from_archive(Path("path"), pyalpm_handle)
generated.remote = package_ahriman.remote
assert generated == package_ahriman
def test_from_aur(package_ahriman: Package, aur_package_ahriman: AURPackage, mocker: MockerFixture) -> None:
"""
must construct package from aur

View File

@@ -55,7 +55,7 @@ def test_root_owner(repository_paths: RepositoryPaths, mocker: MockerFixture) ->
"""
must correctly define root directory owner
"""
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.owner", return_value=(42, 142))
mocker.patch("ahriman.models.repository_paths.owner", return_value=(42, 142))
assert repository_paths.root_owner == (42, 142)
@@ -186,16 +186,54 @@ def test_known_repositories_empty(repository_paths: RepositoryPaths, mocker: Moc
iterdir_mock.assert_not_called()
def test_owner(repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
def test_chown(repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
"""
must correctly retrieve owner of the path
must correctly set owner for the directory
"""
stat_mock = MagicMock()
stat_mock.st_uid = 42
stat_mock.st_gid = 142
mocker.patch("pathlib.Path.stat", return_value=stat_mock)
mocker.patch("ahriman.models.repository_paths.owner", _get_owner(repository_paths.root, same=False))
mocker.patch.object(RepositoryPaths, "root_owner", (42, 42))
chown_mock = mocker.patch("os.chown")
assert RepositoryPaths.owner(repository_paths.root) == (42, 142)
path = repository_paths.root / "path"
repository_paths._chown(path)
chown_mock.assert_called_once_with(path, 42, 42, follow_symlinks=False)
def test_chown_parent(repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
"""
must correctly set owner for the directory including parents
"""
mocker.patch("ahriman.models.repository_paths.owner", _get_owner(repository_paths.root, same=False))
mocker.patch.object(RepositoryPaths, "root_owner", (42, 42))
chown_mock = mocker.patch("os.chown")
path = repository_paths.root / "parent" / "path"
repository_paths._chown(path)
chown_mock.assert_has_calls([
MockCall(path, 42, 42, follow_symlinks=False),
MockCall(path.parent, 42, 42, follow_symlinks=False)
])
def test_chown_skip(repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
"""
must skip ownership set in case if it is same as root
"""
mocker.patch("ahriman.models.repository_paths.owner", _get_owner(repository_paths.root, same=True))
mocker.patch.object(RepositoryPaths, "root_owner", (42, 42))
chown_mock = mocker.patch("os.chown")
path = repository_paths.root / "path"
repository_paths._chown(path)
chown_mock.assert_not_called()
def test_chown_invalid_path(repository_paths: RepositoryPaths) -> None:
"""
must raise invalid path exception in case if directory outside the root supplied
"""
with pytest.raises(PathError):
repository_paths._chown(repository_paths.root.parent)
def test_cache_for(repository_paths: RepositoryPaths, package_ahriman: Package) -> None:
@@ -207,54 +245,34 @@ def test_cache_for(repository_paths: RepositoryPaths, package_ahriman: Package)
assert path.parent == repository_paths.cache
def test_chown(repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
def test_preserve_owner(tmp_path: Path, repository_id: RepositoryId, mocker: MockerFixture) -> None:
"""
must correctly set owner for the directory
must preserve file owner during operations
"""
object.__setattr__(repository_paths, "owner", _get_owner(repository_paths.root, same=False))
mocker.patch.object(RepositoryPaths, "root_owner", (42, 42))
chown_mock = mocker.patch("os.chown")
repository_paths = RepositoryPaths(tmp_path, repository_id)
repository_paths.tree_create()
chown_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths._chown")
path = repository_paths.root / "path"
repository_paths.chown(path)
chown_mock.assert_called_once_with(path, 42, 42, follow_symlinks=False)
with repository_paths.preserve_owner():
(repository_paths.root / "created1").touch()
(repository_paths.chroot / "created2").touch()
chown_mock.assert_has_calls([MockCall(repository_paths.root / "created1")])
def test_chown_parent(repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
def test_preserve_owner_specific(tmp_path: Path, repository_id: RepositoryId, mocker: MockerFixture) -> None:
"""
must correctly set owner for the directory including parents
must preserve file owner during operations only in specific directory
"""
object.__setattr__(repository_paths, "owner", _get_owner(repository_paths.root, same=False))
mocker.patch.object(RepositoryPaths, "root_owner", (42, 42))
chown_mock = mocker.patch("os.chown")
repository_paths = RepositoryPaths(tmp_path, repository_id)
repository_paths.tree_create()
(repository_paths.root / "content").mkdir()
chown_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths._chown")
path = repository_paths.root / "parent" / "path"
repository_paths.chown(path)
chown_mock.assert_has_calls([
MockCall(path, 42, 42, follow_symlinks=False),
MockCall(path.parent, 42, 42, follow_symlinks=False)
])
def test_chown_skip(repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
"""
must skip ownership set in case if it is same as root
"""
object.__setattr__(repository_paths, "owner", _get_owner(repository_paths.root, same=True))
mocker.patch.object(RepositoryPaths, "root_owner", (42, 42))
chown_mock = mocker.patch("os.chown")
path = repository_paths.root / "path"
repository_paths.chown(path)
chown_mock.assert_not_called()
def test_chown_invalid_path(repository_paths: RepositoryPaths) -> None:
"""
must raise invalid path exception in case if directory outside the root supplied
"""
with pytest.raises(PathError):
repository_paths.chown(repository_paths.root.parent)
with repository_paths.preserve_owner(repository_paths.root / "content"):
(repository_paths.root / "created1").touch()
(repository_paths.root / "content" / "created2").touch()
(repository_paths.chroot / "created3").touch()
chown_mock.assert_has_calls([MockCall(repository_paths.root / "content" / "created2")])
def test_tree_clear(repository_paths: RepositoryPaths, package_ahriman: Package, mocker: MockerFixture) -> None:
@@ -293,11 +311,11 @@ def test_tree_create(repository_paths: RepositoryPaths, mocker: MockerFixture) -
and not callable(getattr(repository_paths, prop))
}
mkdir_mock = mocker.patch("pathlib.Path.mkdir")
chown_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.chown")
owner_guard_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.preserve_owner")
repository_paths.tree_create()
mkdir_mock.assert_has_calls([MockCall(mode=0o755, parents=True, exist_ok=True) for _ in paths], any_order=True)
chown_mock.assert_has_calls([MockCall(pytest.helpers.anyvar(int)) for _ in paths], any_order=True)
owner_guard_mock.assert_called_once_with()
def test_tree_create_skip(mocker: MockerFixture) -> None: