add depdendency manager and switch to pyalpm instead of expac

This commit is contained in:
Evgenii Alekseev 2021-03-12 00:04:37 +03:00
parent 2d351fa94f
commit 371019f899
19 changed files with 241 additions and 74 deletions

View File

@ -9,11 +9,14 @@ Base configuration settings.
* `include` - path to directory with configuration files overrides, string, required. * `include` - path to directory with configuration files overrides, string, required.
* `logging` - path to logging configuration, string, required. Check `logging.ini` for reference. * `logging` - path to logging configuration, string, required. Check `logging.ini` for reference.
## `aur` group ## `alpm` group
AUR related configuration. libalpm and AUR related configuration.
* `url` - base url for AUR, string, required. * `aur_url` - base url for AUR, string, required.
* `database` - path to pacman local database cache, string, required.
* `repositories` - list of pacman repositories, space separated list of strings, required.
* `root` - root for alpm library, string, required.
## `build_*` groups ## `build_*` groups

View File

@ -8,7 +8,8 @@ Wrapper for managing custom repository inspired by [repo-scripts](https://github
* Multi-architecture support * Multi-architecture support
* VCS packages support * VCS packages support
* Sign support with gpg (repository, package, per package settings) * Sign support with gpg (repository, package, per package settings)
* Synchronization to remote services (rsync, s3) and report generation (html) * Synchronization to remote services (rsync, s3) and report generation (html)
* Dependency manager
* Repository status interface * Repository status interface
## Installation and run ## Installation and run
@ -24,7 +25,3 @@ Wrapper for managing custom repository inspired by [repo-scripts](https://github
* configure `/etc/sudoers.d/ahriman` to allow running command without password. * configure `/etc/sudoers.d/ahriman` to allow running command without password.
* Start and enable `ahriman.timer` via `systemctl`. * Start and enable `ahriman.timer` via `systemctl`.
* Add packages by using `ahriman add {package}` command. * Add packages by using `ahriman add {package}` command.
## Limitations
* It does not manage dependencies, so you have to add them before main package.

View File

@ -7,7 +7,7 @@ pkgdesc="ArcHlinux ReposItory MANager"
arch=('any') arch=('any')
url="https://github.com/arcan1s/ahriman" url="https://github.com/arcan1s/ahriman"
license=('GPL3') license=('GPL3')
depends=('devtools' 'expac' 'git' 'python-aur' 'python-srcinfo') depends=('devtools' 'git' 'pyalpm' 'python-aur' 'python-srcinfo')
makedepends=('python-pip') makedepends=('python-pip')
optdepends=('aws-cli: sync to s3' optdepends=('aws-cli: sync to s3'
'breezy: -bzr packages support' 'breezy: -bzr packages support'
@ -23,7 +23,7 @@ optdepends=('aws-cli: sync to s3'
source=("https://github.com/arcan1s/ahriman/releases/download/$pkgver/$pkgname-$pkgver-src.tar.xz" source=("https://github.com/arcan1s/ahriman/releases/download/$pkgver/$pkgname-$pkgver-src.tar.xz"
'ahriman.sysusers' 'ahriman.sysusers'
'ahriman.tmpfiles') 'ahriman.tmpfiles')
sha512sums=('941821639fe4410152a21251d9b0fe5f96ee3a60b88e2067ea4a83ef04b5d1393828152ef4843575449bdef8d44ad6a69f9e41e82516d4d1850bd14f17822785' sha512sums=('ddbae1368359c93e4a00a196b06e003895fe5bd36f763f2313c2cdc1cf37db96f258807be087a8aceebb8d608c332cd88695600fd28a728af17187f1568711b4'
'13718afec2c6786a18f0b223ef8e58dccf0688bca4cdbe203f14071f5031ed20120eb0ce38b52c76cfd6e8b6581a9c9eaa2743eb11abbaca637451a84c33f075' '13718afec2c6786a18f0b223ef8e58dccf0688bca4cdbe203f14071f5031ed20120eb0ce38b52c76cfd6e8b6581a9c9eaa2743eb11abbaca637451a84c33f075'
'55b20f6da3d66e7bbf2add5d95a3b60632df121717d25a993e56e737d14f51fe063eb6f1b38bd81cc32e05db01c0c1d80aaa720c45cde87f238d8b46cdb8cbc4') '55b20f6da3d66e7bbf2add5d95a3b60632df121717d25a993e56e737d14f51fe063eb6f1b38bd81cc32e05db01c0c1d80aaa720c45cde87f238d8b46cdb8cbc4')
backup=('etc/ahriman.ini' backup=('etc/ahriman.ini'

View File

@ -2,8 +2,11 @@
include = /etc/ahriman.ini.d include = /etc/ahriman.ini.d
logging = /etc/ahriman.ini.d/logging.ini logging = /etc/ahriman.ini.d/logging.ini
[aur] [alpm]
url = https://aur.archlinux.org aur_url = https://aur.archlinux.org
database = /var/lib/pacman
repositories = core extra community multilib
root = /
[build] [build]
archbuild_flags = archbuild_flags =

View File

@ -28,6 +28,7 @@ setup(
], ],
install_requires=[ install_requires=[
'aur', 'aur',
'pyalpm',
'srcinfo', 'srcinfo',
], ],
setup_requires=[ setup_requires=[

View File

@ -27,7 +27,7 @@ from ahriman.core.configuration import Configuration
def add(args: argparse.Namespace) -> None: def add(args: argparse.Namespace) -> None:
Application.from_args(args).add(args.package) Application.from_args(args).add(args.package, args.without_dependencies)
def rebuild(args: argparse.Namespace) -> None: def rebuild(args: argparse.Namespace) -> None:
@ -75,6 +75,7 @@ if __name__ == '__main__':
add_parser = subparsers.add_parser('add', description='add package') add_parser = subparsers.add_parser('add', description='add package')
add_parser.add_argument('package', help='package name or archive path', nargs='+') add_parser.add_argument('package', help='package name or archive path', nargs='+')
add_parser.add_argument('--without-dependencies', help='do not add dependencies', action='store_true')
add_parser.set_defaults(fn=add) add_parser.set_defaults(fn=add)
check_parser = subparsers.add_parser('check', description='check for updates') check_parser = subparsers.add_parser('check', description='check for updates')

View File

@ -24,11 +24,12 @@ import logging
import os import os
import shutil import shutil
from typing import Callable, List, Optional, Type from typing import Callable, Iterable, List, Optional, Set, Type
from ahriman.core.build_tools.task import Task from ahriman.core.build_tools.task import Task
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.repository import Repository from ahriman.core.repository import Repository
from ahriman.core.tree import Tree
from ahriman.models.package import Package from ahriman.models.package import Package
@ -45,6 +46,14 @@ class Application:
config = Configuration.from_path(args.config) config = Configuration.from_path(args.config)
return cls(args.architecture, config) return cls(args.architecture, config)
def _known_packages(self) -> Set[str]:
known_packages = set()
# local set
for package in self.repository.packages():
known_packages.update(package.packages)
known_packages.update(self.repository.pacman.all_packages())
return known_packages
def _finalize(self) -> None: def _finalize(self) -> None:
self.report() self.report()
self.sync() self.sync()
@ -63,35 +72,55 @@ class Application:
return updates return updates
def add(self, names: List[str]) -> None: def add(self, names: Iterable[str], without_dependencies: bool) -> None:
def add_manual(name: str) -> None: known_packages = self._known_packages()
package = Package.load(name, self.config.get('aur', 'url'))
Task.fetch(os.path.join(self.repository.paths.manual, package.base), package.git_url) def add_manual(name: str) -> str:
package = Package.load(name, self.repository.pacman, self.config.get('alpm', 'aur_url'))
path = os.path.join(self.repository.paths.manual, package.base)
Task.fetch(path, package.git_url)
return path
def add_archive(src: str) -> None: def add_archive(src: str) -> None:
dst = os.path.join(self.repository.paths.packages, os.path.basename(src)) dst = os.path.join(self.repository.paths.packages, os.path.basename(src))
shutil.move(src, dst) shutil.move(src, dst)
for name in names: def process_dependencies(path: str) -> None:
if os.path.isfile(name): if without_dependencies:
add_archive(name) return
else: dependencies = Package.dependencies(path)
add_manual(name) self.add(dependencies.difference(known_packages), without_dependencies)
def remove(self, names: List[str]) -> None: def process_single(name: str) -> None:
if not os.path.isfile(name):
path = add_manual(name)
process_dependencies(path)
else:
add_archive(name)
for name in names:
process_single(name)
def remove(self, names: Iterable[str]) -> None:
self.repository.process_remove(names) self.repository.process_remove(names)
self._finalize() self._finalize()
def report(self, target: Optional[List[str]] = None) -> None: def report(self, target: Optional[Iterable[str]] = None) -> None:
targets = target or None targets = target or None
self.repository.process_report(targets) self.repository.process_report(targets)
def sync(self, target: Optional[List[str]] = None) -> None: def sync(self, target: Optional[Iterable[str]] = None) -> None:
targets = target or None targets = target or None
self.repository.process_sync(targets) self.repository.process_sync(targets)
def update(self, updates: List[Package]) -> None: def update(self, updates: Iterable[Package]) -> None:
packages = self.repository.process_build(updates) def process_single(portion: Iterable[Package]):
self.repository.process_update(packages) packages = self.repository.process_build(portion)
self._finalize() self.repository.process_update(packages)
self._finalize()
tree = Tree()
tree.load(updates)
for num, level in enumerate(tree.levels()):
self.logger.info(f'processing level #{num} {[package.base for package in level]}')
process_single(level)

View File

@ -39,7 +39,6 @@ class Lock:
def __exit__(self, exc_type, exc_val, exc_tb): def __exit__(self, exc_type, exc_val, exc_tb):
self.remove() self.remove()
return True
def check(self) -> None: def check(self) -> None:
if self.path is None: if self.path is None:

View File

@ -0,0 +1,40 @@
#
# Copyright (c) 2021 Evgenii Alekseev.
#
# 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 pyalpm import Handle
from typing import List, Set
from ahriman.core.configuration import Configuration
class Pacman:
def __init__(self, config: Configuration) -> None:
root = config.get('alpm', 'root')
pacman_root = config.get('alpm', 'database')
self.handle = Handle(root, pacman_root)
for repository in config.getlist('alpm', 'repositories'):
self.handle.register_syncdb(repository, 0) # 0 is pgp_level
def all_packages(self) -> List[str]:
result: Set[str] = set()
for database in self.handle.get_syncdbs():
result.update({package.name for package in database.pkgcache})
return list(result)

View File

@ -27,7 +27,7 @@ from ahriman.core.util import check_output
from ahriman.models.repository_paths import RepositoryPaths from ahriman.models.repository_paths import RepositoryPaths
class RepoWrapper: class Repo:
def __init__(self, name: str, paths: RepositoryPaths, sign_args: List[str]) -> None: def __init__(self, name: str, paths: RepositoryPaths, sign_args: List[str]) -> None:
self.logger = logging.getLogger('build_details') self.logger = logging.getLogger('build_details')

View File

@ -35,7 +35,7 @@ class InitializeException(Exception):
Exception.__init__(self, 'Could not load service') Exception.__init__(self, 'Could not load service')
class InvalidOptionException(Exception): class InvalidOption(Exception):
def __init__(self, value: Any) -> None: def __init__(self, value: Any) -> None:
Exception.__init__(self, f'Invalid or unknown option value `{value}`') Exception.__init__(self, f'Invalid or unknown option value `{value}`')

View File

@ -21,13 +21,14 @@ import logging
import os import os
import shutil import shutil
from typing import Dict, List, Optional from typing import Dict, Iterable, List, Optional
from ahriman.core.alpm.pacman import Pacman
from ahriman.core.alpm.repo import Repo
from ahriman.core.build_tools.task import Task from ahriman.core.build_tools.task import Task
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.repo.repo_wrapper import RepoWrapper
from ahriman.core.report.report import Report from ahriman.core.report.report import Report
from ahriman.core.sign.gpg_wrapper import GPGWrapper from ahriman.core.sign.gpg import GPG
from ahriman.core.upload.uploader import Uploader from ahriman.core.upload.uploader import Uploader
from ahriman.core.util import package_like from ahriman.core.util import package_like
from ahriman.core.watcher.client import Client from ahriman.core.watcher.client import Client
@ -42,15 +43,16 @@ class Repository:
self.architecture = architecture self.architecture = architecture
self.config = config self.config = config
self.aur_url = config.get('aur', 'url') self.aur_url = config.get('alpm', 'aur_url')
self.name = config.get('repository', 'name') self.name = config.get('repository', 'name')
self.paths = RepositoryPaths(config.get('repository', 'root'), architecture) self.paths = RepositoryPaths(config.get('repository', 'root'), architecture)
self.paths.create_tree() self.paths.create_tree()
self.sign = GPGWrapper(architecture, config) self.pacman = Pacman(config)
self.wrapper = RepoWrapper(self.name, self.paths, self.sign.repository_sign_args) self.sign = GPG(architecture, config)
self.web_report = Client.load(architecture, config) self.repo = Repo(self.name, self.paths, self.sign.repository_sign_args)
self.web = Client.load(architecture, config)
def _clear_build(self) -> None: def _clear_build(self) -> None:
for package in os.listdir(self.paths.sources): for package in os.listdir(self.paths.sources):
@ -71,16 +73,16 @@ class Repository:
continue continue
full_path = os.path.join(self.paths.repository, fn) full_path = os.path.join(self.paths.repository, fn)
try: try:
local = Package.load(full_path, self.aur_url) local = Package.load(full_path, self.pacman, self.aur_url)
result.setdefault(local.base, local).packages.update(local.packages) result.setdefault(local.base, local).packages.update(local.packages)
except Exception: except Exception:
self.logger.exception(f'could not load package from {fn}', exc_info=True) self.logger.exception(f'could not load package from {fn}', exc_info=True)
continue continue
return list(result.values()) return list(result.values())
def process_build(self, updates: List[Package]) -> List[str]: def process_build(self, updates: Iterable[Package]) -> List[str]:
def build_single(package: Package) -> None: def build_single(package: Package) -> None:
self.web_report.set_building(package.base) self.web.set_building(package.base)
task = Task(package, self.architecture, self.config, self.paths) task = Task(package, self.architecture, self.config, self.paths)
task.clone() task.clone()
built = task.build() built = task.build()
@ -92,7 +94,7 @@ class Repository:
try: try:
build_single(package) build_single(package)
except Exception: except Exception:
self.web_report.set_failed(package.base) self.web.set_failed(package.base)
self.logger.exception(f'{package.base} ({self.architecture}) build exception', exc_info=True) self.logger.exception(f'{package.base} ({self.architecture}) build exception', exc_info=True)
continue continue
self._clear_build() self._clear_build()
@ -102,10 +104,10 @@ class Repository:
for fn in os.listdir(self.paths.packages) for fn in os.listdir(self.paths.packages)
] ]
def process_remove(self, packages: List[str]) -> str: def process_remove(self, packages: Iterable[str]) -> str:
def remove_single(package: str) -> None: def remove_single(package: str) -> None:
try: try:
self.wrapper.remove(package, package) self.repo.remove(package, package)
except Exception: except Exception:
self.logger.exception(f'could not remove {package}', exc_info=True) self.logger.exception(f'could not remove {package}', exc_info=True)
@ -116,41 +118,41 @@ class Repository:
to_remove = local.packages.intersection(packages) to_remove = local.packages.intersection(packages)
else: else:
to_remove = set() to_remove = set()
self.web_report.remove(local.base, to_remove) self.web.remove(local.base, to_remove)
for package in to_remove: for package in to_remove:
remove_single(package) remove_single(package)
return self.wrapper.repo_path return self.repo.repo_path
def process_report(self, targets: Optional[List[str]]) -> None: def process_report(self, targets: Optional[Iterable[str]]) -> None:
if targets is None: if targets is None:
targets = self.config.getlist('report', 'target') targets = self.config.getlist('report', 'target')
for target in targets: for target in targets:
Report.run(self.architecture, self.config, target, self.paths.repository) Report.run(self.architecture, self.config, target, self.paths.repository)
def process_sync(self, targets: Optional[List[str]]) -> None: def process_sync(self, targets: Optional[Iterable[str]]) -> None:
if targets is None: if targets is None:
targets = self.config.getlist('upload', 'target') targets = self.config.getlist('upload', 'target')
for target in targets: for target in targets:
Uploader.run(self.architecture, self.config, target, self.paths.repository) Uploader.run(self.architecture, self.config, target, self.paths.repository)
def process_update(self, packages: List[str]) -> str: def process_update(self, packages: Iterable[str]) -> str:
for package in packages: for package in packages:
local = Package.load(package, self.aur_url) # we will use it for status reports local = Package.load(package, self.pacman, self.aur_url) # we will use it for status reports
try: try:
files = self.sign.sign_package(package, local.base) files = self.sign.sign_package(package, local.base)
for src in files: for src in files:
dst = os.path.join(self.paths.repository, os.path.basename(src)) dst = os.path.join(self.paths.repository, os.path.basename(src))
shutil.move(src, dst) shutil.move(src, dst)
package_fn = os.path.join(self.paths.repository, os.path.basename(package)) package_fn = os.path.join(self.paths.repository, os.path.basename(package))
self.wrapper.add(package_fn) self.repo.add(package_fn)
self.web_report.set_success(local) self.web.set_success(local)
except Exception: except Exception:
self.logger.exception(f'could not process {package}', exc_info=True) self.logger.exception(f'could not process {package}', exc_info=True)
self.web_report.set_failed(local.base) self.web.set_failed(local.base)
self._clear_packages() self._clear_packages()
return self.wrapper.repo_path return self.repo.repo_path
def updates_aur(self, no_vcs: bool) -> List[Package]: def updates_aur(self, no_vcs: bool) -> List[Package]:
result: List[Package] = [] result: List[Package] = []
@ -165,12 +167,12 @@ class Repository:
continue continue
try: try:
remote = Package.load(local.base, self.aur_url) remote = Package.load(local.base, self.pacman, self.aur_url)
if local.is_outdated(remote): if local.is_outdated(remote):
result.append(remote) result.append(remote)
self.web_report.set_pending(local.base) self.web.set_pending(local.base)
except Exception: except Exception:
self.web_report.set_failed(local.base) self.web.set_failed(local.base)
self.logger.exception(f'could not load remote package {local.base}', exc_info=True) self.logger.exception(f'could not load remote package {local.base}', exc_info=True)
continue continue
@ -181,9 +183,9 @@ class Repository:
for fn in os.listdir(self.paths.manual): for fn in os.listdir(self.paths.manual):
try: try:
local = Package.load(os.path.join(self.paths.manual, fn), self.aur_url) local = Package.load(os.path.join(self.paths.manual, fn), self.pacman, self.aur_url)
result.append(local) result.append(local)
self.web_report.set_unknown(local) self.web.set_unknown(local)
except Exception: except Exception:
self.logger.exception(f'could not add package from {fn}', exc_info=True) self.logger.exception(f'could not add package from {fn}', exc_info=True)
self._clear_manual() self._clear_manual()

View File

@ -28,7 +28,7 @@ from ahriman.core.util import check_output
from ahriman.models.sign_settings import SignSettings from ahriman.models.sign_settings import SignSettings
class GPGWrapper: class GPG:
def __init__(self, architecture: str, config: Configuration) -> None: def __init__(self, architecture: str, config: Configuration) -> None:
self.logger = logging.getLogger('build_details') self.logger = logging.getLogger('build_details')

75
src/ahriman/core/tree.py Normal file
View File

@ -0,0 +1,75 @@
#
# Copyright (c) 2021 Evgenii Alekseev.
#
# This file is part of ahriman
# (see https://github.com/arcan1s/ahriman).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import annotations
import shutil
import tempfile
from typing import Iterable, List, Set
from ahriman.core.build_tools.task import Task
from ahriman.models.package import Package
class Tree:
def __init__(self) -> None:
self.packages: List[Leaf] = []
def levels(self) -> List[List[Package]]:
result: List[List[Package]] = []
unprocessed = [leaf for leaf in self.packages]
while unprocessed:
result.append([leaf.package for leaf in unprocessed if leaf.is_root(unprocessed)])
unprocessed = [leaf for leaf in unprocessed if not leaf.is_root(unprocessed)]
return result
def load(self, packages: Iterable[Package]) -> None:
for package in packages:
leaf = Leaf(package)
leaf.load_dependencies()
self.packages.append(leaf)
class Leaf:
def __init__(self, package: Package) -> None:
self.package = package
self.dependencies: Set[str] = set()
def is_root(self, packages: Iterable[Leaf]) -> bool:
'''
:param packages:
:return: true if any of packages is dependency of the leaf, false otherwise
'''
for package in packages:
if package.package.packages.intersection(self.dependencies):
return False
return True
def load_dependencies(self) -> None:
clone_dir = tempfile.mkdtemp()
try:
Task.fetch(clone_dir, self.package.git_url)
self.dependencies = Package.dependencies(clone_dir)
finally:
shutil.rmtree(clone_dir, ignore_errors=True)

View File

@ -25,9 +25,11 @@ import shutil
import tempfile import tempfile
from dataclasses import dataclass, field from dataclasses import dataclass, field
from pyalpm import Handle
from srcinfo.parse import parse_srcinfo from srcinfo.parse import parse_srcinfo
from typing import Set, Type from typing import List, Set, Type
from ahriman.core.alpm.pacman import Pacman
from ahriman.core.exceptions import InvalidPackageInfo from ahriman.core.exceptions import InvalidPackageInfo
from ahriman.core.util import check_output from ahriman.core.util import check_output
@ -79,9 +81,9 @@ class Package:
shutil.rmtree(clone_dir, ignore_errors=True) shutil.rmtree(clone_dir, ignore_errors=True)
@classmethod @classmethod
def from_archive(cls: Type[Package], path: str, aur_url: str) -> Package: def from_archive(cls: Type[Package], path: str, pacman: Pacman, aur_url: str) -> Package:
package, base, version = check_output('expac', '-p', '%n %e %v', path, exception=None).split() package = pacman.handle.load_pkg(path)
return cls(base, version, aur_url, {package}) return cls(package.base, package.version, aur_url, {package.name})
@classmethod @classmethod
def from_aur(cls: Type[Package], name: str, aur_url: str)-> Package: def from_aur(cls: Type[Package], name: str, aur_url: str)-> Package:
@ -99,12 +101,27 @@ class Package:
return cls(src_info['pkgbase'], f'{src_info["pkgver"]}-{src_info["pkgrel"]}', aur_url, packages) return cls(src_info['pkgbase'], f'{src_info["pkgver"]}-{src_info["pkgrel"]}', aur_url, packages)
@staticmethod @staticmethod
def load(path: str, aur_url: str) -> Package: def dependencies(path: str) -> Set[str]:
with open(os.path.join(path, '.SRCINFO')) as fn:
src_info, errors = parse_srcinfo(fn.read())
if errors:
raise InvalidPackageInfo(errors)
makedepends = src_info['makedepends']
# sum over each package
depends: List[str] = src_info.get('depends', [])
for package in src_info['packages'].values():
depends.extend(package.get('depends', []))
# we are not interested in dependencies inside pkgbase
packages = set(src_info['packages'].keys())
return set(depends + makedepends) - packages
@staticmethod
def load(path: str, pacman: Pacman, aur_url: str) -> Package:
try: try:
if os.path.isdir(path): if os.path.isdir(path):
package: Package = Package.from_build(path, aur_url) package: Package = Package.from_build(path, aur_url)
elif os.path.exists(path): elif os.path.exists(path):
package = Package.from_archive(path, aur_url) package = Package.from_archive(path, pacman, aur_url)
else: else:
package = Package.from_aur(path, aur_url) package = Package.from_aur(path, aur_url)
return package return package

View File

@ -21,7 +21,7 @@ from __future__ import annotations
from enum import Enum, auto from enum import Enum, auto
from ahriman.core.exceptions import InvalidOptionException from ahriman.core.exceptions import InvalidOption
class ReportSettings(Enum): class ReportSettings(Enum):
@ -31,4 +31,4 @@ class ReportSettings(Enum):
def from_option(value: str) -> ReportSettings: def from_option(value: str) -> ReportSettings:
if value.lower() in ('html',): if value.lower() in ('html',):
return ReportSettings.HTML return ReportSettings.HTML
raise InvalidOptionException(value) raise InvalidOption(value)

View File

@ -21,7 +21,7 @@ from __future__ import annotations
from enum import Enum, auto from enum import Enum, auto
from ahriman.core.exceptions import InvalidOptionException from ahriman.core.exceptions import InvalidOption
class SignSettings(Enum): class SignSettings(Enum):
@ -34,4 +34,4 @@ class SignSettings(Enum):
return SignSettings.SignPackages return SignSettings.SignPackages
elif value.lower() in ('repository', 'sign-repository'): elif value.lower() in ('repository', 'sign-repository'):
return SignSettings.SignRepository return SignSettings.SignRepository
raise InvalidOptionException(value) raise InvalidOption(value)

View File

@ -21,7 +21,7 @@ from __future__ import annotations
from enum import Enum, auto from enum import Enum, auto
from ahriman.core.exceptions import InvalidOptionException from ahriman.core.exceptions import InvalidOption
class UploadSettings(Enum): class UploadSettings(Enum):
@ -34,4 +34,4 @@ class UploadSettings(Enum):
return UploadSettings.Rsync return UploadSettings.Rsync
elif value.lower() in ('s3',): elif value.lower() in ('s3',):
return UploadSettings.S3 return UploadSettings.S3
raise InvalidOptionException(value) raise InvalidOption(value)