Compare commits

..

704 Commits

Author SHA1 Message Date
d283dccc1e type: update for new cors release 2025-03-17 13:56:59 +02:00
8a4e900ab9 docs: update docs
This commit includes following changes
* add newly added option to configuration referenec
* remove few legacy options from configuration schemas used for
  validation, which might lead to errors during validation.
  Note, however, that settings will be still read by the service
* add link to aurcache
* hide service-setup command description under spoiler
2025-03-17 13:43:04 +02:00
fa6cf8ce36 website: use date instead of version for listing logs
website: make dropdown from logs versions to add some space
2025-03-13 15:45:31 +02:00
a706fbb751 bug: handle dependencies iteratively (fix #141)
It has been found that if there are missing dependencies than whole
process will break instead of just skipping packages. During package
addition it is fine-ish, but it will break updates run
2025-03-13 15:45:27 +02:00
9a23f5c79d refactor: streamline migrations 2025-03-09 23:22:24 +02:00
aaab9069bf docs: rebuild indices 2025-03-09 15:43:41 +02:00
f00b575641 type: use ClassVar decorator for class attributes 2025-03-09 15:43:27 +02:00
6f57ed550b
feat: refine log system (#142)
* refine package logging

* add interface

* revert version selection

* replace tuple with model

* rename column in logs table, add coverters

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

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

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

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

Another side change is that container does not longer ship syncronized
(and out-of-dated) pacman databases; they have to be synced manually
2024-11-15 17:07:37 +02:00
f09082dff2 fix: fix parsing pkgbuild in case if comment starts with multiple sharps (#136) 2024-11-13 17:56:27 +02:00
8d53a59a6a feat: notify users about outdated password hashes used 2024-11-13 16:18:44 +02:00
20e7ba3b1d style: fix some typos and warnings 2024-11-11 18:07:13 +02:00
4b5a645f8d docs: architecture doc update 2024-11-10 16:19:22 +02:00
6a3c16a646 build: move dockerfile to docker directory 2024-11-06 17:18:31 +02:00
93ce7f9a51
feat: use split packages (#135)
* move argument parsers to handlers themselves

* use hatchling instead of flit

* Revert "use hatchling instead of flit"

This reverts commit d18d146d79.

* add package-splitt script

* replace simplify walk method

* split packages

* explicitly install packages

* separate support triggers from main package

* add docs examples

* sort actions

* docs update

* add metapackage

* review fixes
2024-11-01 16:07:04 +02:00
6fe77eb465 test: remove duplicated descriptions from tests 2024-10-24 01:22:16 +03:00
7c6c24a46d feat: allow append list options 2024-10-24 01:22:16 +03:00
f48993ccd5 build: update aur packages list for docker image build 2024-10-07 16:03:23 +03:00
22600a9eac chore: contributing guide update 2024-10-06 15:06:22 +03:00
b167df904b build: use tool.flit.external-data to distribute data 2024-10-05 17:17:16 +03:00
cd0ac7a7bd chore: replace passlib with bcrypt
passlib uses deprecated crypt module which is deprecated and scheduled
for removal in 3.13. Unfortunately, this module seems to be
unmaintained, so this commit replaces passlib with bcrypt, unfortunately
breaking current passwords
2024-10-05 16:35:27 +03:00
910d178c71 docs: replace svg with dot 2024-09-30 14:48:21 +03:00
1e7d4daf18 feat: add package copy subcommand 2024-09-27 17:23:04 +03:00
7bc4810377 fix: change category for dependencies api docs 2024-09-27 14:43:05 +03:00
aa66e76db7 feat: show implicit dependencies for packages 2024-09-27 14:41:45 +03:00
e0f9e38f44 Release 2.15.2 2024-09-26 16:58:19 +03:00
d6cdb5bea5 fix: fix pkgbuild parsing in some cases
It has been found that there are two cases in which pkgbuild was not
parsed correctly

1. Major case in which there is quotation mark inside comment line,
   which would cause ValueError: No closing quotation error
2. Minor case, if there are utf symbols in pkgbuild file (e.g.
   hieroglyphs, see ttf-google-fonts-git), it will case incorrect
   reading in `_is_escaped` method
2024-09-26 16:48:38 +03:00
6d157ca809 fix: do not copy own database during pyalpm initialization
Previous implementation lead to warning in logs in case if the
repository itself wasn't configured on the host
2024-09-25 14:31:32 +03:00
5486ae4a19 fix: suppress info logging during version check 2024-09-25 14:23:53 +03:00
8bdf420cdc feat: suppress info log during vcs version calculation 2024-09-25 07:15:51 +03:00
2deca6d715 refactor: even further improvements for Handler.check_status method 2024-09-25 07:15:51 +03:00
180adf3f33 type: remove unused ignore comment 2024-09-25 07:15:51 +03:00
634054926d docs: improve application help messages 2024-09-24 17:58:08 +03:00
53baaac61e Release 2.15.1 2024-09-24 11:18:38 +03:00
d2a93a94e3 feat: enable changes calculation in unit 2024-09-24 11:01:37 +03:00
7134aea125 refactor: rename Handler.check_if_empty to check_status 2024-09-24 01:36:33 +03:00
740d537618 fix: bump pkgrel if the local version is newer than remote
In case of VCS packages, if PKGBUILD contains older version, the pkgrel
remains the same during the rebuild process. This fix bumps pkgrel in
any case if the local version is newer than the remote
2024-09-23 16:30:33 +03:00
9f78e79f1f build: reduce docker image size 2024-09-23 14:37:36 +03:00
09456141f5 docs: update web preview picture 2024-09-23 14:03:12 +03:00
9e30e98e90 fix: allow colon in options interpolation 2024-09-23 13:52:49 +03:00
df2e98a1d3 Release 2.15.0 2024-09-23 03:32:01 +03:00
24993047c6 build: speedup pacman 2024-09-23 03:30:17 +03:00
b20e844cc9 website: add logo to api docs 2024-09-23 02:39:54 +03:00
ce75ccb405 docs: update configuration references in docs 2024-09-22 15:16:34 +03:00
1acff852d0 docs: add logo 2024-09-22 14:21:01 +03:00
62320e8ec6 feat: drop explicit makepkg usage (#134)
* generate filenames without using makepkg

* pkgbuild parser impl

* completely remove makepkg calls

* simplify typed get

* try to improve parser

* docs and recipes updatte

* never raise keyerror instead return empty string

* udpate tests

* add support of array expansion

* docs update

* tests update

* handle quoted control sequences correctly

* expand bash

* allow packages without package function

* docs update

* add moroe tests

* small improovements

* support escaped arrays and functions
2024-09-21 03:57:22 +03:00
1089bab526 type: ignore too-many-positional-arguments 2024-09-20 23:22:33 +03:00
0e0012a6e0 chore: refresh icons 2024-09-20 03:29:18 +03:00
fbbb80d091 Revert "fix: update Repo.init to the latest pacman release"
This reverts commit 99ca0cb2fd.
2024-09-20 01:48:09 +03:00
5316427371 fix: limit amount of fetches used for changes
The issue appears in case if - somehow - unknown commit sha has been
stored. In this scenario it would try to fetch infinitely
2024-09-20 01:48:03 +03:00
0fa748f302 feat: calculate changes on package addition as well 2024-09-20 01:48:03 +03:00
7a3d32dcfa fix: do not treat cached vcs packages as local 2024-09-20 01:47:58 +03:00
a396126a79 feat: calculate and store changes for each update 2024-09-17 15:01:45 +03:00
9785835c0e docs: improve class init docs 2024-09-15 15:13:54 +03:00
c4f4e37731 feat: get rid of jquery (#133) 2024-09-05 02:26:52 +03:00
f43ee2fd1d build: make cerberus dependency optional 2024-09-04 22:28:25 +03:00
f7a50e5294 feat: implement stats subcommand (#132) 2024-09-04 22:28:25 +03:00
ddd3c3f06f feat: allow filter events by timestamp 2024-09-04 22:28:25 +03:00
242f3d4d34 chore: add rss generation to samples 2024-09-04 22:28:25 +03:00
303f9ff03c feat: add event log and update chart to package info modal 2024-09-04 22:28:25 +03:00
65fac09d8d feat: remove duplicates from the toast 2024-09-04 22:28:25 +03:00
aaf7adbac1 refactor: simplify Validator class 2024-09-04 22:28:25 +03:00
9e011990ee feat: allow cross reference in the configuration (#131) 2024-09-04 22:28:25 +03:00
529d4caa0e feat: implement rss generation (#130) 2024-09-04 22:28:25 +03:00
d7c4fccf98 feat: add ability to log sql statements 2024-09-04 22:28:25 +03:00
1e30838be4 feat: serve logs and events from the newest to oldest, but keep the
ordering

So basically initial implementation, with limit=1, would emit the oldest
record in series. New implementation will return the most recent one
instead

The response is still sorted by ascension
2024-09-04 22:28:25 +03:00
d57276f214 feat: log package update events 2024-09-04 22:28:25 +03:00
31e59df2c8 refactor: allow event to receive keyword arguments
This change also replaces the dataclass implementation of the class to
custom one
2024-09-04 22:28:25 +03:00
23cd843e44 feat: add timer for metrics purposes 2024-09-04 22:28:25 +03:00
c08a292070 docs: update booleans in docs 2024-09-04 22:28:25 +03:00
5163aa4dca feat: implement audit log tables and methods (#129) 2024-09-04 22:28:25 +03:00
69f0966ff1 feat: replace scan paths options to single one
It has been found that previous system didn't allow to configure
specific cases (e.g. a whitelisted directory inside /usr/lib/cmake). The
current solution replaces two options to single one, which also allows a
regular expressions

Also PackageArchive class has been moved to core package, because it is
more about service rather than model
2024-09-04 22:25:54 +03:00
16308dc3ae Release 2.14.1 2024-09-04 22:01:04 +03:00
962599e937 bug: fix removal of the packages
It has been broken since reporter improvements, because it effectivelly
1) didn't call remove functions in database
2) used empty repository identifier for web service

With those changes it also raises exception when you try to call id on
empty identifier
2024-09-04 21:50:33 +03:00
758a81e3db chore: small contributing guide update 2024-09-04 21:49:31 +03:00
84942e3c98 refactor: fix some IDE warnings 2024-09-04 21:49:31 +03:00
6f8b1509d7 build: update pytest configuration to suppress deprecation warnings 2024-09-04 21:49:31 +03:00
b4372ff583 Release 2.14.0 2024-08-23 14:37:05 +03:00
41fc7bffbb docs: improve waiter classes docs 2024-08-23 14:33:07 +03:00
300f5026c4 feat: add ability to suppress git hints
It can be done by setting options in command. The commit author/email is
also now using this logic
2024-08-23 14:33:07 +03:00
10aa91a033 feat: add blacklisted paths to implicit dependencies processing
It has been found that in some cases additional packages have been added
as dependencies, like usr/share/applications, usr/lib/cmake, etc

This commit adds an ability to blacklist specific paths from processing
2024-08-23 14:33:07 +03:00
4169851eaa docs: split faq into multiple files 2024-08-20 16:44:40 +03:00
4d9e06156d feat: add support of pam authentication
Add naive implementation of user password check by calling su command.
Also change some authentication method to require username to be string
instead of optional string
2024-08-20 16:44:40 +03:00
af2269c64a fix: print current and updated version correctly
The issue appears in case if versions ar the same (e.g. rebuild); in
this case printer doesn't increment version as builder does.

Also util has been renamed to utils, keeping backward compatibiltiy
2024-08-16 16:24:11 +03:00
f44fa19c42 feat: optimize archive reading
Instead of trying to load every database and look for files, this commit
introduces the optimization in which, the service loads packages first,
groups them by database and load files later.

In some cases it significantly descreases times for loading files
2024-08-14 17:07:10 +03:00
fd3c6343f1 fix: explicitly process list of packages
Small workaround to remove debug packages from being processed
2024-08-14 17:07:10 +03:00
9edff2826f fix: remove trailit slash when loading packages files from a database 2024-08-14 17:07:10 +03:00
b38ecfb35c fix: skip debug packages as well 2024-08-14 17:07:10 +03:00
3c7c748b4a docs: update documentation for implicit dependencies resolution 2024-08-14 17:07:10 +03:00
434057ec49 feat: remove excess dependencies leaves (#128)
This mr improves implicit dependencies processing by reducing tree leaves by using the following algorithm:

* remove paths which belong to any base package
* remove packages which are (opt)dependencies of one of the package which provides same path. It also tries to handle circular dependencies by excluding them from being "satisfied"
* remove packages which are already satisfied by any children path
2024-08-14 17:07:10 +03:00
a01b090c2b feat: improve lock mechanisms
* improve lock mechanisms

* use /run/ahriman for sockett

* better water
2024-08-14 17:07:10 +03:00
8ffc1299f0 feat: implement local reporter mode (#126)
* implement local reporter mode

* simplify watcher class

* review changes

* do not update unknown status

* allow empty key patches via api

* fix some pylint warnings in tests
2024-08-14 17:07:10 +03:00
02b13de7f4 feat: allow to use simplified keys for context
Initial implementation requires explicit context key name to be set.
Though it is still useful sometimes (e.g. if there should be two
variables with the same type), in the most used scenarios internally
only type is required. This commit extends set and get methods to allow
to construct ContextKey from type directly

Also it breaks old keys, since - in order to reduce amount of possible
mistakes - internal classes uses this generation method
2024-08-14 17:07:10 +03:00
50a045434d feat: add abillity to check broken dependencies (#122)
* implement elf dynamic linking check

* load local database too in pacman wrapper
2024-08-14 17:07:10 +03:00
7bbe3242d4 type: drop MiddlewareType in favour of Middleware builtin 2024-08-14 17:07:10 +03:00
a9cb357182 type: fix mypy warn for fresh unixsocket release 2024-08-14 17:07:10 +03:00
feec9141b2 type: remove another unused mypy directive 2024-08-14 17:07:10 +03:00
148ef09e70 build: use requests-unixsocket2 fork
Since requests-2.32.0, the http+unix url scheme is brokek, check
https://github.com/msabramo/requests-unixsocket/issues/73 for more
details
2024-08-14 17:07:10 +03:00
5ff635db70 Release 2.13.8 2024-05-12 11:53:19 +03:00
9df5820bce fix: drop integrity check for javascript
It has been added to improve security, however, it changes over time for
no reason ¯\_(ツ)_/¯ I guess either cdn was hacked or fuck js
2024-05-12 11:49:12 +03:00
b7d3493ae3 Release 2.13.7 2024-05-09 13:26:40 +03:00
f8b725d175 fix: parse array variable from command 2024-05-09 13:21:42 +03:00
46b3c82aca Release 2.13.6 2024-05-05 21:59:30 +03:00
0d34432c9a fix: update integrity checksums for momentjs and daterangepicker 2024-05-05 21:17:30 +03:00
3cd9cff4ee refactor: update code to the latest python (3.12+) 2024-05-05 21:17:30 +03:00
9e02d7a38f fix: remove debug packages together with normal ones (#124) 2024-05-05 21:17:30 +03:00
9819ed761e Release 2.13.5 2024-04-04 13:33:03 +03:00
99ca0cb2fd fix: update Repo.init to the latest pacman release 2024-04-04 13:16:05 +03:00
ea3cb6e766 build: install base-devel package 2024-04-04 13:16:03 +03:00
0ae4941321 fix: lazy web component initialization
In some cases (probably slow internet) in place initialization can cause
exception, because elements are not available yet. This commit moves
events initialization to $()
2024-04-04 13:14:17 +03:00
855b55237b feat: add ability to disable debug packages distribution
The feature is implemented as supplying !debug option to makepkg when
generating package list. In this case debug packages still will be
built, however, they will not be added to the repository
2024-04-04 13:14:17 +03:00
59d14665a5 docs: update docs 2024-02-10 03:12:09 +02:00
414eb93b1e Release 2.13.4 2024-02-09 17:47:01 +02:00
14721913a4 fix: return only built packages from task
Since the last updates makepkg --packagelist also adds debug packages
which causes errors
2024-02-09 17:37:50 +02:00
f68e48fb47 refactor: rename packages http methods to own package
docs: update docs import
2024-01-22 02:20:11 +02:00
77cceb4c10 Release 2.13.3 2024-01-13 01:24:30 +02:00
eca22fdaed fix: replace logo and name in title to just icon 2024-01-12 01:25:46 +02:00
719af3676e Release 2.13.2 2024-01-08 22:48:55 +02:00
6c63ad6df5 fix: report only unique result entries
since builder intro the triggers are called with merged result, thus it
would lead to duplicated callouts
2024-01-08 22:46:42 +02:00
497a115535 Release 2.13.1 2024-01-08 21:17:35 +02:00
91598951c5 fix: do not raise 404 in case of unknown package on patches endpoints
Previous improvements raise 404 error in case if no packages were found
for patches endpoints. However, in case of multirepo setup this feature
doesn't work properly because package can be located in any other
repository different from default
2024-01-08 14:32:40 +02:00
f364e00bea build: pass ssh agent to tox release env 2024-01-08 14:22:53 +02:00
87c87d6455 Release 2.13.0 2024-01-05 22:48:03 +02:00
265de3dc72 ci: explicit isolated build for old ubuntu tox 2024-01-05 22:47:28 +02:00
d06c02a1c7 docs: add comments to configuration 2024-01-05 22:24:37 +02:00
29bb6284b0 test: add pytlint imports plugin and fix errors 2024-01-05 19:52:51 +02:00
70b7fcf47a refactor: fix pylint warnings in tests 2024-01-05 16:40:38 +02:00
706808fc97 refactor: simplify lock processing in worker trigger 2024-01-05 16:11:32 +02:00
7e5f21c26d refactor: split Path elements to / and first directory 2024-01-05 15:22:46 +02:00
9a7f55605a docs: url spelling 2024-01-05 12:37:23 +02:00
6085e88f5e chore: add index page recipe 2024-01-05 12:34:55 +02:00
56e97040d6 feat: read username if email is not available for oauth provider
Also add recipe for OAuth with GitHub setup
2024-01-05 12:28:31 +02:00
9510a14b90 refactor: use root RequestException instead of the one from subpackage 2024-01-05 11:48:38 +02:00
6eeef39fe5 fix: safe urls for packages
String catenation used for url generators didn't encode package names
which could lead to missing data in case if e.g. there is slash (/) in
package name
2024-01-03 14:28:20 +02:00
0e6434faad refactor: remove custom access logger
It is fine when application is able to log request, however, normally it
produces a lot noise, which has been handled by adding special logger.
However, nowadays it requires a lot endpoints to be filtered and doesn't
provide any choice.

Instead of it lets disable access logger by default and let users decide
do they need or not to see access log messages
2024-01-03 12:18:50 +02:00
768132bb6c chore: copyright update 2024-01-03 12:09:10 +02:00
f1095fe007 feat: raise 404 in case if package is unknown for logs and patches 2024-01-03 12:09:10 +02:00
1af04448c9 feat: threadsafe services
In the most cases it was enough to just add lock. In case of worker
trigger, since there is atomic operation on timer, it was also required
to add queue (coz python doesn't have atomics)
2024-01-03 12:09:10 +02:00
aad607eaef feat: add workers autodicsovery feature (#121)
* add workers autodicsovery feature

* suppress erros while retrieving worker list

* update recipes

* fix tests and update docs

* filter health checks

* ping based workers
2024-01-03 02:25:24 +02:00
3347212bf2 chore: make yamll style consistent 2023-12-29 03:57:13 +02:00
f3e9fbf9d0 refactor: fix warnings and typos, cleanup code 2023-12-28 16:53:45 +02:00
c3dacd6883 build: install aiohttp-cors from aur 2023-12-28 16:05:48 +02:00
624b4619f1 chore: add daemon unit 2023-12-28 15:24:14 +02:00
215fe7a592 test: add tests to check args list
Some parsers are shared between different subcommands. It causes errors
when wwe add new arguments to one of them. This commit adds some tests
to cover those cases (except for well-known differencies)
2023-12-27 15:01:07 +02:00
dd8d5d130b refactor: use AppKey's instead of string identifiers for web application 2023-12-27 13:53:23 +02:00
b4fa10781b feat: allow to run daemon mode with split packages check (#120) 2023-12-27 03:05:44 +02:00
f6cdd806b2 feat: add healh-check like endpoint, support of healthcheck in docker compose 2023-12-21 17:49:35 +02:00
cf9a1e7bec docs: add reference how to copy package 2023-12-21 02:14:27 +02:00
1b93f4f5e0 fix: drop debug toolbar 2023-12-20 16:26:14 +02:00
a872ecfc23 docs: docs review 2023-12-20 10:00:12 +02:00
c130f52163 chore: add configuration recipes 2023-12-20 10:00:12 +02:00
5fb93bd331 build: drop makefile
It has been a while since we moved to tox. Lets also drop makefile since
it seems to be useless with tox
2023-12-17 02:26:52 +02:00
58e702213d docs: restore docs for the view 2023-12-15 16:17:19 +02:00
e784032bc6 feat: add ability to disable specific routes (#119) 2023-12-15 14:34:03 +02:00
c54b14b833 feat: add ability to run build process to remote instances (#118) 2023-12-13 15:38:51 +02:00
e61b246216 fix: correct url for update requests in remote-call trigger 2023-12-11 15:43:28 +02:00
2a9eab5f1a feat: changes screen implementation (#117)
Add support of changes generation. Changes will be generated (unless explicitly asked not to) automatically during check process (i.e. `repo-update --dry-run` and aliases) and uploaded to the remote server. Changes can be reviewed either by web interface or by special subcommands.

Changes will be automatically cleared during next successful build
2023-11-30 14:56:41 +02:00
acc204de6d fix: use event instead of chained timer for daemon
Old solution causes amount of thread to be growing as well as stack is
increased during each iteration. Instead of cycle-free implementation,
this commit just uses while cycle
2023-11-30 13:40:59 +02:00
0991dbb59c type: update to the typed aiohttp release 2023-11-23 15:35:38 +02:00
18d17d4d52 feat: forbid form data in html
It has been a while since all pages have moved to json instead of form
data, except for login page. This commit changes login to json data
instead of form one
2023-11-16 16:42:27 +02:00
de7184fc3a feat: add separated web client for ahriman web services 2023-11-14 16:41:33 +02:00
2d21c999d1 docs: move timeout settings from web to status group 2023-11-13 16:53:16 +02:00
ff78577d61 Release 2.12.2 2023-11-13 12:26:00 +02:00
eb6eda578c style: highligh __del__ methods in formatting 2023-11-13 12:16:30 +02:00
e823fd3f27 fix: fix some security issues 2023-11-12 22:22:05 +02:00
e4a857dad0 feat: add separated switch for status reporting 2023-11-11 15:18:17 +02:00
fc8f6c2985 feat: extend result class 2023-11-10 17:09:01 +02:00
bb6414f9d4 fix: pass packagers object insteaed of string during rebuild 2023-11-08 16:05:27 +02:00
064ac6811c build: rename push action to release 2023-11-06 23:25:29 +02:00
7d16142b3b Release 2.12.1 2023-11-06 16:31:56 +02:00
69a79a2e64 fix: show unique upstream urls only 2023-11-06 16:29:18 +02:00
5b4bff9c93 Release 2.12.0 2023-11-06 15:50:11 +02:00
3f8b9eaed6 feat: add upstream and aur urls to package info modal 2023-11-06 15:46:32 +02:00
deab8ddae6 feat: serve favicon in root 2023-11-06 15:46:32 +02:00
eacb6ec729 build: remove spaces from names 2023-11-06 14:04:15 +02:00
dc2eebce39 docs: correct crossreference in docs 2023-11-06 14:04:15 +02:00
6b755b4828 refactor: replace enum with intenum and strenum 2023-11-05 13:26:11 +02:00
a73341e885 feat: allow to pass repository identifier to all database methods 2023-11-05 13:26:11 +02:00
969aa78c95 build: remove unused files from tarball 2023-11-05 13:26:11 +02:00
df787657aa chore: add metthod definition order plugin to pylint
Also reorder some methods to fix errors
2023-11-05 13:26:11 +02:00
eec94521a7 feat: read old web sections 2023-11-04 13:34:53 +02:00
b18000c777 feat: improve small screens views
also fix case when invalid repository id has been sent
2023-11-01 16:38:53 +02:00
dbaff5f981 fix: reset logs window manually 2023-10-31 12:33:57 +02:00
ae84ca0c56 fix: correct month serialization 2023-10-31 10:13:25 +02:00
8f047f9a96 feat: add patch controls to web, review web, enrich info tab (#115)
* add ability to specify one-time patch on package addition

* support vars in interface
2023-10-29 23:41:20 +02:00
54bd016c17 refactor: drop _check_output class attribute 2023-10-23 02:24:53 +03:00
42f77742f8 refactor: add ability to pass anything as environment variable to build task 2023-10-23 02:24:41 +03:00
46bb9c95d0 fix: make toggle button works on small displays 2023-10-21 15:18:09 +03:00
5dd4763a80 fix: write new line for telegram index 2023-10-21 03:56:48 +03:00
45eba6a6e3 fix: do not automatically add unknown local packages
Instead of automatic package addition now it is required to add package
manually after clone. Less magic, plus would allow to use caches for
multi-repo setup (see #109)
2023-10-21 01:33:12 +03:00
4c1d0abb85 feat: add ability to run multiple commands on success 2023-10-19 04:34:49 +03:00
1e00bf9398 feat: allow to use single web instance for all repositories (#114)
* Allow to use single web instance for any repository

* some improvements

* drop includes from user home directory, introduce new variables to docker

The old solution didn't actually work as expected, because devtools
configuration belongs to filesystem (as well as sudo one), so it was
still required to run setup command.

In order to handle additional repositories, the POSTSETUP and PRESETUP
commands variables have been introduced. FAQ has been updated as well

* raise 404 in case if repository is unknown
2023-10-17 03:58:50 +03:00
bf9a46936c chore: update comments to the latest mypy release 2023-10-12 20:31:00 +03:00
a0b17981e3 feat: add ability to override oauth2 icon 2023-10-07 18:12:17 +03:00
c440f5bbd5 fix: whitelist environment variables instead of passing all of them
Earlier applied fix bc9682373d introduced
errors with interaction, because (in docker container) HOME variable was
passed also to subprocesses. This fix limits variables to be passed to
the whitelisted ones
2023-10-02 16:37:20 +03:00
8ff567cac3 feat: add __call__ method to printers 2023-10-01 15:14:18 +03:00
9fe760efdf feat: load http views dynamically (#113) 2023-09-30 01:24:04 +03:00
bc9682373d fix: processes in docker images and pass full environment to
subprocesses

Since 1.0.4 release devtools require systemd to be run in order to
create slice for unit
2023-09-29 03:57:26 +03:00
aedcbf1985 fix: fix documentation building 2023-09-28 15:09:33 +03:00
26b991bf47 feat: add pagination to packages list 2023-09-11 18:08:26 +03:00
8bf422b02a docs: update documentation to new api calls 2023-09-11 15:57:00 +03:00
0c920832c9 fix: add note about pacman configuration 2023-09-10 23:48:03 +03:00
bef8d33570 feat: improve template processing (#112)
* Improve template processing

* docs update, config validation rules update
2023-09-08 23:38:07 +03:00
b540ced77f perf: limit clone and fetch by the latest commit 2023-09-08 15:52:59 +03:00
723b6971dd fix: correct version check in postinstall script 2023-09-08 14:48:31 +03:00
59356e905a feat: allow to use one application for multiple repositories (#111)
* allow to use one application for multiple repositories

* update tests

* handle None append argument everywhere

* rewrite repository definition logic

* drop optional flags from docs

* support of new schema in systemd units

* add migration docs and ability to migrate tree automatically

* use repostory id instead

* verbose multiarchitectureerror

* object path support for s3 sync

* fix tests after rebase
2023-09-08 14:01:07 +03:00
99eecdebf3 feat: pagination support for logs request 2023-09-08 01:41:36 +03:00
5e42dd4e70 fix: mark failed packages as failed in console handler 2023-09-06 18:22:05 +03:00
4ec7e2d129 docs: mock cryptography import due to build errors 2023-09-05 18:37:46 +03:00
9a521af078 feat: show help message if no command specified 2023-09-05 18:26:22 +03:00
d1132b49fc feat: add ability to skip migrations
This feature can be used in order to handle conflicting migrations
2023-09-02 14:30:50 +03:00
2c21ae26c3 ci: publish docker image to ghcr 2023-08-28 03:21:25 +03:00
bba90b3eb8 Release 2.11.0 2023-08-27 02:12:21 +03:00
3cac53ac11 add ability to partition tree before calculationn 2023-08-27 01:55:57 +03:00
9fa6722eaa small improvements on code smell
* fix some grammar/typo errors
* change some statements to be more clear
* use pattern matching for enum processing
2023-08-25 04:15:10 +03:00
1d4ed0e0c3 force rtd theme
Since Aug, 22 rtd doesn't force its theme anymore, leaving it as default
2023-08-23 15:27:51 +03:00
2cda4a2469 use http client class for all http requests 2023-08-23 03:27:42 +03:00
9406537a15 bump pylintrc 2023-08-21 02:55:08 +03:00
598af7d9db verbose subprocess exception handle annd quite git 2023-08-21 01:35:43 +03:00
6530afbfc7 review exception raise
In some cases for better readability of logs, exceptions are now raised
without parent exception stacktrace. Also updated docs and contributing
guidelines
2023-08-20 17:03:46 +03:00
ad1c0051c4 Remote call trigger support (#105)
* add support of remote task tracking
* add remote call trigger implementation
* docs update
* add cross-service upload
* add notes about user
* add more ability to control upload
* multipart upload with signatures as well as safe file save
* configuration reference update
* rename watcher methods
* erase logs based on current package version

Old implementation has used process id instead, but it leads to log
removal in case of remote process trigger

* add --server flag for setup command
* restore behavior of the httploghandler
2023-08-20 03:44:31 +03:00
5b172ad20b update gh actions install script 2023-08-17 16:33:02 +03:00
42fccb76ef add dummy type fields for pkgbuild generators
This field is required in order to pass config validation in case if
section name differs from default one. Also by default keyring_generator
and mirrorlist_generator have been renamed to keyring-generator and
mirrorlist-generator respectively for consistence
2023-08-17 16:02:15 +03:00
c37f67c558 close descriptor after uploading archive on github 2023-08-15 02:31:46 +03:00
89d9b581bd contributing guide update 2023-08-14 02:51:14 +03:00
116dc0b329 resoolve dependencies by using local cache too (#107) 2023-08-14 02:31:24 +03:00
e3ed36fafd add ability to read values from environment variables
It makes sense to read some values from environment. In particular this
feature is useful in case of running application in containers in ci/cd

See #108 for more details
2023-08-14 01:48:08 +03:00
573ade4ba5 remove unused absolute path validator (#106)
Extracted path is always absolute, so there is no need to check it
2023-08-13 20:48:07 +03:00
9259d9c727 Local packages support improvements (#104)
* handle git author correctly
* make remote source required argument
2023-08-13 15:45:53 +03:00
c863ee063c make auth.salt parameter optional
Used implementation of the hasher includes salt itself, thus additional
salt is optional and can be safely (in terms of security) treat as empty
string
2023-08-11 16:31:47 +03:00
480c3a54b8 full support of pep517
Since llast upgrade build is broken. Lets fully migrate to
pyproject.toml. Note for maintaners: because data_files option is
deprectated (see https://github.com/pypa/setuptools/discussions/2648)
you will have to install files manually inside your packaging process
2023-08-11 03:55:31 +03:00
3b3ef43863 automatically bump pkgrel on version duplicates
The new --(no-)increment flag has been added to add, update and rebuild
subcommands. In case if it is true and package version is the same as in
repository, it will automatically bump pkgrel appending (increasing)
minor part of it (e.g. 1.0.0-1 -> 1.0.0-1.1).

Inn order to implement this, the shadow (e.g. it will not store it in
database) patch for pkgrel will be created
2023-08-08 03:14:47 +03:00
368db86dde Release 2.10.2 2023-08-08 02:54:23 +03:00
adf6a0a952 remove napoleon contrib dependency 2023-08-08 02:53:08 +03:00
575a618096 fix issues with remote pull triggers (see #103)
* The issue appears when repository contains PKGBUILD in root. In this
  case it will copy tree with loosing package information, because
  the repository will be cloned to temporary path with random generated
  name
* The issue appears when branch which is different from master is used
  for any reposittory with git files (e.g. single-pkgbuild repo or repo
  with submodules)
2023-08-08 02:34:44 +03:00
2c03354d4a Release 2.10.1 2023-07-28 03:21:19 +03:00
4008aa2e0a do not create application in shell handler
The main reason for having shell handler is to be able to fix if
something (e.g. migrations) goes wrong. In this way we need to reduce
actions inside this wrapper
2023-07-28 03:06:28 +03:00
9cb39f6767 rase 405 error in case if GET login method is used whereas no aioauth
library installed
2023-07-23 03:01:25 +03:00
c7de182f3d optimize schemas import 2023-07-23 02:24:39 +03:00
d21c3fdf9f Release 2.10.0 2023-07-22 05:28:57 +03:00
9f2fe219c8 add support of table filter controls (#101) 2023-07-21 02:10:26 +03:00
ad570aae0f remove unsafe flag from handlers
This flag became reduntant there and tree creation has been moved to
lock
2023-07-07 03:25:05 +03:00
116b65d92a fix code block in docs 2023-07-06 19:17:11 +03:00
5e5171cf3e add salt generator to setup command instead 2023-07-06 19:16:49 +03:00
af3360e84a register dependency package before build
If package has been added as dependency, the service miss remote as well
as causes some 400 errors in reporter
2023-07-06 03:11:19 +03:00
95f52f7ebe handle packages load from aur by package name also
In general package names array may not contain package base, thus it
leads to inability to load packages from aur by its base during update
process
2023-07-01 15:55:04 +03:00
f5fe200247 explicitly pass user agent for the arch linux sites requests 2023-06-26 02:52:08 +03:00
a1c12200b8 print configuration paths in dump command 2023-06-11 15:11:34 +03:00
09839f755a remove salt generation from users handler
It causes issues, because users handler is operating with service user,
but writtinng salt requires root privileges
2023-06-05 05:25:10 +03:00
fcd4d60cad complitely disable signature check for local repository in devtools
It appears that with optional level pacman still tries to validate the
key, which can lead to errors whille processing in docker container
2023-06-05 04:41:03 +03:00
3681473942 packager documentation update 2023-06-05 03:40:02 +03:00
4dd5a1e82e packagers support (#100) 2023-06-05 02:37:19 +03:00
cbd1d3d5b8 use autodoc_mock_imports instead of custom mocking for docs 2023-05-31 19:17:16 +03:00
e3347aec2d use cached property instead of custom __getattr__ implementation 2023-05-31 19:17:16 +03:00
3ad6cd27c6 support check dependencies 2023-05-31 19:17:16 +03:00
54a68279be mimic parent arguments during spawn process (#99) 2023-05-30 18:09:35 +03:00
d99091a3b4 do not terminate child process explicitly
This feature sometimes causes the main process termination. Since the
child process has been already terminated (or going to) there is no need
to terminate it manually
2023-05-29 17:27:04 +03:00
be6cf5b8af fix case where it was impossible to create session if user and password
are required

Issue appears if auth is enabled and unix socket is disabled and caused
by d81e91e117
2023-05-29 17:23:57 +03:00
91e548569d runtime logger handler selector 2023-05-29 03:41:11 +03:00
6c3b2ef266 add repod reference to faq 2023-05-26 12:58:25 +03:00
785607c70b allow to filter packages for rebuild by their statuses 2023-05-25 17:41:54 +03:00
d22a3152db fix documentation error 2023-05-25 16:31:47 +03:00
adb5b58a1d Support type triggers (#96)
* implement mirrorlist package generator

* implement keyring package generator

* docs update

* do not skip empty lines

* fill remote source for local packages

* faq update
2023-05-25 16:27:16 +03:00
8b2601beaa switch to explicit journald logger instead of syslog 2023-05-25 04:44:38 +03:00
9116a4370e update optional dependencies list 2023-05-24 15:39:36 +03:00
da93fdc77a bump rtd image 2023-05-24 03:58:14 +03:00
8bbd643551 update packaging files
also remove makedependencies after installation in docker
2023-05-22 18:23:06 +03:00
6834dd442c Release 2.9.0 2023-05-22 17:04:32 +03:00
d23e3cbbea update models index 2023-05-22 17:02:55 +03:00
6bc6bdaeae migrate to the latest devtools & archlinux git changes
This migration includes
* removal of community repository as it is no more
* fixed paths for devtools configurations
* migration of archlinux packaging git url
2023-05-22 16:51:27 +03:00
7458c73c7d disable debugpanel for now 2023-05-04 14:30:27 +03:00
2cecbb3d53 do not assign path in context manager as it is deprectated 2023-05-04 14:29:39 +03:00
c73a6c7bae PEP-673 use Self as return type for classmethods (#94)
* PEP-673 use Self as return type for classmethods

* add dummy test file

* remove python3.10 compat
2023-05-04 03:28:08 +03:00
0b70b5af45 fix flapping tests for oauth
Original implementation sends requests to httpbin which sometimes might
not be available. With proposed changes we are blocking redirects and
just check request itself
2023-05-03 14:53:35 +03:00
fde75a14c2 PEP-561 complaint: add py.typed marker 2023-04-17 18:56:49 +03:00
1e0d1a5a32 fix some pycharm warnings 2023-04-17 02:23:50 +03:00
75919637e8 suppress status errors also if option is set 2023-04-15 05:05:55 +03:00
467d109cfc add referencne to api docs to docs 2023-04-14 05:06:53 +03:00
a131c77699 add reference to api documentation from main page 2023-04-12 04:22:49 +03:00
10fbc31d2a PEP-585 complaint: remove type aliases (#93) 2023-04-12 04:09:28 +03:00
7e0d12b8b1 docs update 2023-04-10 21:13:43 +03:00
7ab00ee579 Release 2.8.0 2023-04-09 13:06:54 +03:00
2d62148ee6 try to remove unknown packages from api 2023-04-06 18:14:36 +03:00
c1f2d5ff4a hide cookie key and salt from config output 2023-04-06 00:31:50 +03:00
2888649ced optimize imports 2023-04-06 00:24:39 +03:00
63855f5964 argument annootation update 2023-04-06 00:24:39 +03:00
8bf665d7d3 fix license url 2023-04-06 00:24:39 +03:00
a7ac77ce4d extract schemas automatically from views 2023-04-06 00:24:39 +03:00
fc01bf3d1c use api generated docs instead of comments (#92) 2023-04-06 00:24:39 +03:00
d81e91e117 execute request in context methods instead of handling them each time
manually
2023-03-23 12:43:04 +02:00
57f62ba163 Release 2.7.1 2023-03-06 01:15:47 +02:00
ded896ee1b gracefully terminate web server
In previous revisions server was terminated by itself, thus no lock or
socket was removed. In new version, graceful termination of the queue
has been added as well as server now handles singals
2023-03-06 01:13:41 +02:00
1fdcea0524 replace InitializeException with InitializeError in docs 2023-03-02 11:07:59 +02:00
a93f43dcd0 simplify login ttl processing 2023-02-24 16:52:55 +02:00
20974dae6f add more validation rules 2023-02-23 15:18:56 +02:00
cbcfff27b8 add ability to read cookie secret from config 2023-02-22 18:47:56 +02:00
96f394bab0 Release 2.7.0 2023-02-20 03:05:08 +02:00
aae3c82f3d update dependencies before build (#91)
Old implementation has used add step in order to fetch dependencies,
which could lead to build errors in case if dependency list was updated.

New solution uses dependencies which are declared at current version and
fetch them (if required and if enabled) before update process.

Closes #90
2023-02-12 06:02:30 +03:00
ab9e1fb1bd handle .gitignore file correctly in remote push trigger 2023-02-11 04:41:24 +02:00
82322f7a6c mask mypy warning
The newest mypy produces the following warning:

src/ahriman/application/handlers/search.py:43: error: Non-overlapping identity check (left operand type: "Union[_DefaultFactory[Any], Literal[_MISSING_TYPE.MISSING]]", right operand type: "Type[List[Any]]")  [comparison-overlap]

which is more likely caused by updated dataclass models to protoocol (however decorators are still calllable). This commit masks problematic line from checking
2023-02-09 22:46:08 +02:00
125da217d3 hide passwords and secrets from repo-config subcommand by default 2023-02-05 16:44:48 +02:00
d113c65c81 note about local database update (see #85) 2023-01-31 14:47:58 +02:00
050041b2de handle architecture specific fields for dependencies
This change requires srcinfo at least 0.1.2 version. Unfortunatelly aur
api don't support architecture specific arrays for now, so we just leave
it as is

Closes #82
2023-01-31 14:34:09 +02:00
e0ed636d7e filter empty packages from database
In some cases (e.g. during addition of the package to build queue) we don't have
full information about package inself; in these cases we produce lines
with empty architecture, which duplicates normal ones.

This commit changes architecture column type to required and also
filters packages which don't have architecture set yet.

Closes #83
2023-01-30 17:57:13 +02:00
61feb2ebc7 trim version from provides list
Closes #87
2023-01-30 17:27:34 +02:00
da1c6b0101 add ability to suppress http logging errors (#86) 2023-01-30 17:19:01 +02:00
c1718b3862 calculate dependencies based on package information (#89) 2023-01-30 17:28:05 +03:00
34fe8128aa remove debug line 2023-01-27 16:41:41 +02:00
a78c48ed4d Release 2.6.1 2023-01-25 15:28:27 +02:00
e368396653 make oauth client trully optional (#84)
Same old song, after migraiton to packages some optional modules are
being imported globally which lead to making hard dependency
2023-01-25 15:25:42 +02:00
f4abd83568 enable lock for web service 2023-01-18 01:39:55 +02:00
e6888ba788 Release 2.6.0 2023-01-16 01:35:12 +02:00
a78050c1bf add notes about non-x86_64 architecture setup 2023-01-15 18:16:29 +02:00
93876307f8 add ability to override pacman mirror in devtools configuration
This commit also extends configuration of the multilib option, adding
the ability to exlcude multilib repository from repositories list

Note, that in order to support repository list and mirror correctly,
alpm configuration section is now architectture specific
2023-01-15 18:05:15 +02:00
4d482520cd add note about other authroization options to gitremote triggers 2023-01-13 17:27:19 +02:00
461fbd40ce consider vcs flag and vcs_allowed_age during local packages update 2023-01-12 15:37:05 +02:00
419da3db89 add ability to check for service updates 2023-01-12 15:37:05 +02:00
00ca06ffab subcommand review
Some commands have been moved to another group and thus having another
default name (old subcommands are still available...for now):

* daemon -> repo-daemon
* key-import -> service-key-import
* repo-clean -> service-clean
* repo-config -> service-config
* repo-config-validate -> service-config-validate
* repo-setup -> service-setup
* repo-shell -> service-shell
* version -> help-version
2023-01-12 15:37:05 +02:00
5a05c8ce91 expose trigger configuration schema
Note that this commit contains the following breaking changes:

* remote pull and remote push triggers are now enabled by default (with
  empty target list)
* remote pull and remote push triggers now require target option to be
  set (old behaviour had fallback on `gitremote`)
* validation is now considered to be stable, so it is enabled by default
  in docker image (can be disabled however)
2023-01-10 03:33:52 +02:00
b09aea13af add config validator subcommand (#80)
* add config validator subcommand

* add --exit-code flag

* docs & faq update
2023-01-09 18:22:29 +03:00
04a52f759d sort unsafe commands response 2023-01-04 18:00:10 +02:00
ef6cf0f00b review unsafe commands access
Some commands were made unsafe in old versions, but nowadays they can be
run without having special privileges.

There was also a bug in which status commands were not available if you
are not ahriman user and unix socket is used. It has been fixed by
switching to manual socket creation (see also
https://github.com/aio-libs/aiohttp/issues/4155)
2023-01-04 17:45:44 +02:00
ab650b7417 copyright update 2023-01-04 03:43:10 +02:00
7ca5b3a363 Release 2.5.4 2023-01-03 01:59:25 +02:00
666fa98075 add notes about documentation and methods inside class
Because I always forget which way I used before
2023-01-03 01:53:10 +02:00
684ef33dbc Correct way to allow setting context with existing
This reverts commit 11732a8609.

Original solution has introduced special workaround (strict flag) which
contradicts the concept of immutable context. Moreover, it introduces
possible side-effects, because child process will use the one set by
parent instead of having own one.

The correct solution is to re-create context in process entry point

Sorry, it was Jan 1 and I was drunk :(
2023-01-03 00:48:14 +02:00
cf35addaa5 Release 2.5.3 2023-01-02 03:24:11 +02:00
11732a8609 allow setting context with existing
In case of running command from web interface, it will raise exception
because context has been copied with subprocesses
2023-01-02 03:21:15 +02:00
64cc8fd6b0 Release 2.5.2 2023-01-02 01:57:09 +02:00
4202751e9c remote all gitfiles in git remote trigger
In case if there is .gitignore file with asterics, the pkgbuild upload
would not appear
2023-01-02 01:45:50 +02:00
41515f6c95 Release 2.5.1 2022-12-31 14:58:37 +02:00
ac92b506e0 remote log for calculate version as it cleans logs 2022-12-31 14:48:21 +02:00
5bbd1ad9a9 fully lazy handle load
In case of immediate handle load it would try to sync databases (or at
least to create database files), which is not possible in case if
command is run as non-ahriman user. This commit makes handle load lazy
and allows to run some commands as non-ahriman user
2022-12-31 14:48:21 +02:00
541d8d9b39 Release 2.5.0 2022-12-31 02:02:37 +02:00
e41dd09a8a force upgrade sphinx documentation 2022-12-30 22:58:13 +02:00
8e65263b90 add completion files generated by shtab 2022-12-30 21:19:23 +02:00
afc488255c allow 3 symbols for package search 2022-12-30 21:19:23 +02:00
effc120a43 improve VCS packages checks
* Unlike older version, currently service will always try to pull AUR
  package to check version. Previously if no-vcs flag is set, it would
  ignore VCS packages completelly
* Introduce build.vcs_allowed_age option. If set, it will skip version
  calculation if package age (now - build_date) is less than this value
2022-12-30 21:19:23 +02:00
4b27e102ef change another boolean info option to boolean action 2022-12-29 03:15:48 +02:00
e0126bb811 add repo-structure subcommand
This commit also changes Tree class, replacing load method by resolve
2022-12-27 10:35:03 +02:00
8c04dc4c2a fix property description in docs 2022-12-26 02:32:14 +02:00
83e9d7c523 write patches via gitremote push trigger (#79)
* write patches via gitremote push trigger

* implement context variables intead of custom database class
2022-12-25 02:10:38 +03:00
9be4a89c08 Release 2.4.1 2022-12-11 05:17:10 +02:00
0f8596db1e replace alert bodals with toasts 2022-12-09 11:33:19 +02:00
c403c45d72 remove badges from status page 2022-12-09 00:58:03 +02:00
00dbd90953 check that package has been created during setup workflow 2022-12-06 11:09:56 +02:00
3e299d9685 Release 2.4.0 2022-12-05 00:25:53 +02:00
e20637f7ad do not update database via pacman, use ahriman's own databses 2022-12-04 23:45:10 +02:00
5a09d46f9a Some minor documentation related fixes
* Improve some wording (again)
* Change default type for refresh option to False (does not affect
  behavior)
* Update docstrings to reflect last changes
* Configuration.__convert_path has been replaced by shlex
* aiosecurity functions support kwargs now
2022-12-04 02:10:46 +02:00
90be3276dd improve wording in documentation 2022-12-02 15:45:01 +02:00
a4f646eb2a do not trigger update on sign command 2022-12-02 01:41:23 +02:00
ebd06cb443 improve setup command by --makeflags-jobs argument and fix repository sign on creation 2022-12-02 01:41:23 +02:00
fe66c6c45c implement support of unix socket for server
This feature can be used for unauthorized access to apis - e.g. for
reporting service if it is run on the same machine. Since now it becomes
recommended way for the interprocess communication, thus some options
(e.g. creating user with as-service flag) are no longer available now
2022-12-02 01:41:23 +02:00
bba58352e0 do not invoke configuration write in case if no salt or user was written 2022-12-02 01:41:23 +02:00
41cc58ed31 add rebuild implementation to interface 2022-12-02 01:41:23 +02:00
20e45845ba make package actions as dropdown 2022-12-02 01:41:23 +02:00
9fa1fa108f add key-import button to interface 2022-12-02 01:41:23 +02:00
577bd9e5f8 add demos links 2022-11-24 02:38:33 +02:00
20b9c1fa4a add security notes 2022-11-24 02:38:33 +02:00
a7c9183aa0 add curl examples to web views 2022-11-24 02:38:33 +02:00
9e0dd3ae97 build docs together with web views 2022-11-24 02:38:33 +02:00
f4e4e88e82 change respone for service requests 2022-11-24 02:38:33 +02:00
2684e4b3f4 add fallback for copying to clipboard 2022-11-24 02:38:33 +02:00
45f5006db3 add show/hide password button 2022-11-24 02:38:33 +02:00
b26aa2145f update web preview picture 2022-11-24 02:38:33 +02:00
4462eba860 render httpunauthorized as html in plain http requests 2022-11-22 23:40:27 +02:00
f2c23bad17 allow scrolling with fixed copy button position 2022-11-22 22:20:21 +02:00
1603086b96 change logging module imports 2022-11-22 22:20:21 +02:00
b6f6ee8c76 change wording for package actions 2022-11-22 15:46:49 +02:00
b71d1f6e3d fix login and logout buttons decorations 2022-11-22 11:17:59 +02:00
7883746e53 add more notes about docker 2022-11-22 10:49:46 +02:00
ae9118654d check log record in handler instead of client 2022-11-22 02:30:37 +02:00
81fa73f725 ask users to repeat password
In case if password is asked via getpass, it is possible to make typo
and user will not see the mistake. In order to avoid it, additional
confirmation has been added
2022-11-22 02:19:37 +02:00
14cb548c3b Extended package status page (#76)
* implement log storage at backend
* handle process id during removal. During one process we can write logs from different packages in different times (e.g. check and update later) and we would like to store all logs belong to the same process
* set package context in main functions
* implement logs support in interface
* filter out logs posting http logs
* add timestamp to log records
* hide getting logs under reporter permission

List of breaking changes:

* `ahriman.core.lazy_logging.LazyLogging` has been renamed to `ahriman.core.log.LazyLogging`
* `ahriman.core.configuration.Configuration.from_path` does not have `quiet` attribute now
* `ahriman.core.configuration.Configuration` class does not have `load_logging` method now
* `ahriman.core.status.client.Client.load` requires `report` argument now
2022-11-22 02:58:22 +03:00
2eb93a6090 Release 2.3.0 2022-11-16 00:53:48 +02:00
dd6ef38c99 remote threadname from logging
Since application is mostly singlethreaded it makes no sense to log it
2022-11-14 23:21:06 +02:00
415dc42313 Release 2.3.0rc4 2022-11-14 01:02:27 +02:00
3e1af17796 fix case when no files were commited in remote push trigger
The issue appears together with --intent-to-add flag for adding new
files. Original testing has been performed by having already added new
files, thus it passed all checks.

This commit also adds `commit_author` option which will allow to
overwrite the author.
2022-11-14 00:59:43 +02:00
880cebe54f Release 2.3.0rc3 2022-11-11 21:20:55 +02:00
cbcc796a3a rollback cwd parameter for clone 2022-11-11 21:19:27 +02:00
dc8a52f6c0 Release 2.3.0rc2 2022-11-11 17:25:11 +02:00
34c93e53cc Fix issue when there is no cached source directory yet (closes #75) 2022-11-11 17:23:15 +02:00
f7ec24523b Release 2.3.0rc1 2022-11-11 16:36:13 +02:00
f817b32976 use intersection of from_database and depends_on filters for the rebuild subcommand
Old logic used OR condition, i.e. if set from-database, it would ignore
the --depends-on flag. In new logic it calculates dependencies based on
the package list, which can be retrieved from database
2022-11-11 16:02:19 +02:00
9fc2b681d4 limit max module size and improve some help messages 2022-11-11 16:01:54 +02:00
59ff0589ab speedup docker build command by adding dockerignore listing 2022-11-11 12:47:31 +02:00
1b53de6f2b man update 2022-11-10 20:10:07 +02:00
41080c5ff8 add exec to shell subcommand 2022-11-10 18:52:55 +02:00
791ce4f242 make exception optional argument for check_output method 2022-11-10 18:05:32 +02:00
b75bd30658 replace several store_true keys to booleanoptionalaction alternative (#74) 2022-11-10 18:34:01 +03:00
b3b3cad706 write .makepkg.conf to home dir instead of repository root (#72) 2022-11-08 17:02:13 +02:00
82b932371b add ability to use ahriman pacman database instead of system one (#71)
By default this feature is enabled. On the first run it will copy (if
exists) databases from filesystem to local cache (one per each
architecture). Later it will use this cache for all alpm operations. In
order to update this cache, some commands (mainly package building)
provide `-y`/`--refresh` option which has same semantics as pacman -Sy
does.

Note however that due to extending `Pacman` class some methods were
renamed in order to be more descriptive:
* `Pacman.all_packages` -> `Pacman.packages`
* `Pacman.get` -> `Pacman.package_get`

This commit also adds multilib repository to the default docker image
which was missed.
2022-11-08 17:26:51 +03:00
45fb2f3c46 improve repo-setup command
* Move devtools executable to ahriman home, because we don't really
  need to use executable inside root
* Use named sudoers file instead of single file. It will allow easily to
  remove file as well as use setup command for several
  repositories/architectures
2022-11-06 14:25:44 +02:00
4a5b9d9fa1 fix case in which if no source PKGBUILDs were updated, an exception will occur 2022-11-03 03:39:54 +02:00
2f8316ecb0 faq update 2022-11-02 17:15:17 +02:00
77ad35fce8 docs update 2022-11-02 04:17:26 +02:00
48da4646cf change gitremote api to be same as report and upload
These changes are keeping fallback to old settings, but will allow to
run multiple git targets with different settings
2022-11-02 04:09:42 +02:00
3d98dd267a fix update handler tests
If daemon tests are run before the update handler it causes test
failure, because there are other calls
2022-10-31 11:51:12 +02:00
09678a3ae1 add possibility to run full update
In case if packages are not set from web, the spawner will run full
repository update
2022-10-31 02:41:24 +02:00
8e2732f6fe add daemon subcommand
This command emulates default systemd timer and can be useful in docker
container in order to run 24/7
2022-10-31 01:38:01 +02:00
73e311a41c implement single-function patches (#69) 2022-10-30 03:11:03 +03:00
1e8388af5d drop ahriman.core.triggers.Trigger.run method
In order to force new triggers to use on_result method, the old method
has been removed. However, default on_result method still checks if the
old method exists and tries to run it
2022-10-19 20:07:31 +03:00
c1d74726b7 fix rtd docs building
Commit 9d016f51b5 introduced kw_only
dataclasess which require python 3.10+
2022-10-18 02:24:18 +03:00
f2ddcc6d23 disallow no values in configuration
This option could lead to missing warnings about missing or invalid
configuration values because code usually expects that values are exists
and not empty unless it is explicitly specified.

However, pacman configuration still requires this option in order to be
able to deal with boolean values
2022-10-18 02:13:01 +03:00
a5ce6b78dd Add gitremote triggers (#68)
* add gitremote pull trigger

* add push gitremote trigger

* docs update
2022-10-18 01:46:27 +03:00
1a83dd6f5a extend triggers to on_start and on_stop methods
This commit also replaces old run method to new on_result
2022-09-26 01:22:54 +03:00
16a33f7729 add minimal install step to workflow 2022-09-17 14:52:08 +03:00
fb21b1da53 make sqlite import consistent 2022-09-17 14:32:21 +03:00
8394004943 Release 2.2.2 2022-09-17 04:05:06 +03:00
75c6bf6119 skip architecture list patching in case if any architecture is set 2022-09-17 04:04:28 +03:00
7e20ff5184 Release 2.2.1 2022-09-14 04:49:08 +03:00
757614f5a0 docs update 2022-09-14 04:48:11 +03:00
43166e5f94 Release 2.2.0 2022-09-14 03:28:28 +03:00
43696b9920 Make optional dependencies trully optional (#67)
The issue appears when there is no boto, jinja and some other libraries
are not installed because the classes which use these libraries are
still being imported inside the package file. The fix removes those
imports from package root, because they should not be here, in fact,
content of report and upload packages must be imported only inside the
trigger class and only if they are actually required

This commit also adds setuptools as required dependency since it is used
for some parsers (previously it was provided dependency)
2022-09-11 01:44:06 +03:00
8befee58fe patch architecture list in runtime (#66) 2022-08-09 15:18:20 +03:00
9d016f51b5 frozen dataclasses 2022-07-26 14:40:28 +03:00
c5fbccd519 reduce docker image size a bit 2022-07-18 11:42:26 +03:00
eae5748a30 Release 2.1.0 2022-07-02 15:42:39 +03:00
695ef708b6 simplify tmpdir method 2022-06-28 19:11:38 +03:00
26408e82c0 review loggers once more
This commit makes loggers like java.util.logging with fully qualified
logger name which is created by LazyLogging trait
2022-06-28 11:00:45 +03:00
7b647a9b5a fix case with package name which cannot be downloaded
(without special settings)

The issue appears if file or its version contains one of special URI
characters, e.g. +. Theu will be interpreted as query parameters by
(some) servers (e.g. S3 works in this way). In this commit we rename
archive to the one with safe name.
2022-06-27 18:53:48 +03:00
fac228d6c6 review loggers once more
This commit makes loggers like java.util.logging with fully qualified
logger name which is created by LazyLogging trait
2022-06-27 01:41:49 +03:00
eb5ac5a52b bump web libraries
also encode strings for the views
2022-06-24 12:03:38 +03:00
047925dcfe review loggers 2022-06-21 11:48:42 +03:00
b8d2775050 replace if with while for telelgram reporting 2022-06-10 12:02:00 +03:00
bf959ceb5f Release 2.0.0 2022-06-05 20:46:32 +03:00
945b6d0ac0 small docs update 2022-06-04 15:24:14 +03:00
5df9f30e37 do not pass timestamp to pretty_datetime functioon 2022-05-31 21:26:39 +03:00
1ea3911531 rewrite api under single /api endpoint 2022-05-29 17:15:49 +03:00
d7966e419d add shell and version parser 2022-05-27 18:34:07 +03:00
3a5268993e update readme 2022-05-22 16:00:24 +03:00
ad84895e18 do not bump timestamp on empty updates 2022-05-21 04:19:04 +03:00
b1dfafe275 dynamic html load (#63)
* dynamic html load
* split by classes
2022-05-20 22:29:36 +03:00
375f9fcfb7 add ability to run only speicifed triggers from command line
This commit also restores repo-report and repo-sync subcommands
2022-05-12 18:43:36 +03:00
04dcaa93ab fix case when provided trigger path is directory
If trigger is directory and we have permissions to read it, the loaded
will try to load this from it and will fail with IsADirectoryError
2022-05-12 07:22:50 +03:00
f42c2c57fb add not about pacman database update 2022-05-11 04:30:24 +03:00
dc3562a4ec add contribution guide 2022-05-11 03:17:37 +03:00
dda94f8f9e Release 2.0.0rc11 2022-05-10 06:03:33 +03:00
709db6a5ed fix bug with checking file
The bug appear when the file exists or doesn't, but we don't have
permissions to read it. This one must be treated as missed permission
2022-05-10 06:01:41 +03:00
89a2d8e298 Release 2.0.0rc10 2022-05-09 21:51:35 +03:00
b9cd98235e triggers implementation (#62) 2022-05-09 20:00:20 +03:00
1905360f8f Release 2.0.0rc9 2022-05-08 03:58:53 +03:00
a7018d9f7d fix error with missing sources
In case if package has local cache it will fail to load because no
remote source set. Particially this case can be observed during tree
load
2022-05-08 03:56:54 +03:00
73057bc08d Release 2.0.0rc8 2022-05-06 20:55:54 +03:00
7f87863734 shorten public imports 2022-05-06 04:08:05 +03:00
2dac5a2520 Docs update (#61)
* Improve sphinx documentation

* update faq formatting

* fix setup doc

* fix docs according to the generated htmls
2022-05-06 02:54:37 +03:00
720edc24ba correct archllinux wording in readme 2022-05-06 02:54:37 +03:00
fe9711d24f add __all__ attribute 2022-05-06 02:54:37 +03:00
c73a2a4aa9 add note about ahriman to index page 2022-05-06 02:54:37 +03:00
571f720ae2 Complete official repository support (#59) 2022-05-03 00:49:32 +03:00
5030395025 rename classes in order to make documentation reference work 2022-04-18 05:30:02 +03:00
03633d47ea readthedoc integration 2022-04-18 04:39:40 +03:00
1a575d6db8 move documentation to tox 2022-04-18 01:48:36 +03:00
cdc018ad07 apply data migration in the same transaction block with schema migration 2022-04-18 01:19:38 +03:00
f806c8918e fix target naming 2022-04-18 01:19:20 +03:00
4daff81d5f Docstring update (#58)
* migrate docstrings from reST to google format

* add raises note

Also change behaviour of the `from_option` method to fallback to
disabled instead of raising exception on unknown option

* fix part of warnings for sphinx

* make identation a bit more readable

* review fixes

* add verbose description for properties to make them parsed by sphinx extenstion

* add demo sphinx generator
2022-04-17 20:25:28 +03:00
06bd29b78d Release 2.0.0rc7 2022-04-11 00:48:08 +03:00
c67ac3730c docs update 2022-04-11 00:46:46 +03:00
c094d4ee79 add backup and restore subcommands 2022-04-10 21:34:34 +03:00
3cb479ba4b merge restore to rebuild commannd 2022-04-10 01:51:12 +03:00
307a7f4a71 Release 2.0.0rc6 2022-04-09 17:34:23 +03:00
25734876de do not render failed packages in jinja (#57)
basic templates require package info which is unavailable if package
wasn't built
2022-04-09 17:31:13 +03:00
53df735eb2 Release 2.0.0rc5 2022-04-08 04:42:05 +03:00
fb7275f9dd change telegram default index to telegram-index 2022-04-08 04:32:34 +03:00
f01af5f54a force git run from the same dir to clone 2022-04-08 04:04:06 +03:00
1abe8d291f fix users migration 2022-04-08 03:45:17 +03:00
1a83e55d64 add telegram integraion 2022-04-08 03:41:07 +03:00
b8e17c4879 Release 2.0.0rc4 2022-04-08 01:14:35 +03:00
bee41dcc55 trim versions before dependency list calculation
When dependencies list contains same package with version it tries to
find packages which don't exists
2022-04-07 20:32:55 +03:00
9f7995fb2f add support of repository restoration 2022-04-07 04:49:07 +03:00
9ce1c36f35 add support of officiall repositories api 2022-04-07 04:19:37 +03:00
4990ce4198 fix descriptions 2022-04-06 01:48:03 +03:00
8f18ead4cc Release 2.0.0rc3 2022-04-04 02:40:17 +03:00
7ea50887a4 allow any tag for push 2022-04-04 02:39:56 +03:00
97ec5bfa41 Release 2.0.0rc2 2022-04-04 02:27:19 +03:00
5fcc15191a change regex for sed 2022-04-04 02:26:42 +03:00
c5f086a7c6 Release 2.0.0-rc1 2022-04-04 02:18:31 +03:00
432ca0cc48 better processing for subcommands
Old versions cached full output to memory and only after that printed it
into log. This behaviour causes issues in case if operation stucks and
you would need to find the step at which it does. New check_output
method uses Popen directly and iterates over stdout lines

Also changed behaviour from merging stderr into stdout to separate
stderr logging.

Any other behaviour of the function must be the same.

Also changed GPG.key_import method to disable local signing since it
seems it is useless (and may break process in case if there is no
private key)
2022-04-04 00:03:22 +03:00
1a0322b32e docs update 2022-04-03 01:44:11 +03:00
fc086c0d87 remove implicit user from docker 2022-04-01 18:39:24 +03:00
d5503b22ba add configurable exit codes to some commands (#55) 2022-04-01 18:30:11 +03:00
a132b1544a create user in docker container
also fix user reading and add nocolor flag by default
2022-03-31 03:25:53 +03:00
63acae4b1c configure docker to work with tags 2022-03-31 02:19:48 +03:00
8e6473d2a0 add help command 2022-03-31 02:18:39 +03:00
fdcbcc4541 update license years 2022-03-31 01:49:31 +03:00
83931f5cf4 port part of settings to database (#54) 2022-03-31 01:48:06 +03:00
d4eadf0013 migrate to tox
this also requires to move default configuration files to share/ahriman.
Thus the following features have been added
* default configuration is not stored in /usr/share/ahriman/settings
* package installed via PKGBUILD now copies files from /usr
* configuration class now fallbacks to default in /usr
2022-03-21 04:38:42 +03:00
04174a3e6d deprecate init/repo-init command
In current workflow you need to run setup to run init (because of
repository name), but you need to run init before setup (because of
repository tree rights).

New solution just add `Repo.init()` method call to setup subcommand
after config reload to make sure that repository name has been applied.
In addition chown method as well as setuid method for check_output have
been added.
2022-03-21 01:32:11 +03:00
041b3824c1 enable privileged mode for the docker 2022-03-20 04:05:43 +03:00
a11cce43ff fallback to AUR source in case of PermissionError exception 2022-03-20 03:46:56 +03:00
1388df9a7e add fallback for utf option 2022-03-20 03:16:33 +03:00
6ee1c8ef5a replace pspec with spec 2022-03-20 03:08:51 +03:00
a7c6d95b34 add console printer
also add python-requests as explicit dependency and escape symbols in
repository name for badges in default tempate
2022-03-20 02:31:50 +03:00
060c7412b1 ALLOW_AUTO_ARCHITECTURE_RUN flag for unsafe commands 2022-03-19 03:08:45 +03:00
93406483fe docker hub integration 2022-03-14 00:08:21 +03:00
046febc440 add docker support (#52)
* add docker support

* make shellcheck happy
2022-03-13 23:43:25 +03:00
9964a96296 strict test checks 2022-03-04 02:04:52 +03:00
9529525cb5 set success status on up to date packages 2022-02-06 06:22:58 +03:00
fa4c1c6205 Release 1.8.0 2022-02-06 05:45:50 +03:00
f9b1d89756 update for new aiohttp api 2022-02-06 04:05:33 +03:00
9197b416e6 use own aur wrapper (#49) 2022-02-06 03:44:57 +03:00
f54a2fe740 Release 1.7.0 2021-12-26 02:01:09 +03:00
d1f990eac8 make mypy happy 2021-12-26 01:58:55 +03:00
1e85c1db70 handle dependencies recursively 2021-12-22 19:35:09 +03:00
32aaa4a1f8 initial implementation of the local git clones (#48) 2021-12-22 15:56:24 +03:00
a9e20f0958 do not read aur_url from settings, use repository property instead 2021-11-15 11:27:41 +03:00
32b129a806 Release 1.6.4 2021-11-10 21:29:45 +03:00
2752e68ade handle packages which have been removed from the repository (#45)
* handle packages which have been removed from the repository

* manually remove packages which have been removed from the base
2021-11-10 01:37:25 +03:00
5b678149dc Release 1.6.3 2021-11-04 21:32:27 +03:00
79e1cff421 take python laziness into account 2021-11-04 21:30:34 +03:00
2e07de4a12 Release 1.6.2 2021-10-28 03:20:52 +03:00
7e3ef889e8 improve configuration extension
* Allow spaces in lists. This feature has been done in the way as shell
  interprets arguments by using quotation marks
* Clear current content on reload
2021-10-28 03:19:50 +03:00
52b54a9d05 add nginx configuration to the faq 2021-10-27 03:35:33 +03:00
c0f7f81050 Release 1.6.1 2021-10-27 03:16:53 +03:00
38af344bde update license headers 2021-10-27 03:14:39 +03:00
62496478ae add update printer which will print current version if any 2021-10-27 03:11:43 +03:00
ce48169aad use PackageSource enum for Package.load method
When using add function it sill tries to load data with invalid source
2021-10-27 02:49:23 +03:00
21845bc934 Release 1.6.0 2021-10-27 01:59:36 +03:00
249003de0a drop no-quiet option and change tree_create message error to warn 2021-10-27 01:57:54 +03:00
d8704e9c75 remove help sample from readme because it changes faster than om able to maintain it 2021-10-26 04:53:45 +03:00
0a8b172e9c unify aur.search method
due to specific of the AUR API in order to reduce the code we are using
own wrapper and work with it instead of direct library calls
2021-10-26 04:49:55 +03:00
7d782f120d Add ability to show more info in search and status subcommands
This feature also introduces the followiing changes
* aur-search command now works as expected with multiterms
* printer classes for managing of data print
* --sort-by argument for aur-search subcommand instead of using package
  name
* --quiet argument now has also --no-quite option
* if --quite is supplied, the log level will be set to warn instead of
  critical to be able to see error messages
* pretty_datetime function now also supports datetime objects
* BuildStatus is now pure dataclass
2021-10-26 04:27:36 +03:00
9057ecf67a always update environnment before any action 2021-10-24 04:14:57 +03:00
35df354c14 split application class into traits 2021-10-23 13:44:57 +03:00
4d4e5e9dde add patches to clean command 2021-10-20 03:22:16 +03:00
ff24188ca1 add ability to download package from external links (e.g. HTTP) 2021-10-20 03:09:58 +03:00
9d4f85624d add ability to read argument list from file 2021-10-20 02:15:59 +03:00
295f810222 logger improvements
* remove build log since it has no usages actually (replaced by root
  logger)
* decrease boto3 log levels to INFO by default to reduce noice
2021-10-20 02:12:49 +03:00
d8523bd83b always return json in responses 2021-10-20 02:12:39 +03:00
be017ed102 Release 1.5.0 2021-10-18 03:48:24 +03:00
c73f24f8c6 minor architecture description update 2021-10-18 03:35:39 +03:00
0d806e3471 add repo-status-update subcommand 2021-10-17 06:38:49 +03:00
20962f0385 allow to use multiple upload and report targets with the same name
In this feature target option must allways point to section name instead
of type. Type will be read from type option. In case if type option is
not presented it will try to check if section with architecture exists
(e.g. target = email, section = email:x86_64); if it does, the correct
section name and type will be used. Otherwise it will check if the
specified section exists; if it does, seection name and type will be
returned.
2021-10-17 06:06:08 +03:00
fd38dfd176 split github upload into generic http method and github specific
We might use some features from the http upload for another parser
2021-10-15 23:36:26 +03:00
5f7f58041d docs update 2021-10-15 04:55:46 +03:00
233b1f7f39 disallow to create tree in case of unsafe run 2021-10-14 04:53:09 +03:00
a83f1d5aa5 use generic removal method 2021-10-14 04:08:21 +03:00
be09c04e78 change method spelling
in order to sort method correctly we are going to use the following
namiing schema:

{subject}_{action}_{details}

This schema still have some exceptions, e.g. single word methods, bool
methods (is_) and getters in case if they are singular (i.e. there is
no any other method with this subject)
2021-10-14 04:01:54 +03:00
bfbbb987ad add test for every file 2021-10-14 03:34:12 +03:00
04f365f1a6 aggressive small case 2021-10-14 03:13:15 +03:00
86bd49ed1b exactly one called with instead of last call check 2021-10-14 03:12:45 +03:00
f6ad609616 github upload support (#41) 2021-10-14 02:30:13 +03:00
2f5790f69f add ability to add manually stored packages (#40)
* add ability to add manually stored packages

* update tests

* handle manual packages in remove-unknown method

* live fixes

also rename branches to has_remotes method and change return type
2021-10-12 21:15:35 +03:00
faaf72a840 improve scripts
move logic to separated shell scripts and also create shell script for
repository setup

Also force create directory according to systemd recommendations
2021-10-11 02:20:16 +03:00
ef44895b0d more verbose help messages 2021-10-07 01:56:22 +03:00
5cfffbcd46 patch control subcommands 2021-10-05 08:57:42 +03:00
3e0058620b patch support (#35) 2021-10-03 15:20:36 +03:00
e897e2cde2 do not write anything on httpexceptions in log 2021-10-03 02:05:28 +03:00
edef4944f6 replace no-log with quiet
Also behavior of the flag has been changed: now it disables logs at all
2021-10-03 01:59:33 +03:00
a4eaf87116 Release 1.4.1 2021-10-03 01:02:41 +03:00
1192f12f91 do not use set_defaults for architecture arguments
according to the source code defaults always updates the values
dictionary. This in this specific case it is impossible to override the
value it will be always empty list.

In order to handle it we are adding another property to the Handler
class which allows to run with None architecture list.

This particular set_defaults behaviour is still useful for other cases
when we have to run command without any specific architecture
2021-10-03 00:59:24 +03:00
444da87fdc Release 1.4.0 2021-10-01 09:25:35 +03:00
6be6614e6d add package request endpoint 2021-10-01 08:58:50 +03:00
8add507957 docs update 2021-09-26 14:39:35 +03:00
af5363d158 add index url 2021-09-26 14:29:42 +03:00
d60c553ea2 add debugtoolbar support 2021-09-26 12:31:12 +03:00
5a6d0e0000 set both value and innerText during search
current implementation just adds package name with the description which
is incorrect
2021-09-26 10:34:21 +03:00
427ba0f0ea add ability to specify package source explicitly during the addition 2021-09-26 09:55:14 +03:00
266d2bd77d define permissions in views directly 2021-09-25 17:03:46 +03:00
f333e89bd1 only set file rights if requested 2021-09-23 20:36:22 +03:00
659db071a1 raise httpexception instead of returning it from a function 2021-09-19 14:28:24 +03:00
56c642e2a9 add manpage 2021-09-19 13:56:11 +03:00
845bc9b5e8 Release 1.3.0 2021-09-18 06:28:52 +03:00
57f45fdc89 better reload 2021-09-17 19:15:53 +03:00
ba483173af update aioauth-client to newest version 2021-09-17 18:45:43 +03:00
6d1f641e50 add ability to reload authentication module 2021-09-17 16:05:38 +03:00
0cf7756ec4 add ability to remove an user
also replace old user by new one before creation
2021-09-16 02:41:56 +03:00
b561bcc25d remove own implementations of getlist and getpath method in order to use
converters feature
2021-09-14 03:57:20 +03:00
25d76b0482 add ability to filter status response by package status 2021-09-13 23:27:36 +03:00
d2fe4b044f raise InvalidCommand exception in case if remove option supplied without
package
2021-09-13 22:38:38 +03:00
22272167e6 change spelling for distro name 2021-09-13 02:49:22 +03:00
38dce8c0fe add target for architecture and also update it 2021-09-13 02:01:48 +03:00
68aa327670 expiration on server side support (#33) 2021-09-13 01:18:04 +03:00
04f6af58d9 send data in json_responses in case of error instead of text 2021-09-12 22:41:02 +03:00
41c8f4c35f return description from the search 2021-09-12 22:31:34 +03:00
168b2f6880 OAuth2 (#32)
* make auth method asyncs

* oauth2 demo support

* full coverage

* update docs
2021-09-12 21:41:38 +03:00
14e8eee986 remove deprecated access status 2021-09-11 23:06:30 +03:00
88c8c929dc add error description to modals 2021-09-11 23:05:51 +03:00
5bb244cbe8 add static files support and cookie expiration settings 2021-09-11 16:34:43 +03:00
f3fd0780fb documentation update 2021-09-10 03:32:45 +03:00
11c03a9041 Add ability to trigger updates from the web (#31)
* add external process spawner and update test cases

* pass no_report to handlers

* provide service api endpoints

* do not spawn process for single architecture run

* pass no report to handlers

* make _call method of handlers public and also simplify process spawn

* move update under add

* implement actions from web page

* clear logging & improve l&f
2021-09-10 00:33:35 +03:00
214f319123 add option to set user-password for service when updating its hash 2021-09-05 15:40:03 +03:00
cfbc9d3267 move api endpoints to status-api 2021-09-05 06:46:14 +03:00
0f4c89145b allow head for every get request 2021-09-05 06:41:50 +03:00
49a05d0520 add repository name to base tempalte 2021-09-05 06:15:24 +03:00
19d1e17727 allow read only pages to be requested without authorization 2021-09-05 06:09:43 +03:00
d7bf647493 update docs 2021-09-05 05:38:45 +03:00
19ba2ba8e5 migration of jinja tempaltes to bootstrap (#30) 2021-09-05 05:27:58 +03:00
f49894107a add remove uknown method (#29) 2021-09-03 02:28:27 +03:00
233ba9c415 add license header to __init__.py 2021-09-02 23:43:05 +03:00
b7cff0a19d Auth support (#25)
* initial auth implementation

* add create user parser

* add tests

* update dependencies list

* add login annd logout to index also improve auth

* realworld fixes

* add method set_option to Configuration and also use it everywhere
* split CreateUser handler to additional read method
* check user duplicate on auth mapping read
* generate salt by using passlib instead of random.choice
* case-insensetive usernames
* update dependencies
* update configuration reference
* improve tests

* fix codefactor errors

* hide fields if authorization is enabled, but no auth supplied

* add settings object for auth provider

* readme update
2021-09-02 23:36:00 +03:00
60b94b9ac0 use {} instead of dict literal according to pylint recommendation 2021-08-22 13:24:42 +03:00
284f449225 Release 1.2.6 2021-08-21 16:19:21 +03:00
d18df0935e Release 1.2.5 2021-08-19 02:36:05 +03:00
c15cc4b853 disable manpages building for now since it requires installed distribution 2021-08-19 02:35:48 +03:00
fc67778e89 Release 1.2.4 2021-08-19 00:45:58 +03:00
39ac9d4e1f include setup.cfg to tarball 2021-08-19 00:45:26 +03:00
bc923b0e8f Release 1.2.3 2021-08-19 00:18:12 +03:00
2842e40bf7 split S3.sync to different methods 2021-08-18 23:59:18 +03:00
343768e015 guess mime type for local files 2021-08-18 05:04:26 +03:00
8f55cc600e add manpage generator 2021-08-17 04:05:18 +03:00
c757554148 Release 1.2.2 2021-08-17 01:03:04 +03:00
899603e4b9 fix typo in log naming 2021-08-17 01:02:42 +03:00
f488105fd2 Release 1.2.1 2021-08-17 00:52:09 +03:00
2e89b9483f logging rethink
* well lets replace f-strings by %s as it is originally recommended
* use syslog handler by default
2021-08-17 00:23:34 +03:00
d3a00e1937 use asyncmock from unittest library 2021-08-11 21:09:10 +03:00
d9b4015be5 Release 1.2.0 2021-08-11 05:02:23 +03:00
c6b550761b cleanup and speedup runs 2021-08-11 04:59:45 +03:00
0129ec39ec use nosec instead of disabling mktemp rule 2021-08-11 02:51:29 +03:00
62661c9fb1 add bandit integration and fix its warnings 2021-08-11 02:45:13 +03:00
78636c2035 web templates improvements
* enable jinja autoescape by default for jinja raw generator
* allow to search by multiple strings (OR)
* replace test templates by symlink
2021-08-11 02:12:14 +03:00
47c4e5bb42 move web server to loopback by default 2021-08-11 02:02:18 +03:00
d548fa02f0 add docstrings for every fixture and test methods
also add tests for missing components
2021-08-11 01:55:27 +03:00
b5c6c286f7 skip update process if no update supplied 2021-08-10 23:25:12 +03:00
aad599be67 Native s3 sync (#23)
* Native S3 sync implementation

* fix imports

* fix paths reading

* install s3 components duriing test stage
2021-08-10 23:18:56 +03:00
f8ff2cbf5b Release 1.1.0 2021-07-05 22:11:14 +03:00
dad3f418ad handle provides list 2021-07-05 22:08:04 +03:00
c455bd34ce install types for mypy 2021-06-28 02:54:20 +03:00
69b319d39a remove type: ignore for newest python 2021-06-28 02:32:54 +03:00
33cfa8fef8 Feature/all archs (#21)
* add init subcommand

* add also init command to repository object

* add ability to generate list of architectures

* check if architecture list is not empty
2021-05-23 16:40:40 +03:00
9d37e3ae23 imply no-log for every unsafe parser (#20) 2021-05-19 23:30:59 +03:00
2eb2d3a70a allow to specify list of package dependencies in rebuild target
also replace nargs= by action=append in non-positional args. It is
required to make arguments parsing result more predictable and
consistent
2021-04-18 13:34:27 +03:00
46389b87e7 Release 1.0.0 2021-04-10 01:38:55 +03:00
856a94ff00 import pgp key implementation (#17)
* import pgp key implementation

* do not ask confirmation for local sign. Also add argparser test

* superseed requests by python-aur package

* ...and drop --skippgpcheck makgepkg flag by default
2021-04-10 01:37:45 +03:00
a0e6009876 better naming for actions 2021-04-09 20:02:17 +03:00
f2b39fe439 add search subparser (#15) 2021-04-09 11:57:06 +03:00
213b2c65a0 Add web status route (#13)
* add status route

* typed status and get status at the start of application
2021-04-08 01:48:53 +03:00
a416214e5f Move search line inside extended report option 2021-04-06 17:03:34 +03:00
e5966c497f Release 0.22.1 2021-04-06 05:54:04 +03:00
fbccb1394d format long line 2021-04-06 05:53:38 +03:00
01887ec44b add ability to skip email report generation for empty update list 2021-04-06 05:51:50 +03:00
4d4ddffa8f Release 0.22.0 2021-04-06 05:46:12 +03:00
4729c0ea5f Email report (#11)
* Demo email report implementation

* improved ssl mode

* correct default option spelling and more fields to be hidden for not
extended reports
2021-04-06 05:45:17 +03:00
035a23a8de Release 0.21.4 2021-04-05 02:28:38 +03:00
0d37ce5095 drop changelog
the main reason is that it uses github to generate changelog. Thus it
will be updated AFTER release is created
2021-04-05 02:27:12 +03:00
70465b5044 Release 0.21.3 2021-04-05 02:22:44 +03:00
81afa23d98 update changelog at correct step
also fix commit filter and do not update sha anymore
2021-04-05 02:22:11 +03:00
1b979725a3 Release 0.21.2 2021-04-05 02:01:28 +03:00
c2c7ee6292 add changelog generator to both gh-actions and repository 2021-04-05 02:00:05 +03:00
a3fe361596 Release 0.21.1 2021-04-05 00:45:12 +03:00
20d13f1c10 use globing instead 2021-04-05 00:44:39 +03:00
6c96c9e73a Release 0.21.0 2021-04-05 00:38:23 +03:00
9b08b0694e try to make auto archive upload 2021-04-05 00:37:03 +03:00
fcb892f39f implicit type conversion from command line 2021-04-04 23:53:30 +03:00
1785b0470f more options in setup command 2021-04-04 15:42:06 +03:00
c04f940ad3 fix check errors 2021-04-04 14:00:42 +03:00
207da4caa7 100% coverage 2021-04-03 21:30:57 +03:00
cad85b0f20 add ability to fitler by dependency list 2021-04-02 04:20:39 +03:00
3e8e54857f add ability to remove package from status page 2021-04-02 01:26:46 +03:00
6470b13511 Release 0.20.0 2021-04-01 02:38:59 +03:00
4e08297311 constistent classmethod and staticmethod usage
General idea is to use classmethod for every constructor and
statismethod otherwise.
Also use self and cls whenever it's possible to call static and class
methods
2021-03-31 04:29:08 +03:00
32c3c52874 change arch specific section naming from section_arch to section:arch
Some archs can have _ in their name. Also in future we can use sections
with similar names
2021-03-31 02:31:14 +03:00
e637a647c5 Release 0.19.0 2021-03-31 02:19:44 +03:00
e21b990777 add now argument to add command 2021-03-31 02:19:13 +03:00
c0be7f7a17 filter out every foreign arch in config 2021-03-31 01:55:39 +03:00
612cb2fa22 read sign targets from correct path 2021-03-31 00:11:05 +03:00
cf276f2398 make configuration object arch-specific 2021-03-31 00:04:13 +03:00
4ca2348f0d more verbose variables 2021-03-30 05:29:13 +03:00
eb02e1e62b merge settings groups instead of using whole group 2021-03-30 04:58:15 +03:00
8d7d508bb2 move rsync and s3 options to configuration 2021-03-30 02:38:18 +03:00
a875225b78 verbose help message 2021-03-30 02:25:23 +03:00
5449dec32a add status badge 2021-03-30 02:01:59 +03:00
eb7f3b2484 rename gpg test to correct naming 2021-03-30 01:53:23 +03:00
e87402fdde add more tests 2021-03-30 01:42:01 +03:00
3996055f56 Release 0.18.0 2021-03-29 11:48:54 +03:00
74fc283078 more properties to be shown in status pages 2021-03-29 11:48:32 +03:00
eb92f75384 architecture depending pacman.conf 2021-03-29 10:08:11 +03:00
63529633ec add status update subcommand
also satisfy pylint with too big method with too much variables
2021-03-29 04:17:10 +03:00
930b47c704 Release 0.17.0 2021-03-29 03:25:43 +03:00
a89888769f Setup command (#9)
* block issues without templates

* add setup subcommand

* handle devtools config correctly
2021-03-29 03:24:58 +03:00
b6bc1b77dc more templates 2021-03-29 00:13:20 +03:00
4a462502e7 Add issue templates 2021-03-28 23:50:41 +03:00
f383b04754 try to integrate with github workflows 2021-03-28 23:13:42 +03:00
d744fe1647 remove unused import 2021-03-28 16:24:51 +03:00
6f1b37c4cb add sign command (#7) (#8) 2021-03-28 16:24:00 +03:00
5cb3fd5853 Release 0.16.0 2021-03-28 15:38:12 +03:00
60b8477cde Add tests (#1) (#5)
* add models tests (#1)

also replace single quote to double one to confort PEP docstring
+ move _check_output to class properties to make it available for
mocking

* alpm tests implementation

* try to replace os with pathlib

* update tests for pathlib

* fix includes glob and trim version from dependencies

* build_tools package tests

* repository component tests

* add sign tests

* complete status tests

* handle exceptions in actual_version calls

* complete core tests

* move configuration to root conftest

* application tests

* complete application tests

* change copyright to more generic one

* base web tests

* complete web tests

* complete testkit

also add argument parsers test
2021-03-28 15:30:51 +03:00
502 changed files with 9374 additions and 15881 deletions

View File

@ -48,5 +48,6 @@ jobs:
- name: Build an image and push - name: Build an image and push
uses: docker/build-push-action@v4 uses: docker/build-push-action@v4
with: with:
file: docker/Dockerfile
push: true push: true
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}

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

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

View File

@ -10,7 +10,7 @@ echo -e '[arcanisrepo]\nServer = https://repo.arcanis.me/$arch\nSigLevel = Never
# refresh the image # refresh the image
pacman -Syyu --noconfirm pacman -Syyu --noconfirm
# main dependencies # main dependencies
pacman -S --noconfirm devtools git pyalpm python-inflection python-passlib python-pyelftools python-requests python-systemd sudo pacman -S --noconfirm devtools git pyalpm python-bcrypt python-inflection python-pyelftools python-requests python-systemd sudo
# make dependencies # make dependencies
pacman -S --noconfirm --asdeps base-devel python-build python-flit python-installer python-tox python-wheel pacman -S --noconfirm --asdeps base-devel python-build python-flit python-installer python-tox python-wheel
# optional dependencies # optional dependencies
@ -18,7 +18,7 @@ if [[ -z $MINIMAL_INSTALL ]]; then
# web server # web server
pacman -S --noconfirm python-aioauth-client python-aiohttp python-aiohttp-apispec-git python-aiohttp-cors python-aiohttp-jinja2 python-aiohttp-security python-aiohttp-session python-cryptography python-jinja pacman -S --noconfirm python-aioauth-client python-aiohttp python-aiohttp-apispec-git python-aiohttp-cors python-aiohttp-jinja2 python-aiohttp-security python-aiohttp-session python-cryptography python-jinja
# additional features # additional features
pacman -S --noconfirm gnupg python-boto3 python-cerberus python-matplotlib rsync pacman -S --noconfirm gnupg ipython python-boto3 python-cerberus python-matplotlib rsync
fi fi
# FIXME since 1.0.4 devtools requires dbus to be run, which doesn't work now in container # FIXME since 1.0.4 devtools requires dbus to be run, which doesn't work now in container
cp "docker/systemd-nspawn.sh" "/usr/local/bin/systemd-nspawn" cp "docker/systemd-nspawn.sh" "/usr/local/bin/systemd-nspawn"
@ -26,11 +26,16 @@ cp "docker/systemd-nspawn.sh" "/usr/local/bin/systemd-nspawn"
# create fresh tarball # create fresh tarball
tox -e archive tox -e archive
# run makepkg # run makepkg
mv dist/ahriman-*.tar.gz package/archlinux PKGVER=$(python -c "from src.ahriman import __version__; print(__version__)")
mv "dist/ahriman-$PKGVER.tar.gz" package/archlinux
chmod +777 package/archlinux # because fuck you that's why chmod +777 package/archlinux # because fuck you that's why
cd package/archlinux cd package/archlinux
sudo -u nobody -- makepkg -cf --skipchecksums --noconfirm sudo -u nobody -- makepkg -cf --skipchecksums --noconfirm
sudo -u nobody -- makepkg --packagelist | grep -v -- -debug- | pacman -U --noconfirm - sudo -u nobody -- makepkg --packagelist | grep "ahriman-core-$PKGVER" | pacman -U --noconfirm --nodeps -
if [[ -z $MINIMAL_INSTALL ]]; then
sudo -u nobody -- makepkg --packagelist | grep "ahriman-triggers-$PKGVER" | pacman -U --noconfirm --nodeps -
sudo -u nobody -- makepkg --packagelist | grep "ahriman-web-$PKGVER" | pacman -U --noconfirm --nodeps -
fi
# create machine-id which is required by build tools # create machine-id which is required by build tools
systemd-machine-id-setup systemd-machine-id-setup
@ -41,12 +46,12 @@ pacman -Qdtq | pacman -Rscn --noconfirm -
[[ -z $MINIMAL_INSTALL ]] && WEB_ARGS=("--web-port" "8080") [[ -z $MINIMAL_INSTALL ]] && WEB_ARGS=("--web-port" "8080")
ahriman -a x86_64 -r "github" service-setup --packager "ahriman bot <ahriman@example.com>" "${WEB_ARGS[@]}" ahriman -a x86_64 -r "github" service-setup --packager "ahriman bot <ahriman@example.com>" "${WEB_ARGS[@]}"
# enable services # enable services
systemctl enable ahriman-web
systemctl enable ahriman@x86_64-github.timer systemctl enable ahriman@x86_64-github.timer
if [[ -z $MINIMAL_INSTALL ]]; then if [[ -z $MINIMAL_INSTALL ]]; then
# validate configuration # validate configuration
ahriman service-config-validate --exit-code ahriman service-config-validate --exit-code
# run web service (detached) # run web service (detached)
systemctl enable ahriman-web
sudo -u ahriman -- ahriman web & sudo -u ahriman -- ahriman web &
WEB_PID=$! WEB_PID=$!
fi fi

View File

@ -15,9 +15,9 @@ jobs:
container: container:
image: archlinux:base image: archlinux:base
options: --privileged -w /build
volumes: volumes:
- ${{ github.workspace }}:/build - ${{ github.workspace }}:/build
options: --privileged -w /build
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3

View File

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

View File

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

View File

@ -4,6 +4,8 @@ build:
os: ubuntu-20.04 os: ubuntu-20.04
tools: tools:
python: "3.12" python: "3.12"
apt_packages:
- graphviz
python: python:
install: install:

View File

@ -80,7 +80,7 @@ Again, the most checks can be performed by `tox` command, though some additional
>>> clazz = Clazz() >>> clazz = Clazz()
""" """
CLAZZ_ATTRIBUTE = 42 CLAZZ_ATTRIBUTE: ClassVar[int] = 42
def __init__(self, *args: Any, **kwargs: Any) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None:
""" """
@ -96,6 +96,7 @@ Again, the most checks can be performed by `tox` command, though some additional
* Type annotations are the must, even for local functions. For the function argument `self` (for instance methods) and `cls` (for class methods) should not be annotated. * Type annotations are the must, even for local functions. For the function argument `self` (for instance methods) and `cls` (for class methods) should not be annotated.
* For collection types built-in classes must be used if possible (e.g. `dict` instead of `typing.Dict`, `tuple` instead of `typing.Tuple`). In case if built-in type is not available, but `collections.abc` provides interface, it must be used (e.g. `collections.abc.Awaitable` instead of `typing.Awaitable`, `collections.abc.Iterable` instead of `typing.Iterable`). For union classes, the bar operator (`|`) must be used (e.g. `float | int` instead of `typing.Union[float, int]`), which also includes `typing.Optional` (e.g. `str | None` instead of `Optional[str]`). * For collection types built-in classes must be used if possible (e.g. `dict` instead of `typing.Dict`, `tuple` instead of `typing.Tuple`). In case if built-in type is not available, but `collections.abc` provides interface, it must be used (e.g. `collections.abc.Awaitable` instead of `typing.Awaitable`, `collections.abc.Iterable` instead of `typing.Iterable`). For union classes, the bar operator (`|`) must be used (e.g. `float | int` instead of `typing.Union[float, int]`), which also includes `typing.Optional` (e.g. `str | None` instead of `Optional[str]`).
* `classmethod` should (almost) always return `Self`. In case of mypy warning (e.g. if there is a branch in which function doesn't return the instance of `cls`) consider using `staticmethod` instead. * `classmethod` should (almost) always return `Self`. In case of mypy warning (e.g. if there is a branch in which function doesn't return the instance of `cls`) consider using `staticmethod` instead.
* Class attributes must be decorated as `ClassVar[...]`.
* Recommended order of function definitions in class: * Recommended order of function definitions in class:
```python ```python
@ -175,11 +176,10 @@ Again, the most checks can be performed by `tox` command, though some additional
* Web API methods must be documented by using `aiohttp_apispec` library. The schema testing mostly should be implemented in related view class tests. Recommended example for documentation (excluding comments): * Web API methods must be documented by using `aiohttp_apispec` library. The schema testing mostly should be implemented in related view class tests. Recommended example for documentation (excluding comments):
```python ```python
import aiohttp_apispec
from marshmallow import Schema, fields from marshmallow import Schema, fields
from ahriman.web.schemas import AuthSchema, ErrorSchema, PackageNameSchema, PaginationSchema from ahriman.web.apispec.decorators import apidocs
from ahriman.web.schemas import PackageNameSchema, PaginationSchema
from ahriman.web.views.base import BaseView from ahriman.web.views.base import BaseView
@ -198,25 +198,17 @@ Again, the most checks can be performed by `tox` command, though some additional
POST_PERMISSION = ... POST_PERMISSION = ...
ROUTES = ... ROUTES = ...
@aiohttp_apispec.docs( @apidocs(
tags=["Tag"], tags=["Tag"],
summary="Do foo", summary="Do foo",
description="Extended description of the method which does foo", description="Extended description of the method which does foo",
responses={ error_400_enabled=True, # exception raised by this method
200: {"description": "Success response", "schema": ResponseSchema}, error_404_description="Repository is unknown",
204: {"description": "Success response"}, # example without json schema response schema=ResponseSchema, # leave empty if no responses here
400: {"description": "Bad data is supplied", "schema": ErrorSchema}, # exception raised by this method match_schema=PackageNameSchema,
401: {"description": "Authorization required", "schema": ErrorSchema}, # should be always presented query_schema=PaginationSchema,
403: {"description": "Access is forbidden", "schema": ErrorSchema}, # should be always presented body_schema=RequestSchema(many=True),
404: {"description": "Repository is unknown", "schema": ErrorSchema}, # include if BaseView.service() method is called
500: {"description": "Internal server error", "schema": ErrorSchema}, # should be always presented
},
security=[{"token": [POST_PERMISSION]}],
) )
@aiohttp_apispec.cookies_schema(AuthSchema) # should be always presented
@aiohttp_apispec.match_info_schema(PackageNameSchema)
@aiohttp_apispec.querystring_schema(PaginationSchema)
@aiohttp_apispec.json_schema(RequestSchema(many=True))
async def post(self) -> None: ... async def post(self) -> None: ...
``` ```
@ -236,16 +228,50 @@ The projects also uses typing checks (provided by `mypy`) and some linter checks
tox tox
``` ```
Must be usually done before any pushes.
### Generate documentation templates ### Generate documentation templates
```shell ```shell
tox -e docs tox -e docs
``` ```
Must be usually done if there are changes in modules structure.
### Create release ### Create release
```shell ```shell
tox -m release -- x.y.z tox -m release -- major.minor.patch
``` ```
The command above will generate documentation, tags, etc., and will push them to GitHub. Other things will be handled by GitHub workflows automatically. The command above will generate documentation, tags, etc., and will push them to GitHub. Other things will be handled by GitHub workflows automatically.
### Hotfixes policy
Sometimes it is required to publish hotfix with specific commits, but some features have been already committed, which should not be included to the hotfix. In this case, some manual steps are required:
1. Create new branch from the last stable release (`major.minor.patch`):
```shell
git checkout -b release/major.minor major.minor.patch
```
2. Cherry-pick desired commit(s):
```shell
git cherry-pick <commit-sha>
```
Alternatively, make changes to the new branch and commit them.
3. Push newly created branch to remote:
```shell
git push --set-upstream origin release/major.minor
```
4. Proceed to release as usual:
```shell
tox -m release -- major.minor.patch+1
```

View File

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

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

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

View File

@ -4,7 +4,7 @@ set -e
[ -n "$AHRIMAN_DEBUG" ] && set -x [ -n "$AHRIMAN_DEBUG" ] && set -x
# configuration tune # configuration tune
cat <<EOF > "/etc/ahriman.ini.d/00-docker.ini" cat <<EOF > "/etc/ahriman.ini.d/01-docker.ini"
[repository] [repository]
root = $AHRIMAN_REPOSITORY_ROOT root = $AHRIMAN_REPOSITORY_ROOT
@ -57,6 +57,9 @@ ahriman "${AHRIMAN_DEFAULT_ARGS[@]}" service-setup "${AHRIMAN_SETUP_ARGS[@]}"
# create machine-id which is required by build tools # create machine-id which is required by build tools
systemd-machine-id-setup &> /dev/null systemd-machine-id-setup &> /dev/null
# special workaround to emulate /bin/bash entrypoint if first argument starts with /
[[ "$1" =~ ^/.* ]] && exec "$@"
# if AHRIMAN_FORCE_ROOT is set or command is unsafe we can run without sudo # if AHRIMAN_FORCE_ROOT is set or command is unsafe we can run without sudo
# otherwise we prepend executable by sudo command # otherwise we prepend executable by sudo command
if [ -n "$AHRIMAN_FORCE_ROOT" ]; then if [ -n "$AHRIMAN_FORCE_ROOT" ]; then

View File

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

1846
docs/_static/architecture.dot vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 1.3 MiB

View File

@ -0,0 +1,51 @@
Writing own handler
===================
It is possible to extend the application by adding own custom commands. To do so it is required to implement class, which derives from ``ahriman.application.handlers.handler.Handler`` and put it to the ``ahriman.application.handlers`` package. The class later will be loaded automatically and included to each command run.
Let's imagine, that the new class implements ``help-web``, which prints server information to the stdout. To do so, we need to implement base ``ahriman.application.handlers.handler.Handler.run`` method which is entry point for all subcommands:
.. code-block:: python
from ahriman.application.application import Application
from ahriman.application.handlers.handler import Handler
class HelpWeb(Handler):
@classmethod
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
report: bool) -> None:
# load application instance
# report is set to True to make sure that web client is loaded
application = Application(repository_id, configuration, report=True)
# extract web client
client = application.repository.reporter
# send request to the server
response = client.make_request("GET", f"{client.address}/api/v1/info")
result = response.json()
print(result)
The main functionality of the class is already described, but command is still not available yet. To do so, it is required to set ``arguments`` property, which is the list of the functions, each of them which takes argument parser object, creates new subcommand and returns the modified parser, e.g.:
.. code-block:: python
import argparse
from ahriman.application.handlers.handler import SubParserAction
...
@staticmethod
def set_parser(root: SubParserAction) -> argparse.ArgumentParser:
parser = root.add_parser("help-web", help="get web server status",
description="request server info and print it to stdout")
arguments = set_parser
In addition, ``ahriman.application.handlers.handler.Handler.ALLOW_MULTI_ARCHITECTURE_RUN`` can be set to ``False`` in order to disable multiprocess run (e.g. in case if there are conflicting operations, like writing to stdout).
Save the file above as ``/usr/lib/python3.12/site-packages/ahriman/application/handlers/help_web.py`` (replace ``python3.12`` with actual python version) and you are set.
For more examples and details, please check builtin handlers and classes documentations.

View File

@ -1,6 +1,12 @@
Advanced usage Advanced usage
============== ==============
.. toctree::
:maxdepth: 2
handlers
views
Depending on the goal the package can be used in different ways. Nevertheless, in the most cases you will need some basic classes Depending on the goal the package can be used in different ways. Nevertheless, in the most cases you will need some basic classes
.. code-block:: python .. code-block:: python

View File

@ -0,0 +1,41 @@
Writing own API endpoint
========================
The web service loads views dynamically, thus it is possible to add custom API endpoint or even web page. The view must be derived from ``ahriman.web.views.base.BaseView`` and should implement desired HTTP methods. The API specification will be also loaded automatically if available, but optional. The implementation must be saved into the ``ahriman.web.views`` package
Let's consider example of API endpoint which always returns 204 with no response:
.. code-block:: python
from aiohttp.web import Response, HTTPNoContent
from ahriman.web.views.base import BaseView
class PingView(BaseView):
async def get(self) -> Response:
# do nothing, just raise 204 response
# check public methods of the BaseView class for all available controls
raise HTTPNoContent
The ``get()`` method can be decorated by ``aiohttp_apispec`` methods, but we will leave it for a self-study, please, consider to check examples of usages in the main package.
In order to view to be added to the route list correctly, few more properties are required to be set. First of all, it is required to specify ``ROUTES`` (list of strings), which contains list of all available routes, e.g.:
.. code-block:: python
...
ROUTES = ["/api/v1/ping"]
In addition, it is also recommended to specify permission level for using this endpoint. Since this endpoint neither does anything nor returns sensitive information, it can be set to ``UserAccess.Unauthorized``:
.. code-block:: python
...
GET_PERMISSION = UserAccess.Unauthorized
That's all. Just save the file as ``/usr/lib/python3.12/site-packages/ahriman/web/views/ping.py`` (replace ``python3.12`` with actual python version) and restart web server.
For more examples and details, please check builtin handlers and classes documentations.

View File

@ -36,6 +36,14 @@ ahriman.application.handlers.clean module
:no-undoc-members: :no-undoc-members:
:show-inheritance: :show-inheritance:
ahriman.application.handlers.copy module
----------------------------------------
.. automodule:: ahriman.application.handlers.copy
:members:
:no-undoc-members:
:show-inheritance:
ahriman.application.handlers.daemon module ahriman.application.handlers.daemon module
------------------------------------------ ------------------------------------------
@ -220,6 +228,14 @@ ahriman.application.handlers.triggers module
:no-undoc-members: :no-undoc-members:
:show-inheritance: :show-inheritance:
ahriman.application.handlers.triggers\_support module
-----------------------------------------------------
.. automodule:: ahriman.application.handlers.triggers_support
:members:
:no-undoc-members:
:show-inheritance:
ahriman.application.handlers.unsafe\_commands module ahriman.application.handlers.unsafe\_commands module
---------------------------------------------------- ----------------------------------------------------

View File

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

View File

@ -12,6 +12,14 @@ ahriman.core.configuration.configuration module
:no-undoc-members: :no-undoc-members:
:show-inheritance: :show-inheritance:
ahriman.core.configuration.configuration\_multi\_dict module
------------------------------------------------------------
.. automodule:: ahriman.core.configuration.configuration_multi_dict
:members:
:no-undoc-members:
:show-inheritance:
ahriman.core.configuration.schema module ahriman.core.configuration.schema module
---------------------------------------- ----------------------------------------

View File

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

View File

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

View File

@ -36,6 +36,14 @@ ahriman.core.exceptions module
:no-undoc-members: :no-undoc-members:
:show-inheritance: :show-inheritance:
ahriman.core.module\_loader module
----------------------------------
.. automodule:: ahriman.core.module_loader
:members:
:no-undoc-members:
:show-inheritance:
ahriman.core.spawn module ahriman.core.spawn module
------------------------- -------------------------

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,18 +8,18 @@ Packages have strict rules of importing:
* ``ahriman.application`` package must not be used outside of this package. * ``ahriman.application`` package must not be used outside of this package.
* ``ahriman.core`` and ``ahriman.models`` packages don't have any import restriction. Actually we would like to totally restrict importing of ``core`` package from ``models``, but it is impossible at the moment. * ``ahriman.core`` and ``ahriman.models`` packages don't have any import restriction. Actually we would like to totally restrict importing of ``core`` package from ``models``, but it is impossible at the moment.
* ``ahriman.web`` package is allowed to be imported from ``ahriman.application`` (web handler only, only ``ahriman.web.web`` methods). It also must not be imported globally, only local import is allowed. * ``ahriman.web`` package is allowed to be imported from ``ahriman.application`` (web handler only, only ``ahriman.web.web`` methods).
* The idea remains the same for all imports, if an package requires some specific dependencies, it must be imported locally to keep dependencies optional.
Full dependency diagram: Full dependency diagram:
.. image:: _static/architecture.svg .. graphviz:: _static/architecture.dot
:target: _static/architecture.svg
:alt: architecture :alt: architecture
``ahriman.application`` package ``ahriman.application`` package
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This package contains application (aka executable) related classes and everything for it. It also contains package called ``ahriman.application.handlers`` in which all available subcommands are described as separated classes derived from the base ``ahriman.application.handlers.Handler`` class. This package contains application (aka executable) related classes and everything for it. It also contains package called ``ahriman.application.handlers`` in which all available subcommands are described as separated classes derived from the base ``ahriman.application.handlers.handler.Handler`` class. Those classes are being loaded dynamically through the lookup of the ``ahriman.application.handlers`` package.
``ahriman.application.application.Application`` (god class) is used for any interaction from parsers with repository. It is divided into multiple traits by functions (package related and repository related) in the same package. ``ahriman.application.application.Application`` (god class) is used for any interaction from parsers with repository. It is divided into multiple traits by functions (package related and repository related) in the same package.
@ -33,9 +33,9 @@ This package contains application (aka executable) related classes and everythin
This package contains everything required for the most of application actions and it is separated into several packages: This package contains everything required for the most of application actions and it is separated into several packages:
* ``ahriman.core.alpm`` package controls pacman related functions. It provides wrappers for ``pyalpm`` library and safe calls for repository tools (``repo-add`` and ``repo-remove``). Also this package contains ``ahriman.core.alpm.remote`` package which provides wrapper for remote sources (e.g. AUR RPC and official repositories RPC) and some other helpers. * ``ahriman.core.alpm`` package controls pacman related functions. It provides wrappers for ``pyalpm`` library and safe calls for repository tools (``repo-add`` and ``repo-remove``). Also this package contains ``ahriman.core.alpm.remote`` package which provides wrapper for remote sources (e.g. AUR RPC and official repositories RPC) and some other helpers.
* ``ahriman.core.auth`` package provides classes for authorization methods used by web mostly. Base class is ``ahriman.core.auth.Auth`` which must be instantiated by ``load`` method. * ``ahriman.core.auth`` package provides classes for authorization methods used by web mostly. Base class is ``ahriman.core.auth.Auth`` which must be instantiated by ``load`` method. This package is only required by the ``ahriman.web`` package.
* ``ahriman.core.build_tools`` is a package which provides wrapper for ``devtools`` commands. * ``ahriman.core.build_tools`` is a package which provides wrapper for ``devtools`` commands.
* ``ahriman.core.configuration`` contains extension for standard ``configparser`` library and some validation related classes. * ``ahriman.core.configuration`` contains extensions for standard ``configparser`` module and some validation related classes.
* ``ahriman.core.database`` is everything for database, including data and schema migrations. * ``ahriman.core.database`` is everything for database, including data and schema migrations.
* ``ahriman.core.distributed`` package with triggers and helpers for distributed build system. * ``ahriman.core.distributed`` package with triggers and helpers for distributed build system.
* ``ahriman.core.formatters`` package provides ``Printer`` sub-classes for printing data (e.g. package properties) to stdout which are used by some handlers. * ``ahriman.core.formatters`` package provides ``Printer`` sub-classes for printing data (e.g. package properties) to stdout which are used by some handlers.
@ -53,8 +53,11 @@ This package contains everything required for the most of application actions an
This package also provides some generic functions and classes which may be used by other packages: This package also provides some generic functions and classes which may be used by other packages:
* ``ahriman.core.exceptions`` provides custom exceptions. * ``ahriman.core.exceptions`` provides custom exceptions.
* ``ahriman.core.module_loader`` provides ``implementations`` method which can be used for dynamic classes load. In particular, this method is used for web views and application handlers loading.
* ``ahriman.core.spawn.Spawn`` is a tool which can spawn another ``ahriman`` process. This feature is used by web application. * ``ahriman.core.spawn.Spawn`` is a tool which can spawn another ``ahriman`` process. This feature is used by web application.
* ``ahriman.core.tree`` is a dependency tree implementation. * ``ahriman.core.tree`` is a dependency tree implementation.
* ``ahriman.core.types`` are an additional global types for mypy checks.
* ``ahriman.core.utils`` contains some useful functions which are not the part of any other class.
``ahriman.models`` package ``ahriman.models`` package
^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -68,7 +71,7 @@ Web application. It is important that this package is isolated from any other to
* ``ahriman.web.middlewares`` provides middlewares for request handlers. * ``ahriman.web.middlewares`` provides middlewares for request handlers.
* ``ahriman.web.schemas`` provides schemas (actually copy paste from dataclasses) used by swagger documentation. * ``ahriman.web.schemas`` provides schemas (actually copy paste from dataclasses) used by swagger documentation.
* ``ahriman.web.views`` contains web views derived from aiohttp view class. * ``ahriman.web.views`` contains web views derived from aiohttp view class. Those classes are loaded dynamically through the filesystem lookup.
* ``ahriman.web.apispec`` provides generators for swagger documentation. * ``ahriman.web.apispec`` provides generators for swagger documentation.
* ``ahriman.web.cors`` contains helpers for cross origin resource sharing middlewares. * ``ahriman.web.cors`` contains helpers for cross origin resource sharing middlewares.
* ``ahriman.web.routes`` creates routes for web application. * ``ahriman.web.routes`` creates routes for web application.
@ -79,7 +82,7 @@ Application run
#. Parse command line arguments, find subcommand and related handler which is set by the parser. #. Parse command line arguments, find subcommand and related handler which is set by the parser.
#. Call ``Handler.execute`` method. #. Call ``Handler.execute`` method.
#. Define list of architectures to run. In case if there is more than one architecture specified run several subprocesses or continue in current process otherwise. Class attribute ``ALLOW_MULTI_ARCHITECTURE_RUN`` controls whether the application can be run in multiple processes or not - this feature is required for some handlers (e.g. ``Web``, which should be able to spawn child process in daemon mode; it is impossible to do from daemonic processes). #. Define list of architectures to run. In case if there is more than one architecture specified run several subprocesses or continue in current process otherwise. Class attribute ``ALLOW_MULTI_ARCHITECTURE_RUN`` controls whether the application can be run in multiple processes or not - this feature is required for some handlers (e.g. ``Config``, which utilizes stdout to print messages).
#. In each child process call lock functions. #. In each child process call lock functions.
#. After success checks pass control to ``Handler.run`` method defined by specific handler class. #. After success checks pass control to ``Handler.run`` method defined by specific handler class.
#. Return result (success or failure) of each subprocess and exit from application. #. Return result (success or failure) of each subprocess and exit from application.
@ -148,7 +151,7 @@ There are multiple subdirectories, some of them are commons for any repository,
* ``pacman/{repository}/{architecture}`` is the repository and architecture specific caches for pacman's databases. * ``pacman/{repository}/{architecture}`` is the repository and architecture specific caches for pacman's databases.
* ``repository/{repository}/{architecture}`` is a repository packages directory. * ``repository/{repository}/{architecture}`` is a repository packages directory.
Normally you should avoid direct interaction with the application tree. For tree migration process refer to the :doc:`migration notes <migration>`. Normally you should avoid direct interaction with the application tree. For tree migration process refer to the :doc:`migration notes <migrations/index>`.
Database Database
-------- --------
@ -174,28 +177,28 @@ Type conversions
By default, it parses rows into python dictionary. In addition, the following pseudo-types are supported: By default, it parses rows into python dictionary. In addition, the following pseudo-types are supported:
* ``dict[str, Any]``, ``list[Any]`` - for storing JSON data structures in database (technically there is no restriction on types for dictionary keys and values, but it is recommended to use only string keys). The type is stored as ``json`` data type and ``json.loads`` and ``json.dumps`` methods are used in order to read and write from/to database respectively. * ``dict[str, Any]`` and ``list[Any]`` - for storing JSON data structures in database (technically there is no restriction on types for dictionary keys and values, but it is recommended to use only string keys). The type is stored as ``json`` data type and ``json.loads`` and ``json.dumps`` methods are used in order to read and write from/to database respectively.
Basic flows Basic flows
----------- -----------
By default package build operations are performed with ``PACKAGER`` which is specified in ``makepkg.conf``, however, it is possible to override this variable from command line; in this case service performs lookup in the following way: By default package build operations are performed with ``PACKAGER`` which is specified in ``makepkg.conf``, however, it is possible to override this variable from command line; in this case service performs lookup in the following way:
* If packager is not set, it reads environment variables (e.g. ``SUDO_USER`` and ``USER``), otherwise it uses value from command line. * If packager is not set, it reads environment variables (e.g. ``DOAS_USER``, ``SUDO_USER`` and ``USER``), otherwise it uses value from command line.
* It checks users for the specified username and tries to extract packager variable from it. * It checks users for the specified username and tries to extract packager variable from it.
* If packager value has been found, it will be passed as ``PACKAGER`` system variable (additional sudo configuration might be required). * If packager value has been found, it will be passed as ``PACKAGER`` system variable (additional sudo configuration to pass environment variables might be required).
Add new packages or rebuild existing Add new packages or rebuild existing
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Idea is to add package to a build queue from which it will be handled automatically during the next update run. Different variants are supported: The idea is to add package to a build queue from which it will be handled automatically during the next update run. Different variants are supported:
* If supplied argument is file, then application moves the file to the directory with built packages. Same rule applies for directory, but in this case it copies every package-like file from the specified directory. * If supplied argument is file, then application moves the file to the directory with the built packages. Same rule is applied for directory, but in this case it copies every package-like file from the specified directory.
* If supplied argument is directory and there is ``PKGBUILD`` file there, it will be treated as local package. In this case it will queue this package to build and copy source files (``PKGBUILD`` and ``.SRCINFO``) to caches. * If supplied argument is directory and there is ``PKGBUILD`` file there, it will be treated as local package. In this case it will queue this package to build and copy source files (``PKGBUILD`` and ``.SRCINFO``) to caches.
* If supplied argument looks like URL (i.e. it has scheme - e.g. ``http://`` which is neither ``data`` nor ``file``), it tries to download the package from the specified remote source. * If supplied argument looks like URL (i.e. it has scheme, which is neither ``data`` nor ``file``, e.g. ``http://``), it tries to download the package from the specified remote source.
* If supplied argument is not file then application tries to lookup for the specified name in AUR and clones it into the directory with manual updates. This scenario can also handle package dependencies which are missing in repositories. * If supplied argument is not file then application tries to lookup for the specified name in AUR and clones it into the temporary directory, from which it will be added into the build queue. This scenario can also handle package dependencies which are missing in repositories.
This logic can be overwritten by specifying the ``source`` parameter, which is partially useful if you would like to add package from AUR, but there is local directory cloned from AUR. Also official repositories calls are hidden behind explicit source definition. This logic can be overwritten by specifying the ``source`` parameter, which is partially useful if you would like to add package from AUR, but there is local directory cloned from AUR. Also the official repositories calls are hidden behind explicit source definition.
Rebuild packages Rebuild packages
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
@ -220,7 +223,7 @@ There are few ways for packages to be marked as out-of-date and hence requiring
Update packages Update packages
^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
This feature is divided into to the following stages: check AUR for updates and run rebuild for required packages. The package update flow is the following: This feature is divided into the following stages: check AUR for updates and run rebuild for required packages. The package update flow is the following:
#. Process every built package first. Those packages are usually added manually. #. Process every built package first. Those packages are usually added manually.
#. Run sync and report methods. #. Run sync and report methods.
@ -254,18 +257,17 @@ The upload process is performed via special API endpoint, which is disabled by d
After success upload, the update process must be called as usual in order to copy built packages to the main repository tree. After success upload, the update process must be called as usual in order to copy built packages to the main repository tree.
On the other side, the delegation uses upload feature, but in addition it also calls external services in order to trigger build process. The packages are separated to chunks based on the amount of the configured workers and their dependencies. On the other side, the delegation uses upload feature, but in addition it also calls external services in order to trigger build process. The packages are separated into the chunks based on the amount of the configured workers and their dependencies.
pkgrel bump rules pkgrel bump rules
^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^
The application is able to automatically bump package release (``pkgrel``) during build process if there is duplicate version in repository. The version will be incremented as following: The application is able to automatically bump package release (``pkgrel`` variable) during the build process if there is duplicated version in the repository. The version will be incremented as following:
#. Get version of the remote package. #. Get version of the remote package.
#. Get version of the local package if available. #. Get version of the local package if available.
#. If local version is not set, proceed with remote one. #. If the local version is not set, proceed with the remote one.
#. If local version is set and epoch or package version (``pkgver``) are different, proceed with remote version. #. If the local version is set and the remote version is newer than local one, proceed with remote.
#. If local version is set and remote version is newer than local one, proceed with remote.
#. Extract ``pkgrel`` value. #. Extract ``pkgrel`` value.
#. If it has ``major.minor`` notation (e.g. ``1.1``), then increment last part by 1, e.g. ``1.1 -> 1.2``, ``1.0.1 -> 1.0.2``. #. If it has ``major.minor`` notation (e.g. ``1.1``), then increment last part by 1, e.g. ``1.1 -> 1.2``, ``1.0.1 -> 1.0.2``.
#. If ``pkgrel`` is a number (e.g. ``1``), then append 1 to the end of the string, e.g. ``1 -> 1.1``. #. If ``pkgrel`` is a number (e.g. ``1``), then append 1 to the end of the string, e.g. ``1 -> 1.1``.
@ -273,9 +275,9 @@ The application is able to automatically bump package release (``pkgrel``) durin
Implicit dependencies resolution Implicit dependencies resolution
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In addition to the depends/optional/make/check depends lists the server also handles implicit dependencies. After success build, the application traverse through the build tree and finds In addition to the depends/optional/make/check depends lists the server also handles implicit dependencies. After success build, the application traverse through the build tree and finds:
* Libraries to which the binaries (ELF-files) are linked. To do so, the ``NEEDED`` section of the ELF-files are read. * Libraries to which the binaries (ELF-files) are linked. To do so, the ``NEEDED`` section of the ELF-files is read.
* Directories which contains files of the package, but do not belong to this package. This case covers, for example, python and ruby submodules. * Directories which contains files of the package, but do not belong to this package. This case covers, for example, python and ruby submodules.
Having the initial dependencies tree, the application is looking for packages which contains those (both files and directories) paths and creates the initial packages list. After that, the packages list is reduced in the following way: Having the initial dependencies tree, the application is looking for packages which contains those (both files and directories) paths and creates the initial packages list. After that, the packages list is reduced in the following way:
@ -286,6 +288,8 @@ Having the initial dependencies tree, the application is looking for packages wh
* After that, if there is a package which *optionally* depends on the another package in the remaining list, the package will be removed. * After that, if there is a package which *optionally* depends on the another package in the remaining list, the package will be removed.
* And finally, if there is any path, which is the child of the entry, and it contains the same package, the package from the smaller entry will be removed. * And finally, if there is any path, which is the child of the entry, and it contains the same package, the package from the smaller entry will be removed.
Those paths are also filtered by regular expressions set in the configuration.
All those implicit dependencies are stored in the database and extracted on each check. In case if any of the repository packages doesn't contain any entry anymore (e.g. so version has been changed or modules directory has been changed), the dependent package will be marked as out-of-dated. All those implicit dependencies are stored in the database and extracted on each check. In case if any of the repository packages doesn't contain any entry anymore (e.g. so version has been changed or modules directory has been changed), the dependent package will be marked as out-of-dated.
Core functions reference Core functions reference
@ -325,7 +329,7 @@ Some packages provide different behaviour depending on configuration settings. I
Authorization Authorization
^^^^^^^^^^^^^ ^^^^^^^^^^^^^
The package provides several authorization methods: disabled, based on configuration and OAuth2. The package provides several authorization methods: disabled, based on configuration, PAM and OAuth2.
Disabled (default) authorization provider just allows everything for everyone and does not have any specific configuration (it uses some default configuration parameters though). It also provides generic interface for derived classes. Disabled (default) authorization provider just allows everything for everyone and does not have any specific configuration (it uses some default configuration parameters though). It also provides generic interface for derived classes.
@ -334,7 +338,7 @@ Mapping (aka configuration) provider uses hashed passwords with optional salt fr
* ``check_credentials`` - user password validation (authentication). * ``check_credentials`` - user password validation (authentication).
* ``verify_access`` - user permission validation (authorization). * ``verify_access`` - user permission validation (authorization).
Passwords must be stored in database as ``hash(password + salt)``, where ``password`` is user defined password (taken from user input), ``salt`` is random string (any length) defined globally in configuration and ``hash`` is secure hash function. Thus, the following configuration Passwords must be stored in database as ``hash(password + salt)``, where ``password`` is user defined password (taken from user input), ``salt`` is random string (any length) defined globally in configuration and ``hash`` is a secure hash function. Thus, the following configuration
.. code-block:: .. code-block::
@ -347,7 +351,7 @@ OAuth provider uses library definitions (``aioauth-client``) in order *authentic
OAuth's implementation also allows authenticating users via username + password (in the same way as mapping does) though it is not recommended for end-users and password must be left blank. In particular this feature can be used by service reporting (aka robots). OAuth's implementation also allows authenticating users via username + password (in the same way as mapping does) though it is not recommended for end-users and password must be left blank. In particular this feature can be used by service reporting (aka robots).
In addition, web service checks the source socket used. In case if it belongs to ``socket.AF_UNIX`` family, it will skip any further checks considering the request to be performed in safe environment (e.g. on the same physical machine). This feature, in particular is being used by the reporter instances in case if socket address is set in configuration. In addition, web service checks the source socket used. In case if it belongs to ``socket.AF_UNIX`` family, it will skip any further checks considering the request to be performed in safe environment (e.g. on the same physical machine). This feature, in particular is being used by the reporter instances in case if socket address is set in configuration. Note, however, that this behaviour can be disabled by configuration.
In order to configure users there are special subcommands. In order to configure users there are special subcommands.
@ -382,7 +386,7 @@ The application provides a house-made shell parser ``ahriman.core.alpm.pkgbuild_
#. During the parser process, firstly, it extract next token from the source file (basically, the word) and tries to match it to the variable assignment. If so, then just processes accordingly. #. During the parser process, firstly, it extract next token from the source file (basically, the word) and tries to match it to the variable assignment. If so, then just processes accordingly.
#. If it is not an assignment, the parser checks if the token was quoted. #. If it is not an assignment, the parser checks if the token was quoted.
#. If it wasn't then the parser tries to match the array starts (two consecutive tokens like ``array=`` and ``(``) or it is function (``function``, ``()`` and ``{``). #. If it wasn't quoted then the parser tries to match the array starts (two consecutive tokens like ``array=`` and ``(``) or it is function (``function``, ``()`` and ``{``).
#. The arrays are processed until the next closing bracket ``)``. After extraction, the parser tries to expand an array according to bash rules (``prefix{first,second}suffix`` constructions). #. The arrays are processed until the next closing bracket ``)``. After extraction, the parser tries to expand an array according to bash rules (``prefix{first,second}suffix`` constructions).
#. The functions are just read until the closing bracket ``}`` and then reread whole text from the input string without a tokenization. #. The functions are just read until the closing bracket ``}`` and then reread whole text from the input string without a tokenization.
@ -390,7 +394,7 @@ All extracted fields are packed as ``ahriman.models.pkgbuild_patch.PkgbuildPatch
The PKGBUILD class also provides some additional functions on top of that: The PKGBUILD class also provides some additional functions on top of that:
* Ability to extract fields defined inside ``package*()`` functions, which are in particular used for the multipackages. * Ability to extract fields defined inside ``package*()`` functions, which are in particular used for the multi-packages.
* Shell substitution, which supports constructions ``$var`` (including ``${var}``), ``${var#(#)pattern}``, ``${var%(%)pattern}`` and ``${var/(/)pattern/replacement}`` (including ``#pattern`` and ``%pattern``). * Shell substitution, which supports constructions ``$var`` (including ``${var}``), ``${var#(#)pattern}``, ``${var%(%)pattern}`` and ``${var/(/)pattern/replacement}`` (including ``#pattern`` and ``%pattern``).
Additional features Additional features
@ -398,7 +402,6 @@ Additional features
Some features require optional dependencies to be installed: Some features require optional dependencies to be installed:
* Version control executables (e.g. ``git``, ``svn``) for VCS packages.
* ``gnupg`` application for package and repository sign feature. * ``gnupg`` application for package and repository sign feature.
* ``rsync`` application for rsync based repository sync. * ``rsync`` application for rsync based repository sync.
* ``boto3`` python package for ``S3`` sync. * ``boto3`` python package for ``S3`` sync.
@ -437,6 +440,9 @@ REST API supports only JSON data.
Different APIs are separated into different packages: Different APIs are separated into different packages:
* ``ahriman.web.views.api`` not a real API, but some views which provide OpenAPI support. * ``ahriman.web.views.api`` not a real API, but some views which provide OpenAPI support.
* ``ahriman.web.views.*.auditlog`` provides event log API.
* ``ahriman.web.views.*.distributed`` is an API for builders interaction for multi-node setup.
* ``ahriman.web.views.*.packages`` contains views which provide information about existing packages.
* ``ahriman.web.views.*.service`` provides views for application controls. * ``ahriman.web.views.*.service`` provides views for application controls.
* ``ahriman.web.views.*.status`` package provides REST API for application reporting. * ``ahriman.web.views.*.status`` package provides REST API for application reporting.
* ``ahriman.web.views.*.user`` package provides login and logout methods which can be called without authorization. * ``ahriman.web.views.*.user`` package provides login and logout methods which can be called without authorization.
@ -455,7 +461,7 @@ Service provides optional authorization which can be turned on in settings. In o
If this feature is configured any request will be prohibited without authentication. In addition, configuration flag ``auth.allow_read_only`` can be used in order to allow read-only operations - reading index page and packages - without authorization. If this feature is configured any request will be prohibited without authentication. In addition, configuration flag ``auth.allow_read_only`` can be used in order to allow read-only operations - reading index page and packages - without authorization.
For authenticated users it uses encrypted session cookies to store tokens; encryption key is generated each time at the start of the application. It also stores expiration time of the session inside. For authenticated users it uses encrypted session cookies to store tokens; encryption key is read from configuration or generated at the start of the application if not set. It also stores expiration time of the session inside.
External calls External calls
^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^

View File

@ -10,7 +10,7 @@
# add these directories to sys.path here. If the directory is relative to the # 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. # documentation root, use os.path.abspath to make it absolute, like shown here.
# #
import os import datetime
import sys import sys
from pathlib import Path from pathlib import Path
@ -21,13 +21,11 @@ from ahriman import __version__
basedir = Path(__file__).resolve().parent.parent / "src" basedir = Path(__file__).resolve().parent.parent / "src"
sys.path.insert(0, str(basedir)) sys.path.insert(0, str(basedir))
on_rtd = os.environ.get("READTHEDOCS", None) == "True"
# -- Project information ----------------------------------------------------- # -- Project information -----------------------------------------------------
project = "ahriman" project = "ahriman"
copyright = "2021-2023, ahriman team" copyright = f"2021-{datetime.date.today().year}, ahriman team"
author = "ahriman team" author = "ahriman team"
# The full version, including alpha/beta/rc tags # The full version, including alpha/beta/rc tags
@ -41,6 +39,7 @@ release = __version__
# ones. # ones.
extensions = [ extensions = [
"sphinx.ext.autodoc", "sphinx.ext.autodoc",
"sphinx.ext.graphviz",
"sphinx.ext.napoleon", "sphinx.ext.napoleon",
"sphinx_rtd_theme", "sphinx_rtd_theme",
"sphinxarg.ext", "sphinxarg.ext",
@ -78,7 +77,12 @@ html_logo = "_static/logo.svg"
add_module_names = False add_module_names = False
modindex_common_prefix = ["ahriman.application.", "ahriman.core.", "ahriman.models.", "ahriman.web."] modindex_common_prefix = [
"ahriman.application.",
"ahriman.core.",
"ahriman.models.",
"ahriman.web.",
]
# -- Extension configuration ------------------------------------------------- # -- Extension configuration -------------------------------------------------
@ -92,3 +96,5 @@ autodoc_mock_imports = ["cryptography", "pyalpm"]
autodoc_default_options = { autodoc_default_options = {
"no-undoc-members": True, "no-undoc-members": True,
} }
graphviz_output_format = "svg"

View File

@ -13,7 +13,27 @@ There are two variable types which have been added to default ones, they are pat
* By default, it splits value by spaces excluding empty elements. * By default, it splits value by spaces excluding empty elements.
* In case if quotation mark (``"`` or ``'``) will be found, any spaces inside will be ignored. * In case if quotation mark (``"`` or ``'``) will be found, any spaces inside will be ignored.
* In order to use quotation mark inside value it is required to put it to another quotation mark, e.g. ``wor"'"d "with quote"`` will be parsed as ``["wor'd", "with quote"]`` and vice versa. * In order to use quotation mark inside value it is required to put it to another quotation mark, e.g. ``wor"'"d "with quote"`` will be parsed as ``["wor'd", "with quote"]`` and vice versa.
* Unclosed quotation mark is not allowed and will rise an exception. * Unclosed quotation mark is not allowed and will raise an exception.
It is also possible to split list option between multiple declarations. To do so, append key name with ``[]`` (like PHP, sorry!), e.g.:
.. code-block:: ini
[section]
list[] = value1
list[] = value2
will lead to ``${section:list}`` value to be set to ``value1 value2``. The values will be set in order of appearance, meaning that values which appear in different include files will be set in alphabetical order of file names. In order to reset list values, set option to empty string, e.g.:
.. code-block:: ini
[section]
list[] = value1
list[] =
list[] = value2
list[] = value3
will set option ``${section:list}`` to ``value2 value3``. Alternatively, setting the original option (e.g. ``list`` in the example above) will also reset value, though the subsequent options with leading ``[]`` will append the previous value.
Path values, except for casting to ``pathlib.Path`` type, will be also expanded to absolute paths relative to the configuration path. E.g. if path is set to ``ahriman.ini.d/logging.ini`` and root configuration path is ``/etc/ahriman.ini``, the value will be expanded to ``/etc/ahriman.ini.d/logging.ini``. In order to disable path expand, use the full path, e.g. ``/etc/ahriman.ini.d/logging.ini``. Path values, except for casting to ``pathlib.Path`` type, will be also expanded to absolute paths relative to the configuration path. E.g. if path is set to ``ahriman.ini.d/logging.ini`` and root configuration path is ``/etc/ahriman.ini``, the value will be expanded to ``/etc/ahriman.ini.d/logging.ini``. In order to disable path expand, use the full path, e.g. ``/etc/ahriman.ini.d/logging.ini``.
@ -22,7 +42,7 @@ Configuration allows string interpolation from the same configuration file, e.g.
.. code-block:: ini .. code-block:: ini
[section] [section]
key = ${anoher_key} key = ${another_key}
another_key = value another_key = value
will read value for the ``key`` option from ``another_key`` in the same section. In case if the cross-section reference is required, the ``${section:another_key}`` notation must be used. It also allows string interpolation from environment variables, e.g.: will read value for the ``key`` option from ``another_key`` in the same section. In case if the cross-section reference is required, the ``${section:another_key}`` notation must be used. It also allows string interpolation from environment variables, e.g.:
@ -61,6 +81,7 @@ Base configuration settings.
* ``apply_migrations`` - perform database migrations on the application start, boolean, optional, default ``yes``. Useful if you are using git version. Note, however, that this option must be changed only if you know what to do and going to handle migrations manually. * ``apply_migrations`` - perform database migrations on the application start, boolean, optional, default ``yes``. Useful if you are using git version. Note, however, that this option must be changed only if you know what to do and going to handle migrations manually.
* ``database`` - path to the application SQLite database, string, required. * ``database`` - path to the application SQLite database, string, required.
* ``include`` - path to directory with configuration files overrides, string, optional. Files will be read in alphabetical order. * ``include`` - path to directory with configuration files overrides, string, optional. Files will be read in alphabetical order.
* ``keep_last_logs`` - amount of build logs to be kept for each package, integer, optional ,default ``0``. Logs will be cleared at the end of each process.
* ``logging`` - path to logging configuration, string, required. Check ``logging.ini`` for reference. * ``logging`` - path to logging configuration, string, required. Check ``logging.ini`` for reference.
``alpm:*`` groups ``alpm:*`` groups
@ -197,7 +218,7 @@ Mirrorlist generator plugin
``remote-pull`` group ``remote-pull`` group
--------------------- ---------------------
Remote git source synchronization settings. Unlike ``Upload`` triggers those triggers are used for PKGBUILD synchronization - fetch from remote repository PKGBUILDs before updating process. Remote git source synchronization settings. Unlike ``upload`` triggers those triggers are used for PKGBUILD synchronization - fetch from remote repository PKGBUILDs before updating process.
It supports authorization; to do so you'd need to prefix the URL with authorization part, e.g. ``https://key:token@github.com/arcan1s/ahriman.git``. It is highly recommended to use application tokens instead of your user authorization details. Alternatively, you can use any other option supported by git, e.g.: It supports authorization; to do so you'd need to prefix the URL with authorization part, e.g. ``https://key:token@github.com/arcan1s/ahriman.git``. It is highly recommended to use application tokens instead of your user authorization details. Alternatively, you can use any other option supported by git, e.g.:

View File

@ -311,6 +311,12 @@ Automatic worker nodes discovery
Instead of setting ``${build:workers}`` option explicitly it is also possible to configure services to load worker list dynamically. To do so, the ``ahriman.core.distributed.WorkerLoaderTrigger`` and ``ahriman.core.distributed.WorkerTrigger`` must be used for **master** and **worker** nodes respectively. See recipes for more details. Instead of setting ``${build:workers}`` option explicitly it is also possible to configure services to load worker list dynamically. To do so, the ``ahriman.core.distributed.WorkerLoaderTrigger`` and ``ahriman.core.distributed.WorkerTrigger`` must be used for **master** and **worker** nodes respectively. See recipes for more details.
Those triggers have to be installed as a separate package:
.. code-block:: shell
yay -S ahriman-triggers
Known limitations Known limitations
""""""""""""""""" """""""""""""""""

View File

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

View File

@ -13,7 +13,7 @@ TL;DR
.. code-block:: shell .. code-block:: shell
yay -S ahriman yay -S ahriman-core
ahriman -a x86_64 -r aur service-setup --packager "ahriman bot <ahriman@example.com>" ahriman -a x86_64 -r aur service-setup --packager "ahriman bot <ahriman@example.com>"
systemctl enable --now ahriman@x86_64-aur.timer systemctl enable --now ahriman@x86_64-aur.timer
@ -148,13 +148,11 @@ Before using this command you will need to create local directory and put ``PKGB
How to copy package from another repository How to copy package from another repository
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
As simple as add package from archive. Considering case when you would like to copy package ``package`` with version ``ver-rel`` from repository ``source-repository`` to ``target-respository`` (same architecture), the command will be following: It is possible to copy package and its metadata between local repositories, optionally removing the source archive, e.g.:
.. code-block:: shell .. code-block:: shell
sudo -u ahriman ahriman -r target-repository package-add /var/lib/ahriman/repository/source-repository/x86_64/package-ver-rel-x86_64.pkg.tar.zst sudo -u ahriman ahriman -r target-repository package-copy source-repository ahriman
In addition, you can remove source package as usual later.
This feature in particular useful if for managing multiple repositories like ``[testing]`` and ``[extra]``. This feature in particular useful if for managing multiple repositories like ``[testing]`` and ``[extra]``.

View File

@ -1,6 +1,12 @@
Maintenance packages Maintenance packages
-------------------- --------------------
Those features require extensions package to be installed before, e.g.:
.. code-block:: shell
yay -S ahriman-triggers
Generate keyring package Generate keyring package
^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^

View File

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

View File

@ -5,11 +5,11 @@ How to setup web service
^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^
#. #.
Install dependencies: Install web service:
.. code-block:: shell .. code-block:: shell
yay -S --asdeps python-aiohttp python-aiohttp-jinja2 python-aiohttp-apispec>=3.0.0 python-aiohttp-cors yay -S ahriman-web
#. #.
Configure service: Configure service:

View File

@ -34,8 +34,8 @@ Contents
configuration configuration
command-line command-line
faq/index faq/index
migration migrations/index
architecture architecture
advanced-usage advanced-usage/index
triggers triggers
modules modules

View File

@ -1,25 +1,5 @@
Manual migrations
=================
Normally the most of migrations are handled automatically after application start, however, some upgrades require manual interventions; this document describes them.
Upgrades to breakpoints
-----------------------
To 2.9.0
^^^^^^^^
This release includes major upgrade for the newest devtools and archlinux repository structure. In order to upgrade package need to:
#. Upgrade to the latest major release of python (3.11) (required by other changes).
#. Upgrade devtools to the latest release.
#. Backup local settings, ``/etc/ahriman.ini.d/00-setup-overrides.ini`` by default.
#. Run setup command (i.e. ``ahriman service-setup``) again with the same arguments as used before. This step can be done manually by moving ``devtools`` configuration (something like ``/usr/share/devtools/pacman-ahriman*.conf``) to new location ``/usr/share/devtools/pacman.conf.d/`` under name ``ahriman.conf``. After that make sure to remove any ``community`` mentions from configurations (e.g. ``/usr/share/devtools/pacman.conf.d/ahriman.conf``, ``/etc/ahriman.ini``) if there were any. The only thing which will change is ``devtools`` configuration.
#. Remove build chroot as it is incompatible, e.g. ``sudo ahriman service-clean --chroot``.
#. Run ``sudo -u ahriman ahriman update --no-aur --no-local --no-manual -yy`` in order to update local databases.
To 2.12.0 To 2.12.0
^^^^^^^^^ ---------
This release includes paths migration. Unlike usual case, no automatic migration is performed because it might break user configuration. The following noticeable changes have been made: This release includes paths migration. Unlike usual case, no automatic migration is performed because it might break user configuration. The following noticeable changes have been made:

View File

@ -0,0 +1,16 @@
To 2.16.0
---------
This release replaces ``passlib`` dependency with ``bcrypt``.
The reason behind this change is that python developers have deprecated and scheduled for removal ``crypt`` module, which is used by ``passlib``. (By the way, they recommend to use ``passlib`` as a replacement.) Unfortunately, it appears that ``passlib`` is unmaintained (see `the issue <https://foss.heptapod.net/python-libs/passlib/-/issues/187>`__), so the only solution is to migrate to another library.
Because passwords are stored as hashes, it is near to impossible to shadow change passwords in database, the manual intervention is required if:
#. Authentication is used.
#. Notification provider is ``configuration`` or a user with explicitly set password exists.
Manual steps might look as:
#. Get list of users with their roles ``ahriman user-list``.
#. For each user run update command, i.e. ``ahriman user-add <username> -R <role>``. Type password when it will be requested.

11
docs/migrations/2.9.0.rst Normal file
View File

@ -0,0 +1,11 @@
To 2.9.0
--------
This release includes major upgrade for the newest devtools and archlinux repository structure. In order to upgrade package need to:
#. Upgrade to the latest major release of python (3.11) (required by other changes).
#. Upgrade devtools to the latest release.
#. Backup local settings, ``/etc/ahriman.ini.d/00-setup-overrides.ini`` by default.
#. Run setup command (i.e. ``ahriman service-setup``) again with the same arguments as used before. This step can be done manually by moving ``devtools`` configuration (something like ``/usr/share/devtools/pacman-ahriman*.conf``) to new location ``/usr/share/devtools/pacman.conf.d/`` under name ``ahriman.conf``. After that make sure to remove any ``community`` mentions from configurations (e.g. ``/usr/share/devtools/pacman.conf.d/ahriman.conf``, ``/etc/ahriman.ini``) if there were any. The only thing which will change is ``devtools`` configuration.
#. Remove build chroot as it is incompatible, e.g. ``sudo ahriman service-clean --chroot``.
#. Run ``sudo -u ahriman ahriman update --no-aur --no-local --no-manual -yy`` in order to update local databases.

14
docs/migrations/index.rst Normal file
View File

@ -0,0 +1,14 @@
Manual migrations
=================
Normally the most of migrations are handled automatically after application start, however, some upgrades require manual interventions; this document describes them.
Upgrades to breakpoints
-----------------------
.. toctree::
:maxdepth: 2
2.9.0
2.12.0
2.16.0

View File

@ -2,7 +2,7 @@ Initial setup
============= =============
#. #.
Install package as usual. Install package(s) as usual. At least, ``ahriman-core`` package is required; other features can be installed separately. Alternatively, it is possible to install meta-package, which includes everything.
#. #.
Change settings if required, see :doc:`configuration reference <configuration>` for more details. Change settings if required, see :doc:`configuration reference <configuration>` for more details.
#. #.
@ -12,6 +12,9 @@ Initial setup
sudo ahriman -a x86_64 -r aur service-setup ... sudo ahriman -a x86_64 -r aur service-setup ...
.. admonition:: Details
:collapsible: closed
``service-setup`` literally does the following steps: ``service-setup`` literally does the following steps:
#. #.

View File

@ -1,58 +1,89 @@
# Maintainer: Evgeniy Alekseev # Maintainer: Evgeniy Alekseev
pkgname='ahriman' pkgbase='ahriman'
pkgver=2.15.3 pkgname=('ahriman' 'ahriman-core' 'ahriman-triggers' 'ahriman-web')
pkgver=2.17.1
pkgrel=1 pkgrel=1
pkgdesc="ArcH linux ReposItory MANager" pkgdesc="ArcH linux ReposItory MANager"
arch=('any') arch=('any')
url="https://github.com/arcan1s/ahriman" url="https://ahriman.readthedocs.io/"
license=('GPL3') license=('GPL-3.0-or-later')
depends=('devtools>=1:1.0.0' 'git' 'pyalpm' 'python-inflection' 'python-passlib' 'python-pyelftools' 'python-requests') depends=('devtools>=1:1.0.0' 'git' 'pyalpm' 'python-bcrypt' 'python-inflection' 'python-pyelftools' 'python-requests')
makedepends=('python-build' 'python-flit' 'python-installer' 'python-wheel') makedepends=('python-build' 'python-flit' 'python-installer' 'python-wheel')
optdepends=('python-aioauth-client: web server with OAuth2 authorization' source=("https://github.com/arcan1s/ahriman/releases/download/$pkgver/$pkgbase-$pkgver.tar.gz"
'python-aiohttp: web server' "$pkgbase.sysusers"
'python-aiohttp-apispec>=3.0.0: web server' "$pkgbase.tmpfiles")
'python-aiohttp-cors: web server'
'python-aiohttp-jinja2: web server' build() {
'python-aiohttp-security: web server with authorization' cd "$pkgbase-$pkgver"
'python-aiohttp-session: web server with authorization'
python -m build --wheel --no-isolation
}
package_ahriman() {
pkgname='ahriman'
pkgdesc="ArcH linux ReposItory MANager (meta package)"
depends=("$pkgbase-core=$pkgver" "$pkgbase-triggers=$pkgver" "$pkgbase-web=$pkgver")
}
package_ahriman-core() {
pkgname='ahriman-core'
optdepends=('ahriman-triggers: additional extensions for the application'
'ahriman-web: web server'
'ipython: an enhanced shell interpreter'
'python-boto3: sync to s3' 'python-boto3: sync to s3'
'python-cerberus: configuration validator' 'python-cerberus: configuration validator'
'python-cryptography: web server with authorization'
'python-matplotlib: usage statistics chart' 'python-matplotlib: usage statistics chart'
'python-requests-unixsocket2: client report to web server by unix socket' 'python-requests-unixsocket2: client report to web server by unix socket'
'python-jinja: html report generation' 'python-jinja: html report generation'
'python-systemd: journal support' 'python-systemd: journal support'
'rsync: sync by using rsync') 'rsync: sync by using rsync')
source=("https://github.com/arcan1s/ahriman/releases/download/$pkgver/$pkgname-$pkgver.tar.gz" install="$pkgbase.install"
'ahriman.sysusers'
'ahriman.tmpfiles')
install="$pkgname.install"
backup=('etc/ahriman.ini' backup=('etc/ahriman.ini'
'etc/ahriman.ini.d/logging.ini') 'etc/ahriman.ini.d/logging.ini')
build() { cd "$pkgbase-$pkgver"
cd "$pkgname-$pkgver"
python -m build --wheel --no-isolation python -m installer --destdir="$pkgdir" "dist/$pkgbase-$pkgver-py3-none-any.whl"
} python subpackages.py "$pkgdir" "$pkgname"
package() {
cd "$pkgname-$pkgver"
python -m installer --destdir="$pkgdir" "dist/$pkgname-$pkgver-py3-none-any.whl"
# thanks too PEP517, which we all wanted, you need to install data files manually nowadays
pushd package && find . \( -type f -or -type l \) -exec install -Dm644 "{}" "$pkgdir/usr/{}" \; && popd
# keep usr/share configs as reference and copy them to /etc # keep usr/share configs as reference and copy them to /etc
install -Dm644 "$pkgdir/usr/share/$pkgname/settings/ahriman.ini" "$pkgdir/etc/ahriman.ini" install -Dm644 "$pkgdir/usr/share/$pkgbase/settings/ahriman.ini" "$pkgdir/etc/ahriman.ini"
install -Dm644 "$pkgdir/usr/share/$pkgname/settings/ahriman.ini.d/logging.ini" "$pkgdir/etc/ahriman.ini.d/logging.ini" install -Dm644 "$pkgdir/usr/share/$pkgbase/settings/ahriman.ini.d/logging.ini" "$pkgdir/etc/ahriman.ini.d/logging.ini"
install -Dm644 "$srcdir/$pkgname.sysusers" "$pkgdir/usr/lib/sysusers.d/$pkgname.conf" install -Dm644 "$srcdir/$pkgbase.sysusers" "$pkgdir/usr/lib/sysusers.d/$pkgbase.conf"
install -Dm644 "$srcdir/$pkgname.tmpfiles" "$pkgdir/usr/lib/tmpfiles.d/$pkgname.conf" install -Dm644 "$srcdir/$pkgbase.tmpfiles" "$pkgdir/usr/lib/tmpfiles.d/$pkgbase.conf"
} }
sha512sums=('19841842641520b573cdde6cb80a7cfcd69756d323fdfeebc2eee2d264a1325ead4ab2f8383bb369f7896bfc1de59d7358f133f4afeb90a9b9f0695f482a58d0' package_ahriman-triggers() {
'53d37efec812afebf86281716259f9ea78a307b83897166c72777251c3eebcb587ecee375d907514781fb2a5c808cbb24ef9f3f244f12740155d0603bf213131' pkgname='ahriman-triggers'
'62b2eccc352d33853ef243c9cddd63663014aa97b87242f1b5bc5099a7dbd69ff3821f24ffc58e1b7f2387bd4e9e9712cc4c67f661b1724ad99cdf09b3717794') pkgdesc="ArcH linux ReposItory MANager, additional extensions"
depends=("$pkgbase-core=$pkgver")
backup=('etc/ahriman.ini.d/00-triggers.ini')
cd "$pkgbase-$pkgver"
python -m installer --destdir="$pkgdir" "dist/$pkgbase-$pkgver-py3-none-any.whl"
python subpackages.py "$pkgdir" "$pkgname"
install -Dm644 "$pkgdir/usr/share/$pkgbase/settings/ahriman.ini.d/00-triggers.ini" "$pkgdir/etc/ahriman.ini.d/00-triggers.ini"
}
package_ahriman-web() {
pkgname='ahriman-web'
pkgdesc="ArcH linux ReposItory MANager, web server"
depends=("$pkgbase-core=$pkgver" 'python-aiohttp-cors' 'python-aiohttp-jinja2')
optdepends=('python-aioauth-client: OAuth2 authorization support'
'python-aiohttp-apispec>=3.0.0: autogenerated API documentation'
'python-aiohttp-security: authorization support'
'python-aiohttp-session: authorization support'
'python-cryptography: authorization support')
backup=('etc/ahriman.ini.d/00-web.ini')
cd "$pkgbase-$pkgver"
python -m installer --destdir="$pkgdir" "dist/$pkgbase-$pkgver-py3-none-any.whl"
python subpackages.py "$pkgdir" "$pkgname"
install -Dm644 "$pkgdir/usr/share/$pkgbase/settings/ahriman.ini.d/00-web.ini" "$pkgdir/etc/ahriman.ini.d/00-web.ini"
}

View File

@ -2,6 +2,7 @@ post_upgrade() {
local breakpoints=( local breakpoints=(
2.9.0-1 2.9.0-1
2.12.0-1 2.12.0-1
2.16.0-1
) )
for v in "${breakpoints[@]}"; do for v in "${breakpoints[@]}"; do
@ -21,7 +22,7 @@ It was found that there was an upgrade from old devtools package to the new one,
* remove build chroot, e.g.: ahriman service-clean --chroot; * remove build chroot, e.g.: ahriman service-clean --chroot;
* update local databases: ahriman update --no-aur --no-local --no-manual -yy. * update local databases: ahriman update --no-aur --no-local --no-manual -yy.
For more information kindly refer to migration notes https://ahriman.readthedocs.io/en/stable/migration.html. For more information kindly refer to migration notes https://ahriman.readthedocs.io/en/stable/migrations/2.9.0.html.
EOF EOF
} }
@ -37,6 +38,16 @@ Whereas old local tree is still supported it is highly recommended to migrate to
* enable web and timer services again by using x86_64-aur suffix, * enable web and timer services again by using x86_64-aur suffix,
where x86_64 is the repository architecture and aur is the repository name. where x86_64 is the repository architecture and aur is the repository name.
For more information kindly refer to migration notes https://ahriman.readthedocs.io/en/stable/migration.html. For more information kindly refer to migration notes https://ahriman.readthedocs.io/en/stable/migrations/2.12.0.html.
EOF
}
_2_16_0_1_changes() {
cat << EOF
In order to prepare to python 3.13 the project now uses bcrypt instead of passlib for generating and validating
passwords, because the passlib seems to be unmaintained and will be broken since then. If you are using password
authentication, you'd need to generate passwords again.
For more information kindly refer to migration notes https://ahriman.readthedocs.io/en/stable/migrations/2.16.0.html.
EOF EOF
} }

View File

@ -7,6 +7,8 @@ logging = ahriman.ini.d/logging.ini
;apply_migrations = yes ;apply_migrations = yes
; Path to the application SQLite database. ; Path to the application SQLite database.
database = ${repository:root}/ahriman.db database = ${repository:root}/ahriman.db
; Keep last build logs for each package
keep_last_logs = 5
[alpm] [alpm]
; Path to pacman system database cache. ; Path to pacman system database cache.
@ -23,32 +25,6 @@ sync_files_database = yes
; as additional option for some subcommands). If set to no, databases must be synchronized manually. ; as additional option for some subcommands). If set to no, databases must be synchronized manually.
use_ahriman_cache = yes use_ahriman_cache = yes
[auth]
; Authentication provider, must be one of disabled, configuration, pam, oauth.
target = disabled
; Allow read-only endpoint to be called without authentication.
allow_read_only = yes
; OAuth2 application client ID and secret. Required if oauth is used.
;client_id =
;client_secret =
; Cookie secret key to be used for cookies encryption. Must be valid 32 bytes URL-safe base64-encoded string.
; If not set, it will be generated automatically.
;cookie_secret_key =
; Name of the secondary group to be used as admin group in the service. Required if pam is used.
;full_access_group = wheel
; Authentication cookie expiration in seconds.
;max_age = 604800
; OAuth2 provider icon for the web interface.
;oauth_icon = google
; OAuth2 provider class name, one of provided by aioauth-client. Required if oauth is used.
;oauth_provider = GoogleClient
; Scopes list for OAuth2 provider. Required if oauth is used.
;oauth_scopes = https://www.googleapis.com/auth/userinfo.email
; Allow login as root user (only applicable if PAM is used).
;permit_root_login = no
; Optional password salt.
;salt =
[build] [build]
; List of additional flags passed to archbuild command. ; List of additional flags passed to archbuild command.
;archbuild_flags = ;archbuild_flags =
@ -65,15 +41,17 @@ makepkg_flags = --nocolor --ignorearch
; List of paths to be used for implicit dependency scan. Regular expressions are supported. ; List of paths to be used for implicit dependency scan. Regular expressions are supported.
scan_paths = ^usr/lib(?!/cmake).*$ scan_paths = ^usr/lib(?!/cmake).*$
; List of enabled triggers in the order of calls. ; List of enabled triggers in the order of calls.
triggers = ahriman.core.gitremote.RemotePullTrigger ahriman.core.report.ReportTrigger ahriman.core.upload.UploadTrigger ahriman.core.gitremote.RemotePushTrigger triggers[] = ahriman.core.gitremote.RemotePullTrigger
triggers[] = ahriman.core.report.ReportTrigger
triggers[] = ahriman.core.upload.UploadTrigger
triggers[] = ahriman.core.gitremote.RemotePushTrigger
; List of well-known triggers. Used only for configuration purposes. ; List of well-known triggers. Used only for configuration purposes.
triggers_known = ahriman.core.distributed.WorkerLoaderTrigger ahriman.core.distributed.WorkerRegisterTrigger ahriman.core.distributed.WorkerTrigger ahriman.core.distributed.WorkerUnregisterTrigger ahriman.core.gitremote.RemotePullTrigger ahriman.core.gitremote.RemotePushTrigger ahriman.core.report.ReportTrigger ahriman.core.upload.UploadTrigger ahriman.core.support.KeyringTrigger ahriman.core.support.MirrorlistTrigger triggers_known[] = ahriman.core.gitremote.RemotePullTrigger
triggers_known[] = ahriman.core.gitremote.RemotePushTrigger
triggers_known[] = ahriman.core.report.ReportTrigger
triggers_known[] = ahriman.core.upload.UploadTrigger
; Maximal age in seconds of the VCS packages before their version will be updated with its remote source. ; Maximal age in seconds of the VCS packages before their version will be updated with its remote source.
;vcs_allowed_age = 604800 ;vcs_allowed_age = 604800
; List of worker nodes addresses used for build process, e.g.:
; workers = http://10.0.0.1:8080 http://10.0.0.3:8080
; Empty list means run on the local instance.
;workers =
[repository] [repository]
; Application root. ; Application root.
@ -102,79 +80,6 @@ suppress_http_log_errors = yes
; Optional username for authentication (if enabled). ; Optional username for authentication (if enabled).
;username = ;username =
[web]
; External address of the web service. Will be used for some features like OAuth. If none set will be generated as
; address = http://${web:host}:${web:port}
;address = http://${web:host}:${web:port}
; Enable file upload endpoint used by some triggers.
;enable_archive_upload = no
; Address to bind the server.
host = 127.0.0.1
; Full URL to the repository index page used by templates.
;index_url =
; Max file size in bytes which can be uploaded to the server. Requires ${web:enable_archive_upload} to be enabled.
;max_body_size =
; Port to listen. Must be set, if the web service is enabled.
;port =
; Disable status (e.g. package status, logs, etc) endpoints. Useful for build only modes.
;service_only = no
; Path to directory with static files.
static_path = ${templates}/static
; List of directories with templates.
templates = ${prefix}/share/ahriman/templates
; Path to unix socket. If none set, unix socket will be disabled.
;unix_socket =
; Allow unix socket to be world readable.
;unix_socket_unsafe = yes
; Maximum amount of time in seconds to be waited before lock will be free, used by spawned processes (0 is infinite).
;wait_timeout =
[keyring]
; List of configuration section names for keyring generator plugin, e.g.:
; target = keyring-trigger
target =
; Keyring generator trigger sample.
;[keyring-trigger]
; Generator type name.
;type = keyring-generator
; Optional keyring package description.
;description=
; Optional URL to the repository homepage.
;homepage=
; Keyring package licenses list.
;license = Unlicense
; Optional keyring package name.
;package =
; Optional packager PGP keys list. If none set, it will read from database.
;packagers =
; List of revoked PGP keys.
;revoked =
; List of master PGP keys. If none set, the sign.key value will be used.
;trusted =
[mirrorlist]
; List of configuration section names for mirrorlist generator plugin, e.g.:
; target = mirrorlist-trigger
target =
; Mirror list generator trigger sample.
;[mirrorlist-trigger]
; Generator type name.
;type = mirrorlist-generator
; Optional mirrorlist package description.
;description=
; Optional URL to the repository homepage.
;homepage=
; Mirrorlist package licenses list.
;license = Unlicense
; Optional mirrorlist package name.
;package =
; Absolute path to generated mirrorlist file, usually path inside /etc/pacman.d directory.
;path =
; List of repository mirrors.
;servers =
[remote-pull] [remote-pull]
; List of configuration section names for git remote pull plugin, e.g.: ; List of configuration section names for git remote pull plugin, e.g.:
; target = remote-pull-trigger ; target = remote-pull-trigger
@ -246,7 +151,7 @@ template = email-index.jinja2
; Template name to be used for full packages list generation (same as HTML report). ; Template name to be used for full packages list generation (same as HTML report).
;template_full = ;template_full =
; List of directories with templates. ; List of directories with templates.
templates = ${prefix}/share/ahriman/templates templates[] = ${prefix}/share/ahriman/templates
; SMTP user. ; SMTP user.
;user = ;user =
@ -265,7 +170,7 @@ templates = ${prefix}/share/ahriman/templates
; Template name to be used. ; Template name to be used.
template = repo-index.jinja2 template = repo-index.jinja2
; List of directories with templates. ; List of directories with templates.
templates = ${prefix}/share/ahriman/templates templates[] = ${prefix}/share/ahriman/templates
; Remote service callback trigger configuration sample. ; Remote service callback trigger configuration sample.
[remote-call] [remote-call]
@ -295,7 +200,7 @@ templates = ${prefix}/share/ahriman/templates
; Template name to be used. ; Template name to be used.
template = rss.jinja2 template = rss.jinja2
; List of directories with templates. ; List of directories with templates.
templates = ${prefix}/share/ahriman/templates templates[] = ${prefix}/share/ahriman/templates
; Telegram reporting trigger configuration sample. ; Telegram reporting trigger configuration sample.
[telegram] [telegram]
@ -316,7 +221,7 @@ template = telegram-index.jinja2
; Telegram specific template mode, one of MarkdownV2, HTML or Markdown. ; Telegram specific template mode, one of MarkdownV2, HTML or Markdown.
;template_type = HTML ;template_type = HTML
; List of directories with templates. ; List of directories with templates.
templates = ${prefix}/share/ahriman/templates templates[] = ${prefix}/share/ahriman/templates
; HTTP request timeout in seconds. ; HTTP request timeout in seconds.
;timeout = 30 ;timeout = 30

View File

@ -0,0 +1,56 @@
[build]
; List of well-known triggers. Used only for configuration purposes.
triggers_known[] = ahriman.core.distributed.WorkerLoaderTrigger
triggers_known[] = ahriman.core.distributed.WorkerTrigger
triggers_known[] = ahriman.core.support.KeyringTrigger
triggers_known[] = ahriman.core.support.MirrorlistTrigger
; List of worker nodes addresses used for build process, e.g.:
; workers = http://10.0.0.1:8080 http://10.0.0.3:8080
; Empty list means run on the local instance.
;workers =
[keyring]
; List of configuration section names for keyring generator plugin, e.g.:
; target = keyring-trigger
target =
; Keyring generator trigger sample.
;[keyring-trigger]
; Generator type name.
;type = keyring-generator
; Optional keyring package description.
;description=
; Optional URL to the repository homepage.
;homepage=
; Keyring package licenses list.
;license = Unlicense
; Optional keyring package name.
;package =
; Optional packager PGP keys list. If none set, it will read from database.
;packagers =
; List of revoked PGP keys.
;revoked =
; List of master PGP keys. If none set, the sign.key value will be used.
;trusted =
[mirrorlist]
; List of configuration section names for mirrorlist generator plugin, e.g.:
; target = mirrorlist-trigger
target =
; Mirror list generator trigger sample.
;[mirrorlist-trigger]
; Generator type name.
;type = mirrorlist-generator
; Optional mirrorlist package description.
;description=
; Optional URL to the repository homepage.
;homepage=
; Mirrorlist package licenses list.
;license = Unlicense
; Optional mirrorlist package name.
;package =
; Absolute path to generated mirrorlist file, usually path inside /etc/pacman.d directory.
;path =
; List of repository mirrors.
;servers =

View File

@ -0,0 +1,52 @@
[auth]
; Authentication provider, must be one of disabled, configuration, pam, oauth.
target = disabled
; Allow read-only endpoint to be called without authentication.
allow_read_only = yes
; OAuth2 application client ID and secret. Required if oauth is used.
;client_id =
;client_secret =
; Cookie secret key to be used for cookies encryption. Must be valid 32 bytes URL-safe base64-encoded string.
; If not set, it will be generated automatically.
;cookie_secret_key =
; Name of the secondary group to be used as admin group in the service. Required if pam is used.
;full_access_group = wheel
; Authentication cookie expiration in seconds.
;max_age = 604800
; OAuth2 provider icon for the web interface.
;oauth_icon = google
; OAuth2 provider class name, one of provided by aioauth-client. Required if oauth is used.
;oauth_provider = GoogleClient
; Scopes list for OAuth2 provider. Required if oauth is used.
;oauth_scopes = https://www.googleapis.com/auth/userinfo.email
; Allow login as root user (only applicable if PAM is used).
;permit_root_login = no
; Optional password salt.
;salt =
[web]
; External address of the web service. Will be used for some features like OAuth. If none set will be generated as
; address = http://${web:host}:${web:port}
;address = http://${web:host}:${web:port}
; Enable file upload endpoint used by some triggers.
;enable_archive_upload = no
; Address to bind the server.
host = 127.0.0.1
; Full URL to the repository index page used by templates.
;index_url =
; Max file size in bytes which can be uploaded to the server. Requires ${web:enable_archive_upload} to be enabled.
;max_body_size =
; Port to listen. Must be set, if the web service is enabled.
;port =
; Disable status (e.g. package status, logs, etc) endpoints. Useful for build only modes.
;service_only = no
; Path to directory with static files.
static_path = ${templates}/static
; List of directories with templates.
templates[] = ${prefix}/share/ahriman/templates
; Path to unix socket. If none set, unix socket will be disabled.
;unix_socket =
; Allow unix socket to be world readable.
;unix_socket_unsafe = yes
; Maximum amount of time in seconds to be waited before lock will be free, used by spawned processes (0 is infinite).
;wait_timeout =

View File

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

View File

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

View File

@ -7,10 +7,17 @@
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div class="form-group row mt-2"> <div class="form-group row mt-2">
<div class="col-4 col-lg-1" style="text-align: right">packages</div>
<div id="package-info-packages" class="col-8 col-lg-5"></div>
<div class="col-4 col-lg-1" style="text-align: right">version</div> <div class="col-4 col-lg-1" style="text-align: right">version</div>
<div id="package-info-version" class="col-8 col-lg-5"></div> <div id="package-info-version" class="col-8 col-lg-5"></div>
</div>
<div class="form-group row mt-2">
<div class="col-4 col-lg-1" style="text-align: right">packager</div> <div class="col-4 col-lg-1" style="text-align: right">packager</div>
<div id="package-info-packager" class="col-8 col-lg-5"></div> <div id="package-info-packager" class="col-8 col-lg-5"></div>
<div class="col-4 col-lg-1" style="text-align: right"></div>
<div id="package-info---placeholder" class="col-8 col-lg-5"></div>
</div> </div>
<div class="form-group row mt-2"> <div class="form-group row mt-2">
@ -28,10 +35,10 @@
</div> </div>
<div class="form-group row mt-2"> <div class="form-group row mt-2">
<div class="col-4 col-lg-1" style="text-align: right">packages</div>
<div id="package-info-packages" class="col-8 col-lg-5"></div>
<div class="col-4 col-lg-1" style="text-align: right">depends</div> <div class="col-4 col-lg-1" style="text-align: right">depends</div>
<div id="package-info-depends" class="col-8 col-lg-5"></div> <div id="package-info-depends" class="col-8 col-lg-5"></div>
<div class="col-4 col-lg-1" style="text-align: right">implicitly depends</div>
<div id="package-info-implicitly-depends" class="col-8 col-lg-5"></div>
</div> </div>
<hr class="col-12"> <hr class="col-12">
@ -52,8 +59,18 @@
</nav> </nav>
<div class="tab-content" id="nav-tabContent"> <div class="tab-content" id="nav-tabContent">
<div id="package-info-logs" class="tab-pane fade show active" role="tabpanel" aria-labelledby="package-info-logs-button" tabindex="0"> <div id="package-info-logs" class="tab-pane fade show active" role="tabpanel" aria-labelledby="package-info-logs-button" tabindex="0">
<div class="row">
<div class="col-1 dropend">
<button id="package-info-logs-dropdown" class="btn dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<i class="bi bi-list"></i>
</button>
<nav id="package-info-logs-versions" class="dropdown-menu" aria-labelledby="package-info-logs-dropdown"></nav>
</div>
<div class="col-11">
<pre class="language-console"><code id="package-info-logs-input" class="pre-scrollable language-console"></code><button id="package-info-logs-copy-button" type="button" class="btn language-console" onclick="copyLogs()"><i class="bi bi-clipboard"></i> copy</button></pre> <pre class="language-console"><code id="package-info-logs-input" class="pre-scrollable language-console"></code><button id="package-info-logs-copy-button" type="button" class="btn language-console" onclick="copyLogs()"><i class="bi bi-clipboard"></i> copy</button></pre>
</div> </div>
</div>
</div>
<div id="package-info-changes" class="tab-pane fade" role="tabpanel" aria-labelledby="package-info-changes-button" tabindex="0"> <div id="package-info-changes" class="tab-pane fade" role="tabpanel" aria-labelledby="package-info-changes-button" tabindex="0">
<pre class="language-diff"><code id="package-info-changes-input" class="pre-scrollable language-diff"></code><button id="package-info-changes-copy-button" type="button" class="btn language-diff" onclick="copyChanges()"><i class="bi bi-clipboard"></i> copy</button></pre> <pre class="language-diff"><code id="package-info-changes-input" class="pre-scrollable language-diff"></code><button id="package-info-changes-copy-button" type="button" class="btn language-diff" onclick="copyChanges()"><i class="bi bi-clipboard"></i> copy</button></pre>
</div> </div>
@ -93,6 +110,7 @@
const packageInfoModalHeader = document.getElementById("package-info-modal-header"); const packageInfoModalHeader = document.getElementById("package-info-modal-header");
const packageInfo = document.getElementById("package-info"); const packageInfo = document.getElementById("package-info");
const packageInfoLogsVersions = document.getElementById("package-info-logs-versions");
const packageInfoLogsInput = document.getElementById("package-info-logs-input"); const packageInfoLogsInput = document.getElementById("package-info-logs-input");
const packageInfoLogsCopyButton = document.getElementById("package-info-logs-copy-button"); const packageInfoLogsCopyButton = document.getElementById("package-info-logs-copy-button");
@ -107,6 +125,7 @@
const packageInfoAurUrl = document.getElementById("package-info-aur-url"); const packageInfoAurUrl = document.getElementById("package-info-aur-url");
const packageInfoDepends = document.getElementById("package-info-depends"); const packageInfoDepends = document.getElementById("package-info-depends");
const packageInfoGroups = document.getElementById("package-info-groups"); const packageInfoGroups = document.getElementById("package-info-groups");
const packageInfoImplicitlyDepends = document.getElementById("package-info-implicitly-depends");
const packageInfoLicenses = document.getElementById("package-info-licenses"); const packageInfoLicenses = document.getElementById("package-info-licenses");
const packageInfoPackager = document.getElementById("package-info-packager"); const packageInfoPackager = document.getElementById("package-info-packager");
const packageInfoPackages = document.getElementById("package-info-packages"); const packageInfoPackages = document.getElementById("package-info-packages");
@ -155,7 +174,7 @@
const variableValueInput = document.createElement("input"); const variableValueInput = document.createElement("input");
variableValueInput.classList.add("form-control"); variableValueInput.classList.add("form-control");
variableValueInput.readOnly = true; variableValueInput.readOnly = true;
variableValueInput.value = variable.value; variableValueInput.value = JSON.stringify(variable.value);
const variableButtonRemove = document.createElement("button"); const variableButtonRemove = document.createElement("button");
variableButtonRemove.type = "button"; variableButtonRemove.type = "button";
@ -200,6 +219,26 @@
); );
} }
function loadDependencies(packageBase, onFailure) {
makeRequest(
`/api/v1/packages/${packageBase}/dependencies`,
{
query: {
architecture: repository.architecture,
repository: repository.repository,
},
convert: response => response.json(),
},
data => {
packageInfoImplicitlyDepends.innerHTML = listToTable(
Object.values(data.paths)
.reduce((accumulator, currentValue) => accumulator.concat(currentValue), [])
);
},
onFailure,
);
}
function loadEvents(packageBase, onFailure) { function loadEvents(packageBase, onFailure) {
packageInfoEventsTable.bootstrapTable("showLoading"); packageInfoEventsTable.bootstrapTable("showLoading");
clearChart(); clearChart();
@ -257,25 +296,51 @@
convert: response => response.json(), convert: response => response.json(),
}, },
data => { data => {
const logs = data.map(log_record => { const selectors = Object
return `[${new Date(1000 * log_record.created).toISOString()}] ${log_record.message}`; .values(
}); data.reduce((acc, log_record) => {
const id = `${log_record.version}-${log_record.process_id}`;
if (acc[id])
acc[id].created = Math.min(log_record.created, acc[id].created);
else
acc[id] = log_record;
return acc;
}, {})
)
.sort(({created: left}, {created: right}) =>
right - left
)
.map(version => {
const link = document.createElement("a");
link.classList.add("dropdown-item");
link.textContent = new Date(1000 * version.created).toISOStringShort();
link.href = "#";
link.onclick = _ => {
const logs = data
.filter(log_record => log_record.version === version.version && log_record.process_id === version.process_id)
.map(log_record => `[${new Date(1000 * log_record.created).toISOString()}] ${log_record.message}`);
packageInfoLogsInput.textContent = logs.join("\n"); packageInfoLogsInput.textContent = logs.join("\n");
highlight(packageInfoLogsInput); highlight(packageInfoLogsInput);
Array.from(packageInfoLogsVersions.children).forEach(el => el.classList.remove("active"));
link.classList.add("active");
return false;
};
return link;
});
packageInfoLogsVersions.replaceChildren(...selectors);
selectors.find(Boolean)?.click();
}, },
onFailure, onFailure,
); );
} }
function loadPackage(packageBase, onFailure) { function loadPackage(packageBase, onFailure) {
const headerClass = status => {
if (status === "pending") return ["bg-warning"];
if (status === "building") return ["bg-warning"];
if (status === "failed") return ["bg-danger", "text-white"];
if (status === "success") return ["bg-success", "text-white"];
return ["bg-secondary", "text-white"];
};
makeRequest( makeRequest(
`/api/v1/packages/${packageBase}`, `/api/v1/packages/${packageBase}`,
{ {
@ -287,14 +352,9 @@
}, },
data => { data => {
const description = data.find(Boolean); const description = data.find(Boolean);
const packages = Object.keys(description.package.packages); const packages = description.package.packages;
const aurUrl = description.package.remote.web_url; const aurUrl = description.package.remote.web_url;
const upstreamUrls = Array.from( const upstreamUrls = Array.from(new Set(Object.values(packages).map(single => single.url))).sort();
new Set(
Object.values(description.package.packages)
.map(single => single.url)
)
).sort();
packageInfo.textContent = `${description.package.base} ${description.status.status} at ${new Date(1000 * description.status.timestamp).toISOStringShort()}`; packageInfo.textContent = `${description.package.base} ${description.status.status} at ${new Date(1000 * description.status.timestamp).toISOStringShort()}`;
@ -304,17 +364,17 @@
packageInfoAurUrl.innerHTML = aurUrl ? safeLink(aurUrl, aurUrl, "AUR link").outerHTML : ""; packageInfoAurUrl.innerHTML = aurUrl ? safeLink(aurUrl, aurUrl, "AUR link").outerHTML : "";
packageInfoDepends.innerHTML = listToTable( packageInfoDepends.innerHTML = listToTable(
Object.values(description.package.packages) Object.values(packages)
.reduce((accumulator, currentValue) => { .reduce((accumulator, currentValue) => {
return accumulator.concat(currentValue.depends.filter(v => packages.indexOf(v) === -1)) return accumulator.concat(currentValue.depends.filter(v => !packages.hasOwnProperty(v)))
.concat(currentValue.make_depends.filter(v => packages.indexOf(v) === -1).map(v => `${v} (make)`)) .concat(currentValue.make_depends.filter(v => !packages.hasOwnProperty(v)).map(v => `${v} (make)`))
.concat(currentValue.opt_depends.filter(v => packages.indexOf(v) === -1).map(v => `${v} (optional)`)); .concat(currentValue.opt_depends.filter(v => !packages.hasOwnProperty(v)).map(v => `${v} (optional)`));
}, []) }, [])
); );
packageInfoGroups.innerHTML = listToTable(extractListProperties(description.package, "groups")); packageInfoGroups.innerHTML = listToTable(extractListProperties(description.package, "groups"));
packageInfoLicenses.innerHTML = listToTable(extractListProperties(description.package, "licenses")); packageInfoLicenses.innerHTML = listToTable(extractListProperties(description.package, "licenses"));
packageInfoPackager.textContent = description.package.packager; packageInfoPackager.textContent = description.package.packager;
packageInfoPackages.innerHTML = listToTable(packages); packageInfoPackages.innerHTML = listToTable(Object.entries(packages).map(([key, value]) => `${key} (${value.description})`));
packageInfoUpstreamUrl.innerHTML = upstreamUrls.map(url => safeLink(url, url, "upstream link").outerHTML).join("<br>"); packageInfoUpstreamUrl.innerHTML = upstreamUrls.map(url => safeLink(url, url, "upstream link").outerHTML).join("<br>");
packageInfoVersion.textContent = description.package.version; packageInfoVersion.textContent = description.package.version;
}, },
@ -365,6 +425,7 @@
}; };
loadPackage(packageBase, onFailure); loadPackage(packageBase, onFailure);
loadDependencies(packageBase, onFailure);
loadPatches(packageBase, onFailure); loadPatches(packageBase, onFailure);
loadLogs(packageBase, onFailure); loadLogs(packageBase, onFailure);
loadChanges(packageBase, onFailure); loadChanges(packageBase, onFailure);
@ -388,6 +449,7 @@
packageInfoAurUrl.textContent = ""; packageInfoAurUrl.textContent = "";
packageInfoDepends.textContent = ""; packageInfoDepends.textContent = "";
packageInfoGroups.textContent = ""; packageInfoGroups.textContent = "";
packageInfoImplicitlyDepends.textContent = "";
packageInfoLicenses.textContent = ""; packageInfoLicenses.textContent = "";
packageInfoPackager.textContent = ""; packageInfoPackager.textContent = "";
packageInfoPackages.textContent = ""; packageInfoPackages.textContent = "";

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -30,12 +30,14 @@ class ImportType(StrEnum):
import type enumeration import type enumeration
Attributes: Attributes:
Future(MethodTypeOrder): (class attribute) from __future__ import
Package(MethodTypeOrder): (class attribute) package import Package(MethodTypeOrder): (class attribute) package import
PackageFrom(MethodTypeOrder): (class attribute) package import, from clause PackageFrom(MethodTypeOrder): (class attribute) package import, from clause
System(ImportType): (class attribute) system installed packages System(ImportType): (class attribute) system installed packages
SystemFrom(MethodTypeOrder): (class attribute) system installed packages, from clause SystemFrom(MethodTypeOrder): (class attribute) system installed packages, from clause
""" """
Future = "future"
Package = "package" Package = "package"
PackageFrom = "package-from" PackageFrom = "package-from"
System = "system" System = "system"
@ -70,6 +72,7 @@ class ImportOrder(BaseRawFileChecker):
"import-type-order", "import-type-order",
{ {
"default": [ "default": [
"future",
"system", "system",
"system-from", "system-from",
"package", "package",
@ -91,7 +94,7 @@ class ImportOrder(BaseRawFileChecker):
) )
@staticmethod @staticmethod
def imports(source: Iterable[Any], start_lineno: int = 0) -> list[nodes.Import | nodes.ImportFrom]: def imports(source: Iterable[Any], start_lineno: int = 0) -> Iterable[nodes.Import | nodes.ImportFrom]:
""" """
extract import nodes from list of raw nodes extract import nodes from list of raw nodes
@ -100,7 +103,7 @@ class ImportOrder(BaseRawFileChecker):
start_lineno(int, optional): minimal allowed line number (Default value = 0) start_lineno(int, optional): minimal allowed line number (Default value = 0)
Returns: Returns:
list[nodes.Import | nodes.ImportFrom]: list of import nodes Iterable[nodes.Import | nodes.ImportFrom]: list of import nodes
""" """
def is_defined_import(imports: Any) -> bool: def is_defined_import(imports: Any) -> bool:
@ -108,7 +111,7 @@ class ImportOrder(BaseRawFileChecker):
and imports.lineno is not None \ and imports.lineno is not None \
and imports.lineno >= start_lineno and imports.lineno >= start_lineno
return list(filter(is_defined_import, source)) return sorted(filter(is_defined_import, source), key=lambda imports: imports.lineno)
def check_from_imports(self, imports: nodes.ImportFrom) -> None: def check_from_imports(self, imports: nodes.ImportFrom) -> None:
""" """
@ -124,30 +127,36 @@ class ImportOrder(BaseRawFileChecker):
self.add_message("from-imports-out-of-order", line=imports.lineno, args=(real, expected)) self.add_message("from-imports-out-of-order", line=imports.lineno, args=(real, expected))
break break
def check_imports(self, imports: list[nodes.Import | nodes.ImportFrom], root_package: str) -> None: def check_imports(self, imports: Iterable[nodes.Import | nodes.ImportFrom], root_package: str) -> None:
""" """
check imports check imports
Args: Args:
imports(list[nodes.Import | nodes.ImportFrom]): list of imports in their defined order imports(Iterable[nodes.Import | nodes.ImportFrom]): list of imports in their defined order
root_package(str): root package name root_package(str): root package name
""" """
last_statement: tuple[int, str] | None = None last_statement: tuple[int, str] | None = None
for statement in imports: for statement in imports:
# define types and perform specific checks # define types and perform specific checks
if isinstance(statement, nodes.ImportFrom): match statement:
case nodes.ImportFrom() if statement.modname == "__future__":
import_name = statement.modname
import_type = ImportType.Future
case nodes.ImportFrom():
import_name = statement.modname import_name = statement.modname
root, *_ = import_name.split(".", maxsplit=1) root, *_ = import_name.split(".", maxsplit=1)
import_type = ImportType.PackageFrom if root_package == root else ImportType.SystemFrom import_type = ImportType.PackageFrom if root_package == root else ImportType.SystemFrom
# check from import itself # check from import itself
self.check_from_imports(statement) self.check_from_imports(statement)
else: case nodes.Import():
import_name = next(name for name, _ in statement.names) import_name = next(name for name, _ in statement.names)
root, *_ = import_name.split(".", maxsplit=1)[0] root, *_ = import_name.split(".", maxsplit=1)
import_type = ImportType.Package if root_package == root else ImportType.System import_type = ImportType.Package if root_package == root else ImportType.System
# check import itself # check import itself
self.check_package_imports(statement) self.check_package_imports(statement)
case _:
continue
# extract index # extract index
try: try:

View File

@ -17,8 +17,8 @@ authors = [
] ]
dependencies = [ dependencies = [
"bcrypt",
"inflection", "inflection",
"passlib",
"pyelftools", "pyelftools",
"requests", "requests",
] ]
@ -60,6 +60,9 @@ pacman = [
s3 = [ s3 = [
"boto3", "boto3",
] ]
shell = [
"IPython"
]
stats = [ stats = [
"matplotlib", "matplotlib",
] ]
@ -95,8 +98,12 @@ include = [
"CONTRIBUTING.md", "CONTRIBUTING.md",
"SECURITY.md", "SECURITY.md",
"package", "package",
"subpackages.py",
"web.png", "web.png",
] ]
exclude = [ exclude = [
"package/archlinux", "package/archlinux",
] ]
[tool.flit.external-data]
directory = "package"

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -141,19 +141,19 @@ class ApplicationPackages(ApplicationProperties):
self.database.build_queue_insert(package) self.database.build_queue_insert(package)
self.reporter.set_unknown(package) self.reporter.set_unknown(package)
def add(self, names: Iterable[str], source: PackageSource, username: str | None = None) -> None: def add(self, packages: Iterable[str], source: PackageSource, username: str | None = None) -> None:
""" """
add packages for the next build add packages for the next build
Args: Args:
names(Iterable[str]): list of package bases to add packages(Iterable[str]): list of package bases to add
source(PackageSource): package source to add source(PackageSource): package source to add
username(str | None, optional): optional override of username for build process (Default value = None) username(str | None, optional): optional override of username for build process (Default value = None)
""" """
for name in names: for package in packages:
resolved_source = source.resolve(name, self.repository.paths) resolved_source = source.resolve(package, self.repository.paths)
fn = getattr(self, f"_add_{resolved_source.value}") fn = getattr(self, f"_add_{resolved_source.value}")
fn(name, username) fn(package, username)
def on_result(self, result: Result) -> None: def on_result(self, result: Result) -> None:
""" """
@ -167,16 +167,16 @@ class ApplicationPackages(ApplicationProperties):
""" """
raise NotImplementedError raise NotImplementedError
def remove(self, names: Iterable[str]) -> Result: def remove(self, packages: Iterable[str]) -> Result:
""" """
remove packages from repository remove packages from repository
Args: Args:
names(Iterable[str]): list of packages (either base or name) to remove packages(Iterable[str]): list of packages (either base or name) to remove
Returns: Returns:
Result: removal result Result: removal result
""" """
result = self.repository.process_remove(names) result = self.repository.process_remove(packages)
self.on_result(result) self.on_result(result)
return result return result

View File

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

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -191,6 +191,12 @@ class ApplicationRepository(ApplicationProperties):
""" """
updates = {} updates = {}
# always add already built packages, because they will be always added
updates.update({
package.base: package
for package in self.repository.load_archives(self.repository.packages_built())
})
if aur: if aur:
updates.update({package.base: package for package in self.repository.updates_aur(filter_packages, vcs=vcs)}) updates.update({package.base: package for package in self.repository.updates_aur(filter_packages, vcs=vcs)})
if local: if local:

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -17,36 +17,3 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
from ahriman.application.handlers.add import Add
from ahriman.application.handlers.backup import Backup
from ahriman.application.handlers.change import Change
from ahriman.application.handlers.clean import Clean
from ahriman.application.handlers.daemon import Daemon
from ahriman.application.handlers.dump import Dump
from ahriman.application.handlers.handler import Handler
from ahriman.application.handlers.help import Help
from ahriman.application.handlers.key_import import KeyImport
from ahriman.application.handlers.patch import Patch
from ahriman.application.handlers.rebuild import Rebuild
from ahriman.application.handlers.remove import Remove
from ahriman.application.handlers.remove_unknown import RemoveUnknown
from ahriman.application.handlers.repositories import Repositories
from ahriman.application.handlers.restore import Restore
from ahriman.application.handlers.run import Run
from ahriman.application.handlers.search import Search
from ahriman.application.handlers.service_updates import ServiceUpdates
from ahriman.application.handlers.setup import Setup
from ahriman.application.handlers.shell import Shell
from ahriman.application.handlers.sign import Sign
from ahriman.application.handlers.statistics import Statistics
from ahriman.application.handlers.status import Status
from ahriman.application.handlers.status_update import StatusUpdate
from ahriman.application.handlers.structure import Structure
from ahriman.application.handlers.tree_migrate import TreeMigrate
from ahriman.application.handlers.triggers import Triggers
from ahriman.application.handlers.unsafe_commands import UnsafeCommands
from ahriman.application.handlers.update import Update
from ahriman.application.handlers.users import Users
from ahriman.application.handlers.validate import Validate
from ahriman.application.handlers.versions import Versions
from ahriman.application.handlers.web import Web

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -20,8 +20,10 @@
import argparse import argparse
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, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.utils import enum_values, extract_user
from ahriman.models.package_source import PackageSource
from ahriman.models.packagers import Packagers from ahriman.models.packagers import Packagers
from ahriman.models.pkgbuild_patch import PkgbuildPatch from ahriman.models.pkgbuild_patch import PkgbuildPatch
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -66,3 +68,49 @@ class Add(Handler):
application.print_updates(packages, log_fn=application.logger.info) application.print_updates(packages, log_fn=application.logger.info)
result = application.update(packages, packagers, bump_pkgrel=args.increment) result = application.update(packages, packagers, bump_pkgrel=args.increment)
Add.check_status(args.exit_code, not result.is_empty) Add.check_status(args.exit_code, not result.is_empty)
@staticmethod
def _set_package_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for package addition subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("package-add", aliases=["add", "package-update"], help="add package",
description="add existing or new package to the build queue",
epilog="This subcommand should be used for new package addition. "
"It also supports flag --now in case if you would like to build "
"the package immediately. You can add new package from one of "
"supported sources:\n\n"
"1. If it is already built package you can specify the path to the archive.\n"
"2. You can also add built packages from the directory (e.g. during the "
"migration from another repository source).\n"
"3. It is also possible to add package from local PKGBUILD, but in this case "
"it will be ignored during the next automatic updates.\n"
"4. Ahriman supports downloading archives from remote (e.g. HTTP) sources.\n"
"5. Finally you can add package from AUR.")
parser.add_argument("package", help="package source (base name, path to local files, remote URL)", nargs="+")
parser.add_argument("--changes", help="calculate changes from the latest known commit if available",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--dependencies", help="process missing package dependencies",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty",
action="store_true")
parser.add_argument("--increment", help="increment package release (pkgrel) version on duplicate",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("-n", "--now", help="run update function after", action="store_true")
parser.add_argument("-y", "--refresh", help="download fresh package databases from the mirror before actions, "
"-yy to force refresh even if up to date",
action="count", default=False)
parser.add_argument("-s", "--source", help="explicitly specify the package source for this command",
type=PackageSource, choices=enum_values(PackageSource), default=PackageSource.Auto)
parser.add_argument("-u", "--username", help="build as user", default=extract_user())
parser.add_argument("-v", "--variable", help="apply specified makepkg variables to the next build",
action="append")
return parser
arguments = [_set_package_add_parser]

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -23,7 +23,7 @@ import tarfile
from pathlib import Path from pathlib import Path
from pwd import getpwuid from pwd import getpwuid
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.database import SQLite from ahriman.core.database import SQLite
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -53,6 +53,23 @@ class Backup(Handler):
for backup_path in backup_paths: for backup_path in backup_paths:
archive.add(backup_path) archive.add(backup_path)
@staticmethod
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 repository settings and database")
parser.add_argument("path", help="path of the output archive", type=Path)
parser.set_defaults(architecture="", lock=None, report=False, repository="", unsafe=True)
return parser
@staticmethod @staticmethod
def get_paths(configuration: Configuration) -> set[Path]: def get_paths(configuration: Configuration) -> set[Path]:
""" """
@ -83,3 +100,5 @@ class Backup(Handler):
paths.add(gnupg_home) paths.add(gnupg_home)
return paths return paths
arguments = [_set_repo_backup_parser]

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -20,7 +20,7 @@
import argparse import argparse
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, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.formatters import ChangesPrinter from ahriman.core.formatters import ChangesPrinter
from ahriman.models.action import Action from ahriman.models.action import Action
@ -57,3 +57,43 @@ class Change(Handler):
Change.check_status(args.exit_code, not changes.is_empty) Change.check_status(args.exit_code, not changes.is_empty)
case Action.Remove: case Action.Remove:
client.package_changes_update(args.package, Changes()) client.package_changes_update(args.package, Changes())
@staticmethod
def _set_package_changes_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for package changes subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("package-changes", help="get package changes",
description="retrieve package changes stored in database",
epilog="This command requests package status from the web interface "
"if it is available.")
parser.add_argument("package", help="package base")
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty",
action="store_true")
parser.set_defaults(action=Action.List, lock=None, quiet=True, report=False, unsafe=True)
return parser
@staticmethod
def _set_package_changes_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for package change remove subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("package-changes-remove", help="remove package changes",
description="remove the package changes stored remotely")
parser.add_argument("package", help="package base")
parser.set_defaults(action=Action.Remove, exit_code=False, lock=None, quiet=True, report=False, unsafe=True)
return parser
arguments = [_set_package_changes_parser, _set_package_changes_remove_parser]

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -20,7 +20,7 @@
import argparse import argparse
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, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -46,3 +46,33 @@ class Clean(Handler):
application.on_start() application.on_start()
application.clean(cache=args.cache, chroot=args.chroot, manual=args.manual, packages=args.packages, application.clean(cache=args.cache, chroot=args.chroot, manual=args.manual, packages=args.packages,
pacman=args.pacman) pacman=args.pacman)
@staticmethod
def _set_service_clean_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for repository clean subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("service-clean", aliases=["clean", "repo-clean"], help="clean local caches",
description="remove local caches",
epilog="The subcommand clears every temporary directories (builds, caches etc). "
"Normally you should not run this command manually. Also in case if "
"you are going to clear the chroot directories you will need root privileges.")
parser.add_argument("--cache", help="clear directory with package caches",
action=argparse.BooleanOptionalAction, default=False)
parser.add_argument("--chroot", help="clear build chroot", action=argparse.BooleanOptionalAction, default=False)
parser.add_argument("--manual", help="clear manually added packages queue",
action=argparse.BooleanOptionalAction, default=False)
parser.add_argument("--packages", help="clear directory with built packages",
action=argparse.BooleanOptionalAction, default=False)
parser.add_argument("--pacman", help="clear directory with pacman local database cache",
action=argparse.BooleanOptionalAction, default=False)
parser.set_defaults(lock=None, quiet=True, unsafe=True)
return parser
arguments = [_set_service_clean_parser]

View File

@ -0,0 +1,117 @@
#
# Copyright (c) 2021-2025 ahriman team.
#
# This file is part of ahriman
# (see https://github.com/arcan1s/ahriman).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import argparse
from ahriman.application.application import Application
from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration
from ahriman.models.build_status import BuildStatusEnum
from ahriman.models.package import Package
from ahriman.models.package_source import PackageSource
from ahriman.models.repository_id import RepositoryId
class Copy(Handler):
"""
copy packages handler
"""
ALLOW_MULTI_ARCHITECTURE_RUN = False # conflicting action
@classmethod
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
report: bool) -> None:
"""
callback for command line
Args:
args(argparse.Namespace): command line args
repository_id(RepositoryId): repository unique identifier
configuration(Configuration): configuration instance
report(bool): force enable or disable reporting
"""
application = Application(repository_id, configuration, report=report)
application.on_start()
configuration_path, _ = configuration.check_loaded()
source_repository_id = RepositoryId(repository_id.architecture, args.source)
source_configuration = Configuration.from_path(configuration_path, source_repository_id)
source_application = Application(source_repository_id, source_configuration, report=report)
packages = source_application.repository.packages(args.package)
Copy.check_status(args.exit_code, packages)
for package in packages:
Copy.copy_package(package, application, source_application)
# run update
application.update([])
if args.remove:
source_application.remove(args.package)
@staticmethod
def _set_package_copy_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for package copy subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("package-copy", aliases=["copy"], help="copy package from another repository",
description="copy package and its metadata from another repository")
parser.add_argument("source", help="source repository name")
parser.add_argument("package", help="package base", nargs="+")
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty",
action="store_true")
parser.add_argument("--remove", help="remove package from the source repository after", action="store_true")
return parser
@staticmethod
def copy_package(package: Package, application: Application, source_application: Application) -> None:
"""
copy package ``package`` from source repository to target repository
Args:
package(Package): package to copy
application(Application): application instance of the target repository
source_application(Application): application instance of the source repository
"""
# copy files
source_paths = [
str(source_application.repository.paths.repository / source.filename)
for source in package.packages.values()
if source.filename is not None
]
application.add(source_paths, PackageSource.Archive)
# copy metadata
application.reporter.package_changes_update(
package.base, source_application.reporter.package_changes_get(package.base)
)
application.reporter.package_dependencies_update(
package.base, source_application.reporter.package_dependencies_get(package.base)
)
application.reporter.package_update(package, BuildStatusEnum.Pending)
arguments = [_set_package_copy_parser]

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -19,11 +19,14 @@
# #
import argparse import argparse
from pathlib import Path
from ahriman.application.application import Application from ahriman.application.application import Application
from ahriman.application.application.updates_iterator import FixedUpdatesIterator, UpdatesIterator from ahriman.application.application.updates_iterator import FixedUpdatesIterator, UpdatesIterator
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.application.handlers.update import Update from ahriman.application.handlers.update import Update
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.utils import extract_user
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -56,3 +59,48 @@ class Daemon(Handler):
args.package = packages args.package = packages
Update.run(args, repository_id, configuration, report=report) Update.run(args, repository_id, configuration, report=report)
@staticmethod
def _set_repo_daemon_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for daemon subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("repo-daemon", aliases=["daemon"], help="run application as daemon",
description="start process which periodically will run update process")
parser.add_argument("-i", "--interval", help="interval between runs in seconds", type=int, default=60 * 60 * 12)
parser.add_argument("--aur", help="enable or disable checking for AUR updates",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--changes", help="calculate changes from the latest known commit if available. "
"Only applicable in dry run mode",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--check-files", help="enable or disable checking of broken dependencies "
"(e.g. dynamically linked libraries or modules directories)",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--dependencies", help="process missing package dependencies",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--dry-run", help="just perform check for updates, same as check command",
action="store_true")
parser.add_argument("--increment", help="increment package release (pkgrel) on duplicate",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--local", help="enable or disable checking of local packages for updates",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--manual", help="include or exclude manual updates",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--partitions", help="instead of updating whole repository, split updates into chunks",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("-u", "--username", help="build as user", default=extract_user())
parser.add_argument("--vcs", help="fetch actual version of VCS packages",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("-y", "--refresh", help="download fresh package databases from the mirror before actions, "
"-yy to force refresh even if up to date",
action="count", default=False)
parser.set_defaults(exit_code=False, lock=Path("ahriman-daemon.pid"), package=[])
return parser
arguments = [_set_repo_daemon_parser]

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -19,7 +19,7 @@
# #
import argparse import argparse
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.formatters import ConfigurationPathsPrinter, ConfigurationPrinter, StringPrinter from ahriman.core.formatters import ConfigurationPathsPrinter, ConfigurationPrinter, StringPrinter
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -59,3 +59,27 @@ class Dump(Handler):
case section, key: # key only case section, key: # key only
value = configuration.get(section, key, fallback="") value = configuration.get(section, key, fallback="")
StringPrinter(value)(verbose=False) StringPrinter(value)(verbose=False)
@staticmethod
def _set_service_config_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for config subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("service-config", aliases=["config", "repo-config"], help="dump configuration",
description="dump configuration for the specified architecture")
parser.add_argument("section", help="filter settings by section", nargs="?")
parser.add_argument("key", help="filter settings by key", nargs="?")
parser.add_argument("--info", help="show additional information, e.g. configuration files",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--secure", help="hide passwords and secrets from output",
action=argparse.BooleanOptionalAction, default=True)
parser.set_defaults(lock=None, quiet=True, report=False, unsafe=True)
return parser
arguments = [_set_service_config_parser]

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -22,6 +22,7 @@ import logging
from collections.abc import Callable, Iterable from collections.abc import Callable, Iterable
from multiprocessing import Pool from multiprocessing import Pool
from typing import ClassVar, TypeVar
from ahriman.application.lock import Lock from ahriman.application.lock import Lock
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
@ -32,23 +33,33 @@ from ahriman.models.repository_id import RepositoryId
from ahriman.models.repository_paths import RepositoryPaths from ahriman.models.repository_paths import RepositoryPaths
# this workaround is for several things
# firstly python devs don't think that is it error and asking you for workarounds https://bugs.python.org/issue41592
# secondly linters don't like when you are importing private members
# thirdly new mypy doesn't like _SubParsersAction and thinks it is a template
SubParserAction = TypeVar("SubParserAction", bound="argparse._SubParsersAction[argparse.ArgumentParser]")
class Handler: class Handler:
""" """
base handler class for command callbacks base handler class for command callbacks
Attributes: Attributes:
ALLOW_MULTI_ARCHITECTURE_RUN(bool): (class attribute) allow running with multiple architectures ALLOW_MULTI_ARCHITECTURE_RUN(bool): (class attribute) allow running with multiple architectures
arguments(list[Callable[[SubParserAction], argparse.ArgumentParser]]): (class attribute) argument parser
methods, which will be called to create command line parsers
Examples: Examples:
Wrapper for all command line actions, though each derived class implements :func:`run()` method, it usually Wrapper for all command line actions, though each derived class implements :func:`run()` method, it usually
must not be called directly. The recommended way is to call :func:`execute()` class method, e.g.:: must not be called directly. The recommended way is to call :func:`execute()` class method, e.g.::
>>> from ahriman.application.handlers import Add >>> from ahriman.application.handlers.add import Add
>>> >>>
>>> Add.execute(args) >>> Add.execute(args)
""" """
ALLOW_MULTI_ARCHITECTURE_RUN = True ALLOW_MULTI_ARCHITECTURE_RUN: ClassVar[bool] = True
arguments: ClassVar[list[Callable[[SubParserAction], argparse.ArgumentParser]]]
@classmethod @classmethod
def call(cls, args: argparse.Namespace, repository_id: RepositoryId) -> bool: def call(cls, args: argparse.Namespace, repository_id: RepositoryId) -> bool:

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -19,7 +19,7 @@
# #
import argparse import argparse
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -48,3 +48,22 @@ class Help(Handler):
parser.parse_args(["--help"]) parser.parse_args(["--help"])
else: else:
parser.parse_args([args.subcommand, "--help"]) parser.parse_args([args.subcommand, "--help"])
@staticmethod
def _set_help_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for listing help subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("help", help="show help message",
description="show help message for application or command and exit")
parser.add_argument("subcommand", help="show help message for specific command", nargs="?")
parser.set_defaults(architecture="", lock=None, quiet=True, report=False, repository="", unsafe=True)
return parser
arguments = [_set_help_parser]

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -20,7 +20,7 @@
import argparse import argparse
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, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -46,3 +46,27 @@ class KeyImport(Handler):
""" """
application = Application(repository_id, configuration, report=report) application = Application(repository_id, configuration, report=report)
application.repository.sign.key_import(args.key_server, args.key) application.repository.sign.key_import(args.key_server, args.key)
@staticmethod
def _set_service_key_import_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for key import subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("service-key-import", aliases=["key-import"], help="import PGP key",
description="import PGP key from public sources to the repository user",
epilog="By default ahriman runs build process with package sources validation "
"(in case if signature and keys are available in PKGBUILD). This process will "
"fail in case if key is not known for build user. This subcommand can be used "
"in order to import the PGP key to user keychain.")
parser.add_argument("--key-server", help="key server for key import", default="keyserver.ubuntu.com")
parser.add_argument("key", help="PGP key to import from public server")
parser.set_defaults(architecture="", lock=None, report=False, repository="")
return parser
arguments = [_set_service_key_import_parser]

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -23,7 +23,7 @@ import sys
from pathlib import Path from pathlib import Path
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, SubParserAction
from ahriman.core.build_tools.sources import Sources from ahriman.core.build_tools.sources import Sources
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.formatters import PatchPrinter from ahriman.core.formatters import PatchPrinter
@ -67,6 +67,100 @@ class Patch(Handler):
case Action.Remove: case Action.Remove:
Patch.patch_set_remove(application, args.package, args.variable) Patch.patch_set_remove(application, args.package, args.variable)
@staticmethod
def _set_patch_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for new single-function patch subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("patch-add", help="add patch for PKGBUILD function",
description="create or update patched PKGBUILD function or variable",
epilog="Unlike ``patch-set-add``, this function allows to patch only one PKGBUILD "
"function, e.g. typing ``ahriman patch-add ahriman pkgver`` it will change the "
"``pkgver`` inside PKGBUILD, typing ``ahriman patch-add ahriman build()`` "
"it will change ``build()`` function inside PKGBUILD.")
parser.add_argument("package", help="package base")
parser.add_argument("variable", help="PKGBUILD variable or function name. If variable is a function, "
"it must end with ()")
parser.add_argument("patch", help="path to file which contains function or variable value. If not set, "
"the value will be read from stdin", type=Path, nargs="?")
parser.set_defaults(action=Action.Update, architecture="", exit_code=False, lock=None, report=False,
repository="")
return parser
@staticmethod
def _set_patch_list_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for list patches subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("patch-list", help="list patch sets",
description="list available patches for the package")
parser.add_argument("package", help="package base")
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty",
action="store_true")
parser.add_argument("-v", "--variable", help="if set, show only patches for specified PKGBUILD variables",
action="append")
parser.set_defaults(action=Action.List, architecture="", lock=None, report=False, repository="", unsafe=True)
return parser
@staticmethod
def _set_patch_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for remove patches subcommand
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.add_argument("package", help="package base")
parser.add_argument("-v", "--variable",
help="should be used for single-function patches in case if you wold like "
"to remove only specified PKGBUILD variables. In case if not set, "
"it will remove all patches related to the package",
action="append")
parser.set_defaults(action=Action.Remove, architecture="", exit_code=False, lock=None, report=False,
repository="")
return parser
@staticmethod
def _set_patch_set_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for new full-diff patch subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("patch-set-add", help="add patch set", description="create or update source patches",
epilog="In order to add a patch set for the package you will need to:\n\n"
"1. Clone the AUR package manually.\n"
"2. Add required changes (e.g. external patches, edit PKGBUILD).\n"
"3. Run command, e.g. ``ahriman patch-set-add path/to/directory``.\n\n"
"By default it tracks ``*.patch`` and ``*.diff`` files, but this behavior "
"can be changed by using ``--track`` option.")
parser.add_argument("package", help="path to directory with changed files for patch addition/update", type=Path)
parser.add_argument("-t", "--track", help="files which has to be tracked", action="append",
default=["*.diff", "*.patch"])
parser.set_defaults(action=Action.Update, architecture="", exit_code=False, lock=None, report=False,
repository="", variable=None)
return parser
@staticmethod @staticmethod
def patch_create_from_diff(sources_dir: Path, architecture: str, track: list[str]) -> tuple[str, PkgbuildPatch]: def patch_create_from_diff(sources_dir: Path, architecture: str, track: list[str]) -> tuple[str, PkgbuildPatch]:
""" """
@ -104,8 +198,7 @@ class Patch(Handler):
else: else:
patch = patch_path.read_text(encoding="utf8") patch = patch_path.read_text(encoding="utf8")
# remove spaces around the patch and parse to correct type # remove spaces around the patch and parse to correct type
parsed = PkgbuildPatch.parse(patch.strip()) return PkgbuildPatch.parse(variable, patch.strip())
return PkgbuildPatch(variable, parsed)
@staticmethod @staticmethod
def patch_set_create(application: Application, package_base: str, patch: PkgbuildPatch) -> None: def patch_set_create(application: Application, package_base: str, patch: PkgbuildPatch) -> None:
@ -155,3 +248,10 @@ class Patch(Handler):
application.reporter.package_patches_remove(package_base, variable) application.reporter.package_patches_remove(package_base, variable)
else: else:
application.reporter.package_patches_remove(package_base, None) # just pass as is application.reporter.package_patches_remove(package_base, None) # just pass as is
arguments = [
_set_patch_add_parser,
_set_patch_list_parser,
_set_patch_remove_parser,
_set_patch_set_add_parser,
]

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -20,8 +20,9 @@
import argparse import argparse
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, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.utils import enum_values, extract_user
from ahriman.models.build_status import BuildStatusEnum from ahriman.models.build_status import BuildStatusEnum
from ahriman.models.package import Package from ahriman.models.package import Package
from ahriman.models.packagers import Packagers from ahriman.models.packagers import Packagers
@ -59,6 +60,38 @@ class Rebuild(Handler):
result = application.update(packages, Packagers(args.username), bump_pkgrel=args.increment) result = application.update(packages, Packagers(args.username), bump_pkgrel=args.increment)
Rebuild.check_status(args.exit_code, not result.is_empty) Rebuild.check_status(args.exit_code, not result.is_empty)
@staticmethod
def _set_repo_rebuild_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for repository rebuild subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("repo-rebuild", aliases=["rebuild"], help="rebuild repository",
description="force rebuild whole repository")
parser.add_argument("--depends-on", help="only rebuild packages that depend on specified packages",
action="append")
parser.add_argument("--dry-run", help="just perform check for packages without rebuild process itself",
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("--increment", help="increment package release (pkgrel) on duplicate",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty",
action="store_true")
parser.add_argument("-s", "--status", help="filter packages by status. Requires --from-database to be set",
type=BuildStatusEnum, choices=enum_values(BuildStatusEnum))
parser.add_argument("-u", "--username", help="build as user", default=extract_user())
return parser
@staticmethod @staticmethod
def extract_packages(application: Application, status: BuildStatusEnum | None, *, def extract_packages(application: Application, status: BuildStatusEnum | None, *,
from_database: bool) -> list[Package]: from_database: bool) -> list[Package]:
@ -81,3 +114,5 @@ class Rebuild(Handler):
] ]
return application.repository.packages() return application.repository.packages()
arguments = [_set_repo_rebuild_parser]

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -20,7 +20,7 @@
import argparse import argparse
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, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -45,3 +45,21 @@ class Remove(Handler):
application = Application(repository_id, configuration, report=report) application = Application(repository_id, configuration, report=report)
application.on_start() application.on_start()
application.remove(args.package) application.remove(args.package)
@staticmethod
def _set_package_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for package removal subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("package-remove", aliases=["remove"], help="remove package",
description="remove package from the repository")
parser.add_argument("package", help="package name or base", nargs="+")
return parser
arguments = [_set_package_remove_parser]

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -20,7 +20,7 @@
import argparse import argparse
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, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.formatters import StringPrinter from ahriman.core.formatters import StringPrinter
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -53,3 +53,21 @@ class RemoveUnknown(Handler):
return return
application.remove(unknown_packages) application.remove(unknown_packages)
@staticmethod
def _set_repo_remove_unknown_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for remove unknown packages subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("repo-remove-unknown", aliases=["remove-unknown"], help="remove unknown packages",
description="remove packages which are missing in AUR and do not have local PKGBUILDs")
parser.add_argument("--dry-run", help="just perform check for packages without removal", action="store_true")
return parser
arguments = [_set_repo_remove_unknown_parser]

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -19,7 +19,7 @@
# #
import argparse import argparse
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.formatters import RepositoryPrinter from ahriman.core.formatters import RepositoryPrinter
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -52,3 +52,23 @@ class Repositories(Handler):
) )
for repository in cls.repositories_extract(dummy_args): for repository in cls.repositories_extract(dummy_args):
RepositoryPrinter(repository)(verbose=not args.id_only) RepositoryPrinter(repository)(verbose=not args.id_only)
@staticmethod
def _set_service_repositories(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for repositories listing
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("service-repositories", help="show repositories",
description="list all available repositories")
parser.add_argument("--id-only", help="show machine readable identifier instead",
action=argparse.BooleanOptionalAction, default=False)
parser.set_defaults(architecture="", lock=None, report=False, repository="", unsafe=True)
return parser
arguments = [_set_service_repositories]

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -20,7 +20,9 @@
import argparse import argparse
import tarfile import tarfile
from ahriman.application.handlers.handler import Handler from pathlib import Path
from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -46,3 +48,23 @@ class Restore(Handler):
""" """
with tarfile.open(args.path) as archive: with tarfile.open(args.path) as archive:
archive.extractall(path=args.output) # nosec archive.extractall(path=args.output) # nosec
@staticmethod
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")
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(architecture="", lock=None, report=False, repository="", unsafe=True)
return parser
arguments = [_set_repo_restore_parser]

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -20,7 +20,7 @@
import argparse import argparse
import shlex import shlex
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -49,6 +49,25 @@ class Run(Handler):
status = Run.run_command(shlex.split(command), parser) status = Run.run_command(shlex.split(command), parser)
Run.check_status(True, status) Run.check_status(True, status)
@staticmethod
def _set_service_run(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for multicommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("service-run", aliases=["run"], help="run multiple commands",
description="run multiple commands on success run of the previous command",
epilog="Commands must be quoted by using usual bash rules. Processes will be spawned "
"under the same user as this command.")
parser.add_argument("command", help="command to be run (quoted) without ``ahriman``", nargs="+")
parser.set_defaults(architecture="", lock=None, report=False, repository="", unsafe=True)
return parser
@staticmethod @staticmethod
def run_command(command: list[str], parser: argparse.ArgumentParser) -> bool: def run_command(command: list[str], parser: argparse.ArgumentParser) -> bool:
""" """
@ -64,3 +83,5 @@ class Run(Handler):
args = parser.parse_args(command) args = parser.parse_args(command)
handler: Handler = args.handler handler: Handler = args.handler
return handler.execute(args) == 0 return handler.execute(args) == 0
arguments = [_set_service_run]

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -21,8 +21,9 @@ import argparse
from collections.abc import Callable, Iterable from collections.abc import Callable, Iterable
from dataclasses import fields from dataclasses import fields
from typing import ClassVar
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.alpm.remote import AUR, Official from ahriman.core.alpm.remote import AUR, Official
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.exceptions import OptionError from ahriman.core.exceptions import OptionError
@ -40,7 +41,7 @@ class Search(Handler):
""" """
ALLOW_MULTI_ARCHITECTURE_RUN = False # system-wide action ALLOW_MULTI_ARCHITECTURE_RUN = False # system-wide action
SORT_FIELDS = { SORT_FIELDS: ClassVar[set[str]] = {
field.name field.name
for field in fields(AURPackage) for field in fields(AURPackage)
if field.default_factory is not list if field.default_factory is not list
@ -68,6 +69,33 @@ class Search(Handler):
for package in Search.sort(packages_list, args.sort_by): for package in Search.sort(packages_list, args.sort_by):
AurPrinter(package)(verbose=args.info) AurPrinter(package)(verbose=args.info)
@staticmethod
def _set_aur_search_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for AUR search subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("aur-search", aliases=["search"], help="search for package",
description="search for package in AUR using API")
parser.add_argument("search",
help="search terms, can be specified multiple times, the result will match all terms",
nargs="+")
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty",
action="store_true")
parser.add_argument("--info", help="show additional package information",
action=argparse.BooleanOptionalAction, default=False)
parser.add_argument("--sort-by",
help="sort field by this field. In case if two packages have the same value of "
"the specified field, they will be always sorted by name",
default="name", choices=sorted(Search.SORT_FIELDS))
parser.set_defaults(architecture="", lock=None, quiet=True, report=False, repository="", unsafe=True)
return parser
@staticmethod @staticmethod
def sort(packages: Iterable[AURPackage], sort_by: str) -> list[AURPackage]: def sort(packages: Iterable[AURPackage], sort_by: str) -> list[AURPackage]:
""" """
@ -90,3 +118,5 @@ class Search(Handler):
comparator: Callable[[AURPackage], tuple[str, str]] =\ comparator: Callable[[AURPackage], tuple[str, str]] =\
lambda package: (getattr(package, sort_by), package.name) lambda package: (getattr(package, sort_by), package.name)
return sorted(packages, key=comparator) return sorted(packages, key=comparator)
arguments = [_set_aur_search_parser]

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -20,7 +20,7 @@
import argparse import argparse
from ahriman import __version__ from ahriman import __version__
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.formatters import UpdatePrinter from ahriman.core.formatters import UpdatePrinter
from ahriman.models.package import Package from ahriman.models.package import Package
@ -58,3 +58,23 @@ class ServiceUpdates(Handler):
UpdatePrinter(remote, local_version)(verbose=True, separator=" -> ") UpdatePrinter(remote, local_version)(verbose=True, separator=" -> ")
ServiceUpdates.check_status(args.exit_code, same_version) ServiceUpdates.check_status(args.exit_code, same_version)
@staticmethod
def _set_help_updates_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for service update check subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("help-updates", help="check for service updates",
description="request AUR for current version and compare with current service version")
parser.add_argument("-e", "--exit-code", help="return non-zero exit code if updates available",
action="store_true")
parser.set_defaults(architecture="", lock=None, quiet=True, report=False, repository="", unsafe=True)
return parser
arguments = [_set_help_updates_parser]

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -21,14 +21,17 @@ import argparse
from pathlib import Path from pathlib import Path
from pwd import getpwuid from pwd import getpwuid
from urllib.parse import quote_plus as urlencode from typing import ClassVar
from urllib.parse import quote_plus as url_encode
from ahriman.application.application import Application from ahriman.application.application import Application
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.exceptions import MissingArchitectureError from ahriman.core.exceptions import MissingArchitectureError
from ahriman.core.utils import enum_values
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
from ahriman.models.repository_paths import RepositoryPaths from ahriman.models.repository_paths import RepositoryPaths
from ahriman.models.sign_settings import SignSettings
from ahriman.models.user import User from ahriman.models.user import User
@ -44,9 +47,9 @@ class Setup(Handler):
ALLOW_MULTI_ARCHITECTURE_RUN = False # conflicting io ALLOW_MULTI_ARCHITECTURE_RUN = False # conflicting io
ARCHBUILD_COMMAND_PATH = Path("/") / "usr" / "bin" / "archbuild" ARCHBUILD_COMMAND_PATH: ClassVar[Path] = Path("/") / "usr" / "bin" / "archbuild"
MIRRORLIST_PATH = Path("/") / "etc" / "pacman.d" / "mirrorlist" MIRRORLIST_PATH: ClassVar[Path] = Path("/") / "etc" / "pacman.d" / "mirrorlist"
SUDOERS_DIR_PATH = Path("/") / "etc" / "sudoers.d" SUDOERS_DIR_PATH: ClassVar[Path] = Path("/") / "etc" / "sudoers.d"
@classmethod @classmethod
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *, def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
@ -80,6 +83,44 @@ class Setup(Handler):
# lazy database sync # lazy database sync
application.repository.pacman.handle # pylint: disable=pointless-statement application.repository.pacman.handle # pylint: disable=pointless-statement
@staticmethod
def _set_service_setup_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for setup subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("service-setup", aliases=["init", "repo-init", "repo-setup", "setup"],
help="initial service configuration",
description="create initial service configuration, requires root",
epilog="Create minimal configuration for the service according to provided options.")
parser.add_argument("--build-as-user", help="force makepkg user to the specific one")
parser.add_argument("--from-configuration", help="path to default devtools pacman configuration",
type=Path,
default=Path("/") / "usr" / "share" / "devtools" / "pacman.conf.d" / "extra.conf")
parser.add_argument("--generate-salt", help="generate salt for user passwords",
action=argparse.BooleanOptionalAction, default=False)
parser.add_argument("--makeflags-jobs",
help="append MAKEFLAGS variable with parallelism set to number of cores",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--mirror", help="use the specified explicitly mirror instead of including mirrorlist")
parser.add_argument("--multilib", help="add or do not multilib repository",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--packager", help="packager name and email", required=True)
parser.add_argument("--server", help="server to be used for devtools. If none set, local files will be used")
parser.add_argument("--sign-key", help="sign key id")
parser.add_argument("--sign-target", help="sign options", action="append",
type=SignSettings.from_option, choices=enum_values(SignSettings))
parser.add_argument("--web-port", help="port of the web service", type=int)
parser.add_argument("--web-unix-socket", help="path to unix socket used for interprocess communications",
type=Path)
parser.set_defaults(lock=None, quiet=True, report=False, unsafe=True)
return parser
@staticmethod @staticmethod
def build_command(root: Path, repository_id: RepositoryId) -> Path: def build_command(root: Path, repository_id: RepositoryId) -> Path:
""" """
@ -134,7 +175,7 @@ class Setup(Handler):
if args.web_unix_socket is not None: if args.web_unix_socket is not None:
unix_socket = str(args.web_unix_socket) unix_socket = str(args.web_unix_socket)
configuration.set_option("web", "unix_socket", unix_socket) configuration.set_option("web", "unix_socket", unix_socket)
configuration.set_option("status", "address", f"http+unix://{urlencode(unix_socket)}") configuration.set_option("status", "address", f"http+unix://{url_encode(unix_socket)}")
if args.generate_salt: if args.generate_salt:
configuration.set_option("auth", "salt", User.generate_password(20)) configuration.set_option("auth", "salt", User.generate_password(20))
@ -161,8 +202,8 @@ class Setup(Handler):
repository_server(str): url of the repository repository_server(str): url of the repository
""" """
# allow_no_value=True is required because pacman uses boolean configuration in which just keys present # allow_no_value=True is required because pacman uses boolean configuration in which just keys present
# (e.g. NoProgressBar) which will lead to exception # (e.g. NoProgressBar) which will lead to exception. allow_multi_key=False is set just for fun
configuration = Configuration(allow_no_value=True) configuration = Configuration(allow_no_value=True, allow_multi_key=False)
# preserve case # preserve case
# stupid mypy thinks that it is impossible # stupid mypy thinks that it is impossible
configuration.optionxform = lambda optionstr: optionstr # type: ignore[method-assign] configuration.optionxform = lambda optionstr: optionstr # type: ignore[method-assign]
@ -240,3 +281,5 @@ class Setup(Handler):
command.unlink(missing_ok=True) command.unlink(missing_ok=True)
command.symlink_to(Setup.ARCHBUILD_COMMAND_PATH) command.symlink_to(Setup.ARCHBUILD_COMMAND_PATH)
paths.chown(command) # we would like to keep owner inside ahriman's home paths.chown(command) # we would like to keep owner inside ahriman's home
arguments = [_set_service_setup_parser]

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -18,12 +18,12 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
import argparse import argparse
import code
import sys import sys
from pathlib import Path from pathlib import Path
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.application.interactive_shell import InteractiveShell
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.formatters import StringPrinter from ahriman.core.formatters import StringPrinter
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -58,8 +58,31 @@ class Shell(Handler):
"configuration": configuration, "configuration": configuration,
"repository_id": repository_id, "repository_id": repository_id,
} }
console = InteractiveShell(locals=local_variables)
if args.code is None: match args.code:
code.interact(local=local_variables) case None:
else: console.interact()
code.InteractiveConsole(locals=local_variables).runcode(args.code) case snippet:
console.runcode(snippet)
@staticmethod
def _set_service_shell_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for shell subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("service-shell", aliases=["shell"], help="invoke python shell",
description="drop into python shell")
parser.add_argument("code", help="instead of dropping into shell, just execute the specified code", nargs="?")
parser.add_argument("-v", "--verbose", help=argparse.SUPPRESS, action="store_true")
parser.add_argument("-o", "--output", help="output commands and result to the file", type=Path)
parser.set_defaults(lock=None, report=False)
return parser
arguments = [_set_service_shell_parser]

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -20,7 +20,7 @@
import argparse import argparse
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, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -43,3 +43,22 @@ class Sign(Handler):
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
""" """
Application(repository_id, configuration, report=report).sign(args.package) Application(repository_id, configuration, report=report).sign(args.package)
@staticmethod
def _set_repo_sign_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for sign subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("repo-sign", aliases=["sign"], help="sign packages",
description="(re-)sign packages and repository database according to current settings",
epilog="Sign repository and/or packages as configured.")
parser.add_argument("package", help="sign only specified packages", nargs="*")
return parser
arguments = [_set_repo_sign_parser]

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -25,11 +25,11 @@ from collections.abc import Callable
from pathlib import Path from pathlib import Path
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, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.formatters import EventStatsPrinter, PackageStatsPrinter from ahriman.core.formatters import EventStatsPrinter, PackageStatsPrinter, RepositoryStatsPrinter
from ahriman.core.utils import pretty_datetime from ahriman.core.utils import enum_values, pretty_datetime
from ahriman.models.event import Event from ahriman.models.event import Event, EventType
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -64,10 +64,35 @@ class Statistics(Handler):
match args.package: match args.package:
case None: case None:
RepositoryStatsPrinter(repository_id, application.reporter.statistics())(verbose=True)
Statistics.stats_per_package(args.event, events, args.chart) Statistics.stats_per_package(args.event, events, args.chart)
case _: case _:
Statistics.stats_for_package(args.event, events, args.chart) Statistics.stats_for_package(args.event, events, args.chart)
@staticmethod
def _set_repo_statistics_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for repository statistics subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("repo-statistics", help="repository statistics",
description="fetch repository statistics")
parser.add_argument("package", help="fetch only events for the specified package", nargs="?")
parser.add_argument("--chart", help="create updates chart and save it to the specified path", type=Path)
parser.add_argument("-e", "--event", help="event type filter",
type=EventType, choices=enum_values(EventType), default=EventType.PackageUpdated)
parser.add_argument("--from-date", help="only fetch events which are newer than the date")
parser.add_argument("--limit", help="limit response by specified amount of events", type=int, default=-1)
parser.add_argument("--offset", help="skip specified amount of events", type=int, default=0)
parser.add_argument("--to-date", help="only fetch events which are older than the date")
parser.set_defaults(lock=None, quiet=True, report=False, unsafe=True)
return parser
@staticmethod @staticmethod
def event_stats(event_type: str, events: list[Event]) -> None: def event_stats(event_type: str, events: list[Event]) -> None:
""" """
@ -168,3 +193,5 @@ class Statistics(Handler):
# chart if enabled # chart if enabled
if chart_path is not None: if chart_path is not None:
Statistics.plot_packages(event_type, by_object_id, chart_path) Statistics.plot_packages(event_type, by_object_id, chart_path)
arguments = [_set_repo_statistics_parser]

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -22,10 +22,11 @@ import argparse
from collections.abc import Callable from collections.abc import Callable
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, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.formatters import PackagePrinter, StatusPrinter from ahriman.core.formatters import PackagePrinter, StatusPrinter
from ahriman.models.build_status import BuildStatus from ahriman.core.utils import enum_values
from ahriman.models.build_status import BuildStatus, BuildStatusEnum
from ahriman.models.package import Package from ahriman.models.package import Package
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -68,3 +69,31 @@ class Status(Handler):
lambda item: args.status is None or item[1].status == args.status lambda item: args.status is None or item[1].status == args.status
for package, package_status in sorted(filter(filter_fn, packages), key=comparator): for package, package_status in sorted(filter(filter_fn, packages), key=comparator):
PackagePrinter(package, package_status)(verbose=args.info) PackagePrinter(package, package_status)(verbose=args.info)
@staticmethod
def _set_package_status_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for package status subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("package-status", aliases=["status"], help="get package status",
description="request status of the package",
epilog="This command requests package status from the web interface "
"if it is available.")
parser.add_argument("package", help="filter status by package base", nargs="*")
parser.add_argument("--ahriman", help="get service status itself", action="store_true")
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty",
action="store_true")
parser.add_argument("--info", help="show additional package information",
action=argparse.BooleanOptionalAction, default=False)
parser.add_argument("-s", "--status", help="filter packages by status",
type=BuildStatusEnum, choices=enum_values(BuildStatusEnum))
parser.set_defaults(lock=None, quiet=True, report=False, unsafe=True)
return parser
arguments = [_set_package_status_parser]

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -20,9 +20,11 @@
import argparse import argparse
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, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.utils import enum_values
from ahriman.models.action import Action from ahriman.models.action import Action
from ahriman.models.build_status import BuildStatusEnum
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -52,10 +54,74 @@ class StatusUpdate(Handler):
case Action.Update if args.package: case Action.Update if args.package:
# update packages statuses # update packages statuses
for package in args.package: for package in args.package:
client.package_update(package, args.status) client.package_status_update(package, args.status)
case Action.Update: case Action.Update:
# update service status # update service status
client.status_update(args.status) client.status_update(args.status)
case Action.Remove: case Action.Remove:
for package in args.package: for package in args.package:
client.package_remove(package) client.package_remove(package)
@staticmethod
def _set_package_status_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for package status remove subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("package-status-remove", help="remove package status",
description="remove the package from the status page",
epilog="Please note that this subcommand does not remove the package itself, it just "
"clears the status page.")
parser.add_argument("package", help="remove specified packages from status page", nargs="+")
parser.set_defaults(action=Action.Remove, lock=None, quiet=True, report=False, unsafe=True)
return parser
@staticmethod
def _set_package_status_update_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for package status update subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("package-status-update", aliases=["status-update"], help="update package status",
description="update package status on the status page")
parser.add_argument("package", help="set status for specified packages. "
"If no packages supplied, service status will be updated",
nargs="*")
parser.add_argument("-s", "--status", help="new package build status",
type=BuildStatusEnum, choices=enum_values(BuildStatusEnum), default=BuildStatusEnum.Success)
parser.set_defaults(action=Action.Update, lock=None, quiet=True, report=False, unsafe=True)
return parser
@staticmethod
def _set_repo_status_update_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for repository status update subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("repo-status-update", help="update repository status",
description="update repository status on the status page")
parser.add_argument("-s", "--status", help="new status",
type=BuildStatusEnum, choices=enum_values(BuildStatusEnum), default=BuildStatusEnum.Success)
parser.set_defaults(action=Action.Update, lock=None, package=[], quiet=True, report=False, unsafe=True)
return parser
arguments = [
_set_package_status_remove_parser,
_set_package_status_update_parser,
_set_repo_status_update_parser,
]

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -20,7 +20,7 @@
import argparse import argparse
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, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.formatters import StringPrinter, TreePrinter from ahriman.core.formatters import StringPrinter, TreePrinter
from ahriman.core.tree import Tree from ahriman.core.tree import Tree
@ -58,3 +58,23 @@ class Structure(Handler):
# empty line # empty line
StringPrinter("")(verbose=False) StringPrinter("")(verbose=False)
@staticmethod
def _set_repo_tree_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for repository tree subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("repo-tree", help="dump repository tree",
description="dump repository tree based on packages dependencies")
parser.add_argument("-p", "--partitions", help="also divide packages by independent partitions",
type=int, default=1)
parser.set_defaults(lock=None, quiet=True, report=False, unsafe=True)
return parser
arguments = [_set_repo_tree_parser]

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -19,7 +19,7 @@
# #
import argparse import argparse
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
from ahriman.models.repository_paths import RepositoryPaths from ahriman.models.repository_paths import RepositoryPaths
@ -50,6 +50,22 @@ class TreeMigrate(Handler):
# perform migration # perform migration
TreeMigrate.tree_move(current_tree, target_tree) TreeMigrate.tree_move(current_tree, target_tree)
@staticmethod
def _set_service_tree_migrate_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for tree migration subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("service-tree-migrate", help="migrate repository tree",
description="migrate repository tree between versions")
parser.set_defaults(lock=None, quiet=True, report=False)
return parser
@staticmethod @staticmethod
def tree_move(from_tree: RepositoryPaths, to_tree: RepositoryPaths) -> None: def tree_move(from_tree: RepositoryPaths, to_tree: RepositoryPaths) -> None:
""" """
@ -66,3 +82,5 @@ class TreeMigrate(Handler):
RepositoryPaths.repository, RepositoryPaths.repository,
): ):
attribute.fget(from_tree).rename(attribute.fget(to_tree)) # type: ignore[attr-defined] attribute.fget(from_tree).rename(attribute.fget(to_tree)) # type: ignore[attr-defined]
arguments = [_set_service_tree_migrate_parser]

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2021-2024 ahriman team. # Copyright (c) 2021-2025 ahriman team.
# #
# This file is part of ahriman # This file is part of ahriman
# (see https://github.com/arcan1s/ahriman). # (see https://github.com/arcan1s/ahriman).
@ -20,7 +20,7 @@
import argparse import argparse
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, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
from ahriman.models.result import Result from ahriman.models.result import Result
@ -49,3 +49,60 @@ class Triggers(Handler):
loader.triggers = [loader.load_trigger(trigger, repository_id, configuration) for trigger in args.trigger] loader.triggers = [loader.load_trigger(trigger, repository_id, configuration) for trigger in args.trigger]
application.on_start() application.on_start()
application.on_result(Result()) application.on_result(Result())
@staticmethod
def _set_repo_report_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for report subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("repo-report", aliases=["report"], help="generate report",
description="generate repository report according to current settings",
epilog="Create and/or update repository report as configured.")
parser.set_defaults(trigger=["ahriman.core.report.ReportTrigger"])
return parser
@staticmethod
def _set_repo_sync_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for repository sync subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("repo-sync", aliases=["sync"], help="sync repository",
description="sync repository files to remote server according to current settings",
epilog="Synchronize the repository to remote services as configured.")
parser.set_defaults(trigger=["ahriman.core.upload.UploadTrigger"])
return parser
@staticmethod
def _set_repo_triggers_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for repository triggers subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("repo-triggers", help="run triggers",
description="run triggers on empty build result as configured by settings")
parser.add_argument("trigger", help="instead of running all triggers as set by configuration, just process "
"specified ones in order of mention", nargs="*")
return parser
arguments = [
_set_repo_report_parser,
_set_repo_sync_parser,
_set_repo_triggers_parser,
]

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