mirror of
				https://github.com/arcan1s/ahriman.git
				synced 2025-11-03 23:33:41 +00:00 
			
		
		
		
	add shell and version parser
This commit is contained in:
		
							
								
								
									
										10
									
								
								.github/ISSUE_TEMPLATE/bug-report.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								.github/ISSUE_TEMPLATE/bug-report.md
									
									
									
									
										vendored
									
									
								
							@ -11,9 +11,9 @@ assignees: ''
 | 
			
		||||
 | 
			
		||||
A clear and concise description of what the bug is.
 | 
			
		||||
 | 
			
		||||
### Steps to Reproduce
 | 
			
		||||
### Steps to reproduce
 | 
			
		||||
 | 
			
		||||
Steps to reproduce the behavior (commands, environment etc)
 | 
			
		||||
Steps to reproduce the behavior (commands, environment etc).
 | 
			
		||||
 | 
			
		||||
### Expected behavior
 | 
			
		||||
 | 
			
		||||
@ -21,4 +21,8 @@ A clear and concise description of what you expected to happen.
 | 
			
		||||
 | 
			
		||||
### Logs
 | 
			
		||||
 | 
			
		||||
Add logs to help explain your problem. Logs to stderr can be generated by using `--no-log` command line option.
 | 
			
		||||
Add logs to help explain your problem. By default, the application writes logs into `/dev/log` which is usually default systemd journal and can be accessed by `journalctl` command.
 | 
			
		||||
 | 
			
		||||
You can also attach any additional information which can be helpful, e.g. configuration used by the application (be aware of passwords and other secrets if any); it can be generated by using `ahriman config` command.
 | 
			
		||||
 | 
			
		||||
It is also sometimes useful to have information about installed packages which can be accessed by `ahriman version` command.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								.github/ISSUE_TEMPLATE/feature-request.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/ISSUE_TEMPLATE/feature-request.md
									
									
									
									
										vendored
									
									
								
							@ -13,7 +13,7 @@ Brief description of the feature required
 | 
			
		||||
 | 
			
		||||
### Cause of the feature request
 | 
			
		||||
 | 
			
		||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
 | 
			
		||||
A clear and concise description of what the problem is. E.g. I'm always frustrated when [...]
 | 
			
		||||
 | 
			
		||||
### Proposed changes and/or features
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -3,9 +3,9 @@
 | 
			
		||||
ahriman
 | 
			
		||||
.SH SYNOPSIS
 | 
			
		||||
.B ahriman
 | 
			
		||||
[-h] [-a ARCHITECTURE] [-c CONFIGURATION] [--force] [-l LOCK] [--no-report] [-q] [--unsafe] [-v] {aur-search,search,help,help-commands-unsafe,key-import,package-add,add,package-update,package-remove,remove,package-status,status,package-status-remove,package-status-update,status-update,patch-add,patch-list,patch-remove,repo-backup,repo-check,check,repo-clean,clean,repo-config,config,repo-rebuild,rebuild,repo-remove-unknown,remove-unknown,repo-report,report,repo-restore,repo-setup,init,repo-init,setup,repo-sign,sign,repo-status-update,repo-sync,sync,repo-triggers,repo-update,update,user-add,user-list,user-remove,web} ...
 | 
			
		||||
[-h] [-a ARCHITECTURE] [-c CONFIGURATION] [--force] [-l LOCK] [--no-report] [-q] [--unsafe] [-V] {aur-search,search,help,help-commands-unsafe,key-import,package-add,add,package-update,package-remove,remove,package-status,status,package-status-remove,package-status-update,status-update,patch-add,patch-list,patch-remove,repo-backup,repo-check,check,repo-clean,clean,repo-config,config,repo-rebuild,rebuild,repo-remove-unknown,remove-unknown,repo-report,report,repo-restore,repo-setup,init,repo-init,setup,repo-sign,sign,repo-status-update,repo-sync,sync,repo-triggers,repo-update,update,shell,user-add,user-list,user-remove,version,web} ...
 | 
			
		||||
.SH DESCRIPTION
 | 
			
		||||
ArcH Linux ReposItory MANager
 | 
			
		||||
ArcH linux ReposItory MANager
 | 
			
		||||
 | 
			
		||||
.SH OPTIONS
 | 
			
		||||
.TP
 | 
			
		||||
@ -37,7 +37,7 @@ force disable any logging
 | 
			
		||||
allow to run ahriman as non\-ahriman user. Some actions might be unavailable
 | 
			
		||||
 | 
			
		||||
.TP
 | 
			
		||||
\fB\-v\fR, \fB\-\-version\fR
 | 
			
		||||
\fB\-V\fR, \fB\-\-version\fR
 | 
			
		||||
show program's version number and exit
 | 
			
		||||
 | 
			
		||||
.SH
 | 
			
		||||
@ -121,6 +121,9 @@ run triggers
 | 
			
		||||
\fBahriman\fR \fI\,repo-update\/\fR
 | 
			
		||||
update packages
 | 
			
		||||
.TP
 | 
			
		||||
\fBahriman\fR \fI\,shell\/\fR
 | 
			
		||||
envoke python shell
 | 
			
		||||
.TP
 | 
			
		||||
\fBahriman\fR \fI\,user-add\/\fR
 | 
			
		||||
create or update user
 | 
			
		||||
.TP
 | 
			
		||||
@ -130,6 +133,9 @@ user known users and their access
 | 
			
		||||
\fBahriman\fR \fI\,user-remove\/\fR
 | 
			
		||||
remove user
 | 
			
		||||
.TP
 | 
			
		||||
\fBahriman\fR \fI\,version\/\fR
 | 
			
		||||
application version
 | 
			
		||||
.TP
 | 
			
		||||
\fBahriman\fR \fI\,web\/\fR
 | 
			
		||||
web server
 | 
			
		||||
.SH COMMAND \fI\,'ahriman aur-search'\/\fR
 | 
			
		||||
@ -544,6 +550,11 @@ do not include manual updates
 | 
			
		||||
\fB\-\-no\-vcs\fR
 | 
			
		||||
do not check VCS packages
 | 
			
		||||
 | 
			
		||||
.SH COMMAND \fI\,'ahriman shell'\/\fR
 | 
			
		||||
usage: ahriman shell [-h]
 | 
			
		||||
 | 
			
		||||
drop into python shell while having created application
 | 
			
		||||
 | 
			
		||||
.SH COMMAND \fI\,'ahriman user-add'\/\fR
 | 
			
		||||
usage: ahriman user-add [-h] [--as-service] [-p PASSWORD]
 | 
			
		||||
                        [-r {UserAccess.Unauthorized,UserAccess.Read,UserAccess.Reporter,UserAccess.Full}] [-s]
 | 
			
		||||
@ -606,6 +617,11 @@ username for web service
 | 
			
		||||
\fB\-s\fR, \fB\-\-secure\fR
 | 
			
		||||
set file permissions to user\-only
 | 
			
		||||
 | 
			
		||||
.SH COMMAND \fI\,'ahriman version'\/\fR
 | 
			
		||||
usage: ahriman version [-h]
 | 
			
		||||
 | 
			
		||||
print application and its dependencies versions
 | 
			
		||||
 | 
			
		||||
.SH COMMAND \fI\,'ahriman web'\/\fR
 | 
			
		||||
usage: ahriman web [-h]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -116,6 +116,14 @@ ahriman.application.handlers.setup module
 | 
			
		||||
   :no-undoc-members:
 | 
			
		||||
   :show-inheritance:
 | 
			
		||||
 | 
			
		||||
ahriman.application.handlers.shell module
 | 
			
		||||
-----------------------------------------
 | 
			
		||||
 | 
			
		||||
.. automodule:: ahriman.application.handlers.shell
 | 
			
		||||
   :members:
 | 
			
		||||
   :no-undoc-members:
 | 
			
		||||
   :show-inheritance:
 | 
			
		||||
 | 
			
		||||
ahriman.application.handlers.sign module
 | 
			
		||||
----------------------------------------
 | 
			
		||||
 | 
			
		||||
@ -172,6 +180,14 @@ ahriman.application.handlers.users module
 | 
			
		||||
   :no-undoc-members:
 | 
			
		||||
   :show-inheritance:
 | 
			
		||||
 | 
			
		||||
ahriman.application.handlers.versions module
 | 
			
		||||
--------------------------------------------
 | 
			
		||||
 | 
			
		||||
.. automodule:: ahriman.application.handlers.versions
 | 
			
		||||
   :members:
 | 
			
		||||
   :no-undoc-members:
 | 
			
		||||
   :show-inheritance:
 | 
			
		||||
 | 
			
		||||
ahriman.application.handlers.web module
 | 
			
		||||
---------------------------------------
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -76,6 +76,14 @@ ahriman.core.formatters.user\_printer module
 | 
			
		||||
   :no-undoc-members:
 | 
			
		||||
   :show-inheritance:
 | 
			
		||||
 | 
			
		||||
ahriman.core.formatters.version\_printer module
 | 
			
		||||
-----------------------------------------------
 | 
			
		||||
 | 
			
		||||
.. automodule:: ahriman.core.formatters.version_printer
 | 
			
		||||
   :members:
 | 
			
		||||
   :no-undoc-members:
 | 
			
		||||
   :show-inheritance:
 | 
			
		||||
 | 
			
		||||
Module contents
 | 
			
		||||
---------------
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -104,5 +104,4 @@ autodoc_member_order = "groupwise"
 | 
			
		||||
 | 
			
		||||
autodoc_default_options = {
 | 
			
		||||
    "no-undoc-members": True,
 | 
			
		||||
    "special-members": "__init__",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										18
									
								
								package/share/ahriman/templates/shell
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								package/share/ahriman/templates/shell
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
			
		||||
                                              [00m
 | 
			
		||||
                         [38;5;60m▄[48;5;60;38;5;67m▄[49;38;5;60m▄[39m    [38;5;60m▄▄▄▄▄▄[48;5;60m█[49m▀[39m      [00m
 | 
			
		||||
                       [38;5;60m▄[48;5;60;38;5;67m▄[48;5;67;38;5;60m▄[48;5;60;38;5;103m▄[48;5;103;38;5;110m▄[48;5;60;38;5;103m▄[38;5;67m▄▄▄[48;5;67m██[38;5;60m▄▄▄[38;5;67m█[48;5;60m▄[49;38;5;60m▄[39m      [00m
 | 
			
		||||
                       [48;5;60;38;5;60m█[48;5;67;38;5;67m█[48;5;60;38;5;103m▄[48;5;103;38;5;110m▄[48;5;110m██[48;5;103;38;5;103m█[48;5;60;38;5;67m▄▄▄▄[48;5;67;38;5;60m▄[38;5;67m██[48;5;60m▄[48;5;67;38;5;60m▄[38;5;67m█[48;5;60m▄[49;38;5;60m▄[39m    [00m
 | 
			
		||||
                       [48;5;60;38;5;60m█[48;5;67m▄[48;5;103;38;5;103m█[48;5;110;38;5;110m█[48;5;103;38;5;103m█[48;5;110;38;5;110m██[48;5;103;38;5;103m█[48;5;60;38;5;110m▄▄[38;5;103m▄[48;5;110;38;5;110m█[48;5;60;38;5;60m█[48;5;67;38;5;67m██[48;5;60m▄[48;5;67;38;5;60m▄[38;5;67m█[48;5;60m▄[49;38;5;60m▄[39m  [38;5;60m▄[39m[00m
 | 
			
		||||
                       [48;5;60;38;5;60m█[38;5;67m▄[48;5;103;38;5;60m▄[48;5;110;38;5;103m▄[38;5;110m█████████[48;5;60m▄▄[48;5;67;38;5;60m▄▄[49m▀[48;5;67m▄[38;5;67m█[48;5;60m▄[38;5;60m█[49m▀[39m[00m
 | 
			
		||||
                      [48;5;60;38;5;60m█[49m▄▀[48;5;67m▄[48;5;103;38;5;103m█[48;5;110;38;5;110m███[38;5;232m▄[38;5;110m█[38;5;232m▄▄▄▄[38;5;110m███[48;5;103m▄[49;38;5;103m▄[39m [38;5;60m▀▀[39m  [00m
 | 
			
		||||
                      [48;5;60;38;5;60m█[48;5;67m▄[48;5;60;38;5;67m▄▄[48;5;103;38;5;103m█[48;5;110;38;5;110m███[38;5;232m▄[48;5;232m█[48;5;188;38;5;188m█[48;5;231;38;5;231m██[48;5;232;38;5;232m██[48;5;110;38;5;110m███[48;5;103;38;5;103m█[49;39m     [00m
 | 
			
		||||
         [38;5;60m▄▄[48;5;60;38;5;67m▄▄▄▄[49;38;5;60m▄▄▄[39m     [38;5;60m▀[48;5;60m█[38;5;67m▄[48;5;103;38;5;103m█[48;5;110;38;5;110m████[48;5;232m▄[48;5;145;38;5;231m▄[48;5;232;38;5;145m▄[38;5;231m▄[38;5;232m█[38;5;231m▄[48;5;110;38;5;110m██[48;5;103;38;5;103m█[49m▄[39m     [00m
 | 
			
		||||
       [38;5;60m▄[48;5;60;38;5;67m▄[48;5;67m███[38;5;60m▄▄▄▄▄▄[48;5;60;38;5;67m▄▄[49;38;5;60m▄[39m    [38;5;60m▀[39m [38;5;103m▀[48;5;110m▄[38;5;110m█████[48;5;188m▄▄[48;5;110m█[38;5;103m▄[38;5;110m██[48;5;103;38;5;103m█[49;39m     [00m
 | 
			
		||||
       [48;5;60;38;5;60m█[48;5;67;38;5;67m██[38;5;60m▄[48;5;60;38;5;67m▄[48;5;67m████[38;5;60m▄▄[48;5;60m█[48;5;67m▄[38;5;67m█[48;5;60;38;5;60m█[49;38;5;103m▄▄▄[39m   [48;5;103;38;5;103m█[48;5;110;38;5;110m██[48;5;103m▄[48;5;110;38;5;103m▄▄▄▄▄[48;5;103m█[49m▀▀[39m      [00m
 | 
			
		||||
       [48;5;60;38;5;60m█[48;5;67;38;5;67m█[48;5;60;38;5;60m█[48;5;67;38;5;67m████[38;5;60m▄[49m▀[39m    [48;5;60;38;5;103m▄[48;5;103;38;5;110m▄[48;5;110;38;5;179m▄[38;5;110m██[48;5;103m▄▄▄[48;5;110m████[48;5;103;38;5;103m█[49;39m             [00m
 | 
			
		||||
       [48;5;60;38;5;60m█[48;5;67;38;5;67m█[48;5;60m▄[48;5;67;38;5;60m▄[38;5;67m███[48;5;60;38;5;60m█[49;39m    [48;5;103;38;5;103m█[48;5;185;38;5;110m▄[48;5;110m█[38;5;179m▄[48;5;179;38;5;110m▄[48;5;110m████████[48;5;103;38;5;103m█[49;39m             [00m
 | 
			
		||||
      [38;5;60m▄[48;5;60;38;5;67m▄[48;5;67m█[38;5;60m▄[48;5;60;38;5;67m▄[48;5;67m██[38;5;60m▄[49m▀[39m    [38;5;103m▀[48;5;110m▄[38;5;110m████[38;5;103m▄[38;5;110m██[38;5;103m▄[38;5;110m██[38;5;103m▄[48;5;103;38;5;67m▄[49;39m             [00m
 | 
			
		||||
      [48;5;60;38;5;60m█[48;5;67;38;5;67m██[48;5;60;38;5;60m█[48;5;67;38;5;67m███[48;5;60;38;5;60m█[49;39m      [38;5;103m▄[48;5;103m█[48;5;110;38;5;110m██[38;5;103m▄[48;5;103;38;5;110m▄[38;5;67m▄[38;5;103m█[38;5;110m▄[48;5;110m█[48;5;103;38;5;103m█[48;5;110;38;5;110m█[48;5;67;38;5;67m█[49;39m             [00m
 | 
			
		||||
     [38;5;60m▄[48;5;60;38;5;67m▄[48;5;67;38;5;60m▄[48;5;60;38;5;67m▄[48;5;67m███[38;5;60m▄[49m▀[39m     [38;5;103m▄[48;5;103;38;5;110m▄[48;5;110m██[48;5;103;38;5;103m█[48;5;110;38;5;110m█[48;5;67;38;5;67m█[49;39m [48;5;103;38;5;103m█[48;5;110;38;5;110m██[48;5;103m▄[48;5;110;38;5;103m▄[48;5;67;38;5;110m▄[49;38;5;67m▄[39m            [00m
 | 
			
		||||
 [38;5;60m▄▄▄[48;5;60m█[48;5;67;38;5;67m█[38;5;60m▄[48;5;60;38;5;67m▄[48;5;67m█[38;5;60m▄▄▄[49m▀[39m      [48;5;103;38;5;103m█[48;5;110;38;5;110m███[48;5;103;38;5;103m█[48;5;110;38;5;67m▄[48;5;67m█[49;39m [48;5;103;38;5;103m█[48;5;110;38;5;110m███[48;5;103;38;5;103m█[48;5;110;38;5;67m▄[48;5;67m█[49;39m            [00m
 | 
			
		||||
  [38;5;60m▀▀▀▀▀▀▀[39m           [38;5;103m▀▀▀▀[39m    [38;5;103m▀▀▀▀[39m              [00m
 | 
			
		||||
							
								
								
									
										1
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								setup.py
									
									
									
									
									
								
							@ -66,6 +66,7 @@ setup(
 | 
			
		||||
            "package/share/ahriman/templates/build-status.jinja2",
 | 
			
		||||
            "package/share/ahriman/templates/email-index.jinja2",
 | 
			
		||||
            "package/share/ahriman/templates/repo-index.jinja2",
 | 
			
		||||
            "package/share/ahriman/templates/shell",
 | 
			
		||||
            "package/share/ahriman/templates/telegram-index.jinja2",
 | 
			
		||||
        ]),
 | 
			
		||||
        ("share/ahriman/templates/build-status", [
 | 
			
		||||
 | 
			
		||||
@ -26,6 +26,7 @@ from typing import List, TypeVar
 | 
			
		||||
 | 
			
		||||
from ahriman import version
 | 
			
		||||
from ahriman.application import handlers
 | 
			
		||||
from ahriman.core.util import enum_values
 | 
			
		||||
from ahriman.models.action import Action
 | 
			
		||||
from ahriman.models.build_status import BuildStatusEnum
 | 
			
		||||
from ahriman.models.package_source import PackageSource
 | 
			
		||||
@ -76,7 +77,7 @@ def _parser() -> argparse.ArgumentParser:
 | 
			
		||||
    parser.add_argument("-q", "--quiet", help="force disable any logging", action="store_true")
 | 
			
		||||
    parser.add_argument("--unsafe", help="allow to run ahriman as non-ahriman user. Some actions might be unavailable",
 | 
			
		||||
                        action="store_true")
 | 
			
		||||
    parser.add_argument("-v", "--version", action="version", version=version.__version__)
 | 
			
		||||
    parser.add_argument("-V", "--version", action="version", version=version.__version__)
 | 
			
		||||
 | 
			
		||||
    subparsers = parser.add_subparsers(title="command", help="command to run", dest="command", required=True)
 | 
			
		||||
 | 
			
		||||
@ -106,9 +107,11 @@ def _parser() -> argparse.ArgumentParser:
 | 
			
		||||
    _set_repo_sync_parser(subparsers)
 | 
			
		||||
    _set_repo_triggers_parser(subparsers)
 | 
			
		||||
    _set_repo_update_parser(subparsers)
 | 
			
		||||
    _set_shell_parser(subparsers)
 | 
			
		||||
    _set_user_add_parser(subparsers)
 | 
			
		||||
    _set_user_list_parser(subparsers)
 | 
			
		||||
    _set_user_remove_parser(subparsers)
 | 
			
		||||
    _set_version_parser(subparsers)
 | 
			
		||||
    _set_web_parser(subparsers)
 | 
			
		||||
 | 
			
		||||
    return parser
 | 
			
		||||
@ -225,7 +228,7 @@ def _set_package_add_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("-n", "--now", help="run update function after", action="store_true")
 | 
			
		||||
    parser.add_argument("-s", "--source", help="explicitly specify the package source for this command",
 | 
			
		||||
                        type=PackageSource, choices=PackageSource, default=PackageSource.Auto)
 | 
			
		||||
                        type=PackageSource, choices=enum_values(PackageSource), default=PackageSource.Auto)
 | 
			
		||||
    parser.add_argument("--without-dependencies", help="do not add dependencies", action="store_true")
 | 
			
		||||
    parser.set_defaults(handler=handlers.Add)
 | 
			
		||||
    return parser
 | 
			
		||||
@ -267,7 +270,7 @@ def _set_package_status_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("-i", "--info", help="show additional package information", action="store_true")
 | 
			
		||||
    parser.add_argument("-s", "--status", help="filter packages by status",
 | 
			
		||||
                        type=BuildStatusEnum, choices=BuildStatusEnum)
 | 
			
		||||
                        type=BuildStatusEnum, choices=enum_values(BuildStatusEnum))
 | 
			
		||||
    parser.set_defaults(handler=handlers.Status, lock=None, no_report=True, quiet=True, unsafe=True)
 | 
			
		||||
    return parser
 | 
			
		||||
 | 
			
		||||
@ -309,7 +312,7 @@ def _set_package_status_update_parser(root: SubParserAction) -> argparse.Argumen
 | 
			
		||||
                                        "If no packages supplied, service status will be updated",
 | 
			
		||||
                        nargs="*")
 | 
			
		||||
    parser.add_argument("-s", "--status", help="new status",
 | 
			
		||||
                        type=BuildStatusEnum, choices=BuildStatusEnum, default=BuildStatusEnum.Success)
 | 
			
		||||
                        type=BuildStatusEnum, choices=enum_values(BuildStatusEnum), default=BuildStatusEnum.Success)
 | 
			
		||||
    parser.set_defaults(handler=handlers.StatusUpdate, action=Action.Update, lock=None, no_report=True, quiet=True,
 | 
			
		||||
                        unsafe=True)
 | 
			
		||||
    return parser
 | 
			
		||||
@ -556,7 +559,7 @@ def _set_repo_setup_parser(root: SubParserAction) -> argparse.ArgumentParser:
 | 
			
		||||
    parser.add_argument("--repository", help="repository name", required=True)
 | 
			
		||||
    parser.add_argument("--sign-key", help="sign key id")
 | 
			
		||||
    parser.add_argument("--sign-target", help="sign options", action="append",
 | 
			
		||||
                        type=SignSettings.from_option, choices=SignSettings)
 | 
			
		||||
                        type=SignSettings.from_option, choices=enum_values(SignSettings))
 | 
			
		||||
    parser.add_argument("--web-port", help="port of the web service", type=int)
 | 
			
		||||
    parser.set_defaults(handler=handlers.Setup, lock=None, no_report=True, quiet=True, unsafe=True)
 | 
			
		||||
    return parser
 | 
			
		||||
@ -594,7 +597,7 @@ def _set_repo_status_update_parser(root: SubParserAction) -> argparse.ArgumentPa
 | 
			
		||||
    parser = root.add_parser("repo-status-update", help="update repository status",
 | 
			
		||||
                             description="update repository status on the status page", formatter_class=_formatter)
 | 
			
		||||
    parser.add_argument("-s", "--status", help="new status",
 | 
			
		||||
                        type=BuildStatusEnum, choices=BuildStatusEnum, default=BuildStatusEnum.Success)
 | 
			
		||||
                        type=BuildStatusEnum, choices=enum_values(BuildStatusEnum), default=BuildStatusEnum.Success)
 | 
			
		||||
    parser.set_defaults(handler=handlers.StatusUpdate, action=Action.Update, lock=None, no_report=True, package=[],
 | 
			
		||||
                        quiet=True, unsafe=True)
 | 
			
		||||
    return parser
 | 
			
		||||
@ -661,6 +664,24 @@ def _set_repo_update_parser(root: SubParserAction) -> argparse.ArgumentParser:
 | 
			
		||||
    return parser
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _set_shell_parser(root: SubParserAction) -> argparse.ArgumentParser:
 | 
			
		||||
    """
 | 
			
		||||
    add parser for shell subcommand
 | 
			
		||||
 | 
			
		||||
    Args:
 | 
			
		||||
        root(SubParserAction): subparsers for the commands
 | 
			
		||||
 | 
			
		||||
    Returns:
 | 
			
		||||
        argparse.ArgumentParser: created argument parser
 | 
			
		||||
    """
 | 
			
		||||
    parser = root.add_parser("shell", help="envoke python shell",
 | 
			
		||||
                             description="drop into python shell while having created application",
 | 
			
		||||
                             formatter_class=_formatter)
 | 
			
		||||
    parser.add_argument("-v", "--verbose", help=argparse.SUPPRESS, action="store_true")
 | 
			
		||||
    parser.set_defaults(handler=handlers.Shell, lock=None, no_report=True)
 | 
			
		||||
    return parser
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _set_user_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
 | 
			
		||||
    """
 | 
			
		||||
    add parser for create user subcommand
 | 
			
		||||
@ -680,7 +701,7 @@ def _set_user_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
 | 
			
		||||
    parser.add_argument("-p", "--password", help="user password. Blank password will be treated as empty password, "
 | 
			
		||||
                                                 "which is in particular must be used for OAuth2 authorization type.")
 | 
			
		||||
    parser.add_argument("-r", "--role", help="user access level",
 | 
			
		||||
                        type=UserAccess, choices=UserAccess, default=UserAccess.Read)
 | 
			
		||||
                        type=UserAccess, choices=enum_values(UserAccess), default=UserAccess.Read)
 | 
			
		||||
    parser.add_argument("-s", "--secure", help="set file permissions to user-only", action="store_true")
 | 
			
		||||
    parser.set_defaults(handler=handlers.Users, action=Action.Update, architecture=[""], lock=None, no_report=True,
 | 
			
		||||
                        quiet=True, unsafe=True)
 | 
			
		||||
@ -702,7 +723,7 @@ def _set_user_list_parser(root: SubParserAction) -> argparse.ArgumentParser:
 | 
			
		||||
                             formatter_class=_formatter)
 | 
			
		||||
    parser.add_argument("username", help="filter users by username", nargs="?")
 | 
			
		||||
    parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
 | 
			
		||||
    parser.add_argument("-r", "--role", help="filter users by role", type=UserAccess, choices=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, no_report=True,  # nosec
 | 
			
		||||
                        password="", quiet=True, unsafe=True)
 | 
			
		||||
    return parser
 | 
			
		||||
@ -728,6 +749,23 @@ def _set_user_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
 | 
			
		||||
    return parser
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _set_version_parser(root: SubParserAction) -> argparse.ArgumentParser:
 | 
			
		||||
    """
 | 
			
		||||
    add parser for version subcommand
 | 
			
		||||
 | 
			
		||||
    Args:
 | 
			
		||||
        root(SubParserAction): subparsers for the commands
 | 
			
		||||
 | 
			
		||||
    Returns:
 | 
			
		||||
        argparse.ArgumentParser: created argument parser
 | 
			
		||||
    """
 | 
			
		||||
    parser = root.add_parser("version", help="application version",
 | 
			
		||||
                             description="print application and its dependencies versions", formatter_class=_formatter)
 | 
			
		||||
    parser.set_defaults(handler=handlers.Versions, architecture=[""], lock=None, no_report=True, quiet=True,
 | 
			
		||||
                        unsafe=True)
 | 
			
		||||
    return parser
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _set_web_parser(root: SubParserAction) -> argparse.ArgumentParser:
 | 
			
		||||
    """
 | 
			
		||||
    add parser for web subcommand
 | 
			
		||||
 | 
			
		||||
@ -32,6 +32,7 @@ from ahriman.application.handlers.remove_unknown import RemoveUnknown
 | 
			
		||||
from ahriman.application.handlers.restore import Restore
 | 
			
		||||
from ahriman.application.handlers.search import Search
 | 
			
		||||
from ahriman.application.handlers.setup import Setup
 | 
			
		||||
from ahriman.application.handlers.shell import Shell
 | 
			
		||||
from ahriman.application.handlers.sign import Sign
 | 
			
		||||
from ahriman.application.handlers.status import Status
 | 
			
		||||
from ahriman.application.handlers.status_update import StatusUpdate
 | 
			
		||||
@ -39,4 +40,5 @@ from ahriman.application.handlers.triggers import Triggers
 | 
			
		||||
from ahriman.application.handlers.unsafe_commands import UnsafeCommands
 | 
			
		||||
from ahriman.application.handlers.update import Update
 | 
			
		||||
from ahriman.application.handlers.users import Users
 | 
			
		||||
from ahriman.application.handlers.versions import Versions
 | 
			
		||||
from ahriman.application.handlers.web import Web
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										59
									
								
								src/ahriman/application/handlers/shell.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								src/ahriman/application/handlers/shell.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,59 @@
 | 
			
		||||
#
 | 
			
		||||
# Copyright (c) 2021-2022 ahriman team.
 | 
			
		||||
#
 | 
			
		||||
# This file is part of ahriman
 | 
			
		||||
# (see https://github.com/arcan1s/ahriman).
 | 
			
		||||
#
 | 
			
		||||
# This program is free software: you can redistribute it and/or modify
 | 
			
		||||
# it under the terms of the GNU General Public License as published by
 | 
			
		||||
# the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
# (at your option) any later version.
 | 
			
		||||
#
 | 
			
		||||
# This program is distributed in the hope that it will be useful,
 | 
			
		||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
# GNU General Public License for more details.
 | 
			
		||||
#
 | 
			
		||||
# You should have received a copy of the GNU General Public License
 | 
			
		||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
#
 | 
			
		||||
import argparse
 | 
			
		||||
import code
 | 
			
		||||
import sys
 | 
			
		||||
 | 
			
		||||
from pathlib import Path
 | 
			
		||||
from typing import Type
 | 
			
		||||
 | 
			
		||||
from ahriman.application.application import Application
 | 
			
		||||
from ahriman.application.handlers import Handler
 | 
			
		||||
from ahriman.core.configuration import Configuration
 | 
			
		||||
from ahriman.core.formatters import StringPrinter
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Shell(Handler):
 | 
			
		||||
    """
 | 
			
		||||
    python shell handler
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    ALLOW_MULTI_ARCHITECTURE_RUN = False
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
 | 
			
		||||
            configuration: Configuration, no_report: bool, unsafe: bool) -> None:
 | 
			
		||||
        """
 | 
			
		||||
        callback for command line
 | 
			
		||||
 | 
			
		||||
        Args:
 | 
			
		||||
            args(argparse.Namespace): command line args
 | 
			
		||||
            architecture(str): repository architecture
 | 
			
		||||
            configuration(Configuration): configuration instance
 | 
			
		||||
            no_report(bool): force disable reporting
 | 
			
		||||
            unsafe(bool): if set no user check will be performed before path creation
 | 
			
		||||
        """
 | 
			
		||||
        # pylint: disable=possibly-unused-variable
 | 
			
		||||
        application = Application(architecture, configuration, no_report, unsafe)
 | 
			
		||||
        if args.verbose:
 | 
			
		||||
            # licensed by https://creativecommons.org/licenses/by-sa/3.0
 | 
			
		||||
            path = Path(sys.prefix) / "share" / "ahriman" / "templates" / "shell"
 | 
			
		||||
            StringPrinter(path.read_text(encoding="utf8")).print(verbose=False)
 | 
			
		||||
        code.interact(local=locals())
 | 
			
		||||
							
								
								
									
										87
									
								
								src/ahriman/application/handlers/versions.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								src/ahriman/application/handlers/versions.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,87 @@
 | 
			
		||||
#
 | 
			
		||||
# Copyright (c) 2021-2022 ahriman team.
 | 
			
		||||
#
 | 
			
		||||
# This file is part of ahriman
 | 
			
		||||
# (see https://github.com/arcan1s/ahriman).
 | 
			
		||||
#
 | 
			
		||||
# This program is free software: you can redistribute it and/or modify
 | 
			
		||||
# it under the terms of the GNU General Public License as published by
 | 
			
		||||
# the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
# (at your option) any later version.
 | 
			
		||||
#
 | 
			
		||||
# This program is distributed in the hope that it will be useful,
 | 
			
		||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
# GNU General Public License for more details.
 | 
			
		||||
#
 | 
			
		||||
# You should have received a copy of the GNU General Public License
 | 
			
		||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
#
 | 
			
		||||
import argparse
 | 
			
		||||
import pkg_resources
 | 
			
		||||
import sys
 | 
			
		||||
 | 
			
		||||
from typing import Dict, List, Tuple, Type
 | 
			
		||||
 | 
			
		||||
from ahriman import version
 | 
			
		||||
from ahriman.application.handlers import Handler
 | 
			
		||||
from ahriman.core.configuration import Configuration
 | 
			
		||||
from ahriman.core.formatters import VersionPrinter
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Versions(Handler):
 | 
			
		||||
    """
 | 
			
		||||
    version handler
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    ALLOW_AUTO_ARCHITECTURE_RUN = False  # it should be called only as "no-architecture"
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
 | 
			
		||||
            configuration: Configuration, no_report: bool, unsafe: bool) -> None:
 | 
			
		||||
        """
 | 
			
		||||
        callback for command line
 | 
			
		||||
 | 
			
		||||
        Args:
 | 
			
		||||
            args(argparse.Namespace): command line args
 | 
			
		||||
            architecture(str): repository architecture
 | 
			
		||||
            configuration(Configuration): configuration instance
 | 
			
		||||
            no_report(bool): force disable reporting
 | 
			
		||||
            unsafe(bool): if set no user check will be performed before path creation
 | 
			
		||||
        """
 | 
			
		||||
        VersionPrinter(f"Module version {version.__version__}",
 | 
			
		||||
                       {"Python": sys.version}).print(verbose=False, separator=" ")
 | 
			
		||||
        packages = Versions.package_dependencies("ahriman", ("pacman", "s3", "web"))
 | 
			
		||||
        VersionPrinter("Installed packages", packages).print(verbose=False, separator=" ")
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def package_dependencies(root: str, root_extras: Tuple[str, ...] = ()) -> Dict[str, str]:
 | 
			
		||||
        """
 | 
			
		||||
        extract list of ahriman package dependencies installed into system with their versions
 | 
			
		||||
 | 
			
		||||
        Args:
 | 
			
		||||
            root(str): root package name
 | 
			
		||||
            root_extras(Tuple[str, ...]): extras for the root package (Default value = ())
 | 
			
		||||
 | 
			
		||||
        Returns:
 | 
			
		||||
            Dict[str, str]: map of installed dependency to its version
 | 
			
		||||
        """
 | 
			
		||||
        resources: Dict[str, pkg_resources.Distribution] = pkg_resources.working_set.by_key  # type: ignore
 | 
			
		||||
 | 
			
		||||
        def dependencies_by_key(key: str, extras: Tuple[str, ...] = ()) -> List[str]:
 | 
			
		||||
            return [entry.key for entry in resources[key].requires(extras)]
 | 
			
		||||
 | 
			
		||||
        keys: List[str] = []
 | 
			
		||||
        portion = {key for key in dependencies_by_key(root, root_extras) if key in resources}
 | 
			
		||||
        while portion:
 | 
			
		||||
            keys.extend(portion)
 | 
			
		||||
            portion = {
 | 
			
		||||
                key
 | 
			
		||||
                for key in sum([dependencies_by_key(key) for key in portion], start=[])
 | 
			
		||||
                if key not in keys and key in resources
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
            resource.project_name: resource.version
 | 
			
		||||
            for resource in map(lambda key: resources[key], keys)
 | 
			
		||||
        }
 | 
			
		||||
@ -27,3 +27,4 @@ from ahriman.core.formatters.package_printer import PackagePrinter
 | 
			
		||||
from ahriman.core.formatters.status_printer import StatusPrinter
 | 
			
		||||
from ahriman.core.formatters.update_printer import UpdatePrinter
 | 
			
		||||
from ahriman.core.formatters.user_printer import UserPrinter
 | 
			
		||||
from ahriman.core.formatters.version_printer import VersionPrinter
 | 
			
		||||
 | 
			
		||||
@ -25,6 +25,9 @@ from ahriman.core.formatters import Printer
 | 
			
		||||
class StringPrinter(Printer):
 | 
			
		||||
    """
 | 
			
		||||
    print content of the random string
 | 
			
		||||
 | 
			
		||||
    Attributes:
 | 
			
		||||
        content(str): any content string
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def __init__(self, content: str) -> None:
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										55
									
								
								src/ahriman/core/formatters/version_printer.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								src/ahriman/core/formatters/version_printer.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,55 @@
 | 
			
		||||
#
 | 
			
		||||
# Copyright (c) 2021-2022 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 typing import Dict, List
 | 
			
		||||
 | 
			
		||||
from ahriman.core.formatters import StringPrinter
 | 
			
		||||
from ahriman.models.property import Property
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class VersionPrinter(StringPrinter):
 | 
			
		||||
    """
 | 
			
		||||
    print content of the python package versions
 | 
			
		||||
 | 
			
		||||
    Attributes:
 | 
			
		||||
        packages(Dict[str, str]): map of package name to its version
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def __init__(self, title: str, packages: Dict[str, str]) -> None:
 | 
			
		||||
        """
 | 
			
		||||
        default constructor
 | 
			
		||||
 | 
			
		||||
        Args:
 | 
			
		||||
            title(str): title of the message
 | 
			
		||||
            packages(Dict[str, str]): map of package name to its version
 | 
			
		||||
        """
 | 
			
		||||
        StringPrinter.__init__(self, title)
 | 
			
		||||
        self.packages = packages
 | 
			
		||||
 | 
			
		||||
    def properties(self) -> List[Property]:
 | 
			
		||||
        """
 | 
			
		||||
        convert content into printable data
 | 
			
		||||
 | 
			
		||||
        Returns:
 | 
			
		||||
            List[Property]: list of content properties
 | 
			
		||||
        """
 | 
			
		||||
        return [
 | 
			
		||||
            Property(package, version, is_required=True)
 | 
			
		||||
            for package, version in sorted(self.packages.items())
 | 
			
		||||
        ]
 | 
			
		||||
@ -18,7 +18,10 @@
 | 
			
		||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
#
 | 
			
		||||
import datetime
 | 
			
		||||
import io
 | 
			
		||||
import os
 | 
			
		||||
from enum import Enum
 | 
			
		||||
 | 
			
		||||
import requests
 | 
			
		||||
import shutil
 | 
			
		||||
import subprocess
 | 
			
		||||
@ -27,14 +30,14 @@ import tempfile
 | 
			
		||||
from contextlib import contextmanager
 | 
			
		||||
from logging import Logger
 | 
			
		||||
from pathlib import Path
 | 
			
		||||
from typing import Any, Dict, Generator, Iterable, List, Optional, Union
 | 
			
		||||
from typing import Any, Dict, Generator, IO, Iterable, List, Optional, Type, Union
 | 
			
		||||
 | 
			
		||||
from ahriman.core.exceptions import InvalidOption, UnsafeRun
 | 
			
		||||
from ahriman.models.repository_paths import RepositoryPaths
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
__all__ = ["check_output", "check_user", "exception_response_text", "filter_json", "full_version", "package_like",
 | 
			
		||||
           "pretty_datetime", "pretty_size", "tmpdir", "walk"]
 | 
			
		||||
__all__ = ["check_output", "check_user", "exception_response_text", "filter_json", "full_version", "enum_values",
 | 
			
		||||
           "package_like", "pretty_datetime", "pretty_size", "tmpdir", "walk"]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def check_output(*args: str, exception: Optional[Exception], cwd: Optional[Path] = None,
 | 
			
		||||
@ -73,6 +76,11 @@ def check_output(*args: str, exception: Optional[Exception], cwd: Optional[Path]
 | 
			
		||||
 | 
			
		||||
            >>> check_output("false", exception=RuntimeError("An exception occurred"))
 | 
			
		||||
    """
 | 
			
		||||
    # hack for Optional[IO[str]] handle
 | 
			
		||||
    def get_io(proc: subprocess.Popen[str], channel_name: str) -> IO[str]:
 | 
			
		||||
        channel: Optional[IO[str]] = getattr(proc, channel_name, None)
 | 
			
		||||
        return channel if channel is not None else io.StringIO()
 | 
			
		||||
 | 
			
		||||
    def log(single: str) -> None:
 | 
			
		||||
        if logger is not None:
 | 
			
		||||
            logger.debug(single)
 | 
			
		||||
@ -80,14 +88,15 @@ def check_output(*args: str, exception: Optional[Exception], cwd: Optional[Path]
 | 
			
		||||
    # FIXME additional workaround for linter and type check which do not know that user arg is supported
 | 
			
		||||
    # pylint: disable=unexpected-keyword-arg
 | 
			
		||||
    with subprocess.Popen(args, cwd=cwd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
 | 
			
		||||
                          user=user, text=True, encoding="utf8", bufsize=1) as process:  # type: ignore
 | 
			
		||||
                          user=user, text=True, encoding="utf8", bufsize=1) as process:
 | 
			
		||||
        if input_data is not None:
 | 
			
		||||
            process.stdin.write(input_data)
 | 
			
		||||
            process.stdin.close()
 | 
			
		||||
            input_channel = get_io(process, "stdin")
 | 
			
		||||
            input_channel.write(input_data)
 | 
			
		||||
            input_channel.close()
 | 
			
		||||
 | 
			
		||||
        # read stdout and append to output result
 | 
			
		||||
        result: List[str] = []
 | 
			
		||||
        for line in iter(process.stdout.readline, ""):
 | 
			
		||||
        for line in iter(get_io(process, "stdout").readline, ""):
 | 
			
		||||
            line = line.strip()
 | 
			
		||||
            if not line:  # skip empty lines
 | 
			
		||||
                continue
 | 
			
		||||
@ -95,7 +104,7 @@ def check_output(*args: str, exception: Optional[Exception], cwd: Optional[Path]
 | 
			
		||||
            log(line)
 | 
			
		||||
 | 
			
		||||
        # read stderr and write info to logs
 | 
			
		||||
        for line in iter(process.stderr.readline, ""):
 | 
			
		||||
        for line in iter(get_io(process, "stderr").readline, ""):
 | 
			
		||||
            log(line.strip())
 | 
			
		||||
 | 
			
		||||
        process.terminate()  # make sure that process is terminated
 | 
			
		||||
@ -134,6 +143,19 @@ def check_user(paths: RepositoryPaths, unsafe: bool) -> None:
 | 
			
		||||
        raise UnsafeRun(current_uid, root_uid)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def enum_values(enum: Type[Enum]) -> List[str]:
 | 
			
		||||
    """
 | 
			
		||||
    generate list of enumeration values from the source
 | 
			
		||||
 | 
			
		||||
    Args:
 | 
			
		||||
        enum(Type[Enum]): source enumeration class
 | 
			
		||||
 | 
			
		||||
    Returns:
 | 
			
		||||
        List[str]: available enumeration values as string
 | 
			
		||||
    """
 | 
			
		||||
    return [key.value for key in enum]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def exception_response_text(exception: requests.exceptions.HTTPError) -> str:
 | 
			
		||||
    """
 | 
			
		||||
    safe response exception text generation
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										48
									
								
								tests/ahriman/application/handlers/test_handler_shell.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								tests/ahriman/application/handlers/test_handler_shell.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,48 @@
 | 
			
		||||
import argparse
 | 
			
		||||
import pytest
 | 
			
		||||
 | 
			
		||||
from pytest_mock import MockerFixture
 | 
			
		||||
 | 
			
		||||
from ahriman.application.handlers import Shell
 | 
			
		||||
from ahriman.core.configuration import Configuration
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
 | 
			
		||||
    """
 | 
			
		||||
    default arguments for these test cases
 | 
			
		||||
 | 
			
		||||
    Args:
 | 
			
		||||
        args(argparse.Namespace): command line arguments fixture
 | 
			
		||||
 | 
			
		||||
    Returns:
 | 
			
		||||
        argparse.Namespace: generated arguments for these test cases
 | 
			
		||||
    """
 | 
			
		||||
    args.verbose = False
 | 
			
		||||
    return args
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_run(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
 | 
			
		||||
    """
 | 
			
		||||
    must run command
 | 
			
		||||
    """
 | 
			
		||||
    args = _default_args(args)
 | 
			
		||||
    mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
 | 
			
		||||
    application_mock = mocker.patch("code.interact")
 | 
			
		||||
 | 
			
		||||
    Shell.run(args, "x86_64", configuration, True, False)
 | 
			
		||||
    application_mock.assert_called_once_with(local=pytest.helpers.anyvar(int))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_run_verbose(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
 | 
			
		||||
    """
 | 
			
		||||
    must run command with verbose option
 | 
			
		||||
    """
 | 
			
		||||
    args = _default_args(args)
 | 
			
		||||
    args.verbose = True
 | 
			
		||||
    mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
 | 
			
		||||
    print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
 | 
			
		||||
    application_mock = mocker.patch("code.interact")
 | 
			
		||||
 | 
			
		||||
    Shell.run(args, "x86_64", configuration, True, False)
 | 
			
		||||
    application_mock.assert_called_once_with(local=pytest.helpers.anyvar(int))
 | 
			
		||||
    print_mock.assert_called_once_with(verbose=False)
 | 
			
		||||
							
								
								
									
										38
									
								
								tests/ahriman/application/handlers/test_handler_versions.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								tests/ahriman/application/handlers/test_handler_versions.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,38 @@
 | 
			
		||||
import argparse
 | 
			
		||||
 | 
			
		||||
from pytest_mock import MockerFixture
 | 
			
		||||
from unittest import mock
 | 
			
		||||
 | 
			
		||||
from ahriman.application.handlers import Versions
 | 
			
		||||
from ahriman.core.configuration import Configuration
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_run(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
 | 
			
		||||
    """
 | 
			
		||||
    must run command
 | 
			
		||||
    """
 | 
			
		||||
    application_mock = mocker.patch("ahriman.application.handlers.Versions.package_dependencies")
 | 
			
		||||
    print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
 | 
			
		||||
 | 
			
		||||
    Versions.run(args, "x86_64", configuration, True, False)
 | 
			
		||||
    application_mock.assert_called_once_with("ahriman", ("pacman", "s3", "web"))
 | 
			
		||||
    print_mock.assert_has_calls([mock.call(verbose=False, separator=" "), mock.call(verbose=False, separator=" ")])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_package_dependencies() -> None:
 | 
			
		||||
    """
 | 
			
		||||
    must extract package dependencies
 | 
			
		||||
    """
 | 
			
		||||
    packages = Versions.package_dependencies("srcinfo")
 | 
			
		||||
    assert packages
 | 
			
		||||
    assert packages.get("parse") is not None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_package_dependencies_missing() -> None:
 | 
			
		||||
    """
 | 
			
		||||
    must extract package dependencies even if some of them are missing
 | 
			
		||||
    """
 | 
			
		||||
    packages = Versions.package_dependencies("ahriman", ("docs", "pacman", "s3", "web"))
 | 
			
		||||
    assert packages
 | 
			
		||||
    assert packages.get("pyalpm") is not None
 | 
			
		||||
    assert packages.get("Sphinx") is None
 | 
			
		||||
@ -492,6 +492,15 @@ def test_subparsers_repo_update_architecture(parser: argparse.ArgumentParser) ->
 | 
			
		||||
    assert args.architecture == ["x86_64"]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_subparsers_shell(parser: argparse.ArgumentParser) -> None:
 | 
			
		||||
    """
 | 
			
		||||
    shell command must imply lock and no-report
 | 
			
		||||
    """
 | 
			
		||||
    args = parser.parse_args(["shell"])
 | 
			
		||||
    assert args.lock is None
 | 
			
		||||
    assert args.no_report
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_subparsers_user_add(parser: argparse.ArgumentParser) -> None:
 | 
			
		||||
    """
 | 
			
		||||
    user-add command must imply action, architecture, lock, no-report, quiet and unsafe
 | 
			
		||||
@ -575,6 +584,26 @@ def test_subparsers_user_remove_architecture(parser: argparse.ArgumentParser) ->
 | 
			
		||||
    assert args.architecture == [""]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_subparsers_version(parser: argparse.ArgumentParser) -> None:
 | 
			
		||||
    """
 | 
			
		||||
    version command must imply architecture, lock, no-report, quiet and unsafe
 | 
			
		||||
    """
 | 
			
		||||
    args = parser.parse_args(["version"])
 | 
			
		||||
    assert args.architecture == [""]
 | 
			
		||||
    assert args.lock is None
 | 
			
		||||
    assert args.no_report
 | 
			
		||||
    assert args.quiet
 | 
			
		||||
    assert args.unsafe
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_subparsers_version_architecture(parser: argparse.ArgumentParser) -> None:
 | 
			
		||||
    """
 | 
			
		||||
    version command must correctly parse architecture list
 | 
			
		||||
    """
 | 
			
		||||
    args = parser.parse_args(["-a", "x86_64", "version"])
 | 
			
		||||
    assert args.architecture == [""]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_subparsers_web(parser: argparse.ArgumentParser) -> None:
 | 
			
		||||
    """
 | 
			
		||||
    web command must imply lock, no_report and parser
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
import pytest
 | 
			
		||||
 | 
			
		||||
from ahriman.core.formatters import AurPrinter, ConfigurationPrinter, PackagePrinter, StatusPrinter, StringPrinter, UpdatePrinter, UserPrinter
 | 
			
		||||
from ahriman.core.formatters import AurPrinter, ConfigurationPrinter, PackagePrinter, StatusPrinter, StringPrinter, \
 | 
			
		||||
    UpdatePrinter, UserPrinter, VersionPrinter
 | 
			
		||||
from ahriman.models.aur_package import AURPackage
 | 
			
		||||
from ahriman.models.build_status import BuildStatus
 | 
			
		||||
from ahriman.models.package import Package
 | 
			
		||||
@ -94,3 +95,17 @@ def user_printer(user: User) -> UserPrinter:
 | 
			
		||||
        UserPrinter: user printer test instance
 | 
			
		||||
    """
 | 
			
		||||
    return UserPrinter(user)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def version_printer(package_ahriman: Package) -> VersionPrinter:
 | 
			
		||||
    """
 | 
			
		||||
    fixture for version printer
 | 
			
		||||
 | 
			
		||||
    Args:
 | 
			
		||||
        package_ahriman(Package): package fixture
 | 
			
		||||
 | 
			
		||||
    Returns:
 | 
			
		||||
        VersionPrinter: version printer test instance
 | 
			
		||||
    """
 | 
			
		||||
    return VersionPrinter("package", {package_ahriman.base: package_ahriman.version})
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										15
									
								
								tests/ahriman/core/formatters/test_version_printer.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								tests/ahriman/core/formatters/test_version_printer.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
from ahriman.core.formatters import VersionPrinter
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_properties(version_printer: VersionPrinter) -> None:
 | 
			
		||||
    """
 | 
			
		||||
    must return empty properties list
 | 
			
		||||
    """
 | 
			
		||||
    assert version_printer.properties()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_title(version_printer: VersionPrinter) -> None:
 | 
			
		||||
    """
 | 
			
		||||
    must return non empty title
 | 
			
		||||
    """
 | 
			
		||||
    assert version_printer.title() is not None
 | 
			
		||||
@ -10,8 +10,9 @@ from unittest.mock import MagicMock
 | 
			
		||||
 | 
			
		||||
from ahriman.core.exceptions import BuildFailed, InvalidOption, UnsafeRun
 | 
			
		||||
from ahriman.core.util import check_output, check_user, exception_response_text, filter_json, full_version, \
 | 
			
		||||
    package_like, pretty_datetime, pretty_size, tmpdir, walk
 | 
			
		||||
    enum_values, package_like, pretty_datetime, pretty_size, tmpdir, walk
 | 
			
		||||
from ahriman.models.package import Package
 | 
			
		||||
from ahriman.models.package_source import PackageSource
 | 
			
		||||
from ahriman.models.repository_paths import RepositoryPaths
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -177,6 +178,15 @@ def test_filter_json_empty_value(package_ahriman: Package) -> None:
 | 
			
		||||
    assert "base" not in filter_json(probe, probe.keys())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_enum_values() -> None:
 | 
			
		||||
    """
 | 
			
		||||
    must correctly generate choices from enumeration classes
 | 
			
		||||
    """
 | 
			
		||||
    values = enum_values(PackageSource)
 | 
			
		||||
    for value in values:
 | 
			
		||||
        assert PackageSource(value).value == value
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_full_version() -> None:
 | 
			
		||||
    """
 | 
			
		||||
    must construct full version
 | 
			
		||||
@ -331,6 +341,7 @@ def test_walk(resource_path_root: Path) -> None:
 | 
			
		||||
        resource_path_root / "web" / "templates" / "build-status.jinja2",
 | 
			
		||||
        resource_path_root / "web" / "templates" / "email-index.jinja2",
 | 
			
		||||
        resource_path_root / "web" / "templates" / "repo-index.jinja2",
 | 
			
		||||
        resource_path_root / "web" / "templates" / "shell",
 | 
			
		||||
        resource_path_root / "web" / "templates" / "telegram-index.jinja2",
 | 
			
		||||
    ])
 | 
			
		||||
    local_files = list(sorted(walk(resource_path_root)))
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user