mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-06-28 06:41:43 +00:00
Compare commits
34 Commits
Author | SHA1 | Date | |
---|---|---|---|
8a6854c867 | |||
299732181c | |||
84c1b4d82d | |||
cdd66ee780 | |||
b2ed383de0 | |||
551ee670bf | |||
5d4bd9e459 | |||
4f21eb6fe6 | |||
9a008ddafa | |||
0cd07afa0f | |||
f590136197 | |||
1855e513a8 | |||
233dda8420 | |||
9556779ee2 | |||
8b32bd43db | |||
0eadef597a | |||
e58ccdc8ad | |||
2a07356d24 | |||
43c553a3db | |||
0d1a890bd0 | |||
3aeaa8ce2c | |||
7cee859f19 | |||
fb6b22cdd7 | |||
4f35ec6542 | |||
d98211e5e5 | |||
b97c8928e1 | |||
649df81aa5 | |||
ad7cdb7d95 | |||
4bb598d2eb | |||
f47be6cab0 | |||
342b3cb652 | |||
fc0d8387df | |||
e0b0c3caeb | |||
61969dd682 |
14
.dockerignore
Normal file
14
.dockerignore
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
.eggs/
|
||||||
|
.git/
|
||||||
|
.github/
|
||||||
|
.idea/
|
||||||
|
.mypy_cache/
|
||||||
|
.pytest_cache/
|
||||||
|
.tox/
|
||||||
|
.venv/
|
||||||
|
|
||||||
|
*.egg-info/
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
*.pyd
|
||||||
|
*.pyo
|
16
.github/workflows/run-setup.yml
vendored
16
.github/workflows/run-setup.yml
vendored
@ -7,6 +7,22 @@ on:
|
|||||||
branches: [ master ]
|
branches: [ master ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
run-setup-minimal:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
container:
|
||||||
|
image: archlinux:latest
|
||||||
|
volumes:
|
||||||
|
- ${{ github.workspace }}:/build
|
||||||
|
options: --privileged -w /build
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: setup the minimal service in arch linux container
|
||||||
|
run: .github/workflows/setup.sh minimal
|
||||||
|
|
||||||
run-setup:
|
run-setup:
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
31
.github/workflows/setup.sh
vendored
31
.github/workflows/setup.sh
vendored
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
set -ex
|
set -ex
|
||||||
|
|
||||||
|
[[ $1 = "minimal" ]] && MINIMAL_INSTALL=1
|
||||||
|
|
||||||
# install dependencies
|
# install dependencies
|
||||||
echo -e '[arcanisrepo]\nServer = http://repo.arcanis.me/$arch\nSigLevel = Never' | tee -a /etc/pacman.conf
|
echo -e '[arcanisrepo]\nServer = http://repo.arcanis.me/$arch\nSigLevel = Never' | tee -a /etc/pacman.conf
|
||||||
# refresh the image
|
# refresh the image
|
||||||
@ -12,12 +14,14 @@ pacman --noconfirm -Sy base-devel devtools git pyalpm python-aur python-passlib
|
|||||||
# make dependencies
|
# make dependencies
|
||||||
pacman --noconfirm -Sy python-build python-installer python-wheel
|
pacman --noconfirm -Sy python-build python-installer python-wheel
|
||||||
# optional dependencies
|
# optional dependencies
|
||||||
# VCS support
|
if [[ -z $MINIMAL_INSTALL ]]; then
|
||||||
pacman --noconfirm -Sy breezy darcs mercurial subversion
|
# VCS support
|
||||||
# web server
|
pacman --noconfirm -Sy breezy darcs mercurial subversion
|
||||||
pacman --noconfirm -Sy python-aioauth-client python-aiohttp python-aiohttp-debugtoolbar python-aiohttp-jinja2 python-aiohttp-security python-aiohttp-session python-cryptography python-jinja
|
# web server
|
||||||
# additional features
|
pacman --noconfirm -Sy python-aioauth-client python-aiohttp python-aiohttp-debugtoolbar python-aiohttp-jinja2 python-aiohttp-security python-aiohttp-session python-cryptography python-jinja
|
||||||
pacman --noconfirm -Sy gnupg python-boto3 rsync
|
# additional features
|
||||||
|
pacman --noconfirm -Sy gnupg python-boto3 rsync
|
||||||
|
fi
|
||||||
|
|
||||||
# create fresh tarball
|
# create fresh tarball
|
||||||
make VERSION=1.0.0 archlinux # well, it does not really matter which version we will put here
|
make VERSION=1.0.0 archlinux # well, it does not really matter which version we will put here
|
||||||
@ -33,14 +37,17 @@ systemd-machine-id-setup
|
|||||||
# special thing for the container, because /dev/log interface is not available there
|
# 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
|
# initial setup command as root
|
||||||
ahriman -a x86_64 repo-setup --packager "ahriman bot <ahriman@example.com>" --repository "github" --web-port 8080
|
[[ -z $MINIMAL_INSTALL ]] && WEB_ARGS=("--web-port" "8080")
|
||||||
|
ahriman -a x86_64 repo-setup --packager "ahriman bot <ahriman@example.com>" --repository "github" "${WEB_ARGS[@]}"
|
||||||
# enable services
|
# enable services
|
||||||
systemctl enable ahriman-web@x86_64
|
systemctl enable ahriman-web@x86_64
|
||||||
systemctl enable ahriman@x86_64.timer
|
systemctl enable ahriman@x86_64.timer
|
||||||
# run web service (detached)
|
if [[ -z $MINIMAL_INSTALL ]]; then
|
||||||
sudo -u ahriman -- ahriman -a x86_64 web &
|
# run web service (detached)
|
||||||
WEBPID=$!
|
sudo -u ahriman -- ahriman -a x86_64 web &
|
||||||
sleep 15s # wait for the web service activation
|
WEB_PID=$!
|
||||||
|
sleep 15s # wait for the web service activation
|
||||||
|
fi
|
||||||
# add the first package
|
# add the first package
|
||||||
# the build itself does not really work in the container
|
# the build itself does not really work in the container
|
||||||
sudo -u ahriman -- ahriman package-add --now yay
|
sudo -u ahriman -- ahriman package-add --now yay
|
||||||
@ -49,4 +56,4 @@ sudo -u ahriman -- ahriman package-add --now yay
|
|||||||
# run package check
|
# run package check
|
||||||
sudo -u ahriman -- ahriman repo-update
|
sudo -u ahriman -- ahriman repo-update
|
||||||
# stop web service lol
|
# stop web service lol
|
||||||
kill $WEBPID
|
[[ -z $WEB_PID ]] || kill $WEB_PID
|
||||||
|
@ -82,7 +82,8 @@ disable=raw-checker-failed,
|
|||||||
fixme,
|
fixme,
|
||||||
too-many-arguments,
|
too-many-arguments,
|
||||||
duplicate-code,
|
duplicate-code,
|
||||||
cyclic-import
|
cyclic-import,
|
||||||
|
confusing-with-statement,
|
||||||
|
|
||||||
|
|
||||||
# Enable the message, report, category or checker with the given id(s). You can
|
# Enable the message, report, category or checker with the given id(s). You can
|
||||||
@ -148,7 +149,7 @@ indent-string=' '
|
|||||||
max-line-length=100
|
max-line-length=100
|
||||||
|
|
||||||
# Maximum number of lines in a module.
|
# Maximum number of lines in a module.
|
||||||
max-module-lines=1000
|
max-module-lines=400
|
||||||
|
|
||||||
# Allow the body of a class to be on the same line as the declaration if body
|
# Allow the body of a class to be on the same line as the declaration if body
|
||||||
# contains single statement.
|
# contains single statement.
|
||||||
|
@ -5,7 +5,7 @@ formats: all
|
|||||||
build:
|
build:
|
||||||
os: ubuntu-20.04
|
os: ubuntu-20.04
|
||||||
tools:
|
tools:
|
||||||
python: "3.9"
|
python: "3.10"
|
||||||
|
|
||||||
sphinx:
|
sphinx:
|
||||||
builder: html
|
builder: html
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# Contributing to ahriman
|
# Contributing to ahriman
|
||||||
|
|
||||||
Welcome to ahriman! The goal of the project is to provide the best user experience to manage Archlinux repositories. In order to follow this we set some limitations for the issue creations and heavily restricted code contribution.
|
Welcome to ahriman! The goal of the project is to provide the best user experience to manage Arch linux repositories. In order to follow this we set some limitations for the issue creations and heavily restricted code contribution.
|
||||||
|
|
||||||
## Create an issue
|
## Create an issue
|
||||||
|
|
||||||
@ -26,12 +26,13 @@ In order to resolve all difficult cases the `autopep8` is used. You can perform
|
|||||||
Again, the most checks can be performed by `make check` command, though some additional guidelines must be applied:
|
Again, the most checks can be performed by `make check` command, though some additional guidelines must be applied:
|
||||||
|
|
||||||
* Every class, every function (including private and protected), every attribute must be documented. The project follows [Google style documentation](https://google.github.io/styleguide/pyguide.html). The only exception is local functions.
|
* Every class, every function (including private and protected), every attribute must be documented. The project follows [Google style documentation](https://google.github.io/styleguide/pyguide.html). The only exception is local functions.
|
||||||
|
* Type annotations are the must, even for local functions.
|
||||||
* For any path interactions `pathlib.Path` must be used.
|
* For any path interactions `pathlib.Path` must be used.
|
||||||
* Configuration interactions must go through `ahriman.core.configuration.Configuration` class instance.
|
* Configuration interactions must go through `ahriman.core.configuration.Configuration` class instance.
|
||||||
* In case if class load requires some actions, it is recommended to create class method which can be used for class instantiating.
|
* In case if class load requires some actions, it is recommended to create class method which can be used for class instantiating.
|
||||||
* The code must follow the exception safety, unless it is explicitly asked by end user. It means that most exceptions must be handled and printed to log, no other actions must be done (e.g. raising another exception).
|
* The code must follow the exception safety, unless it is explicitly asked by end user. It means that most exceptions must be handled and printed to log, no other actions must be done (e.g. raising another exception).
|
||||||
* For the external command `ahriman.core.util.check_output` function must be used.
|
* For the external command `ahriman.core.util.check_output` function must be used.
|
||||||
* Every temporary file/directory must be removed at the end of processing, no matter what. The ``tempfile`` module provides good ways to do it.
|
* Every temporary file/directory must be removed at the end of processing, no matter what. The `tempfile` module provides good ways to do it.
|
||||||
* Import order must be the following:
|
* Import order must be the following:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@ -55,10 +56,10 @@ Again, the most checks can be performed by `make check` command, though some add
|
|||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
```
|
```
|
||||||
|
|
||||||
* One file should define only one class, exception is class satellites in case if file length remain less than 200 lines.
|
* One file should define only one class, exception is class satellites in case if file length remains less than 400 lines.
|
||||||
* It is possible to create file which contains some functions (e.g. `ahriman.core.util`), but in this case you would need to define `__all__` attribute.
|
* It is possible to create file which contains some functions (e.g. `ahriman.core.util`), but in this case you would need to define `__all__` attribute.
|
||||||
* The file size mentioned above must be applicable in general. In case of big classes consider splitting them into traits.
|
* The file size mentioned above must be applicable in general. In case of big classes consider splitting them into traits. Note, however, that `pylint` includes comments and docstrings into counter, thus you need to check file size by other tools.
|
||||||
* No global variable allowed outside of `ahriman.version` module.
|
* No global variable is allowed outside of `ahriman.version` module.
|
||||||
* Single quotes are not allowed. The reason behind this restriction is the fact that docstrings must be written by using double quotes only, and we would like to make style consistent.
|
* Single quotes are not allowed. The reason behind this restriction is the fact that docstrings must be written by using double quotes only, and we would like to make style consistent.
|
||||||
* If your class writes anything to log, the `ahriman.core.lazy_logging.LazyLogging` trait must be used.
|
* If your class writes anything to log, the `ahriman.core.lazy_logging.LazyLogging` trait must be used.
|
||||||
|
|
||||||
|
@ -13,11 +13,14 @@ ENV AHRIMAN_REPOSITORY_ROOT="/var/lib/ahriman/ahriman"
|
|||||||
ENV AHRIMAN_USER="ahriman"
|
ENV AHRIMAN_USER="ahriman"
|
||||||
|
|
||||||
# install environment
|
# install environment
|
||||||
|
## update pacman.conf with multilib
|
||||||
|
RUN echo "[multilib]" >> "/etc/pacman.conf" && \
|
||||||
|
echo "Include = /etc/pacman.d/mirrorlist" >> "/etc/pacman.conf"
|
||||||
## install minimal required packages
|
## install minimal required packages
|
||||||
RUN pacman --noconfirm -Syu binutils fakeroot git make sudo
|
RUN pacman --noconfirm -Syu binutils fakeroot git make sudo
|
||||||
## create build user
|
## create build user
|
||||||
RUN useradd -m -d /home/build -s /usr/bin/nologin build && \
|
RUN useradd -m -d "/home/build" -s "/usr/bin/nologin" build && \
|
||||||
echo "build ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/build
|
echo "build ALL=(ALL) NOPASSWD: ALL" > "/etc/sudoers.d/build"
|
||||||
COPY "docker/install-aur-package.sh" "/usr/local/bin/install-aur-package"
|
COPY "docker/install-aur-package.sh" "/usr/local/bin/install-aur-package"
|
||||||
## install package dependencies
|
## install package dependencies
|
||||||
## darcs is not installed by reasons, because it requires a lot haskell packages which dramatically increase image size
|
## darcs is not installed by reasons, because it requires a lot haskell packages which dramatically increase image size
|
||||||
|
2
Makefile
2
Makefile
@ -56,4 +56,4 @@ version:
|
|||||||
ifndef VERSION
|
ifndef VERSION
|
||||||
$(error VERSION is required, but not set)
|
$(error VERSION is required, but not set)
|
||||||
endif
|
endif
|
||||||
sed -i '/__version__ = .*/s/[^"][^)]*/__version__ = "$(VERSION)"/' src/ahriman/version.py
|
sed -i 's/^__version__ = .*/__version__ = "$(VERSION)"/' src/ahriman/version.py
|
||||||
|
File diff suppressed because it is too large
Load Diff
Before Width: | Height: | Size: 537 KiB After Width: | Height: | Size: 613 KiB |
395
docs/ahriman.1
395
docs/ahriman.1
@ -1,9 +1,9 @@
|
|||||||
.TH AHRIMAN "1" Manual
|
.TH AHRIMAN "1" "2022\-11\-16" "ahriman" "Generated Python Manual"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
ahriman
|
ahriman
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.B ahriman
|
.B ahriman
|
||||||
[-h] [-a ARCHITECTURE] [-c CONFIGURATION] [--force] [-l LOCK] [--no-report] [-q] [--unsafe] [-V] {aur-search,search,help,help-commands-unsafe,key-import,package-add,add,package-update,package-remove,remove,package-status,status,package-status-remove,package-status-update,status-update,patch-add,patch-list,patch-remove,repo-backup,repo-check,check,repo-clean,clean,repo-config,config,repo-rebuild,rebuild,repo-remove-unknown,remove-unknown,repo-report,report,repo-restore,repo-setup,init,repo-init,setup,repo-sign,sign,repo-status-update,repo-sync,sync,repo-triggers,repo-update,update,shell,user-add,user-list,user-remove,version,web} ...
|
[-h] [-a ARCHITECTURE] [-c CONFIGURATION] [--force] [-l LOCK] [--report | --no-report] [-q] [--unsafe] [-V] {aur-search,search,daemon,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,patch-set-add,repo-backup,repo-check,check,repo-clean,clean,repo-config,config,repo-rebuild,rebuild,repo-remove-unknown,remove-unknown,repo-report,report,repo-restore,repo-setup,init,repo-init,setup,repo-sign,sign,repo-status-update,repo-sync,sync,repo-triggers,repo-update,update,shell,user-add,user-list,user-remove,version,web} ...
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
ArcH linux ReposItory MANager
|
ArcH linux ReposItory MANager
|
||||||
|
|
||||||
@ -25,8 +25,8 @@ force run, remove file lock
|
|||||||
lock file
|
lock file
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-no\-report\fR
|
\fB\-\-report\fR, \fB\-\-no\-report\fR
|
||||||
force disable reporting to web service
|
force enable or disable reporting to web service (default: True)
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-q\fR, \fB\-\-quiet\fR
|
\fB\-q\fR, \fB\-\-quiet\fR
|
||||||
@ -43,94 +43,100 @@ show program's version number and exit
|
|||||||
.SH
|
.SH
|
||||||
COMMAND
|
COMMAND
|
||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,aur-search\/\fR
|
\fBahriman\fR \fI\,aur\-search\/\fR
|
||||||
search for package
|
search for package
|
||||||
.TP
|
.TP
|
||||||
|
\fBahriman\fR \fI\,daemon\/\fR
|
||||||
|
run application as daemon
|
||||||
|
.TP
|
||||||
\fBahriman\fR \fI\,help\/\fR
|
\fBahriman\fR \fI\,help\/\fR
|
||||||
show help message
|
show help message
|
||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,help-commands-unsafe\/\fR
|
\fBahriman\fR \fI\,help\-commands\-unsafe\/\fR
|
||||||
list unsafe commands
|
list unsafe commands
|
||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,key-import\/\fR
|
\fBahriman\fR \fI\,key\-import\/\fR
|
||||||
import PGP key
|
import PGP key
|
||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,package-add\/\fR
|
\fBahriman\fR \fI\,package\-add\/\fR
|
||||||
add package
|
add package
|
||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,package-remove\/\fR
|
\fBahriman\fR \fI\,package\-remove\/\fR
|
||||||
remove package
|
remove package
|
||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,package-status\/\fR
|
\fBahriman\fR \fI\,package\-status\/\fR
|
||||||
get package status
|
get package status
|
||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,package-status-remove\/\fR
|
\fBahriman\fR \fI\,package\-status\-remove\/\fR
|
||||||
remove package status
|
remove package status
|
||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,package-status-update\/\fR
|
\fBahriman\fR \fI\,package\-status\-update\/\fR
|
||||||
update package status
|
update package status
|
||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,patch-add\/\fR
|
\fBahriman\fR \fI\,patch\-add\/\fR
|
||||||
add patch set
|
add patch for PKGBUILD function
|
||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,patch-list\/\fR
|
\fBahriman\fR \fI\,patch\-list\/\fR
|
||||||
list patch sets
|
list patch sets
|
||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,patch-remove\/\fR
|
\fBahriman\fR \fI\,patch\-remove\/\fR
|
||||||
remove patch set
|
remove patch set
|
||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,repo-backup\/\fR
|
\fBahriman\fR \fI\,patch\-set\-add\/\fR
|
||||||
|
add patch set
|
||||||
|
.TP
|
||||||
|
\fBahriman\fR \fI\,repo\-backup\/\fR
|
||||||
backup repository data
|
backup repository data
|
||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,repo-check\/\fR
|
\fBahriman\fR \fI\,repo\-check\/\fR
|
||||||
check for updates
|
check for updates
|
||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,repo-clean\/\fR
|
\fBahriman\fR \fI\,repo\-clean\/\fR
|
||||||
clean local caches
|
clean local caches
|
||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,repo-config\/\fR
|
\fBahriman\fR \fI\,repo\-config\/\fR
|
||||||
dump configuration
|
dump configuration
|
||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,repo-rebuild\/\fR
|
\fBahriman\fR \fI\,repo\-rebuild\/\fR
|
||||||
rebuild repository
|
rebuild repository
|
||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,repo-remove-unknown\/\fR
|
\fBahriman\fR \fI\,repo\-remove\-unknown\/\fR
|
||||||
remove unknown packages
|
remove unknown packages
|
||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,repo-report\/\fR
|
\fBahriman\fR \fI\,repo\-report\/\fR
|
||||||
generate report
|
generate report
|
||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,repo-restore\/\fR
|
\fBahriman\fR \fI\,repo\-restore\/\fR
|
||||||
restore repository data
|
restore repository data
|
||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,repo-setup\/\fR
|
\fBahriman\fR \fI\,repo\-setup\/\fR
|
||||||
initial service configuration
|
initial service configuration
|
||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,repo-sign\/\fR
|
\fBahriman\fR \fI\,repo\-sign\/\fR
|
||||||
sign packages
|
sign packages
|
||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,repo-status-update\/\fR
|
\fBahriman\fR \fI\,repo\-status\-update\/\fR
|
||||||
update repository status
|
update repository status
|
||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,repo-sync\/\fR
|
\fBahriman\fR \fI\,repo\-sync\/\fR
|
||||||
sync repository
|
sync repository
|
||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,repo-triggers\/\fR
|
\fBahriman\fR \fI\,repo\-triggers\/\fR
|
||||||
run triggers
|
run triggers
|
||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,repo-update\/\fR
|
\fBahriman\fR \fI\,repo\-update\/\fR
|
||||||
update packages
|
update packages
|
||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,shell\/\fR
|
\fBahriman\fR \fI\,shell\/\fR
|
||||||
envoke python shell
|
envoke python shell
|
||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,user-add\/\fR
|
\fBahriman\fR \fI\,user\-add\/\fR
|
||||||
create or update user
|
create or update user
|
||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,user-list\/\fR
|
\fBahriman\fR \fI\,user\-list\/\fR
|
||||||
user known users and their access
|
user known users and their access
|
||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,user-remove\/\fR
|
\fBahriman\fR \fI\,user\-remove\/\fR
|
||||||
remove user
|
remove user
|
||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,version\/\fR
|
\fBahriman\fR \fI\,version\/\fR
|
||||||
@ -138,33 +144,65 @@ application version
|
|||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,web\/\fR
|
\fBahriman\fR \fI\,web\/\fR
|
||||||
web server
|
web server
|
||||||
.SH COMMAND \fI\,'ahriman aur-search'\/\fR
|
|
||||||
usage: ahriman aur-search [-h] [-e] [-i]
|
.SH COMMAND \fI\,'ahriman aur\-search'\/\fR
|
||||||
[--sort-by {description,first_submitted,id,last_modified,maintainer,name,num_votes,out_of_date,package_base,package_base_id,popularity,repository,url,url_path,version}]
|
usage: ahriman aur\-search [\-h] [\-e] [\-\-info | \-\-no\-info]
|
||||||
|
[\-\-sort\-by {description,first_submitted,id,last_modified,maintainer,name,num_votes,out_of_date,package_base,package_base_id,popularity,repository,url,url_path,version}]
|
||||||
search [search ...]
|
search [search ...]
|
||||||
|
|
||||||
search for package in AUR using API
|
search for package in AUR using API
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fBsearch\fR
|
\fBsearch\fR
|
||||||
search terms, can be specified multiple times, result will match all terms
|
search terms, can be specified multiple times, the result will match all terms
|
||||||
|
|
||||||
.SH OPTIONS \fI\,'ahriman aur-search'\/\fR
|
.SH OPTIONS \fI\,'ahriman aur\-search'\/\fR
|
||||||
.TP
|
.TP
|
||||||
\fB\-e\fR, \fB\-\-exit\-code\fR
|
\fB\-e\fR, \fB\-\-exit\-code\fR
|
||||||
return non\-zero exit status if result is empty
|
return non\-zero exit status if result is empty
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-i\fR, \fB\-\-info\fR
|
\fB\-\-info\fR, \fB\-\-no\-info\fR
|
||||||
show additional package information
|
show additional package information (default: False)
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-sort\-by\fR \fI\,{description,first_submitted,id,last_modified,maintainer,name,num_votes,out_of_date,package_base,package_base_id,popularity,repository,url,url_path,version}\/\fR
|
\fB\-\-sort\-by\fR \fI\,{description,first_submitted,id,last_modified,maintainer,name,num_votes,out_of_date,package_base,package_base_id,popularity,repository,url,url_path,version}\/\fR
|
||||||
sort field by this field. In case if two packages have the same value of the specified field, they will be always sorted
|
sort field by this field. In case if two packages have the same value of the specified field, they will be always sorted
|
||||||
by name
|
by name
|
||||||
|
|
||||||
|
.SH COMMAND \fI\,'ahriman daemon'\/\fR
|
||||||
|
usage: ahriman daemon [\-h] [\-i INTERVAL] [\-\-aur | \-\-no\-aur] [\-\-local | \-\-no\-local] [\-\-manual | \-\-no\-manual]
|
||||||
|
[\-\-vcs | \-\-no\-vcs] [\-y]
|
||||||
|
|
||||||
|
start process which periodically will run update process
|
||||||
|
|
||||||
|
.SH OPTIONS \fI\,'ahriman daemon'\/\fR
|
||||||
|
.TP
|
||||||
|
\fB\-i\fR \fI\,INTERVAL\/\fR, \fB\-\-interval\fR \fI\,INTERVAL\/\fR
|
||||||
|
interval between runs in seconds
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fB\-\-aur\fR, \fB\-\-no\-aur\fR
|
||||||
|
enable or disable checking for AUR updates. Implies \-\-no\-vcs (default: True)
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fB\-\-local\fR, \fB\-\-no\-local\fR
|
||||||
|
enable or disable checking of local packages for updates (default: True)
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fB\-\-manual\fR, \fB\-\-no\-manual\fR
|
||||||
|
include or exclude manual updates (default: True)
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fB\-\-vcs\fR, \fB\-\-no\-vcs\fR
|
||||||
|
enable or disable checking of VCS packages (default: True)
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fB\-y\fR, \fB\-\-refresh\fR
|
||||||
|
download fresh package databases from the mirror before actions, \-yy to force refresh even if up to date
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman help'\/\fR
|
.SH COMMAND \fI\,'ahriman help'\/\fR
|
||||||
usage: ahriman help [-h] [command]
|
usage: ahriman help [\-h] [command]
|
||||||
|
|
||||||
show help message for application or command and exit
|
show help message for application or command and exit
|
||||||
|
|
||||||
@ -172,19 +210,19 @@ show help message for application or command and exit
|
|||||||
\fBcommand\fR
|
\fBcommand\fR
|
||||||
show help message for specific command
|
show help message for specific command
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman help-commands-unsafe'\/\fR
|
.SH COMMAND \fI\,'ahriman help\-commands\-unsafe'\/\fR
|
||||||
usage: ahriman help-commands-unsafe [-h] [--command COMMAND]
|
usage: ahriman help\-commands\-unsafe [\-h] [\-\-command COMMAND]
|
||||||
|
|
||||||
list unsafe commands as defined in default args
|
list unsafe commands as defined in default args
|
||||||
|
|
||||||
.SH OPTIONS \fI\,'ahriman help-commands-unsafe'\/\fR
|
.SH OPTIONS \fI\,'ahriman help\-commands\-unsafe'\/\fR
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-command\fR \fI\,COMMAND\/\fR
|
\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
|
instead of showing commands, just test command line for unsafe subcommand and return 0 in case if command is safe and 1
|
||||||
otherwise
|
otherwise
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman key-import'\/\fR
|
.SH COMMAND \fI\,'ahriman key\-import'\/\fR
|
||||||
usage: ahriman key-import [-h] [--key-server KEY_SERVER] key
|
usage: ahriman key\-import [\-h] [\-\-key\-server KEY_SERVER] key
|
||||||
|
|
||||||
import PGP key from public sources to the repository user
|
import PGP key from public sources to the repository user
|
||||||
|
|
||||||
@ -192,14 +230,14 @@ import PGP key from public sources to the repository user
|
|||||||
\fBkey\fR
|
\fBkey\fR
|
||||||
PGP key to import from public server
|
PGP key to import from public server
|
||||||
|
|
||||||
.SH OPTIONS \fI\,'ahriman key-import'\/\fR
|
.SH OPTIONS \fI\,'ahriman key\-import'\/\fR
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-key\-server\fR \fI\,KEY_SERVER\/\fR
|
\fB\-\-key\-server\fR \fI\,KEY_SERVER\/\fR
|
||||||
key server for key import
|
key server for key import
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman package-add'\/\fR
|
.SH COMMAND \fI\,'ahriman package\-add'\/\fR
|
||||||
usage: ahriman package-add [-h] [-e] [-n] [-s {auto,archive,aur,directory,local,remote,repository}]
|
usage: ahriman package\-add [\-h] [\-e] [\-n] [\-y] [\-s {auto,archive,aur,directory,local,remote,repository}]
|
||||||
[--without-dependencies]
|
[\-\-without\-dependencies]
|
||||||
package [package ...]
|
package [package ...]
|
||||||
|
|
||||||
add existing or new package to the build queue
|
add existing or new package to the build queue
|
||||||
@ -208,7 +246,7 @@ add existing or new package to the build queue
|
|||||||
\fBpackage\fR
|
\fBpackage\fR
|
||||||
package source (base name, path to local files, remote URL)
|
package source (base name, path to local files, remote URL)
|
||||||
|
|
||||||
.SH OPTIONS \fI\,'ahriman package-add'\/\fR
|
.SH OPTIONS \fI\,'ahriman package\-add'\/\fR
|
||||||
.TP
|
.TP
|
||||||
\fB\-e\fR, \fB\-\-exit\-code\fR
|
\fB\-e\fR, \fB\-\-exit\-code\fR
|
||||||
return non\-zero exit status if result is empty
|
return non\-zero exit status if result is empty
|
||||||
@ -217,6 +255,10 @@ return non\-zero exit status if result is empty
|
|||||||
\fB\-n\fR, \fB\-\-now\fR
|
\fB\-n\fR, \fB\-\-now\fR
|
||||||
run update function after
|
run update function after
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fB\-y\fR, \fB\-\-refresh\fR
|
||||||
|
download fresh package databases from the mirror before actions, \-yy to force refresh even if up to date
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-s\fR \fI\,{auto,archive,aur,directory,local,remote,repository}\/\fR, \fB\-\-source\fR \fI\,{auto,archive,aur,directory,local,remote,repository}\/\fR
|
\fB\-s\fR \fI\,{auto,archive,aur,directory,local,remote,repository}\/\fR, \fB\-\-source\fR \fI\,{auto,archive,aur,directory,local,remote,repository}\/\fR
|
||||||
explicitly specify the package source for this command
|
explicitly specify the package source for this command
|
||||||
@ -225,8 +267,8 @@ explicitly specify the package source for this command
|
|||||||
\fB\-\-without\-dependencies\fR
|
\fB\-\-without\-dependencies\fR
|
||||||
do not add dependencies
|
do not add dependencies
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman package-remove'\/\fR
|
.SH COMMAND \fI\,'ahriman package\-remove'\/\fR
|
||||||
usage: ahriman package-remove [-h] package [package ...]
|
usage: ahriman package\-remove [\-h] package [package ...]
|
||||||
|
|
||||||
remove package from the repository
|
remove package from the repository
|
||||||
|
|
||||||
@ -234,8 +276,8 @@ remove package from the repository
|
|||||||
\fBpackage\fR
|
\fBpackage\fR
|
||||||
package name or base
|
package name or base
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman package-status'\/\fR
|
.SH COMMAND \fI\,'ahriman package\-status'\/\fR
|
||||||
usage: ahriman package-status [-h] [--ahriman] [-e] [-i] [-s {unknown,pending,building,failed,success}] [package ...]
|
usage: ahriman package\-status [\-h] [\-\-ahriman] [\-e] [\-i] [\-s {unknown,pending,building,failed,success}] [package ...]
|
||||||
|
|
||||||
request status of the package
|
request status of the package
|
||||||
|
|
||||||
@ -243,7 +285,7 @@ request status of the package
|
|||||||
\fBpackage\fR
|
\fBpackage\fR
|
||||||
filter status by package base
|
filter status by package base
|
||||||
|
|
||||||
.SH OPTIONS \fI\,'ahriman package-status'\/\fR
|
.SH OPTIONS \fI\,'ahriman package\-status'\/\fR
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-ahriman\fR
|
\fB\-\-ahriman\fR
|
||||||
get service status itself
|
get service status itself
|
||||||
@ -260,17 +302,17 @@ show additional package information
|
|||||||
\fB\-s\fR \fI\,{unknown,pending,building,failed,success}\/\fR, \fB\-\-status\fR \fI\,{unknown,pending,building,failed,success}\/\fR
|
\fB\-s\fR \fI\,{unknown,pending,building,failed,success}\/\fR, \fB\-\-status\fR \fI\,{unknown,pending,building,failed,success}\/\fR
|
||||||
filter packages by status
|
filter packages by status
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman package-status-remove'\/\fR
|
.SH COMMAND \fI\,'ahriman package\-status\-remove'\/\fR
|
||||||
usage: ahriman package-status-remove [-h] package [package ...]
|
usage: ahriman package\-status\-remove [\-h] package [package ...]
|
||||||
|
|
||||||
remove the package from the status page
|
remove the package from the status page
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fBpackage\fR
|
\fBpackage\fR
|
||||||
remove specified packages
|
remove specified packages from status page
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman package-status-update'\/\fR
|
.SH COMMAND \fI\,'ahriman package\-status\-update'\/\fR
|
||||||
usage: ahriman package-status-update [-h] [-s {unknown,pending,building,failed,success}] [package ...]
|
usage: ahriman package\-status\-update [\-h] [\-s {unknown,pending,building,failed,success}] [package ...]
|
||||||
|
|
||||||
update package status on the status page
|
update package status on the status page
|
||||||
|
|
||||||
@ -278,27 +320,30 @@ update package status on the status page
|
|||||||
\fBpackage\fR
|
\fBpackage\fR
|
||||||
set status for specified packages. If no packages supplied, service status will be updated
|
set status for specified packages. If no packages supplied, service status will be updated
|
||||||
|
|
||||||
.SH OPTIONS \fI\,'ahriman package-status-update'\/\fR
|
.SH OPTIONS \fI\,'ahriman package\-status\-update'\/\fR
|
||||||
.TP
|
.TP
|
||||||
\fB\-s\fR \fI\,{unknown,pending,building,failed,success}\/\fR, \fB\-\-status\fR \fI\,{unknown,pending,building,failed,success}\/\fR
|
\fB\-s\fR \fI\,{unknown,pending,building,failed,success}\/\fR, \fB\-\-status\fR \fI\,{unknown,pending,building,failed,success}\/\fR
|
||||||
new status
|
new package build status
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman patch-add'\/\fR
|
.SH COMMAND \fI\,'ahriman patch\-add'\/\fR
|
||||||
usage: ahriman patch-add [-h] [-t TRACK] package
|
usage: ahriman patch\-add [\-h] package variable [patch]
|
||||||
|
|
||||||
create or update source patches
|
create or update patched PKGBUILD function or variable
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fBpackage\fR
|
\fBpackage\fR
|
||||||
path to directory with changed files for patch addition/update
|
package base
|
||||||
|
|
||||||
.SH OPTIONS \fI\,'ahriman patch-add'\/\fR
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-t\fR \fI\,TRACK\/\fR, \fB\-\-track\fR \fI\,TRACK\/\fR
|
\fBvariable\fR
|
||||||
files which has to be tracked
|
PKGBUILD variable or function name. If variable is a function, it must end with ()
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman patch-list'\/\fR
|
.TP
|
||||||
usage: ahriman patch-list [-h] [-e] [package]
|
\fBpatch\fR
|
||||||
|
path to file which contains function or variable value. If not set, the value will be read from stdin
|
||||||
|
|
||||||
|
.SH COMMAND \fI\,'ahriman patch\-list'\/\fR
|
||||||
|
usage: ahriman patch\-list [\-h] [\-e] [\-v VARIABLE] [package]
|
||||||
|
|
||||||
list available patches for the package
|
list available patches for the package
|
||||||
|
|
||||||
@ -306,13 +351,17 @@ list available patches for the package
|
|||||||
\fBpackage\fR
|
\fBpackage\fR
|
||||||
package base
|
package base
|
||||||
|
|
||||||
.SH OPTIONS \fI\,'ahriman patch-list'\/\fR
|
.SH OPTIONS \fI\,'ahriman patch\-list'\/\fR
|
||||||
.TP
|
.TP
|
||||||
\fB\-e\fR, \fB\-\-exit\-code\fR
|
\fB\-e\fR, \fB\-\-exit\-code\fR
|
||||||
return non\-zero exit status if result is empty
|
return non\-zero exit status if result is empty
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman patch-remove'\/\fR
|
.TP
|
||||||
usage: ahriman patch-remove [-h] package
|
\fB\-v\fR \fI\,VARIABLE\/\fR, \fB\-\-variable\fR \fI\,VARIABLE\/\fR
|
||||||
|
if set, show only patches for specified PKGBUILD variables
|
||||||
|
|
||||||
|
.SH COMMAND \fI\,'ahriman patch\-remove'\/\fR
|
||||||
|
usage: ahriman patch\-remove [\-h] [\-v VARIABLE] package
|
||||||
|
|
||||||
remove patches for the package
|
remove patches for the package
|
||||||
|
|
||||||
@ -320,69 +369,98 @@ remove patches for the package
|
|||||||
\fBpackage\fR
|
\fBpackage\fR
|
||||||
package base
|
package base
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman repo-backup'\/\fR
|
.SH OPTIONS \fI\,'ahriman patch\-remove'\/\fR
|
||||||
usage: ahriman repo-backup [-h] path
|
.TP
|
||||||
|
\fB\-v\fR \fI\,VARIABLE\/\fR, \fB\-\-variable\fR \fI\,VARIABLE\/\fR
|
||||||
|
should be used for single\-function patches in case if you wold like to remove only specified PKGBUILD variables. In case
|
||||||
|
if not set, it will remove all patches related to the package
|
||||||
|
|
||||||
backup settings and database
|
.SH COMMAND \fI\,'ahriman patch\-set\-add'\/\fR
|
||||||
|
usage: ahriman patch\-set\-add [\-h] [\-t TRACK] package
|
||||||
|
|
||||||
|
create or update source patches
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fBpackage\fR
|
||||||
|
path to directory with changed files for patch addition/update
|
||||||
|
|
||||||
|
.SH OPTIONS \fI\,'ahriman patch\-set\-add'\/\fR
|
||||||
|
.TP
|
||||||
|
\fB\-t\fR \fI\,TRACK\/\fR, \fB\-\-track\fR \fI\,TRACK\/\fR
|
||||||
|
files which has to be tracked
|
||||||
|
|
||||||
|
.SH COMMAND \fI\,'ahriman repo\-backup'\/\fR
|
||||||
|
usage: ahriman repo\-backup [\-h] path
|
||||||
|
|
||||||
|
backup repository settings and database
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fBpath\fR
|
\fBpath\fR
|
||||||
path of the output archive
|
path of the output archive
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman repo-check'\/\fR
|
.SH COMMAND \fI\,'ahriman repo\-check'\/\fR
|
||||||
usage: ahriman repo-check [-h] [-e] [--no-vcs] [package ...]
|
usage: ahriman repo\-check [\-h] [\-e] [\-\-vcs | \-\-no\-vcs] [\-y] [package ...]
|
||||||
|
|
||||||
check for packages updates. Same as update \-\-dry\-run \-\-no\-manual
|
check for packages updates. Same as repo\-update \-\-dry\-run \-\-no\-manual
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fBpackage\fR
|
\fBpackage\fR
|
||||||
filter check by package base
|
filter check by package base
|
||||||
|
|
||||||
.SH OPTIONS \fI\,'ahriman repo-check'\/\fR
|
.SH OPTIONS \fI\,'ahriman repo\-check'\/\fR
|
||||||
.TP
|
.TP
|
||||||
\fB\-e\fR, \fB\-\-exit\-code\fR
|
\fB\-e\fR, \fB\-\-exit\-code\fR
|
||||||
return non\-zero exit status if result is empty
|
return non\-zero exit status if result is empty
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-no\-vcs\fR
|
\fB\-\-vcs\fR, \fB\-\-no\-vcs\fR
|
||||||
do not check VCS packages
|
enable or disable checking of VCS packages (default: True)
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman repo-clean'\/\fR
|
.TP
|
||||||
usage: ahriman repo-clean [-h] [--cache] [--chroot] [--manual] [--packages]
|
\fB\-y\fR, \fB\-\-refresh\fR
|
||||||
|
download fresh package databases from the mirror before actions, \-yy to force refresh even if up to date
|
||||||
|
|
||||||
|
.SH COMMAND \fI\,'ahriman repo\-clean'\/\fR
|
||||||
|
usage: ahriman repo\-clean [\-h] [\-\-cache | \-\-no\-cache] [\-\-chroot | \-\-no\-chroot] [\-\-manual | \-\-no\-manual]
|
||||||
|
[\-\-packages | \-\-no\-packages] [\-\-pacman | \-\-no\-pacman]
|
||||||
|
|
||||||
remove local caches
|
remove local caches
|
||||||
|
|
||||||
.SH OPTIONS \fI\,'ahriman repo-clean'\/\fR
|
.SH OPTIONS \fI\,'ahriman repo\-clean'\/\fR
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-cache\fR
|
\fB\-\-cache\fR, \fB\-\-no\-cache\fR
|
||||||
clear directory with package caches
|
clear directory with package caches (default: False)
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-chroot\fR
|
\fB\-\-chroot\fR, \fB\-\-no\-chroot\fR
|
||||||
clear build chroot
|
clear build chroot (default: False)
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-manual\fR
|
\fB\-\-manual\fR, \fB\-\-no\-manual\fR
|
||||||
clear manually added packages queue
|
clear manually added packages queue (default: False)
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-packages\fR
|
\fB\-\-packages\fR, \fB\-\-no\-packages\fR
|
||||||
clear directory with built packages
|
clear directory with built packages (default: False)
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman repo-config'\/\fR
|
.TP
|
||||||
usage: ahriman repo-config [-h]
|
\fB\-\-pacman\fR, \fB\-\-no\-pacman\fR
|
||||||
|
clear directory with pacman local database cache (default: False)
|
||||||
|
|
||||||
|
.SH COMMAND \fI\,'ahriman repo\-config'\/\fR
|
||||||
|
usage: ahriman repo\-config [\-h]
|
||||||
|
|
||||||
dump configuration for the specified architecture
|
dump configuration for the specified architecture
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman repo-rebuild'\/\fR
|
.SH COMMAND \fI\,'ahriman repo\-rebuild'\/\fR
|
||||||
usage: ahriman repo-rebuild [-h] [--depends-on DEPENDS_ON] [--dry-run] [--from-database] [-e]
|
usage: ahriman repo\-rebuild [\-h] [\-\-depends\-on DEPENDS_ON] [\-\-dry\-run] [\-\-from\-database] [\-e]
|
||||||
|
|
||||||
force rebuild whole repository
|
force rebuild whole repository
|
||||||
|
|
||||||
.SH OPTIONS \fI\,'ahriman repo-rebuild'\/\fR
|
.SH OPTIONS \fI\,'ahriman repo\-rebuild'\/\fR
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-depends\-on\fR \fI\,DEPENDS_ON\/\fR
|
\fB\-\-depends\-on\fR \fI\,DEPENDS_ON\/\fR
|
||||||
only rebuild packages that depend on specified package
|
only rebuild packages that depend on specified packages
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-dry\-run\fR
|
\fB\-\-dry\-run\fR
|
||||||
@ -391,34 +469,30 @@ just perform check for packages without rebuild process itself
|
|||||||
.TP
|
.TP
|
||||||
\fB\-\-from\-database\fR
|
\fB\-\-from\-database\fR
|
||||||
read packages from database instead of filesystem. This feature in particular is required in case if you would like to
|
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
|
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.
|
original ahriman instance run with web service and have run repo\-update at least once.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-e\fR, \fB\-\-exit\-code\fR
|
\fB\-e\fR, \fB\-\-exit\-code\fR
|
||||||
return non\-zero exit status if result is empty
|
return non\-zero exit status if result is empty
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman repo-remove-unknown'\/\fR
|
.SH COMMAND \fI\,'ahriman repo\-remove\-unknown'\/\fR
|
||||||
usage: ahriman repo-remove-unknown [-h] [--dry-run] [-i]
|
usage: ahriman repo\-remove\-unknown [\-h] [\-\-dry\-run]
|
||||||
|
|
||||||
remove packages which are missing in AUR and do not have local PKGBUILDs
|
remove packages which are missing in AUR and do not have local PKGBUILDs
|
||||||
|
|
||||||
.SH OPTIONS \fI\,'ahriman repo-remove-unknown'\/\fR
|
.SH OPTIONS \fI\,'ahriman repo\-remove\-unknown'\/\fR
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-dry\-run\fR
|
\fB\-\-dry\-run\fR
|
||||||
just perform check for packages without removal
|
just perform check for packages without removal
|
||||||
|
|
||||||
.TP
|
.SH COMMAND \fI\,'ahriman repo\-report'\/\fR
|
||||||
\fB\-i\fR, \fB\-\-info\fR
|
usage: ahriman repo\-report [\-h]
|
||||||
show additional package information
|
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman repo-report'\/\fR
|
|
||||||
usage: ahriman repo-report [-h]
|
|
||||||
|
|
||||||
generate repository report according to current settings
|
generate repository report according to current settings
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman repo-restore'\/\fR
|
.SH COMMAND \fI\,'ahriman repo\-restore'\/\fR
|
||||||
usage: ahriman repo-restore [-h] [-o OUTPUT] path
|
usage: ahriman repo\-restore [\-h] [\-o OUTPUT] path
|
||||||
|
|
||||||
restore settings and database
|
restore settings and database
|
||||||
|
|
||||||
@ -426,20 +500,20 @@ restore settings and database
|
|||||||
\fBpath\fR
|
\fBpath\fR
|
||||||
path of the input archive
|
path of the input archive
|
||||||
|
|
||||||
.SH OPTIONS \fI\,'ahriman repo-restore'\/\fR
|
.SH OPTIONS \fI\,'ahriman repo\-restore'\/\fR
|
||||||
.TP
|
.TP
|
||||||
\fB\-o\fR \fI\,OUTPUT\/\fR, \fB\-\-output\fR \fI\,OUTPUT\/\fR
|
\fB\-o\fR \fI\,OUTPUT\/\fR, \fB\-\-output\fR \fI\,OUTPUT\/\fR
|
||||||
root path of the extracted files
|
root path of the extracted files
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman repo-setup'\/\fR
|
.SH COMMAND \fI\,'ahriman repo\-setup'\/\fR
|
||||||
usage: ahriman repo-setup [-h] [--build-as-user BUILD_AS_USER] [--build-command BUILD_COMMAND]
|
usage: ahriman repo\-setup [\-h] [\-\-build\-as\-user BUILD_AS_USER] [\-\-build\-command BUILD_COMMAND]
|
||||||
[--from-configuration FROM_CONFIGURATION] [--no-multilib] --packager PACKAGER --repository
|
[\-\-from\-configuration FROM_CONFIGURATION] [\-\-multilib | \-\-no\-multilib] \-\-packager PACKAGER
|
||||||
REPOSITORY [--sign-key SIGN_KEY] [--sign-target {disabled,pacakges,repository}]
|
\-\-repository REPOSITORY [\-\-sign\-key SIGN_KEY] [\-\-sign\-target {disabled,pacakges,repository}]
|
||||||
[--web-port WEB_PORT]
|
[\-\-web\-port WEB_PORT]
|
||||||
|
|
||||||
create initial service configuration, requires root
|
create initial service configuration, requires root
|
||||||
|
|
||||||
.SH OPTIONS \fI\,'ahriman repo-setup'\/\fR
|
.SH OPTIONS \fI\,'ahriman repo\-setup'\/\fR
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-build\-as\-user\fR \fI\,BUILD_AS_USER\/\fR
|
\fB\-\-build\-as\-user\fR \fI\,BUILD_AS_USER\/\fR
|
||||||
force makepkg user to the specific one
|
force makepkg user to the specific one
|
||||||
@ -453,8 +527,8 @@ build command prefix
|
|||||||
path to default devtools pacman configuration
|
path to default devtools pacman configuration
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-no\-multilib\fR
|
\fB\-\-multilib\fR, \fB\-\-no\-multilib\fR
|
||||||
do not add multilib repository
|
add or do not multilib repository (default: True)
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-packager\fR \fI\,PACKAGER\/\fR
|
\fB\-\-packager\fR \fI\,PACKAGER\/\fR
|
||||||
@ -476,8 +550,8 @@ sign options
|
|||||||
\fB\-\-web\-port\fR \fI\,WEB_PORT\/\fR
|
\fB\-\-web\-port\fR \fI\,WEB_PORT\/\fR
|
||||||
port of the web service
|
port of the web service
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman repo-sign'\/\fR
|
.SH COMMAND \fI\,'ahriman repo\-sign'\/\fR
|
||||||
usage: ahriman repo-sign [-h] [package ...]
|
usage: ahriman repo\-sign [\-h] [package ...]
|
||||||
|
|
||||||
(re\-)sign packages and repository database according to current settings
|
(re\-)sign packages and repository database according to current settings
|
||||||
|
|
||||||
@ -485,23 +559,23 @@ usage: ahriman repo-sign [-h] [package ...]
|
|||||||
\fBpackage\fR
|
\fBpackage\fR
|
||||||
sign only specified packages
|
sign only specified packages
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman repo-status-update'\/\fR
|
.SH COMMAND \fI\,'ahriman repo\-status\-update'\/\fR
|
||||||
usage: ahriman repo-status-update [-h] [-s {unknown,pending,building,failed,success}]
|
usage: ahriman repo\-status\-update [\-h] [\-s {unknown,pending,building,failed,success}]
|
||||||
|
|
||||||
update repository status on the status page
|
update repository status on the status page
|
||||||
|
|
||||||
.SH OPTIONS \fI\,'ahriman repo-status-update'\/\fR
|
.SH OPTIONS \fI\,'ahriman repo\-status\-update'\/\fR
|
||||||
.TP
|
.TP
|
||||||
\fB\-s\fR \fI\,{unknown,pending,building,failed,success}\/\fR, \fB\-\-status\fR \fI\,{unknown,pending,building,failed,success}\/\fR
|
\fB\-s\fR \fI\,{unknown,pending,building,failed,success}\/\fR, \fB\-\-status\fR \fI\,{unknown,pending,building,failed,success}\/\fR
|
||||||
new status
|
new status
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman repo-sync'\/\fR
|
.SH COMMAND \fI\,'ahriman repo\-sync'\/\fR
|
||||||
usage: ahriman repo-sync [-h]
|
usage: ahriman repo\-sync [\-h]
|
||||||
|
|
||||||
sync repository files to remote server according to current settings
|
sync repository files to remote server according to current settings
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman repo-triggers'\/\fR
|
.SH COMMAND \fI\,'ahriman repo\-triggers'\/\fR
|
||||||
usage: ahriman repo-triggers [-h] [trigger ...]
|
usage: ahriman repo\-triggers [\-h] [trigger ...]
|
||||||
|
|
||||||
run triggers on empty build result as configured by settings
|
run triggers on empty build result as configured by settings
|
||||||
|
|
||||||
@ -509,8 +583,10 @@ run triggers on empty build result as configured by settings
|
|||||||
\fBtrigger\fR
|
\fBtrigger\fR
|
||||||
instead of running all triggers as set by configuration, just process specified ones oin order of metion
|
instead of running all triggers as set by configuration, just process specified ones oin order of metion
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman repo-update'\/\fR
|
.SH COMMAND \fI\,'ahriman repo\-update'\/\fR
|
||||||
usage: ahriman repo-update [-h] [--dry-run] [-e] [--no-aur] [--no-local] [--no-manual] [--no-vcs] [package ...]
|
usage: ahriman repo\-update [\-h] [\-\-dry\-run] [\-e] [\-\-aur | \-\-no\-aur] [\-\-local | \-\-no\-local] [\-\-manual | \-\-no\-manual]
|
||||||
|
[\-\-vcs | \-\-no\-vcs] [\-y]
|
||||||
|
[package ...]
|
||||||
|
|
||||||
check for packages updates and run build process if requested
|
check for packages updates and run build process if requested
|
||||||
|
|
||||||
@ -518,7 +594,7 @@ check for packages updates and run build process if requested
|
|||||||
\fBpackage\fR
|
\fBpackage\fR
|
||||||
filter check by package base
|
filter check by package base
|
||||||
|
|
||||||
.SH OPTIONS \fI\,'ahriman repo-update'\/\fR
|
.SH OPTIONS \fI\,'ahriman repo\-update'\/\fR
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-dry\-run\fR
|
\fB\-\-dry\-run\fR
|
||||||
just perform check for updates, same as check command
|
just perform check for updates, same as check command
|
||||||
@ -528,28 +604,36 @@ just perform check for updates, same as check command
|
|||||||
return non\-zero exit status if result is empty
|
return non\-zero exit status if result is empty
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-no\-aur\fR
|
\fB\-\-aur\fR, \fB\-\-no\-aur\fR
|
||||||
do not check for AUR updates. Implies \-\-no\-vcs
|
enable or disable checking for AUR updates. Implies \-\-no\-vcs (default: True)
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-no\-local\fR
|
\fB\-\-local\fR, \fB\-\-no\-local\fR
|
||||||
do not check local packages for updates
|
enable or disable checking of local packages for updates (default: True)
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-no\-manual\fR
|
\fB\-\-manual\fR, \fB\-\-no\-manual\fR
|
||||||
do not include manual updates
|
include or exclude manual updates (default: True)
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-no\-vcs\fR
|
\fB\-\-vcs\fR, \fB\-\-no\-vcs\fR
|
||||||
do not check VCS packages
|
enable or disable checking of VCS packages (default: True)
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fB\-y\fR, \fB\-\-refresh\fR
|
||||||
|
download fresh package databases from the mirror before actions, \-yy to force refresh even if up to date
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman shell'\/\fR
|
.SH COMMAND \fI\,'ahriman shell'\/\fR
|
||||||
usage: ahriman shell [-h]
|
usage: ahriman shell [\-h] [code]
|
||||||
|
|
||||||
drop into python shell while having created application
|
drop into python shell while having created application
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman user-add'\/\fR
|
.TP
|
||||||
usage: ahriman user-add [-h] [--as-service] [-p PASSWORD] [-r {unauthorized,read,reporter,full}] [-s] username
|
\fBcode\fR
|
||||||
|
instead of dropping into shell, just execute the specified code
|
||||||
|
|
||||||
|
.SH COMMAND \fI\,'ahriman user\-add'\/\fR
|
||||||
|
usage: ahriman user\-add [\-h] [\-\-as\-service] [\-p PASSWORD] [\-r {unauthorized,read,reporter,full}] [\-s] username
|
||||||
|
|
||||||
update user for web services with the given password and role. In case if password was not entered it will be asked interactively
|
update user for web services with the given password and role. In case if password was not entered it will be asked interactively
|
||||||
|
|
||||||
@ -557,7 +641,7 @@ update user for web services with the given password and role. In case if passwo
|
|||||||
\fBusername\fR
|
\fBusername\fR
|
||||||
username for web service
|
username for web service
|
||||||
|
|
||||||
.SH OPTIONS \fI\,'ahriman user-add'\/\fR
|
.SH OPTIONS \fI\,'ahriman user\-add'\/\fR
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-as\-service\fR
|
\fB\-\-as\-service\fR
|
||||||
add user as service user
|
add user as service user
|
||||||
@ -575,8 +659,8 @@ user access level
|
|||||||
\fB\-s\fR, \fB\-\-secure\fR
|
\fB\-s\fR, \fB\-\-secure\fR
|
||||||
set file permissions to user\-only
|
set file permissions to user\-only
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman user-list'\/\fR
|
.SH COMMAND \fI\,'ahriman user\-list'\/\fR
|
||||||
usage: ahriman user-list [-h] [-e] [-r {unauthorized,read,reporter,full}] [username]
|
usage: ahriman user\-list [\-h] [\-e] [\-r {unauthorized,read,reporter,full}] [username]
|
||||||
|
|
||||||
list users from the user mapping and their roles
|
list users from the user mapping and their roles
|
||||||
|
|
||||||
@ -584,7 +668,7 @@ list users from the user mapping and their roles
|
|||||||
\fBusername\fR
|
\fBusername\fR
|
||||||
filter users by username
|
filter users by username
|
||||||
|
|
||||||
.SH OPTIONS \fI\,'ahriman user-list'\/\fR
|
.SH OPTIONS \fI\,'ahriman user\-list'\/\fR
|
||||||
.TP
|
.TP
|
||||||
\fB\-e\fR, \fB\-\-exit\-code\fR
|
\fB\-e\fR, \fB\-\-exit\-code\fR
|
||||||
return non\-zero exit status if result is empty
|
return non\-zero exit status if result is empty
|
||||||
@ -593,8 +677,8 @@ return non\-zero exit status if result is empty
|
|||||||
\fB\-r\fR \fI\,{unauthorized,read,reporter,full}\/\fR, \fB\-\-role\fR \fI\,{unauthorized,read,reporter,full}\/\fR
|
\fB\-r\fR \fI\,{unauthorized,read,reporter,full}\/\fR, \fB\-\-role\fR \fI\,{unauthorized,read,reporter,full}\/\fR
|
||||||
filter users by role
|
filter users by role
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman user-remove'\/\fR
|
.SH COMMAND \fI\,'ahriman user\-remove'\/\fR
|
||||||
usage: ahriman user-remove [-h] [-s] username
|
usage: ahriman user\-remove [\-h] [\-s] username
|
||||||
|
|
||||||
remove user from the user mapping and update the configuration
|
remove user from the user mapping and update the configuration
|
||||||
|
|
||||||
@ -602,18 +686,18 @@ remove user from the user mapping and update the configuration
|
|||||||
\fBusername\fR
|
\fBusername\fR
|
||||||
username for web service
|
username for web service
|
||||||
|
|
||||||
.SH OPTIONS \fI\,'ahriman user-remove'\/\fR
|
.SH OPTIONS \fI\,'ahriman user\-remove'\/\fR
|
||||||
.TP
|
.TP
|
||||||
\fB\-s\fR, \fB\-\-secure\fR
|
\fB\-s\fR, \fB\-\-secure\fR
|
||||||
set file permissions to user\-only
|
set file permissions to user\-only
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman version'\/\fR
|
.SH COMMAND \fI\,'ahriman version'\/\fR
|
||||||
usage: ahriman version [-h]
|
usage: ahriman version [\-h]
|
||||||
|
|
||||||
print application and its dependencies versions
|
print application and its dependencies versions
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman web'\/\fR
|
.SH COMMAND \fI\,'ahriman web'\/\fR
|
||||||
usage: ahriman web [-h]
|
usage: ahriman web [\-h]
|
||||||
|
|
||||||
start web server
|
start web server
|
||||||
|
|
||||||
@ -623,7 +707,8 @@ Argument list can also be read from file by using @ prefix.
|
|||||||
.SH AUTHORS
|
.SH AUTHORS
|
||||||
.nf
|
.nf
|
||||||
ahriman team
|
ahriman team
|
||||||
.fi.nf
|
.fi
|
||||||
|
.nf
|
||||||
|
|
||||||
.fi
|
.fi
|
||||||
|
|
||||||
|
@ -28,6 +28,14 @@ ahriman.application.handlers.clean module
|
|||||||
:no-undoc-members:
|
:no-undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
ahriman.application.handlers.daemon module
|
||||||
|
------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.application.handlers.daemon
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
ahriman.application.handlers.dump module
|
ahriman.application.handlers.dump module
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
|
|
||||||
|
@ -28,6 +28,14 @@ ahriman.core.database.migrations.m002\_user\_access module
|
|||||||
:no-undoc-members:
|
:no-undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
ahriman.core.database.migrations.m003\_patch\_variables module
|
||||||
|
--------------------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.database.migrations.m003_patch_variables
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
Module contents
|
Module contents
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
@ -36,6 +36,14 @@ ahriman.core.formatters.package\_printer module
|
|||||||
:no-undoc-members:
|
:no-undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
ahriman.core.formatters.patch\_printer module
|
||||||
|
---------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.formatters.patch_printer
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
ahriman.core.formatters.printer module
|
ahriman.core.formatters.printer module
|
||||||
--------------------------------------
|
--------------------------------------
|
||||||
|
|
||||||
|
45
docs/ahriman.core.gitremote.rst
Normal file
45
docs/ahriman.core.gitremote.rst
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
ahriman.core.gitremote package
|
||||||
|
==============================
|
||||||
|
|
||||||
|
Submodules
|
||||||
|
----------
|
||||||
|
|
||||||
|
ahriman.core.gitremote.remote\_pull module
|
||||||
|
------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.gitremote.remote_pull
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
ahriman.core.gitremote.remote\_pull\_trigger module
|
||||||
|
---------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.gitremote.remote_pull_trigger
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
ahriman.core.gitremote.remote\_push module
|
||||||
|
------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.gitremote.remote_push
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
ahriman.core.gitremote.remote\_push\_trigger module
|
||||||
|
---------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.gitremote.remote_push_trigger
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
Module contents
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.gitremote
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
@ -12,6 +12,7 @@ Subpackages
|
|||||||
ahriman.core.build_tools
|
ahriman.core.build_tools
|
||||||
ahriman.core.database
|
ahriman.core.database
|
||||||
ahriman.core.formatters
|
ahriman.core.formatters
|
||||||
|
ahriman.core.gitremote
|
||||||
ahriman.core.report
|
ahriman.core.report
|
||||||
ahriman.core.repository
|
ahriman.core.repository
|
||||||
ahriman.core.sign
|
ahriman.core.sign
|
||||||
|
@ -35,12 +35,13 @@ This package contains everything which is required for any time of application r
|
|||||||
* ``ahriman.core.build_tools`` is a package which provides wrapper for ``devtools`` commands.
|
* ``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.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.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.load`` method.
|
* ``ahriman.core.gitremote`` is a package with remote PKGBUILD triggers. Should not be called directly.
|
||||||
|
* ``ahriman.core.report`` is a package with reporting triggers. Should not be called directly.
|
||||||
* ``ahriman.core.repository`` contains several traits and base repository (``ahriman.core.repository.Repository`` class) implementation.
|
* ``ahriman.core.repository`` contains several traits and base repository (``ahriman.core.repository.Repository`` class) implementation.
|
||||||
* ``ahriman.core.sign`` package provides sign feature (only gpg calls are available).
|
* ``ahriman.core.sign`` package provides sign feature (only gpg calls are available).
|
||||||
* ``ahriman.core.status`` contains helpers and watcher class which are required for web application. Reporter must be initialized by using ``ahriman.core.status.client.Client.load`` method.
|
* ``ahriman.core.status`` contains helpers and watcher class which are required for web application. Reporter must be initialized by using ``ahriman.core.status.client.Client.load`` method.
|
||||||
* ``ahriman.core.triggers`` package contains base trigger classes. Classes from this package must be imported in order to implement user extensions. In fact, ``ahriman.core.report`` and ``ahriman.core.upload`` use this package.
|
* ``ahriman.core.triggers`` package contains base trigger classes. Classes from this package must be imported in order to implement user extensions. In fact, ``ahriman.core.report`` and ``ahriman.core.upload`` use this package.
|
||||||
* ``ahriman.core.upload`` package provides sync feature, must be called by ``ahriman.core.upload.Upload.load`` method.
|
* ``ahriman.core.upload`` package provides sync feature, should not be called directly.
|
||||||
|
|
||||||
This package also provides some generic functions and classes which may be used by other packages:
|
This package also provides some generic functions and classes which may be used by other packages:
|
||||||
|
|
||||||
@ -103,7 +104,7 @@ Type conversions
|
|||||||
|
|
||||||
By default, it parses rows into python dictionary. In addition, the following pseudo-types are supported:
|
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.
|
* ``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`` data type and ``json.loads`` and ``json.dumps`` methods are used in order to read and write from/to database respectively.
|
||||||
|
|
||||||
Basic flows
|
Basic flows
|
||||||
-----------
|
-----------
|
||||||
@ -202,12 +203,14 @@ In order to configure users there are special commands.
|
|||||||
Triggers
|
Triggers
|
||||||
^^^^^^^^
|
^^^^^^^^
|
||||||
|
|
||||||
Triggers are extensions which can be used in order to perform any actions after the update process. The package provides two default extensions - one is report generation and another one is remote upload feature.
|
Triggers are extensions which can be used in order to perform any actions on application start, after the update process and, finally, before the application exit. The package provides two default extensions - one is report generation and another one is remote upload feature.
|
||||||
|
|
||||||
The main idea is to load classes by their full path (e.g. ``ahriman.core.upload.UploadTrigger``) by using ``importlib``: get the last part of the import and treat it as class name, join remain part by ``.`` and interpret as module path, import module and extract attribute from it.
|
The main idea is to load classes by their full path (e.g. ``ahriman.core.upload.UploadTrigger``) by using ``importlib``: get the last part of the import and treat it as class name, join remain part by ``.`` and interpret as module path, import module and extract attribute from it.
|
||||||
|
|
||||||
The loaded triggers will be called with ``ahriman.models.result.Result`` and ``List[Packages]`` arguments, which describes the process result and current repository packages respectively. Any exception raised will be suppressed and will generate an exception message in logs.
|
The loaded triggers will be called with ``ahriman.models.result.Result`` and ``List[Packages]`` arguments, which describes the process result and current repository packages respectively. Any exception raised will be suppressed and will generate an exception message in logs.
|
||||||
|
|
||||||
|
In addition triggers can implement ``on_start`` and ``on_stop`` actions which will be called on the application start and right before the application exit. The ``on_start`` action is usually being called from handlers directly in order to make sure that no trigger will be run when it is not required (e.g. on user management). As soon as ``on_start`` action is called, the additional flag will be set; ``ahriman.core.triggers.TriggerLoader`` class implements ``__del__`` method in which, if the flag is set, the ``on_stop`` actions will be called.
|
||||||
|
|
||||||
For more details how to deal with the triggers, refer to :doc:`documentation <triggers>` and modules descriptions.
|
For more details how to deal with the triggers, refer to :doc:`documentation <triggers>` and modules descriptions.
|
||||||
|
|
||||||
Remote synchronization
|
Remote synchronization
|
||||||
|
@ -26,9 +26,11 @@ Base configuration settings.
|
|||||||
|
|
||||||
libalpm and AUR related configuration.
|
libalpm and AUR related configuration.
|
||||||
|
|
||||||
* ``database`` - path to pacman local database cache, string, required.
|
* ``database`` - path to pacman system database cache, string, required.
|
||||||
|
* ``mirror`` - package database mirror used by pacman for syncronization, string, required. This option supports standard pacman substitutions with ``$arch`` and ``$repo``. Note that the mentioned mirror should contain all repositories which are set by ``alpm.repositories`` option.
|
||||||
* ``repositories`` - list of pacman repositories, space separated list of strings, required.
|
* ``repositories`` - list of pacman repositories, space separated list of strings, required.
|
||||||
* ``root`` - root for alpm library, string, required.
|
* ``root`` - root for alpm library, string, required.
|
||||||
|
* ``use_ahriman_cache`` - use local pacman package cache instead of system one, boolean, required. With this option enabled you might want to refresh database periodically (available as additional flag for some subcommands).
|
||||||
|
|
||||||
``auth`` group
|
``auth`` group
|
||||||
--------------
|
--------------
|
||||||
@ -75,6 +77,37 @@ Settings for signing packages or repository. Group name can refer to architectur
|
|||||||
* ``key`` - default PGP key, string, required. This key will also be used for database signing if enabled.
|
* ``key`` - default PGP key, string, required. This key will also be used for database signing if enabled.
|
||||||
* ``key_*`` settings - PGP key which will be used for specific packages, string, optional. For example, if there is ``key_yay`` option the specified key will be used for yay package and default key for others.
|
* ``key_*`` settings - PGP key which will be used for specific packages, string, optional. For example, if there is ``key_yay`` option the specified key will be used for yay package and default key for others.
|
||||||
|
|
||||||
|
``remote-pull`` group
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
Remote git source synchronization settings. Unlike ``Upload`` triggers those triggers are used for PKGBUILD synchronization - fetch from remote repository PKGBUILDs before updating process.
|
||||||
|
|
||||||
|
It supports authorization; to do so you'd need to prefix the url with authorization part, e.g. ``https://key:token@github.com/arcan1s/ahriman.git``. It is highly recommended to use application tokens instead of your user authorization details.
|
||||||
|
|
||||||
|
* ``target`` - list of remote pull triggers to be used, space separated list of strings, optional, defaults to ``gitremote``. It must point to valid section (or to section with architecture), e.g. ``gitremote`` must point to either ``gitremote`` or ``gitremote:x86_64`` (the one with architecture has higher priority).
|
||||||
|
|
||||||
|
Remote pull trigger
|
||||||
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
* ``pull_url`` - url of the remote repository from which PKGBUILDs can be pulled before build process, string, required.
|
||||||
|
* ``pull_branch`` - branch of the remote repository from which PKGBUILDs can be pulled before build process, string, optional, default is ``master``.
|
||||||
|
|
||||||
|
``remote-push`` group
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
Remote git source synchronization settings. Same as remote pull triggers those triggers are used for PKGBUILD synchronization - push updated PKGBUILDs to the remote repository after build process.
|
||||||
|
|
||||||
|
It supports authorization; to do so you'd need to prefix the url with authorization part, e.g. ``https://key:token@github.com/arcan1s/ahriman.git``. It is highly recommended to use application tokens instead of your user authorization details.
|
||||||
|
|
||||||
|
* ``target`` - list of remote push triggers to be used, space separated list of strings, optional, defaults to ``gitremote``. It must point to valid section (or to section with architecture), e.g. ``gitremote`` must point to either ``gitremote`` or ``gitremote:x86_64`` (the one with architecture has higher priority).
|
||||||
|
|
||||||
|
Remote push trigger
|
||||||
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
* ``commit_author`` - git commit author, string, optional. In case if not set, the git will generate author for you. Note, however, that in this case it will disclosure your hostname.
|
||||||
|
* ``push_url`` - url of the remote repository to which PKGBUILDs should be pushed after build process, string, required.
|
||||||
|
* ``push_branch`` - branch of the remote repository to which PKGBUILDs should be pushed after build process, string, optional, default is ``master``.
|
||||||
|
|
||||||
``report`` group
|
``report`` group
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
|
203
docs/faq.rst
203
docs/faq.rst
@ -1,16 +1,17 @@
|
|||||||
|
|
||||||
FAQ
|
FAQ
|
||||||
===
|
===
|
||||||
|
|
||||||
General topics
|
General topics
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
What is the purpose of the project?
|
What is the purpose of the project
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
This project has been created in order to maintain self-hosted Arch Linux user repository without manual intervention - checking for updates and building packages.
|
This project has been created in order to maintain self-hosted Arch Linux user repository without manual intervention - checking for updates and building packages.
|
||||||
|
|
||||||
How do I install it?
|
How to install ahriman
|
||||||
^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
TL;DR
|
TL;DR
|
||||||
|
|
||||||
@ -25,8 +26,8 @@ Long answer
|
|||||||
|
|
||||||
The idea is to install the package as usual, create working directory tree, create configuration for ``sudo`` and ``devtools``. Detailed description of the setup instruction can be found :doc:`here <setup>`.
|
The idea is to install the package as usual, create working directory tree, create configuration for ``sudo`` and ``devtools``. Detailed description of the setup instruction can be found :doc:`here <setup>`.
|
||||||
|
|
||||||
What does "architecture specific" mean? / How to configure for different architectures?
|
What does "architecture specific" mean / How to configure for different architectures
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Some sections can be configured per architecture. The service will merge architecture specific values into common settings. In order to specify settings for specific architecture you must point it in section name.
|
Some sections can be configured per architecture. The service will merge architecture specific values into common settings. In order to specify settings for specific architecture you must point it in section name.
|
||||||
|
|
||||||
@ -46,8 +47,8 @@ states that default build command is ``extra-x86_64-build``. But if there is sec
|
|||||||
|
|
||||||
the ``extra-i686-build`` command will be used for ``i686`` architecture.
|
the ``extra-i686-build`` command will be used for ``i686`` architecture.
|
||||||
|
|
||||||
How to use reporter/upload settings?
|
How to generate build reports
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Normally you probably like to generate only one report for the specific type, e.g. only one email report. In order to do it you will need to have the following configuration:
|
Normally you probably like to generate only one report for the specific type, e.g. only one email report. In order to do it you will need to have the following configuration:
|
||||||
|
|
||||||
@ -87,8 +88,8 @@ But for some cases you would like to have multiple different reports with the sa
|
|||||||
type = email
|
type = email
|
||||||
...
|
...
|
||||||
|
|
||||||
Okay, I've installed ahriman, how do I add new package?
|
How do I add new package
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
.. code-block:: shell
|
.. code-block:: shell
|
||||||
|
|
||||||
@ -101,8 +102,8 @@ Okay, I've installed ahriman, how do I add new package?
|
|||||||
sudo -u ahriman ahriman package-add ahriman
|
sudo -u ahriman ahriman package-add ahriman
|
||||||
sudo -u ahriman ahriman repo-update
|
sudo -u ahriman ahriman repo-update
|
||||||
|
|
||||||
AUR is fine, but I would like to create package from local PKGBUILD
|
How to build package from local PKGBUILD
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
TL;DR
|
TL;DR
|
||||||
|
|
||||||
@ -112,19 +113,74 @@ TL;DR
|
|||||||
|
|
||||||
Before using this command you will need to create local directory, put ``PKGBUILD`` there and generate ``.SRCINFO`` by using ``makepkg --printsrcinfo > .SRCINFO`` command. These packages will be stored locally and *will be ignored* during automatic update; in order to update the package you will need to run ``package-add`` command again.
|
Before using this command you will need to create local directory, put ``PKGBUILD`` there and generate ``.SRCINFO`` by using ``makepkg --printsrcinfo > .SRCINFO`` command. These packages will be stored locally and *will be ignored* during automatic update; in order to update the package you will need to run ``package-add`` command again.
|
||||||
|
|
||||||
But I just wanted to change PKGBUILD from AUR a bit!
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
Well it is supported also.
|
How to fetch PKGBUILDs from remote repository
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
For that purpose you could use ``RemotePullTrigger`` trigger. To do so you will need:
|
||||||
|
|
||||||
|
#.
|
||||||
|
Append ``triggers`` option in ``build`` section with the following line:
|
||||||
|
|
||||||
|
.. code-block:: ini
|
||||||
|
|
||||||
|
[build]
|
||||||
|
triggers = ahriman.core.gitremote.RemotePullTrigger
|
||||||
|
|
||||||
|
#.
|
||||||
|
Configure trigger as following:
|
||||||
|
|
||||||
|
.. code-block:: ini
|
||||||
|
|
||||||
|
[remote-pull]
|
||||||
|
target = gitremote
|
||||||
|
|
||||||
|
[gitremote]
|
||||||
|
pull_url = https://github.com/username/repository
|
||||||
|
|
||||||
|
During the next application run it will fetch repository from the specified url and will try to find packages there which can be used as local sources.
|
||||||
|
|
||||||
|
How to push updated PKGBUILDs to remote repository
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
For that purpose you'd need to use another trigger called ``RemotePushTrigger``. Configure it as following:
|
||||||
|
|
||||||
|
#.
|
||||||
|
Append ``triggers`` option in ``build`` section with the trigger name:
|
||||||
|
|
||||||
|
.. code-block:: ini
|
||||||
|
|
||||||
|
[build]
|
||||||
|
triggers = ahriman.core.gitremote.RemotePushTrigger
|
||||||
|
|
||||||
|
#.
|
||||||
|
Configure trigger as following:
|
||||||
|
|
||||||
|
.. code-block:: ini
|
||||||
|
|
||||||
|
[remote-push]
|
||||||
|
target = gitremote
|
||||||
|
|
||||||
|
[gitremote]
|
||||||
|
push_url = https://github.com/username/repository
|
||||||
|
|
||||||
|
Unlike ``RemotePullTrigger`` trigger, the ``RemotePushTrigger`` more likely will require authorization. It is highly recommended to use application tokens for that instead of using your password (e.g. for Github you can generate tokens `here <https://github.com/settings/tokens>`_ with scope ``public_repo``). Authorization can be supplied by using authorization part of the url, e.g. ``https://key:token@github.com/username/repository``.
|
||||||
|
|
||||||
|
How to change PKGBUILDs before build
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Well it is supported also. The recommended way is to patch specific function, e.g. by running ``sudo -u ahriman ahriman patch-add ahriman version``. This command will prompt for new value of the PKGBUILD variable ``version``. You can also write it to file and read from it ``sudo -u ahriman ahriman patch-add ahriman version version.patch``.
|
||||||
|
|
||||||
|
Alternatively you can create full-diff patches, which are calculated by using ``git diff`` from current PKGBUILD master branch:
|
||||||
|
|
||||||
#. Clone sources from AUR.
|
#. Clone sources from AUR.
|
||||||
#. Make changes you would like to (e.g. edit ``PKGBUILD``, add external patches).
|
#. Make changes you would like to (e.g. edit ``PKGBUILD``, add external patches).
|
||||||
#. Run ``sudo -u ahriman ahriman patch-add /path/to/local/directory/with/PKGBUILD``.
|
#. Run ``sudo -u ahriman ahriman patch-set-add /path/to/local/directory/with/PKGBUILD``.
|
||||||
|
|
||||||
The last command will calculate diff from current tree to the ``HEAD`` and will store it locally. Patches will be applied on any package actions (e.g. it can be used for dependency management).
|
The last command will calculate diff from current tree to the ``HEAD`` and will store it locally. Patches will be applied on any package actions (e.g. it can be used for dependency management).
|
||||||
|
|
||||||
Hey, I would like to rebuild the official repository package
|
How to build package from official repository
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
So it is the same as adding any other package, but due to restrictions you must specify source explicitly, e.g.:
|
So it is the same as adding any other package, but due to restrictions you must specify source explicitly, e.g.:
|
||||||
|
|
||||||
@ -143,17 +199,17 @@ TL;DR
|
|||||||
|
|
||||||
sudo -u ahriman ahriman key-import ...
|
sudo -u ahriman ahriman key-import ...
|
||||||
|
|
||||||
How do I check if there are new commits for VCS packages?
|
How to update VCS packages
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Normally the service handles VCS packages correctly, but it requires additional dependencies:
|
Normally the service handles VCS packages correctly, however it requires additional dependencies:
|
||||||
|
|
||||||
.. code-block:: shell
|
.. code-block:: shell
|
||||||
|
|
||||||
pacman -S breezy darcs mercurial subversion
|
pacman -S breezy darcs mercurial subversion
|
||||||
|
|
||||||
I would like to remove package because it is no longer needed/moved to official repositories
|
How to remove package
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
.. code-block:: shell
|
.. code-block:: shell
|
||||||
|
|
||||||
@ -163,8 +219,8 @@ Also, there is command ``repo-remove-unknown`` which checks packages in AUR and
|
|||||||
|
|
||||||
Remove commands also remove any package files (patches, caches etc).
|
Remove commands also remove any package files (patches, caches etc).
|
||||||
|
|
||||||
There is new major release of %library-name%, how do I rebuild packages?
|
How to rebuild packages after library update
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
TL;DR
|
TL;DR
|
||||||
|
|
||||||
@ -176,8 +232,8 @@ You can even rebuild the whole repository (which is particular useful in case if
|
|||||||
|
|
||||||
However, note that you do not need to rebuild repository in case if you just changed signing option, just use ``repo-sign`` command instead.
|
However, note that you do not need to rebuild repository in case if you just changed signing option, just use ``repo-sign`` command instead.
|
||||||
|
|
||||||
Hmm, I have packages built, but how can I use it?
|
How to install built packages
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Add the following lines to your ``pacman.conf``:
|
Add the following lines to your ``pacman.conf``:
|
||||||
|
|
||||||
@ -188,8 +244,8 @@ Add the following lines to your ``pacman.conf``:
|
|||||||
|
|
||||||
(You might need to add ``SigLevel`` option according to the pacman documentation.)
|
(You might need to add ``SigLevel`` option according to the pacman documentation.)
|
||||||
|
|
||||||
I would like to serve the repository
|
How to serve repository
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Easy. For example, nginx configuration (without SSL) will look like:
|
Easy. For example, nginx configuration (without SSL) will look like:
|
||||||
|
|
||||||
@ -226,7 +282,7 @@ Example of the status page configuration is the following (status service is usi
|
|||||||
Docker image
|
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.
|
We provide official images which can be found under ``arcan1s/ahriman`` repository. Docker image is being updated on each commit to master 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.:
|
The default action (in case if no arguments provided) is ``repo-update``. Basically the idea is to run container, e.g.:
|
||||||
|
|
||||||
@ -287,11 +343,22 @@ For every next container run use arguments ``-e AHRIMAN_PORT=8080 --net=host``,
|
|||||||
|
|
||||||
docker run --privileged -e AHRIMAN_PORT=8080 --net=host -v /path/to/local/repo:/var/lib/ahriman arcan1s/ahriman:latest
|
docker run --privileged -e AHRIMAN_PORT=8080 --net=host -v /path/to/local/repo:/var/lib/ahriman arcan1s/ahriman:latest
|
||||||
|
|
||||||
|
Daemon service
|
||||||
|
^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
There is special subcommand which emulates systemd timer and will perform repository update periodically:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
docker run arcan1s/ahriman:latest daemon
|
||||||
|
|
||||||
|
This command uses same rules as ``repo-update``, thus, e.g. requires ``--privileged`` flag.
|
||||||
|
|
||||||
Remote synchronization
|
Remote synchronization
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
Wait I would like to use the repository from another server
|
How to sync repository to another server
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
There are several choices:
|
There are several choices:
|
||||||
|
|
||||||
@ -320,8 +387,8 @@ There are several choices:
|
|||||||
|
|
||||||
After that just add ``/srv/repo`` to the ``pacman.conf`` as usual. You can also upload to S3 (e.g. ``Server = https://s3.eu-central-1.amazonaws.com/repository/x86_64``) or to Github (e.g. ``Server = https://github.com/ahriman/repository/releases/download/x86_64``).
|
After that just add ``/srv/repo`` to the ``pacman.conf`` as usual. You can also upload to S3 (e.g. ``Server = https://s3.eu-central-1.amazonaws.com/repository/x86_64``) or to Github (e.g. ``Server = https://github.com/ahriman/repository/releases/download/x86_64``).
|
||||||
|
|
||||||
How do I configure S3?
|
How to sync to S3
|
||||||
^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
#.
|
#.
|
||||||
Install dependencies:
|
Install dependencies:
|
||||||
@ -379,8 +446,8 @@ How do I configure S3?
|
|||||||
region = eu-central-1
|
region = eu-central-1
|
||||||
secret_key = ...
|
secret_key = ...
|
||||||
|
|
||||||
How do I configure Github?
|
How to sync to Github releases
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
#.
|
#.
|
||||||
Create a repository.
|
Create a repository.
|
||||||
@ -403,8 +470,8 @@ How do I configure Github?
|
|||||||
Reporting
|
Reporting
|
||||||
---------
|
---------
|
||||||
|
|
||||||
I would like to get report to email
|
How to report by email
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
#.
|
#.
|
||||||
Install dependencies:
|
Install dependencies:
|
||||||
@ -430,8 +497,8 @@ I would like to get report to email
|
|||||||
sender = me@example.com
|
sender = me@example.com
|
||||||
user = me@example.com
|
user = me@example.com
|
||||||
|
|
||||||
I'm using synchronization to S3 and would like to generate index page
|
How to generate index page for S3
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
#.
|
#.
|
||||||
Install dependencies:
|
Install dependencies:
|
||||||
@ -454,8 +521,8 @@ I'm using synchronization to S3 and would like to generate index page
|
|||||||
|
|
||||||
After these steps ``index.html`` file will be automatically synced to S3
|
After these steps ``index.html`` file will be automatically synced to S3
|
||||||
|
|
||||||
I would like to get messages to my telegram account/channel
|
How to post build report to telegram
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
#.
|
#.
|
||||||
It still requires additional dependencies:
|
It still requires additional dependencies:
|
||||||
@ -504,8 +571,8 @@ If you did everything fine you should receive the message with the next update.
|
|||||||
Web service
|
Web service
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
Readme mentions web interface, how do I use it?
|
How to setup web service
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
#.
|
#.
|
||||||
Install dependencies:
|
Install dependencies:
|
||||||
@ -525,8 +592,8 @@ Readme mentions web interface, how do I use it?
|
|||||||
#.
|
#.
|
||||||
Start the web service ``systemctl enable --now ahriman-web@x86_64``.
|
Start the web service ``systemctl enable --now ahriman-web@x86_64``.
|
||||||
|
|
||||||
I would like to limit user access to the status page
|
How to enable basic authorization
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
#.
|
#.
|
||||||
Install dependencies 😊:
|
Install dependencies 😊:
|
||||||
@ -557,8 +624,8 @@ I would like to limit user access to the status page
|
|||||||
|
|
||||||
#. Restart web service ``systemctl restart ahriman-web@x86_64``.
|
#. Restart web service ``systemctl restart ahriman-web@x86_64``.
|
||||||
|
|
||||||
I would like to use OAuth
|
How to enable OAuth authorization
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
#.
|
#.
|
||||||
Create OAuth web application, download its ``client_id`` and ``client_secret``.
|
Create OAuth web application, download its ``client_id`` and ``client_secret``.
|
||||||
@ -638,51 +705,55 @@ Other topics
|
|||||||
How does it differ from %another-manager%?
|
How does it differ from %another-manager%?
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Short answer - I do not know.
|
Short answer - I do not know. Also for some references credits to `Alad <https://github.com/AladW>`_, he `did <https://wiki.archlinux.org/title/User:Alad/Local_repo_tools>`_ really good investigation of existing alternatives.
|
||||||
|
|
||||||
|
`arch-repo-manager <https://github.com/Martchus/arch-repo-manager>`_
|
||||||
|
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||||
|
|
||||||
|
Looks actually pretty good, in case if I would find it, I would probably didn't start this project, most of features (like web interface or additional helpers) are already implemented or planned to be. However, this project seems to be at early alpha stage (as for Nov 2022), written in C++ (not pro or con) and misses code documentation.
|
||||||
|
|
||||||
`archrepo2 <https://github.com/lilydjwg/archrepo2>`_
|
`archrepo2 <https://github.com/lilydjwg/archrepo2>`_
|
||||||
""""""""""""""""""""""""""""""""""""""""""""""""""""
|
""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||||
|
|
||||||
Don't know, haven't tried it. But it lacks of documentation at least.
|
Don't know, haven't tried it. But it lacks of documentation at least.
|
||||||
|
|
||||||
* Web interface.
|
* ``ahriman`` has web interface.
|
||||||
* No synchronization and reporting.
|
* ``archrepo2`` doesn't have synchronization and reporting.
|
||||||
* ``archrepo2`` actively uses direct shell calls and ``yaourt`` components.
|
* ``archrepo2`` actively uses direct shell calls and ``yaourt`` components.
|
||||||
* It has constantly running process instead of timer process (it is not pro or con).
|
* ``archrepo2`` has constantly running process instead of timer process (it is not pro or con).
|
||||||
|
|
||||||
`repoctl <https://github.com/cassava/repoctl>`_
|
`repoctl <https://github.com/cassava/repoctl>`_
|
||||||
"""""""""""""""""""""""""""""""""""""""""""""""
|
"""""""""""""""""""""""""""""""""""""""""""""""
|
||||||
|
|
||||||
* Web interface.
|
* ``ahriman`` has web interface.
|
||||||
* No reporting.
|
* ``repoctl`` does not have reporting feature.
|
||||||
* Local packages and patches support.
|
* ``repoctl`` does not support local packages and patches.
|
||||||
* Some actions are not fully automated (e.g. package update still requires manual intervention for the build itself).
|
* Some actions are not fully automated in ``repoctl`` (e.g. package update still requires manual intervention for the build itself).
|
||||||
* ``repoctl`` has better AUR interaction features. With colors!
|
* ``repoctl`` has better AUR interaction features. With colors!
|
||||||
* ``repoctl`` has much easier configuration and even completion.
|
* ``repoctl`` has much easier configuration and even completion.
|
||||||
* ``repoctl`` is able to store old packages.
|
* ``repoctl`` is able to store old packages.
|
||||||
* Ability to host repository from same command vs external services (e.g. nginx) in ``ahriman``.
|
* Ability to host repository from same command in ``repoctl`` vs external services (e.g. nginx) in ``ahriman``.
|
||||||
|
|
||||||
`repo-scripts <https://github.com/arcan1s/repo-scripts>`_
|
`repo-scripts <https://github.com/arcan1s/repo-scripts>`_
|
||||||
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||||
|
|
||||||
Though originally I've created ahriman by trying to improve the project, it still lacks a lot of features:
|
Though originally I've created ahriman by trying to improve the project, it still lacks a lot of features:
|
||||||
|
|
||||||
* Web interface.
|
* ``ahriman`` has web interface.
|
||||||
* Better reporting with template support.
|
* ``ahriman`` has better reporting with template support.
|
||||||
* Synchronization features (there was only ``rsync`` based).
|
* ``ahriman`` has more synchronization features (there was only ``rsync`` based).
|
||||||
* Local packages and patches support.
|
* ``ahriman`` supports local packages and patches.
|
||||||
* No dependency management.
|
* ``repo-scripts`` doesn't have dependency management.
|
||||||
* And so on.
|
|
||||||
|
|
||||||
``repo-scripts`` also have bad architecture and bad quality code and uses out-of-dated ``yaourt`` and ``package-query``.
|
...and so on. ``repo-scripts`` also has bad architecture and bad quality code and uses out-of-dated ``yaourt`` and ``package-query``.
|
||||||
|
|
||||||
`toolbox <https://github.com/chaotic-aur/toolbox>`_
|
`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.
|
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
|
How 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).
|
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).
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ Initial setup
|
|||||||
#.
|
#.
|
||||||
Change settings if required, see :doc:`configuration reference <configuration>` for more details.
|
Change settings if required, see :doc:`configuration reference <configuration>` for more details.
|
||||||
#.
|
#.
|
||||||
TL;DR:
|
Perform initial setup:
|
||||||
|
|
||||||
.. code-block:: shell
|
.. code-block:: shell
|
||||||
|
|
||||||
@ -67,6 +67,8 @@ Initial setup
|
|||||||
echo 'ahriman ALL=(ALL) NOPASSWD: CARCHBUILD_CMD' | tee -a /etc/sudoers.d/ahriman
|
echo 'ahriman ALL=(ALL) NOPASSWD: CARCHBUILD_CMD' | tee -a /etc/sudoers.d/ahriman
|
||||||
chmod 400 /etc/sudoers.d/ahriman
|
chmod 400 /etc/sudoers.d/ahriman
|
||||||
|
|
||||||
|
This command supports several arguments, kindly refer to its help message.
|
||||||
|
|
||||||
#.
|
#.
|
||||||
Start and enable ``ahriman@.timer`` via ``systemctl``:
|
Start and enable ``ahriman@.timer`` via ``systemctl``:
|
||||||
|
|
||||||
|
@ -1,12 +1,45 @@
|
|||||||
Triggers
|
Triggers
|
||||||
========
|
========
|
||||||
|
|
||||||
The package provides ability to write custom extensions which will be run on (the most) actions, e.g. after updates. By default ahriman provides two types of extensions - reporting and files uploading. Each extension must derive from the ``ahriman.core.triggers.Trigger`` class and implement ``run`` method
|
The package provides ability to write custom extensions which will be run on (the most) actions, e.g. after updates. By default ahriman provides three types of extensions - reporting, files uploading and PKGBUILD syncronization. Each extension must derive from the ``ahriman.core.triggers.Trigger`` class and should implement at least one of the abstract methods:
|
||||||
|
|
||||||
|
* ``on_result`` - trigger action which will be called after build process, the build result and the list of repository packages will be supplied as arguments.
|
||||||
|
* ``on_start`` - trigger action which will be called right before the start of the application process.
|
||||||
|
* ``on_stop`` - action which will be called right before the exit.
|
||||||
|
|
||||||
|
Note, it isn't required to implement all of those methods (or even one of them), however, it is highly recommended to avoid trigger actions in ``__init__`` method as it will be run on any application start (e.g. even if you are just searching in AUR).
|
||||||
|
|
||||||
|
Built-in triggers
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
For the configuration details and settings explanation kindly refer to the :doc:`documentation <configuration>`.
|
||||||
|
|
||||||
|
``ahriman.core.gitremote.RemotePullTrigger``
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
This trigger will be called before any action (``on_start``) and pulls remote PKGBUILD repository locally; after that it copies found PKGBUILDs from the cloned repository to the local cache. It is useful in case if you have patched PGKBUILDs (or even missing in AUR) which you would like to use for package building and, technically, just simplifies the local package building.
|
||||||
|
|
||||||
|
In order to update those packages you would need to clone your repository separately, make changes in PKGBUILD (e.g. bump version and update checksums), commit them and push back. On the next ahriman's repository update, it will pull changes you commited and will perform package update.
|
||||||
|
|
||||||
|
``ahriman.core.gitremote.RemotePushTrigger``
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
This trigger will be called right after build process (``on_result``). It will pick PKGBUILDs for the updated packages, pull them (together with any other files) and commit and push changes to remote repository. No real use cases, but the most of user repositories do it.
|
||||||
|
|
||||||
|
``ahriman.core.report.ReportTrigger``
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Trigger which can be used for reporting. It implements ``on_result`` method and thus being called on each build update and generates report (e.g. html, telegram etc) according to the current settings.
|
||||||
|
|
||||||
|
``ahriman.core.upload.UploadTrigger``
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
This trigger takes build result (``on_result``) and performs syncing of the local packages to the remote mirror (e.g. S3 or just by rsync).
|
||||||
|
|
||||||
Trigger example
|
Trigger example
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
Lets consider example of reporting trigger (e.g. `slack <https://slack.com/>`_, which provides easy HTTP API for integration triggers).
|
Lets consider example of reporting trigger (e.g. `slack <https://slack.com/>`_, which provides easy HTTP API for integration triggers).gre
|
||||||
|
|
||||||
In order to post message to slack we will need a specific trigger url (something like ``https://hooks.slack.com/services/company_id/trigger_id``), channel (e.g. ``#archrepo``) and username (``repo-bot``).
|
In order to post message to slack we will need a specific trigger url (something like ``https://hooks.slack.com/services/company_id/trigger_id``), channel (e.g. ``#archrepo``) and username (``repo-bot``).
|
||||||
|
|
||||||
@ -49,12 +82,12 @@ Obviously you can implement the specified method in class, but for guide purpose
|
|||||||
self.channel = configuration.get("slack", "channel")
|
self.channel = configuration.get("slack", "channel")
|
||||||
self.username = configuration.get("slack", "username")
|
self.username = configuration.get("slack", "username")
|
||||||
|
|
||||||
def run(self, result, packages):
|
def on_result(self, result, packages):
|
||||||
notify(result, self.slack_url, self.channel, self.username)
|
notify(result, self.slack_url, self.channel, self.username)
|
||||||
|
|
||||||
Setup the trigger
|
Setup the trigger
|
||||||
-----------------
|
^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
First, put the trigger in any path it can be exported, e.g. by packing the resource into python package (which will lead to import path as ``package.slack_reporter.SlackReporter``) or just put file somewhere it can be accessed by application (e.g. ``/usr/local/lib/slack_reporter.py.SlackReporter``.
|
First, put the trigger in any path it can be exported, e.g. by packing the resource into python package (which will lead to import path as ``package.slack_reporter.SlackReporter``) or just put file somewhere it can be accessed by application (e.g. ``/usr/local/lib/slack_reporter.py.SlackReporter``).
|
||||||
|
|
||||||
After that run application as usual and receive notification in your slack channel.
|
After that run application as usual and receive notification in your slack channel.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# Maintainer: Evgeniy Alekseev
|
# Maintainer: Evgeniy Alekseev
|
||||||
|
|
||||||
pkgname='ahriman'
|
pkgname='ahriman'
|
||||||
pkgver=2.2.2
|
pkgver=2.3.0
|
||||||
pkgrel=1
|
pkgrel=1
|
||||||
pkgdesc="ArcH linux ReposItory MANager"
|
pkgdesc="ArcH linux ReposItory MANager"
|
||||||
arch=('any')
|
arch=('any')
|
||||||
|
@ -2,6 +2,6 @@
|
|||||||
Description=ArcH linux ReposItory MANager (%I architecture)
|
Description=ArcH linux ReposItory MANager (%I architecture)
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
ExecStart=/usr/bin/ahriman --architecture %i update
|
ExecStart=/usr/bin/ahriman --architecture %i repo-update --refresh
|
||||||
User=ahriman
|
User=ahriman
|
||||||
Group=ahriman
|
Group=ahriman
|
@ -5,8 +5,10 @@ database = /var/lib/ahriman/ahriman.db
|
|||||||
|
|
||||||
[alpm]
|
[alpm]
|
||||||
database = /var/lib/pacman
|
database = /var/lib/pacman
|
||||||
|
mirror = https://geo.mirror.pkgbuild.com/$repo/os/$arch
|
||||||
repositories = core extra community multilib
|
repositories = core extra community multilib
|
||||||
root = /
|
root = /
|
||||||
|
use_ahriman_cache = yes
|
||||||
|
|
||||||
[auth]
|
[auth]
|
||||||
target = disabled
|
target = disabled
|
||||||
|
@ -20,11 +20,11 @@ formatter = syslog_format
|
|||||||
args = ("/dev/log",)
|
args = ("/dev/log",)
|
||||||
|
|
||||||
[formatter_generic_format]
|
[formatter_generic_format]
|
||||||
format = [%(levelname)s %(asctime)s] [%(threadName)s] [%(name)s]: %(message)s
|
format = [%(levelname)s %(asctime)s] [%(name)s]: %(message)s
|
||||||
datefmt =
|
datefmt =
|
||||||
|
|
||||||
[formatter_syslog_format]
|
[formatter_syslog_format]
|
||||||
format = [%(levelname)s] [%(threadName)s] [%(name)s]: %(message)s
|
format = [%(levelname)s] [%(name)s]: %(message)s
|
||||||
datefmt =
|
datefmt =
|
||||||
|
|
||||||
[logger_root]
|
[logger_root]
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
<button id="add-btn" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#add-form" hidden>
|
<button id="add-btn" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#add-form" hidden>
|
||||||
<i class="bi bi-plus"></i> add
|
<i class="bi bi-plus"></i> add
|
||||||
</button>
|
</button>
|
||||||
<button id="update-btn" class="btn btn-secondary" onclick="updatePackages()" disabled hidden>
|
<button id="update-btn" class="btn btn-secondary" onclick="updatePackages()" hidden>
|
||||||
<i class="bi bi-play"></i> update
|
<i class="bi bi-play"></i> update
|
||||||
</button>
|
</button>
|
||||||
<button id="remove-btn" class="btn btn-danger" onclick="removePackages()" disabled hidden>
|
<button id="remove-btn" class="btn btn-danger" onclick="removePackages()" disabled hidden>
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
table.on("check.bs.table uncheck.bs.table check-all.bs.table uncheck-all.bs.table",
|
table.on("check.bs.table uncheck.bs.table check-all.bs.table uncheck-all.bs.table",
|
||||||
() => {
|
() => {
|
||||||
removeButton.prop("disabled", !table.bootstrapTable("getSelections").length);
|
removeButton.prop("disabled", !table.bootstrapTable("getSelections").length);
|
||||||
updateButton.prop("disabled", !table.bootstrapTable("getSelections").length);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const architectureBadge = $("#badge-architecture");
|
const architectureBadge = $("#badge-architecture");
|
||||||
@ -16,8 +15,6 @@
|
|||||||
const versionBadge = $("#badge-version");
|
const versionBadge = $("#badge-version");
|
||||||
|
|
||||||
function doPackageAction(uri, packages) {
|
function doPackageAction(uri, packages) {
|
||||||
if (packages.length === 0)
|
|
||||||
return;
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: uri,
|
url: uri,
|
||||||
data: JSON.stringify({packages: packages}),
|
data: JSON.stringify({packages: packages}),
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
|
# pylint: disable=too-many-lines
|
||||||
import argparse
|
import argparse
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
@ -73,7 +74,8 @@ def _parser() -> argparse.ArgumentParser:
|
|||||||
parser.add_argument("--force", help="force run, remove file lock", action="store_true")
|
parser.add_argument("--force", help="force run, remove file lock", action="store_true")
|
||||||
parser.add_argument("-l", "--lock", help="lock file", type=Path,
|
parser.add_argument("-l", "--lock", help="lock file", type=Path,
|
||||||
default=Path(tempfile.gettempdir()) / "ahriman.lock")
|
default=Path(tempfile.gettempdir()) / "ahriman.lock")
|
||||||
parser.add_argument("--no-report", help="force disable reporting to web service", action="store_true")
|
parser.add_argument("--report", help="force enable or disable reporting to web service",
|
||||||
|
action=argparse.BooleanOptionalAction, default=True)
|
||||||
parser.add_argument("-q", "--quiet", help="force disable any logging", action="store_true")
|
parser.add_argument("-q", "--quiet", help="force disable any logging", action="store_true")
|
||||||
parser.add_argument("--unsafe", help="allow to run ahriman as non-ahriman user. Some actions might be unavailable",
|
parser.add_argument("--unsafe", help="allow to run ahriman as non-ahriman user. Some actions might be unavailable",
|
||||||
action="store_true")
|
action="store_true")
|
||||||
@ -82,6 +84,7 @@ def _parser() -> argparse.ArgumentParser:
|
|||||||
subparsers = parser.add_subparsers(title="command", help="command to run", dest="command", required=True)
|
subparsers = parser.add_subparsers(title="command", help="command to run", dest="command", required=True)
|
||||||
|
|
||||||
_set_aur_search_parser(subparsers)
|
_set_aur_search_parser(subparsers)
|
||||||
|
_set_daemon_parser(subparsers)
|
||||||
_set_help_parser(subparsers)
|
_set_help_parser(subparsers)
|
||||||
_set_help_commands_unsafe_parser(subparsers)
|
_set_help_commands_unsafe_parser(subparsers)
|
||||||
_set_key_import_parser(subparsers)
|
_set_key_import_parser(subparsers)
|
||||||
@ -93,6 +96,7 @@ def _parser() -> argparse.ArgumentParser:
|
|||||||
_set_patch_add_parser(subparsers)
|
_set_patch_add_parser(subparsers)
|
||||||
_set_patch_list_parser(subparsers)
|
_set_patch_list_parser(subparsers)
|
||||||
_set_patch_remove_parser(subparsers)
|
_set_patch_remove_parser(subparsers)
|
||||||
|
_set_patch_set_add_parser(subparsers)
|
||||||
_set_repo_backup_parser(subparsers)
|
_set_repo_backup_parser(subparsers)
|
||||||
_set_repo_check_parser(subparsers)
|
_set_repo_check_parser(subparsers)
|
||||||
_set_repo_clean_parser(subparsers)
|
_set_repo_clean_parser(subparsers)
|
||||||
@ -129,14 +133,44 @@ def _set_aur_search_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
"""
|
"""
|
||||||
parser = root.add_parser("aur-search", aliases=["search"], help="search for package",
|
parser = root.add_parser("aur-search", aliases=["search"], help="search for package",
|
||||||
description="search for package in AUR using API", formatter_class=_formatter)
|
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",
|
parser.add_argument("search", help="search terms, can be specified multiple times, the result will match all terms",
|
||||||
nargs="+")
|
nargs="+")
|
||||||
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
|
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
|
||||||
parser.add_argument("-i", "--info", help="show additional package information", action="store_true")
|
parser.add_argument("--info", help="show additional package information",
|
||||||
|
action=argparse.BooleanOptionalAction, default=False)
|
||||||
parser.add_argument("--sort-by", help="sort field by this field. In case if two packages have the same value of "
|
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",
|
"the specified field, they will be always sorted by name",
|
||||||
default="name", choices=sorted(handlers.Search.SORT_FIELDS))
|
default="name", choices=sorted(handlers.Search.SORT_FIELDS))
|
||||||
parser.set_defaults(handler=handlers.Search, architecture=[""], lock=None, no_report=True, quiet=True, unsafe=True)
|
parser.set_defaults(handler=handlers.Search, architecture=[""], lock=None, report=False, quiet=True, unsafe=True)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
def _set_daemon_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
|
"""
|
||||||
|
add parser for daemon subcommand
|
||||||
|
|
||||||
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
|
"""
|
||||||
|
parser = root.add_parser("daemon", help="run application as daemon",
|
||||||
|
description="start process which periodically will run update process",
|
||||||
|
formatter_class=_formatter)
|
||||||
|
parser.add_argument("-i", "--interval", help="interval between runs in seconds", type=int, default=60 * 60 * 12)
|
||||||
|
parser.add_argument("--aur", help="enable or disable checking for AUR updates. Implies --no-vcs",
|
||||||
|
action=argparse.BooleanOptionalAction, default=True)
|
||||||
|
parser.add_argument("--local", help="enable or disable checking of local packages for updates",
|
||||||
|
action=argparse.BooleanOptionalAction, default=True)
|
||||||
|
parser.add_argument("--manual", help="include or exclude manual updates",
|
||||||
|
action=argparse.BooleanOptionalAction, default=True)
|
||||||
|
parser.add_argument("--vcs", help="enable or disable checking of VCS packages",
|
||||||
|
action=argparse.BooleanOptionalAction, default=True)
|
||||||
|
parser.add_argument("-y", "--refresh", help="download fresh package databases from the mirror before actions, "
|
||||||
|
"-yy to force refresh even if up to date",
|
||||||
|
action="count", default=0)
|
||||||
|
parser.set_defaults(handler=handlers.Daemon, dry_run=False, exit_code=False, package=[])
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
@ -154,7 +188,7 @@ def _set_help_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
description="show help message for application or command and exit",
|
description="show help message for application or command and exit",
|
||||||
formatter_class=_formatter)
|
formatter_class=_formatter)
|
||||||
parser.add_argument("command", help="show help message for specific command", nargs="?")
|
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,
|
parser.set_defaults(handler=handlers.Help, architecture=[""], lock=None, report=False, quiet=True,
|
||||||
unsafe=True, parser=_parser)
|
unsafe=True, parser=_parser)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
@ -173,7 +207,7 @@ def _set_help_commands_unsafe_parser(root: SubParserAction) -> argparse.Argument
|
|||||||
description="list unsafe commands as defined in default args", formatter_class=_formatter)
|
description="list unsafe commands as defined in default args", formatter_class=_formatter)
|
||||||
parser.add_argument("--command", help="instead of showing commands, just test command line for unsafe subcommand "
|
parser.add_argument("--command", help="instead of showing commands, just test command line for unsafe subcommand "
|
||||||
"and return 0 in case if command is safe and 1 otherwise")
|
"and return 0 in case if command is safe and 1 otherwise")
|
||||||
parser.set_defaults(handler=handlers.UnsafeCommands, architecture=[""], lock=None, no_report=True, quiet=True,
|
parser.set_defaults(handler=handlers.UnsafeCommands, architecture=[""], lock=None, report=False, quiet=True,
|
||||||
unsafe=True, parser=_parser)
|
unsafe=True, parser=_parser)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
@ -197,7 +231,7 @@ def _set_key_import_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
formatter_class=_formatter)
|
formatter_class=_formatter)
|
||||||
parser.add_argument("--key-server", help="key server for key import", default="pgp.mit.edu")
|
parser.add_argument("--key-server", help="key server for key import", default="pgp.mit.edu")
|
||||||
parser.add_argument("key", help="PGP key to import from public server")
|
parser.add_argument("key", help="PGP key to import from public server")
|
||||||
parser.set_defaults(handler=handlers.KeyImport, architecture=[""], lock=None, no_report=True)
|
parser.set_defaults(handler=handlers.KeyImport, architecture=[""], lock=None, report=False)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
@ -227,6 +261,9 @@ def _set_package_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
parser.add_argument("package", help="package source (base name, path to local files, remote URL)", nargs="+")
|
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("-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("-n", "--now", help="run update function after", action="store_true")
|
||||||
|
parser.add_argument("-y", "--refresh", help="download fresh package databases from the mirror before actions, "
|
||||||
|
"-yy to force refresh even if up to date",
|
||||||
|
action="count", default=0)
|
||||||
parser.add_argument("-s", "--source", help="explicitly specify the package source for this command",
|
parser.add_argument("-s", "--source", help="explicitly specify the package source for this command",
|
||||||
type=PackageSource, choices=enum_values(PackageSource), default=PackageSource.Auto)
|
type=PackageSource, choices=enum_values(PackageSource), default=PackageSource.Auto)
|
||||||
parser.add_argument("--without-dependencies", help="do not add dependencies", action="store_true")
|
parser.add_argument("--without-dependencies", help="do not add dependencies", action="store_true")
|
||||||
@ -271,7 +308,7 @@ def _set_package_status_parser(root: SubParserAction) -> argparse.ArgumentParser
|
|||||||
parser.add_argument("-i", "--info", help="show additional package information", 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",
|
parser.add_argument("-s", "--status", help="filter packages by status",
|
||||||
type=BuildStatusEnum, choices=enum_values(BuildStatusEnum))
|
type=BuildStatusEnum, choices=enum_values(BuildStatusEnum))
|
||||||
parser.set_defaults(handler=handlers.Status, lock=None, no_report=True, quiet=True, unsafe=True)
|
parser.set_defaults(handler=handlers.Status, lock=None, report=False, quiet=True, unsafe=True)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
@ -290,8 +327,8 @@ def _set_package_status_remove_parser(root: SubParserAction) -> argparse.Argumen
|
|||||||
epilog="Please note that this subcommand does not remove the package itself, it just "
|
epilog="Please note that this subcommand does not remove the package itself, it just "
|
||||||
"clears the status page.",
|
"clears the status page.",
|
||||||
formatter_class=_formatter)
|
formatter_class=_formatter)
|
||||||
parser.add_argument("package", help="remove specified packages", nargs="+")
|
parser.add_argument("package", help="remove specified packages from status page", nargs="+")
|
||||||
parser.set_defaults(handler=handlers.StatusUpdate, action=Action.Remove, lock=None, no_report=True, quiet=True,
|
parser.set_defaults(handler=handlers.StatusUpdate, action=Action.Remove, lock=None, report=False, quiet=True,
|
||||||
unsafe=True)
|
unsafe=True)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
@ -311,16 +348,16 @@ def _set_package_status_update_parser(root: SubParserAction) -> argparse.Argumen
|
|||||||
parser.add_argument("package", help="set status for specified packages. "
|
parser.add_argument("package", help="set status for specified packages. "
|
||||||
"If no packages supplied, service status will be updated",
|
"If no packages supplied, service status will be updated",
|
||||||
nargs="*")
|
nargs="*")
|
||||||
parser.add_argument("-s", "--status", help="new status",
|
parser.add_argument("-s", "--status", help="new package build status",
|
||||||
type=BuildStatusEnum, choices=enum_values(BuildStatusEnum), default=BuildStatusEnum.Success)
|
type=BuildStatusEnum, choices=enum_values(BuildStatusEnum), default=BuildStatusEnum.Success)
|
||||||
parser.set_defaults(handler=handlers.StatusUpdate, action=Action.Update, lock=None, no_report=True, quiet=True,
|
parser.set_defaults(handler=handlers.StatusUpdate, action=Action.Update, lock=None, report=False, quiet=True,
|
||||||
unsafe=True)
|
unsafe=True)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
def _set_patch_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
def _set_patch_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
"""
|
"""
|
||||||
add parser for new patch subcommand
|
add parser for new single-function patch subcommand
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
root(SubParserAction): subparsers for the commands
|
root(SubParserAction): subparsers for the commands
|
||||||
@ -328,17 +365,19 @@ def _set_patch_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
Returns:
|
Returns:
|
||||||
argparse.ArgumentParser: created argument parser
|
argparse.ArgumentParser: created argument parser
|
||||||
"""
|
"""
|
||||||
parser = root.add_parser("patch-add", help="add patch set", description="create or update source patches",
|
parser = root.add_parser("patch-add", help="add patch for PKGBUILD function",
|
||||||
epilog="In order to add a patch set for the package you will need to clone "
|
description="create or update patched PKGBUILD function or variable",
|
||||||
"the AUR package manually, add required changes (e.g. external patches, "
|
epilog="Unlike ``patch-set-add``, this function allows to patch only one PKGBUILD "
|
||||||
"edit PKGBUILD) and run command, e.g. ``ahriman patch path/to/directory``. "
|
"function, e.g. typing ``ahriman patch-add ahriman pkgver`` it will change the "
|
||||||
"By default it tracks *.patch and *.diff files, but this behavior can be changed "
|
"``pkgver`` inside PKGBUILD, typing ``ahriman patch-add ahriman build()`` "
|
||||||
"by using --track option",
|
"it will change ``build()`` function inside PKGBUILD",
|
||||||
formatter_class=_formatter)
|
formatter_class=_formatter)
|
||||||
parser.add_argument("package", help="path to directory with changed files for patch addition/update")
|
parser.add_argument("package", help="package base")
|
||||||
parser.add_argument("-t", "--track", help="files which has to be tracked", action="append",
|
parser.add_argument("variable", help="PKGBUILD variable or function name. If variable is a function, "
|
||||||
default=["*.diff", "*.patch"])
|
"it must end with ()")
|
||||||
parser.set_defaults(handler=handlers.Patch, action=Action.Update, architecture=[""], lock=None, no_report=True)
|
parser.add_argument("patch", help="path to file which contains function or variable value. If not set, "
|
||||||
|
"the value will be read from stdin", type=Path, nargs="?")
|
||||||
|
parser.set_defaults(handler=handlers.Patch, action=Action.Update, architecture=[""], lock=None, report=False)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
@ -356,7 +395,9 @@ def _set_patch_list_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
description="list available patches for the package", formatter_class=_formatter)
|
description="list available patches for the package", formatter_class=_formatter)
|
||||||
parser.add_argument("package", help="package base", nargs="?")
|
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.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)
|
parser.add_argument("-v", "--variable", help="if set, show only patches for specified PKGBUILD variables",
|
||||||
|
action="append")
|
||||||
|
parser.set_defaults(handler=handlers.Patch, action=Action.List, architecture=[""], lock=None, report=False)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
@ -373,7 +414,36 @@ def _set_patch_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
parser = root.add_parser("patch-remove", help="remove patch set", description="remove patches for the package",
|
parser = root.add_parser("patch-remove", help="remove patch set", description="remove patches for the package",
|
||||||
formatter_class=_formatter)
|
formatter_class=_formatter)
|
||||||
parser.add_argument("package", help="package base")
|
parser.add_argument("package", help="package base")
|
||||||
parser.set_defaults(handler=handlers.Patch, action=Action.Remove, architecture=[""], lock=None, no_report=True)
|
parser.add_argument("-v", "--variable", help="should be used for single-function patches in case if you wold like "
|
||||||
|
"to remove only specified PKGBUILD variables. In case if not set, "
|
||||||
|
"it will remove all patches related to the package",
|
||||||
|
action="append")
|
||||||
|
parser.set_defaults(handler=handlers.Patch, action=Action.Remove, architecture=[""], lock=None, report=False)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
def _set_patch_set_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
|
"""
|
||||||
|
add parser for new full-diff patch subcommand
|
||||||
|
|
||||||
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
|
"""
|
||||||
|
parser = root.add_parser("patch-set-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 "
|
||||||
|
"the AUR package manually, add required changes (e.g. external patches, "
|
||||||
|
"edit PKGBUILD) and run command, e.g. ``ahriman patch-set-add path/to/directory``. "
|
||||||
|
"By default it tracks *.patch and *.diff files, but this behavior can be changed "
|
||||||
|
"by using --track option",
|
||||||
|
formatter_class=_formatter)
|
||||||
|
parser.add_argument("package", help="path to directory with changed files for patch addition/update", type=Path)
|
||||||
|
parser.add_argument("-t", "--track", help="files which has to be tracked", action="append",
|
||||||
|
default=["*.diff", "*.patch"])
|
||||||
|
parser.set_defaults(handler=handlers.Patch, action=Action.Update, architecture=[""], lock=None, report=False,
|
||||||
|
variable=None)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
@ -388,9 +458,9 @@ def _set_repo_backup_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
argparse.ArgumentParser: created argument parser
|
argparse.ArgumentParser: created argument parser
|
||||||
"""
|
"""
|
||||||
parser = root.add_parser("repo-backup", help="backup repository data",
|
parser = root.add_parser("repo-backup", help="backup repository data",
|
||||||
description="backup settings and database", formatter_class=_formatter)
|
description="backup repository settings and database", formatter_class=_formatter)
|
||||||
parser.add_argument("path", help="path of the output archive", type=Path)
|
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)
|
parser.set_defaults(handler=handlers.Backup, architecture=[""], lock=None, report=False, unsafe=True)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
@ -405,12 +475,16 @@ def _set_repo_check_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
argparse.ArgumentParser: created argument parser
|
argparse.ArgumentParser: created argument parser
|
||||||
"""
|
"""
|
||||||
parser = root.add_parser("repo-check", aliases=["check"], help="check for updates",
|
parser = root.add_parser("repo-check", aliases=["check"], help="check for updates",
|
||||||
description="check for packages updates. Same as update --dry-run --no-manual",
|
description="check for packages updates. Same as repo-update --dry-run --no-manual",
|
||||||
formatter_class=_formatter)
|
formatter_class=_formatter)
|
||||||
parser.add_argument("package", help="filter check by package base", nargs="*")
|
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("-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.add_argument("--vcs", help="enable or disable checking of VCS packages",
|
||||||
parser.set_defaults(handler=handlers.Update, dry_run=True, no_aur=False, no_local=False, no_manual=True)
|
action=argparse.BooleanOptionalAction, default=True)
|
||||||
|
parser.add_argument("-y", "--refresh", help="download fresh package databases from the mirror before actions, "
|
||||||
|
"-yy to force refresh even if up to date",
|
||||||
|
action="count", default=0)
|
||||||
|
parser.set_defaults(handler=handlers.Update, dry_run=True, aur=True, local=True, manual=False)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
@ -430,10 +504,15 @@ 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 "
|
"you should not run this command manually. Also in case if you are going to clear "
|
||||||
"the chroot directories you will need root privileges.",
|
"the chroot directories you will need root privileges.",
|
||||||
formatter_class=_formatter)
|
formatter_class=_formatter)
|
||||||
parser.add_argument("--cache", help="clear directory with package caches", action="store_true")
|
parser.add_argument("--cache", help="clear directory with package caches",
|
||||||
parser.add_argument("--chroot", help="clear build chroot", action="store_true")
|
action=argparse.BooleanOptionalAction, default=False)
|
||||||
parser.add_argument("--manual", help="clear manually added packages queue", action="store_true")
|
parser.add_argument("--chroot", help="clear build chroot", action=argparse.BooleanOptionalAction, default=False)
|
||||||
parser.add_argument("--packages", help="clear directory with built packages", action="store_true")
|
parser.add_argument("--manual", help="clear manually added packages queue",
|
||||||
|
action=argparse.BooleanOptionalAction, default=False)
|
||||||
|
parser.add_argument("--packages", help="clear directory with built packages",
|
||||||
|
action=argparse.BooleanOptionalAction, default=False)
|
||||||
|
parser.add_argument("--pacman", help="clear directory with pacman local database cache",
|
||||||
|
action=argparse.BooleanOptionalAction, default=False)
|
||||||
parser.set_defaults(handler=handlers.Clean, quiet=True, unsafe=True)
|
parser.set_defaults(handler=handlers.Clean, quiet=True, unsafe=True)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
@ -451,7 +530,7 @@ def _set_repo_config_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
parser = root.add_parser("repo-config", aliases=["config"], help="dump configuration",
|
parser = root.add_parser("repo-config", aliases=["config"], help="dump configuration",
|
||||||
description="dump configuration for the specified architecture",
|
description="dump configuration for the specified architecture",
|
||||||
formatter_class=_formatter)
|
formatter_class=_formatter)
|
||||||
parser.set_defaults(handler=handlers.Dump, lock=None, no_report=True, quiet=True, unsafe=True)
|
parser.set_defaults(handler=handlers.Dump, lock=None, report=False, quiet=True, unsafe=True)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
@ -467,13 +546,13 @@ def _set_repo_rebuild_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
"""
|
"""
|
||||||
parser = root.add_parser("repo-rebuild", aliases=["rebuild"], help="rebuild repository",
|
parser = root.add_parser("repo-rebuild", aliases=["rebuild"], help="rebuild repository",
|
||||||
description="force rebuild whole repository", formatter_class=_formatter)
|
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("--depends-on", help="only rebuild packages that depend on specified packages", action="append")
|
||||||
parser.add_argument("--dry-run", help="just perform check for packages without rebuild process itself",
|
parser.add_argument("--dry-run", help="just perform check for packages without rebuild process itself",
|
||||||
action="store_true")
|
action="store_true")
|
||||||
parser.add_argument("--from-database",
|
parser.add_argument("--from-database",
|
||||||
help="read packages from database instead of filesystem. This feature in particular is "
|
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 "
|
"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 "
|
"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.",
|
"ahriman instance run with web service and have run repo-update at least once.",
|
||||||
action="store_true")
|
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("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
|
||||||
@ -495,7 +574,6 @@ def _set_repo_remove_unknown_parser(root: SubParserAction) -> argparse.ArgumentP
|
|||||||
description="remove packages which are missing in AUR and do not have local PKGBUILDs",
|
description="remove packages which are missing in AUR and do not have local PKGBUILDs",
|
||||||
formatter_class=_formatter)
|
formatter_class=_formatter)
|
||||||
parser.add_argument("--dry-run", help="just perform check for packages without removal", action="store_true")
|
parser.add_argument("--dry-run", help="just perform check for packages without removal", action="store_true")
|
||||||
parser.add_argument("-i", "--info", help="show additional package information", action="store_true")
|
|
||||||
parser.set_defaults(handler=handlers.RemoveUnknown)
|
parser.set_defaults(handler=handlers.RemoveUnknown)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
@ -532,7 +610,7 @@ def _set_repo_restore_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
description="restore settings and database", formatter_class=_formatter)
|
description="restore settings and database", formatter_class=_formatter)
|
||||||
parser.add_argument("path", help="path of the input archive", type=Path)
|
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.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)
|
parser.set_defaults(handler=handlers.Restore, architecture=[""], lock=None, report=False, unsafe=True)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
@ -554,14 +632,15 @@ def _set_repo_setup_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
parser.add_argument("--build-command", help="build command prefix", default="ahriman")
|
parser.add_argument("--build-command", help="build command prefix", default="ahriman")
|
||||||
parser.add_argument("--from-configuration", help="path to default devtools pacman configuration",
|
parser.add_argument("--from-configuration", help="path to default devtools pacman configuration",
|
||||||
type=Path, default=Path("/usr/share/devtools/pacman-extra.conf"))
|
type=Path, default=Path("/usr/share/devtools/pacman-extra.conf"))
|
||||||
parser.add_argument("--no-multilib", help="do not add multilib repository", action="store_true")
|
parser.add_argument("--multilib", help="add or do not multilib repository",
|
||||||
|
action=argparse.BooleanOptionalAction, default=True)
|
||||||
parser.add_argument("--packager", help="packager name and email", required=True)
|
parser.add_argument("--packager", help="packager name and email", required=True)
|
||||||
parser.add_argument("--repository", help="repository name", required=True)
|
parser.add_argument("--repository", help="repository name", required=True)
|
||||||
parser.add_argument("--sign-key", help="sign key id")
|
parser.add_argument("--sign-key", help="sign key id")
|
||||||
parser.add_argument("--sign-target", help="sign options", action="append",
|
parser.add_argument("--sign-target", help="sign options", action="append",
|
||||||
type=SignSettings.from_option, choices=enum_values(SignSettings))
|
type=SignSettings.from_option, choices=enum_values(SignSettings))
|
||||||
parser.add_argument("--web-port", help="port of the web service", type=int)
|
parser.add_argument("--web-port", help="port of the web service", type=int)
|
||||||
parser.set_defaults(handler=handlers.Setup, lock=None, no_report=True, quiet=True, unsafe=True)
|
parser.set_defaults(handler=handlers.Setup, lock=None, report=False, quiet=True, unsafe=True)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
@ -598,7 +677,7 @@ def _set_repo_status_update_parser(root: SubParserAction) -> argparse.ArgumentPa
|
|||||||
description="update repository status on the status page", formatter_class=_formatter)
|
description="update repository status on the status page", formatter_class=_formatter)
|
||||||
parser.add_argument("-s", "--status", help="new status",
|
parser.add_argument("-s", "--status", help="new status",
|
||||||
type=BuildStatusEnum, choices=enum_values(BuildStatusEnum), default=BuildStatusEnum.Success)
|
type=BuildStatusEnum, choices=enum_values(BuildStatusEnum), default=BuildStatusEnum.Success)
|
||||||
parser.set_defaults(handler=handlers.StatusUpdate, action=Action.Update, lock=None, no_report=True, package=[],
|
parser.set_defaults(handler=handlers.StatusUpdate, action=Action.Update, lock=None, report=False, package=[],
|
||||||
quiet=True, unsafe=True)
|
quiet=True, unsafe=True)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
@ -656,10 +735,17 @@ def _set_repo_update_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
parser.add_argument("package", help="filter check by package base", nargs="*")
|
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("--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("-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("--aur", help="enable or disable checking for AUR updates. Implies --no-vcs",
|
||||||
parser.add_argument("--no-local", help="do not check local packages for updates", action="store_true")
|
action=argparse.BooleanOptionalAction, default=True)
|
||||||
parser.add_argument("--no-manual", help="do not include manual updates", action="store_true")
|
parser.add_argument("--local", help="enable or disable checking of local packages for updates",
|
||||||
parser.add_argument("--no-vcs", help="do not check VCS packages", action="store_true")
|
action=argparse.BooleanOptionalAction, default=True)
|
||||||
|
parser.add_argument("--manual", help="include or exclude manual updates",
|
||||||
|
action=argparse.BooleanOptionalAction, default=True)
|
||||||
|
parser.add_argument("--vcs", help="enable or disable checking of VCS packages",
|
||||||
|
action=argparse.BooleanOptionalAction, default=True)
|
||||||
|
parser.add_argument("-y", "--refresh", help="download fresh package databases from the mirror before actions, "
|
||||||
|
"-yy to force refresh even if up to date",
|
||||||
|
action="count", default=0)
|
||||||
parser.set_defaults(handler=handlers.Update)
|
parser.set_defaults(handler=handlers.Update)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
@ -677,8 +763,9 @@ def _set_shell_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
parser = root.add_parser("shell", help="envoke python shell",
|
parser = root.add_parser("shell", help="envoke python shell",
|
||||||
description="drop into python shell while having created application",
|
description="drop into python shell while having created application",
|
||||||
formatter_class=_formatter)
|
formatter_class=_formatter)
|
||||||
|
parser.add_argument("code", help="instead of dropping into shell, just execute the specified code", nargs="?")
|
||||||
parser.add_argument("-v", "--verbose", help=argparse.SUPPRESS, action="store_true")
|
parser.add_argument("-v", "--verbose", help=argparse.SUPPRESS, action="store_true")
|
||||||
parser.set_defaults(handler=handlers.Shell, lock=None, no_report=True)
|
parser.set_defaults(handler=handlers.Shell, lock=None, report=False)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
@ -703,7 +790,7 @@ def _set_user_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
parser.add_argument("-r", "--role", help="user access level",
|
parser.add_argument("-r", "--role", help="user access level",
|
||||||
type=UserAccess, choices=enum_values(UserAccess), default=UserAccess.Read)
|
type=UserAccess, choices=enum_values(UserAccess), default=UserAccess.Read)
|
||||||
parser.add_argument("-s", "--secure", help="set file permissions to user-only", action="store_true")
|
parser.add_argument("-s", "--secure", help="set file permissions to user-only", action="store_true")
|
||||||
parser.set_defaults(handler=handlers.Users, action=Action.Update, architecture=[""], lock=None, no_report=True,
|
parser.set_defaults(handler=handlers.Users, action=Action.Update, architecture=[""], lock=None, report=False,
|
||||||
quiet=True, unsafe=True)
|
quiet=True, unsafe=True)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
@ -724,7 +811,7 @@ def _set_user_list_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
parser.add_argument("username", help="filter users by username", nargs="?")
|
parser.add_argument("username", help="filter users by username", nargs="?")
|
||||||
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
|
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
|
||||||
parser.add_argument("-r", "--role", help="filter users by role", type=UserAccess, choices=enum_values(UserAccess))
|
parser.add_argument("-r", "--role", help="filter users by role", type=UserAccess, choices=enum_values(UserAccess))
|
||||||
parser.set_defaults(handler=handlers.Users, action=Action.List, architecture=[""], lock=None, no_report=True, # nosec
|
parser.set_defaults(handler=handlers.Users, action=Action.List, architecture=[""], lock=None, report=False, # nosec
|
||||||
password="", quiet=True, unsafe=True)
|
password="", quiet=True, unsafe=True)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
@ -744,7 +831,7 @@ def _set_user_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
formatter_class=_formatter)
|
formatter_class=_formatter)
|
||||||
parser.add_argument("username", help="username for web service")
|
parser.add_argument("username", help="username for web service")
|
||||||
parser.add_argument("-s", "--secure", help="set file permissions to user-only", action="store_true")
|
parser.add_argument("-s", "--secure", help="set file permissions to user-only", action="store_true")
|
||||||
parser.set_defaults(handler=handlers.Users, action=Action.Remove, architecture=[""], lock=None, no_report=True, # nosec
|
parser.set_defaults(handler=handlers.Users, action=Action.Remove, architecture=[""], lock=None, report=False, # nosec
|
||||||
password="", quiet=True, unsafe=True)
|
password="", quiet=True, unsafe=True)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
@ -761,7 +848,7 @@ def _set_version_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
"""
|
"""
|
||||||
parser = root.add_parser("version", help="application version",
|
parser = root.add_parser("version", help="application version",
|
||||||
description="print application and its dependencies versions", formatter_class=_formatter)
|
description="print application and its dependencies versions", formatter_class=_formatter)
|
||||||
parser.set_defaults(handler=handlers.Versions, architecture=[""], lock=None, no_report=True, quiet=True,
|
parser.set_defaults(handler=handlers.Versions, architecture=[""], lock=None, report=False, quiet=True,
|
||||||
unsafe=True)
|
unsafe=True)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
@ -777,7 +864,7 @@ def _set_web_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
argparse.ArgumentParser: created argument parser
|
argparse.ArgumentParser: created argument parser
|
||||||
"""
|
"""
|
||||||
parser = root.add_parser("web", help="web server", description="start web server", formatter_class=_formatter)
|
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)
|
parser.set_defaults(handler=handlers.Web, lock=None, report=False, parser=_parser)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,12 +36,12 @@ class Application(ApplicationPackages, ApplicationRepository):
|
|||||||
>>> from ahriman.models.package_source import PackageSource
|
>>> from ahriman.models.package_source import PackageSource
|
||||||
>>>
|
>>>
|
||||||
>>> configuration = Configuration()
|
>>> configuration = Configuration()
|
||||||
>>> application = Application("x86_64", configuration, no_report=False, unsafe=False)
|
>>> application = Application("x86_64", configuration, report=True, unsafe=False)
|
||||||
>>> # add packages to build queue
|
>>> # add packages to build queue
|
||||||
>>> application.add(["ahriman"], PackageSource.AUR, without_dependencies=False)
|
>>> application.add(["ahriman"], PackageSource.AUR, without_dependencies=False)
|
||||||
>>>
|
>>>
|
||||||
>>> # check for updates
|
>>> # check for updates
|
||||||
>>> updates = application.updates([], no_aur=False, no_local=False, no_manual=False, no_vcs=False, log_fn=print)
|
>>> updates = application.updates([], aur=True, local=True, manual=True, vcs=True, log_fn=print)
|
||||||
>>> # updates for specified packages
|
>>> # updates for specified packages
|
||||||
>>> application.update(updates)
|
>>> application.update(updates)
|
||||||
|
|
||||||
@ -49,15 +49,6 @@ class Application(ApplicationPackages, ApplicationRepository):
|
|||||||
be used instead.
|
be used instead.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def _finalize(self, result: Result) -> None:
|
|
||||||
"""
|
|
||||||
generate report and sync to remote server
|
|
||||||
|
|
||||||
Args:
|
|
||||||
result(Result): build result
|
|
||||||
"""
|
|
||||||
self.repository.process_triggers(result)
|
|
||||||
|
|
||||||
def _known_packages(self) -> Set[str]:
|
def _known_packages(self) -> Set[str]:
|
||||||
"""
|
"""
|
||||||
load packages from repository and pacman repositories
|
load packages from repository and pacman repositories
|
||||||
@ -71,5 +62,28 @@ class Application(ApplicationPackages, ApplicationRepository):
|
|||||||
for package, properties in base.packages.items():
|
for package, properties in base.packages.items():
|
||||||
known_packages.add(package)
|
known_packages.add(package)
|
||||||
known_packages.update(properties.provides)
|
known_packages.update(properties.provides)
|
||||||
known_packages.update(self.repository.pacman.all_packages())
|
known_packages.update(self.repository.pacman.packages())
|
||||||
return known_packages
|
return known_packages
|
||||||
|
|
||||||
|
def on_result(self, result: Result) -> None:
|
||||||
|
"""
|
||||||
|
generate report and sync to remote server
|
||||||
|
|
||||||
|
Args:
|
||||||
|
result(Result): build result
|
||||||
|
"""
|
||||||
|
packages = self.repository.packages()
|
||||||
|
self.repository.triggers.on_result(result, packages)
|
||||||
|
|
||||||
|
def on_start(self) -> None:
|
||||||
|
"""
|
||||||
|
run triggers on start of the application
|
||||||
|
"""
|
||||||
|
self.repository.triggers.on_start()
|
||||||
|
|
||||||
|
def on_stop(self) -> None:
|
||||||
|
"""
|
||||||
|
run triggers on stop of the application. Note, however, that in most cases this method should not be called
|
||||||
|
directly as it will be called after on_start action
|
||||||
|
"""
|
||||||
|
self.repository.triggers.on_stop()
|
||||||
|
@ -37,18 +37,6 @@ class ApplicationPackages(ApplicationProperties):
|
|||||||
package control class
|
package 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 _known_packages(self) -> Set[str]:
|
def _known_packages(self) -> Set[str]:
|
||||||
"""
|
"""
|
||||||
load packages from repository and pacman repositories
|
load packages from repository and pacman repositories
|
||||||
@ -61,6 +49,18 @@ class ApplicationPackages(ApplicationProperties):
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def on_result(self, result: Result) -> None:
|
||||||
|
"""
|
||||||
|
generate report and sync to remote server
|
||||||
|
|
||||||
|
Args:
|
||||||
|
result(Result): build result
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
NotImplementedError: not implemented method
|
||||||
|
"""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
def _add_archive(self, source: str, *_: Any) -> None:
|
def _add_archive(self, source: str, *_: Any) -> None:
|
||||||
"""
|
"""
|
||||||
add package from archive
|
add package from archive
|
||||||
@ -86,8 +86,7 @@ class ApplicationPackages(ApplicationProperties):
|
|||||||
self.database.build_queue_insert(package)
|
self.database.build_queue_insert(package)
|
||||||
self.database.remote_update(package)
|
self.database.remote_update(package)
|
||||||
|
|
||||||
with TemporaryDirectory(ignore_cleanup_errors=True) as dir_name, \
|
with TemporaryDirectory(ignore_cleanup_errors=True) as dir_name, (local_dir := Path(dir_name)):
|
||||||
(local_dir := Path(dir_name)): # pylint: disable=confusing-with-statement
|
|
||||||
Sources.load(local_dir, package, self.database.patches_get(package.base), self.repository.paths)
|
Sources.load(local_dir, package, self.database.patches_get(package.base), self.repository.paths)
|
||||||
self._process_dependencies(local_dir, known_packages, without_dependencies)
|
self._process_dependencies(local_dir, known_packages, without_dependencies)
|
||||||
|
|
||||||
@ -187,4 +186,4 @@ class ApplicationPackages(ApplicationProperties):
|
|||||||
names(Iterable[str]): list of packages (either base or name) to remove
|
names(Iterable[str]): list of packages (either base or name) to remove
|
||||||
"""
|
"""
|
||||||
self.repository.process_remove(names)
|
self.repository.process_remove(names)
|
||||||
self._finalize(Result())
|
self.on_result(Result())
|
||||||
|
@ -34,17 +34,20 @@ class ApplicationProperties(LazyLogging):
|
|||||||
repository(Repository): repository instance
|
repository(Repository): repository instance
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, architecture: str, configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
def __init__(self, architecture: str, configuration: Configuration, *,
|
||||||
|
report: bool, unsafe: bool, refresh_pacman_database: int = 0) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
default constructor
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
no_report(bool): force disable reporting
|
report(bool): force enable or disable reporting
|
||||||
unsafe(bool): if set no user check will be performed before path creation
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
|
refresh_pacman_database(int): pacman database syncronization level, ``0`` is disabled
|
||||||
"""
|
"""
|
||||||
self.configuration = configuration
|
self.configuration = configuration
|
||||||
self.architecture = architecture
|
self.architecture = architecture
|
||||||
self.database = SQLite.load(configuration)
|
self.database = SQLite.load(configuration)
|
||||||
self.repository = Repository(architecture, configuration, self.database, no_report, unsafe)
|
self.repository = Repository(architecture, configuration, self.database,
|
||||||
|
report=report, unsafe=unsafe, refresh_pacman_database=refresh_pacman_database)
|
||||||
|
@ -35,7 +35,7 @@ class ApplicationRepository(ApplicationProperties):
|
|||||||
repository control class
|
repository control class
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def _finalize(self, result: Result) -> None:
|
def on_result(self, result: Result) -> None:
|
||||||
"""
|
"""
|
||||||
generate report and sync to remote server
|
generate report and sync to remote server
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ class ApplicationRepository(ApplicationProperties):
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def clean(self, cache: bool, chroot: bool, manual: bool, packages: bool) -> None:
|
def clean(self, *, cache: bool, chroot: bool, manual: bool, packages: bool, pacman: bool) -> None:
|
||||||
"""
|
"""
|
||||||
run all clean methods. Warning: some functions might not be available under non-root
|
run all clean methods. Warning: some functions might not be available under non-root
|
||||||
|
|
||||||
@ -56,6 +56,7 @@ class ApplicationRepository(ApplicationProperties):
|
|||||||
chroot(bool): clear build chroot
|
chroot(bool): clear build chroot
|
||||||
manual(bool): clear directory with manually added packages
|
manual(bool): clear directory with manually added packages
|
||||||
packages(bool): clear directory with built packages
|
packages(bool): clear directory with built packages
|
||||||
|
pacman(bool): clear directory with pacman databases
|
||||||
"""
|
"""
|
||||||
if cache:
|
if cache:
|
||||||
self.repository.clear_cache()
|
self.repository.clear_cache()
|
||||||
@ -65,6 +66,8 @@ class ApplicationRepository(ApplicationProperties):
|
|||||||
self.repository.clear_queue()
|
self.repository.clear_queue()
|
||||||
if packages:
|
if packages:
|
||||||
self.repository.clear_packages()
|
self.repository.clear_packages()
|
||||||
|
if pacman:
|
||||||
|
self.repository.clear_pacman()
|
||||||
|
|
||||||
def sign(self, packages: Iterable[str]) -> None:
|
def sign(self, packages: Iterable[str]) -> None:
|
||||||
"""
|
"""
|
||||||
@ -89,7 +92,7 @@ class ApplicationRepository(ApplicationProperties):
|
|||||||
self.update([])
|
self.update([])
|
||||||
# sign repository database if set
|
# sign repository database if set
|
||||||
self.repository.sign.process_sign_repository(self.repository.repo.repo_path)
|
self.repository.sign.process_sign_repository(self.repository.repo.repo_path)
|
||||||
self._finalize(Result())
|
self.on_result(Result())
|
||||||
|
|
||||||
def unknown(self) -> List[str]:
|
def unknown(self) -> List[str]:
|
||||||
"""
|
"""
|
||||||
@ -139,7 +142,7 @@ class ApplicationRepository(ApplicationProperties):
|
|||||||
if not paths:
|
if not paths:
|
||||||
return # don't need to process if no update supplied
|
return # don't need to process if no update supplied
|
||||||
update_result = self.repository.process_update(paths)
|
update_result = self.repository.process_update(paths)
|
||||||
self._finalize(result.merge(update_result))
|
self.on_result(result.merge(update_result))
|
||||||
|
|
||||||
# process built packages
|
# process built packages
|
||||||
build_result = Result()
|
build_result = Result()
|
||||||
@ -156,17 +159,17 @@ class ApplicationRepository(ApplicationProperties):
|
|||||||
|
|
||||||
return build_result
|
return build_result
|
||||||
|
|
||||||
def updates(self, filter_packages: Iterable[str], no_aur: bool, no_local: bool, no_manual: bool, no_vcs: bool,
|
def updates(self, filter_packages: Iterable[str], *,
|
||||||
log_fn: Callable[[str], None]) -> List[Package]:
|
aur: bool, local: bool, manual: bool, vcs: bool, log_fn: Callable[[str], None]) -> List[Package]:
|
||||||
"""
|
"""
|
||||||
get list of packages to run update process
|
get list of packages to run update process
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
filter_packages(Iterable[str]): do not check every package just specified in the list
|
filter_packages(Iterable[str]): do not check every package just specified in the list
|
||||||
no_aur(bool): do not check for aur updates
|
aur(bool): enable or disable checking for AUR updates
|
||||||
no_local(bool): do not check local packages for updates
|
local(bool): enable or disable checking of local packages for updates
|
||||||
no_manual(bool): do not check for manual updates
|
manual(bool): include or exclude manual updates
|
||||||
no_vcs(bool): do not check VCS packages
|
vcs(bool): enable or disable checking of VCS packages
|
||||||
log_fn(Callable[[str], None]): logger function to log updates
|
log_fn(Callable[[str], None]): logger function to log updates
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@ -174,11 +177,11 @@ class ApplicationRepository(ApplicationProperties):
|
|||||||
"""
|
"""
|
||||||
updates = {}
|
updates = {}
|
||||||
|
|
||||||
if not no_aur:
|
if aur:
|
||||||
updates.update({package.base: package for package in self.repository.updates_aur(filter_packages, no_vcs)})
|
updates.update({package.base: package for package in self.repository.updates_aur(filter_packages, vcs=vcs)})
|
||||||
if not no_local:
|
if local:
|
||||||
updates.update({package.base: package for package in self.repository.updates_local()})
|
updates.update({package.base: package for package in self.repository.updates_local()})
|
||||||
if not no_manual:
|
if manual:
|
||||||
updates.update({package.base: package for package in self.repository.updates_manual()})
|
updates.update({package.base: package for package in self.repository.updates_manual()})
|
||||||
|
|
||||||
local_versions = {package.base: package.version for package in self.repository.packages()}
|
local_versions = {package.base: package.version for package in self.repository.packages()}
|
||||||
|
@ -22,6 +22,7 @@ from ahriman.application.handlers.handler import Handler
|
|||||||
from ahriman.application.handlers.add import Add
|
from ahriman.application.handlers.add import Add
|
||||||
from ahriman.application.handlers.backup import Backup
|
from ahriman.application.handlers.backup import Backup
|
||||||
from ahriman.application.handlers.clean import Clean
|
from ahriman.application.handlers.clean import Clean
|
||||||
|
from ahriman.application.handlers.daemon import Daemon
|
||||||
from ahriman.application.handlers.dump import Dump
|
from ahriman.application.handlers.dump import Dump
|
||||||
from ahriman.application.handlers.help import Help
|
from ahriman.application.handlers.help import Help
|
||||||
from ahriman.application.handlers.key_import import KeyImport
|
from ahriman.application.handlers.key_import import KeyImport
|
||||||
|
@ -32,8 +32,8 @@ class Add(Handler):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
|
|
||||||
@ -41,14 +41,17 @@ class Add(Handler):
|
|||||||
args(argparse.Namespace): command line args
|
args(argparse.Namespace): command line args
|
||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
no_report(bool): force disable reporting
|
report(bool): force enable or disable reporting
|
||||||
unsafe(bool): if set no user check will be performed before path creation
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
application = Application(architecture, configuration, no_report, unsafe)
|
application = Application(architecture, configuration,
|
||||||
|
report=report, unsafe=unsafe, refresh_pacman_database=args.refresh)
|
||||||
|
application.on_start()
|
||||||
application.add(args.package, args.source, args.without_dependencies)
|
application.add(args.package, args.source, args.without_dependencies)
|
||||||
if not args.now:
|
if not args.now:
|
||||||
return
|
return
|
||||||
|
|
||||||
packages = application.updates(args.package, True, True, False, True, application.logger.info)
|
packages = application.updates(args.package, aur=False, local=False, manual=True, vcs=False,
|
||||||
|
log_fn=application.logger.info)
|
||||||
result = application.update(packages)
|
result = application.update(packages)
|
||||||
Add.check_if_empty(args.exit_code, result.is_empty)
|
Add.check_if_empty(args.exit_code, result.is_empty)
|
||||||
|
@ -37,8 +37,8 @@ class Backup(Handler):
|
|||||||
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ class Backup(Handler):
|
|||||||
args(argparse.Namespace): command line args
|
args(argparse.Namespace): command line args
|
||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
no_report(bool): force disable reporting
|
report(bool): force enable or disable reporting
|
||||||
unsafe(bool): if set no user check will be performed before path creation
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
backup_paths = Backup.get_paths(configuration)
|
backup_paths = Backup.get_paths(configuration)
|
||||||
|
@ -32,8 +32,8 @@ class Clean(Handler):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
|
|
||||||
@ -41,8 +41,10 @@ class Clean(Handler):
|
|||||||
args(argparse.Namespace): command line args
|
args(argparse.Namespace): command line args
|
||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
no_report(bool): force disable reporting
|
report(bool): force enable or disable reporting
|
||||||
unsafe(bool): if set no user check will be performed before path creation
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
Application(architecture, configuration, no_report, unsafe).clean(
|
application = Application(architecture, configuration, report=report, unsafe=unsafe)
|
||||||
args.cache, args.chroot, args.manual, args.packages)
|
application.on_start()
|
||||||
|
application.clean(cache=args.cache, chroot=args.chroot, manual=args.manual, packages=args.packages,
|
||||||
|
pacman=args.pacman)
|
||||||
|
52
src/ahriman/application/handlers/daemon.py
Normal file
52
src/ahriman/application/handlers/daemon.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
|
||||||
|
import threading
|
||||||
|
|
||||||
|
from typing import Type
|
||||||
|
|
||||||
|
from ahriman.application.handlers import Handler
|
||||||
|
from ahriman.core.configuration import Configuration
|
||||||
|
|
||||||
|
|
||||||
|
class Daemon(Handler):
|
||||||
|
"""
|
||||||
|
daemon packages handler
|
||||||
|
"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||||
|
report: bool, unsafe: bool) -> None:
|
||||||
|
"""
|
||||||
|
callback for command line
|
||||||
|
|
||||||
|
Args:
|
||||||
|
args(argparse.Namespace): command line args
|
||||||
|
architecture(str): repository architecture
|
||||||
|
configuration(Configuration): configuration instance
|
||||||
|
report(bool): force enable or disable reporting
|
||||||
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
|
"""
|
||||||
|
from ahriman.application.handlers import Update
|
||||||
|
Update.run(args, architecture, configuration, report=report, unsafe=unsafe)
|
||||||
|
timer = threading.Timer(args.interval, Daemon.run, args=[args, architecture, configuration],
|
||||||
|
kwargs={"report": report, "unsafe": unsafe})
|
||||||
|
timer.start()
|
||||||
|
timer.join()
|
@ -34,8 +34,8 @@ class Dump(Handler):
|
|||||||
ALLOW_AUTO_ARCHITECTURE_RUN = False
|
ALLOW_AUTO_ARCHITECTURE_RUN = False
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ class Dump(Handler):
|
|||||||
args(argparse.Namespace): command line args
|
args(argparse.Namespace): command line args
|
||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
no_report(bool): force disable reporting
|
report(bool): force enable or disable reporting
|
||||||
unsafe(bool): if set no user check will be performed before path creation
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
dump = configuration.dump()
|
dump = configuration.dump()
|
||||||
|
@ -27,7 +27,7 @@ from typing import List, Type
|
|||||||
|
|
||||||
from ahriman.application.lock import Lock
|
from ahriman.application.lock import Lock
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
from ahriman.core.exceptions import ExitCode, MissingArchitecture, MultipleArchitectures
|
from ahriman.core.exceptions import ExitCode, MissingArchitectureError, MultipleArchitecturesError
|
||||||
from ahriman.models.repository_paths import RepositoryPaths
|
from ahriman.models.repository_paths import RepositoryPaths
|
||||||
|
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ class Handler:
|
|||||||
if not cls.ALLOW_AUTO_ARCHITECTURE_RUN and args.architecture is None:
|
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 some parsers (e.g. config) we need to run with specific architecture
|
||||||
# for those cases architecture must be set explicitly
|
# for those cases architecture must be set explicitly
|
||||||
raise MissingArchitecture(args.command)
|
raise MissingArchitectureError(args.command)
|
||||||
if args.architecture: # architecture is specified explicitly
|
if args.architecture: # architecture is specified explicitly
|
||||||
return sorted(set(args.architecture))
|
return sorted(set(args.architecture))
|
||||||
|
|
||||||
@ -78,7 +78,7 @@ class Handler:
|
|||||||
architectures = RepositoryPaths.known_architectures(root)
|
architectures = RepositoryPaths.known_architectures(root)
|
||||||
|
|
||||||
if not architectures: # well we did not find anything
|
if not architectures: # well we did not find anything
|
||||||
raise MissingArchitecture(args.command)
|
raise MissingArchitectureError(args.command)
|
||||||
return sorted(architectures)
|
return sorted(architectures)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -96,7 +96,7 @@ class Handler:
|
|||||||
try:
|
try:
|
||||||
configuration = Configuration.from_path(args.configuration, architecture, args.quiet)
|
configuration = Configuration.from_path(args.configuration, architecture, args.quiet)
|
||||||
with Lock(args, architecture, configuration):
|
with Lock(args, architecture, configuration):
|
||||||
cls.run(args, architecture, configuration, args.no_report, args.unsafe)
|
cls.run(args, architecture, configuration, report=args.report, unsafe=args.unsafe)
|
||||||
return True
|
return True
|
||||||
except ExitCode:
|
except ExitCode:
|
||||||
return False
|
return False
|
||||||
@ -124,7 +124,7 @@ class Handler:
|
|||||||
# actually we do not have to spawn another process if it is single-process application, do we?
|
# actually we do not have to spawn another process if it is single-process application, do we?
|
||||||
if len(architectures) > 1:
|
if len(architectures) > 1:
|
||||||
if not cls.ALLOW_MULTI_ARCHITECTURE_RUN:
|
if not cls.ALLOW_MULTI_ARCHITECTURE_RUN:
|
||||||
raise MultipleArchitectures(args.command)
|
raise MultipleArchitecturesError(args.command)
|
||||||
|
|
||||||
with Pool(len(architectures)) as pool:
|
with Pool(len(architectures)) as pool:
|
||||||
result = pool.starmap(
|
result = pool.starmap(
|
||||||
@ -135,8 +135,8 @@ class Handler:
|
|||||||
return 0 if all(result) else 1
|
return 0 if all(result) else 1
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
|
|
||||||
@ -144,7 +144,7 @@ class Handler:
|
|||||||
args(argparse.Namespace): command line args
|
args(argparse.Namespace): command line args
|
||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
no_report(bool): force disable reporting
|
report(bool): force enable or disable reporting
|
||||||
unsafe(bool): if set no user check will be performed before path creation
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
|
@ -33,8 +33,8 @@ class Help(Handler):
|
|||||||
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ class Help(Handler):
|
|||||||
args(argparse.Namespace): command line args
|
args(argparse.Namespace): command line args
|
||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
no_report(bool): force disable reporting
|
report(bool): force enable or disable reporting
|
||||||
unsafe(bool): if set no user check will be performed before path creation
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
parser: argparse.ArgumentParser = args.parser()
|
parser: argparse.ArgumentParser = args.parser()
|
||||||
|
@ -34,8 +34,8 @@ class KeyImport(Handler):
|
|||||||
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
|
|
||||||
@ -43,8 +43,8 @@ class KeyImport(Handler):
|
|||||||
args(argparse.Namespace): command line args
|
args(argparse.Namespace): command line args
|
||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
no_report(bool): force disable reporting
|
report(bool): force enable or disable reporting
|
||||||
unsafe(bool): if set no user check will be performed before path creation
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
Application(architecture, configuration, no_report, unsafe).repository.sign.key_import(
|
application = Application(architecture, configuration, report=report, unsafe=unsafe)
|
||||||
args.key_server, args.key)
|
application.repository.sign.key_import(args.key_server, args.key)
|
||||||
|
@ -18,17 +18,19 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
import argparse
|
import argparse
|
||||||
|
import sys
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Optional, Type
|
from typing import List, Optional, Tuple, Type
|
||||||
|
|
||||||
from ahriman.application.application import Application
|
from ahriman.application.application import Application
|
||||||
from ahriman.application.handlers import Handler
|
from ahriman.application.handlers import Handler
|
||||||
from ahriman.core.build_tools.sources import Sources
|
from ahriman.core.build_tools.sources import Sources
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
from ahriman.core.formatters import StringPrinter
|
from ahriman.core.formatters import PatchPrinter
|
||||||
from ahriman.models.action import Action
|
from ahriman.models.action import Action
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
|
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
||||||
|
|
||||||
|
|
||||||
class Patch(Handler):
|
class Patch(Handler):
|
||||||
@ -37,8 +39,8 @@ class Patch(Handler):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
|
|
||||||
@ -46,56 +48,99 @@ class Patch(Handler):
|
|||||||
args(argparse.Namespace): command line args
|
args(argparse.Namespace): command line args
|
||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
no_report(bool): force disable reporting
|
report(bool): force enable or disable reporting
|
||||||
unsafe(bool): if set no user check will be performed before path creation
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
application = Application(architecture, configuration, no_report, unsafe)
|
application = Application(architecture, configuration, report=report, unsafe=unsafe)
|
||||||
|
application.on_start()
|
||||||
|
|
||||||
if args.action == Action.List:
|
if args.action == Action.Update and args.variable is not None:
|
||||||
Patch.patch_set_list(application, args.package, args.exit_code)
|
patch = Patch.patch_create_from_function(args.variable, args.patch)
|
||||||
|
Patch.patch_set_create(application, args.package, patch)
|
||||||
|
elif args.action == Action.Update and args.variable is None:
|
||||||
|
package_base, patch = Patch.patch_create_from_diff(args.package, args.track)
|
||||||
|
Patch.patch_set_create(application, package_base, patch)
|
||||||
|
elif args.action == Action.List:
|
||||||
|
Patch.patch_set_list(application, args.package, args.variable, args.exit_code)
|
||||||
elif args.action == Action.Remove:
|
elif args.action == Action.Remove:
|
||||||
Patch.patch_set_remove(application, args.package)
|
Patch.patch_set_remove(application, args.package, args.variable)
|
||||||
elif args.action == Action.Update:
|
|
||||||
Patch.patch_set_create(application, Path(args.package), args.track)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def patch_set_create(application: Application, sources_dir: Path, track: List[str]) -> None:
|
def patch_create_from_diff(sources_dir: Path, track: List[str]) -> Tuple[str, PkgbuildPatch]:
|
||||||
|
"""
|
||||||
|
create PKGBUILD plain diff patches from sources directory
|
||||||
|
|
||||||
|
Args:
|
||||||
|
sources_dir(Path): path to directory with the package sources
|
||||||
|
track(List[str]): track files which match the glob before creating the patch
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tuple[str, PkgbuildPatch]: package base and created PKGBUILD patch based on the diff from master HEAD
|
||||||
|
to current files
|
||||||
|
"""
|
||||||
|
package = Package.from_build(sources_dir)
|
||||||
|
patch = Sources.patch_create(sources_dir, *track)
|
||||||
|
return package.base, PkgbuildPatch(None, patch)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def patch_create_from_function(variable: str, patch_path: Optional[Path]) -> PkgbuildPatch:
|
||||||
|
"""
|
||||||
|
create single-function patch set for the package base
|
||||||
|
|
||||||
|
Args:
|
||||||
|
variable(str): function or variable name inside PKGBUILD
|
||||||
|
patch_path(Path): optional path to patch content. If not set, it will be read from stdin
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
PkgbuildPatch: created patch for the PKGBUILD function
|
||||||
|
"""
|
||||||
|
if patch_path is None:
|
||||||
|
print("Post new function or variable value below. Press Ctrl-D to finish:", file=sys.stderr)
|
||||||
|
patch = "".join(list(sys.stdin))
|
||||||
|
else:
|
||||||
|
patch = patch_path.read_text(encoding="utf8")
|
||||||
|
patch = patch.strip() # remove spaces around the patch
|
||||||
|
return PkgbuildPatch(variable, patch)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def patch_set_create(application: Application, package_base: str, patch: PkgbuildPatch) -> None:
|
||||||
"""
|
"""
|
||||||
create patch set for the package base
|
create patch set for the package base
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
application(Application): application instance
|
application(Application): application instance
|
||||||
sources_dir(Path): path to directory with the package sources
|
package_base(str): package base
|
||||||
track(List[str]): track files which match the glob before creating the patch
|
patch(PkgbuildPatch): patch descriptor
|
||||||
"""
|
"""
|
||||||
package = Package.from_build(sources_dir)
|
application.database.patches_insert(package_base, patch)
|
||||||
patch = Sources.patch_create(sources_dir, *track)
|
|
||||||
application.database.patches_insert(package.base, patch)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def patch_set_list(application: Application, package_base: Optional[str], exit_code: bool) -> None:
|
def patch_set_list(application: Application, package_base: Optional[str], variables: List[str],
|
||||||
|
exit_code: bool) -> None:
|
||||||
"""
|
"""
|
||||||
list patches available for the package base
|
list patches available for the package base
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
application(Application): application instance
|
application(Application): application instance
|
||||||
package_base(Optional[str]): package base
|
package_base(Optional[str]): package base
|
||||||
|
variables(List[str]): extract patches only for specified PKGBUILD variables
|
||||||
exit_code(bool): exit with error on empty search result
|
exit_code(bool): exit with error on empty search result
|
||||||
|
:
|
||||||
"""
|
"""
|
||||||
patches = application.database.patches_list(package_base)
|
patches = application.database.patches_list(package_base, variables)
|
||||||
Patch.check_if_empty(exit_code, not patches)
|
Patch.check_if_empty(exit_code, not patches)
|
||||||
|
|
||||||
for base, patch in patches.items():
|
for base, patch in patches.items():
|
||||||
content = base if package_base is None else patch
|
PatchPrinter(base, patch).print(verbose=True, separator=" = ")
|
||||||
StringPrinter(content).print(verbose=True)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def patch_set_remove(application: Application, package_base: str) -> None:
|
def patch_set_remove(application: Application, package_base: str, variables: List[str]) -> None:
|
||||||
"""
|
"""
|
||||||
remove patch set for the package base
|
remove patch set for the package base
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
application(Application): application instance
|
application(Application): application instance
|
||||||
package_base(str): package base
|
package_base(str): package base
|
||||||
|
variables(List[str]): remove patches only for specified PKGBUILD variables
|
||||||
"""
|
"""
|
||||||
application.database.patches_remove(package_base)
|
application.database.patches_remove(package_base, variables)
|
||||||
|
@ -34,8 +34,8 @@ class Rebuild(Handler):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
|
|
||||||
@ -43,16 +43,16 @@ class Rebuild(Handler):
|
|||||||
args(argparse.Namespace): command line args
|
args(argparse.Namespace): command line args
|
||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
no_report(bool): force disable reporting
|
report(bool): force enable or disable reporting
|
||||||
unsafe(bool): if set no user check will be performed before path creation
|
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
|
depends_on = set(args.depends_on) if args.depends_on else None
|
||||||
|
|
||||||
application = Application(architecture, configuration, no_report, unsafe)
|
application = Application(architecture, configuration, report=report, unsafe=unsafe)
|
||||||
if args.from_database:
|
application.on_start()
|
||||||
updates = Rebuild.extract_packages(application)
|
|
||||||
else:
|
packages = Rebuild.extract_packages(application, from_database=args.from_database)
|
||||||
updates = application.repository.packages_depend_on(depends_on)
|
updates = application.repository.packages_depend_on(packages, depends_on)
|
||||||
|
|
||||||
Rebuild.check_if_empty(args.exit_code, not updates)
|
Rebuild.check_if_empty(args.exit_code, not updates)
|
||||||
if args.dry_run:
|
if args.dry_run:
|
||||||
@ -64,14 +64,17 @@ class Rebuild(Handler):
|
|||||||
Rebuild.check_if_empty(args.exit_code, result.is_empty)
|
Rebuild.check_if_empty(args.exit_code, result.is_empty)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def extract_packages(application: Application) -> List[Package]:
|
def extract_packages(application: Application, *, from_database: bool) -> List[Package]:
|
||||||
"""
|
"""
|
||||||
extract packages from database file
|
extract packages from database file
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
application(Application): application instance
|
application(Application): application instance
|
||||||
|
from_database(bool): extract packages from database instead of repository filesystem
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List[Package]: list of packages which were stored in database
|
List[Package]: list of packages which were stored in database
|
||||||
"""
|
"""
|
||||||
|
if from_database:
|
||||||
|
return application.repository.packages()
|
||||||
return [package for (package, _) in application.database.packages_get()]
|
return [package for (package, _) in application.database.packages_get()]
|
||||||
|
@ -32,8 +32,8 @@ class Remove(Handler):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
|
|
||||||
@ -41,7 +41,9 @@ class Remove(Handler):
|
|||||||
args(argparse.Namespace): command line args
|
args(argparse.Namespace): command line args
|
||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
no_report(bool): force disable reporting
|
report(bool): force enable or disable reporting
|
||||||
unsafe(bool): if set no user check will be performed before path creation
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
Application(architecture, configuration, no_report, unsafe).remove(args.package)
|
application = Application(architecture, configuration, report=report, unsafe=unsafe)
|
||||||
|
application.on_start()
|
||||||
|
application.remove(args.package)
|
||||||
|
@ -33,8 +33,8 @@ class RemoveUnknown(Handler):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
|
|
||||||
@ -42,15 +42,16 @@ class RemoveUnknown(Handler):
|
|||||||
args(argparse.Namespace): command line args
|
args(argparse.Namespace): command line args
|
||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
no_report(bool): force disable reporting
|
report(bool): force enable or disable reporting
|
||||||
unsafe(bool): if set no user check will be performed before path creation
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
application = Application(architecture, configuration, no_report, unsafe)
|
application = Application(architecture, configuration, report=report, unsafe=unsafe)
|
||||||
|
application.on_start()
|
||||||
unknown_packages = application.unknown()
|
unknown_packages = application.unknown()
|
||||||
|
|
||||||
if args.dry_run:
|
if args.dry_run:
|
||||||
for package in sorted(unknown_packages):
|
for package in sorted(unknown_packages):
|
||||||
StringPrinter(package).print(args.info)
|
StringPrinter(package).print(False)
|
||||||
return
|
return
|
||||||
|
|
||||||
application.remove(unknown_packages)
|
application.remove(unknown_packages)
|
||||||
|
@ -34,8 +34,8 @@ class Restore(Handler):
|
|||||||
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ class Restore(Handler):
|
|||||||
args(argparse.Namespace): command line args
|
args(argparse.Namespace): command line args
|
||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
no_report(bool): force disable reporting
|
report(bool): force enable or disable reporting
|
||||||
unsafe(bool): if set no user check will be performed before path creation
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
with TarFile(args.path) as archive:
|
with TarFile(args.path) as archive:
|
||||||
|
@ -26,7 +26,7 @@ from ahriman.application.application import Application
|
|||||||
from ahriman.application.handlers import Handler
|
from ahriman.application.handlers import Handler
|
||||||
from ahriman.core.alpm.remote import AUR, Official
|
from ahriman.core.alpm.remote import AUR, Official
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
from ahriman.core.exceptions import InvalidOption
|
from ahriman.core.exceptions import OptionError
|
||||||
from ahriman.core.formatters import AurPrinter
|
from ahriman.core.formatters import AurPrinter
|
||||||
from ahriman.models.aur_package import AURPackage
|
from ahriman.models.aur_package import AURPackage
|
||||||
|
|
||||||
@ -43,8 +43,8 @@ class Search(Handler):
|
|||||||
SORT_FIELDS = {field.name for field in fields(AURPackage) if field.default_factory is not list}
|
SORT_FIELDS = {field.name for field in fields(AURPackage) if field.default_factory is not list}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
|
|
||||||
@ -52,10 +52,10 @@ class Search(Handler):
|
|||||||
args(argparse.Namespace): command line args
|
args(argparse.Namespace): command line args
|
||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
no_report(bool): force disable reporting
|
report(bool): force enable or disable reporting
|
||||||
unsafe(bool): if set no user check will be performed before path creation
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
application = Application(architecture, configuration, no_report, unsafe)
|
application = Application(architecture, configuration, report=report, unsafe=unsafe)
|
||||||
|
|
||||||
official_packages_list = Official.multisearch(*args.search, pacman=application.repository.pacman)
|
official_packages_list = Official.multisearch(*args.search, pacman=application.repository.pacman)
|
||||||
aur_packages_list = AUR.multisearch(*args.search, pacman=application.repository.pacman)
|
aur_packages_list = AUR.multisearch(*args.search, pacman=application.repository.pacman)
|
||||||
@ -82,7 +82,7 @@ class Search(Handler):
|
|||||||
InvalidOption: if search fields is not in list of allowed ones
|
InvalidOption: if search fields is not in list of allowed ones
|
||||||
"""
|
"""
|
||||||
if sort_by not in Search.SORT_FIELDS:
|
if sort_by not in Search.SORT_FIELDS:
|
||||||
raise InvalidOption(sort_by)
|
raise OptionError(sort_by)
|
||||||
# always sort by package name at the last
|
# always sort by package name at the last
|
||||||
# well technically it is not a string, but we can deal with it
|
# well technically it is not a string, but we can deal with it
|
||||||
comparator: Callable[[AURPackage], Tuple[str, str]] =\
|
comparator: Callable[[AURPackage], Tuple[str, str]] =\
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from pwd import getpwuid
|
||||||
from typing import Type
|
from typing import Type
|
||||||
|
|
||||||
from ahriman.application.application import Application
|
from ahriman.application.application import Application
|
||||||
@ -34,21 +35,19 @@ class Setup(Handler):
|
|||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
ARCHBUILD_COMMAND_PATH(Path): (class attribute) default devtools command
|
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)
|
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
|
SUDOERS_DIR_PATH(Path): (class attribute) path to sudoers.d includes directory
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ALLOW_AUTO_ARCHITECTURE_RUN = False
|
ALLOW_AUTO_ARCHITECTURE_RUN = False
|
||||||
|
|
||||||
ARCHBUILD_COMMAND_PATH = Path("/usr/bin/archbuild")
|
ARCHBUILD_COMMAND_PATH = Path("/usr/bin/archbuild")
|
||||||
BIN_DIR_PATH = Path("/usr/local/bin")
|
|
||||||
MIRRORLIST_PATH = Path("/etc/pacman.d/mirrorlist")
|
MIRRORLIST_PATH = Path("/etc/pacman.d/mirrorlist")
|
||||||
SUDOERS_PATH = Path("/etc/sudoers.d/ahriman")
|
SUDOERS_DIR_PATH = Path("/etc/sudoers.d")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
|
|
||||||
@ -56,39 +55,41 @@ class Setup(Handler):
|
|||||||
args(argparse.Namespace): command line args
|
args(argparse.Namespace): command line args
|
||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
no_report(bool): force disable reporting
|
report(bool): force enable or disable reporting
|
||||||
unsafe(bool): if set no user check will be performed before path creation
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
Setup.configuration_create_ahriman(args, architecture, args.repository, configuration.include)
|
Setup.configuration_create_ahriman(args, architecture, args.repository, configuration.include,
|
||||||
|
configuration.repository_paths)
|
||||||
configuration.reload()
|
configuration.reload()
|
||||||
|
|
||||||
application = Application(architecture, configuration, no_report, unsafe)
|
application = Application(architecture, configuration, report=report, unsafe=unsafe)
|
||||||
|
|
||||||
Setup.configuration_create_makepkg(args.packager, application.repository.paths)
|
Setup.configuration_create_makepkg(args.packager, application.repository.paths)
|
||||||
Setup.executable_create(args.build_command, architecture)
|
Setup.executable_create(application.repository.paths, args.build_command, architecture)
|
||||||
Setup.configuration_create_devtools(args.build_command, architecture, args.from_configuration,
|
Setup.configuration_create_devtools(args.build_command, architecture, args.from_configuration,
|
||||||
args.no_multilib, args.repository, application.repository.paths)
|
args.multilib, args.repository, application.repository.paths)
|
||||||
Setup.configuration_create_sudo(args.build_command, architecture)
|
Setup.configuration_create_sudo(application.repository.paths, args.build_command, architecture)
|
||||||
|
|
||||||
application.repository.repo.init()
|
application.repository.repo.init()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def build_command(prefix: str, architecture: str) -> Path:
|
def build_command(root: Path, prefix: str, architecture: str) -> Path:
|
||||||
"""
|
"""
|
||||||
generate build command name
|
generate build command name
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
root(Path): root directory for the build command (must be root of the reporitory)
|
||||||
prefix(str): command prefix in {prefix}-{architecture}-build
|
prefix(str): command prefix in {prefix}-{architecture}-build
|
||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Path: valid devtools command name
|
Path: valid devtools command name
|
||||||
"""
|
"""
|
||||||
return Setup.BIN_DIR_PATH / f"{prefix}-{architecture}-build"
|
return root / f"{prefix}-{architecture}-build"
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def configuration_create_ahriman(args: argparse.Namespace, architecture: str, repository: str,
|
def configuration_create_ahriman(args: argparse.Namespace, architecture: str, repository: str,
|
||||||
include_path: Path) -> None:
|
include_path: Path, paths: RepositoryPaths) -> None:
|
||||||
"""
|
"""
|
||||||
create service specific configuration
|
create service specific configuration
|
||||||
|
|
||||||
@ -97,11 +98,13 @@ class Setup(Handler):
|
|||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
repository(str): repository name
|
repository(str): repository name
|
||||||
include_path(Path): path to directory with configuration includes
|
include_path(Path): path to directory with configuration includes
|
||||||
|
paths(RepositoryPaths): repository paths instance
|
||||||
"""
|
"""
|
||||||
configuration = Configuration()
|
configuration = Configuration()
|
||||||
|
|
||||||
section = Configuration.section_name("build", architecture)
|
section = Configuration.section_name("build", architecture)
|
||||||
configuration.set_option(section, "build_command", str(Setup.build_command(args.build_command, architecture)))
|
build_command = Setup.build_command(paths.root, args.build_command, architecture)
|
||||||
|
configuration.set_option(section, "build_command", str(build_command))
|
||||||
configuration.set_option("repository", "name", repository)
|
configuration.set_option("repository", "name", repository)
|
||||||
if args.build_as_user is not None:
|
if args.build_as_user is not None:
|
||||||
configuration.set_option(section, "makechrootpkg_flags", f"-U {args.build_as_user}")
|
configuration.set_option(section, "makechrootpkg_flags", f"-U {args.build_as_user}")
|
||||||
@ -121,19 +124,24 @@ class Setup(Handler):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def configuration_create_devtools(prefix: str, architecture: str, source: Path,
|
def configuration_create_devtools(prefix: str, architecture: str, source: Path,
|
||||||
no_multilib: bool, repository: str, paths: RepositoryPaths) -> None:
|
multilib: bool, repository: str, paths: RepositoryPaths) -> None:
|
||||||
"""
|
"""
|
||||||
create configuration for devtools based on ``source`` configuration
|
create configuration for devtools based on ``source`` configuration
|
||||||
|
|
||||||
|
Note:
|
||||||
|
devtools does not allow to specify the pacman configuration, thus we still have to use configuration in /usr
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
prefix(str): command prefix in {prefix}-{architecture}-build
|
prefix(str): command prefix in {prefix}-{architecture}-build
|
||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
source(Path): path to source configuration file
|
source(Path): path to source configuration file
|
||||||
no_multilib(bool): do not add multilib repository
|
multilib(bool): add or do not multilib repository
|
||||||
repository(str): repository name
|
repository(str): repository name
|
||||||
paths(RepositoryPaths): repository paths instance
|
paths(RepositoryPaths): repository paths instance
|
||||||
"""
|
"""
|
||||||
configuration = Configuration()
|
# allow_no_value=True is required because pacman uses boolean configuration in which just keys present
|
||||||
|
# (e.g. NoProgressBar) which will lead to exception
|
||||||
|
configuration = Configuration(allow_no_value=True)
|
||||||
# preserve case
|
# preserve case
|
||||||
# stupid mypy thinks that it is impossible
|
# stupid mypy thinks that it is impossible
|
||||||
configuration.optionxform = lambda key: key # type: ignore
|
configuration.optionxform = lambda key: key # type: ignore
|
||||||
@ -146,7 +154,7 @@ class Setup(Handler):
|
|||||||
configuration.set_option("options", "Architecture", architecture)
|
configuration.set_option("options", "Architecture", architecture)
|
||||||
|
|
||||||
# add multilib
|
# add multilib
|
||||||
if not no_multilib:
|
if multilib:
|
||||||
configuration.set_option("multilib", "Include", str(Setup.MIRRORLIST_PATH))
|
configuration.set_option("multilib", "Include", str(Setup.MIRRORLIST_PATH))
|
||||||
|
|
||||||
# add repository itself
|
# add repository itself
|
||||||
@ -166,30 +174,36 @@ class Setup(Handler):
|
|||||||
packager(str): packager identifier (e.g. name, email)
|
packager(str): packager identifier (e.g. name, email)
|
||||||
paths(RepositoryPaths): repository paths instance
|
paths(RepositoryPaths): repository paths instance
|
||||||
"""
|
"""
|
||||||
(paths.root / ".makepkg.conf").write_text(f"PACKAGER='{packager}'\n", encoding="utf8")
|
uid, _ = paths.root_owner
|
||||||
|
home_dir = Path(getpwuid(uid).pw_dir)
|
||||||
|
(home_dir / ".makepkg.conf").write_text(f"PACKAGER='{packager}'\n", encoding="utf8")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def configuration_create_sudo(prefix: str, architecture: str) -> None:
|
def configuration_create_sudo(paths: RepositoryPaths, prefix: str, architecture: str) -> None:
|
||||||
"""
|
"""
|
||||||
create configuration to run build command with sudo without password
|
create configuration to run build command with sudo without password
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
paths(RepositoryPaths): repository paths instance
|
||||||
prefix(str): command prefix in {prefix}-{architecture}-build
|
prefix(str): command prefix in {prefix}-{architecture}-build
|
||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
"""
|
"""
|
||||||
command = Setup.build_command(prefix, architecture)
|
command = Setup.build_command(paths.root, prefix, architecture)
|
||||||
Setup.SUDOERS_PATH.write_text(f"ahriman ALL=(ALL) NOPASSWD: {command} *\n", encoding="utf8")
|
sudoers_file = Setup.build_command(Setup.SUDOERS_DIR_PATH, prefix, architecture)
|
||||||
Setup.SUDOERS_PATH.chmod(0o400) # security!
|
sudoers_file.write_text(f"ahriman ALL=(ALL) NOPASSWD: {command} *\n", encoding="utf8")
|
||||||
|
sudoers_file.chmod(0o400) # security!
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def executable_create(prefix: str, architecture: str) -> None:
|
def executable_create(paths: RepositoryPaths, prefix: str, architecture: str) -> None:
|
||||||
"""
|
"""
|
||||||
create executable for the service
|
create executable for the service
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
paths(RepositoryPaths): repository paths instance
|
||||||
prefix(str): command prefix in {prefix}-{architecture}-build
|
prefix(str): command prefix in {prefix}-{architecture}-build
|
||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
"""
|
"""
|
||||||
command = Setup.build_command(prefix, architecture)
|
command = Setup.build_command(paths.root, prefix, architecture)
|
||||||
command.unlink(missing_ok=True)
|
command.unlink(missing_ok=True)
|
||||||
command.symlink_to(Setup.ARCHBUILD_COMMAND_PATH)
|
command.symlink_to(Setup.ARCHBUILD_COMMAND_PATH)
|
||||||
|
paths.chown(command) # we would like to keep owner inside ahriman's home
|
||||||
|
@ -38,8 +38,8 @@ class Shell(Handler):
|
|||||||
ALLOW_MULTI_ARCHITECTURE_RUN = False
|
ALLOW_MULTI_ARCHITECTURE_RUN = False
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
|
|
||||||
@ -47,13 +47,16 @@ class Shell(Handler):
|
|||||||
args(argparse.Namespace): command line args
|
args(argparse.Namespace): command line args
|
||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
no_report(bool): force disable reporting
|
report(bool): force enable or disable reporting
|
||||||
unsafe(bool): if set no user check will be performed before path creation
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
# pylint: disable=possibly-unused-variable
|
# pylint: disable=possibly-unused-variable
|
||||||
application = Application(architecture, configuration, no_report, unsafe)
|
application = Application(architecture, configuration, report=report, unsafe=unsafe)
|
||||||
if args.verbose:
|
if args.verbose:
|
||||||
# licensed by https://creativecommons.org/licenses/by-sa/3.0
|
# licensed by https://creativecommons.org/licenses/by-sa/3.0
|
||||||
path = Path(sys.prefix) / "share" / "ahriman" / "templates" / "shell"
|
path = Path(sys.prefix) / "share" / "ahriman" / "templates" / "shell"
|
||||||
StringPrinter(path.read_text(encoding="utf8")).print(verbose=False)
|
StringPrinter(path.read_text(encoding="utf8")).print(verbose=False)
|
||||||
code.interact(local=locals())
|
if args.code is None:
|
||||||
|
code.interact(local=locals())
|
||||||
|
else:
|
||||||
|
code.InteractiveConsole(locals=locals()).runcode(args.code)
|
||||||
|
@ -32,8 +32,8 @@ class Sign(Handler):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ class Sign(Handler):
|
|||||||
args(argparse.Namespace): command line args
|
args(argparse.Namespace): command line args
|
||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
no_report(bool): force disable reporting
|
report(bool): force enable or disable reporting
|
||||||
unsafe(bool): if set no user check will be performed before path creation
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
Application(architecture, configuration, no_report, unsafe).sign(args.package)
|
Application(architecture, configuration, report=report, unsafe=unsafe).sign(args.package)
|
||||||
|
@ -37,8 +37,8 @@ class Status(Handler):
|
|||||||
ALLOW_AUTO_ARCHITECTURE_RUN = False
|
ALLOW_AUTO_ARCHITECTURE_RUN = False
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
|
|
||||||
@ -46,11 +46,11 @@ class Status(Handler):
|
|||||||
args(argparse.Namespace): command line args
|
args(argparse.Namespace): command line args
|
||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
no_report(bool): force disable reporting
|
report(bool): force enable or disable reporting
|
||||||
unsafe(bool): if set no user check will be performed before path creation
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
# we are using reporter here
|
# we are using reporter here
|
||||||
client = Application(architecture, configuration, no_report=False, unsafe=unsafe).repository.reporter
|
client = Application(architecture, configuration, report=True, unsafe=unsafe).repository.reporter
|
||||||
if args.ahriman:
|
if args.ahriman:
|
||||||
service_status = client.get_internal()
|
service_status = client.get_internal()
|
||||||
StatusPrinter(service_status.status).print(args.info)
|
StatusPrinter(service_status.status).print(args.info)
|
||||||
|
@ -35,8 +35,8 @@ class StatusUpdate(Handler):
|
|||||||
ALLOW_AUTO_ARCHITECTURE_RUN = False
|
ALLOW_AUTO_ARCHITECTURE_RUN = False
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
|
|
||||||
@ -44,11 +44,11 @@ class StatusUpdate(Handler):
|
|||||||
args(argparse.Namespace): command line args
|
args(argparse.Namespace): command line args
|
||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
no_report(bool): force disable reporting
|
report(bool): force enable or disable reporting
|
||||||
unsafe(bool): if set no user check will be performed before path creation
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
# we are using reporter here
|
# we are using reporter here
|
||||||
client = Application(architecture, configuration, no_report=False, unsafe=unsafe).repository.reporter
|
client = Application(architecture, configuration, report=True, unsafe=unsafe).repository.reporter
|
||||||
|
|
||||||
if args.action == Action.Update and args.package:
|
if args.action == Action.Update and args.package:
|
||||||
# update packages statuses
|
# update packages statuses
|
||||||
|
@ -33,8 +33,8 @@ class Triggers(Handler):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
|
|
||||||
@ -42,11 +42,12 @@ class Triggers(Handler):
|
|||||||
args(argparse.Namespace): command line args
|
args(argparse.Namespace): command line args
|
||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
no_report(bool): force disable reporting
|
report(bool): force enable or disable reporting
|
||||||
unsafe(bool): if set no user check will be performed before path creation
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
application = Application(architecture, configuration, no_report, unsafe)
|
application = Application(architecture, configuration, report=report, unsafe=unsafe)
|
||||||
if args.trigger:
|
if args.trigger:
|
||||||
loader = application.repository.triggers
|
loader = application.repository.triggers
|
||||||
loader.triggers = [loader.load_trigger(trigger) for trigger in args.trigger]
|
loader.triggers = [loader.load_trigger(trigger) for trigger in args.trigger]
|
||||||
application.repository.process_triggers(Result())
|
application.on_start()
|
||||||
|
application.on_result(Result())
|
||||||
|
@ -35,8 +35,8 @@ class UnsafeCommands(Handler):
|
|||||||
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ class UnsafeCommands(Handler):
|
|||||||
args(argparse.Namespace): command line args
|
args(argparse.Namespace): command line args
|
||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
no_report(bool): force disable reporting
|
report(bool): force enable or disable reporting
|
||||||
unsafe(bool): if set no user check will be performed before path creation
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
parser = args.parser()
|
parser = args.parser()
|
||||||
@ -79,6 +79,7 @@ class UnsafeCommands(Handler):
|
|||||||
Returns:
|
Returns:
|
||||||
List[str]: list of commands with default unsafe flag
|
List[str]: list of commands with default unsafe flag
|
||||||
"""
|
"""
|
||||||
|
# should never fail
|
||||||
# pylint: disable=protected-access
|
# pylint: disable=protected-access
|
||||||
subparser = next(action for action in parser._actions if isinstance(action, argparse._SubParsersAction))
|
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")]
|
return [action_name for action_name, action in subparser.choices.items() if action.get_default("unsafe")]
|
||||||
|
@ -32,8 +32,8 @@ class Update(Handler):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
|
|
||||||
@ -41,12 +41,14 @@ class Update(Handler):
|
|||||||
args(argparse.Namespace): command line args
|
args(argparse.Namespace): command line args
|
||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
no_report(bool): force disable reporting
|
report(bool): force enable or disable reporting
|
||||||
unsafe(bool): if set no user check will be performed before path creation
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
application = Application(architecture, configuration, no_report, unsafe)
|
application = Application(architecture, configuration, report=report, unsafe=unsafe,
|
||||||
packages = application.updates(args.package, args.no_aur, args.no_local, args.no_manual, args.no_vcs,
|
refresh_pacman_database=args.refresh)
|
||||||
Update.log_fn(application, args.dry_run))
|
application.on_start()
|
||||||
|
packages = application.updates(args.package, aur=args.aur, local=args.local, manual=args.manual, vcs=args.vcs,
|
||||||
|
log_fn=Update.log_fn(application, args.dry_run))
|
||||||
Update.check_if_empty(args.exit_code, not packages)
|
Update.check_if_empty(args.exit_code, not packages)
|
||||||
if args.dry_run:
|
if args.dry_run:
|
||||||
return
|
return
|
||||||
|
@ -39,8 +39,8 @@ class Users(Handler):
|
|||||||
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ class Users(Handler):
|
|||||||
args(argparse.Namespace): command line args
|
args(argparse.Namespace): command line args
|
||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
no_report(bool): force disable reporting
|
report(bool): force enable or disable reporting
|
||||||
unsafe(bool): if set no user check will be performed before path creation
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
database = SQLite.load(configuration)
|
database = SQLite.load(configuration)
|
||||||
|
@ -37,8 +37,8 @@ class Versions(Handler):
|
|||||||
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ class Versions(Handler):
|
|||||||
args(argparse.Namespace): command line args
|
args(argparse.Namespace): command line args
|
||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
no_report(bool): force disable reporting
|
report(bool): force enable or disable reporting
|
||||||
unsafe(bool): if set no user check will be performed before path creation
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
VersionPrinter(f"Module version {version.__version__}",
|
VersionPrinter(f"Module version {version.__version__}",
|
||||||
|
@ -35,8 +35,8 @@ class Web(Handler):
|
|||||||
ALLOW_MULTI_ARCHITECTURE_RUN = False # required to be able to spawn external processes
|
ALLOW_MULTI_ARCHITECTURE_RUN = False # required to be able to spawn external processes
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ class Web(Handler):
|
|||||||
args(argparse.Namespace): command line args
|
args(argparse.Namespace): command line args
|
||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
no_report(bool): force disable reporting
|
report(bool): force enable or disable reporting
|
||||||
unsafe(bool): if set no user check will be performed before path creation
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
# we are using local import for optional dependencies
|
# we are using local import for optional dependencies
|
||||||
|
@ -27,7 +27,7 @@ from typing import Literal, Optional, Type
|
|||||||
|
|
||||||
from ahriman import version
|
from ahriman import version
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
from ahriman.core.exceptions import DuplicateRun
|
from ahriman.core.exceptions import DuplicateRunError
|
||||||
from ahriman.core.lazy_logging import LazyLogging
|
from ahriman.core.lazy_logging import LazyLogging
|
||||||
from ahriman.core.status.client import Client
|
from ahriman.core.status.client import Client
|
||||||
from ahriman.core.util import check_user
|
from ahriman.core.util import check_user
|
||||||
@ -73,7 +73,7 @@ class Lock(LazyLogging):
|
|||||||
self.unsafe = args.unsafe
|
self.unsafe = args.unsafe
|
||||||
|
|
||||||
self.paths = configuration.repository_paths
|
self.paths = configuration.repository_paths
|
||||||
self.reporter = Client() if args.no_report else Client.load(configuration)
|
self.reporter = Client.load(configuration) if args.report else Client()
|
||||||
|
|
||||||
def __enter__(self) -> Lock:
|
def __enter__(self) -> Lock:
|
||||||
"""
|
"""
|
||||||
@ -122,7 +122,7 @@ class Lock(LazyLogging):
|
|||||||
"""
|
"""
|
||||||
check if current user is actually owner of ahriman root
|
check if current user is actually owner of ahriman root
|
||||||
"""
|
"""
|
||||||
check_user(self.paths, self.unsafe)
|
check_user(self.paths, unsafe=self.unsafe)
|
||||||
|
|
||||||
def clear(self) -> None:
|
def clear(self) -> None:
|
||||||
"""
|
"""
|
||||||
@ -144,4 +144,4 @@ class Lock(LazyLogging):
|
|||||||
try:
|
try:
|
||||||
self.path.touch(exist_ok=self.force)
|
self.path.touch(exist_ok=self.force)
|
||||||
except FileExistsError:
|
except FileExistsError:
|
||||||
raise DuplicateRun()
|
raise DuplicateRunError()
|
||||||
|
@ -17,13 +17,18 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
from pyalpm import Handle, Package, SIG_PACKAGE # type: ignore
|
import shutil
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
from pyalpm import DB, Handle, Package, SIG_PACKAGE, error as PyalpmError # type: ignore
|
||||||
from typing import Generator, Set
|
from typing import Generator, Set
|
||||||
|
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
|
from ahriman.core.lazy_logging import LazyLogging
|
||||||
|
from ahriman.models.repository_paths import RepositoryPaths
|
||||||
|
|
||||||
|
|
||||||
class Pacman:
|
class Pacman(LazyLogging):
|
||||||
"""
|
"""
|
||||||
alpm wrapper
|
alpm wrapper
|
||||||
|
|
||||||
@ -31,35 +36,96 @@ class Pacman:
|
|||||||
handle(Handle): pyalpm root ``Handle``
|
handle(Handle): pyalpm root ``Handle``
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, configuration: Configuration) -> None:
|
def __init__(self, architecture: str, configuration: Configuration, *, refresh_database: int) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
default constructor
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
architecture(str): repository architecture
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
|
refresh_database(int): synchronize local cache to remote. If set to ``0``, no syncronization will be
|
||||||
|
enabled, if set to ``1`` - normal syncronization, if set to ``2`` - force syncronization
|
||||||
"""
|
"""
|
||||||
root = configuration.get("alpm", "root")
|
root = configuration.getpath("alpm", "root")
|
||||||
pacman_root = configuration.getpath("alpm", "database")
|
pacman_root = configuration.getpath("alpm", "database")
|
||||||
self.handle = Handle(root, str(pacman_root))
|
use_ahriman_cache = configuration.getboolean("alpm", "use_ahriman_cache")
|
||||||
for repository in configuration.getlist("alpm", "repositories"):
|
mirror = configuration.get("alpm", "mirror")
|
||||||
self.handle.register_syncdb(repository, SIG_PACKAGE)
|
paths = configuration.repository_paths
|
||||||
|
database_path = paths.pacman if use_ahriman_cache else pacman_root
|
||||||
|
|
||||||
def all_packages(self) -> Set[str]:
|
self.handle = Handle(str(root), str(database_path))
|
||||||
|
for repository in configuration.getlist("alpm", "repositories"):
|
||||||
|
database = self.database_init(repository, mirror, architecture)
|
||||||
|
self.database_copy(database, pacman_root, paths, use_ahriman_cache=use_ahriman_cache)
|
||||||
|
|
||||||
|
if use_ahriman_cache and refresh_database:
|
||||||
|
self.database_sync(refresh_database > 1)
|
||||||
|
|
||||||
|
def database_copy(self, database: DB, pacman_root: Path, paths: RepositoryPaths, *,
|
||||||
|
use_ahriman_cache: bool) -> None:
|
||||||
"""
|
"""
|
||||||
get list of packages known for alpm
|
copy database from the operating system root to the ahriman local home
|
||||||
|
|
||||||
|
Args:
|
||||||
|
database(DB): pacman database instance to be copied
|
||||||
|
pacman_root(Path): operating system pacman's root
|
||||||
|
paths(RepositoryPaths): repository paths instance
|
||||||
|
use_ahriman_cache(bool): use local ahriman cache instead of system one
|
||||||
|
"""
|
||||||
|
def repository_database(root: Path) -> Path:
|
||||||
|
return root / "sync" / f"{database.name}.db"
|
||||||
|
|
||||||
|
if not use_ahriman_cache:
|
||||||
|
return
|
||||||
|
# copy root database if no local copy found
|
||||||
|
pacman_db_path = Path(self.handle.dbpath)
|
||||||
|
if not pacman_db_path.is_dir():
|
||||||
|
return # root directory does not exist yet
|
||||||
|
dst = repository_database(pacman_db_path)
|
||||||
|
if dst.is_file():
|
||||||
|
return # file already exists, do not copy
|
||||||
|
src = repository_database(pacman_root)
|
||||||
|
if not src.is_file():
|
||||||
|
self.logger.warning("repository %s is set to be used, however, no working copy was found", database.name)
|
||||||
|
return # database for some reasons deos not exist
|
||||||
|
self.logger.info("copy pacman database from operating system root to ahriman's home")
|
||||||
|
shutil.copy(src, dst)
|
||||||
|
paths.chown(dst)
|
||||||
|
|
||||||
|
def database_init(self, repository: str, mirror: str, architecture: str) -> DB:
|
||||||
|
"""
|
||||||
|
create database instance from pacman handler and set its properties
|
||||||
|
|
||||||
|
Args:
|
||||||
|
repository(str): pacman repository name (e.g. core)
|
||||||
|
mirror(str): arch linux mirror url
|
||||||
|
architecture(str): repository architecture
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Set[str]: list of package names
|
DB: loaded pacman database instance
|
||||||
"""
|
"""
|
||||||
result: Set[str] = set()
|
database: DB = self.handle.register_syncdb(repository, SIG_PACKAGE)
|
||||||
|
# replace variables in mirror address
|
||||||
|
database.servers = [mirror.replace("$repo", repository).replace("$arch", architecture)]
|
||||||
|
return database
|
||||||
|
|
||||||
|
def database_sync(self, force: bool) -> None:
|
||||||
|
"""
|
||||||
|
sync local database
|
||||||
|
|
||||||
|
Args:
|
||||||
|
force(bool): force database syncronization (same as ``pacman -Syy``)
|
||||||
|
"""
|
||||||
|
self.logger.info("refresh ahriman's home pacman database (force refresh %s)", force)
|
||||||
|
transaction = self.handle.init_transaction()
|
||||||
for database in self.handle.get_syncdbs():
|
for database in self.handle.get_syncdbs():
|
||||||
for package in database.pkgcache:
|
try:
|
||||||
result.add(package.name) # package itself
|
database.update(force)
|
||||||
result.update(package.provides) # provides list for meta-packages
|
except PyalpmError:
|
||||||
|
self.logger.exception("exception during update %s", database.name)
|
||||||
|
transaction.release()
|
||||||
|
|
||||||
return result
|
def package_get(self, package_name: str) -> Generator[Package, None, None]:
|
||||||
|
|
||||||
def get(self, package_name: str) -> Generator[Package, None, None]:
|
|
||||||
"""
|
"""
|
||||||
retrieve list of the packages from the repository by name
|
retrieve list of the packages from the repository by name
|
||||||
|
|
||||||
@ -74,3 +140,18 @@ class Pacman:
|
|||||||
if package is None:
|
if package is None:
|
||||||
continue
|
continue
|
||||||
yield package
|
yield package
|
||||||
|
|
||||||
|
def packages(self) -> Set[str]:
|
||||||
|
"""
|
||||||
|
get list of packages known for alpm
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Set[str]: list of package names
|
||||||
|
"""
|
||||||
|
result: Set[str] = set()
|
||||||
|
for database in self.handle.get_syncdbs():
|
||||||
|
for package in database.pkgcache:
|
||||||
|
result.add(package.name) # package itself
|
||||||
|
result.update(package.provides) # provides list for meta-packages
|
||||||
|
|
||||||
|
return result
|
||||||
|
@ -23,7 +23,7 @@ from typing import Any, Dict, List, Type
|
|||||||
|
|
||||||
from ahriman.core.alpm.pacman import Pacman
|
from ahriman.core.alpm.pacman import Pacman
|
||||||
from ahriman.core.alpm.remote import Remote
|
from ahriman.core.alpm.remote import Remote
|
||||||
from ahriman.core.exceptions import InvalidPackageInfo
|
from ahriman.core.exceptions import PackageInfoError, UnknownPackageError
|
||||||
from ahriman.core.util import exception_response_text
|
from ahriman.core.util import exception_response_text
|
||||||
from ahriman.models.aur_package import AURPackage
|
from ahriman.models.aur_package import AURPackage
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ class AUR(Remote):
|
|||||||
response_type = response["type"]
|
response_type = response["type"]
|
||||||
if response_type == "error":
|
if response_type == "error":
|
||||||
error_details = response.get("error", "Unknown API error")
|
error_details = response.get("error", "Unknown API error")
|
||||||
raise InvalidPackageInfo(error_details)
|
raise PackageInfoError(error_details)
|
||||||
return [AURPackage.from_json(package) for package in response["results"]]
|
return [AURPackage.from_json(package) for package in response["results"]]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -140,7 +140,10 @@ class AUR(Remote):
|
|||||||
AURPackage: package which match the package name
|
AURPackage: package which match the package name
|
||||||
"""
|
"""
|
||||||
packages = self.make_request("info", package_name)
|
packages = self.make_request("info", package_name)
|
||||||
return next(package for package in packages if package.name == package_name)
|
try:
|
||||||
|
return next(package for package in packages if package.name == package_name)
|
||||||
|
except StopIteration:
|
||||||
|
raise UnknownPackageError(package_name)
|
||||||
|
|
||||||
def package_search(self, *keywords: str, pacman: Pacman) -> List[AURPackage]:
|
def package_search(self, *keywords: str, pacman: Pacman) -> List[AURPackage]:
|
||||||
"""
|
"""
|
||||||
|
@ -23,7 +23,7 @@ from typing import Any, Dict, List, Type
|
|||||||
|
|
||||||
from ahriman.core.alpm.pacman import Pacman
|
from ahriman.core.alpm.pacman import Pacman
|
||||||
from ahriman.core.alpm.remote import Remote
|
from ahriman.core.alpm.remote import Remote
|
||||||
from ahriman.core.exceptions import InvalidPackageInfo
|
from ahriman.core.exceptions import PackageInfoError, UnknownPackageError
|
||||||
from ahriman.core.util import exception_response_text
|
from ahriman.core.util import exception_response_text
|
||||||
from ahriman.models.aur_package import AURPackage
|
from ahriman.models.aur_package import AURPackage
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ class Official(Remote):
|
|||||||
InvalidPackageInfo: for error API response
|
InvalidPackageInfo: for error API response
|
||||||
"""
|
"""
|
||||||
if not response["valid"]:
|
if not response["valid"]:
|
||||||
raise InvalidPackageInfo("API validation error")
|
raise PackageInfoError("API validation error")
|
||||||
return [AURPackage.from_repo(package) for package in response["results"]]
|
return [AURPackage.from_repo(package) for package in response["results"]]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -128,7 +128,10 @@ class Official(Remote):
|
|||||||
AURPackage: package which match the package name
|
AURPackage: package which match the package name
|
||||||
"""
|
"""
|
||||||
packages = self.make_request(package_name, by="name")
|
packages = self.make_request(package_name, by="name")
|
||||||
return next(package for package in packages if package.name == package_name)
|
try:
|
||||||
|
return next(package for package in packages if package.name == package_name)
|
||||||
|
except StopIteration:
|
||||||
|
raise UnknownPackageError(package_name)
|
||||||
|
|
||||||
def package_search(self, *keywords: str, pacman: Pacman) -> List[AURPackage]:
|
def package_search(self, *keywords: str, pacman: Pacman) -> List[AURPackage]:
|
||||||
"""
|
"""
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#
|
#
|
||||||
from ahriman.core.alpm.pacman import Pacman
|
from ahriman.core.alpm.pacman import Pacman
|
||||||
from ahriman.core.alpm.remote import Official
|
from ahriman.core.alpm.remote import Official
|
||||||
|
from ahriman.core.exceptions import UnknownPackageError
|
||||||
from ahriman.models.aur_package import AURPackage
|
from ahriman.models.aur_package import AURPackage
|
||||||
|
|
||||||
|
|
||||||
@ -48,4 +49,7 @@ class OfficialSyncdb(Official):
|
|||||||
Returns:
|
Returns:
|
||||||
AURPackage: package which match the package name
|
AURPackage: package which match the package name
|
||||||
"""
|
"""
|
||||||
return next(AURPackage.from_pacman(package) for package in pacman.get(package_name))
|
try:
|
||||||
|
return next(AURPackage.from_pacman(package) for package in pacman.package_get(package_name))
|
||||||
|
except StopIteration:
|
||||||
|
raise UnknownPackageError(package_name)
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from ahriman.core.exceptions import BuildFailed
|
from ahriman.core.exceptions import BuildError
|
||||||
from ahriman.core.lazy_logging import LazyLogging
|
from ahriman.core.lazy_logging import LazyLogging
|
||||||
from ahriman.core.util import check_output
|
from ahriman.core.util import check_output
|
||||||
from ahriman.models.repository_paths import RepositoryPaths
|
from ahriman.models.repository_paths import RepositoryPaths
|
||||||
@ -72,7 +72,7 @@ class Repo(LazyLogging):
|
|||||||
"""
|
"""
|
||||||
Repo._check_output(
|
Repo._check_output(
|
||||||
"repo-add", *self.sign_args, "-R", str(self.repo_path), str(path),
|
"repo-add", *self.sign_args, "-R", str(self.repo_path), str(path),
|
||||||
exception=BuildFailed(path.name),
|
exception=BuildError(path.name),
|
||||||
cwd=self.paths.repository,
|
cwd=self.paths.repository,
|
||||||
logger=self.logger,
|
logger=self.logger,
|
||||||
user=self.uid)
|
user=self.uid)
|
||||||
@ -81,12 +81,8 @@ class Repo(LazyLogging):
|
|||||||
"""
|
"""
|
||||||
create empty repository database
|
create empty repository database
|
||||||
"""
|
"""
|
||||||
Repo._check_output(
|
Repo._check_output("repo-add", *self.sign_args, str(self.repo_path),
|
||||||
"repo-add", *self.sign_args, str(self.repo_path),
|
cwd=self.paths.repository, logger=self.logger, user=self.uid)
|
||||||
exception=None,
|
|
||||||
cwd=self.paths.repository,
|
|
||||||
logger=self.logger,
|
|
||||||
user=self.uid)
|
|
||||||
|
|
||||||
def remove(self, package: str, filename: Path) -> None:
|
def remove(self, package: str, filename: Path) -> None:
|
||||||
"""
|
"""
|
||||||
@ -103,7 +99,7 @@ class Repo(LazyLogging):
|
|||||||
# remove package from registry
|
# remove package from registry
|
||||||
Repo._check_output(
|
Repo._check_output(
|
||||||
"repo-remove", *self.sign_args, str(self.repo_path), package,
|
"repo-remove", *self.sign_args, str(self.repo_path), package,
|
||||||
exception=BuildFailed(package),
|
exception=BuildError(package),
|
||||||
cwd=self.paths.repository,
|
cwd=self.paths.repository,
|
||||||
logger=self.logger,
|
logger=self.logger,
|
||||||
user=self.uid)
|
user=self.uid)
|
||||||
|
@ -24,7 +24,7 @@ from typing import Optional, Type
|
|||||||
from ahriman.core.auth import Mapping
|
from ahriman.core.auth import Mapping
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
from ahriman.core.database import SQLite
|
from ahriman.core.database import SQLite
|
||||||
from ahriman.core.exceptions import InvalidOption
|
from ahriman.core.exceptions import OptionError
|
||||||
from ahriman.models.auth_settings import AuthSettings
|
from ahriman.models.auth_settings import AuthSettings
|
||||||
|
|
||||||
|
|
||||||
@ -91,7 +91,7 @@ class OAuth(Mapping):
|
|||||||
except TypeError: # what if it is random string?
|
except TypeError: # what if it is random string?
|
||||||
is_oauth2_client = False
|
is_oauth2_client = False
|
||||||
if not is_oauth2_client:
|
if not is_oauth2_client:
|
||||||
raise InvalidOption(name)
|
raise OptionError(name)
|
||||||
return provider
|
return provider
|
||||||
|
|
||||||
def get_client(self) -> aioauth_client.OAuth2Client:
|
def get_client(self) -> aioauth_client.OAuth2Client:
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
|
import datetime
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@ -44,24 +45,22 @@ class Sources(LazyLogging):
|
|||||||
_check_output = check_output
|
_check_output = check_output
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def extend_architectures(sources_dir: Path, architecture: str) -> None:
|
def extend_architectures(sources_dir: Path, architecture: str) -> List[PkgbuildPatch]:
|
||||||
"""
|
"""
|
||||||
extend existing PKGBUILD with repository architecture
|
extend existing PKGBUILD with repository architecture
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
sources_dir(Path): local path to directory with source files
|
sources_dir(Path): local path to directory with source files
|
||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
"""
|
|
||||||
pkgbuild_path = sources_dir / "PKGBUILD"
|
|
||||||
if not pkgbuild_path.is_file():
|
|
||||||
return
|
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[PkgbuildPatch]: generated patch for PKGBUILD architectures if required
|
||||||
|
"""
|
||||||
architectures = Package.supported_architectures(sources_dir)
|
architectures = Package.supported_architectures(sources_dir)
|
||||||
if "any" in architectures: # makepkg does not like when there is any other arch except for any
|
if "any" in architectures: # makepkg does not like when there is any other arch except for any
|
||||||
return
|
return []
|
||||||
architectures.add(architecture)
|
architectures.add(architecture)
|
||||||
patch = PkgbuildPatch("arch", list(architectures))
|
return [PkgbuildPatch("arch", list(architectures))]
|
||||||
patch.write(pkgbuild_path)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def fetch(sources_dir: Path, remote: Optional[RemoteSource]) -> None:
|
def fetch(sources_dir: Path, remote: Optional[RemoteSource]) -> None:
|
||||||
@ -83,22 +82,18 @@ class Sources(LazyLogging):
|
|||||||
branch = remote.branch if remote is not None else instance.DEFAULT_BRANCH
|
branch = remote.branch if remote is not None else instance.DEFAULT_BRANCH
|
||||||
if is_initialized_git:
|
if is_initialized_git:
|
||||||
instance.logger.info("update HEAD to remote at %s using branch %s", sources_dir, branch)
|
instance.logger.info("update HEAD to remote at %s using branch %s", sources_dir, branch)
|
||||||
Sources._check_output("git", "fetch", "origin", branch,
|
Sources._check_output("git", "fetch", "origin", branch, cwd=sources_dir, logger=instance.logger)
|
||||||
exception=None, cwd=sources_dir, logger=instance.logger)
|
|
||||||
elif remote is not None:
|
elif remote is not None:
|
||||||
instance.logger.info("clone remote %s to %s using branch %s", remote.git_url, sources_dir, branch)
|
instance.logger.info("clone remote %s to %s using branch %s", remote.git_url, sources_dir, branch)
|
||||||
Sources._check_output("git", "clone", "--branch", branch, "--single-branch",
|
Sources._check_output("git", "clone", "--branch", branch, "--single-branch",
|
||||||
remote.git_url, str(sources_dir),
|
remote.git_url, str(sources_dir), cwd=sources_dir.parent, logger=instance.logger)
|
||||||
exception=None, cwd=sources_dir, logger=instance.logger)
|
|
||||||
else:
|
else:
|
||||||
# it will cause an exception later
|
# it will cause an exception later
|
||||||
instance.logger.error("%s is not initialized, but no remote provided", sources_dir)
|
instance.logger.error("%s is not initialized, but no remote provided", sources_dir)
|
||||||
|
|
||||||
# and now force reset to our branch
|
# and now force reset to our branch
|
||||||
Sources._check_output("git", "checkout", "--force", branch,
|
Sources._check_output("git", "checkout", "--force", branch, cwd=sources_dir, logger=instance.logger)
|
||||||
exception=None, cwd=sources_dir, logger=instance.logger)
|
Sources._check_output("git", "reset", "--hard", f"origin/{branch}", cwd=sources_dir, logger=instance.logger)
|
||||||
Sources._check_output("git", "reset", "--hard", f"origin/{branch}",
|
|
||||||
exception=None, cwd=sources_dir, logger=instance.logger)
|
|
||||||
|
|
||||||
# move content if required
|
# move content if required
|
||||||
# we are using full path to source directory in order to make append possible
|
# we are using full path to source directory in order to make append possible
|
||||||
@ -117,7 +112,7 @@ class Sources(LazyLogging):
|
|||||||
bool: True in case if there is any remote and false otherwise
|
bool: True in case if there is any remote and false otherwise
|
||||||
"""
|
"""
|
||||||
instance = Sources()
|
instance = Sources()
|
||||||
remotes = Sources._check_output("git", "remote", exception=None, cwd=sources_dir, logger=instance.logger)
|
remotes = Sources._check_output("git", "remote", cwd=sources_dir, logger=instance.logger)
|
||||||
return bool(remotes)
|
return bool(remotes)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -130,17 +125,17 @@ class Sources(LazyLogging):
|
|||||||
"""
|
"""
|
||||||
instance = Sources()
|
instance = Sources()
|
||||||
Sources._check_output("git", "init", "--initial-branch", instance.DEFAULT_BRANCH,
|
Sources._check_output("git", "init", "--initial-branch", instance.DEFAULT_BRANCH,
|
||||||
exception=None, cwd=sources_dir, logger=instance.logger)
|
cwd=sources_dir, logger=instance.logger)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def load(sources_dir: Path, package: Package, patch: Optional[str], paths: RepositoryPaths) -> None:
|
def load(sources_dir: Path, package: Package, patches: List[PkgbuildPatch], paths: RepositoryPaths) -> None:
|
||||||
"""
|
"""
|
||||||
fetch sources from remote and apply patches
|
fetch sources from remote and apply patches
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
sources_dir(Path): local path to fetch
|
sources_dir(Path): local path to fetch
|
||||||
package(Package): package definitions
|
package(Package): package definitions
|
||||||
patch(Optional[str]): optional patch to be applied
|
patches(List[PkgbuildPatch]): optional patch to be applied
|
||||||
paths(RepositoryPaths): repository paths instance
|
paths(RepositoryPaths): repository paths instance
|
||||||
"""
|
"""
|
||||||
instance = Sources()
|
instance = Sources()
|
||||||
@ -149,9 +144,9 @@ class Sources(LazyLogging):
|
|||||||
shutil.copytree(cache_dir, sources_dir, dirs_exist_ok=True)
|
shutil.copytree(cache_dir, sources_dir, dirs_exist_ok=True)
|
||||||
instance.fetch(sources_dir, package.remote)
|
instance.fetch(sources_dir, package.remote)
|
||||||
|
|
||||||
if patch is not None:
|
patches.extend(instance.extend_architectures(sources_dir, paths.architecture))
|
||||||
|
for patch in patches:
|
||||||
instance.patch_apply(sources_dir, patch)
|
instance.patch_apply(sources_dir, patch)
|
||||||
instance.extend_architectures(sources_dir, paths.architecture)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def patch_create(sources_dir: Path, *pattern: str) -> str:
|
def patch_create(sources_dir: Path, *pattern: str) -> str:
|
||||||
@ -166,17 +161,34 @@ class Sources(LazyLogging):
|
|||||||
str: patch as plain text
|
str: patch as plain text
|
||||||
"""
|
"""
|
||||||
instance = Sources()
|
instance = Sources()
|
||||||
instance.add(sources_dir, *pattern)
|
instance.add(sources_dir, *pattern, intent_to_add=True)
|
||||||
diff = instance.diff(sources_dir)
|
diff = instance.diff(sources_dir)
|
||||||
return f"{diff}\n" # otherwise, patch will be broken
|
return f"{diff}\n" # otherwise, patch will be broken
|
||||||
|
|
||||||
def add(self, sources_dir: Path, *pattern: str) -> None:
|
@staticmethod
|
||||||
|
def push(sources_dir: Path, remote: RemoteSource, *pattern: str, commit_author: Optional[str] = None) -> None:
|
||||||
|
"""
|
||||||
|
commit selected changes and push files to the remote repository
|
||||||
|
|
||||||
|
Args:
|
||||||
|
sources_dir(Path): local path to git repository
|
||||||
|
remote(RemoteSource): remote target, branch and url
|
||||||
|
*pattern(str): glob patterns
|
||||||
|
commit_author(Optional[str]): commit author in form of git config (i.e. ``user <user@host>``)
|
||||||
|
"""
|
||||||
|
instance = Sources()
|
||||||
|
instance.add(sources_dir, *pattern)
|
||||||
|
instance.commit(sources_dir, author=commit_author)
|
||||||
|
Sources._check_output("git", "push", remote.git_url, remote.branch, cwd=sources_dir, logger=instance.logger)
|
||||||
|
|
||||||
|
def add(self, sources_dir: Path, *pattern: str, intent_to_add: bool = False) -> None:
|
||||||
"""
|
"""
|
||||||
track found files via git
|
track found files via git
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
sources_dir(Path): local path to git repository
|
sources_dir(Path): local path to git repository
|
||||||
*pattern(str): glob patterns
|
*pattern(str): glob patterns
|
||||||
|
intent_to_add(bool): record only the fact that it will be added later, acts as --intent-to-add git flag
|
||||||
"""
|
"""
|
||||||
# glob directory to find files which match the specified patterns
|
# glob directory to find files which match the specified patterns
|
||||||
found_files: List[Path] = []
|
found_files: List[Path] = []
|
||||||
@ -186,9 +198,26 @@ class Sources(LazyLogging):
|
|||||||
return # no additional files found
|
return # no additional files found
|
||||||
self.logger.info("found matching files %s", found_files)
|
self.logger.info("found matching files %s", found_files)
|
||||||
# add them to index
|
# add them to index
|
||||||
Sources._check_output("git", "add", "--intent-to-add",
|
args = ["--intent-to-add"] if intent_to_add else []
|
||||||
*[str(fn.relative_to(sources_dir)) for fn in found_files],
|
Sources._check_output("git", "add", *args, *[str(fn.relative_to(sources_dir)) for fn in found_files],
|
||||||
exception=None, cwd=sources_dir, logger=self.logger)
|
cwd=sources_dir, logger=self.logger)
|
||||||
|
|
||||||
|
def commit(self, sources_dir: Path, message: Optional[str] = None, author: Optional[str] = None) -> None:
|
||||||
|
"""
|
||||||
|
commit changes
|
||||||
|
|
||||||
|
Args:
|
||||||
|
sources_dir(Path): local path to git repository
|
||||||
|
message(Optional[str]): optional commit message if any. If none set, message will be generated according to
|
||||||
|
the current timestamp
|
||||||
|
author(Optional[str]): optional commit author if any
|
||||||
|
"""
|
||||||
|
if message is None:
|
||||||
|
message = f"Autogenerated commit at {datetime.datetime.utcnow()}"
|
||||||
|
args = ["--allow-empty", "--message", message]
|
||||||
|
if author is not None:
|
||||||
|
args.extend(["--author", author])
|
||||||
|
Sources._check_output("git", "commit", *args, cwd=sources_dir, logger=self.logger)
|
||||||
|
|
||||||
def diff(self, sources_dir: Path) -> str:
|
def diff(self, sources_dir: Path) -> str:
|
||||||
"""
|
"""
|
||||||
@ -200,7 +229,7 @@ class Sources(LazyLogging):
|
|||||||
Returns:
|
Returns:
|
||||||
str: patch as plain string
|
str: patch as plain string
|
||||||
"""
|
"""
|
||||||
return Sources._check_output("git", "diff", exception=None, cwd=sources_dir, logger=self.logger)
|
return Sources._check_output("git", "diff", cwd=sources_dir, logger=self.logger)
|
||||||
|
|
||||||
def move(self, pkgbuild_dir: Path, sources_dir: Path) -> None:
|
def move(self, pkgbuild_dir: Path, sources_dir: Path) -> None:
|
||||||
"""
|
"""
|
||||||
@ -217,15 +246,18 @@ class Sources(LazyLogging):
|
|||||||
dst = sources_dir / src.relative_to(pkgbuild_dir)
|
dst = sources_dir / src.relative_to(pkgbuild_dir)
|
||||||
shutil.move(src, dst)
|
shutil.move(src, dst)
|
||||||
|
|
||||||
def patch_apply(self, sources_dir: Path, patch: str) -> None:
|
def patch_apply(self, sources_dir: Path, patch: PkgbuildPatch) -> None:
|
||||||
"""
|
"""
|
||||||
apply patches if any
|
apply patches if any
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
sources_dir(Path): local path to directory with git sources
|
sources_dir(Path): local path to directory with git sources
|
||||||
patch(str): patch to be applied
|
patch(PkgbuildPatch): patch to be applied
|
||||||
"""
|
"""
|
||||||
# create patch
|
# create patch
|
||||||
self.logger.info("apply patch from database")
|
self.logger.info("apply patch %s from database at %s", patch.key, sources_dir)
|
||||||
Sources._check_output("git", "apply", "--ignore-space-change", "--ignore-whitespace",
|
if patch.is_plain_diff:
|
||||||
exception=None, cwd=sources_dir, input_data=patch, logger=self.logger)
|
Sources._check_output("git", "apply", "--ignore-space-change", "--ignore-whitespace",
|
||||||
|
cwd=sources_dir, input_data=patch.serialize(), logger=self.logger)
|
||||||
|
else:
|
||||||
|
patch.write(sources_dir / "PKGBUILD")
|
||||||
|
@ -23,7 +23,7 @@ from typing import List
|
|||||||
from ahriman.core.build_tools.sources import Sources
|
from ahriman.core.build_tools.sources import Sources
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
from ahriman.core.database import SQLite
|
from ahriman.core.database import SQLite
|
||||||
from ahriman.core.exceptions import BuildFailed
|
from ahriman.core.exceptions import BuildError
|
||||||
from ahriman.core.lazy_logging import LazyLogging
|
from ahriman.core.lazy_logging import LazyLogging
|
||||||
from ahriman.core.util import check_output
|
from ahriman.core.util import check_output
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
@ -78,14 +78,14 @@ class Task(LazyLogging):
|
|||||||
|
|
||||||
Task._check_output(
|
Task._check_output(
|
||||||
*command,
|
*command,
|
||||||
exception=BuildFailed(self.package.base),
|
exception=BuildError(self.package.base),
|
||||||
cwd=sources_dir,
|
cwd=sources_dir,
|
||||||
logger=self.logger,
|
logger=self.logger,
|
||||||
user=self.uid)
|
user=self.uid)
|
||||||
|
|
||||||
# well it is not actually correct, but we can deal with it
|
# well it is not actually correct, but we can deal with it
|
||||||
packages = Task._check_output("makepkg", "--packagelist",
|
packages = Task._check_output("makepkg", "--packagelist",
|
||||||
exception=BuildFailed(self.package.base),
|
exception=BuildError(self.package.base),
|
||||||
cwd=sources_dir,
|
cwd=sources_dir,
|
||||||
logger=self.logger).splitlines()
|
logger=self.logger).splitlines()
|
||||||
return [Path(package) for package in packages]
|
return [Path(package) for package in packages]
|
||||||
|
@ -27,7 +27,7 @@ from logging.config import fileConfig
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict, Generator, List, Optional, Tuple, Type
|
from typing import Any, Dict, Generator, List, Optional, Tuple, Type
|
||||||
|
|
||||||
from ahriman.core.exceptions import InitializeException
|
from ahriman.core.exceptions import InitializeError
|
||||||
from ahriman.models.repository_paths import RepositoryPaths
|
from ahriman.models.repository_paths import RepositoryPaths
|
||||||
|
|
||||||
|
|
||||||
@ -70,11 +70,15 @@ class Configuration(configparser.RawConfigParser):
|
|||||||
ARCHITECTURE_SPECIFIC_SECTIONS = ["build", "sign", "web"]
|
ARCHITECTURE_SPECIFIC_SECTIONS = ["build", "sign", "web"]
|
||||||
SYSTEM_CONFIGURATION_PATH = Path(sys.prefix) / "share" / "ahriman" / "settings" / "ahriman.ini"
|
SYSTEM_CONFIGURATION_PATH = Path(sys.prefix) / "share" / "ahriman" / "settings" / "ahriman.ini"
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self, allow_no_value: bool = False) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor. In the most cases must not be called directly
|
default constructor. In the most cases must not be called directly
|
||||||
|
|
||||||
|
Args:
|
||||||
|
allow_no_value(bool): copies ``configparser.RawConfigParser`` behaviour. In case if it is set to ``True``,
|
||||||
|
the keys without values will be allowed
|
||||||
"""
|
"""
|
||||||
configparser.RawConfigParser.__init__(self, allow_no_value=True, converters={
|
configparser.RawConfigParser.__init__(self, allow_no_value=allow_no_value, converters={
|
||||||
"list": self.__convert_list,
|
"list": self.__convert_list,
|
||||||
"path": self.__convert_path,
|
"path": self.__convert_path,
|
||||||
})
|
})
|
||||||
@ -204,7 +208,7 @@ class Configuration(configparser.RawConfigParser):
|
|||||||
InitializeException: in case if architecture and/or path are not set
|
InitializeException: in case if architecture and/or path are not set
|
||||||
"""
|
"""
|
||||||
if self.path is None or self.architecture is None:
|
if self.path is None or self.architecture is None:
|
||||||
raise InitializeException("Configuration path and/or architecture are not set")
|
raise InitializeError("Configuration path and/or architecture are not set")
|
||||||
return self.path, self.architecture
|
return self.path, self.architecture
|
||||||
|
|
||||||
def dump(self) -> Dict[str, Dict[str, str]]:
|
def dump(self) -> Dict[str, Dict[str, str]]:
|
||||||
@ -221,14 +225,14 @@ class Configuration(configparser.RawConfigParser):
|
|||||||
|
|
||||||
# pylint and mypy are too stupid to find these methods
|
# pylint and mypy are too stupid to find these methods
|
||||||
# pylint: disable=missing-function-docstring,multiple-statements,unused-argument
|
# pylint: disable=missing-function-docstring,multiple-statements,unused-argument
|
||||||
def getlist(self, *args: Any, **kwargs: Any) -> List[str]: ...
|
def getlist(self, *args: Any, **kwargs: Any) -> List[str]: ... # type: ignore
|
||||||
|
|
||||||
def getpath(self, *args: Any, **kwargs: Any) -> Path: ...
|
def getpath(self, *args: Any, **kwargs: Any) -> Path: ... # type: ignore
|
||||||
|
|
||||||
def gettype(self, section: str, architecture: str) -> Tuple[str, str]:
|
def gettype(self, section: str, architecture: str) -> Tuple[str, str]:
|
||||||
"""
|
"""
|
||||||
get type variable with fallback to old logic
|
get type variable with fallback to old logic. Despite the fact that it has same semantics as other get* methods,
|
||||||
Despite the fact that it has same semantics as other get* methods, but it has different argument list
|
but it has different argument list
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
section(str): section name
|
section(str): section name
|
||||||
|
43
src/ahriman/core/database/migrations/m003_patch_variables.py
Normal file
43
src/ahriman/core/database/migrations/m003_patch_variables.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#
|
||||||
|
# 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/>.
|
||||||
|
#
|
||||||
|
__all__ = ["steps"]
|
||||||
|
|
||||||
|
|
||||||
|
steps = [
|
||||||
|
"""
|
||||||
|
alter table patches rename to patches_
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
create table patches (
|
||||||
|
package_base text not null,
|
||||||
|
variable text,
|
||||||
|
patch blob not null
|
||||||
|
)
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
create unique index patches_package_base_variable on patches (package_base, coalesce(variable, ''))
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
insert into patches (package_base, patch) select package_base, patch from patches_
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
drop table patches_
|
||||||
|
""",
|
||||||
|
]
|
@ -20,7 +20,6 @@
|
|||||||
import sqlite3
|
import sqlite3
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from sqlite3 import Connection, Cursor
|
|
||||||
from typing import Any, Dict, Tuple, TypeVar, Callable
|
from typing import Any, Dict, Tuple, TypeVar, Callable
|
||||||
|
|
||||||
from ahriman.core.lazy_logging import LazyLogging
|
from ahriman.core.lazy_logging import LazyLogging
|
||||||
@ -46,7 +45,7 @@ class Operations(LazyLogging):
|
|||||||
self.path = path
|
self.path = path
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def factory(cursor: Cursor, row: Tuple[Any, ...]) -> Dict[str, Any]:
|
def factory(cursor: sqlite3.Cursor, row: Tuple[Any, ...]) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
dictionary factory based on official documentation
|
dictionary factory based on official documentation
|
||||||
|
|
||||||
@ -62,7 +61,7 @@ class Operations(LazyLogging):
|
|||||||
result[column[0]] = row[index]
|
result[column[0]] = row[index]
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def with_connection(self, query: Callable[[Connection], T], commit: bool = False) -> T:
|
def with_connection(self, query: Callable[[sqlite3.Connection], T], *, commit: bool = False) -> T:
|
||||||
"""
|
"""
|
||||||
perform operation in connection
|
perform operation in connection
|
||||||
|
|
||||||
|
@ -17,10 +17,13 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
from sqlite3 import Connection
|
from sqlite3 import Connection
|
||||||
from typing import Dict, Optional
|
from typing import Dict, List, Optional, Tuple
|
||||||
|
|
||||||
from ahriman.core.database.operations import Operations
|
from ahriman.core.database.operations import Operations
|
||||||
|
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
||||||
|
|
||||||
|
|
||||||
class PatchOperations(Operations):
|
class PatchOperations(Operations):
|
||||||
@ -28,7 +31,7 @@ class PatchOperations(Operations):
|
|||||||
operations for patches
|
operations for patches
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def patches_get(self, package_base: str) -> Optional[str]:
|
def patches_get(self, package_base: str) -> List[PkgbuildPatch]:
|
||||||
"""
|
"""
|
||||||
retrieve patches for the package
|
retrieve patches for the package
|
||||||
|
|
||||||
@ -36,62 +39,77 @@ class PatchOperations(Operations):
|
|||||||
package_base(str): package base to search for patches
|
package_base(str): package base to search for patches
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Optional[str]: plain text patch for the package
|
List[PkgbuildPatch]: plain text patch for the package
|
||||||
"""
|
"""
|
||||||
return self.patches_list(package_base).get(package_base)
|
return self.patches_list(package_base, []).get(package_base, [])
|
||||||
|
|
||||||
def patches_insert(self, package_base: str, patch: str) -> None:
|
def patches_insert(self, package_base: str, patch: PkgbuildPatch) -> None:
|
||||||
"""
|
"""
|
||||||
insert or update patch in database
|
insert or update patch in database
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
package_base(str): package base to insert
|
package_base(str): package base to insert
|
||||||
patch(str): patch content
|
patch(PkgbuildPatch): patch content
|
||||||
"""
|
"""
|
||||||
def run(connection: Connection) -> None:
|
def run(connection: Connection) -> None:
|
||||||
connection.execute(
|
connection.execute(
|
||||||
"""
|
"""
|
||||||
insert into patches
|
insert into patches
|
||||||
(package_base, patch)
|
(package_base, variable, patch)
|
||||||
values
|
values
|
||||||
(:package_base, :patch)
|
(:package_base, :variable, :patch)
|
||||||
on conflict (package_base) do update set
|
on conflict (package_base, coalesce(variable, '')) do update set
|
||||||
patch = :patch
|
patch = :patch
|
||||||
""",
|
""",
|
||||||
{"package_base": package_base, "patch": patch})
|
{"package_base": package_base, "variable": patch.key, "patch": patch.value})
|
||||||
|
|
||||||
return self.with_connection(run, commit=True)
|
return self.with_connection(run, commit=True)
|
||||||
|
|
||||||
def patches_list(self, package_base: Optional[str]) -> Dict[str, str]:
|
def patches_list(self, package_base: Optional[str], variables: List[str]) -> Dict[str, List[PkgbuildPatch]]:
|
||||||
"""
|
"""
|
||||||
extract all patches
|
extract all patches
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
package_base(Optional[str]): optional filter by package base
|
package_base(Optional[str]): optional filter by package base
|
||||||
|
variables(List[str]): extract patches only for specified PKGBUILD variables
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Dict[str, str]: map of package base to patch content
|
Dict[str, List[PkgbuildPatch]]: map of package base to patch content
|
||||||
"""
|
"""
|
||||||
def run(connection: Connection) -> Dict[str, str]:
|
def run(connection: Connection) -> List[Tuple[str, PkgbuildPatch]]:
|
||||||
return {
|
return [
|
||||||
cursor["package_base"]: cursor["patch"]
|
(cursor["package_base"], PkgbuildPatch(cursor["variable"], cursor["patch"]))
|
||||||
for cursor in connection.execute(
|
for cursor in connection.execute(
|
||||||
"""select * from patches where :package_base is null or package_base = :package_base""",
|
"""select * from patches where :package_base is null or package_base = :package_base""",
|
||||||
{"package_base": package_base})
|
{"package_base": package_base})
|
||||||
}
|
]
|
||||||
|
|
||||||
return self.with_connection(run)
|
# we could use itertools & operator but why?
|
||||||
|
patches: Dict[str, List[PkgbuildPatch]] = defaultdict(list)
|
||||||
|
for package, patch in self.with_connection(run):
|
||||||
|
if variables and patch.key not in variables:
|
||||||
|
continue
|
||||||
|
patches[package].append(patch)
|
||||||
|
return dict(patches)
|
||||||
|
|
||||||
def patches_remove(self, package_base: str) -> None:
|
def patches_remove(self, package_base: str, variables: List[str]) -> None:
|
||||||
"""
|
"""
|
||||||
remove patch set
|
remove patch set
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
package_base(str): package base to clear patches
|
package_base(str): package base to clear patches
|
||||||
|
variables(List[str]): remove patches only for specified PKGBUILD variables
|
||||||
"""
|
"""
|
||||||
|
def run_many(connection: Connection) -> None:
|
||||||
|
connection.executemany(
|
||||||
|
"""delete from patches where package_base = :package_base and variable = :variable""",
|
||||||
|
[{"package_base": package_base, "variable": variable} for variable in variables])
|
||||||
|
|
||||||
def run(connection: Connection) -> None:
|
def run(connection: Connection) -> None:
|
||||||
connection.execute(
|
connection.execute(
|
||||||
"""delete from patches where package_base = :package_base""",
|
"""delete from patches where package_base = :package_base""",
|
||||||
{"package_base": package_base})
|
{"package_base": package_base})
|
||||||
|
|
||||||
|
if variables:
|
||||||
|
return self.with_connection(run_many, commit=True)
|
||||||
return self.with_connection(run, commit=True)
|
return self.with_connection(run, commit=True)
|
||||||
|
@ -21,7 +21,7 @@ from pathlib import Path
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
class BuildFailed(RuntimeError):
|
class BuildError(RuntimeError):
|
||||||
"""
|
"""
|
||||||
base exception for failed builds
|
base exception for failed builds
|
||||||
"""
|
"""
|
||||||
@ -36,7 +36,7 @@ class BuildFailed(RuntimeError):
|
|||||||
RuntimeError.__init__(self, f"Package {package_base} build failed, check logs for details")
|
RuntimeError.__init__(self, f"Package {package_base} build failed, check logs for details")
|
||||||
|
|
||||||
|
|
||||||
class DuplicateRun(RuntimeError):
|
class DuplicateRunError(RuntimeError):
|
||||||
"""
|
"""
|
||||||
exception which will be raised if there is another application instance
|
exception which will be raised if there is another application instance
|
||||||
"""
|
"""
|
||||||
@ -55,7 +55,25 @@ class ExitCode(RuntimeError):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class InitializeException(RuntimeError):
|
class ExtensionError(RuntimeError):
|
||||||
|
"""
|
||||||
|
exception being raised by trigger load in case of errors
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class GitRemoteError(RuntimeError):
|
||||||
|
"""
|
||||||
|
git remote exception
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
"""
|
||||||
|
default constructor
|
||||||
|
"""
|
||||||
|
RuntimeError.__init__(self, "Git remote failed")
|
||||||
|
|
||||||
|
|
||||||
|
class InitializeError(RuntimeError):
|
||||||
"""
|
"""
|
||||||
base service initialization exception
|
base service initialization exception
|
||||||
"""
|
"""
|
||||||
@ -70,58 +88,6 @@ class InitializeException(RuntimeError):
|
|||||||
RuntimeError.__init__(self, f"Could not load service: {details}")
|
RuntimeError.__init__(self, f"Could not load service: {details}")
|
||||||
|
|
||||||
|
|
||||||
class InvalidExtension(RuntimeError):
|
|
||||||
"""
|
|
||||||
exception being raised by trigger load in case of errors
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class InvalidOption(ValueError):
|
|
||||||
"""
|
|
||||||
exception which will be raised on configuration errors
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, value: Any) -> None:
|
|
||||||
"""
|
|
||||||
default constructor
|
|
||||||
|
|
||||||
Args:
|
|
||||||
value(Any): option value
|
|
||||||
"""
|
|
||||||
ValueError.__init__(self, f"Invalid or unknown option value `{value}`")
|
|
||||||
|
|
||||||
|
|
||||||
class InvalidPath(ValueError):
|
|
||||||
"""
|
|
||||||
exception which will be raised on path which is not belong to root directory
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, path: Path, root: Path) -> None:
|
|
||||||
"""
|
|
||||||
default constructor
|
|
||||||
|
|
||||||
Args:
|
|
||||||
path(Path): path which raised an exception
|
|
||||||
root(Path): repository root (i.e. ahriman home)
|
|
||||||
"""
|
|
||||||
ValueError.__init__(self, f"Path `{path}` does not belong to repository root `{root}`")
|
|
||||||
|
|
||||||
|
|
||||||
class InvalidPackageInfo(RuntimeError):
|
|
||||||
"""
|
|
||||||
exception which will be raised on package load errors
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, details: Any) -> None:
|
|
||||||
"""
|
|
||||||
default constructor
|
|
||||||
|
|
||||||
Args:
|
|
||||||
details(Any): error details
|
|
||||||
"""
|
|
||||||
RuntimeError.__init__(self, f"There are errors during reading package information: `{details}`")
|
|
||||||
|
|
||||||
|
|
||||||
class MigrationError(RuntimeError):
|
class MigrationError(RuntimeError):
|
||||||
"""
|
"""
|
||||||
exception which will be raised on migration error
|
exception which will be raised on migration error
|
||||||
@ -137,7 +103,7 @@ class MigrationError(RuntimeError):
|
|||||||
RuntimeError.__init__(self, details)
|
RuntimeError.__init__(self, details)
|
||||||
|
|
||||||
|
|
||||||
class MissingArchitecture(ValueError):
|
class MissingArchitectureError(ValueError):
|
||||||
"""
|
"""
|
||||||
exception which will be raised if architecture is required, but missing
|
exception which will be raised if architecture is required, but missing
|
||||||
"""
|
"""
|
||||||
@ -152,7 +118,7 @@ class MissingArchitecture(ValueError):
|
|||||||
ValueError.__init__(self, f"Architecture required for subcommand {command}, but missing")
|
ValueError.__init__(self, f"Architecture required for subcommand {command}, but missing")
|
||||||
|
|
||||||
|
|
||||||
class MultipleArchitectures(ValueError):
|
class MultipleArchitecturesError(ValueError):
|
||||||
"""
|
"""
|
||||||
exception which will be raised if multiple architectures are not supported by the handler
|
exception which will be raised if multiple architectures are not supported by the handler
|
||||||
"""
|
"""
|
||||||
@ -167,7 +133,53 @@ class MultipleArchitectures(ValueError):
|
|||||||
ValueError.__init__(self, f"Multiple architectures are not supported by subcommand {command}")
|
ValueError.__init__(self, f"Multiple architectures are not supported by subcommand {command}")
|
||||||
|
|
||||||
|
|
||||||
class ReportFailed(RuntimeError):
|
class OptionError(ValueError):
|
||||||
|
"""
|
||||||
|
exception which will be raised on configuration errors
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, value: Any) -> None:
|
||||||
|
"""
|
||||||
|
default constructor
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value(Any): option value
|
||||||
|
"""
|
||||||
|
ValueError.__init__(self, f"Invalid or unknown option value `{value}`")
|
||||||
|
|
||||||
|
|
||||||
|
class PackageInfoError(RuntimeError):
|
||||||
|
"""
|
||||||
|
exception which will be raised on package load errors
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, details: Any) -> None:
|
||||||
|
"""
|
||||||
|
default constructor
|
||||||
|
|
||||||
|
Args:
|
||||||
|
details(Any): error details
|
||||||
|
"""
|
||||||
|
RuntimeError.__init__(self, f"There are errors during reading package information: `{details}`")
|
||||||
|
|
||||||
|
|
||||||
|
class PathError(ValueError):
|
||||||
|
"""
|
||||||
|
exception which will be raised on path which is not belong to root directory
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, path: Path, root: Path) -> None:
|
||||||
|
"""
|
||||||
|
default constructor
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path(Path): path which raised an exception
|
||||||
|
root(Path): repository root (i.e. ahriman home)
|
||||||
|
"""
|
||||||
|
ValueError.__init__(self, f"Path `{path}` does not belong to repository root `{root}`")
|
||||||
|
|
||||||
|
|
||||||
|
class ReportError(RuntimeError):
|
||||||
"""
|
"""
|
||||||
report generation exception
|
report generation exception
|
||||||
"""
|
"""
|
||||||
@ -179,22 +191,7 @@ class ReportFailed(RuntimeError):
|
|||||||
RuntimeError.__init__(self, "Report failed")
|
RuntimeError.__init__(self, "Report failed")
|
||||||
|
|
||||||
|
|
||||||
class SuccessFailed(ValueError):
|
class SynchronizationError(RuntimeError):
|
||||||
"""
|
|
||||||
exception for merging invalid statues
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, package_base: str) -> None:
|
|
||||||
"""
|
|
||||||
default constructor
|
|
||||||
|
|
||||||
Args:
|
|
||||||
package_base(str): package base name
|
|
||||||
"""
|
|
||||||
ValueError.__init__(self, f"Package base {package_base} had status failed, but new status is success")
|
|
||||||
|
|
||||||
|
|
||||||
class SyncFailed(RuntimeError):
|
|
||||||
"""
|
"""
|
||||||
remote synchronization exception
|
remote synchronization exception
|
||||||
"""
|
"""
|
||||||
@ -206,7 +203,7 @@ class SyncFailed(RuntimeError):
|
|||||||
RuntimeError.__init__(self, "Sync failed")
|
RuntimeError.__init__(self, "Sync failed")
|
||||||
|
|
||||||
|
|
||||||
class UnknownPackage(ValueError):
|
class UnknownPackageError(ValueError):
|
||||||
"""
|
"""
|
||||||
exception for status watcher which will be thrown on unknown package
|
exception for status watcher which will be thrown on unknown package
|
||||||
"""
|
"""
|
||||||
@ -221,7 +218,22 @@ class UnknownPackage(ValueError):
|
|||||||
ValueError.__init__(self, f"Package base {package_base} is unknown")
|
ValueError.__init__(self, f"Package base {package_base} is unknown")
|
||||||
|
|
||||||
|
|
||||||
class UnsafeRun(RuntimeError):
|
class UnprocessedPackageStatusError(ValueError):
|
||||||
|
"""
|
||||||
|
exception for merging invalid statues
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, package_base: str) -> None:
|
||||||
|
"""
|
||||||
|
default constructor
|
||||||
|
|
||||||
|
Args:
|
||||||
|
package_base(str): package base name
|
||||||
|
"""
|
||||||
|
ValueError.__init__(self, f"Package base {package_base} had status failed, but new status is success")
|
||||||
|
|
||||||
|
|
||||||
|
class UnsafeRunError(RuntimeError):
|
||||||
"""
|
"""
|
||||||
exception which will be raised in case if user is not owner of repository
|
exception which will be raised in case if user is not owner of repository
|
||||||
"""
|
"""
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
#
|
#
|
||||||
# copyright (c) 2021-2022 ahriman team.
|
# Copyright (c) 2021-2022 ahriman team.
|
||||||
#
|
#
|
||||||
# this file is part of ahriman
|
# This file is part of ahriman
|
||||||
# (see https://github.com/arcan1s/ahriman).
|
# (see https://github.com/arcan1s/ahriman).
|
||||||
#
|
#
|
||||||
# this program is free software: you can redistribute it and/or modify
|
# 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
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the free software foundation, either version 3 of the license, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# this program is distributed in the hope that it will be useful,
|
# This program is distributed in the hope that it will be useful,
|
||||||
# but without any warranty; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# merchantability or fitness for a particular purpose. see the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# gnu general public license for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# you should have received a copy of the gnu general public license
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. if not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
from ahriman.core.formatters.printer import Printer
|
from ahriman.core.formatters.printer import Printer
|
||||||
from ahriman.core.formatters.string_printer import StringPrinter
|
from ahriman.core.formatters.string_printer import StringPrinter
|
||||||
@ -24,6 +24,7 @@ from ahriman.core.formatters.aur_printer import AurPrinter
|
|||||||
from ahriman.core.formatters.build_printer import BuildPrinter
|
from ahriman.core.formatters.build_printer import BuildPrinter
|
||||||
from ahriman.core.formatters.configuration_printer import ConfigurationPrinter
|
from ahriman.core.formatters.configuration_printer import ConfigurationPrinter
|
||||||
from ahriman.core.formatters.package_printer import PackagePrinter
|
from ahriman.core.formatters.package_printer import PackagePrinter
|
||||||
|
from ahriman.core.formatters.patch_printer import PatchPrinter
|
||||||
from ahriman.core.formatters.status_printer import StatusPrinter
|
from ahriman.core.formatters.status_printer import StatusPrinter
|
||||||
from ahriman.core.formatters.update_printer import UpdatePrinter
|
from ahriman.core.formatters.update_printer import UpdatePrinter
|
||||||
from ahriman.core.formatters.user_printer import UserPrinter
|
from ahriman.core.formatters.user_printer import UserPrinter
|
||||||
|
56
src/ahriman/core/formatters/patch_printer.py
Normal file
56
src/ahriman/core/formatters/patch_printer.py
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2022 ahriman team.
|
||||||
|
#
|
||||||
|
# This file is part of ahriman
|
||||||
|
# (see https://github.com/arcan1s/ahriman).
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
from ahriman.core.formatters import StringPrinter
|
||||||
|
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
||||||
|
from ahriman.models.property import Property
|
||||||
|
|
||||||
|
|
||||||
|
class PatchPrinter(StringPrinter):
|
||||||
|
"""
|
||||||
|
print content of the PKGBUILD patch
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
patches(List[PkgbuildPatch]): PKGBUILD patch object
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, package_base: str, patches: List[PkgbuildPatch]) -> None:
|
||||||
|
"""
|
||||||
|
default constructor
|
||||||
|
|
||||||
|
Args:
|
||||||
|
package_base(str): package base
|
||||||
|
patches(List[PkgbuildPatch]): PKGBUILD patch object
|
||||||
|
"""
|
||||||
|
StringPrinter.__init__(self, package_base)
|
||||||
|
self.patches = patches
|
||||||
|
|
||||||
|
def properties(self) -> List[Property]:
|
||||||
|
"""
|
||||||
|
convert content into printable data
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[Property]: list of content properties
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
Property(patch.key or "Full source diff", patch.value, is_required=True)
|
||||||
|
for patch in self.patches
|
||||||
|
]
|
21
src/ahriman/core/gitremote/__init__.py
Normal file
21
src/ahriman/core/gitremote/__init__.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2022 ahriman team.
|
||||||
|
#
|
||||||
|
# This file is part of ahriman
|
||||||
|
# (see https://github.com/arcan1s/ahriman).
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
from ahriman.core.gitremote.remote_pull_trigger import RemotePullTrigger
|
||||||
|
from ahriman.core.gitremote.remote_push_trigger import RemotePushTrigger
|
90
src/ahriman/core/gitremote/remote_pull.py
Normal file
90
src/ahriman/core/gitremote/remote_pull.py
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
#
|
||||||
|
# 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 tempfile import TemporaryDirectory
|
||||||
|
|
||||||
|
from ahriman.core.build_tools.sources import Sources
|
||||||
|
from ahriman.core.configuration import Configuration
|
||||||
|
from ahriman.core.exceptions import GitRemoteError
|
||||||
|
from ahriman.core.lazy_logging import LazyLogging
|
||||||
|
from ahriman.core.util import walk
|
||||||
|
from ahriman.models.package_source import PackageSource
|
||||||
|
from ahriman.models.remote_source import RemoteSource
|
||||||
|
|
||||||
|
|
||||||
|
class RemotePull(LazyLogging):
|
||||||
|
"""
|
||||||
|
fetch PKGBUILDs from remote repository and use them for following actions
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
remote_source(RemoteSource): repository remote source (remote pull url and branch)
|
||||||
|
repository_paths(RepositoryPaths): repository paths instance
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, configuration: Configuration, section: str) -> None:
|
||||||
|
"""
|
||||||
|
default constructor
|
||||||
|
|
||||||
|
Args:
|
||||||
|
configuration(Configuration): configuration instance
|
||||||
|
section(str): settings section name
|
||||||
|
"""
|
||||||
|
self.remote_source = RemoteSource(
|
||||||
|
git_url=configuration.get(section, "pull_url"),
|
||||||
|
web_url="",
|
||||||
|
path=".",
|
||||||
|
branch=configuration.get(section, "pull_branch", fallback="master"),
|
||||||
|
source=PackageSource.Local,
|
||||||
|
)
|
||||||
|
self.repository_paths = configuration.repository_paths
|
||||||
|
|
||||||
|
def repo_clone(self) -> None:
|
||||||
|
"""
|
||||||
|
clone repository from remote source
|
||||||
|
"""
|
||||||
|
with TemporaryDirectory(ignore_cleanup_errors=True) as dir_name, (clone_dir := Path(dir_name)):
|
||||||
|
Sources.fetch(clone_dir, self.remote_source)
|
||||||
|
self.repo_copy(clone_dir)
|
||||||
|
|
||||||
|
def repo_copy(self, clone_dir: Path) -> None:
|
||||||
|
"""
|
||||||
|
copy directories from cloned remote source to local cache
|
||||||
|
|
||||||
|
Args:
|
||||||
|
clone_dir(Path): path to temporary cloned directory
|
||||||
|
"""
|
||||||
|
for pkgbuild_path in filter(lambda path: path.name == "PKGBUILD", walk(clone_dir)):
|
||||||
|
cloned_pkgbuild_dir = pkgbuild_path.parent
|
||||||
|
package_base = cloned_pkgbuild_dir.name
|
||||||
|
local_pkgbuild_dir = self.repository_paths.cache_for(package_base)
|
||||||
|
shutil.copytree(cloned_pkgbuild_dir, local_pkgbuild_dir, dirs_exist_ok=True)
|
||||||
|
Sources.init(local_pkgbuild_dir) # initialized git repository is required for local sources
|
||||||
|
|
||||||
|
def run(self) -> None:
|
||||||
|
"""
|
||||||
|
run git pull action
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
self.repo_clone()
|
||||||
|
except Exception:
|
||||||
|
self.logger.exception("git pull failed")
|
||||||
|
raise GitRemoteError()
|
48
src/ahriman/core/gitremote/remote_pull_trigger.py
Normal file
48
src/ahriman/core/gitremote/remote_pull_trigger.py
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2022 ahriman team.
|
||||||
|
#
|
||||||
|
# This file is part of ahriman
|
||||||
|
# (see https://github.com/arcan1s/ahriman).
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
from ahriman.core.configuration import Configuration
|
||||||
|
from ahriman.core.gitremote.remote_pull import RemotePull
|
||||||
|
from ahriman.core.triggers import Trigger
|
||||||
|
|
||||||
|
|
||||||
|
class RemotePullTrigger(Trigger):
|
||||||
|
"""
|
||||||
|
trigger based on pulling PKGBUILDs before the actions
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, architecture: str, configuration: Configuration) -> None:
|
||||||
|
"""
|
||||||
|
default constructor
|
||||||
|
|
||||||
|
Args:
|
||||||
|
architecture(str): repository architecture
|
||||||
|
configuration(Configuration): configuration instance
|
||||||
|
"""
|
||||||
|
Trigger.__init__(self, architecture, configuration)
|
||||||
|
self.targets = configuration.getlist("remote-pull", "target", fallback=["gitremote"])
|
||||||
|
|
||||||
|
def on_start(self) -> None:
|
||||||
|
"""
|
||||||
|
trigger action which will be called at the start of the application
|
||||||
|
"""
|
||||||
|
for target in self.targets:
|
||||||
|
section, _ = self.configuration.gettype(target, self.architecture)
|
||||||
|
runner = RemotePull(self.configuration, section)
|
||||||
|
runner.run()
|
114
src/ahriman/core/gitremote/remote_push.py
Normal file
114
src/ahriman/core/gitremote/remote_push.py
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
#
|
||||||
|
# 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 tempfile import TemporaryDirectory
|
||||||
|
from typing import Generator
|
||||||
|
|
||||||
|
from ahriman.core.build_tools.sources import Sources
|
||||||
|
from ahriman.core.configuration import Configuration
|
||||||
|
from ahriman.core.exceptions import GitRemoteError
|
||||||
|
from ahriman.core.lazy_logging import LazyLogging
|
||||||
|
from ahriman.models.package import Package
|
||||||
|
from ahriman.models.package_source import PackageSource
|
||||||
|
from ahriman.models.remote_source import RemoteSource
|
||||||
|
from ahriman.models.result import Result
|
||||||
|
|
||||||
|
|
||||||
|
class RemotePush(LazyLogging):
|
||||||
|
"""
|
||||||
|
sync PKGBUILDs to remote repository after actions
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
commit_author(Optional[str]): optional commit author in form of git config (i.e. ``user <user@host>``)
|
||||||
|
remote_source(RemoteSource): repository remote source (remote pull url and branch)
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, configuration: Configuration, section: str) -> None:
|
||||||
|
"""
|
||||||
|
default constructor
|
||||||
|
|
||||||
|
Args:
|
||||||
|
configuration(Configuration): configuration instance
|
||||||
|
remote_push_trigger.py
|
||||||
|
"""
|
||||||
|
self.commit_author = configuration.get(section, "commit_author", fallback=None)
|
||||||
|
self.remote_source = RemoteSource(
|
||||||
|
git_url=configuration.get(section, "push_url"),
|
||||||
|
web_url="",
|
||||||
|
path=".",
|
||||||
|
branch=configuration.get(section, "push_branch", fallback="master"),
|
||||||
|
source=PackageSource.Local,
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def package_update(package: Package, target_dir: Path) -> str:
|
||||||
|
"""
|
||||||
|
clone specified package and update its content in cloned PKGBUILD repository
|
||||||
|
|
||||||
|
Args:
|
||||||
|
package(Package): built package to update pkgbuild repository
|
||||||
|
target_dir(Path): path to the cloned PKGBUILD repository
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: relative path to be added as new file
|
||||||
|
"""
|
||||||
|
# instead of iterating by directory we can simplify the process
|
||||||
|
# firstly, we need to remove old data to make sure that removed files are not tracked anymore...
|
||||||
|
package_target_dir = target_dir / package.base
|
||||||
|
shutil.rmtree(package_target_dir, ignore_errors=True)
|
||||||
|
# ...secondly, we clone whole tree...
|
||||||
|
Sources.fetch(package_target_dir, package.remote)
|
||||||
|
# ...and last, but not least, we remove the dot-git directory...
|
||||||
|
shutil.rmtree(package_target_dir / ".git", ignore_errors=True)
|
||||||
|
# ...and finally return path to the copied directory
|
||||||
|
return package.base
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def packages_update(result: Result, target_dir: Path) -> Generator[str, None, None]:
|
||||||
|
"""
|
||||||
|
update all packages from the build result
|
||||||
|
|
||||||
|
Args:
|
||||||
|
result(Result): build result
|
||||||
|
target_dir(Path): path to the cloned PKGBUILD repository
|
||||||
|
|
||||||
|
Yields:
|
||||||
|
str: path to updated files
|
||||||
|
"""
|
||||||
|
for package in result.success:
|
||||||
|
yield RemotePush.package_update(package, target_dir)
|
||||||
|
|
||||||
|
def run(self, result: Result) -> None:
|
||||||
|
"""
|
||||||
|
run git pull action
|
||||||
|
|
||||||
|
Args:
|
||||||
|
result(Result): build result
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
with TemporaryDirectory(ignore_cleanup_errors=True) as dir_name, (clone_dir := Path(dir_name)):
|
||||||
|
Sources.fetch(clone_dir, self.remote_source)
|
||||||
|
Sources.push(clone_dir, self.remote_source, *RemotePush.packages_update(result, clone_dir),
|
||||||
|
commit_author=self.commit_author)
|
||||||
|
except Exception:
|
||||||
|
self.logger.exception("git push failed")
|
||||||
|
raise GitRemoteError()
|
56
src/ahriman/core/gitremote/remote_push_trigger.py
Normal file
56
src/ahriman/core/gitremote/remote_push_trigger.py
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2022 ahriman team.
|
||||||
|
#
|
||||||
|
# This file is part of ahriman
|
||||||
|
# (see https://github.com/arcan1s/ahriman).
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
from typing import Iterable
|
||||||
|
|
||||||
|
from ahriman.core.configuration import Configuration
|
||||||
|
from ahriman.core.gitremote.remote_push import RemotePush
|
||||||
|
from ahriman.core.triggers import Trigger
|
||||||
|
from ahriman.models.package import Package
|
||||||
|
from ahriman.models.result import Result
|
||||||
|
|
||||||
|
|
||||||
|
class RemotePushTrigger(Trigger):
|
||||||
|
"""
|
||||||
|
trigger for syncing PKGBUILDs to remote repository
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, architecture: str, configuration: Configuration) -> None:
|
||||||
|
"""
|
||||||
|
default constructor
|
||||||
|
|
||||||
|
Args:
|
||||||
|
architecture(str): repository architecture
|
||||||
|
configuration(Configuration): configuration instance
|
||||||
|
"""
|
||||||
|
Trigger.__init__(self, architecture, configuration)
|
||||||
|
self.targets = configuration.getlist("remote-push", "target", fallback=["gitremote"])
|
||||||
|
|
||||||
|
def on_result(self, result: Result, packages: Iterable[Package]) -> None:
|
||||||
|
"""
|
||||||
|
trigger action which will be called after build process with process result
|
||||||
|
|
||||||
|
Args:
|
||||||
|
result(Result): build result
|
||||||
|
packages(Iterable[Package]): list of all available packages
|
||||||
|
"""
|
||||||
|
for target in self.targets:
|
||||||
|
section, _ = self.configuration.gettype(target, self.architecture)
|
||||||
|
runner = RemotePush(self.configuration, section)
|
||||||
|
runner.run(result)
|
@ -61,4 +61,4 @@ class LazyLogging:
|
|||||||
"""
|
"""
|
||||||
clazz = self.__class__
|
clazz = self.__class__
|
||||||
prefix = "" if clazz.__module__ is None else f"{clazz.__module__}."
|
prefix = "" if clazz.__module__ is None else f"{clazz.__module__}."
|
||||||
return f"{prefix}{self.__class__.__qualname__}"
|
return f"{prefix}{clazz.__qualname__}"
|
||||||
|
@ -17,5 +17,4 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
from ahriman.core.report.report import Report
|
|
||||||
from ahriman.core.report.report_trigger import ReportTrigger
|
from ahriman.core.report.report_trigger import ReportTrigger
|
||||||
|
@ -21,7 +21,7 @@ from typing import Iterable
|
|||||||
|
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
from ahriman.core.formatters import BuildPrinter
|
from ahriman.core.formatters import BuildPrinter
|
||||||
from ahriman.core.report import Report
|
from ahriman.core.report.report import Report
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
from ahriman.models.result import Result
|
from ahriman.models.result import Result
|
||||||
|
|
||||||
|
@ -25,8 +25,8 @@ from email.mime.text import MIMEText
|
|||||||
from typing import Dict, Iterable
|
from typing import Dict, Iterable
|
||||||
|
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
from ahriman.core.report import Report
|
|
||||||
from ahriman.core.report.jinja_template import JinjaTemplate
|
from ahriman.core.report.jinja_template import JinjaTemplate
|
||||||
|
from ahriman.core.report.report import Report
|
||||||
from ahriman.core.util import pretty_datetime
|
from ahriman.core.util import pretty_datetime
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
from ahriman.models.result import Result
|
from ahriman.models.result import Result
|
||||||
|
@ -20,8 +20,8 @@
|
|||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
|
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
from ahriman.core.report import Report
|
|
||||||
from ahriman.core.report.jinja_template import JinjaTemplate
|
from ahriman.core.report.jinja_template import JinjaTemplate
|
||||||
|
from ahriman.core.report.report import Report
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
from ahriman.models.result import Result
|
from ahriman.models.result import Result
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ from __future__ import annotations
|
|||||||
from typing import Iterable, Type
|
from typing import Iterable, Type
|
||||||
|
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
from ahriman.core.exceptions import ReportFailed
|
from ahriman.core.exceptions import ReportError
|
||||||
from ahriman.core.lazy_logging import LazyLogging
|
from ahriman.core.lazy_logging import LazyLogging
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
from ahriman.models.report_settings import ReportSettings
|
from ahriman.models.report_settings import ReportSettings
|
||||||
@ -121,4 +121,4 @@ class Report(LazyLogging):
|
|||||||
self.generate(packages, result)
|
self.generate(packages, result)
|
||||||
except Exception:
|
except Exception:
|
||||||
self.logger.exception("report generation failed")
|
self.logger.exception("report generation failed")
|
||||||
raise ReportFailed()
|
raise ReportError()
|
||||||
|
@ -21,7 +21,7 @@ from typing import Iterable
|
|||||||
|
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
from ahriman.core.triggers import Trigger
|
from ahriman.core.triggers import Trigger
|
||||||
from ahriman.core.report import Report
|
from ahriman.core.report.report import Report
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
from ahriman.models.result import Result
|
from ahriman.models.result import Result
|
||||||
|
|
||||||
@ -43,9 +43,9 @@ class ReportTrigger(Trigger):
|
|||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
"""
|
"""
|
||||||
Trigger.__init__(self, architecture, configuration)
|
Trigger.__init__(self, architecture, configuration)
|
||||||
self.targets = configuration.getlist("report", "target")
|
self.targets = configuration.getlist("report", "target", fallback=[])
|
||||||
|
|
||||||
def run(self, result: Result, packages: Iterable[Package]) -> None:
|
def on_result(self, result: Result, packages: Iterable[Package]) -> None:
|
||||||
"""
|
"""
|
||||||
run trigger
|
run trigger
|
||||||
|
|
||||||
|
@ -17,14 +17,13 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
# technically we could use python-telegram-bot, but it is just a single request, cmon
|
import requests # technically we could use python-telegram-bot, but it is just a single request, cmon
|
||||||
import requests
|
|
||||||
|
|
||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
|
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
from ahriman.core.report import Report
|
|
||||||
from ahriman.core.report.jinja_template import JinjaTemplate
|
from ahriman.core.report.jinja_template import JinjaTemplate
|
||||||
|
from ahriman.core.report.report import Report
|
||||||
from ahriman.core.util import exception_response_text
|
from ahriman.core.util import exception_response_text
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
from ahriman.models.result import Result
|
from ahriman.models.result import Result
|
||||||
|
@ -66,6 +66,14 @@ class Cleaner(RepositoryProperties):
|
|||||||
for package in self.packages_built():
|
for package in self.packages_built():
|
||||||
package.unlink()
|
package.unlink()
|
||||||
|
|
||||||
|
def clear_pacman(self) -> None:
|
||||||
|
"""
|
||||||
|
clear directory with pacman databases
|
||||||
|
"""
|
||||||
|
self.logger.info("clear pacman database directory")
|
||||||
|
for pacman in self.paths.pacman.iterdir():
|
||||||
|
shutil.rmtree(pacman)
|
||||||
|
|
||||||
def clear_queue(self) -> None:
|
def clear_queue(self) -> None:
|
||||||
"""
|
"""
|
||||||
clear packages which were queued for the update
|
clear packages which were queued for the update
|
||||||
|
@ -21,7 +21,7 @@ import shutil
|
|||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from tempfile import TemporaryDirectory
|
from tempfile import TemporaryDirectory
|
||||||
from typing import Iterable, List, Optional, Set
|
from typing import Iterable, List, Optional
|
||||||
|
|
||||||
from ahriman.core.build_tools.task import Task
|
from ahriman.core.build_tools.task import Task
|
||||||
from ahriman.core.repository.cleaner import Cleaner
|
from ahriman.core.repository.cleaner import Cleaner
|
||||||
@ -84,8 +84,7 @@ class Executor(Cleaner):
|
|||||||
|
|
||||||
result = Result()
|
result = Result()
|
||||||
for single in updates:
|
for single in updates:
|
||||||
with TemporaryDirectory(ignore_cleanup_errors=True) as dir_name, \
|
with TemporaryDirectory(ignore_cleanup_errors=True) as dir_name, (build_dir := Path(dir_name)):
|
||||||
(build_dir := Path(dir_name)): # pylint: disable=confusing-with-statement
|
|
||||||
try:
|
try:
|
||||||
build_single(single, build_dir)
|
build_single(single, build_dir)
|
||||||
result.add_success(single)
|
result.add_success(single)
|
||||||
@ -110,7 +109,7 @@ class Executor(Cleaner):
|
|||||||
try:
|
try:
|
||||||
self.paths.tree_clear(package_base) # remove all internal files
|
self.paths.tree_clear(package_base) # remove all internal files
|
||||||
self.database.build_queue_clear(package_base)
|
self.database.build_queue_clear(package_base)
|
||||||
self.database.patches_remove(package_base)
|
self.database.patches_remove(package_base, [])
|
||||||
self.reporter.remove(package_base) # we only update status page in case of base removal
|
self.reporter.remove(package_base) # we only update status page in case of base removal
|
||||||
except Exception:
|
except Exception:
|
||||||
self.logger.exception("could not remove base %s", package_base)
|
self.logger.exception("could not remove base %s", package_base)
|
||||||
@ -144,15 +143,6 @@ class Executor(Cleaner):
|
|||||||
|
|
||||||
return self.repo.repo_path
|
return self.repo.repo_path
|
||||||
|
|
||||||
def process_triggers(self, result: Result) -> None:
|
|
||||||
"""
|
|
||||||
process triggers setup by settings
|
|
||||||
|
|
||||||
Args:
|
|
||||||
result(Result): build result
|
|
||||||
"""
|
|
||||||
self.triggers.process(result, self.packages())
|
|
||||||
|
|
||||||
def process_update(self, packages: Iterable[Path]) -> Result:
|
def process_update(self, packages: Iterable[Path]) -> Result:
|
||||||
"""
|
"""
|
||||||
sign packages, add them to repository and update repository database
|
sign packages, add them to repository and update repository database
|
||||||
@ -197,8 +187,12 @@ class Executor(Cleaner):
|
|||||||
self.reporter.set_success(local)
|
self.reporter.set_success(local)
|
||||||
result.add_success(local)
|
result.add_success(local)
|
||||||
|
|
||||||
current_package_archives: Set[str] = next(
|
current_package_archives = {
|
||||||
(set(current.packages) for current in current_packages if current.base == local.base), set())
|
package
|
||||||
|
for current in current_packages
|
||||||
|
if current.base == local.base
|
||||||
|
for package in current.packages
|
||||||
|
}
|
||||||
removed_packages.extend(current_package_archives.difference(local.packages))
|
removed_packages.extend(current_package_archives.difference(local.packages))
|
||||||
except Exception:
|
except Exception:
|
||||||
self.reporter.set_failed(local.base)
|
self.reporter.set_failed(local.base)
|
||||||
|
@ -39,7 +39,7 @@ class Repository(Executor, UpdateHandler):
|
|||||||
>>>
|
>>>
|
||||||
>>> configuration = Configuration()
|
>>> configuration = Configuration()
|
||||||
>>> database = SQLite.load(configuration)
|
>>> database = SQLite.load(configuration)
|
||||||
>>> repository = Repository("x86_64", configuration, database, no_report=False, unsafe=False)
|
>>> repository = Repository("x86_64", configuration, database, report=True, unsafe=False)
|
||||||
>>> known_packages = repository.packages()
|
>>> known_packages = repository.packages()
|
||||||
>>>
|
>>>
|
||||||
>>> build_result = repository.process_build(known_packages)
|
>>> build_result = repository.process_build(known_packages)
|
||||||
@ -99,17 +99,17 @@ class Repository(Executor, UpdateHandler):
|
|||||||
"""
|
"""
|
||||||
return list(filter(package_like, self.paths.packages.iterdir()))
|
return list(filter(package_like, self.paths.packages.iterdir()))
|
||||||
|
|
||||||
def packages_depend_on(self, depends_on: Optional[Iterable[str]]) -> List[Package]:
|
def packages_depend_on(self, packages: List[Package], depends_on: Optional[Iterable[str]]) -> List[Package]:
|
||||||
"""
|
"""
|
||||||
extract list of packages which depends on specified package
|
extract list of packages which depends on specified package
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
packages(List[Package]): list of packages to be filtered
|
||||||
depends_on(Optional[Iterable[str]]): dependencies of the packages
|
depends_on(Optional[Iterable[str]]): dependencies of the packages
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List[Package]: list of repository packages which depend on specified packages
|
List[Package]: list of repository packages which depend on specified packages
|
||||||
"""
|
"""
|
||||||
packages = self.packages()
|
|
||||||
if depends_on is None:
|
if depends_on is None:
|
||||||
return packages # no list provided extract everything by default
|
return packages # no list provided extract everything by default
|
||||||
depends_on = set(depends_on)
|
depends_on = set(depends_on)
|
||||||
|
@ -21,7 +21,7 @@ from ahriman.core.alpm.pacman import Pacman
|
|||||||
from ahriman.core.alpm.repo import Repo
|
from ahriman.core.alpm.repo import Repo
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
from ahriman.core.database import SQLite
|
from ahriman.core.database import SQLite
|
||||||
from ahriman.core.exceptions import UnsafeRun
|
from ahriman.core.exceptions import UnsafeRunError
|
||||||
from ahriman.core.lazy_logging import LazyLogging
|
from ahriman.core.lazy_logging import LazyLogging
|
||||||
from ahriman.core.sign.gpg import GPG
|
from ahriman.core.sign.gpg import GPG
|
||||||
from ahriman.core.status.client import Client
|
from ahriman.core.status.client import Client
|
||||||
@ -47,8 +47,8 @@ class RepositoryProperties(LazyLogging):
|
|||||||
triggers(TriggerLoader): triggers holder
|
triggers(TriggerLoader): triggers holder
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, architecture: str, configuration: Configuration, database: SQLite,
|
def __init__(self, architecture: str, configuration: Configuration, database: SQLite, *,
|
||||||
no_report: bool, unsafe: bool) -> None:
|
report: bool, unsafe: bool, refresh_pacman_database: int = 0) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
default constructor
|
||||||
|
|
||||||
@ -56,8 +56,9 @@ class RepositoryProperties(LazyLogging):
|
|||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
database(SQLite): database instance
|
database(SQLite): database instance
|
||||||
no_report(bool): force disable reporting
|
report(bool): force enable or disable reporting
|
||||||
unsafe(bool): if set no user check will be performed before path creation
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
|
refresh_pacman_database(int): pacman database syncronization level, ``0`` is disabled
|
||||||
"""
|
"""
|
||||||
self.architecture = architecture
|
self.architecture = architecture
|
||||||
self.configuration = configuration
|
self.configuration = configuration
|
||||||
@ -67,14 +68,14 @@ class RepositoryProperties(LazyLogging):
|
|||||||
|
|
||||||
self.paths = configuration.repository_paths
|
self.paths = configuration.repository_paths
|
||||||
try:
|
try:
|
||||||
check_user(self.paths, unsafe)
|
check_user(self.paths, unsafe=unsafe)
|
||||||
self.paths.tree_create()
|
self.paths.tree_create()
|
||||||
except UnsafeRun:
|
except UnsafeRunError:
|
||||||
self.logger.warning("root owner differs from the current user, skipping tree creation")
|
self.logger.warning("root owner differs from the current user, skipping tree creation")
|
||||||
|
|
||||||
self.ignore_list = configuration.getlist("build", "ignore_packages", fallback=[])
|
self.ignore_list = configuration.getlist("build", "ignore_packages", fallback=[])
|
||||||
self.pacman = Pacman(configuration)
|
self.pacman = Pacman(architecture, configuration, refresh_database=refresh_pacman_database)
|
||||||
self.sign = GPG(architecture, configuration)
|
self.sign = GPG(architecture, configuration)
|
||||||
self.repo = Repo(self.name, self.paths, self.sign.repository_sign_args)
|
self.repo = Repo(self.name, self.paths, self.sign.repository_sign_args)
|
||||||
self.reporter = Client() if no_report else Client.load(configuration)
|
self.reporter = Client.load(configuration) if report else Client()
|
||||||
self.triggers = TriggerLoader(architecture, configuration)
|
self.triggers = TriggerLoader(architecture, configuration)
|
||||||
|
@ -42,13 +42,13 @@ class UpdateHandler(Cleaner):
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def updates_aur(self, filter_packages: Iterable[str], no_vcs: bool) -> List[Package]:
|
def updates_aur(self, filter_packages: Iterable[str], *, vcs: bool) -> List[Package]:
|
||||||
"""
|
"""
|
||||||
check AUR for updates
|
check AUR for updates
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
filter_packages(Iterable[str]): do not check every package just specified in the list
|
filter_packages(Iterable[str]): do not check every package just specified in the list
|
||||||
no_vcs(bool): do not check VCS packages
|
vcs(bool): enable or disable checking of VCS packages
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List[Package]: list of packages which are out-of-dated
|
List[Package]: list of packages which are out-of-dated
|
||||||
@ -58,7 +58,7 @@ class UpdateHandler(Cleaner):
|
|||||||
for local in self.packages():
|
for local in self.packages():
|
||||||
if local.base in self.ignore_list:
|
if local.base in self.ignore_list:
|
||||||
continue
|
continue
|
||||||
if local.is_vcs and no_vcs:
|
if local.is_vcs and not vcs:
|
||||||
continue
|
continue
|
||||||
if filter_packages and local.base not in filter_packages:
|
if filter_packages and local.base not in filter_packages:
|
||||||
continue
|
continue
|
||||||
|
@ -23,7 +23,7 @@ from pathlib import Path
|
|||||||
from typing import List, Optional, Set, Tuple
|
from typing import List, Optional, Set, Tuple
|
||||||
|
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
from ahriman.core.exceptions import BuildFailed
|
from ahriman.core.exceptions import BuildError
|
||||||
from ahriman.core.lazy_logging import LazyLogging
|
from ahriman.core.lazy_logging import LazyLogging
|
||||||
from ahriman.core.util import check_output, exception_response_text
|
from ahriman.core.util import check_output, exception_response_text
|
||||||
from ahriman.models.sign_settings import SignSettings
|
from ahriman.models.sign_settings import SignSettings
|
||||||
@ -97,7 +97,7 @@ class GPG(LazyLogging):
|
|||||||
Tuple[Set[SignSettings], Optional[str]]: tuple of sign targets and default PGP key
|
Tuple[Set[SignSettings], Optional[str]]: tuple of sign targets and default PGP key
|
||||||
"""
|
"""
|
||||||
targets: Set[SignSettings] = set()
|
targets: Set[SignSettings] = set()
|
||||||
for option in configuration.getlist("sign", "target"):
|
for option in configuration.getlist("sign", "target", fallback=[]):
|
||||||
target = SignSettings.from_option(option)
|
target = SignSettings.from_option(option)
|
||||||
if target == SignSettings.Disabled:
|
if target == SignSettings.Disabled:
|
||||||
continue
|
continue
|
||||||
@ -138,7 +138,7 @@ class GPG(LazyLogging):
|
|||||||
key(str): key ID to import
|
key(str): key ID to import
|
||||||
"""
|
"""
|
||||||
key_body = self.key_download(server, key)
|
key_body = self.key_download(server, key)
|
||||||
GPG._check_output("gpg", "--import", input_data=key_body, exception=None, logger=self.logger)
|
GPG._check_output("gpg", "--import", input_data=key_body, logger=self.logger)
|
||||||
|
|
||||||
def process(self, path: Path, key: str) -> List[Path]:
|
def process(self, path: Path, key: str) -> List[Path]:
|
||||||
"""
|
"""
|
||||||
@ -153,7 +153,7 @@ class GPG(LazyLogging):
|
|||||||
"""
|
"""
|
||||||
GPG._check_output(
|
GPG._check_output(
|
||||||
*GPG.sign_command(path, key),
|
*GPG.sign_command(path, key),
|
||||||
exception=BuildFailed(path.name),
|
exception=BuildError(path.name),
|
||||||
logger=self.logger)
|
logger=self.logger)
|
||||||
return [path, path.parent / f"{path.name}.sig"]
|
return [path, path.parent / f"{path.name}.sig"]
|
||||||
|
|
||||||
@ -181,7 +181,7 @@ class GPG(LazyLogging):
|
|||||||
sign repository if required by configuration
|
sign repository if required by configuration
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
more likely you just want to pass ``repository_sign_args`` to repo wrapper
|
More likely you just want to pass ``repository_sign_args`` to repo wrapper
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
path(Path): path to repository database
|
path(Path): path to repository database
|
||||||
|
@ -78,7 +78,7 @@ class Spawn(Thread, LazyLogging):
|
|||||||
result = callback(args, architecture)
|
result = callback(args, architecture)
|
||||||
queue.put((process_id, result))
|
queue.put((process_id, result))
|
||||||
|
|
||||||
def packages_add(self, packages: Iterable[str], now: bool) -> None:
|
def packages_add(self, packages: Iterable[str], *, now: bool) -> None:
|
||||||
"""
|
"""
|
||||||
add packages
|
add packages
|
||||||
|
|
||||||
@ -86,10 +86,12 @@ class Spawn(Thread, LazyLogging):
|
|||||||
packages(Iterable[str]): packages list to add
|
packages(Iterable[str]): packages list to add
|
||||||
now(bool): build packages now
|
now(bool): build packages now
|
||||||
"""
|
"""
|
||||||
|
if not packages:
|
||||||
|
return self.spawn_process("repo-update")
|
||||||
kwargs = {"source": PackageSource.AUR.value} # avoid abusing by building non-aur packages
|
kwargs = {"source": PackageSource.AUR.value} # avoid abusing by building non-aur packages
|
||||||
if now:
|
if now:
|
||||||
kwargs["now"] = ""
|
kwargs["now"] = ""
|
||||||
self.spawn_process("add", *packages, **kwargs)
|
return self.spawn_process("package-add", *packages, **kwargs)
|
||||||
|
|
||||||
def packages_remove(self, packages: Iterable[str]) -> None:
|
def packages_remove(self, packages: Iterable[str]) -> None:
|
||||||
"""
|
"""
|
||||||
@ -98,7 +100,7 @@ class Spawn(Thread, LazyLogging):
|
|||||||
Args:
|
Args:
|
||||||
packages(Iterable[str]): packages list to remove
|
packages(Iterable[str]): packages list to remove
|
||||||
"""
|
"""
|
||||||
self.spawn_process("remove", *packages)
|
self.spawn_process("package-remove", *packages)
|
||||||
|
|
||||||
def spawn_process(self, command: str, *args: str, **kwargs: str) -> None:
|
def spawn_process(self, command: str, *args: str, **kwargs: str) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -21,7 +21,7 @@ from typing import Dict, List, Optional, Tuple
|
|||||||
|
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
from ahriman.core.database import SQLite
|
from ahriman.core.database import SQLite
|
||||||
from ahriman.core.exceptions import UnknownPackage
|
from ahriman.core.exceptions import UnknownPackageError
|
||||||
from ahriman.core.lazy_logging import LazyLogging
|
from ahriman.core.lazy_logging import LazyLogging
|
||||||
from ahriman.core.repository import Repository
|
from ahriman.core.repository import Repository
|
||||||
from ahriman.models.build_status import BuildStatus, BuildStatusEnum
|
from ahriman.models.build_status import BuildStatus, BuildStatusEnum
|
||||||
@ -52,7 +52,7 @@ class Watcher(LazyLogging):
|
|||||||
"""
|
"""
|
||||||
self.architecture = architecture
|
self.architecture = architecture
|
||||||
self.database = database
|
self.database = database
|
||||||
self.repository = Repository(architecture, configuration, database, no_report=True, unsafe=False)
|
self.repository = Repository(architecture, configuration, database, report=False, unsafe=False)
|
||||||
|
|
||||||
self.known: Dict[str, Tuple[Package, BuildStatus]] = {}
|
self.known: Dict[str, Tuple[Package, BuildStatus]] = {}
|
||||||
self.status = BuildStatus()
|
self.status = BuildStatus()
|
||||||
@ -83,7 +83,7 @@ class Watcher(LazyLogging):
|
|||||||
try:
|
try:
|
||||||
return self.known[base]
|
return self.known[base]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise UnknownPackage(base)
|
raise UnknownPackageError(base)
|
||||||
|
|
||||||
def load(self) -> None:
|
def load(self) -> None:
|
||||||
"""
|
"""
|
||||||
@ -127,7 +127,7 @@ class Watcher(LazyLogging):
|
|||||||
try:
|
try:
|
||||||
package, _ = self.known[package_base]
|
package, _ = self.known[package_base]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise UnknownPackage(package_base)
|
raise UnknownPackageError(package_base)
|
||||||
full_status = BuildStatus(status)
|
full_status = BuildStatus(status)
|
||||||
self.known[package_base] = (package, full_status)
|
self.known[package_base] = (package, full_status)
|
||||||
self.database.package_update(package, full_status)
|
self.database.package_update(package, full_status)
|
||||||
|
@ -72,8 +72,7 @@ class Leaf:
|
|||||||
Returns:
|
Returns:
|
||||||
Leaf: loaded class
|
Leaf: loaded class
|
||||||
"""
|
"""
|
||||||
with TemporaryDirectory(ignore_cleanup_errors=True) as dir_name, \
|
with TemporaryDirectory(ignore_cleanup_errors=True) as dir_name, (clone_dir := Path(dir_name)):
|
||||||
(clone_dir := Path(dir_name)): # pylint: disable=confusing-with-statement
|
|
||||||
Sources.load(clone_dir, package, database.patches_get(package.base), paths)
|
Sources.load(clone_dir, package, database.patches_get(package.base), paths)
|
||||||
dependencies = Package.dependencies(clone_dir)
|
dependencies = Package.dependencies(clone_dir)
|
||||||
return cls(package, dependencies)
|
return cls(package, dependencies)
|
||||||
@ -111,7 +110,7 @@ class Tree:
|
|||||||
>>>
|
>>>
|
||||||
>>> configuration = Configuration()
|
>>> configuration = Configuration()
|
||||||
>>> database = SQLite.load(configuration)
|
>>> database = SQLite.load(configuration)
|
||||||
>>> repository = Repository("x86_64", configuration, database, no_report=False, unsafe=False)
|
>>> repository = Repository("x86_64", configuration, database, report=True, unsafe=False)
|
||||||
>>> packages = repository.packages()
|
>>> packages = repository.packages()
|
||||||
>>>
|
>>>
|
||||||
>>> tree = Tree.load(packages, configuration.repository_paths, database)
|
>>> tree = Tree.load(packages, configuration.repository_paths, database)
|
||||||
|
@ -37,7 +37,7 @@ class Trigger(LazyLogging):
|
|||||||
This class must be used in order to create own extension. Basically idea is the following::
|
This class must be used in order to create own extension. Basically idea is the following::
|
||||||
|
|
||||||
>>> class CustomTrigger(Trigger):
|
>>> class CustomTrigger(Trigger):
|
||||||
>>> def run(self, result: Result, packages: Iterable[Package]) -> None:
|
>>> def on_result(self, result: Result, packages: Iterable[Package]) -> None:
|
||||||
>>> perform_some_action()
|
>>> perform_some_action()
|
||||||
|
|
||||||
Having this class you can pass it to ``configuration`` and it will be run on action::
|
Having this class you can pass it to ``configuration`` and it will be run on action::
|
||||||
@ -48,7 +48,7 @@ class Trigger(LazyLogging):
|
|||||||
>>> configuration.set_option("build", "triggers", "my.awesome.package.CustomTrigger")
|
>>> configuration.set_option("build", "triggers", "my.awesome.package.CustomTrigger")
|
||||||
>>>
|
>>>
|
||||||
>>> loader = TriggerLoader("x86_64", configuration)
|
>>> loader = TriggerLoader("x86_64", configuration)
|
||||||
>>> loader.process(Result(), [])
|
>>> loader.on_result(Result(), [])
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, architecture: str, configuration: Configuration) -> None:
|
def __init__(self, architecture: str, configuration: Configuration) -> None:
|
||||||
@ -62,15 +62,23 @@ class Trigger(LazyLogging):
|
|||||||
self.architecture = architecture
|
self.architecture = architecture
|
||||||
self.configuration = configuration
|
self.configuration = configuration
|
||||||
|
|
||||||
def run(self, result: Result, packages: Iterable[Package]) -> None:
|
def on_result(self, result: Result, packages: Iterable[Package]) -> None:
|
||||||
"""
|
"""
|
||||||
run trigger
|
trigger action which will be called after build process with process result
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
result(Result): build result
|
result(Result): build result
|
||||||
packages(Iterable[Package]): list of all available packages
|
packages(Iterable[Package]): list of all available packages
|
||||||
|
|
||||||
Raises:
|
|
||||||
NotImplementedError: not implemented method
|
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
if (run := getattr(self, "run", None)) is not None:
|
||||||
|
run(result, packages) # compatibility with old triggers
|
||||||
|
|
||||||
|
def on_start(self) -> None:
|
||||||
|
"""
|
||||||
|
trigger action which will be called at the start of the application
|
||||||
|
"""
|
||||||
|
|
||||||
|
def on_stop(self) -> None:
|
||||||
|
"""
|
||||||
|
trigger action which will be called before the stop of the application
|
||||||
|
"""
|
||||||
|
@ -17,15 +17,16 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
|
import contextlib
|
||||||
import importlib
|
import importlib
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from types import ModuleType
|
from types import ModuleType
|
||||||
from typing import Iterable
|
from typing import Generator, Iterable
|
||||||
|
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
from ahriman.core.exceptions import InvalidExtension
|
from ahriman.core.exceptions import ExtensionError
|
||||||
from ahriman.core.lazy_logging import LazyLogging
|
from ahriman.core.lazy_logging import LazyLogging
|
||||||
from ahriman.core.triggers import Trigger
|
from ahriman.core.triggers import Trigger
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
@ -54,7 +55,7 @@ class TriggerLoader(LazyLogging):
|
|||||||
|
|
||||||
After that you are free to run triggers::
|
After that you are free to run triggers::
|
||||||
|
|
||||||
>>> loader.process(Result(), [])
|
>>> loader.on_result(Result(), [])
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, architecture: str, configuration: Configuration) -> None:
|
def __init__(self, architecture: str, configuration: Configuration) -> None:
|
||||||
@ -72,6 +73,31 @@ class TriggerLoader(LazyLogging):
|
|||||||
self.load_trigger(trigger)
|
self.load_trigger(trigger)
|
||||||
for trigger in configuration.getlist("build", "triggers")
|
for trigger in configuration.getlist("build", "triggers")
|
||||||
]
|
]
|
||||||
|
self._on_stop_requested = False
|
||||||
|
|
||||||
|
def __del__(self) -> None:
|
||||||
|
"""
|
||||||
|
custom destructor object which calls on_stop in case if it was requested
|
||||||
|
"""
|
||||||
|
if not self._on_stop_requested:
|
||||||
|
return
|
||||||
|
self.on_stop()
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def __execute_trigger(self, trigger: Trigger) -> Generator[None, None, None]:
|
||||||
|
"""
|
||||||
|
decorator for calling triggers
|
||||||
|
|
||||||
|
Args:
|
||||||
|
trigger(Trigger): trigger instance to be called
|
||||||
|
"""
|
||||||
|
trigger_name = type(trigger).__name__
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.logger.info("executing extension %s", trigger_name)
|
||||||
|
yield
|
||||||
|
except Exception:
|
||||||
|
self.logger.exception("got exception while run trigger %s", trigger_name)
|
||||||
|
|
||||||
def _load_module_from_file(self, module_path: str, implementation: str) -> ModuleType:
|
def _load_module_from_file(self, module_path: str, implementation: str) -> ModuleType:
|
||||||
"""
|
"""
|
||||||
@ -110,7 +136,7 @@ class TriggerLoader(LazyLogging):
|
|||||||
try:
|
try:
|
||||||
return importlib.import_module(package)
|
return importlib.import_module(package)
|
||||||
except ModuleNotFoundError:
|
except ModuleNotFoundError:
|
||||||
raise InvalidExtension(f"Module {package} not found")
|
raise ExtensionError(f"Module {package} not found")
|
||||||
|
|
||||||
def load_trigger(self, module_path: str) -> Trigger:
|
def load_trigger(self, module_path: str) -> Trigger:
|
||||||
"""
|
"""
|
||||||
@ -137,30 +163,46 @@ class TriggerLoader(LazyLogging):
|
|||||||
|
|
||||||
trigger_type = getattr(module, class_name, None)
|
trigger_type = getattr(module, class_name, None)
|
||||||
if not isinstance(trigger_type, type):
|
if not isinstance(trigger_type, type):
|
||||||
raise InvalidExtension(f"{class_name} of {package_or_path} is not a type")
|
raise ExtensionError(f"{class_name} of {package_or_path} is not a type")
|
||||||
self.logger.info("loaded type %s of package %s", class_name, package_or_path)
|
self.logger.info("loaded type %s of package %s", class_name, package_or_path)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
trigger = trigger_type(self.architecture, self.configuration)
|
trigger = trigger_type(self.architecture, self.configuration)
|
||||||
except Exception:
|
except Exception:
|
||||||
raise InvalidExtension(f"Could not load instance of trigger from {class_name} of {package_or_path}")
|
raise ExtensionError(f"Could not load instance of trigger from {class_name} of {package_or_path}")
|
||||||
if not isinstance(trigger, Trigger):
|
if not isinstance(trigger, Trigger):
|
||||||
raise InvalidExtension(f"Class {class_name} of {package_or_path} is not a Trigger")
|
raise ExtensionError(f"Class {class_name} of {package_or_path} is not a Trigger")
|
||||||
|
|
||||||
return trigger
|
return trigger
|
||||||
|
|
||||||
def process(self, result: Result, packages: Iterable[Package]) -> None:
|
def on_result(self, result: Result, packages: Iterable[Package]) -> None:
|
||||||
"""
|
"""
|
||||||
run remote sync
|
run trigger with result of application run
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
result(Result): build result
|
result(Result): build result
|
||||||
packages(Iterable[Package]): list of all available packages
|
packages(Iterable[Package]): list of all available packages
|
||||||
"""
|
"""
|
||||||
|
self.logger.debug("executing triggers on result")
|
||||||
for trigger in self.triggers:
|
for trigger in self.triggers:
|
||||||
trigger_name = type(trigger).__name__
|
with self.__execute_trigger(trigger):
|
||||||
try:
|
trigger.on_result(result, packages)
|
||||||
self.logger.info("executing extension %s", trigger_name)
|
|
||||||
trigger.run(result, packages)
|
def on_start(self) -> None:
|
||||||
except Exception:
|
"""
|
||||||
self.logger.exception("got exception while run trigger %s", trigger_name)
|
run triggers on load
|
||||||
|
"""
|
||||||
|
self.logger.debug("executing triggers on start")
|
||||||
|
self._on_stop_requested = True
|
||||||
|
for trigger in self.triggers:
|
||||||
|
with self.__execute_trigger(trigger):
|
||||||
|
trigger.on_start()
|
||||||
|
|
||||||
|
def on_stop(self) -> None:
|
||||||
|
"""
|
||||||
|
run triggers before the application exit
|
||||||
|
"""
|
||||||
|
self.logger.debug("executing triggers on stop")
|
||||||
|
for trigger in self.triggers:
|
||||||
|
with self.__execute_trigger(trigger):
|
||||||
|
trigger.on_stop()
|
||||||
|
@ -17,5 +17,4 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
from ahriman.core.upload.upload import Upload
|
|
||||||
from ahriman.core.upload.upload_trigger import UploadTrigger
|
from ahriman.core.upload.upload_trigger import UploadTrigger
|
||||||
|
@ -24,7 +24,7 @@ from pathlib import Path
|
|||||||
from typing import Any, Dict
|
from typing import Any, Dict
|
||||||
|
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
from ahriman.core.upload import Upload
|
from ahriman.core.upload.upload import Upload
|
||||||
from ahriman.core.util import exception_response_text
|
from ahriman.core.util import exception_response_text
|
||||||
|
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ class HttpUpload(Upload):
|
|||||||
helper for the http based uploads
|
helper for the http based uploads
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
auth(Tuple[str, str]): HTTP auth object
|
auth(Optional[Tuple[str, str]]): HTTP auth object if set
|
||||||
timeout(int): HTTP request timeout in seconds
|
timeout(int): HTTP request timeout in seconds
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -47,9 +47,9 @@ class HttpUpload(Upload):
|
|||||||
section(str): configuration section name
|
section(str): configuration section name
|
||||||
"""
|
"""
|
||||||
Upload.__init__(self, architecture, configuration)
|
Upload.__init__(self, architecture, configuration)
|
||||||
password = configuration.get(section, "password")
|
password = configuration.get(section, "password", fallback=None)
|
||||||
username = configuration.get(section, "username")
|
username = configuration.get(section, "username", fallback=None)
|
||||||
self.auth = (password, username)
|
self.auth = (password, username) if password and username else None
|
||||||
self.timeout = configuration.getint(section, "timeout", fallback=30)
|
self.timeout = configuration.getint(section, "timeout", fallback=30)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -21,7 +21,7 @@ from pathlib import Path
|
|||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
|
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
from ahriman.core.upload import Upload
|
from ahriman.core.upload.upload import Upload
|
||||||
from ahriman.core.util import check_output
|
from ahriman.core.util import check_output
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
|
|
||||||
@ -58,4 +58,4 @@ class Rsync(Upload):
|
|||||||
path(Path): local path to sync
|
path(Path): local path to sync
|
||||||
built_packages(Iterable[Package]): list of packages which has just been built
|
built_packages(Iterable[Package]): list of packages which has just been built
|
||||||
"""
|
"""
|
||||||
Rsync._check_output(*self.command, str(path), self.remote, exception=None, logger=self.logger)
|
Rsync._check_output(*self.command, str(path), self.remote, logger=self.logger)
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user