Compare commits

...

49 Commits

Author SHA1 Message Date
8d0d597473 Release 2.18.2 2025-06-16 19:03:05 +03:00
995b396360 bug: fix invalid logs rotation 2025-06-16 16:36:34 +03:00
7f813cf0c3 Release 2.18.1 2025-06-16 15:33:24 +03:00
d4eb55ef95 bug: correctly close sqlite3 connection
After the last updates, tests produce warnings that the connection to
database is leaked, which appears to be correct. This commit changes
behaviour to closing connection explicitly via contextlib
2025-06-16 15:24:57 +03:00
09350e88ab style: fix few typos 2025-06-14 23:34:53 +03:00
2feaa14f46 Release 2.18.0 2025-06-13 16:37:58 +03:00
9653fc4f4a type: support new configparser signatures 2025-05-31 02:16:07 +03:00
bcd46c66e8 test: use new-style fixtures instead of event_loop for asyncio 2025-05-12 15:57:05 +03:00
6ea56faede build: fix tox environment creation with the latest updates 2025-05-09 15:00:40 +03:00
9e346530f2 refactor: use backslashreplace error handling instead of guessing encoding 2025-05-08 14:03:47 +03:00
d283dccc1e type: update for new cors release 2025-03-17 13:56:59 +02:00
8a4e900ab9 docs: update docs
This commit includes following changes
* add newly added option to configuration referenec
* remove few legacy options from configuration schemas used for
  validation, which might lead to errors during validation.
  Note, however, that settings will be still read by the service
* add link to aurcache
* hide service-setup command description under spoiler
2025-03-17 13:43:04 +02:00
fa6cf8ce36 website: use date instead of version for listing logs
website: make dropdown from logs versions to add some space
2025-03-13 15:45:31 +02:00
a706fbb751 bug: handle dependencies iteratively (fix #141)
It has been found that if there are missing dependencies than whole
process will break instead of just skipping packages. During package
addition it is fine-ish, but it will break updates run
2025-03-13 15:45:27 +02:00
9a23f5c79d refactor: streamline migrations 2025-03-09 23:22:24 +02:00
aaab9069bf docs: rebuild indices 2025-03-09 15:43:41 +02:00
f00b575641 type: use ClassVar decorator for class attributes 2025-03-09 15:43:27 +02:00
6f57ed550b feat: refine log system (#142)
* refine package logging

* add interface

* revert version selection

* replace tuple with model

* rename column in logs table, add coverters

* generate process identifier for child proocesses
2025-03-09 14:46:33 +02:00
08640d9108 feat: add dashboard (#139) 2025-02-24 00:10:15 +02:00
65324633b4 feat: add counters to repository stats overview 2025-02-24 00:10:15 +02:00
ed67898012 fix: parse non-utf pkgbuilds as well (#140)
it has been reported that duriing reading pkgbuilds with latin-1 charset
the execption will be raised. Well, it is one more point to rewrite
parser to use own impl instead of shlex and parse raw byte array instead
2025-02-24 00:10:15 +02:00
a1a8dd68e8 type: remove unused ignore directive 2025-02-24 00:10:15 +02:00
a9505386c2 fix: force dry run build on task initialization for VCS packages
Previously if package is VCS and version in PKGBUILD doesn't match to
AUR one, then makepkg will update pkgbuild ignoring all previous pkgrel
patches

With this change during task init dry ryn process is always run for vcs
packages
2025-02-24 00:10:15 +02:00
a07b20bf50 Release 2.17.1 2025-01-06 01:14:28 +02:00
ed70897c39 fix: suppress traceback in shell if no ipython installed
Old implementation was showing import error, new implementation instead
hides it behind separated call and if-else check
2025-01-06 01:07:13 +02:00
0423c3e67c Release 2.17.0 2024-12-29 18:07:23 +02:00
571f62327f build: remove unused line from dockerfile 2024-12-24 16:49:30 +02:00
286ff4bcef fix: update packages properties after rebuild
This case leads to issue when it is impossible to update list of
implicit dependencies correctly in case of multi-packages
2024-12-24 15:13:18 +02:00
0660c33de3 chore: copyright update 2024-12-23 16:03:26 +02:00
c8421e97ee fix: fix pkgbuild parsing in case if comment mark is followed by token
without whitespaces

In this case, the next line was ignored
2024-12-23 15:55:07 +02:00
bc2288afc1 fix: suppress codefactor warning 2024-12-23 01:52:23 +02:00
503c8b0355 feat: make apispec dependency optional (#138) 2024-12-22 20:33:31 +02:00
6738f9206d type: remove unused typeguard 2024-12-21 17:02:09 +02:00
f865e998b0 feat: add link to logo 2024-12-19 12:47:17 +02:00
4880ca4fee feat: use IPython shell if available 2024-12-18 15:41:36 +02:00
56114ecc1e Release 2.16.0 2024-12-01 21:05:56 +02:00
57ab3ffb8f build: fix tox release target 2024-12-01 21:04:47 +02:00
8b08bfe3b4 ci: create regress job 2024-12-01 17:45:20 +02:00
e34356989d fix: invalid call in package-status-update subcommand 2024-12-01 17:37:12 +02:00
7c7804a9f4 build: allow to execute command from container from entrypoint 2024-11-29 16:17:45 +02:00
c4a56f1454 ci: add daily job 2024-11-26 11:55:08 +02:00
1caed156ad docs: add description about privileged and non--privileged container 2024-11-24 23:52:49 +02:00
45a620c40b fix: process list patch values in http requests
This commit parses values from post request as well as always serializes
values for the web interface
2024-11-22 17:22:37 +02:00
3c1fdec0e9 fix: serialize patches inside double quotes if there are variables inside (#137)
Old behaviour leads to variable to be serialized always in single quotes
(if shlex decides to quote it). It doesn't allow to expand variables during execution,
so those values should be put inside double quotes instead. This commit
checks if there is sign char in the variable and quotes manually,
otherwise returning shlex call
2024-11-19 14:39:48 +02:00
f5d7085325 fix: correctly serialize patches from database (#137)
If value is stored as array in database it is serialized as json, but
read as normal string, which lead to innability to use list patches

This fix also removes any postprocessing (unquoting) for functions
2024-11-19 02:42:28 +02:00
0cc35e70e3 build: docker image generation improvements
There are two major changes here. First of all, the image generation now
consist of two separated stages, the build itself and the production
image generation. Secondly, the packages inside image are now installed
as they were at the time of the root image generation (defined by stat
command)

Another side change is that container does not longer ship syncronized
(and out-of-dated) pacman databases; they have to be synced manually
2024-11-15 17:07:37 +02:00
f09082dff2 fix: fix parsing pkgbuild in case if comment starts with multiple sharps (#136) 2024-11-13 17:56:27 +02:00
8d53a59a6a feat: notify users about outdated password hashes used 2024-11-13 16:18:44 +02:00
20e7ba3b1d style: fix some typos and warnings 2024-11-11 18:07:13 +02:00
441 changed files with 7229 additions and 4114 deletions

View File

@ -8,6 +8,10 @@ on:
- '*' - '*'
- '!*rc*' - '!*rc*'
permissions:
contents: read
packages: write
jobs: jobs:
docker-image: docker-image:

139
.github/workflows/regress.yml vendored Normal file
View File

@ -0,0 +1,139 @@
name: Regress
on: workflow_dispatch
permissions:
contents: read
jobs:
run-regress-tests:
runs-on: ubuntu-latest
services:
ahriman:
image: arcan1s/ahriman:edge
env:
AHRIMAN_PORT: 8080
AHRIMAN_UNIX_SOCKET: /var/lib/ahriman/ahriman/ahriman-web.sock
options: --privileged --entrypoint entrypoint-web
ports:
- 8080
volumes:
- repo:/var/lib/ahriman
container:
image: arcan1s/ahriman:edge
env:
AHRIMAN_DEBUG: y
AHRIMAN_OUTPUT: console
AHRIMAN_PORT: 8080
AHRIMAN_UNIX_SOCKET: /var/lib/ahriman/ahriman/ahriman-web.sock
options: --privileged
volumes:
- repo:/var/lib/ahriman
steps:
- uses: actions/checkout@v3
- run: pacman -Sy
- name: Init repository
run: entrypoint help
- name: Print configuration
run: |
ahriman \
--log-handler "$AHRIMAN_OUTPUT" \
service-config
- name: Validate configuration
run: |
ahriman \
--log-handler "$AHRIMAN_OUTPUT" \
service-config-validate
- name: Create a user
run: |
sudo -u ahriman ahriman \
--log-handler "$AHRIMAN_OUTPUT" \
user-add \
--packager "github actions <actions@github.com>" \
--password ahriman \
--role full \
ahriman
- name: Fetch users
run: |
ahriman \
--log-handler "$AHRIMAN_OUTPUT" \
user-list \
--exit-code
- name: Add package
run: |
sudo -u ahriman ahriman \
--log-handler "$AHRIMAN_OUTPUT" \
package-add \
--exit-code \
--now \
--refresh \
ahriman
- name: Update status of the package
run: |
ahriman \
--log-handler "$AHRIMAN_OUTPUT" \
package-status-update \
--status failed \
ahriman
- name: Request status of the package
run: |
ahriman \
--log-handler "$AHRIMAN_OUTPUT" \
package-status \
--exit-code \
--info \
--status failed \
ahriman
- name: Update packages
run: |
sudo -u ahriman ahriman \
--log-handler "$AHRIMAN_OUTPUT" \
repo-update \
--exit-code \
|| true
- name: Add patch
run: |
echo '${pkgver%%.*}' | \
sudo -u ahriman ahriman \
--log-handler "$AHRIMAN_OUTPUT" \
patch-add \
ahriman \
pkgrel
- name: Retrieve patches
run: |
ahriman \
--log-handler "$AHRIMAN_OUTPUT" \
patch-list \
--exit-code \
ahriman
- name: Rebuild packages
run: |
sudo -u ahriman ahriman \
--log-handler "$AHRIMAN_OUTPUT" \
repo-rebuild \
--depends-on python \
--exit-code
- name: Remove package
run: |
sudo -u ahriman ahriman \
--log-handler "$AHRIMAN_OUTPUT" \
package-remove \
ahriman

View File

@ -5,6 +5,9 @@ on:
tags: tags:
- '*' - '*'
permissions:
contents: write
jobs: jobs:
make-release: make-release:

View File

@ -18,7 +18,7 @@ if [[ -z $MINIMAL_INSTALL ]]; then
# web server # web server
pacman -S --noconfirm python-aioauth-client python-aiohttp python-aiohttp-apispec-git python-aiohttp-cors python-aiohttp-jinja2 python-aiohttp-security python-aiohttp-session python-cryptography python-jinja pacman -S --noconfirm python-aioauth-client python-aiohttp python-aiohttp-apispec-git python-aiohttp-cors python-aiohttp-jinja2 python-aiohttp-security python-aiohttp-session python-cryptography python-jinja
# additional features # additional features
pacman -S --noconfirm gnupg python-boto3 python-cerberus python-matplotlib rsync pacman -S --noconfirm gnupg ipython python-boto3 python-cerberus python-matplotlib rsync
fi fi
# FIXME since 1.0.4 devtools requires dbus to be run, which doesn't work now in container # FIXME since 1.0.4 devtools requires dbus to be run, which doesn't work now in container
cp "docker/systemd-nspawn.sh" "/usr/local/bin/systemd-nspawn" cp "docker/systemd-nspawn.sh" "/usr/local/bin/systemd-nspawn"

View File

@ -8,6 +8,9 @@ on:
branches: branches:
- master - master
permissions:
contents: read
jobs: jobs:
run-setup-minimal: run-setup-minimal:
@ -15,9 +18,9 @@ jobs:
container: container:
image: archlinux:base image: archlinux:base
options: --privileged -w /build
volumes: volumes:
- ${{ github.workspace }}:/build - ${{ github.workspace }}:/build
options: --privileged -w /build
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3

View File

@ -7,6 +7,11 @@ on:
pull_request: pull_request:
branches: branches:
- master - master
schedule:
- cron: 1 0 * * *
permissions:
contents: read
jobs: jobs:
run-tests: run-tests:
@ -15,9 +20,9 @@ jobs:
container: container:
image: archlinux:base image: archlinux:base
options: -w /build
volumes: volumes:
- ${{ github.workspace }}:/build - ${{ github.workspace }}:/build
options: -w /build
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3

View File

@ -305,7 +305,7 @@ max-branches=12
max-locals=15 max-locals=15
# Maximum number of parents for a class (see R0901). # Maximum number of parents for a class (see R0901).
max-parents=7 max-parents=15
# Maximum number of public methods for a class (see R0904). # Maximum number of public methods for a class (see R0904).
max-public-methods=20 max-public-methods=20

View File

@ -9,13 +9,7 @@ build:
python: python:
install: install:
- method: pip - requirements: docs/requirements.txt
path: .
extra_requirements:
- docs
- s3
- validator
- web
formats: formats:
- pdf - pdf

View File

@ -80,7 +80,7 @@ Again, the most checks can be performed by `tox` command, though some additional
>>> clazz = Clazz() >>> clazz = Clazz()
""" """
CLAZZ_ATTRIBUTE = 42 CLAZZ_ATTRIBUTE: ClassVar[int] = 42
def __init__(self, *args: Any, **kwargs: Any) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None:
""" """
@ -96,6 +96,7 @@ Again, the most checks can be performed by `tox` command, though some additional
* Type annotations are the must, even for local functions. For the function argument `self` (for instance methods) and `cls` (for class methods) should not be annotated. * Type annotations are the must, even for local functions. For the function argument `self` (for instance methods) and `cls` (for class methods) should not be annotated.
* For collection types built-in classes must be used if possible (e.g. `dict` instead of `typing.Dict`, `tuple` instead of `typing.Tuple`). In case if built-in type is not available, but `collections.abc` provides interface, it must be used (e.g. `collections.abc.Awaitable` instead of `typing.Awaitable`, `collections.abc.Iterable` instead of `typing.Iterable`). For union classes, the bar operator (`|`) must be used (e.g. `float | int` instead of `typing.Union[float, int]`), which also includes `typing.Optional` (e.g. `str | None` instead of `Optional[str]`). * For collection types built-in classes must be used if possible (e.g. `dict` instead of `typing.Dict`, `tuple` instead of `typing.Tuple`). In case if built-in type is not available, but `collections.abc` provides interface, it must be used (e.g. `collections.abc.Awaitable` instead of `typing.Awaitable`, `collections.abc.Iterable` instead of `typing.Iterable`). For union classes, the bar operator (`|`) must be used (e.g. `float | int` instead of `typing.Union[float, int]`), which also includes `typing.Optional` (e.g. `str | None` instead of `Optional[str]`).
* `classmethod` should (almost) always return `Self`. In case of mypy warning (e.g. if there is a branch in which function doesn't return the instance of `cls`) consider using `staticmethod` instead. * `classmethod` should (almost) always return `Self`. In case of mypy warning (e.g. if there is a branch in which function doesn't return the instance of `cls`) consider using `staticmethod` instead.
* Class attributes must be decorated as `ClassVar[...]`.
* Recommended order of function definitions in class: * Recommended order of function definitions in class:
```python ```python
@ -175,11 +176,10 @@ Again, the most checks can be performed by `tox` command, though some additional
* Web API methods must be documented by using `aiohttp_apispec` library. The schema testing mostly should be implemented in related view class tests. Recommended example for documentation (excluding comments): * Web API methods must be documented by using `aiohttp_apispec` library. The schema testing mostly should be implemented in related view class tests. Recommended example for documentation (excluding comments):
```python ```python
import aiohttp_apispec
from marshmallow import Schema, fields from marshmallow import Schema, fields
from ahriman.web.schemas import AuthSchema, ErrorSchema, PackageNameSchema, PaginationSchema from ahriman.web.apispec.decorators import apidocs
from ahriman.web.schemas import PackageNameSchema, PaginationSchema
from ahriman.web.views.base import BaseView from ahriman.web.views.base import BaseView
@ -198,25 +198,17 @@ Again, the most checks can be performed by `tox` command, though some additional
POST_PERMISSION = ... POST_PERMISSION = ...
ROUTES = ... ROUTES = ...
@aiohttp_apispec.docs( @apidocs(
tags=["Tag"], tags=["Tag"],
summary="Do foo", summary="Do foo",
description="Extended description of the method which does foo", description="Extended description of the method which does foo",
responses={ error_400_enabled=True, # exception raised by this method
200: {"description": "Success response", "schema": ResponseSchema}, error_404_description="Repository is unknown",
204: {"description": "Success response"}, # example without json schema response schema=ResponseSchema, # leave empty if no responses here
400: {"description": "Bad data is supplied", "schema": ErrorSchema}, # exception raised by this method match_schema=PackageNameSchema,
401: {"description": "Authorization required", "schema": ErrorSchema}, # should be always presented query_schema=PaginationSchema,
403: {"description": "Access is forbidden", "schema": ErrorSchema}, # should be always presented body_schema=RequestSchema(many=True),
404: {"description": "Repository is unknown", "schema": ErrorSchema}, # include if BaseView.service() method is called
500: {"description": "Internal server error", "schema": ErrorSchema}, # should be always presented
},
security=[{"token": [POST_PERMISSION]}],
) )
@aiohttp_apispec.cookies_schema(AuthSchema) # should be always presented
@aiohttp_apispec.match_info_schema(PackageNameSchema)
@aiohttp_apispec.querystring_schema(PaginationSchema)
@aiohttp_apispec.json_schema(RequestSchema(many=True))
async def post(self) -> None: ... async def post(self) -> None: ...
``` ```

View File

@ -1,4 +1,77 @@
FROM archlinux:base # build image
FROM archlinux:base AS build
# install environment
## create build user
RUN useradd -m -d "/home/build" -s "/usr/bin/nologin" build
## extract container creation date and set mirror for this timestamp, set PKGEXT and refresh database next
RUN echo "Server = https://archive.archlinux.org/repos/$(stat -c "%y" "/var/lib/pacman" | cut -d " " -f 1 | sed "s,-,/,g")/\$repo/os/\$arch" > "/etc/pacman.d/mirrorlist" && \
pacman -Sy
## setup package cache
RUN runuser -u build -- mkdir "/tmp/pkg" && \
echo "PKGDEST=/tmp/pkg" >> "/etc/makepkg.conf" && \
echo "[options]" >> "/etc/pacman.conf" && \
echo "CacheDir = /tmp/pkg/" >> "/etc/pacman.conf"
## install anc configure sudo
RUN pacman -S --noconfirm --asdeps sudo && \
echo "build ALL=(ALL) NOPASSWD: ALL" > "/etc/sudoers.d/build"
## copy install script
COPY "docker/install-aur-package.sh" "/usr/local/bin/install-aur-package"
## install package dependencies
RUN pacman -S --noconfirm --asdeps \
devtools \
git \
pyalpm \
python-bcrypt \
python-inflection \
python-pyelftools \
python-requests \
&& \
pacman -S --noconfirm --asdeps \
base-devel \
python-build \
python-flit \
python-installer \
python-tox \
python-wheel \
&& \
pacman -S --noconfirm --asdeps \
git \
python-aiohttp \
python-boto3 \
python-cerberus \
python-cryptography \
python-jinja \
python-systemd \
rsync \
&& \
runuser -u build -- install-aur-package \
python-aioauth-client \
python-sphinx-typlog-theme \
python-webargs \
python-aiohttp-apispec-git \
python-aiohttp-cors \
python-aiohttp-jinja2 \
python-aiohttp-session \
python-aiohttp-security \
python-requests-unixsocket2
# install ahriman
## copy tree
COPY --chown=build . "/home/build/ahriman"
## create package archive and install it
RUN cd "/home/build/ahriman" && \
tox -e archive && \
cp ./dist/*.tar.gz "package/archlinux" && \
cd "package/archlinux" && \
runuser -u build -- makepkg --noconfirm --skipchecksums && \
cd / && rm -r "/home/build/ahriman"
# main image
FROM archlinux:base AS ahriman
# image configuration # image configuration
ENV AHRIMAN_ARCHITECTURE="x86_64" ENV AHRIMAN_ARCHITECTURE="x86_64"
@ -23,74 +96,45 @@ ENV AHRIMAN_VALIDATE_CONFIGURATION="yes"
## update pacman.conf with multilib ## update pacman.conf with multilib
RUN echo "[multilib]" >> "/etc/pacman.conf" && \ RUN echo "[multilib]" >> "/etc/pacman.conf" && \
echo "Include = /etc/pacman.d/mirrorlist" >> "/etc/pacman.conf" echo "Include = /etc/pacman.d/mirrorlist" >> "/etc/pacman.conf"
## refresh packages, install sudo and install packages for building ## copy built packages from build image and setup repository
RUN pacman -Syu --noconfirm sudo && \ COPY --from=build "/tmp/pkg" "/var/cache/pacman/pkg"
pacman -S --noconfirm --asdeps fakeroot python-tox RUN repo-add "/var/cache/pacman/pkg/core.db.tar.zst" "/var/cache/pacman/pkg/"*.pkg.tar.zst && \
## create build user repo-add "/var/cache/pacman/pkg/extra.db.tar.zst" && \
RUN useradd -m -d "/home/build" -s "/usr/bin/nologin" build && \ repo-add "/var/cache/pacman/pkg/multilib.db.tar.zst"
echo "build ALL=(ALL) NOPASSWD: ALL" > "/etc/sudoers.d/build" ## set local directory to use as repository and refresh database
COPY "docker/install-aur-package.sh" "/usr/local/bin/install-aur-package" RUN cp "/etc/pacman.d/mirrorlist" "/etc/pacman.d/mirrorlist.orig" && \
## install package dependencies echo "Server = file:///var/cache/pacman/pkg" > "/etc/pacman.d/mirrorlist" && \
cp "/etc/pacman.conf" "/etc/pacman.conf.orig" && \
sed -i "s/SigLevel *=.*/SigLevel = Optional/g" "/etc/pacman.conf" && \
pacman -Sy
## install package and its optional dependencies
RUN pacman -S --noconfirm ahriman
RUN pacman -S --noconfirm --asdeps \ RUN pacman -S --noconfirm --asdeps \
devtools \ python-aioauth-client \
git \ python-aiohttp-apispec-git \
pyalpm \ python-aiohttp-security \
python-bcrypt \ python-aiohttp-session \
python-inflection \
python-pyelftools \
python-requests \
&& \
pacman -S --noconfirm --asdeps \
base-devel \
python-build \
python-flit \
python-installer \
python-wheel \
&& \
pacman -S --noconfirm --asdeps \
git \
python-aiohttp \
python-boto3 \ python-boto3 \
python-cerberus \ python-cerberus \
python-cryptography \ python-cryptography \
python-jinja \
python-systemd \ python-systemd \
python-requests-unixsocket2 \
rsync \ rsync \
&& \ sudo
runuser -u build -- install-aur-package \
python-aioauth-client \
python-sphinx-typlog-theme \
python-webargs \
python-aiohttp-apispec-git \
python-aiohttp-cors \
python-aiohttp-jinja2 \
python-aiohttp-session \
python-aiohttp-security \
python-requests-unixsocket2
## FIXME since 1.0.4 devtools requires dbus to be run, which doesn't work now in container ## clear cache and restore system
COPY "docker/systemd-nspawn.sh" "/usr/local/bin/systemd-nspawn" RUN find "/var/cache/pacman/pkg" "/var/lib/pacman/sync" -type "f,l" -delete && \
cp "/etc/pacman.d/mirrorlist.orig" "/etc/pacman.d/mirrorlist" && \
# install ahriman cp "/etc/pacman.conf.orig" "/etc/pacman.conf"
## copy tree
COPY --chown=build . "/home/build/ahriman"
## create package archive and install it
RUN cd "/home/build/ahriman" && \
tox -e archive && \
cp ./dist/*.tar.gz "package/archlinux" && \
cd "package/archlinux" && \
runuser -u build -- makepkg --noconfirm --skipchecksums && \
runuser -u build -- makepkg --packagelist | grep -v -- -debug- | pacman -U --noconfirm --nodeps - && \
cd / && rm -r "/home/build/ahriman"
# cleanup unused
RUN find "/var/cache/pacman/pkg" -type f -delete
RUN pacman -Qdtq | pacman -Rscn --noconfirm -
VOLUME ["/var/lib/ahriman"] VOLUME ["/var/lib/ahriman"]
# minimal runtime ahriman setup # minimal runtime ahriman setup
## FIXME since 1.0.4 devtools requires dbus to be run, which doesn't work now in container
COPY "docker/systemd-nspawn.sh" "/usr/local/bin/systemd-nspawn"
## entrypoint setup
COPY "docker/entrypoint.sh" "/usr/local/bin/entrypoint" COPY "docker/entrypoint.sh" "/usr/local/bin/entrypoint"
COPY "docker/entrypoint-web.sh" "/usr/local/bin/entrypoint-web"
ENTRYPOINT ["entrypoint"] ENTRYPOINT ["entrypoint"]
# default command # default command
CMD ["repo-update", "--refresh"] CMD ["repo-update", "--refresh"]

5
docker/entrypoint-web.sh Executable file
View File

@ -0,0 +1,5 @@
#!/bin/bash
# Special workaround for running web service in github actions, must not be usually used in real environment,
# consider running web command explicitly instead
exec entrypoint web "$@"

View File

@ -57,6 +57,9 @@ ahriman "${AHRIMAN_DEFAULT_ARGS[@]}" service-setup "${AHRIMAN_SETUP_ARGS[@]}"
# create machine-id which is required by build tools # create machine-id which is required by build tools
systemd-machine-id-setup &> /dev/null systemd-machine-id-setup &> /dev/null
# special workaround to emulate /bin/bash entrypoint if first argument starts with /
[[ "$1" =~ ^/.* ]] && exec "$@"
# if AHRIMAN_FORCE_ROOT is set or command is unsafe we can run without sudo # if AHRIMAN_FORCE_ROOT is set or command is unsafe we can run without sudo
# 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

View File

@ -4,8 +4,12 @@ set -e
for PACKAGE in "$@"; do for PACKAGE in "$@"; do
BUILD_DIR="$(mktemp -d)" BUILD_DIR="$(mktemp -d)"
# clone the remote source
git clone https://aur.archlinux.org/"$PACKAGE".git "$BUILD_DIR" git clone https://aur.archlinux.org/"$PACKAGE".git "$BUILD_DIR"
cd "$BUILD_DIR" cd "$BUILD_DIR"
# checkout to the image date
git checkout "$(git rev-list -1 --before="$(stat -c "%y" "/var/lib/pacman" | cut -d " " -f 1)" master)"
# build and install the package
makepkg --nocheck --noconfirm --install --rmdeps --syncdeps makepkg --nocheck --noconfirm --install --rmdeps --syncdeps
cd / cd /
rm -r "$BUILD_DIR" rm -r "$BUILD_DIR"

File diff suppressed because it is too large Load Diff

View File

@ -44,7 +44,7 @@ The main functionality of the class is already described, but command is still n
arguments = set_parser arguments = set_parser
In addition, ``ahriman.application.handlers.handler.Handler.ALLOW_MULTI_ARCHITECTURE_RUN`` can be set to ``False`` in order to disable multiprocess run (e.g. in case if there are conflicting operations, like writting to stdout). In addition, ``ahriman.application.handlers.handler.Handler.ALLOW_MULTI_ARCHITECTURE_RUN`` can be set to ``False`` in order to disable multiprocess run (e.g. in case if there are conflicting operations, like writing to stdout).
Save the file above as ``/usr/lib/python3.12/site-packages/ahriman/application/handlers/help_web.py`` (replace ``python3.12`` with actual python version) and you are set. Save the file above as ``/usr/lib/python3.12/site-packages/ahriman/application/handlers/help_web.py`` (replace ``python3.12`` with actual python version) and you are set.

View File

@ -29,6 +29,14 @@ ahriman.application.help\_formatter module
:no-undoc-members: :no-undoc-members:
:show-inheritance: :show-inheritance:
ahriman.application.interactive\_shell module
---------------------------------------------
.. automodule:: ahriman.application.interactive_shell
:members:
:no-undoc-members:
:show-inheritance:
ahriman.application.lock module ahriman.application.lock module
------------------------------- -------------------------------

View File

@ -124,6 +124,14 @@ ahriman.core.database.migrations.m014\_auditlog module
:no-undoc-members: :no-undoc-members:
:show-inheritance: :show-inheritance:
ahriman.core.database.migrations.m015\_logs\_process\_id module
---------------------------------------------------------------
.. automodule:: ahriman.core.database.migrations.m015_logs_process_id
:members:
:no-undoc-members:
:show-inheritance:
Module contents Module contents
--------------- ---------------

View File

@ -92,6 +92,14 @@ ahriman.core.formatters.repository\_printer module
:no-undoc-members: :no-undoc-members:
:show-inheritance: :show-inheritance:
ahriman.core.formatters.repository\_stats\_printer module
---------------------------------------------------------
.. automodule:: ahriman.core.formatters.repository_stats_printer
:members:
:no-undoc-members:
:show-inheritance:
ahriman.core.formatters.status\_printer module ahriman.core.formatters.status\_printer module
---------------------------------------------- ----------------------------------------------

View File

@ -100,6 +100,14 @@ ahriman.models.log\_handler module
:no-undoc-members: :no-undoc-members:
:show-inheritance: :show-inheritance:
ahriman.models.log\_record module
---------------------------------
.. automodule:: ahriman.models.log_record
:members:
:no-undoc-members:
:show-inheritance:
ahriman.models.log\_record\_id module ahriman.models.log\_record\_id module
------------------------------------- -------------------------------------
@ -236,6 +244,14 @@ ahriman.models.repository\_paths module
:no-undoc-members: :no-undoc-members:
:show-inheritance: :show-inheritance:
ahriman.models.repository\_stats module
---------------------------------------
.. automodule:: ahriman.models.repository_stats
:members:
:no-undoc-members:
:show-inheritance:
ahriman.models.result module ahriman.models.result module
---------------------------- ----------------------------
@ -252,6 +268,14 @@ ahriman.models.scan\_paths module
:no-undoc-members: :no-undoc-members:
:show-inheritance: :show-inheritance:
ahriman.models.series\_statistics module
----------------------------------------
.. automodule:: ahriman.models.series_statistics
:members:
:no-undoc-members:
:show-inheritance:
ahriman.models.sign\_settings module ahriman.models.sign\_settings module
------------------------------------ ------------------------------------

View File

@ -0,0 +1,29 @@
ahriman.web.apispec package
===========================
Submodules
----------
ahriman.web.apispec.decorators module
-------------------------------------
.. automodule:: ahriman.web.apispec.decorators
:members:
:no-undoc-members:
:show-inheritance:
ahriman.web.apispec.info module
-------------------------------
.. automodule:: ahriman.web.apispec.info
:members:
:no-undoc-members:
:show-inheritance:
Module contents
---------------
.. automodule:: ahriman.web.apispec
:members:
:no-undoc-members:
:show-inheritance:

View File

@ -7,6 +7,7 @@ Subpackages
.. toctree:: .. toctree::
:maxdepth: 4 :maxdepth: 4
ahriman.web.apispec
ahriman.web.middlewares ahriman.web.middlewares
ahriman.web.schemas ahriman.web.schemas
ahriman.web.views ahriman.web.views
@ -14,14 +15,6 @@ Subpackages
Submodules Submodules
---------- ----------
ahriman.web.apispec module
--------------------------
.. automodule:: ahriman.web.apispec
:members:
:no-undoc-members:
:show-inheritance:
ahriman.web.cors module ahriman.web.cors module
----------------------- -----------------------

View File

@ -116,6 +116,14 @@ ahriman.web.schemas.login\_schema module
:no-undoc-members: :no-undoc-members:
:show-inheritance: :show-inheritance:
ahriman.web.schemas.logs\_rotate\_schema module
-----------------------------------------------
.. automodule:: ahriman.web.schemas.logs_rotate_schema
:members:
:no-undoc-members:
:show-inheritance:
ahriman.web.schemas.logs\_schema module ahriman.web.schemas.logs\_schema module
--------------------------------------- ---------------------------------------
@ -260,6 +268,14 @@ ahriman.web.schemas.repository\_id\_schema module
:no-undoc-members: :no-undoc-members:
:show-inheritance: :show-inheritance:
ahriman.web.schemas.repository\_stats\_schema module
----------------------------------------------------
.. automodule:: ahriman.web.schemas.repository_stats_schema
:members:
:no-undoc-members:
:show-inheritance:
ahriman.web.schemas.search\_schema module ahriman.web.schemas.search\_schema module
----------------------------------------- -----------------------------------------
@ -284,14 +300,6 @@ ahriman.web.schemas.update\_flags\_schema module
:no-undoc-members: :no-undoc-members:
:show-inheritance: :show-inheritance:
ahriman.web.schemas.versioned\_log\_schema module
-------------------------------------------------
.. automodule:: ahriman.web.schemas.versioned_log_schema
:members:
:no-undoc-members:
:show-inheritance:
ahriman.web.schemas.worker\_schema module ahriman.web.schemas.worker\_schema module
----------------------------------------- -----------------------------------------

View File

@ -12,6 +12,14 @@ ahriman.web.views.v1.service.add module
:no-undoc-members: :no-undoc-members:
:show-inheritance: :show-inheritance:
ahriman.web.views.v1.service.logs module
----------------------------------------
.. automodule:: ahriman.web.views.v1.service.logs
:members:
:no-undoc-members:
:show-inheritance:
ahriman.web.views.v1.service.pgp module ahriman.web.views.v1.service.pgp module
--------------------------------------- ---------------------------------------

View File

@ -394,7 +394,7 @@ All extracted fields are packed as ``ahriman.models.pkgbuild_patch.PkgbuildPatch
The PKGBUILD class also provides some additional functions on top of that: The PKGBUILD class also provides some additional functions on top of that:
* Ability to extract fields defined inside ``package*()`` functions, which are in particular used for the multipackages. * Ability to extract fields defined inside ``package*()`` functions, which are in particular used for the multi-packages.
* Shell substitution, which supports constructions ``$var`` (including ``${var}``), ``${var#(#)pattern}``, ``${var%(%)pattern}`` and ``${var/(/)pattern/replacement}`` (including ``#pattern`` and ``%pattern``). * Shell substitution, which supports constructions ``$var`` (including ``${var}``), ``${var#(#)pattern}``, ``${var%(%)pattern}`` and ``${var/(/)pattern/replacement}`` (including ``#pattern`` and ``%pattern``).
Additional features Additional features

View File

@ -15,9 +15,8 @@ import sys
from pathlib import Path from pathlib import Path
from ahriman import __version__
# support package imports
basedir = Path(__file__).resolve().parent.parent / "src" basedir = Path(__file__).resolve().parent.parent / "src"
sys.path.insert(0, str(basedir)) sys.path.insert(0, str(basedir))
@ -29,6 +28,7 @@ copyright = f"2021-{datetime.date.today().year}, ahriman team"
author = "ahriman team" author = "ahriman team"
# The full version, including alpha/beta/rc tags # The full version, including alpha/beta/rc tags
from ahriman import __version__
release = __version__ release = __version__
@ -91,7 +91,13 @@ autoclass_content = "both"
autodoc_member_order = "groupwise" autodoc_member_order = "groupwise"
autodoc_mock_imports = ["cryptography", "pyalpm"] autodoc_mock_imports = [
"aioauth_client",
"aiohttp_security",
"aiohttp_session",
"cryptography",
"pyalpm",
]
autodoc_default_options = { autodoc_default_options = {
"no-undoc-members": True, "no-undoc-members": True,

View File

@ -81,6 +81,7 @@ Base configuration settings.
* ``apply_migrations`` - perform database migrations on the application start, boolean, optional, default ``yes``. Useful if you are using git version. Note, however, that this option must be changed only if you know what to do and going to handle migrations manually. * ``apply_migrations`` - perform database migrations on the application start, boolean, optional, default ``yes``. Useful if you are using git version. Note, however, that this option must be changed only if you know what to do and going to handle migrations manually.
* ``database`` - path to the application SQLite database, string, required. * ``database`` - path to the application SQLite database, string, required.
* ``include`` - path to directory with configuration files overrides, string, optional. Files will be read in alphabetical order. * ``include`` - path to directory with configuration files overrides, string, optional. Files will be read in alphabetical order.
* ``keep_last_logs`` - amount of build logs to be kept for each package, integer, optional ,default ``0``. Logs will be cleared at the end of each process.
* ``logging`` - path to logging configuration, string, required. Check ``logging.ini`` for reference. * ``logging`` - path to logging configuration, string, required. Check ``logging.ini`` for reference.
``alpm:*`` groups ``alpm:*`` groups
@ -217,7 +218,7 @@ Mirrorlist generator plugin
``remote-pull`` group ``remote-pull`` group
--------------------- ---------------------
Remote git source synchronization settings. Unlike ``Upload`` triggers those triggers are used for PKGBUILD synchronization - fetch from remote repository PKGBUILDs before updating process. Remote git source synchronization settings. Unlike ``upload`` triggers those triggers are used for PKGBUILD synchronization - fetch from remote repository PKGBUILDs before updating process.
It supports authorization; to do so you'd need to prefix the URL with authorization part, e.g. ``https://key:token@github.com/arcan1s/ahriman.git``. It is highly recommended to use application tokens instead of your user authorization details. Alternatively, you can use any other option supported by git, e.g.: It supports authorization; to do so you'd need to prefix the URL with authorization part, e.g. ``https://key:token@github.com/arcan1s/ahriman.git``. It is highly recommended to use application tokens instead of your user authorization details. Alternatively, you can use any other option supported by git, e.g.:

View File

@ -16,7 +16,7 @@ The default action (in case if no arguments provided) is ``repo-update``. Basica
docker run --privileged -v /path/to/local/repo:/var/lib/ahriman arcan1s/ahriman:latest docker run --privileged -v /path/to/local/repo:/var/lib/ahriman arcan1s/ahriman:latest
``--privileged`` flag is required to make mount possible inside container. In order to make data available outside of container, you would need to mount local (parent) directory inside container by using ``-v /path/to/local/repo:/var/lib/ahriman`` argument, where ``/path/to/local/repo`` is a path to repository on local machine. In addition, you can pass own configuration overrides by using the same ``-v`` flag, e.g.: In order to make data available outside of container, you would need to mount local (parent) directory inside container by using ``-v /path/to/local/repo:/var/lib/ahriman`` argument, where ``/path/to/local/repo`` is a path to repository on local machine. In addition, you can pass own configuration overrides by using the same ``-v`` flag, e.g.:
.. code-block:: shell .. code-block:: shell
@ -30,6 +30,28 @@ The action can be specified during run, e.g.:
For more details please refer to the docker FAQ. For more details please refer to the docker FAQ.
Privileged and non-privileged container
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Examples here suggest using ``--privileged`` flag which is required for the devtools and is involved in two types of operations: tmpfs mount and cgroup manipulation. Whereas it is the easiest way to operate, it might be not really secure. The other way to make devtools working is to grant required capabilities, which can be achieved by using flags:
* ``--cap-add=SYS_ADMIN``, which grants permissions to operate with tmpfs for ``systemd-nspawn``.
* ``-v /sys/fs/cgroup:/sys/fs/cgroup`` which allows access to cgroup manipulation.
Thus, there are two possible ways to run the container:
.. code-block:: shell
docker run --privileged arcan1s/ahriman:latest
and
.. code-block:: shell
docker run --cap-add=SYS_ADMIN -v /sys/fs/cgroup:/sys/fs/cgroup arcan1s/ahriman:latest
but for the simplicity this FAQ will always use ``--privileged`` flag.
Environment variables Environment variables
^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^
@ -97,7 +119,7 @@ Otherwise, you would need to pass ``AHRIMAN_PORT`` and mount container network t
Simple server with authentication can be found in `examples <https://github.com/arcan1s/ahriman/tree/master/recipes/web>`__ too. Simple server with authentication can be found in `examples <https://github.com/arcan1s/ahriman/tree/master/recipes/web>`__ too.
Mutli-repository web service Multi-repository web service
"""""""""""""""""""""""""""" """"""""""""""""""""""""""""
Idea is pretty same as to just run web service. However, it is required to run setup commands for each repository, except for one which is specified by ``AHRIMAN_REPOSITORY`` and ``AHRIMAN_ARCHITECTURE`` variables. Idea is pretty same as to just run web service. However, it is required to run setup commands for each repository, except for one which is specified by ``AHRIMAN_REPOSITORY`` and ``AHRIMAN_ARCHITECTURE`` variables.

View File

@ -56,6 +56,13 @@ Though originally I've created ahriman by trying to improve the project, it stil
It is automation tools for ``repoctl`` mentioned above. Except for using shell it looks pretty cool and also offers some additional features like patches, remote synchronization (isn't it?) and reporting. It is automation tools for ``repoctl`` mentioned above. Except for using shell it looks pretty cool and also offers some additional features like patches, remote synchronization (isn't it?) and reporting.
`AURCache <https://github.com/Lukas-Heiligenbrunner/AURCache>`__
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
That's really cool project if you are looking for simple service to build AUR packages. It provides very informative dashboard and easy to configure and use. However, it doesn't provide direct way to control build process (e.g. it is neither trivial to build packages for architectures which are not supported by default nor to change build flags).
Also this application relies on docker setup (e.g. builders are only available as special docker containers). In addition, it uses ``paru`` to build packages instead of ``devtools``.
How to check service logs How to check service logs
^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -3,7 +3,7 @@ To 2.16.0
This release replaces ``passlib`` dependency with ``bcrypt``. This release replaces ``passlib`` dependency with ``bcrypt``.
The reason behind this change is that python developers have deprecated and scheduled for removal ``crypt`` module, which is used by ``passlib``. (By the way, they recommend to use ``passlib`` as a replacement.) Unfortunately, it appears that ``passlib`` is unmaintained (see `the issue <https://foss.heptapod.net/python-libs/passlib/-/issues/187>`__), so the only solution is to migrate to anoher library. The reason behind this change is that python developers have deprecated and scheduled for removal ``crypt`` module, which is used by ``passlib``. (By the way, they recommend to use ``passlib`` as a replacement.) Unfortunately, it appears that ``passlib`` is unmaintained (see `the issue <https://foss.heptapod.net/python-libs/passlib/-/issues/187>`__), so the only solution is to migrate to another library.
Because passwords are stored as hashes, it is near to impossible to shadow change passwords in database, the manual intervention is required if: Because passwords are stored as hashes, it is near to impossible to shadow change passwords in database, the manual intervention is required if:

128
docs/requirements.txt Normal file
View File

@ -0,0 +1,128 @@
# This file was autogenerated by uv via the following command:
# uv pip compile --group ../pyproject.toml:docs --extra s3 --extra validator --extra web --output-file ../docs/requirements.txt ../pyproject.toml
aiohappyeyeballs==2.6.1
# via aiohttp
aiohttp==3.11.18
# via
# ahriman (../pyproject.toml)
# aiohttp-cors
# aiohttp-jinja2
aiohttp-cors==0.8.1
# via ahriman (../pyproject.toml)
aiohttp-jinja2==1.6
# via ahriman (../pyproject.toml)
aiosignal==1.3.2
# via aiohttp
alabaster==1.0.0
# via sphinx
argparse-manpage==4.6
# via ahriman (../pyproject.toml:docs)
attrs==25.3.0
# via aiohttp
babel==2.17.0
# via sphinx
bcrypt==4.3.0
# via ahriman (../pyproject.toml)
boto3==1.38.11
# via ahriman (../pyproject.toml)
botocore==1.38.11
# via
# boto3
# s3transfer
cerberus==1.3.7
# via ahriman (../pyproject.toml)
certifi==2025.4.26
# via requests
charset-normalizer==3.4.2
# via requests
docutils==0.21.2
# via
# sphinx
# sphinx-argparse
# sphinx-rtd-theme
frozenlist==1.6.0
# via
# aiohttp
# aiosignal
idna==3.10
# via
# requests
# yarl
imagesize==1.4.1
# via sphinx
inflection==0.5.1
# via ahriman (../pyproject.toml)
jinja2==3.1.6
# via
# aiohttp-jinja2
# sphinx
jmespath==1.0.1
# via
# boto3
# botocore
markupsafe==3.0.2
# via jinja2
multidict==6.4.3
# via
# aiohttp
# yarl
packaging==25.0
# via sphinx
propcache==0.3.1
# via
# aiohttp
# yarl
pydeps==3.0.1
# via ahriman (../pyproject.toml:docs)
pyelftools==0.32
# via ahriman (../pyproject.toml)
pygments==2.19.1
# via sphinx
python-dateutil==2.9.0.post0
# via botocore
requests==2.32.3
# via
# ahriman (../pyproject.toml)
# sphinx
roman-numerals-py==3.1.0
# via sphinx
s3transfer==0.12.0
# via boto3
shtab==1.7.2
# via ahriman (../pyproject.toml:docs)
six==1.17.0
# via python-dateutil
snowballstemmer==3.0.0.1
# via sphinx
sphinx==8.2.3
# via
# ahriman (../pyproject.toml:docs)
# sphinx-argparse
# sphinx-rtd-theme
# sphinxcontrib-jquery
sphinx-argparse==0.5.2
# via ahriman (../pyproject.toml:docs)
sphinx-rtd-theme==3.0.2
# via ahriman (../pyproject.toml:docs)
sphinxcontrib-applehelp==2.0.0
# via sphinx
sphinxcontrib-devhelp==2.0.0
# via sphinx
sphinxcontrib-htmlhelp==2.1.0
# via sphinx
sphinxcontrib-jquery==4.1
# via sphinx-rtd-theme
sphinxcontrib-jsmath==1.0.1
# via sphinx
sphinxcontrib-qthelp==2.0.0
# via sphinx
sphinxcontrib-serializinghtml==2.0.0
# via sphinx
stdlib-list==0.11.1
# via pydeps
urllib3==2.4.0
# via
# botocore
# requests
yarl==1.20.0
# via aiohttp

View File

@ -12,19 +12,22 @@ Initial setup
sudo ahriman -a x86_64 -r aur service-setup ... sudo ahriman -a x86_64 -r aur service-setup ...
``service-setup`` literally does the following steps: .. admonition:: Details
:collapsible: closed
#. ``service-setup`` literally does the following steps:
Create ``/var/lib/ahriman/.makepkg.conf`` with ``makepkg.conf`` overrides if required (at least you might want to set ``PACKAGER``):
.. code-block:: shell #.
Create ``/var/lib/ahriman/.makepkg.conf`` with ``makepkg.conf`` overrides if required (at least you might want to set ``PACKAGER``):
echo 'PACKAGER="ahriman bot <ahriman@example.com>"' | sudo -u ahriman tee -a /var/lib/ahriman/.makepkg.conf .. code-block:: shell
#. echo 'PACKAGER="ahriman bot <ahriman@example.com>"' | sudo -u ahriman tee -a /var/lib/ahriman/.makepkg.conf
Configure build tools (it is required for correct dependency management system):
#. #.
Configure build tools (it is required for correct dependency management system):
#.
Create build command (you can choose any name for command, basically it should be ``{name}-{arch}-build``): Create build command (you can choose any name for command, basically it should be ``{name}-{arch}-build``):
.. code-block:: shell .. code-block:: shell
@ -67,7 +70,7 @@ Initial setup
echo 'ahriman ALL=(ALL) NOPASSWD:SETENV: 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.
#. #.
Start and enable ``ahriman@.timer`` via ``systemctl``: Start and enable ``ahriman@.timer`` via ``systemctl``:

View File

@ -2,7 +2,7 @@
pkgbase='ahriman' pkgbase='ahriman'
pkgname=('ahriman' 'ahriman-core' 'ahriman-triggers' 'ahriman-web') pkgname=('ahriman' 'ahriman-core' 'ahriman-triggers' 'ahriman-web')
pkgver=2.15.2 pkgver=2.18.2
pkgrel=1 pkgrel=1
pkgdesc="ArcH linux ReposItory MANager" pkgdesc="ArcH linux ReposItory MANager"
arch=('any') arch=('any')
@ -30,6 +30,7 @@ package_ahriman-core() {
pkgname='ahriman-core' pkgname='ahriman-core'
optdepends=('ahriman-triggers: additional extensions for the application' optdepends=('ahriman-triggers: additional extensions for the application'
'ahriman-web: web server' 'ahriman-web: web server'
'ipython: an enhanced shell interpreter'
'python-boto3: sync to s3' 'python-boto3: sync to s3'
'python-cerberus: configuration validator' 'python-cerberus: configuration validator'
'python-matplotlib: usage statistics chart' 'python-matplotlib: usage statistics chart'
@ -71,8 +72,9 @@ package_ahriman-triggers() {
package_ahriman-web() { package_ahriman-web() {
pkgname='ahriman-web' pkgname='ahriman-web'
pkgdesc="ArcH linux ReposItory MANager, web server" pkgdesc="ArcH linux ReposItory MANager, web server"
depends=("$pkgbase-core=$pkgver" 'python-aiohttp-apispec>=3.0.0' 'python-aiohttp-cors' 'python-aiohttp-jinja2') depends=("$pkgbase-core=$pkgver" 'python-aiohttp-cors' 'python-aiohttp-jinja2')
optdepends=('python-aioauth-client: OAuth2 authorization support' optdepends=('python-aioauth-client: OAuth2 authorization support'
'python-aiohttp-apispec>=3.0.0: autogenerated API documentation'
'python-aiohttp-security: authorization support' 'python-aiohttp-security: authorization support'
'python-aiohttp-session: authorization support' 'python-aiohttp-session: authorization support'
'python-cryptography: authorization support') 'python-cryptography: authorization support')

View File

@ -7,6 +7,8 @@ logging = ahriman.ini.d/logging.ini
;apply_migrations = yes ;apply_migrations = yes
; Path to the application SQLite database. ; Path to the application SQLite database.
database = ${repository:root}/ahriman.db database = ${repository:root}/ahriman.db
; Keep last build logs for each package
keep_last_logs = 5
[alpm] [alpm]
; Path to pacman system database cache. ; Path to pacman system database cache.

View File

@ -15,12 +15,12 @@
<div class="container"> <div class="container">
<nav class="navbar navbar-expand-lg"> <nav class="navbar navbar-expand-lg">
<div class="navbar-brand"><img src="/static/logo.svg" width="30" height="30" alt=""></div> <div class="navbar-brand"><a href="https://github.com/arcan1s/ahriman" title="logo"><img src="/static/logo.svg" width="30" height="30" alt=""></a></div>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#repositories-navbar-supported-content" aria-controls="repositories-navbar-supported-content" aria-expanded="false" aria-label="Toggle navigation"> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#repositories-navbar" aria-controls="repositories-navbar" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon"></span>
</button> </button>
<div id="repositories-navbar-supported-content" class="collapse navbar-collapse"> <div id="repositories-navbar" class="collapse navbar-collapse">
<ul id="repositories" class="nav nav-tabs"> <ul id="repositories" class="nav nav-tabs">
{% for repository in repositories %} {% for repository in repositories %}
<li class="nav-item"> <li class="nav-item">
@ -36,7 +36,9 @@
<div class="container"> <div class="container">
<div id="toolbar" class="dropdown"> <div id="toolbar" class="dropdown">
<a id="badge-status" tabindex="0" role="button" class="btn btn-outline-secondary" data-bs-toggle="popover" data-bs-trigger="focus" data-bs-content="no run data"><i class="bi bi-info-circle"></i></a> <button id="dashboard-button" type="button" class="btn btn-outline-secondary" data-bs-toggle="modal" data-bs-target="#dashboard-modal">
<i class="bi bi-info-circle"></i>
</button>
{% if not auth.enabled or auth.username is not none %} {% if not auth.enabled or auth.username is not none %}
<button type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false"> <button type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
@ -119,7 +121,9 @@
<li><a id="badge-version" class="nav-link" href="https://github.com/arcan1s/ahriman" title="sources"><i class="bi bi-github"></i> ahriman</a></li> <li><a id="badge-version" class="nav-link" href="https://github.com/arcan1s/ahriman" title="sources"><i class="bi bi-github"></i> ahriman</a></li>
<li><a class="nav-link" href="https://github.com/arcan1s/ahriman/releases" title="releases list">releases</a></li> <li><a class="nav-link" href="https://github.com/arcan1s/ahriman/releases" title="releases list">releases</a></li>
<li><a class="nav-link" href="https://github.com/arcan1s/ahriman/issues" title="issues tracker">report a bug</a></li> <li><a class="nav-link" href="https://github.com/arcan1s/ahriman/issues" title="issues tracker">report a bug</a></li>
<li><a class="nav-link" href="/api-docs" title="API documentation">api</a></li> {% if docs_enabled %}
<li><a class="nav-link" href="/api-docs" title="API documentation">api</a></li>
{% endif %}
</ul> </ul>
{% if index_url is not none %} {% if index_url is not none %}
@ -150,6 +154,7 @@
{% include "build-status/alerts.jinja2" %} {% include "build-status/alerts.jinja2" %}
{% include "build-status/dashboard.jinja2" %}
{% include "build-status/package-add-modal.jinja2" %} {% include "build-status/package-add-modal.jinja2" %}
{% include "build-status/package-rebuild-modal.jinja2" %} {% include "build-status/package-rebuild-modal.jinja2" %}
{% include "build-status/key-import-modal.jinja2" %} {% include "build-status/key-import-modal.jinja2" %}

View File

@ -0,0 +1,76 @@
<div id="dashboard-modal" tabindex="-1" role="dialog" class="modal fade">
<div class="modal-dialog modal-xl" role="document">
<div class="modal-content">
<div id="dashboard-modal-header" class="modal-header">
<h4 class="modal-title">System health</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="close"></button>
</div>
<div class="modal-body">
<div class="form-group row mt-2">
<div class="col-4 col-lg-2" style="text-align: right">Repository name</div>
<div id="dashboard-name" class="col-8 col-lg-3"></div>
<div class="col-4 col-lg-2" style="text-align: right">Repository architecture</div>
<div id="dashboard-architecture" class="col-8 col-lg-3"></div>
</div>
<div class="form-group row mt-2">
<div class="col-4 col-lg-2" style="text-align: right">Current status</div>
<div id="dashboard-status" class="col-8 col-lg-3"></div>
<div class="col-4 col-lg-2" style="text-align: right">Updated at</div>
<div id="dashboard-status-timestamp" class="col-8 col-lg-3"></div>
</div>
<div id="dashboard-canvas" class="form-group row mt-2">
<div class="col-8 col-lg-6">
<canvas id="dashboard-packages-count-chart"></canvas>
</div>
<div class="col-8 col-lg-6">
<canvas id="dashboard-packages-statuses-chart"></canvas>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-bs-dismiss="modal"><i class="bi bi-x"></i><span class="d-none d-sm-inline"> close</span></button>
</div>
</div>
</div>
</div>
<script>
const dashboardModal = document.getElementById("dashboard-modal");
const dashboardModalHeader = document.getElementById("dashboard-modal-header");
const dashboardName = document.getElementById("dashboard-name");
const dashboardArchitecture = document.getElementById("dashboard-architecture");
const dashboardStatus = document.getElementById("dashboard-status");
const dashboardStatusTimestamp = document.getElementById("dashboard-status-timestamp");
const dashboardCanvas = document.getElementById("dashboard-canvas");
const dashboardPackagesStatusesChartCanvas = document.getElementById("dashboard-packages-statuses-chart");
let dashboardPackagesStatusesChart = null;
const dashboardPackagesCountChartCanvas = document.getElementById("dashboard-packages-count-chart");
let dashboardPackagesCountChart = null;
ready(_ => {
dashboardPackagesStatusesChart = new Chart(dashboardPackagesStatusesChartCanvas, {
type: "pie",
data: {},
options: {
responsive: true,
},
});
dashboardPackagesCountChart = new Chart(dashboardPackagesCountChartCanvas, {
type: "bar",
data: {},
options: {
maintainAspectRatio: false,
responsive: true,
scales: {
x: {
stacked: true,
},
},
},
});
});
</script>

View File

@ -59,7 +59,17 @@
</nav> </nav>
<div class="tab-content" id="nav-tabContent"> <div class="tab-content" id="nav-tabContent">
<div id="package-info-logs" class="tab-pane fade show active" role="tabpanel" aria-labelledby="package-info-logs-button" tabindex="0"> <div id="package-info-logs" class="tab-pane fade show active" role="tabpanel" aria-labelledby="package-info-logs-button" tabindex="0">
<pre class="language-console"><code id="package-info-logs-input" class="pre-scrollable language-console"></code><button id="package-info-logs-copy-button" type="button" class="btn language-console" onclick="copyLogs()"><i class="bi bi-clipboard"></i> copy</button></pre> <div class="row">
<div class="col-1 dropend">
<button id="package-info-logs-dropdown" class="btn dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<i class="bi bi-list"></i>
</button>
<nav id="package-info-logs-versions" class="dropdown-menu" aria-labelledby="package-info-logs-dropdown"></nav>
</div>
<div class="col-11">
<pre class="language-console"><code id="package-info-logs-input" class="pre-scrollable language-console"></code><button id="package-info-logs-copy-button" type="button" class="btn language-console" onclick="copyLogs()"><i class="bi bi-clipboard"></i> copy</button></pre>
</div>
</div>
</div> </div>
<div id="package-info-changes" class="tab-pane fade" role="tabpanel" aria-labelledby="package-info-changes-button" tabindex="0"> <div id="package-info-changes" class="tab-pane fade" role="tabpanel" aria-labelledby="package-info-changes-button" tabindex="0">
<pre class="language-diff"><code id="package-info-changes-input" class="pre-scrollable language-diff"></code><button id="package-info-changes-copy-button" type="button" class="btn language-diff" onclick="copyChanges()"><i class="bi bi-clipboard"></i> copy</button></pre> <pre class="language-diff"><code id="package-info-changes-input" class="pre-scrollable language-diff"></code><button id="package-info-changes-copy-button" type="button" class="btn language-diff" onclick="copyChanges()"><i class="bi bi-clipboard"></i> copy</button></pre>
@ -100,6 +110,7 @@
const packageInfoModalHeader = document.getElementById("package-info-modal-header"); const packageInfoModalHeader = document.getElementById("package-info-modal-header");
const packageInfo = document.getElementById("package-info"); const packageInfo = document.getElementById("package-info");
const packageInfoLogsVersions = document.getElementById("package-info-logs-versions");
const packageInfoLogsInput = document.getElementById("package-info-logs-input"); const packageInfoLogsInput = document.getElementById("package-info-logs-input");
const packageInfoLogsCopyButton = document.getElementById("package-info-logs-copy-button"); const packageInfoLogsCopyButton = document.getElementById("package-info-logs-copy-button");
@ -163,7 +174,7 @@
const variableValueInput = document.createElement("input"); const variableValueInput = document.createElement("input");
variableValueInput.classList.add("form-control"); variableValueInput.classList.add("form-control");
variableValueInput.readOnly = true; variableValueInput.readOnly = true;
variableValueInput.value = variable.value; variableValueInput.value = JSON.stringify(variable.value);
const variableButtonRemove = document.createElement("button"); const variableButtonRemove = document.createElement("button");
variableButtonRemove.type = "button"; variableButtonRemove.type = "button";
@ -285,25 +296,51 @@
convert: response => response.json(), convert: response => response.json(),
}, },
data => { data => {
const logs = data.map(log_record => { const selectors = Object
return `[${new Date(1000 * log_record.created).toISOString()}] ${log_record.message}`; .values(
}); data.reduce((acc, log_record) => {
packageInfoLogsInput.textContent = logs.join("\n"); const id = `${log_record.version}-${log_record.process_id}`;
highlight(packageInfoLogsInput); if (acc[id])
acc[id].created = Math.min(log_record.created, acc[id].created);
else
acc[id] = log_record;
return acc;
}, {})
)
.sort(({created: left}, {created: right}) =>
right - left
)
.map(version => {
const link = document.createElement("a");
link.classList.add("dropdown-item");
link.textContent = new Date(1000 * version.created).toISOStringShort();
link.href = "#";
link.onclick = _ => {
const logs = data
.filter(log_record => log_record.version === version.version && log_record.process_id === version.process_id)
.map(log_record => `[${new Date(1000 * log_record.created).toISOString()}] ${log_record.message}`);
packageInfoLogsInput.textContent = logs.join("\n");
highlight(packageInfoLogsInput);
Array.from(packageInfoLogsVersions.children).forEach(el => el.classList.remove("active"));
link.classList.add("active");
return false;
};
return link;
});
packageInfoLogsVersions.replaceChildren(...selectors);
selectors.find(Boolean)?.click();
}, },
onFailure, onFailure,
); );
} }
function loadPackage(packageBase, onFailure) { function loadPackage(packageBase, onFailure) {
const headerClass = status => {
if (status === "pending") return ["bg-warning"];
if (status === "building") return ["bg-warning"];
if (status === "failed") return ["bg-danger", "text-white"];
if (status === "success") return ["bg-success", "text-white"];
return ["bg-secondary", "text-white"];
};
makeRequest( makeRequest(
`/api/v1/packages/${packageBase}`, `/api/v1/packages/${packageBase}`,
{ {

View File

@ -7,7 +7,7 @@
// so far bootstrap-table only operates with jquery elements // so far bootstrap-table only operates with jquery elements
const table = $(document.getElementById("packages")); const table = $(document.getElementById("packages"));
const statusBadge = document.getElementById("badge-status"); const dashboardButton = document.getElementById("dashboard-button");
const versionBadge = document.getElementById("badge-version"); const versionBadge = document.getElementById("badge-version");
function doPackageAction(uri, packages, repository, successText, failureText, data) { function doPackageAction(uri, packages, repository, successText, failureText, data) {
@ -141,14 +141,62 @@
data => { data => {
versionBadge.innerHTML = `<i class="bi bi-github"></i> ahriman ${safe(data.version)}`; versionBadge.innerHTML = `<i class="bi bi-github"></i> ahriman ${safe(data.version)}`;
statusBadge.classList.remove(...statusBadge.classList); dashboardButton.classList.remove(...dashboardButton.classList);
statusBadge.classList.add("btn"); dashboardButton.classList.add("btn");
statusBadge.classList.add(badgeClass(data.status.status)); dashboardButton.classList.add(badgeClass(data.status.status));
const popover = bootstrap.Popover.getOrCreateInstance(statusBadge); dashboardModalHeader.classList.remove(...dashboardModalHeader.classList);
popover.dispose(); dashboardModalHeader.classList.add("modal-header");
statusBadge.dataset.bsContent = `${data.status.status} at ${new Date(1000 * data.status.timestamp).toISOStringShort()}`; headerClass(data.status.status).forEach(clz => dashboardModalHeader.classList.add(clz));
bootstrap.Popover.getOrCreateInstance(statusBadge);
dashboardName.textContent = data.repository;
dashboardArchitecture.textContent = data.architecture;
dashboardStatus.textContent = data.status.status;
dashboardStatusTimestamp.textContent = new Date(1000 * data.status.timestamp).toISOStringShort();
if (dashboardPackagesStatusesChart) {
const labels = [
"unknown",
"pending",
"building",
"failed",
"success",
];
dashboardPackagesStatusesChart.config.data = {
labels: labels,
datasets: [{
label: "packages in status",
data: labels.map(label => data.packages[label]),
backgroundColor: [
"rgb(55, 58, 60)",
"rgb(255, 117, 24)",
"rgb(255, 117, 24)",
"rgb(255, 0, 57)",
"rgb(63, 182, 24)", // copy-paste from current style
],
}],
};
dashboardPackagesStatusesChart.update();
}
if (dashboardPackagesCountChart) {
dashboardPackagesCountChart.config.data = {
labels: ["packages"],
datasets: [
{
label: "archives",
data: [data.stats.packages],
},
{
label: "bases",
data: [data.stats.bases],
},
],
};
dashboardPackagesCountChart.update();
}
dashboardCanvas.hidden = data.status.total > 0;
}, },
); );
} }
@ -227,7 +275,6 @@
}); });
}); });
bootstrap.Popover.getOrCreateInstance(statusBadge);
selectRepository(); selectRepository();
}); });
</script> </script>

View File

@ -58,6 +58,14 @@
return value.includes(dataList[index].toLowerCase()); return value.includes(dataList[index].toLowerCase());
} }
function headerClass(status) {
if (status === "pending") return ["bg-warning"];
if (status === "building") return ["bg-warning"];
if (status === "failed") return ["bg-danger", "text-white"];
if (status === "success") return ["bg-success", "text-white"];
return ["bg-secondary", "text-white"];
}
function listToTable(data) { function listToTable(data) {
return Array.from(new Set(data)) return Array.from(new Set(data))
.sort() .sort()

View File

@ -1,115 +1,117 @@
# AUTOMATICALLY GENERATED by `shtab` # AUTOMATICALLY GENERATED by `shtab`
_shtab_ahriman_subparsers=('aur-search' 'search' 'help-commands-unsafe' 'help' 'help-updates' 'help-version' 'version' 'package-add' 'add' 'package-update' 'package-changes' 'package-changes-remove' 'package-remove' 'remove' 'package-status' 'status' 'package-status-remove' 'package-status-update' 'status-update' 'patch-add' 'patch-list' 'patch-remove' 'patch-set-add' 'repo-backup' 'repo-check' 'check' 'repo-create-keyring' 'repo-create-mirrorlist' 'repo-daemon' 'daemon' 'repo-rebuild' 'rebuild' 'repo-remove-unknown' 'remove-unknown' 'repo-report' 'report' 'repo-restore' 'repo-sign' 'sign' 'repo-statistics' 'repo-status-update' 'repo-sync' 'sync' 'repo-tree' 'repo-triggers' 'repo-update' 'update' 'service-clean' 'clean' 'repo-clean' 'service-config' 'config' 'repo-config' 'service-config-validate' 'config-validate' 'repo-config-validate' 'service-key-import' 'key-import' 'service-repositories' 'service-run' 'run' 'service-setup' 'init' 'repo-init' 'repo-setup' 'setup' 'service-shell' 'shell' 'service-tree-migrate' 'user-add' 'user-list' 'user-remove' 'web') _shtab_ahriman_subparsers=('add' 'aur-search' 'check' 'clean' 'config' 'config-validate' 'copy' 'daemon' 'help' 'help-commands-unsafe' 'help-updates' 'help-version' 'init' 'key-import' 'package-add' 'package-changes' 'package-changes-remove' 'package-copy' 'package-remove' 'package-status' 'package-status-remove' 'package-status-update' 'package-update' 'patch-add' 'patch-list' 'patch-remove' 'patch-set-add' 'rebuild' 'remove' 'remove-unknown' 'repo-backup' 'repo-check' 'repo-clean' 'repo-config' 'repo-config-validate' 'repo-create-keyring' 'repo-create-mirrorlist' 'repo-daemon' 'repo-init' 'repo-rebuild' 'repo-remove-unknown' 'repo-report' 'repo-restore' 'repo-setup' 'repo-sign' 'repo-statistics' 'repo-status-update' 'repo-sync' 'repo-tree' 'repo-triggers' 'repo-update' 'report' 'run' 'search' 'service-clean' 'service-config' 'service-config-validate' 'service-key-import' 'service-repositories' 'service-run' 'service-setup' 'service-shell' 'service-tree-migrate' 'setup' 'shell' 'sign' 'status' 'status-update' 'sync' 'update' 'user-add' 'user-list' 'user-remove' 'version' 'web')
_shtab_ahriman_option_strings=('-h' '--help' '-a' '--architecture' '-c' '--configuration' '--force' '-l' '--lock' '--log-handler' '-q' '--quiet' '--report' '--no-report' '-r' '--repository' '--unsafe' '-V' '--version' '--wait-timeout') _shtab_ahriman_option_strings=('-h' '--help' '-a' '--architecture' '-c' '--configuration' '--force' '-l' '--lock' '--log-handler' '-q' '--quiet' '--report' '--no-report' '-r' '--repository' '--unsafe' '-V' '--version' '--wait-timeout')
_shtab_ahriman_add_option_strings=('-h' '--help' '--changes' '--no-changes' '--dependencies' '--no-dependencies' '-e' '--exit-code' '--increment' '--no-increment' '-n' '--now' '-y' '--refresh' '-s' '--source' '-u' '--username' '-v' '--variable')
_shtab_ahriman_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_check_option_strings=('-h' '--help' '--changes' '--no-changes' '--check-files' '--no-check-files' '-e' '--exit-code' '--vcs' '--no-vcs' '-y' '--refresh')
_shtab_ahriman_help_commands_unsafe_option_strings=('-h' '--help') _shtab_ahriman_clean_option_strings=('-h' '--help' '--cache' '--no-cache' '--chroot' '--no-chroot' '--manual' '--no-manual' '--packages' '--no-packages' '--pacman' '--no-pacman')
_shtab_ahriman_config_option_strings=('-h' '--help' '--info' '--no-info' '--secure' '--no-secure')
_shtab_ahriman_config_validate_option_strings=('-h' '--help' '-e' '--exit-code')
_shtab_ahriman_copy_option_strings=('-h' '--help' '-e' '--exit-code' '--remove')
_shtab_ahriman_daemon_option_strings=('-h' '--help' '-i' '--interval' '--aur' '--no-aur' '--changes' '--no-changes' '--check-files' '--no-check-files' '--dependencies' '--no-dependencies' '--dry-run' '--increment' '--no-increment' '--local' '--no-local' '--manual' '--no-manual' '--partitions' '--no-partitions' '-u' '--username' '--vcs' '--no-vcs' '-y' '--refresh')
_shtab_ahriman_help_option_strings=('-h' '--help') _shtab_ahriman_help_option_strings=('-h' '--help')
_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_init_option_strings=('-h' '--help' '--build-as-user' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--server' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket')
_shtab_ahriman_key_import_option_strings=('-h' '--help' '--key-server')
_shtab_ahriman_package_add_option_strings=('-h' '--help' '--changes' '--no-changes' '--dependencies' '--no-dependencies' '-e' '--exit-code' '--increment' '--no-increment' '-n' '--now' '-y' '--refresh' '-s' '--source' '-u' '--username' '-v' '--variable') _shtab_ahriman_package_add_option_strings=('-h' '--help' '--changes' '--no-changes' '--dependencies' '--no-dependencies' '-e' '--exit-code' '--increment' '--no-increment' '-n' '--now' '-y' '--refresh' '-s' '--source' '-u' '--username' '-v' '--variable')
_shtab_ahriman_add_option_strings=('-h' '--help' '--changes' '--no-changes' '--dependencies' '--no-dependencies' '-e' '--exit-code' '--increment' '--no-increment' '-n' '--now' '-y' '--refresh' '-s' '--source' '-u' '--username' '-v' '--variable')
_shtab_ahriman_package_update_option_strings=('-h' '--help' '--changes' '--no-changes' '--dependencies' '--no-dependencies' '-e' '--exit-code' '--increment' '--no-increment' '-n' '--now' '-y' '--refresh' '-s' '--source' '-u' '--username' '-v' '--variable')
_shtab_ahriman_package_changes_option_strings=('-h' '--help' '-e' '--exit-code') _shtab_ahriman_package_changes_option_strings=('-h' '--help' '-e' '--exit-code')
_shtab_ahriman_package_changes_remove_option_strings=('-h' '--help') _shtab_ahriman_package_changes_remove_option_strings=('-h' '--help')
_shtab_ahriman_package_copy_option_strings=('-h' '--help' '-e' '--exit-code' '--remove')
_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_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')
_shtab_ahriman_status_option_strings=('-h' '--help' '--ahriman' '-e' '--exit-code' '--info' '--no-info' '-s' '--status')
_shtab_ahriman_package_status_remove_option_strings=('-h' '--help') _shtab_ahriman_package_status_remove_option_strings=('-h' '--help')
_shtab_ahriman_package_status_update_option_strings=('-h' '--help' '-s' '--status') _shtab_ahriman_package_status_update_option_strings=('-h' '--help' '-s' '--status')
_shtab_ahriman_status_update_option_strings=('-h' '--help' '-s' '--status') _shtab_ahriman_package_update_option_strings=('-h' '--help' '--changes' '--no-changes' '--dependencies' '--no-dependencies' '-e' '--exit-code' '--increment' '--no-increment' '-n' '--now' '-y' '--refresh' '-s' '--source' '-u' '--username' '-v' '--variable')
_shtab_ahriman_patch_add_option_strings=('-h' '--help') _shtab_ahriman_patch_add_option_strings=('-h' '--help')
_shtab_ahriman_patch_list_option_strings=('-h' '--help' '-e' '--exit-code' '-v' '--variable') _shtab_ahriman_patch_list_option_strings=('-h' '--help' '-e' '--exit-code' '-v' '--variable')
_shtab_ahriman_patch_remove_option_strings=('-h' '--help' '-v' '--variable') _shtab_ahriman_patch_remove_option_strings=('-h' '--help' '-v' '--variable')
_shtab_ahriman_patch_set_add_option_strings=('-h' '--help' '-t' '--track') _shtab_ahriman_patch_set_add_option_strings=('-h' '--help' '-t' '--track')
_shtab_ahriman_rebuild_option_strings=('-h' '--help' '--depends-on' '--dry-run' '--from-database' '--increment' '--no-increment' '-e' '--exit-code' '-s' '--status' '-u' '--username')
_shtab_ahriman_remove_option_strings=('-h' '--help')
_shtab_ahriman_remove_unknown_option_strings=('-h' '--help' '--dry-run')
_shtab_ahriman_repo_backup_option_strings=('-h' '--help') _shtab_ahriman_repo_backup_option_strings=('-h' '--help')
_shtab_ahriman_repo_check_option_strings=('-h' '--help' '--changes' '--no-changes' '--check-files' '--no-check-files' '-e' '--exit-code' '--vcs' '--no-vcs' '-y' '--refresh') _shtab_ahriman_repo_check_option_strings=('-h' '--help' '--changes' '--no-changes' '--check-files' '--no-check-files' '-e' '--exit-code' '--vcs' '--no-vcs' '-y' '--refresh')
_shtab_ahriman_check_option_strings=('-h' '--help' '--changes' '--no-changes' '--check-files' '--no-check-files' '-e' '--exit-code' '--vcs' '--no-vcs' '-y' '--refresh') _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_config_option_strings=('-h' '--help' '--info' '--no-info' '--secure' '--no-secure')
_shtab_ahriman_repo_config_validate_option_strings=('-h' '--help' '-e' '--exit-code')
_shtab_ahriman_repo_create_keyring_option_strings=('-h' '--help') _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' '--changes' '--no-changes' '--check-files' '--no-check-files' '--dependencies' '--no-dependencies' '--dry-run' '--increment' '--no-increment' '--local' '--no-local' '--manual' '--no-manual' '--partitions' '--no-partitions' '-u' '--username' '--vcs' '--no-vcs' '-y' '--refresh') _shtab_ahriman_repo_daemon_option_strings=('-h' '--help' '-i' '--interval' '--aur' '--no-aur' '--changes' '--no-changes' '--check-files' '--no-check-files' '--dependencies' '--no-dependencies' '--dry-run' '--increment' '--no-increment' '--local' '--no-local' '--manual' '--no-manual' '--partitions' '--no-partitions' '-u' '--username' '--vcs' '--no-vcs' '-y' '--refresh')
_shtab_ahriman_daemon_option_strings=('-h' '--help' '-i' '--interval' '--aur' '--no-aur' '--changes' '--no-changes' '--check-files' '--no-check-files' '--dependencies' '--no-dependencies' '--dry-run' '--increment' '--no-increment' '--local' '--no-local' '--manual' '--no-manual' '--partitions' '--no-partitions' '-u' '--username' '--vcs' '--no-vcs' '-y' '--refresh') _shtab_ahriman_repo_init_option_strings=('-h' '--help' '--build-as-user' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--server' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket')
_shtab_ahriman_repo_rebuild_option_strings=('-h' '--help' '--depends-on' '--dry-run' '--from-database' '--increment' '--no-increment' '-e' '--exit-code' '-s' '--status' '-u' '--username') _shtab_ahriman_repo_rebuild_option_strings=('-h' '--help' '--depends-on' '--dry-run' '--from-database' '--increment' '--no-increment' '-e' '--exit-code' '-s' '--status' '-u' '--username')
_shtab_ahriman_rebuild_option_strings=('-h' '--help' '--depends-on' '--dry-run' '--from-database' '--increment' '--no-increment' '-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_repo_report_option_strings=('-h' '--help') _shtab_ahriman_repo_report_option_strings=('-h' '--help')
_shtab_ahriman_report_option_strings=('-h' '--help')
_shtab_ahriman_repo_restore_option_strings=('-h' '--help' '-o' '--output') _shtab_ahriman_repo_restore_option_strings=('-h' '--help' '-o' '--output')
_shtab_ahriman_repo_setup_option_strings=('-h' '--help' '--build-as-user' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--server' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket')
_shtab_ahriman_repo_sign_option_strings=('-h' '--help') _shtab_ahriman_repo_sign_option_strings=('-h' '--help')
_shtab_ahriman_sign_option_strings=('-h' '--help')
_shtab_ahriman_repo_statistics_option_strings=('-h' '--help' '--chart' '-e' '--event' '--from-date' '--limit' '--offset' '--to-date') _shtab_ahriman_repo_statistics_option_strings=('-h' '--help' '--chart' '-e' '--event' '--from-date' '--limit' '--offset' '--to-date')
_shtab_ahriman_repo_status_update_option_strings=('-h' '--help' '-s' '--status') _shtab_ahriman_repo_status_update_option_strings=('-h' '--help' '-s' '--status')
_shtab_ahriman_repo_sync_option_strings=('-h' '--help') _shtab_ahriman_repo_sync_option_strings=('-h' '--help')
_shtab_ahriman_sync_option_strings=('-h' '--help')
_shtab_ahriman_repo_tree_option_strings=('-h' '--help' '-p' '--partitions') _shtab_ahriman_repo_tree_option_strings=('-h' '--help' '-p' '--partitions')
_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' '--changes' '--no-changes' '--check-files' '--no-check-files' '--dependencies' '--no-dependencies' '--dry-run' '-e' '--exit-code' '--increment' '--no-increment' '--local' '--no-local' '--manual' '--no-manual' '-u' '--username' '--vcs' '--no-vcs' '-y' '--refresh') _shtab_ahriman_repo_update_option_strings=('-h' '--help' '--aur' '--no-aur' '--changes' '--no-changes' '--check-files' '--no-check-files' '--dependencies' '--no-dependencies' '--dry-run' '-e' '--exit-code' '--increment' '--no-increment' '--local' '--no-local' '--manual' '--no-manual' '-u' '--username' '--vcs' '--no-vcs' '-y' '--refresh')
_shtab_ahriman_update_option_strings=('-h' '--help' '--aur' '--no-aur' '--changes' '--no-changes' '--check-files' '--no-check-files' '--dependencies' '--no-dependencies' '--dry-run' '-e' '--exit-code' '--increment' '--no-increment' '--local' '--no-local' '--manual' '--no-manual' '-u' '--username' '--vcs' '--no-vcs' '-y' '--refresh') _shtab_ahriman_report_option_strings=('-h' '--help')
_shtab_ahriman_run_option_strings=('-h' '--help')
_shtab_ahriman_search_option_strings=('-h' '--help' '-e' '--exit-code' '--info' '--no-info' '--sort-by')
_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_repo_clean_option_strings=('-h' '--help' '--cache' '--no-cache' '--chroot' '--no-chroot' '--manual' '--no-manual' '--packages' '--no-packages' '--pacman' '--no-pacman')
_shtab_ahriman_service_config_option_strings=('-h' '--help' '--info' '--no-info' '--secure' '--no-secure') _shtab_ahriman_service_config_option_strings=('-h' '--help' '--info' '--no-info' '--secure' '--no-secure')
_shtab_ahriman_config_option_strings=('-h' '--help' '--info' '--no-info' '--secure' '--no-secure')
_shtab_ahriman_repo_config_option_strings=('-h' '--help' '--info' '--no-info' '--secure' '--no-secure')
_shtab_ahriman_service_config_validate_option_strings=('-h' '--help' '-e' '--exit-code') _shtab_ahriman_service_config_validate_option_strings=('-h' '--help' '-e' '--exit-code')
_shtab_ahriman_config_validate_option_strings=('-h' '--help' '-e' '--exit-code')
_shtab_ahriman_repo_config_validate_option_strings=('-h' '--help' '-e' '--exit-code')
_shtab_ahriman_service_key_import_option_strings=('-h' '--help' '--key-server') _shtab_ahriman_service_key_import_option_strings=('-h' '--help' '--key-server')
_shtab_ahriman_key_import_option_strings=('-h' '--help' '--key-server')
_shtab_ahriman_service_repositories_option_strings=('-h' '--help' '--id-only' '--no-id-only') _shtab_ahriman_service_repositories_option_strings=('-h' '--help' '--id-only' '--no-id-only')
_shtab_ahriman_service_run_option_strings=('-h' '--help') _shtab_ahriman_service_run_option_strings=('-h' '--help')
_shtab_ahriman_run_option_strings=('-h' '--help')
_shtab_ahriman_service_setup_option_strings=('-h' '--help' '--build-as-user' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--server' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket') _shtab_ahriman_service_setup_option_strings=('-h' '--help' '--build-as-user' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--server' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket')
_shtab_ahriman_init_option_strings=('-h' '--help' '--build-as-user' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--server' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket') _shtab_ahriman_service_shell_option_strings=('-h' '--help' '-o' '--output')
_shtab_ahriman_repo_init_option_strings=('-h' '--help' '--build-as-user' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--server' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket')
_shtab_ahriman_repo_setup_option_strings=('-h' '--help' '--build-as-user' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--server' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket')
_shtab_ahriman_setup_option_strings=('-h' '--help' '--build-as-user' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--server' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket')
_shtab_ahriman_service_shell_option_strings=('-h' '--help')
_shtab_ahriman_shell_option_strings=('-h' '--help')
_shtab_ahriman_service_tree_migrate_option_strings=('-h' '--help') _shtab_ahriman_service_tree_migrate_option_strings=('-h' '--help')
_shtab_ahriman_setup_option_strings=('-h' '--help' '--build-as-user' '--from-configuration' '--generate-salt' '--no-generate-salt' '--makeflags-jobs' '--no-makeflags-jobs' '--mirror' '--multilib' '--no-multilib' '--packager' '--server' '--sign-key' '--sign-target' '--web-port' '--web-unix-socket')
_shtab_ahriman_shell_option_strings=('-h' '--help' '-o' '--output')
_shtab_ahriman_sign_option_strings=('-h' '--help')
_shtab_ahriman_status_option_strings=('-h' '--help' '--ahriman' '-e' '--exit-code' '--info' '--no-info' '-s' '--status')
_shtab_ahriman_status_update_option_strings=('-h' '--help' '-s' '--status')
_shtab_ahriman_sync_option_strings=('-h' '--help')
_shtab_ahriman_update_option_strings=('-h' '--help' '--aur' '--no-aur' '--changes' '--no-changes' '--check-files' '--no-check-files' '--dependencies' '--no-dependencies' '--dry-run' '-e' '--exit-code' '--increment' '--no-increment' '--local' '--no-local' '--manual' '--no-manual' '-u' '--username' '--vcs' '--no-vcs' '-y' '--refresh')
_shtab_ahriman_user_add_option_strings=('-h' '--help' '--key' '--packager' '-p' '--password' '-R' '--role') _shtab_ahriman_user_add_option_strings=('-h' '--help' '--key' '--packager' '-p' '--password' '-R' '--role')
_shtab_ahriman_user_list_option_strings=('-h' '--help' '-e' '--exit-code' '-R' '--role') _shtab_ahriman_user_list_option_strings=('-h' '--help' '-e' '--exit-code' '-R' '--role')
_shtab_ahriman_user_remove_option_strings=('-h' '--help') _shtab_ahriman_user_remove_option_strings=('-h' '--help')
_shtab_ahriman_version_option_strings=('-h' '--help')
_shtab_ahriman_web_option_strings=('-h' '--help') _shtab_ahriman_web_option_strings=('-h' '--help')
_shtab_ahriman_pos_0_choices=('aur-search' 'search' 'help-commands-unsafe' 'help' 'help-updates' 'help-version' 'version' 'package-add' 'add' 'package-update' 'package-changes' 'package-changes-remove' 'package-remove' 'remove' 'package-status' 'status' 'package-status-remove' 'package-status-update' 'status-update' 'patch-add' 'patch-list' 'patch-remove' 'patch-set-add' 'repo-backup' 'repo-check' 'check' 'repo-create-keyring' 'repo-create-mirrorlist' 'repo-daemon' 'daemon' 'repo-rebuild' 'rebuild' 'repo-remove-unknown' 'remove-unknown' 'repo-report' 'report' 'repo-restore' 'repo-sign' 'sign' 'repo-statistics' 'repo-status-update' 'repo-sync' 'sync' 'repo-tree' 'repo-triggers' 'repo-update' 'update' 'service-clean' 'clean' 'repo-clean' 'service-config' 'config' 'repo-config' 'service-config-validate' 'config-validate' 'repo-config-validate' 'service-key-import' 'key-import' 'service-repositories' 'service-run' 'run' 'service-setup' 'init' 'repo-init' 'repo-setup' 'setup' 'service-shell' 'shell' 'service-tree-migrate' 'user-add' 'user-list' 'user-remove' 'web') _shtab_ahriman_pos_0_choices=('add' 'aur-search' 'check' 'clean' 'config' 'config-validate' 'copy' 'daemon' 'help' 'help-commands-unsafe' 'help-updates' 'help-version' 'init' 'key-import' 'package-add' 'package-changes' 'package-changes-remove' 'package-copy' 'package-remove' 'package-status' 'package-status-remove' 'package-status-update' 'package-update' 'patch-add' 'patch-list' 'patch-remove' 'patch-set-add' 'rebuild' 'remove' 'remove-unknown' 'repo-backup' 'repo-check' 'repo-clean' 'repo-config' 'repo-config-validate' 'repo-create-keyring' 'repo-create-mirrorlist' 'repo-daemon' 'repo-init' 'repo-rebuild' 'repo-remove-unknown' 'repo-report' 'repo-restore' 'repo-setup' 'repo-sign' 'repo-statistics' 'repo-status-update' 'repo-sync' 'repo-tree' 'repo-triggers' 'repo-update' 'report' 'run' 'search' 'service-clean' 'service-config' 'service-config-validate' 'service-key-import' 'service-repositories' 'service-run' 'service-setup' 'service-shell' 'service-tree-migrate' 'setup' 'shell' 'sign' 'status' 'status-update' 'sync' 'update' 'user-add' 'user-list' 'user-remove' 'version' 'web')
_shtab_ahriman___log_handler_choices=('console' 'syslog' 'journald') _shtab_ahriman___log_handler_choices=('console' 'syslog' 'journald')
_shtab_ahriman_aur_search___sort_by_choices=('description' 'first_submitted' 'id' 'last_modified' 'maintainer' 'name' 'num_votes' 'out_of_date' 'package_base' 'package_base_id' 'popularity' 'repository' 'submitter' 'url' 'url_path' 'version')
_shtab_ahriman_search___sort_by_choices=('description' 'first_submitted' 'id' 'last_modified' 'maintainer' 'name' 'num_votes' 'out_of_date' 'package_base' 'package_base_id' 'popularity' 'repository' 'submitter' 'url' 'url_path' 'version')
_shtab_ahriman_package_add__s_choices=('auto' 'archive' 'aur' 'directory' 'local' 'remote' 'repository')
_shtab_ahriman_package_add___source_choices=('auto' 'archive' 'aur' 'directory' 'local' 'remote' 'repository')
_shtab_ahriman_add__s_choices=('auto' 'archive' 'aur' 'directory' 'local' 'remote' 'repository') _shtab_ahriman_add__s_choices=('auto' 'archive' 'aur' 'directory' 'local' 'remote' 'repository')
_shtab_ahriman_add___source_choices=('auto' 'archive' 'aur' 'directory' 'local' 'remote' 'repository') _shtab_ahriman_add___source_choices=('auto' 'archive' 'aur' 'directory' 'local' 'remote' 'repository')
_shtab_ahriman_package_update__s_choices=('auto' 'archive' 'aur' 'directory' 'local' 'remote' 'repository') _shtab_ahriman_aur_search___sort_by_choices=('description' 'first_submitted' 'id' 'last_modified' 'maintainer' 'name' 'num_votes' 'out_of_date' 'package_base' 'package_base_id' 'popularity' 'repository' 'submitter' 'url' 'url_path' 'version')
_shtab_ahriman_package_update___source_choices=('auto' 'archive' 'aur' 'directory' 'local' 'remote' 'repository') _shtab_ahriman_init___sign_target_choices=('disabled' 'packages' 'repository')
_shtab_ahriman_package_add__s_choices=('auto' 'archive' 'aur' 'directory' 'local' 'remote' 'repository')
_shtab_ahriman_package_add___source_choices=('auto' 'archive' 'aur' 'directory' 'local' 'remote' 'repository')
_shtab_ahriman_package_status__s_choices=('unknown' 'pending' 'building' 'failed' 'success') _shtab_ahriman_package_status__s_choices=('unknown' 'pending' 'building' 'failed' 'success')
_shtab_ahriman_package_status___status_choices=('unknown' 'pending' 'building' 'failed' 'success') _shtab_ahriman_package_status___status_choices=('unknown' 'pending' 'building' 'failed' 'success')
_shtab_ahriman_status__s_choices=('unknown' 'pending' 'building' 'failed' 'success')
_shtab_ahriman_status___status_choices=('unknown' 'pending' 'building' 'failed' 'success')
_shtab_ahriman_package_status_update__s_choices=('unknown' 'pending' 'building' 'failed' 'success') _shtab_ahriman_package_status_update__s_choices=('unknown' 'pending' 'building' 'failed' 'success')
_shtab_ahriman_package_status_update___status_choices=('unknown' 'pending' 'building' 'failed' 'success') _shtab_ahriman_package_status_update___status_choices=('unknown' 'pending' 'building' 'failed' 'success')
_shtab_ahriman_status_update__s_choices=('unknown' 'pending' 'building' 'failed' 'success') _shtab_ahriman_package_update__s_choices=('auto' 'archive' 'aur' 'directory' 'local' 'remote' 'repository')
_shtab_ahriman_status_update___status_choices=('unknown' 'pending' 'building' 'failed' 'success') _shtab_ahriman_package_update___source_choices=('auto' 'archive' 'aur' 'directory' 'local' 'remote' 'repository')
_shtab_ahriman_repo_rebuild__s_choices=('unknown' 'pending' 'building' 'failed' 'success')
_shtab_ahriman_repo_rebuild___status_choices=('unknown' 'pending' 'building' 'failed' 'success')
_shtab_ahriman_rebuild__s_choices=('unknown' 'pending' 'building' 'failed' 'success') _shtab_ahriman_rebuild__s_choices=('unknown' 'pending' 'building' 'failed' 'success')
_shtab_ahriman_rebuild___status_choices=('unknown' 'pending' 'building' 'failed' 'success') _shtab_ahriman_rebuild___status_choices=('unknown' 'pending' 'building' 'failed' 'success')
_shtab_ahriman_repo_init___sign_target_choices=('disabled' 'packages' 'repository')
_shtab_ahriman_repo_rebuild__s_choices=('unknown' 'pending' 'building' 'failed' 'success')
_shtab_ahriman_repo_rebuild___status_choices=('unknown' 'pending' 'building' 'failed' 'success')
_shtab_ahriman_repo_setup___sign_target_choices=('disabled' 'packages' 'repository')
_shtab_ahriman_repo_statistics__e_choices=('package-outdated' 'package-removed' 'package-update-failed' 'package-updated') _shtab_ahriman_repo_statistics__e_choices=('package-outdated' 'package-removed' 'package-update-failed' 'package-updated')
_shtab_ahriman_repo_statistics___event_choices=('package-outdated' 'package-removed' 'package-update-failed' 'package-updated') _shtab_ahriman_repo_statistics___event_choices=('package-outdated' 'package-removed' 'package-update-failed' 'package-updated')
_shtab_ahriman_repo_status_update__s_choices=('unknown' 'pending' 'building' 'failed' 'success') _shtab_ahriman_repo_status_update__s_choices=('unknown' 'pending' 'building' 'failed' 'success')
_shtab_ahriman_repo_status_update___status_choices=('unknown' 'pending' 'building' 'failed' 'success') _shtab_ahriman_repo_status_update___status_choices=('unknown' 'pending' 'building' 'failed' 'success')
_shtab_ahriman_search___sort_by_choices=('description' 'first_submitted' 'id' 'last_modified' 'maintainer' 'name' 'num_votes' 'out_of_date' 'package_base' 'package_base_id' 'popularity' 'repository' 'submitter' 'url' 'url_path' 'version')
_shtab_ahriman_service_setup___sign_target_choices=('disabled' 'packages' 'repository') _shtab_ahriman_service_setup___sign_target_choices=('disabled' 'packages' 'repository')
_shtab_ahriman_init___sign_target_choices=('disabled' 'packages' 'repository')
_shtab_ahriman_repo_init___sign_target_choices=('disabled' 'packages' 'repository')
_shtab_ahriman_repo_setup___sign_target_choices=('disabled' 'packages' 'repository')
_shtab_ahriman_setup___sign_target_choices=('disabled' 'packages' 'repository') _shtab_ahriman_setup___sign_target_choices=('disabled' 'packages' 'repository')
_shtab_ahriman_status__s_choices=('unknown' 'pending' 'building' 'failed' 'success')
_shtab_ahriman_status___status_choices=('unknown' 'pending' 'building' 'failed' 'success')
_shtab_ahriman_status_update__s_choices=('unknown' 'pending' 'building' 'failed' 'success')
_shtab_ahriman_status_update___status_choices=('unknown' 'pending' 'building' 'failed' 'success')
_shtab_ahriman_user_add__R_choices=('unauthorized' 'read' 'reporter' 'full') _shtab_ahriman_user_add__R_choices=('unauthorized' 'read' 'reporter' 'full')
_shtab_ahriman_user_add___role_choices=('unauthorized' 'read' 'reporter' 'full') _shtab_ahriman_user_add___role_choices=('unauthorized' 'read' 'reporter' 'full')
_shtab_ahriman_user_list__R_choices=('unauthorized' 'read' 'reporter' 'full') _shtab_ahriman_user_list__R_choices=('unauthorized' 'read' 'reporter' 'full')
@ -126,48 +128,6 @@ _shtab_ahriman___no_report_nargs=0
_shtab_ahriman___unsafe_nargs=0 _shtab_ahriman___unsafe_nargs=0
_shtab_ahriman__V_nargs=0 _shtab_ahriman__V_nargs=0
_shtab_ahriman___version_nargs=0 _shtab_ahriman___version_nargs=0
_shtab_ahriman_aur_search_pos_0_nargs=+
_shtab_ahriman_aur_search__h_nargs=0
_shtab_ahriman_aur_search___help_nargs=0
_shtab_ahriman_aur_search__e_nargs=0
_shtab_ahriman_aur_search___exit_code_nargs=0
_shtab_ahriman_aur_search___info_nargs=0
_shtab_ahriman_aur_search___no_info_nargs=0
_shtab_ahriman_search_pos_0_nargs=+
_shtab_ahriman_search__h_nargs=0
_shtab_ahriman_search___help_nargs=0
_shtab_ahriman_search__e_nargs=0
_shtab_ahriman_search___exit_code_nargs=0
_shtab_ahriman_search___info_nargs=0
_shtab_ahriman_search___no_info_nargs=0
_shtab_ahriman_help_commands_unsafe_pos_0_nargs=*
_shtab_ahriman_help_commands_unsafe__h_nargs=0
_shtab_ahriman_help_commands_unsafe___help_nargs=0
_shtab_ahriman_help__h_nargs=0
_shtab_ahriman_help___help_nargs=0
_shtab_ahriman_help_updates__h_nargs=0
_shtab_ahriman_help_updates___help_nargs=0
_shtab_ahriman_help_updates__e_nargs=0
_shtab_ahriman_help_updates___exit_code_nargs=0
_shtab_ahriman_help_version__h_nargs=0
_shtab_ahriman_help_version___help_nargs=0
_shtab_ahriman_version__h_nargs=0
_shtab_ahriman_version___help_nargs=0
_shtab_ahriman_package_add_pos_0_nargs=+
_shtab_ahriman_package_add__h_nargs=0
_shtab_ahriman_package_add___help_nargs=0
_shtab_ahriman_package_add___changes_nargs=0
_shtab_ahriman_package_add___no_changes_nargs=0
_shtab_ahriman_package_add___dependencies_nargs=0
_shtab_ahriman_package_add___no_dependencies_nargs=0
_shtab_ahriman_package_add__e_nargs=0
_shtab_ahriman_package_add___exit_code_nargs=0
_shtab_ahriman_package_add___increment_nargs=0
_shtab_ahriman_package_add___no_increment_nargs=0
_shtab_ahriman_package_add__n_nargs=0
_shtab_ahriman_package_add___now_nargs=0
_shtab_ahriman_package_add__y_nargs=0
_shtab_ahriman_package_add___refresh_nargs=0
_shtab_ahriman_add_pos_0_nargs=+ _shtab_ahriman_add_pos_0_nargs=+
_shtab_ahriman_add__h_nargs=0 _shtab_ahriman_add__h_nargs=0
_shtab_ahriman_add___help_nargs=0 _shtab_ahriman_add___help_nargs=0
@ -183,6 +143,142 @@ _shtab_ahriman_add__n_nargs=0
_shtab_ahriman_add___now_nargs=0 _shtab_ahriman_add___now_nargs=0
_shtab_ahriman_add__y_nargs=0 _shtab_ahriman_add__y_nargs=0
_shtab_ahriman_add___refresh_nargs=0 _shtab_ahriman_add___refresh_nargs=0
_shtab_ahriman_aur_search_pos_0_nargs=+
_shtab_ahriman_aur_search__h_nargs=0
_shtab_ahriman_aur_search___help_nargs=0
_shtab_ahriman_aur_search__e_nargs=0
_shtab_ahriman_aur_search___exit_code_nargs=0
_shtab_ahriman_aur_search___info_nargs=0
_shtab_ahriman_aur_search___no_info_nargs=0
_shtab_ahriman_check_pos_0_nargs=*
_shtab_ahriman_check__h_nargs=0
_shtab_ahriman_check___help_nargs=0
_shtab_ahriman_check___changes_nargs=0
_shtab_ahriman_check___no_changes_nargs=0
_shtab_ahriman_check___check_files_nargs=0
_shtab_ahriman_check___no_check_files_nargs=0
_shtab_ahriman_check__e_nargs=0
_shtab_ahriman_check___exit_code_nargs=0
_shtab_ahriman_check___vcs_nargs=0
_shtab_ahriman_check___no_vcs_nargs=0
_shtab_ahriman_check__y_nargs=0
_shtab_ahriman_check___refresh_nargs=0
_shtab_ahriman_clean__h_nargs=0
_shtab_ahriman_clean___help_nargs=0
_shtab_ahriman_clean___cache_nargs=0
_shtab_ahriman_clean___no_cache_nargs=0
_shtab_ahriman_clean___chroot_nargs=0
_shtab_ahriman_clean___no_chroot_nargs=0
_shtab_ahriman_clean___manual_nargs=0
_shtab_ahriman_clean___no_manual_nargs=0
_shtab_ahriman_clean___packages_nargs=0
_shtab_ahriman_clean___no_packages_nargs=0
_shtab_ahriman_clean___pacman_nargs=0
_shtab_ahriman_clean___no_pacman_nargs=0
_shtab_ahriman_config__h_nargs=0
_shtab_ahriman_config___help_nargs=0
_shtab_ahriman_config___info_nargs=0
_shtab_ahriman_config___no_info_nargs=0
_shtab_ahriman_config___secure_nargs=0
_shtab_ahriman_config___no_secure_nargs=0
_shtab_ahriman_config_validate__h_nargs=0
_shtab_ahriman_config_validate___help_nargs=0
_shtab_ahriman_config_validate__e_nargs=0
_shtab_ahriman_config_validate___exit_code_nargs=0
_shtab_ahriman_copy_pos_1_nargs=+
_shtab_ahriman_copy__h_nargs=0
_shtab_ahriman_copy___help_nargs=0
_shtab_ahriman_copy__e_nargs=0
_shtab_ahriman_copy___exit_code_nargs=0
_shtab_ahriman_copy___remove_nargs=0
_shtab_ahriman_daemon__h_nargs=0
_shtab_ahriman_daemon___help_nargs=0
_shtab_ahriman_daemon___aur_nargs=0
_shtab_ahriman_daemon___no_aur_nargs=0
_shtab_ahriman_daemon___changes_nargs=0
_shtab_ahriman_daemon___no_changes_nargs=0
_shtab_ahriman_daemon___check_files_nargs=0
_shtab_ahriman_daemon___no_check_files_nargs=0
_shtab_ahriman_daemon___dependencies_nargs=0
_shtab_ahriman_daemon___no_dependencies_nargs=0
_shtab_ahriman_daemon___dry_run_nargs=0
_shtab_ahriman_daemon___increment_nargs=0
_shtab_ahriman_daemon___no_increment_nargs=0
_shtab_ahriman_daemon___local_nargs=0
_shtab_ahriman_daemon___no_local_nargs=0
_shtab_ahriman_daemon___manual_nargs=0
_shtab_ahriman_daemon___no_manual_nargs=0
_shtab_ahriman_daemon___partitions_nargs=0
_shtab_ahriman_daemon___no_partitions_nargs=0
_shtab_ahriman_daemon___vcs_nargs=0
_shtab_ahriman_daemon___no_vcs_nargs=0
_shtab_ahriman_daemon__y_nargs=0
_shtab_ahriman_daemon___refresh_nargs=0
_shtab_ahriman_help__h_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___help_nargs=0
_shtab_ahriman_help_updates__h_nargs=0
_shtab_ahriman_help_updates___help_nargs=0
_shtab_ahriman_help_updates__e_nargs=0
_shtab_ahriman_help_updates___exit_code_nargs=0
_shtab_ahriman_help_version__h_nargs=0
_shtab_ahriman_help_version___help_nargs=0
_shtab_ahriman_init__h_nargs=0
_shtab_ahriman_init___help_nargs=0
_shtab_ahriman_init___generate_salt_nargs=0
_shtab_ahriman_init___no_generate_salt_nargs=0
_shtab_ahriman_init___makeflags_jobs_nargs=0
_shtab_ahriman_init___no_makeflags_jobs_nargs=0
_shtab_ahriman_init___multilib_nargs=0
_shtab_ahriman_init___no_multilib_nargs=0
_shtab_ahriman_key_import__h_nargs=0
_shtab_ahriman_key_import___help_nargs=0
_shtab_ahriman_package_add_pos_0_nargs=+
_shtab_ahriman_package_add__h_nargs=0
_shtab_ahriman_package_add___help_nargs=0
_shtab_ahriman_package_add___changes_nargs=0
_shtab_ahriman_package_add___no_changes_nargs=0
_shtab_ahriman_package_add___dependencies_nargs=0
_shtab_ahriman_package_add___no_dependencies_nargs=0
_shtab_ahriman_package_add__e_nargs=0
_shtab_ahriman_package_add___exit_code_nargs=0
_shtab_ahriman_package_add___increment_nargs=0
_shtab_ahriman_package_add___no_increment_nargs=0
_shtab_ahriman_package_add__n_nargs=0
_shtab_ahriman_package_add___now_nargs=0
_shtab_ahriman_package_add__y_nargs=0
_shtab_ahriman_package_add___refresh_nargs=0
_shtab_ahriman_package_changes__h_nargs=0
_shtab_ahriman_package_changes___help_nargs=0
_shtab_ahriman_package_changes__e_nargs=0
_shtab_ahriman_package_changes___exit_code_nargs=0
_shtab_ahriman_package_changes_remove__h_nargs=0
_shtab_ahriman_package_changes_remove___help_nargs=0
_shtab_ahriman_package_copy_pos_1_nargs=+
_shtab_ahriman_package_copy__h_nargs=0
_shtab_ahriman_package_copy___help_nargs=0
_shtab_ahriman_package_copy__e_nargs=0
_shtab_ahriman_package_copy___exit_code_nargs=0
_shtab_ahriman_package_copy___remove_nargs=0
_shtab_ahriman_package_remove_pos_0_nargs=+
_shtab_ahriman_package_remove__h_nargs=0
_shtab_ahriman_package_remove___help_nargs=0
_shtab_ahriman_package_status_pos_0_nargs=*
_shtab_ahriman_package_status__h_nargs=0
_shtab_ahriman_package_status___help_nargs=0
_shtab_ahriman_package_status___ahriman_nargs=0
_shtab_ahriman_package_status__e_nargs=0
_shtab_ahriman_package_status___exit_code_nargs=0
_shtab_ahriman_package_status___info_nargs=0
_shtab_ahriman_package_status___no_info_nargs=0
_shtab_ahriman_package_status_remove_pos_0_nargs=+
_shtab_ahriman_package_status_remove__h_nargs=0
_shtab_ahriman_package_status_remove___help_nargs=0
_shtab_ahriman_package_status_update_pos_0_nargs=*
_shtab_ahriman_package_status_update__h_nargs=0
_shtab_ahriman_package_status_update___help_nargs=0
_shtab_ahriman_package_update_pos_0_nargs=+ _shtab_ahriman_package_update_pos_0_nargs=+
_shtab_ahriman_package_update__h_nargs=0 _shtab_ahriman_package_update__h_nargs=0
_shtab_ahriman_package_update___help_nargs=0 _shtab_ahriman_package_update___help_nargs=0
@ -198,43 +294,6 @@ _shtab_ahriman_package_update__n_nargs=0
_shtab_ahriman_package_update___now_nargs=0 _shtab_ahriman_package_update___now_nargs=0
_shtab_ahriman_package_update__y_nargs=0 _shtab_ahriman_package_update__y_nargs=0
_shtab_ahriman_package_update___refresh_nargs=0 _shtab_ahriman_package_update___refresh_nargs=0
_shtab_ahriman_package_changes__h_nargs=0
_shtab_ahriman_package_changes___help_nargs=0
_shtab_ahriman_package_changes__e_nargs=0
_shtab_ahriman_package_changes___exit_code_nargs=0
_shtab_ahriman_package_changes_remove__h_nargs=0
_shtab_ahriman_package_changes_remove___help_nargs=0
_shtab_ahriman_package_remove_pos_0_nargs=+
_shtab_ahriman_package_remove__h_nargs=0
_shtab_ahriman_package_remove___help_nargs=0
_shtab_ahriman_remove_pos_0_nargs=+
_shtab_ahriman_remove__h_nargs=0
_shtab_ahriman_remove___help_nargs=0
_shtab_ahriman_package_status_pos_0_nargs=*
_shtab_ahriman_package_status__h_nargs=0
_shtab_ahriman_package_status___help_nargs=0
_shtab_ahriman_package_status___ahriman_nargs=0
_shtab_ahriman_package_status__e_nargs=0
_shtab_ahriman_package_status___exit_code_nargs=0
_shtab_ahriman_package_status___info_nargs=0
_shtab_ahriman_package_status___no_info_nargs=0
_shtab_ahriman_status_pos_0_nargs=*
_shtab_ahriman_status__h_nargs=0
_shtab_ahriman_status___help_nargs=0
_shtab_ahriman_status___ahriman_nargs=0
_shtab_ahriman_status__e_nargs=0
_shtab_ahriman_status___exit_code_nargs=0
_shtab_ahriman_status___info_nargs=0
_shtab_ahriman_status___no_info_nargs=0
_shtab_ahriman_package_status_remove_pos_0_nargs=+
_shtab_ahriman_package_status_remove__h_nargs=0
_shtab_ahriman_package_status_remove___help_nargs=0
_shtab_ahriman_package_status_update_pos_0_nargs=*
_shtab_ahriman_package_status_update__h_nargs=0
_shtab_ahriman_package_status_update___help_nargs=0
_shtab_ahriman_status_update_pos_0_nargs=*
_shtab_ahriman_status_update__h_nargs=0
_shtab_ahriman_status_update___help_nargs=0
_shtab_ahriman_patch_add__h_nargs=0 _shtab_ahriman_patch_add__h_nargs=0
_shtab_ahriman_patch_add___help_nargs=0 _shtab_ahriman_patch_add___help_nargs=0
_shtab_ahriman_patch_list__h_nargs=0 _shtab_ahriman_patch_list__h_nargs=0
@ -245,6 +304,20 @@ _shtab_ahriman_patch_remove__h_nargs=0
_shtab_ahriman_patch_remove___help_nargs=0 _shtab_ahriman_patch_remove___help_nargs=0
_shtab_ahriman_patch_set_add__h_nargs=0 _shtab_ahriman_patch_set_add__h_nargs=0
_shtab_ahriman_patch_set_add___help_nargs=0 _shtab_ahriman_patch_set_add___help_nargs=0
_shtab_ahriman_rebuild__h_nargs=0
_shtab_ahriman_rebuild___help_nargs=0
_shtab_ahriman_rebuild___dry_run_nargs=0
_shtab_ahriman_rebuild___from_database_nargs=0
_shtab_ahriman_rebuild___increment_nargs=0
_shtab_ahriman_rebuild___no_increment_nargs=0
_shtab_ahriman_rebuild__e_nargs=0
_shtab_ahriman_rebuild___exit_code_nargs=0
_shtab_ahriman_remove_pos_0_nargs=+
_shtab_ahriman_remove__h_nargs=0
_shtab_ahriman_remove___help_nargs=0
_shtab_ahriman_remove_unknown__h_nargs=0
_shtab_ahriman_remove_unknown___help_nargs=0
_shtab_ahriman_remove_unknown___dry_run_nargs=0
_shtab_ahriman_repo_backup__h_nargs=0 _shtab_ahriman_repo_backup__h_nargs=0
_shtab_ahriman_repo_backup___help_nargs=0 _shtab_ahriman_repo_backup___help_nargs=0
_shtab_ahriman_repo_check_pos_0_nargs=* _shtab_ahriman_repo_check_pos_0_nargs=*
@ -260,19 +333,28 @@ _shtab_ahriman_repo_check___vcs_nargs=0
_shtab_ahriman_repo_check___no_vcs_nargs=0 _shtab_ahriman_repo_check___no_vcs_nargs=0
_shtab_ahriman_repo_check__y_nargs=0 _shtab_ahriman_repo_check__y_nargs=0
_shtab_ahriman_repo_check___refresh_nargs=0 _shtab_ahriman_repo_check___refresh_nargs=0
_shtab_ahriman_check_pos_0_nargs=* _shtab_ahriman_repo_clean__h_nargs=0
_shtab_ahriman_check__h_nargs=0 _shtab_ahriman_repo_clean___help_nargs=0
_shtab_ahriman_check___help_nargs=0 _shtab_ahriman_repo_clean___cache_nargs=0
_shtab_ahriman_check___changes_nargs=0 _shtab_ahriman_repo_clean___no_cache_nargs=0
_shtab_ahriman_check___no_changes_nargs=0 _shtab_ahriman_repo_clean___chroot_nargs=0
_shtab_ahriman_check___check_files_nargs=0 _shtab_ahriman_repo_clean___no_chroot_nargs=0
_shtab_ahriman_check___no_check_files_nargs=0 _shtab_ahriman_repo_clean___manual_nargs=0
_shtab_ahriman_check__e_nargs=0 _shtab_ahriman_repo_clean___no_manual_nargs=0
_shtab_ahriman_check___exit_code_nargs=0 _shtab_ahriman_repo_clean___packages_nargs=0
_shtab_ahriman_check___vcs_nargs=0 _shtab_ahriman_repo_clean___no_packages_nargs=0
_shtab_ahriman_check___no_vcs_nargs=0 _shtab_ahriman_repo_clean___pacman_nargs=0
_shtab_ahriman_check__y_nargs=0 _shtab_ahriman_repo_clean___no_pacman_nargs=0
_shtab_ahriman_check___refresh_nargs=0 _shtab_ahriman_repo_config__h_nargs=0
_shtab_ahriman_repo_config___help_nargs=0
_shtab_ahriman_repo_config___info_nargs=0
_shtab_ahriman_repo_config___no_info_nargs=0
_shtab_ahriman_repo_config___secure_nargs=0
_shtab_ahriman_repo_config___no_secure_nargs=0
_shtab_ahriman_repo_config_validate__h_nargs=0
_shtab_ahriman_repo_config_validate___help_nargs=0
_shtab_ahriman_repo_config_validate__e_nargs=0
_shtab_ahriman_repo_config_validate___exit_code_nargs=0
_shtab_ahriman_repo_create_keyring__h_nargs=0 _shtab_ahriman_repo_create_keyring__h_nargs=0
_shtab_ahriman_repo_create_keyring___help_nargs=0 _shtab_ahriman_repo_create_keyring___help_nargs=0
_shtab_ahriman_repo_create_mirrorlist__h_nargs=0 _shtab_ahriman_repo_create_mirrorlist__h_nargs=0
@ -300,29 +382,14 @@ _shtab_ahriman_repo_daemon___vcs_nargs=0
_shtab_ahriman_repo_daemon___no_vcs_nargs=0 _shtab_ahriman_repo_daemon___no_vcs_nargs=0
_shtab_ahriman_repo_daemon__y_nargs=0 _shtab_ahriman_repo_daemon__y_nargs=0
_shtab_ahriman_repo_daemon___refresh_nargs=0 _shtab_ahriman_repo_daemon___refresh_nargs=0
_shtab_ahriman_daemon__h_nargs=0 _shtab_ahriman_repo_init__h_nargs=0
_shtab_ahriman_daemon___help_nargs=0 _shtab_ahriman_repo_init___help_nargs=0
_shtab_ahriman_daemon___aur_nargs=0 _shtab_ahriman_repo_init___generate_salt_nargs=0
_shtab_ahriman_daemon___no_aur_nargs=0 _shtab_ahriman_repo_init___no_generate_salt_nargs=0
_shtab_ahriman_daemon___changes_nargs=0 _shtab_ahriman_repo_init___makeflags_jobs_nargs=0
_shtab_ahriman_daemon___no_changes_nargs=0 _shtab_ahriman_repo_init___no_makeflags_jobs_nargs=0
_shtab_ahriman_daemon___check_files_nargs=0 _shtab_ahriman_repo_init___multilib_nargs=0
_shtab_ahriman_daemon___no_check_files_nargs=0 _shtab_ahriman_repo_init___no_multilib_nargs=0
_shtab_ahriman_daemon___dependencies_nargs=0
_shtab_ahriman_daemon___no_dependencies_nargs=0
_shtab_ahriman_daemon___dry_run_nargs=0
_shtab_ahriman_daemon___increment_nargs=0
_shtab_ahriman_daemon___no_increment_nargs=0
_shtab_ahriman_daemon___local_nargs=0
_shtab_ahriman_daemon___no_local_nargs=0
_shtab_ahriman_daemon___manual_nargs=0
_shtab_ahriman_daemon___no_manual_nargs=0
_shtab_ahriman_daemon___partitions_nargs=0
_shtab_ahriman_daemon___no_partitions_nargs=0
_shtab_ahriman_daemon___vcs_nargs=0
_shtab_ahriman_daemon___no_vcs_nargs=0
_shtab_ahriman_daemon__y_nargs=0
_shtab_ahriman_daemon___refresh_nargs=0
_shtab_ahriman_repo_rebuild__h_nargs=0 _shtab_ahriman_repo_rebuild__h_nargs=0
_shtab_ahriman_repo_rebuild___help_nargs=0 _shtab_ahriman_repo_rebuild___help_nargs=0
_shtab_ahriman_repo_rebuild___dry_run_nargs=0 _shtab_ahriman_repo_rebuild___dry_run_nargs=0
@ -331,40 +398,30 @@ _shtab_ahriman_repo_rebuild___increment_nargs=0
_shtab_ahriman_repo_rebuild___no_increment_nargs=0 _shtab_ahriman_repo_rebuild___no_increment_nargs=0
_shtab_ahriman_repo_rebuild__e_nargs=0 _shtab_ahriman_repo_rebuild__e_nargs=0
_shtab_ahriman_repo_rebuild___exit_code_nargs=0 _shtab_ahriman_repo_rebuild___exit_code_nargs=0
_shtab_ahriman_rebuild__h_nargs=0
_shtab_ahriman_rebuild___help_nargs=0
_shtab_ahriman_rebuild___dry_run_nargs=0
_shtab_ahriman_rebuild___from_database_nargs=0
_shtab_ahriman_rebuild___increment_nargs=0
_shtab_ahriman_rebuild___no_increment_nargs=0
_shtab_ahriman_rebuild__e_nargs=0
_shtab_ahriman_rebuild___exit_code_nargs=0
_shtab_ahriman_repo_remove_unknown__h_nargs=0 _shtab_ahriman_repo_remove_unknown__h_nargs=0
_shtab_ahriman_repo_remove_unknown___help_nargs=0 _shtab_ahriman_repo_remove_unknown___help_nargs=0
_shtab_ahriman_repo_remove_unknown___dry_run_nargs=0 _shtab_ahriman_repo_remove_unknown___dry_run_nargs=0
_shtab_ahriman_remove_unknown__h_nargs=0
_shtab_ahriman_remove_unknown___help_nargs=0
_shtab_ahriman_remove_unknown___dry_run_nargs=0
_shtab_ahriman_repo_report__h_nargs=0 _shtab_ahriman_repo_report__h_nargs=0
_shtab_ahriman_repo_report___help_nargs=0 _shtab_ahriman_repo_report___help_nargs=0
_shtab_ahriman_report__h_nargs=0
_shtab_ahriman_report___help_nargs=0
_shtab_ahriman_repo_restore__h_nargs=0 _shtab_ahriman_repo_restore__h_nargs=0
_shtab_ahriman_repo_restore___help_nargs=0 _shtab_ahriman_repo_restore___help_nargs=0
_shtab_ahriman_repo_setup__h_nargs=0
_shtab_ahriman_repo_setup___help_nargs=0
_shtab_ahriman_repo_setup___generate_salt_nargs=0
_shtab_ahriman_repo_setup___no_generate_salt_nargs=0
_shtab_ahriman_repo_setup___makeflags_jobs_nargs=0
_shtab_ahriman_repo_setup___no_makeflags_jobs_nargs=0
_shtab_ahriman_repo_setup___multilib_nargs=0
_shtab_ahriman_repo_setup___no_multilib_nargs=0
_shtab_ahriman_repo_sign_pos_0_nargs=* _shtab_ahriman_repo_sign_pos_0_nargs=*
_shtab_ahriman_repo_sign__h_nargs=0 _shtab_ahriman_repo_sign__h_nargs=0
_shtab_ahriman_repo_sign___help_nargs=0 _shtab_ahriman_repo_sign___help_nargs=0
_shtab_ahriman_sign_pos_0_nargs=*
_shtab_ahriman_sign__h_nargs=0
_shtab_ahriman_sign___help_nargs=0
_shtab_ahriman_repo_statistics__h_nargs=0 _shtab_ahriman_repo_statistics__h_nargs=0
_shtab_ahriman_repo_statistics___help_nargs=0 _shtab_ahriman_repo_statistics___help_nargs=0
_shtab_ahriman_repo_status_update__h_nargs=0 _shtab_ahriman_repo_status_update__h_nargs=0
_shtab_ahriman_repo_status_update___help_nargs=0 _shtab_ahriman_repo_status_update___help_nargs=0
_shtab_ahriman_repo_sync__h_nargs=0 _shtab_ahriman_repo_sync__h_nargs=0
_shtab_ahriman_repo_sync___help_nargs=0 _shtab_ahriman_repo_sync___help_nargs=0
_shtab_ahriman_sync__h_nargs=0
_shtab_ahriman_sync___help_nargs=0
_shtab_ahriman_repo_tree__h_nargs=0 _shtab_ahriman_repo_tree__h_nargs=0
_shtab_ahriman_repo_tree___help_nargs=0 _shtab_ahriman_repo_tree___help_nargs=0
_shtab_ahriman_repo_triggers_pos_0_nargs=* _shtab_ahriman_repo_triggers_pos_0_nargs=*
@ -394,6 +451,91 @@ _shtab_ahriman_repo_update___vcs_nargs=0
_shtab_ahriman_repo_update___no_vcs_nargs=0 _shtab_ahriman_repo_update___no_vcs_nargs=0
_shtab_ahriman_repo_update__y_nargs=0 _shtab_ahriman_repo_update__y_nargs=0
_shtab_ahriman_repo_update___refresh_nargs=0 _shtab_ahriman_repo_update___refresh_nargs=0
_shtab_ahriman_report__h_nargs=0
_shtab_ahriman_report___help_nargs=0
_shtab_ahriman_run_pos_0_nargs=+
_shtab_ahriman_run__h_nargs=0
_shtab_ahriman_run___help_nargs=0
_shtab_ahriman_search_pos_0_nargs=+
_shtab_ahriman_search__h_nargs=0
_shtab_ahriman_search___help_nargs=0
_shtab_ahriman_search__e_nargs=0
_shtab_ahriman_search___exit_code_nargs=0
_shtab_ahriman_search___info_nargs=0
_shtab_ahriman_search___no_info_nargs=0
_shtab_ahriman_service_clean__h_nargs=0
_shtab_ahriman_service_clean___help_nargs=0
_shtab_ahriman_service_clean___cache_nargs=0
_shtab_ahriman_service_clean___no_cache_nargs=0
_shtab_ahriman_service_clean___chroot_nargs=0
_shtab_ahriman_service_clean___no_chroot_nargs=0
_shtab_ahriman_service_clean___manual_nargs=0
_shtab_ahriman_service_clean___no_manual_nargs=0
_shtab_ahriman_service_clean___packages_nargs=0
_shtab_ahriman_service_clean___no_packages_nargs=0
_shtab_ahriman_service_clean___pacman_nargs=0
_shtab_ahriman_service_clean___no_pacman_nargs=0
_shtab_ahriman_service_config__h_nargs=0
_shtab_ahriman_service_config___help_nargs=0
_shtab_ahriman_service_config___info_nargs=0
_shtab_ahriman_service_config___no_info_nargs=0
_shtab_ahriman_service_config___secure_nargs=0
_shtab_ahriman_service_config___no_secure_nargs=0
_shtab_ahriman_service_config_validate__h_nargs=0
_shtab_ahriman_service_config_validate___help_nargs=0
_shtab_ahriman_service_config_validate__e_nargs=0
_shtab_ahriman_service_config_validate___exit_code_nargs=0
_shtab_ahriman_service_key_import__h_nargs=0
_shtab_ahriman_service_key_import___help_nargs=0
_shtab_ahriman_service_repositories__h_nargs=0
_shtab_ahriman_service_repositories___help_nargs=0
_shtab_ahriman_service_repositories___id_only_nargs=0
_shtab_ahriman_service_repositories___no_id_only_nargs=0
_shtab_ahriman_service_run_pos_0_nargs=+
_shtab_ahriman_service_run__h_nargs=0
_shtab_ahriman_service_run___help_nargs=0
_shtab_ahriman_service_setup__h_nargs=0
_shtab_ahriman_service_setup___help_nargs=0
_shtab_ahriman_service_setup___generate_salt_nargs=0
_shtab_ahriman_service_setup___no_generate_salt_nargs=0
_shtab_ahriman_service_setup___makeflags_jobs_nargs=0
_shtab_ahriman_service_setup___no_makeflags_jobs_nargs=0
_shtab_ahriman_service_setup___multilib_nargs=0
_shtab_ahriman_service_setup___no_multilib_nargs=0
_shtab_ahriman_service_shell__h_nargs=0
_shtab_ahriman_service_shell___help_nargs=0
_shtab_ahriman_service_shell__v_nargs=0
_shtab_ahriman_service_shell___verbose_nargs=0
_shtab_ahriman_service_tree_migrate__h_nargs=0
_shtab_ahriman_service_tree_migrate___help_nargs=0
_shtab_ahriman_setup__h_nargs=0
_shtab_ahriman_setup___help_nargs=0
_shtab_ahriman_setup___generate_salt_nargs=0
_shtab_ahriman_setup___no_generate_salt_nargs=0
_shtab_ahriman_setup___makeflags_jobs_nargs=0
_shtab_ahriman_setup___no_makeflags_jobs_nargs=0
_shtab_ahriman_setup___multilib_nargs=0
_shtab_ahriman_setup___no_multilib_nargs=0
_shtab_ahriman_shell__h_nargs=0
_shtab_ahriman_shell___help_nargs=0
_shtab_ahriman_shell__v_nargs=0
_shtab_ahriman_shell___verbose_nargs=0
_shtab_ahriman_sign_pos_0_nargs=*
_shtab_ahriman_sign__h_nargs=0
_shtab_ahriman_sign___help_nargs=0
_shtab_ahriman_status_pos_0_nargs=*
_shtab_ahriman_status__h_nargs=0
_shtab_ahriman_status___help_nargs=0
_shtab_ahriman_status___ahriman_nargs=0
_shtab_ahriman_status__e_nargs=0
_shtab_ahriman_status___exit_code_nargs=0
_shtab_ahriman_status___info_nargs=0
_shtab_ahriman_status___no_info_nargs=0
_shtab_ahriman_status_update_pos_0_nargs=*
_shtab_ahriman_status_update__h_nargs=0
_shtab_ahriman_status_update___help_nargs=0
_shtab_ahriman_sync__h_nargs=0
_shtab_ahriman_sync___help_nargs=0
_shtab_ahriman_update_pos_0_nargs=* _shtab_ahriman_update_pos_0_nargs=*
_shtab_ahriman_update__h_nargs=0 _shtab_ahriman_update__h_nargs=0
_shtab_ahriman_update___help_nargs=0 _shtab_ahriman_update___help_nargs=0
@ -418,136 +560,6 @@ _shtab_ahriman_update___vcs_nargs=0
_shtab_ahriman_update___no_vcs_nargs=0 _shtab_ahriman_update___no_vcs_nargs=0
_shtab_ahriman_update__y_nargs=0 _shtab_ahriman_update__y_nargs=0
_shtab_ahriman_update___refresh_nargs=0 _shtab_ahriman_update___refresh_nargs=0
_shtab_ahriman_service_clean__h_nargs=0
_shtab_ahriman_service_clean___help_nargs=0
_shtab_ahriman_service_clean___cache_nargs=0
_shtab_ahriman_service_clean___no_cache_nargs=0
_shtab_ahriman_service_clean___chroot_nargs=0
_shtab_ahriman_service_clean___no_chroot_nargs=0
_shtab_ahriman_service_clean___manual_nargs=0
_shtab_ahriman_service_clean___no_manual_nargs=0
_shtab_ahriman_service_clean___packages_nargs=0
_shtab_ahriman_service_clean___no_packages_nargs=0
_shtab_ahriman_service_clean___pacman_nargs=0
_shtab_ahriman_service_clean___no_pacman_nargs=0
_shtab_ahriman_clean__h_nargs=0
_shtab_ahriman_clean___help_nargs=0
_shtab_ahriman_clean___cache_nargs=0
_shtab_ahriman_clean___no_cache_nargs=0
_shtab_ahriman_clean___chroot_nargs=0
_shtab_ahriman_clean___no_chroot_nargs=0
_shtab_ahriman_clean___manual_nargs=0
_shtab_ahriman_clean___no_manual_nargs=0
_shtab_ahriman_clean___packages_nargs=0
_shtab_ahriman_clean___no_packages_nargs=0
_shtab_ahriman_clean___pacman_nargs=0
_shtab_ahriman_clean___no_pacman_nargs=0
_shtab_ahriman_repo_clean__h_nargs=0
_shtab_ahriman_repo_clean___help_nargs=0
_shtab_ahriman_repo_clean___cache_nargs=0
_shtab_ahriman_repo_clean___no_cache_nargs=0
_shtab_ahriman_repo_clean___chroot_nargs=0
_shtab_ahriman_repo_clean___no_chroot_nargs=0
_shtab_ahriman_repo_clean___manual_nargs=0
_shtab_ahriman_repo_clean___no_manual_nargs=0
_shtab_ahriman_repo_clean___packages_nargs=0
_shtab_ahriman_repo_clean___no_packages_nargs=0
_shtab_ahriman_repo_clean___pacman_nargs=0
_shtab_ahriman_repo_clean___no_pacman_nargs=0
_shtab_ahriman_service_config__h_nargs=0
_shtab_ahriman_service_config___help_nargs=0
_shtab_ahriman_service_config___info_nargs=0
_shtab_ahriman_service_config___no_info_nargs=0
_shtab_ahriman_service_config___secure_nargs=0
_shtab_ahriman_service_config___no_secure_nargs=0
_shtab_ahriman_config__h_nargs=0
_shtab_ahriman_config___help_nargs=0
_shtab_ahriman_config___info_nargs=0
_shtab_ahriman_config___no_info_nargs=0
_shtab_ahriman_config___secure_nargs=0
_shtab_ahriman_config___no_secure_nargs=0
_shtab_ahriman_repo_config__h_nargs=0
_shtab_ahriman_repo_config___help_nargs=0
_shtab_ahriman_repo_config___info_nargs=0
_shtab_ahriman_repo_config___no_info_nargs=0
_shtab_ahriman_repo_config___secure_nargs=0
_shtab_ahriman_repo_config___no_secure_nargs=0
_shtab_ahriman_service_config_validate__h_nargs=0
_shtab_ahriman_service_config_validate___help_nargs=0
_shtab_ahriman_service_config_validate__e_nargs=0
_shtab_ahriman_service_config_validate___exit_code_nargs=0
_shtab_ahriman_config_validate__h_nargs=0
_shtab_ahriman_config_validate___help_nargs=0
_shtab_ahriman_config_validate__e_nargs=0
_shtab_ahriman_config_validate___exit_code_nargs=0
_shtab_ahriman_repo_config_validate__h_nargs=0
_shtab_ahriman_repo_config_validate___help_nargs=0
_shtab_ahriman_repo_config_validate__e_nargs=0
_shtab_ahriman_repo_config_validate___exit_code_nargs=0
_shtab_ahriman_service_key_import__h_nargs=0
_shtab_ahriman_service_key_import___help_nargs=0
_shtab_ahriman_key_import__h_nargs=0
_shtab_ahriman_key_import___help_nargs=0
_shtab_ahriman_service_repositories__h_nargs=0
_shtab_ahriman_service_repositories___help_nargs=0
_shtab_ahriman_service_repositories___id_only_nargs=0
_shtab_ahriman_service_repositories___no_id_only_nargs=0
_shtab_ahriman_service_run_pos_0_nargs=+
_shtab_ahriman_service_run__h_nargs=0
_shtab_ahriman_service_run___help_nargs=0
_shtab_ahriman_run_pos_0_nargs=+
_shtab_ahriman_run__h_nargs=0
_shtab_ahriman_run___help_nargs=0
_shtab_ahriman_service_setup__h_nargs=0
_shtab_ahriman_service_setup___help_nargs=0
_shtab_ahriman_service_setup___generate_salt_nargs=0
_shtab_ahriman_service_setup___no_generate_salt_nargs=0
_shtab_ahriman_service_setup___makeflags_jobs_nargs=0
_shtab_ahriman_service_setup___no_makeflags_jobs_nargs=0
_shtab_ahriman_service_setup___multilib_nargs=0
_shtab_ahriman_service_setup___no_multilib_nargs=0
_shtab_ahriman_init__h_nargs=0
_shtab_ahriman_init___help_nargs=0
_shtab_ahriman_init___generate_salt_nargs=0
_shtab_ahriman_init___no_generate_salt_nargs=0
_shtab_ahriman_init___makeflags_jobs_nargs=0
_shtab_ahriman_init___no_makeflags_jobs_nargs=0
_shtab_ahriman_init___multilib_nargs=0
_shtab_ahriman_init___no_multilib_nargs=0
_shtab_ahriman_repo_init__h_nargs=0
_shtab_ahriman_repo_init___help_nargs=0
_shtab_ahriman_repo_init___generate_salt_nargs=0
_shtab_ahriman_repo_init___no_generate_salt_nargs=0
_shtab_ahriman_repo_init___makeflags_jobs_nargs=0
_shtab_ahriman_repo_init___no_makeflags_jobs_nargs=0
_shtab_ahriman_repo_init___multilib_nargs=0
_shtab_ahriman_repo_init___no_multilib_nargs=0
_shtab_ahriman_repo_setup__h_nargs=0
_shtab_ahriman_repo_setup___help_nargs=0
_shtab_ahriman_repo_setup___generate_salt_nargs=0
_shtab_ahriman_repo_setup___no_generate_salt_nargs=0
_shtab_ahriman_repo_setup___makeflags_jobs_nargs=0
_shtab_ahriman_repo_setup___no_makeflags_jobs_nargs=0
_shtab_ahriman_repo_setup___multilib_nargs=0
_shtab_ahriman_repo_setup___no_multilib_nargs=0
_shtab_ahriman_setup__h_nargs=0
_shtab_ahriman_setup___help_nargs=0
_shtab_ahriman_setup___generate_salt_nargs=0
_shtab_ahriman_setup___no_generate_salt_nargs=0
_shtab_ahriman_setup___makeflags_jobs_nargs=0
_shtab_ahriman_setup___no_makeflags_jobs_nargs=0
_shtab_ahriman_setup___multilib_nargs=0
_shtab_ahriman_setup___no_multilib_nargs=0
_shtab_ahriman_service_shell__h_nargs=0
_shtab_ahriman_service_shell___help_nargs=0
_shtab_ahriman_service_shell__v_nargs=0
_shtab_ahriman_service_shell___verbose_nargs=0
_shtab_ahriman_shell__h_nargs=0
_shtab_ahriman_shell___help_nargs=0
_shtab_ahriman_shell__v_nargs=0
_shtab_ahriman_shell___verbose_nargs=0
_shtab_ahriman_service_tree_migrate__h_nargs=0
_shtab_ahriman_service_tree_migrate___help_nargs=0
_shtab_ahriman_user_add__h_nargs=0 _shtab_ahriman_user_add__h_nargs=0
_shtab_ahriman_user_add___help_nargs=0 _shtab_ahriman_user_add___help_nargs=0
_shtab_ahriman_user_list__h_nargs=0 _shtab_ahriman_user_list__h_nargs=0
@ -556,6 +568,8 @@ _shtab_ahriman_user_list__e_nargs=0
_shtab_ahriman_user_list___exit_code_nargs=0 _shtab_ahriman_user_list___exit_code_nargs=0
_shtab_ahriman_user_remove__h_nargs=0 _shtab_ahriman_user_remove__h_nargs=0
_shtab_ahriman_user_remove___help_nargs=0 _shtab_ahriman_user_remove___help_nargs=0
_shtab_ahriman_version__h_nargs=0
_shtab_ahriman_version___help_nargs=0
_shtab_ahriman_web__h_nargs=0 _shtab_ahriman_web__h_nargs=0
_shtab_ahriman_web___help_nargs=0 _shtab_ahriman_web___help_nargs=0
@ -621,6 +635,7 @@ _set_new_action() {
# ${!x} -> ${hello} -> "world" # ${!x} -> ${hello} -> "world"
_shtab_ahriman() { _shtab_ahriman() {
local completing_word="${COMP_WORDS[COMP_CWORD]}" local completing_word="${COMP_WORDS[COMP_CWORD]}"
local previous_word="${COMP_WORDS[COMP_CWORD-1]}"
local completed_positional_actions local completed_positional_actions
local current_action local current_action
local current_action_args_start_index local current_action_args_start_index
@ -677,6 +692,10 @@ _shtab_ahriman() {
if [[ $pos_only = 0 && "${completing_word}" == -* ]]; then if [[ $pos_only = 0 && "${completing_word}" == -* ]]; then
# optional argument started: use option strings # optional argument started: use option strings
COMPREPLY=( $(compgen -W "${current_option_strings[*]}" -- "${completing_word}") ) COMPREPLY=( $(compgen -W "${current_option_strings[*]}" -- "${completing_word}") )
elif [[ "${previous_word}" == ">" || "${previous_word}" == ">>" ||
"${previous_word}" =~ ^[12]">" || "${previous_word}" =~ ^[12]">>" ]]; then
# handle redirection operators
COMPREPLY=( $(compgen -f -- "${completing_word}") )
else else
# use choices & compgen # use choices & compgen
local IFS=$'\n' # items may contain spaces, so delimit using newline local IFS=$'\n' # items may contain spaces, so delimit using newline

View File

@ -1,9 +1,9 @@
.TH AHRIMAN "1" "2024\-09\-26" "ahriman" "Generated Python Manual" .TH AHRIMAN "1" "2025\-06\-16" "ahriman" "Generated Python Manual"
.SH NAME .SH NAME
ahriman ahriman
.SH SYNOPSIS .SH SYNOPSIS
.B ahriman .B ahriman
[-h] [-a ARCHITECTURE] [-c CONFIGURATION] [--force] [-l LOCK] [--log-handler {console,syslog,journald}] [-q] [--report | --no-report] [-r REPOSITORY] [--unsafe] [-V] [--wait-timeout WAIT_TIMEOUT] {aur-search,search,help-commands-unsafe,help,help-updates,help-version,version,package-add,add,package-update,package-changes,package-changes-remove,package-remove,remove,package-status,status,package-status-remove,package-status-update,status-update,patch-add,patch-list,patch-remove,patch-set-add,repo-backup,repo-check,check,repo-create-keyring,repo-create-mirrorlist,repo-daemon,daemon,repo-rebuild,rebuild,repo-remove-unknown,remove-unknown,repo-report,report,repo-restore,repo-sign,sign,repo-statistics,repo-status-update,repo-sync,sync,repo-tree,repo-triggers,repo-update,update,service-clean,clean,repo-clean,service-config,config,repo-config,service-config-validate,config-validate,repo-config-validate,service-key-import,key-import,service-repositories,service-run,run,service-setup,init,repo-init,repo-setup,setup,service-shell,shell,service-tree-migrate,user-add,user-list,user-remove,web} ... [-h] [-a ARCHITECTURE] [-c CONFIGURATION] [--force] [-l LOCK] [--log-handler {console,syslog,journald}] [-q] [--report | --no-report] [-r REPOSITORY] [--unsafe] [-V] [--wait-timeout WAIT_TIMEOUT] {add,aur-search,check,clean,config,config-validate,copy,daemon,help,help-commands-unsafe,help-updates,help-version,init,key-import,package-add,package-changes,package-changes-remove,package-copy,package-remove,package-status,package-status-remove,package-status-update,package-update,patch-add,patch-list,patch-remove,patch-set-add,rebuild,remove,remove-unknown,repo-backup,repo-check,repo-clean,repo-config,repo-config-validate,repo-create-keyring,repo-create-mirrorlist,repo-daemon,repo-init,repo-rebuild,repo-remove-unknown,repo-report,repo-restore,repo-setup,repo-sign,repo-statistics,repo-status-update,repo-sync,repo-tree,repo-triggers,repo-update,report,run,search,service-clean,service-config,service-config-validate,service-key-import,service-repositories,service-run,service-setup,service-shell,service-tree-migrate,setup,shell,sign,status,status-update,sync,update,user-add,user-list,user-remove,version,web} ...
.SH DESCRIPTION .SH DESCRIPTION
ArcH linux ReposItory MANager ArcH linux ReposItory MANager
@ -59,12 +59,12 @@ COMMAND
\fBahriman\fR \fI\,aur\-search\/\fR \fBahriman\fR \fI\,aur\-search\/\fR
search for package search for package
.TP .TP
\fBahriman\fR \fI\,help\-commands\-unsafe\/\fR
list unsafe commands
.TP
\fBahriman\fR \fI\,help\/\fR \fBahriman\fR \fI\,help\/\fR
show help message show help message
.TP .TP
\fBahriman\fR \fI\,help\-commands\-unsafe\/\fR
list unsafe commands
.TP
\fBahriman\fR \fI\,help\-updates\/\fR \fBahriman\fR \fI\,help\-updates\/\fR
check for service updates check for service updates
.TP .TP
@ -80,6 +80,9 @@ get package changes
\fBahriman\fR \fI\,package\-changes\-remove\/\fR \fBahriman\fR \fI\,package\-changes\-remove\/\fR
remove package changes remove package changes
.TP .TP
\fBahriman\fR \fI\,package\-copy\/\fR
copy package from another repository
.TP
\fBahriman\fR \fI\,package\-remove\/\fR \fBahriman\fR \fI\,package\-remove\/\fR
remove package remove package
.TP .TP
@ -216,6 +219,15 @@ show additional package information
sort field by this field. In case if two packages have the same value of the specified field, they will be always sorted sort field by this field. In case if two packages have the same value of the specified field, they will be always sorted
by name by name
.SH COMMAND \fI\,'ahriman help'\/\fR
usage: ahriman help [\-h] [subcommand]
show help message for application or command and exit
.TP
\fBsubcommand\fR
show help message for specific command
.SH COMMAND \fI\,'ahriman help\-commands\-unsafe'\/\fR .SH COMMAND \fI\,'ahriman help\-commands\-unsafe'\/\fR
usage: ahriman help\-commands\-unsafe [\-h] [subcommand ...] usage: ahriman help\-commands\-unsafe [\-h] [subcommand ...]
@ -226,15 +238,6 @@ list unsafe commands as defined in default args
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
.SH COMMAND \fI\,'ahriman help'\/\fR
usage: ahriman help [\-h] [subcommand]
show help message for application or command and exit
.TP
\fBsubcommand\fR
show help message for specific command
.SH COMMAND \fI\,'ahriman help\-updates'\/\fR .SH COMMAND \fI\,'ahriman help\-updates'\/\fR
usage: ahriman help\-updates [\-h] [\-e] usage: ahriman help\-updates [\-h] [\-e]
@ -322,6 +325,28 @@ remove the package changes stored remotely
\fBpackage\fR \fBpackage\fR
package base package base
.SH COMMAND \fI\,'ahriman package\-copy'\/\fR
usage: ahriman package\-copy [\-h] [\-e] [\-\-remove] source package [package ...]
copy package and its metadata from another repository
.TP
\fBsource\fR
source repository name
.TP
\fBpackage\fR
package base
.SH OPTIONS \fI\,'ahriman package\-copy'\/\fR
.TP
\fB\-e\fR, \fB\-\-exit\-code\fR
return non\-zero exit status if result is empty
.TP
\fB\-\-remove\fR
remove package from the source repository after
.SH COMMAND \fI\,'ahriman package\-remove'\/\fR .SH COMMAND \fI\,'ahriman package\-remove'\/\fR
usage: ahriman package\-remove [\-h] package [package ...] usage: ahriman package\-remove [\-h] package [package ...]
@ -915,7 +940,7 @@ port of the web service
path to unix socket used for interprocess communications path to unix socket used for interprocess communications
.SH COMMAND \fI\,'ahriman service\-shell'\/\fR .SH COMMAND \fI\,'ahriman service\-shell'\/\fR
usage: ahriman service\-shell [\-h] [code] usage: ahriman service\-shell [\-h] [\-o OUTPUT] [code]
drop into python shell drop into python shell
@ -923,6 +948,11 @@ drop into python shell
\fBcode\fR \fBcode\fR
instead of dropping into shell, just execute the specified code instead of dropping into shell, just execute the specified code
.SH OPTIONS \fI\,'ahriman service\-shell'\/\fR
.TP
\fB\-o\fR \fI\,OUTPUT\/\fR, \fB\-\-output\fR \fI\,OUTPUT\/\fR
output commands and result to the file
.SH COMMAND \fI\,'ahriman service\-tree\-migrate'\/\fR .SH COMMAND \fI\,'ahriman service\-tree\-migrate'\/\fR
usage: ahriman service\-tree\-migrate [\-h] usage: ahriman service\-tree\-migrate [\-h]

View File

@ -11,6 +11,7 @@ _shtab_ahriman_commands() {
"clean:remove local caches" "clean:remove local caches"
"config:dump configuration for the specified architecture" "config:dump configuration for the specified architecture"
"config-validate:validate configuration and print found errors" "config-validate:validate configuration and print found errors"
"copy:copy package and its metadata from another repository"
"daemon:start process which periodically will run update process" "daemon:start process which periodically will run update process"
"help:show help message for application or command and exit" "help:show help message for application or command and exit"
"help-commands-unsafe:list unsafe commands as defined in default args" "help-commands-unsafe:list unsafe commands as defined in default args"
@ -21,6 +22,7 @@ _shtab_ahriman_commands() {
"package-add:add existing or new package to the build queue" "package-add:add existing or new package to the build queue"
"package-changes:retrieve package changes stored in database" "package-changes:retrieve package changes stored in database"
"package-changes-remove:remove the package changes stored remotely" "package-changes-remove:remove the package changes stored remotely"
"package-copy:copy package and its metadata from another repository"
"package-remove:remove package from the repository" "package-remove:remove package from the repository"
"package-status:request status of the package" "package-status:request status of the package"
"package-status-remove:remove the package from the status page" "package-status-remove:remove the package from the status page"
@ -151,6 +153,14 @@ _shtab_ahriman_config_validate_options=(
{-e,--exit-code}"[return non-zero exit status if configuration is invalid (default\: False)]" {-e,--exit-code}"[return non-zero exit status if configuration is invalid (default\: False)]"
) )
_shtab_ahriman_copy_options=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
"--remove[remove package from the source repository after (default\: False)]"
":source repository name:"
"(*):package base:"
)
_shtab_ahriman_daemon_options=( _shtab_ahriman_daemon_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{-i,--interval}"[interval between runs in seconds (default\: 43200)]:interval:" {-i,--interval}"[interval between runs in seconds (default\: 43200)]:interval:"
@ -234,6 +244,14 @@ _shtab_ahriman_package_changes_remove_options=(
":package base:" ":package base:"
) )
_shtab_ahriman_package_copy_options=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
"--remove[remove package from the source repository after (default\: False)]"
":source repository name:"
"(*):package base:"
)
_shtab_ahriman_package_remove_options=( _shtab_ahriman_package_remove_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
"(*):package name or base:" "(*):package name or base:"
@ -565,6 +583,7 @@ _shtab_ahriman_service_setup_options=(
_shtab_ahriman_service_shell_options=( _shtab_ahriman_service_shell_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{-o,--output}"[output commands and result to the file (default\: None)]:output:"
":instead of dropping into shell, just execute the specified code (default\: None):" ":instead of dropping into shell, just execute the specified code (default\: None):"
) )
@ -590,6 +609,7 @@ _shtab_ahriman_setup_options=(
_shtab_ahriman_shell_options=( _shtab_ahriman_shell_options=(
"(- : *)"{-h,--help}"[show this help message and exit]" "(- : *)"{-h,--help}"[show this help message and exit]"
{-o,--output}"[output commands and result to the file (default\: None)]:output:"
":instead of dropping into shell, just execute the specified code (default\: None):" ":instead of dropping into shell, just execute the specified code (default\: None):"
) )
@ -684,6 +704,7 @@ _shtab_ahriman() {
clean) _arguments -C -s $_shtab_ahriman_clean_options ;; clean) _arguments -C -s $_shtab_ahriman_clean_options ;;
config) _arguments -C -s $_shtab_ahriman_config_options ;; config) _arguments -C -s $_shtab_ahriman_config_options ;;
config-validate) _arguments -C -s $_shtab_ahriman_config_validate_options ;; config-validate) _arguments -C -s $_shtab_ahriman_config_validate_options ;;
copy) _arguments -C -s $_shtab_ahriman_copy_options ;;
daemon) _arguments -C -s $_shtab_ahriman_daemon_options ;; daemon) _arguments -C -s $_shtab_ahriman_daemon_options ;;
help) _arguments -C -s $_shtab_ahriman_help_options ;; help) _arguments -C -s $_shtab_ahriman_help_options ;;
help-commands-unsafe) _arguments -C -s $_shtab_ahriman_help_commands_unsafe_options ;; help-commands-unsafe) _arguments -C -s $_shtab_ahriman_help_commands_unsafe_options ;;
@ -694,6 +715,7 @@ _shtab_ahriman() {
package-add) _arguments -C -s $_shtab_ahriman_package_add_options ;; package-add) _arguments -C -s $_shtab_ahriman_package_add_options ;;
package-changes) _arguments -C -s $_shtab_ahriman_package_changes_options ;; package-changes) _arguments -C -s $_shtab_ahriman_package_changes_options ;;
package-changes-remove) _arguments -C -s $_shtab_ahriman_package_changes_remove_options ;; package-changes-remove) _arguments -C -s $_shtab_ahriman_package_changes_remove_options ;;
package-copy) _arguments -C -s $_shtab_ahriman_package_copy_options ;;
package-remove) _arguments -C -s $_shtab_ahriman_package_remove_options ;; package-remove) _arguments -C -s $_shtab_ahriman_package_remove_options ;;
package-status) _arguments -C -s $_shtab_ahriman_package_status_options ;; package-status) _arguments -C -s $_shtab_ahriman_package_status_options ;;
package-status-remove) _arguments -C -s $_shtab_ahriman_package_status_remove_options ;; package-status-remove) _arguments -C -s $_shtab_ahriman_package_status_remove_options ;;

View File

@ -25,15 +25,64 @@ dependencies = [
dynamic = ["version"] dynamic = ["version"]
[project.optional-dependencies]
journald = [
"systemd-python",
]
# FIXME technically this dependency is required, but in some cases we do not have access to
# the libalpm which is required in order to install the package. Thus in case if we do not
# really need to run the application we can move it to "optional" dependencies
pacman = [
"pyalpm",
]
reports = [
"Jinja2",
]
s3 = [
"boto3",
]
shell = [
"IPython"
]
stats = [
"matplotlib",
]
unixsocket = [
"requests-unixsocket2", # required by unix socket support
]
validator = [
"cerberus",
]
web = [
"aiohttp",
"aiohttp_cors",
"aiohttp_jinja2",
]
web_api-docs = [
"ahriman[web]",
"aiohttp-apispec",
"setuptools", # required by aiohttp-apispec
]
web_auth = [
"ahriman[web]",
"aiohttp_session",
"aiohttp_security",
"cryptography",
]
web_oauth2 = [
"ahriman[web_auth]",
"aioauth-client",
]
[project.scripts]
ahriman = "ahriman.application.ahriman:run"
[project.urls] [project.urls]
Documentation = "https://ahriman.readthedocs.io/" Documentation = "https://ahriman.readthedocs.io/"
Repository = "https://github.com/arcan1s/ahriman" Repository = "https://github.com/arcan1s/ahriman"
Changelog = "https://github.com/arcan1s/ahriman/releases" Changelog = "https://github.com/arcan1s/ahriman/releases"
[project.scripts] [dependency-groups]
ahriman = "ahriman.application.ahriman:run"
[project.optional-dependencies]
check = [ check = [
"autopep8", "autopep8",
"bandit", "bandit",
@ -47,21 +96,6 @@ docs = [
"shtab", "shtab",
"sphinx-argparse", "sphinx-argparse",
"sphinx-rtd-theme>=1.1.1", # https://stackoverflow.com/a/74355734 "sphinx-rtd-theme>=1.1.1", # https://stackoverflow.com/a/74355734
]
journald = [
"systemd-python",
]
# FIXME technically this dependency is required, but in some cases we do not have access to
# the libalpm which is required in order to install the package. Thus in case if we do not
# really need to run the application we can move it to "optional" dependencies
pacman = [
"pyalpm",
]
s3 = [
"boto3",
]
stats = [
"matplotlib",
] ]
tests = [ tests = [
"pytest", "pytest",
@ -72,22 +106,6 @@ tests = [
"pytest-resource-path", "pytest-resource-path",
"pytest-spec", "pytest-spec",
] ]
validator = [
"cerberus",
]
web = [
"Jinja2",
"aioauth-client",
"aiohttp",
"aiohttp-apispec",
"aiohttp_cors",
"aiohttp_jinja2",
"aiohttp_session",
"aiohttp_security",
"cryptography",
"requests-unixsocket2", # required by unix socket support
"setuptools", # required by aiohttp-apispec
]
[tool.flit.sdist] [tool.flit.sdist]
include = [ include = [

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -17,4 +17,4 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
__version__ = "2.15.2" __version__ = "2.18.2"

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -117,7 +117,7 @@ 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 set to ``False``, dependencies will not be processed
Returns: Returns:
list[Package]: updated packages list. Packager for dependencies will be copied from the original package list[Package]: updated packages list. Packager for dependencies will be copied from the original package
@ -130,6 +130,9 @@ class Application(ApplicationPackages, ApplicationRepository):
>>> packages = application.with_dependencies(packages, process_dependencies=True) >>> packages = application.with_dependencies(packages, process_dependencies=True)
>>> application.print_updates(packages, log_fn=print) >>> application.print_updates(packages, log_fn=print)
""" """
if not process_dependencies or not packages:
return packages
def missing_dependencies(source: Iterable[Package]) -> dict[str, str | None]: def missing_dependencies(source: Iterable[Package]) -> dict[str, str | None]:
# append list of known packages with packages which are in current sources # append list of known packages with packages which are in current sources
satisfied_packages = known_packages | { satisfied_packages = known_packages | {
@ -145,22 +148,29 @@ class Application(ApplicationPackages, ApplicationRepository):
if dependency not in satisfied_packages if dependency not in satisfied_packages
} }
if not process_dependencies or not packages: def new_packages(root: Package) -> dict[str, Package]:
return packages portion = {root.base: root}
while missing := missing_dependencies(portion.values()):
for package_name, packager in missing.items():
if (source_dir := self.repository.paths.cache_for(package_name)).is_dir():
# there is local cache, load package from it
leaf = Package.from_build(source_dir, self.repository.architecture, packager)
else:
leaf = Package.from_aur(package_name, packager)
portion[leaf.base] = leaf
# register package in the database
self.repository.reporter.set_unknown(leaf)
return portion
known_packages = self._known_packages() known_packages = self._known_packages()
with_dependencies = {package.base: package for package in packages} with_dependencies: dict[str, Package] = {}
for package in packages:
while missing := missing_dependencies(with_dependencies.values()): with self.in_package_context(package.base, package.version): # use the same context for the logger
for package_name, username in missing.items(): try:
if (source_dir := self.repository.paths.cache_for(package_name)).is_dir(): with_dependencies |= new_packages(package)
# there is local cache, load package from it except Exception:
package = Package.from_build(source_dir, self.repository.architecture, username) self.logger.exception("could not process dependencies of %s, skip the package", package.base)
else:
package = Package.from_aur(package_name, username)
with_dependencies[package.base] = package
# register package in the database
self.repository.reporter.set_unknown(package)
return list(with_dependencies.values()) return list(with_dependencies.values())

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -22,7 +22,7 @@ import logging
from collections.abc import Callable, Iterable from collections.abc import Callable, Iterable
from multiprocessing import Pool from multiprocessing import Pool
from typing import TypeVar from typing import ClassVar, TypeVar
from ahriman.application.lock import Lock from ahriman.application.lock import Lock
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
@ -53,13 +53,13 @@ class Handler:
Wrapper for all command line actions, though each derived class implements :func:`run()` method, it usually Wrapper for all command line actions, though each derived class implements :func:`run()` method, it usually
must not be called directly. The recommended way is to call :func:`execute()` class method, e.g.:: must not be called directly. The recommended way is to call :func:`execute()` class method, e.g.::
>>> from ahriman.application.handlers import Add >>> from ahriman.application.handlers.add import Add
>>> >>>
>>> Add.execute(args) >>> Add.execute(args)
""" """
ALLOW_MULTI_ARCHITECTURE_RUN = True ALLOW_MULTI_ARCHITECTURE_RUN: ClassVar[bool] = True
arguments: list[Callable[[SubParserAction], argparse.ArgumentParser]] arguments: ClassVar[list[Callable[[SubParserAction], argparse.ArgumentParser]]]
@classmethod @classmethod
def call(cls, args: argparse.Namespace, repository_id: RepositoryId) -> bool: def call(cls, args: argparse.Namespace, repository_id: RepositoryId) -> bool:

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -198,8 +198,7 @@ class Patch(Handler):
else: else:
patch = patch_path.read_text(encoding="utf8") patch = patch_path.read_text(encoding="utf8")
# remove spaces around the patch and parse to correct type # remove spaces around the patch and parse to correct type
parsed = PkgbuildPatch.parse(patch.strip()) return PkgbuildPatch.parse(variable, patch.strip())
return PkgbuildPatch(variable, parsed)
@staticmethod @staticmethod
def patch_set_create(application: Application, package_base: str, patch: PkgbuildPatch) -> None: def patch_set_create(application: Application, package_base: str, patch: PkgbuildPatch) -> None:

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -21,6 +21,7 @@ import argparse
from collections.abc import Callable, Iterable from collections.abc import Callable, Iterable
from dataclasses import fields from dataclasses import fields
from typing import ClassVar
from ahriman.application.handlers.handler import Handler, SubParserAction from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.alpm.remote import AUR, Official from ahriman.core.alpm.remote import AUR, Official
@ -40,7 +41,7 @@ class Search(Handler):
""" """
ALLOW_MULTI_ARCHITECTURE_RUN = False # system-wide action ALLOW_MULTI_ARCHITECTURE_RUN = False # system-wide action
SORT_FIELDS = { SORT_FIELDS: ClassVar[set[str]] = {
field.name field.name
for field in fields(AURPackage) for field in fields(AURPackage)
if field.default_factory is not list if field.default_factory is not list

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -21,7 +21,8 @@ import argparse
from pathlib import Path from pathlib import Path
from pwd import getpwuid from pwd import getpwuid
from urllib.parse import quote_plus as urlencode from typing import ClassVar
from urllib.parse import quote_plus as url_encode
from ahriman.application.application import Application from ahriman.application.application import Application
from ahriman.application.handlers.handler import Handler, SubParserAction from ahriman.application.handlers.handler import Handler, SubParserAction
@ -46,9 +47,9 @@ class Setup(Handler):
ALLOW_MULTI_ARCHITECTURE_RUN = False # conflicting io ALLOW_MULTI_ARCHITECTURE_RUN = False # conflicting io
ARCHBUILD_COMMAND_PATH = Path("/") / "usr" / "bin" / "archbuild" ARCHBUILD_COMMAND_PATH: ClassVar[Path] = Path("/") / "usr" / "bin" / "archbuild"
MIRRORLIST_PATH = Path("/") / "etc" / "pacman.d" / "mirrorlist" MIRRORLIST_PATH: ClassVar[Path] = Path("/") / "etc" / "pacman.d" / "mirrorlist"
SUDOERS_DIR_PATH = Path("/") / "etc" / "sudoers.d" SUDOERS_DIR_PATH: ClassVar[Path] = Path("/") / "etc" / "sudoers.d"
@classmethod @classmethod
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *, def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
@ -174,7 +175,7 @@ class Setup(Handler):
if args.web_unix_socket is not None: if args.web_unix_socket is not None:
unix_socket = str(args.web_unix_socket) unix_socket = str(args.web_unix_socket)
configuration.set_option("web", "unix_socket", unix_socket) configuration.set_option("web", "unix_socket", unix_socket)
configuration.set_option("status", "address", f"http+unix://{urlencode(unix_socket)}") configuration.set_option("status", "address", f"http+unix://{url_encode(unix_socket)}")
if args.generate_salt: if args.generate_salt:
configuration.set_option("auth", "salt", User.generate_password(20)) configuration.set_option("auth", "salt", User.generate_password(20))

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -18,12 +18,12 @@
# 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 code
import sys import sys
from pathlib import Path from pathlib import Path
from ahriman.application.handlers.handler import Handler, SubParserAction from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.application.interactive_shell import InteractiveShell
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.formatters import StringPrinter from ahriman.core.formatters import StringPrinter
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -58,11 +58,13 @@ class Shell(Handler):
"configuration": configuration, "configuration": configuration,
"repository_id": repository_id, "repository_id": repository_id,
} }
console = InteractiveShell(locals=local_variables)
if args.code is None: match args.code:
code.interact(local=local_variables) case None:
else: console.interact()
code.InteractiveConsole(locals=local_variables).runcode(args.code) case snippet:
console.runcode(snippet)
@staticmethod @staticmethod
def _set_service_shell_parser(root: SubParserAction) -> argparse.ArgumentParser: def _set_service_shell_parser(root: SubParserAction) -> argparse.ArgumentParser:
@ -79,6 +81,7 @@ class Shell(Handler):
description="drop into python shell") description="drop into python shell")
parser.add_argument("code", help="instead of dropping into shell, just execute the specified code", nargs="?") parser.add_argument("code", help="instead of dropping into shell, just execute the specified code", nargs="?")
parser.add_argument("-v", "--verbose", help=argparse.SUPPRESS, action="store_true") parser.add_argument("-v", "--verbose", help=argparse.SUPPRESS, action="store_true")
parser.add_argument("-o", "--output", help="output commands and result to the file", type=Path)
parser.set_defaults(lock=None, report=False) parser.set_defaults(lock=None, report=False)
return parser return parser

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -27,7 +27,7 @@ from pathlib import Path
from ahriman.application.application import Application from ahriman.application.application import Application
from ahriman.application.handlers.handler import Handler, SubParserAction from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.formatters import EventStatsPrinter, PackageStatsPrinter from ahriman.core.formatters import EventStatsPrinter, PackageStatsPrinter, RepositoryStatsPrinter
from ahriman.core.utils import enum_values, pretty_datetime from ahriman.core.utils import enum_values, pretty_datetime
from ahriman.models.event import Event, EventType from ahriman.models.event import Event, EventType
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -64,6 +64,7 @@ class Statistics(Handler):
match args.package: match args.package:
case None: case None:
RepositoryStatsPrinter(repository_id, application.reporter.statistics())(verbose=True)
Statistics.stats_per_package(args.event, events, args.chart) Statistics.stats_per_package(args.event, events, args.chart)
case _: case _:
Statistics.stats_for_package(args.event, events, args.chart) Statistics.stats_for_package(args.event, events, args.chart)

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -54,7 +54,7 @@ class StatusUpdate(Handler):
case Action.Update if args.package: case Action.Update if args.package:
# update packages statuses # update packages statuses
for package in args.package: for package in args.package:
client.package_update(package, args.status) client.package_status_update(package, args.status)
case Action.Update: case Action.Update:
# update service status # update service status
client.status_update(args.status) client.status_update(args.status)

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -23,6 +23,7 @@ import sys
from collections.abc import Generator from collections.abc import Generator
from importlib import metadata from importlib import metadata
from typing import ClassVar
from ahriman import __version__ from ahriman import __version__
from ahriman.application.handlers.handler import Handler, SubParserAction from ahriman.application.handlers.handler import Handler, SubParserAction
@ -36,11 +37,11 @@ class Versions(Handler):
version handler version handler
Attributes: Attributes:
PEP423_PACKAGE_NAME(str): (class attribute) special regex for valid PEP423 package name PEP423_PACKAGE_NAME(re.Pattern[str]): (class attribute) special regex for valid PEP423 package name
""" """
ALLOW_MULTI_ARCHITECTURE_RUN = False # system-wide action ALLOW_MULTI_ARCHITECTURE_RUN = False # system-wide action
PEP423_PACKAGE_NAME = re.compile(r"^[A-Za-z0-9._-]+") PEP423_PACKAGE_NAME: ClassVar[re.Pattern[str]] = re.compile(r"^[A-Za-z0-9._-]+")
@classmethod @classmethod
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *, def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -0,0 +1,60 @@
#
# Copyright (c) 2021-2025 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 code import InteractiveConsole
from importlib.util import find_spec
from typing import Any
class InteractiveShell(InteractiveConsole):
"""
wrapper around :class:`code.InteractiveConsole` to pass :func:`interact()` to IPython shell
"""
@staticmethod
def has_ipython() -> bool:
"""
check if IPython shell is available
Returns:
bool: ``True`` if IPython shell is available, ``False`` otherwise
"""
try:
return find_spec("IPython.terminal.embed") is not None
except ModuleNotFoundError:
return False
def interact(self, *args: Any, **kwargs: Any) -> None:
"""
pass controller to IPython shell
Args:
*args(Any): positional arguments
**kwargs(Any): keyword arguments
"""
if self.has_ipython():
from IPython.terminal.embed import InteractiveShellEmbed
shell = InteractiveShellEmbed(user_ns=self.locals) # type: ignore[no-untyped-call]
shell.show_banner() # type: ignore[no-untyped-call]
shell.interact() # type: ignore[no-untyped-call]
else:
# fallback to default
import readline # pylint: disable=unused-import
InteractiveConsole.interact(self, *args, **kwargs)

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -23,6 +23,7 @@ import shutil
from email.utils import parsedate_to_datetime from email.utils import parsedate_to_datetime
from pathlib import Path from pathlib import Path
from pyalpm import DB # type: ignore[import-not-found] from pyalpm import DB # type: ignore[import-not-found]
from typing import ClassVar
from urllib.parse import urlparse from urllib.parse import urlparse
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
@ -41,7 +42,7 @@ class PacmanDatabase(SyncHttpClient):
sync_files_database(bool): sync files database sync_files_database(bool): sync files database
""" """
LAST_MODIFIED_HEADER = "Last-Modified" LAST_MODIFIED_HEADER: ClassVar[str] = "Last-Modified"
def __init__(self, database: DB, configuration: Configuration) -> None: def __init__(self, database: DB, configuration: Configuration) -> None:
""" """

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -34,13 +34,14 @@ class PkgbuildToken(StrEnum):
well-known tokens dictionary well-known tokens dictionary
Attributes: Attributes:
ArrayEnds(PkgbuildToken): (class attribute) array ends token ArrayEnds(PkgbuildToken): array ends token
ArrayStarts(PkgbuildToken): (class attribute) array starts token ArrayStarts(PkgbuildToken): array starts token
Comma(PkgbuildToken): (class attribute) comma token Comma(PkgbuildToken): comma token
Comment(PkgbuildToken): (class attribute) comment token Comment(PkgbuildToken): comment token
FunctionDeclaration(PkgbuildToken): (class attribute) function declaration token FunctionDeclaration(PkgbuildToken): function declaration token
FunctionEnds(PkgbuildToken): (class attribute) function ends token FunctionEnds(PkgbuildToken): function ends token
FunctionStarts(PkgbuildToken): (class attribute) function starts token FunctionStarts(PkgbuildToken): function starts token
NewLine(PkgbuildToken): new line token
""" """
ArrayStarts = "(" ArrayStarts = "("
@ -54,6 +55,8 @@ class PkgbuildToken(StrEnum):
FunctionStarts = "{" FunctionStarts = "{"
FunctionEnds = "}" FunctionEnds = "}"
NewLine = "\n"
class PkgbuildParser(shlex.shlex): class PkgbuildParser(shlex.shlex):
""" """
@ -146,7 +149,7 @@ class PkgbuildParser(shlex.shlex):
# reset state # reset state
buffer, prefix = [], None buffer, prefix = [], None
# we have already prefix string, so we are in progress of expansion # we have already got prefix string, so we are in progress of expansion
# we always operate the last element, so this matches ",", "next" # we always operate the last element, so this matches ",", "next"
case (PkgbuildToken.Comma, _) if prefix is not None: case (PkgbuildToken.Comma, _) if prefix is not None:
buffer.append(f"{prefix}{second}") buffer.append(f"{prefix}{second}")
@ -168,37 +171,24 @@ class PkgbuildParser(shlex.shlex):
def _is_escaped(self) -> bool: def _is_escaped(self) -> bool:
""" """
check if the last element was quoted. ``shlex.shlex`` parser doesn't provide information about was the token check if the last element was quoted. ``shlex.shlex`` parser doesn't provide information about was the token
quoted or not, thus there is no difference between "'#'" (diez in quotes) and "#" (diez without quotes). This quoted or not, thus there is no difference between "'#'" (sharp in quotes) and "#" (sharp without quotes). This
method simply rolls back to the last non-space character and check if it is a quotation mark method simply rolls back to the last non-space character and check if it is a quotation mark
Returns: Returns:
bool: ``True`` if the previous element of the stream is a quote or escaped and ``False`` otherwise bool: ``True`` if the previous element of the stream is a quote or escaped and ``False`` otherwise
""" """
# wrapper around reading utf symbols from random position of the stream
def read_last() -> tuple[int, str]:
while (position := self._io.tell()) > 0:
try:
return position, self._io.read(1)
except UnicodeDecodeError:
self._io.seek(position - 1)
raise PkgbuildParserError("reached starting position, no valid symbols found")
current_position = self._io.tell() current_position = self._io.tell()
last_char = penultimate_char = None last_char = penultimate_char = None
index = current_position - 1 index = current_position - 1
while index > 0: while index > 0:
self._io.seek(index) index, last_char = self._read_last(index)
index, last_char = read_last()
if last_char.isspace(): if last_char.isspace():
index -= 1 index -= 1
continue continue
if index > 1: if index > 1:
self._io.seek(index - 1) _, penultimate_char = self._read_last(index - 1)
_, penultimate_char = read_last()
break break
@ -226,8 +216,8 @@ class PkgbuildParser(shlex.shlex):
pass pass
case PkgbuildToken.ArrayEnds: case PkgbuildToken.ArrayEnds:
break break
case PkgbuildToken.Comment: case comment if comment.startswith(PkgbuildToken.Comment):
self.instream.readline() self._read_comment()
continue continue
yield token yield token
@ -267,8 +257,8 @@ class PkgbuildParser(shlex.shlex):
counter -= 1 counter -= 1
if counter == 0: if counter == 0:
break break
case PkgbuildToken.Comment: case comment if comment.startswith(PkgbuildToken.Comment):
self.instream.readline() self._read_comment()
if not 0 < start_position < end_position: if not 0 < start_position < end_position:
raise PkgbuildParserError("function body wasn't found") raise PkgbuildParserError("function body wasn't found")
@ -303,8 +293,8 @@ class PkgbuildParser(shlex.shlex):
yield PkgbuildPatch(key, value) yield PkgbuildPatch(key, value)
return return
if token == PkgbuildToken.Comment: if token.startswith(PkgbuildToken.Comment):
self.instream.readline() self._read_comment()
return return
match self.get_token(): match self.get_token():
@ -332,6 +322,44 @@ class PkgbuildParser(shlex.shlex):
case other if other is not None: case other if other is not None:
yield from self._parse_token(other) yield from self._parse_token(other)
def _read_comment(self) -> None:
"""
read comment from the current position. This method doesn't check comment itself, just read the stream
until the comment line ends
"""
_, last_symbol = self._read_last()
if last_symbol != PkgbuildToken.NewLine:
self.instream.readline()
def _read_last(self, initial_index: int | None = None) -> tuple[int, str]:
"""
wrapper around read to read the last symbol from the input stream. This method is designed to process UTF-8
symbols correctly. This method does not reset current stream position
Args:
initial_index(int | None, optional): initial index to start reading from. If none set, the previous position
will be used (Default value = None)
Returns:
tuple[int, str]: last symbol and its position in the stream
Raises:
PkgbuildParserError: in case if stream reached starting position, but no valid symbols were found
"""
if initial_index is None:
initial_index = self._io.tell() - 1
if initial_index < 0:
raise PkgbuildParserError("stream is on starting position")
self._io.seek(initial_index)
while (position := self._io.tell()) > 0:
try:
return position, self._io.read(1)
except UnicodeDecodeError:
self._io.seek(position - 1)
raise PkgbuildParserError("reached starting position, no valid symbols found")
def parse(self) -> Generator[PkgbuildPatch, None, None]: def parse(self) -> Generator[PkgbuildPatch, None, None]:
""" """
parse source stream and yield parsed entries parse source stream and yield parsed entries

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).

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