Compare commits

...

10 Commits

Author SHA1 Message Date
931ff9bd98 Release 2.10.0 2023-07-22 05:28:57 +03:00
6b3fc3a6a0 add support of table filter controls (#101) 2023-07-21 02:10:26 +03:00
b7852f55c8 remove unsafe flag from handlers
This flag became reduntant there and tree creation has been moved to
lock
2023-07-07 03:25:05 +03:00
721b447767 fix code block in docs 2023-07-06 19:17:11 +03:00
b80ea80e9d add salt generator to setup command instead 2023-07-06 19:16:49 +03:00
8e9da5baab register dependency package before build
If package has been added as dependency, the service miss remote as well
as causes some 400 errors in reporter
2023-07-06 03:11:19 +03:00
a443abb94e handle packages load from aur by package name also
In general package names array may not contain package base, thus it
leads to inability to load packages from aur by its base during update
process
2023-07-01 15:55:04 +03:00
61c565ab0d explicitly pass user agent for the arch linux sites requests 2023-06-26 02:52:08 +03:00
10100b20e1 print configuration paths in dump command 2023-06-11 15:11:34 +03:00
2922bb9d72 remove salt generation from users handler
It causes issues, because users handler is operating with service user,
but writtinng salt requires root privileges
2023-06-05 05:25:10 +03:00
105 changed files with 5214 additions and 4650 deletions

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 762 KiB

After

Width:  |  Height:  |  Size: 812 KiB

View File

@ -1,4 +1,4 @@
.TH AHRIMAN "1" "2023\-06\-03" "ahriman" "Generated Python Manual" .TH AHRIMAN "1" "2023\-07\-22" "ahriman" "Generated Python Manual"
.SH NAME .SH NAME
ahriman ahriman
.SH SYNOPSIS .SH SYNOPSIS
@ -669,9 +669,10 @@ key server for key import
.SH COMMAND \fI\,'ahriman service\-setup'\/\fR .SH COMMAND \fI\,'ahriman service\-setup'\/\fR
usage: ahriman service\-setup [\-h] [\-\-build\-as\-user BUILD_AS_USER] [\-\-build\-command BUILD_COMMAND] usage: ahriman service\-setup [\-h] [\-\-build\-as\-user BUILD_AS_USER] [\-\-build\-command BUILD_COMMAND]
[\-\-from\-configuration FROM_CONFIGURATION] [\-\-makeflags\-jobs | \-\-no\-makeflags\-jobs] [\-\-from\-configuration FROM_CONFIGURATION] [\-\-generate\-salt | \-\-no\-generate\-salt]
[\-\-mirror MIRROR] [\-\-multilib | \-\-no\-multilib] \-\-packager PACKAGER \-\-repository REPOSITORY [\-\-makeflags\-jobs | \-\-no\-makeflags\-jobs] [\-\-mirror MIRROR] [\-\-multilib | \-\-no\-multilib]
[\-\-sign\-key SIGN_KEY] [\-\-sign\-target {disabled,packages,repository}] [\-\-web\-port WEB_PORT] \-\-packager PACKAGER \-\-repository REPOSITORY [\-\-sign\-key SIGN_KEY]
[\-\-sign\-target {disabled,packages,repository}] [\-\-web\-port WEB_PORT]
[\-\-web\-unix\-socket WEB_UNIX_SOCKET] [\-\-web\-unix\-socket WEB_UNIX_SOCKET]
create initial service configuration, requires root create initial service configuration, requires root
@ -689,6 +690,10 @@ build command prefix
\fB\-\-from\-configuration\fR \fI\,FROM_CONFIGURATION\/\fR \fB\-\-from\-configuration\fR \fI\,FROM_CONFIGURATION\/\fR
path to default devtools pacman configuration path to default devtools pacman configuration
.TP
\fB\-\-generate\-salt\fR, \fB\-\-no\-generate\-salt\fR
generate salt for user passwords
.TP .TP
\fB\-\-makeflags\-jobs\fR, \fB\-\-no\-makeflags\-jobs\fR \fB\-\-makeflags\-jobs\fR, \fB\-\-no\-makeflags\-jobs\fR
append MAKEFLAGS variable with parallelism set to number of cores append MAKEFLAGS variable with parallelism set to number of cores
@ -735,7 +740,7 @@ drop into python shell while having created application
instead of dropping into shell, just execute the specified code instead of dropping into shell, just execute the specified code
.SH COMMAND \fI\,'ahriman user\-add'\/\fR .SH COMMAND \fI\,'ahriman user\-add'\/\fR
usage: ahriman user\-add [\-h] [\-\-key KEY] [\-\-packager PACKAGER] [\-p PASSWORD] [\-r {unauthorized,read,reporter,full}] [\-s] usage: ahriman user\-add [\-h] [\-\-key KEY] [\-\-packager PACKAGER] [\-p PASSWORD] [\-r {unauthorized,read,reporter,full}]
username username
update user for web services with the given password and role. In case if password was not entered it will be asked interactively update user for web services with the given password and role. In case if password was not entered it will be asked interactively
@ -762,10 +767,6 @@ authorization type.
\fB\-r\fR \fI\,{unauthorized,read,reporter,full}\/\fR, \fB\-\-role\fR \fI\,{unauthorized,read,reporter,full}\/\fR \fB\-r\fR \fI\,{unauthorized,read,reporter,full}\/\fR, \fB\-\-role\fR \fI\,{unauthorized,read,reporter,full}\/\fR
user access level user access level
.TP
\fB\-s\fR, \fB\-\-secure\fR
set file permissions to user\-only
.SH COMMAND \fI\,'ahriman user\-list'\/\fR .SH COMMAND \fI\,'ahriman user\-list'\/\fR
usage: ahriman user\-list [\-h] [\-e] [\-r {unauthorized,read,reporter,full}] [username] usage: ahriman user\-list [\-h] [\-e] [\-r {unauthorized,read,reporter,full}] [username]

View File

@ -58,14 +58,14 @@ _shtab_ahriman_config_validate_option_strings=('-h' '--help' '-e' '--exit-code')
_shtab_ahriman_repo_config_validate_option_strings=('-h' '--help' '-e' '--exit-code') _shtab_ahriman_repo_config_validate_option_strings=('-h' '--help' '-e' '--exit-code')
_shtab_ahriman_service_key_import_option_strings=('-h' '--help' '--key-server') _shtab_ahriman_service_key_import_option_strings=('-h' '--help' '--key-server')
_shtab_ahriman_key_import_option_strings=('-h' '--help' '--key-server') _shtab_ahriman_key_import_option_strings=('-h' '--help' '--key-server')
_shtab_ahriman_service_setup_option_strings=('-h' '--help' '--build-as-user' '--build-command' '--from-configuration' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--repository' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket') _shtab_ahriman_service_setup_option_strings=('-h' '--help' '--build-as-user' '--build-command' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--repository' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket')
_shtab_ahriman_init_option_strings=('-h' '--help' '--build-as-user' '--build-command' '--from-configuration' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--repository' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket') _shtab_ahriman_init_option_strings=('-h' '--help' '--build-as-user' '--build-command' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--repository' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket')
_shtab_ahriman_repo_init_option_strings=('-h' '--help' '--build-as-user' '--build-command' '--from-configuration' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--repository' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket') _shtab_ahriman_repo_init_option_strings=('-h' '--help' '--build-as-user' '--build-command' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--repository' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket')
_shtab_ahriman_repo_setup_option_strings=('-h' '--help' '--build-as-user' '--build-command' '--from-configuration' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--repository' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket') _shtab_ahriman_repo_setup_option_strings=('-h' '--help' '--build-as-user' '--build-command' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--repository' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket')
_shtab_ahriman_setup_option_strings=('-h' '--help' '--build-as-user' '--build-command' '--from-configuration' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--repository' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket') _shtab_ahriman_setup_option_strings=('-h' '--help' '--build-as-user' '--build-command' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--repository' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket')
_shtab_ahriman_service_shell_option_strings=('-h' '--help') _shtab_ahriman_service_shell_option_strings=('-h' '--help')
_shtab_ahriman_shell_option_strings=('-h' '--help') _shtab_ahriman_shell_option_strings=('-h' '--help')
_shtab_ahriman_user_add_option_strings=('-h' '--help' '--key' '--packager' '-p' '--password' '-r' '--role' '-s' '--secure') _shtab_ahriman_user_add_option_strings=('-h' '--help' '--key' '--packager' '-p' '--password' '-r' '--role')
_shtab_ahriman_user_list_option_strings=('-h' '--help' '-e' '--exit-code' '-r' '--role') _shtab_ahriman_user_list_option_strings=('-h' '--help' '-e' '--exit-code' '-r' '--role')
_shtab_ahriman_user_remove_option_strings=('-h' '--help') _shtab_ahriman_user_remove_option_strings=('-h' '--help')
_shtab_ahriman_web_option_strings=('-h' '--help') _shtab_ahriman_web_option_strings=('-h' '--help')
@ -413,30 +413,40 @@ _shtab_ahriman_key_import__h_nargs=0
_shtab_ahriman_key_import___help_nargs=0 _shtab_ahriman_key_import___help_nargs=0
_shtab_ahriman_service_setup__h_nargs=0 _shtab_ahriman_service_setup__h_nargs=0
_shtab_ahriman_service_setup___help_nargs=0 _shtab_ahriman_service_setup___help_nargs=0
_shtab_ahriman_service_setup___generate_salt_nargs=0
_shtab_ahriman_service_setup___no_generate_salt_nargs=0
_shtab_ahriman_service_setup___makeflags_jobs_nargs=0 _shtab_ahriman_service_setup___makeflags_jobs_nargs=0
_shtab_ahriman_service_setup___no_makeflags_jobs_nargs=0 _shtab_ahriman_service_setup___no_makeflags_jobs_nargs=0
_shtab_ahriman_service_setup___multilib_nargs=0 _shtab_ahriman_service_setup___multilib_nargs=0
_shtab_ahriman_service_setup___no_multilib_nargs=0 _shtab_ahriman_service_setup___no_multilib_nargs=0
_shtab_ahriman_init__h_nargs=0 _shtab_ahriman_init__h_nargs=0
_shtab_ahriman_init___help_nargs=0 _shtab_ahriman_init___help_nargs=0
_shtab_ahriman_init___generate_salt_nargs=0
_shtab_ahriman_init___no_generate_salt_nargs=0
_shtab_ahriman_init___makeflags_jobs_nargs=0 _shtab_ahriman_init___makeflags_jobs_nargs=0
_shtab_ahriman_init___no_makeflags_jobs_nargs=0 _shtab_ahriman_init___no_makeflags_jobs_nargs=0
_shtab_ahriman_init___multilib_nargs=0 _shtab_ahriman_init___multilib_nargs=0
_shtab_ahriman_init___no_multilib_nargs=0 _shtab_ahriman_init___no_multilib_nargs=0
_shtab_ahriman_repo_init__h_nargs=0 _shtab_ahriman_repo_init__h_nargs=0
_shtab_ahriman_repo_init___help_nargs=0 _shtab_ahriman_repo_init___help_nargs=0
_shtab_ahriman_repo_init___generate_salt_nargs=0
_shtab_ahriman_repo_init___no_generate_salt_nargs=0
_shtab_ahriman_repo_init___makeflags_jobs_nargs=0 _shtab_ahriman_repo_init___makeflags_jobs_nargs=0
_shtab_ahriman_repo_init___no_makeflags_jobs_nargs=0 _shtab_ahriman_repo_init___no_makeflags_jobs_nargs=0
_shtab_ahriman_repo_init___multilib_nargs=0 _shtab_ahriman_repo_init___multilib_nargs=0
_shtab_ahriman_repo_init___no_multilib_nargs=0 _shtab_ahriman_repo_init___no_multilib_nargs=0
_shtab_ahriman_repo_setup__h_nargs=0 _shtab_ahriman_repo_setup__h_nargs=0
_shtab_ahriman_repo_setup___help_nargs=0 _shtab_ahriman_repo_setup___help_nargs=0
_shtab_ahriman_repo_setup___generate_salt_nargs=0
_shtab_ahriman_repo_setup___no_generate_salt_nargs=0
_shtab_ahriman_repo_setup___makeflags_jobs_nargs=0 _shtab_ahriman_repo_setup___makeflags_jobs_nargs=0
_shtab_ahriman_repo_setup___no_makeflags_jobs_nargs=0 _shtab_ahriman_repo_setup___no_makeflags_jobs_nargs=0
_shtab_ahriman_repo_setup___multilib_nargs=0 _shtab_ahriman_repo_setup___multilib_nargs=0
_shtab_ahriman_repo_setup___no_multilib_nargs=0 _shtab_ahriman_repo_setup___no_multilib_nargs=0
_shtab_ahriman_setup__h_nargs=0 _shtab_ahriman_setup__h_nargs=0
_shtab_ahriman_setup___help_nargs=0 _shtab_ahriman_setup___help_nargs=0
_shtab_ahriman_setup___generate_salt_nargs=0
_shtab_ahriman_setup___no_generate_salt_nargs=0
_shtab_ahriman_setup___makeflags_jobs_nargs=0 _shtab_ahriman_setup___makeflags_jobs_nargs=0
_shtab_ahriman_setup___no_makeflags_jobs_nargs=0 _shtab_ahriman_setup___no_makeflags_jobs_nargs=0
_shtab_ahriman_setup___multilib_nargs=0 _shtab_ahriman_setup___multilib_nargs=0
@ -451,8 +461,6 @@ _shtab_ahriman_shell__v_nargs=0
_shtab_ahriman_shell___verbose_nargs=0 _shtab_ahriman_shell___verbose_nargs=0
_shtab_ahriman_user_add__h_nargs=0 _shtab_ahriman_user_add__h_nargs=0
_shtab_ahriman_user_add___help_nargs=0 _shtab_ahriman_user_add___help_nargs=0
_shtab_ahriman_user_add__s_nargs=0
_shtab_ahriman_user_add___secure_nargs=0
_shtab_ahriman_user_list__h_nargs=0 _shtab_ahriman_user_list__h_nargs=0
_shtab_ahriman_user_list___help_nargs=0 _shtab_ahriman_user_list___help_nargs=0
_shtab_ahriman_user_list__e_nargs=0 _shtab_ahriman_user_list__e_nargs=0

View File

@ -169,6 +169,7 @@ _shtab_ahriman_init_options=(
"--build-as-user[force makepkg user to the specific one]:build_as_user:" "--build-as-user[force makepkg user to the specific one]:build_as_user:"
"--build-command[build command prefix]:build_command:" "--build-command[build command prefix]:build_command:"
"--from-configuration[path to default devtools pacman configuration]:from_configuration:" "--from-configuration[path to default devtools pacman configuration]:from_configuration:"
{--generate-salt,--no-generate-salt}"[generate salt for user passwords]:generate_salt:"
{--makeflags-jobs,--no-makeflags-jobs}"[append MAKEFLAGS variable with parallelism set to number of cores]:makeflags_jobs:" {--makeflags-jobs,--no-makeflags-jobs}"[append MAKEFLAGS variable with parallelism set to number of cores]:makeflags_jobs:"
"--mirror[use the specified explicitly mirror instead of including mirrorlist]:mirror:" "--mirror[use the specified explicitly mirror instead of including mirrorlist]:mirror:"
{--multilib,--no-multilib}"[add or do not multilib repository]:multilib:" {--multilib,--no-multilib}"[add or do not multilib repository]:multilib:"
@ -335,6 +336,7 @@ _shtab_ahriman_repo_init_options=(
"--build-as-user[force makepkg user to the specific one]:build_as_user:" "--build-as-user[force makepkg user to the specific one]:build_as_user:"
"--build-command[build command prefix]:build_command:" "--build-command[build command prefix]:build_command:"
"--from-configuration[path to default devtools pacman configuration]:from_configuration:" "--from-configuration[path to default devtools pacman configuration]:from_configuration:"
{--generate-salt,--no-generate-salt}"[generate salt for user passwords]:generate_salt:"
{--makeflags-jobs,--no-makeflags-jobs}"[append MAKEFLAGS variable with parallelism set to number of cores]:makeflags_jobs:" {--makeflags-jobs,--no-makeflags-jobs}"[append MAKEFLAGS variable with parallelism set to number of cores]:makeflags_jobs:"
"--mirror[use the specified explicitly mirror instead of including mirrorlist]:mirror:" "--mirror[use the specified explicitly mirror instead of including mirrorlist]:mirror:"
{--multilib,--no-multilib}"[add or do not multilib repository]:multilib:" {--multilib,--no-multilib}"[add or do not multilib repository]:multilib:"
@ -376,6 +378,7 @@ _shtab_ahriman_repo_setup_options=(
"--build-as-user[force makepkg user to the specific one]:build_as_user:" "--build-as-user[force makepkg user to the specific one]:build_as_user:"
"--build-command[build command prefix]:build_command:" "--build-command[build command prefix]:build_command:"
"--from-configuration[path to default devtools pacman configuration]:from_configuration:" "--from-configuration[path to default devtools pacman configuration]:from_configuration:"
{--generate-salt,--no-generate-salt}"[generate salt for user passwords]:generate_salt:"
{--makeflags-jobs,--no-makeflags-jobs}"[append MAKEFLAGS variable with parallelism set to number of cores]:makeflags_jobs:" {--makeflags-jobs,--no-makeflags-jobs}"[append MAKEFLAGS variable with parallelism set to number of cores]:makeflags_jobs:"
"--mirror[use the specified explicitly mirror instead of including mirrorlist]:mirror:" "--mirror[use the specified explicitly mirror instead of including mirrorlist]:mirror:"
{--multilib,--no-multilib}"[add or do not multilib repository]:multilib:" {--multilib,--no-multilib}"[add or do not multilib repository]:multilib:"
@ -466,6 +469,7 @@ _shtab_ahriman_service_setup_options=(
"--build-as-user[force makepkg user to the specific one]:build_as_user:" "--build-as-user[force makepkg user to the specific one]:build_as_user:"
"--build-command[build command prefix]:build_command:" "--build-command[build command prefix]:build_command:"
"--from-configuration[path to default devtools pacman configuration]:from_configuration:" "--from-configuration[path to default devtools pacman configuration]:from_configuration:"
{--generate-salt,--no-generate-salt}"[generate salt for user passwords]:generate_salt:"
{--makeflags-jobs,--no-makeflags-jobs}"[append MAKEFLAGS variable with parallelism set to number of cores]:makeflags_jobs:" {--makeflags-jobs,--no-makeflags-jobs}"[append MAKEFLAGS variable with parallelism set to number of cores]:makeflags_jobs:"
"--mirror[use the specified explicitly mirror instead of including mirrorlist]:mirror:" "--mirror[use the specified explicitly mirror instead of including mirrorlist]:mirror:"
{--multilib,--no-multilib}"[add or do not multilib repository]:multilib:" {--multilib,--no-multilib}"[add or do not multilib repository]:multilib:"
@ -487,6 +491,7 @@ _shtab_ahriman_setup_options=(
"--build-as-user[force makepkg user to the specific one]:build_as_user:" "--build-as-user[force makepkg user to the specific one]:build_as_user:"
"--build-command[build command prefix]:build_command:" "--build-command[build command prefix]:build_command:"
"--from-configuration[path to default devtools pacman configuration]:from_configuration:" "--from-configuration[path to default devtools pacman configuration]:from_configuration:"
{--generate-salt,--no-generate-salt}"[generate salt for user passwords]:generate_salt:"
{--makeflags-jobs,--no-makeflags-jobs}"[append MAKEFLAGS variable with parallelism set to number of cores]:makeflags_jobs:" {--makeflags-jobs,--no-makeflags-jobs}"[append MAKEFLAGS variable with parallelism set to number of cores]:makeflags_jobs:"
"--mirror[use the specified explicitly mirror instead of including mirrorlist]:mirror:" "--mirror[use the specified explicitly mirror instead of including mirrorlist]:mirror:"
{--multilib,--no-multilib}"[add or do not multilib repository]:multilib:" {--multilib,--no-multilib}"[add or do not multilib repository]:multilib:"
@ -547,7 +552,6 @@ _shtab_ahriman_user_add_options=(
"--packager[optional packager id used for build process in form of \`Name Surname \<mail\@example.com\>\`]:packager:" "--packager[optional packager id used for build process in form of \`Name Surname \<mail\@example.com\>\`]:packager:"
{-p,--password}"[user password. Blank password will be treated as empty password, which is in particular must be used for OAuth2 authorization type.]:password:" {-p,--password}"[user password. Blank password will be treated as empty password, which is in particular must be used for OAuth2 authorization type.]:password:"
{-r,--role}"[user access level]:role:(unauthorized read reporter full)" {-r,--role}"[user access level]:role:(unauthorized read reporter full)"
{-s,--secure}"[set file permissions to user-only]"
":username for web service:" ":username for web service:"
) )

View File

@ -196,7 +196,7 @@ Alternatively you can create full-diff patches, which are calculated by using ``
.. code-block:: shell .. code-block:: shell
sudo -u ahriman ahriman patch-set-add /path/to/local/directory/with/PKGBUILD sudo -u ahriman ahriman patch-set-add /path/to/local/directory/with/PKGBUILD
The last command will calculate diff from current tree to the ``HEAD`` and will store it locally. Patches will be applied on any package actions (e.g. it can be used for dependency management). The last command will calculate diff from current tree to the ``HEAD`` and will store it locally. Patches will be applied on any package actions (e.g. it can be used for dependency management).
@ -862,12 +862,13 @@ How to enable basic authorization
yay -S --asdeps python-aiohttp-security python-aiohttp-session python-cryptography yay -S --asdeps python-aiohttp-security python-aiohttp-session python-cryptography
#. #.
Configure the service to enable authorization: Configure the service to enable authorization (``salt`` can be generated as any random string):
.. code-block:: ini .. code-block:: ini
[auth] [auth]
target = configuration target = configuration
salt = somerandomstring
#. #.
In order to provide access for reporting from application instances you can (recommended way) use unix sockets by configuring the following (note, that it requires ``python-requests-unixsocket`` package to be installed): In order to provide access for reporting from application instances you can (recommended way) use unix sockets by configuring the following (note, that it requires ``python-requests-unixsocket`` package to be installed):
@ -933,7 +934,7 @@ How to enable OAuth authorization
Configure ``oauth_provider`` and ``oauth_scopes`` in case if you would like to use different from Google provider. Scope must grant access to user email. ``web.address`` is required to make callback URL available from internet. Configure ``oauth_provider`` and ``oauth_scopes`` in case if you would like to use different from Google provider. Scope must grant access to user email. ``web.address`` is required to make callback URL available from internet.
#. #.
Create service user: If you are not going to use unix socket, you also need to create service user (remember to set ``auth.salt`` option before):
.. code-block:: shell .. code-block:: shell

BIN
github-logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

View File

@ -1,7 +1,7 @@
# Maintainer: Evgeniy Alekseev # Maintainer: Evgeniy Alekseev
pkgname='ahriman' pkgname='ahriman'
pkgver=2.9.0 pkgver=2.10.0
pkgrel=1 pkgrel=1
pkgdesc="ArcH linux ReposItory MANager" pkgdesc="ArcH linux ReposItory MANager"
arch=('any') arch=('any')

View File

@ -63,6 +63,8 @@
<table id="packages" class="table table-striped table-hover" <table id="packages" class="table table-striped table-hover"
data-export-options='{"fileName": "packages"}' data-export-options='{"fileName": "packages"}'
data-filter-control="true"
data-filter-control-visible="false"
data-page-list="[10, 25, 50, 100, all]" data-page-list="[10, 25, 50, 100, all]"
data-page-size="10" data-page-size="10"
data-pagination="true" data-pagination="true"
@ -72,6 +74,7 @@
data-show-columns-search="true" data-show-columns-search="true"
data-show-columns-toggle-all="true" data-show-columns-toggle-all="true"
data-show-export="true" data-show-export="true"
data-show-filter-control-switch="true"
data-show-fullscreen="true" data-show-fullscreen="true"
data-show-search-clear-button="true" data-show-search-clear-button="true"
data-sortable="true" data-sortable="true"
@ -82,14 +85,14 @@
<thead class="table-primary"> <thead class="table-primary">
<tr> <tr>
<th data-checkbox="true"></th> <th data-checkbox="true"></th>
<th data-sortable="true" data-switchable="false" data-field="base">package base</th> <th data-sortable="true" data-switchable="false" data-field="base" data-filter-control="input" data-filter-control-placeholder="(any base)">package base</th>
<th data-sortable="true" data-field="version">version</th> <th data-sortable="true" data-field="version" data-filter-control="input" data-filter-control-placeholder="(any version)">version</th>
<th data-sortable="true" data-field="packages">packages</th> <th data-sortable="true" data-field="packages" data-filter-control="input" data-filter-control-placeholder="(any package)">packages</th>
<th data-sortable="true" data-visible="false" data-field="groups">groups</th> <th data-sortable="true" data-visible="false" data-field="groups" data-filter-control="select" data-filter-data="func:filterListGroups" data-filter-custom-search="filterList" data-filter-control-placeholder="(any group)">groups</th>
<th data-sortable="true" data-visible="false" data-field="licenses">licenses</th> <th data-sortable="true" data-visible="false" data-field="licenses" data-filter-control="select" data-filter-data="func:filterListLicenses" data-filter-custom-search="filterList" data-filter-control-placeholder="(any license)">licenses</th>
<th data-sortable="true" data-visible="false" data-field="packager">packager</th> <th data-sortable="true" data-visible="false" data-field="packager" data-filter-control="select" data-filter-custom-search="filterContains" data-filter-control-placeholder="(any packager)">packager</th>
<th data-sortable="true" data-field="timestamp">last update</th> <th data-sortable="true" data-field="timestamp" data-filter-control="input" data-filter-custom-search="filterDateRange" data-filter-control-placeholder="(any date)">last update</th>
<th data-sortable="true" data-cell-style="statusFormat" data-field="status">status</th> <th data-sortable="true" data-cell-style="statusFormat" data-field="status" data-filter-control="select" data-filter-control-placeholder="(any status)">status</th>
</tr> </tr>
</thead> </thead>
</table> </table>

View File

@ -84,7 +84,7 @@
showSuccess("Success", `Key ${key} has been imported`); showSuccess("Success", `Key ${key} has been imported`);
}, },
error: (jqXHR, _, errorThrown) => { error: (jqXHR, _, errorThrown) => {
const message = _ => { return `Could not import key ${key} from ${server}`; }; const message = _ => `Could not import key ${key} from ${server}`;
showFailure("Action failed", message, jqXHR, errorThrown); showFailure("Action failed", message, jqXHR, errorThrown);
}, },
}); });

View File

@ -60,8 +60,8 @@
const packages = packageInput.val(); const packages = packageInput.val();
if (packages) { if (packages) {
packageAddModal.modal("hide"); packageAddModal.modal("hide");
const onSuccess = update => { return `Packages ${update} have been added`; }; const onSuccess = update => `Packages ${update} have been added`;
const onFailure = error => { return `Package addition failed: ${error}`; }; const onFailure = error => `Package addition failed: ${error}`;
doPackageAction("/api/v1/service/add", [packages], onSuccess, onFailure); doPackageAction("/api/v1/service/add", [packages], onSuccess, onFailure);
} }
} }
@ -70,8 +70,8 @@
const packages = packageInput.val(); const packages = packageInput.val();
if (packages) { if (packages) {
packageAddModal.modal("hide"); packageAddModal.modal("hide");
const onSuccess = update => { return `Packages ${update} have been requested`; }; const onSuccess = update => `Packages ${update} have been requested`;
const onFailure = error => { return `Package request failed: ${error}`; }; const onFailure = error => `Package request failed: ${error}`;
doPackageAction("/api/v1/service/request", [packages], onSuccess, onFailure); doPackageAction("/api/v1/service/request", [packages], onSuccess, onFailure);
} }
} }

View File

@ -61,7 +61,7 @@
error: (jqXHR, _, errorThrown) => { error: (jqXHR, _, errorThrown) => {
// show failed modal in case if first time loading // show failed modal in case if first time loading
if (isPackageBaseSet) { if (isPackageBaseSet) {
const message = error => { return `Could not load package ${packageBase} logs: ${error}`; }; const message = error => `Could not load package ${packageBase} logs: ${error}`;
showFailure("Load failure", message, jqXHR, errorThrown); showFailure("Load failure", message, jqXHR, errorThrown);
} }
}, },

View File

@ -33,8 +33,8 @@
const packages = dependencyInput.val(); const packages = dependencyInput.val();
if (packages) { if (packages) {
packageRebuildModal.modal("hide"); packageRebuildModal.modal("hide");
const onSuccess = update => { return `Repository rebuild has been run for packages which depend on ${update}`; }; const onSuccess = update => `Repository rebuild has been run for packages which depend on ${update}`;
const onFailure = error => { return `Repository rebuild failed: ${error}`; }; const onFailure = error => `Repository rebuild failed: ${error}`;
doPackageAction("/api/v1/service/rebuild", [packages], onSuccess, onFailure); doPackageAction("/api/v1/service/rebuild", [packages], onSuccess, onFailure);
} }
} }

View File

@ -15,6 +15,25 @@
table.bootstrapTable(method, {field: "id", values: [data.id]}); table.bootstrapTable(method, {field: "id", values: [data.id]});
} else showLogs(data.id); } else showLogs(data.id);
}); });
table.on("created-controls.bs.table", () => {
const pickerInput = $(".bootstrap-table-filter-control-timestamp");
pickerInput.daterangepicker({
autoUpdateInput: false,
locale: {
cancelLabel: "Clear",
},
});
pickerInput.on("apply.daterangepicker", (event, picker) => {
pickerInput.val(`${picker.startDate.format("YYYY-MM-DD")} - ${picker.endDate.format("YYYY-MM-DD")}`);
table.bootstrapTable("triggerSearch");
});
pickerInput.on("cancel.daterangepicker", () => {
pickerInput.val("");
table.bootstrapTable("triggerSearch");
});
});
const repositoryBadge = $("#badge-repository"); const repositoryBadge = $("#badge-repository");
const statusBadge = $("#badge-status"); const statusBadge = $("#badge-status");
@ -37,21 +56,21 @@
} }
function getSelection() { function getSelection() {
return table.bootstrapTable("getSelections").map(row => { return row.id; }); return table.bootstrapTable("getSelections").map(row => row.id);
} }
function removePackages() { function removePackages() {
const onSuccess = update => { return `Packages ${update} have been removed`; }; const onSuccess = update => `Packages ${update} have been removed`;
const onFailure = error => { return `Could not remove packages: ${error}`; }; const onFailure = error => `Could not remove packages: ${error}`;
doPackageAction("/api/v1/service/remove", getSelection(), onSuccess, onFailure); doPackageAction("/api/v1/service/remove", getSelection(), onSuccess, onFailure);
} }
function updatePackages() { function updatePackages() {
const currentSelection = getSelection(); const currentSelection = getSelection();
const [url, onSuccess] = currentSelection.length === 0 const [url, onSuccess] = currentSelection.length === 0
? ["/api/v1/service/update", _ => { return "Repository update has been run"; }] ? ["/api/v1/service/update", _ => "Repository update has been run"]
: ["/api/v1/service/add", update => { return `Run update for packages ${update}`; }]; : ["/api/v1/service/add", update => `Run update for packages ${update}`];
const onFailure = error => { return `Packages update failed: ${error}`; }; const onFailure = error => `Packages update failed: ${error}`;
doPackageAction(url, currentSelection, onSuccess, onFailure); doPackageAction(url, currentSelection, onSuccess, onFailure);
} }
@ -81,13 +100,13 @@
success: response => { success: response => {
const extractListProperties = (description, property) => { const extractListProperties = (description, property) => {
return Object.values(description.packages) return Object.values(description.packages)
.map(pkg => { return pkg[property]; }) .map(pkg => pkg[property])
.reduce((left, right) => { return left.concat(right); }, []); .reduce((left, right) => left.concat(right), []);
}; };
const listToTable = data => { const listToTable = data => {
return Array.from(new Set(data)) return Array.from(new Set(data))
.sort() .sort()
.map(entry => { return safe(entry); }) .map(entry => safe(entry))
.join("<br>"); .join("<br>");
}; };
@ -121,7 +140,7 @@
table.bootstrapTable("hideLoading"); table.bootstrapTable("hideLoading");
} else { } else {
// other errors // other errors
const message = error => { return `Could not load list of packages: ${error}`; }; const message = error => `Could not load list of packages: ${error}`;
showFailure("Load failure", message, jqXHR, errorThrown); showFailure("Load failure", message, jqXHR, errorThrown);
} }
hideControls(true); hideControls(true);
@ -158,6 +177,18 @@
return {classes: cellClass(value)}; return {classes: cellClass(value)};
} }
function filterListGroups() {
return extractDataList(table.bootstrapTable("getData"), "groups");
}
function filterListLicenses() {
return extractDataList(table.bootstrapTable("getData"), "licenses");
}
function filterListPackagers() {
return extractDataList(table.bootstrapTable("getData"), "packager");
}
$(() => { $(() => {
table.bootstrapTable({}); table.bootstrapTable({});
statusBadge.popover(); statusBadge.popover();

View File

@ -31,6 +31,8 @@ SigLevel = Database{% if has_repo_signed %}Required{% else %}Never{% endif %} Pa
<div class="container"> <div class="container">
<table id="packages" class="table table-striped table-hover" <table id="packages" class="table table-striped table-hover"
data-export-options='{"fileName": "packages"}' data-export-options='{"fileName": "packages"}'
data-filter-control="true"
data-filter-control-visible="false"
data-page-list="[10, 25, 50, 100, all]" data-page-list="[10, 25, 50, 100, all]"
data-page-size="10" data-page-size="10"
data-pagination="true" data-pagination="true"
@ -40,6 +42,7 @@ SigLevel = Database{% if has_repo_signed %}Required{% else %}Never{% endif %} Pa
data-show-columns-search="true" data-show-columns-search="true"
data-show-columns-toggle-all="true" data-show-columns-toggle-all="true"
data-show-export="true" data-show-export="true"
data-show-filter-control-switch="true"
data-show-fullscreen="true" data-show-fullscreen="true"
data-show-search-clear-button="true" data-show-search-clear-button="true"
data-sortable="true" data-sortable="true"
@ -48,17 +51,17 @@ SigLevel = Database{% if has_repo_signed %}Required{% else %}Never{% endif %} Pa
data-toggle="table"> data-toggle="table">
<thead class="table-primary"> <thead class="table-primary">
<tr> <tr>
<th data-sortable="true" data-switchable="false">package</th> <th data-sortable="true" data-switchable="false" data-field="name" data-filter-control="input" data-filter-control-placeholder="(any package)">package</th>
<th data-sortable="true">version</th> <th data-sortable="true" data-field="version" data-filter-control="input" data-filter-control-placeholder="(any version)">version</th>
<th data-sortable="true" data-visible="false">architecture</th> <th data-sortable="true" data-visible="false" data-field="architecture" data-filter-control="select" data-filter-control-placeholder="(any arch)">architecture</th>
<th data-sortable="true" data-visible="false">description</th> <th data-sortable="true" data-visible="false" data-field="description" data-filter-control="input" data-filter-control-placeholder="(any description)">description</th>
<th data-sortable="true" data-visible="false">upstream url</th> <th data-sortable="true" data-visible="false" data-field="url">upstream url</th>
<th data-sortable="true" data-visible="false">licenses</th> <th data-sortable="true" data-visible="false" data-field="licenses" data-filter-control="select" data-filter-data="func:filterListLicenses" data-filter-custom-search="filterList" data-filter-control-placeholder="(any license)">licenses</th>
<th data-sortable="true" data-visible="false">groups</th> <th data-sortable="true" data-visible="false" data-field="groups" data-filter-control="select" data-filter-data="func:filterListGroups" data-filter-custom-search="filterList" data-filter-control-placeholder="(any group)">groups</th>
<th data-sortable="true" data-visible="false">depends</th> <th data-sortable="true" data-visible="false" data-field="depends" data-filter-control="select" data-filter-data="func:filterListDepends" data-filter-custom-search="filterList" data-filter-control-placeholder="(any depends)">depends</th>
<th data-sortable="true">archive size</th> <th data-sortable="true" data-field="archive_size">archive size</th>
<th data-sortable="true">installed size</th> <th data-sortable="true" data-field="installed_size">installed size</th>
<th data-sortable="true">build date</th> <th data-sortable="true" data-field="timestamp" data-filter-control="input" data-filter-custom-search="filterDateRange" data-filter-control-placeholder="(any date)">build date</th>
</tr> </tr>
</thead> </thead>
@ -96,6 +99,27 @@ SigLevel = Database{% if has_repo_signed %}Required{% else %}Never{% endif %} Pa
</div> </div>
<script> <script>
const table = $("#packages");
table.on("created-controls.bs.table", () => {
const pickerInput = $(".bootstrap-table-filter-control-timestamp");
pickerInput.daterangepicker({
autoUpdateInput: false,
locale: {
cancelLabel: "Clear",
},
});
pickerInput.on("apply.daterangepicker", (event, picker) => {
pickerInput.val(`${picker.startDate.format("YYYY-MM-DD")} - ${picker.endDate.format("YYYY-MM-DD")}`);
table.bootstrapTable("triggerSearch");
});
pickerInput.on("cancel.daterangepicker", () => {
pickerInput.val("");
table.bootstrapTable("triggerSearch");
});
});
const pacmanConf = $("#pacman-conf"); const pacmanConf = $("#pacman-conf");
const pacmanConfCopyButton = $("#copy-btn"); const pacmanConfCopyButton = $("#copy-btn");
@ -103,6 +127,18 @@ SigLevel = Database{% if has_repo_signed %}Required{% else %}Never{% endif %} Pa
const conf = pacmanConf.text(); const conf = pacmanConf.text();
await copyToClipboard(conf, pacmanConfCopyButton); await copyToClipboard(conf, pacmanConfCopyButton);
} }
function filterListDepends() {
return extractDataList(table.bootstrapTable("getData"), "depends");
}
function filterListGroups() {
return extractDataList(table.bootstrapTable("getData"), "groups");
}
function filterListLicenses() {
return extractDataList(table.bootstrapTable("getData"), "licenses");
}
</script> </script>
</body> </body>

View File

@ -1,16 +1,21 @@
<script src="https://cdn.jsdelivr.net/npm/jquery/dist/jquery.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/jquery@3.7.0/dist/jquery.min.js" integrity="sha384-NXgwF8Kv9SSAr+jemKKcbvQsz+teULH/a5UNJvZc6kP47hZgl62M1vGnw6gHQhb1" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://unpkg.com/tableexport.jquery.plugin/tableExport.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/moment@2.29.4/moment.min.js" integrity="sha384-8hHkOkbWN1TLWwet/jpbJ0zbx3FJDeYJgQ8dX1mRrv/vfCfHCqFSFZYCgaMML3z9" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/daterangepicker@3.1.0/daterangepicker.min.js" integrity="sha384-u4eJN1VWrTf/FnYYQJo2kqJyVxEQf5UmWY4iUcNAoLenOEtEuCkfwc5bKvZOWBi5" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://unpkg.com/jquery-resizable-columns@0.2.3/dist/jquery.resizableColumns.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/tableexport.jquery.plugin@1.28.0/tableExport.min.js" integrity="sha384-1Rz4Kz/y1rSWw+ZsjTcxB684XgofbO8iizY+UFIzCwFeQ+QUyhBNWBMh/STOyomI" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.6/dist/umd/popper.min.js" integrity="sha384-oBqDVmMz9ATKxIep9tiCxS/Z9fNfEXiDAYTujMAeBAsjFuCZSmKbSSUnQlmh/jp3" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/jquery-resizable-columns@0.2.3/dist/jquery.resizableColumns.min.js" integrity="sha384-IazMVNyYoUNx6357fWJoqtHYUWWCNHIXxFVtbpVgvImQNWuRP2WbHPaIb3QF8j97" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.min.js" integrity="sha384-IDwe1+LCz02ROU9k972gdyvl+AESN10+x7tBKgc9I5HFtuNz0wWnPclzo6p9vxnk" crossorigin="anonymous"></script>
<script src="https://unpkg.com/bootstrap-table@1.21.1/dist/bootstrap-table.min.js"></script>
<script src="https://unpkg.com/bootstrap-table@1.21.1/dist/extensions/export/bootstrap-table-export.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js" integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.min.js" integrity="sha384-cuYeSxntonz0PPNlHhBs68uyIAVpIIOZZ5JqeqvYYIcEL727kskC66kF92t6Xl2V" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap-table@1.22.1/dist/bootstrap-table.min.js" integrity="sha384-GVLHfbEvuGA/RFiQ3MK2ClEJkWYJXABg55t9LpoDPZFGIsSq8xhFlQydm5poV2jW" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://unpkg.com/bootstrap-table@1.21.1/dist/extensions/resizable/bootstrap-table-resizable.js"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap-table@1.21.4/dist/extensions/export/bootstrap-table-export.min.js" integrity="sha384-jeldDadm+qM2RwGER3qVqxFgWVpAEJ7Jie+0rlYj8ni3KkQA654T8TSXDtol022X" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap-table@1.21.4/dist/extensions/resizable/bootstrap-table-resizable.js" integrity="sha384-wd8Vc6Febikdnsnk9vthRWRvMwffw246vhqiqNO3aSNe1maTEA07Vh3zAQiSyDji" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap-table@1.21.4/dist/extensions/filter-control/bootstrap-table-filter-control.js" integrity="sha384-B6xNXlSOaOFxjlKo9OW3htbox+9/DcaEcjPPEi1+pTMwH5Tzc/s2wNTYriHz7Tb8" crossorigin="anonymous" type="application/javascript"></script>
<script> <script>
async function copyToClipboard(text, button) { async function copyToClipboard(text, button) {
@ -38,4 +43,28 @@
.replace(/>/g, "&gt;") .replace(/>/g, "&gt;")
.replace(/"/g, "&quot;"); .replace(/"/g, "&quot;");
} }
function extractDataList(data, column) {
const elements = data.flatMap(row => row[column].split("<br>")).filter(v => v); // remove empty elements from array
return Array.from(new Set(elements)).sort();
}
function filterContains(text, value) {
return value.includes(text.toLowerCase().trim());
}
function filterDateRange(text, value) {
const asOfStartOfDay = date => date.setUTCHours(0, 0, 0, 0);
const [minDate, maxDate] = text.split(" - ");
const buildDate = asOfStartOfDay(new Date(value));
return (buildDate >= asOfStartOfDay(new Date(minDate))) && (buildDate <= asOfStartOfDay(new Date(maxDate)));
}
function filterList(index, value, field, data) {
const dataList = extractDataList(data, field);
// the library removes all symbols from string, so it is just string
return value.includes(dataList[index].toLowerCase());
}
</script> </script>

View File

@ -1,11 +1,15 @@
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous" type="text/css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous" type="text/css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.2/font/bootstrap-icons.css" type="text/css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.4/font/bootstrap-icons.css" integrity="sha384-LrVLJJYk9OiJmjNDakUBU7kS9qCT8wk1j2OU7ncpsfB3QS37UPdkCuq3ZD1MugNY" crossorigin="anonymous" type="text/css">
<link rel="stylesheet" href="https://unpkg.com/bootstrap-table@1.21.1/dist/bootstrap-table.min.css" type="text/css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-table@1.21.4/dist/bootstrap-table.min.css" integrity="sha384-pTEAhytv7JmEG2D7qiW5gY0lI5EKZ9n3CNmj6Qp+U3qhnmH2qnnN9KJbVwbtMHN0" crossorigin="anonymous" type="text/css">
<link rel="stylesheet" href="https://unpkg.com/jquery-resizable-columns@0.2.3/dist/jquery.resizableColumns.css" type="text/css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jquery-resizable-columns@0.2.3/dist/jquery.resizableColumns.css" integrity="sha384-1sLxvR8mXzjhvFY9f8mzXl97DNLepeZ0PnRiMMdm/rQsKjsrPZPJxYle2wwT2PMg" crossorigin="anonymous" type="text/css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootswatch@5.2.2/dist/cosmo/bootstrap.min.css" integrity="sha256-5t++JZpgVLzo9vF7snO5Qw0y3fA5/NkoJENWB7kpg0E=" crossorigin="anonymous" type="text/css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-table@1.21.4/dist/extensions/filter-control/bootstrap-table-filter-control.css" integrity="sha384-4Glx18jZ0Un+yDG6KUpYJ/af8hkssJ02jRASuFv23gfCl0mTXaVMPI9cB4cn3GvE" crossorigin="anonymous" type="text/css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootswatch@5.2.3/dist/cosmo/bootstrap.min.css" integrity="sha384-P1PBFVifKf1Ww0gS5B8A0siIeDpcFd4uU7S68LA1XMdE0R+y1WN3DR4HcLc9csRC" crossorigin="anonymous" type="text/css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/daterangepicker@3.1.0/daterangepicker.css" integrity="sha384-zLkQsiLfAQqGeIJeKLC+rcCR1YoYaQFLCL7cLDUoKE1ajKJzySpjzWGfYS2vjSG+" crossorigin="anonymous" type="text/css">
<style> <style>
.pre-scrollable { .pre-scrollable {

View File

@ -875,6 +875,8 @@ def _set_service_setup_parser(root: SubParserAction) -> argparse.ArgumentParser:
parser.add_argument("--build-command", help="build command prefix", default="ahriman") parser.add_argument("--build-command", help="build command prefix", default="ahriman")
parser.add_argument("--from-configuration", help="path to default devtools pacman configuration", parser.add_argument("--from-configuration", help="path to default devtools pacman configuration",
type=Path, default=Path("/usr") / "share" / "devtools" / "pacman.conf.d" / "extra.conf") type=Path, default=Path("/usr") / "share" / "devtools" / "pacman.conf.d" / "extra.conf")
parser.add_argument("--generate-salt", help="generate salt for user passwords",
action=argparse.BooleanOptionalAction, default=False)
parser.add_argument("--makeflags-jobs", help="append MAKEFLAGS variable with parallelism set to number of cores", parser.add_argument("--makeflags-jobs", help="append MAKEFLAGS variable with parallelism set to number of cores",
action=argparse.BooleanOptionalAction, default=True) action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--mirror", help="use the specified explicitly mirror instead of including mirrorlist") parser.add_argument("--mirror", help="use the specified explicitly mirror instead of including mirrorlist")
@ -923,8 +925,6 @@ def _set_user_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
parser = root.add_parser("user-add", help="create or update user", parser = root.add_parser("user-add", help="create or update user",
description="update user for web services with the given password and role. " description="update user for web services with the given password and role. "
"In case if password was not entered it will be asked interactively", "In case if password was not entered it will be asked interactively",
epilog="In case of first run (i.e. if password salt is not set yet) this action requires "
"root privileges because it performs write to filesystem configuration.",
formatter_class=_formatter) formatter_class=_formatter)
parser.add_argument("username", help="username for web service") parser.add_argument("username", help="username for web service")
parser.add_argument("--key", help="optional PGP key used by this user. The private key must be imported") parser.add_argument("--key", help="optional PGP key used by this user. The private key must be imported")
@ -934,7 +934,6 @@ def _set_user_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
"which is in particular must be used for OAuth2 authorization type.") "which is in particular must be used for OAuth2 authorization type.")
parser.add_argument("-r", "--role", help="user access level", parser.add_argument("-r", "--role", help="user access level",
type=UserAccess, choices=enum_values(UserAccess), default=UserAccess.Read) type=UserAccess, choices=enum_values(UserAccess), default=UserAccess.Read)
parser.add_argument("-s", "--secure", help="set file permissions to user-only", action="store_true")
parser.set_defaults(handler=handlers.Users, action=Action.Update, architecture=[""], lock=None, report=False, parser.set_defaults(handler=handlers.Users, action=Action.Update, architecture=[""], lock=None, report=False,
quiet=True) quiet=True)
return parser return parser

View File

@ -17,10 +17,12 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
from collections.abc import Iterable from collections.abc import Callable, Iterable
from ahriman.application.application.application_packages import ApplicationPackages from ahriman.application.application.application_packages import ApplicationPackages
from ahriman.application.application.application_repository import ApplicationRepository from ahriman.application.application.application_repository import ApplicationRepository
from ahriman.core.formatters import UpdatePrinter
from ahriman.core.tree import Tree
from ahriman.models.package import Package from ahriman.models.package import Package
from ahriman.models.result import Result from ahriman.models.result import Result
@ -37,12 +39,12 @@ class Application(ApplicationPackages, ApplicationRepository):
>>> from ahriman.models.package_source import PackageSource >>> from ahriman.models.package_source import PackageSource
>>> >>>
>>> configuration = Configuration() >>> configuration = Configuration()
>>> application = Application("x86_64", configuration, report=True, unsafe=False) >>> application = Application("x86_64", configuration, report=True)
>>> # add packages to build queue >>> # add packages to build queue
>>> application.add(["ahriman"], PackageSource.AUR) >>> application.add(["ahriman"], PackageSource.AUR)
>>> >>>
>>> # check for updates >>> # check for updates
>>> updates = application.updates([], aur=True, local=True, manual=True, vcs=True, log_fn=print) >>> updates = application.updates([], aur=True, local=True, manual=True, vcs=True)
>>> # updates for specified packages >>> # updates for specified packages
>>> application.update(updates) >>> application.update(updates)
@ -89,6 +91,22 @@ class Application(ApplicationPackages, ApplicationRepository):
""" """
self.repository.triggers.on_stop() self.repository.triggers.on_stop()
def print_updates(self, packages: list[Package], *, log_fn: Callable[[str], None]) -> None:
"""
print list of packages to be built. This method will build dependency tree and print updates accordingly
Args:
packages(list[Package]): package list to be printed
log_fn(Callable[[str], None]): logger function to log updates
"""
local_versions = {package.base: package.version for package in self.repository.packages()}
tree = Tree.resolve(packages)
for level in tree:
for package in level:
UpdatePrinter(package, local_versions.get(package.base)).print(
verbose=True, log_fn=log_fn, separator=" -> ")
def with_dependencies(self, packages: list[Package], *, process_dependencies: bool) -> list[Package]: def with_dependencies(self, packages: list[Package], *, process_dependencies: bool) -> list[Package]:
""" """
add missing dependencies to list of packages add missing dependencies to list of packages
@ -126,5 +144,8 @@ class Application(ApplicationPackages, ApplicationRepository):
for package_name, username in missing.items(): for package_name, username in missing.items():
package = Package.from_aur(package_name, self.repository.pacman, username) package = Package.from_aur(package_name, self.repository.pacman, username)
with_dependencies[package.base] = package with_dependencies[package.base] = package
# register package in local database
self.database.remote_update(package)
self.repository.reporter.set_unknown(package)
return list(with_dependencies.values()) return list(with_dependencies.values())

View File

@ -35,7 +35,7 @@ class ApplicationProperties(LazyLogging):
repository(Repository): repository instance repository(Repository): repository instance
""" """
def __init__(self, architecture: str, configuration: Configuration, *, report: bool, unsafe: bool, def __init__(self, architecture: str, configuration: Configuration, *, report: bool,
refresh_pacman_database: PacmanSynchronization = PacmanSynchronization.Disabled) -> None: refresh_pacman_database: PacmanSynchronization = PacmanSynchronization.Disabled) -> None:
""" """
default constructor default constructor
@ -44,12 +44,11 @@ class ApplicationProperties(LazyLogging):
architecture(str): repository architecture architecture(str): repository architecture
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
refresh_pacman_database(PacmanSynchronization, optional): pacman database synchronization level refresh_pacman_database(PacmanSynchronization, optional): pacman database synchronization level
(Default value = PacmanSynchronization.Disabled) (Default value = PacmanSynchronization.Disabled)
""" """
self.configuration = configuration self.configuration = configuration
self.architecture = architecture self.architecture = architecture
self.database = SQLite.load(configuration) self.database = SQLite.load(configuration)
self.repository = Repository.load(architecture, configuration, self.database, report=report, unsafe=unsafe, self.repository = Repository.load(architecture, configuration, self.database, report=report,
refresh_pacman_database=refresh_pacman_database) refresh_pacman_database=refresh_pacman_database)

View File

@ -17,12 +17,11 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
from collections.abc import Callable, Iterable from collections.abc import Iterable
from pathlib import Path from pathlib import Path
from ahriman.application.application.application_properties import ApplicationProperties from ahriman.application.application.application_properties import ApplicationProperties
from ahriman.core.build_tools.sources import Sources from ahriman.core.build_tools.sources import Sources
from ahriman.core.formatters import UpdatePrinter
from ahriman.core.tree import Tree from ahriman.core.tree import Tree
from ahriman.models.package import Package from ahriman.models.package import Package
from ahriman.models.packagers import Packagers from ahriman.models.packagers import Packagers
@ -158,7 +157,7 @@ class ApplicationRepository(ApplicationProperties):
return build_result return build_result
def updates(self, filter_packages: Iterable[str], *, def updates(self, filter_packages: Iterable[str], *,
aur: bool, local: bool, manual: bool, vcs: bool, log_fn: Callable[[str], None]) -> list[Package]: aur: bool, local: bool, manual: bool, vcs: bool) -> list[Package]:
""" """
get list of packages to run update process get list of packages to run update process
@ -168,7 +167,6 @@ class ApplicationRepository(ApplicationProperties):
local(bool): enable or disable checking of local packages for updates local(bool): enable or disable checking of local packages for updates
manual(bool): include or exclude manual updates manual(bool): include or exclude manual updates
vcs(bool): enable or disable checking of VCS packages vcs(bool): enable or disable checking of VCS packages
log_fn(Callable[[str], None]): logger function to log updates
Returns: Returns:
list[Package]: list of out-of-dated packages list[Package]: list of out-of-dated packages
@ -182,14 +180,4 @@ class ApplicationRepository(ApplicationProperties):
if manual: if manual:
updates.update({package.base: package for package in self.repository.updates_manual()}) updates.update({package.base: package for package in self.repository.updates_manual()})
local_versions = {package.base: package.version for package in self.repository.packages()} return [package for _, package in sorted(updates.items())]
updated_packages = [package for _, package in sorted(updates.items())]
# reorder updates according to the dependency tree
tree = Tree.resolve(updated_packages)
for level in tree:
for package in level:
UpdatePrinter(package, local_versions.get(package.base)).print(
verbose=True, log_fn=log_fn, separator=" -> ")
return updated_packages

View File

@ -31,8 +31,7 @@ class Add(Handler):
""" """
@classmethod @classmethod
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
report: bool, unsafe: bool) -> None:
""" """
callback for command line callback for command line
@ -41,19 +40,17 @@ class Add(Handler):
architecture(str): repository architecture architecture(str): repository architecture
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
""" """
application = Application(architecture, configuration, application = Application(architecture, configuration, report=report, refresh_pacman_database=args.refresh)
report=report, unsafe=unsafe, refresh_pacman_database=args.refresh)
application.on_start() application.on_start()
application.add(args.package, args.source, args.username) application.add(args.package, args.source, args.username)
if not args.now: if not args.now:
return return
packages = application.updates(args.package, aur=False, local=False, manual=True, vcs=False, packages = application.updates(args.package, aur=False, local=False, manual=True, vcs=False)
log_fn=application.logger.info)
packages = application.with_dependencies(packages, process_dependencies=args.dependencies) packages = application.with_dependencies(packages, process_dependencies=args.dependencies)
packagers = Packagers(args.username, {package.base: package.packager for package in packages}) packagers = Packagers(args.username, {package.base: package.packager for package in packages})
application.print_updates(packages, log_fn=application.logger.info)
result = application.update(packages, packagers) result = application.update(packages, packagers)
Add.check_if_empty(args.exit_code, result.is_empty) Add.check_if_empty(args.exit_code, result.is_empty)

View File

@ -36,8 +36,7 @@ class Backup(Handler):
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture" ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
@classmethod @classmethod
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
report: bool, unsafe: bool) -> None:
""" """
callback for command line callback for command line
@ -46,7 +45,6 @@ class Backup(Handler):
architecture(str): repository architecture architecture(str): repository architecture
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
""" """
backup_paths = Backup.get_paths(configuration) backup_paths = Backup.get_paths(configuration)
with TarFile(args.path, mode="w") as archive: # well we don't actually use compression with TarFile(args.path, mode="w") as archive: # well we don't actually use compression

View File

@ -30,8 +30,7 @@ class Clean(Handler):
""" """
@classmethod @classmethod
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
report: bool, unsafe: bool) -> None:
""" """
callback for command line callback for command line
@ -40,9 +39,8 @@ class Clean(Handler):
architecture(str): repository architecture architecture(str): repository architecture
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
""" """
application = Application(architecture, configuration, report=report, unsafe=unsafe) application = Application(architecture, configuration, report=report)
application.on_start() application.on_start()
application.clean(cache=args.cache, chroot=args.chroot, manual=args.manual, packages=args.packages, application.clean(cache=args.cache, chroot=args.chroot, manual=args.manual, packages=args.packages,
pacman=args.pacman) pacman=args.pacman)

View File

@ -30,8 +30,7 @@ class Daemon(Handler):
""" """
@classmethod @classmethod
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
report: bool, unsafe: bool) -> None:
""" """
callback for command line callback for command line
@ -40,11 +39,10 @@ class Daemon(Handler):
architecture(str): repository architecture architecture(str): repository architecture
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
""" """
from ahriman.application.handlers import Update from ahriman.application.handlers import Update
Update.run(args, architecture, configuration, report=report, unsafe=unsafe) Update.run(args, architecture, configuration, report=report)
timer = threading.Timer(args.interval, Daemon.run, args=[args, architecture, configuration], timer = threading.Timer(args.interval, Daemon.run, args=[args, architecture, configuration],
kwargs={"report": report, "unsafe": unsafe}) kwargs={"report": report})
timer.start() timer.start()
timer.join() timer.join()

View File

@ -21,7 +21,7 @@ import argparse
from ahriman.application.handlers import Handler from ahriman.application.handlers import Handler
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.formatters import ConfigurationPrinter from ahriman.core.formatters import ConfigurationPathsPrinter, ConfigurationPrinter, StringPrinter
class Dump(Handler): class Dump(Handler):
@ -32,8 +32,7 @@ class Dump(Handler):
ALLOW_AUTO_ARCHITECTURE_RUN = False ALLOW_AUTO_ARCHITECTURE_RUN = False
@classmethod @classmethod
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
report: bool, unsafe: bool) -> None:
""" """
callback for command line callback for command line
@ -42,8 +41,13 @@ class Dump(Handler):
architecture(str): repository architecture architecture(str): repository architecture
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
""" """
root, _ = configuration.check_loaded()
ConfigurationPathsPrinter(root, configuration.includes).print(verbose=True, separator=" = ")
# empty line
StringPrinter("").print(verbose=False)
dump = configuration.dump() dump = configuration.dump()
for section, values in sorted(dump.items()): for section, values in sorted(dump.items()):
ConfigurationPrinter(section, values).print(verbose=not args.secure, separator=" = ") ConfigurationPrinter(section, values).print(verbose=not args.secure, separator=" = ")

View File

@ -97,7 +97,7 @@ class Handler:
log_handler = Log.handler(args.log_handler) log_handler = Log.handler(args.log_handler)
Log.load(configuration, log_handler, quiet=args.quiet, report=args.report) Log.load(configuration, log_handler, quiet=args.quiet, report=args.report)
with Lock(args, architecture, configuration): with Lock(args, architecture, configuration):
cls.run(args, architecture, configuration, report=args.report, unsafe=args.unsafe) cls.run(args, architecture, configuration, report=args.report)
return True return True
except ExitCode: except ExitCode:
return False return False
@ -136,8 +136,7 @@ class Handler:
return 0 if all(result) else 1 return 0 if all(result) else 1
@classmethod @classmethod
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
report: bool, unsafe: bool) -> None:
""" """
callback for command line callback for command line
@ -146,7 +145,6 @@ class Handler:
architecture(str): repository architecture architecture(str): repository architecture
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
Raises: Raises:
NotImplementedError: not implemented method NotImplementedError: not implemented method

View File

@ -31,8 +31,7 @@ class Help(Handler):
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture" ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
@classmethod @classmethod
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
report: bool, unsafe: bool) -> None:
""" """
callback for command line callback for command line
@ -41,7 +40,6 @@ class Help(Handler):
architecture(str): repository architecture architecture(str): repository architecture
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
""" """
parser: argparse.ArgumentParser = args.parser() parser: argparse.ArgumentParser = args.parser()
if args.command is None: if args.command is None:

View File

@ -32,8 +32,7 @@ class KeyImport(Handler):
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture" ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
@classmethod @classmethod
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
report: bool, unsafe: bool) -> None:
""" """
callback for command line callback for command line
@ -42,7 +41,6 @@ class KeyImport(Handler):
architecture(str): repository architecture architecture(str): repository architecture
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
""" """
application = Application(architecture, configuration, report=report, unsafe=unsafe) application = Application(architecture, configuration, report=report)
application.repository.sign.key_import(args.key_server, args.key) application.repository.sign.key_import(args.key_server, args.key)

View File

@ -38,8 +38,7 @@ class Patch(Handler):
""" """
@classmethod @classmethod
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
report: bool, unsafe: bool) -> None:
""" """
callback for command line callback for command line
@ -48,9 +47,8 @@ class Patch(Handler):
architecture(str): repository architecture architecture(str): repository architecture
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
""" """
application = Application(architecture, configuration, report=report, unsafe=unsafe) application = Application(architecture, configuration, report=report)
application.on_start() application.on_start()
if args.action == Action.Update and args.variable is not None: if args.action == Action.Update and args.variable is not None:

View File

@ -22,7 +22,6 @@ import argparse
from ahriman.application.application import Application from ahriman.application.application import Application
from ahriman.application.handlers import Handler from ahriman.application.handlers import Handler
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.formatters import UpdatePrinter
from ahriman.models.build_status import BuildStatusEnum from ahriman.models.build_status import BuildStatusEnum
from ahriman.models.package import Package from ahriman.models.package import Package
@ -33,8 +32,7 @@ class Rebuild(Handler):
""" """
@classmethod @classmethod
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
report: bool, unsafe: bool) -> None:
""" """
callback for command line callback for command line
@ -43,9 +41,8 @@ class Rebuild(Handler):
architecture(str): repository architecture architecture(str): repository architecture
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
""" """
application = Application(architecture, configuration, report=report, unsafe=unsafe) application = Application(architecture, configuration, report=report)
application.on_start() application.on_start()
packages = Rebuild.extract_packages(application, args.status, from_database=args.from_database) packages = Rebuild.extract_packages(application, args.status, from_database=args.from_database)
@ -53,8 +50,7 @@ class Rebuild(Handler):
Rebuild.check_if_empty(args.exit_code, not updates) Rebuild.check_if_empty(args.exit_code, not updates)
if args.dry_run: if args.dry_run:
for package in updates: application.print_updates(updates, log_fn=print)
UpdatePrinter(package, package.version).print(verbose=True)
return return
result = application.update(updates, args.username) result = application.update(updates, args.username)

View File

@ -30,8 +30,7 @@ class Remove(Handler):
""" """
@classmethod @classmethod
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
report: bool, unsafe: bool) -> None:
""" """
callback for command line callback for command line
@ -40,8 +39,7 @@ class Remove(Handler):
architecture(str): repository architecture architecture(str): repository architecture
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
""" """
application = Application(architecture, configuration, report=report, unsafe=unsafe) application = Application(architecture, configuration, report=report)
application.on_start() application.on_start()
application.remove(args.package) application.remove(args.package)

View File

@ -31,8 +31,7 @@ class RemoveUnknown(Handler):
""" """
@classmethod @classmethod
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
report: bool, unsafe: bool) -> None:
""" """
callback for command line callback for command line
@ -41,9 +40,8 @@ class RemoveUnknown(Handler):
architecture(str): repository architecture architecture(str): repository architecture
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
""" """
application = Application(architecture, configuration, report=report, unsafe=unsafe) application = Application(architecture, configuration, report=report)
application.on_start() application.on_start()
unknown_packages = application.unknown() unknown_packages = application.unknown()

View File

@ -33,8 +33,7 @@ class Restore(Handler):
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture" ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
@classmethod @classmethod
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
report: bool, unsafe: bool) -> None:
""" """
callback for command line callback for command line
@ -43,7 +42,6 @@ class Restore(Handler):
architecture(str): repository architecture architecture(str): repository architecture
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
""" """
with TarFile(args.path) as archive: with TarFile(args.path) as archive:
archive.extractall(path=args.output) archive.extractall(path=args.output)

View File

@ -47,8 +47,7 @@ class Search(Handler):
} }
@classmethod @classmethod
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
report: bool, unsafe: bool) -> None:
""" """
callback for command line callback for command line
@ -57,9 +56,8 @@ class Search(Handler):
architecture(str): repository architecture architecture(str): repository architecture
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
""" """
application = Application(architecture, configuration, report=report, unsafe=unsafe) application = Application(architecture, configuration, report=report)
official_packages_list = Official.multisearch(*args.search, pacman=application.repository.pacman) official_packages_list = Official.multisearch(*args.search, pacman=application.repository.pacman)
aur_packages_list = AUR.multisearch(*args.search, pacman=application.repository.pacman) aur_packages_list = AUR.multisearch(*args.search, pacman=application.repository.pacman)

View File

@ -35,8 +35,7 @@ class ServiceUpdates(Handler):
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture" ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
@classmethod @classmethod
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
report: bool, unsafe: bool) -> None:
""" """
callback for command line callback for command line
@ -45,9 +44,8 @@ class ServiceUpdates(Handler):
architecture(str): repository architecture architecture(str): repository architecture
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
""" """
application = Application(architecture, configuration, report=report, unsafe=unsafe) application = Application(architecture, configuration, report=report)
remote = Package.from_aur("ahriman", application.repository.pacman, None) remote = Package.from_aur("ahriman", application.repository.pacman, None)
release = remote.version.rsplit("-", 1)[-1] # we don't store pkgrel locally, so we just append it release = remote.version.rsplit("-", 1)[-1] # we don't store pkgrel locally, so we just append it

View File

@ -26,6 +26,7 @@ from ahriman.application.application import Application
from ahriman.application.handlers import Handler from ahriman.application.handlers import Handler
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.models.repository_paths import RepositoryPaths from ahriman.models.repository_paths import RepositoryPaths
from ahriman.models.user import User
class Setup(Handler): class Setup(Handler):
@ -45,8 +46,7 @@ class Setup(Handler):
SUDOERS_DIR_PATH = Path("/etc") / "sudoers.d" SUDOERS_DIR_PATH = Path("/etc") / "sudoers.d"
@classmethod @classmethod
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
report: bool, unsafe: bool) -> None:
""" """
callback for command line callback for command line
@ -55,12 +55,11 @@ class Setup(Handler):
architecture(str): repository architecture architecture(str): repository architecture
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
""" """
Setup.configuration_create_ahriman(args, architecture, args.repository, configuration) Setup.configuration_create_ahriman(args, architecture, args.repository, configuration)
configuration.reload() configuration.reload()
application = Application(architecture, configuration, report=report, unsafe=unsafe) application = Application(architecture, configuration, report=report)
Setup.configuration_create_makepkg(args.packager, args.makeflags_jobs, application.repository.paths) Setup.configuration_create_makepkg(args.packager, args.makeflags_jobs, application.repository.paths)
Setup.executable_create(application.repository.paths, args.build_command, architecture) Setup.executable_create(application.repository.paths, args.build_command, architecture)
@ -126,6 +125,9 @@ class Setup(Handler):
if args.web_unix_socket is not None: if args.web_unix_socket is not None:
configuration.set_option(section, "unix_socket", str(args.web_unix_socket)) configuration.set_option(section, "unix_socket", str(args.web_unix_socket))
if args.generate_salt:
configuration.set_option("auth", "salt", User.generate_password(20))
target = root.include / "00-setup-overrides.ini" target = root.include / "00-setup-overrides.ini"
with target.open("w") as ahriman_configuration: with target.open("w") as ahriman_configuration:
configuration.write(ahriman_configuration) configuration.write(ahriman_configuration)

View File

@ -37,8 +37,7 @@ class Shell(Handler):
ALLOW_MULTI_ARCHITECTURE_RUN = False ALLOW_MULTI_ARCHITECTURE_RUN = False
@classmethod @classmethod
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
report: bool, unsafe: bool) -> None:
""" """
callback for command line callback for command line
@ -47,10 +46,9 @@ class Shell(Handler):
architecture(str): repository architecture architecture(str): repository architecture
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
""" """
# pylint: disable=possibly-unused-variable # pylint: disable=possibly-unused-variable
application = Application(architecture, configuration, report=report, unsafe=unsafe) application = Application(architecture, configuration, report=report)
if args.verbose: if args.verbose:
# licensed by https://creativecommons.org/licenses/by-sa/3.0 # licensed by https://creativecommons.org/licenses/by-sa/3.0
path = Path(sys.prefix) / "share" / "ahriman" / "templates" / "shell" path = Path(sys.prefix) / "share" / "ahriman" / "templates" / "shell"

View File

@ -30,8 +30,7 @@ class Sign(Handler):
""" """
@classmethod @classmethod
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
report: bool, unsafe: bool) -> None:
""" """
callback for command line callback for command line
@ -40,6 +39,5 @@ class Sign(Handler):
architecture(str): repository architecture architecture(str): repository architecture
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
""" """
Application(architecture, configuration, report=report, unsafe=unsafe).sign(args.package) Application(architecture, configuration, report=report).sign(args.package)

View File

@ -37,8 +37,7 @@ class Status(Handler):
ALLOW_AUTO_ARCHITECTURE_RUN = False ALLOW_AUTO_ARCHITECTURE_RUN = False
@classmethod @classmethod
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
report: bool, unsafe: bool) -> None:
""" """
callback for command line callback for command line
@ -47,10 +46,9 @@ class Status(Handler):
architecture(str): repository architecture architecture(str): repository architecture
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
""" """
# we are using reporter here # we are using reporter here
client = Application(architecture, configuration, report=True, unsafe=unsafe).repository.reporter client = Application(architecture, configuration, report=True).repository.reporter
if args.ahriman: if args.ahriman:
service_status = client.get_internal() service_status = client.get_internal()
StatusPrinter(service_status.status).print(verbose=args.info) StatusPrinter(service_status.status).print(verbose=args.info)

View File

@ -33,8 +33,7 @@ class StatusUpdate(Handler):
ALLOW_AUTO_ARCHITECTURE_RUN = False ALLOW_AUTO_ARCHITECTURE_RUN = False
@classmethod @classmethod
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
report: bool, unsafe: bool) -> None:
""" """
callback for command line callback for command line
@ -43,10 +42,9 @@ class StatusUpdate(Handler):
architecture(str): repository architecture architecture(str): repository architecture
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
""" """
# we are using reporter here # we are using reporter here
client = Application(architecture, configuration, report=True, unsafe=unsafe).repository.reporter client = Application(architecture, configuration, report=True).repository.reporter
if args.action == Action.Update and args.package: if args.action == Action.Update and args.package:
# update packages statuses # update packages statuses

View File

@ -34,8 +34,7 @@ class Structure(Handler):
ALLOW_AUTO_ARCHITECTURE_RUN = False ALLOW_AUTO_ARCHITECTURE_RUN = False
@classmethod @classmethod
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
report: bool, unsafe: bool) -> None:
""" """
callback for command line callback for command line
@ -44,9 +43,8 @@ class Structure(Handler):
architecture(str): repository architecture architecture(str): repository architecture
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
""" """
application = Application(architecture, configuration, report=report, unsafe=unsafe) application = Application(architecture, configuration, report=report)
packages = application.repository.packages() packages = application.repository.packages()
tree = Tree.resolve(packages) tree = Tree.resolve(packages)

View File

@ -31,8 +31,7 @@ class Triggers(Handler):
""" """
@classmethod @classmethod
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
report: bool, unsafe: bool) -> None:
""" """
callback for command line callback for command line
@ -41,9 +40,8 @@ class Triggers(Handler):
architecture(str): repository architecture architecture(str): repository architecture
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
""" """
application = Application(architecture, configuration, report=report, unsafe=unsafe) application = Application(architecture, configuration, report=report)
if args.trigger: if args.trigger:
loader = application.repository.triggers loader = application.repository.triggers
loader.triggers = [loader.load_trigger(trigger, architecture, configuration) for trigger in args.trigger] loader.triggers = [loader.load_trigger(trigger, architecture, configuration) for trigger in args.trigger]

View File

@ -32,8 +32,7 @@ class UnsafeCommands(Handler):
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture" ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
@classmethod @classmethod
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
report: bool, unsafe: bool) -> None:
""" """
callback for command line callback for command line
@ -42,7 +41,6 @@ class UnsafeCommands(Handler):
architecture(str): repository architecture architecture(str): repository architecture
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
""" """
parser = args.parser() parser = args.parser()
unsafe_commands = UnsafeCommands.get_unsafe_commands(parser) unsafe_commands = UnsafeCommands.get_unsafe_commands(parser)

View File

@ -33,8 +33,7 @@ class Update(Handler):
""" """
@classmethod @classmethod
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
report: bool, unsafe: bool) -> None:
""" """
callback for command line callback for command line
@ -43,13 +42,10 @@ class Update(Handler):
architecture(str): repository architecture architecture(str): repository architecture
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
""" """
application = Application(architecture, configuration, report=report, unsafe=unsafe, application = Application(architecture, configuration, report=report, refresh_pacman_database=args.refresh)
refresh_pacman_database=args.refresh)
application.on_start() application.on_start()
packages = application.updates(args.package, aur=args.aur, local=args.local, manual=args.manual, vcs=args.vcs, packages = application.updates(args.package, aur=args.aur, local=args.local, manual=args.manual, vcs=args.vcs)
log_fn=Update.log_fn(application, args.dry_run))
Update.check_if_empty(args.exit_code, not packages) Update.check_if_empty(args.exit_code, not packages)
if args.dry_run: if args.dry_run:
return return
@ -57,6 +53,7 @@ class Update(Handler):
packages = application.with_dependencies(packages, process_dependencies=args.dependencies) packages = application.with_dependencies(packages, process_dependencies=args.dependencies)
packagers = Packagers(args.username, {package.base: package.packager for package in packages}) packagers = Packagers(args.username, {package.base: package.packager for package in packages})
application.print_updates(packages, log_fn=application.logger.info)
result = application.update(packages, packagers) result = application.update(packages, packagers)
Update.check_if_empty(args.exit_code, result.is_empty) Update.check_if_empty(args.exit_code, result.is_empty)

View File

@ -20,8 +20,6 @@
import argparse import argparse
import getpass import getpass
from pathlib import Path
from ahriman.application.handlers import Handler from ahriman.application.handlers import Handler
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.database import SQLite from ahriman.core.database import SQLite
@ -39,8 +37,7 @@ class Users(Handler):
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture" ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
@classmethod @classmethod
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
report: bool, unsafe: bool) -> None:
""" """
callback for command line callback for command line
@ -49,18 +46,13 @@ class Users(Handler):
architecture(str): repository architecture architecture(str): repository architecture
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
""" """
database = SQLite.load(configuration) database = SQLite.load(configuration)
if args.action == Action.Update: if args.action == Action.Update:
old_salt, salt = Users.get_salt(configuration)
user = Users.user_create(args) user = Users.user_create(args)
# if password is left blank we are not going to require salt to be set
if old_salt is None: salt = configuration.get("auth", "salt") if user.password else ""
auth_configuration = Users.configuration_get(configuration.include)
Users.configuration_create(auth_configuration, salt, args.secure)
database.user_update(user.hash_password(salt)) database.user_update(user.hash_password(salt))
elif args.action == Action.List: elif args.action == Action.List:
users = database.user_list(args.username, args.role) users = database.user_list(args.username, args.role)
@ -70,70 +62,6 @@ class Users(Handler):
elif args.action == Action.Remove: elif args.action == Action.Remove:
database.user_remove(args.username) database.user_remove(args.username)
@staticmethod
def configuration_create(configuration: Configuration, salt: str, secure: bool) -> None:
"""
enable configuration if it has been disabled
Args:
configuration(Configuration): configuration instance
salt(str): password hash salt
secure(bool): if true then set file permissions to 0o600
"""
configuration.set_option("auth", "salt", salt)
Users.configuration_write(configuration, secure)
@staticmethod
def configuration_get(include_path: Path) -> Configuration:
"""
create configuration instance
Args:
include_path(Path): path to directory with configuration includes
Returns:
Configuration: configuration instance. In case if there are local settings they will be loaded
"""
target = include_path / "00-auth.ini"
configuration = Configuration()
configuration.load(target)
configuration.architecture = "" # not user anyway
return configuration
@staticmethod
def configuration_write(configuration: Configuration, secure: bool) -> None:
"""
write configuration file
Args:
configuration(Configuration): configuration instance
secure(bool): if true then set file permissions to 0o600
"""
path, _ = configuration.check_loaded()
with path.open("w") as ahriman_configuration:
configuration.write(ahriman_configuration)
if secure:
path.chmod(0o600)
@staticmethod
def get_salt(configuration: Configuration, salt_length: int = 20) -> tuple[str | None, str]:
"""
get salt from configuration or create new string
Args:
configuration(Configuration): configuration instance
salt_length(int, optional): salt length (Default value = 20)
Returns:
tuple[str | None, str]: tuple containing salt from configuration if any and actual salt which must be
used for password hash
"""
if salt := configuration.get("auth", "salt", fallback=None):
return salt, salt
return None, User.generate_password(salt_length)
@staticmethod @staticmethod
def user_create(args: argparse.Namespace) -> User: def user_create(args: argparse.Namespace) -> User:
""" """

View File

@ -39,8 +39,7 @@ class Validate(Handler):
ALLOW_AUTO_ARCHITECTURE_RUN = False ALLOW_AUTO_ARCHITECTURE_RUN = False
@classmethod @classmethod
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
report: bool, unsafe: bool) -> None:
""" """
callback for command line callback for command line
@ -49,7 +48,6 @@ class Validate(Handler):
architecture(str): repository architecture architecture(str): repository architecture
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
""" """
schema = Validate.schema(architecture, configuration) schema = Validate.schema(architecture, configuration)
validator = Validator(configuration=configuration, schema=schema) validator = Validator(configuration=configuration, schema=schema)

View File

@ -42,8 +42,7 @@ class Versions(Handler):
PEP423_PACKAGE_NAME = re.compile(r"^[A-Za-z0-9._-]+") PEP423_PACKAGE_NAME = re.compile(r"^[A-Za-z0-9._-]+")
@classmethod @classmethod
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
report: bool, unsafe: bool) -> None:
""" """
callback for command line callback for command line
@ -52,7 +51,6 @@ class Versions(Handler):
architecture(str): repository architecture architecture(str): repository architecture
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
""" """
VersionPrinter(f"Module version {version.__version__}", VersionPrinter(f"Module version {version.__version__}",
{"Python": sys.version}).print(verbose=False, separator=" ") {"Python": sys.version}).print(verbose=False, separator=" ")

View File

@ -36,8 +36,7 @@ class Web(Handler):
COMMAND_ARGS_WHITELIST = ["force", "log_handler", ""] COMMAND_ARGS_WHITELIST = ["force", "log_handler", ""]
@classmethod @classmethod
def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *, report: bool) -> None:
report: bool, unsafe: bool) -> None:
""" """
callback for command line callback for command line
@ -46,7 +45,6 @@ class Web(Handler):
architecture(str): repository architecture architecture(str): repository architecture
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
""" """
# we are using local import for optional dependencies # we are using local import for optional dependencies
from ahriman.web.web import run_server, setup_service from ahriman.web.web import run_server, setup_service

View File

@ -86,6 +86,7 @@ class Lock(LazyLogging):
check if current user is actually owner of ahriman root check if current user is actually owner of ahriman root
""" """
check_user(self.paths, unsafe=self.unsafe) check_user(self.paths, unsafe=self.unsafe)
self.paths.tree_create()
def clear(self) -> None: def clear(self) -> None:
""" """
@ -116,7 +117,7 @@ class Lock(LazyLogging):
1. Check user UID 1. Check user UID
2. Check if there is lock file 2. Check if there is lock file
3. Check web status watcher status 3. Check web status watcher status
4. Create lock file 4. Create lock file and directory tree
5. Report to status page if enabled 5. Report to status page if enabled
Returns: Returns:

View File

@ -115,7 +115,11 @@ class AUR(Remote):
query[key] = value query[key] = value
try: try:
response = requests.get(self.DEFAULT_RPC_URL, params=query, timeout=self.DEFAULT_TIMEOUT) response = requests.get(
self.DEFAULT_RPC_URL,
params=query,
headers={"User-Agent": self.DEFAULT_USER_AGENT},
timeout=self.DEFAULT_TIMEOUT)
response.raise_for_status() response.raise_for_status()
return self.parse_response(response.json()) return self.parse_response(response.json())
except requests.HTTPError as e: except requests.HTTPError as e:

View File

@ -106,6 +106,7 @@ class Official(Remote):
response = requests.get( response = requests.get(
self.DEFAULT_RPC_URL, self.DEFAULT_RPC_URL,
params={by: args, "repo": self.DEFAULT_SEARCH_REPOSITORIES}, params={by: args, "repo": self.DEFAULT_SEARCH_REPOSITORIES},
headers={"User-Agent": self.DEFAULT_USER_AGENT},
timeout=self.DEFAULT_TIMEOUT) timeout=self.DEFAULT_TIMEOUT)
response.raise_for_status() response.raise_for_status()
return self.parse_response(response.json()) return self.parse_response(response.json())

View File

@ -17,6 +17,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
from ahriman import version
from ahriman.core.alpm.pacman import Pacman from ahriman.core.alpm.pacman import Pacman
from ahriman.core.log import LazyLogging from ahriman.core.log import LazyLogging
from ahriman.models.aur_package import AURPackage from ahriman.models.aur_package import AURPackage
@ -26,6 +27,9 @@ class Remote(LazyLogging):
""" """
base class for remote package search base class for remote package search
Attributes:
DEFAULT_USER_AGENT(str): (class attribute) default user agent
Examples: Examples:
These classes are designed to be used without instancing. In order to achieve it several class methods are These classes are designed to be used without instancing. In order to achieve it several class methods are
provided: ``info``, ``multisearch`` and ``search``. Thus, the basic flow is the following:: provided: ``info``, ``multisearch`` and ``search``. Thus, the basic flow is the following::
@ -39,6 +43,8 @@ class Remote(LazyLogging):
directly, whereas ``multisearch`` splits search one by one and finds intersection between search results. directly, whereas ``multisearch`` splits search one by one and finds intersection between search results.
""" """
DEFAULT_USER_AGENT = f"ahriman/{version.__version__}"
@classmethod @classmethod
def info(cls, package_name: str, *, pacman: Pacman) -> AURPackage: def info(cls, package_name: str, *, pacman: Pacman) -> AURPackage:
""" """

View File

@ -38,6 +38,7 @@ class Configuration(configparser.RawConfigParser):
Required by dump and merging functions Required by dump and merging functions
SYSTEM_CONFIGURATION_PATH(Path): (class attribute) default system configuration path distributed by package SYSTEM_CONFIGURATION_PATH(Path): (class attribute) default system configuration path distributed by package
architecture(str | None): repository architecture architecture(str | None): repository architecture
includes(list[Path]): list of includes which were read
path(Path | None): path to root configuration file path(Path | None): path to root configuration file
Examples: Examples:
@ -78,6 +79,7 @@ class Configuration(configparser.RawConfigParser):
}) })
self.architecture: str | None = None self.architecture: str | None = None
self.path: Path | None = None self.path: Path | None = None
self.includes: list[Path] = []
@property @property
def include(self) -> Path: def include(self) -> Path:
@ -193,7 +195,7 @@ class Configuration(configparser.RawConfigParser):
} }
# pylint and mypy are too stupid to find these methods # pylint and mypy are too stupid to find these methods
# pylint: disable=missing-function-docstring,multiple-statements,unused-argument # pylint: disable=missing-function-docstring,unused-argument
def getlist(self, *args: Any, **kwargs: Any) -> list[str]: ... # type: ignore[empty-body] def getlist(self, *args: Any, **kwargs: Any) -> list[str]: ... # type: ignore[empty-body]
def getpath(self, *args: Any, **kwargs: Any) -> Path: ... # type: ignore[empty-body] def getpath(self, *args: Any, **kwargs: Any) -> Path: ... # type: ignore[empty-body]
@ -243,11 +245,13 @@ class Configuration(configparser.RawConfigParser):
""" """
load configuration includes load configuration includes
""" """
self.includes = [] # reset state
try: try:
for path in sorted(self.include.glob("*.ini")): for path in sorted(self.include.glob("*.ini")):
if path == self.logging_path: if path == self.logging_path:
continue # we don't want to load logging explicitly continue # we don't want to load logging explicitly
self.read(path) self.read(path)
self.includes.append(path)
except (FileNotFoundError, configparser.NoOptionError, configparser.NoSectionError): except (FileNotFoundError, configparser.NoOptionError, configparser.NoSectionError):
pass pass

View File

@ -22,6 +22,7 @@ from ahriman.core.formatters.string_printer import StringPrinter
from ahriman.core.formatters.aur_printer import AurPrinter from ahriman.core.formatters.aur_printer import AurPrinter
from ahriman.core.formatters.build_printer import BuildPrinter from ahriman.core.formatters.build_printer import BuildPrinter
from ahriman.core.formatters.configuration_paths_printer import ConfigurationPathsPrinter
from ahriman.core.formatters.configuration_printer import ConfigurationPrinter from ahriman.core.formatters.configuration_printer import ConfigurationPrinter
from ahriman.core.formatters.package_printer import PackagePrinter from ahriman.core.formatters.package_printer import PackagePrinter
from ahriman.core.formatters.patch_printer import PatchPrinter from ahriman.core.formatters.patch_printer import PatchPrinter

View File

@ -0,0 +1,52 @@
#
# Copyright (c) 2021-2023 ahriman team.
#
# This file is part of ahriman
# (see https://github.com/arcan1s/ahriman).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from pathlib import Path
from ahriman.core.formatters import StringPrinter
from ahriman.models.property import Property
class ConfigurationPathsPrinter(StringPrinter):
"""
print configuration paths
Attributes:
includes(list[Path]): list of include files
"""
def __init__(self, root: Path, includes: list[Path]) -> None:
"""
default constructor
Args:
root(Path): path to root configuration file
includes(list[Path]): list of include files
"""
StringPrinter.__init__(self, str(root))
self.includes = includes
def properties(self) -> list[Property]:
"""
convert content into printable data
Returns:
list[Property]: list of content properties
"""
return [Property("Include", str(path), is_required=True) for path in self.includes]

View File

@ -47,7 +47,7 @@ class Repository(Executor, UpdateHandler):
>>> >>>
>>> configuration = Configuration() >>> configuration = Configuration()
>>> database = SQLite.load(configuration) >>> database = SQLite.load(configuration)
>>> repository = Repository.load("x86_64", configuration, database, report=True, unsafe=False) >>> repository = Repository.load("x86_64", configuration, database, report=True)
>>> known_packages = repository.packages() >>> known_packages = repository.packages()
>>> >>>
>>> build_result = repository.process_build(known_packages) >>> build_result = repository.process_build(known_packages)
@ -58,7 +58,7 @@ class Repository(Executor, UpdateHandler):
""" """
@classmethod @classmethod
def load(cls, architecture: str, configuration: Configuration, database: SQLite, *, report: bool, unsafe: bool, def load(cls, architecture: str, configuration: Configuration, database: SQLite, *, report: bool,
refresh_pacman_database: PacmanSynchronization = PacmanSynchronization.Disabled) -> Self: refresh_pacman_database: PacmanSynchronization = PacmanSynchronization.Disabled) -> Self:
""" """
load instance from argument list load instance from argument list
@ -68,7 +68,6 @@ class Repository(Executor, UpdateHandler):
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
database(SQLite): database instance database(SQLite): database instance
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
refresh_pacman_database(PacmanSynchronization, optional): pacman database synchronization level refresh_pacman_database(PacmanSynchronization, optional): pacman database synchronization level
(Default value = PacmanSynchronization.Disabled) (Default value = PacmanSynchronization.Disabled)
@ -76,7 +75,7 @@ class Repository(Executor, UpdateHandler):
Self: fully loaded repository class instance Self: fully loaded repository class instance
""" """
instance = cls(architecture, configuration, database, instance = cls(architecture, configuration, database,
report=report, unsafe=unsafe, refresh_pacman_database=refresh_pacman_database) report=report, refresh_pacman_database=refresh_pacman_database)
instance._set_context() instance._set_context()
return instance return instance

View File

@ -21,12 +21,10 @@ from ahriman.core.alpm.pacman import Pacman
from ahriman.core.alpm.repo import Repo from ahriman.core.alpm.repo import Repo
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.database import SQLite from ahriman.core.database import SQLite
from ahriman.core.exceptions import UnsafeRunError
from ahriman.core.log import LazyLogging from ahriman.core.log import LazyLogging
from ahriman.core.sign.gpg import GPG from ahriman.core.sign.gpg import GPG
from ahriman.core.status.client import Client from ahriman.core.status.client import Client
from ahriman.core.triggers import TriggerLoader from ahriman.core.triggers import TriggerLoader
from ahriman.core.util import check_user
from ahriman.models.packagers import Packagers from ahriman.models.packagers import Packagers
from ahriman.models.pacman_synchronization import PacmanSynchronization from ahriman.models.pacman_synchronization import PacmanSynchronization
from ahriman.models.repository_paths import RepositoryPaths from ahriman.models.repository_paths import RepositoryPaths
@ -53,7 +51,7 @@ class RepositoryProperties(LazyLogging):
vcs_allowed_age(int): maximal age of the VCS packages before they will be checked vcs_allowed_age(int): maximal age of the VCS packages before they will be checked
""" """
def __init__(self, architecture: str, configuration: Configuration, database: SQLite, *, report: bool, unsafe: bool, def __init__(self, architecture: str, configuration: Configuration, database: SQLite, *, report: bool,
refresh_pacman_database: PacmanSynchronization) -> None: refresh_pacman_database: PacmanSynchronization) -> None:
""" """
default constructor default constructor
@ -63,7 +61,6 @@ class RepositoryProperties(LazyLogging):
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
database(SQLite): database instance database(SQLite): database instance
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
refresh_pacman_database(PacmanSynchronization): pacman database synchronization level refresh_pacman_database(PacmanSynchronization): pacman database synchronization level
""" """
self.architecture = architecture self.architecture = architecture
@ -74,11 +71,6 @@ class RepositoryProperties(LazyLogging):
self.vcs_allowed_age = configuration.getint("build", "vcs_allowed_age", fallback=0) self.vcs_allowed_age = configuration.getint("build", "vcs_allowed_age", fallback=0)
self.paths: RepositoryPaths = configuration.repository_paths # additional workaround for pycharm typing self.paths: RepositoryPaths = configuration.repository_paths # additional workaround for pycharm typing
try:
check_user(self.paths, unsafe=unsafe)
self.paths.tree_create()
except UnsafeRunError:
self.logger.warning("root owner differs from the current user, skipping tree creation")
self.ignore_list = configuration.getlist("build", "ignore_packages", fallback=[]) self.ignore_list = configuration.getlist("build", "ignore_packages", fallback=[])
self.pacman = Pacman(architecture, configuration, refresh_database=refresh_pacman_database) self.pacman = Pacman(architecture, configuration, refresh_database=refresh_pacman_database)

View File

@ -20,6 +20,7 @@
from collections.abc import Iterable from collections.abc import Iterable
from ahriman.core.build_tools.sources import Sources from ahriman.core.build_tools.sources import Sources
from ahriman.core.exceptions import UnknownPackageError
from ahriman.core.repository.cleaner import Cleaner from ahriman.core.repository.cleaner import Cleaner
from ahriman.models.package import Package from ahriman.models.package import Package
from ahriman.models.package_source import PackageSource from ahriman.models.package_source import PackageSource
@ -53,6 +54,19 @@ class UpdateHandler(Cleaner):
Returns: Returns:
list[Package]: list of packages which are out-of-dated list[Package]: list of packages which are out-of-dated
""" """
def load_remote(package: Package) -> Package:
source = package.remote.source if package.remote is not None else None
# try to load package from base and if none found try to load by separated packages
for probe in [package.base] + sorted(package.packages.keys()):
try:
if source == PackageSource.Repository:
return Package.from_official(probe, self.pacman, None)
return Package.from_aur(probe, self.pacman, None)
except UnknownPackageError:
continue
raise UnknownPackageError(package.base)
result: list[Package] = [] result: list[Package] = []
for local in self.packages(): for local in self.packages():
@ -61,13 +75,9 @@ class UpdateHandler(Cleaner):
continue continue
if filter_packages and local.base not in filter_packages: if filter_packages and local.base not in filter_packages:
continue continue
source = local.remote.source if local.remote is not None else None
try: try:
if source == PackageSource.Repository: remote = load_remote(local)
remote = Package.from_official(local.base, self.pacman, None)
else:
remote = Package.from_aur(local.base, self.pacman, None)
if local.is_outdated( if local.is_outdated(
remote, self.paths, remote, self.paths,

View File

@ -53,7 +53,7 @@ class Watcher(LazyLogging):
""" """
self.architecture = architecture self.architecture = architecture
self.database = database self.database = database
self.repository = Repository.load(architecture, configuration, database, report=False, unsafe=False) self.repository = Repository.load(architecture, configuration, database, report=False)
self.known: dict[str, tuple[Package, BuildStatus]] = {} self.known: dict[str, tuple[Package, BuildStatus]] = {}
self.status = BuildStatus() self.status = BuildStatus()

View File

@ -24,6 +24,7 @@ import requests
from collections.abc import Generator from collections.abc import Generator
from urllib.parse import quote_plus as urlencode from urllib.parse import quote_plus as urlencode
from ahriman import version
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.log import LazyLogging from ahriman.core.log import LazyLogging
from ahriman.core.status.client import Client from ahriman.core.status.client import Client
@ -140,9 +141,11 @@ class WebClient(Client, LazyLogging):
if use_unix_socket: if use_unix_socket:
import requests_unixsocket # type: ignore[import] import requests_unixsocket # type: ignore[import]
session: requests.Session = requests_unixsocket.Session() session: requests.Session = requests_unixsocket.Session()
session.headers["User-Agent"] = f"ahriman/{version.__version__}"
return session return session
session = requests.Session() session = requests.Session()
session.headers["User-Agent"] = f"ahriman/{version.__version__}"
self._login(session) self._login(session)
return session return session

View File

@ -104,7 +104,7 @@ class Tree:
>>> >>>
>>> configuration = Configuration() >>> configuration = Configuration()
>>> database = SQLite.load(configuration) >>> database = SQLite.load(configuration)
>>> repository = Repository.load("x86_64", configuration, database, report=True, unsafe=False) >>> repository = Repository.load("x86_64", configuration, database, report=True)
>>> packages = repository.packages() >>> packages = repository.packages()
>>> >>>
>>> tree = Tree.resolve(packages) >>> tree = Tree.resolve(packages)

View File

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

View File

@ -27,7 +27,7 @@ def application_packages(configuration: Configuration, database: SQLite, reposit
""" """
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
mocker.patch("ahriman.core.database.SQLite.load", return_value=database) mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
return ApplicationPackages("x86_64", configuration, report=False, unsafe=False) return ApplicationPackages("x86_64", configuration, report=False)
@pytest.fixture @pytest.fixture
@ -47,7 +47,7 @@ def application_properties(configuration: Configuration, database: SQLite, repos
""" """
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
mocker.patch("ahriman.core.database.SQLite.load", return_value=database) mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
return ApplicationProperties("x86_64", configuration, report=False, unsafe=False) return ApplicationProperties("x86_64", configuration, report=False)
@pytest.fixture @pytest.fixture
@ -67,4 +67,4 @@ def application_repository(configuration: Configuration, database: SQLite, repos
""" """
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
mocker.patch("ahriman.core.database.SQLite.load", return_value=database) mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
return ApplicationRepository("x86_64", configuration, report=False, unsafe=False) return ApplicationRepository("x86_64", configuration, report=False)

View File

@ -2,6 +2,7 @@ from pytest_mock import MockerFixture
from unittest.mock import MagicMock, call as MockCall from unittest.mock import MagicMock, call as MockCall
from ahriman.application.application import Application from ahriman.application.application import Application
from ahriman.core.tree import Leaf, Tree
from ahriman.models.package import Package from ahriman.models.package import Package
from ahriman.models.result import Result from ahriman.models.result import Result
@ -47,6 +48,19 @@ def test_on_stop(application: Application, mocker: MockerFixture) -> None:
triggers_mock.assert_called_once_with() triggers_mock.assert_called_once_with()
def test_print_updates(application: Application, package_ahriman: Package, mocker: MockerFixture) -> None:
"""
must print updates
"""
tree = Tree([Leaf(package_ahriman)])
mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[package_ahriman])
mocker.patch("ahriman.core.tree.Tree.resolve", return_value=tree.levels())
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
application.print_updates([package_ahriman], log_fn=print)
print_mock.assert_called_once_with(verbose=True, log_fn=print, separator=" -> ")
def test_with_dependencies(application: Application, package_ahriman: Package, package_python_schedule: Package, def test_with_dependencies(application: Application, package_ahriman: Package, package_python_schedule: Package,
mocker: MockerFixture) -> None: mocker: MockerFixture) -> None:
""" """
@ -75,6 +89,8 @@ def test_with_dependencies(application: Application, package_ahriman: Package, p
package_mock = mocker.patch("ahriman.models.package.Package.from_aur", side_effect=lambda *args: packages[args[0]]) package_mock = mocker.patch("ahriman.models.package.Package.from_aur", side_effect=lambda *args: packages[args[0]])
packages_mock = mocker.patch("ahriman.application.application.Application._known_packages", packages_mock = mocker.patch("ahriman.application.application.Application._known_packages",
return_value={"devtools", "python-build", "python-pytest"}) return_value={"devtools", "python-build", "python-pytest"})
update_remote_mock = mocker.patch("ahriman.core.database.SQLite.remote_update")
status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_unknown")
result = application.with_dependencies([package_ahriman], process_dependencies=True) result = application.with_dependencies([package_ahriman], process_dependencies=True)
assert {package.base: package for package in result} == packages assert {package.base: package for package in result} == packages
@ -85,6 +101,17 @@ def test_with_dependencies(application: Application, package_ahriman: Package, p
], any_order=True) ], any_order=True)
packages_mock.assert_called_once_with() packages_mock.assert_called_once_with()
update_remote_mock.assert_has_calls([
MockCall(package_python_schedule),
MockCall(packages["python"]),
MockCall(packages["python-installer"]),
], any_order=True)
status_client_mock.assert_has_calls([
MockCall(package_python_schedule),
MockCall(packages["python"]),
MockCall(packages["python-installer"]),
], any_order=True)
def test_with_dependencies_skip(application: Application, package_ahriman: Package, mocker: MockerFixture) -> None: def test_with_dependencies_skip(application: Application, package_ahriman: Package, mocker: MockerFixture) -> None:
""" """

View File

@ -197,16 +197,12 @@ def test_updates_all(application_repository: ApplicationRepository, package_ahri
""" """
must get updates for all must get updates for all
""" """
tree = Tree([Leaf(package_ahriman)])
mocker.patch("ahriman.core.tree.Tree.resolve", return_value=tree.levels())
mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[])
updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur", updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur",
return_value=[package_ahriman]) return_value=[package_ahriman])
updates_local_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_local") updates_local_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_local")
updates_manual_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_manual") updates_manual_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_manual")
application_repository.updates([], aur=True, local=True, manual=True, vcs=True, log_fn=print) application_repository.updates([], aur=True, local=True, manual=True, vcs=True)
updates_aur_mock.assert_called_once_with([], vcs=True) updates_aur_mock.assert_called_once_with([], vcs=True)
updates_local_mock.assert_called_once_with(vcs=True) updates_local_mock.assert_called_once_with(vcs=True)
updates_manual_mock.assert_called_once_with() updates_manual_mock.assert_called_once_with()
@ -216,12 +212,11 @@ def test_updates_disabled(application_repository: ApplicationRepository, mocker:
""" """
must get updates without anything must get updates without anything
""" """
mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[])
updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur") updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur")
updates_local_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_local") updates_local_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_local")
updates_manual_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_manual") updates_manual_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_manual")
application_repository.updates([], aur=False, local=False, manual=False, vcs=True, log_fn=print) application_repository.updates([], aur=False, local=False, manual=False, vcs=True)
updates_aur_mock.assert_not_called() updates_aur_mock.assert_not_called()
updates_local_mock.assert_not_called() updates_local_mock.assert_not_called()
updates_manual_mock.assert_not_called() updates_manual_mock.assert_not_called()
@ -231,12 +226,11 @@ def test_updates_no_aur(application_repository: ApplicationRepository, mocker: M
""" """
must get updates without aur must get updates without aur
""" """
mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[])
updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur") updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur")
updates_local_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_local") updates_local_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_local")
updates_manual_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_manual") updates_manual_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_manual")
application_repository.updates([], aur=False, local=True, manual=True, vcs=True, log_fn=print) application_repository.updates([], aur=False, local=True, manual=True, vcs=True)
updates_aur_mock.assert_not_called() updates_aur_mock.assert_not_called()
updates_local_mock.assert_called_once_with(vcs=True) updates_local_mock.assert_called_once_with(vcs=True)
updates_manual_mock.assert_called_once_with() updates_manual_mock.assert_called_once_with()
@ -246,12 +240,11 @@ def test_updates_no_local(application_repository: ApplicationRepository, mocker:
""" """
must get updates without local packages must get updates without local packages
""" """
mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[])
updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur") updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur")
updates_local_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_local") updates_local_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_local")
updates_manual_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_manual") updates_manual_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_manual")
application_repository.updates([], aur=True, local=False, manual=True, vcs=True, log_fn=print) application_repository.updates([], aur=True, local=False, manual=True, vcs=True)
updates_aur_mock.assert_called_once_with([], vcs=True) updates_aur_mock.assert_called_once_with([], vcs=True)
updates_local_mock.assert_not_called() updates_local_mock.assert_not_called()
updates_manual_mock.assert_called_once_with() updates_manual_mock.assert_called_once_with()
@ -261,12 +254,11 @@ def test_updates_no_manual(application_repository: ApplicationRepository, mocker
""" """
must get updates without manual must get updates without manual
""" """
mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[])
updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur") updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur")
updates_local_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_local") updates_local_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_local")
updates_manual_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_manual") updates_manual_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_manual")
application_repository.updates([], aur=True, local=True, manual=False, vcs=True, log_fn=print) application_repository.updates([], aur=True, local=True, manual=False, vcs=True)
updates_aur_mock.assert_called_once_with([], vcs=True) updates_aur_mock.assert_called_once_with([], vcs=True)
updates_local_mock.assert_called_once_with(vcs=True) updates_local_mock.assert_called_once_with(vcs=True)
updates_manual_mock.assert_not_called() updates_manual_mock.assert_not_called()
@ -276,12 +268,11 @@ def test_updates_no_vcs(application_repository: ApplicationRepository, mocker: M
""" """
must get updates without VCS must get updates without VCS
""" """
mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[])
updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur") updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur")
updates_local_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_local") updates_local_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_local")
updates_manual_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_manual") updates_manual_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_manual")
application_repository.updates([], aur=True, local=True, manual=True, vcs=False, log_fn=print) application_repository.updates([], aur=True, local=True, manual=True, vcs=False)
updates_aur_mock.assert_called_once_with([], vcs=False) updates_aur_mock.assert_called_once_with([], vcs=False)
updates_local_mock.assert_called_once_with(vcs=False) updates_local_mock.assert_called_once_with(vcs=False)
updates_manual_mock.assert_called_once_with() updates_manual_mock.assert_called_once_with()
@ -291,12 +282,11 @@ def test_updates_with_filter(application_repository: ApplicationRepository, mock
""" """
must get updates with filter must get updates with filter
""" """
mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[])
updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur") updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur")
updates_local_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_local") updates_local_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_local")
updates_manual_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_manual") updates_manual_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_manual")
application_repository.updates(["filter"], aur=True, local=True, manual=True, vcs=True, log_fn=print) application_repository.updates(["filter"], aur=True, local=True, manual=True, vcs=True)
updates_aur_mock.assert_called_once_with(["filter"], vcs=True) updates_aur_mock.assert_called_once_with(["filter"], vcs=True)
updates_local_mock.assert_called_once_with(vcs=True) updates_local_mock.assert_called_once_with(vcs=True)
updates_manual_mock.assert_called_once_with() updates_manual_mock.assert_called_once_with()

View File

@ -26,10 +26,9 @@ def application(configuration: Configuration, repository: Repository, database:
Returns: Returns:
Application: application test instance Application: application test instance
""" """
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
mocker.patch("ahriman.core.database.SQLite.load", return_value=database) mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
return Application("x86_64", configuration, report=False, unsafe=False) return Application("x86_64", configuration, report=False)
@pytest.fixture @pytest.fixture

View File

@ -143,7 +143,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration) -> None:
must raise NotImplemented for missing method must raise NotImplemented for missing method
""" """
with pytest.raises(NotImplementedError): with pytest.raises(NotImplementedError):
Handler.run(args, "x86_64", configuration, report=True, unsafe=True) Handler.run(args, "x86_64", configuration, report=True)
def test_check_if_empty() -> None: def test_check_if_empty() -> None:

View File

@ -43,7 +43,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
dependencies_mock = mocker.patch("ahriman.application.application.Application.with_dependencies") dependencies_mock = mocker.patch("ahriman.application.application.Application.with_dependencies")
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start") on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
Add.run(args, "x86_64", configuration, report=False, unsafe=False) Add.run(args, "x86_64", configuration, report=False)
application_mock.assert_called_once_with(args.package, args.source, args.username) application_mock.assert_called_once_with(args.package, args.source, args.username)
dependencies_mock.assert_not_called() dependencies_mock.assert_not_called()
on_start_mock.assert_called_once_with() on_start_mock.assert_called_once_with()
@ -65,14 +65,15 @@ def test_run_with_updates(args: argparse.Namespace, configuration: Configuration
updates_mock = mocker.patch("ahriman.application.application.Application.updates", return_value=[package_ahriman]) updates_mock = mocker.patch("ahriman.application.application.Application.updates", return_value=[package_ahriman])
dependencies_mock = mocker.patch("ahriman.application.application.Application.with_dependencies", dependencies_mock = mocker.patch("ahriman.application.application.Application.with_dependencies",
return_value=[package_ahriman]) return_value=[package_ahriman])
print_mock = mocker.patch("ahriman.application.application.Application.print_updates")
Add.run(args, "x86_64", configuration, report=False, unsafe=False) Add.run(args, "x86_64", configuration, report=False)
updates_mock.assert_called_once_with(args.package, aur=False, local=False, manual=True, vcs=False, updates_mock.assert_called_once_with(args.package, aur=False, local=False, manual=True, vcs=False)
log_fn=pytest.helpers.anyvar(int))
application_mock.assert_called_once_with([package_ahriman], application_mock.assert_called_once_with([package_ahriman],
Packagers(args.username, {package_ahriman.base: "packager"})) Packagers(args.username, {package_ahriman.base: "packager"}))
dependencies_mock.assert_called_once_with([package_ahriman], process_dependencies=args.dependencies) dependencies_mock.assert_called_once_with([package_ahriman], process_dependencies=args.dependencies)
check_mock.assert_called_once_with(False, False) check_mock.assert_called_once_with(False, False)
print_mock.assert_called_once_with([package_ahriman], log_fn=pytest.helpers.anyvar(int))
def test_run_empty_exception(args: argparse.Namespace, configuration: Configuration, repository: Repository, def test_run_empty_exception(args: argparse.Namespace, configuration: Configuration, repository: Repository,
@ -88,7 +89,8 @@ def test_run_empty_exception(args: argparse.Namespace, configuration: Configurat
mocker.patch("ahriman.application.application.Application.update", return_value=Result()) mocker.patch("ahriman.application.application.Application.update", return_value=Result())
mocker.patch("ahriman.application.application.Application.with_dependencies") mocker.patch("ahriman.application.application.Application.with_dependencies")
mocker.patch("ahriman.application.application.Application.updates") mocker.patch("ahriman.application.application.Application.updates")
mocker.patch("ahriman.application.application.Application.print_updates")
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty") check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
Add.run(args, "x86_64", configuration, report=False, unsafe=False) Add.run(args, "x86_64", configuration, report=False)
check_mock.assert_called_once_with(True, True) check_mock.assert_called_once_with(True, True)

View File

@ -33,7 +33,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
add_mock = tarfile.__enter__.return_value = MagicMock() add_mock = tarfile.__enter__.return_value = MagicMock()
mocker.patch("tarfile.TarFile.__new__", return_value=tarfile) mocker.patch("tarfile.TarFile.__new__", return_value=tarfile)
Backup.run(args, "x86_64", configuration, report=False, unsafe=False) Backup.run(args, "x86_64", configuration, report=False)
add_mock.add.assert_called_once_with(Path("path")) add_mock.add.assert_called_once_with(Path("path"))

View File

@ -35,6 +35,6 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
application_mock = mocker.patch("ahriman.application.application.Application.clean") application_mock = mocker.patch("ahriman.application.application.Application.clean")
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start") on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
Clean.run(args, "x86_64", configuration, report=False, unsafe=False) Clean.run(args, "x86_64", configuration, report=False)
application_mock.assert_called_once_with(cache=False, chroot=False, manual=False, packages=False, pacman=False) application_mock.assert_called_once_with(cache=False, chroot=False, manual=False, packages=False, pacman=False)
on_start_mock.assert_called_once_with() on_start_mock.assert_called_once_with()

View File

@ -33,7 +33,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
start_mock = mocker.patch("threading.Timer.start") start_mock = mocker.patch("threading.Timer.start")
join_mock = mocker.patch("threading.Timer.join") join_mock = mocker.patch("threading.Timer.join")
Daemon.run(args, "x86_64", configuration, report=True, unsafe=False) Daemon.run(args, "x86_64", configuration, report=True)
run_mock.assert_called_once_with(args, "x86_64", configuration, report=True, unsafe=False) run_mock.assert_called_once_with(args, "x86_64", configuration, report=True)
start_mock.assert_called_once_with() start_mock.assert_called_once_with()
join_mock.assert_called_once_with() join_mock.assert_called_once_with()

View File

@ -29,7 +29,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
application_mock = mocker.patch("ahriman.core.configuration.Configuration.dump", application_mock = mocker.patch("ahriman.core.configuration.Configuration.dump",
return_value=configuration.dump()) return_value=configuration.dump())
Dump.run(args, "x86_64", configuration, report=False, unsafe=False) Dump.run(args, "x86_64", configuration, report=False)
application_mock.assert_called_once_with() application_mock.assert_called_once_with()
print_mock.assert_called() print_mock.assert_called()

View File

@ -29,7 +29,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
args = _default_args(args) args = _default_args(args)
parse_mock = mocker.patch("argparse.ArgumentParser.parse_args") parse_mock = mocker.patch("argparse.ArgumentParser.parse_args")
Help.run(args, "x86_64", configuration, report=False, unsafe=False) Help.run(args, "x86_64", configuration, report=False)
parse_mock.assert_called_once_with(["--help"]) parse_mock.assert_called_once_with(["--help"])
@ -41,7 +41,7 @@ def test_run_command(args: argparse.Namespace, configuration: Configuration, moc
args.command = "aur-search" args.command = "aur-search"
parse_mock = mocker.patch("argparse.ArgumentParser.parse_args") parse_mock = mocker.patch("argparse.ArgumentParser.parse_args")
Help.run(args, "x86_64", configuration, report=False, unsafe=False) Help.run(args, "x86_64", configuration, report=False)
parse_mock.assert_called_once_with(["aur-search", "--help"]) parse_mock.assert_called_once_with(["aur-search", "--help"])

View File

@ -31,7 +31,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
application_mock = mocker.patch("ahriman.core.sign.gpg.GPG.key_import") application_mock = mocker.patch("ahriman.core.sign.gpg.GPG.key_import")
KeyImport.run(args, "x86_64", configuration, report=False, unsafe=False) KeyImport.run(args, "x86_64", configuration, report=False)
application_mock.assert_called_once_with(args.key_server, args.key) application_mock.assert_called_once_with(args.key_server, args.key)

View File

@ -44,7 +44,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
return_value=(args.package, PkgbuildPatch(None, "patch"))) return_value=(args.package, PkgbuildPatch(None, "patch")))
application_mock = mocker.patch("ahriman.application.handlers.Patch.patch_set_create") application_mock = mocker.patch("ahriman.application.handlers.Patch.patch_set_create")
Patch.run(args, "x86_64", configuration, report=False, unsafe=False) Patch.run(args, "x86_64", configuration, report=False)
patch_mock.assert_called_once_with(args.package, "x86_64", args.track) patch_mock.assert_called_once_with(args.package, "x86_64", args.track)
application_mock.assert_called_once_with(pytest.helpers.anyvar(int), args.package, PkgbuildPatch(None, "patch")) application_mock.assert_called_once_with(pytest.helpers.anyvar(int), args.package, PkgbuildPatch(None, "patch"))
@ -63,7 +63,7 @@ def test_run_function(args: argparse.Namespace, configuration: Configuration, re
patch_mock = mocker.patch("ahriman.application.handlers.Patch.patch_create_from_function", return_value=patch) patch_mock = mocker.patch("ahriman.application.handlers.Patch.patch_create_from_function", return_value=patch)
application_mock = mocker.patch("ahriman.application.handlers.Patch.patch_set_create") application_mock = mocker.patch("ahriman.application.handlers.Patch.patch_set_create")
Patch.run(args, "x86_64", configuration, report=False, unsafe=False) Patch.run(args, "x86_64", configuration, report=False)
patch_mock.assert_called_once_with(args.variable, args.patch) patch_mock.assert_called_once_with(args.variable, args.patch)
application_mock.assert_called_once_with(pytest.helpers.anyvar(int), args.package, patch) application_mock.assert_called_once_with(pytest.helpers.anyvar(int), args.package, patch)
@ -79,7 +79,7 @@ def test_run_list(args: argparse.Namespace, configuration: Configuration, reposi
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
application_mock = mocker.patch("ahriman.application.handlers.Patch.patch_set_list") application_mock = mocker.patch("ahriman.application.handlers.Patch.patch_set_list")
Patch.run(args, "x86_64", configuration, report=False, unsafe=False) Patch.run(args, "x86_64", configuration, report=False)
application_mock.assert_called_once_with(pytest.helpers.anyvar(int), args.package, ["version"], False) application_mock.assert_called_once_with(pytest.helpers.anyvar(int), args.package, ["version"], False)
@ -94,7 +94,7 @@ def test_run_remove(args: argparse.Namespace, configuration: Configuration, repo
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
application_mock = mocker.patch("ahriman.application.handlers.Patch.patch_set_remove") application_mock = mocker.patch("ahriman.application.handlers.Patch.patch_set_remove")
Patch.run(args, "x86_64", configuration, report=False, unsafe=False) Patch.run(args, "x86_64", configuration, report=False)
application_mock.assert_called_once_with(pytest.helpers.anyvar(int), args.package, ["version"]) application_mock.assert_called_once_with(pytest.helpers.anyvar(int), args.package, ["version"])

View File

@ -48,7 +48,7 @@ def test_run(args: argparse.Namespace, package_ahriman: Package, configuration:
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty") check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start") on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
Rebuild.run(args, "x86_64", configuration, report=False, unsafe=False) Rebuild.run(args, "x86_64", configuration, report=False)
extract_mock.assert_called_once_with(pytest.helpers.anyvar(int), args.status, from_database=args.from_database) extract_mock.assert_called_once_with(pytest.helpers.anyvar(int), args.status, from_database=args.from_database)
application_packages_mock.assert_called_once_with([package_ahriman], None) application_packages_mock.assert_called_once_with([package_ahriman], None)
application_mock.assert_called_once_with([package_ahriman], args.username) application_mock.assert_called_once_with([package_ahriman], args.username)
@ -66,9 +66,10 @@ def test_run_extract_packages(args: argparse.Namespace, configuration: Configura
args.dry_run = True args.dry_run = True
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
mocker.patch("ahriman.application.application.Application.add") mocker.patch("ahriman.application.application.Application.add")
mocker.patch("ahriman.application.application.Application.print_updates")
extract_mock = mocker.patch("ahriman.application.handlers.Rebuild.extract_packages", return_value=[]) extract_mock = mocker.patch("ahriman.application.handlers.Rebuild.extract_packages", return_value=[])
Rebuild.run(args, "x86_64", configuration, report=False, unsafe=False) Rebuild.run(args, "x86_64", configuration, report=False)
extract_mock.assert_called_once_with(pytest.helpers.anyvar(int), args.status, from_database=args.from_database) extract_mock.assert_called_once_with(pytest.helpers.anyvar(int), args.status, from_database=args.from_database)
@ -83,10 +84,12 @@ def test_run_dry_run(args: argparse.Namespace, configuration: Configuration, rep
mocker.patch("ahriman.application.handlers.Rebuild.extract_packages", return_value=[package_ahriman]) mocker.patch("ahriman.application.handlers.Rebuild.extract_packages", return_value=[package_ahriman])
application_mock = mocker.patch("ahriman.application.application.Application.update") application_mock = mocker.patch("ahriman.application.application.Application.update")
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty") check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
print_mock = mocker.patch("ahriman.application.application.Application.print_updates")
Rebuild.run(args, "x86_64", configuration, report=False, unsafe=False) Rebuild.run(args, "x86_64", configuration, report=False)
application_mock.assert_not_called() application_mock.assert_not_called()
check_mock.assert_called_once_with(False, False) check_mock.assert_called_once_with(False, False)
print_mock.assert_called_once_with([package_ahriman], log_fn=pytest.helpers.anyvar(int))
def test_run_filter(args: argparse.Namespace, configuration: Configuration, repository: Repository, def test_run_filter(args: argparse.Namespace, configuration: Configuration, repository: Repository,
@ -101,7 +104,7 @@ def test_run_filter(args: argparse.Namespace, configuration: Configuration, repo
mocker.patch("ahriman.application.handlers.Rebuild.extract_packages", return_value=[]) mocker.patch("ahriman.application.handlers.Rebuild.extract_packages", return_value=[])
application_packages_mock = mocker.patch("ahriman.core.repository.repository.Repository.packages_depend_on") application_packages_mock = mocker.patch("ahriman.core.repository.repository.Repository.packages_depend_on")
Rebuild.run(args, "x86_64", configuration, report=False, unsafe=False) Rebuild.run(args, "x86_64", configuration, report=False)
application_packages_mock.assert_called_once_with([], ["python-aur"]) application_packages_mock.assert_called_once_with([], ["python-aur"])
@ -116,7 +119,7 @@ def test_run_without_filter(args: argparse.Namespace, configuration: Configurati
mocker.patch("ahriman.application.handlers.Rebuild.extract_packages", return_value=[]) mocker.patch("ahriman.application.handlers.Rebuild.extract_packages", return_value=[])
application_packages_mock = mocker.patch("ahriman.core.repository.repository.Repository.packages_depend_on") application_packages_mock = mocker.patch("ahriman.core.repository.repository.Repository.packages_depend_on")
Rebuild.run(args, "x86_64", configuration, report=False, unsafe=False) Rebuild.run(args, "x86_64", configuration, report=False)
application_packages_mock.assert_called_once_with([], None) application_packages_mock.assert_called_once_with([], None)
@ -131,9 +134,10 @@ def test_run_update_empty_exception(args: argparse.Namespace, configuration: Con
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
mocker.patch("ahriman.application.handlers.Rebuild.extract_packages") mocker.patch("ahriman.application.handlers.Rebuild.extract_packages")
mocker.patch("ahriman.core.repository.repository.Repository.packages_depend_on", return_value=[]) mocker.patch("ahriman.core.repository.repository.Repository.packages_depend_on", return_value=[])
mocker.patch("ahriman.application.application.Application.print_updates")
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty") check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
Rebuild.run(args, "x86_64", configuration, report=False, unsafe=False) Rebuild.run(args, "x86_64", configuration, report=False)
check_mock.assert_called_once_with(True, True) check_mock.assert_called_once_with(True, True)
@ -150,7 +154,7 @@ def test_run_build_empty_exception(args: argparse.Namespace, configuration: Conf
mocker.patch("ahriman.application.application.Application.update", return_value=Result()) mocker.patch("ahriman.application.application.Application.update", return_value=Result())
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty") check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
Rebuild.run(args, "x86_64", configuration, report=False, unsafe=False) Rebuild.run(args, "x86_64", configuration, report=False)
check_mock.assert_has_calls([MockCall(True, False), MockCall(True, True)]) check_mock.assert_has_calls([MockCall(True, False), MockCall(True, True)])

View File

@ -31,6 +31,6 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
application_mock = mocker.patch("ahriman.application.application.Application.remove") application_mock = mocker.patch("ahriman.application.application.Application.remove")
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start") on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
Remove.run(args, "x86_64", configuration, report=False, unsafe=False) Remove.run(args, "x86_64", configuration, report=False)
application_mock.assert_called_once_with([]) application_mock.assert_called_once_with([])
on_start_mock.assert_called_once_with() on_start_mock.assert_called_once_with()

View File

@ -34,7 +34,7 @@ def test_run(args: argparse.Namespace, package_ahriman: Package, configuration:
remove_mock = mocker.patch("ahriman.application.application.Application.remove") remove_mock = mocker.patch("ahriman.application.application.Application.remove")
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start") on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
RemoveUnknown.run(args, "x86_64", configuration, report=False, unsafe=False) RemoveUnknown.run(args, "x86_64", configuration, report=False)
application_mock.assert_called_once_with() application_mock.assert_called_once_with()
remove_mock.assert_called_once_with([package_ahriman]) remove_mock.assert_called_once_with([package_ahriman])
on_start_mock.assert_called_once_with() on_start_mock.assert_called_once_with()
@ -53,7 +53,7 @@ def test_run_dry_run(args: argparse.Namespace, configuration: Configuration, rep
remove_mock = mocker.patch("ahriman.application.application.Application.remove") remove_mock = mocker.patch("ahriman.application.application.Application.remove")
print_mock = mocker.patch("ahriman.core.formatters.Printer.print") print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
RemoveUnknown.run(args, "x86_64", configuration, report=False, unsafe=False) RemoveUnknown.run(args, "x86_64", configuration, report=False)
application_mock.assert_called_once_with() application_mock.assert_called_once_with()
remove_mock.assert_not_called() remove_mock.assert_not_called()
print_mock.assert_called_once_with(verbose=False) print_mock.assert_called_once_with(verbose=False)

View File

@ -32,7 +32,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
extract_mock = tarfile.__enter__.return_value = MagicMock() extract_mock = tarfile.__enter__.return_value = MagicMock()
mocker.patch("tarfile.TarFile.__new__", return_value=tarfile) mocker.patch("tarfile.TarFile.__new__", return_value=tarfile)
Restore.run(args, "x86_64", configuration, report=False, unsafe=False) Restore.run(args, "x86_64", configuration, report=False)
extract_mock.extractall.assert_called_once_with(path=args.output) extract_mock.extractall.assert_called_once_with(path=args.output)

View File

@ -42,7 +42,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty") check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
print_mock = mocker.patch("ahriman.core.formatters.Printer.print") print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
Search.run(args, "x86_64", configuration, report=False, unsafe=False) Search.run(args, "x86_64", configuration, report=False)
aur_search_mock.assert_called_once_with("ahriman", pacman=pytest.helpers.anyvar(int)) aur_search_mock.assert_called_once_with("ahriman", pacman=pytest.helpers.anyvar(int))
official_search_mock.assert_called_once_with("ahriman", pacman=pytest.helpers.anyvar(int)) official_search_mock.assert_called_once_with("ahriman", pacman=pytest.helpers.anyvar(int))
check_mock.assert_called_once_with(False, False) check_mock.assert_called_once_with(False, False)
@ -62,7 +62,7 @@ def test_run_empty_exception(args: argparse.Namespace, configuration: Configurat
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty") check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
Search.run(args, "x86_64", configuration, report=False, unsafe=False) Search.run(args, "x86_64", configuration, report=False)
check_mock.assert_called_once_with(True, True) check_mock.assert_called_once_with(True, True)
@ -77,7 +77,7 @@ def test_run_sort(args: argparse.Namespace, configuration: Configuration, reposi
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
sort_mock = mocker.patch("ahriman.application.handlers.Search.sort") sort_mock = mocker.patch("ahriman.application.handlers.Search.sort")
Search.run(args, "x86_64", configuration, report=False, unsafe=False) Search.run(args, "x86_64", configuration, report=False)
sort_mock.assert_has_calls([ sort_mock.assert_has_calls([
MockCall([], "name"), MockCall().__iter__(), MockCall([], "name"), MockCall().__iter__(),
MockCall([aur_package_ahriman], "name"), MockCall().__iter__() MockCall([aur_package_ahriman], "name"), MockCall().__iter__()
@ -96,7 +96,7 @@ def test_run_sort_by(args: argparse.Namespace, configuration: Configuration, rep
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
sort_mock = mocker.patch("ahriman.application.handlers.Search.sort") sort_mock = mocker.patch("ahriman.application.handlers.Search.sort")
Search.run(args, "x86_64", configuration, report=False, unsafe=False) Search.run(args, "x86_64", configuration, report=False)
sort_mock.assert_has_calls([ sort_mock.assert_has_calls([
MockCall([], "field"), MockCall().__iter__(), MockCall([], "field"), MockCall().__iter__(),
MockCall([aur_package_ahriman], "field"), MockCall().__iter__() MockCall([aur_package_ahriman], "field"), MockCall().__iter__()

View File

@ -35,7 +35,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
application_mock = mocker.patch("ahriman.core.formatters.Printer.print") application_mock = mocker.patch("ahriman.core.formatters.Printer.print")
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty") check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
ServiceUpdates.run(args, "x86_64", configuration, report=False, unsafe=False) ServiceUpdates.run(args, "x86_64", configuration, report=False)
package_mock.assert_called_once_with(package_ahriman.base, repository.pacman, None) package_mock.assert_called_once_with(package_ahriman.base, repository.pacman, None)
application_mock.assert_called_once_with(verbose=True, separator=" -> ") application_mock.assert_called_once_with(verbose=True, separator=" -> ")
check_mock.assert_called_once_with(args.exit_code, True) check_mock.assert_called_once_with(args.exit_code, True)
@ -53,6 +53,6 @@ def test_run_skip(args: argparse.Namespace, configuration: Configuration, reposi
application_mock = mocker.patch("ahriman.core.formatters.Printer.print") application_mock = mocker.patch("ahriman.core.formatters.Printer.print")
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty") check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
ServiceUpdates.run(args, "x86_64", configuration, report=False, unsafe=False) ServiceUpdates.run(args, "x86_64", configuration, report=False)
application_mock.assert_not_called() application_mock.assert_not_called()
check_mock.assert_not_called() check_mock.assert_not_called()

View File

@ -26,6 +26,7 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace:
args.build_as_user = "ahriman" args.build_as_user = "ahriman"
args.build_command = "ahriman" args.build_command = "ahriman"
args.from_configuration = Path("/usr/share/devtools/pacman.conf.d/extra.conf") args.from_configuration = Path("/usr/share/devtools/pacman.conf.d/extra.conf")
args.generate_salt = True
args.makeflags_jobs = True args.makeflags_jobs = True
args.mirror = "mirror" args.mirror = "mirror"
args.multilib = True args.multilib = True
@ -52,7 +53,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
executable_mock = mocker.patch("ahriman.application.handlers.Setup.executable_create") executable_mock = mocker.patch("ahriman.application.handlers.Setup.executable_create")
init_mock = mocker.patch("ahriman.core.alpm.repo.Repo.init") init_mock = mocker.patch("ahriman.core.alpm.repo.Repo.init")
Setup.run(args, "x86_64", configuration, report=False, unsafe=False) Setup.run(args, "x86_64", configuration, report=False)
ahriman_configuration_mock.assert_called_once_with(args, "x86_64", args.repository, configuration) ahriman_configuration_mock.assert_called_once_with(args, "x86_64", args.repository, configuration)
devtools_configuration_mock.assert_called_once_with( devtools_configuration_mock.assert_called_once_with(
args.build_command, "x86_64", args.from_configuration, args.mirror, args.multilib, args.repository, args.build_command, "x86_64", args.from_configuration, args.mirror, args.multilib, args.repository,
@ -97,6 +98,7 @@ def test_configuration_create_ahriman(args: argparse.Namespace, configuration: C
MockCall(Configuration.section_name("sign", "x86_64"), "key", args.sign_key), MockCall(Configuration.section_name("sign", "x86_64"), "key", args.sign_key),
MockCall(Configuration.section_name("web", "x86_64"), "port", str(args.web_port)), MockCall(Configuration.section_name("web", "x86_64"), "port", str(args.web_port)),
MockCall(Configuration.section_name("web", "x86_64"), "unix_socket", str(args.web_unix_socket)), MockCall(Configuration.section_name("web", "x86_64"), "unix_socket", str(args.web_unix_socket)),
MockCall("auth", "salt", pytest.helpers.anyvar(str, strict=True)),
]) ])
write_mock.assert_called_once_with(pytest.helpers.anyvar(int)) write_mock.assert_called_once_with(pytest.helpers.anyvar(int))

View File

@ -32,7 +32,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
application_mock = mocker.patch("code.interact") application_mock = mocker.patch("code.interact")
Shell.run(args, "x86_64", configuration, report=False, unsafe=False) Shell.run(args, "x86_64", configuration, report=False)
application_mock.assert_called_once_with(local=pytest.helpers.anyvar(int)) application_mock.assert_called_once_with(local=pytest.helpers.anyvar(int))
@ -46,7 +46,7 @@ def test_run_eval(args: argparse.Namespace, configuration: Configuration, reposi
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
application_mock = mocker.patch("code.InteractiveConsole.runcode") application_mock = mocker.patch("code.InteractiveConsole.runcode")
Shell.run(args, "x86_64", configuration, report=False, unsafe=False) Shell.run(args, "x86_64", configuration, report=False)
application_mock.assert_called_once_with(args.code) application_mock.assert_called_once_with(args.code)
@ -61,6 +61,6 @@ def test_run_verbose(args: argparse.Namespace, configuration: Configuration, rep
print_mock = mocker.patch("ahriman.core.formatters.Printer.print") print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
application_mock = mocker.patch("code.interact") application_mock = mocker.patch("code.interact")
Shell.run(args, "x86_64", configuration, report=False, unsafe=False) Shell.run(args, "x86_64", configuration, report=False)
application_mock.assert_called_once_with(local=pytest.helpers.anyvar(int)) application_mock.assert_called_once_with(local=pytest.helpers.anyvar(int))
print_mock.assert_called_once_with(verbose=False) print_mock.assert_called_once_with(verbose=False)

View File

@ -30,5 +30,5 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
application_mock = mocker.patch("ahriman.application.application.Application.sign") application_mock = mocker.patch("ahriman.application.application.Application.sign")
Sign.run(args, "x86_64", configuration, report=False, unsafe=False) Sign.run(args, "x86_64", configuration, report=False)
application_mock.assert_called_once_with([]) application_mock.assert_called_once_with([])

View File

@ -43,7 +43,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty") check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
print_mock = mocker.patch("ahriman.core.formatters.Printer.print") print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
Status.run(args, "x86_64", configuration, report=False, unsafe=False) Status.run(args, "x86_64", configuration, report=False)
application_mock.assert_called_once_with() application_mock.assert_called_once_with()
packages_mock.assert_called_once_with(None) packages_mock.assert_called_once_with(None)
check_mock.assert_called_once_with(False, False) check_mock.assert_called_once_with(False, False)
@ -62,7 +62,7 @@ def test_run_empty_exception(args: argparse.Namespace, configuration: Configurat
mocker.patch("ahriman.core.status.client.Client.get", return_value=[]) mocker.patch("ahriman.core.status.client.Client.get", return_value=[])
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty") check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
Status.run(args, "x86_64", configuration, report=False, unsafe=False) Status.run(args, "x86_64", configuration, report=False)
check_mock.assert_called_once_with(True, True) check_mock.assert_called_once_with(True, True)
@ -78,7 +78,7 @@ def test_run_verbose(args: argparse.Namespace, configuration: Configuration, rep
return_value=[(package_ahriman, BuildStatus(BuildStatusEnum.Success))]) return_value=[(package_ahriman, BuildStatus(BuildStatusEnum.Success))])
print_mock = mocker.patch("ahriman.core.formatters.Printer.print") print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
Status.run(args, "x86_64", configuration, report=False, unsafe=False) Status.run(args, "x86_64", configuration, report=False)
print_mock.assert_has_calls([MockCall(verbose=True) for _ in range(2)]) print_mock.assert_has_calls([MockCall(verbose=True) for _ in range(2)])
@ -93,7 +93,7 @@ def test_run_with_package_filter(args: argparse.Namespace, configuration: Config
packages_mock = mocker.patch("ahriman.core.status.client.Client.get", packages_mock = mocker.patch("ahriman.core.status.client.Client.get",
return_value=[(package_ahriman, BuildStatus(BuildStatusEnum.Success))]) return_value=[(package_ahriman, BuildStatus(BuildStatusEnum.Success))])
Status.run(args, "x86_64", configuration, report=False, unsafe=False) Status.run(args, "x86_64", configuration, report=False)
packages_mock.assert_called_once_with(package_ahriman.base) packages_mock.assert_called_once_with(package_ahriman.base)
@ -110,7 +110,7 @@ def test_run_by_status(args: argparse.Namespace, configuration: Configuration, r
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
print_mock = mocker.patch("ahriman.core.formatters.Printer.print") print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
Status.run(args, "x86_64", configuration, report=False, unsafe=False) Status.run(args, "x86_64", configuration, report=False)
print_mock.assert_has_calls([MockCall(verbose=False) for _ in range(2)]) print_mock.assert_has_calls([MockCall(verbose=False) for _ in range(2)])
@ -123,9 +123,8 @@ def test_imply_with_report(args: argparse.Namespace, configuration: Configuratio
mocker.patch("ahriman.core.database.SQLite.load", return_value=database) mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
load_mock = mocker.patch("ahriman.core.repository.Repository.load") load_mock = mocker.patch("ahriman.core.repository.Repository.load")
Status.run(args, "x86_64", configuration, report=False, unsafe=False) Status.run(args, "x86_64", configuration, report=False)
load_mock.assert_called_once_with("x86_64", configuration, database, load_mock.assert_called_once_with("x86_64", configuration, database, report=True, refresh_pacman_database=0)
report=True, unsafe=False, refresh_pacman_database=0)
def test_disallow_auto_architecture_run() -> None: def test_disallow_auto_architecture_run() -> None:

View File

@ -36,7 +36,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
update_self_mock = mocker.patch("ahriman.core.status.client.Client.update_self") update_self_mock = mocker.patch("ahriman.core.status.client.Client.update_self")
StatusUpdate.run(args, "x86_64", configuration, report=False, unsafe=False) StatusUpdate.run(args, "x86_64", configuration, report=False)
update_self_mock.assert_called_once_with(args.status) update_self_mock.assert_called_once_with(args.status)
@ -50,7 +50,7 @@ def test_run_packages(args: argparse.Namespace, configuration: Configuration, re
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
update_mock = mocker.patch("ahriman.core.status.client.Client.update") update_mock = mocker.patch("ahriman.core.status.client.Client.update")
StatusUpdate.run(args, "x86_64", configuration, report=False, unsafe=False) StatusUpdate.run(args, "x86_64", configuration, report=False)
update_mock.assert_called_once_with(package_ahriman.base, args.status) update_mock.assert_called_once_with(package_ahriman.base, args.status)
@ -65,7 +65,7 @@ def test_run_remove(args: argparse.Namespace, configuration: Configuration, repo
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
update_mock = mocker.patch("ahriman.core.status.client.Client.remove") update_mock = mocker.patch("ahriman.core.status.client.Client.remove")
StatusUpdate.run(args, "x86_64", configuration, report=False, unsafe=False) StatusUpdate.run(args, "x86_64", configuration, report=False)
update_mock.assert_called_once_with(package_ahriman.base) update_mock.assert_called_once_with(package_ahriman.base)
@ -78,9 +78,8 @@ def test_imply_with_report(args: argparse.Namespace, configuration: Configuratio
mocker.patch("ahriman.core.database.SQLite.load", return_value=database) mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
load_mock = mocker.patch("ahriman.core.repository.Repository.load") load_mock = mocker.patch("ahriman.core.repository.Repository.load")
StatusUpdate.run(args, "x86_64", configuration, report=False, unsafe=False) StatusUpdate.run(args, "x86_64", configuration, report=False)
load_mock.assert_called_once_with("x86_64", configuration, database, load_mock.assert_called_once_with("x86_64", configuration, database, report=True, refresh_pacman_database=0)
report=True, unsafe=False, refresh_pacman_database=0)
def test_disallow_auto_architecture_run() -> None: def test_disallow_auto_architecture_run() -> None:

View File

@ -18,7 +18,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
application_mock = mocker.patch("ahriman.core.tree.Tree.resolve", return_value=[[package_ahriman]]) application_mock = mocker.patch("ahriman.core.tree.Tree.resolve", return_value=[[package_ahriman]])
print_mock = mocker.patch("ahriman.core.formatters.Printer.print") print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
Structure.run(args, "x86_64", configuration, report=False, unsafe=False) Structure.run(args, "x86_64", configuration, report=False)
application_mock.assert_called_once_with([package_ahriman]) application_mock.assert_called_once_with([package_ahriman])
print_mock.assert_called_once_with(verbose=True, separator=" ") print_mock.assert_called_once_with(verbose=True, separator=" ")

View File

@ -33,7 +33,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
application_mock = mocker.patch("ahriman.application.application.Application.on_result") application_mock = mocker.patch("ahriman.application.application.Application.on_result")
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start") on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
Triggers.run(args, "x86_64", configuration, report=False, unsafe=False) Triggers.run(args, "x86_64", configuration, report=False)
application_mock.assert_called_once_with(Result()) application_mock.assert_called_once_with(Result())
on_start_mock.assert_called_once_with() on_start_mock.assert_called_once_with()
@ -50,6 +50,6 @@ def test_run_trigger(args: argparse.Namespace, configuration: Configuration, rep
report_mock = mocker.patch("ahriman.core.report.ReportTrigger.on_result") report_mock = mocker.patch("ahriman.core.report.ReportTrigger.on_result")
upload_mock = mocker.patch("ahriman.core.upload.UploadTrigger.on_result") upload_mock = mocker.patch("ahriman.core.upload.UploadTrigger.on_result")
Triggers.run(args, "x86_64", configuration, report=False, unsafe=False) Triggers.run(args, "x86_64", configuration, report=False)
report_mock.assert_called_once_with(Result(), [package_ahriman]) report_mock.assert_called_once_with(Result(), [package_ahriman])
upload_mock.assert_not_called() upload_mock.assert_not_called()

View File

@ -32,7 +32,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
return_value=["command"]) return_value=["command"])
print_mock = mocker.patch("ahriman.core.formatters.Printer.print") print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
UnsafeCommands.run(args, "x86_64", configuration, report=False, unsafe=False) UnsafeCommands.run(args, "x86_64", configuration, report=False)
commands_mock.assert_called_once_with(pytest.helpers.anyvar(int)) commands_mock.assert_called_once_with(pytest.helpers.anyvar(int))
print_mock.assert_called_once_with(verbose=True) print_mock.assert_called_once_with(verbose=True)
@ -47,7 +47,7 @@ def test_run_check(args: argparse.Namespace, configuration: Configuration, mocke
return_value=["command"]) return_value=["command"])
check_mock = mocker.patch("ahriman.application.handlers.UnsafeCommands.check_unsafe") check_mock = mocker.patch("ahriman.application.handlers.UnsafeCommands.check_unsafe")
UnsafeCommands.run(args, "x86_64", configuration, report=False, unsafe=False) UnsafeCommands.run(args, "x86_64", configuration, report=False)
commands_mock.assert_called_once_with(pytest.helpers.anyvar(int)) commands_mock.assert_called_once_with(pytest.helpers.anyvar(int))
check_mock.assert_called_once_with(["clean"], ["command"], pytest.helpers.anyvar(int)) check_mock.assert_called_once_with(["clean"], ["command"], pytest.helpers.anyvar(int))

View File

@ -51,15 +51,16 @@ def test_run(args: argparse.Namespace, package_ahriman: Package, configuration:
return_value=[package_ahriman]) return_value=[package_ahriman])
updates_mock = mocker.patch("ahriman.application.application.Application.updates", return_value=[package_ahriman]) updates_mock = mocker.patch("ahriman.application.application.Application.updates", return_value=[package_ahriman])
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start") on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
print_mock = mocker.patch("ahriman.application.application.Application.print_updates")
Update.run(args, "x86_64", configuration, report=False, unsafe=False) Update.run(args, "x86_64", configuration, report=False)
application_mock.assert_called_once_with([package_ahriman], application_mock.assert_called_once_with([package_ahriman],
Packagers(args.username, {package_ahriman.base: "packager"})) Packagers(args.username, {package_ahriman.base: "packager"}))
updates_mock.assert_called_once_with(args.package, aur=args.aur, local=args.local, manual=args.manual, vcs=args.vcs, updates_mock.assert_called_once_with(args.package, aur=args.aur, local=args.local, manual=args.manual, vcs=args.vcs)
log_fn=pytest.helpers.anyvar(int))
dependencies_mock.assert_called_once_with([package_ahriman], process_dependencies=args.dependencies) dependencies_mock.assert_called_once_with([package_ahriman], process_dependencies=args.dependencies)
check_mock.assert_has_calls([MockCall(False, False), MockCall(False, False)]) check_mock.assert_has_calls([MockCall(False, False), MockCall(False, False)])
on_start_mock.assert_called_once_with() on_start_mock.assert_called_once_with()
print_mock.assert_called_once_with([package_ahriman], log_fn=pytest.helpers.anyvar(int))
def test_run_empty_exception(args: argparse.Namespace, configuration: Configuration, repository: Repository, def test_run_empty_exception(args: argparse.Namespace, configuration: Configuration, repository: Repository,
@ -74,7 +75,7 @@ def test_run_empty_exception(args: argparse.Namespace, configuration: Configurat
mocker.patch("ahriman.application.application.Application.updates", return_value=[]) mocker.patch("ahriman.application.application.Application.updates", return_value=[])
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty") check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
Update.run(args, "x86_64", configuration, report=False, unsafe=False) Update.run(args, "x86_64", configuration, report=False)
check_mock.assert_called_once_with(True, True) check_mock.assert_called_once_with(True, True)
@ -89,9 +90,10 @@ def test_run_update_empty_exception(args: argparse.Namespace, package_ahriman: P
mocker.patch("ahriman.application.application.Application.update", return_value=Result()) mocker.patch("ahriman.application.application.Application.update", return_value=Result())
mocker.patch("ahriman.application.application.Application.updates", return_value=[package_ahriman]) mocker.patch("ahriman.application.application.Application.updates", return_value=[package_ahriman])
mocker.patch("ahriman.application.application.Application.with_dependencies", return_value=[package_ahriman]) mocker.patch("ahriman.application.application.Application.with_dependencies", return_value=[package_ahriman])
mocker.patch("ahriman.application.application.Application.print_updates")
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty") check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
Update.run(args, "x86_64", configuration, report=False, unsafe=False) Update.run(args, "x86_64", configuration, report=False)
check_mock.assert_has_calls([MockCall(True, False), MockCall(True, True)]) check_mock.assert_has_calls([MockCall(True, False), MockCall(True, True)])
@ -107,9 +109,8 @@ def test_run_dry_run(args: argparse.Namespace, configuration: Configuration, rep
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty") check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
updates_mock = mocker.patch("ahriman.application.application.Application.updates") updates_mock = mocker.patch("ahriman.application.application.Application.updates")
Update.run(args, "x86_64", configuration, report=False, unsafe=False) Update.run(args, "x86_64", configuration, report=False)
updates_mock.assert_called_once_with(args.package, aur=args.aur, local=args.local, manual=args.manual, vcs=args.vcs, updates_mock.assert_called_once_with(args.package, aur=args.aur, local=args.local, manual=args.manual, vcs=args.vcs)
log_fn=pytest.helpers.anyvar(int))
application_mock.assert_not_called() application_mock.assert_not_called()
check_mock.assert_called_once_with(False, pytest.helpers.anyvar(int)) check_mock.assert_called_once_with(False, pytest.helpers.anyvar(int))

View File

@ -1,14 +1,15 @@
import argparse import argparse
import configparser
import pytest import pytest
from pathlib import Path
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from unittest.mock import call as MockCall from unittest.mock import call as MockCall
from ahriman.application.handlers import Users from ahriman.application.handlers import Users
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.database import SQLite from ahriman.core.database import SQLite
from ahriman.core.exceptions import InitializeError, PasswordError from ahriman.core.exceptions import PasswordError
from ahriman.models.action import Action from ahriman.models.action import Action
from ahriman.models.user import User from ahriman.models.user import User
from ahriman.models.user_access import UserAccess from ahriman.models.user_access import UserAccess
@ -31,7 +32,6 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace:
args.packager = "packager" args.packager = "packager"
args.password = "pa55w0rd" args.password = "pa55w0rd"
args.role = UserAccess.Reporter args.role = UserAccess.Reporter
args.secure = False
return args return args
@ -44,42 +44,44 @@ def test_run(args: argparse.Namespace, configuration: Configuration, database: S
packager_id=args.packager, key=args.key) packager_id=args.packager, key=args.key)
mocker.patch("ahriman.core.database.SQLite.load", return_value=database) mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
mocker.patch("ahriman.models.user.User.hash_password", return_value=user) mocker.patch("ahriman.models.user.User.hash_password", return_value=user)
get_auth_configuration_mock = mocker.patch("ahriman.application.handlers.Users.configuration_get")
create_configuration_mock = mocker.patch("ahriman.application.handlers.Users.configuration_create")
create_user_mock = mocker.patch("ahriman.application.handlers.Users.user_create", return_value=user) create_user_mock = mocker.patch("ahriman.application.handlers.Users.user_create", return_value=user)
get_salt_mock = mocker.patch("ahriman.application.handlers.Users.get_salt", return_value=("salt", "salt"))
update_mock = mocker.patch("ahriman.core.database.SQLite.user_update") update_mock = mocker.patch("ahriman.core.database.SQLite.user_update")
Users.run(args, "x86_64", configuration, report=False, unsafe=False) Users.run(args, "x86_64", configuration, report=False)
get_auth_configuration_mock.assert_not_called()
create_configuration_mock.assert_not_called()
create_user_mock.assert_called_once_with(args) create_user_mock.assert_called_once_with(args)
get_salt_mock.assert_called_once_with(configuration)
update_mock.assert_called_once_with(user) update_mock.assert_called_once_with(user)
def test_run_empty_salt(args: argparse.Namespace, configuration: Configuration, database: SQLite, def test_run_empty_salt(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
mocker: MockerFixture) -> None:
""" """
must create configuration if salt was not set must raise exception if salt is required, but not set
""" """
configuration.remove_option("auth", "salt")
args = _default_args(args) args = _default_args(args)
user = User(username=args.username, password=args.password, access=args.role, user = User(username=args.username, password=args.password, access=args.role,
packager_id=args.packager, key=args.key) packager_id=args.packager, key=args.key)
mocker.patch("ahriman.models.user.User.hash_password", return_value=user)
with pytest.raises(configparser.NoOptionError):
Users.run(args, "x86_64", configuration, report=False)
def test_run_empty_salt_without_password(args: argparse.Namespace, configuration: Configuration, database: SQLite,
mocker: MockerFixture) -> None:
"""
must skip salt option in case if password was empty
"""
configuration.remove_option("auth", "salt")
args = _default_args(args)
user = User(username=args.username, password="", access=args.role,
packager_id=args.packager, key=args.key)
mocker.patch("ahriman.core.database.SQLite.load", return_value=database) mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
mocker.patch("ahriman.models.user.User.hash_password", return_value=user) mocker.patch("ahriman.models.user.User.hash_password", return_value=user)
get_auth_configuration_mock = mocker.patch("ahriman.application.handlers.Users.configuration_get")
create_configuration_mock = mocker.patch("ahriman.application.handlers.Users.configuration_create")
create_user_mock = mocker.patch("ahriman.application.handlers.Users.user_create", return_value=user) create_user_mock = mocker.patch("ahriman.application.handlers.Users.user_create", return_value=user)
get_salt_mock = mocker.patch("ahriman.application.handlers.Users.get_salt", return_value=(None, "salt"))
update_mock = mocker.patch("ahriman.core.database.SQLite.user_update") update_mock = mocker.patch("ahriman.core.database.SQLite.user_update")
Users.run(args, "x86_64", configuration, report=False, unsafe=False) Users.run(args, "x86_64", configuration, report=False)
get_auth_configuration_mock.assert_called_once_with(configuration.include)
create_configuration_mock.assert_called_once_with(
pytest.helpers.anyvar(int), pytest.helpers.anyvar(int), args.secure)
create_user_mock.assert_called_once_with(args) create_user_mock.assert_called_once_with(args)
get_salt_mock.assert_called_once_with(configuration)
update_mock.assert_called_once_with(user) update_mock.assert_called_once_with(user)
@ -94,7 +96,7 @@ def test_run_list(args: argparse.Namespace, configuration: Configuration, databa
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty") check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
list_mock = mocker.patch("ahriman.core.database.SQLite.user_list", return_value=[user]) list_mock = mocker.patch("ahriman.core.database.SQLite.user_list", return_value=[user])
Users.run(args, "x86_64", configuration, report=False, unsafe=False) Users.run(args, "x86_64", configuration, report=False)
list_mock.assert_called_once_with("user", args.role) list_mock.assert_called_once_with("user", args.role)
check_mock.assert_called_once_with(False, False) check_mock.assert_called_once_with(False, False)
@ -111,7 +113,7 @@ def test_run_empty_exception(args: argparse.Namespace, configuration: Configurat
mocker.patch("ahriman.core.database.SQLite.user_list", return_value=[]) mocker.patch("ahriman.core.database.SQLite.user_list", return_value=[])
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty") check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
Users.run(args, "x86_64", configuration, report=False, unsafe=False) Users.run(args, "x86_64", configuration, report=False)
check_mock.assert_called_once_with(True, True) check_mock.assert_called_once_with(True, True)
@ -125,90 +127,10 @@ def test_run_remove(args: argparse.Namespace, configuration: Configuration, data
mocker.patch("ahriman.core.database.SQLite.load", return_value=database) mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
remove_mock = mocker.patch("ahriman.core.database.SQLite.user_remove") remove_mock = mocker.patch("ahriman.core.database.SQLite.user_remove")
Users.run(args, "x86_64", configuration, report=False, unsafe=False) Users.run(args, "x86_64", configuration, report=False)
remove_mock.assert_called_once_with(args.username) remove_mock.assert_called_once_with(args.username)
def test_configuration_create(configuration: Configuration, mocker: MockerFixture) -> None:
"""
must correctly create configuration file
"""
mocker.patch("pathlib.Path.open")
set_mock = mocker.patch("ahriman.core.configuration.Configuration.set_option")
write_mock = mocker.patch("ahriman.application.handlers.Users.configuration_write")
Users.configuration_create(configuration, "salt", False)
set_mock.assert_called_once_with("auth", "salt", pytest.helpers.anyvar(int))
write_mock.assert_called_once_with(configuration, False)
def test_configuration_get(mocker: MockerFixture) -> None:
"""
must load configuration from filesystem
"""
mocker.patch("pathlib.Path.open")
mocker.patch("pathlib.Path.is_file", return_value=True)
read_mock = mocker.patch("ahriman.core.configuration.Configuration.read")
assert Users.configuration_get(Path("path"))
read_mock.assert_called_once_with(Path("path") / "00-auth.ini")
def test_configuration_write(configuration: Configuration, mocker: MockerFixture) -> None:
"""
must write configuration
"""
mocker.patch("pathlib.Path.open")
write_mock = mocker.patch("ahriman.core.configuration.Configuration.write")
chmod_mock = mocker.patch("pathlib.Path.chmod")
Users.configuration_write(configuration, secure=True)
write_mock.assert_called_once_with(pytest.helpers.anyvar(int))
chmod_mock.assert_called_once_with(0o600)
def test_configuration_write_insecure(configuration: Configuration, mocker: MockerFixture) -> None:
"""
must write configuration without setting file permissions
"""
mocker.patch("pathlib.Path.open")
mocker.patch("ahriman.core.configuration.Configuration.write")
chmod_mock = mocker.patch("pathlib.Path.chmod")
Users.configuration_write(configuration, secure=False)
chmod_mock.assert_not_called()
def test_configuration_write_not_loaded(configuration: Configuration, mocker: MockerFixture) -> None:
"""
must do nothing in case if configuration is not loaded
"""
configuration.path = None
mocker.patch("pathlib.Path.open")
with pytest.raises(InitializeError):
Users.configuration_write(configuration, secure=True)
def test_get_salt_read(configuration: Configuration) -> None:
"""
must read salt from configuration
"""
assert Users.get_salt(configuration) == ("salt", "salt")
def test_get_salt_generate(configuration: Configuration) -> None:
"""
must generate salt if it does not exist
"""
configuration.remove_option("auth", "salt")
old_salt, salt = Users.get_salt(configuration, 16)
assert salt
assert old_salt is None
assert len(salt) == 16
def test_user_create(args: argparse.Namespace, user: User) -> None: def test_user_create(args: argparse.Namespace, user: User) -> None:
""" """
must create user must create user

View File

@ -33,7 +33,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
print_mock = mocker.patch("ahriman.core.formatters.Printer.print") print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
application_mock = mocker.patch("ahriman.core.configuration.validator.Validator.validate", return_value=False) application_mock = mocker.patch("ahriman.core.configuration.validator.Validator.validate", return_value=False)
Validate.run(args, "x86_64", configuration, report=False, unsafe=False) Validate.run(args, "x86_64", configuration, report=False)
application_mock.assert_called_once_with(configuration.dump()) application_mock.assert_called_once_with(configuration.dump())
print_mock.assert_called_once_with(verbose=True) print_mock.assert_called_once_with(verbose=True)
@ -47,7 +47,7 @@ def test_run_skip(args: argparse.Namespace, configuration: Configuration, mocker
mocker.patch("ahriman.core.configuration.validator.Validator.validate", return_value=True) mocker.patch("ahriman.core.configuration.validator.Validator.validate", return_value=True)
print_mock = mocker.patch("ahriman.core.formatters.Printer.print") print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
Validate.run(args, "x86_64", configuration, report=False, unsafe=False) Validate.run(args, "x86_64", configuration, report=False)
print_mock.assert_not_called() print_mock.assert_not_called()

View File

@ -14,7 +14,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
application_mock = mocker.patch("ahriman.application.handlers.Versions.package_dependencies") application_mock = mocker.patch("ahriman.application.handlers.Versions.package_dependencies")
print_mock = mocker.patch("ahriman.core.formatters.Printer.print") print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
Versions.run(args, "x86_64", configuration, report=False, unsafe=False) Versions.run(args, "x86_64", configuration, report=False)
application_mock.assert_called_once_with("ahriman") application_mock.assert_called_once_with("ahriman")
print_mock.assert_has_calls([MockCall(verbose=False, separator=" "), MockCall(verbose=False, separator=" ")]) print_mock.assert_has_calls([MockCall(verbose=False, separator=" "), MockCall(verbose=False, separator=" ")])

View File

@ -41,7 +41,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
stop_mock = mocker.patch("ahriman.core.spawn.Spawn.stop") stop_mock = mocker.patch("ahriman.core.spawn.Spawn.stop")
join_mock = mocker.patch("ahriman.core.spawn.Spawn.join") join_mock = mocker.patch("ahriman.core.spawn.Spawn.join")
Web.run(args, "x86_64", configuration, report=False, unsafe=False) Web.run(args, "x86_64", configuration, report=False)
setup_mock.assert_called_once_with("x86_64", configuration, pytest.helpers.anyvar(int)) setup_mock.assert_called_once_with("x86_64", configuration, pytest.helpers.anyvar(int))
run_mock.assert_called_once_with(pytest.helpers.anyvar(int)) run_mock.assert_called_once_with(pytest.helpers.anyvar(int))
start_mock.assert_called_once_with() start_mock.assert_called_once_with()

View File

@ -57,8 +57,11 @@ def test_check_user(lock: Lock, mocker: MockerFixture) -> None:
must check user correctly must check user correctly
""" """
check_user_patch = mocker.patch("ahriman.application.lock.check_user") check_user_patch = mocker.patch("ahriman.application.lock.check_user")
tree_create = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
lock.check_user() lock.check_user()
check_user_patch.assert_called_once_with(lock.paths, unsafe=False) check_user_patch.assert_called_once_with(lock.paths, unsafe=False)
tree_create.assert_called_once_with()
def test_check_user_exception(lock: Lock, mocker: MockerFixture) -> None: def test_check_user_exception(lock: Lock, mocker: MockerFixture) -> None:
@ -70,10 +73,11 @@ def test_check_user_exception(lock: Lock, mocker: MockerFixture) -> None:
lock.check_user() lock.check_user()
def test_check_user_unsafe(lock: Lock) -> None: def test_check_user_unsafe(lock: Lock, mocker: MockerFixture) -> None:
""" """
must skip user check if unsafe flag set must skip user check if unsafe flag set
""" """
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
lock.unsafe = True lock.unsafe = True
lock.check_user() lock.check_user()

View File

@ -443,9 +443,8 @@ def repository(configuration: Configuration, database: SQLite, mocker: MockerFix
Returns: Returns:
Repository: repository test instance Repository: repository test instance
""" """
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
mocker.patch("ahriman.core.repository.Repository._set_context") mocker.patch("ahriman.core.repository.Repository._set_context")
return Repository.load("x86_64", configuration, database, report=False, unsafe=False) return Repository.load("x86_64", configuration, database, report=False)
@pytest.fixture @pytest.fixture

View File

@ -80,6 +80,7 @@ def test_make_request(aur: AUR, aur_package_ahriman: AURPackage,
request_mock.assert_called_once_with( request_mock.assert_called_once_with(
"https://aur.archlinux.org/rpc", "https://aur.archlinux.org/rpc",
params={"v": "5", "type": "info", "arg": ["ahriman"]}, params={"v": "5", "type": "info", "arg": ["ahriman"]},
headers={"User-Agent": AUR.DEFAULT_USER_AGENT},
timeout=aur.DEFAULT_TIMEOUT) timeout=aur.DEFAULT_TIMEOUT)
@ -96,6 +97,7 @@ def test_make_request_multi_arg(aur: AUR, aur_package_ahriman: AURPackage,
request_mock.assert_called_once_with( request_mock.assert_called_once_with(
"https://aur.archlinux.org/rpc", "https://aur.archlinux.org/rpc",
params={"v": "5", "type": "search", "arg[]": ["ahriman", "is", "cool"]}, params={"v": "5", "type": "search", "arg[]": ["ahriman", "is", "cool"]},
headers={"User-Agent": AUR.DEFAULT_USER_AGENT},
timeout=aur.DEFAULT_TIMEOUT) timeout=aur.DEFAULT_TIMEOUT)
@ -112,6 +114,7 @@ def test_make_request_with_kwargs(aur: AUR, aur_package_ahriman: AURPackage,
request_mock.assert_called_once_with( request_mock.assert_called_once_with(
"https://aur.archlinux.org/rpc", "https://aur.archlinux.org/rpc",
params={"v": "5", "type": "search", "arg": ["ahriman"], "by": "name"}, params={"v": "5", "type": "search", "arg": ["ahriman"], "by": "name"},
headers={"User-Agent": AUR.DEFAULT_USER_AGENT},
timeout=aur.DEFAULT_TIMEOUT) timeout=aur.DEFAULT_TIMEOUT)

View File

@ -75,6 +75,7 @@ def test_make_request(official: Official, aur_package_akonadi: AURPackage,
request_mock.assert_called_once_with( request_mock.assert_called_once_with(
"https://archlinux.org/packages/search/json", "https://archlinux.org/packages/search/json",
params={"q": ("akonadi",), "repo": Official.DEFAULT_SEARCH_REPOSITORIES}, params={"q": ("akonadi",), "repo": Official.DEFAULT_SEARCH_REPOSITORIES},
headers={"User-Agent": Official.DEFAULT_USER_AGENT},
timeout=official.DEFAULT_TIMEOUT) timeout=official.DEFAULT_TIMEOUT)

View File

@ -1,7 +1,10 @@
import pytest import pytest
from ahriman.core.formatters import AurPrinter, ConfigurationPrinter, PackagePrinter, PatchPrinter, StatusPrinter, \ from pathlib import Path
StringPrinter, TreePrinter, UpdatePrinter, UserPrinter, ValidationPrinter, VersionPrinter
from ahriman.core.formatters import AurPrinter, ConfigurationPrinter, ConfigurationPathsPrinter, PackagePrinter,\
PatchPrinter, StatusPrinter, StringPrinter, TreePrinter, UpdatePrinter, UserPrinter, ValidationPrinter, \
VersionPrinter
from ahriman.models.aur_package import AURPackage from ahriman.models.aur_package import AURPackage
from ahriman.models.build_status import BuildStatus from ahriman.models.build_status import BuildStatus
from ahriman.models.package import Package from ahriman.models.package import Package
@ -23,6 +26,17 @@ def aur_package_ahriman_printer(aur_package_ahriman: AURPackage) -> AurPrinter:
return AurPrinter(aur_package_ahriman) return AurPrinter(aur_package_ahriman)
@pytest.fixture
def configuration_paths_printer() -> ConfigurationPathsPrinter:
"""
fixture for configuration paths printer
Returns:
ConfigurationPathsPrinter: configuration paths printer test instance
"""
return ConfigurationPathsPrinter(Path("root"), [Path("include1"), Path("include2")])
@pytest.fixture @pytest.fixture
def configuration_printer() -> ConfigurationPrinter: def configuration_printer() -> ConfigurationPrinter:
""" """

View File

@ -0,0 +1,15 @@
from ahriman.core.formatters import ConfigurationPathsPrinter
def test_properties(configuration_paths_printer: ConfigurationPathsPrinter) -> None:
"""
must return non-empty properties list
"""
assert configuration_paths_printer.properties()
def test_title(configuration_paths_printer: ConfigurationPathsPrinter) -> None:
"""
must return non-empty title
"""
assert configuration_paths_printer.title() is not None

Some files were not shown because too many files have changed in this diff Show More