mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-04-24 15:27:17 +00:00
packagers support (#100)
This commit is contained in:
parent
cbd1d3d5b8
commit
4dd5a1e82e
@ -58,7 +58,7 @@ systemd-machine-id-setup &> /dev/null
|
|||||||
# otherwise we prepend executable by sudo command
|
# otherwise we prepend executable by sudo command
|
||||||
if [ -n "$AHRIMAN_FORCE_ROOT" ]; then
|
if [ -n "$AHRIMAN_FORCE_ROOT" ]; then
|
||||||
AHRIMAN_EXECUTABLE=("ahriman")
|
AHRIMAN_EXECUTABLE=("ahriman")
|
||||||
elif ahriman help-commands-unsafe --command="$*" &> /dev/null; then
|
elif ahriman help-commands-unsafe -- "$@" &> /dev/null; then
|
||||||
AHRIMAN_EXECUTABLE=("sudo" "-u" "$AHRIMAN_USER" "--" "ahriman")
|
AHRIMAN_EXECUTABLE=("sudo" "-u" "$AHRIMAN_USER" "--" "ahriman")
|
||||||
else
|
else
|
||||||
AHRIMAN_EXECUTABLE=("ahriman")
|
AHRIMAN_EXECUTABLE=("ahriman")
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
.TH AHRIMAN "1" "2023\-05\-28" "ahriman" "Generated Python Manual"
|
.TH AHRIMAN "1" "2023\-06\-03" "ahriman" "Generated Python Manual"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
ahriman
|
ahriman
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
@ -199,13 +199,12 @@ show help message for application or command and exit
|
|||||||
show help message for specific command
|
show help message for specific command
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman help\-commands\-unsafe'\/\fR
|
.SH COMMAND \fI\,'ahriman help\-commands\-unsafe'\/\fR
|
||||||
usage: ahriman help\-commands\-unsafe [\-h] [\-\-command COMMAND]
|
usage: ahriman help\-commands\-unsafe [\-h] [command ...]
|
||||||
|
|
||||||
list unsafe commands as defined in default args
|
list unsafe commands as defined in default args
|
||||||
|
|
||||||
.SH OPTIONS \fI\,'ahriman help\-commands\-unsafe'\/\fR
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-command\fR \fI\,COMMAND\/\fR
|
\fBcommand\fR
|
||||||
instead of showing commands, just test command line for unsafe subcommand and return 0 in case if command is safe and 1
|
instead of showing commands, just test command line for unsafe subcommand and return 0 in case if command is safe and 1
|
||||||
otherwise
|
otherwise
|
||||||
|
|
||||||
@ -226,7 +225,7 @@ print application and its dependencies versions
|
|||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman package\-add'\/\fR
|
.SH COMMAND \fI\,'ahriman package\-add'\/\fR
|
||||||
usage: ahriman package\-add [\-h] [\-\-dependencies | \-\-no\-dependencies] [\-e] [\-n] [\-y]
|
usage: ahriman package\-add [\-h] [\-\-dependencies | \-\-no\-dependencies] [\-e] [\-n] [\-y]
|
||||||
[\-s {auto,archive,aur,directory,local,remote,repository}]
|
[\-s {auto,archive,aur,directory,local,remote,repository}] [\-u USERNAME]
|
||||||
package [package ...]
|
package [package ...]
|
||||||
|
|
||||||
add existing or new package to the build queue
|
add existing or new package to the build queue
|
||||||
@ -256,6 +255,10 @@ download fresh package databases from the mirror before actions, \-yy to force r
|
|||||||
\fB\-s\fR \fI\,{auto,archive,aur,directory,local,remote,repository}\/\fR, \fB\-\-source\fR \fI\,{auto,archive,aur,directory,local,remote,repository}\/\fR
|
\fB\-s\fR \fI\,{auto,archive,aur,directory,local,remote,repository}\/\fR, \fB\-\-source\fR \fI\,{auto,archive,aur,directory,local,remote,repository}\/\fR
|
||||||
explicitly specify the package source for this command
|
explicitly specify the package source for this command
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fB\-u\fR \fI\,USERNAME\/\fR, \fB\-\-username\fR \fI\,USERNAME\/\fR
|
||||||
|
build as user
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman package\-remove'\/\fR
|
.SH COMMAND \fI\,'ahriman package\-remove'\/\fR
|
||||||
usage: ahriman package\-remove [\-h] package [package ...]
|
usage: ahriman package\-remove [\-h] package [package ...]
|
||||||
|
|
||||||
@ -457,7 +460,7 @@ download fresh package databases from the mirror before actions, \-yy to force r
|
|||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman repo\-rebuild'\/\fR
|
.SH COMMAND \fI\,'ahriman repo\-rebuild'\/\fR
|
||||||
usage: ahriman repo\-rebuild [\-h] [\-\-depends\-on DEPENDS_ON] [\-\-dry\-run] [\-\-from\-database] [\-e]
|
usage: ahriman repo\-rebuild [\-h] [\-\-depends\-on DEPENDS_ON] [\-\-dry\-run] [\-\-from\-database] [\-e]
|
||||||
[\-s {unknown,pending,building,failed,success}]
|
[\-s {unknown,pending,building,failed,success}] [\-u USERNAME]
|
||||||
|
|
||||||
force rebuild whole repository
|
force rebuild whole repository
|
||||||
|
|
||||||
@ -484,6 +487,10 @@ return non\-zero exit status if result is empty
|
|||||||
\fB\-s\fR \fI\,{unknown,pending,building,failed,success}\/\fR, \fB\-\-status\fR \fI\,{unknown,pending,building,failed,success}\/\fR
|
\fB\-s\fR \fI\,{unknown,pending,building,failed,success}\/\fR, \fB\-\-status\fR \fI\,{unknown,pending,building,failed,success}\/\fR
|
||||||
filter packages by status. Requires \-\-from\-database to be set
|
filter packages by status. Requires \-\-from\-database to be set
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fB\-u\fR \fI\,USERNAME\/\fR, \fB\-\-username\fR \fI\,USERNAME\/\fR
|
||||||
|
build as user
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman repo\-remove\-unknown'\/\fR
|
.SH COMMAND \fI\,'ahriman repo\-remove\-unknown'\/\fR
|
||||||
usage: ahriman repo\-remove\-unknown [\-h] [\-\-dry\-run]
|
usage: ahriman repo\-remove\-unknown [\-h] [\-\-dry\-run]
|
||||||
|
|
||||||
@ -553,7 +560,7 @@ instead of running all triggers as set by configuration, just process specified
|
|||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman repo\-update'\/\fR
|
.SH COMMAND \fI\,'ahriman repo\-update'\/\fR
|
||||||
usage: ahriman repo\-update [\-h] [\-\-aur | \-\-no\-aur] [\-\-dependencies | \-\-no\-dependencies] [\-\-dry\-run] [\-e]
|
usage: ahriman repo\-update [\-h] [\-\-aur | \-\-no\-aur] [\-\-dependencies | \-\-no\-dependencies] [\-\-dry\-run] [\-e]
|
||||||
[\-\-local | \-\-no\-local] [\-\-manual | \-\-no\-manual] [\-\-vcs | \-\-no\-vcs] [\-y]
|
[\-\-local | \-\-no\-local] [\-\-manual | \-\-no\-manual] [\-u USERNAME] [\-\-vcs | \-\-no\-vcs] [\-y]
|
||||||
[package ...]
|
[package ...]
|
||||||
|
|
||||||
check for packages updates and run build process if requested
|
check for packages updates and run build process if requested
|
||||||
@ -587,6 +594,10 @@ enable or disable checking of local packages for updates
|
|||||||
\fB\-\-manual\fR, \fB\-\-no\-manual\fR
|
\fB\-\-manual\fR, \fB\-\-no\-manual\fR
|
||||||
include or exclude manual updates
|
include or exclude manual updates
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fB\-u\fR \fI\,USERNAME\/\fR, \fB\-\-username\fR \fI\,USERNAME\/\fR
|
||||||
|
build as user
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-vcs\fR, \fB\-\-no\-vcs\fR
|
\fB\-\-vcs\fR, \fB\-\-no\-vcs\fR
|
||||||
fetch actual version of VCS packages
|
fetch actual version of VCS packages
|
||||||
@ -724,7 +735,8 @@ 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] [\-p PASSWORD] [\-r {unauthorized,read,reporter,full}] [\-s] username
|
usage: ahriman user\-add [\-h] [\-\-key KEY] [\-\-packager PACKAGER] [\-p PASSWORD] [\-r {unauthorized,read,reporter,full}] [\-s]
|
||||||
|
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
|
||||||
|
|
||||||
@ -733,6 +745,14 @@ update user for web services with the given password and role. In case if passwo
|
|||||||
username for web service
|
username for web service
|
||||||
|
|
||||||
.SH OPTIONS \fI\,'ahriman user\-add'\/\fR
|
.SH OPTIONS \fI\,'ahriman user\-add'\/\fR
|
||||||
|
.TP
|
||||||
|
\fB\-\-key\fR \fI\,KEY\/\fR
|
||||||
|
optional PGP key used by this user. The private key must be imported
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fB\-\-packager\fR \fI\,PACKAGER\/\fR
|
||||||
|
optional packager id used for build process in form of `Name Surname <mail@example.com>`
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-p\fR \fI\,PASSWORD\/\fR, \fB\-\-password\fR \fI\,PASSWORD\/\fR
|
\fB\-p\fR \fI\,PASSWORD\/\fR, \fB\-\-password\fR \fI\,PASSWORD\/\fR
|
||||||
user password. Blank password will be treated as empty password, which is in particular must be used for OAuth2
|
user password. Blank password will be treated as empty password, which is in particular must be used for OAuth2
|
||||||
|
@ -68,6 +68,14 @@ ahriman.core.database.migrations.m007\_check\_depends module
|
|||||||
:no-undoc-members:
|
:no-undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
ahriman.core.database.migrations.m008\_packagers module
|
||||||
|
-------------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.database.migrations.m008_packagers
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
Module contents
|
Module contents
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
@ -116,6 +116,14 @@ ahriman.models.package\_source module
|
|||||||
:no-undoc-members:
|
:no-undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
ahriman.models.packagers module
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.models.packagers
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
ahriman.models.pacman\_synchronization module
|
ahriman.models.pacman\_synchronization module
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|
|
||||||
|
@ -6,13 +6,13 @@ _shtab_ahriman_option_strings=('-h' '--help' '-a' '--architecture' '-c' '--confi
|
|||||||
_shtab_ahriman_aur_search_option_strings=('-h' '--help' '-e' '--exit-code' '--info' '--no-info' '--sort-by')
|
_shtab_ahriman_aur_search_option_strings=('-h' '--help' '-e' '--exit-code' '--info' '--no-info' '--sort-by')
|
||||||
_shtab_ahriman_search_option_strings=('-h' '--help' '-e' '--exit-code' '--info' '--no-info' '--sort-by')
|
_shtab_ahriman_search_option_strings=('-h' '--help' '-e' '--exit-code' '--info' '--no-info' '--sort-by')
|
||||||
_shtab_ahriman_help_option_strings=('-h' '--help')
|
_shtab_ahriman_help_option_strings=('-h' '--help')
|
||||||
_shtab_ahriman_help_commands_unsafe_option_strings=('-h' '--help' '--command')
|
_shtab_ahriman_help_commands_unsafe_option_strings=('-h' '--help')
|
||||||
_shtab_ahriman_help_updates_option_strings=('-h' '--help' '-e' '--exit-code')
|
_shtab_ahriman_help_updates_option_strings=('-h' '--help' '-e' '--exit-code')
|
||||||
_shtab_ahriman_help_version_option_strings=('-h' '--help')
|
_shtab_ahriman_help_version_option_strings=('-h' '--help')
|
||||||
_shtab_ahriman_version_option_strings=('-h' '--help')
|
_shtab_ahriman_version_option_strings=('-h' '--help')
|
||||||
_shtab_ahriman_package_add_option_strings=('-h' '--help' '--dependencies' '--no-dependencies' '-e' '--exit-code' '-n' '--now' '-y' '--refresh' '-s' '--source')
|
_shtab_ahriman_package_add_option_strings=('-h' '--help' '--dependencies' '--no-dependencies' '-e' '--exit-code' '-n' '--now' '-y' '--refresh' '-s' '--source' '-u' '--username')
|
||||||
_shtab_ahriman_add_option_strings=('-h' '--help' '--dependencies' '--no-dependencies' '-e' '--exit-code' '-n' '--now' '-y' '--refresh' '-s' '--source')
|
_shtab_ahriman_add_option_strings=('-h' '--help' '--dependencies' '--no-dependencies' '-e' '--exit-code' '-n' '--now' '-y' '--refresh' '-s' '--source' '-u' '--username')
|
||||||
_shtab_ahriman_package_update_option_strings=('-h' '--help' '--dependencies' '--no-dependencies' '-e' '--exit-code' '-n' '--now' '-y' '--refresh' '-s' '--source')
|
_shtab_ahriman_package_update_option_strings=('-h' '--help' '--dependencies' '--no-dependencies' '-e' '--exit-code' '-n' '--now' '-y' '--refresh' '-s' '--source' '-u' '--username')
|
||||||
_shtab_ahriman_package_remove_option_strings=('-h' '--help')
|
_shtab_ahriman_package_remove_option_strings=('-h' '--help')
|
||||||
_shtab_ahriman_remove_option_strings=('-h' '--help')
|
_shtab_ahriman_remove_option_strings=('-h' '--help')
|
||||||
_shtab_ahriman_package_status_option_strings=('-h' '--help' '--ahriman' '-e' '--exit-code' '--info' '--no-info' '-s' '--status')
|
_shtab_ahriman_package_status_option_strings=('-h' '--help' '--ahriman' '-e' '--exit-code' '--info' '--no-info' '-s' '--status')
|
||||||
@ -31,8 +31,8 @@ _shtab_ahriman_repo_create_keyring_option_strings=('-h' '--help')
|
|||||||
_shtab_ahriman_repo_create_mirrorlist_option_strings=('-h' '--help')
|
_shtab_ahriman_repo_create_mirrorlist_option_strings=('-h' '--help')
|
||||||
_shtab_ahriman_repo_daemon_option_strings=('-h' '--help' '-i' '--interval' '--aur' '--no-aur' '--dependencies' '--no-dependencies' '--local' '--no-local' '--manual' '--no-manual' '--vcs' '--no-vcs' '-y' '--refresh')
|
_shtab_ahriman_repo_daemon_option_strings=('-h' '--help' '-i' '--interval' '--aur' '--no-aur' '--dependencies' '--no-dependencies' '--local' '--no-local' '--manual' '--no-manual' '--vcs' '--no-vcs' '-y' '--refresh')
|
||||||
_shtab_ahriman_daemon_option_strings=('-h' '--help' '-i' '--interval' '--aur' '--no-aur' '--dependencies' '--no-dependencies' '--local' '--no-local' '--manual' '--no-manual' '--vcs' '--no-vcs' '-y' '--refresh')
|
_shtab_ahriman_daemon_option_strings=('-h' '--help' '-i' '--interval' '--aur' '--no-aur' '--dependencies' '--no-dependencies' '--local' '--no-local' '--manual' '--no-manual' '--vcs' '--no-vcs' '-y' '--refresh')
|
||||||
_shtab_ahriman_repo_rebuild_option_strings=('-h' '--help' '--depends-on' '--dry-run' '--from-database' '-e' '--exit-code' '-s' '--status')
|
_shtab_ahriman_repo_rebuild_option_strings=('-h' '--help' '--depends-on' '--dry-run' '--from-database' '-e' '--exit-code' '-s' '--status' '-u' '--username')
|
||||||
_shtab_ahriman_rebuild_option_strings=('-h' '--help' '--depends-on' '--dry-run' '--from-database' '-e' '--exit-code' '-s' '--status')
|
_shtab_ahriman_rebuild_option_strings=('-h' '--help' '--depends-on' '--dry-run' '--from-database' '-e' '--exit-code' '-s' '--status' '-u' '--username')
|
||||||
_shtab_ahriman_repo_remove_unknown_option_strings=('-h' '--help' '--dry-run')
|
_shtab_ahriman_repo_remove_unknown_option_strings=('-h' '--help' '--dry-run')
|
||||||
_shtab_ahriman_remove_unknown_option_strings=('-h' '--help' '--dry-run')
|
_shtab_ahriman_remove_unknown_option_strings=('-h' '--help' '--dry-run')
|
||||||
_shtab_ahriman_repo_report_option_strings=('-h' '--help')
|
_shtab_ahriman_repo_report_option_strings=('-h' '--help')
|
||||||
@ -45,8 +45,8 @@ _shtab_ahriman_repo_sync_option_strings=('-h' '--help')
|
|||||||
_shtab_ahriman_sync_option_strings=('-h' '--help')
|
_shtab_ahriman_sync_option_strings=('-h' '--help')
|
||||||
_shtab_ahriman_repo_tree_option_strings=('-h' '--help')
|
_shtab_ahriman_repo_tree_option_strings=('-h' '--help')
|
||||||
_shtab_ahriman_repo_triggers_option_strings=('-h' '--help')
|
_shtab_ahriman_repo_triggers_option_strings=('-h' '--help')
|
||||||
_shtab_ahriman_repo_update_option_strings=('-h' '--help' '--aur' '--no-aur' '--dependencies' '--no-dependencies' '--dry-run' '-e' '--exit-code' '--local' '--no-local' '--manual' '--no-manual' '--vcs' '--no-vcs' '-y' '--refresh')
|
_shtab_ahriman_repo_update_option_strings=('-h' '--help' '--aur' '--no-aur' '--dependencies' '--no-dependencies' '--dry-run' '-e' '--exit-code' '--local' '--no-local' '--manual' '--no-manual' '-u' '--username' '--vcs' '--no-vcs' '-y' '--refresh')
|
||||||
_shtab_ahriman_update_option_strings=('-h' '--help' '--aur' '--no-aur' '--dependencies' '--no-dependencies' '--dry-run' '-e' '--exit-code' '--local' '--no-local' '--manual' '--no-manual' '--vcs' '--no-vcs' '-y' '--refresh')
|
_shtab_ahriman_update_option_strings=('-h' '--help' '--aur' '--no-aur' '--dependencies' '--no-dependencies' '--dry-run' '-e' '--exit-code' '--local' '--no-local' '--manual' '--no-manual' '-u' '--username' '--vcs' '--no-vcs' '-y' '--refresh')
|
||||||
_shtab_ahriman_service_clean_option_strings=('-h' '--help' '--cache' '--no-cache' '--chroot' '--no-chroot' '--manual' '--no-manual' '--packages' '--no-packages' '--pacman' '--no-pacman')
|
_shtab_ahriman_service_clean_option_strings=('-h' '--help' '--cache' '--no-cache' '--chroot' '--no-chroot' '--manual' '--no-manual' '--packages' '--no-packages' '--pacman' '--no-pacman')
|
||||||
_shtab_ahriman_clean_option_strings=('-h' '--help' '--cache' '--no-cache' '--chroot' '--no-chroot' '--manual' '--no-manual' '--packages' '--no-packages' '--pacman' '--no-pacman')
|
_shtab_ahriman_clean_option_strings=('-h' '--help' '--cache' '--no-cache' '--chroot' '--no-chroot' '--manual' '--no-manual' '--packages' '--no-packages' '--pacman' '--no-pacman')
|
||||||
_shtab_ahriman_repo_clean_option_strings=('-h' '--help' '--cache' '--no-cache' '--chroot' '--no-chroot' '--manual' '--no-manual' '--packages' '--no-packages' '--pacman' '--no-pacman')
|
_shtab_ahriman_repo_clean_option_strings=('-h' '--help' '--cache' '--no-cache' '--chroot' '--no-chroot' '--manual' '--no-manual' '--packages' '--no-packages' '--pacman' '--no-pacman')
|
||||||
@ -65,7 +65,7 @@ _shtab_ahriman_repo_setup_option_strings=('-h' '--help' '--build-as-user' '--bui
|
|||||||
_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' '--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' '-p' '--password' '-r' '--role' '-s' '--secure')
|
_shtab_ahriman_user_add_option_strings=('-h' '--help' '--key' '--packager' '-p' '--password' '-r' '--role' '-s' '--secure')
|
||||||
_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')
|
||||||
@ -133,6 +133,7 @@ _shtab_ahriman_search___info_nargs=0
|
|||||||
_shtab_ahriman_search___no_info_nargs=0
|
_shtab_ahriman_search___no_info_nargs=0
|
||||||
_shtab_ahriman_help__h_nargs=0
|
_shtab_ahriman_help__h_nargs=0
|
||||||
_shtab_ahriman_help___help_nargs=0
|
_shtab_ahriman_help___help_nargs=0
|
||||||
|
_shtab_ahriman_help_commands_unsafe_pos_0_nargs=*
|
||||||
_shtab_ahriman_help_commands_unsafe__h_nargs=0
|
_shtab_ahriman_help_commands_unsafe__h_nargs=0
|
||||||
_shtab_ahriman_help_commands_unsafe___help_nargs=0
|
_shtab_ahriman_help_commands_unsafe___help_nargs=0
|
||||||
_shtab_ahriman_help_updates__h_nargs=0
|
_shtab_ahriman_help_updates__h_nargs=0
|
||||||
|
@ -95,6 +95,7 @@ _shtab_ahriman_add_options=(
|
|||||||
{-n,--now}"[run update function after]"
|
{-n,--now}"[run update function after]"
|
||||||
"*"{-y,--refresh}"[download fresh package databases from the mirror before actions, -yy to force refresh even if up to date]"
|
"*"{-y,--refresh}"[download fresh package databases from the mirror before actions, -yy to force refresh even if up to date]"
|
||||||
{-s,--source}"[explicitly specify the package source for this command]:source:(auto archive aur directory local remote repository)"
|
{-s,--source}"[explicitly specify the package source for this command]:source:(auto archive aur directory local remote repository)"
|
||||||
|
{-u,--username}"[build as user]:username:"
|
||||||
"(*):package source (base name, path to local files, remote URL):"
|
"(*):package source (base name, path to local files, remote URL):"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -151,7 +152,7 @@ _shtab_ahriman_help_options=(
|
|||||||
|
|
||||||
_shtab_ahriman_help_commands_unsafe_options=(
|
_shtab_ahriman_help_commands_unsafe_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
"--command[instead of showing commands, just test command line for unsafe subcommand and return 0 in case if command is safe and 1 otherwise]:command:"
|
"(*)::instead of showing commands, just test command line for unsafe subcommand and return 0 in case if command is safe and 1 otherwise:"
|
||||||
)
|
)
|
||||||
|
|
||||||
_shtab_ahriman_help_updates_options=(
|
_shtab_ahriman_help_updates_options=(
|
||||||
@ -192,6 +193,7 @@ _shtab_ahriman_package_add_options=(
|
|||||||
{-n,--now}"[run update function after]"
|
{-n,--now}"[run update function after]"
|
||||||
"*"{-y,--refresh}"[download fresh package databases from the mirror before actions, -yy to force refresh even if up to date]"
|
"*"{-y,--refresh}"[download fresh package databases from the mirror before actions, -yy to force refresh even if up to date]"
|
||||||
{-s,--source}"[explicitly specify the package source for this command]:source:(auto archive aur directory local remote repository)"
|
{-s,--source}"[explicitly specify the package source for this command]:source:(auto archive aur directory local remote repository)"
|
||||||
|
{-u,--username}"[build as user]:username:"
|
||||||
"(*):package source (base name, path to local files, remote URL):"
|
"(*):package source (base name, path to local files, remote URL):"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -227,6 +229,7 @@ _shtab_ahriman_package_update_options=(
|
|||||||
{-n,--now}"[run update function after]"
|
{-n,--now}"[run update function after]"
|
||||||
"*"{-y,--refresh}"[download fresh package databases from the mirror before actions, -yy to force refresh even if up to date]"
|
"*"{-y,--refresh}"[download fresh package databases from the mirror before actions, -yy to force refresh even if up to date]"
|
||||||
{-s,--source}"[explicitly specify the package source for this command]:source:(auto archive aur directory local remote repository)"
|
{-s,--source}"[explicitly specify the package source for this command]:source:(auto archive aur directory local remote repository)"
|
||||||
|
{-u,--username}"[build as user]:username:"
|
||||||
"(*):package source (base name, path to local files, remote URL):"
|
"(*):package source (base name, path to local files, remote URL):"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -263,6 +266,7 @@ _shtab_ahriman_rebuild_options=(
|
|||||||
"--from-database[read packages from database instead of filesystem. This feature in particular is required in case if you would like to restore repository from another repository instance. Note, however, that in order to restore packages you need to have original ahriman instance run with web service and have run repo-update at least once.]"
|
"--from-database[read packages from database instead of filesystem. This feature in particular is required in case if you would like to restore repository from another repository instance. Note, however, that in order to restore packages you need to have original ahriman instance run with web service and have run repo-update at least once.]"
|
||||||
{-e,--exit-code}"[return non-zero exit status if result is empty]"
|
{-e,--exit-code}"[return non-zero exit status if result is empty]"
|
||||||
{-s,--status}"[filter packages by status. Requires --from-database to be set]:status:(unknown pending building failed success)"
|
{-s,--status}"[filter packages by status. Requires --from-database to be set]:status:(unknown pending building failed success)"
|
||||||
|
{-u,--username}"[build as user]:username:"
|
||||||
)
|
)
|
||||||
|
|
||||||
_shtab_ahriman_remove_options=(
|
_shtab_ahriman_remove_options=(
|
||||||
@ -349,6 +353,7 @@ _shtab_ahriman_repo_rebuild_options=(
|
|||||||
"--from-database[read packages from database instead of filesystem. This feature in particular is required in case if you would like to restore repository from another repository instance. Note, however, that in order to restore packages you need to have original ahriman instance run with web service and have run repo-update at least once.]"
|
"--from-database[read packages from database instead of filesystem. This feature in particular is required in case if you would like to restore repository from another repository instance. Note, however, that in order to restore packages you need to have original ahriman instance run with web service and have run repo-update at least once.]"
|
||||||
{-e,--exit-code}"[return non-zero exit status if result is empty]"
|
{-e,--exit-code}"[return non-zero exit status if result is empty]"
|
||||||
{-s,--status}"[filter packages by status. Requires --from-database to be set]:status:(unknown pending building failed success)"
|
{-s,--status}"[filter packages by status. Requires --from-database to be set]:status:(unknown pending building failed success)"
|
||||||
|
{-u,--username}"[build as user]:username:"
|
||||||
)
|
)
|
||||||
|
|
||||||
_shtab_ahriman_repo_remove_unknown_options=(
|
_shtab_ahriman_repo_remove_unknown_options=(
|
||||||
@ -413,6 +418,7 @@ _shtab_ahriman_repo_update_options=(
|
|||||||
{-e,--exit-code}"[return non-zero exit status if result is empty]"
|
{-e,--exit-code}"[return non-zero exit status if result is empty]"
|
||||||
{--local,--no-local}"[enable or disable checking of local packages for updates]:local:"
|
{--local,--no-local}"[enable or disable checking of local packages for updates]:local:"
|
||||||
{--manual,--no-manual}"[include or exclude manual updates]:manual:"
|
{--manual,--no-manual}"[include or exclude manual updates]:manual:"
|
||||||
|
{-u,--username}"[build as user]:username:"
|
||||||
{--vcs,--no-vcs}"[fetch actual version of VCS packages]:vcs:"
|
{--vcs,--no-vcs}"[fetch actual version of VCS packages]:vcs:"
|
||||||
"*"{-y,--refresh}"[download fresh package databases from the mirror before actions, -yy to force refresh even if up to date]"
|
"*"{-y,--refresh}"[download fresh package databases from the mirror before actions, -yy to force refresh even if up to date]"
|
||||||
"(*)::filter check by package base:"
|
"(*)::filter check by package base:"
|
||||||
@ -529,6 +535,7 @@ _shtab_ahriman_update_options=(
|
|||||||
{-e,--exit-code}"[return non-zero exit status if result is empty]"
|
{-e,--exit-code}"[return non-zero exit status if result is empty]"
|
||||||
{--local,--no-local}"[enable or disable checking of local packages for updates]:local:"
|
{--local,--no-local}"[enable or disable checking of local packages for updates]:local:"
|
||||||
{--manual,--no-manual}"[include or exclude manual updates]:manual:"
|
{--manual,--no-manual}"[include or exclude manual updates]:manual:"
|
||||||
|
{-u,--username}"[build as user]:username:"
|
||||||
{--vcs,--no-vcs}"[fetch actual version of VCS packages]:vcs:"
|
{--vcs,--no-vcs}"[fetch actual version of VCS packages]:vcs:"
|
||||||
"*"{-y,--refresh}"[download fresh package databases from the mirror before actions, -yy to force refresh even if up to date]"
|
"*"{-y,--refresh}"[download fresh package databases from the mirror before actions, -yy to force refresh even if up to date]"
|
||||||
"(*)::filter check by package base:"
|
"(*)::filter check by package base:"
|
||||||
@ -536,6 +543,8 @@ _shtab_ahriman_update_options=(
|
|||||||
|
|
||||||
_shtab_ahriman_user_add_options=(
|
_shtab_ahriman_user_add_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
|
"--key[optional PGP key used by this user. The private key must be imported]:key:"
|
||||||
|
"--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]"
|
{-s,--secure}"[set file permissions to user-only]"
|
||||||
|
@ -87,7 +87,6 @@ Settings for signing packages or repository. Group name can refer to architectur
|
|||||||
|
|
||||||
* ``target`` - configuration flag to enable signing, space separated list of strings, required. Allowed values are ``package`` (sign each package separately), ``repository`` (sign repository database file).
|
* ``target`` - configuration flag to enable signing, space separated list of strings, required. Allowed values are ``package`` (sign each package separately), ``repository`` (sign repository database file).
|
||||||
* ``key`` - default PGP key, string, required. This key will also be used for database signing if enabled.
|
* ``key`` - default PGP key, string, required. This key will also be used for database signing if enabled.
|
||||||
* ``key_*`` settings - PGP key which will be used for specific packages, string, optional. For example, if there is ``key_yay`` option the specified key will be used for yay package and default key for others.
|
|
||||||
|
|
||||||
``web:*`` groups
|
``web:*`` groups
|
||||||
----------------
|
----------------
|
||||||
|
@ -64,7 +64,7 @@ Initial setup
|
|||||||
.. code-block:: shell
|
.. code-block:: shell
|
||||||
|
|
||||||
echo 'Cmnd_Alias CARCHBUILD_CMD = /usr/local/bin/ahriman-x86_64-build *' | tee -a /etc/sudoers.d/ahriman
|
echo 'Cmnd_Alias CARCHBUILD_CMD = /usr/local/bin/ahriman-x86_64-build *' | tee -a /etc/sudoers.d/ahriman
|
||||||
echo 'ahriman ALL=(ALL) NOPASSWD: CARCHBUILD_CMD' | tee -a /etc/sudoers.d/ahriman
|
echo 'ahriman ALL=(ALL) NOPASSWD:SETENV: CARCHBUILD_CMD' | tee -a /etc/sudoers.d/ahriman
|
||||||
chmod 400 /etc/sudoers.d/ahriman
|
chmod 400 /etc/sudoers.d/ahriman
|
||||||
|
|
||||||
This command supports several arguments, kindly refer to its help message.
|
This command supports several arguments, kindly refer to its help message.
|
||||||
|
@ -87,6 +87,7 @@
|
|||||||
<th data-sortable="true" data-field="packages">packages</th>
|
<th data-sortable="true" data-field="packages">packages</th>
|
||||||
<th data-sortable="true" data-visible="false" data-field="groups">groups</th>
|
<th data-sortable="true" data-visible="false" data-field="groups">groups</th>
|
||||||
<th data-sortable="true" data-visible="false" data-field="licenses">licenses</th>
|
<th data-sortable="true" data-visible="false" data-field="licenses">licenses</th>
|
||||||
|
<th data-sortable="true" data-visible="false" data-field="packager">packager</th>
|
||||||
<th data-sortable="true" data-field="timestamp">last update</th>
|
<th data-sortable="true" data-field="timestamp">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">status</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -98,6 +98,7 @@
|
|||||||
id: package_base,
|
id: package_base,
|
||||||
base: web_url ? `<a href="${safe(web_url)}" title="${safe(package_base)}">${safe(package_base)}</a>` : safe(package_base),
|
base: web_url ? `<a href="${safe(web_url)}" title="${safe(package_base)}">${safe(package_base)}</a>` : safe(package_base),
|
||||||
version: safe(description.package.version),
|
version: safe(description.package.version),
|
||||||
|
packager: description.package.packager ? safe(description.package.packager) : "",
|
||||||
packages: listToTable(Object.keys(description.package.packages)),
|
packages: listToTable(Object.keys(description.package.packages)),
|
||||||
groups: listToTable(extractListProperties(description.package, "groups")),
|
groups: listToTable(extractListProperties(description.package, "groups")),
|
||||||
licenses: listToTable(extractListProperties(description.package, "licenses")),
|
licenses: listToTable(extractListProperties(description.package, "licenses")),
|
||||||
@ -120,8 +121,8 @@
|
|||||||
table.bootstrapTable("hideLoading");
|
table.bootstrapTable("hideLoading");
|
||||||
} else {
|
} else {
|
||||||
// other errors
|
// other errors
|
||||||
const messaga = error => { return `Could not load list of packages: ${error}`; };
|
const message = error => { return `Could not load list of packages: ${error}`; };
|
||||||
showFailure("Load failure", messaga, jqXHR, errorThrown);
|
showFailure("Load failure", message, jqXHR, errorThrown);
|
||||||
}
|
}
|
||||||
hideControls(true);
|
hideControls(true);
|
||||||
},
|
},
|
||||||
|
@ -27,7 +27,7 @@ from typing import TypeVar
|
|||||||
|
|
||||||
from ahriman import version
|
from ahriman import version
|
||||||
from ahriman.application import handlers
|
from ahriman.application import handlers
|
||||||
from ahriman.core.util import enum_values
|
from ahriman.core.util import enum_values, extract_user
|
||||||
from ahriman.models.action import Action
|
from ahriman.models.action import Action
|
||||||
from ahriman.models.build_status import BuildStatusEnum
|
from ahriman.models.build_status import BuildStatusEnum
|
||||||
from ahriman.models.log_handler import LogHandler
|
from ahriman.models.log_handler import LogHandler
|
||||||
@ -187,8 +187,8 @@ def _set_help_commands_unsafe_parser(root: SubParserAction) -> argparse.Argument
|
|||||||
"""
|
"""
|
||||||
parser = root.add_parser("help-commands-unsafe", help="list unsafe commands",
|
parser = root.add_parser("help-commands-unsafe", help="list unsafe commands",
|
||||||
description="list unsafe commands as defined in default args", formatter_class=_formatter)
|
description="list unsafe commands as defined in default args", formatter_class=_formatter)
|
||||||
parser.add_argument("--command", help="instead of showing commands, just test command line for unsafe subcommand "
|
parser.add_argument("command", help="instead of showing commands, just test command line for unsafe subcommand "
|
||||||
"and return 0 in case if command is safe and 1 otherwise")
|
"and return 0 in case if command is safe and 1 otherwise", nargs="*")
|
||||||
parser.set_defaults(handler=handlers.UnsafeCommands, architecture=[""], lock=None, report=False, quiet=True,
|
parser.set_defaults(handler=handlers.UnsafeCommands, architecture=[""], lock=None, report=False, quiet=True,
|
||||||
unsafe=True, parser=_parser)
|
unsafe=True, parser=_parser)
|
||||||
return parser
|
return parser
|
||||||
@ -262,6 +262,7 @@ def _set_package_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
action="count", default=False)
|
action="count", default=False)
|
||||||
parser.add_argument("-s", "--source", help="explicitly specify the package source for this command",
|
parser.add_argument("-s", "--source", help="explicitly specify the package source for this command",
|
||||||
type=PackageSource, choices=enum_values(PackageSource), default=PackageSource.Auto)
|
type=PackageSource, choices=enum_values(PackageSource), default=PackageSource.Auto)
|
||||||
|
parser.add_argument("-u", "--username", help="build as user", default=extract_user())
|
||||||
parser.set_defaults(handler=handlers.Add)
|
parser.set_defaults(handler=handlers.Add)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
@ -481,7 +482,8 @@ def _set_repo_check_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
parser.add_argument("-y", "--refresh", help="download fresh package databases from the mirror before actions, "
|
parser.add_argument("-y", "--refresh", help="download fresh package databases from the mirror before actions, "
|
||||||
"-yy to force refresh even if up to date",
|
"-yy to force refresh even if up to date",
|
||||||
action="count", default=False)
|
action="count", default=False)
|
||||||
parser.set_defaults(handler=handlers.Update, dependencies=False, dry_run=True, aur=True, local=True, manual=False)
|
parser.set_defaults(handler=handlers.Update, dependencies=False, dry_run=True, aur=True, local=True, manual=False,
|
||||||
|
username=None)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
@ -578,6 +580,7 @@ def _set_repo_rebuild_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
|
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
|
||||||
parser.add_argument("-s", "--status", help="filter packages by status. Requires --from-database to be set",
|
parser.add_argument("-s", "--status", help="filter packages by status. Requires --from-database to be set",
|
||||||
type=BuildStatusEnum, choices=enum_values(BuildStatusEnum))
|
type=BuildStatusEnum, choices=enum_values(BuildStatusEnum))
|
||||||
|
parser.add_argument("-u", "--username", help="build as user", default=extract_user())
|
||||||
parser.set_defaults(handler=handlers.Rebuild)
|
parser.set_defaults(handler=handlers.Rebuild)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
@ -752,6 +755,7 @@ def _set_repo_update_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
action=argparse.BooleanOptionalAction, default=True)
|
action=argparse.BooleanOptionalAction, default=True)
|
||||||
parser.add_argument("--manual", help="include or exclude manual updates",
|
parser.add_argument("--manual", help="include or exclude manual updates",
|
||||||
action=argparse.BooleanOptionalAction, default=True)
|
action=argparse.BooleanOptionalAction, default=True)
|
||||||
|
parser.add_argument("-u", "--username", help="build as user", default=extract_user())
|
||||||
parser.add_argument("--vcs", help="fetch actual version of VCS packages",
|
parser.add_argument("--vcs", help="fetch actual version of VCS packages",
|
||||||
action=argparse.BooleanOptionalAction, default=True)
|
action=argparse.BooleanOptionalAction, default=True)
|
||||||
parser.add_argument("-y", "--refresh", help="download fresh package databases from the mirror before actions, "
|
parser.add_argument("-y", "--refresh", help="download fresh package databases from the mirror before actions, "
|
||||||
@ -923,6 +927,9 @@ def _set_user_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
"root privileges because it performs write to filesystem configuration.",
|
"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("--packager", help="optional packager id used for build process in form of "
|
||||||
|
"`Name Surname <mail@example.com>`")
|
||||||
parser.add_argument("-p", "--password", help="user password. Blank password will be treated as empty password, "
|
parser.add_argument("-p", "--password", help="user password. Blank password will be treated as empty password, "
|
||||||
"which is in particular must be used for OAuth2 authorization type.")
|
"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",
|
||||||
@ -949,8 +956,8 @@ def _set_user_list_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
parser.add_argument("username", help="filter users by username", nargs="?")
|
parser.add_argument("username", help="filter users by username", nargs="?")
|
||||||
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
|
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
|
||||||
parser.add_argument("-r", "--role", help="filter users by role", type=UserAccess, choices=enum_values(UserAccess))
|
parser.add_argument("-r", "--role", help="filter users by role", type=UserAccess, choices=enum_values(UserAccess))
|
||||||
parser.set_defaults(handler=handlers.Users, action=Action.List, architecture=[""], lock=None, report=False, # nosec
|
parser.set_defaults(handler=handlers.Users, action=Action.List, architecture=[""], lock=None, report=False,
|
||||||
password="", quiet=True, unsafe=True)
|
quiet=True, unsafe=True)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
@ -968,8 +975,8 @@ def _set_user_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
description="remove user from the user mapping and update the configuration",
|
description="remove user from the user mapping and update the 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.set_defaults(handler=handlers.Users, action=Action.Remove, architecture=[""], lock=None, report=False, # nosec
|
parser.set_defaults(handler=handlers.Users, action=Action.Remove, architecture=[""], lock=None, report=False,
|
||||||
password="", quiet=True)
|
quiet=True)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ class Application(ApplicationPackages, ApplicationRepository):
|
|||||||
>>> configuration = Configuration()
|
>>> configuration = Configuration()
|
||||||
>>> application = Application("x86_64", configuration, report=True, unsafe=False)
|
>>> application = Application("x86_64", configuration, report=True, unsafe=False)
|
||||||
>>> # add packages to build queue
|
>>> # add packages to build queue
|
||||||
>>> application.add(["ahriman"], PackageSource.AUR, without_dependencies=False)
|
>>> 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, log_fn=print)
|
||||||
@ -96,21 +96,25 @@ class Application(ApplicationPackages, ApplicationRepository):
|
|||||||
Args:
|
Args:
|
||||||
packages(list[Package]): list of source packages of which dependencies have to be processed
|
packages(list[Package]): list of source packages of which dependencies have to be processed
|
||||||
process_dependencies(bool): if no set, dependencies will not be processed
|
process_dependencies(bool): if no set, dependencies will not be processed
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[Package]: updated packages list. Packager for dependencies will be copied from
|
||||||
|
original package
|
||||||
"""
|
"""
|
||||||
def missing_dependencies(source: Iterable[Package]) -> set[str]:
|
def missing_dependencies(source: Iterable[Package]) -> dict[str, str | None]:
|
||||||
# build initial list of dependencies
|
# append list of known packages with packages which are in current sources
|
||||||
result = set()
|
satisfied_packages = known_packages | {
|
||||||
for package in source:
|
single
|
||||||
result.update(package.depends_build)
|
for package in source
|
||||||
|
for single in package.packages_full
|
||||||
|
}
|
||||||
|
|
||||||
# remove ones which are already well-known
|
return {
|
||||||
result = result.difference(known_packages)
|
dependency: package.packager
|
||||||
|
for package in source
|
||||||
# remove ones which are in this list already
|
for dependency in package.depends_build
|
||||||
for package in source:
|
if dependency not in satisfied_packages
|
||||||
result = result.difference(package.packages_full)
|
}
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
if not process_dependencies or not packages:
|
if not process_dependencies or not packages:
|
||||||
return packages
|
return packages
|
||||||
@ -119,8 +123,8 @@ class Application(ApplicationPackages, ApplicationRepository):
|
|||||||
with_dependencies = {package.base: package for package in packages}
|
with_dependencies = {package.base: package for package in packages}
|
||||||
|
|
||||||
while missing := missing_dependencies(with_dependencies.values()):
|
while missing := missing_dependencies(with_dependencies.values()):
|
||||||
for package_name in missing:
|
for package_name, username in missing.items():
|
||||||
package = Package.from_aur(package_name, self.repository.pacman)
|
package = Package.from_aur(package_name, self.repository.pacman, username)
|
||||||
with_dependencies[package.base] = package
|
with_dependencies[package.base] = package
|
||||||
|
|
||||||
return list(with_dependencies.values())
|
return list(with_dependencies.values())
|
||||||
|
@ -55,15 +55,15 @@ class ApplicationPackages(ApplicationProperties):
|
|||||||
dst = self.repository.paths.packages / local_path.name
|
dst = self.repository.paths.packages / local_path.name
|
||||||
shutil.copy(local_path, dst)
|
shutil.copy(local_path, dst)
|
||||||
|
|
||||||
def _add_aur(self, source: str) -> None:
|
def _add_aur(self, source: str, username: str | None) -> None:
|
||||||
"""
|
"""
|
||||||
add package from AUR
|
add package from AUR
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
source(str): package base name
|
source(str): package base name
|
||||||
|
username(str | None): optional override of username for build process
|
||||||
"""
|
"""
|
||||||
package = Package.from_aur(source, self.repository.pacman)
|
package = Package.from_aur(source, self.repository.pacman, username)
|
||||||
|
|
||||||
self.database.build_queue_insert(package)
|
self.database.build_queue_insert(package)
|
||||||
self.database.remote_update(package)
|
self.database.remote_update(package)
|
||||||
|
|
||||||
@ -81,23 +81,24 @@ class ApplicationPackages(ApplicationProperties):
|
|||||||
for full_path in filter(package_like, local_dir.iterdir()):
|
for full_path in filter(package_like, local_dir.iterdir()):
|
||||||
self._add_archive(str(full_path))
|
self._add_archive(str(full_path))
|
||||||
|
|
||||||
def _add_local(self, source: str) -> None:
|
def _add_local(self, source: str, username: str | None) -> None:
|
||||||
"""
|
"""
|
||||||
add package from local PKGBUILDs
|
add package from local PKGBUILDs
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
source(str): path to directory with local source files
|
source(str): path to directory with local source files
|
||||||
|
username(str | None): optional override of username for build process
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
UnknownPackageError: if specified package is unknown or doesn't exist
|
UnknownPackageError: if specified package is unknown or doesn't exist
|
||||||
"""
|
"""
|
||||||
if (source_dir := Path(source)).is_dir():
|
if (source_dir := Path(source)).is_dir():
|
||||||
package = Package.from_build(source_dir, self.architecture)
|
package = Package.from_build(source_dir, self.architecture, username)
|
||||||
cache_dir = self.repository.paths.cache_for(package.base)
|
cache_dir = self.repository.paths.cache_for(package.base)
|
||||||
shutil.copytree(source_dir, cache_dir) # copy package to store in caches
|
shutil.copytree(source_dir, cache_dir) # copy package to store in caches
|
||||||
Sources.init(cache_dir) # we need to run init command in directory where we do have permissions
|
Sources.init(cache_dir) # we need to run init command in directory where we do have permissions
|
||||||
elif (source_dir := self.repository.paths.cache_for(source)).is_dir():
|
elif (source_dir := self.repository.paths.cache_for(source)).is_dir():
|
||||||
package = Package.from_build(source_dir, self.architecture)
|
package = Package.from_build(source_dir, self.architecture, username)
|
||||||
else:
|
else:
|
||||||
raise UnknownPackageError(source)
|
raise UnknownPackageError(source)
|
||||||
|
|
||||||
@ -122,29 +123,31 @@ class ApplicationPackages(ApplicationProperties):
|
|||||||
for chunk in response.iter_content(chunk_size=1024):
|
for chunk in response.iter_content(chunk_size=1024):
|
||||||
local_file.write(chunk)
|
local_file.write(chunk)
|
||||||
|
|
||||||
def _add_repository(self, source: str, *_: Any) -> None:
|
def _add_repository(self, source: str, username: str | None) -> None:
|
||||||
"""
|
"""
|
||||||
add package from official repository
|
add package from official repository
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
source(str): package base name
|
source(str): package base name
|
||||||
|
username(str | None): optional override of username for build process
|
||||||
"""
|
"""
|
||||||
package = Package.from_official(source, self.repository.pacman)
|
package = Package.from_official(source, self.repository.pacman, username)
|
||||||
self.database.build_queue_insert(package)
|
self.database.build_queue_insert(package)
|
||||||
self.database.remote_update(package)
|
self.database.remote_update(package)
|
||||||
|
|
||||||
def add(self, names: Iterable[str], source: PackageSource) -> None:
|
def add(self, names: Iterable[str], source: PackageSource, username: str | None = None) -> None:
|
||||||
"""
|
"""
|
||||||
add packages for the next build
|
add packages for the next build
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
names(Iterable[str]): list of package bases to add
|
names(Iterable[str]): list of package bases to add
|
||||||
source(PackageSource): package source to add
|
source(PackageSource): package source to add
|
||||||
|
username(str | None, optional): optional override of username for build process (Default value = None)
|
||||||
"""
|
"""
|
||||||
for name in names:
|
for name in names:
|
||||||
resolved_source = source.resolve(name)
|
resolved_source = source.resolve(name)
|
||||||
fn = getattr(self, f"_add_{resolved_source.value}")
|
fn = getattr(self, f"_add_{resolved_source.value}")
|
||||||
fn(name)
|
fn(name, username)
|
||||||
|
|
||||||
def on_result(self, result: Result) -> None:
|
def on_result(self, result: Result) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -25,6 +25,7 @@ from ahriman.core.build_tools.sources import Sources
|
|||||||
from ahriman.core.formatters import UpdatePrinter
|
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.result import Result
|
from ahriman.models.result import Result
|
||||||
|
|
||||||
|
|
||||||
@ -83,7 +84,7 @@ class ApplicationRepository(ApplicationProperties):
|
|||||||
if archive.filepath is None:
|
if archive.filepath is None:
|
||||||
self.logger.warning("filepath is empty for %s", package.base)
|
self.logger.warning("filepath is empty for %s", package.base)
|
||||||
continue # avoid mypy warning
|
continue # avoid mypy warning
|
||||||
self.repository.sign.process_sign_package(archive.filepath, package.base)
|
self.repository.sign.process_sign_package(archive.filepath, None)
|
||||||
# sign repository database if set
|
# sign repository database if set
|
||||||
self.repository.sign.process_sign_repository(self.repository.repo.repo_path)
|
self.repository.sign.process_sign_repository(self.repository.repo.repo_path)
|
||||||
# process triggers
|
# process triggers
|
||||||
@ -104,14 +105,14 @@ class ApplicationRepository(ApplicationProperties):
|
|||||||
packages: list[str] = []
|
packages: list[str] = []
|
||||||
for single in probe.packages:
|
for single in probe.packages:
|
||||||
try:
|
try:
|
||||||
_ = Package.from_aur(single, self.repository.pacman)
|
_ = Package.from_aur(single, self.repository.pacman, None)
|
||||||
except Exception:
|
except Exception:
|
||||||
packages.append(single)
|
packages.append(single)
|
||||||
return packages
|
return packages
|
||||||
|
|
||||||
def unknown_local(probe: Package) -> list[str]:
|
def unknown_local(probe: Package) -> list[str]:
|
||||||
cache_dir = self.repository.paths.cache_for(probe.base)
|
cache_dir = self.repository.paths.cache_for(probe.base)
|
||||||
local = Package.from_build(cache_dir, self.architecture)
|
local = Package.from_build(cache_dir, self.architecture, None)
|
||||||
packages = set(probe.packages.keys()).difference(local.packages.keys())
|
packages = set(probe.packages.keys()).difference(local.packages.keys())
|
||||||
return list(packages)
|
return list(packages)
|
||||||
|
|
||||||
@ -123,12 +124,14 @@ class ApplicationRepository(ApplicationProperties):
|
|||||||
result.extend(unknown_aur(package)) # local package not found
|
result.extend(unknown_aur(package)) # local package not found
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def update(self, updates: Iterable[Package]) -> Result:
|
def update(self, updates: Iterable[Package], packagers: Packagers | None = None) -> Result:
|
||||||
"""
|
"""
|
||||||
run package updates
|
run package updates
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
updates(Iterable[Package]): list of packages to update
|
updates(Iterable[Package]): list of packages to update
|
||||||
|
packagers(Packagers | None, optional): optional override of username for build process
|
||||||
|
(Default value = None)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Result: update result
|
Result: update result
|
||||||
@ -136,7 +139,7 @@ class ApplicationRepository(ApplicationProperties):
|
|||||||
def process_update(paths: Iterable[Path], result: Result) -> None:
|
def process_update(paths: Iterable[Path], result: Result) -> None:
|
||||||
if not paths:
|
if not paths:
|
||||||
return # don't need to process if no update supplied
|
return # don't need to process if no update supplied
|
||||||
update_result = self.repository.process_update(paths)
|
update_result = self.repository.process_update(paths, packagers)
|
||||||
self.on_result(result.merge(update_result))
|
self.on_result(result.merge(update_result))
|
||||||
|
|
||||||
# process built packages
|
# process built packages
|
||||||
@ -148,7 +151,7 @@ class ApplicationRepository(ApplicationProperties):
|
|||||||
tree = Tree.resolve(updates)
|
tree = Tree.resolve(updates)
|
||||||
for num, level in enumerate(tree):
|
for num, level in enumerate(tree):
|
||||||
self.logger.info("processing level #%i %s", num, [package.base for package in level])
|
self.logger.info("processing level #%i %s", num, [package.base for package in level])
|
||||||
build_result = self.repository.process_build(level)
|
build_result = self.repository.process_build(level, packagers)
|
||||||
packages = self.repository.packages_built()
|
packages = self.repository.packages_built()
|
||||||
process_update(packages, build_result)
|
process_update(packages, build_result)
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ 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.models.packagers import Packagers
|
||||||
|
|
||||||
|
|
||||||
class Add(Handler):
|
class Add(Handler):
|
||||||
@ -45,12 +46,14 @@ class Add(Handler):
|
|||||||
application = Application(architecture, configuration,
|
application = Application(architecture, configuration,
|
||||||
report=report, unsafe=unsafe, 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)
|
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)
|
log_fn=application.logger.info)
|
||||||
packages = application.with_dependencies(packages, process_dependencies=args.dependencies)
|
packages = application.with_dependencies(packages, process_dependencies=args.dependencies)
|
||||||
result = application.update(packages)
|
packagers = Packagers(args.username, {package.base: package.packager for package in packages})
|
||||||
|
|
||||||
|
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)
|
||||||
|
@ -78,7 +78,7 @@ class Patch(Handler):
|
|||||||
tuple[str, PkgbuildPatch]: package base and created PKGBUILD patch based on the diff from master HEAD
|
tuple[str, PkgbuildPatch]: package base and created PKGBUILD patch based on the diff from master HEAD
|
||||||
to current files
|
to current files
|
||||||
"""
|
"""
|
||||||
package = Package.from_build(sources_dir, architecture)
|
package = Package.from_build(sources_dir, architecture, None)
|
||||||
patch = Sources.patch_create(sources_dir, *track)
|
patch = Sources.patch_create(sources_dir, *track)
|
||||||
return package.base, PkgbuildPatch(None, patch)
|
return package.base, PkgbuildPatch(None, patch)
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ class Rebuild(Handler):
|
|||||||
UpdatePrinter(package, package.version).print(verbose=True)
|
UpdatePrinter(package, package.version).print(verbose=True)
|
||||||
return
|
return
|
||||||
|
|
||||||
result = application.update(updates)
|
result = application.update(updates, args.username)
|
||||||
Rebuild.check_if_empty(args.exit_code, result.is_empty)
|
Rebuild.check_if_empty(args.exit_code, result.is_empty)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -49,7 +49,7 @@ class ServiceUpdates(Handler):
|
|||||||
"""
|
"""
|
||||||
application = Application(architecture, configuration, report=report, unsafe=unsafe)
|
application = Application(architecture, configuration, report=report, unsafe=unsafe)
|
||||||
|
|
||||||
remote = Package.from_aur("ahriman", application.repository.pacman)
|
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
|
||||||
local_version = f"{version.__version__}-{release}"
|
local_version = f"{version.__version__}-{release}"
|
||||||
|
|
||||||
|
@ -213,7 +213,7 @@ class Setup(Handler):
|
|||||||
"""
|
"""
|
||||||
command = Setup.build_command(paths.root, prefix, architecture)
|
command = Setup.build_command(paths.root, prefix, architecture)
|
||||||
sudoers_file = Setup.build_command(Setup.SUDOERS_DIR_PATH, prefix, architecture)
|
sudoers_file = Setup.build_command(Setup.SUDOERS_DIR_PATH, prefix, architecture)
|
||||||
sudoers_file.write_text(f"ahriman ALL=(ALL) NOPASSWD: {command} *\n", encoding="utf8")
|
sudoers_file.write_text(f"ahriman ALL=(ALL) NOPASSWD:SETENV: {command} *\n", encoding="utf8")
|
||||||
sudoers_file.chmod(0o400) # security!
|
sudoers_file.chmod(0o400) # security!
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
import argparse
|
import argparse
|
||||||
import shlex
|
|
||||||
|
|
||||||
from ahriman.application.handlers import Handler
|
from ahriman.application.handlers import Handler
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
@ -47,14 +46,14 @@ class UnsafeCommands(Handler):
|
|||||||
"""
|
"""
|
||||||
parser = args.parser()
|
parser = args.parser()
|
||||||
unsafe_commands = UnsafeCommands.get_unsafe_commands(parser)
|
unsafe_commands = UnsafeCommands.get_unsafe_commands(parser)
|
||||||
if args.command is None:
|
if args.command:
|
||||||
|
UnsafeCommands.check_unsafe(args.command, unsafe_commands, parser)
|
||||||
|
else:
|
||||||
for command in unsafe_commands:
|
for command in unsafe_commands:
|
||||||
StringPrinter(command).print(verbose=True)
|
StringPrinter(command).print(verbose=True)
|
||||||
else:
|
|
||||||
UnsafeCommands.check_unsafe(args.command, unsafe_commands, parser)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def check_unsafe(command: str, unsafe_commands: list[str], parser: argparse.ArgumentParser) -> None:
|
def check_unsafe(command: list[str], unsafe_commands: list[str], parser: argparse.ArgumentParser) -> None:
|
||||||
"""
|
"""
|
||||||
check if command is unsafe
|
check if command is unsafe
|
||||||
|
|
||||||
@ -63,7 +62,7 @@ class UnsafeCommands(Handler):
|
|||||||
unsafe_commands(list[str]): list of unsafe commands
|
unsafe_commands(list[str]): list of unsafe commands
|
||||||
parser(argparse.ArgumentParser): generated argument parser
|
parser(argparse.ArgumentParser): generated argument parser
|
||||||
"""
|
"""
|
||||||
args = parser.parse_args(shlex.split(command))
|
args = parser.parse_args(command)
|
||||||
UnsafeCommands.check_if_empty(True, args.command in unsafe_commands)
|
UnsafeCommands.check_if_empty(True, args.command in unsafe_commands)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -24,6 +24,7 @@ from collections.abc import Callable
|
|||||||
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.models.packagers import Packagers
|
||||||
|
|
||||||
|
|
||||||
class Update(Handler):
|
class Update(Handler):
|
||||||
@ -54,7 +55,9 @@ class Update(Handler):
|
|||||||
return
|
return
|
||||||
|
|
||||||
packages = application.with_dependencies(packages, process_dependencies=args.dependencies)
|
packages = application.with_dependencies(packages, process_dependencies=args.dependencies)
|
||||||
result = application.update(packages)
|
packagers = Packagers(args.username, {package.base: package.packager for package in packages})
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -156,4 +156,5 @@ class Users(Handler):
|
|||||||
if password is None:
|
if password is None:
|
||||||
password = read_password()
|
password = read_password()
|
||||||
|
|
||||||
return User(username=args.username, password=password, access=args.role)
|
return User(username=args.username, password=password, access=args.role,
|
||||||
|
packager_id=args.packager, key=args.key)
|
||||||
|
@ -59,12 +59,13 @@ class Task(LazyLogging):
|
|||||||
self.makepkg_flags = configuration.getlist("build", "makepkg_flags", fallback=[])
|
self.makepkg_flags = configuration.getlist("build", "makepkg_flags", fallback=[])
|
||||||
self.makechrootpkg_flags = configuration.getlist("build", "makechrootpkg_flags", fallback=[])
|
self.makechrootpkg_flags = configuration.getlist("build", "makechrootpkg_flags", fallback=[])
|
||||||
|
|
||||||
def build(self, sources_dir: Path) -> list[Path]:
|
def build(self, sources_dir: Path, packager: str | None = None) -> list[Path]:
|
||||||
"""
|
"""
|
||||||
run package build
|
run package build
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
sources_dir(Path): path to where sources are
|
sources_dir(Path): path to where sources are
|
||||||
|
packager(str | None, optional): optional packager override (Default value = None)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
list[Path]: paths of produced packages
|
list[Path]: paths of produced packages
|
||||||
@ -75,12 +76,18 @@ class Task(LazyLogging):
|
|||||||
command.extend(["--"] + self.makepkg_flags)
|
command.extend(["--"] + self.makepkg_flags)
|
||||||
self.logger.info("using %s for %s", command, self.package.base)
|
self.logger.info("using %s for %s", command, self.package.base)
|
||||||
|
|
||||||
|
environment: dict[str, str] = {}
|
||||||
|
if packager is not None:
|
||||||
|
environment["PACKAGER"] = packager
|
||||||
|
self.logger.info("using environment variables %s", environment)
|
||||||
|
|
||||||
Task._check_output(
|
Task._check_output(
|
||||||
*command,
|
*command,
|
||||||
exception=BuildError(self.package.base),
|
exception=BuildError(self.package.base),
|
||||||
cwd=sources_dir,
|
cwd=sources_dir,
|
||||||
logger=self.logger,
|
logger=self.logger,
|
||||||
user=self.uid)
|
user=self.uid,
|
||||||
|
environment=environment)
|
||||||
|
|
||||||
# well it is not actually correct, but we can deal with it
|
# well it is not actually correct, but we can deal with it
|
||||||
packages = Task._check_output(
|
packages = Task._check_output(
|
||||||
|
@ -191,10 +191,6 @@ CONFIGURATION_SCHEMA: ConfigurationSchema = {
|
|||||||
"sign": {
|
"sign": {
|
||||||
"type": "dict",
|
"type": "dict",
|
||||||
"allow_unknown": True,
|
"allow_unknown": True,
|
||||||
"keysrules": {
|
|
||||||
"type": "string",
|
|
||||||
"anyof_regex": ["^target$", "^key$", "^key_.*"],
|
|
||||||
},
|
|
||||||
"schema": {
|
"schema": {
|
||||||
"target": {
|
"target": {
|
||||||
"type": "list",
|
"type": "list",
|
||||||
|
85
src/ahriman/core/database/migrations/m008_packagers.py
Normal file
85
src/ahriman/core/database/migrations/m008_packagers.py
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2023 ahriman team.
|
||||||
|
#
|
||||||
|
# This file is part of ahriman
|
||||||
|
# (see https://github.com/arcan1s/ahriman).
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
from sqlite3 import Connection
|
||||||
|
|
||||||
|
from ahriman.core.alpm.pacman import Pacman
|
||||||
|
from ahriman.core.configuration import Configuration
|
||||||
|
from ahriman.core.util import package_like
|
||||||
|
from ahriman.models.package import Package
|
||||||
|
from ahriman.models.pacman_synchronization import PacmanSynchronization
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["migrate_data", "steps"]
|
||||||
|
|
||||||
|
|
||||||
|
steps = [
|
||||||
|
"""
|
||||||
|
alter table users add column packager_id
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
alter table users add column key_id
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
alter table package_bases add column packager
|
||||||
|
""",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_data(connection: Connection, configuration: Configuration) -> None:
|
||||||
|
"""
|
||||||
|
perform data migration
|
||||||
|
|
||||||
|
Args:
|
||||||
|
connection(Connection): database connection
|
||||||
|
configuration(Configuration): configuration instance
|
||||||
|
"""
|
||||||
|
migrate_package_base_packager(connection, configuration)
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_package_base_packager(connection: Connection, configuration: Configuration) -> None:
|
||||||
|
"""
|
||||||
|
migrate package packager field
|
||||||
|
|
||||||
|
Args:
|
||||||
|
connection(Connection): database connection
|
||||||
|
configuration(Configuration): configuration instance
|
||||||
|
"""
|
||||||
|
if not configuration.repository_paths.repository.is_dir():
|
||||||
|
return
|
||||||
|
|
||||||
|
_, architecture = configuration.check_loaded()
|
||||||
|
pacman = Pacman(architecture, configuration, refresh_database=PacmanSynchronization.Disabled)
|
||||||
|
|
||||||
|
package_list = []
|
||||||
|
for full_path in filter(package_like, configuration.repository_paths.repository.iterdir()):
|
||||||
|
package = Package.from_archive(full_path, pacman, remote=None)
|
||||||
|
package_list.append({
|
||||||
|
"package_base": package.base,
|
||||||
|
"packager": package.packager,
|
||||||
|
})
|
||||||
|
|
||||||
|
connection.executemany(
|
||||||
|
"""
|
||||||
|
update package_bases set
|
||||||
|
packager = :packager
|
||||||
|
where package_base = :package_base
|
||||||
|
""",
|
||||||
|
package_list
|
||||||
|
)
|
@ -57,8 +57,9 @@ class AuthOperations(Operations):
|
|||||||
|
|
||||||
def run(connection: Connection) -> list[User]:
|
def run(connection: Connection) -> list[User]:
|
||||||
return [
|
return [
|
||||||
User(username=cursor["username"], password=cursor["password"], access=UserAccess(cursor["access"]))
|
User(username=row["username"], password=row["password"], access=UserAccess(row["access"]),
|
||||||
for cursor in connection.execute(
|
packager_id=row["packager_id"], key=row["key_id"])
|
||||||
|
for row in connection.execute(
|
||||||
"""
|
"""
|
||||||
select * from users
|
select * from users
|
||||||
where (:username is null or username = :username) and (:access is null or access = :access)
|
where (:username is null or username = :username) and (:access is null or access = :access)
|
||||||
@ -91,12 +92,13 @@ class AuthOperations(Operations):
|
|||||||
connection.execute(
|
connection.execute(
|
||||||
"""
|
"""
|
||||||
insert into users
|
insert into users
|
||||||
(username, access, password)
|
(username, access, password, packager_id, key_id)
|
||||||
values
|
values
|
||||||
(:username, :access, :password)
|
(:username, :access, :password, :packager_id, :key_id)
|
||||||
on conflict (username) do update set
|
on conflict (username) do update set
|
||||||
access = :access, password = :password
|
access = :access, password = :password, packager_id = :packager_id, key_id = :key_id
|
||||||
""",
|
""",
|
||||||
{"username": user.username.lower(), "access": user.access.value, "password": user.password})
|
{"username": user.username.lower(), "access": user.access.value, "password": user.password,
|
||||||
|
"packager_id": user.packager_id, "key_id": user.key})
|
||||||
|
|
||||||
self.with_connection(run, commit=True)
|
self.with_connection(run, commit=True)
|
||||||
|
@ -76,11 +76,12 @@ class PackageOperations(Operations):
|
|||||||
connection.execute(
|
connection.execute(
|
||||||
"""
|
"""
|
||||||
insert into package_bases
|
insert into package_bases
|
||||||
(package_base, version, source, branch, git_url, path, web_url)
|
(package_base, version, source, branch, git_url, path, web_url, packager)
|
||||||
values
|
values
|
||||||
(:package_base, :version, :source, :branch, :git_url, :path, :web_url)
|
(:package_base, :version, :source, :branch, :git_url, :path, :web_url, :packager)
|
||||||
on conflict (package_base) do update set
|
on conflict (package_base) do update set
|
||||||
version = :version, branch = :branch, git_url = :git_url, path = :path, web_url = :web_url, source = :source
|
version = :version, branch = :branch, git_url = :git_url, path = :path, web_url = :web_url,
|
||||||
|
source = :source, packager = :packager
|
||||||
""",
|
""",
|
||||||
{
|
{
|
||||||
"package_base": package.base,
|
"package_base": package.base,
|
||||||
@ -90,6 +91,7 @@ class PackageOperations(Operations):
|
|||||||
"path": package.remote.path if package.remote is not None else None,
|
"path": package.remote.path if package.remote is not None else None,
|
||||||
"web_url": package.remote.web_url if package.remote is not None else None,
|
"web_url": package.remote.web_url if package.remote is not None else None,
|
||||||
"source": package.remote.source.value if package.remote is not None else None,
|
"source": package.remote.source.value if package.remote is not None else None,
|
||||||
|
"packager": package.packager,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -163,8 +165,9 @@ class PackageOperations(Operations):
|
|||||||
base=row["package_base"],
|
base=row["package_base"],
|
||||||
version=row["version"],
|
version=row["version"],
|
||||||
remote=RemoteSource.from_json(row),
|
remote=RemoteSource.from_json(row),
|
||||||
packages={})
|
packages={},
|
||||||
for row in connection.execute("""select * from package_bases""")
|
packager=row["packager"] or None,
|
||||||
|
) for row in connection.execute("""select * from package_bases""")
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -77,8 +77,8 @@ class PatchOperations(Operations):
|
|||||||
"""
|
"""
|
||||||
def run(connection: Connection) -> list[tuple[str, PkgbuildPatch]]:
|
def run(connection: Connection) -> list[tuple[str, PkgbuildPatch]]:
|
||||||
return [
|
return [
|
||||||
(cursor["package_base"], PkgbuildPatch(cursor["variable"], cursor["patch"]))
|
(row["package_base"], PkgbuildPatch(row["variable"], row["patch"]))
|
||||||
for cursor in connection.execute(
|
for row in connection.execute(
|
||||||
"""select * from patches where :package_base is null or package_base = :package_base""",
|
"""select * from patches where :package_base is null or package_base = :package_base""",
|
||||||
{"package_base": package_base})
|
{"package_base": package_base})
|
||||||
]
|
]
|
||||||
|
@ -44,13 +44,13 @@ class RemotePush(LazyLogging):
|
|||||||
remote_source(RemoteSource): repository remote source (remote pull url and branch)
|
remote_source(RemoteSource): repository remote source (remote pull url and branch)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, configuration: Configuration, database: SQLite, section: str) -> None:
|
def __init__(self, database: SQLite, configuration: Configuration, section: str) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
default constructor
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
configuration(Configuration): configuration instance
|
|
||||||
database(SQLite): database instance
|
database(SQLite): database instance
|
||||||
|
configuration(Configuration): configuration instance
|
||||||
section(str): settings section name
|
section(str): settings section name
|
||||||
"""
|
"""
|
||||||
self.database = database
|
self.database = database
|
||||||
|
@ -105,5 +105,5 @@ class RemotePushTrigger(Trigger):
|
|||||||
for target in self.targets:
|
for target in self.targets:
|
||||||
section, _ = self.configuration.gettype(
|
section, _ = self.configuration.gettype(
|
||||||
target, self.architecture, fallback=self.CONFIGURATION_SCHEMA_FALLBACK)
|
target, self.architecture, fallback=self.CONFIGURATION_SCHEMA_FALLBACK)
|
||||||
runner = RemotePush(self.configuration, database, section)
|
runner = RemotePush(database, self.configuration, section)
|
||||||
runner.run(result)
|
runner.run(result)
|
||||||
|
@ -28,6 +28,7 @@ from ahriman.core.repository.cleaner import Cleaner
|
|||||||
from ahriman.core.util import safe_filename
|
from ahriman.core.util import safe_filename
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
from ahriman.models.package_description import PackageDescription
|
from ahriman.models.package_description import PackageDescription
|
||||||
|
from ahriman.models.packagers import Packagers
|
||||||
from ahriman.models.result import Result
|
from ahriman.models.result import Result
|
||||||
|
|
||||||
|
|
||||||
@ -63,30 +64,35 @@ class Executor(Cleaner):
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def process_build(self, updates: Iterable[Package]) -> Result:
|
def process_build(self, updates: Iterable[Package], packagers: Packagers | None = None) -> Result:
|
||||||
"""
|
"""
|
||||||
build packages
|
build packages
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
updates(Iterable[Package]): list of packages properties to build
|
updates(Iterable[Package]): list of packages properties to build
|
||||||
|
packagers(Packagers | None, optional): optional override of username for build process
|
||||||
|
(Default value = None)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Result: build result
|
Result: build result
|
||||||
"""
|
"""
|
||||||
def build_single(package: Package, local_path: Path) -> None:
|
def build_single(package: Package, local_path: Path, packager_id: str | None) -> None:
|
||||||
self.reporter.set_building(package.base)
|
self.reporter.set_building(package.base)
|
||||||
task = Task(package, self.configuration, self.paths)
|
task = Task(package, self.configuration, self.paths)
|
||||||
task.init(local_path, self.database)
|
task.init(local_path, self.database)
|
||||||
built = task.build(local_path)
|
built = task.build(local_path, packager_id)
|
||||||
for src in built:
|
for src in built:
|
||||||
dst = self.paths.packages / src.name
|
dst = self.paths.packages / src.name
|
||||||
shutil.move(src, dst)
|
shutil.move(src, dst)
|
||||||
|
|
||||||
|
packagers = packagers or Packagers()
|
||||||
|
|
||||||
result = Result()
|
result = Result()
|
||||||
for single in updates:
|
for single in updates:
|
||||||
with self.in_package_context(single.base), TemporaryDirectory(ignore_cleanup_errors=True) as dir_name:
|
with self.in_package_context(single.base), TemporaryDirectory(ignore_cleanup_errors=True) as dir_name:
|
||||||
try:
|
try:
|
||||||
build_single(single, Path(dir_name))
|
packager = self.packager(packagers, single.base)
|
||||||
|
build_single(single, Path(dir_name), packager.packager_id)
|
||||||
result.add_success(single)
|
result.add_success(single)
|
||||||
except Exception:
|
except Exception:
|
||||||
self.reporter.set_failed(single.base)
|
self.reporter.set_failed(single.base)
|
||||||
@ -158,12 +164,14 @@ class Executor(Cleaner):
|
|||||||
|
|
||||||
return self.repo.repo_path
|
return self.repo.repo_path
|
||||||
|
|
||||||
def process_update(self, packages: Iterable[Path]) -> Result:
|
def process_update(self, packages: Iterable[Path], packagers: Packagers | None = None) -> Result:
|
||||||
"""
|
"""
|
||||||
sign packages, add them to repository and update repository database
|
sign packages, add them to repository and update repository database
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
packages(Iterable[Path]): list of filenames to run
|
packages(Iterable[Path]): list of filenames to run
|
||||||
|
packagers(Packagers | None, optional): optional override of username for build process
|
||||||
|
(Default value = None)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Result: path to repository database
|
Result: path to repository database
|
||||||
@ -176,13 +184,13 @@ class Executor(Cleaner):
|
|||||||
shutil.move(self.paths.packages / archive.filename, self.paths.packages / safe)
|
shutil.move(self.paths.packages / archive.filename, self.paths.packages / safe)
|
||||||
archive.filename = safe
|
archive.filename = safe
|
||||||
|
|
||||||
def update_single(name: str | None, package_base: str) -> None:
|
def update_single(name: str | None, package_base: str, packager_key: str | None) -> None:
|
||||||
if name is None:
|
if name is None:
|
||||||
self.logger.warning("received empty package name for base %s", package_base)
|
self.logger.warning("received empty package name for base %s", package_base)
|
||||||
return # suppress type checking, it never can be none actually
|
return # suppress type checking, it never can be none actually
|
||||||
# in theory, it might be NOT packages directory, but we suppose it is
|
# in theory, it might be NOT packages directory, but we suppose it is
|
||||||
full_path = self.paths.packages / name
|
full_path = self.paths.packages / name
|
||||||
files = self.sign.process_sign_package(full_path, package_base)
|
files = self.sign.process_sign_package(full_path, packager_key)
|
||||||
for src in files:
|
for src in files:
|
||||||
dst = self.paths.repository / safe_filename(src.name)
|
dst = self.paths.repository / safe_filename(src.name)
|
||||||
shutil.move(src, dst)
|
shutil.move(src, dst)
|
||||||
@ -192,14 +200,17 @@ class Executor(Cleaner):
|
|||||||
current_packages = self.packages()
|
current_packages = self.packages()
|
||||||
removed_packages: list[str] = [] # list of packages which have been removed from the base
|
removed_packages: list[str] = [] # list of packages which have been removed from the base
|
||||||
updates = self.load_archives(packages)
|
updates = self.load_archives(packages)
|
||||||
|
packagers = packagers or Packagers()
|
||||||
|
|
||||||
result = Result()
|
result = Result()
|
||||||
for local in updates:
|
for local in updates:
|
||||||
with self.in_package_context(local.base):
|
with self.in_package_context(local.base):
|
||||||
try:
|
try:
|
||||||
|
packager = self.packager(packagers, local.base)
|
||||||
|
|
||||||
for description in local.packages.values():
|
for description in local.packages.values():
|
||||||
rename(description, local.base)
|
rename(description, local.base)
|
||||||
update_single(description.filename, local.base)
|
update_single(description.filename, local.base, packager.key)
|
||||||
self.reporter.set_success(local)
|
self.reporter.set_success(local)
|
||||||
result.add_success(local)
|
result.add_success(local)
|
||||||
|
|
||||||
|
@ -27,8 +27,11 @@ 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.core.util import check_user
|
||||||
|
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
|
||||||
|
from ahriman.models.user import User
|
||||||
|
from ahriman.models.user_access import UserAccess
|
||||||
|
|
||||||
|
|
||||||
class RepositoryProperties(LazyLogging):
|
class RepositoryProperties(LazyLogging):
|
||||||
@ -83,3 +86,23 @@ class RepositoryProperties(LazyLogging):
|
|||||||
self.repo = Repo(self.name, self.paths, self.sign.repository_sign_args)
|
self.repo = Repo(self.name, self.paths, self.sign.repository_sign_args)
|
||||||
self.reporter = Client.load(configuration, report=report)
|
self.reporter = Client.load(configuration, report=report)
|
||||||
self.triggers = TriggerLoader.load(architecture, configuration)
|
self.triggers = TriggerLoader.load(architecture, configuration)
|
||||||
|
|
||||||
|
def packager(self, packagers: Packagers, package_base: str) -> User:
|
||||||
|
"""
|
||||||
|
extract packager from configuration having username
|
||||||
|
|
||||||
|
Args:
|
||||||
|
packagers(Packagers): packagers override holder
|
||||||
|
package_base(str): package base to lookup
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
User | None: user found in database if any and empty object otherwise
|
||||||
|
"""
|
||||||
|
username = packagers.for_base(package_base)
|
||||||
|
if username is None: # none to search
|
||||||
|
return User(username="", password="", access=UserAccess.Read, packager_id=None, key=None) # nosec
|
||||||
|
|
||||||
|
if (user := self.database.user_get(username)) is not None: # found user
|
||||||
|
return user
|
||||||
|
# empty user with the username
|
||||||
|
return User(username=username, password="", access=UserAccess.Read, packager_id=None, key=None) # nosec
|
||||||
|
@ -65,9 +65,9 @@ class UpdateHandler(Cleaner):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
if source == PackageSource.Repository:
|
if source == PackageSource.Repository:
|
||||||
remote = Package.from_official(local.base, self.pacman)
|
remote = Package.from_official(local.base, self.pacman, None)
|
||||||
else:
|
else:
|
||||||
remote = Package.from_aur(local.base, self.pacman)
|
remote = Package.from_aur(local.base, self.pacman, None)
|
||||||
|
|
||||||
if local.is_outdated(
|
if local.is_outdated(
|
||||||
remote, self.paths,
|
remote, self.paths,
|
||||||
@ -98,7 +98,7 @@ class UpdateHandler(Cleaner):
|
|||||||
with self.in_package_context(cache_dir.name):
|
with self.in_package_context(cache_dir.name):
|
||||||
try:
|
try:
|
||||||
Sources.fetch(cache_dir, remote=None)
|
Sources.fetch(cache_dir, remote=None)
|
||||||
remote = Package.from_build(cache_dir, self.architecture)
|
remote = Package.from_build(cache_dir, self.architecture, None)
|
||||||
|
|
||||||
local = packages.get(remote.base)
|
local = packages.get(remote.base)
|
||||||
if local is None:
|
if local is None:
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
#
|
#
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from collections.abc import Generator
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
@ -165,21 +164,6 @@ class GPG(LazyLogging):
|
|||||||
key_body = self.key_download(server, key)
|
key_body = self.key_download(server, key)
|
||||||
GPG._check_output("gpg", "--import", input_data=key_body, logger=self.logger)
|
GPG._check_output("gpg", "--import", input_data=key_body, logger=self.logger)
|
||||||
|
|
||||||
def keys(self) -> list[str]:
|
|
||||||
"""
|
|
||||||
extract list of keys described in configuration
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
list[str]: list of unique keys which are set in configuration
|
|
||||||
"""
|
|
||||||
def generator() -> Generator[str, None, None]:
|
|
||||||
if self.default_key is not None:
|
|
||||||
yield self.default_key
|
|
||||||
for _, value in filter(lambda pair: pair[0].startswith("key_"), self.configuration["sign"].items()):
|
|
||||||
yield value
|
|
||||||
|
|
||||||
return sorted(set(generator()))
|
|
||||||
|
|
||||||
def process(self, path: Path, key: str) -> list[Path]:
|
def process(self, path: Path, key: str) -> list[Path]:
|
||||||
"""
|
"""
|
||||||
gpg command wrapper
|
gpg command wrapper
|
||||||
@ -197,20 +181,21 @@ class GPG(LazyLogging):
|
|||||||
logger=self.logger)
|
logger=self.logger)
|
||||||
return [path, path.parent / f"{path.name}.sig"]
|
return [path, path.parent / f"{path.name}.sig"]
|
||||||
|
|
||||||
def process_sign_package(self, path: Path, package_base: str) -> list[Path]:
|
def process_sign_package(self, path: Path, packager_key: str | None) -> list[Path]:
|
||||||
"""
|
"""
|
||||||
sign package if required by configuration
|
sign package if required by configuration
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
path(Path): path to file to sign
|
path(Path): path to file to sign
|
||||||
package_base(str): package base required to check for key overrides
|
packager_key(str | None): optional packager key to sign
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
list[Path]: list of generated files including original file
|
list[Path]: list of generated files including original file
|
||||||
"""
|
"""
|
||||||
if SignSettings.Packages not in self.targets:
|
if SignSettings.Packages not in self.targets:
|
||||||
return [path]
|
return [path]
|
||||||
key = self.configuration.get("sign", f"key_{package_base}", fallback=self.default_key)
|
|
||||||
|
key = packager_key or self.default_key
|
||||||
if key is None:
|
if key is None:
|
||||||
self.logger.error("no default key set, skip package %s sign", path)
|
self.logger.error("no default key set, skip package %s sign", path)
|
||||||
return [path]
|
return [path]
|
||||||
|
@ -78,7 +78,7 @@ class Spawn(Thread, LazyLogging):
|
|||||||
result = callback(args, architecture)
|
result = callback(args, architecture)
|
||||||
queue.put((process_id, result))
|
queue.put((process_id, result))
|
||||||
|
|
||||||
def _spawn_process(self, command: str, *args: str, **kwargs: str) -> None:
|
def _spawn_process(self, command: str, *args: str, **kwargs: str | None) -> None:
|
||||||
"""
|
"""
|
||||||
spawn external ahriman process with supplied arguments
|
spawn external ahriman process with supplied arguments
|
||||||
|
|
||||||
@ -94,6 +94,8 @@ class Spawn(Thread, LazyLogging):
|
|||||||
arguments.extend(args)
|
arguments.extend(args)
|
||||||
# named command arguments
|
# named command arguments
|
||||||
for argument, value in kwargs.items():
|
for argument, value in kwargs.items():
|
||||||
|
if value is None:
|
||||||
|
continue # skip null values
|
||||||
arguments.append(f"--{argument}")
|
arguments.append(f"--{argument}")
|
||||||
if value:
|
if value:
|
||||||
arguments.append(value)
|
arguments.append(value)
|
||||||
@ -122,27 +124,31 @@ class Spawn(Thread, LazyLogging):
|
|||||||
kwargs = {} if server is None else {"key-server": server}
|
kwargs = {} if server is None else {"key-server": server}
|
||||||
self._spawn_process("service-key-import", key, **kwargs)
|
self._spawn_process("service-key-import", key, **kwargs)
|
||||||
|
|
||||||
def packages_add(self, packages: Iterable[str], *, now: bool) -> None:
|
def packages_add(self, packages: Iterable[str], username: str | None, *, now: bool) -> None:
|
||||||
"""
|
"""
|
||||||
add packages
|
add packages
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
packages(Iterable[str]): packages list to add
|
packages(Iterable[str]): packages list to add
|
||||||
|
username(str | None): optional override of username for build process
|
||||||
now(bool): build packages now
|
now(bool): build packages now
|
||||||
"""
|
"""
|
||||||
kwargs = {"source": PackageSource.AUR.value} # avoid abusing by building non-aur packages
|
# avoid abusing by building non-aur packages
|
||||||
|
kwargs = {"source": PackageSource.AUR.value, "username": username}
|
||||||
if now:
|
if now:
|
||||||
kwargs["now"] = ""
|
kwargs["now"] = ""
|
||||||
self._spawn_process("package-add", *packages, **kwargs)
|
self._spawn_process("package-add", *packages, **kwargs)
|
||||||
|
|
||||||
def packages_rebuild(self, depends_on: str) -> None:
|
def packages_rebuild(self, depends_on: str, username: str | None) -> None:
|
||||||
"""
|
"""
|
||||||
rebuild packages which depend on the specified package
|
rebuild packages which depend on the specified package
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
depends_on(str): packages dependency
|
depends_on(str): packages dependency
|
||||||
|
username(str | None): optional override of username for build process
|
||||||
"""
|
"""
|
||||||
self._spawn_process("repo-rebuild", **{"depends-on": depends_on})
|
kwargs = {"depends-on": depends_on, "username": username}
|
||||||
|
self._spawn_process("repo-rebuild", **kwargs)
|
||||||
|
|
||||||
def packages_remove(self, packages: Iterable[str]) -> None:
|
def packages_remove(self, packages: Iterable[str]) -> None:
|
||||||
"""
|
"""
|
||||||
@ -153,11 +159,15 @@ class Spawn(Thread, LazyLogging):
|
|||||||
"""
|
"""
|
||||||
self._spawn_process("package-remove", *packages)
|
self._spawn_process("package-remove", *packages)
|
||||||
|
|
||||||
def packages_update(self) -> None:
|
def packages_update(self, username: str | None) -> None:
|
||||||
"""
|
"""
|
||||||
run full repository update
|
run full repository update
|
||||||
|
|
||||||
|
Args:
|
||||||
|
username(str | None): optional override of username for build process
|
||||||
"""
|
"""
|
||||||
self._spawn_process("repo-update")
|
kwargs = {"username": username}
|
||||||
|
self._spawn_process("repo-update", **kwargs)
|
||||||
|
|
||||||
def run(self) -> None:
|
def run(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#
|
#
|
||||||
from ahriman.core import context
|
from ahriman.core import context
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
|
from ahriman.core.database import SQLite
|
||||||
from ahriman.core.sign.gpg import GPG
|
from ahriman.core.sign.gpg import GPG
|
||||||
from ahriman.core.support.package_creator import PackageCreator
|
from ahriman.core.support.package_creator import PackageCreator
|
||||||
from ahriman.core.support.pkgbuild.keyring_generator import KeyringGenerator
|
from ahriman.core.support.pkgbuild.keyring_generator import KeyringGenerator
|
||||||
@ -107,8 +108,9 @@ class KeyringTrigger(Trigger):
|
|||||||
"""
|
"""
|
||||||
ctx = context.get()
|
ctx = context.get()
|
||||||
sign = ctx.get(ContextKey("sign", GPG))
|
sign = ctx.get(ContextKey("sign", GPG))
|
||||||
|
database = ctx.get(ContextKey("database", SQLite))
|
||||||
|
|
||||||
for target in self.targets:
|
for target in self.targets:
|
||||||
generator = KeyringGenerator(sign, self.configuration, target)
|
generator = KeyringGenerator(database, sign, self.configuration, target)
|
||||||
runner = PackageCreator(self.configuration, generator)
|
runner = PackageCreator(self.configuration, generator)
|
||||||
runner.run()
|
runner.run()
|
||||||
|
@ -67,5 +67,5 @@ class PackageCreator:
|
|||||||
ctx = context.get()
|
ctx = context.get()
|
||||||
database: SQLite = ctx.get(ContextKey("database", SQLite))
|
database: SQLite = ctx.get(ContextKey("database", SQLite))
|
||||||
_, architecture = self.configuration.check_loaded()
|
_, architecture = self.configuration.check_loaded()
|
||||||
package = Package.from_build(local_path, architecture)
|
package = Package.from_build(local_path, architecture, None)
|
||||||
database.package_update(package, BuildStatus())
|
database.package_update(package, BuildStatus())
|
||||||
|
@ -21,6 +21,7 @@ from collections.abc import Callable
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
|
from ahriman.core.database import SQLite
|
||||||
from ahriman.core.exceptions import PkgbuildGeneratorError
|
from ahriman.core.exceptions import PkgbuildGeneratorError
|
||||||
from ahriman.core.sign.gpg import GPG
|
from ahriman.core.sign.gpg import GPG
|
||||||
from ahriman.core.support.pkgbuild.pkgbuild_generator import PkgbuildGenerator
|
from ahriman.core.support.pkgbuild.pkgbuild_generator import PkgbuildGenerator
|
||||||
@ -42,11 +43,12 @@ class KeyringGenerator(PkgbuildGenerator):
|
|||||||
trusted(list[str]): lif of trusted PGP keys
|
trusted(list[str]): lif of trusted PGP keys
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, sign: GPG, configuration: Configuration, section: str) -> None:
|
def __init__(self, database: SQLite, sign: GPG, configuration: Configuration, section: str) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
default constructor
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
database(SQLite): database instance
|
||||||
sign(GPG): GPG wrapper instance
|
sign(GPG): GPG wrapper instance
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
section(str): settings section name
|
section(str): settings section name
|
||||||
@ -55,7 +57,8 @@ class KeyringGenerator(PkgbuildGenerator):
|
|||||||
self.name = configuration.repository_name
|
self.name = configuration.repository_name
|
||||||
|
|
||||||
# configuration fields
|
# configuration fields
|
||||||
self.packagers = configuration.getlist(section, "packagers", fallback=sign.keys())
|
packager_keys = [packager.key for packager in database.user_list(None, None) if packager.key is not None]
|
||||||
|
self.packagers = configuration.getlist(section, "packagers", fallback=packager_keys)
|
||||||
self.revoked = configuration.getlist(section, "revoked", fallback=[])
|
self.revoked = configuration.getlist(section, "revoked", fallback=[])
|
||||||
self.trusted = configuration.getlist(
|
self.trusted = configuration.getlist(
|
||||||
section, "trusted", fallback=[sign.default_key] if sign.default_key is not None else [])
|
section, "trusted", fallback=[sign.default_key] if sign.default_key is not None else [])
|
||||||
@ -148,10 +151,10 @@ class KeyringGenerator(PkgbuildGenerator):
|
|||||||
|
|
||||||
def install(self) -> str | None:
|
def install(self) -> str | None:
|
||||||
"""
|
"""
|
||||||
content of the install functions
|
content of the .install functions
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str | None: content of the install functions if any
|
str | None: content of the .install functions if any
|
||||||
"""
|
"""
|
||||||
# copy-paste from archlinux-keyring
|
# copy-paste from archlinux-keyring
|
||||||
return f"""post_upgrade() {{
|
return f"""post_upgrade() {{
|
||||||
|
@ -98,10 +98,10 @@ class PkgbuildGenerator:
|
|||||||
|
|
||||||
def install(self) -> str | None:
|
def install(self) -> str | None:
|
||||||
"""
|
"""
|
||||||
content of the install functions
|
content of the .install functions
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str | None: content of the install functions if any
|
str | None: content of the .install functions if any
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def package(self) -> str:
|
def package(self) -> str:
|
||||||
|
@ -28,6 +28,7 @@ import requests
|
|||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from collections.abc import Callable, Generator, Iterable
|
from collections.abc import Callable, Generator, Iterable
|
||||||
|
from dataclasses import asdict
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from pwd import getpwuid
|
from pwd import getpwuid
|
||||||
@ -40,8 +41,10 @@ from ahriman.models.repository_paths import RepositoryPaths
|
|||||||
__all__ = [
|
__all__ = [
|
||||||
"check_output",
|
"check_output",
|
||||||
"check_user",
|
"check_user",
|
||||||
|
"dataclass_view",
|
||||||
"enum_values",
|
"enum_values",
|
||||||
"exception_response_text",
|
"exception_response_text",
|
||||||
|
"extract_user",
|
||||||
"filter_json",
|
"filter_json",
|
||||||
"full_version",
|
"full_version",
|
||||||
"package_like",
|
"package_like",
|
||||||
@ -61,7 +64,8 @@ T = TypeVar("T")
|
|||||||
|
|
||||||
|
|
||||||
def check_output(*args: str, exception: Exception | None = None, cwd: Path | None = None, input_data: str | None = None,
|
def check_output(*args: str, exception: Exception | None = None, cwd: Path | None = None, input_data: str | None = None,
|
||||||
logger: logging.Logger | None = None, user: int | None = None) -> str:
|
logger: logging.Logger | None = None, user: int | None = None,
|
||||||
|
environment: dict[str, str] | None = None) -> str:
|
||||||
"""
|
"""
|
||||||
subprocess wrapper
|
subprocess wrapper
|
||||||
|
|
||||||
@ -73,6 +77,7 @@ def check_output(*args: str, exception: Exception | None = None, cwd: Path | Non
|
|||||||
input_data(str | None, optional): data which will be written to command stdin (Default value = None)
|
input_data(str | None, optional): data which will be written to command stdin (Default value = None)
|
||||||
logger(logging.Logger | None, optional): logger to log command result if required (Default value = None)
|
logger(logging.Logger | None, optional): logger to log command result if required (Default value = None)
|
||||||
user(int | None, optional): run process as specified user (Default value = None)
|
user(int | None, optional): run process as specified user (Default value = None)
|
||||||
|
environment(dict[str, str] | None, optional): optional environment variables if any (Default value = None)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: command output
|
str: command output
|
||||||
@ -106,7 +111,9 @@ def check_output(*args: str, exception: Exception | None = None, cwd: Path | Non
|
|||||||
if logger is not None:
|
if logger is not None:
|
||||||
logger.debug(single)
|
logger.debug(single)
|
||||||
|
|
||||||
environment = {"HOME": getpwuid(user).pw_dir} if user is not None else {}
|
environment = environment or {}
|
||||||
|
if user is not None:
|
||||||
|
environment["HOME"] = getpwuid(user).pw_dir
|
||||||
# FIXME additional workaround for linter and type check which do not know that user arg is supported
|
# FIXME additional workaround for linter and type check which do not know that user arg is supported
|
||||||
# pylint: disable=unexpected-keyword-arg
|
# pylint: disable=unexpected-keyword-arg
|
||||||
with subprocess.Popen(args, cwd=cwd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
with subprocess.Popen(args, cwd=cwd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
||||||
@ -163,6 +170,19 @@ def check_user(paths: RepositoryPaths, *, unsafe: bool) -> None:
|
|||||||
raise UnsafeRunError(current_uid, root_uid)
|
raise UnsafeRunError(current_uid, root_uid)
|
||||||
|
|
||||||
|
|
||||||
|
def dataclass_view(instance: Any) -> dict[str, Any]:
|
||||||
|
"""
|
||||||
|
convert dataclass instance to json object
|
||||||
|
|
||||||
|
Args:
|
||||||
|
instance(Any): dataclass instance
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict[str, Any]: json representation of the dataclass with empty field removed
|
||||||
|
"""
|
||||||
|
return asdict(instance, dict_factory=lambda fields: {key: value for key, value in fields if value is not None})
|
||||||
|
|
||||||
|
|
||||||
def enum_values(enum: type[Enum]) -> list[str]:
|
def enum_values(enum: type[Enum]) -> list[str]:
|
||||||
"""
|
"""
|
||||||
generate list of enumeration values from the source
|
generate list of enumeration values from the source
|
||||||
@ -190,6 +210,17 @@ def exception_response_text(exception: requests.exceptions.RequestException) ->
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def extract_user() -> str | None:
|
||||||
|
"""
|
||||||
|
extract user from system environment
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str | None: SUDO_USER in case if set and USER otherwise. It can return None in case if environment has been
|
||||||
|
cleared before application start
|
||||||
|
"""
|
||||||
|
return os.getenv("SUDO_USER") or os.getenv("DOAS_USER") or os.getenv("USER")
|
||||||
|
|
||||||
|
|
||||||
def filter_json(source: dict[str, Any], known_fields: Iterable[str]) -> dict[str, Any]:
|
def filter_json(source: dict[str, Any], known_fields: Iterable[str]) -> dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
filter json object by fields used for json-to-object conversion
|
filter json object by fields used for json-to-object conversion
|
||||||
|
@ -17,9 +17,10 @@
|
|||||||
# 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 dataclasses import asdict, dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from typing import Any, Self
|
from typing import Any, Self
|
||||||
|
|
||||||
|
from ahriman.core.util import dataclass_view
|
||||||
from ahriman.models.build_status import BuildStatus
|
from ahriman.models.build_status import BuildStatus
|
||||||
from ahriman.models.counters import Counters
|
from ahriman.models.counters import Counters
|
||||||
|
|
||||||
@ -69,4 +70,4 @@ class InternalStatus:
|
|||||||
Returns:
|
Returns:
|
||||||
dict[str, Any]: json-friendly dictionary
|
dict[str, Any]: json-friendly dictionary
|
||||||
"""
|
"""
|
||||||
return asdict(self)
|
return dataclass_view(self)
|
||||||
|
@ -23,7 +23,7 @@ from __future__ import annotations
|
|||||||
import copy
|
import copy
|
||||||
|
|
||||||
from collections.abc import Callable, Generator, Iterable
|
from collections.abc import Callable, Generator, Iterable
|
||||||
from dataclasses import asdict, dataclass
|
from dataclasses import dataclass
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from pyalpm import vercmp # type: ignore[import]
|
from pyalpm import vercmp # type: ignore[import]
|
||||||
from srcinfo.parse import parse_srcinfo # type: ignore[import]
|
from srcinfo.parse import parse_srcinfo # type: ignore[import]
|
||||||
@ -34,7 +34,7 @@ from ahriman.core.alpm.pacman import Pacman
|
|||||||
from ahriman.core.alpm.remote import AUR, Official, OfficialSyncdb
|
from ahriman.core.alpm.remote import AUR, Official, OfficialSyncdb
|
||||||
from ahriman.core.exceptions import PackageInfoError
|
from ahriman.core.exceptions import PackageInfoError
|
||||||
from ahriman.core.log import LazyLogging
|
from ahriman.core.log import LazyLogging
|
||||||
from ahriman.core.util import check_output, full_version, srcinfo_property_list, utcnow
|
from ahriman.core.util import check_output, dataclass_view, full_version, srcinfo_property_list, utcnow
|
||||||
from ahriman.models.package_description import PackageDescription
|
from ahriman.models.package_description import PackageDescription
|
||||||
from ahriman.models.package_source import PackageSource
|
from ahriman.models.package_source import PackageSource
|
||||||
from ahriman.models.remote_source import RemoteSource
|
from ahriman.models.remote_source import RemoteSource
|
||||||
@ -48,6 +48,7 @@ class Package(LazyLogging):
|
|||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
base(str): package base name
|
base(str): package base name
|
||||||
|
packager(str | None): package packager if available
|
||||||
packages(dict[str, PackageDescription): map of package names to their properties.
|
packages(dict[str, PackageDescription): map of package names to their properties.
|
||||||
Filled only on load from archive
|
Filled only on load from archive
|
||||||
remote(RemoteSource | None): package remote source if applicable
|
remote(RemoteSource | None): package remote source if applicable
|
||||||
@ -77,6 +78,7 @@ class Package(LazyLogging):
|
|||||||
version: str
|
version: str
|
||||||
remote: RemoteSource | None
|
remote: RemoteSource | None
|
||||||
packages: dict[str, PackageDescription]
|
packages: dict[str, PackageDescription]
|
||||||
|
packager: str | None = None
|
||||||
|
|
||||||
_check_output = check_output
|
_check_output = check_output
|
||||||
|
|
||||||
@ -204,16 +206,18 @@ class Package(LazyLogging):
|
|||||||
"""
|
"""
|
||||||
package = pacman.handle.load_pkg(str(path))
|
package = pacman.handle.load_pkg(str(path))
|
||||||
description = PackageDescription.from_package(package, path)
|
description = PackageDescription.from_package(package, path)
|
||||||
return cls(base=package.base, version=package.version, remote=remote, packages={package.name: description})
|
return cls(base=package.base, version=package.version, remote=remote, packages={package.name: description},
|
||||||
|
packager=package.packager)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_aur(cls, name: str, pacman: Pacman) -> Self:
|
def from_aur(cls, name: str, pacman: Pacman, packager: str | None = None) -> Self:
|
||||||
"""
|
"""
|
||||||
construct package properties from AUR page
|
construct package properties from AUR page
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
name(str): package name (either base or normal name)
|
name(str): package name (either base or normal name)
|
||||||
pacman(Pacman): alpm wrapper instance
|
pacman(Pacman): alpm wrapper instance
|
||||||
|
packager(str | None, optional): packager to be used for this build (Default value = None)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Self: package properties
|
Self: package properties
|
||||||
@ -224,16 +228,19 @@ class Package(LazyLogging):
|
|||||||
base=package.package_base,
|
base=package.package_base,
|
||||||
version=package.version,
|
version=package.version,
|
||||||
remote=remote,
|
remote=remote,
|
||||||
packages={package.name: PackageDescription.from_aur(package)})
|
packages={package.name: PackageDescription.from_aur(package)},
|
||||||
|
packager=packager,
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_build(cls, path: Path, architecture: str) -> Self:
|
def from_build(cls, path: Path, architecture: str, packager: str | None = None) -> Self:
|
||||||
"""
|
"""
|
||||||
construct package properties from sources directory
|
construct package properties from sources directory
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
path(Path): path to package sources directory
|
path(Path): path to package sources directory
|
||||||
architecture(str): load package for specific architecture
|
architecture(str): load package for specific architecture
|
||||||
|
packager(str | None, optional): packager to be used for this build (Default value = None)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Self: package properties
|
Self: package properties
|
||||||
@ -265,7 +272,7 @@ class Package(LazyLogging):
|
|||||||
source=PackageSource.Local,
|
source=PackageSource.Local,
|
||||||
)
|
)
|
||||||
|
|
||||||
return cls(base=srcinfo["pkgbase"], version=version, remote=remote, packages=packages)
|
return cls(base=srcinfo["pkgbase"], version=version, remote=remote, packages=packages, packager=packager)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_json(cls, dump: dict[str, Any]) -> Self:
|
def from_json(cls, dump: dict[str, Any]) -> Self:
|
||||||
@ -284,16 +291,18 @@ class Package(LazyLogging):
|
|||||||
for key, value in packages_json.items()
|
for key, value in packages_json.items()
|
||||||
}
|
}
|
||||||
remote = dump.get("remote") or {}
|
remote = dump.get("remote") or {}
|
||||||
return cls(base=dump["base"], version=dump["version"], remote=RemoteSource.from_json(remote), packages=packages)
|
return cls(base=dump["base"], version=dump["version"], remote=RemoteSource.from_json(remote), packages=packages,
|
||||||
|
packager=dump.get("packager"))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_official(cls, name: str, pacman: Pacman, *, use_syncdb: bool = True) -> Self:
|
def from_official(cls, name: str, pacman: Pacman, packager: str | None = None, *, use_syncdb: bool = True) -> Self:
|
||||||
"""
|
"""
|
||||||
construct package properties from official repository page
|
construct package properties from official repository page
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
name(str): package name (either base or normal name)
|
name(str): package name (either base or normal name)
|
||||||
pacman(Pacman): alpm wrapper instance
|
pacman(Pacman): alpm wrapper instance
|
||||||
|
packager(str | None, optional): packager to be used for this build (Default value = None)
|
||||||
use_syncdb(bool, optional): use pacman databases instead of official repositories RPC (Default value = True)
|
use_syncdb(bool, optional): use pacman databases instead of official repositories RPC (Default value = True)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@ -305,7 +314,9 @@ class Package(LazyLogging):
|
|||||||
base=package.package_base,
|
base=package.package_base,
|
||||||
version=package.version,
|
version=package.version,
|
||||||
remote=remote,
|
remote=remote,
|
||||||
packages={package.name: PackageDescription.from_aur(package)})
|
packages={package.name: PackageDescription.from_aur(package)},
|
||||||
|
packager=packager,
|
||||||
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def local_files(path: Path) -> Generator[Path, None, None]:
|
def local_files(path: Path) -> Generator[Path, None, None]:
|
||||||
@ -513,4 +524,4 @@ class Package(LazyLogging):
|
|||||||
Returns:
|
Returns:
|
||||||
dict[str, Any]: json-friendly dictionary
|
dict[str, Any]: json-friendly dictionary
|
||||||
"""
|
"""
|
||||||
return asdict(self)
|
return dataclass_view(self)
|
||||||
|
@ -17,12 +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 dataclasses import asdict, dataclass, field, fields
|
from dataclasses import dataclass, field, fields
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from pyalpm import Package # type: ignore[import]
|
from pyalpm import Package # type: ignore[import]
|
||||||
from typing import Any, Self
|
from typing import Any, Self
|
||||||
|
|
||||||
from ahriman.core.util import filter_json, trim_package
|
from ahriman.core.util import dataclass_view, filter_json, trim_package
|
||||||
from ahriman.models.aur_package import AURPackage
|
from ahriman.models.aur_package import AURPackage
|
||||||
|
|
||||||
|
|
||||||
@ -172,4 +172,4 @@ class PackageDescription:
|
|||||||
Returns:
|
Returns:
|
||||||
dict[str, Any]: json-friendly dictionary
|
dict[str, Any]: json-friendly dictionary
|
||||||
"""
|
"""
|
||||||
return asdict(self)
|
return dataclass_view(self)
|
||||||
|
46
src/ahriman/models/packagers.py
Normal file
46
src/ahriman/models/packagers.py
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#
|
||||||
|
# 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 dataclasses import dataclass, field
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class Packagers:
|
||||||
|
"""
|
||||||
|
holder for packagers overrides
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
default(str | None): default packager username if any to be used if no override for the specified base was found
|
||||||
|
overrides: dict[str, str | None]: packager username override for specific package base
|
||||||
|
"""
|
||||||
|
|
||||||
|
default: str | None = None
|
||||||
|
overrides: dict[str, str | None] = field(default_factory=dict)
|
||||||
|
|
||||||
|
def for_base(self, package_base: str) -> str | None:
|
||||||
|
"""
|
||||||
|
extract username for the specified package base
|
||||||
|
|
||||||
|
Args:
|
||||||
|
package_base(str): package base to lookup
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str | None: package base override if set and default packager username otherwise
|
||||||
|
"""
|
||||||
|
return self.overrides.get(package_base) or self.default
|
@ -17,11 +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 dataclasses import asdict, dataclass, fields
|
from dataclasses import dataclass, fields
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Self
|
from typing import Any, Self
|
||||||
|
|
||||||
from ahriman.core.util import filter_json
|
from ahriman.core.util import dataclass_view, filter_json
|
||||||
from ahriman.models.package_source import PackageSource
|
from ahriman.models.package_source import PackageSource
|
||||||
|
|
||||||
|
|
||||||
@ -118,4 +118,4 @@ class RemoteSource:
|
|||||||
Returns:
|
Returns:
|
||||||
dict[str, Any]: json-friendly dictionary
|
dict[str, Any]: json-friendly dictionary
|
||||||
"""
|
"""
|
||||||
return asdict(self)
|
return dataclass_view(self)
|
||||||
|
@ -34,12 +34,14 @@ class User:
|
|||||||
username(str): username
|
username(str): username
|
||||||
password(str): hashed user password with salt
|
password(str): hashed user password with salt
|
||||||
access(UserAccess): user role
|
access(UserAccess): user role
|
||||||
|
packager_id(str | None): packager id to be used. If not set, the default service packager will be used
|
||||||
|
key(str | None): personal packager key if any. If user id is empty, it is interpreted as default key
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
Simply create user from database data and perform required validation::
|
Simply create user from database data and perform required validation::
|
||||||
|
|
||||||
>>> password = User.generate_password(24)
|
>>> password = User.generate_password(24)
|
||||||
>>> user = User("ahriman", password, UserAccess.Full)
|
>>> user = User(username="ahriman", password=password, access=UserAccess.Full, packager_id=None, key=None)
|
||||||
|
|
||||||
Since the password supplied may be plain text, the ``hash_password`` method can be used to hash the password::
|
Since the password supplied may be plain text, the ``hash_password`` method can be used to hash the password::
|
||||||
|
|
||||||
@ -61,9 +63,18 @@ class User:
|
|||||||
username: str
|
username: str
|
||||||
password: str
|
password: str
|
||||||
access: UserAccess
|
access: UserAccess
|
||||||
|
packager_id: str | None
|
||||||
|
key: str | None
|
||||||
|
|
||||||
_HASHER = sha512_crypt
|
_HASHER = sha512_crypt
|
||||||
|
|
||||||
|
def __post_init__(self) -> None:
|
||||||
|
"""
|
||||||
|
remove empty fields
|
||||||
|
"""
|
||||||
|
object.__setattr__(self, "packager_id", self.packager_id or None)
|
||||||
|
object.__setattr__(self, "key", self.key or None)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_option(cls, username: str | None, password: str | None,
|
def from_option(cls, username: str | None, password: str | None,
|
||||||
access: UserAccess = UserAccess.Read) -> Self | None:
|
access: UserAccess = UserAccess.Read) -> Self | None:
|
||||||
@ -80,7 +91,7 @@ class User:
|
|||||||
"""
|
"""
|
||||||
if username is None or password is None:
|
if username is None or password is None:
|
||||||
return None
|
return None
|
||||||
return cls(username=username, password=password, access=access)
|
return cls(username=username, password=password, access=access, packager_id=None, key=None)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def generate_password(length: int) -> str:
|
def generate_password(length: int) -> str:
|
||||||
@ -149,4 +160,4 @@ class User:
|
|||||||
Returns:
|
Returns:
|
||||||
str: unique string representation
|
str: unique string representation
|
||||||
"""
|
"""
|
||||||
return f"User(username={self.username}, access={self.access})"
|
return f"User(username={self.username}, access={self.access}, packager_id={self.packager_id}, key={self.key})"
|
||||||
|
@ -148,7 +148,7 @@ def setup_auth(application: Application, configuration: Configuration, validator
|
|||||||
setup_session(application, storage)
|
setup_session(application, storage)
|
||||||
|
|
||||||
authorization_policy = _AuthorizationPolicy(validator)
|
authorization_policy = _AuthorizationPolicy(validator)
|
||||||
identity_policy = aiohttp_security.SessionIdentityPolicy()
|
identity_policy = application["identity"] = aiohttp_security.SessionIdentityPolicy()
|
||||||
|
|
||||||
aiohttp_security.setup(application, identity_policy, authorization_policy)
|
aiohttp_security.setup(application, identity_policy, authorization_policy)
|
||||||
application.middlewares.append(_auth_handler(validator.allow_read_only))
|
application.middlewares.append(_auth_handler(validator.allow_read_only))
|
||||||
|
@ -44,3 +44,7 @@ class PackageSchema(Schema):
|
|||||||
keys=fields.String(), values=fields.Nested(PackagePropertiesSchema()), required=True, metadata={
|
keys=fields.String(), values=fields.Nested(PackagePropertiesSchema()), required=True, metadata={
|
||||||
"description": "Packages which belong to this base",
|
"description": "Packages which belong to this base",
|
||||||
})
|
})
|
||||||
|
packager = fields.String(metadata={
|
||||||
|
"description": "packager for the last success package build",
|
||||||
|
"example": "John Doe <john@doe.com>",
|
||||||
|
})
|
||||||
|
@ -183,3 +183,16 @@ class BaseView(View, CorsViewMixin):
|
|||||||
return response
|
return response
|
||||||
|
|
||||||
self._raise_allowed_methods()
|
self._raise_allowed_methods()
|
||||||
|
|
||||||
|
async def username(self) -> str | None:
|
||||||
|
"""
|
||||||
|
extract username from request if any
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str | None: authorized username if any and None otherwise (e.g. if authorization is disabled)
|
||||||
|
"""
|
||||||
|
policy = self.request.app.get("identity")
|
||||||
|
if policy is not None:
|
||||||
|
identity: str = await policy.identify(self.request)
|
||||||
|
return identity
|
||||||
|
return None
|
||||||
|
@ -67,6 +67,7 @@ class AddView(BaseView):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise HTTPBadRequest(reason=str(e))
|
raise HTTPBadRequest(reason=str(e))
|
||||||
|
|
||||||
self.spawner.packages_add(packages, now=True)
|
username = await self.username()
|
||||||
|
self.spawner.packages_add(packages, username, now=True)
|
||||||
|
|
||||||
raise HTTPNoContent()
|
raise HTTPNoContent()
|
||||||
|
@ -68,6 +68,7 @@ class RebuildView(BaseView):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise HTTPBadRequest(reason=str(e))
|
raise HTTPBadRequest(reason=str(e))
|
||||||
|
|
||||||
self.spawner.packages_rebuild(depends_on)
|
username = await self.username()
|
||||||
|
self.spawner.packages_rebuild(depends_on, username)
|
||||||
|
|
||||||
raise HTTPNoContent()
|
raise HTTPNoContent()
|
||||||
|
@ -67,6 +67,7 @@ class RequestView(BaseView):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise HTTPBadRequest(reason=str(e))
|
raise HTTPBadRequest(reason=str(e))
|
||||||
|
|
||||||
self.spawner.packages_add(packages, now=False)
|
username = await self.username()
|
||||||
|
self.spawner.packages_add(packages, username, now=False)
|
||||||
|
|
||||||
raise HTTPNoContent()
|
raise HTTPNoContent()
|
||||||
|
@ -57,6 +57,7 @@ class UpdateView(BaseView):
|
|||||||
Raises:
|
Raises:
|
||||||
HTTPNoContent: in case of success response
|
HTTPNoContent: in case of success response
|
||||||
"""
|
"""
|
||||||
self.spawner.packages_update()
|
username = await self.username()
|
||||||
|
self.spawner.packages_update(username)
|
||||||
|
|
||||||
raise HTTPNoContent()
|
raise HTTPNoContent()
|
||||||
|
@ -72,16 +72,16 @@ def test_with_dependencies(application: Application, package_ahriman: Package, p
|
|||||||
"python-installer": create_package_mock("python-installer"),
|
"python-installer": create_package_mock("python-installer"),
|
||||||
}
|
}
|
||||||
|
|
||||||
package_mock = mocker.patch("ahriman.models.package.Package.from_aur", side_effect=lambda p, _: packages[p])
|
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"})
|
||||||
|
|
||||||
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
|
||||||
package_mock.assert_has_calls([
|
package_mock.assert_has_calls([
|
||||||
MockCall(package_python_schedule.base, application.repository.pacman),
|
MockCall(package_python_schedule.base, application.repository.pacman, package_ahriman.packager),
|
||||||
MockCall("python", application.repository.pacman),
|
MockCall("python", application.repository.pacman, package_ahriman.packager),
|
||||||
MockCall("python-installer", application.repository.pacman),
|
MockCall("python-installer", application.repository.pacman, package_ahriman.packager),
|
||||||
], any_order=True)
|
], any_order=True)
|
||||||
packages_mock.assert_called_once_with()
|
packages_mock.assert_called_once_with()
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ def test_add_aur(application_packages: ApplicationPackages, package_ahriman: Pac
|
|||||||
build_queue_mock = mocker.patch("ahriman.core.database.SQLite.build_queue_insert")
|
build_queue_mock = mocker.patch("ahriman.core.database.SQLite.build_queue_insert")
|
||||||
update_remote_mock = mocker.patch("ahriman.core.database.SQLite.remote_update")
|
update_remote_mock = mocker.patch("ahriman.core.database.SQLite.remote_update")
|
||||||
|
|
||||||
application_packages._add_aur(package_ahriman.base)
|
application_packages._add_aur(package_ahriman.base, "packager")
|
||||||
build_queue_mock.assert_called_once_with(package_ahriman)
|
build_queue_mock.assert_called_once_with(package_ahriman)
|
||||||
update_remote_mock.assert_called_once_with(package_ahriman)
|
update_remote_mock.assert_called_once_with(package_ahriman)
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ def test_add_local(application_packages: ApplicationPackages, package_ahriman: P
|
|||||||
copytree_mock = mocker.patch("shutil.copytree")
|
copytree_mock = mocker.patch("shutil.copytree")
|
||||||
build_queue_mock = mocker.patch("ahriman.core.database.SQLite.build_queue_insert")
|
build_queue_mock = mocker.patch("ahriman.core.database.SQLite.build_queue_insert")
|
||||||
|
|
||||||
application_packages._add_local(package_ahriman.base)
|
application_packages._add_local(package_ahriman.base, "packager")
|
||||||
is_dir_mock.assert_called_once_with()
|
is_dir_mock.assert_called_once_with()
|
||||||
copytree_mock.assert_called_once_with(
|
copytree_mock.assert_called_once_with(
|
||||||
Path(package_ahriman.base), application_packages.repository.paths.cache_for(package_ahriman.base))
|
Path(package_ahriman.base), application_packages.repository.paths.cache_for(package_ahriman.base))
|
||||||
@ -103,7 +103,7 @@ def test_add_local_cache(application_packages: ApplicationPackages, package_ahri
|
|||||||
copytree_mock = mocker.patch("shutil.copytree")
|
copytree_mock = mocker.patch("shutil.copytree")
|
||||||
build_queue_mock = mocker.patch("ahriman.core.database.SQLite.build_queue_insert")
|
build_queue_mock = mocker.patch("ahriman.core.database.SQLite.build_queue_insert")
|
||||||
|
|
||||||
application_packages._add_local(package_ahriman.base)
|
application_packages._add_local(package_ahriman.base, "packager")
|
||||||
copytree_mock.assert_not_called()
|
copytree_mock.assert_not_called()
|
||||||
init_mock.assert_not_called()
|
init_mock.assert_not_called()
|
||||||
build_queue_mock.assert_called_once_with(package_ahriman)
|
build_queue_mock.assert_called_once_with(package_ahriman)
|
||||||
@ -115,7 +115,7 @@ def test_add_local_missing(application_packages: ApplicationPackages, mocker: Mo
|
|||||||
"""
|
"""
|
||||||
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
||||||
with pytest.raises(UnknownPackageError):
|
with pytest.raises(UnknownPackageError):
|
||||||
application_packages._add_local("package")
|
application_packages._add_local("package", "packager")
|
||||||
|
|
||||||
|
|
||||||
def test_add_remote(application_packages: ApplicationPackages, package_description_ahriman: PackageDescription,
|
def test_add_remote(application_packages: ApplicationPackages, package_description_ahriman: PackageDescription,
|
||||||
@ -153,7 +153,7 @@ def test_add_repository(application_packages: ApplicationPackages, package_ahrim
|
|||||||
build_queue_mock = mocker.patch("ahriman.core.database.SQLite.build_queue_insert")
|
build_queue_mock = mocker.patch("ahriman.core.database.SQLite.build_queue_insert")
|
||||||
update_remote_mock = mocker.patch("ahriman.core.database.SQLite.remote_update")
|
update_remote_mock = mocker.patch("ahriman.core.database.SQLite.remote_update")
|
||||||
|
|
||||||
application_packages._add_repository(package_ahriman.base)
|
application_packages._add_repository(package_ahriman.base, "packager")
|
||||||
build_queue_mock.assert_called_once_with(package_ahriman)
|
build_queue_mock.assert_called_once_with(package_ahriman)
|
||||||
update_remote_mock.assert_called_once_with(package_ahriman)
|
update_remote_mock.assert_called_once_with(package_ahriman)
|
||||||
|
|
||||||
@ -165,8 +165,8 @@ def test_add_add_archive(application_packages: ApplicationPackages, package_ahri
|
|||||||
"""
|
"""
|
||||||
add_mock = mocker.patch("ahriman.application.application.application_packages.ApplicationPackages._add_archive")
|
add_mock = mocker.patch("ahriman.application.application.application_packages.ApplicationPackages._add_archive")
|
||||||
|
|
||||||
application_packages.add([package_ahriman.base], PackageSource.Archive)
|
application_packages.add([package_ahriman.base], PackageSource.Archive, "packager")
|
||||||
add_mock.assert_called_once_with(package_ahriman.base)
|
add_mock.assert_called_once_with(package_ahriman.base, "packager")
|
||||||
|
|
||||||
|
|
||||||
def test_add_add_aur(application_packages: ApplicationPackages, package_ahriman: Package,
|
def test_add_add_aur(application_packages: ApplicationPackages, package_ahriman: Package,
|
||||||
@ -176,8 +176,8 @@ def test_add_add_aur(application_packages: ApplicationPackages, package_ahriman:
|
|||||||
"""
|
"""
|
||||||
add_mock = mocker.patch("ahriman.application.application.application_packages.ApplicationPackages._add_aur")
|
add_mock = mocker.patch("ahriman.application.application.application_packages.ApplicationPackages._add_aur")
|
||||||
|
|
||||||
application_packages.add([package_ahriman.base], PackageSource.AUR)
|
application_packages.add([package_ahriman.base], PackageSource.AUR, "packager")
|
||||||
add_mock.assert_called_once_with(package_ahriman.base)
|
add_mock.assert_called_once_with(package_ahriman.base, "packager")
|
||||||
|
|
||||||
|
|
||||||
def test_add_add_directory(application_packages: ApplicationPackages, package_ahriman: Package,
|
def test_add_add_directory(application_packages: ApplicationPackages, package_ahriman: Package,
|
||||||
@ -187,8 +187,8 @@ def test_add_add_directory(application_packages: ApplicationPackages, package_ah
|
|||||||
"""
|
"""
|
||||||
add_mock = mocker.patch("ahriman.application.application.application_packages.ApplicationPackages._add_directory")
|
add_mock = mocker.patch("ahriman.application.application.application_packages.ApplicationPackages._add_directory")
|
||||||
|
|
||||||
application_packages.add([package_ahriman.base], PackageSource.Directory)
|
application_packages.add([package_ahriman.base], PackageSource.Directory, "packager")
|
||||||
add_mock.assert_called_once_with(package_ahriman.base)
|
add_mock.assert_called_once_with(package_ahriman.base, "packager")
|
||||||
|
|
||||||
|
|
||||||
def test_add_add_local(application_packages: ApplicationPackages, package_ahriman: Package,
|
def test_add_add_local(application_packages: ApplicationPackages, package_ahriman: Package,
|
||||||
@ -198,8 +198,8 @@ def test_add_add_local(application_packages: ApplicationPackages, package_ahrima
|
|||||||
"""
|
"""
|
||||||
add_mock = mocker.patch("ahriman.application.application.application_packages.ApplicationPackages._add_local")
|
add_mock = mocker.patch("ahriman.application.application.application_packages.ApplicationPackages._add_local")
|
||||||
|
|
||||||
application_packages.add([package_ahriman.base], PackageSource.Local)
|
application_packages.add([package_ahriman.base], PackageSource.Local, "packager")
|
||||||
add_mock.assert_called_once_with(package_ahriman.base)
|
add_mock.assert_called_once_with(package_ahriman.base, "packager")
|
||||||
|
|
||||||
|
|
||||||
def test_add_add_remote(application_packages: ApplicationPackages, package_description_ahriman: PackageDescription,
|
def test_add_add_remote(application_packages: ApplicationPackages, package_description_ahriman: PackageDescription,
|
||||||
@ -210,8 +210,8 @@ def test_add_add_remote(application_packages: ApplicationPackages, package_descr
|
|||||||
add_mock = mocker.patch("ahriman.application.application.application_packages.ApplicationPackages._add_remote")
|
add_mock = mocker.patch("ahriman.application.application.application_packages.ApplicationPackages._add_remote")
|
||||||
url = f"https://host/{package_description_ahriman.filename}"
|
url = f"https://host/{package_description_ahriman.filename}"
|
||||||
|
|
||||||
application_packages.add([url], PackageSource.Remote)
|
application_packages.add([url], PackageSource.Remote, "packager")
|
||||||
add_mock.assert_called_once_with(url)
|
add_mock.assert_called_once_with(url, "packager")
|
||||||
|
|
||||||
|
|
||||||
def test_on_result(application_packages: ApplicationPackages) -> None:
|
def test_on_result(application_packages: ApplicationPackages) -> None:
|
||||||
|
@ -76,9 +76,9 @@ def test_sign(application_repository: ApplicationRepository, package_ahriman: Pa
|
|||||||
|
|
||||||
application_repository.sign([])
|
application_repository.sign([])
|
||||||
sign_package_mock.assert_has_calls([
|
sign_package_mock.assert_has_calls([
|
||||||
MockCall(pytest.helpers.anyvar(int), package_ahriman.base),
|
MockCall(pytest.helpers.anyvar(int), None),
|
||||||
MockCall(pytest.helpers.anyvar(int), package_python_schedule.base),
|
MockCall(pytest.helpers.anyvar(int), None),
|
||||||
MockCall(pytest.helpers.anyvar(int), package_python_schedule.base),
|
MockCall(pytest.helpers.anyvar(int), None),
|
||||||
])
|
])
|
||||||
sign_repository_mock.assert_called_once_with(application_repository.repository.repo.repo_path)
|
sign_repository_mock.assert_called_once_with(application_repository.repository.repo.repo_path)
|
||||||
on_result_mock.assert_called_once_with(Result())
|
on_result_mock.assert_called_once_with(Result())
|
||||||
@ -111,7 +111,7 @@ def test_sign_specific(application_repository: ApplicationRepository, package_ah
|
|||||||
|
|
||||||
filename = package_ahriman.packages[package_ahriman.base].filepath
|
filename = package_ahriman.packages[package_ahriman.base].filepath
|
||||||
application_repository.sign([package_ahriman.base])
|
application_repository.sign([package_ahriman.base])
|
||||||
sign_package_mock.assert_called_once_with(filename, package_ahriman.base)
|
sign_package_mock.assert_called_once_with(filename, None)
|
||||||
sign_repository_mock.assert_called_once_with(application_repository.repository.repo.repo_path)
|
sign_repository_mock.assert_called_once_with(application_repository.repository.repo.repo_path)
|
||||||
on_result_mock.assert_called_once_with(Result())
|
on_result_mock.assert_called_once_with(Result())
|
||||||
|
|
||||||
@ -170,9 +170,9 @@ def test_update(application_repository: ApplicationRepository, package_ahriman:
|
|||||||
on_result_mock = mocker.patch(
|
on_result_mock = mocker.patch(
|
||||||
"ahriman.application.application.application_repository.ApplicationRepository.on_result")
|
"ahriman.application.application.application_repository.ApplicationRepository.on_result")
|
||||||
|
|
||||||
application_repository.update([package_ahriman])
|
application_repository.update([package_ahriman], "username")
|
||||||
build_mock.assert_called_once_with([package_ahriman])
|
build_mock.assert_called_once_with([package_ahriman], "username")
|
||||||
update_mock.assert_has_calls([MockCall(paths), MockCall(paths)])
|
update_mock.assert_has_calls([MockCall(paths, "username"), MockCall(paths, "username")])
|
||||||
on_result_mock.assert_has_calls([MockCall(result), MockCall(result)])
|
on_result_mock.assert_has_calls([MockCall(result), MockCall(result)])
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ from ahriman.core.configuration import Configuration
|
|||||||
from ahriman.core.repository import Repository
|
from ahriman.core.repository import Repository
|
||||||
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
|
||||||
|
from ahriman.models.packagers import Packagers
|
||||||
from ahriman.models.result import Result
|
from ahriman.models.result import Result
|
||||||
|
|
||||||
|
|
||||||
@ -27,6 +28,7 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
|||||||
args.refresh = 0
|
args.refresh = 0
|
||||||
args.source = PackageSource.Auto
|
args.source = PackageSource.Auto
|
||||||
args.dependencies = True
|
args.dependencies = True
|
||||||
|
args.username = "username"
|
||||||
return args
|
return args
|
||||||
|
|
||||||
|
|
||||||
@ -42,7 +44,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
|
|||||||
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, unsafe=False)
|
||||||
application_mock.assert_called_once_with(args.package, args.source)
|
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()
|
||||||
|
|
||||||
@ -67,7 +69,8 @@ def test_run_with_updates(args: argparse.Namespace, configuration: Configuration
|
|||||||
Add.run(args, "x86_64", configuration, report=False, unsafe=False)
|
Add.run(args, "x86_64", configuration, report=False, unsafe=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))
|
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"}))
|
||||||
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)
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ def test_patch_create_from_diff(package_ahriman: Package, mocker: MockerFixture)
|
|||||||
sources_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.patch_create", return_value=patch.value)
|
sources_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.patch_create", return_value=patch.value)
|
||||||
|
|
||||||
assert Patch.patch_create_from_diff(path, "x86_64", ["*.diff"]) == (package_ahriman.base, patch)
|
assert Patch.patch_create_from_diff(path, "x86_64", ["*.diff"]) == (package_ahriman.base, patch)
|
||||||
package_mock.assert_called_once_with(path, "x86_64")
|
package_mock.assert_called_once_with(path, "x86_64", None)
|
||||||
sources_mock.assert_called_once_with(path, "*.diff")
|
sources_mock.assert_called_once_with(path, "*.diff")
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
|||||||
args.from_database = False
|
args.from_database = False
|
||||||
args.exit_code = False
|
args.exit_code = False
|
||||||
args.status = None
|
args.status = None
|
||||||
|
args.username = "username"
|
||||||
return args
|
return args
|
||||||
|
|
||||||
|
|
||||||
@ -50,7 +51,7 @@ def test_run(args: argparse.Namespace, package_ahriman: Package, configuration:
|
|||||||
Rebuild.run(args, "x86_64", configuration, report=False, unsafe=False)
|
Rebuild.run(args, "x86_64", configuration, report=False, unsafe=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])
|
application_mock.assert_called_once_with([package_ahriman], args.username)
|
||||||
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()
|
||||||
|
|
||||||
|
@ -36,7 +36,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")
|
||||||
|
|
||||||
ServiceUpdates.run(args, "x86_64", configuration, report=False, unsafe=False)
|
ServiceUpdates.run(args, "x86_64", configuration, report=False, unsafe=False)
|
||||||
package_mock.assert_called_once_with(package_ahriman.base, repository.pacman)
|
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)
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
|||||||
argparse.Namespace: generated arguments for these test cases
|
argparse.Namespace: generated arguments for these test cases
|
||||||
"""
|
"""
|
||||||
args.parser = _parser
|
args.parser = _parser
|
||||||
args.command = None
|
args.command = []
|
||||||
return args
|
return args
|
||||||
|
|
||||||
|
|
||||||
@ -42,14 +42,14 @@ def test_run_check(args: argparse.Namespace, configuration: Configuration, mocke
|
|||||||
must run command and check if command is unsafe
|
must run command and check if command is unsafe
|
||||||
"""
|
"""
|
||||||
args = _default_args(args)
|
args = _default_args(args)
|
||||||
args.command = "clean"
|
args.command = ["clean"]
|
||||||
commands_mock = mocker.patch("ahriman.application.handlers.UnsafeCommands.get_unsafe_commands",
|
commands_mock = mocker.patch("ahriman.application.handlers.UnsafeCommands.get_unsafe_commands",
|
||||||
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, unsafe=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))
|
||||||
|
|
||||||
|
|
||||||
def test_check_unsafe(mocker: MockerFixture) -> None:
|
def test_check_unsafe(mocker: MockerFixture) -> None:
|
||||||
@ -57,7 +57,7 @@ def test_check_unsafe(mocker: MockerFixture) -> None:
|
|||||||
must check if command is unsafe
|
must check if command is unsafe
|
||||||
"""
|
"""
|
||||||
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
|
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
|
||||||
UnsafeCommands.check_unsafe("service-clean", ["service-clean"], _parser())
|
UnsafeCommands.check_unsafe(["service-clean"], ["service-clean"], _parser())
|
||||||
check_mock.assert_called_once_with(True, True)
|
check_mock.assert_called_once_with(True, True)
|
||||||
|
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ def test_check_unsafe_safe(mocker: MockerFixture) -> None:
|
|||||||
must check if command is safe
|
must check if command is safe
|
||||||
"""
|
"""
|
||||||
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
|
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
|
||||||
UnsafeCommands.check_unsafe("package-status", ["service-clean"], _parser())
|
UnsafeCommands.check_unsafe(["package-status"], ["service-clean"], _parser())
|
||||||
check_mock.assert_called_once_with(True, False)
|
check_mock.assert_called_once_with(True, False)
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ from ahriman.application.handlers import Update
|
|||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
from ahriman.core.repository import Repository
|
from ahriman.core.repository import Repository
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
|
from ahriman.models.packagers import Packagers
|
||||||
from ahriman.models.result import Result
|
from ahriman.models.result import Result
|
||||||
|
|
||||||
|
|
||||||
@ -31,6 +32,7 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
|||||||
args.manual = True
|
args.manual = True
|
||||||
args.vcs = True
|
args.vcs = True
|
||||||
args.refresh = 0
|
args.refresh = 0
|
||||||
|
args.username = "username"
|
||||||
return args
|
return args
|
||||||
|
|
||||||
|
|
||||||
@ -51,7 +53,8 @@ def test_run(args: argparse.Namespace, package_ahriman: Package, configuration:
|
|||||||
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
|
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
|
||||||
|
|
||||||
Update.run(args, "x86_64", configuration, report=False, unsafe=False)
|
Update.run(args, "x86_64", configuration, report=False, unsafe=False)
|
||||||
application_mock.assert_called_once_with([package_ahriman])
|
application_mock.assert_called_once_with([package_ahriman],
|
||||||
|
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))
|
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)
|
||||||
|
@ -27,6 +27,8 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
|||||||
args.username = "user"
|
args.username = "user"
|
||||||
args.action = Action.Update
|
args.action = Action.Update
|
||||||
args.exit_code = False
|
args.exit_code = False
|
||||||
|
args.key = "key"
|
||||||
|
args.packager = "packager"
|
||||||
args.password = "pa55w0rd"
|
args.password = "pa55w0rd"
|
||||||
args.role = UserAccess.Reporter
|
args.role = UserAccess.Reporter
|
||||||
args.secure = False
|
args.secure = False
|
||||||
@ -38,7 +40,8 @@ def test_run(args: argparse.Namespace, configuration: Configuration, database: S
|
|||||||
must run command
|
must run command
|
||||||
"""
|
"""
|
||||||
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)
|
||||||
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")
|
get_auth_configuration_mock = mocker.patch("ahriman.application.handlers.Users.configuration_get")
|
||||||
@ -61,7 +64,8 @@ def test_run_empty_salt(args: argparse.Namespace, configuration: Configuration,
|
|||||||
must create configuration if salt was not set
|
must create configuration if salt was not set
|
||||||
"""
|
"""
|
||||||
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)
|
||||||
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")
|
get_auth_configuration_mock = mocker.patch("ahriman.application.handlers.Users.configuration_get")
|
||||||
|
@ -351,13 +351,14 @@ def test_subparsers_repo_backup_architecture(parser: argparse.ArgumentParser) ->
|
|||||||
|
|
||||||
def test_subparsers_repo_check(parser: argparse.ArgumentParser) -> None:
|
def test_subparsers_repo_check(parser: argparse.ArgumentParser) -> None:
|
||||||
"""
|
"""
|
||||||
repo-check command must imply dependencies, dry-run, aur and manual
|
repo-check command must imply dependencies, dry-run, aur, manual and username
|
||||||
"""
|
"""
|
||||||
args = parser.parse_args(["repo-check"])
|
args = parser.parse_args(["repo-check"])
|
||||||
assert not args.dependencies
|
assert not args.dependencies
|
||||||
assert args.dry_run
|
assert args.dry_run
|
||||||
assert args.aur
|
assert args.aur
|
||||||
assert not args.manual
|
assert not args.manual
|
||||||
|
assert args.username is None
|
||||||
|
|
||||||
|
|
||||||
def test_subparsers_repo_check_architecture(parser: argparse.ArgumentParser) -> None:
|
def test_subparsers_repo_check_architecture(parser: argparse.ArgumentParser) -> None:
|
||||||
@ -757,14 +758,13 @@ def test_subparsers_user_add_option_role(parser: argparse.ArgumentParser) -> Non
|
|||||||
|
|
||||||
def test_subparsers_user_list(parser: argparse.ArgumentParser) -> None:
|
def test_subparsers_user_list(parser: argparse.ArgumentParser) -> None:
|
||||||
"""
|
"""
|
||||||
user-list command must imply action, architecture, lock, report, password, quiet and unsafe
|
user-list command must imply action, architecture, lock, report, quiet and unsafe
|
||||||
"""
|
"""
|
||||||
args = parser.parse_args(["user-list"])
|
args = parser.parse_args(["user-list"])
|
||||||
assert args.action == Action.List
|
assert args.action == Action.List
|
||||||
assert args.architecture == [""]
|
assert args.architecture == [""]
|
||||||
assert args.lock is None
|
assert args.lock is None
|
||||||
assert not args.report
|
assert not args.report
|
||||||
assert args.password is not None
|
|
||||||
assert args.quiet
|
assert args.quiet
|
||||||
assert args.unsafe
|
assert args.unsafe
|
||||||
|
|
||||||
@ -787,14 +787,13 @@ def test_subparsers_user_list_option_role(parser: argparse.ArgumentParser) -> No
|
|||||||
|
|
||||||
def test_subparsers_user_remove(parser: argparse.ArgumentParser) -> None:
|
def test_subparsers_user_remove(parser: argparse.ArgumentParser) -> None:
|
||||||
"""
|
"""
|
||||||
user-remove command must imply action, architecture, lock, report, password and quiet
|
user-remove command must imply action, architecture, lock, report and quiet
|
||||||
"""
|
"""
|
||||||
args = parser.parse_args(["user-remove", "username"])
|
args = parser.parse_args(["user-remove", "username"])
|
||||||
assert args.action == Action.Remove
|
assert args.action == Action.Remove
|
||||||
assert args.architecture == [""]
|
assert args.architecture == [""]
|
||||||
assert args.lock is None
|
assert args.lock is None
|
||||||
assert not args.report
|
assert not args.report
|
||||||
assert args.password is not None
|
|
||||||
assert args.quiet
|
assert args.quiet
|
||||||
|
|
||||||
|
|
||||||
|
@ -265,7 +265,8 @@ def package_ahriman(package_description_ahriman: PackageDescription, remote_sour
|
|||||||
base="ahriman",
|
base="ahriman",
|
||||||
version="2.6.0-1",
|
version="2.6.0-1",
|
||||||
remote=remote_source,
|
remote=remote_source,
|
||||||
packages=packages)
|
packages=packages,
|
||||||
|
packager="packager")
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@ -499,7 +500,7 @@ def user() -> User:
|
|||||||
Returns:
|
Returns:
|
||||||
User: user descriptor instance
|
User: user descriptor instance
|
||||||
"""
|
"""
|
||||||
return User(username="user", password="pa55w0rd", access=UserAccess.Reporter)
|
return User(username="user", password="pa55w0rd", access=UserAccess.Reporter, packager_id="packager", key="key")
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
|
@ -10,7 +10,7 @@ def test_build(task_ahriman: Task, mocker: MockerFixture) -> None:
|
|||||||
must build package
|
must build package
|
||||||
"""
|
"""
|
||||||
check_output_mock = mocker.patch("ahriman.core.build_tools.task.Task._check_output")
|
check_output_mock = mocker.patch("ahriman.core.build_tools.task.Task._check_output")
|
||||||
task_ahriman.build(Path("ahriman"))
|
task_ahriman.build(Path("ahriman"), "packager")
|
||||||
check_output_mock.assert_called()
|
check_output_mock.assert_called()
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ def test_migrate_data(connection: Connection, configuration: Configuration, mock
|
|||||||
def test_migrate_package_depends(connection: Connection, configuration: Configuration, package_ahriman: Package,
|
def test_migrate_package_depends(connection: Connection, configuration: Configuration, package_ahriman: Package,
|
||||||
mocker: MockerFixture) -> None:
|
mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must update make and opt depends list
|
must update check depends list
|
||||||
"""
|
"""
|
||||||
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
||||||
mocker.patch("pathlib.Path.iterdir", return_value=[package_ahriman.packages[package_ahriman.base].filepath])
|
mocker.patch("pathlib.Path.iterdir", return_value=[package_ahriman.packages[package_ahriman.base].filepath])
|
||||||
@ -45,7 +45,7 @@ def test_migrate_package_depends(connection: Connection, configuration: Configur
|
|||||||
def test_migrate_package_depends_skip(connection: Connection, configuration: Configuration,
|
def test_migrate_package_depends_skip(connection: Connection, configuration: Configuration,
|
||||||
mocker: MockerFixture) -> None:
|
mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must skip update make and opt depends list if no repository directory found
|
must skip update check depends list if no repository directory found
|
||||||
"""
|
"""
|
||||||
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
||||||
migrate_package_check_depends(connection, configuration)
|
migrate_package_check_depends(connection, configuration)
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from pytest_mock import MockerFixture
|
||||||
|
from sqlite3 import Connection
|
||||||
|
|
||||||
|
from ahriman.core.configuration import Configuration
|
||||||
|
from ahriman.core.database.migrations.m008_packagers import migrate_data, migrate_package_base_packager, steps
|
||||||
|
from ahriman.models.package import Package
|
||||||
|
|
||||||
|
|
||||||
|
def test_migration_packagers() -> None:
|
||||||
|
"""
|
||||||
|
migration must not be empty
|
||||||
|
"""
|
||||||
|
assert steps
|
||||||
|
|
||||||
|
|
||||||
|
def test_migrate_data(connection: Connection, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must perform data migration
|
||||||
|
"""
|
||||||
|
depends_mock = mocker.patch("ahriman.core.database.migrations.m008_packagers.migrate_package_base_packager")
|
||||||
|
migrate_data(connection, configuration)
|
||||||
|
depends_mock.assert_called_once_with(connection, configuration)
|
||||||
|
|
||||||
|
|
||||||
|
def test_migrate_package_base_packager(connection: Connection, configuration: Configuration, package_ahriman: Package,
|
||||||
|
mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must update packagers
|
||||||
|
"""
|
||||||
|
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
||||||
|
mocker.patch("pathlib.Path.iterdir", return_value=[package_ahriman.packages[package_ahriman.base].filepath])
|
||||||
|
package_mock = mocker.patch("ahriman.models.package.Package.from_archive", return_value=package_ahriman)
|
||||||
|
|
||||||
|
migrate_package_base_packager(connection, configuration)
|
||||||
|
package_mock.assert_called_once_with(
|
||||||
|
package_ahriman.packages[package_ahriman.base].filepath, pytest.helpers.anyvar(int), remote=None)
|
||||||
|
connection.executemany.assert_called_once_with(pytest.helpers.anyvar(str, strict=True), [{
|
||||||
|
"package_base": package_ahriman.base,
|
||||||
|
"packager": package_ahriman.packager,
|
||||||
|
}])
|
||||||
|
|
||||||
|
|
||||||
|
def test_migrate_package_depends_skip(connection: Connection, configuration: Configuration,
|
||||||
|
mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must skip update packagers if no repository directory found
|
||||||
|
"""
|
||||||
|
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
||||||
|
migrate_package_base_packager(connection, configuration)
|
||||||
|
connection.executemany.assert_not_called()
|
@ -16,21 +16,22 @@ def test_user_list(database: SQLite, user: User) -> None:
|
|||||||
must return all users
|
must return all users
|
||||||
"""
|
"""
|
||||||
database.user_update(user)
|
database.user_update(user)
|
||||||
database.user_update(User(username=user.password, password=user.username, access=user.access))
|
second = User(username=user.password, password=user.username, access=user.access, packager_id=None, key=None)
|
||||||
|
database.user_update(second)
|
||||||
|
|
||||||
users = database.user_list(None, None)
|
users = database.user_list(None, None)
|
||||||
assert len(users) == 2
|
assert len(users) == 2
|
||||||
assert user in users
|
assert user in users
|
||||||
assert User(username=user.password, password=user.username, access=user.access) in users
|
assert second in users
|
||||||
|
|
||||||
|
|
||||||
def test_user_list_filter_by_username(database: SQLite) -> None:
|
def test_user_list_filter_by_username(database: SQLite) -> None:
|
||||||
"""
|
"""
|
||||||
must return users filtered by its id
|
must return users filtered by its id
|
||||||
"""
|
"""
|
||||||
first = User(username="1", password="", access=UserAccess.Read)
|
first = User(username="1", password="", access=UserAccess.Read, packager_id=None, key=None)
|
||||||
second = User(username="2", password="", access=UserAccess.Full)
|
second = User(username="2", password="", access=UserAccess.Full, packager_id=None, key=None)
|
||||||
third = User(username="3", password="", access=UserAccess.Read)
|
third = User(username="3", password="", access=UserAccess.Read, packager_id=None, key=None)
|
||||||
|
|
||||||
database.user_update(first)
|
database.user_update(first)
|
||||||
database.user_update(second)
|
database.user_update(second)
|
||||||
@ -45,9 +46,9 @@ def test_user_list_filter_by_access(database: SQLite) -> None:
|
|||||||
"""
|
"""
|
||||||
must return users filtered by its access
|
must return users filtered by its access
|
||||||
"""
|
"""
|
||||||
first = User(username="1", password="", access=UserAccess.Read)
|
first = User(username="1", password="", access=UserAccess.Read, packager_id=None, key=None)
|
||||||
second = User(username="2", password="", access=UserAccess.Full)
|
second = User(username="2", password="", access=UserAccess.Full, packager_id=None, key=None)
|
||||||
third = User(username="3", password="", access=UserAccess.Read)
|
third = User(username="3", password="", access=UserAccess.Read, packager_id=None, key=None)
|
||||||
|
|
||||||
database.user_update(first)
|
database.user_update(first)
|
||||||
database.user_update(second)
|
database.user_update(second)
|
||||||
@ -63,9 +64,9 @@ def test_user_list_filter_by_username_access(database: SQLite) -> None:
|
|||||||
"""
|
"""
|
||||||
must return users filtered by its access and username
|
must return users filtered by its access and username
|
||||||
"""
|
"""
|
||||||
first = User(username="1", password="", access=UserAccess.Read)
|
first = User(username="1", password="", access=UserAccess.Read, packager_id=None, key=None)
|
||||||
second = User(username="2", password="", access=UserAccess.Full)
|
second = User(username="2", password="", access=UserAccess.Full, packager_id=None, key=None)
|
||||||
third = User(username="3", password="", access=UserAccess.Read)
|
third = User(username="3", password="", access=UserAccess.Read, packager_id=None, key=None)
|
||||||
|
|
||||||
database.user_update(first)
|
database.user_update(first)
|
||||||
database.user_update(second)
|
database.user_update(second)
|
||||||
@ -91,6 +92,7 @@ def test_user_update(database: SQLite, user: User) -> None:
|
|||||||
database.user_update(user)
|
database.user_update(user)
|
||||||
assert database.user_get(user.username) == user
|
assert database.user_get(user.username) == user
|
||||||
|
|
||||||
new_user = User(username=user.username, password=user.hash_password("salt").password, access=UserAccess.Full)
|
new_user = User(username=user.username, password=user.hash_password("salt").password, access=UserAccess.Full,
|
||||||
|
packager_id=None, key="new key")
|
||||||
database.user_update(new_user)
|
database.user_update(new_user)
|
||||||
assert database.user_get(new_user.username) == new_user
|
assert database.user_get(new_user.username) == new_user
|
||||||
|
@ -32,7 +32,7 @@ def test_package_update(database: SQLite, configuration: Configuration, package_
|
|||||||
fetch_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.fetch")
|
fetch_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.fetch")
|
||||||
patches_mock = mocker.patch("ahriman.core.database.SQLite.patches_get", return_value=[patch1, patch2])
|
patches_mock = mocker.patch("ahriman.core.database.SQLite.patches_get", return_value=[patch1, patch2])
|
||||||
patches_write_mock = mocker.patch("ahriman.models.pkgbuild_patch.PkgbuildPatch.write")
|
patches_write_mock = mocker.patch("ahriman.models.pkgbuild_patch.PkgbuildPatch.write")
|
||||||
runner = RemotePush(configuration, database, "gitremote")
|
runner = RemotePush(database, configuration, "gitremote")
|
||||||
|
|
||||||
assert runner.package_update(package_ahriman, local) == package_ahriman.base
|
assert runner.package_update(package_ahriman, local) == package_ahriman.base
|
||||||
glob_mock.assert_called_once_with(".git*")
|
glob_mock.assert_called_once_with(".git*")
|
||||||
@ -56,7 +56,7 @@ def test_packages_update(database: SQLite, configuration: Configuration, result:
|
|||||||
"""
|
"""
|
||||||
update_mock = mocker.patch("ahriman.core.gitremote.remote_push.RemotePush.package_update",
|
update_mock = mocker.patch("ahriman.core.gitremote.remote_push.RemotePush.package_update",
|
||||||
return_value=[package_ahriman.base])
|
return_value=[package_ahriman.base])
|
||||||
runner = RemotePush(configuration, database, "gitremote")
|
runner = RemotePush(database, configuration, "gitremote")
|
||||||
|
|
||||||
local = Path("local")
|
local = Path("local")
|
||||||
assert list(runner.packages_update(result, local))
|
assert list(runner.packages_update(result, local))
|
||||||
@ -71,7 +71,7 @@ def test_run(database: SQLite, configuration: Configuration, result: Result, pac
|
|||||||
mocker.patch("ahriman.core.gitremote.remote_push.RemotePush.packages_update", return_value=[package_ahriman.base])
|
mocker.patch("ahriman.core.gitremote.remote_push.RemotePush.packages_update", return_value=[package_ahriman.base])
|
||||||
fetch_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.fetch")
|
fetch_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.fetch")
|
||||||
push_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.push")
|
push_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.push")
|
||||||
runner = RemotePush(configuration, database, "gitremote")
|
runner = RemotePush(database, configuration, "gitremote")
|
||||||
|
|
||||||
runner.run(result)
|
runner.run(result)
|
||||||
fetch_mock.assert_called_once_with(pytest.helpers.anyvar(int), runner.remote_source)
|
fetch_mock.assert_called_once_with(pytest.helpers.anyvar(int), runner.remote_source)
|
||||||
@ -85,7 +85,7 @@ def test_run_failed(database: SQLite, configuration: Configuration, result: Resu
|
|||||||
must reraise exception on error occurred
|
must reraise exception on error occurred
|
||||||
"""
|
"""
|
||||||
mocker.patch("ahriman.core.build_tools.sources.Sources.fetch", side_effect=Exception())
|
mocker.patch("ahriman.core.build_tools.sources.Sources.fetch", side_effect=Exception())
|
||||||
runner = RemotePush(configuration, database, "gitremote")
|
runner = RemotePush(database, configuration, "gitremote")
|
||||||
|
|
||||||
with pytest.raises(GitRemoteError):
|
with pytest.raises(GitRemoteError):
|
||||||
runner.run(result)
|
runner.run(result)
|
||||||
|
@ -6,6 +6,8 @@ from unittest.mock import call as MockCall
|
|||||||
|
|
||||||
from ahriman.core.repository.executor import Executor
|
from ahriman.core.repository.executor import Executor
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
|
from ahriman.models.packagers import Packagers
|
||||||
|
from ahriman.models.user import User
|
||||||
|
|
||||||
|
|
||||||
def test_load_archives(executor: Executor) -> None:
|
def test_load_archives(executor: Executor) -> None:
|
||||||
@ -33,7 +35,7 @@ def test_process_build(executor: Executor, package_ahriman: Package, mocker: Moc
|
|||||||
move_mock = mocker.patch("shutil.move")
|
move_mock = mocker.patch("shutil.move")
|
||||||
status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_building")
|
status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_building")
|
||||||
|
|
||||||
executor.process_build([package_ahriman])
|
executor.process_build([package_ahriman], Packagers("packager"))
|
||||||
# must move files (once)
|
# must move files (once)
|
||||||
move_mock.assert_called_once_with(Path(package_ahriman.base), executor.paths.packages / package_ahriman.base)
|
move_mock.assert_called_once_with(Path(package_ahriman.base), executor.paths.packages / package_ahriman.base)
|
||||||
# must update status
|
# must update status
|
||||||
@ -157,7 +159,7 @@ def test_process_remove_unknown(executor: Executor, package_ahriman: Package, mo
|
|||||||
status_client_mock.assert_called_once_with(package_ahriman.base)
|
status_client_mock.assert_called_once_with(package_ahriman.base)
|
||||||
|
|
||||||
|
|
||||||
def test_process_update(executor: Executor, package_ahriman: Package, mocker: MockerFixture) -> None:
|
def test_process_update(executor: Executor, package_ahriman: Package, user: User, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must run update process
|
must run update process
|
||||||
"""
|
"""
|
||||||
@ -168,14 +170,16 @@ def test_process_update(executor: Executor, package_ahriman: Package, mocker: Mo
|
|||||||
sign_package_mock = mocker.patch("ahriman.core.sign.gpg.GPG.process_sign_package", side_effect=lambda fn, _: [fn])
|
sign_package_mock = mocker.patch("ahriman.core.sign.gpg.GPG.process_sign_package", side_effect=lambda fn, _: [fn])
|
||||||
status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_success")
|
status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_success")
|
||||||
remove_mock = mocker.patch("ahriman.core.repository.executor.Executor.process_remove")
|
remove_mock = mocker.patch("ahriman.core.repository.executor.Executor.process_remove")
|
||||||
|
packager_mock = mocker.patch("ahriman.core.repository.executor.Executor.packager", return_value=user)
|
||||||
filepath = next(package.filepath for package in package_ahriman.packages.values())
|
filepath = next(package.filepath for package in package_ahriman.packages.values())
|
||||||
|
|
||||||
# must return complete
|
# must return complete
|
||||||
assert executor.process_update([filepath])
|
assert executor.process_update([filepath], Packagers("packager"))
|
||||||
|
packager_mock.assert_called_once_with(Packagers("packager"), "ahriman")
|
||||||
# must move files (once)
|
# must move files (once)
|
||||||
move_mock.assert_called_once_with(executor.paths.packages / filepath, executor.paths.repository / filepath)
|
move_mock.assert_called_once_with(executor.paths.packages / filepath, executor.paths.repository / filepath)
|
||||||
# must sign package
|
# must sign package
|
||||||
sign_package_mock.assert_called_once_with(executor.paths.packages / filepath, package_ahriman.base)
|
sign_package_mock.assert_called_once_with(executor.paths.packages / filepath, user.key)
|
||||||
# must add package
|
# must add package
|
||||||
repo_add_mock.assert_called_once_with(executor.paths.repository / filepath)
|
repo_add_mock.assert_called_once_with(executor.paths.repository / filepath)
|
||||||
# must update status
|
# must update status
|
||||||
|
@ -4,6 +4,10 @@ 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.exceptions import UnsafeRunError
|
||||||
from ahriman.core.repository.repository_properties import RepositoryProperties
|
from ahriman.core.repository.repository_properties import RepositoryProperties
|
||||||
|
from ahriman.models.packagers import Packagers
|
||||||
|
from ahriman.models.pacman_synchronization import PacmanSynchronization
|
||||||
|
from ahriman.models.user import User
|
||||||
|
from ahriman.models.user_access import UserAccess
|
||||||
|
|
||||||
|
|
||||||
def test_create_tree_on_load(configuration: Configuration, database: SQLite, mocker: MockerFixture) -> None:
|
def test_create_tree_on_load(configuration: Configuration, database: SQLite, mocker: MockerFixture) -> None:
|
||||||
@ -12,7 +16,8 @@ def test_create_tree_on_load(configuration: Configuration, database: SQLite, moc
|
|||||||
"""
|
"""
|
||||||
mocker.patch("ahriman.core.repository.repository_properties.check_user")
|
mocker.patch("ahriman.core.repository.repository_properties.check_user")
|
||||||
tree_create_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
|
tree_create_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
|
||||||
RepositoryProperties("x86_64", configuration, database, report=False, unsafe=False, refresh_pacman_database=0)
|
RepositoryProperties("x86_64", configuration, database, report=False, unsafe=False,
|
||||||
|
refresh_pacman_database=PacmanSynchronization.Disabled)
|
||||||
|
|
||||||
tree_create_mock.assert_called_once_with()
|
tree_create_mock.assert_called_once_with()
|
||||||
|
|
||||||
@ -23,6 +28,36 @@ def test_create_tree_on_load_unsafe(configuration: Configuration, database: SQLi
|
|||||||
"""
|
"""
|
||||||
mocker.patch("ahriman.core.repository.repository_properties.check_user", side_effect=UnsafeRunError(0, 1))
|
mocker.patch("ahriman.core.repository.repository_properties.check_user", side_effect=UnsafeRunError(0, 1))
|
||||||
tree_create_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
|
tree_create_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
|
||||||
RepositoryProperties("x86_64", configuration, database, report=False, unsafe=False, refresh_pacman_database=0)
|
RepositoryProperties("x86_64", configuration, database, report=False, unsafe=False,
|
||||||
|
refresh_pacman_database=PacmanSynchronization.Disabled)
|
||||||
|
|
||||||
tree_create_mock.assert_not_called()
|
tree_create_mock.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
def test_packager(repository: RepositoryProperties, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must extract packager
|
||||||
|
"""
|
||||||
|
database_mock = mocker.patch("ahriman.core.database.SQLite.user_get")
|
||||||
|
assert repository.packager(Packagers("username", {}), "base")
|
||||||
|
database_mock.assert_called_once_with("username")
|
||||||
|
|
||||||
|
|
||||||
|
def test_packager_empty(repository: RepositoryProperties, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must return empty user if username was not set
|
||||||
|
"""
|
||||||
|
database_mock = mocker.patch("ahriman.core.database.SQLite.user_get")
|
||||||
|
user = User(username="", password="", access=UserAccess.Read, packager_id=None, key=None)
|
||||||
|
assert repository.packager(Packagers(), "base") == user
|
||||||
|
database_mock.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
def test_packager_empty_result(repository: RepositoryProperties, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must return empty user if it wasn't found in database
|
||||||
|
"""
|
||||||
|
database_mock = mocker.patch("ahriman.core.database.SQLite.user_get", return_value=None)
|
||||||
|
user = User(username="username", password="", access=UserAccess.Read, packager_id=None, key=None)
|
||||||
|
assert repository.packager(Packagers(user.username), "base") == user
|
||||||
|
database_mock.assert_called_once_with(user.username)
|
||||||
|
@ -74,7 +74,7 @@ def test_updates_aur_filter(update_handler: UpdateHandler, package_ahriman: Pack
|
|||||||
package_load_mock = mocker.patch("ahriman.models.package.Package.from_aur", return_value=package_ahriman)
|
package_load_mock = mocker.patch("ahriman.models.package.Package.from_aur", return_value=package_ahriman)
|
||||||
|
|
||||||
assert update_handler.updates_aur([package_ahriman.base], vcs=True) == [package_ahriman]
|
assert update_handler.updates_aur([package_ahriman.base], vcs=True) == [package_ahriman]
|
||||||
package_load_mock.assert_called_once_with(package_ahriman.base, update_handler.pacman)
|
package_load_mock.assert_called_once_with(package_ahriman.base, update_handler.pacman, None)
|
||||||
|
|
||||||
|
|
||||||
def test_updates_aur_ignore(update_handler: UpdateHandler, package_ahriman: Package,
|
def test_updates_aur_ignore(update_handler: UpdateHandler, package_ahriman: Package,
|
||||||
@ -120,7 +120,7 @@ def test_updates_local(update_handler: UpdateHandler, package_ahriman: Package,
|
|||||||
|
|
||||||
assert update_handler.updates_local(vcs=True) == [package_ahriman]
|
assert update_handler.updates_local(vcs=True) == [package_ahriman]
|
||||||
fetch_mock.assert_called_once_with(Path(package_ahriman.base), remote=None)
|
fetch_mock.assert_called_once_with(Path(package_ahriman.base), remote=None)
|
||||||
package_load_mock.assert_called_once_with(Path(package_ahriman.base), "x86_64")
|
package_load_mock.assert_called_once_with(Path(package_ahriman.base), "x86_64", None)
|
||||||
status_client_mock.assert_called_once_with(package_ahriman.base)
|
status_client_mock.assert_called_once_with(package_ahriman.base)
|
||||||
package_is_outdated_mock.assert_called_once_with(
|
package_is_outdated_mock.assert_called_once_with(
|
||||||
package_ahriman, update_handler.paths,
|
package_ahriman, update_handler.paths,
|
||||||
|
@ -135,21 +135,6 @@ def test_key_import(gpg: GPG, mocker: MockerFixture) -> None:
|
|||||||
check_output_mock.assert_called_once_with("gpg", "--import", input_data="key", logger=pytest.helpers.anyvar(int))
|
check_output_mock.assert_called_once_with("gpg", "--import", input_data="key", logger=pytest.helpers.anyvar(int))
|
||||||
|
|
||||||
|
|
||||||
def test_keys(gpg: GPG) -> None:
|
|
||||||
"""
|
|
||||||
must extract keys
|
|
||||||
"""
|
|
||||||
assert gpg.keys() == []
|
|
||||||
|
|
||||||
gpg.default_key = "key"
|
|
||||||
assert gpg.keys() == [gpg.default_key]
|
|
||||||
|
|
||||||
gpg.configuration.set_option("sign", "key_a", "key1")
|
|
||||||
gpg.configuration.set_option("sign", "key_b", "key1")
|
|
||||||
gpg.configuration.set_option("sign", "key_c", "key2")
|
|
||||||
assert gpg.keys() == ["key", "key1", "key2"]
|
|
||||||
|
|
||||||
|
|
||||||
def test_process(gpg_with_key: GPG, mocker: MockerFixture) -> None:
|
def test_process(gpg_with_key: GPG, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must call process method correctly
|
must call process method correctly
|
||||||
@ -170,7 +155,7 @@ def test_process_sign_package_1(gpg_with_key: GPG, mocker: MockerFixture) -> Non
|
|||||||
|
|
||||||
gpg_with_key.targets = {SignSettings.Packages}
|
gpg_with_key.targets = {SignSettings.Packages}
|
||||||
assert gpg_with_key.process_sign_package(Path("a"), "a") == result
|
assert gpg_with_key.process_sign_package(Path("a"), "a") == result
|
||||||
process_mock.assert_called_once_with(Path("a"), "key")
|
process_mock.assert_called_once_with(Path("a"), "a")
|
||||||
|
|
||||||
|
|
||||||
def test_process_sign_package_2(gpg_with_key: GPG, mocker: MockerFixture) -> None:
|
def test_process_sign_package_2(gpg_with_key: GPG, mocker: MockerFixture) -> None:
|
||||||
@ -182,7 +167,19 @@ def test_process_sign_package_2(gpg_with_key: GPG, mocker: MockerFixture) -> Non
|
|||||||
|
|
||||||
gpg_with_key.targets = {SignSettings.Packages, SignSettings.Repository}
|
gpg_with_key.targets = {SignSettings.Packages, SignSettings.Repository}
|
||||||
assert gpg_with_key.process_sign_package(Path("a"), "a") == result
|
assert gpg_with_key.process_sign_package(Path("a"), "a") == result
|
||||||
process_mock.assert_called_once_with(Path("a"), "key")
|
process_mock.assert_called_once_with(Path("a"), "a")
|
||||||
|
|
||||||
|
|
||||||
|
def test_process_sign_package_3(gpg_with_key: GPG, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must sign package with default key if none passed
|
||||||
|
"""
|
||||||
|
result = [Path("a"), Path("a.sig")]
|
||||||
|
process_mock = mocker.patch("ahriman.core.sign.gpg.GPG.process", return_value=result)
|
||||||
|
|
||||||
|
gpg_with_key.targets = {SignSettings.Packages}
|
||||||
|
assert gpg_with_key.process_sign_package(Path("a"), None) == result
|
||||||
|
process_mock.assert_called_once_with(Path("a"), gpg_with_key.default_key)
|
||||||
|
|
||||||
|
|
||||||
def test_process_sign_package_skip_1(gpg_with_key: GPG, mocker: MockerFixture) -> None:
|
def test_process_sign_package_skip_1(gpg_with_key: GPG, mocker: MockerFixture) -> None:
|
||||||
@ -211,7 +208,7 @@ def test_process_sign_package_skip_3(gpg: GPG, mocker: MockerFixture) -> None:
|
|||||||
"""
|
"""
|
||||||
process_mock = mocker.patch("ahriman.core.sign.gpg.GPG.process")
|
process_mock = mocker.patch("ahriman.core.sign.gpg.GPG.process")
|
||||||
gpg.targets = {SignSettings.Packages}
|
gpg.targets = {SignSettings.Packages}
|
||||||
gpg.process_sign_package(Path("a"), "a")
|
gpg.process_sign_package(Path("a"), None)
|
||||||
process_mock.assert_not_called()
|
process_mock.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
@ -221,7 +218,7 @@ def test_process_sign_package_skip_4(gpg: GPG, mocker: MockerFixture) -> None:
|
|||||||
"""
|
"""
|
||||||
process_mock = mocker.patch("ahriman.core.sign.gpg.GPG.process")
|
process_mock = mocker.patch("ahriman.core.sign.gpg.GPG.process")
|
||||||
gpg.targets = {SignSettings.Packages, SignSettings.Repository}
|
gpg.targets = {SignSettings.Packages, SignSettings.Repository}
|
||||||
gpg.process_sign_package(Path("a"), "a")
|
gpg.process_sign_package(Path("a"), None)
|
||||||
process_mock.assert_not_called()
|
process_mock.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,24 +1,26 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
|
from ahriman.core.database import SQLite
|
||||||
from ahriman.core.sign.gpg import GPG
|
from ahriman.core.sign.gpg import GPG
|
||||||
from ahriman.core.support.pkgbuild.keyring_generator import KeyringGenerator
|
from ahriman.core.support.pkgbuild.keyring_generator import KeyringGenerator
|
||||||
from ahriman.core.support.pkgbuild.pkgbuild_generator import PkgbuildGenerator
|
from ahriman.core.support.pkgbuild.pkgbuild_generator import PkgbuildGenerator
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def keyring_generator(gpg: GPG, configuration: Configuration) -> KeyringGenerator:
|
def keyring_generator(database: SQLite, gpg: GPG, configuration: Configuration) -> KeyringGenerator:
|
||||||
"""
|
"""
|
||||||
fixture for keyring pkgbuild generator
|
fixture for keyring pkgbuild generator
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
database(SQLite): database fixture
|
||||||
gpg(GPG): empty GPG fixture
|
gpg(GPG): empty GPG fixture
|
||||||
configuration(Configuration): configuration fixture
|
configuration(Configuration): configuration fixture
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
KeyringGenerator: keyring generator test instance
|
KeyringGenerator: keyring generator test instance
|
||||||
"""
|
"""
|
||||||
return KeyringGenerator(gpg, configuration, "keyring")
|
return KeyringGenerator(database, gpg, configuration, "keyring")
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
|
@ -5,84 +5,87 @@ from pytest_mock import MockerFixture
|
|||||||
from unittest.mock import MagicMock, call as MockCall
|
from unittest.mock import MagicMock, call as MockCall
|
||||||
|
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
|
from ahriman.core.database import SQLite
|
||||||
from ahriman.core.exceptions import PkgbuildGeneratorError
|
from ahriman.core.exceptions import PkgbuildGeneratorError
|
||||||
from ahriman.core.sign.gpg import GPG
|
from ahriman.core.sign.gpg import GPG
|
||||||
from ahriman.core.support.pkgbuild.keyring_generator import KeyringGenerator
|
from ahriman.core.support.pkgbuild.keyring_generator import KeyringGenerator
|
||||||
|
from ahriman.models.user import User
|
||||||
|
|
||||||
|
|
||||||
def test_init_packagers(gpg: GPG, configuration: Configuration, mocker: MockerFixture) -> None:
|
def test_init_packagers(database: SQLite, gpg: GPG, configuration: Configuration, user: User,
|
||||||
|
mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must extract packagers keys
|
must extract packagers keys
|
||||||
"""
|
"""
|
||||||
mocker.patch("ahriman.core.sign.gpg.GPG.keys", return_value=["key"])
|
mocker.patch("ahriman.core.database.SQLite.user_list", return_value=[user])
|
||||||
|
|
||||||
assert KeyringGenerator(gpg, configuration, "keyring").packagers == ["key"]
|
assert KeyringGenerator(database, gpg, configuration, "keyring").packagers == ["key"]
|
||||||
|
|
||||||
configuration.set_option("keyring", "packagers", "key1")
|
configuration.set_option("keyring", "packagers", "key1")
|
||||||
assert KeyringGenerator(gpg, configuration, "keyring").packagers == ["key1"]
|
assert KeyringGenerator(database, gpg, configuration, "keyring").packagers == ["key1"]
|
||||||
|
|
||||||
|
|
||||||
def test_init_revoked(gpg: GPG, configuration: Configuration) -> None:
|
def test_init_revoked(database: SQLite, gpg: GPG, configuration: Configuration) -> None:
|
||||||
"""
|
"""
|
||||||
must extract revoked keys
|
must extract revoked keys
|
||||||
"""
|
"""
|
||||||
assert KeyringGenerator(gpg, configuration, "keyring").revoked == []
|
assert KeyringGenerator(database, gpg, configuration, "keyring").revoked == []
|
||||||
|
|
||||||
configuration.set_option("keyring", "revoked", "key1")
|
configuration.set_option("keyring", "revoked", "key1")
|
||||||
assert KeyringGenerator(gpg, configuration, "keyring").revoked == ["key1"]
|
assert KeyringGenerator(database, gpg, configuration, "keyring").revoked == ["key1"]
|
||||||
|
|
||||||
|
|
||||||
def test_init_trusted(gpg: GPG, configuration: Configuration) -> None:
|
def test_init_trusted(database: SQLite, gpg: GPG, configuration: Configuration) -> None:
|
||||||
"""
|
"""
|
||||||
must extract trusted keys
|
must extract trusted keys
|
||||||
"""
|
"""
|
||||||
assert KeyringGenerator(gpg, configuration, "keyring").trusted == []
|
assert KeyringGenerator(database, gpg, configuration, "keyring").trusted == []
|
||||||
|
|
||||||
gpg.default_key = "key"
|
gpg.default_key = "key"
|
||||||
assert KeyringGenerator(gpg, configuration, "keyring").trusted == ["key"]
|
assert KeyringGenerator(database, gpg, configuration, "keyring").trusted == ["key"]
|
||||||
|
|
||||||
configuration.set_option("keyring", "trusted", "key1")
|
configuration.set_option("keyring", "trusted", "key1")
|
||||||
assert KeyringGenerator(gpg, configuration, "keyring").trusted == ["key1"]
|
assert KeyringGenerator(database, gpg, configuration, "keyring").trusted == ["key1"]
|
||||||
|
|
||||||
|
|
||||||
def test_license(gpg: GPG, configuration: Configuration) -> None:
|
def test_license(database: SQLite, gpg: GPG, configuration: Configuration) -> None:
|
||||||
"""
|
"""
|
||||||
must generate correct licenses list
|
must generate correct licenses list
|
||||||
"""
|
"""
|
||||||
assert KeyringGenerator(gpg, configuration, "keyring").license == ["Unlicense"]
|
assert KeyringGenerator(database, gpg, configuration, "keyring").license == ["Unlicense"]
|
||||||
|
|
||||||
configuration.set_option("keyring", "license", "GPL MPL")
|
configuration.set_option("keyring", "license", "GPL MPL")
|
||||||
assert KeyringGenerator(gpg, configuration, "keyring").license == ["GPL", "MPL"]
|
assert KeyringGenerator(database, gpg, configuration, "keyring").license == ["GPL", "MPL"]
|
||||||
|
|
||||||
|
|
||||||
def test_pkgdesc(gpg: GPG, configuration: Configuration) -> None:
|
def test_pkgdesc(database: SQLite, gpg: GPG, configuration: Configuration) -> None:
|
||||||
"""
|
"""
|
||||||
must generate correct pkgdesc property
|
must generate correct pkgdesc property
|
||||||
"""
|
"""
|
||||||
assert KeyringGenerator(gpg, configuration, "keyring").pkgdesc == "aur-clone PGP keyring"
|
assert KeyringGenerator(database, gpg, configuration, "keyring").pkgdesc == "aur-clone PGP keyring"
|
||||||
|
|
||||||
configuration.set_option("keyring", "description", "description")
|
configuration.set_option("keyring", "description", "description")
|
||||||
assert KeyringGenerator(gpg, configuration, "keyring").pkgdesc == "description"
|
assert KeyringGenerator(database, gpg, configuration, "keyring").pkgdesc == "description"
|
||||||
|
|
||||||
|
|
||||||
def test_pkgname(gpg: GPG, configuration: Configuration) -> None:
|
def test_pkgname(database: SQLite, gpg: GPG, configuration: Configuration) -> None:
|
||||||
"""
|
"""
|
||||||
must generate correct pkgname property
|
must generate correct pkgname property
|
||||||
"""
|
"""
|
||||||
assert KeyringGenerator(gpg, configuration, "keyring").pkgname == "aur-clone-keyring"
|
assert KeyringGenerator(database, gpg, configuration, "keyring").pkgname == "aur-clone-keyring"
|
||||||
|
|
||||||
configuration.set_option("keyring", "package", "keyring")
|
configuration.set_option("keyring", "package", "keyring")
|
||||||
assert KeyringGenerator(gpg, configuration, "keyring").pkgname == "keyring"
|
assert KeyringGenerator(database, gpg, configuration, "keyring").pkgname == "keyring"
|
||||||
|
|
||||||
|
|
||||||
def test_url(gpg: GPG, configuration: Configuration) -> None:
|
def test_url(database: SQLite, gpg: GPG, configuration: Configuration) -> None:
|
||||||
"""
|
"""
|
||||||
must generate correct url property
|
must generate correct url property
|
||||||
"""
|
"""
|
||||||
assert KeyringGenerator(gpg, configuration, "keyring").url == ""
|
assert KeyringGenerator(database, gpg, configuration, "keyring").url == ""
|
||||||
|
|
||||||
configuration.set_option("keyring", "homepage", "homepage")
|
configuration.set_option("keyring", "homepage", "homepage")
|
||||||
assert KeyringGenerator(gpg, configuration, "keyring").url == "homepage"
|
assert KeyringGenerator(database, gpg, configuration, "keyring").url == "homepage"
|
||||||
|
|
||||||
|
|
||||||
def test_generate_gpg(keyring_generator: KeyringGenerator, mocker: MockerFixture) -> None:
|
def test_generate_gpg(keyring_generator: KeyringGenerator, mocker: MockerFixture) -> None:
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
from pytest_mock import MockerFixture
|
from pytest_mock import MockerFixture
|
||||||
|
from unittest.mock import call as MockCall
|
||||||
|
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
|
from ahriman.core.database import SQLite
|
||||||
from ahriman.core.sign.gpg import GPG
|
from ahriman.core.sign.gpg import GPG
|
||||||
from ahriman.core.support import KeyringTrigger
|
from ahriman.core.support import KeyringTrigger
|
||||||
from ahriman.models.context_key import ContextKey
|
from ahriman.models.context_key import ContextKey
|
||||||
@ -21,10 +23,10 @@ def test_on_start(configuration: Configuration, mocker: MockerFixture) -> None:
|
|||||||
"""
|
"""
|
||||||
must run report for specified targets
|
must run report for specified targets
|
||||||
"""
|
"""
|
||||||
gpg_mock = mocker.patch("ahriman.core._Context.get")
|
context_mock = mocker.patch("ahriman.core._Context.get")
|
||||||
run_mock = mocker.patch("ahriman.core.support.package_creator.PackageCreator.run")
|
run_mock = mocker.patch("ahriman.core.support.package_creator.PackageCreator.run")
|
||||||
|
|
||||||
trigger = KeyringTrigger("x86_64", configuration)
|
trigger = KeyringTrigger("x86_64", configuration)
|
||||||
trigger.on_start()
|
trigger.on_start()
|
||||||
gpg_mock.assert_called_once_with(ContextKey("sign", GPG))
|
context_mock.assert_has_calls([MockCall(ContextKey("sign", GPG)), MockCall(ContextKey("database", SQLite))])
|
||||||
run_mock.assert_called_once_with()
|
run_mock.assert_called_once_with()
|
||||||
|
@ -35,6 +35,6 @@ def test_run(package_creator: PackageCreator, database: SQLite, mocker: MockerFi
|
|||||||
write_mock.assert_called_once_with(local_path)
|
write_mock.assert_called_once_with(local_path)
|
||||||
init_mock.assert_called_once_with(local_path)
|
init_mock.assert_called_once_with(local_path)
|
||||||
|
|
||||||
package_mock.assert_called_once_with(local_path, "x86_64")
|
package_mock.assert_called_once_with(local_path, "x86_64", None)
|
||||||
database_mock.assert_called_once_with(ContextKey("database", SQLite))
|
database_mock.assert_called_once_with(ContextKey("database", SQLite))
|
||||||
insert_mock.assert_called_once_with(package, pytest.helpers.anyvar(int))
|
insert_mock.assert_called_once_with(package, pytest.helpers.anyvar(int))
|
||||||
|
@ -42,7 +42,7 @@ def test_spawn_process(spawner: Spawn, mocker: MockerFixture) -> None:
|
|||||||
"""
|
"""
|
||||||
start_mock = mocker.patch("multiprocessing.Process.start")
|
start_mock = mocker.patch("multiprocessing.Process.start")
|
||||||
|
|
||||||
spawner._spawn_process("add", "ahriman", now="", maybe="?")
|
spawner._spawn_process("add", "ahriman", now="", maybe="?", none=None)
|
||||||
start_mock.assert_called_once_with()
|
start_mock.assert_called_once_with()
|
||||||
spawner.args_parser.parse_args.assert_called_once_with(
|
spawner.args_parser.parse_args.assert_called_once_with(
|
||||||
spawner.command_arguments + [
|
spawner.command_arguments + [
|
||||||
@ -74,8 +74,8 @@ def test_packages_add(spawner: Spawn, mocker: MockerFixture) -> None:
|
|||||||
must call package addition
|
must call package addition
|
||||||
"""
|
"""
|
||||||
spawn_mock = mocker.patch("ahriman.core.spawn.Spawn._spawn_process")
|
spawn_mock = mocker.patch("ahriman.core.spawn.Spawn._spawn_process")
|
||||||
spawner.packages_add(["ahriman", "linux"], now=False)
|
spawner.packages_add(["ahriman", "linux"], None, now=False)
|
||||||
spawn_mock.assert_called_once_with("package-add", "ahriman", "linux", source="aur")
|
spawn_mock.assert_called_once_with("package-add", "ahriman", "linux", source="aur", username=None)
|
||||||
|
|
||||||
|
|
||||||
def test_packages_add_with_build(spawner: Spawn, mocker: MockerFixture) -> None:
|
def test_packages_add_with_build(spawner: Spawn, mocker: MockerFixture) -> None:
|
||||||
@ -83,8 +83,17 @@ def test_packages_add_with_build(spawner: Spawn, mocker: MockerFixture) -> None:
|
|||||||
must call package addition with update
|
must call package addition with update
|
||||||
"""
|
"""
|
||||||
spawn_mock = mocker.patch("ahriman.core.spawn.Spawn._spawn_process")
|
spawn_mock = mocker.patch("ahriman.core.spawn.Spawn._spawn_process")
|
||||||
spawner.packages_add(["ahriman", "linux"], now=True)
|
spawner.packages_add(["ahriman", "linux"], None, now=True)
|
||||||
spawn_mock.assert_called_once_with("package-add", "ahriman", "linux", source="aur", now="")
|
spawn_mock.assert_called_once_with("package-add", "ahriman", "linux", source="aur", username=None, now="")
|
||||||
|
|
||||||
|
|
||||||
|
def test_packages_add_with_username(spawner: Spawn, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must call package addition with username
|
||||||
|
"""
|
||||||
|
spawn_mock = mocker.patch("ahriman.core.spawn.Spawn._spawn_process")
|
||||||
|
spawner.packages_add(["ahriman", "linux"], "username", now=False)
|
||||||
|
spawn_mock.assert_called_once_with("package-add", "ahriman", "linux", source="aur", username="username")
|
||||||
|
|
||||||
|
|
||||||
def test_packages_rebuild(spawner: Spawn, mocker: MockerFixture) -> None:
|
def test_packages_rebuild(spawner: Spawn, mocker: MockerFixture) -> None:
|
||||||
@ -92,8 +101,8 @@ def test_packages_rebuild(spawner: Spawn, mocker: MockerFixture) -> None:
|
|||||||
must call package rebuild
|
must call package rebuild
|
||||||
"""
|
"""
|
||||||
spawn_mock = mocker.patch("ahriman.core.spawn.Spawn._spawn_process")
|
spawn_mock = mocker.patch("ahriman.core.spawn.Spawn._spawn_process")
|
||||||
spawner.packages_rebuild("python")
|
spawner.packages_rebuild("python", "packager")
|
||||||
spawn_mock.assert_called_once_with("repo-rebuild", **{"depends-on": "python"})
|
spawn_mock.assert_called_once_with("repo-rebuild", **{"depends-on": "python", "username": "packager"})
|
||||||
|
|
||||||
|
|
||||||
def test_packages_remove(spawner: Spawn, mocker: MockerFixture) -> None:
|
def test_packages_remove(spawner: Spawn, mocker: MockerFixture) -> None:
|
||||||
@ -110,8 +119,8 @@ def test_packages_update(spawner: Spawn, mocker: MockerFixture) -> None:
|
|||||||
must call repo update
|
must call repo update
|
||||||
"""
|
"""
|
||||||
spawn_mock = mocker.patch("ahriman.core.spawn.Spawn._spawn_process")
|
spawn_mock = mocker.patch("ahriman.core.spawn.Spawn._spawn_process")
|
||||||
spawner.packages_update()
|
spawner.packages_update("packager")
|
||||||
spawn_mock.assert_called_once_with("repo-update")
|
spawn_mock.assert_called_once_with("repo-update", username="packager")
|
||||||
|
|
||||||
|
|
||||||
def test_run(spawner: Spawn, mocker: MockerFixture) -> None:
|
def test_run(spawner: Spawn, mocker: MockerFixture) -> None:
|
||||||
|
@ -11,9 +11,9 @@ from typing import Any
|
|||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
from ahriman.core.exceptions import BuildError, OptionError, UnsafeRunError
|
from ahriman.core.exceptions import BuildError, OptionError, UnsafeRunError
|
||||||
from ahriman.core.util import check_output, check_user, enum_values, exception_response_text, filter_json, \
|
from ahriman.core.util import check_output, check_user, dataclass_view, enum_values, exception_response_text,\
|
||||||
full_version, package_like, partition, pretty_datetime, pretty_size, safe_filename, srcinfo_property, \
|
extract_user, filter_json, full_version, package_like, partition, pretty_datetime, pretty_size, safe_filename, \
|
||||||
srcinfo_property_list, trim_package, utcnow, walk
|
srcinfo_property, srcinfo_property_list, trim_package, utcnow, walk
|
||||||
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
|
||||||
from ahriman.models.repository_paths import RepositoryPaths
|
from ahriman.models.repository_paths import RepositoryPaths
|
||||||
@ -91,6 +91,16 @@ def test_check_output_with_user(passwd: Any, mocker: MockerFixture) -> None:
|
|||||||
getpwuid_mock.assert_called_once_with(user)
|
getpwuid_mock.assert_called_once_with(user)
|
||||||
|
|
||||||
|
|
||||||
|
def test_check_output_with_user_and_environment(passwd: Any, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must run set environment if both environment and user are set
|
||||||
|
"""
|
||||||
|
mocker.patch("ahriman.core.util.getpwuid", return_value=passwd)
|
||||||
|
user = os.getuid()
|
||||||
|
assert check_output("python", "-c", """import os; print(os.getenv("HOME"), os.getenv("VAR"))""",
|
||||||
|
environment={"VAR": "VALUE"}, user=user) == f"{passwd.pw_dir} VALUE"
|
||||||
|
|
||||||
|
|
||||||
def test_check_output_failure(mocker: MockerFixture) -> None:
|
def test_check_output_failure(mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must process exception correctly
|
must process exception correctly
|
||||||
@ -155,6 +165,23 @@ def test_check_user_unsafe(mocker: MockerFixture) -> None:
|
|||||||
check_user(paths, unsafe=True)
|
check_user(paths, unsafe=True)
|
||||||
|
|
||||||
|
|
||||||
|
def test_dataclass_view(package_ahriman: Package) -> None:
|
||||||
|
"""
|
||||||
|
must serialize dataclasses
|
||||||
|
"""
|
||||||
|
assert Package.from_json(dataclass_view(package_ahriman)) == package_ahriman
|
||||||
|
|
||||||
|
|
||||||
|
def test_dataclass_view_without_none(package_ahriman: Package) -> None:
|
||||||
|
"""
|
||||||
|
must serialize dataclasses with None fields removed
|
||||||
|
"""
|
||||||
|
package_ahriman.packager = None
|
||||||
|
result = dataclass_view(package_ahriman)
|
||||||
|
assert "packager" not in result
|
||||||
|
assert Package.from_json(result) == package_ahriman
|
||||||
|
|
||||||
|
|
||||||
def test_exception_response_text() -> None:
|
def test_exception_response_text() -> None:
|
||||||
"""
|
"""
|
||||||
must parse HTTP response to string
|
must parse HTTP response to string
|
||||||
@ -174,6 +201,23 @@ def test_exception_response_text_empty() -> None:
|
|||||||
assert exception_response_text(exception) == ""
|
assert exception_response_text(exception) == ""
|
||||||
|
|
||||||
|
|
||||||
|
def test_extract_user() -> None:
|
||||||
|
"""
|
||||||
|
must extract user from system environment
|
||||||
|
"""
|
||||||
|
os.environ["USER"] = "user"
|
||||||
|
assert extract_user() == "user"
|
||||||
|
|
||||||
|
os.environ["SUDO_USER"] = "sudo"
|
||||||
|
assert extract_user() == "sudo"
|
||||||
|
|
||||||
|
os.environ["DOAS_USER"] = "doas"
|
||||||
|
assert extract_user() == "sudo"
|
||||||
|
|
||||||
|
del os.environ["SUDO_USER"]
|
||||||
|
assert extract_user() == "doas"
|
||||||
|
|
||||||
|
|
||||||
def test_filter_json(package_ahriman: Package) -> None:
|
def test_filter_json(package_ahriman: Package) -> None:
|
||||||
"""
|
"""
|
||||||
must filter fields by known list
|
must filter fields by known list
|
||||||
|
@ -116,6 +116,7 @@ def pyalpm_package_ahriman(aur_package_ahriman: AURPackage) -> MagicMock:
|
|||||||
type(mock).name = PropertyMock(return_value=aur_package_ahriman.name)
|
type(mock).name = PropertyMock(return_value=aur_package_ahriman.name)
|
||||||
type(mock).optdepends = PropertyMock(return_value=aur_package_ahriman.opt_depends)
|
type(mock).optdepends = PropertyMock(return_value=aur_package_ahriman.opt_depends)
|
||||||
type(mock).checkdepends = PropertyMock(return_value=aur_package_ahriman.check_depends)
|
type(mock).checkdepends = PropertyMock(return_value=aur_package_ahriman.check_depends)
|
||||||
|
type(mock).packager = PropertyMock(return_value="packager")
|
||||||
type(mock).provides = PropertyMock(return_value=aur_package_ahriman.provides)
|
type(mock).provides = PropertyMock(return_value=aur_package_ahriman.provides)
|
||||||
type(mock).version = PropertyMock(return_value=aur_package_ahriman.version)
|
type(mock).version = PropertyMock(return_value=aur_package_ahriman.version)
|
||||||
type(mock).url = PropertyMock(return_value=aur_package_ahriman.url)
|
type(mock).url = PropertyMock(return_value=aur_package_ahriman.url)
|
||||||
|
@ -56,7 +56,7 @@ def test_depends_build_with_version_and_overlap(mocker: MockerFixture, resource_
|
|||||||
srcinfo = (resource_path_root / "models" / "package_gcc10_srcinfo").read_text()
|
srcinfo = (resource_path_root / "models" / "package_gcc10_srcinfo").read_text()
|
||||||
mocker.patch("ahriman.models.package.Package._check_output", return_value=srcinfo)
|
mocker.patch("ahriman.models.package.Package._check_output", return_value=srcinfo)
|
||||||
|
|
||||||
package_gcc10 = Package.from_build(Path("local"), "x86_64")
|
package_gcc10 = Package.from_build(Path("local"), "x86_64", None)
|
||||||
assert package_gcc10.depends_build == {
|
assert package_gcc10.depends_build == {
|
||||||
"glibc", "zstd", # depends
|
"glibc", "zstd", # depends
|
||||||
"doxygen", "binutils", "git", "libmpc", "python", # make depends
|
"doxygen", "binutils", "git", "libmpc", "python", # make depends
|
||||||
@ -168,10 +168,11 @@ def test_from_aur(package_ahriman: Package, aur_package_ahriman: AURPackage, pac
|
|||||||
"""
|
"""
|
||||||
mocker.patch("ahriman.core.alpm.remote.AUR.info", return_value=aur_package_ahriman)
|
mocker.patch("ahriman.core.alpm.remote.AUR.info", return_value=aur_package_ahriman)
|
||||||
|
|
||||||
package = Package.from_aur(package_ahriman.base, pacman)
|
package = Package.from_aur(package_ahriman.base, pacman, package_ahriman.packager)
|
||||||
assert package_ahriman.base == package.base
|
assert package_ahriman.base == package.base
|
||||||
assert package_ahriman.version == package.version
|
assert package_ahriman.version == package.version
|
||||||
assert package_ahriman.packages.keys() == package.packages.keys()
|
assert package_ahriman.packages.keys() == package.packages.keys()
|
||||||
|
assert package_ahriman.packager == package.packager
|
||||||
|
|
||||||
|
|
||||||
def test_from_build(package_ahriman: Package, mocker: MockerFixture, resource_path_root: Path) -> None:
|
def test_from_build(package_ahriman: Package, mocker: MockerFixture, resource_path_root: Path) -> None:
|
||||||
@ -181,7 +182,7 @@ def test_from_build(package_ahriman: Package, mocker: MockerFixture, resource_pa
|
|||||||
srcinfo = (resource_path_root / "models" / "package_ahriman_srcinfo").read_text()
|
srcinfo = (resource_path_root / "models" / "package_ahriman_srcinfo").read_text()
|
||||||
mocker.patch("ahriman.models.package.Package._check_output", return_value=srcinfo)
|
mocker.patch("ahriman.models.package.Package._check_output", return_value=srcinfo)
|
||||||
|
|
||||||
package = Package.from_build(Path("path"), "x86_64")
|
package = Package.from_build(Path("path"), "x86_64", "packager")
|
||||||
assert package_ahriman.packages.keys() == package.packages.keys()
|
assert package_ahriman.packages.keys() == package.packages.keys()
|
||||||
package_ahriman.packages = package.packages # we are not going to test PackageDescription here
|
package_ahriman.packages = package.packages # we are not going to test PackageDescription here
|
||||||
package_ahriman.remote = package.remote
|
package_ahriman.remote = package.remote
|
||||||
@ -195,7 +196,7 @@ def test_from_build_multiple_packages(mocker: MockerFixture, resource_path_root:
|
|||||||
srcinfo = (resource_path_root / "models" / "package_gcc10_srcinfo").read_text()
|
srcinfo = (resource_path_root / "models" / "package_gcc10_srcinfo").read_text()
|
||||||
mocker.patch("ahriman.models.package.Package._check_output", return_value=srcinfo)
|
mocker.patch("ahriman.models.package.Package._check_output", return_value=srcinfo)
|
||||||
|
|
||||||
package = Package.from_build(Path("path"), "x86_64")
|
package = Package.from_build(Path("path"), "x86_64", None)
|
||||||
assert package.packages == {
|
assert package.packages == {
|
||||||
"gcc10": PackageDescription(
|
"gcc10": PackageDescription(
|
||||||
depends=["gcc10-libs=10.3.0-2", "binutils>=2.28", "libmpc", "zstd"],
|
depends=["gcc10-libs=10.3.0-2", "binutils>=2.28", "libmpc", "zstd"],
|
||||||
@ -225,7 +226,7 @@ def test_from_build_architecture(mocker: MockerFixture, resource_path_root: Path
|
|||||||
srcinfo = (resource_path_root / "models" / "package_jellyfin-ffmpeg5-bin_srcinfo").read_text()
|
srcinfo = (resource_path_root / "models" / "package_jellyfin-ffmpeg5-bin_srcinfo").read_text()
|
||||||
mocker.patch("ahriman.models.package.Package._check_output", return_value=srcinfo)
|
mocker.patch("ahriman.models.package.Package._check_output", return_value=srcinfo)
|
||||||
|
|
||||||
package = Package.from_build(Path("path"), "x86_64")
|
package = Package.from_build(Path("path"), "x86_64", None)
|
||||||
assert package.packages == {
|
assert package.packages == {
|
||||||
"jellyfin-ffmpeg5-bin": PackageDescription(
|
"jellyfin-ffmpeg5-bin": PackageDescription(
|
||||||
depends=["glibc"],
|
depends=["glibc"],
|
||||||
@ -254,7 +255,7 @@ def test_from_build_failed(package_ahriman: Package, mocker: MockerFixture) -> N
|
|||||||
mocker.patch("ahriman.models.package.parse_srcinfo", return_value=({"packages": {}}, ["an error"]))
|
mocker.patch("ahriman.models.package.parse_srcinfo", return_value=({"packages": {}}, ["an error"]))
|
||||||
|
|
||||||
with pytest.raises(PackageInfoError):
|
with pytest.raises(PackageInfoError):
|
||||||
Package.from_build(Path("path"), "x86_64")
|
Package.from_build(Path("path"), "x86_64", None)
|
||||||
|
|
||||||
|
|
||||||
def test_from_json_view_1(package_ahriman: Package) -> None:
|
def test_from_json_view_1(package_ahriman: Package) -> None:
|
||||||
@ -285,10 +286,11 @@ def test_from_official(package_ahriman: Package, aur_package_ahriman: AURPackage
|
|||||||
"""
|
"""
|
||||||
mocker.patch("ahriman.core.alpm.remote.Official.info", return_value=aur_package_ahriman)
|
mocker.patch("ahriman.core.alpm.remote.Official.info", return_value=aur_package_ahriman)
|
||||||
|
|
||||||
package = Package.from_official(package_ahriman.base, pacman)
|
package = Package.from_official(package_ahriman.base, pacman, package_ahriman.packager)
|
||||||
assert package_ahriman.base == package.base
|
assert package_ahriman.base == package.base
|
||||||
assert package_ahriman.version == package.version
|
assert package_ahriman.version == package.version
|
||||||
assert package_ahriman.packages.keys() == package.packages.keys()
|
assert package_ahriman.packages.keys() == package.packages.keys()
|
||||||
|
assert package_ahriman.packager == package.packager
|
||||||
|
|
||||||
|
|
||||||
def test_local_files(mocker: MockerFixture, resource_path_root: Path) -> None:
|
def test_local_files(mocker: MockerFixture, resource_path_root: Path) -> None:
|
||||||
|
12
tests/ahriman/models/test_packagers.py
Normal file
12
tests/ahriman/models/test_packagers.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
from ahriman.models.package import Package
|
||||||
|
from ahriman.models.packagers import Packagers
|
||||||
|
|
||||||
|
|
||||||
|
def test_for_base(package_ahriman: Package) -> None:
|
||||||
|
"""
|
||||||
|
must return username used for base package
|
||||||
|
"""
|
||||||
|
assert Packagers(None, {package_ahriman.base: "packager"}).for_base(package_ahriman.base) == "packager"
|
||||||
|
assert Packagers("default", {package_ahriman.base: "packager"}).for_base("random") == "default"
|
||||||
|
assert Packagers("default").for_base(package_ahriman.base) == "default"
|
||||||
|
assert Packagers().for_base(package_ahriman.base) is None
|
@ -8,7 +8,7 @@ def test_from_option(user: User) -> None:
|
|||||||
"""
|
"""
|
||||||
must generate user from options
|
must generate user from options
|
||||||
"""
|
"""
|
||||||
user = replace(user, access=UserAccess.Read)
|
user = replace(user, access=UserAccess.Read, packager_id=None, key=None)
|
||||||
assert User.from_option(user.username, user.password) == user
|
assert User.from_option(user.username, user.password) == user
|
||||||
# default is read access
|
# default is read access
|
||||||
user = replace(user, access=UserAccess.Full)
|
user = replace(user, access=UserAccess.Full)
|
||||||
|
@ -2,6 +2,7 @@ import pytest
|
|||||||
|
|
||||||
from aiohttp.test_utils import TestClient
|
from aiohttp.test_utils import TestClient
|
||||||
from pytest_mock import MockerFixture
|
from pytest_mock import MockerFixture
|
||||||
|
from unittest.mock import AsyncMock
|
||||||
|
|
||||||
from ahriman.models.user_access import UserAccess
|
from ahriman.models.user_access import UserAccess
|
||||||
from ahriman.web.views.service.add import AddView
|
from ahriman.web.views.service.add import AddView
|
||||||
@ -21,13 +22,16 @@ async def test_post(client: TestClient, mocker: MockerFixture) -> None:
|
|||||||
must call post request correctly
|
must call post request correctly
|
||||||
"""
|
"""
|
||||||
add_mock = mocker.patch("ahriman.core.spawn.Spawn.packages_add")
|
add_mock = mocker.patch("ahriman.core.spawn.Spawn.packages_add")
|
||||||
|
user_mock = AsyncMock()
|
||||||
|
user_mock.return_value = "username"
|
||||||
|
mocker.patch("ahriman.web.views.base.BaseView.username", side_effect=user_mock)
|
||||||
request_schema = pytest.helpers.schema_request(AddView.post)
|
request_schema = pytest.helpers.schema_request(AddView.post)
|
||||||
|
|
||||||
payload = {"packages": ["ahriman"]}
|
payload = {"packages": ["ahriman"]}
|
||||||
assert not request_schema.validate(payload)
|
assert not request_schema.validate(payload)
|
||||||
response = await client.post("/api/v1/service/add", json=payload)
|
response = await client.post("/api/v1/service/add", json=payload)
|
||||||
assert response.ok
|
assert response.ok
|
||||||
add_mock.assert_called_once_with(["ahriman"], now=True)
|
add_mock.assert_called_once_with(["ahriman"], "username", now=True)
|
||||||
|
|
||||||
|
|
||||||
async def test_post_empty(client: TestClient, mocker: MockerFixture) -> None:
|
async def test_post_empty(client: TestClient, mocker: MockerFixture) -> None:
|
||||||
|
@ -2,6 +2,7 @@ import pytest
|
|||||||
|
|
||||||
from aiohttp.test_utils import TestClient
|
from aiohttp.test_utils import TestClient
|
||||||
from pytest_mock import MockerFixture
|
from pytest_mock import MockerFixture
|
||||||
|
from unittest.mock import AsyncMock
|
||||||
|
|
||||||
from ahriman.models.user_access import UserAccess
|
from ahriman.models.user_access import UserAccess
|
||||||
from ahriman.web.views.service.rebuild import RebuildView
|
from ahriman.web.views.service.rebuild import RebuildView
|
||||||
@ -21,13 +22,16 @@ async def test_post(client: TestClient, mocker: MockerFixture) -> None:
|
|||||||
must call post request correctly
|
must call post request correctly
|
||||||
"""
|
"""
|
||||||
rebuild_mock = mocker.patch("ahriman.core.spawn.Spawn.packages_rebuild")
|
rebuild_mock = mocker.patch("ahriman.core.spawn.Spawn.packages_rebuild")
|
||||||
|
user_mock = AsyncMock()
|
||||||
|
user_mock.return_value = "username"
|
||||||
|
mocker.patch("ahriman.web.views.base.BaseView.username", side_effect=user_mock)
|
||||||
request_schema = pytest.helpers.schema_request(RebuildView.post)
|
request_schema = pytest.helpers.schema_request(RebuildView.post)
|
||||||
|
|
||||||
payload = {"packages": ["python", "ahriman"]}
|
payload = {"packages": ["python", "ahriman"]}
|
||||||
assert not request_schema.validate(payload)
|
assert not request_schema.validate(payload)
|
||||||
response = await client.post("/api/v1/service/rebuild", json=payload)
|
response = await client.post("/api/v1/service/rebuild", json=payload)
|
||||||
assert response.ok
|
assert response.ok
|
||||||
rebuild_mock.assert_called_once_with("python")
|
rebuild_mock.assert_called_once_with("python", "username")
|
||||||
|
|
||||||
|
|
||||||
async def test_post_exception(client: TestClient, mocker: MockerFixture) -> None:
|
async def test_post_exception(client: TestClient, mocker: MockerFixture) -> None:
|
||||||
|
@ -2,6 +2,7 @@ import pytest
|
|||||||
|
|
||||||
from aiohttp.test_utils import TestClient
|
from aiohttp.test_utils import TestClient
|
||||||
from pytest_mock import MockerFixture
|
from pytest_mock import MockerFixture
|
||||||
|
from unittest.mock import AsyncMock
|
||||||
|
|
||||||
from ahriman.models.user_access import UserAccess
|
from ahriman.models.user_access import UserAccess
|
||||||
from ahriman.web.views.service.request import RequestView
|
from ahriman.web.views.service.request import RequestView
|
||||||
@ -21,13 +22,16 @@ async def test_post(client: TestClient, mocker: MockerFixture) -> None:
|
|||||||
must call post request correctly
|
must call post request correctly
|
||||||
"""
|
"""
|
||||||
add_mock = mocker.patch("ahriman.core.spawn.Spawn.packages_add")
|
add_mock = mocker.patch("ahriman.core.spawn.Spawn.packages_add")
|
||||||
|
user_mock = AsyncMock()
|
||||||
|
user_mock.return_value = "username"
|
||||||
|
mocker.patch("ahriman.web.views.base.BaseView.username", side_effect=user_mock)
|
||||||
request_schema = pytest.helpers.schema_request(RequestView.post)
|
request_schema = pytest.helpers.schema_request(RequestView.post)
|
||||||
|
|
||||||
payload = {"packages": ["ahriman"]}
|
payload = {"packages": ["ahriman"]}
|
||||||
assert not request_schema.validate(payload)
|
assert not request_schema.validate(payload)
|
||||||
response = await client.post("/api/v1/service/request", json=payload)
|
response = await client.post("/api/v1/service/request", json=payload)
|
||||||
assert response.ok
|
assert response.ok
|
||||||
add_mock.assert_called_once_with(["ahriman"], now=False)
|
add_mock.assert_called_once_with(["ahriman"], "username", now=False)
|
||||||
|
|
||||||
|
|
||||||
async def test_post_exception(client: TestClient, mocker: MockerFixture) -> None:
|
async def test_post_exception(client: TestClient, mocker: MockerFixture) -> None:
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
from aiohttp.test_utils import TestClient
|
from aiohttp.test_utils import TestClient
|
||||||
from pytest_mock import MockerFixture
|
from pytest_mock import MockerFixture
|
||||||
|
from unittest.mock import AsyncMock
|
||||||
|
|
||||||
|
|
||||||
async def test_post_update(client: TestClient, mocker: MockerFixture) -> None:
|
async def test_post_update(client: TestClient, mocker: MockerFixture) -> None:
|
||||||
@ -7,7 +8,10 @@ async def test_post_update(client: TestClient, mocker: MockerFixture) -> None:
|
|||||||
must call post request correctly for alias
|
must call post request correctly for alias
|
||||||
"""
|
"""
|
||||||
update_mock = mocker.patch("ahriman.core.spawn.Spawn.packages_update")
|
update_mock = mocker.patch("ahriman.core.spawn.Spawn.packages_update")
|
||||||
|
user_mock = AsyncMock()
|
||||||
|
user_mock.return_value = "username"
|
||||||
|
mocker.patch("ahriman.web.views.base.BaseView.username", side_effect=user_mock)
|
||||||
|
|
||||||
response = await client.post("/api/v1/service/update")
|
response = await client.post("/api/v1/service/update")
|
||||||
assert response.ok
|
assert response.ok
|
||||||
update_mock.assert_called_once_with()
|
update_mock.assert_called_once_with("username")
|
||||||
|
@ -2,6 +2,8 @@ import pytest
|
|||||||
|
|
||||||
from multidict import MultiDict
|
from multidict import MultiDict
|
||||||
from aiohttp.test_utils import TestClient
|
from aiohttp.test_utils import TestClient
|
||||||
|
from pytest_mock import MockerFixture
|
||||||
|
from unittest.mock import AsyncMock
|
||||||
|
|
||||||
from ahriman.models.user_access import UserAccess
|
from ahriman.models.user_access import UserAccess
|
||||||
from ahriman.web.views.base import BaseView
|
from ahriman.web.views.base import BaseView
|
||||||
@ -146,3 +148,22 @@ async def test_head_not_allowed(client: TestClient) -> None:
|
|||||||
"""
|
"""
|
||||||
response = await client.head("/api/v1/service/add")
|
response = await client.head("/api/v1/service/add")
|
||||||
assert response.status == 405
|
assert response.status == 405
|
||||||
|
|
||||||
|
|
||||||
|
async def test_username(base: BaseView, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must return identity of logged-in user
|
||||||
|
"""
|
||||||
|
policy = AsyncMock()
|
||||||
|
policy.identify.return_value = "identity"
|
||||||
|
mocker.patch("aiohttp.web.Application.get", return_value=policy)
|
||||||
|
|
||||||
|
assert await base.username() == "identity"
|
||||||
|
policy.identify.assert_called_once_with(base.request)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_username_no_auth(base: BaseView) -> None:
|
||||||
|
"""
|
||||||
|
must return None in case if auth is disabled
|
||||||
|
"""
|
||||||
|
assert await base.username() is None
|
||||||
|
Loading…
Reference in New Issue
Block a user