mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-08-29 04:49:57 +00:00
Compare commits
24 Commits
2.0.0rc2
...
1cfc751d21
Author | SHA1 | Date | |
---|---|---|---|
1cfc751d21 | |||
6ebbb04504 | |||
c9ee470ee2 | |||
a2610504e5 | |||
36b8b0f46a | |||
d90f417cae | |||
0db619136d | |||
208a9b920d | |||
cb63bc08ff | |||
6551c8d983 | |||
a6c8d64053 | |||
fd78f2b5e2 | |||
900907cdaa | |||
5ff2f43506 | |||
dd521b49b5 | |||
5b1f5a8473 | |||
86af13f09e | |||
733c014229 | |||
783c16b2ed | |||
2536b8dc1f | |||
e200ac9776 | |||
6946745153 | |||
6de75377c3 | |||
a734b86e66 |
3
.github/workflows/docker-image.yml
vendored
3
.github/workflows/docker-image.yml
vendored
@ -3,6 +3,9 @@ name: docker image
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ master ]
|
branches: [ master ]
|
||||||
|
tags:
|
||||||
|
- '*'
|
||||||
|
- '!*rc*'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
docker-image:
|
docker-image:
|
||||||
|
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@ -3,7 +3,7 @@ name: release
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- '*.*.*'
|
- '*'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
make-release:
|
make-release:
|
||||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -97,3 +97,5 @@ ENV/
|
|||||||
status_cache.json
|
status_cache.json
|
||||||
|
|
||||||
*.db
|
*.db
|
||||||
|
|
||||||
|
docs/html/
|
||||||
|
20
.readthedocs.yaml
Normal file
20
.readthedocs.yaml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
version: 2
|
||||||
|
|
||||||
|
formats: all
|
||||||
|
|
||||||
|
build:
|
||||||
|
os: ubuntu-20.04
|
||||||
|
tools:
|
||||||
|
python: "3.9"
|
||||||
|
|
||||||
|
sphinx:
|
||||||
|
builder: html
|
||||||
|
configuration: docs/source/conf.py
|
||||||
|
|
||||||
|
python:
|
||||||
|
install:
|
||||||
|
- method: pip
|
||||||
|
path: .
|
||||||
|
extra_requirements:
|
||||||
|
- docs
|
||||||
|
system_packages: true
|
20
Makefile
20
Makefile
@ -1,4 +1,4 @@
|
|||||||
.PHONY: architecture archive archive_directory archlinux check clean directory man push tests version
|
.PHONY: archive archive_directory archlinux check clean directory push spec spec-html tests version
|
||||||
.DEFAULT_GOAL := archlinux
|
.DEFAULT_GOAL := archlinux
|
||||||
|
|
||||||
PROJECT := ahriman
|
PROJECT := ahriman
|
||||||
@ -10,9 +10,6 @@ IGNORE_FILES := package/archlinux src/.mypy_cache
|
|||||||
$(TARGET_FILES) : $(addprefix $(PROJECT), %) : $(addprefix ., %) directory version
|
$(TARGET_FILES) : $(addprefix $(PROJECT), %) : $(addprefix ., %) directory version
|
||||||
@cp -rp $< $@
|
@cp -rp $< $@
|
||||||
|
|
||||||
architecture:
|
|
||||||
cd src && pydeps ahriman -o ../docs/ahriman-architecture.svg --no-show --cluster
|
|
||||||
|
|
||||||
archive: archive_directory
|
archive: archive_directory
|
||||||
tar cJf "$(PROJECT)-$(VERSION)-src.tar.xz" "$(PROJECT)"
|
tar cJf "$(PROJECT)-$(VERSION)-src.tar.xz" "$(PROJECT)"
|
||||||
rm -rf "$(PROJECT)"
|
rm -rf "$(PROJECT)"
|
||||||
@ -36,16 +33,23 @@ clean:
|
|||||||
directory: clean
|
directory: clean
|
||||||
mkdir "$(PROJECT)"
|
mkdir "$(PROJECT)"
|
||||||
|
|
||||||
man:
|
push: spec archlinux
|
||||||
cd src && PYTHONPATH=. argparse-manpage --module ahriman.application.ahriman --function _parser --author "ahriman team" --project-name ahriman --author-email "" --url https://github.com/arcan1s/ahriman --output ../docs/ahriman.1
|
|
||||||
|
|
||||||
push: architecture man archlinux
|
|
||||||
git add package/archlinux/PKGBUILD src/ahriman/version.py docs/ahriman-architecture.svg docs/ahriman.1
|
git add package/archlinux/PKGBUILD src/ahriman/version.py docs/ahriman-architecture.svg docs/ahriman.1
|
||||||
git commit -m "Release $(VERSION)"
|
git commit -m "Release $(VERSION)"
|
||||||
git tag "$(VERSION)"
|
git tag "$(VERSION)"
|
||||||
git push
|
git push
|
||||||
git push --tags
|
git push --tags
|
||||||
|
|
||||||
|
spec:
|
||||||
|
# make sure that old files are removed
|
||||||
|
find docs/source -type f -name "$(PROJECT)*.rst" -delete
|
||||||
|
rm -f docs/source/modules.rst
|
||||||
|
tox -e docs
|
||||||
|
|
||||||
|
spec-html: spec
|
||||||
|
rm -rf docs/html
|
||||||
|
tox -e docs-html
|
||||||
|
|
||||||
tests: clean
|
tests: clean
|
||||||
tox -e tests
|
tox -e tests
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
[](https://github.com/arcan1s/ahriman/actions/workflows/run-setup.yml)
|
[](https://github.com/arcan1s/ahriman/actions/workflows/run-setup.yml)
|
||||||
[](https://github.com/arcan1s/ahriman/actions/workflows/docker-image.yml)
|
[](https://github.com/arcan1s/ahriman/actions/workflows/docker-image.yml)
|
||||||
[](https://www.codefactor.io/repository/github/arcan1s/ahriman)
|
[](https://www.codefactor.io/repository/github/arcan1s/ahriman)
|
||||||
|
[](https://ahriman.readthedocs.io/?badge=latest)
|
||||||
|
|
||||||
Wrapper for managing custom repository inspired by [repo-scripts](https://github.com/arcan1s/repo-scripts).
|
Wrapper for managing custom repository inspired by [repo-scripts](https://github.com/arcan1s/repo-scripts).
|
||||||
|
|
||||||
@ -13,7 +14,7 @@ Wrapper for managing custom repository inspired by [repo-scripts](https://github
|
|||||||
* Multi-architecture support.
|
* Multi-architecture support.
|
||||||
* VCS packages support.
|
* VCS packages support.
|
||||||
* Sign support with gpg (repository, package, per package settings).
|
* Sign support with gpg (repository, package, per package settings).
|
||||||
* Synchronization to remote services (rsync, s3 and github) and report generation (html).
|
* Synchronization to remote services (rsync, s3 and github) and report generation (email, html, telegram).
|
||||||
* Dependency manager.
|
* Dependency manager.
|
||||||
* Ability to patch AUR packages and even create package from local PKGBUILDs.
|
* Ability to patch AUR packages and even create package from local PKGBUILDs.
|
||||||
* Repository status interface with optional authorization and control options:
|
* Repository status interface with optional authorization and control options:
|
||||||
|
File diff suppressed because it is too large
Load Diff
Before Width: | Height: | Size: 503 KiB After Width: | Height: | Size: 540 KiB |
@ -3,7 +3,7 @@
|
|||||||
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-check,check,repo-clean,clean,repo-config,config,repo-rebuild,rebuild,repo-remove-unknown,remove-unknown,repo-report,report,repo-setup,init,repo-init,setup,repo-sign,sign,repo-status-update,repo-sync,sync,repo-update,update,user-add,user-list,user-remove,web} ...
|
[-h] [-a ARCHITECTURE] [-c CONFIGURATION] [--force] [-l LOCK] [--no-report] [-q] [--unsafe] [-v] {aur-search,search,help,help-commands-unsafe,key-import,package-add,add,package-update,package-remove,remove,package-status,status,package-status-remove,package-status-update,status-update,patch-add,patch-list,patch-remove,repo-backup,repo-check,check,repo-clean,clean,repo-config,config,repo-rebuild,rebuild,repo-remove-unknown,remove-unknown,repo-report,report,repo-restore,repo-setup,init,repo-init,setup,repo-sign,sign,repo-status-update,repo-sync,sync,repo-update,update,user-add,user-list,user-remove,web} ...
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
ArcH Linux ReposItory MANager
|
ArcH Linux ReposItory MANager
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
@ -79,6 +79,9 @@ list patch sets
|
|||||||
\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
|
||||||
|
backup repository data
|
||||||
|
.TP
|
||||||
\fBahriman\fR \fI\,repo-check\/\fR
|
\fBahriman\fR \fI\,repo-check\/\fR
|
||||||
check for updates
|
check for updates
|
||||||
.TP
|
.TP
|
||||||
@ -97,6 +100,9 @@ remove unknown packages
|
|||||||
\fBahriman\fR \fI\,repo-report\/\fR
|
\fBahriman\fR \fI\,repo-report\/\fR
|
||||||
generate report
|
generate report
|
||||||
.TP
|
.TP
|
||||||
|
\fBahriman\fR \fI\,repo-restore\/\fR
|
||||||
|
restore repository data
|
||||||
|
.TP
|
||||||
\fBahriman\fR \fI\,repo-setup\/\fR
|
\fBahriman\fR \fI\,repo-setup\/\fR
|
||||||
initial service configuration
|
initial service configuration
|
||||||
.TP
|
.TP
|
||||||
@ -207,7 +213,7 @@ key server for key import
|
|||||||
|
|
||||||
.SH OPTIONS 'ahriman package-add'
|
.SH OPTIONS 'ahriman package-add'
|
||||||
usage: ahriman package-add [-h] [-e] [-n]
|
usage: ahriman package-add [-h] [-e] [-n]
|
||||||
[-s {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote}]
|
[-s {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote,PackageSource.Repository}]
|
||||||
[--without-dependencies]
|
[--without-dependencies]
|
||||||
package [package ...]
|
package [package ...]
|
||||||
|
|
||||||
@ -226,7 +232,7 @@ return non\-zero exit status if result is empty
|
|||||||
run update function after
|
run update function after
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-s\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote}, \fB\-\-source\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote}
|
\fB\-s\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote,PackageSource.Repository}, \fB\-\-source\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote,PackageSource.Repository}
|
||||||
explicitly specify the package source for this command
|
explicitly specify the package source for this command
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
@ -235,7 +241,7 @@ do not add dependencies
|
|||||||
|
|
||||||
.SH OPTIONS 'ahriman add'
|
.SH OPTIONS 'ahriman add'
|
||||||
usage: ahriman package-add [-h] [-e] [-n]
|
usage: ahriman package-add [-h] [-e] [-n]
|
||||||
[-s {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote}]
|
[-s {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote,PackageSource.Repository}]
|
||||||
[--without-dependencies]
|
[--without-dependencies]
|
||||||
package [package ...]
|
package [package ...]
|
||||||
|
|
||||||
@ -254,7 +260,7 @@ return non\-zero exit status if result is empty
|
|||||||
run update function after
|
run update function after
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-s\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote}, \fB\-\-source\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote}
|
\fB\-s\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote,PackageSource.Repository}, \fB\-\-source\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote,PackageSource.Repository}
|
||||||
explicitly specify the package source for this command
|
explicitly specify the package source for this command
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
@ -263,7 +269,7 @@ do not add dependencies
|
|||||||
|
|
||||||
.SH OPTIONS 'ahriman package-update'
|
.SH OPTIONS 'ahriman package-update'
|
||||||
usage: ahriman package-add [-h] [-e] [-n]
|
usage: ahriman package-add [-h] [-e] [-n]
|
||||||
[-s {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote}]
|
[-s {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote,PackageSource.Repository}]
|
||||||
[--without-dependencies]
|
[--without-dependencies]
|
||||||
package [package ...]
|
package [package ...]
|
||||||
|
|
||||||
@ -282,7 +288,7 @@ return non\-zero exit status if result is empty
|
|||||||
run update function after
|
run update function after
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-s\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote}, \fB\-\-source\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote}
|
\fB\-s\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote,PackageSource.Repository}, \fB\-\-source\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote,PackageSource.Repository}
|
||||||
explicitly specify the package source for this command
|
explicitly specify the package source for this command
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
@ -439,6 +445,16 @@ remove patches for the package
|
|||||||
package base
|
package base
|
||||||
|
|
||||||
|
|
||||||
|
.SH OPTIONS 'ahriman repo-backup'
|
||||||
|
usage: ahriman repo-backup [-h] path
|
||||||
|
|
||||||
|
backup settings and database
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fBpath\fR
|
||||||
|
path of the output archive
|
||||||
|
|
||||||
|
|
||||||
.SH OPTIONS 'ahriman repo-check'
|
.SH OPTIONS 'ahriman repo-check'
|
||||||
usage: ahriman repo-check [-h] [-e] [--no-vcs] [package ...]
|
usage: ahriman repo-check [-h] [-e] [--no-vcs] [package ...]
|
||||||
|
|
||||||
@ -532,7 +548,7 @@ dump configuration for the specified architecture
|
|||||||
|
|
||||||
|
|
||||||
.SH OPTIONS 'ahriman repo-rebuild'
|
.SH OPTIONS 'ahriman repo-rebuild'
|
||||||
usage: ahriman repo-rebuild [-h] [--depends-on DEPENDS_ON] [--dry-run] [-e]
|
usage: ahriman repo-rebuild [-h] [--depends-on DEPENDS_ON] [--dry-run] [--from-database] [-e]
|
||||||
|
|
||||||
force rebuild whole repository
|
force rebuild whole repository
|
||||||
|
|
||||||
@ -545,12 +561,18 @@ only rebuild packages that depend on specified package
|
|||||||
\fB\-\-dry\-run\fR
|
\fB\-\-dry\-run\fR
|
||||||
just perform check for packages without rebuild process itself
|
just perform check for packages without rebuild process itself
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fB\-\-from\-database\fR
|
||||||
|
read packages from database instead of filesystem. This feature in particular is required in case if you would like to
|
||||||
|
restore repository from another repository instance. Note however that in order to restore packages you need to have
|
||||||
|
original ahriman instance run with web service and have run repo\-update at least once.
|
||||||
|
|
||||||
.TP
|
.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 OPTIONS 'ahriman rebuild'
|
.SH OPTIONS 'ahriman rebuild'
|
||||||
usage: ahriman repo-rebuild [-h] [--depends-on DEPENDS_ON] [--dry-run] [-e]
|
usage: ahriman repo-rebuild [-h] [--depends-on DEPENDS_ON] [--dry-run] [--from-database] [-e]
|
||||||
|
|
||||||
force rebuild whole repository
|
force rebuild whole repository
|
||||||
|
|
||||||
@ -563,6 +585,12 @@ only rebuild packages that depend on specified package
|
|||||||
\fB\-\-dry\-run\fR
|
\fB\-\-dry\-run\fR
|
||||||
just perform check for packages without rebuild process itself
|
just perform check for packages without rebuild process itself
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fB\-\-from\-database\fR
|
||||||
|
read packages from database instead of filesystem. This feature in particular is required in case if you would like to
|
||||||
|
restore repository from another repository instance. Note however that in order to restore packages you need to have
|
||||||
|
original ahriman instance run with web service and have run repo\-update at least once.
|
||||||
|
|
||||||
.TP
|
.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
|
||||||
@ -615,6 +643,19 @@ generate repository report according to current settings
|
|||||||
target to generate report
|
target to generate report
|
||||||
|
|
||||||
|
|
||||||
|
.SH OPTIONS 'ahriman repo-restore'
|
||||||
|
usage: ahriman repo-restore [-h] [-o OUTPUT] path
|
||||||
|
|
||||||
|
restore settings and database
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fBpath\fR
|
||||||
|
path of the input archive
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fB\-o\fR \fI\,OUTPUT\/\fR, \fB\-\-output\fR \fI\,OUTPUT\/\fR
|
||||||
|
root path of the extracted files
|
||||||
|
|
||||||
.SH OPTIONS 'ahriman repo-setup'
|
.SH OPTIONS 'ahriman repo-setup'
|
||||||
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] [--no-multilib] --packager PACKAGER --repository
|
||||||
|
@ -114,6 +114,18 @@ Section name must be either `html` (plus optional architecture name, e.g. `html:
|
|||||||
* `link_path` - prefix for HTML links, string, required.
|
* `link_path` - prefix for HTML links, string, required.
|
||||||
* `template_path` - path to Jinja2 template, string, required.
|
* `template_path` - path to Jinja2 template, string, required.
|
||||||
|
|
||||||
|
### `telegram` type
|
||||||
|
|
||||||
|
Section name must be either `telegram` (plus optional architecture name, e.g. `telegram:x86_64`) or random name with `type` set.
|
||||||
|
|
||||||
|
* `type` - type of the report, string, optional, must be set to `telegram` if exists.
|
||||||
|
* `api_key` - telegram bot API key, string, required. Please refer FAQ about how to create chat and bot
|
||||||
|
* `chat_id` - telegram chat id, either string with `@` or integer value, required.
|
||||||
|
* `homepage` - link to homepage, string, optional.
|
||||||
|
* `link_path` - prefix for HTML links, string, required.
|
||||||
|
* `template_path` - path to Jinja2 template, string, required.
|
||||||
|
* `template_type` - `parse_mode` to be passed to telegram API, one of `MarkdownV2`, `HTML`, `Markdown`, string, optional, default `HTML`.
|
||||||
|
|
||||||
## `upload` group
|
## `upload` group
|
||||||
|
|
||||||
Remote synchronization settings.
|
Remote synchronization settings.
|
||||||
|
80
docs/faq.md
80
docs/faq.md
@ -199,7 +199,7 @@ server {
|
|||||||
|
|
||||||
## 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 `latest` tag; 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 master commit as well as on each version. If you would like to use last (probably unstable) build you can use `edge` tag or `latest` for any tagged versions; otherwise you can use any version tag available.
|
||||||
|
|
||||||
The default action (in case if no arguments provided) is `repo-update`. Basically the idea is to run container, e.g.:
|
The default action (in case if no arguments provided) is `repo-update`. Basically the idea is to run container, e.g.:
|
||||||
|
|
||||||
@ -242,7 +242,7 @@ You can pass any of these variables by using `-e` argument, e.g.:
|
|||||||
docker run -e AHRIMAN_PORT=8080 arcan1s/ahriman:latest
|
docker run -e AHRIMAN_PORT=8080 arcan1s/ahriman:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
### Working with web service
|
### Web service setup
|
||||||
|
|
||||||
Well for that you would need to have web container instance running forever; it can be achieved by the following command:
|
Well for that you would need to have web container instance running forever; it can be achieved by the following command:
|
||||||
|
|
||||||
@ -402,6 +402,46 @@ There are several choices:
|
|||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
1. It still requires additional dependencies:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
yay -S python-jinja
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Register bot in telegram. You can do it by talking with [@BotFather](https://t.me/botfather). For more details please refer to [official documentation](https://core.telegram.org/bots).
|
||||||
|
|
||||||
|
3. Optionally (if you want to post message in chat):
|
||||||
|
|
||||||
|
1. Create telegram channel.
|
||||||
|
2. Invite your bot into the channel.
|
||||||
|
3. Make your channel public
|
||||||
|
|
||||||
|
4. Get chat id if you want to use by numerical id or just use id prefixed with `@` (e.g. `@ahriman`). If you are not using chat the chat id is your user id. If you don't want to make channel public you can use [this guide](https://stackoverflow.com/a/33862907).
|
||||||
|
|
||||||
|
5. Configure the service:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[report]
|
||||||
|
target = telegram
|
||||||
|
|
||||||
|
[telegram]
|
||||||
|
api_key = aaAAbbBBccCC
|
||||||
|
chat_id = @ahriman
|
||||||
|
link_path = http://example.com/x86_64
|
||||||
|
```
|
||||||
|
|
||||||
|
`api_key` is the one sent by [@BotFather](https://t.me/botfather), `chat_id` is the value retrieved from previous step.
|
||||||
|
|
||||||
|
If you did everything fine you should receive the message with the next update. Quick credentials check can be done by using the following command:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl 'https://api.telegram.org/bot${CHAT_ID}/sendMessage?chat_id=${API_KEY}&text=hello'
|
||||||
|
```
|
||||||
|
|
||||||
|
(replace `${CHAT_ID}` and `${API_KEY}` with the values from configuration).
|
||||||
|
|
||||||
## Web service
|
## Web service
|
||||||
|
|
||||||
### Readme mentions web interface, how do I use it?
|
### Readme mentions web interface, how do I use it?
|
||||||
@ -479,6 +519,36 @@ After these steps `index.html` file will be automatically synced to S3
|
|||||||
5. Create end-user `sudo -u ahriman ahriman user-add -r write my-first-user`. When it will ask for the password leave it blank.
|
5. Create end-user `sudo -u ahriman ahriman user-add -r write my-first-user`. When it will ask for the password leave it blank.
|
||||||
6. Restart web service `systemctl restart ahriman-web@x86_64`.
|
6. Restart web service `systemctl restart ahriman-web@x86_64`.
|
||||||
|
|
||||||
|
## Backup and restore
|
||||||
|
|
||||||
|
The service provides several commands aim to do easy repository backup and restore. If you would like to move repository from the server `server1.example.com` to another `server2.example.com` you have to perform the following steps:
|
||||||
|
|
||||||
|
1. On the source server `server1.example.com` run `repo-backup` command, e.g.:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
sudo ahriman repo-backup /tmp/repo.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
This command will pack all configuration files together with database file into the archive specified as command line argument (i.e. `/tmp/repo.tar.gz`). In addition it will also archive `cache` directory (the one which contains local clones used by e.g. local packages) and `.gnupg` of the `ahriman` user.
|
||||||
|
|
||||||
|
2. Copy created archive from source server `server1.example.com` to target `server2.example.com`.
|
||||||
|
|
||||||
|
3. Install ahriman as usual on the target server `server2.example.com` if you didn't yet.
|
||||||
|
|
||||||
|
4. Extract archive e.g. by using subcommand:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
sudo ahriman repo-restore /tmp/repo.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
An additional argument `-o`/`--output` can be used to specify extraction root (`/` by default).
|
||||||
|
|
||||||
|
5. Rebuild repository:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
sudo -u ahriman ahriman repo-rebuild --from-database
|
||||||
|
```
|
||||||
|
|
||||||
## Other topics
|
## Other topics
|
||||||
|
|
||||||
### How does it differ from %another-manager%?
|
### How does it differ from %another-manager%?
|
||||||
@ -518,6 +588,10 @@ Though originally I've created ahriman by trying to improve the project, it stil
|
|||||||
|
|
||||||
`repo-scripts` also have bad architecture and bad quality code and uses out-of-dated `yaourt` and `package-query`.
|
`repo-scripts` also have bad architecture and bad quality code and uses out-of-dated `yaourt` and `package-query`.
|
||||||
|
|
||||||
|
#### [toolbox](https://github.com/chaotic-aur/toolbox)
|
||||||
|
|
||||||
|
It is automation tools for `repoctl` mentioned above. Except for using shell it looks pretty cool and also offers some additional features like patches, remote synchronization (isn't it?) and reporting.
|
||||||
|
|
||||||
### I would like to check service logs
|
### I would like to check service logs
|
||||||
|
|
||||||
By default, the service writes logs to `/dev/log` which can be accessed by using `journalctl` command (logs are written to the journal of the user under which command is run).
|
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).
|
||||||
@ -528,7 +602,7 @@ You can also edit configuration and forward logs to `stderr`, just change `handl
|
|||||||
sed -i 's/handlers = syslog_handler/handlers = console_handler/g' /etc/ahriman.ini.d/logging.ini
|
sed -i 's/handlers = syslog_handler/handlers = console_handler/g' /etc/ahriman.ini.d/logging.ini
|
||||||
```
|
```
|
||||||
|
|
||||||
You can even configure logging as you wish, but kindly refer to python `logging` module configuration.
|
You can even configure logging as you wish, but kindly refer to python `logging` module [configuration](https://docs.python.org/3/library/logging.config.html).
|
||||||
|
|
||||||
### Html customization
|
### Html customization
|
||||||
|
|
||||||
|
50
docs/source/ahriman.application.application.rst
Normal file
50
docs/source/ahriman.application.application.rst
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
ahriman.application.application package
|
||||||
|
=======================================
|
||||||
|
|
||||||
|
Submodules
|
||||||
|
----------
|
||||||
|
|
||||||
|
ahriman.application.application.application module
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.application.application.application
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.application.application.application\_packages module
|
||||||
|
------------------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.application.application.application_packages
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.application.application.application\_properties module
|
||||||
|
--------------------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.application.application.application_properties
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.application.application.application\_repository module
|
||||||
|
--------------------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.application.application.application_repository
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
Module contents
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.application.application
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
221
docs/source/ahriman.application.handlers.rst
Normal file
221
docs/source/ahriman.application.handlers.rst
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
ahriman.application.handlers package
|
||||||
|
====================================
|
||||||
|
|
||||||
|
Submodules
|
||||||
|
----------
|
||||||
|
|
||||||
|
ahriman.application.handlers.add module
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.application.handlers.add
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.application.handlers.backup module
|
||||||
|
------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.application.handlers.backup
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.application.handlers.clean module
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.application.handlers.clean
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.application.handlers.dump module
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.application.handlers.dump
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.application.handlers.handler module
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.application.handlers.handler
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.application.handlers.help module
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.application.handlers.help
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.application.handlers.key\_import module
|
||||||
|
-----------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.application.handlers.key_import
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.application.handlers.patch module
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.application.handlers.patch
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.application.handlers.rebuild module
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.application.handlers.rebuild
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.application.handlers.remove module
|
||||||
|
------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.application.handlers.remove
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.application.handlers.remove\_unknown module
|
||||||
|
---------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.application.handlers.remove_unknown
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.application.handlers.report module
|
||||||
|
------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.application.handlers.report
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.application.handlers.restore module
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.application.handlers.restore
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.application.handlers.search module
|
||||||
|
------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.application.handlers.search
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.application.handlers.setup module
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.application.handlers.setup
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.application.handlers.sign module
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.application.handlers.sign
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.application.handlers.status module
|
||||||
|
------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.application.handlers.status
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.application.handlers.status\_update module
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.application.handlers.status_update
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.application.handlers.sync module
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.application.handlers.sync
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.application.handlers.unsafe\_commands module
|
||||||
|
----------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.application.handlers.unsafe_commands
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.application.handlers.update module
|
||||||
|
------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.application.handlers.update
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.application.handlers.users module
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.application.handlers.users
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.application.handlers.web module
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.application.handlers.web
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
Module contents
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.application.handlers
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
41
docs/source/ahriman.application.rst
Normal file
41
docs/source/ahriman.application.rst
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
ahriman.application package
|
||||||
|
===========================
|
||||||
|
|
||||||
|
Subpackages
|
||||||
|
-----------
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 4
|
||||||
|
|
||||||
|
ahriman.application.application
|
||||||
|
ahriman.application.handlers
|
||||||
|
|
||||||
|
Submodules
|
||||||
|
----------
|
||||||
|
|
||||||
|
ahriman.application.ahriman module
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.application.ahriman
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.application.lock module
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.application.lock
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
Module contents
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.application
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
41
docs/source/ahriman.core.alpm.remote.rst
Normal file
41
docs/source/ahriman.core.alpm.remote.rst
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
ahriman.core.alpm.remote package
|
||||||
|
================================
|
||||||
|
|
||||||
|
Submodules
|
||||||
|
----------
|
||||||
|
|
||||||
|
ahriman.core.alpm.remote.aur module
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.alpm.remote.aur
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.alpm.remote.official module
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.alpm.remote.official
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.alpm.remote.remote module
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.alpm.remote.remote
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
Module contents
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.alpm.remote
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
40
docs/source/ahriman.core.alpm.rst
Normal file
40
docs/source/ahriman.core.alpm.rst
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
ahriman.core.alpm package
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Subpackages
|
||||||
|
-----------
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 4
|
||||||
|
|
||||||
|
ahriman.core.alpm.remote
|
||||||
|
|
||||||
|
Submodules
|
||||||
|
----------
|
||||||
|
|
||||||
|
ahriman.core.alpm.pacman module
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.alpm.pacman
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.alpm.repo module
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.alpm.repo
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
Module contents
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.alpm
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
50
docs/source/ahriman.core.auth.rst
Normal file
50
docs/source/ahriman.core.auth.rst
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
ahriman.core.auth package
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Submodules
|
||||||
|
----------
|
||||||
|
|
||||||
|
ahriman.core.auth.auth module
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.auth.auth
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.auth.helpers module
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.auth.helpers
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.auth.mapping module
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.auth.mapping
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.auth.oauth module
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.auth.oauth
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
Module contents
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.auth
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
32
docs/source/ahriman.core.build_tools.rst
Normal file
32
docs/source/ahriman.core.build_tools.rst
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
ahriman.core.build\_tools package
|
||||||
|
=================================
|
||||||
|
|
||||||
|
Submodules
|
||||||
|
----------
|
||||||
|
|
||||||
|
ahriman.core.build\_tools.sources module
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.build_tools.sources
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.build\_tools.task module
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.build_tools.task
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
Module contents
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.build_tools
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
41
docs/source/ahriman.core.database.data.rst
Normal file
41
docs/source/ahriman.core.database.data.rst
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
ahriman.core.database.data package
|
||||||
|
==================================
|
||||||
|
|
||||||
|
Submodules
|
||||||
|
----------
|
||||||
|
|
||||||
|
ahriman.core.database.data.package\_statuses module
|
||||||
|
---------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.database.data.package_statuses
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.database.data.patches module
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.database.data.patches
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.database.data.users module
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.database.data.users
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
Module contents
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.database.data
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
23
docs/source/ahriman.core.database.migrations.rst
Normal file
23
docs/source/ahriman.core.database.migrations.rst
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
ahriman.core.database.migrations package
|
||||||
|
========================================
|
||||||
|
|
||||||
|
Submodules
|
||||||
|
----------
|
||||||
|
|
||||||
|
ahriman.core.database.migrations.m000\_initial module
|
||||||
|
-----------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.database.migrations.m000_initial
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
Module contents
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.database.migrations
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
59
docs/source/ahriman.core.database.operations.rst
Normal file
59
docs/source/ahriman.core.database.operations.rst
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
ahriman.core.database.operations package
|
||||||
|
========================================
|
||||||
|
|
||||||
|
Submodules
|
||||||
|
----------
|
||||||
|
|
||||||
|
ahriman.core.database.operations.auth\_operations module
|
||||||
|
--------------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.database.operations.auth_operations
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.database.operations.build\_operations module
|
||||||
|
---------------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.database.operations.build_operations
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.database.operations.operations module
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.database.operations.operations
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.database.operations.package\_operations module
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.database.operations.package_operations
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.database.operations.patch\_operations module
|
||||||
|
---------------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.database.operations.patch_operations
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
Module contents
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.database.operations
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
33
docs/source/ahriman.core.database.rst
Normal file
33
docs/source/ahriman.core.database.rst
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
ahriman.core.database package
|
||||||
|
=============================
|
||||||
|
|
||||||
|
Subpackages
|
||||||
|
-----------
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 4
|
||||||
|
|
||||||
|
ahriman.core.database.data
|
||||||
|
ahriman.core.database.migrations
|
||||||
|
ahriman.core.database.operations
|
||||||
|
|
||||||
|
Submodules
|
||||||
|
----------
|
||||||
|
|
||||||
|
ahriman.core.database.sqlite module
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.database.sqlite
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
Module contents
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.database
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
95
docs/source/ahriman.core.formatters.rst
Normal file
95
docs/source/ahriman.core.formatters.rst
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
ahriman.core.formatters package
|
||||||
|
===============================
|
||||||
|
|
||||||
|
Submodules
|
||||||
|
----------
|
||||||
|
|
||||||
|
ahriman.core.formatters.aur\_printer module
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.formatters.aur_printer
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.formatters.build\_printer module
|
||||||
|
---------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.formatters.build_printer
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.formatters.configuration\_printer module
|
||||||
|
-----------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.formatters.configuration_printer
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.formatters.package\_printer module
|
||||||
|
-----------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.formatters.package_printer
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.formatters.printer module
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.formatters.printer
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.formatters.status\_printer module
|
||||||
|
----------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.formatters.status_printer
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.formatters.string\_printer module
|
||||||
|
----------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.formatters.string_printer
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.formatters.update\_printer module
|
||||||
|
----------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.formatters.update_printer
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.formatters.user\_printer module
|
||||||
|
--------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.formatters.user_printer
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
Module contents
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.formatters
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
68
docs/source/ahriman.core.report.rst
Normal file
68
docs/source/ahriman.core.report.rst
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
ahriman.core.report package
|
||||||
|
===========================
|
||||||
|
|
||||||
|
Submodules
|
||||||
|
----------
|
||||||
|
|
||||||
|
ahriman.core.report.console module
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.report.console
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.report.email module
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.report.email
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.report.html module
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.report.html
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.report.jinja\_template module
|
||||||
|
------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.report.jinja_template
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.report.report module
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.report.report
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.report.telegram module
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.report.telegram
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
Module contents
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.report
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
59
docs/source/ahriman.core.repository.rst
Normal file
59
docs/source/ahriman.core.repository.rst
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
ahriman.core.repository package
|
||||||
|
===============================
|
||||||
|
|
||||||
|
Submodules
|
||||||
|
----------
|
||||||
|
|
||||||
|
ahriman.core.repository.cleaner module
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.repository.cleaner
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.repository.executor module
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.repository.executor
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.repository.repository module
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.repository.repository
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.repository.repository\_properties module
|
||||||
|
-----------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.repository.repository_properties
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.repository.update\_handler module
|
||||||
|
----------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.repository.update_handler
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
Module contents
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.repository
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
76
docs/source/ahriman.core.rst
Normal file
76
docs/source/ahriman.core.rst
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
ahriman.core package
|
||||||
|
====================
|
||||||
|
|
||||||
|
Subpackages
|
||||||
|
-----------
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 4
|
||||||
|
|
||||||
|
ahriman.core.alpm
|
||||||
|
ahriman.core.auth
|
||||||
|
ahriman.core.build_tools
|
||||||
|
ahriman.core.database
|
||||||
|
ahriman.core.formatters
|
||||||
|
ahriman.core.report
|
||||||
|
ahriman.core.repository
|
||||||
|
ahriman.core.sign
|
||||||
|
ahriman.core.status
|
||||||
|
ahriman.core.upload
|
||||||
|
|
||||||
|
Submodules
|
||||||
|
----------
|
||||||
|
|
||||||
|
ahriman.core.configuration module
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.configuration
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.exceptions module
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.exceptions
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.spawn module
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.spawn
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.tree module
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.tree
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.util module
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.util
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
Module contents
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
23
docs/source/ahriman.core.sign.rst
Normal file
23
docs/source/ahriman.core.sign.rst
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
ahriman.core.sign package
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Submodules
|
||||||
|
----------
|
||||||
|
|
||||||
|
ahriman.core.sign.gpg module
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.sign.gpg
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
Module contents
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.sign
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
41
docs/source/ahriman.core.status.rst
Normal file
41
docs/source/ahriman.core.status.rst
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
ahriman.core.status package
|
||||||
|
===========================
|
||||||
|
|
||||||
|
Submodules
|
||||||
|
----------
|
||||||
|
|
||||||
|
ahriman.core.status.client module
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.status.client
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.status.watcher module
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.status.watcher
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.status.web\_client module
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.status.web_client
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
Module contents
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.status
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
59
docs/source/ahriman.core.upload.rst
Normal file
59
docs/source/ahriman.core.upload.rst
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
ahriman.core.upload package
|
||||||
|
===========================
|
||||||
|
|
||||||
|
Submodules
|
||||||
|
----------
|
||||||
|
|
||||||
|
ahriman.core.upload.github module
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.upload.github
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.upload.http\_upload module
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.upload.http_upload
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.upload.rsync module
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.upload.rsync
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.upload.s3 module
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.upload.s3
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.core.upload.upload module
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.upload.upload
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
Module contents
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.upload
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
203
docs/source/ahriman.models.rst
Normal file
203
docs/source/ahriman.models.rst
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
ahriman.models package
|
||||||
|
======================
|
||||||
|
|
||||||
|
Submodules
|
||||||
|
----------
|
||||||
|
|
||||||
|
ahriman.models.action module
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.models.action
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.models.aur\_package module
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.models.aur_package
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.models.auth\_settings module
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.models.auth_settings
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.models.build\_status module
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.models.build_status
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.models.counters module
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.models.counters
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.models.internal\_status module
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.models.internal_status
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.models.migration module
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.models.migration
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.models.migration\_result module
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.models.migration_result
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.models.package module
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.models.package
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.models.package\_description module
|
||||||
|
------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.models.package_description
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.models.package\_source module
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.models.package_source
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.models.property module
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.models.property
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.models.report\_settings module
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.models.report_settings
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.models.repository\_paths module
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.models.repository_paths
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.models.result module
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.models.result
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.models.sign\_settings module
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.models.sign_settings
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.models.smtp\_ssl\_settings module
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.models.smtp_ssl_settings
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.models.upload\_settings module
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.models.upload_settings
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.models.user module
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.models.user
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.models.user\_access module
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.models.user_access
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.models.user\_identity module
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.models.user_identity
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
Module contents
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.models
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
34
docs/source/ahriman.rst
Normal file
34
docs/source/ahriman.rst
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
ahriman package
|
||||||
|
===============
|
||||||
|
|
||||||
|
Subpackages
|
||||||
|
-----------
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 4
|
||||||
|
|
||||||
|
ahriman.application
|
||||||
|
ahriman.core
|
||||||
|
ahriman.models
|
||||||
|
ahriman.web
|
||||||
|
|
||||||
|
Submodules
|
||||||
|
----------
|
||||||
|
|
||||||
|
ahriman.version module
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.version
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
Module contents
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
32
docs/source/ahriman.web.middlewares.rst
Normal file
32
docs/source/ahriman.web.middlewares.rst
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
ahriman.web.middlewares package
|
||||||
|
===============================
|
||||||
|
|
||||||
|
Submodules
|
||||||
|
----------
|
||||||
|
|
||||||
|
ahriman.web.middlewares.auth\_handler module
|
||||||
|
--------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.web.middlewares.auth_handler
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.web.middlewares.exception\_handler module
|
||||||
|
-------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.web.middlewares.exception_handler
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
Module contents
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.web.middlewares
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
41
docs/source/ahriman.web.rst
Normal file
41
docs/source/ahriman.web.rst
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
ahriman.web package
|
||||||
|
===================
|
||||||
|
|
||||||
|
Subpackages
|
||||||
|
-----------
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 4
|
||||||
|
|
||||||
|
ahriman.web.middlewares
|
||||||
|
ahriman.web.views
|
||||||
|
|
||||||
|
Submodules
|
||||||
|
----------
|
||||||
|
|
||||||
|
ahriman.web.routes module
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.web.routes
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.web.web module
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.web.web
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
Module contents
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.web
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
42
docs/source/ahriman.web.views.rst
Normal file
42
docs/source/ahriman.web.views.rst
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
ahriman.web.views package
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Subpackages
|
||||||
|
-----------
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 4
|
||||||
|
|
||||||
|
ahriman.web.views.service
|
||||||
|
ahriman.web.views.status
|
||||||
|
ahriman.web.views.user
|
||||||
|
|
||||||
|
Submodules
|
||||||
|
----------
|
||||||
|
|
||||||
|
ahriman.web.views.base module
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.web.views.base
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.web.views.index module
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.web.views.index
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
Module contents
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.web.views
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
50
docs/source/ahriman.web.views.service.rst
Normal file
50
docs/source/ahriman.web.views.service.rst
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
ahriman.web.views.service package
|
||||||
|
=================================
|
||||||
|
|
||||||
|
Submodules
|
||||||
|
----------
|
||||||
|
|
||||||
|
ahriman.web.views.service.add module
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.web.views.service.add
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.web.views.service.remove module
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.web.views.service.remove
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.web.views.service.request module
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.web.views.service.request
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.web.views.service.search module
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.web.views.service.search
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
Module contents
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.web.views.service
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
50
docs/source/ahriman.web.views.status.rst
Normal file
50
docs/source/ahriman.web.views.status.rst
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
ahriman.web.views.status package
|
||||||
|
================================
|
||||||
|
|
||||||
|
Submodules
|
||||||
|
----------
|
||||||
|
|
||||||
|
ahriman.web.views.status.ahriman module
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.web.views.status.ahriman
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.web.views.status.package module
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.web.views.status.package
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.web.views.status.packages module
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.web.views.status.packages
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.web.views.status.status module
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.web.views.status.status
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
Module contents
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.web.views.status
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
32
docs/source/ahriman.web.views.user.rst
Normal file
32
docs/source/ahriman.web.views.user.rst
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
ahriman.web.views.user package
|
||||||
|
==============================
|
||||||
|
|
||||||
|
Submodules
|
||||||
|
----------
|
||||||
|
|
||||||
|
ahriman.web.views.user.login module
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.web.views.user.login
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
ahriman.web.views.user.logout module
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.web.views.user.logout
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
Module contents
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.web.views.user
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:private-members:
|
83
docs/source/conf.py
Normal file
83
docs/source/conf.py
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
# Configuration file for the Sphinx documentation builder.
|
||||||
|
#
|
||||||
|
# This file only contains a selection of the most common options. For a full
|
||||||
|
# list see the documentation:
|
||||||
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
||||||
|
|
||||||
|
# -- Path setup --------------------------------------------------------------
|
||||||
|
|
||||||
|
# If extensions (or modules to document with autodoc) are in another directory,
|
||||||
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
|
#
|
||||||
|
import os
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
# import sys
|
||||||
|
# sys.path.insert(0, os.path.abspath("."))
|
||||||
|
|
||||||
|
basedir = Path(__file__).resolve().parent.parent.parent
|
||||||
|
metadata_path = basedir / "src/ahriman/version.py"
|
||||||
|
metadata = {}
|
||||||
|
with metadata_path.open() as metadata_file:
|
||||||
|
exec(metadata_file.read(), metadata) # pylint: disable=exec-used
|
||||||
|
|
||||||
|
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
|
||||||
|
|
||||||
|
|
||||||
|
# -- Project information -----------------------------------------------------
|
||||||
|
|
||||||
|
project = "ahriman"
|
||||||
|
copyright = "2021-2022, ahriman team"
|
||||||
|
author = "ahriman team"
|
||||||
|
|
||||||
|
# The full version, including alpha/beta/rc tags
|
||||||
|
release = metadata["__version__"]
|
||||||
|
|
||||||
|
|
||||||
|
# -- General configuration ---------------------------------------------------
|
||||||
|
|
||||||
|
# Add any Sphinx extension module names here, as strings. They can be
|
||||||
|
# extensions coming with Sphinx (named "sphinx.ext.*") or your custom
|
||||||
|
# ones.
|
||||||
|
extensions = [
|
||||||
|
"sphinx.ext.autodoc",
|
||||||
|
"sphinx.ext.napoleon",
|
||||||
|
]
|
||||||
|
|
||||||
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
|
templates_path = ["_templates"]
|
||||||
|
|
||||||
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
|
# for a list of supported languages.
|
||||||
|
#
|
||||||
|
# This is also used if you do content translation via gettext catalogs.
|
||||||
|
# Usually you set "language" from the command line for these cases.
|
||||||
|
language = "en"
|
||||||
|
|
||||||
|
# List of patterns, relative to source directory, that match files and
|
||||||
|
# directories to ignore when looking for source files.
|
||||||
|
# This pattern also affects html_static_path and html_extra_path.
|
||||||
|
exclude_patterns = []
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for HTML output -------------------------------------------------
|
||||||
|
|
||||||
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
|
# a list of builtin themes.
|
||||||
|
#
|
||||||
|
html_theme = "default" if on_rtd else "alabaster"
|
||||||
|
|
||||||
|
# Add any paths that contain custom static files (such as style sheets) here,
|
||||||
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||||
|
html_static_path = ["_static"]
|
||||||
|
|
||||||
|
|
||||||
|
# -- Extension configuration -------------------------------------------------
|
||||||
|
|
||||||
|
autodoc_member_order = "groupwise"
|
||||||
|
|
||||||
|
autodoc_default_options = {
|
||||||
|
"no-undoc-members": True,
|
||||||
|
}
|
27
docs/source/index.rst
Normal file
27
docs/source/index.rst
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
Welcome to ahriman's documentation!
|
||||||
|
===================================
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
:caption: Contents:
|
||||||
|
|
||||||
|
Wrapper for managing custom repository inspired by `repo-scripts <https://github.com/arcan1s/repo-scripts>`_.
|
||||||
|
|
||||||
|
Features
|
||||||
|
--------
|
||||||
|
|
||||||
|
* Install-configure-forget manager for own repository.
|
||||||
|
* Multi-architecture support.
|
||||||
|
* VCS packages support.
|
||||||
|
* Sign support with gpg (repository, package, per package settings).
|
||||||
|
* Synchronization to remote services (rsync, s3 and github) and report generation (email, html, telegram).
|
||||||
|
* Dependency manager.
|
||||||
|
* Ability to patch AUR packages and even create package from local PKGBUILDs.
|
||||||
|
* Repository status interface with optional authorization and control options.
|
||||||
|
|
||||||
|
Indices and tables
|
||||||
|
==================
|
||||||
|
|
||||||
|
* :ref:`genindex`
|
||||||
|
* :ref:`modindex`
|
||||||
|
* :ref:`search`
|
7
docs/source/modules.rst
Normal file
7
docs/source/modules.rst
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
src
|
||||||
|
===
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 4
|
||||||
|
|
||||||
|
ahriman
|
@ -1,7 +1,7 @@
|
|||||||
# Maintainer: Evgeniy Alekseev
|
# Maintainer: Evgeniy Alekseev
|
||||||
|
|
||||||
pkgname='ahriman'
|
pkgname='ahriman'
|
||||||
pkgver=2.0.0rc2
|
pkgver=2.0.0rc7
|
||||||
pkgrel=1
|
pkgrel=1
|
||||||
pkgdesc="ArcH Linux ReposItory MANager"
|
pkgdesc="ArcH Linux ReposItory MANager"
|
||||||
arch=('any')
|
arch=('any')
|
||||||
@ -38,7 +38,7 @@ build() {
|
|||||||
package() {
|
package() {
|
||||||
cd "$pkgname"
|
cd "$pkgname"
|
||||||
|
|
||||||
python -m installer --destdir="$pkgdir" dist/*.whl
|
python -m installer --destdir="$pkgdir" "dist/$pkgname-$pkgver-py3-none-any.whl"
|
||||||
|
|
||||||
# python-installer actually thinks that you cannot just copy files to root
|
# python-installer actually thinks that you cannot just copy files to root
|
||||||
# thus we need to copy them manually
|
# thus we need to copy them manually
|
||||||
|
@ -45,6 +45,9 @@ ssl = disabled
|
|||||||
[html]
|
[html]
|
||||||
template_path = /usr/share/ahriman/templates/repo-index.jinja2
|
template_path = /usr/share/ahriman/templates/repo-index.jinja2
|
||||||
|
|
||||||
|
[telegram]
|
||||||
|
template_path = /usr/share/ahriman/templates/telegram-index.jinja2
|
||||||
|
|
||||||
[upload]
|
[upload]
|
||||||
target =
|
target =
|
||||||
|
|
||||||
|
4
package/share/ahriman/templates/telegram-index.jinja2
Normal file
4
package/share/ahriman/templates/telegram-index.jinja2
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{#simplified version of full report#}
|
||||||
|
<b>{{ repository }} update</b>
|
||||||
|
{% for package in packages %}
|
||||||
|
<a href="{{ link_path }}/{{ package.filename }}">{{ package.name }}</a> {{ package.version }}{% endfor %}
|
14
setup.py
14
setup.py
@ -31,7 +31,6 @@ setup(
|
|||||||
install_requires=[
|
install_requires=[
|
||||||
"inflection",
|
"inflection",
|
||||||
"passlib",
|
"passlib",
|
||||||
"pyalpm",
|
|
||||||
"requests",
|
"requests",
|
||||||
"srcinfo",
|
"srcinfo",
|
||||||
],
|
],
|
||||||
@ -67,6 +66,7 @@ setup(
|
|||||||
"package/share/ahriman/templates/build-status.jinja2",
|
"package/share/ahriman/templates/build-status.jinja2",
|
||||||
"package/share/ahriman/templates/email-index.jinja2",
|
"package/share/ahriman/templates/email-index.jinja2",
|
||||||
"package/share/ahriman/templates/repo-index.jinja2",
|
"package/share/ahriman/templates/repo-index.jinja2",
|
||||||
|
"package/share/ahriman/templates/telegram-index.jinja2",
|
||||||
]),
|
]),
|
||||||
("share/ahriman/templates/build-status", [
|
("share/ahriman/templates/build-status", [
|
||||||
"package/share/ahriman/templates/build-status/login-modal.jinja2",
|
"package/share/ahriman/templates/build-status/login-modal.jinja2",
|
||||||
@ -92,6 +92,18 @@ setup(
|
|||||||
"mypy",
|
"mypy",
|
||||||
"pylint",
|
"pylint",
|
||||||
],
|
],
|
||||||
|
"docs": [
|
||||||
|
"Sphinx",
|
||||||
|
"argparse-manpage",
|
||||||
|
"pydeps",
|
||||||
|
"sphinxcontrib-napoleon",
|
||||||
|
],
|
||||||
|
# FIXME technically this dependency is required, but in some cases we do not have access to
|
||||||
|
# the libalpm which is required in order to install the package. Thus in case if we do not
|
||||||
|
# really need to run the application we can move it to "optional" dependencies
|
||||||
|
"pacman": [
|
||||||
|
"pyalpm",
|
||||||
|
],
|
||||||
"s3": [
|
"s3": [
|
||||||
"boto3",
|
"boto3",
|
||||||
],
|
],
|
||||||
|
@ -43,8 +43,12 @@ SubParserAction = TypeVar("SubParserAction", bound="argparse._SubParsersAction[a
|
|||||||
def _formatter(prog: str) -> argparse.HelpFormatter:
|
def _formatter(prog: str) -> argparse.HelpFormatter:
|
||||||
"""
|
"""
|
||||||
formatter for the help message
|
formatter for the help message
|
||||||
:param prog: application name
|
|
||||||
:return: formatter used by default
|
Args:
|
||||||
|
prog(str): application name
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.HelpFormatter: formatter used by default
|
||||||
"""
|
"""
|
||||||
return argparse.ArgumentDefaultsHelpFormatter(prog, width=120)
|
return argparse.ArgumentDefaultsHelpFormatter(prog, width=120)
|
||||||
|
|
||||||
@ -52,7 +56,9 @@ def _formatter(prog: str) -> argparse.HelpFormatter:
|
|||||||
def _parser() -> argparse.ArgumentParser:
|
def _parser() -> argparse.ArgumentParser:
|
||||||
"""
|
"""
|
||||||
command line parser generator
|
command line parser generator
|
||||||
:return: command line parser for the application
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: command line parser for the application
|
||||||
"""
|
"""
|
||||||
parser = argparse.ArgumentParser(prog="ahriman", description="ArcH Linux ReposItory MANager",
|
parser = argparse.ArgumentParser(prog="ahriman", description="ArcH Linux ReposItory MANager",
|
||||||
epilog="Argument list can also be read from file by using @ prefix.",
|
epilog="Argument list can also be read from file by using @ prefix.",
|
||||||
@ -83,12 +89,14 @@ 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_repo_backup_parser(subparsers)
|
||||||
_set_repo_check_parser(subparsers)
|
_set_repo_check_parser(subparsers)
|
||||||
_set_repo_clean_parser(subparsers)
|
_set_repo_clean_parser(subparsers)
|
||||||
_set_repo_config_parser(subparsers)
|
_set_repo_config_parser(subparsers)
|
||||||
_set_repo_rebuild_parser(subparsers)
|
_set_repo_rebuild_parser(subparsers)
|
||||||
_set_repo_remove_unknown_parser(subparsers)
|
_set_repo_remove_unknown_parser(subparsers)
|
||||||
_set_repo_report_parser(subparsers)
|
_set_repo_report_parser(subparsers)
|
||||||
|
_set_repo_restore_parser(subparsers)
|
||||||
_set_repo_setup_parser(subparsers)
|
_set_repo_setup_parser(subparsers)
|
||||||
_set_repo_sign_parser(subparsers)
|
_set_repo_sign_parser(subparsers)
|
||||||
_set_repo_status_update_parser(subparsers)
|
_set_repo_status_update_parser(subparsers)
|
||||||
@ -105,8 +113,12 @@ def _parser() -> argparse.ArgumentParser:
|
|||||||
def _set_aur_search_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
def _set_aur_search_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
"""
|
"""
|
||||||
add parser for AUR search subcommand
|
add parser for AUR search subcommand
|
||||||
:param root: subparsers for the commands
|
|
||||||
:return: created argument parser
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
"""
|
"""
|
||||||
parser = root.add_parser("aur-search", aliases=["search"], help="search for package",
|
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)
|
||||||
@ -124,8 +136,12 @@ def _set_aur_search_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
def _set_help_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
def _set_help_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
"""
|
"""
|
||||||
add parser for listing help subcommand
|
add parser for listing help subcommand
|
||||||
:param root: subparsers for the commands
|
|
||||||
:return: created argument parser
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
"""
|
"""
|
||||||
parser = root.add_parser("help", help="show help message",
|
parser = root.add_parser("help", help="show help message",
|
||||||
description="show help message for application or command and exit",
|
description="show help message for application or command and exit",
|
||||||
@ -139,8 +155,12 @@ def _set_help_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
def _set_help_commands_unsafe_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
def _set_help_commands_unsafe_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
"""
|
"""
|
||||||
add parser for listing unsafe commands
|
add parser for listing unsafe commands
|
||||||
:param root: subparsers for the commands
|
|
||||||
:return: created argument parser
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
"""
|
"""
|
||||||
parser = root.add_parser("help-commands-unsafe", help="list unsafe commands",
|
parser = root.add_parser("help-commands-unsafe", help="list unsafe commands",
|
||||||
description="list unsafe commands as defined in default args", formatter_class=_formatter)
|
description="list unsafe commands as defined in default args", formatter_class=_formatter)
|
||||||
@ -154,8 +174,12 @@ def _set_help_commands_unsafe_parser(root: SubParserAction) -> argparse.Argument
|
|||||||
def _set_key_import_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
def _set_key_import_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
"""
|
"""
|
||||||
add parser for key import subcommand
|
add parser for key import subcommand
|
||||||
:param root: subparsers for the commands
|
|
||||||
:return: created argument parser
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
"""
|
"""
|
||||||
parser = root.add_parser("key-import", help="import PGP key",
|
parser = root.add_parser("key-import", help="import PGP key",
|
||||||
description="import PGP key from public sources to the repository user",
|
description="import PGP key from public sources to the repository user",
|
||||||
@ -173,8 +197,12 @@ def _set_key_import_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
def _set_package_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
def _set_package_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
"""
|
"""
|
||||||
add parser for package addition subcommand
|
add parser for package addition subcommand
|
||||||
:param root: subparsers for the commands
|
|
||||||
:return: created argument parser
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
"""
|
"""
|
||||||
parser = root.add_parser("package-add", aliases=["add", "package-update"], help="add package",
|
parser = root.add_parser("package-add", aliases=["add", "package-update"], help="add package",
|
||||||
description="add existing or new package to the build queue",
|
description="add existing or new package to the build queue",
|
||||||
@ -202,8 +230,12 @@ def _set_package_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
def _set_package_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
def _set_package_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
"""
|
"""
|
||||||
add parser for package removal subcommand
|
add parser for package removal subcommand
|
||||||
:param root: subparsers for the commands
|
|
||||||
:return: created argument parser
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
"""
|
"""
|
||||||
parser = root.add_parser("package-remove", aliases=["remove"], help="remove package",
|
parser = root.add_parser("package-remove", aliases=["remove"], help="remove package",
|
||||||
description="remove package from the repository", formatter_class=_formatter)
|
description="remove package from the repository", formatter_class=_formatter)
|
||||||
@ -215,8 +247,12 @@ def _set_package_remove_parser(root: SubParserAction) -> argparse.ArgumentParser
|
|||||||
def _set_package_status_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
def _set_package_status_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
"""
|
"""
|
||||||
add parser for package status subcommand
|
add parser for package status subcommand
|
||||||
:param root: subparsers for the commands
|
|
||||||
:return: created argument parser
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
"""
|
"""
|
||||||
parser = root.add_parser("package-status", aliases=["status"], help="get package status",
|
parser = root.add_parser("package-status", aliases=["status"], help="get package status",
|
||||||
description="request status of the package",
|
description="request status of the package",
|
||||||
@ -235,8 +271,12 @@ def _set_package_status_parser(root: SubParserAction) -> argparse.ArgumentParser
|
|||||||
def _set_package_status_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
def _set_package_status_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
"""
|
"""
|
||||||
add parser for package status remove subcommand
|
add parser for package status remove subcommand
|
||||||
:param root: subparsers for the commands
|
|
||||||
:return: created argument parser
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
"""
|
"""
|
||||||
parser = root.add_parser("package-status-remove", help="remove package status",
|
parser = root.add_parser("package-status-remove", help="remove package status",
|
||||||
description="remove the package from the status page",
|
description="remove the package from the status page",
|
||||||
@ -252,8 +292,12 @@ def _set_package_status_remove_parser(root: SubParserAction) -> argparse.Argumen
|
|||||||
def _set_package_status_update_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
def _set_package_status_update_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
"""
|
"""
|
||||||
add parser for package status update subcommand
|
add parser for package status update subcommand
|
||||||
:param root: subparsers for the commands
|
|
||||||
:return: created argument parser
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
"""
|
"""
|
||||||
parser = root.add_parser("package-status-update", aliases=["status-update"], help="update package status",
|
parser = root.add_parser("package-status-update", aliases=["status-update"], help="update package status",
|
||||||
description="update package status on the status page", formatter_class=_formatter)
|
description="update package status on the status page", formatter_class=_formatter)
|
||||||
@ -270,8 +314,12 @@ def _set_package_status_update_parser(root: SubParserAction) -> argparse.Argumen
|
|||||||
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 patch subcommand
|
||||||
:param root: subparsers for the commands
|
|
||||||
:return: created argument parser
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
"""
|
"""
|
||||||
parser = root.add_parser("patch-add", help="add patch set", description="create or update source patches",
|
parser = root.add_parser("patch-add", help="add patch set", description="create or update source patches",
|
||||||
epilog="In order to add a patch set for the package you will need to clone "
|
epilog="In order to add a patch set for the package you will need to clone "
|
||||||
@ -290,8 +338,12 @@ def _set_patch_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
def _set_patch_list_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
def _set_patch_list_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
"""
|
"""
|
||||||
add parser for list patches subcommand
|
add parser for list patches subcommand
|
||||||
:param root: subparsers for the commands
|
|
||||||
:return: created argument parser
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
"""
|
"""
|
||||||
parser = root.add_parser("patch-list", help="list patch sets",
|
parser = root.add_parser("patch-list", help="list patch sets",
|
||||||
description="list available patches for the package", formatter_class=_formatter)
|
description="list available patches for the package", formatter_class=_formatter)
|
||||||
@ -304,8 +356,12 @@ def _set_patch_list_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
def _set_patch_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
def _set_patch_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
"""
|
"""
|
||||||
add parser for remove patches subcommand
|
add parser for remove patches subcommand
|
||||||
:param root: subparsers for the commands
|
|
||||||
:return: created argument parser
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
"""
|
"""
|
||||||
parser = root.add_parser("patch-remove", help="remove patch set", description="remove patches for the package",
|
parser = root.add_parser("patch-remove", help="remove patch set", description="remove patches for the package",
|
||||||
formatter_class=_formatter)
|
formatter_class=_formatter)
|
||||||
@ -314,11 +370,32 @@ def _set_patch_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
def _set_repo_backup_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
|
"""
|
||||||
|
add parser for repository backup subcommand
|
||||||
|
|
||||||
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
|
"""
|
||||||
|
parser = root.add_parser("repo-backup", help="backup repository data",
|
||||||
|
description="backup settings and database", formatter_class=_formatter)
|
||||||
|
parser.add_argument("path", help="path of the output archive", type=Path)
|
||||||
|
parser.set_defaults(handler=handlers.Backup, architecture=[""], lock=None, no_report=True, unsafe=True)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
|
||||||
def _set_repo_check_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
def _set_repo_check_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
"""
|
"""
|
||||||
add parser for repository check subcommand
|
add parser for repository check subcommand
|
||||||
:param root: subparsers for the commands
|
|
||||||
:return: created argument parser
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
"""
|
"""
|
||||||
parser = root.add_parser("repo-check", aliases=["check"], help="check for updates",
|
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 update --dry-run --no-manual",
|
||||||
@ -333,8 +410,12 @@ def _set_repo_check_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
def _set_repo_clean_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
def _set_repo_clean_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
"""
|
"""
|
||||||
add parser for repository clean subcommand
|
add parser for repository clean subcommand
|
||||||
:param root: subparsers for the commands
|
|
||||||
:return: created argument parser
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
"""
|
"""
|
||||||
parser = root.add_parser("repo-clean", aliases=["clean"], help="clean local caches",
|
parser = root.add_parser("repo-clean", aliases=["clean"], help="clean local caches",
|
||||||
description="remove local caches",
|
description="remove local caches",
|
||||||
@ -353,8 +434,12 @@ def _set_repo_clean_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
def _set_repo_config_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
def _set_repo_config_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
"""
|
"""
|
||||||
add parser for config subcommand
|
add parser for config subcommand
|
||||||
:param root: subparsers for the commands
|
|
||||||
:return: created argument parser
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
"""
|
"""
|
||||||
parser = root.add_parser("repo-config", aliases=["config"], help="dump configuration",
|
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",
|
||||||
@ -366,14 +451,24 @@ def _set_repo_config_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
def _set_repo_rebuild_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
def _set_repo_rebuild_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
"""
|
"""
|
||||||
add parser for repository rebuild subcommand
|
add parser for repository rebuild subcommand
|
||||||
:param root: subparsers for the commands
|
|
||||||
:return: created argument parser
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
"""
|
"""
|
||||||
parser = root.add_parser("repo-rebuild", aliases=["rebuild"], help="rebuild repository",
|
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 package", 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",
|
||||||
|
help="read packages from database instead of filesystem. This feature in particular is "
|
||||||
|
"required in case if you would like to restore repository from another repository "
|
||||||
|
"instance. Note however that in order to restore packages you need to have original "
|
||||||
|
"ahriman instance run with web service and have run repo-update at least once.",
|
||||||
|
action="store_true")
|
||||||
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
|
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
|
||||||
parser.set_defaults(handler=handlers.Rebuild)
|
parser.set_defaults(handler=handlers.Rebuild)
|
||||||
return parser
|
return parser
|
||||||
@ -382,8 +477,12 @@ def _set_repo_rebuild_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
def _set_repo_remove_unknown_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
def _set_repo_remove_unknown_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
"""
|
"""
|
||||||
add parser for remove unknown packages subcommand
|
add parser for remove unknown packages subcommand
|
||||||
:param root: subparsers for the commands
|
|
||||||
:return: created argument parser
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
"""
|
"""
|
||||||
parser = root.add_parser("repo-remove-unknown", aliases=["remove-unknown"], help="remove unknown packages",
|
parser = root.add_parser("repo-remove-unknown", aliases=["remove-unknown"], help="remove unknown packages",
|
||||||
description="remove packages which are missing in AUR and do not have local PKGBUILDs",
|
description="remove packages which are missing in AUR and do not have local PKGBUILDs",
|
||||||
@ -397,8 +496,12 @@ def _set_repo_remove_unknown_parser(root: SubParserAction) -> argparse.ArgumentP
|
|||||||
def _set_repo_report_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
def _set_repo_report_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
"""
|
"""
|
||||||
add parser for report subcommand
|
add parser for report subcommand
|
||||||
:param root: subparsers for the commands
|
|
||||||
:return: created argument parser
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
"""
|
"""
|
||||||
parser = root.add_parser("repo-report", aliases=["report"], help="generate report",
|
parser = root.add_parser("repo-report", aliases=["report"], help="generate report",
|
||||||
description="generate repository report according to current settings",
|
description="generate repository report according to current settings",
|
||||||
@ -409,11 +512,33 @@ def _set_repo_report_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
def _set_repo_restore_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
|
"""
|
||||||
|
add parser for repository restore subcommand
|
||||||
|
|
||||||
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
|
"""
|
||||||
|
parser = root.add_parser("repo-restore", help="restore repository data",
|
||||||
|
description="restore settings and database", formatter_class=_formatter)
|
||||||
|
parser.add_argument("path", help="path of the input archive", type=Path)
|
||||||
|
parser.add_argument("-o", "--output", help="root path of the extracted files", type=Path, default=Path("/"))
|
||||||
|
parser.set_defaults(handler=handlers.Restore, architecture=[""], lock=None, no_report=True, unsafe=True)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
|
||||||
def _set_repo_setup_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
def _set_repo_setup_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
"""
|
"""
|
||||||
add parser for setup subcommand
|
add parser for setup subcommand
|
||||||
:param root: subparsers for the commands
|
|
||||||
:return: created argument parser
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
"""
|
"""
|
||||||
parser = root.add_parser("repo-setup", aliases=["init", "repo-init", "setup"], help="initial service configuration",
|
parser = root.add_parser("repo-setup", aliases=["init", "repo-init", "setup"], help="initial service configuration",
|
||||||
description="create initial service configuration, requires root",
|
description="create initial service configuration, requires root",
|
||||||
@ -437,8 +562,12 @@ def _set_repo_setup_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
def _set_repo_sign_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
def _set_repo_sign_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
"""
|
"""
|
||||||
add parser for sign subcommand
|
add parser for sign subcommand
|
||||||
:param root: subparsers for the commands
|
|
||||||
:return: created argument parser
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
"""
|
"""
|
||||||
parser = root.add_parser("repo-sign", aliases=["sign"], help="sign packages",
|
parser = root.add_parser("repo-sign", aliases=["sign"], help="sign packages",
|
||||||
description="(re-)sign packages and repository database according to current settings",
|
description="(re-)sign packages and repository database according to current settings",
|
||||||
@ -452,8 +581,12 @@ def _set_repo_sign_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
def _set_repo_status_update_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
def _set_repo_status_update_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
"""
|
"""
|
||||||
add parser for repository status update subcommand
|
add parser for repository status update subcommand
|
||||||
:param root: subparsers for the commands
|
|
||||||
:return: created argument parser
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
"""
|
"""
|
||||||
parser = root.add_parser("repo-status-update", help="update repository status",
|
parser = root.add_parser("repo-status-update", help="update repository status",
|
||||||
description="update repository status on the status page", formatter_class=_formatter)
|
description="update repository status on the status page", formatter_class=_formatter)
|
||||||
@ -467,8 +600,12 @@ def _set_repo_status_update_parser(root: SubParserAction) -> argparse.ArgumentPa
|
|||||||
def _set_repo_sync_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
def _set_repo_sync_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
"""
|
"""
|
||||||
add parser for repository sync subcommand
|
add parser for repository sync subcommand
|
||||||
:param root: subparsers for the commands
|
|
||||||
:return: created argument parser
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
"""
|
"""
|
||||||
parser = root.add_parser("repo-sync", aliases=["sync"], help="sync repository",
|
parser = root.add_parser("repo-sync", aliases=["sync"], help="sync repository",
|
||||||
description="sync repository files to remote server according to current settings",
|
description="sync repository files to remote server according to current settings",
|
||||||
@ -482,8 +619,12 @@ def _set_repo_sync_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
def _set_repo_update_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
def _set_repo_update_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
"""
|
"""
|
||||||
add parser for repository update subcommand
|
add parser for repository update subcommand
|
||||||
:param root: subparsers for the commands
|
|
||||||
:return: created argument parser
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
"""
|
"""
|
||||||
parser = root.add_parser("repo-update", aliases=["update"], help="update packages",
|
parser = root.add_parser("repo-update", aliases=["update"], help="update packages",
|
||||||
description="check for packages updates and run build process if requested",
|
description="check for packages updates and run build process if requested",
|
||||||
@ -502,8 +643,12 @@ def _set_repo_update_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
def _set_user_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
def _set_user_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
"""
|
"""
|
||||||
add parser for create user subcommand
|
add parser for create user subcommand
|
||||||
:param root: subparsers for the commands
|
|
||||||
:return: created argument parser
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
"""
|
"""
|
||||||
parser = root.add_parser("user-add", help="create or update user",
|
parser = root.add_parser("user-add", help="create or update user",
|
||||||
description="update user for web services with the given password and role. "
|
description="update user for web services with the given password and role. "
|
||||||
@ -516,7 +661,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=UserAccess, default=UserAccess.Read)
|
type=UserAccess, choices=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.User, action=Action.Update, architecture=[""], lock=None, no_report=True,
|
parser.set_defaults(handler=handlers.Users, action=Action.Update, architecture=[""], lock=None, no_report=True,
|
||||||
quiet=True, unsafe=True)
|
quiet=True, unsafe=True)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
@ -524,8 +669,12 @@ def _set_user_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
def _set_user_list_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
def _set_user_list_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
"""
|
"""
|
||||||
add parser for user list subcommand
|
add parser for user list subcommand
|
||||||
:param root: subparsers for the commands
|
|
||||||
:return: created argument parser
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
"""
|
"""
|
||||||
parser = root.add_parser("user-list", help="user known users and their access",
|
parser = root.add_parser("user-list", help="user known users and their access",
|
||||||
description="list users from the user mapping and their roles",
|
description="list users from the user mapping and their roles",
|
||||||
@ -533,7 +682,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=UserAccess)
|
parser.add_argument("-r", "--role", help="filter users by role", type=UserAccess, choices=UserAccess)
|
||||||
parser.set_defaults(handler=handlers.User, action=Action.List, architecture=[""], lock=None, no_report=True, # nosec
|
parser.set_defaults(handler=handlers.Users, action=Action.List, architecture=[""], lock=None, no_report=True, # nosec
|
||||||
password="", quiet=True, unsafe=True)
|
password="", quiet=True, unsafe=True)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
@ -541,15 +690,19 @@ def _set_user_list_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
def _set_user_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
def _set_user_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
"""
|
"""
|
||||||
add parser for user removal subcommand
|
add parser for user removal subcommand
|
||||||
:param root: subparsers for the commands
|
|
||||||
:return: created argument parser
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
"""
|
"""
|
||||||
parser = root.add_parser("user-remove", help="remove user",
|
parser = root.add_parser("user-remove", help="remove user",
|
||||||
description="remove user from the user mapping and update the configuration",
|
description="remove user from the user mapping and update the configuration",
|
||||||
formatter_class=_formatter)
|
formatter_class=_formatter)
|
||||||
parser.add_argument("username", help="username for web service")
|
parser.add_argument("username", help="username for web service")
|
||||||
parser.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.User, action=Action.Remove, architecture=[""], lock=None, no_report=True, # nosec
|
parser.set_defaults(handler=handlers.Users, action=Action.Remove, architecture=[""], lock=None, no_report=True, # nosec
|
||||||
password="", quiet=True, unsafe=True)
|
password="", quiet=True, unsafe=True)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
@ -557,8 +710,12 @@ def _set_user_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
def _set_web_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
def _set_web_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
"""
|
"""
|
||||||
add parser for web subcommand
|
add parser for web subcommand
|
||||||
:param root: subparsers for the commands
|
|
||||||
:return: created argument parser
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
"""
|
"""
|
||||||
parser = root.add_parser("web", help="web server", description="start web server", formatter_class=_formatter)
|
parser = 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, no_report=True, parser=_parser)
|
||||||
|
@ -19,12 +19,12 @@
|
|||||||
#
|
#
|
||||||
from typing import Set
|
from typing import Set
|
||||||
|
|
||||||
from ahriman.application.application.packages import Packages
|
from ahriman.application.application.application_packages import ApplicationPackages
|
||||||
from ahriman.application.application.repository import Repository
|
from ahriman.application.application.application_repository import ApplicationRepository
|
||||||
from ahriman.models.result import Result
|
from ahriman.models.result import Result
|
||||||
|
|
||||||
|
|
||||||
class Application(Packages, Repository):
|
class Application(ApplicationPackages, ApplicationRepository):
|
||||||
"""
|
"""
|
||||||
base application class
|
base application class
|
||||||
"""
|
"""
|
||||||
@ -32,7 +32,9 @@ class Application(Packages, Repository):
|
|||||||
def _finalize(self, result: Result) -> None:
|
def _finalize(self, result: Result) -> None:
|
||||||
"""
|
"""
|
||||||
generate report and sync to remote server
|
generate report and sync to remote server
|
||||||
:param result: build result
|
|
||||||
|
Args:
|
||||||
|
result(Result): build result
|
||||||
"""
|
"""
|
||||||
self.report([], result)
|
self.report([], result)
|
||||||
self.sync([], result.success)
|
self.sync([], result.success)
|
||||||
@ -40,7 +42,9 @@ class Application(Packages, Repository):
|
|||||||
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
|
||||||
:return: list of known packages
|
|
||||||
|
Returns:
|
||||||
|
Set[str]: list of known packages
|
||||||
"""
|
"""
|
||||||
known_packages: Set[str] = set()
|
known_packages: Set[str] = set()
|
||||||
# local set
|
# local set
|
||||||
|
@ -23,7 +23,7 @@ import shutil
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Iterable, Set
|
from typing import Any, Iterable, Set
|
||||||
|
|
||||||
from ahriman.application.application.properties import Properties
|
from ahriman.application.application.application_properties import ApplicationProperties
|
||||||
from ahriman.core.build_tools.sources import Sources
|
from ahriman.core.build_tools.sources import Sources
|
||||||
from ahriman.core.util import package_like, tmpdir
|
from ahriman.core.util import package_like, tmpdir
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
@ -31,7 +31,7 @@ from ahriman.models.package_source import PackageSource
|
|||||||
from ahriman.models.result import Result
|
from ahriman.models.result import Result
|
||||||
|
|
||||||
|
|
||||||
class Packages(Properties):
|
class ApplicationPackages(ApplicationProperties):
|
||||||
"""
|
"""
|
||||||
package control class
|
package control class
|
||||||
"""
|
"""
|
||||||
@ -39,21 +39,33 @@ class Packages(Properties):
|
|||||||
def _finalize(self, result: Result) -> None:
|
def _finalize(self, result: Result) -> None:
|
||||||
"""
|
"""
|
||||||
generate report and sync to remote server
|
generate report and sync to remote server
|
||||||
:param result: build result
|
|
||||||
|
Args:
|
||||||
|
result(Result): build result
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
NotImplementedError: not implemented method
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
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
|
||||||
:return: list of known packages
|
|
||||||
|
Returns:
|
||||||
|
Set[str]: list of known packages
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
NotImplementedError: not implemented method
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
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
|
||||||
:param source: path to package archive
|
|
||||||
|
Args:
|
||||||
|
source(str): path to package archive
|
||||||
"""
|
"""
|
||||||
local_path = Path(source)
|
local_path = Path(source)
|
||||||
dst = self.repository.paths.packages / local_path.name
|
dst = self.repository.paths.packages / local_path.name
|
||||||
@ -62,12 +74,15 @@ class Packages(Properties):
|
|||||||
def _add_aur(self, source: str, known_packages: Set[str], without_dependencies: bool) -> None:
|
def _add_aur(self, source: str, known_packages: Set[str], without_dependencies: bool) -> None:
|
||||||
"""
|
"""
|
||||||
add package from AUR
|
add package from AUR
|
||||||
:param source: package base name
|
|
||||||
:param known_packages: list of packages which are known by the service
|
Args:
|
||||||
:param without_dependencies: if set, dependency check will be disabled
|
source(str): package base name
|
||||||
|
known_packages(Set[str]): list of packages which are known by the service
|
||||||
|
without_dependencies(bool): if set, dependency check will be disabled
|
||||||
"""
|
"""
|
||||||
package = Package.load(source, PackageSource.AUR, self.repository.pacman, self.repository.aur_url)
|
package = Package.load(source, PackageSource.AUR, self.repository.pacman, self.repository.aur_url)
|
||||||
self.repository.database.build_queue_insert(package)
|
|
||||||
|
self.database.build_queue_insert(package)
|
||||||
|
|
||||||
with tmpdir() as local_path:
|
with tmpdir() as local_path:
|
||||||
Sources.load(local_path, package.git_url, self.database.patches_get(package.base))
|
Sources.load(local_path, package.git_url, self.database.patches_get(package.base))
|
||||||
@ -76,7 +91,9 @@ class Packages(Properties):
|
|||||||
def _add_directory(self, source: str, *_: Any) -> None:
|
def _add_directory(self, source: str, *_: Any) -> None:
|
||||||
"""
|
"""
|
||||||
add packages from directory
|
add packages from directory
|
||||||
:param source: path to local directory
|
|
||||||
|
Args:
|
||||||
|
source(str): path to local directory
|
||||||
"""
|
"""
|
||||||
local_path = Path(source)
|
local_path = Path(source)
|
||||||
for full_path in filter(package_like, local_path.iterdir()):
|
for full_path in filter(package_like, local_path.iterdir()):
|
||||||
@ -85,22 +102,27 @@ class Packages(Properties):
|
|||||||
def _add_local(self, source: str, known_packages: Set[str], without_dependencies: bool) -> None:
|
def _add_local(self, source: str, known_packages: Set[str], without_dependencies: bool) -> None:
|
||||||
"""
|
"""
|
||||||
add package from local PKGBUILDs
|
add package from local PKGBUILDs
|
||||||
:param source: path to directory with local source files
|
|
||||||
:param known_packages: list of packages which are known by the service
|
Args:
|
||||||
:param without_dependencies: if set, dependency check will be disabled
|
source(str): path to directory with local source files
|
||||||
|
known_packages(Set[str]): list of packages which are known by the service
|
||||||
|
without_dependencies(bool): if set, dependency check will be disabled
|
||||||
"""
|
"""
|
||||||
package = Package.load(source, PackageSource.Local, self.repository.pacman, self.repository.aur_url)
|
package = Package.load(source, PackageSource.Local, self.repository.pacman, self.repository.aur_url)
|
||||||
cache_dir = self.repository.paths.cache_for(package.base)
|
cache_dir = self.repository.paths.cache_for(package.base)
|
||||||
shutil.copytree(Path(source), cache_dir) # copy package to store in caches
|
shutil.copytree(Path(source), cache_dir) # copy package to store in caches
|
||||||
Sources.init(cache_dir) # we need to run init command in directory where we do have permissions
|
Sources.init(cache_dir) # we need to run init command in directory where we do have permissions
|
||||||
self.repository.database.build_queue_insert(package)
|
|
||||||
|
self.database.build_queue_insert(package)
|
||||||
|
|
||||||
self._process_dependencies(cache_dir, known_packages, without_dependencies)
|
self._process_dependencies(cache_dir, known_packages, without_dependencies)
|
||||||
|
|
||||||
def _add_remote(self, source: str, *_: Any) -> None:
|
def _add_remote(self, source: str, *_: Any) -> None:
|
||||||
"""
|
"""
|
||||||
add package from remote sources (e.g. HTTP)
|
add package from remote sources (e.g. HTTP)
|
||||||
:param remote_url: remote URL to the package archive
|
|
||||||
|
Args:
|
||||||
|
source(str): remote URL of the package archive
|
||||||
"""
|
"""
|
||||||
dst = self.repository.paths.packages / Path(source).name # URL is path, is not it?
|
dst = self.repository.paths.packages / Path(source).name # URL is path, is not it?
|
||||||
response = requests.get(source, stream=True)
|
response = requests.get(source, stream=True)
|
||||||
@ -113,9 +135,11 @@ class Packages(Properties):
|
|||||||
def _process_dependencies(self, local_path: Path, known_packages: Set[str], without_dependencies: bool) -> None:
|
def _process_dependencies(self, local_path: Path, known_packages: Set[str], without_dependencies: bool) -> None:
|
||||||
"""
|
"""
|
||||||
process package dependencies
|
process package dependencies
|
||||||
:param local_path: path to local package sources (i.e. cloned AUR repository)
|
|
||||||
:param known_packages: list of packages which are known by the service
|
Args:
|
||||||
:param without_dependencies: if set, dependency check will be disabled
|
local_path(Path): path to local package sources (i.e. cloned AUR repository)
|
||||||
|
known_packages(Set[str]): list of packages which are known by the service
|
||||||
|
without_dependencies(bool): if set, dependency check will be disabled
|
||||||
"""
|
"""
|
||||||
if without_dependencies:
|
if without_dependencies:
|
||||||
return
|
return
|
||||||
@ -126,9 +150,11 @@ class Packages(Properties):
|
|||||||
def add(self, names: Iterable[str], source: PackageSource, without_dependencies: bool) -> None:
|
def add(self, names: Iterable[str], source: PackageSource, without_dependencies: bool) -> None:
|
||||||
"""
|
"""
|
||||||
add packages for the next build
|
add packages for the next build
|
||||||
:param names: list of package bases to add
|
|
||||||
:param source: package source to add
|
Args:
|
||||||
:param without_dependencies: if set, dependency check will be disabled
|
names(Iterable[str]): list of package bases to add
|
||||||
|
source(PackageSource): package source to add
|
||||||
|
without_dependencies(bool): if set, dependency check will be disabled
|
||||||
"""
|
"""
|
||||||
known_packages = self._known_packages() # speedup dependencies processing
|
known_packages = self._known_packages() # speedup dependencies processing
|
||||||
|
|
||||||
@ -140,7 +166,9 @@ class Packages(Properties):
|
|||||||
def remove(self, names: Iterable[str]) -> None:
|
def remove(self, names: Iterable[str]) -> None:
|
||||||
"""
|
"""
|
||||||
remove packages from repository
|
remove packages from repository
|
||||||
:param names: list of packages (either base or name) to remove
|
|
||||||
|
Args:
|
||||||
|
names(Iterable[str]): list of packages (either base or name) to remove
|
||||||
"""
|
"""
|
||||||
self.repository.process_remove(names)
|
self.repository.process_remove(names)
|
||||||
self._finalize(Result())
|
self._finalize(Result())
|
@ -24,23 +24,27 @@ from ahriman.core.database.sqlite import SQLite
|
|||||||
from ahriman.core.repository import Repository
|
from ahriman.core.repository import Repository
|
||||||
|
|
||||||
|
|
||||||
class Properties:
|
class ApplicationProperties:
|
||||||
"""
|
"""
|
||||||
application base properties class
|
application base properties class
|
||||||
:ivar architecture: repository architecture
|
|
||||||
:ivar configuration: configuration instance
|
Attributes:
|
||||||
:ivar database: database instance
|
architecture(str): repository architecture
|
||||||
:ivar logger: application logger
|
configuration(Configuration): configuration instance
|
||||||
:ivar repository: repository instance
|
database(SQLite): database instance
|
||||||
|
logger(logging.Logger): application logger
|
||||||
|
repository(Repository): repository instance
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, architecture: str, configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
def __init__(self, architecture: str, configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
default constructor
|
||||||
:param architecture: repository architecture
|
|
||||||
:param configuration: configuration instance
|
Args:
|
||||||
:param no_report: force disable reporting
|
architecture(str): repository architecture
|
||||||
:param unsafe: if set no user check will be performed before path creation
|
configuration(Configuration): configuration instance
|
||||||
|
no_report(bool): force disable reporting
|
||||||
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
self.logger = logging.getLogger("root")
|
self.logger = logging.getLogger("root")
|
||||||
self.configuration = configuration
|
self.configuration = configuration
|
@ -22,7 +22,7 @@ import shutil
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Callable, Iterable, List
|
from typing import Callable, Iterable, List
|
||||||
|
|
||||||
from ahriman.application.application.properties import Properties
|
from ahriman.application.application.application_properties import ApplicationProperties
|
||||||
from ahriman.core.build_tools.sources import Sources
|
from ahriman.core.build_tools.sources import Sources
|
||||||
from ahriman.core.formatters.update_printer import UpdatePrinter
|
from ahriman.core.formatters.update_printer import UpdatePrinter
|
||||||
from ahriman.core.tree import Tree
|
from ahriman.core.tree import Tree
|
||||||
@ -30,7 +30,7 @@ from ahriman.models.package import Package
|
|||||||
from ahriman.models.result import Result
|
from ahriman.models.result import Result
|
||||||
|
|
||||||
|
|
||||||
class Repository(Properties):
|
class ApplicationRepository(ApplicationProperties):
|
||||||
"""
|
"""
|
||||||
repository control class
|
repository control class
|
||||||
"""
|
"""
|
||||||
@ -38,17 +38,24 @@ class Repository(Properties):
|
|||||||
def _finalize(self, result: Result) -> None:
|
def _finalize(self, result: Result) -> None:
|
||||||
"""
|
"""
|
||||||
generate report and sync to remote server
|
generate report and sync to remote server
|
||||||
:param result: build result
|
|
||||||
|
Args:
|
||||||
|
result(Result): build result
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
NotImplementedError: not implemented method
|
||||||
"""
|
"""
|
||||||
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) -> 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
|
||||||
:param cache: clear directory with package caches
|
|
||||||
:param chroot: clear build chroot
|
Args:
|
||||||
:param manual: clear directory with manually added packages
|
cache(bool): clear directory with package caches
|
||||||
:param packages: clear directory with built packages
|
chroot(bool): clear build chroot
|
||||||
|
manual(bool): clear directory with manually added packages
|
||||||
|
packages(bool): clear directory with built packages
|
||||||
"""
|
"""
|
||||||
if cache:
|
if cache:
|
||||||
self.repository.clear_cache()
|
self.repository.clear_cache()
|
||||||
@ -62,8 +69,10 @@ class Repository(Properties):
|
|||||||
def report(self, target: Iterable[str], result: Result) -> None:
|
def report(self, target: Iterable[str], result: Result) -> None:
|
||||||
"""
|
"""
|
||||||
generate report
|
generate report
|
||||||
:param target: list of targets to run (e.g. html)
|
|
||||||
:param result: build result
|
Args:
|
||||||
|
target(Iterable[str]): list of targets to run (e.g. html)
|
||||||
|
result(Result): build result
|
||||||
"""
|
"""
|
||||||
targets = target or None
|
targets = target or None
|
||||||
self.repository.process_report(targets, result)
|
self.repository.process_report(targets, result)
|
||||||
@ -71,7 +80,9 @@ class Repository(Properties):
|
|||||||
def sign(self, packages: Iterable[str]) -> None:
|
def sign(self, packages: Iterable[str]) -> None:
|
||||||
"""
|
"""
|
||||||
sign packages and repository
|
sign packages and repository
|
||||||
:param packages: only sign specified packages
|
|
||||||
|
Args:
|
||||||
|
packages(Iterable[str]): only sign specified packages
|
||||||
"""
|
"""
|
||||||
# copy to prebuilt directory
|
# copy to prebuilt directory
|
||||||
for package in self.repository.packages():
|
for package in self.repository.packages():
|
||||||
@ -94,8 +105,10 @@ class Repository(Properties):
|
|||||||
def sync(self, target: Iterable[str], built_packages: Iterable[Package]) -> None:
|
def sync(self, target: Iterable[str], built_packages: Iterable[Package]) -> None:
|
||||||
"""
|
"""
|
||||||
sync to remote server
|
sync to remote server
|
||||||
:param target: list of targets to run (e.g. s3)
|
|
||||||
:param built_packages: list of packages which has just been built
|
Args:
|
||||||
|
target(Iterable[str]): list of targets to run (e.g. s3)
|
||||||
|
built_packages(Iterable[Package]): list of packages which has just been built
|
||||||
"""
|
"""
|
||||||
targets = target or None
|
targets = target or None
|
||||||
self.repository.process_sync(targets, built_packages)
|
self.repository.process_sync(targets, built_packages)
|
||||||
@ -103,7 +116,9 @@ class Repository(Properties):
|
|||||||
def unknown(self) -> List[str]:
|
def unknown(self) -> List[str]:
|
||||||
"""
|
"""
|
||||||
get packages which were not found in AUR
|
get packages which were not found in AUR
|
||||||
:return: unknown package archive list
|
|
||||||
|
Returns:
|
||||||
|
List[str]: unknown package archive list
|
||||||
"""
|
"""
|
||||||
def has_local(probe: Package) -> bool:
|
def has_local(probe: Package) -> bool:
|
||||||
cache_dir = self.repository.paths.cache_for(probe.base)
|
cache_dir = self.repository.paths.cache_for(probe.base)
|
||||||
@ -135,7 +150,12 @@ class Repository(Properties):
|
|||||||
def update(self, updates: Iterable[Package]) -> Result:
|
def update(self, updates: Iterable[Package]) -> Result:
|
||||||
"""
|
"""
|
||||||
run package updates
|
run package updates
|
||||||
:param updates: list of packages to update
|
|
||||||
|
Args:
|
||||||
|
updates(Iterable[Package]): list of packages to update
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Result: update result
|
||||||
"""
|
"""
|
||||||
def process_update(paths: Iterable[Path], result: Result) -> None:
|
def process_update(paths: Iterable[Path], result: Result) -> None:
|
||||||
if not paths:
|
if not paths:
|
||||||
@ -162,13 +182,17 @@ class Repository(Properties):
|
|||||||
log_fn: Callable[[str], None]) -> List[Package]:
|
log_fn: Callable[[str], None]) -> List[Package]:
|
||||||
"""
|
"""
|
||||||
get list of packages to run update process
|
get list of packages to run update process
|
||||||
:param filter_packages: do not check every package just specified in the list
|
|
||||||
:param no_aur: do not check for aur updates
|
Args:
|
||||||
:param no_local: do not check local packages for updates
|
filter_packages(Iterable[str]): do not check every package just specified in the list
|
||||||
:param no_manual: do not check for manual updates
|
no_aur(bool): do not check for aur updates
|
||||||
:param no_vcs: do not check VCS packages
|
no_local(bool): do not check local packages for updates
|
||||||
:param log_fn: logger function to log updates
|
no_manual(bool): do not check for manual updates
|
||||||
:return: list of out-of-dated packages
|
no_vcs(bool): do not check VCS packages
|
||||||
|
log_fn(Callable[[str], None]): logger function to log updates
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[Package]: list of out-of-dated packages
|
||||||
"""
|
"""
|
||||||
updates = {}
|
updates = {}
|
||||||
|
|
@ -20,6 +20,7 @@
|
|||||||
from ahriman.application.handlers.handler import Handler
|
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.clean import Clean
|
from ahriman.application.handlers.clean import Clean
|
||||||
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
|
||||||
@ -29,6 +30,7 @@ from ahriman.application.handlers.rebuild import Rebuild
|
|||||||
from ahriman.application.handlers.remove import Remove
|
from ahriman.application.handlers.remove import Remove
|
||||||
from ahriman.application.handlers.remove_unknown import RemoveUnknown
|
from ahriman.application.handlers.remove_unknown import RemoveUnknown
|
||||||
from ahriman.application.handlers.report import Report
|
from ahriman.application.handlers.report import Report
|
||||||
|
from ahriman.application.handlers.restore import Restore
|
||||||
from ahriman.application.handlers.search import Search
|
from ahriman.application.handlers.search import Search
|
||||||
from ahriman.application.handlers.setup import Setup
|
from ahriman.application.handlers.setup import Setup
|
||||||
from ahriman.application.handlers.sign import Sign
|
from ahriman.application.handlers.sign import Sign
|
||||||
@ -37,5 +39,5 @@ from ahriman.application.handlers.status_update import StatusUpdate
|
|||||||
from ahriman.application.handlers.sync import Sync
|
from ahriman.application.handlers.sync import Sync
|
||||||
from ahriman.application.handlers.unsafe_commands import UnsafeCommands
|
from ahriman.application.handlers.unsafe_commands import UnsafeCommands
|
||||||
from ahriman.application.handlers.update import Update
|
from ahriman.application.handlers.update import Update
|
||||||
from ahriman.application.handlers.user import User
|
from ahriman.application.handlers.users import Users
|
||||||
from ahriman.application.handlers.web import Web
|
from ahriman.application.handlers.web import Web
|
||||||
|
@ -36,11 +36,13 @@ class Add(Handler):
|
|||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
:param args: command line args
|
|
||||||
:param architecture: repository architecture
|
Args:
|
||||||
:param configuration: configuration instance
|
args(argparse.Namespace): command line args
|
||||||
:param no_report: force disable reporting
|
architecture(str): repository architecture
|
||||||
:param unsafe: if set no user check will be performed before path creation
|
configuration(Configuration): configuration instance
|
||||||
|
no_report(bool): force disable reporting
|
||||||
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
application = Application(architecture, configuration, no_report, unsafe)
|
application = Application(architecture, configuration, no_report, unsafe)
|
||||||
application.add(args.package, args.source, args.without_dependencies)
|
application.add(args.package, args.source, args.without_dependencies)
|
||||||
|
86
src/ahriman/application/handlers/backup.py
Normal file
86
src/ahriman/application/handlers/backup.py
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2022 ahriman team.
|
||||||
|
#
|
||||||
|
# This file is part of ahriman
|
||||||
|
# (see https://github.com/arcan1s/ahriman).
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
import argparse
|
||||||
|
import pwd
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
from tarfile import TarFile
|
||||||
|
from typing import Set, Type
|
||||||
|
|
||||||
|
from ahriman.application.handlers.handler import Handler
|
||||||
|
from ahriman.core.configuration import Configuration
|
||||||
|
from ahriman.core.database.sqlite import SQLite
|
||||||
|
|
||||||
|
|
||||||
|
class Backup(Handler):
|
||||||
|
"""
|
||||||
|
backup packages handler
|
||||||
|
"""
|
||||||
|
|
||||||
|
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
||||||
|
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||||
|
"""
|
||||||
|
callback for command line
|
||||||
|
|
||||||
|
Args:
|
||||||
|
args(argparse.Namespace): command line args
|
||||||
|
architecture(str): repository architecture
|
||||||
|
configuration(Configuration): configuration instance
|
||||||
|
no_report(bool): force disable reporting
|
||||||
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
|
"""
|
||||||
|
backup_paths = Backup.get_paths(configuration)
|
||||||
|
with TarFile(args.path, mode="w") as archive: # well we don't actually use compression
|
||||||
|
for backup_path in backup_paths:
|
||||||
|
archive.add(backup_path)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_paths(configuration: Configuration) -> Set[Path]:
|
||||||
|
"""
|
||||||
|
extract paths to backup
|
||||||
|
|
||||||
|
Args:
|
||||||
|
configuration(Configuration): configuration instance
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Set[Path]: map of the filesystem paths
|
||||||
|
"""
|
||||||
|
paths = set(configuration.include.glob("*.ini"))
|
||||||
|
|
||||||
|
root, _ = configuration.check_loaded()
|
||||||
|
paths.add(root) # the configuration itself
|
||||||
|
paths.add(SQLite.database_path(configuration)) # database
|
||||||
|
|
||||||
|
# local caches
|
||||||
|
repository_paths = configuration.repository_paths
|
||||||
|
if repository_paths.cache.is_dir():
|
||||||
|
paths.add(repository_paths.cache)
|
||||||
|
|
||||||
|
# gnupg home with imported keys
|
||||||
|
uid, _ = repository_paths.root_owner
|
||||||
|
system_user = pwd.getpwuid(uid)
|
||||||
|
gnupg_home = Path(system_user.pw_dir) / ".gnupg"
|
||||||
|
if gnupg_home.is_dir():
|
||||||
|
paths.add(gnupg_home)
|
||||||
|
|
||||||
|
return paths
|
@ -36,11 +36,13 @@ class Clean(Handler):
|
|||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
:param args: command line args
|
|
||||||
:param architecture: repository architecture
|
Args:
|
||||||
:param configuration: configuration instance
|
args(argparse.Namespace): command line args
|
||||||
:param no_report: force disable reporting
|
architecture(str): repository architecture
|
||||||
:param unsafe: if set no user check will be performed before path creation
|
configuration(Configuration): configuration instance
|
||||||
|
no_report(bool): force disable reporting
|
||||||
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
Application(architecture, configuration, no_report, unsafe).clean(
|
Application(architecture, configuration, no_report, unsafe).clean(
|
||||||
args.cache, args.chroot, args.manual, args.packages)
|
args.cache, args.chroot, args.manual, args.packages)
|
||||||
|
@ -38,11 +38,13 @@ class Dump(Handler):
|
|||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
:param args: command line args
|
|
||||||
:param architecture: repository architecture
|
Args:
|
||||||
:param configuration: configuration instance
|
args(argparse.Namespace): command line args
|
||||||
:param no_report: force disable reporting
|
architecture(str): repository architecture
|
||||||
:param unsafe: if set no user check will be performed before path creation
|
configuration(Configuration): configuration instance
|
||||||
|
no_report(bool): force disable reporting
|
||||||
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
dump = configuration.dump()
|
dump = configuration.dump()
|
||||||
for section, values in sorted(dump.items()):
|
for section, values in sorted(dump.items()):
|
||||||
|
@ -34,8 +34,10 @@ from ahriman.models.repository_paths import RepositoryPaths
|
|||||||
class Handler:
|
class Handler:
|
||||||
"""
|
"""
|
||||||
base handler class for command callbacks
|
base handler class for command callbacks
|
||||||
:cvar ALLOW_AUTO_ARCHITECTURE_RUN: allow to define architecture from existing repositories
|
|
||||||
:cvar ALLOW_MULTI_ARCHITECTURE_RUN: allow to run with multiple architectures
|
Attributes:
|
||||||
|
ALLOW_AUTO_ARCHITECTURE_RUN(bool): (class attribute) allow defining architecture from existing repositories
|
||||||
|
ALLOW_MULTI_ARCHITECTURE_RUN(bool): (class attribute) allow running with multiple architectures
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ALLOW_AUTO_ARCHITECTURE_RUN = True
|
ALLOW_AUTO_ARCHITECTURE_RUN = True
|
||||||
@ -45,8 +47,15 @@ class Handler:
|
|||||||
def architectures_extract(cls: Type[Handler], args: argparse.Namespace) -> List[str]:
|
def architectures_extract(cls: Type[Handler], args: argparse.Namespace) -> List[str]:
|
||||||
"""
|
"""
|
||||||
get known architectures
|
get known architectures
|
||||||
:param args: command line args
|
|
||||||
:return: list of architectures for which tree is created
|
Args:
|
||||||
|
args(argparse.Namespace): command line args
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[str]: list of architectures for which tree is created
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
MissingArchitecture: if no architecture set and automatic detection is not allowed or failed
|
||||||
"""
|
"""
|
||||||
if not cls.ALLOW_AUTO_ARCHITECTURE_RUN and args.architecture is None:
|
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
|
||||||
@ -69,9 +78,13 @@ class Handler:
|
|||||||
def call(cls: Type[Handler], args: argparse.Namespace, architecture: str) -> bool:
|
def call(cls: Type[Handler], args: argparse.Namespace, architecture: str) -> bool:
|
||||||
"""
|
"""
|
||||||
additional function to wrap all calls for multiprocessing library
|
additional function to wrap all calls for multiprocessing library
|
||||||
:param args: command line args
|
|
||||||
:param architecture: repository architecture
|
Args:
|
||||||
:return: True on success, False otherwise
|
args(argparse.Namespace): command line args
|
||||||
|
architecture(str): repository architecture
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True on success, False otherwise
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
configuration = Configuration.from_path(args.configuration, architecture, args.quiet)
|
configuration = Configuration.from_path(args.configuration, architecture, args.quiet)
|
||||||
@ -89,8 +102,15 @@ class Handler:
|
|||||||
def execute(cls: Type[Handler], args: argparse.Namespace) -> int:
|
def execute(cls: Type[Handler], args: argparse.Namespace) -> int:
|
||||||
"""
|
"""
|
||||||
execute function for all aru
|
execute function for all aru
|
||||||
:param args: command line args
|
|
||||||
:return: 0 on success, 1 otherwise
|
Args:
|
||||||
|
args(argparse.Namespace): command line args
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: 0 on success, 1 otherwise
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
MultipleArchitectures: if more than one architecture supplied and no multi architecture supported
|
||||||
"""
|
"""
|
||||||
architectures = cls.architectures_extract(args)
|
architectures = cls.architectures_extract(args)
|
||||||
|
|
||||||
@ -112,11 +132,16 @@ class Handler:
|
|||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
:param args: command line args
|
|
||||||
:param architecture: repository architecture
|
Args:
|
||||||
:param configuration: configuration instance
|
args(argparse.Namespace): command line args
|
||||||
:param no_report: force disable reporting
|
architecture(str): repository architecture
|
||||||
:param unsafe: if set no user check will be performed before path creation
|
configuration(Configuration): configuration instance
|
||||||
|
no_report(bool): force disable reporting
|
||||||
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
NotImplementedError: not implemented method
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@ -124,8 +149,13 @@ class Handler:
|
|||||||
def check_if_empty(enabled: bool, predicate: bool) -> None:
|
def check_if_empty(enabled: bool, predicate: bool) -> None:
|
||||||
"""
|
"""
|
||||||
check condition and flag and raise ExitCode exception in case if it is enabled and condition match
|
check condition and flag and raise ExitCode exception in case if it is enabled and condition match
|
||||||
:param enabled: if False no check will be performed
|
|
||||||
:param predicate: indicates condition on which exception should be thrown
|
Args:
|
||||||
|
enabled(bool): if False no check will be performed
|
||||||
|
predicate(bool): indicates condition on which exception should be thrown
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ExitCode: if result is empty and check is enabled
|
||||||
"""
|
"""
|
||||||
if enabled and predicate:
|
if enabled and predicate:
|
||||||
raise ExitCode()
|
raise ExitCode()
|
||||||
|
@ -37,11 +37,13 @@ class Help(Handler):
|
|||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
:param args: command line args
|
|
||||||
:param architecture: repository architecture
|
Args:
|
||||||
:param configuration: configuration instance
|
args(argparse.Namespace): command line args
|
||||||
:param no_report: force disable reporting
|
architecture(str): repository architecture
|
||||||
:param unsafe: if set no user check will be performed before path creation
|
configuration(Configuration): configuration instance
|
||||||
|
no_report(bool): force disable reporting
|
||||||
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
parser: argparse.ArgumentParser = args.parser()
|
parser: argparse.ArgumentParser = args.parser()
|
||||||
if args.command is None:
|
if args.command is None:
|
||||||
|
@ -38,11 +38,13 @@ class KeyImport(Handler):
|
|||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
:param args: command line args
|
|
||||||
:param architecture: repository architecture
|
Args:
|
||||||
:param configuration: configuration instance
|
args(argparse.Namespace): command line args
|
||||||
:param no_report: force disable reporting
|
architecture(str): repository architecture
|
||||||
:param unsafe: if set no user check will be performed before path creation
|
configuration(Configuration): configuration instance
|
||||||
|
no_report(bool): force disable reporting
|
||||||
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
Application(architecture, configuration, no_report, unsafe).repository.sign.key_import(
|
Application(architecture, configuration, no_report, unsafe).repository.sign.key_import(
|
||||||
args.key_server, args.key)
|
args.key_server, args.key)
|
||||||
|
@ -42,11 +42,13 @@ class Patch(Handler):
|
|||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
:param args: command line args
|
|
||||||
:param architecture: repository architecture
|
Args:
|
||||||
:param configuration: configuration instance
|
args(argparse.Namespace): command line args
|
||||||
:param no_report: force disable reporting
|
architecture(str): repository architecture
|
||||||
:param unsafe: if set no user check will be performed before path creation
|
configuration(Configuration): configuration instance
|
||||||
|
no_report(bool): force disable reporting
|
||||||
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
application = Application(architecture, configuration, no_report, unsafe)
|
application = Application(architecture, configuration, no_report, unsafe)
|
||||||
|
|
||||||
@ -61,9 +63,11 @@ class Patch(Handler):
|
|||||||
def patch_set_create(application: Application, sources_dir: str, track: List[str]) -> None:
|
def patch_set_create(application: Application, sources_dir: str, track: List[str]) -> None:
|
||||||
"""
|
"""
|
||||||
create patch set for the package base
|
create patch set for the package base
|
||||||
:param application: application instance
|
|
||||||
:param sources_dir: path to directory with the package sources
|
Args:
|
||||||
:param track: track files which match the glob before creating the patch
|
application(Application): application instance
|
||||||
|
sources_dir(str): path to directory with the package sources
|
||||||
|
track(List[str]): track files which match the glob before creating the patch
|
||||||
"""
|
"""
|
||||||
package = Package.load(sources_dir, PackageSource.Local, application.repository.pacman,
|
package = Package.load(sources_dir, PackageSource.Local, application.repository.pacman,
|
||||||
application.repository.aur_url)
|
application.repository.aur_url)
|
||||||
@ -74,9 +78,11 @@ class Patch(Handler):
|
|||||||
def patch_set_list(application: Application, package_base: Optional[str], exit_code: bool) -> None:
|
def patch_set_list(application: Application, package_base: Optional[str], exit_code: bool) -> None:
|
||||||
"""
|
"""
|
||||||
list patches available for the package base
|
list patches available for the package base
|
||||||
:param application: application instance
|
|
||||||
:param package_base: package base
|
Args:
|
||||||
:param exit_code: raise ExitCode on empty search result
|
application(Application): application instance
|
||||||
|
package_base(Optional[str]): package base
|
||||||
|
exit_code(bool): exit with error on empty search result
|
||||||
"""
|
"""
|
||||||
patches = application.database.patches_list(package_base)
|
patches = application.database.patches_list(package_base)
|
||||||
Patch.check_if_empty(exit_code, not patches)
|
Patch.check_if_empty(exit_code, not patches)
|
||||||
@ -89,7 +95,9 @@ class Patch(Handler):
|
|||||||
def patch_set_remove(application: Application, package_base: str) -> None:
|
def patch_set_remove(application: Application, package_base: str) -> None:
|
||||||
"""
|
"""
|
||||||
remove patch set for the package base
|
remove patch set for the package base
|
||||||
:param application: application instance
|
|
||||||
:param package_base: package base
|
Args:
|
||||||
|
application(Application): application instance
|
||||||
|
package_base(str): package base
|
||||||
"""
|
"""
|
||||||
application.database.patches_remove(package_base)
|
application.database.patches_remove(package_base)
|
||||||
|
@ -19,12 +19,13 @@
|
|||||||
#
|
#
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
from typing import Type
|
from typing import List, Type
|
||||||
|
|
||||||
from ahriman.application.application import Application
|
from ahriman.application.application import Application
|
||||||
from ahriman.application.handlers.handler import Handler
|
from ahriman.application.handlers.handler import Handler
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
from ahriman.core.formatters.update_printer import UpdatePrinter
|
from ahriman.core.formatters.update_printer import UpdatePrinter
|
||||||
|
from ahriman.models.package import Package
|
||||||
|
|
||||||
|
|
||||||
class Rebuild(Handler):
|
class Rebuild(Handler):
|
||||||
@ -37,16 +38,21 @@ class Rebuild(Handler):
|
|||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
:param args: command line args
|
|
||||||
:param architecture: repository architecture
|
Args:
|
||||||
:param configuration: configuration instance
|
args(argparse.Namespace): command line args
|
||||||
:param no_report: force disable reporting
|
architecture(str): repository architecture
|
||||||
:param unsafe: if set no user check will be performed before path creation
|
configuration(Configuration): configuration instance
|
||||||
|
no_report(bool): force disable reporting
|
||||||
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
depends_on = set(args.depends_on) if args.depends_on else None
|
depends_on = set(args.depends_on) if args.depends_on else None
|
||||||
|
|
||||||
application = Application(architecture, configuration, no_report, unsafe)
|
application = Application(architecture, configuration, no_report, unsafe)
|
||||||
updates = application.repository.packages_depends_on(depends_on)
|
if args.from_database:
|
||||||
|
updates = Rebuild.extract_packages(application)
|
||||||
|
else:
|
||||||
|
updates = application.repository.packages_depends_on(depends_on)
|
||||||
|
|
||||||
Rebuild.check_if_empty(args.exit_code, not updates)
|
Rebuild.check_if_empty(args.exit_code, not updates)
|
||||||
if args.dry_run:
|
if args.dry_run:
|
||||||
@ -56,3 +62,16 @@ class Rebuild(Handler):
|
|||||||
|
|
||||||
result = application.update(updates)
|
result = application.update(updates)
|
||||||
Rebuild.check_if_empty(args.exit_code, result.is_empty)
|
Rebuild.check_if_empty(args.exit_code, result.is_empty)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def extract_packages(application: Application) -> List[Package]:
|
||||||
|
"""
|
||||||
|
extract packages from database file
|
||||||
|
|
||||||
|
Args:
|
||||||
|
application(Application): application instance
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[Package]: list of packages which were stored in database
|
||||||
|
"""
|
||||||
|
return [package for (package, _) in application.database.packages_get()]
|
||||||
|
@ -36,10 +36,12 @@ class Remove(Handler):
|
|||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
:param args: command line args
|
|
||||||
:param architecture: repository architecture
|
Args:
|
||||||
:param configuration: configuration instance
|
args(argparse.Namespace): command line args
|
||||||
:param no_report: force disable reporting
|
architecture(str): repository architecture
|
||||||
:param unsafe: if set no user check will be performed before path creation
|
configuration(Configuration): configuration instance
|
||||||
|
no_report(bool): force disable reporting
|
||||||
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
Application(architecture, configuration, no_report, unsafe).remove(args.package)
|
Application(architecture, configuration, no_report, unsafe).remove(args.package)
|
||||||
|
@ -37,11 +37,13 @@ class RemoveUnknown(Handler):
|
|||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
:param args: command line args
|
|
||||||
:param architecture: repository architecture
|
Args:
|
||||||
:param configuration: configuration instance
|
args(argparse.Namespace): command line args
|
||||||
:param no_report: force disable reporting
|
architecture(str): repository architecture
|
||||||
:param unsafe: if set no user check will be performed before path creation
|
configuration(Configuration): configuration instance
|
||||||
|
no_report(bool): force disable reporting
|
||||||
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
application = Application(architecture, configuration, no_report, unsafe)
|
application = Application(architecture, configuration, no_report, unsafe)
|
||||||
unknown_packages = application.unknown()
|
unknown_packages = application.unknown()
|
||||||
|
@ -37,10 +37,12 @@ class Report(Handler):
|
|||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
:param args: command line args
|
|
||||||
:param architecture: repository architecture
|
Args:
|
||||||
:param configuration: configuration instance
|
args(argparse.Namespace): command line args
|
||||||
:param no_report: force disable reporting
|
architecture(str): repository architecture
|
||||||
:param unsafe: if set no user check will be performed before path creation
|
configuration(Configuration): configuration instance
|
||||||
|
no_report(bool): force disable reporting
|
||||||
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
Application(architecture, configuration, no_report, unsafe).report(args.target, Result())
|
Application(architecture, configuration, no_report, unsafe).report(args.target, Result())
|
||||||
|
50
src/ahriman/application/handlers/restore.py
Normal file
50
src/ahriman/application/handlers/restore.py
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2022 ahriman team.
|
||||||
|
#
|
||||||
|
# This file is part of ahriman
|
||||||
|
# (see https://github.com/arcan1s/ahriman).
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
from typing import Type
|
||||||
|
from tarfile import TarFile
|
||||||
|
|
||||||
|
from ahriman.application.handlers.handler import Handler
|
||||||
|
from ahriman.core.configuration import Configuration
|
||||||
|
|
||||||
|
|
||||||
|
class Restore(Handler):
|
||||||
|
"""
|
||||||
|
restore packages handler
|
||||||
|
"""
|
||||||
|
|
||||||
|
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str,
|
||||||
|
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||||
|
"""
|
||||||
|
callback for command line
|
||||||
|
|
||||||
|
Args:
|
||||||
|
args(argparse.Namespace): command line args
|
||||||
|
architecture(str): repository architecture
|
||||||
|
configuration(Configuration): configuration instance
|
||||||
|
no_report(bool): force disable reporting
|
||||||
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
|
"""
|
||||||
|
with TarFile(args.path) as archive:
|
||||||
|
archive.extractall(path=args.output)
|
@ -23,7 +23,8 @@ from dataclasses import fields
|
|||||||
from typing import Callable, Iterable, List, Tuple, Type
|
from typing import Callable, Iterable, List, Tuple, Type
|
||||||
|
|
||||||
from ahriman.application.handlers.handler import Handler
|
from ahriman.application.handlers.handler import Handler
|
||||||
from ahriman.core.alpm.aur import AUR
|
from ahriman.core.alpm.remote.aur import AUR
|
||||||
|
from ahriman.core.alpm.remote.official import Official
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
from ahriman.core.exceptions import InvalidOption
|
from ahriman.core.exceptions import InvalidOption
|
||||||
from ahriman.core.formatters.aur_printer import AurPrinter
|
from ahriman.core.formatters.aur_printer import AurPrinter
|
||||||
@ -33,7 +34,9 @@ from ahriman.models.aur_package import AURPackage
|
|||||||
class Search(Handler):
|
class Search(Handler):
|
||||||
"""
|
"""
|
||||||
packages search handler
|
packages search handler
|
||||||
:cvar SORT_FIELDS: allowed fields to sort the package list
|
|
||||||
|
Attributes:
|
||||||
|
SORT_FIELDS(Set[str]): (class attribute) allowed fields to sort the package list
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||||
@ -44,24 +47,37 @@ class Search(Handler):
|
|||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
:param args: command line args
|
|
||||||
:param architecture: repository architecture
|
Args:
|
||||||
:param configuration: configuration instance
|
args(argparse.Namespace): command line args
|
||||||
:param no_report: force disable reporting
|
architecture(str): repository architecture
|
||||||
:param unsafe: if set no user check will be performed before path creation
|
configuration(Configuration): configuration instance
|
||||||
|
no_report(bool): force disable reporting
|
||||||
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
packages_list = AUR.multisearch(*args.search)
|
official_packages_list = Official.multisearch(*args.search)
|
||||||
Search.check_if_empty(args.exit_code, not packages_list)
|
aur_packages_list = AUR.multisearch(*args.search)
|
||||||
for package in Search.sort(packages_list, args.sort_by):
|
Search.check_if_empty(args.exit_code, not official_packages_list and not aur_packages_list)
|
||||||
AurPrinter(package).print(args.info)
|
|
||||||
|
for packages_list in (official_packages_list, aur_packages_list):
|
||||||
|
# keep sorting by packages source
|
||||||
|
for package in Search.sort(packages_list, args.sort_by):
|
||||||
|
AurPrinter(package).print(args.info)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def sort(packages: Iterable[AURPackage], sort_by: str) -> List[AURPackage]:
|
def sort(packages: Iterable[AURPackage], sort_by: str) -> List[AURPackage]:
|
||||||
"""
|
"""
|
||||||
sort package list by specified field
|
sort package list by specified field
|
||||||
:param packages: packages list to sort
|
|
||||||
:param sort_by: AUR package field name to sort by
|
Args:
|
||||||
:return: sorted list for packages
|
packages(Iterable[AURPackage]): packages list to sort
|
||||||
|
sort_by(str): AUR package field name to sort by
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[AURPackage]: sorted list for packages
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
InvalidOption: if search fields is not in list of allowed ones
|
||||||
"""
|
"""
|
||||||
if sort_by not in Search.SORT_FIELDS:
|
if sort_by not in Search.SORT_FIELDS:
|
||||||
raise InvalidOption(sort_by)
|
raise InvalidOption(sort_by)
|
||||||
|
@ -31,10 +31,12 @@ from ahriman.models.repository_paths import RepositoryPaths
|
|||||||
class Setup(Handler):
|
class Setup(Handler):
|
||||||
"""
|
"""
|
||||||
setup handler
|
setup handler
|
||||||
:cvar ARCHBUILD_COMMAND_PATH: default devtools command
|
|
||||||
:cvar BIN_DIR_PATH: directory for custom binaries
|
Attributes:
|
||||||
:cvar MIRRORLIST_PATH: path to pacman default mirrorlist (used by multilib repository)
|
ARCHBUILD_COMMAND_PATH(Path): (class attribute) default devtools command
|
||||||
:cvar SUDOERS_PATH: path to sudoers.d include configuration
|
BIN_DIR_PATH(Path): (class attribute) directory for custom binaries
|
||||||
|
MIRRORLIST_PATH(Path): (class attribute) path to pacman default mirrorlist (used by multilib repository)
|
||||||
|
SUDOERS_PATH(Path): (class attribute) path to sudoers.d include configuration
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ALLOW_AUTO_ARCHITECTURE_RUN = False
|
ALLOW_AUTO_ARCHITECTURE_RUN = False
|
||||||
@ -49,11 +51,13 @@ class Setup(Handler):
|
|||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
:param args: command line args
|
|
||||||
:param architecture: repository architecture
|
Args:
|
||||||
:param configuration: configuration instance
|
args(argparse.Namespace): command line args
|
||||||
:param no_report: force disable reporting
|
architecture(str): repository architecture
|
||||||
:param unsafe: if set no user check will be performed before path creation
|
configuration(Configuration): configuration instance
|
||||||
|
no_report(bool): force disable reporting
|
||||||
|
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.reload()
|
configuration.reload()
|
||||||
@ -72,9 +76,13 @@ class Setup(Handler):
|
|||||||
def build_command(prefix: str, architecture: str) -> Path:
|
def build_command(prefix: str, architecture: str) -> Path:
|
||||||
"""
|
"""
|
||||||
generate build command name
|
generate build command name
|
||||||
:param prefix: command prefix in {prefix}-{architecture}-build
|
|
||||||
:param architecture: repository architecture
|
Args:
|
||||||
:return: valid devtools command name
|
prefix(str): command prefix in {prefix}-{architecture}-build
|
||||||
|
architecture(str): repository architecture
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Path: valid devtools command name
|
||||||
"""
|
"""
|
||||||
return Setup.BIN_DIR_PATH / f"{prefix}-{architecture}-build"
|
return Setup.BIN_DIR_PATH / f"{prefix}-{architecture}-build"
|
||||||
|
|
||||||
@ -83,10 +91,12 @@ class Setup(Handler):
|
|||||||
include_path: Path) -> None:
|
include_path: Path) -> None:
|
||||||
"""
|
"""
|
||||||
create service specific configuration
|
create service specific configuration
|
||||||
:param args: command line args
|
|
||||||
:param architecture: repository architecture
|
Args:
|
||||||
:param repository: repository name
|
args(argparse.Namespace): command line args
|
||||||
:param include_path: path to directory with configuration includes
|
architecture(str): repository architecture
|
||||||
|
repository(str): repository name
|
||||||
|
include_path(Path): path to directory with configuration includes
|
||||||
"""
|
"""
|
||||||
configuration = Configuration()
|
configuration = Configuration()
|
||||||
|
|
||||||
@ -114,12 +124,14 @@ class Setup(Handler):
|
|||||||
no_multilib: bool, repository: str, paths: RepositoryPaths) -> None:
|
no_multilib: bool, repository: str, paths: RepositoryPaths) -> None:
|
||||||
"""
|
"""
|
||||||
create configuration for devtools based on `source` configuration
|
create configuration for devtools based on `source` configuration
|
||||||
:param prefix: command prefix in {prefix}-{architecture}-build
|
|
||||||
:param architecture: repository architecture
|
Args:
|
||||||
:param source: path to source configuration file
|
prefix(str): command prefix in {prefix}-{architecture}-build
|
||||||
:param no_multilib: do not add multilib repository
|
architecture(str): repository architecture
|
||||||
:param repository: repository name
|
source(Path): path to source configuration file
|
||||||
:param paths: repository paths instance
|
no_multilib(bool): do not add multilib repository
|
||||||
|
repository(str): repository name
|
||||||
|
paths(RepositoryPaths): repository paths instance
|
||||||
"""
|
"""
|
||||||
configuration = Configuration()
|
configuration = Configuration()
|
||||||
# preserve case
|
# preserve case
|
||||||
@ -149,8 +161,10 @@ class Setup(Handler):
|
|||||||
def configuration_create_makepkg(packager: str, paths: RepositoryPaths) -> None:
|
def configuration_create_makepkg(packager: str, paths: RepositoryPaths) -> None:
|
||||||
"""
|
"""
|
||||||
create configuration for makepkg
|
create configuration for makepkg
|
||||||
:param packager: packager identifier (e.g. name, email)
|
|
||||||
:param paths: repository paths instance
|
Args:
|
||||||
|
packager(str): packager identifier (e.g. name, email)
|
||||||
|
paths(RepositoryPaths): repository paths instance
|
||||||
"""
|
"""
|
||||||
(paths.root / ".makepkg.conf").write_text(f"PACKAGER='{packager}'\n", encoding="utf8")
|
(paths.root / ".makepkg.conf").write_text(f"PACKAGER='{packager}'\n", encoding="utf8")
|
||||||
|
|
||||||
@ -158,8 +172,10 @@ class Setup(Handler):
|
|||||||
def configuration_create_sudo(prefix: str, architecture: str) -> None:
|
def configuration_create_sudo(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
|
||||||
:param prefix: command prefix in {prefix}-{architecture}-build
|
|
||||||
:param architecture: repository architecture
|
Args:
|
||||||
|
prefix(str): command prefix in {prefix}-{architecture}-build
|
||||||
|
architecture(str): repository architecture
|
||||||
"""
|
"""
|
||||||
command = Setup.build_command(prefix, architecture)
|
command = Setup.build_command(prefix, architecture)
|
||||||
Setup.SUDOERS_PATH.write_text(f"ahriman ALL=(ALL) NOPASSWD: {command} *\n", encoding="utf8")
|
Setup.SUDOERS_PATH.write_text(f"ahriman ALL=(ALL) NOPASSWD: {command} *\n", encoding="utf8")
|
||||||
@ -169,8 +185,10 @@ class Setup(Handler):
|
|||||||
def executable_create(prefix: str, architecture: str) -> None:
|
def executable_create(prefix: str, architecture: str) -> None:
|
||||||
"""
|
"""
|
||||||
create executable for the service
|
create executable for the service
|
||||||
:param prefix: command prefix in {prefix}-{architecture}-build
|
|
||||||
:param architecture: repository architecture
|
Args:
|
||||||
|
prefix(str): command prefix in {prefix}-{architecture}-build
|
||||||
|
architecture(str): repository architecture
|
||||||
"""
|
"""
|
||||||
command = Setup.build_command(prefix, architecture)
|
command = Setup.build_command(prefix, architecture)
|
||||||
command.unlink(missing_ok=True)
|
command.unlink(missing_ok=True)
|
||||||
|
@ -36,10 +36,12 @@ class Sign(Handler):
|
|||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
:param args: command line args
|
|
||||||
:param architecture: repository architecture
|
Args:
|
||||||
:param configuration: configuration instance
|
args(argparse.Namespace): command line args
|
||||||
:param no_report: force disable reporting
|
architecture(str): repository architecture
|
||||||
:param unsafe: if set no user check will be performed before path creation
|
configuration(Configuration): configuration instance
|
||||||
|
no_report(bool): force disable reporting
|
||||||
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
Application(architecture, configuration, no_report, unsafe).sign(args.package)
|
Application(architecture, configuration, no_report, unsafe).sign(args.package)
|
||||||
|
@ -42,11 +42,13 @@ class Status(Handler):
|
|||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
:param args: command line args
|
|
||||||
:param architecture: repository architecture
|
Args:
|
||||||
:param configuration: configuration instance
|
args(argparse.Namespace): command line args
|
||||||
:param no_report: force disable reporting
|
architecture(str): repository architecture
|
||||||
:param unsafe: if set no user check will be performed before path creation
|
configuration(Configuration): configuration instance
|
||||||
|
no_report(bool): force disable reporting
|
||||||
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
# we are using reporter here
|
# we are using reporter here
|
||||||
client = Application(architecture, configuration, no_report=False, unsafe=unsafe).repository.reporter
|
client = Application(architecture, configuration, no_report=False, unsafe=unsafe).repository.reporter
|
||||||
|
@ -39,11 +39,13 @@ class StatusUpdate(Handler):
|
|||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
:param args: command line args
|
|
||||||
:param architecture: repository architecture
|
Args:
|
||||||
:param configuration: configuration instance
|
args(argparse.Namespace): command line args
|
||||||
:param no_report: force disable reporting
|
architecture(str): repository architecture
|
||||||
:param unsafe: if set no user check will be performed before path creation
|
configuration(Configuration): configuration instance
|
||||||
|
no_report(bool): force disable reporting
|
||||||
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
# we are using reporter here
|
# we are using reporter here
|
||||||
client = Application(architecture, configuration, no_report=False, unsafe=unsafe).repository.reporter
|
client = Application(architecture, configuration, no_report=False, unsafe=unsafe).repository.reporter
|
||||||
|
@ -28,7 +28,7 @@ from ahriman.core.configuration import Configuration
|
|||||||
|
|
||||||
class Sync(Handler):
|
class Sync(Handler):
|
||||||
"""
|
"""
|
||||||
remove sync handler
|
remote sync handler
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -36,10 +36,12 @@ class Sync(Handler):
|
|||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
:param args: command line args
|
|
||||||
:param architecture: repository architecture
|
Args:
|
||||||
:param configuration: configuration instance
|
args(argparse.Namespace): command line args
|
||||||
:param no_report: force disable reporting
|
architecture(str): repository architecture
|
||||||
:param unsafe: if set no user check will be performed before path creation
|
configuration(Configuration): configuration instance
|
||||||
|
no_report(bool): force disable reporting
|
||||||
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
Application(architecture, configuration, no_report, unsafe).sync(args.target, [])
|
Application(architecture, configuration, no_report, unsafe).sync(args.target, [])
|
||||||
|
@ -24,7 +24,6 @@ from typing import List, Type
|
|||||||
|
|
||||||
from ahriman.application.handlers.handler import Handler
|
from ahriman.application.handlers.handler import Handler
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
from ahriman.core.exceptions import ExitCode
|
|
||||||
from ahriman.core.formatters.string_printer import StringPrinter
|
from ahriman.core.formatters.string_printer import StringPrinter
|
||||||
|
|
||||||
|
|
||||||
@ -40,11 +39,13 @@ class UnsafeCommands(Handler):
|
|||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
:param args: command line args
|
|
||||||
:param architecture: repository architecture
|
Args:
|
||||||
:param configuration: configuration instance
|
args(argparse.Namespace): command line args
|
||||||
:param no_report: force disable reporting
|
architecture(str): repository architecture
|
||||||
:param unsafe: if set no user check will be performed before path creation
|
configuration(Configuration): configuration instance
|
||||||
|
no_report(bool): force disable reporting
|
||||||
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
parser = args.parser()
|
parser = args.parser()
|
||||||
unsafe_commands = UnsafeCommands.get_unsafe_commands(parser)
|
unsafe_commands = UnsafeCommands.get_unsafe_commands(parser)
|
||||||
@ -58,20 +59,25 @@ class UnsafeCommands(Handler):
|
|||||||
def check_unsafe(command: str, unsafe_commands: List[str], parser: argparse.ArgumentParser) -> None:
|
def check_unsafe(command: str, unsafe_commands: List[str], parser: argparse.ArgumentParser) -> None:
|
||||||
"""
|
"""
|
||||||
check if command is unsafe
|
check if command is unsafe
|
||||||
:param command: command to check
|
|
||||||
:param unsafe_commands: list of unsafe commands
|
Args:
|
||||||
:param parser: generated argument parser
|
command(str): command to check
|
||||||
|
unsafe_commands(List[str]): list of unsafe commands
|
||||||
|
parser(argparse.ArgumentParser): generated argument parser
|
||||||
"""
|
"""
|
||||||
args = parser.parse_args(shlex.split(command))
|
args = parser.parse_args(shlex.split(command))
|
||||||
if args.command in unsafe_commands:
|
UnsafeCommands.check_if_empty(True, args.command in unsafe_commands)
|
||||||
raise ExitCode()
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_unsafe_commands(parser: argparse.ArgumentParser) -> List[str]:
|
def get_unsafe_commands(parser: argparse.ArgumentParser) -> List[str]:
|
||||||
"""
|
"""
|
||||||
extract unsafe commands from argument parser
|
extract unsafe commands from argument parser
|
||||||
:param parser: generated argument parser
|
|
||||||
:return: list of commands with default unsafe flag
|
Args:
|
||||||
|
parser(argparse.ArgumentParser): generated argument parser
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[str]: list of commands with default unsafe flag
|
||||||
"""
|
"""
|
||||||
# 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))
|
||||||
|
@ -36,11 +36,13 @@ class Update(Handler):
|
|||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
:param args: command line args
|
|
||||||
:param architecture: repository architecture
|
Args:
|
||||||
:param configuration: configuration instance
|
args(argparse.Namespace): command line args
|
||||||
:param no_report: force disable reporting
|
architecture(str): repository architecture
|
||||||
:param unsafe: if set no user check will be performed before path creation
|
configuration(Configuration): configuration instance
|
||||||
|
no_report(bool): force disable reporting
|
||||||
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
application = Application(architecture, configuration, no_report, unsafe)
|
application = Application(architecture, configuration, no_report, unsafe)
|
||||||
packages = application.updates(args.package, args.no_aur, args.no_local, args.no_manual, args.no_vcs,
|
packages = application.updates(args.package, args.no_aur, args.no_local, args.no_manual, args.no_vcs,
|
||||||
@ -56,9 +58,13 @@ class Update(Handler):
|
|||||||
def log_fn(application: Application, dry_run: bool) -> Callable[[str], None]:
|
def log_fn(application: Application, dry_run: bool) -> Callable[[str], None]:
|
||||||
"""
|
"""
|
||||||
package updates log function
|
package updates log function
|
||||||
:param application: application instance
|
|
||||||
:param dry_run: do not perform update itself
|
Args:
|
||||||
:return: in case if dry_run is set it will return print, logger otherwise
|
application(Application): application instance
|
||||||
|
dry_run(bool): do not perform update itself
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Callable[[str], None]: in case if dry_run is set it will return print, logger otherwise
|
||||||
"""
|
"""
|
||||||
def inner(line: str) -> None:
|
def inner(line: str) -> None:
|
||||||
return print(line) if dry_run else application.logger.info(line)
|
return print(line) if dry_run else application.logger.info(line)
|
||||||
|
@ -28,10 +28,10 @@ from ahriman.core.configuration import Configuration
|
|||||||
from ahriman.core.database.sqlite import SQLite
|
from ahriman.core.database.sqlite import SQLite
|
||||||
from ahriman.core.formatters.user_printer import UserPrinter
|
from ahriman.core.formatters.user_printer import UserPrinter
|
||||||
from ahriman.models.action import Action
|
from ahriman.models.action import Action
|
||||||
from ahriman.models.user import User as MUser
|
from ahriman.models.user import User
|
||||||
|
|
||||||
|
|
||||||
class User(Handler):
|
class Users(Handler):
|
||||||
"""
|
"""
|
||||||
user management handler
|
user management handler
|
||||||
"""
|
"""
|
||||||
@ -43,53 +43,61 @@ class User(Handler):
|
|||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
:param args: command line args
|
|
||||||
:param architecture: repository architecture
|
Args:
|
||||||
:param configuration: configuration instance
|
args(argparse.Namespace): command line args
|
||||||
:param no_report: force disable reporting
|
architecture(str): repository architecture
|
||||||
:param unsafe: if set no user check will be performed before path creation
|
configuration(Configuration): configuration instance
|
||||||
|
no_report(bool): force disable reporting
|
||||||
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
database = SQLite.load(configuration)
|
database = SQLite.load(configuration)
|
||||||
|
|
||||||
if args.action == Action.Update:
|
if args.action == Action.Update:
|
||||||
salt = User.get_salt(configuration)
|
salt = Users.get_salt(configuration)
|
||||||
user = User.user_create(args)
|
user = Users.user_create(args)
|
||||||
|
|
||||||
auth_configuration = User.configuration_get(configuration.include)
|
auth_configuration = Users.configuration_get(configuration.include)
|
||||||
|
|
||||||
User.configuration_create(auth_configuration, user, salt, args.as_service, args.secure)
|
Users.configuration_create(auth_configuration, user, salt, args.as_service, args.secure)
|
||||||
database.user_update(user.hash_password(salt))
|
database.user_update(user.hash_password(salt))
|
||||||
elif args.action == Action.List:
|
elif args.action == Action.List:
|
||||||
users = database.user_list(args.username, args.role)
|
users = database.user_list(args.username, args.role)
|
||||||
User.check_if_empty(args.exit_code, not users)
|
Users.check_if_empty(args.exit_code, not users)
|
||||||
for user in users:
|
for user in users:
|
||||||
UserPrinter(user).print(verbose=True)
|
UserPrinter(user).print(verbose=True)
|
||||||
elif args.action == Action.Remove:
|
elif args.action == Action.Remove:
|
||||||
database.user_remove(args.username)
|
database.user_remove(args.username)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def configuration_create(configuration: Configuration, user: MUser, salt: str,
|
def configuration_create(configuration: Configuration, user: User, salt: str,
|
||||||
as_service_user: bool, secure: bool) -> None:
|
as_service_user: bool, secure: bool) -> None:
|
||||||
"""
|
"""
|
||||||
enable configuration if it has been disabled
|
enable configuration if it has been disabled
|
||||||
:param configuration: configuration instance
|
|
||||||
:param user: user descriptor
|
Args:
|
||||||
:param salt: password hash salt
|
configuration(Configuration): configuration instance
|
||||||
:param as_service_user: add user as service user, also set password and user to configuration
|
user(User): user descriptor
|
||||||
:param secure: if true then set file permissions to 0o600
|
salt(str): password hash salt
|
||||||
|
as_service_user(bool): add user as service user, also set password and user to configuration
|
||||||
|
secure(bool): if true then set file permissions to 0o600
|
||||||
"""
|
"""
|
||||||
configuration.set_option("auth", "salt", salt)
|
configuration.set_option("auth", "salt", salt)
|
||||||
if as_service_user:
|
if as_service_user:
|
||||||
configuration.set_option("web", "username", user.username)
|
configuration.set_option("web", "username", user.username)
|
||||||
configuration.set_option("web", "password", user.password)
|
configuration.set_option("web", "password", user.password)
|
||||||
User.configuration_write(configuration, secure)
|
Users.configuration_write(configuration, secure)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def configuration_get(include_path: Path) -> Configuration:
|
def configuration_get(include_path: Path) -> Configuration:
|
||||||
"""
|
"""
|
||||||
create configuration instance
|
create configuration instance
|
||||||
:param include_path: path to directory with configuration includes
|
|
||||||
:return: configuration instance. In case if there are local settings they will be loaded
|
Args:
|
||||||
|
include_path(Path): path to directory with configuration includes
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Configuration: configuration instance. In case if there are local settings they will be loaded
|
||||||
"""
|
"""
|
||||||
target = include_path / "auth.ini"
|
target = include_path / "auth.ini"
|
||||||
configuration = Configuration()
|
configuration = Configuration()
|
||||||
@ -103,8 +111,10 @@ class User(Handler):
|
|||||||
def configuration_write(configuration: Configuration, secure: bool) -> None:
|
def configuration_write(configuration: Configuration, secure: bool) -> None:
|
||||||
"""
|
"""
|
||||||
write configuration file
|
write configuration file
|
||||||
:param configuration: configuration instance
|
|
||||||
:param secure: if true then set file permissions to 0o600
|
Args:
|
||||||
|
configuration(Configuration): configuration instance
|
||||||
|
secure(bool): if true then set file permissions to 0o600
|
||||||
"""
|
"""
|
||||||
path, _ = configuration.check_loaded()
|
path, _ = configuration.check_loaded()
|
||||||
with path.open("w") as ahriman_configuration:
|
with path.open("w") as ahriman_configuration:
|
||||||
@ -116,22 +126,30 @@ class User(Handler):
|
|||||||
def get_salt(configuration: Configuration, salt_length: int = 20) -> str:
|
def get_salt(configuration: Configuration, salt_length: int = 20) -> str:
|
||||||
"""
|
"""
|
||||||
get salt from configuration or create new string
|
get salt from configuration or create new string
|
||||||
:param configuration: configuration instance
|
|
||||||
:param salt_length: salt length
|
Args:
|
||||||
:return: current salt
|
configuration(Configuration): configuration instance
|
||||||
|
salt_length(int, optional): salt length (Default value = 20)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: current salt
|
||||||
"""
|
"""
|
||||||
if salt := configuration.get("auth", "salt", fallback=None):
|
if salt := configuration.get("auth", "salt", fallback=None):
|
||||||
return salt
|
return salt
|
||||||
return MUser.generate_password(salt_length)
|
return User.generate_password(salt_length)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def user_create(args: argparse.Namespace) -> MUser:
|
def user_create(args: argparse.Namespace) -> User:
|
||||||
"""
|
"""
|
||||||
create user descriptor from arguments
|
create user descriptor from arguments
|
||||||
:param args: command line args
|
|
||||||
:return: built user descriptor
|
Args:
|
||||||
|
args(argparse.Namespace): command line args
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
User: built user descriptor
|
||||||
"""
|
"""
|
||||||
user = MUser(args.username, args.password, args.role)
|
user = User(args.username, args.password, args.role)
|
||||||
if user.password is None:
|
if user.password is None:
|
||||||
user.password = getpass.getpass()
|
user.password = getpass.getpass()
|
||||||
return user
|
return user
|
@ -39,11 +39,13 @@ class Web(Handler):
|
|||||||
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
configuration: Configuration, no_report: bool, unsafe: bool) -> None:
|
||||||
"""
|
"""
|
||||||
callback for command line
|
callback for command line
|
||||||
:param args: command line args
|
|
||||||
:param architecture: repository architecture
|
Args:
|
||||||
:param configuration: configuration instance
|
args(argparse.Namespace): command line args
|
||||||
:param no_report: force disable reporting
|
architecture(str): repository architecture
|
||||||
:param unsafe: if set no user check will be performed before path creation
|
configuration(Configuration): configuration instance
|
||||||
|
no_report(bool): force disable reporting
|
||||||
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
# we are using local import for optional dependencies
|
# we are using local import for optional dependencies
|
||||||
from ahriman.web.web import run_server, setup_service
|
from ahriman.web.web import run_server, setup_service
|
||||||
|
@ -37,19 +37,23 @@ from ahriman.models.build_status import BuildStatusEnum
|
|||||||
class Lock:
|
class Lock:
|
||||||
"""
|
"""
|
||||||
wrapper for application lock file
|
wrapper for application lock file
|
||||||
:ivar force: remove lock file on start if any
|
|
||||||
:ivar path: path to lock file if any
|
Attributes:
|
||||||
:ivar reporter: build status reporter instance
|
force(bool): remove lock file on start if any
|
||||||
:ivar paths: repository paths instance
|
path(Path): path to lock file if any
|
||||||
:ivar unsafe: skip user check
|
reporter(Client): build status reporter instance
|
||||||
|
paths(RepositoryPaths): repository paths instance
|
||||||
|
unsafe(bool): skip user check
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, args: argparse.Namespace, architecture: str, configuration: Configuration) -> None:
|
def __init__(self, args: argparse.Namespace, architecture: str, configuration: Configuration) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
default constructor
|
||||||
:param args: command line args
|
|
||||||
:param architecture: repository architecture
|
Args:
|
||||||
:param configuration: configuration instance
|
args(argparse.Namespace): command line args
|
||||||
|
architecture(str): repository architecture
|
||||||
|
configuration(Configuration): configuration instance
|
||||||
"""
|
"""
|
||||||
self.path = Path(f"{args.lock}_{architecture}") if args.lock is not None else None
|
self.path = Path(f"{args.lock}_{architecture}") if args.lock is not None else None
|
||||||
self.force = args.force
|
self.force = args.force
|
||||||
@ -62,11 +66,11 @@ class Lock:
|
|||||||
"""
|
"""
|
||||||
default workflow is the following:
|
default workflow is the following:
|
||||||
|
|
||||||
check user UID
|
1. Check user UID
|
||||||
check if there is lock file
|
2. Check if there is lock file
|
||||||
check web status watcher status
|
3. Check web status watcher status
|
||||||
create lock file
|
4. Create lock file
|
||||||
report to web if enabled
|
5. Report to status page if enabled
|
||||||
"""
|
"""
|
||||||
self.check_user()
|
self.check_user()
|
||||||
self.check_version()
|
self.check_version()
|
||||||
@ -78,10 +82,14 @@ class Lock:
|
|||||||
exc_tb: TracebackType) -> Literal[False]:
|
exc_tb: TracebackType) -> Literal[False]:
|
||||||
"""
|
"""
|
||||||
remove lock file when done
|
remove lock file when done
|
||||||
:param exc_type: exception type name if any
|
|
||||||
:param exc_val: exception raised if any
|
Args:
|
||||||
:param exc_tb: exception traceback if any
|
exc_type(Optional[Type[Exception]]): exception type name if any
|
||||||
:return: always False (do not suppress any exception)
|
exc_val(Optional[Exception]): exception raised if any
|
||||||
|
exc_tb(TracebackType): exception traceback if any
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Literal[False]: always False (do not suppress any exception)
|
||||||
"""
|
"""
|
||||||
self.clear()
|
self.clear()
|
||||||
status = BuildStatusEnum.Success if exc_val is None else BuildStatusEnum.Failed
|
status = BuildStatusEnum.Success if exc_val is None else BuildStatusEnum.Failed
|
||||||
@ -116,6 +124,9 @@ class Lock:
|
|||||||
def create(self) -> None:
|
def create(self) -> None:
|
||||||
"""
|
"""
|
||||||
create lock file
|
create lock file
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
DuplicateRun: if lock exists and no force flag supplied
|
||||||
"""
|
"""
|
||||||
if self.path is None:
|
if self.path is None:
|
||||||
return
|
return
|
||||||
|
@ -26,13 +26,17 @@ from ahriman.core.configuration import Configuration
|
|||||||
class Pacman:
|
class Pacman:
|
||||||
"""
|
"""
|
||||||
alpm wrapper
|
alpm wrapper
|
||||||
:ivar handle: pyalpm root `Handle`
|
|
||||||
|
Attributes:
|
||||||
|
handle(Handle): pyalpm root `Handle`
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, configuration: Configuration) -> None:
|
def __init__(self, configuration: Configuration) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
default constructor
|
||||||
:param configuration: configuration instance
|
|
||||||
|
Args:
|
||||||
|
configuration(Configuration): configuration instance
|
||||||
"""
|
"""
|
||||||
root = configuration.get("alpm", "root")
|
root = configuration.get("alpm", "root")
|
||||||
pacman_root = configuration.getpath("alpm", "database")
|
pacman_root = configuration.getpath("alpm", "database")
|
||||||
@ -43,7 +47,9 @@ class Pacman:
|
|||||||
def all_packages(self) -> Set[str]:
|
def all_packages(self) -> Set[str]:
|
||||||
"""
|
"""
|
||||||
get list of packages known for alpm
|
get list of packages known for alpm
|
||||||
:return: list of package names
|
|
||||||
|
Returns:
|
||||||
|
Set[str]: list of package names
|
||||||
"""
|
"""
|
||||||
result: Set[str] = set()
|
result: Set[str] = set()
|
||||||
for database in self.handle.get_syncdbs():
|
for database in self.handle.get_syncdbs():
|
||||||
|
19
src/ahriman/core/alpm/remote/__init__.py
Normal file
19
src/ahriman/core/alpm/remote/__init__.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#
|
||||||
|
# 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/>.
|
||||||
|
#
|
@ -17,26 +17,25 @@
|
|||||||
# 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 __future__ import annotations
|
|
||||||
|
|
||||||
import logging
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from typing import Any, Dict, List, Optional, Type
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
|
from ahriman.core.alpm.remote.remote import Remote
|
||||||
from ahriman.core.exceptions import InvalidPackageInfo
|
from ahriman.core.exceptions import InvalidPackageInfo
|
||||||
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
|
||||||
|
|
||||||
|
|
||||||
class AUR:
|
class AUR(Remote):
|
||||||
"""
|
"""
|
||||||
AUR RPC wrapper
|
AUR RPC wrapper
|
||||||
:cvar DEFAULT_RPC_URL: default AUR RPC url
|
|
||||||
:cvar DEFAULT_RPC_VERSION: default AUR RPC version
|
Attributes:
|
||||||
:ivar logger: class logger
|
DEFAULT_RPC_URL(str): (class attribute) default AUR RPC url
|
||||||
:ivar rpc_url: AUR RPC url
|
DEFAULT_RPC_VERSION(str): (class attribute) default AUR RPC version
|
||||||
:ivar rpc_version: AUR RPC version
|
rpc_url(str): AUR RPC url
|
||||||
|
rpc_version(str): AUR RPC version
|
||||||
"""
|
"""
|
||||||
|
|
||||||
DEFAULT_RPC_URL = "https://aur.archlinux.org/rpc"
|
DEFAULT_RPC_URL = "https://aur.archlinux.org/rpc"
|
||||||
@ -45,56 +44,28 @@ class AUR:
|
|||||||
def __init__(self, rpc_url: Optional[str] = None, rpc_version: Optional[str] = None) -> None:
|
def __init__(self, rpc_url: Optional[str] = None, rpc_version: Optional[str] = None) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
default constructor
|
||||||
:param rpc_url: AUR RPC url
|
|
||||||
:param rpc_version: AUR RPC version
|
Args:
|
||||||
|
rpc_url(Optional[str], optional): AUR RPC url (Default value = None)
|
||||||
|
rpc_version(Optional[str], optional): AUR RPC version (Default value = None)
|
||||||
"""
|
"""
|
||||||
|
Remote.__init__(self)
|
||||||
self.rpc_url = rpc_url or self.DEFAULT_RPC_URL
|
self.rpc_url = rpc_url or self.DEFAULT_RPC_URL
|
||||||
self.rpc_version = rpc_version or self.DEFAULT_RPC_VERSION
|
self.rpc_version = rpc_version or self.DEFAULT_RPC_VERSION
|
||||||
self.logger = logging.getLogger("build_details")
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def info(cls: Type[AUR], package_name: str) -> AURPackage:
|
|
||||||
"""
|
|
||||||
get package info by its name
|
|
||||||
:param package_name: package name to search
|
|
||||||
:return: package which match the package name
|
|
||||||
"""
|
|
||||||
return cls().package_info(package_name)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def multisearch(cls: Type[AUR], *keywords: str) -> List[AURPackage]:
|
|
||||||
"""
|
|
||||||
search in AUR by using API with multiple words. This method is required in order to handle
|
|
||||||
https://bugs.archlinux.org/task/49133. In addition short words will be dropped
|
|
||||||
:param keywords: search terms, e.g. "ahriman", "is", "cool"
|
|
||||||
:return: list of packages each of them matches all search terms
|
|
||||||
"""
|
|
||||||
instance = cls()
|
|
||||||
packages: Dict[str, AURPackage] = {}
|
|
||||||
for term in filter(lambda word: len(word) > 3, keywords):
|
|
||||||
portion = instance.search(term)
|
|
||||||
packages = {
|
|
||||||
package.package_base: package
|
|
||||||
for package in portion
|
|
||||||
if package.package_base in packages or not packages
|
|
||||||
}
|
|
||||||
return list(packages.values())
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def search(cls: Type[AUR], *keywords: str) -> List[AURPackage]:
|
|
||||||
"""
|
|
||||||
search package in AUR web
|
|
||||||
:param keywords: keywords to search
|
|
||||||
:return: list of packages which match the criteria
|
|
||||||
"""
|
|
||||||
return cls().package_search(*keywords)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def parse_response(response: Dict[str, Any]) -> List[AURPackage]:
|
def parse_response(response: Dict[str, Any]) -> List[AURPackage]:
|
||||||
"""
|
"""
|
||||||
parse RPC response to package list
|
parse RPC response to package list
|
||||||
:param response: RPC response json
|
|
||||||
:return: list of parsed packages
|
Args:
|
||||||
|
response(Dict[str, Any]): RPC response json
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[AURPackage]: list of parsed packages
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
InvalidPackageInfo: for error API response
|
||||||
"""
|
"""
|
||||||
response_type = response["type"]
|
response_type = response["type"]
|
||||||
if response_type == "error":
|
if response_type == "error":
|
||||||
@ -105,10 +76,14 @@ class AUR:
|
|||||||
def make_request(self, request_type: str, *args: str, **kwargs: str) -> List[AURPackage]:
|
def make_request(self, request_type: str, *args: str, **kwargs: str) -> List[AURPackage]:
|
||||||
"""
|
"""
|
||||||
perform request to AUR RPC
|
perform request to AUR RPC
|
||||||
:param request_type: AUR request type, e.g. search, info
|
|
||||||
:param args: list of arguments to be passed as args query parameter
|
Args:
|
||||||
:param kwargs: list of additional named parameters like by
|
request_type(str): AUR request type, e.g. search, info
|
||||||
:return: response parsed to package list
|
*args(str): list of arguments to be passed as args query parameter
|
||||||
|
**kwargs(str): list of additional named parameters like by
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[AURPackage]: response parsed to package list
|
||||||
"""
|
"""
|
||||||
query: Dict[str, Any] = {
|
query: Dict[str, Any] = {
|
||||||
"type": request_type,
|
"type": request_type,
|
||||||
@ -138,17 +113,24 @@ class AUR:
|
|||||||
def package_info(self, package_name: str) -> AURPackage:
|
def package_info(self, package_name: str) -> AURPackage:
|
||||||
"""
|
"""
|
||||||
get package info by its name
|
get package info by its name
|
||||||
:param package_name: package name to search
|
|
||||||
:return: package which match the package name
|
Args:
|
||||||
|
package_name(str): package name to search
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
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)
|
return next(package for package in packages if package.name == package_name)
|
||||||
|
|
||||||
def package_search(self, *keywords: str, by: str = "name-desc") -> List[AURPackage]:
|
def package_search(self, *keywords: str) -> List[AURPackage]:
|
||||||
"""
|
"""
|
||||||
search package in AUR web
|
search package in AUR web
|
||||||
:param keywords: keywords to search
|
|
||||||
:param by: search by the field
|
Args:
|
||||||
:return: list of packages which match the criteria
|
*keywords(str): keywords to search
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[AURPackage]: list of packages which match the criteria
|
||||||
"""
|
"""
|
||||||
return self.make_request("search", *keywords, by=by)
|
return self.make_request("search", *keywords, by="name-desc")
|
114
src/ahriman/core/alpm/remote/official.py
Normal file
114
src/ahriman/core/alpm/remote/official.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 requests
|
||||||
|
|
||||||
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
|
from ahriman.core.alpm.remote.remote import Remote
|
||||||
|
from ahriman.core.exceptions import InvalidPackageInfo
|
||||||
|
from ahriman.core.util import exception_response_text
|
||||||
|
from ahriman.models.aur_package import AURPackage
|
||||||
|
|
||||||
|
|
||||||
|
class Official(Remote):
|
||||||
|
"""
|
||||||
|
official repository RPC wrapper
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
DEFAULT_RPC_URL(str): (class attribute) default AUR RPC url
|
||||||
|
rpc_url(str): AUR RPC url
|
||||||
|
"""
|
||||||
|
|
||||||
|
DEFAULT_RPC_URL = "https://archlinux.org/packages/search/json"
|
||||||
|
|
||||||
|
def __init__(self, rpc_url: Optional[str] = None) -> None:
|
||||||
|
"""
|
||||||
|
default constructor
|
||||||
|
|
||||||
|
Args:
|
||||||
|
rpc_url(Optional[str], optional): AUR RPC url (Default value = None)
|
||||||
|
"""
|
||||||
|
Remote.__init__(self)
|
||||||
|
self.rpc_url = rpc_url or self.DEFAULT_RPC_URL
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def parse_response(response: Dict[str, Any]) -> List[AURPackage]:
|
||||||
|
"""
|
||||||
|
parse RPC response to package list
|
||||||
|
|
||||||
|
Args:
|
||||||
|
response(Dict[str, Any]): RPC response json
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[AURPackage]: list of parsed packages
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
InvalidPackageInfo: for error API response
|
||||||
|
"""
|
||||||
|
if not response["valid"]:
|
||||||
|
raise InvalidPackageInfo("API validation error")
|
||||||
|
return [AURPackage.from_repo(package) for package in response["results"]]
|
||||||
|
|
||||||
|
def make_request(self, *args: str, by: str) -> List[AURPackage]:
|
||||||
|
"""
|
||||||
|
perform request to official repositories RPC
|
||||||
|
|
||||||
|
Args:
|
||||||
|
*args(str): list of arguments to be passed as args query parameter
|
||||||
|
by(str): search by the field
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[AURPackage]: response parsed to package list
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
response = requests.get(self.rpc_url, params={by: args})
|
||||||
|
response.raise_for_status()
|
||||||
|
return self.parse_response(response.json())
|
||||||
|
except requests.HTTPError as e:
|
||||||
|
self.logger.exception("could not perform request: %s", exception_response_text(e))
|
||||||
|
raise
|
||||||
|
except Exception:
|
||||||
|
self.logger.exception("could not perform request")
|
||||||
|
raise
|
||||||
|
|
||||||
|
def package_info(self, package_name: str) -> AURPackage:
|
||||||
|
"""
|
||||||
|
get package info by its name
|
||||||
|
|
||||||
|
Args:
|
||||||
|
package_name(str): package name to search
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
AURPackage: package which match the package name
|
||||||
|
"""
|
||||||
|
packages = self.make_request(package_name, by="name")
|
||||||
|
return next(package for package in packages if package.name == package_name)
|
||||||
|
|
||||||
|
def package_search(self, *keywords: str) -> List[AURPackage]:
|
||||||
|
"""
|
||||||
|
search package in AUR web
|
||||||
|
|
||||||
|
Args:
|
||||||
|
*keywords(str): keywords to search
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[AURPackage]: list of packages which match the criteria
|
||||||
|
"""
|
||||||
|
return self.make_request(*keywords, by="q")
|
120
src/ahriman/core/alpm/remote/remote.py
Normal file
120
src/ahriman/core/alpm/remote/remote.py
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
#
|
||||||
|
# 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 __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from typing import Dict, List, Type
|
||||||
|
|
||||||
|
from ahriman.models.aur_package import AURPackage
|
||||||
|
|
||||||
|
|
||||||
|
class Remote:
|
||||||
|
"""
|
||||||
|
base class for remote package search
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
logger(logging.Logger): class logger
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
"""
|
||||||
|
default constructor
|
||||||
|
"""
|
||||||
|
self.logger = logging.getLogger("build_details")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def info(cls: Type[Remote], package_name: str) -> AURPackage:
|
||||||
|
"""
|
||||||
|
get package info by its name
|
||||||
|
|
||||||
|
Args:
|
||||||
|
package_name(str): package name to search
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
AURPackage: package which match the package name
|
||||||
|
"""
|
||||||
|
return cls().package_info(package_name)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def multisearch(cls: Type[Remote], *keywords: str) -> List[AURPackage]:
|
||||||
|
"""
|
||||||
|
search in remote repository by using API with multiple words. This method is required in order to handle
|
||||||
|
https://bugs.archlinux.org/task/49133. In addition, short words will be dropped
|
||||||
|
|
||||||
|
Args:
|
||||||
|
*keywords(str): search terms, e.g. "ahriman", "is", "cool"
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[AURPackage]: list of packages each of them matches all search terms
|
||||||
|
"""
|
||||||
|
instance = cls()
|
||||||
|
packages: Dict[str, AURPackage] = {}
|
||||||
|
for term in filter(lambda word: len(word) > 3, keywords):
|
||||||
|
portion = instance.search(term)
|
||||||
|
packages = {
|
||||||
|
package.name: package # not mistake to group them by name
|
||||||
|
for package in portion
|
||||||
|
if package.name in packages or not packages
|
||||||
|
}
|
||||||
|
return list(packages.values())
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def search(cls: Type[Remote], *keywords: str) -> List[AURPackage]:
|
||||||
|
"""
|
||||||
|
search package in AUR web
|
||||||
|
|
||||||
|
Args:
|
||||||
|
*keywords(str): search terms, e.g. "ahriman", "is", "cool"
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[AURPackage]: list of packages which match the criteria
|
||||||
|
"""
|
||||||
|
return cls().package_search(*keywords)
|
||||||
|
|
||||||
|
def package_info(self, package_name: str) -> AURPackage:
|
||||||
|
"""
|
||||||
|
get package info by its name
|
||||||
|
|
||||||
|
Args:
|
||||||
|
package_name(str): package name to search
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
AURPackage: package which match the package name
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
NotImplementedError: not implemented method
|
||||||
|
"""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def package_search(self, *keywords: str) -> List[AURPackage]:
|
||||||
|
"""
|
||||||
|
search package in AUR web
|
||||||
|
|
||||||
|
Args:
|
||||||
|
*keywords(str): keywords to search
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[AURPackage]: list of packages which match the criteria
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
NotImplementedError: not implemented method
|
||||||
|
"""
|
||||||
|
raise NotImplementedError
|
@ -30,11 +30,13 @@ from ahriman.models.repository_paths import RepositoryPaths
|
|||||||
class Repo:
|
class Repo:
|
||||||
"""
|
"""
|
||||||
repo-add and repo-remove wrapper
|
repo-add and repo-remove wrapper
|
||||||
:ivar logger: class logger
|
|
||||||
:ivar name: repository name
|
Attributes:
|
||||||
:ivar paths: repository paths instance
|
logger(logging.Logger): class logger
|
||||||
:ivar sign_args: additional args which have to be used to sign repository archive
|
name(str): repository name
|
||||||
:ivar uid: uid of the repository owner user
|
paths(RepositoryPaths): repository paths instance
|
||||||
|
sign_args(List[str]): additional args which have to be used to sign repository archive
|
||||||
|
uid(int): uid of the repository owner user
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_check_output = check_output
|
_check_output = check_output
|
||||||
@ -42,9 +44,11 @@ class Repo:
|
|||||||
def __init__(self, name: str, paths: RepositoryPaths, sign_args: List[str]) -> None:
|
def __init__(self, name: str, paths: RepositoryPaths, sign_args: List[str]) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
default constructor
|
||||||
:param name: repository name
|
|
||||||
:param paths: repository paths instance
|
Args:
|
||||||
:param sign_args: additional args which have to be used to sign repository archive
|
name(str): repository name
|
||||||
|
paths(RepositoryPaths): repository paths instance
|
||||||
|
sign_args(List[str]): additional args which have to be used to sign repository archive
|
||||||
"""
|
"""
|
||||||
self.logger = logging.getLogger("build_details")
|
self.logger = logging.getLogger("build_details")
|
||||||
self.name = name
|
self.name = name
|
||||||
@ -55,14 +59,19 @@ class Repo:
|
|||||||
@property
|
@property
|
||||||
def repo_path(self) -> Path:
|
def repo_path(self) -> Path:
|
||||||
"""
|
"""
|
||||||
:return: path to repository database
|
get full path to the repository database
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Path: path to repository database
|
||||||
"""
|
"""
|
||||||
return self.paths.repository / f"{self.name}.db.tar.gz"
|
return self.paths.repository / f"{self.name}.db.tar.gz"
|
||||||
|
|
||||||
def add(self, path: Path) -> None:
|
def add(self, path: Path) -> None:
|
||||||
"""
|
"""
|
||||||
add new package to repository
|
add new package to repository
|
||||||
:param path: path to archive to add
|
|
||||||
|
Args:
|
||||||
|
path(Path): path to archive to add
|
||||||
"""
|
"""
|
||||||
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),
|
||||||
@ -85,8 +94,10 @@ class Repo:
|
|||||||
def remove(self, package: str, filename: Path) -> None:
|
def remove(self, package: str, filename: Path) -> None:
|
||||||
"""
|
"""
|
||||||
remove package from repository
|
remove package from repository
|
||||||
:param package: package name to remove
|
|
||||||
:param filename: package filename to remove
|
Args:
|
||||||
|
package(str): package name to remove
|
||||||
|
filename(Path): package filename to remove
|
||||||
"""
|
"""
|
||||||
# remove package and signature (if any) from filesystem
|
# remove package and signature (if any) from filesystem
|
||||||
for full_path in self.paths.repository.glob(f"{filename}*"):
|
for full_path in self.paths.repository.glob(f"{filename}*"):
|
||||||
|
@ -32,16 +32,21 @@ from ahriman.models.user_access import UserAccess
|
|||||||
class Auth:
|
class Auth:
|
||||||
"""
|
"""
|
||||||
helper to deal with user authorization
|
helper to deal with user authorization
|
||||||
:ivar enabled: indicates if authorization is enabled
|
|
||||||
:ivar max_age: session age in seconds. It will be used for both client side and server side checks
|
Attributes:
|
||||||
:ivar safe_build_status: allow read only access to the index page
|
enabled(bool): indicates if authorization is enabled
|
||||||
|
logger(logging.Logger): class logger
|
||||||
|
max_age(int): session age in seconds. It will be used for both client side and server side checks
|
||||||
|
safe_build_status(bool): allow read only access to the index page
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, configuration: Configuration, provider: AuthSettings = AuthSettings.Disabled) -> None:
|
def __init__(self, configuration: Configuration, provider: AuthSettings = AuthSettings.Disabled) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
default constructor
|
||||||
:param configuration: configuration instance
|
|
||||||
:param provider: authorization type definition
|
Args:
|
||||||
|
configuration(Configuration): configuration instance
|
||||||
|
provider(AuthSettings, optional): authorization type definition (Default value = AuthSettings.Disabled)
|
||||||
"""
|
"""
|
||||||
self.logger = logging.getLogger("http")
|
self.logger = logging.getLogger("http")
|
||||||
|
|
||||||
@ -57,7 +62,9 @@ class Auth:
|
|||||||
In case of internal authentication it must provide an interface (modal form) to login with button sends POST
|
In case of internal authentication it must provide an interface (modal form) to login with button sends POST
|
||||||
request. But for an external providers behaviour can be different: e.g. OAuth provider requires sending GET
|
request. But for an external providers behaviour can be different: e.g. OAuth provider requires sending GET
|
||||||
request to external resource
|
request to external resource
|
||||||
:return: login control as html code to insert
|
|
||||||
|
Returns:
|
||||||
|
str: login control as html code to insert
|
||||||
"""
|
"""
|
||||||
return """<button type="button" class="btn btn-link" data-bs-toggle="modal" data-bs-target="#loginForm" style="text-decoration: none">login</button>"""
|
return """<button type="button" class="btn btn-link" data-bs-toggle="modal" data-bs-target="#loginForm" style="text-decoration: none">login</button>"""
|
||||||
|
|
||||||
@ -65,9 +72,13 @@ class Auth:
|
|||||||
def load(cls: Type[Auth], configuration: Configuration, database: SQLite) -> Auth:
|
def load(cls: Type[Auth], configuration: Configuration, database: SQLite) -> Auth:
|
||||||
"""
|
"""
|
||||||
load authorization module from settings
|
load authorization module from settings
|
||||||
:param configuration: configuration instance
|
|
||||||
:param database: database instance
|
Args:
|
||||||
:return: authorization module according to current settings
|
configuration(Configuration): configuration instance
|
||||||
|
database(SQLite): database instance
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Auth: authorization module according to current settings
|
||||||
"""
|
"""
|
||||||
provider = AuthSettings.from_option(configuration.get("auth", "target", fallback="disabled"))
|
provider = AuthSettings.from_option(configuration.get("auth", "target", fallback="disabled"))
|
||||||
if provider == AuthSettings.Configuration:
|
if provider == AuthSettings.Configuration:
|
||||||
@ -81,9 +92,13 @@ class Auth:
|
|||||||
async def check_credentials(self, username: Optional[str], password: Optional[str]) -> bool: # pylint: disable=no-self-use
|
async def check_credentials(self, username: Optional[str], password: Optional[str]) -> bool: # pylint: disable=no-self-use
|
||||||
"""
|
"""
|
||||||
validate user password
|
validate user password
|
||||||
:param username: username
|
|
||||||
:param password: entered password
|
Args:
|
||||||
:return: True in case if password matches, False otherwise
|
username(Optional[str]): username
|
||||||
|
password(Optional[str]): entered password
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True in case if password matches, False otherwise
|
||||||
"""
|
"""
|
||||||
del username, password
|
del username, password
|
||||||
return True
|
return True
|
||||||
@ -91,8 +106,12 @@ class Auth:
|
|||||||
async def known_username(self, username: Optional[str]) -> bool: # pylint: disable=no-self-use
|
async def known_username(self, username: Optional[str]) -> bool: # pylint: disable=no-self-use
|
||||||
"""
|
"""
|
||||||
check if user is known
|
check if user is known
|
||||||
:param username: username
|
|
||||||
:return: True in case if user is known and can be authorized and False otherwise
|
Args:
|
||||||
|
username(Optional[str]): username
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True in case if user is known and can be authorized and False otherwise
|
||||||
"""
|
"""
|
||||||
del username
|
del username
|
||||||
return True
|
return True
|
||||||
@ -100,10 +119,14 @@ class Auth:
|
|||||||
async def verify_access(self, username: str, required: UserAccess, context: Optional[str]) -> bool: # pylint: disable=no-self-use
|
async def verify_access(self, username: str, required: UserAccess, context: Optional[str]) -> bool: # pylint: disable=no-self-use
|
||||||
"""
|
"""
|
||||||
validate if user has access to requested resource
|
validate if user has access to requested resource
|
||||||
:param username: username
|
|
||||||
:param required: required access level
|
Args:
|
||||||
:param context: URI request path
|
username(str): username
|
||||||
:return: True in case if user is allowed to do this request and False otherwise
|
required(UserAccess): required access level
|
||||||
|
context(Optional[str]): URI request path
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True in case if user is allowed to do this request and False otherwise
|
||||||
"""
|
"""
|
||||||
del username, required, context
|
del username, required, context
|
||||||
return True
|
return True
|
||||||
|
@ -29,8 +29,12 @@ except ImportError:
|
|||||||
async def authorized_userid(*args: Any) -> Any:
|
async def authorized_userid(*args: Any) -> Any:
|
||||||
"""
|
"""
|
||||||
handle aiohttp security methods
|
handle aiohttp security methods
|
||||||
:param args: argument list as provided by authorized_userid function
|
|
||||||
:return: None in case if no aiohttp_security module found and function call otherwise
|
Args:
|
||||||
|
*args(Any): argument list as provided by authorized_userid function
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Any: None in case if no aiohttp_security module found and function call otherwise
|
||||||
"""
|
"""
|
||||||
if _has_aiohttp_security:
|
if _has_aiohttp_security:
|
||||||
return await aiohttp_security.authorized_userid(*args) # pylint: disable=no-value-for-parameter
|
return await aiohttp_security.authorized_userid(*args) # pylint: disable=no-value-for-parameter
|
||||||
@ -40,8 +44,12 @@ async def authorized_userid(*args: Any) -> Any:
|
|||||||
async def check_authorized(*args: Any) -> Any:
|
async def check_authorized(*args: Any) -> Any:
|
||||||
"""
|
"""
|
||||||
handle aiohttp security methods
|
handle aiohttp security methods
|
||||||
:param args: argument list as provided by check_authorized function
|
|
||||||
:return: None in case if no aiohttp_security module found and function call otherwise
|
Args:
|
||||||
|
*args(Any): argument list as provided by check_authorized function
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Any: None in case if no aiohttp_security module found and function call otherwise
|
||||||
"""
|
"""
|
||||||
if _has_aiohttp_security:
|
if _has_aiohttp_security:
|
||||||
return await aiohttp_security.check_authorized(*args) # pylint: disable=no-value-for-parameter
|
return await aiohttp_security.check_authorized(*args) # pylint: disable=no-value-for-parameter
|
||||||
@ -51,8 +59,12 @@ async def check_authorized(*args: Any) -> Any:
|
|||||||
async def forget(*args: Any) -> Any:
|
async def forget(*args: Any) -> Any:
|
||||||
"""
|
"""
|
||||||
handle aiohttp security methods
|
handle aiohttp security methods
|
||||||
:param args: argument list as provided by forget function
|
|
||||||
:return: None in case if no aiohttp_security module found and function call otherwise
|
Args:
|
||||||
|
*args(Any): argument list as provided by forget function
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Any: None in case if no aiohttp_security module found and function call otherwise
|
||||||
"""
|
"""
|
||||||
if _has_aiohttp_security:
|
if _has_aiohttp_security:
|
||||||
return await aiohttp_security.forget(*args) # pylint: disable=no-value-for-parameter
|
return await aiohttp_security.forget(*args) # pylint: disable=no-value-for-parameter
|
||||||
@ -62,8 +74,12 @@ async def forget(*args: Any) -> Any:
|
|||||||
async def remember(*args: Any) -> Any:
|
async def remember(*args: Any) -> Any:
|
||||||
"""
|
"""
|
||||||
handle disabled auth
|
handle disabled auth
|
||||||
:param args: argument list as provided by remember function
|
|
||||||
:return: None in case if no aiohttp_security module found and function call otherwise
|
Args:
|
||||||
|
*args(Any): argument list as provided by remember function
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Any: None in case if no aiohttp_security module found and function call otherwise
|
||||||
"""
|
"""
|
||||||
if _has_aiohttp_security:
|
if _has_aiohttp_security:
|
||||||
return await aiohttp_security.remember(*args) # pylint: disable=no-value-for-parameter
|
return await aiohttp_security.remember(*args) # pylint: disable=no-value-for-parameter
|
||||||
|
@ -31,17 +31,21 @@ from ahriman.models.user_access import UserAccess
|
|||||||
class Mapping(Auth):
|
class Mapping(Auth):
|
||||||
"""
|
"""
|
||||||
user authorization based on mapping from configuration file
|
user authorization based on mapping from configuration file
|
||||||
:ivar salt: random generated string to salt passwords
|
|
||||||
:ivar database: database instance
|
Attributes:
|
||||||
|
salt(str): random generated string to salt passwords
|
||||||
|
database(SQLite): database instance
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, configuration: Configuration, database: SQLite,
|
def __init__(self, configuration: Configuration, database: SQLite,
|
||||||
provider: AuthSettings = AuthSettings.Configuration) -> None:
|
provider: AuthSettings = AuthSettings.Configuration) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
default constructor
|
||||||
:param configuration: configuration instance
|
|
||||||
:param database: database instance
|
Args:
|
||||||
:param provider: authorization type definition
|
configuration(Configuration): configuration instance
|
||||||
|
database(SQLite): database instance
|
||||||
|
provider(AuthSettings, optional): authorization type definition (Default value = AuthSettings.Configuration)
|
||||||
"""
|
"""
|
||||||
Auth.__init__(self, configuration, provider)
|
Auth.__init__(self, configuration, provider)
|
||||||
self.database = database
|
self.database = database
|
||||||
@ -50,9 +54,13 @@ class Mapping(Auth):
|
|||||||
async def check_credentials(self, username: Optional[str], password: Optional[str]) -> bool:
|
async def check_credentials(self, username: Optional[str], password: Optional[str]) -> bool:
|
||||||
"""
|
"""
|
||||||
validate user password
|
validate user password
|
||||||
:param username: username
|
|
||||||
:param password: entered password
|
Args:
|
||||||
:return: True in case if password matches, False otherwise
|
username(Optional[str]): username
|
||||||
|
password(Optional[str]): entered password
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True in case if password matches, False otherwise
|
||||||
"""
|
"""
|
||||||
if username is None or password is None:
|
if username is None or password is None:
|
||||||
return False # invalid data supplied
|
return False # invalid data supplied
|
||||||
@ -62,26 +70,38 @@ class Mapping(Auth):
|
|||||||
def get_user(self, username: str) -> Optional[User]:
|
def get_user(self, username: str) -> Optional[User]:
|
||||||
"""
|
"""
|
||||||
retrieve user from in-memory mapping
|
retrieve user from in-memory mapping
|
||||||
:param username: username
|
|
||||||
:return: user descriptor if username is known and None otherwise
|
Args:
|
||||||
|
username(str): username
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Optional[User]: user descriptor if username is known and None otherwise
|
||||||
"""
|
"""
|
||||||
return self.database.user_get(username)
|
return self.database.user_get(username)
|
||||||
|
|
||||||
async def known_username(self, username: Optional[str]) -> bool:
|
async def known_username(self, username: Optional[str]) -> bool:
|
||||||
"""
|
"""
|
||||||
check if user is known
|
check if user is known
|
||||||
:param username: username
|
|
||||||
:return: True in case if user is known and can be authorized and False otherwise
|
Args:
|
||||||
|
username(Optional[str]): username
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True in case if user is known and can be authorized and False otherwise
|
||||||
"""
|
"""
|
||||||
return username is not None and self.get_user(username) is not None
|
return username is not None and self.get_user(username) is not None
|
||||||
|
|
||||||
async def verify_access(self, username: str, required: UserAccess, context: Optional[str]) -> bool:
|
async def verify_access(self, username: str, required: UserAccess, context: Optional[str]) -> bool:
|
||||||
"""
|
"""
|
||||||
validate if user has access to requested resource
|
validate if user has access to requested resource
|
||||||
:param username: username
|
|
||||||
:param required: required access level
|
Args:
|
||||||
:param context: URI request path
|
username(str): username
|
||||||
:return: True in case if user is allowed to do this request and False otherwise
|
required(UserAccess): required access level
|
||||||
|
context(Optional[str]): URI request path
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True in case if user is allowed to do this request and False otherwise
|
||||||
"""
|
"""
|
||||||
user = self.get_user(username)
|
user = self.get_user(username)
|
||||||
return user is not None and user.verify_access(required)
|
return user is not None and user.verify_access(required)
|
||||||
|
@ -32,20 +32,24 @@ class OAuth(Mapping):
|
|||||||
"""
|
"""
|
||||||
OAuth user authorization.
|
OAuth user authorization.
|
||||||
It is required to create application first and put application credentials.
|
It is required to create application first and put application credentials.
|
||||||
:ivar client_id: application client id
|
|
||||||
:ivar client_secret: application client secret key
|
Attributes:
|
||||||
:ivar provider: provider class, should be one of aiohttp-client provided classes
|
client_id(str): application client id
|
||||||
:ivar redirect_uri: redirect URI registered in provider
|
client_secret(str): application client secret key
|
||||||
:ivar scopes: list of scopes required by the application
|
provider(aioauth_client.OAuth2Client): provider class, should be one of aiohttp-client provided classes
|
||||||
|
redirect_uri(str): redirect URI registered in provider
|
||||||
|
scopes(str): list of scopes required by the application
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, configuration: Configuration, database: SQLite,
|
def __init__(self, configuration: Configuration, database: SQLite,
|
||||||
provider: AuthSettings = AuthSettings.OAuth) -> None:
|
provider: AuthSettings = AuthSettings.OAuth) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
default constructor
|
||||||
:param configuration: configuration instance
|
|
||||||
:param database: database instance
|
Args:
|
||||||
:param provider: authorization type definition
|
configuration(Configuration): configuration instance
|
||||||
|
database(SQLite): database instance
|
||||||
|
provider(AuthSettings, optional): authorization type definition (Default value = AuthSettings.OAuth)
|
||||||
"""
|
"""
|
||||||
Mapping.__init__(self, configuration, database, provider)
|
Mapping.__init__(self, configuration, database, provider)
|
||||||
self.client_id = configuration.get("auth", "client_id")
|
self.client_id = configuration.get("auth", "client_id")
|
||||||
@ -60,7 +64,10 @@ class OAuth(Mapping):
|
|||||||
@property
|
@property
|
||||||
def auth_control(self) -> str:
|
def auth_control(self) -> str:
|
||||||
"""
|
"""
|
||||||
:return: login control as html code to insert
|
get authorization html control
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: login control as html code to insert
|
||||||
"""
|
"""
|
||||||
return """<a class="nav-link" href="/user-api/v1/login" title="login via OAuth2">login</a>"""
|
return """<a class="nav-link" href="/user-api/v1/login" title="login via OAuth2">login</a>"""
|
||||||
|
|
||||||
@ -68,8 +75,15 @@ class OAuth(Mapping):
|
|||||||
def get_provider(name: str) -> Type[aioauth_client.OAuth2Client]:
|
def get_provider(name: str) -> Type[aioauth_client.OAuth2Client]:
|
||||||
"""
|
"""
|
||||||
load OAuth2 provider by name
|
load OAuth2 provider by name
|
||||||
:param name: name of the provider. Must be valid class defined in aioauth-client library
|
|
||||||
:return: loaded provider type
|
Args:
|
||||||
|
name(str): name of the provider. Must be valid class defined in aioauth-client library
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Type[aioauth_client.OAuth2Client]: loaded provider type
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
InvalidOption: in case if invalid OAuth provider name supplied
|
||||||
"""
|
"""
|
||||||
provider: Type[aioauth_client.OAuth2Client] = getattr(aioauth_client, name)
|
provider: Type[aioauth_client.OAuth2Client] = getattr(aioauth_client, name)
|
||||||
try:
|
try:
|
||||||
@ -83,14 +97,18 @@ class OAuth(Mapping):
|
|||||||
def get_client(self) -> aioauth_client.OAuth2Client:
|
def get_client(self) -> aioauth_client.OAuth2Client:
|
||||||
"""
|
"""
|
||||||
load client from parameters
|
load client from parameters
|
||||||
:return: generated client according to current settings
|
|
||||||
|
Returns:
|
||||||
|
aioauth_client.OAuth2Client: generated client according to current settings
|
||||||
"""
|
"""
|
||||||
return self.provider(client_id=self.client_id, client_secret=self.client_secret)
|
return self.provider(client_id=self.client_id, client_secret=self.client_secret)
|
||||||
|
|
||||||
def get_oauth_url(self) -> str:
|
def get_oauth_url(self) -> str:
|
||||||
"""
|
"""
|
||||||
get authorization URI for the specified settings
|
get authorization URI for the specified settings
|
||||||
:return: authorization URI as a string
|
|
||||||
|
Returns:
|
||||||
|
str: authorization URI as a string
|
||||||
"""
|
"""
|
||||||
client = self.get_client()
|
client = self.get_client()
|
||||||
uri: str = client.get_authorize_url(scope=self.scopes, redirect_uri=self.redirect_uri)
|
uri: str = client.get_authorize_url(scope=self.scopes, redirect_uri=self.redirect_uri)
|
||||||
@ -99,8 +117,12 @@ class OAuth(Mapping):
|
|||||||
async def get_oauth_username(self, code: str) -> Optional[str]:
|
async def get_oauth_username(self, code: str) -> Optional[str]:
|
||||||
"""
|
"""
|
||||||
extract OAuth username from remote
|
extract OAuth username from remote
|
||||||
:param code: authorization code provided by external service
|
|
||||||
:return: username as is in OAuth provider
|
Args:
|
||||||
|
code(str): authorization code provided by external service
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Optional[str]: username as is in OAuth provider
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
client = self.get_client()
|
client = self.get_client()
|
||||||
|
@ -28,7 +28,9 @@ from ahriman.core.util import check_output
|
|||||||
class Sources:
|
class Sources:
|
||||||
"""
|
"""
|
||||||
helper to download package sources (PKGBUILD etc)
|
helper to download package sources (PKGBUILD etc)
|
||||||
:cvar logger: class logger
|
|
||||||
|
Attributes:
|
||||||
|
logger(logging.Logger): (class attribute) class logger
|
||||||
"""
|
"""
|
||||||
|
|
||||||
logger = logging.getLogger("build_details")
|
logger = logging.getLogger("build_details")
|
||||||
@ -40,8 +42,10 @@ class Sources:
|
|||||||
def add(sources_dir: Path, *pattern: str) -> None:
|
def add(sources_dir: Path, *pattern: str) -> None:
|
||||||
"""
|
"""
|
||||||
track found files via git
|
track found files via git
|
||||||
:param sources_dir: local path to git repository
|
|
||||||
:param pattern: glob patterns
|
Args:
|
||||||
|
sources_dir(Path): local path to git repository
|
||||||
|
*pattern(str): glob patterns
|
||||||
"""
|
"""
|
||||||
# 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] = []
|
||||||
@ -59,8 +63,12 @@ class Sources:
|
|||||||
def diff(sources_dir: Path) -> str:
|
def diff(sources_dir: Path) -> str:
|
||||||
"""
|
"""
|
||||||
generate diff from the current version and write it to the output file
|
generate diff from the current version and write it to the output file
|
||||||
:param sources_dir: local path to git repository
|
|
||||||
:return: patch as plain string
|
Args:
|
||||||
|
sources_dir(Path): local path to git repository
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: patch as plain string
|
||||||
"""
|
"""
|
||||||
return Sources._check_output("git", "diff", exception=None, cwd=sources_dir, logger=Sources.logger)
|
return Sources._check_output("git", "diff", exception=None, cwd=sources_dir, logger=Sources.logger)
|
||||||
|
|
||||||
@ -68,8 +76,10 @@ class Sources:
|
|||||||
def fetch(sources_dir: Path, remote: Optional[str]) -> None:
|
def fetch(sources_dir: Path, remote: Optional[str]) -> None:
|
||||||
"""
|
"""
|
||||||
either clone repository or update it to origin/`branch`
|
either clone repository or update it to origin/`branch`
|
||||||
:param sources_dir: local path to fetch
|
|
||||||
:param remote: remote target (from where to fetch)
|
Args:
|
||||||
|
sources_dir(Path): local path to fetch
|
||||||
|
remote(Optional[str]): remote target (from where to fetch)
|
||||||
"""
|
"""
|
||||||
# local directory exists and there is .git directory
|
# local directory exists and there is .git directory
|
||||||
is_initialized_git = (sources_dir / ".git").is_dir()
|
is_initialized_git = (sources_dir / ".git").is_dir()
|
||||||
@ -86,7 +96,8 @@ class Sources:
|
|||||||
Sources.logger.warning("%s is not initialized, but no remote provided", sources_dir)
|
Sources.logger.warning("%s is not initialized, but no remote provided", sources_dir)
|
||||||
else:
|
else:
|
||||||
Sources.logger.info("clone remote %s to %s", remote, sources_dir)
|
Sources.logger.info("clone remote %s to %s", remote, sources_dir)
|
||||||
Sources._check_output("git", "clone", remote, str(sources_dir), exception=None, logger=Sources.logger)
|
Sources._check_output("git", "clone", remote, str(sources_dir),
|
||||||
|
exception=None, cwd=sources_dir, logger=Sources.logger)
|
||||||
# and now force reset to our branch
|
# and now force reset to our branch
|
||||||
Sources._check_output("git", "checkout", "--force", Sources._branch,
|
Sources._check_output("git", "checkout", "--force", Sources._branch,
|
||||||
exception=None, cwd=sources_dir, logger=Sources.logger)
|
exception=None, cwd=sources_dir, logger=Sources.logger)
|
||||||
@ -97,8 +108,12 @@ class Sources:
|
|||||||
def has_remotes(sources_dir: Path) -> bool:
|
def has_remotes(sources_dir: Path) -> bool:
|
||||||
"""
|
"""
|
||||||
check if there are remotes for the repository
|
check if there are remotes for the repository
|
||||||
:param sources_dir: local path to git repository
|
|
||||||
:return: True in case if there is any remote and false otherwise
|
Args:
|
||||||
|
sources_dir(Path): local path to git repository
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True in case if there is any remote and false otherwise
|
||||||
"""
|
"""
|
||||||
remotes = Sources._check_output("git", "remote", exception=None, cwd=sources_dir, logger=Sources.logger)
|
remotes = Sources._check_output("git", "remote", exception=None, cwd=sources_dir, logger=Sources.logger)
|
||||||
return bool(remotes)
|
return bool(remotes)
|
||||||
@ -107,7 +122,9 @@ class Sources:
|
|||||||
def init(sources_dir: Path) -> None:
|
def init(sources_dir: Path) -> None:
|
||||||
"""
|
"""
|
||||||
create empty git repository at the specified path
|
create empty git repository at the specified path
|
||||||
:param sources_dir: local path to sources
|
|
||||||
|
Args:
|
||||||
|
sources_dir(Path): local path to sources
|
||||||
"""
|
"""
|
||||||
Sources._check_output("git", "init", "--initial-branch", Sources._branch,
|
Sources._check_output("git", "init", "--initial-branch", Sources._branch,
|
||||||
exception=None, cwd=sources_dir, logger=Sources.logger)
|
exception=None, cwd=sources_dir, logger=Sources.logger)
|
||||||
@ -116,9 +133,11 @@ class Sources:
|
|||||||
def load(sources_dir: Path, remote: str, patch: Optional[str]) -> None:
|
def load(sources_dir: Path, remote: str, patch: Optional[str]) -> None:
|
||||||
"""
|
"""
|
||||||
fetch sources from remote and apply patches
|
fetch sources from remote and apply patches
|
||||||
:param sources_dir: local path to fetch
|
|
||||||
:param remote: remote target (from where to fetch)
|
Args:
|
||||||
:param patch: optional patch to be applied
|
sources_dir(Path): local path to fetch
|
||||||
|
remote(str): remote target (from where to fetch)
|
||||||
|
patch(Optional[str]): optional patch to be applied
|
||||||
"""
|
"""
|
||||||
Sources.fetch(sources_dir, remote)
|
Sources.fetch(sources_dir, remote)
|
||||||
if patch is None:
|
if patch is None:
|
||||||
@ -130,8 +149,10 @@ class Sources:
|
|||||||
def patch_apply(sources_dir: Path, patch: str) -> None:
|
def patch_apply(sources_dir: Path, patch: str) -> None:
|
||||||
"""
|
"""
|
||||||
apply patches if any
|
apply patches if any
|
||||||
:param sources_dir: local path to directory with git sources
|
|
||||||
:param patch: patch to be applied
|
Args:
|
||||||
|
sources_dir(Path): local path to directory with git sources
|
||||||
|
patch(str): patch to be applied
|
||||||
"""
|
"""
|
||||||
# create patch
|
# create patch
|
||||||
Sources.logger.info("apply patch from database")
|
Sources.logger.info("apply patch from database")
|
||||||
@ -142,9 +163,13 @@ class Sources:
|
|||||||
def patch_create(sources_dir: Path, *pattern: str) -> str:
|
def patch_create(sources_dir: Path, *pattern: str) -> str:
|
||||||
"""
|
"""
|
||||||
create patch set for the specified local path
|
create patch set for the specified local path
|
||||||
:param sources_dir: local path to git repository
|
|
||||||
:param pattern: glob patterns
|
Args:
|
||||||
:return: patch as plain text
|
sources_dir(Path): local path to git repository
|
||||||
|
*pattern(str): glob patterns
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: patch as plain text
|
||||||
"""
|
"""
|
||||||
Sources.add(sources_dir, *pattern)
|
Sources.add(sources_dir, *pattern)
|
||||||
diff = Sources.diff(sources_dir)
|
diff = Sources.diff(sources_dir)
|
||||||
|
@ -35,11 +35,13 @@ from ahriman.models.repository_paths import RepositoryPaths
|
|||||||
class Task:
|
class Task:
|
||||||
"""
|
"""
|
||||||
base package build task
|
base package build task
|
||||||
:ivar build_logger: logger for build process
|
|
||||||
:ivar logger: class logger
|
Attributes:
|
||||||
:ivar package: package definitions
|
build_logger(logging.Logger): logger for build process
|
||||||
:ivar paths: repository paths instance
|
logger(logging.Logger): class logger
|
||||||
:ivar uid: uid of the repository owner user
|
package(Package): package definitions
|
||||||
|
paths(RepositoryPaths): repository paths instance
|
||||||
|
uid(int): uid of the repository owner user
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_check_output = check_output
|
_check_output = check_output
|
||||||
@ -47,9 +49,11 @@ class Task:
|
|||||||
def __init__(self, package: Package, configuration: Configuration, paths: RepositoryPaths) -> None:
|
def __init__(self, package: Package, configuration: Configuration, paths: RepositoryPaths) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
default constructor
|
||||||
:param package: package definitions
|
|
||||||
:param configuration: configuration instance
|
Args:
|
||||||
:param paths: repository paths instance
|
package(Package): package definitions
|
||||||
|
configuration(Configuration): configuration instance
|
||||||
|
paths(RepositoryPaths): repository paths instance
|
||||||
"""
|
"""
|
||||||
self.logger = logging.getLogger("root")
|
self.logger = logging.getLogger("root")
|
||||||
self.build_logger = logging.getLogger("build_details")
|
self.build_logger = logging.getLogger("build_details")
|
||||||
@ -65,8 +69,12 @@ class Task:
|
|||||||
def build(self, sources_path: Path) -> List[Path]:
|
def build(self, sources_path: Path) -> List[Path]:
|
||||||
"""
|
"""
|
||||||
run package build
|
run package build
|
||||||
:param sources_path: path to where sources are
|
|
||||||
:return: paths of produced packages
|
Args:
|
||||||
|
sources_path(Path): path to where sources are
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[Path]: paths of produced packages
|
||||||
"""
|
"""
|
||||||
command = [self.build_command, "-r", str(self.paths.chroot)]
|
command = [self.build_command, "-r", str(self.paths.chroot)]
|
||||||
command.extend(self.archbuild_flags)
|
command.extend(self.archbuild_flags)
|
||||||
@ -91,8 +99,10 @@ class Task:
|
|||||||
def init(self, path: Path, database: SQLite) -> None:
|
def init(self, path: Path, database: SQLite) -> None:
|
||||||
"""
|
"""
|
||||||
fetch package from git
|
fetch package from git
|
||||||
:param path: local path to fetch
|
|
||||||
:param database: database instance
|
Args:
|
||||||
|
path(Path): local path to fetch
|
||||||
|
database(SQLite): database instance
|
||||||
"""
|
"""
|
||||||
if self.paths.cache_for(self.package.base).is_dir():
|
if self.paths.cache_for(self.package.base).is_dir():
|
||||||
# no need to clone whole repository, just copy from cache first
|
# no need to clone whole repository, just copy from cache first
|
||||||
|
@ -34,12 +34,15 @@ from ahriman.models.repository_paths import RepositoryPaths
|
|||||||
class Configuration(configparser.RawConfigParser):
|
class Configuration(configparser.RawConfigParser):
|
||||||
"""
|
"""
|
||||||
extension for built-in configuration parser
|
extension for built-in configuration parser
|
||||||
:ivar architecture: repository architecture
|
|
||||||
:ivar path: path to root configuration file
|
Attributes:
|
||||||
:cvar ARCHITECTURE_SPECIFIC_SECTIONS: known sections which can be architecture specific (required by dump)
|
ARCHITECTURE_SPECIFIC_SECTIONS(List[str]): (class attribute) known sections which can be architecture specific.
|
||||||
:cvar DEFAULT_LOG_FORMAT: default log format (in case of fallback)
|
Required by dump and merging functions
|
||||||
:cvar DEFAULT_LOG_LEVEL: default log level (in case of fallback)
|
DEFAULT_LOG_FORMAT(str): (class attribute) default log format (in case of fallback)
|
||||||
:cvar SYSTEM_CONFIGURATION_PATH: default system configuration path distributed by package
|
DEFAULT_LOG_LEVEL(int): (class attribute) default log level (in case of fallback)
|
||||||
|
SYSTEM_CONFIGURATION_PATH(Path): (class attribute) default system configuration path distributed by package
|
||||||
|
architecture(Optional[str]): repository architecture
|
||||||
|
path(Optional[Path]): path to root configuration file
|
||||||
"""
|
"""
|
||||||
|
|
||||||
DEFAULT_LOG_FORMAT = "[%(levelname)s %(asctime)s] [%(filename)s:%(lineno)d %(funcName)s]: %(message)s"
|
DEFAULT_LOG_FORMAT = "[%(levelname)s %(asctime)s] [%(filename)s:%(lineno)d %(funcName)s]: %(message)s"
|
||||||
@ -62,21 +65,30 @@ class Configuration(configparser.RawConfigParser):
|
|||||||
@property
|
@property
|
||||||
def include(self) -> Path:
|
def include(self) -> Path:
|
||||||
"""
|
"""
|
||||||
:return: path to directory with configuration includes
|
get full path to include directory
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Path: path to directory with configuration includes
|
||||||
"""
|
"""
|
||||||
return self.getpath("settings", "include")
|
return self.getpath("settings", "include")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def logging_path(self) -> Path:
|
def logging_path(self) -> Path:
|
||||||
"""
|
"""
|
||||||
:return: path to logging configuration
|
get full path to logging configuration
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Path: path to logging configuration
|
||||||
"""
|
"""
|
||||||
return self.getpath("settings", "logging")
|
return self.getpath("settings", "logging")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def repository_paths(self) -> RepositoryPaths:
|
def repository_paths(self) -> RepositoryPaths:
|
||||||
"""
|
"""
|
||||||
:return: repository paths instance
|
construct RepositoryPaths instance based on the configuration
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
RepositoryPaths: repository paths instance
|
||||||
"""
|
"""
|
||||||
_, architecture = self.check_loaded()
|
_, architecture = self.check_loaded()
|
||||||
return RepositoryPaths(self.getpath("repository", "root"), architecture)
|
return RepositoryPaths(self.getpath("repository", "root"), architecture)
|
||||||
@ -85,10 +97,14 @@ class Configuration(configparser.RawConfigParser):
|
|||||||
def from_path(cls: Type[Configuration], path: Path, architecture: str, quiet: bool) -> Configuration:
|
def from_path(cls: Type[Configuration], path: Path, architecture: str, quiet: bool) -> Configuration:
|
||||||
"""
|
"""
|
||||||
constructor with full object initialization
|
constructor with full object initialization
|
||||||
:param path: path to root configuration file
|
|
||||||
:param architecture: repository architecture
|
Args:
|
||||||
:param quiet: force disable any log messages
|
path(Path): path to root configuration file
|
||||||
:return: configuration instance
|
architecture(str): repository architecture
|
||||||
|
quiet(bool): force disable any log messages
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Configuration: configuration instance
|
||||||
"""
|
"""
|
||||||
config = cls()
|
config = cls()
|
||||||
config.load(path)
|
config.load(path)
|
||||||
@ -100,8 +116,15 @@ class Configuration(configparser.RawConfigParser):
|
|||||||
def __convert_list(value: str) -> List[str]:
|
def __convert_list(value: str) -> List[str]:
|
||||||
"""
|
"""
|
||||||
convert string value to list of strings
|
convert string value to list of strings
|
||||||
:param value: string configuration value
|
|
||||||
:return: list of string from the parsed string
|
Args:
|
||||||
|
value(str): string configuration value
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[str]: list of string from the parsed string
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: in case if option value contains unclosed quotes
|
||||||
"""
|
"""
|
||||||
def generator() -> Generator[str, None, None]:
|
def generator() -> Generator[str, None, None]:
|
||||||
quote_mark = None
|
quote_mark = None
|
||||||
@ -111,7 +134,7 @@ class Configuration(configparser.RawConfigParser):
|
|||||||
quote_mark = char
|
quote_mark = char
|
||||||
elif char == quote_mark: # quoted part ended, reset quotation
|
elif char == quote_mark: # quoted part ended, reset quotation
|
||||||
quote_mark = None
|
quote_mark = None
|
||||||
elif char == " " and quote_mark is None: # found space outside of the quotation, yield the word
|
elif char == " " and quote_mark is None: # found space outside the quotation, yield the word
|
||||||
yield word
|
yield word
|
||||||
word = ""
|
word = ""
|
||||||
else: # append character to the buffer
|
else: # append character to the buffer
|
||||||
@ -126,17 +149,25 @@ class Configuration(configparser.RawConfigParser):
|
|||||||
def section_name(section: str, suffix: str) -> str:
|
def section_name(section: str, suffix: str) -> str:
|
||||||
"""
|
"""
|
||||||
generate section name for sections which depends on context
|
generate section name for sections which depends on context
|
||||||
:param section: section name
|
|
||||||
:param suffix: session suffix, e.g. repository architecture
|
Args:
|
||||||
:return: correct section name for repository specific section
|
section(str): section name
|
||||||
|
suffix(str): session suffix, e.g. repository architecture
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: correct section name for repository specific section
|
||||||
"""
|
"""
|
||||||
return f"{section}:{suffix}"
|
return f"{section}:{suffix}"
|
||||||
|
|
||||||
def __convert_path(self, value: str) -> Path:
|
def __convert_path(self, value: str) -> Path:
|
||||||
"""
|
"""
|
||||||
convert string value to path object
|
convert string value to path object
|
||||||
:param value: string configuration value
|
|
||||||
:return: path object which represents the configuration value
|
Args:
|
||||||
|
value(str): string configuration value
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Path: path object which represents the configuration value
|
||||||
"""
|
"""
|
||||||
path = Path(value)
|
path = Path(value)
|
||||||
if self.path is None or path.is_absolute():
|
if self.path is None or path.is_absolute():
|
||||||
@ -146,7 +177,12 @@ class Configuration(configparser.RawConfigParser):
|
|||||||
def check_loaded(self) -> Tuple[Path, str]:
|
def check_loaded(self) -> Tuple[Path, str]:
|
||||||
"""
|
"""
|
||||||
check if service was actually loaded
|
check if service was actually loaded
|
||||||
:return: configuration root path and architecture if loaded
|
|
||||||
|
Returns:
|
||||||
|
Tuple[Path, str]: configuration root path and architecture if loaded
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
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 InitializeException("Configuration path and/or architecture are not set")
|
||||||
@ -155,7 +191,9 @@ class Configuration(configparser.RawConfigParser):
|
|||||||
def dump(self) -> Dict[str, Dict[str, str]]:
|
def dump(self) -> Dict[str, Dict[str, str]]:
|
||||||
"""
|
"""
|
||||||
dump configuration to dictionary
|
dump configuration to dictionary
|
||||||
:return: configuration dump for specific architecture
|
|
||||||
|
Returns:
|
||||||
|
Dict[str, Dict[str, str]]: configuration dump for specific architecture
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
section: dict(self[section])
|
section: dict(self[section])
|
||||||
@ -172,9 +210,16 @@ class Configuration(configparser.RawConfigParser):
|
|||||||
"""
|
"""
|
||||||
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, but it has different argument list
|
Despite the fact that it has same semantics as other get* methods, but it has different argument list
|
||||||
:param section: section name
|
|
||||||
:param architecture: repository architecture
|
Args:
|
||||||
:return: section name and found type name
|
section(str): section name
|
||||||
|
architecture(str): repository architecture
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tuple[str, str]: section name and found type name
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
configparser.NoSectionError: in case if no section found
|
||||||
"""
|
"""
|
||||||
group_type = self.get(section, "type", fallback=None) # new-style logic
|
group_type = self.get(section, "type", fallback=None) # new-style logic
|
||||||
if group_type is not None:
|
if group_type is not None:
|
||||||
@ -191,7 +236,9 @@ class Configuration(configparser.RawConfigParser):
|
|||||||
def load(self, path: Path) -> None:
|
def load(self, path: Path) -> None:
|
||||||
"""
|
"""
|
||||||
fully load configuration
|
fully load configuration
|
||||||
:param path: path to root configuration file
|
|
||||||
|
Args:
|
||||||
|
path(Path): path to root configuration file
|
||||||
"""
|
"""
|
||||||
if not path.is_file(): # fallback to the system file
|
if not path.is_file(): # fallback to the system file
|
||||||
path = self.SYSTEM_CONFIGURATION_PATH
|
path = self.SYSTEM_CONFIGURATION_PATH
|
||||||
@ -214,7 +261,9 @@ class Configuration(configparser.RawConfigParser):
|
|||||||
def load_logging(self, quiet: bool) -> None:
|
def load_logging(self, quiet: bool) -> None:
|
||||||
"""
|
"""
|
||||||
setup logging settings from configuration
|
setup logging settings from configuration
|
||||||
:param quiet: force disable any log messages
|
|
||||||
|
Args:
|
||||||
|
quiet(bool): force disable any log messages
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
path = self.logging_path
|
path = self.logging_path
|
||||||
@ -229,7 +278,9 @@ class Configuration(configparser.RawConfigParser):
|
|||||||
def merge_sections(self, architecture: str) -> None:
|
def merge_sections(self, architecture: str) -> None:
|
||||||
"""
|
"""
|
||||||
merge architecture specific sections into main configuration
|
merge architecture specific sections into main configuration
|
||||||
:param architecture: repository architecture
|
|
||||||
|
Args:
|
||||||
|
architecture(str): repository architecture
|
||||||
"""
|
"""
|
||||||
self.architecture = architecture
|
self.architecture = architecture
|
||||||
for section in self.ARCHITECTURE_SPECIFIC_SECTIONS:
|
for section in self.ARCHITECTURE_SPECIFIC_SECTIONS:
|
||||||
@ -260,9 +311,11 @@ class Configuration(configparser.RawConfigParser):
|
|||||||
def set_option(self, section: str, option: str, value: Optional[str]) -> None:
|
def set_option(self, section: str, option: str, value: Optional[str]) -> None:
|
||||||
"""
|
"""
|
||||||
set option. Unlike default `configparser.RawConfigParser.set` it also creates section if it does not exist
|
set option. Unlike default `configparser.RawConfigParser.set` it also creates section if it does not exist
|
||||||
:param section: section name
|
|
||||||
:param option: option name
|
Args:
|
||||||
:param value: option value as string in parsable format
|
section(str): section name
|
||||||
|
option(str): option name
|
||||||
|
value(Optional[str]): option value as string in parsable format
|
||||||
"""
|
"""
|
||||||
if not self.has_section(section):
|
if not self.has_section(section):
|
||||||
self.add_section(section)
|
self.add_section(section)
|
||||||
|
@ -20,24 +20,26 @@
|
|||||||
from sqlite3 import Connection
|
from sqlite3 import Connection
|
||||||
|
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
|
from ahriman.core.database.data.package_statuses import migrate_package_statuses
|
||||||
from ahriman.core.database.data.patches import migrate_patches
|
from ahriman.core.database.data.patches import migrate_patches
|
||||||
from ahriman.core.database.data.users import migrate_users_data
|
from ahriman.core.database.data.users import migrate_users_data
|
||||||
from ahriman.core.database.data.package_statuses import migrate_package_statuses
|
|
||||||
from ahriman.models.migration_result import MigrationResult
|
from ahriman.models.migration_result import MigrationResult
|
||||||
from ahriman.models.repository_paths import RepositoryPaths
|
|
||||||
|
|
||||||
|
|
||||||
def migrate_data(result: MigrationResult, connection: Connection,
|
def migrate_data(
|
||||||
configuration: Configuration, paths: RepositoryPaths) -> None:
|
result: MigrationResult, connection: Connection, configuration: Configuration) -> None:
|
||||||
"""
|
"""
|
||||||
perform data migration
|
perform data migration
|
||||||
:param result: result of the schema migration
|
|
||||||
:param connection: database connection
|
Args:
|
||||||
:param configuration: configuration instance
|
result(MigrationResult): result of the schema migration
|
||||||
:param paths: repository paths instance
|
connection(Connection): database connection
|
||||||
|
configuration(Configuration): configuration instance
|
||||||
"""
|
"""
|
||||||
# initial data migration
|
# initial data migration
|
||||||
if result.old_version == 0:
|
repository_paths = configuration.repository_paths
|
||||||
migrate_package_statuses(connection, paths)
|
|
||||||
|
if result.old_version <= 0:
|
||||||
|
migrate_package_statuses(connection, repository_paths)
|
||||||
|
migrate_patches(connection, repository_paths)
|
||||||
migrate_users_data(connection, configuration)
|
migrate_users_data(connection, configuration)
|
||||||
migrate_patches(connection, paths)
|
|
||||||
|
@ -29,8 +29,10 @@ from ahriman.models.repository_paths import RepositoryPaths
|
|||||||
def migrate_package_statuses(connection: Connection, paths: RepositoryPaths) -> None:
|
def migrate_package_statuses(connection: Connection, paths: RepositoryPaths) -> None:
|
||||||
"""
|
"""
|
||||||
perform migration for package statuses
|
perform migration for package statuses
|
||||||
:param connection: database connection
|
|
||||||
:param paths: repository paths instance
|
Args:
|
||||||
|
connection(Connection): database connection
|
||||||
|
paths(RepositoryPaths): repository paths instance
|
||||||
"""
|
"""
|
||||||
def insert_base(metadata: Package, last_status: BuildStatus) -> None:
|
def insert_base(metadata: Package, last_status: BuildStatus) -> None:
|
||||||
connection.execute(
|
connection.execute(
|
||||||
@ -75,6 +77,3 @@ def migrate_package_statuses(connection: Connection, paths: RepositoryPaths) ->
|
|||||||
status = BuildStatus.from_json(item["status"])
|
status = BuildStatus.from_json(item["status"])
|
||||||
insert_base(package, status)
|
insert_base(package, status)
|
||||||
insert_packages(package)
|
insert_packages(package)
|
||||||
|
|
||||||
connection.commit()
|
|
||||||
cache_path.unlink()
|
|
||||||
|
@ -25,8 +25,10 @@ from ahriman.models.repository_paths import RepositoryPaths
|
|||||||
def migrate_patches(connection: Connection, paths: RepositoryPaths) -> None:
|
def migrate_patches(connection: Connection, paths: RepositoryPaths) -> None:
|
||||||
"""
|
"""
|
||||||
perform migration for patches
|
perform migration for patches
|
||||||
:param connection: database connection
|
|
||||||
:param paths: repository paths instance
|
Args:
|
||||||
|
connection(Connection): database connection
|
||||||
|
paths(RepositoryPaths): repository paths instance
|
||||||
"""
|
"""
|
||||||
root = paths.root / "patches"
|
root = paths.root / "patches"
|
||||||
if not root.is_dir():
|
if not root.is_dir():
|
||||||
@ -40,5 +42,3 @@ def migrate_patches(connection: Connection, paths: RepositoryPaths) -> None:
|
|||||||
connection.execute(
|
connection.execute(
|
||||||
"""insert into patches (package_base, patch) values (:package_base, :patch)""",
|
"""insert into patches (package_base, patch) values (:package_base, :patch)""",
|
||||||
{"package_base": package.name, "patch": content})
|
{"package_base": package.name, "patch": content})
|
||||||
|
|
||||||
connection.commit()
|
|
||||||
|
@ -25,16 +25,16 @@ from ahriman.core.configuration import Configuration
|
|||||||
def migrate_users_data(connection: Connection, configuration: Configuration) -> None:
|
def migrate_users_data(connection: Connection, configuration: Configuration) -> None:
|
||||||
"""
|
"""
|
||||||
perform migration for users
|
perform migration for users
|
||||||
:param connection: database connection
|
|
||||||
:param configuration: configuration instance
|
Args:
|
||||||
|
connection(Connection): database connection
|
||||||
|
configuration(Configuration): configuration instance
|
||||||
"""
|
"""
|
||||||
for section in configuration.sections():
|
for section in configuration.sections():
|
||||||
for option, value in configuration[section].items():
|
for option, value in configuration[section].items():
|
||||||
if not section.startswith("auth:"):
|
if not section.startswith("auth:"):
|
||||||
continue
|
continue
|
||||||
permission = section[5:]
|
access = section[5:]
|
||||||
connection.execute(
|
connection.execute(
|
||||||
"""insert into users (username, permission, password) values (:username, :permission, :password)""",
|
"""insert into users (username, access, password) values (:username, :access, :password)""",
|
||||||
{"username": option.lower(), "permission": permission, "password": value})
|
{"username": option.lower(), "access": access, "password": value})
|
||||||
|
|
||||||
connection.commit()
|
|
||||||
|
@ -27,6 +27,8 @@ from pkgutil import iter_modules
|
|||||||
from sqlite3 import Connection
|
from sqlite3 import Connection
|
||||||
from typing import List, Type
|
from typing import List, Type
|
||||||
|
|
||||||
|
from ahriman.core.configuration import Configuration
|
||||||
|
from ahriman.core.database.data import migrate_data
|
||||||
from ahriman.models.migration import Migration
|
from ahriman.models.migration import Migration
|
||||||
from ahriman.models.migration_result import MigrationResult
|
from ahriman.models.migration_result import MigrationResult
|
||||||
|
|
||||||
@ -35,32 +37,46 @@ class Migrations:
|
|||||||
"""
|
"""
|
||||||
simple migration wrapper for the sqlite
|
simple migration wrapper for the sqlite
|
||||||
idea comes from https://www.ash.dev/blog/simple-migration-system-in-sqlite/
|
idea comes from https://www.ash.dev/blog/simple-migration-system-in-sqlite/
|
||||||
:ivar connection: database connection
|
|
||||||
:ivar logger: class logger
|
Attributes:
|
||||||
|
configuration(Configuration): configuration instance
|
||||||
|
connection(Connection): database connection
|
||||||
|
logger(logging.Logger): class logger
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, connection: Connection) -> None:
|
def __init__(self, connection: Connection, configuration: Configuration) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
default constructor
|
||||||
:param connection: database connection
|
|
||||||
|
Args:
|
||||||
|
connection(Connection): database connection
|
||||||
|
configuration(Configuration): configuration instance
|
||||||
"""
|
"""
|
||||||
self.connection = connection
|
self.connection = connection
|
||||||
|
self.configuration = configuration
|
||||||
self.logger = logging.getLogger("database")
|
self.logger = logging.getLogger("database")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def migrate(cls: Type[Migrations], connection: Connection) -> MigrationResult:
|
def migrate(cls: Type[Migrations], connection: Connection, configuration: Configuration) -> MigrationResult:
|
||||||
"""
|
"""
|
||||||
perform migrations implicitly
|
perform migrations implicitly
|
||||||
:param connection: database connection
|
|
||||||
:return: current schema version
|
Args:
|
||||||
|
connection(Connection): database connection
|
||||||
|
configuration(Configuration): configuration instance
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
MigrationResult: current schema version
|
||||||
"""
|
"""
|
||||||
return cls(connection).run()
|
return cls(connection, configuration).run()
|
||||||
|
|
||||||
def migrations(self) -> List[Migration]:
|
def migrations(self) -> List[Migration]:
|
||||||
"""
|
"""
|
||||||
extract all migrations from the current package
|
extract all migrations from the current package
|
||||||
idea comes from https://julienharbulot.com/python-dynamical-import.html
|
idea comes from https://julienharbulot.com/python-dynamical-import.html
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[Migration]: list of found migrations
|
||||||
"""
|
"""
|
||||||
migrations: List[Migration] = []
|
migrations: List[Migration] = []
|
||||||
package_dir = Path(__file__).resolve().parent
|
package_dir = Path(__file__).resolve().parent
|
||||||
@ -77,7 +93,9 @@ class Migrations:
|
|||||||
def run(self) -> MigrationResult:
|
def run(self) -> MigrationResult:
|
||||||
"""
|
"""
|
||||||
perform migrations
|
perform migrations
|
||||||
:return: current schema version
|
|
||||||
|
Return:
|
||||||
|
MigrationResult: current schema version
|
||||||
"""
|
"""
|
||||||
migrations = self.migrations()
|
migrations = self.migrations()
|
||||||
current_version = self.user_version()
|
current_version = self.user_version()
|
||||||
@ -100,6 +118,8 @@ class Migrations:
|
|||||||
cursor.execute(statement)
|
cursor.execute(statement)
|
||||||
self.logger.info("migration %s at index %s has been applied", migration.name, migration.index)
|
self.logger.info("migration %s at index %s has been applied", migration.name, migration.index)
|
||||||
|
|
||||||
|
migrate_data(result, self.connection, self.configuration)
|
||||||
|
|
||||||
cursor.execute(f"pragma user_version = {expected_version}") # no support for ? placeholders
|
cursor.execute(f"pragma user_version = {expected_version}") # no support for ? placeholders
|
||||||
except Exception:
|
except Exception:
|
||||||
self.logger.exception("migration failed with exception")
|
self.logger.exception("migration failed with exception")
|
||||||
@ -118,7 +138,9 @@ class Migrations:
|
|||||||
def user_version(self) -> int:
|
def user_version(self) -> int:
|
||||||
"""
|
"""
|
||||||
get schema version from sqlite database
|
get schema version from sqlite database
|
||||||
;return: current schema version
|
|
||||||
|
Returns:
|
||||||
|
int: current schema version
|
||||||
"""
|
"""
|
||||||
cursor = self.connection.execute("pragma user_version")
|
cursor = self.connection.execute("pragma user_version")
|
||||||
current_version: int = cursor.fetchone()["user_version"]
|
current_version: int = cursor.fetchone()["user_version"]
|
||||||
|
@ -17,8 +17,6 @@
|
|||||||
# 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 __future__ import annotations
|
|
||||||
|
|
||||||
from sqlite3 import Connection
|
from sqlite3 import Connection
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
@ -35,17 +33,25 @@ class AuthOperations(Operations):
|
|||||||
def user_get(self, username: str) -> Optional[User]:
|
def user_get(self, username: str) -> Optional[User]:
|
||||||
"""
|
"""
|
||||||
get user by username
|
get user by username
|
||||||
:param username: username
|
|
||||||
:return: user if it was found
|
Args:
|
||||||
|
username(str): username
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Optional[User]: user if it was found
|
||||||
"""
|
"""
|
||||||
return next(iter(self.user_list(username, None)), None)
|
return next(iter(self.user_list(username, None)), None)
|
||||||
|
|
||||||
def user_list(self, username: Optional[str], access: Optional[UserAccess]) -> List[User]:
|
def user_list(self, username: Optional[str], access: Optional[UserAccess]) -> List[User]:
|
||||||
"""
|
"""
|
||||||
get users by filter
|
get users by filter
|
||||||
:param username: optional filter by username
|
|
||||||
:param access: optional filter by role
|
Args:
|
||||||
:return: list of users who match criteria
|
username(Optional[str]): optional filter by username
|
||||||
|
access(Optional[UserAccess]): optional filter by role
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[User]: list of users who match criteria
|
||||||
"""
|
"""
|
||||||
username_filter = username.lower() if username is not None else username
|
username_filter = username.lower() if username is not None else username
|
||||||
access_filter = access.value if access is not None else access
|
access_filter = access.value if access is not None else access
|
||||||
@ -66,7 +72,9 @@ class AuthOperations(Operations):
|
|||||||
def user_remove(self, username: str) -> None:
|
def user_remove(self, username: str) -> None:
|
||||||
"""
|
"""
|
||||||
remove user from storage
|
remove user from storage
|
||||||
:param username: username
|
|
||||||
|
Args:
|
||||||
|
username(str): username
|
||||||
"""
|
"""
|
||||||
def run(connection: Connection) -> None:
|
def run(connection: Connection) -> None:
|
||||||
connection.execute("""delete from users where username = :username""", {"username": username.lower()})
|
connection.execute("""delete from users where username = :username""", {"username": username.lower()})
|
||||||
@ -75,8 +83,10 @@ class AuthOperations(Operations):
|
|||||||
|
|
||||||
def user_update(self, user: User) -> None:
|
def user_update(self, user: User) -> None:
|
||||||
"""
|
"""
|
||||||
get user by username
|
update user by username
|
||||||
:param user: user descriptor
|
|
||||||
|
Args:
|
||||||
|
user(User): user descriptor
|
||||||
"""
|
"""
|
||||||
def run(connection: Connection) -> None:
|
def run(connection: Connection) -> None:
|
||||||
connection.execute(
|
connection.execute(
|
||||||
|
@ -32,7 +32,9 @@ class BuildOperations(Operations):
|
|||||||
def build_queue_clear(self, package_base: Optional[str]) -> None:
|
def build_queue_clear(self, package_base: Optional[str]) -> None:
|
||||||
"""
|
"""
|
||||||
remove packages from build queue
|
remove packages from build queue
|
||||||
:param package_base: optional filter by package base
|
|
||||||
|
Args:
|
||||||
|
package_base(Optional[str]): optional filter by package base
|
||||||
"""
|
"""
|
||||||
def run(connection: Connection) -> None:
|
def run(connection: Connection) -> None:
|
||||||
connection.execute(
|
connection.execute(
|
||||||
@ -47,7 +49,9 @@ class BuildOperations(Operations):
|
|||||||
def build_queue_get(self) -> List[Package]:
|
def build_queue_get(self) -> List[Package]:
|
||||||
"""
|
"""
|
||||||
retrieve packages from build queue
|
retrieve packages from build queue
|
||||||
:return: list of packages to be built
|
|
||||||
|
Return:
|
||||||
|
List[Package]: list of packages to be built
|
||||||
"""
|
"""
|
||||||
def run(connection: Connection) -> List[Package]:
|
def run(connection: Connection) -> List[Package]:
|
||||||
return [
|
return [
|
||||||
@ -60,7 +64,9 @@ class BuildOperations(Operations):
|
|||||||
def build_queue_insert(self, package: Package) -> None:
|
def build_queue_insert(self, package: Package) -> None:
|
||||||
"""
|
"""
|
||||||
insert packages to build queue
|
insert packages to build queue
|
||||||
:param package: package to be inserted
|
|
||||||
|
Args:
|
||||||
|
package(Package): package to be inserted
|
||||||
"""
|
"""
|
||||||
def run(connection: Connection) -> None:
|
def run(connection: Connection) -> None:
|
||||||
connection.execute(
|
connection.execute(
|
||||||
|
@ -31,14 +31,18 @@ T = TypeVar("T")
|
|||||||
class Operations:
|
class Operations:
|
||||||
"""
|
"""
|
||||||
base operation class
|
base operation class
|
||||||
:ivar logger: class logger
|
|
||||||
:ivar path: path to the database file
|
Attributes:
|
||||||
|
logger(logging.Logger): class logger
|
||||||
|
path(Path): path to the database file
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, path: Path) -> None:
|
def __init__(self, path: Path) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
default constructor
|
||||||
:param path: path to the database file
|
|
||||||
|
Args:
|
||||||
|
path(Path): path to the database file
|
||||||
"""
|
"""
|
||||||
self.path = path
|
self.path = path
|
||||||
self.logger = logging.getLogger("database")
|
self.logger = logging.getLogger("database")
|
||||||
@ -47,9 +51,13 @@ class Operations:
|
|||||||
def factory(cursor: Cursor, row: Tuple[Any, ...]) -> Dict[str, Any]:
|
def factory(cursor: Cursor, row: Tuple[Any, ...]) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
dictionary factory based on official documentation
|
dictionary factory based on official documentation
|
||||||
:param cursor: cursor descriptor
|
|
||||||
:param row: fetched row
|
Args:
|
||||||
:return: row converted to dictionary
|
cursor(Cursor): cursor descriptor
|
||||||
|
row(Tuple[Any, ...]): fetched row
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict[str, Any]: row converted to dictionary
|
||||||
"""
|
"""
|
||||||
result = {}
|
result = {}
|
||||||
for index, column in enumerate(cursor.description):
|
for index, column in enumerate(cursor.description):
|
||||||
@ -59,9 +67,13 @@ class Operations:
|
|||||||
def with_connection(self, query: Callable[[Connection], T], commit: bool = False) -> T:
|
def with_connection(self, query: Callable[[Connection], T], commit: bool = False) -> T:
|
||||||
"""
|
"""
|
||||||
perform operation in connection
|
perform operation in connection
|
||||||
:param query: function to be called with connection
|
|
||||||
:param commit: if True commit() will be called on success
|
Args:
|
||||||
:return: result of the `query` call
|
query(Callable[[Connection], T]): function to be called with connection
|
||||||
|
commit(bool, optional): if True commit() will be called on success (Default value = False)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
T: result of the `query` call
|
||||||
"""
|
"""
|
||||||
with sqlite3.connect(self.path, detect_types=sqlite3.PARSE_DECLTYPES) as connection:
|
with sqlite3.connect(self.path, detect_types=sqlite3.PARSE_DECLTYPES) as connection:
|
||||||
connection.row_factory = self.factory
|
connection.row_factory = self.factory
|
||||||
|
@ -35,8 +35,10 @@ class PackageOperations(Operations):
|
|||||||
def _package_remove_package_base(connection: Connection, package_base: str) -> None:
|
def _package_remove_package_base(connection: Connection, package_base: str) -> None:
|
||||||
"""
|
"""
|
||||||
remove package base information
|
remove package base information
|
||||||
:param connection: database connection
|
|
||||||
:param package_base: package base name
|
Args:
|
||||||
|
connection(Connection): database connection
|
||||||
|
package_base(str): package base name
|
||||||
"""
|
"""
|
||||||
connection.execute("""delete from package_statuses where package_base = :package_base""",
|
connection.execute("""delete from package_statuses where package_base = :package_base""",
|
||||||
{"package_base": package_base})
|
{"package_base": package_base})
|
||||||
@ -47,9 +49,11 @@ class PackageOperations(Operations):
|
|||||||
def _package_remove_packages(connection: Connection, package_base: str, current_packages: Iterable[str]) -> None:
|
def _package_remove_packages(connection: Connection, package_base: str, current_packages: Iterable[str]) -> None:
|
||||||
"""
|
"""
|
||||||
remove packages belong to the package base
|
remove packages belong to the package base
|
||||||
:param connection: database connection
|
|
||||||
:param package_base: package base name
|
Args:
|
||||||
:param current_packages: current packages list which has to be left in database
|
connection(Connection): database connection
|
||||||
|
package_base(str): package base name
|
||||||
|
current_packages(Iterable[str]): current packages list which has to be left in database
|
||||||
"""
|
"""
|
||||||
packages = [
|
packages = [
|
||||||
package
|
package
|
||||||
@ -63,8 +67,10 @@ class PackageOperations(Operations):
|
|||||||
def _package_update_insert_base(connection: Connection, package: Package) -> None:
|
def _package_update_insert_base(connection: Connection, package: Package) -> None:
|
||||||
"""
|
"""
|
||||||
insert base package into table
|
insert base package into table
|
||||||
:param connection: database connection
|
|
||||||
:param package: package properties
|
Args:
|
||||||
|
connection(Connection): database connection
|
||||||
|
package(Package): package properties
|
||||||
"""
|
"""
|
||||||
connection.execute(
|
connection.execute(
|
||||||
"""
|
"""
|
||||||
@ -81,8 +87,10 @@ class PackageOperations(Operations):
|
|||||||
def _package_update_insert_packages(connection: Connection, package: Package) -> None:
|
def _package_update_insert_packages(connection: Connection, package: Package) -> None:
|
||||||
"""
|
"""
|
||||||
insert packages into table
|
insert packages into table
|
||||||
:param connection: database connection
|
|
||||||
:param package: package properties
|
Args:
|
||||||
|
connection(Connection): database connection
|
||||||
|
package(Package): package properties
|
||||||
"""
|
"""
|
||||||
package_list = []
|
package_list = []
|
||||||
for name, description in package.packages.items():
|
for name, description in package.packages.items():
|
||||||
@ -108,9 +116,11 @@ class PackageOperations(Operations):
|
|||||||
def _package_update_insert_status(connection: Connection, package_base: str, status: BuildStatus) -> None:
|
def _package_update_insert_status(connection: Connection, package_base: str, status: BuildStatus) -> None:
|
||||||
"""
|
"""
|
||||||
insert base package status into table
|
insert base package status into table
|
||||||
:param connection: database connection
|
|
||||||
:param package_base: package base name
|
Args:
|
||||||
:param status: new build status
|
connection(Connection): database connection
|
||||||
|
package_base(str): package base name
|
||||||
|
status(BuildStatus): new build status
|
||||||
"""
|
"""
|
||||||
connection.execute(
|
connection.execute(
|
||||||
"""
|
"""
|
||||||
@ -126,8 +136,12 @@ class PackageOperations(Operations):
|
|||||||
def _packages_get_select_package_bases(connection: Connection) -> Dict[str, Package]:
|
def _packages_get_select_package_bases(connection: Connection) -> Dict[str, Package]:
|
||||||
"""
|
"""
|
||||||
select package bases from the table
|
select package bases from the table
|
||||||
:param connection: database connection
|
|
||||||
:return: map of the package base to its descriptor (without packages themselves)
|
Args:
|
||||||
|
connection(Connection): database connection
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict[str, Package]: map of the package base to its descriptor (without packages themselves)
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
row["package_base"]: Package(row["package_base"], row["version"], row["aur_url"], {})
|
row["package_base"]: Package(row["package_base"], row["version"], row["aur_url"], {})
|
||||||
@ -138,9 +152,13 @@ class PackageOperations(Operations):
|
|||||||
def _packages_get_select_packages(connection: Connection, packages: Dict[str, Package]) -> Dict[str, Package]:
|
def _packages_get_select_packages(connection: Connection, packages: Dict[str, Package]) -> Dict[str, Package]:
|
||||||
"""
|
"""
|
||||||
select packages from the table
|
select packages from the table
|
||||||
:param connection: database connection
|
|
||||||
:param packages: packages descriptor map
|
Args:
|
||||||
:return: map of the package base to its descriptor including individual packages
|
connection(Connection): database connection
|
||||||
|
packages(Dict[str, Package]): packages descriptor map
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict[str, Package]: map of the package base to its descriptor including individual packages
|
||||||
"""
|
"""
|
||||||
for row in connection.execute("""select * from packages"""):
|
for row in connection.execute("""select * from packages"""):
|
||||||
if row["package_base"] not in packages:
|
if row["package_base"] not in packages:
|
||||||
@ -152,8 +170,12 @@ class PackageOperations(Operations):
|
|||||||
def _packages_get_select_statuses(connection: Connection) -> Dict[str, BuildStatus]:
|
def _packages_get_select_statuses(connection: Connection) -> Dict[str, BuildStatus]:
|
||||||
"""
|
"""
|
||||||
select package build statuses from the table
|
select package build statuses from the table
|
||||||
:param connection: database connection
|
|
||||||
:return: map of the package base to its status
|
Args:
|
||||||
|
connection(Connection): database connection
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict[str, BuildStatus]: map of the package base to its status
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
row["package_base"]: BuildStatus.from_json({"status": row["status"], "timestamp": row["last_updated"]})
|
row["package_base"]: BuildStatus.from_json({"status": row["status"], "timestamp": row["last_updated"]})
|
||||||
@ -163,7 +185,9 @@ class PackageOperations(Operations):
|
|||||||
def package_remove(self, package_base: str) -> None:
|
def package_remove(self, package_base: str) -> None:
|
||||||
"""
|
"""
|
||||||
remove package from database
|
remove package from database
|
||||||
:param package_base: package base name
|
|
||||||
|
Args:
|
||||||
|
package_base(str): package base name
|
||||||
"""
|
"""
|
||||||
def run(connection: Connection) -> None:
|
def run(connection: Connection) -> None:
|
||||||
self._package_remove_packages(connection, package_base, [])
|
self._package_remove_packages(connection, package_base, [])
|
||||||
@ -174,8 +198,10 @@ class PackageOperations(Operations):
|
|||||||
def package_update(self, package: Package, status: BuildStatus) -> None:
|
def package_update(self, package: Package, status: BuildStatus) -> None:
|
||||||
"""
|
"""
|
||||||
update package status
|
update package status
|
||||||
:param package: package properties
|
|
||||||
:param status: new build status
|
Args:
|
||||||
|
package(Package): package properties
|
||||||
|
status(BuildStatus): new build status
|
||||||
"""
|
"""
|
||||||
def run(connection: Connection) -> None:
|
def run(connection: Connection) -> None:
|
||||||
self._package_update_insert_base(connection, package)
|
self._package_update_insert_base(connection, package)
|
||||||
@ -188,7 +214,9 @@ class PackageOperations(Operations):
|
|||||||
def packages_get(self) -> List[Tuple[Package, BuildStatus]]:
|
def packages_get(self) -> List[Tuple[Package, BuildStatus]]:
|
||||||
"""
|
"""
|
||||||
get package list and their build statuses from database
|
get package list and their build statuses from database
|
||||||
:return: list of package properties and their statuses
|
|
||||||
|
Return:
|
||||||
|
List[Tuple[Package, BuildStatus]]: list of package properties and their statuses
|
||||||
"""
|
"""
|
||||||
def run(connection: Connection) -> Generator[Tuple[Package, BuildStatus], None, None]:
|
def run(connection: Connection) -> Generator[Tuple[Package, BuildStatus], None, None]:
|
||||||
packages = self._packages_get_select_package_bases(connection)
|
packages = self._packages_get_select_package_bases(connection)
|
||||||
|
@ -31,16 +31,22 @@ class PatchOperations(Operations):
|
|||||||
def patches_get(self, package_base: str) -> Optional[str]:
|
def patches_get(self, package_base: str) -> Optional[str]:
|
||||||
"""
|
"""
|
||||||
retrieve patches for the package
|
retrieve patches for the package
|
||||||
:param package_base: package base to search for patches
|
|
||||||
:return: plain text patch for the package
|
Args:
|
||||||
|
package_base(str): package base to search for patches
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Optional[str]: 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: str) -> None:
|
||||||
"""
|
"""
|
||||||
insert or update patch in database
|
insert or update patch in database
|
||||||
:param package_base: package base to insert
|
|
||||||
:param patch: patch content
|
Args:
|
||||||
|
package_base(str): package base to insert
|
||||||
|
patch(str): patch content
|
||||||
"""
|
"""
|
||||||
def run(connection: Connection) -> None:
|
def run(connection: Connection) -> None:
|
||||||
connection.execute(
|
connection.execute(
|
||||||
@ -59,8 +65,12 @@ class PatchOperations(Operations):
|
|||||||
def patches_list(self, package_base: Optional[str]) -> Dict[str, str]:
|
def patches_list(self, package_base: Optional[str]) -> Dict[str, str]:
|
||||||
"""
|
"""
|
||||||
extract all patches
|
extract all patches
|
||||||
:param package_base: optional filter by package base
|
|
||||||
:return: map of package base to patch content
|
Args:
|
||||||
|
package_base(Optional[str]): optional filter by package base
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict[str, str]: map of package base to patch content
|
||||||
"""
|
"""
|
||||||
def run(connection: Connection) -> Dict[str, str]:
|
def run(connection: Connection) -> Dict[str, str]:
|
||||||
return {
|
return {
|
||||||
@ -75,7 +85,9 @@ class PatchOperations(Operations):
|
|||||||
def patches_remove(self, package_base: str) -> None:
|
def patches_remove(self, package_base: str) -> None:
|
||||||
"""
|
"""
|
||||||
remove patch set
|
remove patch set
|
||||||
:param package_base: package base to clear patches
|
|
||||||
|
Args:
|
||||||
|
package_base(str): package base to clear patches
|
||||||
"""
|
"""
|
||||||
def run(connection: Connection) -> None:
|
def run(connection: Connection) -> None:
|
||||||
connection.execute(
|
connection.execute(
|
||||||
|
@ -22,11 +22,10 @@ from __future__ import annotations
|
|||||||
import json
|
import json
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
|
||||||
from sqlite3 import Connection
|
from pathlib import Path
|
||||||
from typing import Type
|
from typing import Type
|
||||||
|
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
from ahriman.core.database.data import migrate_data
|
|
||||||
from ahriman.core.database.migrations import Migrations
|
from ahriman.core.database.migrations import Migrations
|
||||||
from ahriman.core.database.operations.auth_operations import AuthOperations
|
from ahriman.core.database.operations.auth_operations import AuthOperations
|
||||||
from ahriman.core.database.operations.build_operations import BuildOperations
|
from ahriman.core.database.operations.build_operations import BuildOperations
|
||||||
@ -43,17 +42,37 @@ class SQLite(AuthOperations, BuildOperations, PackageOperations, PatchOperations
|
|||||||
def load(cls: Type[SQLite], configuration: Configuration) -> SQLite:
|
def load(cls: Type[SQLite], configuration: Configuration) -> SQLite:
|
||||||
"""
|
"""
|
||||||
construct instance from configuration
|
construct instance from configuration
|
||||||
:param configuration: configuration instance
|
|
||||||
:return: fully initialized instance of the database
|
Args:
|
||||||
|
configuration(Configuration): configuration instance
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
SQLite: fully initialized instance of the database
|
||||||
"""
|
"""
|
||||||
database = cls(configuration.getpath("settings", "database"))
|
path = cls.database_path(configuration)
|
||||||
|
database = cls(path)
|
||||||
database.init(configuration)
|
database.init(configuration)
|
||||||
return database
|
return database
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def database_path(configuration: Configuration) -> Path:
|
||||||
|
"""
|
||||||
|
read database from configuration
|
||||||
|
|
||||||
|
Args:
|
||||||
|
configuration(Configuration): configuration instance
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Path: database path according to the configuration
|
||||||
|
"""
|
||||||
|
return configuration.getpath("settings", "database")
|
||||||
|
|
||||||
def init(self, configuration: Configuration) -> None:
|
def init(self, configuration: Configuration) -> None:
|
||||||
"""
|
"""
|
||||||
perform database migrations
|
perform database migrations
|
||||||
:param configuration: configuration instance
|
|
||||||
|
Args:
|
||||||
|
configuration(Configuration): configuration instance
|
||||||
"""
|
"""
|
||||||
# custom types support
|
# custom types support
|
||||||
sqlite3.register_adapter(dict, json.dumps)
|
sqlite3.register_adapter(dict, json.dumps)
|
||||||
@ -62,9 +81,5 @@ class SQLite(AuthOperations, BuildOperations, PackageOperations, PatchOperations
|
|||||||
|
|
||||||
paths = configuration.repository_paths
|
paths = configuration.repository_paths
|
||||||
|
|
||||||
def run(connection: Connection) -> None:
|
self.with_connection(lambda conn: Migrations.migrate(conn, configuration))
|
||||||
result = Migrations.migrate(connection)
|
|
||||||
migrate_data(result, connection, configuration, paths)
|
|
||||||
|
|
||||||
self.with_connection(run)
|
|
||||||
paths.chown(self.path)
|
paths.chown(self.path)
|
||||||
|
@ -29,7 +29,9 @@ class BuildFailed(RuntimeError):
|
|||||||
def __init__(self, package_base: str) -> None:
|
def __init__(self, package_base: str) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
default constructor
|
||||||
:param package_base: package base raised exception
|
|
||||||
|
Args:
|
||||||
|
package_base(str): package base raised exception
|
||||||
"""
|
"""
|
||||||
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")
|
||||||
|
|
||||||
@ -61,7 +63,9 @@ class InitializeException(RuntimeError):
|
|||||||
def __init__(self, details: str) -> None:
|
def __init__(self, details: str) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
default constructor
|
||||||
:param details: details of the exception
|
|
||||||
|
Args:
|
||||||
|
details(str): details of the exception
|
||||||
"""
|
"""
|
||||||
RuntimeError.__init__(self, f"Could not load service: {details}")
|
RuntimeError.__init__(self, f"Could not load service: {details}")
|
||||||
|
|
||||||
@ -74,7 +78,9 @@ class InvalidOption(ValueError):
|
|||||||
def __init__(self, value: Any) -> None:
|
def __init__(self, value: Any) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
default constructor
|
||||||
:param value: option value
|
|
||||||
|
Args:
|
||||||
|
value(Any): option value
|
||||||
"""
|
"""
|
||||||
ValueError.__init__(self, f"Invalid or unknown option value `{value}`")
|
ValueError.__init__(self, f"Invalid or unknown option value `{value}`")
|
||||||
|
|
||||||
@ -87,8 +93,10 @@ class InvalidPath(ValueError):
|
|||||||
def __init__(self, path: Path, root: Path) -> None:
|
def __init__(self, path: Path, root: Path) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
default constructor
|
||||||
:param path: path which raised an exception
|
|
||||||
:param root: repository root (i.e. ahriman home)
|
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}`")
|
ValueError.__init__(self, f"Path `{path}` does not belong to repository root `{root}`")
|
||||||
|
|
||||||
@ -101,7 +109,9 @@ class InvalidPackageInfo(RuntimeError):
|
|||||||
def __init__(self, details: Any) -> None:
|
def __init__(self, details: Any) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
default constructor
|
||||||
:param details: error details
|
|
||||||
|
Args:
|
||||||
|
details(Any): error details
|
||||||
"""
|
"""
|
||||||
RuntimeError.__init__(self, f"There are errors during reading package information: `{details}`")
|
RuntimeError.__init__(self, f"There are errors during reading package information: `{details}`")
|
||||||
|
|
||||||
@ -114,7 +124,9 @@ class MigrationError(RuntimeError):
|
|||||||
def __init__(self, details: str) -> None:
|
def __init__(self, details: str) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
default constructor
|
||||||
:param details: error details
|
|
||||||
|
Args:
|
||||||
|
details(str): error details
|
||||||
"""
|
"""
|
||||||
RuntimeError.__init__(self, details)
|
RuntimeError.__init__(self, details)
|
||||||
|
|
||||||
@ -127,7 +139,9 @@ class MissingArchitecture(ValueError):
|
|||||||
def __init__(self, command: str) -> None:
|
def __init__(self, command: str) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
default constructor
|
||||||
:param command: command name which throws exception
|
|
||||||
|
Args:
|
||||||
|
command(str): command name which throws exception
|
||||||
"""
|
"""
|
||||||
ValueError.__init__(self, f"Architecture required for subcommand {command}, but missing")
|
ValueError.__init__(self, f"Architecture required for subcommand {command}, but missing")
|
||||||
|
|
||||||
@ -140,7 +154,9 @@ class MultipleArchitectures(ValueError):
|
|||||||
def __init__(self, command: str) -> None:
|
def __init__(self, command: str) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
default constructor
|
||||||
:param command: command name which throws exception
|
|
||||||
|
Args:
|
||||||
|
command(str): command name which throws exception
|
||||||
"""
|
"""
|
||||||
ValueError.__init__(self, f"Multiple architectures are not supported by subcommand {command}")
|
ValueError.__init__(self, f"Multiple architectures are not supported by subcommand {command}")
|
||||||
|
|
||||||
@ -165,7 +181,9 @@ class SuccessFailed(ValueError):
|
|||||||
def __init__(self, package_base: str) -> None:
|
def __init__(self, package_base: str) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
default constructor
|
||||||
:param package_base: package base name
|
|
||||||
|
Args:
|
||||||
|
package_base(str): package base name
|
||||||
"""
|
"""
|
||||||
ValueError.__init__(self, f"Package base {package_base} had status failed, but new status is success")
|
ValueError.__init__(self, f"Package base {package_base} had status failed, but new status is success")
|
||||||
|
|
||||||
@ -190,7 +208,9 @@ class UnknownPackage(ValueError):
|
|||||||
def __init__(self, package_base: str) -> None:
|
def __init__(self, package_base: str) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
default constructor
|
||||||
:param package_base: package base name
|
|
||||||
|
Args:
|
||||||
|
package_base(str): package base name
|
||||||
"""
|
"""
|
||||||
ValueError.__init__(self, f"Package base {package_base} is unknown")
|
ValueError.__init__(self, f"Package base {package_base} is unknown")
|
||||||
|
|
||||||
@ -203,8 +223,10 @@ class UnsafeRun(RuntimeError):
|
|||||||
def __init__(self, current_uid: int, root_uid: int) -> None:
|
def __init__(self, current_uid: int, root_uid: int) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
default constructor
|
||||||
:param current_uid: current user ID
|
|
||||||
:param root_uid: ID of the owner of root directory
|
Args:
|
||||||
|
current_uid(int): current user ID
|
||||||
|
root_uid(int): ID of the owner of root directory
|
||||||
"""
|
"""
|
||||||
RuntimeError.__init__(self, f"Current UID {current_uid} differs from root owner {root_uid}. "
|
RuntimeError.__init__(self, f"Current UID {current_uid} differs from root owner {root_uid}. "
|
||||||
f"Note that for the most actions it is unsafe to run application as different user."
|
f"Note that for the most actions it is unsafe to run application as different user."
|
||||||
|
@ -28,13 +28,17 @@ from ahriman.models.property import Property
|
|||||||
class AurPrinter(StringPrinter):
|
class AurPrinter(StringPrinter):
|
||||||
"""
|
"""
|
||||||
print content of the AUR package
|
print content of the AUR package
|
||||||
:ivar package: AUR package description
|
|
||||||
|
Attributes:
|
||||||
|
package(AURPackage): AUR package description
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, package: AURPackage) -> None:
|
def __init__(self, package: AURPackage) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
default constructor
|
||||||
:param package: AUR package description
|
|
||||||
|
Args:
|
||||||
|
package(AURPackage): AUR package description
|
||||||
"""
|
"""
|
||||||
StringPrinter.__init__(self, f"{package.name} {package.version} ({package.num_votes})")
|
StringPrinter.__init__(self, f"{package.name} {package.version} ({package.num_votes})")
|
||||||
self.package = package
|
self.package = package
|
||||||
@ -42,7 +46,9 @@ class AurPrinter(StringPrinter):
|
|||||||
def properties(self) -> List[Property]:
|
def properties(self) -> List[Property]:
|
||||||
"""
|
"""
|
||||||
convert content into printable data
|
convert content into printable data
|
||||||
:return: list of content properties
|
|
||||||
|
Returns:
|
||||||
|
List[Property]: list of content properties
|
||||||
"""
|
"""
|
||||||
return [
|
return [
|
||||||
Property("Package base", self.package.package_base),
|
Property("Package base", self.package.package_base),
|
||||||
|
@ -29,9 +29,11 @@ class BuildPrinter(StringPrinter):
|
|||||||
def __init__(self, package: Package, is_success: bool, use_utf: bool) -> None:
|
def __init__(self, package: Package, is_success: bool, use_utf: bool) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
default constructor
|
||||||
:param package: built package
|
|
||||||
:param is_success: True in case if build has success status and False otherwise
|
Args:
|
||||||
:param use_utf: use utf instead of normal symbols
|
package(Package): built package
|
||||||
|
is_success(bool): True in case if build has success status and False otherwise
|
||||||
|
use_utf(bool): use utf instead of normal symbols
|
||||||
"""
|
"""
|
||||||
StringPrinter.__init__(self, f"{self.sign(is_success, use_utf)} {package.base}")
|
StringPrinter.__init__(self, f"{self.sign(is_success, use_utf)} {package.base}")
|
||||||
|
|
||||||
@ -39,9 +41,13 @@ class BuildPrinter(StringPrinter):
|
|||||||
def sign(is_success: bool, use_utf: bool) -> str:
|
def sign(is_success: bool, use_utf: bool) -> str:
|
||||||
"""
|
"""
|
||||||
generate sign according to settings
|
generate sign according to settings
|
||||||
:param use_utf: use utf instead of normal symbols
|
|
||||||
:param is_success: True in case if build has success status and False otherwise
|
Args:
|
||||||
:return: sign symbol according to current settings
|
is_success(bool): True in case if build has success status and False otherwise
|
||||||
|
use_utf(bool): use utf instead of normal symbols
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: sign symbol according to current settings
|
||||||
"""
|
"""
|
||||||
if is_success:
|
if is_success:
|
||||||
return "[✔]" if use_utf else "[x]"
|
return "[✔]" if use_utf else "[x]"
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user