mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-08-27 20:09:57 +00:00
Compare commits
58 Commits
1.6.3
...
1cfc751d21
Author | SHA1 | Date | |
---|---|---|---|
1cfc751d21 | |||
6ebbb04504 | |||
c9ee470ee2 | |||
a2610504e5 | |||
36b8b0f46a | |||
d90f417cae | |||
0db619136d | |||
208a9b920d | |||
cb63bc08ff | |||
6551c8d983 | |||
a6c8d64053 | |||
fd78f2b5e2 | |||
900907cdaa | |||
5ff2f43506 | |||
dd521b49b5 | |||
5b1f5a8473 | |||
86af13f09e | |||
733c014229 | |||
783c16b2ed | |||
2536b8dc1f | |||
e200ac9776 | |||
6946745153 | |||
6de75377c3 | |||
a734b86e66 | |||
74906d084a | |||
22d1d835af | |||
b7cd83502a | |||
2d2cd73010 | |||
40b84b810d | |||
7188cfaf78 | |||
e909e4f570 | |||
06ec16ac77 | |||
fed2f3aab8 | |||
2bc2b63a8a | |||
0c5a90cd66 | |||
28cc38aaa5 | |||
fb02e676af | |||
13121298f5 | |||
63e79ec57a | |||
b83bc5a732 | |||
8374590b62 | |||
4cc665f6ee | |||
57f25c309a | |||
d33844e7b2 | |||
e9886efaa2 | |||
61efbb71a2 | |||
9f4acacada | |||
026f74121a | |||
e414616bbd | |||
60a2e25b9a | |||
683abca9e5 | |||
5a3770b739 | |||
52cd9a0ea9 | |||
bfca7e41ab | |||
603c5449a8 | |||
5aac3db2d5 | |||
3c5bcbd172 | |||
042638d40e |
@ -1 +1 @@
|
||||
skips: ['B101', 'B404']
|
||||
skips: ['B101', 'B105', 'B404']
|
42
.github/workflows/docker-image.yml
vendored
Normal file
42
.github/workflows/docker-image.yml
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
name: docker image
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
tags:
|
||||
- '*'
|
||||
- '!*rc*'
|
||||
|
||||
jobs:
|
||||
docker-image:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: extract docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v3
|
||||
with:
|
||||
images: |
|
||||
arcan1s/ahriman
|
||||
tags: |
|
||||
type=ref,event=tag
|
||||
type=edge
|
||||
|
||||
- name: setup QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
|
||||
- name: setup docker buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
|
||||
- name: login to docker hub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: build an image and push
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
8
.github/workflows/release.yml
vendored
8
.github/workflows/release.yml
vendored
@ -3,7 +3,7 @@ name: release
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*.*.*'
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
make-release:
|
||||
@ -12,20 +12,24 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: extract version
|
||||
id: version
|
||||
run: echo ::set-output name=VERSION::${GITHUB_REF#refs/tags/}
|
||||
|
||||
- name: create changelog
|
||||
id: changelog
|
||||
uses: jaywcjlove/changelog-generator@main
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
filter: 'Release \d+\.\d+\.\d+'
|
||||
|
||||
- name: create archive
|
||||
run: make archive
|
||||
env:
|
||||
VERSION: ${{ steps.version.outputs.VERSION }}
|
||||
- name: Release
|
||||
|
||||
- name: release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
body: |
|
||||
|
13
.github/workflows/run-setup.yml
vendored
13
.github/workflows/run-setup.yml
vendored
@ -11,11 +11,14 @@ jobs:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
container:
|
||||
image: archlinux:latest
|
||||
volumes:
|
||||
- ${{ github.workspace }}:/build
|
||||
options: --privileged -w /build
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: setup the service in arch linux container
|
||||
run: |
|
||||
docker run \
|
||||
-v ${{ github.workspace }}:/build -w /build \
|
||||
archlinux:latest \
|
||||
.github/workflows/setup.sh
|
||||
run: .github/workflows/setup.sh
|
||||
|
13
.github/workflows/run-tests.yml
vendored
13
.github/workflows/run-tests.yml
vendored
@ -11,11 +11,14 @@ jobs:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
container:
|
||||
image: archlinux:latest
|
||||
volumes:
|
||||
- ${{ github.workspace }}:/build
|
||||
options: -w /build
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: run check and tests in arch linux container
|
||||
run: |
|
||||
docker run \
|
||||
-v ${{ github.workspace }}:/build -w /build \
|
||||
archlinux:latest \
|
||||
.github/workflows/tests.sh
|
||||
run: .github/workflows/tests.sh
|
||||
|
19
.github/workflows/setup.sh
vendored
19
.github/workflows/setup.sh
vendored
@ -10,7 +10,7 @@ pacman --noconfirm -Syu
|
||||
# main dependencies
|
||||
pacman --noconfirm -Sy base-devel devtools git pyalpm python-aur python-passlib python-srcinfo sudo
|
||||
# make dependencies
|
||||
pacman --noconfirm -Sy python-pip
|
||||
pacman --noconfirm -Sy python-build python-installer python-wheel
|
||||
# optional dependencies
|
||||
# VCS support
|
||||
pacman --noconfirm -Sy breezy darcs mercurial subversion
|
||||
@ -25,25 +25,28 @@ make VERSION=1.0.0 archlinux # well, it does not really matter which version we
|
||||
mv ahriman-*-src.tar.xz package/archlinux
|
||||
chmod +777 package/archlinux # because fuck you that's why
|
||||
cd package/archlinux
|
||||
sudo -u nobody makepkg -cf --skipchecksums --noconfirm
|
||||
sudo -u nobody -- makepkg -cf --skipchecksums --noconfirm
|
||||
pacman --noconfirm -U ahriman-1.0.0-1-any.pkg.tar.zst
|
||||
# create machine-id which is required by build tools
|
||||
systemd-machine-id-setup
|
||||
|
||||
# special thing for the container, because /dev/log interface is not available there
|
||||
sed -i 's/handlers = syslog_handler/handlers = console_handler/g' /etc/ahriman.ini.d/logging.ini
|
||||
sed -i "s/handlers = syslog_handler/handlers = console_handler/g" /etc/ahriman.ini.d/logging.ini
|
||||
# initial setup command as root
|
||||
sudo -u ahriman ahriman -a x86_64 init
|
||||
ahriman -a x86_64 repo-setup --packager "ahriman bot <ahriman@example.com>" --repository "github" --web-port 8080
|
||||
# enable services
|
||||
systemctl enable ahriman-web@x86_64
|
||||
systemctl enable ahriman@x86_64.timer
|
||||
# run web service (detached)
|
||||
sudo -u ahriman ahriman -a x86_64 web &
|
||||
sudo -u ahriman -- ahriman -a x86_64 web &
|
||||
WEBPID=$!
|
||||
sleep 15s # wait for the web service activation
|
||||
# add the first package
|
||||
# the build itself does not really work in the container because it requires procfs
|
||||
sudo -u ahriman ahriman package-add yay
|
||||
# the build itself does not really work in the container
|
||||
sudo -u ahriman -- ahriman package-add --now yay
|
||||
# check if package was actually installed
|
||||
#test -n "$(find "/var/lib/ahriman/repository/x86_64" -name "yay*pkg*")"
|
||||
# run package check
|
||||
sudo -u ahriman ahriman repo-update
|
||||
sudo -u ahriman -- ahriman repo-update
|
||||
# stop web service lol
|
||||
kill $WEBPID
|
||||
|
8
.github/workflows/tests.sh
vendored
8
.github/workflows/tests.sh
vendored
@ -4,13 +4,7 @@
|
||||
set -ex
|
||||
|
||||
# install dependencies
|
||||
pacman --noconfirm -Syu base-devel python-pip
|
||||
|
||||
# install python packages
|
||||
pip install -e .[web]
|
||||
pip install -e .[check]
|
||||
pip install -e .[s3]
|
||||
pip install -e .[test]
|
||||
pacman --noconfirm -Syu base-devel python-pip python-tox
|
||||
|
||||
# run test and check targets
|
||||
make check tests
|
||||
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -94,3 +94,8 @@ ENV/
|
||||
.venv/
|
||||
|
||||
*.tar.xz
|
||||
status_cache.json
|
||||
|
||||
*.db
|
||||
|
||||
docs/html/
|
||||
|
20
.readthedocs.yaml
Normal file
20
.readthedocs.yaml
Normal file
@ -0,0 +1,20 @@
|
||||
version: 2
|
||||
|
||||
formats: all
|
||||
|
||||
build:
|
||||
os: ubuntu-20.04
|
||||
tools:
|
||||
python: "3.9"
|
||||
|
||||
sphinx:
|
||||
builder: html
|
||||
configuration: docs/source/conf.py
|
||||
|
||||
python:
|
||||
install:
|
||||
- method: pip
|
||||
path: .
|
||||
extra_requirements:
|
||||
- docs
|
||||
system_packages: true
|
52
Dockerfile
Normal file
52
Dockerfile
Normal file
@ -0,0 +1,52 @@
|
||||
FROM archlinux:base-devel
|
||||
|
||||
# image configuration
|
||||
ENV AHRIMAN_ARCHITECTURE="x86_64"
|
||||
ENV AHRIMAN_DEBUG=""
|
||||
ENV AHRIMAN_FORCE_ROOT=""
|
||||
ENV AHRIMAN_HOST="0.0.0.0"
|
||||
ENV AHRIMAN_OUTPUT="syslog"
|
||||
ENV AHRIMAN_PACKAGER="ahriman bot <ahriman@example.com>"
|
||||
ENV AHRIMAN_PORT=""
|
||||
ENV AHRIMAN_REPOSITORY="aur-clone"
|
||||
ENV AHRIMAN_REPOSITORY_ROOT="/var/lib/ahriman/ahriman"
|
||||
ENV AHRIMAN_USER="ahriman"
|
||||
|
||||
# install environment
|
||||
## install git which is required for AUR interaction and go for yay
|
||||
RUN pacman --noconfirm -Syu git go
|
||||
## create build user
|
||||
RUN useradd -m -d /home/build -s /usr/bin/nologin build && \
|
||||
echo "build ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/build
|
||||
## install AUR helper
|
||||
RUN YAY_DIR="$(runuser -u build -- mktemp -d)" && \
|
||||
git clone https://aur.archlinux.org/yay.git "$YAY_DIR" && \
|
||||
cd "$YAY_DIR" && \
|
||||
runuser -u build -- makepkg --noconfirm --install && \
|
||||
cd - && rm -r "$YAY_DIR"
|
||||
## install package dependencies
|
||||
RUN runuser -u build -- yay --noconfirm -Sy devtools git pyalpm python-inflection python-passlib python-requests python-srcinfo && \
|
||||
runuser -u build -- yay --noconfirm -Sy python-build python-installer python-wheel && \
|
||||
runuser -u build -- yay --noconfirm -Sy breezy darcs mercurial python-aioauth-client python-aiohttp \
|
||||
python-aiohttp-debugtoolbar python-aiohttp-jinja2 python-aiohttp-security \
|
||||
python-aiohttp-session python-boto3 python-cryptography python-jinja \
|
||||
rsync subversion
|
||||
|
||||
# install ahriman
|
||||
## copy tree
|
||||
COPY --chown=build . "/home/build/ahriman"
|
||||
## create package archive and install it
|
||||
RUN cd "/home/build/ahriman" && \
|
||||
make VERSION=$(python -c "from src.ahriman.version import __version__; print(__version__)") archlinux && \
|
||||
cp ./*-src.tar.xz "package/archlinux" && \
|
||||
cd "package/archlinux" && \
|
||||
runuser -u build -- makepkg --noconfirm --install --skipchecksums && \
|
||||
cd - && rm -r "/home/build/ahriman"
|
||||
|
||||
VOLUME ["/var/lib/ahriman"]
|
||||
|
||||
# minimal runtime ahriman setup
|
||||
COPY "docker/entrypoint.sh" "/usr/local/bin/entrypoint"
|
||||
ENTRYPOINT ["entrypoint"]
|
||||
# default command
|
||||
CMD ["repo-update"]
|
39
Makefile
39
Makefile
@ -1,18 +1,15 @@
|
||||
.PHONY: architecture archive archive_directory archlinux check clean directory man push tests version
|
||||
.PHONY: archive archive_directory archlinux check clean directory push spec spec-html tests version
|
||||
.DEFAULT_GOAL := archlinux
|
||||
|
||||
PROJECT := ahriman
|
||||
|
||||
FILES := AUTHORS COPYING README.md docs package src setup.cfg setup.py web.png
|
||||
FILES := AUTHORS COPYING README.md docs package src setup.py tox.ini web.png
|
||||
TARGET_FILES := $(addprefix $(PROJECT)/, $(FILES))
|
||||
IGNORE_FILES := package/archlinux src/.mypy_cache
|
||||
|
||||
$(TARGET_FILES) : $(addprefix $(PROJECT), %) : $(addprefix ., %) directory version
|
||||
@cp -rp $< $@
|
||||
|
||||
architecture:
|
||||
cd src && pydeps ahriman -o ../docs/ahriman-architecture.svg --no-show --cluster
|
||||
|
||||
archive: archive_directory
|
||||
tar cJf "$(PROJECT)-$(VERSION)-src.tar.xz" "$(PROJECT)"
|
||||
rm -rf "$(PROJECT)"
|
||||
@ -24,13 +21,10 @@ archive_directory: $(TARGET_FILES)
|
||||
find "$(PROJECT)" -depth -type d -name "*.egg-info" -execdir rm -rf {} +
|
||||
|
||||
archlinux: archive
|
||||
sed -i "s/pkgver=[0-9.]*/pkgver=$(VERSION)/" package/archlinux/PKGBUILD
|
||||
sed -i "s/pkgver=.*/pkgver=$(VERSION)/" package/archlinux/PKGBUILD
|
||||
|
||||
check: clean mypy
|
||||
autopep8 --exit-code --max-line-length 120 -aa -i -j 0 -r "src/$(PROJECT)" "tests/$(PROJECT)"
|
||||
pylint --rcfile=.pylintrc "src/$(PROJECT)"
|
||||
bandit -c .bandit.yml -r "src/$(PROJECT)"
|
||||
bandit -c .bandit-test.yml -r "tests/$(PROJECT)"
|
||||
check: clean
|
||||
tox -e check
|
||||
|
||||
clean:
|
||||
find . -type f -name "$(PROJECT)-*-src.tar.xz" -delete
|
||||
@ -39,25 +33,28 @@ clean:
|
||||
directory: clean
|
||||
mkdir "$(PROJECT)"
|
||||
|
||||
man:
|
||||
cd src && PYTHONPATH=. argparse-manpage --module ahriman.application.ahriman --function _parser --author "ahriman team" --project-name ahriman --author-email "" --url https://github.com/arcan1s/ahriman --output ../docs/ahriman.1
|
||||
|
||||
mypy:
|
||||
cd src && mypy --implicit-reexport --strict -p "$(PROJECT)" --install-types --non-interactive || true
|
||||
cd src && mypy --implicit-reexport --strict -p "$(PROJECT)"
|
||||
|
||||
push: architecture man archlinux
|
||||
push: spec archlinux
|
||||
git add package/archlinux/PKGBUILD src/ahriman/version.py docs/ahriman-architecture.svg docs/ahriman.1
|
||||
git commit -m "Release $(VERSION)"
|
||||
git tag "$(VERSION)"
|
||||
git push
|
||||
git push --tags
|
||||
|
||||
spec:
|
||||
# make sure that old files are removed
|
||||
find docs/source -type f -name "$(PROJECT)*.rst" -delete
|
||||
rm -f docs/source/modules.rst
|
||||
tox -e docs
|
||||
|
||||
spec-html: spec
|
||||
rm -rf docs/html
|
||||
tox -e docs-html
|
||||
|
||||
tests: clean
|
||||
python setup.py test
|
||||
tox -e tests
|
||||
|
||||
version:
|
||||
ifndef VERSION
|
||||
$(error VERSION is required, but not set)
|
||||
endif
|
||||
sed -i '/__version__ = "[0-9.]*/s/[^"][^)]*/__version__ = "$(VERSION)"/' src/ahriman/version.py
|
||||
sed -i '/__version__ = .*/s/[^"][^)]*/__version__ = "$(VERSION)"/' src/ahriman/version.py
|
||||
|
@ -2,7 +2,9 @@
|
||||
|
||||
[](https://github.com/arcan1s/ahriman/actions/workflows/run-tests.yml)
|
||||
[](https://github.com/arcan1s/ahriman/actions/workflows/run-setup.yml)
|
||||
[](https://github.com/arcan1s/ahriman/actions/workflows/docker-image.yml)
|
||||
[](https://www.codefactor.io/repository/github/arcan1s/ahriman)
|
||||
[](https://ahriman.readthedocs.io/?badge=latest)
|
||||
|
||||
Wrapper for managing custom repository inspired by [repo-scripts](https://github.com/arcan1s/repo-scripts).
|
||||
|
||||
@ -12,7 +14,7 @@ Wrapper for managing custom repository inspired by [repo-scripts](https://github
|
||||
* Multi-architecture support.
|
||||
* VCS packages support.
|
||||
* Sign support with gpg (repository, package, per package settings).
|
||||
* Synchronization to remote services (rsync, s3 and github) and report generation (html).
|
||||
* Synchronization to remote services (rsync, s3 and github) and report generation (email, html, telegram).
|
||||
* Dependency manager.
|
||||
* Ability to patch AUR packages and even create package from local PKGBUILDs.
|
||||
* Repository status interface with optional authorization and control options:
|
||||
|
49
docker/entrypoint.sh
Executable file
49
docker/entrypoint.sh
Executable file
@ -0,0 +1,49 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
[ -n "$AHRIMAN_DEBUG" ] && set -x
|
||||
|
||||
# configuration tune
|
||||
sed -i "s|root = /var/lib/ahriman|root = $AHRIMAN_REPOSITORY_ROOT|g" "/etc/ahriman.ini"
|
||||
sed -i "s|database = /var/lib/ahriman/ahriman.db|database = $AHRIMAN_REPOSITORY_ROOT/ahriman.db|g" "/etc/ahriman.ini"
|
||||
sed -i "s|host = 127.0.0.1|host = $AHRIMAN_HOST|g" "/etc/ahriman.ini"
|
||||
sed -i "s|handlers = syslog_handler|handlers = ${AHRIMAN_OUTPUT}_handler|g" "/etc/ahriman.ini.d/logging.ini"
|
||||
|
||||
AHRIMAN_DEFAULT_ARGS=("--architecture" "$AHRIMAN_ARCHITECTURE")
|
||||
if [[ "$AHRIMAN_OUTPUT" == "syslog" ]]; then
|
||||
if [ ! -e "/dev/log" ]; then
|
||||
# by default ahriman uses syslog which is not available inside container
|
||||
# to make noise less we force quiet mode in case if /dev/log was not mounted
|
||||
AHRIMAN_DEFAULT_ARGS+=("--quiet")
|
||||
fi
|
||||
fi
|
||||
|
||||
# create repository root inside the [[mounted]] directory and set correct ownership
|
||||
[ -d "$AHRIMAN_REPOSITORY_ROOT" ] || mkdir "$AHRIMAN_REPOSITORY_ROOT"
|
||||
chown "$AHRIMAN_USER":"$AHRIMAN_USER" "$AHRIMAN_REPOSITORY_ROOT"
|
||||
|
||||
# run built-in setup command
|
||||
AHRIMAN_SETUP_ARGS=("--build-as-user" "$AHRIMAN_USER")
|
||||
AHRIMAN_SETUP_ARGS+=("--packager" "$AHRIMAN_PACKAGER")
|
||||
AHRIMAN_SETUP_ARGS+=("--repository" "$AHRIMAN_REPOSITORY")
|
||||
if [ -n "$AHRIMAN_PORT" ]; then
|
||||
# in addition it must be handled in docker run command
|
||||
AHRIMAN_SETUP_ARGS+=("--web-port" "$AHRIMAN_PORT")
|
||||
fi
|
||||
ahriman "${AHRIMAN_DEFAULT_ARGS[@]}" repo-setup "${AHRIMAN_SETUP_ARGS[@]}"
|
||||
|
||||
# refresh database
|
||||
runuser -u build -- yay --noconfirm -Syy &> /dev/null
|
||||
# create machine-id which is required by build tools
|
||||
systemd-machine-id-setup &> /dev/null
|
||||
|
||||
# if AHRIMAN_FORCE_ROOT is set or command is unsafe we can run without sudo
|
||||
# otherwise we prepend executable by sudo command
|
||||
if [ -n "$AHRIMAN_FORCE_ROOT" ]; then
|
||||
AHRIMAN_EXECUTABLE=("ahriman")
|
||||
elif ahriman help-commands-unsafe --command="$*" &> /dev/null; then
|
||||
AHRIMAN_EXECUTABLE=("sudo" "-u" "$AHRIMAN_USER" "--" "ahriman")
|
||||
else
|
||||
AHRIMAN_EXECUTABLE=("ahriman")
|
||||
fi
|
||||
exec "${AHRIMAN_EXECUTABLE[@]}" "${AHRIMAN_DEFAULT_ARGS[@]}" "$@"
|
File diff suppressed because it is too large
Load Diff
Before Width: | Height: | Size: 398 KiB After Width: | Height: | Size: 540 KiB |
371
docs/ahriman.1
371
docs/ahriman.1
@ -3,7 +3,7 @@
|
||||
ahriman
|
||||
.SH SYNOPSIS
|
||||
.B ahriman
|
||||
[-h] [-a ARCHITECTURE] [-c CONFIGURATION] [--force] [-l LOCK] [--no-report] [-q] [--unsafe] [-v] {aur-search,search,key-import,package-add,add,package-update,package-remove,remove,package-status,status,package-status-remove,package-status-update,status-update,patch-add,patch-list,patch-remove,repo-check,check,repo-clean,clean,repo-config,config,repo-init,init,repo-rebuild,rebuild,repo-remove-unknown,remove-unknown,repo-report,report,repo-setup,setup,repo-sign,sign,repo-status-update,repo-sync,sync,repo-update,update,user-add,user-remove,web} ...
|
||||
[-h] [-a ARCHITECTURE] [-c CONFIGURATION] [--force] [-l LOCK] [--no-report] [-q] [--unsafe] [-v] {aur-search,search,help,help-commands-unsafe,key-import,package-add,add,package-update,package-remove,remove,package-status,status,package-status-remove,package-status-update,status-update,patch-add,patch-list,patch-remove,repo-backup,repo-check,check,repo-clean,clean,repo-config,config,repo-rebuild,rebuild,repo-remove-unknown,remove-unknown,repo-report,report,repo-restore,repo-setup,init,repo-init,setup,repo-sign,sign,repo-status-update,repo-sync,sync,repo-update,update,user-add,user-list,user-remove,web} ...
|
||||
.SH DESCRIPTION
|
||||
ArcH Linux ReposItory MANager
|
||||
.SH OPTIONS
|
||||
@ -46,6 +46,12 @@ show program's version number and exit
|
||||
\fBahriman\fR \fI\,aur-search\/\fR
|
||||
search for package
|
||||
.TP
|
||||
\fBahriman\fR \fI\,help\/\fR
|
||||
show help message
|
||||
.TP
|
||||
\fBahriman\fR \fI\,help-commands-unsafe\/\fR
|
||||
list unsafe commands
|
||||
.TP
|
||||
\fBahriman\fR \fI\,key-import\/\fR
|
||||
import PGP key
|
||||
.TP
|
||||
@ -73,6 +79,9 @@ list patch sets
|
||||
\fBahriman\fR \fI\,patch-remove\/\fR
|
||||
remove patch set
|
||||
.TP
|
||||
\fBahriman\fR \fI\,repo-backup\/\fR
|
||||
backup repository data
|
||||
.TP
|
||||
\fBahriman\fR \fI\,repo-check\/\fR
|
||||
check for updates
|
||||
.TP
|
||||
@ -82,9 +91,6 @@ clean local caches
|
||||
\fBahriman\fR \fI\,repo-config\/\fR
|
||||
dump configuration
|
||||
.TP
|
||||
\fBahriman\fR \fI\,repo-init\/\fR
|
||||
create repository tree
|
||||
.TP
|
||||
\fBahriman\fR \fI\,repo-rebuild\/\fR
|
||||
rebuild repository
|
||||
.TP
|
||||
@ -94,6 +100,9 @@ remove unknown packages
|
||||
\fBahriman\fR \fI\,repo-report\/\fR
|
||||
generate report
|
||||
.TP
|
||||
\fBahriman\fR \fI\,repo-restore\/\fR
|
||||
restore repository data
|
||||
.TP
|
||||
\fBahriman\fR \fI\,repo-setup\/\fR
|
||||
initial service configuration
|
||||
.TP
|
||||
@ -112,14 +121,17 @@ update packages
|
||||
\fBahriman\fR \fI\,user-add\/\fR
|
||||
create or update user
|
||||
.TP
|
||||
\fBahriman\fR \fI\,user-list\/\fR
|
||||
user known users and their access
|
||||
.TP
|
||||
\fBahriman\fR \fI\,user-remove\/\fR
|
||||
remove user
|
||||
.TP
|
||||
\fBahriman\fR \fI\,web\/\fR
|
||||
web server
|
||||
.SH OPTIONS 'ahriman aur-search'
|
||||
usage: ahriman aur-search [-h] [-i]
|
||||
[--sort-by {category_id,description,first_submitted,id,last_modified,license,maintainer,name,num_votes,out_of_date,package_base,package_base_id,url,url_path,version}]
|
||||
usage: ahriman aur-search [-h] [-e] [-i]
|
||||
[--sort-by {description,first_submitted,id,last_modified,maintainer,name,num_votes,out_of_date,package_base,package_base_id,popularity,url,url_path,version}]
|
||||
search [search ...]
|
||||
|
||||
search for package in AUR using API
|
||||
@ -128,18 +140,22 @@ search for package in AUR using API
|
||||
\fBsearch\fR
|
||||
search terms, can be specified multiple times, result will match all terms
|
||||
|
||||
.TP
|
||||
\fB\-e\fR, \fB\-\-exit\-code\fR
|
||||
return non\-zero exit status if result is empty
|
||||
|
||||
.TP
|
||||
\fB\-i\fR, \fB\-\-info\fR
|
||||
show additional package information
|
||||
|
||||
.TP
|
||||
\fB\-\-sort\-by\fR {category_id,description,first_submitted,id,last_modified,license,maintainer,name,num_votes,out_of_date,package_base,package_base_id,url,url_path,version}
|
||||
\fB\-\-sort\-by\fR {description,first_submitted,id,last_modified,maintainer,name,num_votes,out_of_date,package_base,package_base_id,popularity,url,url_path,version}
|
||||
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
|
||||
|
||||
.SH OPTIONS 'ahriman search'
|
||||
usage: ahriman aur-search [-h] [-i]
|
||||
[--sort-by {category_id,description,first_submitted,id,last_modified,license,maintainer,name,num_votes,out_of_date,package_base,package_base_id,url,url_path,version}]
|
||||
usage: ahriman aur-search [-h] [-e] [-i]
|
||||
[--sort-by {description,first_submitted,id,last_modified,maintainer,name,num_votes,out_of_date,package_base,package_base_id,popularity,url,url_path,version}]
|
||||
search [search ...]
|
||||
|
||||
search for package in AUR using API
|
||||
@ -148,15 +164,40 @@ search for package in AUR using API
|
||||
\fBsearch\fR
|
||||
search terms, can be specified multiple times, result will match all terms
|
||||
|
||||
.TP
|
||||
\fB\-e\fR, \fB\-\-exit\-code\fR
|
||||
return non\-zero exit status if result is empty
|
||||
|
||||
.TP
|
||||
\fB\-i\fR, \fB\-\-info\fR
|
||||
show additional package information
|
||||
|
||||
.TP
|
||||
\fB\-\-sort\-by\fR {category_id,description,first_submitted,id,last_modified,license,maintainer,name,num_votes,out_of_date,package_base,package_base_id,url,url_path,version}
|
||||
\fB\-\-sort\-by\fR {description,first_submitted,id,last_modified,maintainer,name,num_votes,out_of_date,package_base,package_base_id,popularity,url,url_path,version}
|
||||
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
|
||||
|
||||
.SH OPTIONS 'ahriman help'
|
||||
usage: ahriman help [-h] [command]
|
||||
|
||||
show help message for application or command and exit
|
||||
|
||||
.TP
|
||||
\fBcommand\fR
|
||||
show help message for specific command
|
||||
|
||||
|
||||
.SH OPTIONS 'ahriman help-commands-unsafe'
|
||||
usage: ahriman help-commands-unsafe [-h] [--command COMMAND]
|
||||
|
||||
list unsafe commands as defined in default args
|
||||
|
||||
|
||||
.TP
|
||||
\fB\-\-command\fR \fI\,COMMAND\/\fR
|
||||
instead of showing commands, just test command line for unsafe subcommand and return 0 in case if command is safe and 1
|
||||
otherwise
|
||||
|
||||
.SH OPTIONS 'ahriman key-import'
|
||||
usage: ahriman key-import [-h] [--key-server KEY_SERVER] key
|
||||
|
||||
@ -171,8 +212,8 @@ PGP key to import from public server
|
||||
key server for key import
|
||||
|
||||
.SH OPTIONS 'ahriman package-add'
|
||||
usage: ahriman package-add [-h] [-n]
|
||||
[-s {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote}]
|
||||
usage: ahriman package-add [-h] [-e] [-n]
|
||||
[-s {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote,PackageSource.Repository}]
|
||||
[--without-dependencies]
|
||||
package [package ...]
|
||||
|
||||
@ -182,12 +223,16 @@ add existing or new package to the build queue
|
||||
\fBpackage\fR
|
||||
package source (base name, path to local files, remote URL)
|
||||
|
||||
.TP
|
||||
\fB\-e\fR, \fB\-\-exit\-code\fR
|
||||
return non\-zero exit status if result is empty
|
||||
|
||||
.TP
|
||||
\fB\-n\fR, \fB\-\-now\fR
|
||||
run update function after
|
||||
|
||||
.TP
|
||||
\fB\-s\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote}, \fB\-\-source\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote}
|
||||
\fB\-s\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote,PackageSource.Repository}, \fB\-\-source\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote,PackageSource.Repository}
|
||||
explicitly specify the package source for this command
|
||||
|
||||
.TP
|
||||
@ -195,8 +240,8 @@ explicitly specify the package source for this command
|
||||
do not add dependencies
|
||||
|
||||
.SH OPTIONS 'ahriman add'
|
||||
usage: ahriman package-add [-h] [-n]
|
||||
[-s {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote}]
|
||||
usage: ahriman package-add [-h] [-e] [-n]
|
||||
[-s {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote,PackageSource.Repository}]
|
||||
[--without-dependencies]
|
||||
package [package ...]
|
||||
|
||||
@ -206,12 +251,16 @@ add existing or new package to the build queue
|
||||
\fBpackage\fR
|
||||
package source (base name, path to local files, remote URL)
|
||||
|
||||
.TP
|
||||
\fB\-e\fR, \fB\-\-exit\-code\fR
|
||||
return non\-zero exit status if result is empty
|
||||
|
||||
.TP
|
||||
\fB\-n\fR, \fB\-\-now\fR
|
||||
run update function after
|
||||
|
||||
.TP
|
||||
\fB\-s\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote}, \fB\-\-source\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote}
|
||||
\fB\-s\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote,PackageSource.Repository}, \fB\-\-source\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote,PackageSource.Repository}
|
||||
explicitly specify the package source for this command
|
||||
|
||||
.TP
|
||||
@ -219,8 +268,8 @@ explicitly specify the package source for this command
|
||||
do not add dependencies
|
||||
|
||||
.SH OPTIONS 'ahriman package-update'
|
||||
usage: ahriman package-add [-h] [-n]
|
||||
[-s {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote}]
|
||||
usage: ahriman package-add [-h] [-e] [-n]
|
||||
[-s {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote,PackageSource.Repository}]
|
||||
[--without-dependencies]
|
||||
package [package ...]
|
||||
|
||||
@ -230,12 +279,16 @@ add existing or new package to the build queue
|
||||
\fBpackage\fR
|
||||
package source (base name, path to local files, remote URL)
|
||||
|
||||
.TP
|
||||
\fB\-e\fR, \fB\-\-exit\-code\fR
|
||||
return non\-zero exit status if result is empty
|
||||
|
||||
.TP
|
||||
\fB\-n\fR, \fB\-\-now\fR
|
||||
run update function after
|
||||
|
||||
.TP
|
||||
\fB\-s\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote}, \fB\-\-source\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote}
|
||||
\fB\-s\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote,PackageSource.Repository}, \fB\-\-source\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote,PackageSource.Repository}
|
||||
explicitly specify the package source for this command
|
||||
|
||||
.TP
|
||||
@ -263,7 +316,7 @@ package name or base
|
||||
|
||||
|
||||
.SH OPTIONS 'ahriman package-status'
|
||||
usage: ahriman package-status [-h] [--ahriman] [-i]
|
||||
usage: ahriman package-status [-h] [--ahriman] [-e] [-i]
|
||||
[-s {BuildStatusEnum.Unknown,BuildStatusEnum.Pending,BuildStatusEnum.Building,BuildStatusEnum.Failed,BuildStatusEnum.Success}]
|
||||
[package ...]
|
||||
|
||||
@ -277,6 +330,10 @@ filter status by package base
|
||||
\fB\-\-ahriman\fR
|
||||
get service status itself
|
||||
|
||||
.TP
|
||||
\fB\-e\fR, \fB\-\-exit\-code\fR
|
||||
return non\-zero exit status if result is empty
|
||||
|
||||
.TP
|
||||
\fB\-i\fR, \fB\-\-info\fR
|
||||
show additional package information
|
||||
@ -286,7 +343,7 @@ show additional package information
|
||||
filter packages by status
|
||||
|
||||
.SH OPTIONS 'ahriman status'
|
||||
usage: ahriman package-status [-h] [--ahriman] [-i]
|
||||
usage: ahriman package-status [-h] [--ahriman] [-e] [-i]
|
||||
[-s {BuildStatusEnum.Unknown,BuildStatusEnum.Pending,BuildStatusEnum.Building,BuildStatusEnum.Failed,BuildStatusEnum.Success}]
|
||||
[package ...]
|
||||
|
||||
@ -300,6 +357,10 @@ filter status by package base
|
||||
\fB\-\-ahriman\fR
|
||||
get service status itself
|
||||
|
||||
.TP
|
||||
\fB\-e\fR, \fB\-\-exit\-code\fR
|
||||
return non\-zero exit status if result is empty
|
||||
|
||||
.TP
|
||||
\fB\-i\fR, \fB\-\-info\fR
|
||||
show additional package information
|
||||
@ -362,7 +423,7 @@ path to directory with changed files for patch addition/update
|
||||
files which has to be tracked
|
||||
|
||||
.SH OPTIONS 'ahriman patch-list'
|
||||
usage: ahriman patch-list [-h] package
|
||||
usage: ahriman patch-list [-h] [-e] [package]
|
||||
|
||||
list available patches for the package
|
||||
|
||||
@ -370,6 +431,9 @@ list available patches for the package
|
||||
\fBpackage\fR
|
||||
package base
|
||||
|
||||
.TP
|
||||
\fB\-e\fR, \fB\-\-exit\-code\fR
|
||||
return non\-zero exit status if result is empty
|
||||
|
||||
.SH OPTIONS 'ahriman patch-remove'
|
||||
usage: ahriman patch-remove [-h] package
|
||||
@ -381,8 +445,18 @@ remove patches for the package
|
||||
package base
|
||||
|
||||
|
||||
.SH OPTIONS 'ahriman repo-backup'
|
||||
usage: ahriman repo-backup [-h] path
|
||||
|
||||
backup settings and database
|
||||
|
||||
.TP
|
||||
\fBpath\fR
|
||||
path of the output archive
|
||||
|
||||
|
||||
.SH OPTIONS 'ahriman repo-check'
|
||||
usage: ahriman repo-check [-h] [--no-vcs] [package ...]
|
||||
usage: ahriman repo-check [-h] [-e] [--no-vcs] [package ...]
|
||||
|
||||
check for packages updates. Same as update \-\-dry\-run \-\-no\-manual
|
||||
|
||||
@ -390,12 +464,16 @@ check for packages updates. Same as update \-\-dry\-run \-\-no\-manual
|
||||
\fBpackage\fR
|
||||
filter check by package base
|
||||
|
||||
.TP
|
||||
\fB\-e\fR, \fB\-\-exit\-code\fR
|
||||
return non\-zero exit status if result is empty
|
||||
|
||||
.TP
|
||||
\fB\-\-no\-vcs\fR
|
||||
do not check VCS packages
|
||||
|
||||
.SH OPTIONS 'ahriman check'
|
||||
usage: ahriman repo-check [-h] [--no-vcs] [package ...]
|
||||
usage: ahriman repo-check [-h] [-e] [--no-vcs] [package ...]
|
||||
|
||||
check for packages updates. Same as update \-\-dry\-run \-\-no\-manual
|
||||
|
||||
@ -403,20 +481,20 @@ check for packages updates. Same as update \-\-dry\-run \-\-no\-manual
|
||||
\fBpackage\fR
|
||||
filter check by package base
|
||||
|
||||
.TP
|
||||
\fB\-e\fR, \fB\-\-exit\-code\fR
|
||||
return non\-zero exit status if result is empty
|
||||
|
||||
.TP
|
||||
\fB\-\-no\-vcs\fR
|
||||
do not check VCS packages
|
||||
|
||||
.SH OPTIONS 'ahriman repo-clean'
|
||||
usage: ahriman repo-clean [-h] [--build] [--cache] [--chroot] [--manual] [--packages] [--patches]
|
||||
usage: ahriman repo-clean [-h] [--cache] [--chroot] [--manual] [--packages]
|
||||
|
||||
remove local caches
|
||||
|
||||
|
||||
.TP
|
||||
\fB\-\-build\fR
|
||||
clear directory with package sources
|
||||
|
||||
.TP
|
||||
\fB\-\-cache\fR
|
||||
clear directory with package caches
|
||||
@ -427,26 +505,18 @@ clear build chroot
|
||||
|
||||
.TP
|
||||
\fB\-\-manual\fR
|
||||
clear directory with manually added packages
|
||||
clear manually added packages queue
|
||||
|
||||
.TP
|
||||
\fB\-\-packages\fR
|
||||
clear directory with built packages
|
||||
|
||||
.TP
|
||||
\fB\-\-patches\fR
|
||||
clear directory with patches
|
||||
|
||||
.SH OPTIONS 'ahriman clean'
|
||||
usage: ahriman repo-clean [-h] [--build] [--cache] [--chroot] [--manual] [--packages] [--patches]
|
||||
usage: ahriman repo-clean [-h] [--cache] [--chroot] [--manual] [--packages]
|
||||
|
||||
remove local caches
|
||||
|
||||
|
||||
.TP
|
||||
\fB\-\-build\fR
|
||||
clear directory with package sources
|
||||
|
||||
.TP
|
||||
\fB\-\-cache\fR
|
||||
clear directory with package caches
|
||||
@ -457,16 +527,12 @@ clear build chroot
|
||||
|
||||
.TP
|
||||
\fB\-\-manual\fR
|
||||
clear directory with manually added packages
|
||||
clear manually added packages queue
|
||||
|
||||
.TP
|
||||
\fB\-\-packages\fR
|
||||
clear directory with built packages
|
||||
|
||||
.TP
|
||||
\fB\-\-patches\fR
|
||||
clear directory with patches
|
||||
|
||||
.SH OPTIONS 'ahriman repo-config'
|
||||
usage: ahriman repo-config [-h]
|
||||
|
||||
@ -481,22 +547,8 @@ dump configuration for the specified architecture
|
||||
|
||||
|
||||
|
||||
.SH OPTIONS 'ahriman repo-init'
|
||||
usage: ahriman repo-init [-h]
|
||||
|
||||
create empty repository tree. Optional command for auto architecture support
|
||||
|
||||
|
||||
|
||||
.SH OPTIONS 'ahriman init'
|
||||
usage: ahriman repo-init [-h]
|
||||
|
||||
create empty repository tree. Optional command for auto architecture support
|
||||
|
||||
|
||||
|
||||
.SH OPTIONS 'ahriman repo-rebuild'
|
||||
usage: ahriman repo-rebuild [-h] [--depends-on DEPENDS_ON]
|
||||
usage: ahriman repo-rebuild [-h] [--depends-on DEPENDS_ON] [--dry-run] [--from-database] [-e]
|
||||
|
||||
force rebuild whole repository
|
||||
|
||||
@ -505,8 +557,22 @@ force rebuild whole repository
|
||||
\fB\-\-depends\-on\fR \fI\,DEPENDS_ON\/\fR
|
||||
only rebuild packages that depend on specified package
|
||||
|
||||
.TP
|
||||
\fB\-\-dry\-run\fR
|
||||
just perform check for packages without rebuild process itself
|
||||
|
||||
.TP
|
||||
\fB\-\-from\-database\fR
|
||||
read packages from database instead of filesystem. This feature in particular is required in case if you would like to
|
||||
restore repository from another repository instance. Note however that in order to restore packages you need to have
|
||||
original ahriman instance run with web service and have run repo\-update at least once.
|
||||
|
||||
.TP
|
||||
\fB\-e\fR, \fB\-\-exit\-code\fR
|
||||
return non\-zero exit status if result is empty
|
||||
|
||||
.SH OPTIONS 'ahriman rebuild'
|
||||
usage: ahriman repo-rebuild [-h] [--depends-on DEPENDS_ON]
|
||||
usage: ahriman repo-rebuild [-h] [--depends-on DEPENDS_ON] [--dry-run] [--from-database] [-e]
|
||||
|
||||
force rebuild whole repository
|
||||
|
||||
@ -515,6 +581,20 @@ force rebuild whole repository
|
||||
\fB\-\-depends\-on\fR \fI\,DEPENDS_ON\/\fR
|
||||
only rebuild packages that depend on specified package
|
||||
|
||||
.TP
|
||||
\fB\-\-dry\-run\fR
|
||||
just perform check for packages without rebuild process itself
|
||||
|
||||
.TP
|
||||
\fB\-\-from\-database\fR
|
||||
read packages from database instead of filesystem. This feature in particular is required in case if you would like to
|
||||
restore repository from another repository instance. Note however that in order to restore packages you need to have
|
||||
original ahriman instance run with web service and have run repo\-update at least once.
|
||||
|
||||
.TP
|
||||
\fB\-e\fR, \fB\-\-exit\-code\fR
|
||||
return non\-zero exit status if result is empty
|
||||
|
||||
.SH OPTIONS 'ahriman repo-remove-unknown'
|
||||
usage: ahriman repo-remove-unknown [-h] [--dry-run] [-i]
|
||||
|
||||
@ -563,14 +643,122 @@ generate repository report according to current settings
|
||||
target to generate report
|
||||
|
||||
|
||||
.SH OPTIONS 'ahriman repo-restore'
|
||||
usage: ahriman repo-restore [-h] [-o OUTPUT] path
|
||||
|
||||
restore settings and database
|
||||
|
||||
.TP
|
||||
\fBpath\fR
|
||||
path of the input archive
|
||||
|
||||
.TP
|
||||
\fB\-o\fR \fI\,OUTPUT\/\fR, \fB\-\-output\fR \fI\,OUTPUT\/\fR
|
||||
root path of the extracted files
|
||||
|
||||
.SH OPTIONS 'ahriman repo-setup'
|
||||
usage: ahriman repo-setup [-h] [--build-command BUILD_COMMAND] [--from-configuration FROM_CONFIGURATION] [--no-multilib]
|
||||
--packager PACKAGER --repository REPOSITORY [--sign-key SIGN_KEY]
|
||||
usage: ahriman repo-setup [-h] [--build-as-user BUILD_AS_USER] [--build-command BUILD_COMMAND]
|
||||
[--from-configuration FROM_CONFIGURATION] [--no-multilib] --packager PACKAGER --repository
|
||||
REPOSITORY [--sign-key SIGN_KEY]
|
||||
[--sign-target {SignSettings.Packages,SignSettings.Repository}] [--web-port WEB_PORT]
|
||||
|
||||
create initial service configuration, requires root
|
||||
|
||||
|
||||
.TP
|
||||
\fB\-\-build\-as\-user\fR \fI\,BUILD_AS_USER\/\fR
|
||||
force makepkg user to the specific one
|
||||
|
||||
.TP
|
||||
\fB\-\-build\-command\fR \fI\,BUILD_COMMAND\/\fR
|
||||
build command prefix
|
||||
|
||||
.TP
|
||||
\fB\-\-from\-configuration\fR \fI\,FROM_CONFIGURATION\/\fR
|
||||
path to default devtools pacman configuration
|
||||
|
||||
.TP
|
||||
\fB\-\-no\-multilib\fR
|
||||
do not add multilib repository
|
||||
|
||||
.TP
|
||||
\fB\-\-packager\fR \fI\,PACKAGER\/\fR
|
||||
packager name and email
|
||||
|
||||
.TP
|
||||
\fB\-\-repository\fR \fI\,REPOSITORY\/\fR
|
||||
repository name
|
||||
|
||||
.TP
|
||||
\fB\-\-sign\-key\fR \fI\,SIGN_KEY\/\fR
|
||||
sign key id
|
||||
|
||||
.TP
|
||||
\fB\-\-sign\-target\fR {SignSettings.Packages,SignSettings.Repository}
|
||||
sign options
|
||||
|
||||
.TP
|
||||
\fB\-\-web\-port\fR \fI\,WEB_PORT\/\fR
|
||||
port of the web service
|
||||
|
||||
.SH OPTIONS 'ahriman init'
|
||||
usage: ahriman repo-setup [-h] [--build-as-user BUILD_AS_USER] [--build-command BUILD_COMMAND]
|
||||
[--from-configuration FROM_CONFIGURATION] [--no-multilib] --packager PACKAGER --repository
|
||||
REPOSITORY [--sign-key SIGN_KEY]
|
||||
[--sign-target {SignSettings.Packages,SignSettings.Repository}] [--web-port WEB_PORT]
|
||||
|
||||
create initial service configuration, requires root
|
||||
|
||||
|
||||
.TP
|
||||
\fB\-\-build\-as\-user\fR \fI\,BUILD_AS_USER\/\fR
|
||||
force makepkg user to the specific one
|
||||
|
||||
.TP
|
||||
\fB\-\-build\-command\fR \fI\,BUILD_COMMAND\/\fR
|
||||
build command prefix
|
||||
|
||||
.TP
|
||||
\fB\-\-from\-configuration\fR \fI\,FROM_CONFIGURATION\/\fR
|
||||
path to default devtools pacman configuration
|
||||
|
||||
.TP
|
||||
\fB\-\-no\-multilib\fR
|
||||
do not add multilib repository
|
||||
|
||||
.TP
|
||||
\fB\-\-packager\fR \fI\,PACKAGER\/\fR
|
||||
packager name and email
|
||||
|
||||
.TP
|
||||
\fB\-\-repository\fR \fI\,REPOSITORY\/\fR
|
||||
repository name
|
||||
|
||||
.TP
|
||||
\fB\-\-sign\-key\fR \fI\,SIGN_KEY\/\fR
|
||||
sign key id
|
||||
|
||||
.TP
|
||||
\fB\-\-sign\-target\fR {SignSettings.Packages,SignSettings.Repository}
|
||||
sign options
|
||||
|
||||
.TP
|
||||
\fB\-\-web\-port\fR \fI\,WEB_PORT\/\fR
|
||||
port of the web service
|
||||
|
||||
.SH OPTIONS 'ahriman repo-init'
|
||||
usage: ahriman repo-setup [-h] [--build-as-user BUILD_AS_USER] [--build-command BUILD_COMMAND]
|
||||
[--from-configuration FROM_CONFIGURATION] [--no-multilib] --packager PACKAGER --repository
|
||||
REPOSITORY [--sign-key SIGN_KEY]
|
||||
[--sign-target {SignSettings.Packages,SignSettings.Repository}] [--web-port WEB_PORT]
|
||||
|
||||
create initial service configuration, requires root
|
||||
|
||||
|
||||
.TP
|
||||
\fB\-\-build\-as\-user\fR \fI\,BUILD_AS_USER\/\fR
|
||||
force makepkg user to the specific one
|
||||
|
||||
.TP
|
||||
\fB\-\-build\-command\fR \fI\,BUILD_COMMAND\/\fR
|
||||
build command prefix
|
||||
@ -604,13 +792,18 @@ sign options
|
||||
port of the web service
|
||||
|
||||
.SH OPTIONS 'ahriman setup'
|
||||
usage: ahriman repo-setup [-h] [--build-command BUILD_COMMAND] [--from-configuration FROM_CONFIGURATION] [--no-multilib]
|
||||
--packager PACKAGER --repository REPOSITORY [--sign-key SIGN_KEY]
|
||||
usage: ahriman repo-setup [-h] [--build-as-user BUILD_AS_USER] [--build-command BUILD_COMMAND]
|
||||
[--from-configuration FROM_CONFIGURATION] [--no-multilib] --packager PACKAGER --repository
|
||||
REPOSITORY [--sign-key SIGN_KEY]
|
||||
[--sign-target {SignSettings.Packages,SignSettings.Repository}] [--web-port WEB_PORT]
|
||||
|
||||
create initial service configuration, requires root
|
||||
|
||||
|
||||
.TP
|
||||
\fB\-\-build\-as\-user\fR \fI\,BUILD_AS_USER\/\fR
|
||||
force makepkg user to the specific one
|
||||
|
||||
.TP
|
||||
\fB\-\-build\-command\fR \fI\,BUILD_COMMAND\/\fR
|
||||
build command prefix
|
||||
@ -695,7 +888,7 @@ target to sync
|
||||
|
||||
|
||||
.SH OPTIONS 'ahriman repo-update'
|
||||
usage: ahriman repo-update [-h] [--dry-run] [--no-aur] [--no-manual] [--no-vcs] [package ...]
|
||||
usage: ahriman repo-update [-h] [--dry-run] [-e] [--no-aur] [--no-local] [--no-manual] [--no-vcs] [package ...]
|
||||
|
||||
check for packages updates and run build process if requested
|
||||
|
||||
@ -707,10 +900,18 @@ filter check by package base
|
||||
\fB\-\-dry\-run\fR
|
||||
just perform check for updates, same as check command
|
||||
|
||||
.TP
|
||||
\fB\-e\fR, \fB\-\-exit\-code\fR
|
||||
return non\-zero exit status if result is empty
|
||||
|
||||
.TP
|
||||
\fB\-\-no\-aur\fR
|
||||
do not check for AUR updates. Implies \-\-no\-vcs
|
||||
|
||||
.TP
|
||||
\fB\-\-no\-local\fR
|
||||
do not check local packages for updates
|
||||
|
||||
.TP
|
||||
\fB\-\-no\-manual\fR
|
||||
do not include manual updates
|
||||
@ -720,7 +921,7 @@ do not include manual updates
|
||||
do not check VCS packages
|
||||
|
||||
.SH OPTIONS 'ahriman update'
|
||||
usage: ahriman repo-update [-h] [--dry-run] [--no-aur] [--no-manual] [--no-vcs] [package ...]
|
||||
usage: ahriman repo-update [-h] [--dry-run] [-e] [--no-aur] [--no-local] [--no-manual] [--no-vcs] [package ...]
|
||||
|
||||
check for packages updates and run build process if requested
|
||||
|
||||
@ -732,10 +933,18 @@ filter check by package base
|
||||
\fB\-\-dry\-run\fR
|
||||
just perform check for updates, same as check command
|
||||
|
||||
.TP
|
||||
\fB\-e\fR, \fB\-\-exit\-code\fR
|
||||
return non\-zero exit status if result is empty
|
||||
|
||||
.TP
|
||||
\fB\-\-no\-aur\fR
|
||||
do not check for AUR updates. Implies \-\-no\-vcs
|
||||
|
||||
.TP
|
||||
\fB\-\-no\-local\fR
|
||||
do not check local packages for updates
|
||||
|
||||
.TP
|
||||
\fB\-\-no\-manual\fR
|
||||
do not include manual updates
|
||||
@ -745,8 +954,7 @@ do not include manual updates
|
||||
do not check VCS packages
|
||||
|
||||
.SH OPTIONS 'ahriman user-add'
|
||||
usage: ahriman user-add [-h] [--as-service] [--no-reload] [-p PASSWORD]
|
||||
[-r {UserAccess.Safe,UserAccess.Read,UserAccess.Write}] [-s]
|
||||
usage: ahriman user-add [-h] [--as-service] [-p PASSWORD] [-r {UserAccess.Safe,UserAccess.Read,UserAccess.Write}] [-s]
|
||||
username
|
||||
|
||||
update user for web services with the given password and role. In case if password was not entered it will be asked interactively
|
||||
@ -759,10 +967,6 @@ username for web service
|
||||
\fB\-\-as\-service\fR
|
||||
add user as service user
|
||||
|
||||
.TP
|
||||
\fB\-\-no\-reload\fR
|
||||
do not reload authentication module
|
||||
|
||||
.TP
|
||||
\fB\-p\fR \fI\,PASSWORD\/\fR, \fB\-\-password\fR \fI\,PASSWORD\/\fR
|
||||
user password. Blank password will be treated as empty password, which is in particular must be used for OAuth2
|
||||
@ -776,8 +980,25 @@ user access level
|
||||
\fB\-s\fR, \fB\-\-secure\fR
|
||||
set file permissions to user\-only
|
||||
|
||||
.SH OPTIONS 'ahriman user-list'
|
||||
usage: ahriman user-list [-h] [-e] [-r {UserAccess.Safe,UserAccess.Read,UserAccess.Write}] [username]
|
||||
|
||||
list users from the user mapping and their roles
|
||||
|
||||
.TP
|
||||
\fBusername\fR
|
||||
filter users by username
|
||||
|
||||
.TP
|
||||
\fB\-e\fR, \fB\-\-exit\-code\fR
|
||||
return non\-zero exit status if result is empty
|
||||
|
||||
.TP
|
||||
\fB\-r\fR {UserAccess.Safe,UserAccess.Read,UserAccess.Write}, \fB\-\-role\fR {UserAccess.Safe,UserAccess.Read,UserAccess.Write}
|
||||
filter users by role
|
||||
|
||||
.SH OPTIONS 'ahriman user-remove'
|
||||
usage: ahriman user-remove [-h] [--no-reload] [-s] username
|
||||
usage: ahriman user-remove [-h] [-s] username
|
||||
|
||||
remove user from the user mapping and update the configuration
|
||||
|
||||
@ -785,10 +1006,6 @@ remove user from the user mapping and update the configuration
|
||||
\fBusername\fR
|
||||
username for web service
|
||||
|
||||
.TP
|
||||
\fB\-\-no\-reload\fR
|
||||
do not reload authentication module
|
||||
|
||||
.TP
|
||||
\fB\-s\fR, \fB\-\-secure\fR
|
||||
set file permissions to user\-only
|
||||
|
@ -16,8 +16,6 @@ This package contains application (aka executable) related classes and everythin
|
||||
|
||||
`ahriman.application.application.application.Application` (god class) is used for any interaction from parsers with repository, web etc. It is divided into multiple traits by functions (package related and repository related) in the same package.
|
||||
|
||||
`ahriman.application.formatters` package provides `Printer` sub-classes for printing data (e.g. package properties) to stdout which are used by some handlers.
|
||||
|
||||
`ahriman.application.ahriman` contains only command line parses and executes specified `Handler` on success, `ahriman.application.lock.Lock` is additional class which provides file-based lock and also performs some common checks.
|
||||
|
||||
## `ahriman.core` package
|
||||
@ -27,6 +25,8 @@ This package contains everything which is required for any time of application r
|
||||
* `ahriman.core.alpm` package controls pacman related functions. It provides wrappers for `pyalpm` library and safe calls for repository tools (`repo-add` and `repo-remove`).
|
||||
* `ahriman.core.auth` package provides classes for authorization methods used by web mostly. Base class is `ahriman.core.auth.auth.Auth` which must be called by `load` method.
|
||||
* `ahriman.core.build_tools` is a package which provides wrapper for `devtools` commands.
|
||||
* `ahriman.core.database` is everything including data and schema migrations for database.
|
||||
* `ahriman.core.formatters` package provides `Printer` sub-classes for printing data (e.g. package properties) to stdout which are used by some handlers.
|
||||
* `ahriman.core.report` is a package with reporting classes. Usually it must be called by `ahriman.core.report.report.Report.load` method.
|
||||
* `ahriman.core.repository` contains several traits and base repository (`ahriman.core.repository.repository.Repository` class) implementation.
|
||||
* `ahriman.core.sign` package provides sign feature (only gpg calls are available).
|
||||
@ -61,11 +61,34 @@ Web application. It is important that this package is isolated from any other to
|
||||
* In each child process call lock functions.
|
||||
* After success checks pass control to `Handler.run` method defined by specific handler class.
|
||||
* Return result (success or failure) of each subprocess and exit from application.
|
||||
* Some handlers may override their status and throw `ExitCode` exception. This exception is just silently suppressed and changes application exit code to `1`.
|
||||
|
||||
In most cases handlers spawn god class `ahriman.application.application.Application` class and call required methods.
|
||||
|
||||
Application is designed to run from `systemd` services and provides parametrized by architecture timer and service file for that.
|
||||
|
||||
# Database
|
||||
|
||||
The service uses SQLite database in order to store some internal info.
|
||||
|
||||
## Database instance
|
||||
|
||||
All methods related to specific part of database (basically operations per table) are split into different traits located inside `ahriman.core.database.operations` package. The base trait `ahriman.core.database.operations.operations.Operations` also provides generic methods for database access (e.g. row converters and transactional support).
|
||||
|
||||
The `ahriman.core.database.sqlite.SQLite` class itself derives from all of these traits and implements methods for initialization, including migrations.
|
||||
|
||||
## Schema and data migrations
|
||||
|
||||
The schema migration are applied according to current `pragma user_info` values, located at `ahriman.core.database.migrations` package and named as `m000_migration_name.py` (the preceding `m` is required in order to import migration content for tests). Additional class `ahriman.core.database.migrations.Migrations` reads all migrations autmatically and applies them in alphabetical order.
|
||||
|
||||
There are also data migrations which are located at `ahriman.core.database.data` package and move data from old-style (e.g. json files in filesystem, directory trees, etc) to the database. They are also part of migration and (unlike schema migrations) are applied only at specific version breakpoints (e.g. if `user_version` is more than 0 no initial migration will be applied).
|
||||
|
||||
## Type conversions
|
||||
|
||||
By default, it parses rows into python dictionary. In addition, the following pseudo-types are supported:
|
||||
|
||||
* `Dict[str, Any]`, `List[Any]` - for storing JSON data structures in database (technically there is no restriction on types for dictionary keys and values, but it is recommended to use only string keys). The type is stored as `json` datatype and `json.loads` and `json.dumps` methods are used in order to read and write from/to database respectively.
|
||||
|
||||
# Basic flows
|
||||
|
||||
## Add new packages or rebuild existing
|
||||
@ -122,21 +145,21 @@ The package provides several authorization methods: disabled, based on configura
|
||||
|
||||
Disabled (default) authorization provider just allows everything for everyone and does not have any specific configuration (it uses some default configuration parameters though). It also provides generic interface for derived classes.
|
||||
|
||||
Mapping (aka configuration) provider uses hashed passwords with salt from configuration file in order to authenticate users. This provider also enables user permission checking (read/write) (authorization). Thus, it defines the following methods:
|
||||
Mapping (aka configuration) provider uses hashed passwords with salt from the database in order to authenticate users. This provider also enables user permission checking (read/write) (authorization). Thus, it defines the following methods:
|
||||
|
||||
* `check_credentials` - user password validation (authentication).
|
||||
* `verify_access` - user permission validation (authorization).
|
||||
|
||||
Passwords must be stored in configuration as `hash(password + salt)`, where `password` is user defined password (taken from user input), `salt` is random string (any length) defined globally in configuration and `hash` is secure hash function. Thus, the following configuration
|
||||
Passwords must be stored in database as `hash(password + salt)`, where `password` is user defined password (taken from user input), `salt` is random string (any length) defined globally in configuration and `hash` is secure hash function. Thus, the following configuration
|
||||
|
||||
```ini
|
||||
[auth:read]
|
||||
username = $6$rounds=656000$mWBiecMPrHAL1VgX$oU4Y5HH8HzlvMaxwkNEJjK13ozElyU1wAHBoO/WW5dAaE4YEfnB0X3FxbynKMl4FBdC3Ovap0jINz4LPkNADg0
|
||||
```csv
|
||||
"username","password","access"
|
||||
"username","$6$rounds=656000$mWBiecMPrHAL1VgX$oU4Y5HH8HzlvMaxwkNEJjK13ozElyU1wAHBoO/WW5dAaE4YEfnB0X3FxbynKMl4FBdC3Ovap0jINz4LPkNADg0","read"
|
||||
```
|
||||
|
||||
means that there is user `username` with `read` access and password `password` hashed by `sha512` with salt `salt`.
|
||||
|
||||
OAuth provider uses library definitions (`aioauth-client`) in order _authenticate_ users. It still requires user permission to be set in configuration, thus it inherits mapping provider without any changes. Whereas we could override `check_credentials` (authentication method) by something custom, OAuth flow is a bit more complex than just forward request, thus we have to implement the flow in login form.
|
||||
OAuth provider uses library definitions (`aioauth-client`) in order _authenticate_ users. It still requires user permission to be set in database, thus it inherits mapping provider without any changes. Whereas we could override `check_credentials` (authentication method) by something custom, OAuth flow is a bit more complex than just forward request, thus we have to implement the flow in login form.
|
||||
|
||||
OAuth's implementation also allows authenticating users via username + password (in the same way as mapping does) though it is not recommended for end-users and password must be left blank. In particular this feature is used by service reporting (aka robots).
|
||||
|
||||
|
@ -2,18 +2,21 @@
|
||||
|
||||
Some groups can be specified for each architecture separately. E.g. if there are `build` and `build:x86_64` groups it will use the option from `build:x86_64` for the `x86_64` architecture and `build` for any other (architecture specific group has higher priority). In case if both groups are presented, architecture specific options will be merged into global ones overriding them.
|
||||
|
||||
Some values have list of strings type. Those values will be read in the same way as shell does:
|
||||
There are two variable types which have been added to default ones, they are paths and lists. List values will be read in the same way as shell does:
|
||||
|
||||
* By default, it splits value by spaces excluding empty elements.
|
||||
* In case if quotation mark (`"` or `'`) will be found, any spaces inside will be ignored.
|
||||
* In order to use quotation mark inside value it is required to put it to another quotation mark, e.g. `wor"'"d "with quote"` will be parsed as `["wor'd", "with quote"]` and vice versa.
|
||||
* Unclosed quotation mark is not allowed and will rise an exception.
|
||||
|
||||
Path values, except for casting to `pathlib.Path` type, will be also expanded to absolute paths relative to the configuration path. E.g. if path is set to `ahriman.ini.d/logging.ini` and root configuration path is `/etc/ahriman.ini`, the value will be expanded to `/etc/ahriman.ini.d/logging.ini`. In order to disable path expand, use the full path, e.g. `/etc/ahriman.ini.d/logging.ini`.
|
||||
|
||||
## `settings` group
|
||||
|
||||
Base configuration settings.
|
||||
|
||||
* `include` - path to directory with configuration files overrides, string, required.
|
||||
* `database` - path to SQLite database, string, required.
|
||||
* `logging` - path to logging configuration, string, required. Check `logging.ini` for reference.
|
||||
|
||||
## `alpm` group
|
||||
@ -38,14 +41,7 @@ Base authorization settings. `OAuth` provider requires `aioauth-client` library
|
||||
* `safe_build_status` - allow requesting status page without authorization, boolean, required.
|
||||
* `salt` - password hash salt, string, required in case if authorization enabled (automatically generated by `create-user` subcommand).
|
||||
|
||||
## `auth:*` groups
|
||||
|
||||
Authorization mapping. Group name must refer to user access level, i.e. it should be one of `auth:read` (read hidden pages), `auth:write` (everything is allowed).
|
||||
|
||||
Key is always username (case-insensitive), option value depends on authorization provider:
|
||||
|
||||
* `OAuth` - by default requires only usernames and ignores values. But in case of direct login method call (via POST request) it will act as `Mapping` authorization method.
|
||||
* `Mapping` (default) - reads salted password hashes from values, uses SHA512 in order to hash passwords. Password can be set by using `user-add` subcommand.
|
||||
Authorized users are stored inside internal database, if any of external provides are used the password field for non-service users must be empty.
|
||||
|
||||
## `build:*` groups
|
||||
|
||||
@ -84,6 +80,12 @@ Type will be read from several ways:
|
||||
* Otherwise, it will look for type from section name removing architecture name.
|
||||
* And finally, it will use section name as type.
|
||||
|
||||
### `console` type
|
||||
|
||||
Section name must be either `console` (plus optional architecture name, e.g. `console:x86_64`) or random name with `type` set.
|
||||
|
||||
* `use_utf` - use utf8 symbols in output if set and ascii otherwise, boolean, optional, default `yes`.
|
||||
|
||||
### `email` type
|
||||
|
||||
Section name must be either `email` (plus optional architecture name, e.g. `email:x86_64`) or random name with `type` set.
|
||||
@ -112,6 +114,18 @@ Section name must be either `html` (plus optional architecture name, e.g. `html:
|
||||
* `link_path` - prefix for HTML links, string, required.
|
||||
* `template_path` - path to Jinja2 template, string, required.
|
||||
|
||||
### `telegram` type
|
||||
|
||||
Section name must be either `telegram` (plus optional architecture name, e.g. `telegram:x86_64`) or random name with `type` set.
|
||||
|
||||
* `type` - type of the report, string, optional, must be set to `telegram` if exists.
|
||||
* `api_key` - telegram bot API key, string, required. Please refer FAQ about how to create chat and bot
|
||||
* `chat_id` - telegram chat id, either string with `@` or integer value, required.
|
||||
* `homepage` - link to homepage, string, optional.
|
||||
* `link_path` - prefix for HTML links, string, required.
|
||||
* `template_path` - path to Jinja2 template, string, required.
|
||||
* `template_type` - `parse_mode` to be passed to telegram API, one of `MarkdownV2`, `HTML`, `Markdown`, string, optional, default `HTML`.
|
||||
|
||||
## `upload` group
|
||||
|
||||
Remote synchronization settings.
|
||||
|
138
docs/faq.md
138
docs/faq.md
@ -12,7 +12,6 @@ TL;DR
|
||||
|
||||
```shell
|
||||
yay -S ahriman
|
||||
sudo -u ahriman ahriman -a x86_64 init
|
||||
sudo ahriman -a x86_64 repo-setup --packager "ahriman bot <ahriman@example.com>" --repository "repository"
|
||||
systemctl enable --now ahriman@x86_64.timer
|
||||
```
|
||||
@ -198,6 +197,67 @@ server {
|
||||
}
|
||||
```
|
||||
|
||||
## Docker image
|
||||
|
||||
We provide official images which can be found under `arcan1s/ahriman` repository. Docker image is being updated on each master commit as well as on each version. If you would like to use last (probably unstable) build you can use `edge` tag or `latest` for any tagged versions; otherwise you can use any version tag available.
|
||||
|
||||
The default action (in case if no arguments provided) is `repo-update`. Basically the idea is to run container, e.g.:
|
||||
|
||||
```shell
|
||||
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 addition, you can pass own configuration overrides by using the same `-v` flag, e.g.:
|
||||
|
||||
```shell
|
||||
docker run -v /path/to/local/repo:/var/lib/ahriman -v /etc/ahriman.ini:/etc/ahriman.ini.d/10-overrides.ini arcan1s/ahriman:latest
|
||||
```
|
||||
|
||||
By default, it runs `repo-update`, but it can be overwritten to any other command you would like to, e.g.:
|
||||
|
||||
```shell
|
||||
docker run arcan1s/ahriman:latest package-add ahriman --now
|
||||
```
|
||||
|
||||
For more details please refer to docker FAQ.
|
||||
|
||||
### Environment variables
|
||||
|
||||
The following environment variables are supported:
|
||||
|
||||
* `AHRIMAN_ARCHITECTURE` - architecture of the repository, default is `x86_64`.
|
||||
* `AHRIMAN_DEBUG` - if set all commands will be logged to console.
|
||||
* `AHRIMAN_FORCE_ROOT` - force run ahriman as root instead of guessing by subcommand.
|
||||
* `AHRIMAN_HOST` - host for the web interface, default is `0.0.0.0`.
|
||||
* `AHRIMAN_OUTPUT` - controls logging handler, e.g. `syslog`, `console`. The name must be found in logging configuration. Note that if `syslog` (the default) handler is used you will need to mount `/dev/log` inside container because it is not available there.
|
||||
* `AHRIMAN_PACKAGER` - packager name from which packages will be built, default is `ahriman bot <ahriman@example.com>`.
|
||||
* `AHRIMAN_PORT` - HTTP server port if any, default is empty.
|
||||
* `AHRIMAN_REPOSITORY` - repository name, default is `aur-clone`.
|
||||
* `AHRIMAN_REPOSITORY_ROOT` - repository root. Because of filesystem rights it is required to override default repository root. By default, it uses `ahriman` directory inside ahriman's home, which can be passed as mount volume.
|
||||
* `AHRIMAN_USER` - ahriman user, usually must not be overwritten, default is `ahriman`.
|
||||
|
||||
You can pass any of these variables by using `-e` argument, e.g.:
|
||||
|
||||
```shell
|
||||
docker run -e AHRIMAN_PORT=8080 arcan1s/ahriman:latest
|
||||
```
|
||||
|
||||
### Web service setup
|
||||
|
||||
Well for that you would need to have web container instance running forever; it can be achieved by the following command:
|
||||
|
||||
```shell
|
||||
docker run -p 8080:8080 -e AHRIMAN_PORT=8080 -v /path/to/local/repo:/var/lib/ahriman arcan1s/ahriman:latest
|
||||
```
|
||||
|
||||
Note about `AHRIMAN_PORT` environment variable which is required in order to enable web service. An additional port bind by `-p 8080:8080` is required to pass docker port outside of container.
|
||||
|
||||
For every next container run use arguments `-e AHRIMAN_PORT=8080 --net=host`, e.g.:
|
||||
|
||||
```shell
|
||||
docker run --privileged -e AHRIMAN_PORT=8080 --net=host -v /path/to/local/repo:/var/lib/ahriman arcan1s/ahriman:latest
|
||||
```
|
||||
|
||||
## Remote synchronization
|
||||
|
||||
### Wait I would like to use the repository from another server
|
||||
@ -342,6 +402,46 @@ There are several choices:
|
||||
|
||||
After these steps `index.html` file will be automatically synced to S3
|
||||
|
||||
### I would like to get messages to my telegram account/channel
|
||||
|
||||
1. It still requires additional dependencies:
|
||||
|
||||
```shell
|
||||
yay -S python-jinja
|
||||
```
|
||||
|
||||
2. Register bot in telegram. You can do it by talking with [@BotFather](https://t.me/botfather). For more details please refer to [official documentation](https://core.telegram.org/bots).
|
||||
|
||||
3. Optionally (if you want to post message in chat):
|
||||
|
||||
1. Create telegram channel.
|
||||
2. Invite your bot into the channel.
|
||||
3. Make your channel public
|
||||
|
||||
4. Get chat id if you want to use by numerical id or just use id prefixed with `@` (e.g. `@ahriman`). If you are not using chat the chat id is your user id. If you don't want to make channel public you can use [this guide](https://stackoverflow.com/a/33862907).
|
||||
|
||||
5. Configure the service:
|
||||
|
||||
```ini
|
||||
[report]
|
||||
target = telegram
|
||||
|
||||
[telegram]
|
||||
api_key = aaAAbbBBccCC
|
||||
chat_id = @ahriman
|
||||
link_path = http://example.com/x86_64
|
||||
```
|
||||
|
||||
`api_key` is the one sent by [@BotFather](https://t.me/botfather), `chat_id` is the value retrieved from previous step.
|
||||
|
||||
If you did everything fine you should receive the message with the next update. Quick credentials check can be done by using the following command:
|
||||
|
||||
```shell
|
||||
curl 'https://api.telegram.org/bot${CHAT_ID}/sendMessage?chat_id=${API_KEY}&text=hello'
|
||||
```
|
||||
|
||||
(replace `${CHAT_ID}` and `${API_KEY}` with the values from configuration).
|
||||
|
||||
## Web service
|
||||
|
||||
### Readme mentions web interface, how do I use it?
|
||||
@ -419,6 +519,36 @@ After these steps `index.html` file will be automatically synced to S3
|
||||
5. Create end-user `sudo -u ahriman ahriman user-add -r write my-first-user`. When it will ask for the password leave it blank.
|
||||
6. Restart web service `systemctl restart ahriman-web@x86_64`.
|
||||
|
||||
## Backup and restore
|
||||
|
||||
The service provides several commands aim to do easy repository backup and restore. If you would like to move repository from the server `server1.example.com` to another `server2.example.com` you have to perform the following steps:
|
||||
|
||||
1. On the source server `server1.example.com` run `repo-backup` command, e.g.:
|
||||
|
||||
```shell
|
||||
sudo ahriman repo-backup /tmp/repo.tar.gz
|
||||
```
|
||||
|
||||
This command will pack all configuration files together with database file into the archive specified as command line argument (i.e. `/tmp/repo.tar.gz`). In addition it will also archive `cache` directory (the one which contains local clones used by e.g. local packages) and `.gnupg` of the `ahriman` user.
|
||||
|
||||
2. Copy created archive from source server `server1.example.com` to target `server2.example.com`.
|
||||
|
||||
3. Install ahriman as usual on the target server `server2.example.com` if you didn't yet.
|
||||
|
||||
4. Extract archive e.g. by using subcommand:
|
||||
|
||||
```shell
|
||||
sudo ahriman repo-restore /tmp/repo.tar.gz
|
||||
```
|
||||
|
||||
An additional argument `-o`/`--output` can be used to specify extraction root (`/` by default).
|
||||
|
||||
5. Rebuild repository:
|
||||
|
||||
```shell
|
||||
sudo -u ahriman ahriman repo-rebuild --from-database
|
||||
```
|
||||
|
||||
## Other topics
|
||||
|
||||
### How does it differ from %another-manager%?
|
||||
@ -458,6 +588,10 @@ Though originally I've created ahriman by trying to improve the project, it stil
|
||||
|
||||
`repo-scripts` also have bad architecture and bad quality code and uses out-of-dated `yaourt` and `package-query`.
|
||||
|
||||
#### [toolbox](https://github.com/chaotic-aur/toolbox)
|
||||
|
||||
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.
|
||||
|
||||
### I would like to check service logs
|
||||
|
||||
By default, the service writes logs to `/dev/log` which can be accessed by using `journalctl` command (logs are written to the journal of the user under which command is run).
|
||||
@ -468,7 +602,7 @@ You can also edit configuration and forward logs to `stderr`, just change `handl
|
||||
sed -i 's/handlers = syslog_handler/handlers = console_handler/g' /etc/ahriman.ini.d/logging.ini
|
||||
```
|
||||
|
||||
You can even configure logging as you wish, but kindly refer to python `logging` module configuration.
|
||||
You can even configure logging as you wish, but kindly refer to python `logging` module [configuration](https://docs.python.org/3/library/logging.config.html).
|
||||
|
||||
### Html customization
|
||||
|
||||
|
@ -5,11 +5,10 @@
|
||||
3. TL;DR
|
||||
|
||||
```shell
|
||||
sudo -u ahriman ahriman -a x86_64 repo-init
|
||||
sudo ahriman -a x86_64 repo-setup ...
|
||||
```
|
||||
|
||||
`repo-init` subcommand is required to create the repository tree with correct rights. `repo-setup` literally does the following steps:
|
||||
`repo-setup` literally does the following steps:
|
||||
|
||||
1. Create `/var/lib/ahriman/.makepkg.conf` with `makepkg.conf` overrides if required (at least you might want to set `PACKAGER`):
|
||||
|
||||
|
50
docs/source/ahriman.application.application.rst
Normal file
50
docs/source/ahriman.application.application.rst
Normal file
@ -0,0 +1,50 @@
|
||||
ahriman.application.application package
|
||||
=======================================
|
||||
|
||||
Submodules
|
||||
----------
|
||||
|
||||
ahriman.application.application.application module
|
||||
--------------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.application.application.application
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.application.application.application\_packages module
|
||||
------------------------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.application.application.application_packages
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.application.application.application\_properties module
|
||||
--------------------------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.application.application.application_properties
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.application.application.application\_repository module
|
||||
--------------------------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.application.application.application_repository
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
.. automodule:: ahriman.application.application
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
221
docs/source/ahriman.application.handlers.rst
Normal file
221
docs/source/ahriman.application.handlers.rst
Normal file
@ -0,0 +1,221 @@
|
||||
ahriman.application.handlers package
|
||||
====================================
|
||||
|
||||
Submodules
|
||||
----------
|
||||
|
||||
ahriman.application.handlers.add module
|
||||
---------------------------------------
|
||||
|
||||
.. automodule:: ahriman.application.handlers.add
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.application.handlers.backup module
|
||||
------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.application.handlers.backup
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.application.handlers.clean module
|
||||
-----------------------------------------
|
||||
|
||||
.. automodule:: ahriman.application.handlers.clean
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.application.handlers.dump module
|
||||
----------------------------------------
|
||||
|
||||
.. automodule:: ahriman.application.handlers.dump
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.application.handlers.handler module
|
||||
-------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.application.handlers.handler
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.application.handlers.help module
|
||||
----------------------------------------
|
||||
|
||||
.. automodule:: ahriman.application.handlers.help
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.application.handlers.key\_import module
|
||||
-----------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.application.handlers.key_import
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.application.handlers.patch module
|
||||
-----------------------------------------
|
||||
|
||||
.. automodule:: ahriman.application.handlers.patch
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.application.handlers.rebuild module
|
||||
-------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.application.handlers.rebuild
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.application.handlers.remove module
|
||||
------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.application.handlers.remove
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.application.handlers.remove\_unknown module
|
||||
---------------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.application.handlers.remove_unknown
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.application.handlers.report module
|
||||
------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.application.handlers.report
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.application.handlers.restore module
|
||||
-------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.application.handlers.restore
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.application.handlers.search module
|
||||
------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.application.handlers.search
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.application.handlers.setup module
|
||||
-----------------------------------------
|
||||
|
||||
.. automodule:: ahriman.application.handlers.setup
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.application.handlers.sign module
|
||||
----------------------------------------
|
||||
|
||||
.. automodule:: ahriman.application.handlers.sign
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.application.handlers.status module
|
||||
------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.application.handlers.status
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.application.handlers.status\_update module
|
||||
--------------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.application.handlers.status_update
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.application.handlers.sync module
|
||||
----------------------------------------
|
||||
|
||||
.. automodule:: ahriman.application.handlers.sync
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.application.handlers.unsafe\_commands module
|
||||
----------------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.application.handlers.unsafe_commands
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.application.handlers.update module
|
||||
------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.application.handlers.update
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.application.handlers.users module
|
||||
-----------------------------------------
|
||||
|
||||
.. automodule:: ahriman.application.handlers.users
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.application.handlers.web module
|
||||
---------------------------------------
|
||||
|
||||
.. automodule:: ahriman.application.handlers.web
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
.. automodule:: ahriman.application.handlers
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
41
docs/source/ahriman.application.rst
Normal file
41
docs/source/ahriman.application.rst
Normal file
@ -0,0 +1,41 @@
|
||||
ahriman.application package
|
||||
===========================
|
||||
|
||||
Subpackages
|
||||
-----------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 4
|
||||
|
||||
ahriman.application.application
|
||||
ahriman.application.handlers
|
||||
|
||||
Submodules
|
||||
----------
|
||||
|
||||
ahriman.application.ahriman module
|
||||
----------------------------------
|
||||
|
||||
.. automodule:: ahriman.application.ahriman
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.application.lock module
|
||||
-------------------------------
|
||||
|
||||
.. automodule:: ahriman.application.lock
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
.. automodule:: ahriman.application
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
41
docs/source/ahriman.core.alpm.remote.rst
Normal file
41
docs/source/ahriman.core.alpm.remote.rst
Normal file
@ -0,0 +1,41 @@
|
||||
ahriman.core.alpm.remote package
|
||||
================================
|
||||
|
||||
Submodules
|
||||
----------
|
||||
|
||||
ahriman.core.alpm.remote.aur module
|
||||
-----------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.alpm.remote.aur
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.alpm.remote.official module
|
||||
----------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.alpm.remote.official
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.alpm.remote.remote module
|
||||
--------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.alpm.remote.remote
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
.. automodule:: ahriman.core.alpm.remote
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
40
docs/source/ahriman.core.alpm.rst
Normal file
40
docs/source/ahriman.core.alpm.rst
Normal file
@ -0,0 +1,40 @@
|
||||
ahriman.core.alpm package
|
||||
=========================
|
||||
|
||||
Subpackages
|
||||
-----------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 4
|
||||
|
||||
ahriman.core.alpm.remote
|
||||
|
||||
Submodules
|
||||
----------
|
||||
|
||||
ahriman.core.alpm.pacman module
|
||||
-------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.alpm.pacman
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.alpm.repo module
|
||||
-----------------------------
|
||||
|
||||
.. automodule:: ahriman.core.alpm.repo
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
.. automodule:: ahriman.core.alpm
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
50
docs/source/ahriman.core.auth.rst
Normal file
50
docs/source/ahriman.core.auth.rst
Normal file
@ -0,0 +1,50 @@
|
||||
ahriman.core.auth package
|
||||
=========================
|
||||
|
||||
Submodules
|
||||
----------
|
||||
|
||||
ahriman.core.auth.auth module
|
||||
-----------------------------
|
||||
|
||||
.. automodule:: ahriman.core.auth.auth
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.auth.helpers module
|
||||
--------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.auth.helpers
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.auth.mapping module
|
||||
--------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.auth.mapping
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.auth.oauth module
|
||||
------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.auth.oauth
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
.. automodule:: ahriman.core.auth
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
32
docs/source/ahriman.core.build_tools.rst
Normal file
32
docs/source/ahriman.core.build_tools.rst
Normal file
@ -0,0 +1,32 @@
|
||||
ahriman.core.build\_tools package
|
||||
=================================
|
||||
|
||||
Submodules
|
||||
----------
|
||||
|
||||
ahriman.core.build\_tools.sources module
|
||||
----------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.build_tools.sources
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.build\_tools.task module
|
||||
-------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.build_tools.task
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
.. automodule:: ahriman.core.build_tools
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
41
docs/source/ahriman.core.database.data.rst
Normal file
41
docs/source/ahriman.core.database.data.rst
Normal file
@ -0,0 +1,41 @@
|
||||
ahriman.core.database.data package
|
||||
==================================
|
||||
|
||||
Submodules
|
||||
----------
|
||||
|
||||
ahriman.core.database.data.package\_statuses module
|
||||
---------------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.database.data.package_statuses
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.database.data.patches module
|
||||
-----------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.database.data.patches
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.database.data.users module
|
||||
---------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.database.data.users
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
.. automodule:: ahriman.core.database.data
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
23
docs/source/ahriman.core.database.migrations.rst
Normal file
23
docs/source/ahriman.core.database.migrations.rst
Normal file
@ -0,0 +1,23 @@
|
||||
ahriman.core.database.migrations package
|
||||
========================================
|
||||
|
||||
Submodules
|
||||
----------
|
||||
|
||||
ahriman.core.database.migrations.m000\_initial module
|
||||
-----------------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.database.migrations.m000_initial
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
.. automodule:: ahriman.core.database.migrations
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
59
docs/source/ahriman.core.database.operations.rst
Normal file
59
docs/source/ahriman.core.database.operations.rst
Normal file
@ -0,0 +1,59 @@
|
||||
ahriman.core.database.operations package
|
||||
========================================
|
||||
|
||||
Submodules
|
||||
----------
|
||||
|
||||
ahriman.core.database.operations.auth\_operations module
|
||||
--------------------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.database.operations.auth_operations
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.database.operations.build\_operations module
|
||||
---------------------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.database.operations.build_operations
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.database.operations.operations module
|
||||
--------------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.database.operations.operations
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.database.operations.package\_operations module
|
||||
-----------------------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.database.operations.package_operations
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.database.operations.patch\_operations module
|
||||
---------------------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.database.operations.patch_operations
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
.. automodule:: ahriman.core.database.operations
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
33
docs/source/ahriman.core.database.rst
Normal file
33
docs/source/ahriman.core.database.rst
Normal file
@ -0,0 +1,33 @@
|
||||
ahriman.core.database package
|
||||
=============================
|
||||
|
||||
Subpackages
|
||||
-----------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 4
|
||||
|
||||
ahriman.core.database.data
|
||||
ahriman.core.database.migrations
|
||||
ahriman.core.database.operations
|
||||
|
||||
Submodules
|
||||
----------
|
||||
|
||||
ahriman.core.database.sqlite module
|
||||
-----------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.database.sqlite
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
.. automodule:: ahriman.core.database
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
95
docs/source/ahriman.core.formatters.rst
Normal file
95
docs/source/ahriman.core.formatters.rst
Normal file
@ -0,0 +1,95 @@
|
||||
ahriman.core.formatters package
|
||||
===============================
|
||||
|
||||
Submodules
|
||||
----------
|
||||
|
||||
ahriman.core.formatters.aur\_printer module
|
||||
-------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.formatters.aur_printer
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.formatters.build\_printer module
|
||||
---------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.formatters.build_printer
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.formatters.configuration\_printer module
|
||||
-----------------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.formatters.configuration_printer
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.formatters.package\_printer module
|
||||
-----------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.formatters.package_printer
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.formatters.printer module
|
||||
--------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.formatters.printer
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.formatters.status\_printer module
|
||||
----------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.formatters.status_printer
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.formatters.string\_printer module
|
||||
----------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.formatters.string_printer
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.formatters.update\_printer module
|
||||
----------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.formatters.update_printer
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.formatters.user\_printer module
|
||||
--------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.formatters.user_printer
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
.. automodule:: ahriman.core.formatters
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
68
docs/source/ahriman.core.report.rst
Normal file
68
docs/source/ahriman.core.report.rst
Normal file
@ -0,0 +1,68 @@
|
||||
ahriman.core.report package
|
||||
===========================
|
||||
|
||||
Submodules
|
||||
----------
|
||||
|
||||
ahriman.core.report.console module
|
||||
----------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.report.console
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.report.email module
|
||||
--------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.report.email
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.report.html module
|
||||
-------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.report.html
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.report.jinja\_template module
|
||||
------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.report.jinja_template
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.report.report module
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.report.report
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.report.telegram module
|
||||
-----------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.report.telegram
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
.. automodule:: ahriman.core.report
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
59
docs/source/ahriman.core.repository.rst
Normal file
59
docs/source/ahriman.core.repository.rst
Normal file
@ -0,0 +1,59 @@
|
||||
ahriman.core.repository package
|
||||
===============================
|
||||
|
||||
Submodules
|
||||
----------
|
||||
|
||||
ahriman.core.repository.cleaner module
|
||||
--------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.repository.cleaner
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.repository.executor module
|
||||
---------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.repository.executor
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.repository.repository module
|
||||
-----------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.repository.repository
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.repository.repository\_properties module
|
||||
-----------------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.repository.repository_properties
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.repository.update\_handler module
|
||||
----------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.repository.update_handler
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
.. automodule:: ahriman.core.repository
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
76
docs/source/ahriman.core.rst
Normal file
76
docs/source/ahriman.core.rst
Normal file
@ -0,0 +1,76 @@
|
||||
ahriman.core package
|
||||
====================
|
||||
|
||||
Subpackages
|
||||
-----------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 4
|
||||
|
||||
ahriman.core.alpm
|
||||
ahriman.core.auth
|
||||
ahriman.core.build_tools
|
||||
ahriman.core.database
|
||||
ahriman.core.formatters
|
||||
ahriman.core.report
|
||||
ahriman.core.repository
|
||||
ahriman.core.sign
|
||||
ahriman.core.status
|
||||
ahriman.core.upload
|
||||
|
||||
Submodules
|
||||
----------
|
||||
|
||||
ahriman.core.configuration module
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.configuration
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.exceptions module
|
||||
------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.exceptions
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.spawn module
|
||||
-------------------------
|
||||
|
||||
.. automodule:: ahriman.core.spawn
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.tree module
|
||||
------------------------
|
||||
|
||||
.. automodule:: ahriman.core.tree
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.util module
|
||||
------------------------
|
||||
|
||||
.. automodule:: ahriman.core.util
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
.. automodule:: ahriman.core
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
23
docs/source/ahriman.core.sign.rst
Normal file
23
docs/source/ahriman.core.sign.rst
Normal file
@ -0,0 +1,23 @@
|
||||
ahriman.core.sign package
|
||||
=========================
|
||||
|
||||
Submodules
|
||||
----------
|
||||
|
||||
ahriman.core.sign.gpg module
|
||||
----------------------------
|
||||
|
||||
.. automodule:: ahriman.core.sign.gpg
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
.. automodule:: ahriman.core.sign
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
41
docs/source/ahriman.core.status.rst
Normal file
41
docs/source/ahriman.core.status.rst
Normal file
@ -0,0 +1,41 @@
|
||||
ahriman.core.status package
|
||||
===========================
|
||||
|
||||
Submodules
|
||||
----------
|
||||
|
||||
ahriman.core.status.client module
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.status.client
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.status.watcher module
|
||||
----------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.status.watcher
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.status.web\_client module
|
||||
--------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.status.web_client
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
.. automodule:: ahriman.core.status
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
59
docs/source/ahriman.core.upload.rst
Normal file
59
docs/source/ahriman.core.upload.rst
Normal file
@ -0,0 +1,59 @@
|
||||
ahriman.core.upload package
|
||||
===========================
|
||||
|
||||
Submodules
|
||||
----------
|
||||
|
||||
ahriman.core.upload.github module
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.upload.github
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.upload.http\_upload module
|
||||
---------------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.upload.http_upload
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.upload.rsync module
|
||||
--------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.upload.rsync
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.upload.s3 module
|
||||
-----------------------------
|
||||
|
||||
.. automodule:: ahriman.core.upload.s3
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.core.upload.upload module
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: ahriman.core.upload.upload
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
.. automodule:: ahriman.core.upload
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
203
docs/source/ahriman.models.rst
Normal file
203
docs/source/ahriman.models.rst
Normal file
@ -0,0 +1,203 @@
|
||||
ahriman.models package
|
||||
======================
|
||||
|
||||
Submodules
|
||||
----------
|
||||
|
||||
ahriman.models.action module
|
||||
----------------------------
|
||||
|
||||
.. automodule:: ahriman.models.action
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.models.aur\_package module
|
||||
----------------------------------
|
||||
|
||||
.. automodule:: ahriman.models.aur_package
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.models.auth\_settings module
|
||||
------------------------------------
|
||||
|
||||
.. automodule:: ahriman.models.auth_settings
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.models.build\_status module
|
||||
-----------------------------------
|
||||
|
||||
.. automodule:: ahriman.models.build_status
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.models.counters module
|
||||
------------------------------
|
||||
|
||||
.. automodule:: ahriman.models.counters
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.models.internal\_status module
|
||||
--------------------------------------
|
||||
|
||||
.. automodule:: ahriman.models.internal_status
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.models.migration module
|
||||
-------------------------------
|
||||
|
||||
.. automodule:: ahriman.models.migration
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.models.migration\_result module
|
||||
---------------------------------------
|
||||
|
||||
.. automodule:: ahriman.models.migration_result
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.models.package module
|
||||
-----------------------------
|
||||
|
||||
.. automodule:: ahriman.models.package
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.models.package\_description module
|
||||
------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.models.package_description
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.models.package\_source module
|
||||
-------------------------------------
|
||||
|
||||
.. automodule:: ahriman.models.package_source
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.models.property module
|
||||
------------------------------
|
||||
|
||||
.. automodule:: ahriman.models.property
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.models.report\_settings module
|
||||
--------------------------------------
|
||||
|
||||
.. automodule:: ahriman.models.report_settings
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.models.repository\_paths module
|
||||
---------------------------------------
|
||||
|
||||
.. automodule:: ahriman.models.repository_paths
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.models.result module
|
||||
----------------------------
|
||||
|
||||
.. automodule:: ahriman.models.result
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.models.sign\_settings module
|
||||
------------------------------------
|
||||
|
||||
.. automodule:: ahriman.models.sign_settings
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.models.smtp\_ssl\_settings module
|
||||
-----------------------------------------
|
||||
|
||||
.. automodule:: ahriman.models.smtp_ssl_settings
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.models.upload\_settings module
|
||||
--------------------------------------
|
||||
|
||||
.. automodule:: ahriman.models.upload_settings
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.models.user module
|
||||
--------------------------
|
||||
|
||||
.. automodule:: ahriman.models.user
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.models.user\_access module
|
||||
----------------------------------
|
||||
|
||||
.. automodule:: ahriman.models.user_access
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.models.user\_identity module
|
||||
------------------------------------
|
||||
|
||||
.. automodule:: ahriman.models.user_identity
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
.. automodule:: ahriman.models
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
34
docs/source/ahriman.rst
Normal file
34
docs/source/ahriman.rst
Normal file
@ -0,0 +1,34 @@
|
||||
ahriman package
|
||||
===============
|
||||
|
||||
Subpackages
|
||||
-----------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 4
|
||||
|
||||
ahriman.application
|
||||
ahriman.core
|
||||
ahriman.models
|
||||
ahriman.web
|
||||
|
||||
Submodules
|
||||
----------
|
||||
|
||||
ahriman.version module
|
||||
----------------------
|
||||
|
||||
.. automodule:: ahriman.version
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
.. automodule:: ahriman
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
32
docs/source/ahriman.web.middlewares.rst
Normal file
32
docs/source/ahriman.web.middlewares.rst
Normal file
@ -0,0 +1,32 @@
|
||||
ahriman.web.middlewares package
|
||||
===============================
|
||||
|
||||
Submodules
|
||||
----------
|
||||
|
||||
ahriman.web.middlewares.auth\_handler module
|
||||
--------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.web.middlewares.auth_handler
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.web.middlewares.exception\_handler module
|
||||
-------------------------------------------------
|
||||
|
||||
.. automodule:: ahriman.web.middlewares.exception_handler
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
.. automodule:: ahriman.web.middlewares
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
41
docs/source/ahriman.web.rst
Normal file
41
docs/source/ahriman.web.rst
Normal file
@ -0,0 +1,41 @@
|
||||
ahriman.web package
|
||||
===================
|
||||
|
||||
Subpackages
|
||||
-----------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 4
|
||||
|
||||
ahriman.web.middlewares
|
||||
ahriman.web.views
|
||||
|
||||
Submodules
|
||||
----------
|
||||
|
||||
ahriman.web.routes module
|
||||
-------------------------
|
||||
|
||||
.. automodule:: ahriman.web.routes
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.web.web module
|
||||
----------------------
|
||||
|
||||
.. automodule:: ahriman.web.web
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
.. automodule:: ahriman.web
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
42
docs/source/ahriman.web.views.rst
Normal file
42
docs/source/ahriman.web.views.rst
Normal file
@ -0,0 +1,42 @@
|
||||
ahriman.web.views package
|
||||
=========================
|
||||
|
||||
Subpackages
|
||||
-----------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 4
|
||||
|
||||
ahriman.web.views.service
|
||||
ahriman.web.views.status
|
||||
ahriman.web.views.user
|
||||
|
||||
Submodules
|
||||
----------
|
||||
|
||||
ahriman.web.views.base module
|
||||
-----------------------------
|
||||
|
||||
.. automodule:: ahriman.web.views.base
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.web.views.index module
|
||||
------------------------------
|
||||
|
||||
.. automodule:: ahriman.web.views.index
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
.. automodule:: ahriman.web.views
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
50
docs/source/ahriman.web.views.service.rst
Normal file
50
docs/source/ahriman.web.views.service.rst
Normal file
@ -0,0 +1,50 @@
|
||||
ahriman.web.views.service package
|
||||
=================================
|
||||
|
||||
Submodules
|
||||
----------
|
||||
|
||||
ahriman.web.views.service.add module
|
||||
------------------------------------
|
||||
|
||||
.. automodule:: ahriman.web.views.service.add
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.web.views.service.remove module
|
||||
---------------------------------------
|
||||
|
||||
.. automodule:: ahriman.web.views.service.remove
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.web.views.service.request module
|
||||
----------------------------------------
|
||||
|
||||
.. automodule:: ahriman.web.views.service.request
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.web.views.service.search module
|
||||
---------------------------------------
|
||||
|
||||
.. automodule:: ahriman.web.views.service.search
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
.. automodule:: ahriman.web.views.service
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
50
docs/source/ahriman.web.views.status.rst
Normal file
50
docs/source/ahriman.web.views.status.rst
Normal file
@ -0,0 +1,50 @@
|
||||
ahriman.web.views.status package
|
||||
================================
|
||||
|
||||
Submodules
|
||||
----------
|
||||
|
||||
ahriman.web.views.status.ahriman module
|
||||
---------------------------------------
|
||||
|
||||
.. automodule:: ahriman.web.views.status.ahriman
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.web.views.status.package module
|
||||
---------------------------------------
|
||||
|
||||
.. automodule:: ahriman.web.views.status.package
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.web.views.status.packages module
|
||||
----------------------------------------
|
||||
|
||||
.. automodule:: ahriman.web.views.status.packages
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.web.views.status.status module
|
||||
--------------------------------------
|
||||
|
||||
.. automodule:: ahriman.web.views.status.status
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
.. automodule:: ahriman.web.views.status
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
32
docs/source/ahriman.web.views.user.rst
Normal file
32
docs/source/ahriman.web.views.user.rst
Normal file
@ -0,0 +1,32 @@
|
||||
ahriman.web.views.user package
|
||||
==============================
|
||||
|
||||
Submodules
|
||||
----------
|
||||
|
||||
ahriman.web.views.user.login module
|
||||
-----------------------------------
|
||||
|
||||
.. automodule:: ahriman.web.views.user.login
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
ahriman.web.views.user.logout module
|
||||
------------------------------------
|
||||
|
||||
.. automodule:: ahriman.web.views.user.logout
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
.. automodule:: ahriman.web.views.user
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
:show-inheritance:
|
||||
:private-members:
|
83
docs/source/conf.py
Normal file
83
docs/source/conf.py
Normal file
@ -0,0 +1,83 @@
|
||||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# This file only contains a selection of the most common options. For a full
|
||||
# list see the documentation:
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
||||
|
||||
# -- Path setup --------------------------------------------------------------
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
import os
|
||||
|
||||
from pathlib import Path
|
||||
# import sys
|
||||
# sys.path.insert(0, os.path.abspath("."))
|
||||
|
||||
basedir = Path(__file__).resolve().parent.parent.parent
|
||||
metadata_path = basedir / "src/ahriman/version.py"
|
||||
metadata = {}
|
||||
with metadata_path.open() as metadata_file:
|
||||
exec(metadata_file.read(), metadata) # pylint: disable=exec-used
|
||||
|
||||
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
|
||||
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
project = "ahriman"
|
||||
copyright = "2021-2022, ahriman team"
|
||||
author = "ahriman team"
|
||||
|
||||
# The full version, including alpha/beta/rc tags
|
||||
release = metadata["__version__"]
|
||||
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named "sphinx.ext.*") or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
"sphinx.ext.autodoc",
|
||||
"sphinx.ext.napoleon",
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ["_templates"]
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#
|
||||
# This is also used if you do content translation via gettext catalogs.
|
||||
# Usually you set "language" from the command line for these cases.
|
||||
language = "en"
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This pattern also affects html_static_path and html_extra_path.
|
||||
exclude_patterns = []
|
||||
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = "default" if on_rtd else "alabaster"
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ["_static"]
|
||||
|
||||
|
||||
# -- Extension configuration -------------------------------------------------
|
||||
|
||||
autodoc_member_order = "groupwise"
|
||||
|
||||
autodoc_default_options = {
|
||||
"no-undoc-members": True,
|
||||
}
|
27
docs/source/index.rst
Normal file
27
docs/source/index.rst
Normal file
@ -0,0 +1,27 @@
|
||||
Welcome to ahriman's documentation!
|
||||
===================================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Contents:
|
||||
|
||||
Wrapper for managing custom repository inspired by `repo-scripts <https://github.com/arcan1s/repo-scripts>`_.
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* Install-configure-forget manager for own repository.
|
||||
* Multi-architecture support.
|
||||
* VCS packages support.
|
||||
* Sign support with gpg (repository, package, per package settings).
|
||||
* Synchronization to remote services (rsync, s3 and github) and report generation (email, html, telegram).
|
||||
* Dependency manager.
|
||||
* Ability to patch AUR packages and even create package from local PKGBUILDs.
|
||||
* Repository status interface with optional authorization and control options.
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
7
docs/source/modules.rst
Normal file
7
docs/source/modules.rst
Normal file
@ -0,0 +1,7 @@
|
||||
src
|
||||
===
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 4
|
||||
|
||||
ahriman
|
@ -1,14 +1,14 @@
|
||||
# Maintainer: Evgeniy Alekseev
|
||||
|
||||
pkgname='ahriman'
|
||||
pkgver=1.6.3
|
||||
pkgver=2.0.0rc7
|
||||
pkgrel=1
|
||||
pkgdesc="ArcH Linux ReposItory MANager"
|
||||
arch=('any')
|
||||
url="https://github.com/arcan1s/ahriman"
|
||||
license=('GPL3')
|
||||
depends=('devtools' 'git' 'pyalpm' 'python-aur' 'python-passlib' 'python-srcinfo')
|
||||
makedepends=('python-pip')
|
||||
depends=('devtools' 'git' 'pyalpm' 'python-inflection' 'python-passlib' 'python-requests' 'python-srcinfo')
|
||||
makedepends=('python-build' 'python-installer' 'python-wheel')
|
||||
optdepends=('breezy: -bzr packages support'
|
||||
'darcs: -darcs packages support'
|
||||
'mercurial: -hg packages support'
|
||||
@ -32,18 +32,23 @@ backup=('etc/ahriman.ini'
|
||||
build() {
|
||||
cd "$pkgname"
|
||||
|
||||
python setup.py build
|
||||
python -m build --wheel --no-isolation
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$pkgname"
|
||||
|
||||
python setup.py install --root="$pkgdir"
|
||||
python -m installer --destdir="$pkgdir" "dist/$pkgname-$pkgver-py3-none-any.whl"
|
||||
|
||||
# python-installer actually thinks that you cannot just copy files to root
|
||||
# thus we need to copy them manually
|
||||
install -Dm644 "$pkgdir/usr/share/$pkgname/settings/ahriman.ini" "$pkgdir/etc/ahriman.ini"
|
||||
install -Dm644 "$pkgdir/usr/share/$pkgname/settings/ahriman.ini.d/logging.ini" "$pkgdir/etc/ahriman.ini.d/logging.ini"
|
||||
|
||||
install -Dm644 "$srcdir/$pkgname.sysusers" "$pkgdir/usr/lib/sysusers.d/$pkgname.conf"
|
||||
install -Dm644 "$srcdir/$pkgname.tmpfiles" "$pkgdir/usr/lib/tmpfiles.d/$pkgname.conf"
|
||||
}
|
||||
|
||||
sha512sums=('6ab741bfb42f92ab00d1b6ecfc44426c00e5c433486e014efbdb585715d9a12dbbafc280e5a9f85b941c8681b13a9dad41327a3e3c44a9683ae30c1d6f017f50'
|
||||
'13718afec2c6786a18f0b223ef8e58dccf0688bca4cdbe203f14071f5031ed20120eb0ce38b52c76cfd6e8b6581a9c9eaa2743eb11abbaca637451a84c33f075'
|
||||
'55b20f6da3d66e7bbf2add5d95a3b60632df121717d25a993e56e737d14f51fe063eb6f1b38bd81cc32e05db01c0c1d80aaa720c45cde87f238d8b46cdb8cbc4')
|
||||
sha512sums=('112b0d8aac68e5330bbdd2b86a59c8a9af8ab7a7c636489623c8460bb90f1318585851edd2a97a8ce20e2d2ad93b847b522685df707c190aa39d23ab908fa8ef'
|
||||
'53d37efec812afebf86281716259f9ea78a307b83897166c72777251c3eebcb587ecee375d907514781fb2a5c808cbb24ef9f3f244f12740155d0603bf213131'
|
||||
'62b2eccc352d33853ef243c9cddd63663014aa97b87242f1b5bc5099a7dbd69ff3821f24ffc58e1b7f2387bd4e9e9712cc4c67f661b1724ad99cdf09b3717794')
|
||||
|
@ -1,6 +1,7 @@
|
||||
[settings]
|
||||
include = /etc/ahriman.ini.d
|
||||
logging = /etc/ahriman.ini.d/logging.ini
|
||||
include = ahriman.ini.d
|
||||
logging = ahriman.ini.d/logging.ini
|
||||
database = /var/lib/ahriman/ahriman.db
|
||||
|
||||
[alpm]
|
||||
aur_url = https://aur.archlinux.org
|
||||
@ -20,7 +21,7 @@ archbuild_flags =
|
||||
build_command = extra-x86_64-build
|
||||
ignore_packages =
|
||||
makechrootpkg_flags =
|
||||
makepkg_flags =
|
||||
makepkg_flags = --nocolor
|
||||
|
||||
[repository]
|
||||
name = aur-clone
|
||||
@ -30,16 +31,22 @@ root = /var/lib/ahriman
|
||||
target =
|
||||
|
||||
[report]
|
||||
target =
|
||||
target = console
|
||||
|
||||
[console]
|
||||
use_utf = yes
|
||||
|
||||
[email]
|
||||
full_template_path = /usr/share/ahriman/repo-index.jinja2
|
||||
full_template_path = /usr/share/ahriman/templates/repo-index.jinja2
|
||||
no_empty_report = yes
|
||||
template_path = /usr/share/ahriman/email-index.jinja2
|
||||
template_path = /usr/share/ahriman/templates/email-index.jinja2
|
||||
ssl = disabled
|
||||
|
||||
[html]
|
||||
template_path = /usr/share/ahriman/repo-index.jinja2
|
||||
template_path = /usr/share/ahriman/templates/repo-index.jinja2
|
||||
|
||||
[telegram]
|
||||
template_path = /usr/share/ahriman/templates/telegram-index.jinja2
|
||||
|
||||
[upload]
|
||||
target =
|
||||
@ -55,5 +62,5 @@ debug = no
|
||||
debug_check_host = no
|
||||
debug_allowed_hosts =
|
||||
host = 127.0.0.1
|
||||
static_path = /usr/share/ahriman/static
|
||||
templates = /usr/share/ahriman
|
||||
static_path = /usr/share/ahriman/templates/static
|
||||
templates = /usr/share/ahriman/templates
|
@ -1,5 +1,5 @@
|
||||
[loggers]
|
||||
keys = root,build_details,http,stderr,boto3,botocore,nose,s3transfer
|
||||
keys = root,build_details,database,http,stderr,boto3,botocore,nose,s3transfer
|
||||
|
||||
[handlers]
|
||||
keys = console_handler,syslog_handler
|
||||
@ -38,6 +38,12 @@ handlers = syslog_handler
|
||||
qualname = build_details
|
||||
propagate = 0
|
||||
|
||||
[logger_database]
|
||||
level = DEBUG
|
||||
handlers = syslog_handler
|
||||
qualname = database
|
||||
propagate = 0
|
||||
|
||||
[logger_http]
|
||||
level = DEBUG
|
||||
handlers = syslog_handler
|
@ -16,7 +16,7 @@
|
||||
<h1>ahriman
|
||||
{% if auth.authenticated %}
|
||||
<img src="https://img.shields.io/badge/version-{{ version }}-informational" alt="{{ version }}">
|
||||
<img src="https://img.shields.io/badge/repository-{{ repository }}-informational" alt="{{ repository }}">
|
||||
<img src="https://img.shields.io/badge/repository-{{ repository | replace("-", "--") }}-informational" alt="{{ repository }}">
|
||||
<img src="https://img.shields.io/badge/architecture-{{ architecture }}-informational" alt="{{ architecture }}">
|
||||
<img src="https://img.shields.io/badge/service%20status-{{ service.status }}-{{ service.status_color }}" alt="{{ service.status }}" title="{{ service.timestamp }}">
|
||||
{% endif %}
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
4
package/share/ahriman/templates/telegram-index.jinja2
Normal file
4
package/share/ahriman/templates/telegram-index.jinja2
Normal file
@ -0,0 +1,4 @@
|
||||
{#simplified version of full report#}
|
||||
<b>{{ repository }} update</b>
|
||||
{% for package in packages %}
|
||||
<a href="{{ link_path }}/{{ package.filename }}">{{ package.name }}</a> {{ package.version }}{% endfor %}
|
@ -1,5 +0,0 @@
|
||||
[aliases]
|
||||
test = pytest
|
||||
|
||||
[tool:pytest]
|
||||
addopts = --cov=ahriman --cov-report term-missing:skip-covered --pspec
|
57
setup.py
57
setup.py
@ -29,14 +29,12 @@ setup(
|
||||
dependency_links=[
|
||||
],
|
||||
install_requires=[
|
||||
"aur",
|
||||
"inflection",
|
||||
"passlib",
|
||||
"pyalpm",
|
||||
"requests",
|
||||
"srcinfo",
|
||||
],
|
||||
setup_requires=[
|
||||
"pytest-runner",
|
||||
],
|
||||
tests_require=[
|
||||
"pytest",
|
||||
@ -44,7 +42,7 @@ setup(
|
||||
"pytest-cov",
|
||||
"pytest-helpers-namespace",
|
||||
"pytest-mock",
|
||||
"pytest-pspec",
|
||||
"pytest-spec",
|
||||
"pytest-resource-path",
|
||||
],
|
||||
|
||||
@ -53,33 +51,34 @@ setup(
|
||||
"package/bin/ahriman",
|
||||
],
|
||||
data_files=[
|
||||
("/etc", [
|
||||
"package/etc/ahriman.ini",
|
||||
("share/ahriman/settings", [
|
||||
"package/share/ahriman/settings/ahriman.ini",
|
||||
]),
|
||||
("/etc/ahriman.ini.d", [
|
||||
"package/etc/ahriman.ini.d/logging.ini",
|
||||
("share/ahriman/settings/ahriman.ini.d", [
|
||||
"package/share/ahriman/settings/ahriman.ini.d/logging.ini",
|
||||
]),
|
||||
("lib/systemd/system", [
|
||||
"package/lib/systemd/system/ahriman@.service",
|
||||
"package/lib/systemd/system/ahriman@.timer",
|
||||
"package/lib/systemd/system/ahriman-web@.service",
|
||||
]),
|
||||
("share/ahriman", [
|
||||
"package/share/ahriman/build-status.jinja2",
|
||||
"package/share/ahriman/email-index.jinja2",
|
||||
"package/share/ahriman/repo-index.jinja2",
|
||||
("share/ahriman/templates", [
|
||||
"package/share/ahriman/templates/build-status.jinja2",
|
||||
"package/share/ahriman/templates/email-index.jinja2",
|
||||
"package/share/ahriman/templates/repo-index.jinja2",
|
||||
"package/share/ahriman/templates/telegram-index.jinja2",
|
||||
]),
|
||||
("share/ahriman/build-status", [
|
||||
"package/share/ahriman/build-status/login-modal.jinja2",
|
||||
"package/share/ahriman/build-status/package-actions-modals.jinja2",
|
||||
"package/share/ahriman/build-status/package-actions-script.jinja2",
|
||||
("share/ahriman/templates/build-status", [
|
||||
"package/share/ahriman/templates/build-status/login-modal.jinja2",
|
||||
"package/share/ahriman/templates/build-status/package-actions-modals.jinja2",
|
||||
"package/share/ahriman/templates/build-status/package-actions-script.jinja2",
|
||||
]),
|
||||
("share/ahriman/static", [
|
||||
"package/share/ahriman/static/favicon.ico",
|
||||
("share/ahriman/templates/static", [
|
||||
"package/share/ahriman/templates/static/favicon.ico",
|
||||
]),
|
||||
("share/ahriman/utils", [
|
||||
"package/share/ahriman/utils/bootstrap-scripts.jinja2",
|
||||
"package/share/ahriman/utils/style.jinja2",
|
||||
("share/ahriman/templates/utils", [
|
||||
"package/share/ahriman/templates/utils/bootstrap-scripts.jinja2",
|
||||
"package/share/ahriman/templates/utils/style.jinja2",
|
||||
]),
|
||||
("share/man/man1", [
|
||||
"docs/ahriman.1",
|
||||
@ -93,17 +92,29 @@ setup(
|
||||
"mypy",
|
||||
"pylint",
|
||||
],
|
||||
"docs": [
|
||||
"Sphinx",
|
||||
"argparse-manpage",
|
||||
"pydeps",
|
||||
"sphinxcontrib-napoleon",
|
||||
],
|
||||
# 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",
|
||||
],
|
||||
"test": [
|
||||
"tests": [
|
||||
"pytest",
|
||||
"pytest-aiohttp",
|
||||
"pytest-cov",
|
||||
"pytest-helpers-namespace",
|
||||
"pytest-mock",
|
||||
"pytest-pspec",
|
||||
"pytest-resource-path",
|
||||
"pytest-spec",
|
||||
],
|
||||
"web": [
|
||||
"Jinja2",
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
@ -22,6 +22,7 @@ import sys
|
||||
import tempfile
|
||||
|
||||
from pathlib import Path
|
||||
from typing import TypeVar
|
||||
|
||||
from ahriman import version
|
||||
from ahriman.application import handlers
|
||||
@ -32,15 +33,22 @@ from ahriman.models.sign_settings import SignSettings
|
||||
from ahriman.models.user_access import UserAccess
|
||||
|
||||
|
||||
# pylint thinks it is bad idea, but get the fuck off
|
||||
SubParserAction = argparse._SubParsersAction # pylint: disable=protected-access
|
||||
# this workaround is for several things
|
||||
# firstly python devs don't think that is it error and asking you for workarounds https://bugs.python.org/issue41592
|
||||
# secondly linters don't like when you are importing private members
|
||||
# thirdly new mypy doesn't like _SubParsersAction and thinks it is a template
|
||||
SubParserAction = TypeVar("SubParserAction", bound="argparse._SubParsersAction[argparse.ArgumentParser]")
|
||||
|
||||
|
||||
def _formatter(prog: str) -> argparse.HelpFormatter:
|
||||
"""
|
||||
formatter for the help message
|
||||
:param prog: application name
|
||||
:return: formatter used by default
|
||||
|
||||
Args:
|
||||
prog(str): application name
|
||||
|
||||
Returns:
|
||||
argparse.HelpFormatter: formatter used by default
|
||||
"""
|
||||
return argparse.ArgumentDefaultsHelpFormatter(prog, width=120)
|
||||
|
||||
@ -48,7 +56,9 @@ def _formatter(prog: str) -> argparse.HelpFormatter:
|
||||
def _parser() -> argparse.ArgumentParser:
|
||||
"""
|
||||
command line parser generator
|
||||
:return: command line parser for the application
|
||||
|
||||
Returns:
|
||||
argparse.ArgumentParser: command line parser for the application
|
||||
"""
|
||||
parser = argparse.ArgumentParser(prog="ahriman", description="ArcH Linux ReposItory MANager",
|
||||
epilog="Argument list can also be read from file by using @ prefix.",
|
||||
@ -68,6 +78,8 @@ def _parser() -> argparse.ArgumentParser:
|
||||
subparsers = parser.add_subparsers(title="command", help="command to run", dest="command", required=True)
|
||||
|
||||
_set_aur_search_parser(subparsers)
|
||||
_set_help_parser(subparsers)
|
||||
_set_help_commands_unsafe_parser(subparsers)
|
||||
_set_key_import_parser(subparsers)
|
||||
_set_package_add_parser(subparsers)
|
||||
_set_package_remove_parser(subparsers)
|
||||
@ -77,19 +89,21 @@ def _parser() -> argparse.ArgumentParser:
|
||||
_set_patch_add_parser(subparsers)
|
||||
_set_patch_list_parser(subparsers)
|
||||
_set_patch_remove_parser(subparsers)
|
||||
_set_repo_backup_parser(subparsers)
|
||||
_set_repo_check_parser(subparsers)
|
||||
_set_repo_clean_parser(subparsers)
|
||||
_set_repo_config_parser(subparsers)
|
||||
_set_repo_init_parser(subparsers)
|
||||
_set_repo_rebuild_parser(subparsers)
|
||||
_set_repo_remove_unknown_parser(subparsers)
|
||||
_set_repo_report_parser(subparsers)
|
||||
_set_repo_restore_parser(subparsers)
|
||||
_set_repo_setup_parser(subparsers)
|
||||
_set_repo_sign_parser(subparsers)
|
||||
_set_repo_status_update_parser(subparsers)
|
||||
_set_repo_sync_parser(subparsers)
|
||||
_set_repo_update_parser(subparsers)
|
||||
_set_user_add_parser(subparsers)
|
||||
_set_user_list_parser(subparsers)
|
||||
_set_user_remove_parser(subparsers)
|
||||
_set_web_parser(subparsers)
|
||||
|
||||
@ -99,13 +113,18 @@ def _parser() -> argparse.ArgumentParser:
|
||||
def _set_aur_search_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for AUR search subcommand
|
||||
:param root: subparsers for the commands
|
||||
:return: created argument parser
|
||||
|
||||
Args:
|
||||
root(SubParserAction): subparsers for the commands
|
||||
|
||||
Returns:
|
||||
argparse.ArgumentParser: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("aur-search", aliases=["search"], help="search for package",
|
||||
description="search for package in AUR using API", formatter_class=_formatter)
|
||||
parser.add_argument("search", help="search terms, can be specified multiple times, result will match all terms",
|
||||
nargs="+")
|
||||
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
|
||||
parser.add_argument("-i", "--info", help="show additional package information", action="store_true")
|
||||
parser.add_argument("--sort-by", help="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",
|
||||
@ -114,11 +133,53 @@ def _set_aur_search_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
return parser
|
||||
|
||||
|
||||
def _set_help_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for listing help subcommand
|
||||
|
||||
Args:
|
||||
root(SubParserAction): subparsers for the commands
|
||||
|
||||
Returns:
|
||||
argparse.ArgumentParser: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("help", help="show help message",
|
||||
description="show help message for application or command and exit",
|
||||
formatter_class=_formatter)
|
||||
parser.add_argument("command", help="show help message for specific command", nargs="?")
|
||||
parser.set_defaults(handler=handlers.Help, architecture=[""], lock=None, no_report=True, quiet=True,
|
||||
unsafe=True, parser=_parser)
|
||||
return parser
|
||||
|
||||
|
||||
def _set_help_commands_unsafe_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for listing unsafe commands
|
||||
|
||||
Args:
|
||||
root(SubParserAction): subparsers for the commands
|
||||
|
||||
Returns:
|
||||
argparse.ArgumentParser: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("help-commands-unsafe", help="list unsafe commands",
|
||||
description="list unsafe commands as defined in default args", formatter_class=_formatter)
|
||||
parser.add_argument("--command", help="instead of showing commands, just test command line for unsafe subcommand "
|
||||
"and return 0 in case if command is safe and 1 otherwise")
|
||||
parser.set_defaults(handler=handlers.UnsafeCommands, architecture=[""], lock=None, no_report=True, quiet=True,
|
||||
unsafe=True, parser=_parser)
|
||||
return parser
|
||||
|
||||
|
||||
def _set_key_import_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for key import subcommand
|
||||
:param root: subparsers for the commands
|
||||
:return: created argument parser
|
||||
|
||||
Args:
|
||||
root(SubParserAction): subparsers for the commands
|
||||
|
||||
Returns:
|
||||
argparse.ArgumentParser: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("key-import", help="import PGP key",
|
||||
description="import PGP key from public sources to the repository user",
|
||||
@ -136,8 +197,12 @@ def _set_key_import_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
def _set_package_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for package addition subcommand
|
||||
:param root: subparsers for the commands
|
||||
:return: created argument parser
|
||||
|
||||
Args:
|
||||
root(SubParserAction): subparsers for the commands
|
||||
|
||||
Returns:
|
||||
argparse.ArgumentParser: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("package-add", aliases=["add", "package-update"], help="add package",
|
||||
description="add existing or new package to the build queue",
|
||||
@ -153,6 +218,7 @@ def _set_package_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"5) and finally you can add package from AUR.",
|
||||
formatter_class=_formatter)
|
||||
parser.add_argument("package", help="package source (base name, path to local files, remote URL)", nargs="+")
|
||||
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
|
||||
parser.add_argument("-n", "--now", help="run update function after", action="store_true")
|
||||
parser.add_argument("-s", "--source", help="explicitly specify the package source for this command",
|
||||
type=PackageSource, choices=PackageSource, default=PackageSource.Auto)
|
||||
@ -164,8 +230,12 @@ def _set_package_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
def _set_package_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for package removal subcommand
|
||||
:param root: subparsers for the commands
|
||||
:return: created argument parser
|
||||
|
||||
Args:
|
||||
root(SubParserAction): subparsers for the commands
|
||||
|
||||
Returns:
|
||||
argparse.ArgumentParser: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("package-remove", aliases=["remove"], help="remove package",
|
||||
description="remove package from the repository", formatter_class=_formatter)
|
||||
@ -177,8 +247,12 @@ def _set_package_remove_parser(root: SubParserAction) -> argparse.ArgumentParser
|
||||
def _set_package_status_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for package status subcommand
|
||||
:param root: subparsers for the commands
|
||||
:return: created argument parser
|
||||
|
||||
Args:
|
||||
root(SubParserAction): subparsers for the commands
|
||||
|
||||
Returns:
|
||||
argparse.ArgumentParser: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("package-status", aliases=["status"], help="get package status",
|
||||
description="request status of the package",
|
||||
@ -186,6 +260,7 @@ def _set_package_status_parser(root: SubParserAction) -> argparse.ArgumentParser
|
||||
formatter_class=_formatter)
|
||||
parser.add_argument("package", help="filter status by package base", nargs="*")
|
||||
parser.add_argument("--ahriman", help="get service status itself", action="store_true")
|
||||
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
|
||||
parser.add_argument("-i", "--info", help="show additional package information", action="store_true")
|
||||
parser.add_argument("-s", "--status", help="filter packages by status",
|
||||
type=BuildStatusEnum, choices=BuildStatusEnum)
|
||||
@ -196,8 +271,12 @@ def _set_package_status_parser(root: SubParserAction) -> argparse.ArgumentParser
|
||||
def _set_package_status_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for package status remove subcommand
|
||||
:param root: subparsers for the commands
|
||||
:return: created argument parser
|
||||
|
||||
Args:
|
||||
root(SubParserAction): subparsers for the commands
|
||||
|
||||
Returns:
|
||||
argparse.ArgumentParser: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("package-status-remove", help="remove package status",
|
||||
description="remove the package from the status page",
|
||||
@ -213,8 +292,12 @@ def _set_package_status_remove_parser(root: SubParserAction) -> argparse.Argumen
|
||||
def _set_package_status_update_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for package status update subcommand
|
||||
:param root: subparsers for the commands
|
||||
:return: created argument parser
|
||||
|
||||
Args:
|
||||
root(SubParserAction): subparsers for the commands
|
||||
|
||||
Returns:
|
||||
argparse.ArgumentParser: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("package-status-update", aliases=["status-update"], help="update package status",
|
||||
description="update package status on the status page", formatter_class=_formatter)
|
||||
@ -231,8 +314,12 @@ def _set_package_status_update_parser(root: SubParserAction) -> argparse.Argumen
|
||||
def _set_patch_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for new patch subcommand
|
||||
:param root: subparsers for the commands
|
||||
:return: created argument parser
|
||||
|
||||
Args:
|
||||
root(SubParserAction): subparsers for the commands
|
||||
|
||||
Returns:
|
||||
argparse.ArgumentParser: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("patch-add", help="add patch set", description="create or update source patches",
|
||||
epilog="In order to add a patch set for the package you will need to clone "
|
||||
@ -251,12 +338,17 @@ def _set_patch_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
def _set_patch_list_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for list patches subcommand
|
||||
:param root: subparsers for the commands
|
||||
:return: created argument parser
|
||||
|
||||
Args:
|
||||
root(SubParserAction): subparsers for the commands
|
||||
|
||||
Returns:
|
||||
argparse.ArgumentParser: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("patch-list", help="list patch sets",
|
||||
description="list available patches for the package", formatter_class=_formatter)
|
||||
parser.add_argument("package", help="package base")
|
||||
parser.add_argument("package", help="package base", nargs="?")
|
||||
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
|
||||
parser.set_defaults(handler=handlers.Patch, action=Action.List, architecture=[""], lock=None, no_report=True)
|
||||
return parser
|
||||
|
||||
@ -264,8 +356,12 @@ def _set_patch_list_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
def _set_patch_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for remove patches subcommand
|
||||
:param root: subparsers for the commands
|
||||
:return: created argument parser
|
||||
|
||||
Args:
|
||||
root(SubParserAction): subparsers for the commands
|
||||
|
||||
Returns:
|
||||
argparse.ArgumentParser: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("patch-remove", help="remove patch set", description="remove patches for the package",
|
||||
formatter_class=_formatter)
|
||||
@ -274,26 +370,52 @@ def _set_patch_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
return parser
|
||||
|
||||
|
||||
def _set_repo_backup_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for repository backup subcommand
|
||||
|
||||
Args:
|
||||
root(SubParserAction): subparsers for the commands
|
||||
|
||||
Returns:
|
||||
argparse.ArgumentParser: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("repo-backup", help="backup repository data",
|
||||
description="backup settings and database", formatter_class=_formatter)
|
||||
parser.add_argument("path", help="path of the output archive", type=Path)
|
||||
parser.set_defaults(handler=handlers.Backup, architecture=[""], lock=None, no_report=True, unsafe=True)
|
||||
return parser
|
||||
|
||||
|
||||
def _set_repo_check_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for repository check subcommand
|
||||
:param root: subparsers for the commands
|
||||
:return: created argument parser
|
||||
|
||||
Args:
|
||||
root(SubParserAction): subparsers for the commands
|
||||
|
||||
Returns:
|
||||
argparse.ArgumentParser: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("repo-check", aliases=["check"], help="check for updates",
|
||||
description="check for packages updates. Same as update --dry-run --no-manual",
|
||||
formatter_class=_formatter)
|
||||
parser.add_argument("package", help="filter check by package base", nargs="*")
|
||||
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
|
||||
parser.add_argument("--no-vcs", help="do not check VCS packages", action="store_true")
|
||||
parser.set_defaults(handler=handlers.Update, dry_run=True, no_aur=False, no_manual=True)
|
||||
parser.set_defaults(handler=handlers.Update, dry_run=True, no_aur=False, no_local=False, no_manual=True)
|
||||
return parser
|
||||
|
||||
|
||||
def _set_repo_clean_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for repository clean subcommand
|
||||
:param root: subparsers for the commands
|
||||
:return: created argument parser
|
||||
|
||||
Args:
|
||||
root(SubParserAction): subparsers for the commands
|
||||
|
||||
Returns:
|
||||
argparse.ArgumentParser: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("repo-clean", aliases=["clean"], help="clean local caches",
|
||||
description="remove local caches",
|
||||
@ -301,12 +423,10 @@ def _set_repo_clean_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"you should not run this command manually. Also in case if you are going to clear "
|
||||
"the chroot directories you will need root privileges.",
|
||||
formatter_class=_formatter)
|
||||
parser.add_argument("--build", help="clear directory with package sources", action="store_true")
|
||||
parser.add_argument("--cache", help="clear directory with package caches", action="store_true")
|
||||
parser.add_argument("--chroot", help="clear build chroot", action="store_true")
|
||||
parser.add_argument("--manual", help="clear directory with manually added packages", action="store_true")
|
||||
parser.add_argument("--manual", help="clear manually added packages queue", action="store_true")
|
||||
parser.add_argument("--packages", help="clear directory with built packages", action="store_true")
|
||||
parser.add_argument("--patches", help="clear directory with patches", action="store_true")
|
||||
parser.set_defaults(handler=handlers.Clean, quiet=True, unsafe=True)
|
||||
return parser
|
||||
|
||||
@ -314,8 +434,12 @@ def _set_repo_clean_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
def _set_repo_config_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for config subcommand
|
||||
:param root: subparsers for the commands
|
||||
:return: created argument parser
|
||||
|
||||
Args:
|
||||
root(SubParserAction): subparsers for the commands
|
||||
|
||||
Returns:
|
||||
argparse.ArgumentParser: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("repo-config", aliases=["config"], help="dump configuration",
|
||||
description="dump configuration for the specified architecture",
|
||||
@ -324,28 +448,28 @@ def _set_repo_config_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
return parser
|
||||
|
||||
|
||||
def _set_repo_init_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for repository init subcommand
|
||||
:param root: subparsers for the commands
|
||||
:return: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("repo-init", aliases=["init"], help="create repository tree",
|
||||
description="create empty repository tree. Optional command for auto architecture support",
|
||||
formatter_class=_formatter)
|
||||
parser.set_defaults(handler=handlers.Init, no_report=True)
|
||||
return parser
|
||||
|
||||
|
||||
def _set_repo_rebuild_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for repository rebuild subcommand
|
||||
:param root: subparsers for the commands
|
||||
:return: created argument parser
|
||||
|
||||
Args:
|
||||
root(SubParserAction): subparsers for the commands
|
||||
|
||||
Returns:
|
||||
argparse.ArgumentParser: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("repo-rebuild", aliases=["rebuild"], help="rebuild repository",
|
||||
description="force rebuild whole repository", formatter_class=_formatter)
|
||||
parser.add_argument("--depends-on", help="only rebuild packages that depend on specified package", action="append")
|
||||
parser.add_argument("--dry-run", help="just perform check for packages without rebuild process itself",
|
||||
action="store_true")
|
||||
parser.add_argument("--from-database",
|
||||
help="read packages from database instead of filesystem. This feature in particular is "
|
||||
"required in case if you would like to restore repository from another repository "
|
||||
"instance. Note however that in order to restore packages you need to have original "
|
||||
"ahriman instance run with web service and have run repo-update at least once.",
|
||||
action="store_true")
|
||||
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
|
||||
parser.set_defaults(handler=handlers.Rebuild)
|
||||
return parser
|
||||
|
||||
@ -353,8 +477,12 @@ def _set_repo_rebuild_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
def _set_repo_remove_unknown_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for remove unknown packages subcommand
|
||||
:param root: subparsers for the commands
|
||||
:return: created argument parser
|
||||
|
||||
Args:
|
||||
root(SubParserAction): subparsers for the commands
|
||||
|
||||
Returns:
|
||||
argparse.ArgumentParser: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("repo-remove-unknown", aliases=["remove-unknown"], help="remove unknown packages",
|
||||
description="remove packages which are missing in AUR and do not have local PKGBUILDs",
|
||||
@ -368,8 +496,12 @@ def _set_repo_remove_unknown_parser(root: SubParserAction) -> argparse.ArgumentP
|
||||
def _set_repo_report_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for report subcommand
|
||||
:param root: subparsers for the commands
|
||||
:return: created argument parser
|
||||
|
||||
Args:
|
||||
root(SubParserAction): subparsers for the commands
|
||||
|
||||
Returns:
|
||||
argparse.ArgumentParser: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("repo-report", aliases=["report"], help="generate report",
|
||||
description="generate repository report according to current settings",
|
||||
@ -380,16 +512,39 @@ def _set_repo_report_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
return parser
|
||||
|
||||
|
||||
def _set_repo_restore_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for repository restore subcommand
|
||||
|
||||
Args:
|
||||
root(SubParserAction): subparsers for the commands
|
||||
|
||||
Returns:
|
||||
argparse.ArgumentParser: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("repo-restore", help="restore repository data",
|
||||
description="restore settings and database", formatter_class=_formatter)
|
||||
parser.add_argument("path", help="path of the input archive", type=Path)
|
||||
parser.add_argument("-o", "--output", help="root path of the extracted files", type=Path, default=Path("/"))
|
||||
parser.set_defaults(handler=handlers.Restore, architecture=[""], lock=None, no_report=True, unsafe=True)
|
||||
return parser
|
||||
|
||||
|
||||
def _set_repo_setup_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for setup subcommand
|
||||
:param root: subparsers for the commands
|
||||
:return: created argument parser
|
||||
|
||||
Args:
|
||||
root(SubParserAction): subparsers for the commands
|
||||
|
||||
Returns:
|
||||
argparse.ArgumentParser: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("repo-setup", aliases=["setup"], help="initial service configuration",
|
||||
parser = root.add_parser("repo-setup", aliases=["init", "repo-init", "setup"], help="initial service configuration",
|
||||
description="create initial service configuration, requires root",
|
||||
epilog="Create _minimal_ configuration for the service according to provided options.",
|
||||
formatter_class=_formatter)
|
||||
parser.add_argument("--build-as-user", help="force makepkg user to the specific one")
|
||||
parser.add_argument("--build-command", help="build command prefix", default="ahriman")
|
||||
parser.add_argument("--from-configuration", help="path to default devtools pacman configuration",
|
||||
type=Path, default=Path("/usr/share/devtools/pacman-extra.conf"))
|
||||
@ -407,8 +562,12 @@ def _set_repo_setup_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
def _set_repo_sign_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for sign subcommand
|
||||
:param root: subparsers for the commands
|
||||
:return: created argument parser
|
||||
|
||||
Args:
|
||||
root(SubParserAction): subparsers for the commands
|
||||
|
||||
Returns:
|
||||
argparse.ArgumentParser: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("repo-sign", aliases=["sign"], help="sign packages",
|
||||
description="(re-)sign packages and repository database according to current settings",
|
||||
@ -422,8 +581,12 @@ def _set_repo_sign_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
def _set_repo_status_update_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for repository status update subcommand
|
||||
:param root: subparsers for the commands
|
||||
:return: created argument parser
|
||||
|
||||
Args:
|
||||
root(SubParserAction): subparsers for the commands
|
||||
|
||||
Returns:
|
||||
argparse.ArgumentParser: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("repo-status-update", help="update repository status",
|
||||
description="update repository status on the status page", formatter_class=_formatter)
|
||||
@ -437,8 +600,12 @@ def _set_repo_status_update_parser(root: SubParserAction) -> argparse.ArgumentPa
|
||||
def _set_repo_sync_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for repository sync subcommand
|
||||
:param root: subparsers for the commands
|
||||
:return: created argument parser
|
||||
|
||||
Args:
|
||||
root(SubParserAction): subparsers for the commands
|
||||
|
||||
Returns:
|
||||
argparse.ArgumentParser: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("repo-sync", aliases=["sync"], help="sync repository",
|
||||
description="sync repository files to remote server according to current settings",
|
||||
@ -452,15 +619,21 @@ def _set_repo_sync_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
def _set_repo_update_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for repository update subcommand
|
||||
:param root: subparsers for the commands
|
||||
:return: created argument parser
|
||||
|
||||
Args:
|
||||
root(SubParserAction): subparsers for the commands
|
||||
|
||||
Returns:
|
||||
argparse.ArgumentParser: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("repo-update", aliases=["update"], help="update packages",
|
||||
description="check for packages updates and run build process if requested",
|
||||
formatter_class=_formatter)
|
||||
parser.add_argument("package", help="filter check by package base", nargs="*")
|
||||
parser.add_argument("--dry-run", help="just perform check for updates, same as check command", action="store_true")
|
||||
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
|
||||
parser.add_argument("--no-aur", help="do not check for AUR updates. Implies --no-vcs", action="store_true")
|
||||
parser.add_argument("--no-local", help="do not check local packages for updates", action="store_true")
|
||||
parser.add_argument("--no-manual", help="do not include manual updates", action="store_true")
|
||||
parser.add_argument("--no-vcs", help="do not check VCS packages", action="store_true")
|
||||
parser.set_defaults(handler=handlers.Update)
|
||||
@ -470,8 +643,12 @@ def _set_repo_update_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
def _set_user_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for create user subcommand
|
||||
:param root: subparsers for the commands
|
||||
:return: created argument parser
|
||||
|
||||
Args:
|
||||
root(SubParserAction): subparsers for the commands
|
||||
|
||||
Returns:
|
||||
argparse.ArgumentParser: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("user-add", help="create or update user",
|
||||
description="update user for web services with the given password and role. "
|
||||
@ -479,39 +656,66 @@ def _set_user_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
formatter_class=_formatter)
|
||||
parser.add_argument("username", help="username for web service")
|
||||
parser.add_argument("--as-service", help="add user as service user", action="store_true")
|
||||
parser.add_argument("--no-reload", help="do not reload authentication module", action="store_true")
|
||||
parser.add_argument("-p", "--password", help="user password. Blank password will be treated as empty password, "
|
||||
"which is in particular must be used for OAuth2 authorization type.")
|
||||
parser.add_argument("-r", "--role", help="user access level",
|
||||
type=UserAccess, choices=UserAccess, default=UserAccess.Read)
|
||||
parser.add_argument("-s", "--secure", help="set file permissions to user-only", action="store_true")
|
||||
parser.set_defaults(handler=handlers.User, action=Action.Update, architecture=[""], lock=None, no_report=True,
|
||||
parser.set_defaults(handler=handlers.Users, action=Action.Update, architecture=[""], lock=None, no_report=True,
|
||||
quiet=True, unsafe=True)
|
||||
return parser
|
||||
|
||||
|
||||
def _set_user_list_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for user list subcommand
|
||||
|
||||
Args:
|
||||
root(SubParserAction): subparsers for the commands
|
||||
|
||||
Returns:
|
||||
argparse.ArgumentParser: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("user-list", help="user known users and their access",
|
||||
description="list users from the user mapping and their roles",
|
||||
formatter_class=_formatter)
|
||||
parser.add_argument("username", help="filter users by username", nargs="?")
|
||||
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
|
||||
parser.add_argument("-r", "--role", help="filter users by role", type=UserAccess, choices=UserAccess)
|
||||
parser.set_defaults(handler=handlers.Users, action=Action.List, architecture=[""], lock=None, no_report=True, # nosec
|
||||
password="", quiet=True, unsafe=True)
|
||||
return parser
|
||||
|
||||
|
||||
def _set_user_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for user removal subcommand
|
||||
:param root: subparsers for the commands
|
||||
:return: created argument parser
|
||||
|
||||
Args:
|
||||
root(SubParserAction): subparsers for the commands
|
||||
|
||||
Returns:
|
||||
argparse.ArgumentParser: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("user-remove", help="remove user",
|
||||
description="remove user from the user mapping and update the configuration",
|
||||
formatter_class=_formatter)
|
||||
parser.add_argument("username", help="username for web service")
|
||||
parser.add_argument("--no-reload", help="do not reload authentication module", action="store_true")
|
||||
parser.add_argument("-s", "--secure", help="set file permissions to user-only", action="store_true")
|
||||
parser.set_defaults(handler=handlers.User, action=Action.Remove, architecture=[""], lock=None, no_report=True, # nosec
|
||||
password="", quiet=True, role=UserAccess.Read, unsafe=True)
|
||||
parser.set_defaults(handler=handlers.Users, action=Action.Remove, architecture=[""], lock=None, no_report=True, # nosec
|
||||
password="", quiet=True, unsafe=True)
|
||||
return parser
|
||||
|
||||
|
||||
def _set_web_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for web subcommand
|
||||
:param root: subparsers for the commands
|
||||
:return: created argument parser
|
||||
|
||||
Args:
|
||||
root(SubParserAction): subparsers for the commands
|
||||
|
||||
Returns:
|
||||
argparse.ArgumentParser: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("web", help="web server", description="start web server", formatter_class=_formatter)
|
||||
parser.set_defaults(handler=handlers.Web, lock=None, no_report=True, parser=_parser)
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
@ -17,29 +17,34 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from typing import Iterable, Set
|
||||
from typing import Set
|
||||
|
||||
from ahriman.application.application.packages import Packages
|
||||
from ahriman.application.application.repository import Repository
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.application.application.application_packages import ApplicationPackages
|
||||
from ahriman.application.application.application_repository import ApplicationRepository
|
||||
from ahriman.models.result import Result
|
||||
|
||||
|
||||
class Application(Packages, Repository):
|
||||
class Application(ApplicationPackages, ApplicationRepository):
|
||||
"""
|
||||
base application class
|
||||
"""
|
||||
|
||||
def _finalize(self, built_packages: Iterable[Package]) -> None:
|
||||
def _finalize(self, result: Result) -> None:
|
||||
"""
|
||||
generate report and sync to remote server
|
||||
|
||||
Args:
|
||||
result(Result): build result
|
||||
"""
|
||||
self.report([], built_packages)
|
||||
self.sync([], built_packages)
|
||||
self.report([], result)
|
||||
self.sync([], result.success)
|
||||
|
||||
def _known_packages(self) -> Set[str]:
|
||||
"""
|
||||
load packages from repository and pacman repositories
|
||||
:return: list of known packages
|
||||
|
||||
Returns:
|
||||
Set[str]: list of known packages
|
||||
"""
|
||||
known_packages: Set[str] = set()
|
||||
# local set
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
@ -23,35 +23,49 @@ import shutil
|
||||
from pathlib import Path
|
||||
from typing import Any, Iterable, Set
|
||||
|
||||
from ahriman.application.application.properties import Properties
|
||||
from ahriman.application.application.application_properties import ApplicationProperties
|
||||
from ahriman.core.build_tools.sources import Sources
|
||||
from ahriman.core.util import package_like
|
||||
from ahriman.core.util import package_like, tmpdir
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.package_source import PackageSource
|
||||
from ahriman.models.result import Result
|
||||
|
||||
|
||||
class Packages(Properties):
|
||||
class ApplicationPackages(ApplicationProperties):
|
||||
"""
|
||||
package control class
|
||||
"""
|
||||
|
||||
def _finalize(self, built_packages: Iterable[Package]) -> None:
|
||||
def _finalize(self, result: Result) -> None:
|
||||
"""
|
||||
generate report and sync to remote server
|
||||
|
||||
Args:
|
||||
result(Result): build result
|
||||
|
||||
Raises:
|
||||
NotImplementedError: not implemented method
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def _known_packages(self) -> Set[str]:
|
||||
"""
|
||||
load packages from repository and pacman repositories
|
||||
:return: list of known packages
|
||||
|
||||
Returns:
|
||||
Set[str]: list of known packages
|
||||
|
||||
Raises:
|
||||
NotImplementedError: not implemented method
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def _add_archive(self, source: str, *_: Any) -> None:
|
||||
"""
|
||||
add package from archive
|
||||
:param source: path to package archive
|
||||
|
||||
Args:
|
||||
source(str): path to package archive
|
||||
"""
|
||||
local_path = Path(source)
|
||||
dst = self.repository.paths.packages / local_path.name
|
||||
@ -60,21 +74,26 @@ class Packages(Properties):
|
||||
def _add_aur(self, source: str, known_packages: Set[str], without_dependencies: bool) -> None:
|
||||
"""
|
||||
add package from AUR
|
||||
:param source: package base name
|
||||
:param known_packages: list of packages which are known by the service
|
||||
:param without_dependencies: if set, dependency check will be disabled
|
||||
"""
|
||||
aur_url = self.configuration.get("alpm", "aur_url")
|
||||
package = Package.load(source, PackageSource.AUR, self.repository.pacman, aur_url)
|
||||
local_path = self.repository.paths.manual_for(package.base)
|
||||
|
||||
Sources.load(local_path, package.git_url, self.repository.paths.patches_for(package.base))
|
||||
self._process_dependencies(local_path, known_packages, without_dependencies)
|
||||
Args:
|
||||
source(str): package base name
|
||||
known_packages(Set[str]): list of packages which are known by the service
|
||||
without_dependencies(bool): if set, dependency check will be disabled
|
||||
"""
|
||||
package = Package.load(source, PackageSource.AUR, self.repository.pacman, self.repository.aur_url)
|
||||
|
||||
self.database.build_queue_insert(package)
|
||||
|
||||
with tmpdir() as local_path:
|
||||
Sources.load(local_path, package.git_url, self.database.patches_get(package.base))
|
||||
self._process_dependencies(local_path, known_packages, without_dependencies)
|
||||
|
||||
def _add_directory(self, source: str, *_: Any) -> None:
|
||||
"""
|
||||
add packages from directory
|
||||
:param source: path to local directory
|
||||
|
||||
Args:
|
||||
source(str): path to local directory
|
||||
"""
|
||||
local_path = Path(source)
|
||||
for full_path in filter(package_like, local_path.iterdir()):
|
||||
@ -83,24 +102,27 @@ class Packages(Properties):
|
||||
def _add_local(self, source: str, known_packages: Set[str], without_dependencies: bool) -> None:
|
||||
"""
|
||||
add package from local PKGBUILDs
|
||||
:param source: path to directory with local source files
|
||||
:param known_packages: list of packages which are known by the service
|
||||
:param without_dependencies: if set, dependency check will be disabled
|
||||
|
||||
Args:
|
||||
source(str): path to directory with local source files
|
||||
known_packages(Set[str]): list of packages which are known by the service
|
||||
without_dependencies(bool): if set, dependency check will be disabled
|
||||
"""
|
||||
aur_url = self.configuration.get("alpm", "aur_url")
|
||||
package = Package.load(source, PackageSource.Local, self.repository.pacman, aur_url)
|
||||
package = Package.load(source, PackageSource.Local, self.repository.pacman, self.repository.aur_url)
|
||||
cache_dir = self.repository.paths.cache_for(package.base)
|
||||
shutil.copytree(Path(source), cache_dir) # copy package to store in caches
|
||||
Sources.init(cache_dir) # we need to run init command in directory where we do have permissions
|
||||
|
||||
dst = self.repository.paths.manual_for(package.base)
|
||||
shutil.copytree(cache_dir, dst) # copy package for the build
|
||||
self._process_dependencies(dst, known_packages, without_dependencies)
|
||||
self.database.build_queue_insert(package)
|
||||
|
||||
self._process_dependencies(cache_dir, known_packages, without_dependencies)
|
||||
|
||||
def _add_remote(self, source: str, *_: Any) -> None:
|
||||
"""
|
||||
add package from remote sources (e.g. HTTP)
|
||||
:param remote_url: remote URL to the package archive
|
||||
|
||||
Args:
|
||||
source(str): remote URL of the package archive
|
||||
"""
|
||||
dst = self.repository.paths.packages / Path(source).name # URL is path, is not it?
|
||||
response = requests.get(source, stream=True)
|
||||
@ -113,9 +135,11 @@ class Packages(Properties):
|
||||
def _process_dependencies(self, local_path: Path, known_packages: Set[str], without_dependencies: bool) -> None:
|
||||
"""
|
||||
process package dependencies
|
||||
:param local_path: path to local package sources (i.e. cloned AUR repository)
|
||||
:param known_packages: list of packages which are known by the service
|
||||
:param without_dependencies: if set, dependency check will be disabled
|
||||
|
||||
Args:
|
||||
local_path(Path): path to local package sources (i.e. cloned AUR repository)
|
||||
known_packages(Set[str]): list of packages which are known by the service
|
||||
without_dependencies(bool): if set, dependency check will be disabled
|
||||
"""
|
||||
if without_dependencies:
|
||||
return
|
||||
@ -126,9 +150,11 @@ class Packages(Properties):
|
||||
def add(self, names: Iterable[str], source: PackageSource, without_dependencies: bool) -> None:
|
||||
"""
|
||||
add packages for the next build
|
||||
:param names: list of package bases to add
|
||||
:param source: package source to add
|
||||
:param without_dependencies: if set, dependency check will be disabled
|
||||
|
||||
Args:
|
||||
names(Iterable[str]): list of package bases to add
|
||||
source(PackageSource): package source to add
|
||||
without_dependencies(bool): if set, dependency check will be disabled
|
||||
"""
|
||||
known_packages = self._known_packages() # speedup dependencies processing
|
||||
|
||||
@ -140,7 +166,9 @@ class Packages(Properties):
|
||||
def remove(self, names: Iterable[str]) -> None:
|
||||
"""
|
||||
remove packages from repository
|
||||
:param names: list of packages (either base or name) to remove
|
||||
|
||||
Args:
|
||||
names(Iterable[str]): list of packages (either base or name) to remove
|
||||
"""
|
||||
self.repository.process_remove(names)
|
||||
self._finalize([])
|
||||
self._finalize(Result())
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
@ -20,26 +20,34 @@
|
||||
import logging
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database.sqlite import SQLite
|
||||
from ahriman.core.repository import Repository
|
||||
|
||||
|
||||
class Properties:
|
||||
class ApplicationProperties:
|
||||
"""
|
||||
application base properties class
|
||||
:ivar architecture: repository architecture
|
||||
:ivar configuration: configuration instance
|
||||
:ivar logger: application logger
|
||||
:ivar repository: repository instance
|
||||
|
||||
Attributes:
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
database(SQLite): database instance
|
||||
logger(logging.Logger): application logger
|
||||
repository(Repository): repository instance
|
||||
"""
|
||||
|
||||
def __init__(self, architecture: str, configuration: Configuration, no_report: bool) -> None:
|
||||
def __init__(self, architecture: str, configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
default constructor
|
||||
:param architecture: repository architecture
|
||||
:param configuration: configuration instance
|
||||
:param no_report: force disable reporting
|
||||
|
||||
Args:
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
no_report(bool): force disable reporting
|
||||
unsafe(bool): if set no user check will be performed before path creation
|
||||
"""
|
||||
self.logger = logging.getLogger("root")
|
||||
self.configuration = configuration
|
||||
self.architecture = architecture
|
||||
self.repository = Repository(architecture, configuration, no_report)
|
||||
self.database = SQLite.load(configuration)
|
||||
self.repository = Repository(architecture, configuration, self.database, no_report, unsafe)
|
212
src/ahriman/application/application/application_repository.py
Normal file
212
src/ahriman/application/application/application_repository.py
Normal file
@ -0,0 +1,212 @@
|
||||
#
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
import shutil
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Callable, Iterable, List
|
||||
|
||||
from ahriman.application.application.application_properties import ApplicationProperties
|
||||
from ahriman.core.build_tools.sources import Sources
|
||||
from ahriman.core.formatters.update_printer import UpdatePrinter
|
||||
from ahriman.core.tree import Tree
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.result import Result
|
||||
|
||||
|
||||
class ApplicationRepository(ApplicationProperties):
|
||||
"""
|
||||
repository control class
|
||||
"""
|
||||
|
||||
def _finalize(self, result: Result) -> None:
|
||||
"""
|
||||
generate report and sync to remote server
|
||||
|
||||
Args:
|
||||
result(Result): build result
|
||||
|
||||
Raises:
|
||||
NotImplementedError: not implemented method
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def clean(self, cache: bool, chroot: bool, manual: bool, packages: bool) -> None:
|
||||
"""
|
||||
run all clean methods. Warning: some functions might not be available under non-root
|
||||
|
||||
Args:
|
||||
cache(bool): clear directory with package caches
|
||||
chroot(bool): clear build chroot
|
||||
manual(bool): clear directory with manually added packages
|
||||
packages(bool): clear directory with built packages
|
||||
"""
|
||||
if cache:
|
||||
self.repository.clear_cache()
|
||||
if chroot:
|
||||
self.repository.clear_chroot()
|
||||
if manual:
|
||||
self.repository.clear_queue()
|
||||
if packages:
|
||||
self.repository.clear_packages()
|
||||
|
||||
def report(self, target: Iterable[str], result: Result) -> None:
|
||||
"""
|
||||
generate report
|
||||
|
||||
Args:
|
||||
target(Iterable[str]): list of targets to run (e.g. html)
|
||||
result(Result): build result
|
||||
"""
|
||||
targets = target or None
|
||||
self.repository.process_report(targets, result)
|
||||
|
||||
def sign(self, packages: Iterable[str]) -> None:
|
||||
"""
|
||||
sign packages and repository
|
||||
|
||||
Args:
|
||||
packages(Iterable[str]): only sign specified packages
|
||||
"""
|
||||
# copy to prebuilt directory
|
||||
for package in self.repository.packages():
|
||||
# no one requested this package
|
||||
if packages and package.base not in packages:
|
||||
continue
|
||||
for archive in package.packages.values():
|
||||
if archive.filepath is None:
|
||||
self.logger.warning("filepath is empty for %s", package.base)
|
||||
continue # avoid mypy warning
|
||||
src = self.repository.paths.repository / archive.filepath
|
||||
dst = self.repository.paths.packages / archive.filepath
|
||||
shutil.copy(src, dst)
|
||||
# run generic update function
|
||||
self.update([])
|
||||
# sign repository database if set
|
||||
self.repository.sign.process_sign_repository(self.repository.repo.repo_path)
|
||||
self._finalize(Result())
|
||||
|
||||
def sync(self, target: Iterable[str], built_packages: Iterable[Package]) -> None:
|
||||
"""
|
||||
sync to remote server
|
||||
|
||||
Args:
|
||||
target(Iterable[str]): list of targets to run (e.g. s3)
|
||||
built_packages(Iterable[Package]): list of packages which has just been built
|
||||
"""
|
||||
targets = target or None
|
||||
self.repository.process_sync(targets, built_packages)
|
||||
|
||||
def unknown(self) -> List[str]:
|
||||
"""
|
||||
get packages which were not found in AUR
|
||||
|
||||
Returns:
|
||||
List[str]: unknown package archive list
|
||||
"""
|
||||
def has_local(probe: Package) -> bool:
|
||||
cache_dir = self.repository.paths.cache_for(probe.base)
|
||||
return cache_dir.is_dir() and not Sources.has_remotes(cache_dir)
|
||||
|
||||
def unknown_aur(probe: Package) -> List[str]:
|
||||
packages: List[str] = []
|
||||
for single in probe.packages:
|
||||
try:
|
||||
_ = Package.from_aur(single, probe.aur_url)
|
||||
except Exception:
|
||||
packages.append(single)
|
||||
return packages
|
||||
|
||||
def unknown_local(probe: Package) -> List[str]:
|
||||
cache_dir = self.repository.paths.cache_for(probe.base)
|
||||
local = Package.from_build(cache_dir, probe.aur_url)
|
||||
packages = set(probe.packages.keys()).difference(local.packages.keys())
|
||||
return list(packages)
|
||||
|
||||
result = []
|
||||
for package in self.repository.packages():
|
||||
if has_local(package):
|
||||
result.extend(unknown_local(package)) # there is local package
|
||||
else:
|
||||
result.extend(unknown_aur(package)) # local package not found
|
||||
return result
|
||||
|
||||
def update(self, updates: Iterable[Package]) -> Result:
|
||||
"""
|
||||
run package updates
|
||||
|
||||
Args:
|
||||
updates(Iterable[Package]): list of packages to update
|
||||
|
||||
Returns:
|
||||
Result: update result
|
||||
"""
|
||||
def process_update(paths: Iterable[Path], result: Result) -> None:
|
||||
if not paths:
|
||||
return # don't need to process if no update supplied
|
||||
update_result = self.repository.process_update(paths)
|
||||
self._finalize(result.merge(update_result))
|
||||
|
||||
# process built packages
|
||||
build_result = Result()
|
||||
packages = self.repository.packages_built()
|
||||
process_update(packages, build_result)
|
||||
|
||||
# process manual packages
|
||||
tree = Tree.load(updates, self.database)
|
||||
for num, level in enumerate(tree.levels()):
|
||||
self.logger.info("processing level #%i %s", num, [package.base for package in level])
|
||||
build_result = self.repository.process_build(level)
|
||||
packages = self.repository.packages_built()
|
||||
process_update(packages, build_result)
|
||||
|
||||
return build_result
|
||||
|
||||
def updates(self, filter_packages: Iterable[str], no_aur: bool, no_local: bool, no_manual: bool, no_vcs: bool,
|
||||
log_fn: Callable[[str], None]) -> List[Package]:
|
||||
"""
|
||||
get list of packages to run update process
|
||||
|
||||
Args:
|
||||
filter_packages(Iterable[str]): do not check every package just specified in the list
|
||||
no_aur(bool): do not check for aur updates
|
||||
no_local(bool): do not check local packages for updates
|
||||
no_manual(bool): do not check for manual updates
|
||||
no_vcs(bool): do not check VCS packages
|
||||
log_fn(Callable[[str], None]): logger function to log updates
|
||||
|
||||
Returns:
|
||||
List[Package]: list of out-of-dated packages
|
||||
"""
|
||||
updates = {}
|
||||
|
||||
if not no_aur:
|
||||
updates.update({package.base: package for package in self.repository.updates_aur(filter_packages, no_vcs)})
|
||||
if not no_local:
|
||||
updates.update({package.base: package for package in self.repository.updates_local()})
|
||||
if not no_manual:
|
||||
updates.update({package.base: package for package in self.repository.updates_manual()})
|
||||
|
||||
local_versions = {package.base: package.version for package in self.repository.packages()}
|
||||
updated_packages = [package for _, package in sorted(updates.items())]
|
||||
for package in updated_packages:
|
||||
UpdatePrinter(package, local_versions.get(package.base)).print(
|
||||
verbose=True, log_fn=log_fn, separator=" -> ")
|
||||
|
||||
return updated_packages
|
@ -1,179 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
import shutil
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Callable, Iterable, List
|
||||
|
||||
from ahriman.application.application.properties import Properties
|
||||
from ahriman.application.formatters.update_printer import UpdatePrinter
|
||||
from ahriman.core.build_tools.sources import Sources
|
||||
from ahriman.core.tree import Tree
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.package_source import PackageSource
|
||||
|
||||
|
||||
class Repository(Properties):
|
||||
"""
|
||||
repository control class
|
||||
"""
|
||||
|
||||
def _finalize(self, built_packages: Iterable[Package]) -> None:
|
||||
"""
|
||||
generate report and sync to remote server
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def clean(self, build: bool, cache: bool, chroot: bool, manual: bool, packages: bool, patches: bool) -> None:
|
||||
"""
|
||||
run all clean methods. Warning: some functions might not be available under non-root
|
||||
:param build: clear directory with package sources
|
||||
:param cache: clear directory with package caches
|
||||
:param chroot: clear build chroot
|
||||
:param manual: clear directory with manually added packages
|
||||
:param packages: clear directory with built packages
|
||||
:param patches: clear directory with patches
|
||||
"""
|
||||
if build:
|
||||
self.repository.clear_build()
|
||||
if cache:
|
||||
self.repository.clear_cache()
|
||||
if chroot:
|
||||
self.repository.clear_chroot()
|
||||
if manual:
|
||||
self.repository.clear_manual()
|
||||
if packages:
|
||||
self.repository.clear_packages()
|
||||
if patches:
|
||||
self.repository.clear_patches()
|
||||
|
||||
def report(self, target: Iterable[str], built_packages: Iterable[Package]) -> None:
|
||||
"""
|
||||
generate report
|
||||
:param target: list of targets to run (e.g. html)
|
||||
:param built_packages: list of packages which has just been built
|
||||
"""
|
||||
targets = target or None
|
||||
self.repository.process_report(targets, built_packages)
|
||||
|
||||
def sign(self, packages: Iterable[str]) -> None:
|
||||
"""
|
||||
sign packages and repository
|
||||
:param packages: only sign specified packages
|
||||
"""
|
||||
# copy to prebuilt directory
|
||||
for package in self.repository.packages():
|
||||
# no one requested this package
|
||||
if packages and package.base not in packages:
|
||||
continue
|
||||
for archive in package.packages.values():
|
||||
if archive.filepath is None:
|
||||
self.logger.warning("filepath is empty for %s", package.base)
|
||||
continue # avoid mypy warning
|
||||
src = self.repository.paths.repository / archive.filepath
|
||||
dst = self.repository.paths.packages / archive.filepath
|
||||
shutil.copy(src, dst)
|
||||
# run generic update function
|
||||
self.update([])
|
||||
# sign repository database if set
|
||||
self.repository.sign.process_sign_repository(self.repository.repo.repo_path)
|
||||
self._finalize([])
|
||||
|
||||
def sync(self, target: Iterable[str], built_packages: Iterable[Package]) -> None:
|
||||
"""
|
||||
sync to remote server
|
||||
:param target: list of targets to run (e.g. s3)
|
||||
:param built_packages: list of packages which has just been built
|
||||
"""
|
||||
targets = target or None
|
||||
self.repository.process_sync(targets, built_packages)
|
||||
|
||||
def unknown(self) -> List[Package]:
|
||||
"""
|
||||
get packages which were not found in AUR
|
||||
:return: unknown package list
|
||||
"""
|
||||
def has_aur(package_base: str, aur_url: str) -> bool:
|
||||
try:
|
||||
_ = Package.from_aur(package_base, aur_url)
|
||||
except Exception:
|
||||
return False
|
||||
return True
|
||||
|
||||
def has_local(package_base: str) -> bool:
|
||||
cache_dir = self.repository.paths.cache_for(package_base)
|
||||
return cache_dir.is_dir() and not Sources.has_remotes(cache_dir)
|
||||
|
||||
return [
|
||||
package
|
||||
for package in self.repository.packages()
|
||||
if not has_aur(package.base, package.aur_url) and not has_local(package.base)
|
||||
]
|
||||
|
||||
def update(self, updates: Iterable[Package]) -> None:
|
||||
"""
|
||||
run package updates
|
||||
:param updates: list of packages to update
|
||||
"""
|
||||
def process_update(paths: Iterable[Path]) -> None:
|
||||
if not paths:
|
||||
return # don't need to process if no update supplied
|
||||
updated = [
|
||||
Package.load(str(path), PackageSource.Archive, self.repository.pacman, self.repository.aur_url)
|
||||
for path in paths
|
||||
]
|
||||
self.repository.process_update(paths)
|
||||
self._finalize(updated)
|
||||
|
||||
# process built packages
|
||||
packages = self.repository.packages_built()
|
||||
process_update(packages)
|
||||
|
||||
# process manual packages
|
||||
tree = Tree.load(updates, self.repository.paths)
|
||||
for num, level in enumerate(tree.levels()):
|
||||
self.logger.info("processing level #%i %s", num, [package.base for package in level])
|
||||
packages = self.repository.process_build(level)
|
||||
process_update(packages)
|
||||
|
||||
def updates(self, filter_packages: Iterable[str], no_aur: bool, no_manual: bool, no_vcs: bool,
|
||||
log_fn: Callable[[str], None]) -> List[Package]:
|
||||
"""
|
||||
get list of packages to run update process
|
||||
:param filter_packages: do not check every package just specified in the list
|
||||
:param no_aur: do not check for aur updates
|
||||
:param no_manual: do not check for manual updates
|
||||
:param no_vcs: do not check VCS packages
|
||||
:param log_fn: logger function to log updates
|
||||
:return: list of out-of-dated packages
|
||||
"""
|
||||
updates = []
|
||||
|
||||
if not no_aur:
|
||||
updates.extend(self.repository.updates_aur(filter_packages, no_vcs))
|
||||
if not no_manual:
|
||||
updates.extend(self.repository.updates_manual())
|
||||
|
||||
local_versions = {package.base: package.version for package in self.repository.packages()}
|
||||
for package in updates:
|
||||
UpdatePrinter(package, local_versions.get(package.base)).print(
|
||||
verbose=True, log_fn=log_fn, separator=" -> ")
|
||||
|
||||
return updates
|
@ -1,62 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
import aur # type: ignore
|
||||
|
||||
from typing import List, Optional
|
||||
|
||||
from ahriman.application.formatters.printer import Printer
|
||||
from ahriman.core.util import pretty_datetime
|
||||
from ahriman.models.property import Property
|
||||
|
||||
|
||||
class AurPrinter(Printer):
|
||||
"""
|
||||
print content of the AUR package
|
||||
"""
|
||||
|
||||
def __init__(self, package: aur.Package) -> None:
|
||||
"""
|
||||
default constructor
|
||||
:param package: AUR package description
|
||||
"""
|
||||
self.content = package
|
||||
|
||||
def properties(self) -> List[Property]:
|
||||
"""
|
||||
convert content into printable data
|
||||
:return: list of content properties
|
||||
"""
|
||||
return [
|
||||
Property("Package base", self.content.package_base),
|
||||
Property("Description", self.content.description, is_required=True),
|
||||
Property("Upstream URL", self.content.url),
|
||||
Property("Licenses", self.content.license), # it should be actually a list
|
||||
Property("Maintainer", self.content.maintainer or ""), # I think it is optional
|
||||
Property("First submitted", pretty_datetime(self.content.first_submitted)),
|
||||
Property("Last updated", pretty_datetime(self.content.last_modified)),
|
||||
# more fields coming https://github.com/cdown/aur/pull/29
|
||||
]
|
||||
|
||||
def title(self) -> Optional[str]:
|
||||
"""
|
||||
generate entry title from content
|
||||
:return: content title if it can be generated and None otherwise
|
||||
"""
|
||||
return f"{self.content.name} {self.content.version} ({self.content.num_votes})"
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
@ -20,21 +20,24 @@
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
|
||||
from ahriman.application.handlers.add import Add
|
||||
from ahriman.application.handlers.backup import Backup
|
||||
from ahriman.application.handlers.clean import Clean
|
||||
from ahriman.application.handlers.dump import Dump
|
||||
from ahriman.application.handlers.init import Init
|
||||
from ahriman.application.handlers.help import Help
|
||||
from ahriman.application.handlers.key_import import KeyImport
|
||||
from ahriman.application.handlers.patch import Patch
|
||||
from ahriman.application.handlers.rebuild import Rebuild
|
||||
from ahriman.application.handlers.remove import Remove
|
||||
from ahriman.application.handlers.remove_unknown import RemoveUnknown
|
||||
from ahriman.application.handlers.report import Report
|
||||
from ahriman.application.handlers.restore import Restore
|
||||
from ahriman.application.handlers.search import Search
|
||||
from ahriman.application.handlers.setup import Setup
|
||||
from ahriman.application.handlers.sign import Sign
|
||||
from ahriman.application.handlers.status import Status
|
||||
from ahriman.application.handlers.status_update import StatusUpdate
|
||||
from ahriman.application.handlers.sync import Sync
|
||||
from ahriman.application.handlers.unsafe_commands import UnsafeCommands
|
||||
from ahriman.application.handlers.update import Update
|
||||
from ahriman.application.handlers.user import User
|
||||
from ahriman.application.handlers.users import Users
|
||||
from ahriman.application.handlers.web import Web
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
@ -33,18 +33,22 @@ class Add(Handler):
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
||||
configuration: Configuration, no_report: bool) -> None:
|
||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
:param args: command line args
|
||||
:param architecture: repository architecture
|
||||
:param configuration: configuration instance
|
||||
:param no_report: force disable reporting
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
no_report(bool): force disable reporting
|
||||
unsafe(bool): if set no user check will be performed before path creation
|
||||
"""
|
||||
application = Application(architecture, configuration, no_report)
|
||||
application = Application(architecture, configuration, no_report, unsafe)
|
||||
application.add(args.package, args.source, args.without_dependencies)
|
||||
if not args.now:
|
||||
return
|
||||
|
||||
packages = application.updates(args.package, True, False, True, application.logger.info)
|
||||
application.update(packages)
|
||||
packages = application.updates(args.package, True, True, False, True, application.logger.info)
|
||||
result = application.update(packages)
|
||||
Add.check_if_empty(args.exit_code, result.is_empty)
|
||||
|
86
src/ahriman/application/handlers/backup.py
Normal file
86
src/ahriman/application/handlers/backup.py
Normal file
@ -0,0 +1,86 @@
|
||||
#
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
import argparse
|
||||
import pwd
|
||||
|
||||
from pathlib import Path
|
||||
from tarfile import TarFile
|
||||
from typing import Set, Type
|
||||
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database.sqlite import SQLite
|
||||
|
||||
|
||||
class Backup(Handler):
|
||||
"""
|
||||
backup packages handler
|
||||
"""
|
||||
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
no_report(bool): force disable reporting
|
||||
unsafe(bool): if set no user check will be performed before path creation
|
||||
"""
|
||||
backup_paths = Backup.get_paths(configuration)
|
||||
with TarFile(args.path, mode="w") as archive: # well we don't actually use compression
|
||||
for backup_path in backup_paths:
|
||||
archive.add(backup_path)
|
||||
|
||||
@staticmethod
|
||||
def get_paths(configuration: Configuration) -> Set[Path]:
|
||||
"""
|
||||
extract paths to backup
|
||||
|
||||
Args:
|
||||
configuration(Configuration): configuration instance
|
||||
|
||||
Returns:
|
||||
Set[Path]: map of the filesystem paths
|
||||
"""
|
||||
paths = set(configuration.include.glob("*.ini"))
|
||||
|
||||
root, _ = configuration.check_loaded()
|
||||
paths.add(root) # the configuration itself
|
||||
paths.add(SQLite.database_path(configuration)) # database
|
||||
|
||||
# local caches
|
||||
repository_paths = configuration.repository_paths
|
||||
if repository_paths.cache.is_dir():
|
||||
paths.add(repository_paths.cache)
|
||||
|
||||
# gnupg home with imported keys
|
||||
uid, _ = repository_paths.root_owner
|
||||
system_user = pwd.getpwuid(uid)
|
||||
gnupg_home = Path(system_user.pw_dir) / ".gnupg"
|
||||
if gnupg_home.is_dir():
|
||||
paths.add(gnupg_home)
|
||||
|
||||
return paths
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
@ -33,13 +33,16 @@ class Clean(Handler):
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
||||
configuration: Configuration, no_report: bool) -> None:
|
||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
:param args: command line args
|
||||
:param architecture: repository architecture
|
||||
:param configuration: configuration instance
|
||||
:param no_report: force disable reporting
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
no_report(bool): force disable reporting
|
||||
unsafe(bool): if set no user check will be performed before path creation
|
||||
"""
|
||||
Application(architecture, configuration, no_report).clean(
|
||||
args.build, args.cache, args.chroot, args.manual, args.packages, args.patches)
|
||||
Application(architecture, configuration, no_report, unsafe).clean(
|
||||
args.cache, args.chroot, args.manual, args.packages)
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
@ -21,9 +21,9 @@ import argparse
|
||||
|
||||
from typing import Type
|
||||
|
||||
from ahriman.application.formatters.configuration_printer import ConfigurationPrinter
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.formatters.configuration_printer import ConfigurationPrinter
|
||||
|
||||
|
||||
class Dump(Handler):
|
||||
@ -35,13 +35,16 @@ class Dump(Handler):
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
||||
configuration: Configuration, no_report: bool) -> None:
|
||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
:param args: command line args
|
||||
:param architecture: repository architecture
|
||||
:param configuration: configuration instance
|
||||
:param no_report: force disable reporting
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
no_report(bool): force disable reporting
|
||||
unsafe(bool): if set no user check will be performed before path creation
|
||||
"""
|
||||
dump = configuration.dump()
|
||||
for section, values in sorted(dump.items()):
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
@ -23,37 +23,46 @@ import argparse
|
||||
import logging
|
||||
|
||||
from multiprocessing import Pool
|
||||
from typing import Set, Type
|
||||
from typing import List, Type
|
||||
|
||||
from ahriman.application.lock import Lock
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.exceptions import MissingArchitecture, MultipleArchitecture
|
||||
from ahriman.core.exceptions import ExitCode, MissingArchitecture, MultipleArchitectures
|
||||
from ahriman.models.repository_paths import RepositoryPaths
|
||||
|
||||
|
||||
class Handler:
|
||||
"""
|
||||
base handler class for command callbacks
|
||||
:cvar ALLOW_AUTO_ARCHITECTURE_RUN: allow to define architecture from existing repositories
|
||||
:cvar ALLOW_MULTI_ARCHITECTURE_RUN: allow to run with multiple architectures
|
||||
|
||||
Attributes:
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN(bool): (class attribute) allow defining architecture from existing repositories
|
||||
ALLOW_MULTI_ARCHITECTURE_RUN(bool): (class attribute) allow running with multiple architectures
|
||||
"""
|
||||
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = True
|
||||
ALLOW_MULTI_ARCHITECTURE_RUN = True
|
||||
|
||||
@classmethod
|
||||
def architectures_extract(cls: Type[Handler], args: argparse.Namespace) -> Set[str]:
|
||||
def architectures_extract(cls: Type[Handler], args: argparse.Namespace) -> List[str]:
|
||||
"""
|
||||
get known architectures
|
||||
:param args: command line args
|
||||
:return: list of architectures for which tree is created
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
|
||||
Returns:
|
||||
List[str]: list of architectures for which tree is created
|
||||
|
||||
Raises:
|
||||
MissingArchitecture: if no architecture set and automatic detection is not allowed or failed
|
||||
"""
|
||||
if not cls.ALLOW_AUTO_ARCHITECTURE_RUN and args.architecture is None:
|
||||
# for some parsers (e.g. config) we need to run with specific architecture
|
||||
# for those cases architecture must be set explicitly
|
||||
raise MissingArchitecture(args.command)
|
||||
if args.architecture: # architecture is specified explicitly
|
||||
return set(args.architecture)
|
||||
return sorted(set(args.architecture))
|
||||
|
||||
config = Configuration()
|
||||
config.load(args.configuration)
|
||||
@ -63,21 +72,27 @@ class Handler:
|
||||
|
||||
if not architectures: # well we did not find anything
|
||||
raise MissingArchitecture(args.command)
|
||||
return architectures
|
||||
return sorted(architectures)
|
||||
|
||||
@classmethod
|
||||
def call(cls: Type[Handler], args: argparse.Namespace, architecture: str) -> bool:
|
||||
"""
|
||||
additional function to wrap all calls for multiprocessing library
|
||||
:param args: command line args
|
||||
:param architecture: repository architecture
|
||||
:return: True on success, False otherwise
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
|
||||
Returns:
|
||||
bool: True on success, False otherwise
|
||||
"""
|
||||
try:
|
||||
configuration = Configuration.from_path(args.configuration, architecture, args.quiet)
|
||||
with Lock(args, architecture, configuration):
|
||||
cls.run(args, architecture, configuration, args.no_report)
|
||||
cls.run(args, architecture, configuration, args.no_report, args.unsafe)
|
||||
return True
|
||||
except ExitCode:
|
||||
return False
|
||||
except Exception:
|
||||
# we are basically always want to print error to stderr instead of default logger
|
||||
logging.getLogger("stderr").exception("process exception")
|
||||
@ -87,15 +102,22 @@ class Handler:
|
||||
def execute(cls: Type[Handler], args: argparse.Namespace) -> int:
|
||||
"""
|
||||
execute function for all aru
|
||||
:param args: command line args
|
||||
:return: 0 on success, 1 otherwise
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
|
||||
Returns:
|
||||
int: 0 on success, 1 otherwise
|
||||
|
||||
Raises:
|
||||
MultipleArchitectures: if more than one architecture supplied and no multi architecture supported
|
||||
"""
|
||||
architectures = cls.architectures_extract(args)
|
||||
|
||||
# actually we do not have to spawn another process if it is single-process application, do we?
|
||||
if len(architectures) > 1:
|
||||
if not cls.ALLOW_MULTI_ARCHITECTURE_RUN:
|
||||
raise MultipleArchitecture(args.command)
|
||||
raise MultipleArchitectures(args.command)
|
||||
|
||||
with Pool(len(architectures)) as pool:
|
||||
result = pool.starmap(
|
||||
@ -107,12 +129,33 @@ class Handler:
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
||||
configuration: Configuration, no_report: bool) -> None:
|
||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
:param args: command line args
|
||||
:param architecture: repository architecture
|
||||
:param configuration: configuration instance
|
||||
:param no_report: force disable reporting
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
no_report(bool): force disable reporting
|
||||
unsafe(bool): if set no user check will be performed before path creation
|
||||
|
||||
Raises:
|
||||
NotImplementedError: not implemented method
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@staticmethod
|
||||
def check_if_empty(enabled: bool, predicate: bool) -> None:
|
||||
"""
|
||||
check condition and flag and raise ExitCode exception in case if it is enabled and condition match
|
||||
|
||||
Args:
|
||||
enabled(bool): if False no check will be performed
|
||||
predicate(bool): indicates condition on which exception should be thrown
|
||||
|
||||
Raises:
|
||||
ExitCode: if result is empty and check is enabled
|
||||
"""
|
||||
if enabled and predicate:
|
||||
raise ExitCode()
|
||||
|
52
src/ahriman/application/handlers/help.py
Normal file
52
src/ahriman/application/handlers/help.py
Normal file
@ -0,0 +1,52 @@
|
||||
#
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
import argparse
|
||||
|
||||
from typing import Type
|
||||
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
|
||||
|
||||
class Help(Handler):
|
||||
"""
|
||||
help handler
|
||||
"""
|
||||
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
no_report(bool): force disable reporting
|
||||
unsafe(bool): if set no user check will be performed before path creation
|
||||
"""
|
||||
parser: argparse.ArgumentParser = args.parser()
|
||||
if args.command is None:
|
||||
parser.parse_args(["--help"])
|
||||
else:
|
||||
parser.parse_args([args.command, "--help"])
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
@ -35,12 +35,16 @@ class KeyImport(Handler):
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
||||
configuration: Configuration, no_report: bool) -> None:
|
||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
:param args: command line args
|
||||
:param architecture: repository architecture
|
||||
:param configuration: configuration instance
|
||||
:param no_report: force disable reporting
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
no_report(bool): force disable reporting
|
||||
unsafe(bool): if set no user check will be performed before path creation
|
||||
"""
|
||||
Application(architecture, configuration, no_report).repository.sign.key_import(args.key_server, args.key)
|
||||
Application(architecture, configuration, no_report, unsafe).repository.sign.key_import(
|
||||
args.key_server, args.key)
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
@ -18,15 +18,15 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
import argparse
|
||||
import shutil
|
||||
|
||||
from pathlib import Path
|
||||
from typing import List, Type
|
||||
from typing import List, Optional, Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.core.build_tools.sources import Sources
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.formatters.string_printer import StringPrinter
|
||||
from ahriman.models.action import Action
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.package_source import PackageSource
|
||||
@ -37,22 +37,23 @@ class Patch(Handler):
|
||||
patch control handler
|
||||
"""
|
||||
|
||||
_print = print
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
||||
configuration: Configuration, no_report: bool) -> None:
|
||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
:param args: command line args
|
||||
:param architecture: repository architecture
|
||||
:param configuration: configuration instance
|
||||
:param no_report: force disable reporting
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
no_report(bool): force disable reporting
|
||||
unsafe(bool): if set no user check will be performed before path creation
|
||||
"""
|
||||
application = Application(architecture, configuration, no_report)
|
||||
application = Application(architecture, configuration, no_report, unsafe)
|
||||
|
||||
if args.action == Action.List:
|
||||
Patch.patch_set_list(application, args.package)
|
||||
Patch.patch_set_list(application, args.package, args.exit_code)
|
||||
elif args.action == Action.Remove:
|
||||
Patch.patch_set_remove(application, args.package)
|
||||
elif args.action == Action.Update:
|
||||
@ -62,38 +63,41 @@ class Patch(Handler):
|
||||
def patch_set_create(application: Application, sources_dir: str, track: List[str]) -> None:
|
||||
"""
|
||||
create patch set for the package base
|
||||
:param application: application instance
|
||||
:param sources_dir: path to directory with the package sources
|
||||
:param track: track files which match the glob before creating the patch
|
||||
|
||||
Args:
|
||||
application(Application): application instance
|
||||
sources_dir(str): path to directory with the package sources
|
||||
track(List[str]): track files which match the glob before creating the patch
|
||||
"""
|
||||
package = Package.load(sources_dir, PackageSource.Local, application.repository.pacman,
|
||||
application.repository.aur_url)
|
||||
patch_dir = application.repository.paths.patches_for(package.base)
|
||||
|
||||
Patch.patch_set_remove(application, package.base) # remove old patches
|
||||
patch_dir.mkdir(mode=0o755, parents=True)
|
||||
|
||||
Sources.patch_create(Path(sources_dir), patch_dir / "00-main.patch", *track)
|
||||
patch = Sources.patch_create(Path(sources_dir), *track)
|
||||
application.database.patches_insert(package.base, patch)
|
||||
|
||||
@staticmethod
|
||||
def patch_set_list(application: Application, package_base: str) -> None:
|
||||
def patch_set_list(application: Application, package_base: Optional[str], exit_code: bool) -> None:
|
||||
"""
|
||||
list patches available for the package base
|
||||
:param application: application instance
|
||||
:param package_base: package base
|
||||
|
||||
Args:
|
||||
application(Application): application instance
|
||||
package_base(Optional[str]): package base
|
||||
exit_code(bool): exit with error on empty search result
|
||||
"""
|
||||
patch_dir = application.repository.paths.patches_for(package_base)
|
||||
if not patch_dir.is_dir():
|
||||
return
|
||||
for patch_path in sorted(patch_dir.glob("*.patch")):
|
||||
Patch._print(patch_path.name)
|
||||
patches = application.database.patches_list(package_base)
|
||||
Patch.check_if_empty(exit_code, not patches)
|
||||
|
||||
for base, patch in patches.items():
|
||||
content = base if package_base is None else patch
|
||||
StringPrinter(content).print(verbose=True)
|
||||
|
||||
@staticmethod
|
||||
def patch_set_remove(application: Application, package_base: str) -> None:
|
||||
"""
|
||||
remove patch set for the package base
|
||||
:param application: application instance
|
||||
:param package_base: package base
|
||||
|
||||
Args:
|
||||
application(Application): application instance
|
||||
package_base(str): package base
|
||||
"""
|
||||
patch_dir = application.repository.paths.patches_for(package_base)
|
||||
shutil.rmtree(patch_dir, ignore_errors=True)
|
||||
application.database.patches_remove(package_base)
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
@ -19,11 +19,13 @@
|
||||
#
|
||||
import argparse
|
||||
|
||||
from typing import Type
|
||||
from typing import List, Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.formatters.update_printer import UpdatePrinter
|
||||
from ahriman.models.package import Package
|
||||
|
||||
|
||||
class Rebuild(Handler):
|
||||
@ -33,20 +35,43 @@ class Rebuild(Handler):
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
||||
configuration: Configuration, no_report: bool) -> None:
|
||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
:param args: command line args
|
||||
:param architecture: repository architecture
|
||||
:param configuration: configuration instance
|
||||
:param no_report: force disable reporting
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
no_report(bool): force disable reporting
|
||||
unsafe(bool): if set no user check will be performed before path creation
|
||||
"""
|
||||
depends_on = set(args.depends_on) if args.depends_on else None
|
||||
|
||||
application = Application(architecture, configuration, no_report)
|
||||
packages = [
|
||||
package
|
||||
for package in application.repository.packages()
|
||||
if depends_on is None or depends_on.intersection(package.depends)
|
||||
] # we have to use explicit list here for testing purpose
|
||||
application.update(packages)
|
||||
application = Application(architecture, configuration, no_report, unsafe)
|
||||
if args.from_database:
|
||||
updates = Rebuild.extract_packages(application)
|
||||
else:
|
||||
updates = application.repository.packages_depends_on(depends_on)
|
||||
|
||||
Rebuild.check_if_empty(args.exit_code, not updates)
|
||||
if args.dry_run:
|
||||
for package in updates:
|
||||
UpdatePrinter(package, package.version).print(verbose=True)
|
||||
return
|
||||
|
||||
result = application.update(updates)
|
||||
Rebuild.check_if_empty(args.exit_code, result.is_empty)
|
||||
|
||||
@staticmethod
|
||||
def extract_packages(application: Application) -> List[Package]:
|
||||
"""
|
||||
extract packages from database file
|
||||
|
||||
Args:
|
||||
application(Application): application instance
|
||||
|
||||
Returns:
|
||||
List[Package]: list of packages which were stored in database
|
||||
"""
|
||||
return [package for (package, _) in application.database.packages_get()]
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
@ -33,12 +33,15 @@ class Remove(Handler):
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
||||
configuration: Configuration, no_report: bool) -> None:
|
||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
:param args: command line args
|
||||
:param architecture: repository architecture
|
||||
:param configuration: configuration instance
|
||||
:param no_report: force disable reporting
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
no_report(bool): force disable reporting
|
||||
unsafe(bool): if set no user check will be performed before path creation
|
||||
"""
|
||||
Application(architecture, configuration, no_report).remove(args.package)
|
||||
Application(architecture, configuration, no_report, unsafe).remove(args.package)
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
@ -22,10 +22,9 @@ import argparse
|
||||
from typing import Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.formatters.package_printer import PackagePrinter
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.models.build_status import BuildStatus
|
||||
from ahriman.core.formatters.string_printer import StringPrinter
|
||||
|
||||
|
||||
class RemoveUnknown(Handler):
|
||||
@ -35,19 +34,23 @@ class RemoveUnknown(Handler):
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
||||
configuration: Configuration, no_report: bool) -> None:
|
||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
:param args: command line args
|
||||
:param architecture: repository architecture
|
||||
:param configuration: configuration instance
|
||||
:param no_report: force disable reporting
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
no_report(bool): force disable reporting
|
||||
unsafe(bool): if set no user check will be performed before path creation
|
||||
"""
|
||||
application = Application(architecture, configuration, no_report)
|
||||
application = Application(architecture, configuration, no_report, unsafe)
|
||||
unknown_packages = application.unknown()
|
||||
|
||||
if args.dry_run:
|
||||
for package in unknown_packages:
|
||||
PackagePrinter(package, BuildStatus()).print(args.info)
|
||||
for package in sorted(unknown_packages):
|
||||
StringPrinter(package).print(args.info)
|
||||
return
|
||||
|
||||
application.remove(package.base for package in unknown_packages)
|
||||
application.remove(unknown_packages)
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
@ -24,6 +24,7 @@ from typing import Type
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.models.result import Result
|
||||
|
||||
|
||||
class Report(Handler):
|
||||
@ -33,12 +34,15 @@ class Report(Handler):
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
||||
configuration: Configuration, no_report: bool) -> None:
|
||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
:param args: command line args
|
||||
:param architecture: repository architecture
|
||||
:param configuration: configuration instance
|
||||
:param no_report: force disable reporting
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
no_report(bool): force disable reporting
|
||||
unsafe(bool): if set no user check will be performed before path creation
|
||||
"""
|
||||
Application(architecture, configuration, no_report).report(args.target, [])
|
||||
Application(architecture, configuration, no_report, unsafe).report(args.target, Result())
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
@ -20,27 +20,31 @@
|
||||
import argparse
|
||||
|
||||
from typing import Type
|
||||
from tarfile import TarFile
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
|
||||
|
||||
class Init(Handler):
|
||||
class Restore(Handler):
|
||||
"""
|
||||
repository init handler
|
||||
restore packages handler
|
||||
"""
|
||||
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
||||
configuration: Configuration, no_report: bool) -> None:
|
||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
:param args: command line args
|
||||
:param architecture: repository architecture
|
||||
:param configuration: configuration instance
|
||||
:param no_report: force disable reporting
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
no_report(bool): force disable reporting
|
||||
unsafe(bool): if set no user check will be performed before path creation
|
||||
"""
|
||||
Application(architecture, configuration, no_report).repository.repo.init()
|
||||
with TarFile(args.path) as archive:
|
||||
archive.extractall(path=args.output)
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
@ -18,51 +18,71 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
import argparse
|
||||
import aur # type: ignore
|
||||
|
||||
from dataclasses import fields
|
||||
from typing import Callable, Iterable, List, Tuple, Type
|
||||
|
||||
from ahriman.application.formatters.aur_printer import AurPrinter
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.core.alpm.remote.aur import AUR
|
||||
from ahriman.core.alpm.remote.official import Official
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.exceptions import InvalidOption
|
||||
from ahriman.core.util import aur_search
|
||||
from ahriman.core.formatters.aur_printer import AurPrinter
|
||||
from ahriman.models.aur_package import AURPackage
|
||||
|
||||
|
||||
class Search(Handler):
|
||||
"""
|
||||
packages search handler
|
||||
|
||||
Attributes:
|
||||
SORT_FIELDS(Set[str]): (class attribute) allowed fields to sort the package list
|
||||
"""
|
||||
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||
SORT_FIELDS = set(aur.Package._fields) # later we will have to remove some fields from here (lists)
|
||||
SORT_FIELDS = {field.name for field in fields(AURPackage) if field.default_factory is not list}
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
||||
configuration: Configuration, no_report: bool) -> None:
|
||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
:param args: command line args
|
||||
:param architecture: repository architecture
|
||||
:param configuration: configuration instance
|
||||
:param no_report: force disable reporting
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
no_report(bool): force disable reporting
|
||||
unsafe(bool): if set no user check will be performed before path creation
|
||||
"""
|
||||
packages_list = aur_search(*args.search)
|
||||
for package in Search.sort(packages_list, args.sort_by):
|
||||
AurPrinter(package).print(args.info)
|
||||
official_packages_list = Official.multisearch(*args.search)
|
||||
aur_packages_list = AUR.multisearch(*args.search)
|
||||
Search.check_if_empty(args.exit_code, not official_packages_list and not aur_packages_list)
|
||||
|
||||
for packages_list in (official_packages_list, aur_packages_list):
|
||||
# keep sorting by packages source
|
||||
for package in Search.sort(packages_list, args.sort_by):
|
||||
AurPrinter(package).print(args.info)
|
||||
|
||||
@staticmethod
|
||||
def sort(packages: Iterable[aur.Package], sort_by: str) -> List[aur.Package]:
|
||||
def sort(packages: Iterable[AURPackage], sort_by: str) -> List[AURPackage]:
|
||||
"""
|
||||
sort package list by specified field
|
||||
:param packages: packages list to sort
|
||||
:param sort_by: AUR package field name to sort by
|
||||
:return: sorted list for packages
|
||||
|
||||
Args:
|
||||
packages(Iterable[AURPackage]): packages list to sort
|
||||
sort_by(str): AUR package field name to sort by
|
||||
|
||||
Returns:
|
||||
List[AURPackage]: sorted list for packages
|
||||
|
||||
Raises:
|
||||
InvalidOption: if search fields is not in list of allowed ones
|
||||
"""
|
||||
if sort_by not in Search.SORT_FIELDS:
|
||||
raise InvalidOption(sort_by)
|
||||
# always sort by package name at the last
|
||||
# well technically it is not a string, but we can deal with it
|
||||
comparator: Callable[[aur.Package], Tuple[str, str]] =\
|
||||
comparator: Callable[[AURPackage], Tuple[str, str]] =\
|
||||
lambda package: (getattr(package, sort_by), package.name)
|
||||
return sorted(packages, key=comparator)
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
@ -31,10 +31,12 @@ from ahriman.models.repository_paths import RepositoryPaths
|
||||
class Setup(Handler):
|
||||
"""
|
||||
setup handler
|
||||
:cvar ARCHBUILD_COMMAND_PATH: default devtools command
|
||||
:cvar BIN_DIR_PATH: directory for custom binaries
|
||||
:cvar MIRRORLIST_PATH: path to pacman default mirrorlist (used by multilib repository)
|
||||
:cvar SUDOERS_PATH: path to sudoers.d include configuration
|
||||
|
||||
Attributes:
|
||||
ARCHBUILD_COMMAND_PATH(Path): (class attribute) default devtools command
|
||||
BIN_DIR_PATH(Path): (class attribute) directory for custom binaries
|
||||
MIRRORLIST_PATH(Path): (class attribute) path to pacman default mirrorlist (used by multilib repository)
|
||||
SUDOERS_PATH(Path): (class attribute) path to sudoers.d include configuration
|
||||
"""
|
||||
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False
|
||||
@ -46,29 +48,41 @@ class Setup(Handler):
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
||||
configuration: Configuration, no_report: bool) -> None:
|
||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
:param args: command line args
|
||||
:param architecture: repository architecture
|
||||
:param configuration: configuration instance
|
||||
:param no_report: force disable reporting
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
no_report(bool): force disable reporting
|
||||
unsafe(bool): if set no user check will be performed before path creation
|
||||
"""
|
||||
application = Application(architecture, configuration, no_report)
|
||||
Setup.configuration_create_ahriman(args, architecture, args.repository, configuration.include)
|
||||
configuration.reload()
|
||||
|
||||
application = Application(architecture, configuration, no_report, unsafe)
|
||||
|
||||
Setup.configuration_create_makepkg(args.packager, application.repository.paths)
|
||||
Setup.executable_create(args.build_command, architecture)
|
||||
Setup.configuration_create_devtools(args.build_command, architecture, args.from_configuration,
|
||||
args.no_multilib, args.repository, application.repository.paths)
|
||||
Setup.configuration_create_ahriman(args, architecture, args.repository, configuration.include)
|
||||
Setup.configuration_create_sudo(args.build_command, architecture)
|
||||
|
||||
application.repository.repo.init()
|
||||
|
||||
@staticmethod
|
||||
def build_command(prefix: str, architecture: str) -> Path:
|
||||
"""
|
||||
generate build command name
|
||||
:param prefix: command prefix in {prefix}-{architecture}-build
|
||||
:param architecture: repository architecture
|
||||
:return: valid devtools command name
|
||||
|
||||
Args:
|
||||
prefix(str): command prefix in {prefix}-{architecture}-build
|
||||
architecture(str): repository architecture
|
||||
|
||||
Returns:
|
||||
Path: valid devtools command name
|
||||
"""
|
||||
return Setup.BIN_DIR_PATH / f"{prefix}-{architecture}-build"
|
||||
|
||||
@ -77,16 +91,20 @@ class Setup(Handler):
|
||||
include_path: Path) -> None:
|
||||
"""
|
||||
create service specific configuration
|
||||
:param args: command line args
|
||||
:param architecture: repository architecture
|
||||
:param repository: repository name
|
||||
:param include_path: path to directory with configuration includes
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
repository(str): repository name
|
||||
include_path(Path): path to directory with configuration includes
|
||||
"""
|
||||
configuration = Configuration()
|
||||
|
||||
section = Configuration.section_name("build", architecture)
|
||||
configuration.set_option(section, "build_command", str(Setup.build_command(args.build_command, architecture)))
|
||||
configuration.set_option("repository", "name", repository)
|
||||
if args.build_as_user is not None:
|
||||
configuration.set_option(section, "makechrootpkg_flags", f"-U {args.build_as_user}")
|
||||
|
||||
if args.sign_key is not None:
|
||||
section = Configuration.section_name("sign", architecture)
|
||||
@ -106,12 +124,14 @@ class Setup(Handler):
|
||||
no_multilib: bool, repository: str, paths: RepositoryPaths) -> None:
|
||||
"""
|
||||
create configuration for devtools based on `source` configuration
|
||||
:param prefix: command prefix in {prefix}-{architecture}-build
|
||||
:param architecture: repository architecture
|
||||
:param source: path to source configuration file
|
||||
:param no_multilib: do not add multilib repository
|
||||
:param repository: repository name
|
||||
:param paths: repository paths instance
|
||||
|
||||
Args:
|
||||
prefix(str): command prefix in {prefix}-{architecture}-build
|
||||
architecture(str): repository architecture
|
||||
source(Path): path to source configuration file
|
||||
no_multilib(bool): do not add multilib repository
|
||||
repository(str): repository name
|
||||
paths(RepositoryPaths): repository paths instance
|
||||
"""
|
||||
configuration = Configuration()
|
||||
# preserve case
|
||||
@ -141,17 +161,21 @@ class Setup(Handler):
|
||||
def configuration_create_makepkg(packager: str, paths: RepositoryPaths) -> None:
|
||||
"""
|
||||
create configuration for makepkg
|
||||
:param packager: packager identifier (e.g. name, email)
|
||||
:param paths: repository paths instance
|
||||
|
||||
Args:
|
||||
packager(str): packager identifier (e.g. name, email)
|
||||
paths(RepositoryPaths): repository paths instance
|
||||
"""
|
||||
(paths.root / ".makepkg.conf").write_text(f"PACKAGER='{packager}'\n")
|
||||
(paths.root / ".makepkg.conf").write_text(f"PACKAGER='{packager}'\n", encoding="utf8")
|
||||
|
||||
@staticmethod
|
||||
def configuration_create_sudo(prefix: str, architecture: str) -> None:
|
||||
"""
|
||||
create configuration to run build command with sudo without password
|
||||
:param prefix: command prefix in {prefix}-{architecture}-build
|
||||
:param architecture: repository architecture
|
||||
|
||||
Args:
|
||||
prefix(str): command prefix in {prefix}-{architecture}-build
|
||||
architecture(str): repository architecture
|
||||
"""
|
||||
command = Setup.build_command(prefix, architecture)
|
||||
Setup.SUDOERS_PATH.write_text(f"ahriman ALL=(ALL) NOPASSWD: {command} *\n", encoding="utf8")
|
||||
@ -161,8 +185,10 @@ class Setup(Handler):
|
||||
def executable_create(prefix: str, architecture: str) -> None:
|
||||
"""
|
||||
create executable for the service
|
||||
:param prefix: command prefix in {prefix}-{architecture}-build
|
||||
:param architecture: repository architecture
|
||||
|
||||
Args:
|
||||
prefix(str): command prefix in {prefix}-{architecture}-build
|
||||
architecture(str): repository architecture
|
||||
"""
|
||||
command = Setup.build_command(prefix, architecture)
|
||||
command.unlink(missing_ok=True)
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
@ -33,12 +33,15 @@ class Sign(Handler):
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
||||
configuration: Configuration, no_report: bool) -> None:
|
||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
:param args: command line args
|
||||
:param architecture: repository architecture
|
||||
:param configuration: configuration instance
|
||||
:param no_report: force disable reporting
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
no_report(bool): force disable reporting
|
||||
unsafe(bool): if set no user check will be performed before path creation
|
||||
"""
|
||||
Application(architecture, configuration, no_report).sign(args.package)
|
||||
Application(architecture, configuration, no_report, unsafe).sign(args.package)
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
@ -22,10 +22,10 @@ import argparse
|
||||
from typing import Callable, Iterable, Tuple, Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.formatters.package_printer import PackagePrinter
|
||||
from ahriman.application.formatters.status_printer import StatusPrinter
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.formatters.package_printer import PackagePrinter
|
||||
from ahriman.core.formatters.status_printer import StatusPrinter
|
||||
from ahriman.models.build_status import BuildStatus
|
||||
from ahriman.models.package import Package
|
||||
|
||||
@ -39,16 +39,19 @@ class Status(Handler):
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
||||
configuration: Configuration, no_report: bool) -> None:
|
||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
:param args: command line args
|
||||
:param architecture: repository architecture
|
||||
:param configuration: configuration instance
|
||||
:param no_report: force disable reporting
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
no_report(bool): force disable reporting
|
||||
unsafe(bool): if set no user check will be performed before path creation
|
||||
"""
|
||||
# we are using reporter here
|
||||
client = Application(architecture, configuration, no_report=False).repository.reporter
|
||||
client = Application(architecture, configuration, no_report=False, unsafe=unsafe).repository.reporter
|
||||
if args.ahriman:
|
||||
ahriman = client.get_self()
|
||||
StatusPrinter(ahriman).print(args.info)
|
||||
@ -59,6 +62,8 @@ class Status(Handler):
|
||||
else:
|
||||
packages = client.get(None)
|
||||
|
||||
Status.check_if_empty(args.exit_code, not packages)
|
||||
|
||||
comparator: Callable[[Tuple[Package, BuildStatus]], str] = lambda item: item[0].base
|
||||
filter_fn: Callable[[Tuple[Package, BuildStatus]], bool] =\
|
||||
lambda item: args.status is None or item[1].status == args.status
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
@ -36,16 +36,19 @@ class StatusUpdate(Handler):
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
||||
configuration: Configuration, no_report: bool) -> None:
|
||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
:param args: command line args
|
||||
:param architecture: repository architecture
|
||||
:param configuration: configuration instance
|
||||
:param no_report: force disable reporting
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
no_report(bool): force disable reporting
|
||||
unsafe(bool): if set no user check will be performed before path creation
|
||||
"""
|
||||
# we are using reporter here
|
||||
client = Application(architecture, configuration, no_report=False).repository.reporter
|
||||
client = Application(architecture, configuration, no_report=False, unsafe=unsafe).repository.reporter
|
||||
|
||||
if args.action == Action.Update and args.package:
|
||||
# update packages statuses
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
@ -28,17 +28,20 @@ from ahriman.core.configuration import Configuration
|
||||
|
||||
class Sync(Handler):
|
||||
"""
|
||||
remove sync handler
|
||||
remote sync handler
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
||||
configuration: Configuration, no_report: bool) -> None:
|
||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
:param args: command line args
|
||||
:param architecture: repository architecture
|
||||
:param configuration: configuration instance
|
||||
:param no_report: force disable reporting
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
no_report(bool): force disable reporting
|
||||
unsafe(bool): if set no user check will be performed before path creation
|
||||
"""
|
||||
Application(architecture, configuration, no_report).sync(args.target, [])
|
||||
Application(architecture, configuration, no_report, unsafe).sync(args.target, [])
|
||||
|
84
src/ahriman/application/handlers/unsafe_commands.py
Normal file
84
src/ahriman/application/handlers/unsafe_commands.py
Normal file
@ -0,0 +1,84 @@
|
||||
#
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
import argparse
|
||||
import shlex
|
||||
|
||||
from typing import List, Type
|
||||
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.formatters.string_printer import StringPrinter
|
||||
|
||||
|
||||
class UnsafeCommands(Handler):
|
||||
"""
|
||||
unsafe command help parser
|
||||
"""
|
||||
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
no_report(bool): force disable reporting
|
||||
unsafe(bool): if set no user check will be performed before path creation
|
||||
"""
|
||||
parser = args.parser()
|
||||
unsafe_commands = UnsafeCommands.get_unsafe_commands(parser)
|
||||
if args.command is None:
|
||||
for command in unsafe_commands:
|
||||
StringPrinter(command).print(verbose=True)
|
||||
else:
|
||||
UnsafeCommands.check_unsafe(args.command, unsafe_commands, parser)
|
||||
|
||||
@staticmethod
|
||||
def check_unsafe(command: str, unsafe_commands: List[str], parser: argparse.ArgumentParser) -> None:
|
||||
"""
|
||||
check if command is unsafe
|
||||
|
||||
Args:
|
||||
command(str): command to check
|
||||
unsafe_commands(List[str]): list of unsafe commands
|
||||
parser(argparse.ArgumentParser): generated argument parser
|
||||
"""
|
||||
args = parser.parse_args(shlex.split(command))
|
||||
UnsafeCommands.check_if_empty(True, args.command in unsafe_commands)
|
||||
|
||||
@staticmethod
|
||||
def get_unsafe_commands(parser: argparse.ArgumentParser) -> List[str]:
|
||||
"""
|
||||
extract unsafe commands from argument parser
|
||||
|
||||
Args:
|
||||
parser(argparse.ArgumentParser): generated argument parser
|
||||
|
||||
Returns:
|
||||
List[str]: list of commands with default unsafe flag
|
||||
"""
|
||||
# pylint: disable=protected-access
|
||||
subparser = next(action for action in parser._actions if isinstance(action, argparse._SubParsersAction))
|
||||
return [action_name for action_name, action in subparser.choices.items() if action.get_default("unsafe")]
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
@ -33,29 +33,38 @@ class Update(Handler):
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
||||
configuration: Configuration, no_report: bool) -> None:
|
||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
:param args: command line args
|
||||
:param architecture: repository architecture
|
||||
:param configuration: configuration instance
|
||||
:param no_report: force disable reporting
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
no_report(bool): force disable reporting
|
||||
unsafe(bool): if set no user check will be performed before path creation
|
||||
"""
|
||||
application = Application(architecture, configuration, no_report)
|
||||
packages = application.updates(args.package, args.no_aur, args.no_manual, args.no_vcs,
|
||||
application = Application(architecture, configuration, no_report, unsafe)
|
||||
packages = application.updates(args.package, args.no_aur, args.no_local, args.no_manual, args.no_vcs,
|
||||
Update.log_fn(application, args.dry_run))
|
||||
Update.check_if_empty(args.exit_code, not packages)
|
||||
if args.dry_run:
|
||||
return
|
||||
|
||||
application.update(packages)
|
||||
result = application.update(packages)
|
||||
Update.check_if_empty(args.exit_code, result.is_empty)
|
||||
|
||||
@staticmethod
|
||||
def log_fn(application: Application, dry_run: bool) -> Callable[[str], None]:
|
||||
"""
|
||||
package updates log function
|
||||
:param application: application instance
|
||||
:param dry_run: do not perform update itself
|
||||
:return: in case if dry_run is set it will return print, logger otherwise
|
||||
|
||||
Args:
|
||||
application(Application): application instance
|
||||
dry_run(bool): do not perform update itself
|
||||
|
||||
Returns:
|
||||
Callable[[str], None]: in case if dry_run is set it will return print, logger otherwise
|
||||
"""
|
||||
def inner(line: str) -> None:
|
||||
return print(line) if dry_run else application.logger.info(line)
|
||||
|
@ -1,143 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
import argparse
|
||||
import getpass
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.models.action import Action
|
||||
from ahriman.models.user import User as MUser
|
||||
from ahriman.models.user_access import UserAccess
|
||||
|
||||
|
||||
class User(Handler):
|
||||
"""
|
||||
user management handler
|
||||
"""
|
||||
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
||||
configuration: Configuration, no_report: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
:param args: command line args
|
||||
:param architecture: repository architecture
|
||||
:param configuration: configuration instance
|
||||
:param no_report: force disable reporting
|
||||
"""
|
||||
salt = User.get_salt(configuration)
|
||||
user = User.user_create(args)
|
||||
auth_configuration = User.configuration_get(configuration.include)
|
||||
|
||||
User.user_clear(auth_configuration, user)
|
||||
if args.action == Action.Update:
|
||||
User.configuration_create(auth_configuration, user, salt, args.as_service)
|
||||
User.configuration_write(auth_configuration, args.secure)
|
||||
|
||||
if not args.no_reload:
|
||||
client = Application(architecture, configuration, no_report=False).repository.reporter
|
||||
client.reload_auth()
|
||||
|
||||
@staticmethod
|
||||
def configuration_create(configuration: Configuration, user: MUser, salt: str, as_service_user: bool) -> None:
|
||||
"""
|
||||
put new user to configuration
|
||||
:param configuration: configuration instance
|
||||
:param user: user descriptor
|
||||
:param salt: password hash salt
|
||||
:param as_service_user: add user as service user, also set password and user to configuration
|
||||
"""
|
||||
section = Configuration.section_name("auth", user.access.value)
|
||||
configuration.set_option("auth", "salt", salt)
|
||||
configuration.set_option(section, user.username, user.hash_password(salt))
|
||||
|
||||
if as_service_user:
|
||||
configuration.set_option("web", "username", user.username)
|
||||
configuration.set_option("web", "password", user.password)
|
||||
|
||||
@staticmethod
|
||||
def configuration_get(include_path: Path) -> Configuration:
|
||||
"""
|
||||
create configuration instance
|
||||
:param include_path: path to directory with configuration includes
|
||||
:return: configuration instance. In case if there are local settings they will be loaded
|
||||
"""
|
||||
target = include_path / "auth.ini"
|
||||
configuration = Configuration()
|
||||
configuration.load(target)
|
||||
|
||||
return configuration
|
||||
|
||||
@staticmethod
|
||||
def configuration_write(configuration: Configuration, secure: bool) -> None:
|
||||
"""
|
||||
write configuration file
|
||||
:param configuration: configuration instance
|
||||
:param secure: if true then set file permissions to 0o600
|
||||
"""
|
||||
if configuration.path is None:
|
||||
return # should never happen actually
|
||||
with configuration.path.open("w") as ahriman_configuration:
|
||||
configuration.write(ahriman_configuration)
|
||||
if secure:
|
||||
configuration.path.chmod(0o600)
|
||||
|
||||
@staticmethod
|
||||
def get_salt(configuration: Configuration, salt_length: int = 20) -> str:
|
||||
"""
|
||||
get salt from configuration or create new string
|
||||
:param configuration: configuration instance
|
||||
:param salt_length: salt length
|
||||
:return: current salt
|
||||
"""
|
||||
if salt := configuration.get("auth", "salt", fallback=None):
|
||||
return salt
|
||||
return MUser.generate_password(salt_length)
|
||||
|
||||
@staticmethod
|
||||
def user_clear(configuration: Configuration, user: MUser) -> None:
|
||||
"""
|
||||
remove user user from configuration file in case if it exists
|
||||
:param configuration: configuration instance
|
||||
:param user: user descriptor
|
||||
"""
|
||||
for role in UserAccess:
|
||||
section = Configuration.section_name("auth", role.value)
|
||||
if not configuration.has_option(section, user.username):
|
||||
continue
|
||||
configuration.remove_option(section, user.username)
|
||||
|
||||
@staticmethod
|
||||
def user_create(args: argparse.Namespace) -> MUser:
|
||||
"""
|
||||
create user descriptor from arguments
|
||||
:param args: command line args
|
||||
:return: built user descriptor
|
||||
"""
|
||||
user = MUser(args.username, args.password, args.role)
|
||||
if user.password is None:
|
||||
user.password = getpass.getpass()
|
||||
return user
|
155
src/ahriman/application/handlers/users.py
Normal file
155
src/ahriman/application/handlers/users.py
Normal file
@ -0,0 +1,155 @@
|
||||
#
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
import argparse
|
||||
import getpass
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Type
|
||||
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database.sqlite import SQLite
|
||||
from ahriman.core.formatters.user_printer import UserPrinter
|
||||
from ahriman.models.action import Action
|
||||
from ahriman.models.user import User
|
||||
|
||||
|
||||
class Users(Handler):
|
||||
"""
|
||||
user management handler
|
||||
"""
|
||||
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
no_report(bool): force disable reporting
|
||||
unsafe(bool): if set no user check will be performed before path creation
|
||||
"""
|
||||
database = SQLite.load(configuration)
|
||||
|
||||
if args.action == Action.Update:
|
||||
salt = Users.get_salt(configuration)
|
||||
user = Users.user_create(args)
|
||||
|
||||
auth_configuration = Users.configuration_get(configuration.include)
|
||||
|
||||
Users.configuration_create(auth_configuration, user, salt, args.as_service, args.secure)
|
||||
database.user_update(user.hash_password(salt))
|
||||
elif args.action == Action.List:
|
||||
users = database.user_list(args.username, args.role)
|
||||
Users.check_if_empty(args.exit_code, not users)
|
||||
for user in users:
|
||||
UserPrinter(user).print(verbose=True)
|
||||
elif args.action == Action.Remove:
|
||||
database.user_remove(args.username)
|
||||
|
||||
@staticmethod
|
||||
def configuration_create(configuration: Configuration, user: User, salt: str,
|
||||
as_service_user: bool, secure: bool) -> None:
|
||||
"""
|
||||
enable configuration if it has been disabled
|
||||
|
||||
Args:
|
||||
configuration(Configuration): configuration instance
|
||||
user(User): user descriptor
|
||||
salt(str): password hash salt
|
||||
as_service_user(bool): add user as service user, also set password and user to configuration
|
||||
secure(bool): if true then set file permissions to 0o600
|
||||
"""
|
||||
configuration.set_option("auth", "salt", salt)
|
||||
if as_service_user:
|
||||
configuration.set_option("web", "username", user.username)
|
||||
configuration.set_option("web", "password", user.password)
|
||||
Users.configuration_write(configuration, secure)
|
||||
|
||||
@staticmethod
|
||||
def configuration_get(include_path: Path) -> Configuration:
|
||||
"""
|
||||
create configuration instance
|
||||
|
||||
Args:
|
||||
include_path(Path): path to directory with configuration includes
|
||||
|
||||
Returns:
|
||||
Configuration: configuration instance. In case if there are local settings they will be loaded
|
||||
"""
|
||||
target = include_path / "auth.ini"
|
||||
configuration = Configuration()
|
||||
configuration.load(target)
|
||||
|
||||
configuration.architecture = "" # not user anyway
|
||||
|
||||
return configuration
|
||||
|
||||
@staticmethod
|
||||
def configuration_write(configuration: Configuration, secure: bool) -> None:
|
||||
"""
|
||||
write configuration file
|
||||
|
||||
Args:
|
||||
configuration(Configuration): configuration instance
|
||||
secure(bool): if true then set file permissions to 0o600
|
||||
"""
|
||||
path, _ = configuration.check_loaded()
|
||||
with path.open("w") as ahriman_configuration:
|
||||
configuration.write(ahriman_configuration)
|
||||
if secure:
|
||||
path.chmod(0o600)
|
||||
|
||||
@staticmethod
|
||||
def get_salt(configuration: Configuration, salt_length: int = 20) -> str:
|
||||
"""
|
||||
get salt from configuration or create new string
|
||||
|
||||
Args:
|
||||
configuration(Configuration): configuration instance
|
||||
salt_length(int, optional): salt length (Default value = 20)
|
||||
|
||||
Returns:
|
||||
str: current salt
|
||||
"""
|
||||
if salt := configuration.get("auth", "salt", fallback=None):
|
||||
return salt
|
||||
return User.generate_password(salt_length)
|
||||
|
||||
@staticmethod
|
||||
def user_create(args: argparse.Namespace) -> User:
|
||||
"""
|
||||
create user descriptor from arguments
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
|
||||
Returns:
|
||||
User: built user descriptor
|
||||
"""
|
||||
user = User(args.username, args.password, args.role)
|
||||
if user.password is None:
|
||||
user.password = getpass.getpass()
|
||||
return user
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
@ -36,13 +36,16 @@ class Web(Handler):
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
||||
configuration: Configuration, no_report: bool) -> None:
|
||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
:param args: command line args
|
||||
:param architecture: repository architecture
|
||||
:param configuration: configuration instance
|
||||
:param no_report: force disable reporting
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
no_report(bool): force disable reporting
|
||||
unsafe(bool): if set no user check will be performed before path creation
|
||||
"""
|
||||
# we are using local import for optional dependencies
|
||||
from ahriman.web.web import run_server, setup_service
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
@ -37,36 +37,40 @@ from ahriman.models.build_status import BuildStatusEnum
|
||||
class Lock:
|
||||
"""
|
||||
wrapper for application lock file
|
||||
:ivar force: remove lock file on start if any
|
||||
:ivar path: path to lock file if any
|
||||
:ivar reporter: build status reporter instance
|
||||
:ivar root: repository root (i.e. ahriman home)
|
||||
:ivar unsafe: skip user check
|
||||
|
||||
Attributes:
|
||||
force(bool): remove lock file on start if any
|
||||
path(Path): path to lock file if any
|
||||
reporter(Client): build status reporter instance
|
||||
paths(RepositoryPaths): repository paths instance
|
||||
unsafe(bool): skip user check
|
||||
"""
|
||||
|
||||
def __init__(self, args: argparse.Namespace, architecture: str, configuration: Configuration) -> None:
|
||||
"""
|
||||
default constructor
|
||||
:param args: command line args
|
||||
:param architecture: repository architecture
|
||||
:param configuration: configuration instance
|
||||
|
||||
Args:
|
||||
args(argparse.Namespace): command line args
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
"""
|
||||
self.path = Path(f"{args.lock}_{architecture}") if args.lock is not None else None
|
||||
self.force = args.force
|
||||
self.unsafe = args.unsafe
|
||||
|
||||
self.root = Path(configuration.get("repository", "root"))
|
||||
self.paths = configuration.repository_paths
|
||||
self.reporter = Client() if args.no_report else Client.load(configuration)
|
||||
|
||||
def __enter__(self) -> Lock:
|
||||
"""
|
||||
default workflow is the following:
|
||||
|
||||
check user UID
|
||||
check if there is lock file
|
||||
check web status watcher status
|
||||
create lock file
|
||||
report to web if enabled
|
||||
1. Check user UID
|
||||
2. Check if there is lock file
|
||||
3. Check web status watcher status
|
||||
4. Create lock file
|
||||
5. Report to status page if enabled
|
||||
"""
|
||||
self.check_user()
|
||||
self.check_version()
|
||||
@ -78,10 +82,14 @@ class Lock:
|
||||
exc_tb: TracebackType) -> Literal[False]:
|
||||
"""
|
||||
remove lock file when done
|
||||
:param exc_type: exception type name if any
|
||||
:param exc_val: exception raised if any
|
||||
:param exc_tb: exception traceback if any
|
||||
:return: always False (do not suppress any exception)
|
||||
|
||||
Args:
|
||||
exc_type(Optional[Type[Exception]]): exception type name if any
|
||||
exc_val(Optional[Exception]): exception raised if any
|
||||
exc_tb(TracebackType): exception traceback if any
|
||||
|
||||
Returns:
|
||||
Literal[False]: always False (do not suppress any exception)
|
||||
"""
|
||||
self.clear()
|
||||
status = BuildStatusEnum.Success if exc_val is None else BuildStatusEnum.Failed
|
||||
@ -103,9 +111,7 @@ class Lock:
|
||||
"""
|
||||
check if current user is actually owner of ahriman root
|
||||
"""
|
||||
if self.unsafe:
|
||||
return
|
||||
check_user(self.root)
|
||||
check_user(self.paths, self.unsafe)
|
||||
|
||||
def clear(self) -> None:
|
||||
"""
|
||||
@ -118,6 +124,9 @@ class Lock:
|
||||
def create(self) -> None:
|
||||
"""
|
||||
create lock file
|
||||
|
||||
Raises:
|
||||
DuplicateRun: if lock exists and no force flag supplied
|
||||
"""
|
||||
if self.path is None:
|
||||
return
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2021 ahriman team.
|
||||
# Copyright (c) 2021-2022 ahriman team.
|
||||
#
|
||||
# This file is part of ahriman
|
||||
# (see https://github.com/arcan1s/ahriman).
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user