mirror of
https://github.com/arcan1s/ahriman.git
synced 2026-07-13 14:21:08 +00:00
Compare commits
848 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e2e013a33b | |||
| da0853b6f1 | |||
| 7db38ff9e4 | |||
| 92ac036f78 | |||
| aef7fa5f93 | |||
| c412b08135 | |||
| a3b6372c11 | |||
| 78288befb8 | |||
| 49cd3d43c8 | |||
| d9b52806c0 | |||
| 774db2d780 | |||
| 68afda4c71 | |||
| fa9fa73078 | |||
| 3e1e24cb50 | |||
| 18fe38c30b | |||
| 6ee8b26bd5 | |||
| fce49f22c9 | |||
| af8e2c9e9b | |||
| 1c312bb528 | |||
| e39194e9f6 | |||
| 21cc029c18 | |||
| 40671b99d5 | |||
| 3ad2c494af | |||
| 34014d1cdd | |||
| 93ed2b864b | |||
| cca931ccd0 | |||
| 5e090cebdb | |||
| d7984c12f0 | |||
| 96684d7ddd | |||
| 2e9837b70d | |||
| ac4a8fb2cd | |||
| 1db8eb0ac4 | |||
| dc394f7df9 | |||
| 058f784b05 | |||
| f688768ca7 | |||
| a09ad7617d | |||
| 81aeb56ba3 | |||
| 2cd4ef5e86 | |||
| 998ed48dde | |||
| 021d88dc4c | |||
| 9012ee7144 | |||
| 945ddb2942 | |||
| 9cd0926588 | |||
| f5c12d03ec | |||
| 606ee2fb0e | |||
| 875e9cf58a | |||
| a809a4b67f | |||
| 437ae2c16c | |||
| 10661f3127 | |||
| 88ac3d82a0 | |||
| 386765ab4e | |||
| 78998182b8 | |||
| 2563391aaf | |||
| 90a78e99e7 | |||
| a05eab9042 | |||
| db46147f0d | |||
| 49ebbc34fa | |||
| e376f1307f | |||
| 415fcf58ce | |||
| 17a2d6362c | |||
| e6275de4ed | |||
| 4d009cba6d | |||
| f6defbf90d | |||
| c4fefa6071 | |||
| b0f1828ae7 | |||
| dec025b45a | |||
| 89008e5350 | |||
| 422196d413 | |||
| 6fe2eade26 | |||
| 5266f54257 | |||
| bbf9e38fda | |||
| ba80a91d95 | |||
| 536d040a6a | |||
| bed8752f3a | |||
| 4093ca8986 | |||
| f027155885 | |||
| 443d4ae667 | |||
| c8f7fa8c51 | |||
| 93c36fb429 | |||
| 2d6d42f969 | |||
| 6a2454548d | |||
| 389bad6725 | |||
| 5738b8b911 | |||
| 5ac2e3de19 | |||
| 799dc73d8a | |||
| 4e79cbf71a | |||
| 4fa5d55317 | |||
| a7fa3b90e4 | |||
| ce07cda8ab | |||
| 00c4f32294 | |||
| 49cf91ea52 | |||
| 4a8430dc67 | |||
| 46af782db2 | |||
| 6443e02352 | |||
| 999ad39d6f | |||
| dfab5f56b2 | |||
| 10798b9ba3 | |||
| 358e3dc4d2 | |||
| c13cd029bc | |||
| ae32cc8fbb | |||
| dff5b775a9 | |||
| db3f20546e | |||
| 53368468a4 | |||
| 228c2cce51 | |||
| f5aec4e5c1 | |||
| 9217c8c759 | |||
| 6392520e06 | |||
| c6306631e6 | |||
| 97b906c536 | |||
| 435375721d | |||
| 4c5caba6b7 | |||
| b83df9d2c5 | |||
| f2ea76aab9 | |||
| 471b1c1331 | |||
| bd770aac2f | |||
| 6abe35ef8c | |||
| fdc27a9ebf | |||
| b729096a25 | |||
| 390b9da29e | |||
| 256376df85 | |||
| 939a94d889 | |||
| 2b1b17a1a3 | |||
| 9e6705056a | |||
| b3a3a81f70 | |||
| 3e5dbbd6cd | |||
| f41e44895d | |||
| 765bbf486f | |||
| a3c54afb82 | |||
| 7f223ecc0a | |||
| 7769a4a6e0 | |||
| 066d1b1dde | |||
| 1f22a27360 | |||
| 75682bc7be | |||
| e5d824b03f | |||
| 8d0d597473 | |||
| 995b396360 | |||
| 7f813cf0c3 | |||
| d4eb55ef95 | |||
| 09350e88ab | |||
| 2feaa14f46 | |||
| 9653fc4f4a | |||
| bcd46c66e8 | |||
| 6ea56faede | |||
| 9e346530f2 | |||
| d283dccc1e | |||
| 8a4e900ab9 | |||
| fa6cf8ce36 | |||
| a706fbb751 | |||
| 9a23f5c79d | |||
| aaab9069bf | |||
| f00b575641 | |||
| 6f57ed550b | |||
| 08640d9108 | |||
| 65324633b4 | |||
| ed67898012 | |||
| a1a8dd68e8 | |||
| a9505386c2 | |||
| a07b20bf50 | |||
| ed70897c39 | |||
| 0423c3e67c | |||
| 571f62327f | |||
| 286ff4bcef | |||
| 0660c33de3 | |||
| c8421e97ee | |||
| bc2288afc1 | |||
| 503c8b0355 | |||
| 6738f9206d | |||
| f865e998b0 | |||
| 4880ca4fee | |||
| 56114ecc1e | |||
| 57ab3ffb8f | |||
| 8b08bfe3b4 | |||
| e34356989d | |||
| 7c7804a9f4 | |||
| c4a56f1454 | |||
| 1caed156ad | |||
| 45a620c40b | |||
| 3c1fdec0e9 | |||
| f5d7085325 | |||
| 0cc35e70e3 | |||
| f09082dff2 | |||
| 8d53a59a6a | |||
| 20e7ba3b1d | |||
| 4b5a645f8d | |||
| 6a3c16a646 | |||
| 93ce7f9a51 | |||
| 6fe77eb465 | |||
| 7c6c24a46d | |||
| f48993ccd5 | |||
| 22600a9eac | |||
| b167df904b | |||
| cd0ac7a7bd | |||
| 910d178c71 | |||
| 1e7d4daf18 | |||
| 7bc4810377 | |||
| aa66e76db7 | |||
| e0f9e38f44 | |||
| d6cdb5bea5 | |||
| 6d157ca809 | |||
| 5486ae4a19 | |||
| 8bdf420cdc | |||
| 2deca6d715 | |||
| 180adf3f33 | |||
| 634054926d | |||
| 53baaac61e | |||
| d2a93a94e3 | |||
| 7134aea125 | |||
| 740d537618 | |||
| 9f78e79f1f | |||
| 09456141f5 | |||
| 9e30e98e90 | |||
| df2e98a1d3 | |||
| 24993047c6 | |||
| b20e844cc9 | |||
| ce75ccb405 | |||
| 1acff852d0 | |||
| 62320e8ec6 | |||
| 1089bab526 | |||
| 0e0012a6e0 | |||
| fbbb80d091 | |||
| 5316427371 | |||
| 0fa748f302 | |||
| 7a3d32dcfa | |||
| a396126a79 | |||
| 9785835c0e | |||
| c4f4e37731 | |||
| f43ee2fd1d | |||
| f7a50e5294 | |||
| ddd3c3f06f | |||
| 242f3d4d34 | |||
| 303f9ff03c | |||
| 65fac09d8d | |||
| aaf7adbac1 | |||
| 9e011990ee | |||
| 529d4caa0e | |||
| d7c4fccf98 | |||
| 1e30838be4 | |||
| d57276f214 | |||
| 31e59df2c8 | |||
| 23cd843e44 | |||
| c08a292070 | |||
| 5163aa4dca | |||
| 69f0966ff1 | |||
| 16308dc3ae | |||
| 962599e937 | |||
| 758a81e3db | |||
| 84942e3c98 | |||
| 6f8b1509d7 | |||
| b4372ff583 | |||
| 41fc7bffbb | |||
| 300f5026c4 | |||
| 10aa91a033 | |||
| 4169851eaa | |||
| 4d9e06156d | |||
| af2269c64a | |||
| f44fa19c42 | |||
| fd3c6343f1 | |||
| 9edff2826f | |||
| b38ecfb35c | |||
| 3c7c748b4a | |||
| 434057ec49 | |||
| a01b090c2b | |||
| 8ffc1299f0 | |||
| 02b13de7f4 | |||
| 50a045434d | |||
| 7bbe3242d4 | |||
| a9cb357182 | |||
| feec9141b2 | |||
| 148ef09e70 | |||
| 5ff635db70 | |||
| 9df5820bce | |||
| b7d3493ae3 | |||
| f8b725d175 | |||
| 46b3c82aca | |||
| 0d34432c9a | |||
| 3cd9cff4ee | |||
| 9e02d7a38f | |||
| 9819ed761e | |||
| 99ca0cb2fd | |||
| ea3cb6e766 | |||
| 0ae4941321 | |||
| 855b55237b | |||
| 59d14665a5 | |||
| 414eb93b1e | |||
| 14721913a4 | |||
| f68e48fb47 | |||
| 77cceb4c10 | |||
| eca22fdaed | |||
| 719af3676e | |||
| 6c63ad6df5 | |||
| 497a115535 | |||
| 91598951c5 | |||
| f364e00bea | |||
| 87c87d6455 | |||
| 265de3dc72 | |||
| d06c02a1c7 | |||
| 29bb6284b0 | |||
| 70b7fcf47a | |||
| 706808fc97 | |||
| 7e5f21c26d | |||
| 9a7f55605a | |||
| 6085e88f5e | |||
| 56e97040d6 | |||
| 9510a14b90 | |||
| 6eeef39fe5 | |||
| 0e6434faad | |||
| 768132bb6c | |||
| f1095fe007 | |||
| 1af04448c9 | |||
| aad607eaef | |||
| 3347212bf2 | |||
| f3e9fbf9d0 | |||
| c3dacd6883 | |||
| 624b4619f1 | |||
| 215fe7a592 | |||
| dd8d5d130b | |||
| b4fa10781b | |||
| f6cdd806b2 | |||
| cf9a1e7bec | |||
| 1b93f4f5e0 | |||
| a872ecfc23 | |||
| c130f52163 | |||
| 5fb93bd331 | |||
| 58e702213d | |||
| e784032bc6 | |||
| c54b14b833 | |||
| e61b246216 | |||
| 2a9eab5f1a | |||
| acc204de6d | |||
| 0991dbb59c | |||
| 18d17d4d52 | |||
| de7184fc3a | |||
| 2d21c999d1 | |||
| ff78577d61 | |||
| eb6eda578c | |||
| e823fd3f27 | |||
| e4a857dad0 | |||
| fc8f6c2985 | |||
| bb6414f9d4 | |||
| 064ac6811c | |||
| 7d16142b3b | |||
| 69a79a2e64 | |||
| 5b4bff9c93 | |||
| 3f8b9eaed6 | |||
| deab8ddae6 | |||
| eacb6ec729 | |||
| dc2eebce39 | |||
| 6b755b4828 | |||
| a73341e885 | |||
| 969aa78c95 | |||
| df787657aa | |||
| eec94521a7 | |||
| b18000c777 | |||
| dbaff5f981 | |||
| ae84ca0c56 | |||
| 8f047f9a96 | |||
| 54bd016c17 | |||
| 42f77742f8 | |||
| 46bb9c95d0 | |||
| 5dd4763a80 | |||
| 45eba6a6e3 | |||
| 4c1d0abb85 | |||
| 1e00bf9398 | |||
| bf9a46936c | |||
| a0b17981e3 | |||
| c440f5bbd5 | |||
| 8ff567cac3 | |||
| 9fe760efdf | |||
| bc9682373d | |||
| aedcbf1985 | |||
| 26b991bf47 | |||
| 8bf422b02a | |||
| 0c920832c9 | |||
| bef8d33570 | |||
| b540ced77f | |||
| 723b6971dd | |||
| 59356e905a | |||
| 99eecdebf3 | |||
| 5e42dd4e70 | |||
| 4ec7e2d129 | |||
| 9a521af078 | |||
| d1132b49fc | |||
| 2c21ae26c3 | |||
| bba90b3eb8 | |||
| 3cac53ac11 | |||
| 9fa6722eaa | |||
| 1d4ed0e0c3 | |||
| 2cda4a2469 | |||
| 9406537a15 | |||
| 598af7d9db | |||
| 6530afbfc7 | |||
| ad1c0051c4 | |||
| 5b172ad20b | |||
| 42fccb76ef | |||
| c37f67c558 | |||
| 89d9b581bd | |||
| 116dc0b329 | |||
| e3ed36fafd | |||
| 573ade4ba5 | |||
| 9259d9c727 | |||
| c863ee063c | |||
| 480c3a54b8 | |||
| 3b3ef43863 | |||
| 368db86dde | |||
| adf6a0a952 | |||
| 575a618096 | |||
| 2c03354d4a | |||
| 4008aa2e0a | |||
| 9cb39f6767 | |||
| c7de182f3d | |||
| d21c3fdf9f | |||
| 9f2fe219c8 | |||
| ad570aae0f | |||
| 116b65d92a | |||
| 5e5171cf3e | |||
| af3360e84a | |||
| 95f52f7ebe | |||
| f5fe200247 | |||
| a1c12200b8 | |||
| 09839f755a | |||
| fcd4d60cad | |||
| 3681473942 | |||
| 4dd5a1e82e | |||
| cbd1d3d5b8 | |||
| e3347aec2d | |||
| 3ad6cd27c6 | |||
| 54a68279be | |||
| d99091a3b4 | |||
| be6cf5b8af | |||
| 91e548569d | |||
| 6c3b2ef266 | |||
| 785607c70b | |||
| d22a3152db | |||
| adb5b58a1d | |||
| 8b2601beaa | |||
| 9116a4370e | |||
| da93fdc77a | |||
| 8bbd643551 | |||
| 6834dd442c | |||
| d23e3cbbea | |||
| 6bc6bdaeae | |||
| 7458c73c7d | |||
| 2cecbb3d53 | |||
| c73a6c7bae | |||
| 0b70b5af45 | |||
| fde75a14c2 | |||
| 1e0d1a5a32 | |||
| 75919637e8 | |||
| 467d109cfc | |||
| a131c77699 | |||
| 10fbc31d2a | |||
| 7e0d12b8b1 | |||
| 7ab00ee579 | |||
| 2d62148ee6 | |||
| c1f2d5ff4a | |||
| 2888649ced | |||
| 63855f5964 | |||
| 8bf665d7d3 | |||
| a7ac77ce4d | |||
| fc01bf3d1c | |||
| d81e91e117 | |||
| 57f62ba163 | |||
| ded896ee1b | |||
| 1fdcea0524 | |||
| a93f43dcd0 | |||
| 20974dae6f | |||
| cbcfff27b8 | |||
| 96f394bab0 | |||
| aae3c82f3d | |||
| ab9e1fb1bd | |||
| 82322f7a6c | |||
| 125da217d3 | |||
| d113c65c81 | |||
| 050041b2de | |||
| e0ed636d7e | |||
| 61feb2ebc7 | |||
| da1c6b0101 | |||
| c1718b3862 | |||
| 34fe8128aa | |||
| a78c48ed4d | |||
| e368396653 | |||
| f4abd83568 | |||
| e6888ba788 | |||
| a78050c1bf | |||
| 93876307f8 | |||
| 4d482520cd | |||
| 461fbd40ce | |||
| 419da3db89 | |||
| 00ca06ffab | |||
| 5a05c8ce91 | |||
| b09aea13af | |||
| 04a52f759d | |||
| ef6cf0f00b | |||
| ab650b7417 | |||
| 7ca5b3a363 | |||
| 666fa98075 | |||
| 684ef33dbc | |||
| cf35addaa5 | |||
| 11732a8609 | |||
| 64cc8fd6b0 | |||
| 4202751e9c | |||
| 41515f6c95 | |||
| ac92b506e0 | |||
| 5bbd1ad9a9 | |||
| 541d8d9b39 | |||
| e41dd09a8a | |||
| 8e65263b90 | |||
| afc488255c | |||
| effc120a43 | |||
| 4b27e102ef | |||
| e0126bb811 | |||
| 8c04dc4c2a | |||
| 83e9d7c523 | |||
| 9be4a89c08 | |||
| 0f8596db1e | |||
| c403c45d72 | |||
| 00dbd90953 | |||
| 3e299d9685 | |||
| e20637f7ad | |||
| 5a09d46f9a | |||
| 90be3276dd | |||
| a4f646eb2a | |||
| ebd06cb443 | |||
| fe66c6c45c | |||
| bba58352e0 | |||
| 41cc58ed31 | |||
| 20e45845ba | |||
| 9fa1fa108f | |||
| 577bd9e5f8 | |||
| 20b9c1fa4a | |||
| a7c9183aa0 | |||
| 9e0dd3ae97 | |||
| f4e4e88e82 | |||
| 2684e4b3f4 | |||
| 45f5006db3 | |||
| b26aa2145f | |||
| 4462eba860 | |||
| f2c23bad17 | |||
| 1603086b96 | |||
| b6f6ee8c76 | |||
| b71d1f6e3d | |||
| 7883746e53 | |||
| ae9118654d | |||
| 81fa73f725 | |||
| 14cb548c3b | |||
| 2eb93a6090 | |||
| dd6ef38c99 | |||
| 415dc42313 | |||
| 3e1af17796 | |||
| 880cebe54f | |||
| cbcc796a3a | |||
| dc8a52f6c0 | |||
| 34c93e53cc | |||
| f7ec24523b | |||
| f817b32976 | |||
| 9fc2b681d4 | |||
| 59ff0589ab | |||
| 1b53de6f2b | |||
| 41080c5ff8 | |||
| 791ce4f242 | |||
| b75bd30658 | |||
| b3b3cad706 | |||
| 82b932371b | |||
| 45fb2f3c46 | |||
| 4a5b9d9fa1 | |||
| 2f8316ecb0 | |||
| 77ad35fce8 | |||
| 48da4646cf | |||
| 3d98dd267a | |||
| 09678a3ae1 | |||
| 8e2732f6fe | |||
| 73e311a41c | |||
| 1e8388af5d | |||
| c1d74726b7 | |||
| f2ddcc6d23 | |||
| a5ce6b78dd | |||
| 1a83dd6f5a | |||
| 16a33f7729 | |||
| fb21b1da53 | |||
| 8394004943 | |||
| 75c6bf6119 | |||
| 7e20ff5184 | |||
| 757614f5a0 | |||
| 43166e5f94 | |||
| 43696b9920 | |||
| 8befee58fe | |||
| 9d016f51b5 | |||
| c5fbccd519 | |||
| eae5748a30 | |||
| 695ef708b6 | |||
| 26408e82c0 | |||
| 7b647a9b5a | |||
| fac228d6c6 | |||
| eb5ac5a52b | |||
| 047925dcfe | |||
| b8d2775050 | |||
| bf959ceb5f | |||
| 945b6d0ac0 | |||
| 5df9f30e37 | |||
| 1ea3911531 | |||
| d7966e419d | |||
| 3a5268993e | |||
| ad84895e18 | |||
| b1dfafe275 | |||
| 375f9fcfb7 | |||
| 04dcaa93ab | |||
| f42c2c57fb | |||
| dc3562a4ec | |||
| dda94f8f9e | |||
| 709db6a5ed | |||
| 89a2d8e298 | |||
| b9cd98235e | |||
| 1905360f8f | |||
| a7018d9f7d | |||
| 73057bc08d | |||
| 7f87863734 | |||
| 2dac5a2520 | |||
| 720edc24ba | |||
| fe9711d24f | |||
| c73a2a4aa9 | |||
| 571f720ae2 | |||
| 5030395025 | |||
| 03633d47ea | |||
| 1a575d6db8 | |||
| cdc018ad07 | |||
| f806c8918e | |||
| 4daff81d5f | |||
| 06bd29b78d | |||
| c67ac3730c | |||
| c094d4ee79 | |||
| 3cb479ba4b | |||
| 307a7f4a71 | |||
| 25734876de | |||
| 53df735eb2 | |||
| fb7275f9dd | |||
| f01af5f54a | |||
| 1abe8d291f | |||
| 1a83e55d64 | |||
| b8e17c4879 | |||
| bee41dcc55 | |||
| 9f7995fb2f | |||
| 9ce1c36f35 | |||
| 4990ce4198 | |||
| 8f18ead4cc | |||
| 7ea50887a4 | |||
| 97ec5bfa41 | |||
| 5fcc15191a | |||
| c5f086a7c6 | |||
| 432ca0cc48 | |||
| 1a0322b32e | |||
| fc086c0d87 | |||
| d5503b22ba | |||
| a132b1544a | |||
| 63acae4b1c | |||
| 8e6473d2a0 | |||
| fdcbcc4541 | |||
| 83931f5cf4 | |||
| d4eadf0013 | |||
| 04174a3e6d | |||
| 041b3824c1 | |||
| a11cce43ff | |||
| 1388df9a7e | |||
| 6ee1c8ef5a | |||
| a7c6d95b34 | |||
| 060c7412b1 | |||
| 93406483fe | |||
| 046febc440 | |||
| 9964a96296 | |||
| 9529525cb5 | |||
| fa4c1c6205 | |||
| f9b1d89756 | |||
| 9197b416e6 | |||
| f54a2fe740 | |||
| d1f990eac8 | |||
| 1e85c1db70 | |||
| 32aaa4a1f8 | |||
| a9e20f0958 | |||
| 32b129a806 | |||
| 2752e68ade | |||
| 5b678149dc | |||
| 79e1cff421 | |||
| 2e07de4a12 | |||
| 7e3ef889e8 | |||
| 52b54a9d05 | |||
| c0f7f81050 | |||
| 38af344bde | |||
| 62496478ae | |||
| ce48169aad | |||
| 21845bc934 | |||
| 249003de0a | |||
| d8704e9c75 | |||
| 0a8b172e9c | |||
| 7d782f120d | |||
| 9057ecf67a | |||
| 35df354c14 | |||
| 4d4e5e9dde | |||
| ff24188ca1 | |||
| 9d4f85624d | |||
| 295f810222 | |||
| d8523bd83b | |||
| be017ed102 | |||
| c73f24f8c6 | |||
| 0d806e3471 | |||
| 20962f0385 | |||
| fd38dfd176 | |||
| 5f7f58041d | |||
| 233b1f7f39 | |||
| a83f1d5aa5 | |||
| be09c04e78 | |||
| bfbbb987ad | |||
| 04f365f1a6 | |||
| 86bd49ed1b | |||
| f6ad609616 | |||
| 2f5790f69f | |||
| faaf72a840 | |||
| ef44895b0d | |||
| 5cfffbcd46 | |||
| 3e0058620b | |||
| e897e2cde2 | |||
| edef4944f6 | |||
| a4eaf87116 | |||
| 1192f12f91 | |||
| 444da87fdc | |||
| 6be6614e6d | |||
| 8add507957 | |||
| af5363d158 | |||
| d60c553ea2 | |||
| 5a6d0e0000 | |||
| 427ba0f0ea | |||
| 266d2bd77d | |||
| f333e89bd1 | |||
| 659db071a1 | |||
| 56c642e2a9 | |||
| 845bc9b5e8 | |||
| 57f45fdc89 | |||
| ba483173af | |||
| 6d1f641e50 | |||
| 0cf7756ec4 | |||
| b561bcc25d | |||
| 25d76b0482 | |||
| d2fe4b044f | |||
| 22272167e6 | |||
| 38dce8c0fe | |||
| 68aa327670 | |||
| 04f6af58d9 | |||
| 41c8f4c35f | |||
| 168b2f6880 | |||
| 14e8eee986 | |||
| 88c8c929dc | |||
| 5bb244cbe8 | |||
| f3fd0780fb | |||
| 11c03a9041 | |||
| 214f319123 | |||
| cfbc9d3267 | |||
| 0f4c89145b | |||
| 49a05d0520 | |||
| 19d1e17727 | |||
| d7bf647493 | |||
| 19ba2ba8e5 | |||
| f49894107a | |||
| 233ba9c415 | |||
| b7cff0a19d | |||
| 60b94b9ac0 | |||
| 284f449225 | |||
| d18df0935e | |||
| c15cc4b853 | |||
| fc67778e89 | |||
| 39ac9d4e1f | |||
| bc923b0e8f | |||
| 2842e40bf7 | |||
| 343768e015 | |||
| 8f55cc600e | |||
| c757554148 | |||
| 899603e4b9 | |||
| f488105fd2 | |||
| 2e89b9483f | |||
| d3a00e1937 | |||
| d9b4015be5 | |||
| c6b550761b | |||
| 0129ec39ec | |||
| 62661c9fb1 | |||
| 78636c2035 | |||
| 47c4e5bb42 | |||
| d548fa02f0 | |||
| b5c6c286f7 | |||
| aad599be67 | |||
| f8ff2cbf5b | |||
| dad3f418ad | |||
| c455bd34ce | |||
| 69b319d39a | |||
| 33cfa8fef8 | |||
| 9d37e3ae23 | |||
| 2eb2d3a70a | |||
| 46389b87e7 | |||
| 856a94ff00 | |||
| a0e6009876 | |||
| f2b39fe439 | |||
| 213b2c65a0 | |||
| a416214e5f | |||
| e5966c497f | |||
| fbccb1394d | |||
| 01887ec44b | |||
| 4d4ddffa8f | |||
| 4729c0ea5f | |||
| 035a23a8de | |||
| 0d37ce5095 | |||
| 70465b5044 | |||
| 81afa23d98 | |||
| 1b979725a3 | |||
| c2c7ee6292 | |||
| a3fe361596 | |||
| 20d13f1c10 | |||
| 6c96c9e73a | |||
| 9b08b0694e | |||
| fcb892f39f | |||
| 1785b0470f | |||
| c04f940ad3 | |||
| 207da4caa7 | |||
| cad85b0f20 | |||
| 3e8e54857f | |||
| 6470b13511 | |||
| 4e08297311 | |||
| 32c3c52874 | |||
| e637a647c5 | |||
| e21b990777 | |||
| c0be7f7a17 | |||
| 612cb2fa22 | |||
| cf276f2398 | |||
| 4ca2348f0d | |||
| eb02e1e62b | |||
| 8d7d508bb2 | |||
| a875225b78 | |||
| 5449dec32a | |||
| eb7f3b2484 | |||
| e87402fdde | |||
| 3996055f56 | |||
| 74fc283078 | |||
| eb92f75384 | |||
| 63529633ec | |||
| 930b47c704 | |||
| a89888769f | |||
| b6bc1b77dc | |||
| 4a462502e7 | |||
| f383b04754 | |||
| d744fe1647 | |||
| 6f1b37c4cb | |||
| 5cb3fd5853 | |||
| 60b8477cde |
@@ -1,6 +0,0 @@
|
|||||||
skips:
|
|
||||||
- B101
|
|
||||||
- B104
|
|
||||||
- B105
|
|
||||||
- B106
|
|
||||||
- B404
|
|
||||||
@@ -12,3 +12,6 @@ __pycache__/
|
|||||||
*.pyc
|
*.pyc
|
||||||
*.pyd
|
*.pyd
|
||||||
*.pyo
|
*.pyo
|
||||||
|
|
||||||
|
node_modules/
|
||||||
|
package-lock.json
|
||||||
|
|||||||
@@ -7,6 +7,11 @@ on:
|
|||||||
tags:
|
tags:
|
||||||
- '*'
|
- '*'
|
||||||
- '!*rc*'
|
- '!*rc*'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
docker-image:
|
docker-image:
|
||||||
@@ -17,18 +22,22 @@ jobs:
|
|||||||
packages: write
|
packages: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: docker/setup-qemu-action@v2
|
- uses: docker/setup-qemu-action@v3
|
||||||
|
|
||||||
- uses: docker/setup-buildx-action@v2
|
- uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Set image date
|
||||||
|
id: args
|
||||||
|
run: echo "::set-output name=date::$(date -d yesterday +'%Y-%m-%d')"
|
||||||
|
|
||||||
- name: Login to docker hub
|
- name: Login to docker hub
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Login to github container registry
|
- name: Login to github container registry
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
@@ -36,7 +45,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Extract docker metadata
|
- name: Extract docker metadata
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v3
|
uses: docker/metadata-action@v5
|
||||||
with:
|
with:
|
||||||
images: |
|
images: |
|
||||||
arcan1s/ahriman
|
arcan1s/ahriman
|
||||||
@@ -46,7 +55,10 @@ jobs:
|
|||||||
type=edge
|
type=edge
|
||||||
|
|
||||||
- name: Build an image and push
|
- name: Build an image and push
|
||||||
uses: docker/build-push-action@v4
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
|
build-args: |
|
||||||
|
BUILD_DATE=${{ steps.args.outputs.date }}
|
||||||
|
file: docker/Dockerfile
|
||||||
push: true
|
push: true
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
|||||||
@@ -0,0 +1,140 @@
|
|||||||
|
name: Regress
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: 1 0 * * 0
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
run-regress-tests:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
services:
|
||||||
|
ahriman:
|
||||||
|
image: arcan1s/ahriman:edge
|
||||||
|
env:
|
||||||
|
AHRIMAN_PORT: 8080
|
||||||
|
AHRIMAN_UNIX_SOCKET: /var/lib/ahriman/ahriman/ahriman-web.sock
|
||||||
|
options: --privileged --entrypoint entrypoint-web
|
||||||
|
ports:
|
||||||
|
- 8080
|
||||||
|
volumes:
|
||||||
|
- repo:/var/lib/ahriman
|
||||||
|
|
||||||
|
container:
|
||||||
|
image: arcan1s/ahriman:edge
|
||||||
|
env:
|
||||||
|
AHRIMAN_DEBUG: y
|
||||||
|
AHRIMAN_OUTPUT: console
|
||||||
|
AHRIMAN_PORT: 8080
|
||||||
|
AHRIMAN_UNIX_SOCKET: /var/lib/ahriman/ahriman/ahriman-web.sock
|
||||||
|
options: --privileged
|
||||||
|
volumes:
|
||||||
|
- repo:/var/lib/ahriman
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- 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
|
||||||
@@ -5,13 +5,24 @@ on:
|
|||||||
tags:
|
tags:
|
||||||
- '*'
|
- '*'
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
make-release:
|
make-release:
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
container:
|
||||||
|
image: archlinux:base
|
||||||
|
options: -w /build
|
||||||
|
volumes:
|
||||||
|
- ${{ github.workspace }}:/build
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- run: pacman --noconfirm -Syu base-devel git python-tox
|
||||||
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Extract version
|
- name: Extract version
|
||||||
id: version
|
id: version
|
||||||
@@ -24,18 +35,13 @@ jobs:
|
|||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
filter: 'Release \d+\.\d+\.\d+'
|
filter: 'Release \d+\.\d+\.\d+'
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
uses: ConorMacBride/install-package@v1.1.0
|
|
||||||
with:
|
|
||||||
apt: tox
|
|
||||||
|
|
||||||
- name: Create archive
|
- name: Create archive
|
||||||
run: tox -e archive
|
run: tox -e archive
|
||||||
env:
|
env:
|
||||||
VERSION: ${{ steps.version.outputs.VERSION }}
|
VERSION: ${{ steps.version.outputs.VERSION }}
|
||||||
|
|
||||||
- name: Publish release
|
- name: Publish release
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
body: |
|
body: |
|
||||||
${{ steps.changelog.outputs.compareurl }}
|
${{ steps.changelog.outputs.compareurl }}
|
||||||
|
|||||||
+19
-13
@@ -8,19 +8,17 @@ set -ex
|
|||||||
# install dependencies
|
# install dependencies
|
||||||
echo -e '[arcanisrepo]\nServer = https://repo.arcanis.me/$arch\nSigLevel = Never' | tee -a /etc/pacman.conf
|
echo -e '[arcanisrepo]\nServer = https://repo.arcanis.me/$arch\nSigLevel = Never' | tee -a /etc/pacman.conf
|
||||||
# refresh the image
|
# refresh the image
|
||||||
pacman -Syu --noconfirm
|
pacman -Syyu --noconfirm
|
||||||
# main dependencies
|
# main dependencies
|
||||||
pacman -Sy --noconfirm devtools git pyalpm python-cerberus python-inflection python-passlib python-requests python-srcinfo python-systemd sudo
|
pacman -S --noconfirm devtools git npm pyalpm python-bcrypt python-filelock python-inflection python-pyelftools python-requests python-systemd sudo
|
||||||
# make dependencies
|
# make dependencies
|
||||||
pacman -Sy --noconfirm python-build python-flit python-installer python-tox python-wheel
|
pacman -S --noconfirm --asdeps base-devel python-build python-hatchling python-installer python-tox python-wheel
|
||||||
# optional dependencies
|
# optional dependencies
|
||||||
if [[ -z $MINIMAL_INSTALL ]]; then
|
if [[ -z $MINIMAL_INSTALL ]]; then
|
||||||
# VCS support
|
|
||||||
pacman -Sy --noconfirm breezy darcs mercurial subversion
|
|
||||||
# web server
|
# web server
|
||||||
pacman -Sy --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-aiohttp-sse-git python-cryptography python-jinja
|
||||||
# additional features
|
# additional features
|
||||||
pacman -Sy --noconfirm gnupg python-boto3 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"
|
||||||
@@ -28,29 +26,37 @@ 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
|
||||||
|
|
||||||
|
# remove unused dependencies
|
||||||
|
pacman -Qdtq | pacman -Rscn --noconfirm -
|
||||||
|
|
||||||
# initial setup command as root
|
# initial setup command as root
|
||||||
[[ -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[@]}"
|
||||||
# validate configuration
|
|
||||||
ahriman service-config-validate --exit-code
|
|
||||||
# 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
|
||||||
|
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
|
||||||
# add the first package
|
# add the first package
|
||||||
sudo -u ahriman -- ahriman package-add --now ahriman
|
sudo -u ahriman -- ahriman --log-handler console package-add --now ahriman
|
||||||
# check if package was actually installed
|
# check if package was actually installed
|
||||||
test -n "$(find "/var/lib/ahriman/repository/github/x86_64" -name "ahriman*pkg*")"
|
test -n "$(find "/var/lib/ahriman/repository/github/x86_64" -name "ahriman*pkg*")"
|
||||||
# run package check
|
# run package check
|
||||||
|
|||||||
@@ -7,6 +7,10 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
run-setup-minimal:
|
run-setup-minimal:
|
||||||
@@ -15,12 +19,12 @@ 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@v4
|
||||||
|
|
||||||
- name: Setup the minimal service in arch linux container
|
- name: Setup the minimal service in arch linux container
|
||||||
run: .github/workflows/setup.sh minimal
|
run: .github/workflows/setup.sh minimal
|
||||||
@@ -36,7 +40,7 @@ jobs:
|
|||||||
options: --privileged -w /build
|
options: --privileged -w /build
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup the service in arch linux container
|
- name: Setup the service in arch linux container
|
||||||
run: .github/workflows/setup.sh
|
run: .github/workflows/setup.sh
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Install dependencies and run test in container
|
|
||||||
|
|
||||||
set -ex
|
|
||||||
|
|
||||||
# install dependencies
|
|
||||||
pacman --noconfirm -Syu base-devel python-tox
|
|
||||||
|
|
||||||
# run test and check targets
|
|
||||||
tox
|
|
||||||
@@ -7,6 +7,12 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
|
schedule:
|
||||||
|
- cron: 1 0 * * *
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
run-tests:
|
run-tests:
|
||||||
@@ -15,12 +21,21 @@ 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
|
- run: pacman --noconfirm -Syu base-devel git npm python-tox
|
||||||
|
|
||||||
- name: Run check and tests in arch linux container
|
- run: git config --global --add safe.directory *
|
||||||
run: .github/workflows/tests.sh
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Run check and tests
|
||||||
|
run: tox
|
||||||
|
|
||||||
|
- name: Generate documentation and check if there are untracked changes
|
||||||
|
run: |
|
||||||
|
tox -e docs
|
||||||
|
[ -z "$(git status --porcelain docs/*.rst)" ]
|
||||||
|
|||||||
@@ -99,3 +99,12 @@ status_cache.json
|
|||||||
*.db
|
*.db
|
||||||
|
|
||||||
docs/html/
|
docs/html/
|
||||||
|
|
||||||
|
# Frontend
|
||||||
|
node_modules/
|
||||||
|
package-lock.json
|
||||||
|
ahriman-web/package/share/ahriman/templates/static/index.js
|
||||||
|
ahriman-web/package/share/ahriman/templates/static/index.css
|
||||||
|
|
||||||
|
# local configs
|
||||||
|
/*.ini
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
[tool.pylint.main]
|
||||||
|
init-hook = "sys.path.append('tools')"
|
||||||
|
load-plugins = [
|
||||||
|
"pylint.extensions.docparams",
|
||||||
|
"pylint.extensions.bad_builtin",
|
||||||
|
"pylint_plugins.definition_order",
|
||||||
|
"pylint_plugins.import_order",
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.pylint.classes]
|
||||||
|
bad-functions = [
|
||||||
|
"print",
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.pylint.design]
|
||||||
|
max-parents = 15
|
||||||
|
|
||||||
|
[tool.pylint."messages control"]
|
||||||
|
disable = [
|
||||||
|
"raw-checker-failed",
|
||||||
|
"bad-inline-option",
|
||||||
|
"locally-disabled",
|
||||||
|
"file-ignored",
|
||||||
|
"suppressed-message",
|
||||||
|
"useless-suppression",
|
||||||
|
"deprecated-pragma",
|
||||||
|
"use-symbolic-message-instead",
|
||||||
|
"use-implicit-booleaness-not-comparison-to-string",
|
||||||
|
"use-implicit-booleaness-not-comparison-to-zero",
|
||||||
|
"missing-module-docstring",
|
||||||
|
"line-too-long",
|
||||||
|
"no-name-in-module",
|
||||||
|
"import-outside-toplevel",
|
||||||
|
"invalid-name",
|
||||||
|
"raise-missing-from",
|
||||||
|
"wrong-import-order",
|
||||||
|
"too-few-public-methods",
|
||||||
|
"too-many-instance-attributes",
|
||||||
|
"broad-exception-caught",
|
||||||
|
"fixme",
|
||||||
|
"too-many-arguments",
|
||||||
|
"duplicate-code",
|
||||||
|
"cyclic-import",
|
||||||
|
"too-many-positional-arguments",
|
||||||
|
]
|
||||||
@@ -1,647 +0,0 @@
|
|||||||
[MAIN]
|
|
||||||
|
|
||||||
# Analyse import fallback blocks. This can be used to support both Python 2 and
|
|
||||||
# 3 compatible code, which means that the block might have code that exists
|
|
||||||
# only in one or another interpreter, leading to false positives when analysed.
|
|
||||||
analyse-fallback-blocks=no
|
|
||||||
|
|
||||||
# Clear in-memory caches upon conclusion of linting. Useful if running pylint
|
|
||||||
# in a server-like mode.
|
|
||||||
clear-cache-post-run=no
|
|
||||||
|
|
||||||
# Load and enable all available extensions. Use --list-extensions to see a list
|
|
||||||
# all available extensions.
|
|
||||||
#enable-all-extensions=
|
|
||||||
|
|
||||||
# In error mode, messages with a category besides ERROR or FATAL are
|
|
||||||
# suppressed, and no reports are done by default. Error mode is compatible with
|
|
||||||
# disabling specific errors.
|
|
||||||
#errors-only=
|
|
||||||
|
|
||||||
# Always return a 0 (non-error) status code, even if lint errors are found.
|
|
||||||
# This is primarily useful in continuous integration scripts.
|
|
||||||
#exit-zero=
|
|
||||||
|
|
||||||
# A comma-separated list of package or module names from where C extensions may
|
|
||||||
# be loaded. Extensions are loading into the active Python interpreter and may
|
|
||||||
# run arbitrary code.
|
|
||||||
extension-pkg-allow-list=
|
|
||||||
|
|
||||||
# A comma-separated list of package or module names from where C extensions may
|
|
||||||
# be loaded. Extensions are loading into the active Python interpreter and may
|
|
||||||
# run arbitrary code. (This is an alternative name to extension-pkg-allow-list
|
|
||||||
# for backward compatibility.)
|
|
||||||
extension-pkg-whitelist=
|
|
||||||
|
|
||||||
# Return non-zero exit code if any of these messages/categories are detected,
|
|
||||||
# even if score is above --fail-under value. Syntax same as enable. Messages
|
|
||||||
# specified are enabled, while categories only check already-enabled messages.
|
|
||||||
fail-on=
|
|
||||||
|
|
||||||
# Specify a score threshold under which the program will exit with error.
|
|
||||||
fail-under=10
|
|
||||||
|
|
||||||
# Interpret the stdin as a python script, whose filename needs to be passed as
|
|
||||||
# the module_or_package argument.
|
|
||||||
#from-stdin=
|
|
||||||
|
|
||||||
# Files or directories to be skipped. They should be base names, not paths.
|
|
||||||
ignore=CVS
|
|
||||||
|
|
||||||
# Add files or directories matching the regular expressions patterns to the
|
|
||||||
# ignore-list. The regex matches against paths and can be in Posix or Windows
|
|
||||||
# format. Because '\\' represents the directory delimiter on Windows systems,
|
|
||||||
# it can't be used as an escape character.
|
|
||||||
ignore-paths=
|
|
||||||
|
|
||||||
# Files or directories matching the regular expression patterns are skipped.
|
|
||||||
# The regex matches against base names, not paths. The default value ignores
|
|
||||||
# Emacs file locks
|
|
||||||
ignore-patterns=^\.#
|
|
||||||
|
|
||||||
# List of module names for which member attributes should not be checked
|
|
||||||
# (useful for modules/projects where namespaces are manipulated during runtime
|
|
||||||
# and thus existing member attributes cannot be deduced by static analysis). It
|
|
||||||
# supports qualified module names, as well as Unix pattern matching.
|
|
||||||
ignored-modules=
|
|
||||||
|
|
||||||
# Python code to execute, usually for sys.path manipulation such as
|
|
||||||
# pygtk.require().
|
|
||||||
init-hook='import sys; sys.path.append("pylint_plugins")'
|
|
||||||
|
|
||||||
# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
|
|
||||||
# number of processors available to use, and will cap the count on Windows to
|
|
||||||
# avoid hangs.
|
|
||||||
jobs=1
|
|
||||||
|
|
||||||
# Control the amount of potential inferred values when inferring a single
|
|
||||||
# object. This can help the performance when dealing with large functions or
|
|
||||||
# complex, nested conditions.
|
|
||||||
limit-inference-results=100
|
|
||||||
|
|
||||||
# List of plugins (as comma separated values of python module names) to load,
|
|
||||||
# usually to register additional checkers.
|
|
||||||
load-plugins=pylint.extensions.docparams,
|
|
||||||
definition_order,
|
|
||||||
import_order,
|
|
||||||
|
|
||||||
# Pickle collected data for later comparisons.
|
|
||||||
persistent=yes
|
|
||||||
|
|
||||||
# Minimum Python version to use for version dependent checks. Will default to
|
|
||||||
# the version used to run pylint.
|
|
||||||
py-version=3.11
|
|
||||||
|
|
||||||
# Discover python modules and packages in the file system subtree.
|
|
||||||
recursive=no
|
|
||||||
|
|
||||||
# Add paths to the list of the source roots. Supports globbing patterns. The
|
|
||||||
# source root is an absolute path or a path relative to the current working
|
|
||||||
# directory used to determine a package namespace for modules located under the
|
|
||||||
# source root.
|
|
||||||
source-roots=
|
|
||||||
|
|
||||||
# When enabled, pylint would attempt to guess common misconfiguration and emit
|
|
||||||
# user-friendly hints instead of false-positive error messages.
|
|
||||||
suggestion-mode=yes
|
|
||||||
|
|
||||||
# Allow loading of arbitrary C extensions. Extensions are imported into the
|
|
||||||
# active Python interpreter and may run arbitrary code.
|
|
||||||
unsafe-load-any-extension=no
|
|
||||||
|
|
||||||
# In verbose mode, extra non-checker-related info will be displayed.
|
|
||||||
#verbose=
|
|
||||||
|
|
||||||
|
|
||||||
[BASIC]
|
|
||||||
|
|
||||||
# Naming style matching correct argument names.
|
|
||||||
argument-naming-style=snake_case
|
|
||||||
|
|
||||||
# Regular expression matching correct argument names. Overrides argument-
|
|
||||||
# naming-style. If left empty, argument names will be checked with the set
|
|
||||||
# naming style.
|
|
||||||
#argument-rgx=
|
|
||||||
|
|
||||||
# Naming style matching correct attribute names.
|
|
||||||
attr-naming-style=snake_case
|
|
||||||
|
|
||||||
# Regular expression matching correct attribute names. Overrides attr-naming-
|
|
||||||
# style. If left empty, attribute names will be checked with the set naming
|
|
||||||
# style.
|
|
||||||
#attr-rgx=
|
|
||||||
|
|
||||||
# Bad variable names which should always be refused, separated by a comma.
|
|
||||||
bad-names=foo,
|
|
||||||
bar,
|
|
||||||
baz,
|
|
||||||
toto,
|
|
||||||
tutu,
|
|
||||||
tata
|
|
||||||
|
|
||||||
# Bad variable names regexes, separated by a comma. If names match any regex,
|
|
||||||
# they will always be refused
|
|
||||||
bad-names-rgxs=
|
|
||||||
|
|
||||||
# Naming style matching correct class attribute names.
|
|
||||||
class-attribute-naming-style=any
|
|
||||||
|
|
||||||
# Regular expression matching correct class attribute names. Overrides class-
|
|
||||||
# attribute-naming-style. If left empty, class attribute names will be checked
|
|
||||||
# with the set naming style.
|
|
||||||
#class-attribute-rgx=
|
|
||||||
|
|
||||||
# Naming style matching correct class constant names.
|
|
||||||
class-const-naming-style=UPPER_CASE
|
|
||||||
|
|
||||||
# Regular expression matching correct class constant names. Overrides class-
|
|
||||||
# const-naming-style. If left empty, class constant names will be checked with
|
|
||||||
# the set naming style.
|
|
||||||
#class-const-rgx=
|
|
||||||
|
|
||||||
# Naming style matching correct class names.
|
|
||||||
class-naming-style=PascalCase
|
|
||||||
|
|
||||||
# Regular expression matching correct class names. Overrides class-naming-
|
|
||||||
# style. If left empty, class names will be checked with the set naming style.
|
|
||||||
#class-rgx=
|
|
||||||
|
|
||||||
# Naming style matching correct constant names.
|
|
||||||
const-naming-style=UPPER_CASE
|
|
||||||
|
|
||||||
# Regular expression matching correct constant names. Overrides const-naming-
|
|
||||||
# style. If left empty, constant names will be checked with the set naming
|
|
||||||
# style.
|
|
||||||
#const-rgx=
|
|
||||||
|
|
||||||
# Minimum line length for functions/classes that require docstrings, shorter
|
|
||||||
# ones are exempt.
|
|
||||||
docstring-min-length=-1
|
|
||||||
|
|
||||||
# Naming style matching correct function names.
|
|
||||||
function-naming-style=snake_case
|
|
||||||
|
|
||||||
# Regular expression matching correct function names. Overrides function-
|
|
||||||
# naming-style. If left empty, function names will be checked with the set
|
|
||||||
# naming style.
|
|
||||||
#function-rgx=
|
|
||||||
|
|
||||||
# Good variable names which should always be accepted, separated by a comma.
|
|
||||||
good-names=i,
|
|
||||||
j,
|
|
||||||
k,
|
|
||||||
ex,
|
|
||||||
Run,
|
|
||||||
_
|
|
||||||
|
|
||||||
# Good variable names regexes, separated by a comma. If names match any regex,
|
|
||||||
# they will always be accepted
|
|
||||||
good-names-rgxs=
|
|
||||||
|
|
||||||
# Include a hint for the correct naming format with invalid-name.
|
|
||||||
include-naming-hint=no
|
|
||||||
|
|
||||||
# Naming style matching correct inline iteration names.
|
|
||||||
inlinevar-naming-style=any
|
|
||||||
|
|
||||||
# Regular expression matching correct inline iteration names. Overrides
|
|
||||||
# inlinevar-naming-style. If left empty, inline iteration names will be checked
|
|
||||||
# with the set naming style.
|
|
||||||
#inlinevar-rgx=
|
|
||||||
|
|
||||||
# Naming style matching correct method names.
|
|
||||||
method-naming-style=snake_case
|
|
||||||
|
|
||||||
# Regular expression matching correct method names. Overrides method-naming-
|
|
||||||
# style. If left empty, method names will be checked with the set naming style.
|
|
||||||
#method-rgx=
|
|
||||||
|
|
||||||
# Naming style matching correct module names.
|
|
||||||
module-naming-style=snake_case
|
|
||||||
|
|
||||||
# Regular expression matching correct module names. Overrides module-naming-
|
|
||||||
# style. If left empty, module names will be checked with the set naming style.
|
|
||||||
#module-rgx=
|
|
||||||
|
|
||||||
# Colon-delimited sets of names that determine each other's naming style when
|
|
||||||
# the name regexes allow several styles.
|
|
||||||
name-group=
|
|
||||||
|
|
||||||
# Regular expression which should only match function or class names that do
|
|
||||||
# not require a docstring.
|
|
||||||
no-docstring-rgx=
|
|
||||||
|
|
||||||
# List of decorators that produce properties, such as abc.abstractproperty. Add
|
|
||||||
# to this list to register other decorators that produce valid properties.
|
|
||||||
# These decorators are taken in consideration only for invalid-name.
|
|
||||||
property-classes=abc.abstractproperty
|
|
||||||
|
|
||||||
# Regular expression matching correct type alias names. If left empty, type
|
|
||||||
# alias names will be checked with the set naming style.
|
|
||||||
#typealias-rgx=
|
|
||||||
|
|
||||||
# Regular expression matching correct type variable names. If left empty, type
|
|
||||||
# variable names will be checked with the set naming style.
|
|
||||||
#typevar-rgx=
|
|
||||||
|
|
||||||
# Naming style matching correct variable names.
|
|
||||||
variable-naming-style=snake_case
|
|
||||||
|
|
||||||
# Regular expression matching correct variable names. Overrides variable-
|
|
||||||
# naming-style. If left empty, variable names will be checked with the set
|
|
||||||
# naming style.
|
|
||||||
#variable-rgx=
|
|
||||||
|
|
||||||
|
|
||||||
[CLASSES]
|
|
||||||
|
|
||||||
# Warn about protected attribute access inside special methods
|
|
||||||
check-protected-access-in-special-methods=no
|
|
||||||
|
|
||||||
# List of method names used to declare (i.e. assign) instance attributes.
|
|
||||||
defining-attr-methods=__init__,
|
|
||||||
__new__,
|
|
||||||
setUp,
|
|
||||||
asyncSetUp,
|
|
||||||
__post_init__
|
|
||||||
|
|
||||||
# List of member names, which should be excluded from the protected access
|
|
||||||
# warning.
|
|
||||||
exclude-protected=_asdict,_fields,_replace,_source,_make,os._exit
|
|
||||||
|
|
||||||
# List of valid names for the first argument in a class method.
|
|
||||||
valid-classmethod-first-arg=cls
|
|
||||||
|
|
||||||
# List of valid names for the first argument in a metaclass class method.
|
|
||||||
valid-metaclass-classmethod-first-arg=mcs
|
|
||||||
|
|
||||||
|
|
||||||
[DESIGN]
|
|
||||||
|
|
||||||
# List of regular expressions of class ancestor names to ignore when counting
|
|
||||||
# public methods (see R0903)
|
|
||||||
exclude-too-few-public-methods=
|
|
||||||
|
|
||||||
# List of qualified class names to ignore when counting class parents (see
|
|
||||||
# R0901)
|
|
||||||
ignored-parents=
|
|
||||||
|
|
||||||
# Maximum number of arguments for function / method.
|
|
||||||
max-args=5
|
|
||||||
|
|
||||||
# Maximum number of attributes for a class (see R0902).
|
|
||||||
max-attributes=7
|
|
||||||
|
|
||||||
# Maximum number of boolean expressions in an if statement (see R0916).
|
|
||||||
max-bool-expr=5
|
|
||||||
|
|
||||||
# Maximum number of branch for function / method body.
|
|
||||||
max-branches=12
|
|
||||||
|
|
||||||
# Maximum number of locals for function / method body.
|
|
||||||
max-locals=15
|
|
||||||
|
|
||||||
# Maximum number of parents for a class (see R0901).
|
|
||||||
max-parents=7
|
|
||||||
|
|
||||||
# Maximum number of public methods for a class (see R0904).
|
|
||||||
max-public-methods=20
|
|
||||||
|
|
||||||
# Maximum number of return / yield for function / method body.
|
|
||||||
max-returns=6
|
|
||||||
|
|
||||||
# Maximum number of statements in function / method body.
|
|
||||||
max-statements=50
|
|
||||||
|
|
||||||
# Minimum number of public methods for a class (see R0903).
|
|
||||||
min-public-methods=2
|
|
||||||
|
|
||||||
|
|
||||||
[EXCEPTIONS]
|
|
||||||
|
|
||||||
# Exceptions that will emit a warning when caught.
|
|
||||||
overgeneral-exceptions=builtins.BaseException,builtins.Exception
|
|
||||||
|
|
||||||
|
|
||||||
[FORMAT]
|
|
||||||
|
|
||||||
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
|
|
||||||
expected-line-ending-format=
|
|
||||||
|
|
||||||
# Regexp for a line that is allowed to be longer than the limit.
|
|
||||||
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
|
|
||||||
|
|
||||||
# Number of spaces of indent required inside a hanging or continued line.
|
|
||||||
indent-after-paren=4
|
|
||||||
|
|
||||||
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
|
|
||||||
# tab).
|
|
||||||
indent-string=' '
|
|
||||||
|
|
||||||
# Maximum number of characters on a single line.
|
|
||||||
max-line-length=100
|
|
||||||
|
|
||||||
# Maximum number of lines in a module.
|
|
||||||
max-module-lines=1000
|
|
||||||
|
|
||||||
# Allow the body of a class to be on the same line as the declaration if body
|
|
||||||
# contains single statement.
|
|
||||||
single-line-class-stmt=no
|
|
||||||
|
|
||||||
# Allow the body of an if to be on the same line as the test if there is no
|
|
||||||
# else.
|
|
||||||
single-line-if-stmt=no
|
|
||||||
|
|
||||||
|
|
||||||
[IMPORTS]
|
|
||||||
|
|
||||||
# List of modules that can be imported at any level, not just the top level
|
|
||||||
# one.
|
|
||||||
allow-any-import-level=
|
|
||||||
|
|
||||||
# Allow explicit reexports by alias from a package __init__.
|
|
||||||
allow-reexport-from-package=no
|
|
||||||
|
|
||||||
# Allow wildcard imports from modules that define __all__.
|
|
||||||
allow-wildcard-with-all=no
|
|
||||||
|
|
||||||
# Deprecated modules which should not be used, separated by a comma.
|
|
||||||
deprecated-modules=
|
|
||||||
|
|
||||||
# Output a graph (.gv or any supported image format) of external dependencies
|
|
||||||
# to the given file (report RP0402 must not be disabled).
|
|
||||||
ext-import-graph=
|
|
||||||
|
|
||||||
# Output a graph (.gv or any supported image format) of all (i.e. internal and
|
|
||||||
# external) dependencies to the given file (report RP0402 must not be
|
|
||||||
# disabled).
|
|
||||||
import-graph=
|
|
||||||
|
|
||||||
# Output a graph (.gv or any supported image format) of internal dependencies
|
|
||||||
# to the given file (report RP0402 must not be disabled).
|
|
||||||
int-import-graph=
|
|
||||||
|
|
||||||
# Force import order to recognize a module as part of the standard
|
|
||||||
# compatibility libraries.
|
|
||||||
known-standard-library=
|
|
||||||
|
|
||||||
# Force import order to recognize a module as part of a third party library.
|
|
||||||
known-third-party=enchant
|
|
||||||
|
|
||||||
# Couples of modules and preferred modules, separated by a comma.
|
|
||||||
preferred-modules=
|
|
||||||
|
|
||||||
|
|
||||||
[LOGGING]
|
|
||||||
|
|
||||||
# The type of string formatting that logging methods do. `old` means using %
|
|
||||||
# formatting, `new` is for `{}` formatting.
|
|
||||||
logging-format-style=old
|
|
||||||
|
|
||||||
# Logging modules to check that the string format arguments are in logging
|
|
||||||
# function parameter format.
|
|
||||||
logging-modules=logging
|
|
||||||
|
|
||||||
|
|
||||||
[MESSAGES CONTROL]
|
|
||||||
|
|
||||||
# Only show warnings with the listed confidence levels. Leave empty to show
|
|
||||||
# all. Valid levels: HIGH, CONTROL_FLOW, INFERENCE, INFERENCE_FAILURE,
|
|
||||||
# UNDEFINED.
|
|
||||||
confidence=HIGH,
|
|
||||||
CONTROL_FLOW,
|
|
||||||
INFERENCE,
|
|
||||||
INFERENCE_FAILURE,
|
|
||||||
UNDEFINED
|
|
||||||
|
|
||||||
# Disable the message, report, category or checker with the given id(s). You
|
|
||||||
# can either give multiple identifiers separated by comma (,) or put this
|
|
||||||
# option multiple times (only on the command line, not in the configuration
|
|
||||||
# file where it should appear only once). You can also use "--disable=all" to
|
|
||||||
# disable everything first and then re-enable specific checks. For example, if
|
|
||||||
# you want to run only the similarities checker, you can use "--disable=all
|
|
||||||
# --enable=similarities". If you want to run only the classes checker, but have
|
|
||||||
# no Warning level messages displayed, use "--disable=all --enable=classes
|
|
||||||
# --disable=W".
|
|
||||||
disable=raw-checker-failed,
|
|
||||||
bad-inline-option,
|
|
||||||
locally-disabled,
|
|
||||||
file-ignored,
|
|
||||||
suppressed-message,
|
|
||||||
useless-suppression,
|
|
||||||
deprecated-pragma,
|
|
||||||
use-symbolic-message-instead,
|
|
||||||
missing-module-docstring,
|
|
||||||
line-too-long,
|
|
||||||
no-name-in-module,
|
|
||||||
import-outside-toplevel,
|
|
||||||
invalid-name,
|
|
||||||
raise-missing-from,
|
|
||||||
wrong-import-order,
|
|
||||||
too-few-public-methods,
|
|
||||||
too-many-instance-attributes,
|
|
||||||
broad-except,
|
|
||||||
fixme,
|
|
||||||
too-many-arguments,
|
|
||||||
duplicate-code,
|
|
||||||
cyclic-import,
|
|
||||||
|
|
||||||
# Enable the message, report, category or checker with the given id(s). You can
|
|
||||||
# either give multiple identifier separated by comma (,) or put this option
|
|
||||||
# multiple time (only on the command line, not in the configuration file where
|
|
||||||
# it should appear only once). See also the "--disable" option for examples.
|
|
||||||
enable=c-extension-no-member
|
|
||||||
|
|
||||||
|
|
||||||
[METHOD_ARGS]
|
|
||||||
|
|
||||||
# List of qualified names (i.e., library.method) which require a timeout
|
|
||||||
# parameter e.g. 'requests.api.get,requests.api.post'
|
|
||||||
timeout-methods=requests.api.delete,requests.api.get,requests.api.head,requests.api.options,requests.api.patch,requests.api.post,requests.api.put,requests.api.request
|
|
||||||
|
|
||||||
|
|
||||||
[MISCELLANEOUS]
|
|
||||||
|
|
||||||
# List of note tags to take in consideration, separated by a comma.
|
|
||||||
notes=FIXME,
|
|
||||||
XXX,
|
|
||||||
TODO
|
|
||||||
|
|
||||||
# Regular expression of note tags to take in consideration.
|
|
||||||
notes-rgx=
|
|
||||||
|
|
||||||
|
|
||||||
[REFACTORING]
|
|
||||||
|
|
||||||
# Maximum number of nested blocks for function / method body
|
|
||||||
max-nested-blocks=5
|
|
||||||
|
|
||||||
# Complete name of functions that never returns. When checking for
|
|
||||||
# inconsistent-return-statements if a never returning function is called then
|
|
||||||
# it will be considered as an explicit return statement and no message will be
|
|
||||||
# printed.
|
|
||||||
never-returning-functions=sys.exit,argparse.parse_error
|
|
||||||
|
|
||||||
|
|
||||||
[REPORTS]
|
|
||||||
|
|
||||||
# Python expression which should return a score less than or equal to 10. You
|
|
||||||
# have access to the variables 'fatal', 'error', 'warning', 'refactor',
|
|
||||||
# 'convention', and 'info' which contain the number of messages in each
|
|
||||||
# category, as well as 'statement' which is the total number of statements
|
|
||||||
# analyzed. This score is used by the global evaluation report (RP0004).
|
|
||||||
evaluation=max(0, 0 if fatal else 10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10))
|
|
||||||
|
|
||||||
# Template used to display messages. This is a python new-style format string
|
|
||||||
# used to format the message information. See doc for all details.
|
|
||||||
msg-template=
|
|
||||||
|
|
||||||
# Set the output format. Available formats are text, parseable, colorized, json
|
|
||||||
# and msvs (visual studio). You can also give a reporter class, e.g.
|
|
||||||
# mypackage.mymodule.MyReporterClass.
|
|
||||||
#output-format=
|
|
||||||
|
|
||||||
# Tells whether to display a full report or only the messages.
|
|
||||||
reports=no
|
|
||||||
|
|
||||||
# Activate the evaluation score.
|
|
||||||
score=yes
|
|
||||||
|
|
||||||
|
|
||||||
[SIMILARITIES]
|
|
||||||
|
|
||||||
# Comments are removed from the similarity computation
|
|
||||||
ignore-comments=yes
|
|
||||||
|
|
||||||
# Docstrings are removed from the similarity computation
|
|
||||||
ignore-docstrings=yes
|
|
||||||
|
|
||||||
# Imports are removed from the similarity computation
|
|
||||||
ignore-imports=yes
|
|
||||||
|
|
||||||
# Signatures are removed from the similarity computation
|
|
||||||
ignore-signatures=yes
|
|
||||||
|
|
||||||
# Minimum lines number of a similarity.
|
|
||||||
min-similarity-lines=4
|
|
||||||
|
|
||||||
|
|
||||||
[SPELLING]
|
|
||||||
|
|
||||||
# Limits count of emitted suggestions for spelling mistakes.
|
|
||||||
max-spelling-suggestions=4
|
|
||||||
|
|
||||||
# Spelling dictionary name. No available dictionaries : You need to install
|
|
||||||
# both the python package and the system dependency for enchant to work..
|
|
||||||
spelling-dict=
|
|
||||||
|
|
||||||
# List of comma separated words that should be considered directives if they
|
|
||||||
# appear at the beginning of a comment and should not be checked.
|
|
||||||
spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy:
|
|
||||||
|
|
||||||
# List of comma separated words that should not be checked.
|
|
||||||
spelling-ignore-words=
|
|
||||||
|
|
||||||
# A path to a file that contains the private dictionary; one word per line.
|
|
||||||
spelling-private-dict-file=
|
|
||||||
|
|
||||||
# Tells whether to store unknown words to the private dictionary (see the
|
|
||||||
# --spelling-private-dict-file option) instead of raising a message.
|
|
||||||
spelling-store-unknown-words=no
|
|
||||||
|
|
||||||
|
|
||||||
[STRING]
|
|
||||||
|
|
||||||
# This flag controls whether inconsistent-quotes generates a warning when the
|
|
||||||
# character used as a quote delimiter is used inconsistently within a module.
|
|
||||||
check-quote-consistency=no
|
|
||||||
|
|
||||||
# This flag controls whether the implicit-str-concat should generate a warning
|
|
||||||
# on implicit string concatenation in sequences defined over several lines.
|
|
||||||
check-str-concat-over-line-jumps=no
|
|
||||||
|
|
||||||
|
|
||||||
[TYPECHECK]
|
|
||||||
|
|
||||||
# List of decorators that produce context managers, such as
|
|
||||||
# contextlib.contextmanager. Add to this list to register other decorators that
|
|
||||||
# produce valid context managers.
|
|
||||||
contextmanager-decorators=contextlib.contextmanager
|
|
||||||
|
|
||||||
# List of members which are set dynamically and missed by pylint inference
|
|
||||||
# system, and so shouldn't trigger E1101 when accessed. Python regular
|
|
||||||
# expressions are accepted.
|
|
||||||
generated-members=
|
|
||||||
|
|
||||||
# Tells whether to warn about missing members when the owner of the attribute
|
|
||||||
# is inferred to be None.
|
|
||||||
ignore-none=yes
|
|
||||||
|
|
||||||
# This flag controls whether pylint should warn about no-member and similar
|
|
||||||
# checks whenever an opaque object is returned when inferring. The inference
|
|
||||||
# can return multiple potential results while evaluating a Python object, but
|
|
||||||
# some branches might not be evaluated, which results in partial inference. In
|
|
||||||
# that case, it might be useful to still emit no-member and other checks for
|
|
||||||
# the rest of the inferred objects.
|
|
||||||
ignore-on-opaque-inference=yes
|
|
||||||
|
|
||||||
# List of symbolic message names to ignore for Mixin members.
|
|
||||||
ignored-checks-for-mixins=no-member,
|
|
||||||
not-async-context-manager,
|
|
||||||
not-context-manager,
|
|
||||||
attribute-defined-outside-init
|
|
||||||
|
|
||||||
# List of class names for which member attributes should not be checked (useful
|
|
||||||
# for classes with dynamically set attributes). This supports the use of
|
|
||||||
# qualified names.
|
|
||||||
ignored-classes=optparse.Values,thread._local,_thread._local,argparse.Namespace
|
|
||||||
|
|
||||||
# Show a hint with possible names when a member name was not found. The aspect
|
|
||||||
# of finding the hint is based on edit distance.
|
|
||||||
missing-member-hint=yes
|
|
||||||
|
|
||||||
# The minimum edit distance a name should have in order to be considered a
|
|
||||||
# similar match for a missing member name.
|
|
||||||
missing-member-hint-distance=1
|
|
||||||
|
|
||||||
# The total number of similar names that should be taken in consideration when
|
|
||||||
# showing a hint for a missing member.
|
|
||||||
missing-member-max-choices=1
|
|
||||||
|
|
||||||
# Regex pattern to define which classes are considered mixins.
|
|
||||||
mixin-class-rgx=.*[Mm]ixin
|
|
||||||
|
|
||||||
# List of decorators that change the signature of a decorated function.
|
|
||||||
signature-mutators=
|
|
||||||
|
|
||||||
|
|
||||||
[VARIABLES]
|
|
||||||
|
|
||||||
# List of additional names supposed to be defined in builtins. Remember that
|
|
||||||
# you should avoid defining new builtins when possible.
|
|
||||||
additional-builtins=
|
|
||||||
|
|
||||||
# Tells whether unused global variables should be treated as a violation.
|
|
||||||
allow-global-unused-variables=yes
|
|
||||||
|
|
||||||
# List of names allowed to shadow builtins
|
|
||||||
allowed-redefined-builtins=
|
|
||||||
|
|
||||||
# List of strings which can identify a callback function by name. A callback
|
|
||||||
# name must start or end with one of those strings.
|
|
||||||
callbacks=cb_,
|
|
||||||
_cb
|
|
||||||
|
|
||||||
# A regular expression matching the name of dummy variables (i.e. expected to
|
|
||||||
# not be used).
|
|
||||||
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
|
|
||||||
|
|
||||||
# Argument names that match this expression will be ignored.
|
|
||||||
ignored-argument-names=_.*|^ignored_|^unused_
|
|
||||||
|
|
||||||
# Tells whether we should check for unused import in __init__ files.
|
|
||||||
init-import=no
|
|
||||||
|
|
||||||
# List of qualified module names which can have objects that can redefine
|
|
||||||
# builtins.
|
|
||||||
redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[pytest]
|
||||||
|
addopts = --cov=ahriman --cov-report=term-missing:skip-covered --no-cov-on-fail --cov-fail-under=100 --spec
|
||||||
|
asyncio_default_fixture_loop_scope = function
|
||||||
|
asyncio_mode = auto
|
||||||
|
pythonpath = tests
|
||||||
|
resource-path.directory-name-test-resources = ../../tests/testresources
|
||||||
|
spec_test_format = {result} {docstring_summary}
|
||||||
+5
-8
@@ -1,18 +1,15 @@
|
|||||||
version: 2
|
version: 2
|
||||||
|
|
||||||
build:
|
build:
|
||||||
os: ubuntu-20.04
|
os: ubuntu-lts-latest
|
||||||
tools:
|
tools:
|
||||||
python: "3.11"
|
python: "3.13"
|
||||||
|
apt_packages:
|
||||||
|
- graphviz
|
||||||
|
|
||||||
python:
|
python:
|
||||||
install:
|
install:
|
||||||
- method: pip
|
- requirements: docs/requirements.txt
|
||||||
path: .
|
|
||||||
extra_requirements:
|
|
||||||
- docs
|
|
||||||
- s3
|
|
||||||
- web
|
|
||||||
|
|
||||||
formats:
|
formats:
|
||||||
- pdf
|
- pdf
|
||||||
|
|||||||
+65
-28
@@ -36,6 +36,7 @@ Again, the most checks can be performed by `tox` command, though some additional
|
|||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
Very important note about this function
|
Very important note about this function
|
||||||
|
Probably multi-line
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
argument(str): an argument. This argument has
|
argument(str): an argument. This argument has
|
||||||
@@ -70,6 +71,7 @@ Again, the most checks can be performed by `tox` command, though some additional
|
|||||||
Attributes:
|
Attributes:
|
||||||
CLAZZ_ATTRIBUTE(int): (class attribute) a brand-new class attribute
|
CLAZZ_ATTRIBUTE(int): (class attribute) a brand-new class attribute
|
||||||
instance_attribute(str): an instance attribute
|
instance_attribute(str): an instance attribute
|
||||||
|
with the long description
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
Very informative class usage example, e.g.::
|
Very informative class usage example, e.g.::
|
||||||
@@ -78,12 +80,10 @@ 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:
|
||||||
"""
|
"""
|
||||||
default constructor
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
*args(Any): positional arguments
|
*args(Any): positional arguments
|
||||||
**kwargs(Any): keyword arguments
|
**kwargs(Any): keyword arguments
|
||||||
@@ -91,9 +91,12 @@ Again, the most checks can be performed by `tox` command, though some additional
|
|||||||
self.instance_attribute = ""
|
self.instance_attribute = ""
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Note missing comment for the `__init__` method, which is the special case.
|
||||||
|
|
||||||
* 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 `typinng.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
|
||||||
@@ -122,7 +125,7 @@ Again, the most checks can be performed by `tox` command, though some additional
|
|||||||
def __hash__(self) -> int: ... # basically any magic (or look-alike) method
|
def __hash__(self) -> int: ... # basically any magic (or look-alike) method
|
||||||
```
|
```
|
||||||
|
|
||||||
Methods inside one group should be ordered alphabetically, the only exceptions are `__init__` (`__post_init__` for dataclasses), `__new__` and `__del__` methods which should be defined first. For test methods it is recommended to follow the order in which functions are defined.
|
Methods inside one group should be ordered alphabetically, the only exceptions are `__init__` (`__post_init__` for dataclasses), `__new__` and `__del__` methods which should be defined first. For test methods it is recommended to follow the order in which functions are defined. Same idea applies to frontend classes.
|
||||||
|
|
||||||
Though, we would like to highlight abstract methods (i.e. ones which raise `NotImplementedError`), we still keep in global order at the moment.
|
Though, we would like to highlight abstract methods (i.e. ones which raise `NotImplementedError`), we still keep in global order at the moment.
|
||||||
|
|
||||||
@@ -132,7 +135,7 @@ Again, the most checks can be performed by `tox` command, though some additional
|
|||||||
* For any path interactions `pathlib.Path` must be used.
|
* For any path interactions `pathlib.Path` must be used.
|
||||||
* Configuration interactions must go through `ahriman.core.configuration.Configuration` class instance.
|
* Configuration interactions must go through `ahriman.core.configuration.Configuration` class instance.
|
||||||
* In case if class load requires some actions, it is recommended to create class method which can be used for class instantiating.
|
* In case if class load requires some actions, it is recommended to create class method which can be used for class instantiating.
|
||||||
* The code must follow the exception safety, unless it is explicitly asked by end user. It means that most exceptions must be handled and printed to log, no other actions must be done (e.g. raising another exception).
|
* The most (expected) exceptions must be handled and printed to log, allowing service to continue work. However, fatal and (in some cases) unexpected exceptions may lead to the application termination.
|
||||||
* Exceptions without parameters should be raised without parentheses, e.g.:
|
* Exceptions without parameters should be raised without parentheses, e.g.:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@@ -162,10 +165,16 @@ Again, the most checks can be performed by `tox` command, though some additional
|
|||||||
|
|
||||||
# Blank line again and package imports
|
# Blank line again and package imports
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
|
# Multiline import example
|
||||||
|
from ahriman.core.database.operations import (
|
||||||
|
AuthOperations,
|
||||||
|
BuildOperations,
|
||||||
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
* One file should define only one class, exception is class satellites in case if file length remains less than 400 lines.
|
* Imports goes in alphabetical order, no relative imports allowed. Same rule applies to frontend classes.
|
||||||
* It is possible to create file which contains some functions (e.g. `ahriman.core.util`), but in this case you would need to define `__all__` attribute.
|
* One file should define only one class, exception is class satellites in case if file length remains less than 400 lines. Same rule applies to frontend classes.
|
||||||
|
* It is possible to create file which contains some functions (e.g. `ahriman.core.utils`), but in this case you would need to define `__all__` attribute.
|
||||||
* The file size mentioned above must be applicable in general. In case of big classes consider splitting them into traits. Note, however, that `pylint` includes comments and docstrings into counter, thus you need to check file size by other tools.
|
* The file size mentioned above must be applicable in general. In case of big classes consider splitting them into traits. Note, however, that `pylint` includes comments and docstrings into counter, thus you need to check file size by other tools.
|
||||||
* No global variable is allowed outside of `ahriman` module. `ahriman.core.context` is also special case.
|
* No global variable is allowed outside of `ahriman` module. `ahriman.core.context` is also special case.
|
||||||
* Single quotes are not allowed. The reason behind this restriction is the fact that docstrings must be written by using double quotes only, and we would like to make style consistent.
|
* Single quotes are not allowed. The reason behind this restriction is the fact that docstrings must be written by using double quotes only, and we would like to make style consistent.
|
||||||
@@ -173,11 +182,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
|
||||||
|
|
||||||
|
|
||||||
@@ -196,36 +204,31 @@ 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: ...
|
||||||
```
|
```
|
||||||
|
|
||||||
* It is allowed to change web API to add new fields or remove optional ones. However, in case of model changes, new API version must be introduced.
|
* It is allowed to change web API to add new fields or remove optional ones. However, in case of model changes, new API version must be introduced.
|
||||||
* On the other hand, it is allowed to change method signatures, however, it is recommended to add new parameters as optional if possible. Deprecated API can be dropped during major release.
|
* On the other hand, it is allowed to change method signatures, however, it is recommended to add new parameters as optional if possible. Deprecated API can be dropped during major release.
|
||||||
* Enumerations (`Enum` classes) are allowed and recommended. However, it is recommended to use `StrEnum` class if there are from/to string conversions and `IntEnum` otherwise.
|
* Enumerations (`Enum` classes) are allowed and recommended. However, it is recommended to use `StrEnum` class if there are from/to string conversions and `IntEnum` otherwise.
|
||||||
|
* `Generator` return type is not allowed. Generator functions must return generic `Iterator` object. Documentation should be described as `Yields`, however, because of pylint checks. Unfortunately, `Iterable` return type is not available for generators also, because of specific `contextlib.contextmanager` case.
|
||||||
|
|
||||||
### Other checks
|
### Other checks
|
||||||
|
|
||||||
The projects also uses typing checks (provided by `mypy`) and some linter checks provided by `pylint` and `bandit`. Those checks must be passed successfully for any open pull requests.
|
The projects also uses typing checks (provided by `mypy`) and some linter checks provided by `pylint` and `bandit`. Those checks must be passed successfully for any open pull requests.
|
||||||
|
|
||||||
|
Frontend checks normally are performed by `eslint` (e.g. `npx run eslint`).
|
||||||
|
|
||||||
## Developers how to
|
## Developers how to
|
||||||
|
|
||||||
### Run automated checks
|
### Run automated checks
|
||||||
@@ -234,16 +237,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
|
||||||
|
```
|
||||||
|
|||||||
-65
@@ -1,65 +0,0 @@
|
|||||||
FROM archlinux:base
|
|
||||||
|
|
||||||
# image configuration
|
|
||||||
ENV AHRIMAN_ARCHITECTURE="x86_64"
|
|
||||||
ENV AHRIMAN_DEBUG=""
|
|
||||||
ENV AHRIMAN_FORCE_ROOT=""
|
|
||||||
ENV AHRIMAN_HOST="0.0.0.0"
|
|
||||||
ENV AHRIMAN_MULTILIB="yes"
|
|
||||||
ENV AHRIMAN_OUTPUT=""
|
|
||||||
ENV AHRIMAN_PACKAGER="ahriman bot <ahriman@example.com>"
|
|
||||||
ENV AHRIMAN_PACMAN_MIRROR=""
|
|
||||||
ENV AHRIMAN_PORT=""
|
|
||||||
ENV AHRIMAN_POSTSETUP_COMMAND=""
|
|
||||||
ENV AHRIMAN_PRESETUP_COMMAND=""
|
|
||||||
ENV AHRIMAN_REPOSITORY="aur-clone"
|
|
||||||
ENV AHRIMAN_REPOSITORY_SERVER=""
|
|
||||||
ENV AHRIMAN_REPOSITORY_ROOT="/var/lib/ahriman/ahriman"
|
|
||||||
ENV AHRIMAN_UNIX_SOCKET=""
|
|
||||||
ENV AHRIMAN_USER="ahriman"
|
|
||||||
ENV AHRIMAN_VALIDATE_CONFIGURATION="yes"
|
|
||||||
|
|
||||||
# install environment
|
|
||||||
## update pacman.conf with multilib
|
|
||||||
RUN echo "[multilib]" >> "/etc/pacman.conf" && \
|
|
||||||
echo "Include = /etc/pacman.d/mirrorlist" >> "/etc/pacman.conf"
|
|
||||||
## refresh packages, install sudo and install packages for building
|
|
||||||
RUN pacman -Syu --noconfirm sudo && \
|
|
||||||
pacman -Sy --noconfirm --asdeps fakeroot python-tox
|
|
||||||
## create build user
|
|
||||||
RUN useradd -m -d "/home/build" -s "/usr/bin/nologin" build && \
|
|
||||||
echo "build ALL=(ALL) NOPASSWD: ALL" > "/etc/sudoers.d/build"
|
|
||||||
COPY "docker/install-aur-package.sh" "/usr/local/bin/install-aur-package"
|
|
||||||
## install package dependencies
|
|
||||||
## darcs is not installed by reasons, because it requires a lot haskell packages which dramatically increase image size
|
|
||||||
RUN pacman -Sy --noconfirm --asdeps devtools git pyalpm python-cerberus python-inflection python-passlib python-requests python-srcinfo && \
|
|
||||||
pacman -Sy --noconfirm --asdeps python-build python-flit python-installer python-wheel && \
|
|
||||||
pacman -Sy --noconfirm --asdeps breezy git mercurial python-aiohttp python-boto3 python-cryptography python-jinja python-requests-unixsocket python-systemd rsync subversion && \
|
|
||||||
runuser -u build -- install-aur-package python-aioauth-client python-aiohttp-apispec-git python-aiohttp-cors \
|
|
||||||
python-aiohttp-jinja2 python-aiohttp-session python-aiohttp-security
|
|
||||||
|
|
||||||
## 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"
|
|
||||||
|
|
||||||
# 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 --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"]
|
|
||||||
|
|
||||||
# minimal runtime ahriman setup
|
|
||||||
COPY "docker/entrypoint.sh" "/usr/local/bin/entrypoint"
|
|
||||||
ENTRYPOINT ["entrypoint"]
|
|
||||||
# default command
|
|
||||||
CMD ["repo-update", "--refresh"]
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
[](https://github.com/arcan1s/ahriman/actions/workflows/tests.yml)
|
[](https://github.com/arcan1s/ahriman/actions/workflows/tests.yml)
|
||||||
[](https://github.com/arcan1s/ahriman/actions/workflows/setup.yml)
|
[](https://github.com/arcan1s/ahriman/actions/workflows/setup.yml)
|
||||||
[](https://hub.docker.com/r/arcan1s/ahriman)
|
[](https://hub.docker.com/r/arcan1s/ahriman)
|
||||||
[](https://www.codefactor.io/repository/github/arcan1s/ahriman)
|
[](https://www.codefactor.io/repository/github/arcan1s/ahriman)
|
||||||
[](https://ahriman.readthedocs.io)
|
[](https://ahriman.readthedocs.io)
|
||||||
|
|
||||||
@@ -33,10 +33,12 @@ Every available option is described in the [documentation](https://ahriman.readt
|
|||||||
|
|
||||||
The application provides reasonable defaults which allow to use it out-of-box; however additional steps (like configuring build toolchain and sudoers) are recommended and can be easily achieved by following install instructions.
|
The application provides reasonable defaults which allow to use it out-of-box; however additional steps (like configuring build toolchain and sudoers) are recommended and can be easily achieved by following install instructions.
|
||||||
|
|
||||||
## [FAQ](https://ahriman.readthedocs.io/en/stable/faq.html)
|
## [FAQ](https://ahriman.readthedocs.io/en/stable/faq/index.html)
|
||||||
|
|
||||||
## Live demos
|
## Live demos
|
||||||
|
|
||||||
* [Build status page](https://ahriman-demo.arcanis.me). You can log in as `demo` user by using `demo` password. However, you will not be able to run tasks. [HTTP API documentation](https://ahriman-demo.arcanis.me/api-docs) is also available.
|
* [Build status page](https://ahriman-demo.arcanis.me). You can log in as `demo` user by using `demo` password. However, you will not be able to run tasks. [HTTP API documentation](https://ahriman-demo.arcanis.me/api-docs) is also available.
|
||||||
* [Repository index](https://repo.arcanis.me/arcanisrepo/x86_64/).
|
* [Repository index](https://repo.arcanis.me/arcanisrepo/x86_64/).
|
||||||
* [Telegram feed](https://t.me/arcanisrepo).
|
* [Telegram feed](https://t.me/arcanisrepo).
|
||||||
|
|
||||||
|
Do you have any success story? You can [share it](https://github.com/arcan1s/ahriman/issues/new?template=04-discussion.md)!
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@ Description=ArcH linux ReposItory MANager (%i)
|
|||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
ExecStart=/usr/bin/ahriman --repository-id "%I" repo-daemon --no-changes --refresh
|
ExecStart=/usr/bin/ahriman --repository-id "%I" repo-daemon --refresh
|
||||||
User=ahriman
|
User=ahriman
|
||||||
Group=ahriman
|
Group=ahriman
|
||||||
|
|
||||||
+1
-1
@@ -2,6 +2,6 @@
|
|||||||
Description=ArcH linux ReposItory MANager (%i)
|
Description=ArcH linux ReposItory MANager (%i)
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
ExecStart=/usr/bin/ahriman --repository-id "%I" repo-update --no-changes --refresh
|
ExecStart=/usr/bin/ahriman --repository-id "%I" repo-update --refresh
|
||||||
User=ahriman
|
User=ahriman
|
||||||
Group=ahriman
|
Group=ahriman
|
||||||
+82
-116
@@ -3,10 +3,10 @@
|
|||||||
include = ahriman.ini.d
|
include = ahriman.ini.d
|
||||||
; Relative path to configuration used by logging package.
|
; Relative path to configuration used by logging package.
|
||||||
logging = ahriman.ini.d/logging.ini
|
logging = ahriman.ini.d/logging.ini
|
||||||
; Perform database migrations on the application start. Do not touch this option unless you know what are you doing.
|
; Perform database migrations on the application start. Do not touch this option unless you know what you are doing.
|
||||||
;apply_migrations = yes
|
;apply_migrations = yes
|
||||||
; Path to the application SQLite database.
|
; Path to the application SQLite database.
|
||||||
database = /var/lib/ahriman/ahriman.db
|
database = ${repository:root}/ahriman.db
|
||||||
|
|
||||||
[alpm]
|
[alpm]
|
||||||
; Path to pacman system database cache.
|
; Path to pacman system database cache.
|
||||||
@@ -17,51 +17,51 @@ mirror = https://geo.mirror.pkgbuild.com/$repo/os/$arch
|
|||||||
repositories = core extra multilib
|
repositories = core extra multilib
|
||||||
; Pacman's root directory. In the most cases it must point to the system root.
|
; Pacman's root directory. In the most cases it must point to the system root.
|
||||||
root = /
|
root = /
|
||||||
|
; Sync files databases too, which is required by deep dependencies check.
|
||||||
|
sync_files_database = yes
|
||||||
; Use local packages cache. If this option is enabled, the service will be able to synchronize databases (available
|
; Use local packages cache. If this option is enabled, the service will be able to synchronize databases (available
|
||||||
; 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]
|
[aur]
|
||||||
; Authentication provider, must be one of disabled, configuration, oauth.
|
; Maximum amount of retries of HTTP requests.
|
||||||
target = disabled
|
max_retries = 3
|
||||||
; Allow read-only endpoint to be called without authentication.
|
; Retry exponential backoff.
|
||||||
allow_read_only = yes
|
retry_backoff = 1.0
|
||||||
; OAuth2 application client ID and secret. Required if oauth is used.
|
; HTTP request timeout in seconds.
|
||||||
;client_id =
|
;timeout = 30
|
||||||
;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 =
|
|
||||||
; 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
|
|
||||||
; 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 =
|
||||||
|
; Path to build command.
|
||||||
|
;build_command =
|
||||||
; List of packages to be ignored during automatic updates.
|
; List of packages to be ignored during automatic updates.
|
||||||
;ignore_packages =
|
;ignore_packages =
|
||||||
|
; Include debug packages.
|
||||||
|
;include_debug_packages = yes
|
||||||
; List of additional flags passed to makechrootpkg command.
|
; List of additional flags passed to makechrootpkg command.
|
||||||
;makechrootpkg_flags =
|
;makechrootpkg_flags =
|
||||||
; List of additional flags passed to makepkg command.
|
; List of additional flags passed to makepkg command.
|
||||||
makepkg_flags = --nocolor --ignorearch
|
makepkg_flags = --nocolor --ignorearch
|
||||||
|
; List of paths to be used for implicit dependency scan. Regular expressions are supported.
|
||||||
|
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
|
||||||
|
triggers[] = ahriman.core.housekeeping.LogsRotationTrigger
|
||||||
|
triggers[] = ahriman.core.housekeeping.ArchiveRotationTrigger
|
||||||
; 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.housekeeping.ArchiveRotationTrigger
|
||||||
|
triggers_known[] = ahriman.core.housekeeping.LogsRotationTrigger
|
||||||
|
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.
|
||||||
@@ -77,12 +77,16 @@ target =
|
|||||||
; Global switch to enable or disable status reporting.
|
; Global switch to enable or disable status reporting.
|
||||||
enabled = yes
|
enabled = yes
|
||||||
; Address of the remote service, e.g.:
|
; Address of the remote service, e.g.:
|
||||||
; address = http://1.0.0.1:8080
|
; address = http://127.0.0.1:8080
|
||||||
; In case if unix sockets are used, it might point to the valid socket with encoded path, e.g.:
|
; In case if unix sockets are used, it might point to the valid socket with encoded path, e.g.:
|
||||||
; address = http+unix://%2Fvar%2Flib%2Fahriman%2Fsocket
|
; address = http+unix://%2Fvar%2Flib%2Fahriman%2Fsocket
|
||||||
;address =
|
;address = http://${web:host}:${web:port}
|
||||||
|
; Maximum amount of retries of HTTP requests.
|
||||||
|
;max_retries = 0
|
||||||
; Optional password for authentication (if enabled).
|
; Optional password for authentication (if enabled).
|
||||||
;password =
|
;password =
|
||||||
|
; Retry exponential backoff.
|
||||||
|
;retry_backoff = 0.0
|
||||||
; Do not log HTTP errors if occurs.
|
; Do not log HTTP errors if occurs.
|
||||||
suppress_http_log_errors = yes
|
suppress_http_log_errors = yes
|
||||||
; HTTP request timeout in seconds.
|
; HTTP request timeout in seconds.
|
||||||
@@ -90,79 +94,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 =
|
|
||||||
; 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.
|
|
||||||
;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 = /usr/share/ahriman/templates/static
|
|
||||||
; List of directories with templates.
|
|
||||||
templates = /usr/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
|
||||||
@@ -200,14 +131,14 @@ target = console
|
|||||||
|
|
||||||
; Console reporting trigger configuration sample.
|
; Console reporting trigger configuration sample.
|
||||||
[console]
|
[console]
|
||||||
; Trigger type name
|
; Trigger type name.
|
||||||
;type = console
|
;type = console
|
||||||
; Use utf8 symbols in output.
|
; Use utf8 symbols in output.
|
||||||
use_utf = yes
|
use_utf = yes
|
||||||
|
|
||||||
; Email reporting trigger configuration sample.
|
; Email reporting trigger configuration sample.
|
||||||
[email]
|
[email]
|
||||||
; Trigger type name
|
; Trigger type name.
|
||||||
;type = email
|
;type = email
|
||||||
; Optional URL to the repository homepage.
|
; Optional URL to the repository homepage.
|
||||||
;homepage=
|
;homepage=
|
||||||
@@ -223,6 +154,8 @@ use_utf = yes
|
|||||||
;port =
|
;port =
|
||||||
; List of emails to receive the reports.
|
; List of emails to receive the reports.
|
||||||
;receivers =
|
;receivers =
|
||||||
|
; Optional link to the RSS feed.
|
||||||
|
;rss_url =
|
||||||
; Sender email.
|
; Sender email.
|
||||||
;sender =
|
;sender =
|
||||||
; SMTP server SSL mode, one of ssl, starttls, disabled.
|
; SMTP server SSL mode, one of ssl, starttls, disabled.
|
||||||
@@ -232,13 +165,13 @@ 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 = /usr/share/ahriman/templates
|
templates[] = ${prefix}/share/ahriman/templates
|
||||||
; SMTP user.
|
; SMTP user.
|
||||||
;user =
|
;user =
|
||||||
|
|
||||||
; HTML reporting trigger configuration sample.
|
; HTML reporting trigger configuration sample.
|
||||||
[html]
|
[html]
|
||||||
; Trigger type name
|
; Trigger type name.
|
||||||
;type = html
|
;type = html
|
||||||
; Optional URL to the repository homepage.
|
; Optional URL to the repository homepage.
|
||||||
;homepage=
|
;homepage=
|
||||||
@@ -246,14 +179,16 @@ templates = /usr/share/ahriman/templates
|
|||||||
;link_path =
|
;link_path =
|
||||||
; Output path for the HTML report.
|
; Output path for the HTML report.
|
||||||
;path =
|
;path =
|
||||||
|
; Optional link to the RSS feed.
|
||||||
|
;rss_url =
|
||||||
; 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 = /usr/share/ahriman/templates
|
templates[] = ${prefix}/share/ahriman/templates
|
||||||
|
|
||||||
; Remote service callback trigger configuration sample.
|
; Remote service callback trigger configuration sample.
|
||||||
[remote-call]
|
[remote-call]
|
||||||
; Trigger type name
|
; Trigger type name.
|
||||||
;type = remote-call
|
;type = remote-call
|
||||||
; Call for AUR packages update.
|
; Call for AUR packages update.
|
||||||
;aur = no
|
;aur = no
|
||||||
@@ -264,9 +199,26 @@ templates = /usr/share/ahriman/templates
|
|||||||
; Wait until remote process will be terminated in seconds.
|
; Wait until remote process will be terminated in seconds.
|
||||||
;wait_timeout = -1
|
;wait_timeout = -1
|
||||||
|
|
||||||
|
; RSS reporting trigger configuration sample.
|
||||||
|
[rss]
|
||||||
|
; Trigger type name.
|
||||||
|
;type = rss
|
||||||
|
; Optional URL to the repository homepage.
|
||||||
|
;homepage=
|
||||||
|
; Prefix for packages links. Link to a package will be formed as link_path / filename.
|
||||||
|
;link_path =
|
||||||
|
; Output path for the RSS report.
|
||||||
|
;path =
|
||||||
|
; Optional link to the RSS feed.
|
||||||
|
;rss_url =
|
||||||
|
; Template name to be used.
|
||||||
|
template = rss.jinja2
|
||||||
|
; List of directories with templates.
|
||||||
|
templates[] = ${prefix}/share/ahriman/templates
|
||||||
|
|
||||||
; Telegram reporting trigger configuration sample.
|
; Telegram reporting trigger configuration sample.
|
||||||
[telegram]
|
[telegram]
|
||||||
; Trigger type name
|
; Trigger type name.
|
||||||
;type = telegram
|
;type = telegram
|
||||||
; Telegram bot API key.
|
; Telegram bot API key.
|
||||||
;api_key =
|
;api_key =
|
||||||
@@ -276,12 +228,18 @@ templates = /usr/share/ahriman/templates
|
|||||||
;homepage=
|
;homepage=
|
||||||
; Prefix for packages links. Link to a package will be formed as link_path / filename.
|
; Prefix for packages links. Link to a package will be formed as link_path / filename.
|
||||||
;link_path =
|
;link_path =
|
||||||
|
; Maximum amount of retries of HTTP requests.
|
||||||
|
;max_retries = 0
|
||||||
|
; Retry exponential backoff.
|
||||||
|
;retry_backoff = 0.0
|
||||||
|
; Optional link to the RSS feed.
|
||||||
|
;rss_url =
|
||||||
; Template name to be used.
|
; Template name to be used.
|
||||||
template = telegram-index.jinja2
|
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 = /usr/share/ahriman/templates
|
templates[] = ${prefix}/share/ahriman/templates
|
||||||
; HTTP request timeout in seconds.
|
; HTTP request timeout in seconds.
|
||||||
;timeout = 30
|
;timeout = 30
|
||||||
|
|
||||||
@@ -292,14 +250,18 @@ target =
|
|||||||
|
|
||||||
; GitHub upload trigger configuration sample.
|
; GitHub upload trigger configuration sample.
|
||||||
[github]
|
[github]
|
||||||
; Trigger type name
|
; Trigger type name.
|
||||||
;type = github
|
;type = github
|
||||||
|
; Maximum amount of retries of HTTP requests.
|
||||||
|
;max_retries = 0
|
||||||
; GitHub repository owner username.
|
; GitHub repository owner username.
|
||||||
;owner =
|
;owner =
|
||||||
; GitHub API key. public_repo (repo) scope is required.
|
; GitHub API key. public_repo (repo) scope is required.
|
||||||
;password =
|
;password =
|
||||||
; GitHub repository name.
|
; GitHub repository name.
|
||||||
;repository =
|
;repository =
|
||||||
|
; Retry exponential backoff.
|
||||||
|
;retry_backoff = 0.0
|
||||||
; HTTP request timeout in seconds.
|
; HTTP request timeout in seconds.
|
||||||
;timeout = 30
|
;timeout = 30
|
||||||
; Include repository name to release name (recommended).
|
; Include repository name to release name (recommended).
|
||||||
@@ -309,14 +271,18 @@ target =
|
|||||||
|
|
||||||
; Remote instance upload trigger configuration sample.
|
; Remote instance upload trigger configuration sample.
|
||||||
[remote-service]
|
[remote-service]
|
||||||
; Trigger type name
|
; Trigger type name.
|
||||||
;type = remote-service
|
;type = remote-service
|
||||||
|
; Maximum amount of retries of HTTP requests.
|
||||||
|
;max_retries = 0
|
||||||
|
; Retry exponential backoff.
|
||||||
|
;retry_backoff = 0.0
|
||||||
; HTTP request timeout in seconds.
|
; HTTP request timeout in seconds.
|
||||||
;timeout = 30
|
;timeout = 30
|
||||||
|
|
||||||
; rsync upload trigger configuration sample.
|
; rsync upload trigger configuration sample.
|
||||||
[rsync]
|
[rsync]
|
||||||
; Trigger type name
|
; Trigger type name.
|
||||||
;type = rsync
|
;type = rsync
|
||||||
; rsync command to run.
|
; rsync command to run.
|
||||||
command = rsync --archive --compress --partial --delete
|
command = rsync --archive --compress --partial --delete
|
||||||
@@ -326,7 +292,7 @@ command = rsync --archive --compress --partial --delete
|
|||||||
|
|
||||||
; S3 upload trigger configuration sample.
|
; S3 upload trigger configuration sample.
|
||||||
[s3]
|
[s3]
|
||||||
; Trigger type name
|
; Trigger type name.
|
||||||
;type = s3
|
;type = s3
|
||||||
; AWS services access key.
|
; AWS services access key.
|
||||||
;access_key =
|
;access_key =
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[archive]
|
||||||
|
; Keep amount of last built packages in archive. 0 means keep all packages
|
||||||
|
keep_built_packages = 1
|
||||||
|
|
||||||
|
[logs-rotation]
|
||||||
|
; Keep last build logs for each package
|
||||||
|
keep_last_logs = 5
|
||||||
+10
-3
@@ -1,5 +1,5 @@
|
|||||||
[loggers]
|
[loggers]
|
||||||
keys = root,http,stderr,boto3,botocore,nose,s3transfer
|
keys = root,http,stderr,boto3,botocore,nose,s3transfer,sql
|
||||||
|
|
||||||
[handlers]
|
[handlers]
|
||||||
keys = console_handler,journald_handler,syslog_handler
|
keys = console_handler,journald_handler,syslog_handler
|
||||||
@@ -26,10 +26,12 @@ formatter = syslog_format
|
|||||||
args = ("/dev/log",)
|
args = ("/dev/log",)
|
||||||
|
|
||||||
[formatter_generic_format]
|
[formatter_generic_format]
|
||||||
format = [%(levelname)s %(asctime)s] [%(name)s]: %(message)s
|
format = [{levelname} {asctime}] [{name}]: {message}
|
||||||
|
style = {
|
||||||
|
|
||||||
[formatter_syslog_format]
|
[formatter_syslog_format]
|
||||||
format = [%(levelname)s] [%(name)s]: %(message)s
|
format = [{levelname}] [{name}]: {message}
|
||||||
|
style = {
|
||||||
|
|
||||||
[logger_root]
|
[logger_root]
|
||||||
level = DEBUG
|
level = DEBUG
|
||||||
@@ -64,3 +66,8 @@ propagate = 0
|
|||||||
level = INFO
|
level = INFO
|
||||||
qualname = s3transfer
|
qualname = s3transfer
|
||||||
propagate = 0
|
propagate = 0
|
||||||
|
|
||||||
|
[logger_sql]
|
||||||
|
level = INFO
|
||||||
|
qualname = sql
|
||||||
|
propagate = 0
|
||||||
+45
-25
@@ -7,6 +7,10 @@
|
|||||||
|
|
||||||
{% include "utils/style.jinja2" %}
|
{% include "utils/style.jinja2" %}
|
||||||
{% include "user-style.jinja2" ignore missing %}
|
{% include "user-style.jinja2" ignore missing %}
|
||||||
|
|
||||||
|
{% if rss_url is not none %}
|
||||||
|
<link rel="alternate" href="{{ rss_url }}" type="application/rss+xml">
|
||||||
|
{% endif %}
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
@@ -49,8 +53,7 @@ SigLevel = Database{% if has_repo_signed %}Required{% else %}Never{% endif %} Pa
|
|||||||
data-show-search-clear-button="true"
|
data-show-search-clear-button="true"
|
||||||
data-sortable="true"
|
data-sortable="true"
|
||||||
data-sort-name="base"
|
data-sort-name="base"
|
||||||
data-sort-order="asc"
|
data-sort-order="asc">
|
||||||
data-toggle="table">
|
|
||||||
<thead class="table-primary">
|
<thead class="table-primary">
|
||||||
<tr>
|
<tr>
|
||||||
<th data-sortable="true" data-switchable="false" data-field="name" data-filter-control="input" data-filter-control-placeholder="(any package)">package</th>
|
<th data-sortable="true" data-switchable="false" data-field="name" data-filter-control="input" data-filter-control-placeholder="(any package)">package</th>
|
||||||
@@ -101,32 +104,13 @@ SigLevel = Database{% if has_repo_signed %}Required{% else %}Never{% endif %} Pa
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const table = $("#packages");
|
const table = $(document.getElementById("packages"));
|
||||||
table.on("created-controls.bs.table", () => {
|
|
||||||
const pickerInput = $(".bootstrap-table-filter-control-timestamp");
|
|
||||||
pickerInput.daterangepicker({
|
|
||||||
autoUpdateInput: false,
|
|
||||||
locale: {
|
|
||||||
cancelLabel: "Clear",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
pickerInput.on("apply.daterangepicker", (event, picker) => {
|
const pacmanConf = document.getElementById("pacman-conf");
|
||||||
pickerInput.val(`${picker.startDate.format("YYYY-MM-DD")} - ${picker.endDate.format("YYYY-MM-DD")}`);
|
const pacmanConfCopyButton = document.getElementById("copy-btn");
|
||||||
table.bootstrapTable("triggerSearch");
|
|
||||||
});
|
|
||||||
|
|
||||||
pickerInput.on("cancel.daterangepicker", () => {
|
|
||||||
pickerInput.val("");
|
|
||||||
table.bootstrapTable("triggerSearch");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const pacmanConf = $("#pacman-conf");
|
|
||||||
const pacmanConfCopyButton = $("#copy-btn");
|
|
||||||
|
|
||||||
async function copyPacmanConf() {
|
async function copyPacmanConf() {
|
||||||
const conf = pacmanConf.text();
|
const conf = pacmanConf.textContent;
|
||||||
await copyToClipboard(conf, pacmanConfCopyButton);
|
await copyToClipboard(conf, pacmanConfCopyButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,6 +125,42 @@ SigLevel = Database{% if has_repo_signed %}Required{% else %}Never{% endif %} Pa
|
|||||||
function filterListLicenses() {
|
function filterListLicenses() {
|
||||||
return extractDataList(table.bootstrapTable("getData"), "licenses");
|
return extractDataList(table.bootstrapTable("getData"), "licenses");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ready(_ => {
|
||||||
|
table.bootstrapTable({
|
||||||
|
onCreatedControls: _ => {
|
||||||
|
new easepick.create({
|
||||||
|
element: document.querySelector(".bootstrap-table-filter-control-timestamp"),
|
||||||
|
css: [
|
||||||
|
"https://cdn.jsdelivr.net/npm/@easepick/bundle@1.2.1/dist/index.css",
|
||||||
|
],
|
||||||
|
grid: 2,
|
||||||
|
calendars: 2,
|
||||||
|
autoApply: false,
|
||||||
|
locale: {
|
||||||
|
cancel: "Clear",
|
||||||
|
},
|
||||||
|
RangePlugin: {
|
||||||
|
tooltip: false,
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
"RangePlugin",
|
||||||
|
],
|
||||||
|
setup: picker => {
|
||||||
|
picker.on("select", _ => { table.bootstrapTable("triggerSearch"); });
|
||||||
|
// replace "Cancel" behaviour to "Clear"
|
||||||
|
picker.onClickCancelButton = element => {
|
||||||
|
if (picker.isCancelButton(element)) {
|
||||||
|
picker.clear();
|
||||||
|
picker.hide();
|
||||||
|
table.bootstrapTable("triggerSearch");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||||
|
<channel>
|
||||||
|
<title>{{ repository }}: Recent package updates</title>
|
||||||
|
{% if homepage is not none %}
|
||||||
|
<link>{{ homepage }}</link>
|
||||||
|
{% endif %}
|
||||||
|
<description>Recently updated packages in the {{ repository }}.</description>
|
||||||
|
{% if rss_url is not none %}
|
||||||
|
<atom:link href="{{ rss_url }}" rel="self"/>
|
||||||
|
{% endif %}
|
||||||
|
<language>en-us</language>
|
||||||
|
<lastBuildDate>{{ last_update }}</lastBuildDate>
|
||||||
|
|
||||||
|
{% for package in packages %}
|
||||||
|
<item>
|
||||||
|
<title>{{ package.name }} {{ package.version }} {{ package.architecture }}</title>
|
||||||
|
<link>{{ link_path }}/{{ package.filename }}</link>
|
||||||
|
<description>{{ package.description }}</description>
|
||||||
|
<pubDate>{{ package.build_date }}</pubDate>
|
||||||
|
<guid isPermaLink="false">{{ package.tag }}</guid>
|
||||||
|
<category>{{ repository }}</category>
|
||||||
|
<category>{{ package.architecture }}</category>
|
||||||
|
</item>
|
||||||
|
{% endfor %}
|
||||||
|
</channel>
|
||||||
|
</rss>
|
||||||
@@ -0,0 +1,248 @@
|
|||||||
|
<script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js" crossorigin="anonymous" type="application/javascript"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/js-md5@0.8.3/src/md5.min.js" crossorigin="anonymous" type="application/javascript"></script>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/tableexport.jquery.plugin@1.33.0/tableExport.min.js" crossorigin="anonymous" type="application/javascript"></script>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/jquery-resizable-columns@0.2.3/dist/jquery.resizableColumns.min.js" crossorigin="anonymous" type="application/javascript"></script>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js" crossorigin="anonymous" type="application/javascript"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.7/dist/js/bootstrap.min.js" crossorigin="anonymous" type="application/javascript"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap-table@1.24.1/dist/bootstrap-table.min.js" crossorigin="anonymous" type="application/javascript"></script>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap-table@1.24.1/dist/extensions/export/bootstrap-table-export.min.js" crossorigin="anonymous" type="application/javascript"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap-table@1.24.1/dist/extensions/resizable/bootstrap-table-resizable.js" crossorigin="anonymous" type="application/javascript"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap-table@1.24.1/dist/extensions/filter-control/bootstrap-table-filter-control.js" crossorigin="anonymous" type="application/javascript"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap-table@1.24.1/dist/extensions/cookie/bootstrap-table-cookie.min.js" crossorigin="anonymous" type="application/javascript"></script>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/@easepick/bundle@1.2.1/dist/index.umd.min.js" crossorigin="anonymous" type="application/javascript"></script>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.11.1/build/highlight.min.js" crossorigin="anonymous" type="application/javascript"></script>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.5.0/dist/chart.umd.min.js" crossorigin="anonymous" type="application/javascript"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
async function copyToClipboard(text, button) {
|
||||||
|
await navigator.clipboard.writeText(text);
|
||||||
|
button.innerHTML = "<i class=\"bi bi-clipboard-check\"></i> copied";
|
||||||
|
setTimeout(_ => {
|
||||||
|
button.innerHTML = "<i class=\"bi bi-clipboard\"></i> copy";
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractDataList(data, column) {
|
||||||
|
const elements = data.flatMap(row => row[column].split("<br>")).filter(v => v); // remove empty elements from array
|
||||||
|
return Array.from(new Set(elements)).sort();
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractListProperties(description, property) {
|
||||||
|
return Object.values(description.packages)
|
||||||
|
.map(pkg => pkg[property])
|
||||||
|
.reduce((left, right) => left.concat(right), []);
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterContains(text, value) {
|
||||||
|
return value.includes(text.toLowerCase().trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterDateRange(text, value) {
|
||||||
|
const asOfStartOfDay = date => date.setUTCHours(0, 0, 0, 0);
|
||||||
|
|
||||||
|
const [minDate, maxDate] = text.split(" - ");
|
||||||
|
const buildDate = asOfStartOfDay(new Date(value));
|
||||||
|
|
||||||
|
return (buildDate >= new Date(minDate)) && (buildDate <= new Date(maxDate));
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterList(index, value, field, data) {
|
||||||
|
const dataList = extractDataList(data, field);
|
||||||
|
// the library removes all symbols from string, so it is just string
|
||||||
|
return value.includes(dataList[index].toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasActiveSelection() {
|
||||||
|
return !document.getSelection().isCollapsed; // not sure if it is a valid way, but I guess so
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasActiveDropdown() {
|
||||||
|
return Array.from(document.querySelectorAll(".dropdown-menu"))
|
||||||
|
.some(el => el.classList.contains("show"));
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasActiveModal() {
|
||||||
|
return Array.from(document.querySelectorAll(".modal"))
|
||||||
|
.some(el => el.classList.contains("show"));
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
return Array.from(new Set(data))
|
||||||
|
.sort()
|
||||||
|
.map(entry => safe(entry))
|
||||||
|
.join("<br>");
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeRequest(url, params, onSuccess, onFailure) {
|
||||||
|
const requestParams = {
|
||||||
|
method: params.method,
|
||||||
|
body: params.json ? JSON.stringify(params.json) : params.json,
|
||||||
|
headers: {
|
||||||
|
"Accept": "application/json",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
if (params.query) {
|
||||||
|
const query = new URLSearchParams(params.query);
|
||||||
|
url += `?${query.toString()}`;
|
||||||
|
}
|
||||||
|
const convert = params.convert ?? (response => response.text());
|
||||||
|
|
||||||
|
return fetch(url, requestParams)
|
||||||
|
.then(response => {
|
||||||
|
if (response.ok) {
|
||||||
|
return convert(response);
|
||||||
|
} else {
|
||||||
|
const error = new Error("Network request error");
|
||||||
|
error.status = response.status;
|
||||||
|
error.statusText = response.statusText;
|
||||||
|
return response.text().then(text => {
|
||||||
|
error.text = text;
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(data => onSuccess && onSuccess(data))
|
||||||
|
.catch(error => onFailure && onFailure(error));
|
||||||
|
}
|
||||||
|
|
||||||
|
function readOptional(extractor, callback) {
|
||||||
|
for (let value = extractor(); !!value; value = null) {
|
||||||
|
callback(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ready(fn) {
|
||||||
|
if (document.readyState === "complete" || document.readyState === "interactive") {
|
||||||
|
setTimeout(fn, 1);
|
||||||
|
} else {
|
||||||
|
document.addEventListener("DOMContentLoaded", fn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function restoreAutoReloadSettings(toggle, intervalSelector) {
|
||||||
|
readOptional(() => localStorage.getItem(`ahriman-${toggle.id}-refresh-enabled`), value => toggle.checked = value === "true");
|
||||||
|
readOptional(() => localStorage.getItem(`ahriman-${toggle.id}-refresh-interval`), value => toggleActiveElement(intervalSelector, "interval", value));
|
||||||
|
}
|
||||||
|
|
||||||
|
function safe(string) {
|
||||||
|
return String(string)
|
||||||
|
.replace(/&/g, "&")
|
||||||
|
.replace(/</g, "<")
|
||||||
|
.replace(/>/g, ">")
|
||||||
|
.replace(/"/g, """);
|
||||||
|
}
|
||||||
|
|
||||||
|
// because I'm tired of safe element generation
|
||||||
|
function safeLink(url, text, title) {
|
||||||
|
const element = document.createElement("a");
|
||||||
|
element.href = url;
|
||||||
|
element.innerText = text;
|
||||||
|
if (title) {
|
||||||
|
element.title = title;
|
||||||
|
}
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleActiveElement(selector, dataType, value) {
|
||||||
|
const targetElement = selector.querySelector(`a[data-${dataType}="${value}"]`);
|
||||||
|
if (targetElement?.classList?.contains("active")) {
|
||||||
|
return; // element is already active, skip processing
|
||||||
|
}
|
||||||
|
|
||||||
|
Array.from(selector.children).forEach(il => {
|
||||||
|
Array.from(il.children).forEach(el => el.classList.remove("active"));
|
||||||
|
});
|
||||||
|
targetElement?.classList?.add("active");
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleAutoReload(toggle, interval, intervalSelector, callback) {
|
||||||
|
if (interval) {
|
||||||
|
toggle.checked = true; // toggle reload
|
||||||
|
} else {
|
||||||
|
interval = intervalSelector.querySelector(".active")?.dataset?.interval; // find active element
|
||||||
|
}
|
||||||
|
|
||||||
|
let intervalId = null;
|
||||||
|
if (interval) {
|
||||||
|
if (toggle.checked) {
|
||||||
|
// refresh UI
|
||||||
|
toggleActiveElement(intervalSelector, "interval", interval);
|
||||||
|
// finally create timer task
|
||||||
|
intervalId = setInterval(callback, interval);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
toggle.checked = false; // no active interval found, disable toggle
|
||||||
|
}
|
||||||
|
|
||||||
|
localStorage.setItem(`ahriman-${toggle.id}-refresh-enabled`, toggle.checked);
|
||||||
|
localStorage.setItem(`ahriman-${toggle.id}-refresh-interval`, interval);
|
||||||
|
return intervalId;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateTable(table, rows, rowChangedKey) {
|
||||||
|
// instead of using load method here, we just update rows manually to avoid table reinitialization
|
||||||
|
const currentData = table.bootstrapTable("getData").reduce((accumulator, row) => {
|
||||||
|
accumulator[row.id] = {state: row["0"], key: rowChangedKey(row)};
|
||||||
|
return accumulator;
|
||||||
|
}, {});
|
||||||
|
// insert or update rows, skipping ones whose status hasn't changed
|
||||||
|
rows.forEach(row => {
|
||||||
|
if (Object.hasOwn(currentData, row.id)) {
|
||||||
|
if (rowChangedKey(row) === currentData[row.id].key) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
row["0"] = currentData[row.id].state; // copy checkbox state
|
||||||
|
table.bootstrapTable("updateByUniqueId", {
|
||||||
|
id: row.id,
|
||||||
|
row: row,
|
||||||
|
replace: true,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
table.bootstrapTable("insertRow", {index: 0, row: row});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// remove old rows
|
||||||
|
const newData = rows.map(value => value.id);
|
||||||
|
Object.keys(currentData).forEach(id => {
|
||||||
|
if (!newData.includes(id)) {
|
||||||
|
table.bootstrapTable("removeByUniqueId", id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Array.prototype.equals = function (right, comparator) {
|
||||||
|
let index = this.length;
|
||||||
|
if (index !== right.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (index--) {
|
||||||
|
if (!comparator(this[index], right[index])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Date.prototype.toISOStringShort = function () {
|
||||||
|
const pad = number => String(number).padStart(2, "0");
|
||||||
|
return `${this.getFullYear()}-${pad(this.getMonth() + 1)}-${pad(this.getDate())} ${pad(this.getHours())}:${pad(this.getMinutes())}:${pad(this.getSeconds())}`;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.7/dist/css/bootstrap.min.css" crossorigin="anonymous" type="text/css">
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.13.1/font/bootstrap-icons.css" crossorigin="anonymous" type="text/css">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-table@1.24.1/dist/bootstrap-table.min.css" crossorigin="anonymous" type="text/css">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jquery-resizable-columns@0.2.3/dist/jquery.resizableColumns.css" crossorigin="anonymous" type="text/css">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-table@1.24.1/dist/extensions/filter-control/bootstrap-table-filter-control.css" crossorigin="anonymous" type="text/css">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootswatch@5.3.7/dist/cosmo/bootstrap.min.css" crossorigin="anonymous" type="text/css">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.11.1/build/styles/github.min.css" crossorigin="anonymous" type="text/css">
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.pre-scrollable {
|
||||||
|
display: block;
|
||||||
|
max-height: 680px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre[class*="language-"] {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre[class*="language-"] button {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 5px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
+408
-357
@@ -1,112 +1,118 @@
|
|||||||
# 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-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' 'web-reload')
|
||||||
|
|
||||||
_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_package_add_option_strings=('-h' '--help' '--dependencies' '--no-dependencies' '-e' '--exit-code' '--increment' '--no-increment' '-n' '--now' '-y' '--refresh' '-s' '--source' '-u' '--username' '-v' '--variable')
|
_shtab_ahriman_key_import_option_strings=('-h' '--help' '--key-server')
|
||||||
_shtab_ahriman_add_option_strings=('-h' '--help' '--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_package_update_option_strings=('-h' '--help' '--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' '-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' '-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' '--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' '--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_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' '--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' '--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_web_reload_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-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' 'web-reload')
|
||||||
_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___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')
|
||||||
@@ -123,49 +129,11 @@ _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___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
|
||||||
|
_shtab_ahriman_add___changes_nargs=0
|
||||||
|
_shtab_ahriman_add___no_changes_nargs=0
|
||||||
_shtab_ahriman_add___dependencies_nargs=0
|
_shtab_ahriman_add___dependencies_nargs=0
|
||||||
_shtab_ahriman_add___no_dependencies_nargs=0
|
_shtab_ahriman_add___no_dependencies_nargs=0
|
||||||
_shtab_ahriman_add__e_nargs=0
|
_shtab_ahriman_add__e_nargs=0
|
||||||
@@ -176,121 +144,62 @@ _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_package_update_pos_0_nargs=+
|
_shtab_ahriman_aur_search_pos_0_nargs=+
|
||||||
_shtab_ahriman_package_update__h_nargs=0
|
_shtab_ahriman_aur_search__h_nargs=0
|
||||||
_shtab_ahriman_package_update___help_nargs=0
|
_shtab_ahriman_aur_search___help_nargs=0
|
||||||
_shtab_ahriman_package_update___dependencies_nargs=0
|
_shtab_ahriman_aur_search__e_nargs=0
|
||||||
_shtab_ahriman_package_update___no_dependencies_nargs=0
|
_shtab_ahriman_aur_search___exit_code_nargs=0
|
||||||
_shtab_ahriman_package_update__e_nargs=0
|
_shtab_ahriman_aur_search___info_nargs=0
|
||||||
_shtab_ahriman_package_update___exit_code_nargs=0
|
_shtab_ahriman_aur_search___no_info_nargs=0
|
||||||
_shtab_ahriman_package_update___increment_nargs=0
|
|
||||||
_shtab_ahriman_package_update___no_increment_nargs=0
|
|
||||||
_shtab_ahriman_package_update__n_nargs=0
|
|
||||||
_shtab_ahriman_package_update___now_nargs=0
|
|
||||||
_shtab_ahriman_package_update__y_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___help_nargs=0
|
|
||||||
_shtab_ahriman_patch_list__h_nargs=0
|
|
||||||
_shtab_ahriman_patch_list___help_nargs=0
|
|
||||||
_shtab_ahriman_patch_list__e_nargs=0
|
|
||||||
_shtab_ahriman_patch_list___exit_code_nargs=0
|
|
||||||
_shtab_ahriman_patch_remove__h_nargs=0
|
|
||||||
_shtab_ahriman_patch_remove___help_nargs=0
|
|
||||||
_shtab_ahriman_patch_set_add__h_nargs=0
|
|
||||||
_shtab_ahriman_patch_set_add___help_nargs=0
|
|
||||||
_shtab_ahriman_repo_backup__h_nargs=0
|
|
||||||
_shtab_ahriman_repo_backup___help_nargs=0
|
|
||||||
_shtab_ahriman_repo_check_pos_0_nargs=*
|
|
||||||
_shtab_ahriman_repo_check__h_nargs=0
|
|
||||||
_shtab_ahriman_repo_check___help_nargs=0
|
|
||||||
_shtab_ahriman_repo_check___changes_nargs=0
|
|
||||||
_shtab_ahriman_repo_check___no_changes_nargs=0
|
|
||||||
_shtab_ahriman_repo_check__e_nargs=0
|
|
||||||
_shtab_ahriman_repo_check___exit_code_nargs=0
|
|
||||||
_shtab_ahriman_repo_check___vcs_nargs=0
|
|
||||||
_shtab_ahriman_repo_check___no_vcs_nargs=0
|
|
||||||
_shtab_ahriman_repo_check__y_nargs=0
|
|
||||||
_shtab_ahriman_repo_check___refresh_nargs=0
|
|
||||||
_shtab_ahriman_check_pos_0_nargs=*
|
_shtab_ahriman_check_pos_0_nargs=*
|
||||||
_shtab_ahriman_check__h_nargs=0
|
_shtab_ahriman_check__h_nargs=0
|
||||||
_shtab_ahriman_check___help_nargs=0
|
_shtab_ahriman_check___help_nargs=0
|
||||||
_shtab_ahriman_check___changes_nargs=0
|
_shtab_ahriman_check___changes_nargs=0
|
||||||
_shtab_ahriman_check___no_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__e_nargs=0
|
||||||
_shtab_ahriman_check___exit_code_nargs=0
|
_shtab_ahriman_check___exit_code_nargs=0
|
||||||
_shtab_ahriman_check___vcs_nargs=0
|
_shtab_ahriman_check___vcs_nargs=0
|
||||||
_shtab_ahriman_check___no_vcs_nargs=0
|
_shtab_ahriman_check___no_vcs_nargs=0
|
||||||
_shtab_ahriman_check__y_nargs=0
|
_shtab_ahriman_check__y_nargs=0
|
||||||
_shtab_ahriman_check___refresh_nargs=0
|
_shtab_ahriman_check___refresh_nargs=0
|
||||||
_shtab_ahriman_repo_create_keyring__h_nargs=0
|
_shtab_ahriman_clean__h_nargs=0
|
||||||
_shtab_ahriman_repo_create_keyring___help_nargs=0
|
_shtab_ahriman_clean___help_nargs=0
|
||||||
_shtab_ahriman_repo_create_mirrorlist__h_nargs=0
|
_shtab_ahriman_clean___cache_nargs=0
|
||||||
_shtab_ahriman_repo_create_mirrorlist___help_nargs=0
|
_shtab_ahriman_clean___no_cache_nargs=0
|
||||||
_shtab_ahriman_repo_daemon__h_nargs=0
|
_shtab_ahriman_clean___chroot_nargs=0
|
||||||
_shtab_ahriman_repo_daemon___help_nargs=0
|
_shtab_ahriman_clean___no_chroot_nargs=0
|
||||||
_shtab_ahriman_repo_daemon___aur_nargs=0
|
_shtab_ahriman_clean___manual_nargs=0
|
||||||
_shtab_ahriman_repo_daemon___no_aur_nargs=0
|
_shtab_ahriman_clean___no_manual_nargs=0
|
||||||
_shtab_ahriman_repo_daemon___changes_nargs=0
|
_shtab_ahriman_clean___packages_nargs=0
|
||||||
_shtab_ahriman_repo_daemon___no_changes_nargs=0
|
_shtab_ahriman_clean___no_packages_nargs=0
|
||||||
_shtab_ahriman_repo_daemon___dependencies_nargs=0
|
_shtab_ahriman_clean___pacman_nargs=0
|
||||||
_shtab_ahriman_repo_daemon___no_dependencies_nargs=0
|
_shtab_ahriman_clean___no_pacman_nargs=0
|
||||||
_shtab_ahriman_repo_daemon___dry_run_nargs=0
|
_shtab_ahriman_config__h_nargs=0
|
||||||
_shtab_ahriman_repo_daemon___increment_nargs=0
|
_shtab_ahriman_config___help_nargs=0
|
||||||
_shtab_ahriman_repo_daemon___no_increment_nargs=0
|
_shtab_ahriman_config___info_nargs=0
|
||||||
_shtab_ahriman_repo_daemon___local_nargs=0
|
_shtab_ahriman_config___no_info_nargs=0
|
||||||
_shtab_ahriman_repo_daemon___no_local_nargs=0
|
_shtab_ahriman_config___secure_nargs=0
|
||||||
_shtab_ahriman_repo_daemon___manual_nargs=0
|
_shtab_ahriman_config___no_secure_nargs=0
|
||||||
_shtab_ahriman_repo_daemon___no_manual_nargs=0
|
_shtab_ahriman_config_validate__h_nargs=0
|
||||||
_shtab_ahriman_repo_daemon___partitions_nargs=0
|
_shtab_ahriman_config_validate___help_nargs=0
|
||||||
_shtab_ahriman_repo_daemon___no_partitions_nargs=0
|
_shtab_ahriman_config_validate__e_nargs=0
|
||||||
_shtab_ahriman_repo_daemon___vcs_nargs=0
|
_shtab_ahriman_config_validate___exit_code_nargs=0
|
||||||
_shtab_ahriman_repo_daemon___no_vcs_nargs=0
|
_shtab_ahriman_copy_pos_1_nargs=+
|
||||||
_shtab_ahriman_repo_daemon__y_nargs=0
|
_shtab_ahriman_copy__h_nargs=0
|
||||||
_shtab_ahriman_repo_daemon___refresh_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__h_nargs=0
|
||||||
_shtab_ahriman_daemon___help_nargs=0
|
_shtab_ahriman_daemon___help_nargs=0
|
||||||
_shtab_ahriman_daemon___aur_nargs=0
|
_shtab_ahriman_daemon___aur_nargs=0
|
||||||
_shtab_ahriman_daemon___no_aur_nargs=0
|
_shtab_ahriman_daemon___no_aur_nargs=0
|
||||||
_shtab_ahriman_daemon___changes_nargs=0
|
_shtab_ahriman_daemon___changes_nargs=0
|
||||||
_shtab_ahriman_daemon___no_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___dependencies_nargs=0
|
||||||
_shtab_ahriman_daemon___no_dependencies_nargs=0
|
_shtab_ahriman_daemon___no_dependencies_nargs=0
|
||||||
_shtab_ahriman_daemon___dry_run_nargs=0
|
_shtab_ahriman_daemon___dry_run_nargs=0
|
||||||
@@ -306,14 +215,96 @@ _shtab_ahriman_daemon___vcs_nargs=0
|
|||||||
_shtab_ahriman_daemon___no_vcs_nargs=0
|
_shtab_ahriman_daemon___no_vcs_nargs=0
|
||||||
_shtab_ahriman_daemon__y_nargs=0
|
_shtab_ahriman_daemon__y_nargs=0
|
||||||
_shtab_ahriman_daemon___refresh_nargs=0
|
_shtab_ahriman_daemon___refresh_nargs=0
|
||||||
_shtab_ahriman_repo_rebuild__h_nargs=0
|
_shtab_ahriman_help__h_nargs=0
|
||||||
_shtab_ahriman_repo_rebuild___help_nargs=0
|
_shtab_ahriman_help___help_nargs=0
|
||||||
_shtab_ahriman_repo_rebuild___dry_run_nargs=0
|
_shtab_ahriman_help_commands_unsafe_pos_0_nargs=*
|
||||||
_shtab_ahriman_repo_rebuild___from_database_nargs=0
|
_shtab_ahriman_help_commands_unsafe__h_nargs=0
|
||||||
_shtab_ahriman_repo_rebuild___increment_nargs=0
|
_shtab_ahriman_help_commands_unsafe___help_nargs=0
|
||||||
_shtab_ahriman_repo_rebuild___no_increment_nargs=0
|
_shtab_ahriman_help_updates__h_nargs=0
|
||||||
_shtab_ahriman_repo_rebuild__e_nargs=0
|
_shtab_ahriman_help_updates___help_nargs=0
|
||||||
_shtab_ahriman_repo_rebuild___exit_code_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__h_nargs=0
|
||||||
|
_shtab_ahriman_package_update___help_nargs=0
|
||||||
|
_shtab_ahriman_package_update___changes_nargs=0
|
||||||
|
_shtab_ahriman_package_update___no_changes_nargs=0
|
||||||
|
_shtab_ahriman_package_update___dependencies_nargs=0
|
||||||
|
_shtab_ahriman_package_update___no_dependencies_nargs=0
|
||||||
|
_shtab_ahriman_package_update__e_nargs=0
|
||||||
|
_shtab_ahriman_package_update___exit_code_nargs=0
|
||||||
|
_shtab_ahriman_package_update___increment_nargs=0
|
||||||
|
_shtab_ahriman_package_update___no_increment_nargs=0
|
||||||
|
_shtab_ahriman_package_update__n_nargs=0
|
||||||
|
_shtab_ahriman_package_update___now_nargs=0
|
||||||
|
_shtab_ahriman_package_update__y_nargs=0
|
||||||
|
_shtab_ahriman_package_update___refresh_nargs=0
|
||||||
|
_shtab_ahriman_patch_add__h_nargs=0
|
||||||
|
_shtab_ahriman_patch_add___help_nargs=0
|
||||||
|
_shtab_ahriman_patch_list__h_nargs=0
|
||||||
|
_shtab_ahriman_patch_list___help_nargs=0
|
||||||
|
_shtab_ahriman_patch_list__e_nargs=0
|
||||||
|
_shtab_ahriman_patch_list___exit_code_nargs=0
|
||||||
|
_shtab_ahriman_patch_remove__h_nargs=0
|
||||||
|
_shtab_ahriman_patch_remove___help_nargs=0
|
||||||
|
_shtab_ahriman_patch_set_add__h_nargs=0
|
||||||
|
_shtab_ahriman_patch_set_add___help_nargs=0
|
||||||
_shtab_ahriman_rebuild__h_nargs=0
|
_shtab_ahriman_rebuild__h_nargs=0
|
||||||
_shtab_ahriman_rebuild___help_nargs=0
|
_shtab_ahriman_rebuild___help_nargs=0
|
||||||
_shtab_ahriman_rebuild___dry_run_nargs=0
|
_shtab_ahriman_rebuild___dry_run_nargs=0
|
||||||
@@ -322,30 +313,116 @@ _shtab_ahriman_rebuild___increment_nargs=0
|
|||||||
_shtab_ahriman_rebuild___no_increment_nargs=0
|
_shtab_ahriman_rebuild___no_increment_nargs=0
|
||||||
_shtab_ahriman_rebuild__e_nargs=0
|
_shtab_ahriman_rebuild__e_nargs=0
|
||||||
_shtab_ahriman_rebuild___exit_code_nargs=0
|
_shtab_ahriman_rebuild___exit_code_nargs=0
|
||||||
_shtab_ahriman_repo_remove_unknown__h_nargs=0
|
_shtab_ahriman_remove_pos_0_nargs=+
|
||||||
_shtab_ahriman_repo_remove_unknown___help_nargs=0
|
_shtab_ahriman_remove__h_nargs=0
|
||||||
_shtab_ahriman_repo_remove_unknown___dry_run_nargs=0
|
_shtab_ahriman_remove___help_nargs=0
|
||||||
_shtab_ahriman_remove_unknown__h_nargs=0
|
_shtab_ahriman_remove_unknown__h_nargs=0
|
||||||
_shtab_ahriman_remove_unknown___help_nargs=0
|
_shtab_ahriman_remove_unknown___help_nargs=0
|
||||||
_shtab_ahriman_remove_unknown___dry_run_nargs=0
|
_shtab_ahriman_remove_unknown___dry_run_nargs=0
|
||||||
|
_shtab_ahriman_repo_backup__h_nargs=0
|
||||||
|
_shtab_ahriman_repo_backup___help_nargs=0
|
||||||
|
_shtab_ahriman_repo_check_pos_0_nargs=*
|
||||||
|
_shtab_ahriman_repo_check__h_nargs=0
|
||||||
|
_shtab_ahriman_repo_check___help_nargs=0
|
||||||
|
_shtab_ahriman_repo_check___changes_nargs=0
|
||||||
|
_shtab_ahriman_repo_check___no_changes_nargs=0
|
||||||
|
_shtab_ahriman_repo_check___check_files_nargs=0
|
||||||
|
_shtab_ahriman_repo_check___no_check_files_nargs=0
|
||||||
|
_shtab_ahriman_repo_check__e_nargs=0
|
||||||
|
_shtab_ahriman_repo_check___exit_code_nargs=0
|
||||||
|
_shtab_ahriman_repo_check___vcs_nargs=0
|
||||||
|
_shtab_ahriman_repo_check___no_vcs_nargs=0
|
||||||
|
_shtab_ahriman_repo_check__y_nargs=0
|
||||||
|
_shtab_ahriman_repo_check___refresh_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_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___help_nargs=0
|
||||||
|
_shtab_ahriman_repo_create_mirrorlist__h_nargs=0
|
||||||
|
_shtab_ahriman_repo_create_mirrorlist___help_nargs=0
|
||||||
|
_shtab_ahriman_repo_daemon__h_nargs=0
|
||||||
|
_shtab_ahriman_repo_daemon___help_nargs=0
|
||||||
|
_shtab_ahriman_repo_daemon___aur_nargs=0
|
||||||
|
_shtab_ahriman_repo_daemon___no_aur_nargs=0
|
||||||
|
_shtab_ahriman_repo_daemon___changes_nargs=0
|
||||||
|
_shtab_ahriman_repo_daemon___no_changes_nargs=0
|
||||||
|
_shtab_ahriman_repo_daemon___check_files_nargs=0
|
||||||
|
_shtab_ahriman_repo_daemon___no_check_files_nargs=0
|
||||||
|
_shtab_ahriman_repo_daemon___dependencies_nargs=0
|
||||||
|
_shtab_ahriman_repo_daemon___no_dependencies_nargs=0
|
||||||
|
_shtab_ahriman_repo_daemon___dry_run_nargs=0
|
||||||
|
_shtab_ahriman_repo_daemon___increment_nargs=0
|
||||||
|
_shtab_ahriman_repo_daemon___no_increment_nargs=0
|
||||||
|
_shtab_ahriman_repo_daemon___local_nargs=0
|
||||||
|
_shtab_ahriman_repo_daemon___no_local_nargs=0
|
||||||
|
_shtab_ahriman_repo_daemon___manual_nargs=0
|
||||||
|
_shtab_ahriman_repo_daemon___no_manual_nargs=0
|
||||||
|
_shtab_ahriman_repo_daemon___partitions_nargs=0
|
||||||
|
_shtab_ahriman_repo_daemon___no_partitions_nargs=0
|
||||||
|
_shtab_ahriman_repo_daemon___vcs_nargs=0
|
||||||
|
_shtab_ahriman_repo_daemon___no_vcs_nargs=0
|
||||||
|
_shtab_ahriman_repo_daemon__y_nargs=0
|
||||||
|
_shtab_ahriman_repo_daemon___refresh_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_rebuild__h_nargs=0
|
||||||
|
_shtab_ahriman_repo_rebuild___help_nargs=0
|
||||||
|
_shtab_ahriman_repo_rebuild___dry_run_nargs=0
|
||||||
|
_shtab_ahriman_repo_rebuild___from_database_nargs=0
|
||||||
|
_shtab_ahriman_repo_rebuild___increment_nargs=0
|
||||||
|
_shtab_ahriman_repo_rebuild___no_increment_nargs=0
|
||||||
|
_shtab_ahriman_repo_rebuild__e_nargs=0
|
||||||
|
_shtab_ahriman_repo_rebuild___exit_code_nargs=0
|
||||||
|
_shtab_ahriman_repo_remove_unknown__h_nargs=0
|
||||||
|
_shtab_ahriman_repo_remove_unknown___help_nargs=0
|
||||||
|
_shtab_ahriman_repo_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_repo_statistics__h_nargs=0
|
||||||
_shtab_ahriman_sign__h_nargs=0
|
_shtab_ahriman_repo_statistics___help_nargs=0
|
||||||
_shtab_ahriman_sign___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=*
|
||||||
@@ -358,6 +435,8 @@ _shtab_ahriman_repo_update___aur_nargs=0
|
|||||||
_shtab_ahriman_repo_update___no_aur_nargs=0
|
_shtab_ahriman_repo_update___no_aur_nargs=0
|
||||||
_shtab_ahriman_repo_update___changes_nargs=0
|
_shtab_ahriman_repo_update___changes_nargs=0
|
||||||
_shtab_ahriman_repo_update___no_changes_nargs=0
|
_shtab_ahriman_repo_update___no_changes_nargs=0
|
||||||
|
_shtab_ahriman_repo_update___check_files_nargs=0
|
||||||
|
_shtab_ahriman_repo_update___no_check_files_nargs=0
|
||||||
_shtab_ahriman_repo_update___dependencies_nargs=0
|
_shtab_ahriman_repo_update___dependencies_nargs=0
|
||||||
_shtab_ahriman_repo_update___no_dependencies_nargs=0
|
_shtab_ahriman_repo_update___no_dependencies_nargs=0
|
||||||
_shtab_ahriman_repo_update___dry_run_nargs=0
|
_shtab_ahriman_repo_update___dry_run_nargs=0
|
||||||
@@ -373,6 +452,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
|
||||||
@@ -380,6 +544,8 @@ _shtab_ahriman_update___aur_nargs=0
|
|||||||
_shtab_ahriman_update___no_aur_nargs=0
|
_shtab_ahriman_update___no_aur_nargs=0
|
||||||
_shtab_ahriman_update___changes_nargs=0
|
_shtab_ahriman_update___changes_nargs=0
|
||||||
_shtab_ahriman_update___no_changes_nargs=0
|
_shtab_ahriman_update___no_changes_nargs=0
|
||||||
|
_shtab_ahriman_update___check_files_nargs=0
|
||||||
|
_shtab_ahriman_update___no_check_files_nargs=0
|
||||||
_shtab_ahriman_update___dependencies_nargs=0
|
_shtab_ahriman_update___dependencies_nargs=0
|
||||||
_shtab_ahriman_update___no_dependencies_nargs=0
|
_shtab_ahriman_update___no_dependencies_nargs=0
|
||||||
_shtab_ahriman_update___dry_run_nargs=0
|
_shtab_ahriman_update___dry_run_nargs=0
|
||||||
@@ -395,136 +561,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
|
||||||
@@ -533,8 +569,12 @@ _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
|
||||||
|
_shtab_ahriman_web_reload__h_nargs=0
|
||||||
|
_shtab_ahriman_web_reload___help_nargs=0
|
||||||
|
|
||||||
|
|
||||||
# $1=COMP_WORDS[1]
|
# $1=COMP_WORDS[1]
|
||||||
@@ -584,7 +624,7 @@ _set_new_action() {
|
|||||||
current_action_nargs=1
|
current_action_nargs=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
current_action_args_start_index=$(( $word_index + 1 ))
|
current_action_args_start_index=$(( $word_index + 1 - $pos_only ))
|
||||||
|
|
||||||
current_action_is_positional=$2
|
current_action_is_positional=$2
|
||||||
}
|
}
|
||||||
@@ -598,6 +638,7 @@ _set_new_action() {
|
|||||||
# ${!x} -> ${hello} -> "world"
|
# ${!x} -> ${hello} -> "world"
|
||||||
_shtab_ahriman() {
|
_shtab_ahriman() {
|
||||||
local completing_word="${COMP_WORDS[COMP_CWORD]}"
|
local completing_word="${COMP_WORDS[COMP_CWORD]}"
|
||||||
|
local previous_word="${COMP_WORDS[COMP_CWORD-1]}"
|
||||||
local completed_positional_actions
|
local completed_positional_actions
|
||||||
local current_action
|
local current_action
|
||||||
local current_action_args_start_index
|
local current_action_args_start_index
|
||||||
@@ -611,6 +652,7 @@ _shtab_ahriman() {
|
|||||||
|
|
||||||
local prefix=_shtab_ahriman
|
local prefix=_shtab_ahriman
|
||||||
local word_index=0
|
local word_index=0
|
||||||
|
local pos_only=0 # "--" delimeter not encountered yet
|
||||||
_set_parser_defaults
|
_set_parser_defaults
|
||||||
word_index=1
|
word_index=1
|
||||||
|
|
||||||
@@ -619,26 +661,31 @@ _shtab_ahriman() {
|
|||||||
while [ $word_index -ne $COMP_CWORD ]; do
|
while [ $word_index -ne $COMP_CWORD ]; do
|
||||||
local this_word="${COMP_WORDS[$word_index]}"
|
local this_word="${COMP_WORDS[$word_index]}"
|
||||||
|
|
||||||
if [[ -n $sub_parsers && " ${sub_parsers[@]} " == *" ${this_word} "* ]]; then
|
if [[ $pos_only = 1 || " $this_word " != " -- " ]]; then
|
||||||
# valid subcommand: add it to the prefix & reset the current action
|
if [[ -n $sub_parsers && " ${sub_parsers[@]} " == *" ${this_word} "* ]]; then
|
||||||
prefix="${prefix}_$(_shtab_replace_nonword $this_word)"
|
# valid subcommand: add it to the prefix & reset the current action
|
||||||
_set_parser_defaults
|
prefix="${prefix}_$(_shtab_replace_nonword $this_word)"
|
||||||
fi
|
_set_parser_defaults
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ " ${current_option_strings[@]} " == *" ${this_word} "* ]]; then
|
if [[ " ${current_option_strings[@]} " == *" ${this_word} "* ]]; then
|
||||||
# a new action should be acquired (due to recognised option string or
|
# a new action should be acquired (due to recognised option string or
|
||||||
# no more input expected from current action);
|
# no more input expected from current action);
|
||||||
# the next positional action can fill in here
|
# the next positional action can fill in here
|
||||||
_set_new_action $this_word false
|
_set_new_action $this_word false
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$current_action_nargs" != "*" ]] && \
|
if [[ "$current_action_nargs" != "*" ]] && \
|
||||||
[[ "$current_action_nargs" != "+" ]] && \
|
[[ "$current_action_nargs" != "+" ]] && \
|
||||||
[[ "$current_action_nargs" != *"..." ]] && \
|
[[ "$current_action_nargs" != "?" ]] && \
|
||||||
(( $word_index + 1 - $current_action_args_start_index >= \
|
[[ "$current_action_nargs" != *"..." ]] && \
|
||||||
$current_action_nargs )); then
|
(( $word_index + 1 - $current_action_args_start_index - $pos_only >= \
|
||||||
$current_action_is_positional && let "completed_positional_actions += 1"
|
$current_action_nargs )); then
|
||||||
_set_new_action "pos_${completed_positional_actions}" true
|
$current_action_is_positional && let "completed_positional_actions += 1"
|
||||||
|
_set_new_action "pos_${completed_positional_actions}" true
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
pos_only=1 # "--" delimeter encountered
|
||||||
fi
|
fi
|
||||||
|
|
||||||
let "word_index+=1"
|
let "word_index+=1"
|
||||||
@@ -646,9 +693,13 @@ _shtab_ahriman() {
|
|||||||
|
|
||||||
# Generate the completions
|
# Generate the completions
|
||||||
|
|
||||||
if [[ "${completing_word}" == -* ]]; then
|
if [[ $pos_only = 0 && "${completing_word}" == -* ]]; then
|
||||||
# optional argument started: use option strings
|
# optional argument started: use option strings
|
||||||
COMPREPLY=( $(compgen -W "${current_option_strings[*]}" -- "${completing_word}") )
|
COMPREPLY=( $(compgen -W "${current_option_strings[*]}" -- "${completing_word}") )
|
||||||
|
elif [[ "${previous_word}" == ">" || "${previous_word}" == ">>" ||
|
||||||
|
"${previous_word}" =~ ^[12]">" || "${previous_word}" =~ ^[12]">>" ]]; then
|
||||||
|
# handle redirection operators
|
||||||
|
COMPREPLY=( $(compgen -f -- "${completing_word}") )
|
||||||
else
|
else
|
||||||
# use choices & compgen
|
# use choices & compgen
|
||||||
local IFS=$'\n' # items may contain spaces, so delimit using newline
|
local IFS=$'\n' # items may contain spaces, so delimit using newline
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
.TH AHRIMAN "1" "2024\-02\-09" "ahriman" "Generated Python Manual"
|
.TH AHRIMAN "1" "2026\-03\-08" "ahriman 2.20.0" "ArcH linux ReposItory MANager"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
ahriman
|
ahriman \- ArcH linux ReposItory MANager
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.B ahriman
|
.B [0m[1;35mahriman[0m
|
||||||
[-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-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} ...
|
[[32m-h[0m] [[32m-a [33mARCHITECTURE[0m] [[32m-c [33mCONFIGURATION[0m] [[36m--force[0m] [[32m-l [33mLOCK[0m] [[36m--log-handler [33m{console,syslog,journald}[0m] [[32m-q[0m] [[36m--report | --no-report[0m] [[32m-r [33mREPOSITORY[0m] [[36m--unsafe[0m] [[32m-V[0m] [[36m--wait-timeout [33mWAIT_TIMEOUT[0m] [32m{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,web-reload} ...[0m
|
||||||
.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
|
||||||
@@ -134,6 +137,9 @@ restore repository data
|
|||||||
\fBahriman\fR \fI\,repo\-sign\/\fR
|
\fBahriman\fR \fI\,repo\-sign\/\fR
|
||||||
sign packages
|
sign packages
|
||||||
.TP
|
.TP
|
||||||
|
\fBahriman\fR \fI\,repo\-statistics\/\fR
|
||||||
|
repository statistics
|
||||||
|
.TP
|
||||||
\fBahriman\fR \fI\,repo\-status\-update\/\fR
|
\fBahriman\fR \fI\,repo\-status\-update\/\fR
|
||||||
update repository status
|
update repository status
|
||||||
.TP
|
.TP
|
||||||
@@ -187,11 +193,14 @@ remove user
|
|||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,web\/\fR
|
\fBahriman\fR \fI\,web\/\fR
|
||||||
web server
|
web server
|
||||||
|
.TP
|
||||||
|
\fBahriman\fR \fI\,web\-reload\/\fR
|
||||||
|
reload configuration
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman aur\-search'\/\fR
|
.SH COMMAND \fI\,'ahriman aur\-search'\/\fR
|
||||||
usage: ahriman aur\-search [\-h] [\-e] [\-\-info | \-\-no\-info]
|
[1;34musage: [0m[1;35mahriman aur\-search[0m [[32m\-h[0m] [[32m\-e[0m] [[36m\-\-info | \-\-no\-info[0m]
|
||||||
[\-\-sort\-by {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}]
|
[[36m\-\-sort\-by [33m{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}[0m]
|
||||||
search [search ...]
|
[32msearch [search ...][0m
|
||||||
|
|
||||||
search for package in AUR using API
|
search for package in AUR using API
|
||||||
|
|
||||||
@@ -213,8 +222,17 @@ 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
|
||||||
|
[1;34musage: [0m[1;35mahriman help[0m [[32m\-h[0m] [32m[subcommand][0m
|
||||||
|
|
||||||
|
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 ...]
|
[1;34musage: [0m[1;35mahriman help\-commands\-unsafe[0m [[32m\-h[0m] [32m[subcommand ...][0m
|
||||||
|
|
||||||
list unsafe commands as defined in default args
|
list unsafe commands as defined in default args
|
||||||
|
|
||||||
@@ -223,17 +241,8 @@ 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]
|
[1;34musage: [0m[1;35mahriman help\-updates[0m [[32m\-h[0m] [[32m\-e[0m]
|
||||||
|
|
||||||
request AUR for current version and compare with current service version
|
request AUR for current version and compare with current service version
|
||||||
|
|
||||||
@@ -243,14 +252,15 @@ request AUR for current version and compare with current service version
|
|||||||
return non\-zero exit code if updates available
|
return non\-zero exit code if updates available
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman help\-version'\/\fR
|
.SH COMMAND \fI\,'ahriman help\-version'\/\fR
|
||||||
usage: ahriman help\-version [\-h]
|
[1;34musage: [0m[1;35mahriman help\-version[0m [[32m\-h[0m]
|
||||||
|
|
||||||
print application and its dependencies versions
|
print application and its dependencies versions
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman package\-add'\/\fR
|
.SH COMMAND \fI\,'ahriman package\-add'\/\fR
|
||||||
usage: ahriman package\-add [\-h] [\-\-dependencies | \-\-no\-dependencies] [\-e] [\-\-increment | \-\-no\-increment] [\-n] [\-y]
|
[1;34musage: [0m[1;35mahriman package\-add[0m [[32m\-h[0m] [[36m\-\-changes | \-\-no\-changes[0m] [[36m\-\-dependencies | \-\-no\-dependencies[0m] [[32m\-e[0m]
|
||||||
[\-s {auto,archive,aur,directory,local,remote,repository}] [\-u USERNAME] [\-v VARIABLE]
|
[[36m\-\-increment | \-\-no\-increment[0m] [[32m\-n[0m] [[32m\-y[0m]
|
||||||
package [package ...]
|
[[32m\-s [33m{auto,archive,aur,directory,local,remote,repository}[0m] [[32m\-u [33mUSERNAME[0m] [[32m\-v [33mVARIABLE[0m]
|
||||||
|
[32mpackage [package ...][0m
|
||||||
|
|
||||||
add existing or new package to the build queue
|
add existing or new package to the build queue
|
||||||
|
|
||||||
@@ -259,6 +269,10 @@ add existing or new package to the build queue
|
|||||||
package source (base name, path to local files, remote URL)
|
package source (base name, path to local files, remote URL)
|
||||||
|
|
||||||
.SH OPTIONS \fI\,'ahriman package\-add'\/\fR
|
.SH OPTIONS \fI\,'ahriman package\-add'\/\fR
|
||||||
|
.TP
|
||||||
|
\fB\-\-changes\fR, \fB\-\-no\-changes\fR
|
||||||
|
calculate changes from the latest known commit if available
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-dependencies\fR, \fB\-\-no\-dependencies\fR
|
\fB\-\-dependencies\fR, \fB\-\-no\-dependencies\fR
|
||||||
process missing package dependencies
|
process missing package dependencies
|
||||||
@@ -292,7 +306,7 @@ build as user
|
|||||||
apply specified makepkg variables to the next build
|
apply specified makepkg variables to the next build
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman package\-changes'\/\fR
|
.SH COMMAND \fI\,'ahriman package\-changes'\/\fR
|
||||||
usage: ahriman package\-changes [\-h] [\-e] package
|
[1;34musage: [0m[1;35mahriman package\-changes[0m [[32m\-h[0m] [[32m\-e[0m] [32mpackage[0m
|
||||||
|
|
||||||
retrieve package changes stored in database
|
retrieve package changes stored in database
|
||||||
|
|
||||||
@@ -306,7 +320,7 @@ package base
|
|||||||
return non\-zero exit status if result is empty
|
return non\-zero exit status if result is empty
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman package\-changes\-remove'\/\fR
|
.SH COMMAND \fI\,'ahriman package\-changes\-remove'\/\fR
|
||||||
usage: ahriman package\-changes\-remove [\-h] package
|
[1;34musage: [0m[1;35mahriman package\-changes\-remove[0m [[32m\-h[0m] [32mpackage[0m
|
||||||
|
|
||||||
remove the package changes stored remotely
|
remove the package changes stored remotely
|
||||||
|
|
||||||
@@ -314,8 +328,30 @@ remove the package changes stored remotely
|
|||||||
\fBpackage\fR
|
\fBpackage\fR
|
||||||
package base
|
package base
|
||||||
|
|
||||||
|
.SH COMMAND \fI\,'ahriman package\-copy'\/\fR
|
||||||
|
[1;34musage: [0m[1;35mahriman package\-copy[0m [[32m\-h[0m] [[32m\-e[0m] [[36m\-\-remove[0m] [32msource[0m [32mpackage [package ...][0m
|
||||||
|
|
||||||
|
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 ...]
|
[1;34musage: [0m[1;35mahriman package\-remove[0m [[32m\-h[0m] [32mpackage [package ...][0m
|
||||||
|
|
||||||
remove package from the repository
|
remove package from the repository
|
||||||
|
|
||||||
@@ -324,8 +360,8 @@ remove package from the repository
|
|||||||
package name or base
|
package name or base
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman package\-status'\/\fR
|
.SH COMMAND \fI\,'ahriman package\-status'\/\fR
|
||||||
usage: ahriman package\-status [\-h] [\-\-ahriman] [\-e] [\-\-info | \-\-no\-info] [\-s {unknown,pending,building,failed,success}]
|
[1;34musage: [0m[1;35mahriman package\-status[0m [[32m\-h[0m] [[36m\-\-ahriman[0m] [[32m\-e[0m] [[36m\-\-info | \-\-no\-info[0m] [[32m\-s [33m{unknown,pending,building,failed,success}[0m]
|
||||||
[package ...]
|
[32m[package ...][0m
|
||||||
|
|
||||||
request status of the package
|
request status of the package
|
||||||
|
|
||||||
@@ -351,7 +387,7 @@ show additional package information
|
|||||||
filter packages by status
|
filter packages by status
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman package\-status\-remove'\/\fR
|
.SH COMMAND \fI\,'ahriman package\-status\-remove'\/\fR
|
||||||
usage: ahriman package\-status\-remove [\-h] package [package ...]
|
[1;34musage: [0m[1;35mahriman package\-status\-remove[0m [[32m\-h[0m] [32mpackage [package ...][0m
|
||||||
|
|
||||||
remove the package from the status page
|
remove the package from the status page
|
||||||
|
|
||||||
@@ -360,7 +396,7 @@ remove the package from the status page
|
|||||||
remove specified packages from status page
|
remove specified packages from status page
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman package\-status\-update'\/\fR
|
.SH COMMAND \fI\,'ahriman package\-status\-update'\/\fR
|
||||||
usage: ahriman package\-status\-update [\-h] [\-s {unknown,pending,building,failed,success}] [package ...]
|
[1;34musage: [0m[1;35mahriman package\-status\-update[0m [[32m\-h[0m] [[32m\-s [33m{unknown,pending,building,failed,success}[0m] [32m[package ...][0m
|
||||||
|
|
||||||
update package status on the status page
|
update package status on the status page
|
||||||
|
|
||||||
@@ -374,7 +410,7 @@ set status for specified packages. If no packages supplied, service status will
|
|||||||
new package build status
|
new package build status
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman patch\-add'\/\fR
|
.SH COMMAND \fI\,'ahriman patch\-add'\/\fR
|
||||||
usage: ahriman patch\-add [\-h] package variable [patch]
|
[1;34musage: [0m[1;35mahriman patch\-add[0m [[32m\-h[0m] [32mpackage[0m [32mvariable[0m [32m[patch][0m
|
||||||
|
|
||||||
create or update patched PKGBUILD function or variable
|
create or update patched PKGBUILD function or variable
|
||||||
|
|
||||||
@@ -391,7 +427,7 @@ PKGBUILD variable or function name. If variable is a function, it must end with
|
|||||||
path to file which contains function or variable value. If not set, the value will be read from stdin
|
path to file which contains function or variable value. If not set, the value will be read from stdin
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman patch\-list'\/\fR
|
.SH COMMAND \fI\,'ahriman patch\-list'\/\fR
|
||||||
usage: ahriman patch\-list [\-h] [\-e] [\-v VARIABLE] [package]
|
[1;34musage: [0m[1;35mahriman patch\-list[0m [[32m\-h[0m] [[32m\-e[0m] [[32m\-v [33mVARIABLE[0m] [32mpackage[0m
|
||||||
|
|
||||||
list available patches for the package
|
list available patches for the package
|
||||||
|
|
||||||
@@ -409,7 +445,7 @@ return non\-zero exit status if result is empty
|
|||||||
if set, show only patches for specified PKGBUILD variables
|
if set, show only patches for specified PKGBUILD variables
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman patch\-remove'\/\fR
|
.SH COMMAND \fI\,'ahriman patch\-remove'\/\fR
|
||||||
usage: ahriman patch\-remove [\-h] [\-v VARIABLE] package
|
[1;34musage: [0m[1;35mahriman patch\-remove[0m [[32m\-h[0m] [[32m\-v [33mVARIABLE[0m] [32mpackage[0m
|
||||||
|
|
||||||
remove patches for the package
|
remove patches for the package
|
||||||
|
|
||||||
@@ -424,7 +460,7 @@ should be used for single\-function patches in case if you wold like to remove o
|
|||||||
if not set, it will remove all patches related to the package
|
if not set, it will remove all patches related to the package
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman patch\-set\-add'\/\fR
|
.SH COMMAND \fI\,'ahriman patch\-set\-add'\/\fR
|
||||||
usage: ahriman patch\-set\-add [\-h] [\-t TRACK] package
|
[1;34musage: [0m[1;35mahriman patch\-set\-add[0m [[32m\-h[0m] [[32m\-t [33mTRACK[0m] [32mpackage[0m
|
||||||
|
|
||||||
create or update source patches
|
create or update source patches
|
||||||
|
|
||||||
@@ -438,7 +474,7 @@ path to directory with changed files for patch addition/update
|
|||||||
files which has to be tracked
|
files which has to be tracked
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman repo\-backup'\/\fR
|
.SH COMMAND \fI\,'ahriman repo\-backup'\/\fR
|
||||||
usage: ahriman repo\-backup [\-h] path
|
[1;34musage: [0m[1;35mahriman repo\-backup[0m [[32m\-h[0m] [32mpath[0m
|
||||||
|
|
||||||
backup repository settings and database
|
backup repository settings and database
|
||||||
|
|
||||||
@@ -447,7 +483,9 @@ backup repository settings and database
|
|||||||
path of the output archive
|
path of the output archive
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman repo\-check'\/\fR
|
.SH COMMAND \fI\,'ahriman repo\-check'\/\fR
|
||||||
usage: ahriman repo\-check [\-h] [\-\-changes | \-\-no\-changes] [\-e] [\-\-vcs | \-\-no\-vcs] [\-y] [package ...]
|
[1;34musage: [0m[1;35mahriman repo\-check[0m [[32m\-h[0m] [[36m\-\-changes | \-\-no\-changes[0m] [[36m\-\-check\-files | \-\-no\-check\-files[0m] [[32m\-e[0m] [[36m\-\-vcs | \-\-no\-vcs[0m]
|
||||||
|
[[32m\-y[0m]
|
||||||
|
[32m[package ...][0m
|
||||||
|
|
||||||
check for packages updates. Same as repo\-update \-\-dry\-run \-\-no\-manual
|
check for packages updates. Same as repo\-update \-\-dry\-run \-\-no\-manual
|
||||||
|
|
||||||
@@ -458,7 +496,11 @@ filter check by package base
|
|||||||
.SH OPTIONS \fI\,'ahriman repo\-check'\/\fR
|
.SH OPTIONS \fI\,'ahriman repo\-check'\/\fR
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-changes\fR, \fB\-\-no\-changes\fR
|
\fB\-\-changes\fR, \fB\-\-no\-changes\fR
|
||||||
calculate changes from the latest known commit if available. Only applicable in dry run mode
|
calculate changes from the latest known commit if available
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fB\-\-check\-files\fR, \fB\-\-no\-check\-files\fR
|
||||||
|
enable or disable checking of broken dependencies (e.g. dynamically linked libraries or modules directories)
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-e\fR, \fB\-\-exit\-code\fR
|
\fB\-e\fR, \fB\-\-exit\-code\fR
|
||||||
@@ -473,20 +515,20 @@ fetch actual version of VCS packages
|
|||||||
download fresh package databases from the mirror before actions, \-yy to force refresh even if up to date
|
download fresh package databases from the mirror before actions, \-yy to force refresh even if up to date
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman repo\-create\-keyring'\/\fR
|
.SH COMMAND \fI\,'ahriman repo\-create\-keyring'\/\fR
|
||||||
usage: ahriman repo\-create\-keyring [\-h]
|
[1;34musage: [0m[1;35mahriman repo\-create\-keyring[0m [[32m\-h[0m]
|
||||||
|
|
||||||
create package which contains list of trusted keys as set by configuration. Note, that this action will only create package, the package itself has to be built manually
|
create package which contains list of trusted keys as set by configuration. Note, that this action will only create package, the package itself has to be built manually
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman repo\-create\-mirrorlist'\/\fR
|
.SH COMMAND \fI\,'ahriman repo\-create\-mirrorlist'\/\fR
|
||||||
usage: ahriman repo\-create\-mirrorlist [\-h]
|
[1;34musage: [0m[1;35mahriman repo\-create\-mirrorlist[0m [[32m\-h[0m]
|
||||||
|
|
||||||
create package which contains list of available mirrors as set by configuration. Note, that this action will only create package, the package itself has to be built manually
|
create package which contains list of available mirrors as set by configuration. Note, that this action will only create package, the package itself has to be built manually
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman repo\-daemon'\/\fR
|
.SH COMMAND \fI\,'ahriman repo\-daemon'\/\fR
|
||||||
usage: ahriman repo\-daemon [\-h] [\-i INTERVAL] [\-\-aur | \-\-no\-aur] [\-\-changes | \-\-no\-changes]
|
[1;34musage: [0m[1;35mahriman repo\-daemon[0m [[32m\-h[0m] [[32m\-i [33mINTERVAL[0m] [[36m\-\-aur | \-\-no\-aur[0m] [[36m\-\-changes | \-\-no\-changes[0m]
|
||||||
[\-\-dependencies | \-\-no\-dependencies] [\-\-dry\-run] [\-\-increment | \-\-no\-increment]
|
[[36m\-\-check\-files | \-\-no\-check\-files[0m] [[36m\-\-dependencies | \-\-no\-dependencies[0m] [[36m\-\-dry\-run[0m]
|
||||||
[\-\-local | \-\-no\-local] [\-\-manual | \-\-no\-manual] [\-\-partitions | \-\-no\-partitions]
|
[[36m\-\-increment | \-\-no\-increment[0m] [[36m\-\-local | \-\-no\-local[0m] [[36m\-\-manual | \-\-no\-manual[0m]
|
||||||
[\-u USERNAME] [\-\-vcs | \-\-no\-vcs] [\-y]
|
[[36m\-\-partitions | \-\-no\-partitions[0m] [[32m\-u [33mUSERNAME[0m] [[36m\-\-vcs | \-\-no\-vcs[0m] [[32m\-y[0m]
|
||||||
|
|
||||||
start process which periodically will run update process
|
start process which periodically will run update process
|
||||||
|
|
||||||
@@ -503,6 +545,10 @@ enable or disable checking for AUR updates
|
|||||||
\fB\-\-changes\fR, \fB\-\-no\-changes\fR
|
\fB\-\-changes\fR, \fB\-\-no\-changes\fR
|
||||||
calculate changes from the latest known commit if available. Only applicable in dry run mode
|
calculate changes from the latest known commit if available. Only applicable in dry run mode
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fB\-\-check\-files\fR, \fB\-\-no\-check\-files\fR
|
||||||
|
enable or disable checking of broken dependencies (e.g. dynamically linked libraries or modules directories)
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-dependencies\fR, \fB\-\-no\-dependencies\fR
|
\fB\-\-dependencies\fR, \fB\-\-no\-dependencies\fR
|
||||||
process missing package dependencies
|
process missing package dependencies
|
||||||
@@ -540,8 +586,8 @@ fetch actual version of VCS packages
|
|||||||
download fresh package databases from the mirror before actions, \-yy to force refresh even if up to date
|
download fresh package databases from the mirror before actions, \-yy to force refresh even if up to date
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman repo\-rebuild'\/\fR
|
.SH COMMAND \fI\,'ahriman repo\-rebuild'\/\fR
|
||||||
usage: ahriman repo\-rebuild [\-h] [\-\-depends\-on DEPENDS_ON] [\-\-dry\-run] [\-\-from\-database] [\-\-increment | \-\-no\-increment]
|
[1;34musage: [0m[1;35mahriman repo\-rebuild[0m [[32m\-h[0m] [[36m\-\-depends\-on [33mDEPENDS_ON[0m] [[36m\-\-dry\-run[0m] [[36m\-\-from\-database[0m] [[36m\-\-increment | \-\-no\-increment[0m]
|
||||||
[\-e] [\-s {unknown,pending,building,failed,success}] [\-u USERNAME]
|
[[32m\-e[0m] [[32m\-s [33m{unknown,pending,building,failed,success}[0m] [[32m\-u [33mUSERNAME[0m]
|
||||||
|
|
||||||
force rebuild whole repository
|
force rebuild whole repository
|
||||||
|
|
||||||
@@ -577,7 +623,7 @@ filter packages by status. Requires \-\-from\-database to be set
|
|||||||
build as user
|
build as user
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman repo\-remove\-unknown'\/\fR
|
.SH COMMAND \fI\,'ahriman repo\-remove\-unknown'\/\fR
|
||||||
usage: ahriman repo\-remove\-unknown [\-h] [\-\-dry\-run]
|
[1;34musage: [0m[1;35mahriman repo\-remove\-unknown[0m [[32m\-h[0m] [[36m\-\-dry\-run[0m]
|
||||||
|
|
||||||
remove packages which are missing in AUR and do not have local PKGBUILDs
|
remove packages which are missing in AUR and do not have local PKGBUILDs
|
||||||
|
|
||||||
@@ -587,12 +633,12 @@ remove packages which are missing in AUR and do not have local PKGBUILDs
|
|||||||
just perform check for packages without removal
|
just perform check for packages without removal
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman repo\-report'\/\fR
|
.SH COMMAND \fI\,'ahriman repo\-report'\/\fR
|
||||||
usage: ahriman repo\-report [\-h]
|
[1;34musage: [0m[1;35mahriman repo\-report[0m [[32m\-h[0m]
|
||||||
|
|
||||||
generate repository report according to current settings
|
generate repository report according to current settings
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman repo\-restore'\/\fR
|
.SH COMMAND \fI\,'ahriman repo\-restore'\/\fR
|
||||||
usage: ahriman repo\-restore [\-h] [\-o OUTPUT] path
|
[1;34musage: [0m[1;35mahriman repo\-restore[0m [[32m\-h[0m] [[32m\-o [33mOUTPUT[0m] [32mpath[0m
|
||||||
|
|
||||||
restore settings and database
|
restore settings and database
|
||||||
|
|
||||||
@@ -606,7 +652,7 @@ path of the input archive
|
|||||||
root path of the extracted files
|
root path of the extracted files
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman repo\-sign'\/\fR
|
.SH COMMAND \fI\,'ahriman repo\-sign'\/\fR
|
||||||
usage: ahriman repo\-sign [\-h] [package ...]
|
[1;34musage: [0m[1;35mahriman repo\-sign[0m [[32m\-h[0m] [32m[package ...][0m
|
||||||
|
|
||||||
(re\-)sign packages and repository database according to current settings
|
(re\-)sign packages and repository database according to current settings
|
||||||
|
|
||||||
@@ -614,8 +660,45 @@ usage: ahriman repo\-sign [\-h] [package ...]
|
|||||||
\fBpackage\fR
|
\fBpackage\fR
|
||||||
sign only specified packages
|
sign only specified packages
|
||||||
|
|
||||||
|
.SH COMMAND \fI\,'ahriman repo\-statistics'\/\fR
|
||||||
|
[1;34musage: [0m[1;35mahriman repo\-statistics[0m [[32m\-h[0m] [[36m\-\-chart [33mCHART[0m]
|
||||||
|
[[32m\-e [33m{package\-outdated,package\-removed,package\-update\-failed,package\-updated}[0m]
|
||||||
|
[[36m\-\-from\-date [33mFROM_DATE[0m] [[36m\-\-limit [33mLIMIT[0m] [[36m\-\-offset [33mOFFSET[0m] [[36m\-\-to\-date [33mTO_DATE[0m]
|
||||||
|
[32m[package][0m
|
||||||
|
|
||||||
|
fetch repository statistics
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fBpackage\fR
|
||||||
|
fetch only events for the specified package
|
||||||
|
|
||||||
|
.SH OPTIONS \fI\,'ahriman repo\-statistics'\/\fR
|
||||||
|
.TP
|
||||||
|
\fB\-\-chart\fR \fI\,CHART\/\fR
|
||||||
|
create updates chart and save it to the specified path
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fB\-e\fR \fI\,{package\-outdated,package\-removed,package\-update\-failed,package\-updated}\/\fR, \fB\-\-event\fR \fI\,{package\-outdated,package\-removed,package\-update\-failed,package\-updated}\/\fR
|
||||||
|
event type filter
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fB\-\-from\-date\fR \fI\,FROM_DATE\/\fR
|
||||||
|
only fetch events which are newer than the date
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fB\-\-limit\fR \fI\,LIMIT\/\fR
|
||||||
|
limit response by specified amount of events
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fB\-\-offset\fR \fI\,OFFSET\/\fR
|
||||||
|
skip specified amount of events
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fB\-\-to\-date\fR \fI\,TO_DATE\/\fR
|
||||||
|
only fetch events which are older than the date
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman repo\-status\-update'\/\fR
|
.SH COMMAND \fI\,'ahriman repo\-status\-update'\/\fR
|
||||||
usage: ahriman repo\-status\-update [\-h] [\-s {unknown,pending,building,failed,success}]
|
[1;34musage: [0m[1;35mahriman repo\-status\-update[0m [[32m\-h[0m] [[32m\-s [33m{unknown,pending,building,failed,success}[0m]
|
||||||
|
|
||||||
update repository status on the status page
|
update repository status on the status page
|
||||||
|
|
||||||
@@ -625,12 +708,12 @@ update repository status on the status page
|
|||||||
new status
|
new status
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman repo\-sync'\/\fR
|
.SH COMMAND \fI\,'ahriman repo\-sync'\/\fR
|
||||||
usage: ahriman repo\-sync [\-h]
|
[1;34musage: [0m[1;35mahriman repo\-sync[0m [[32m\-h[0m]
|
||||||
|
|
||||||
sync repository files to remote server according to current settings
|
sync repository files to remote server according to current settings
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman repo\-tree'\/\fR
|
.SH COMMAND \fI\,'ahriman repo\-tree'\/\fR
|
||||||
usage: ahriman repo\-tree [\-h] [\-p PARTITIONS]
|
[1;34musage: [0m[1;35mahriman repo\-tree[0m [[32m\-h[0m] [[32m\-p [33mPARTITIONS[0m]
|
||||||
|
|
||||||
dump repository tree based on packages dependencies
|
dump repository tree based on packages dependencies
|
||||||
|
|
||||||
@@ -640,7 +723,7 @@ dump repository tree based on packages dependencies
|
|||||||
also divide packages by independent partitions
|
also divide packages by independent partitions
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman repo\-triggers'\/\fR
|
.SH COMMAND \fI\,'ahriman repo\-triggers'\/\fR
|
||||||
usage: ahriman repo\-triggers [\-h] [trigger ...]
|
[1;34musage: [0m[1;35mahriman repo\-triggers[0m [[32m\-h[0m] [32m[trigger ...][0m
|
||||||
|
|
||||||
run triggers on empty build result as configured by settings
|
run triggers on empty build result as configured by settings
|
||||||
|
|
||||||
@@ -649,10 +732,10 @@ run triggers on empty build result as configured by settings
|
|||||||
instead of running all triggers as set by configuration, just process specified ones in order of mention
|
instead of running all triggers as set by configuration, just process specified ones in order of mention
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman repo\-update'\/\fR
|
.SH COMMAND \fI\,'ahriman repo\-update'\/\fR
|
||||||
usage: ahriman repo\-update [\-h] [\-\-aur | \-\-no\-aur] [\-\-changes | \-\-no\-changes] [\-\-dependencies | \-\-no\-dependencies]
|
[1;34musage: [0m[1;35mahriman repo\-update[0m [[32m\-h[0m] [[36m\-\-aur | \-\-no\-aur[0m] [[36m\-\-changes | \-\-no\-changes[0m] [[36m\-\-check\-files | \-\-no\-check\-files[0m]
|
||||||
[\-\-dry\-run] [\-e] [\-\-increment | \-\-no\-increment] [\-\-local | \-\-no\-local]
|
[[36m\-\-dependencies | \-\-no\-dependencies[0m] [[36m\-\-dry\-run[0m] [[32m\-e[0m] [[36m\-\-increment | \-\-no\-increment[0m]
|
||||||
[\-\-manual | \-\-no\-manual] [\-u USERNAME] [\-\-vcs | \-\-no\-vcs] [\-y]
|
[[36m\-\-local | \-\-no\-local[0m] [[36m\-\-manual | \-\-no\-manual[0m] [[32m\-u [33mUSERNAME[0m] [[36m\-\-vcs | \-\-no\-vcs[0m] [[32m\-y[0m]
|
||||||
[package ...]
|
[32m[package ...][0m
|
||||||
|
|
||||||
check for packages updates and run build process if requested
|
check for packages updates and run build process if requested
|
||||||
|
|
||||||
@@ -669,6 +752,10 @@ enable or disable checking for AUR updates
|
|||||||
\fB\-\-changes\fR, \fB\-\-no\-changes\fR
|
\fB\-\-changes\fR, \fB\-\-no\-changes\fR
|
||||||
calculate changes from the latest known commit if available. Only applicable in dry run mode
|
calculate changes from the latest known commit if available. Only applicable in dry run mode
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fB\-\-check\-files\fR, \fB\-\-no\-check\-files\fR
|
||||||
|
enable or disable checking of broken dependencies (e.g. dynamically linked libraries or modules directories)
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-dependencies\fR, \fB\-\-no\-dependencies\fR
|
\fB\-\-dependencies\fR, \fB\-\-no\-dependencies\fR
|
||||||
process missing package dependencies
|
process missing package dependencies
|
||||||
@@ -706,8 +793,8 @@ fetch actual version of VCS packages
|
|||||||
download fresh package databases from the mirror before actions, \-yy to force refresh even if up to date
|
download fresh package databases from the mirror before actions, \-yy to force refresh even if up to date
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman service\-clean'\/\fR
|
.SH COMMAND \fI\,'ahriman service\-clean'\/\fR
|
||||||
usage: ahriman service\-clean [\-h] [\-\-cache | \-\-no\-cache] [\-\-chroot | \-\-no\-chroot] [\-\-manual | \-\-no\-manual]
|
[1;34musage: [0m[1;35mahriman service\-clean[0m [[32m\-h[0m] [[36m\-\-cache | \-\-no\-cache[0m] [[36m\-\-chroot | \-\-no\-chroot[0m] [[36m\-\-manual | \-\-no\-manual[0m]
|
||||||
[\-\-packages | \-\-no\-packages] [\-\-pacman | \-\-no\-pacman]
|
[[36m\-\-packages | \-\-no\-packages[0m] [[36m\-\-pacman | \-\-no\-pacman[0m]
|
||||||
|
|
||||||
remove local caches
|
remove local caches
|
||||||
|
|
||||||
@@ -733,7 +820,7 @@ clear directory with built packages
|
|||||||
clear directory with pacman local database cache
|
clear directory with pacman local database cache
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman service\-config'\/\fR
|
.SH COMMAND \fI\,'ahriman service\-config'\/\fR
|
||||||
usage: ahriman service\-config [\-h] [\-\-info | \-\-no\-info] [\-\-secure | \-\-no\-secure] [section] [key]
|
[1;34musage: [0m[1;35mahriman service\-config[0m [[32m\-h[0m] [[36m\-\-info | \-\-no\-info[0m] [[36m\-\-secure | \-\-no\-secure[0m] [32m[section][0m [32m[key][0m
|
||||||
|
|
||||||
dump configuration for the specified architecture
|
dump configuration for the specified architecture
|
||||||
|
|
||||||
@@ -755,7 +842,7 @@ show additional information, e.g. configuration files
|
|||||||
hide passwords and secrets from output
|
hide passwords and secrets from output
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman service\-config\-validate'\/\fR
|
.SH COMMAND \fI\,'ahriman service\-config\-validate'\/\fR
|
||||||
usage: ahriman service\-config\-validate [\-h] [\-e]
|
[1;34musage: [0m[1;35mahriman service\-config\-validate[0m [[32m\-h[0m] [[32m\-e[0m]
|
||||||
|
|
||||||
validate configuration and print found errors
|
validate configuration and print found errors
|
||||||
|
|
||||||
@@ -765,7 +852,7 @@ validate configuration and print found errors
|
|||||||
return non\-zero exit status if configuration is invalid
|
return non\-zero exit status if configuration is invalid
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman service\-key\-import'\/\fR
|
.SH COMMAND \fI\,'ahriman service\-key\-import'\/\fR
|
||||||
usage: ahriman service\-key\-import [\-h] [\-\-key\-server KEY_SERVER] key
|
[1;34musage: [0m[1;35mahriman service\-key\-import[0m [[32m\-h[0m] [[36m\-\-key\-server [33mKEY_SERVER[0m] [32mkey[0m
|
||||||
|
|
||||||
import PGP key from public sources to the repository user
|
import PGP key from public sources to the repository user
|
||||||
|
|
||||||
@@ -779,7 +866,7 @@ PGP key to import from public server
|
|||||||
key server for key import
|
key server for key import
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman service\-repositories'\/\fR
|
.SH COMMAND \fI\,'ahriman service\-repositories'\/\fR
|
||||||
usage: ahriman service\-repositories [\-h] [\-\-id\-only | \-\-no\-id\-only]
|
[1;34musage: [0m[1;35mahriman service\-repositories[0m [[32m\-h[0m] [[36m\-\-id\-only | \-\-no\-id\-only[0m]
|
||||||
|
|
||||||
list all available repositories
|
list all available repositories
|
||||||
|
|
||||||
@@ -789,7 +876,7 @@ list all available repositories
|
|||||||
show machine readable identifier instead
|
show machine readable identifier instead
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman service\-run'\/\fR
|
.SH COMMAND \fI\,'ahriman service\-run'\/\fR
|
||||||
usage: ahriman service\-run [\-h] command [command ...]
|
[1;34musage: [0m[1;35mahriman service\-run[0m [[32m\-h[0m] [32mcommand [command ...][0m
|
||||||
|
|
||||||
run multiple commands on success run of the previous command
|
run multiple commands on success run of the previous command
|
||||||
|
|
||||||
@@ -798,11 +885,11 @@ run multiple commands on success run of the previous command
|
|||||||
command to be run (quoted) without ``ahriman``
|
command to be run (quoted) without ``ahriman``
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman service\-setup'\/\fR
|
.SH COMMAND \fI\,'ahriman service\-setup'\/\fR
|
||||||
usage: ahriman service\-setup [\-h] [\-\-build\-as\-user BUILD_AS_USER] [\-\-from\-configuration FROM_CONFIGURATION]
|
[1;34musage: [0m[1;35mahriman service\-setup[0m [[32m\-h[0m] [[36m\-\-build\-as\-user [33mBUILD_AS_USER[0m] [[36m\-\-from\-configuration [33mFROM_CONFIGURATION[0m]
|
||||||
[\-\-generate\-salt | \-\-no\-generate\-salt] [\-\-makeflags\-jobs | \-\-no\-makeflags\-jobs]
|
[[36m\-\-generate\-salt | \-\-no\-generate\-salt[0m] [[36m\-\-makeflags\-jobs | \-\-no\-makeflags\-jobs[0m]
|
||||||
[\-\-mirror MIRROR] [\-\-multilib | \-\-no\-multilib] \-\-packager PACKAGER [\-\-server SERVER]
|
[[36m\-\-mirror [33mMIRROR[0m] [[36m\-\-multilib | \-\-no\-multilib[0m] [36m\-\-packager [33mPACKAGER[0m [[36m\-\-server [33mSERVER[0m]
|
||||||
[\-\-sign\-key SIGN_KEY] [\-\-sign\-target {disabled,packages,repository}] [\-\-web\-port WEB_PORT]
|
[[36m\-\-sign\-key [33mSIGN_KEY[0m] [[36m\-\-sign\-target [33m{disabled,packages,repository}[0m] [[36m\-\-web\-port [33mWEB_PORT[0m]
|
||||||
[\-\-web\-unix\-socket WEB_UNIX_SOCKET]
|
[[36m\-\-web\-unix\-socket [33mWEB_UNIX_SOCKET[0m]
|
||||||
|
|
||||||
create initial service configuration, requires root
|
create initial service configuration, requires root
|
||||||
|
|
||||||
@@ -856,7 +943,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]
|
[1;34musage: [0m[1;35mahriman service\-shell[0m [[32m\-h[0m] [[32m\-o [33mOUTPUT[0m] [32m[code][0m
|
||||||
|
|
||||||
drop into python shell
|
drop into python shell
|
||||||
|
|
||||||
@@ -864,14 +951,19 @@ 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]
|
[1;34musage: [0m[1;35mahriman service\-tree\-migrate[0m [[32m\-h[0m]
|
||||||
|
|
||||||
migrate repository tree between versions
|
migrate repository tree between versions
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman user\-add'\/\fR
|
.SH COMMAND \fI\,'ahriman user\-add'\/\fR
|
||||||
usage: ahriman user\-add [\-h] [\-\-key KEY] [\-\-packager PACKAGER] [\-p PASSWORD] [\-R {unauthorized,read,reporter,full}]
|
[1;34musage: [0m[1;35mahriman user\-add[0m [[32m\-h[0m] [[36m\-\-key [33mKEY[0m] [[36m\-\-packager [33mPACKAGER[0m] [[32m\-p [33mPASSWORD[0m] [[32m\-R [33m{unauthorized,read,reporter,full}[0m]
|
||||||
username
|
[32musername[0m
|
||||||
|
|
||||||
update user for web services with the given password and role. In case if password was not entered it will be asked interactively
|
update user for web services with the given password and role. In case if password was not entered it will be asked interactively
|
||||||
|
|
||||||
@@ -898,7 +990,7 @@ authorization type.
|
|||||||
user access level
|
user access level
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman user\-list'\/\fR
|
.SH COMMAND \fI\,'ahriman user\-list'\/\fR
|
||||||
usage: ahriman user\-list [\-h] [\-e] [\-R {unauthorized,read,reporter,full}] [username]
|
[1;34musage: [0m[1;35mahriman user\-list[0m [[32m\-h[0m] [[32m\-e[0m] [[32m\-R [33m{unauthorized,read,reporter,full}[0m] [32m[username][0m
|
||||||
|
|
||||||
list users from the user mapping and their roles
|
list users from the user mapping and their roles
|
||||||
|
|
||||||
@@ -916,7 +1008,7 @@ return non\-zero exit status if result is empty
|
|||||||
filter users by role
|
filter users by role
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman user\-remove'\/\fR
|
.SH COMMAND \fI\,'ahriman user\-remove'\/\fR
|
||||||
usage: ahriman user\-remove [\-h] username
|
[1;34musage: [0m[1;35mahriman user\-remove[0m [[32m\-h[0m] [32musername[0m
|
||||||
|
|
||||||
remove user from the user mapping and update the configuration
|
remove user from the user mapping and update the configuration
|
||||||
|
|
||||||
@@ -925,12 +1017,35 @@ remove user from the user mapping and update the configuration
|
|||||||
username for web service
|
username for web service
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman web'\/\fR
|
.SH COMMAND \fI\,'ahriman web'\/\fR
|
||||||
usage: ahriman web [\-h]
|
[1;34musage: [0m[1;35mahriman web[0m [[32m\-h[0m]
|
||||||
|
|
||||||
start web server
|
start web server
|
||||||
|
|
||||||
|
.SH COMMAND \fI\,'ahriman web\-reload'\/\fR
|
||||||
|
[1;34musage: [0m[1;35mahriman web\-reload[0m [[32m\-h[0m]
|
||||||
|
|
||||||
|
reload web server configuration
|
||||||
|
|
||||||
.SH COMMENTS
|
.SH COMMENTS
|
||||||
Argument list can also be read from file by using @ prefix.
|
Quick setup command (replace repository name, architecture and packager as needed):
|
||||||
|
|
||||||
|
>>> ahriman \-a x86_64 \-r aur service\-setup \-\-packager "ahriman bot <ahriman@example.com>"
|
||||||
|
|
||||||
|
Add new package from AUR:
|
||||||
|
|
||||||
|
>>> ahriman package\-add ahriman \-\-now
|
||||||
|
|
||||||
|
Check for updates and build out\-of\-dated packages (add ``\-\-dry\-run`` to build it later):
|
||||||
|
|
||||||
|
>>> ahriman repo\-update
|
||||||
|
|
||||||
|
Remove package from the repository:
|
||||||
|
|
||||||
|
>>> ahriman package\-remove ahriman
|
||||||
|
|
||||||
|
Start web service (requires additional configuration):
|
||||||
|
|
||||||
|
>>> ahriman web
|
||||||
|
|
||||||
.SH AUTHOR
|
.SH AUTHOR
|
||||||
.nf
|
.nf
|
||||||
+306
-13
@@ -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"
|
||||||
@@ -48,6 +50,7 @@ _shtab_ahriman_commands() {
|
|||||||
"repo-restore:restore settings and database"
|
"repo-restore:restore settings and database"
|
||||||
"repo-setup:create initial service configuration, requires root"
|
"repo-setup:create initial service configuration, requires root"
|
||||||
"repo-sign:(re-)sign packages and repository database according to current settings"
|
"repo-sign:(re-)sign packages and repository database according to current settings"
|
||||||
|
"repo-statistics:fetch repository statistics"
|
||||||
"repo-status-update:update repository status on the status page"
|
"repo-status-update:update repository status on the status page"
|
||||||
"repo-sync:sync repository files to remote server according to current settings"
|
"repo-sync:sync repository files to remote server according to current settings"
|
||||||
"repo-tree:dump repository tree based on packages dependencies"
|
"repo-tree:dump repository tree based on packages dependencies"
|
||||||
@@ -77,6 +80,7 @@ _shtab_ahriman_commands() {
|
|||||||
"user-remove:remove user from the user mapping and update the configuration"
|
"user-remove:remove user from the user mapping and update the configuration"
|
||||||
"version:print application and its dependencies versions"
|
"version:print application and its dependencies versions"
|
||||||
"web:start web server"
|
"web:start web server"
|
||||||
|
"web-reload:reload web server configuration"
|
||||||
)
|
)
|
||||||
_describe 'ahriman commands' _commands
|
_describe 'ahriman commands' _commands
|
||||||
}
|
}
|
||||||
@@ -86,7 +90,7 @@ _shtab_ahriman_options=(
|
|||||||
{-a,--architecture}"[filter by target architecture (default\: None)]:architecture:"
|
{-a,--architecture}"[filter by target architecture (default\: None)]:architecture:"
|
||||||
{-c,--configuration}"[configuration path (default\: \/etc\/ahriman.ini)]:configuration:"
|
{-c,--configuration}"[configuration path (default\: \/etc\/ahriman.ini)]:configuration:"
|
||||||
"--force[force run, remove file lock (default\: False)]"
|
"--force[force run, remove file lock (default\: False)]"
|
||||||
{-l,--lock}"[lock file (default\: \/tmp\/ahriman.lock)]:lock:"
|
{-l,--lock}"[lock file (default\: ahriman.pid)]:lock:"
|
||||||
"--log-handler[explicit log handler specification. If none set, the handler will be guessed from environment (default\: None)]:log_handler:(console syslog journald)"
|
"--log-handler[explicit log handler specification. If none set, the handler will be guessed from environment (default\: None)]:log_handler:(console syslog journald)"
|
||||||
{-q,--quiet}"[force disable any logging (default\: False)]"
|
{-q,--quiet}"[force disable any logging (default\: False)]"
|
||||||
{--report,--no-report}"[force enable or disable reporting to web service (default\: True)]:report:"
|
{--report,--no-report}"[force enable or disable reporting to web service (default\: True)]:report:"
|
||||||
@@ -96,8 +100,12 @@ _shtab_ahriman_options=(
|
|||||||
"--wait-timeout[wait for lock to be free. Negative value will lead to immediate application run even if there is lock file. In case of zero value, the application will wait infinitely (default\: -1)]:wait_timeout:"
|
"--wait-timeout[wait for lock to be free. Negative value will lead to immediate application run even if there is lock file. In case of zero value, the application will wait infinitely (default\: -1)]:wait_timeout:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_add_options=(
|
_shtab_ahriman_add_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
|
{--changes,--no-changes}"[calculate changes from the latest known commit if available (default\: True)]:changes:"
|
||||||
{--dependencies,--no-dependencies}"[process missing package dependencies (default\: True)]:dependencies:"
|
{--dependencies,--no-dependencies}"[process missing package dependencies (default\: True)]:dependencies:"
|
||||||
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
|
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
|
||||||
{--increment,--no-increment}"[increment package release (pkgrel) version on duplicate (default\: True)]:increment:"
|
{--increment,--no-increment}"[increment package release (pkgrel) version on duplicate (default\: True)]:increment:"
|
||||||
@@ -109,6 +117,9 @@ _shtab_ahriman_add_options=(
|
|||||||
"(*):package source (base name, path to local files, remote URL):"
|
"(*):package source (base name, path to local files, remote URL):"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_add_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_aur_search_options=(
|
_shtab_ahriman_aur_search_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
|
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
|
||||||
@@ -117,15 +128,22 @@ _shtab_ahriman_aur_search_options=(
|
|||||||
"(*):search terms, can be specified multiple times, the result will match all terms:"
|
"(*):search terms, can be specified multiple times, the result will match all terms:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_aur_search_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_check_options=(
|
_shtab_ahriman_check_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
{--changes,--no-changes}"[calculate changes from the latest known commit if available. Only applicable in dry run mode (default\: True)]:changes:"
|
{--changes,--no-changes}"[calculate changes from the latest known commit if available (default\: True)]:changes:"
|
||||||
|
{--check-files,--no-check-files}"[enable or disable checking of broken dependencies (e.g. dynamically linked libraries or modules directories) (default\: True)]:check_files:"
|
||||||
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
|
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
|
||||||
{--vcs,--no-vcs}"[fetch actual version of VCS packages (default\: True)]:vcs:"
|
{--vcs,--no-vcs}"[fetch actual version of VCS packages (default\: True)]:vcs:"
|
||||||
"*"{-y,--refresh}"[download fresh package databases from the mirror before actions, -yy to force refresh even if up to date (default\: False)]"
|
"*"{-y,--refresh}"[download fresh package databases from the mirror before actions, -yy to force refresh even if up to date (default\: False)]"
|
||||||
"(*)::filter check by package base (default\: None):"
|
"(*)::filter check by package base (default\: None):"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_check_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_clean_options=(
|
_shtab_ahriman_clean_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
{--cache,--no-cache}"[clear directory with package caches (default\: False)]:cache:"
|
{--cache,--no-cache}"[clear directory with package caches (default\: False)]:cache:"
|
||||||
@@ -135,6 +153,9 @@ _shtab_ahriman_clean_options=(
|
|||||||
{--pacman,--no-pacman}"[clear directory with pacman local database cache (default\: False)]:pacman:"
|
{--pacman,--no-pacman}"[clear directory with pacman local database cache (default\: False)]:pacman:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_clean_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_config_options=(
|
_shtab_ahriman_config_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
{--info,--no-info}"[show additional information, e.g. configuration files (default\: True)]:info:"
|
{--info,--no-info}"[show additional information, e.g. configuration files (default\: True)]:info:"
|
||||||
@@ -143,16 +164,34 @@ _shtab_ahriman_config_options=(
|
|||||||
":filter settings by key (default\: None):"
|
":filter settings by key (default\: None):"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_config_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_config_validate_options=(
|
_shtab_ahriman_config_validate_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
{-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)]"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_config_validate_defaults_added=0
|
||||||
|
|
||||||
|
_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:"
|
||||||
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_copy_defaults_added=0
|
||||||
|
|
||||||
_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:"
|
||||||
{--aur,--no-aur}"[enable or disable checking for AUR updates (default\: True)]:aur:"
|
{--aur,--no-aur}"[enable or disable checking for AUR updates (default\: True)]:aur:"
|
||||||
{--changes,--no-changes}"[calculate changes from the latest known commit if available. Only applicable in dry run mode (default\: True)]:changes:"
|
{--changes,--no-changes}"[calculate changes from the latest known commit if available. Only applicable in dry run mode (default\: True)]:changes:"
|
||||||
|
{--check-files,--no-check-files}"[enable or disable checking of broken dependencies (e.g. dynamically linked libraries or modules directories) (default\: True)]:check_files:"
|
||||||
{--dependencies,--no-dependencies}"[process missing package dependencies (default\: True)]:dependencies:"
|
{--dependencies,--no-dependencies}"[process missing package dependencies (default\: True)]:dependencies:"
|
||||||
"--dry-run[just perform check for updates, same as check command (default\: False)]"
|
"--dry-run[just perform check for updates, same as check command (default\: False)]"
|
||||||
{--increment,--no-increment}"[increment package release (pkgrel) on duplicate (default\: True)]:increment:"
|
{--increment,--no-increment}"[increment package release (pkgrel) on duplicate (default\: True)]:increment:"
|
||||||
@@ -164,25 +203,40 @@ _shtab_ahriman_daemon_options=(
|
|||||||
"*"{-y,--refresh}"[download fresh package databases from the mirror before actions, -yy to force refresh even if up to date (default\: False)]"
|
"*"{-y,--refresh}"[download fresh package databases from the mirror before actions, -yy to force refresh even if up to date (default\: False)]"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_daemon_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_help_options=(
|
_shtab_ahriman_help_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
":show help message for specific command (default\: None):"
|
":show help message for specific command (default\: None):"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_help_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_help_commands_unsafe_options=(
|
_shtab_ahriman_help_commands_unsafe_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
"(*)::instead of showing commands, just test command line for unsafe subcommand and return 0 in case if command is safe and 1 otherwise (default\: None):"
|
"(*)::instead of showing commands, just test command line for unsafe subcommand and return 0 in case if command is safe and 1 otherwise (default\: None):"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_help_commands_unsafe_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_help_updates_options=(
|
_shtab_ahriman_help_updates_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
{-e,--exit-code}"[return non-zero exit code if updates available (default\: False)]"
|
{-e,--exit-code}"[return non-zero exit code if updates available (default\: False)]"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_help_updates_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_help_version_options=(
|
_shtab_ahriman_help_version_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_help_version_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_init_options=(
|
_shtab_ahriman_init_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
"--build-as-user[force makepkg user to the specific one (default\: None)]:build_as_user:"
|
"--build-as-user[force makepkg user to the specific one (default\: None)]:build_as_user:"
|
||||||
@@ -191,7 +245,7 @@ _shtab_ahriman_init_options=(
|
|||||||
{--makeflags-jobs,--no-makeflags-jobs}"[append MAKEFLAGS variable with parallelism set to number of cores (default\: True)]:makeflags_jobs:"
|
{--makeflags-jobs,--no-makeflags-jobs}"[append MAKEFLAGS variable with parallelism set to number of cores (default\: True)]:makeflags_jobs:"
|
||||||
"--mirror[use the specified explicitly mirror instead of including mirrorlist (default\: None)]:mirror:"
|
"--mirror[use the specified explicitly mirror instead of including mirrorlist (default\: None)]:mirror:"
|
||||||
{--multilib,--no-multilib}"[add or do not multilib repository (default\: True)]:multilib:"
|
{--multilib,--no-multilib}"[add or do not multilib repository (default\: True)]:multilib:"
|
||||||
"--packager[packager name and email (default\: None)]:packager:"
|
"--packager[packager name and email]:packager:"
|
||||||
"--server[server to be used for devtools. If none set, local files will be used (default\: None)]:server:"
|
"--server[server to be used for devtools. If none set, local files will be used (default\: None)]:server:"
|
||||||
"--sign-key[sign key id (default\: None)]:sign_key:"
|
"--sign-key[sign key id (default\: None)]:sign_key:"
|
||||||
"*--sign-target[sign options (default\: None)]:sign_target:(disabled packages repository)"
|
"*--sign-target[sign options (default\: None)]:sign_target:(disabled packages repository)"
|
||||||
@@ -199,14 +253,21 @@ _shtab_ahriman_init_options=(
|
|||||||
"--web-unix-socket[path to unix socket used for interprocess communications (default\: None)]:web_unix_socket:"
|
"--web-unix-socket[path to unix socket used for interprocess communications (default\: None)]:web_unix_socket:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_init_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_key_import_options=(
|
_shtab_ahriman_key_import_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
"--key-server[key server for key import (default\: keyserver.ubuntu.com)]:key_server:"
|
"--key-server[key server for key import (default\: keyserver.ubuntu.com)]:key_server:"
|
||||||
":PGP key to import from public server:"
|
":PGP key to import from public server:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_key_import_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_package_add_options=(
|
_shtab_ahriman_package_add_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
|
{--changes,--no-changes}"[calculate changes from the latest known commit if available (default\: True)]:changes:"
|
||||||
{--dependencies,--no-dependencies}"[process missing package dependencies (default\: True)]:dependencies:"
|
{--dependencies,--no-dependencies}"[process missing package dependencies (default\: True)]:dependencies:"
|
||||||
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
|
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
|
||||||
{--increment,--no-increment}"[increment package release (pkgrel) version on duplicate (default\: True)]:increment:"
|
{--increment,--no-increment}"[increment package release (pkgrel) version on duplicate (default\: True)]:increment:"
|
||||||
@@ -218,22 +279,45 @@ _shtab_ahriman_package_add_options=(
|
|||||||
"(*):package source (base name, path to local files, remote URL):"
|
"(*):package source (base name, path to local files, remote URL):"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_package_add_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_package_changes_options=(
|
_shtab_ahriman_package_changes_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
|
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
|
||||||
":package base:"
|
":package base:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_package_changes_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_package_changes_remove_options=(
|
_shtab_ahriman_package_changes_remove_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
":package base:"
|
":package base:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_package_changes_remove_defaults_added=0
|
||||||
|
|
||||||
|
_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:"
|
||||||
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_package_copy_defaults_added=0
|
||||||
|
|
||||||
_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:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_package_remove_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_package_status_options=(
|
_shtab_ahriman_package_status_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
"--ahriman[get service status itself (default\: False)]"
|
"--ahriman[get service status itself (default\: False)]"
|
||||||
@@ -243,19 +327,29 @@ _shtab_ahriman_package_status_options=(
|
|||||||
"(*)::filter status by package base (default\: None):"
|
"(*)::filter status by package base (default\: None):"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_package_status_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_package_status_remove_options=(
|
_shtab_ahriman_package_status_remove_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
"(*):remove specified packages from status page:"
|
"(*):remove specified packages from status page:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_package_status_remove_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_package_status_update_options=(
|
_shtab_ahriman_package_status_update_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
{-s,--status}"[new package build status (default\: success)]:status:(unknown pending building failed success)"
|
{-s,--status}"[new package build status (default\: success)]:status:(unknown pending building failed success)"
|
||||||
"(*)::set status for specified packages. If no packages supplied, service status will be updated (default\: None):"
|
"(*)::set status for specified packages. If no packages supplied, service status will be updated (default\: None):"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_package_status_update_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_package_update_options=(
|
_shtab_ahriman_package_update_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
|
{--changes,--no-changes}"[calculate changes from the latest known commit if available (default\: True)]:changes:"
|
||||||
{--dependencies,--no-dependencies}"[process missing package dependencies (default\: True)]:dependencies:"
|
{--dependencies,--no-dependencies}"[process missing package dependencies (default\: True)]:dependencies:"
|
||||||
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
|
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
|
||||||
{--increment,--no-increment}"[increment package release (pkgrel) version on duplicate (default\: True)]:increment:"
|
{--increment,--no-increment}"[increment package release (pkgrel) version on duplicate (default\: True)]:increment:"
|
||||||
@@ -267,6 +361,9 @@ _shtab_ahriman_package_update_options=(
|
|||||||
"(*):package source (base name, path to local files, remote URL):"
|
"(*):package source (base name, path to local files, remote URL):"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_package_update_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_patch_add_options=(
|
_shtab_ahriman_patch_add_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
":package base:"
|
":package base:"
|
||||||
@@ -274,25 +371,37 @@ _shtab_ahriman_patch_add_options=(
|
|||||||
":path to file which contains function or variable value. If not set, the value will be read from stdin (default\: None):"
|
":path to file which contains function or variable value. If not set, the value will be read from stdin (default\: None):"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_patch_add_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_patch_list_options=(
|
_shtab_ahriman_patch_list_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
|
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
|
||||||
"*"{-v,--variable}"[if set, show only patches for specified PKGBUILD variables (default\: None)]:variable:"
|
"*"{-v,--variable}"[if set, show only patches for specified PKGBUILD variables (default\: None)]:variable:"
|
||||||
":package base (default\: None):"
|
":package base:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_patch_list_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_patch_remove_options=(
|
_shtab_ahriman_patch_remove_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
"*"{-v,--variable}"[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 (default\: None)]:variable:"
|
"*"{-v,--variable}"[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 (default\: None)]:variable:"
|
||||||
":package base:"
|
":package base:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_patch_remove_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_patch_set_add_options=(
|
_shtab_ahriman_patch_set_add_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
"*"{-t,--track}"[files which has to be tracked (default\: \[\'\*.diff\', \'\*.patch\'\])]:track:"
|
"*"{-t,--track}"[files which has to be tracked (default\: \[\'\*.diff\', \'\*.patch\'\])]:track:"
|
||||||
":path to directory with changed files for patch addition\/update:"
|
":path to directory with changed files for patch addition\/update:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_patch_set_add_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_rebuild_options=(
|
_shtab_ahriman_rebuild_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
"*--depends-on[only rebuild packages that depend on specified packages (default\: None)]:depends_on:"
|
"*--depends-on[only rebuild packages that depend on specified packages (default\: None)]:depends_on:"
|
||||||
@@ -304,30 +413,46 @@ _shtab_ahriman_rebuild_options=(
|
|||||||
{-u,--username}"[build as user (default\: None)]:username:"
|
{-u,--username}"[build as user (default\: None)]:username:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_rebuild_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_remove_options=(
|
_shtab_ahriman_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:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_remove_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_remove_unknown_options=(
|
_shtab_ahriman_remove_unknown_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
"--dry-run[just perform check for packages without removal (default\: False)]"
|
"--dry-run[just perform check for packages without removal (default\: False)]"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_remove_unknown_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_repo_backup_options=(
|
_shtab_ahriman_repo_backup_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
":path of the output archive:"
|
":path of the output archive:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_repo_backup_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_repo_check_options=(
|
_shtab_ahriman_repo_check_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
{--changes,--no-changes}"[calculate changes from the latest known commit if available. Only applicable in dry run mode (default\: True)]:changes:"
|
{--changes,--no-changes}"[calculate changes from the latest known commit if available (default\: True)]:changes:"
|
||||||
|
{--check-files,--no-check-files}"[enable or disable checking of broken dependencies (e.g. dynamically linked libraries or modules directories) (default\: True)]:check_files:"
|
||||||
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
|
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
|
||||||
{--vcs,--no-vcs}"[fetch actual version of VCS packages (default\: True)]:vcs:"
|
{--vcs,--no-vcs}"[fetch actual version of VCS packages (default\: True)]:vcs:"
|
||||||
"*"{-y,--refresh}"[download fresh package databases from the mirror before actions, -yy to force refresh even if up to date (default\: False)]"
|
"*"{-y,--refresh}"[download fresh package databases from the mirror before actions, -yy to force refresh even if up to date (default\: False)]"
|
||||||
"(*)::filter check by package base (default\: None):"
|
"(*)::filter check by package base (default\: None):"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_repo_check_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_repo_clean_options=(
|
_shtab_ahriman_repo_clean_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
{--cache,--no-cache}"[clear directory with package caches (default\: False)]:cache:"
|
{--cache,--no-cache}"[clear directory with package caches (default\: False)]:cache:"
|
||||||
@@ -337,6 +462,9 @@ _shtab_ahriman_repo_clean_options=(
|
|||||||
{--pacman,--no-pacman}"[clear directory with pacman local database cache (default\: False)]:pacman:"
|
{--pacman,--no-pacman}"[clear directory with pacman local database cache (default\: False)]:pacman:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_repo_clean_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_repo_config_options=(
|
_shtab_ahriman_repo_config_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
{--info,--no-info}"[show additional information, e.g. configuration files (default\: True)]:info:"
|
{--info,--no-info}"[show additional information, e.g. configuration files (default\: True)]:info:"
|
||||||
@@ -345,24 +473,37 @@ _shtab_ahriman_repo_config_options=(
|
|||||||
":filter settings by key (default\: None):"
|
":filter settings by key (default\: None):"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_repo_config_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_repo_config_validate_options=(
|
_shtab_ahriman_repo_config_validate_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
{-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)]"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_repo_config_validate_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_repo_create_keyring_options=(
|
_shtab_ahriman_repo_create_keyring_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_repo_create_keyring_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_repo_create_mirrorlist_options=(
|
_shtab_ahriman_repo_create_mirrorlist_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_repo_create_mirrorlist_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_repo_daemon_options=(
|
_shtab_ahriman_repo_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:"
|
||||||
{--aur,--no-aur}"[enable or disable checking for AUR updates (default\: True)]:aur:"
|
{--aur,--no-aur}"[enable or disable checking for AUR updates (default\: True)]:aur:"
|
||||||
{--changes,--no-changes}"[calculate changes from the latest known commit if available. Only applicable in dry run mode (default\: True)]:changes:"
|
{--changes,--no-changes}"[calculate changes from the latest known commit if available. Only applicable in dry run mode (default\: True)]:changes:"
|
||||||
|
{--check-files,--no-check-files}"[enable or disable checking of broken dependencies (e.g. dynamically linked libraries or modules directories) (default\: True)]:check_files:"
|
||||||
{--dependencies,--no-dependencies}"[process missing package dependencies (default\: True)]:dependencies:"
|
{--dependencies,--no-dependencies}"[process missing package dependencies (default\: True)]:dependencies:"
|
||||||
"--dry-run[just perform check for updates, same as check command (default\: False)]"
|
"--dry-run[just perform check for updates, same as check command (default\: False)]"
|
||||||
{--increment,--no-increment}"[increment package release (pkgrel) on duplicate (default\: True)]:increment:"
|
{--increment,--no-increment}"[increment package release (pkgrel) on duplicate (default\: True)]:increment:"
|
||||||
@@ -374,6 +515,9 @@ _shtab_ahriman_repo_daemon_options=(
|
|||||||
"*"{-y,--refresh}"[download fresh package databases from the mirror before actions, -yy to force refresh even if up to date (default\: False)]"
|
"*"{-y,--refresh}"[download fresh package databases from the mirror before actions, -yy to force refresh even if up to date (default\: False)]"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_repo_daemon_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_repo_init_options=(
|
_shtab_ahriman_repo_init_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
"--build-as-user[force makepkg user to the specific one (default\: None)]:build_as_user:"
|
"--build-as-user[force makepkg user to the specific one (default\: None)]:build_as_user:"
|
||||||
@@ -382,7 +526,7 @@ _shtab_ahriman_repo_init_options=(
|
|||||||
{--makeflags-jobs,--no-makeflags-jobs}"[append MAKEFLAGS variable with parallelism set to number of cores (default\: True)]:makeflags_jobs:"
|
{--makeflags-jobs,--no-makeflags-jobs}"[append MAKEFLAGS variable with parallelism set to number of cores (default\: True)]:makeflags_jobs:"
|
||||||
"--mirror[use the specified explicitly mirror instead of including mirrorlist (default\: None)]:mirror:"
|
"--mirror[use the specified explicitly mirror instead of including mirrorlist (default\: None)]:mirror:"
|
||||||
{--multilib,--no-multilib}"[add or do not multilib repository (default\: True)]:multilib:"
|
{--multilib,--no-multilib}"[add or do not multilib repository (default\: True)]:multilib:"
|
||||||
"--packager[packager name and email (default\: None)]:packager:"
|
"--packager[packager name and email]:packager:"
|
||||||
"--server[server to be used for devtools. If none set, local files will be used (default\: None)]:server:"
|
"--server[server to be used for devtools. If none set, local files will be used (default\: None)]:server:"
|
||||||
"--sign-key[sign key id (default\: None)]:sign_key:"
|
"--sign-key[sign key id (default\: None)]:sign_key:"
|
||||||
"*--sign-target[sign options (default\: None)]:sign_target:(disabled packages repository)"
|
"*--sign-target[sign options (default\: None)]:sign_target:(disabled packages repository)"
|
||||||
@@ -390,6 +534,9 @@ _shtab_ahriman_repo_init_options=(
|
|||||||
"--web-unix-socket[path to unix socket used for interprocess communications (default\: None)]:web_unix_socket:"
|
"--web-unix-socket[path to unix socket used for interprocess communications (default\: None)]:web_unix_socket:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_repo_init_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_repo_rebuild_options=(
|
_shtab_ahriman_repo_rebuild_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
"*--depends-on[only rebuild packages that depend on specified packages (default\: None)]:depends_on:"
|
"*--depends-on[only rebuild packages that depend on specified packages (default\: None)]:depends_on:"
|
||||||
@@ -401,21 +548,33 @@ _shtab_ahriman_repo_rebuild_options=(
|
|||||||
{-u,--username}"[build as user (default\: None)]:username:"
|
{-u,--username}"[build as user (default\: None)]:username:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_repo_rebuild_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_repo_remove_unknown_options=(
|
_shtab_ahriman_repo_remove_unknown_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
"--dry-run[just perform check for packages without removal (default\: False)]"
|
"--dry-run[just perform check for packages without removal (default\: False)]"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_repo_remove_unknown_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_repo_report_options=(
|
_shtab_ahriman_repo_report_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_repo_report_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_repo_restore_options=(
|
_shtab_ahriman_repo_restore_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
{-o,--output}"[root path of the extracted files (default\: \/)]:output:"
|
{-o,--output}"[root path of the extracted files (default\: \/)]:output:"
|
||||||
":path of the input archive:"
|
":path of the input archive:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_repo_restore_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_repo_setup_options=(
|
_shtab_ahriman_repo_setup_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
"--build-as-user[force makepkg user to the specific one (default\: None)]:build_as_user:"
|
"--build-as-user[force makepkg user to the specific one (default\: None)]:build_as_user:"
|
||||||
@@ -424,7 +583,7 @@ _shtab_ahriman_repo_setup_options=(
|
|||||||
{--makeflags-jobs,--no-makeflags-jobs}"[append MAKEFLAGS variable with parallelism set to number of cores (default\: True)]:makeflags_jobs:"
|
{--makeflags-jobs,--no-makeflags-jobs}"[append MAKEFLAGS variable with parallelism set to number of cores (default\: True)]:makeflags_jobs:"
|
||||||
"--mirror[use the specified explicitly mirror instead of including mirrorlist (default\: None)]:mirror:"
|
"--mirror[use the specified explicitly mirror instead of including mirrorlist (default\: None)]:mirror:"
|
||||||
{--multilib,--no-multilib}"[add or do not multilib repository (default\: True)]:multilib:"
|
{--multilib,--no-multilib}"[add or do not multilib repository (default\: True)]:multilib:"
|
||||||
"--packager[packager name and email (default\: None)]:packager:"
|
"--packager[packager name and email]:packager:"
|
||||||
"--server[server to be used for devtools. If none set, local files will be used (default\: None)]:server:"
|
"--server[server to be used for devtools. If none set, local files will be used (default\: None)]:server:"
|
||||||
"--sign-key[sign key id (default\: None)]:sign_key:"
|
"--sign-key[sign key id (default\: None)]:sign_key:"
|
||||||
"*--sign-target[sign options (default\: None)]:sign_target:(disabled packages repository)"
|
"*--sign-target[sign options (default\: None)]:sign_target:(disabled packages repository)"
|
||||||
@@ -432,34 +591,67 @@ _shtab_ahriman_repo_setup_options=(
|
|||||||
"--web-unix-socket[path to unix socket used for interprocess communications (default\: None)]:web_unix_socket:"
|
"--web-unix-socket[path to unix socket used for interprocess communications (default\: None)]:web_unix_socket:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_repo_setup_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_repo_sign_options=(
|
_shtab_ahriman_repo_sign_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
"(*)::sign only specified packages (default\: None):"
|
"(*)::sign only specified packages (default\: None):"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_repo_sign_defaults_added=0
|
||||||
|
|
||||||
|
_shtab_ahriman_repo_statistics_options=(
|
||||||
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
|
"--chart[create updates chart and save it to the specified path (default\: None)]:chart:"
|
||||||
|
{-e,--event}"[event type filter (default\: package-updated)]:event:(package-outdated package-removed package-update-failed package-updated)"
|
||||||
|
"--from-date[only fetch events which are newer than the date (default\: None)]:from_date:"
|
||||||
|
"--limit[limit response by specified amount of events (default\: -1)]:limit:"
|
||||||
|
"--offset[skip specified amount of events (default\: 0)]:offset:"
|
||||||
|
"--to-date[only fetch events which are older than the date (default\: None)]:to_date:"
|
||||||
|
":fetch only events for the specified package (default\: None):"
|
||||||
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_repo_statistics_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_repo_status_update_options=(
|
_shtab_ahriman_repo_status_update_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
{-s,--status}"[new status (default\: success)]:status:(unknown pending building failed success)"
|
{-s,--status}"[new status (default\: success)]:status:(unknown pending building failed success)"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_repo_status_update_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_repo_sync_options=(
|
_shtab_ahriman_repo_sync_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_repo_sync_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_repo_tree_options=(
|
_shtab_ahriman_repo_tree_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
{-p,--partitions}"[also divide packages by independent partitions (default\: 1)]:partitions:"
|
{-p,--partitions}"[also divide packages by independent partitions (default\: 1)]:partitions:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_repo_tree_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_repo_triggers_options=(
|
_shtab_ahriman_repo_triggers_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
"(*)::instead of running all triggers as set by configuration, just process specified ones in order of mention (default\: None):"
|
"(*)::instead of running all triggers as set by configuration, just process specified ones in order of mention (default\: None):"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_repo_triggers_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_repo_update_options=(
|
_shtab_ahriman_repo_update_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
{--aur,--no-aur}"[enable or disable checking for AUR updates (default\: True)]:aur:"
|
{--aur,--no-aur}"[enable or disable checking for AUR updates (default\: True)]:aur:"
|
||||||
{--changes,--no-changes}"[calculate changes from the latest known commit if available. Only applicable in dry run mode (default\: True)]:changes:"
|
{--changes,--no-changes}"[calculate changes from the latest known commit if available. Only applicable in dry run mode (default\: True)]:changes:"
|
||||||
|
{--check-files,--no-check-files}"[enable or disable checking of broken dependencies (e.g. dynamically linked libraries or modules directories) (default\: True)]:check_files:"
|
||||||
{--dependencies,--no-dependencies}"[process missing package dependencies (default\: True)]:dependencies:"
|
{--dependencies,--no-dependencies}"[process missing package dependencies (default\: True)]:dependencies:"
|
||||||
"--dry-run[just perform check for updates, same as check command (default\: False)]"
|
"--dry-run[just perform check for updates, same as check command (default\: False)]"
|
||||||
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
|
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
|
||||||
@@ -472,15 +664,24 @@ _shtab_ahriman_repo_update_options=(
|
|||||||
"(*)::filter check by package base (default\: None):"
|
"(*)::filter check by package base (default\: None):"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_repo_update_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_report_options=(
|
_shtab_ahriman_report_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_report_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_run_options=(
|
_shtab_ahriman_run_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
"(*):command to be run (quoted) without \`\`ahriman\`\`:"
|
"(*):command to be run (quoted) without \`\`ahriman\`\`:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_run_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_search_options=(
|
_shtab_ahriman_search_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
|
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
|
||||||
@@ -489,6 +690,9 @@ _shtab_ahriman_search_options=(
|
|||||||
"(*):search terms, can be specified multiple times, the result will match all terms:"
|
"(*):search terms, can be specified multiple times, the result will match all terms:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_search_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_service_clean_options=(
|
_shtab_ahriman_service_clean_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
{--cache,--no-cache}"[clear directory with package caches (default\: False)]:cache:"
|
{--cache,--no-cache}"[clear directory with package caches (default\: False)]:cache:"
|
||||||
@@ -498,6 +702,9 @@ _shtab_ahriman_service_clean_options=(
|
|||||||
{--pacman,--no-pacman}"[clear directory with pacman local database cache (default\: False)]:pacman:"
|
{--pacman,--no-pacman}"[clear directory with pacman local database cache (default\: False)]:pacman:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_service_clean_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_service_config_options=(
|
_shtab_ahriman_service_config_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
{--info,--no-info}"[show additional information, e.g. configuration files (default\: True)]:info:"
|
{--info,--no-info}"[show additional information, e.g. configuration files (default\: True)]:info:"
|
||||||
@@ -506,27 +713,42 @@ _shtab_ahriman_service_config_options=(
|
|||||||
":filter settings by key (default\: None):"
|
":filter settings by key (default\: None):"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_service_config_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_service_config_validate_options=(
|
_shtab_ahriman_service_config_validate_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
{-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)]"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_service_config_validate_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_service_key_import_options=(
|
_shtab_ahriman_service_key_import_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
"--key-server[key server for key import (default\: keyserver.ubuntu.com)]:key_server:"
|
"--key-server[key server for key import (default\: keyserver.ubuntu.com)]:key_server:"
|
||||||
":PGP key to import from public server:"
|
":PGP key to import from public server:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_service_key_import_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_service_repositories_options=(
|
_shtab_ahriman_service_repositories_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
{--id-only,--no-id-only}"[show machine readable identifier instead (default\: False)]:id_only:"
|
{--id-only,--no-id-only}"[show machine readable identifier instead (default\: False)]:id_only:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_service_repositories_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_service_run_options=(
|
_shtab_ahriman_service_run_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
"(*):command to be run (quoted) without \`\`ahriman\`\`:"
|
"(*):command to be run (quoted) without \`\`ahriman\`\`:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_service_run_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_service_setup_options=(
|
_shtab_ahriman_service_setup_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
"--build-as-user[force makepkg user to the specific one (default\: None)]:build_as_user:"
|
"--build-as-user[force makepkg user to the specific one (default\: None)]:build_as_user:"
|
||||||
@@ -535,7 +757,7 @@ _shtab_ahriman_service_setup_options=(
|
|||||||
{--makeflags-jobs,--no-makeflags-jobs}"[append MAKEFLAGS variable with parallelism set to number of cores (default\: True)]:makeflags_jobs:"
|
{--makeflags-jobs,--no-makeflags-jobs}"[append MAKEFLAGS variable with parallelism set to number of cores (default\: True)]:makeflags_jobs:"
|
||||||
"--mirror[use the specified explicitly mirror instead of including mirrorlist (default\: None)]:mirror:"
|
"--mirror[use the specified explicitly mirror instead of including mirrorlist (default\: None)]:mirror:"
|
||||||
{--multilib,--no-multilib}"[add or do not multilib repository (default\: True)]:multilib:"
|
{--multilib,--no-multilib}"[add or do not multilib repository (default\: True)]:multilib:"
|
||||||
"--packager[packager name and email (default\: None)]:packager:"
|
"--packager[packager name and email]:packager:"
|
||||||
"--server[server to be used for devtools. If none set, local files will be used (default\: None)]:server:"
|
"--server[server to be used for devtools. If none set, local files will be used (default\: None)]:server:"
|
||||||
"--sign-key[sign key id (default\: None)]:sign_key:"
|
"--sign-key[sign key id (default\: None)]:sign_key:"
|
||||||
"*--sign-target[sign options (default\: None)]:sign_target:(disabled packages repository)"
|
"*--sign-target[sign options (default\: None)]:sign_target:(disabled packages repository)"
|
||||||
@@ -543,15 +765,25 @@ _shtab_ahriman_service_setup_options=(
|
|||||||
"--web-unix-socket[path to unix socket used for interprocess communications (default\: None)]:web_unix_socket:"
|
"--web-unix-socket[path to unix socket used for interprocess communications (default\: None)]:web_unix_socket:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_service_setup_defaults_added=0
|
||||||
|
|
||||||
_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):"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_service_shell_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_service_tree_migrate_options=(
|
_shtab_ahriman_service_tree_migrate_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_service_tree_migrate_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_setup_options=(
|
_shtab_ahriman_setup_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
"--build-as-user[force makepkg user to the specific one (default\: None)]:build_as_user:"
|
"--build-as-user[force makepkg user to the specific one (default\: None)]:build_as_user:"
|
||||||
@@ -560,7 +792,7 @@ _shtab_ahriman_setup_options=(
|
|||||||
{--makeflags-jobs,--no-makeflags-jobs}"[append MAKEFLAGS variable with parallelism set to number of cores (default\: True)]:makeflags_jobs:"
|
{--makeflags-jobs,--no-makeflags-jobs}"[append MAKEFLAGS variable with parallelism set to number of cores (default\: True)]:makeflags_jobs:"
|
||||||
"--mirror[use the specified explicitly mirror instead of including mirrorlist (default\: None)]:mirror:"
|
"--mirror[use the specified explicitly mirror instead of including mirrorlist (default\: None)]:mirror:"
|
||||||
{--multilib,--no-multilib}"[add or do not multilib repository (default\: True)]:multilib:"
|
{--multilib,--no-multilib}"[add or do not multilib repository (default\: True)]:multilib:"
|
||||||
"--packager[packager name and email (default\: None)]:packager:"
|
"--packager[packager name and email]:packager:"
|
||||||
"--server[server to be used for devtools. If none set, local files will be used (default\: None)]:server:"
|
"--server[server to be used for devtools. If none set, local files will be used (default\: None)]:server:"
|
||||||
"--sign-key[sign key id (default\: None)]:sign_key:"
|
"--sign-key[sign key id (default\: None)]:sign_key:"
|
||||||
"*--sign-target[sign options (default\: None)]:sign_target:(disabled packages repository)"
|
"*--sign-target[sign options (default\: None)]:sign_target:(disabled packages repository)"
|
||||||
@@ -568,16 +800,26 @@ _shtab_ahriman_setup_options=(
|
|||||||
"--web-unix-socket[path to unix socket used for interprocess communications (default\: None)]:web_unix_socket:"
|
"--web-unix-socket[path to unix socket used for interprocess communications (default\: None)]:web_unix_socket:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_setup_defaults_added=0
|
||||||
|
|
||||||
_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):"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_shell_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_sign_options=(
|
_shtab_ahriman_sign_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
"(*)::sign only specified packages (default\: None):"
|
"(*)::sign only specified packages (default\: None):"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_sign_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_status_options=(
|
_shtab_ahriman_status_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
"--ahriman[get service status itself (default\: False)]"
|
"--ahriman[get service status itself (default\: False)]"
|
||||||
@@ -587,20 +829,30 @@ _shtab_ahriman_status_options=(
|
|||||||
"(*)::filter status by package base (default\: None):"
|
"(*)::filter status by package base (default\: None):"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_status_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_status_update_options=(
|
_shtab_ahriman_status_update_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
{-s,--status}"[new package build status (default\: success)]:status:(unknown pending building failed success)"
|
{-s,--status}"[new package build status (default\: success)]:status:(unknown pending building failed success)"
|
||||||
"(*)::set status for specified packages. If no packages supplied, service status will be updated (default\: None):"
|
"(*)::set status for specified packages. If no packages supplied, service status will be updated (default\: None):"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_status_update_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_sync_options=(
|
_shtab_ahriman_sync_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_sync_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_update_options=(
|
_shtab_ahriman_update_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
{--aur,--no-aur}"[enable or disable checking for AUR updates (default\: True)]:aur:"
|
{--aur,--no-aur}"[enable or disable checking for AUR updates (default\: True)]:aur:"
|
||||||
{--changes,--no-changes}"[calculate changes from the latest known commit if available. Only applicable in dry run mode (default\: True)]:changes:"
|
{--changes,--no-changes}"[calculate changes from the latest known commit if available. Only applicable in dry run mode (default\: True)]:changes:"
|
||||||
|
{--check-files,--no-check-files}"[enable or disable checking of broken dependencies (e.g. dynamically linked libraries or modules directories) (default\: True)]:check_files:"
|
||||||
{--dependencies,--no-dependencies}"[process missing package dependencies (default\: True)]:dependencies:"
|
{--dependencies,--no-dependencies}"[process missing package dependencies (default\: True)]:dependencies:"
|
||||||
"--dry-run[just perform check for updates, same as check command (default\: False)]"
|
"--dry-run[just perform check for updates, same as check command (default\: False)]"
|
||||||
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
|
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
|
||||||
@@ -613,6 +865,9 @@ _shtab_ahriman_update_options=(
|
|||||||
"(*)::filter check by package base (default\: None):"
|
"(*)::filter check by package base (default\: None):"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_update_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_user_add_options=(
|
_shtab_ahriman_user_add_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
"--key[optional PGP key used by this user. The private key must be imported (default\: None)]:key:"
|
"--key[optional PGP key used by this user. The private key must be imported (default\: None)]:key:"
|
||||||
@@ -622,6 +877,9 @@ _shtab_ahriman_user_add_options=(
|
|||||||
":username for web service:"
|
":username for web service:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_user_add_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_user_list_options=(
|
_shtab_ahriman_user_list_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
|
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
|
||||||
@@ -629,25 +887,48 @@ _shtab_ahriman_user_list_options=(
|
|||||||
":filter users by username (default\: None):"
|
":filter users by username (default\: None):"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_user_list_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_user_remove_options=(
|
_shtab_ahriman_user_remove_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
":username for web service:"
|
":username for web service:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_user_remove_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_version_options=(
|
_shtab_ahriman_version_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_version_defaults_added=0
|
||||||
|
|
||||||
_shtab_ahriman_web_options=(
|
_shtab_ahriman_web_options=(
|
||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_web_defaults_added=0
|
||||||
|
|
||||||
|
_shtab_ahriman_web_reload_options=(
|
||||||
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
|
)
|
||||||
|
|
||||||
|
# guard to ensure default positional specs are added only once per session
|
||||||
|
_shtab_ahriman_web_reload_defaults_added=0
|
||||||
|
|
||||||
|
|
||||||
_shtab_ahriman() {
|
_shtab_ahriman() {
|
||||||
local context state line curcontext="$curcontext" one_or_more='(-)*' remainder='(*)'
|
local context state line curcontext="$curcontext" one_or_more='(*)' remainder='(-)*' default='*::: :->ahriman'
|
||||||
|
|
||||||
if ((${_shtab_ahriman_options[(I)${(q)one_or_more}*]} + ${_shtab_ahriman_options[(I)${(q)remainder}*]} == 0)); then # noqa: E501
|
# Add default positional/remainder specs only if none exist, and only once per session
|
||||||
_shtab_ahriman_options+=(': :_shtab_ahriman_commands' '*::: :->ahriman')
|
if (( ! _shtab_ahriman_defaults_added )); then
|
||||||
|
if (( ${_shtab_ahriman_options[(I)${(q)one_or_more}*]} + ${_shtab_ahriman_options[(I)${(q)remainder}*]} + ${_shtab_ahriman_options[(I)${(q)default}]} == 0 )); then
|
||||||
|
_shtab_ahriman_options+=(': :_shtab_ahriman_commands' '*::: :->ahriman')
|
||||||
|
fi
|
||||||
|
_shtab_ahriman_defaults_added=1
|
||||||
fi
|
fi
|
||||||
_arguments -C -s $_shtab_ahriman_options
|
_arguments -C -s $_shtab_ahriman_options
|
||||||
|
|
||||||
@@ -663,6 +944,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 ;;
|
||||||
@@ -673,6 +955,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 ;;
|
||||||
@@ -700,6 +983,7 @@ _shtab_ahriman() {
|
|||||||
repo-restore) _arguments -C -s $_shtab_ahriman_repo_restore_options ;;
|
repo-restore) _arguments -C -s $_shtab_ahriman_repo_restore_options ;;
|
||||||
repo-setup) _arguments -C -s $_shtab_ahriman_repo_setup_options ;;
|
repo-setup) _arguments -C -s $_shtab_ahriman_repo_setup_options ;;
|
||||||
repo-sign) _arguments -C -s $_shtab_ahriman_repo_sign_options ;;
|
repo-sign) _arguments -C -s $_shtab_ahriman_repo_sign_options ;;
|
||||||
|
repo-statistics) _arguments -C -s $_shtab_ahriman_repo_statistics_options ;;
|
||||||
repo-status-update) _arguments -C -s $_shtab_ahriman_repo_status_update_options ;;
|
repo-status-update) _arguments -C -s $_shtab_ahriman_repo_status_update_options ;;
|
||||||
repo-sync) _arguments -C -s $_shtab_ahriman_repo_sync_options ;;
|
repo-sync) _arguments -C -s $_shtab_ahriman_repo_sync_options ;;
|
||||||
repo-tree) _arguments -C -s $_shtab_ahriman_repo_tree_options ;;
|
repo-tree) _arguments -C -s $_shtab_ahriman_repo_tree_options ;;
|
||||||
@@ -729,6 +1013,7 @@ _shtab_ahriman() {
|
|||||||
user-remove) _arguments -C -s $_shtab_ahriman_user_remove_options ;;
|
user-remove) _arguments -C -s $_shtab_ahriman_user_remove_options ;;
|
||||||
version) _arguments -C -s $_shtab_ahriman_version_options ;;
|
version) _arguments -C -s $_shtab_ahriman_version_options ;;
|
||||||
web) _arguments -C -s $_shtab_ahriman_web_options ;;
|
web) _arguments -C -s $_shtab_ahriman_web_options ;;
|
||||||
|
web-reload) _arguments -C -s $_shtab_ahriman_web_reload_options ;;
|
||||||
esac
|
esac
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
@@ -736,4 +1021,12 @@ _shtab_ahriman() {
|
|||||||
|
|
||||||
|
|
||||||
typeset -A opt_args
|
typeset -A opt_args
|
||||||
_shtab_ahriman "$@"
|
|
||||||
|
if [[ $zsh_eval_context[-1] == eval ]]; then
|
||||||
|
# eval/source/. command, register function for later
|
||||||
|
compdef _shtab_ahriman -N ahriman
|
||||||
|
else
|
||||||
|
# autoload from fpath, call function directly
|
||||||
|
_shtab_ahriman "$@"
|
||||||
|
fi
|
||||||
|
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
[build-system]
|
||||||
|
requires = ["hatchling"]
|
||||||
|
build-backend = "hatchling.build"
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "ahriman-core"
|
||||||
|
description = "ArcH linux ReposItory MANager, core package"
|
||||||
|
readme = "../README.md"
|
||||||
|
requires-python = ">=3.13"
|
||||||
|
license = {file = "../COPYING"}
|
||||||
|
authors = [
|
||||||
|
{name = "ahriman team"},
|
||||||
|
]
|
||||||
|
dependencies = [
|
||||||
|
"bcrypt",
|
||||||
|
"filelock",
|
||||||
|
"inflection",
|
||||||
|
"pyelftools",
|
||||||
|
"requests",
|
||||||
|
]
|
||||||
|
dynamic = ["version"]
|
||||||
|
|
||||||
|
[project.optional-dependencies]
|
||||||
|
journald = [
|
||||||
|
"systemd-python",
|
||||||
|
]
|
||||||
|
# FIXME technically this dependency is required, but in some cases we do not have access to
|
||||||
|
# the libalpm which is required in order to install the package. Thus in case if we do not
|
||||||
|
# really need to run the application we can move it to "optional" dependencies
|
||||||
|
pacman = [
|
||||||
|
"pyalpm",
|
||||||
|
]
|
||||||
|
reports = [
|
||||||
|
"Jinja2",
|
||||||
|
]
|
||||||
|
s3 = [
|
||||||
|
"boto3",
|
||||||
|
]
|
||||||
|
shell = [
|
||||||
|
"IPython",
|
||||||
|
]
|
||||||
|
stats = [
|
||||||
|
"matplotlib",
|
||||||
|
]
|
||||||
|
unixsocket = [
|
||||||
|
"requests-unixsocket2",
|
||||||
|
]
|
||||||
|
validator = [
|
||||||
|
"cerberus",
|
||||||
|
]
|
||||||
|
|
||||||
|
[project.scripts]
|
||||||
|
ahriman = "ahriman.application.ahriman:run"
|
||||||
|
|
||||||
|
[project.urls]
|
||||||
|
Documentation = "https://ahriman.readthedocs.io/"
|
||||||
|
Repository = "https://github.com/arcan1s/ahriman"
|
||||||
|
Changelog = "https://github.com/arcan1s/ahriman/releases"
|
||||||
|
|
||||||
|
[tool.hatch.version]
|
||||||
|
path = "src/ahriman/__init__.py"
|
||||||
|
|
||||||
|
[tool.hatch.build.targets.wheel]
|
||||||
|
packages = ["src/ahriman"]
|
||||||
|
|
||||||
|
[tool.hatch.build.targets.wheel.shared-data]
|
||||||
|
"package/lib" = "lib"
|
||||||
|
"package/share" = "share"
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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.13.4"
|
__version__ = "2.20.0"
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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).
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2026 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 pathlib import Path
|
||||||
|
|
||||||
|
import ahriman.application.handlers
|
||||||
|
|
||||||
|
from ahriman import __version__
|
||||||
|
from ahriman.application.handlers.handler import Handler
|
||||||
|
from ahriman.application.help_formatter import _HelpFormatter
|
||||||
|
from ahriman.core.module_loader import implementations
|
||||||
|
from ahriman.core.utils import enum_values
|
||||||
|
from ahriman.models.log_handler import LogHandler
|
||||||
|
|
||||||
|
|
||||||
|
__all__: list[str] = []
|
||||||
|
|
||||||
|
|
||||||
|
def _parser() -> argparse.ArgumentParser:
|
||||||
|
"""
|
||||||
|
command line parser generator
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: command line parser for the application
|
||||||
|
"""
|
||||||
|
parser = argparse.ArgumentParser(prog="ahriman", description="ArcH linux ReposItory MANager",
|
||||||
|
epilog="""
|
||||||
|
Quick setup command (replace repository name, architecture and packager as needed):
|
||||||
|
|
||||||
|
>>> ahriman -a x86_64 -r aur service-setup --packager "ahriman bot <ahriman@example.com>"
|
||||||
|
|
||||||
|
Add new package from AUR:
|
||||||
|
|
||||||
|
>>> ahriman package-add ahriman --now
|
||||||
|
|
||||||
|
Check for updates and build out-of-dated packages (add ``--dry-run`` to build it later):
|
||||||
|
|
||||||
|
>>> ahriman repo-update
|
||||||
|
|
||||||
|
Remove package from the repository:
|
||||||
|
|
||||||
|
>>> ahriman package-remove ahriman
|
||||||
|
|
||||||
|
Start web service (requires additional configuration):
|
||||||
|
|
||||||
|
>>> ahriman web
|
||||||
|
""",
|
||||||
|
fromfile_prefix_chars="@", formatter_class=_HelpFormatter)
|
||||||
|
parser.add_argument("-a", "--architecture", help="filter by target architecture")
|
||||||
|
parser.add_argument("-c", "--configuration", help="configuration path", type=Path,
|
||||||
|
default=Path("/") / "etc" / "ahriman.ini")
|
||||||
|
parser.add_argument("--force", help="force run, remove file lock", action="store_true")
|
||||||
|
parser.add_argument("-l", "--lock", help="lock file", type=Path, default=Path("ahriman.pid"))
|
||||||
|
parser.add_argument("--log-handler", help="explicit log handler specification. If none set, the handler will be "
|
||||||
|
"guessed from environment",
|
||||||
|
type=LogHandler, choices=enum_values(LogHandler))
|
||||||
|
parser.add_argument("-q", "--quiet", help="force disable any logging", action="store_true")
|
||||||
|
parser.add_argument("--report", help="force enable or disable reporting to web service",
|
||||||
|
action=argparse.BooleanOptionalAction, default=True)
|
||||||
|
parser.add_argument("-r", "--repository", help="filter by target repository")
|
||||||
|
# special secret argument for systemd unit. The issue is that systemd doesn't allow multiple arguments to template
|
||||||
|
# name. This parameter accepts [[arch]-repo] in order to keep backward compatibility
|
||||||
|
parser.add_argument("--repository-id", help=argparse.SUPPRESS)
|
||||||
|
parser.add_argument("--unsafe", help="allow to run ahriman as non-ahriman user. Some actions might be unavailable",
|
||||||
|
action="store_true")
|
||||||
|
parser.add_argument("-V", "--version", action="version", version=__version__)
|
||||||
|
parser.add_argument("--wait-timeout", help="wait for lock to be free. Negative value will lead to "
|
||||||
|
"immediate application run even if there is lock file. "
|
||||||
|
"In case of zero value, the application will wait infinitely",
|
||||||
|
type=int, default=-1)
|
||||||
|
|
||||||
|
subparsers = parser.add_subparsers(title="command", help="command to run", dest="command")
|
||||||
|
|
||||||
|
for handler in implementations(ahriman.application.handlers, Handler):
|
||||||
|
for subparser_parser in handler.arguments:
|
||||||
|
subparser = subparser_parser(subparsers)
|
||||||
|
subparser.formatter_class = _HelpFormatter
|
||||||
|
subparser.set_defaults(handler=handler, parser=_parser)
|
||||||
|
|
||||||
|
# sort actions alphabetically in both choices and help message
|
||||||
|
# pylint: disable=protected-access
|
||||||
|
subparsers._choices_actions = sorted(subparsers._choices_actions, key=lambda action: action.dest)
|
||||||
|
subparsers.choices = dict(sorted(subparsers.choices.items()))
|
||||||
|
|
||||||
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
def run() -> int:
|
||||||
|
"""
|
||||||
|
run application instance
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: application status code
|
||||||
|
"""
|
||||||
|
parser = _parser()
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.command is None: # in case of empty command we would like to print help message
|
||||||
|
parser.exit(status=2, message=parser.format_help())
|
||||||
|
|
||||||
|
handler: Handler = args.handler
|
||||||
|
return handler.execute(args)
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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).
|
||||||
+44
-33
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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).
|
||||||
@@ -62,10 +62,13 @@ class Application(ApplicationPackages, ApplicationRepository):
|
|||||||
"""
|
"""
|
||||||
known_packages: set[str] = set()
|
known_packages: set[str] = set()
|
||||||
# local set
|
# local set
|
||||||
|
# this action is not really needed in case if ``alpm.use_ahriman_cache`` set to yes, because pacman
|
||||||
|
# will eventually contain all the local packages
|
||||||
for base in self.repository.packages():
|
for base in self.repository.packages():
|
||||||
for package, properties in base.packages.items():
|
for package, properties in base.packages.items():
|
||||||
known_packages.add(package)
|
known_packages.add(package)
|
||||||
known_packages.update(properties.provides)
|
known_packages.update(properties.provides)
|
||||||
|
# known pacman databases
|
||||||
known_packages.update(self.repository.pacman.packages())
|
known_packages.update(self.repository.pacman.packages())
|
||||||
return known_packages
|
return known_packages
|
||||||
|
|
||||||
@@ -114,11 +117,10 @@ 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
|
list[Package]: updated packages list. Packager for dependencies will be copied from the original package
|
||||||
original package
|
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
In the most cases, in order to avoid build failure, it is required to add missing packages, which can be
|
In the most cases, in order to avoid build failure, it is required to add missing packages, which can be
|
||||||
@@ -128,38 +130,47 @@ 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)
|
||||||
"""
|
"""
|
||||||
def missing_dependencies(source: Iterable[Package]) -> dict[str, str | None]:
|
|
||||||
# append list of known packages with packages which are in current sources
|
|
||||||
satisfied_packages = known_packages | {
|
|
||||||
single
|
|
||||||
for package in source
|
|
||||||
for single in package.packages_full
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
dependency: package.packager
|
|
||||||
for package in source
|
|
||||||
for dependency in package.depends_build
|
|
||||||
if dependency not in satisfied_packages
|
|
||||||
}
|
|
||||||
|
|
||||||
if not process_dependencies or not packages:
|
if not process_dependencies or not packages:
|
||||||
return packages
|
return packages
|
||||||
|
|
||||||
|
def missing_dependencies(sources: Iterable[Package]) -> dict[str, str | None]:
|
||||||
|
# append list of known packages with packages which are in current sources
|
||||||
|
satisfied_packages = known_packages | {
|
||||||
|
single
|
||||||
|
for source in sources
|
||||||
|
for single in source.packages_full
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
dependency: source.packager
|
||||||
|
for source in sources
|
||||||
|
for dependency in source.depends_build
|
||||||
|
if dependency not in satisfied_packages
|
||||||
|
}
|
||||||
|
|
||||||
|
def new_packages(root: Package) -> dict[str, Package]:
|
||||||
|
portion = {root.base: root}
|
||||||
|
while missing := missing_dependencies(portion.values()):
|
||||||
|
for package_name, packager in missing.items():
|
||||||
|
if (source_dir := self.repository.paths.cache_for(package_name)).is_dir():
|
||||||
|
# there is local cache, load package from it
|
||||||
|
leaf = Package.from_build(source_dir, self.repository.repository_id.architecture, packager)
|
||||||
|
else:
|
||||||
|
leaf = Package.from_aur(package_name, packager, include_provides=True)
|
||||||
|
portion[leaf.base] = leaf
|
||||||
|
|
||||||
|
# register package in the database
|
||||||
|
self.reporter.set_unknown(leaf)
|
||||||
|
|
||||||
|
return portion
|
||||||
|
|
||||||
known_packages = self._known_packages()
|
known_packages = self._known_packages()
|
||||||
with_dependencies = {package.base: package for package in packages}
|
with_dependencies: dict[str, Package] = {}
|
||||||
|
for package in packages:
|
||||||
while missing := missing_dependencies(with_dependencies.values()):
|
with self.in_package_context(package.base, package.version): # use the same context for the logger
|
||||||
for package_name, username in missing.items():
|
try:
|
||||||
if (source_dir := self.repository.paths.cache_for(package_name)).is_dir():
|
with_dependencies |= new_packages(package)
|
||||||
# there is local cache, load package from it
|
except Exception:
|
||||||
package = Package.from_build(source_dir, self.repository.architecture, username)
|
self.logger.exception("could not process dependencies of %s, skip the package", package.base)
|
||||||
else:
|
|
||||||
package = Package.from_aur(package_name, username)
|
|
||||||
with_dependencies[package.base] = package
|
|
||||||
|
|
||||||
# register package in local database
|
|
||||||
self.database.package_base_update(package)
|
|
||||||
self.repository.reporter.set_unknown(package)
|
|
||||||
|
|
||||||
return list(with_dependencies.values())
|
return list(with_dependencies.values())
|
||||||
+12
-12
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 ahriman team.
|
||||||
#
|
#
|
||||||
# This file is part of ahriman
|
# This file is part of ahriman
|
||||||
# (see https://github.com/arcan1s/ahriman).
|
# (see https://github.com/arcan1s/ahriman).
|
||||||
@@ -27,7 +27,7 @@ from typing import Any
|
|||||||
from ahriman.application.application.application_properties import ApplicationProperties
|
from ahriman.application.application.application_properties import ApplicationProperties
|
||||||
from ahriman.core.build_tools.sources import Sources
|
from ahriman.core.build_tools.sources import Sources
|
||||||
from ahriman.core.exceptions import UnknownPackageError
|
from ahriman.core.exceptions import UnknownPackageError
|
||||||
from ahriman.core.util import package_like
|
from ahriman.core.utils import package_like
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
from ahriman.models.package_source import PackageSource
|
from ahriman.models.package_source import PackageSource
|
||||||
from ahriman.models.result import Result
|
from ahriman.models.result import Result
|
||||||
@@ -65,7 +65,7 @@ class ApplicationPackages(ApplicationProperties):
|
|||||||
"""
|
"""
|
||||||
package = Package.from_aur(source, username)
|
package = Package.from_aur(source, username)
|
||||||
self.database.build_queue_insert(package)
|
self.database.build_queue_insert(package)
|
||||||
self.database.package_base_update(package)
|
self.reporter.set_unknown(package)
|
||||||
|
|
||||||
def _add_directory(self, source: str, *_: Any) -> None:
|
def _add_directory(self, source: str, *_: Any) -> None:
|
||||||
"""
|
"""
|
||||||
@@ -139,21 +139,21 @@ class ApplicationPackages(ApplicationProperties):
|
|||||||
"""
|
"""
|
||||||
package = Package.from_official(source, self.repository.pacman, username)
|
package = Package.from_official(source, self.repository.pacman, username)
|
||||||
self.database.build_queue_insert(package)
|
self.database.build_queue_insert(package)
|
||||||
self.database.package_base_update(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
|
||||||
+12
-3
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 ahriman team.
|
||||||
#
|
#
|
||||||
# This file is part of ahriman
|
# This file is part of ahriman
|
||||||
# (see https://github.com/arcan1s/ahriman).
|
# (see https://github.com/arcan1s/ahriman).
|
||||||
@@ -21,6 +21,7 @@ from ahriman.core.configuration import Configuration
|
|||||||
from ahriman.core.database import SQLite
|
from ahriman.core.database import SQLite
|
||||||
from ahriman.core.log import LazyLogging
|
from ahriman.core.log import LazyLogging
|
||||||
from ahriman.core.repository import Repository
|
from ahriman.core.repository import Repository
|
||||||
|
from ahriman.core.status import Client
|
||||||
from ahriman.models.pacman_synchronization import PacmanSynchronization
|
from ahriman.models.pacman_synchronization import PacmanSynchronization
|
||||||
from ahriman.models.repository_id import RepositoryId
|
from ahriman.models.repository_id import RepositoryId
|
||||||
|
|
||||||
@@ -39,8 +40,6 @@ class ApplicationProperties(LazyLogging):
|
|||||||
def __init__(self, repository_id: RepositoryId, configuration: Configuration, *, report: bool,
|
def __init__(self, repository_id: RepositoryId, configuration: Configuration, *, report: bool,
|
||||||
refresh_pacman_database: PacmanSynchronization = PacmanSynchronization.Disabled) -> None:
|
refresh_pacman_database: PacmanSynchronization = PacmanSynchronization.Disabled) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
repository_id(RepositoryId): repository unique identifier
|
repository_id(RepositoryId): repository unique identifier
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
@@ -63,3 +62,13 @@ class ApplicationProperties(LazyLogging):
|
|||||||
str: repository architecture
|
str: repository architecture
|
||||||
"""
|
"""
|
||||||
return self.repository_id.architecture
|
return self.repository_id.architecture
|
||||||
|
|
||||||
|
@property
|
||||||
|
def reporter(self) -> Client:
|
||||||
|
"""
|
||||||
|
instance of the web/database client
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Client: repository reposter
|
||||||
|
"""
|
||||||
|
return self.repository.reporter
|
||||||
+22
-14
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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 @@ from collections.abc import Iterable
|
|||||||
from ahriman.application.application.application_properties import ApplicationProperties
|
from ahriman.application.application.application_properties import ApplicationProperties
|
||||||
from ahriman.application.application.workers import Updater
|
from ahriman.application.application.workers import Updater
|
||||||
from ahriman.core.build_tools.sources import Sources
|
from ahriman.core.build_tools.sources import Sources
|
||||||
|
from ahriman.core.exceptions import UnknownPackageError
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
from ahriman.models.packagers import Packagers
|
from ahriman.models.packagers import Packagers
|
||||||
from ahriman.models.result import Result
|
from ahriman.models.result import Result
|
||||||
@@ -39,15 +40,13 @@ class ApplicationRepository(ApplicationProperties):
|
|||||||
Args:
|
Args:
|
||||||
packages(Iterable[Package]): list of packages to retrieve changes
|
packages(Iterable[Package]): list of packages to retrieve changes
|
||||||
"""
|
"""
|
||||||
last_commit_hashes = self.database.hashes_get()
|
|
||||||
|
|
||||||
for package in packages:
|
for package in packages:
|
||||||
last_commit_sha = last_commit_hashes.get(package.base)
|
last_commit_sha = self.reporter.package_changes_get(package.base).last_commit_sha
|
||||||
if last_commit_sha is None:
|
if last_commit_sha is None:
|
||||||
continue # skip check in case if we can't calculate diff
|
continue # skip check in case if we can't calculate diff
|
||||||
|
|
||||||
changes = self.repository.package_changes(package, last_commit_sha)
|
if (changes := self.repository.package_changes(package, last_commit_sha)) is not None:
|
||||||
self.repository.reporter.package_changes_set(package.base, changes)
|
self.reporter.package_changes_update(package.base, changes)
|
||||||
|
|
||||||
def clean(self, *, cache: bool, chroot: bool, manual: bool, packages: bool, pacman: bool) -> None:
|
def clean(self, *, cache: bool, chroot: bool, manual: bool, packages: bool, pacman: bool) -> None:
|
||||||
"""
|
"""
|
||||||
@@ -91,10 +90,7 @@ class ApplicationRepository(ApplicationProperties):
|
|||||||
packages(Iterable[str]): only sign specified packages
|
packages(Iterable[str]): only sign specified packages
|
||||||
"""
|
"""
|
||||||
# copy to prebuilt directory
|
# copy to prebuilt directory
|
||||||
for package in self.repository.packages():
|
for package in self.repository.packages(packages):
|
||||||
# no one requested this package
|
|
||||||
if packages and package.base not in packages:
|
|
||||||
continue
|
|
||||||
for archive in package.packages.values():
|
for archive in package.packages.values():
|
||||||
if archive.filepath is None:
|
if archive.filepath is None:
|
||||||
self.logger.warning("filepath is empty for %s", package.base)
|
self.logger.warning("filepath is empty for %s", package.base)
|
||||||
@@ -121,7 +117,7 @@ class ApplicationRepository(ApplicationProperties):
|
|||||||
for single in probe.packages:
|
for single in probe.packages:
|
||||||
try:
|
try:
|
||||||
_ = Package.from_aur(single, None)
|
_ = Package.from_aur(single, None)
|
||||||
except Exception:
|
except UnknownPackageError:
|
||||||
packages.append(single)
|
packages.append(single)
|
||||||
return packages
|
return packages
|
||||||
|
|
||||||
@@ -160,12 +156,15 @@ class ApplicationRepository(ApplicationProperties):
|
|||||||
result = Result()
|
result = Result()
|
||||||
|
|
||||||
# process already built packages if any
|
# process already built packages if any
|
||||||
built_packages = self.repository.packages_built()
|
if built_packages := self.repository.packages_built(): # speedup a bit
|
||||||
if built_packages: # speedup a bit
|
|
||||||
build_result = self.repository.process_update(built_packages, packagers)
|
build_result = self.repository.process_update(built_packages, packagers)
|
||||||
self.on_result(build_result)
|
self.on_result(build_result)
|
||||||
result.merge(build_result)
|
result.merge(build_result)
|
||||||
|
|
||||||
|
# filter packages which were prebuilt
|
||||||
|
succeeded = {package.base for package in build_result.success}
|
||||||
|
updates = [package for package in updates if package.base not in succeeded]
|
||||||
|
|
||||||
builder = Updater.load(self.repository_id, self.configuration, self.repository)
|
builder = Updater.load(self.repository_id, self.configuration, self.repository)
|
||||||
|
|
||||||
# ok so for now we split all packages into chunks and process each chunk accordingly
|
# ok so for now we split all packages into chunks and process each chunk accordingly
|
||||||
@@ -179,7 +178,7 @@ class ApplicationRepository(ApplicationProperties):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
def updates(self, filter_packages: Iterable[str], *,
|
def updates(self, filter_packages: Iterable[str], *,
|
||||||
aur: bool, local: bool, manual: bool, vcs: bool) -> list[Package]:
|
aur: bool, local: bool, manual: bool, vcs: bool, check_files: bool) -> list[Package]:
|
||||||
"""
|
"""
|
||||||
get list of packages to run update process
|
get list of packages to run update process
|
||||||
|
|
||||||
@@ -189,17 +188,26 @@ class ApplicationRepository(ApplicationProperties):
|
|||||||
local(bool): enable or disable checking of local packages for updates
|
local(bool): enable or disable checking of local packages for updates
|
||||||
manual(bool): include or exclude manual updates
|
manual(bool): include or exclude manual updates
|
||||||
vcs(bool): enable or disable checking of VCS packages
|
vcs(bool): enable or disable checking of VCS packages
|
||||||
|
check_files(bool): check for broken dependencies
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
list[Package]: list of out-of-dated packages
|
list[Package]: list of out-of-dated packages
|
||||||
"""
|
"""
|
||||||
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:
|
||||||
updates.update({package.base: package for package in self.repository.updates_local(vcs=vcs)})
|
updates.update({package.base: package for package in self.repository.updates_local(vcs=vcs)})
|
||||||
if manual:
|
if manual:
|
||||||
updates.update({package.base: package for package in self.repository.updates_manual()})
|
updates.update({package.base: package for package in self.repository.updates_manual()})
|
||||||
|
if check_files:
|
||||||
|
updates.update({package.base: package for package in self.repository.updates_dependencies(filter_packages)})
|
||||||
|
|
||||||
return [package for _, package in sorted(updates.items())]
|
return [package for _, package in sorted(updates.items())]
|
||||||
+1
-3
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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).
|
||||||
@@ -49,8 +49,6 @@ class UpdatesIterator(Iterator[list[str] | None]):
|
|||||||
|
|
||||||
def __init__(self, application: Application, interval: int) -> None:
|
def __init__(self, application: Application, interval: int) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
application(Application): application instance
|
application(Application): application instance
|
||||||
interval(int): predefined interval for updates
|
interval(int): predefined interval for updates
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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).
|
||||||
+1
-3
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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).
|
||||||
@@ -37,8 +37,6 @@ class LocalUpdater(Updater):
|
|||||||
|
|
||||||
def __init__(self, repository: Repository) -> None:
|
def __init__(self, repository: Repository) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
repository(Repository): repository instance
|
repository(Repository): repository instance
|
||||||
"""
|
"""
|
||||||
+1
-3
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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).
|
||||||
@@ -43,8 +43,6 @@ class RemoteUpdater(Updater):
|
|||||||
|
|
||||||
def __init__(self, workers: list[Worker], repository_id: RepositoryId, configuration: Configuration) -> None:
|
def __init__(self, workers: list[Worker], repository_id: RepositoryId, configuration: Configuration) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
workers(list[Worker]): worker identifiers
|
workers(list[Worker]): worker identifiers
|
||||||
repository_id(RepositoryId): repository unique identifier
|
repository_id(RepositoryId): repository unique identifier
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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).
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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).
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2026 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.application.handlers.update import Update
|
||||||
|
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.pkgbuild_patch import PkgbuildPatch
|
||||||
|
from ahriman.models.repository_id import RepositoryId
|
||||||
|
|
||||||
|
|
||||||
|
class Add(Handler):
|
||||||
|
"""
|
||||||
|
add packages handler
|
||||||
|
"""
|
||||||
|
|
||||||
|
@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, refresh_pacman_database=args.refresh)
|
||||||
|
application.on_start()
|
||||||
|
Add.perform_action(application, args)
|
||||||
|
|
||||||
|
@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("-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")
|
||||||
|
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(aur=False, check_files=False, dry_run=False, local=False, manual=True, vcs=False)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def perform_action(application: Application, args: argparse.Namespace) -> None:
|
||||||
|
"""
|
||||||
|
perform add action
|
||||||
|
|
||||||
|
Args:
|
||||||
|
application(Application): application instance
|
||||||
|
args(argparse.Namespace): command line args
|
||||||
|
"""
|
||||||
|
application.add(args.package, args.source, args.username)
|
||||||
|
patches = [PkgbuildPatch.from_env(patch) for patch in args.variable] if args.variable is not None else []
|
||||||
|
for package in args.package: # for each requested package insert patch
|
||||||
|
for patch in patches:
|
||||||
|
application.reporter.package_patches_update(package, patch)
|
||||||
|
|
||||||
|
if not args.now:
|
||||||
|
return
|
||||||
|
Update.perform_action(application, args)
|
||||||
|
|
||||||
|
arguments = [_set_package_add_parser]
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2026 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.core.formatters import PackagePrinter
|
||||||
|
from ahriman.models.action import Action
|
||||||
|
from ahriman.models.build_status import BuildStatus, BuildStatusEnum
|
||||||
|
from ahriman.models.repository_id import RepositoryId
|
||||||
|
|
||||||
|
|
||||||
|
class Archives(Handler):
|
||||||
|
"""
|
||||||
|
package archives handler
|
||||||
|
"""
|
||||||
|
|
||||||
|
ALLOW_MULTI_ARCHITECTURE_RUN = False # conflicting io
|
||||||
|
|
||||||
|
@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=True)
|
||||||
|
|
||||||
|
match args.action:
|
||||||
|
case Action.List:
|
||||||
|
archives = application.repository.package_archives(args.package)
|
||||||
|
for package in archives:
|
||||||
|
PackagePrinter(package, BuildStatus(BuildStatusEnum.Success))(verbose=args.info)
|
||||||
|
|
||||||
|
Archives.check_status(args.exit_code, bool(archives))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _set_package_archives_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
|
"""
|
||||||
|
add parser for package archives subcommand
|
||||||
|
|
||||||
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
|
"""
|
||||||
|
parser = root.add_parser("package-archives", help="list package archive versions",
|
||||||
|
description="list available archive versions 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("--info", help="show additional package information",
|
||||||
|
action=argparse.BooleanOptionalAction, default=False)
|
||||||
|
parser.set_defaults(action=Action.List, lock=None, quiet=True, report=False, unsafe=True)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
arguments = [_set_package_archives_parser]
|
||||||
+31
-10
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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 pwd
|
import tarfile
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from tarfile import TarFile
|
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
|
||||||
@@ -49,10 +49,27 @@ class Backup(Handler):
|
|||||||
report(bool): force enable or disable reporting
|
report(bool): force enable or disable reporting
|
||||||
"""
|
"""
|
||||||
backup_paths = Backup.get_paths(configuration)
|
backup_paths = Backup.get_paths(configuration)
|
||||||
with TarFile(args.path, mode="w") as archive: # well we don't actually use compression
|
with tarfile.open(args.path, mode="w") as archive: # well we don't actually use compression
|
||||||
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]:
|
||||||
"""
|
"""
|
||||||
@@ -64,11 +81,13 @@ class Backup(Handler):
|
|||||||
Returns:
|
Returns:
|
||||||
set[Path]: map of the filesystem paths
|
set[Path]: map of the filesystem paths
|
||||||
"""
|
"""
|
||||||
paths = set(configuration.include.glob("*.ini"))
|
# configuration files
|
||||||
|
|
||||||
root, _ = configuration.check_loaded()
|
root, _ = configuration.check_loaded()
|
||||||
paths.add(root) # the configuration itself
|
paths = set(configuration.includes)
|
||||||
paths.add(SQLite.database_path(configuration)) # database
|
paths.add(root)
|
||||||
|
|
||||||
|
# database
|
||||||
|
paths.add(SQLite.database_path(configuration))
|
||||||
|
|
||||||
# local caches
|
# local caches
|
||||||
repository_paths = configuration.repository_paths
|
repository_paths = configuration.repository_paths
|
||||||
@@ -77,9 +96,11 @@ class Backup(Handler):
|
|||||||
|
|
||||||
# gnupg home with imported keys
|
# gnupg home with imported keys
|
||||||
uid, _ = repository_paths.root_owner
|
uid, _ = repository_paths.root_owner
|
||||||
system_user = pwd.getpwuid(uid)
|
system_user = getpwuid(uid)
|
||||||
gnupg_home = Path(system_user.pw_dir) / ".gnupg"
|
gnupg_home = Path(system_user.pw_dir) / ".gnupg"
|
||||||
if gnupg_home.is_dir():
|
if gnupg_home.is_dir():
|
||||||
paths.add(gnupg_home)
|
paths.add(gnupg_home)
|
||||||
|
|
||||||
return paths
|
return paths
|
||||||
|
|
||||||
|
arguments = [_set_repo_backup_parser]
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2026 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.core.formatters import ChangesPrinter
|
||||||
|
from ahriman.models.action import Action
|
||||||
|
from ahriman.models.changes import Changes
|
||||||
|
from ahriman.models.repository_id import RepositoryId
|
||||||
|
|
||||||
|
|
||||||
|
class Change(Handler):
|
||||||
|
"""
|
||||||
|
package changes handler
|
||||||
|
"""
|
||||||
|
|
||||||
|
ALLOW_MULTI_ARCHITECTURE_RUN = False # conflicting io
|
||||||
|
|
||||||
|
@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
|
||||||
|
"""
|
||||||
|
client = Application(repository_id, configuration, report=True).reporter
|
||||||
|
|
||||||
|
match args.action:
|
||||||
|
case Action.List:
|
||||||
|
changes = client.package_changes_get(args.package)
|
||||||
|
ChangesPrinter(changes)(verbose=True, separator="")
|
||||||
|
Change.check_status(args.exit_code, changes.changes is not None)
|
||||||
|
case Action.Remove:
|
||||||
|
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]
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2026 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.repository_id import RepositoryId
|
||||||
|
|
||||||
|
|
||||||
|
class Clean(Handler):
|
||||||
|
"""
|
||||||
|
clean caches handler
|
||||||
|
"""
|
||||||
|
|
||||||
|
@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()
|
||||||
|
application.clean(cache=args.cache, chroot=args.chroot, manual=args.manual, packages=args.packages,
|
||||||
|
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]
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2026 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]
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2026 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 pathlib import Path
|
||||||
|
|
||||||
|
from ahriman.application.application import Application
|
||||||
|
from ahriman.application.application.updates_iterator import FixedUpdatesIterator, UpdatesIterator
|
||||||
|
from ahriman.application.handlers.handler import Handler, SubParserAction
|
||||||
|
from ahriman.application.handlers.update import Update
|
||||||
|
from ahriman.core.configuration import Configuration
|
||||||
|
from ahriman.core.utils import extract_user
|
||||||
|
from ahriman.models.repository_id import RepositoryId
|
||||||
|
|
||||||
|
|
||||||
|
class Daemon(Handler):
|
||||||
|
"""
|
||||||
|
daemon packages handler
|
||||||
|
"""
|
||||||
|
|
||||||
|
@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, refresh_pacman_database=args.refresh)
|
||||||
|
if args.partitions:
|
||||||
|
iterator = UpdatesIterator(application, args.interval)
|
||||||
|
else:
|
||||||
|
iterator = FixedUpdatesIterator(application, args.interval)
|
||||||
|
|
||||||
|
for packages in iterator:
|
||||||
|
if packages is None:
|
||||||
|
continue # nothing to check case
|
||||||
|
|
||||||
|
args.package = packages
|
||||||
|
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]
|
||||||
+26
-2
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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]
|
||||||
+32
-37
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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,15 +20,24 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from collections.abc import Iterable
|
from collections.abc import Callable
|
||||||
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
|
||||||
from ahriman.core.exceptions import ExitCode, MissingArchitectureError, MultipleArchitecturesError
|
from ahriman.core.exceptions import ExitCode, MissingArchitectureError, MultipleArchitecturesError
|
||||||
from ahriman.core.log.log_loader import LogLoader
|
from ahriman.core.log.log_loader import LogLoader
|
||||||
|
from ahriman.core.repository import Explorer
|
||||||
|
from ahriman.core.types import ExplicitBool
|
||||||
from ahriman.models.repository_id import RepositoryId
|
from ahriman.models.repository_id import RepositoryId
|
||||||
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:
|
||||||
@@ -37,17 +46,20 @@ class Handler:
|
|||||||
|
|
||||||
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:
|
||||||
@@ -59,7 +71,7 @@ class Handler:
|
|||||||
repository_id(RepositoryId): repository unique identifier
|
repository_id(RepositoryId): repository unique identifier
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True on success, False otherwise
|
bool: ``True`` on success, ``False`` otherwise
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
configuration = Configuration.from_path(args.configuration, repository_id)
|
configuration = Configuration.from_path(args.configuration, repository_id)
|
||||||
@@ -124,18 +136,23 @@ class Handler:
|
|||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def check_if_empty(enabled: bool, predicate: bool) -> None:
|
def check_status(enabled: bool, status: ExplicitBool | Callable[[], ExplicitBool]) -> None:
|
||||||
"""
|
"""
|
||||||
check condition and flag and raise ExitCode exception in case if it is enabled and condition match
|
check condition and flag and raise ExitCode exception in case if it is enabled and condition match
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
enabled(bool): if False no check will be performed
|
enabled(bool): if ``False`` no check will be performed
|
||||||
predicate(bool): indicates condition on which exception should be thrown
|
status(ExplicitBool | Callable[[], ExplicitBool]): return status or function to check.
|
||||||
|
``True`` means success and vice versa
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
ExitCode: if result is empty and check is enabled
|
ExitCode: if result is empty and check is enabled
|
||||||
"""
|
"""
|
||||||
if enabled and predicate:
|
if not enabled:
|
||||||
|
return
|
||||||
|
|
||||||
|
status = status() if callable(status) else status
|
||||||
|
if not status:
|
||||||
raise ExitCode
|
raise ExitCode
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -152,11 +169,6 @@ class Handler:
|
|||||||
Raises:
|
Raises:
|
||||||
MissingArchitectureError: if no architecture set and automatic detection is not allowed or failed
|
MissingArchitectureError: if no architecture set and automatic detection is not allowed or failed
|
||||||
"""
|
"""
|
||||||
configuration = Configuration()
|
|
||||||
configuration.load(args.configuration)
|
|
||||||
# pylint, wtf???
|
|
||||||
root = configuration.getpath("repository", "root") # pylint: disable=assignment-from-no-return
|
|
||||||
|
|
||||||
# preparse systemd repository-id argument
|
# preparse systemd repository-id argument
|
||||||
# we are using unescaped values, so / is not allowed here, because it is impossible to separate if from dashes
|
# we are using unescaped values, so / is not allowed here, because it is impossible to separate if from dashes
|
||||||
if args.repository_id is not None:
|
if args.repository_id is not None:
|
||||||
@@ -167,27 +179,10 @@ class Handler:
|
|||||||
if repository_parts:
|
if repository_parts:
|
||||||
args.repository = "-".join(repository_parts) # replace slash with dash
|
args.repository = "-".join(repository_parts) # replace slash with dash
|
||||||
|
|
||||||
# extract repository names first
|
configuration = Configuration()
|
||||||
if (from_args := args.repository) is not None:
|
configuration.load(args.configuration)
|
||||||
repositories: Iterable[str] = [from_args]
|
repositories = Explorer.repositories_extract(configuration, args.repository, args.architecture)
|
||||||
elif from_filesystem := RepositoryPaths.known_repositories(root):
|
|
||||||
repositories = from_filesystem
|
|
||||||
else: # try to read configuration now
|
|
||||||
repositories = [configuration.get("repository", "name")]
|
|
||||||
|
|
||||||
# extract architecture names
|
if not repositories:
|
||||||
if (architecture := args.architecture) is not None:
|
|
||||||
parsed = set(
|
|
||||||
RepositoryId(architecture, repository)
|
|
||||||
for repository in repositories
|
|
||||||
)
|
|
||||||
else: # try to read from file system
|
|
||||||
parsed = set(
|
|
||||||
RepositoryId(architecture, repository)
|
|
||||||
for repository in repositories
|
|
||||||
for architecture in RepositoryPaths.known_architectures(root, repository)
|
|
||||||
)
|
|
||||||
|
|
||||||
if not parsed:
|
|
||||||
raise MissingArchitectureError(args.command)
|
raise MissingArchitectureError(args.command)
|
||||||
return sorted(parsed)
|
return sorted(repositories)
|
||||||
+21
-2
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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]
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2026 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.action import Action
|
||||||
|
from ahriman.models.repository_id import RepositoryId
|
||||||
|
|
||||||
|
|
||||||
|
class Hold(Handler):
|
||||||
|
"""
|
||||||
|
package hold handler
|
||||||
|
"""
|
||||||
|
|
||||||
|
@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
|
||||||
|
"""
|
||||||
|
client = Application(repository_id, configuration, report=True).reporter
|
||||||
|
|
||||||
|
match args.action:
|
||||||
|
case Action.Remove:
|
||||||
|
for package in args.package:
|
||||||
|
client.package_hold_update(package, enabled=False)
|
||||||
|
case Action.Update:
|
||||||
|
for package in args.package:
|
||||||
|
client.package_hold_update(package, enabled=True)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _set_package_hold_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
|
"""
|
||||||
|
add parser for hold package subcommand
|
||||||
|
|
||||||
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
|
"""
|
||||||
|
parser = root.add_parser("package-hold", help="hold package",
|
||||||
|
description="hold package from automatic updates")
|
||||||
|
parser.add_argument("package", help="package base", nargs="+")
|
||||||
|
parser.set_defaults(action=Action.Update, lock=None, quiet=True, report=False, unsafe=True)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _set_package_unhold_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
|
"""
|
||||||
|
add parser for unhold package subcommand
|
||||||
|
|
||||||
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
|
"""
|
||||||
|
parser = root.add_parser("package-unhold", help="unhold package",
|
||||||
|
description="remove package hold, allowing automatic updates")
|
||||||
|
parser.add_argument("package", help="package base", nargs="+")
|
||||||
|
parser.set_defaults(action=Action.Remove, lock=None, quiet=True, report=False, unsafe=True)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
arguments = [
|
||||||
|
_set_package_hold_parser,
|
||||||
|
_set_package_unhold_parser,
|
||||||
|
]
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2026 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.repository_id import RepositoryId
|
||||||
|
|
||||||
|
|
||||||
|
class KeyImport(Handler):
|
||||||
|
"""
|
||||||
|
key import packages handler
|
||||||
|
"""
|
||||||
|
|
||||||
|
ALLOW_MULTI_ARCHITECTURE_RUN = False # system-wide 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.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]
|
||||||
@@ -0,0 +1,257 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2026 ahriman team.
|
||||||
|
#
|
||||||
|
# This file is part of ahriman
|
||||||
|
# (see https://github.com/arcan1s/ahriman).
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
import argparse
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from ahriman.application.application import Application
|
||||||
|
from ahriman.application.handlers.handler import Handler, SubParserAction
|
||||||
|
from ahriman.core.build_tools.sources import Sources
|
||||||
|
from ahriman.core.configuration import Configuration
|
||||||
|
from ahriman.core.formatters import PatchPrinter
|
||||||
|
from ahriman.models.action import Action
|
||||||
|
from ahriman.models.package import Package
|
||||||
|
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
||||||
|
from ahriman.models.repository_id import RepositoryId
|
||||||
|
|
||||||
|
|
||||||
|
class Patch(Handler):
|
||||||
|
"""
|
||||||
|
patch control handler
|
||||||
|
"""
|
||||||
|
|
||||||
|
ALLOW_MULTI_ARCHITECTURE_RUN = False # system-wide 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()
|
||||||
|
|
||||||
|
match args.action:
|
||||||
|
case Action.Update if args.variable is not None:
|
||||||
|
patch = Patch.patch_create_from_function(args.variable, args.patch)
|
||||||
|
Patch.patch_set_create(application, args.package, patch)
|
||||||
|
case Action.Update:
|
||||||
|
package_base, patch = Patch.patch_create_from_diff(args.package, repository_id.architecture, args.track)
|
||||||
|
Patch.patch_set_create(application, package_base, patch)
|
||||||
|
case Action.List:
|
||||||
|
Patch.patch_set_list(application, args.package, args.variable, args.exit_code)
|
||||||
|
case Action.Remove:
|
||||||
|
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
|
||||||
|
def patch_create_from_diff(sources_dir: Path, architecture: str, track: list[str]) -> tuple[str, PkgbuildPatch]:
|
||||||
|
"""
|
||||||
|
create PKGBUILD plain diff patches from sources directory
|
||||||
|
|
||||||
|
Args:
|
||||||
|
sources_dir(Path): path to directory with the package sources
|
||||||
|
architecture(str): repository architecture
|
||||||
|
track(list[str]): track files which match the glob before creating the patch
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple[str, PkgbuildPatch]: package base and created PKGBUILD patch based on the diff from master HEAD
|
||||||
|
to current files
|
||||||
|
"""
|
||||||
|
package = Package.from_build(sources_dir, architecture, None)
|
||||||
|
patch = Sources.patch_create(sources_dir, *track)
|
||||||
|
return package.base, PkgbuildPatch(None, patch)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def patch_create_from_function(variable: str, patch_path: Path | None) -> PkgbuildPatch:
|
||||||
|
"""
|
||||||
|
create single-function patch set for the package base
|
||||||
|
|
||||||
|
Args:
|
||||||
|
variable(str): function or variable name inside PKGBUILD
|
||||||
|
patch_path(Path | None): optional path to patch content. If not set, it will be read from stdin
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
PkgbuildPatch: created patch for the PKGBUILD function
|
||||||
|
"""
|
||||||
|
if patch_path is None:
|
||||||
|
# pylint: disable=bad-builtin
|
||||||
|
print("Post new function or variable value below. Press Ctrl-D to finish:", file=sys.stderr)
|
||||||
|
patch = "".join(list(sys.stdin))
|
||||||
|
else:
|
||||||
|
patch = patch_path.read_text(encoding="utf8")
|
||||||
|
# remove spaces around the patch and parse to correct type
|
||||||
|
return PkgbuildPatch.parse(variable, patch.strip())
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def patch_set_create(application: Application, package_base: str, patch: PkgbuildPatch) -> None:
|
||||||
|
"""
|
||||||
|
create patch set for the package base
|
||||||
|
|
||||||
|
Args:
|
||||||
|
application(Application): application instance
|
||||||
|
package_base(str): package base
|
||||||
|
patch(PkgbuildPatch): patch descriptor
|
||||||
|
"""
|
||||||
|
application.reporter.package_patches_update(package_base, patch)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def patch_set_list(application: Application, package_base: str, variables: list[str] | None,
|
||||||
|
exit_code: bool) -> None:
|
||||||
|
"""
|
||||||
|
list patches available for the package base
|
||||||
|
|
||||||
|
Args:
|
||||||
|
application(Application): application instance
|
||||||
|
package_base(str): package base
|
||||||
|
variables(list[str] | None): extract patches only for specified PKGBUILD variables
|
||||||
|
exit_code(bool): exit with error on empty search result
|
||||||
|
"""
|
||||||
|
patches = [
|
||||||
|
patch
|
||||||
|
for patch in application.reporter.package_patches_get(package_base, None)
|
||||||
|
if variables is None or patch.key in variables
|
||||||
|
]
|
||||||
|
Patch.check_status(exit_code, patches)
|
||||||
|
|
||||||
|
PatchPrinter(package_base, patches)(verbose=True, separator=" = ")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def patch_set_remove(application: Application, package_base: str, variables: list[str] | None) -> None:
|
||||||
|
"""
|
||||||
|
remove patch set for the package base
|
||||||
|
|
||||||
|
Args:
|
||||||
|
application(Application): application instance
|
||||||
|
package_base(str): package base
|
||||||
|
variables(list[str] | None): remove patches only for specified PKGBUILD variables
|
||||||
|
"""
|
||||||
|
if variables is not None:
|
||||||
|
for variable in variables: # iterate over single variable
|
||||||
|
application.reporter.package_patches_remove(package_base, variable)
|
||||||
|
else:
|
||||||
|
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,
|
||||||
|
]
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2026 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 dataclasses import replace
|
||||||
|
|
||||||
|
from ahriman.application.application import Application
|
||||||
|
from ahriman.application.handlers.handler import Handler, SubParserAction
|
||||||
|
from ahriman.core.configuration import Configuration
|
||||||
|
from ahriman.core.formatters import PkgbuildPrinter
|
||||||
|
from ahriman.models.action import Action
|
||||||
|
from ahriman.models.repository_id import RepositoryId
|
||||||
|
|
||||||
|
|
||||||
|
class Pkgbuild(Handler):
|
||||||
|
"""
|
||||||
|
package pkgbuild handler
|
||||||
|
"""
|
||||||
|
|
||||||
|
ALLOW_MULTI_ARCHITECTURE_RUN = False # conflicting io
|
||||||
|
|
||||||
|
@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
|
||||||
|
"""
|
||||||
|
client = Application(repository_id, configuration, report=True).reporter
|
||||||
|
|
||||||
|
match args.action:
|
||||||
|
case Action.List:
|
||||||
|
changes = client.package_changes_get(args.package)
|
||||||
|
PkgbuildPrinter(changes)(verbose=True, separator="")
|
||||||
|
Pkgbuild.check_status(args.exit_code, changes.pkgbuild is not None)
|
||||||
|
case Action.Remove:
|
||||||
|
changes = client.package_changes_get(args.package)
|
||||||
|
client.package_changes_update(args.package, replace(changes, pkgbuild=None))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _set_package_pkgbuild_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
|
"""
|
||||||
|
add parser for package pkgbuild subcommand
|
||||||
|
|
||||||
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
|
"""
|
||||||
|
parser = root.add_parser("package-pkgbuild", help="get package pkgbuild",
|
||||||
|
description="retrieve package PKGBUILD 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_pkgbuild_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
|
"""
|
||||||
|
add parser for package pkgbuild remove subcommand
|
||||||
|
|
||||||
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
|
"""
|
||||||
|
parser = root.add_parser("package-pkgbuild-remove", help="remove package pkgbuild",
|
||||||
|
description="remove the package PKGBUILD 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_pkgbuild_parser, _set_package_pkgbuild_remove_parser]
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2026 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.core.utils import enum_values, extract_user
|
||||||
|
from ahriman.models.build_status import BuildStatusEnum
|
||||||
|
from ahriman.models.package import Package
|
||||||
|
from ahriman.models.packagers import Packagers
|
||||||
|
from ahriman.models.repository_id import RepositoryId
|
||||||
|
|
||||||
|
|
||||||
|
class Rebuild(Handler):
|
||||||
|
"""
|
||||||
|
make world handler
|
||||||
|
"""
|
||||||
|
|
||||||
|
@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()
|
||||||
|
|
||||||
|
packages = Rebuild.extract_packages(application, args.status, from_database=args.from_database)
|
||||||
|
packages = application.repository.packages_depend_on(packages, args.depends_on)
|
||||||
|
|
||||||
|
Rebuild.check_status(args.exit_code, packages)
|
||||||
|
if args.dry_run:
|
||||||
|
application.print_updates(packages, log_fn=print)
|
||||||
|
return
|
||||||
|
|
||||||
|
result = application.update(packages, Packagers(args.username), bump_pkgrel=args.increment)
|
||||||
|
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
|
||||||
|
def extract_packages(application: Application, status: BuildStatusEnum | None, *,
|
||||||
|
from_database: bool) -> list[Package]:
|
||||||
|
"""
|
||||||
|
extract packages from database file
|
||||||
|
|
||||||
|
Args:
|
||||||
|
application(Application): application instance
|
||||||
|
status(BuildStatusEnum | None): optional filter by package status
|
||||||
|
from_database(bool): extract packages from database instead of repository filesystem
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[Package]: list of packages which were stored in database
|
||||||
|
"""
|
||||||
|
if from_database:
|
||||||
|
return [
|
||||||
|
package
|
||||||
|
for (package, last_status) in application.reporter.package_get(None)
|
||||||
|
if status is None or last_status.status == status
|
||||||
|
]
|
||||||
|
|
||||||
|
return application.repository.packages()
|
||||||
|
|
||||||
|
arguments = [_set_repo_rebuild_parser]
|
||||||
+27
-6
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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,14 +20,14 @@
|
|||||||
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
|
||||||
|
|
||||||
|
|
||||||
class KeyImport(Handler):
|
class Reload(Handler):
|
||||||
"""
|
"""
|
||||||
key import packages handler
|
web server reload handler
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ALLOW_MULTI_ARCHITECTURE_RUN = False # system-wide action
|
ALLOW_MULTI_ARCHITECTURE_RUN = False # system-wide action
|
||||||
@@ -44,5 +44,26 @@ class KeyImport(Handler):
|
|||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
report(bool): force enable or disable reporting
|
report(bool): force enable or disable reporting
|
||||||
"""
|
"""
|
||||||
application = Application(repository_id, configuration, report=report)
|
client = Application(repository_id, configuration, report=True).reporter
|
||||||
application.repository.sign.key_import(args.key_server, args.key)
|
client.configuration_reload()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _set_web_reload_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
|
"""
|
||||||
|
add parser for web reload subcommand
|
||||||
|
|
||||||
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
|
"""
|
||||||
|
parser = root.add_parser("web-reload", help="reload configuration",
|
||||||
|
description="reload web server configuration",
|
||||||
|
epilog="This method forces the web server to reload its configuration. "
|
||||||
|
"Note, however, that this method does not apply all configuration changes "
|
||||||
|
"(like ports, authentication, etc)")
|
||||||
|
parser.set_defaults(architecture="", lock=None, quiet=True, report=False, repository="", unsafe=True)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
arguments = [_set_web_reload_parser]
|
||||||
+20
-2
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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]
|
||||||
+20
-2
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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]
|
||||||
+22
-2
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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]
|
||||||
+26
-5
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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,10 +18,11 @@
|
|||||||
# 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 tarfile
|
||||||
|
|
||||||
from tarfile import TarFile
|
from pathlib import Path
|
||||||
|
|
||||||
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,5 +46,25 @@ class Restore(Handler):
|
|||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
report(bool): force enable or disable reporting
|
report(bool): force enable or disable reporting
|
||||||
"""
|
"""
|
||||||
with TarFile(args.path) as archive:
|
with tarfile.open(args.path) as archive:
|
||||||
archive.extractall(path=args.output)
|
archive.extractall(path=args.output, filter="data")
|
||||||
|
|
||||||
|
@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]
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2026 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 dataclasses import replace
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from ahriman.application.application import Application
|
||||||
|
from ahriman.application.handlers.add import Add
|
||||||
|
from ahriman.application.handlers.handler import Handler, SubParserAction
|
||||||
|
from ahriman.core.configuration import Configuration
|
||||||
|
from ahriman.core.exceptions import UnknownPackageError
|
||||||
|
from ahriman.core.utils import extract_user
|
||||||
|
from ahriman.models.package import Package
|
||||||
|
from ahriman.models.package_source import PackageSource
|
||||||
|
from ahriman.models.repository_id import RepositoryId
|
||||||
|
|
||||||
|
|
||||||
|
class Rollback(Handler):
|
||||||
|
"""
|
||||||
|
package rollback handler
|
||||||
|
"""
|
||||||
|
|
||||||
|
@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()
|
||||||
|
|
||||||
|
package = Rollback.package_load(application, args.package, args.version)
|
||||||
|
artifacts = Rollback.package_artifacts(application, package)
|
||||||
|
|
||||||
|
args.package = [str(artifact) for artifact in artifacts]
|
||||||
|
Add.perform_action(application, args)
|
||||||
|
|
||||||
|
if args.hold:
|
||||||
|
application.reporter.package_hold_update(package.base, enabled=True)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _set_package_rollback_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
|
"""
|
||||||
|
add parser for package rollback subcommand
|
||||||
|
|
||||||
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
|
"""
|
||||||
|
parser = root.add_parser("package-rollback", help="rollback package",
|
||||||
|
description="rollback package to specified version from archives")
|
||||||
|
parser.add_argument("package", help="package base")
|
||||||
|
parser.add_argument("version", help="package version")
|
||||||
|
parser.add_argument("--hold", help="hold package afterwards",
|
||||||
|
action=argparse.BooleanOptionalAction, default=True)
|
||||||
|
parser.add_argument("-u", "--username", help="build as user", default=extract_user())
|
||||||
|
parser.set_defaults(aur=False, changes=False, check_files=False, dependencies=False, dry_run=False,
|
||||||
|
exit_code=True, increment=False, now=True, local=False, manual=False, refresh=False,
|
||||||
|
source=PackageSource.Archive, variable=None, vcs=False)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def package_artifacts(application: Application, package: Package) -> list[Path]:
|
||||||
|
"""
|
||||||
|
look for requested package artifacts and return paths to them
|
||||||
|
|
||||||
|
Args:
|
||||||
|
application(Application): application instance
|
||||||
|
package(Package): package descriptor
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[Path]: paths to found artifacts
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
UnknownPackageError: if artifacts do not exist
|
||||||
|
"""
|
||||||
|
# lookup for built artifacts
|
||||||
|
artifacts = application.repository.package_archives_lookup(package)
|
||||||
|
if not artifacts:
|
||||||
|
raise UnknownPackageError(package.base)
|
||||||
|
return artifacts
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def package_load(application: Application, package_base: str, version: str) -> Package:
|
||||||
|
"""
|
||||||
|
load package from repository, while setting requested version
|
||||||
|
|
||||||
|
Args:
|
||||||
|
application(Application): application instance
|
||||||
|
package_base(str): package base
|
||||||
|
version(str): package version
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Package: loaded package
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
UnknownPackageError: if package does not exist
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
package, _ = next(iter(application.reporter.package_get(package_base)))
|
||||||
|
return replace(package, version=version)
|
||||||
|
except StopIteration:
|
||||||
|
raise UnknownPackageError(package_base) from None
|
||||||
|
|
||||||
|
arguments = [_set_package_rollback_parser]
|
||||||
+24
-3
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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
|
||||||
|
|
||||||
@@ -47,7 +47,26 @@ class Run(Handler):
|
|||||||
parser = args.parser()
|
parser = args.parser()
|
||||||
for command in args.command:
|
for command in args.command:
|
||||||
status = Run.run_command(shlex.split(command), parser)
|
status = Run.run_command(shlex.split(command), parser)
|
||||||
Run.check_if_empty(True, not 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]
|
||||||
+38
-6
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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,12 +21,14 @@ 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
|
||||||
from ahriman.core.formatters import AurPrinter
|
from ahriman.core.formatters import AurPrinter
|
||||||
|
from ahriman.core.types import Comparable
|
||||||
from ahriman.models.aur_package import AURPackage
|
from ahriman.models.aur_package import AURPackage
|
||||||
from ahriman.models.repository_id import RepositoryId
|
from ahriman.models.repository_id import RepositoryId
|
||||||
|
|
||||||
@@ -40,10 +42,10 @@ 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 # type: ignore[comparison-overlap]
|
if field.default_factory is not list
|
||||||
}
|
}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -60,13 +62,41 @@ class Search(Handler):
|
|||||||
"""
|
"""
|
||||||
official_packages_list = Official.multisearch(*args.search)
|
official_packages_list = Official.multisearch(*args.search)
|
||||||
aur_packages_list = AUR.multisearch(*args.search)
|
aur_packages_list = AUR.multisearch(*args.search)
|
||||||
Search.check_if_empty(args.exit_code, not official_packages_list and not aur_packages_list)
|
non_empty = bool(official_packages_list or aur_packages_list)
|
||||||
|
Search.check_status(args.exit_code, non_empty)
|
||||||
|
|
||||||
for packages_list in (official_packages_list, aur_packages_list):
|
for packages_list in (official_packages_list, aur_packages_list):
|
||||||
# keep sorting by packages source
|
# keep sorting by packages source
|
||||||
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]:
|
||||||
"""
|
"""
|
||||||
@@ -86,6 +116,8 @@ class Search(Handler):
|
|||||||
raise OptionError(sort_by)
|
raise OptionError(sort_by)
|
||||||
# always sort by package name at the last
|
# always sort by package name at the last
|
||||||
# well technically it is not a string, but we can deal with it
|
# well technically it is not a string, but we can deal with it
|
||||||
comparator: Callable[[AURPackage], tuple[str, str]] =\
|
comparator: Callable[[AURPackage], Comparable] = \
|
||||||
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]
|
||||||
+24
-4
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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
|
||||||
@@ -47,7 +47,7 @@ class ServiceUpdates(Handler):
|
|||||||
report(bool): force enable or disable reporting
|
report(bool): force enable or disable reporting
|
||||||
"""
|
"""
|
||||||
remote = Package.from_aur("ahriman", None)
|
remote = Package.from_aur("ahriman", None)
|
||||||
_, release = remote.version.rsplit("-", 1) # we don't store pkgrel locally, so we just append it
|
_, release = remote.version.rsplit("-", maxsplit=1) # we don't store pkgrel locally, so we just append it
|
||||||
local_version = f"{__version__}-{release}"
|
local_version = f"{__version__}-{release}"
|
||||||
|
|
||||||
# technically we would like to compare versions, but it is fine to raise an exception in case if locally
|
# technically we would like to compare versions, but it is fine to raise an exception in case if locally
|
||||||
@@ -57,4 +57,24 @@ class ServiceUpdates(Handler):
|
|||||||
return
|
return
|
||||||
|
|
||||||
UpdatePrinter(remote, local_version)(verbose=True, separator=" -> ")
|
UpdatePrinter(remote, local_version)(verbose=True, separator=" -> ")
|
||||||
ServiceUpdates.check_if_empty(args.exit_code, not 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]
|
||||||
+61
-16
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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, *,
|
||||||
@@ -69,6 +72,7 @@ class Setup(Handler):
|
|||||||
|
|
||||||
application = Application(repository_id, configuration, report=report)
|
application = Application(repository_id, configuration, report=report)
|
||||||
|
|
||||||
|
# basically we create configuration here as root, but it is ok, because those files are only used for reading
|
||||||
Setup.configuration_create_makepkg(args.packager, args.makeflags_jobs, application.repository.paths)
|
Setup.configuration_create_makepkg(args.packager, args.makeflags_jobs, application.repository.paths)
|
||||||
Setup.executable_create(application.repository.paths, repository_id)
|
Setup.executable_create(application.repository.paths, repository_id)
|
||||||
repository_server = f"file://{application.repository.paths.repository}" if args.server is None else args.server
|
repository_server = f"file://{application.repository.paths.repository}" if args.server is None else args.server
|
||||||
@@ -76,9 +80,49 @@ class Setup(Handler):
|
|||||||
repository_id, args.from_configuration, args.mirror, args.multilib, repository_server)
|
repository_id, args.from_configuration, args.mirror, args.multilib, repository_server)
|
||||||
Setup.configuration_create_sudo(application.repository.paths, repository_id)
|
Setup.configuration_create_sudo(application.repository.paths, repository_id)
|
||||||
|
|
||||||
application.repository.repo.init()
|
# finish initialization
|
||||||
# lazy database sync
|
with application.repository.paths.preserve_owner():
|
||||||
application.repository.pacman.handle # pylint: disable=pointless-statement
|
application.repository.repo.init()
|
||||||
|
# lazy database sync
|
||||||
|
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,14 +178,14 @@ 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))
|
||||||
|
|
||||||
(root.include / "00-setup-overrides.ini").unlink(missing_ok=True) # remove old-style configuration
|
(root.include / "00-setup-overrides.ini").unlink(missing_ok=True) # remove old-style configuration
|
||||||
target = root.include / f"00-setup-overrides-{repository_id.id}.ini"
|
target = root.include / f"00-setup-overrides-{repository_id.id}.ini"
|
||||||
with target.open("w") as ahriman_configuration:
|
with target.open("w", encoding="utf8") as ahriman_configuration:
|
||||||
configuration.write(ahriman_configuration)
|
configuration.write(ahriman_configuration)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -161,8 +205,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]
|
||||||
@@ -191,7 +235,7 @@ class Setup(Handler):
|
|||||||
configuration.set_option(repository_id.name, "Server", repository_server)
|
configuration.set_option(repository_id.name, "Server", repository_server)
|
||||||
|
|
||||||
target = source.parent / f"{repository_id.name}-{repository_id.architecture}.conf"
|
target = source.parent / f"{repository_id.name}-{repository_id.architecture}.conf"
|
||||||
with target.open("w") as devtools_configuration:
|
with target.open("w", encoding="utf8") as devtools_configuration:
|
||||||
configuration.write(devtools_configuration)
|
configuration.write(devtools_configuration)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -207,7 +251,7 @@ class Setup(Handler):
|
|||||||
|
|
||||||
content = f"PACKAGER='{packager}'\n"
|
content = f"PACKAGER='{packager}'\n"
|
||||||
if makeflags_jobs:
|
if makeflags_jobs:
|
||||||
content += """MAKEFLAGS="-j$(nproc)"\n"""
|
content += "MAKEFLAGS=\"-j$(nproc)\"\n"
|
||||||
|
|
||||||
uid, _ = paths.root_owner
|
uid, _ = paths.root_owner
|
||||||
home_dir = Path(getpwuid(uid).pw_dir)
|
home_dir = Path(getpwuid(uid).pw_dir)
|
||||||
@@ -239,4 +283,5 @@ class Setup(Handler):
|
|||||||
command = Setup.build_command(paths.root, repository_id)
|
command = Setup.build_command(paths.root, repository_id)
|
||||||
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
|
|
||||||
|
arguments = [_set_service_setup_parser]
|
||||||
+30
-7
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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]
|
||||||
+21
-2
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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]
|
||||||
@@ -0,0 +1,197 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2026 ahriman team.
|
||||||
|
#
|
||||||
|
# This file is part of ahriman
|
||||||
|
# (see https://github.com/arcan1s/ahriman).
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
import argparse
|
||||||
|
import datetime
|
||||||
|
import itertools
|
||||||
|
|
||||||
|
from collections.abc import Callable
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from ahriman.application.application import Application
|
||||||
|
from ahriman.application.handlers.handler import Handler, SubParserAction
|
||||||
|
from ahriman.core.configuration import Configuration
|
||||||
|
from ahriman.core.formatters import EventStatsPrinter, PackageStatsPrinter, RepositoryStatsPrinter
|
||||||
|
from ahriman.core.utils import enum_values, pretty_datetime
|
||||||
|
from ahriman.models.event import Event, EventType
|
||||||
|
from ahriman.models.repository_id import RepositoryId
|
||||||
|
|
||||||
|
|
||||||
|
class Statistics(Handler):
|
||||||
|
"""
|
||||||
|
repository statistics handler
|
||||||
|
"""
|
||||||
|
|
||||||
|
ALLOW_MULTI_ARCHITECTURE_RUN = False # conflicting io
|
||||||
|
|
||||||
|
@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=True)
|
||||||
|
|
||||||
|
from_date = to_date = None
|
||||||
|
if (value := args.from_date) is not None:
|
||||||
|
from_date = datetime.datetime.fromisoformat(value).timestamp()
|
||||||
|
if (value := args.to_date) is not None:
|
||||||
|
to_date = datetime.datetime.fromisoformat(value).timestamp()
|
||||||
|
|
||||||
|
events = application.reporter.event_get(args.event, args.package, from_date, to_date, args.limit, args.offset)
|
||||||
|
|
||||||
|
match args.package:
|
||||||
|
case None:
|
||||||
|
RepositoryStatsPrinter(repository_id, application.reporter.statistics())(verbose=True)
|
||||||
|
Statistics.stats_per_package(args.event, events, args.chart)
|
||||||
|
case _:
|
||||||
|
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
|
||||||
|
def event_stats(event_type: str, events: list[Event]) -> None:
|
||||||
|
"""
|
||||||
|
calculate event stats
|
||||||
|
|
||||||
|
Args:
|
||||||
|
event_type(str): event type
|
||||||
|
events(list[Event]): list of events
|
||||||
|
"""
|
||||||
|
times = [event.get("took") for event in events if event.get("took") is not None]
|
||||||
|
EventStatsPrinter(f"{event_type} duration, s", times)(verbose=True)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def plot_packages(event_type: str, events: dict[str, int], path: Path) -> None:
|
||||||
|
"""
|
||||||
|
plot packages frequency
|
||||||
|
|
||||||
|
Args:
|
||||||
|
event_type(str): event type
|
||||||
|
events(dict[str, int]): list of events
|
||||||
|
path(Path): path to save plot
|
||||||
|
"""
|
||||||
|
from matplotlib import pyplot as plt
|
||||||
|
|
||||||
|
x, y = list(events.keys()), list(events.values())
|
||||||
|
plt.bar(x, y)
|
||||||
|
|
||||||
|
plt.xlabel("Package base")
|
||||||
|
plt.ylabel("Frequency")
|
||||||
|
plt.title(f"Frequency of the {event_type} event per package")
|
||||||
|
|
||||||
|
plt.savefig(path)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def plot_times(event_type: str, events: list[Event], path: Path) -> None:
|
||||||
|
"""
|
||||||
|
plot events timeline
|
||||||
|
|
||||||
|
Args:
|
||||||
|
event_type(str): event type
|
||||||
|
events(list[Event]): list of events
|
||||||
|
path(Path): path to save plot
|
||||||
|
"""
|
||||||
|
from matplotlib import pyplot as plt
|
||||||
|
|
||||||
|
figure = plt.figure()
|
||||||
|
|
||||||
|
x, y = zip(*[(pretty_datetime(event.created), event.get("took")) for event in events])
|
||||||
|
plt.plot(x, y)
|
||||||
|
|
||||||
|
plt.xlabel("Event timestamp")
|
||||||
|
plt.ylabel("Duration, s")
|
||||||
|
plt.title(f"Duration of the {event_type} event")
|
||||||
|
figure.autofmt_xdate()
|
||||||
|
|
||||||
|
plt.savefig(path)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def stats_for_package(event_type: str, events: list[Event], chart_path: Path | None) -> None:
|
||||||
|
"""
|
||||||
|
calculate statistics for a package
|
||||||
|
|
||||||
|
Args:
|
||||||
|
event_type(str): event type
|
||||||
|
events(list[Event]): list of events
|
||||||
|
chart_path(Path): path to save plot if any
|
||||||
|
"""
|
||||||
|
# event statistics
|
||||||
|
Statistics.event_stats(event_type, events)
|
||||||
|
|
||||||
|
# chart if enabled
|
||||||
|
if chart_path is not None:
|
||||||
|
Statistics.plot_times(event_type, events, chart_path)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def stats_per_package(event_type: str, events: list[Event], chart_path: Path | None) -> None:
|
||||||
|
"""
|
||||||
|
calculate overall statistics
|
||||||
|
|
||||||
|
Args:
|
||||||
|
event_type(str): event type
|
||||||
|
events(list[Event]): list of events
|
||||||
|
chart_path(Path): path to save plot if any
|
||||||
|
"""
|
||||||
|
key: Callable[[Event], str] = lambda event: event.object_id
|
||||||
|
by_object_id = {
|
||||||
|
object_id: len(list(related))
|
||||||
|
for object_id, related in itertools.groupby(sorted(events, key=key), key=key)
|
||||||
|
}
|
||||||
|
|
||||||
|
# distribution per package
|
||||||
|
PackageStatsPrinter(by_object_id)(verbose=True)
|
||||||
|
EventStatsPrinter(f"{event_type} frequency", list(by_object_id.values()))(verbose=True)
|
||||||
|
|
||||||
|
# event statistics
|
||||||
|
Statistics.event_stats(event_type, events)
|
||||||
|
|
||||||
|
# chart if enabled
|
||||||
|
if chart_path is not None:
|
||||||
|
Statistics.plot_packages(event_type, by_object_id, chart_path)
|
||||||
|
|
||||||
|
arguments = [_set_repo_statistics_parser]
|
||||||
+37
-7
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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,12 @@ 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.types import Comparable
|
||||||
|
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
|
||||||
|
|
||||||
@@ -50,7 +52,7 @@ class Status(Handler):
|
|||||||
report(bool): force enable or disable reporting
|
report(bool): force enable or disable reporting
|
||||||
"""
|
"""
|
||||||
# we are using reporter here
|
# we are using reporter here
|
||||||
client = Application(repository_id, configuration, report=True).repository.reporter
|
client = Application(repository_id, configuration, report=True).reporter
|
||||||
if args.ahriman:
|
if args.ahriman:
|
||||||
service_status = client.status_get()
|
service_status = client.status_get()
|
||||||
StatusPrinter(service_status.status)(verbose=args.info)
|
StatusPrinter(service_status.status)(verbose=args.info)
|
||||||
@@ -61,10 +63,38 @@ class Status(Handler):
|
|||||||
else:
|
else:
|
||||||
packages = client.package_get(None)
|
packages = client.package_get(None)
|
||||||
|
|
||||||
Status.check_if_empty(args.exit_code, not packages)
|
Status.check_status(args.exit_code, packages)
|
||||||
|
|
||||||
comparator: Callable[[tuple[Package, BuildStatus]], str] = lambda item: item[0].base
|
comparator: Callable[[tuple[Package, BuildStatus]], Comparable] = lambda item: item[0].base
|
||||||
filter_fn: Callable[[tuple[Package, BuildStatus]], bool] =\
|
filter_fn: Callable[[tuple[Package, BuildStatus]], bool] = \
|
||||||
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]
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2026 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.core.utils import enum_values
|
||||||
|
from ahriman.models.action import Action
|
||||||
|
from ahriman.models.build_status import BuildStatusEnum
|
||||||
|
from ahriman.models.repository_id import RepositoryId
|
||||||
|
|
||||||
|
|
||||||
|
class StatusUpdate(Handler):
|
||||||
|
"""
|
||||||
|
status update handler
|
||||||
|
"""
|
||||||
|
|
||||||
|
ALLOW_MULTI_ARCHITECTURE_RUN = False # conflicting io
|
||||||
|
|
||||||
|
@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
|
||||||
|
"""
|
||||||
|
client = Application(repository_id, configuration, report=True).reporter
|
||||||
|
|
||||||
|
match args.action:
|
||||||
|
case Action.Update if args.package:
|
||||||
|
# update packages statuses
|
||||||
|
for package in args.package:
|
||||||
|
client.package_status_update(package, args.status)
|
||||||
|
case Action.Update:
|
||||||
|
# update service status
|
||||||
|
client.status_update(args.status)
|
||||||
|
case Action.Remove:
|
||||||
|
for package in args.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,
|
||||||
|
]
|
||||||
+22
-2
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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]
|
||||||
+38
-2
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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,8 +19,9 @@
|
|||||||
#
|
#
|
||||||
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.utils import symlink_relative, walk
|
||||||
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
|
||||||
|
|
||||||
@@ -49,6 +50,39 @@ class TreeMigrate(Handler):
|
|||||||
target_tree.tree_create()
|
target_tree.tree_create()
|
||||||
# perform migration
|
# perform migration
|
||||||
TreeMigrate.tree_move(current_tree, target_tree)
|
TreeMigrate.tree_move(current_tree, target_tree)
|
||||||
|
TreeMigrate.symlinks_fix(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
|
||||||
|
def symlinks_fix(paths: RepositoryPaths) -> None:
|
||||||
|
"""
|
||||||
|
fix package archive symlinks
|
||||||
|
|
||||||
|
Args:
|
||||||
|
paths(RepositoryPaths): new repository paths
|
||||||
|
"""
|
||||||
|
archives = {path.name: path for path in walk(paths.archive)}
|
||||||
|
for symlink in walk(paths.repository):
|
||||||
|
if symlink.exists(): # no need to check for symlinks as we have just walked through the tree
|
||||||
|
continue
|
||||||
|
if (source_archive := archives.get(symlink.name)) is not None:
|
||||||
|
symlink.unlink()
|
||||||
|
symlink_relative(symlink, source_archive)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def tree_move(from_tree: RepositoryPaths, to_tree: RepositoryPaths) -> None:
|
def tree_move(from_tree: RepositoryPaths, to_tree: RepositoryPaths) -> None:
|
||||||
@@ -66,3 +100,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]
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2026 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.repository_id import RepositoryId
|
||||||
|
from ahriman.models.result import Result
|
||||||
|
|
||||||
|
|
||||||
|
class Triggers(Handler):
|
||||||
|
"""
|
||||||
|
triggers handlers
|
||||||
|
"""
|
||||||
|
|
||||||
|
@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)
|
||||||
|
if args.trigger:
|
||||||
|
loader = application.repository.triggers
|
||||||
|
loader.triggers = [loader.load_trigger(trigger, repository_id, configuration) for trigger in args.trigger]
|
||||||
|
application.on_start()
|
||||||
|
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,
|
||||||
|
]
|
||||||
+24
-3
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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 StringPrinter
|
from ahriman.core.formatters import StringPrinter
|
||||||
from ahriman.models.repository_id import RepositoryId
|
from ahriman.models.repository_id import RepositoryId
|
||||||
@@ -52,6 +52,25 @@ class UnsafeCommands(Handler):
|
|||||||
for command in unsafe_commands:
|
for command in unsafe_commands:
|
||||||
StringPrinter(command)(verbose=True)
|
StringPrinter(command)(verbose=True)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _set_help_commands_unsafe_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
|
"""
|
||||||
|
add parser for listing unsafe commands
|
||||||
|
|
||||||
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
|
"""
|
||||||
|
parser = root.add_parser("help-commands-unsafe", help="list unsafe commands",
|
||||||
|
description="list unsafe commands as defined in default args")
|
||||||
|
parser.add_argument("subcommand",
|
||||||
|
help="instead of showing commands, just test command line for unsafe subcommand "
|
||||||
|
"and return 0 in case if command is safe and 1 otherwise", nargs="*")
|
||||||
|
parser.set_defaults(architecture="", lock=None, quiet=True, report=False, repository="", unsafe=True)
|
||||||
|
return parser
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def check_unsafe(command: list[str], unsafe_commands: list[str], parser: argparse.ArgumentParser) -> None:
|
def check_unsafe(command: list[str], unsafe_commands: list[str], parser: argparse.ArgumentParser) -> None:
|
||||||
"""
|
"""
|
||||||
@@ -63,7 +82,7 @@ class UnsafeCommands(Handler):
|
|||||||
parser(argparse.ArgumentParser): generated argument parser
|
parser(argparse.ArgumentParser): generated argument parser
|
||||||
"""
|
"""
|
||||||
args = parser.parse_args(command)
|
args = parser.parse_args(command)
|
||||||
UnsafeCommands.check_if_empty(True, args.command in unsafe_commands)
|
UnsafeCommands.check_status(True, args.command not in unsafe_commands)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_unsafe_commands(parser: argparse.ArgumentParser) -> list[str]:
|
def get_unsafe_commands(parser: argparse.ArgumentParser) -> list[str]:
|
||||||
@@ -81,3 +100,5 @@ class UnsafeCommands(Handler):
|
|||||||
subparser = next((action for action in parser._actions if isinstance(action, argparse._SubParsersAction)), None)
|
subparser = next((action for action in parser._actions if isinstance(action, argparse._SubParsersAction)), None)
|
||||||
actions = subparser.choices if subparser is not None else {}
|
actions = subparser.choices if subparser is not None else {}
|
||||||
return sorted(action_name for action_name, action in actions.items() if action.get_default("unsafe"))
|
return sorted(action_name for action_name, action in actions.items() if action.get_default("unsafe"))
|
||||||
|
|
||||||
|
arguments = [_set_help_commands_unsafe_parser]
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2026 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 collections.abc import Callable
|
||||||
|
|
||||||
|
from ahriman.application.application import Application
|
||||||
|
from ahriman.application.handlers.handler import Handler, SubParserAction
|
||||||
|
from ahriman.core.configuration import Configuration
|
||||||
|
from ahriman.core.utils import extract_user
|
||||||
|
from ahriman.models.packagers import Packagers
|
||||||
|
from ahriman.models.repository_id import RepositoryId
|
||||||
|
|
||||||
|
|
||||||
|
class Update(Handler):
|
||||||
|
"""
|
||||||
|
package update handler
|
||||||
|
"""
|
||||||
|
|
||||||
|
@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, refresh_pacman_database=args.refresh)
|
||||||
|
application.on_start()
|
||||||
|
Update.perform_action(application, args)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _set_repo_check_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
|
"""
|
||||||
|
add parser for repository check subcommand
|
||||||
|
|
||||||
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
|
"""
|
||||||
|
parser = root.add_parser("repo-check", aliases=["check"], help="check for updates",
|
||||||
|
description="check for packages updates. Same as repo-update --dry-run --no-manual")
|
||||||
|
parser.add_argument("package", help="filter check by package base", nargs="*")
|
||||||
|
parser.add_argument("--changes", help="calculate changes from the latest known commit if available",
|
||||||
|
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("-e", "--exit-code", help="return non-zero exit status if result is empty",
|
||||||
|
action="store_true")
|
||||||
|
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(aur=True, dependencies=False, dry_run=True, increment=False, local=True, manual=False,
|
||||||
|
username=None)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _set_repo_update_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
|
"""
|
||||||
|
add parser for repository update subcommand
|
||||||
|
|
||||||
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
|
"""
|
||||||
|
parser = root.add_parser("repo-update", aliases=["update"], help="update packages",
|
||||||
|
description="check for packages updates and run build process if requested")
|
||||||
|
parser.add_argument("package", help="filter check by package base", nargs="*")
|
||||||
|
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("-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) 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("-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)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def log_fn(application: Application, dry_run: bool) -> Callable[[str], None]:
|
||||||
|
"""
|
||||||
|
package updates log function
|
||||||
|
|
||||||
|
Args:
|
||||||
|
application(Application): application instance
|
||||||
|
dry_run(bool): do not perform update itself
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Callable[[str], None]: in case if dry_run is set it will return print, logger otherwise
|
||||||
|
"""
|
||||||
|
def inner(line: str) -> None:
|
||||||
|
return print(line) if dry_run else application.logger.info(line) # pylint: disable=bad-builtin
|
||||||
|
return inner
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def perform_action(application: Application, args: argparse.Namespace) -> None:
|
||||||
|
"""
|
||||||
|
perform update action
|
||||||
|
|
||||||
|
Args:
|
||||||
|
application(Application): application instance
|
||||||
|
args(argparse.Namespace): command line args
|
||||||
|
"""
|
||||||
|
packages = application.updates(args.package, aur=args.aur, local=args.local, manual=args.manual, vcs=args.vcs,
|
||||||
|
check_files=args.check_files)
|
||||||
|
if args.changes: # generate changes if requested
|
||||||
|
application.changes(packages)
|
||||||
|
|
||||||
|
if args.dry_run: # exit from application if no build requested
|
||||||
|
Update.check_status(args.exit_code, packages) # status code check
|
||||||
|
return
|
||||||
|
|
||||||
|
packages = application.with_dependencies(packages, process_dependencies=args.dependencies)
|
||||||
|
packagers = Packagers(args.username, {package.base: package.packager for package in packages})
|
||||||
|
|
||||||
|
application.print_updates(packages, log_fn=application.logger.info)
|
||||||
|
result = application.update(packages, packagers, bump_pkgrel=args.increment)
|
||||||
|
Update.check_status(args.exit_code, not result.is_empty)
|
||||||
|
|
||||||
|
arguments = [
|
||||||
|
_set_repo_check_parser,
|
||||||
|
_set_repo_update_parser,
|
||||||
|
]
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2026 ahriman team.
|
||||||
|
#
|
||||||
|
# This file is part of ahriman
|
||||||
|
# (see https://github.com/arcan1s/ahriman).
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
import argparse
|
||||||
|
import getpass
|
||||||
|
|
||||||
|
from ahriman.application.handlers.handler import Handler, SubParserAction
|
||||||
|
from ahriman.core.configuration import Configuration
|
||||||
|
from ahriman.core.database import SQLite
|
||||||
|
from ahriman.core.exceptions import PasswordError
|
||||||
|
from ahriman.core.formatters import UserPrinter
|
||||||
|
from ahriman.core.utils import enum_values
|
||||||
|
from ahriman.models.action import Action
|
||||||
|
from ahriman.models.repository_id import RepositoryId
|
||||||
|
from ahriman.models.user import User
|
||||||
|
from ahriman.models.user_access import UserAccess
|
||||||
|
|
||||||
|
|
||||||
|
class Users(Handler):
|
||||||
|
"""
|
||||||
|
user management handler
|
||||||
|
"""
|
||||||
|
|
||||||
|
ALLOW_MULTI_ARCHITECTURE_RUN = False # system-wide 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
|
||||||
|
"""
|
||||||
|
database = SQLite.load(configuration)
|
||||||
|
|
||||||
|
match args.action:
|
||||||
|
case Action.Update:
|
||||||
|
user = Users.user_create(args)
|
||||||
|
# if password is left blank we are not going to require salt to be set
|
||||||
|
salt = configuration.get("auth", "salt", fallback="") if user.password else ""
|
||||||
|
database.user_update(user.hash_password(salt))
|
||||||
|
case Action.List:
|
||||||
|
users = database.user_list(args.username, args.role)
|
||||||
|
for user in users:
|
||||||
|
UserPrinter(user)(verbose=True)
|
||||||
|
Users.check_status(args.exit_code, users)
|
||||||
|
case Action.Remove:
|
||||||
|
database.user_remove(args.username)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _set_user_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
|
"""
|
||||||
|
add parser for create user subcommand
|
||||||
|
|
||||||
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
|
"""
|
||||||
|
parser = root.add_parser("user-add", help="create or update user",
|
||||||
|
description="update user for web services with the given password and role. "
|
||||||
|
"In case if password was not entered it will be asked interactively")
|
||||||
|
parser.add_argument("username", help="username for web service")
|
||||||
|
parser.add_argument("--key", help="optional PGP key used by this user. The private key must be imported")
|
||||||
|
parser.add_argument("--packager", help="optional packager id used for build process in form of "
|
||||||
|
"`Name Surname <mail@example.com>`")
|
||||||
|
parser.add_argument(
|
||||||
|
"-p", "--password", help="user password. Blank password will be treated as empty password, "
|
||||||
|
"which is in particular must be used for OAuth2 authorization type.")
|
||||||
|
parser.add_argument("-R", "--role", help="user access level",
|
||||||
|
type=UserAccess, choices=enum_values(UserAccess), default=UserAccess.Read)
|
||||||
|
parser.set_defaults(action=Action.Update, architecture="", exit_code=False, lock=None, quiet=True,
|
||||||
|
report=False, repository="")
|
||||||
|
return parser
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _set_user_list_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
|
"""
|
||||||
|
add parser for user list subcommand
|
||||||
|
|
||||||
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
|
"""
|
||||||
|
parser = root.add_parser("user-list", help="user known users and their access",
|
||||||
|
description="list users from the user mapping and their roles")
|
||||||
|
parser.add_argument("username", help="filter users by username", nargs="?")
|
||||||
|
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty",
|
||||||
|
action="store_true")
|
||||||
|
parser.add_argument("-R", "--role", help="filter users by role", type=UserAccess,
|
||||||
|
choices=enum_values(UserAccess))
|
||||||
|
parser.set_defaults(action=Action.List, architecture="", lock=None, quiet=True, report=False, repository="",
|
||||||
|
unsafe=True)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _set_user_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
|
"""
|
||||||
|
add parser for user removal subcommand
|
||||||
|
|
||||||
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
|
"""
|
||||||
|
parser = root.add_parser("user-remove", help="remove user",
|
||||||
|
description="remove user from the user mapping and update the configuration")
|
||||||
|
parser.add_argument("username", help="username for web service")
|
||||||
|
parser.set_defaults(action=Action.Remove, architecture="", exit_code=False, lock=None, quiet=True,
|
||||||
|
report=False, repository="")
|
||||||
|
return parser
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def user_create(args: argparse.Namespace) -> User:
|
||||||
|
"""
|
||||||
|
create user descriptor from arguments
|
||||||
|
|
||||||
|
Args:
|
||||||
|
args(argparse.Namespace): command line args
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
User: built user descriptor
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
PasswordError: password input is invalid
|
||||||
|
"""
|
||||||
|
def read_password() -> str:
|
||||||
|
first_password = getpass.getpass()
|
||||||
|
second_password = getpass.getpass("Repeat password: ")
|
||||||
|
if first_password != second_password:
|
||||||
|
raise PasswordError("passwords don't match")
|
||||||
|
return first_password
|
||||||
|
|
||||||
|
password = args.password
|
||||||
|
if password is None:
|
||||||
|
password = read_password()
|
||||||
|
|
||||||
|
return User(username=args.username, password=password, access=args.role,
|
||||||
|
packager_id=args.packager, key=args.key)
|
||||||
|
|
||||||
|
arguments = [
|
||||||
|
_set_user_add_parser,
|
||||||
|
_set_user_list_parser,
|
||||||
|
_set_user_remove_parser,
|
||||||
|
]
|
||||||
+30
-9
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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,9 @@ import copy
|
|||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
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.configuration.schema import CONFIGURATION_SCHEMA, ConfigurationSchema
|
from ahriman.core.configuration.schema import CONFIGURATION_SCHEMA, ConfigurationSchema
|
||||||
from ahriman.core.configuration.validator import Validator
|
|
||||||
from ahriman.core.exceptions import ExtensionError
|
from ahriman.core.exceptions import ExtensionError
|
||||||
from ahriman.core.formatters import ValidationPrinter
|
from ahriman.core.formatters import ValidationPrinter
|
||||||
from ahriman.core.triggers import TriggerLoader
|
from ahriman.core.triggers import TriggerLoader
|
||||||
@@ -51,7 +50,9 @@ class Validate(Handler):
|
|||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
report(bool): force enable or disable reporting
|
report(bool): force enable or disable reporting
|
||||||
"""
|
"""
|
||||||
schema = Validate.schema(repository_id, configuration)
|
from ahriman.core.configuration.validator import Validator
|
||||||
|
|
||||||
|
schema = Validate.schema(configuration)
|
||||||
validator = Validator(configuration=configuration, schema=schema)
|
validator = Validator(configuration=configuration, schema=schema)
|
||||||
|
|
||||||
if validator.validate(configuration.dump()):
|
if validator.validate(configuration.dump()):
|
||||||
@@ -60,15 +61,33 @@ class Validate(Handler):
|
|||||||
ValidationPrinter(node, errors)(verbose=True)
|
ValidationPrinter(node, errors)(verbose=True)
|
||||||
|
|
||||||
# as we reach this part it means that we always have errors
|
# as we reach this part it means that we always have errors
|
||||||
Validate.check_if_empty(args.exit_code, True)
|
Validate.check_status(args.exit_code, False)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def schema(repository_id: RepositoryId, configuration: Configuration) -> ConfigurationSchema:
|
def _set_service_config_validate_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
|
"""
|
||||||
|
add parser for config validation subcommand
|
||||||
|
|
||||||
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
|
"""
|
||||||
|
parser = root.add_parser("service-config-validate", aliases=["config-validate", "repo-config-validate"],
|
||||||
|
help="validate system configuration",
|
||||||
|
description="validate configuration and print found errors")
|
||||||
|
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if configuration is invalid",
|
||||||
|
action="store_true")
|
||||||
|
parser.set_defaults(lock=None, quiet=True, report=False, unsafe=True)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def schema(configuration: Configuration) -> ConfigurationSchema:
|
||||||
"""
|
"""
|
||||||
get schema with triggers
|
get schema with triggers
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
repository_id(RepositoryId): repository unique identifier
|
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@@ -87,12 +106,12 @@ class Validate(Handler):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
# default settings if any
|
# default settings if any
|
||||||
for schema_name, schema in trigger_class.configuration_schema(repository_id, None).items():
|
for schema_name, schema in trigger_class.configuration_schema(None).items():
|
||||||
erased = Validate.schema_erase_required(copy.deepcopy(schema))
|
erased = Validate.schema_erase_required(copy.deepcopy(schema))
|
||||||
root[schema_name] = Validate.schema_merge(root.get(schema_name, {}), erased)
|
root[schema_name] = Validate.schema_merge(root.get(schema_name, {}), erased)
|
||||||
|
|
||||||
# settings according to enabled triggers
|
# settings according to enabled triggers
|
||||||
for schema_name, schema in trigger_class.configuration_schema(repository_id, configuration).items():
|
for schema_name, schema in trigger_class.configuration_schema(configuration).items():
|
||||||
root[schema_name] = Validate.schema_merge(root.get(schema_name, {}), copy.deepcopy(schema))
|
root[schema_name] = Validate.schema_merge(root.get(schema_name, {}), copy.deepcopy(schema))
|
||||||
|
|
||||||
return root
|
return root
|
||||||
@@ -135,3 +154,5 @@ class Validate(Handler):
|
|||||||
Validate.schema_merge(value, schema[key])
|
Validate.schema_merge(value, schema[key])
|
||||||
|
|
||||||
return schema
|
return schema
|
||||||
|
|
||||||
|
arguments = [_set_service_config_validate_parser]
|
||||||
+26
-7
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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,11 +21,12 @@ import argparse
|
|||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from collections.abc import Generator
|
from collections.abc import Iterator
|
||||||
from importlib import metadata
|
from importlib import metadata
|
||||||
|
from typing import ClassVar
|
||||||
|
|
||||||
from ahriman import __version__
|
from ahriman import __version__
|
||||||
from ahriman.application.handlers.handler import Handler
|
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 VersionPrinter
|
from ahriman.core.formatters import VersionPrinter
|
||||||
from ahriman.models.repository_id import RepositoryId
|
from ahriman.models.repository_id import RepositoryId
|
||||||
@@ -36,11 +37,11 @@ class Versions(Handler):
|
|||||||
version handler
|
version handler
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
PEP423_PACKAGE_NAME(str): (class attribute) special regex for valid PEP423 package name
|
PEP423_PACKAGE_NAME(re.Pattern[str]): (class attribute) special regex for valid PEP423 package name
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ALLOW_MULTI_ARCHITECTURE_RUN = False # system-wide action
|
ALLOW_MULTI_ARCHITECTURE_RUN = False # system-wide action
|
||||||
PEP423_PACKAGE_NAME = re.compile(r"^[A-Za-z0-9._-]+")
|
PEP423_PACKAGE_NAME: ClassVar[re.Pattern[str]] = re.compile(r"^[A-Za-z0-9._-]+")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
|
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
|
||||||
@@ -60,7 +61,23 @@ class Versions(Handler):
|
|||||||
VersionPrinter("Installed packages", dict(packages))(verbose=False, separator=" ")
|
VersionPrinter("Installed packages", dict(packages))(verbose=False, separator=" ")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def package_dependencies(root: str) -> Generator[tuple[str, str], None, None]:
|
def _set_help_version_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
|
"""
|
||||||
|
add parser for version subcommand
|
||||||
|
|
||||||
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
|
"""
|
||||||
|
parser = root.add_parser("help-version", aliases=["version"], help="application version",
|
||||||
|
description="print application and its dependencies versions")
|
||||||
|
parser.set_defaults(architecture="", lock=None, quiet=True, report=False, repository="", unsafe=True)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def package_dependencies(root: str) -> Iterator[tuple[str, str]]:
|
||||||
"""
|
"""
|
||||||
extract list of ahriman package dependencies installed into system with their versions
|
extract list of ahriman package dependencies installed into system with their versions
|
||||||
|
|
||||||
@@ -70,7 +87,7 @@ class Versions(Handler):
|
|||||||
Yields:
|
Yields:
|
||||||
tuple[str, str]: map of installed dependency to its version
|
tuple[str, str]: map of installed dependency to its version
|
||||||
"""
|
"""
|
||||||
def dependencies_by_key(key: str) -> Generator[str, None, None]:
|
def dependencies_by_key(key: str) -> Iterator[str]:
|
||||||
# in importlib it returns requires in the following format
|
# in importlib it returns requires in the following format
|
||||||
# ["pytest (>=3.0.0) ; extra == 'test'", "pytest-cov ; extra == 'test'"]
|
# ["pytest (>=3.0.0) ; extra == 'test'", "pytest-cov ; extra == 'test'"]
|
||||||
try:
|
try:
|
||||||
@@ -96,3 +113,5 @@ class Versions(Handler):
|
|||||||
yield distribution.name, distribution.version
|
yield distribution.name, distribution.version
|
||||||
except metadata.PackageNotFoundError:
|
except metadata.PackageNotFoundError:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
arguments = [_set_help_version_parser]
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2026 ahriman team.
|
||||||
|
#
|
||||||
|
# This file is part of ahriman
|
||||||
|
# (see https://github.com/arcan1s/ahriman).
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
import argparse
|
||||||
|
import re
|
||||||
|
import textwrap
|
||||||
|
|
||||||
|
|
||||||
|
class _HelpFormatter(argparse.ArgumentDefaultsHelpFormatter):
|
||||||
|
"""
|
||||||
|
:class:`argparse.ArgumentDefaultsHelpFormatter` extension which keeps new lines in help messages
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, prog: str) -> None:
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
prog(str): application name
|
||||||
|
"""
|
||||||
|
argparse.ArgumentDefaultsHelpFormatter.__init__(self, prog, width=120)
|
||||||
|
self._whitespace_matcher = re.compile(r"[ \t]+")
|
||||||
|
|
||||||
|
def _fill_text(self, text: str, width: int, indent: str) -> str:
|
||||||
|
"""
|
||||||
|
implementation of the protected method to format text. Format text, keeping new lines
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text(str): text to format
|
||||||
|
width(int): maximal text width
|
||||||
|
indent(str): indentation string
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: formatted text
|
||||||
|
"""
|
||||||
|
text = self._whitespace_matcher.sub(" ", text).strip()
|
||||||
|
return "\n".join([
|
||||||
|
textwrap.fill(line, width, initial_indent=indent, subsequent_indent=indent)
|
||||||
|
for line in text.splitlines()
|
||||||
|
])
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2026 ahriman team.
|
||||||
|
#
|
||||||
|
# This file is part of ahriman
|
||||||
|
# (see https://github.com/arcan1s/ahriman).
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
from code import InteractiveConsole
|
||||||
|
from importlib.util import find_spec
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
|
class InteractiveShell(InteractiveConsole):
|
||||||
|
"""
|
||||||
|
wrapper around :class:`code.InteractiveConsole` to pass :func:`interact()` to IPython shell
|
||||||
|
"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def has_ipython() -> bool:
|
||||||
|
"""
|
||||||
|
check if IPython shell is available
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: ``True`` if IPython shell is available, ``False`` otherwise
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return find_spec("IPython.terminal.embed") is not None
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def interact(self, *args: Any, **kwargs: Any) -> None:
|
||||||
|
"""
|
||||||
|
pass controller to IPython shell
|
||||||
|
|
||||||
|
Args:
|
||||||
|
*args(Any): positional arguments
|
||||||
|
**kwargs(Any): keyword arguments
|
||||||
|
"""
|
||||||
|
if self.has_ipython():
|
||||||
|
from IPython.terminal.embed import InteractiveShellEmbed
|
||||||
|
|
||||||
|
shell = InteractiveShellEmbed(user_ns=self.locals) # type: ignore[no-untyped-call]
|
||||||
|
shell.show_banner() # type: ignore[no-untyped-call]
|
||||||
|
shell.interact() # type: ignore[no-untyped-call]
|
||||||
|
else:
|
||||||
|
# fallback to default
|
||||||
|
import readline # pylint: disable=unused-import
|
||||||
|
InteractiveConsole.interact(self, *args, **kwargs)
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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,7 +18,10 @@
|
|||||||
# 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 fcntl
|
||||||
|
import os
|
||||||
|
|
||||||
|
from io import TextIOWrapper
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from types import TracebackType
|
from types import TracebackType
|
||||||
from typing import Literal, Self
|
from typing import Literal, Self
|
||||||
@@ -27,8 +30,8 @@ from ahriman import __version__
|
|||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
from ahriman.core.exceptions import DuplicateRunError
|
from ahriman.core.exceptions import DuplicateRunError
|
||||||
from ahriman.core.log import LazyLogging
|
from ahriman.core.log import LazyLogging
|
||||||
from ahriman.core.status.client import Client
|
from ahriman.core.status import Client
|
||||||
from ahriman.core.util import check_user
|
from ahriman.core.utils import check_user
|
||||||
from ahriman.models.build_status import BuildStatusEnum
|
from ahriman.models.build_status import BuildStatusEnum
|
||||||
from ahriman.models.repository_id import RepositoryId
|
from ahriman.models.repository_id import RepositoryId
|
||||||
from ahriman.models.waiter import Waiter
|
from ahriman.models.waiter import Waiter
|
||||||
@@ -36,7 +39,7 @@ from ahriman.models.waiter import Waiter
|
|||||||
|
|
||||||
class Lock(LazyLogging):
|
class Lock(LazyLogging):
|
||||||
"""
|
"""
|
||||||
wrapper for application lock file
|
wrapper for application lock file. Credits for idea to https://github.com/bmhatfield/python-pidfile.git
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
force(bool): remove lock file on start if any
|
force(bool): remove lock file on start if any
|
||||||
@@ -55,23 +58,28 @@ class Lock(LazyLogging):
|
|||||||
>>>
|
>>>
|
||||||
>>> configuration = Configuration()
|
>>> configuration = Configuration()
|
||||||
>>> try:
|
>>> try:
|
||||||
>>> with Lock(args, RepositoryId("x86_64", "aur-clone"), configuration):
|
>>> with Lock(args, RepositoryId("x86_64", "aur"), configuration):
|
||||||
>>> perform_actions()
|
>>> do_something()
|
||||||
>>> except Exception as exception:
|
>>> except Exception as exception:
|
||||||
>>> handle_exceptions(exception)
|
>>> handle_exceptions(exception)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration) -> None:
|
def __init__(self, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
args(argparse.Namespace): command line args
|
args(argparse.Namespace): command line args
|
||||||
repository_id(RepositoryId): repository unique identifier
|
repository_id(RepositoryId): repository unique identifier
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
"""
|
"""
|
||||||
self.path: Path | None = \
|
self.path: Path | None = None
|
||||||
args.lock.with_stem(f"{args.lock.stem}_{repository_id.id}") if args.lock is not None else None
|
if args.lock is not None:
|
||||||
|
self.path = args.lock
|
||||||
|
if not repository_id.is_empty:
|
||||||
|
self.path = self.path.with_stem(f"{args.lock.stem}_{repository_id.id}")
|
||||||
|
if not self.path.is_absolute():
|
||||||
|
# prepend full path to the lock file
|
||||||
|
self.path = Path("/") / "run" / "ahriman" / self.path
|
||||||
|
self._pid_file: TextIOWrapper | None = None
|
||||||
|
|
||||||
self.force: bool = args.force
|
self.force: bool = args.force
|
||||||
self.unsafe: bool = args.unsafe
|
self.unsafe: bool = args.unsafe
|
||||||
@@ -80,11 +88,77 @@ class Lock(LazyLogging):
|
|||||||
self.paths = configuration.repository_paths
|
self.paths = configuration.repository_paths
|
||||||
self.reporter = Client.load(repository_id, configuration, report=args.report)
|
self.reporter = Client.load(repository_id, configuration, report=args.report)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def perform_lock(fd: int) -> bool:
|
||||||
|
"""
|
||||||
|
perform file lock
|
||||||
|
|
||||||
|
Args:
|
||||||
|
fd(int): file descriptor:
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: ``True`` in case if file is locked and ``False`` otherwise
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||||||
|
except OSError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _open(self) -> None:
|
||||||
|
"""
|
||||||
|
create lock file
|
||||||
|
"""
|
||||||
|
if self.path is None:
|
||||||
|
return
|
||||||
|
self._pid_file = self.path.open("a+", encoding="utf8")
|
||||||
|
|
||||||
|
def _watch(self) -> bool:
|
||||||
|
"""
|
||||||
|
watch until lock disappear
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: ``True`` in case if file is locked and ``False`` otherwise
|
||||||
|
"""
|
||||||
|
# there are reasons why we are not using inotify here. First of all, if we would use it, it would bring to
|
||||||
|
# race conditions because multiple processes will be notified at the same time. Secondly, it is good library,
|
||||||
|
# but platform-specific, and we only need to check if file exists
|
||||||
|
if self._pid_file is None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
waiter = Waiter(self.wait_timeout)
|
||||||
|
return bool(waiter.wait(lambda fd: not self.perform_lock(fd), self._pid_file.fileno()))
|
||||||
|
|
||||||
|
def _write(self, *, is_locked: bool = False) -> None:
|
||||||
|
"""
|
||||||
|
write pid to the lock file
|
||||||
|
|
||||||
|
Args:
|
||||||
|
is_locked(bool, optional): indicates if file was already locked or not (Default value = False)
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
DuplicateRunError: if it cannot lock PID file
|
||||||
|
"""
|
||||||
|
if self._pid_file is None:
|
||||||
|
return
|
||||||
|
if not is_locked:
|
||||||
|
if not self.perform_lock(self._pid_file.fileno()):
|
||||||
|
raise DuplicateRunError
|
||||||
|
|
||||||
|
self._pid_file.seek(0) # reset position and remove file content if any
|
||||||
|
self._pid_file.truncate()
|
||||||
|
|
||||||
|
self._pid_file.write(str(os.getpid())) # write current pid
|
||||||
|
self._pid_file.flush() # flush data to disk
|
||||||
|
|
||||||
|
self._pid_file.seek(0) # reset position again
|
||||||
|
|
||||||
def check_user(self) -> None:
|
def check_user(self) -> None:
|
||||||
"""
|
"""
|
||||||
check if current user is actually owner of ahriman root
|
check if current user is actually owner of ahriman root
|
||||||
"""
|
"""
|
||||||
check_user(self.paths, unsafe=self.unsafe)
|
check_user(self.paths.root, unsafe=self.unsafe)
|
||||||
self.paths.tree_create()
|
self.paths.tree_create()
|
||||||
|
|
||||||
def check_version(self) -> None:
|
def check_version(self) -> None:
|
||||||
@@ -100,46 +174,33 @@ class Lock(LazyLogging):
|
|||||||
"""
|
"""
|
||||||
remove lock file
|
remove lock file
|
||||||
"""
|
"""
|
||||||
if self.path is None:
|
if self._pid_file is not None: # close file descriptor
|
||||||
return
|
try:
|
||||||
self.path.unlink(missing_ok=True)
|
self._pid_file.close()
|
||||||
|
except IOError:
|
||||||
|
pass # suppress any IO errors occur
|
||||||
|
if self.path is not None: # remove lock file
|
||||||
|
self.path.unlink(missing_ok=True)
|
||||||
|
|
||||||
def create(self) -> None:
|
def lock(self) -> None:
|
||||||
"""
|
"""
|
||||||
create lock file
|
create pid file
|
||||||
|
|
||||||
Raises:
|
|
||||||
DuplicateRunError: if lock exists and no force flag supplied
|
|
||||||
"""
|
"""
|
||||||
if self.path is None:
|
if self.force: # remove lock if force flag is set
|
||||||
return
|
self.clear()
|
||||||
try:
|
self._open()
|
||||||
self.path.touch(exist_ok=self.force)
|
is_locked = self._watch()
|
||||||
except FileExistsError:
|
self._write(is_locked=is_locked)
|
||||||
raise DuplicateRunError from None
|
|
||||||
|
|
||||||
def watch(self) -> None:
|
|
||||||
"""
|
|
||||||
watch until lock disappear
|
|
||||||
"""
|
|
||||||
# there are reasons why we are not using inotify here. First of all, if we would use it, it would bring to
|
|
||||||
# race conditions because multiple processes will be notified in the same time. Secondly, it is good library,
|
|
||||||
# but platform-specific, and we only need to check if file exists
|
|
||||||
if self.path is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
waiter = Waiter(self.wait_timeout)
|
|
||||||
waiter.wait(self.path.is_file)
|
|
||||||
|
|
||||||
def __enter__(self) -> Self:
|
def __enter__(self) -> Self:
|
||||||
"""
|
"""
|
||||||
default workflow is the following:
|
default workflow is the following:
|
||||||
|
|
||||||
#. Check user UID
|
#. Check user UID
|
||||||
#. Check if there is lock file
|
|
||||||
#. Check web status watcher status
|
#. Check web status watcher status
|
||||||
|
#. Open lock file
|
||||||
#. Wait for lock file to be free
|
#. Wait for lock file to be free
|
||||||
#. Create lock file and directory tree
|
#. Write current PID to the lock file
|
||||||
#. Report to status page if enabled
|
#. Report to status page if enabled
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@@ -147,8 +208,7 @@ class Lock(LazyLogging):
|
|||||||
"""
|
"""
|
||||||
self.check_user()
|
self.check_user()
|
||||||
self.check_version()
|
self.check_version()
|
||||||
self.watch()
|
self.lock()
|
||||||
self.create()
|
|
||||||
self.reporter.status_update(BuildStatusEnum.Building)
|
self.reporter.status_update(BuildStatusEnum.Building)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@@ -163,7 +223,7 @@ class Lock(LazyLogging):
|
|||||||
exc_tb(TracebackType): exception traceback if any
|
exc_tb(TracebackType): exception traceback if any
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Literal[False]: always False (do not suppress any exception)
|
Literal[False]: always ``False`` (do not suppress any exception)
|
||||||
"""
|
"""
|
||||||
self.clear()
|
self.clear()
|
||||||
status = BuildStatusEnum.Success if exc_val is None else BuildStatusEnum.Failed
|
status = BuildStatusEnum.Success if exc_val is None else BuildStatusEnum.Failed
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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).
|
||||||
@@ -33,17 +33,15 @@ class _Context:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
"""
|
""""""
|
||||||
default constructor. Must not be used directly
|
|
||||||
"""
|
|
||||||
self._content: dict[str, Any] = {}
|
self._content: dict[str, Any] = {}
|
||||||
|
|
||||||
def get(self, key: ContextKey[T]) -> T:
|
def get(self, key: ContextKey[T] | type[T]) -> T:
|
||||||
"""
|
"""
|
||||||
get value for the specified key
|
get value for the specified key
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
key(ContextKey[T]): context key name
|
key(ContextKey[T] | type[T]): context key name
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
T: value associated with the key
|
T: value associated with the key
|
||||||
@@ -52,29 +50,37 @@ class _Context:
|
|||||||
KeyError: in case if the specified context variable was not found
|
KeyError: in case if the specified context variable was not found
|
||||||
ValueError: in case if type of value is not an instance of specified return type
|
ValueError: in case if type of value is not an instance of specified return type
|
||||||
"""
|
"""
|
||||||
|
if not isinstance(key, ContextKey):
|
||||||
|
key = ContextKey.from_type(key)
|
||||||
|
|
||||||
if key.key not in self._content:
|
if key.key not in self._content:
|
||||||
raise KeyError(key.key)
|
raise KeyError(key.key)
|
||||||
value = self._content[key.key]
|
value = self._content[key.key]
|
||||||
if not isinstance(value, key.return_type):
|
if not isinstance(value, key.return_type):
|
||||||
raise ValueError(f"Value {value} is not an instance of {key.return_type}")
|
raise ValueError(f"Value {value} is not an instance of {key.return_type}")
|
||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def set(self, key: ContextKey[T], value: T) -> None:
|
def set(self, key: ContextKey[T] | type[T], value: T) -> None:
|
||||||
"""
|
"""
|
||||||
set value for the specified key
|
set value for the specified key
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
key(ContextKey[T]): context key name
|
key(ContextKey[T] | type[T]): context key name
|
||||||
value(T): context value associated with the specified key
|
value(T): context value associated with the specified key
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
KeyError: in case if the specified context variable already exists
|
KeyError: in case if the specified context variable already exists
|
||||||
ValueError: in case if type of value is not an instance of specified return type
|
ValueError: in case if type of value is not an instance of specified return type
|
||||||
"""
|
"""
|
||||||
|
if not isinstance(key, ContextKey):
|
||||||
|
key = ContextKey.from_type(key)
|
||||||
|
|
||||||
if key.key in self._content:
|
if key.key in self._content:
|
||||||
raise KeyError(key.key)
|
raise KeyError(key.key)
|
||||||
if not isinstance(value, key.return_type):
|
if not isinstance(value, key.return_type):
|
||||||
raise ValueError(f"Value {value} is not an instance of {key.return_type}")
|
raise ValueError(f"Value {value} is not an instance of {key.return_type}")
|
||||||
|
|
||||||
self._content[key.key] = value
|
self._content[key.key] = value
|
||||||
|
|
||||||
def __iter__(self) -> Iterator[str]:
|
def __iter__(self) -> Iterator[str]:
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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).
|
||||||
@@ -0,0 +1,275 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2026 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 itertools
|
||||||
|
import shutil
|
||||||
|
import tarfile
|
||||||
|
|
||||||
|
from collections.abc import Iterable, Iterator
|
||||||
|
from functools import cached_property
|
||||||
|
from pathlib import Path
|
||||||
|
from pyalpm import DB, Package, SIG_DATABASE_OPTIONAL, SIG_PACKAGE_OPTIONAL # type: ignore[import-not-found]
|
||||||
|
from string import Template
|
||||||
|
|
||||||
|
from ahriman.core.alpm.pacman_database import PacmanDatabase
|
||||||
|
from ahriman.core.alpm.pacman_handle import PacmanHandle
|
||||||
|
from ahriman.core.configuration import Configuration
|
||||||
|
from ahriman.core.log import LazyLogging
|
||||||
|
from ahriman.core.utils import trim_package
|
||||||
|
from ahriman.models.pacman_synchronization import PacmanSynchronization
|
||||||
|
from ahriman.models.repository_id import RepositoryId
|
||||||
|
|
||||||
|
|
||||||
|
class Pacman(LazyLogging):
|
||||||
|
"""
|
||||||
|
alpm wrapper
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
configuration(Configuration): configuration instance
|
||||||
|
refresh_database(PacmanSynchronization): synchronize local cache to remote
|
||||||
|
repository_id(RepositoryId): repository unique identifier
|
||||||
|
repository_paths(RepositoryPaths): repository paths instance
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, repository_id: RepositoryId, configuration: Configuration, *,
|
||||||
|
refresh_database: PacmanSynchronization) -> None:
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
repository_id(RepositoryId): repository unique identifier
|
||||||
|
configuration(Configuration): configuration instance
|
||||||
|
refresh_database(PacmanSynchronization): synchronize local cache to remote
|
||||||
|
"""
|
||||||
|
self.configuration = configuration
|
||||||
|
self.repository_id = repository_id
|
||||||
|
self.repository_paths = configuration.repository_paths
|
||||||
|
|
||||||
|
self.refresh_database = refresh_database
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def handle(self) -> PacmanHandle:
|
||||||
|
"""
|
||||||
|
pyalpm handle
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
PacmanHandle: generated pyalpm handle instance
|
||||||
|
"""
|
||||||
|
return self.__create_handle(refresh_database=self.refresh_database)
|
||||||
|
|
||||||
|
def __create_handle(self, *, refresh_database: PacmanSynchronization) -> PacmanHandle:
|
||||||
|
"""
|
||||||
|
create lazy handle function
|
||||||
|
|
||||||
|
Args:
|
||||||
|
refresh_database(PacmanSynchronization): synchronize local cache to remote
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
PacmanHandle: fully initialized pacman handle
|
||||||
|
"""
|
||||||
|
pacman_root = self.configuration.getpath("alpm", "database")
|
||||||
|
use_ahriman_cache = self.configuration.getboolean("alpm", "use_ahriman_cache")
|
||||||
|
|
||||||
|
database_path = self.repository_paths.pacman if use_ahriman_cache else pacman_root
|
||||||
|
root = self.configuration.getpath("alpm", "root")
|
||||||
|
handle = PacmanHandle(str(root), str(database_path))
|
||||||
|
|
||||||
|
for repository in self.configuration.getlist("alpm", "repositories"):
|
||||||
|
database = self.database_init(handle, repository, self.repository_id.architecture)
|
||||||
|
self.database_copy(handle, database, pacman_root, use_ahriman_cache=use_ahriman_cache)
|
||||||
|
|
||||||
|
# install repository database too (without copying)
|
||||||
|
self.database_init(handle, self.repository_id.name, self.repository_id.architecture)
|
||||||
|
|
||||||
|
if use_ahriman_cache and refresh_database:
|
||||||
|
self.database_sync(handle, force=refresh_database == PacmanSynchronization.Force)
|
||||||
|
|
||||||
|
return handle
|
||||||
|
|
||||||
|
def database_copy(self, handle: PacmanHandle, database: DB, pacman_root: Path, *, use_ahriman_cache: bool) -> None:
|
||||||
|
"""
|
||||||
|
copy database from the operating system root to the ahriman local home
|
||||||
|
|
||||||
|
Args:
|
||||||
|
handle(PacmanHandle): pacman handle which will be used for database copying
|
||||||
|
database(DB): pacman database instance to be copied
|
||||||
|
pacman_root(Path): operating system pacman root
|
||||||
|
use_ahriman_cache(bool): use local ahriman cache instead of system one
|
||||||
|
"""
|
||||||
|
def repository_database(root: Path) -> Path:
|
||||||
|
return root / "sync" / f"{database.name}.db"
|
||||||
|
|
||||||
|
if not use_ahriman_cache:
|
||||||
|
return
|
||||||
|
|
||||||
|
# copy root database if no local copy found
|
||||||
|
pacman_db_path = Path(handle.dbpath)
|
||||||
|
if not pacman_db_path.is_dir():
|
||||||
|
return # root directory does not exist yet
|
||||||
|
dst = repository_database(pacman_db_path)
|
||||||
|
if dst.is_file():
|
||||||
|
return # file already exists, do not copy
|
||||||
|
dst.parent.mkdir(mode=0o755, exist_ok=True) # create sync directory if it doesn't exist
|
||||||
|
|
||||||
|
src = repository_database(pacman_root)
|
||||||
|
if not src.is_file():
|
||||||
|
self.logger.warning("repository %s is set to be used, however, no working copy was found", database.name)
|
||||||
|
return # database for some reason deos not exist
|
||||||
|
|
||||||
|
self.logger.info("copy pacman database %s from operating system root to ahriman's home %s", src, dst)
|
||||||
|
with self.repository_paths.preserve_owner():
|
||||||
|
shutil.copy(src, dst)
|
||||||
|
|
||||||
|
def database_init(self, handle: PacmanHandle, repository: str, architecture: str) -> DB:
|
||||||
|
"""
|
||||||
|
create database instance from pacman handler and set its properties
|
||||||
|
|
||||||
|
Args:
|
||||||
|
handle(PacmanHandle): pacman handle which will be used for database initializing
|
||||||
|
repository(str): pacman repository name (e.g. core)
|
||||||
|
architecture(str): repository architecture
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
DB: loaded pacman database instance
|
||||||
|
"""
|
||||||
|
self.logger.info("loading pacman database %s", repository)
|
||||||
|
database: DB = handle.register_syncdb(repository, SIG_DATABASE_OPTIONAL | SIG_PACKAGE_OPTIONAL)
|
||||||
|
|
||||||
|
if repository != self.repository_id.name:
|
||||||
|
mirror = self.configuration.get("alpm", "mirror")
|
||||||
|
# replace variables in mirror address
|
||||||
|
variables = {
|
||||||
|
"arch": architecture,
|
||||||
|
"repo": repository,
|
||||||
|
}
|
||||||
|
server = Template(mirror).safe_substitute(variables)
|
||||||
|
else:
|
||||||
|
# special case, same database, use local storage instead
|
||||||
|
server = f"file://{self.repository_paths.repository}"
|
||||||
|
|
||||||
|
database.servers = [server]
|
||||||
|
|
||||||
|
return database
|
||||||
|
|
||||||
|
def database_sync(self, handle: PacmanHandle, *, force: bool) -> None:
|
||||||
|
"""
|
||||||
|
sync local database
|
||||||
|
|
||||||
|
Args:
|
||||||
|
handle(PacmanHandle): pacman handle which will be used for database sync
|
||||||
|
force(bool): force database synchronization (same as ``pacman -Syy``)
|
||||||
|
"""
|
||||||
|
self.logger.info("refresh ahriman's home pacman database (force refresh %s)", force)
|
||||||
|
transaction = handle.init_transaction()
|
||||||
|
for database in handle.get_syncdbs():
|
||||||
|
PacmanDatabase(database, self.configuration).sync(force=force)
|
||||||
|
transaction.release()
|
||||||
|
|
||||||
|
def files(self, packages: Iterable[str]) -> dict[str, set[str]]:
|
||||||
|
"""
|
||||||
|
extract list of known packages from the databases
|
||||||
|
|
||||||
|
Args:
|
||||||
|
packages(Iterable[str]): filter by package names
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict[str, set[str]]: map of package name to its list of files
|
||||||
|
"""
|
||||||
|
def extract(tar: tarfile.TarFile, versions: dict[str, str]) -> Iterator[tuple[str, set[str]]]:
|
||||||
|
for package_name, version in versions.items():
|
||||||
|
path = Path(f"{package_name}-{version}") / "files"
|
||||||
|
try:
|
||||||
|
content = tar.extractfile(str(path))
|
||||||
|
except KeyError:
|
||||||
|
# in case if database and its files has been desync somehow, the extractfile will raise
|
||||||
|
# KeyError because the entry doesn't exist
|
||||||
|
content = None
|
||||||
|
if content is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# this is just array of files, however, the directories are with trailing slash,
|
||||||
|
# which previously has been removed by the conversion to ``pathlib.Path``
|
||||||
|
files = {filename.decode("utf8").rstrip().removesuffix("/") for filename in content.readlines()}
|
||||||
|
yield package_name, files
|
||||||
|
|
||||||
|
# sort is required for the following group by operation
|
||||||
|
descriptors = sorted(
|
||||||
|
(package for package_name in packages for package in self.package(package_name)),
|
||||||
|
key=lambda package: package.db.name
|
||||||
|
)
|
||||||
|
|
||||||
|
result: dict[str, set[str]] = {}
|
||||||
|
for database_name, pacman_packages in itertools.groupby(descriptors, lambda package: package.db.name):
|
||||||
|
database_file = self.repository_paths.pacman / "sync" / f"{database_name}.files.tar.gz"
|
||||||
|
if not database_file.is_file():
|
||||||
|
continue # no database file found
|
||||||
|
|
||||||
|
package_names = {package.name: package.version for package in pacman_packages}
|
||||||
|
with tarfile.open(database_file, "r:gz") as archive:
|
||||||
|
result.update(extract(archive, package_names))
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def package(self, package_name: str) -> Iterator[Package]:
|
||||||
|
"""
|
||||||
|
retrieve list of the packages from the repository by name
|
||||||
|
|
||||||
|
Args:
|
||||||
|
package_name(str): package name to search
|
||||||
|
|
||||||
|
Yields:
|
||||||
|
Package: list of packages which were returned by the query
|
||||||
|
"""
|
||||||
|
for database in self.handle.get_syncdbs():
|
||||||
|
package = database.get_pkg(package_name)
|
||||||
|
if package is None:
|
||||||
|
continue
|
||||||
|
yield package
|
||||||
|
|
||||||
|
def packages(self) -> set[str]:
|
||||||
|
"""
|
||||||
|
get list of packages known for alpm
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
set[str]: list of package names
|
||||||
|
"""
|
||||||
|
result: set[str] = set()
|
||||||
|
for database in self.handle.get_syncdbs():
|
||||||
|
for package in database.pkgcache:
|
||||||
|
# package itself
|
||||||
|
result.add(package.name)
|
||||||
|
# provides list for meta-packages
|
||||||
|
result.update(trim_package(provides) for provides in package.provides)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def provided_by(self, package_name: str) -> Iterator[Package]:
|
||||||
|
"""
|
||||||
|
search through databases and emit packages which provides the ``package_name``
|
||||||
|
|
||||||
|
Args:
|
||||||
|
package_name(str): package name to search
|
||||||
|
|
||||||
|
Yields:
|
||||||
|
Package: list of packages which were returned by the query
|
||||||
|
"""
|
||||||
|
def is_package_provided(package: Package) -> bool:
|
||||||
|
provides = [trim_package(name) for name in package.provides]
|
||||||
|
return package_name in provides
|
||||||
|
|
||||||
|
for database in self.handle.get_syncdbs():
|
||||||
|
yield from filter(is_package_provided, database.search(package_name))
|
||||||
@@ -0,0 +1,176 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2026 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 os
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
from email.utils import parsedate_to_datetime
|
||||||
|
from pathlib import Path
|
||||||
|
from pyalpm import DB # type: ignore[import-not-found]
|
||||||
|
from typing import ClassVar
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
|
from ahriman.core.configuration import Configuration
|
||||||
|
from ahriman.core.exceptions import PacmanError
|
||||||
|
from ahriman.core.http import SyncHttpClient
|
||||||
|
|
||||||
|
|
||||||
|
class PacmanDatabase(SyncHttpClient):
|
||||||
|
"""
|
||||||
|
implementation for database sync, because pyalpm is not always enough
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
LAST_MODIFIED_HEADER(str): last modified header name
|
||||||
|
database(DB): pyalpm database object
|
||||||
|
repository_paths(RepositoryPaths): repository paths instance
|
||||||
|
sync_files_database(bool): sync files database
|
||||||
|
"""
|
||||||
|
|
||||||
|
LAST_MODIFIED_HEADER: ClassVar[str] = "Last-Modified"
|
||||||
|
|
||||||
|
def __init__(self, database: DB, configuration: Configuration) -> None:
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
database(DB): pyalpm database object
|
||||||
|
configuration(Configuration): configuration instance
|
||||||
|
"""
|
||||||
|
SyncHttpClient.__init__(self)
|
||||||
|
self.timeout = None # reset timeout
|
||||||
|
|
||||||
|
self.database = database
|
||||||
|
self.repository_paths = configuration.repository_paths
|
||||||
|
|
||||||
|
self.sync_files_database = configuration.getboolean("alpm", "sync_files_database")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def copy(remote_path: Path, local_path: Path) -> None:
|
||||||
|
"""
|
||||||
|
copy local database file
|
||||||
|
|
||||||
|
Args:
|
||||||
|
remote_path(Path): path to source (remote) file
|
||||||
|
local_path(Path): path to locally stored file
|
||||||
|
"""
|
||||||
|
shutil.copy(remote_path, local_path)
|
||||||
|
|
||||||
|
def download(self, url: str, local_path: Path) -> None:
|
||||||
|
"""
|
||||||
|
download remote file and store it to local path with the correct last modified headers
|
||||||
|
|
||||||
|
Args:
|
||||||
|
url(str): remote url to request file
|
||||||
|
local_path(Path): path to locally stored file
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
PacmanError: in case if no last-modified header was found
|
||||||
|
"""
|
||||||
|
response = self.make_request("GET", url, stream=True)
|
||||||
|
if self.LAST_MODIFIED_HEADER not in response.headers:
|
||||||
|
raise PacmanError("No last-modified header found")
|
||||||
|
|
||||||
|
with local_path.open("wb") as local_file:
|
||||||
|
for chunk in response.iter_content(chunk_size=1024):
|
||||||
|
local_file.write(chunk)
|
||||||
|
|
||||||
|
# set correct (a,m)time for the file
|
||||||
|
remote_changed = parsedate_to_datetime(response.headers[self.LAST_MODIFIED_HEADER]).timestamp()
|
||||||
|
os.utime(local_path, (remote_changed, remote_changed))
|
||||||
|
|
||||||
|
def is_outdated(self, url: str, local_path: Path) -> bool:
|
||||||
|
"""
|
||||||
|
check if local file is outdated
|
||||||
|
|
||||||
|
Args:
|
||||||
|
url(str): remote url to request last modified header
|
||||||
|
local_path(Path): path to locally stored file
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: ``True`` in case if remote file is newer than local file
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
PacmanError: in case if no last-modified header was found
|
||||||
|
"""
|
||||||
|
if not local_path.is_file():
|
||||||
|
return True # no local file found, requires to update
|
||||||
|
|
||||||
|
response = self.make_request("HEAD", url)
|
||||||
|
if self.LAST_MODIFIED_HEADER not in response.headers:
|
||||||
|
raise PacmanError("No last-modified header found")
|
||||||
|
|
||||||
|
remote_changed = parsedate_to_datetime(response.headers["Last-Modified"]).timestamp()
|
||||||
|
local_changed = local_path.stat().st_mtime
|
||||||
|
|
||||||
|
return remote_changed > local_changed
|
||||||
|
|
||||||
|
def sync(self, *, force: bool) -> None:
|
||||||
|
"""
|
||||||
|
sync packages and files databases
|
||||||
|
|
||||||
|
Args:
|
||||||
|
force(bool): force database synchronization (same as ``pacman -Syy``)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
self.sync_packages(force=force)
|
||||||
|
if self.sync_files_database:
|
||||||
|
self.sync_files(force=force)
|
||||||
|
except Exception:
|
||||||
|
self.logger.exception("exception during update %s", self.database.name)
|
||||||
|
|
||||||
|
def sync_files(self, *, force: bool) -> None:
|
||||||
|
"""
|
||||||
|
sync files by using http request
|
||||||
|
|
||||||
|
Args:
|
||||||
|
force(bool): force database synchronization (same as ``pacman -Syy``)
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
PacmanError: on operation error (invalid scheme or incomplete configuration)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
server = next(iter(self.database.servers))
|
||||||
|
except StopIteration:
|
||||||
|
raise PacmanError("No configured servers available for database") from None
|
||||||
|
filename = f"{self.database.name}.files.tar.gz"
|
||||||
|
url = f"{server}/{filename}"
|
||||||
|
|
||||||
|
remote_uri = urlparse(url)
|
||||||
|
local_path = Path(self.repository_paths.pacman / "sync" / filename)
|
||||||
|
|
||||||
|
match remote_uri.scheme:
|
||||||
|
case "http" | "https":
|
||||||
|
if not force and not self.is_outdated(url, local_path):
|
||||||
|
return
|
||||||
|
|
||||||
|
self.download(url, local_path)
|
||||||
|
|
||||||
|
case "file":
|
||||||
|
# just copy file as it is relatively cheap operation, no need to check timestamps
|
||||||
|
self.copy(Path(remote_uri.path), local_path)
|
||||||
|
|
||||||
|
case other:
|
||||||
|
raise PacmanError(f"Unknown or unsupported URL scheme {other}")
|
||||||
|
|
||||||
|
def sync_packages(self, *, force: bool) -> None:
|
||||||
|
"""
|
||||||
|
sync packages by using built-in pyalpm methods
|
||||||
|
|
||||||
|
Args:
|
||||||
|
force(bool): force database synchronization (same as ``pacman -Syy``)
|
||||||
|
"""
|
||||||
|
self.database.update(force)
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2026 ahriman team.
|
||||||
|
#
|
||||||
|
# This file is part of ahriman
|
||||||
|
# (see https://github.com/arcan1s/ahriman).
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
from pathlib import Path
|
||||||
|
from pyalpm import Handle, Package # type: ignore[import-not-found]
|
||||||
|
from tempfile import TemporaryDirectory
|
||||||
|
from typing import Any, ClassVar, Self
|
||||||
|
|
||||||
|
|
||||||
|
class PacmanHandle:
|
||||||
|
"""
|
||||||
|
lightweight wrapper for pacman handle to be used for direct alpm operations (e.g. package load)
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
handle(Handle): pyalpm handle instance
|
||||||
|
"""
|
||||||
|
|
||||||
|
_ephemeral: ClassVar[Self | None] = None
|
||||||
|
|
||||||
|
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
*args(Any): positional arguments for :class:`pyalpm.Handle`
|
||||||
|
**kwargs(Any): keyword arguments for :class:`pyalpm.Handle`
|
||||||
|
"""
|
||||||
|
self.handle = Handle(*args, **kwargs)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def ephemeral(cls) -> Self:
|
||||||
|
"""
|
||||||
|
create temporary instance with no access to real databases
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Self: loaded class
|
||||||
|
"""
|
||||||
|
if cls._ephemeral is None:
|
||||||
|
# handle creates alpm version file, but we don't use it
|
||||||
|
# so it is ok to just remove it
|
||||||
|
with TemporaryDirectory(ignore_cleanup_errors=True) as dir_name:
|
||||||
|
cls._ephemeral = cls("/", dir_name)
|
||||||
|
return cls._ephemeral
|
||||||
|
|
||||||
|
def package_load(self, path: Path) -> Package:
|
||||||
|
"""
|
||||||
|
load package from path to the archive
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path(Path): path to package archive
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Package: package instance
|
||||||
|
"""
|
||||||
|
return self.handle.load_pkg(str(path))
|
||||||
|
|
||||||
|
def __getattr__(self, item: str) -> Any:
|
||||||
|
"""
|
||||||
|
proxy methods for :class:`pyalpm.Handle`, because it doesn't allow subclassing
|
||||||
|
|
||||||
|
Args:
|
||||||
|
item(str): property name
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Any: attribute by its name
|
||||||
|
"""
|
||||||
|
return self.handle.__getattribute__(item)
|
||||||
@@ -0,0 +1,371 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2026 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 itertools
|
||||||
|
import re
|
||||||
|
import shlex
|
||||||
|
|
||||||
|
from collections.abc import Iterator
|
||||||
|
from enum import StrEnum
|
||||||
|
from typing import IO
|
||||||
|
|
||||||
|
from ahriman.core.exceptions import PkgbuildParserError
|
||||||
|
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
||||||
|
|
||||||
|
|
||||||
|
class PkgbuildToken(StrEnum):
|
||||||
|
"""
|
||||||
|
well-known tokens dictionary
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
ArrayEnds(PkgbuildToken): array ends token
|
||||||
|
ArrayStarts(PkgbuildToken): array starts token
|
||||||
|
Comma(PkgbuildToken): comma token
|
||||||
|
Comment(PkgbuildToken): comment token
|
||||||
|
FunctionDeclaration(PkgbuildToken): function declaration token
|
||||||
|
FunctionEnds(PkgbuildToken): function ends token
|
||||||
|
FunctionStarts(PkgbuildToken): function starts token
|
||||||
|
NewLine(PkgbuildToken): new line token
|
||||||
|
"""
|
||||||
|
|
||||||
|
ArrayStarts = "("
|
||||||
|
ArrayEnds = ")"
|
||||||
|
|
||||||
|
Comma = ","
|
||||||
|
|
||||||
|
Comment = "#"
|
||||||
|
|
||||||
|
FunctionDeclaration = "()"
|
||||||
|
FunctionStarts = "{"
|
||||||
|
FunctionEnds = "}"
|
||||||
|
|
||||||
|
NewLine = "\n"
|
||||||
|
|
||||||
|
|
||||||
|
class PkgbuildParser(shlex.shlex):
|
||||||
|
"""
|
||||||
|
simple pkgbuild reader implementation in pure python, because others suck.
|
||||||
|
|
||||||
|
What is it:
|
||||||
|
|
||||||
|
#. Simple PKGBUILD parser written in python.
|
||||||
|
#. No shell execution, so it is free from random shell attacks.
|
||||||
|
#. Able to parse simple constructions (assignments, comments, functions, arrays).
|
||||||
|
|
||||||
|
What it is not:
|
||||||
|
|
||||||
|
#. Fully functional shell parser.
|
||||||
|
#. Shell executor.
|
||||||
|
#. No parameter expansion.
|
||||||
|
|
||||||
|
For more details what does it support, please, consult with the test cases.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
This class is heavily based on :mod:`shlex` parser, but instead of strings operates with the
|
||||||
|
:class:`ahriman.models.pkgbuild_patch.PkgbuildPatch` objects. The main way to use it is to call :func:`parse()`
|
||||||
|
function and collect parsed objects, e.g.::
|
||||||
|
|
||||||
|
>>> parser = PkgbuildParser(StringIO("input string"))
|
||||||
|
>>> for patch in parser.parse():
|
||||||
|
>>> print(f"{patch.key} = {patch.value}")
|
||||||
|
|
||||||
|
It doesn't store the state of the fields (but operates with the :mod:`shlex` parser state), so no shell
|
||||||
|
post-processing is performed (e.g. variable substitution).
|
||||||
|
"""
|
||||||
|
|
||||||
|
_ARRAY_ASSIGNMENT = re.compile(r"^(?P<key>\w+)=$")
|
||||||
|
# in addition to usual assignment, functions can have dash
|
||||||
|
_FUNCTION_DECLARATION = re.compile(r"^(?P<key>[\w-]+)$")
|
||||||
|
_STRING_ASSIGNMENT = re.compile(r"^(?P<key>\w+)=(?P<value>.+)$")
|
||||||
|
|
||||||
|
def __init__(self, stream: IO[str]) -> None:
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
stream(IO[str]): input stream containing PKGBUILD content
|
||||||
|
"""
|
||||||
|
shlex.shlex.__init__(self, stream, posix=True, punctuation_chars=True)
|
||||||
|
self._io = stream # direct access without type casting
|
||||||
|
|
||||||
|
# ignore substitution and extend bash symbols
|
||||||
|
self.wordchars += "${}#:+-@!"
|
||||||
|
# in case of default behavior, it will ignore, for example, segment part of url outside of quotes
|
||||||
|
self.commenters = ""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _expand_array(array: list[str]) -> list[str]:
|
||||||
|
"""
|
||||||
|
bash array expansion simulator. It takes raw array and tries to expand constructions like
|
||||||
|
``(first prefix-{mid1,mid2}-suffix last)`` into ``(first, prefix-mid1-suffix prefix-mid2-suffix last)``
|
||||||
|
|
||||||
|
Args:
|
||||||
|
array(list[str]): input array
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[str]: either source array or expanded array if possible
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
PkgbuildParserError: if there are errors in parser
|
||||||
|
"""
|
||||||
|
# we are using comma as marker for expansion (if any)
|
||||||
|
if PkgbuildToken.Comma not in array:
|
||||||
|
return array
|
||||||
|
# again sanity check, for expansion there are at least 3 elements (first, last and comma)
|
||||||
|
if len(array) < 3:
|
||||||
|
return array
|
||||||
|
|
||||||
|
result = []
|
||||||
|
buffer, prefix = [], None
|
||||||
|
|
||||||
|
for index, (first, second) in enumerate(itertools.pairwise(array)):
|
||||||
|
match (first, second):
|
||||||
|
# in this case we check if expansion should be started
|
||||||
|
# this condition matches "prefix{first", ","
|
||||||
|
case (_, PkgbuildToken.Comma) if PkgbuildToken.FunctionStarts in first:
|
||||||
|
prefix, part = first.rsplit(PkgbuildToken.FunctionStarts, maxsplit=1)
|
||||||
|
buffer.append(f"{prefix}{part}")
|
||||||
|
|
||||||
|
# the last element case, it matches either ",", "last}" or ",", "last}suffix"
|
||||||
|
# in case if there is suffix, it must be appended to all list elements
|
||||||
|
case (PkgbuildToken.Comma, _) if prefix is not None and PkgbuildToken.FunctionEnds in second:
|
||||||
|
part, suffix = second.rsplit(PkgbuildToken.FunctionEnds, maxsplit=1)
|
||||||
|
buffer.append(f"{prefix}{part}")
|
||||||
|
result.extend([f"{part}{suffix}" for part in buffer])
|
||||||
|
# reset state
|
||||||
|
buffer, prefix = [], None
|
||||||
|
|
||||||
|
# we have already got prefix string, so we are in progress of expansion
|
||||||
|
# we always operate the last element, so this matches ",", "next"
|
||||||
|
case (PkgbuildToken.Comma, _) if prefix is not None:
|
||||||
|
buffer.append(f"{prefix}{second}")
|
||||||
|
|
||||||
|
# exactly first element of the list
|
||||||
|
case (_, _) if prefix is None and index == 0:
|
||||||
|
result.append(first)
|
||||||
|
|
||||||
|
# any next normal element
|
||||||
|
case (_, _) if prefix is None:
|
||||||
|
result.append(second)
|
||||||
|
|
||||||
|
# small sanity check
|
||||||
|
if prefix is not None:
|
||||||
|
raise PkgbuildParserError("error in array expansion", array)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def _is_escaped(self) -> bool:
|
||||||
|
"""
|
||||||
|
check if the last element was quoted. ``shlex.shlex`` parser doesn't provide information about was the token
|
||||||
|
quoted or not, thus there is no difference between "'#'" (sharp in quotes) and "#" (sharp without quotes). This
|
||||||
|
method simply rolls back to the last non-space character and check if it is a quotation mark
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: ``True`` if the previous element of the stream is a quote or escaped and ``False`` otherwise
|
||||||
|
"""
|
||||||
|
current_position = self._io.tell()
|
||||||
|
|
||||||
|
last_char = penultimate_char = None
|
||||||
|
index = current_position - 1
|
||||||
|
while index > 0:
|
||||||
|
index, last_char = self._read_last(index)
|
||||||
|
if last_char.isspace():
|
||||||
|
index -= 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
if index > 1:
|
||||||
|
_, penultimate_char = self._read_last(index - 1)
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
|
self._io.seek(current_position) # reset position of the stream
|
||||||
|
is_quoted = last_char is not None and last_char in self.quotes
|
||||||
|
is_escaped = penultimate_char is not None and penultimate_char in self.escape
|
||||||
|
|
||||||
|
return is_quoted or is_escaped
|
||||||
|
|
||||||
|
def _parse_array(self) -> list[str]:
|
||||||
|
"""
|
||||||
|
parse array from the PKGBUILD. This method will extract tokens from parser until it matches closing array,
|
||||||
|
modifying source parser state
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[str]: extracted arrays elements
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
PkgbuildParserError: if array is not closed
|
||||||
|
"""
|
||||||
|
def extract() -> Iterator[str]:
|
||||||
|
while token := self.get_token():
|
||||||
|
match token:
|
||||||
|
case _ if self._is_escaped():
|
||||||
|
pass
|
||||||
|
case PkgbuildToken.ArrayEnds:
|
||||||
|
break
|
||||||
|
case comment if comment.startswith(PkgbuildToken.Comment):
|
||||||
|
self._read_comment()
|
||||||
|
continue
|
||||||
|
|
||||||
|
yield token
|
||||||
|
|
||||||
|
if token != PkgbuildToken.ArrayEnds:
|
||||||
|
raise PkgbuildParserError("no closing array bracket found")
|
||||||
|
|
||||||
|
return self._expand_array(list(extract()))
|
||||||
|
|
||||||
|
def _parse_function(self) -> str:
|
||||||
|
"""
|
||||||
|
parse function from the PKGBUILD. This method will extract tokens from parser until it matches closing function,
|
||||||
|
modifying source parser state. Instead of trying to combine tokens together, it uses positions of the file
|
||||||
|
and reads content again in this range
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: function body
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
PkgbuildParserError: if function body wasn't found or parser input stream doesn't support position reading
|
||||||
|
"""
|
||||||
|
# find start and end positions
|
||||||
|
start_position = end_position = -1
|
||||||
|
counter = 0 # simple processing of the inner "{" and "}"
|
||||||
|
for token in self:
|
||||||
|
match token:
|
||||||
|
case _ if self._is_escaped():
|
||||||
|
continue
|
||||||
|
case PkgbuildToken.FunctionStarts:
|
||||||
|
if counter == 0:
|
||||||
|
start_position = self._io.tell() - 1
|
||||||
|
counter += 1
|
||||||
|
case PkgbuildToken.FunctionEnds:
|
||||||
|
end_position = self._io.tell()
|
||||||
|
if self.state != self.eof: # type: ignore[attr-defined]
|
||||||
|
end_position -= 1 # if we are not at the end of the file, position is _after_ the token
|
||||||
|
counter -= 1
|
||||||
|
if counter == 0:
|
||||||
|
break
|
||||||
|
case comment if comment.startswith(PkgbuildToken.Comment):
|
||||||
|
self._read_comment()
|
||||||
|
|
||||||
|
if not 0 < start_position < end_position:
|
||||||
|
raise PkgbuildParserError("function body wasn't found")
|
||||||
|
|
||||||
|
# read the specified interval from source stream
|
||||||
|
self._io.seek(start_position - 1) # start from the previous symbol
|
||||||
|
# we cannot use :func:`read()` here, because it reads characters, not bytes
|
||||||
|
content = ""
|
||||||
|
while self._io.tell() != end_position and (next_char := self._io.read(1)):
|
||||||
|
content += next_char
|
||||||
|
|
||||||
|
# special case of the end of file
|
||||||
|
if self.state == self.eof: # type: ignore[attr-defined]
|
||||||
|
content += self._io.read(1)
|
||||||
|
|
||||||
|
return content
|
||||||
|
|
||||||
|
def _parse_token(self, token: str) -> Iterator[PkgbuildPatch]:
|
||||||
|
"""
|
||||||
|
parse single token to the PKGBUILD field
|
||||||
|
|
||||||
|
Args:
|
||||||
|
token(str): current token
|
||||||
|
|
||||||
|
Yields:
|
||||||
|
PkgbuildPatch: extracted a PKGBUILD node
|
||||||
|
"""
|
||||||
|
# simple assignment rule
|
||||||
|
if m := self._STRING_ASSIGNMENT.match(token):
|
||||||
|
key = m.group("key")
|
||||||
|
value = m.group("value")
|
||||||
|
yield PkgbuildPatch(key, value)
|
||||||
|
return
|
||||||
|
|
||||||
|
if token.startswith(PkgbuildToken.Comment):
|
||||||
|
self._read_comment()
|
||||||
|
return
|
||||||
|
|
||||||
|
match self.get_token():
|
||||||
|
# array processing. Arrays will be sent as "key=", "(", values, ")"
|
||||||
|
case PkgbuildToken.ArrayStarts if m := self._ARRAY_ASSIGNMENT.match(token):
|
||||||
|
key = m.group("key")
|
||||||
|
value = self._parse_array()
|
||||||
|
yield PkgbuildPatch(key, value)
|
||||||
|
|
||||||
|
# functions processing. Function will be sent as "name", "()", "{", body, "}"
|
||||||
|
case PkgbuildToken.FunctionDeclaration if self._FUNCTION_DECLARATION.match(token):
|
||||||
|
key = f"{token}{PkgbuildToken.FunctionDeclaration}"
|
||||||
|
value = self._parse_function()
|
||||||
|
yield PkgbuildPatch(key, value) # this is not mistake, assign to token without ()
|
||||||
|
|
||||||
|
# special function case, where "(" and ")" are separated tokens, e.g. "pkgver ( )"
|
||||||
|
case PkgbuildToken.ArrayStarts if self._FUNCTION_DECLARATION.match(token):
|
||||||
|
next_token = self.get_token()
|
||||||
|
if next_token == PkgbuildToken.ArrayEnds: # replace closing bracket with "()"
|
||||||
|
next_token = PkgbuildToken.FunctionDeclaration
|
||||||
|
self.push_token(next_token) # type: ignore[arg-type]
|
||||||
|
yield from self._parse_token(token)
|
||||||
|
|
||||||
|
# some random token received without continuation, lets guess it is empty assignment (i.e. key=)
|
||||||
|
case other if other is not None:
|
||||||
|
yield from self._parse_token(other)
|
||||||
|
|
||||||
|
def _read_comment(self) -> None:
|
||||||
|
"""
|
||||||
|
read comment from the current position. This method doesn't check comment itself, just read the stream
|
||||||
|
until the comment line ends
|
||||||
|
"""
|
||||||
|
_, last_symbol = self._read_last()
|
||||||
|
if last_symbol != PkgbuildToken.NewLine:
|
||||||
|
self.instream.readline()
|
||||||
|
|
||||||
|
def _read_last(self, initial_index: int | None = None) -> tuple[int, str]:
|
||||||
|
"""
|
||||||
|
wrapper around read to read the last symbol from the input stream. This method is designed to process UTF-8
|
||||||
|
symbols correctly. This method does not reset current stream position
|
||||||
|
|
||||||
|
Args:
|
||||||
|
initial_index(int | None, optional): initial index to start reading from. If none set, the previous position
|
||||||
|
will be used (Default value = None)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple[int, str]: last symbol and its position in the stream
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
PkgbuildParserError: in case if stream reached starting position, but no valid symbols were found
|
||||||
|
"""
|
||||||
|
if initial_index is None:
|
||||||
|
initial_index = self._io.tell() - 1
|
||||||
|
if initial_index < 0:
|
||||||
|
raise PkgbuildParserError("stream is on starting position")
|
||||||
|
self._io.seek(initial_index)
|
||||||
|
|
||||||
|
while (position := self._io.tell()) > 0:
|
||||||
|
try:
|
||||||
|
return position, self._io.read(1)
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
self._io.seek(position - 1)
|
||||||
|
|
||||||
|
raise PkgbuildParserError("reached starting position, no valid symbols found")
|
||||||
|
|
||||||
|
def parse(self) -> Iterator[PkgbuildPatch]:
|
||||||
|
"""
|
||||||
|
parse source stream and yield parsed entries
|
||||||
|
|
||||||
|
Yields:
|
||||||
|
PkgbuildPatch: extracted a PKGBUILD node
|
||||||
|
"""
|
||||||
|
for token in self:
|
||||||
|
yield from self._parse_token(token)
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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).
|
||||||
+39
-21
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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,7 +17,7 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
from typing import Any
|
from typing import Any, ClassVar
|
||||||
|
|
||||||
from ahriman.core.alpm.pacman import Pacman
|
from ahriman.core.alpm.pacman import Pacman
|
||||||
from ahriman.core.alpm.remote.remote import Remote
|
from ahriman.core.alpm.remote.remote import Remote
|
||||||
@@ -35,16 +35,16 @@ class AUR(Remote):
|
|||||||
DEFAULT_RPC_VERSION(str): (class attribute) default AUR RPC version
|
DEFAULT_RPC_VERSION(str): (class attribute) default AUR RPC version
|
||||||
"""
|
"""
|
||||||
|
|
||||||
DEFAULT_AUR_URL = "https://aur.archlinux.org"
|
DEFAULT_AUR_URL: ClassVar[str] = "https://aur.archlinux.org"
|
||||||
DEFAULT_RPC_URL = f"{DEFAULT_AUR_URL}/rpc"
|
DEFAULT_RPC_URL: ClassVar[str] = f"{DEFAULT_AUR_URL}/rpc"
|
||||||
DEFAULT_RPC_VERSION = "5"
|
DEFAULT_RPC_VERSION: ClassVar[str] = "5"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def remote_git_url(cls, package_base: str, repository: str) -> str:
|
def remote_git_url(cls, package_base: str, repository: str) -> str:
|
||||||
"""
|
"""
|
||||||
generate remote git url from the package base
|
generate remote git url from the package base
|
||||||
|
|
||||||
Args
|
Args:
|
||||||
package_base(str): package base
|
package_base(str): package base
|
||||||
repository(str): repository name
|
repository(str): repository name
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ class AUR(Remote):
|
|||||||
"""
|
"""
|
||||||
generate remote web url from the package base
|
generate remote web url from the package base
|
||||||
|
|
||||||
Args
|
Args:
|
||||||
package_base(str): package base
|
package_base(str): package base
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@@ -72,7 +72,7 @@ class AUR(Remote):
|
|||||||
parse RPC response to package list
|
parse RPC response to package list
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
response(dict[str, Any]): RPC response json
|
response(dict[str, Any]): RPC response JSON
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
list[AURPackage]: list of parsed packages
|
list[AURPackage]: list of parsed packages
|
||||||
@@ -97,20 +97,17 @@ class AUR(Remote):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
list[AURPackage]: response parsed to package list
|
list[AURPackage]: response parsed to package list
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
PackageInfoError: if multiple arguments are passed
|
||||||
"""
|
"""
|
||||||
query: list[tuple[str, str]] = [
|
if len(args) != 1:
|
||||||
("type", request_type),
|
raise PackageInfoError("AUR API requires exactly one argument to search")
|
||||||
("v", self.DEFAULT_RPC_VERSION),
|
|
||||||
]
|
|
||||||
|
|
||||||
arg_query = "arg[]" if len(args) > 1 else "arg"
|
url = f"{self.DEFAULT_RPC_URL}/v{self.DEFAULT_RPC_VERSION}/{request_type}/{args[0]}"
|
||||||
for arg in args:
|
query = list(kwargs.items())
|
||||||
query.append((arg_query, arg))
|
|
||||||
|
|
||||||
for key, value in kwargs.items():
|
response = self.make_request("GET", url, params=query)
|
||||||
query.append((key, value))
|
|
||||||
|
|
||||||
response = self.make_request("GET", self.DEFAULT_RPC_URL, params=query)
|
|
||||||
return self.parse_response(response.json())
|
return self.parse_response(response.json())
|
||||||
|
|
||||||
def package_info(self, package_name: str, *, pacman: Pacman | None) -> AURPackage:
|
def package_info(self, package_name: str, *, pacman: Pacman | None) -> AURPackage:
|
||||||
@@ -133,15 +130,36 @@ class AUR(Remote):
|
|||||||
except StopIteration:
|
except StopIteration:
|
||||||
raise UnknownPackageError(package_name) from None
|
raise UnknownPackageError(package_name) from None
|
||||||
|
|
||||||
def package_search(self, *keywords: str, pacman: Pacman | None) -> list[AURPackage]:
|
def package_provided_by(self, package_name: str, *, pacman: Pacman | None) -> list[AURPackage]:
|
||||||
|
"""
|
||||||
|
get package list which provide the specified package name
|
||||||
|
|
||||||
|
Args:
|
||||||
|
package_name(str): package name to search
|
||||||
|
pacman(Pacman | None): alpm wrapper instance, required for official repositories search
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[AURPackage]: list of packages which match the criteria
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
package
|
||||||
|
# search api provides reduced models
|
||||||
|
for stub in self.package_search(package_name, pacman=pacman, search_by="provides")
|
||||||
|
# verity that found package actually provides it
|
||||||
|
if package_name in (package := self.package_info(stub.name, pacman=pacman)).provides
|
||||||
|
]
|
||||||
|
|
||||||
|
def package_search(self, *keywords: str, pacman: Pacman | None, search_by: str | None) -> list[AURPackage]:
|
||||||
"""
|
"""
|
||||||
search package in AUR web
|
search package in AUR web
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
*keywords(str): keywords to search
|
*keywords(str): keywords to search
|
||||||
pacman(Pacman | None): alpm wrapper instance, required for official repositories search
|
pacman(Pacman | None): alpm wrapper instance, required for official repositories search
|
||||||
|
search_by(str | None): search by keywords
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
list[AURPackage]: list of packages which match the criteria
|
list[AURPackage]: list of packages which match the criteria
|
||||||
"""
|
"""
|
||||||
return self.aur_request("search", *keywords, by="name-desc")
|
search_by = search_by or "name-desc"
|
||||||
|
return self.aur_request("search", *keywords, by=search_by)
|
||||||
+13
-11
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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,7 +17,7 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
from typing import Any
|
from typing import Any, ClassVar
|
||||||
|
|
||||||
from ahriman.core.alpm.pacman import Pacman
|
from ahriman.core.alpm.pacman import Pacman
|
||||||
from ahriman.core.alpm.remote.remote import Remote
|
from ahriman.core.alpm.remote.remote import Remote
|
||||||
@@ -36,17 +36,17 @@ class Official(Remote):
|
|||||||
DEFAULT_RPC_URL(str): (class attribute) default archlinux repositories RPC url
|
DEFAULT_RPC_URL(str): (class attribute) default archlinux repositories RPC url
|
||||||
"""
|
"""
|
||||||
|
|
||||||
DEFAULT_ARCHLINUX_GIT_URL = "https://gitlab.archlinux.org"
|
DEFAULT_ARCHLINUX_GIT_URL: ClassVar[str] = "https://gitlab.archlinux.org"
|
||||||
DEFAULT_ARCHLINUX_URL = "https://archlinux.org"
|
DEFAULT_ARCHLINUX_URL: ClassVar[str] = "https://archlinux.org"
|
||||||
DEFAULT_SEARCH_REPOSITORIES = ["Core", "Extra", "Multilib"]
|
DEFAULT_SEARCH_REPOSITORIES: ClassVar[list[str]] = ["Core", "Extra", "Multilib"]
|
||||||
DEFAULT_RPC_URL = "https://archlinux.org/packages/search/json"
|
DEFAULT_RPC_URL: ClassVar[str] = "https://archlinux.org/packages/search/json"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def remote_git_url(cls, package_base: str, repository: str) -> str:
|
def remote_git_url(cls, package_base: str, repository: str) -> str:
|
||||||
"""
|
"""
|
||||||
generate remote git url from the package base
|
generate remote git url from the package base
|
||||||
|
|
||||||
Args
|
Args:
|
||||||
package_base(str): package base
|
package_base(str): package base
|
||||||
repository(str): repository name
|
repository(str): repository name
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@ class Official(Remote):
|
|||||||
"""
|
"""
|
||||||
generate remote web url from the package base
|
generate remote web url from the package base
|
||||||
|
|
||||||
Args
|
Args:
|
||||||
package_base(str): package base
|
package_base(str): package base
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@@ -74,7 +74,7 @@ class Official(Remote):
|
|||||||
parse RPC response to package list
|
parse RPC response to package list
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
response(dict[str, Any]): RPC response json
|
response(dict[str, Any]): RPC response JSON
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
list[AURPackage]: list of parsed packages
|
list[AURPackage]: list of parsed packages
|
||||||
@@ -127,15 +127,17 @@ class Official(Remote):
|
|||||||
except StopIteration:
|
except StopIteration:
|
||||||
raise UnknownPackageError(package_name) from None
|
raise UnknownPackageError(package_name) from None
|
||||||
|
|
||||||
def package_search(self, *keywords: str, pacman: Pacman | None) -> list[AURPackage]:
|
def package_search(self, *keywords: str, pacman: Pacman | None, search_by: str | None) -> list[AURPackage]:
|
||||||
"""
|
"""
|
||||||
search package in AUR web
|
search package in AUR web
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
*keywords(str): keywords to search
|
*keywords(str): keywords to search
|
||||||
pacman(Pacman | None): alpm wrapper instance, required for official repositories search
|
pacman(Pacman | None): alpm wrapper instance, required for official repositories search
|
||||||
|
search_by(str | None): search by keywords
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
list[AURPackage]: list of packages which match the criteria
|
list[AURPackage]: list of packages which match the criteria
|
||||||
"""
|
"""
|
||||||
return self.arch_request(*keywords, by="q")
|
search_by = search_by or "q"
|
||||||
|
return self.arch_request(*keywords, by=search_by)
|
||||||
+22
-3
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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).
|
||||||
@@ -32,7 +32,7 @@ class OfficialSyncdb(Official):
|
|||||||
updates.
|
updates.
|
||||||
|
|
||||||
This approach also has limitations, because we don't require superuser rights (neither going to download database
|
This approach also has limitations, because we don't require superuser rights (neither going to download database
|
||||||
separately), the database file might be outdated and must be handled manually (or kind of). This behaviour might be
|
separately), the database file might be outdated and must be handled manually (or kind of). This behavior might be
|
||||||
changed in the future.
|
changed in the future.
|
||||||
|
|
||||||
Still we leave search function based on the official repositories RPC.
|
Still we leave search function based on the official repositories RPC.
|
||||||
@@ -56,6 +56,25 @@ class OfficialSyncdb(Official):
|
|||||||
raise UnknownPackageError(package_name)
|
raise UnknownPackageError(package_name)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return next(AURPackage.from_pacman(package) for package in pacman.package_get(package_name))
|
return next(AURPackage.from_pacman(package) for package in pacman.package(package_name))
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
raise UnknownPackageError(package_name) from None
|
raise UnknownPackageError(package_name) from None
|
||||||
|
|
||||||
|
def package_provided_by(self, package_name: str, *, pacman: Pacman | None) -> list[AURPackage]:
|
||||||
|
"""
|
||||||
|
get package list which provide the specified package name
|
||||||
|
|
||||||
|
Args:
|
||||||
|
package_name(str): package name to search
|
||||||
|
pacman(Pacman | None): alpm wrapper instance, required for official repositories search
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[AURPackage]: list of packages which match the criteria
|
||||||
|
"""
|
||||||
|
if pacman is None:
|
||||||
|
return []
|
||||||
|
|
||||||
|
return [
|
||||||
|
AURPackage.from_pacman(package)
|
||||||
|
for package in pacman.provided_by(package_name)
|
||||||
|
]
|
||||||
+53
-12
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2021-2024 ahriman team.
|
# Copyright (c) 2021-2026 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,6 +18,7 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
from ahriman.core.alpm.pacman import Pacman
|
from ahriman.core.alpm.pacman import Pacman
|
||||||
|
from ahriman.core.exceptions import UnknownPackageError
|
||||||
from ahriman.core.http import SyncHttpClient
|
from ahriman.core.http import SyncHttpClient
|
||||||
from ahriman.models.aur_package import AURPackage
|
from ahriman.models.aur_package import AURPackage
|
||||||
|
|
||||||
@@ -35,28 +36,42 @@ class Remote(SyncHttpClient):
|
|||||||
>>> package = AUR.info("ahriman")
|
>>> package = AUR.info("ahriman")
|
||||||
>>> search_result = Official.multisearch("pacman", "manager", pacman=pacman)
|
>>> search_result = Official.multisearch("pacman", "manager", pacman=pacman)
|
||||||
|
|
||||||
Differnece between :func:`search()` and :func:`multisearch()` is that :func:`search()` passes all arguments to
|
Difference between :func:`search()` and :func:`multisearch()` is that :func:`search()` passes all arguments to
|
||||||
underlying wrapper directly, whereas :func:`multisearch()` splits search one by one and finds intersection
|
underlying wrapper directly, whereas :func:`multisearch()` splits search one by one and finds intersection
|
||||||
between search results.
|
between search results.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def info(cls, package_name: str, *, pacman: Pacman | None = None) -> AURPackage:
|
def info(cls, package_name: str, *, pacman: Pacman | None = None, include_provides: bool = False) -> AURPackage:
|
||||||
"""
|
"""
|
||||||
get package info by its name
|
get package info by its name. If ``include_provides`` is set to ``True``, then, in addition, this method
|
||||||
|
will perform search by :attr:`ahriman.models.aur_package.AURPackage.provides` and return first package found.
|
||||||
|
Note, however, that in this case some implementation might not provide this method and search result will might
|
||||||
|
not be stable
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
package_name(str): package name to search
|
package_name(str): package name to search
|
||||||
pacman(Pacman | None, optional): alpm wrapper instance, required for official repositories search
|
pacman(Pacman | None, optional): alpm wrapper instance, required for official repositories search
|
||||||
(Default value = None)
|
(Default value = None)
|
||||||
|
include_provides(bool, optional): search by provides if no exact match found (Default value = False)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
AURPackage: package which match the package name
|
AURPackage: package which match the package name
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
UnknownPackageError: if requested package not found
|
||||||
"""
|
"""
|
||||||
return cls().package_info(package_name, pacman=pacman)
|
instance = cls()
|
||||||
|
try:
|
||||||
|
return instance.package_info(package_name, pacman=pacman)
|
||||||
|
except UnknownPackageError:
|
||||||
|
if include_provides and (provided_by := instance.package_provided_by(package_name, pacman=pacman)):
|
||||||
|
return next(iter(provided_by))
|
||||||
|
raise
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def multisearch(cls, *keywords: str, pacman: Pacman | None = None) -> list[AURPackage]:
|
def multisearch(cls, *keywords: str, pacman: Pacman | None = None,
|
||||||
|
search_by: str | None = None) -> list[AURPackage]:
|
||||||
"""
|
"""
|
||||||
search in remote repository by using API with multiple words. This method is required in order to handle
|
search in remote repository by using API with multiple words. This method is required in order to handle
|
||||||
https://bugs.archlinux.org/task/49133. In addition, short words will be dropped
|
https://bugs.archlinux.org/task/49133. In addition, short words will be dropped
|
||||||
@@ -65,6 +80,7 @@ class Remote(SyncHttpClient):
|
|||||||
*keywords(str): search terms, e.g. "ahriman", "is", "cool"
|
*keywords(str): search terms, e.g. "ahriman", "is", "cool"
|
||||||
pacman(Pacman | None, optional): alpm wrapper instance, required for official repositories search
|
pacman(Pacman | None, optional): alpm wrapper instance, required for official repositories search
|
||||||
(Default value = None)
|
(Default value = None)
|
||||||
|
search_by(str | None, optional): search by keywords (Default value = None)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
list[AURPackage]: list of packages each of them matches all search terms
|
list[AURPackage]: list of packages each of them matches all search terms
|
||||||
@@ -72,12 +88,21 @@ class Remote(SyncHttpClient):
|
|||||||
instance = cls()
|
instance = cls()
|
||||||
packages: dict[str, AURPackage] = {}
|
packages: dict[str, AURPackage] = {}
|
||||||
for term in filter(lambda word: len(word) >= 3, keywords):
|
for term in filter(lambda word: len(word) >= 3, keywords):
|
||||||
portion = instance.search(term, pacman=pacman)
|
portion = instance.package_search(term, pacman=pacman, search_by=search_by)
|
||||||
packages = {
|
packages = {
|
||||||
package.name: package # not mistake to group them by name
|
package.name: package # not mistake to group them by name
|
||||||
for package in portion
|
for package in portion
|
||||||
if package.name in packages or not packages
|
if package.name in packages or not packages
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# simple check for duplicates. This method will remove all packages under base if there is
|
||||||
|
# a package named exactly as its base
|
||||||
|
packages = {
|
||||||
|
package.name: package
|
||||||
|
for package in packages.values()
|
||||||
|
if package.package_base not in packages or package.package_base == package.name
|
||||||
|
}
|
||||||
|
|
||||||
return list(packages.values())
|
return list(packages.values())
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -85,7 +110,7 @@ class Remote(SyncHttpClient):
|
|||||||
"""
|
"""
|
||||||
generate remote git url from the package base
|
generate remote git url from the package base
|
||||||
|
|
||||||
Args
|
Args:
|
||||||
package_base(str): package base
|
package_base(str): package base
|
||||||
repository(str): repository name
|
repository(str): repository name
|
||||||
|
|
||||||
@@ -102,7 +127,7 @@ class Remote(SyncHttpClient):
|
|||||||
"""
|
"""
|
||||||
generate remote web url from the package base
|
generate remote web url from the package base
|
||||||
|
|
||||||
Args
|
Args:
|
||||||
package_base(str): package base
|
package_base(str): package base
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@@ -114,7 +139,7 @@ class Remote(SyncHttpClient):
|
|||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def search(cls, *keywords: str, pacman: Pacman | None = None) -> list[AURPackage]:
|
def search(cls, *keywords: str, pacman: Pacman | None = None, search_by: str | None = None) -> list[AURPackage]:
|
||||||
"""
|
"""
|
||||||
search package in AUR web
|
search package in AUR web
|
||||||
|
|
||||||
@@ -122,11 +147,12 @@ class Remote(SyncHttpClient):
|
|||||||
*keywords(str): search terms, e.g. "ahriman", "is", "cool"
|
*keywords(str): search terms, e.g. "ahriman", "is", "cool"
|
||||||
pacman(Pacman | None, optional): alpm wrapper instance, required for official repositories search
|
pacman(Pacman | None, optional): alpm wrapper instance, required for official repositories search
|
||||||
(Default value = None)
|
(Default value = None)
|
||||||
|
search_by(str | None, optional): search by keywords (Default value = None)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
list[AURPackage]: list of packages which match the criteria
|
list[AURPackage]: list of packages which match the criteria
|
||||||
"""
|
"""
|
||||||
return cls().package_search(*keywords, pacman=pacman)
|
return cls().package_search(*keywords, pacman=pacman, search_by=search_by)
|
||||||
|
|
||||||
def package_info(self, package_name: str, *, pacman: Pacman | None) -> AURPackage:
|
def package_info(self, package_name: str, *, pacman: Pacman | None) -> AURPackage:
|
||||||
"""
|
"""
|
||||||
@@ -144,13 +170,28 @@ class Remote(SyncHttpClient):
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def package_search(self, *keywords: str, pacman: Pacman | None) -> list[AURPackage]:
|
def package_provided_by(self, package_name: str, *, pacman: Pacman | None) -> list[AURPackage]:
|
||||||
|
"""
|
||||||
|
get package list which provide the specified package name
|
||||||
|
|
||||||
|
Args:
|
||||||
|
package_name(str): package name to search
|
||||||
|
pacman(Pacman | None): alpm wrapper instance, required for official repositories search
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[AURPackage]: list of packages which match the criteria
|
||||||
|
"""
|
||||||
|
del package_name, pacman
|
||||||
|
return []
|
||||||
|
|
||||||
|
def package_search(self, *keywords: str, pacman: Pacman | None, search_by: str | None) -> list[AURPackage]:
|
||||||
"""
|
"""
|
||||||
search package in AUR web
|
search package in AUR web
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
*keywords(str): keywords to search
|
*keywords(str): keywords to search
|
||||||
pacman(Pacman | None): alpm wrapper instance, required for official repositories search
|
pacman(Pacman | None): alpm wrapper instance, required for official repositories search
|
||||||
|
search_by(str | None): search by keywords
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
list[AURPackage]: list of packages which match the criteria
|
list[AURPackage]: list of packages which match the criteria
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user